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