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