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