]> git.saurik.com Git - apple/xnu.git/blob - iokit/Kernel/IOServicePM.cpp
97711e1c8d28683e2e58d025290ceb51f9a9d0e2
[apple/xnu.git] / iokit / Kernel / IOServicePM.cpp
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 //#undef IOASSERT
30 //#define IOASSERT 1
31
32 #include <IOKit/assert.h>
33 #include <IOKit/IOKitDebug.h>
34 #include <IOKit/IOLib.h>
35 #include <IOKit/IOMessage.h>
36 #include <IOKit/IOPlatformExpert.h>
37 #include <IOKit/IOService.h>
38 #include <IOKit/IOEventSource.h>
39 #include <IOKit/IOWorkLoop.h>
40 #include <IOKit/IOCommand.h>
41 #include <IOKit/IOTimeStamp.h>
42
43 #include <IOKit/pwr_mgt/IOPMlog.h>
44 #include <IOKit/pwr_mgt/IOPMinformee.h>
45 #include <IOKit/pwr_mgt/IOPMinformeeList.h>
46 #include <IOKit/pwr_mgt/IOPowerConnection.h>
47 #include <IOKit/pwr_mgt/RootDomain.h>
48 #include <IOKit/pwr_mgt/IOPMPrivate.h>
49
50 #include <sys/proc.h>
51 #include <sys/proc_internal.h>
52 #include <libkern/OSDebug.h>
53
54 // Required for notification instrumentation
55 #include "IOServicePrivate.h"
56 #include "IOServicePMPrivate.h"
57 #include "IOKitKernelInternal.h"
58
59 static void settle_timer_expired(thread_call_param_t, thread_call_param_t);
60 static void idle_timer_expired(thread_call_param_t, thread_call_param_t);
61 static void tellKernelClientApplier(OSObject * object, void * arg);
62 static void tellAppClientApplier(OSObject * object, void * arg);
63
64 static uint64_t computeTimeDeltaNS( const AbsoluteTime * start )
65 {
66 AbsoluteTime now;
67 uint64_t nsec;
68
69 clock_get_uptime(&now);
70 SUB_ABSOLUTETIME(&now, start);
71 absolutetime_to_nanoseconds(now, &nsec);
72 return nsec;
73 }
74
75 #if PM_VARS_SUPPORT
76 OSDefineMetaClassAndStructors(IOPMprot, OSObject)
77 #endif
78
79 // Container class for recording system power events
80 OSDefineMetaClassAndStructors( PMEventDetails, OSObject );
81
82 //******************************************************************************
83 // Globals
84 //******************************************************************************
85
86 static bool gIOPMInitialized = false;
87 static uint32_t gIOPMBusyCount = 0;
88 static uint32_t gIOPMWorkCount = 0;
89 static IOWorkLoop * gIOPMWorkLoop = 0;
90 static IOPMRequestQueue * gIOPMRequestQueue = 0;
91 static IOPMRequestQueue * gIOPMReplyQueue = 0;
92 static IOPMWorkQueue * gIOPMWorkQueue = 0;
93 static IOPMCompletionQueue * gIOPMFreeQueue = 0;
94 static IOPMRequest * gIOPMRequest = 0;
95 static IOService * gIOPMRootNode = 0;
96 static IOPlatformExpert * gPlatform = 0;
97
98 static const OSSymbol * gIOPMPowerClientDevice = 0;
99 static const OSSymbol * gIOPMPowerClientDriver = 0;
100 static const OSSymbol * gIOPMPowerClientChildProxy = 0;
101 static const OSSymbol * gIOPMPowerClientChildren = 0;
102
103 static const OSSymbol * gIOPMPowerClientAdvisoryTickle = 0;
104 static bool gIOPMAdvisoryTickleEnabled = true;
105
106 static uint32_t getPMRequestType( void )
107 {
108 uint32_t type = kIOPMRequestTypeInvalid;
109 if (gIOPMRequest)
110 type = gIOPMRequest->getType();
111 return type;
112 }
113
114 //******************************************************************************
115 // Macros
116 //******************************************************************************
117
118 #define PM_ERROR(x...) do { kprintf(x); IOLog(x); } while (false)
119 #define PM_LOG(x...) do { kprintf(x); } while (false)
120
121 #define PM_LOG1(x...) do { \
122 if (kIOLogDebugPower & gIOKitDebug) \
123 kprintf(x); } while (false)
124
125 #define PM_LOG2(x...) do { \
126 if (kIOLogDebugPower & gIOKitDebug) \
127 kprintf(x); } while (false)
128
129 #if 0
130 #define PM_LOG3(x...) do { kprintf(x); } while (false)
131 #else
132 #define PM_LOG3(x...)
133 #endif
134
135 #define RD_LOG(x...) do { \
136 if ((kIOLogPMRootDomain & gIOKitDebug) && \
137 (getPMRootDomain() == this)) \
138 kprintf("PMRD: " x); } while (false)
139
140 #define PM_ASSERT_IN_GATE(x) \
141 do { \
142 assert(gIOPMWorkLoop->inGate()); \
143 } while(false)
144
145 #define PM_LOCK() IOLockLock(fPMLock)
146 #define PM_UNLOCK() IOLockUnlock(fPMLock)
147 #define PM_LOCK_SLEEP(event, dl) IOLockSleepDeadline(fPMLock, event, dl, THREAD_UNINT)
148 #define PM_LOCK_WAKEUP(event) IOLockWakeup(fPMLock, event, false)
149
150 #define ns_per_us 1000
151 #define k30Seconds (30*1000000)
152 #define kMinAckTimeoutTicks (10*1000000)
153 #define kIOPMTardyAckSPSKey "IOPMTardyAckSetPowerState"
154 #define kIOPMTardyAckPSCKey "IOPMTardyAckPowerStateChange"
155 #define kPwrMgtKey "IOPowerManagement"
156
157 #define OUR_PMLog(t, a, b) do { \
158 if (gIOKitDebug & kIOLogPower) \
159 pwrMgt->pmPrint(t, a, b); \
160 if (gIOKitTrace & kIOTracePowerMgmt) \
161 pwrMgt->pmTrace(t, a, b); \
162 } while(0)
163
164 #define NS_TO_MS(nsec) ((int)((nsec) / 1000000ULL))
165 #define NS_TO_US(nsec) ((int)((nsec) / 1000ULL))
166
167 #if CONFIG_EMBEDDED
168 #define SUPPORT_IDLE_CANCEL 1
169 #endif
170
171 #define kIOPMPowerStateMax 0xFFFFFFFF
172 #define kInvalidTicklePowerState (-1)
173
174 #define kNoTickleCancelWindow (60ULL * 1000ULL * 1000ULL * 1000ULL)
175
176 #define IS_PM_ROOT (this == gIOPMRootNode)
177 #define IS_ROOT_DOMAIN (getPMRootDomain() == this)
178 #define IS_POWER_DROP (fHeadNotePowerState < fCurrentPowerState)
179 #define IS_POWER_RISE (fHeadNotePowerState > fCurrentPowerState)
180
181 // log setPowerStates longer than (ns):
182 #define LOG_SETPOWER_TIMES (50ULL * 1000ULL * 1000ULL)
183 // log app responses longer than (ns):
184 #define LOG_APP_RESPONSE_TIMES (100ULL * 1000ULL * 1000ULL)
185 // use message tracer to log messages longer than (ns):
186 #define LOG_APP_RESPONSE_MSG_TRACER (3 * 1000ULL * 1000ULL * 1000ULL)
187
188 enum {
189 kReserveDomainPower = 1
190 };
191
192 #define MS_PUSH(n) \
193 do { assert(kIOPM_BadMachineState == fSavedMachineState); \
194 assert(kIOPM_BadMachineState != n); \
195 fSavedMachineState = n; } while (false)
196
197 #define MS_POP() \
198 do { assert(kIOPM_BadMachineState != fSavedMachineState); \
199 fMachineState = fSavedMachineState; \
200 fSavedMachineState = kIOPM_BadMachineState; } while (false)
201
202 #define PM_ACTION_0(a) \
203 do { if (fPMActions.a) { \
204 (fPMActions.a)(fPMActions.target, this, &fPMActions); } \
205 } while (false)
206
207 #define PM_ACTION_2(a, x, y) \
208 do { if (fPMActions.a) { \
209 (fPMActions.a)(fPMActions.target, this, &fPMActions, x, y); } \
210 } while (false)
211
212 static OSNumber * copyClientIDForNotification(
213 OSObject *object,
214 IOPMInterestContext *context);
215
216 static void logClientIDForNotification(
217 OSObject *object,
218 IOPMInterestContext *context,
219 const char *logString);
220
221 //*********************************************************************************
222 // PM machine states
223 //
224 // Check kgmacros after modifying machine states.
225 //*********************************************************************************
226
227 enum {
228 kIOPM_Finished = 0,
229
230 kIOPM_OurChangeTellClientsPowerDown = 1,
231 kIOPM_OurChangeTellPriorityClientsPowerDown = 2,
232 kIOPM_OurChangeNotifyInterestedDriversWillChange = 3,
233 kIOPM_OurChangeSetPowerState = 4,
234 kIOPM_OurChangeWaitForPowerSettle = 5,
235 kIOPM_OurChangeNotifyInterestedDriversDidChange = 6,
236 kIOPM_OurChangeTellCapabilityDidChange = 7,
237 kIOPM_OurChangeFinish = 8,
238
239 kIOPM_ParentChangeTellPriorityClientsPowerDown = 10,
240 kIOPM_ParentChangeNotifyInterestedDriversWillChange = 11,
241 kIOPM_ParentChangeSetPowerState = 12,
242 kIOPM_ParentChangeWaitForPowerSettle = 13,
243 kIOPM_ParentChangeNotifyInterestedDriversDidChange = 14,
244 kIOPM_ParentChangeTellCapabilityDidChange = 15,
245 kIOPM_ParentChangeAcknowledgePowerChange = 16,
246
247 kIOPM_NotifyChildrenStart = 17,
248 kIOPM_NotifyChildrenOrdered = 18,
249 kIOPM_NotifyChildrenDelayed = 19,
250 kIOPM_SyncTellClientsPowerDown = 20,
251 kIOPM_SyncTellPriorityClientsPowerDown = 21,
252 kIOPM_SyncNotifyWillChange = 22,
253 kIOPM_SyncNotifyDidChange = 23,
254 kIOPM_SyncTellCapabilityDidChange = 24,
255 kIOPM_SyncFinish = 25,
256 kIOPM_TellCapabilityChangeDone = 26,
257 kIOPM_DriverThreadCallDone = 27,
258
259 kIOPM_BadMachineState = 0xFFFFFFFF
260 };
261
262
263 /*
264 Power Management defines a few roles that drivers can play in their own,
265 and other drivers', power management. We briefly define those here.
266
267 Many drivers implement their policy maker and power controller within the same
268 IOService object, but that is not required.
269
270 == Policy Maker ==
271 * Virtual IOService PM methods a "policy maker" may implement
272 * maxCapabilityForDomainState()
273 * initialPowerStateForDomainState()
274 * powerStateForDomainState()
275
276 * Virtual IOService PM methods a "policy maker" may CALL
277 * PMinit()
278
279 == Power Controller ==
280 * Virtual IOService PM methods a "power controller" may implement
281 * setPowerState()
282
283 * Virtual IOService PM methods a "power controller" may CALL
284 * joinPMtree()
285 * registerPowerDriver()
286
287 =======================
288 There are two different kinds of power state changes.
289 * One is initiated by a subclassed device object which has either decided
290 to change power state, or its controlling driver has suggested it, or
291 some other driver wants to use the idle device and has asked it to become
292 usable.
293 * The second kind of power state change is initiated by the power domain
294 parent.
295 The two are handled through different code paths.
296
297 We maintain a queue of "change notifications," or change notes.
298 * Usually the queue is empty.
299 * When it isn't, usually there is one change note in it
300 * It's possible to have more than one power state change pending at one
301 time, so a queue is implemented.
302 Example:
303 * The subclass device decides it's idle and initiates a change to a lower
304 power state. This causes interested parties to be notified, but they
305 don't all acknowledge right away. This causes the change note to sit
306 in the queue until all the acks are received. During this time, the
307 device decides it isn't idle anymore and wants to raise power back up
308 again. This change can't be started, however, because the previous one
309 isn't complete yet, so the second one waits in the queue. During this
310 time, the parent decides to lower or raise the power state of the entire
311 power domain and notifies the device, and that notification goes into
312 the queue, too, and can't be actioned until the others are.
313
314 == SelfInitiated ==
315 This is how a power change initiated by the subclass device is handled:
316 -> First, all interested parties are notified of the change via their
317 powerStateWillChangeTo method. If they all don't acknowledge via return
318 code, then we have to wait. If they do, or when they finally all
319 acknowledge via our acknowledgePowerChange method, then we can continue.
320 -> We call the controlling driver, instructing it to change to the new state
321 -> Then we wait for power to settle. If there is no settling-time, or after
322 it has passed,
323 -> we notify interested parties again, this time via their
324 powerStateDidChangeTo methods.
325 -> When they have all acked, we're done.
326 If we lowered power and don't need the power domain to be in its current power
327 state, we suggest to the parent that it lower the power domain state.
328
329 == PowerDomainDownInitiated ==
330 How a change to a lower power domain state initiated by the parent is handled:
331 -> First, we figure out what power state we will be in when the new domain
332 state is reached.
333 -> Then all interested parties are notified that we are moving to that new
334 state.
335 -> When they have acknowledged, we call the controlling driver to assume
336 that state and we wait for power to settle.
337 -> Then we acknowledge our preparedness to our parent. When all its
338 interested parties have acknowledged,
339 -> it lowers power and then notifies its interested parties again.
340 -> When we get this call, we notify our interested parties that the power
341 state has changed, and when they have all acknowledged, we're done.
342
343 == PowerDomainUpInitiated ==
344 How a change to a higher power domain state initiated by the parent is handled:
345 -> We figure out what power state we will be in when the new domain state is
346 reached.
347 -> If it is different from our current state we acknowledge the parent.
348 -> When all the parent's interested parties have acknowledged, it raises
349 power in the domain and waits for power to settle.
350 -> Then it notifies everyone that the new state has been reached.
351 -> When we get this call, we call the controlling driver, instructing it to
352 assume the new state, and wait for power to settle.
353 -> Then we notify our interested parties. When they all acknowledge we are
354 done.
355
356 In either of the two power domain state cases above, it is possible that we
357 will not be changing state even though the domain is.
358 Examples:
359 * A change to a lower domain state may not affect us because we are already
360 in a low enough state,
361 * We will not take advantage of a change to a higher domain state, because
362 we have no need of the higher power. In such cases, there is nothing to
363 do but acknowledge the parent. So when the parent calls our
364 powerDomainWillChange method, and we decide that we will not be changing
365 state, we merely acknowledge the parent, via return code, and wait.
366 When the parent subsequently calls powerStateDidChange, we acknowledge again
367 via return code, and the change is complete.
368
369 == 4 Paths Through State Machine ==
370 Power state changes are processed in a state machine, and since there are four
371 varieties of power state changes, there are four major paths through the state
372 machine.
373
374 == 5. No Need To change ==
375 The fourth is nearly trivial. In this path, the parent is changing the domain
376 state, but we are not changing the device state. The change starts when the
377 parent calls powerDomainWillChange. All we do is acknowledge the parent. When
378 the parent calls powerStateDidChange, we acknowledge the parent again, and
379 we're done.
380
381 == 1. OurChange Down == XXX gvdl
382 The first is fairly simple. It starts:
383 * when a power domain child calls requestPowerDomainState and we decide to
384 change power states to accomodate the child,
385 * or if our power-controlling driver calls changePowerStateTo,
386 * or if some other driver which is using our device calls makeUsable,
387 * or if a subclassed object calls changePowerStateToPriv.
388 These are all power changes initiated by us, not forced upon us by the parent.
389
390 -> We start by notifying interested parties.
391 -> If they all acknowledge via return code, we can go on to state
392 "msSetPowerState".
393 -> Otherwise, we start the ack timer and wait for the stragglers to
394 acknowlege by calling acknowledgePowerChange.
395 -> We move on to state "msSetPowerState" when all the
396 stragglers have acknowledged, or when the ack timer expires on
397 all those which didn't acknowledge.
398 In "msSetPowerState" we call the power-controlling driver to change the
399 power state of the hardware.
400 -> If it returns saying it has done so, we go on to state
401 "msWaitForPowerSettle".
402 -> Otherwise, we have to wait for it, so we set the ack timer and wait.
403 -> When it calls acknowledgeSetPowerState, or when the ack timer
404 expires, we go on.
405 In "msWaitForPowerSettle", we look in the power state array to see if
406 there is any settle time required when changing from our current state to the
407 new state.
408 -> If not, we go right away to "msNotifyInterestedDriversDidChange".
409 -> Otherwise, we set the settle timer and wait. When it expires, we move on.
410 In "msNotifyInterestedDriversDidChange" state, we notify all our
411 interested parties via their powerStateDidChange methods that we have finished
412 changing power state.
413 -> If they all acknowledge via return code, we move on to "msFinish".
414 -> Otherwise we set the ack timer and wait. When they have all
415 acknowledged, or when the ack timer has expired for those that didn't,
416 we move on to "msFinish".
417 In "msFinish" we remove the used change note from the head of the queue
418 and start the next one if one exists.
419
420 == 2. Parent Change Down ==
421 Start at Stage 2 of OurChange Down XXX gvdl
422
423 == 3. Change Up ==
424 Start at Stage 4 of OurChange Down XXX gvdl
425
426 Note all parent requested changes need to acknowledge the power has changed to the parent when done.
427 */
428
429 //*********************************************************************************
430 // [public] PMinit
431 //
432 // Initialize power management.
433 //*********************************************************************************
434
435 void IOService::PMinit ( void )
436 {
437 if ( !initialized )
438 {
439 if ( !gIOPMInitialized )
440 {
441 gPlatform = getPlatform();
442 gIOPMWorkLoop = IOWorkLoop::workLoop();
443 if (gIOPMWorkLoop)
444 {
445 gIOPMRequestQueue = IOPMRequestQueue::create(
446 this, OSMemberFunctionCast(IOPMRequestQueue::Action,
447 this, &IOService::servicePMRequestQueue));
448
449 gIOPMReplyQueue = IOPMRequestQueue::create(
450 this, OSMemberFunctionCast(IOPMRequestQueue::Action,
451 this, &IOService::servicePMReplyQueue));
452
453 gIOPMWorkQueue = IOPMWorkQueue::create(
454 this,
455 OSMemberFunctionCast(IOPMWorkQueue::Action, this,
456 &IOService::servicePMRequest),
457 OSMemberFunctionCast(IOPMWorkQueue::Action, this,
458 &IOService::retirePMRequest));
459
460 gIOPMFreeQueue = IOPMCompletionQueue::create(
461 this, OSMemberFunctionCast(IOPMCompletionQueue::Action,
462 this, &IOService::servicePMFreeQueue));
463
464 if (gIOPMWorkLoop->addEventSource(gIOPMRequestQueue) !=
465 kIOReturnSuccess)
466 {
467 gIOPMRequestQueue->release();
468 gIOPMRequestQueue = 0;
469 }
470
471 if (gIOPMWorkLoop->addEventSource(gIOPMReplyQueue) !=
472 kIOReturnSuccess)
473 {
474 gIOPMReplyQueue->release();
475 gIOPMReplyQueue = 0;
476 }
477
478 if (gIOPMWorkLoop->addEventSource(gIOPMWorkQueue) !=
479 kIOReturnSuccess)
480 {
481 gIOPMWorkQueue->release();
482 gIOPMWorkQueue = 0;
483 }
484
485 if (gIOPMWorkLoop->addEventSource(gIOPMFreeQueue) !=
486 kIOReturnSuccess)
487 {
488 gIOPMFreeQueue->release();
489 gIOPMFreeQueue = 0;
490 }
491
492 gIOPMPowerClientDevice =
493 OSSymbol::withCStringNoCopy( "DevicePowerState" );
494
495 gIOPMPowerClientDriver =
496 OSSymbol::withCStringNoCopy( "DriverPowerState" );
497
498 gIOPMPowerClientChildProxy =
499 OSSymbol::withCStringNoCopy( "ChildProxyPowerState" );
500
501 gIOPMPowerClientChildren =
502 OSSymbol::withCStringNoCopy( "ChildrenPowerState" );
503
504 gIOPMPowerClientAdvisoryTickle =
505 OSSymbol::withCStringNoCopy( "AdvisoryTicklePowerState" );
506 }
507
508 if (gIOPMRequestQueue && gIOPMReplyQueue && gIOPMFreeQueue)
509 gIOPMInitialized = true;
510 }
511 if (!gIOPMInitialized)
512 return;
513
514 pwrMgt = new IOServicePM;
515 pwrMgt->init();
516 setProperty(kPwrMgtKey, pwrMgt);
517
518 queue_init(&pwrMgt->WorkChain);
519 queue_init(&pwrMgt->RequestHead);
520 queue_init(&pwrMgt->PMDriverCallQueue);
521
522 fOwner = this;
523 fPMLock = IOLockAlloc();
524 fInterestedDrivers = new IOPMinformeeList;
525 fInterestedDrivers->initialize();
526 fDesiredPowerState = 0;
527 fDeviceDesire = 0;
528 fInitialPowerChange = true;
529 fInitialSetPowerState = true;
530 fPreviousRequestPowerFlags = 0;
531 fDeviceOverrideEnabled = false;
532 fMachineState = kIOPM_Finished;
533 fSavedMachineState = kIOPM_BadMachineState;
534 fIdleTimerMinPowerState = 0;
535 fActivityLock = IOLockAlloc();
536 fStrictTreeOrder = false;
537 fActivityTicklePowerState = kInvalidTicklePowerState;
538 fAdvisoryTicklePowerState = kInvalidTicklePowerState;
539 fControllingDriver = NULL;
540 fPowerStates = NULL;
541 fNumberOfPowerStates = 0;
542 fCurrentPowerState = 0;
543 fParentsCurrentPowerFlags = 0;
544 fMaxPowerState = 0;
545 fName = getName();
546 fParentsKnowState = false;
547 fSerialNumber = 0;
548 fResponseArray = NULL;
549 fNotifyClientArray = NULL;
550 fCurrentPowerConsumption = kIOPMUnknown;
551 fOverrideMaxPowerState = kIOPMPowerStateMax;
552
553 if (!gIOPMRootNode && (getParentEntry(gIOPowerPlane) == getRegistryRoot()))
554 {
555 gIOPMRootNode = this;
556 fParentsKnowState = true;
557 }
558
559 fAckTimer = thread_call_allocate(
560 &IOService::ack_timer_expired, (thread_call_param_t)this);
561 fSettleTimer = thread_call_allocate(
562 &settle_timer_expired, (thread_call_param_t)this);
563 fIdleTimer = thread_call_allocate(
564 &idle_timer_expired, (thread_call_param_t)this);
565 fDriverCallEntry = thread_call_allocate(
566 (thread_call_func_t) &IOService::pmDriverCallout, this);
567 assert(fDriverCallEntry);
568
569 // Check for powerChangeDone override.
570 if (OSMemberFunctionCast(void (*)(void),
571 getResourceService(), &IOService::powerChangeDone) !=
572 OSMemberFunctionCast(void (*)(void),
573 this, &IOService::powerChangeDone))
574 {
575 fPCDFunctionOverride = true;
576 }
577
578 #if PM_VARS_SUPPORT
579 IOPMprot * prot = new IOPMprot;
580 if (prot)
581 {
582 prot->init();
583 prot->ourName = fName;
584 prot->thePlatform = gPlatform;
585 fPMVars = prot;
586 pm_vars = prot;
587 }
588 #else
589 pm_vars = (void *) (uintptr_t) true;
590 #endif
591
592 initialized = true;
593 }
594 }
595
596 //*********************************************************************************
597 // [private] PMfree
598 //
599 // Free the data created by PMinit. Only called from IOService::free().
600 //*********************************************************************************
601
602 void IOService::PMfree ( void )
603 {
604 initialized = false;
605 pm_vars = 0;
606
607 if ( pwrMgt )
608 {
609 assert(fMachineState == kIOPM_Finished);
610 assert(fInsertInterestSet == NULL);
611 assert(fRemoveInterestSet == NULL);
612 assert(fNotifyChildArray == NULL);
613 assert(queue_empty(&pwrMgt->RequestHead));
614 assert(queue_empty(&fPMDriverCallQueue));
615
616 if ( fSettleTimer ) {
617 thread_call_cancel(fSettleTimer);
618 thread_call_free(fSettleTimer);
619 fSettleTimer = NULL;
620 }
621 if ( fAckTimer ) {
622 thread_call_cancel(fAckTimer);
623 thread_call_free(fAckTimer);
624 fAckTimer = NULL;
625 }
626 if ( fIdleTimer ) {
627 thread_call_cancel(fIdleTimer);
628 thread_call_free(fIdleTimer);
629 fIdleTimer = NULL;
630 }
631 if ( fDriverCallEntry ) {
632 thread_call_free(fDriverCallEntry);
633 fDriverCallEntry = NULL;
634 }
635 if ( fPMLock ) {
636 IOLockFree(fPMLock);
637 fPMLock = NULL;
638 }
639 if ( fActivityLock ) {
640 IOLockFree(fActivityLock);
641 fActivityLock = NULL;
642 }
643 if ( fInterestedDrivers ) {
644 fInterestedDrivers->release();
645 fInterestedDrivers = NULL;
646 }
647 if (fDriverCallParamSlots && fDriverCallParamPtr) {
648 IODelete(fDriverCallParamPtr, DriverCallParam, fDriverCallParamSlots);
649 fDriverCallParamPtr = 0;
650 fDriverCallParamSlots = 0;
651 }
652 if ( fResponseArray ) {
653 fResponseArray->release();
654 fResponseArray = NULL;
655 }
656 if ( fNotifyClientArray ) {
657 fNotifyClientArray->release();
658 fNotifyClientArray = NULL;
659 }
660 if (fPowerStates && fNumberOfPowerStates) {
661 IODelete(fPowerStates, IOPMPSEntry, fNumberOfPowerStates);
662 fNumberOfPowerStates = 0;
663 fPowerStates = NULL;
664 }
665 if (fPowerClients) {
666 fPowerClients->release();
667 fPowerClients = 0;
668 }
669
670 #if PM_VARS_SUPPORT
671 if (fPMVars)
672 {
673 fPMVars->release();
674 fPMVars = 0;
675 }
676 #endif
677
678 pwrMgt->release();
679 pwrMgt = 0;
680 }
681 }
682
683 void IOService::PMDebug( uint32_t event, uintptr_t param1, uintptr_t param2 )
684 {
685 OUR_PMLog(event, param1, param2);
686 }
687
688 //*********************************************************************************
689 // [public] joinPMtree
690 //
691 // A policy-maker calls its nub here when initializing, to be attached into
692 // the power management hierarchy. The default function is to call the
693 // platform expert, which knows how to do it. This method is overridden
694 // by a nub subclass which may either know how to do it, or may need to
695 // take other action.
696 //
697 // This may be the only "power management" method used in a nub,
698 // meaning it may not be initialized for power management.
699 //*********************************************************************************
700
701 void IOService::joinPMtree ( IOService * driver )
702 {
703 IOPlatformExpert * platform;
704
705 platform = getPlatform();
706 assert(platform != 0);
707 platform->PMRegisterDevice(this, driver);
708 }
709
710 #ifndef __LP64__
711 //*********************************************************************************
712 // [deprecated] youAreRoot
713 //
714 // Power Managment is informing us that we are the root power domain.
715 //*********************************************************************************
716
717 IOReturn IOService::youAreRoot ( void )
718 {
719 return IOPMNoErr;
720 }
721 #endif /* !__LP64__ */
722
723 //*********************************************************************************
724 // [public] PMstop
725 //
726 // Immediately stop driver callouts. Schedule an async stop request to detach
727 // from power plane.
728 //*********************************************************************************
729
730 void IOService::PMstop ( void )
731 {
732 IOPMRequest * request;
733
734 if (!initialized)
735 return;
736
737 PM_LOCK();
738
739 if (fLockedFlags.PMStop)
740 {
741 PM_LOG2("%s: PMstop() already stopped\n", fName);
742 PM_UNLOCK();
743 return;
744 }
745
746 // Inhibit future driver calls.
747 fLockedFlags.PMStop = true;
748
749 // Wait for all prior driver calls to finish.
750 waitForPMDriverCall();
751
752 PM_UNLOCK();
753
754 // The rest of the work is performed async.
755 request = acquirePMRequest( this, kIOPMRequestTypePMStop );
756 if (request)
757 {
758 PM_LOG2("%s: %p PMstop\n", getName(), this);
759 submitPMRequest( request );
760 }
761 }
762
763 //*********************************************************************************
764 // [private] handlePMstop
765 //
766 // Disconnect the node from all parents and children in the power plane.
767 //*********************************************************************************
768
769 void IOService::handlePMstop ( IOPMRequest * request )
770 {
771 OSIterator * iter;
772 OSObject * next;
773 IOPowerConnection * connection;
774 IOService * theChild;
775 IOService * theParent;
776
777 PM_ASSERT_IN_GATE();
778 PM_LOG2("%s: %p %s start\n", getName(), this, __FUNCTION__);
779
780 // remove driver from prevent system sleep lists
781 getPMRootDomain()->updatePreventIdleSleepList(this, false);
782 getPMRootDomain()->updatePreventSystemSleepList(this, false);
783
784 // remove the property
785 removeProperty(kPwrMgtKey);
786
787 // detach parents
788 iter = getParentIterator(gIOPowerPlane);
789 if ( iter )
790 {
791 while ( (next = iter->getNextObject()) )
792 {
793 if ( (connection = OSDynamicCast(IOPowerConnection, next)) )
794 {
795 theParent = (IOService *)connection->copyParentEntry(gIOPowerPlane);
796 if ( theParent )
797 {
798 theParent->removePowerChild(connection);
799 theParent->release();
800 }
801 }
802 }
803 iter->release();
804 }
805
806 // detach IOConnections
807 detachAbove( gIOPowerPlane );
808
809 // no more power state changes
810 fParentsKnowState = false;
811
812 // detach children
813 iter = getChildIterator(gIOPowerPlane);
814 if ( iter )
815 {
816 while ( (next = iter->getNextObject()) )
817 {
818 if ( (connection = OSDynamicCast(IOPowerConnection, next)) )
819 {
820 theChild = ((IOService *)(connection->copyChildEntry(gIOPowerPlane)));
821 if ( theChild )
822 {
823 // detach nub from child
824 connection->detachFromChild(theChild, gIOPowerPlane);
825 theChild->release();
826 }
827 // detach us from nub
828 detachFromChild(connection, gIOPowerPlane);
829 }
830 }
831 iter->release();
832 }
833
834 // Remove all interested drivers from the list, including the power
835 // controlling driver.
836 //
837 // Usually, the controlling driver and the policy-maker functionality
838 // are implemented by the same object, and without the deregistration,
839 // the object will be holding an extra retain on itself, and cannot
840 // be freed.
841
842 if ( fInterestedDrivers )
843 {
844 IOPMinformeeList * list = fInterestedDrivers;
845 IOPMinformee * item;
846
847 PM_LOCK();
848 while ((item = list->firstInList()))
849 {
850 list->removeFromList(item->whatObject);
851 }
852 PM_UNLOCK();
853 }
854
855 // Tell idleTimerExpired() to ignore idle timer.
856 fIdleTimerPeriod = 0;
857 if (fIdleTimer && thread_call_cancel(fIdleTimer))
858 release();
859
860 PM_LOG2("%s: %p %s done\n", getName(), this, __FUNCTION__);
861 }
862
863 //*********************************************************************************
864 // [public] addPowerChild
865 //
866 // Power Management is informing us who our children are.
867 //*********************************************************************************
868
869 IOReturn IOService::addPowerChild ( IOService * child )
870 {
871 IOPowerConnection * connection = 0;
872 IOPMRequest * requests[3] = {0, 0, 0};
873 OSIterator * iter;
874 bool ok = true;
875
876 if (!child)
877 return kIOReturnBadArgument;
878
879 if (!initialized || !child->initialized)
880 return IOPMNotYetInitialized;
881
882 OUR_PMLog( kPMLogAddChild, (uintptr_t) child, 0 );
883
884 do {
885 // Is this child already one of our children?
886
887 iter = child->getParentIterator( gIOPowerPlane );
888 if ( iter )
889 {
890 IORegistryEntry * entry;
891 OSObject * next;
892
893 while ((next = iter->getNextObject()))
894 {
895 if ((entry = OSDynamicCast(IORegistryEntry, next)) &&
896 isChild(entry, gIOPowerPlane))
897 {
898 ok = false;
899 break;
900 }
901 }
902 iter->release();
903 }
904 if (!ok)
905 {
906 PM_LOG("%s: %s (%p) is already a child\n",
907 getName(), child->getName(), child);
908 break;
909 }
910
911 // Add the child to the power plane immediately, but the
912 // joining connection is marked as not ready.
913 // We want the child to appear in the power plane before
914 // returning to the caller, but don't want the caller to
915 // block on the PM work loop.
916
917 connection = new IOPowerConnection;
918 if (!connection)
919 break;
920
921 // Create a chain of PM requests to perform the bottom-half
922 // work from the PM work loop.
923
924 requests[0] = acquirePMRequest(
925 /* target */ this,
926 /* type */ kIOPMRequestTypeAddPowerChild1 );
927
928 requests[1] = acquirePMRequest(
929 /* target */ child,
930 /* type */ kIOPMRequestTypeAddPowerChild2 );
931
932 requests[2] = acquirePMRequest(
933 /* target */ this,
934 /* type */ kIOPMRequestTypeAddPowerChild3 );
935
936 if (!requests[0] || !requests[1] || !requests[2])
937 break;
938
939 requests[0]->attachNextRequest( requests[1] );
940 requests[1]->attachNextRequest( requests[2] );
941
942 connection->init();
943 connection->start(this);
944 connection->setAwaitingAck(false);
945 connection->setReadyFlag(false);
946
947 attachToChild( connection, gIOPowerPlane );
948 connection->attachToChild( child, gIOPowerPlane );
949
950 // connection needs to be released
951 requests[0]->fArg0 = connection;
952 requests[1]->fArg0 = connection;
953 requests[2]->fArg0 = connection;
954
955 submitPMRequest( requests, 3 );
956 return kIOReturnSuccess;
957 }
958 while (false);
959
960 if (connection) connection->release();
961 if (requests[0]) releasePMRequest(requests[0]);
962 if (requests[1]) releasePMRequest(requests[1]);
963 if (requests[2]) releasePMRequest(requests[2]);
964
965 // Silent failure, to prevent platform drivers from adding the child
966 // to the root domain.
967
968 return kIOReturnSuccess;
969 }
970
971 //*********************************************************************************
972 // [private] addPowerChild1
973 //
974 // Step 1/3 of adding a power child. Called on the power parent.
975 //*********************************************************************************
976
977 void IOService::addPowerChild1 ( IOPMRequest * request )
978 {
979 unsigned long tempDesire = 0;
980
981 // Make us temporary usable before adding the child.
982
983 PM_ASSERT_IN_GATE();
984 OUR_PMLog( kPMLogMakeUsable, kPMLogMakeUsable, 0 );
985
986 if (fControllingDriver && inPlane(gIOPowerPlane) && fParentsKnowState)
987 {
988 tempDesire = fNumberOfPowerStates - 1;
989 }
990
991 if (tempDesire && (IS_PM_ROOT || (fMaxPowerState >= tempDesire)))
992 {
993 adjustPowerState(tempDesire);
994 }
995 }
996
997 //*********************************************************************************
998 // [private] addPowerChild2
999 //
1000 // Step 2/3 of adding a power child. Called on the joining child.
1001 // Execution blocked behind addPowerChild1.
1002 //*********************************************************************************
1003
1004 void IOService::addPowerChild2 ( IOPMRequest * request )
1005 {
1006 IOPowerConnection * connection = (IOPowerConnection *) request->fArg0;
1007 IOService * parent;
1008 IOPMPowerFlags powerFlags;
1009 bool knowsState;
1010 unsigned long powerState;
1011 unsigned long tempDesire;
1012
1013 PM_ASSERT_IN_GATE();
1014 parent = (IOService *) connection->getParentEntry(gIOPowerPlane);
1015
1016 if (!parent || !inPlane(gIOPowerPlane))
1017 {
1018 PM_LOG("%s: addPowerChild2 not in power plane\n", getName());
1019 return;
1020 }
1021
1022 // Parent will be waiting for us to complete this stage.
1023 // It is safe to directly access parent's vars.
1024
1025 knowsState = (parent->fPowerStates) && (parent->fParentsKnowState);
1026 powerState = parent->fCurrentPowerState;
1027
1028 if (knowsState)
1029 powerFlags = parent->fPowerStates[powerState].outputPowerFlags;
1030 else
1031 powerFlags = 0;
1032
1033 // Set our power parent.
1034
1035 OUR_PMLog(kPMLogSetParent, knowsState, powerFlags);
1036
1037 setParentInfo( powerFlags, connection, knowsState );
1038
1039 connection->setReadyFlag(true);
1040
1041 if ( fControllingDriver && fParentsKnowState )
1042 {
1043 fMaxPowerState = fControllingDriver->maxCapabilityForDomainState(fParentsCurrentPowerFlags);
1044 // initially change into the state we are already in
1045 tempDesire = fControllingDriver->initialPowerStateForDomainState(fParentsCurrentPowerFlags);
1046 fPreviousRequestPowerFlags = (IOPMPowerFlags)(-1);
1047 adjustPowerState(tempDesire);
1048 }
1049
1050 getPMRootDomain()->tagPowerPlaneService(this, &fPMActions);
1051 }
1052
1053 //*********************************************************************************
1054 // [private] addPowerChild3
1055 //
1056 // Step 3/3 of adding a power child. Called on the parent.
1057 // Execution blocked behind addPowerChild2.
1058 //*********************************************************************************
1059
1060 void IOService::addPowerChild3 ( IOPMRequest * request )
1061 {
1062 IOPowerConnection * connection = (IOPowerConnection *) request->fArg0;
1063 IOService * child;
1064 IOPMrootDomain * rootDomain = getPMRootDomain();
1065
1066 PM_ASSERT_IN_GATE();
1067 child = (IOService *) connection->getChildEntry(gIOPowerPlane);
1068
1069 if (child && inPlane(gIOPowerPlane))
1070 {
1071 if ((this != rootDomain) && child->getProperty("IOPMStrictTreeOrder"))
1072 {
1073 PM_LOG1("%s: strict PM order enforced\n", getName());
1074 fStrictTreeOrder = true;
1075 }
1076
1077 if (rootDomain)
1078 rootDomain->joinAggressiveness( child );
1079 }
1080 else
1081 {
1082 PM_LOG("%s: addPowerChild3 not in power plane\n", getName());
1083 }
1084
1085 connection->release();
1086 }
1087
1088 #ifndef __LP64__
1089 //*********************************************************************************
1090 // [deprecated] setPowerParent
1091 //
1092 // Power Management is informing us who our parent is.
1093 // If we have a controlling driver, find out, given our newly-informed
1094 // power domain state, what state it would be in, and then tell it
1095 // to assume that state.
1096 //*********************************************************************************
1097
1098 IOReturn IOService::setPowerParent (
1099 IOPowerConnection * theParent, bool stateKnown, IOPMPowerFlags powerFlags )
1100 {
1101 return kIOReturnUnsupported;
1102 }
1103 #endif /* !__LP64__ */
1104
1105 //*********************************************************************************
1106 // [public] removePowerChild
1107 //
1108 // Called on a parent whose child is being removed by PMstop().
1109 //*********************************************************************************
1110
1111 IOReturn IOService::removePowerChild ( IOPowerConnection * theNub )
1112 {
1113 IORegistryEntry * theChild;
1114
1115 PM_ASSERT_IN_GATE();
1116 OUR_PMLog( kPMLogRemoveChild, 0, 0 );
1117
1118 theNub->retain();
1119
1120 // detach nub from child
1121 theChild = theNub->copyChildEntry(gIOPowerPlane);
1122 if ( theChild )
1123 {
1124 theNub->detachFromChild(theChild, gIOPowerPlane);
1125 theChild->release();
1126 }
1127 // detach from the nub
1128 detachFromChild(theNub, gIOPowerPlane);
1129
1130 // Are we awaiting an ack from this child?
1131 if ( theNub->getAwaitingAck() )
1132 {
1133 // yes, pretend we got one
1134 theNub->setAwaitingAck(false);
1135 if (fHeadNotePendingAcks != 0 )
1136 {
1137 // that's one fewer ack to worry about
1138 fHeadNotePendingAcks--;
1139
1140 // is that the last?
1141 if ( fHeadNotePendingAcks == 0 )
1142 {
1143 stop_ack_timer();
1144
1145 // Request unblocked, work queue
1146 // should re-scan all busy requests.
1147 gIOPMWorkQueue->incrementProducerCount();
1148 }
1149 }
1150 }
1151
1152 theNub->release();
1153
1154 // A child has gone away, re-scan children desires and clamp bits.
1155 // The fPendingAdjustPowerRequest helps to reduce redundant parent work.
1156
1157 if (!fAdjustPowerScheduled)
1158 {
1159 IOPMRequest * request;
1160 request = acquirePMRequest( this, kIOPMRequestTypeAdjustPowerState );
1161 if (request)
1162 {
1163 submitPMRequest( request );
1164 fAdjustPowerScheduled = true;
1165 }
1166 }
1167
1168 return IOPMNoErr;
1169 }
1170
1171 //*********************************************************************************
1172 // [public] registerPowerDriver
1173 //
1174 // A driver has called us volunteering to control power to our device.
1175 //*********************************************************************************
1176
1177 IOReturn IOService::registerPowerDriver (
1178 IOService * powerDriver,
1179 IOPMPowerState * powerStates,
1180 unsigned long numberOfStates )
1181 {
1182 IOPMRequest * request;
1183 IOPMPSEntry * powerStatesCopy = 0;
1184
1185 if (!initialized)
1186 return IOPMNotYetInitialized;
1187
1188 // Validate arguments.
1189 if (!powerStates || (numberOfStates < 2))
1190 {
1191 OUR_PMLog(kPMLogControllingDriverErr5, numberOfStates, 0);
1192 return kIOReturnBadArgument;
1193 }
1194
1195 if (!powerDriver || !powerDriver->initialized)
1196 {
1197 OUR_PMLog(kPMLogControllingDriverErr4, 0, 0);
1198 return kIOReturnBadArgument;
1199 }
1200
1201 if (powerStates[0].version != kIOPMPowerStateVersion1)
1202 {
1203 OUR_PMLog(kPMLogControllingDriverErr1, powerStates[0].version, 0);
1204 return kIOReturnBadArgument;
1205 }
1206
1207 do {
1208 // Make a copy of the supplied power state array.
1209 powerStatesCopy = IONew(IOPMPSEntry, numberOfStates);
1210 if (!powerStatesCopy)
1211 break;
1212
1213 for (uint32_t i = 0; i < numberOfStates; i++)
1214 {
1215 powerStatesCopy[i].capabilityFlags = powerStates[i].capabilityFlags;
1216 powerStatesCopy[i].outputPowerFlags = powerStates[i].outputPowerCharacter;
1217 powerStatesCopy[i].inputPowerFlags = powerStates[i].inputPowerRequirement;
1218 powerStatesCopy[i].staticPower = powerStates[i].staticPower;
1219 powerStatesCopy[i].settleUpTime = powerStates[i].settleUpTime;
1220 powerStatesCopy[i].settleDownTime = powerStates[i].settleDownTime;
1221 }
1222
1223 request = acquirePMRequest( this, kIOPMRequestTypeRegisterPowerDriver );
1224 if (!request)
1225 break;
1226
1227 powerDriver->retain();
1228 request->fArg0 = (void *) powerDriver;
1229 request->fArg1 = (void *) powerStatesCopy;
1230 request->fArg2 = (void *) numberOfStates;
1231
1232 submitPMRequest( request );
1233 return kIOReturnSuccess;
1234 }
1235 while (false);
1236
1237 if (powerStatesCopy)
1238 IODelete(powerStatesCopy, IOPMPSEntry, numberOfStates);
1239 return kIOReturnNoMemory;
1240 }
1241
1242 //*********************************************************************************
1243 // [private] handleRegisterPowerDriver
1244 //*********************************************************************************
1245
1246 void IOService::handleRegisterPowerDriver ( IOPMRequest * request )
1247 {
1248 IOService * powerDriver = (IOService *) request->fArg0;
1249 IOPMPSEntry * powerStates = (IOPMPSEntry *) request->fArg1;
1250 unsigned long numberOfStates = (unsigned long) request->fArg2;
1251 unsigned long i;
1252 IOService * root;
1253 OSIterator * iter;
1254
1255 PM_ASSERT_IN_GATE();
1256 assert(powerStates);
1257 assert(powerDriver);
1258 assert(numberOfStates > 1);
1259
1260 if ( !fNumberOfPowerStates )
1261 {
1262 OUR_PMLog(kPMLogControllingDriver,
1263 (unsigned long) numberOfStates,
1264 (unsigned long) kIOPMPowerStateVersion1);
1265
1266 fPowerStates = powerStates;
1267 fNumberOfPowerStates = numberOfStates;
1268 fControllingDriver = powerDriver;
1269 fCurrentCapabilityFlags = fPowerStates[0].capabilityFlags;
1270
1271 // make a mask of all the character bits we know about
1272 fOutputPowerCharacterFlags = 0;
1273 for ( i = 0; i < numberOfStates; i++ ) {
1274 fOutputPowerCharacterFlags |= fPowerStates[i].outputPowerFlags;
1275 if (!fDeviceUsablePowerState &&
1276 (fPowerStates[i].capabilityFlags & IOPMDeviceUsable))
1277 {
1278 // The minimum power state that the device is usable
1279 fDeviceUsablePowerState = i;
1280 }
1281 }
1282
1283 // Register powerDriver as interested, unless already done.
1284 // We don't want to register the default implementation since
1285 // it does nothing. One ramification of not always registering
1286 // is the one fewer retain count held.
1287
1288 root = getPlatform()->getProvider();
1289 assert(root);
1290 if (!root ||
1291 ((OSMemberFunctionCast(void (*)(void),
1292 root, &IOService::powerStateDidChangeTo)) !=
1293 ((OSMemberFunctionCast(void (*)(void),
1294 this, &IOService::powerStateDidChangeTo)))) ||
1295 ((OSMemberFunctionCast(void (*)(void),
1296 root, &IOService::powerStateWillChangeTo)) !=
1297 ((OSMemberFunctionCast(void (*)(void),
1298 this, &IOService::powerStateWillChangeTo)))))
1299 {
1300 if (fInterestedDrivers->findItem(powerDriver) == NULL)
1301 {
1302 PM_LOCK();
1303 fInterestedDrivers->appendNewInformee(powerDriver);
1304 PM_UNLOCK();
1305 }
1306 }
1307
1308 // Examine all existing power clients and perform limit check.
1309
1310 if (fPowerClients)
1311 {
1312 iter = OSCollectionIterator::withCollection(fPowerClients);
1313 if (iter)
1314 {
1315 const OSSymbol * client;
1316 while ((client = (const OSSymbol *) iter->getNextObject()))
1317 {
1318 uint32_t powerState = getPowerStateForClient(client);
1319 if (powerState >= numberOfStates)
1320 {
1321 updatePowerClient(client, numberOfStates - 1);
1322 }
1323 }
1324 iter->release();
1325 }
1326 }
1327
1328 if ( inPlane(gIOPowerPlane) && fParentsKnowState )
1329 {
1330 unsigned long tempDesire;
1331 fMaxPowerState = fControllingDriver->maxCapabilityForDomainState(fParentsCurrentPowerFlags);
1332 // initially change into the state we are already in
1333 tempDesire = fControllingDriver->initialPowerStateForDomainState(fParentsCurrentPowerFlags);
1334 adjustPowerState(tempDesire);
1335 }
1336 }
1337 else
1338 {
1339 OUR_PMLog(kPMLogControllingDriverErr2, numberOfStates, 0);
1340 IODelete(powerStates, IOPMPSEntry, numberOfStates);
1341 }
1342
1343 powerDriver->release();
1344 }
1345
1346 //*********************************************************************************
1347 // [public] registerInterestedDriver
1348 //
1349 // Add the caller to our list of interested drivers and return our current
1350 // power state. If we don't have a power-controlling driver yet, we will
1351 // call this interested driver again later when we do get a driver and find
1352 // out what the current power state of the device is.
1353 //*********************************************************************************
1354
1355 IOPMPowerFlags IOService::registerInterestedDriver ( IOService * driver )
1356 {
1357 IOPMRequest * request;
1358 bool signal;
1359
1360 if (!driver || !initialized || !fInterestedDrivers)
1361 return 0;
1362
1363 PM_LOCK();
1364 signal = (!fInsertInterestSet && !fRemoveInterestSet);
1365 if (fInsertInterestSet == NULL)
1366 fInsertInterestSet = OSSet::withCapacity(4);
1367 if (fInsertInterestSet)
1368 {
1369 fInsertInterestSet->setObject(driver);
1370 if (fRemoveInterestSet)
1371 fRemoveInterestSet->removeObject(driver);
1372 }
1373 PM_UNLOCK();
1374
1375 if (signal)
1376 {
1377 request = acquirePMRequest( this, kIOPMRequestTypeInterestChanged );
1378 if (request)
1379 submitPMRequest( request );
1380 }
1381
1382 // This return value cannot be trusted, but return a value
1383 // for those clients that care.
1384
1385 OUR_PMLog(kPMLogInterestedDriver, kIOPMDeviceUsable, 2);
1386 return kIOPMDeviceUsable;
1387 }
1388
1389 //*********************************************************************************
1390 // [public] deRegisterInterestedDriver
1391 //*********************************************************************************
1392
1393 IOReturn IOService::deRegisterInterestedDriver ( IOService * driver )
1394 {
1395 IOPMinformeeList * list;
1396 IOPMinformee * item;
1397 IOPMRequest * request;
1398 bool signal;
1399
1400 if (!driver)
1401 return kIOReturnBadArgument;
1402 if (!initialized || !fInterestedDrivers)
1403 return IOPMNotPowerManaged;
1404
1405 PM_LOCK();
1406 signal = (!fRemoveInterestSet && !fInsertInterestSet);
1407 if (fRemoveInterestSet == NULL)
1408 fRemoveInterestSet = OSSet::withCapacity(4);
1409 if (fRemoveInterestSet)
1410 {
1411 fRemoveInterestSet->setObject(driver);
1412 if (fInsertInterestSet)
1413 fInsertInterestSet->removeObject(driver);
1414
1415 list = fInterestedDrivers;
1416 item = list->findItem(driver);
1417 if (item && item->active)
1418 {
1419 item->active = false;
1420 waitForPMDriverCall( driver );
1421 }
1422 }
1423 PM_UNLOCK();
1424
1425 if (signal)
1426 {
1427 request = acquirePMRequest( this, kIOPMRequestTypeInterestChanged );
1428 if (request)
1429 submitPMRequest( request );
1430 }
1431
1432 return IOPMNoErr;
1433 }
1434
1435 //*********************************************************************************
1436 // [private] handleInterestChanged
1437 //
1438 // Handle interest added or removed.
1439 //*********************************************************************************
1440
1441 void IOService::handleInterestChanged( IOPMRequest * request )
1442 {
1443 IOService * driver;
1444 IOPMinformee * informee;
1445 IOPMinformeeList * list = fInterestedDrivers;
1446
1447 PM_LOCK();
1448
1449 if (fInsertInterestSet)
1450 {
1451 while ((driver = (IOService *) fInsertInterestSet->getAnyObject()))
1452 {
1453 if (list->findItem(driver) == NULL)
1454 {
1455 informee = list->appendNewInformee(driver);
1456 }
1457 fInsertInterestSet->removeObject(driver);
1458 }
1459 fInsertInterestSet->release();
1460 fInsertInterestSet = 0;
1461 }
1462
1463 if (fRemoveInterestSet)
1464 {
1465 while ((driver = (IOService *) fRemoveInterestSet->getAnyObject()))
1466 {
1467 informee = list->findItem(driver);
1468 if (informee)
1469 {
1470 // Clean-up async interest acknowledgement
1471 if (fHeadNotePendingAcks && informee->timer)
1472 {
1473 informee->timer = 0;
1474 fHeadNotePendingAcks--;
1475 }
1476 list->removeFromList(driver);
1477 }
1478 fRemoveInterestSet->removeObject(driver);
1479 }
1480 fRemoveInterestSet->release();
1481 fRemoveInterestSet = 0;
1482 }
1483
1484 PM_UNLOCK();
1485 }
1486
1487 //*********************************************************************************
1488 // [public] acknowledgePowerChange
1489 //
1490 // After we notified one of the interested drivers or a power-domain child
1491 // of an impending change in power, it has called to say it is now
1492 // prepared for the change. If this object is the last to
1493 // acknowledge this change, we take whatever action we have been waiting
1494 // for.
1495 // That may include acknowledging to our parent. In this case, we do it
1496 // last of all to insure that this doesn't cause the parent to call us some-
1497 // where else and alter data we are relying on here (like the very existance
1498 // of a "current change note".)
1499 //*********************************************************************************
1500
1501 IOReturn IOService::acknowledgePowerChange ( IOService * whichObject )
1502 {
1503 IOPMRequest * request;
1504
1505 if (!initialized)
1506 return IOPMNotYetInitialized;
1507 if (!whichObject)
1508 return kIOReturnBadArgument;
1509
1510 request = acquirePMRequest( this, kIOPMRequestTypeAckPowerChange );
1511 if (!request)
1512 return kIOReturnNoMemory;
1513
1514 whichObject->retain();
1515 request->fArg0 = whichObject;
1516
1517 submitPMRequest( request );
1518 return IOPMNoErr;
1519 }
1520
1521 //*********************************************************************************
1522 // [private] handleAcknowledgePowerChange
1523 //*********************************************************************************
1524
1525 bool IOService::handleAcknowledgePowerChange ( IOPMRequest * request )
1526 {
1527 IOPMinformee * informee;
1528 unsigned long childPower = kIOPMUnknown;
1529 IOService * theChild;
1530 IOService * whichObject;
1531 bool all_acked = false;
1532
1533 PM_ASSERT_IN_GATE();
1534 whichObject = (IOService *) request->fArg0;
1535 assert(whichObject);
1536
1537 // one of our interested drivers?
1538 informee = fInterestedDrivers->findItem( whichObject );
1539 if ( informee == NULL )
1540 {
1541 if ( !isChild(whichObject, gIOPowerPlane) )
1542 {
1543 OUR_PMLog(kPMLogAcknowledgeErr1, 0, 0);
1544 goto no_err;
1545 } else {
1546 OUR_PMLog(kPMLogChildAcknowledge, fHeadNotePendingAcks, 0);
1547 }
1548 } else {
1549 OUR_PMLog(kPMLogDriverAcknowledge, fHeadNotePendingAcks, 0);
1550 }
1551
1552 if ( fHeadNotePendingAcks != 0 )
1553 {
1554 assert(fPowerStates != NULL);
1555
1556 // yes, make sure we're expecting acks
1557 if ( informee != NULL )
1558 {
1559 // it's an interested driver
1560 // make sure we're expecting this ack
1561 if ( informee->timer != 0 )
1562 {
1563 #if LOG_SETPOWER_TIMES
1564 if (informee->timer > 0)
1565 {
1566 uint64_t nsec = computeTimeDeltaNS(&informee->startTime);
1567 if (nsec > LOG_SETPOWER_TIMES)
1568 PM_LOG("%s::powerState%sChangeTo(%p, %s, %lu -> %lu) async took %d ms\n",
1569 informee->whatObject->getName(),
1570 (fDriverCallReason == kDriverCallInformPreChange) ? "Will" : "Did",
1571 informee->whatObject,
1572 fName, fCurrentPowerState, fHeadNotePowerState, NS_TO_US(nsec));
1573
1574 uint16_t logType = (fDriverCallReason == kDriverCallInformPreChange)
1575 ? kIOPMEventTypePSWillChangeTo
1576 : kIOPMEventTypePSDidChangeTo;
1577
1578 PMEventDetails *details = PMEventDetails::eventDetails(
1579 logType,
1580 fName,
1581 (uintptr_t)this,
1582 informee->whatObject->getName(),
1583 0, 0, 0,
1584 NS_TO_MS(nsec));
1585
1586 getPMRootDomain()->recordAndReleasePMEventGated( details );
1587 }
1588 #endif
1589 // mark it acked
1590 informee->timer = 0;
1591 // that's one fewer to worry about
1592 fHeadNotePendingAcks--;
1593 } else {
1594 // this driver has already acked
1595 OUR_PMLog(kPMLogAcknowledgeErr2, 0, 0);
1596 }
1597 } else {
1598 // it's a child
1599 // make sure we're expecting this ack
1600 if ( ((IOPowerConnection *)whichObject)->getAwaitingAck() )
1601 {
1602 // that's one fewer to worry about
1603 fHeadNotePendingAcks--;
1604 ((IOPowerConnection *)whichObject)->setAwaitingAck(false);
1605 theChild = (IOService *)whichObject->copyChildEntry(gIOPowerPlane);
1606 if ( theChild )
1607 {
1608 childPower = theChild->currentPowerConsumption();
1609 theChild->release();
1610 }
1611 if ( childPower == kIOPMUnknown )
1612 {
1613 fHeadNotePowerArrayEntry->staticPower = kIOPMUnknown;
1614 } else {
1615 if (fHeadNotePowerArrayEntry->staticPower != kIOPMUnknown)
1616 {
1617 fHeadNotePowerArrayEntry->staticPower += childPower;
1618 }
1619 }
1620 }
1621 }
1622
1623 if ( fHeadNotePendingAcks == 0 ) {
1624 // yes, stop the timer
1625 stop_ack_timer();
1626 // and now we can continue
1627 all_acked = true;
1628 }
1629 } else {
1630 OUR_PMLog(kPMLogAcknowledgeErr3, 0, 0); // not expecting anybody to ack
1631 }
1632
1633 no_err:
1634 if (whichObject)
1635 whichObject->release();
1636
1637 return all_acked;
1638 }
1639
1640 //*********************************************************************************
1641 // [public] acknowledgeSetPowerState
1642 //
1643 // After we instructed our controlling driver to change power states,
1644 // it has called to say it has finished doing so.
1645 // We continue to process the power state change.
1646 //*********************************************************************************
1647
1648 IOReturn IOService::acknowledgeSetPowerState ( void )
1649 {
1650 IOPMRequest * request;
1651
1652 if (!initialized)
1653 return IOPMNotYetInitialized;
1654
1655 request = acquirePMRequest( this, kIOPMRequestTypeAckSetPowerState );
1656 if (!request)
1657 return kIOReturnNoMemory;
1658
1659 submitPMRequest( request );
1660 return kIOReturnSuccess;
1661 }
1662
1663 //*********************************************************************************
1664 // [private] adjustPowerState
1665 //*********************************************************************************
1666
1667 void IOService::adjustPowerState ( uint32_t clamp )
1668 {
1669 PM_ASSERT_IN_GATE();
1670 computeDesiredState(clamp);
1671 if (fControllingDriver && fParentsKnowState && inPlane(gIOPowerPlane))
1672 {
1673 IOPMPowerChangeFlags changeFlags = kIOPMSelfInitiated;
1674
1675 // Indicate that children desires were ignored, and do not ask
1676 // apps for permission to drop power. This is used by root domain
1677 // for demand sleep.
1678
1679 if (getPMRequestType() == kIOPMRequestTypeRequestPowerStateOverride)
1680 changeFlags |= (kIOPMIgnoreChildren | kIOPMSkipAskPowerDown);
1681
1682 startPowerChange(
1683 /* flags */ changeFlags,
1684 /* power state */ fDesiredPowerState,
1685 /* domain flags */ 0,
1686 /* connection */ 0,
1687 /* parent flags */ 0);
1688 }
1689 }
1690
1691 //*********************************************************************************
1692 // [public] synchronizePowerTree
1693 //*********************************************************************************
1694
1695 IOReturn IOService::synchronizePowerTree (
1696 IOOptionBits options,
1697 IOService * notifyRoot )
1698 {
1699 IOPMRequest * request_c = 0;
1700 IOPMRequest * request_s;
1701
1702 if (this != getPMRootDomain())
1703 return kIOReturnBadArgument;
1704 if (!initialized)
1705 return kIOPMNotYetInitialized;
1706
1707 if (notifyRoot)
1708 {
1709 IOPMRequest * nr;
1710
1711 // Cancels don't need to be synchronized.
1712 nr = acquirePMRequest(notifyRoot, kIOPMRequestTypeChildNotifyDelayCancel);
1713 if (nr) submitPMRequest(nr);
1714 nr = acquirePMRequest(getPMRootDomain(), kIOPMRequestTypeChildNotifyDelayCancel);
1715 if (nr) submitPMRequest(nr);
1716 }
1717
1718 request_s = acquirePMRequest( this, kIOPMRequestTypeSynchronizePowerTree );
1719 if (!request_s)
1720 goto error_no_memory;
1721
1722 if (options & kIOPMSyncCancelPowerDown)
1723 request_c = acquirePMRequest( this, kIOPMRequestTypeIdleCancel );
1724 if (request_c)
1725 {
1726 request_c->attachNextRequest( request_s );
1727 submitPMRequest(request_c);
1728 }
1729
1730 request_s->fArg0 = (void *)(uintptr_t) options;
1731 submitPMRequest(request_s);
1732
1733 return kIOReturnSuccess;
1734
1735 error_no_memory:
1736 if (request_c) releasePMRequest(request_c);
1737 if (request_s) releasePMRequest(request_s);
1738 return kIOReturnNoMemory;
1739 }
1740
1741 //*********************************************************************************
1742 // [private] handleSynchronizePowerTree
1743 //*********************************************************************************
1744
1745 void IOService::handleSynchronizePowerTree ( IOPMRequest * request )
1746 {
1747 PM_ASSERT_IN_GATE();
1748 if (fControllingDriver && fParentsKnowState && inPlane(gIOPowerPlane) &&
1749 (fCurrentPowerState == fNumberOfPowerStates - 1))
1750 {
1751 IOOptionBits options = (uintptr_t) request->fArg0;
1752
1753 startPowerChange(
1754 /* flags */ kIOPMSelfInitiated | kIOPMSynchronize |
1755 (options & kIOPMSyncNoChildNotify),
1756 /* power state */ fCurrentPowerState,
1757 /* domain flags */ 0,
1758 /* connection */ 0,
1759 /* parent flags */ 0);
1760 }
1761 }
1762
1763 #ifndef __LP64__
1764 //*********************************************************************************
1765 // [deprecated] powerDomainWillChangeTo
1766 //
1767 // Called by the power-hierarchy parent notifying of a new power state
1768 // in the power domain.
1769 // We enqueue a parent power-change to our queue of power changes.
1770 // This may or may not cause us to change power, depending on what
1771 // kind of change is occuring in the domain.
1772 //*********************************************************************************
1773
1774 IOReturn IOService::powerDomainWillChangeTo (
1775 IOPMPowerFlags newPowerFlags,
1776 IOPowerConnection * whichParent )
1777 {
1778 assert(false);
1779 return kIOReturnUnsupported;
1780 }
1781 #endif /* !__LP64__ */
1782
1783 //*********************************************************************************
1784 // [private] handlePowerDomainWillChangeTo
1785 //*********************************************************************************
1786
1787 void IOService::handlePowerDomainWillChangeTo ( IOPMRequest * request )
1788 {
1789 IOPMPowerFlags parentPowerFlags = (IOPMPowerFlags) request->fArg0;
1790 IOPowerConnection * whichParent = (IOPowerConnection *) request->fArg1;
1791 IOPMPowerChangeFlags parentChangeFlags = (IOPMPowerChangeFlags)(uintptr_t) request->fArg2;
1792 IOPMPowerChangeFlags myChangeFlags;
1793 OSIterator * iter;
1794 OSObject * next;
1795 IOPowerConnection * connection;
1796 IOPMPowerStateIndex newPowerState;
1797 IOPMPowerFlags combinedPowerFlags;
1798 bool savedParentsKnowState;
1799 IOReturn result = IOPMAckImplied;
1800
1801 PM_ASSERT_IN_GATE();
1802 OUR_PMLog(kPMLogWillChange, parentPowerFlags, 0);
1803
1804 if (!inPlane(gIOPowerPlane) || !whichParent || !whichParent->getAwaitingAck())
1805 {
1806 PM_LOG("%s::%s not in power tree\n", getName(), __FUNCTION__);
1807 goto exit_no_ack;
1808 }
1809
1810 savedParentsKnowState = fParentsKnowState;
1811
1812 // Combine parents' output power flags.
1813
1814 combinedPowerFlags = 0;
1815
1816 iter = getParentIterator(gIOPowerPlane);
1817 if ( iter )
1818 {
1819 while ( (next = iter->getNextObject()) )
1820 {
1821 if ( (connection = OSDynamicCast(IOPowerConnection, next)) )
1822 {
1823 if ( connection == whichParent )
1824 combinedPowerFlags |= parentPowerFlags;
1825 else
1826 combinedPowerFlags |= connection->parentCurrentPowerFlags();
1827 }
1828 }
1829 iter->release();
1830 }
1831
1832 // If our initial change has yet to occur, then defer the power change
1833 // until after the power domain has completed its power transition.
1834
1835 if ( fControllingDriver && !fInitialPowerChange )
1836 {
1837 newPowerState = fControllingDriver->maxCapabilityForDomainState(
1838 combinedPowerFlags);
1839
1840 // Absorb parent's kIOPMSynchronize flag.
1841 myChangeFlags = kIOPMParentInitiated | kIOPMDomainWillChange |
1842 (parentChangeFlags & kIOPMSynchronize);
1843
1844 result = startPowerChange(
1845 /* flags */ myChangeFlags,
1846 /* power state */ newPowerState,
1847 /* domain flags */ combinedPowerFlags,
1848 /* connection */ whichParent,
1849 /* parent flags */ parentPowerFlags);
1850 }
1851
1852 // If parent is dropping power, immediately update the parent's
1853 // capability flags. Any future merging of parent(s) combined
1854 // power flags should account for this power drop.
1855
1856 if (parentChangeFlags & kIOPMDomainPowerDrop)
1857 {
1858 setParentInfo(parentPowerFlags, whichParent, true);
1859 }
1860
1861 // Parent is expecting an ACK from us. If we did not embark on a state
1862 // transition, i.e. startPowerChange() returned IOPMAckImplied. We are
1863 // still required to issue an ACK to our parent.
1864
1865 if (IOPMAckImplied == result)
1866 {
1867 IOService * parent;
1868 parent = (IOService *) whichParent->copyParentEntry(gIOPowerPlane);
1869 assert(parent);
1870 if ( parent )
1871 {
1872 parent->acknowledgePowerChange( whichParent );
1873 parent->release();
1874 }
1875 }
1876
1877 exit_no_ack:
1878 // Drop the retain from notifyChild().
1879 if (whichParent) whichParent->release();
1880 }
1881
1882 #ifndef __LP64__
1883 //*********************************************************************************
1884 // [deprecated] powerDomainDidChangeTo
1885 //
1886 // Called by the power-hierarchy parent after the power state of the power domain
1887 // has settled at a new level.
1888 // We enqueue a parent power-change to our queue of power changes.
1889 // This may or may not cause us to change power, depending on what
1890 // kind of change is occuring in the domain.
1891 //*********************************************************************************
1892
1893 IOReturn IOService::powerDomainDidChangeTo (
1894 IOPMPowerFlags newPowerFlags,
1895 IOPowerConnection * whichParent )
1896 {
1897 assert(false);
1898 return kIOReturnUnsupported;
1899 }
1900 #endif /* !__LP64__ */
1901
1902 //*********************************************************************************
1903 // [private] handlePowerDomainDidChangeTo
1904 //*********************************************************************************
1905
1906 void IOService::handlePowerDomainDidChangeTo ( IOPMRequest * request )
1907 {
1908 IOPMPowerFlags parentPowerFlags = (IOPMPowerFlags) request->fArg0;
1909 IOPowerConnection * whichParent = (IOPowerConnection *) request->fArg1;
1910 IOPMPowerChangeFlags parentChangeFlags = (IOPMPowerChangeFlags)(uintptr_t) request->fArg2;
1911 IOPMPowerChangeFlags myChangeFlags;
1912 IOPMPowerStateIndex newPowerState;
1913 IOPMPowerStateIndex initialDesire;
1914 bool savedParentsKnowState;
1915 IOReturn result = IOPMAckImplied;
1916
1917 PM_ASSERT_IN_GATE();
1918 OUR_PMLog(kPMLogDidChange, parentPowerFlags, 0);
1919
1920 if (!inPlane(gIOPowerPlane) || !whichParent || !whichParent->getAwaitingAck())
1921 {
1922 PM_LOG("%s::%s not in power tree\n", getName(), __FUNCTION__);
1923 goto exit_no_ack;
1924 }
1925
1926 savedParentsKnowState = fParentsKnowState;
1927
1928 setParentInfo(parentPowerFlags, whichParent, true);
1929
1930 if ( fControllingDriver )
1931 {
1932 newPowerState = fControllingDriver->maxCapabilityForDomainState(
1933 fParentsCurrentPowerFlags);
1934
1935 if (fInitialPowerChange)
1936 {
1937 initialDesire = fControllingDriver->initialPowerStateForDomainState(
1938 fParentsCurrentPowerFlags);
1939 computeDesiredState(initialDesire);
1940 }
1941 else if (fAdvisoryTickleUsed && (newPowerState > 0) &&
1942 ((parentChangeFlags & kIOPMSynchronize) == 0))
1943 {
1944 // re-compute desired state in case advisory tickle was enabled
1945 computeDesiredState();
1946 }
1947
1948 // Absorb parent's kIOPMSynchronize flag.
1949 myChangeFlags = kIOPMParentInitiated | kIOPMDomainDidChange |
1950 (parentChangeFlags & kIOPMSynchronize);
1951
1952 result = startPowerChange(
1953 /* flags */ myChangeFlags,
1954 /* power state */ newPowerState,
1955 /* domain flags */ fParentsCurrentPowerFlags,
1956 /* connection */ whichParent,
1957 /* parent flags */ 0);
1958 }
1959
1960 // Parent is expecting an ACK from us. If we did not embark on a state
1961 // transition, i.e. startPowerChange() returned IOPMAckImplied. We are
1962 // still required to issue an ACK to our parent.
1963
1964 if (IOPMAckImplied == result)
1965 {
1966 IOService * parent;
1967 parent = (IOService *) whichParent->copyParentEntry(gIOPowerPlane);
1968 assert(parent);
1969 if ( parent )
1970 {
1971 parent->acknowledgePowerChange( whichParent );
1972 parent->release();
1973 }
1974 }
1975
1976 // If the parent registers its power driver late, then this is the
1977 // first opportunity to tell our parent about our desire.
1978
1979 if (!savedParentsKnowState && fParentsKnowState)
1980 {
1981 PM_LOG1("%s::powerDomainDidChangeTo parentsKnowState = true\n",
1982 getName());
1983 requestDomainPower( fDesiredPowerState );
1984 }
1985
1986 exit_no_ack:
1987 // Drop the retain from notifyChild().
1988 if (whichParent) whichParent->release();
1989 }
1990
1991 //*********************************************************************************
1992 // [private] setParentInfo
1993 //
1994 // Set our connection data for one specific parent, and then combine all the parent
1995 // data together.
1996 //*********************************************************************************
1997
1998 void IOService::setParentInfo (
1999 IOPMPowerFlags newPowerFlags,
2000 IOPowerConnection * whichParent,
2001 bool knowsState )
2002 {
2003 OSIterator * iter;
2004 OSObject * next;
2005 IOPowerConnection * conn;
2006
2007 PM_ASSERT_IN_GATE();
2008
2009 // set our connection data
2010 whichParent->setParentCurrentPowerFlags(newPowerFlags);
2011 whichParent->setParentKnowsState(knowsState);
2012
2013 // recompute our parent info
2014 fParentsCurrentPowerFlags = 0;
2015 fParentsKnowState = true;
2016
2017 iter = getParentIterator(gIOPowerPlane);
2018 if ( iter )
2019 {
2020 while ( (next = iter->getNextObject()) )
2021 {
2022 if ( (conn = OSDynamicCast(IOPowerConnection, next)) )
2023 {
2024 fParentsKnowState &= conn->parentKnowsState();
2025 fParentsCurrentPowerFlags |= conn->parentCurrentPowerFlags();
2026 }
2027 }
2028 iter->release();
2029 }
2030 }
2031
2032 //******************************************************************************
2033 // [private] trackSystemSleepPreventers
2034 //******************************************************************************
2035
2036 void IOService::trackSystemSleepPreventers(
2037 IOPMPowerStateIndex oldPowerState,
2038 IOPMPowerStateIndex newPowerState,
2039 IOPMPowerChangeFlags changeFlags __unused )
2040 {
2041 IOPMPowerFlags oldCapability, newCapability;
2042
2043 oldCapability = fPowerStates[oldPowerState].capabilityFlags &
2044 (kIOPMPreventIdleSleep | kIOPMPreventSystemSleep);
2045 newCapability = fPowerStates[newPowerState].capabilityFlags &
2046 (kIOPMPreventIdleSleep | kIOPMPreventSystemSleep);
2047
2048 if (fHeadNoteChangeFlags & kIOPMInitialPowerChange)
2049 oldCapability = 0;
2050 if (oldCapability == newCapability)
2051 return;
2052
2053 if ((oldCapability ^ newCapability) & kIOPMPreventIdleSleep)
2054 {
2055 #if SUPPORT_IDLE_CANCEL
2056 if ((oldCapability & kIOPMPreventIdleSleep) == 0)
2057 {
2058 IOPMRequest * cancelRequest;
2059
2060 cancelRequest = acquirePMRequest( this, kIOPMRequestTypeIdleCancel );
2061 if (cancelRequest)
2062 {
2063 getPMRootDomain()->submitPMRequest( cancelRequest );
2064 }
2065 }
2066 #endif
2067
2068 getPMRootDomain()->updatePreventIdleSleepList(this,
2069 ((oldCapability & kIOPMPreventIdleSleep) == 0));
2070 }
2071
2072 if ((oldCapability ^ newCapability) & kIOPMPreventSystemSleep)
2073 {
2074
2075 getPMRootDomain()->updatePreventSystemSleepList(this,
2076 ((oldCapability & kIOPMPreventSystemSleep) == 0));
2077 }
2078 }
2079
2080 //*********************************************************************************
2081 // [public] requestPowerDomainState
2082 //
2083 // Called on a power parent when a child's power requirement changes.
2084 //*********************************************************************************
2085
2086 IOReturn IOService::requestPowerDomainState(
2087 IOPMPowerFlags childRequestPowerFlags,
2088 IOPowerConnection * childConnection,
2089 unsigned long specification )
2090 {
2091 IOPMPowerStateIndex ps;
2092 IOPMPowerFlags outputPowerFlags;
2093 IOService * child;
2094 IOPMRequest * subRequest;
2095 bool adjustPower = false;
2096
2097 if (!initialized)
2098 return IOPMNotYetInitialized;
2099
2100 if (gIOPMWorkLoop->onThread() == false)
2101 {
2102 PM_LOG("%s::requestPowerDomainState\n", getName());
2103 return kIOReturnSuccess;
2104 }
2105
2106 OUR_PMLog(kPMLogRequestDomain, childRequestPowerFlags, specification);
2107
2108 if (!isChild(childConnection, gIOPowerPlane))
2109 return kIOReturnNotAttached;
2110
2111 if (!fControllingDriver || !fNumberOfPowerStates)
2112 return kIOReturnNotReady;
2113
2114 child = (IOService *) childConnection->getChildEntry(gIOPowerPlane);
2115 assert(child);
2116
2117 // Merge in the power flags contributed by this power parent
2118 // at its current or impending power state.
2119
2120 outputPowerFlags = fPowerStates[fCurrentPowerState].outputPowerFlags;
2121 if (fMachineState != kIOPM_Finished)
2122 {
2123 if (IS_POWER_DROP && !IS_ROOT_DOMAIN)
2124 {
2125 // Use the lower power state when dropping power.
2126 // Must be careful since a power drop can be canceled
2127 // from the following states:
2128 // - kIOPM_OurChangeTellClientsPowerDown
2129 // - kIOPM_OurChangeTellPriorityClientsPowerDown
2130 //
2131 // The child must not wait for this parent to raise power
2132 // if the power drop was cancelled. The solution is to cancel
2133 // the power drop if possible, then schedule an adjustment to
2134 // re-evaluate the parent's power state.
2135 //
2136 // Root domain is excluded to avoid idle sleep issues. And permit
2137 // root domain children to pop up when system is going to sleep.
2138
2139 if ((fMachineState == kIOPM_OurChangeTellClientsPowerDown) ||
2140 (fMachineState == kIOPM_OurChangeTellPriorityClientsPowerDown))
2141 {
2142 fDoNotPowerDown = true; // cancel power drop
2143 adjustPower = true; // schedule an adjustment
2144 PM_LOG1("%s: power drop cancelled in state %u by %s\n",
2145 getName(), fMachineState, child->getName());
2146 }
2147 else
2148 {
2149 // Beyond cancellation point, report the impending state.
2150 outputPowerFlags =
2151 fPowerStates[fHeadNotePowerState].outputPowerFlags;
2152 }
2153 }
2154 else if (IS_POWER_RISE)
2155 {
2156 // When raising power, must report the output power flags from
2157 // child's perspective. A child power request may arrive while
2158 // parent is transitioning upwards. If a request arrives after
2159 // setParentInfo() has already recorded the output power flags
2160 // for the next power state, then using the power supplied by
2161 // fCurrentPowerState is incorrect, and might cause the child
2162 // to wait when it should not.
2163
2164 outputPowerFlags = childConnection->parentCurrentPowerFlags();
2165 }
2166 }
2167 child->fHeadNoteDomainTargetFlags |= outputPowerFlags;
2168
2169 // Map child's requested power flags to one of our power state.
2170
2171 for (ps = 0; ps < fNumberOfPowerStates; ps++)
2172 {
2173 if ((fPowerStates[ps].outputPowerFlags & childRequestPowerFlags) ==
2174 (fOutputPowerCharacterFlags & childRequestPowerFlags))
2175 break;
2176 }
2177 if (ps >= fNumberOfPowerStates)
2178 {
2179 ps = 0; // should never happen
2180 }
2181
2182 // Conditions that warrants a power adjustment on this parent.
2183 // Adjust power will also propagate any changes to the child's
2184 // prevent idle/sleep flags towards the root domain.
2185
2186 if (!childConnection->childHasRequestedPower() ||
2187 (ps != childConnection->getDesiredDomainState()))
2188 adjustPower = true;
2189
2190 #if ENABLE_DEBUG_LOGS
2191 if (adjustPower)
2192 {
2193 PM_LOG("requestPowerDomainState[%s]: %s, init %d, %u->%u\n",
2194 getName(), child->getName(),
2195 !childConnection->childHasRequestedPower(),
2196 (uint32_t) childConnection->getDesiredDomainState(),
2197 (uint32_t) ps);
2198 }
2199 #endif
2200
2201 // Record the child's desires on the connection.
2202 childConnection->setChildHasRequestedPower();
2203 childConnection->setDesiredDomainState( ps );
2204
2205 // Schedule a request to re-evaluate all children desires and
2206 // adjust power state. Submit a request if one wasn't pending,
2207 // or if the current request is part of a call tree.
2208
2209 if (adjustPower && !fDeviceOverrideEnabled &&
2210 (!fAdjustPowerScheduled || gIOPMRequest->getRootRequest()))
2211 {
2212 subRequest = acquirePMRequest(
2213 this, kIOPMRequestTypeAdjustPowerState, gIOPMRequest );
2214 if (subRequest)
2215 {
2216 submitPMRequest( subRequest );
2217 fAdjustPowerScheduled = true;
2218 }
2219 }
2220
2221 return kIOReturnSuccess;
2222 }
2223
2224 //*********************************************************************************
2225 // [public] temporaryPowerClampOn
2226 //
2227 // A power domain wants to clamp its power on till it has children which
2228 // will thendetermine the power domain state.
2229 //
2230 // We enter the highest state until addPowerChild is called.
2231 //*********************************************************************************
2232
2233 IOReturn IOService::temporaryPowerClampOn ( void )
2234 {
2235 return requestPowerState( gIOPMPowerClientChildProxy, kIOPMPowerStateMax );
2236 }
2237
2238 //*********************************************************************************
2239 // [public] makeUsable
2240 //
2241 // Some client of our device is asking that we become usable. Although
2242 // this has not come from a subclassed device object, treat it exactly
2243 // as if it had. In this way, subsequent requests for lower power from
2244 // a subclassed device object will pre-empt this request.
2245 //
2246 // We treat this as a subclass object request to switch to the
2247 // highest power state.
2248 //*********************************************************************************
2249
2250 IOReturn IOService::makeUsable ( void )
2251 {
2252 OUR_PMLog(kPMLogMakeUsable, 0, 0);
2253 return requestPowerState( gIOPMPowerClientDevice, kIOPMPowerStateMax );
2254 }
2255
2256 //*********************************************************************************
2257 // [public] currentCapability
2258 //*********************************************************************************
2259
2260 IOPMPowerFlags IOService::currentCapability ( void )
2261 {
2262 if (!initialized)
2263 return IOPMNotPowerManaged;
2264
2265 return fCurrentCapabilityFlags;
2266 }
2267
2268 //*********************************************************************************
2269 // [public] changePowerStateTo
2270 //
2271 // Called by our power-controlling driver to change power state. The new desired
2272 // power state is computed and compared against the current power state. If those
2273 // power states differ, then a power state change is initiated.
2274 //*********************************************************************************
2275
2276 IOReturn IOService::changePowerStateTo ( unsigned long ordinal )
2277 {
2278 OUR_PMLog(kPMLogChangeStateTo, ordinal, 0);
2279 return requestPowerState( gIOPMPowerClientDriver, ordinal );
2280 }
2281
2282 //*********************************************************************************
2283 // [protected] changePowerStateToPriv
2284 //
2285 // Called by our driver subclass to change power state. The new desired power
2286 // state is computed and compared against the current power state. If those
2287 // power states differ, then a power state change is initiated.
2288 //*********************************************************************************
2289
2290 IOReturn IOService::changePowerStateToPriv ( unsigned long ordinal )
2291 {
2292 OUR_PMLog(kPMLogChangeStateToPriv, ordinal, 0);
2293 return requestPowerState( gIOPMPowerClientDevice, ordinal );
2294 }
2295
2296 //*********************************************************************************
2297 // [protected] changePowerStateWithOverrideTo
2298 //
2299 // Called by our driver subclass to change power state. The new desired power
2300 // state is computed and compared against the current power state. If those
2301 // power states differ, then a power state change is initiated.
2302 // Override enforced - Children and Driver desires are ignored.
2303 //*********************************************************************************
2304
2305 IOReturn IOService::changePowerStateWithOverrideTo ( unsigned long ordinal )
2306 {
2307 IOPMRequest * request;
2308
2309 if (!initialized)
2310 return kIOPMNotYetInitialized;
2311
2312 OUR_PMLog(kPMLogChangeStateToPriv, ordinal, 0);
2313
2314 request = acquirePMRequest( this, kIOPMRequestTypeRequestPowerStateOverride );
2315 if (!request)
2316 return kIOReturnNoMemory;
2317
2318 gIOPMPowerClientDevice->retain();
2319 request->fArg0 = (void *) ordinal;
2320 request->fArg1 = (void *) gIOPMPowerClientDevice;
2321 request->fArg2 = 0;
2322 #if NOT_READY
2323 if (action)
2324 request->installCompletionAction( action, target, param );
2325 #endif
2326
2327 // Prevent needless downwards power transitions by clamping power
2328 // until the scheduled request is executed.
2329
2330 if (gIOPMWorkLoop->inGate() && (ordinal < fNumberOfPowerStates))
2331 {
2332 fTempClampPowerState = max(fTempClampPowerState, ordinal);
2333 fTempClampCount++;
2334 fOverrideMaxPowerState = ordinal;
2335 request->fArg2 = (void *) (uintptr_t) true;
2336 }
2337
2338 submitPMRequest( request );
2339 return IOPMNoErr;
2340 }
2341
2342 //*********************************************************************************
2343 // [private] requestPowerState
2344 //*********************************************************************************
2345
2346 IOReturn IOService::requestPowerState (
2347 const OSSymbol * client,
2348 uint32_t state )
2349 {
2350 IOPMRequest * request;
2351
2352 if (!client)
2353 return kIOReturnBadArgument;
2354 if (!initialized)
2355 return kIOPMNotYetInitialized;
2356
2357 request = acquirePMRequest( this, kIOPMRequestTypeRequestPowerState );
2358 if (!request)
2359 return kIOReturnNoMemory;
2360
2361 client->retain();
2362 request->fArg0 = (void *) state;
2363 request->fArg1 = (void *) client;
2364 request->fArg2 = 0;
2365 #if NOT_READY
2366 if (action)
2367 request->installCompletionAction( action, target, param );
2368 #endif
2369
2370 // Prevent needless downwards power transitions by clamping power
2371 // until the scheduled request is executed.
2372
2373 if (gIOPMWorkLoop->inGate() && (state < fNumberOfPowerStates))
2374 {
2375 fTempClampPowerState = max(fTempClampPowerState, state);
2376 fTempClampCount++;
2377 request->fArg2 = (void *) (uintptr_t) true;
2378 }
2379
2380 submitPMRequest( request );
2381 return IOPMNoErr;
2382 }
2383
2384 //*********************************************************************************
2385 // [private] handleRequestPowerState
2386 //*********************************************************************************
2387
2388 void IOService::handleRequestPowerState ( IOPMRequest * request )
2389 {
2390 const OSSymbol * client = (const OSSymbol *) request->fArg1;
2391 uint32_t state = (uint32_t)(uintptr_t) request->fArg0;
2392
2393 PM_ASSERT_IN_GATE();
2394 if (request->fArg2)
2395 {
2396 assert(fTempClampCount != 0);
2397 if (fTempClampCount) fTempClampCount--;
2398 if (!fTempClampCount) fTempClampPowerState = 0;
2399 }
2400
2401 if (fNumberOfPowerStates && (state >= fNumberOfPowerStates))
2402 state = fNumberOfPowerStates - 1;
2403
2404 // The power suppression due to changePowerStateWithOverrideTo() expires
2405 // upon the next "device" power request - changePowerStateToPriv().
2406
2407 if ((getPMRequestType() != kIOPMRequestTypeRequestPowerStateOverride) &&
2408 (client == gIOPMPowerClientDevice))
2409 fOverrideMaxPowerState = kIOPMPowerStateMax;
2410
2411 if ((state == 0) &&
2412 (client != gIOPMPowerClientDevice) &&
2413 (client != gIOPMPowerClientDriver) &&
2414 (client != gIOPMPowerClientChildProxy))
2415 removePowerClient(client);
2416 else
2417 updatePowerClient(client, state);
2418
2419 adjustPowerState();
2420 client->release();
2421 }
2422
2423 //*********************************************************************************
2424 // [private] Helper functions to update/remove power clients.
2425 //*********************************************************************************
2426
2427 void IOService::updatePowerClient( const OSSymbol * client, uint32_t powerState )
2428 {
2429 if (!fPowerClients)
2430 fPowerClients = OSDictionary::withCapacity(4);
2431 if (fPowerClients && client)
2432 {
2433 OSNumber * num = (OSNumber *) fPowerClients->getObject(client);
2434 if (num)
2435 num->setValue(powerState);
2436 else
2437 {
2438 num = OSNumber::withNumber(powerState, 32);
2439 if (num)
2440 {
2441 fPowerClients->setObject(client, num);
2442 num->release();
2443 }
2444 }
2445 }
2446 }
2447
2448 void IOService::removePowerClient( const OSSymbol * client )
2449 {
2450 if (fPowerClients && client)
2451 fPowerClients->removeObject(client);
2452 }
2453
2454 uint32_t IOService::getPowerStateForClient( const OSSymbol * client )
2455 {
2456 uint32_t powerState = 0;
2457
2458 if (fPowerClients && client)
2459 {
2460 OSNumber * num = (OSNumber *) fPowerClients->getObject(client);
2461 if (num) powerState = num->unsigned32BitValue();
2462 }
2463 return powerState;
2464 }
2465
2466 //*********************************************************************************
2467 // [protected] powerOverrideOnPriv
2468 //*********************************************************************************
2469
2470 IOReturn IOService::powerOverrideOnPriv ( void )
2471 {
2472 IOPMRequest * request;
2473
2474 if (!initialized)
2475 return IOPMNotYetInitialized;
2476
2477 if (gIOPMWorkLoop->inGate())
2478 {
2479 fDeviceOverrideEnabled = true;
2480 return IOPMNoErr;
2481 }
2482
2483 request = acquirePMRequest( this, kIOPMRequestTypePowerOverrideOnPriv );
2484 if (!request)
2485 return kIOReturnNoMemory;
2486
2487 submitPMRequest( request );
2488 return IOPMNoErr;
2489 }
2490
2491 //*********************************************************************************
2492 // [protected] powerOverrideOffPriv
2493 //*********************************************************************************
2494
2495 IOReturn IOService::powerOverrideOffPriv ( void )
2496 {
2497 IOPMRequest * request;
2498
2499 if (!initialized)
2500 return IOPMNotYetInitialized;
2501
2502 if (gIOPMWorkLoop->inGate())
2503 {
2504 fDeviceOverrideEnabled = false;
2505 return IOPMNoErr;
2506 }
2507
2508 request = acquirePMRequest( this, kIOPMRequestTypePowerOverrideOffPriv );
2509 if (!request)
2510 return kIOReturnNoMemory;
2511
2512 submitPMRequest( request );
2513 return IOPMNoErr;
2514 }
2515
2516 //*********************************************************************************
2517 // [private] handlePowerOverrideChanged
2518 //*********************************************************************************
2519
2520 void IOService::handlePowerOverrideChanged ( IOPMRequest * request )
2521 {
2522 PM_ASSERT_IN_GATE();
2523 if (request->getType() == kIOPMRequestTypePowerOverrideOnPriv)
2524 {
2525 OUR_PMLog(kPMLogOverrideOn, 0, 0);
2526 fDeviceOverrideEnabled = true;
2527 }
2528 else
2529 {
2530 OUR_PMLog(kPMLogOverrideOff, 0, 0);
2531 fDeviceOverrideEnabled = false;
2532 }
2533
2534 adjustPowerState();
2535 }
2536
2537 //*********************************************************************************
2538 // [private] computeDesiredState
2539 //*********************************************************************************
2540
2541 void IOService::computeDesiredState ( unsigned long localClamp )
2542 {
2543 OSIterator * iter;
2544 OSObject * next;
2545 IOPowerConnection * connection;
2546 uint32_t desiredState = 0;
2547 uint32_t newPowerState = 0;
2548 bool hasChildren = false;
2549
2550 // Desired power state is always 0 without a controlling driver.
2551
2552 if (!fNumberOfPowerStates)
2553 {
2554 fDesiredPowerState = 0;
2555 //PM_LOG("%s::%s no controlling driver\n", getName(), __FUNCTION__);
2556 return;
2557 }
2558
2559 // Examine the children's desired power state.
2560
2561 iter = getChildIterator(gIOPowerPlane);
2562 if (iter)
2563 {
2564 while ((next = iter->getNextObject()))
2565 {
2566 if ((connection = OSDynamicCast(IOPowerConnection, next)))
2567 {
2568 if (connection->getReadyFlag() == false)
2569 {
2570 PM_LOG3("[%s] %s: connection not ready\n",
2571 getName(), __FUNCTION__);
2572 continue;
2573 }
2574 if (connection->childHasRequestedPower())
2575 hasChildren = true;
2576 if (connection->getDesiredDomainState() > desiredState)
2577 desiredState = connection->getDesiredDomainState();
2578 }
2579 }
2580 iter->release();
2581 }
2582 if (hasChildren)
2583 updatePowerClient(gIOPMPowerClientChildren, desiredState);
2584 else
2585 removePowerClient(gIOPMPowerClientChildren);
2586
2587 // Iterate through all power clients to determine the min power state.
2588
2589 iter = OSCollectionIterator::withCollection(fPowerClients);
2590 if (iter)
2591 {
2592 const OSSymbol * client;
2593 while ((client = (const OSSymbol *) iter->getNextObject()))
2594 {
2595 // Ignore child and driver when override is in effect.
2596 if ((fDeviceOverrideEnabled ||
2597 (getPMRequestType() == kIOPMRequestTypeRequestPowerStateOverride)) &&
2598 ((client == gIOPMPowerClientChildren) ||
2599 (client == gIOPMPowerClientDriver)))
2600 continue;
2601
2602 // Ignore child proxy when children are present.
2603 if (hasChildren && (client == gIOPMPowerClientChildProxy))
2604 continue;
2605
2606 if (client == gIOPMPowerClientAdvisoryTickle &&
2607 !gIOPMAdvisoryTickleEnabled)
2608 continue;
2609
2610 desiredState = getPowerStateForClient(client);
2611 assert(desiredState < fNumberOfPowerStates);
2612 PM_LOG1(" %u %s\n",
2613 desiredState, client->getCStringNoCopy());
2614
2615 newPowerState = max(newPowerState, desiredState);
2616
2617 if (client == gIOPMPowerClientDevice)
2618 fDeviceDesire = desiredState;
2619 }
2620 iter->release();
2621 }
2622
2623 // Factor in the temporary power desires.
2624
2625 newPowerState = max(newPowerState, localClamp);
2626 newPowerState = max(newPowerState, fTempClampPowerState);
2627
2628 // Limit check against max power override.
2629
2630 newPowerState = min(newPowerState, fOverrideMaxPowerState);
2631
2632 // Limit check against number of power states.
2633
2634 if (newPowerState >= fNumberOfPowerStates)
2635 newPowerState = fNumberOfPowerStates - 1;
2636
2637 fDesiredPowerState = newPowerState;
2638
2639 PM_LOG1(" temp %u, clamp %u, current %u, new %u\n",
2640 (uint32_t) localClamp, (uint32_t) fTempClampPowerState,
2641 (uint32_t) fCurrentPowerState, newPowerState);
2642
2643 // Restart idle timer if stopped and device desire has increased.
2644 // Or if advisory desire exists.
2645
2646 if (fIdleTimerStopped)
2647 {
2648 if (fDeviceDesire > 0)
2649 {
2650 fIdleTimerStopped = false;
2651 fActivityTickleCount = 0;
2652 clock_get_uptime(&fIdleTimerStartTime);
2653 start_PM_idle_timer();
2654 }
2655 else if (fHasAdvisoryDesire)
2656 {
2657 fIdleTimerStopped = false;
2658 start_PM_idle_timer();
2659 }
2660 }
2661
2662 // Invalidate cached tickle power state when desires change, and not
2663 // due to a tickle request. This invalidation must occur before the
2664 // power state change to minimize races. We want to err on the side
2665 // of servicing more activity tickles rather than dropping one when
2666 // the device is in a low power state.
2667
2668 if ((getPMRequestType() != kIOPMRequestTypeActivityTickle) &&
2669 (fActivityTicklePowerState != kInvalidTicklePowerState))
2670 {
2671 IOLockLock(fActivityLock);
2672 fActivityTicklePowerState = kInvalidTicklePowerState;
2673 IOLockUnlock(fActivityLock);
2674 }
2675 }
2676
2677 //*********************************************************************************
2678 // [public] currentPowerConsumption
2679 //
2680 //*********************************************************************************
2681
2682 unsigned long IOService::currentPowerConsumption ( void )
2683 {
2684 if (!initialized)
2685 return kIOPMUnknown;
2686
2687 return fCurrentPowerConsumption;
2688 }
2689
2690 //*********************************************************************************
2691 // [deprecated] getPMworkloop
2692 //*********************************************************************************
2693
2694 IOWorkLoop * IOService::getPMworkloop ( void )
2695 {
2696 return gIOPMWorkLoop;
2697 }
2698
2699 #if NOT_YET
2700
2701 //*********************************************************************************
2702 // Power Parent/Children Applier
2703 //*********************************************************************************
2704
2705 static void
2706 applyToPowerChildren(
2707 IOService * service,
2708 IOServiceApplierFunction applier,
2709 void * context,
2710 IOOptionBits options )
2711 {
2712 PM_ASSERT_IN_GATE();
2713
2714 IORegistryEntry * entry;
2715 IORegistryIterator * iter;
2716 IOPowerConnection * connection;
2717 IOService * child;
2718
2719 iter = IORegistryIterator::iterateOver(service, gIOPowerPlane, options);
2720 if (iter)
2721 {
2722 while ((entry = iter->getNextObject()))
2723 {
2724 // Get child of IOPowerConnection objects
2725 if ((connection = OSDynamicCast(IOPowerConnection, entry)))
2726 {
2727 child = (IOService *) connection->copyChildEntry(gIOPowerPlane);
2728 if (child)
2729 {
2730 (*applier)(child, context);
2731 child->release();
2732 }
2733 }
2734 }
2735 iter->release();
2736 }
2737 }
2738
2739 static void
2740 applyToPowerParent(
2741 IOService * service,
2742 IOServiceApplierFunction applier,
2743 void * context,
2744 IOOptionBits options )
2745 {
2746 PM_ASSERT_IN_GATE();
2747
2748 IORegistryEntry * entry;
2749 IORegistryIterator * iter;
2750 IOPowerConnection * connection;
2751 IOService * parent;
2752
2753 iter = IORegistryIterator::iterateOver(service, gIOPowerPlane,
2754 options | kIORegistryIterateParents);
2755 if (iter)
2756 {
2757 while ((entry = iter->getNextObject()))
2758 {
2759 // Get child of IOPowerConnection objects
2760 if ((connection = OSDynamicCast(IOPowerConnection, entry)))
2761 {
2762 parent = (IOService *) connection->copyParentEntry(gIOPowerPlane);
2763 if (parent)
2764 {
2765 (*applier)(parent, context);
2766 parent->release();
2767 }
2768 }
2769 }
2770 iter->release();
2771 }
2772 }
2773
2774 #endif /* NOT_YET */
2775
2776 // MARK: -
2777 // MARK: Activity Tickle & Idle Timer
2778
2779 void IOService::setAdvisoryTickleEnable( bool enable )
2780 {
2781 gIOPMAdvisoryTickleEnabled = enable;
2782 }
2783
2784 //*********************************************************************************
2785 // [public] activityTickle
2786 //
2787 // The tickle with parameter kIOPMSuperclassPolicy1 causes the activity
2788 // flag to be set, and the device state checked. If the device has been
2789 // powered down, it is powered up again.
2790 // The tickle with parameter kIOPMSubclassPolicy is ignored here and
2791 // should be intercepted by a subclass.
2792 //*********************************************************************************
2793
2794 bool IOService::activityTickle ( unsigned long type, unsigned long stateNumber )
2795 {
2796 IOPMRequest * request;
2797 bool noPowerChange = true;
2798
2799 if (!initialized)
2800 return true; // no power change
2801
2802 if ((type == kIOPMSuperclassPolicy1) && stateNumber)
2803 {
2804 IOLockLock(fActivityLock);
2805
2806 // Record device activity for the idle timer handler.
2807
2808 fDeviceWasActive = true;
2809 fActivityTickleCount++;
2810 clock_get_uptime(&fDeviceActiveTimestamp);
2811
2812 PM_ACTION_0(actionActivityTickle);
2813
2814 // Record the last tickle power state.
2815 // This helps to filter out redundant tickles as
2816 // this function may be called from the data path.
2817
2818 if (fActivityTicklePowerState < (int)stateNumber)
2819 {
2820 fActivityTicklePowerState = stateNumber;
2821 noPowerChange = false;
2822
2823 request = acquirePMRequest( this, kIOPMRequestTypeActivityTickle );
2824 if (request)
2825 {
2826 request->fArg0 = (void *) stateNumber; // power state
2827 request->fArg1 = (void *) true; // power rise
2828 request->fArg2 = (void *) false; // regular tickle
2829 submitPMRequest(request);
2830 }
2831 }
2832
2833 IOLockUnlock(fActivityLock);
2834 }
2835
2836 else if ((type == kIOPMActivityTickleTypeAdvisory) &&
2837 ((stateNumber = fDeviceUsablePowerState)))
2838 {
2839 IOLockLock(fActivityLock);
2840
2841 fAdvisoryTickled = true;
2842
2843 if (fAdvisoryTicklePowerState != (int)stateNumber)
2844 {
2845 fAdvisoryTicklePowerState = stateNumber;
2846 noPowerChange = false;
2847
2848 request = acquirePMRequest( this, kIOPMRequestTypeActivityTickle );
2849 if (request)
2850 {
2851 request->fArg0 = (void *) stateNumber; // power state
2852 request->fArg1 = (void *) true; // power rise
2853 request->fArg2 = (void *) true; // advisory tickle
2854 submitPMRequest(request);
2855 }
2856 }
2857
2858 IOLockUnlock(fActivityLock);
2859 }
2860
2861 // Returns false if the activityTickle might cause a transition to a
2862 // higher powered state, true otherwise.
2863
2864 return noPowerChange;
2865 }
2866
2867 //*********************************************************************************
2868 // [private] handleActivityTickle
2869 //*********************************************************************************
2870
2871 void IOService::handleActivityTickle ( IOPMRequest * request )
2872 {
2873 uint32_t ticklePowerState = (uint32_t)(uintptr_t) request->fArg0;
2874 bool deviceWasActive = (request->fArg1 == (void *) true);
2875 bool isRegularTickle = (request->fArg2 == (void *) false);
2876 bool adjustPower = false;
2877
2878 PM_ASSERT_IN_GATE();
2879 if (isRegularTickle)
2880 {
2881 if (deviceWasActive)
2882 {
2883 if ((ticklePowerState > fDeviceDesire) &&
2884 (ticklePowerState < fNumberOfPowerStates))
2885 {
2886 fIdleTimerMinPowerState = ticklePowerState;
2887 updatePowerClient(gIOPMPowerClientDevice, ticklePowerState);
2888 adjustPower = true;
2889 }
2890 }
2891 else if (fDeviceDesire > fIdleTimerMinPowerState)
2892 {
2893 // Power drop due to idle timer expiration.
2894 // Do not allow idle timer to reduce power below tickle power.
2895 // This prevents the idle timer from decreasing the device desire
2896 // to zero and cancelling the effect of a pre-sleep tickle when
2897 // system wakes up to doze state, while the device is unable to
2898 // raise its power state to satisfy the tickle.
2899
2900 ticklePowerState = fDeviceDesire - 1;
2901 updatePowerClient(gIOPMPowerClientDevice, ticklePowerState);
2902 adjustPower = true;
2903 }
2904 }
2905 else // advisory tickle
2906 {
2907 if (deviceWasActive)
2908 {
2909 if ((ticklePowerState == fDeviceUsablePowerState) &&
2910 (ticklePowerState < fNumberOfPowerStates))
2911 {
2912 updatePowerClient(gIOPMPowerClientAdvisoryTickle, ticklePowerState);
2913 fHasAdvisoryDesire = true;
2914 fAdvisoryTickleUsed = true;
2915 adjustPower = true;
2916 }
2917 else
2918 {
2919 IOLockLock(fActivityLock);
2920 fAdvisoryTicklePowerState = kInvalidTicklePowerState;
2921 IOLockUnlock(fActivityLock);
2922 }
2923 }
2924 else if (fHasAdvisoryDesire)
2925 {
2926 removePowerClient(gIOPMPowerClientAdvisoryTickle);
2927 fHasAdvisoryDesire = false;
2928 adjustPower = true;
2929 }
2930 }
2931
2932 if (adjustPower)
2933 {
2934 adjustPowerState();
2935 }
2936 }
2937
2938 //******************************************************************************
2939 // [public] setIdleTimerPeriod
2940 //
2941 // A subclass policy-maker is using our standard idleness detection service.
2942 // Start the idle timer. Period is in seconds.
2943 //******************************************************************************
2944
2945 IOReturn IOService::setIdleTimerPeriod ( unsigned long period )
2946 {
2947 if (!initialized)
2948 return IOPMNotYetInitialized;
2949
2950 OUR_PMLog(kPMLogSetIdleTimerPeriod, period, fIdleTimerPeriod);
2951
2952 IOPMRequest * request =
2953 acquirePMRequest( this, kIOPMRequestTypeSetIdleTimerPeriod );
2954 if (!request)
2955 return kIOReturnNoMemory;
2956
2957 request->fArg0 = (void *) period;
2958 submitPMRequest( request );
2959
2960 return kIOReturnSuccess;
2961 }
2962
2963 IOReturn IOService::setIgnoreIdleTimer( bool ignore )
2964 {
2965 if (!initialized)
2966 return IOPMNotYetInitialized;
2967
2968 OUR_PMLog(kIOPMRequestTypeIgnoreIdleTimer, ignore, 0);
2969
2970 IOPMRequest * request =
2971 acquirePMRequest( this, kIOPMRequestTypeIgnoreIdleTimer );
2972 if (!request)
2973 return kIOReturnNoMemory;
2974
2975 request->fArg0 = (void *) ignore;
2976 submitPMRequest( request );
2977
2978 return kIOReturnSuccess;
2979 }
2980
2981 //******************************************************************************
2982 // [public] nextIdleTimeout
2983 //
2984 // Returns how many "seconds from now" the device should idle into its
2985 // next lowest power state.
2986 //******************************************************************************
2987
2988 SInt32 IOService::nextIdleTimeout(
2989 AbsoluteTime currentTime,
2990 AbsoluteTime lastActivity,
2991 unsigned int powerState)
2992 {
2993 AbsoluteTime delta;
2994 UInt64 delta_ns;
2995 SInt32 delta_secs;
2996 SInt32 delay_secs;
2997
2998 // Calculate time difference using funky macro from clock.h.
2999 delta = currentTime;
3000 SUB_ABSOLUTETIME(&delta, &lastActivity);
3001
3002 // Figure it in seconds.
3003 absolutetime_to_nanoseconds(delta, &delta_ns);
3004 delta_secs = (SInt32)(delta_ns / NSEC_PER_SEC);
3005
3006 // Be paranoid about delta somehow exceeding timer period.
3007 if (delta_secs < (int) fIdleTimerPeriod)
3008 delay_secs = (int) fIdleTimerPeriod - delta_secs;
3009 else
3010 delay_secs = (int) fIdleTimerPeriod;
3011
3012 return (SInt32)delay_secs;
3013 }
3014
3015 //*********************************************************************************
3016 // [public] start_PM_idle_timer
3017 //*********************************************************************************
3018
3019 void IOService::start_PM_idle_timer ( void )
3020 {
3021 static const int maxTimeout = 100000;
3022 static const int minTimeout = 1;
3023 AbsoluteTime uptime, deadline;
3024 SInt32 idle_in = 0;
3025 boolean_t pending;
3026
3027 if (!initialized || !fIdleTimerPeriod)
3028 return;
3029
3030 IOLockLock(fActivityLock);
3031
3032 clock_get_uptime(&uptime);
3033
3034 // Subclasses may modify idle sleep algorithm
3035 idle_in = nextIdleTimeout(uptime, fDeviceActiveTimestamp, fCurrentPowerState);
3036
3037 // Check for out-of range responses
3038 if (idle_in > maxTimeout)
3039 {
3040 // use standard implementation
3041 idle_in = IOService::nextIdleTimeout(uptime,
3042 fDeviceActiveTimestamp,
3043 fCurrentPowerState);
3044 } else if (idle_in < minTimeout) {
3045 idle_in = fIdleTimerPeriod;
3046 }
3047
3048 IOLockUnlock(fActivityLock);
3049
3050 retain();
3051 clock_interval_to_absolutetime_interval(idle_in, kSecondScale, &deadline);
3052 ADD_ABSOLUTETIME(&deadline, &uptime);
3053 pending = thread_call_enter_delayed(fIdleTimer, deadline);
3054 if (pending) release();
3055 }
3056
3057 //*********************************************************************************
3058 // idle_timer_expired
3059 //*********************************************************************************
3060
3061 static void
3062 idle_timer_expired (
3063 thread_call_param_t arg0, thread_call_param_t arg1 )
3064 {
3065 IOService * me = (IOService *) arg0;
3066
3067 if (gIOPMWorkLoop)
3068 gIOPMWorkLoop->runAction(
3069 OSMemberFunctionCast(IOWorkLoop::Action, me,
3070 &IOService::idleTimerExpired),
3071 me);
3072
3073 me->release();
3074 }
3075
3076 //*********************************************************************************
3077 // [private] idleTimerExpired
3078 //
3079 // The idle timer has expired. If there has been activity since the last
3080 // expiration, just restart the timer and return. If there has not been
3081 // activity, switch to the next lower power state and restart the timer.
3082 //*********************************************************************************
3083
3084 void IOService::idleTimerExpired( void )
3085 {
3086 IOPMRequest * request;
3087 bool restartTimer = true;
3088
3089 if ( !initialized || !fIdleTimerPeriod || fLockedFlags.PMStop )
3090 return;
3091
3092 IOLockLock(fActivityLock);
3093
3094 // Check for device activity (tickles) over last timer period.
3095
3096 if (fDeviceWasActive)
3097 {
3098 // Device was active - do not drop power, restart timer.
3099 fDeviceWasActive = false;
3100 }
3101 else if (!fIdleTimerIgnored)
3102 {
3103 // No device activity - drop power state by one level.
3104 // Decrement the cached tickle power state when possible.
3105 // This value may be (-1) before activityTickle() is called,
3106 // but the power drop request must be issued regardless.
3107
3108 if (fActivityTicklePowerState > 0)
3109 fActivityTicklePowerState--;
3110
3111 request = acquirePMRequest( this, kIOPMRequestTypeActivityTickle );
3112 if (request)
3113 {
3114 request->fArg0 = (void *) 0; // power state (irrelevant)
3115 request->fArg1 = (void *) false; // timer expiration (not tickle)
3116 request->fArg2 = (void *) false; // regular tickle
3117 submitPMRequest( request );
3118
3119 // Do not restart timer until after the tickle request has been
3120 // processed.
3121
3122 restartTimer = false;
3123 }
3124 }
3125
3126 if (fAdvisoryTickled)
3127 {
3128 fAdvisoryTickled = false;
3129 }
3130 else if (fHasAdvisoryDesire)
3131 {
3132 // Want new tickles to turn into pm request after we drop the lock
3133 fAdvisoryTicklePowerState = kInvalidTicklePowerState;
3134
3135 request = acquirePMRequest( this, kIOPMRequestTypeActivityTickle );
3136 if (request)
3137 {
3138 request->fArg0 = (void *) 0; // power state (irrelevant)
3139 request->fArg1 = (void *) false; // timer expiration (not tickle)
3140 request->fArg2 = (void *) true; // advisory tickle
3141 submitPMRequest( request );
3142
3143 // Do not restart timer until after the tickle request has been
3144 // processed.
3145
3146 restartTimer = false;
3147 }
3148 }
3149
3150 IOLockUnlock(fActivityLock);
3151
3152 if (restartTimer)
3153 start_PM_idle_timer();
3154 }
3155
3156 #ifndef __LP64__
3157 //*********************************************************************************
3158 // [deprecated] PM_idle_timer_expiration
3159 //*********************************************************************************
3160
3161 void IOService::PM_idle_timer_expiration ( void )
3162 {
3163 }
3164
3165 //*********************************************************************************
3166 // [deprecated] command_received
3167 //*********************************************************************************
3168
3169 void IOService::command_received ( void *statePtr , void *, void * , void * )
3170 {
3171 }
3172 #endif /* !__LP64__ */
3173
3174 //*********************************************************************************
3175 // [public] setAggressiveness
3176 //
3177 // Pass on the input parameters to all power domain children. All those which are
3178 // power domains will pass it on to their children, etc.
3179 //*********************************************************************************
3180
3181 IOReturn IOService::setAggressiveness ( unsigned long type, unsigned long newLevel )
3182 {
3183 return kIOReturnSuccess;
3184 }
3185
3186 //*********************************************************************************
3187 // [public] getAggressiveness
3188 //
3189 // Called by the user client.
3190 //*********************************************************************************
3191
3192 IOReturn IOService::getAggressiveness ( unsigned long type, unsigned long * currentLevel )
3193 {
3194 IOPMrootDomain * rootDomain = getPMRootDomain();
3195
3196 if (!rootDomain)
3197 return kIOReturnNotReady;
3198
3199 return rootDomain->getAggressiveness( type, currentLevel );
3200 }
3201
3202 //*********************************************************************************
3203 // [public] getPowerState
3204 //
3205 //*********************************************************************************
3206
3207 UInt32 IOService::getPowerState ( void )
3208 {
3209 if (!initialized)
3210 return 0;
3211
3212 return fCurrentPowerState;
3213 }
3214
3215 #ifndef __LP64__
3216 //*********************************************************************************
3217 // [deprecated] systemWake
3218 //
3219 // Pass this to all power domain children. All those which are
3220 // power domains will pass it on to their children, etc.
3221 //*********************************************************************************
3222
3223 IOReturn IOService::systemWake ( void )
3224 {
3225 OSIterator * iter;
3226 OSObject * next;
3227 IOPowerConnection * connection;
3228 IOService * theChild;
3229
3230 iter = getChildIterator(gIOPowerPlane);
3231 if ( iter )
3232 {
3233 while ( (next = iter->getNextObject()) )
3234 {
3235 if ( (connection = OSDynamicCast(IOPowerConnection, next)) )
3236 {
3237 if (connection->getReadyFlag() == false)
3238 {
3239 PM_LOG3("[%s] %s: connection not ready\n",
3240 getName(), __FUNCTION__);
3241 continue;
3242 }
3243
3244 theChild = (IOService *)connection->copyChildEntry(gIOPowerPlane);
3245 if ( theChild )
3246 {
3247 theChild->systemWake();
3248 theChild->release();
3249 }
3250 }
3251 }
3252 iter->release();
3253 }
3254
3255 if ( fControllingDriver != NULL )
3256 {
3257 if ( fControllingDriver->didYouWakeSystem() )
3258 {
3259 makeUsable();
3260 }
3261 }
3262
3263 return IOPMNoErr;
3264 }
3265
3266 //*********************************************************************************
3267 // [deprecated] temperatureCriticalForZone
3268 //*********************************************************************************
3269
3270 IOReturn IOService::temperatureCriticalForZone ( IOService * whichZone )
3271 {
3272 IOService * theParent;
3273 IOService * theNub;
3274
3275 OUR_PMLog(kPMLogCriticalTemp, 0, 0);
3276
3277 if ( inPlane(gIOPowerPlane) && !IS_PM_ROOT )
3278 {
3279 theNub = (IOService *)copyParentEntry(gIOPowerPlane);
3280 if ( theNub )
3281 {
3282 theParent = (IOService *)theNub->copyParentEntry(gIOPowerPlane);
3283 theNub->release();
3284 if ( theParent )
3285 {
3286 theParent->temperatureCriticalForZone(whichZone);
3287 theParent->release();
3288 }
3289 }
3290 }
3291 return IOPMNoErr;
3292 }
3293 #endif /* !__LP64__ */
3294
3295 // MARK: -
3296 // MARK: Power Change (Common)
3297
3298 //*********************************************************************************
3299 // [private] startPowerChange
3300 //
3301 // All power state changes starts here.
3302 //*********************************************************************************
3303
3304 IOReturn IOService::startPowerChange(
3305 IOPMPowerChangeFlags changeFlags,
3306 IOPMPowerStateIndex powerState,
3307 IOPMPowerFlags domainFlags,
3308 IOPowerConnection * parentConnection,
3309 IOPMPowerFlags parentFlags )
3310 {
3311 PM_ASSERT_IN_GATE();
3312 assert( fMachineState == kIOPM_Finished );
3313 assert( powerState < fNumberOfPowerStates );
3314
3315 if (powerState >= fNumberOfPowerStates)
3316 return IOPMAckImplied;
3317
3318 fIsPreChange = true;
3319 PM_ACTION_2(actionPowerChangeOverride, &powerState, &changeFlags);
3320
3321 // Forks to either Driver or Parent initiated power change paths.
3322
3323 fHeadNoteChangeFlags = changeFlags;
3324 fHeadNotePowerState = powerState;
3325 fHeadNotePowerArrayEntry = &fPowerStates[ powerState ];
3326 fHeadNoteParentConnection = NULL;
3327
3328 if (changeFlags & kIOPMSelfInitiated)
3329 {
3330 if (changeFlags & kIOPMSynchronize)
3331 OurSyncStart();
3332 else
3333 OurChangeStart();
3334 return 0;
3335 }
3336 else
3337 {
3338 assert(changeFlags & kIOPMParentInitiated);
3339 fHeadNoteDomainFlags = domainFlags;
3340 fHeadNoteParentFlags = parentFlags;
3341 fHeadNoteParentConnection = parentConnection;
3342 return ParentChangeStart();
3343 }
3344 }
3345
3346 //*********************************************************************************
3347 // [private] notifyInterestedDrivers
3348 //*********************************************************************************
3349
3350 bool IOService::notifyInterestedDrivers ( void )
3351 {
3352 IOPMinformee * informee;
3353 IOPMinformeeList * list = fInterestedDrivers;
3354 DriverCallParam * param;
3355 IOItemCount count;
3356
3357 PM_ASSERT_IN_GATE();
3358 assert( fDriverCallParamCount == 0 );
3359 assert( fHeadNotePendingAcks == 0 );
3360
3361 fHeadNotePendingAcks = 0;
3362
3363 count = list->numberOfItems();
3364 if (!count)
3365 goto done; // no interested drivers
3366
3367 // Allocate an array of interested drivers and their return values
3368 // for the callout thread. Everything else is still "owned" by the
3369 // PM work loop, which can run to process acknowledgePowerChange()
3370 // responses.
3371
3372 param = (DriverCallParam *) fDriverCallParamPtr;
3373 if (count > fDriverCallParamSlots)
3374 {
3375 if (fDriverCallParamSlots)
3376 {
3377 assert(fDriverCallParamPtr);
3378 IODelete(fDriverCallParamPtr, DriverCallParam, fDriverCallParamSlots);
3379 fDriverCallParamPtr = 0;
3380 fDriverCallParamSlots = 0;
3381 }
3382
3383 param = IONew(DriverCallParam, count);
3384 if (!param)
3385 goto done; // no memory
3386
3387 fDriverCallParamPtr = (void *) param;
3388 fDriverCallParamSlots = count;
3389 }
3390
3391 informee = list->firstInList();
3392 assert(informee);
3393 for (IOItemCount i = 0; i < count; i++)
3394 {
3395 informee->timer = -1;
3396 param[i].Target = informee;
3397 informee->retain();
3398 informee = list->nextInList( informee );
3399 }
3400
3401 fDriverCallParamCount = count;
3402 fHeadNotePendingAcks = count;
3403
3404 // Block state machine and wait for callout completion.
3405 assert(!fDriverCallBusy);
3406 fDriverCallBusy = true;
3407 thread_call_enter( fDriverCallEntry );
3408 return true;
3409
3410 done:
3411 // Return false if there are no interested drivers or could not schedule
3412 // callout thread due to error.
3413 return false;
3414 }
3415
3416 //*********************************************************************************
3417 // [private] notifyInterestedDriversDone
3418 //*********************************************************************************
3419
3420 void IOService::notifyInterestedDriversDone ( void )
3421 {
3422 IOPMinformee * informee;
3423 IOItemCount count;
3424 DriverCallParam * param;
3425 IOReturn result;
3426
3427 PM_ASSERT_IN_GATE();
3428 assert( fDriverCallBusy == false );
3429 assert( fMachineState == kIOPM_DriverThreadCallDone );
3430
3431 param = (DriverCallParam *) fDriverCallParamPtr;
3432 count = fDriverCallParamCount;
3433
3434 if (param && count)
3435 {
3436 for (IOItemCount i = 0; i < count; i++, param++)
3437 {
3438 informee = (IOPMinformee *) param->Target;
3439 result = param->Result;
3440
3441 if ((result == IOPMAckImplied) || (result < 0))
3442 {
3443 // Interested driver return IOPMAckImplied.
3444 // If informee timer is zero, it must have de-registered
3445 // interest during the thread callout. That also drops
3446 // the pending ack count.
3447
3448 if (fHeadNotePendingAcks && informee->timer)
3449 fHeadNotePendingAcks--;
3450
3451 informee->timer = 0;
3452 }
3453 else if (informee->timer)
3454 {
3455 assert(informee->timer == -1);
3456
3457 // Driver has not acked, and has returned a positive result.
3458 // Enforce a minimum permissible timeout value.
3459 // Make the min value large enough so timeout is less likely
3460 // to occur if a driver misinterpreted that the return value
3461 // should be in microsecond units. And make it large enough
3462 // to be noticeable if a driver neglects to ack.
3463
3464 if (result < kMinAckTimeoutTicks)
3465 result = kMinAckTimeoutTicks;
3466
3467 informee->timer = (result / (ACK_TIMER_PERIOD / ns_per_us)) + 1;
3468 }
3469 // else, child has already acked or driver has removed interest,
3470 // and head_note_pendingAcks decremented.
3471 // informee may have been removed from the interested drivers list,
3472 // thus the informee must be retained across the callout.
3473
3474 informee->release();
3475 }
3476
3477 fDriverCallParamCount = 0;
3478
3479 if ( fHeadNotePendingAcks )
3480 {
3481 OUR_PMLog(kPMLogStartAckTimer, 0, 0);
3482 start_ack_timer();
3483 }
3484 }
3485
3486 MS_POP(); // pushed by notifyAll()
3487
3488 // If interest acks are outstanding, wait for fHeadNotePendingAcks to become
3489 // zero before notifying children. This enforces the children after interest
3490 // ordering even for async interest clients.
3491
3492 if (!fHeadNotePendingAcks)
3493 {
3494 notifyChildren();
3495 }
3496 else
3497 {
3498 MS_PUSH(fMachineState);
3499 fMachineState = kIOPM_NotifyChildrenStart;
3500 PM_LOG2("%s: %u outstanding async interest\n",
3501 getName(), fHeadNotePendingAcks);
3502 }
3503 }
3504
3505 //*********************************************************************************
3506 // [private] notifyChildren
3507 //*********************************************************************************
3508
3509 void IOService::notifyChildren ( void )
3510 {
3511 OSIterator * iter;
3512 OSObject * next;
3513 IOPowerConnection * connection;
3514 OSArray * children = 0;
3515 IOPMrootDomain * rootDomain;
3516 bool delayNotify = false;
3517
3518 if ((fHeadNotePowerState != fCurrentPowerState) &&
3519 (IS_POWER_DROP == fIsPreChange) &&
3520 ((rootDomain = getPMRootDomain()) == this))
3521 {
3522 rootDomain->tracePoint( IS_POWER_DROP ?
3523 kIOPMTracePointSleepPowerPlaneDrivers :
3524 kIOPMTracePointWakePowerPlaneDrivers );
3525 }
3526
3527 if (fStrictTreeOrder)
3528 children = OSArray::withCapacity(8);
3529
3530 // Sum child power consumption in notifyChild()
3531 fHeadNotePowerArrayEntry->staticPower = 0;
3532
3533 iter = getChildIterator(gIOPowerPlane);
3534 if ( iter )
3535 {
3536 while ((next = iter->getNextObject()))
3537 {
3538 if ((connection = OSDynamicCast(IOPowerConnection, next)))
3539 {
3540 if (connection->getReadyFlag() == false)
3541 {
3542 PM_LOG3("[%s] %s: connection not ready\n",
3543 getName(), __FUNCTION__);
3544 continue;
3545 }
3546
3547 // Mechanism to postpone the did-change notification to
3548 // certain power children to order those children last.
3549 // Cannot be used together with strict tree ordering.
3550
3551 if (!fIsPreChange &&
3552 (connection->delayChildNotification) &&
3553 getPMRootDomain()->shouldDelayChildNotification(this))
3554 {
3555 if (!children)
3556 {
3557 children = OSArray::withCapacity(8);
3558 if (children)
3559 delayNotify = true;
3560 }
3561 if (delayNotify)
3562 {
3563 children->setObject( connection );
3564 continue;
3565 }
3566 }
3567
3568 if (!delayNotify && children)
3569 children->setObject( connection );
3570 else
3571 notifyChild( connection );
3572 }
3573 }
3574 iter->release();
3575 }
3576
3577 if (children && (children->getCount() == 0))
3578 {
3579 children->release();
3580 children = 0;
3581 }
3582 if (children)
3583 {
3584 assert(fNotifyChildArray == 0);
3585 fNotifyChildArray = children;
3586 MS_PUSH(fMachineState);
3587
3588 if (delayNotify)
3589 {
3590 // Wait for exiting child notifications to complete,
3591 // before notifying the children in the array.
3592 fMachineState = kIOPM_NotifyChildrenDelayed;
3593 PM_LOG2("%s: %d children in delayed array\n",
3594 getName(), children->getCount());
3595 }
3596 else
3597 {
3598 // Notify children in the array one at a time.
3599 fMachineState = kIOPM_NotifyChildrenOrdered;
3600 }
3601 }
3602 }
3603
3604 //*********************************************************************************
3605 // [private] notifyChildrenOrdered
3606 //*********************************************************************************
3607
3608 void IOService::notifyChildrenOrdered ( void )
3609 {
3610 PM_ASSERT_IN_GATE();
3611 assert(fNotifyChildArray);
3612 assert(fMachineState == kIOPM_NotifyChildrenOrdered);
3613
3614 // Notify one child, wait for it to ack, then repeat for next child.
3615 // This is a workaround for some drivers with multiple instances at
3616 // the same branch in the power tree, but the driver is slow to power
3617 // up unless the tree ordering is observed. Problem observed only on
3618 // system wake, not on system sleep.
3619 //
3620 // We have the ability to power off in reverse child index order.
3621 // That works nicely on some machines, but not on all HW configs.
3622
3623 if (fNotifyChildArray->getCount())
3624 {
3625 IOPowerConnection * connection;
3626 connection = (IOPowerConnection *) fNotifyChildArray->getObject(0);
3627 notifyChild( connection );
3628 fNotifyChildArray->removeObject(0);
3629 }
3630 else
3631 {
3632 fNotifyChildArray->release();
3633 fNotifyChildArray = 0;
3634
3635 MS_POP(); // pushed by notifyChildren()
3636 }
3637 }
3638
3639 //*********************************************************************************
3640 // [private] notifyChildrenDelayed
3641 //*********************************************************************************
3642
3643 void IOService::notifyChildrenDelayed ( void )
3644 {
3645 IOPowerConnection * connection;
3646
3647 PM_ASSERT_IN_GATE();
3648 assert(fNotifyChildArray);
3649 assert(fMachineState == kIOPM_NotifyChildrenDelayed);
3650
3651 // Wait after all non-delayed children and interested drivers have ack'ed,
3652 // then notify all delayed children. When explicitly cancelled, interest
3653 // acks (and ack timer) may still be outstanding.
3654
3655 for (int i = 0; ; i++)
3656 {
3657 connection = (IOPowerConnection *) fNotifyChildArray->getObject(i);
3658 if (!connection)
3659 break;
3660
3661 notifyChild( connection );
3662 }
3663
3664 PM_LOG2("%s: notified delayed children\n", getName());
3665 fNotifyChildArray->release();
3666 fNotifyChildArray = 0;
3667
3668 MS_POP(); // pushed by notifyChildren()
3669 }
3670
3671 //*********************************************************************************
3672 // [private] notifyAll
3673 //*********************************************************************************
3674
3675 IOReturn IOService::notifyAll ( uint32_t nextMS )
3676 {
3677 // Save the next machine_state to be restored by notifyInterestedDriversDone()
3678
3679 PM_ASSERT_IN_GATE();
3680 MS_PUSH(nextMS);
3681 fMachineState = kIOPM_DriverThreadCallDone;
3682 fDriverCallReason = fIsPreChange ?
3683 kDriverCallInformPreChange : kDriverCallInformPostChange;
3684
3685 if (!notifyInterestedDrivers())
3686 notifyInterestedDriversDone();
3687
3688 return IOPMWillAckLater;
3689 }
3690
3691 //*********************************************************************************
3692 // [private, static] pmDriverCallout
3693 //
3694 // Thread call context
3695 //*********************************************************************************
3696
3697 IOReturn IOService::actionDriverCalloutDone (
3698 OSObject * target,
3699 void * arg0, void * arg1,
3700 void * arg2, void * arg3 )
3701 {
3702 IOServicePM * pwrMgt = (IOServicePM *) arg0;
3703
3704 assert( fDriverCallBusy );
3705 fDriverCallBusy = false;
3706
3707 assert(gIOPMWorkQueue);
3708 gIOPMWorkQueue->signalWorkAvailable();
3709
3710 return kIOReturnSuccess;
3711 }
3712
3713 void IOService::pmDriverCallout ( IOService * from )
3714 {
3715 assert(from);
3716 switch (from->fDriverCallReason)
3717 {
3718 case kDriverCallSetPowerState:
3719 from->driverSetPowerState();
3720 break;
3721
3722 case kDriverCallInformPreChange:
3723 case kDriverCallInformPostChange:
3724 from->driverInformPowerChange();
3725 break;
3726
3727 default:
3728 panic("IOService::pmDriverCallout bad machine state %x",
3729 from->fDriverCallReason);
3730 }
3731
3732 gIOPMWorkLoop->runAction(actionDriverCalloutDone,
3733 /* target */ from,
3734 /* arg0 */ (void *) from->pwrMgt );
3735 }
3736
3737 //*********************************************************************************
3738 // [private] driverSetPowerState
3739 //
3740 // Thread call context
3741 //*********************************************************************************
3742
3743 void IOService::driverSetPowerState ( void )
3744 {
3745 IOPMPowerStateIndex powerState;
3746 DriverCallParam * param;
3747 IOPMDriverCallEntry callEntry;
3748 AbsoluteTime end;
3749 IOReturn result;
3750 uint32_t oldPowerState = getPowerState();
3751
3752 assert( fDriverCallBusy );
3753 assert( fDriverCallParamPtr );
3754 assert( fDriverCallParamCount == 1 );
3755
3756 param = (DriverCallParam *) fDriverCallParamPtr;
3757 powerState = fHeadNotePowerState;
3758
3759 if (assertPMDriverCall(&callEntry))
3760 {
3761 OUR_PMLog( kPMLogProgramHardware, (uintptr_t) this, powerState);
3762 clock_get_uptime(&fDriverCallStartTime);
3763 result = fControllingDriver->setPowerState( powerState, this );
3764 clock_get_uptime(&end);
3765 OUR_PMLog((UInt32) -kPMLogProgramHardware, (uintptr_t) this, (UInt32) result);
3766
3767 deassertPMDriverCall(&callEntry);
3768
3769 if (result < 0)
3770 {
3771 PM_LOG("%s::setPowerState(%p, %lu -> %lu) returned 0x%x\n",
3772 fName, this, fCurrentPowerState, powerState, result);
3773 }
3774
3775 #if LOG_SETPOWER_TIMES
3776 if ((result == IOPMAckImplied) || (result < 0))
3777 {
3778 uint64_t nsec;
3779
3780 SUB_ABSOLUTETIME(&end, &fDriverCallStartTime);
3781 absolutetime_to_nanoseconds(end, &nsec);
3782 if (nsec > LOG_SETPOWER_TIMES)
3783 PM_LOG("%s::setPowerState(%p, %lu -> %lu) took %d ms\n",
3784 fName, this, fCurrentPowerState, powerState, NS_TO_MS(nsec));
3785
3786 PMEventDetails *details = PMEventDetails::eventDetails(
3787 kIOPMEventTypeSetPowerStateImmediate, // type
3788 fName, // who
3789 (uintptr_t)this, // owner unique
3790 NULL, // interest name
3791 (uint8_t)oldPowerState, // old
3792 (uint8_t)powerState, // new
3793 0, // result
3794 NS_TO_US(nsec)); // usec completion time
3795
3796 getPMRootDomain()->recordAndReleasePMEventGated( details );
3797 }
3798 #endif
3799 }
3800 else
3801 result = kIOPMAckImplied;
3802
3803 param->Result = result;
3804 }
3805
3806 //*********************************************************************************
3807 // [private] driverInformPowerChange
3808 //
3809 // Thread call context
3810 //*********************************************************************************
3811
3812 void IOService::driverInformPowerChange ( void )
3813 {
3814 IOPMinformee * informee;
3815 IOService * driver;
3816 DriverCallParam * param;
3817 IOPMDriverCallEntry callEntry;
3818 IOPMPowerFlags powerFlags;
3819 IOPMPowerStateIndex powerState;
3820 AbsoluteTime end;
3821 IOReturn result;
3822 IOItemCount count;
3823
3824 assert( fDriverCallBusy );
3825 assert( fDriverCallParamPtr );
3826 assert( fDriverCallParamCount );
3827
3828 param = (DriverCallParam *) fDriverCallParamPtr;
3829 count = fDriverCallParamCount;
3830
3831 powerFlags = fHeadNotePowerArrayEntry->capabilityFlags;
3832 powerState = fHeadNotePowerState;
3833
3834 for (IOItemCount i = 0; i < count; i++)
3835 {
3836 informee = (IOPMinformee *) param->Target;
3837 driver = informee->whatObject;
3838
3839 if (assertPMDriverCall(&callEntry, 0, informee))
3840 {
3841 if (fDriverCallReason == kDriverCallInformPreChange)
3842 {
3843 OUR_PMLog(kPMLogInformDriverPreChange, (uintptr_t) this, powerState);
3844 clock_get_uptime(&informee->startTime);
3845 result = driver->powerStateWillChangeTo(powerFlags, powerState, this);
3846 clock_get_uptime(&end);
3847 OUR_PMLog((UInt32)-kPMLogInformDriverPreChange, (uintptr_t) this, result);
3848 }
3849 else
3850 {
3851 OUR_PMLog(kPMLogInformDriverPostChange, (uintptr_t) this, powerState);
3852 clock_get_uptime(&informee->startTime);
3853 result = driver->powerStateDidChangeTo(powerFlags, powerState, this);
3854 clock_get_uptime(&end);
3855 OUR_PMLog((UInt32)-kPMLogInformDriverPostChange, (uintptr_t) this, result);
3856 }
3857
3858 deassertPMDriverCall(&callEntry);
3859
3860 #if LOG_SETPOWER_TIMES
3861 if ((result == IOPMAckImplied) || (result < 0))
3862 {
3863 uint64_t nsec;
3864
3865 SUB_ABSOLUTETIME(&end, &informee->startTime);
3866 absolutetime_to_nanoseconds(end, &nsec);
3867 if (nsec > LOG_SETPOWER_TIMES)
3868 PM_LOG("%s::powerState%sChangeTo(%p, %s, %lu -> %lu) took %d ms\n",
3869 driver->getName(),
3870 (fDriverCallReason == kDriverCallInformPreChange) ? "Will" : "Did",
3871 driver, fName, fCurrentPowerState, powerState, NS_TO_MS(nsec));
3872
3873 uint16_t logType = (fDriverCallReason == kDriverCallInformPreChange)
3874 ? kIOPMEventTypePSWillChangeTo
3875 : kIOPMEventTypePSDidChangeTo;
3876
3877 PMEventDetails *details = PMEventDetails::eventDetails(
3878 logType, // type
3879 fName, // who
3880 (uintptr_t)this, // owner unique
3881 driver->getName(), // interest name
3882 (uint8_t)fCurrentPowerState, // old
3883 (uint8_t)fHeadNotePowerState, // new
3884 0, // result
3885 NS_TO_US(nsec)); // usec completion time
3886
3887 getPMRootDomain()->recordAndReleasePMEventGated( details );
3888 }
3889 #endif
3890 }
3891 else
3892 result = kIOPMAckImplied;
3893
3894 param->Result = result;
3895 param++;
3896 }
3897 }
3898
3899 //*********************************************************************************
3900 // [private] notifyChild
3901 //
3902 // Notify a power domain child of an upcoming power change.
3903 // If the object acknowledges the current change, we return TRUE.
3904 //*********************************************************************************
3905
3906 bool IOService::notifyChild ( IOPowerConnection * theNub )
3907 {
3908 IOReturn ret = IOPMAckImplied;
3909 unsigned long childPower;
3910 IOService * theChild;
3911 IOPMRequest * childRequest;
3912 IOPMPowerChangeFlags requestArg2;
3913 int requestType;
3914
3915 PM_ASSERT_IN_GATE();
3916 theChild = (IOService *)(theNub->copyChildEntry(gIOPowerPlane));
3917 if (!theChild)
3918 {
3919 return true;
3920 }
3921
3922 // Unless the child handles the notification immediately and returns
3923 // kIOPMAckImplied, we'll be awaiting their acknowledgement later.
3924 fHeadNotePendingAcks++;
3925 theNub->setAwaitingAck(true);
3926
3927 requestArg2 = fHeadNoteChangeFlags;
3928 if (fHeadNotePowerState < fCurrentPowerState)
3929 requestArg2 |= kIOPMDomainPowerDrop;
3930
3931 requestType = fIsPreChange ?
3932 kIOPMRequestTypePowerDomainWillChange :
3933 kIOPMRequestTypePowerDomainDidChange;
3934
3935 childRequest = acquirePMRequest( theChild, requestType );
3936 if (childRequest)
3937 {
3938 theNub->retain();
3939 childRequest->fArg0 = (void *) fHeadNotePowerArrayEntry->outputPowerFlags;
3940 childRequest->fArg1 = (void *) theNub;
3941 childRequest->fArg2 = (void *) requestArg2;
3942 theChild->submitPMRequest( childRequest );
3943 ret = IOPMWillAckLater;
3944 }
3945 else
3946 {
3947 ret = IOPMAckImplied;
3948 fHeadNotePendingAcks--;
3949 theNub->setAwaitingAck(false);
3950 childPower = theChild->currentPowerConsumption();
3951 if ( childPower == kIOPMUnknown )
3952 {
3953 fHeadNotePowerArrayEntry->staticPower = kIOPMUnknown;
3954 } else {
3955 if (fHeadNotePowerArrayEntry->staticPower != kIOPMUnknown )
3956 fHeadNotePowerArrayEntry->staticPower += childPower;
3957 }
3958 }
3959
3960 theChild->release();
3961 return (IOPMAckImplied == ret);
3962 }
3963
3964 //*********************************************************************************
3965 // [private] notifyControllingDriver
3966 //*********************************************************************************
3967
3968 bool IOService::notifyControllingDriver ( void )
3969 {
3970 DriverCallParam * param;
3971
3972 PM_ASSERT_IN_GATE();
3973 assert( fDriverCallParamCount == 0 );
3974 assert( fControllingDriver );
3975
3976 if (fInitialSetPowerState)
3977 {
3978 fInitialSetPowerState = false;
3979 fHeadNoteChangeFlags |= kIOPMInitialPowerChange;
3980
3981 // Driver specified flag to skip the inital setPowerState()
3982 if (fHeadNotePowerArrayEntry->capabilityFlags & kIOPMInitialDeviceState)
3983 {
3984 return false;
3985 }
3986 }
3987
3988 param = (DriverCallParam *) fDriverCallParamPtr;
3989 if (!param)
3990 {
3991 param = IONew(DriverCallParam, 1);
3992 if (!param)
3993 return false; // no memory
3994
3995 fDriverCallParamPtr = (void *) param;
3996 fDriverCallParamSlots = 1;
3997 }
3998
3999 param->Target = fControllingDriver;
4000 fDriverCallParamCount = 1;
4001 fDriverTimer = -1;
4002
4003 // Block state machine and wait for callout completion.
4004 assert(!fDriverCallBusy);
4005 fDriverCallBusy = true;
4006 thread_call_enter( fDriverCallEntry );
4007
4008 return true;
4009 }
4010
4011 //*********************************************************************************
4012 // [private] notifyControllingDriverDone
4013 //*********************************************************************************
4014
4015 void IOService::notifyControllingDriverDone( void )
4016 {
4017 DriverCallParam * param;
4018 IOReturn result;
4019
4020 PM_ASSERT_IN_GATE();
4021 param = (DriverCallParam *) fDriverCallParamPtr;
4022
4023 assert( fDriverCallBusy == false );
4024 assert( fMachineState == kIOPM_DriverThreadCallDone );
4025
4026 if (param && fDriverCallParamCount)
4027 {
4028 assert(fDriverCallParamCount == 1);
4029
4030 // the return value from setPowerState()
4031 result = param->Result;
4032
4033 if ((result == IOPMAckImplied) || (result < 0))
4034 {
4035 fDriverTimer = 0;
4036 }
4037 else if (fDriverTimer)
4038 {
4039 assert(fDriverTimer == -1);
4040
4041 // Driver has not acked, and has returned a positive result.
4042 // Enforce a minimum permissible timeout value.
4043 // Make the min value large enough so timeout is less likely
4044 // to occur if a driver misinterpreted that the return value
4045 // should be in microsecond units. And make it large enough
4046 // to be noticeable if a driver neglects to ack.
4047
4048 if (result < kMinAckTimeoutTicks)
4049 result = kMinAckTimeoutTicks;
4050
4051 fDriverTimer = (result / (ACK_TIMER_PERIOD / ns_per_us)) + 1;
4052 }
4053 // else, child has already acked and driver_timer reset to 0.
4054
4055 fDriverCallParamCount = 0;
4056
4057 if ( fDriverTimer )
4058 {
4059 OUR_PMLog(kPMLogStartAckTimer, 0, 0);
4060 start_ack_timer();
4061 }
4062 }
4063
4064 MS_POP(); // pushed by OurChangeSetPowerState()
4065 fIsPreChange = false;
4066 }
4067
4068 //*********************************************************************************
4069 // [private] all_done
4070 //
4071 // A power change is done.
4072 //*********************************************************************************
4073
4074 void IOService::all_done ( void )
4075 {
4076 IOPMPowerStateIndex prevPowerState;
4077 const IOPMPSEntry * powerStatePtr;
4078 IOPMDriverCallEntry callEntry;
4079 uint32_t prevMachineState = fMachineState;
4080 bool callAction = false;
4081
4082 fMachineState = kIOPM_Finished;
4083
4084 if ((fHeadNoteChangeFlags & kIOPMSynchronize) &&
4085 ((prevMachineState == kIOPM_Finished) ||
4086 (prevMachineState == 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 PM_ACTION_2(actionPowerChangeDone,
4093 fHeadNotePowerState, fHeadNoteChangeFlags);
4094
4095 if (getPMRequestType() == kIOPMRequestTypeSynchronizePowerTree)
4096 {
4097 powerChangeDone(fCurrentPowerState);
4098 }
4099 else if (fAdvisoryTickleUsed)
4100 {
4101 // Not root domain and advisory tickle target
4102 // Re-adjust power after power tree sync at the 'did' pass
4103 if (!fAdjustPowerScheduled &&
4104 (fHeadNoteChangeFlags & kIOPMDomainDidChange))
4105 {
4106 IOPMRequest * request;
4107 request = acquirePMRequest( this, kIOPMRequestTypeAdjustPowerState );
4108 if (request)
4109 {
4110 submitPMRequest( request );
4111 fAdjustPowerScheduled = true;
4112 }
4113 }
4114 }
4115
4116 return;
4117 }
4118
4119 // our power change
4120 if ( fHeadNoteChangeFlags & kIOPMSelfInitiated )
4121 {
4122 // could our driver switch to the new state?
4123 if ( !( fHeadNoteChangeFlags & kIOPMNotDone) )
4124 {
4125 trackSystemSleepPreventers(
4126 fCurrentPowerState, fHeadNotePowerState, fHeadNoteChangeFlags);
4127
4128 // we changed, tell our parent
4129 requestDomainPower(fHeadNotePowerState);
4130
4131 // yes, did power raise?
4132 if ( fCurrentPowerState < fHeadNotePowerState )
4133 {
4134 // yes, inform clients and apps
4135 tellChangeUp (fHeadNotePowerState);
4136 }
4137 prevPowerState = fCurrentPowerState;
4138 // either way
4139 fCurrentPowerState = fHeadNotePowerState;
4140 #if PM_VARS_SUPPORT
4141 fPMVars->myCurrentState = fCurrentPowerState;
4142 #endif
4143 OUR_PMLog(kPMLogChangeDone, fCurrentPowerState, prevPowerState);
4144 PM_ACTION_2(actionPowerChangeDone,
4145 fHeadNotePowerState, fHeadNoteChangeFlags);
4146 callAction = true;
4147
4148 powerStatePtr = &fPowerStates[fCurrentPowerState];
4149 fCurrentCapabilityFlags = powerStatePtr->capabilityFlags;
4150 if (fCurrentCapabilityFlags & kIOPMStaticPowerValid)
4151 fCurrentPowerConsumption = powerStatePtr->staticPower;
4152
4153 // inform subclass policy-maker
4154 if (fPCDFunctionOverride && fParentsKnowState &&
4155 assertPMDriverCall(&callEntry, kIOPMADC_NoInactiveCheck))
4156 {
4157 powerChangeDone(prevPowerState);
4158 deassertPMDriverCall(&callEntry);
4159 }
4160 }
4161 else if (getPMRequestType() == kIOPMRequestTypeRequestPowerStateOverride)
4162 {
4163 // changePowerStateWithOverrideTo() was cancelled
4164 fOverrideMaxPowerState = kIOPMPowerStateMax;
4165 }
4166 }
4167
4168 // parent's power change
4169 if ( fHeadNoteChangeFlags & kIOPMParentInitiated)
4170 {
4171 if (((fHeadNoteChangeFlags & kIOPMDomainWillChange) &&
4172 (fCurrentPowerState >= fHeadNotePowerState)) ||
4173 ((fHeadNoteChangeFlags & kIOPMDomainDidChange) &&
4174 (fCurrentPowerState < fHeadNotePowerState)))
4175 {
4176 trackSystemSleepPreventers(
4177 fCurrentPowerState, fHeadNotePowerState, fHeadNoteChangeFlags);
4178
4179 // did power raise?
4180 if ( fCurrentPowerState < fHeadNotePowerState )
4181 {
4182 // yes, inform clients and apps
4183 tellChangeUp (fHeadNotePowerState);
4184 }
4185 // either way
4186 prevPowerState = fCurrentPowerState;
4187 fCurrentPowerState = fHeadNotePowerState;
4188 #if PM_VARS_SUPPORT
4189 fPMVars->myCurrentState = fCurrentPowerState;
4190 #endif
4191 fMaxPowerState = fControllingDriver->maxCapabilityForDomainState(fHeadNoteDomainFlags);
4192
4193 OUR_PMLog(kPMLogChangeDone, fCurrentPowerState, prevPowerState);
4194 PM_ACTION_2(actionPowerChangeDone,
4195 fHeadNotePowerState, fHeadNoteChangeFlags);
4196 callAction = true;
4197
4198 powerStatePtr = &fPowerStates[fCurrentPowerState];
4199 fCurrentCapabilityFlags = powerStatePtr->capabilityFlags;
4200 if (fCurrentCapabilityFlags & kIOPMStaticPowerValid)
4201 fCurrentPowerConsumption = powerStatePtr->staticPower;
4202
4203 // inform subclass policy-maker
4204 if (fPCDFunctionOverride && fParentsKnowState &&
4205 assertPMDriverCall(&callEntry, kIOPMADC_NoInactiveCheck))
4206 {
4207 powerChangeDone(prevPowerState);
4208 deassertPMDriverCall(&callEntry);
4209 }
4210 }
4211 }
4212
4213 // When power rises enough to satisfy the tickle's desire for more power,
4214 // the condition preventing idle-timer from dropping power is removed.
4215
4216 if (fCurrentPowerState >= fIdleTimerMinPowerState)
4217 {
4218 fIdleTimerMinPowerState = 0;
4219 }
4220
4221 if (!callAction)
4222 {
4223 PM_ACTION_2(actionPowerChangeDone,
4224 fHeadNotePowerState, fHeadNoteChangeFlags);
4225 }
4226 }
4227
4228 // MARK: -
4229 // MARK: Power Change Initiated by Driver
4230
4231 //*********************************************************************************
4232 // [private] OurChangeStart
4233 //
4234 // Begin the processing of a power change initiated by us.
4235 //*********************************************************************************
4236
4237 void IOService::OurChangeStart ( void )
4238 {
4239 PM_ASSERT_IN_GATE();
4240 OUR_PMLog( kPMLogStartDeviceChange, fHeadNotePowerState, fCurrentPowerState );
4241
4242 // fMaxPowerState is our maximum possible power state based on the current
4243 // power state of our parents. If we are trying to raise power beyond the
4244 // maximum, send an async request for more power to all parents.
4245
4246 if (!IS_PM_ROOT && (fMaxPowerState < fHeadNotePowerState))
4247 {
4248 fHeadNoteChangeFlags |= kIOPMNotDone;
4249 requestDomainPower(fHeadNotePowerState);
4250 OurChangeFinish();
4251 return;
4252 }
4253
4254 // Redundant power changes skips to the end of the state machine.
4255
4256 if (!fInitialPowerChange && (fHeadNotePowerState == fCurrentPowerState))
4257 {
4258 OurChangeFinish();
4259 return;
4260 }
4261 fInitialPowerChange = false;
4262
4263 // Change started, but may not complete...
4264 // Can be canceled (power drop) or deferred (power rise).
4265
4266 PM_ACTION_2(actionPowerChangeStart, fHeadNotePowerState, &fHeadNoteChangeFlags);
4267
4268 // Two separate paths, depending if power is being raised or lowered.
4269 // Lowering power is subject to approval by clients of this service.
4270
4271 if (IS_POWER_DROP)
4272 {
4273 fDoNotPowerDown = false;
4274
4275 // Ask for persmission to drop power state
4276 fMachineState = kIOPM_OurChangeTellClientsPowerDown;
4277 fOutOfBandParameter = kNotifyApps;
4278 askChangeDown(fHeadNotePowerState);
4279 }
4280 else
4281 {
4282 // This service is raising power and parents are able to support the
4283 // new power state. However a parent may have already committed to
4284 // drop power, which might force this object to temporarily drop power.
4285 // This results in "oscillations" before the state machines converge
4286 // to a steady state.
4287 //
4288 // To prevent this, a child must make a power reservation against all
4289 // parents before raising power. If the reservation fails, indicating
4290 // that the child will be unable to sustain the higher power state,
4291 // then the child will signal the parent to adjust power, and the child
4292 // will defer its power change.
4293
4294 IOReturn ret;
4295
4296 // Reserve parent power necessary to achieve fHeadNotePowerState.
4297 ret = requestDomainPower( fHeadNotePowerState, kReserveDomainPower );
4298 if (ret != kIOReturnSuccess)
4299 {
4300 // Reservation failed, defer power rise.
4301 fHeadNoteChangeFlags |= kIOPMNotDone;
4302 OurChangeFinish();
4303 return;
4304 }
4305
4306 OurChangeTellCapabilityWillChange();
4307 }
4308 }
4309
4310 //*********************************************************************************
4311
4312 struct IOPMRequestDomainPowerContext {
4313 IOService * child; // the requesting child
4314 IOPMPowerFlags requestPowerFlags; // power flags requested by child
4315 };
4316
4317 static void
4318 requestDomainPowerApplier(
4319 IORegistryEntry * entry,
4320 void * inContext )
4321 {
4322 IOPowerConnection * connection;
4323 IOService * parent;
4324 IOPMRequestDomainPowerContext * context;
4325
4326 if ((connection = OSDynamicCast(IOPowerConnection, entry)) == 0)
4327 return;
4328 parent = (IOService *) connection->copyParentEntry(gIOPowerPlane);
4329 if (!parent)
4330 return;
4331
4332 assert(inContext);
4333 context = (IOPMRequestDomainPowerContext *) inContext;
4334
4335 if (connection->parentKnowsState() && connection->getReadyFlag())
4336 {
4337 parent->requestPowerDomainState(
4338 context->requestPowerFlags,
4339 connection,
4340 IOPMLowestState);
4341 }
4342
4343 parent->release();
4344 }
4345
4346 //*********************************************************************************
4347 // [private] requestDomainPower
4348 //*********************************************************************************
4349
4350 IOReturn IOService::requestDomainPower(
4351 IOPMPowerStateIndex ourPowerState,
4352 IOOptionBits options )
4353 {
4354 IOPMPowerFlags requestPowerFlags;
4355 IOPMPowerStateIndex maxPowerState;
4356 IOPMRequestDomainPowerContext context;
4357
4358 PM_ASSERT_IN_GATE();
4359 assert(ourPowerState < fNumberOfPowerStates);
4360 if (ourPowerState >= fNumberOfPowerStates)
4361 return kIOReturnBadArgument;
4362 if (IS_PM_ROOT)
4363 return kIOReturnSuccess;
4364
4365 // Fetch the input power flags for the requested power state.
4366 // Parent request is stated in terms of required power flags.
4367
4368 requestPowerFlags = fPowerStates[ourPowerState].inputPowerFlags;
4369
4370 // Disregard the "previous request" for power reservation.
4371
4372 if (((options & kReserveDomainPower) == 0) &&
4373 (fPreviousRequestPowerFlags == requestPowerFlags))
4374 {
4375 // skip if domain already knows our requirements
4376 goto done;
4377 }
4378 fPreviousRequestPowerFlags = requestPowerFlags;
4379
4380 context.child = this;
4381 context.requestPowerFlags = requestPowerFlags;
4382 fHeadNoteDomainTargetFlags = 0;
4383 applyToParents(requestDomainPowerApplier, &context, gIOPowerPlane);
4384
4385 if (options & kReserveDomainPower)
4386 {
4387 maxPowerState = fControllingDriver->maxCapabilityForDomainState(
4388 fHeadNoteDomainTargetFlags );
4389
4390 if (maxPowerState < fHeadNotePowerState)
4391 {
4392 PM_LOG1("%s: power desired %u:0x%x got %u:0x%x\n",
4393 getName(),
4394 (uint32_t) ourPowerState, (uint32_t) requestPowerFlags,
4395 (uint32_t) maxPowerState, (uint32_t) fHeadNoteDomainTargetFlags);
4396 return kIOReturnNoPower;
4397 }
4398 }
4399
4400 done:
4401 return kIOReturnSuccess;
4402 }
4403
4404 //*********************************************************************************
4405 // [private] OurSyncStart
4406 //*********************************************************************************
4407
4408 void IOService::OurSyncStart ( void )
4409 {
4410 PM_ASSERT_IN_GATE();
4411
4412 if (fInitialPowerChange)
4413 return;
4414
4415 PM_ACTION_2(actionPowerChangeStart, fHeadNotePowerState, &fHeadNoteChangeFlags);
4416
4417 if (fHeadNoteChangeFlags & kIOPMNotDone)
4418 {
4419 OurChangeFinish();
4420 return;
4421 }
4422
4423 if (fHeadNoteChangeFlags & kIOPMSyncTellPowerDown)
4424 {
4425 fDoNotPowerDown = false;
4426
4427 // Ask for permission to drop power state
4428 fMachineState = kIOPM_SyncTellClientsPowerDown;
4429 fOutOfBandParameter = kNotifyApps;
4430 askChangeDown(fHeadNotePowerState);
4431 }
4432 else
4433 {
4434 // Only inform capability app and clients.
4435 tellSystemCapabilityChange( kIOPM_SyncNotifyWillChange );
4436 }
4437 }
4438
4439 //*********************************************************************************
4440 // [private] OurChangeTellClientsPowerDown
4441 //
4442 // All applications and kernel clients have acknowledged our permission to drop
4443 // power. Here we notify them that we will lower the power and wait for acks.
4444 //*********************************************************************************
4445
4446 void IOService::OurChangeTellClientsPowerDown ( void )
4447 {
4448 fMachineState = kIOPM_OurChangeTellPriorityClientsPowerDown;
4449 tellChangeDown1(fHeadNotePowerState);
4450 }
4451
4452 //*********************************************************************************
4453 // [private] OurChangeTellPriorityClientsPowerDown
4454 //
4455 // All applications and kernel clients have acknowledged our intention to drop
4456 // power. Here we notify "priority" clients that we are lowering power.
4457 //*********************************************************************************
4458
4459 void IOService::OurChangeTellPriorityClientsPowerDown ( void )
4460 {
4461 fMachineState = kIOPM_OurChangeNotifyInterestedDriversWillChange;
4462 tellChangeDown2(fHeadNotePowerState);
4463 }
4464
4465 //*********************************************************************************
4466 // [private] OurChangeTellCapabilityWillChange
4467 //
4468 // Extra stage for root domain to notify apps and drivers about the
4469 // system capability change when raising power state.
4470 //*********************************************************************************
4471
4472 void IOService::OurChangeTellCapabilityWillChange ( void )
4473 {
4474 if (!IS_ROOT_DOMAIN)
4475 return OurChangeNotifyInterestedDriversWillChange();
4476
4477 tellSystemCapabilityChange( kIOPM_OurChangeNotifyInterestedDriversWillChange );
4478 }
4479
4480 //*********************************************************************************
4481 // [private] OurChangeNotifyInterestedDriversWillChange
4482 //
4483 // All applications and kernel clients have acknowledged our power state change.
4484 // Here we notify interested drivers pre-change.
4485 //*********************************************************************************
4486
4487 void IOService::OurChangeNotifyInterestedDriversWillChange ( void )
4488 {
4489 IOPMrootDomain * rootDomain;
4490 if ((rootDomain = getPMRootDomain()) == this)
4491 {
4492 if (IS_POWER_DROP)
4493 {
4494 rootDomain->tracePoint( kIOPMTracePointSleepWillChangeInterests );
4495
4496 PMEventDetails *details = PMEventDetails::eventDetails(
4497 kIOPMEventTypeAppNotificationsFinished,
4498 NULL,
4499 100,
4500 kIOReturnSuccess);
4501 rootDomain->recordAndReleasePMEventGated( details );
4502 }
4503 else
4504 rootDomain->tracePoint( kIOPMTracePointWakeWillChangeInterests );
4505 }
4506
4507 notifyAll( kIOPM_OurChangeSetPowerState );
4508 }
4509
4510 //*********************************************************************************
4511 // [private] OurChangeSetPowerState
4512 //
4513 // Instruct our controlling driver to program the hardware for the power state
4514 // change. Wait for async completions.
4515 //*********************************************************************************
4516
4517 void IOService::OurChangeSetPowerState ( void )
4518 {
4519 MS_PUSH( kIOPM_OurChangeWaitForPowerSettle );
4520 fMachineState = kIOPM_DriverThreadCallDone;
4521 fDriverCallReason = kDriverCallSetPowerState;
4522
4523 if (notifyControllingDriver() == false)
4524 notifyControllingDriverDone();
4525 }
4526
4527 //*********************************************************************************
4528 // [private] OurChangeWaitForPowerSettle
4529 //
4530 // Our controlling driver has completed the power state change we initiated.
4531 // Wait for the driver specified settle time to expire.
4532 //*********************************************************************************
4533
4534 void IOService::OurChangeWaitForPowerSettle ( void )
4535 {
4536 fMachineState = kIOPM_OurChangeNotifyInterestedDriversDidChange;
4537 startSettleTimer();
4538 }
4539
4540 //*********************************************************************************
4541 // [private] OurChangeNotifyInterestedDriversDidChange
4542 //
4543 // Power has settled on a power change we initiated. Here we notify
4544 // all our interested drivers post-change.
4545 //*********************************************************************************
4546
4547 void IOService::OurChangeNotifyInterestedDriversDidChange ( void )
4548 {
4549 IOPMrootDomain * rootDomain;
4550 if ((rootDomain = getPMRootDomain()) == this)
4551 {
4552 rootDomain->tracePoint( IS_POWER_DROP ?
4553 kIOPMTracePointSleepDidChangeInterests :
4554 kIOPMTracePointWakeDidChangeInterests );
4555 }
4556
4557 notifyAll( kIOPM_OurChangeTellCapabilityDidChange );
4558 }
4559
4560 //*********************************************************************************
4561 // [private] OurChangeTellCapabilityDidChange
4562 //
4563 // For root domain to notify capability power-change.
4564 //*********************************************************************************
4565
4566 void IOService::OurChangeTellCapabilityDidChange ( void )
4567 {
4568 if (!IS_ROOT_DOMAIN)
4569 return OurChangeFinish();
4570
4571 getPMRootDomain()->tracePoint( IS_POWER_DROP ?
4572 kIOPMTracePointSleepCapabilityClients :
4573 kIOPMTracePointWakeCapabilityClients );
4574
4575 tellSystemCapabilityChange( kIOPM_OurChangeFinish );
4576 }
4577
4578 //*********************************************************************************
4579 // [private] OurChangeFinish
4580 //
4581 // Done with this self-induced power state change.
4582 //*********************************************************************************
4583
4584 void IOService::OurChangeFinish ( void )
4585 {
4586 all_done();
4587 }
4588
4589 // MARK: -
4590 // MARK: Power Change Initiated by Parent
4591
4592 //*********************************************************************************
4593 // [private] ParentChangeStart
4594 //
4595 // Here we begin the processing of a power change initiated by our parent.
4596 //*********************************************************************************
4597
4598 IOReturn IOService::ParentChangeStart ( void )
4599 {
4600 PM_ASSERT_IN_GATE();
4601 OUR_PMLog( kPMLogStartParentChange, fHeadNotePowerState, fCurrentPowerState );
4602
4603 // Power domain is lowering power
4604 if ( fHeadNotePowerState < fCurrentPowerState )
4605 {
4606 // Piggy-back idle timer cancellation on a parent down
4607 if (0 == fHeadNotePowerState)
4608 ParentChangeCancelIdleTimer(fHeadNotePowerState);
4609
4610 // TODO: redundant? See handlePowerDomainWillChangeTo()
4611 setParentInfo( fHeadNoteParentFlags, fHeadNoteParentConnection, true );
4612
4613 PM_ACTION_2(actionPowerChangeStart, fHeadNotePowerState, &fHeadNoteChangeFlags);
4614
4615 // Tell apps and kernel clients
4616 fInitialPowerChange = false;
4617 fMachineState = kIOPM_ParentChangeTellPriorityClientsPowerDown;
4618 tellChangeDown1(fHeadNotePowerState);
4619 return IOPMWillAckLater;
4620 }
4621
4622 // Power domain is raising power
4623 if ( fHeadNotePowerState > fCurrentPowerState )
4624 {
4625 if ( fDesiredPowerState > fCurrentPowerState )
4626 {
4627 if ( fDesiredPowerState < fHeadNotePowerState )
4628 {
4629 // We power up, but not all the way
4630 fHeadNotePowerState = fDesiredPowerState;
4631 fHeadNotePowerArrayEntry = &fPowerStates[fDesiredPowerState];
4632 OUR_PMLog(kPMLogAmendParentChange, fHeadNotePowerState, 0);
4633 }
4634 } else {
4635 // We don't need to change
4636 fHeadNotePowerState = fCurrentPowerState;
4637 fHeadNotePowerArrayEntry = &fPowerStates[fCurrentPowerState];
4638 OUR_PMLog(kPMLogAmendParentChange, fHeadNotePowerState, 0);
4639 }
4640 }
4641
4642 if ( fHeadNoteChangeFlags & kIOPMDomainDidChange )
4643 {
4644 if ( fHeadNotePowerState > fCurrentPowerState )
4645 {
4646 PM_ACTION_2(actionPowerChangeStart,
4647 fHeadNotePowerState, &fHeadNoteChangeFlags);
4648
4649 // Parent did change up - start our change up
4650 fInitialPowerChange = false;
4651 ParentChangeTellCapabilityWillChange();
4652 return IOPMWillAckLater;
4653 }
4654 else if (fHeadNoteChangeFlags & kIOPMSynchronize)
4655 {
4656 // We do not need to change power state, but notify
4657 // children to propagate tree synchronization.
4658 fMachineState = kIOPM_SyncNotifyDidChange;
4659 fDriverCallReason = kDriverCallInformPreChange;
4660 notifyChildren();
4661 return IOPMWillAckLater;
4662 }
4663 }
4664
4665 all_done();
4666 return IOPMAckImplied;
4667 }
4668
4669 //*********************************************************************************
4670 // [private] ParentChangeTellPriorityClientsPowerDown
4671 //
4672 // All applications and kernel clients have acknowledged our intention to drop
4673 // power. Here we notify "priority" clients that we are lowering power.
4674 //*********************************************************************************
4675
4676 void IOService::ParentChangeTellPriorityClientsPowerDown ( void )
4677 {
4678 fMachineState = kIOPM_ParentChangeNotifyInterestedDriversWillChange;
4679 tellChangeDown2(fHeadNotePowerState);
4680 }
4681
4682 //*********************************************************************************
4683 // [private] ParentChangeTellCapabilityWillChange
4684 //
4685 // All (legacy) applications and kernel clients have acknowledged, extra stage for
4686 // root domain to notify apps and drivers about the system capability change.
4687 //*********************************************************************************
4688
4689 void IOService::ParentChangeTellCapabilityWillChange ( void )
4690 {
4691 if (!IS_ROOT_DOMAIN)
4692 return ParentChangeNotifyInterestedDriversWillChange();
4693
4694 tellSystemCapabilityChange( kIOPM_ParentChangeNotifyInterestedDriversWillChange );
4695 }
4696
4697 //*********************************************************************************
4698 // [private] ParentChangeNotifyInterestedDriversWillChange
4699 //
4700 // All applications and kernel clients have acknowledged our power state change.
4701 // Here we notify interested drivers pre-change.
4702 //*********************************************************************************
4703
4704 void IOService::ParentChangeNotifyInterestedDriversWillChange ( void )
4705 {
4706 notifyAll( kIOPM_ParentChangeSetPowerState );
4707 }
4708
4709 //*********************************************************************************
4710 // [private] ParentChangeSetPowerState
4711 //
4712 // Instruct our controlling driver to program the hardware for the power state
4713 // change. Wait for async completions.
4714 //*********************************************************************************
4715
4716 void IOService::ParentChangeSetPowerState ( void )
4717 {
4718 MS_PUSH( kIOPM_ParentChangeWaitForPowerSettle );
4719 fMachineState = kIOPM_DriverThreadCallDone;
4720 fDriverCallReason = kDriverCallSetPowerState;
4721
4722 if (notifyControllingDriver() == false)
4723 notifyControllingDriverDone();
4724 }
4725
4726 //*********************************************************************************
4727 // [private] ParentChangeWaitForPowerSettle
4728 //
4729 // Our controlling driver has completed the power state change initiated by our
4730 // parent. Wait for the driver specified settle time to expire.
4731 //*********************************************************************************
4732
4733 void IOService::ParentChangeWaitForPowerSettle ( void )
4734 {
4735 fMachineState = kIOPM_ParentChangeNotifyInterestedDriversDidChange;
4736 startSettleTimer();
4737 }
4738
4739 //*********************************************************************************
4740 // [private] ParentChangeNotifyInterestedDriversDidChange
4741 //
4742 // Power has settled on a power change initiated by our parent. Here we notify
4743 // all our interested drivers post-change.
4744 //*********************************************************************************
4745
4746 void IOService::ParentChangeNotifyInterestedDriversDidChange ( void )
4747 {
4748 notifyAll( kIOPM_ParentChangeTellCapabilityDidChange );
4749 }
4750
4751 //*********************************************************************************
4752 // [private] ParentChangeTellCapabilityDidChange
4753 //
4754 // For root domain to notify capability power-change.
4755 //*********************************************************************************
4756
4757 void IOService::ParentChangeTellCapabilityDidChange ( void )
4758 {
4759 if (!IS_ROOT_DOMAIN)
4760 return ParentChangeAcknowledgePowerChange();
4761
4762 tellSystemCapabilityChange( kIOPM_ParentChangeAcknowledgePowerChange );
4763 }
4764
4765 //*********************************************************************************
4766 // [private] ParentAcknowledgePowerChange
4767 //
4768 // Acknowledge our power parent that our power change is done.
4769 //*********************************************************************************
4770
4771 void IOService::ParentChangeAcknowledgePowerChange ( void )
4772 {
4773 IORegistryEntry * nub;
4774 IOService * parent;
4775
4776 nub = fHeadNoteParentConnection;
4777 nub->retain();
4778 all_done();
4779 parent = (IOService *)nub->copyParentEntry(gIOPowerPlane);
4780 if ( parent )
4781 {
4782 parent->acknowledgePowerChange((IOService *)nub);
4783 parent->release();
4784 }
4785 nub->release();
4786 }
4787
4788 void IOService::ParentChangeCancelIdleTimer( IOPMPowerStateIndex newPowerState )
4789 {
4790 AbsoluteTime now;
4791 uint64_t nsec;
4792 bool cancel = false;
4793
4794 // No ready or idle timer not in use
4795 if (!initialized || !fIdleTimerPeriod || fLockedFlags.PMStop ||
4796 !fAdvisoryTickleUsed)
4797 return;
4798
4799 // Not allowed to induce artifical idle timeout
4800 if (fIdleTimerIgnored || fIdleTimerMinPowerState)
4801 goto done;
4802
4803 // Idle timer already has no influence
4804 if (!fDesiredPowerState || fIdleTimerStopped)
4805 goto done;
4806
4807 IOLockLock(fActivityLock);
4808
4809 if (!fDeviceWasActive)
4810 {
4811 // No tickles since the last idle timer expiration.
4812 // Safe to drop the device desire to zero.
4813 cancel = true;
4814 }
4815 else
4816 {
4817 // Was tickled since the last idle timer expiration,
4818 // but not in the last minute.
4819 clock_get_uptime(&now);
4820 SUB_ABSOLUTETIME(&now, &fDeviceActiveTimestamp);
4821 absolutetime_to_nanoseconds(now, &nsec);
4822 if (nsec >= kNoTickleCancelWindow)
4823 {
4824 cancel = true;
4825 }
4826 }
4827
4828 if (cancel)
4829 {
4830 // Force the next tickle to raise power state
4831 fActivityTicklePowerState = kInvalidTicklePowerState;
4832 fDeviceWasActive = false;
4833 }
4834
4835 IOLockUnlock(fActivityLock);
4836
4837 if (cancel)
4838 {
4839 // cancel idle timer
4840 if (fIdleTimer && thread_call_cancel(fIdleTimer))
4841 release();
4842
4843 updatePowerClient(gIOPMPowerClientDevice, 0);
4844 computeDesiredState();
4845
4846 fIdleTimerStopped = true;
4847 }
4848
4849 done:
4850 OUR_PMLog( kPMLogStartParentChange, fHeadNotePowerState, fCurrentPowerState );
4851 PM_LOG("%s::%s cancel=%d\n", fName, __FUNCTION__, cancel);
4852 }
4853
4854 // MARK: -
4855 // MARK: Ack and Settle timers
4856
4857 //*********************************************************************************
4858 // [private] settleTimerExpired
4859 //
4860 // Power has settled after our last change. Notify interested parties that
4861 // there is a new power state.
4862 //*********************************************************************************
4863
4864 void IOService::settleTimerExpired( void )
4865 {
4866 fSettleTimeUS = 0;
4867 gIOPMWorkQueue->signalWorkAvailable();
4868 }
4869
4870 //*********************************************************************************
4871 // settle_timer_expired
4872 //
4873 // Holds a retain while the settle timer callout is in flight.
4874 //*********************************************************************************
4875
4876 static void
4877 settle_timer_expired( thread_call_param_t arg0, thread_call_param_t arg1 )
4878 {
4879 IOService * me = (IOService *) arg0;
4880
4881 if (gIOPMWorkLoop && gIOPMWorkQueue)
4882 {
4883 gIOPMWorkLoop->runAction(
4884 OSMemberFunctionCast(IOWorkLoop::Action, me, &IOService::settleTimerExpired),
4885 me);
4886 }
4887 me->release();
4888 }
4889
4890 //*********************************************************************************
4891 // [private] startSettleTimer
4892 //
4893 // Calculate a power-settling delay in microseconds and start a timer.
4894 //*********************************************************************************
4895
4896 void IOService::startSettleTimer( void )
4897 {
4898 AbsoluteTime deadline;
4899 IOPMPowerStateIndex i;
4900 uint32_t settleTime = 0;
4901 boolean_t pending;
4902
4903 PM_ASSERT_IN_GATE();
4904
4905 i = fCurrentPowerState;
4906
4907 // lowering power
4908 if ( fHeadNotePowerState < fCurrentPowerState )
4909 {
4910 while ( i > fHeadNotePowerState )
4911 {
4912 settleTime += (uint32_t) fPowerStates[i].settleDownTime;
4913 i--;
4914 }
4915 }
4916
4917 // raising power
4918 if ( fHeadNotePowerState > fCurrentPowerState )
4919 {
4920 while ( i < fHeadNotePowerState )
4921 {
4922 settleTime += (uint32_t) fPowerStates[i+1].settleUpTime;
4923 i++;
4924 }
4925 }
4926
4927 if (settleTime)
4928 {
4929 retain();
4930 clock_interval_to_deadline(settleTime, kMicrosecondScale, &deadline);
4931 pending = thread_call_enter_delayed(fSettleTimer, deadline);
4932 if (pending) release();
4933 }
4934 }
4935
4936 //*********************************************************************************
4937 // [private] ackTimerTick
4938 //
4939 // The acknowledgement timeout periodic timer has ticked.
4940 // If we are awaiting acks for a power change notification,
4941 // we decrement the timer word of each interested driver which hasn't acked.
4942 // If a timer word becomes zero, we pretend the driver aknowledged.
4943 // If we are waiting for the controlling driver to change the power
4944 // state of the hardware, we decrement its timer word, and if it becomes
4945 // zero, we pretend the driver acknowledged.
4946 //
4947 // Returns true if the timer tick made it possible to advance to the next
4948 // machine state, false otherwise.
4949 //*********************************************************************************
4950
4951 #ifndef __LP64__
4952 void IOService::ack_timer_ticked ( void )
4953 {
4954 assert(false);
4955 }
4956 #endif /* !__LP64__ */
4957
4958 bool IOService::ackTimerTick( void )
4959 {
4960 IOPMinformee * nextObject;
4961 bool done = false;
4962
4963 PM_ASSERT_IN_GATE();
4964 switch (fMachineState) {
4965 case kIOPM_OurChangeWaitForPowerSettle:
4966 case kIOPM_ParentChangeWaitForPowerSettle:
4967 // are we waiting for controlling driver to acknowledge?
4968 if ( fDriverTimer > 0 )
4969 {
4970 // yes, decrement timer tick
4971 fDriverTimer--;
4972 if ( fDriverTimer == 0 )
4973 {
4974 // controlling driver is tardy
4975 uint64_t nsec = computeTimeDeltaNS(&fDriverCallStartTime);
4976 OUR_PMLog(kPMLogCtrlDriverTardy, 0, 0);
4977 setProperty(kIOPMTardyAckSPSKey, kOSBooleanTrue);
4978 PM_ERROR("%s::setPowerState(%p, %lu -> %lu) timed out after %d ms\n",
4979 fName, this, fCurrentPowerState, fHeadNotePowerState, NS_TO_MS(nsec));
4980
4981 #if LOG_SETPOWER_TIMES
4982 PMEventDetails *details = PMEventDetails::eventDetails(
4983 kIOPMEventTypeSetPowerStateDelayed, // type
4984 fName, // who
4985 (uintptr_t)this, // owner unique
4986 NULL, // interest name
4987 (uint8_t)getPowerState(), // old
4988 0, // new
4989 kIOReturnTimeout, // result
4990 NS_TO_US(nsec)); // usec completion time
4991
4992 getPMRootDomain()->recordAndReleasePMEventGated( details );
4993 #endif
4994
4995 if (gIOKitDebug & kIOLogDebugPower)
4996 {
4997 panic("%s::setPowerState(%p, %lu -> %lu) timed out after %d ms",
4998 fName, this, fCurrentPowerState, fHeadNotePowerState, NS_TO_MS(nsec));
4999 }
5000 else
5001 {
5002 // Unblock state machine and pretend driver has acked.
5003 done = true;
5004 }
5005 } else {
5006 // still waiting, set timer again
5007 start_ack_timer();
5008 }
5009 }
5010 break;
5011
5012 case kIOPM_NotifyChildrenStart:
5013 // are we waiting for interested parties to acknowledge?
5014 if ( fHeadNotePendingAcks != 0 )
5015 {
5016 // yes, go through the list of interested drivers
5017 nextObject = fInterestedDrivers->firstInList();
5018 // and check each one
5019 while ( nextObject != NULL )
5020 {
5021 if ( nextObject->timer > 0 )
5022 {
5023 nextObject->timer--;
5024 // this one should have acked by now
5025 if ( nextObject->timer == 0 )
5026 {
5027 uint64_t nsec = computeTimeDeltaNS(&nextObject->startTime);
5028 OUR_PMLog(kPMLogIntDriverTardy, 0, 0);
5029 nextObject->whatObject->setProperty(kIOPMTardyAckPSCKey, kOSBooleanTrue);
5030 PM_ERROR("%s::powerState%sChangeTo(%p, %s, %lu -> %lu) timed out after %d ms\n",
5031 nextObject->whatObject->getName(),
5032 (fDriverCallReason == kDriverCallInformPreChange) ? "Will" : "Did",
5033 nextObject->whatObject, fName, fCurrentPowerState, fHeadNotePowerState,
5034 NS_TO_MS(nsec));
5035
5036 #if LOG_SETPOWER_TIMES
5037 uint16_t logType = (fDriverCallReason == kDriverCallInformPreChange)
5038 ? kIOPMEventTypePSWillChangeTo
5039 : kIOPMEventTypePSDidChangeTo;
5040
5041 PMEventDetails *details = PMEventDetails::eventDetails(
5042 logType, // type
5043 fName, // who
5044 (uintptr_t)this, // owner unique
5045 nextObject->whatObject->getName(), // interest name
5046 (uint8_t)fCurrentPowerState, // old
5047 (uint8_t)fHeadNotePowerState, // new
5048 kIOReturnTimeout, // result
5049 NS_TO_US(nsec)); // usec completion time
5050
5051 getPMRootDomain()->recordAndReleasePMEventGated( details );
5052 #endif
5053
5054 // Pretend driver has acked.
5055 fHeadNotePendingAcks--;
5056 }
5057 }
5058 nextObject = fInterestedDrivers->nextInList(nextObject);
5059 }
5060
5061 // is that the last?
5062 if ( fHeadNotePendingAcks == 0 )
5063 {
5064 // yes, we can continue
5065 done = true;
5066 } else {
5067 // no, set timer again
5068 start_ack_timer();
5069 }
5070 }
5071 break;
5072
5073 // TODO: aggreggate this
5074 case kIOPM_OurChangeTellClientsPowerDown:
5075 case kIOPM_OurChangeTellPriorityClientsPowerDown:
5076 case kIOPM_OurChangeNotifyInterestedDriversWillChange:
5077 case kIOPM_ParentChangeTellPriorityClientsPowerDown:
5078 case kIOPM_ParentChangeNotifyInterestedDriversWillChange:
5079 case kIOPM_SyncTellClientsPowerDown:
5080 case kIOPM_SyncTellPriorityClientsPowerDown:
5081 case kIOPM_SyncNotifyWillChange:
5082 case kIOPM_TellCapabilityChangeDone:
5083 // apps didn't respond in time
5084 cleanClientResponses(true);
5085 OUR_PMLog(kPMLogClientTardy, 0, 1);
5086 // tardy equates to approval
5087 done = true;
5088 break;
5089
5090 default:
5091 PM_LOG1("%s: unexpected ack timer tick (state = %d)\n",
5092 getName(), fMachineState);
5093 break;
5094 }
5095 return done;
5096 }
5097
5098 //*********************************************************************************
5099 // [private] start_ack_timer
5100 //*********************************************************************************
5101
5102 void IOService::start_ack_timer ( void )
5103 {
5104 start_ack_timer( ACK_TIMER_PERIOD, kNanosecondScale );
5105 }
5106
5107 void IOService::start_ack_timer ( UInt32 interval, UInt32 scale )
5108 {
5109 AbsoluteTime deadline;
5110 boolean_t pending;
5111
5112 clock_interval_to_deadline(interval, scale, &deadline);
5113
5114 retain();
5115 pending = thread_call_enter_delayed(fAckTimer, deadline);
5116 if (pending) release();
5117 }
5118
5119 //*********************************************************************************
5120 // [private] stop_ack_timer
5121 //*********************************************************************************
5122
5123 void IOService::stop_ack_timer ( void )
5124 {
5125 boolean_t pending;
5126
5127 pending = thread_call_cancel(fAckTimer);
5128 if (pending) release();
5129 }
5130
5131 //*********************************************************************************
5132 // [static] actionAckTimerExpired
5133 //
5134 // Inside PM work loop's gate.
5135 //*********************************************************************************
5136
5137 IOReturn
5138 IOService::actionAckTimerExpired (
5139 OSObject * target,
5140 void * arg0, void * arg1,
5141 void * arg2, void * arg3 )
5142 {
5143 IOService * me = (IOService *) target;
5144 bool done;
5145
5146 // done will be true if the timer tick unblocks the machine state,
5147 // otherwise no need to signal the work loop.
5148
5149 done = me->ackTimerTick();
5150 if (done && gIOPMWorkQueue)
5151 gIOPMWorkQueue->signalWorkAvailable();
5152
5153 return kIOReturnSuccess;
5154 }
5155
5156 //*********************************************************************************
5157 // ack_timer_expired
5158 //
5159 // Thread call function. Holds a retain while the callout is in flight.
5160 //*********************************************************************************
5161
5162 void
5163 IOService::ack_timer_expired ( thread_call_param_t arg0, thread_call_param_t arg1 )
5164 {
5165 IOService * me = (IOService *) arg0;
5166
5167 if (gIOPMWorkLoop)
5168 {
5169 gIOPMWorkLoop->runAction(&actionAckTimerExpired, me);
5170 }
5171 me->release();
5172 }
5173
5174 // MARK: -
5175 // MARK: Client Messaging
5176
5177 //*********************************************************************************
5178 // [private] tellSystemCapabilityChange
5179 //*********************************************************************************
5180
5181 void IOService::tellSystemCapabilityChange( uint32_t nextMS )
5182 {
5183 MS_PUSH( nextMS );
5184 fMachineState = kIOPM_TellCapabilityChangeDone;
5185 fOutOfBandMessage = kIOMessageSystemCapabilityChange;
5186
5187 if (fIsPreChange)
5188 {
5189 // Notify app first on pre-change.
5190 fOutOfBandParameter = kNotifyCapabilityChangeApps;
5191 }
5192 else
5193 {
5194 // Notify kernel clients first on post-change.
5195 fOutOfBandParameter = kNotifyCapabilityChangePriority;
5196 }
5197
5198 tellClientsWithResponse( fOutOfBandMessage );
5199 }
5200
5201 //*********************************************************************************
5202 // [public] askChangeDown
5203 //
5204 // Ask registered applications and kernel clients if we can change to a lower
5205 // power state.
5206 //
5207 // Subclass can override this to send a different message type. Parameter is
5208 // the destination state number.
5209 //
5210 // Return true if we don't have to wait for acknowledgements
5211 //*********************************************************************************
5212
5213 bool IOService::askChangeDown ( unsigned long stateNum )
5214 {
5215 return tellClientsWithResponse( kIOMessageCanDevicePowerOff );
5216 }
5217
5218 //*********************************************************************************
5219 // [private] tellChangeDown1
5220 //
5221 // Notify registered applications and kernel clients that we are definitely
5222 // dropping power.
5223 //
5224 // Return true if we don't have to wait for acknowledgements
5225 //*********************************************************************************
5226
5227 bool IOService::tellChangeDown1 ( unsigned long stateNum )
5228 {
5229 fOutOfBandParameter = kNotifyApps;
5230 return tellChangeDown(stateNum);
5231 }
5232
5233 //*********************************************************************************
5234 // [private] tellChangeDown2
5235 //
5236 // Notify priority clients that we are definitely dropping power.
5237 //
5238 // Return true if we don't have to wait for acknowledgements
5239 //*********************************************************************************
5240
5241 bool IOService::tellChangeDown2 ( unsigned long stateNum )
5242 {
5243 fOutOfBandParameter = kNotifyPriority;
5244 return tellChangeDown(stateNum);
5245 }
5246
5247 //*********************************************************************************
5248 // [public] tellChangeDown
5249 //
5250 // Notify registered applications and kernel clients that we are definitely
5251 // dropping power.
5252 //
5253 // Subclass can override this to send a different message type. Parameter is
5254 // the destination state number.
5255 //
5256 // Return true if we don't have to wait for acknowledgements
5257 //*********************************************************************************
5258
5259 bool IOService::tellChangeDown ( unsigned long stateNum )
5260 {
5261 return tellClientsWithResponse( kIOMessageDeviceWillPowerOff );
5262 }
5263
5264 //*********************************************************************************
5265 // cleanClientResponses
5266 //
5267 //*********************************************************************************
5268
5269 static void logAppTimeouts ( OSObject * object, void * arg )
5270 {
5271 IOPMInterestContext * context = (IOPMInterestContext *) arg;
5272 OSObject * flag;
5273 unsigned int clientIndex;
5274
5275 if (OSDynamicCast(_IOServiceInterestNotifier, object))
5276 {
5277 // Discover the 'counter' value or index assigned to this client
5278 // when it was notified, by searching for the array index of the
5279 // client in an array holding the cached interested clients.
5280
5281 clientIndex = context->notifyClients->getNextIndexOfObject(object, 0);
5282
5283 if ((clientIndex != (unsigned int) -1) &&
5284 (flag = context->responseArray->getObject(clientIndex)) &&
5285 (flag != kOSBooleanTrue))
5286 {
5287 OSString *logClientID = NULL;
5288 OSNumber *clientID = copyClientIDForNotification(object, context);
5289
5290 if (clientID) {
5291 logClientID = IOCopyLogNameForPID(clientID->unsigned32BitValue());
5292 clientID->release();
5293 }
5294
5295 PM_ERROR(context->errorLog, logClientID ? logClientID->getCStringNoCopy() : "");
5296
5297 // TODO: record message type if possible
5298 IOService::getPMRootDomain()->pmStatsRecordApplicationResponse(
5299 gIOPMStatsApplicationResponseTimedOut,
5300 logClientID ? logClientID->getCStringNoCopy() : "",
5301 0, (30*1000), -1);
5302
5303 if (logClientID)
5304 logClientID->release();
5305 }
5306 }
5307 }
5308
5309 void IOService::cleanClientResponses ( bool logErrors )
5310 {
5311 if (logErrors && fResponseArray)
5312 {
5313 switch ( fOutOfBandParameter ) {
5314 case kNotifyApps:
5315 case kNotifyCapabilityChangeApps:
5316 if (fNotifyClientArray)
5317 {
5318 IOPMInterestContext context;
5319
5320 context.responseArray = fResponseArray;
5321 context.notifyClients = fNotifyClientArray;
5322 context.serialNumber = fSerialNumber;
5323 context.messageType = kIOMessageCopyClientID;
5324 context.notifyType = kNotifyApps;
5325 context.isPreChange = fIsPreChange;
5326 context.enableTracing = false;
5327 context.us = this;
5328 context.maxTimeRequested = 0;
5329 context.stateNumber = fHeadNotePowerState;
5330 context.stateFlags = fHeadNotePowerArrayEntry->capabilityFlags;
5331 context.changeFlags = fHeadNoteChangeFlags;
5332 context.errorLog = "PM notification timeout (%s)\n";
5333
5334 applyToInterested(gIOAppPowerStateInterest, logAppTimeouts, (void *) &context);
5335 }
5336 break;
5337
5338 default:
5339 // kNotifyPriority, kNotifyCapabilityChangePriority
5340 // TODO: identify the priority client that has not acked
5341 PM_ERROR("PM priority notification timeout\n");
5342 if (gIOKitDebug & kIOLogDebugPower)
5343 {
5344 panic("PM priority notification timeout");
5345 }
5346 break;
5347 }
5348 }
5349
5350 if (fResponseArray)
5351 {
5352 fResponseArray->release();
5353 fResponseArray = NULL;
5354 }
5355 if (fNotifyClientArray)
5356 {
5357 fNotifyClientArray->release();
5358 fNotifyClientArray = NULL;
5359 }
5360 }
5361
5362 //*********************************************************************************
5363 // [protected] tellClientsWithResponse
5364 //
5365 // Notify registered applications and kernel clients that we are definitely
5366 // dropping power.
5367 //
5368 // Return true if we don't have to wait for acknowledgements
5369 //*********************************************************************************
5370
5371 bool IOService::tellClientsWithResponse ( int messageType )
5372 {
5373 IOPMInterestContext context;
5374 bool isRootDomain = IS_ROOT_DOMAIN;
5375
5376 PM_ASSERT_IN_GATE();
5377 assert( fResponseArray == NULL );
5378 assert( fNotifyClientArray == NULL );
5379
5380 RD_LOG("tellClientsWithResponse( %s, %d )\n",
5381 getIOMessageString(messageType), fOutOfBandParameter);
5382
5383 fResponseArray = OSArray::withCapacity( 1 );
5384 if (!fResponseArray)
5385 goto exit;
5386
5387 fResponseArray->setCapacityIncrement(8);
5388 if (++fSerialNumber == 0)
5389 fSerialNumber++;
5390
5391 context.responseArray = fResponseArray;
5392 context.notifyClients = 0;
5393 context.serialNumber = fSerialNumber;
5394 context.messageType = messageType;
5395 context.notifyType = fOutOfBandParameter;
5396 context.isPreChange = fIsPreChange;
5397 context.enableTracing = false;
5398 context.us = this;
5399 context.maxTimeRequested = 0;
5400 context.stateNumber = fHeadNotePowerState;
5401 context.stateFlags = fHeadNotePowerArrayEntry->capabilityFlags;
5402 context.changeFlags = fHeadNoteChangeFlags;
5403 context.messageFilter = (isRootDomain) ?
5404 OSMemberFunctionCast(
5405 IOPMMessageFilter,
5406 this,
5407 &IOPMrootDomain::systemMessageFilter) : 0;
5408
5409 switch ( fOutOfBandParameter ) {
5410 case kNotifyApps:
5411 applyToInterested( gIOAppPowerStateInterest,
5412 pmTellAppWithResponse, (void *) &context );
5413
5414 if (isRootDomain &&
5415 (fMachineState != kIOPM_OurChangeTellClientsPowerDown) &&
5416 (fMachineState != kIOPM_SyncTellClientsPowerDown))
5417 {
5418 // Notify capability app for tellChangeDown1()
5419 // but not for askChangeDown().
5420 context.notifyType = kNotifyCapabilityChangeApps;
5421 context.messageType = kIOMessageSystemCapabilityChange;
5422 applyToInterested( gIOAppPowerStateInterest,
5423 pmTellCapabilityAppWithResponse, (void *) &context );
5424 context.notifyType = fOutOfBandParameter;
5425 context.messageType = messageType;
5426 }
5427 context.maxTimeRequested = k30Seconds;
5428
5429 applyToInterested( gIOGeneralInterest,
5430 pmTellClientWithResponse, (void *) &context );
5431
5432 fNotifyClientArray = context.notifyClients;
5433 break;
5434
5435 case kNotifyPriority:
5436 context.enableTracing = isRootDomain;
5437 applyToInterested( gIOPriorityPowerStateInterest,
5438 pmTellClientWithResponse, (void *) &context );
5439
5440 if (isRootDomain)
5441 {
5442 // Notify capability clients for tellChangeDown2().
5443 context.notifyType = kNotifyCapabilityChangePriority;
5444 context.messageType = kIOMessageSystemCapabilityChange;
5445 applyToInterested( gIOPriorityPowerStateInterest,
5446 pmTellCapabilityClientWithResponse, (void *) &context );
5447 }
5448 break;
5449
5450 case kNotifyCapabilityChangeApps:
5451 applyToInterested( gIOAppPowerStateInterest,
5452 pmTellCapabilityAppWithResponse, (void *) &context );
5453 fNotifyClientArray = context.notifyClients;
5454 context.maxTimeRequested = k30Seconds;
5455 break;
5456
5457 case kNotifyCapabilityChangePriority:
5458 applyToInterested( gIOPriorityPowerStateInterest,
5459 pmTellCapabilityClientWithResponse, (void *) &context );
5460 break;
5461 }
5462
5463 // do we have to wait for somebody?
5464 if ( !checkForDone() )
5465 {
5466 OUR_PMLog(kPMLogStartAckTimer, context.maxTimeRequested, 0);
5467 if (context.enableTracing)
5468 getPMRootDomain()->traceDetail( context.maxTimeRequested / 1000 );
5469 start_ack_timer( context.maxTimeRequested / 1000, kMillisecondScale );
5470 return false;
5471 }
5472
5473 exit:
5474 // everybody responded
5475 if (fResponseArray)
5476 {
5477 fResponseArray->release();
5478 fResponseArray = NULL;
5479 }
5480 if (fNotifyClientArray)
5481 {
5482 fNotifyClientArray->release();
5483 fNotifyClientArray = NULL;
5484 }
5485
5486 return true;
5487 }
5488
5489 //*********************************************************************************
5490 // [static private] pmTellAppWithResponse
5491 //
5492 // We send a message to an application, and we expect a response, so we compute a
5493 // cookie we can identify the response with.
5494 //*********************************************************************************
5495
5496 void IOService::pmTellAppWithResponse ( OSObject * object, void * arg )
5497 {
5498 IOPMInterestContext * context = (IOPMInterestContext *) arg;
5499 IOServicePM * pwrMgt = context->us->pwrMgt;
5500 uint32_t msgIndex, msgRef, msgType;
5501 OSNumber *clientID = NULL;
5502 proc_t proc = NULL;
5503 boolean_t proc_suspended = FALSE;
5504 #if LOG_APP_RESPONSE_TIMES
5505 AbsoluteTime now;
5506 #endif
5507
5508 if (!OSDynamicCast(_IOServiceInterestNotifier, object))
5509 return;
5510
5511 if (context->us == getPMRootDomain())
5512 {
5513 if ((clientID = copyClientIDForNotification(object, context)))
5514 {
5515 uint32_t clientPID = clientID->unsigned32BitValue();
5516 clientID->release();
5517 proc = proc_find(clientPID);
5518
5519 if (proc)
5520 {
5521 proc_suspended = get_task_pidsuspended((task_t) proc->task);
5522 proc_rele(proc);
5523
5524 if (proc_suspended)
5525 {
5526 logClientIDForNotification(object, context, "PMTellAppWithResponse - Suspended");
5527 return;
5528 }
5529 }
5530 }
5531 }
5532
5533 if (context->messageFilter &&
5534 !context->messageFilter(context->us, object, context, 0, 0))
5535 {
5536 if (kIOLogDebugPower & gIOKitDebug)
5537 {
5538 logClientIDForNotification(object, context, "DROP App");
5539 }
5540 return;
5541 }
5542
5543 // Create client array (for tracking purposes) only if the service
5544 // has app clients. Usually only root domain does.
5545 if (0 == context->notifyClients)
5546 context->notifyClients = OSArray::withCapacity( 32 );
5547
5548 msgType = context->messageType;
5549 msgIndex = context->responseArray->getCount();
5550 msgRef = ((context->serialNumber & 0xFFFF) << 16) + (msgIndex & 0xFFFF);
5551
5552 OUR_PMLog(kPMLogAppNotify, msgType, msgRef);
5553 if (kIOLogDebugPower & gIOKitDebug)
5554 {
5555 logClientIDForNotification(object, context, "MESG App");
5556 }
5557
5558 #if LOG_APP_RESPONSE_TIMES
5559 OSNumber * num;
5560 clock_get_uptime(&now);
5561 num = OSNumber::withNumber(AbsoluteTime_to_scalar(&now), sizeof(uint64_t) * 8);
5562 if (num)
5563 {
5564 context->responseArray->setObject(msgIndex, num);
5565 num->release();
5566 }
5567 else
5568 #endif
5569 context->responseArray->setObject(msgIndex, kOSBooleanFalse);
5570
5571 if (context->notifyClients)
5572 context->notifyClients->setObject(msgIndex, object);
5573
5574 context->us->messageClient(msgType, object, (void *) msgRef);
5575 }
5576
5577 //*********************************************************************************
5578 // [static private] pmTellClientWithResponse
5579 //
5580 // We send a message to an in-kernel client, and we expect a response,
5581 // so we compute a cookie we can identify the response with.
5582 //*********************************************************************************
5583
5584 void IOService::pmTellClientWithResponse ( OSObject * object, void * arg )
5585 {
5586 IOPowerStateChangeNotification notify;
5587 IOPMInterestContext * context = (IOPMInterestContext *) arg;
5588 OSObject * replied = kOSBooleanTrue;
5589 _IOServiceInterestNotifier * notifier;
5590 uint32_t msgIndex, msgRef, msgType;
5591 IOReturn retCode;
5592
5593 if (context->messageFilter &&
5594 !context->messageFilter(context->us, object, context, 0, 0))
5595 {
5596 if ((kIOLogDebugPower & gIOKitDebug) &&
5597 (OSDynamicCast(_IOServiceInterestNotifier, object)))
5598 {
5599 _IOServiceInterestNotifier *n = (_IOServiceInterestNotifier *) object;
5600 PM_LOG("%s DROP Client %s, notifier %p, handler %p\n",
5601 context->us->getName(),
5602 getIOMessageString(context->messageType),
5603 object, n->handler);
5604 }
5605 return;
5606 }
5607
5608 notifier = OSDynamicCast(_IOServiceInterestNotifier, object);
5609 msgType = context->messageType;
5610 msgIndex = context->responseArray->getCount();
5611 msgRef = ((context->serialNumber & 0xFFFF) << 16) + (msgIndex & 0xFFFF);
5612
5613 IOServicePM * pwrMgt = context->us->pwrMgt;
5614 if (gIOKitDebug & kIOLogPower) {
5615 OUR_PMLog(kPMLogClientNotify, msgRef, msgType);
5616 if (OSDynamicCast(IOService, object)) {
5617 const char *who = ((IOService *) object)->getName();
5618 gPlatform->PMLog(who, kPMLogClientNotify, (uintptr_t) object, 0);
5619 }
5620 else if (notifier) {
5621 OUR_PMLog(kPMLogClientNotify, (uintptr_t) notifier->handler, 0);
5622 }
5623 }
5624 if ((kIOLogDebugPower & gIOKitDebug) && notifier)
5625 {
5626 PM_LOG("%s MESG Client %s, notifier %p, handler %p\n",
5627 context->us->getName(),
5628 getIOMessageString(msgType),
5629 object, notifier->handler);
5630 }
5631
5632 notify.powerRef = (void *)(uintptr_t) msgRef;
5633 notify.returnValue = 0;
5634 notify.stateNumber = context->stateNumber;
5635 notify.stateFlags = context->stateFlags;
5636
5637 if (context->enableTracing && (notifier != 0))
5638 {
5639 uint32_t detail = ((msgIndex & 0xff) << 24) |
5640 ((msgType & 0xfff) << 12) |
5641 (((uintptr_t) notifier->handler) & 0xfff);
5642 getPMRootDomain()->traceDetail( detail );
5643 }
5644
5645 retCode = context->us->messageClient(msgType, object, (void *) &notify, sizeof(notify));
5646
5647 if (kIOReturnSuccess == retCode)
5648 {
5649 if (0 == notify.returnValue) {
5650 OUR_PMLog(kPMLogClientAcknowledge, msgRef, (uintptr_t) object);
5651 } else {
5652 replied = kOSBooleanFalse;
5653 if ( notify.returnValue > context->maxTimeRequested )
5654 {
5655 if (notify.returnValue > kPriorityClientMaxWait)
5656 {
5657 context->maxTimeRequested = kPriorityClientMaxWait;
5658 PM_ERROR("%s: client %p returned %llu for %s\n",
5659 context->us->getName(),
5660 notifier ? (void *) notifier->handler : object,
5661 (uint64_t) notify.returnValue,
5662 getIOMessageString(msgType));
5663 }
5664 else
5665 context->maxTimeRequested = notify.returnValue;
5666 }
5667 }
5668 } else {
5669 // not a client of ours
5670 // so we won't be waiting for response
5671 OUR_PMLog(kPMLogClientAcknowledge, msgRef, 0);
5672 }
5673
5674 context->responseArray->setObject(msgIndex, replied);
5675 }
5676
5677 //*********************************************************************************
5678 // [static private] pmTellCapabilityAppWithResponse
5679 //*********************************************************************************
5680
5681 void IOService::pmTellCapabilityAppWithResponse ( OSObject * object, void * arg )
5682 {
5683 IOPMSystemCapabilityChangeParameters msgArg;
5684 IOPMInterestContext * context = (IOPMInterestContext *) arg;
5685 OSObject * replied = kOSBooleanTrue;
5686 IOServicePM * pwrMgt = context->us->pwrMgt;
5687 uint32_t msgIndex, msgRef, msgType;
5688 #if LOG_APP_RESPONSE_TIMES
5689 AbsoluteTime now;
5690 #endif
5691
5692 if (!OSDynamicCast(_IOServiceInterestNotifier, object))
5693 return;
5694
5695 memset(&msgArg, 0, sizeof(msgArg));
5696 if (context->messageFilter &&
5697 !context->messageFilter(context->us, object, context, &msgArg, &replied))
5698 {
5699 return;
5700 }
5701
5702 // Create client array (for tracking purposes) only if the service
5703 // has app clients. Usually only root domain does.
5704 if (0 == context->notifyClients)
5705 context->notifyClients = OSArray::withCapacity( 32 );
5706
5707 msgType = context->messageType;
5708 msgIndex = context->responseArray->getCount();
5709 msgRef = ((context->serialNumber & 0xFFFF) << 16) + (msgIndex & 0xFFFF);
5710
5711 OUR_PMLog(kPMLogAppNotify, msgType, msgRef);
5712 if (kIOLogDebugPower & gIOKitDebug)
5713 {
5714 // Log client pid/name and client array index.
5715 OSNumber * clientID = NULL;
5716 OSString * clientIDString = NULL;;
5717 context->us->messageClient(kIOMessageCopyClientID, object, &clientID);
5718 if (clientID) {
5719 clientIDString = IOCopyLogNameForPID(clientID->unsigned32BitValue());
5720 }
5721
5722 PM_LOG("%s MESG App(%u) %s, wait %u, %s\n",
5723 context->us->getName(),
5724 msgIndex, getIOMessageString(msgType),
5725 (replied != kOSBooleanTrue),
5726 clientIDString ? clientIDString->getCStringNoCopy() : "");
5727 if (clientID) clientID->release();
5728 if (clientIDString) clientIDString->release();
5729 }
5730
5731 msgArg.notifyRef = msgRef;
5732 msgArg.maxWaitForReply = 0;
5733
5734 if (replied == kOSBooleanTrue)
5735 {
5736 msgArg.notifyRef = 0;
5737 context->responseArray->setObject(msgIndex, kOSBooleanTrue);
5738 if (context->notifyClients)
5739 context->notifyClients->setObject(msgIndex, kOSBooleanTrue);
5740 }
5741 else
5742 {
5743 #if LOG_APP_RESPONSE_TIMES
5744 OSNumber * num;
5745 clock_get_uptime(&now);
5746 num = OSNumber::withNumber(AbsoluteTime_to_scalar(&now), sizeof(uint64_t) * 8);
5747 if (num)
5748 {
5749 context->responseArray->setObject(msgIndex, num);
5750 num->release();
5751 }
5752 else
5753 #endif
5754 context->responseArray->setObject(msgIndex, kOSBooleanFalse);
5755
5756 if (context->notifyClients)
5757 context->notifyClients->setObject(msgIndex, object);
5758 }
5759
5760 context->us->messageClient(msgType, object, (void *) &msgArg, sizeof(msgArg));
5761 }
5762
5763 //*********************************************************************************
5764 // [static private] pmTellCapabilityClientWithResponse
5765 //*********************************************************************************
5766
5767 void IOService::pmTellCapabilityClientWithResponse(
5768 OSObject * object, void * arg )
5769 {
5770 IOPMSystemCapabilityChangeParameters msgArg;
5771 IOPMInterestContext * context = (IOPMInterestContext *) arg;
5772 OSObject * replied = kOSBooleanTrue;
5773 _IOServiceInterestNotifier * notifier;
5774 uint32_t msgIndex, msgRef, msgType;
5775 IOReturn retCode;
5776
5777 memset(&msgArg, 0, sizeof(msgArg));
5778 if (context->messageFilter &&
5779 !context->messageFilter(context->us, object, context, &msgArg, 0))
5780 {
5781 if ((kIOLogDebugPower & gIOKitDebug) &&
5782 (OSDynamicCast(_IOServiceInterestNotifier, object)))
5783 {
5784 _IOServiceInterestNotifier *n = (_IOServiceInterestNotifier *) object;
5785 PM_LOG("%s DROP Client %s, notifier %p, handler %p\n",
5786 context->us->getName(),
5787 getIOMessageString(context->messageType),
5788 object, n->handler);
5789 }
5790 return;
5791 }
5792
5793 notifier = OSDynamicCast(_IOServiceInterestNotifier, object);
5794 msgType = context->messageType;
5795 msgIndex = context->responseArray->getCount();
5796 msgRef = ((context->serialNumber & 0xFFFF) << 16) + (msgIndex & 0xFFFF);
5797
5798 IOServicePM * pwrMgt = context->us->pwrMgt;
5799 if (gIOKitDebug & kIOLogPower) {
5800 OUR_PMLog(kPMLogClientNotify, msgRef, msgType);
5801 if (OSDynamicCast(IOService, object)) {
5802 const char *who = ((IOService *) object)->getName();
5803 gPlatform->PMLog(who, kPMLogClientNotify, (uintptr_t) object, 0);
5804 }
5805 else if (notifier) {
5806 OUR_PMLog(kPMLogClientNotify, (uintptr_t) notifier->handler, 0);
5807 }
5808 }
5809 if ((kIOLogDebugPower & gIOKitDebug) && notifier)
5810 {
5811 PM_LOG("%s MESG Client %s, notifier %p, handler %p\n",
5812 context->us->getName(),
5813 getIOMessageString(msgType),
5814 object, notifier->handler);
5815 }
5816
5817 msgArg.notifyRef = msgRef;
5818 msgArg.maxWaitForReply = 0;
5819
5820 if (context->enableTracing && (notifier != 0))
5821 {
5822 uint32_t detail = ((msgIndex & 0xff) << 24) |
5823 ((msgType & 0xfff) << 12) |
5824 (((uintptr_t) notifier->handler) & 0xfff);
5825 getPMRootDomain()->traceDetail( detail );
5826 }
5827
5828 retCode = context->us->messageClient(
5829 msgType, object, (void *) &msgArg, sizeof(msgArg));
5830
5831 if ( kIOReturnSuccess == retCode )
5832 {
5833 if ( 0 == msgArg.maxWaitForReply )
5834 {
5835 // client doesn't want time to respond
5836 OUR_PMLog(kPMLogClientAcknowledge, msgRef, (uintptr_t) object);
5837 }
5838 else
5839 {
5840 replied = kOSBooleanFalse;
5841 if ( msgArg.maxWaitForReply > context->maxTimeRequested )
5842 {
5843 if (msgArg.maxWaitForReply > kCapabilityClientMaxWait)
5844 {
5845 context->maxTimeRequested = kCapabilityClientMaxWait;
5846 PM_ERROR("%s: client %p returned %u for %s\n",
5847 context->us->getName(),
5848 notifier ? (void *) notifier->handler : object,
5849 msgArg.maxWaitForReply,
5850 getIOMessageString(msgType));
5851 }
5852 else
5853 context->maxTimeRequested = msgArg.maxWaitForReply;
5854 }
5855 }
5856 }
5857 else
5858 {
5859 // not a client of ours
5860 // so we won't be waiting for response
5861 OUR_PMLog(kPMLogClientAcknowledge, msgRef, 0);
5862 }
5863
5864 context->responseArray->setObject(msgIndex, replied);
5865 }
5866
5867 //*********************************************************************************
5868 // [public] tellNoChangeDown
5869 //
5870 // Notify registered applications and kernel clients that we are not
5871 // dropping power.
5872 //
5873 // Subclass can override this to send a different message type. Parameter is
5874 // the aborted destination state number.
5875 //*********************************************************************************
5876
5877 void IOService::tellNoChangeDown ( unsigned long )
5878 {
5879 return tellClients( kIOMessageDeviceWillNotPowerOff );
5880 }
5881
5882 //*********************************************************************************
5883 // [public] tellChangeUp
5884 //
5885 // Notify registered applications and kernel clients that we are raising power.
5886 //
5887 // Subclass can override this to send a different message type. Parameter is
5888 // the aborted destination state number.
5889 //*********************************************************************************
5890
5891 void IOService::tellChangeUp ( unsigned long )
5892 {
5893 return tellClients( kIOMessageDeviceHasPoweredOn );
5894 }
5895
5896 //*********************************************************************************
5897 // [protected] tellClients
5898 //
5899 // Notify registered applications and kernel clients of something.
5900 //*********************************************************************************
5901
5902 void IOService::tellClients ( int messageType )
5903 {
5904 IOPMInterestContext context;
5905
5906 RD_LOG("tellClients( %s )\n", getIOMessageString(messageType));
5907
5908 memset(&context, 0, sizeof(context));
5909 context.messageType = messageType;
5910 context.isPreChange = fIsPreChange;
5911 context.us = this;
5912 context.stateNumber = fHeadNotePowerState;
5913 context.stateFlags = fHeadNotePowerArrayEntry->capabilityFlags;
5914 context.changeFlags = fHeadNoteChangeFlags;
5915 context.messageFilter = (IS_ROOT_DOMAIN) ?
5916 OSMemberFunctionCast(
5917 IOPMMessageFilter,
5918 this,
5919 &IOPMrootDomain::systemMessageFilter) : 0;
5920
5921 context.notifyType = kNotifyPriority;
5922 applyToInterested( gIOPriorityPowerStateInterest,
5923 tellKernelClientApplier, (void *) &context );
5924
5925 context.notifyType = kNotifyApps;
5926 applyToInterested( gIOAppPowerStateInterest,
5927 tellAppClientApplier, (void *) &context );
5928
5929 applyToInterested( gIOGeneralInterest,
5930 tellKernelClientApplier, (void *) &context );
5931 }
5932
5933 //*********************************************************************************
5934 // [private] tellKernelClientApplier
5935 //
5936 // Message a kernel client.
5937 //*********************************************************************************
5938
5939 static void tellKernelClientApplier ( OSObject * object, void * arg )
5940 {
5941 IOPowerStateChangeNotification notify;
5942 IOPMInterestContext * context = (IOPMInterestContext *) arg;
5943
5944 if (context->messageFilter &&
5945 !context->messageFilter(context->us, object, context, 0, 0))
5946 {
5947 if ((kIOLogDebugPower & gIOKitDebug) &&
5948 (OSDynamicCast(_IOServiceInterestNotifier, object)))
5949 {
5950 _IOServiceInterestNotifier *n = (_IOServiceInterestNotifier *) object;
5951 PM_LOG("%s DROP Client %s, notifier %p, handler %p\n",
5952 context->us->getName(),
5953 IOService::getIOMessageString(context->messageType),
5954 object, n->handler);
5955 }
5956 return;
5957 }
5958
5959 notify.powerRef = (void *) 0;
5960 notify.returnValue = 0;
5961 notify.stateNumber = context->stateNumber;
5962 notify.stateFlags = context->stateFlags;
5963
5964 context->us->messageClient(context->messageType, object, &notify, sizeof(notify));
5965
5966 if ((kIOLogDebugPower & gIOKitDebug) &&
5967 (OSDynamicCast(_IOServiceInterestNotifier, object)))
5968 {
5969 _IOServiceInterestNotifier *n = (_IOServiceInterestNotifier *) object;
5970 PM_LOG("%s MESG Client %s, notifier %p, handler %p\n",
5971 context->us->getName(),
5972 IOService::getIOMessageString(context->messageType),
5973 object, n->handler);
5974 }
5975 }
5976
5977 static OSNumber * copyClientIDForNotification(
5978 OSObject *object,
5979 IOPMInterestContext *context)
5980 {
5981 OSNumber *clientID = NULL;
5982 context->us->messageClient(kIOMessageCopyClientID, object, &clientID);
5983 return clientID;
5984 }
5985
5986 static void logClientIDForNotification(
5987 OSObject *object,
5988 IOPMInterestContext *context,
5989 const char *logString)
5990 {
5991 OSString *logClientID = NULL;
5992 OSNumber *clientID = copyClientIDForNotification(object, context);
5993
5994 if (logString)
5995 {
5996 if (clientID)
5997 logClientID = IOCopyLogNameForPID(clientID->unsigned32BitValue());
5998
5999 PM_LOG("%s %s %s, %s\n",
6000 context->us->getName(), logString,
6001 IOService::getIOMessageString(context->messageType),
6002 logClientID ? logClientID->getCStringNoCopy() : "");
6003
6004 if (logClientID)
6005 logClientID->release();
6006 }
6007
6008 if (clientID)
6009 clientID->release();
6010
6011 return;
6012 }
6013
6014
6015 static void tellAppClientApplier ( OSObject * object, void * arg )
6016 {
6017 IOPMInterestContext * context = (IOPMInterestContext *) arg;
6018 OSNumber * clientID = NULL;
6019 proc_t proc = NULL;
6020 boolean_t proc_suspended = FALSE;
6021
6022 if (context->us == IOService::getPMRootDomain())
6023 {
6024 if ((clientID = copyClientIDForNotification(object, context)))
6025 {
6026 uint32_t clientPID = clientID->unsigned32BitValue();
6027 clientID->release();
6028 proc = proc_find(clientPID);
6029
6030 if (proc)
6031 {
6032 proc_suspended = get_task_pidsuspended((task_t) proc->task);
6033 proc_rele(proc);
6034
6035 if (proc_suspended)
6036 {
6037 logClientIDForNotification(object, context, "tellAppClientApplier - Suspended");
6038 return;
6039 }
6040 }
6041 }
6042 }
6043
6044 if (context->messageFilter &&
6045 !context->messageFilter(context->us, object, context, 0, 0))
6046 {
6047 if (kIOLogDebugPower & gIOKitDebug)
6048 {
6049 logClientIDForNotification(object, context, "DROP App");
6050 }
6051 return;
6052 }
6053
6054 if (kIOLogDebugPower & gIOKitDebug)
6055 {
6056 logClientIDForNotification(object, context, "MESG App");
6057 }
6058
6059 context->us->messageClient(context->messageType, object, 0);
6060 }
6061
6062 //*********************************************************************************
6063 // [private] checkForDone
6064 //*********************************************************************************
6065
6066 bool IOService::checkForDone ( void )
6067 {
6068 int i = 0;
6069 OSObject * theFlag;
6070
6071 if (fResponseArray == NULL) {
6072 return true;
6073 }
6074
6075 for (i = 0; ; i++) {
6076 theFlag = fResponseArray->getObject(i);
6077
6078 if (NULL == theFlag) {
6079 break;
6080 }
6081
6082 if (kOSBooleanTrue != theFlag) {
6083 return false;
6084 }
6085 }
6086 return true;
6087 }
6088
6089 //*********************************************************************************
6090 // [public] responseValid
6091 //*********************************************************************************
6092
6093 bool IOService::responseValid ( uint32_t refcon, int pid )
6094 {
6095 UInt16 serialComponent;
6096 UInt16 ordinalComponent;
6097 OSObject * theFlag;
6098
6099 serialComponent = (refcon >> 16) & 0xFFFF;
6100 ordinalComponent = (refcon & 0xFFFF);
6101
6102 if ( serialComponent != fSerialNumber )
6103 {
6104 return false;
6105 }
6106
6107 if ( fResponseArray == NULL )
6108 {
6109 return false;
6110 }
6111
6112 theFlag = fResponseArray->getObject(ordinalComponent);
6113
6114 if ( theFlag == 0 )
6115 {
6116 return false;
6117 }
6118
6119 OSNumber * num;
6120 if ((num = OSDynamicCast(OSNumber, theFlag)))
6121 {
6122 #if LOG_APP_RESPONSE_TIMES
6123 AbsoluteTime now;
6124 AbsoluteTime start;
6125 uint64_t nsec;
6126 OSString *name = IOCopyLogNameForPID(pid);
6127
6128 clock_get_uptime(&now);
6129 AbsoluteTime_to_scalar(&start) = num->unsigned64BitValue();
6130 SUB_ABSOLUTETIME(&now, &start);
6131 absolutetime_to_nanoseconds(now, &nsec);
6132
6133 PMEventDetails *details = PMEventDetails::eventDetails(
6134 kIOPMEventTypeAppResponse, // type
6135 name ? name->getCStringNoCopy() : "", // who
6136 (uintptr_t)pid, // owner unique
6137 NULL, // interest name
6138 0, // old
6139 0, // new
6140 0, // result
6141 NS_TO_US(nsec)); // usec completion time
6142
6143 getPMRootDomain()->recordAndReleasePMEventGated( details );
6144
6145 if (kIOLogDebugPower & gIOKitDebug)
6146 {
6147 PM_LOG("Ack(%u) %u ms\n",
6148 (uint32_t) ordinalComponent,
6149 NS_TO_MS(nsec));
6150 }
6151
6152 // > 100 ms
6153 if (nsec > LOG_APP_RESPONSE_TIMES)
6154 {
6155 PM_LOG("PM response took %d ms (%s)\n", NS_TO_MS(nsec),
6156 name ? name->getCStringNoCopy() : "");
6157
6158 if (nsec > LOG_APP_RESPONSE_MSG_TRACER)
6159 {
6160 // TODO: populate the messageType argument
6161 getPMRootDomain()->pmStatsRecordApplicationResponse(
6162 gIOPMStatsApplicationResponseSlow,
6163 name ? name->getCStringNoCopy() : "", 0,
6164 NS_TO_MS(nsec), pid);
6165 }
6166 }
6167
6168 if (name)
6169 name->release();
6170 #endif
6171 theFlag = kOSBooleanFalse;
6172 }
6173
6174 if ( kOSBooleanFalse == theFlag )
6175 {
6176 fResponseArray->replaceObject(ordinalComponent, kOSBooleanTrue);
6177 }
6178
6179 return true;
6180 }
6181
6182 //*********************************************************************************
6183 // [public] allowPowerChange
6184 //
6185 // Our power state is about to lower, and we have notified applications
6186 // and kernel clients, and one of them has acknowledged. If this is the last to do
6187 // so, and all acknowledgements are positive, we continue with the power change.
6188 //*********************************************************************************
6189
6190 IOReturn IOService::allowPowerChange ( unsigned long refcon )
6191 {
6192 IOPMRequest * request;
6193
6194 if ( !initialized )
6195 {
6196 // we're unloading
6197 return kIOReturnSuccess;
6198 }
6199
6200 request = acquirePMRequest( this, kIOPMRequestTypeAllowPowerChange );
6201 if (!request)
6202 return kIOReturnNoMemory;
6203
6204 request->fArg0 = (void *) refcon;
6205 request->fArg1 = (void *) proc_selfpid();
6206 request->fArg2 = (void *) 0;
6207 submitPMRequest( request );
6208
6209 return kIOReturnSuccess;
6210 }
6211
6212 #ifndef __LP64__
6213 IOReturn IOService::serializedAllowPowerChange2 ( unsigned long refcon )
6214 {
6215 // [deprecated] public
6216 return kIOReturnUnsupported;
6217 }
6218 #endif /* !__LP64__ */
6219
6220 //*********************************************************************************
6221 // [public] cancelPowerChange
6222 //
6223 // Our power state is about to lower, and we have notified applications
6224 // and kernel clients, and one of them has vetoed the change. If this is the last
6225 // client to respond, we abandon the power change.
6226 //*********************************************************************************
6227
6228 IOReturn IOService::cancelPowerChange ( unsigned long refcon )
6229 {
6230 IOPMRequest * request;
6231 OSString * name;
6232
6233 if ( !initialized )
6234 {
6235 // we're unloading
6236 return kIOReturnSuccess;
6237 }
6238
6239 name = IOCopyLogNameForPID(proc_selfpid());
6240 PM_ERROR("PM notification cancel (%s)\n", name ? name->getCStringNoCopy() : "");
6241
6242 request = acquirePMRequest( this, kIOPMRequestTypeCancelPowerChange );
6243 if (!request)
6244 {
6245 if (name)
6246 name->release();
6247 return kIOReturnNoMemory;
6248 }
6249
6250 request->fArg0 = (void *) refcon;
6251 request->fArg1 = (void *) proc_selfpid();
6252 request->fArg2 = (void *) name;
6253 submitPMRequest( request );
6254
6255 return kIOReturnSuccess;
6256 }
6257
6258 #ifndef __LP64__
6259 IOReturn IOService::serializedCancelPowerChange2 ( unsigned long refcon )
6260 {
6261 // [deprecated] public
6262 return kIOReturnUnsupported;
6263 }
6264
6265 //*********************************************************************************
6266 // PM_Clamp_Timer_Expired
6267 //
6268 // called when clamp timer expires...set power state to 0.
6269 //*********************************************************************************
6270
6271 void IOService::PM_Clamp_Timer_Expired ( void )
6272 {
6273 }
6274
6275 //*********************************************************************************
6276 // clampPowerOn
6277 //
6278 // Set to highest available power state for a minimum of duration milliseconds
6279 //*********************************************************************************
6280
6281 void IOService::clampPowerOn ( unsigned long duration )
6282 {
6283 }
6284 #endif /* !__LP64__ */
6285
6286 // MARK: -
6287 // MARK: Driver Overrides
6288
6289 //*********************************************************************************
6290 // [public] setPowerState
6291 //
6292 // Does nothing here. This should be implemented in a subclass driver.
6293 //*********************************************************************************
6294
6295 IOReturn IOService::setPowerState (
6296 unsigned long powerStateOrdinal, IOService * whatDevice )
6297 {
6298 return IOPMNoErr;
6299 }
6300
6301 //*********************************************************************************
6302 // [public] maxCapabilityForDomainState
6303 //
6304 // Finds the highest power state in the array whose input power
6305 // requirement is equal to the input parameter. Where a more intelligent
6306 // decision is possible, override this in the subclassed driver.
6307 //*********************************************************************************
6308
6309 unsigned long IOService::maxCapabilityForDomainState ( IOPMPowerFlags domainState )
6310 {
6311 int i;
6312
6313 if (fNumberOfPowerStates == 0 )
6314 {
6315 return 0;
6316 }
6317 for ( i = fNumberOfPowerStates - 1; i >= 0; i-- )
6318 {
6319 if ( (domainState & fPowerStates[i].inputPowerFlags) ==
6320 fPowerStates[i].inputPowerFlags )
6321 {
6322 return i;
6323 }
6324 }
6325 return 0;
6326 }
6327
6328 //*********************************************************************************
6329 // [public] initialPowerStateForDomainState
6330 //
6331 // Finds the highest power state in the array whose input power
6332 // requirement is equal to the input parameter. Where a more intelligent
6333 // decision is possible, override this in the subclassed driver.
6334 //*********************************************************************************
6335
6336 unsigned long IOService::initialPowerStateForDomainState ( IOPMPowerFlags domainState )
6337 {
6338 int i;
6339
6340 if (fNumberOfPowerStates == 0 )
6341 {
6342 return 0;
6343 }
6344 for ( i = fNumberOfPowerStates - 1; i >= 0; i-- )
6345 {
6346 if ( (domainState & fPowerStates[i].inputPowerFlags) ==
6347 fPowerStates[i].inputPowerFlags )
6348 {
6349 return i;
6350 }
6351 }
6352 return 0;
6353 }
6354
6355 //*********************************************************************************
6356 // [public] powerStateForDomainState
6357 //
6358 // Finds the highest power state in the array whose input power
6359 // requirement is equal to the input parameter. Where a more intelligent
6360 // decision is possible, override this in the subclassed driver.
6361 //*********************************************************************************
6362
6363 unsigned long IOService::powerStateForDomainState ( IOPMPowerFlags domainState )
6364 {
6365 int i;
6366
6367 if (fNumberOfPowerStates == 0 )
6368 {
6369 return 0;
6370 }
6371 for ( i = fNumberOfPowerStates - 1; i >= 0; i-- )
6372 {
6373 if ( (domainState & fPowerStates[i].inputPowerFlags) ==
6374 fPowerStates[i].inputPowerFlags )
6375 {
6376 return i;
6377 }
6378 }
6379 return 0;
6380 }
6381
6382 #ifndef __LP64__
6383 //*********************************************************************************
6384 // [deprecated] didYouWakeSystem
6385 //
6386 // Does nothing here. This should be implemented in a subclass driver.
6387 //*********************************************************************************
6388
6389 bool IOService::didYouWakeSystem ( void )
6390 {
6391 return false;
6392 }
6393 #endif /* !__LP64__ */
6394
6395 //*********************************************************************************
6396 // [public] powerStateWillChangeTo
6397 //
6398 // Does nothing here. This should be implemented in a subclass driver.
6399 //*********************************************************************************
6400
6401 IOReturn IOService::powerStateWillChangeTo ( IOPMPowerFlags, unsigned long, IOService * )
6402 {
6403 return kIOPMAckImplied;
6404 }
6405
6406 //*********************************************************************************
6407 // [public] powerStateDidChangeTo
6408 //
6409 // Does nothing here. This should be implemented in a subclass driver.
6410 //*********************************************************************************
6411
6412 IOReturn IOService::powerStateDidChangeTo ( IOPMPowerFlags, unsigned long, IOService * )
6413 {
6414 return kIOPMAckImplied;
6415 }
6416
6417 //*********************************************************************************
6418 // [protected] powerChangeDone
6419 //
6420 // Called from PM work loop thread.
6421 // Does nothing here. This should be implemented in a subclass policy-maker.
6422 //*********************************************************************************
6423
6424 void IOService::powerChangeDone ( unsigned long )
6425 {
6426 }
6427
6428 #ifndef __LP64__
6429 //*********************************************************************************
6430 // [deprecated] newTemperature
6431 //
6432 // Does nothing here. This should be implemented in a subclass driver.
6433 //*********************************************************************************
6434
6435 IOReturn IOService::newTemperature ( long currentTemp, IOService * whichZone )
6436 {
6437 return IOPMNoErr;
6438 }
6439 #endif /* !__LP64__ */
6440
6441 //*********************************************************************************
6442 // [public] systemWillShutdown
6443 //
6444 // System shutdown and restart notification.
6445 //*********************************************************************************
6446
6447 void IOService::systemWillShutdown( IOOptionBits specifier )
6448 {
6449 IOPMrootDomain * rootDomain = IOService::getPMRootDomain();
6450 if (rootDomain)
6451 rootDomain->acknowledgeSystemWillShutdown( this );
6452 }
6453
6454 // MARK: -
6455 // MARK: PM State Machine
6456
6457 //*********************************************************************************
6458 // [private static] acquirePMRequest
6459 //*********************************************************************************
6460
6461 IOPMRequest *
6462 IOService::acquirePMRequest( IOService * target, IOOptionBits requestType,
6463 IOPMRequest * active )
6464 {
6465 IOPMRequest * request;
6466
6467 assert(target);
6468
6469 request = IOPMRequest::create();
6470 if (request)
6471 {
6472 request->init( target, requestType );
6473 if (active)
6474 {
6475 IOPMRequest * root = active->getRootRequest();
6476 if (root) request->attachRootRequest(root);
6477 }
6478 }
6479 else
6480 {
6481 PM_ERROR("%s: No memory for PM request type 0x%x\n",
6482 target->getName(), (uint32_t) requestType);
6483 }
6484 return request;
6485 }
6486
6487 //*********************************************************************************
6488 // [private static] releasePMRequest
6489 //*********************************************************************************
6490
6491 void IOService::releasePMRequest( IOPMRequest * request )
6492 {
6493 if (request)
6494 {
6495 request->reset();
6496 request->release();
6497 }
6498 }
6499
6500 //*********************************************************************************
6501 // [private] submitPMRequest
6502 //*********************************************************************************
6503
6504 void IOService::submitPMRequest( IOPMRequest * request )
6505 {
6506 assert( request );
6507 assert( gIOPMReplyQueue );
6508 assert( gIOPMRequestQueue );
6509
6510 PM_LOG1("[+ %02lx] %p [%p %s] %p %p %p\n",
6511 (long)request->getType(), request,
6512 request->getTarget(), request->getTarget()->getName(),
6513 request->fArg0, request->fArg1, request->fArg2);
6514
6515 if (request->isReplyType())
6516 gIOPMReplyQueue->queuePMRequest( request );
6517 else
6518 gIOPMRequestQueue->queuePMRequest( request );
6519 }
6520
6521 void IOService::submitPMRequest( IOPMRequest ** requests, IOItemCount count )
6522 {
6523 assert( requests );
6524 assert( count > 0 );
6525 assert( gIOPMRequestQueue );
6526
6527 for (IOItemCount i = 0; i < count; i++)
6528 {
6529 IOPMRequest * req = requests[i];
6530 PM_LOG1("[+ %02lx] %p [%p %s] %p %p %p\n",
6531 (long)req->getType(), req,
6532 req->getTarget(), req->getTarget()->getName(),
6533 req->fArg0, req->fArg1, req->fArg2);
6534 }
6535
6536 gIOPMRequestQueue->queuePMRequestChain( requests, count );
6537 }
6538
6539 //*********************************************************************************
6540 // [private] servicePMRequestQueue
6541 //
6542 // Called from IOPMRequestQueue::checkForWork().
6543 //*********************************************************************************
6544
6545 bool IOService::servicePMRequestQueue(
6546 IOPMRequest * request,
6547 IOPMRequestQueue * queue )
6548 {
6549 bool more;
6550
6551 if (initialized)
6552 {
6553 // Work queue will immediately execute the queue'd request if possible.
6554 // If execution blocks, the work queue will wait for a producer signal.
6555 // Only need to signal more when completing attached requests.
6556
6557 more = gIOPMWorkQueue->queuePMRequest(request, pwrMgt);
6558 return more;
6559 }
6560
6561 // Calling PM without PMinit() is not allowed, fail the request.
6562
6563 PM_LOG("%s: PM not initialized\n", getName());
6564 fAdjustPowerScheduled = false;
6565 more = gIOPMFreeQueue->queuePMRequest(request);
6566 if (more) gIOPMWorkQueue->incrementProducerCount();
6567 return more;
6568 }
6569
6570 //*********************************************************************************
6571 // [private] servicePMFreeQueue
6572 //
6573 // Called from IOPMCompletionQueue::checkForWork().
6574 //*********************************************************************************
6575
6576 bool IOService::servicePMFreeQueue(
6577 IOPMRequest * request,
6578 IOPMCompletionQueue * queue )
6579 {
6580 bool more = request->getNextRequest();
6581 IOPMRequest * root = request->getRootRequest();
6582
6583 if (root && (root != request))
6584 more = true;
6585 if (more)
6586 gIOPMWorkQueue->incrementProducerCount();
6587
6588 releasePMRequest( request );
6589 return more;
6590 }
6591
6592 //*********************************************************************************
6593 // [private] retirePMRequest
6594 //
6595 // Called by IOPMWorkQueue to retire a completed request.
6596 //*********************************************************************************
6597
6598 bool IOService::retirePMRequest( IOPMRequest * request, IOPMWorkQueue * queue )
6599 {
6600 assert(request && queue);
6601
6602 PM_LOG1("[- %02x] %p [%p %s] state %d, busy %d\n",
6603 request->getType(), request, this, getName(),
6604 fMachineState, gIOPMBusyCount);
6605
6606 // Catch requests created by idleTimerExpired().
6607
6608 if ((request->getType() == kIOPMRequestTypeActivityTickle) &&
6609 (request->fArg1 == (void *) false))
6610 {
6611 // Idle timer expiration - power drop request completed.
6612 // Restart the idle timer if deviceDesire can go lower, otherwise set
6613 // a flag so we know to restart idle timer when fDeviceDesire > 0.
6614
6615 if (fDeviceDesire > 0)
6616 {
6617 fActivityTickleCount = 0;
6618 clock_get_uptime(&fIdleTimerStartTime);
6619 start_PM_idle_timer();
6620 }
6621 else if (fHasAdvisoryDesire)
6622 {
6623 start_PM_idle_timer();
6624 }
6625 else
6626 {
6627 fIdleTimerStopped = true;
6628 }
6629 }
6630
6631 // If the request is linked, then Work queue has already incremented its
6632 // producer count.
6633
6634 return (gIOPMFreeQueue->queuePMRequest( request ));
6635 }
6636
6637 //*********************************************************************************
6638 // [private] isPMBlocked
6639 //
6640 // Check if machine state transition is blocked.
6641 //*********************************************************************************
6642
6643 bool IOService::isPMBlocked ( IOPMRequest * request, int count )
6644 {
6645 int reason = 0;
6646
6647 do {
6648 if (kIOPM_Finished == fMachineState)
6649 break;
6650
6651 if (kIOPM_DriverThreadCallDone == fMachineState)
6652 {
6653 // 5 = kDriverCallInformPreChange
6654 // 6 = kDriverCallInformPostChange
6655 // 7 = kDriverCallSetPowerState
6656 if (fDriverCallBusy)
6657 reason = 5 + fDriverCallReason;
6658 break;
6659 }
6660
6661 // Waiting on driver's setPowerState() timeout.
6662 if (fDriverTimer)
6663 {
6664 reason = 1; break;
6665 }
6666
6667 // Child or interested driver acks pending.
6668 if (fHeadNotePendingAcks)
6669 {
6670 reason = 2; break;
6671 }
6672
6673 // Waiting on apps or priority power interest clients.
6674 if (fResponseArray)
6675 {
6676 reason = 3; break;
6677 }
6678
6679 // Waiting on settle timer expiration.
6680 if (fSettleTimeUS)
6681 {
6682 reason = 4; break;
6683 }
6684 } while (false);
6685
6686 fWaitReason = reason;
6687
6688 if (reason)
6689 {
6690 if (count)
6691 {
6692 PM_LOG1("[B %02x] %p [%p %s] state %d, reason %d\n",
6693 request->getType(), request, this, getName(),
6694 fMachineState, reason);
6695 }
6696
6697 return true;
6698 }
6699
6700 return false;
6701 }
6702
6703 //*********************************************************************************
6704 // [private] servicePMRequest
6705 //
6706 // Service a request from our work queue.
6707 //*********************************************************************************
6708
6709 bool IOService::servicePMRequest( IOPMRequest * request, IOPMWorkQueue * queue )
6710 {
6711 bool done = false;
6712 int loop = 0;
6713
6714 assert(request && queue);
6715
6716 while (isPMBlocked(request, loop++) == false)
6717 {
6718 PM_LOG1("[W %02x] %p [%p %s] state %d\n",
6719 request->getType(), request, this, getName(), fMachineState);
6720
6721 gIOPMRequest = request;
6722 gIOPMWorkCount++;
6723
6724 // Every PM machine states must be handled in one of the cases below.
6725
6726 switch ( fMachineState )
6727 {
6728 case kIOPM_Finished:
6729 executePMRequest( request );
6730 break;
6731
6732 case kIOPM_OurChangeTellClientsPowerDown:
6733 // Root domain might self cancel due to assertions.
6734 if (IS_ROOT_DOMAIN)
6735 {
6736 bool cancel = (bool) fDoNotPowerDown;
6737 getPMRootDomain()->askChangeDownDone(
6738 &fHeadNoteChangeFlags, &cancel);
6739 fDoNotPowerDown = cancel;
6740 }
6741
6742 // askChangeDown() done, was it vetoed?
6743 if (!fDoNotPowerDown)
6744 {
6745 if (IS_ROOT_DOMAIN) {
6746 PMEventDetails *details = PMEventDetails::eventDetails(
6747 kIOPMEventTypeAppNotificationsFinished,
6748 NULL,
6749 0,
6750 0);
6751
6752 getPMRootDomain()->recordAndReleasePMEventGated( details );
6753 }
6754
6755 // no, we can continue
6756 OurChangeTellClientsPowerDown();
6757 }
6758 else
6759 {
6760 if (IS_ROOT_DOMAIN) {
6761 PMEventDetails *details = PMEventDetails::eventDetails(
6762 kIOPMEventTypeSleepDone,
6763 NULL,
6764 1, /* reason: 1 == Ask clients succeeded */
6765 kIOReturnAborted); /* result */
6766
6767 getPMRootDomain()->recordAndReleasePMEventGated( details );
6768 }
6769
6770 OUR_PMLog(kPMLogIdleCancel, (uintptr_t) this, fMachineState);
6771 PM_ERROR("%s: idle cancel\n", fName);
6772 // yes, rescind the warning
6773 tellNoChangeDown(fHeadNotePowerState);
6774 // mark the change note un-actioned
6775 fHeadNoteChangeFlags |= kIOPMNotDone;
6776 // and we're done
6777 OurChangeFinish();
6778 }
6779 break;
6780
6781 case kIOPM_OurChangeTellPriorityClientsPowerDown:
6782 // tellChangeDown(kNotifyApps) done, was it cancelled?
6783 if (fDoNotPowerDown)
6784 {
6785 if (IS_ROOT_DOMAIN) {
6786 PMEventDetails *details = PMEventDetails::eventDetails(
6787 kIOPMEventTypeSleepDone,
6788 NULL,
6789 2, /* reason: 2 == Client cancelled wake */
6790 kIOReturnAborted); /* result */
6791
6792 getPMRootDomain()->recordAndReleasePMEventGated( details );
6793 }
6794 OUR_PMLog(kPMLogIdleCancel, (uintptr_t) this, fMachineState);
6795 PM_ERROR("%s: idle revert\n", fName);
6796 // no, tell clients we're back in the old state
6797 tellChangeUp(fCurrentPowerState);
6798 // mark the change note un-actioned
6799 fHeadNoteChangeFlags |= kIOPMNotDone;
6800 // and we're done
6801 OurChangeFinish();
6802 }
6803 else
6804 {
6805 if (IS_ROOT_DOMAIN) {
6806 PMEventDetails *details = PMEventDetails::eventDetails(
6807 kIOPMEventTypeAppNotificationsFinished,
6808 NULL,
6809 2, /* reason: 2 == TellPriorityClientsDone */
6810 kIOReturnSuccess); /* result */
6811
6812 getPMRootDomain()->recordAndReleasePMEventGated( details );
6813 }
6814 // yes, we can continue
6815 OurChangeTellPriorityClientsPowerDown();
6816 }
6817 break;
6818
6819 case kIOPM_OurChangeNotifyInterestedDriversWillChange:
6820 OurChangeNotifyInterestedDriversWillChange();
6821 break;
6822
6823 case kIOPM_OurChangeSetPowerState:
6824 OurChangeSetPowerState();
6825 break;
6826
6827 case kIOPM_OurChangeWaitForPowerSettle:
6828 OurChangeWaitForPowerSettle();
6829 break;
6830
6831 case kIOPM_OurChangeNotifyInterestedDriversDidChange:
6832 OurChangeNotifyInterestedDriversDidChange();
6833 break;
6834
6835 case kIOPM_OurChangeTellCapabilityDidChange:
6836 OurChangeTellCapabilityDidChange();
6837 break;
6838
6839 case kIOPM_OurChangeFinish:
6840 OurChangeFinish();
6841 break;
6842
6843 case kIOPM_ParentChangeTellPriorityClientsPowerDown:
6844 ParentChangeTellPriorityClientsPowerDown();
6845 break;
6846
6847 case kIOPM_ParentChangeNotifyInterestedDriversWillChange:
6848 ParentChangeNotifyInterestedDriversWillChange();
6849 break;
6850
6851 case kIOPM_ParentChangeSetPowerState:
6852 ParentChangeSetPowerState();
6853 break;
6854
6855 case kIOPM_ParentChangeWaitForPowerSettle:
6856 ParentChangeWaitForPowerSettle();
6857 break;
6858
6859 case kIOPM_ParentChangeNotifyInterestedDriversDidChange:
6860 ParentChangeNotifyInterestedDriversDidChange();
6861 break;
6862
6863 case kIOPM_ParentChangeTellCapabilityDidChange:
6864 ParentChangeTellCapabilityDidChange();
6865 break;
6866
6867 case kIOPM_ParentChangeAcknowledgePowerChange:
6868 ParentChangeAcknowledgePowerChange();
6869 break;
6870
6871 case kIOPM_DriverThreadCallDone:
6872 if (fDriverCallReason == kDriverCallSetPowerState)
6873 notifyControllingDriverDone();
6874 else
6875 notifyInterestedDriversDone();
6876 break;
6877
6878 case kIOPM_NotifyChildrenOrdered:
6879 notifyChildrenOrdered();
6880 break;
6881
6882 case kIOPM_NotifyChildrenDelayed:
6883 notifyChildrenDelayed();
6884 break;
6885
6886 case kIOPM_NotifyChildrenStart:
6887 PM_LOG2("%s: kIOPM_NotifyChildrenStart done\n", getName());
6888 MS_POP(); // from notifyInterestedDriversDone()
6889 notifyChildren();
6890 break;
6891
6892 case kIOPM_SyncTellClientsPowerDown:
6893 // Root domain might self cancel due to assertions.
6894 if (IS_ROOT_DOMAIN)
6895 {
6896 bool cancel = (bool) fDoNotPowerDown;
6897 getPMRootDomain()->askChangeDownDone(
6898 &fHeadNoteChangeFlags, &cancel);
6899 fDoNotPowerDown = cancel;
6900 }
6901 if (!fDoNotPowerDown)
6902 {
6903 fMachineState = kIOPM_SyncTellPriorityClientsPowerDown;
6904 fOutOfBandParameter = kNotifyApps;
6905 tellChangeDown(fHeadNotePowerState);
6906 }
6907 else
6908 {
6909 OUR_PMLog(kPMLogIdleCancel, (uintptr_t) this, fMachineState);
6910 PM_ERROR("%s: idle cancel\n", fName);
6911 tellNoChangeDown(fHeadNotePowerState);
6912 fHeadNoteChangeFlags |= kIOPMNotDone;
6913 OurChangeFinish();
6914 }
6915 break;
6916
6917 case kIOPM_SyncTellPriorityClientsPowerDown:
6918 if (!fDoNotPowerDown)
6919 {
6920 fMachineState = kIOPM_SyncNotifyWillChange;
6921 fOutOfBandParameter = kNotifyPriority;
6922 tellChangeDown(fHeadNotePowerState);
6923 }
6924 else
6925 {
6926 OUR_PMLog(kPMLogIdleCancel, (uintptr_t) this, fMachineState);
6927 PM_ERROR("%s: idle revert\n", fName);
6928 tellChangeUp(fCurrentPowerState);
6929 fHeadNoteChangeFlags |= kIOPMNotDone;
6930 OurChangeFinish();
6931 }
6932 break;
6933
6934 case kIOPM_SyncNotifyWillChange:
6935 if (kIOPMSyncNoChildNotify & fHeadNoteChangeFlags)
6936 {
6937 fMachineState = kIOPM_SyncFinish;
6938 continue;
6939 }
6940 fMachineState = kIOPM_SyncNotifyDidChange;
6941 fDriverCallReason = kDriverCallInformPreChange;
6942 notifyChildren();
6943 break;
6944
6945 case kIOPM_SyncNotifyDidChange:
6946 fIsPreChange = false;
6947
6948 if (fHeadNoteChangeFlags & kIOPMParentInitiated)
6949 fMachineState = kIOPM_SyncFinish;
6950 else
6951 fMachineState = kIOPM_SyncTellCapabilityDidChange;
6952
6953 fDriverCallReason = kDriverCallInformPostChange;
6954 notifyChildren();
6955 break;
6956
6957 case kIOPM_SyncTellCapabilityDidChange:
6958 tellSystemCapabilityChange( kIOPM_SyncFinish );
6959 break;
6960
6961 case kIOPM_SyncFinish:
6962 if (fHeadNoteChangeFlags & kIOPMParentInitiated)
6963 ParentChangeAcknowledgePowerChange();
6964 else
6965 OurChangeFinish();
6966 break;
6967
6968 case kIOPM_TellCapabilityChangeDone:
6969 if (fIsPreChange)
6970 {
6971 if (fOutOfBandParameter == kNotifyCapabilityChangePriority)
6972 {
6973 MS_POP(); // tellSystemCapabilityChange()
6974 continue;
6975 }
6976 fOutOfBandParameter = kNotifyCapabilityChangePriority;
6977 }
6978 else
6979 {
6980 if (fOutOfBandParameter == kNotifyCapabilityChangeApps)
6981 {
6982 MS_POP(); // tellSystemCapabilityChange()
6983 continue;
6984 }
6985 fOutOfBandParameter = kNotifyCapabilityChangeApps;
6986 }
6987 tellClientsWithResponse( fOutOfBandMessage );
6988 break;
6989
6990 default:
6991 panic("servicePMWorkQueue: unknown machine state %x",
6992 fMachineState);
6993 }
6994
6995 gIOPMRequest = 0;
6996
6997 if (fMachineState == kIOPM_Finished)
6998 {
6999 done = true;
7000 break;
7001 }
7002 }
7003
7004 return done;
7005 }
7006
7007 //*********************************************************************************
7008 // [private] executePMRequest
7009 //*********************************************************************************
7010
7011 void IOService::executePMRequest( IOPMRequest * request )
7012 {
7013 assert( kIOPM_Finished == fMachineState );
7014
7015 switch (request->getType())
7016 {
7017 case kIOPMRequestTypePMStop:
7018 handlePMstop( request );
7019 break;
7020
7021 case kIOPMRequestTypeAddPowerChild1:
7022 addPowerChild1( request );
7023 break;
7024
7025 case kIOPMRequestTypeAddPowerChild2:
7026 addPowerChild2( request );
7027 break;
7028
7029 case kIOPMRequestTypeAddPowerChild3:
7030 addPowerChild3( request );
7031 break;
7032
7033 case kIOPMRequestTypeRegisterPowerDriver:
7034 handleRegisterPowerDriver( request );
7035 break;
7036
7037 case kIOPMRequestTypeAdjustPowerState:
7038 fAdjustPowerScheduled = false;
7039 adjustPowerState();
7040 break;
7041
7042 case kIOPMRequestTypePowerDomainWillChange:
7043 handlePowerDomainWillChangeTo( request );
7044 break;
7045
7046 case kIOPMRequestTypePowerDomainDidChange:
7047 handlePowerDomainDidChangeTo( request );
7048 break;
7049
7050 case kIOPMRequestTypeRequestPowerState:
7051 case kIOPMRequestTypeRequestPowerStateOverride:
7052 handleRequestPowerState( request );
7053 break;
7054
7055 case kIOPMRequestTypePowerOverrideOnPriv:
7056 case kIOPMRequestTypePowerOverrideOffPriv:
7057 handlePowerOverrideChanged( request );
7058 break;
7059
7060 case kIOPMRequestTypeActivityTickle:
7061 handleActivityTickle( request );
7062 break;
7063
7064 case kIOPMRequestTypeSynchronizePowerTree:
7065 handleSynchronizePowerTree( request );
7066 break;
7067
7068 case kIOPMRequestTypeSetIdleTimerPeriod:
7069 {
7070 fIdleTimerPeriod = (uintptr_t) request->fArg0;
7071
7072 if ((false == fLockedFlags.PMStop) && (fIdleTimerPeriod > 0))
7073 {
7074 fActivityTickleCount = 0;
7075 clock_get_uptime(&fIdleTimerStartTime);
7076 start_PM_idle_timer();
7077 }
7078 }
7079 break;
7080
7081 case kIOPMRequestTypeIgnoreIdleTimer:
7082 fIdleTimerIgnored = request->fArg0 ? 1 : 0;
7083 break;
7084
7085 default:
7086 panic("executePMRequest: unknown request type %x", request->getType());
7087 }
7088 }
7089
7090 //*********************************************************************************
7091 // [private] servicePMReplyQueue
7092 //*********************************************************************************
7093
7094 bool IOService::servicePMReplyQueue( IOPMRequest * request, IOPMRequestQueue * queue )
7095 {
7096 bool more = false;
7097
7098 assert( request && queue );
7099 assert( request->isReplyType() );
7100
7101 PM_LOG1("[A %02x] %p [%p %s] state %d\n",
7102 request->getType(), request, this, getName(), fMachineState);
7103
7104 switch ( request->getType() )
7105 {
7106 case kIOPMRequestTypeAllowPowerChange:
7107 case kIOPMRequestTypeCancelPowerChange:
7108 // Check if we are expecting this response.
7109 if (responseValid((uint32_t)(uintptr_t) request->fArg0,
7110 (int)(uintptr_t) request->fArg1))
7111 {
7112 if (kIOPMRequestTypeCancelPowerChange == request->getType())
7113 {
7114 // Clients are not allowed to cancel when kIOPMSkipAskPowerDown
7115 // flag is set. Only root domain will set this flag.
7116
7117 if ((fHeadNoteChangeFlags & kIOPMSkipAskPowerDown) == 0)
7118 {
7119 fDoNotPowerDown = true;
7120
7121 OSString * name = (OSString *) request->fArg2;
7122 getPMRootDomain()->pmStatsRecordApplicationResponse(
7123 gIOPMStatsApplicationResponseCancel,
7124 name ? name->getCStringNoCopy() : "", 0,
7125 0, (int)(uintptr_t) request->fArg1);
7126 }
7127 }
7128
7129 if (checkForDone())
7130 {
7131 stop_ack_timer();
7132 cleanClientResponses(false);
7133 more = true;
7134 }
7135 }
7136 // OSString containing app name in Arg2 must be released.
7137 if (request->getType() == kIOPMRequestTypeCancelPowerChange)
7138 {
7139 OSObject * obj = (OSObject *) request->fArg2;
7140 if (obj) obj->release();
7141 }
7142 break;
7143
7144 case kIOPMRequestTypeAckPowerChange:
7145 more = handleAcknowledgePowerChange( request );
7146 break;
7147
7148 case kIOPMRequestTypeAckSetPowerState:
7149 if (fDriverTimer == -1)
7150 {
7151 // driver acked while setPowerState() call is in-flight.
7152 // take this ack, return value from setPowerState() is irrelevant.
7153 OUR_PMLog(kPMLogDriverAcknowledgeSet,
7154 (uintptr_t) this, fDriverTimer);
7155 fDriverTimer = 0;
7156 }
7157 else if (fDriverTimer > 0)
7158 {
7159 // expected ack, stop the timer
7160 stop_ack_timer();
7161
7162 #if LOG_SETPOWER_TIMES
7163 uint64_t nsec = computeTimeDeltaNS(&fDriverCallStartTime);
7164 if (nsec > LOG_SETPOWER_TIMES)
7165 PM_LOG("%s::setPowerState(%p, %lu -> %lu) async took %d ms\n",
7166 fName, this, fCurrentPowerState, fHeadNotePowerState, NS_TO_MS(nsec));
7167
7168 PMEventDetails *details = PMEventDetails::eventDetails(
7169 kIOPMEventTypeSetPowerStateDelayed, // type
7170 fName, // who
7171 (uintptr_t)this, // owner unique
7172 NULL, // interest name
7173 (uint8_t)getPowerState(), // old
7174 (uint8_t)fHeadNotePowerState, // new
7175 0, // result
7176 NS_TO_US(nsec)); // usec completion time
7177
7178 getPMRootDomain()->recordAndReleasePMEventGated( details );
7179 #endif
7180 OUR_PMLog(kPMLogDriverAcknowledgeSet, (uintptr_t) this, fDriverTimer);
7181 fDriverTimer = 0;
7182 more = true;
7183 }
7184 else
7185 {
7186 // unexpected ack
7187 OUR_PMLog(kPMLogAcknowledgeErr4, (uintptr_t) this, 0);
7188 }
7189 break;
7190
7191 case kIOPMRequestTypeInterestChanged:
7192 handleInterestChanged( request );
7193 more = true;
7194 break;
7195
7196 case kIOPMRequestTypeIdleCancel:
7197 if ((fMachineState == kIOPM_OurChangeTellClientsPowerDown)
7198 || (fMachineState == kIOPM_OurChangeTellPriorityClientsPowerDown)
7199 || (fMachineState == kIOPM_SyncTellClientsPowerDown)
7200 || (fMachineState == kIOPM_SyncTellPriorityClientsPowerDown))
7201 {
7202 OUR_PMLog(kPMLogIdleCancel, (uintptr_t) this, fMachineState);
7203 PM_LOG2("%s: cancel from machine state %d\n",
7204 getName(), fMachineState);
7205 fDoNotPowerDown = true;
7206 // Stop waiting for app replys.
7207 if ((fMachineState == kIOPM_OurChangeTellPriorityClientsPowerDown) ||
7208 (fMachineState == kIOPM_SyncTellPriorityClientsPowerDown))
7209 cleanClientResponses(false);
7210 more = true;
7211 }
7212 break;
7213
7214 case kIOPMRequestTypeChildNotifyDelayCancel:
7215 if (fMachineState == kIOPM_NotifyChildrenDelayed)
7216 {
7217 PM_LOG2("%s: delay notify cancelled\n", getName());
7218 notifyChildrenDelayed();
7219 }
7220 break;
7221
7222 default:
7223 panic("servicePMReplyQueue: unknown reply type %x",
7224 request->getType());
7225 }
7226
7227 more |= gIOPMFreeQueue->queuePMRequest(request);
7228 if (more)
7229 gIOPMWorkQueue->incrementProducerCount();
7230
7231 return more;
7232 }
7233
7234 //*********************************************************************************
7235 // [private] assertPMDriverCall / deassertPMDriverCall
7236 //*********************************************************************************
7237
7238 bool IOService::assertPMDriverCall(
7239 IOPMDriverCallEntry * entry,
7240 IOOptionBits options,
7241 IOPMinformee * inform )
7242 {
7243 IOService * target = 0;
7244 bool ok = false;
7245
7246 if (!initialized)
7247 return false;
7248
7249 PM_LOCK();
7250
7251 if (fLockedFlags.PMStop)
7252 {
7253 goto fail;
7254 }
7255
7256 if (((options & kIOPMADC_NoInactiveCheck) == 0) && isInactive())
7257 {
7258 goto fail;
7259 }
7260
7261 if (inform)
7262 {
7263 if (!inform->active)
7264 {
7265 goto fail;
7266 }
7267 target = inform->whatObject;
7268 if (target->isInactive())
7269 {
7270 goto fail;
7271 }
7272 }
7273
7274 entry->thread = current_thread();
7275 entry->target = target;
7276 queue_enter(&fPMDriverCallQueue, entry, IOPMDriverCallEntry *, link);
7277 ok = true;
7278
7279 fail:
7280 PM_UNLOCK();
7281
7282 return ok;
7283 }
7284
7285 void IOService::deassertPMDriverCall( IOPMDriverCallEntry * entry )
7286 {
7287 bool wakeup = false;
7288
7289 PM_LOCK();
7290
7291 assert( !queue_empty(&fPMDriverCallQueue) );
7292 queue_remove(&fPMDriverCallQueue, entry, IOPMDriverCallEntry *, link);
7293 if (fLockedFlags.PMDriverCallWait)
7294 {
7295 wakeup = true;
7296 }
7297
7298 PM_UNLOCK();
7299
7300 if (wakeup)
7301 PM_LOCK_WAKEUP(&fPMDriverCallQueue);
7302 }
7303
7304 void IOService::waitForPMDriverCall( IOService * target )
7305 {
7306 const IOPMDriverCallEntry * entry;
7307 thread_t thread = current_thread();
7308 AbsoluteTime deadline;
7309 int waitResult;
7310 bool log = true;
7311 bool wait;
7312
7313 do {
7314 wait = false;
7315 queue_iterate(&fPMDriverCallQueue, entry, const IOPMDriverCallEntry *, link)
7316 {
7317 // Target of interested driver call
7318 if (target && (target != entry->target))
7319 continue;
7320
7321 if (entry->thread == thread)
7322 {
7323 if (log)
7324 {
7325 PM_LOG("%s: %s(%s) on PM thread\n",
7326 fName, __FUNCTION__, target ? target->getName() : "");
7327 OSReportWithBacktrace("%s: %s(%s) on PM thread\n",
7328 fName, __FUNCTION__, target ? target->getName() : "");
7329 log = false;
7330 }
7331 continue;
7332 }
7333
7334 wait = true;
7335 break;
7336 }
7337
7338 if (wait)
7339 {
7340 fLockedFlags.PMDriverCallWait = true;
7341 clock_interval_to_deadline(15, kSecondScale, &deadline);
7342 waitResult = PM_LOCK_SLEEP(&fPMDriverCallQueue, deadline);
7343 fLockedFlags.PMDriverCallWait = false;
7344 if (THREAD_TIMED_OUT == waitResult)
7345 {
7346 PM_ERROR("%s: waitForPMDriverCall timeout\n", fName);
7347 wait = false;
7348 }
7349 }
7350 } while (wait);
7351 }
7352
7353 //*********************************************************************************
7354 // [private] Debug helpers
7355 //*********************************************************************************
7356
7357 const char * IOService::getIOMessageString( uint32_t msg )
7358 {
7359 #define MSG_ENTRY(x) {x, #x}
7360
7361 static const IONamedValue msgNames[] = {
7362 MSG_ENTRY( kIOMessageCanDevicePowerOff ),
7363 MSG_ENTRY( kIOMessageDeviceWillPowerOff ),
7364 MSG_ENTRY( kIOMessageDeviceWillNotPowerOff ),
7365 MSG_ENTRY( kIOMessageDeviceHasPoweredOn ),
7366 MSG_ENTRY( kIOMessageCanSystemPowerOff ),
7367 MSG_ENTRY( kIOMessageSystemWillPowerOff ),
7368 MSG_ENTRY( kIOMessageSystemWillNotPowerOff ),
7369 MSG_ENTRY( kIOMessageCanSystemSleep ),
7370 MSG_ENTRY( kIOMessageSystemWillSleep ),
7371 MSG_ENTRY( kIOMessageSystemWillNotSleep ),
7372 MSG_ENTRY( kIOMessageSystemHasPoweredOn ),
7373 MSG_ENTRY( kIOMessageSystemWillRestart ),
7374 MSG_ENTRY( kIOMessageSystemWillPowerOn ),
7375 MSG_ENTRY( kIOMessageSystemCapabilityChange )
7376 };
7377
7378 return IOFindNameForValue(msg, msgNames);
7379 }
7380
7381 // MARK: -
7382 // MARK: IOPMRequest
7383
7384 //*********************************************************************************
7385 // IOPMRequest Class
7386 //
7387 // Requests from PM clients, and also used for inter-object messaging within PM.
7388 //*********************************************************************************
7389
7390 OSDefineMetaClassAndStructors( IOPMRequest, IOCommand );
7391
7392 IOPMRequest * IOPMRequest::create( void )
7393 {
7394 IOPMRequest * me = OSTypeAlloc(IOPMRequest);
7395 if (me && !me->init(0, kIOPMRequestTypeInvalid))
7396 {
7397 me->release();
7398 me = 0;
7399 }
7400 return me;
7401 }
7402
7403 bool IOPMRequest::init( IOService * target, IOOptionBits type )
7404 {
7405 if (!IOCommand::init())
7406 return false;
7407
7408 fType = type;
7409 fTarget = target;
7410 fCompletionStatus = kIOReturnSuccess;
7411
7412 if (fTarget)
7413 fTarget->retain();
7414
7415 return true;
7416 }
7417
7418 void IOPMRequest::reset( void )
7419 {
7420 assert( fWorkWaitCount == 0 );
7421 assert( fFreeWaitCount == 0 );
7422
7423 detachNextRequest();
7424 detachRootRequest();
7425
7426 fType = kIOPMRequestTypeInvalid;
7427
7428 if (fCompletionAction)
7429 {
7430 fCompletionAction(fCompletionTarget, fCompletionParam, fCompletionStatus);
7431 }
7432
7433 if (fTarget)
7434 {
7435 fTarget->release();
7436 fTarget = 0;
7437 }
7438 }
7439
7440 bool IOPMRequest::attachNextRequest( IOPMRequest * next )
7441 {
7442 bool ok = false;
7443
7444 if (!fRequestNext)
7445 {
7446 // Postpone the execution of the next request after
7447 // this request.
7448 fRequestNext = next;
7449 fRequestNext->fWorkWaitCount++;
7450 #if LOG_REQUEST_ATTACH
7451 kprintf("Attached next: %p [0x%x] -> %p [0x%x, %u] %s\n",
7452 this, (uint32_t) fType, fRequestNext,
7453 (uint32_t) fRequestNext->fType,
7454 (uint32_t) fRequestNext->fWorkWaitCount,
7455 fTarget->getName());
7456 #endif
7457 ok = true;
7458 }
7459 return ok;
7460 }
7461
7462 bool IOPMRequest::detachNextRequest( void )
7463 {
7464 bool ok = false;
7465
7466 if (fRequestNext)
7467 {
7468 assert(fRequestNext->fWorkWaitCount);
7469 if (fRequestNext->fWorkWaitCount)
7470 fRequestNext->fWorkWaitCount--;
7471 #if LOG_REQUEST_ATTACH
7472 kprintf("Detached next: %p [0x%x] -> %p [0x%x, %u] %s\n",
7473 this, (uint32_t) fType, fRequestNext,
7474 (uint32_t) fRequestNext->fType,
7475 (uint32_t) fRequestNext->fWorkWaitCount,
7476 fTarget->getName());
7477 #endif
7478 fRequestNext = 0;
7479 ok = true;
7480 }
7481 return ok;
7482 }
7483
7484 bool IOPMRequest::attachRootRequest( IOPMRequest * root )
7485 {
7486 bool ok = false;
7487
7488 if (!fRequestRoot)
7489 {
7490 // Delay the completion of the root request after
7491 // this request.
7492 fRequestRoot = root;
7493 fRequestRoot->fFreeWaitCount++;
7494 #if LOG_REQUEST_ATTACH
7495 kprintf("Attached root: %p [0x%x] -> %p [0x%x, %u] %s\n",
7496 this, (uint32_t) fType, fRequestRoot,
7497 (uint32_t) fRequestRoot->fType,
7498 (uint32_t) fRequestRoot->fFreeWaitCount,
7499 fTarget->getName());
7500 #endif
7501 ok = true;
7502 }
7503 return ok;
7504 }
7505
7506 bool IOPMRequest::detachRootRequest( void )
7507 {
7508 bool ok = false;
7509
7510 if (fRequestRoot)
7511 {
7512 assert(fRequestRoot->fFreeWaitCount);
7513 if (fRequestRoot->fFreeWaitCount)
7514 fRequestRoot->fFreeWaitCount--;
7515 #if LOG_REQUEST_ATTACH
7516 kprintf("Detached root: %p [0x%x] -> %p [0x%x, %u] %s\n",
7517 this, (uint32_t) fType, fRequestRoot,
7518 (uint32_t) fRequestRoot->fType,
7519 (uint32_t) fRequestRoot->fFreeWaitCount,
7520 fTarget->getName());
7521 #endif
7522 fRequestRoot = 0;
7523 ok = true;
7524 }
7525 return ok;
7526 }
7527
7528 // MARK: -
7529 // MARK: IOPMRequestQueue
7530
7531 //*********************************************************************************
7532 // IOPMRequestQueue Class
7533 //
7534 // Global queues. Queues are created once and never released.
7535 //*********************************************************************************
7536
7537 OSDefineMetaClassAndStructors( IOPMRequestQueue, IOEventSource );
7538
7539 IOPMRequestQueue * IOPMRequestQueue::create( IOService * inOwner, Action inAction )
7540 {
7541 IOPMRequestQueue * me = OSTypeAlloc(IOPMRequestQueue);
7542 if (me && !me->init(inOwner, inAction))
7543 {
7544 me->release();
7545 me = 0;
7546 }
7547 return me;
7548 }
7549
7550 bool IOPMRequestQueue::init( IOService * inOwner, Action inAction )
7551 {
7552 if (!inAction || !IOEventSource::init(inOwner, (IOEventSourceAction)inAction))
7553 return false;
7554
7555 queue_init(&fQueue);
7556 fLock = IOLockAlloc();
7557 return (fLock != 0);
7558 }
7559
7560 void IOPMRequestQueue::free( void )
7561 {
7562 if (fLock)
7563 {
7564 IOLockFree(fLock);
7565 fLock = 0;
7566 }
7567 return IOEventSource::free();
7568 }
7569
7570 void IOPMRequestQueue::queuePMRequest( IOPMRequest * request )
7571 {
7572 assert(request);
7573 IOLockLock(fLock);
7574 queue_enter(&fQueue, request, IOPMRequest *, fCommandChain);
7575 IOLockUnlock(fLock);
7576 if (workLoop) signalWorkAvailable();
7577 }
7578
7579 void
7580 IOPMRequestQueue::queuePMRequestChain( IOPMRequest ** requests, IOItemCount count )
7581 {
7582 IOPMRequest * next;
7583
7584 assert(requests && count);
7585 IOLockLock(fLock);
7586 while (count--)
7587 {
7588 next = *requests;
7589 requests++;
7590 queue_enter(&fQueue, next, IOPMRequest *, fCommandChain);
7591 }
7592 IOLockUnlock(fLock);
7593 if (workLoop) signalWorkAvailable();
7594 }
7595
7596 bool IOPMRequestQueue::checkForWork( void )
7597 {
7598 Action dqAction = (Action) action;
7599 IOPMRequest * request;
7600 IOService * target;
7601 bool more = false;
7602
7603 IOLockLock( fLock );
7604
7605 while (!queue_empty(&fQueue))
7606 {
7607 queue_remove_first( &fQueue, request, IOPMRequest *, fCommandChain );
7608 IOLockUnlock( fLock );
7609 target = request->getTarget();
7610 assert(target);
7611 more |= (*dqAction)( target, request, this );
7612 IOLockLock( fLock );
7613 }
7614
7615 IOLockUnlock( fLock );
7616 return more;
7617 }
7618
7619 // MARK: -
7620 // MARK: IOPMWorkQueue
7621
7622 //*********************************************************************************
7623 // IOPMWorkQueue Class
7624 //
7625 // Queue of IOServicePM objects with busy IOPMRequest(s).
7626 //*********************************************************************************
7627
7628 OSDefineMetaClassAndStructors( IOPMWorkQueue, IOEventSource );
7629
7630 IOPMWorkQueue *
7631 IOPMWorkQueue::create( IOService * inOwner, Action work, Action retire )
7632 {
7633 IOPMWorkQueue * me = OSTypeAlloc(IOPMWorkQueue);
7634 if (me && !me->init(inOwner, work, retire))
7635 {
7636 me->release();
7637 me = 0;
7638 }
7639 return me;
7640 }
7641
7642 bool IOPMWorkQueue::init( IOService * inOwner, Action work, Action retire )
7643 {
7644 if (!work || !retire ||
7645 !IOEventSource::init(inOwner, (IOEventSourceAction)0))
7646 return false;
7647
7648 queue_init(&fWorkQueue);
7649
7650 fWorkAction = work;
7651 fRetireAction = retire;
7652 fConsumerCount = fProducerCount = 0;
7653
7654 return true;
7655 }
7656
7657 bool IOPMWorkQueue::queuePMRequest( IOPMRequest * request, IOServicePM * pwrMgt )
7658 {
7659 bool more = false;
7660 bool empty;
7661
7662 assert( request );
7663 assert( pwrMgt );
7664 assert( onThread() );
7665 assert( queue_next(&request->fCommandChain) ==
7666 queue_prev(&request->fCommandChain) );
7667
7668 gIOPMBusyCount++;
7669
7670 // Add new request to the tail of the per-service request queue.
7671 // Then immediately check the request queue to minimize latency
7672 // if the queue was empty.
7673
7674 empty = queue_empty(&pwrMgt->RequestHead);
7675 queue_enter(&pwrMgt->RequestHead, request, IOPMRequest *, fCommandChain);
7676 if (empty)
7677 {
7678 more = checkRequestQueue(&pwrMgt->RequestHead, &empty);
7679 if (!empty)
7680 {
7681 // New Request is blocked, add IOServicePM to work queue.
7682 assert( queue_next(&pwrMgt->WorkChain) ==
7683 queue_prev(&pwrMgt->WorkChain) );
7684
7685 queue_enter(&fWorkQueue, pwrMgt, IOServicePM *, WorkChain);
7686 fQueueLength++;
7687 PM_LOG3("IOPMWorkQueue: [%u] added %s@%p to queue\n",
7688 fQueueLength, pwrMgt->Name, pwrMgt);
7689 }
7690 }
7691
7692 return more;
7693 }
7694
7695 bool IOPMWorkQueue::checkRequestQueue( queue_head_t * queue, bool * empty )
7696 {
7697 IOPMRequest * request;
7698 IOService * target;
7699 bool more = false;
7700 bool done = false;
7701
7702 assert(!queue_empty(queue));
7703 do {
7704 request = (IOPMRequest *) queue_first(queue);
7705 if (request->isWorkBlocked())
7706 break; // cannot start, blocked on attached request
7707
7708 target = request->getTarget();
7709 done = (*fWorkAction)( target, request, this );
7710 if (!done)
7711 break; // work started, blocked on PM state machine
7712
7713 assert(gIOPMBusyCount > 0);
7714 if (gIOPMBusyCount)
7715 gIOPMBusyCount--;
7716
7717 queue_remove_first(queue, request, IOPMRequest *, fCommandChain);
7718 more |= (*fRetireAction)( target, request, this );
7719 done = queue_empty(queue);
7720 } while (!done);
7721
7722 *empty = done;
7723
7724 if (more)
7725 {
7726 // Retired request blocks another request, since the
7727 // blocked request may reside in the work queue, we
7728 // must bump the producer count to avoid work stall.
7729 fProducerCount++;
7730 }
7731
7732 return more;
7733 }
7734
7735 bool IOPMWorkQueue::checkForWork( void )
7736 {
7737 IOServicePM * entry;
7738 IOServicePM * next;
7739 bool more = false;
7740 bool empty;
7741
7742 #if WORK_QUEUE_STATS
7743 fStatCheckForWork++;
7744 #endif
7745
7746 // Each producer signal triggers a full iteration over
7747 // all IOServicePM entries in the work queue.
7748
7749 while (fConsumerCount != fProducerCount)
7750 {
7751 PM_LOG3("IOPMWorkQueue: checkForWork %u %u\n",
7752 fProducerCount, fConsumerCount);
7753
7754 fConsumerCount = fProducerCount;
7755
7756 #if WORK_QUEUE_STATS
7757 if (queue_empty(&fWorkQueue))
7758 {
7759 fStatQueueEmpty++;
7760 break;
7761 }
7762 fStatScanEntries++;
7763 uint32_t cachedWorkCount = gIOPMWorkCount;
7764 #endif
7765
7766 entry = (IOServicePM *) queue_first(&fWorkQueue);
7767 while (!queue_end(&fWorkQueue, (queue_entry_t) entry))
7768 {
7769 more |= checkRequestQueue(&entry->RequestHead, &empty);
7770
7771 // Get next entry, points to head if current entry is last.
7772 next = (IOServicePM *) queue_next(&entry->WorkChain);
7773
7774 // if request queue is empty, remove IOServicePM from queue.
7775 if (empty)
7776 {
7777 assert(fQueueLength);
7778 if (fQueueLength) fQueueLength--;
7779 PM_LOG3("IOPMWorkQueue: [%u] removed %s@%p from queue\n",
7780 fQueueLength, entry->Name, entry);
7781 queue_remove(&fWorkQueue, entry, IOServicePM *, WorkChain);
7782 }
7783 entry = next;
7784 }
7785
7786 #if WORK_QUEUE_STATS
7787 if (cachedWorkCount == gIOPMWorkCount)
7788 fStatNoWorkDone++;
7789 #endif
7790 }
7791
7792 return more;
7793 }
7794
7795 void IOPMWorkQueue::signalWorkAvailable( void )
7796 {
7797 fProducerCount++;
7798 IOEventSource::signalWorkAvailable();
7799 }
7800
7801 void IOPMWorkQueue::incrementProducerCount( void )
7802 {
7803 fProducerCount++;
7804 }
7805
7806 // MARK: -
7807 // MARK: IOPMCompletionQueue
7808
7809 //*********************************************************************************
7810 // IOPMCompletionQueue Class
7811 //*********************************************************************************
7812
7813 OSDefineMetaClassAndStructors( IOPMCompletionQueue, IOEventSource );
7814
7815 IOPMCompletionQueue *
7816 IOPMCompletionQueue::create( IOService * inOwner, Action inAction )
7817 {
7818 IOPMCompletionQueue * me = OSTypeAlloc(IOPMCompletionQueue);
7819 if (me && !me->init(inOwner, inAction))
7820 {
7821 me->release();
7822 me = 0;
7823 }
7824 return me;
7825 }
7826
7827 bool IOPMCompletionQueue::init( IOService * inOwner, Action inAction )
7828 {
7829 if (!inAction || !IOEventSource::init(inOwner, (IOEventSourceAction)inAction))
7830 return false;
7831
7832 queue_init(&fQueue);
7833 return true;
7834 }
7835
7836 bool IOPMCompletionQueue::queuePMRequest( IOPMRequest * request )
7837 {
7838 bool more;
7839
7840 assert(request);
7841 // unblock dependent request
7842 more = request->detachNextRequest();
7843 queue_enter(&fQueue, request, IOPMRequest *, fCommandChain);
7844 return more;
7845 }
7846
7847 bool IOPMCompletionQueue::checkForWork( void )
7848 {
7849 Action dqAction = (Action) action;
7850 IOPMRequest * request;
7851 IOPMRequest * next;
7852 IOService * target;
7853 bool more = false;
7854
7855 request = (IOPMRequest *) queue_first(&fQueue);
7856 while (!queue_end(&fQueue, (queue_entry_t) request))
7857 {
7858 next = (IOPMRequest *) queue_next(&request->fCommandChain);
7859 if (!request->isFreeBlocked())
7860 {
7861 queue_remove(&fQueue, request, IOPMRequest *, fCommandChain);
7862 target = request->getTarget();
7863 assert(target);
7864 more |= (*dqAction)( target, request, this );
7865 }
7866 request = next;
7867 }
7868
7869 return more;
7870 }
7871
7872 // MARK: -
7873 // MARK: IOServicePM
7874
7875 OSDefineMetaClassAndStructors(IOServicePM, OSObject)
7876
7877 //*********************************************************************************
7878 // serialize
7879 //
7880 // Serialize IOServicePM for debugging.
7881 //*********************************************************************************
7882
7883 static void
7884 setPMProperty( OSDictionary * dict, const char * key, uint64_t value )
7885 {
7886 OSNumber * num = OSNumber::withNumber(value, sizeof(value) * 8);
7887 if (num)
7888 {
7889 dict->setObject(key, num);
7890 num->release();
7891 }
7892 }
7893
7894 IOReturn IOServicePM::gatedSerialize( OSSerialize * s )
7895 {
7896 OSDictionary * dict;
7897 bool ok = false;
7898 int dictSize = 5;
7899
7900 if (IdleTimerPeriod)
7901 dictSize += 4;
7902
7903 #if WORK_QUEUE_STATS
7904 if (gIOPMRootNode == ControllingDriver)
7905 dictSize += 4;
7906 #endif
7907
7908 if (PowerClients)
7909 dict = OSDictionary::withDictionary(
7910 PowerClients, PowerClients->getCount() + dictSize);
7911 else
7912 dict = OSDictionary::withCapacity(dictSize);
7913
7914 if (dict)
7915 {
7916 setPMProperty(dict, "CurrentPowerState", CurrentPowerState);
7917 if (NumberOfPowerStates)
7918 setPMProperty(dict, "MaxPowerState", NumberOfPowerStates-1);
7919 if (DesiredPowerState != CurrentPowerState)
7920 setPMProperty(dict, "DesiredPowerState", DesiredPowerState);
7921 if (kIOPM_Finished != MachineState)
7922 setPMProperty(dict, "MachineState", MachineState);
7923 if (DeviceOverrideEnabled)
7924 dict->setObject("PowerOverrideOn", kOSBooleanTrue);
7925
7926 if (IdleTimerPeriod)
7927 {
7928 AbsoluteTime now;
7929 AbsoluteTime delta;
7930 uint64_t nsecs;
7931
7932 clock_get_uptime(&now);
7933
7934 // The idle timer period in milliseconds.
7935 setPMProperty(dict, "IdleTimerPeriod", IdleTimerPeriod * 1000ULL);
7936
7937 // The number of activity tickles recorded since device idle
7938 setPMProperty(dict, "ActivityTickles", ActivityTickleCount);
7939
7940 if (AbsoluteTime_to_scalar(&DeviceActiveTimestamp))
7941 {
7942 // The number of milliseconds since the last activity tickle.
7943 delta = now;
7944 SUB_ABSOLUTETIME(&delta, &DeviceActiveTimestamp);
7945 absolutetime_to_nanoseconds(delta, &nsecs);
7946 setPMProperty(dict, "TimeSinceLastTickle", NS_TO_MS(nsecs));
7947 }
7948
7949 if (AbsoluteTime_to_scalar(&IdleTimerStartTime))
7950 {
7951 // The number of milliseconds since the last device idle.
7952 delta = now;
7953 SUB_ABSOLUTETIME(&delta, &IdleTimerStartTime);
7954 absolutetime_to_nanoseconds(delta, &nsecs);
7955 setPMProperty(dict, "TimeSinceDeviceIdle", NS_TO_MS(nsecs));
7956 }
7957 }
7958
7959 #if WORK_QUEUE_STATS
7960 if (gIOPMRootNode == Owner)
7961 {
7962 setPMProperty(dict, "WQ-CheckForWork",
7963 gIOPMWorkQueue->fStatCheckForWork);
7964 setPMProperty(dict, "WQ-ScanEntries",
7965 gIOPMWorkQueue->fStatScanEntries);
7966 setPMProperty(dict, "WQ-QueueEmpty",
7967 gIOPMWorkQueue->fStatQueueEmpty);
7968 setPMProperty(dict, "WQ-NoWorkDone",
7969 gIOPMWorkQueue->fStatNoWorkDone);
7970 }
7971 #endif
7972
7973 if (HasAdvisoryDesire && !gIOPMAdvisoryTickleEnabled)
7974 {
7975 // Don't report advisory tickle when it has no influence
7976 dict->removeObject(gIOPMPowerClientAdvisoryTickle);
7977 }
7978
7979 ok = dict->serialize(s);
7980 dict->release();
7981 }
7982
7983 return (ok ? kIOReturnSuccess : kIOReturnNoMemory);
7984 }
7985
7986 bool IOServicePM::serialize( OSSerialize * s ) const
7987 {
7988 IOReturn ret = kIOReturnNotReady;
7989
7990 if (gIOPMWorkLoop)
7991 {
7992 ret = gIOPMWorkLoop->runAction(
7993 OSMemberFunctionCast(IOWorkLoop::Action, this, &IOServicePM::gatedSerialize),
7994 (OSObject *) this, (void *) s);
7995 }
7996
7997 return (kIOReturnSuccess == ret);
7998 }
7999
8000 void IOServicePM::pmPrint(
8001 uint32_t event,
8002 uintptr_t param1,
8003 uintptr_t param2 ) const
8004 {
8005 gPlatform->PMLog(Name, event, param1, param2);
8006 }
8007
8008 void IOServicePM::pmTrace(
8009 uint32_t event,
8010 uintptr_t param1,
8011 uintptr_t param2 ) const
8012 {
8013 const char * who = Name;
8014 uint64_t regId = Owner->getRegistryEntryID();
8015 uintptr_t name = 0;
8016
8017 static const uint32_t sStartStopBitField[] =
8018 { 0x00000000, 0x00000040 }; // Only Program Hardware so far
8019
8020 // Arcane formula from Hacker's Delight by Warren
8021 // abs(x) = ((int) x >> 31) ^ (x + ((int) x >> 31))
8022 uint32_t sgnevent = ((int) event >> 31);
8023 uint32_t absevent = sgnevent ^ (event + sgnevent);
8024 uint32_t code = IODBG_POWER(absevent);
8025
8026 uint32_t bit = 1 << (absevent & 0x1f);
8027 if ((absevent < (sizeof(sStartStopBitField) * 8)) &&
8028 (sStartStopBitField[absevent >> 5] & bit))
8029 {
8030 // Or in the START or END bits, Start = 1 & END = 2
8031 // If sgnevent == 0 then START - 0 => START
8032 // else if sgnevent == -1 then START - -1 => END
8033 code |= DBG_FUNC_START - sgnevent;
8034 }
8035
8036 // Copy the first characters of the name into an uintptr_t
8037 for (uint32_t i = 0; (i < sizeof(uintptr_t) && who[i] != 0); i++)
8038 {
8039 ((char *) &name)[sizeof(uintptr_t) - i - 1] = who[i];
8040 }
8041
8042 IOTimeStampConstant(code, name, (uintptr_t) regId, param1, param2);
8043 }
8044
8045 PMEventDetails* PMEventDetails::eventDetails(uint32_t type,
8046 const char *ownerName,
8047 uintptr_t ownerUnique,
8048 const char *interestName,
8049 uint8_t oldState,
8050 uint8_t newState,
8051 uint32_t result,
8052 uint32_t elapsedTimeUS) {
8053
8054 PMEventDetails *myself;
8055 myself = new PMEventDetails;
8056
8057 if(myself) {
8058 myself->eventType = type;
8059 myself->ownerName = ownerName;
8060 myself->ownerUnique = ownerUnique;
8061 myself->interestName = interestName;
8062 myself->oldState = oldState;
8063 myself->newState = newState;
8064 myself->result = result;
8065 myself->elapsedTimeUS = elapsedTimeUS;
8066
8067 myself->eventClassifier = kIOPMEventClassDriverEvent;
8068 }
8069
8070 return myself;
8071 }
8072
8073
8074 PMEventDetails* PMEventDetails::eventDetails(uint32_t type,
8075 const char *uuid,
8076 uint32_t reason,
8077 uint32_t result) {
8078
8079 PMEventDetails *myself;
8080 myself = new PMEventDetails;
8081
8082 if(myself) {
8083 myself->eventType = type;
8084 myself->uuid = uuid;
8085 myself->reason = reason;
8086 myself->result = result;
8087
8088 myself->eventClassifier = kIOPMEventClassSystemEvent;
8089 }
8090
8091 return myself;
8092 }
8093