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