]> git.saurik.com Git - apple/xnu.git/blame_incremental - iokit/Kernel/IOServicePM.cpp
xnu-1504.15.3.tar.gz
[apple/xnu.git] / iokit / Kernel / IOServicePM.cpp
... / ...
CommitLineData
1/*
2 * Copyright (c) 1998-2006 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
14 *
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
17 *
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
25 *
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27 */
28
29//#define IOASSERT 1
30#include <IOKit/assert.h>
31#include <IOKit/IOKitDebug.h>
32#include <IOKit/IOLib.h>
33#include <IOKit/IOMessage.h>
34#include <IOKit/IOPlatformExpert.h>
35#include <IOKit/IOService.h>
36#include <IOKit/IOTimerEventSource.h>
37#include <IOKit/IOWorkLoop.h>
38#include <IOKit/IOCommand.h>
39
40#include <IOKit/pwr_mgt/IOPMlog.h>
41#include <IOKit/pwr_mgt/IOPMinformee.h>
42#include <IOKit/pwr_mgt/IOPMinformeeList.h>
43#include <IOKit/pwr_mgt/IOPowerConnection.h>
44#include <IOKit/pwr_mgt/RootDomain.h>
45
46#include <sys/proc.h>
47
48// Required for notification instrumentation
49#include "IOServicePrivate.h"
50#include "IOServicePMPrivate.h"
51#include "IOKitKernelInternal.h"
52
53static void settle_timer_expired(thread_call_param_t, thread_call_param_t);
54static void tellKernelClientApplier(OSObject * object, void * arg);
55static void tellAppClientApplier(OSObject * object, void * arg);
56
57static uint64_t computeTimeDeltaNS( const AbsoluteTime * start )
58{
59 AbsoluteTime now;
60 uint64_t nsec;
61
62 clock_get_uptime(&now);
63 SUB_ABSOLUTETIME(&now, start);
64 absolutetime_to_nanoseconds(now, &nsec);
65 return nsec;
66}
67
68#if PM_VARS_SUPPORT
69OSDefineMetaClassAndStructors(IOPMprot, OSObject)
70#endif
71
72//*********************************************************************************
73// Globals
74//*********************************************************************************
75
76static bool gIOPMInitialized = false;
77static uint32_t gIOPMBusyCount = 0;
78static IOWorkLoop * gIOPMWorkLoop = 0;
79static IOPMRequestQueue * gIOPMRequestQueue = 0;
80static IOPMRequestQueue * gIOPMReplyQueue = 0;
81static IOPMCompletionQueue * gIOPMFreeQueue = 0;
82static IOPMRequest * gIOPMRequest = 0;
83static IOPlatformExpert * gPlatform = 0;
84static IOService * gIOPMRootNode = 0;
85
86static const OSSymbol * gIOPMPowerClientDevice = 0;
87static const OSSymbol * gIOPMPowerClientDriver = 0;
88static const OSSymbol * gIOPMPowerClientChildProxy = 0;
89static const OSSymbol * gIOPMPowerClientChildren = 0;
90
91static uint32_t getPMRequestType( void )
92{
93 uint32_t type = kIOPMRequestTypeInvalid;
94 if (gIOPMRequest)
95 type = gIOPMRequest->getType();
96 return type;
97}
98
99//*********************************************************************************
100// Macros
101//*********************************************************************************
102
103#define PM_ERROR(x...) do { kprintf(x); IOLog(x); } while (false)
104#define PM_DEBUG(x...) do { kprintf(x); } while (false)
105#define PM_TRACE(x...) do { \
106 if (kIOLogDebugPower & gIOKitDebug) kprintf(x); } while (false)
107
108#define PM_CONNECT(x...)
109
110#define PM_ASSERT_IN_GATE(x) \
111do { \
112 assert(gIOPMWorkLoop->inGate()); \
113} while(false)
114
115#define PM_LOCK() IOLockLock(fPMLock)
116#define PM_UNLOCK() IOLockUnlock(fPMLock)
117#define PM_LOCK_SLEEP(event) IOLockSleep(fPMLock, event, THREAD_UNINT)
118#define PM_LOCK_WAKEUP(event) IOLockWakeup(fPMLock, event, false)
119
120#define ns_per_us 1000
121#define k30seconds (30*1000000)
122#define kMinAckTimeoutTicks (10*1000000)
123#define kIOPMTardyAckSPSKey "IOPMTardyAckSetPowerState"
124#define kIOPMTardyAckPSCKey "IOPMTardyAckPowerStateChange"
125#define kPwrMgtKey "IOPowerManagement"
126
127#define OUR_PMLog(t, a, b) \
128 do { gPlatform->PMLog( fName, t, a, b); } while(0)
129
130#define NS_TO_MS(nsec) ((int)((nsec) / 1000000ULL))
131
132#if CONFIG_EMBEDDED
133#define SUPPORT_IDLE_CANCEL 1
134#endif
135
136#define kNotifyWillChange (true)
137#define kNotifyDidChange (false)
138
139#define kIOPMPowerStateMax 0xFFFFFFFF
140
141#define IS_PM_ROOT() (this == gIOPMRootNode)
142#define IS_POWER_DROP (fHeadNotePowerState < fCurrentPowerState)
143#define IS_POWER_RISE (fHeadNotePowerState > fCurrentPowerState)
144
145// log setPowerStates longer than (ns):
146#define LOG_SETPOWER_TIMES (50ULL * 1000ULL * 1000ULL)
147// log app responses longer than (ns):
148#define LOG_APP_RESPONSE_TIMES (100ULL * 1000ULL * 1000ULL)
149// use message tracer to log messages longer than (ns):
150#define LOG_APP_RESPONSE_MSG_TRACER (3 * 1000ULL * 1000ULL * 1000ULL)
151
152#define RESERVE_DOMAIN_POWER 1
153
154enum {
155 kReserveDomainPower = 1
156};
157
158//*********************************************************************************
159// PM machine states
160//*********************************************************************************
161
162enum {
163 kIOPM_OurChangeTellClientsPowerDown = 1,
164 kIOPM_OurChangeTellPriorityClientsPowerDown = 2,
165 kIOPM_OurChangeNotifyInterestedDriversWillChange = 3,
166 kIOPM_OurChangeSetPowerState = 4,
167 kIOPM_OurChangeWaitForPowerSettle = 5,
168 kIOPM_OurChangeNotifyInterestedDriversDidChange = 6,
169 kIOPM_OurChangeFinish = 7,
170 kIOPM_ParentDownTellPriorityClientsPowerDown = 8,
171 kIOPM_ParentDownNotifyInterestedDriversWillChange = 9,
172 /* 10 not used */
173 kIOPM_ParentDownNotifyDidChangeAndAcknowledgeChange = 11,
174 kIOPM_ParentDownSetPowerState = 12,
175 kIOPM_ParentDownWaitForPowerSettle = 13,
176 kIOPM_ParentAcknowledgePowerChange = 14,
177 kIOPM_ParentUpSetPowerState = 15,
178 /* 16 not used */
179 kIOPM_ParentUpWaitForSettleTime = 17,
180 kIOPM_ParentUpNotifyInterestedDriversDidChange = 18,
181 /* 19 not used */
182 kIOPM_Finished = 20,
183 kIOPM_DriverThreadCallDone = 21,
184 kIOPM_NotifyChildrenDone = 22,
185 kIOPM_SyncNotifyDidChange = 23,
186 kIOPM_SyncFinish = 24
187};
188
189
190 /*
191 Power Management defines a few roles that drivers can play in their own,
192 and other drivers', power management. We briefly define those here.
193
194 Many drivers implement their policy maker and power controller within the same
195 IOService object, but that is not required.
196
197== Policy Maker ==
198 * Virtual IOService PM methods a "policy maker" may implement
199 * maxCapabilityForDomainState()
200 * initialPowerStateForDomainState()
201 * powerStateForDomainState()
202
203 * Virtual IOService PM methods a "policy maker" may CALL
204 * PMinit()
205
206== Power Controller ==
207 * Virtual IOService PM methods a "power controller" may implement
208 * setPowerState()
209
210 * Virtual IOService PM methods a "power controller" may CALL
211 * joinPMtree()
212 * registerPowerDriver()
213
214=======================
215 There are two different kinds of power state changes.
216 * One is initiated by a subclassed device object which has either decided
217 to change power state, or its controlling driver has suggested it, or
218 some other driver wants to use the idle device and has asked it to become
219 usable.
220 * The second kind of power state change is initiated by the power domain
221 parent.
222 The two are handled through different code paths.
223
224 We maintain a queue of "change notifications," or change notes.
225 * Usually the queue is empty.
226 * When it isn't, usually there is one change note in it
227 * It's possible to have more than one power state change pending at one
228 time, so a queue is implemented.
229 Example:
230 * The subclass device decides it's idle and initiates a change to a lower
231 power state. This causes interested parties to be notified, but they
232 don't all acknowledge right away. This causes the change note to sit
233 in the queue until all the acks are received. During this time, the
234 device decides it isn't idle anymore and wants to raise power back up
235 again. This change can't be started, however, because the previous one
236 isn't complete yet, so the second one waits in the queue. During this
237 time, the parent decides to lower or raise the power state of the entire
238 power domain and notifies the device, and that notification goes into
239 the queue, too, and can't be actioned until the others are.
240
241 == SelfInitiated ==
242 This is how a power change initiated by the subclass device is handled:
243 -> First, all interested parties are notified of the change via their
244 powerStateWillChangeTo method. If they all don't acknowledge via return
245 code, then we have to wait. If they do, or when they finally all
246 acknowledge via our acknowledgePowerChange method, then we can continue.
247 -> We call the controlling driver, instructing it to change to the new state
248 -> Then we wait for power to settle. If there is no settling-time, or after
249 it has passed,
250 -> we notify interested parties again, this time via their
251 powerStateDidChangeTo methods.
252 -> When they have all acked, we're done.
253 If we lowered power and don't need the power domain to be in its current power
254 state, we suggest to the parent that it lower the power domain state.
255
256 == PowerDomainDownInitiated ==
257How a change to a lower power domain state initiated by the parent is handled:
258 -> First, we figure out what power state we will be in when the new domain
259 state is reached.
260 -> Then all interested parties are notified that we are moving to that new
261 state.
262 -> When they have acknowledged, we call the controlling driver to assume
263 that state and we wait for power to settle.
264 -> Then we acknowledge our preparedness to our parent. When all its
265 interested parties have acknowledged,
266 -> it lowers power and then notifies its interested parties again.
267 -> When we get this call, we notify our interested parties that the power
268 state has changed, and when they have all acknowledged, we're done.
269
270 == PowerDomainUpInitiated ==
271How a change to a higher power domain state initiated by the parent is handled:
272 -> We figure out what power state we will be in when the new domain state is
273 reached.
274 -> If it is different from our current state we acknowledge the parent.
275 -> When all the parent's interested parties have acknowledged, it raises
276 power in the domain and waits for power to settle.
277 -> Then it notifies everyone that the new state has been reached.
278 -> When we get this call, we call the controlling driver, instructing it to
279 assume the new state, and wait for power to settle.
280 -> Then we notify our interested parties. When they all acknowledge we are
281 done.
282
283 In either of the two power domain state cases above, it is possible that we
284 will not be changing state even though the domain is.
285 Examples:
286 * A change to a lower domain state may not affect us because we are already
287 in a low enough state,
288 * We will not take advantage of a change to a higher domain state, because
289 we have no need of the higher power. In such cases, there is nothing to
290 do but acknowledge the parent. So when the parent calls our
291 powerDomainWillChange method, and we decide that we will not be changing
292 state, we merely acknowledge the parent, via return code, and wait.
293 When the parent subsequently calls powerStateDidChange, we acknowledge again
294 via return code, and the change is complete.
295
296 == 4 Paths Through State Machine ==
297 Power state changes are processed in a state machine, and since there are four
298 varieties of power state changes, there are four major paths through the state
299 machine.
300
301 == 5. No Need To change ==
302 The fourth is nearly trivial. In this path, the parent is changing the domain
303 state, but we are not changing the device state. The change starts when the
304 parent calls powerDomainWillChange. All we do is acknowledge the parent. When
305 the parent calls powerStateDidChange, we acknowledge the parent again, and
306 we're done.
307
308 == 1. OurChange Down == XXX gvdl
309 The first is fairly simple. It starts:
310 * when a power domain child calls requestPowerDomainState and we decide to
311 change power states to accomodate the child,
312 * or if our power-controlling driver calls changePowerStateTo,
313 * or if some other driver which is using our device calls makeUsable,
314 * or if a subclassed object calls changePowerStateToPriv.
315 These are all power changes initiated by us, not forced upon us by the parent.
316
317 -> We start by notifying interested parties.
318 -> If they all acknowledge via return code, we can go on to state
319 "msSetPowerState".
320 -> Otherwise, we start the ack timer and wait for the stragglers to
321 acknowlege by calling acknowledgePowerChange.
322 -> We move on to state "msSetPowerState" when all the
323 stragglers have acknowledged, or when the ack timer expires on
324 all those which didn't acknowledge.
325 In "msSetPowerState" we call the power-controlling driver to change the
326 power state of the hardware.
327 -> If it returns saying it has done so, we go on to state
328 "msWaitForPowerSettle".
329 -> Otherwise, we have to wait for it, so we set the ack timer and wait.
330 -> When it calls acknowledgeSetPowerState, or when the ack timer
331 expires, we go on.
332 In "msWaitForPowerSettle", we look in the power state array to see if
333 there is any settle time required when changing from our current state to the
334 new state.
335 -> If not, we go right away to "msNotifyInterestedDriversDidChange".
336 -> Otherwise, we set the settle timer and wait. When it expires, we move on.
337 In "msNotifyInterestedDriversDidChange" state, we notify all our
338 interested parties via their powerStateDidChange methods that we have finished
339 changing power state.
340 -> If they all acknowledge via return code, we move on to "msFinish".
341 -> Otherwise we set the ack timer and wait. When they have all
342 acknowledged, or when the ack timer has expired for those that didn't,
343 we move on to "msFinish".
344 In "msFinish" we remove the used change note from the head of the queue
345 and start the next one if one exists.
346
347 == 2. Parent Change Down ==
348 Start at Stage 2 of OurChange Down XXX gvdl
349
350 == 3. Change Up ==
351 Start at Stage 4 of OurChange Down XXX gvdl
352
353Note all parent requested changes need to acknowledge the power has changed to the parent when done.
354 */
355
356//*********************************************************************************
357// [public] PMinit
358//
359// Initialize power management.
360//*********************************************************************************
361
362void IOService::PMinit ( void )
363{
364 if ( !initialized )
365 {
366 if ( !gIOPMInitialized )
367 {
368 gPlatform = getPlatform();
369 gIOPMWorkLoop = IOWorkLoop::workLoop();
370 if (gIOPMWorkLoop)
371 {
372 gIOPMRequestQueue = IOPMRequestQueue::create(
373 this, OSMemberFunctionCast(IOPMRequestQueue::Action,
374 this, &IOService::servicePMRequestQueue));
375
376 gIOPMReplyQueue = IOPMRequestQueue::create(
377 this, OSMemberFunctionCast(IOPMRequestQueue::Action,
378 this, &IOService::servicePMReplyQueue));
379
380 gIOPMFreeQueue = IOPMCompletionQueue::create(
381 this, OSMemberFunctionCast(IOPMCompletionQueue::Action,
382 this, &IOService::servicePMFreeQueue));
383
384 if (gIOPMWorkLoop->addEventSource(gIOPMRequestQueue) !=
385 kIOReturnSuccess)
386 {
387 gIOPMRequestQueue->release();
388 gIOPMRequestQueue = 0;
389 }
390
391 if (gIOPMWorkLoop->addEventSource(gIOPMReplyQueue) !=
392 kIOReturnSuccess)
393 {
394 gIOPMReplyQueue->release();
395 gIOPMReplyQueue = 0;
396 }
397
398 if (gIOPMWorkLoop->addEventSource(gIOPMFreeQueue) !=
399 kIOReturnSuccess)
400 {
401 gIOPMFreeQueue->release();
402 gIOPMFreeQueue = 0;
403 }
404
405 gIOPMPowerClientDevice = OSSymbol::withCStringNoCopy( "DevicePowerState" );
406 gIOPMPowerClientDriver = OSSymbol::withCStringNoCopy( "DriverPowerState" );
407 gIOPMPowerClientChildProxy = OSSymbol::withCStringNoCopy( "ChildProxyPowerState" );
408 gIOPMPowerClientChildren = OSSymbol::withCStringNoCopy( "ChildrenPowerState" );
409 }
410
411 if (gIOPMRequestQueue && gIOPMReplyQueue && gIOPMFreeQueue)
412 gIOPMInitialized = true;
413 }
414 if (!gIOPMInitialized)
415 return;
416
417 pwrMgt = new IOServicePM;
418 pwrMgt->init();
419 setProperty(kPwrMgtKey, pwrMgt);
420
421 fPMLock = IOLockAlloc();
422 fInterestedDrivers = new IOPMinformeeList;
423 fInterestedDrivers->initialize();
424 fDesiredPowerState = 0;
425 fDeviceDesire = 0;
426 fInitialChange = true;
427 fPreviousRequest = 0;
428 fDeviceOverrides = false;
429 fMachineState = kIOPM_Finished;
430 fIdleTimerEventSource = NULL;
431 fIdleTimerMinPowerState = 0;
432 fActivityLock = IOLockAlloc();
433 fStrictTreeOrder = false;
434 fActivityTicklePowerState = -1;
435 fControllingDriver = NULL;
436 fPowerStates = NULL;
437 fNumberOfPowerStates = 0;
438 fCurrentPowerState = 0;
439 fParentsCurrentPowerFlags = 0;
440 fMaxCapability = 0;
441 fName = getName();
442 fParentsKnowState = false;
443 fSerialNumber = 0;
444 fResponseArray = NULL;
445 fNotifyClientArray = NULL;
446 fDoNotPowerDown = true;
447 fCurrentPowerConsumption = kIOPMUnknown;
448 fOverrideMaxPowerState = kIOPMPowerStateMax;
449
450 if (!gIOPMRootNode && (getParentEntry(gIOPowerPlane) == getRegistryRoot()))
451 {
452 gIOPMRootNode = this;
453 fParentsKnowState = true;
454 }
455
456 fAckTimer = thread_call_allocate(
457 &IOService::ack_timer_expired, (thread_call_param_t)this);
458 fSettleTimer = thread_call_allocate(
459 &settle_timer_expired, (thread_call_param_t)this);
460 fDriverCallEntry = thread_call_allocate(
461 (thread_call_func_t) &IOService::pmDriverCallout, this);
462 assert(fDriverCallEntry);
463
464#if PM_VARS_SUPPORT
465 IOPMprot * prot = new IOPMprot;
466 if (prot)
467 {
468 prot->init();
469 prot->ourName = fName;
470 prot->thePlatform = gPlatform;
471 fPMVars = prot;
472 pm_vars = prot;
473 }
474#else
475 pm_vars = (void *) true;
476#endif
477
478 initialized = true;
479 }
480}
481
482//*********************************************************************************
483// [private] PMfree
484//
485// Free the data created by PMinit. Only called from IOService::free().
486//*********************************************************************************
487
488void IOService::PMfree ( void )
489{
490 initialized = false;
491 pm_vars = 0;
492
493 if ( pwrMgt )
494 {
495 assert(fMachineState == kIOPM_Finished);
496 assert(fInsertInterestSet == NULL);
497 assert(fRemoveInterestSet == NULL);
498 assert(fNotifyChildArray == NULL);
499
500 if ( fIdleTimerEventSource != NULL ) {
501 fIdleTimerEventSource->disable();
502 gIOPMWorkLoop->removeEventSource(fIdleTimerEventSource);
503 fIdleTimerEventSource->release();
504 fIdleTimerEventSource = NULL;
505 }
506 if ( fSettleTimer ) {
507 thread_call_cancel(fSettleTimer);
508 thread_call_free(fSettleTimer);
509 fSettleTimer = NULL;
510 }
511 if ( fAckTimer ) {
512 thread_call_cancel(fAckTimer);
513 thread_call_free(fAckTimer);
514 fAckTimer = NULL;
515 }
516 if ( fDriverCallEntry ) {
517 thread_call_free(fDriverCallEntry);
518 fDriverCallEntry = NULL;
519 }
520 if ( fPMLock ) {
521 IOLockFree(fPMLock);
522 fPMLock = NULL;
523 }
524 if ( fActivityLock ) {
525 IOLockFree(fActivityLock);
526 fActivityLock = NULL;
527 }
528 if ( fInterestedDrivers ) {
529 fInterestedDrivers->release();
530 fInterestedDrivers = NULL;
531 }
532 if ( fPMWorkQueue ) {
533 gIOPMWorkLoop->removeEventSource(fPMWorkQueue);
534 fPMWorkQueue->release();
535 fPMWorkQueue = 0;
536 }
537 if (fDriverCallParamSlots && fDriverCallParamPtr) {
538 IODelete(fDriverCallParamPtr, DriverCallParam, fDriverCallParamSlots);
539 fDriverCallParamPtr = 0;
540 fDriverCallParamSlots = 0;
541 }
542 if ( fResponseArray ) {
543 fResponseArray->release();
544 fResponseArray = NULL;
545 }
546 if ( fNotifyClientArray ) {
547 fNotifyClientArray->release();
548 fNotifyClientArray = NULL;
549 }
550 if (fPowerStates && fNumberOfPowerStates) {
551 IODelete(fPowerStates, IOPMPowerState, fNumberOfPowerStates);
552 fNumberOfPowerStates = 0;
553 fPowerStates = NULL;
554 }
555 if (fPowerClients) {
556 fPowerClients->release();
557 fPowerClients = 0;
558 }
559
560#if PM_VARS_SUPPORT
561 if (fPMVars)
562 {
563 fPMVars->release();
564 fPMVars = 0;
565 }
566#endif
567
568 pwrMgt->release();
569 pwrMgt = 0;
570 }
571}
572
573//*********************************************************************************
574// [public] joinPMtree
575//
576// A policy-maker calls its nub here when initializing, to be attached into
577// the power management hierarchy. The default function is to call the
578// platform expert, which knows how to do it. This method is overridden
579// by a nub subclass which may either know how to do it, or may need to
580// take other action.
581//
582// This may be the only "power management" method used in a nub,
583// meaning it may not be initialized for power management.
584//*********************************************************************************
585
586void IOService::joinPMtree ( IOService * driver )
587{
588 IOPlatformExpert * platform;
589
590 platform = getPlatform();
591 assert(platform != 0);
592 platform->PMRegisterDevice(this, driver);
593}
594
595#ifndef __LP64__
596//*********************************************************************************
597// [deprecated] youAreRoot
598//
599// Power Managment is informing us that we are the root power domain.
600//*********************************************************************************
601
602IOReturn IOService::youAreRoot ( void )
603{
604 return IOPMNoErr;
605}
606#endif /* !__LP64__ */
607
608//*********************************************************************************
609// [public] PMstop
610//
611// Immediately stop driver callouts. Schedule an async stop request to detach
612// from power plane.
613//*********************************************************************************
614
615void IOService::PMstop ( void )
616{
617 IOPMRequest * request;
618
619 if (!initialized)
620 return;
621
622 // Schedule an async PMstop request, but immediately stop any further
623 // calls to the controlling or interested drivers. This device will
624 // continue to exist in the power plane and participate in power state
625 // changes until the PMstop async request is processed.
626
627 PM_LOCK();
628 fLockedFlags.PMStop = true;
629 if (fLockedFlags.DriverCallBusy)
630 {
631 PM_DEBUG("%s: PMstop() driver call busy\n", getName());
632 }
633 while (fThreadAssertionCount != 0)
634 {
635 if (current_thread() == fThreadAssertionThread)
636 {
637 PM_ERROR("%s: PMstop() called from PM thread call\n", getName());
638 break;
639 }
640 // Wait for thread assertions to drop to zero.
641 PM_DEBUG("%s: PMstop() wait for %u thread assertion(s)\n",
642 getName(), fThreadAssertionCount);
643 PM_LOCK_SLEEP(&fThreadAssertionCount);
644 }
645 PM_UNLOCK();
646
647 request = acquirePMRequest( this, kIOPMRequestTypePMStop );
648 if (request)
649 {
650 PM_TRACE("%s: %p PMstop\n", getName(), this);
651 submitPMRequest( request );
652 }
653}
654
655//*********************************************************************************
656// [private] handlePMstop
657//
658// Disconnect the node from all parents and children in the power plane.
659//*********************************************************************************
660
661void IOService::handlePMstop ( IOPMRequest * request )
662{
663 OSIterator * iter;
664 OSObject * next;
665 IOPowerConnection * connection;
666 IOService * theChild;
667 IOService * theParent;
668
669 PM_ASSERT_IN_GATE();
670 PM_TRACE("%s: %p %s start\n", getName(), this, __FUNCTION__);
671
672 // remove the property
673 removeProperty(kPwrMgtKey);
674
675 // detach parents
676 iter = getParentIterator(gIOPowerPlane);
677 if ( iter )
678 {
679 while ( (next = iter->getNextObject()) )
680 {
681 if ( (connection = OSDynamicCast(IOPowerConnection, next)) )
682 {
683 theParent = (IOService *)connection->copyParentEntry(gIOPowerPlane);
684 if ( theParent )
685 {
686 theParent->removePowerChild(connection);
687 theParent->release();
688 }
689 }
690 }
691 iter->release();
692 }
693
694 // detach IOConnections
695 detachAbove( gIOPowerPlane );
696
697 // no more power state changes
698 fParentsKnowState = false;
699
700 // detach children
701 iter = getChildIterator(gIOPowerPlane);
702 if ( iter )
703 {
704 while ( (next = iter->getNextObject()) )
705 {
706 if ( (connection = OSDynamicCast(IOPowerConnection, next)) )
707 {
708 theChild = ((IOService *)(connection->copyChildEntry(gIOPowerPlane)));
709 if ( theChild )
710 {
711 // detach nub from child
712 connection->detachFromChild(theChild, gIOPowerPlane);
713 theChild->release();
714 }
715 // detach us from nub
716 detachFromChild(connection, gIOPowerPlane);
717 }
718 }
719 iter->release();
720 }
721
722 // Remove all interested drivers from the list, including the power
723 // controlling driver.
724 //
725 // Usually, the controlling driver and the policy-maker functionality
726 // are implemented by the same object, and without the deregistration,
727 // the object will be holding an extra retain on itself, and cannot
728 // be freed.
729
730 if ( fInterestedDrivers )
731 {
732 IOPMinformeeList * list = fInterestedDrivers;
733 IOPMinformee * item;
734
735 PM_LOCK();
736 while ((item = list->firstInList()))
737 {
738 list->removeFromList(item->whatObject);
739 }
740 PM_UNLOCK();
741 }
742
743 // Tell idleTimerExpired() to ignore idle timer.
744 fIdleTimerPeriod = 0;
745 if (fIdleTimerEventSource)
746 fIdleTimerEventSource->disable();
747
748 PM_TRACE("%s: %p %s done\n", getName(), this, __FUNCTION__);
749}
750
751//*********************************************************************************
752// [public] addPowerChild
753//
754// Power Management is informing us who our children are.
755//*********************************************************************************
756
757IOReturn IOService::addPowerChild ( IOService * child )
758{
759 IOPowerConnection * connection = 0;
760 IOPMRequest * requests[3] = {0, 0, 0};
761 OSIterator * iter;
762 bool ok = true;
763
764 if (!child)
765 return kIOReturnBadArgument;
766
767 if (!initialized || !child->initialized)
768 return IOPMNotYetInitialized;
769
770 OUR_PMLog( kPMLogAddChild, (uintptr_t) child, 0 );
771
772 do {
773 // Is this child already one of our children?
774
775 iter = child->getParentIterator( gIOPowerPlane );
776 if ( iter )
777 {
778 IORegistryEntry * entry;
779 OSObject * next;
780
781 while ((next = iter->getNextObject()))
782 {
783 if ((entry = OSDynamicCast(IORegistryEntry, next)) &&
784 isChild(entry, gIOPowerPlane))
785 {
786 ok = false;
787 break;
788 }
789 }
790 iter->release();
791 }
792 if (!ok)
793 {
794 PM_DEBUG("%s: %s (%p) is already a child\n",
795 getName(), child->getName(), child);
796 break;
797 }
798
799 // Add the child to the power plane immediately, but the
800 // joining connection is marked as not ready.
801 // We want the child to appear in the power plane before
802 // returning to the caller, but don't want the caller to
803 // block on the PM work loop.
804
805 connection = new IOPowerConnection;
806 if (!connection)
807 break;
808
809 // Create a chain of PM requests to perform the bottom-half
810 // work from the PM work loop.
811
812 requests[0] = acquirePMRequest(
813 /* target */ this,
814 /* type */ kIOPMRequestTypeAddPowerChild1 );
815
816 requests[1] = acquirePMRequest(
817 /* target */ child,
818 /* type */ kIOPMRequestTypeAddPowerChild2 );
819
820 requests[2] = acquirePMRequest(
821 /* target */ this,
822 /* type */ kIOPMRequestTypeAddPowerChild3 );
823
824 if (!requests[0] || !requests[1] || !requests[2])
825 break;
826
827 requests[0]->attachNextRequest( requests[1] );
828 requests[1]->attachNextRequest( requests[2] );
829
830 connection->init();
831 connection->start(this);
832 connection->setAwaitingAck(false);
833 connection->setReadyFlag(false);
834
835 attachToChild( connection, gIOPowerPlane );
836 connection->attachToChild( child, gIOPowerPlane );
837
838 // connection needs to be released
839 requests[0]->fArg0 = connection;
840 requests[1]->fArg0 = connection;
841 requests[2]->fArg0 = connection;
842
843 submitPMRequest( requests, 3 );
844 return kIOReturnSuccess;
845 }
846 while (false);
847
848 if (connection) connection->release();
849 if (requests[0]) releasePMRequest(requests[0]);
850 if (requests[1]) releasePMRequest(requests[1]);
851 if (requests[2]) releasePMRequest(requests[2]);
852
853 // Silent failure, to prevent platform drivers from adding the child
854 // to the root domain.
855
856 return kIOReturnSuccess;
857}
858
859//*********************************************************************************
860// [private] addPowerChild1
861//
862// Step 1/3 of adding a power child. Called on the power parent.
863//*********************************************************************************
864
865void IOService::addPowerChild1 ( IOPMRequest * request )
866{
867 unsigned long tempDesire = 0;
868
869 // Make us temporary usable before adding the child.
870
871 PM_ASSERT_IN_GATE();
872 OUR_PMLog( kPMLogMakeUsable, kPMLogMakeUsable, 0 );
873
874 if (fControllingDriver && inPlane(gIOPowerPlane) && fParentsKnowState)
875 {
876 tempDesire = fNumberOfPowerStates - 1;
877 }
878
879 if (tempDesire && (IS_PM_ROOT() || (fMaxCapability >= tempDesire)))
880 {
881 adjustPowerState(tempDesire);
882 }
883}
884
885//*********************************************************************************
886// [private] addPowerChild2
887//
888// Step 2/3 of adding a power child. Called on the joining child.
889// Execution blocked behind addPowerChild1.
890//*********************************************************************************
891
892void IOService::addPowerChild2 ( IOPMRequest * request )
893{
894 IOPowerConnection * connection = (IOPowerConnection *) request->fArg0;
895 IOService * parent;
896 IOPMPowerFlags powerFlags;
897 bool knowsState;
898 unsigned long powerState;
899 unsigned long tempDesire;
900
901 PM_ASSERT_IN_GATE();
902 parent = (IOService *) connection->getParentEntry(gIOPowerPlane);
903
904 if (!parent || !inPlane(gIOPowerPlane))
905 {
906 PM_DEBUG("%s: addPowerChild2 not in power plane\n", getName());
907 return;
908 }
909
910 // Parent will be waiting for us to complete this stage.
911 // It is safe to directly access parent's vars.
912
913 knowsState = (parent->fPowerStates) && (parent->fParentsKnowState);
914 powerState = parent->fCurrentPowerState;
915
916 if (knowsState)
917 powerFlags = parent->fPowerStates[powerState].outputPowerCharacter;
918 else
919 powerFlags = 0;
920
921 // Set our power parent.
922
923 OUR_PMLog(kPMLogSetParent, knowsState, powerFlags);
924
925 setParentInfo( powerFlags, connection, knowsState );
926
927 connection->setReadyFlag(true);
928
929 if ( fControllingDriver && fParentsKnowState )
930 {
931 fMaxCapability = fControllingDriver->maxCapabilityForDomainState(fParentsCurrentPowerFlags);
932 // initially change into the state we are already in
933 tempDesire = fControllingDriver->initialPowerStateForDomainState(fParentsCurrentPowerFlags);
934 fPreviousRequest = 0xffffffff;
935 adjustPowerState(tempDesire);
936 }
937
938#if ROOT_DOMAIN_RUN_STATES
939 getPMRootDomain()->tagPowerPlaneService(this, &fRootDomainState);
940#endif
941}
942
943//*********************************************************************************
944// [private] addPowerChild3
945//
946// Step 3/3 of adding a power child. Called on the parent.
947// Execution blocked behind addPowerChild2.
948//*********************************************************************************
949
950void IOService::addPowerChild3 ( IOPMRequest * request )
951{
952 IOPowerConnection * connection = (IOPowerConnection *) request->fArg0;
953 IOService * child;
954 IOPMrootDomain * rootDomain = getPMRootDomain();
955
956 PM_ASSERT_IN_GATE();
957 child = (IOService *) connection->getChildEntry(gIOPowerPlane);
958
959 if (child && inPlane(gIOPowerPlane))
960 {
961 if (child->getProperty("IOPMStrictTreeOrder"))
962 {
963 PM_DEBUG("%s: strict PM order enforced\n", getName());
964 fStrictTreeOrder = true;
965 }
966
967 if (rootDomain)
968 rootDomain->joinAggressiveness( child );
969 }
970 else
971 {
972 PM_DEBUG("%s: addPowerChild3 not in power plane\n", getName());
973 }
974
975 connection->release();
976}
977
978#ifndef __LP64__
979//*********************************************************************************
980// [deprecated] setPowerParent
981//
982// Power Management is informing us who our parent is.
983// If we have a controlling driver, find out, given our newly-informed
984// power domain state, what state it would be in, and then tell it
985// to assume that state.
986//*********************************************************************************
987
988IOReturn IOService::setPowerParent (
989 IOPowerConnection * theParent, bool stateKnown, IOPMPowerFlags powerFlags )
990{
991 return kIOReturnUnsupported;
992}
993#endif /* !__LP64__ */
994
995//*********************************************************************************
996// [public] removePowerChild
997//
998// Called on a parent whose child is being removed by PMstop().
999//*********************************************************************************
1000
1001IOReturn IOService::removePowerChild ( IOPowerConnection * theNub )
1002{
1003 IORegistryEntry * theChild;
1004
1005 PM_ASSERT_IN_GATE();
1006 OUR_PMLog( kPMLogRemoveChild, 0, 0 );
1007
1008 theNub->retain();
1009
1010 // detach nub from child
1011 theChild = theNub->copyChildEntry(gIOPowerPlane);
1012 if ( theChild )
1013 {
1014 theNub->detachFromChild(theChild, gIOPowerPlane);
1015 theChild->release();
1016 }
1017 // detach from the nub
1018 detachFromChild(theNub, gIOPowerPlane);
1019
1020 // Are we awaiting an ack from this child?
1021 if ( theNub->getAwaitingAck() )
1022 {
1023 // yes, pretend we got one
1024 theNub->setAwaitingAck(false);
1025 if (fHeadNotePendingAcks != 0 )
1026 {
1027 // that's one fewer ack to worry about
1028 fHeadNotePendingAcks--;
1029
1030 // is that the last?
1031 if ( fHeadNotePendingAcks == 0 )
1032 {
1033 stop_ack_timer();
1034 }
1035 }
1036 }
1037
1038 theNub->release();
1039
1040 // A child has gone away, re-scan children desires and clamp bits.
1041 // The fPendingAdjustPowerRequest helps to reduce redundant parent work.
1042
1043 if (!fAdjustPowerScheduled)
1044 {
1045 IOPMRequest * request;
1046 request = acquirePMRequest( this, kIOPMRequestTypeAdjustPowerState );
1047 if (request)
1048 {
1049 submitPMRequest( request );
1050 fAdjustPowerScheduled = true;
1051 }
1052 }
1053
1054 return IOPMNoErr;
1055}
1056
1057//*********************************************************************************
1058// [public] registerPowerDriver
1059//
1060// A driver has called us volunteering to control power to our device.
1061//*********************************************************************************
1062
1063IOReturn IOService::registerPowerDriver (
1064 IOService * powerDriver,
1065 IOPMPowerState * powerStates,
1066 unsigned long numberOfStates )
1067{
1068 IOPMRequest * request;
1069 IOPMPowerState * powerStatesCopy = 0;
1070
1071 if (!initialized)
1072 return IOPMNotYetInitialized;
1073
1074 // Validate arguments.
1075 if (!powerStates || (numberOfStates < 2))
1076 {
1077 OUR_PMLog(kPMLogControllingDriverErr5, numberOfStates, 0);
1078 return kIOReturnBadArgument;
1079 }
1080
1081 if (!powerDriver || !powerDriver->initialized)
1082 {
1083 OUR_PMLog(kPMLogControllingDriverErr4, 0, 0);
1084 return kIOReturnBadArgument;
1085 }
1086
1087 if (powerStates[0].version != kIOPMPowerStateVersion1)
1088 {
1089 OUR_PMLog(kPMLogControllingDriverErr1, powerStates[0].version, 0);
1090 return kIOReturnBadArgument;
1091 }
1092
1093 do {
1094 // Make a copy of the supplied power state array.
1095 powerStatesCopy = IONew(IOPMPowerState, numberOfStates);
1096 if (!powerStatesCopy)
1097 break;
1098
1099 bcopy( powerStates, powerStatesCopy,
1100 sizeof(IOPMPowerState) * numberOfStates );
1101
1102 request = acquirePMRequest( this, kIOPMRequestTypeRegisterPowerDriver );
1103 if (!request)
1104 break;
1105
1106 powerDriver->retain();
1107 request->fArg0 = (void *) powerDriver;
1108 request->fArg1 = (void *) powerStatesCopy;
1109 request->fArg2 = (void *) numberOfStates;
1110
1111 submitPMRequest( request );
1112 return kIOReturnSuccess;
1113 }
1114 while (false);
1115
1116 if (powerStatesCopy)
1117 IODelete(powerStatesCopy, IOPMPowerState, numberOfStates);
1118 return kIOReturnNoMemory;
1119}
1120
1121//*********************************************************************************
1122// [private] handleRegisterPowerDriver
1123//*********************************************************************************
1124
1125void IOService::handleRegisterPowerDriver ( IOPMRequest * request )
1126{
1127 IOService * powerDriver = (IOService *) request->fArg0;
1128 IOPMPowerState * powerStates = (IOPMPowerState *) request->fArg1;
1129 unsigned long numberOfStates = (unsigned long) request->fArg2;
1130 unsigned long i;
1131 IOService * root;
1132 OSIterator * iter;
1133
1134 PM_ASSERT_IN_GATE();
1135 assert(powerStates);
1136 assert(powerDriver);
1137 assert(numberOfStates > 1);
1138
1139 if ( !fNumberOfPowerStates )
1140 {
1141 OUR_PMLog(kPMLogControllingDriver,
1142 (unsigned long) numberOfStates,
1143 (unsigned long) powerStates[0].version);
1144
1145 fPowerStates = powerStates;
1146 fNumberOfPowerStates = numberOfStates;
1147 fControllingDriver = powerDriver;
1148 fCurrentCapabilityFlags = fPowerStates[0].capabilityFlags;
1149
1150 // make a mask of all the character bits we know about
1151 fOutputPowerCharacterFlags = 0;
1152 for ( i = 0; i < numberOfStates; i++ ) {
1153 fOutputPowerCharacterFlags |= fPowerStates[i].outputPowerCharacter;
1154 }
1155
1156 // Register powerDriver as interested, unless already done.
1157 // We don't want to register the default implementation since
1158 // it does nothing. One ramification of not always registering
1159 // is the one fewer retain count held.
1160
1161 root = getPlatform()->getProvider();
1162 assert(root);
1163 if (!root ||
1164 ((OSMemberFunctionCast(void (*)(void),
1165 root, &IOService::powerStateDidChangeTo)) !=
1166 ((OSMemberFunctionCast(void (*)(void),
1167 this, &IOService::powerStateDidChangeTo)))) ||
1168 ((OSMemberFunctionCast(void (*)(void),
1169 root, &IOService::powerStateWillChangeTo)) !=
1170 ((OSMemberFunctionCast(void (*)(void),
1171 this, &IOService::powerStateWillChangeTo)))))
1172 {
1173 if (fInterestedDrivers->findItem(powerDriver) == NULL)
1174 {
1175 PM_LOCK();
1176 fInterestedDrivers->appendNewInformee(powerDriver);
1177 PM_UNLOCK();
1178 }
1179 }
1180
1181 // Examine all existing power clients and perform limit check.
1182
1183 if (fPowerClients)
1184 {
1185 iter = OSCollectionIterator::withCollection(fPowerClients);
1186 if (iter)
1187 {
1188 const OSSymbol * client;
1189 while ((client = (const OSSymbol *) iter->getNextObject()))
1190 {
1191 uint32_t powerState = getPowerStateForClient(client);
1192 if (powerState >= numberOfStates)
1193 {
1194 updatePowerClient(client, numberOfStates - 1);
1195 }
1196 }
1197 iter->release();
1198 }
1199 }
1200
1201 if ( inPlane(gIOPowerPlane) && fParentsKnowState )
1202 {
1203 unsigned long tempDesire;
1204 fMaxCapability = fControllingDriver->maxCapabilityForDomainState(fParentsCurrentPowerFlags);
1205 // initially change into the state we are already in
1206 tempDesire = fControllingDriver->initialPowerStateForDomainState(fParentsCurrentPowerFlags);
1207 adjustPowerState(tempDesire);
1208 }
1209 }
1210 else
1211 {
1212 OUR_PMLog(kPMLogControllingDriverErr2, numberOfStates, 0);
1213 IODelete(powerStates, IOPMPowerState, numberOfStates);
1214 }
1215
1216 powerDriver->release();
1217}
1218
1219//*********************************************************************************
1220// [public] registerInterestedDriver
1221//
1222// Add the caller to our list of interested drivers and return our current
1223// power state. If we don't have a power-controlling driver yet, we will
1224// call this interested driver again later when we do get a driver and find
1225// out what the current power state of the device is.
1226//*********************************************************************************
1227
1228IOPMPowerFlags IOService::registerInterestedDriver ( IOService * driver )
1229{
1230 IOPMRequest * request;
1231 bool signal;
1232
1233 if (!initialized || !fInterestedDrivers)
1234 return IOPMNotPowerManaged;
1235
1236 PM_LOCK();
1237 signal = (!fInsertInterestSet && !fRemoveInterestSet);
1238 if (fInsertInterestSet == NULL)
1239 fInsertInterestSet = OSSet::withCapacity(4);
1240 if (fInsertInterestSet)
1241 fInsertInterestSet->setObject(driver);
1242 PM_UNLOCK();
1243
1244 if (signal)
1245 {
1246 request = acquirePMRequest( this, kIOPMRequestTypeInterestChanged );
1247 if (request)
1248 submitPMRequest( request );
1249 }
1250
1251 // This return value cannot be trusted, but return a value
1252 // for those clients that care.
1253
1254 OUR_PMLog(kPMLogInterestedDriver, kIOPMDeviceUsable, 2);
1255 return kIOPMDeviceUsable;
1256}
1257
1258//*********************************************************************************
1259// [public] deRegisterInterestedDriver
1260//*********************************************************************************
1261
1262IOReturn IOService::deRegisterInterestedDriver ( IOService * driver )
1263{
1264 IOPMinformeeList * list;
1265 IOPMinformee * item;
1266 IOPMRequest * request;
1267 bool signal;
1268
1269 if (!initialized || !fInterestedDrivers)
1270 return IOPMNotPowerManaged;
1271
1272 PM_LOCK();
1273 signal = (!fRemoveInterestSet && !fInsertInterestSet);
1274 if (fRemoveInterestSet == NULL)
1275 fRemoveInterestSet = OSSet::withCapacity(4);
1276 if (fRemoveInterestSet)
1277 {
1278 fRemoveInterestSet->setObject(driver);
1279
1280 list = fInterestedDrivers;
1281 item = list->findItem(driver);
1282 if (item && item->active)
1283 {
1284 item->active = false;
1285 }
1286 if (fLockedFlags.DriverCallBusy)
1287 PM_DEBUG("%s::deRegisterInterestedDriver() driver call busy\n", getName());
1288 }
1289 PM_UNLOCK();
1290
1291 if (signal)
1292 {
1293 request = acquirePMRequest( this, kIOPMRequestTypeInterestChanged );
1294 if (request)
1295 submitPMRequest( request );
1296 }
1297
1298 return IOPMNoErr;
1299}
1300
1301//*********************************************************************************
1302// [private] handleInterestChanged
1303//
1304// Handle interest added or removed.
1305//*********************************************************************************
1306
1307void IOService::handleInterestChanged( IOPMRequest * request )
1308{
1309 IOService * driver;
1310 IOPMinformee * informee;
1311 IOPMinformeeList * list = fInterestedDrivers;
1312
1313 PM_LOCK();
1314
1315 if (fInsertInterestSet)
1316 {
1317 while ((driver = (IOService *) fInsertInterestSet->getAnyObject()))
1318 {
1319 if ((list->findItem(driver) == NULL) &&
1320 (!fRemoveInterestSet ||
1321 !fRemoveInterestSet->containsObject(driver)))
1322 {
1323 informee = list->appendNewInformee(driver);
1324 }
1325 fInsertInterestSet->removeObject(driver);
1326 }
1327 fInsertInterestSet->release();
1328 fInsertInterestSet = 0;
1329 }
1330
1331 if (fRemoveInterestSet)
1332 {
1333 while ((driver = (IOService *) fRemoveInterestSet->getAnyObject()))
1334 {
1335 informee = list->findItem(driver);
1336 if (informee)
1337 {
1338 if (fHeadNotePendingAcks && informee->timer)
1339 {
1340 informee->timer = 0;
1341 fHeadNotePendingAcks--;
1342 }
1343 list->removeFromList(driver);
1344 }
1345 fRemoveInterestSet->removeObject(driver);
1346 }
1347 fRemoveInterestSet->release();
1348 fRemoveInterestSet = 0;
1349 }
1350
1351 PM_UNLOCK();
1352}
1353
1354//*********************************************************************************
1355// [public] acknowledgePowerChange
1356//
1357// After we notified one of the interested drivers or a power-domain child
1358// of an impending change in power, it has called to say it is now
1359// prepared for the change. If this object is the last to
1360// acknowledge this change, we take whatever action we have been waiting
1361// for.
1362// That may include acknowledging to our parent. In this case, we do it
1363// last of all to insure that this doesn't cause the parent to call us some-
1364// where else and alter data we are relying on here (like the very existance
1365// of a "current change note".)
1366//*********************************************************************************
1367
1368IOReturn IOService::acknowledgePowerChange ( IOService * whichObject )
1369{
1370 IOPMRequest * request;
1371
1372 if (!initialized)
1373 return IOPMNotYetInitialized;
1374 if (!whichObject)
1375 return kIOReturnBadArgument;
1376
1377 request = acquirePMRequest( this, kIOPMRequestTypeAckPowerChange );
1378 if (!request)
1379 return kIOReturnNoMemory;
1380
1381 whichObject->retain();
1382 request->fArg0 = whichObject;
1383
1384 submitPMRequest( request );
1385 return IOPMNoErr;
1386}
1387
1388//*********************************************************************************
1389// [private] handleAcknowledgePowerChange
1390//*********************************************************************************
1391
1392bool IOService::handleAcknowledgePowerChange ( IOPMRequest * request )
1393{
1394 IOPMinformee * informee;
1395 unsigned long childPower = kIOPMUnknown;
1396 IOService * theChild;
1397 IOService * whichObject;
1398 bool all_acked = false;
1399
1400 PM_ASSERT_IN_GATE();
1401 whichObject = (IOService *) request->fArg0;
1402 assert(whichObject);
1403
1404 // one of our interested drivers?
1405 informee = fInterestedDrivers->findItem( whichObject );
1406 if ( informee == NULL )
1407 {
1408 if ( !isChild(whichObject, gIOPowerPlane) )
1409 {
1410 OUR_PMLog(kPMLogAcknowledgeErr1, 0, 0);
1411 goto no_err;
1412 } else {
1413 OUR_PMLog(kPMLogChildAcknowledge, fHeadNotePendingAcks, 0);
1414 }
1415 } else {
1416 OUR_PMLog(kPMLogDriverAcknowledge, fHeadNotePendingAcks, 0);
1417 }
1418
1419 if ( fHeadNotePendingAcks != 0 )
1420 {
1421 assert(fPowerStates != NULL);
1422
1423 // yes, make sure we're expecting acks
1424 if ( informee != NULL )
1425 {
1426 // it's an interested driver
1427 // make sure we're expecting this ack
1428 if ( informee->timer != 0 )
1429 {
1430#if LOG_SETPOWER_TIMES
1431 if (informee->timer > 0)
1432 {
1433 uint64_t nsec = computeTimeDeltaNS(&informee->startTime);
1434 if (nsec > LOG_SETPOWER_TIMES)
1435 PM_DEBUG("%s::powerState%sChangeTo(%p, %s, %lu -> %lu) async took %d ms\n",
1436 informee->whatObject->getName(),
1437 (fDriverCallReason == kDriverCallInformPreChange) ? "Will" : "Did",
1438 informee->whatObject,
1439 fName, fCurrentPowerState, fHeadNotePowerState, NS_TO_MS(nsec));
1440 }
1441#endif
1442 // mark it acked
1443 informee->timer = 0;
1444 // that's one fewer to worry about
1445 fHeadNotePendingAcks--;
1446 } else {
1447 // this driver has already acked
1448 OUR_PMLog(kPMLogAcknowledgeErr2, 0, 0);
1449 }
1450 } else {
1451 // it's a child
1452 // make sure we're expecting this ack
1453 if ( ((IOPowerConnection *)whichObject)->getAwaitingAck() )
1454 {
1455 // that's one fewer to worry about
1456 fHeadNotePendingAcks--;
1457 ((IOPowerConnection *)whichObject)->setAwaitingAck(false);
1458 theChild = (IOService *)whichObject->copyChildEntry(gIOPowerPlane);
1459 if ( theChild )
1460 {
1461 childPower = theChild->currentPowerConsumption();
1462 theChild->release();
1463 }
1464 if ( childPower == kIOPMUnknown )
1465 {
1466 fHeadNotePowerArrayEntry->staticPower = kIOPMUnknown;
1467 } else {
1468 if (fHeadNotePowerArrayEntry->staticPower != kIOPMUnknown)
1469 {
1470 fHeadNotePowerArrayEntry->staticPower += childPower;
1471 }
1472 }
1473 }
1474 }
1475
1476 if ( fHeadNotePendingAcks == 0 ) {
1477 // yes, stop the timer
1478 stop_ack_timer();
1479 // and now we can continue
1480 all_acked = true;
1481 }
1482 } else {
1483 OUR_PMLog(kPMLogAcknowledgeErr3, 0, 0); // not expecting anybody to ack
1484 }
1485
1486no_err:
1487 if (whichObject)
1488 whichObject->release();
1489
1490 return all_acked;
1491}
1492
1493//*********************************************************************************
1494// [public] acknowledgeSetPowerState
1495//
1496// After we instructed our controlling driver to change power states,
1497// it has called to say it has finished doing so.
1498// We continue to process the power state change.
1499//*********************************************************************************
1500
1501IOReturn IOService::acknowledgeSetPowerState ( void )
1502{
1503 IOPMRequest * request;
1504
1505 if (!initialized)
1506 return IOPMNotYetInitialized;
1507
1508 request = acquirePMRequest( this, kIOPMRequestTypeAckSetPowerState );
1509 if (!request)
1510 return kIOReturnNoMemory;
1511
1512 submitPMRequest( request );
1513 return kIOReturnSuccess;
1514}
1515
1516//*********************************************************************************
1517// [private] adjustPowerState
1518//*********************************************************************************
1519
1520void IOService::adjustPowerState ( uint32_t clamp )
1521{
1522 PM_ASSERT_IN_GATE();
1523 computeDesiredState(clamp);
1524 if (fControllingDriver && fParentsKnowState && inPlane(gIOPowerPlane))
1525 {
1526 startPowerChange(
1527 /* flags */ kIOPMWeInitiated,
1528 /* power state */ fDesiredPowerState,
1529 /* domain flags */ 0,
1530 /* connection */ 0,
1531 /* parent flags */ 0);
1532 }
1533}
1534
1535//*********************************************************************************
1536// [public] synchronizePowerTree
1537//*********************************************************************************
1538
1539IOReturn IOService::synchronizePowerTree ( void )
1540{
1541 IOPMRequest * request_c;
1542 IOPMRequest * request_s;
1543
1544 if (this != getPMRootDomain())
1545 return kIOReturnBadArgument;
1546 if (!initialized)
1547 return kIOPMNotYetInitialized;
1548
1549 request_c = acquirePMRequest( this, kIOPMRequestTypeIdleCancel );
1550 request_s = acquirePMRequest( this, kIOPMRequestTypeSynchronizePowerTree );
1551
1552 if (!request_c || !request_s)
1553 goto error_no_memory;
1554
1555 request_c->attachNextRequest( request_s );
1556
1557 submitPMRequest(request_c);
1558 submitPMRequest(request_s);
1559
1560 return kIOReturnSuccess;
1561
1562error_no_memory:
1563 if (request_c) releasePMRequest(request_c);
1564 if (request_s) releasePMRequest(request_s);
1565 return kIOReturnNoMemory;
1566}
1567
1568//*********************************************************************************
1569// [private] handleSynchronizePowerTree
1570//*********************************************************************************
1571
1572void IOService::handleSynchronizePowerTree ( IOPMRequest * /*request*/ )
1573{
1574 PM_ASSERT_IN_GATE();
1575 if (fControllingDriver && fParentsKnowState && inPlane(gIOPowerPlane) &&
1576 (fCurrentPowerState == fNumberOfPowerStates - 1))
1577 {
1578 startPowerChange(
1579 /* flags */ kIOPMWeInitiated | kIOPMSynchronize,
1580 /* power state */ fCurrentPowerState,
1581 /* domain flags */ 0,
1582 /* connection */ 0,
1583 /* parent flags */ 0);
1584 }
1585}
1586
1587#ifndef __LP64__
1588//*********************************************************************************
1589// [deprecated] powerDomainWillChangeTo
1590//
1591// Called by the power-hierarchy parent notifying of a new power state
1592// in the power domain.
1593// We enqueue a parent power-change to our queue of power changes.
1594// This may or may not cause us to change power, depending on what
1595// kind of change is occuring in the domain.
1596//*********************************************************************************
1597
1598IOReturn IOService::powerDomainWillChangeTo (
1599 IOPMPowerFlags newPowerFlags,
1600 IOPowerConnection * whichParent )
1601{
1602 assert(false);
1603 return kIOReturnUnsupported;
1604}
1605#endif /* !__LP64__ */
1606
1607//*********************************************************************************
1608// [private] handlePowerDomainWillChangeTo
1609//*********************************************************************************
1610
1611void IOService::handlePowerDomainWillChangeTo ( IOPMRequest * request )
1612{
1613 IOPMPowerFlags parentPowerFlags = (IOPMPowerFlags) request->fArg0;
1614 IOPowerConnection * whichParent = (IOPowerConnection *) request->fArg1;
1615 unsigned long parentChangeFlags = (unsigned long) request->fArg2;
1616 OSIterator * iter;
1617 OSObject * next;
1618 IOPowerConnection * connection;
1619 unsigned long newPowerState;
1620 unsigned long myChangeFlags;
1621 IOPMPowerFlags combinedPowerFlags;
1622 bool savedParentsKnowState;
1623 IOReturn result = IOPMAckImplied;
1624
1625 PM_ASSERT_IN_GATE();
1626 OUR_PMLog(kPMLogWillChange, parentPowerFlags, 0);
1627
1628 if (!inPlane(gIOPowerPlane) || !whichParent || !whichParent->getAwaitingAck())
1629 {
1630 PM_DEBUG("%s::%s not in power tree\n", getName(), __FUNCTION__);
1631 goto exit_no_ack;
1632 }
1633
1634 savedParentsKnowState = fParentsKnowState;
1635
1636 // Combine parents' output power flags.
1637
1638 combinedPowerFlags = 0;
1639
1640 iter = getParentIterator(gIOPowerPlane);
1641 if ( iter )
1642 {
1643 while ( (next = iter->getNextObject()) )
1644 {
1645 if ( (connection = OSDynamicCast(IOPowerConnection, next)) )
1646 {
1647 if ( connection == whichParent )
1648 combinedPowerFlags |= parentPowerFlags;
1649 else
1650 combinedPowerFlags |= connection->parentCurrentPowerFlags();
1651 }
1652 }
1653 iter->release();
1654 }
1655
1656 // If our initial change has yet to occur, then defer the power change
1657 // until after the power domain has completed its power transition.
1658
1659 if ( fControllingDriver && !fInitialChange )
1660 {
1661 newPowerState = fControllingDriver->maxCapabilityForDomainState(
1662 combinedPowerFlags);
1663
1664 // Absorb parent's kIOPMSynchronize flag.
1665 myChangeFlags = kIOPMParentInitiated | kIOPMDomainWillChange |
1666 (parentChangeFlags & kIOPMSynchronize);
1667
1668 result = startPowerChange(
1669 /* flags */ myChangeFlags,
1670 /* power state */ newPowerState,
1671 /* domain flags */ combinedPowerFlags,
1672 /* connection */ whichParent,
1673 /* parent flags */ parentPowerFlags);
1674 }
1675
1676 // If parent is dropping power, immediately update the parent's
1677 // capability flags. Any future merging of parent(s) combined
1678 // power flags should account for this power drop.
1679
1680 if (parentChangeFlags & kIOPMDomainPowerDrop)
1681 {
1682 setParentInfo(parentPowerFlags, whichParent, true);
1683 }
1684
1685 // Parent is expecting an ACK from us. If we did not embark on a state
1686 // transition, i.e. startPowerChange() returned IOPMAckImplied. We are
1687 // still required to issue an ACK to our parent.
1688
1689 if (IOPMAckImplied == result)
1690 {
1691 IOService * parent;
1692 parent = (IOService *) whichParent->copyParentEntry(gIOPowerPlane);
1693 assert(parent);
1694 if ( parent )
1695 {
1696 parent->acknowledgePowerChange( whichParent );
1697 parent->release();
1698 }
1699 }
1700
1701exit_no_ack:
1702 // Drop the retain from notifyChild().
1703 if (whichParent) whichParent->release();
1704}
1705
1706#ifndef __LP64__
1707//*********************************************************************************
1708// [deprecated] powerDomainDidChangeTo
1709//
1710// Called by the power-hierarchy parent after the power state of the power domain
1711// has settled at a new level.
1712// We enqueue a parent power-change to our queue of power changes.
1713// This may or may not cause us to change power, depending on what
1714// kind of change is occuring in the domain.
1715//*********************************************************************************
1716
1717IOReturn IOService::powerDomainDidChangeTo (
1718 IOPMPowerFlags newPowerFlags,
1719 IOPowerConnection * whichParent )
1720{
1721 assert(false);
1722 return kIOReturnUnsupported;
1723}
1724#endif /* !__LP64__ */
1725
1726//*********************************************************************************
1727// [private] handlePowerDomainDidChangeTo
1728//*********************************************************************************
1729
1730void IOService::handlePowerDomainDidChangeTo ( IOPMRequest * request )
1731{
1732 IOPMPowerFlags parentPowerFlags = (IOPMPowerFlags) request->fArg0;
1733 IOPowerConnection * whichParent = (IOPowerConnection *) request->fArg1;
1734 unsigned long parentChangeFlags = (unsigned long) request->fArg2;
1735 unsigned long newPowerState;
1736 unsigned long myChangeFlags;
1737 unsigned long initialDesire;
1738 bool savedParentsKnowState;
1739 IOReturn result = IOPMAckImplied;
1740
1741 PM_ASSERT_IN_GATE();
1742 OUR_PMLog(kPMLogDidChange, parentPowerFlags, 0);
1743
1744 if (!inPlane(gIOPowerPlane) || !whichParent || !whichParent->getAwaitingAck())
1745 {
1746 PM_DEBUG("%s::%s not in power tree\n", getName(), __FUNCTION__);
1747 goto exit_no_ack;
1748 }
1749
1750 savedParentsKnowState = fParentsKnowState;
1751
1752 setParentInfo(parentPowerFlags, whichParent, true);
1753
1754 if ( fControllingDriver )
1755 {
1756 newPowerState = fControllingDriver->maxCapabilityForDomainState(
1757 fParentsCurrentPowerFlags);
1758
1759 if (fInitialChange)
1760 {
1761 initialDesire = fControllingDriver->initialPowerStateForDomainState(
1762 fParentsCurrentPowerFlags);
1763 computeDesiredState(initialDesire);
1764 }
1765
1766 // Absorb parent's kIOPMSynchronize flag.
1767 myChangeFlags = kIOPMParentInitiated | kIOPMDomainDidChange |
1768 (parentChangeFlags & kIOPMSynchronize);
1769
1770 result = startPowerChange(
1771 /* flags */ myChangeFlags,
1772 /* power state */ newPowerState,
1773 /* domain flags */ fParentsCurrentPowerFlags,
1774 /* connection */ whichParent,
1775 /* parent flags */ 0);
1776 }
1777
1778 // Parent is expecting an ACK from us. If we did not embark on a state
1779 // transition, i.e. startPowerChange() returned IOPMAckImplied. We are
1780 // still required to issue an ACK to our parent.
1781
1782 if (IOPMAckImplied == result)
1783 {
1784 IOService * parent;
1785 parent = (IOService *) whichParent->copyParentEntry(gIOPowerPlane);
1786 assert(parent);
1787 if ( parent )
1788 {
1789 parent->acknowledgePowerChange( whichParent );
1790 parent->release();
1791 }
1792 }
1793
1794 // If the parent registers its power driver late, then this is the
1795 // first opportunity to tell our parent about our desire.
1796
1797 if (!savedParentsKnowState && fParentsKnowState)
1798 {
1799 PM_TRACE("%s::powerDomainDidChangeTo parentsKnowState = true\n",
1800 getName());
1801 requestDomainPower( fDesiredPowerState );
1802 }
1803
1804exit_no_ack:
1805 // Drop the retain from notifyChild().
1806 if (whichParent) whichParent->release();
1807}
1808
1809//*********************************************************************************
1810// [private] setParentInfo
1811//
1812// Set our connection data for one specific parent, and then combine all the parent
1813// data together.
1814//*********************************************************************************
1815
1816void IOService::setParentInfo (
1817 IOPMPowerFlags newPowerFlags,
1818 IOPowerConnection * whichParent,
1819 bool knowsState )
1820{
1821 OSIterator * iter;
1822 OSObject * next;
1823 IOPowerConnection * conn;
1824
1825 PM_ASSERT_IN_GATE();
1826
1827 // set our connection data
1828 whichParent->setParentCurrentPowerFlags(newPowerFlags);
1829 whichParent->setParentKnowsState(knowsState);
1830
1831 // recompute our parent info
1832 fParentsCurrentPowerFlags = 0;
1833 fParentsKnowState = true;
1834
1835 iter = getParentIterator(gIOPowerPlane);
1836 if ( iter )
1837 {
1838 while ( (next = iter->getNextObject()) )
1839 {
1840 if ( (conn = OSDynamicCast(IOPowerConnection, next)) )
1841 {
1842 fParentsKnowState &= conn->parentKnowsState();
1843 fParentsCurrentPowerFlags |= conn->parentCurrentPowerFlags();
1844 }
1845 }
1846 iter->release();
1847 }
1848}
1849
1850//*********************************************************************************
1851// [private] rebuildChildClampBits
1852//
1853// The ChildClamp bits (kIOPMChildClamp & kIOPMChildClamp2) in our capabilityFlags
1854// indicate that one of our children (or grandchildren or great-grandchildren ...)
1855// doesn't support idle or system sleep in its current state. Since we don't track
1856// the origin of each bit, every time any child changes state we have to clear
1857// these bits and rebuild them.
1858//*********************************************************************************
1859
1860void IOService::rebuildChildClampBits ( void )
1861{
1862 unsigned long i;
1863 OSIterator * iter;
1864 OSObject * next;
1865 IOPowerConnection * connection;
1866 unsigned long powerState;
1867
1868 // A child's desires has changed. We need to rebuild the child-clamp bits in
1869 // our power state array. Start by clearing the bits in each power state.
1870
1871 for ( i = 0; i < fNumberOfPowerStates; i++ )
1872 {
1873 fPowerStates[i].capabilityFlags &= ~(kIOPMChildClamp | kIOPMChildClamp2);
1874 }
1875
1876 if (!inPlane(gIOPowerPlane))
1877 return;
1878
1879 // Loop through the children. When we encounter the calling child, save the
1880 // computed state as this child's desire. And set the ChildClamp bits in any
1881 // of our states that some child has clamp on.
1882
1883 iter = getChildIterator(gIOPowerPlane);
1884 if ( iter )
1885 {
1886 while ( (next = iter->getNextObject()) )
1887 {
1888 if ( (connection = OSDynamicCast(IOPowerConnection, next)) )
1889 {
1890 if (connection->getReadyFlag() == false)
1891 {
1892 PM_CONNECT("[%s] %s: connection not ready\n",
1893 getName(), __FUNCTION__);
1894 continue;
1895 }
1896
1897 powerState = connection->getDesiredDomainState();
1898 if (powerState < fNumberOfPowerStates)
1899 {
1900 if ( connection->getPreventIdleSleepFlag() )
1901 fPowerStates[powerState].capabilityFlags |= kIOPMChildClamp;
1902 if ( connection->getPreventSystemSleepFlag() )
1903 fPowerStates[powerState].capabilityFlags |= kIOPMChildClamp2;
1904 }
1905 }
1906 }
1907 iter->release();
1908 }
1909}
1910
1911//*********************************************************************************
1912// [public] requestPowerDomainState
1913//
1914// Called on a power parent when a child's power requirement changes.
1915//*********************************************************************************
1916
1917IOReturn IOService::requestPowerDomainState(
1918 IOPMPowerFlags childRequestPowerFlags,
1919 IOPowerConnection * childConnection,
1920 unsigned long specification )
1921{
1922 unsigned long ps;
1923 IOPMPowerFlags outputPowerFlags;
1924 IOService * child;
1925 IOPMRequest * subRequest;
1926 bool preventIdle, preventSleep;
1927 bool adjustPower = false;
1928
1929 if (!initialized)
1930 return IOPMNotYetInitialized;
1931
1932 if (gIOPMWorkLoop->onThread() == false)
1933 {
1934 PM_DEBUG("%s::requestPowerDomainState\n", getName());
1935 return kIOReturnSuccess;
1936 }
1937
1938 OUR_PMLog(kPMLogRequestDomain, childRequestPowerFlags, specification);
1939
1940 if (!isChild(childConnection, gIOPowerPlane))
1941 return kIOReturnNotAttached;
1942
1943 if (!fControllingDriver || !fNumberOfPowerStates)
1944 return IOPMNotYetInitialized;
1945
1946 child = (IOService *) childConnection->getChildEntry(gIOPowerPlane);
1947 assert(child);
1948
1949 preventIdle = ((childRequestPowerFlags & kIOPMPreventIdleSleep) != 0);
1950 preventSleep = ((childRequestPowerFlags & kIOPMPreventSystemSleep) != 0);
1951 childRequestPowerFlags &= ~(kIOPMPreventIdleSleep | kIOPMPreventSystemSleep);
1952
1953 // Merge in the power flags contributed by this power parent
1954 // at its current or impending power state.
1955
1956 outputPowerFlags = fPowerStates[fCurrentPowerState].outputPowerCharacter;
1957 if (fMachineState != kIOPM_Finished)
1958 {
1959 if (IS_POWER_DROP && (getPMRootDomain() != this))
1960 {
1961 // Use the lower power state when dropping power.
1962 // Must be careful since a power drop can be canceled
1963 // from the following states:
1964 // - kIOPM_OurChangeTellClientsPowerDown
1965 // - kIOPM_OurChangeTellPriorityClientsPowerDown
1966 //
1967 // The child must not wait for this parent to raise power
1968 // if the power drop was cancelled. The solution is to cancel
1969 // the power drop if possible, then schedule an adjustment to
1970 // re-evaluate our correct power state.
1971 //
1972 // Root domain is excluded to avoid idle sleep issues. And permit
1973 // root domain children to pop up when system is going to sleep.
1974
1975 if ((fMachineState == kIOPM_OurChangeTellClientsPowerDown) ||
1976 (fMachineState == kIOPM_OurChangeTellPriorityClientsPowerDown))
1977 {
1978 fDoNotPowerDown = true; // cancel power drop
1979 adjustPower = true; // schedule an adjustment
1980 PM_TRACE("%s: power drop cancelled in state %u by %s\n",
1981 getName(), fMachineState, child->getName());
1982 }
1983 else
1984 {
1985 // Beyond cancellation point, report the impending state.
1986 outputPowerFlags =
1987 fPowerStates[fHeadNotePowerState].outputPowerCharacter;
1988 }
1989 }
1990 else if (IS_POWER_RISE)
1991 {
1992 // When raising power, must report the output power flags from
1993 // child's perspective. A child power request may arrive while
1994 // parent is transitioning upwards. If a request arrives after
1995 // setParentInfo() has already recorded the output power flags
1996 // for the next power state, then using the power supplied by
1997 // fCurrentPowerState is incorrect, and might cause the child
1998 // to wait when it should not.
1999
2000 outputPowerFlags = childConnection->parentCurrentPowerFlags();
2001 }
2002 }
2003 child->fHeadNoteDomainTargetFlags |= outputPowerFlags;
2004
2005 // Map child's requested power flags to one of our power state.
2006
2007 for (ps = 0; ps < fNumberOfPowerStates; ps++)
2008 {
2009 if ((fPowerStates[ps].outputPowerCharacter & childRequestPowerFlags) ==
2010 (fOutputPowerCharacterFlags & childRequestPowerFlags))
2011 break;
2012 }
2013 if (ps >= fNumberOfPowerStates)
2014 {
2015 ps = 0; // should never happen
2016 }
2017
2018 // Conditions that warrants a power adjustment on this parent.
2019 // Adjust power will also propagate any changes to the child's
2020 // prevent idle/sleep flags towards the root domain.
2021
2022 if (!childConnection->childHasRequestedPower() ||
2023 (ps != childConnection->getDesiredDomainState()) ||
2024 (childConnection->getPreventIdleSleepFlag() != preventIdle) ||
2025 (childConnection->getPreventSystemSleepFlag() != preventSleep))
2026 adjustPower = true;
2027
2028#if ENABLE_DEBUG_LOGS
2029 if (adjustPower)
2030 {
2031 PM_DEBUG("requestPowerDomainState[%s]: %s, init %d, %u->%u\n",
2032 getName(), child->getName(),
2033 !childConnection->childHasRequestedPower(),
2034 (uint32_t) childConnection->getDesiredDomainState(),
2035 (uint32_t) ps);
2036 }
2037#endif
2038
2039 // Record the child's desires on the connection.
2040#if SUPPORT_IDLE_CANCEL
2041 bool attemptCancel = (preventIdle && !childConnection->getPreventIdleSleepFlag());
2042#endif
2043 childConnection->setChildHasRequestedPower();
2044 childConnection->setDesiredDomainState( ps );
2045 childConnection->setPreventIdleSleepFlag( preventIdle );
2046 childConnection->setPreventSystemSleepFlag( preventSleep );
2047
2048 // Schedule a request to re-evaluate all children desires and
2049 // adjust power state. Submit a request if one wasn't pending,
2050 // or if the current request is part of a call tree.
2051
2052 if (adjustPower && !fDeviceOverrides &&
2053 (!fAdjustPowerScheduled || gIOPMRequest->getRootRequest()))
2054 {
2055 subRequest = acquirePMRequest(
2056 this, kIOPMRequestTypeAdjustPowerState, gIOPMRequest );
2057 if (subRequest)
2058 {
2059 submitPMRequest( subRequest );
2060 fAdjustPowerScheduled = true;
2061 }
2062 }
2063
2064#if SUPPORT_IDLE_CANCEL
2065 if (attemptCancel)
2066 {
2067 subRequest = acquirePMRequest( this, kIOPMRequestTypeIdleCancel );
2068 if (subRequest)
2069 {
2070 submitPMRequest( subRequest );
2071 }
2072 }
2073#endif
2074
2075 return kIOReturnSuccess;
2076}
2077
2078//*********************************************************************************
2079// [public] temporaryPowerClampOn
2080//
2081// A power domain wants to clamp its power on till it has children which
2082// will thendetermine the power domain state.
2083//
2084// We enter the highest state until addPowerChild is called.
2085//*********************************************************************************
2086
2087IOReturn IOService::temporaryPowerClampOn ( void )
2088{
2089 return requestPowerState( gIOPMPowerClientChildProxy, kIOPMPowerStateMax );
2090}
2091
2092//*********************************************************************************
2093// [public] makeUsable
2094//
2095// Some client of our device is asking that we become usable. Although
2096// this has not come from a subclassed device object, treat it exactly
2097// as if it had. In this way, subsequent requests for lower power from
2098// a subclassed device object will pre-empt this request.
2099//
2100// We treat this as a subclass object request to switch to the
2101// highest power state.
2102//*********************************************************************************
2103
2104IOReturn IOService::makeUsable ( void )
2105{
2106 OUR_PMLog(kPMLogMakeUsable, 0, 0);
2107 return requestPowerState( gIOPMPowerClientDevice, kIOPMPowerStateMax );
2108}
2109
2110//*********************************************************************************
2111// [public] currentCapability
2112//*********************************************************************************
2113
2114IOPMPowerFlags IOService::currentCapability ( void )
2115{
2116 if (!initialized)
2117 return IOPMNotPowerManaged;
2118
2119 return fCurrentCapabilityFlags;
2120}
2121
2122//*********************************************************************************
2123// [public] changePowerStateTo
2124//
2125// Called by our power-controlling driver to change power state. The new desired
2126// power state is computed and compared against the current power state. If those
2127// power states differ, then a power state change is initiated.
2128//*********************************************************************************
2129
2130IOReturn IOService::changePowerStateTo ( unsigned long ordinal )
2131{
2132 OUR_PMLog(kPMLogChangeStateTo, ordinal, 0);
2133 return requestPowerState( gIOPMPowerClientDriver, ordinal );
2134}
2135
2136//*********************************************************************************
2137// [protected] changePowerStateToPriv
2138//
2139// Called by our driver subclass to change power state. The new desired power
2140// state is computed and compared against the current power state. If those
2141// power states differ, then a power state change is initiated.
2142//*********************************************************************************
2143
2144IOReturn IOService::changePowerStateToPriv ( unsigned long ordinal )
2145{
2146 OUR_PMLog(kPMLogChangeStateToPriv, ordinal, 0);
2147 return requestPowerState( gIOPMPowerClientDevice, ordinal );
2148}
2149
2150//*********************************************************************************
2151// [protected] changePowerStateWithOverrideTo
2152//
2153// Called by our driver subclass to change power state. The new desired power
2154// state is computed and compared against the current power state. If those
2155// power states differ, then a power state change is initiated.
2156// Override enforced - Children and Driver desires are ignored.
2157//*********************************************************************************
2158
2159IOReturn IOService::changePowerStateWithOverrideTo ( unsigned long ordinal )
2160{
2161 IOPMRequest * request;
2162
2163 if (!initialized)
2164 return kIOPMNotYetInitialized;
2165
2166 OUR_PMLog(kPMLogChangeStateToPriv, ordinal, 0);
2167
2168 request = acquirePMRequest( this, kIOPMRequestTypeRequestPowerStateOverride );
2169 if (!request)
2170 return kIOReturnNoMemory;
2171
2172 gIOPMPowerClientDevice->retain();
2173 request->fArg0 = (void *) ordinal;
2174 request->fArg1 = (void *) gIOPMPowerClientDevice;
2175 request->fArg2 = 0;
2176#if NOT_READY
2177 if (action)
2178 request->installCompletionAction( action, target, param );
2179#endif
2180
2181 // Prevent needless downwards power transitions by clamping power
2182 // until the scheduled request is executed.
2183
2184 if (gIOPMWorkLoop->inGate() && (ordinal < fNumberOfPowerStates))
2185 {
2186 fTempClampPowerState = max(fTempClampPowerState, ordinal);
2187 fTempClampCount++;
2188 fOverrideMaxPowerState = ordinal;
2189 request->fArg2 = (void *) true;
2190 }
2191
2192 submitPMRequest( request );
2193 return IOPMNoErr;
2194}
2195
2196//*********************************************************************************
2197// [private] requestPowerState
2198//*********************************************************************************
2199
2200IOReturn IOService::requestPowerState (
2201 const OSSymbol * client,
2202 uint32_t state )
2203{
2204 IOPMRequest * request;
2205
2206 if (!client)
2207 return kIOReturnBadArgument;
2208 if (!initialized)
2209 return kIOPMNotYetInitialized;
2210
2211 request = acquirePMRequest( this, kIOPMRequestTypeRequestPowerState );
2212 if (!request)
2213 return kIOReturnNoMemory;
2214
2215 client->retain();
2216 request->fArg0 = (void *) state;
2217 request->fArg1 = (void *) client;
2218 request->fArg2 = 0;
2219#if NOT_READY
2220 if (action)
2221 request->installCompletionAction( action, target, param );
2222#endif
2223
2224 // Prevent needless downwards power transitions by clamping power
2225 // until the scheduled request is executed.
2226
2227 if (gIOPMWorkLoop->inGate() && (state < fNumberOfPowerStates))
2228 {
2229 fTempClampPowerState = max(fTempClampPowerState, state);
2230 fTempClampCount++;
2231 request->fArg2 = (void *) true;
2232 }
2233
2234 submitPMRequest( request );
2235 return IOPMNoErr;
2236}
2237
2238//*********************************************************************************
2239// [private] handleRequestPowerState
2240//*********************************************************************************
2241
2242void IOService::handleRequestPowerState ( IOPMRequest * request )
2243{
2244 const OSSymbol * client = (const OSSymbol *) request->fArg1;
2245 uint32_t state = (uint32_t)(uintptr_t) request->fArg0;
2246
2247 PM_ASSERT_IN_GATE();
2248 if (request->fArg2)
2249 {
2250 assert(fTempClampCount != 0);
2251 if (fTempClampCount) fTempClampCount--;
2252 if (!fTempClampCount) fTempClampPowerState = 0;
2253 }
2254
2255 if (fNumberOfPowerStates && (state >= fNumberOfPowerStates))
2256 state = fNumberOfPowerStates - 1;
2257
2258 // Override from changePowerStateWithOverrideTo() persists until
2259 // the next "device" power request, such as changePowerStateToPriv().
2260
2261 if ((getPMRequestType() != kIOPMRequestTypeRequestPowerStateOverride) &&
2262 (client == gIOPMPowerClientDevice))
2263 fOverrideMaxPowerState = kIOPMPowerStateMax;
2264
2265 if ((state == 0) &&
2266 (client != gIOPMPowerClientDevice) &&
2267 (client != gIOPMPowerClientDriver) &&
2268 (client != gIOPMPowerClientChildProxy))
2269 removePowerClient(client);
2270 else
2271 updatePowerClient(client, state);
2272
2273 adjustPowerState();
2274 client->release();
2275}
2276
2277//*********************************************************************************
2278// [private] Helper functions to update/remove power clients.
2279//*********************************************************************************
2280
2281void IOService::updatePowerClient( const OSSymbol * client, uint32_t powerState )
2282{
2283 if (!fPowerClients)
2284 fPowerClients = OSDictionary::withCapacity(4);
2285 if (fPowerClients && client)
2286 {
2287 OSNumber * num = (OSNumber *) fPowerClients->getObject(client);
2288 if (num)
2289 num->setValue(powerState);
2290 else
2291 {
2292 num = OSNumber::withNumber(powerState, 32);
2293 if (num)
2294 {
2295 fPowerClients->setObject(client, num);
2296 num->release();
2297 }
2298 }
2299 }
2300}
2301
2302void IOService::removePowerClient( const OSSymbol * client )
2303{
2304 if (fPowerClients && client)
2305 fPowerClients->removeObject(client);
2306}
2307
2308uint32_t IOService::getPowerStateForClient( const OSSymbol * client )
2309{
2310 uint32_t powerState = 0;
2311
2312 if (fPowerClients && client)
2313 {
2314 OSNumber * num = (OSNumber *) fPowerClients->getObject(client);
2315 if (num) powerState = num->unsigned32BitValue();
2316 }
2317 return powerState;
2318}
2319
2320//*********************************************************************************
2321// [private] computeDesiredState
2322//*********************************************************************************
2323
2324void IOService::computeDesiredState ( unsigned long localClamp )
2325{
2326 OSIterator * iter;
2327 OSObject * next;
2328 IOPowerConnection * connection;
2329 uint32_t desiredState = 0;
2330 uint32_t newPowerState = 0;
2331 bool hasChildren = false;
2332
2333 // Desired power state is always 0 without a controlling driver.
2334
2335 if (!fNumberOfPowerStates)
2336 {
2337 fDesiredPowerState = 0;
2338 //PM_DEBUG("%s::%s no controlling driver\n", getName(), __FUNCTION__);
2339 return;
2340 }
2341
2342 // Examine the children's desired power state.
2343
2344 iter = getChildIterator(gIOPowerPlane);
2345 if (iter)
2346 {
2347 while ((next = iter->getNextObject()))
2348 {
2349 if ((connection = OSDynamicCast(IOPowerConnection, next)))
2350 {
2351 if (connection->getReadyFlag() == false)
2352 {
2353 PM_CONNECT("[%s] %s: connection not ready\n",
2354 getName(), __FUNCTION__);
2355 continue;
2356 }
2357 if (connection->childHasRequestedPower())
2358 hasChildren = true;
2359 if (connection->getDesiredDomainState() > desiredState)
2360 desiredState = connection->getDesiredDomainState();
2361 }
2362 }
2363 iter->release();
2364 }
2365 if (hasChildren)
2366 updatePowerClient(gIOPMPowerClientChildren, desiredState);
2367 else
2368 removePowerClient(gIOPMPowerClientChildren);
2369
2370 // Iterate through all power clients to determine the min power state.
2371
2372 iter = OSCollectionIterator::withCollection(fPowerClients);
2373 if (iter)
2374 {
2375 const OSSymbol * client;
2376 while ((client = (const OSSymbol *) iter->getNextObject()))
2377 {
2378 // Ignore child and driver when override is in effect.
2379 if ((fDeviceOverrides ||
2380 (getPMRequestType() == kIOPMRequestTypeRequestPowerStateOverride)) &&
2381 ((client == gIOPMPowerClientChildren) ||
2382 (client == gIOPMPowerClientDriver)))
2383 continue;
2384
2385 // Ignore child proxy when children are present.
2386 if (hasChildren && (client == gIOPMPowerClientChildProxy))
2387 continue;
2388
2389 desiredState = getPowerStateForClient(client);
2390 assert(desiredState < fNumberOfPowerStates);
2391 PM_TRACE(" %u %s\n",
2392 desiredState, client->getCStringNoCopy());
2393
2394 newPowerState = max(newPowerState, desiredState);
2395
2396 if (client == gIOPMPowerClientDevice)
2397 fDeviceDesire = desiredState;
2398 }
2399 iter->release();
2400 }
2401
2402 // Factor in the temporary power desires.
2403
2404 newPowerState = max(newPowerState, localClamp);
2405 newPowerState = max(newPowerState, fTempClampPowerState);
2406
2407 // Limit check against max power override.
2408
2409 newPowerState = min(newPowerState, fOverrideMaxPowerState);
2410
2411 // Limit check against number of power states.
2412
2413 if (newPowerState >= fNumberOfPowerStates)
2414 newPowerState = fNumberOfPowerStates - 1;
2415
2416 fDesiredPowerState = newPowerState;
2417
2418 PM_TRACE(" temp %u, clamp %u, current %u, new %u\n",
2419 (uint32_t) localClamp, (uint32_t) fTempClampPowerState,
2420 (uint32_t) fCurrentPowerState, newPowerState);
2421
2422 // Restart idle timer if stopped and device desire has increased.
2423
2424 if (fDeviceDesire && fIdleTimerStopped)
2425 {
2426 fIdleTimerStopped = false;
2427 fActivityTickleCount = 0;
2428 clock_get_uptime(&fIdleTimerStartTime);
2429 start_PM_idle_timer();
2430 }
2431
2432 // Invalidate cached tickle power state when desires change, and not
2433 // due to a tickle request. This invalidation must occur before the
2434 // power state change to minimize races. We want to err on the side
2435 // of servicing more activity tickles rather than dropping one when
2436 // the device is in a low power state.
2437
2438 if ((getPMRequestType() != kIOPMRequestTypeActivityTickle) &&
2439 (fActivityTicklePowerState != -1))
2440 {
2441 IOLockLock(fActivityLock);
2442 fActivityTicklePowerState = -1;
2443 IOLockUnlock(fActivityLock);
2444 }
2445}
2446
2447//*********************************************************************************
2448// [public] currentPowerConsumption
2449//
2450//*********************************************************************************
2451
2452unsigned long IOService::currentPowerConsumption ( void )
2453{
2454 if (!initialized)
2455 return kIOPMUnknown;
2456
2457 return fCurrentPowerConsumption;
2458}
2459
2460//*********************************************************************************
2461// [deprecated] getPMworkloop
2462//*********************************************************************************
2463
2464IOWorkLoop * IOService::getPMworkloop ( void )
2465{
2466 return gIOPMWorkLoop;
2467}
2468
2469//*********************************************************************************
2470// [public] activityTickle
2471//
2472// The tickle with parameter kIOPMSuperclassPolicy1 causes the activity
2473// flag to be set, and the device state checked. If the device has been
2474// powered down, it is powered up again.
2475// The tickle with parameter kIOPMSubclassPolicy is ignored here and
2476// should be intercepted by a subclass.
2477//*********************************************************************************
2478
2479bool IOService::activityTickle ( unsigned long type, unsigned long stateNumber )
2480{
2481 IOPMRequest * request;
2482 bool noPowerChange = true;
2483
2484 if ( initialized && stateNumber && (type == kIOPMSuperclassPolicy1) )
2485 {
2486 IOLockLock(fActivityLock);
2487
2488 // Record device activity for the idle timer handler.
2489
2490 fDeviceActive = true;
2491 fActivityTickleCount++;
2492 clock_get_uptime(&fDeviceActiveTimestamp);
2493
2494#if ROOT_DOMAIN_RUN_STATES
2495 getPMRootDomain()->handleActivityTickleForService(this, type,
2496 fCurrentPowerState, fActivityTickleCount);
2497#endif
2498
2499 // Record the last tickle power state.
2500 // This helps to filter out redundant tickles as
2501 // this function may be called from the data path.
2502
2503 if (fActivityTicklePowerState < (long)stateNumber)
2504 {
2505 fActivityTicklePowerState = stateNumber;
2506 noPowerChange = false;
2507
2508 request = acquirePMRequest( this, kIOPMRequestTypeActivityTickle );
2509 if (request)
2510 {
2511 request->fArg0 = (void *) stateNumber; // power state
2512 request->fArg1 = (void *) true; // power rise
2513 submitPMRequest(request);
2514 }
2515 }
2516
2517 IOLockUnlock(fActivityLock);
2518 }
2519
2520 // Returns false if the activityTickle might cause a transition to a
2521 // higher powered state, true otherwise.
2522
2523 return noPowerChange;
2524}
2525
2526//*********************************************************************************
2527// [private] handleActivityTickle
2528//*********************************************************************************
2529
2530void IOService::handleActivityTickle ( IOPMRequest * request )
2531{
2532 uint32_t ticklePowerState = (uint32_t)(uintptr_t) request->fArg0;
2533 bool adjustPower = false;
2534
2535 PM_ASSERT_IN_GATE();
2536 if (request->fArg1)
2537 {
2538 // Power rise from activity tickle.
2539 if ((ticklePowerState > fDeviceDesire) &&
2540 (ticklePowerState < fNumberOfPowerStates))
2541 {
2542 fIdleTimerMinPowerState = ticklePowerState;
2543 adjustPower = true;
2544 }
2545 }
2546 else if (fDeviceDesire > fIdleTimerMinPowerState)
2547 {
2548 // Power drop due to idle timer expiration.
2549 // Do not allow idle timer to reduce power below tickle power.
2550 ticklePowerState = fDeviceDesire - 1;
2551 adjustPower = true;
2552 }
2553
2554 if (adjustPower)
2555 {
2556 updatePowerClient(gIOPMPowerClientDevice, ticklePowerState);
2557 adjustPowerState();
2558 }
2559}
2560
2561//*********************************************************************************
2562// [public] setIdleTimerPeriod
2563//
2564// A subclass policy-maker is going to use our standard idleness
2565// detection service. Make a command queue and an idle timer and
2566// connect them to the power management workloop. Finally,
2567// start the timer.
2568//*********************************************************************************
2569
2570IOReturn IOService::setIdleTimerPeriod ( unsigned long period )
2571{
2572 if (!initialized)
2573 return IOPMNotYetInitialized;
2574
2575 OUR_PMLog(kPMLogSetIdleTimerPeriod, period, 0);
2576
2577 IOPMRequest * request =
2578 acquirePMRequest( this, kIOPMRequestTypeSetIdleTimerPeriod );
2579 if (!request)
2580 return kIOReturnNoMemory;
2581
2582 request->fArg0 = (void *) period;
2583 submitPMRequest( request );
2584
2585 return IOPMNoErr;
2586}
2587
2588//******************************************************************************
2589// [public] nextIdleTimeout
2590//
2591// Returns how many "seconds from now" the device should idle into its
2592// next lowest power state.
2593//******************************************************************************
2594
2595SInt32 IOService::nextIdleTimeout(
2596 AbsoluteTime currentTime,
2597 AbsoluteTime lastActivity,
2598 unsigned int powerState)
2599{
2600 AbsoluteTime delta;
2601 UInt64 delta_ns;
2602 SInt32 delta_secs;
2603 SInt32 delay_secs;
2604
2605 // Calculate time difference using funky macro from clock.h.
2606 delta = currentTime;
2607 SUB_ABSOLUTETIME(&delta, &lastActivity);
2608
2609 // Figure it in seconds.
2610 absolutetime_to_nanoseconds(delta, &delta_ns);
2611 delta_secs = (SInt32)(delta_ns / NSEC_PER_SEC);
2612
2613 // Be paranoid about delta somehow exceeding timer period.
2614 if (delta_secs < (int) fIdleTimerPeriod)
2615 delay_secs = (int) fIdleTimerPeriod - delta_secs;
2616 else
2617 delay_secs = (int) fIdleTimerPeriod;
2618
2619 return (SInt32)delay_secs;
2620}
2621
2622//******************************************************************************
2623// [public] start_PM_idle_timer
2624//
2625// The parameter is a pointer to us. Use it to call our timeout method.
2626//******************************************************************************
2627
2628void IOService::start_PM_idle_timer ( void )
2629{
2630 static const int maxTimeout = 100000;
2631 static const int minTimeout = 1;
2632 AbsoluteTime uptime;
2633 SInt32 idle_in = 0;
2634
2635 if (!initialized || !fIdleTimerPeriod || !fIdleTimerEventSource)
2636 return;
2637
2638 IOLockLock(fActivityLock);
2639
2640 clock_get_uptime(&uptime);
2641
2642 // Subclasses may modify idle sleep algorithm
2643 idle_in = nextIdleTimeout(uptime, fDeviceActiveTimestamp, fCurrentPowerState);
2644
2645 // Check for out-of range responses
2646 if (idle_in > maxTimeout)
2647 {
2648 // use standard implementation
2649 idle_in = IOService::nextIdleTimeout(uptime,
2650 fDeviceActiveTimestamp,
2651 fCurrentPowerState);
2652 } else if (idle_in < minTimeout) {
2653 idle_in = fIdleTimerPeriod;
2654 }
2655
2656 IOLockUnlock(fActivityLock);
2657
2658 fIdleTimerEventSource->setTimeout(idle_in, NSEC_PER_SEC);
2659}
2660
2661//*********************************************************************************
2662// [private] idleTimerExpired
2663//
2664// The idle timer has expired. If there has been activity since the last
2665// expiration, just restart the timer and return. If there has not been
2666// activity, switch to the next lower power state and restart the timer.
2667//*********************************************************************************
2668
2669void IOService::idleTimerExpired( IOTimerEventSource * )
2670{
2671 IOPMRequest * request;
2672 bool restartTimer = true;
2673
2674 if ( !initialized || !fIdleTimerPeriod || fLockedFlags.PMStop )
2675 return;
2676
2677 IOLockLock(fActivityLock);
2678
2679 // Check for device activity (tickles) over last timer period.
2680
2681 if (fDeviceActive)
2682 {
2683 // Device was active - do not drop power, restart timer.
2684 fDeviceActive = false;
2685 }
2686 else
2687 {
2688 // No device activity - drop power state by one level.
2689 // Decrement the cached tickle power state when possible.
2690 // This value may be (-1) before activityTickle() is called,
2691 // but the power drop request must be issued regardless.
2692
2693 if (fActivityTicklePowerState > 0)
2694 {
2695 fActivityTicklePowerState--;
2696 }
2697
2698 request = acquirePMRequest( this, kIOPMRequestTypeActivityTickle );
2699 if (request)
2700 {
2701 request->fArg0 = (void *) 0; // power state (irrelevant)
2702 request->fArg1 = (void *) false; // power drop
2703 submitPMRequest( request );
2704
2705 // Do not restart timer until after the tickle request has been
2706 // processed.
2707
2708 restartTimer = false;
2709 }
2710 }
2711
2712 IOLockUnlock(fActivityLock);
2713
2714 if (restartTimer)
2715 start_PM_idle_timer();
2716}
2717
2718#ifndef __LP64__
2719//*********************************************************************************
2720// [deprecated] PM_idle_timer_expiration
2721//*********************************************************************************
2722
2723void IOService::PM_idle_timer_expiration ( void )
2724{
2725}
2726
2727//*********************************************************************************
2728// [deprecated] command_received
2729//*********************************************************************************
2730
2731void IOService::command_received ( void *statePtr , void *, void * , void * )
2732{
2733}
2734#endif /* !__LP64__ */
2735
2736//*********************************************************************************
2737// [public] setAggressiveness
2738//
2739// Pass on the input parameters to all power domain children. All those which are
2740// power domains will pass it on to their children, etc.
2741//*********************************************************************************
2742
2743IOReturn IOService::setAggressiveness ( unsigned long type, unsigned long newLevel )
2744{
2745 return kIOReturnSuccess;
2746}
2747
2748//*********************************************************************************
2749// [public] getAggressiveness
2750//
2751// Called by the user client.
2752//*********************************************************************************
2753
2754IOReturn IOService::getAggressiveness ( unsigned long type, unsigned long * currentLevel )
2755{
2756 IOPMrootDomain * rootDomain = getPMRootDomain();
2757
2758 if (!rootDomain)
2759 return kIOReturnNotReady;
2760
2761 return rootDomain->getAggressiveness( type, currentLevel );
2762}
2763
2764//*********************************************************************************
2765// [public] getPowerState
2766//
2767//*********************************************************************************
2768
2769UInt32 IOService::getPowerState ( void )
2770{
2771 if (!initialized)
2772 return 0;
2773
2774 return fCurrentPowerState;
2775}
2776
2777#ifndef __LP64__
2778//*********************************************************************************
2779// [deprecated] systemWake
2780//
2781// Pass this to all power domain children. All those which are
2782// power domains will pass it on to their children, etc.
2783//*********************************************************************************
2784
2785IOReturn IOService::systemWake ( void )
2786{
2787 OSIterator * iter;
2788 OSObject * next;
2789 IOPowerConnection * connection;
2790 IOService * theChild;
2791
2792 iter = getChildIterator(gIOPowerPlane);
2793 if ( iter )
2794 {
2795 while ( (next = iter->getNextObject()) )
2796 {
2797 if ( (connection = OSDynamicCast(IOPowerConnection, next)) )
2798 {
2799 if (connection->getReadyFlag() == false)
2800 {
2801 PM_CONNECT("[%s] %s: connection not ready\n",
2802 getName(), __FUNCTION__);
2803 continue;
2804 }
2805
2806 theChild = (IOService *)connection->copyChildEntry(gIOPowerPlane);
2807 if ( theChild )
2808 {
2809 theChild->systemWake();
2810 theChild->release();
2811 }
2812 }
2813 }
2814 iter->release();
2815 }
2816
2817 if ( fControllingDriver != NULL )
2818 {
2819 if ( fControllingDriver->didYouWakeSystem() )
2820 {
2821 makeUsable();
2822 }
2823 }
2824
2825 return IOPMNoErr;
2826}
2827
2828//*********************************************************************************
2829// [deprecated] temperatureCriticalForZone
2830//*********************************************************************************
2831
2832IOReturn IOService::temperatureCriticalForZone ( IOService * whichZone )
2833{
2834 IOService * theParent;
2835 IOService * theNub;
2836
2837 OUR_PMLog(kPMLogCriticalTemp, 0, 0);
2838
2839 if ( inPlane(gIOPowerPlane) && !IS_PM_ROOT() )
2840 {
2841 theNub = (IOService *)copyParentEntry(gIOPowerPlane);
2842 if ( theNub )
2843 {
2844 theParent = (IOService *)theNub->copyParentEntry(gIOPowerPlane);
2845 theNub->release();
2846 if ( theParent )
2847 {
2848 theParent->temperatureCriticalForZone(whichZone);
2849 theParent->release();
2850 }
2851 }
2852 }
2853 return IOPMNoErr;
2854}
2855#endif /* !__LP64__ */
2856
2857//*********************************************************************************
2858// [protected] powerOverrideOnPriv
2859//*********************************************************************************
2860
2861IOReturn IOService::powerOverrideOnPriv ( void )
2862{
2863 IOPMRequest * request;
2864
2865 if (!initialized)
2866 return IOPMNotYetInitialized;
2867
2868 if (gIOPMWorkLoop->inGate())
2869 {
2870 fDeviceOverrides = true;
2871 return IOPMNoErr;
2872 }
2873
2874 request = acquirePMRequest( this, kIOPMRequestTypePowerOverrideOnPriv );
2875 if (!request)
2876 return kIOReturnNoMemory;
2877
2878 submitPMRequest( request );
2879 return IOPMNoErr;
2880}
2881
2882//*********************************************************************************
2883// [protected] powerOverrideOffPriv
2884//*********************************************************************************
2885
2886IOReturn IOService::powerOverrideOffPriv ( void )
2887{
2888 IOPMRequest * request;
2889
2890 if (!initialized)
2891 return IOPMNotYetInitialized;
2892
2893 if (gIOPMWorkLoop->inGate())
2894 {
2895 fDeviceOverrides = false;
2896 return IOPMNoErr;
2897 }
2898
2899 request = acquirePMRequest( this, kIOPMRequestTypePowerOverrideOffPriv );
2900 if (!request)
2901 return kIOReturnNoMemory;
2902
2903 submitPMRequest( request );
2904 return IOPMNoErr;
2905}
2906
2907//*********************************************************************************
2908// [private] handlePowerOverrideChanged
2909//*********************************************************************************
2910
2911void IOService::handlePowerOverrideChanged ( IOPMRequest * request )
2912{
2913 PM_ASSERT_IN_GATE();
2914 if (request->getType() == kIOPMRequestTypePowerOverrideOnPriv)
2915 {
2916 OUR_PMLog(kPMLogOverrideOn, 0, 0);
2917 fDeviceOverrides = true;
2918 }
2919 else
2920 {
2921 OUR_PMLog(kPMLogOverrideOff, 0, 0);
2922 fDeviceOverrides = false;
2923 }
2924
2925 adjustPowerState();
2926}
2927
2928//*********************************************************************************
2929// [private] startPowerChange
2930//*********************************************************************************
2931
2932IOReturn IOService::startPowerChange (
2933 unsigned long changeFlags,
2934 unsigned long powerState,
2935 unsigned long domainFlags,
2936 IOPowerConnection * parentConnection,
2937 unsigned long parentFlags )
2938{
2939 PM_ASSERT_IN_GATE();
2940 assert( fMachineState == kIOPM_Finished );
2941 assert( powerState < fNumberOfPowerStates );
2942
2943 if (powerState >= fNumberOfPowerStates)
2944 return IOPMAckImplied;
2945
2946#if ROOT_DOMAIN_RUN_STATES
2947 // Root domain can override chosen power state to a lower state.
2948 getPMRootDomain()->overridePowerStateForService(
2949 this, &fRootDomainState,
2950 &powerState, changeFlags);
2951#endif
2952
2953 // Invalidate the last recorded tickle power state when a power transition
2954 // is about to occur, and not as a result of a tickle request.
2955
2956 if ((getPMRequestType() != kIOPMRequestTypeActivityTickle) &&
2957 (fActivityTicklePowerState != -1))
2958 {
2959 IOLockLock(fActivityLock);
2960 fActivityTicklePowerState = -1;
2961 IOLockUnlock(fActivityLock);
2962 }
2963
2964 // Initialize the change note.
2965
2966 fHeadNoteFlags = changeFlags;
2967 fHeadNotePowerState = powerState;
2968 fHeadNotePowerArrayEntry = &fPowerStates[ powerState ];
2969 fHeadNoteParentConnection = NULL;
2970
2971 if (changeFlags & kIOPMWeInitiated)
2972 {
2973 if (changeFlags & kIOPMSynchronize)
2974 OurSyncStart();
2975 else
2976 OurChangeStart();
2977 return 0;
2978 }
2979 else
2980 {
2981 assert(changeFlags & kIOPMParentInitiated);
2982 fHeadNoteDomainFlags = domainFlags;
2983 fHeadNoteParentFlags = parentFlags;
2984 fHeadNoteParentConnection = parentConnection;
2985 return ParentChangeStart();
2986 }
2987}
2988
2989//*********************************************************************************
2990// [private] notifyInterestedDrivers
2991//*********************************************************************************
2992
2993bool IOService::notifyInterestedDrivers ( void )
2994{
2995 IOPMinformee * informee;
2996 IOPMinformeeList * list = fInterestedDrivers;
2997 DriverCallParam * param;
2998 IOItemCount count;
2999
3000 PM_ASSERT_IN_GATE();
3001 assert( fDriverCallParamCount == 0 );
3002 assert( fHeadNotePendingAcks == 0 );
3003
3004 fHeadNotePendingAcks = 0;
3005
3006 count = list->numberOfItems();
3007 if (!count)
3008 goto done; // no interested drivers
3009
3010 // Allocate an array of interested drivers and their return values
3011 // for the callout thread. Everything else is still "owned" by the
3012 // PM work loop, which can run to process acknowledgePowerChange()
3013 // responses.
3014
3015 param = (DriverCallParam *) fDriverCallParamPtr;
3016 if (count > fDriverCallParamSlots)
3017 {
3018 if (fDriverCallParamSlots)
3019 {
3020 assert(fDriverCallParamPtr);
3021 IODelete(fDriverCallParamPtr, DriverCallParam, fDriverCallParamSlots);
3022 fDriverCallParamPtr = 0;
3023 fDriverCallParamSlots = 0;
3024 }
3025
3026 param = IONew(DriverCallParam, count);
3027 if (!param)
3028 goto done; // no memory
3029
3030 fDriverCallParamPtr = (void *) param;
3031 fDriverCallParamSlots = count;
3032 }
3033
3034 informee = list->firstInList();
3035 assert(informee);
3036 for (IOItemCount i = 0; i < count; i++)
3037 {
3038 informee->timer = -1;
3039 param[i].Target = informee;
3040 informee->retain();
3041 informee = list->nextInList( informee );
3042 }
3043
3044 fDriverCallParamCount = count;
3045 fHeadNotePendingAcks = count;
3046
3047 // Machine state will be blocked pending callout thread completion.
3048
3049 PM_LOCK();
3050 assert( fLockedFlags.DriverCallBusy == false );
3051 fLockedFlags.DriverCallBusy = true;
3052 PM_UNLOCK();
3053 thread_call_enter( fDriverCallEntry );
3054 return true;
3055
3056done:
3057 // no interested drivers or did not schedule callout thread due to error.
3058 return false;
3059}
3060
3061//*********************************************************************************
3062// [private] notifyInterestedDriversDone
3063//*********************************************************************************
3064
3065void IOService::notifyInterestedDriversDone ( void )
3066{
3067 IOPMinformee * informee;
3068 IOItemCount count;
3069 DriverCallParam * param;
3070 IOReturn result;
3071
3072 PM_ASSERT_IN_GATE();
3073 param = (DriverCallParam *) fDriverCallParamPtr;
3074 count = fDriverCallParamCount;
3075
3076 assert( fLockedFlags.DriverCallBusy == false );
3077 assert( fMachineState == kIOPM_DriverThreadCallDone );
3078
3079 if (param && count)
3080 {
3081 for (IOItemCount i = 0; i < count; i++, param++)
3082 {
3083 informee = (IOPMinformee *) param->Target;
3084 result = param->Result;
3085
3086 if ((result == IOPMAckImplied) || (result < 0))
3087 {
3088 // Interested driver return IOPMAckImplied.
3089 // If informee timer is zero, it must have de-registered
3090 // interest during the thread callout. That also drops
3091 // the pending ack count.
3092
3093 if (fHeadNotePendingAcks && informee->timer)
3094 fHeadNotePendingAcks--;
3095
3096 informee->timer = 0;
3097 }
3098 else if (informee->timer)
3099 {
3100 assert(informee->timer == -1);
3101
3102 // Driver has not acked, and has returned a positive result.
3103 // Enforce a minimum permissible timeout value.
3104 // Make the min value large enough so timeout is less likely
3105 // to occur if a driver misinterpreted that the return value
3106 // should be in microsecond units. And make it large enough
3107 // to be noticeable if a driver neglects to ack.
3108
3109 if (result < kMinAckTimeoutTicks)
3110 result = kMinAckTimeoutTicks;
3111
3112 informee->timer = (result / (ACK_TIMER_PERIOD / ns_per_us)) + 1;
3113 }
3114 // else, child has already acked or driver has removed interest,
3115 // and head_note_pendingAcks decremented.
3116 // informee may have been removed from the interested drivers list,
3117 // thus the informee must be retained across the callout.
3118
3119 informee->release();
3120 }
3121
3122 fDriverCallParamCount = 0;
3123
3124 if ( fHeadNotePendingAcks )
3125 {
3126 OUR_PMLog(kPMLogStartAckTimer, 0, 0);
3127 start_ack_timer();
3128 }
3129 }
3130
3131 // Hop back to original machine state path (from notifyAll)
3132 fMachineState = fNextMachineState;
3133
3134 notifyChildren();
3135}
3136
3137//*********************************************************************************
3138// [private] notifyChildren
3139//*********************************************************************************
3140
3141void IOService::notifyChildren ( void )
3142{
3143 OSIterator * iter;
3144 OSObject * next;
3145 IOPowerConnection * connection;
3146 OSArray * children = 0;
3147
3148 if (fStrictTreeOrder)
3149 children = OSArray::withCapacity(8);
3150
3151 // Sum child power consumption in notifyChild()
3152 fHeadNotePowerArrayEntry->staticPower = 0;
3153
3154 iter = getChildIterator(gIOPowerPlane);
3155 if ( iter )
3156 {
3157 while ((next = iter->getNextObject()))
3158 {
3159 if ((connection = OSDynamicCast(IOPowerConnection, next)))
3160 {
3161 if (connection->getReadyFlag() == false)
3162 {
3163 PM_CONNECT("[%s] %s: connection not ready\n",
3164 getName(), __FUNCTION__);
3165 continue;
3166 }
3167
3168 if (children)
3169 children->setObject( connection );
3170 else
3171 notifyChild( connection,
3172 fDriverCallReason == kDriverCallInformPreChange );
3173 }
3174 }
3175 iter->release();
3176 }
3177
3178 if (children)
3179 {
3180 if (children->getCount() == 0)
3181 {
3182 children->release();
3183 children = 0;
3184 }
3185 else
3186 {
3187 assert(fNotifyChildArray == 0);
3188 fNotifyChildArray = children;
3189 fNextMachineState = fMachineState;
3190 fMachineState = kIOPM_NotifyChildrenDone;
3191 }
3192 }
3193}
3194
3195//*********************************************************************************
3196// [private] notifyChildrenDone
3197//*********************************************************************************
3198
3199void IOService::notifyChildrenDone ( void )
3200{
3201 PM_ASSERT_IN_GATE();
3202 assert(fNotifyChildArray);
3203 assert(fMachineState == kIOPM_NotifyChildrenDone);
3204
3205 // Interested drivers have all acked (if any), ack timer stopped.
3206 // Notify one child, wait for it to ack, then repeat for next child.
3207 // This is a workaround for some drivers with multiple instances at
3208 // the same branch in the power tree, but the driver is slow to power
3209 // up unless the tree ordering is observed. Problem observed only on
3210 // system wake, not on system sleep.
3211 //
3212 // We have the ability to power off in reverse child index order.
3213 // That works nicely on some machines, but not on all HW configs.
3214
3215 if (fNotifyChildArray->getCount())
3216 {
3217 IOPowerConnection * connection;
3218 connection = (IOPowerConnection *) fNotifyChildArray->getObject(0);
3219 fNotifyChildArray->removeObject(0);
3220 notifyChild( connection, fDriverCallReason == kDriverCallInformPreChange );
3221 }
3222 else
3223 {
3224 fNotifyChildArray->release();
3225 fNotifyChildArray = 0;
3226 fMachineState = fNextMachineState;
3227 }
3228}
3229
3230//*********************************************************************************
3231// [private] notifyAll
3232//*********************************************************************************
3233
3234IOReturn IOService::notifyAll ( int nextMachineState, bool is_prechange )
3235{
3236 // Save the next machine_state to be restored by notifyInterestedDriversDone()
3237
3238 PM_ASSERT_IN_GATE();
3239 fNextMachineState = nextMachineState;
3240 fMachineState = kIOPM_DriverThreadCallDone;
3241 fDriverCallReason = is_prechange ?
3242 kDriverCallInformPreChange : kDriverCallInformPostChange;
3243
3244 if (!notifyInterestedDrivers())
3245 notifyInterestedDriversDone();
3246
3247 return IOPMWillAckLater;
3248}
3249
3250//*********************************************************************************
3251// [private, static] pmDriverCallout
3252//
3253// Thread call context
3254//*********************************************************************************
3255
3256IOReturn IOService::actionDriverCalloutDone (
3257 OSObject * target,
3258 void * arg0, void * arg1,
3259 void * arg2, void * arg3 )
3260{
3261 IOServicePM * pwrMgt = (IOServicePM *) arg0;
3262
3263 PM_LOCK();
3264 fLockedFlags.DriverCallBusy = false;
3265 PM_UNLOCK();
3266
3267 if (gIOPMReplyQueue)
3268 gIOPMReplyQueue->signalWorkAvailable();
3269
3270 return kIOReturnSuccess;
3271}
3272
3273void IOService::pmDriverCallout ( IOService * from )
3274{
3275 assert(from);
3276 switch (from->fDriverCallReason)
3277 {
3278 case kDriverCallSetPowerState:
3279 from->driverSetPowerState();
3280 break;
3281
3282 case kDriverCallInformPreChange:
3283 case kDriverCallInformPostChange:
3284 from->driverInformPowerChange();
3285 break;
3286
3287 default:
3288 panic("IOService::pmDriverCallout bad machine state %x",
3289 from->fDriverCallReason);
3290 }
3291
3292 gIOPMWorkLoop->runAction(actionDriverCalloutDone,
3293 /* target */ from,
3294 /* arg0 */ (void *) from->pwrMgt );
3295}
3296
3297//*********************************************************************************
3298// [private] driverSetPowerState
3299//
3300// Thread call context
3301//*********************************************************************************
3302
3303void IOService::driverSetPowerState ( void )
3304{
3305 IOService * driver;
3306 unsigned long powerState;
3307 DriverCallParam * param;
3308 IOReturn result;
3309 AbsoluteTime end;
3310
3311 assert( fLockedFlags.DriverCallBusy == true );
3312 param = (DriverCallParam *) fDriverCallParamPtr;
3313 assert( param );
3314 assert( fDriverCallParamCount == 1 );
3315
3316 driver = fControllingDriver;
3317 powerState = fHeadNotePowerState;
3318
3319 if (fLockedFlags.PMStop == false)
3320 {
3321 OUR_PMLog( kPMLogProgramHardware, (uintptr_t) this, powerState);
3322 clock_get_uptime(&fDriverCallStartTime);
3323 result = driver->setPowerState( powerState, this );
3324 clock_get_uptime(&end);
3325 OUR_PMLog((UInt32) -kPMLogProgramHardware, (uintptr_t) this, (UInt32) result);
3326
3327#if LOG_SETPOWER_TIMES
3328 if ((result == IOPMAckImplied) || (result < 0))
3329 {
3330 uint64_t nsec;
3331
3332 SUB_ABSOLUTETIME(&end, &fDriverCallStartTime);
3333 absolutetime_to_nanoseconds(end, &nsec);
3334 if (nsec > LOG_SETPOWER_TIMES)
3335 PM_DEBUG("%s::setPowerState(%p, %lu -> %lu) took %d ms\n",
3336 fName, this, fCurrentPowerState, powerState, NS_TO_MS(nsec));
3337 }
3338#endif
3339 }
3340 else
3341 result = kIOPMAckImplied;
3342
3343 param->Result = result;
3344}
3345
3346//*********************************************************************************
3347// [private] driverInformPowerChange
3348//
3349// Thread call context
3350//*********************************************************************************
3351
3352void IOService::driverInformPowerChange ( void )
3353{
3354 IOItemCount count;
3355 IOPMinformee * informee;
3356 IOService * driver;
3357 IOReturn result;
3358 IOPMPowerFlags powerFlags;
3359 unsigned long powerState;
3360 DriverCallParam * param;
3361 AbsoluteTime end;
3362
3363 assert( fLockedFlags.DriverCallBusy == true );
3364 param = (DriverCallParam *) fDriverCallParamPtr;
3365 count = fDriverCallParamCount;
3366 assert( count && param );
3367
3368 powerFlags = fHeadNotePowerArrayEntry->capabilityFlags;
3369 powerState = fHeadNotePowerState;
3370
3371 for (IOItemCount i = 0; i < count; i++)
3372 {
3373 informee = (IOPMinformee *) param->Target;
3374 driver = informee->whatObject;
3375
3376 if ((fLockedFlags.PMStop == false) && informee->active)
3377 {
3378 if (fDriverCallReason == kDriverCallInformPreChange)
3379 {
3380 OUR_PMLog(kPMLogInformDriverPreChange, (uintptr_t) this, powerState);
3381 clock_get_uptime(&informee->startTime);
3382 result = driver->powerStateWillChangeTo(powerFlags, powerState, this);
3383 clock_get_uptime(&end);
3384 OUR_PMLog((UInt32)-kPMLogInformDriverPreChange, (uintptr_t) this, result);
3385 }
3386 else
3387 {
3388 OUR_PMLog(kPMLogInformDriverPostChange, (uintptr_t) this, powerState);
3389 clock_get_uptime(&informee->startTime);
3390 result = driver->powerStateDidChangeTo(powerFlags, powerState, this);
3391 clock_get_uptime(&end);
3392 OUR_PMLog((UInt32)-kPMLogInformDriverPostChange, (uintptr_t) this, result);
3393 }
3394
3395#if LOG_SETPOWER_TIMES
3396 if ((result == IOPMAckImplied) || (result < 0))
3397 {
3398 uint64_t nsec;
3399
3400 SUB_ABSOLUTETIME(&end, &informee->startTime);
3401 absolutetime_to_nanoseconds(end, &nsec);
3402 if (nsec > LOG_SETPOWER_TIMES)
3403 PM_DEBUG("%s::powerState%sChangeTo(%p, %s, %lu -> %lu) took %d ms\n",
3404 driver->getName(),
3405 (fDriverCallReason == kDriverCallInformPreChange) ? "Will" : "Did",
3406 driver, fName, fCurrentPowerState, powerState, NS_TO_MS(nsec));
3407 }
3408#endif
3409 }
3410 else
3411 result = kIOPMAckImplied;
3412
3413 param->Result = result;
3414 param++;
3415 }
3416}
3417
3418//*********************************************************************************
3419// [private] notifyChild
3420//
3421// Notify a power domain child of an upcoming power change.
3422// If the object acknowledges the current change, we return TRUE.
3423//*********************************************************************************
3424
3425bool IOService::notifyChild ( IOPowerConnection * theNub, bool is_prechange )
3426{
3427 IOReturn ret = IOPMAckImplied;
3428 unsigned long childPower;
3429 IOService * theChild;
3430 IOPMRequest * childRequest;
3431 uint32_t requestArg2;
3432 int requestType;
3433
3434 PM_ASSERT_IN_GATE();
3435 theChild = (IOService *)(theNub->copyChildEntry(gIOPowerPlane));
3436 if (!theChild)
3437 {
3438 assert(false);
3439 return true;
3440 }
3441
3442 // Unless the child handles the notification immediately and returns
3443 // kIOPMAckImplied, we'll be awaiting their acknowledgement later.
3444 fHeadNotePendingAcks++;
3445 theNub->setAwaitingAck(true);
3446
3447 requestArg2 = fHeadNoteFlags;
3448 if (fHeadNotePowerState < fCurrentPowerState)
3449 requestArg2 |= kIOPMDomainPowerDrop;
3450
3451 requestType = is_prechange ?
3452 kIOPMRequestTypePowerDomainWillChange :
3453 kIOPMRequestTypePowerDomainDidChange;
3454
3455 childRequest = acquirePMRequest( theChild, requestType );
3456 if (childRequest)
3457 {
3458 theNub->retain();
3459 childRequest->fArg0 = (void *) fHeadNotePowerArrayEntry->outputPowerCharacter;
3460 childRequest->fArg1 = (void *) theNub;
3461 childRequest->fArg2 = (void *) requestArg2;
3462 theChild->submitPMRequest( childRequest );
3463 ret = IOPMWillAckLater;
3464 }
3465 else
3466 {
3467 ret = IOPMAckImplied;
3468 fHeadNotePendingAcks--;
3469 theNub->setAwaitingAck(false);
3470 childPower = theChild->currentPowerConsumption();
3471 if ( childPower == kIOPMUnknown )
3472 {
3473 fHeadNotePowerArrayEntry->staticPower = kIOPMUnknown;
3474 } else {
3475 if (fHeadNotePowerArrayEntry->staticPower != kIOPMUnknown )
3476 fHeadNotePowerArrayEntry->staticPower += childPower;
3477 }
3478 }
3479
3480 theChild->release();
3481 return (IOPMAckImplied == ret);
3482}
3483
3484// MARK: -
3485// MARK: Power Change Initiated by Driver
3486
3487//*********************************************************************************
3488// [private] OurChangeStart
3489//
3490// Begin the processing of a power change initiated by us.
3491//*********************************************************************************
3492
3493void IOService::OurChangeStart ( void )
3494{
3495 PM_ASSERT_IN_GATE();
3496 OUR_PMLog( kPMLogStartDeviceChange, fHeadNotePowerState, fCurrentPowerState );
3497
3498 // fMaxCapability is our maximum possible power state based on the current
3499 // power state of our parents. If we are trying to raise power beyond the
3500 // maximum, send an async request for more power to all parents.
3501
3502 if (!IS_PM_ROOT() && (fMaxCapability < fHeadNotePowerState))
3503 {
3504 fHeadNoteFlags |= kIOPMNotDone;
3505 requestDomainPower(fHeadNotePowerState);
3506 OurChangeFinish();
3507 return;
3508 }
3509
3510 // Redundant power changes skips to the end of the state machine.
3511
3512 if (!fInitialChange && (fHeadNotePowerState == fCurrentPowerState))
3513 {
3514 OurChangeFinish();
3515 return;
3516 }
3517 fInitialChange = false;
3518
3519#if ROOT_DOMAIN_RUN_STATES
3520 // Change started, but may not complete...
3521 // Can be canceled (power drop) or deferred (power rise).
3522
3523 getPMRootDomain()->handlePowerChangeStartForService(
3524 /* service */ this,
3525 /* RD flags */ &fRootDomainState,
3526 /* new pwr state */ fHeadNotePowerState,
3527 /* change flags */ fHeadNoteFlags );
3528#endif
3529
3530 // Two separate paths, depending if power is being raised or lowered.
3531 // Lowering power is subject to approval by clients of this service.
3532
3533 if (IS_POWER_DROP)
3534 {
3535 // Next machine state for a power drop.
3536 fMachineState = kIOPM_OurChangeTellClientsPowerDown;
3537 fDoNotPowerDown = false;
3538
3539 // Ask apps and kernel clients permission to lower power.
3540 fOutOfBandParameter = kNotifyApps;
3541 askChangeDown(fHeadNotePowerState);
3542 }
3543 else
3544 {
3545 // This service is raising power and parents are able to support the
3546 // new power state. However a parent may have already committed to
3547 // drop power, which might force this object to temporarily drop power.
3548 // This results in "oscillations" before the state machines converge
3549 // to a steady state.
3550 //
3551 // To prevent this, a child must make a power reservation against all
3552 // parents before raising power. If the reservation fails, indicating
3553 // that the child will be unable to sustain the higher power state,
3554 // then the child will signal the parent to adjust power, and the child
3555 // will defer its power change.
3556
3557#if RESERVE_DOMAIN_POWER
3558 IOReturn ret;
3559
3560 // Reserve parent power necessary to achieve fHeadNotePowerState.
3561 ret = requestDomainPower( fHeadNotePowerState, kReserveDomainPower );
3562 if (ret != kIOReturnSuccess)
3563 {
3564 // Reservation failed, defer power rise.
3565 fHeadNoteFlags |= kIOPMNotDone;
3566 OurChangeFinish();
3567 return;
3568 }
3569#endif
3570 // Notify interested drivers and children.
3571 notifyAll( kIOPM_OurChangeSetPowerState, kNotifyWillChange );
3572 }
3573}
3574
3575//*********************************************************************************
3576
3577struct IOPMRequestDomainPowerContext {
3578 IOService * child; // the requesting child
3579 IOPMPowerFlags requestPowerFlags; // power flags requested by child
3580};
3581
3582static void
3583requestDomainPowerApplier(
3584 IORegistryEntry * entry,
3585 void * inContext )
3586{
3587 IOPowerConnection * connection;
3588 IOService * parent;
3589 IOPMRequestDomainPowerContext * context;
3590
3591 if ((connection = OSDynamicCast(IOPowerConnection, entry)) == 0)
3592 return;
3593 parent = (IOService *) connection->copyParentEntry(gIOPowerPlane);
3594 if (!parent)
3595 return;
3596
3597 assert(inContext);
3598 context = (IOPMRequestDomainPowerContext *) inContext;
3599
3600 if (connection->parentKnowsState() && connection->getReadyFlag())
3601 {
3602 parent->requestPowerDomainState(
3603 context->requestPowerFlags,
3604 connection,
3605 IOPMLowestState);
3606 }
3607
3608 parent->release();
3609}
3610
3611//*********************************************************************************
3612// [private] requestDomainPower
3613//*********************************************************************************
3614
3615IOReturn IOService::requestDomainPower(
3616 unsigned long ourPowerState,
3617 IOOptionBits options )
3618{
3619 const IOPMPowerState * powerStateEntry;
3620 IOPMPowerFlags requestPowerFlags;
3621 unsigned long maxPowerState;
3622 IOPMRequestDomainPowerContext context;
3623
3624 PM_ASSERT_IN_GATE();
3625 assert(ourPowerState < fNumberOfPowerStates);
3626 if (ourPowerState >= fNumberOfPowerStates)
3627 return kIOReturnBadArgument;
3628 if (IS_PM_ROOT())
3629 return kIOReturnSuccess;
3630
3631 // Fetch the input power flags for the requested power state.
3632 // Parent request is stated in terms of required power flags.
3633
3634 powerStateEntry = &fPowerStates[ourPowerState];
3635 requestPowerFlags = powerStateEntry->inputPowerRequirement;
3636
3637 if (powerStateEntry->capabilityFlags & (kIOPMChildClamp | kIOPMPreventIdleSleep))
3638 requestPowerFlags |= kIOPMPreventIdleSleep;
3639 if (powerStateEntry->capabilityFlags & (kIOPMChildClamp2 | kIOPMPreventSystemSleep))
3640 requestPowerFlags |= kIOPMPreventSystemSleep;
3641
3642 // Disregard the "previous request" for power reservation.
3643
3644 if (((options & kReserveDomainPower) == 0) &&
3645 (fPreviousRequest == requestPowerFlags))
3646 {
3647 // skip if domain already knows our requirements
3648 goto done;
3649 }
3650 fPreviousRequest = requestPowerFlags;
3651
3652 context.child = this;
3653 context.requestPowerFlags = requestPowerFlags;
3654 fHeadNoteDomainTargetFlags = 0;
3655 applyToParents(requestDomainPowerApplier, &context, gIOPowerPlane);
3656
3657 if (options & kReserveDomainPower)
3658 {
3659 maxPowerState = fControllingDriver->maxCapabilityForDomainState(
3660 fHeadNoteDomainTargetFlags );
3661
3662 if (maxPowerState < fHeadNotePowerState)
3663 {
3664 PM_TRACE("%s: power desired %u:0x%x got %u:0x%x\n",
3665 getName(),
3666 (uint32_t) ourPowerState, (uint32_t) requestPowerFlags,
3667 (uint32_t) maxPowerState, (uint32_t) fHeadNoteDomainTargetFlags);
3668 return kIOReturnNoPower;
3669 }
3670 }
3671
3672done:
3673 return kIOReturnSuccess;
3674}
3675
3676//*********************************************************************************
3677// [private] OurSyncStart
3678//*********************************************************************************
3679
3680void IOService::OurSyncStart ( void )
3681{
3682 PM_ASSERT_IN_GATE();
3683
3684 if (fInitialChange)
3685 return;
3686
3687#if ROOT_DOMAIN_RUN_STATES
3688 getPMRootDomain()->handlePowerChangeStartForService(
3689 /* service */ this,
3690 /* RD flags */ &fRootDomainState,
3691 /* new pwr state */ fHeadNotePowerState,
3692 /* change flags */ fHeadNoteFlags );
3693#endif
3694
3695 fMachineState = kIOPM_SyncNotifyDidChange;
3696 fDriverCallReason = kDriverCallInformPreChange;
3697
3698 notifyChildren();
3699}
3700
3701//*********************************************************************************
3702// [private] OurChangeTellClientsPowerDown
3703//
3704// All registered applications and kernel clients have positively acknowledged our
3705// intention of lowering power. Here we notify them all that we will definitely
3706// lower the power. If we don't have to wait for any of them to acknowledge, we
3707// carry on by notifying interested drivers. Otherwise, we do wait.
3708//*********************************************************************************
3709
3710void IOService::OurChangeTellClientsPowerDown ( void )
3711{
3712 fMachineState = kIOPM_OurChangeTellPriorityClientsPowerDown;
3713 tellChangeDown1(fHeadNotePowerState);
3714}
3715
3716//*********************************************************************************
3717// [private] OurChangeTellPriorityClientsPowerDown
3718//
3719// All registered applications and kernel clients have positively acknowledged our
3720// intention of lowering power. Here we notify "priority" clients that we are
3721// lowering power. If we don't have to wait for any of them to acknowledge, we
3722// carry on by notifying interested drivers. Otherwise, we do wait.
3723//*********************************************************************************
3724
3725void IOService::OurChangeTellPriorityClientsPowerDown ( void )
3726{
3727 fMachineState = kIOPM_OurChangeNotifyInterestedDriversWillChange;
3728 tellChangeDown2(fHeadNotePowerState);
3729}
3730
3731//*********************************************************************************
3732// [private] OurChangeNotifyInterestedDriversWillChange
3733//
3734// All registered applications and kernel clients have acknowledged our notification
3735// that we are lowering power. Here we notify interested drivers. If we don't have
3736// to wait for any of them to acknowledge, we instruct our power driver to make the
3737// change. Otherwise, we do wait.
3738//*********************************************************************************
3739
3740void IOService::OurChangeNotifyInterestedDriversWillChange ( void )
3741{
3742 IOPMrootDomain *rootDomain;
3743 if ((rootDomain = getPMRootDomain()) == this)
3744 {
3745 rootDomain->tracePoint(kIOPMTracePointSystemSleepDriversPhase);
3746 }
3747
3748 notifyAll( kIOPM_OurChangeSetPowerState, kNotifyWillChange );
3749}
3750
3751//*********************************************************************************
3752// [private] OurChangeSetPowerState
3753//
3754// All interested drivers have acknowledged our pre-change notification of a power
3755// change we initiated. Here we instruct our controlling driver to make
3756// the change to the hardware. If it does so, we continue processing
3757// (waiting for settle and notifying interested parties post-change.)
3758// If it doesn't, we have to wait for it to acknowledge and then continue.
3759//*********************************************************************************
3760
3761void IOService::OurChangeSetPowerState ( void )
3762{
3763 fNextMachineState = kIOPM_OurChangeWaitForPowerSettle;
3764 fMachineState = kIOPM_DriverThreadCallDone;
3765 fDriverCallReason = kDriverCallSetPowerState;
3766
3767 if (notifyControllingDriver() == false)
3768 notifyControllingDriverDone();
3769}
3770
3771//*********************************************************************************
3772// [private] OurChangeWaitForPowerSettle
3773//
3774// Our controlling driver has changed power state on the hardware
3775// during a power change we initiated. Wait for the driver specified
3776// settle time to expire, before notifying interested parties post-change.
3777//*********************************************************************************
3778
3779void IOService::OurChangeWaitForPowerSettle( void )
3780{
3781 fMachineState = kIOPM_OurChangeNotifyInterestedDriversDidChange;
3782 startSettleTimer();
3783}
3784
3785//*********************************************************************************
3786// [private] OurChangeNotifyInterestedDriversDidChange
3787//
3788// Power has settled on a power change we initiated. Here we notify
3789// all our interested parties post-change. If they all acknowledge, we're
3790// done with this change note, and we can start on the next one.
3791// Otherwise we have to wait for acknowledgements and finish up later.
3792//*********************************************************************************
3793
3794void IOService::OurChangeNotifyInterestedDriversDidChange ( void )
3795{
3796 notifyAll( kIOPM_OurChangeFinish, kNotifyDidChange );
3797}
3798
3799//*********************************************************************************
3800// [private] OurChangeFinish
3801//
3802// Power has settled on a power change we initiated, and
3803// all our interested parties have acknowledged. We're
3804// done with this change note, and we can start on the next one.
3805//*********************************************************************************
3806
3807void IOService::OurChangeFinish ( void )
3808{
3809 all_done();
3810}
3811
3812// MARK: -
3813// MARK: Power Change Initiated by Parent
3814
3815//*********************************************************************************
3816// [private] ParentChangeStart
3817//
3818// Here we begin the processing of a power change initiated by our parent.
3819//*********************************************************************************
3820
3821IOReturn IOService::ParentChangeStart ( void )
3822{
3823 PM_ASSERT_IN_GATE();
3824 OUR_PMLog( kPMLogStartParentChange, fHeadNotePowerState, fCurrentPowerState );
3825
3826 // Power domain is lowering power
3827 if ( fHeadNotePowerState < fCurrentPowerState )
3828 {
3829 // TODO: redundant? See handlePowerDomainWillChangeTo()
3830 setParentInfo( fHeadNoteParentFlags, fHeadNoteParentConnection, true );
3831
3832#if ROOT_DOMAIN_RUN_STATES
3833 getPMRootDomain()->handlePowerChangeStartForService(
3834 /* service */ this,
3835 /* RD flags */ &fRootDomainState,
3836 /* new pwr state */ fHeadNotePowerState,
3837 /* change flags */ fHeadNoteFlags );
3838#endif
3839
3840 // tell apps and kernel clients
3841 fInitialChange = false;
3842 fMachineState = kIOPM_ParentDownTellPriorityClientsPowerDown;
3843 tellChangeDown1(fHeadNotePowerState);
3844 return IOPMWillAckLater;
3845 }
3846
3847 // Power domain is raising power
3848 if ( fHeadNotePowerState > fCurrentPowerState )
3849 {
3850 if ( fDesiredPowerState > fCurrentPowerState )
3851 {
3852 if ( fDesiredPowerState < fHeadNotePowerState )
3853 {
3854 // We power up, but not all the way
3855 fHeadNotePowerState = fDesiredPowerState;
3856 fHeadNotePowerArrayEntry = &fPowerStates[fDesiredPowerState];
3857 OUR_PMLog(kPMLogAmendParentChange, fHeadNotePowerState, 0);
3858 }
3859 } else {
3860 // We don't need to change
3861 fHeadNotePowerState = fCurrentPowerState;
3862 fHeadNotePowerArrayEntry = &fPowerStates[fCurrentPowerState];
3863 OUR_PMLog(kPMLogAmendParentChange, fHeadNotePowerState, 0);
3864 }
3865 }
3866
3867 if ( fHeadNoteFlags & kIOPMDomainDidChange )
3868 {
3869 if ( fHeadNotePowerState > fCurrentPowerState )
3870 {
3871#if ROOT_DOMAIN_RUN_STATES
3872 getPMRootDomain()->handlePowerChangeStartForService(
3873 /* service */ this,
3874 /* RD flags */ &fRootDomainState,
3875 /* new pwr state */ fHeadNotePowerState,
3876 /* change flags */ fHeadNoteFlags );
3877#endif
3878
3879 // Parent did change up - start our change up
3880 fInitialChange = false;
3881 notifyAll( kIOPM_ParentUpSetPowerState, kNotifyWillChange );
3882 return IOPMWillAckLater;
3883 }
3884 else if (fHeadNoteFlags & kIOPMSynchronize)
3885 {
3886 // We do not need to change power state, but notify
3887 // children to propagate tree synchronization.
3888 fMachineState = kIOPM_SyncNotifyDidChange;
3889 fDriverCallReason = kDriverCallInformPreChange;
3890 notifyChildren();
3891 return IOPMWillAckLater;
3892 }
3893 }
3894
3895 all_done();
3896 return IOPMAckImplied;
3897}
3898
3899//*********************************************************************************
3900// [private] ParentDownTellPriorityClientsPowerDown
3901//
3902// All applications and kernel clients have been notified of a power lowering
3903// initiated by the parent and we had to wait for responses. Here
3904// we notify any priority clients. If they all ack, we continue with the power change.
3905// If at least one doesn't, we have to wait for it to acknowledge and then continue.
3906//*********************************************************************************
3907
3908void IOService::ParentDownTellPriorityClientsPowerDown ( void )
3909{
3910 fMachineState = kIOPM_ParentDownNotifyInterestedDriversWillChange;
3911 tellChangeDown2(fHeadNotePowerState);
3912}
3913
3914//*********************************************************************************
3915// [private] ParentDownNotifyInterestedDriversWillChange
3916//
3917// All applications and kernel clients have been notified of a power lowering
3918// initiated by the parent and we had to wait for their responses. Here we notify
3919// any interested drivers and power domain children. If they all ack, we continue
3920// with the power change.
3921// If at least one doesn't, we have to wait for it to acknowledge and then continue.
3922//*********************************************************************************
3923
3924void IOService::ParentDownNotifyInterestedDriversWillChange ( void )
3925{
3926 IOPMrootDomain *rootDomain;
3927 if ((rootDomain = getPMRootDomain()) == this)
3928 {
3929 rootDomain->tracePoint(kIOPMTracePointSystemSleepDriversPhase);
3930 }
3931
3932 notifyAll( kIOPM_ParentDownSetPowerState, kNotifyWillChange );
3933}
3934
3935//*********************************************************************************
3936// [private] ParentDownSetPowerState
3937//
3938// We had to wait for it, but all parties have acknowledged our pre-change
3939// notification of a power lowering initiated by the parent.
3940// Here we instruct our controlling driver
3941// to put the hardware in the state it needs to be in when the domain is
3942// lowered. If it does so, we continue processing
3943// (waiting for settle and acknowledging the parent.)
3944// If it doesn't, we have to wait for it to acknowledge and then continue.
3945//*********************************************************************************
3946
3947void IOService::ParentDownSetPowerState ( void )
3948{
3949 fNextMachineState = kIOPM_ParentDownWaitForPowerSettle;
3950 fMachineState = kIOPM_DriverThreadCallDone;
3951 fDriverCallReason = kDriverCallSetPowerState;
3952
3953 if (notifyControllingDriver() == false)
3954 notifyControllingDriverDone();
3955}
3956
3957//*********************************************************************************
3958// [private] ParentDownWaitForPowerSettle
3959//
3960// Our controlling driver has changed power state on the hardware
3961// during a power change initiated by our parent. We have had to wait
3962// for acknowledgement from interested parties, or we have had to wait
3963// for the controlling driver to change the state. Here we see if we need
3964// to wait for power to settle before continuing. If not, we continue
3965// processing (acknowledging our preparedness to the parent).
3966// If so, we wait and continue later.
3967//*********************************************************************************
3968
3969void IOService::ParentDownWaitForPowerSettle ( void )
3970{
3971 fMachineState = kIOPM_ParentDownNotifyDidChangeAndAcknowledgeChange;
3972 startSettleTimer();
3973}
3974
3975//*********************************************************************************
3976// [private] ParentDownNotifyDidChangeAndAcknowledgeChange
3977//
3978// Power has settled on a power change initiated by our parent. Here we
3979// notify interested parties.
3980//*********************************************************************************
3981
3982void IOService::ParentDownNotifyDidChangeAndAcknowledgeChange ( void )
3983{
3984 notifyAll( kIOPM_ParentAcknowledgePowerChange, kNotifyDidChange );
3985}
3986
3987//*********************************************************************************
3988// [private] ParentAcknowledgePowerChange
3989//
3990// We had to wait for it, but all parties have acknowledged our post-change
3991// notification of a power change (either Up or Down) initiated by the parent.
3992// Here we acknowledge the parent.
3993//*********************************************************************************
3994
3995void IOService::ParentAcknowledgePowerChange ( void )
3996{
3997 IORegistryEntry * nub;
3998 IOService * parent;
3999
4000 nub = fHeadNoteParentConnection;
4001 nub->retain();
4002 all_done();
4003 parent = (IOService *)nub->copyParentEntry(gIOPowerPlane);
4004 if ( parent )
4005 {
4006 parent->acknowledgePowerChange((IOService *)nub);
4007 parent->release();
4008 }
4009 nub->release();
4010}
4011
4012//*********************************************************************************
4013// [private] ParentUpSetPowerState
4014//
4015// Our parent has informed us via powerStateDidChange that it has
4016// raised the power in our power domain, and we have had to wait
4017// for some interested party to acknowledge our notification.
4018// Here we instruct our controlling
4019// driver to program the hardware to take advantage of the higher domain
4020// power. If it does so, we continue processing
4021// (waiting for settle and notifying interested parties post-change.)
4022// If it doesn't, we have to wait for it to acknowledge and then continue.
4023//*********************************************************************************
4024
4025void IOService::ParentUpSetPowerState ( void )
4026{
4027 fNextMachineState = kIOPM_ParentUpWaitForSettleTime;
4028 fMachineState = kIOPM_DriverThreadCallDone;
4029 fDriverCallReason = kDriverCallSetPowerState;
4030
4031 if (notifyControllingDriver() == false)
4032 notifyControllingDriverDone();
4033}
4034
4035//*********************************************************************************
4036// [private] ParentUpWaitForSettleTime
4037//
4038// Our controlling driver has changed power state on the hardware
4039// during a power raise initiated by the parent, but we had to wait for it.
4040// Here we see if we need to wait for power to settle before continuing.
4041// If not, we continue processing (notifying interested parties post-change).
4042// If so, we wait and continue later.
4043//*********************************************************************************
4044
4045void IOService::ParentUpWaitForSettleTime ( void )
4046{
4047 fMachineState = kIOPM_ParentUpNotifyInterestedDriversDidChange;
4048 startSettleTimer();
4049}
4050
4051//*********************************************************************************
4052// [private] ParentUpNotifyInterestedDriversDidChange
4053//
4054// Power has settled on a power raise initiated by the parent.
4055// Here we notify all our interested parties post-change. If they all acknowledge,
4056// we're done with this change note, and we can start on the next one.
4057// Otherwise we have to wait for acknowledgements and finish up later.
4058//*********************************************************************************
4059
4060void IOService::ParentUpNotifyInterestedDriversDidChange ( void )
4061{
4062 notifyAll( kIOPM_ParentAcknowledgePowerChange, kNotifyDidChange );
4063}
4064
4065//*********************************************************************************
4066// [private] all_done
4067//
4068// A power change is complete, and the used post-change note is at
4069// the head of the queue. Remove it and set myCurrentState to the result
4070// of the change. Start up the next change in queue.
4071//*********************************************************************************
4072
4073void IOService::all_done ( void )
4074{
4075 unsigned long previous_state;
4076
4077#if ROOT_DOMAIN_RUN_STATES
4078 getPMRootDomain()->handlePowerChangeDoneForService(
4079 /* service */ this,
4080 /* RD flags */ &fRootDomainState,
4081 /* new pwr state */ fHeadNotePowerState,
4082 /* change flags */ fHeadNoteFlags );
4083#endif
4084
4085 if ((fHeadNoteFlags & kIOPMSynchronize) &&
4086 ((fMachineState == kIOPM_Finished) || (fMachineState == kIOPM_SyncFinish)))
4087 {
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).
4091
4092 if (getPMRequestType() == kIOPMRequestTypeSynchronizePowerTree)
4093 {
4094 powerChangeDone(fCurrentPowerState);
4095 }
4096
4097 fMachineState = kIOPM_Finished;
4098 return;
4099 }
4100
4101 fMachineState = kIOPM_Finished;
4102
4103 // our power change
4104 if ( fHeadNoteFlags & kIOPMWeInitiated )
4105 {
4106 // could our driver switch to the new state?
4107 if ( !( fHeadNoteFlags & kIOPMNotDone) )
4108 {
4109 // we changed, tell our parent
4110 requestDomainPower(fHeadNotePowerState);
4111
4112 // yes, did power raise?
4113 if ( fCurrentPowerState < fHeadNotePowerState )
4114 {
4115 // yes, inform clients and apps
4116 tellChangeUp (fHeadNotePowerState);
4117 }
4118 previous_state = fCurrentPowerState;
4119 // either way
4120 fCurrentPowerState = fHeadNotePowerState;
4121#if PM_VARS_SUPPORT
4122 fPMVars->myCurrentState = fCurrentPowerState;
4123#endif
4124 OUR_PMLog(kPMLogChangeDone, fCurrentPowerState, 0);
4125
4126 // inform subclass policy-maker
4127 if ((fLockedFlags.PMStop == false) && fParentsKnowState)
4128 powerChangeDone(previous_state);
4129 else
4130 PM_DEBUG("%s::powerChangeDone() skipped\n", getName());
4131 }
4132 }
4133
4134 // parent's power change
4135 if ( fHeadNoteFlags & kIOPMParentInitiated)
4136 {
4137 if (((fHeadNoteFlags & kIOPMDomainWillChange) && (fCurrentPowerState >= fHeadNotePowerState)) ||
4138 ((fHeadNoteFlags & kIOPMDomainDidChange) && (fCurrentPowerState < fHeadNotePowerState)))
4139 {
4140 // did power raise?
4141 if ( fCurrentPowerState < fHeadNotePowerState )
4142 {
4143 // yes, inform clients and apps
4144 tellChangeUp (fHeadNotePowerState);
4145 }
4146 // either way
4147 previous_state = fCurrentPowerState;
4148 fCurrentPowerState = fHeadNotePowerState;
4149#if PM_VARS_SUPPORT
4150 fPMVars->myCurrentState = fCurrentPowerState;
4151#endif
4152 fMaxCapability = fControllingDriver->maxCapabilityForDomainState(fHeadNoteDomainFlags);
4153
4154 OUR_PMLog(kPMLogChangeDone, fCurrentPowerState, 0);
4155
4156 // inform subclass policy-maker
4157 if ((fLockedFlags.PMStop == false) && fParentsKnowState)
4158 powerChangeDone(previous_state);
4159 else
4160 PM_DEBUG("%s::powerChangeDone() skipped\n", getName());
4161 }
4162 }
4163
4164 if (fCurrentPowerState < fNumberOfPowerStates)
4165 {
4166 const IOPMPowerState * powerStatePtr = &fPowerStates[fCurrentPowerState];
4167
4168 fCurrentCapabilityFlags = powerStatePtr->capabilityFlags;
4169 if (fCurrentCapabilityFlags & kIOPMStaticPowerValid)
4170 fCurrentPowerConsumption = powerStatePtr->staticPower;
4171 }
4172
4173 // When power rises enough to satisfy the tickle's desire for more power,
4174 // the condition preventing idle-timer from dropping power is removed.
4175
4176 if (fCurrentPowerState >= fIdleTimerMinPowerState)
4177 {
4178 fIdleTimerMinPowerState = 0;
4179 }
4180}
4181
4182//*********************************************************************************
4183// [public] settleTimerExpired
4184//
4185// Power has settled after our last change. Notify interested parties that
4186// there is a new power state.
4187//*********************************************************************************
4188
4189void IOService::settleTimerExpired ( void )
4190{
4191 fSettleTimeUS = 0;
4192}
4193
4194//*********************************************************************************
4195// settle_timer_expired
4196//
4197// Holds a retain while the settle timer callout is in flight.
4198//*********************************************************************************
4199
4200static void
4201settle_timer_expired( thread_call_param_t arg0, thread_call_param_t arg1 )
4202{
4203 IOService * me = (IOService *) arg0;
4204
4205 if (gIOPMWorkLoop && gIOPMReplyQueue)
4206 {
4207 gIOPMWorkLoop->runAction(
4208 OSMemberFunctionCast(IOWorkLoop::Action, me, &IOService::settleTimerExpired),
4209 me);
4210 gIOPMReplyQueue->signalWorkAvailable();
4211 }
4212 me->release();
4213}
4214
4215//*********************************************************************************
4216// [private] startSettleTimer
4217//
4218// Calculate a power-settling delay in microseconds and start a timer.
4219//*********************************************************************************
4220
4221void IOService::startSettleTimer( void )
4222{
4223 AbsoluteTime deadline;
4224 unsigned long i;
4225 uint32_t settleTime = 0;
4226 boolean_t pending;
4227
4228 PM_ASSERT_IN_GATE();
4229
4230 i = fCurrentPowerState;
4231
4232 // lowering power
4233 if ( fHeadNotePowerState < fCurrentPowerState )
4234 {
4235 while ( i > fHeadNotePowerState )
4236 {
4237 settleTime += (uint32_t) fPowerStates[i].settleDownTime;
4238 i--;
4239 }
4240 }
4241
4242 // raising power
4243 if ( fHeadNotePowerState > fCurrentPowerState )
4244 {
4245 while ( i < fHeadNotePowerState )
4246 {
4247 settleTime += (uint32_t) fPowerStates[i+1].settleUpTime;
4248 i++;
4249 }
4250 }
4251
4252 if (settleTime)
4253 {
4254 retain();
4255 clock_interval_to_deadline(settleTime, kMicrosecondScale, &deadline);
4256 pending = thread_call_enter_delayed(fSettleTimer, deadline);
4257 if (pending) release();
4258 }
4259}
4260
4261//*********************************************************************************
4262// [private] ackTimerTick
4263//
4264// The acknowledgement timeout periodic timer has ticked.
4265// If we are awaiting acks for a power change notification,
4266// we decrement the timer word of each interested driver which hasn't acked.
4267// If a timer word becomes zero, we pretend the driver aknowledged.
4268// If we are waiting for the controlling driver to change the power
4269// state of the hardware, we decrement its timer word, and if it becomes
4270// zero, we pretend the driver acknowledged.
4271//
4272// Returns true if the timer tick made it possible to advance to the next
4273// machine state, false otherwise.
4274//*********************************************************************************
4275
4276#ifndef __LP64__
4277void IOService::ack_timer_ticked ( void )
4278{
4279 assert(false);
4280}
4281#endif /* !__LP64__ */
4282
4283bool IOService::ackTimerTick( void )
4284{
4285 IOPMinformee * nextObject;
4286 bool done = false;
4287
4288 PM_ASSERT_IN_GATE();
4289 switch (fMachineState) {
4290 case kIOPM_OurChangeWaitForPowerSettle:
4291 case kIOPM_ParentDownWaitForPowerSettle:
4292 case kIOPM_ParentUpWaitForSettleTime:
4293 // are we waiting for controlling driver to acknowledge?
4294 if ( fDriverTimer > 0 )
4295 {
4296 // yes, decrement timer tick
4297 fDriverTimer--;
4298 if ( fDriverTimer == 0 )
4299 {
4300 // controlling driver is tardy
4301 uint64_t nsec = computeTimeDeltaNS(&fDriverCallStartTime);
4302 OUR_PMLog(kPMLogCtrlDriverTardy, 0, 0);
4303 setProperty(kIOPMTardyAckSPSKey, kOSBooleanTrue);
4304 PM_ERROR("%s::setPowerState(%p, %lu -> %lu) timed out after %d ms\n",
4305 fName, this, fCurrentPowerState, fHeadNotePowerState, NS_TO_MS(nsec));
4306
4307 if (gIOKitDebug & kIOLogDebugPower)
4308 {
4309 panic("%s::setPowerState(%p, %lu -> %lu) timed out after %d ms",
4310 fName, this, fCurrentPowerState, fHeadNotePowerState, NS_TO_MS(nsec));
4311 }
4312 else
4313 {
4314 // Unblock state machine and pretend driver has acked.
4315 done = true;
4316 }
4317 } else {
4318 // still waiting, set timer again
4319 start_ack_timer();
4320 }
4321 }
4322 break;
4323
4324 case kIOPM_OurChangeSetPowerState:
4325 case kIOPM_OurChangeFinish:
4326 case kIOPM_ParentDownSetPowerState:
4327 case kIOPM_ParentAcknowledgePowerChange:
4328 case kIOPM_ParentUpSetPowerState:
4329 case kIOPM_NotifyChildrenDone:
4330 // are we waiting for interested parties to acknowledge?
4331 if ( fHeadNotePendingAcks != 0 )
4332 {
4333 // yes, go through the list of interested drivers
4334 nextObject = fInterestedDrivers->firstInList();
4335 // and check each one
4336 while ( nextObject != NULL )
4337 {
4338 if ( nextObject->timer > 0 )
4339 {
4340 nextObject->timer--;
4341 // this one should have acked by now
4342 if ( nextObject->timer == 0 )
4343 {
4344 uint64_t nsec = computeTimeDeltaNS(&nextObject->startTime);
4345 OUR_PMLog(kPMLogIntDriverTardy, 0, 0);
4346 nextObject->whatObject->setProperty(kIOPMTardyAckPSCKey, kOSBooleanTrue);
4347 PM_ERROR("%s::powerState%sChangeTo(%p, %s, %lu -> %lu) timed out after %d ms\n",
4348 nextObject->whatObject->getName(),
4349 (fDriverCallReason == kDriverCallInformPreChange) ? "Will" : "Did",
4350 nextObject->whatObject, fName, fCurrentPowerState, fHeadNotePowerState,
4351 NS_TO_MS(nsec));
4352
4353 // Pretend driver has acked.
4354 fHeadNotePendingAcks--;
4355 }
4356 }
4357 nextObject = fInterestedDrivers->nextInList(nextObject);
4358 }
4359
4360 // is that the last?
4361 if ( fHeadNotePendingAcks == 0 )
4362 {
4363 // yes, we can continue
4364 done = true;
4365 } else {
4366 // no, set timer again
4367 start_ack_timer();
4368 }
4369 }
4370 break;
4371
4372 case kIOPM_ParentDownTellPriorityClientsPowerDown:
4373 case kIOPM_ParentDownNotifyInterestedDriversWillChange:
4374 case kIOPM_OurChangeTellClientsPowerDown:
4375 case kIOPM_OurChangeTellPriorityClientsPowerDown:
4376 case kIOPM_OurChangeNotifyInterestedDriversWillChange:
4377 // apps didn't respond in time
4378 cleanClientResponses(true);
4379 OUR_PMLog(kPMLogClientTardy, 0, 1);
4380 // tardy equates to approval
4381 done = true;
4382 break;
4383
4384 default:
4385 PM_TRACE("%s: unexpected ack timer tick (state = %d)\n",
4386 getName(), fMachineState);
4387 break;
4388 }
4389 return done;
4390}
4391
4392//*********************************************************************************
4393// [private] start_ack_timer
4394//*********************************************************************************
4395
4396void IOService::start_ack_timer ( void )
4397{
4398 start_ack_timer( ACK_TIMER_PERIOD, kNanosecondScale );
4399}
4400
4401void IOService::start_ack_timer ( UInt32 interval, UInt32 scale )
4402{
4403 AbsoluteTime deadline;
4404 boolean_t pending;
4405
4406 clock_interval_to_deadline(interval, scale, &deadline);
4407
4408 retain();
4409 pending = thread_call_enter_delayed(fAckTimer, deadline);
4410 if (pending) release();
4411}
4412
4413//*********************************************************************************
4414// [private] stop_ack_timer
4415//*********************************************************************************
4416
4417void IOService::stop_ack_timer ( void )
4418{
4419 boolean_t pending;
4420
4421 pending = thread_call_cancel(fAckTimer);
4422 if (pending) release();
4423}
4424
4425//*********************************************************************************
4426// [static] actionAckTimerExpired
4427//
4428// Inside PM work loop's gate.
4429//*********************************************************************************
4430
4431IOReturn
4432IOService::actionAckTimerExpired (
4433 OSObject * target,
4434 void * arg0, void * arg1,
4435 void * arg2, void * arg3 )
4436{
4437 IOService * me = (IOService *) target;
4438 bool done;
4439
4440 // done will be true if the timer tick unblocks the machine state,
4441 // otherwise no need to signal the work loop.
4442
4443 done = me->ackTimerTick();
4444 if (done && gIOPMReplyQueue)
4445 gIOPMReplyQueue->signalWorkAvailable();
4446
4447 return kIOReturnSuccess;
4448}
4449
4450//*********************************************************************************
4451// ack_timer_expired
4452//
4453// Thread call function. Holds a retain while the callout is in flight.
4454//*********************************************************************************
4455
4456void
4457IOService::ack_timer_expired ( thread_call_param_t arg0, thread_call_param_t arg1 )
4458{
4459 IOService * me = (IOService *) arg0;
4460
4461 if (gIOPMWorkLoop)
4462 {
4463 gIOPMWorkLoop->runAction(&actionAckTimerExpired, me);
4464 }
4465 me->release();
4466}
4467
4468//*********************************************************************************
4469// [private] notifyControllingDriver
4470//*********************************************************************************
4471
4472bool IOService::notifyControllingDriver ( void )
4473{
4474 DriverCallParam * param;
4475 unsigned long powerState;
4476
4477 PM_ASSERT_IN_GATE();
4478 assert( fDriverCallParamCount == 0 );
4479 assert( fControllingDriver );
4480
4481 powerState = fHeadNotePowerState;
4482
4483 param = (DriverCallParam *) fDriverCallParamPtr;
4484 if (!param)
4485 {
4486 param = IONew(DriverCallParam, 1);
4487 if (!param)
4488 return false; // no memory
4489
4490 fDriverCallParamPtr = (void *) param;
4491 fDriverCallParamSlots = 1;
4492 }
4493
4494 param->Target = fControllingDriver;
4495 fDriverCallParamCount = 1;
4496
4497 fDriverTimer = -1;
4498
4499 // Machine state for this object will stall waiting for a reply
4500 // from the callout thread.
4501
4502 PM_LOCK();
4503 assert( fLockedFlags.DriverCallBusy == false );
4504 fLockedFlags.DriverCallBusy = true;
4505 PM_UNLOCK();
4506 thread_call_enter( fDriverCallEntry );
4507 return true;
4508}
4509
4510//*********************************************************************************
4511// [private] notifyControllingDriverDone
4512//*********************************************************************************
4513
4514void IOService::notifyControllingDriverDone( void )
4515{
4516 DriverCallParam * param;
4517 IOReturn result;
4518
4519 PM_ASSERT_IN_GATE();
4520 param = (DriverCallParam *) fDriverCallParamPtr;
4521
4522 assert( fLockedFlags.DriverCallBusy == false );
4523 assert( fMachineState == kIOPM_DriverThreadCallDone );
4524
4525 if (param)
4526 {
4527 assert(fDriverCallParamCount == 1);
4528
4529 // the return value from setPowerState()
4530 result = param->Result;
4531
4532 if ((result == IOPMAckImplied) || (result < 0))
4533 {
4534 // child return IOPMAckImplied
4535 fDriverTimer = 0;
4536 }
4537 else if (fDriverTimer)
4538 {
4539 assert(fDriverTimer == -1);
4540
4541 // Driver has not acked, and has returned a positive result.
4542 // Enforce a minimum permissible timeout value.
4543 // Make the min value large enough so timeout is less likely
4544 // to occur if a driver misinterpreted that the return value
4545 // should be in microsecond units. And make it large enough
4546 // to be noticeable if a driver neglects to ack.
4547
4548 if (result < kMinAckTimeoutTicks)
4549 result = kMinAckTimeoutTicks;
4550
4551 fDriverTimer = (result / (ACK_TIMER_PERIOD / ns_per_us)) + 1;
4552 }
4553 // else, child has already acked and driver_timer reset to 0.
4554
4555 fDriverCallParamCount = 0;
4556
4557 if ( fDriverTimer )
4558 {
4559 OUR_PMLog(kPMLogStartAckTimer, 0, 0);
4560 start_ack_timer();
4561 }
4562 }
4563
4564 // Hop back to original machine state path.
4565 fMachineState = fNextMachineState;
4566}
4567
4568//*********************************************************************************
4569// [public] askChangeDown
4570//
4571// Ask registered applications and kernel clients if we can change to a lower
4572// power state.
4573//
4574// Subclass can override this to send a different message type. Parameter is
4575// the destination state number.
4576//
4577// Return true if we don't have to wait for acknowledgements
4578//*********************************************************************************
4579
4580bool IOService::askChangeDown ( unsigned long stateNum )
4581{
4582 return tellClientsWithResponse( kIOMessageCanDevicePowerOff );
4583}
4584
4585//*********************************************************************************
4586// [private] tellChangeDown1
4587//
4588// Notify registered applications and kernel clients that we are definitely
4589// dropping power.
4590//
4591// Return true if we don't have to wait for acknowledgements
4592//*********************************************************************************
4593
4594bool IOService::tellChangeDown1 ( unsigned long stateNum )
4595{
4596 fOutOfBandParameter = kNotifyApps;
4597 return tellChangeDown(stateNum);
4598}
4599
4600//*********************************************************************************
4601// [private] tellChangeDown2
4602//
4603// Notify priority clients that we are definitely dropping power.
4604//
4605// Return true if we don't have to wait for acknowledgements
4606//*********************************************************************************
4607
4608bool IOService::tellChangeDown2 ( unsigned long stateNum )
4609{
4610 fOutOfBandParameter = kNotifyPriority;
4611 return tellChangeDown(stateNum);
4612}
4613
4614//*********************************************************************************
4615// [public] tellChangeDown
4616//
4617// Notify registered applications and kernel clients that we are definitely
4618// dropping power.
4619//
4620// Subclass can override this to send a different message type. Parameter is
4621// the destination state number.
4622//
4623// Return true if we don't have to wait for acknowledgements
4624//*********************************************************************************
4625
4626bool IOService::tellChangeDown ( unsigned long stateNum )
4627{
4628 return tellClientsWithResponse( kIOMessageDeviceWillPowerOff );
4629}
4630
4631//*********************************************************************************
4632// cleanClientResponses
4633//
4634//*********************************************************************************
4635
4636static void logAppTimeouts ( OSObject * object, void * arg )
4637{
4638 IOPMInterestContext * context = (IOPMInterestContext *) arg;
4639 OSObject * flag;
4640 unsigned int clientIndex;
4641
4642 if (OSDynamicCast(_IOServiceInterestNotifier, object))
4643 {
4644 // Discover the 'counter' value or index assigned to this client
4645 // when it was notified, by searching for the array index of the
4646 // client in an array holding the cached interested clients.
4647
4648 clientIndex = context->notifyClients->getNextIndexOfObject(object, 0);
4649
4650 if ((clientIndex != (unsigned int) -1) &&
4651 (flag = context->responseFlags->getObject(clientIndex)) &&
4652 (flag != kOSBooleanTrue))
4653 {
4654 OSString * clientID = 0;
4655 context->us->messageClient(context->msgType, object, &clientID);
4656 PM_ERROR(context->errorLog, clientID ? clientID->getCStringNoCopy() : "");
4657
4658 // TODO: record message type if possible
4659 IOService::getPMRootDomain()->pmStatsRecordApplicationResponse(
4660 gIOPMStatsApplicationResponseTimedOut,
4661 clientID ? clientID->getCStringNoCopy() : "",
4662 0, (30*1000), -1);
4663
4664 if (clientID)
4665 clientID->release();
4666 }
4667 }
4668}
4669
4670void IOService::cleanClientResponses ( bool logErrors )
4671{
4672 IOPMInterestContext context;
4673
4674 if (logErrors && fResponseArray && fNotifyClientArray) {
4675 context.responseFlags = fResponseArray;
4676 context.notifyClients = fNotifyClientArray;
4677 context.serialNumber = fSerialNumber;
4678 context.counter = 0;
4679 context.msgType = kIOMessageCopyClientID;
4680 context.us = this;
4681 context.maxTimeRequested = 0;
4682 context.stateNumber = fHeadNotePowerState;
4683 context.stateFlags = fHeadNotePowerArrayEntry->capabilityFlags;
4684 context.errorLog = "PM notification timeout (%s)\n";
4685
4686 switch ( fOutOfBandParameter ) {
4687 case kNotifyApps:
4688 applyToInterested(gIOAppPowerStateInterest, logAppTimeouts, (void *) &context);
4689 case kNotifyPriority:
4690 default:
4691 break;
4692 }
4693 }
4694
4695 if (fResponseArray)
4696 {
4697 // get rid of this stuff
4698 fResponseArray->release();
4699 fResponseArray = NULL;
4700 }
4701 if (fNotifyClientArray)
4702 {
4703 fNotifyClientArray->release();
4704 fNotifyClientArray = NULL;
4705 }
4706
4707 return;
4708}
4709
4710//*********************************************************************************
4711// [protected] tellClientsWithResponse
4712//
4713// Notify registered applications and kernel clients that we are definitely
4714// dropping power.
4715//
4716// Return true if we don't have to wait for acknowledgements
4717//*********************************************************************************
4718
4719bool IOService::tellClientsWithResponse (
4720 int messageType )
4721{
4722 return tellClientsWithResponse( messageType, 0 );
4723}
4724
4725bool IOService::tellClientsWithResponse (
4726 int messageType,
4727 IOPMMessageFilter filter )
4728{
4729 IOPMInterestContext context;
4730
4731 PM_ASSERT_IN_GATE();
4732 assert( fResponseArray == NULL );
4733 assert( fNotifyClientArray == NULL );
4734
4735 fResponseArray = OSArray::withCapacity( 1 );
4736 if (!fResponseArray)
4737 goto exit;
4738
4739 fResponseArray->setCapacityIncrement(8);
4740 fSerialNumber += 1;
4741
4742 context.responseFlags = fResponseArray;
4743 context.notifyClients = 0;
4744 context.serialNumber = fSerialNumber;
4745 context.counter = 0;
4746 context.msgType = messageType;
4747 context.us = this;
4748 context.maxTimeRequested = 0;
4749 context.stateNumber = fHeadNotePowerState;
4750 context.stateFlags = fHeadNotePowerArrayEntry->capabilityFlags;
4751 context.filterFunc = filter;
4752
4753 switch ( fOutOfBandParameter ) {
4754 case kNotifyApps:
4755 applyToInterested( gIOAppPowerStateInterest,
4756 pmTellAppWithResponse, (void *) &context );
4757 fNotifyClientArray = context.notifyClients;
4758
4759 applyToInterested( gIOGeneralInterest,
4760 pmTellClientWithResponse, (void *) &context );
4761 break;
4762
4763 case kNotifyPriority:
4764 applyToInterested( gIOPriorityPowerStateInterest,
4765 pmTellClientWithResponse, (void *) &context );
4766 break;
4767 }
4768
4769 // do we have to wait for somebody?
4770 if ( !checkForDone() )
4771 {
4772 OUR_PMLog(kPMLogStartAckTimer, context.maxTimeRequested, 0);
4773 start_ack_timer( context.maxTimeRequested / 1000, kMillisecondScale );
4774 return false;
4775 }
4776
4777exit:
4778 // everybody responded
4779 if (fResponseArray)
4780 {
4781 fResponseArray->release();
4782 fResponseArray = NULL;
4783 }
4784 if (fNotifyClientArray)
4785 {
4786 fNotifyClientArray->release();
4787 fNotifyClientArray = NULL;
4788 }
4789
4790 return true;
4791}
4792
4793//*********************************************************************************
4794// [static private] pmTellAppWithResponse
4795//
4796// We send a message to an application, and we expect a response, so we compute a
4797// cookie we can identify the response with.
4798//*********************************************************************************
4799
4800void IOService::pmTellAppWithResponse ( OSObject * object, void * arg )
4801{
4802 IOPMInterestContext * context = (IOPMInterestContext *) arg;
4803 IOServicePM * pwrMgt = context->us->pwrMgt;
4804 AbsoluteTime now;
4805 UInt32 refcon;
4806
4807 if (!OSDynamicCast(_IOServiceInterestNotifier, object))
4808 {
4809 // object must be an _IOServiceInterestNotifier.
4810 return;
4811 }
4812
4813 // Lazily create app clients array.
4814 if (0 == context->notifyClients)
4815 {
4816 context->notifyClients = OSArray::withCapacity( 32 );
4817 }
4818
4819 if (context->filterFunc && !context->filterFunc(object, arg))
4820 {
4821 // ack - needed to match the counter index at logAppTimeouts().
4822 context->responseFlags->setObject(context->counter, kOSBooleanTrue);
4823 if (context->notifyClients)
4824 context->notifyClients->setObject(context->counter, kOSBooleanTrue);
4825 }
4826 else
4827 {
4828 refcon = ((context->serialNumber & 0xFFFF)<<16)
4829 + (context->counter & 0xFFFF);
4830 OUR_PMLog(kPMLogAppNotify, context->msgType, refcon);
4831
4832 if (gIOKitDebug & kIOLogDebugPower)
4833 {
4834 // Log client pid/name and associated index.
4835 OSString * clientID = 0;
4836 context->us->messageClient(kIOMessageCopyClientID, object, &clientID);
4837 PM_DEBUG("[Notify %u] message 0x%x to %s\n",
4838 (uint32_t) context->counter,
4839 context->msgType,
4840 clientID ? clientID->getCStringNoCopy() : "");
4841 if (clientID) clientID->release();
4842 }
4843
4844#if LOG_APP_RESPONSE_TIMES
4845 OSNumber * num;
4846 clock_get_uptime(&now);
4847 num = OSNumber::withNumber(AbsoluteTime_to_scalar(&now), sizeof(uint64_t) * 8);
4848 if (num)
4849 {
4850 context->responseFlags->setObject(context->counter, num);
4851 num->release();
4852 }
4853 else
4854#endif
4855 context->responseFlags->setObject(context->counter, kOSBooleanFalse);
4856
4857 if (context->notifyClients)
4858 context->notifyClients->setObject(context->counter, object);
4859
4860 context->us->messageClient(context->msgType, object, (void *)refcon);
4861 if ( context->maxTimeRequested < k30seconds )
4862 {
4863 context->maxTimeRequested = k30seconds;
4864 }
4865 }
4866
4867 context->counter++;
4868}
4869
4870//*********************************************************************************
4871// [static private] pmTellClientWithResponse
4872//
4873// We send a message to an in-kernel client, and we expect a response, so we compute a
4874// cookie we can identify the response with.
4875// If it doesn't understand the notification (it is not power-management savvy)
4876// we won't wait for it to prepare for sleep. If it tells us via a return code
4877// in the passed struct that it is currently ready, we won't wait for it to prepare.
4878// If it tells us via the return code in the struct that it does need time, we will chill.
4879//*********************************************************************************
4880
4881void IOService::pmTellClientWithResponse ( OSObject * object, void * arg )
4882{
4883 IOPMInterestContext * context = (IOPMInterestContext *) arg;
4884 IOPowerStateChangeNotification notify;
4885 UInt32 refcon;
4886 IOReturn retCode;
4887 OSObject * theFlag;
4888
4889 if (context->filterFunc && !context->filterFunc(object, arg))
4890 return;
4891
4892 refcon = ((context->serialNumber & 0xFFFF)<<16) + (context->counter & 0xFFFF);
4893 context->responseFlags->setObject(context->counter, kOSBooleanFalse);
4894
4895 IOServicePM * pwrMgt = context->us->pwrMgt;
4896 if (gIOKitDebug & kIOLogPower) {
4897 OUR_PMLog(kPMLogClientNotify, refcon, (UInt32) context->msgType);
4898 if (OSDynamicCast(IOService, object)) {
4899 const char *who = ((IOService *) object)->getName();
4900 gPlatform->PMLog(who,
4901 kPMLogClientNotify, * (UInt32 *) object, (UInt64) object);
4902 } else if (OSDynamicCast(_IOServiceInterestNotifier, object)) {
4903 _IOServiceInterestNotifier *n = (_IOServiceInterestNotifier *) object;
4904 OUR_PMLog(kPMLogClientNotify, (UInt64) n->handler, 0);
4905 }
4906 }
4907
4908 notify.powerRef = (void *)refcon;
4909 notify.returnValue = 0;
4910 notify.stateNumber = context->stateNumber;
4911 notify.stateFlags = context->stateFlags;
4912 retCode = context->us->messageClient(context->msgType,object,(void *)&notify);
4913 if ( retCode == kIOReturnSuccess )
4914 {
4915 if ( notify.returnValue == 0 )
4916 {
4917 // client doesn't want time to respond
4918 context->responseFlags->replaceObject(context->counter, kOSBooleanTrue);
4919 OUR_PMLog(kPMLogClientAcknowledge, refcon, (UInt64) object);
4920 } else {
4921 // it does want time, and it hasn't responded yet
4922 theFlag = context->responseFlags->getObject(context->counter);
4923 if ( kOSBooleanTrue != theFlag )
4924 {
4925 // so note its time requirement
4926 if ( context->maxTimeRequested < notify.returnValue )
4927 {
4928 context->maxTimeRequested = notify.returnValue;
4929 }
4930 }
4931 }
4932 } else {
4933 OUR_PMLog(kPMLogClientAcknowledge, refcon, 0);
4934 // not a client of ours
4935 // so we won't be waiting for response
4936 context->responseFlags->replaceObject(context->counter, kOSBooleanTrue);
4937 }
4938 context->counter++;
4939}
4940
4941//*********************************************************************************
4942// [public] tellNoChangeDown
4943//
4944// Notify registered applications and kernel clients that we are not
4945// dropping power.
4946//
4947// Subclass can override this to send a different message type. Parameter is
4948// the aborted destination state number.
4949//*********************************************************************************
4950
4951void IOService::tellNoChangeDown ( unsigned long )
4952{
4953 return tellClients( kIOMessageDeviceWillNotPowerOff );
4954}
4955
4956//*********************************************************************************
4957// [public] tellChangeUp
4958//
4959// Notify registered applications and kernel clients that we are raising power.
4960//
4961// Subclass can override this to send a different message type. Parameter is
4962// the aborted destination state number.
4963//*********************************************************************************
4964
4965void IOService::tellChangeUp ( unsigned long )
4966{
4967 return tellClients( kIOMessageDeviceHasPoweredOn );
4968}
4969
4970//*********************************************************************************
4971// [protected] tellClients
4972//
4973// Notify registered applications and kernel clients of something.
4974//*********************************************************************************
4975
4976void IOService::tellClients ( int messageType )
4977{
4978 tellClients( messageType, 0 );
4979}
4980
4981void IOService::tellClients ( int messageType, IOPMMessageFilter filter )
4982{
4983 IOPMInterestContext context;
4984
4985 context.msgType = messageType;
4986 context.us = this;
4987 context.stateNumber = fHeadNotePowerState;
4988 context.stateFlags = fHeadNotePowerArrayEntry->capabilityFlags;
4989 context.filterFunc = filter;
4990
4991 applyToInterested( gIOPriorityPowerStateInterest,
4992 tellKernelClientApplier, (void *) &context );
4993
4994 applyToInterested( gIOAppPowerStateInterest,
4995 tellAppClientApplier, (void *) &context );
4996
4997 applyToInterested( gIOGeneralInterest,
4998 tellKernelClientApplier, (void *) &context );
4999}
5000
5001//*********************************************************************************
5002// [private] tellKernelClientApplier
5003//
5004// Message a kernel client.
5005//*********************************************************************************
5006
5007static void tellKernelClientApplier ( OSObject * object, void * arg )
5008{
5009 IOPMInterestContext * context = (IOPMInterestContext *) arg;
5010 IOPowerStateChangeNotification notify;
5011
5012 if (context->filterFunc && !context->filterFunc(object, arg))
5013 return;
5014
5015 notify.powerRef = (void *) 0;
5016 notify.returnValue = 0;
5017 notify.stateNumber = context->stateNumber;
5018 notify.stateFlags = context->stateFlags;
5019
5020 context->us->messageClient(context->msgType, object, &notify);
5021}
5022
5023//*********************************************************************************
5024// [private] tellAppClientApplier
5025//
5026// Message a registered application.
5027//*********************************************************************************
5028
5029static void tellAppClientApplier ( OSObject * object, void * arg )
5030{
5031 IOPMInterestContext * context = (IOPMInterestContext *) arg;
5032
5033 if (context->filterFunc && !context->filterFunc(object, arg))
5034 return;
5035
5036 context->us->messageClient(context->msgType, object, 0);
5037}
5038
5039//*********************************************************************************
5040// [private] checkForDone
5041//*********************************************************************************
5042
5043bool IOService::checkForDone ( void )
5044{
5045 int i = 0;
5046 OSObject * theFlag;
5047
5048 if ( fResponseArray == NULL )
5049 {
5050 return true;
5051 }
5052
5053 for ( i = 0; ; i++ )
5054 {
5055 theFlag = fResponseArray->getObject(i);
5056 if ( theFlag == NULL )
5057 {
5058 break;
5059 }
5060 if ( kOSBooleanTrue != theFlag )
5061 {
5062 return false;
5063 }
5064 }
5065 return true;
5066}
5067
5068//*********************************************************************************
5069// [public] responseValid
5070//*********************************************************************************
5071
5072bool IOService::responseValid ( unsigned long x, int pid )
5073{
5074 UInt16 serialComponent;
5075 UInt16 ordinalComponent;
5076 OSObject * theFlag;
5077 unsigned long refcon = (unsigned long) x;
5078
5079 serialComponent = (refcon >> 16) & 0xFFFF;
5080 ordinalComponent = (refcon & 0xFFFF);
5081
5082 if ( serialComponent != fSerialNumber )
5083 {
5084 return false;
5085 }
5086
5087 if ( fResponseArray == NULL )
5088 {
5089 return false;
5090 }
5091
5092 theFlag = fResponseArray->getObject(ordinalComponent);
5093
5094 if ( theFlag == 0 )
5095 {
5096 return false;
5097 }
5098
5099 OSNumber * num;
5100 if ((num = OSDynamicCast(OSNumber, theFlag)))
5101 {
5102#if LOG_APP_RESPONSE_TIMES
5103 AbsoluteTime now;
5104 AbsoluteTime start;
5105 uint64_t nsec;
5106
5107 clock_get_uptime(&now);
5108 AbsoluteTime_to_scalar(&start) = num->unsigned64BitValue();
5109 SUB_ABSOLUTETIME(&now, &start);
5110 absolutetime_to_nanoseconds(now, &nsec);
5111
5112 // > 100 ms
5113 if (nsec > LOG_APP_RESPONSE_TIMES)
5114 {
5115 OSString * name = IOCopyLogNameForPID(pid);
5116 PM_DEBUG("PM response took %d ms (%s)\n", NS_TO_MS(nsec),
5117 name ? name->getCStringNoCopy() : "");
5118
5119 if (nsec > LOG_APP_RESPONSE_MSG_TRACER)
5120 {
5121 // TODO: populate the messageType argument
5122 getPMRootDomain()->pmStatsRecordApplicationResponse(
5123 gIOPMStatsApplicationResponseSlow,
5124 name ? name->getCStringNoCopy() : "", 0,
5125 NS_TO_MS(nsec), pid);
5126 }
5127
5128 if (name)
5129 name->release();
5130 }
5131#endif
5132 theFlag = kOSBooleanFalse;
5133 }
5134
5135 if ( kOSBooleanFalse == theFlag )
5136 {
5137 if ((gIOKitDebug & kIOLogDebugPower) &&
5138 (fOutOfBandParameter == kNotifyApps))
5139 {
5140 PM_DEBUG("[Notify %u] acked\n", (uint32_t) ordinalComponent);
5141 }
5142 fResponseArray->replaceObject(ordinalComponent, kOSBooleanTrue);
5143 }
5144
5145 return true;
5146}
5147
5148//*********************************************************************************
5149// [public] allowPowerChange
5150//
5151// Our power state is about to lower, and we have notified applications
5152// and kernel clients, and one of them has acknowledged. If this is the last to do
5153// so, and all acknowledgements are positive, we continue with the power change.
5154//
5155// We serialize this processing with timer expiration with a command gate on the
5156// power management workloop, which the timer expiration is command gated to as well.
5157//*********************************************************************************
5158
5159IOReturn IOService::allowPowerChange ( unsigned long refcon )
5160{
5161 IOPMRequest * request;
5162
5163 if ( !initialized )
5164 {
5165 // we're unloading
5166 return kIOReturnSuccess;
5167 }
5168
5169 request = acquirePMRequest( this, kIOPMRequestTypeAllowPowerChange );
5170 if (!request)
5171 return kIOReturnNoMemory;
5172
5173 request->fArg0 = (void *) refcon;
5174 request->fArg1 = (void *) proc_selfpid();
5175 request->fArg2 = (void *) 0;
5176 submitPMRequest( request );
5177
5178 return kIOReturnSuccess;
5179}
5180
5181#ifndef __LP64__
5182IOReturn IOService::serializedAllowPowerChange2 ( unsigned long refcon )
5183{
5184 // [deprecated] public
5185 return kIOReturnUnsupported;
5186}
5187#endif /* !__LP64__ */
5188
5189//*********************************************************************************
5190// [public] cancelPowerChange
5191//
5192// Our power state is about to lower, and we have notified applications
5193// and kernel clients, and one of them has vetoed the change. If this is the last
5194// client to respond, we abandon the power change.
5195//
5196// We serialize this processing with timer expiration with a command gate on the
5197// power management workloop, which the timer expiration is command gated to as well.
5198//*********************************************************************************
5199
5200IOReturn IOService::cancelPowerChange ( unsigned long refcon )
5201{
5202 IOPMRequest * request;
5203 OSString * name;
5204
5205 if ( !initialized )
5206 {
5207 // we're unloading
5208 return kIOReturnSuccess;
5209 }
5210
5211 name = IOCopyLogNameForPID(proc_selfpid());
5212 PM_ERROR("PM notification cancel (%s)\n", name ? name->getCStringNoCopy() : "");
5213
5214 request = acquirePMRequest( this, kIOPMRequestTypeCancelPowerChange );
5215 if (!request)
5216 {
5217 if (name)
5218 name->release();
5219 return kIOReturnNoMemory;
5220 }
5221
5222 request->fArg0 = (void *) refcon;
5223 request->fArg1 = (void *) proc_selfpid();
5224 request->fArg2 = (void *) name;
5225 submitPMRequest( request );
5226
5227 return kIOReturnSuccess;
5228}
5229
5230#ifndef __LP64__
5231IOReturn IOService::serializedCancelPowerChange2 ( unsigned long refcon )
5232{
5233 // [deprecated] public
5234 return kIOReturnUnsupported;
5235}
5236
5237//*********************************************************************************
5238// PM_Clamp_Timer_Expired
5239//
5240// called when clamp timer expires...set power state to 0.
5241//*********************************************************************************
5242
5243void IOService::PM_Clamp_Timer_Expired ( void )
5244{
5245}
5246
5247//*********************************************************************************
5248// clampPowerOn
5249//
5250// Set to highest available power state for a minimum of duration milliseconds
5251//*********************************************************************************
5252
5253void IOService::clampPowerOn ( unsigned long duration )
5254{
5255}
5256#endif /* !__LP64__ */
5257
5258//*********************************************************************************
5259// [public] setPowerState
5260//
5261// Does nothing here. This should be implemented in a subclass driver.
5262//*********************************************************************************
5263
5264IOReturn IOService::setPowerState (
5265 unsigned long powerStateOrdinal, IOService * whatDevice )
5266{
5267 return IOPMNoErr;
5268}
5269
5270//*********************************************************************************
5271// [public] maxCapabilityForDomainState
5272//
5273// Finds the highest power state in the array whose input power
5274// requirement is equal to the input parameter. Where a more intelligent
5275// decision is possible, override this in the subclassed driver.
5276//*********************************************************************************
5277
5278unsigned long IOService::maxCapabilityForDomainState ( IOPMPowerFlags domainState )
5279{
5280 int i;
5281
5282 if (fNumberOfPowerStates == 0 )
5283 {
5284 return 0;
5285 }
5286 for ( i = fNumberOfPowerStates - 1; i >= 0; i-- )
5287 {
5288 if ( (domainState & fPowerStates[i].inputPowerRequirement) ==
5289 fPowerStates[i].inputPowerRequirement )
5290 {
5291 return i;
5292 }
5293 }
5294 return 0;
5295}
5296
5297//*********************************************************************************
5298// [public] initialPowerStateForDomainState
5299//
5300// Finds the highest power state in the array whose input power
5301// requirement is equal to the input parameter. Where a more intelligent
5302// decision is possible, override this in the subclassed driver.
5303//*********************************************************************************
5304
5305unsigned long IOService::initialPowerStateForDomainState ( IOPMPowerFlags domainState )
5306{
5307 int i;
5308
5309 if (fNumberOfPowerStates == 0 )
5310 {
5311 return 0;
5312 }
5313 for ( i = fNumberOfPowerStates - 1; i >= 0; i-- )
5314 {
5315 if ( (domainState & fPowerStates[i].inputPowerRequirement) ==
5316 fPowerStates[i].inputPowerRequirement )
5317 {
5318 return i;
5319 }
5320 }
5321 return 0;
5322}
5323
5324//*********************************************************************************
5325// [public] powerStateForDomainState
5326//
5327// Finds the highest power state in the array whose input power
5328// requirement is equal to the input parameter. Where a more intelligent
5329// decision is possible, override this in the subclassed driver.
5330//*********************************************************************************
5331
5332unsigned long IOService::powerStateForDomainState ( IOPMPowerFlags domainState )
5333{
5334 int i;
5335
5336 if (fNumberOfPowerStates == 0 )
5337 {
5338 return 0;
5339 }
5340 for ( i = fNumberOfPowerStates - 1; i >= 0; i-- )
5341 {
5342 if ( (domainState & fPowerStates[i].inputPowerRequirement) ==
5343 fPowerStates[i].inputPowerRequirement )
5344 {
5345 return i;
5346 }
5347 }
5348 return 0;
5349}
5350
5351#ifndef __LP64__
5352//*********************************************************************************
5353// [deprecated] didYouWakeSystem
5354//
5355// Does nothing here. This should be implemented in a subclass driver.
5356//*********************************************************************************
5357
5358bool IOService::didYouWakeSystem ( void )
5359{
5360 return false;
5361}
5362#endif /* !__LP64__ */
5363
5364//*********************************************************************************
5365// [public] powerStateWillChangeTo
5366//
5367// Does nothing here. This should be implemented in a subclass driver.
5368//*********************************************************************************
5369
5370IOReturn IOService::powerStateWillChangeTo ( IOPMPowerFlags, unsigned long, IOService * )
5371{
5372 return kIOPMAckImplied;
5373}
5374
5375//*********************************************************************************
5376// [public] powerStateDidChangeTo
5377//
5378// Does nothing here. This should be implemented in a subclass driver.
5379//*********************************************************************************
5380
5381IOReturn IOService::powerStateDidChangeTo ( IOPMPowerFlags, unsigned long, IOService * )
5382{
5383 return kIOPMAckImplied;
5384}
5385
5386//*********************************************************************************
5387// [protected] powerChangeDone
5388//
5389// Called from PM work loop thread.
5390// Does nothing here. This should be implemented in a subclass policy-maker.
5391//*********************************************************************************
5392
5393void IOService::powerChangeDone ( unsigned long )
5394{
5395}
5396
5397#ifndef __LP64__
5398//*********************************************************************************
5399// [deprecated] newTemperature
5400//
5401// Does nothing here. This should be implemented in a subclass driver.
5402//*********************************************************************************
5403
5404IOReturn IOService::newTemperature ( long currentTemp, IOService * whichZone )
5405{
5406 return IOPMNoErr;
5407}
5408#endif /* !__LP64__ */
5409
5410//*********************************************************************************
5411// [public] systemWillShutdown
5412//
5413// System shutdown and restart notification.
5414//*********************************************************************************
5415
5416void IOService::systemWillShutdown( IOOptionBits specifier )
5417{
5418 IOPMrootDomain * rootDomain = IOService::getPMRootDomain();
5419 if (rootDomain)
5420 rootDomain->acknowledgeSystemWillShutdown( this );
5421}
5422
5423//*********************************************************************************
5424// [private static] acquirePMRequest
5425//*********************************************************************************
5426
5427IOPMRequest *
5428IOService::acquirePMRequest( IOService * target, IOOptionBits requestType,
5429 IOPMRequest * active )
5430{
5431 IOPMRequest * request;
5432
5433 assert(target);
5434
5435 request = IOPMRequest::create();
5436 if (request)
5437 {
5438 request->init( target, requestType );
5439 if (active)
5440 {
5441 IOPMRequest * root = active->getRootRequest();
5442 if (root) request->attachRootRequest(root);
5443 }
5444 }
5445 else
5446 {
5447 PM_ERROR("%s: No memory for PM request type 0x%x\n",
5448 target->getName(), (uint32_t) requestType);
5449 }
5450 return request;
5451}
5452
5453//*********************************************************************************
5454// [private static] releasePMRequest
5455//*********************************************************************************
5456
5457void IOService::releasePMRequest( IOPMRequest * request )
5458{
5459 if (request)
5460 {
5461 request->reset();
5462 request->release();
5463 }
5464}
5465
5466//*********************************************************************************
5467// [private] submitPMRequest
5468//*********************************************************************************
5469
5470void IOService::submitPMRequest( IOPMRequest * request )
5471{
5472 assert( request );
5473 assert( gIOPMReplyQueue );
5474 assert( gIOPMRequestQueue );
5475
5476 PM_TRACE("[+ %02lx] %p [%p %s] %p %p %p\n",
5477 (long)request->getType(), request,
5478 request->getTarget(), request->getTarget()->getName(),
5479 request->fArg0, request->fArg1, request->fArg2);
5480
5481 if (request->isReplyType())
5482 gIOPMReplyQueue->queuePMRequest( request );
5483 else
5484 gIOPMRequestQueue->queuePMRequest( request );
5485}
5486
5487void IOService::submitPMRequest( IOPMRequest ** requests, IOItemCount count )
5488{
5489 assert( requests );
5490 assert( count > 0 );
5491 assert( gIOPMRequestQueue );
5492
5493 for (IOItemCount i = 0; i < count; i++)
5494 {
5495 IOPMRequest * req = requests[i];
5496 PM_TRACE("[+ %02lx] %p [%p %s] %p %p %p\n",
5497 (long)req->getType(), req,
5498 req->getTarget(), req->getTarget()->getName(),
5499 req->fArg0, req->fArg1, req->fArg2);
5500 }
5501
5502 gIOPMRequestQueue->queuePMRequestChain( requests, count );
5503}
5504
5505//*********************************************************************************
5506// [private] servicePMRequestQueue
5507//*********************************************************************************
5508
5509bool IOService::servicePMRequestQueue(
5510 IOPMRequest * request,
5511 IOPMRequestQueue * queue )
5512{
5513 // Calling PM methods without PMinit() is not allowed, fail the requests.
5514
5515 if (!initialized)
5516 {
5517 PM_DEBUG("%s: PM not initialized\n", getName());
5518 goto done;
5519 }
5520
5521 // Create an IOPMWorkQueue on demand, when the initial PM request is
5522 // received.
5523
5524 if (!fPMWorkQueue)
5525 {
5526 // Allocate and attach an IOPMWorkQueue on demand to avoid taking
5527 // the work loop lock in PMinit(), which may deadlock with certain
5528 // drivers / families.
5529
5530 fPMWorkQueue = IOPMWorkQueue::create(
5531 /* target */ this,
5532 /* Work */ OSMemberFunctionCast(IOPMWorkQueue::Action, this,
5533 &IOService::servicePMRequest),
5534 /* Done */ OSMemberFunctionCast(IOPMWorkQueue::Action, this,
5535 &IOService::retirePMRequest)
5536 );
5537
5538 if (fPMWorkQueue &&
5539 (gIOPMWorkLoop->addEventSource(fPMWorkQueue) != kIOReturnSuccess))
5540 {
5541 PM_ERROR("%s: add PM work queue failed\n", getName());
5542 fPMWorkQueue->release();
5543 fPMWorkQueue = 0;
5544 }
5545
5546 if (!fPMWorkQueue)
5547 {
5548 PM_ERROR("%s: no PM work queue (type %02lx)\n",
5549 getName(), (long)request->getType());
5550 goto done;
5551 }
5552 }
5553
5554 fPMWorkQueue->queuePMRequest(request);
5555 return false; // do not signal more
5556
5557done:
5558 fAdjustPowerScheduled = false;
5559 gIOPMFreeQueue->queuePMRequest(request);
5560 return false; // do not signal more
5561}
5562
5563//*********************************************************************************
5564// [private] servicePMFreeQueue
5565//
5566// Called by the request completion to recycle a completed request.
5567//*********************************************************************************
5568
5569bool IOService::servicePMFreeQueue(
5570 IOPMRequest * request,
5571 IOPMCompletionQueue * queue )
5572{
5573 bool more = request->getNextRequest();
5574 IOPMRequest * root = request->getRootRequest();
5575
5576 if (root && (root != request))
5577 more = true;
5578
5579 if (fLockedFlags.PMStop && fPMWorkQueue && fPMWorkQueue->isEmpty())
5580 {
5581 // Driver PMstop'ed and the work queue is empty.
5582 // Detach and destroy the work queue to avoid the similar cleanup by
5583 // PMfree(), which is deadlock prone. After PMstop() if driver calls PM,
5584 // or a request from power parent or child arrives, it is possible to
5585 // create/cleanup work queue more than once. Should be rare.
5586
5587 gIOPMWorkLoop->removeEventSource(fPMWorkQueue);
5588 fPMWorkQueue->release();
5589 fPMWorkQueue = 0;
5590
5591 if ( fIdleTimerEventSource != NULL ) {
5592 fIdleTimerEventSource->disable();
5593 gIOPMWorkLoop->removeEventSource(fIdleTimerEventSource);
5594 fIdleTimerEventSource->release();
5595 fIdleTimerEventSource = NULL;
5596 }
5597 }
5598
5599 releasePMRequest( request );
5600 return more;
5601}
5602
5603//*********************************************************************************
5604// [private] retirePMRequest
5605//
5606// Called by IOPMWorkQueue to retire a completed request.
5607//*********************************************************************************
5608
5609bool IOService::retirePMRequest( IOPMRequest * request, IOPMWorkQueue * queue )
5610{
5611 assert(request && queue);
5612
5613 PM_TRACE("[- %02x] %p [%p %s] State %d, Busy %d\n",
5614 request->getType(), request, this, getName(),
5615 fMachineState, gIOPMBusyCount);
5616
5617 // Catch requests created by idleTimerExpired().
5618
5619 if ((request->getType() == kIOPMRequestTypeActivityTickle) &&
5620 (request->fArg1 == (void *) false))
5621 {
5622 // Idle timer power drop request completed.
5623 // Restart the idle timer if deviceDesire can go lower, otherwise set
5624 // a flag so we know to restart idle timer when deviceDesire goes up.
5625
5626 if (fDeviceDesire > 0)
5627 {
5628 fActivityTickleCount = 0;
5629 clock_get_uptime(&fIdleTimerStartTime);
5630 start_PM_idle_timer();
5631 }
5632 else
5633 fIdleTimerStopped = true;
5634 }
5635
5636 gIOPMFreeQueue->queuePMRequest( request );
5637 return true;
5638}
5639
5640//*********************************************************************************
5641// [private] isPMBlocked
5642//
5643// Check if machine state transition is blocked.
5644//*********************************************************************************
5645
5646bool IOService::isPMBlocked ( IOPMRequest * request, int count )
5647{
5648 int reason = 0;
5649
5650 do {
5651 if (kIOPM_Finished == fMachineState)
5652 break;
5653
5654 if (kIOPM_DriverThreadCallDone == fMachineState)
5655 {
5656 // 5 = kDriverCallInformPreChange
5657 // 6 = kDriverCallInformPostChange
5658 // 7 = kDriverCallSetPowerState
5659 if (fLockedFlags.DriverCallBusy) reason = 5 + fDriverCallReason;
5660 break;
5661 }
5662
5663 // Waiting on driver's setPowerState() timeout.
5664 if (fDriverTimer)
5665 {
5666 reason = 1; break;
5667 }
5668
5669 // Child or interested driver acks pending.
5670 if (fHeadNotePendingAcks)
5671 {
5672 reason = 2; break;
5673 }
5674
5675 // Waiting on apps or priority power interest clients.
5676 if (fResponseArray)
5677 {
5678 reason = 3; break;
5679 }
5680
5681 // Waiting on settle timer expiration.
5682 if (fSettleTimeUS)
5683 {
5684 reason = 4; break;
5685 }
5686 } while (false);
5687
5688 fWaitReason = reason;
5689
5690 if (reason)
5691 {
5692 if (count)
5693 {
5694 PM_TRACE("[B %02x] %p [%p %s] State %d, Reason %d\n",
5695 request->getType(), request, this, getName(),
5696 fMachineState, reason);
5697 }
5698
5699 return true;
5700 }
5701
5702 return false;
5703}
5704
5705//*********************************************************************************
5706// [private] servicePMRequest
5707//
5708// Service a request from our work queue.
5709//*********************************************************************************
5710
5711bool IOService::servicePMRequest( IOPMRequest * request, IOPMWorkQueue * queue )
5712{
5713 bool done = false;
5714 int loop = 0;
5715
5716 assert(request && queue);
5717
5718 while (isPMBlocked(request, loop++) == false)
5719 {
5720 PM_TRACE("[W %02x] %p [%p %s] State %d\n",
5721 request->getType(), request, this, getName(), fMachineState);
5722
5723 gIOPMRequest = request;
5724
5725 // Every PM machine states must be handled in one of the cases below.
5726
5727 switch ( fMachineState )
5728 {
5729 case kIOPM_Finished:
5730 executePMRequest( request );
5731 break;
5732
5733 case kIOPM_OurChangeTellClientsPowerDown:
5734 // our change, was it vetoed?
5735 if (!fDoNotPowerDown)
5736 {
5737 // no, we can continue
5738 OurChangeTellClientsPowerDown();
5739 }
5740 else
5741 {
5742 OUR_PMLog(kPMLogIdleCancel, (uintptr_t) this, fMachineState);
5743 PM_ERROR("%s: idle cancel\n", fName);
5744 // yes, rescind the warning
5745 tellNoChangeDown(fHeadNotePowerState);
5746 // mark the change note un-actioned
5747 fHeadNoteFlags |= kIOPMNotDone;
5748 // and we're done
5749 all_done();
5750 }
5751 break;
5752
5753 case kIOPM_OurChangeTellPriorityClientsPowerDown:
5754 // our change, should it be acted on still?
5755 if (fDoNotPowerDown)
5756 {
5757 OUR_PMLog(kPMLogIdleCancel, (uintptr_t) this, fMachineState);
5758 PM_ERROR("%s: idle revert\n", fName);
5759 // no, tell clients we're back in the old state
5760 tellChangeUp(fCurrentPowerState);
5761 // mark the change note un-actioned
5762 fHeadNoteFlags |= kIOPMNotDone;
5763 // and we're done
5764 all_done();
5765 }
5766 else
5767 {
5768 // yes, we can continue
5769 OurChangeTellPriorityClientsPowerDown();
5770 }
5771 break;
5772
5773 case kIOPM_OurChangeNotifyInterestedDriversWillChange:
5774 OurChangeNotifyInterestedDriversWillChange();
5775 break;
5776
5777 case kIOPM_OurChangeSetPowerState:
5778 OurChangeSetPowerState();
5779 break;
5780
5781 case kIOPM_OurChangeWaitForPowerSettle:
5782 OurChangeWaitForPowerSettle();
5783 break;
5784
5785 case kIOPM_OurChangeNotifyInterestedDriversDidChange:
5786 OurChangeNotifyInterestedDriversDidChange();
5787 break;
5788
5789 case kIOPM_OurChangeFinish:
5790 OurChangeFinish();
5791 break;
5792
5793 case kIOPM_ParentDownTellPriorityClientsPowerDown:
5794 ParentDownTellPriorityClientsPowerDown();
5795 break;
5796
5797 case kIOPM_ParentDownNotifyInterestedDriversWillChange:
5798 ParentDownNotifyInterestedDriversWillChange();
5799 break;
5800
5801 case kIOPM_ParentDownNotifyDidChangeAndAcknowledgeChange:
5802 ParentDownNotifyDidChangeAndAcknowledgeChange();
5803 break;
5804
5805 case kIOPM_ParentDownSetPowerState:
5806 ParentDownSetPowerState();
5807 break;
5808
5809 case kIOPM_ParentDownWaitForPowerSettle:
5810 ParentDownWaitForPowerSettle();
5811 break;
5812
5813 case kIOPM_ParentAcknowledgePowerChange:
5814 ParentAcknowledgePowerChange();
5815 break;
5816
5817 case kIOPM_ParentUpSetPowerState:
5818 ParentUpSetPowerState();
5819 break;
5820
5821 case kIOPM_ParentUpWaitForSettleTime:
5822 ParentUpWaitForSettleTime();
5823 break;
5824
5825 case kIOPM_ParentUpNotifyInterestedDriversDidChange:
5826 ParentUpNotifyInterestedDriversDidChange();
5827 break;
5828
5829 case kIOPM_DriverThreadCallDone:
5830 if (fDriverCallReason == kDriverCallSetPowerState)
5831 notifyControllingDriverDone();
5832 else
5833 notifyInterestedDriversDone();
5834 break;
5835
5836 case kIOPM_NotifyChildrenDone:
5837 notifyChildrenDone();
5838 break;
5839
5840 case kIOPM_SyncNotifyDidChange:
5841 fMachineState = kIOPM_SyncFinish;
5842 fDriverCallReason = kDriverCallInformPostChange;
5843 notifyChildren();
5844 break;
5845
5846 case kIOPM_SyncFinish:
5847 if (fHeadNoteFlags & kIOPMParentInitiated)
5848 ParentAcknowledgePowerChange();
5849 else
5850 OurChangeFinish();
5851 break;
5852
5853 default:
5854 panic("servicePMWorkQueue: unknown machine state %x",
5855 fMachineState);
5856 }
5857
5858 gIOPMRequest = 0;
5859
5860 if (fMachineState == kIOPM_Finished)
5861 {
5862 //PM_TRACE("[%s] PM End: Request %p (type %02lx)\n",
5863 // getName(), request, request->getType());
5864 done = true;
5865 break;
5866 }
5867 }
5868
5869 return done;
5870}
5871
5872//*********************************************************************************
5873// [private] executePMRequest
5874//*********************************************************************************
5875
5876void IOService::executePMRequest( IOPMRequest * request )
5877{
5878 assert( kIOPM_Finished == fMachineState );
5879
5880 switch (request->getType())
5881 {
5882 case kIOPMRequestTypePMStop:
5883 handlePMstop( request );
5884 break;
5885
5886 case kIOPMRequestTypeAddPowerChild1:
5887 addPowerChild1( request );
5888 break;
5889
5890 case kIOPMRequestTypeAddPowerChild2:
5891 addPowerChild2( request );
5892 break;
5893
5894 case kIOPMRequestTypeAddPowerChild3:
5895 addPowerChild3( request );
5896 break;
5897
5898 case kIOPMRequestTypeRegisterPowerDriver:
5899 handleRegisterPowerDriver( request );
5900 break;
5901
5902 case kIOPMRequestTypeAdjustPowerState:
5903 fAdjustPowerScheduled = false;
5904 rebuildChildClampBits();
5905 adjustPowerState();
5906 break;
5907
5908 case kIOPMRequestTypePowerDomainWillChange:
5909 handlePowerDomainWillChangeTo( request );
5910 break;
5911
5912 case kIOPMRequestTypePowerDomainDidChange:
5913 handlePowerDomainDidChangeTo( request );
5914 break;
5915
5916 case kIOPMRequestTypeRequestPowerState:
5917 case kIOPMRequestTypeRequestPowerStateOverride:
5918 handleRequestPowerState( request );
5919 break;
5920
5921 case kIOPMRequestTypePowerOverrideOnPriv:
5922 case kIOPMRequestTypePowerOverrideOffPriv:
5923 handlePowerOverrideChanged( request );
5924 break;
5925
5926 case kIOPMRequestTypeActivityTickle:
5927 handleActivityTickle( request );
5928 break;
5929
5930 case kIOPMRequestTypeSynchronizePowerTree:
5931 handleSynchronizePowerTree( request );
5932 break;
5933
5934 case kIOPMRequestTypeSetIdleTimerPeriod:
5935 {
5936 IOWorkLoop * wl = gIOPMWorkLoop;
5937 fIdleTimerPeriod = (uintptr_t) request->fArg0;
5938
5939 if (wl && (false == fLockedFlags.PMStop) && (fIdleTimerPeriod > 0))
5940 {
5941 if ( NULL == fIdleTimerEventSource )
5942 {
5943 IOTimerEventSource * timerSrc;
5944
5945 timerSrc = IOTimerEventSource::timerEventSource(
5946 this,
5947 OSMemberFunctionCast(IOTimerEventSource::Action,
5948 this, &IOService::idleTimerExpired));
5949
5950 if (timerSrc && (wl->addEventSource(timerSrc) != kIOReturnSuccess))
5951 {
5952 timerSrc->release();
5953 timerSrc = 0;
5954 }
5955
5956 fIdleTimerEventSource = timerSrc;
5957 }
5958
5959 fActivityTickleCount = 0;
5960 clock_get_uptime(&fIdleTimerStartTime);
5961 start_PM_idle_timer();
5962 }
5963 }
5964 break;
5965
5966 default:
5967 panic("executePMRequest: unknown request type %x", request->getType());
5968 }
5969}
5970
5971//*********************************************************************************
5972// [private] servicePMReplyQueue
5973//*********************************************************************************
5974
5975bool IOService::servicePMReplyQueue( IOPMRequest * request, IOPMRequestQueue * queue )
5976{
5977 bool more = false;
5978
5979 assert( request && queue );
5980 assert( request->isReplyType() );
5981
5982 PM_TRACE("[A %02x] %p [%p %s] State %d\n",
5983 request->getType(), request, this, getName(), fMachineState);
5984
5985 switch ( request->getType() )
5986 {
5987 case kIOPMRequestTypeAllowPowerChange:
5988 case kIOPMRequestTypeCancelPowerChange:
5989 // Check if we are expecting this response.
5990 if (responseValid((unsigned long) request->fArg0, (int)(long) request->fArg1))
5991 {
5992 if (kIOPMRequestTypeCancelPowerChange == request->getType())
5993 {
5994 OSString * name = (OSString *) request->fArg2;
5995 getPMRootDomain()->pmStatsRecordApplicationResponse(
5996 gIOPMStatsApplicationResponseCancel,
5997 name ? name->getCStringNoCopy() : "", 0,
5998 0, (int)(uintptr_t) request->fArg1);
5999
6000 fDoNotPowerDown = true;
6001 }
6002
6003 if (checkForDone())
6004 {
6005 stop_ack_timer();
6006 if ( fResponseArray )
6007 {
6008 fResponseArray->release();
6009 fResponseArray = NULL;
6010 }
6011 if ( fNotifyClientArray )
6012 {
6013 fNotifyClientArray->release();
6014 fNotifyClientArray = NULL;
6015 }
6016 more = true;
6017 }
6018 }
6019 // OSString containing app name in Arg2 must be released.
6020 if (request->getType() == kIOPMRequestTypeCancelPowerChange)
6021 {
6022 OSObject * obj = (OSObject *) request->fArg2;
6023 if (obj) obj->release();
6024 }
6025 break;
6026
6027 case kIOPMRequestTypeAckPowerChange:
6028 more = handleAcknowledgePowerChange( request );
6029 break;
6030
6031 case kIOPMRequestTypeAckSetPowerState:
6032 if (fDriverTimer == -1)
6033 {
6034 // driver acked while setPowerState() call is in-flight.
6035 // take this ack, return value from setPowerState() is irrelevant.
6036 OUR_PMLog(kPMLogDriverAcknowledgeSet,
6037 (uintptr_t) this, fDriverTimer);
6038 fDriverTimer = 0;
6039 }
6040 else if (fDriverTimer > 0)
6041 {
6042 // expected ack, stop the timer
6043 stop_ack_timer();
6044
6045#if LOG_SETPOWER_TIMES
6046 uint64_t nsec = computeTimeDeltaNS(&fDriverCallStartTime);
6047 if (nsec > LOG_SETPOWER_TIMES)
6048 PM_DEBUG("%s::setPowerState(%p, %lu -> %lu) async took %d ms\n",
6049 fName, this, fCurrentPowerState, fHeadNotePowerState, NS_TO_MS(nsec));
6050#endif
6051 OUR_PMLog(kPMLogDriverAcknowledgeSet, (uintptr_t) this, fDriverTimer);
6052 fDriverTimer = 0;
6053 more = true;
6054 }
6055 else
6056 {
6057 // unexpected ack
6058 OUR_PMLog(kPMLogAcknowledgeErr4, (uintptr_t) this, 0);
6059 }
6060 break;
6061
6062 case kIOPMRequestTypeInterestChanged:
6063 handleInterestChanged( request );
6064 more = true;
6065 break;
6066
6067 case kIOPMRequestTypeIdleCancel:
6068 if ((fMachineState == kIOPM_OurChangeTellClientsPowerDown)
6069 || (fMachineState == kIOPM_OurChangeTellPriorityClientsPowerDown))
6070 {
6071 OUR_PMLog(kPMLogIdleCancel, (uintptr_t) this, 0);
6072 fDoNotPowerDown = true;
6073 if (fMachineState == kIOPM_OurChangeTellPriorityClientsPowerDown)
6074 cleanClientResponses(false);
6075 more = true;
6076 }
6077 break;
6078
6079 default:
6080 panic("servicePMReplyQueue: unknown reply type %x",
6081 request->getType());
6082 }
6083
6084 releasePMRequest( request );
6085 return more;
6086}
6087
6088//*********************************************************************************
6089// [private] assertPMThreadCall / deassertPMThreadCall
6090//*********************************************************************************
6091
6092bool IOService::assertPMThreadCall( void )
6093{
6094 if (!initialized)
6095 return false;
6096
6097 // PMfree() should only be called from IOService::free().
6098 // That makes it safe to touch IOServicePM state here.
6099 // Caller holds a retain and has checked target is on PM plane.
6100
6101 PM_LOCK();
6102 if (fLockedFlags.PMStop)
6103 {
6104 // PMstop() already issued - fail the assertion.
6105 PM_UNLOCK();
6106 return false;
6107 }
6108
6109 // Increment assertion count to block PMstop(), and return true.
6110 fThreadAssertionCount++;
6111 fThreadAssertionThread = current_thread(); // only 1 caller
6112 PM_UNLOCK();
6113
6114 return true;
6115}
6116
6117void IOService::deassertPMThreadCall( void )
6118{
6119 PM_LOCK();
6120 assert(fThreadAssertionCount > 0);
6121 if (fThreadAssertionCount)
6122 fThreadAssertionCount--;
6123 if (current_thread() == fThreadAssertionThread)
6124 fThreadAssertionThread = 0;
6125 if ((fThreadAssertionCount == 0) && fLockedFlags.PMStop)
6126 {
6127 // PMstop() is blocked waiting for assertion count to drop to zero.
6128 PM_LOCK_WAKEUP(&fThreadAssertionCount);
6129 }
6130 PM_UNLOCK();
6131}
6132
6133// MARK: -
6134// MARK: IOPMRequest
6135
6136//*********************************************************************************
6137// IOPMRequest Class
6138//
6139// Requests from PM clients, and also used for inter-object messaging within PM.
6140//*********************************************************************************
6141
6142OSDefineMetaClassAndStructors( IOPMRequest, IOCommand );
6143
6144IOPMRequest * IOPMRequest::create( void )
6145{
6146 IOPMRequest * me = OSTypeAlloc(IOPMRequest);
6147 if (me && !me->init(0, kIOPMRequestTypeInvalid))
6148 {
6149 me->release();
6150 me = 0;
6151 }
6152 return me;
6153}
6154
6155bool IOPMRequest::init( IOService * target, IOOptionBits type )
6156{
6157 if (!IOCommand::init())
6158 return false;
6159
6160 fType = type;
6161 fTarget = target;
6162 fCompletionStatus = kIOReturnSuccess;
6163
6164 if (fTarget)
6165 fTarget->retain();
6166
6167 return true;
6168}
6169
6170void IOPMRequest::reset( void )
6171{
6172 assert( fWorkWaitCount == 0 );
6173 assert( fFreeWaitCount == 0 );
6174
6175 detachNextRequest();
6176 detachRootRequest();
6177
6178 fType = kIOPMRequestTypeInvalid;
6179
6180 if (fCompletionAction)
6181 {
6182 fCompletionAction(fCompletionTarget, fCompletionParam, fCompletionStatus);
6183 }
6184
6185 if (fTarget)
6186 {
6187 fTarget->release();
6188 fTarget = 0;
6189 }
6190}
6191
6192void IOPMRequest::attachNextRequest( IOPMRequest * next )
6193{
6194 if (!fRequestNext)
6195 {
6196 // Postpone the execution of the next request after
6197 // this request.
6198 fRequestNext = next;
6199 fRequestNext->fWorkWaitCount++;
6200#if LOG_REQUEST_ATTACH
6201 kprintf("Attached next: %p [0x%x] -> %p [0x%x, %u] %s\n",
6202 this, (uint32_t) fType, fRequestNext,
6203 (uint32_t) fRequestNext->fType,
6204 (uint32_t) fRequestNext->fWorkWaitCount,
6205 fTarget->getName());
6206#endif
6207 }
6208}
6209
6210void IOPMRequest::detachNextRequest( void )
6211{
6212 if (fRequestNext)
6213 {
6214 assert(fRequestNext->fWorkWaitCount);
6215 if (fRequestNext->fWorkWaitCount)
6216 fRequestNext->fWorkWaitCount--;
6217#if LOG_REQUEST_ATTACH
6218 kprintf("Detached next: %p [0x%x] -> %p [0x%x, %u] %s\n",
6219 this, (uint32_t) fType, fRequestNext,
6220 (uint32_t) fRequestNext->fType,
6221 (uint32_t) fRequestNext->fWorkWaitCount,
6222 fTarget->getName());
6223#endif
6224 fRequestNext = 0;
6225 }
6226}
6227
6228void IOPMRequest::attachRootRequest( IOPMRequest * root )
6229{
6230 if (!fRequestRoot)
6231 {
6232 // Delay the completion of the root request after
6233 // this request.
6234 fRequestRoot = root;
6235 fRequestRoot->fFreeWaitCount++;
6236#if LOG_REQUEST_ATTACH
6237 kprintf("Attached root: %p [0x%x] -> %p [0x%x, %u] %s\n",
6238 this, (uint32_t) fType, fRequestRoot,
6239 (uint32_t) fRequestRoot->fType,
6240 (uint32_t) fRequestRoot->fFreeWaitCount,
6241 fTarget->getName());
6242#endif
6243 }
6244}
6245
6246void IOPMRequest::detachRootRequest( void )
6247{
6248 if (fRequestRoot)
6249 {
6250 assert(fRequestRoot->fFreeWaitCount);
6251 if (fRequestRoot->fFreeWaitCount)
6252 fRequestRoot->fFreeWaitCount--;
6253#if LOG_REQUEST_ATTACH
6254 kprintf("Detached root: %p [0x%x] -> %p [0x%x, %u] %s\n",
6255 this, (uint32_t) fType, fRequestRoot,
6256 (uint32_t) fRequestRoot->fType,
6257 (uint32_t) fRequestRoot->fFreeWaitCount,
6258 fTarget->getName());
6259#endif
6260 fRequestRoot = 0;
6261 }
6262}
6263
6264// MARK: -
6265// MARK: IOPMRequestQueue
6266
6267//*********************************************************************************
6268// IOPMRequestQueue Class
6269//
6270// Global queues. As PM-aware drivers load and unload, their IOPMWorkQueue's are
6271// created and deallocated. IOPMRequestQueue are created once and never released.
6272//*********************************************************************************
6273
6274OSDefineMetaClassAndStructors( IOPMRequestQueue, IOEventSource );
6275
6276IOPMRequestQueue * IOPMRequestQueue::create( IOService * inOwner, Action inAction )
6277{
6278 IOPMRequestQueue * me = OSTypeAlloc(IOPMRequestQueue);
6279 if (me && !me->init(inOwner, inAction))
6280 {
6281 me->release();
6282 me = 0;
6283 }
6284 return me;
6285}
6286
6287bool IOPMRequestQueue::init( IOService * inOwner, Action inAction )
6288{
6289 if (!inAction || !IOEventSource::init(inOwner, (IOEventSourceAction)inAction))
6290 return false;
6291
6292 queue_init(&fQueue);
6293 fLock = IOLockAlloc();
6294 return (fLock != 0);
6295}
6296
6297void IOPMRequestQueue::free( void )
6298{
6299 if (fLock)
6300 {
6301 IOLockFree(fLock);
6302 fLock = 0;
6303 }
6304 return IOEventSource::free();
6305}
6306
6307void IOPMRequestQueue::queuePMRequest( IOPMRequest * request )
6308{
6309 assert(request);
6310 IOLockLock(fLock);
6311 queue_enter(&fQueue, request, IOPMRequest *, fCommandChain);
6312 IOLockUnlock(fLock);
6313 if (workLoop) signalWorkAvailable();
6314}
6315
6316void
6317IOPMRequestQueue::queuePMRequestChain( IOPMRequest ** requests, IOItemCount count )
6318{
6319 IOPMRequest * next;
6320
6321 assert(requests && count);
6322 IOLockLock(fLock);
6323 while (count--)
6324 {
6325 next = *requests;
6326 requests++;
6327 queue_enter(&fQueue, next, IOPMRequest *, fCommandChain);
6328 }
6329 IOLockUnlock(fLock);
6330 if (workLoop) signalWorkAvailable();
6331}
6332
6333bool IOPMRequestQueue::checkForWork( void )
6334{
6335 Action dqAction = (Action) action;
6336 IOPMRequest * request;
6337 IOService * target;
6338 bool more = false;
6339
6340 IOLockLock( fLock );
6341
6342 while (!queue_empty(&fQueue))
6343 {
6344 queue_remove_first( &fQueue, request, IOPMRequest *, fCommandChain );
6345 IOLockUnlock( fLock );
6346 target = request->getTarget();
6347 assert(target);
6348 more |= (*dqAction)( target, request, this );
6349 IOLockLock( fLock );
6350 }
6351
6352 IOLockUnlock( fLock );
6353 return more;
6354}
6355
6356void IOPMRequestQueue::signalWorkAvailable( void )
6357{
6358 IOEventSource::signalWorkAvailable();
6359}
6360
6361// MARK: -
6362// MARK: IOPMWorkQueue
6363
6364//*********************************************************************************
6365// IOPMWorkQueue Class
6366//
6367// Every object in the power plane that has handled a PM request, will have an
6368// instance of IOPMWorkQueue allocated for it.
6369//*********************************************************************************
6370
6371OSDefineMetaClassAndStructors( IOPMWorkQueue, IOEventSource );
6372
6373IOPMWorkQueue *
6374IOPMWorkQueue::create( IOService * inOwner, Action work, Action retire )
6375{
6376 IOPMWorkQueue * me = OSTypeAlloc(IOPMWorkQueue);
6377 if (me && !me->init(inOwner, work, retire))
6378 {
6379 me->release();
6380 me = 0;
6381 }
6382 return me;
6383}
6384
6385bool IOPMWorkQueue::init( IOService * inOwner, Action work, Action retire )
6386{
6387 if (!work || !retire ||
6388 !IOEventSource::init(inOwner, (IOEventSourceAction)0))
6389 return false;
6390
6391 queue_init(&fWorkQueue);
6392
6393 fWorkAction = work;
6394 fRetireAction = retire;
6395
6396 return true;
6397}
6398
6399void IOPMWorkQueue::queuePMRequest( IOPMRequest * request )
6400{
6401 assert( request );
6402 assert( onThread() );
6403
6404 gIOPMBusyCount++;
6405 queue_enter(&fWorkQueue, request, IOPMRequest *, fCommandChain);
6406 checkForWork();
6407}
6408
6409bool IOPMWorkQueue::checkForWork( void )
6410{
6411 IOPMRequest * request;
6412 IOService * target = (IOService *) owner;
6413 bool done;
6414
6415 while (!queue_empty(&fWorkQueue))
6416 {
6417 request = (IOPMRequest *) queue_first(&fWorkQueue);
6418 assert(request->getTarget() == target);
6419 if (request->isWorkBlocked()) break;
6420 done = (*fWorkAction)( target, request, this );
6421 if (!done) break;
6422
6423 assert(gIOPMBusyCount > 0);
6424 if (gIOPMBusyCount) gIOPMBusyCount--;
6425 queue_remove_first(&fWorkQueue, request, IOPMRequest *, fCommandChain);
6426 (*fRetireAction)( target, request, this );
6427 }
6428
6429 return false;
6430}
6431
6432// MARK: -
6433// MARK: IOPMCompletionQueue
6434
6435//*********************************************************************************
6436// IOPMCompletionQueue Class
6437//*********************************************************************************
6438
6439OSDefineMetaClassAndStructors( IOPMCompletionQueue, IOEventSource );
6440
6441IOPMCompletionQueue * IOPMCompletionQueue::create( IOService * inOwner, Action inAction )
6442{
6443 IOPMCompletionQueue * me = OSTypeAlloc(IOPMCompletionQueue);
6444 if (me && !me->init(inOwner, inAction))
6445 {
6446 me->release();
6447 me = 0;
6448 }
6449 return me;
6450}
6451
6452bool IOPMCompletionQueue::init( IOService * inOwner, Action inAction )
6453{
6454 if (!inAction || !IOEventSource::init(inOwner, (IOEventSourceAction)inAction))
6455 return false;
6456
6457 queue_init(&fQueue);
6458 return true;
6459}
6460
6461void IOPMCompletionQueue::queuePMRequest( IOPMRequest * request )
6462{
6463 assert(request);
6464 request->detachNextRequest(); // unblocks next request
6465 queue_enter(&fQueue, request, IOPMRequest *, fCommandChain);
6466 if (workLoop) signalWorkAvailable();
6467}
6468
6469bool IOPMCompletionQueue::checkForWork( void )
6470{
6471 Action dqAction = (Action) action;
6472 IOPMRequest * request;
6473 IOService * target;
6474 bool more = false;
6475 queue_head_t tmpQueue;
6476
6477 queue_init(&tmpQueue);
6478
6479 while (!queue_empty(&fQueue))
6480 {
6481 queue_remove_first( &fQueue, request, IOPMRequest *, fCommandChain );
6482 if (request->isFreeBlocked())
6483 {
6484 queue_enter(&tmpQueue, request, IOPMRequest *, fCommandChain);
6485 continue;
6486 }
6487 target = request->getTarget();
6488 assert(target);
6489 more |= (*dqAction)( target, request, this );
6490 }
6491
6492 queue_new_head(&tmpQueue, &fQueue, IOPMRequest *, fCommandChain);
6493 return more;
6494}
6495
6496// MARK: -
6497// MARK: IOServicePM
6498
6499OSDefineMetaClassAndStructors(IOServicePM, OSObject)
6500
6501//*********************************************************************************
6502// serialize
6503//
6504// Serialize IOServicePM for debugging.
6505//*********************************************************************************
6506
6507static void
6508setPMProperty( OSDictionary * dict, const char * key, uint64_t value )
6509{
6510 OSNumber * num = OSNumber::withNumber(value, sizeof(value) * 8);
6511 if (num)
6512 {
6513 dict->setObject(key, num);
6514 num->release();
6515 }
6516}
6517
6518IOReturn IOServicePM::gatedSerialize( OSSerialize * s )
6519{
6520 OSDictionary * dict;
6521 bool ok = false;
6522 int dictSize = 4;
6523
6524 if (IdleTimerPeriod)
6525 dictSize += 4;
6526
6527 if (PowerClients)
6528 dict = OSDictionary::withDictionary(
6529 PowerClients, PowerClients->getCount() + dictSize);
6530 else
6531 dict = OSDictionary::withCapacity(dictSize);
6532
6533 if (dict)
6534 {
6535 setPMProperty(dict, "CurrentPowerState", CurrentPowerState);
6536 if (DesiredPowerState != CurrentPowerState)
6537 setPMProperty(dict, "DesiredPowerState", DesiredPowerState);
6538 if (kIOPM_Finished != MachineState)
6539 setPMProperty(dict, "MachineState", MachineState);
6540 if (DeviceOverrides)
6541 dict->setObject("PowerOverrideOn", kOSBooleanTrue);
6542
6543 if (IdleTimerPeriod)
6544 {
6545 AbsoluteTime now;
6546 AbsoluteTime delta;
6547 uint64_t nsecs;
6548
6549 clock_get_uptime(&now);
6550
6551 // The idle timer period in milliseconds.
6552 setPMProperty(dict, "IdleTimerPeriod", IdleTimerPeriod * 1000ULL);
6553
6554 // The number of activity tickles recorded since device idle
6555 setPMProperty(dict, "ActivityTickles", ActivityTickleCount);
6556
6557 if (AbsoluteTime_to_scalar(&DeviceActiveTimestamp))
6558 {
6559 // The number of milliseconds since the last activity tickle.
6560 delta = now;
6561 SUB_ABSOLUTETIME(&delta, &DeviceActiveTimestamp);
6562 absolutetime_to_nanoseconds(delta, &nsecs);
6563 setPMProperty(dict, "TimeSinceActivityTickle", NS_TO_MS(nsecs));
6564 }
6565
6566 if (AbsoluteTime_to_scalar(&IdleTimerStartTime))
6567 {
6568 // The number of milliseconds since the last device idle.
6569 delta = now;
6570 SUB_ABSOLUTETIME(&delta, &IdleTimerStartTime);
6571 absolutetime_to_nanoseconds(delta, &nsecs);
6572 setPMProperty(dict, "TimeSinceDeviceIdle", NS_TO_MS(nsecs));
6573 }
6574 }
6575
6576 ok = dict->serialize(s);
6577 dict->release();
6578 }
6579
6580 return (ok ? kIOReturnSuccess : kIOReturnNoMemory);
6581}
6582
6583bool IOServicePM::serialize( OSSerialize * s ) const
6584{
6585 IOReturn ret = kIOReturnNotReady;
6586
6587 if (gIOPMWorkLoop)
6588 {
6589 ret = gIOPMWorkLoop->runAction(
6590 OSMemberFunctionCast(IOWorkLoop::Action, this, &IOServicePM::gatedSerialize),
6591 (OSObject *) this, (void *) s);
6592 }
6593
6594 return (kIOReturnSuccess == ret);
6595}