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>
41 #include <IOKit/IOTimeStamp.h>
43 #include <IOKit/pwr_mgt/IOPMlog.h>
44 #include <IOKit/pwr_mgt/IOPMinformee.h>
45 #include <IOKit/pwr_mgt/IOPMinformeeList.h>
46 #include <IOKit/pwr_mgt/IOPowerConnection.h>
47 #include <IOKit/pwr_mgt/RootDomain.h>
48 #include <IOKit/pwr_mgt/IOPMPrivate.h>
51 #include <sys/proc_internal.h>
52 #include <libkern/OSDebug.h>
54 // Required for notification instrumentation
55 #include "IOServicePrivate.h"
56 #include "IOServicePMPrivate.h"
57 #include "IOKitKernelInternal.h"
59 static void settle_timer_expired(thread_call_param_t
, thread_call_param_t
);
60 static void idle_timer_expired(thread_call_param_t
, thread_call_param_t
);
61 static void tellKernelClientApplier(OSObject
* object
, void * arg
);
62 static void tellAppClientApplier(OSObject
* object
, void * arg
);
64 static uint64_t computeTimeDeltaNS( const AbsoluteTime
* start
)
69 clock_get_uptime(&now
);
70 SUB_ABSOLUTETIME(&now
, start
);
71 absolutetime_to_nanoseconds(now
, &nsec
);
76 OSDefineMetaClassAndStructors(IOPMprot
, OSObject
)
79 // Container class for recording system power events
80 OSDefineMetaClassAndStructors( PMEventDetails
, OSObject
);
82 //******************************************************************************
84 //******************************************************************************
86 static bool gIOPMInitialized
= false;
87 static uint32_t gIOPMBusyCount
= 0;
88 static uint32_t gIOPMWorkCount
= 0;
89 static IOWorkLoop
* gIOPMWorkLoop
= 0;
90 static IOPMRequestQueue
* gIOPMRequestQueue
= 0;
91 static IOPMRequestQueue
* gIOPMReplyQueue
= 0;
92 static IOPMWorkQueue
* gIOPMWorkQueue
= 0;
93 static IOPMCompletionQueue
* gIOPMFreeQueue
= 0;
94 static IOPMRequest
* gIOPMRequest
= 0;
95 static IOService
* gIOPMRootNode
= 0;
96 static IOPlatformExpert
* gPlatform
= 0;
98 static const OSSymbol
* gIOPMPowerClientDevice
= 0;
99 static const OSSymbol
* gIOPMPowerClientDriver
= 0;
100 static const OSSymbol
* gIOPMPowerClientChildProxy
= 0;
101 static const OSSymbol
* gIOPMPowerClientChildren
= 0;
103 static const OSSymbol
* gIOPMPowerClientAdvisoryTickle
= 0;
104 static bool gIOPMAdvisoryTickleEnabled
= true;
106 static uint32_t getPMRequestType( void )
108 uint32_t type
= kIOPMRequestTypeInvalid
;
110 type
= gIOPMRequest
->getType();
114 //******************************************************************************
116 //******************************************************************************
118 #define PM_ERROR(x...) do { kprintf(x); IOLog(x); } while (false)
119 #define PM_LOG(x...) do { kprintf(x); } while (false)
121 #define PM_LOG1(x...) do { \
122 if (kIOLogDebugPower & gIOKitDebug) \
123 kprintf(x); } while (false)
125 #define PM_LOG2(x...) do { \
126 if (kIOLogDebugPower & gIOKitDebug) \
127 kprintf(x); } while (false)
130 #define PM_LOG3(x...) do { kprintf(x); } while (false)
132 #define PM_LOG3(x...)
135 #define RD_LOG(x...) do { \
136 if ((kIOLogPMRootDomain & gIOKitDebug) && \
137 (getPMRootDomain() == this)) \
138 kprintf("PMRD: " x); } while (false)
140 #define PM_ASSERT_IN_GATE(x) \
142 assert(gIOPMWorkLoop->inGate()); \
145 #define PM_LOCK() IOLockLock(fPMLock)
146 #define PM_UNLOCK() IOLockUnlock(fPMLock)
147 #define PM_LOCK_SLEEP(event, dl) IOLockSleepDeadline(fPMLock, event, dl, THREAD_UNINT)
148 #define PM_LOCK_WAKEUP(event) IOLockWakeup(fPMLock, event, false)
150 #define ns_per_us 1000
151 #define k30Seconds (30*1000000)
152 #define kMinAckTimeoutTicks (10*1000000)
153 #define kIOPMTardyAckSPSKey "IOPMTardyAckSetPowerState"
154 #define kIOPMTardyAckPSCKey "IOPMTardyAckPowerStateChange"
155 #define kPwrMgtKey "IOPowerManagement"
157 #define OUR_PMLog(t, a, b) do { \
158 if (gIOKitDebug & kIOLogPower) \
159 pwrMgt->pmPrint(t, a, b); \
160 if (gIOKitTrace & kIOTracePowerMgmt) \
161 pwrMgt->pmTrace(t, a, b); \
164 #define NS_TO_MS(nsec) ((int)((nsec) / 1000000ULL))
165 #define NS_TO_US(nsec) ((int)((nsec) / 1000ULL))
168 #define SUPPORT_IDLE_CANCEL 1
171 #define kIOPMPowerStateMax 0xFFFFFFFF
172 #define kInvalidTicklePowerState (-1)
174 #define kNoTickleCancelWindow (60ULL * 1000ULL * 1000ULL * 1000ULL)
176 #define IS_PM_ROOT (this == gIOPMRootNode)
177 #define IS_ROOT_DOMAIN (getPMRootDomain() == this)
178 #define IS_POWER_DROP (fHeadNotePowerState < fCurrentPowerState)
179 #define IS_POWER_RISE (fHeadNotePowerState > fCurrentPowerState)
181 // log setPowerStates longer than (ns):
182 #define LOG_SETPOWER_TIMES (50ULL * 1000ULL * 1000ULL)
183 // log app responses longer than (ns):
184 #define LOG_APP_RESPONSE_TIMES (100ULL * 1000ULL * 1000ULL)
185 // use message tracer to log messages longer than (ns):
186 #define LOG_APP_RESPONSE_MSG_TRACER (3 * 1000ULL * 1000ULL * 1000ULL)
189 kReserveDomainPower
= 1
193 do { assert(kIOPM_BadMachineState == fSavedMachineState); \
194 assert(kIOPM_BadMachineState != n); \
195 fSavedMachineState = n; } while (false)
198 do { assert(kIOPM_BadMachineState != fSavedMachineState); \
199 fMachineState = fSavedMachineState; \
200 fSavedMachineState = kIOPM_BadMachineState; } while (false)
202 #define PM_ACTION_0(a) \
203 do { if (fPMActions.a) { \
204 (fPMActions.a)(fPMActions.target, this, &fPMActions); } \
207 #define PM_ACTION_2(a, x, y) \
208 do { if (fPMActions.a) { \
209 (fPMActions.a)(fPMActions.target, this, &fPMActions, x, y); } \
212 static OSNumber
* copyClientIDForNotification(
214 IOPMInterestContext
*context
);
216 static void logClientIDForNotification(
218 IOPMInterestContext
*context
,
219 const char *logString
);
221 //*********************************************************************************
224 // Check kgmacros after modifying machine states.
225 //*********************************************************************************
230 kIOPM_OurChangeTellClientsPowerDown
= 1,
231 kIOPM_OurChangeTellPriorityClientsPowerDown
= 2,
232 kIOPM_OurChangeNotifyInterestedDriversWillChange
= 3,
233 kIOPM_OurChangeSetPowerState
= 4,
234 kIOPM_OurChangeWaitForPowerSettle
= 5,
235 kIOPM_OurChangeNotifyInterestedDriversDidChange
= 6,
236 kIOPM_OurChangeTellCapabilityDidChange
= 7,
237 kIOPM_OurChangeFinish
= 8,
239 kIOPM_ParentChangeTellPriorityClientsPowerDown
= 10,
240 kIOPM_ParentChangeNotifyInterestedDriversWillChange
= 11,
241 kIOPM_ParentChangeSetPowerState
= 12,
242 kIOPM_ParentChangeWaitForPowerSettle
= 13,
243 kIOPM_ParentChangeNotifyInterestedDriversDidChange
= 14,
244 kIOPM_ParentChangeTellCapabilityDidChange
= 15,
245 kIOPM_ParentChangeAcknowledgePowerChange
= 16,
247 kIOPM_NotifyChildrenStart
= 17,
248 kIOPM_NotifyChildrenOrdered
= 18,
249 kIOPM_NotifyChildrenDelayed
= 19,
250 kIOPM_SyncTellClientsPowerDown
= 20,
251 kIOPM_SyncTellPriorityClientsPowerDown
= 21,
252 kIOPM_SyncNotifyWillChange
= 22,
253 kIOPM_SyncNotifyDidChange
= 23,
254 kIOPM_SyncTellCapabilityDidChange
= 24,
255 kIOPM_SyncFinish
= 25,
256 kIOPM_TellCapabilityChangeDone
= 26,
257 kIOPM_DriverThreadCallDone
= 27,
259 kIOPM_BadMachineState
= 0xFFFFFFFF
264 Power Management defines a few roles that drivers can play in their own,
265 and other drivers', power management. We briefly define those here.
267 Many drivers implement their policy maker and power controller within the same
268 IOService object, but that is not required.
271 * Virtual IOService PM methods a "policy maker" may implement
272 * maxCapabilityForDomainState()
273 * initialPowerStateForDomainState()
274 * powerStateForDomainState()
276 * Virtual IOService PM methods a "policy maker" may CALL
279 == Power Controller ==
280 * Virtual IOService PM methods a "power controller" may implement
283 * Virtual IOService PM methods a "power controller" may CALL
285 * registerPowerDriver()
287 =======================
288 There are two different kinds of power state changes.
289 * One is initiated by a subclassed device object which has either decided
290 to change power state, or its controlling driver has suggested it, or
291 some other driver wants to use the idle device and has asked it to become
293 * The second kind of power state change is initiated by the power domain
295 The two are handled through different code paths.
297 We maintain a queue of "change notifications," or change notes.
298 * Usually the queue is empty.
299 * When it isn't, usually there is one change note in it
300 * It's possible to have more than one power state change pending at one
301 time, so a queue is implemented.
303 * The subclass device decides it's idle and initiates a change to a lower
304 power state. This causes interested parties to be notified, but they
305 don't all acknowledge right away. This causes the change note to sit
306 in the queue until all the acks are received. During this time, the
307 device decides it isn't idle anymore and wants to raise power back up
308 again. This change can't be started, however, because the previous one
309 isn't complete yet, so the second one waits in the queue. During this
310 time, the parent decides to lower or raise the power state of the entire
311 power domain and notifies the device, and that notification goes into
312 the queue, too, and can't be actioned until the others are.
315 This is how a power change initiated by the subclass device is handled:
316 -> First, all interested parties are notified of the change via their
317 powerStateWillChangeTo method. If they all don't acknowledge via return
318 code, then we have to wait. If they do, or when they finally all
319 acknowledge via our acknowledgePowerChange method, then we can continue.
320 -> We call the controlling driver, instructing it to change to the new state
321 -> Then we wait for power to settle. If there is no settling-time, or after
323 -> we notify interested parties again, this time via their
324 powerStateDidChangeTo methods.
325 -> When they have all acked, we're done.
326 If we lowered power and don't need the power domain to be in its current power
327 state, we suggest to the parent that it lower the power domain state.
329 == PowerDomainDownInitiated ==
330 How a change to a lower power domain state initiated by the parent is handled:
331 -> First, we figure out what power state we will be in when the new domain
333 -> Then all interested parties are notified that we are moving to that new
335 -> When they have acknowledged, we call the controlling driver to assume
336 that state and we wait for power to settle.
337 -> Then we acknowledge our preparedness to our parent. When all its
338 interested parties have acknowledged,
339 -> it lowers power and then notifies its interested parties again.
340 -> When we get this call, we notify our interested parties that the power
341 state has changed, and when they have all acknowledged, we're done.
343 == PowerDomainUpInitiated ==
344 How a change to a higher power domain state initiated by the parent is handled:
345 -> We figure out what power state we will be in when the new domain state is
347 -> If it is different from our current state we acknowledge the parent.
348 -> When all the parent's interested parties have acknowledged, it raises
349 power in the domain and waits for power to settle.
350 -> Then it notifies everyone that the new state has been reached.
351 -> When we get this call, we call the controlling driver, instructing it to
352 assume the new state, and wait for power to settle.
353 -> Then we notify our interested parties. When they all acknowledge we are
356 In either of the two power domain state cases above, it is possible that we
357 will not be changing state even though the domain is.
359 * A change to a lower domain state may not affect us because we are already
360 in a low enough state,
361 * We will not take advantage of a change to a higher domain state, because
362 we have no need of the higher power. In such cases, there is nothing to
363 do but acknowledge the parent. So when the parent calls our
364 powerDomainWillChange method, and we decide that we will not be changing
365 state, we merely acknowledge the parent, via return code, and wait.
366 When the parent subsequently calls powerStateDidChange, we acknowledge again
367 via return code, and the change is complete.
369 == 4 Paths Through State Machine ==
370 Power state changes are processed in a state machine, and since there are four
371 varieties of power state changes, there are four major paths through the state
374 == 5. No Need To change ==
375 The fourth is nearly trivial. In this path, the parent is changing the domain
376 state, but we are not changing the device state. The change starts when the
377 parent calls powerDomainWillChange. All we do is acknowledge the parent. When
378 the parent calls powerStateDidChange, we acknowledge the parent again, and
381 == 1. OurChange Down == XXX gvdl
382 The first is fairly simple. It starts:
383 * when a power domain child calls requestPowerDomainState and we decide to
384 change power states to accomodate the child,
385 * or if our power-controlling driver calls changePowerStateTo,
386 * or if some other driver which is using our device calls makeUsable,
387 * or if a subclassed object calls changePowerStateToPriv.
388 These are all power changes initiated by us, not forced upon us by the parent.
390 -> We start by notifying interested parties.
391 -> If they all acknowledge via return code, we can go on to state
393 -> Otherwise, we start the ack timer and wait for the stragglers to
394 acknowlege by calling acknowledgePowerChange.
395 -> We move on to state "msSetPowerState" when all the
396 stragglers have acknowledged, or when the ack timer expires on
397 all those which didn't acknowledge.
398 In "msSetPowerState" we call the power-controlling driver to change the
399 power state of the hardware.
400 -> If it returns saying it has done so, we go on to state
401 "msWaitForPowerSettle".
402 -> Otherwise, we have to wait for it, so we set the ack timer and wait.
403 -> When it calls acknowledgeSetPowerState, or when the ack timer
405 In "msWaitForPowerSettle", we look in the power state array to see if
406 there is any settle time required when changing from our current state to the
408 -> If not, we go right away to "msNotifyInterestedDriversDidChange".
409 -> Otherwise, we set the settle timer and wait. When it expires, we move on.
410 In "msNotifyInterestedDriversDidChange" state, we notify all our
411 interested parties via their powerStateDidChange methods that we have finished
412 changing power state.
413 -> If they all acknowledge via return code, we move on to "msFinish".
414 -> Otherwise we set the ack timer and wait. When they have all
415 acknowledged, or when the ack timer has expired for those that didn't,
416 we move on to "msFinish".
417 In "msFinish" we remove the used change note from the head of the queue
418 and start the next one if one exists.
420 == 2. Parent Change Down ==
421 Start at Stage 2 of OurChange Down XXX gvdl
424 Start at Stage 4 of OurChange Down XXX gvdl
426 Note all parent requested changes need to acknowledge the power has changed to the parent when done.
429 //*********************************************************************************
432 // Initialize power management.
433 //*********************************************************************************
435 void IOService::PMinit ( void )
439 if ( !gIOPMInitialized
)
441 gPlatform
= getPlatform();
442 gIOPMWorkLoop
= IOWorkLoop::workLoop();
445 gIOPMRequestQueue
= IOPMRequestQueue::create(
446 this, OSMemberFunctionCast(IOPMRequestQueue::Action
,
447 this, &IOService::servicePMRequestQueue
));
449 gIOPMReplyQueue
= IOPMRequestQueue::create(
450 this, OSMemberFunctionCast(IOPMRequestQueue::Action
,
451 this, &IOService::servicePMReplyQueue
));
453 gIOPMWorkQueue
= IOPMWorkQueue::create(
455 OSMemberFunctionCast(IOPMWorkQueue::Action
, this,
456 &IOService::servicePMRequest
),
457 OSMemberFunctionCast(IOPMWorkQueue::Action
, this,
458 &IOService::retirePMRequest
));
460 gIOPMFreeQueue
= IOPMCompletionQueue::create(
461 this, OSMemberFunctionCast(IOPMCompletionQueue::Action
,
462 this, &IOService::servicePMFreeQueue
));
464 if (gIOPMWorkLoop
->addEventSource(gIOPMRequestQueue
) !=
467 gIOPMRequestQueue
->release();
468 gIOPMRequestQueue
= 0;
471 if (gIOPMWorkLoop
->addEventSource(gIOPMReplyQueue
) !=
474 gIOPMReplyQueue
->release();
478 if (gIOPMWorkLoop
->addEventSource(gIOPMWorkQueue
) !=
481 gIOPMWorkQueue
->release();
485 if (gIOPMWorkLoop
->addEventSource(gIOPMFreeQueue
) !=
488 gIOPMFreeQueue
->release();
492 gIOPMPowerClientDevice
=
493 OSSymbol::withCStringNoCopy( "DevicePowerState" );
495 gIOPMPowerClientDriver
=
496 OSSymbol::withCStringNoCopy( "DriverPowerState" );
498 gIOPMPowerClientChildProxy
=
499 OSSymbol::withCStringNoCopy( "ChildProxyPowerState" );
501 gIOPMPowerClientChildren
=
502 OSSymbol::withCStringNoCopy( "ChildrenPowerState" );
504 gIOPMPowerClientAdvisoryTickle
=
505 OSSymbol::withCStringNoCopy( "AdvisoryTicklePowerState" );
508 if (gIOPMRequestQueue
&& gIOPMReplyQueue
&& gIOPMFreeQueue
)
509 gIOPMInitialized
= true;
511 if (!gIOPMInitialized
)
514 pwrMgt
= new IOServicePM
;
516 setProperty(kPwrMgtKey
, pwrMgt
);
518 queue_init(&pwrMgt
->WorkChain
);
519 queue_init(&pwrMgt
->RequestHead
);
520 queue_init(&pwrMgt
->PMDriverCallQueue
);
523 fPMLock
= IOLockAlloc();
524 fInterestedDrivers
= new IOPMinformeeList
;
525 fInterestedDrivers
->initialize();
526 fDesiredPowerState
= 0;
528 fInitialPowerChange
= true;
529 fInitialSetPowerState
= true;
530 fPreviousRequestPowerFlags
= 0;
531 fDeviceOverrideEnabled
= false;
532 fMachineState
= kIOPM_Finished
;
533 fSavedMachineState
= kIOPM_BadMachineState
;
534 fIdleTimerMinPowerState
= 0;
535 fActivityLock
= IOLockAlloc();
536 fStrictTreeOrder
= false;
537 fActivityTicklePowerState
= kInvalidTicklePowerState
;
538 fAdvisoryTicklePowerState
= kInvalidTicklePowerState
;
539 fControllingDriver
= NULL
;
541 fNumberOfPowerStates
= 0;
542 fCurrentPowerState
= 0;
543 fParentsCurrentPowerFlags
= 0;
546 fParentsKnowState
= false;
548 fResponseArray
= NULL
;
549 fNotifyClientArray
= NULL
;
550 fCurrentPowerConsumption
= kIOPMUnknown
;
551 fOverrideMaxPowerState
= kIOPMPowerStateMax
;
553 if (!gIOPMRootNode
&& (getParentEntry(gIOPowerPlane
) == getRegistryRoot()))
555 gIOPMRootNode
= this;
556 fParentsKnowState
= true;
559 fAckTimer
= thread_call_allocate(
560 &IOService::ack_timer_expired
, (thread_call_param_t
)this);
561 fSettleTimer
= thread_call_allocate(
562 &settle_timer_expired
, (thread_call_param_t
)this);
563 fIdleTimer
= thread_call_allocate(
564 &idle_timer_expired
, (thread_call_param_t
)this);
565 fDriverCallEntry
= thread_call_allocate(
566 (thread_call_func_t
) &IOService::pmDriverCallout
, this);
567 assert(fDriverCallEntry
);
569 // Check for powerChangeDone override.
570 if (OSMemberFunctionCast(void (*)(void),
571 getResourceService(), &IOService::powerChangeDone
) !=
572 OSMemberFunctionCast(void (*)(void),
573 this, &IOService::powerChangeDone
))
575 fPCDFunctionOverride
= true;
579 IOPMprot
* prot
= new IOPMprot
;
583 prot
->ourName
= fName
;
584 prot
->thePlatform
= gPlatform
;
589 pm_vars
= (void *) (uintptr_t) true;
596 //*********************************************************************************
599 // Free the data created by PMinit. Only called from IOService::free().
600 //*********************************************************************************
602 void IOService::PMfree ( void )
609 assert(fMachineState
== kIOPM_Finished
);
610 assert(fInsertInterestSet
== NULL
);
611 assert(fRemoveInterestSet
== NULL
);
612 assert(fNotifyChildArray
== NULL
);
613 assert(queue_empty(&pwrMgt
->RequestHead
));
614 assert(queue_empty(&fPMDriverCallQueue
));
616 if ( fSettleTimer
) {
617 thread_call_cancel(fSettleTimer
);
618 thread_call_free(fSettleTimer
);
622 thread_call_cancel(fAckTimer
);
623 thread_call_free(fAckTimer
);
627 thread_call_cancel(fIdleTimer
);
628 thread_call_free(fIdleTimer
);
631 if ( fDriverCallEntry
) {
632 thread_call_free(fDriverCallEntry
);
633 fDriverCallEntry
= NULL
;
639 if ( fActivityLock
) {
640 IOLockFree(fActivityLock
);
641 fActivityLock
= NULL
;
643 if ( fInterestedDrivers
) {
644 fInterestedDrivers
->release();
645 fInterestedDrivers
= NULL
;
647 if (fDriverCallParamSlots
&& fDriverCallParamPtr
) {
648 IODelete(fDriverCallParamPtr
, DriverCallParam
, fDriverCallParamSlots
);
649 fDriverCallParamPtr
= 0;
650 fDriverCallParamSlots
= 0;
652 if ( fResponseArray
) {
653 fResponseArray
->release();
654 fResponseArray
= NULL
;
656 if ( fNotifyClientArray
) {
657 fNotifyClientArray
->release();
658 fNotifyClientArray
= NULL
;
660 if (fPowerStates
&& fNumberOfPowerStates
) {
661 IODelete(fPowerStates
, IOPMPSEntry
, fNumberOfPowerStates
);
662 fNumberOfPowerStates
= 0;
666 fPowerClients
->release();
683 void IOService::PMDebug( uint32_t event
, uintptr_t param1
, uintptr_t param2
)
685 OUR_PMLog(event
, param1
, param2
);
688 //*********************************************************************************
689 // [public] joinPMtree
691 // A policy-maker calls its nub here when initializing, to be attached into
692 // the power management hierarchy. The default function is to call the
693 // platform expert, which knows how to do it. This method is overridden
694 // by a nub subclass which may either know how to do it, or may need to
695 // take other action.
697 // This may be the only "power management" method used in a nub,
698 // meaning it may not be initialized for power management.
699 //*********************************************************************************
701 void IOService::joinPMtree ( IOService
* driver
)
703 IOPlatformExpert
* platform
;
705 platform
= getPlatform();
706 assert(platform
!= 0);
707 platform
->PMRegisterDevice(this, driver
);
711 //*********************************************************************************
712 // [deprecated] youAreRoot
714 // Power Managment is informing us that we are the root power domain.
715 //*********************************************************************************
717 IOReturn
IOService::youAreRoot ( void )
721 #endif /* !__LP64__ */
723 //*********************************************************************************
726 // Immediately stop driver callouts. Schedule an async stop request to detach
728 //*********************************************************************************
730 void IOService::PMstop ( void )
732 IOPMRequest
* request
;
739 if (fLockedFlags
.PMStop
)
741 PM_LOG2("%s: PMstop() already stopped\n", fName
);
746 // Inhibit future driver calls.
747 fLockedFlags
.PMStop
= true;
749 // Wait for all prior driver calls to finish.
750 waitForPMDriverCall();
754 // The rest of the work is performed async.
755 request
= acquirePMRequest( this, kIOPMRequestTypePMStop
);
758 PM_LOG2("%s: %p PMstop\n", getName(), this);
759 submitPMRequest( request
);
763 //*********************************************************************************
764 // [private] handlePMstop
766 // Disconnect the node from all parents and children in the power plane.
767 //*********************************************************************************
769 void IOService::handlePMstop ( IOPMRequest
* request
)
773 IOPowerConnection
* connection
;
774 IOService
* theChild
;
775 IOService
* theParent
;
778 PM_LOG2("%s: %p %s start\n", getName(), this, __FUNCTION__
);
780 // remove driver from prevent system sleep lists
781 getPMRootDomain()->updatePreventIdleSleepList(this, false);
782 getPMRootDomain()->updatePreventSystemSleepList(this, false);
784 // remove the property
785 removeProperty(kPwrMgtKey
);
788 iter
= getParentIterator(gIOPowerPlane
);
791 while ( (next
= iter
->getNextObject()) )
793 if ( (connection
= OSDynamicCast(IOPowerConnection
, next
)) )
795 theParent
= (IOService
*)connection
->copyParentEntry(gIOPowerPlane
);
798 theParent
->removePowerChild(connection
);
799 theParent
->release();
806 // detach IOConnections
807 detachAbove( gIOPowerPlane
);
809 // no more power state changes
810 fParentsKnowState
= false;
813 iter
= getChildIterator(gIOPowerPlane
);
816 while ( (next
= iter
->getNextObject()) )
818 if ( (connection
= OSDynamicCast(IOPowerConnection
, next
)) )
820 theChild
= ((IOService
*)(connection
->copyChildEntry(gIOPowerPlane
)));
823 // detach nub from child
824 connection
->detachFromChild(theChild
, gIOPowerPlane
);
827 // detach us from nub
828 detachFromChild(connection
, gIOPowerPlane
);
834 // Remove all interested drivers from the list, including the power
835 // controlling driver.
837 // Usually, the controlling driver and the policy-maker functionality
838 // are implemented by the same object, and without the deregistration,
839 // the object will be holding an extra retain on itself, and cannot
842 if ( fInterestedDrivers
)
844 IOPMinformeeList
* list
= fInterestedDrivers
;
848 while ((item
= list
->firstInList()))
850 list
->removeFromList(item
->whatObject
);
855 // Tell idleTimerExpired() to ignore idle timer.
856 fIdleTimerPeriod
= 0;
857 if (fIdleTimer
&& thread_call_cancel(fIdleTimer
))
860 PM_LOG2("%s: %p %s done\n", getName(), this, __FUNCTION__
);
863 //*********************************************************************************
864 // [public] addPowerChild
866 // Power Management is informing us who our children are.
867 //*********************************************************************************
869 IOReturn
IOService::addPowerChild ( IOService
* child
)
871 IOPowerConnection
* connection
= 0;
872 IOPMRequest
* requests
[3] = {0, 0, 0};
877 return kIOReturnBadArgument
;
879 if (!initialized
|| !child
->initialized
)
880 return IOPMNotYetInitialized
;
882 OUR_PMLog( kPMLogAddChild
, (uintptr_t) child
, 0 );
885 // Is this child already one of our children?
887 iter
= child
->getParentIterator( gIOPowerPlane
);
890 IORegistryEntry
* entry
;
893 while ((next
= iter
->getNextObject()))
895 if ((entry
= OSDynamicCast(IORegistryEntry
, next
)) &&
896 isChild(entry
, gIOPowerPlane
))
906 PM_LOG("%s: %s (%p) is already a child\n",
907 getName(), child
->getName(), child
);
911 // Add the child to the power plane immediately, but the
912 // joining connection is marked as not ready.
913 // We want the child to appear in the power plane before
914 // returning to the caller, but don't want the caller to
915 // block on the PM work loop.
917 connection
= new IOPowerConnection
;
921 // Create a chain of PM requests to perform the bottom-half
922 // work from the PM work loop.
924 requests
[0] = acquirePMRequest(
926 /* type */ kIOPMRequestTypeAddPowerChild1
);
928 requests
[1] = acquirePMRequest(
930 /* type */ kIOPMRequestTypeAddPowerChild2
);
932 requests
[2] = acquirePMRequest(
934 /* type */ kIOPMRequestTypeAddPowerChild3
);
936 if (!requests
[0] || !requests
[1] || !requests
[2])
939 requests
[0]->attachNextRequest( requests
[1] );
940 requests
[1]->attachNextRequest( requests
[2] );
943 connection
->start(this);
944 connection
->setAwaitingAck(false);
945 connection
->setReadyFlag(false);
947 attachToChild( connection
, gIOPowerPlane
);
948 connection
->attachToChild( child
, gIOPowerPlane
);
950 // connection needs to be released
951 requests
[0]->fArg0
= connection
;
952 requests
[1]->fArg0
= connection
;
953 requests
[2]->fArg0
= connection
;
955 submitPMRequest( requests
, 3 );
956 return kIOReturnSuccess
;
960 if (connection
) connection
->release();
961 if (requests
[0]) releasePMRequest(requests
[0]);
962 if (requests
[1]) releasePMRequest(requests
[1]);
963 if (requests
[2]) releasePMRequest(requests
[2]);
965 // Silent failure, to prevent platform drivers from adding the child
966 // to the root domain.
968 return kIOReturnSuccess
;
971 //*********************************************************************************
972 // [private] addPowerChild1
974 // Step 1/3 of adding a power child. Called on the power parent.
975 //*********************************************************************************
977 void IOService::addPowerChild1 ( IOPMRequest
* request
)
979 unsigned long tempDesire
= 0;
981 // Make us temporary usable before adding the child.
984 OUR_PMLog( kPMLogMakeUsable
, kPMLogMakeUsable
, 0 );
986 if (fControllingDriver
&& inPlane(gIOPowerPlane
) && fParentsKnowState
)
988 tempDesire
= fNumberOfPowerStates
- 1;
991 if (tempDesire
&& (IS_PM_ROOT
|| (fMaxPowerState
>= tempDesire
)))
993 adjustPowerState(tempDesire
);
997 //*********************************************************************************
998 // [private] addPowerChild2
1000 // Step 2/3 of adding a power child. Called on the joining child.
1001 // Execution blocked behind addPowerChild1.
1002 //*********************************************************************************
1004 void IOService::addPowerChild2 ( IOPMRequest
* request
)
1006 IOPowerConnection
* connection
= (IOPowerConnection
*) request
->fArg0
;
1008 IOPMPowerFlags powerFlags
;
1010 unsigned long powerState
;
1011 unsigned long tempDesire
;
1013 PM_ASSERT_IN_GATE();
1014 parent
= (IOService
*) connection
->getParentEntry(gIOPowerPlane
);
1016 if (!parent
|| !inPlane(gIOPowerPlane
))
1018 PM_LOG("%s: addPowerChild2 not in power plane\n", getName());
1022 // Parent will be waiting for us to complete this stage.
1023 // It is safe to directly access parent's vars.
1025 knowsState
= (parent
->fPowerStates
) && (parent
->fParentsKnowState
);
1026 powerState
= parent
->fCurrentPowerState
;
1029 powerFlags
= parent
->fPowerStates
[powerState
].outputPowerFlags
;
1033 // Set our power parent.
1035 OUR_PMLog(kPMLogSetParent
, knowsState
, powerFlags
);
1037 setParentInfo( powerFlags
, connection
, knowsState
);
1039 connection
->setReadyFlag(true);
1041 if ( fControllingDriver
&& fParentsKnowState
)
1043 fMaxPowerState
= fControllingDriver
->maxCapabilityForDomainState(fParentsCurrentPowerFlags
);
1044 // initially change into the state we are already in
1045 tempDesire
= fControllingDriver
->initialPowerStateForDomainState(fParentsCurrentPowerFlags
);
1046 fPreviousRequestPowerFlags
= (IOPMPowerFlags
)(-1);
1047 adjustPowerState(tempDesire
);
1050 getPMRootDomain()->tagPowerPlaneService(this, &fPMActions
);
1053 //*********************************************************************************
1054 // [private] addPowerChild3
1056 // Step 3/3 of adding a power child. Called on the parent.
1057 // Execution blocked behind addPowerChild2.
1058 //*********************************************************************************
1060 void IOService::addPowerChild3 ( IOPMRequest
* request
)
1062 IOPowerConnection
* connection
= (IOPowerConnection
*) request
->fArg0
;
1064 IOPMrootDomain
* rootDomain
= getPMRootDomain();
1066 PM_ASSERT_IN_GATE();
1067 child
= (IOService
*) connection
->getChildEntry(gIOPowerPlane
);
1069 if (child
&& inPlane(gIOPowerPlane
))
1071 if ((this != rootDomain
) && child
->getProperty("IOPMStrictTreeOrder"))
1073 PM_LOG1("%s: strict PM order enforced\n", getName());
1074 fStrictTreeOrder
= true;
1078 rootDomain
->joinAggressiveness( child
);
1082 PM_LOG("%s: addPowerChild3 not in power plane\n", getName());
1085 connection
->release();
1089 //*********************************************************************************
1090 // [deprecated] setPowerParent
1092 // Power Management is informing us who our parent is.
1093 // If we have a controlling driver, find out, given our newly-informed
1094 // power domain state, what state it would be in, and then tell it
1095 // to assume that state.
1096 //*********************************************************************************
1098 IOReturn
IOService::setPowerParent (
1099 IOPowerConnection
* theParent
, bool stateKnown
, IOPMPowerFlags powerFlags
)
1101 return kIOReturnUnsupported
;
1103 #endif /* !__LP64__ */
1105 //*********************************************************************************
1106 // [public] removePowerChild
1108 // Called on a parent whose child is being removed by PMstop().
1109 //*********************************************************************************
1111 IOReturn
IOService::removePowerChild ( IOPowerConnection
* theNub
)
1113 IORegistryEntry
* theChild
;
1115 PM_ASSERT_IN_GATE();
1116 OUR_PMLog( kPMLogRemoveChild
, 0, 0 );
1120 // detach nub from child
1121 theChild
= theNub
->copyChildEntry(gIOPowerPlane
);
1124 theNub
->detachFromChild(theChild
, gIOPowerPlane
);
1125 theChild
->release();
1127 // detach from the nub
1128 detachFromChild(theNub
, gIOPowerPlane
);
1130 // Are we awaiting an ack from this child?
1131 if ( theNub
->getAwaitingAck() )
1133 // yes, pretend we got one
1134 theNub
->setAwaitingAck(false);
1135 if (fHeadNotePendingAcks
!= 0 )
1137 // that's one fewer ack to worry about
1138 fHeadNotePendingAcks
--;
1140 // is that the last?
1141 if ( fHeadNotePendingAcks
== 0 )
1145 // Request unblocked, work queue
1146 // should re-scan all busy requests.
1147 gIOPMWorkQueue
->incrementProducerCount();
1154 // A child has gone away, re-scan children desires and clamp bits.
1155 // The fPendingAdjustPowerRequest helps to reduce redundant parent work.
1157 if (!fAdjustPowerScheduled
)
1159 IOPMRequest
* request
;
1160 request
= acquirePMRequest( this, kIOPMRequestTypeAdjustPowerState
);
1163 submitPMRequest( request
);
1164 fAdjustPowerScheduled
= true;
1171 //*********************************************************************************
1172 // [public] registerPowerDriver
1174 // A driver has called us volunteering to control power to our device.
1175 //*********************************************************************************
1177 IOReturn
IOService::registerPowerDriver (
1178 IOService
* powerDriver
,
1179 IOPMPowerState
* powerStates
,
1180 unsigned long numberOfStates
)
1182 IOPMRequest
* request
;
1183 IOPMPSEntry
* powerStatesCopy
= 0;
1186 return IOPMNotYetInitialized
;
1188 // Validate arguments.
1189 if (!powerStates
|| (numberOfStates
< 2))
1191 OUR_PMLog(kPMLogControllingDriverErr5
, numberOfStates
, 0);
1192 return kIOReturnBadArgument
;
1195 if (!powerDriver
|| !powerDriver
->initialized
)
1197 OUR_PMLog(kPMLogControllingDriverErr4
, 0, 0);
1198 return kIOReturnBadArgument
;
1201 if (powerStates
[0].version
!= kIOPMPowerStateVersion1
)
1203 OUR_PMLog(kPMLogControllingDriverErr1
, powerStates
[0].version
, 0);
1204 return kIOReturnBadArgument
;
1208 // Make a copy of the supplied power state array.
1209 powerStatesCopy
= IONew(IOPMPSEntry
, numberOfStates
);
1210 if (!powerStatesCopy
)
1213 for (uint32_t i
= 0; i
< numberOfStates
; i
++)
1215 powerStatesCopy
[i
].capabilityFlags
= powerStates
[i
].capabilityFlags
;
1216 powerStatesCopy
[i
].outputPowerFlags
= powerStates
[i
].outputPowerCharacter
;
1217 powerStatesCopy
[i
].inputPowerFlags
= powerStates
[i
].inputPowerRequirement
;
1218 powerStatesCopy
[i
].staticPower
= powerStates
[i
].staticPower
;
1219 powerStatesCopy
[i
].settleUpTime
= powerStates
[i
].settleUpTime
;
1220 powerStatesCopy
[i
].settleDownTime
= powerStates
[i
].settleDownTime
;
1223 request
= acquirePMRequest( this, kIOPMRequestTypeRegisterPowerDriver
);
1227 powerDriver
->retain();
1228 request
->fArg0
= (void *) powerDriver
;
1229 request
->fArg1
= (void *) powerStatesCopy
;
1230 request
->fArg2
= (void *) numberOfStates
;
1232 submitPMRequest( request
);
1233 return kIOReturnSuccess
;
1237 if (powerStatesCopy
)
1238 IODelete(powerStatesCopy
, IOPMPSEntry
, numberOfStates
);
1239 return kIOReturnNoMemory
;
1242 //*********************************************************************************
1243 // [private] handleRegisterPowerDriver
1244 //*********************************************************************************
1246 void IOService::handleRegisterPowerDriver ( IOPMRequest
* request
)
1248 IOService
* powerDriver
= (IOService
*) request
->fArg0
;
1249 IOPMPSEntry
* powerStates
= (IOPMPSEntry
*) request
->fArg1
;
1250 unsigned long numberOfStates
= (unsigned long) request
->fArg2
;
1255 PM_ASSERT_IN_GATE();
1256 assert(powerStates
);
1257 assert(powerDriver
);
1258 assert(numberOfStates
> 1);
1260 if ( !fNumberOfPowerStates
)
1262 OUR_PMLog(kPMLogControllingDriver
,
1263 (unsigned long) numberOfStates
,
1264 (unsigned long) kIOPMPowerStateVersion1
);
1266 fPowerStates
= powerStates
;
1267 fNumberOfPowerStates
= numberOfStates
;
1268 fControllingDriver
= powerDriver
;
1269 fCurrentCapabilityFlags
= fPowerStates
[0].capabilityFlags
;
1271 // make a mask of all the character bits we know about
1272 fOutputPowerCharacterFlags
= 0;
1273 for ( i
= 0; i
< numberOfStates
; i
++ ) {
1274 fOutputPowerCharacterFlags
|= fPowerStates
[i
].outputPowerFlags
;
1275 if (!fDeviceUsablePowerState
&&
1276 (fPowerStates
[i
].capabilityFlags
& IOPMDeviceUsable
))
1278 // The minimum power state that the device is usable
1279 fDeviceUsablePowerState
= i
;
1283 // Register powerDriver as interested, unless already done.
1284 // We don't want to register the default implementation since
1285 // it does nothing. One ramification of not always registering
1286 // is the one fewer retain count held.
1288 root
= getPlatform()->getProvider();
1291 ((OSMemberFunctionCast(void (*)(void),
1292 root
, &IOService::powerStateDidChangeTo
)) !=
1293 ((OSMemberFunctionCast(void (*)(void),
1294 this, &IOService::powerStateDidChangeTo
)))) ||
1295 ((OSMemberFunctionCast(void (*)(void),
1296 root
, &IOService::powerStateWillChangeTo
)) !=
1297 ((OSMemberFunctionCast(void (*)(void),
1298 this, &IOService::powerStateWillChangeTo
)))))
1300 if (fInterestedDrivers
->findItem(powerDriver
) == NULL
)
1303 fInterestedDrivers
->appendNewInformee(powerDriver
);
1308 // Examine all existing power clients and perform limit check.
1312 iter
= OSCollectionIterator::withCollection(fPowerClients
);
1315 const OSSymbol
* client
;
1316 while ((client
= (const OSSymbol
*) iter
->getNextObject()))
1318 uint32_t powerState
= getPowerStateForClient(client
);
1319 if (powerState
>= numberOfStates
)
1321 updatePowerClient(client
, numberOfStates
- 1);
1328 if ( inPlane(gIOPowerPlane
) && fParentsKnowState
)
1330 unsigned long tempDesire
;
1331 fMaxPowerState
= fControllingDriver
->maxCapabilityForDomainState(fParentsCurrentPowerFlags
);
1332 // initially change into the state we are already in
1333 tempDesire
= fControllingDriver
->initialPowerStateForDomainState(fParentsCurrentPowerFlags
);
1334 adjustPowerState(tempDesire
);
1339 OUR_PMLog(kPMLogControllingDriverErr2
, numberOfStates
, 0);
1340 IODelete(powerStates
, IOPMPSEntry
, numberOfStates
);
1343 powerDriver
->release();
1346 //*********************************************************************************
1347 // [public] registerInterestedDriver
1349 // Add the caller to our list of interested drivers and return our current
1350 // power state. If we don't have a power-controlling driver yet, we will
1351 // call this interested driver again later when we do get a driver and find
1352 // out what the current power state of the device is.
1353 //*********************************************************************************
1355 IOPMPowerFlags
IOService::registerInterestedDriver ( IOService
* driver
)
1357 IOPMRequest
* request
;
1360 if (!driver
|| !initialized
|| !fInterestedDrivers
)
1364 signal
= (!fInsertInterestSet
&& !fRemoveInterestSet
);
1365 if (fInsertInterestSet
== NULL
)
1366 fInsertInterestSet
= OSSet::withCapacity(4);
1367 if (fInsertInterestSet
)
1369 fInsertInterestSet
->setObject(driver
);
1370 if (fRemoveInterestSet
)
1371 fRemoveInterestSet
->removeObject(driver
);
1377 request
= acquirePMRequest( this, kIOPMRequestTypeInterestChanged
);
1379 submitPMRequest( request
);
1382 // This return value cannot be trusted, but return a value
1383 // for those clients that care.
1385 OUR_PMLog(kPMLogInterestedDriver
, kIOPMDeviceUsable
, 2);
1386 return kIOPMDeviceUsable
;
1389 //*********************************************************************************
1390 // [public] deRegisterInterestedDriver
1391 //*********************************************************************************
1393 IOReturn
IOService::deRegisterInterestedDriver ( IOService
* driver
)
1395 IOPMinformeeList
* list
;
1396 IOPMinformee
* item
;
1397 IOPMRequest
* request
;
1401 return kIOReturnBadArgument
;
1402 if (!initialized
|| !fInterestedDrivers
)
1403 return IOPMNotPowerManaged
;
1406 signal
= (!fRemoveInterestSet
&& !fInsertInterestSet
);
1407 if (fRemoveInterestSet
== NULL
)
1408 fRemoveInterestSet
= OSSet::withCapacity(4);
1409 if (fRemoveInterestSet
)
1411 fRemoveInterestSet
->setObject(driver
);
1412 if (fInsertInterestSet
)
1413 fInsertInterestSet
->removeObject(driver
);
1415 list
= fInterestedDrivers
;
1416 item
= list
->findItem(driver
);
1417 if (item
&& item
->active
)
1419 item
->active
= false;
1420 waitForPMDriverCall( driver
);
1427 request
= acquirePMRequest( this, kIOPMRequestTypeInterestChanged
);
1429 submitPMRequest( request
);
1435 //*********************************************************************************
1436 // [private] handleInterestChanged
1438 // Handle interest added or removed.
1439 //*********************************************************************************
1441 void IOService::handleInterestChanged( IOPMRequest
* request
)
1444 IOPMinformee
* informee
;
1445 IOPMinformeeList
* list
= fInterestedDrivers
;
1449 if (fInsertInterestSet
)
1451 while ((driver
= (IOService
*) fInsertInterestSet
->getAnyObject()))
1453 if (list
->findItem(driver
) == NULL
)
1455 informee
= list
->appendNewInformee(driver
);
1457 fInsertInterestSet
->removeObject(driver
);
1459 fInsertInterestSet
->release();
1460 fInsertInterestSet
= 0;
1463 if (fRemoveInterestSet
)
1465 while ((driver
= (IOService
*) fRemoveInterestSet
->getAnyObject()))
1467 informee
= list
->findItem(driver
);
1470 // Clean-up async interest acknowledgement
1471 if (fHeadNotePendingAcks
&& informee
->timer
)
1473 informee
->timer
= 0;
1474 fHeadNotePendingAcks
--;
1476 list
->removeFromList(driver
);
1478 fRemoveInterestSet
->removeObject(driver
);
1480 fRemoveInterestSet
->release();
1481 fRemoveInterestSet
= 0;
1487 //*********************************************************************************
1488 // [public] acknowledgePowerChange
1490 // After we notified one of the interested drivers or a power-domain child
1491 // of an impending change in power, it has called to say it is now
1492 // prepared for the change. If this object is the last to
1493 // acknowledge this change, we take whatever action we have been waiting
1495 // That may include acknowledging to our parent. In this case, we do it
1496 // last of all to insure that this doesn't cause the parent to call us some-
1497 // where else and alter data we are relying on here (like the very existance
1498 // of a "current change note".)
1499 //*********************************************************************************
1501 IOReturn
IOService::acknowledgePowerChange ( IOService
* whichObject
)
1503 IOPMRequest
* request
;
1506 return IOPMNotYetInitialized
;
1508 return kIOReturnBadArgument
;
1510 request
= acquirePMRequest( this, kIOPMRequestTypeAckPowerChange
);
1512 return kIOReturnNoMemory
;
1514 whichObject
->retain();
1515 request
->fArg0
= whichObject
;
1517 submitPMRequest( request
);
1521 //*********************************************************************************
1522 // [private] handleAcknowledgePowerChange
1523 //*********************************************************************************
1525 bool IOService::handleAcknowledgePowerChange ( IOPMRequest
* request
)
1527 IOPMinformee
* informee
;
1528 unsigned long childPower
= kIOPMUnknown
;
1529 IOService
* theChild
;
1530 IOService
* whichObject
;
1531 bool all_acked
= false;
1533 PM_ASSERT_IN_GATE();
1534 whichObject
= (IOService
*) request
->fArg0
;
1535 assert(whichObject
);
1537 // one of our interested drivers?
1538 informee
= fInterestedDrivers
->findItem( whichObject
);
1539 if ( informee
== NULL
)
1541 if ( !isChild(whichObject
, gIOPowerPlane
) )
1543 OUR_PMLog(kPMLogAcknowledgeErr1
, 0, 0);
1546 OUR_PMLog(kPMLogChildAcknowledge
, fHeadNotePendingAcks
, 0);
1549 OUR_PMLog(kPMLogDriverAcknowledge
, fHeadNotePendingAcks
, 0);
1552 if ( fHeadNotePendingAcks
!= 0 )
1554 assert(fPowerStates
!= NULL
);
1556 // yes, make sure we're expecting acks
1557 if ( informee
!= NULL
)
1559 // it's an interested driver
1560 // make sure we're expecting this ack
1561 if ( informee
->timer
!= 0 )
1563 #if LOG_SETPOWER_TIMES
1564 if (informee
->timer
> 0)
1566 uint64_t nsec
= computeTimeDeltaNS(&informee
->startTime
);
1567 if (nsec
> LOG_SETPOWER_TIMES
)
1568 PM_LOG("%s::powerState%sChangeTo(%p, %s, %lu -> %lu) async took %d ms\n",
1569 informee
->whatObject
->getName(),
1570 (fDriverCallReason
== kDriverCallInformPreChange
) ? "Will" : "Did",
1571 informee
->whatObject
,
1572 fName
, fCurrentPowerState
, fHeadNotePowerState
, NS_TO_US(nsec
));
1574 uint16_t logType
= (fDriverCallReason
== kDriverCallInformPreChange
)
1575 ? kIOPMEventTypePSWillChangeTo
1576 : kIOPMEventTypePSDidChangeTo
;
1578 PMEventDetails
*details
= PMEventDetails::eventDetails(
1582 informee
->whatObject
->getName(),
1586 getPMRootDomain()->recordAndReleasePMEventGated( details
);
1590 informee
->timer
= 0;
1591 // that's one fewer to worry about
1592 fHeadNotePendingAcks
--;
1594 // this driver has already acked
1595 OUR_PMLog(kPMLogAcknowledgeErr2
, 0, 0);
1599 // make sure we're expecting this ack
1600 if ( ((IOPowerConnection
*)whichObject
)->getAwaitingAck() )
1602 // that's one fewer to worry about
1603 fHeadNotePendingAcks
--;
1604 ((IOPowerConnection
*)whichObject
)->setAwaitingAck(false);
1605 theChild
= (IOService
*)whichObject
->copyChildEntry(gIOPowerPlane
);
1608 childPower
= theChild
->currentPowerConsumption();
1609 theChild
->release();
1611 if ( childPower
== kIOPMUnknown
)
1613 fHeadNotePowerArrayEntry
->staticPower
= kIOPMUnknown
;
1615 if (fHeadNotePowerArrayEntry
->staticPower
!= kIOPMUnknown
)
1617 fHeadNotePowerArrayEntry
->staticPower
+= childPower
;
1623 if ( fHeadNotePendingAcks
== 0 ) {
1624 // yes, stop the timer
1626 // and now we can continue
1630 OUR_PMLog(kPMLogAcknowledgeErr3
, 0, 0); // not expecting anybody to ack
1635 whichObject
->release();
1640 //*********************************************************************************
1641 // [public] acknowledgeSetPowerState
1643 // After we instructed our controlling driver to change power states,
1644 // it has called to say it has finished doing so.
1645 // We continue to process the power state change.
1646 //*********************************************************************************
1648 IOReturn
IOService::acknowledgeSetPowerState ( void )
1650 IOPMRequest
* request
;
1653 return IOPMNotYetInitialized
;
1655 request
= acquirePMRequest( this, kIOPMRequestTypeAckSetPowerState
);
1657 return kIOReturnNoMemory
;
1659 submitPMRequest( request
);
1660 return kIOReturnSuccess
;
1663 //*********************************************************************************
1664 // [private] adjustPowerState
1665 //*********************************************************************************
1667 void IOService::adjustPowerState ( uint32_t clamp
)
1669 PM_ASSERT_IN_GATE();
1670 computeDesiredState(clamp
);
1671 if (fControllingDriver
&& fParentsKnowState
&& inPlane(gIOPowerPlane
))
1673 IOPMPowerChangeFlags changeFlags
= kIOPMSelfInitiated
;
1675 // Indicate that children desires were ignored, and do not ask
1676 // apps for permission to drop power. This is used by root domain
1677 // for demand sleep.
1679 if (getPMRequestType() == kIOPMRequestTypeRequestPowerStateOverride
)
1680 changeFlags
|= (kIOPMIgnoreChildren
| kIOPMSkipAskPowerDown
);
1683 /* flags */ changeFlags
,
1684 /* power state */ fDesiredPowerState
,
1685 /* domain flags */ 0,
1687 /* parent flags */ 0);
1691 //*********************************************************************************
1692 // [public] synchronizePowerTree
1693 //*********************************************************************************
1695 IOReturn
IOService::synchronizePowerTree (
1696 IOOptionBits options
,
1697 IOService
* notifyRoot
)
1699 IOPMRequest
* request_c
= 0;
1700 IOPMRequest
* request_s
;
1702 if (this != getPMRootDomain())
1703 return kIOReturnBadArgument
;
1705 return kIOPMNotYetInitialized
;
1711 // Cancels don't need to be synchronized.
1712 nr
= acquirePMRequest(notifyRoot
, kIOPMRequestTypeChildNotifyDelayCancel
);
1713 if (nr
) submitPMRequest(nr
);
1714 nr
= acquirePMRequest(getPMRootDomain(), kIOPMRequestTypeChildNotifyDelayCancel
);
1715 if (nr
) submitPMRequest(nr
);
1718 request_s
= acquirePMRequest( this, kIOPMRequestTypeSynchronizePowerTree
);
1720 goto error_no_memory
;
1722 if (options
& kIOPMSyncCancelPowerDown
)
1723 request_c
= acquirePMRequest( this, kIOPMRequestTypeIdleCancel
);
1726 request_c
->attachNextRequest( request_s
);
1727 submitPMRequest(request_c
);
1730 request_s
->fArg0
= (void *)(uintptr_t) options
;
1731 submitPMRequest(request_s
);
1733 return kIOReturnSuccess
;
1736 if (request_c
) releasePMRequest(request_c
);
1737 if (request_s
) releasePMRequest(request_s
);
1738 return kIOReturnNoMemory
;
1741 //*********************************************************************************
1742 // [private] handleSynchronizePowerTree
1743 //*********************************************************************************
1745 void IOService::handleSynchronizePowerTree ( IOPMRequest
* request
)
1747 PM_ASSERT_IN_GATE();
1748 if (fControllingDriver
&& fParentsKnowState
&& inPlane(gIOPowerPlane
) &&
1749 (fCurrentPowerState
== fNumberOfPowerStates
- 1))
1751 IOOptionBits options
= (uintptr_t) request
->fArg0
;
1754 /* flags */ kIOPMSelfInitiated
| kIOPMSynchronize
|
1755 (options
& kIOPMSyncNoChildNotify
),
1756 /* power state */ fCurrentPowerState
,
1757 /* domain flags */ 0,
1759 /* parent flags */ 0);
1764 //*********************************************************************************
1765 // [deprecated] powerDomainWillChangeTo
1767 // Called by the power-hierarchy parent notifying of a new power state
1768 // in the power domain.
1769 // We enqueue a parent power-change to our queue of power changes.
1770 // This may or may not cause us to change power, depending on what
1771 // kind of change is occuring in the domain.
1772 //*********************************************************************************
1774 IOReturn
IOService::powerDomainWillChangeTo (
1775 IOPMPowerFlags newPowerFlags
,
1776 IOPowerConnection
* whichParent
)
1779 return kIOReturnUnsupported
;
1781 #endif /* !__LP64__ */
1783 //*********************************************************************************
1784 // [private] handlePowerDomainWillChangeTo
1785 //*********************************************************************************
1787 void IOService::handlePowerDomainWillChangeTo ( IOPMRequest
* request
)
1789 IOPMPowerFlags parentPowerFlags
= (IOPMPowerFlags
) request
->fArg0
;
1790 IOPowerConnection
* whichParent
= (IOPowerConnection
*) request
->fArg1
;
1791 IOPMPowerChangeFlags parentChangeFlags
= (IOPMPowerChangeFlags
)(uintptr_t) request
->fArg2
;
1792 IOPMPowerChangeFlags myChangeFlags
;
1795 IOPowerConnection
* connection
;
1796 IOPMPowerStateIndex newPowerState
;
1797 IOPMPowerFlags combinedPowerFlags
;
1798 bool savedParentsKnowState
;
1799 IOReturn result
= IOPMAckImplied
;
1801 PM_ASSERT_IN_GATE();
1802 OUR_PMLog(kPMLogWillChange
, parentPowerFlags
, 0);
1804 if (!inPlane(gIOPowerPlane
) || !whichParent
|| !whichParent
->getAwaitingAck())
1806 PM_LOG("%s::%s not in power tree\n", getName(), __FUNCTION__
);
1810 savedParentsKnowState
= fParentsKnowState
;
1812 // Combine parents' output power flags.
1814 combinedPowerFlags
= 0;
1816 iter
= getParentIterator(gIOPowerPlane
);
1819 while ( (next
= iter
->getNextObject()) )
1821 if ( (connection
= OSDynamicCast(IOPowerConnection
, next
)) )
1823 if ( connection
== whichParent
)
1824 combinedPowerFlags
|= parentPowerFlags
;
1826 combinedPowerFlags
|= connection
->parentCurrentPowerFlags();
1832 // If our initial change has yet to occur, then defer the power change
1833 // until after the power domain has completed its power transition.
1835 if ( fControllingDriver
&& !fInitialPowerChange
)
1837 newPowerState
= fControllingDriver
->maxCapabilityForDomainState(
1838 combinedPowerFlags
);
1840 // Absorb parent's kIOPMSynchronize flag.
1841 myChangeFlags
= kIOPMParentInitiated
| kIOPMDomainWillChange
|
1842 (parentChangeFlags
& kIOPMSynchronize
);
1844 result
= startPowerChange(
1845 /* flags */ myChangeFlags
,
1846 /* power state */ newPowerState
,
1847 /* domain flags */ combinedPowerFlags
,
1848 /* connection */ whichParent
,
1849 /* parent flags */ parentPowerFlags
);
1852 // If parent is dropping power, immediately update the parent's
1853 // capability flags. Any future merging of parent(s) combined
1854 // power flags should account for this power drop.
1856 if (parentChangeFlags
& kIOPMDomainPowerDrop
)
1858 setParentInfo(parentPowerFlags
, whichParent
, true);
1861 // Parent is expecting an ACK from us. If we did not embark on a state
1862 // transition, i.e. startPowerChange() returned IOPMAckImplied. We are
1863 // still required to issue an ACK to our parent.
1865 if (IOPMAckImplied
== result
)
1868 parent
= (IOService
*) whichParent
->copyParentEntry(gIOPowerPlane
);
1872 parent
->acknowledgePowerChange( whichParent
);
1878 // Drop the retain from notifyChild().
1879 if (whichParent
) whichParent
->release();
1883 //*********************************************************************************
1884 // [deprecated] powerDomainDidChangeTo
1886 // Called by the power-hierarchy parent after the power state of the power domain
1887 // has settled at a new level.
1888 // We enqueue a parent power-change to our queue of power changes.
1889 // This may or may not cause us to change power, depending on what
1890 // kind of change is occuring in the domain.
1891 //*********************************************************************************
1893 IOReturn
IOService::powerDomainDidChangeTo (
1894 IOPMPowerFlags newPowerFlags
,
1895 IOPowerConnection
* whichParent
)
1898 return kIOReturnUnsupported
;
1900 #endif /* !__LP64__ */
1902 //*********************************************************************************
1903 // [private] handlePowerDomainDidChangeTo
1904 //*********************************************************************************
1906 void IOService::handlePowerDomainDidChangeTo ( IOPMRequest
* request
)
1908 IOPMPowerFlags parentPowerFlags
= (IOPMPowerFlags
) request
->fArg0
;
1909 IOPowerConnection
* whichParent
= (IOPowerConnection
*) request
->fArg1
;
1910 IOPMPowerChangeFlags parentChangeFlags
= (IOPMPowerChangeFlags
)(uintptr_t) request
->fArg2
;
1911 IOPMPowerChangeFlags myChangeFlags
;
1912 IOPMPowerStateIndex newPowerState
;
1913 IOPMPowerStateIndex initialDesire
;
1914 bool savedParentsKnowState
;
1915 IOReturn result
= IOPMAckImplied
;
1917 PM_ASSERT_IN_GATE();
1918 OUR_PMLog(kPMLogDidChange
, parentPowerFlags
, 0);
1920 if (!inPlane(gIOPowerPlane
) || !whichParent
|| !whichParent
->getAwaitingAck())
1922 PM_LOG("%s::%s not in power tree\n", getName(), __FUNCTION__
);
1926 savedParentsKnowState
= fParentsKnowState
;
1928 setParentInfo(parentPowerFlags
, whichParent
, true);
1930 if ( fControllingDriver
)
1932 newPowerState
= fControllingDriver
->maxCapabilityForDomainState(
1933 fParentsCurrentPowerFlags
);
1935 if (fInitialPowerChange
)
1937 initialDesire
= fControllingDriver
->initialPowerStateForDomainState(
1938 fParentsCurrentPowerFlags
);
1939 computeDesiredState(initialDesire
);
1941 else if (fAdvisoryTickleUsed
&& (newPowerState
> 0) &&
1942 ((parentChangeFlags
& kIOPMSynchronize
) == 0))
1944 // re-compute desired state in case advisory tickle was enabled
1945 computeDesiredState();
1948 // Absorb parent's kIOPMSynchronize flag.
1949 myChangeFlags
= kIOPMParentInitiated
| kIOPMDomainDidChange
|
1950 (parentChangeFlags
& kIOPMSynchronize
);
1952 result
= startPowerChange(
1953 /* flags */ myChangeFlags
,
1954 /* power state */ newPowerState
,
1955 /* domain flags */ fParentsCurrentPowerFlags
,
1956 /* connection */ whichParent
,
1957 /* parent flags */ 0);
1960 // Parent is expecting an ACK from us. If we did not embark on a state
1961 // transition, i.e. startPowerChange() returned IOPMAckImplied. We are
1962 // still required to issue an ACK to our parent.
1964 if (IOPMAckImplied
== result
)
1967 parent
= (IOService
*) whichParent
->copyParentEntry(gIOPowerPlane
);
1971 parent
->acknowledgePowerChange( whichParent
);
1976 // If the parent registers its power driver late, then this is the
1977 // first opportunity to tell our parent about our desire.
1979 if (!savedParentsKnowState
&& fParentsKnowState
)
1981 PM_LOG1("%s::powerDomainDidChangeTo parentsKnowState = true\n",
1983 requestDomainPower( fDesiredPowerState
);
1987 // Drop the retain from notifyChild().
1988 if (whichParent
) whichParent
->release();
1991 //*********************************************************************************
1992 // [private] setParentInfo
1994 // Set our connection data for one specific parent, and then combine all the parent
1996 //*********************************************************************************
1998 void IOService::setParentInfo (
1999 IOPMPowerFlags newPowerFlags
,
2000 IOPowerConnection
* whichParent
,
2005 IOPowerConnection
* conn
;
2007 PM_ASSERT_IN_GATE();
2009 // set our connection data
2010 whichParent
->setParentCurrentPowerFlags(newPowerFlags
);
2011 whichParent
->setParentKnowsState(knowsState
);
2013 // recompute our parent info
2014 fParentsCurrentPowerFlags
= 0;
2015 fParentsKnowState
= true;
2017 iter
= getParentIterator(gIOPowerPlane
);
2020 while ( (next
= iter
->getNextObject()) )
2022 if ( (conn
= OSDynamicCast(IOPowerConnection
, next
)) )
2024 fParentsKnowState
&= conn
->parentKnowsState();
2025 fParentsCurrentPowerFlags
|= conn
->parentCurrentPowerFlags();
2032 //******************************************************************************
2033 // [private] trackSystemSleepPreventers
2034 //******************************************************************************
2036 void IOService::trackSystemSleepPreventers(
2037 IOPMPowerStateIndex oldPowerState
,
2038 IOPMPowerStateIndex newPowerState
,
2039 IOPMPowerChangeFlags changeFlags __unused
)
2041 IOPMPowerFlags oldCapability
, newCapability
;
2043 oldCapability
= fPowerStates
[oldPowerState
].capabilityFlags
&
2044 (kIOPMPreventIdleSleep
| kIOPMPreventSystemSleep
);
2045 newCapability
= fPowerStates
[newPowerState
].capabilityFlags
&
2046 (kIOPMPreventIdleSleep
| kIOPMPreventSystemSleep
);
2048 if (fHeadNoteChangeFlags
& kIOPMInitialPowerChange
)
2050 if (oldCapability
== newCapability
)
2053 if ((oldCapability
^ newCapability
) & kIOPMPreventIdleSleep
)
2055 #if SUPPORT_IDLE_CANCEL
2056 if ((oldCapability
& kIOPMPreventIdleSleep
) == 0)
2058 IOPMRequest
* cancelRequest
;
2060 cancelRequest
= acquirePMRequest( this, kIOPMRequestTypeIdleCancel
);
2063 getPMRootDomain()->submitPMRequest( cancelRequest
);
2068 getPMRootDomain()->updatePreventIdleSleepList(this,
2069 ((oldCapability
& kIOPMPreventIdleSleep
) == 0));
2072 if ((oldCapability
^ newCapability
) & kIOPMPreventSystemSleep
)
2075 getPMRootDomain()->updatePreventSystemSleepList(this,
2076 ((oldCapability
& kIOPMPreventSystemSleep
) == 0));
2080 //*********************************************************************************
2081 // [public] requestPowerDomainState
2083 // Called on a power parent when a child's power requirement changes.
2084 //*********************************************************************************
2086 IOReturn
IOService::requestPowerDomainState(
2087 IOPMPowerFlags childRequestPowerFlags
,
2088 IOPowerConnection
* childConnection
,
2089 unsigned long specification
)
2091 IOPMPowerStateIndex ps
;
2092 IOPMPowerFlags outputPowerFlags
;
2094 IOPMRequest
* subRequest
;
2095 bool adjustPower
= false;
2098 return IOPMNotYetInitialized
;
2100 if (gIOPMWorkLoop
->onThread() == false)
2102 PM_LOG("%s::requestPowerDomainState\n", getName());
2103 return kIOReturnSuccess
;
2106 OUR_PMLog(kPMLogRequestDomain
, childRequestPowerFlags
, specification
);
2108 if (!isChild(childConnection
, gIOPowerPlane
))
2109 return kIOReturnNotAttached
;
2111 if (!fControllingDriver
|| !fNumberOfPowerStates
)
2112 return kIOReturnNotReady
;
2114 child
= (IOService
*) childConnection
->getChildEntry(gIOPowerPlane
);
2117 // Merge in the power flags contributed by this power parent
2118 // at its current or impending power state.
2120 outputPowerFlags
= fPowerStates
[fCurrentPowerState
].outputPowerFlags
;
2121 if (fMachineState
!= kIOPM_Finished
)
2123 if (IS_POWER_DROP
&& !IS_ROOT_DOMAIN
)
2125 // Use the lower power state when dropping power.
2126 // Must be careful since a power drop can be canceled
2127 // from the following states:
2128 // - kIOPM_OurChangeTellClientsPowerDown
2129 // - kIOPM_OurChangeTellPriorityClientsPowerDown
2131 // The child must not wait for this parent to raise power
2132 // if the power drop was cancelled. The solution is to cancel
2133 // the power drop if possible, then schedule an adjustment to
2134 // re-evaluate the parent's power state.
2136 // Root domain is excluded to avoid idle sleep issues. And permit
2137 // root domain children to pop up when system is going to sleep.
2139 if ((fMachineState
== kIOPM_OurChangeTellClientsPowerDown
) ||
2140 (fMachineState
== kIOPM_OurChangeTellPriorityClientsPowerDown
))
2142 fDoNotPowerDown
= true; // cancel power drop
2143 adjustPower
= true; // schedule an adjustment
2144 PM_LOG1("%s: power drop cancelled in state %u by %s\n",
2145 getName(), fMachineState
, child
->getName());
2149 // Beyond cancellation point, report the impending state.
2151 fPowerStates
[fHeadNotePowerState
].outputPowerFlags
;
2154 else if (IS_POWER_RISE
)
2156 // When raising power, must report the output power flags from
2157 // child's perspective. A child power request may arrive while
2158 // parent is transitioning upwards. If a request arrives after
2159 // setParentInfo() has already recorded the output power flags
2160 // for the next power state, then using the power supplied by
2161 // fCurrentPowerState is incorrect, and might cause the child
2162 // to wait when it should not.
2164 outputPowerFlags
= childConnection
->parentCurrentPowerFlags();
2167 child
->fHeadNoteDomainTargetFlags
|= outputPowerFlags
;
2169 // Map child's requested power flags to one of our power state.
2171 for (ps
= 0; ps
< fNumberOfPowerStates
; ps
++)
2173 if ((fPowerStates
[ps
].outputPowerFlags
& childRequestPowerFlags
) ==
2174 (fOutputPowerCharacterFlags
& childRequestPowerFlags
))
2177 if (ps
>= fNumberOfPowerStates
)
2179 ps
= 0; // should never happen
2182 // Conditions that warrants a power adjustment on this parent.
2183 // Adjust power will also propagate any changes to the child's
2184 // prevent idle/sleep flags towards the root domain.
2186 if (!childConnection
->childHasRequestedPower() ||
2187 (ps
!= childConnection
->getDesiredDomainState()))
2190 #if ENABLE_DEBUG_LOGS
2193 PM_LOG("requestPowerDomainState[%s]: %s, init %d, %u->%u\n",
2194 getName(), child
->getName(),
2195 !childConnection
->childHasRequestedPower(),
2196 (uint32_t) childConnection
->getDesiredDomainState(),
2201 // Record the child's desires on the connection.
2202 childConnection
->setChildHasRequestedPower();
2203 childConnection
->setDesiredDomainState( ps
);
2205 // Schedule a request to re-evaluate all children desires and
2206 // adjust power state. Submit a request if one wasn't pending,
2207 // or if the current request is part of a call tree.
2209 if (adjustPower
&& !fDeviceOverrideEnabled
&&
2210 (!fAdjustPowerScheduled
|| gIOPMRequest
->getRootRequest()))
2212 subRequest
= acquirePMRequest(
2213 this, kIOPMRequestTypeAdjustPowerState
, gIOPMRequest
);
2216 submitPMRequest( subRequest
);
2217 fAdjustPowerScheduled
= true;
2221 return kIOReturnSuccess
;
2224 //*********************************************************************************
2225 // [public] temporaryPowerClampOn
2227 // A power domain wants to clamp its power on till it has children which
2228 // will thendetermine the power domain state.
2230 // We enter the highest state until addPowerChild is called.
2231 //*********************************************************************************
2233 IOReturn
IOService::temporaryPowerClampOn ( void )
2235 return requestPowerState( gIOPMPowerClientChildProxy
, kIOPMPowerStateMax
);
2238 //*********************************************************************************
2239 // [public] makeUsable
2241 // Some client of our device is asking that we become usable. Although
2242 // this has not come from a subclassed device object, treat it exactly
2243 // as if it had. In this way, subsequent requests for lower power from
2244 // a subclassed device object will pre-empt this request.
2246 // We treat this as a subclass object request to switch to the
2247 // highest power state.
2248 //*********************************************************************************
2250 IOReturn
IOService::makeUsable ( void )
2252 OUR_PMLog(kPMLogMakeUsable
, 0, 0);
2253 return requestPowerState( gIOPMPowerClientDevice
, kIOPMPowerStateMax
);
2256 //*********************************************************************************
2257 // [public] currentCapability
2258 //*********************************************************************************
2260 IOPMPowerFlags
IOService::currentCapability ( void )
2263 return IOPMNotPowerManaged
;
2265 return fCurrentCapabilityFlags
;
2268 //*********************************************************************************
2269 // [public] changePowerStateTo
2271 // Called by our power-controlling driver to change power state. The new desired
2272 // power state is computed and compared against the current power state. If those
2273 // power states differ, then a power state change is initiated.
2274 //*********************************************************************************
2276 IOReturn
IOService::changePowerStateTo ( unsigned long ordinal
)
2278 OUR_PMLog(kPMLogChangeStateTo
, ordinal
, 0);
2279 return requestPowerState( gIOPMPowerClientDriver
, ordinal
);
2282 //*********************************************************************************
2283 // [protected] changePowerStateToPriv
2285 // Called by our driver subclass to change power state. The new desired power
2286 // state is computed and compared against the current power state. If those
2287 // power states differ, then a power state change is initiated.
2288 //*********************************************************************************
2290 IOReturn
IOService::changePowerStateToPriv ( unsigned long ordinal
)
2292 OUR_PMLog(kPMLogChangeStateToPriv
, ordinal
, 0);
2293 return requestPowerState( gIOPMPowerClientDevice
, ordinal
);
2296 //*********************************************************************************
2297 // [protected] changePowerStateWithOverrideTo
2299 // Called by our driver subclass to change power state. The new desired power
2300 // state is computed and compared against the current power state. If those
2301 // power states differ, then a power state change is initiated.
2302 // Override enforced - Children and Driver desires are ignored.
2303 //*********************************************************************************
2305 IOReturn
IOService::changePowerStateWithOverrideTo ( unsigned long ordinal
)
2307 IOPMRequest
* request
;
2310 return kIOPMNotYetInitialized
;
2312 OUR_PMLog(kPMLogChangeStateToPriv
, ordinal
, 0);
2314 request
= acquirePMRequest( this, kIOPMRequestTypeRequestPowerStateOverride
);
2316 return kIOReturnNoMemory
;
2318 gIOPMPowerClientDevice
->retain();
2319 request
->fArg0
= (void *) ordinal
;
2320 request
->fArg1
= (void *) gIOPMPowerClientDevice
;
2324 request
->installCompletionAction( action
, target
, param
);
2327 // Prevent needless downwards power transitions by clamping power
2328 // until the scheduled request is executed.
2330 if (gIOPMWorkLoop
->inGate() && (ordinal
< fNumberOfPowerStates
))
2332 fTempClampPowerState
= max(fTempClampPowerState
, ordinal
);
2334 fOverrideMaxPowerState
= ordinal
;
2335 request
->fArg2
= (void *) (uintptr_t) true;
2338 submitPMRequest( request
);
2342 //*********************************************************************************
2343 // [private] requestPowerState
2344 //*********************************************************************************
2346 IOReturn
IOService::requestPowerState (
2347 const OSSymbol
* client
,
2350 IOPMRequest
* request
;
2353 return kIOReturnBadArgument
;
2355 return kIOPMNotYetInitialized
;
2357 request
= acquirePMRequest( this, kIOPMRequestTypeRequestPowerState
);
2359 return kIOReturnNoMemory
;
2362 request
->fArg0
= (void *) state
;
2363 request
->fArg1
= (void *) client
;
2367 request
->installCompletionAction( action
, target
, param
);
2370 // Prevent needless downwards power transitions by clamping power
2371 // until the scheduled request is executed.
2373 if (gIOPMWorkLoop
->inGate() && (state
< fNumberOfPowerStates
))
2375 fTempClampPowerState
= max(fTempClampPowerState
, state
);
2377 request
->fArg2
= (void *) (uintptr_t) true;
2380 submitPMRequest( request
);
2384 //*********************************************************************************
2385 // [private] handleRequestPowerState
2386 //*********************************************************************************
2388 void IOService::handleRequestPowerState ( IOPMRequest
* request
)
2390 const OSSymbol
* client
= (const OSSymbol
*) request
->fArg1
;
2391 uint32_t state
= (uint32_t)(uintptr_t) request
->fArg0
;
2393 PM_ASSERT_IN_GATE();
2396 assert(fTempClampCount
!= 0);
2397 if (fTempClampCount
) fTempClampCount
--;
2398 if (!fTempClampCount
) fTempClampPowerState
= 0;
2401 if (fNumberOfPowerStates
&& (state
>= fNumberOfPowerStates
))
2402 state
= fNumberOfPowerStates
- 1;
2404 // The power suppression due to changePowerStateWithOverrideTo() expires
2405 // upon the next "device" power request - changePowerStateToPriv().
2407 if ((getPMRequestType() != kIOPMRequestTypeRequestPowerStateOverride
) &&
2408 (client
== gIOPMPowerClientDevice
))
2409 fOverrideMaxPowerState
= kIOPMPowerStateMax
;
2412 (client
!= gIOPMPowerClientDevice
) &&
2413 (client
!= gIOPMPowerClientDriver
) &&
2414 (client
!= gIOPMPowerClientChildProxy
))
2415 removePowerClient(client
);
2417 updatePowerClient(client
, state
);
2423 //*********************************************************************************
2424 // [private] Helper functions to update/remove power clients.
2425 //*********************************************************************************
2427 void IOService::updatePowerClient( const OSSymbol
* client
, uint32_t powerState
)
2430 fPowerClients
= OSDictionary::withCapacity(4);
2431 if (fPowerClients
&& client
)
2433 OSNumber
* num
= (OSNumber
*) fPowerClients
->getObject(client
);
2435 num
->setValue(powerState
);
2438 num
= OSNumber::withNumber(powerState
, 32);
2441 fPowerClients
->setObject(client
, num
);
2448 void IOService::removePowerClient( const OSSymbol
* client
)
2450 if (fPowerClients
&& client
)
2451 fPowerClients
->removeObject(client
);
2454 uint32_t IOService::getPowerStateForClient( const OSSymbol
* client
)
2456 uint32_t powerState
= 0;
2458 if (fPowerClients
&& client
)
2460 OSNumber
* num
= (OSNumber
*) fPowerClients
->getObject(client
);
2461 if (num
) powerState
= num
->unsigned32BitValue();
2466 //*********************************************************************************
2467 // [protected] powerOverrideOnPriv
2468 //*********************************************************************************
2470 IOReturn
IOService::powerOverrideOnPriv ( void )
2472 IOPMRequest
* request
;
2475 return IOPMNotYetInitialized
;
2477 if (gIOPMWorkLoop
->inGate())
2479 fDeviceOverrideEnabled
= true;
2483 request
= acquirePMRequest( this, kIOPMRequestTypePowerOverrideOnPriv
);
2485 return kIOReturnNoMemory
;
2487 submitPMRequest( request
);
2491 //*********************************************************************************
2492 // [protected] powerOverrideOffPriv
2493 //*********************************************************************************
2495 IOReturn
IOService::powerOverrideOffPriv ( void )
2497 IOPMRequest
* request
;
2500 return IOPMNotYetInitialized
;
2502 if (gIOPMWorkLoop
->inGate())
2504 fDeviceOverrideEnabled
= false;
2508 request
= acquirePMRequest( this, kIOPMRequestTypePowerOverrideOffPriv
);
2510 return kIOReturnNoMemory
;
2512 submitPMRequest( request
);
2516 //*********************************************************************************
2517 // [private] handlePowerOverrideChanged
2518 //*********************************************************************************
2520 void IOService::handlePowerOverrideChanged ( IOPMRequest
* request
)
2522 PM_ASSERT_IN_GATE();
2523 if (request
->getType() == kIOPMRequestTypePowerOverrideOnPriv
)
2525 OUR_PMLog(kPMLogOverrideOn
, 0, 0);
2526 fDeviceOverrideEnabled
= true;
2530 OUR_PMLog(kPMLogOverrideOff
, 0, 0);
2531 fDeviceOverrideEnabled
= false;
2537 //*********************************************************************************
2538 // [private] computeDesiredState
2539 //*********************************************************************************
2541 void IOService::computeDesiredState ( unsigned long localClamp
)
2545 IOPowerConnection
* connection
;
2546 uint32_t desiredState
= 0;
2547 uint32_t newPowerState
= 0;
2548 bool hasChildren
= false;
2550 // Desired power state is always 0 without a controlling driver.
2552 if (!fNumberOfPowerStates
)
2554 fDesiredPowerState
= 0;
2555 //PM_LOG("%s::%s no controlling driver\n", getName(), __FUNCTION__);
2559 // Examine the children's desired power state.
2561 iter
= getChildIterator(gIOPowerPlane
);
2564 while ((next
= iter
->getNextObject()))
2566 if ((connection
= OSDynamicCast(IOPowerConnection
, next
)))
2568 if (connection
->getReadyFlag() == false)
2570 PM_LOG3("[%s] %s: connection not ready\n",
2571 getName(), __FUNCTION__
);
2574 if (connection
->childHasRequestedPower())
2576 if (connection
->getDesiredDomainState() > desiredState
)
2577 desiredState
= connection
->getDesiredDomainState();
2583 updatePowerClient(gIOPMPowerClientChildren
, desiredState
);
2585 removePowerClient(gIOPMPowerClientChildren
);
2587 // Iterate through all power clients to determine the min power state.
2589 iter
= OSCollectionIterator::withCollection(fPowerClients
);
2592 const OSSymbol
* client
;
2593 while ((client
= (const OSSymbol
*) iter
->getNextObject()))
2595 // Ignore child and driver when override is in effect.
2596 if ((fDeviceOverrideEnabled
||
2597 (getPMRequestType() == kIOPMRequestTypeRequestPowerStateOverride
)) &&
2598 ((client
== gIOPMPowerClientChildren
) ||
2599 (client
== gIOPMPowerClientDriver
)))
2602 // Ignore child proxy when children are present.
2603 if (hasChildren
&& (client
== gIOPMPowerClientChildProxy
))
2606 if (client
== gIOPMPowerClientAdvisoryTickle
&&
2607 !gIOPMAdvisoryTickleEnabled
)
2610 desiredState
= getPowerStateForClient(client
);
2611 assert(desiredState
< fNumberOfPowerStates
);
2613 desiredState
, client
->getCStringNoCopy());
2615 newPowerState
= max(newPowerState
, desiredState
);
2617 if (client
== gIOPMPowerClientDevice
)
2618 fDeviceDesire
= desiredState
;
2623 // Factor in the temporary power desires.
2625 newPowerState
= max(newPowerState
, localClamp
);
2626 newPowerState
= max(newPowerState
, fTempClampPowerState
);
2628 // Limit check against max power override.
2630 newPowerState
= min(newPowerState
, fOverrideMaxPowerState
);
2632 // Limit check against number of power states.
2634 if (newPowerState
>= fNumberOfPowerStates
)
2635 newPowerState
= fNumberOfPowerStates
- 1;
2637 fDesiredPowerState
= newPowerState
;
2639 PM_LOG1(" temp %u, clamp %u, current %u, new %u\n",
2640 (uint32_t) localClamp
, (uint32_t) fTempClampPowerState
,
2641 (uint32_t) fCurrentPowerState
, newPowerState
);
2643 // Restart idle timer if stopped and device desire has increased.
2644 // Or if advisory desire exists.
2646 if (fIdleTimerStopped
)
2648 if (fDeviceDesire
> 0)
2650 fIdleTimerStopped
= false;
2651 fActivityTickleCount
= 0;
2652 clock_get_uptime(&fIdleTimerStartTime
);
2653 start_PM_idle_timer();
2655 else if (fHasAdvisoryDesire
)
2657 fIdleTimerStopped
= false;
2658 start_PM_idle_timer();
2662 // Invalidate cached tickle power state when desires change, and not
2663 // due to a tickle request. This invalidation must occur before the
2664 // power state change to minimize races. We want to err on the side
2665 // of servicing more activity tickles rather than dropping one when
2666 // the device is in a low power state.
2668 if ((getPMRequestType() != kIOPMRequestTypeActivityTickle
) &&
2669 (fActivityTicklePowerState
!= kInvalidTicklePowerState
))
2671 IOLockLock(fActivityLock
);
2672 fActivityTicklePowerState
= kInvalidTicklePowerState
;
2673 IOLockUnlock(fActivityLock
);
2677 //*********************************************************************************
2678 // [public] currentPowerConsumption
2680 //*********************************************************************************
2682 unsigned long IOService::currentPowerConsumption ( void )
2685 return kIOPMUnknown
;
2687 return fCurrentPowerConsumption
;
2690 //*********************************************************************************
2691 // [deprecated] getPMworkloop
2692 //*********************************************************************************
2694 IOWorkLoop
* IOService::getPMworkloop ( void )
2696 return gIOPMWorkLoop
;
2701 //*********************************************************************************
2702 // Power Parent/Children Applier
2703 //*********************************************************************************
2706 applyToPowerChildren(
2707 IOService
* service
,
2708 IOServiceApplierFunction applier
,
2710 IOOptionBits options
)
2712 PM_ASSERT_IN_GATE();
2714 IORegistryEntry
* entry
;
2715 IORegistryIterator
* iter
;
2716 IOPowerConnection
* connection
;
2719 iter
= IORegistryIterator::iterateOver(service
, gIOPowerPlane
, options
);
2722 while ((entry
= iter
->getNextObject()))
2724 // Get child of IOPowerConnection objects
2725 if ((connection
= OSDynamicCast(IOPowerConnection
, entry
)))
2727 child
= (IOService
*) connection
->copyChildEntry(gIOPowerPlane
);
2730 (*applier
)(child
, context
);
2741 IOService
* service
,
2742 IOServiceApplierFunction applier
,
2744 IOOptionBits options
)
2746 PM_ASSERT_IN_GATE();
2748 IORegistryEntry
* entry
;
2749 IORegistryIterator
* iter
;
2750 IOPowerConnection
* connection
;
2753 iter
= IORegistryIterator::iterateOver(service
, gIOPowerPlane
,
2754 options
| kIORegistryIterateParents
);
2757 while ((entry
= iter
->getNextObject()))
2759 // Get child of IOPowerConnection objects
2760 if ((connection
= OSDynamicCast(IOPowerConnection
, entry
)))
2762 parent
= (IOService
*) connection
->copyParentEntry(gIOPowerPlane
);
2765 (*applier
)(parent
, context
);
2774 #endif /* NOT_YET */
2777 // MARK: Activity Tickle & Idle Timer
2779 void IOService::setAdvisoryTickleEnable( bool enable
)
2781 gIOPMAdvisoryTickleEnabled
= enable
;
2784 //*********************************************************************************
2785 // [public] activityTickle
2787 // The tickle with parameter kIOPMSuperclassPolicy1 causes the activity
2788 // flag to be set, and the device state checked. If the device has been
2789 // powered down, it is powered up again.
2790 // The tickle with parameter kIOPMSubclassPolicy is ignored here and
2791 // should be intercepted by a subclass.
2792 //*********************************************************************************
2794 bool IOService::activityTickle ( unsigned long type
, unsigned long stateNumber
)
2796 IOPMRequest
* request
;
2797 bool noPowerChange
= true;
2800 return true; // no power change
2802 if ((type
== kIOPMSuperclassPolicy1
) && stateNumber
)
2804 IOLockLock(fActivityLock
);
2806 // Record device activity for the idle timer handler.
2808 fDeviceWasActive
= true;
2809 fActivityTickleCount
++;
2810 clock_get_uptime(&fDeviceActiveTimestamp
);
2812 PM_ACTION_0(actionActivityTickle
);
2814 // Record the last tickle power state.
2815 // This helps to filter out redundant tickles as
2816 // this function may be called from the data path.
2818 if (fActivityTicklePowerState
< (int)stateNumber
)
2820 fActivityTicklePowerState
= stateNumber
;
2821 noPowerChange
= false;
2823 request
= acquirePMRequest( this, kIOPMRequestTypeActivityTickle
);
2826 request
->fArg0
= (void *) stateNumber
; // power state
2827 request
->fArg1
= (void *) true; // power rise
2828 request
->fArg2
= (void *) false; // regular tickle
2829 submitPMRequest(request
);
2833 IOLockUnlock(fActivityLock
);
2836 else if ((type
== kIOPMActivityTickleTypeAdvisory
) &&
2837 ((stateNumber
= fDeviceUsablePowerState
)))
2839 IOLockLock(fActivityLock
);
2841 fAdvisoryTickled
= true;
2843 if (fAdvisoryTicklePowerState
!= (int)stateNumber
)
2845 fAdvisoryTicklePowerState
= stateNumber
;
2846 noPowerChange
= false;
2848 request
= acquirePMRequest( this, kIOPMRequestTypeActivityTickle
);
2851 request
->fArg0
= (void *) stateNumber
; // power state
2852 request
->fArg1
= (void *) true; // power rise
2853 request
->fArg2
= (void *) true; // advisory tickle
2854 submitPMRequest(request
);
2858 IOLockUnlock(fActivityLock
);
2861 // Returns false if the activityTickle might cause a transition to a
2862 // higher powered state, true otherwise.
2864 return noPowerChange
;
2867 //*********************************************************************************
2868 // [private] handleActivityTickle
2869 //*********************************************************************************
2871 void IOService::handleActivityTickle ( IOPMRequest
* request
)
2873 uint32_t ticklePowerState
= (uint32_t)(uintptr_t) request
->fArg0
;
2874 bool deviceWasActive
= (request
->fArg1
== (void *) true);
2875 bool isRegularTickle
= (request
->fArg2
== (void *) false);
2876 bool adjustPower
= false;
2878 PM_ASSERT_IN_GATE();
2879 if (isRegularTickle
)
2881 if (deviceWasActive
)
2883 if ((ticklePowerState
> fDeviceDesire
) &&
2884 (ticklePowerState
< fNumberOfPowerStates
))
2886 fIdleTimerMinPowerState
= ticklePowerState
;
2887 updatePowerClient(gIOPMPowerClientDevice
, ticklePowerState
);
2891 else if (fDeviceDesire
> fIdleTimerMinPowerState
)
2893 // Power drop due to idle timer expiration.
2894 // Do not allow idle timer to reduce power below tickle power.
2895 // This prevents the idle timer from decreasing the device desire
2896 // to zero and cancelling the effect of a pre-sleep tickle when
2897 // system wakes up to doze state, while the device is unable to
2898 // raise its power state to satisfy the tickle.
2900 ticklePowerState
= fDeviceDesire
- 1;
2901 updatePowerClient(gIOPMPowerClientDevice
, ticklePowerState
);
2905 else // advisory tickle
2907 if (deviceWasActive
)
2909 if ((ticklePowerState
== fDeviceUsablePowerState
) &&
2910 (ticklePowerState
< fNumberOfPowerStates
))
2912 updatePowerClient(gIOPMPowerClientAdvisoryTickle
, ticklePowerState
);
2913 fHasAdvisoryDesire
= true;
2914 fAdvisoryTickleUsed
= true;
2919 IOLockLock(fActivityLock
);
2920 fAdvisoryTicklePowerState
= kInvalidTicklePowerState
;
2921 IOLockUnlock(fActivityLock
);
2924 else if (fHasAdvisoryDesire
)
2926 removePowerClient(gIOPMPowerClientAdvisoryTickle
);
2927 fHasAdvisoryDesire
= false;
2938 //******************************************************************************
2939 // [public] setIdleTimerPeriod
2941 // A subclass policy-maker is using our standard idleness detection service.
2942 // Start the idle timer. Period is in seconds.
2943 //******************************************************************************
2945 IOReturn
IOService::setIdleTimerPeriod ( unsigned long period
)
2948 return IOPMNotYetInitialized
;
2950 OUR_PMLog(kPMLogSetIdleTimerPeriod
, period
, fIdleTimerPeriod
);
2952 IOPMRequest
* request
=
2953 acquirePMRequest( this, kIOPMRequestTypeSetIdleTimerPeriod
);
2955 return kIOReturnNoMemory
;
2957 request
->fArg0
= (void *) period
;
2958 submitPMRequest( request
);
2960 return kIOReturnSuccess
;
2963 IOReturn
IOService::setIgnoreIdleTimer( bool ignore
)
2966 return IOPMNotYetInitialized
;
2968 OUR_PMLog(kIOPMRequestTypeIgnoreIdleTimer
, ignore
, 0);
2970 IOPMRequest
* request
=
2971 acquirePMRequest( this, kIOPMRequestTypeIgnoreIdleTimer
);
2973 return kIOReturnNoMemory
;
2975 request
->fArg0
= (void *) ignore
;
2976 submitPMRequest( request
);
2978 return kIOReturnSuccess
;
2981 //******************************************************************************
2982 // [public] nextIdleTimeout
2984 // Returns how many "seconds from now" the device should idle into its
2985 // next lowest power state.
2986 //******************************************************************************
2988 SInt32
IOService::nextIdleTimeout(
2989 AbsoluteTime currentTime
,
2990 AbsoluteTime lastActivity
,
2991 unsigned int powerState
)
2998 // Calculate time difference using funky macro from clock.h.
2999 delta
= currentTime
;
3000 SUB_ABSOLUTETIME(&delta
, &lastActivity
);
3002 // Figure it in seconds.
3003 absolutetime_to_nanoseconds(delta
, &delta_ns
);
3004 delta_secs
= (SInt32
)(delta_ns
/ NSEC_PER_SEC
);
3006 // Be paranoid about delta somehow exceeding timer period.
3007 if (delta_secs
< (int) fIdleTimerPeriod
)
3008 delay_secs
= (int) fIdleTimerPeriod
- delta_secs
;
3010 delay_secs
= (int) fIdleTimerPeriod
;
3012 return (SInt32
)delay_secs
;
3015 //*********************************************************************************
3016 // [public] start_PM_idle_timer
3017 //*********************************************************************************
3019 void IOService::start_PM_idle_timer ( void )
3021 static const int maxTimeout
= 100000;
3022 static const int minTimeout
= 1;
3023 AbsoluteTime uptime
, deadline
;
3027 if (!initialized
|| !fIdleTimerPeriod
)
3030 IOLockLock(fActivityLock
);
3032 clock_get_uptime(&uptime
);
3034 // Subclasses may modify idle sleep algorithm
3035 idle_in
= nextIdleTimeout(uptime
, fDeviceActiveTimestamp
, fCurrentPowerState
);
3037 // Check for out-of range responses
3038 if (idle_in
> maxTimeout
)
3040 // use standard implementation
3041 idle_in
= IOService::nextIdleTimeout(uptime
,
3042 fDeviceActiveTimestamp
,
3043 fCurrentPowerState
);
3044 } else if (idle_in
< minTimeout
) {
3045 idle_in
= fIdleTimerPeriod
;
3048 IOLockUnlock(fActivityLock
);
3051 clock_interval_to_absolutetime_interval(idle_in
, kSecondScale
, &deadline
);
3052 ADD_ABSOLUTETIME(&deadline
, &uptime
);
3053 pending
= thread_call_enter_delayed(fIdleTimer
, deadline
);
3054 if (pending
) release();
3057 //*********************************************************************************
3058 // idle_timer_expired
3059 //*********************************************************************************
3062 idle_timer_expired (
3063 thread_call_param_t arg0
, thread_call_param_t arg1
)
3065 IOService
* me
= (IOService
*) arg0
;
3068 gIOPMWorkLoop
->runAction(
3069 OSMemberFunctionCast(IOWorkLoop::Action
, me
,
3070 &IOService::idleTimerExpired
),
3076 //*********************************************************************************
3077 // [private] idleTimerExpired
3079 // The idle timer has expired. If there has been activity since the last
3080 // expiration, just restart the timer and return. If there has not been
3081 // activity, switch to the next lower power state and restart the timer.
3082 //*********************************************************************************
3084 void IOService::idleTimerExpired( void )
3086 IOPMRequest
* request
;
3087 bool restartTimer
= true;
3089 if ( !initialized
|| !fIdleTimerPeriod
|| fLockedFlags
.PMStop
)
3092 IOLockLock(fActivityLock
);
3094 // Check for device activity (tickles) over last timer period.
3096 if (fDeviceWasActive
)
3098 // Device was active - do not drop power, restart timer.
3099 fDeviceWasActive
= false;
3101 else if (!fIdleTimerIgnored
)
3103 // No device activity - drop power state by one level.
3104 // Decrement the cached tickle power state when possible.
3105 // This value may be (-1) before activityTickle() is called,
3106 // but the power drop request must be issued regardless.
3108 if (fActivityTicklePowerState
> 0)
3109 fActivityTicklePowerState
--;
3111 request
= acquirePMRequest( this, kIOPMRequestTypeActivityTickle
);
3114 request
->fArg0
= (void *) 0; // power state (irrelevant)
3115 request
->fArg1
= (void *) false; // timer expiration (not tickle)
3116 request
->fArg2
= (void *) false; // regular tickle
3117 submitPMRequest( request
);
3119 // Do not restart timer until after the tickle request has been
3122 restartTimer
= false;
3126 if (fAdvisoryTickled
)
3128 fAdvisoryTickled
= false;
3130 else if (fHasAdvisoryDesire
)
3132 // Want new tickles to turn into pm request after we drop the lock
3133 fAdvisoryTicklePowerState
= kInvalidTicklePowerState
;
3135 request
= acquirePMRequest( this, kIOPMRequestTypeActivityTickle
);
3138 request
->fArg0
= (void *) 0; // power state (irrelevant)
3139 request
->fArg1
= (void *) false; // timer expiration (not tickle)
3140 request
->fArg2
= (void *) true; // advisory tickle
3141 submitPMRequest( request
);
3143 // Do not restart timer until after the tickle request has been
3146 restartTimer
= false;
3150 IOLockUnlock(fActivityLock
);
3153 start_PM_idle_timer();
3157 //*********************************************************************************
3158 // [deprecated] PM_idle_timer_expiration
3159 //*********************************************************************************
3161 void IOService::PM_idle_timer_expiration ( void )
3165 //*********************************************************************************
3166 // [deprecated] command_received
3167 //*********************************************************************************
3169 void IOService::command_received ( void *statePtr
, void *, void * , void * )
3172 #endif /* !__LP64__ */
3174 //*********************************************************************************
3175 // [public] setAggressiveness
3177 // Pass on the input parameters to all power domain children. All those which are
3178 // power domains will pass it on to their children, etc.
3179 //*********************************************************************************
3181 IOReturn
IOService::setAggressiveness ( unsigned long type
, unsigned long newLevel
)
3183 return kIOReturnSuccess
;
3186 //*********************************************************************************
3187 // [public] getAggressiveness
3189 // Called by the user client.
3190 //*********************************************************************************
3192 IOReturn
IOService::getAggressiveness ( unsigned long type
, unsigned long * currentLevel
)
3194 IOPMrootDomain
* rootDomain
= getPMRootDomain();
3197 return kIOReturnNotReady
;
3199 return rootDomain
->getAggressiveness( type
, currentLevel
);
3202 //*********************************************************************************
3203 // [public] getPowerState
3205 //*********************************************************************************
3207 UInt32
IOService::getPowerState ( void )
3212 return fCurrentPowerState
;
3216 //*********************************************************************************
3217 // [deprecated] systemWake
3219 // Pass this to all power domain children. All those which are
3220 // power domains will pass it on to their children, etc.
3221 //*********************************************************************************
3223 IOReturn
IOService::systemWake ( void )
3227 IOPowerConnection
* connection
;
3228 IOService
* theChild
;
3230 iter
= getChildIterator(gIOPowerPlane
);
3233 while ( (next
= iter
->getNextObject()) )
3235 if ( (connection
= OSDynamicCast(IOPowerConnection
, next
)) )
3237 if (connection
->getReadyFlag() == false)
3239 PM_LOG3("[%s] %s: connection not ready\n",
3240 getName(), __FUNCTION__
);
3244 theChild
= (IOService
*)connection
->copyChildEntry(gIOPowerPlane
);
3247 theChild
->systemWake();
3248 theChild
->release();
3255 if ( fControllingDriver
!= NULL
)
3257 if ( fControllingDriver
->didYouWakeSystem() )
3266 //*********************************************************************************
3267 // [deprecated] temperatureCriticalForZone
3268 //*********************************************************************************
3270 IOReturn
IOService::temperatureCriticalForZone ( IOService
* whichZone
)
3272 IOService
* theParent
;
3275 OUR_PMLog(kPMLogCriticalTemp
, 0, 0);
3277 if ( inPlane(gIOPowerPlane
) && !IS_PM_ROOT
)
3279 theNub
= (IOService
*)copyParentEntry(gIOPowerPlane
);
3282 theParent
= (IOService
*)theNub
->copyParentEntry(gIOPowerPlane
);
3286 theParent
->temperatureCriticalForZone(whichZone
);
3287 theParent
->release();
3293 #endif /* !__LP64__ */
3296 // MARK: Power Change (Common)
3298 //*********************************************************************************
3299 // [private] startPowerChange
3301 // All power state changes starts here.
3302 //*********************************************************************************
3304 IOReturn
IOService::startPowerChange(
3305 IOPMPowerChangeFlags changeFlags
,
3306 IOPMPowerStateIndex powerState
,
3307 IOPMPowerFlags domainFlags
,
3308 IOPowerConnection
* parentConnection
,
3309 IOPMPowerFlags parentFlags
)
3311 PM_ASSERT_IN_GATE();
3312 assert( fMachineState
== kIOPM_Finished
);
3313 assert( powerState
< fNumberOfPowerStates
);
3315 if (powerState
>= fNumberOfPowerStates
)
3316 return IOPMAckImplied
;
3318 fIsPreChange
= true;
3319 PM_ACTION_2(actionPowerChangeOverride
, &powerState
, &changeFlags
);
3321 // Forks to either Driver or Parent initiated power change paths.
3323 fHeadNoteChangeFlags
= changeFlags
;
3324 fHeadNotePowerState
= powerState
;
3325 fHeadNotePowerArrayEntry
= &fPowerStates
[ powerState
];
3326 fHeadNoteParentConnection
= NULL
;
3328 if (changeFlags
& kIOPMSelfInitiated
)
3330 if (changeFlags
& kIOPMSynchronize
)
3338 assert(changeFlags
& kIOPMParentInitiated
);
3339 fHeadNoteDomainFlags
= domainFlags
;
3340 fHeadNoteParentFlags
= parentFlags
;
3341 fHeadNoteParentConnection
= parentConnection
;
3342 return ParentChangeStart();
3346 //*********************************************************************************
3347 // [private] notifyInterestedDrivers
3348 //*********************************************************************************
3350 bool IOService::notifyInterestedDrivers ( void )
3352 IOPMinformee
* informee
;
3353 IOPMinformeeList
* list
= fInterestedDrivers
;
3354 DriverCallParam
* param
;
3357 PM_ASSERT_IN_GATE();
3358 assert( fDriverCallParamCount
== 0 );
3359 assert( fHeadNotePendingAcks
== 0 );
3361 fHeadNotePendingAcks
= 0;
3363 count
= list
->numberOfItems();
3365 goto done
; // no interested drivers
3367 // Allocate an array of interested drivers and their return values
3368 // for the callout thread. Everything else is still "owned" by the
3369 // PM work loop, which can run to process acknowledgePowerChange()
3372 param
= (DriverCallParam
*) fDriverCallParamPtr
;
3373 if (count
> fDriverCallParamSlots
)
3375 if (fDriverCallParamSlots
)
3377 assert(fDriverCallParamPtr
);
3378 IODelete(fDriverCallParamPtr
, DriverCallParam
, fDriverCallParamSlots
);
3379 fDriverCallParamPtr
= 0;
3380 fDriverCallParamSlots
= 0;
3383 param
= IONew(DriverCallParam
, count
);
3385 goto done
; // no memory
3387 fDriverCallParamPtr
= (void *) param
;
3388 fDriverCallParamSlots
= count
;
3391 informee
= list
->firstInList();
3393 for (IOItemCount i
= 0; i
< count
; i
++)
3395 informee
->timer
= -1;
3396 param
[i
].Target
= informee
;
3398 informee
= list
->nextInList( informee
);
3401 fDriverCallParamCount
= count
;
3402 fHeadNotePendingAcks
= count
;
3404 // Block state machine and wait for callout completion.
3405 assert(!fDriverCallBusy
);
3406 fDriverCallBusy
= true;
3407 thread_call_enter( fDriverCallEntry
);
3411 // Return false if there are no interested drivers or could not schedule
3412 // callout thread due to error.
3416 //*********************************************************************************
3417 // [private] notifyInterestedDriversDone
3418 //*********************************************************************************
3420 void IOService::notifyInterestedDriversDone ( void )
3422 IOPMinformee
* informee
;
3424 DriverCallParam
* param
;
3427 PM_ASSERT_IN_GATE();
3428 assert( fDriverCallBusy
== false );
3429 assert( fMachineState
== kIOPM_DriverThreadCallDone
);
3431 param
= (DriverCallParam
*) fDriverCallParamPtr
;
3432 count
= fDriverCallParamCount
;
3436 for (IOItemCount i
= 0; i
< count
; i
++, param
++)
3438 informee
= (IOPMinformee
*) param
->Target
;
3439 result
= param
->Result
;
3441 if ((result
== IOPMAckImplied
) || (result
< 0))
3443 // Interested driver return IOPMAckImplied.
3444 // If informee timer is zero, it must have de-registered
3445 // interest during the thread callout. That also drops
3446 // the pending ack count.
3448 if (fHeadNotePendingAcks
&& informee
->timer
)
3449 fHeadNotePendingAcks
--;
3451 informee
->timer
= 0;
3453 else if (informee
->timer
)
3455 assert(informee
->timer
== -1);
3457 // Driver has not acked, and has returned a positive result.
3458 // Enforce a minimum permissible timeout value.
3459 // Make the min value large enough so timeout is less likely
3460 // to occur if a driver misinterpreted that the return value
3461 // should be in microsecond units. And make it large enough
3462 // to be noticeable if a driver neglects to ack.
3464 if (result
< kMinAckTimeoutTicks
)
3465 result
= kMinAckTimeoutTicks
;
3467 informee
->timer
= (result
/ (ACK_TIMER_PERIOD
/ ns_per_us
)) + 1;
3469 // else, child has already acked or driver has removed interest,
3470 // and head_note_pendingAcks decremented.
3471 // informee may have been removed from the interested drivers list,
3472 // thus the informee must be retained across the callout.
3474 informee
->release();
3477 fDriverCallParamCount
= 0;
3479 if ( fHeadNotePendingAcks
)
3481 OUR_PMLog(kPMLogStartAckTimer
, 0, 0);
3486 MS_POP(); // pushed by notifyAll()
3488 // If interest acks are outstanding, wait for fHeadNotePendingAcks to become
3489 // zero before notifying children. This enforces the children after interest
3490 // ordering even for async interest clients.
3492 if (!fHeadNotePendingAcks
)
3498 MS_PUSH(fMachineState
);
3499 fMachineState
= kIOPM_NotifyChildrenStart
;
3500 PM_LOG2("%s: %u outstanding async interest\n",
3501 getName(), fHeadNotePendingAcks
);
3505 //*********************************************************************************
3506 // [private] notifyChildren
3507 //*********************************************************************************
3509 void IOService::notifyChildren ( void )
3513 IOPowerConnection
* connection
;
3514 OSArray
* children
= 0;
3515 IOPMrootDomain
* rootDomain
;
3516 bool delayNotify
= false;
3518 if ((fHeadNotePowerState
!= fCurrentPowerState
) &&
3519 (IS_POWER_DROP
== fIsPreChange
) &&
3520 ((rootDomain
= getPMRootDomain()) == this))
3522 rootDomain
->tracePoint( IS_POWER_DROP
?
3523 kIOPMTracePointSleepPowerPlaneDrivers
:
3524 kIOPMTracePointWakePowerPlaneDrivers
);
3527 if (fStrictTreeOrder
)
3528 children
= OSArray::withCapacity(8);
3530 // Sum child power consumption in notifyChild()
3531 fHeadNotePowerArrayEntry
->staticPower
= 0;
3533 iter
= getChildIterator(gIOPowerPlane
);
3536 while ((next
= iter
->getNextObject()))
3538 if ((connection
= OSDynamicCast(IOPowerConnection
, next
)))
3540 if (connection
->getReadyFlag() == false)
3542 PM_LOG3("[%s] %s: connection not ready\n",
3543 getName(), __FUNCTION__
);
3547 // Mechanism to postpone the did-change notification to
3548 // certain power children to order those children last.
3549 // Cannot be used together with strict tree ordering.
3551 if (!fIsPreChange
&&
3552 (connection
->delayChildNotification
) &&
3553 getPMRootDomain()->shouldDelayChildNotification(this))
3557 children
= OSArray::withCapacity(8);
3563 children
->setObject( connection
);
3568 if (!delayNotify
&& children
)
3569 children
->setObject( connection
);
3571 notifyChild( connection
);
3577 if (children
&& (children
->getCount() == 0))
3579 children
->release();
3584 assert(fNotifyChildArray
== 0);
3585 fNotifyChildArray
= children
;
3586 MS_PUSH(fMachineState
);
3590 // Wait for exiting child notifications to complete,
3591 // before notifying the children in the array.
3592 fMachineState
= kIOPM_NotifyChildrenDelayed
;
3593 PM_LOG2("%s: %d children in delayed array\n",
3594 getName(), children
->getCount());
3598 // Notify children in the array one at a time.
3599 fMachineState
= kIOPM_NotifyChildrenOrdered
;
3604 //*********************************************************************************
3605 // [private] notifyChildrenOrdered
3606 //*********************************************************************************
3608 void IOService::notifyChildrenOrdered ( void )
3610 PM_ASSERT_IN_GATE();
3611 assert(fNotifyChildArray
);
3612 assert(fMachineState
== kIOPM_NotifyChildrenOrdered
);
3614 // Notify one child, wait for it to ack, then repeat for next child.
3615 // This is a workaround for some drivers with multiple instances at
3616 // the same branch in the power tree, but the driver is slow to power
3617 // up unless the tree ordering is observed. Problem observed only on
3618 // system wake, not on system sleep.
3620 // We have the ability to power off in reverse child index order.
3621 // That works nicely on some machines, but not on all HW configs.
3623 if (fNotifyChildArray
->getCount())
3625 IOPowerConnection
* connection
;
3626 connection
= (IOPowerConnection
*) fNotifyChildArray
->getObject(0);
3627 notifyChild( connection
);
3628 fNotifyChildArray
->removeObject(0);
3632 fNotifyChildArray
->release();
3633 fNotifyChildArray
= 0;
3635 MS_POP(); // pushed by notifyChildren()
3639 //*********************************************************************************
3640 // [private] notifyChildrenDelayed
3641 //*********************************************************************************
3643 void IOService::notifyChildrenDelayed ( void )
3645 IOPowerConnection
* connection
;
3647 PM_ASSERT_IN_GATE();
3648 assert(fNotifyChildArray
);
3649 assert(fMachineState
== kIOPM_NotifyChildrenDelayed
);
3651 // Wait after all non-delayed children and interested drivers have ack'ed,
3652 // then notify all delayed children. When explicitly cancelled, interest
3653 // acks (and ack timer) may still be outstanding.
3655 for (int i
= 0; ; i
++)
3657 connection
= (IOPowerConnection
*) fNotifyChildArray
->getObject(i
);
3661 notifyChild( connection
);
3664 PM_LOG2("%s: notified delayed children\n", getName());
3665 fNotifyChildArray
->release();
3666 fNotifyChildArray
= 0;
3668 MS_POP(); // pushed by notifyChildren()
3671 //*********************************************************************************
3672 // [private] notifyAll
3673 //*********************************************************************************
3675 IOReturn
IOService::notifyAll ( uint32_t nextMS
)
3677 // Save the next machine_state to be restored by notifyInterestedDriversDone()
3679 PM_ASSERT_IN_GATE();
3681 fMachineState
= kIOPM_DriverThreadCallDone
;
3682 fDriverCallReason
= fIsPreChange
?
3683 kDriverCallInformPreChange
: kDriverCallInformPostChange
;
3685 if (!notifyInterestedDrivers())
3686 notifyInterestedDriversDone();
3688 return IOPMWillAckLater
;
3691 //*********************************************************************************
3692 // [private, static] pmDriverCallout
3694 // Thread call context
3695 //*********************************************************************************
3697 IOReturn
IOService::actionDriverCalloutDone (
3699 void * arg0
, void * arg1
,
3700 void * arg2
, void * arg3
)
3702 IOServicePM
* pwrMgt
= (IOServicePM
*) arg0
;
3704 assert( fDriverCallBusy
);
3705 fDriverCallBusy
= false;
3707 assert(gIOPMWorkQueue
);
3708 gIOPMWorkQueue
->signalWorkAvailable();
3710 return kIOReturnSuccess
;
3713 void IOService::pmDriverCallout ( IOService
* from
)
3716 switch (from
->fDriverCallReason
)
3718 case kDriverCallSetPowerState
:
3719 from
->driverSetPowerState();
3722 case kDriverCallInformPreChange
:
3723 case kDriverCallInformPostChange
:
3724 from
->driverInformPowerChange();
3728 panic("IOService::pmDriverCallout bad machine state %x",
3729 from
->fDriverCallReason
);
3732 gIOPMWorkLoop
->runAction(actionDriverCalloutDone
,
3734 /* arg0 */ (void *) from
->pwrMgt
);
3737 //*********************************************************************************
3738 // [private] driverSetPowerState
3740 // Thread call context
3741 //*********************************************************************************
3743 void IOService::driverSetPowerState ( void )
3745 IOPMPowerStateIndex powerState
;
3746 DriverCallParam
* param
;
3747 IOPMDriverCallEntry callEntry
;
3750 uint32_t oldPowerState
= getPowerState();
3752 assert( fDriverCallBusy
);
3753 assert( fDriverCallParamPtr
);
3754 assert( fDriverCallParamCount
== 1 );
3756 param
= (DriverCallParam
*) fDriverCallParamPtr
;
3757 powerState
= fHeadNotePowerState
;
3759 if (assertPMDriverCall(&callEntry
))
3761 OUR_PMLog( kPMLogProgramHardware
, (uintptr_t) this, powerState
);
3762 clock_get_uptime(&fDriverCallStartTime
);
3763 result
= fControllingDriver
->setPowerState( powerState
, this );
3764 clock_get_uptime(&end
);
3765 OUR_PMLog((UInt32
) -kPMLogProgramHardware
, (uintptr_t) this, (UInt32
) result
);
3767 deassertPMDriverCall(&callEntry
);
3771 PM_LOG("%s::setPowerState(%p, %lu -> %lu) returned 0x%x\n",
3772 fName
, this, fCurrentPowerState
, powerState
, result
);
3775 #if LOG_SETPOWER_TIMES
3776 if ((result
== IOPMAckImplied
) || (result
< 0))
3780 SUB_ABSOLUTETIME(&end
, &fDriverCallStartTime
);
3781 absolutetime_to_nanoseconds(end
, &nsec
);
3782 if (nsec
> LOG_SETPOWER_TIMES
)
3783 PM_LOG("%s::setPowerState(%p, %lu -> %lu) took %d ms\n",
3784 fName
, this, fCurrentPowerState
, powerState
, NS_TO_MS(nsec
));
3786 PMEventDetails
*details
= PMEventDetails::eventDetails(
3787 kIOPMEventTypeSetPowerStateImmediate
, // type
3789 (uintptr_t)this, // owner unique
3790 NULL
, // interest name
3791 (uint8_t)oldPowerState
, // old
3792 (uint8_t)powerState
, // new
3794 NS_TO_US(nsec
)); // usec completion time
3796 getPMRootDomain()->recordAndReleasePMEventGated( details
);
3801 result
= kIOPMAckImplied
;
3803 param
->Result
= result
;
3806 //*********************************************************************************
3807 // [private] driverInformPowerChange
3809 // Thread call context
3810 //*********************************************************************************
3812 void IOService::driverInformPowerChange ( void )
3814 IOPMinformee
* informee
;
3816 DriverCallParam
* param
;
3817 IOPMDriverCallEntry callEntry
;
3818 IOPMPowerFlags powerFlags
;
3819 IOPMPowerStateIndex powerState
;
3824 assert( fDriverCallBusy
);
3825 assert( fDriverCallParamPtr
);
3826 assert( fDriverCallParamCount
);
3828 param
= (DriverCallParam
*) fDriverCallParamPtr
;
3829 count
= fDriverCallParamCount
;
3831 powerFlags
= fHeadNotePowerArrayEntry
->capabilityFlags
;
3832 powerState
= fHeadNotePowerState
;
3834 for (IOItemCount i
= 0; i
< count
; i
++)
3836 informee
= (IOPMinformee
*) param
->Target
;
3837 driver
= informee
->whatObject
;
3839 if (assertPMDriverCall(&callEntry
, 0, informee
))
3841 if (fDriverCallReason
== kDriverCallInformPreChange
)
3843 OUR_PMLog(kPMLogInformDriverPreChange
, (uintptr_t) this, powerState
);
3844 clock_get_uptime(&informee
->startTime
);
3845 result
= driver
->powerStateWillChangeTo(powerFlags
, powerState
, this);
3846 clock_get_uptime(&end
);
3847 OUR_PMLog((UInt32
)-kPMLogInformDriverPreChange
, (uintptr_t) this, result
);
3851 OUR_PMLog(kPMLogInformDriverPostChange
, (uintptr_t) this, powerState
);
3852 clock_get_uptime(&informee
->startTime
);
3853 result
= driver
->powerStateDidChangeTo(powerFlags
, powerState
, this);
3854 clock_get_uptime(&end
);
3855 OUR_PMLog((UInt32
)-kPMLogInformDriverPostChange
, (uintptr_t) this, result
);
3858 deassertPMDriverCall(&callEntry
);
3860 #if LOG_SETPOWER_TIMES
3861 if ((result
== IOPMAckImplied
) || (result
< 0))
3865 SUB_ABSOLUTETIME(&end
, &informee
->startTime
);
3866 absolutetime_to_nanoseconds(end
, &nsec
);
3867 if (nsec
> LOG_SETPOWER_TIMES
)
3868 PM_LOG("%s::powerState%sChangeTo(%p, %s, %lu -> %lu) took %d ms\n",
3870 (fDriverCallReason
== kDriverCallInformPreChange
) ? "Will" : "Did",
3871 driver
, fName
, fCurrentPowerState
, powerState
, NS_TO_MS(nsec
));
3873 uint16_t logType
= (fDriverCallReason
== kDriverCallInformPreChange
)
3874 ? kIOPMEventTypePSWillChangeTo
3875 : kIOPMEventTypePSDidChangeTo
;
3877 PMEventDetails
*details
= PMEventDetails::eventDetails(
3880 (uintptr_t)this, // owner unique
3881 driver
->getName(), // interest name
3882 (uint8_t)fCurrentPowerState
, // old
3883 (uint8_t)fHeadNotePowerState
, // new
3885 NS_TO_US(nsec
)); // usec completion time
3887 getPMRootDomain()->recordAndReleasePMEventGated( details
);
3892 result
= kIOPMAckImplied
;
3894 param
->Result
= result
;
3899 //*********************************************************************************
3900 // [private] notifyChild
3902 // Notify a power domain child of an upcoming power change.
3903 // If the object acknowledges the current change, we return TRUE.
3904 //*********************************************************************************
3906 bool IOService::notifyChild ( IOPowerConnection
* theNub
)
3908 IOReturn ret
= IOPMAckImplied
;
3909 unsigned long childPower
;
3910 IOService
* theChild
;
3911 IOPMRequest
* childRequest
;
3912 IOPMPowerChangeFlags requestArg2
;
3915 PM_ASSERT_IN_GATE();
3916 theChild
= (IOService
*)(theNub
->copyChildEntry(gIOPowerPlane
));
3922 // Unless the child handles the notification immediately and returns
3923 // kIOPMAckImplied, we'll be awaiting their acknowledgement later.
3924 fHeadNotePendingAcks
++;
3925 theNub
->setAwaitingAck(true);
3927 requestArg2
= fHeadNoteChangeFlags
;
3928 if (fHeadNotePowerState
< fCurrentPowerState
)
3929 requestArg2
|= kIOPMDomainPowerDrop
;
3931 requestType
= fIsPreChange
?
3932 kIOPMRequestTypePowerDomainWillChange
:
3933 kIOPMRequestTypePowerDomainDidChange
;
3935 childRequest
= acquirePMRequest( theChild
, requestType
);
3939 childRequest
->fArg0
= (void *) fHeadNotePowerArrayEntry
->outputPowerFlags
;
3940 childRequest
->fArg1
= (void *) theNub
;
3941 childRequest
->fArg2
= (void *) requestArg2
;
3942 theChild
->submitPMRequest( childRequest
);
3943 ret
= IOPMWillAckLater
;
3947 ret
= IOPMAckImplied
;
3948 fHeadNotePendingAcks
--;
3949 theNub
->setAwaitingAck(false);
3950 childPower
= theChild
->currentPowerConsumption();
3951 if ( childPower
== kIOPMUnknown
)
3953 fHeadNotePowerArrayEntry
->staticPower
= kIOPMUnknown
;
3955 if (fHeadNotePowerArrayEntry
->staticPower
!= kIOPMUnknown
)
3956 fHeadNotePowerArrayEntry
->staticPower
+= childPower
;
3960 theChild
->release();
3961 return (IOPMAckImplied
== ret
);
3964 //*********************************************************************************
3965 // [private] notifyControllingDriver
3966 //*********************************************************************************
3968 bool IOService::notifyControllingDriver ( void )
3970 DriverCallParam
* param
;
3972 PM_ASSERT_IN_GATE();
3973 assert( fDriverCallParamCount
== 0 );
3974 assert( fControllingDriver
);
3976 if (fInitialSetPowerState
)
3978 fInitialSetPowerState
= false;
3979 fHeadNoteChangeFlags
|= kIOPMInitialPowerChange
;
3981 // Driver specified flag to skip the inital setPowerState()
3982 if (fHeadNotePowerArrayEntry
->capabilityFlags
& kIOPMInitialDeviceState
)
3988 param
= (DriverCallParam
*) fDriverCallParamPtr
;
3991 param
= IONew(DriverCallParam
, 1);
3993 return false; // no memory
3995 fDriverCallParamPtr
= (void *) param
;
3996 fDriverCallParamSlots
= 1;
3999 param
->Target
= fControllingDriver
;
4000 fDriverCallParamCount
= 1;
4003 // Block state machine and wait for callout completion.
4004 assert(!fDriverCallBusy
);
4005 fDriverCallBusy
= true;
4006 thread_call_enter( fDriverCallEntry
);
4011 //*********************************************************************************
4012 // [private] notifyControllingDriverDone
4013 //*********************************************************************************
4015 void IOService::notifyControllingDriverDone( void )
4017 DriverCallParam
* param
;
4020 PM_ASSERT_IN_GATE();
4021 param
= (DriverCallParam
*) fDriverCallParamPtr
;
4023 assert( fDriverCallBusy
== false );
4024 assert( fMachineState
== kIOPM_DriverThreadCallDone
);
4026 if (param
&& fDriverCallParamCount
)
4028 assert(fDriverCallParamCount
== 1);
4030 // the return value from setPowerState()
4031 result
= param
->Result
;
4033 if ((result
== IOPMAckImplied
) || (result
< 0))
4037 else if (fDriverTimer
)
4039 assert(fDriverTimer
== -1);
4041 // Driver has not acked, and has returned a positive result.
4042 // Enforce a minimum permissible timeout value.
4043 // Make the min value large enough so timeout is less likely
4044 // to occur if a driver misinterpreted that the return value
4045 // should be in microsecond units. And make it large enough
4046 // to be noticeable if a driver neglects to ack.
4048 if (result
< kMinAckTimeoutTicks
)
4049 result
= kMinAckTimeoutTicks
;
4051 fDriverTimer
= (result
/ (ACK_TIMER_PERIOD
/ ns_per_us
)) + 1;
4053 // else, child has already acked and driver_timer reset to 0.
4055 fDriverCallParamCount
= 0;
4059 OUR_PMLog(kPMLogStartAckTimer
, 0, 0);
4064 MS_POP(); // pushed by OurChangeSetPowerState()
4065 fIsPreChange
= false;
4068 //*********************************************************************************
4069 // [private] all_done
4071 // A power change is done.
4072 //*********************************************************************************
4074 void IOService::all_done ( void )
4076 IOPMPowerStateIndex prevPowerState
;
4077 const IOPMPSEntry
* powerStatePtr
;
4078 IOPMDriverCallEntry callEntry
;
4079 uint32_t prevMachineState
= fMachineState
;
4080 bool callAction
= false;
4082 fMachineState
= kIOPM_Finished
;
4084 if ((fHeadNoteChangeFlags
& kIOPMSynchronize
) &&
4085 ((prevMachineState
== kIOPM_Finished
) ||
4086 (prevMachineState
== kIOPM_SyncFinish
)))
4088 // Sync operation and no power change occurred.
4089 // Do not inform driver and clients about this request completion,
4090 // except for the originator (root domain).
4092 PM_ACTION_2(actionPowerChangeDone
,
4093 fHeadNotePowerState
, fHeadNoteChangeFlags
);
4095 if (getPMRequestType() == kIOPMRequestTypeSynchronizePowerTree
)
4097 powerChangeDone(fCurrentPowerState
);
4099 else if (fAdvisoryTickleUsed
)
4101 // Not root domain and advisory tickle target
4102 // Re-adjust power after power tree sync at the 'did' pass
4103 if (!fAdjustPowerScheduled
&&
4104 (fHeadNoteChangeFlags
& kIOPMDomainDidChange
))
4106 IOPMRequest
* request
;
4107 request
= acquirePMRequest( this, kIOPMRequestTypeAdjustPowerState
);
4110 submitPMRequest( request
);
4111 fAdjustPowerScheduled
= true;
4120 if ( fHeadNoteChangeFlags
& kIOPMSelfInitiated
)
4122 // could our driver switch to the new state?
4123 if ( !( fHeadNoteChangeFlags
& kIOPMNotDone
) )
4125 trackSystemSleepPreventers(
4126 fCurrentPowerState
, fHeadNotePowerState
, fHeadNoteChangeFlags
);
4128 // we changed, tell our parent
4129 requestDomainPower(fHeadNotePowerState
);
4131 // yes, did power raise?
4132 if ( fCurrentPowerState
< fHeadNotePowerState
)
4134 // yes, inform clients and apps
4135 tellChangeUp (fHeadNotePowerState
);
4137 prevPowerState
= fCurrentPowerState
;
4139 fCurrentPowerState
= fHeadNotePowerState
;
4141 fPMVars
->myCurrentState
= fCurrentPowerState
;
4143 OUR_PMLog(kPMLogChangeDone
, fCurrentPowerState
, prevPowerState
);
4144 PM_ACTION_2(actionPowerChangeDone
,
4145 fHeadNotePowerState
, fHeadNoteChangeFlags
);
4148 powerStatePtr
= &fPowerStates
[fCurrentPowerState
];
4149 fCurrentCapabilityFlags
= powerStatePtr
->capabilityFlags
;
4150 if (fCurrentCapabilityFlags
& kIOPMStaticPowerValid
)
4151 fCurrentPowerConsumption
= powerStatePtr
->staticPower
;
4153 // inform subclass policy-maker
4154 if (fPCDFunctionOverride
&& fParentsKnowState
&&
4155 assertPMDriverCall(&callEntry
, kIOPMADC_NoInactiveCheck
))
4157 powerChangeDone(prevPowerState
);
4158 deassertPMDriverCall(&callEntry
);
4161 else if (getPMRequestType() == kIOPMRequestTypeRequestPowerStateOverride
)
4163 // changePowerStateWithOverrideTo() was cancelled
4164 fOverrideMaxPowerState
= kIOPMPowerStateMax
;
4168 // parent's power change
4169 if ( fHeadNoteChangeFlags
& kIOPMParentInitiated
)
4171 if (((fHeadNoteChangeFlags
& kIOPMDomainWillChange
) &&
4172 (fCurrentPowerState
>= fHeadNotePowerState
)) ||
4173 ((fHeadNoteChangeFlags
& kIOPMDomainDidChange
) &&
4174 (fCurrentPowerState
< fHeadNotePowerState
)))
4176 trackSystemSleepPreventers(
4177 fCurrentPowerState
, fHeadNotePowerState
, fHeadNoteChangeFlags
);
4180 if ( fCurrentPowerState
< fHeadNotePowerState
)
4182 // yes, inform clients and apps
4183 tellChangeUp (fHeadNotePowerState
);
4186 prevPowerState
= fCurrentPowerState
;
4187 fCurrentPowerState
= fHeadNotePowerState
;
4189 fPMVars
->myCurrentState
= fCurrentPowerState
;
4191 fMaxPowerState
= fControllingDriver
->maxCapabilityForDomainState(fHeadNoteDomainFlags
);
4193 OUR_PMLog(kPMLogChangeDone
, fCurrentPowerState
, prevPowerState
);
4194 PM_ACTION_2(actionPowerChangeDone
,
4195 fHeadNotePowerState
, fHeadNoteChangeFlags
);
4198 powerStatePtr
= &fPowerStates
[fCurrentPowerState
];
4199 fCurrentCapabilityFlags
= powerStatePtr
->capabilityFlags
;
4200 if (fCurrentCapabilityFlags
& kIOPMStaticPowerValid
)
4201 fCurrentPowerConsumption
= powerStatePtr
->staticPower
;
4203 // inform subclass policy-maker
4204 if (fPCDFunctionOverride
&& fParentsKnowState
&&
4205 assertPMDriverCall(&callEntry
, kIOPMADC_NoInactiveCheck
))
4207 powerChangeDone(prevPowerState
);
4208 deassertPMDriverCall(&callEntry
);
4213 // When power rises enough to satisfy the tickle's desire for more power,
4214 // the condition preventing idle-timer from dropping power is removed.
4216 if (fCurrentPowerState
>= fIdleTimerMinPowerState
)
4218 fIdleTimerMinPowerState
= 0;
4223 PM_ACTION_2(actionPowerChangeDone
,
4224 fHeadNotePowerState
, fHeadNoteChangeFlags
);
4229 // MARK: Power Change Initiated by Driver
4231 //*********************************************************************************
4232 // [private] OurChangeStart
4234 // Begin the processing of a power change initiated by us.
4235 //*********************************************************************************
4237 void IOService::OurChangeStart ( void )
4239 PM_ASSERT_IN_GATE();
4240 OUR_PMLog( kPMLogStartDeviceChange
, fHeadNotePowerState
, fCurrentPowerState
);
4242 // fMaxPowerState is our maximum possible power state based on the current
4243 // power state of our parents. If we are trying to raise power beyond the
4244 // maximum, send an async request for more power to all parents.
4246 if (!IS_PM_ROOT
&& (fMaxPowerState
< fHeadNotePowerState
))
4248 fHeadNoteChangeFlags
|= kIOPMNotDone
;
4249 requestDomainPower(fHeadNotePowerState
);
4254 // Redundant power changes skips to the end of the state machine.
4256 if (!fInitialPowerChange
&& (fHeadNotePowerState
== fCurrentPowerState
))
4261 fInitialPowerChange
= false;
4263 // Change started, but may not complete...
4264 // Can be canceled (power drop) or deferred (power rise).
4266 PM_ACTION_2(actionPowerChangeStart
, fHeadNotePowerState
, &fHeadNoteChangeFlags
);
4268 // Two separate paths, depending if power is being raised or lowered.
4269 // Lowering power is subject to approval by clients of this service.
4273 fDoNotPowerDown
= false;
4275 // Ask for persmission to drop power state
4276 fMachineState
= kIOPM_OurChangeTellClientsPowerDown
;
4277 fOutOfBandParameter
= kNotifyApps
;
4278 askChangeDown(fHeadNotePowerState
);
4282 // This service is raising power and parents are able to support the
4283 // new power state. However a parent may have already committed to
4284 // drop power, which might force this object to temporarily drop power.
4285 // This results in "oscillations" before the state machines converge
4286 // to a steady state.
4288 // To prevent this, a child must make a power reservation against all
4289 // parents before raising power. If the reservation fails, indicating
4290 // that the child will be unable to sustain the higher power state,
4291 // then the child will signal the parent to adjust power, and the child
4292 // will defer its power change.
4296 // Reserve parent power necessary to achieve fHeadNotePowerState.
4297 ret
= requestDomainPower( fHeadNotePowerState
, kReserveDomainPower
);
4298 if (ret
!= kIOReturnSuccess
)
4300 // Reservation failed, defer power rise.
4301 fHeadNoteChangeFlags
|= kIOPMNotDone
;
4306 OurChangeTellCapabilityWillChange();
4310 //*********************************************************************************
4312 struct IOPMRequestDomainPowerContext
{
4313 IOService
* child
; // the requesting child
4314 IOPMPowerFlags requestPowerFlags
; // power flags requested by child
4318 requestDomainPowerApplier(
4319 IORegistryEntry
* entry
,
4322 IOPowerConnection
* connection
;
4324 IOPMRequestDomainPowerContext
* context
;
4326 if ((connection
= OSDynamicCast(IOPowerConnection
, entry
)) == 0)
4328 parent
= (IOService
*) connection
->copyParentEntry(gIOPowerPlane
);
4333 context
= (IOPMRequestDomainPowerContext
*) inContext
;
4335 if (connection
->parentKnowsState() && connection
->getReadyFlag())
4337 parent
->requestPowerDomainState(
4338 context
->requestPowerFlags
,
4346 //*********************************************************************************
4347 // [private] requestDomainPower
4348 //*********************************************************************************
4350 IOReturn
IOService::requestDomainPower(
4351 IOPMPowerStateIndex ourPowerState
,
4352 IOOptionBits options
)
4354 IOPMPowerFlags requestPowerFlags
;
4355 IOPMPowerStateIndex maxPowerState
;
4356 IOPMRequestDomainPowerContext context
;
4358 PM_ASSERT_IN_GATE();
4359 assert(ourPowerState
< fNumberOfPowerStates
);
4360 if (ourPowerState
>= fNumberOfPowerStates
)
4361 return kIOReturnBadArgument
;
4363 return kIOReturnSuccess
;
4365 // Fetch the input power flags for the requested power state.
4366 // Parent request is stated in terms of required power flags.
4368 requestPowerFlags
= fPowerStates
[ourPowerState
].inputPowerFlags
;
4370 // Disregard the "previous request" for power reservation.
4372 if (((options
& kReserveDomainPower
) == 0) &&
4373 (fPreviousRequestPowerFlags
== requestPowerFlags
))
4375 // skip if domain already knows our requirements
4378 fPreviousRequestPowerFlags
= requestPowerFlags
;
4380 context
.child
= this;
4381 context
.requestPowerFlags
= requestPowerFlags
;
4382 fHeadNoteDomainTargetFlags
= 0;
4383 applyToParents(requestDomainPowerApplier
, &context
, gIOPowerPlane
);
4385 if (options
& kReserveDomainPower
)
4387 maxPowerState
= fControllingDriver
->maxCapabilityForDomainState(
4388 fHeadNoteDomainTargetFlags
);
4390 if (maxPowerState
< fHeadNotePowerState
)
4392 PM_LOG1("%s: power desired %u:0x%x got %u:0x%x\n",
4394 (uint32_t) ourPowerState
, (uint32_t) requestPowerFlags
,
4395 (uint32_t) maxPowerState
, (uint32_t) fHeadNoteDomainTargetFlags
);
4396 return kIOReturnNoPower
;
4401 return kIOReturnSuccess
;
4404 //*********************************************************************************
4405 // [private] OurSyncStart
4406 //*********************************************************************************
4408 void IOService::OurSyncStart ( void )
4410 PM_ASSERT_IN_GATE();
4412 if (fInitialPowerChange
)
4415 PM_ACTION_2(actionPowerChangeStart
, fHeadNotePowerState
, &fHeadNoteChangeFlags
);
4417 if (fHeadNoteChangeFlags
& kIOPMNotDone
)
4423 if (fHeadNoteChangeFlags
& kIOPMSyncTellPowerDown
)
4425 fDoNotPowerDown
= false;
4427 // Ask for permission to drop power state
4428 fMachineState
= kIOPM_SyncTellClientsPowerDown
;
4429 fOutOfBandParameter
= kNotifyApps
;
4430 askChangeDown(fHeadNotePowerState
);
4434 // Only inform capability app and clients.
4435 tellSystemCapabilityChange( kIOPM_SyncNotifyWillChange
);
4439 //*********************************************************************************
4440 // [private] OurChangeTellClientsPowerDown
4442 // All applications and kernel clients have acknowledged our permission to drop
4443 // power. Here we notify them that we will lower the power and wait for acks.
4444 //*********************************************************************************
4446 void IOService::OurChangeTellClientsPowerDown ( void )
4448 fMachineState
= kIOPM_OurChangeTellPriorityClientsPowerDown
;
4449 tellChangeDown1(fHeadNotePowerState
);
4452 //*********************************************************************************
4453 // [private] OurChangeTellPriorityClientsPowerDown
4455 // All applications and kernel clients have acknowledged our intention to drop
4456 // power. Here we notify "priority" clients that we are lowering power.
4457 //*********************************************************************************
4459 void IOService::OurChangeTellPriorityClientsPowerDown ( void )
4461 fMachineState
= kIOPM_OurChangeNotifyInterestedDriversWillChange
;
4462 tellChangeDown2(fHeadNotePowerState
);
4465 //*********************************************************************************
4466 // [private] OurChangeTellCapabilityWillChange
4468 // Extra stage for root domain to notify apps and drivers about the
4469 // system capability change when raising power state.
4470 //*********************************************************************************
4472 void IOService::OurChangeTellCapabilityWillChange ( void )
4474 if (!IS_ROOT_DOMAIN
)
4475 return OurChangeNotifyInterestedDriversWillChange();
4477 tellSystemCapabilityChange( kIOPM_OurChangeNotifyInterestedDriversWillChange
);
4480 //*********************************************************************************
4481 // [private] OurChangeNotifyInterestedDriversWillChange
4483 // All applications and kernel clients have acknowledged our power state change.
4484 // Here we notify interested drivers pre-change.
4485 //*********************************************************************************
4487 void IOService::OurChangeNotifyInterestedDriversWillChange ( void )
4489 IOPMrootDomain
* rootDomain
;
4490 if ((rootDomain
= getPMRootDomain()) == this)
4494 rootDomain
->tracePoint( kIOPMTracePointSleepWillChangeInterests
);
4496 PMEventDetails
*details
= PMEventDetails::eventDetails(
4497 kIOPMEventTypeAppNotificationsFinished
,
4501 rootDomain
->recordAndReleasePMEventGated( details
);
4504 rootDomain
->tracePoint( kIOPMTracePointWakeWillChangeInterests
);
4507 notifyAll( kIOPM_OurChangeSetPowerState
);
4510 //*********************************************************************************
4511 // [private] OurChangeSetPowerState
4513 // Instruct our controlling driver to program the hardware for the power state
4514 // change. Wait for async completions.
4515 //*********************************************************************************
4517 void IOService::OurChangeSetPowerState ( void )
4519 MS_PUSH( kIOPM_OurChangeWaitForPowerSettle
);
4520 fMachineState
= kIOPM_DriverThreadCallDone
;
4521 fDriverCallReason
= kDriverCallSetPowerState
;
4523 if (notifyControllingDriver() == false)
4524 notifyControllingDriverDone();
4527 //*********************************************************************************
4528 // [private] OurChangeWaitForPowerSettle
4530 // Our controlling driver has completed the power state change we initiated.
4531 // Wait for the driver specified settle time to expire.
4532 //*********************************************************************************
4534 void IOService::OurChangeWaitForPowerSettle ( void )
4536 fMachineState
= kIOPM_OurChangeNotifyInterestedDriversDidChange
;
4540 //*********************************************************************************
4541 // [private] OurChangeNotifyInterestedDriversDidChange
4543 // Power has settled on a power change we initiated. Here we notify
4544 // all our interested drivers post-change.
4545 //*********************************************************************************
4547 void IOService::OurChangeNotifyInterestedDriversDidChange ( void )
4549 IOPMrootDomain
* rootDomain
;
4550 if ((rootDomain
= getPMRootDomain()) == this)
4552 rootDomain
->tracePoint( IS_POWER_DROP
?
4553 kIOPMTracePointSleepDidChangeInterests
:
4554 kIOPMTracePointWakeDidChangeInterests
);
4557 notifyAll( kIOPM_OurChangeTellCapabilityDidChange
);
4560 //*********************************************************************************
4561 // [private] OurChangeTellCapabilityDidChange
4563 // For root domain to notify capability power-change.
4564 //*********************************************************************************
4566 void IOService::OurChangeTellCapabilityDidChange ( void )
4568 if (!IS_ROOT_DOMAIN
)
4569 return OurChangeFinish();
4571 getPMRootDomain()->tracePoint( IS_POWER_DROP
?
4572 kIOPMTracePointSleepCapabilityClients
:
4573 kIOPMTracePointWakeCapabilityClients
);
4575 tellSystemCapabilityChange( kIOPM_OurChangeFinish
);
4578 //*********************************************************************************
4579 // [private] OurChangeFinish
4581 // Done with this self-induced power state change.
4582 //*********************************************************************************
4584 void IOService::OurChangeFinish ( void )
4590 // MARK: Power Change Initiated by Parent
4592 //*********************************************************************************
4593 // [private] ParentChangeStart
4595 // Here we begin the processing of a power change initiated by our parent.
4596 //*********************************************************************************
4598 IOReturn
IOService::ParentChangeStart ( void )
4600 PM_ASSERT_IN_GATE();
4601 OUR_PMLog( kPMLogStartParentChange
, fHeadNotePowerState
, fCurrentPowerState
);
4603 // Power domain is lowering power
4604 if ( fHeadNotePowerState
< fCurrentPowerState
)
4606 // Piggy-back idle timer cancellation on a parent down
4607 if (0 == fHeadNotePowerState
)
4608 ParentChangeCancelIdleTimer(fHeadNotePowerState
);
4610 // TODO: redundant? See handlePowerDomainWillChangeTo()
4611 setParentInfo( fHeadNoteParentFlags
, fHeadNoteParentConnection
, true );
4613 PM_ACTION_2(actionPowerChangeStart
, fHeadNotePowerState
, &fHeadNoteChangeFlags
);
4615 // Tell apps and kernel clients
4616 fInitialPowerChange
= false;
4617 fMachineState
= kIOPM_ParentChangeTellPriorityClientsPowerDown
;
4618 tellChangeDown1(fHeadNotePowerState
);
4619 return IOPMWillAckLater
;
4622 // Power domain is raising power
4623 if ( fHeadNotePowerState
> fCurrentPowerState
)
4625 if ( fDesiredPowerState
> fCurrentPowerState
)
4627 if ( fDesiredPowerState
< fHeadNotePowerState
)
4629 // We power up, but not all the way
4630 fHeadNotePowerState
= fDesiredPowerState
;
4631 fHeadNotePowerArrayEntry
= &fPowerStates
[fDesiredPowerState
];
4632 OUR_PMLog(kPMLogAmendParentChange
, fHeadNotePowerState
, 0);
4635 // We don't need to change
4636 fHeadNotePowerState
= fCurrentPowerState
;
4637 fHeadNotePowerArrayEntry
= &fPowerStates
[fCurrentPowerState
];
4638 OUR_PMLog(kPMLogAmendParentChange
, fHeadNotePowerState
, 0);
4642 if ( fHeadNoteChangeFlags
& kIOPMDomainDidChange
)
4644 if ( fHeadNotePowerState
> fCurrentPowerState
)
4646 PM_ACTION_2(actionPowerChangeStart
,
4647 fHeadNotePowerState
, &fHeadNoteChangeFlags
);
4649 // Parent did change up - start our change up
4650 fInitialPowerChange
= false;
4651 ParentChangeTellCapabilityWillChange();
4652 return IOPMWillAckLater
;
4654 else if (fHeadNoteChangeFlags
& kIOPMSynchronize
)
4656 // We do not need to change power state, but notify
4657 // children to propagate tree synchronization.
4658 fMachineState
= kIOPM_SyncNotifyDidChange
;
4659 fDriverCallReason
= kDriverCallInformPreChange
;
4661 return IOPMWillAckLater
;
4666 return IOPMAckImplied
;
4669 //*********************************************************************************
4670 // [private] ParentChangeTellPriorityClientsPowerDown
4672 // All applications and kernel clients have acknowledged our intention to drop
4673 // power. Here we notify "priority" clients that we are lowering power.
4674 //*********************************************************************************
4676 void IOService::ParentChangeTellPriorityClientsPowerDown ( void )
4678 fMachineState
= kIOPM_ParentChangeNotifyInterestedDriversWillChange
;
4679 tellChangeDown2(fHeadNotePowerState
);
4682 //*********************************************************************************
4683 // [private] ParentChangeTellCapabilityWillChange
4685 // All (legacy) applications and kernel clients have acknowledged, extra stage for
4686 // root domain to notify apps and drivers about the system capability change.
4687 //*********************************************************************************
4689 void IOService::ParentChangeTellCapabilityWillChange ( void )
4691 if (!IS_ROOT_DOMAIN
)
4692 return ParentChangeNotifyInterestedDriversWillChange();
4694 tellSystemCapabilityChange( kIOPM_ParentChangeNotifyInterestedDriversWillChange
);
4697 //*********************************************************************************
4698 // [private] ParentChangeNotifyInterestedDriversWillChange
4700 // All applications and kernel clients have acknowledged our power state change.
4701 // Here we notify interested drivers pre-change.
4702 //*********************************************************************************
4704 void IOService::ParentChangeNotifyInterestedDriversWillChange ( void )
4706 notifyAll( kIOPM_ParentChangeSetPowerState
);
4709 //*********************************************************************************
4710 // [private] ParentChangeSetPowerState
4712 // Instruct our controlling driver to program the hardware for the power state
4713 // change. Wait for async completions.
4714 //*********************************************************************************
4716 void IOService::ParentChangeSetPowerState ( void )
4718 MS_PUSH( kIOPM_ParentChangeWaitForPowerSettle
);
4719 fMachineState
= kIOPM_DriverThreadCallDone
;
4720 fDriverCallReason
= kDriverCallSetPowerState
;
4722 if (notifyControllingDriver() == false)
4723 notifyControllingDriverDone();
4726 //*********************************************************************************
4727 // [private] ParentChangeWaitForPowerSettle
4729 // Our controlling driver has completed the power state change initiated by our
4730 // parent. Wait for the driver specified settle time to expire.
4731 //*********************************************************************************
4733 void IOService::ParentChangeWaitForPowerSettle ( void )
4735 fMachineState
= kIOPM_ParentChangeNotifyInterestedDriversDidChange
;
4739 //*********************************************************************************
4740 // [private] ParentChangeNotifyInterestedDriversDidChange
4742 // Power has settled on a power change initiated by our parent. Here we notify
4743 // all our interested drivers post-change.
4744 //*********************************************************************************
4746 void IOService::ParentChangeNotifyInterestedDriversDidChange ( void )
4748 notifyAll( kIOPM_ParentChangeTellCapabilityDidChange
);
4751 //*********************************************************************************
4752 // [private] ParentChangeTellCapabilityDidChange
4754 // For root domain to notify capability power-change.
4755 //*********************************************************************************
4757 void IOService::ParentChangeTellCapabilityDidChange ( void )
4759 if (!IS_ROOT_DOMAIN
)
4760 return ParentChangeAcknowledgePowerChange();
4762 tellSystemCapabilityChange( kIOPM_ParentChangeAcknowledgePowerChange
);
4765 //*********************************************************************************
4766 // [private] ParentAcknowledgePowerChange
4768 // Acknowledge our power parent that our power change is done.
4769 //*********************************************************************************
4771 void IOService::ParentChangeAcknowledgePowerChange ( void )
4773 IORegistryEntry
* nub
;
4776 nub
= fHeadNoteParentConnection
;
4779 parent
= (IOService
*)nub
->copyParentEntry(gIOPowerPlane
);
4782 parent
->acknowledgePowerChange((IOService
*)nub
);
4788 void IOService::ParentChangeCancelIdleTimer( IOPMPowerStateIndex newPowerState
)
4792 bool cancel
= false;
4794 // No ready or idle timer not in use
4795 if (!initialized
|| !fIdleTimerPeriod
|| fLockedFlags
.PMStop
||
4796 !fAdvisoryTickleUsed
)
4799 // Not allowed to induce artifical idle timeout
4800 if (fIdleTimerIgnored
|| fIdleTimerMinPowerState
)
4803 // Idle timer already has no influence
4804 if (!fDesiredPowerState
|| fIdleTimerStopped
)
4807 IOLockLock(fActivityLock
);
4809 if (!fDeviceWasActive
)
4811 // No tickles since the last idle timer expiration.
4812 // Safe to drop the device desire to zero.
4817 // Was tickled since the last idle timer expiration,
4818 // but not in the last minute.
4819 clock_get_uptime(&now
);
4820 SUB_ABSOLUTETIME(&now
, &fDeviceActiveTimestamp
);
4821 absolutetime_to_nanoseconds(now
, &nsec
);
4822 if (nsec
>= kNoTickleCancelWindow
)
4830 // Force the next tickle to raise power state
4831 fActivityTicklePowerState
= kInvalidTicklePowerState
;
4832 fDeviceWasActive
= false;
4835 IOLockUnlock(fActivityLock
);
4839 // cancel idle timer
4840 if (fIdleTimer
&& thread_call_cancel(fIdleTimer
))
4843 updatePowerClient(gIOPMPowerClientDevice
, 0);
4844 computeDesiredState();
4846 fIdleTimerStopped
= true;
4850 OUR_PMLog( kPMLogStartParentChange
, fHeadNotePowerState
, fCurrentPowerState
);
4851 PM_LOG("%s::%s cancel=%d\n", fName
, __FUNCTION__
, cancel
);
4855 // MARK: Ack and Settle timers
4857 //*********************************************************************************
4858 // [private] settleTimerExpired
4860 // Power has settled after our last change. Notify interested parties that
4861 // there is a new power state.
4862 //*********************************************************************************
4864 void IOService::settleTimerExpired( void )
4867 gIOPMWorkQueue
->signalWorkAvailable();
4870 //*********************************************************************************
4871 // settle_timer_expired
4873 // Holds a retain while the settle timer callout is in flight.
4874 //*********************************************************************************
4877 settle_timer_expired( thread_call_param_t arg0
, thread_call_param_t arg1
)
4879 IOService
* me
= (IOService
*) arg0
;
4881 if (gIOPMWorkLoop
&& gIOPMWorkQueue
)
4883 gIOPMWorkLoop
->runAction(
4884 OSMemberFunctionCast(IOWorkLoop::Action
, me
, &IOService::settleTimerExpired
),
4890 //*********************************************************************************
4891 // [private] startSettleTimer
4893 // Calculate a power-settling delay in microseconds and start a timer.
4894 //*********************************************************************************
4896 void IOService::startSettleTimer( void )
4898 AbsoluteTime deadline
;
4899 IOPMPowerStateIndex i
;
4900 uint32_t settleTime
= 0;
4903 PM_ASSERT_IN_GATE();
4905 i
= fCurrentPowerState
;
4908 if ( fHeadNotePowerState
< fCurrentPowerState
)
4910 while ( i
> fHeadNotePowerState
)
4912 settleTime
+= (uint32_t) fPowerStates
[i
].settleDownTime
;
4918 if ( fHeadNotePowerState
> fCurrentPowerState
)
4920 while ( i
< fHeadNotePowerState
)
4922 settleTime
+= (uint32_t) fPowerStates
[i
+1].settleUpTime
;
4930 clock_interval_to_deadline(settleTime
, kMicrosecondScale
, &deadline
);
4931 pending
= thread_call_enter_delayed(fSettleTimer
, deadline
);
4932 if (pending
) release();
4936 //*********************************************************************************
4937 // [private] ackTimerTick
4939 // The acknowledgement timeout periodic timer has ticked.
4940 // If we are awaiting acks for a power change notification,
4941 // we decrement the timer word of each interested driver which hasn't acked.
4942 // If a timer word becomes zero, we pretend the driver aknowledged.
4943 // If we are waiting for the controlling driver to change the power
4944 // state of the hardware, we decrement its timer word, and if it becomes
4945 // zero, we pretend the driver acknowledged.
4947 // Returns true if the timer tick made it possible to advance to the next
4948 // machine state, false otherwise.
4949 //*********************************************************************************
4952 void IOService::ack_timer_ticked ( void )
4956 #endif /* !__LP64__ */
4958 bool IOService::ackTimerTick( void )
4960 IOPMinformee
* nextObject
;
4963 PM_ASSERT_IN_GATE();
4964 switch (fMachineState
) {
4965 case kIOPM_OurChangeWaitForPowerSettle
:
4966 case kIOPM_ParentChangeWaitForPowerSettle
:
4967 // are we waiting for controlling driver to acknowledge?
4968 if ( fDriverTimer
> 0 )
4970 // yes, decrement timer tick
4972 if ( fDriverTimer
== 0 )
4974 // controlling driver is tardy
4975 uint64_t nsec
= computeTimeDeltaNS(&fDriverCallStartTime
);
4976 OUR_PMLog(kPMLogCtrlDriverTardy
, 0, 0);
4977 setProperty(kIOPMTardyAckSPSKey
, kOSBooleanTrue
);
4978 PM_ERROR("%s::setPowerState(%p, %lu -> %lu) timed out after %d ms\n",
4979 fName
, this, fCurrentPowerState
, fHeadNotePowerState
, NS_TO_MS(nsec
));
4981 #if LOG_SETPOWER_TIMES
4982 PMEventDetails
*details
= PMEventDetails::eventDetails(
4983 kIOPMEventTypeSetPowerStateDelayed
, // type
4985 (uintptr_t)this, // owner unique
4986 NULL
, // interest name
4987 (uint8_t)getPowerState(), // old
4989 kIOReturnTimeout
, // result
4990 NS_TO_US(nsec
)); // usec completion time
4992 getPMRootDomain()->recordAndReleasePMEventGated( details
);
4995 if (gIOKitDebug
& kIOLogDebugPower
)
4997 panic("%s::setPowerState(%p, %lu -> %lu) timed out after %d ms",
4998 fName
, this, fCurrentPowerState
, fHeadNotePowerState
, NS_TO_MS(nsec
));
5002 // Unblock state machine and pretend driver has acked.
5006 // still waiting, set timer again
5012 case kIOPM_NotifyChildrenStart
:
5013 // are we waiting for interested parties to acknowledge?
5014 if ( fHeadNotePendingAcks
!= 0 )
5016 // yes, go through the list of interested drivers
5017 nextObject
= fInterestedDrivers
->firstInList();
5018 // and check each one
5019 while ( nextObject
!= NULL
)
5021 if ( nextObject
->timer
> 0 )
5023 nextObject
->timer
--;
5024 // this one should have acked by now
5025 if ( nextObject
->timer
== 0 )
5027 uint64_t nsec
= computeTimeDeltaNS(&nextObject
->startTime
);
5028 OUR_PMLog(kPMLogIntDriverTardy
, 0, 0);
5029 nextObject
->whatObject
->setProperty(kIOPMTardyAckPSCKey
, kOSBooleanTrue
);
5030 PM_ERROR("%s::powerState%sChangeTo(%p, %s, %lu -> %lu) timed out after %d ms\n",
5031 nextObject
->whatObject
->getName(),
5032 (fDriverCallReason
== kDriverCallInformPreChange
) ? "Will" : "Did",
5033 nextObject
->whatObject
, fName
, fCurrentPowerState
, fHeadNotePowerState
,
5036 #if LOG_SETPOWER_TIMES
5037 uint16_t logType
= (fDriverCallReason
== kDriverCallInformPreChange
)
5038 ? kIOPMEventTypePSWillChangeTo
5039 : kIOPMEventTypePSDidChangeTo
;
5041 PMEventDetails
*details
= PMEventDetails::eventDetails(
5044 (uintptr_t)this, // owner unique
5045 nextObject
->whatObject
->getName(), // interest name
5046 (uint8_t)fCurrentPowerState
, // old
5047 (uint8_t)fHeadNotePowerState
, // new
5048 kIOReturnTimeout
, // result
5049 NS_TO_US(nsec
)); // usec completion time
5051 getPMRootDomain()->recordAndReleasePMEventGated( details
);
5054 // Pretend driver has acked.
5055 fHeadNotePendingAcks
--;
5058 nextObject
= fInterestedDrivers
->nextInList(nextObject
);
5061 // is that the last?
5062 if ( fHeadNotePendingAcks
== 0 )
5064 // yes, we can continue
5067 // no, set timer again
5073 // TODO: aggreggate this
5074 case kIOPM_OurChangeTellClientsPowerDown
:
5075 case kIOPM_OurChangeTellPriorityClientsPowerDown
:
5076 case kIOPM_OurChangeNotifyInterestedDriversWillChange
:
5077 case kIOPM_ParentChangeTellPriorityClientsPowerDown
:
5078 case kIOPM_ParentChangeNotifyInterestedDriversWillChange
:
5079 case kIOPM_SyncTellClientsPowerDown
:
5080 case kIOPM_SyncTellPriorityClientsPowerDown
:
5081 case kIOPM_SyncNotifyWillChange
:
5082 case kIOPM_TellCapabilityChangeDone
:
5083 // apps didn't respond in time
5084 cleanClientResponses(true);
5085 OUR_PMLog(kPMLogClientTardy
, 0, 1);
5086 // tardy equates to approval
5091 PM_LOG1("%s: unexpected ack timer tick (state = %d)\n",
5092 getName(), fMachineState
);
5098 //*********************************************************************************
5099 // [private] start_ack_timer
5100 //*********************************************************************************
5102 void IOService::start_ack_timer ( void )
5104 start_ack_timer( ACK_TIMER_PERIOD
, kNanosecondScale
);
5107 void IOService::start_ack_timer ( UInt32 interval
, UInt32 scale
)
5109 AbsoluteTime deadline
;
5112 clock_interval_to_deadline(interval
, scale
, &deadline
);
5115 pending
= thread_call_enter_delayed(fAckTimer
, deadline
);
5116 if (pending
) release();
5119 //*********************************************************************************
5120 // [private] stop_ack_timer
5121 //*********************************************************************************
5123 void IOService::stop_ack_timer ( void )
5127 pending
= thread_call_cancel(fAckTimer
);
5128 if (pending
) release();
5131 //*********************************************************************************
5132 // [static] actionAckTimerExpired
5134 // Inside PM work loop's gate.
5135 //*********************************************************************************
5138 IOService::actionAckTimerExpired (
5140 void * arg0
, void * arg1
,
5141 void * arg2
, void * arg3
)
5143 IOService
* me
= (IOService
*) target
;
5146 // done will be true if the timer tick unblocks the machine state,
5147 // otherwise no need to signal the work loop.
5149 done
= me
->ackTimerTick();
5150 if (done
&& gIOPMWorkQueue
)
5151 gIOPMWorkQueue
->signalWorkAvailable();
5153 return kIOReturnSuccess
;
5156 //*********************************************************************************
5157 // ack_timer_expired
5159 // Thread call function. Holds a retain while the callout is in flight.
5160 //*********************************************************************************
5163 IOService::ack_timer_expired ( thread_call_param_t arg0
, thread_call_param_t arg1
)
5165 IOService
* me
= (IOService
*) arg0
;
5169 gIOPMWorkLoop
->runAction(&actionAckTimerExpired
, me
);
5175 // MARK: Client Messaging
5177 //*********************************************************************************
5178 // [private] tellSystemCapabilityChange
5179 //*********************************************************************************
5181 void IOService::tellSystemCapabilityChange( uint32_t nextMS
)
5184 fMachineState
= kIOPM_TellCapabilityChangeDone
;
5185 fOutOfBandMessage
= kIOMessageSystemCapabilityChange
;
5189 // Notify app first on pre-change.
5190 fOutOfBandParameter
= kNotifyCapabilityChangeApps
;
5194 // Notify kernel clients first on post-change.
5195 fOutOfBandParameter
= kNotifyCapabilityChangePriority
;
5198 tellClientsWithResponse( fOutOfBandMessage
);
5201 //*********************************************************************************
5202 // [public] askChangeDown
5204 // Ask registered applications and kernel clients if we can change to a lower
5207 // Subclass can override this to send a different message type. Parameter is
5208 // the destination state number.
5210 // Return true if we don't have to wait for acknowledgements
5211 //*********************************************************************************
5213 bool IOService::askChangeDown ( unsigned long stateNum
)
5215 return tellClientsWithResponse( kIOMessageCanDevicePowerOff
);
5218 //*********************************************************************************
5219 // [private] tellChangeDown1
5221 // Notify registered applications and kernel clients that we are definitely
5224 // Return true if we don't have to wait for acknowledgements
5225 //*********************************************************************************
5227 bool IOService::tellChangeDown1 ( unsigned long stateNum
)
5229 fOutOfBandParameter
= kNotifyApps
;
5230 return tellChangeDown(stateNum
);
5233 //*********************************************************************************
5234 // [private] tellChangeDown2
5236 // Notify priority clients that we are definitely dropping power.
5238 // Return true if we don't have to wait for acknowledgements
5239 //*********************************************************************************
5241 bool IOService::tellChangeDown2 ( unsigned long stateNum
)
5243 fOutOfBandParameter
= kNotifyPriority
;
5244 return tellChangeDown(stateNum
);
5247 //*********************************************************************************
5248 // [public] tellChangeDown
5250 // Notify registered applications and kernel clients that we are definitely
5253 // Subclass can override this to send a different message type. Parameter is
5254 // the destination state number.
5256 // Return true if we don't have to wait for acknowledgements
5257 //*********************************************************************************
5259 bool IOService::tellChangeDown ( unsigned long stateNum
)
5261 return tellClientsWithResponse( kIOMessageDeviceWillPowerOff
);
5264 //*********************************************************************************
5265 // cleanClientResponses
5267 //*********************************************************************************
5269 static void logAppTimeouts ( OSObject
* object
, void * arg
)
5271 IOPMInterestContext
* context
= (IOPMInterestContext
*) arg
;
5273 unsigned int clientIndex
;
5275 if (OSDynamicCast(_IOServiceInterestNotifier
, object
))
5277 // Discover the 'counter' value or index assigned to this client
5278 // when it was notified, by searching for the array index of the
5279 // client in an array holding the cached interested clients.
5281 clientIndex
= context
->notifyClients
->getNextIndexOfObject(object
, 0);
5283 if ((clientIndex
!= (unsigned int) -1) &&
5284 (flag
= context
->responseArray
->getObject(clientIndex
)) &&
5285 (flag
!= kOSBooleanTrue
))
5287 OSString
*logClientID
= NULL
;
5288 OSNumber
*clientID
= copyClientIDForNotification(object
, context
);
5291 logClientID
= IOCopyLogNameForPID(clientID
->unsigned32BitValue());
5292 clientID
->release();
5295 PM_ERROR(context
->errorLog
, logClientID
? logClientID
->getCStringNoCopy() : "");
5297 // TODO: record message type if possible
5298 IOService::getPMRootDomain()->pmStatsRecordApplicationResponse(
5299 gIOPMStatsApplicationResponseTimedOut
,
5300 logClientID
? logClientID
->getCStringNoCopy() : "",
5304 logClientID
->release();
5309 void IOService::cleanClientResponses ( bool logErrors
)
5311 if (logErrors
&& fResponseArray
)
5313 switch ( fOutOfBandParameter
) {
5315 case kNotifyCapabilityChangeApps
:
5316 if (fNotifyClientArray
)
5318 IOPMInterestContext context
;
5320 context
.responseArray
= fResponseArray
;
5321 context
.notifyClients
= fNotifyClientArray
;
5322 context
.serialNumber
= fSerialNumber
;
5323 context
.messageType
= kIOMessageCopyClientID
;
5324 context
.notifyType
= kNotifyApps
;
5325 context
.isPreChange
= fIsPreChange
;
5326 context
.enableTracing
= false;
5328 context
.maxTimeRequested
= 0;
5329 context
.stateNumber
= fHeadNotePowerState
;
5330 context
.stateFlags
= fHeadNotePowerArrayEntry
->capabilityFlags
;
5331 context
.changeFlags
= fHeadNoteChangeFlags
;
5332 context
.errorLog
= "PM notification timeout (%s)\n";
5334 applyToInterested(gIOAppPowerStateInterest
, logAppTimeouts
, (void *) &context
);
5339 // kNotifyPriority, kNotifyCapabilityChangePriority
5340 // TODO: identify the priority client that has not acked
5341 PM_ERROR("PM priority notification timeout\n");
5342 if (gIOKitDebug
& kIOLogDebugPower
)
5344 panic("PM priority notification timeout");
5352 fResponseArray
->release();
5353 fResponseArray
= NULL
;
5355 if (fNotifyClientArray
)
5357 fNotifyClientArray
->release();
5358 fNotifyClientArray
= NULL
;
5362 //*********************************************************************************
5363 // [protected] tellClientsWithResponse
5365 // Notify registered applications and kernel clients that we are definitely
5368 // Return true if we don't have to wait for acknowledgements
5369 //*********************************************************************************
5371 bool IOService::tellClientsWithResponse ( int messageType
)
5373 IOPMInterestContext context
;
5374 bool isRootDomain
= IS_ROOT_DOMAIN
;
5376 PM_ASSERT_IN_GATE();
5377 assert( fResponseArray
== NULL
);
5378 assert( fNotifyClientArray
== NULL
);
5380 RD_LOG("tellClientsWithResponse( %s, %d )\n",
5381 getIOMessageString(messageType
), fOutOfBandParameter
);
5383 fResponseArray
= OSArray::withCapacity( 1 );
5384 if (!fResponseArray
)
5387 fResponseArray
->setCapacityIncrement(8);
5388 if (++fSerialNumber
== 0)
5391 context
.responseArray
= fResponseArray
;
5392 context
.notifyClients
= 0;
5393 context
.serialNumber
= fSerialNumber
;
5394 context
.messageType
= messageType
;
5395 context
.notifyType
= fOutOfBandParameter
;
5396 context
.isPreChange
= fIsPreChange
;
5397 context
.enableTracing
= false;
5399 context
.maxTimeRequested
= 0;
5400 context
.stateNumber
= fHeadNotePowerState
;
5401 context
.stateFlags
= fHeadNotePowerArrayEntry
->capabilityFlags
;
5402 context
.changeFlags
= fHeadNoteChangeFlags
;
5403 context
.messageFilter
= (isRootDomain
) ?
5404 OSMemberFunctionCast(
5407 &IOPMrootDomain::systemMessageFilter
) : 0;
5409 switch ( fOutOfBandParameter
) {
5411 applyToInterested( gIOAppPowerStateInterest
,
5412 pmTellAppWithResponse
, (void *) &context
);
5415 (fMachineState
!= kIOPM_OurChangeTellClientsPowerDown
) &&
5416 (fMachineState
!= kIOPM_SyncTellClientsPowerDown
))
5418 // Notify capability app for tellChangeDown1()
5419 // but not for askChangeDown().
5420 context
.notifyType
= kNotifyCapabilityChangeApps
;
5421 context
.messageType
= kIOMessageSystemCapabilityChange
;
5422 applyToInterested( gIOAppPowerStateInterest
,
5423 pmTellCapabilityAppWithResponse
, (void *) &context
);
5424 context
.notifyType
= fOutOfBandParameter
;
5425 context
.messageType
= messageType
;
5427 context
.maxTimeRequested
= k30Seconds
;
5429 applyToInterested( gIOGeneralInterest
,
5430 pmTellClientWithResponse
, (void *) &context
);
5432 fNotifyClientArray
= context
.notifyClients
;
5435 case kNotifyPriority
:
5436 context
.enableTracing
= isRootDomain
;
5437 applyToInterested( gIOPriorityPowerStateInterest
,
5438 pmTellClientWithResponse
, (void *) &context
);
5442 // Notify capability clients for tellChangeDown2().
5443 context
.notifyType
= kNotifyCapabilityChangePriority
;
5444 context
.messageType
= kIOMessageSystemCapabilityChange
;
5445 applyToInterested( gIOPriorityPowerStateInterest
,
5446 pmTellCapabilityClientWithResponse
, (void *) &context
);
5450 case kNotifyCapabilityChangeApps
:
5451 applyToInterested( gIOAppPowerStateInterest
,
5452 pmTellCapabilityAppWithResponse
, (void *) &context
);
5453 fNotifyClientArray
= context
.notifyClients
;
5454 context
.maxTimeRequested
= k30Seconds
;
5457 case kNotifyCapabilityChangePriority
:
5458 applyToInterested( gIOPriorityPowerStateInterest
,
5459 pmTellCapabilityClientWithResponse
, (void *) &context
);
5463 // do we have to wait for somebody?
5464 if ( !checkForDone() )
5466 OUR_PMLog(kPMLogStartAckTimer
, context
.maxTimeRequested
, 0);
5467 if (context
.enableTracing
)
5468 getPMRootDomain()->traceDetail( context
.maxTimeRequested
/ 1000 );
5469 start_ack_timer( context
.maxTimeRequested
/ 1000, kMillisecondScale
);
5474 // everybody responded
5477 fResponseArray
->release();
5478 fResponseArray
= NULL
;
5480 if (fNotifyClientArray
)
5482 fNotifyClientArray
->release();
5483 fNotifyClientArray
= NULL
;
5489 //*********************************************************************************
5490 // [static private] pmTellAppWithResponse
5492 // We send a message to an application, and we expect a response, so we compute a
5493 // cookie we can identify the response with.
5494 //*********************************************************************************
5496 void IOService::pmTellAppWithResponse ( OSObject
* object
, void * arg
)
5498 IOPMInterestContext
* context
= (IOPMInterestContext
*) arg
;
5499 IOServicePM
* pwrMgt
= context
->us
->pwrMgt
;
5500 uint32_t msgIndex
, msgRef
, msgType
;
5501 OSNumber
*clientID
= NULL
;
5503 boolean_t proc_suspended
= FALSE
;
5504 #if LOG_APP_RESPONSE_TIMES
5508 if (!OSDynamicCast(_IOServiceInterestNotifier
, object
))
5511 if (context
->us
== getPMRootDomain())
5513 if ((clientID
= copyClientIDForNotification(object
, context
)))
5515 uint32_t clientPID
= clientID
->unsigned32BitValue();
5516 clientID
->release();
5517 proc
= proc_find(clientPID
);
5521 proc_suspended
= get_task_pidsuspended((task_t
) proc
->task
);
5526 logClientIDForNotification(object
, context
, "PMTellAppWithResponse - Suspended");
5533 if (context
->messageFilter
&&
5534 !context
->messageFilter(context
->us
, object
, context
, 0, 0))
5536 if (kIOLogDebugPower
& gIOKitDebug
)
5538 logClientIDForNotification(object
, context
, "DROP App");
5543 // Create client array (for tracking purposes) only if the service
5544 // has app clients. Usually only root domain does.
5545 if (0 == context
->notifyClients
)
5546 context
->notifyClients
= OSArray::withCapacity( 32 );
5548 msgType
= context
->messageType
;
5549 msgIndex
= context
->responseArray
->getCount();
5550 msgRef
= ((context
->serialNumber
& 0xFFFF) << 16) + (msgIndex
& 0xFFFF);
5552 OUR_PMLog(kPMLogAppNotify
, msgType
, msgRef
);
5553 if (kIOLogDebugPower
& gIOKitDebug
)
5555 logClientIDForNotification(object
, context
, "MESG App");
5558 #if LOG_APP_RESPONSE_TIMES
5560 clock_get_uptime(&now
);
5561 num
= OSNumber::withNumber(AbsoluteTime_to_scalar(&now
), sizeof(uint64_t) * 8);
5564 context
->responseArray
->setObject(msgIndex
, num
);
5569 context
->responseArray
->setObject(msgIndex
, kOSBooleanFalse
);
5571 if (context
->notifyClients
)
5572 context
->notifyClients
->setObject(msgIndex
, object
);
5574 context
->us
->messageClient(msgType
, object
, (void *) msgRef
);
5577 //*********************************************************************************
5578 // [static private] pmTellClientWithResponse
5580 // We send a message to an in-kernel client, and we expect a response,
5581 // so we compute a cookie we can identify the response with.
5582 //*********************************************************************************
5584 void IOService::pmTellClientWithResponse ( OSObject
* object
, void * arg
)
5586 IOPowerStateChangeNotification notify
;
5587 IOPMInterestContext
* context
= (IOPMInterestContext
*) arg
;
5588 OSObject
* replied
= kOSBooleanTrue
;
5589 _IOServiceInterestNotifier
* notifier
;
5590 uint32_t msgIndex
, msgRef
, msgType
;
5593 if (context
->messageFilter
&&
5594 !context
->messageFilter(context
->us
, object
, context
, 0, 0))
5596 if ((kIOLogDebugPower
& gIOKitDebug
) &&
5597 (OSDynamicCast(_IOServiceInterestNotifier
, object
)))
5599 _IOServiceInterestNotifier
*n
= (_IOServiceInterestNotifier
*) object
;
5600 PM_LOG("%s DROP Client %s, notifier %p, handler %p\n",
5601 context
->us
->getName(),
5602 getIOMessageString(context
->messageType
),
5603 object
, n
->handler
);
5608 notifier
= OSDynamicCast(_IOServiceInterestNotifier
, object
);
5609 msgType
= context
->messageType
;
5610 msgIndex
= context
->responseArray
->getCount();
5611 msgRef
= ((context
->serialNumber
& 0xFFFF) << 16) + (msgIndex
& 0xFFFF);
5613 IOServicePM
* pwrMgt
= context
->us
->pwrMgt
;
5614 if (gIOKitDebug
& kIOLogPower
) {
5615 OUR_PMLog(kPMLogClientNotify
, msgRef
, msgType
);
5616 if (OSDynamicCast(IOService
, object
)) {
5617 const char *who
= ((IOService
*) object
)->getName();
5618 gPlatform
->PMLog(who
, kPMLogClientNotify
, (uintptr_t) object
, 0);
5620 else if (notifier
) {
5621 OUR_PMLog(kPMLogClientNotify
, (uintptr_t) notifier
->handler
, 0);
5624 if ((kIOLogDebugPower
& gIOKitDebug
) && notifier
)
5626 PM_LOG("%s MESG Client %s, notifier %p, handler %p\n",
5627 context
->us
->getName(),
5628 getIOMessageString(msgType
),
5629 object
, notifier
->handler
);
5632 notify
.powerRef
= (void *)(uintptr_t) msgRef
;
5633 notify
.returnValue
= 0;
5634 notify
.stateNumber
= context
->stateNumber
;
5635 notify
.stateFlags
= context
->stateFlags
;
5637 if (context
->enableTracing
&& (notifier
!= 0))
5639 uint32_t detail
= ((msgIndex
& 0xff) << 24) |
5640 ((msgType
& 0xfff) << 12) |
5641 (((uintptr_t) notifier
->handler
) & 0xfff);
5642 getPMRootDomain()->traceDetail( detail
);
5645 retCode
= context
->us
->messageClient(msgType
, object
, (void *) ¬ify
, sizeof(notify
));
5647 if (kIOReturnSuccess
== retCode
)
5649 if (0 == notify
.returnValue
) {
5650 OUR_PMLog(kPMLogClientAcknowledge
, msgRef
, (uintptr_t) object
);
5652 replied
= kOSBooleanFalse
;
5653 if ( notify
.returnValue
> context
->maxTimeRequested
)
5655 if (notify
.returnValue
> kPriorityClientMaxWait
)
5657 context
->maxTimeRequested
= kPriorityClientMaxWait
;
5658 PM_ERROR("%s: client %p returned %llu for %s\n",
5659 context
->us
->getName(),
5660 notifier
? (void *) notifier
->handler
: object
,
5661 (uint64_t) notify
.returnValue
,
5662 getIOMessageString(msgType
));
5665 context
->maxTimeRequested
= notify
.returnValue
;
5669 // not a client of ours
5670 // so we won't be waiting for response
5671 OUR_PMLog(kPMLogClientAcknowledge
, msgRef
, 0);
5674 context
->responseArray
->setObject(msgIndex
, replied
);
5677 //*********************************************************************************
5678 // [static private] pmTellCapabilityAppWithResponse
5679 //*********************************************************************************
5681 void IOService::pmTellCapabilityAppWithResponse ( OSObject
* object
, void * arg
)
5683 IOPMSystemCapabilityChangeParameters msgArg
;
5684 IOPMInterestContext
* context
= (IOPMInterestContext
*) arg
;
5685 OSObject
* replied
= kOSBooleanTrue
;
5686 IOServicePM
* pwrMgt
= context
->us
->pwrMgt
;
5687 uint32_t msgIndex
, msgRef
, msgType
;
5688 #if LOG_APP_RESPONSE_TIMES
5692 if (!OSDynamicCast(_IOServiceInterestNotifier
, object
))
5695 memset(&msgArg
, 0, sizeof(msgArg
));
5696 if (context
->messageFilter
&&
5697 !context
->messageFilter(context
->us
, object
, context
, &msgArg
, &replied
))
5702 // Create client array (for tracking purposes) only if the service
5703 // has app clients. Usually only root domain does.
5704 if (0 == context
->notifyClients
)
5705 context
->notifyClients
= OSArray::withCapacity( 32 );
5707 msgType
= context
->messageType
;
5708 msgIndex
= context
->responseArray
->getCount();
5709 msgRef
= ((context
->serialNumber
& 0xFFFF) << 16) + (msgIndex
& 0xFFFF);
5711 OUR_PMLog(kPMLogAppNotify
, msgType
, msgRef
);
5712 if (kIOLogDebugPower
& gIOKitDebug
)
5714 // Log client pid/name and client array index.
5715 OSNumber
* clientID
= NULL
;
5716 OSString
* clientIDString
= NULL
;;
5717 context
->us
->messageClient(kIOMessageCopyClientID
, object
, &clientID
);
5719 clientIDString
= IOCopyLogNameForPID(clientID
->unsigned32BitValue());
5722 PM_LOG("%s MESG App(%u) %s, wait %u, %s\n",
5723 context
->us
->getName(),
5724 msgIndex
, getIOMessageString(msgType
),
5725 (replied
!= kOSBooleanTrue
),
5726 clientIDString
? clientIDString
->getCStringNoCopy() : "");
5727 if (clientID
) clientID
->release();
5728 if (clientIDString
) clientIDString
->release();
5731 msgArg
.notifyRef
= msgRef
;
5732 msgArg
.maxWaitForReply
= 0;
5734 if (replied
== kOSBooleanTrue
)
5736 msgArg
.notifyRef
= 0;
5737 context
->responseArray
->setObject(msgIndex
, kOSBooleanTrue
);
5738 if (context
->notifyClients
)
5739 context
->notifyClients
->setObject(msgIndex
, kOSBooleanTrue
);
5743 #if LOG_APP_RESPONSE_TIMES
5745 clock_get_uptime(&now
);
5746 num
= OSNumber::withNumber(AbsoluteTime_to_scalar(&now
), sizeof(uint64_t) * 8);
5749 context
->responseArray
->setObject(msgIndex
, num
);
5754 context
->responseArray
->setObject(msgIndex
, kOSBooleanFalse
);
5756 if (context
->notifyClients
)
5757 context
->notifyClients
->setObject(msgIndex
, object
);
5760 context
->us
->messageClient(msgType
, object
, (void *) &msgArg
, sizeof(msgArg
));
5763 //*********************************************************************************
5764 // [static private] pmTellCapabilityClientWithResponse
5765 //*********************************************************************************
5767 void IOService::pmTellCapabilityClientWithResponse(
5768 OSObject
* object
, void * arg
)
5770 IOPMSystemCapabilityChangeParameters msgArg
;
5771 IOPMInterestContext
* context
= (IOPMInterestContext
*) arg
;
5772 OSObject
* replied
= kOSBooleanTrue
;
5773 _IOServiceInterestNotifier
* notifier
;
5774 uint32_t msgIndex
, msgRef
, msgType
;
5777 memset(&msgArg
, 0, sizeof(msgArg
));
5778 if (context
->messageFilter
&&
5779 !context
->messageFilter(context
->us
, object
, context
, &msgArg
, 0))
5781 if ((kIOLogDebugPower
& gIOKitDebug
) &&
5782 (OSDynamicCast(_IOServiceInterestNotifier
, object
)))
5784 _IOServiceInterestNotifier
*n
= (_IOServiceInterestNotifier
*) object
;
5785 PM_LOG("%s DROP Client %s, notifier %p, handler %p\n",
5786 context
->us
->getName(),
5787 getIOMessageString(context
->messageType
),
5788 object
, n
->handler
);
5793 notifier
= OSDynamicCast(_IOServiceInterestNotifier
, object
);
5794 msgType
= context
->messageType
;
5795 msgIndex
= context
->responseArray
->getCount();
5796 msgRef
= ((context
->serialNumber
& 0xFFFF) << 16) + (msgIndex
& 0xFFFF);
5798 IOServicePM
* pwrMgt
= context
->us
->pwrMgt
;
5799 if (gIOKitDebug
& kIOLogPower
) {
5800 OUR_PMLog(kPMLogClientNotify
, msgRef
, msgType
);
5801 if (OSDynamicCast(IOService
, object
)) {
5802 const char *who
= ((IOService
*) object
)->getName();
5803 gPlatform
->PMLog(who
, kPMLogClientNotify
, (uintptr_t) object
, 0);
5805 else if (notifier
) {
5806 OUR_PMLog(kPMLogClientNotify
, (uintptr_t) notifier
->handler
, 0);
5809 if ((kIOLogDebugPower
& gIOKitDebug
) && notifier
)
5811 PM_LOG("%s MESG Client %s, notifier %p, handler %p\n",
5812 context
->us
->getName(),
5813 getIOMessageString(msgType
),
5814 object
, notifier
->handler
);
5817 msgArg
.notifyRef
= msgRef
;
5818 msgArg
.maxWaitForReply
= 0;
5820 if (context
->enableTracing
&& (notifier
!= 0))
5822 uint32_t detail
= ((msgIndex
& 0xff) << 24) |
5823 ((msgType
& 0xfff) << 12) |
5824 (((uintptr_t) notifier
->handler
) & 0xfff);
5825 getPMRootDomain()->traceDetail( detail
);
5828 retCode
= context
->us
->messageClient(
5829 msgType
, object
, (void *) &msgArg
, sizeof(msgArg
));
5831 if ( kIOReturnSuccess
== retCode
)
5833 if ( 0 == msgArg
.maxWaitForReply
)
5835 // client doesn't want time to respond
5836 OUR_PMLog(kPMLogClientAcknowledge
, msgRef
, (uintptr_t) object
);
5840 replied
= kOSBooleanFalse
;
5841 if ( msgArg
.maxWaitForReply
> context
->maxTimeRequested
)
5843 if (msgArg
.maxWaitForReply
> kCapabilityClientMaxWait
)
5845 context
->maxTimeRequested
= kCapabilityClientMaxWait
;
5846 PM_ERROR("%s: client %p returned %u for %s\n",
5847 context
->us
->getName(),
5848 notifier
? (void *) notifier
->handler
: object
,
5849 msgArg
.maxWaitForReply
,
5850 getIOMessageString(msgType
));
5853 context
->maxTimeRequested
= msgArg
.maxWaitForReply
;
5859 // not a client of ours
5860 // so we won't be waiting for response
5861 OUR_PMLog(kPMLogClientAcknowledge
, msgRef
, 0);
5864 context
->responseArray
->setObject(msgIndex
, replied
);
5867 //*********************************************************************************
5868 // [public] tellNoChangeDown
5870 // Notify registered applications and kernel clients that we are not
5873 // Subclass can override this to send a different message type. Parameter is
5874 // the aborted destination state number.
5875 //*********************************************************************************
5877 void IOService::tellNoChangeDown ( unsigned long )
5879 return tellClients( kIOMessageDeviceWillNotPowerOff
);
5882 //*********************************************************************************
5883 // [public] tellChangeUp
5885 // Notify registered applications and kernel clients that we are raising power.
5887 // Subclass can override this to send a different message type. Parameter is
5888 // the aborted destination state number.
5889 //*********************************************************************************
5891 void IOService::tellChangeUp ( unsigned long )
5893 return tellClients( kIOMessageDeviceHasPoweredOn
);
5896 //*********************************************************************************
5897 // [protected] tellClients
5899 // Notify registered applications and kernel clients of something.
5900 //*********************************************************************************
5902 void IOService::tellClients ( int messageType
)
5904 IOPMInterestContext context
;
5906 RD_LOG("tellClients( %s )\n", getIOMessageString(messageType
));
5908 memset(&context
, 0, sizeof(context
));
5909 context
.messageType
= messageType
;
5910 context
.isPreChange
= fIsPreChange
;
5912 context
.stateNumber
= fHeadNotePowerState
;
5913 context
.stateFlags
= fHeadNotePowerArrayEntry
->capabilityFlags
;
5914 context
.changeFlags
= fHeadNoteChangeFlags
;
5915 context
.messageFilter
= (IS_ROOT_DOMAIN
) ?
5916 OSMemberFunctionCast(
5919 &IOPMrootDomain::systemMessageFilter
) : 0;
5921 context
.notifyType
= kNotifyPriority
;
5922 applyToInterested( gIOPriorityPowerStateInterest
,
5923 tellKernelClientApplier
, (void *) &context
);
5925 context
.notifyType
= kNotifyApps
;
5926 applyToInterested( gIOAppPowerStateInterest
,
5927 tellAppClientApplier
, (void *) &context
);
5929 applyToInterested( gIOGeneralInterest
,
5930 tellKernelClientApplier
, (void *) &context
);
5933 //*********************************************************************************
5934 // [private] tellKernelClientApplier
5936 // Message a kernel client.
5937 //*********************************************************************************
5939 static void tellKernelClientApplier ( OSObject
* object
, void * arg
)
5941 IOPowerStateChangeNotification notify
;
5942 IOPMInterestContext
* context
= (IOPMInterestContext
*) arg
;
5944 if (context
->messageFilter
&&
5945 !context
->messageFilter(context
->us
, object
, context
, 0, 0))
5947 if ((kIOLogDebugPower
& gIOKitDebug
) &&
5948 (OSDynamicCast(_IOServiceInterestNotifier
, object
)))
5950 _IOServiceInterestNotifier
*n
= (_IOServiceInterestNotifier
*) object
;
5951 PM_LOG("%s DROP Client %s, notifier %p, handler %p\n",
5952 context
->us
->getName(),
5953 IOService::getIOMessageString(context
->messageType
),
5954 object
, n
->handler
);
5959 notify
.powerRef
= (void *) 0;
5960 notify
.returnValue
= 0;
5961 notify
.stateNumber
= context
->stateNumber
;
5962 notify
.stateFlags
= context
->stateFlags
;
5964 context
->us
->messageClient(context
->messageType
, object
, ¬ify
, sizeof(notify
));
5966 if ((kIOLogDebugPower
& gIOKitDebug
) &&
5967 (OSDynamicCast(_IOServiceInterestNotifier
, object
)))
5969 _IOServiceInterestNotifier
*n
= (_IOServiceInterestNotifier
*) object
;
5970 PM_LOG("%s MESG Client %s, notifier %p, handler %p\n",
5971 context
->us
->getName(),
5972 IOService::getIOMessageString(context
->messageType
),
5973 object
, n
->handler
);
5977 static OSNumber
* copyClientIDForNotification(
5979 IOPMInterestContext
*context
)
5981 OSNumber
*clientID
= NULL
;
5982 context
->us
->messageClient(kIOMessageCopyClientID
, object
, &clientID
);
5986 static void logClientIDForNotification(
5988 IOPMInterestContext
*context
,
5989 const char *logString
)
5991 OSString
*logClientID
= NULL
;
5992 OSNumber
*clientID
= copyClientIDForNotification(object
, context
);
5997 logClientID
= IOCopyLogNameForPID(clientID
->unsigned32BitValue());
5999 PM_LOG("%s %s %s, %s\n",
6000 context
->us
->getName(), logString
,
6001 IOService::getIOMessageString(context
->messageType
),
6002 logClientID
? logClientID
->getCStringNoCopy() : "");
6005 logClientID
->release();
6009 clientID
->release();
6015 static void tellAppClientApplier ( OSObject
* object
, void * arg
)
6017 IOPMInterestContext
* context
= (IOPMInterestContext
*) arg
;
6018 OSNumber
* clientID
= NULL
;
6020 boolean_t proc_suspended
= FALSE
;
6022 if (context
->us
== IOService::getPMRootDomain())
6024 if ((clientID
= copyClientIDForNotification(object
, context
)))
6026 uint32_t clientPID
= clientID
->unsigned32BitValue();
6027 clientID
->release();
6028 proc
= proc_find(clientPID
);
6032 proc_suspended
= get_task_pidsuspended((task_t
) proc
->task
);
6037 logClientIDForNotification(object
, context
, "tellAppClientApplier - Suspended");
6044 if (context
->messageFilter
&&
6045 !context
->messageFilter(context
->us
, object
, context
, 0, 0))
6047 if (kIOLogDebugPower
& gIOKitDebug
)
6049 logClientIDForNotification(object
, context
, "DROP App");
6054 if (kIOLogDebugPower
& gIOKitDebug
)
6056 logClientIDForNotification(object
, context
, "MESG App");
6059 context
->us
->messageClient(context
->messageType
, object
, 0);
6062 //*********************************************************************************
6063 // [private] checkForDone
6064 //*********************************************************************************
6066 bool IOService::checkForDone ( void )
6071 if (fResponseArray
== NULL
) {
6075 for (i
= 0; ; i
++) {
6076 theFlag
= fResponseArray
->getObject(i
);
6078 if (NULL
== theFlag
) {
6082 if (kOSBooleanTrue
!= theFlag
) {
6089 //*********************************************************************************
6090 // [public] responseValid
6091 //*********************************************************************************
6093 bool IOService::responseValid ( uint32_t refcon
, int pid
)
6095 UInt16 serialComponent
;
6096 UInt16 ordinalComponent
;
6099 serialComponent
= (refcon
>> 16) & 0xFFFF;
6100 ordinalComponent
= (refcon
& 0xFFFF);
6102 if ( serialComponent
!= fSerialNumber
)
6107 if ( fResponseArray
== NULL
)
6112 theFlag
= fResponseArray
->getObject(ordinalComponent
);
6120 if ((num
= OSDynamicCast(OSNumber
, theFlag
)))
6122 #if LOG_APP_RESPONSE_TIMES
6126 OSString
*name
= IOCopyLogNameForPID(pid
);
6128 clock_get_uptime(&now
);
6129 AbsoluteTime_to_scalar(&start
) = num
->unsigned64BitValue();
6130 SUB_ABSOLUTETIME(&now
, &start
);
6131 absolutetime_to_nanoseconds(now
, &nsec
);
6133 PMEventDetails
*details
= PMEventDetails::eventDetails(
6134 kIOPMEventTypeAppResponse
, // type
6135 name
? name
->getCStringNoCopy() : "", // who
6136 (uintptr_t)pid
, // owner unique
6137 NULL
, // interest name
6141 NS_TO_US(nsec
)); // usec completion time
6143 getPMRootDomain()->recordAndReleasePMEventGated( details
);
6145 if (kIOLogDebugPower
& gIOKitDebug
)
6147 PM_LOG("Ack(%u) %u ms\n",
6148 (uint32_t) ordinalComponent
,
6153 if (nsec
> LOG_APP_RESPONSE_TIMES
)
6155 PM_LOG("PM response took %d ms (%s)\n", NS_TO_MS(nsec
),
6156 name
? name
->getCStringNoCopy() : "");
6158 if (nsec
> LOG_APP_RESPONSE_MSG_TRACER
)
6160 // TODO: populate the messageType argument
6161 getPMRootDomain()->pmStatsRecordApplicationResponse(
6162 gIOPMStatsApplicationResponseSlow
,
6163 name
? name
->getCStringNoCopy() : "", 0,
6164 NS_TO_MS(nsec
), pid
);
6171 theFlag
= kOSBooleanFalse
;
6174 if ( kOSBooleanFalse
== theFlag
)
6176 fResponseArray
->replaceObject(ordinalComponent
, kOSBooleanTrue
);
6182 //*********************************************************************************
6183 // [public] allowPowerChange
6185 // Our power state is about to lower, and we have notified applications
6186 // and kernel clients, and one of them has acknowledged. If this is the last to do
6187 // so, and all acknowledgements are positive, we continue with the power change.
6188 //*********************************************************************************
6190 IOReturn
IOService::allowPowerChange ( unsigned long refcon
)
6192 IOPMRequest
* request
;
6197 return kIOReturnSuccess
;
6200 request
= acquirePMRequest( this, kIOPMRequestTypeAllowPowerChange
);
6202 return kIOReturnNoMemory
;
6204 request
->fArg0
= (void *) refcon
;
6205 request
->fArg1
= (void *) proc_selfpid();
6206 request
->fArg2
= (void *) 0;
6207 submitPMRequest( request
);
6209 return kIOReturnSuccess
;
6213 IOReturn
IOService::serializedAllowPowerChange2 ( unsigned long refcon
)
6215 // [deprecated] public
6216 return kIOReturnUnsupported
;
6218 #endif /* !__LP64__ */
6220 //*********************************************************************************
6221 // [public] cancelPowerChange
6223 // Our power state is about to lower, and we have notified applications
6224 // and kernel clients, and one of them has vetoed the change. If this is the last
6225 // client to respond, we abandon the power change.
6226 //*********************************************************************************
6228 IOReturn
IOService::cancelPowerChange ( unsigned long refcon
)
6230 IOPMRequest
* request
;
6236 return kIOReturnSuccess
;
6239 name
= IOCopyLogNameForPID(proc_selfpid());
6240 PM_ERROR("PM notification cancel (%s)\n", name
? name
->getCStringNoCopy() : "");
6242 request
= acquirePMRequest( this, kIOPMRequestTypeCancelPowerChange
);
6247 return kIOReturnNoMemory
;
6250 request
->fArg0
= (void *) refcon
;
6251 request
->fArg1
= (void *) proc_selfpid();
6252 request
->fArg2
= (void *) name
;
6253 submitPMRequest( request
);
6255 return kIOReturnSuccess
;
6259 IOReturn
IOService::serializedCancelPowerChange2 ( unsigned long refcon
)
6261 // [deprecated] public
6262 return kIOReturnUnsupported
;
6265 //*********************************************************************************
6266 // PM_Clamp_Timer_Expired
6268 // called when clamp timer expires...set power state to 0.
6269 //*********************************************************************************
6271 void IOService::PM_Clamp_Timer_Expired ( void )
6275 //*********************************************************************************
6278 // Set to highest available power state for a minimum of duration milliseconds
6279 //*********************************************************************************
6281 void IOService::clampPowerOn ( unsigned long duration
)
6284 #endif /* !__LP64__ */
6287 // MARK: Driver Overrides
6289 //*********************************************************************************
6290 // [public] setPowerState
6292 // Does nothing here. This should be implemented in a subclass driver.
6293 //*********************************************************************************
6295 IOReturn
IOService::setPowerState (
6296 unsigned long powerStateOrdinal
, IOService
* whatDevice
)
6301 //*********************************************************************************
6302 // [public] maxCapabilityForDomainState
6304 // Finds the highest power state in the array whose input power
6305 // requirement is equal to the input parameter. Where a more intelligent
6306 // decision is possible, override this in the subclassed driver.
6307 //*********************************************************************************
6309 unsigned long IOService::maxCapabilityForDomainState ( IOPMPowerFlags domainState
)
6313 if (fNumberOfPowerStates
== 0 )
6317 for ( i
= fNumberOfPowerStates
- 1; i
>= 0; i
-- )
6319 if ( (domainState
& fPowerStates
[i
].inputPowerFlags
) ==
6320 fPowerStates
[i
].inputPowerFlags
)
6328 //*********************************************************************************
6329 // [public] initialPowerStateForDomainState
6331 // Finds the highest power state in the array whose input power
6332 // requirement is equal to the input parameter. Where a more intelligent
6333 // decision is possible, override this in the subclassed driver.
6334 //*********************************************************************************
6336 unsigned long IOService::initialPowerStateForDomainState ( IOPMPowerFlags domainState
)
6340 if (fNumberOfPowerStates
== 0 )
6344 for ( i
= fNumberOfPowerStates
- 1; i
>= 0; i
-- )
6346 if ( (domainState
& fPowerStates
[i
].inputPowerFlags
) ==
6347 fPowerStates
[i
].inputPowerFlags
)
6355 //*********************************************************************************
6356 // [public] powerStateForDomainState
6358 // Finds the highest power state in the array whose input power
6359 // requirement is equal to the input parameter. Where a more intelligent
6360 // decision is possible, override this in the subclassed driver.
6361 //*********************************************************************************
6363 unsigned long IOService::powerStateForDomainState ( IOPMPowerFlags domainState
)
6367 if (fNumberOfPowerStates
== 0 )
6371 for ( i
= fNumberOfPowerStates
- 1; i
>= 0; i
-- )
6373 if ( (domainState
& fPowerStates
[i
].inputPowerFlags
) ==
6374 fPowerStates
[i
].inputPowerFlags
)
6383 //*********************************************************************************
6384 // [deprecated] didYouWakeSystem
6386 // Does nothing here. This should be implemented in a subclass driver.
6387 //*********************************************************************************
6389 bool IOService::didYouWakeSystem ( void )
6393 #endif /* !__LP64__ */
6395 //*********************************************************************************
6396 // [public] powerStateWillChangeTo
6398 // Does nothing here. This should be implemented in a subclass driver.
6399 //*********************************************************************************
6401 IOReturn
IOService::powerStateWillChangeTo ( IOPMPowerFlags
, unsigned long, IOService
* )
6403 return kIOPMAckImplied
;
6406 //*********************************************************************************
6407 // [public] powerStateDidChangeTo
6409 // Does nothing here. This should be implemented in a subclass driver.
6410 //*********************************************************************************
6412 IOReturn
IOService::powerStateDidChangeTo ( IOPMPowerFlags
, unsigned long, IOService
* )
6414 return kIOPMAckImplied
;
6417 //*********************************************************************************
6418 // [protected] powerChangeDone
6420 // Called from PM work loop thread.
6421 // Does nothing here. This should be implemented in a subclass policy-maker.
6422 //*********************************************************************************
6424 void IOService::powerChangeDone ( unsigned long )
6429 //*********************************************************************************
6430 // [deprecated] newTemperature
6432 // Does nothing here. This should be implemented in a subclass driver.
6433 //*********************************************************************************
6435 IOReturn
IOService::newTemperature ( long currentTemp
, IOService
* whichZone
)
6439 #endif /* !__LP64__ */
6441 //*********************************************************************************
6442 // [public] systemWillShutdown
6444 // System shutdown and restart notification.
6445 //*********************************************************************************
6447 void IOService::systemWillShutdown( IOOptionBits specifier
)
6449 IOPMrootDomain
* rootDomain
= IOService::getPMRootDomain();
6451 rootDomain
->acknowledgeSystemWillShutdown( this );
6455 // MARK: PM State Machine
6457 //*********************************************************************************
6458 // [private static] acquirePMRequest
6459 //*********************************************************************************
6462 IOService::acquirePMRequest( IOService
* target
, IOOptionBits requestType
,
6463 IOPMRequest
* active
)
6465 IOPMRequest
* request
;
6469 request
= IOPMRequest::create();
6472 request
->init( target
, requestType
);
6475 IOPMRequest
* root
= active
->getRootRequest();
6476 if (root
) request
->attachRootRequest(root
);
6481 PM_ERROR("%s: No memory for PM request type 0x%x\n",
6482 target
->getName(), (uint32_t) requestType
);
6487 //*********************************************************************************
6488 // [private static] releasePMRequest
6489 //*********************************************************************************
6491 void IOService::releasePMRequest( IOPMRequest
* request
)
6500 //*********************************************************************************
6501 // [private] submitPMRequest
6502 //*********************************************************************************
6504 void IOService::submitPMRequest( IOPMRequest
* request
)
6507 assert( gIOPMReplyQueue
);
6508 assert( gIOPMRequestQueue
);
6510 PM_LOG1("[+ %02lx] %p [%p %s] %p %p %p\n",
6511 (long)request
->getType(), request
,
6512 request
->getTarget(), request
->getTarget()->getName(),
6513 request
->fArg0
, request
->fArg1
, request
->fArg2
);
6515 if (request
->isReplyType())
6516 gIOPMReplyQueue
->queuePMRequest( request
);
6518 gIOPMRequestQueue
->queuePMRequest( request
);
6521 void IOService::submitPMRequest( IOPMRequest
** requests
, IOItemCount count
)
6524 assert( count
> 0 );
6525 assert( gIOPMRequestQueue
);
6527 for (IOItemCount i
= 0; i
< count
; i
++)
6529 IOPMRequest
* req
= requests
[i
];
6530 PM_LOG1("[+ %02lx] %p [%p %s] %p %p %p\n",
6531 (long)req
->getType(), req
,
6532 req
->getTarget(), req
->getTarget()->getName(),
6533 req
->fArg0
, req
->fArg1
, req
->fArg2
);
6536 gIOPMRequestQueue
->queuePMRequestChain( requests
, count
);
6539 //*********************************************************************************
6540 // [private] servicePMRequestQueue
6542 // Called from IOPMRequestQueue::checkForWork().
6543 //*********************************************************************************
6545 bool IOService::servicePMRequestQueue(
6546 IOPMRequest
* request
,
6547 IOPMRequestQueue
* queue
)
6553 // Work queue will immediately execute the queue'd request if possible.
6554 // If execution blocks, the work queue will wait for a producer signal.
6555 // Only need to signal more when completing attached requests.
6557 more
= gIOPMWorkQueue
->queuePMRequest(request
, pwrMgt
);
6561 // Calling PM without PMinit() is not allowed, fail the request.
6563 PM_LOG("%s: PM not initialized\n", getName());
6564 fAdjustPowerScheduled
= false;
6565 more
= gIOPMFreeQueue
->queuePMRequest(request
);
6566 if (more
) gIOPMWorkQueue
->incrementProducerCount();
6570 //*********************************************************************************
6571 // [private] servicePMFreeQueue
6573 // Called from IOPMCompletionQueue::checkForWork().
6574 //*********************************************************************************
6576 bool IOService::servicePMFreeQueue(
6577 IOPMRequest
* request
,
6578 IOPMCompletionQueue
* queue
)
6580 bool more
= request
->getNextRequest();
6581 IOPMRequest
* root
= request
->getRootRequest();
6583 if (root
&& (root
!= request
))
6586 gIOPMWorkQueue
->incrementProducerCount();
6588 releasePMRequest( request
);
6592 //*********************************************************************************
6593 // [private] retirePMRequest
6595 // Called by IOPMWorkQueue to retire a completed request.
6596 //*********************************************************************************
6598 bool IOService::retirePMRequest( IOPMRequest
* request
, IOPMWorkQueue
* queue
)
6600 assert(request
&& queue
);
6602 PM_LOG1("[- %02x] %p [%p %s] state %d, busy %d\n",
6603 request
->getType(), request
, this, getName(),
6604 fMachineState
, gIOPMBusyCount
);
6606 // Catch requests created by idleTimerExpired().
6608 if ((request
->getType() == kIOPMRequestTypeActivityTickle
) &&
6609 (request
->fArg1
== (void *) false))
6611 // Idle timer expiration - power drop request completed.
6612 // Restart the idle timer if deviceDesire can go lower, otherwise set
6613 // a flag so we know to restart idle timer when fDeviceDesire > 0.
6615 if (fDeviceDesire
> 0)
6617 fActivityTickleCount
= 0;
6618 clock_get_uptime(&fIdleTimerStartTime
);
6619 start_PM_idle_timer();
6621 else if (fHasAdvisoryDesire
)
6623 start_PM_idle_timer();
6627 fIdleTimerStopped
= true;
6631 // If the request is linked, then Work queue has already incremented its
6634 return (gIOPMFreeQueue
->queuePMRequest( request
));
6637 //*********************************************************************************
6638 // [private] isPMBlocked
6640 // Check if machine state transition is blocked.
6641 //*********************************************************************************
6643 bool IOService::isPMBlocked ( IOPMRequest
* request
, int count
)
6648 if (kIOPM_Finished
== fMachineState
)
6651 if (kIOPM_DriverThreadCallDone
== fMachineState
)
6653 // 5 = kDriverCallInformPreChange
6654 // 6 = kDriverCallInformPostChange
6655 // 7 = kDriverCallSetPowerState
6656 if (fDriverCallBusy
)
6657 reason
= 5 + fDriverCallReason
;
6661 // Waiting on driver's setPowerState() timeout.
6667 // Child or interested driver acks pending.
6668 if (fHeadNotePendingAcks
)
6673 // Waiting on apps or priority power interest clients.
6679 // Waiting on settle timer expiration.
6686 fWaitReason
= reason
;
6692 PM_LOG1("[B %02x] %p [%p %s] state %d, reason %d\n",
6693 request
->getType(), request
, this, getName(),
6694 fMachineState
, reason
);
6703 //*********************************************************************************
6704 // [private] servicePMRequest
6706 // Service a request from our work queue.
6707 //*********************************************************************************
6709 bool IOService::servicePMRequest( IOPMRequest
* request
, IOPMWorkQueue
* queue
)
6714 assert(request
&& queue
);
6716 while (isPMBlocked(request
, loop
++) == false)
6718 PM_LOG1("[W %02x] %p [%p %s] state %d\n",
6719 request
->getType(), request
, this, getName(), fMachineState
);
6721 gIOPMRequest
= request
;
6724 // Every PM machine states must be handled in one of the cases below.
6726 switch ( fMachineState
)
6728 case kIOPM_Finished
:
6729 executePMRequest( request
);
6732 case kIOPM_OurChangeTellClientsPowerDown
:
6733 // Root domain might self cancel due to assertions.
6736 bool cancel
= (bool) fDoNotPowerDown
;
6737 getPMRootDomain()->askChangeDownDone(
6738 &fHeadNoteChangeFlags
, &cancel
);
6739 fDoNotPowerDown
= cancel
;
6742 // askChangeDown() done, was it vetoed?
6743 if (!fDoNotPowerDown
)
6745 if (IS_ROOT_DOMAIN
) {
6746 PMEventDetails
*details
= PMEventDetails::eventDetails(
6747 kIOPMEventTypeAppNotificationsFinished
,
6752 getPMRootDomain()->recordAndReleasePMEventGated( details
);
6755 // no, we can continue
6756 OurChangeTellClientsPowerDown();
6760 if (IS_ROOT_DOMAIN
) {
6761 PMEventDetails
*details
= PMEventDetails::eventDetails(
6762 kIOPMEventTypeSleepDone
,
6764 1, /* reason: 1 == Ask clients succeeded */
6765 kIOReturnAborted
); /* result */
6767 getPMRootDomain()->recordAndReleasePMEventGated( details
);
6770 OUR_PMLog(kPMLogIdleCancel
, (uintptr_t) this, fMachineState
);
6771 PM_ERROR("%s: idle cancel\n", fName
);
6772 // yes, rescind the warning
6773 tellNoChangeDown(fHeadNotePowerState
);
6774 // mark the change note un-actioned
6775 fHeadNoteChangeFlags
|= kIOPMNotDone
;
6781 case kIOPM_OurChangeTellPriorityClientsPowerDown
:
6782 // tellChangeDown(kNotifyApps) done, was it cancelled?
6783 if (fDoNotPowerDown
)
6785 if (IS_ROOT_DOMAIN
) {
6786 PMEventDetails
*details
= PMEventDetails::eventDetails(
6787 kIOPMEventTypeSleepDone
,
6789 2, /* reason: 2 == Client cancelled wake */
6790 kIOReturnAborted
); /* result */
6792 getPMRootDomain()->recordAndReleasePMEventGated( details
);
6794 OUR_PMLog(kPMLogIdleCancel
, (uintptr_t) this, fMachineState
);
6795 PM_ERROR("%s: idle revert\n", fName
);
6796 // no, tell clients we're back in the old state
6797 tellChangeUp(fCurrentPowerState
);
6798 // mark the change note un-actioned
6799 fHeadNoteChangeFlags
|= kIOPMNotDone
;
6805 if (IS_ROOT_DOMAIN
) {
6806 PMEventDetails
*details
= PMEventDetails::eventDetails(
6807 kIOPMEventTypeAppNotificationsFinished
,
6809 2, /* reason: 2 == TellPriorityClientsDone */
6810 kIOReturnSuccess
); /* result */
6812 getPMRootDomain()->recordAndReleasePMEventGated( details
);
6814 // yes, we can continue
6815 OurChangeTellPriorityClientsPowerDown();
6819 case kIOPM_OurChangeNotifyInterestedDriversWillChange
:
6820 OurChangeNotifyInterestedDriversWillChange();
6823 case kIOPM_OurChangeSetPowerState
:
6824 OurChangeSetPowerState();
6827 case kIOPM_OurChangeWaitForPowerSettle
:
6828 OurChangeWaitForPowerSettle();
6831 case kIOPM_OurChangeNotifyInterestedDriversDidChange
:
6832 OurChangeNotifyInterestedDriversDidChange();
6835 case kIOPM_OurChangeTellCapabilityDidChange
:
6836 OurChangeTellCapabilityDidChange();
6839 case kIOPM_OurChangeFinish
:
6843 case kIOPM_ParentChangeTellPriorityClientsPowerDown
:
6844 ParentChangeTellPriorityClientsPowerDown();
6847 case kIOPM_ParentChangeNotifyInterestedDriversWillChange
:
6848 ParentChangeNotifyInterestedDriversWillChange();
6851 case kIOPM_ParentChangeSetPowerState
:
6852 ParentChangeSetPowerState();
6855 case kIOPM_ParentChangeWaitForPowerSettle
:
6856 ParentChangeWaitForPowerSettle();
6859 case kIOPM_ParentChangeNotifyInterestedDriversDidChange
:
6860 ParentChangeNotifyInterestedDriversDidChange();
6863 case kIOPM_ParentChangeTellCapabilityDidChange
:
6864 ParentChangeTellCapabilityDidChange();
6867 case kIOPM_ParentChangeAcknowledgePowerChange
:
6868 ParentChangeAcknowledgePowerChange();
6871 case kIOPM_DriverThreadCallDone
:
6872 if (fDriverCallReason
== kDriverCallSetPowerState
)
6873 notifyControllingDriverDone();
6875 notifyInterestedDriversDone();
6878 case kIOPM_NotifyChildrenOrdered
:
6879 notifyChildrenOrdered();
6882 case kIOPM_NotifyChildrenDelayed
:
6883 notifyChildrenDelayed();
6886 case kIOPM_NotifyChildrenStart
:
6887 PM_LOG2("%s: kIOPM_NotifyChildrenStart done\n", getName());
6888 MS_POP(); // from notifyInterestedDriversDone()
6892 case kIOPM_SyncTellClientsPowerDown
:
6893 // Root domain might self cancel due to assertions.
6896 bool cancel
= (bool) fDoNotPowerDown
;
6897 getPMRootDomain()->askChangeDownDone(
6898 &fHeadNoteChangeFlags
, &cancel
);
6899 fDoNotPowerDown
= cancel
;
6901 if (!fDoNotPowerDown
)
6903 fMachineState
= kIOPM_SyncTellPriorityClientsPowerDown
;
6904 fOutOfBandParameter
= kNotifyApps
;
6905 tellChangeDown(fHeadNotePowerState
);
6909 OUR_PMLog(kPMLogIdleCancel
, (uintptr_t) this, fMachineState
);
6910 PM_ERROR("%s: idle cancel\n", fName
);
6911 tellNoChangeDown(fHeadNotePowerState
);
6912 fHeadNoteChangeFlags
|= kIOPMNotDone
;
6917 case kIOPM_SyncTellPriorityClientsPowerDown
:
6918 if (!fDoNotPowerDown
)
6920 fMachineState
= kIOPM_SyncNotifyWillChange
;
6921 fOutOfBandParameter
= kNotifyPriority
;
6922 tellChangeDown(fHeadNotePowerState
);
6926 OUR_PMLog(kPMLogIdleCancel
, (uintptr_t) this, fMachineState
);
6927 PM_ERROR("%s: idle revert\n", fName
);
6928 tellChangeUp(fCurrentPowerState
);
6929 fHeadNoteChangeFlags
|= kIOPMNotDone
;
6934 case kIOPM_SyncNotifyWillChange
:
6935 if (kIOPMSyncNoChildNotify
& fHeadNoteChangeFlags
)
6937 fMachineState
= kIOPM_SyncFinish
;
6940 fMachineState
= kIOPM_SyncNotifyDidChange
;
6941 fDriverCallReason
= kDriverCallInformPreChange
;
6945 case kIOPM_SyncNotifyDidChange
:
6946 fIsPreChange
= false;
6948 if (fHeadNoteChangeFlags
& kIOPMParentInitiated
)
6949 fMachineState
= kIOPM_SyncFinish
;
6951 fMachineState
= kIOPM_SyncTellCapabilityDidChange
;
6953 fDriverCallReason
= kDriverCallInformPostChange
;
6957 case kIOPM_SyncTellCapabilityDidChange
:
6958 tellSystemCapabilityChange( kIOPM_SyncFinish
);
6961 case kIOPM_SyncFinish
:
6962 if (fHeadNoteChangeFlags
& kIOPMParentInitiated
)
6963 ParentChangeAcknowledgePowerChange();
6968 case kIOPM_TellCapabilityChangeDone
:
6971 if (fOutOfBandParameter
== kNotifyCapabilityChangePriority
)
6973 MS_POP(); // tellSystemCapabilityChange()
6976 fOutOfBandParameter
= kNotifyCapabilityChangePriority
;
6980 if (fOutOfBandParameter
== kNotifyCapabilityChangeApps
)
6982 MS_POP(); // tellSystemCapabilityChange()
6985 fOutOfBandParameter
= kNotifyCapabilityChangeApps
;
6987 tellClientsWithResponse( fOutOfBandMessage
);
6991 panic("servicePMWorkQueue: unknown machine state %x",
6997 if (fMachineState
== kIOPM_Finished
)
7007 //*********************************************************************************
7008 // [private] executePMRequest
7009 //*********************************************************************************
7011 void IOService::executePMRequest( IOPMRequest
* request
)
7013 assert( kIOPM_Finished
== fMachineState
);
7015 switch (request
->getType())
7017 case kIOPMRequestTypePMStop
:
7018 handlePMstop( request
);
7021 case kIOPMRequestTypeAddPowerChild1
:
7022 addPowerChild1( request
);
7025 case kIOPMRequestTypeAddPowerChild2
:
7026 addPowerChild2( request
);
7029 case kIOPMRequestTypeAddPowerChild3
:
7030 addPowerChild3( request
);
7033 case kIOPMRequestTypeRegisterPowerDriver
:
7034 handleRegisterPowerDriver( request
);
7037 case kIOPMRequestTypeAdjustPowerState
:
7038 fAdjustPowerScheduled
= false;
7042 case kIOPMRequestTypePowerDomainWillChange
:
7043 handlePowerDomainWillChangeTo( request
);
7046 case kIOPMRequestTypePowerDomainDidChange
:
7047 handlePowerDomainDidChangeTo( request
);
7050 case kIOPMRequestTypeRequestPowerState
:
7051 case kIOPMRequestTypeRequestPowerStateOverride
:
7052 handleRequestPowerState( request
);
7055 case kIOPMRequestTypePowerOverrideOnPriv
:
7056 case kIOPMRequestTypePowerOverrideOffPriv
:
7057 handlePowerOverrideChanged( request
);
7060 case kIOPMRequestTypeActivityTickle
:
7061 handleActivityTickle( request
);
7064 case kIOPMRequestTypeSynchronizePowerTree
:
7065 handleSynchronizePowerTree( request
);
7068 case kIOPMRequestTypeSetIdleTimerPeriod
:
7070 fIdleTimerPeriod
= (uintptr_t) request
->fArg0
;
7072 if ((false == fLockedFlags
.PMStop
) && (fIdleTimerPeriod
> 0))
7074 fActivityTickleCount
= 0;
7075 clock_get_uptime(&fIdleTimerStartTime
);
7076 start_PM_idle_timer();
7081 case kIOPMRequestTypeIgnoreIdleTimer
:
7082 fIdleTimerIgnored
= request
->fArg0
? 1 : 0;
7086 panic("executePMRequest: unknown request type %x", request
->getType());
7090 //*********************************************************************************
7091 // [private] servicePMReplyQueue
7092 //*********************************************************************************
7094 bool IOService::servicePMReplyQueue( IOPMRequest
* request
, IOPMRequestQueue
* queue
)
7098 assert( request
&& queue
);
7099 assert( request
->isReplyType() );
7101 PM_LOG1("[A %02x] %p [%p %s] state %d\n",
7102 request
->getType(), request
, this, getName(), fMachineState
);
7104 switch ( request
->getType() )
7106 case kIOPMRequestTypeAllowPowerChange
:
7107 case kIOPMRequestTypeCancelPowerChange
:
7108 // Check if we are expecting this response.
7109 if (responseValid((uint32_t)(uintptr_t) request
->fArg0
,
7110 (int)(uintptr_t) request
->fArg1
))
7112 if (kIOPMRequestTypeCancelPowerChange
== request
->getType())
7114 // Clients are not allowed to cancel when kIOPMSkipAskPowerDown
7115 // flag is set. Only root domain will set this flag.
7117 if ((fHeadNoteChangeFlags
& kIOPMSkipAskPowerDown
) == 0)
7119 fDoNotPowerDown
= true;
7121 OSString
* name
= (OSString
*) request
->fArg2
;
7122 getPMRootDomain()->pmStatsRecordApplicationResponse(
7123 gIOPMStatsApplicationResponseCancel
,
7124 name
? name
->getCStringNoCopy() : "", 0,
7125 0, (int)(uintptr_t) request
->fArg1
);
7132 cleanClientResponses(false);
7136 // OSString containing app name in Arg2 must be released.
7137 if (request
->getType() == kIOPMRequestTypeCancelPowerChange
)
7139 OSObject
* obj
= (OSObject
*) request
->fArg2
;
7140 if (obj
) obj
->release();
7144 case kIOPMRequestTypeAckPowerChange
:
7145 more
= handleAcknowledgePowerChange( request
);
7148 case kIOPMRequestTypeAckSetPowerState
:
7149 if (fDriverTimer
== -1)
7151 // driver acked while setPowerState() call is in-flight.
7152 // take this ack, return value from setPowerState() is irrelevant.
7153 OUR_PMLog(kPMLogDriverAcknowledgeSet
,
7154 (uintptr_t) this, fDriverTimer
);
7157 else if (fDriverTimer
> 0)
7159 // expected ack, stop the timer
7162 #if LOG_SETPOWER_TIMES
7163 uint64_t nsec
= computeTimeDeltaNS(&fDriverCallStartTime
);
7164 if (nsec
> LOG_SETPOWER_TIMES
)
7165 PM_LOG("%s::setPowerState(%p, %lu -> %lu) async took %d ms\n",
7166 fName
, this, fCurrentPowerState
, fHeadNotePowerState
, NS_TO_MS(nsec
));
7168 PMEventDetails
*details
= PMEventDetails::eventDetails(
7169 kIOPMEventTypeSetPowerStateDelayed
, // type
7171 (uintptr_t)this, // owner unique
7172 NULL
, // interest name
7173 (uint8_t)getPowerState(), // old
7174 (uint8_t)fHeadNotePowerState
, // new
7176 NS_TO_US(nsec
)); // usec completion time
7178 getPMRootDomain()->recordAndReleasePMEventGated( details
);
7180 OUR_PMLog(kPMLogDriverAcknowledgeSet
, (uintptr_t) this, fDriverTimer
);
7187 OUR_PMLog(kPMLogAcknowledgeErr4
, (uintptr_t) this, 0);
7191 case kIOPMRequestTypeInterestChanged
:
7192 handleInterestChanged( request
);
7196 case kIOPMRequestTypeIdleCancel
:
7197 if ((fMachineState
== kIOPM_OurChangeTellClientsPowerDown
)
7198 || (fMachineState
== kIOPM_OurChangeTellPriorityClientsPowerDown
)
7199 || (fMachineState
== kIOPM_SyncTellClientsPowerDown
)
7200 || (fMachineState
== kIOPM_SyncTellPriorityClientsPowerDown
))
7202 OUR_PMLog(kPMLogIdleCancel
, (uintptr_t) this, fMachineState
);
7203 PM_LOG2("%s: cancel from machine state %d\n",
7204 getName(), fMachineState
);
7205 fDoNotPowerDown
= true;
7206 // Stop waiting for app replys.
7207 if ((fMachineState
== kIOPM_OurChangeTellPriorityClientsPowerDown
) ||
7208 (fMachineState
== kIOPM_SyncTellPriorityClientsPowerDown
))
7209 cleanClientResponses(false);
7214 case kIOPMRequestTypeChildNotifyDelayCancel
:
7215 if (fMachineState
== kIOPM_NotifyChildrenDelayed
)
7217 PM_LOG2("%s: delay notify cancelled\n", getName());
7218 notifyChildrenDelayed();
7223 panic("servicePMReplyQueue: unknown reply type %x",
7224 request
->getType());
7227 more
|= gIOPMFreeQueue
->queuePMRequest(request
);
7229 gIOPMWorkQueue
->incrementProducerCount();
7234 //*********************************************************************************
7235 // [private] assertPMDriverCall / deassertPMDriverCall
7236 //*********************************************************************************
7238 bool IOService::assertPMDriverCall(
7239 IOPMDriverCallEntry
* entry
,
7240 IOOptionBits options
,
7241 IOPMinformee
* inform
)
7243 IOService
* target
= 0;
7251 if (fLockedFlags
.PMStop
)
7256 if (((options
& kIOPMADC_NoInactiveCheck
) == 0) && isInactive())
7263 if (!inform
->active
)
7267 target
= inform
->whatObject
;
7268 if (target
->isInactive())
7274 entry
->thread
= current_thread();
7275 entry
->target
= target
;
7276 queue_enter(&fPMDriverCallQueue
, entry
, IOPMDriverCallEntry
*, link
);
7285 void IOService::deassertPMDriverCall( IOPMDriverCallEntry
* entry
)
7287 bool wakeup
= false;
7291 assert( !queue_empty(&fPMDriverCallQueue
) );
7292 queue_remove(&fPMDriverCallQueue
, entry
, IOPMDriverCallEntry
*, link
);
7293 if (fLockedFlags
.PMDriverCallWait
)
7301 PM_LOCK_WAKEUP(&fPMDriverCallQueue
);
7304 void IOService::waitForPMDriverCall( IOService
* target
)
7306 const IOPMDriverCallEntry
* entry
;
7307 thread_t thread
= current_thread();
7308 AbsoluteTime deadline
;
7315 queue_iterate(&fPMDriverCallQueue
, entry
, const IOPMDriverCallEntry
*, link
)
7317 // Target of interested driver call
7318 if (target
&& (target
!= entry
->target
))
7321 if (entry
->thread
== thread
)
7325 PM_LOG("%s: %s(%s) on PM thread\n",
7326 fName
, __FUNCTION__
, target
? target
->getName() : "");
7327 OSReportWithBacktrace("%s: %s(%s) on PM thread\n",
7328 fName
, __FUNCTION__
, target
? target
->getName() : "");
7340 fLockedFlags
.PMDriverCallWait
= true;
7341 clock_interval_to_deadline(15, kSecondScale
, &deadline
);
7342 waitResult
= PM_LOCK_SLEEP(&fPMDriverCallQueue
, deadline
);
7343 fLockedFlags
.PMDriverCallWait
= false;
7344 if (THREAD_TIMED_OUT
== waitResult
)
7346 PM_ERROR("%s: waitForPMDriverCall timeout\n", fName
);
7353 //*********************************************************************************
7354 // [private] Debug helpers
7355 //*********************************************************************************
7357 const char * IOService::getIOMessageString( uint32_t msg
)
7359 #define MSG_ENTRY(x) {x, #x}
7361 static const IONamedValue msgNames
[] = {
7362 MSG_ENTRY( kIOMessageCanDevicePowerOff
),
7363 MSG_ENTRY( kIOMessageDeviceWillPowerOff
),
7364 MSG_ENTRY( kIOMessageDeviceWillNotPowerOff
),
7365 MSG_ENTRY( kIOMessageDeviceHasPoweredOn
),
7366 MSG_ENTRY( kIOMessageCanSystemPowerOff
),
7367 MSG_ENTRY( kIOMessageSystemWillPowerOff
),
7368 MSG_ENTRY( kIOMessageSystemWillNotPowerOff
),
7369 MSG_ENTRY( kIOMessageCanSystemSleep
),
7370 MSG_ENTRY( kIOMessageSystemWillSleep
),
7371 MSG_ENTRY( kIOMessageSystemWillNotSleep
),
7372 MSG_ENTRY( kIOMessageSystemHasPoweredOn
),
7373 MSG_ENTRY( kIOMessageSystemWillRestart
),
7374 MSG_ENTRY( kIOMessageSystemWillPowerOn
),
7375 MSG_ENTRY( kIOMessageSystemCapabilityChange
)
7378 return IOFindNameForValue(msg
, msgNames
);
7382 // MARK: IOPMRequest
7384 //*********************************************************************************
7385 // IOPMRequest Class
7387 // Requests from PM clients, and also used for inter-object messaging within PM.
7388 //*********************************************************************************
7390 OSDefineMetaClassAndStructors( IOPMRequest
, IOCommand
);
7392 IOPMRequest
* IOPMRequest::create( void )
7394 IOPMRequest
* me
= OSTypeAlloc(IOPMRequest
);
7395 if (me
&& !me
->init(0, kIOPMRequestTypeInvalid
))
7403 bool IOPMRequest::init( IOService
* target
, IOOptionBits type
)
7405 if (!IOCommand::init())
7410 fCompletionStatus
= kIOReturnSuccess
;
7418 void IOPMRequest::reset( void )
7420 assert( fWorkWaitCount
== 0 );
7421 assert( fFreeWaitCount
== 0 );
7423 detachNextRequest();
7424 detachRootRequest();
7426 fType
= kIOPMRequestTypeInvalid
;
7428 if (fCompletionAction
)
7430 fCompletionAction(fCompletionTarget
, fCompletionParam
, fCompletionStatus
);
7440 bool IOPMRequest::attachNextRequest( IOPMRequest
* next
)
7446 // Postpone the execution of the next request after
7448 fRequestNext
= next
;
7449 fRequestNext
->fWorkWaitCount
++;
7450 #if LOG_REQUEST_ATTACH
7451 kprintf("Attached next: %p [0x%x] -> %p [0x%x, %u] %s\n",
7452 this, (uint32_t) fType
, fRequestNext
,
7453 (uint32_t) fRequestNext
->fType
,
7454 (uint32_t) fRequestNext
->fWorkWaitCount
,
7455 fTarget
->getName());
7462 bool IOPMRequest::detachNextRequest( void )
7468 assert(fRequestNext
->fWorkWaitCount
);
7469 if (fRequestNext
->fWorkWaitCount
)
7470 fRequestNext
->fWorkWaitCount
--;
7471 #if LOG_REQUEST_ATTACH
7472 kprintf("Detached next: %p [0x%x] -> %p [0x%x, %u] %s\n",
7473 this, (uint32_t) fType
, fRequestNext
,
7474 (uint32_t) fRequestNext
->fType
,
7475 (uint32_t) fRequestNext
->fWorkWaitCount
,
7476 fTarget
->getName());
7484 bool IOPMRequest::attachRootRequest( IOPMRequest
* root
)
7490 // Delay the completion of the root request after
7492 fRequestRoot
= root
;
7493 fRequestRoot
->fFreeWaitCount
++;
7494 #if LOG_REQUEST_ATTACH
7495 kprintf("Attached root: %p [0x%x] -> %p [0x%x, %u] %s\n",
7496 this, (uint32_t) fType
, fRequestRoot
,
7497 (uint32_t) fRequestRoot
->fType
,
7498 (uint32_t) fRequestRoot
->fFreeWaitCount
,
7499 fTarget
->getName());
7506 bool IOPMRequest::detachRootRequest( void )
7512 assert(fRequestRoot
->fFreeWaitCount
);
7513 if (fRequestRoot
->fFreeWaitCount
)
7514 fRequestRoot
->fFreeWaitCount
--;
7515 #if LOG_REQUEST_ATTACH
7516 kprintf("Detached root: %p [0x%x] -> %p [0x%x, %u] %s\n",
7517 this, (uint32_t) fType
, fRequestRoot
,
7518 (uint32_t) fRequestRoot
->fType
,
7519 (uint32_t) fRequestRoot
->fFreeWaitCount
,
7520 fTarget
->getName());
7529 // MARK: IOPMRequestQueue
7531 //*********************************************************************************
7532 // IOPMRequestQueue Class
7534 // Global queues. Queues are created once and never released.
7535 //*********************************************************************************
7537 OSDefineMetaClassAndStructors( IOPMRequestQueue
, IOEventSource
);
7539 IOPMRequestQueue
* IOPMRequestQueue::create( IOService
* inOwner
, Action inAction
)
7541 IOPMRequestQueue
* me
= OSTypeAlloc(IOPMRequestQueue
);
7542 if (me
&& !me
->init(inOwner
, inAction
))
7550 bool IOPMRequestQueue::init( IOService
* inOwner
, Action inAction
)
7552 if (!inAction
|| !IOEventSource::init(inOwner
, (IOEventSourceAction
)inAction
))
7555 queue_init(&fQueue
);
7556 fLock
= IOLockAlloc();
7557 return (fLock
!= 0);
7560 void IOPMRequestQueue::free( void )
7567 return IOEventSource::free();
7570 void IOPMRequestQueue::queuePMRequest( IOPMRequest
* request
)
7574 queue_enter(&fQueue
, request
, IOPMRequest
*, fCommandChain
);
7575 IOLockUnlock(fLock
);
7576 if (workLoop
) signalWorkAvailable();
7580 IOPMRequestQueue::queuePMRequestChain( IOPMRequest
** requests
, IOItemCount count
)
7584 assert(requests
&& count
);
7590 queue_enter(&fQueue
, next
, IOPMRequest
*, fCommandChain
);
7592 IOLockUnlock(fLock
);
7593 if (workLoop
) signalWorkAvailable();
7596 bool IOPMRequestQueue::checkForWork( void )
7598 Action dqAction
= (Action
) action
;
7599 IOPMRequest
* request
;
7603 IOLockLock( fLock
);
7605 while (!queue_empty(&fQueue
))
7607 queue_remove_first( &fQueue
, request
, IOPMRequest
*, fCommandChain
);
7608 IOLockUnlock( fLock
);
7609 target
= request
->getTarget();
7611 more
|= (*dqAction
)( target
, request
, this );
7612 IOLockLock( fLock
);
7615 IOLockUnlock( fLock
);
7620 // MARK: IOPMWorkQueue
7622 //*********************************************************************************
7623 // IOPMWorkQueue Class
7625 // Queue of IOServicePM objects with busy IOPMRequest(s).
7626 //*********************************************************************************
7628 OSDefineMetaClassAndStructors( IOPMWorkQueue
, IOEventSource
);
7631 IOPMWorkQueue::create( IOService
* inOwner
, Action work
, Action retire
)
7633 IOPMWorkQueue
* me
= OSTypeAlloc(IOPMWorkQueue
);
7634 if (me
&& !me
->init(inOwner
, work
, retire
))
7642 bool IOPMWorkQueue::init( IOService
* inOwner
, Action work
, Action retire
)
7644 if (!work
|| !retire
||
7645 !IOEventSource::init(inOwner
, (IOEventSourceAction
)0))
7648 queue_init(&fWorkQueue
);
7651 fRetireAction
= retire
;
7652 fConsumerCount
= fProducerCount
= 0;
7657 bool IOPMWorkQueue::queuePMRequest( IOPMRequest
* request
, IOServicePM
* pwrMgt
)
7664 assert( onThread() );
7665 assert( queue_next(&request
->fCommandChain
) ==
7666 queue_prev(&request
->fCommandChain
) );
7670 // Add new request to the tail of the per-service request queue.
7671 // Then immediately check the request queue to minimize latency
7672 // if the queue was empty.
7674 empty
= queue_empty(&pwrMgt
->RequestHead
);
7675 queue_enter(&pwrMgt
->RequestHead
, request
, IOPMRequest
*, fCommandChain
);
7678 more
= checkRequestQueue(&pwrMgt
->RequestHead
, &empty
);
7681 // New Request is blocked, add IOServicePM to work queue.
7682 assert( queue_next(&pwrMgt
->WorkChain
) ==
7683 queue_prev(&pwrMgt
->WorkChain
) );
7685 queue_enter(&fWorkQueue
, pwrMgt
, IOServicePM
*, WorkChain
);
7687 PM_LOG3("IOPMWorkQueue: [%u] added %s@%p to queue\n",
7688 fQueueLength
, pwrMgt
->Name
, pwrMgt
);
7695 bool IOPMWorkQueue::checkRequestQueue( queue_head_t
* queue
, bool * empty
)
7697 IOPMRequest
* request
;
7702 assert(!queue_empty(queue
));
7704 request
= (IOPMRequest
*) queue_first(queue
);
7705 if (request
->isWorkBlocked())
7706 break; // cannot start, blocked on attached request
7708 target
= request
->getTarget();
7709 done
= (*fWorkAction
)( target
, request
, this );
7711 break; // work started, blocked on PM state machine
7713 assert(gIOPMBusyCount
> 0);
7717 queue_remove_first(queue
, request
, IOPMRequest
*, fCommandChain
);
7718 more
|= (*fRetireAction
)( target
, request
, this );
7719 done
= queue_empty(queue
);
7726 // Retired request blocks another request, since the
7727 // blocked request may reside in the work queue, we
7728 // must bump the producer count to avoid work stall.
7735 bool IOPMWorkQueue::checkForWork( void )
7737 IOServicePM
* entry
;
7742 #if WORK_QUEUE_STATS
7743 fStatCheckForWork
++;
7746 // Each producer signal triggers a full iteration over
7747 // all IOServicePM entries in the work queue.
7749 while (fConsumerCount
!= fProducerCount
)
7751 PM_LOG3("IOPMWorkQueue: checkForWork %u %u\n",
7752 fProducerCount
, fConsumerCount
);
7754 fConsumerCount
= fProducerCount
;
7756 #if WORK_QUEUE_STATS
7757 if (queue_empty(&fWorkQueue
))
7763 uint32_t cachedWorkCount
= gIOPMWorkCount
;
7766 entry
= (IOServicePM
*) queue_first(&fWorkQueue
);
7767 while (!queue_end(&fWorkQueue
, (queue_entry_t
) entry
))
7769 more
|= checkRequestQueue(&entry
->RequestHead
, &empty
);
7771 // Get next entry, points to head if current entry is last.
7772 next
= (IOServicePM
*) queue_next(&entry
->WorkChain
);
7774 // if request queue is empty, remove IOServicePM from queue.
7777 assert(fQueueLength
);
7778 if (fQueueLength
) fQueueLength
--;
7779 PM_LOG3("IOPMWorkQueue: [%u] removed %s@%p from queue\n",
7780 fQueueLength
, entry
->Name
, entry
);
7781 queue_remove(&fWorkQueue
, entry
, IOServicePM
*, WorkChain
);
7786 #if WORK_QUEUE_STATS
7787 if (cachedWorkCount
== gIOPMWorkCount
)
7795 void IOPMWorkQueue::signalWorkAvailable( void )
7798 IOEventSource::signalWorkAvailable();
7801 void IOPMWorkQueue::incrementProducerCount( void )
7807 // MARK: IOPMCompletionQueue
7809 //*********************************************************************************
7810 // IOPMCompletionQueue Class
7811 //*********************************************************************************
7813 OSDefineMetaClassAndStructors( IOPMCompletionQueue
, IOEventSource
);
7815 IOPMCompletionQueue
*
7816 IOPMCompletionQueue::create( IOService
* inOwner
, Action inAction
)
7818 IOPMCompletionQueue
* me
= OSTypeAlloc(IOPMCompletionQueue
);
7819 if (me
&& !me
->init(inOwner
, inAction
))
7827 bool IOPMCompletionQueue::init( IOService
* inOwner
, Action inAction
)
7829 if (!inAction
|| !IOEventSource::init(inOwner
, (IOEventSourceAction
)inAction
))
7832 queue_init(&fQueue
);
7836 bool IOPMCompletionQueue::queuePMRequest( IOPMRequest
* request
)
7841 // unblock dependent request
7842 more
= request
->detachNextRequest();
7843 queue_enter(&fQueue
, request
, IOPMRequest
*, fCommandChain
);
7847 bool IOPMCompletionQueue::checkForWork( void )
7849 Action dqAction
= (Action
) action
;
7850 IOPMRequest
* request
;
7855 request
= (IOPMRequest
*) queue_first(&fQueue
);
7856 while (!queue_end(&fQueue
, (queue_entry_t
) request
))
7858 next
= (IOPMRequest
*) queue_next(&request
->fCommandChain
);
7859 if (!request
->isFreeBlocked())
7861 queue_remove(&fQueue
, request
, IOPMRequest
*, fCommandChain
);
7862 target
= request
->getTarget();
7864 more
|= (*dqAction
)( target
, request
, this );
7873 // MARK: IOServicePM
7875 OSDefineMetaClassAndStructors(IOServicePM
, OSObject
)
7877 //*********************************************************************************
7880 // Serialize IOServicePM for debugging.
7881 //*********************************************************************************
7884 setPMProperty( OSDictionary
* dict
, const char * key
, uint64_t value
)
7886 OSNumber
* num
= OSNumber::withNumber(value
, sizeof(value
) * 8);
7889 dict
->setObject(key
, num
);
7894 IOReturn
IOServicePM::gatedSerialize( OSSerialize
* s
)
7896 OSDictionary
* dict
;
7900 if (IdleTimerPeriod
)
7903 #if WORK_QUEUE_STATS
7904 if (gIOPMRootNode
== ControllingDriver
)
7909 dict
= OSDictionary::withDictionary(
7910 PowerClients
, PowerClients
->getCount() + dictSize
);
7912 dict
= OSDictionary::withCapacity(dictSize
);
7916 setPMProperty(dict
, "CurrentPowerState", CurrentPowerState
);
7917 if (NumberOfPowerStates
)
7918 setPMProperty(dict
, "MaxPowerState", NumberOfPowerStates
-1);
7919 if (DesiredPowerState
!= CurrentPowerState
)
7920 setPMProperty(dict
, "DesiredPowerState", DesiredPowerState
);
7921 if (kIOPM_Finished
!= MachineState
)
7922 setPMProperty(dict
, "MachineState", MachineState
);
7923 if (DeviceOverrideEnabled
)
7924 dict
->setObject("PowerOverrideOn", kOSBooleanTrue
);
7926 if (IdleTimerPeriod
)
7932 clock_get_uptime(&now
);
7934 // The idle timer period in milliseconds.
7935 setPMProperty(dict
, "IdleTimerPeriod", IdleTimerPeriod
* 1000ULL);
7937 // The number of activity tickles recorded since device idle
7938 setPMProperty(dict
, "ActivityTickles", ActivityTickleCount
);
7940 if (AbsoluteTime_to_scalar(&DeviceActiveTimestamp
))
7942 // The number of milliseconds since the last activity tickle.
7944 SUB_ABSOLUTETIME(&delta
, &DeviceActiveTimestamp
);
7945 absolutetime_to_nanoseconds(delta
, &nsecs
);
7946 setPMProperty(dict
, "TimeSinceLastTickle", NS_TO_MS(nsecs
));
7949 if (AbsoluteTime_to_scalar(&IdleTimerStartTime
))
7951 // The number of milliseconds since the last device idle.
7953 SUB_ABSOLUTETIME(&delta
, &IdleTimerStartTime
);
7954 absolutetime_to_nanoseconds(delta
, &nsecs
);
7955 setPMProperty(dict
, "TimeSinceDeviceIdle", NS_TO_MS(nsecs
));
7959 #if WORK_QUEUE_STATS
7960 if (gIOPMRootNode
== Owner
)
7962 setPMProperty(dict
, "WQ-CheckForWork",
7963 gIOPMWorkQueue
->fStatCheckForWork
);
7964 setPMProperty(dict
, "WQ-ScanEntries",
7965 gIOPMWorkQueue
->fStatScanEntries
);
7966 setPMProperty(dict
, "WQ-QueueEmpty",
7967 gIOPMWorkQueue
->fStatQueueEmpty
);
7968 setPMProperty(dict
, "WQ-NoWorkDone",
7969 gIOPMWorkQueue
->fStatNoWorkDone
);
7973 if (HasAdvisoryDesire
&& !gIOPMAdvisoryTickleEnabled
)
7975 // Don't report advisory tickle when it has no influence
7976 dict
->removeObject(gIOPMPowerClientAdvisoryTickle
);
7979 ok
= dict
->serialize(s
);
7983 return (ok
? kIOReturnSuccess
: kIOReturnNoMemory
);
7986 bool IOServicePM::serialize( OSSerialize
* s
) const
7988 IOReturn ret
= kIOReturnNotReady
;
7992 ret
= gIOPMWorkLoop
->runAction(
7993 OSMemberFunctionCast(IOWorkLoop::Action
, this, &IOServicePM::gatedSerialize
),
7994 (OSObject
*) this, (void *) s
);
7997 return (kIOReturnSuccess
== ret
);
8000 void IOServicePM::pmPrint(
8003 uintptr_t param2
) const
8005 gPlatform
->PMLog(Name
, event
, param1
, param2
);
8008 void IOServicePM::pmTrace(
8011 uintptr_t param2
) const
8013 const char * who
= Name
;
8014 uint64_t regId
= Owner
->getRegistryEntryID();
8017 static const uint32_t sStartStopBitField
[] =
8018 { 0x00000000, 0x00000040 }; // Only Program Hardware so far
8020 // Arcane formula from Hacker's Delight by Warren
8021 // abs(x) = ((int) x >> 31) ^ (x + ((int) x >> 31))
8022 uint32_t sgnevent
= ((int) event
>> 31);
8023 uint32_t absevent
= sgnevent
^ (event
+ sgnevent
);
8024 uint32_t code
= IODBG_POWER(absevent
);
8026 uint32_t bit
= 1 << (absevent
& 0x1f);
8027 if ((absevent
< (sizeof(sStartStopBitField
) * 8)) &&
8028 (sStartStopBitField
[absevent
>> 5] & bit
))
8030 // Or in the START or END bits, Start = 1 & END = 2
8031 // If sgnevent == 0 then START - 0 => START
8032 // else if sgnevent == -1 then START - -1 => END
8033 code
|= DBG_FUNC_START
- sgnevent
;
8036 // Copy the first characters of the name into an uintptr_t
8037 for (uint32_t i
= 0; (i
< sizeof(uintptr_t) && who
[i
] != 0); i
++)
8039 ((char *) &name
)[sizeof(uintptr_t) - i
- 1] = who
[i
];
8042 IOTimeStampConstant(code
, name
, (uintptr_t) regId
, param1
, param2
);
8045 PMEventDetails
* PMEventDetails::eventDetails(uint32_t type
,
8046 const char *ownerName
,
8047 uintptr_t ownerUnique
,
8048 const char *interestName
,
8052 uint32_t elapsedTimeUS
) {
8054 PMEventDetails
*myself
;
8055 myself
= new PMEventDetails
;
8058 myself
->eventType
= type
;
8059 myself
->ownerName
= ownerName
;
8060 myself
->ownerUnique
= ownerUnique
;
8061 myself
->interestName
= interestName
;
8062 myself
->oldState
= oldState
;
8063 myself
->newState
= newState
;
8064 myself
->result
= result
;
8065 myself
->elapsedTimeUS
= elapsedTimeUS
;
8067 myself
->eventClassifier
= kIOPMEventClassDriverEvent
;
8074 PMEventDetails
* PMEventDetails::eventDetails(uint32_t type
,
8079 PMEventDetails
*myself
;
8080 myself
= new PMEventDetails
;
8083 myself
->eventType
= type
;
8084 myself
->uuid
= uuid
;
8085 myself
->reason
= reason
;
8086 myself
->result
= result
;
8088 myself
->eventClassifier
= kIOPMEventClassSystemEvent
;