1*0f4c859eSApple OSS Distributions /*
2*0f4c859eSApple OSS Distributions * Copyright (c) 1998-2020 Apple Inc. All rights reserved.
3*0f4c859eSApple OSS Distributions *
4*0f4c859eSApple OSS Distributions * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5*0f4c859eSApple OSS Distributions *
6*0f4c859eSApple OSS Distributions * This file contains Original Code and/or Modifications of Original Code
7*0f4c859eSApple OSS Distributions * as defined in and that are subject to the Apple Public Source License
8*0f4c859eSApple OSS Distributions * Version 2.0 (the 'License'). You may not use this file except in
9*0f4c859eSApple OSS Distributions * compliance with the License. The rights granted to you under the License
10*0f4c859eSApple OSS Distributions * may not be used to create, or enable the creation or redistribution of,
11*0f4c859eSApple OSS Distributions * unlawful or unlicensed copies of an Apple operating system, or to
12*0f4c859eSApple OSS Distributions * circumvent, violate, or enable the circumvention or violation of, any
13*0f4c859eSApple OSS Distributions * terms of an Apple operating system software license agreement.
14*0f4c859eSApple OSS Distributions *
15*0f4c859eSApple OSS Distributions * Please obtain a copy of the License at
16*0f4c859eSApple OSS Distributions * http://www.opensource.apple.com/apsl/ and read it before using this file.
17*0f4c859eSApple OSS Distributions *
18*0f4c859eSApple OSS Distributions * The Original Code and all software distributed under the License are
19*0f4c859eSApple OSS Distributions * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20*0f4c859eSApple OSS Distributions * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21*0f4c859eSApple OSS Distributions * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22*0f4c859eSApple OSS Distributions * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23*0f4c859eSApple OSS Distributions * Please see the License for the specific language governing rights and
24*0f4c859eSApple OSS Distributions * limitations under the License.
25*0f4c859eSApple OSS Distributions *
26*0f4c859eSApple OSS Distributions * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27*0f4c859eSApple OSS Distributions */
28*0f4c859eSApple OSS Distributions
29*0f4c859eSApple OSS Distributions #include <IOKit/assert.h>
30*0f4c859eSApple OSS Distributions #include <IOKit/IOKitDebug.h>
31*0f4c859eSApple OSS Distributions #include <IOKit/IOLib.h>
32*0f4c859eSApple OSS Distributions #include <IOKit/IOMessage.h>
33*0f4c859eSApple OSS Distributions #include <IOKit/IOPlatformExpert.h>
34*0f4c859eSApple OSS Distributions #include <IOKit/IOService.h>
35*0f4c859eSApple OSS Distributions #include <IOKit/IOUserServer.h>
36*0f4c859eSApple OSS Distributions #include <IOKit/IOEventSource.h>
37*0f4c859eSApple OSS Distributions #include <IOKit/IOWorkLoop.h>
38*0f4c859eSApple OSS Distributions #include <IOKit/IOCommand.h>
39*0f4c859eSApple OSS Distributions #include <IOKit/IOTimeStamp.h>
40*0f4c859eSApple OSS Distributions #include <IOKit/IOReportMacros.h>
41*0f4c859eSApple OSS Distributions #include <IOKit/IODeviceTreeSupport.h>
42*0f4c859eSApple OSS Distributions
43*0f4c859eSApple OSS Distributions #include <IOKit/pwr_mgt/IOPMlog.h>
44*0f4c859eSApple OSS Distributions #include <IOKit/pwr_mgt/IOPMinformee.h>
45*0f4c859eSApple OSS Distributions #include <IOKit/pwr_mgt/IOPMinformeeList.h>
46*0f4c859eSApple OSS Distributions #include <IOKit/pwr_mgt/IOPowerConnection.h>
47*0f4c859eSApple OSS Distributions #include <IOKit/pwr_mgt/RootDomain.h>
48*0f4c859eSApple OSS Distributions #include <IOKit/pwr_mgt/IOPMPrivate.h>
49*0f4c859eSApple OSS Distributions
50*0f4c859eSApple OSS Distributions #include <sys/proc.h>
51*0f4c859eSApple OSS Distributions #include <sys/proc_internal.h>
52*0f4c859eSApple OSS Distributions #include <sys/sysctl.h>
53*0f4c859eSApple OSS Distributions #include <libkern/OSDebug.h>
54*0f4c859eSApple OSS Distributions #include <kern/thread.h>
55*0f4c859eSApple OSS Distributions #if DEVELOPMENT || DEBUG
56*0f4c859eSApple OSS Distributions #include <os/system_event_log.h>
57*0f4c859eSApple OSS Distributions #endif /* DEVELOPMENT || DEBUG */
58*0f4c859eSApple OSS Distributions
59*0f4c859eSApple OSS Distributions // Required for notification instrumentation
60*0f4c859eSApple OSS Distributions #include "IOServicePrivate.h"
61*0f4c859eSApple OSS Distributions #include "IOServicePMPrivate.h"
62*0f4c859eSApple OSS Distributions #include "IOKitKernelInternal.h"
63*0f4c859eSApple OSS Distributions
64*0f4c859eSApple OSS Distributions #if USE_SETTLE_TIMER
65*0f4c859eSApple OSS Distributions static void settle_timer_expired(thread_call_param_t, thread_call_param_t);
66*0f4c859eSApple OSS Distributions #endif
67*0f4c859eSApple OSS Distributions static void idle_timer_expired(thread_call_param_t, thread_call_param_t);
68*0f4c859eSApple OSS Distributions static void tellKernelClientApplier(OSObject * object, void * arg);
69*0f4c859eSApple OSS Distributions static void tellAppClientApplier(OSObject * object, void * arg);
70*0f4c859eSApple OSS Distributions static const char * getNotificationPhaseString(uint32_t phase);
71*0f4c859eSApple OSS Distributions
72*0f4c859eSApple OSS Distributions static uint64_t
computeTimeDeltaNS(const AbsoluteTime * start)73*0f4c859eSApple OSS Distributions computeTimeDeltaNS( const AbsoluteTime * start )
74*0f4c859eSApple OSS Distributions {
75*0f4c859eSApple OSS Distributions AbsoluteTime now;
76*0f4c859eSApple OSS Distributions uint64_t nsec;
77*0f4c859eSApple OSS Distributions
78*0f4c859eSApple OSS Distributions clock_get_uptime(&now);
79*0f4c859eSApple OSS Distributions SUB_ABSOLUTETIME(&now, start);
80*0f4c859eSApple OSS Distributions absolutetime_to_nanoseconds(now, &nsec);
81*0f4c859eSApple OSS Distributions return nsec;
82*0f4c859eSApple OSS Distributions }
83*0f4c859eSApple OSS Distributions
84*0f4c859eSApple OSS Distributions #if PM_VARS_SUPPORT
85*0f4c859eSApple OSS Distributions OSDefineMetaClassAndStructors(IOPMprot, OSObject)
86*0f4c859eSApple OSS Distributions #endif
87*0f4c859eSApple OSS Distributions
88*0f4c859eSApple OSS Distributions //******************************************************************************
89*0f4c859eSApple OSS Distributions // Globals
90*0f4c859eSApple OSS Distributions //******************************************************************************
91*0f4c859eSApple OSS Distributions
92*0f4c859eSApple OSS Distributions static bool gIOPMInitialized = false;
93*0f4c859eSApple OSS Distributions static uint32_t gIOPMBusyRequestCount = 0;
94*0f4c859eSApple OSS Distributions static uint32_t gIOPMWorkInvokeCount = 0;
95*0f4c859eSApple OSS Distributions static uint32_t gIOPMTickleGeneration = 0;
96*0f4c859eSApple OSS Distributions static IOWorkLoop * gIOPMWorkLoop = NULL;
97*0f4c859eSApple OSS Distributions static IOPMRequestQueue * gIOPMRequestQueue = NULL;
98*0f4c859eSApple OSS Distributions static IOPMRequestQueue * gIOPMReplyQueue = NULL;
99*0f4c859eSApple OSS Distributions static IOPMWorkQueue * gIOPMWorkQueue = NULL;
100*0f4c859eSApple OSS Distributions static IOPMCompletionQueue * gIOPMCompletionQueue = NULL;
101*0f4c859eSApple OSS Distributions static IOPMRequest * gIOPMRequest = NULL;
102*0f4c859eSApple OSS Distributions static IOService * gIOPMRootNode = NULL;
103*0f4c859eSApple OSS Distributions static IOPlatformExpert * gPlatform = NULL;
104*0f4c859eSApple OSS Distributions static IOLock * gIOPMInitLock = NULL;
105*0f4c859eSApple OSS Distributions
106*0f4c859eSApple OSS Distributions // log setPowerStates and powerStateChange longer than (ns):
107*0f4c859eSApple OSS Distributions static uint64_t gIOPMSetPowerStateLogNS =
108*0f4c859eSApple OSS Distributions #if defined(__i386__) || defined(__x86_64__)
109*0f4c859eSApple OSS Distributions (300ULL * 1000ULL * 1000ULL)
110*0f4c859eSApple OSS Distributions #else
111*0f4c859eSApple OSS Distributions (50ULL * 1000ULL * 1000ULL)
112*0f4c859eSApple OSS Distributions #endif
113*0f4c859eSApple OSS Distributions ;
114*0f4c859eSApple OSS Distributions
115*0f4c859eSApple OSS Distributions const OSSymbol * gIOPMPowerClientDevice = NULL;
116*0f4c859eSApple OSS Distributions const OSSymbol * gIOPMPowerClientDriver = NULL;
117*0f4c859eSApple OSS Distributions const OSSymbol * gIOPMPowerClientChildProxy = NULL;
118*0f4c859eSApple OSS Distributions const OSSymbol * gIOPMPowerClientChildren = NULL;
119*0f4c859eSApple OSS Distributions const OSSymbol * gIOPMPowerClientRootDomain = NULL;
120*0f4c859eSApple OSS Distributions
121*0f4c859eSApple OSS Distributions static const OSSymbol * gIOPMPowerClientAdvisoryTickle = NULL;
122*0f4c859eSApple OSS Distributions static bool gIOPMAdvisoryTickleEnabled = true;
123*0f4c859eSApple OSS Distributions static thread_t gIOPMWatchDogThread = NULL;
124*0f4c859eSApple OSS Distributions TUNABLE_WRITEABLE(uint32_t, gSleepAckTimeout, "pmtimeout", 0);
125*0f4c859eSApple OSS Distributions
126*0f4c859eSApple OSS Distributions /*
127*0f4c859eSApple OSS Distributions * While waiting for a driver callout to complete, we log any instances
128*0f4c859eSApple OSS Distributions * that have taken longer than the below period (in milliseconds) to return.
129*0f4c859eSApple OSS Distributions */
130*0f4c859eSApple OSS Distributions TUNABLE_WRITEABLE(uint32_t, gDriverCalloutTimer, "pmcallouttimer", 2000);
131*0f4c859eSApple OSS Distributions
132*0f4c859eSApple OSS Distributions static uint32_t
getPMRequestType(void)133*0f4c859eSApple OSS Distributions getPMRequestType( void )
134*0f4c859eSApple OSS Distributions {
135*0f4c859eSApple OSS Distributions uint32_t type = kIOPMRequestTypeInvalid;
136*0f4c859eSApple OSS Distributions if (gIOPMRequest) {
137*0f4c859eSApple OSS Distributions type = gIOPMRequest->getType();
138*0f4c859eSApple OSS Distributions }
139*0f4c859eSApple OSS Distributions return type;
140*0f4c859eSApple OSS Distributions }
141*0f4c859eSApple OSS Distributions
142*0f4c859eSApple OSS Distributions SYSCTL_UINT(_kern, OID_AUTO, pmtimeout, CTLFLAG_RW | CTLFLAG_LOCKED, &gSleepAckTimeout, 0, "Power Management Timeout");
143*0f4c859eSApple OSS Distributions SYSCTL_UINT(_kern, OID_AUTO, pmcallouttimer, CTLFLAG_RW | CTLFLAG_LOCKED, &gDriverCalloutTimer, 0, "Power Management Driver Callout Log Timer");
144*0f4c859eSApple OSS Distributions
145*0f4c859eSApple OSS Distributions //******************************************************************************
146*0f4c859eSApple OSS Distributions // Macros
147*0f4c859eSApple OSS Distributions //******************************************************************************
148*0f4c859eSApple OSS Distributions
149*0f4c859eSApple OSS Distributions #define PM_ERROR(x...) do { kprintf(x);IOLog(x); \
150*0f4c859eSApple OSS Distributions } while (false)
151*0f4c859eSApple OSS Distributions #define PM_LOG(x...) do { kprintf(x); } while (false)
152*0f4c859eSApple OSS Distributions
153*0f4c859eSApple OSS Distributions #define PM_LOG1(x...) do { \
154*0f4c859eSApple OSS Distributions if (kIOLogDebugPower & gIOKitDebug) \
155*0f4c859eSApple OSS Distributions kprintf(x); } while (false)
156*0f4c859eSApple OSS Distributions
157*0f4c859eSApple OSS Distributions #define PM_LOG2(x...) do { \
158*0f4c859eSApple OSS Distributions if (kIOLogDebugPower & gIOKitDebug) \
159*0f4c859eSApple OSS Distributions kprintf(x); } while (false)
160*0f4c859eSApple OSS Distributions
161*0f4c859eSApple OSS Distributions #if 0
162*0f4c859eSApple OSS Distributions #define PM_LOG3(x...) do { kprintf(x); } while (false)
163*0f4c859eSApple OSS Distributions #else
164*0f4c859eSApple OSS Distributions #define PM_LOG3(x...)
165*0f4c859eSApple OSS Distributions #endif
166*0f4c859eSApple OSS Distributions
167*0f4c859eSApple OSS Distributions #define RD_LOG(x...) do { \
168*0f4c859eSApple OSS Distributions if ((kIOLogPMRootDomain & gIOKitDebug) && \
169*0f4c859eSApple OSS Distributions (getPMRootDomain() == this)) { \
170*0f4c859eSApple OSS Distributions IOLog("PMRD: " x); \
171*0f4c859eSApple OSS Distributions }} while (false)
172*0f4c859eSApple OSS Distributions #define PM_ASSERT_IN_GATE(x) \
173*0f4c859eSApple OSS Distributions do { \
174*0f4c859eSApple OSS Distributions assert(gIOPMWorkLoop->inGate()); \
175*0f4c859eSApple OSS Distributions } while(false)
176*0f4c859eSApple OSS Distributions
177*0f4c859eSApple OSS Distributions #define PM_LOCK() IOLockLock(fPMLock)
178*0f4c859eSApple OSS Distributions #define PM_UNLOCK() IOLockUnlock(fPMLock)
179*0f4c859eSApple OSS Distributions #define PM_LOCK_SLEEP(event, dl) IOLockSleepDeadline(fPMLock, event, dl, THREAD_UNINT)
180*0f4c859eSApple OSS Distributions #define PM_LOCK_WAKEUP(event) IOLockWakeup(fPMLock, event, false)
181*0f4c859eSApple OSS Distributions
182*0f4c859eSApple OSS Distributions #define us_per_s 1000000
183*0f4c859eSApple OSS Distributions #define ns_per_us 1000
184*0f4c859eSApple OSS Distributions #define k30Seconds (30*us_per_s)
185*0f4c859eSApple OSS Distributions #define k5Seconds ( 5*us_per_s)
186*0f4c859eSApple OSS Distributions #define k7Seconds ( 7*us_per_s)
187*0f4c859eSApple OSS Distributions #if !defined(XNU_TARGET_OS_OSX)
188*0f4c859eSApple OSS Distributions #define kCanSleepMaxTimeReq k5Seconds
189*0f4c859eSApple OSS Distributions #define kWillSleepMaxTimeReq k7Seconds
190*0f4c859eSApple OSS Distributions #else /* defined(XNU_TARGET_OS_OSX) */
191*0f4c859eSApple OSS Distributions #define kCanSleepMaxTimeReq k30Seconds
192*0f4c859eSApple OSS Distributions #define kWillSleepMaxTimeReq k30Seconds
193*0f4c859eSApple OSS Distributions #endif /* defined(XNU_TARGET_OS_OSX) */
194*0f4c859eSApple OSS Distributions #define kMaxTimeRequested k30Seconds
195*0f4c859eSApple OSS Distributions #define kMinAckTimeoutTicks (10*1000000)
196*0f4c859eSApple OSS Distributions #define kIOPMTardyAckSPSKey "IOPMTardyAckSetPowerState"
197*0f4c859eSApple OSS Distributions #define kIOPMTardyAckPSCKey "IOPMTardyAckPowerStateChange"
198*0f4c859eSApple OSS Distributions #define kPwrMgtKey "IOPowerManagement"
199*0f4c859eSApple OSS Distributions
200*0f4c859eSApple OSS Distributions #define OUR_PMLog(t, a, b) do { \
201*0f4c859eSApple OSS Distributions if (pwrMgt) { \
202*0f4c859eSApple OSS Distributions if (gIOKitDebug & kIOLogPower) \
203*0f4c859eSApple OSS Distributions pwrMgt->pmPrint(t, a, b); \
204*0f4c859eSApple OSS Distributions if (gIOKitTrace & kIOTracePowerMgmt) \
205*0f4c859eSApple OSS Distributions pwrMgt->pmTrace(t, DBG_FUNC_NONE, a, b); \
206*0f4c859eSApple OSS Distributions } \
207*0f4c859eSApple OSS Distributions } while(0)
208*0f4c859eSApple OSS Distributions
209*0f4c859eSApple OSS Distributions #define OUR_PMLogFuncStart(t, a, b) do { \
210*0f4c859eSApple OSS Distributions if (pwrMgt) { \
211*0f4c859eSApple OSS Distributions if (gIOKitDebug & kIOLogPower) \
212*0f4c859eSApple OSS Distributions pwrMgt->pmPrint(t, a, b); \
213*0f4c859eSApple OSS Distributions if (gIOKitTrace & kIOTracePowerMgmt) \
214*0f4c859eSApple OSS Distributions pwrMgt->pmTrace(t, DBG_FUNC_START, a, b); \
215*0f4c859eSApple OSS Distributions } \
216*0f4c859eSApple OSS Distributions } while(0)
217*0f4c859eSApple OSS Distributions
218*0f4c859eSApple OSS Distributions #define OUR_PMLogFuncEnd(t, a, b) do { \
219*0f4c859eSApple OSS Distributions if (pwrMgt) { \
220*0f4c859eSApple OSS Distributions if (gIOKitDebug & kIOLogPower) \
221*0f4c859eSApple OSS Distributions pwrMgt->pmPrint(-t, a, b); \
222*0f4c859eSApple OSS Distributions if (gIOKitTrace & kIOTracePowerMgmt) \
223*0f4c859eSApple OSS Distributions pwrMgt->pmTrace(t, DBG_FUNC_END, a, b); \
224*0f4c859eSApple OSS Distributions } \
225*0f4c859eSApple OSS Distributions } while(0)
226*0f4c859eSApple OSS Distributions
227*0f4c859eSApple OSS Distributions #define NS_TO_MS(nsec) ((int)((nsec) / 1000000ULL))
228*0f4c859eSApple OSS Distributions #define NS_TO_US(nsec) ((int)((nsec) / 1000ULL))
229*0f4c859eSApple OSS Distributions
230*0f4c859eSApple OSS Distributions #define SUPPORT_IDLE_CANCEL 1
231*0f4c859eSApple OSS Distributions
232*0f4c859eSApple OSS Distributions #define kIOPMPowerStateMax 0xFFFFFFFF
233*0f4c859eSApple OSS Distributions #define kInvalidTicklePowerState kIOPMPowerStateMax
234*0f4c859eSApple OSS Distributions
235*0f4c859eSApple OSS Distributions #define kNoTickleCancelWindow (60ULL * 1000ULL * 1000ULL * 1000ULL)
236*0f4c859eSApple OSS Distributions
237*0f4c859eSApple OSS Distributions #define IS_PM_ROOT (this == gIOPMRootNode)
238*0f4c859eSApple OSS Distributions #define IS_ROOT_DOMAIN (getPMRootDomain() == this)
239*0f4c859eSApple OSS Distributions #define IS_POWER_DROP (StateOrder(fHeadNotePowerState) < StateOrder(fCurrentPowerState))
240*0f4c859eSApple OSS Distributions #define IS_POWER_RISE (StateOrder(fHeadNotePowerState) > StateOrder(fCurrentPowerState))
241*0f4c859eSApple OSS Distributions
242*0f4c859eSApple OSS Distributions // log app responses longer than (ns):
243*0f4c859eSApple OSS Distributions #define LOG_APP_RESPONSE_TIMES (100ULL * 1000ULL * 1000ULL)
244*0f4c859eSApple OSS Distributions // use message tracer to log messages longer than (ns):
245*0f4c859eSApple OSS Distributions #define LOG_APP_RESPONSE_MSG_TRACER (3 * 1000ULL * 1000ULL * 1000ULL)
246*0f4c859eSApple OSS Distributions
247*0f4c859eSApple OSS Distributions // log kext responses longer than (ns):
248*0f4c859eSApple OSS Distributions #define LOG_KEXT_RESPONSE_TIMES (100ULL * 1000ULL * 1000ULL)
249*0f4c859eSApple OSS Distributions
250*0f4c859eSApple OSS Distributions enum {
251*0f4c859eSApple OSS Distributions kReserveDomainPower = 1
252*0f4c859eSApple OSS Distributions };
253*0f4c859eSApple OSS Distributions
254*0f4c859eSApple OSS Distributions #define MS_PUSH(n) \
255*0f4c859eSApple OSS Distributions do { assert(kIOPM_BadMachineState == fSavedMachineState); \
256*0f4c859eSApple OSS Distributions assert(kIOPM_BadMachineState != n); \
257*0f4c859eSApple OSS Distributions fSavedMachineState = n; } while (false)
258*0f4c859eSApple OSS Distributions
259*0f4c859eSApple OSS Distributions #define MS_POP() \
260*0f4c859eSApple OSS Distributions do { assert(kIOPM_BadMachineState != fSavedMachineState); \
261*0f4c859eSApple OSS Distributions fMachineState = fSavedMachineState; \
262*0f4c859eSApple OSS Distributions fSavedMachineState = kIOPM_BadMachineState; } while (false)
263*0f4c859eSApple OSS Distributions
264*0f4c859eSApple OSS Distributions #define PM_ACTION_TICKLE(a) \
265*0f4c859eSApple OSS Distributions do { if (fPMActions.a) { \
266*0f4c859eSApple OSS Distributions (fPMActions.a)(fPMActions.target, this, &fPMActions); } \
267*0f4c859eSApple OSS Distributions } while (false)
268*0f4c859eSApple OSS Distributions
269*0f4c859eSApple OSS Distributions #define PM_ACTION_CHANGE(a, x, y) \
270*0f4c859eSApple OSS Distributions do { if (fPMActions.a) { \
271*0f4c859eSApple OSS Distributions (fPMActions.a)(fPMActions.target, this, &fPMActions, gIOPMRequest, x, y); } \
272*0f4c859eSApple OSS Distributions } while (false)
273*0f4c859eSApple OSS Distributions
274*0f4c859eSApple OSS Distributions #define PM_ACTION_CLIENT(a, x, y, z) \
275*0f4c859eSApple OSS Distributions do { if (fPMActions.a) { \
276*0f4c859eSApple OSS Distributions (fPMActions.a)(fPMActions.target, this, &fPMActions, x, y, z); } \
277*0f4c859eSApple OSS Distributions } while (false)
278*0f4c859eSApple OSS Distributions
279*0f4c859eSApple OSS Distributions static OSNumber * copyClientIDForNotification(
280*0f4c859eSApple OSS Distributions OSObject *object,
281*0f4c859eSApple OSS Distributions IOPMInterestContext *context);
282*0f4c859eSApple OSS Distributions
283*0f4c859eSApple OSS Distributions static void logClientIDForNotification(
284*0f4c859eSApple OSS Distributions OSObject *object,
285*0f4c859eSApple OSS Distributions IOPMInterestContext *context,
286*0f4c859eSApple OSS Distributions const char *logString);
287*0f4c859eSApple OSS Distributions
288*0f4c859eSApple OSS Distributions //*********************************************************************************
289*0f4c859eSApple OSS Distributions // PM machine states
290*0f4c859eSApple OSS Distributions //
291*0f4c859eSApple OSS Distributions // Check kgmacros after modifying machine states.
292*0f4c859eSApple OSS Distributions //*********************************************************************************
293*0f4c859eSApple OSS Distributions
294*0f4c859eSApple OSS Distributions enum {
295*0f4c859eSApple OSS Distributions kIOPM_Finished = 0,
296*0f4c859eSApple OSS Distributions
297*0f4c859eSApple OSS Distributions kIOPM_OurChangeTellClientsPowerDown = 1,
298*0f4c859eSApple OSS Distributions kIOPM_OurChangeTellUserPMPolicyPowerDown = 2,
299*0f4c859eSApple OSS Distributions kIOPM_OurChangeTellPriorityClientsPowerDown = 3,
300*0f4c859eSApple OSS Distributions kIOPM_OurChangeNotifyInterestedDriversWillChange = 4,
301*0f4c859eSApple OSS Distributions kIOPM_OurChangeSetPowerState = 5,
302*0f4c859eSApple OSS Distributions kIOPM_OurChangeWaitForPowerSettle = 6,
303*0f4c859eSApple OSS Distributions kIOPM_OurChangeNotifyInterestedDriversDidChange = 7,
304*0f4c859eSApple OSS Distributions kIOPM_OurChangeTellCapabilityDidChange = 8,
305*0f4c859eSApple OSS Distributions kIOPM_OurChangeFinish = 9,
306*0f4c859eSApple OSS Distributions
307*0f4c859eSApple OSS Distributions kIOPM_ParentChangeTellPriorityClientsPowerDown = 10,
308*0f4c859eSApple OSS Distributions kIOPM_ParentChangeNotifyInterestedDriversWillChange = 11,
309*0f4c859eSApple OSS Distributions kIOPM_ParentChangeSetPowerState = 12,
310*0f4c859eSApple OSS Distributions kIOPM_ParentChangeWaitForPowerSettle = 13,
311*0f4c859eSApple OSS Distributions kIOPM_ParentChangeNotifyInterestedDriversDidChange = 14,
312*0f4c859eSApple OSS Distributions kIOPM_ParentChangeTellCapabilityDidChange = 15,
313*0f4c859eSApple OSS Distributions kIOPM_ParentChangeAcknowledgePowerChange = 16,
314*0f4c859eSApple OSS Distributions
315*0f4c859eSApple OSS Distributions kIOPM_NotifyChildrenStart = 17,
316*0f4c859eSApple OSS Distributions kIOPM_NotifyChildrenOrdered = 18,
317*0f4c859eSApple OSS Distributions kIOPM_NotifyChildrenDelayed = 19,
318*0f4c859eSApple OSS Distributions kIOPM_SyncTellClientsPowerDown = 20,
319*0f4c859eSApple OSS Distributions kIOPM_SyncTellPriorityClientsPowerDown = 21,
320*0f4c859eSApple OSS Distributions kIOPM_SyncNotifyWillChange = 22,
321*0f4c859eSApple OSS Distributions kIOPM_SyncNotifyDidChange = 23,
322*0f4c859eSApple OSS Distributions kIOPM_SyncTellCapabilityDidChange = 24,
323*0f4c859eSApple OSS Distributions kIOPM_SyncFinish = 25,
324*0f4c859eSApple OSS Distributions kIOPM_TellCapabilityChangeDone = 26,
325*0f4c859eSApple OSS Distributions kIOPM_DriverThreadCallDone = 27,
326*0f4c859eSApple OSS Distributions
327*0f4c859eSApple OSS Distributions kIOPM_BadMachineState = 0xFFFFFFFF
328*0f4c859eSApple OSS Distributions };
329*0f4c859eSApple OSS Distributions
330*0f4c859eSApple OSS Distributions //*********************************************************************************
331*0f4c859eSApple OSS Distributions // [private static] allocPMInitLock
332*0f4c859eSApple OSS Distributions //
333*0f4c859eSApple OSS Distributions // Allocate gIOPMInitLock prior to gIOPMWorkLoop initialization.
334*0f4c859eSApple OSS Distributions //*********************************************************************************
335*0f4c859eSApple OSS Distributions
336*0f4c859eSApple OSS Distributions void
allocPMInitLock(void)337*0f4c859eSApple OSS Distributions IOService::allocPMInitLock( void )
338*0f4c859eSApple OSS Distributions {
339*0f4c859eSApple OSS Distributions gIOPMInitLock = IOLockAlloc();
340*0f4c859eSApple OSS Distributions assert(gIOPMInitLock);
341*0f4c859eSApple OSS Distributions }
342*0f4c859eSApple OSS Distributions
343*0f4c859eSApple OSS Distributions //*********************************************************************************
344*0f4c859eSApple OSS Distributions // [public] PMinit
345*0f4c859eSApple OSS Distributions //
346*0f4c859eSApple OSS Distributions // Initialize power management.
347*0f4c859eSApple OSS Distributions //*********************************************************************************
348*0f4c859eSApple OSS Distributions
349*0f4c859eSApple OSS Distributions void
PMinit(void)350*0f4c859eSApple OSS Distributions IOService::PMinit( void )
351*0f4c859eSApple OSS Distributions {
352*0f4c859eSApple OSS Distributions if (!initialized) {
353*0f4c859eSApple OSS Distributions IOLockLock(gIOPMInitLock);
354*0f4c859eSApple OSS Distributions if (!gIOPMInitialized) {
355*0f4c859eSApple OSS Distributions gPlatform = getPlatform();
356*0f4c859eSApple OSS Distributions gIOPMWorkLoop = IOWorkLoop::workLoop();
357*0f4c859eSApple OSS Distributions if (gIOPMWorkLoop) {
358*0f4c859eSApple OSS Distributions assert(OSDynamicCast(IOPMrootDomain, this));
359*0f4c859eSApple OSS Distributions gIOPMRequestQueue = IOPMRequestQueue::create(
360*0f4c859eSApple OSS Distributions this, OSMemberFunctionCast(IOPMRequestQueue::Action,
361*0f4c859eSApple OSS Distributions this, &IOService::actionPMRequestQueue));
362*0f4c859eSApple OSS Distributions
363*0f4c859eSApple OSS Distributions gIOPMReplyQueue = IOPMRequestQueue::create(
364*0f4c859eSApple OSS Distributions this, OSMemberFunctionCast(IOPMRequestQueue::Action,
365*0f4c859eSApple OSS Distributions this, &IOService::actionPMReplyQueue));
366*0f4c859eSApple OSS Distributions
367*0f4c859eSApple OSS Distributions gIOPMWorkQueue = IOPMWorkQueue::create(this,
368*0f4c859eSApple OSS Distributions OSMemberFunctionCast(IOPMWorkQueue::Action, this,
369*0f4c859eSApple OSS Distributions &IOService::actionPMWorkQueueInvoke),
370*0f4c859eSApple OSS Distributions OSMemberFunctionCast(IOPMWorkQueue::Action, this,
371*0f4c859eSApple OSS Distributions &IOService::actionPMWorkQueueRetire));
372*0f4c859eSApple OSS Distributions
373*0f4c859eSApple OSS Distributions gIOPMCompletionQueue = IOPMCompletionQueue::create(
374*0f4c859eSApple OSS Distributions this, OSMemberFunctionCast(IOPMCompletionQueue::Action,
375*0f4c859eSApple OSS Distributions this, &IOService::actionPMCompletionQueue));
376*0f4c859eSApple OSS Distributions
377*0f4c859eSApple OSS Distributions if (gIOPMWorkLoop->addEventSource(gIOPMRequestQueue) !=
378*0f4c859eSApple OSS Distributions kIOReturnSuccess) {
379*0f4c859eSApple OSS Distributions gIOPMRequestQueue->release();
380*0f4c859eSApple OSS Distributions gIOPMRequestQueue = NULL;
381*0f4c859eSApple OSS Distributions }
382*0f4c859eSApple OSS Distributions
383*0f4c859eSApple OSS Distributions if (gIOPMWorkLoop->addEventSource(gIOPMReplyQueue) !=
384*0f4c859eSApple OSS Distributions kIOReturnSuccess) {
385*0f4c859eSApple OSS Distributions gIOPMReplyQueue->release();
386*0f4c859eSApple OSS Distributions gIOPMReplyQueue = NULL;
387*0f4c859eSApple OSS Distributions }
388*0f4c859eSApple OSS Distributions
389*0f4c859eSApple OSS Distributions if (gIOPMWorkLoop->addEventSource(gIOPMWorkQueue) !=
390*0f4c859eSApple OSS Distributions kIOReturnSuccess) {
391*0f4c859eSApple OSS Distributions gIOPMWorkQueue->release();
392*0f4c859eSApple OSS Distributions gIOPMWorkQueue = NULL;
393*0f4c859eSApple OSS Distributions }
394*0f4c859eSApple OSS Distributions
395*0f4c859eSApple OSS Distributions // Must be added after the work queue, which pushes request
396*0f4c859eSApple OSS Distributions // to the completion queue without signaling the work loop.
397*0f4c859eSApple OSS Distributions if (gIOPMWorkLoop->addEventSource(gIOPMCompletionQueue) !=
398*0f4c859eSApple OSS Distributions kIOReturnSuccess) {
399*0f4c859eSApple OSS Distributions gIOPMCompletionQueue->release();
400*0f4c859eSApple OSS Distributions gIOPMCompletionQueue = NULL;
401*0f4c859eSApple OSS Distributions }
402*0f4c859eSApple OSS Distributions
403*0f4c859eSApple OSS Distributions gIOPMPowerClientDevice =
404*0f4c859eSApple OSS Distributions OSSymbol::withCStringNoCopy( "DevicePowerState" );
405*0f4c859eSApple OSS Distributions
406*0f4c859eSApple OSS Distributions gIOPMPowerClientDriver =
407*0f4c859eSApple OSS Distributions OSSymbol::withCStringNoCopy( "DriverPowerState" );
408*0f4c859eSApple OSS Distributions
409*0f4c859eSApple OSS Distributions gIOPMPowerClientChildProxy =
410*0f4c859eSApple OSS Distributions OSSymbol::withCStringNoCopy( "ChildProxyPowerState" );
411*0f4c859eSApple OSS Distributions
412*0f4c859eSApple OSS Distributions gIOPMPowerClientChildren =
413*0f4c859eSApple OSS Distributions OSSymbol::withCStringNoCopy( "ChildrenPowerState" );
414*0f4c859eSApple OSS Distributions
415*0f4c859eSApple OSS Distributions gIOPMPowerClientAdvisoryTickle =
416*0f4c859eSApple OSS Distributions OSSymbol::withCStringNoCopy( "AdvisoryTicklePowerState" );
417*0f4c859eSApple OSS Distributions
418*0f4c859eSApple OSS Distributions gIOPMPowerClientRootDomain =
419*0f4c859eSApple OSS Distributions OSSymbol::withCStringNoCopy( "RootDomainPower" );
420*0f4c859eSApple OSS Distributions }
421*0f4c859eSApple OSS Distributions
422*0f4c859eSApple OSS Distributions if (gIOPMRequestQueue && gIOPMReplyQueue && gIOPMCompletionQueue) {
423*0f4c859eSApple OSS Distributions gIOPMInitialized = true;
424*0f4c859eSApple OSS Distributions }
425*0f4c859eSApple OSS Distributions
426*0f4c859eSApple OSS Distributions #if (DEVELOPMENT || DEBUG)
427*0f4c859eSApple OSS Distributions uint32_t setPowerStateLogMS = 0;
428*0f4c859eSApple OSS Distributions if (PE_parse_boot_argn("setpowerstate_log", &setPowerStateLogMS, sizeof(setPowerStateLogMS))) {
429*0f4c859eSApple OSS Distributions gIOPMSetPowerStateLogNS = setPowerStateLogMS * 1000000ULL;
430*0f4c859eSApple OSS Distributions }
431*0f4c859eSApple OSS Distributions #endif
432*0f4c859eSApple OSS Distributions }
433*0f4c859eSApple OSS Distributions
434*0f4c859eSApple OSS Distributions IOLockUnlock(gIOPMInitLock);
435*0f4c859eSApple OSS Distributions
436*0f4c859eSApple OSS Distributions if (!gIOPMInitialized) {
437*0f4c859eSApple OSS Distributions return;
438*0f4c859eSApple OSS Distributions }
439*0f4c859eSApple OSS Distributions
440*0f4c859eSApple OSS Distributions pwrMgt = new IOServicePM;
441*0f4c859eSApple OSS Distributions pwrMgt->init();
442*0f4c859eSApple OSS Distributions setProperty(kPwrMgtKey, pwrMgt);
443*0f4c859eSApple OSS Distributions
444*0f4c859eSApple OSS Distributions queue_init(&pwrMgt->WorkChain);
445*0f4c859eSApple OSS Distributions queue_init(&pwrMgt->RequestHead);
446*0f4c859eSApple OSS Distributions queue_init(&pwrMgt->PMDriverCallQueue);
447*0f4c859eSApple OSS Distributions
448*0f4c859eSApple OSS Distributions fOwner = this;
449*0f4c859eSApple OSS Distributions fPMLock = IOLockAlloc();
450*0f4c859eSApple OSS Distributions fInterestedDrivers = new IOPMinformeeList;
451*0f4c859eSApple OSS Distributions fInterestedDrivers->initialize();
452*0f4c859eSApple OSS Distributions fDesiredPowerState = kPowerStateZero;
453*0f4c859eSApple OSS Distributions fDeviceDesire = kPowerStateZero;
454*0f4c859eSApple OSS Distributions fInitialPowerChange = true;
455*0f4c859eSApple OSS Distributions fInitialSetPowerState = true;
456*0f4c859eSApple OSS Distributions fPreviousRequestPowerFlags = 0;
457*0f4c859eSApple OSS Distributions fDeviceOverrideEnabled = false;
458*0f4c859eSApple OSS Distributions fMachineState = kIOPM_Finished;
459*0f4c859eSApple OSS Distributions fSavedMachineState = kIOPM_BadMachineState;
460*0f4c859eSApple OSS Distributions fIdleTimerMinPowerState = kPowerStateZero;
461*0f4c859eSApple OSS Distributions fActivityLock = IOLockAlloc();
462*0f4c859eSApple OSS Distributions fStrictTreeOrder = false;
463*0f4c859eSApple OSS Distributions fActivityTicklePowerState = kInvalidTicklePowerState;
464*0f4c859eSApple OSS Distributions fAdvisoryTicklePowerState = kInvalidTicklePowerState;
465*0f4c859eSApple OSS Distributions fControllingDriver = NULL;
466*0f4c859eSApple OSS Distributions fPowerStates = NULL;
467*0f4c859eSApple OSS Distributions fNumberOfPowerStates = 0;
468*0f4c859eSApple OSS Distributions fCurrentPowerState = kPowerStateZero;
469*0f4c859eSApple OSS Distributions fParentsCurrentPowerFlags = 0;
470*0f4c859eSApple OSS Distributions fMaxPowerState = kPowerStateZero;
471*0f4c859eSApple OSS Distributions fName = getName();
472*0f4c859eSApple OSS Distributions fParentsKnowState = false;
473*0f4c859eSApple OSS Distributions fSerialNumber = 0;
474*0f4c859eSApple OSS Distributions fResponseArray = NULL;
475*0f4c859eSApple OSS Distributions fNotifyClientArray = NULL;
476*0f4c859eSApple OSS Distributions fCurrentPowerConsumption = kIOPMUnknown;
477*0f4c859eSApple OSS Distributions fOverrideMaxPowerState = kIOPMPowerStateMax;
478*0f4c859eSApple OSS Distributions
479*0f4c859eSApple OSS Distributions if (!gIOPMRootNode && (getParentEntry(gIOPowerPlane) == getRegistryRoot())) {
480*0f4c859eSApple OSS Distributions gIOPMRootNode = this;
481*0f4c859eSApple OSS Distributions fParentsKnowState = true;
482*0f4c859eSApple OSS Distributions } else if (getProperty(kIOPMResetPowerStateOnWakeKey) == kOSBooleanTrue) {
483*0f4c859eSApple OSS Distributions fResetPowerStateOnWake = true;
484*0f4c859eSApple OSS Distributions }
485*0f4c859eSApple OSS Distributions
486*0f4c859eSApple OSS Distributions if (IS_ROOT_DOMAIN) {
487*0f4c859eSApple OSS Distributions fWatchdogTimer = thread_call_allocate(
488*0f4c859eSApple OSS Distributions &IOService::watchdog_timer_expired, (thread_call_param_t)this);
489*0f4c859eSApple OSS Distributions fWatchdogLock = IOLockAlloc();
490*0f4c859eSApple OSS Distributions
491*0f4c859eSApple OSS Distributions fBlockedArray = OSArray::withCapacity(4);
492*0f4c859eSApple OSS Distributions }
493*0f4c859eSApple OSS Distributions
494*0f4c859eSApple OSS Distributions fAckTimer = thread_call_allocate(
495*0f4c859eSApple OSS Distributions &IOService::ack_timer_expired, (thread_call_param_t)this);
496*0f4c859eSApple OSS Distributions #if USE_SETTLE_TIMER
497*0f4c859eSApple OSS Distributions fSettleTimer = thread_call_allocate(
498*0f4c859eSApple OSS Distributions &settle_timer_expired, (thread_call_param_t)this);
499*0f4c859eSApple OSS Distributions #endif
500*0f4c859eSApple OSS Distributions fIdleTimer = thread_call_allocate(
501*0f4c859eSApple OSS Distributions &idle_timer_expired, (thread_call_param_t)this);
502*0f4c859eSApple OSS Distributions fDriverCallTimer = thread_call_allocate(
503*0f4c859eSApple OSS Distributions &IOService::pmDriverCalloutTimer, (thread_call_param_t)this);
504*0f4c859eSApple OSS Distributions fDriverCallEntry = thread_call_allocate(
505*0f4c859eSApple OSS Distributions (thread_call_func_t) &IOService::pmDriverCallout, this);
506*0f4c859eSApple OSS Distributions assert(fDriverCallEntry);
507*0f4c859eSApple OSS Distributions
508*0f4c859eSApple OSS Distributions // Check for powerChangeDone override.
509*0f4c859eSApple OSS Distributions if (OSMemberFunctionCast(void (*)(void),
510*0f4c859eSApple OSS Distributions getResourceService(), &IOService::powerChangeDone) !=
511*0f4c859eSApple OSS Distributions OSMemberFunctionCast(void (*)(void),
512*0f4c859eSApple OSS Distributions this, &IOService::powerChangeDone)) {
513*0f4c859eSApple OSS Distributions fPCDFunctionOverride = true;
514*0f4c859eSApple OSS Distributions }
515*0f4c859eSApple OSS Distributions
516*0f4c859eSApple OSS Distributions #if PM_VARS_SUPPORT
517*0f4c859eSApple OSS Distributions IOPMprot * prot = new IOPMprot;
518*0f4c859eSApple OSS Distributions if (prot) {
519*0f4c859eSApple OSS Distributions prot->init();
520*0f4c859eSApple OSS Distributions prot->ourName = fName;
521*0f4c859eSApple OSS Distributions prot->thePlatform = gPlatform;
522*0f4c859eSApple OSS Distributions fPMVars = prot;
523*0f4c859eSApple OSS Distributions pm_vars = prot;
524*0f4c859eSApple OSS Distributions }
525*0f4c859eSApple OSS Distributions #else
526*0f4c859eSApple OSS Distributions pm_vars = (void *) (uintptr_t) true;
527*0f4c859eSApple OSS Distributions #endif
528*0f4c859eSApple OSS Distributions
529*0f4c859eSApple OSS Distributions initialized = true;
530*0f4c859eSApple OSS Distributions }
531*0f4c859eSApple OSS Distributions }
532*0f4c859eSApple OSS Distributions
533*0f4c859eSApple OSS Distributions //*********************************************************************************
534*0f4c859eSApple OSS Distributions // [private] PMfree
535*0f4c859eSApple OSS Distributions //
536*0f4c859eSApple OSS Distributions // Free the data created by PMinit. Only called from IOService::free().
537*0f4c859eSApple OSS Distributions //*********************************************************************************
538*0f4c859eSApple OSS Distributions
539*0f4c859eSApple OSS Distributions void
PMfree(void)540*0f4c859eSApple OSS Distributions IOService::PMfree( void )
541*0f4c859eSApple OSS Distributions {
542*0f4c859eSApple OSS Distributions initialized = false;
543*0f4c859eSApple OSS Distributions pm_vars = NULL;
544*0f4c859eSApple OSS Distributions
545*0f4c859eSApple OSS Distributions if (pwrMgt) {
546*0f4c859eSApple OSS Distributions assert(fMachineState == kIOPM_Finished);
547*0f4c859eSApple OSS Distributions assert(fInsertInterestSet == NULL);
548*0f4c859eSApple OSS Distributions assert(fRemoveInterestSet == NULL);
549*0f4c859eSApple OSS Distributions assert(fNotifyChildArray == NULL);
550*0f4c859eSApple OSS Distributions assert(queue_empty(&pwrMgt->RequestHead));
551*0f4c859eSApple OSS Distributions assert(queue_empty(&fPMDriverCallQueue));
552*0f4c859eSApple OSS Distributions
553*0f4c859eSApple OSS Distributions if (fWatchdogTimer) {
554*0f4c859eSApple OSS Distributions thread_call_cancel(fWatchdogTimer);
555*0f4c859eSApple OSS Distributions thread_call_free(fWatchdogTimer);
556*0f4c859eSApple OSS Distributions fWatchdogTimer = NULL;
557*0f4c859eSApple OSS Distributions }
558*0f4c859eSApple OSS Distributions
559*0f4c859eSApple OSS Distributions if (fWatchdogLock) {
560*0f4c859eSApple OSS Distributions IOLockFree(fWatchdogLock);
561*0f4c859eSApple OSS Distributions fWatchdogLock = NULL;
562*0f4c859eSApple OSS Distributions }
563*0f4c859eSApple OSS Distributions
564*0f4c859eSApple OSS Distributions if (fBlockedArray) {
565*0f4c859eSApple OSS Distributions fBlockedArray->release();
566*0f4c859eSApple OSS Distributions fBlockedArray = NULL;
567*0f4c859eSApple OSS Distributions }
568*0f4c859eSApple OSS Distributions #if USE_SETTLE_TIMER
569*0f4c859eSApple OSS Distributions if (fSettleTimer) {
570*0f4c859eSApple OSS Distributions thread_call_cancel(fSettleTimer);
571*0f4c859eSApple OSS Distributions thread_call_free(fSettleTimer);
572*0f4c859eSApple OSS Distributions fSettleTimer = NULL;
573*0f4c859eSApple OSS Distributions }
574*0f4c859eSApple OSS Distributions #endif
575*0f4c859eSApple OSS Distributions if (fAckTimer) {
576*0f4c859eSApple OSS Distributions thread_call_cancel(fAckTimer);
577*0f4c859eSApple OSS Distributions thread_call_free(fAckTimer);
578*0f4c859eSApple OSS Distributions fAckTimer = NULL;
579*0f4c859eSApple OSS Distributions }
580*0f4c859eSApple OSS Distributions if (fIdleTimer) {
581*0f4c859eSApple OSS Distributions thread_call_cancel(fIdleTimer);
582*0f4c859eSApple OSS Distributions thread_call_free(fIdleTimer);
583*0f4c859eSApple OSS Distributions fIdleTimer = NULL;
584*0f4c859eSApple OSS Distributions }
585*0f4c859eSApple OSS Distributions if (fDriverCallEntry) {
586*0f4c859eSApple OSS Distributions thread_call_free(fDriverCallEntry);
587*0f4c859eSApple OSS Distributions fDriverCallEntry = NULL;
588*0f4c859eSApple OSS Distributions }
589*0f4c859eSApple OSS Distributions if (fDriverCallTimer) {
590*0f4c859eSApple OSS Distributions thread_call_free(fDriverCallTimer);
591*0f4c859eSApple OSS Distributions fDriverCallTimer = NULL;
592*0f4c859eSApple OSS Distributions }
593*0f4c859eSApple OSS Distributions if (fPMLock) {
594*0f4c859eSApple OSS Distributions IOLockFree(fPMLock);
595*0f4c859eSApple OSS Distributions fPMLock = NULL;
596*0f4c859eSApple OSS Distributions }
597*0f4c859eSApple OSS Distributions if (fActivityLock) {
598*0f4c859eSApple OSS Distributions IOLockFree(fActivityLock);
599*0f4c859eSApple OSS Distributions fActivityLock = NULL;
600*0f4c859eSApple OSS Distributions }
601*0f4c859eSApple OSS Distributions if (fInterestedDrivers) {
602*0f4c859eSApple OSS Distributions fInterestedDrivers->release();
603*0f4c859eSApple OSS Distributions fInterestedDrivers = NULL;
604*0f4c859eSApple OSS Distributions }
605*0f4c859eSApple OSS Distributions if (fDriverCallParamSlots && fDriverCallParamPtr) {
606*0f4c859eSApple OSS Distributions IODelete(fDriverCallParamPtr, DriverCallParam, fDriverCallParamSlots);
607*0f4c859eSApple OSS Distributions fDriverCallParamPtr = NULL;
608*0f4c859eSApple OSS Distributions fDriverCallParamSlots = 0;
609*0f4c859eSApple OSS Distributions }
610*0f4c859eSApple OSS Distributions if (fResponseArray) {
611*0f4c859eSApple OSS Distributions fResponseArray->release();
612*0f4c859eSApple OSS Distributions fResponseArray = NULL;
613*0f4c859eSApple OSS Distributions }
614*0f4c859eSApple OSS Distributions if (fNotifyClientArray) {
615*0f4c859eSApple OSS Distributions fNotifyClientArray->release();
616*0f4c859eSApple OSS Distributions fNotifyClientArray = NULL;
617*0f4c859eSApple OSS Distributions }
618*0f4c859eSApple OSS Distributions if (fReportBuf && fNumberOfPowerStates) {
619*0f4c859eSApple OSS Distributions IOFreeData(fReportBuf, STATEREPORT_BUFSIZE(fNumberOfPowerStates));
620*0f4c859eSApple OSS Distributions fReportBuf = NULL;
621*0f4c859eSApple OSS Distributions }
622*0f4c859eSApple OSS Distributions if (fPowerStates && fNumberOfPowerStates) {
623*0f4c859eSApple OSS Distributions IODeleteData(fPowerStates, IOPMPSEntry, fNumberOfPowerStates);
624*0f4c859eSApple OSS Distributions fNumberOfPowerStates = 0;
625*0f4c859eSApple OSS Distributions fPowerStates = NULL;
626*0f4c859eSApple OSS Distributions }
627*0f4c859eSApple OSS Distributions if (fPowerClients) {
628*0f4c859eSApple OSS Distributions fPowerClients->release();
629*0f4c859eSApple OSS Distributions fPowerClients = NULL;
630*0f4c859eSApple OSS Distributions }
631*0f4c859eSApple OSS Distributions
632*0f4c859eSApple OSS Distributions #if PM_VARS_SUPPORT
633*0f4c859eSApple OSS Distributions if (fPMVars) {
634*0f4c859eSApple OSS Distributions fPMVars->release();
635*0f4c859eSApple OSS Distributions fPMVars = NULL;
636*0f4c859eSApple OSS Distributions }
637*0f4c859eSApple OSS Distributions #endif
638*0f4c859eSApple OSS Distributions
639*0f4c859eSApple OSS Distributions pwrMgt->release();
640*0f4c859eSApple OSS Distributions pwrMgt = NULL;
641*0f4c859eSApple OSS Distributions }
642*0f4c859eSApple OSS Distributions }
643*0f4c859eSApple OSS Distributions
644*0f4c859eSApple OSS Distributions void
PMDebug(uint32_t event,uintptr_t param1,uintptr_t param2)645*0f4c859eSApple OSS Distributions IOService::PMDebug( uint32_t event, uintptr_t param1, uintptr_t param2 )
646*0f4c859eSApple OSS Distributions {
647*0f4c859eSApple OSS Distributions OUR_PMLog(event, param1, param2);
648*0f4c859eSApple OSS Distributions }
649*0f4c859eSApple OSS Distributions
650*0f4c859eSApple OSS Distributions //*********************************************************************************
651*0f4c859eSApple OSS Distributions // [public] joinPMtree
652*0f4c859eSApple OSS Distributions //
653*0f4c859eSApple OSS Distributions // A policy-maker calls its nub here when initializing, to be attached into
654*0f4c859eSApple OSS Distributions // the power management hierarchy. The default function is to call the
655*0f4c859eSApple OSS Distributions // platform expert, which knows how to do it. This method is overridden
656*0f4c859eSApple OSS Distributions // by a nub subclass which may either know how to do it, or may need to
657*0f4c859eSApple OSS Distributions // take other action.
658*0f4c859eSApple OSS Distributions //
659*0f4c859eSApple OSS Distributions // This may be the only "power management" method used in a nub,
660*0f4c859eSApple OSS Distributions // meaning it may not be initialized for power management.
661*0f4c859eSApple OSS Distributions //*********************************************************************************
662*0f4c859eSApple OSS Distributions
663*0f4c859eSApple OSS Distributions void
joinPMtree(IOService * driver)664*0f4c859eSApple OSS Distributions IOService::joinPMtree( IOService * driver )
665*0f4c859eSApple OSS Distributions {
666*0f4c859eSApple OSS Distributions IOPlatformExpert * platform;
667*0f4c859eSApple OSS Distributions
668*0f4c859eSApple OSS Distributions platform = getPlatform();
669*0f4c859eSApple OSS Distributions assert(platform != NULL);
670*0f4c859eSApple OSS Distributions platform->PMRegisterDevice(this, driver);
671*0f4c859eSApple OSS Distributions }
672*0f4c859eSApple OSS Distributions
673*0f4c859eSApple OSS Distributions #ifndef __LP64__
674*0f4c859eSApple OSS Distributions //*********************************************************************************
675*0f4c859eSApple OSS Distributions // [deprecated] youAreRoot
676*0f4c859eSApple OSS Distributions //
677*0f4c859eSApple OSS Distributions // Power Managment is informing us that we are the root power domain.
678*0f4c859eSApple OSS Distributions //*********************************************************************************
679*0f4c859eSApple OSS Distributions
680*0f4c859eSApple OSS Distributions IOReturn
youAreRoot(void)681*0f4c859eSApple OSS Distributions IOService::youAreRoot( void )
682*0f4c859eSApple OSS Distributions {
683*0f4c859eSApple OSS Distributions return IOPMNoErr;
684*0f4c859eSApple OSS Distributions }
685*0f4c859eSApple OSS Distributions #endif /* !__LP64__ */
686*0f4c859eSApple OSS Distributions
687*0f4c859eSApple OSS Distributions //*********************************************************************************
688*0f4c859eSApple OSS Distributions // [public] PMstop
689*0f4c859eSApple OSS Distributions //
690*0f4c859eSApple OSS Distributions // Immediately stop driver callouts. Schedule an async stop request to detach
691*0f4c859eSApple OSS Distributions // from power plane.
692*0f4c859eSApple OSS Distributions //*********************************************************************************
693*0f4c859eSApple OSS Distributions
694*0f4c859eSApple OSS Distributions void
PMstop(void)695*0f4c859eSApple OSS Distributions IOService::PMstop( void )
696*0f4c859eSApple OSS Distributions {
697*0f4c859eSApple OSS Distributions IOPMRequest * request;
698*0f4c859eSApple OSS Distributions
699*0f4c859eSApple OSS Distributions if (!initialized) {
700*0f4c859eSApple OSS Distributions return;
701*0f4c859eSApple OSS Distributions }
702*0f4c859eSApple OSS Distributions
703*0f4c859eSApple OSS Distributions PM_LOCK();
704*0f4c859eSApple OSS Distributions
705*0f4c859eSApple OSS Distributions if (fLockedFlags.PMStop) {
706*0f4c859eSApple OSS Distributions PM_LOG2("%s: PMstop() already stopped\n", fName);
707*0f4c859eSApple OSS Distributions PM_UNLOCK();
708*0f4c859eSApple OSS Distributions return;
709*0f4c859eSApple OSS Distributions }
710*0f4c859eSApple OSS Distributions
711*0f4c859eSApple OSS Distributions // Inhibit future driver calls.
712*0f4c859eSApple OSS Distributions fLockedFlags.PMStop = true;
713*0f4c859eSApple OSS Distributions
714*0f4c859eSApple OSS Distributions // Wait for all prior driver calls to finish.
715*0f4c859eSApple OSS Distributions waitForPMDriverCall();
716*0f4c859eSApple OSS Distributions
717*0f4c859eSApple OSS Distributions PM_UNLOCK();
718*0f4c859eSApple OSS Distributions
719*0f4c859eSApple OSS Distributions // The rest of the work is performed async.
720*0f4c859eSApple OSS Distributions request = acquirePMRequest( this, kIOPMRequestTypePMStop );
721*0f4c859eSApple OSS Distributions if (request) {
722*0f4c859eSApple OSS Distributions PM_LOG2("%s: %p PMstop\n", getName(), OBFUSCATE(this));
723*0f4c859eSApple OSS Distributions submitPMRequest( request );
724*0f4c859eSApple OSS Distributions }
725*0f4c859eSApple OSS Distributions }
726*0f4c859eSApple OSS Distributions
727*0f4c859eSApple OSS Distributions //*********************************************************************************
728*0f4c859eSApple OSS Distributions // [private] handlePMstop
729*0f4c859eSApple OSS Distributions //
730*0f4c859eSApple OSS Distributions // Disconnect the node from all parents and children in the power plane.
731*0f4c859eSApple OSS Distributions //*********************************************************************************
732*0f4c859eSApple OSS Distributions
733*0f4c859eSApple OSS Distributions void
handlePMstop(IOPMRequest * request)734*0f4c859eSApple OSS Distributions IOService::handlePMstop( IOPMRequest * request )
735*0f4c859eSApple OSS Distributions {
736*0f4c859eSApple OSS Distributions OSIterator * iter;
737*0f4c859eSApple OSS Distributions OSObject * next;
738*0f4c859eSApple OSS Distributions IOPowerConnection * connection;
739*0f4c859eSApple OSS Distributions IOService * theChild;
740*0f4c859eSApple OSS Distributions IOService * theParent;
741*0f4c859eSApple OSS Distributions
742*0f4c859eSApple OSS Distributions PM_ASSERT_IN_GATE();
743*0f4c859eSApple OSS Distributions PM_LOG2("%s: %p %s start\n", getName(), OBFUSCATE(this), __FUNCTION__);
744*0f4c859eSApple OSS Distributions
745*0f4c859eSApple OSS Distributions // remove driver from prevent system sleep lists
746*0f4c859eSApple OSS Distributions getPMRootDomain()->updatePreventIdleSleepList(this, false);
747*0f4c859eSApple OSS Distributions getPMRootDomain()->updatePreventSystemSleepList(this, false);
748*0f4c859eSApple OSS Distributions
749*0f4c859eSApple OSS Distributions // remove the property
750*0f4c859eSApple OSS Distributions removeProperty(kPwrMgtKey);
751*0f4c859eSApple OSS Distributions
752*0f4c859eSApple OSS Distributions // detach parents
753*0f4c859eSApple OSS Distributions iter = getParentIterator(gIOPowerPlane);
754*0f4c859eSApple OSS Distributions if (iter) {
755*0f4c859eSApple OSS Distributions while ((next = iter->getNextObject())) {
756*0f4c859eSApple OSS Distributions if ((connection = OSDynamicCast(IOPowerConnection, next))) {
757*0f4c859eSApple OSS Distributions theParent = (IOService *)connection->copyParentEntry(gIOPowerPlane);
758*0f4c859eSApple OSS Distributions if (theParent) {
759*0f4c859eSApple OSS Distributions theParent->removePowerChild(connection);
760*0f4c859eSApple OSS Distributions theParent->release();
761*0f4c859eSApple OSS Distributions }
762*0f4c859eSApple OSS Distributions }
763*0f4c859eSApple OSS Distributions }
764*0f4c859eSApple OSS Distributions iter->release();
765*0f4c859eSApple OSS Distributions }
766*0f4c859eSApple OSS Distributions
767*0f4c859eSApple OSS Distributions // detach IOConnections
768*0f4c859eSApple OSS Distributions detachAbove( gIOPowerPlane );
769*0f4c859eSApple OSS Distributions
770*0f4c859eSApple OSS Distributions // no more power state changes
771*0f4c859eSApple OSS Distributions fParentsKnowState = false;
772*0f4c859eSApple OSS Distributions
773*0f4c859eSApple OSS Distributions // detach children
774*0f4c859eSApple OSS Distributions iter = getChildIterator(gIOPowerPlane);
775*0f4c859eSApple OSS Distributions if (iter) {
776*0f4c859eSApple OSS Distributions while ((next = iter->getNextObject())) {
777*0f4c859eSApple OSS Distributions if ((connection = OSDynamicCast(IOPowerConnection, next))) {
778*0f4c859eSApple OSS Distributions theChild = ((IOService *)(connection->copyChildEntry(gIOPowerPlane)));
779*0f4c859eSApple OSS Distributions if (theChild) {
780*0f4c859eSApple OSS Distributions // detach nub from child
781*0f4c859eSApple OSS Distributions connection->detachFromChild(theChild, gIOPowerPlane);
782*0f4c859eSApple OSS Distributions theChild->release();
783*0f4c859eSApple OSS Distributions }
784*0f4c859eSApple OSS Distributions // detach us from nub
785*0f4c859eSApple OSS Distributions detachFromChild(connection, gIOPowerPlane);
786*0f4c859eSApple OSS Distributions }
787*0f4c859eSApple OSS Distributions }
788*0f4c859eSApple OSS Distributions iter->release();
789*0f4c859eSApple OSS Distributions }
790*0f4c859eSApple OSS Distributions
791*0f4c859eSApple OSS Distributions // Remove all interested drivers from the list, including the power
792*0f4c859eSApple OSS Distributions // controlling driver.
793*0f4c859eSApple OSS Distributions //
794*0f4c859eSApple OSS Distributions // Usually, the controlling driver and the policy-maker functionality
795*0f4c859eSApple OSS Distributions // are implemented by the same object, and without the deregistration,
796*0f4c859eSApple OSS Distributions // the object will be holding an extra retain on itself, and cannot
797*0f4c859eSApple OSS Distributions // be freed.
798*0f4c859eSApple OSS Distributions
799*0f4c859eSApple OSS Distributions if (fInterestedDrivers) {
800*0f4c859eSApple OSS Distributions IOPMinformeeList * list = fInterestedDrivers;
801*0f4c859eSApple OSS Distributions IOPMinformee * item;
802*0f4c859eSApple OSS Distributions
803*0f4c859eSApple OSS Distributions PM_LOCK();
804*0f4c859eSApple OSS Distributions while ((item = list->firstInList())) {
805*0f4c859eSApple OSS Distributions list->removeFromList(item->whatObject);
806*0f4c859eSApple OSS Distributions }
807*0f4c859eSApple OSS Distributions PM_UNLOCK();
808*0f4c859eSApple OSS Distributions }
809*0f4c859eSApple OSS Distributions
810*0f4c859eSApple OSS Distributions // Clear idle period to prevent idleTimerExpired() from servicing
811*0f4c859eSApple OSS Distributions // idle timer expirations.
812*0f4c859eSApple OSS Distributions
813*0f4c859eSApple OSS Distributions fIdleTimerPeriod = 0;
814*0f4c859eSApple OSS Distributions if (fIdleTimer && thread_call_cancel(fIdleTimer)) {
815*0f4c859eSApple OSS Distributions release();
816*0f4c859eSApple OSS Distributions }
817*0f4c859eSApple OSS Distributions
818*0f4c859eSApple OSS Distributions PM_LOG2("%s: %p %s done\n", getName(), OBFUSCATE(this), __FUNCTION__);
819*0f4c859eSApple OSS Distributions }
820*0f4c859eSApple OSS Distributions
821*0f4c859eSApple OSS Distributions //*********************************************************************************
822*0f4c859eSApple OSS Distributions // [public] addPowerChild
823*0f4c859eSApple OSS Distributions //
824*0f4c859eSApple OSS Distributions // Power Management is informing us who our children are.
825*0f4c859eSApple OSS Distributions //*********************************************************************************
826*0f4c859eSApple OSS Distributions
827*0f4c859eSApple OSS Distributions IOReturn
addPowerChild(IOService * child)828*0f4c859eSApple OSS Distributions IOService::addPowerChild( IOService * child )
829*0f4c859eSApple OSS Distributions {
830*0f4c859eSApple OSS Distributions IOPowerConnection * connection = NULL;
831*0f4c859eSApple OSS Distributions IOPMRequest * requests[3] = {NULL, NULL, NULL};
832*0f4c859eSApple OSS Distributions OSIterator * iter;
833*0f4c859eSApple OSS Distributions bool ok = true;
834*0f4c859eSApple OSS Distributions
835*0f4c859eSApple OSS Distributions if (!child) {
836*0f4c859eSApple OSS Distributions return kIOReturnBadArgument;
837*0f4c859eSApple OSS Distributions }
838*0f4c859eSApple OSS Distributions
839*0f4c859eSApple OSS Distributions if (!initialized || !child->initialized) {
840*0f4c859eSApple OSS Distributions return IOPMNotYetInitialized;
841*0f4c859eSApple OSS Distributions }
842*0f4c859eSApple OSS Distributions
843*0f4c859eSApple OSS Distributions OUR_PMLog( kPMLogAddChild, (uintptr_t) child, 0 );
844*0f4c859eSApple OSS Distributions
845*0f4c859eSApple OSS Distributions do {
846*0f4c859eSApple OSS Distributions // Is this child already one of our children?
847*0f4c859eSApple OSS Distributions
848*0f4c859eSApple OSS Distributions iter = child->getParentIterator( gIOPowerPlane );
849*0f4c859eSApple OSS Distributions if (iter) {
850*0f4c859eSApple OSS Distributions IORegistryEntry * entry;
851*0f4c859eSApple OSS Distributions OSObject * next;
852*0f4c859eSApple OSS Distributions
853*0f4c859eSApple OSS Distributions while ((next = iter->getNextObject())) {
854*0f4c859eSApple OSS Distributions if ((entry = OSDynamicCast(IORegistryEntry, next)) &&
855*0f4c859eSApple OSS Distributions isChild(entry, gIOPowerPlane)) {
856*0f4c859eSApple OSS Distributions ok = false;
857*0f4c859eSApple OSS Distributions break;
858*0f4c859eSApple OSS Distributions }
859*0f4c859eSApple OSS Distributions }
860*0f4c859eSApple OSS Distributions iter->release();
861*0f4c859eSApple OSS Distributions }
862*0f4c859eSApple OSS Distributions if (!ok) {
863*0f4c859eSApple OSS Distributions PM_LOG2("%s: %s (%p) is already a child\n",
864*0f4c859eSApple OSS Distributions getName(), child->getName(), OBFUSCATE(child));
865*0f4c859eSApple OSS Distributions break;
866*0f4c859eSApple OSS Distributions }
867*0f4c859eSApple OSS Distributions
868*0f4c859eSApple OSS Distributions // Add the child to the power plane immediately, but the
869*0f4c859eSApple OSS Distributions // joining connection is marked as not ready.
870*0f4c859eSApple OSS Distributions // We want the child to appear in the power plane before
871*0f4c859eSApple OSS Distributions // returning to the caller, but don't want the caller to
872*0f4c859eSApple OSS Distributions // block on the PM work loop.
873*0f4c859eSApple OSS Distributions
874*0f4c859eSApple OSS Distributions connection = new IOPowerConnection;
875*0f4c859eSApple OSS Distributions if (!connection) {
876*0f4c859eSApple OSS Distributions break;
877*0f4c859eSApple OSS Distributions }
878*0f4c859eSApple OSS Distributions
879*0f4c859eSApple OSS Distributions // Create a chain of PM requests to perform the bottom-half
880*0f4c859eSApple OSS Distributions // work from the PM work loop.
881*0f4c859eSApple OSS Distributions
882*0f4c859eSApple OSS Distributions requests[0] = acquirePMRequest(
883*0f4c859eSApple OSS Distributions /* target */ this,
884*0f4c859eSApple OSS Distributions /* type */ kIOPMRequestTypeAddPowerChild1 );
885*0f4c859eSApple OSS Distributions
886*0f4c859eSApple OSS Distributions requests[1] = acquirePMRequest(
887*0f4c859eSApple OSS Distributions /* target */ child,
888*0f4c859eSApple OSS Distributions /* type */ kIOPMRequestTypeAddPowerChild2 );
889*0f4c859eSApple OSS Distributions
890*0f4c859eSApple OSS Distributions requests[2] = acquirePMRequest(
891*0f4c859eSApple OSS Distributions /* target */ this,
892*0f4c859eSApple OSS Distributions /* type */ kIOPMRequestTypeAddPowerChild3 );
893*0f4c859eSApple OSS Distributions
894*0f4c859eSApple OSS Distributions if (!requests[0] || !requests[1] || !requests[2]) {
895*0f4c859eSApple OSS Distributions break;
896*0f4c859eSApple OSS Distributions }
897*0f4c859eSApple OSS Distributions
898*0f4c859eSApple OSS Distributions requests[0]->attachNextRequest( requests[1] );
899*0f4c859eSApple OSS Distributions requests[1]->attachNextRequest( requests[2] );
900*0f4c859eSApple OSS Distributions
901*0f4c859eSApple OSS Distributions connection->init();
902*0f4c859eSApple OSS Distributions connection->start(this);
903*0f4c859eSApple OSS Distributions connection->setAwaitingAck(false);
904*0f4c859eSApple OSS Distributions connection->setReadyFlag(false);
905*0f4c859eSApple OSS Distributions
906*0f4c859eSApple OSS Distributions attachToChild( connection, gIOPowerPlane );
907*0f4c859eSApple OSS Distributions connection->attachToChild( child, gIOPowerPlane );
908*0f4c859eSApple OSS Distributions
909*0f4c859eSApple OSS Distributions // connection needs to be released
910*0f4c859eSApple OSS Distributions requests[0]->fArg0 = connection;
911*0f4c859eSApple OSS Distributions requests[1]->fArg0 = connection;
912*0f4c859eSApple OSS Distributions requests[2]->fArg0 = connection;
913*0f4c859eSApple OSS Distributions
914*0f4c859eSApple OSS Distributions submitPMRequests( requests, 3 );
915*0f4c859eSApple OSS Distributions return kIOReturnSuccess;
916*0f4c859eSApple OSS Distributions }while (false);
917*0f4c859eSApple OSS Distributions
918*0f4c859eSApple OSS Distributions if (connection) {
919*0f4c859eSApple OSS Distributions connection->release();
920*0f4c859eSApple OSS Distributions }
921*0f4c859eSApple OSS Distributions if (requests[0]) {
922*0f4c859eSApple OSS Distributions releasePMRequest(requests[0]);
923*0f4c859eSApple OSS Distributions }
924*0f4c859eSApple OSS Distributions if (requests[1]) {
925*0f4c859eSApple OSS Distributions releasePMRequest(requests[1]);
926*0f4c859eSApple OSS Distributions }
927*0f4c859eSApple OSS Distributions if (requests[2]) {
928*0f4c859eSApple OSS Distributions releasePMRequest(requests[2]);
929*0f4c859eSApple OSS Distributions }
930*0f4c859eSApple OSS Distributions
931*0f4c859eSApple OSS Distributions // Silent failure, to prevent platform drivers from adding the child
932*0f4c859eSApple OSS Distributions // to the root domain.
933*0f4c859eSApple OSS Distributions
934*0f4c859eSApple OSS Distributions return kIOReturnSuccess;
935*0f4c859eSApple OSS Distributions }
936*0f4c859eSApple OSS Distributions
937*0f4c859eSApple OSS Distributions //*********************************************************************************
938*0f4c859eSApple OSS Distributions // [private] addPowerChild1
939*0f4c859eSApple OSS Distributions //
940*0f4c859eSApple OSS Distributions // Step 1/3 of adding a power child. Called on the power parent.
941*0f4c859eSApple OSS Distributions //*********************************************************************************
942*0f4c859eSApple OSS Distributions
943*0f4c859eSApple OSS Distributions void
addPowerChild1(IOPMRequest * request)944*0f4c859eSApple OSS Distributions IOService::addPowerChild1( IOPMRequest * request )
945*0f4c859eSApple OSS Distributions {
946*0f4c859eSApple OSS Distributions IOPMPowerStateIndex tempDesire = kPowerStateZero;
947*0f4c859eSApple OSS Distributions
948*0f4c859eSApple OSS Distributions // Make us temporary usable before adding the child.
949*0f4c859eSApple OSS Distributions
950*0f4c859eSApple OSS Distributions PM_ASSERT_IN_GATE();
951*0f4c859eSApple OSS Distributions OUR_PMLog( kPMLogMakeUsable, kPMLogMakeUsable, 0 );
952*0f4c859eSApple OSS Distributions
953*0f4c859eSApple OSS Distributions if (fControllingDriver && inPlane(gIOPowerPlane) && fParentsKnowState) {
954*0f4c859eSApple OSS Distributions tempDesire = fHighestPowerState;
955*0f4c859eSApple OSS Distributions }
956*0f4c859eSApple OSS Distributions
957*0f4c859eSApple OSS Distributions if ((tempDesire != kPowerStateZero) &&
958*0f4c859eSApple OSS Distributions (IS_PM_ROOT || (StateOrder(fMaxPowerState) >= StateOrder(tempDesire)))) {
959*0f4c859eSApple OSS Distributions adjustPowerState(tempDesire);
960*0f4c859eSApple OSS Distributions }
961*0f4c859eSApple OSS Distributions }
962*0f4c859eSApple OSS Distributions
963*0f4c859eSApple OSS Distributions //*********************************************************************************
964*0f4c859eSApple OSS Distributions // [private] addPowerChild2
965*0f4c859eSApple OSS Distributions //
966*0f4c859eSApple OSS Distributions // Step 2/3 of adding a power child. Called on the joining child.
967*0f4c859eSApple OSS Distributions // Execution blocked behind addPowerChild1.
968*0f4c859eSApple OSS Distributions //*********************************************************************************
969*0f4c859eSApple OSS Distributions
970*0f4c859eSApple OSS Distributions void
addPowerChild2(IOPMRequest * request)971*0f4c859eSApple OSS Distributions IOService::addPowerChild2( IOPMRequest * request )
972*0f4c859eSApple OSS Distributions {
973*0f4c859eSApple OSS Distributions IOPowerConnection * connection = (IOPowerConnection *) request->fArg0;
974*0f4c859eSApple OSS Distributions IOService * parent;
975*0f4c859eSApple OSS Distributions IOPMPowerFlags powerFlags;
976*0f4c859eSApple OSS Distributions bool knowsState;
977*0f4c859eSApple OSS Distributions IOPMPowerStateIndex powerState;
978*0f4c859eSApple OSS Distributions IOPMPowerStateIndex tempDesire;
979*0f4c859eSApple OSS Distributions
980*0f4c859eSApple OSS Distributions PM_ASSERT_IN_GATE();
981*0f4c859eSApple OSS Distributions parent = (IOService *) connection->getParentEntry(gIOPowerPlane);
982*0f4c859eSApple OSS Distributions
983*0f4c859eSApple OSS Distributions if (!parent || !inPlane(gIOPowerPlane)) {
984*0f4c859eSApple OSS Distributions PM_LOG("%s: addPowerChild2 not in power plane\n", getName());
985*0f4c859eSApple OSS Distributions return;
986*0f4c859eSApple OSS Distributions }
987*0f4c859eSApple OSS Distributions
988*0f4c859eSApple OSS Distributions // Parent will be waiting for us to complete this stage.
989*0f4c859eSApple OSS Distributions // It is safe to directly access parent's vars.
990*0f4c859eSApple OSS Distributions
991*0f4c859eSApple OSS Distributions knowsState = (parent->fPowerStates) && (parent->fParentsKnowState);
992*0f4c859eSApple OSS Distributions powerState = parent->fCurrentPowerState;
993*0f4c859eSApple OSS Distributions
994*0f4c859eSApple OSS Distributions if (knowsState) {
995*0f4c859eSApple OSS Distributions powerFlags = parent->fPowerStates[powerState].outputPowerFlags;
996*0f4c859eSApple OSS Distributions } else {
997*0f4c859eSApple OSS Distributions powerFlags = 0;
998*0f4c859eSApple OSS Distributions }
999*0f4c859eSApple OSS Distributions
1000*0f4c859eSApple OSS Distributions // Set our power parent.
1001*0f4c859eSApple OSS Distributions
1002*0f4c859eSApple OSS Distributions OUR_PMLog(kPMLogSetParent, knowsState, powerFlags);
1003*0f4c859eSApple OSS Distributions
1004*0f4c859eSApple OSS Distributions setParentInfo( powerFlags, connection, knowsState );
1005*0f4c859eSApple OSS Distributions
1006*0f4c859eSApple OSS Distributions connection->setReadyFlag(true);
1007*0f4c859eSApple OSS Distributions
1008*0f4c859eSApple OSS Distributions if (fControllingDriver && fParentsKnowState) {
1009*0f4c859eSApple OSS Distributions fMaxPowerState = fControllingDriver->maxCapabilityForDomainState(fParentsCurrentPowerFlags);
1010*0f4c859eSApple OSS Distributions // initially change into the state we are already in
1011*0f4c859eSApple OSS Distributions tempDesire = fControllingDriver->initialPowerStateForDomainState(fParentsCurrentPowerFlags);
1012*0f4c859eSApple OSS Distributions fPreviousRequestPowerFlags = (IOPMPowerFlags)(-1);
1013*0f4c859eSApple OSS Distributions adjustPowerState(tempDesire);
1014*0f4c859eSApple OSS Distributions }
1015*0f4c859eSApple OSS Distributions }
1016*0f4c859eSApple OSS Distributions
1017*0f4c859eSApple OSS Distributions //*********************************************************************************
1018*0f4c859eSApple OSS Distributions // [private] addPowerChild3
1019*0f4c859eSApple OSS Distributions //
1020*0f4c859eSApple OSS Distributions // Step 3/3 of adding a power child. Called on the parent.
1021*0f4c859eSApple OSS Distributions // Execution blocked behind addPowerChild2.
1022*0f4c859eSApple OSS Distributions //*********************************************************************************
1023*0f4c859eSApple OSS Distributions
1024*0f4c859eSApple OSS Distributions void
addPowerChild3(IOPMRequest * request)1025*0f4c859eSApple OSS Distributions IOService::addPowerChild3( IOPMRequest * request )
1026*0f4c859eSApple OSS Distributions {
1027*0f4c859eSApple OSS Distributions IOPowerConnection * connection = (IOPowerConnection *) request->fArg0;
1028*0f4c859eSApple OSS Distributions IOService * child;
1029*0f4c859eSApple OSS Distributions IOPMrootDomain * rootDomain = getPMRootDomain();
1030*0f4c859eSApple OSS Distributions
1031*0f4c859eSApple OSS Distributions PM_ASSERT_IN_GATE();
1032*0f4c859eSApple OSS Distributions child = (IOService *) connection->getChildEntry(gIOPowerPlane);
1033*0f4c859eSApple OSS Distributions
1034*0f4c859eSApple OSS Distributions if (child && inPlane(gIOPowerPlane)) {
1035*0f4c859eSApple OSS Distributions if ((this != rootDomain) && child->getProperty("IOPMStrictTreeOrder")) {
1036*0f4c859eSApple OSS Distributions PM_LOG1("%s: strict PM order enforced\n", getName());
1037*0f4c859eSApple OSS Distributions fStrictTreeOrder = true;
1038*0f4c859eSApple OSS Distributions }
1039*0f4c859eSApple OSS Distributions
1040*0f4c859eSApple OSS Distributions if (rootDomain) {
1041*0f4c859eSApple OSS Distributions rootDomain->joinAggressiveness( child );
1042*0f4c859eSApple OSS Distributions }
1043*0f4c859eSApple OSS Distributions } else {
1044*0f4c859eSApple OSS Distributions PM_LOG("%s: addPowerChild3 not in power plane\n", getName());
1045*0f4c859eSApple OSS Distributions }
1046*0f4c859eSApple OSS Distributions
1047*0f4c859eSApple OSS Distributions connection->release();
1048*0f4c859eSApple OSS Distributions }
1049*0f4c859eSApple OSS Distributions
1050*0f4c859eSApple OSS Distributions #ifndef __LP64__
1051*0f4c859eSApple OSS Distributions //*********************************************************************************
1052*0f4c859eSApple OSS Distributions // [deprecated] setPowerParent
1053*0f4c859eSApple OSS Distributions //
1054*0f4c859eSApple OSS Distributions // Power Management is informing us who our parent is.
1055*0f4c859eSApple OSS Distributions // If we have a controlling driver, find out, given our newly-informed
1056*0f4c859eSApple OSS Distributions // power domain state, what state it would be in, and then tell it
1057*0f4c859eSApple OSS Distributions // to assume that state.
1058*0f4c859eSApple OSS Distributions //*********************************************************************************
1059*0f4c859eSApple OSS Distributions
1060*0f4c859eSApple OSS Distributions IOReturn
setPowerParent(IOPowerConnection * theParent,bool stateKnown,IOPMPowerFlags powerFlags)1061*0f4c859eSApple OSS Distributions IOService::setPowerParent(
1062*0f4c859eSApple OSS Distributions IOPowerConnection * theParent, bool stateKnown, IOPMPowerFlags powerFlags )
1063*0f4c859eSApple OSS Distributions {
1064*0f4c859eSApple OSS Distributions return kIOReturnUnsupported;
1065*0f4c859eSApple OSS Distributions }
1066*0f4c859eSApple OSS Distributions #endif /* !__LP64__ */
1067*0f4c859eSApple OSS Distributions
1068*0f4c859eSApple OSS Distributions //*********************************************************************************
1069*0f4c859eSApple OSS Distributions // [public] removePowerChild
1070*0f4c859eSApple OSS Distributions //
1071*0f4c859eSApple OSS Distributions // Called on a parent whose child is being removed by PMstop().
1072*0f4c859eSApple OSS Distributions //*********************************************************************************
1073*0f4c859eSApple OSS Distributions
1074*0f4c859eSApple OSS Distributions IOReturn
removePowerChild(IOPowerConnection * theNub)1075*0f4c859eSApple OSS Distributions IOService::removePowerChild( IOPowerConnection * theNub )
1076*0f4c859eSApple OSS Distributions {
1077*0f4c859eSApple OSS Distributions IORegistryEntry * theChild;
1078*0f4c859eSApple OSS Distributions
1079*0f4c859eSApple OSS Distributions PM_ASSERT_IN_GATE();
1080*0f4c859eSApple OSS Distributions OUR_PMLog( kPMLogRemoveChild, 0, 0 );
1081*0f4c859eSApple OSS Distributions
1082*0f4c859eSApple OSS Distributions theNub->retain();
1083*0f4c859eSApple OSS Distributions
1084*0f4c859eSApple OSS Distributions // detach nub from child
1085*0f4c859eSApple OSS Distributions theChild = theNub->copyChildEntry(gIOPowerPlane);
1086*0f4c859eSApple OSS Distributions if (theChild) {
1087*0f4c859eSApple OSS Distributions theNub->detachFromChild(theChild, gIOPowerPlane);
1088*0f4c859eSApple OSS Distributions theChild->release();
1089*0f4c859eSApple OSS Distributions }
1090*0f4c859eSApple OSS Distributions // detach from the nub
1091*0f4c859eSApple OSS Distributions detachFromChild(theNub, gIOPowerPlane);
1092*0f4c859eSApple OSS Distributions
1093*0f4c859eSApple OSS Distributions // Are we awaiting an ack from this child?
1094*0f4c859eSApple OSS Distributions if (theNub->getAwaitingAck()) {
1095*0f4c859eSApple OSS Distributions // yes, pretend we got one
1096*0f4c859eSApple OSS Distributions theNub->setAwaitingAck(false);
1097*0f4c859eSApple OSS Distributions if (fHeadNotePendingAcks != 0) {
1098*0f4c859eSApple OSS Distributions // that's one fewer ack to worry about
1099*0f4c859eSApple OSS Distributions fHeadNotePendingAcks--;
1100*0f4c859eSApple OSS Distributions
1101*0f4c859eSApple OSS Distributions // is that the last?
1102*0f4c859eSApple OSS Distributions if (fHeadNotePendingAcks == 0) {
1103*0f4c859eSApple OSS Distributions stop_ack_timer();
1104*0f4c859eSApple OSS Distributions getPMRootDomain()->reset_watchdog_timer(this, 0);
1105*0f4c859eSApple OSS Distributions
1106*0f4c859eSApple OSS Distributions // This parent may have a request in the work queue that is
1107*0f4c859eSApple OSS Distributions // blocked on fHeadNotePendingAcks=0. And removePowerChild()
1108*0f4c859eSApple OSS Distributions // is called while executing the child's PMstop request so they
1109*0f4c859eSApple OSS Distributions // can occur simultaneously. IOPMWorkQueue::checkForWork() must
1110*0f4c859eSApple OSS Distributions // restart and check all request queues again.
1111*0f4c859eSApple OSS Distributions
1112*0f4c859eSApple OSS Distributions gIOPMWorkQueue->incrementProducerCount();
1113*0f4c859eSApple OSS Distributions }
1114*0f4c859eSApple OSS Distributions }
1115*0f4c859eSApple OSS Distributions }
1116*0f4c859eSApple OSS Distributions
1117*0f4c859eSApple OSS Distributions theNub->release();
1118*0f4c859eSApple OSS Distributions
1119*0f4c859eSApple OSS Distributions // A child has gone away, re-scan children desires and clamp bits.
1120*0f4c859eSApple OSS Distributions // The fPendingAdjustPowerRequest helps to reduce redundant parent work.
1121*0f4c859eSApple OSS Distributions
1122*0f4c859eSApple OSS Distributions if (!fAdjustPowerScheduled) {
1123*0f4c859eSApple OSS Distributions IOPMRequest * request;
1124*0f4c859eSApple OSS Distributions request = acquirePMRequest( this, kIOPMRequestTypeAdjustPowerState );
1125*0f4c859eSApple OSS Distributions if (request) {
1126*0f4c859eSApple OSS Distributions submitPMRequest( request );
1127*0f4c859eSApple OSS Distributions fAdjustPowerScheduled = true;
1128*0f4c859eSApple OSS Distributions }
1129*0f4c859eSApple OSS Distributions }
1130*0f4c859eSApple OSS Distributions
1131*0f4c859eSApple OSS Distributions return IOPMNoErr;
1132*0f4c859eSApple OSS Distributions }
1133*0f4c859eSApple OSS Distributions
1134*0f4c859eSApple OSS Distributions //*********************************************************************************
1135*0f4c859eSApple OSS Distributions // [public] registerPowerDriver
1136*0f4c859eSApple OSS Distributions //
1137*0f4c859eSApple OSS Distributions // A driver has called us volunteering to control power to our device.
1138*0f4c859eSApple OSS Distributions //*********************************************************************************
1139*0f4c859eSApple OSS Distributions
1140*0f4c859eSApple OSS Distributions IOReturn
registerPowerDriver(IOService * powerDriver,IOPMPowerState * powerStates,unsigned long numberOfStates)1141*0f4c859eSApple OSS Distributions IOService::registerPowerDriver(
1142*0f4c859eSApple OSS Distributions IOService * powerDriver,
1143*0f4c859eSApple OSS Distributions IOPMPowerState * powerStates,
1144*0f4c859eSApple OSS Distributions unsigned long numberOfStates )
1145*0f4c859eSApple OSS Distributions {
1146*0f4c859eSApple OSS Distributions IOPMRequest * request;
1147*0f4c859eSApple OSS Distributions IOPMPSEntry * powerStatesCopy = NULL;
1148*0f4c859eSApple OSS Distributions IOPMPowerStateIndex stateOrder;
1149*0f4c859eSApple OSS Distributions IOReturn error = kIOReturnSuccess;
1150*0f4c859eSApple OSS Distributions
1151*0f4c859eSApple OSS Distributions if (!initialized) {
1152*0f4c859eSApple OSS Distributions return IOPMNotYetInitialized;
1153*0f4c859eSApple OSS Distributions }
1154*0f4c859eSApple OSS Distributions
1155*0f4c859eSApple OSS Distributions if (!powerStates || (numberOfStates < 2)) {
1156*0f4c859eSApple OSS Distributions OUR_PMLog(kPMLogControllingDriverErr5, numberOfStates, 0);
1157*0f4c859eSApple OSS Distributions return kIOReturnBadArgument;
1158*0f4c859eSApple OSS Distributions }
1159*0f4c859eSApple OSS Distributions
1160*0f4c859eSApple OSS Distributions if (!powerDriver || !powerDriver->initialized) {
1161*0f4c859eSApple OSS Distributions OUR_PMLog(kPMLogControllingDriverErr4, 0, 0);
1162*0f4c859eSApple OSS Distributions return kIOReturnBadArgument;
1163*0f4c859eSApple OSS Distributions }
1164*0f4c859eSApple OSS Distributions
1165*0f4c859eSApple OSS Distributions if (powerStates[0].version > kIOPMPowerStateVersion2) {
1166*0f4c859eSApple OSS Distributions OUR_PMLog(kPMLogControllingDriverErr1, powerStates[0].version, 0);
1167*0f4c859eSApple OSS Distributions return kIOReturnBadArgument;
1168*0f4c859eSApple OSS Distributions }
1169*0f4c859eSApple OSS Distributions
1170*0f4c859eSApple OSS Distributions do {
1171*0f4c859eSApple OSS Distributions // Make a copy of the supplied power state array.
1172*0f4c859eSApple OSS Distributions powerStatesCopy = IONewData(IOPMPSEntry, numberOfStates);
1173*0f4c859eSApple OSS Distributions if (!powerStatesCopy) {
1174*0f4c859eSApple OSS Distributions error = kIOReturnNoMemory;
1175*0f4c859eSApple OSS Distributions break;
1176*0f4c859eSApple OSS Distributions }
1177*0f4c859eSApple OSS Distributions
1178*0f4c859eSApple OSS Distributions // Initialize to bogus values
1179*0f4c859eSApple OSS Distributions for (IOPMPowerStateIndex i = 0; i < numberOfStates; i++) {
1180*0f4c859eSApple OSS Distributions powerStatesCopy[i].stateOrderToIndex = kIOPMPowerStateMax;
1181*0f4c859eSApple OSS Distributions }
1182*0f4c859eSApple OSS Distributions
1183*0f4c859eSApple OSS Distributions for (uint32_t i = 0; i < numberOfStates; i++) {
1184*0f4c859eSApple OSS Distributions powerStatesCopy[i].capabilityFlags = powerStates[i].capabilityFlags;
1185*0f4c859eSApple OSS Distributions powerStatesCopy[i].outputPowerFlags = powerStates[i].outputPowerCharacter;
1186*0f4c859eSApple OSS Distributions powerStatesCopy[i].inputPowerFlags = powerStates[i].inputPowerRequirement;
1187*0f4c859eSApple OSS Distributions powerStatesCopy[i].staticPower = powerStates[i].staticPower;
1188*0f4c859eSApple OSS Distributions #if USE_SETTLE_TIMER
1189*0f4c859eSApple OSS Distributions powerStatesCopy[i].settleUpTime = powerStates[i].settleUpTime;
1190*0f4c859eSApple OSS Distributions powerStatesCopy[i].settleDownTime = powerStates[i].settleDownTime;
1191*0f4c859eSApple OSS Distributions #endif
1192*0f4c859eSApple OSS Distributions if (powerStates[i].version >= kIOPMPowerStateVersion2) {
1193*0f4c859eSApple OSS Distributions stateOrder = powerStates[i].stateOrder;
1194*0f4c859eSApple OSS Distributions } else {
1195*0f4c859eSApple OSS Distributions stateOrder = i;
1196*0f4c859eSApple OSS Distributions }
1197*0f4c859eSApple OSS Distributions
1198*0f4c859eSApple OSS Distributions if (stateOrder < numberOfStates) {
1199*0f4c859eSApple OSS Distributions powerStatesCopy[i].stateOrder = stateOrder;
1200*0f4c859eSApple OSS Distributions powerStatesCopy[stateOrder].stateOrderToIndex = i;
1201*0f4c859eSApple OSS Distributions }
1202*0f4c859eSApple OSS Distributions }
1203*0f4c859eSApple OSS Distributions
1204*0f4c859eSApple OSS Distributions for (IOPMPowerStateIndex i = 0; i < numberOfStates; i++) {
1205*0f4c859eSApple OSS Distributions if (powerStatesCopy[i].stateOrderToIndex == kIOPMPowerStateMax) {
1206*0f4c859eSApple OSS Distributions // power state order missing
1207*0f4c859eSApple OSS Distributions error = kIOReturnBadArgument;
1208*0f4c859eSApple OSS Distributions break;
1209*0f4c859eSApple OSS Distributions }
1210*0f4c859eSApple OSS Distributions }
1211*0f4c859eSApple OSS Distributions if (kIOReturnSuccess != error) {
1212*0f4c859eSApple OSS Distributions break;
1213*0f4c859eSApple OSS Distributions }
1214*0f4c859eSApple OSS Distributions
1215*0f4c859eSApple OSS Distributions request = acquirePMRequest( this, kIOPMRequestTypeRegisterPowerDriver );
1216*0f4c859eSApple OSS Distributions if (!request) {
1217*0f4c859eSApple OSS Distributions error = kIOReturnNoMemory;
1218*0f4c859eSApple OSS Distributions break;
1219*0f4c859eSApple OSS Distributions }
1220*0f4c859eSApple OSS Distributions
1221*0f4c859eSApple OSS Distributions powerDriver->retain();
1222*0f4c859eSApple OSS Distributions request->fArg0 = (void *) powerDriver;
1223*0f4c859eSApple OSS Distributions request->fArg1 = (void *) powerStatesCopy;
1224*0f4c859eSApple OSS Distributions request->fArg2 = (void *) numberOfStates;
1225*0f4c859eSApple OSS Distributions
1226*0f4c859eSApple OSS Distributions submitPMRequest( request );
1227*0f4c859eSApple OSS Distributions return kIOReturnSuccess;
1228*0f4c859eSApple OSS Distributions }while (false);
1229*0f4c859eSApple OSS Distributions
1230*0f4c859eSApple OSS Distributions if (powerStatesCopy) {
1231*0f4c859eSApple OSS Distributions IODeleteData(powerStatesCopy, IOPMPSEntry, numberOfStates);
1232*0f4c859eSApple OSS Distributions }
1233*0f4c859eSApple OSS Distributions
1234*0f4c859eSApple OSS Distributions return error;
1235*0f4c859eSApple OSS Distributions }
1236*0f4c859eSApple OSS Distributions
1237*0f4c859eSApple OSS Distributions //*********************************************************************************
1238*0f4c859eSApple OSS Distributions // [private] handleRegisterPowerDriver
1239*0f4c859eSApple OSS Distributions //*********************************************************************************
1240*0f4c859eSApple OSS Distributions
1241*0f4c859eSApple OSS Distributions void
handleRegisterPowerDriver(IOPMRequest * request)1242*0f4c859eSApple OSS Distributions IOService::handleRegisterPowerDriver( IOPMRequest * request )
1243*0f4c859eSApple OSS Distributions {
1244*0f4c859eSApple OSS Distributions IOService * powerDriver = (IOService *) request->fArg0;
1245*0f4c859eSApple OSS Distributions IOPMPSEntry * powerStates = (IOPMPSEntry *) request->fArg1;
1246*0f4c859eSApple OSS Distributions IOPMPowerStateIndex numberOfStates = (IOPMPowerStateIndex) request->fArg2;
1247*0f4c859eSApple OSS Distributions IOPMPowerStateIndex i, stateIndex;
1248*0f4c859eSApple OSS Distributions IOPMPowerStateIndex lowestPowerState;
1249*0f4c859eSApple OSS Distributions IOService * root;
1250*0f4c859eSApple OSS Distributions OSIterator * iter;
1251*0f4c859eSApple OSS Distributions
1252*0f4c859eSApple OSS Distributions PM_ASSERT_IN_GATE();
1253*0f4c859eSApple OSS Distributions assert(powerStates);
1254*0f4c859eSApple OSS Distributions assert(powerDriver);
1255*0f4c859eSApple OSS Distributions assert(numberOfStates > 1);
1256*0f4c859eSApple OSS Distributions
1257*0f4c859eSApple OSS Distributions if (!fNumberOfPowerStates) {
1258*0f4c859eSApple OSS Distributions OUR_PMLog(kPMLogControllingDriver, numberOfStates, kIOPMPowerStateVersion1);
1259*0f4c859eSApple OSS Distributions
1260*0f4c859eSApple OSS Distributions fPowerStates = powerStates;
1261*0f4c859eSApple OSS Distributions fNumberOfPowerStates = numberOfStates;
1262*0f4c859eSApple OSS Distributions fControllingDriver = powerDriver;
1263*0f4c859eSApple OSS Distributions fCurrentCapabilityFlags = fPowerStates[0].capabilityFlags;
1264*0f4c859eSApple OSS Distributions
1265*0f4c859eSApple OSS Distributions lowestPowerState = fPowerStates[0].stateOrderToIndex;
1266*0f4c859eSApple OSS Distributions fHighestPowerState = fPowerStates[numberOfStates - 1].stateOrderToIndex;
1267*0f4c859eSApple OSS Distributions
1268*0f4c859eSApple OSS Distributions {
1269*0f4c859eSApple OSS Distributions uint32_t aotFlags;
1270*0f4c859eSApple OSS Distributions IOService * service;
1271*0f4c859eSApple OSS Distributions OSObject * object;
1272*0f4c859eSApple OSS Distributions OSData * data;
1273*0f4c859eSApple OSS Distributions
1274*0f4c859eSApple OSS Distributions // Disallow kIOPMAOTPower states unless device tree enabled
1275*0f4c859eSApple OSS Distributions
1276*0f4c859eSApple OSS Distributions aotFlags = 0;
1277*0f4c859eSApple OSS Distributions service = this;
1278*0f4c859eSApple OSS Distributions while (service && !service->inPlane(gIODTPlane)) {
1279*0f4c859eSApple OSS Distributions service = service->getProvider();
1280*0f4c859eSApple OSS Distributions }
1281*0f4c859eSApple OSS Distributions if (service) {
1282*0f4c859eSApple OSS Distributions object = service->copyProperty(kIOPMAOTPowerKey, gIODTPlane);
1283*0f4c859eSApple OSS Distributions data = OSDynamicCast(OSData, object);
1284*0f4c859eSApple OSS Distributions if (data && (data->getLength() >= sizeof(uint32_t))) {
1285*0f4c859eSApple OSS Distributions aotFlags = ((uint32_t *)data->getBytesNoCopy())[0];
1286*0f4c859eSApple OSS Distributions }
1287*0f4c859eSApple OSS Distributions OSSafeReleaseNULL(object);
1288*0f4c859eSApple OSS Distributions }
1289*0f4c859eSApple OSS Distributions if (!aotFlags) {
1290*0f4c859eSApple OSS Distributions for (i = 0; i < numberOfStates; i++) {
1291*0f4c859eSApple OSS Distributions if (kIOPMAOTPower & fPowerStates[i].inputPowerFlags) {
1292*0f4c859eSApple OSS Distributions fPowerStates[i].inputPowerFlags = 0xFFFFFFFF;
1293*0f4c859eSApple OSS Distributions fPowerStates[i].capabilityFlags = 0;
1294*0f4c859eSApple OSS Distributions fPowerStates[i].outputPowerFlags = 0;
1295*0f4c859eSApple OSS Distributions }
1296*0f4c859eSApple OSS Distributions }
1297*0f4c859eSApple OSS Distributions }
1298*0f4c859eSApple OSS Distributions }
1299*0f4c859eSApple OSS Distributions
1300*0f4c859eSApple OSS Distributions // OR'in all the output power flags
1301*0f4c859eSApple OSS Distributions fMergedOutputPowerFlags = 0;
1302*0f4c859eSApple OSS Distributions fDeviceUsablePowerState = lowestPowerState;
1303*0f4c859eSApple OSS Distributions for (i = 0; i < numberOfStates; i++) {
1304*0f4c859eSApple OSS Distributions fMergedOutputPowerFlags |= fPowerStates[i].outputPowerFlags;
1305*0f4c859eSApple OSS Distributions
1306*0f4c859eSApple OSS Distributions stateIndex = fPowerStates[i].stateOrderToIndex;
1307*0f4c859eSApple OSS Distributions assert(stateIndex < numberOfStates);
1308*0f4c859eSApple OSS Distributions if ((fDeviceUsablePowerState == lowestPowerState) &&
1309*0f4c859eSApple OSS Distributions (fPowerStates[stateIndex].capabilityFlags & IOPMDeviceUsable)) {
1310*0f4c859eSApple OSS Distributions // The minimum power state that the device is usable
1311*0f4c859eSApple OSS Distributions fDeviceUsablePowerState = stateIndex;
1312*0f4c859eSApple OSS Distributions }
1313*0f4c859eSApple OSS Distributions }
1314*0f4c859eSApple OSS Distributions
1315*0f4c859eSApple OSS Distributions // Register powerDriver as interested, unless already done.
1316*0f4c859eSApple OSS Distributions // We don't want to register the default implementation since
1317*0f4c859eSApple OSS Distributions // it does nothing. One ramification of not always registering
1318*0f4c859eSApple OSS Distributions // is the one fewer retain count held.
1319*0f4c859eSApple OSS Distributions
1320*0f4c859eSApple OSS Distributions root = getPlatform()->getProvider();
1321*0f4c859eSApple OSS Distributions assert(root);
1322*0f4c859eSApple OSS Distributions if (!root ||
1323*0f4c859eSApple OSS Distributions ((OSMemberFunctionCast(void (*)(void),
1324*0f4c859eSApple OSS Distributions root, &IOService::powerStateDidChangeTo)) !=
1325*0f4c859eSApple OSS Distributions ((OSMemberFunctionCast(void (*)(void),
1326*0f4c859eSApple OSS Distributions this, &IOService::powerStateDidChangeTo)))) ||
1327*0f4c859eSApple OSS Distributions ((OSMemberFunctionCast(void (*)(void),
1328*0f4c859eSApple OSS Distributions root, &IOService::powerStateWillChangeTo)) !=
1329*0f4c859eSApple OSS Distributions ((OSMemberFunctionCast(void (*)(void),
1330*0f4c859eSApple OSS Distributions this, &IOService::powerStateWillChangeTo))))) {
1331*0f4c859eSApple OSS Distributions if (fInterestedDrivers->findItem(powerDriver) == NULL) {
1332*0f4c859eSApple OSS Distributions PM_LOCK();
1333*0f4c859eSApple OSS Distributions fInterestedDrivers->appendNewInformee(powerDriver);
1334*0f4c859eSApple OSS Distributions PM_UNLOCK();
1335*0f4c859eSApple OSS Distributions }
1336*0f4c859eSApple OSS Distributions }
1337*0f4c859eSApple OSS Distributions
1338*0f4c859eSApple OSS Distributions // Examine all existing power clients and perform limit check.
1339*0f4c859eSApple OSS Distributions
1340*0f4c859eSApple OSS Distributions if (fPowerClients &&
1341*0f4c859eSApple OSS Distributions (iter = OSCollectionIterator::withCollection(fPowerClients))) {
1342*0f4c859eSApple OSS Distributions const OSSymbol * client;
1343*0f4c859eSApple OSS Distributions while ((client = (const OSSymbol *) iter->getNextObject())) {
1344*0f4c859eSApple OSS Distributions IOPMPowerStateIndex powerState = getPowerStateForClient(client);
1345*0f4c859eSApple OSS Distributions if (powerState >= numberOfStates) {
1346*0f4c859eSApple OSS Distributions updatePowerClient(client, fHighestPowerState);
1347*0f4c859eSApple OSS Distributions }
1348*0f4c859eSApple OSS Distributions }
1349*0f4c859eSApple OSS Distributions iter->release();
1350*0f4c859eSApple OSS Distributions }
1351*0f4c859eSApple OSS Distributions
1352*0f4c859eSApple OSS Distributions // Populate IOPMActions for a few special services
1353*0f4c859eSApple OSS Distributions getPMRootDomain()->tagPowerPlaneService(this, &fPMActions, fNumberOfPowerStates - 1);
1354*0f4c859eSApple OSS Distributions
1355*0f4c859eSApple OSS Distributions if (inPlane(gIOPowerPlane) && fParentsKnowState) {
1356*0f4c859eSApple OSS Distributions IOPMPowerStateIndex tempDesire;
1357*0f4c859eSApple OSS Distributions fMaxPowerState = fControllingDriver->maxCapabilityForDomainState(fParentsCurrentPowerFlags);
1358*0f4c859eSApple OSS Distributions // initially change into the state we are already in
1359*0f4c859eSApple OSS Distributions tempDesire = fControllingDriver->initialPowerStateForDomainState(fParentsCurrentPowerFlags);
1360*0f4c859eSApple OSS Distributions adjustPowerState(tempDesire);
1361*0f4c859eSApple OSS Distributions }
1362*0f4c859eSApple OSS Distributions } else {
1363*0f4c859eSApple OSS Distributions OUR_PMLog(kPMLogControllingDriverErr2, numberOfStates, 0);
1364*0f4c859eSApple OSS Distributions IODeleteData(powerStates, IOPMPSEntry, numberOfStates);
1365*0f4c859eSApple OSS Distributions }
1366*0f4c859eSApple OSS Distributions
1367*0f4c859eSApple OSS Distributions powerDriver->release();
1368*0f4c859eSApple OSS Distributions }
1369*0f4c859eSApple OSS Distributions
1370*0f4c859eSApple OSS Distributions //*********************************************************************************
1371*0f4c859eSApple OSS Distributions // [public] registerInterestedDriver
1372*0f4c859eSApple OSS Distributions //
1373*0f4c859eSApple OSS Distributions // Add the caller to our list of interested drivers and return our current
1374*0f4c859eSApple OSS Distributions // power state. If we don't have a power-controlling driver yet, we will
1375*0f4c859eSApple OSS Distributions // call this interested driver again later when we do get a driver and find
1376*0f4c859eSApple OSS Distributions // out what the current power state of the device is.
1377*0f4c859eSApple OSS Distributions //*********************************************************************************
1378*0f4c859eSApple OSS Distributions
1379*0f4c859eSApple OSS Distributions IOPMPowerFlags
registerInterestedDriver(IOService * driver)1380*0f4c859eSApple OSS Distributions IOService::registerInterestedDriver( IOService * driver )
1381*0f4c859eSApple OSS Distributions {
1382*0f4c859eSApple OSS Distributions IOPMRequest * request;
1383*0f4c859eSApple OSS Distributions bool signal;
1384*0f4c859eSApple OSS Distributions
1385*0f4c859eSApple OSS Distributions if (!driver || !initialized || !fInterestedDrivers) {
1386*0f4c859eSApple OSS Distributions return 0;
1387*0f4c859eSApple OSS Distributions }
1388*0f4c859eSApple OSS Distributions
1389*0f4c859eSApple OSS Distributions PM_LOCK();
1390*0f4c859eSApple OSS Distributions signal = (!fInsertInterestSet && !fRemoveInterestSet);
1391*0f4c859eSApple OSS Distributions if (fInsertInterestSet == NULL) {
1392*0f4c859eSApple OSS Distributions fInsertInterestSet = OSSet::withCapacity(4);
1393*0f4c859eSApple OSS Distributions }
1394*0f4c859eSApple OSS Distributions if (fInsertInterestSet) {
1395*0f4c859eSApple OSS Distributions fInsertInterestSet->setObject(driver);
1396*0f4c859eSApple OSS Distributions if (fRemoveInterestSet) {
1397*0f4c859eSApple OSS Distributions fRemoveInterestSet->removeObject(driver);
1398*0f4c859eSApple OSS Distributions }
1399*0f4c859eSApple OSS Distributions }
1400*0f4c859eSApple OSS Distributions PM_UNLOCK();
1401*0f4c859eSApple OSS Distributions
1402*0f4c859eSApple OSS Distributions if (signal) {
1403*0f4c859eSApple OSS Distributions request = acquirePMRequest( this, kIOPMRequestTypeInterestChanged );
1404*0f4c859eSApple OSS Distributions if (request) {
1405*0f4c859eSApple OSS Distributions submitPMRequest( request );
1406*0f4c859eSApple OSS Distributions }
1407*0f4c859eSApple OSS Distributions }
1408*0f4c859eSApple OSS Distributions
1409*0f4c859eSApple OSS Distributions // This return value cannot be trusted, but return a value
1410*0f4c859eSApple OSS Distributions // for those clients that care.
1411*0f4c859eSApple OSS Distributions
1412*0f4c859eSApple OSS Distributions OUR_PMLog(kPMLogInterestedDriver, kIOPMDeviceUsable, 2);
1413*0f4c859eSApple OSS Distributions return kIOPMDeviceUsable;
1414*0f4c859eSApple OSS Distributions }
1415*0f4c859eSApple OSS Distributions
1416*0f4c859eSApple OSS Distributions //*********************************************************************************
1417*0f4c859eSApple OSS Distributions // [public] deRegisterInterestedDriver
1418*0f4c859eSApple OSS Distributions //*********************************************************************************
1419*0f4c859eSApple OSS Distributions
1420*0f4c859eSApple OSS Distributions IOReturn
deRegisterInterestedDriver(IOService * driver)1421*0f4c859eSApple OSS Distributions IOService::deRegisterInterestedDriver( IOService * driver )
1422*0f4c859eSApple OSS Distributions {
1423*0f4c859eSApple OSS Distributions IOPMinformee * item;
1424*0f4c859eSApple OSS Distributions IOPMRequest * request;
1425*0f4c859eSApple OSS Distributions bool signal;
1426*0f4c859eSApple OSS Distributions
1427*0f4c859eSApple OSS Distributions if (!driver) {
1428*0f4c859eSApple OSS Distributions return kIOReturnBadArgument;
1429*0f4c859eSApple OSS Distributions }
1430*0f4c859eSApple OSS Distributions if (!initialized || !fInterestedDrivers) {
1431*0f4c859eSApple OSS Distributions return IOPMNotPowerManaged;
1432*0f4c859eSApple OSS Distributions }
1433*0f4c859eSApple OSS Distributions
1434*0f4c859eSApple OSS Distributions PM_LOCK();
1435*0f4c859eSApple OSS Distributions if (fInsertInterestSet) {
1436*0f4c859eSApple OSS Distributions fInsertInterestSet->removeObject(driver);
1437*0f4c859eSApple OSS Distributions }
1438*0f4c859eSApple OSS Distributions
1439*0f4c859eSApple OSS Distributions item = fInterestedDrivers->findItem(driver);
1440*0f4c859eSApple OSS Distributions if (!item) {
1441*0f4c859eSApple OSS Distributions PM_UNLOCK();
1442*0f4c859eSApple OSS Distributions return kIOReturnNotFound;
1443*0f4c859eSApple OSS Distributions }
1444*0f4c859eSApple OSS Distributions
1445*0f4c859eSApple OSS Distributions signal = (!fRemoveInterestSet && !fInsertInterestSet);
1446*0f4c859eSApple OSS Distributions if (fRemoveInterestSet == NULL) {
1447*0f4c859eSApple OSS Distributions fRemoveInterestSet = OSSet::withCapacity(4);
1448*0f4c859eSApple OSS Distributions }
1449*0f4c859eSApple OSS Distributions if (fRemoveInterestSet) {
1450*0f4c859eSApple OSS Distributions fRemoveInterestSet->setObject(driver);
1451*0f4c859eSApple OSS Distributions if (item->active) {
1452*0f4c859eSApple OSS Distributions item->active = false;
1453*0f4c859eSApple OSS Distributions waitForPMDriverCall( driver );
1454*0f4c859eSApple OSS Distributions }
1455*0f4c859eSApple OSS Distributions }
1456*0f4c859eSApple OSS Distributions PM_UNLOCK();
1457*0f4c859eSApple OSS Distributions
1458*0f4c859eSApple OSS Distributions if (signal) {
1459*0f4c859eSApple OSS Distributions request = acquirePMRequest( this, kIOPMRequestTypeInterestChanged );
1460*0f4c859eSApple OSS Distributions if (request) {
1461*0f4c859eSApple OSS Distributions submitPMRequest( request );
1462*0f4c859eSApple OSS Distributions }
1463*0f4c859eSApple OSS Distributions }
1464*0f4c859eSApple OSS Distributions
1465*0f4c859eSApple OSS Distributions return IOPMNoErr;
1466*0f4c859eSApple OSS Distributions }
1467*0f4c859eSApple OSS Distributions
1468*0f4c859eSApple OSS Distributions //*********************************************************************************
1469*0f4c859eSApple OSS Distributions // [private] handleInterestChanged
1470*0f4c859eSApple OSS Distributions //
1471*0f4c859eSApple OSS Distributions // Handle interest added or removed.
1472*0f4c859eSApple OSS Distributions //*********************************************************************************
1473*0f4c859eSApple OSS Distributions
1474*0f4c859eSApple OSS Distributions void
handleInterestChanged(IOPMRequest * request)1475*0f4c859eSApple OSS Distributions IOService::handleInterestChanged( IOPMRequest * request )
1476*0f4c859eSApple OSS Distributions {
1477*0f4c859eSApple OSS Distributions IOService * driver;
1478*0f4c859eSApple OSS Distributions IOPMinformee * informee;
1479*0f4c859eSApple OSS Distributions IOPMinformeeList * list = fInterestedDrivers;
1480*0f4c859eSApple OSS Distributions
1481*0f4c859eSApple OSS Distributions PM_LOCK();
1482*0f4c859eSApple OSS Distributions
1483*0f4c859eSApple OSS Distributions if (fInsertInterestSet) {
1484*0f4c859eSApple OSS Distributions while ((driver = (IOService *) fInsertInterestSet->getAnyObject())) {
1485*0f4c859eSApple OSS Distributions if (list->findItem(driver) == NULL) {
1486*0f4c859eSApple OSS Distributions list->appendNewInformee(driver);
1487*0f4c859eSApple OSS Distributions }
1488*0f4c859eSApple OSS Distributions fInsertInterestSet->removeObject(driver);
1489*0f4c859eSApple OSS Distributions }
1490*0f4c859eSApple OSS Distributions fInsertInterestSet->release();
1491*0f4c859eSApple OSS Distributions fInsertInterestSet = NULL;
1492*0f4c859eSApple OSS Distributions }
1493*0f4c859eSApple OSS Distributions
1494*0f4c859eSApple OSS Distributions if (fRemoveInterestSet) {
1495*0f4c859eSApple OSS Distributions while ((driver = (IOService *) fRemoveInterestSet->getAnyObject())) {
1496*0f4c859eSApple OSS Distributions informee = list->findItem(driver);
1497*0f4c859eSApple OSS Distributions if (informee) {
1498*0f4c859eSApple OSS Distributions // Clean-up async interest acknowledgement
1499*0f4c859eSApple OSS Distributions if (fHeadNotePendingAcks && informee->timer) {
1500*0f4c859eSApple OSS Distributions informee->timer = 0;
1501*0f4c859eSApple OSS Distributions fHeadNotePendingAcks--;
1502*0f4c859eSApple OSS Distributions }
1503*0f4c859eSApple OSS Distributions list->removeFromList(driver);
1504*0f4c859eSApple OSS Distributions }
1505*0f4c859eSApple OSS Distributions fRemoveInterestSet->removeObject(driver);
1506*0f4c859eSApple OSS Distributions }
1507*0f4c859eSApple OSS Distributions fRemoveInterestSet->release();
1508*0f4c859eSApple OSS Distributions fRemoveInterestSet = NULL;
1509*0f4c859eSApple OSS Distributions }
1510*0f4c859eSApple OSS Distributions
1511*0f4c859eSApple OSS Distributions PM_UNLOCK();
1512*0f4c859eSApple OSS Distributions }
1513*0f4c859eSApple OSS Distributions
1514*0f4c859eSApple OSS Distributions //*********************************************************************************
1515*0f4c859eSApple OSS Distributions // [public] acknowledgePowerChange
1516*0f4c859eSApple OSS Distributions //
1517*0f4c859eSApple OSS Distributions // After we notified one of the interested drivers or a power-domain child
1518*0f4c859eSApple OSS Distributions // of an impending change in power, it has called to say it is now
1519*0f4c859eSApple OSS Distributions // prepared for the change. If this object is the last to
1520*0f4c859eSApple OSS Distributions // acknowledge this change, we take whatever action we have been waiting
1521*0f4c859eSApple OSS Distributions // for.
1522*0f4c859eSApple OSS Distributions // That may include acknowledging to our parent. In this case, we do it
1523*0f4c859eSApple OSS Distributions // last of all to insure that this doesn't cause the parent to call us some-
1524*0f4c859eSApple OSS Distributions // where else and alter data we are relying on here (like the very existance
1525*0f4c859eSApple OSS Distributions // of a "current change note".)
1526*0f4c859eSApple OSS Distributions //*********************************************************************************
1527*0f4c859eSApple OSS Distributions
1528*0f4c859eSApple OSS Distributions IOReturn
acknowledgePowerChange(IOService * whichObject)1529*0f4c859eSApple OSS Distributions IOService::acknowledgePowerChange( IOService * whichObject )
1530*0f4c859eSApple OSS Distributions {
1531*0f4c859eSApple OSS Distributions IOPMRequest * request;
1532*0f4c859eSApple OSS Distributions
1533*0f4c859eSApple OSS Distributions if (!initialized) {
1534*0f4c859eSApple OSS Distributions return IOPMNotYetInitialized;
1535*0f4c859eSApple OSS Distributions }
1536*0f4c859eSApple OSS Distributions if (!whichObject) {
1537*0f4c859eSApple OSS Distributions return kIOReturnBadArgument;
1538*0f4c859eSApple OSS Distributions }
1539*0f4c859eSApple OSS Distributions
1540*0f4c859eSApple OSS Distributions request = acquirePMRequest( this, kIOPMRequestTypeAckPowerChange );
1541*0f4c859eSApple OSS Distributions if (!request) {
1542*0f4c859eSApple OSS Distributions return kIOReturnNoMemory;
1543*0f4c859eSApple OSS Distributions }
1544*0f4c859eSApple OSS Distributions
1545*0f4c859eSApple OSS Distributions whichObject->retain();
1546*0f4c859eSApple OSS Distributions request->fArg0 = whichObject;
1547*0f4c859eSApple OSS Distributions
1548*0f4c859eSApple OSS Distributions submitPMRequest( request );
1549*0f4c859eSApple OSS Distributions return IOPMNoErr;
1550*0f4c859eSApple OSS Distributions }
1551*0f4c859eSApple OSS Distributions
1552*0f4c859eSApple OSS Distributions //*********************************************************************************
1553*0f4c859eSApple OSS Distributions // [private] handleAcknowledgePowerChange
1554*0f4c859eSApple OSS Distributions //*********************************************************************************
1555*0f4c859eSApple OSS Distributions
1556*0f4c859eSApple OSS Distributions bool
handleAcknowledgePowerChange(IOPMRequest * request)1557*0f4c859eSApple OSS Distributions IOService::handleAcknowledgePowerChange( IOPMRequest * request )
1558*0f4c859eSApple OSS Distributions {
1559*0f4c859eSApple OSS Distributions IOPMinformee * informee;
1560*0f4c859eSApple OSS Distributions IOPMPowerStateIndex childPower = kIOPMUnknown;
1561*0f4c859eSApple OSS Distributions IOService * theChild;
1562*0f4c859eSApple OSS Distributions IOService * whichObject;
1563*0f4c859eSApple OSS Distributions bool all_acked = false;
1564*0f4c859eSApple OSS Distributions
1565*0f4c859eSApple OSS Distributions PM_ASSERT_IN_GATE();
1566*0f4c859eSApple OSS Distributions whichObject = (IOService *) request->fArg0;
1567*0f4c859eSApple OSS Distributions assert(whichObject);
1568*0f4c859eSApple OSS Distributions
1569*0f4c859eSApple OSS Distributions // one of our interested drivers?
1570*0f4c859eSApple OSS Distributions informee = fInterestedDrivers->findItem( whichObject );
1571*0f4c859eSApple OSS Distributions if (informee == NULL) {
1572*0f4c859eSApple OSS Distributions if (!isChild(whichObject, gIOPowerPlane)) {
1573*0f4c859eSApple OSS Distributions OUR_PMLog(kPMLogAcknowledgeErr1, 0, 0);
1574*0f4c859eSApple OSS Distributions goto no_err;
1575*0f4c859eSApple OSS Distributions } else {
1576*0f4c859eSApple OSS Distributions OUR_PMLog(kPMLogChildAcknowledge, fHeadNotePendingAcks, 0);
1577*0f4c859eSApple OSS Distributions }
1578*0f4c859eSApple OSS Distributions } else {
1579*0f4c859eSApple OSS Distributions OUR_PMLog(kPMLogDriverAcknowledge, fHeadNotePendingAcks, 0);
1580*0f4c859eSApple OSS Distributions }
1581*0f4c859eSApple OSS Distributions
1582*0f4c859eSApple OSS Distributions if (fHeadNotePendingAcks != 0) {
1583*0f4c859eSApple OSS Distributions assert(fPowerStates != NULL);
1584*0f4c859eSApple OSS Distributions
1585*0f4c859eSApple OSS Distributions // yes, make sure we're expecting acks
1586*0f4c859eSApple OSS Distributions if (informee != NULL) {
1587*0f4c859eSApple OSS Distributions // it's an interested driver
1588*0f4c859eSApple OSS Distributions // make sure we're expecting this ack
1589*0f4c859eSApple OSS Distributions if (informee->timer != 0) {
1590*0f4c859eSApple OSS Distributions SOCD_TRACE_XNU(PM_INFORM_POWER_CHANGE_ACK,
1591*0f4c859eSApple OSS Distributions ADDR(informee->whatObject->getMetaClass()),
1592*0f4c859eSApple OSS Distributions ADDR(this->getMetaClass()),
1593*0f4c859eSApple OSS Distributions PACK_2X32(VALUE(this->getRegistryEntryID()), VALUE(informee->whatObject->getRegistryEntryID())),
1594*0f4c859eSApple OSS Distributions PACK_2X32(VALUE(0), VALUE(fDriverCallReason)));
1595*0f4c859eSApple OSS Distributions
1596*0f4c859eSApple OSS Distributions if (informee->timer > 0) {
1597*0f4c859eSApple OSS Distributions uint64_t nsec = computeTimeDeltaNS(&informee->startTime);
1598*0f4c859eSApple OSS Distributions if (nsec > gIOPMSetPowerStateLogNS) {
1599*0f4c859eSApple OSS Distributions getPMRootDomain()->pmStatsRecordApplicationResponse(
1600*0f4c859eSApple OSS Distributions gIOPMStatsDriverPSChangeSlow, informee->whatObject->getName(),
1601*0f4c859eSApple OSS Distributions fDriverCallReason, NS_TO_MS(nsec), informee->whatObject->getRegistryEntryID(),
1602*0f4c859eSApple OSS Distributions NULL, fHeadNotePowerState, true);
1603*0f4c859eSApple OSS Distributions }
1604*0f4c859eSApple OSS Distributions }
1605*0f4c859eSApple OSS Distributions
1606*0f4c859eSApple OSS Distributions // mark it acked
1607*0f4c859eSApple OSS Distributions informee->timer = 0;
1608*0f4c859eSApple OSS Distributions // that's one fewer to worry about
1609*0f4c859eSApple OSS Distributions fHeadNotePendingAcks--;
1610*0f4c859eSApple OSS Distributions } else {
1611*0f4c859eSApple OSS Distributions // this driver has already acked
1612*0f4c859eSApple OSS Distributions OUR_PMLog(kPMLogAcknowledgeErr2, 0, 0);
1613*0f4c859eSApple OSS Distributions }
1614*0f4c859eSApple OSS Distributions } else {
1615*0f4c859eSApple OSS Distributions // it's a child
1616*0f4c859eSApple OSS Distributions // make sure we're expecting this ack
1617*0f4c859eSApple OSS Distributions if (((IOPowerConnection *)whichObject)->getAwaitingAck()) {
1618*0f4c859eSApple OSS Distributions // that's one fewer to worry about
1619*0f4c859eSApple OSS Distributions fHeadNotePendingAcks--;
1620*0f4c859eSApple OSS Distributions ((IOPowerConnection *)whichObject)->setAwaitingAck(false);
1621*0f4c859eSApple OSS Distributions theChild = (IOService *)whichObject->copyChildEntry(gIOPowerPlane);
1622*0f4c859eSApple OSS Distributions if (theChild) {
1623*0f4c859eSApple OSS Distributions childPower = theChild->currentPowerConsumption();
1624*0f4c859eSApple OSS Distributions theChild->release();
1625*0f4c859eSApple OSS Distributions }
1626*0f4c859eSApple OSS Distributions if (childPower == kIOPMUnknown) {
1627*0f4c859eSApple OSS Distributions fHeadNotePowerArrayEntry->staticPower = kIOPMUnknown;
1628*0f4c859eSApple OSS Distributions } else {
1629*0f4c859eSApple OSS Distributions if (fHeadNotePowerArrayEntry->staticPower != kIOPMUnknown) {
1630*0f4c859eSApple OSS Distributions fHeadNotePowerArrayEntry->staticPower += childPower;
1631*0f4c859eSApple OSS Distributions }
1632*0f4c859eSApple OSS Distributions }
1633*0f4c859eSApple OSS Distributions }
1634*0f4c859eSApple OSS Distributions }
1635*0f4c859eSApple OSS Distributions
1636*0f4c859eSApple OSS Distributions if (fHeadNotePendingAcks == 0) {
1637*0f4c859eSApple OSS Distributions // yes, stop the timer
1638*0f4c859eSApple OSS Distributions stop_ack_timer();
1639*0f4c859eSApple OSS Distributions // and now we can continue
1640*0f4c859eSApple OSS Distributions all_acked = true;
1641*0f4c859eSApple OSS Distributions getPMRootDomain()->reset_watchdog_timer(this, 0);
1642*0f4c859eSApple OSS Distributions }
1643*0f4c859eSApple OSS Distributions } else {
1644*0f4c859eSApple OSS Distributions OUR_PMLog(kPMLogAcknowledgeErr3, 0, 0); // not expecting anybody to ack
1645*0f4c859eSApple OSS Distributions }
1646*0f4c859eSApple OSS Distributions
1647*0f4c859eSApple OSS Distributions no_err:
1648*0f4c859eSApple OSS Distributions if (whichObject) {
1649*0f4c859eSApple OSS Distributions whichObject->release();
1650*0f4c859eSApple OSS Distributions }
1651*0f4c859eSApple OSS Distributions
1652*0f4c859eSApple OSS Distributions return all_acked;
1653*0f4c859eSApple OSS Distributions }
1654*0f4c859eSApple OSS Distributions
1655*0f4c859eSApple OSS Distributions //*********************************************************************************
1656*0f4c859eSApple OSS Distributions // [public] acknowledgeSetPowerState
1657*0f4c859eSApple OSS Distributions //
1658*0f4c859eSApple OSS Distributions // After we instructed our controlling driver to change power states,
1659*0f4c859eSApple OSS Distributions // it has called to say it has finished doing so.
1660*0f4c859eSApple OSS Distributions // We continue to process the power state change.
1661*0f4c859eSApple OSS Distributions //*********************************************************************************
1662*0f4c859eSApple OSS Distributions
1663*0f4c859eSApple OSS Distributions IOReturn
acknowledgeSetPowerState(void)1664*0f4c859eSApple OSS Distributions IOService::acknowledgeSetPowerState( void )
1665*0f4c859eSApple OSS Distributions {
1666*0f4c859eSApple OSS Distributions IOPMRequest * request;
1667*0f4c859eSApple OSS Distributions
1668*0f4c859eSApple OSS Distributions if (!initialized) {
1669*0f4c859eSApple OSS Distributions return IOPMNotYetInitialized;
1670*0f4c859eSApple OSS Distributions }
1671*0f4c859eSApple OSS Distributions
1672*0f4c859eSApple OSS Distributions request = acquirePMRequest( this, kIOPMRequestTypeAckSetPowerState );
1673*0f4c859eSApple OSS Distributions if (!request) {
1674*0f4c859eSApple OSS Distributions return kIOReturnNoMemory;
1675*0f4c859eSApple OSS Distributions }
1676*0f4c859eSApple OSS Distributions
1677*0f4c859eSApple OSS Distributions submitPMRequest( request );
1678*0f4c859eSApple OSS Distributions return kIOReturnSuccess;
1679*0f4c859eSApple OSS Distributions }
1680*0f4c859eSApple OSS Distributions
1681*0f4c859eSApple OSS Distributions //*********************************************************************************
1682*0f4c859eSApple OSS Distributions // [private] handleAcknowledgeSetPowerState
1683*0f4c859eSApple OSS Distributions //*********************************************************************************
1684*0f4c859eSApple OSS Distributions
1685*0f4c859eSApple OSS Distributions bool
handleAcknowledgeSetPowerState(IOPMRequest * request __unused)1686*0f4c859eSApple OSS Distributions IOService::handleAcknowledgeSetPowerState( IOPMRequest * request __unused)
1687*0f4c859eSApple OSS Distributions {
1688*0f4c859eSApple OSS Distributions const OSMetaClass *controllingDriverMetaClass = NULL;
1689*0f4c859eSApple OSS Distributions uint32_t controllingDriverRegistryEntryID = 0;
1690*0f4c859eSApple OSS Distributions bool more = false;
1691*0f4c859eSApple OSS Distributions bool trace_this_ack = true;
1692*0f4c859eSApple OSS Distributions
1693*0f4c859eSApple OSS Distributions if (fDriverTimer == -1) {
1694*0f4c859eSApple OSS Distributions // driver acked while setPowerState() call is in-flight.
1695*0f4c859eSApple OSS Distributions // take this ack, return value from setPowerState() is irrelevant.
1696*0f4c859eSApple OSS Distributions OUR_PMLog(kPMLogDriverAcknowledgeSet,
1697*0f4c859eSApple OSS Distributions (uintptr_t) this, fDriverTimer);
1698*0f4c859eSApple OSS Distributions fDriverTimer = 0;
1699*0f4c859eSApple OSS Distributions } else if (fDriverTimer > 0) {
1700*0f4c859eSApple OSS Distributions // expected ack, stop the timer
1701*0f4c859eSApple OSS Distributions stop_ack_timer();
1702*0f4c859eSApple OSS Distributions
1703*0f4c859eSApple OSS Distributions getPMRootDomain()->reset_watchdog_timer(this, 0);
1704*0f4c859eSApple OSS Distributions
1705*0f4c859eSApple OSS Distributions uint64_t nsec = computeTimeDeltaNS(&fDriverCallStartTime);
1706*0f4c859eSApple OSS Distributions if (nsec > gIOPMSetPowerStateLogNS) {
1707*0f4c859eSApple OSS Distributions getPMRootDomain()->pmStatsRecordApplicationResponse(
1708*0f4c859eSApple OSS Distributions gIOPMStatsDriverPSChangeSlow,
1709*0f4c859eSApple OSS Distributions fName, kDriverCallSetPowerState, NS_TO_MS(nsec), getRegistryEntryID(),
1710*0f4c859eSApple OSS Distributions NULL, fHeadNotePowerState, true);
1711*0f4c859eSApple OSS Distributions }
1712*0f4c859eSApple OSS Distributions
1713*0f4c859eSApple OSS Distributions OUR_PMLog(kPMLogDriverAcknowledgeSet, (uintptr_t) this, fDriverTimer);
1714*0f4c859eSApple OSS Distributions fDriverTimer = 0;
1715*0f4c859eSApple OSS Distributions more = true;
1716*0f4c859eSApple OSS Distributions } else {
1717*0f4c859eSApple OSS Distributions // unexpected ack
1718*0f4c859eSApple OSS Distributions OUR_PMLog(kPMLogAcknowledgeErr4, (uintptr_t) this, 0);
1719*0f4c859eSApple OSS Distributions trace_this_ack = false;
1720*0f4c859eSApple OSS Distributions }
1721*0f4c859eSApple OSS Distributions
1722*0f4c859eSApple OSS Distributions if (trace_this_ack) {
1723*0f4c859eSApple OSS Distributions if (fControllingDriver) {
1724*0f4c859eSApple OSS Distributions controllingDriverMetaClass = fControllingDriver->getMetaClass();
1725*0f4c859eSApple OSS Distributions controllingDriverRegistryEntryID = (uint32_t)fControllingDriver->getRegistryEntryID();
1726*0f4c859eSApple OSS Distributions }
1727*0f4c859eSApple OSS Distributions
1728*0f4c859eSApple OSS Distributions SOCD_TRACE_XNU(PM_SET_POWER_STATE_ACK,
1729*0f4c859eSApple OSS Distributions ADDR(controllingDriverMetaClass),
1730*0f4c859eSApple OSS Distributions ADDR(this->getMetaClass()),
1731*0f4c859eSApple OSS Distributions PACK_2X32(VALUE(this->getRegistryEntryID()), VALUE(controllingDriverRegistryEntryID)),
1732*0f4c859eSApple OSS Distributions PACK_2X32(VALUE(fHeadNotePowerState), VALUE(0)));
1733*0f4c859eSApple OSS Distributions }
1734*0f4c859eSApple OSS Distributions
1735*0f4c859eSApple OSS Distributions return more;
1736*0f4c859eSApple OSS Distributions }
1737*0f4c859eSApple OSS Distributions
1738*0f4c859eSApple OSS Distributions //*********************************************************************************
1739*0f4c859eSApple OSS Distributions // [private] adjustPowerState
1740*0f4c859eSApple OSS Distributions //*********************************************************************************
1741*0f4c859eSApple OSS Distributions
1742*0f4c859eSApple OSS Distributions void
adjustPowerState(IOPMPowerStateIndex clamp)1743*0f4c859eSApple OSS Distributions IOService::adjustPowerState( IOPMPowerStateIndex clamp )
1744*0f4c859eSApple OSS Distributions {
1745*0f4c859eSApple OSS Distributions PM_ASSERT_IN_GATE();
1746*0f4c859eSApple OSS Distributions computeDesiredState(clamp, false);
1747*0f4c859eSApple OSS Distributions if (fControllingDriver && fParentsKnowState && inPlane(gIOPowerPlane)) {
1748*0f4c859eSApple OSS Distributions IOPMPowerChangeFlags changeFlags = kIOPMSelfInitiated;
1749*0f4c859eSApple OSS Distributions
1750*0f4c859eSApple OSS Distributions // Indicate that children desires must be ignored, and do not ask
1751*0f4c859eSApple OSS Distributions // apps for permission to drop power. This is used by root domain
1752*0f4c859eSApple OSS Distributions // for demand sleep.
1753*0f4c859eSApple OSS Distributions
1754*0f4c859eSApple OSS Distributions if (getPMRequestType() == kIOPMRequestTypeRequestPowerStateOverride) {
1755*0f4c859eSApple OSS Distributions changeFlags |= (kIOPMIgnoreChildren | kIOPMSkipAskPowerDown);
1756*0f4c859eSApple OSS Distributions }
1757*0f4c859eSApple OSS Distributions
1758*0f4c859eSApple OSS Distributions startPowerChange(
1759*0f4c859eSApple OSS Distributions /* flags */ changeFlags,
1760*0f4c859eSApple OSS Distributions /* power state */ fDesiredPowerState,
1761*0f4c859eSApple OSS Distributions /* domain flags */ 0,
1762*0f4c859eSApple OSS Distributions /* connection */ NULL,
1763*0f4c859eSApple OSS Distributions /* parent flags */ 0);
1764*0f4c859eSApple OSS Distributions }
1765*0f4c859eSApple OSS Distributions }
1766*0f4c859eSApple OSS Distributions
1767*0f4c859eSApple OSS Distributions //*********************************************************************************
1768*0f4c859eSApple OSS Distributions // [public] synchronizePowerTree
1769*0f4c859eSApple OSS Distributions //*********************************************************************************
1770*0f4c859eSApple OSS Distributions
1771*0f4c859eSApple OSS Distributions IOReturn
synchronizePowerTree(IOOptionBits options,IOService * notifyRoot)1772*0f4c859eSApple OSS Distributions IOService::synchronizePowerTree(
1773*0f4c859eSApple OSS Distributions IOOptionBits options,
1774*0f4c859eSApple OSS Distributions IOService * notifyRoot )
1775*0f4c859eSApple OSS Distributions {
1776*0f4c859eSApple OSS Distributions IOPMRequest * request_c = NULL;
1777*0f4c859eSApple OSS Distributions IOPMRequest * request_s;
1778*0f4c859eSApple OSS Distributions
1779*0f4c859eSApple OSS Distributions if (this != getPMRootDomain()) {
1780*0f4c859eSApple OSS Distributions return kIOReturnBadArgument;
1781*0f4c859eSApple OSS Distributions }
1782*0f4c859eSApple OSS Distributions if (!initialized) {
1783*0f4c859eSApple OSS Distributions return kIOPMNotYetInitialized;
1784*0f4c859eSApple OSS Distributions }
1785*0f4c859eSApple OSS Distributions
1786*0f4c859eSApple OSS Distributions OUR_PMLog(kPMLogCSynchronizePowerTree, options, (notifyRoot != NULL));
1787*0f4c859eSApple OSS Distributions
1788*0f4c859eSApple OSS Distributions if (notifyRoot) {
1789*0f4c859eSApple OSS Distributions IOPMRequest * nr;
1790*0f4c859eSApple OSS Distributions
1791*0f4c859eSApple OSS Distributions // Cancels don't need to be synchronized.
1792*0f4c859eSApple OSS Distributions nr = acquirePMRequest(notifyRoot, kIOPMRequestTypeChildNotifyDelayCancel);
1793*0f4c859eSApple OSS Distributions if (nr) {
1794*0f4c859eSApple OSS Distributions submitPMRequest(nr);
1795*0f4c859eSApple OSS Distributions }
1796*0f4c859eSApple OSS Distributions
1797*0f4c859eSApple OSS Distributions // For display wrangler or any other delay-eligible (dark wake clamped)
1798*0f4c859eSApple OSS Distributions // drivers attached to root domain in the power plane.
1799*0f4c859eSApple OSS Distributions nr = acquirePMRequest(getPMRootDomain(), kIOPMRequestTypeChildNotifyDelayCancel);
1800*0f4c859eSApple OSS Distributions if (nr) {
1801*0f4c859eSApple OSS Distributions submitPMRequest(nr);
1802*0f4c859eSApple OSS Distributions }
1803*0f4c859eSApple OSS Distributions }
1804*0f4c859eSApple OSS Distributions
1805*0f4c859eSApple OSS Distributions request_s = acquirePMRequest( this, kIOPMRequestTypeSynchronizePowerTree );
1806*0f4c859eSApple OSS Distributions if (!request_s) {
1807*0f4c859eSApple OSS Distributions goto error_no_memory;
1808*0f4c859eSApple OSS Distributions }
1809*0f4c859eSApple OSS Distributions
1810*0f4c859eSApple OSS Distributions if (options & kIOPMSyncCancelPowerDown) {
1811*0f4c859eSApple OSS Distributions request_c = acquirePMRequest( this, kIOPMRequestTypeIdleCancel );
1812*0f4c859eSApple OSS Distributions }
1813*0f4c859eSApple OSS Distributions if (request_c) {
1814*0f4c859eSApple OSS Distributions request_c->attachNextRequest( request_s );
1815*0f4c859eSApple OSS Distributions submitPMRequest(request_c);
1816*0f4c859eSApple OSS Distributions }
1817*0f4c859eSApple OSS Distributions
1818*0f4c859eSApple OSS Distributions request_s->fArg0 = (void *)(uintptr_t) options;
1819*0f4c859eSApple OSS Distributions submitPMRequest(request_s);
1820*0f4c859eSApple OSS Distributions
1821*0f4c859eSApple OSS Distributions return kIOReturnSuccess;
1822*0f4c859eSApple OSS Distributions
1823*0f4c859eSApple OSS Distributions error_no_memory:
1824*0f4c859eSApple OSS Distributions if (request_c) {
1825*0f4c859eSApple OSS Distributions releasePMRequest(request_c);
1826*0f4c859eSApple OSS Distributions }
1827*0f4c859eSApple OSS Distributions if (request_s) {
1828*0f4c859eSApple OSS Distributions releasePMRequest(request_s);
1829*0f4c859eSApple OSS Distributions }
1830*0f4c859eSApple OSS Distributions return kIOReturnNoMemory;
1831*0f4c859eSApple OSS Distributions }
1832*0f4c859eSApple OSS Distributions
1833*0f4c859eSApple OSS Distributions //*********************************************************************************
1834*0f4c859eSApple OSS Distributions // [private] handleSynchronizePowerTree
1835*0f4c859eSApple OSS Distributions //*********************************************************************************
1836*0f4c859eSApple OSS Distributions
1837*0f4c859eSApple OSS Distributions void
handleSynchronizePowerTree(IOPMRequest * request)1838*0f4c859eSApple OSS Distributions IOService::handleSynchronizePowerTree( IOPMRequest * request )
1839*0f4c859eSApple OSS Distributions {
1840*0f4c859eSApple OSS Distributions PM_ASSERT_IN_GATE();
1841*0f4c859eSApple OSS Distributions if (fControllingDriver && fParentsKnowState && inPlane(gIOPowerPlane) &&
1842*0f4c859eSApple OSS Distributions (fCurrentPowerState == fHighestPowerState)) {
1843*0f4c859eSApple OSS Distributions IOPMPowerChangeFlags options = (IOPMPowerChangeFlags)(uintptr_t) request->fArg0;
1844*0f4c859eSApple OSS Distributions
1845*0f4c859eSApple OSS Distributions startPowerChange(
1846*0f4c859eSApple OSS Distributions /* flags */ kIOPMSelfInitiated | kIOPMSynchronize |
1847*0f4c859eSApple OSS Distributions (options & kIOPMSyncNoChildNotify),
1848*0f4c859eSApple OSS Distributions /* power state */ fCurrentPowerState,
1849*0f4c859eSApple OSS Distributions /* domain flags */ 0,
1850*0f4c859eSApple OSS Distributions /* connection */ NULL,
1851*0f4c859eSApple OSS Distributions /* parent flags */ 0);
1852*0f4c859eSApple OSS Distributions }
1853*0f4c859eSApple OSS Distributions }
1854*0f4c859eSApple OSS Distributions
1855*0f4c859eSApple OSS Distributions #ifndef __LP64__
1856*0f4c859eSApple OSS Distributions //*********************************************************************************
1857*0f4c859eSApple OSS Distributions // [deprecated] powerDomainWillChangeTo
1858*0f4c859eSApple OSS Distributions //
1859*0f4c859eSApple OSS Distributions // Called by the power-hierarchy parent notifying of a new power state
1860*0f4c859eSApple OSS Distributions // in the power domain.
1861*0f4c859eSApple OSS Distributions // We enqueue a parent power-change to our queue of power changes.
1862*0f4c859eSApple OSS Distributions // This may or may not cause us to change power, depending on what
1863*0f4c859eSApple OSS Distributions // kind of change is occuring in the domain.
1864*0f4c859eSApple OSS Distributions //*********************************************************************************
1865*0f4c859eSApple OSS Distributions
1866*0f4c859eSApple OSS Distributions IOReturn
powerDomainWillChangeTo(IOPMPowerFlags newPowerFlags,IOPowerConnection * whichParent)1867*0f4c859eSApple OSS Distributions IOService::powerDomainWillChangeTo(
1868*0f4c859eSApple OSS Distributions IOPMPowerFlags newPowerFlags,
1869*0f4c859eSApple OSS Distributions IOPowerConnection * whichParent )
1870*0f4c859eSApple OSS Distributions {
1871*0f4c859eSApple OSS Distributions assert(false);
1872*0f4c859eSApple OSS Distributions return kIOReturnUnsupported;
1873*0f4c859eSApple OSS Distributions }
1874*0f4c859eSApple OSS Distributions #endif /* !__LP64__ */
1875*0f4c859eSApple OSS Distributions
1876*0f4c859eSApple OSS Distributions //*********************************************************************************
1877*0f4c859eSApple OSS Distributions // [private] handlePowerDomainWillChangeTo
1878*0f4c859eSApple OSS Distributions //*********************************************************************************
1879*0f4c859eSApple OSS Distributions
1880*0f4c859eSApple OSS Distributions void
handlePowerDomainWillChangeTo(IOPMRequest * request)1881*0f4c859eSApple OSS Distributions IOService::handlePowerDomainWillChangeTo( IOPMRequest * request )
1882*0f4c859eSApple OSS Distributions {
1883*0f4c859eSApple OSS Distributions IOPMPowerFlags parentPowerFlags = (IOPMPowerFlags) request->fArg0;
1884*0f4c859eSApple OSS Distributions IOPowerConnection * whichParent = (IOPowerConnection *) request->fArg1;
1885*0f4c859eSApple OSS Distributions IOPMPowerChangeFlags parentChangeFlags = (IOPMPowerChangeFlags)(uintptr_t) request->fArg2;
1886*0f4c859eSApple OSS Distributions IOPMPowerChangeFlags myChangeFlags;
1887*0f4c859eSApple OSS Distributions OSIterator * iter;
1888*0f4c859eSApple OSS Distributions OSObject * next;
1889*0f4c859eSApple OSS Distributions IOPowerConnection * connection;
1890*0f4c859eSApple OSS Distributions IOPMPowerStateIndex maxPowerState;
1891*0f4c859eSApple OSS Distributions IOPMPowerFlags combinedPowerFlags;
1892*0f4c859eSApple OSS Distributions IOReturn result = IOPMAckImplied;
1893*0f4c859eSApple OSS Distributions
1894*0f4c859eSApple OSS Distributions PM_ASSERT_IN_GATE();
1895*0f4c859eSApple OSS Distributions OUR_PMLog(kPMLogWillChange, parentPowerFlags, 0);
1896*0f4c859eSApple OSS Distributions
1897*0f4c859eSApple OSS Distributions if (!inPlane(gIOPowerPlane) || !whichParent || !whichParent->getAwaitingAck()) {
1898*0f4c859eSApple OSS Distributions PM_LOG("%s::%s not in power tree\n", getName(), __FUNCTION__);
1899*0f4c859eSApple OSS Distributions goto exit_no_ack;
1900*0f4c859eSApple OSS Distributions }
1901*0f4c859eSApple OSS Distributions
1902*0f4c859eSApple OSS Distributions // Combine parents' output power flags.
1903*0f4c859eSApple OSS Distributions
1904*0f4c859eSApple OSS Distributions combinedPowerFlags = 0;
1905*0f4c859eSApple OSS Distributions
1906*0f4c859eSApple OSS Distributions iter = getParentIterator(gIOPowerPlane);
1907*0f4c859eSApple OSS Distributions if (iter) {
1908*0f4c859eSApple OSS Distributions while ((next = iter->getNextObject())) {
1909*0f4c859eSApple OSS Distributions if ((connection = OSDynamicCast(IOPowerConnection, next))) {
1910*0f4c859eSApple OSS Distributions if (connection == whichParent) {
1911*0f4c859eSApple OSS Distributions combinedPowerFlags |= parentPowerFlags;
1912*0f4c859eSApple OSS Distributions } else {
1913*0f4c859eSApple OSS Distributions combinedPowerFlags |= connection->parentCurrentPowerFlags();
1914*0f4c859eSApple OSS Distributions }
1915*0f4c859eSApple OSS Distributions }
1916*0f4c859eSApple OSS Distributions }
1917*0f4c859eSApple OSS Distributions iter->release();
1918*0f4c859eSApple OSS Distributions }
1919*0f4c859eSApple OSS Distributions
1920*0f4c859eSApple OSS Distributions // If our initial change has yet to occur, then defer the power change
1921*0f4c859eSApple OSS Distributions // until after the power domain has completed its power transition.
1922*0f4c859eSApple OSS Distributions
1923*0f4c859eSApple OSS Distributions if (fControllingDriver && !fInitialPowerChange) {
1924*0f4c859eSApple OSS Distributions maxPowerState = fControllingDriver->maxCapabilityForDomainState(
1925*0f4c859eSApple OSS Distributions combinedPowerFlags);
1926*0f4c859eSApple OSS Distributions
1927*0f4c859eSApple OSS Distributions if (parentChangeFlags & kIOPMDomainPowerDrop) {
1928*0f4c859eSApple OSS Distributions // fMaxPowerState set a limit on self-initiated power changes.
1929*0f4c859eSApple OSS Distributions // Update it before a parent power drop.
1930*0f4c859eSApple OSS Distributions fMaxPowerState = maxPowerState;
1931*0f4c859eSApple OSS Distributions }
1932*0f4c859eSApple OSS Distributions
1933*0f4c859eSApple OSS Distributions // Use kIOPMSynchronize below instead of kIOPMRootBroadcastFlags
1934*0f4c859eSApple OSS Distributions // to avoid propagating the root change flags if any service must
1935*0f4c859eSApple OSS Distributions // change power state due to root's will-change notification.
1936*0f4c859eSApple OSS Distributions // Root does not change power state for kIOPMSynchronize.
1937*0f4c859eSApple OSS Distributions
1938*0f4c859eSApple OSS Distributions myChangeFlags = kIOPMParentInitiated | kIOPMDomainWillChange |
1939*0f4c859eSApple OSS Distributions (parentChangeFlags & kIOPMSynchronize);
1940*0f4c859eSApple OSS Distributions
1941*0f4c859eSApple OSS Distributions result = startPowerChange(
1942*0f4c859eSApple OSS Distributions /* flags */ myChangeFlags,
1943*0f4c859eSApple OSS Distributions /* power state */ maxPowerState,
1944*0f4c859eSApple OSS Distributions /* domain flags */ combinedPowerFlags,
1945*0f4c859eSApple OSS Distributions /* connection */ whichParent,
1946*0f4c859eSApple OSS Distributions /* parent flags */ parentPowerFlags);
1947*0f4c859eSApple OSS Distributions }
1948*0f4c859eSApple OSS Distributions
1949*0f4c859eSApple OSS Distributions // If parent is dropping power, immediately update the parent's
1950*0f4c859eSApple OSS Distributions // capability flags. Any future merging of parent(s) combined
1951*0f4c859eSApple OSS Distributions // power flags should account for this power drop.
1952*0f4c859eSApple OSS Distributions
1953*0f4c859eSApple OSS Distributions if (parentChangeFlags & kIOPMDomainPowerDrop) {
1954*0f4c859eSApple OSS Distributions setParentInfo(parentPowerFlags, whichParent, true);
1955*0f4c859eSApple OSS Distributions }
1956*0f4c859eSApple OSS Distributions
1957*0f4c859eSApple OSS Distributions // Parent is expecting an ACK from us. If we did not embark on a state
1958*0f4c859eSApple OSS Distributions // transition, i.e. startPowerChange() returned IOPMAckImplied. We are
1959*0f4c859eSApple OSS Distributions // still required to issue an ACK to our parent.
1960*0f4c859eSApple OSS Distributions
1961*0f4c859eSApple OSS Distributions if (IOPMAckImplied == result) {
1962*0f4c859eSApple OSS Distributions IOService * parent;
1963*0f4c859eSApple OSS Distributions parent = (IOService *) whichParent->copyParentEntry(gIOPowerPlane);
1964*0f4c859eSApple OSS Distributions assert(parent);
1965*0f4c859eSApple OSS Distributions if (parent) {
1966*0f4c859eSApple OSS Distributions parent->acknowledgePowerChange( whichParent );
1967*0f4c859eSApple OSS Distributions parent->release();
1968*0f4c859eSApple OSS Distributions }
1969*0f4c859eSApple OSS Distributions }
1970*0f4c859eSApple OSS Distributions
1971*0f4c859eSApple OSS Distributions exit_no_ack:
1972*0f4c859eSApple OSS Distributions // Drop the retain from notifyChild().
1973*0f4c859eSApple OSS Distributions if (whichParent) {
1974*0f4c859eSApple OSS Distributions whichParent->release();
1975*0f4c859eSApple OSS Distributions }
1976*0f4c859eSApple OSS Distributions }
1977*0f4c859eSApple OSS Distributions
1978*0f4c859eSApple OSS Distributions #ifndef __LP64__
1979*0f4c859eSApple OSS Distributions //*********************************************************************************
1980*0f4c859eSApple OSS Distributions // [deprecated] powerDomainDidChangeTo
1981*0f4c859eSApple OSS Distributions //
1982*0f4c859eSApple OSS Distributions // Called by the power-hierarchy parent after the power state of the power domain
1983*0f4c859eSApple OSS Distributions // has settled at a new level.
1984*0f4c859eSApple OSS Distributions // We enqueue a parent power-change to our queue of power changes.
1985*0f4c859eSApple OSS Distributions // This may or may not cause us to change power, depending on what
1986*0f4c859eSApple OSS Distributions // kind of change is occuring in the domain.
1987*0f4c859eSApple OSS Distributions //*********************************************************************************
1988*0f4c859eSApple OSS Distributions
1989*0f4c859eSApple OSS Distributions IOReturn
powerDomainDidChangeTo(IOPMPowerFlags newPowerFlags,IOPowerConnection * whichParent)1990*0f4c859eSApple OSS Distributions IOService::powerDomainDidChangeTo(
1991*0f4c859eSApple OSS Distributions IOPMPowerFlags newPowerFlags,
1992*0f4c859eSApple OSS Distributions IOPowerConnection * whichParent )
1993*0f4c859eSApple OSS Distributions {
1994*0f4c859eSApple OSS Distributions assert(false);
1995*0f4c859eSApple OSS Distributions return kIOReturnUnsupported;
1996*0f4c859eSApple OSS Distributions }
1997*0f4c859eSApple OSS Distributions #endif /* !__LP64__ */
1998*0f4c859eSApple OSS Distributions
1999*0f4c859eSApple OSS Distributions //*********************************************************************************
2000*0f4c859eSApple OSS Distributions // [private] handlePowerDomainDidChangeTo
2001*0f4c859eSApple OSS Distributions //*********************************************************************************
2002*0f4c859eSApple OSS Distributions
2003*0f4c859eSApple OSS Distributions void
handlePowerDomainDidChangeTo(IOPMRequest * request)2004*0f4c859eSApple OSS Distributions IOService::handlePowerDomainDidChangeTo( IOPMRequest * request )
2005*0f4c859eSApple OSS Distributions {
2006*0f4c859eSApple OSS Distributions IOPMPowerFlags parentPowerFlags = (IOPMPowerFlags) request->fArg0;
2007*0f4c859eSApple OSS Distributions IOPowerConnection * whichParent = (IOPowerConnection *) request->fArg1;
2008*0f4c859eSApple OSS Distributions IOPMPowerChangeFlags parentChangeFlags = (IOPMPowerChangeFlags)(uintptr_t) request->fArg2;
2009*0f4c859eSApple OSS Distributions IOPMPowerChangeFlags myChangeFlags;
2010*0f4c859eSApple OSS Distributions IOPMPowerStateIndex maxPowerState;
2011*0f4c859eSApple OSS Distributions IOPMPowerStateIndex initialDesire = kPowerStateZero;
2012*0f4c859eSApple OSS Distributions bool computeDesire = false;
2013*0f4c859eSApple OSS Distributions bool desireChanged = false;
2014*0f4c859eSApple OSS Distributions bool savedParentsKnowState;
2015*0f4c859eSApple OSS Distributions IOReturn result = IOPMAckImplied;
2016*0f4c859eSApple OSS Distributions
2017*0f4c859eSApple OSS Distributions PM_ASSERT_IN_GATE();
2018*0f4c859eSApple OSS Distributions OUR_PMLog(kPMLogDidChange, parentPowerFlags, 0);
2019*0f4c859eSApple OSS Distributions
2020*0f4c859eSApple OSS Distributions if (!inPlane(gIOPowerPlane) || !whichParent || !whichParent->getAwaitingAck()) {
2021*0f4c859eSApple OSS Distributions PM_LOG("%s::%s not in power tree\n", getName(), __FUNCTION__);
2022*0f4c859eSApple OSS Distributions goto exit_no_ack;
2023*0f4c859eSApple OSS Distributions }
2024*0f4c859eSApple OSS Distributions
2025*0f4c859eSApple OSS Distributions savedParentsKnowState = fParentsKnowState;
2026*0f4c859eSApple OSS Distributions
2027*0f4c859eSApple OSS Distributions setParentInfo(parentPowerFlags, whichParent, true);
2028*0f4c859eSApple OSS Distributions
2029*0f4c859eSApple OSS Distributions if (fControllingDriver) {
2030*0f4c859eSApple OSS Distributions maxPowerState = fControllingDriver->maxCapabilityForDomainState(
2031*0f4c859eSApple OSS Distributions fParentsCurrentPowerFlags);
2032*0f4c859eSApple OSS Distributions
2033*0f4c859eSApple OSS Distributions if ((parentChangeFlags & kIOPMDomainPowerDrop) == 0) {
2034*0f4c859eSApple OSS Distributions // fMaxPowerState set a limit on self-initiated power changes.
2035*0f4c859eSApple OSS Distributions // Update it after a parent power rise.
2036*0f4c859eSApple OSS Distributions fMaxPowerState = maxPowerState;
2037*0f4c859eSApple OSS Distributions }
2038*0f4c859eSApple OSS Distributions
2039*0f4c859eSApple OSS Distributions if (fInitialPowerChange) {
2040*0f4c859eSApple OSS Distributions computeDesire = true;
2041*0f4c859eSApple OSS Distributions initialDesire = fControllingDriver->initialPowerStateForDomainState(
2042*0f4c859eSApple OSS Distributions fParentsCurrentPowerFlags);
2043*0f4c859eSApple OSS Distributions } else if (parentChangeFlags & kIOPMRootChangeUp) {
2044*0f4c859eSApple OSS Distributions if (fAdvisoryTickleUsed) {
2045*0f4c859eSApple OSS Distributions // On system wake, re-compute the desired power state since
2046*0f4c859eSApple OSS Distributions // gIOPMAdvisoryTickleEnabled will change for a full wake,
2047*0f4c859eSApple OSS Distributions // which is an input to computeDesiredState(). This is not
2048*0f4c859eSApple OSS Distributions // necessary for a dark wake because powerChangeDone() will
2049*0f4c859eSApple OSS Distributions // handle the dark to full wake case, but it does no harm.
2050*0f4c859eSApple OSS Distributions
2051*0f4c859eSApple OSS Distributions desireChanged = true;
2052*0f4c859eSApple OSS Distributions }
2053*0f4c859eSApple OSS Distributions
2054*0f4c859eSApple OSS Distributions if (fResetPowerStateOnWake) {
2055*0f4c859eSApple OSS Distributions // Query the driver for the desired power state on system wake.
2056*0f4c859eSApple OSS Distributions // Default implementation returns the lowest power state.
2057*0f4c859eSApple OSS Distributions
2058*0f4c859eSApple OSS Distributions IOPMPowerStateIndex wakePowerState =
2059*0f4c859eSApple OSS Distributions fControllingDriver->initialPowerStateForDomainState(
2060*0f4c859eSApple OSS Distributions kIOPMRootDomainState | kIOPMPowerOn );
2061*0f4c859eSApple OSS Distributions
2062*0f4c859eSApple OSS Distributions // fDesiredPowerState was adjusted before going to sleep
2063*0f4c859eSApple OSS Distributions // with fDeviceDesire at min.
2064*0f4c859eSApple OSS Distributions
2065*0f4c859eSApple OSS Distributions if (StateOrder(wakePowerState) > StateOrder(fDesiredPowerState)) {
2066*0f4c859eSApple OSS Distributions // Must schedule a power adjustment if we changed the
2067*0f4c859eSApple OSS Distributions // device desire. That will update the desired domain
2068*0f4c859eSApple OSS Distributions // power on the parent power connection and ping the
2069*0f4c859eSApple OSS Distributions // power parent if necessary.
2070*0f4c859eSApple OSS Distributions
2071*0f4c859eSApple OSS Distributions updatePowerClient(gIOPMPowerClientDevice, wakePowerState);
2072*0f4c859eSApple OSS Distributions desireChanged = true;
2073*0f4c859eSApple OSS Distributions }
2074*0f4c859eSApple OSS Distributions }
2075*0f4c859eSApple OSS Distributions }
2076*0f4c859eSApple OSS Distributions
2077*0f4c859eSApple OSS Distributions if (computeDesire || desireChanged) {
2078*0f4c859eSApple OSS Distributions computeDesiredState(initialDesire, false);
2079*0f4c859eSApple OSS Distributions }
2080*0f4c859eSApple OSS Distributions
2081*0f4c859eSApple OSS Distributions // Absorb and propagate parent's broadcast flags
2082*0f4c859eSApple OSS Distributions myChangeFlags = kIOPMParentInitiated | kIOPMDomainDidChange |
2083*0f4c859eSApple OSS Distributions (parentChangeFlags & kIOPMRootBroadcastFlags);
2084*0f4c859eSApple OSS Distributions
2085*0f4c859eSApple OSS Distributions if (kIOPMAOTPower & fPowerStates[maxPowerState].inputPowerFlags) {
2086*0f4c859eSApple OSS Distributions IOLog("aotPS %s0x%qx[%ld]\n", getName(), getRegistryEntryID(), maxPowerState);
2087*0f4c859eSApple OSS Distributions }
2088*0f4c859eSApple OSS Distributions
2089*0f4c859eSApple OSS Distributions result = startPowerChange(
2090*0f4c859eSApple OSS Distributions /* flags */ myChangeFlags,
2091*0f4c859eSApple OSS Distributions /* power state */ maxPowerState,
2092*0f4c859eSApple OSS Distributions /* domain flags */ fParentsCurrentPowerFlags,
2093*0f4c859eSApple OSS Distributions /* connection */ whichParent,
2094*0f4c859eSApple OSS Distributions /* parent flags */ 0);
2095*0f4c859eSApple OSS Distributions }
2096*0f4c859eSApple OSS Distributions
2097*0f4c859eSApple OSS Distributions // Parent is expecting an ACK from us. If we did not embark on a state
2098*0f4c859eSApple OSS Distributions // transition, i.e. startPowerChange() returned IOPMAckImplied. We are
2099*0f4c859eSApple OSS Distributions // still required to issue an ACK to our parent.
2100*0f4c859eSApple OSS Distributions
2101*0f4c859eSApple OSS Distributions if (IOPMAckImplied == result) {
2102*0f4c859eSApple OSS Distributions IOService * parent;
2103*0f4c859eSApple OSS Distributions parent = (IOService *) whichParent->copyParentEntry(gIOPowerPlane);
2104*0f4c859eSApple OSS Distributions assert(parent);
2105*0f4c859eSApple OSS Distributions if (parent) {
2106*0f4c859eSApple OSS Distributions parent->acknowledgePowerChange( whichParent );
2107*0f4c859eSApple OSS Distributions parent->release();
2108*0f4c859eSApple OSS Distributions }
2109*0f4c859eSApple OSS Distributions }
2110*0f4c859eSApple OSS Distributions
2111*0f4c859eSApple OSS Distributions // If the parent registers its power driver late, then this is the
2112*0f4c859eSApple OSS Distributions // first opportunity to tell our parent about our desire. Or if the
2113*0f4c859eSApple OSS Distributions // child's desire changed during a parent change notify.
2114*0f4c859eSApple OSS Distributions
2115*0f4c859eSApple OSS Distributions if (fControllingDriver &&
2116*0f4c859eSApple OSS Distributions ((!savedParentsKnowState && fParentsKnowState) || desireChanged)) {
2117*0f4c859eSApple OSS Distributions PM_LOG1("%s::powerDomainDidChangeTo parentsKnowState %d\n",
2118*0f4c859eSApple OSS Distributions getName(), fParentsKnowState);
2119*0f4c859eSApple OSS Distributions requestDomainPower( fDesiredPowerState );
2120*0f4c859eSApple OSS Distributions }
2121*0f4c859eSApple OSS Distributions
2122*0f4c859eSApple OSS Distributions exit_no_ack:
2123*0f4c859eSApple OSS Distributions // Drop the retain from notifyChild().
2124*0f4c859eSApple OSS Distributions if (whichParent) {
2125*0f4c859eSApple OSS Distributions whichParent->release();
2126*0f4c859eSApple OSS Distributions }
2127*0f4c859eSApple OSS Distributions }
2128*0f4c859eSApple OSS Distributions
2129*0f4c859eSApple OSS Distributions //*********************************************************************************
2130*0f4c859eSApple OSS Distributions // [private] setParentInfo
2131*0f4c859eSApple OSS Distributions //
2132*0f4c859eSApple OSS Distributions // Set our connection data for one specific parent, and then combine all the parent
2133*0f4c859eSApple OSS Distributions // data together.
2134*0f4c859eSApple OSS Distributions //*********************************************************************************
2135*0f4c859eSApple OSS Distributions
2136*0f4c859eSApple OSS Distributions void
setParentInfo(IOPMPowerFlags newPowerFlags,IOPowerConnection * whichParent,bool knowsState)2137*0f4c859eSApple OSS Distributions IOService::setParentInfo(
2138*0f4c859eSApple OSS Distributions IOPMPowerFlags newPowerFlags,
2139*0f4c859eSApple OSS Distributions IOPowerConnection * whichParent,
2140*0f4c859eSApple OSS Distributions bool knowsState )
2141*0f4c859eSApple OSS Distributions {
2142*0f4c859eSApple OSS Distributions OSIterator * iter;
2143*0f4c859eSApple OSS Distributions OSObject * next;
2144*0f4c859eSApple OSS Distributions IOPowerConnection * conn;
2145*0f4c859eSApple OSS Distributions
2146*0f4c859eSApple OSS Distributions PM_ASSERT_IN_GATE();
2147*0f4c859eSApple OSS Distributions
2148*0f4c859eSApple OSS Distributions // set our connection data
2149*0f4c859eSApple OSS Distributions whichParent->setParentCurrentPowerFlags(newPowerFlags);
2150*0f4c859eSApple OSS Distributions whichParent->setParentKnowsState(knowsState);
2151*0f4c859eSApple OSS Distributions
2152*0f4c859eSApple OSS Distributions // recompute our parent info
2153*0f4c859eSApple OSS Distributions fParentsCurrentPowerFlags = 0;
2154*0f4c859eSApple OSS Distributions fParentsKnowState = true;
2155*0f4c859eSApple OSS Distributions
2156*0f4c859eSApple OSS Distributions iter = getParentIterator(gIOPowerPlane);
2157*0f4c859eSApple OSS Distributions if (iter) {
2158*0f4c859eSApple OSS Distributions while ((next = iter->getNextObject())) {
2159*0f4c859eSApple OSS Distributions if ((conn = OSDynamicCast(IOPowerConnection, next))) {
2160*0f4c859eSApple OSS Distributions fParentsKnowState &= conn->parentKnowsState();
2161*0f4c859eSApple OSS Distributions fParentsCurrentPowerFlags |= conn->parentCurrentPowerFlags();
2162*0f4c859eSApple OSS Distributions }
2163*0f4c859eSApple OSS Distributions }
2164*0f4c859eSApple OSS Distributions iter->release();
2165*0f4c859eSApple OSS Distributions }
2166*0f4c859eSApple OSS Distributions }
2167*0f4c859eSApple OSS Distributions
2168*0f4c859eSApple OSS Distributions //******************************************************************************
2169*0f4c859eSApple OSS Distributions // [private] trackSystemSleepPreventers
2170*0f4c859eSApple OSS Distributions //******************************************************************************
2171*0f4c859eSApple OSS Distributions
2172*0f4c859eSApple OSS Distributions void
trackSystemSleepPreventers(IOPMPowerStateIndex oldPowerState,IOPMPowerStateIndex newPowerState,IOPMPowerChangeFlags changeFlags __unused)2173*0f4c859eSApple OSS Distributions IOService::trackSystemSleepPreventers(
2174*0f4c859eSApple OSS Distributions IOPMPowerStateIndex oldPowerState,
2175*0f4c859eSApple OSS Distributions IOPMPowerStateIndex newPowerState,
2176*0f4c859eSApple OSS Distributions IOPMPowerChangeFlags changeFlags __unused )
2177*0f4c859eSApple OSS Distributions {
2178*0f4c859eSApple OSS Distributions IOPMPowerFlags oldCapability, newCapability;
2179*0f4c859eSApple OSS Distributions
2180*0f4c859eSApple OSS Distributions oldCapability = fPowerStates[oldPowerState].capabilityFlags &
2181*0f4c859eSApple OSS Distributions (kIOPMPreventIdleSleep | kIOPMPreventSystemSleep);
2182*0f4c859eSApple OSS Distributions newCapability = fPowerStates[newPowerState].capabilityFlags &
2183*0f4c859eSApple OSS Distributions (kIOPMPreventIdleSleep | kIOPMPreventSystemSleep);
2184*0f4c859eSApple OSS Distributions
2185*0f4c859eSApple OSS Distributions if (fHeadNoteChangeFlags & kIOPMInitialPowerChange) {
2186*0f4c859eSApple OSS Distributions oldCapability = 0;
2187*0f4c859eSApple OSS Distributions }
2188*0f4c859eSApple OSS Distributions if (oldCapability == newCapability) {
2189*0f4c859eSApple OSS Distributions return;
2190*0f4c859eSApple OSS Distributions }
2191*0f4c859eSApple OSS Distributions
2192*0f4c859eSApple OSS Distributions if ((oldCapability ^ newCapability) & kIOPMPreventIdleSleep) {
2193*0f4c859eSApple OSS Distributions bool enablePrevention = ((oldCapability & kIOPMPreventIdleSleep) == 0);
2194*0f4c859eSApple OSS Distributions bool idleCancelAllowed = getPMRootDomain()->updatePreventIdleSleepList(
2195*0f4c859eSApple OSS Distributions this, enablePrevention);
2196*0f4c859eSApple OSS Distributions #if SUPPORT_IDLE_CANCEL
2197*0f4c859eSApple OSS Distributions if (idleCancelAllowed && enablePrevention) {
2198*0f4c859eSApple OSS Distributions IOPMRequest * cancelRequest;
2199*0f4c859eSApple OSS Distributions
2200*0f4c859eSApple OSS Distributions cancelRequest = acquirePMRequest( getPMRootDomain(), kIOPMRequestTypeIdleCancel );
2201*0f4c859eSApple OSS Distributions if (cancelRequest) {
2202*0f4c859eSApple OSS Distributions submitPMRequest( cancelRequest );
2203*0f4c859eSApple OSS Distributions }
2204*0f4c859eSApple OSS Distributions }
2205*0f4c859eSApple OSS Distributions #endif
2206*0f4c859eSApple OSS Distributions }
2207*0f4c859eSApple OSS Distributions
2208*0f4c859eSApple OSS Distributions if ((oldCapability ^ newCapability) & kIOPMPreventSystemSleep) {
2209*0f4c859eSApple OSS Distributions getPMRootDomain()->updatePreventSystemSleepList(this,
2210*0f4c859eSApple OSS Distributions ((oldCapability & kIOPMPreventSystemSleep) == 0));
2211*0f4c859eSApple OSS Distributions }
2212*0f4c859eSApple OSS Distributions }
2213*0f4c859eSApple OSS Distributions
2214*0f4c859eSApple OSS Distributions //*********************************************************************************
2215*0f4c859eSApple OSS Distributions // [public] requestPowerDomainState
2216*0f4c859eSApple OSS Distributions //
2217*0f4c859eSApple OSS Distributions // Called on a power parent when a child's power requirement changes.
2218*0f4c859eSApple OSS Distributions //*********************************************************************************
2219*0f4c859eSApple OSS Distributions
2220*0f4c859eSApple OSS Distributions IOReturn
requestPowerDomainState(IOPMPowerFlags childRequestPowerFlags,IOPowerConnection * childConnection,unsigned long specification)2221*0f4c859eSApple OSS Distributions IOService::requestPowerDomainState(
2222*0f4c859eSApple OSS Distributions IOPMPowerFlags childRequestPowerFlags,
2223*0f4c859eSApple OSS Distributions IOPowerConnection * childConnection,
2224*0f4c859eSApple OSS Distributions unsigned long specification )
2225*0f4c859eSApple OSS Distributions {
2226*0f4c859eSApple OSS Distributions IOPMPowerStateIndex order, powerState;
2227*0f4c859eSApple OSS Distributions IOPMPowerFlags outputPowerFlags;
2228*0f4c859eSApple OSS Distributions IOService * child;
2229*0f4c859eSApple OSS Distributions IOPMRequest * subRequest;
2230*0f4c859eSApple OSS Distributions bool adjustPower = false;
2231*0f4c859eSApple OSS Distributions
2232*0f4c859eSApple OSS Distributions if (!initialized) {
2233*0f4c859eSApple OSS Distributions return IOPMNotYetInitialized;
2234*0f4c859eSApple OSS Distributions }
2235*0f4c859eSApple OSS Distributions
2236*0f4c859eSApple OSS Distributions if (gIOPMWorkLoop->onThread() == false) {
2237*0f4c859eSApple OSS Distributions PM_LOG("%s::requestPowerDomainState\n", getName());
2238*0f4c859eSApple OSS Distributions return kIOReturnSuccess;
2239*0f4c859eSApple OSS Distributions }
2240*0f4c859eSApple OSS Distributions
2241*0f4c859eSApple OSS Distributions OUR_PMLog(kPMLogRequestDomain, childRequestPowerFlags, specification);
2242*0f4c859eSApple OSS Distributions
2243*0f4c859eSApple OSS Distributions if (!isChild(childConnection, gIOPowerPlane)) {
2244*0f4c859eSApple OSS Distributions return kIOReturnNotAttached;
2245*0f4c859eSApple OSS Distributions }
2246*0f4c859eSApple OSS Distributions
2247*0f4c859eSApple OSS Distributions if (!fControllingDriver || !fNumberOfPowerStates) {
2248*0f4c859eSApple OSS Distributions return kIOReturnNotReady;
2249*0f4c859eSApple OSS Distributions }
2250*0f4c859eSApple OSS Distributions
2251*0f4c859eSApple OSS Distributions child = (IOService *) childConnection->getChildEntry(gIOPowerPlane);
2252*0f4c859eSApple OSS Distributions assert(child);
2253*0f4c859eSApple OSS Distributions
2254*0f4c859eSApple OSS Distributions // Remove flags from child request which we can't possibly supply
2255*0f4c859eSApple OSS Distributions childRequestPowerFlags &= fMergedOutputPowerFlags;
2256*0f4c859eSApple OSS Distributions
2257*0f4c859eSApple OSS Distributions // Merge in the power flags contributed by this power parent
2258*0f4c859eSApple OSS Distributions // at its current or impending power state.
2259*0f4c859eSApple OSS Distributions
2260*0f4c859eSApple OSS Distributions outputPowerFlags = fPowerStates[fCurrentPowerState].outputPowerFlags;
2261*0f4c859eSApple OSS Distributions if (fMachineState != kIOPM_Finished) {
2262*0f4c859eSApple OSS Distributions if (IS_POWER_DROP && !IS_ROOT_DOMAIN) {
2263*0f4c859eSApple OSS Distributions // Use the lower power state when dropping power.
2264*0f4c859eSApple OSS Distributions // Must be careful since a power drop can be cancelled
2265*0f4c859eSApple OSS Distributions // from the following states:
2266*0f4c859eSApple OSS Distributions // - kIOPM_OurChangeTellClientsPowerDown
2267*0f4c859eSApple OSS Distributions // - kIOPM_OurChangeTellPriorityClientsPowerDown
2268*0f4c859eSApple OSS Distributions //
2269*0f4c859eSApple OSS Distributions // The child must not wait for this parent to raise power
2270*0f4c859eSApple OSS Distributions // if the power drop was cancelled. The solution is to cancel
2271*0f4c859eSApple OSS Distributions // the power drop if possible, then schedule an adjustment to
2272*0f4c859eSApple OSS Distributions // re-evaluate the parent's power state.
2273*0f4c859eSApple OSS Distributions //
2274*0f4c859eSApple OSS Distributions // Root domain is excluded to avoid idle sleep issues. And allow
2275*0f4c859eSApple OSS Distributions // root domain children to pop up when system is going to sleep.
2276*0f4c859eSApple OSS Distributions
2277*0f4c859eSApple OSS Distributions if ((fMachineState == kIOPM_OurChangeTellClientsPowerDown) ||
2278*0f4c859eSApple OSS Distributions (fMachineState == kIOPM_OurChangeTellPriorityClientsPowerDown)) {
2279*0f4c859eSApple OSS Distributions fDoNotPowerDown = true; // cancel power drop
2280*0f4c859eSApple OSS Distributions adjustPower = true;// schedule an adjustment
2281*0f4c859eSApple OSS Distributions PM_LOG1("%s: power drop cancelled in state %u by %s\n",
2282*0f4c859eSApple OSS Distributions getName(), fMachineState, child->getName());
2283*0f4c859eSApple OSS Distributions } else {
2284*0f4c859eSApple OSS Distributions // Beyond cancellation point, report the impending state.
2285*0f4c859eSApple OSS Distributions outputPowerFlags =
2286*0f4c859eSApple OSS Distributions fPowerStates[fHeadNotePowerState].outputPowerFlags;
2287*0f4c859eSApple OSS Distributions }
2288*0f4c859eSApple OSS Distributions } else if (IS_POWER_RISE) {
2289*0f4c859eSApple OSS Distributions // When raising power, must report the output power flags from
2290*0f4c859eSApple OSS Distributions // child's perspective. A child power request may arrive while
2291*0f4c859eSApple OSS Distributions // parent is transitioning upwards. If a request arrives after
2292*0f4c859eSApple OSS Distributions // setParentInfo() has already recorded the output power flags
2293*0f4c859eSApple OSS Distributions // for the next power state, then using the power supplied by
2294*0f4c859eSApple OSS Distributions // fCurrentPowerState is incorrect, and might cause the child
2295*0f4c859eSApple OSS Distributions // to wait when it should not.
2296*0f4c859eSApple OSS Distributions
2297*0f4c859eSApple OSS Distributions outputPowerFlags = childConnection->parentCurrentPowerFlags();
2298*0f4c859eSApple OSS Distributions }
2299*0f4c859eSApple OSS Distributions }
2300*0f4c859eSApple OSS Distributions child->fHeadNoteDomainTargetFlags |= outputPowerFlags;
2301*0f4c859eSApple OSS Distributions
2302*0f4c859eSApple OSS Distributions // Map child's requested power flags to one of our power state.
2303*0f4c859eSApple OSS Distributions
2304*0f4c859eSApple OSS Distributions for (order = 0; order < fNumberOfPowerStates; order++) {
2305*0f4c859eSApple OSS Distributions powerState = fPowerStates[order].stateOrderToIndex;
2306*0f4c859eSApple OSS Distributions if ((fPowerStates[powerState].outputPowerFlags & childRequestPowerFlags)
2307*0f4c859eSApple OSS Distributions == childRequestPowerFlags) {
2308*0f4c859eSApple OSS Distributions break;
2309*0f4c859eSApple OSS Distributions }
2310*0f4c859eSApple OSS Distributions }
2311*0f4c859eSApple OSS Distributions if (order >= fNumberOfPowerStates) {
2312*0f4c859eSApple OSS Distributions powerState = kPowerStateZero;
2313*0f4c859eSApple OSS Distributions }
2314*0f4c859eSApple OSS Distributions
2315*0f4c859eSApple OSS Distributions // Conditions that warrants a power adjustment on this parent.
2316*0f4c859eSApple OSS Distributions // Adjust power will also propagate any changes to the child's
2317*0f4c859eSApple OSS Distributions // prevent idle/sleep flags towards the root domain.
2318*0f4c859eSApple OSS Distributions
2319*0f4c859eSApple OSS Distributions if (!childConnection->childHasRequestedPower() ||
2320*0f4c859eSApple OSS Distributions (powerState != childConnection->getDesiredDomainState())) {
2321*0f4c859eSApple OSS Distributions adjustPower = true;
2322*0f4c859eSApple OSS Distributions }
2323*0f4c859eSApple OSS Distributions
2324*0f4c859eSApple OSS Distributions #if ENABLE_DEBUG_LOGS
2325*0f4c859eSApple OSS Distributions if (adjustPower) {
2326*0f4c859eSApple OSS Distributions PM_LOG("requestPowerDomainState[%s]: %s, init %d, %u->%u\n",
2327*0f4c859eSApple OSS Distributions getName(), child->getName(),
2328*0f4c859eSApple OSS Distributions !childConnection->childHasRequestedPower(),
2329*0f4c859eSApple OSS Distributions (uint32_t) childConnection->getDesiredDomainState(),
2330*0f4c859eSApple OSS Distributions (uint32_t) powerState);
2331*0f4c859eSApple OSS Distributions }
2332*0f4c859eSApple OSS Distributions #endif
2333*0f4c859eSApple OSS Distributions
2334*0f4c859eSApple OSS Distributions // Record the child's desires on the connection.
2335*0f4c859eSApple OSS Distributions childConnection->setChildHasRequestedPower();
2336*0f4c859eSApple OSS Distributions childConnection->setDesiredDomainState( powerState );
2337*0f4c859eSApple OSS Distributions
2338*0f4c859eSApple OSS Distributions // Schedule a request to re-evaluate all children desires and
2339*0f4c859eSApple OSS Distributions // adjust power state. Submit a request if one wasn't pending,
2340*0f4c859eSApple OSS Distributions // or if the current request is part of a call tree.
2341*0f4c859eSApple OSS Distributions
2342*0f4c859eSApple OSS Distributions if (adjustPower && !fDeviceOverrideEnabled &&
2343*0f4c859eSApple OSS Distributions (!fAdjustPowerScheduled || gIOPMRequest->getRootRequest())) {
2344*0f4c859eSApple OSS Distributions subRequest = acquirePMRequest(
2345*0f4c859eSApple OSS Distributions this, kIOPMRequestTypeAdjustPowerState, gIOPMRequest );
2346*0f4c859eSApple OSS Distributions if (subRequest) {
2347*0f4c859eSApple OSS Distributions submitPMRequest( subRequest );
2348*0f4c859eSApple OSS Distributions fAdjustPowerScheduled = true;
2349*0f4c859eSApple OSS Distributions }
2350*0f4c859eSApple OSS Distributions }
2351*0f4c859eSApple OSS Distributions
2352*0f4c859eSApple OSS Distributions return kIOReturnSuccess;
2353*0f4c859eSApple OSS Distributions }
2354*0f4c859eSApple OSS Distributions
2355*0f4c859eSApple OSS Distributions //*********************************************************************************
2356*0f4c859eSApple OSS Distributions // [public] temporaryPowerClampOn
2357*0f4c859eSApple OSS Distributions //
2358*0f4c859eSApple OSS Distributions // A power domain wants to be clamped to max power until it has children which
2359*0f4c859eSApple OSS Distributions // will then determine the power domain state.
2360*0f4c859eSApple OSS Distributions //
2361*0f4c859eSApple OSS Distributions // We enter the highest state until addPowerChild is called.
2362*0f4c859eSApple OSS Distributions //*********************************************************************************
2363*0f4c859eSApple OSS Distributions
2364*0f4c859eSApple OSS Distributions IOReturn
temporaryPowerClampOn(void)2365*0f4c859eSApple OSS Distributions IOService::temporaryPowerClampOn( void )
2366*0f4c859eSApple OSS Distributions {
2367*0f4c859eSApple OSS Distributions return requestPowerState( gIOPMPowerClientChildProxy, kIOPMPowerStateMax );
2368*0f4c859eSApple OSS Distributions }
2369*0f4c859eSApple OSS Distributions
2370*0f4c859eSApple OSS Distributions //*********************************************************************************
2371*0f4c859eSApple OSS Distributions // [public] makeUsable
2372*0f4c859eSApple OSS Distributions //
2373*0f4c859eSApple OSS Distributions // Some client of our device is asking that we become usable. Although
2374*0f4c859eSApple OSS Distributions // this has not come from a subclassed device object, treat it exactly
2375*0f4c859eSApple OSS Distributions // as if it had. In this way, subsequent requests for lower power from
2376*0f4c859eSApple OSS Distributions // a subclassed device object will pre-empt this request.
2377*0f4c859eSApple OSS Distributions //
2378*0f4c859eSApple OSS Distributions // We treat this as a subclass object request to switch to the
2379*0f4c859eSApple OSS Distributions // highest power state.
2380*0f4c859eSApple OSS Distributions //*********************************************************************************
2381*0f4c859eSApple OSS Distributions
2382*0f4c859eSApple OSS Distributions IOReturn
makeUsable(void)2383*0f4c859eSApple OSS Distributions IOService::makeUsable( void )
2384*0f4c859eSApple OSS Distributions {
2385*0f4c859eSApple OSS Distributions OUR_PMLog(kPMLogMakeUsable, 0, 0);
2386*0f4c859eSApple OSS Distributions return requestPowerState( gIOPMPowerClientDevice, kIOPMPowerStateMax );
2387*0f4c859eSApple OSS Distributions }
2388*0f4c859eSApple OSS Distributions
2389*0f4c859eSApple OSS Distributions //*********************************************************************************
2390*0f4c859eSApple OSS Distributions // [public] currentCapability
2391*0f4c859eSApple OSS Distributions //*********************************************************************************
2392*0f4c859eSApple OSS Distributions
2393*0f4c859eSApple OSS Distributions IOPMPowerFlags
currentCapability(void)2394*0f4c859eSApple OSS Distributions IOService::currentCapability( void )
2395*0f4c859eSApple OSS Distributions {
2396*0f4c859eSApple OSS Distributions if (!initialized) {
2397*0f4c859eSApple OSS Distributions return IOPMNotPowerManaged;
2398*0f4c859eSApple OSS Distributions }
2399*0f4c859eSApple OSS Distributions
2400*0f4c859eSApple OSS Distributions return fCurrentCapabilityFlags;
2401*0f4c859eSApple OSS Distributions }
2402*0f4c859eSApple OSS Distributions
2403*0f4c859eSApple OSS Distributions //*********************************************************************************
2404*0f4c859eSApple OSS Distributions // [public] changePowerStateTo
2405*0f4c859eSApple OSS Distributions //
2406*0f4c859eSApple OSS Distributions // Called by our power-controlling driver to change power state. The new desired
2407*0f4c859eSApple OSS Distributions // power state is computed and compared against the current power state. If those
2408*0f4c859eSApple OSS Distributions // power states differ, then a power state change is initiated.
2409*0f4c859eSApple OSS Distributions //*********************************************************************************
2410*0f4c859eSApple OSS Distributions
2411*0f4c859eSApple OSS Distributions IOReturn
changePowerStateTo(unsigned long ordinal)2412*0f4c859eSApple OSS Distributions IOService::changePowerStateTo( unsigned long ordinal )
2413*0f4c859eSApple OSS Distributions {
2414*0f4c859eSApple OSS Distributions OUR_PMLog(kPMLogChangeStateTo, ordinal, 0);
2415*0f4c859eSApple OSS Distributions return requestPowerState( gIOPMPowerClientDriver, ordinal );
2416*0f4c859eSApple OSS Distributions }
2417*0f4c859eSApple OSS Distributions
2418*0f4c859eSApple OSS Distributions //*********************************************************************************
2419*0f4c859eSApple OSS Distributions // [protected] changePowerStateToPriv
2420*0f4c859eSApple OSS Distributions //
2421*0f4c859eSApple OSS Distributions // Called by our driver subclass to change power state. The new desired power
2422*0f4c859eSApple OSS Distributions // state is computed and compared against the current power state. If those
2423*0f4c859eSApple OSS Distributions // power states differ, then a power state change is initiated.
2424*0f4c859eSApple OSS Distributions //*********************************************************************************
2425*0f4c859eSApple OSS Distributions
2426*0f4c859eSApple OSS Distributions IOReturn
changePowerStateToPriv(unsigned long ordinal)2427*0f4c859eSApple OSS Distributions IOService::changePowerStateToPriv( unsigned long ordinal )
2428*0f4c859eSApple OSS Distributions {
2429*0f4c859eSApple OSS Distributions OUR_PMLog(kPMLogChangeStateToPriv, ordinal, 0);
2430*0f4c859eSApple OSS Distributions return requestPowerState( gIOPMPowerClientDevice, ordinal );
2431*0f4c859eSApple OSS Distributions }
2432*0f4c859eSApple OSS Distributions
2433*0f4c859eSApple OSS Distributions //*********************************************************************************
2434*0f4c859eSApple OSS Distributions // [public] changePowerStateWithOverrideTo
2435*0f4c859eSApple OSS Distributions //
2436*0f4c859eSApple OSS Distributions // Called by our driver subclass to change power state. The new desired power
2437*0f4c859eSApple OSS Distributions // state is computed and compared against the current power state. If those
2438*0f4c859eSApple OSS Distributions // power states differ, then a power state change is initiated.
2439*0f4c859eSApple OSS Distributions // Override enforced - Children and Driver desires are ignored.
2440*0f4c859eSApple OSS Distributions //*********************************************************************************
2441*0f4c859eSApple OSS Distributions
2442*0f4c859eSApple OSS Distributions IOReturn
changePowerStateWithOverrideTo(IOPMPowerStateIndex ordinal,IOPMRequestTag tag)2443*0f4c859eSApple OSS Distributions IOService::changePowerStateWithOverrideTo( IOPMPowerStateIndex ordinal,
2444*0f4c859eSApple OSS Distributions IOPMRequestTag tag )
2445*0f4c859eSApple OSS Distributions {
2446*0f4c859eSApple OSS Distributions IOPMRequest * request;
2447*0f4c859eSApple OSS Distributions
2448*0f4c859eSApple OSS Distributions if (!initialized) {
2449*0f4c859eSApple OSS Distributions return kIOPMNotYetInitialized;
2450*0f4c859eSApple OSS Distributions }
2451*0f4c859eSApple OSS Distributions
2452*0f4c859eSApple OSS Distributions OUR_PMLog(kPMLogChangeStateToPriv, ordinal, 0);
2453*0f4c859eSApple OSS Distributions
2454*0f4c859eSApple OSS Distributions request = acquirePMRequest( this, kIOPMRequestTypeRequestPowerStateOverride );
2455*0f4c859eSApple OSS Distributions if (!request) {
2456*0f4c859eSApple OSS Distributions return kIOReturnNoMemory;
2457*0f4c859eSApple OSS Distributions }
2458*0f4c859eSApple OSS Distributions
2459*0f4c859eSApple OSS Distributions gIOPMPowerClientDevice->retain();
2460*0f4c859eSApple OSS Distributions request->fTag = tag;
2461*0f4c859eSApple OSS Distributions request->fArg0 = (void *) ordinal;
2462*0f4c859eSApple OSS Distributions request->fArg1 = (void *) gIOPMPowerClientDevice;
2463*0f4c859eSApple OSS Distributions request->fArg2 = NULL;
2464*0f4c859eSApple OSS Distributions #if NOT_READY
2465*0f4c859eSApple OSS Distributions if (action) {
2466*0f4c859eSApple OSS Distributions request->installCompletionAction( action, target, param );
2467*0f4c859eSApple OSS Distributions }
2468*0f4c859eSApple OSS Distributions #endif
2469*0f4c859eSApple OSS Distributions
2470*0f4c859eSApple OSS Distributions // Prevent needless downwards power transitions by clamping power
2471*0f4c859eSApple OSS Distributions // until the scheduled request is executed.
2472*0f4c859eSApple OSS Distributions //
2473*0f4c859eSApple OSS Distributions // TODO: review fOverrideMaxPowerState
2474*0f4c859eSApple OSS Distributions
2475*0f4c859eSApple OSS Distributions if (gIOPMWorkLoop->inGate() && (ordinal < fNumberOfPowerStates)) {
2476*0f4c859eSApple OSS Distributions fTempClampPowerState = StateMax(fTempClampPowerState, ordinal);
2477*0f4c859eSApple OSS Distributions fTempClampCount++;
2478*0f4c859eSApple OSS Distributions request->fArg2 = (void *)(uintptr_t) true;
2479*0f4c859eSApple OSS Distributions
2480*0f4c859eSApple OSS Distributions // Place a power state ceiling to prevent any transition to a
2481*0f4c859eSApple OSS Distributions // power state higher than fOverrideMaxPowerState.
2482*0f4c859eSApple OSS Distributions fOverrideMaxPowerState = ordinal;
2483*0f4c859eSApple OSS Distributions }
2484*0f4c859eSApple OSS Distributions
2485*0f4c859eSApple OSS Distributions submitPMRequest( request );
2486*0f4c859eSApple OSS Distributions return IOPMNoErr;
2487*0f4c859eSApple OSS Distributions }
2488*0f4c859eSApple OSS Distributions
2489*0f4c859eSApple OSS Distributions //*********************************************************************************
2490*0f4c859eSApple OSS Distributions // Tagged form of changePowerStateTo()
2491*0f4c859eSApple OSS Distributions //*********************************************************************************
2492*0f4c859eSApple OSS Distributions
2493*0f4c859eSApple OSS Distributions IOReturn
changePowerStateWithTagTo(IOPMPowerStateIndex ordinal,IOPMRequestTag tag)2494*0f4c859eSApple OSS Distributions IOService::changePowerStateWithTagTo( IOPMPowerStateIndex ordinal, IOPMRequestTag tag )
2495*0f4c859eSApple OSS Distributions {
2496*0f4c859eSApple OSS Distributions OUR_PMLog(kPMLogChangeStateTo, ordinal, tag);
2497*0f4c859eSApple OSS Distributions return requestPowerState(gIOPMPowerClientDriver, ordinal, tag);
2498*0f4c859eSApple OSS Distributions }
2499*0f4c859eSApple OSS Distributions
2500*0f4c859eSApple OSS Distributions //*********************************************************************************
2501*0f4c859eSApple OSS Distributions // Tagged form of changePowerStateToPriv()
2502*0f4c859eSApple OSS Distributions //*********************************************************************************
2503*0f4c859eSApple OSS Distributions
2504*0f4c859eSApple OSS Distributions IOReturn
changePowerStateWithTagToPriv(unsigned long ordinal,IOPMRequestTag tag)2505*0f4c859eSApple OSS Distributions IOService::changePowerStateWithTagToPriv( unsigned long ordinal, IOPMRequestTag tag )
2506*0f4c859eSApple OSS Distributions {
2507*0f4c859eSApple OSS Distributions OUR_PMLog(kPMLogChangeStateToPriv, ordinal, tag);
2508*0f4c859eSApple OSS Distributions return requestPowerState(gIOPMPowerClientDevice, ordinal, tag);
2509*0f4c859eSApple OSS Distributions }
2510*0f4c859eSApple OSS Distributions
2511*0f4c859eSApple OSS Distributions //*********************************************************************************
2512*0f4c859eSApple OSS Distributions // [public] changePowerStateForRootDomain
2513*0f4c859eSApple OSS Distributions //
2514*0f4c859eSApple OSS Distributions // Adjust the root domain's power desire on the target
2515*0f4c859eSApple OSS Distributions //*********************************************************************************
2516*0f4c859eSApple OSS Distributions
2517*0f4c859eSApple OSS Distributions IOReturn
changePowerStateForRootDomain(IOPMPowerStateIndex ordinal)2518*0f4c859eSApple OSS Distributions IOService::changePowerStateForRootDomain( IOPMPowerStateIndex ordinal )
2519*0f4c859eSApple OSS Distributions {
2520*0f4c859eSApple OSS Distributions OUR_PMLog(kPMLogChangeStateForRootDomain, ordinal, 0);
2521*0f4c859eSApple OSS Distributions return requestPowerState( gIOPMPowerClientRootDomain, ordinal );
2522*0f4c859eSApple OSS Distributions }
2523*0f4c859eSApple OSS Distributions
2524*0f4c859eSApple OSS Distributions //*********************************************************************************
2525*0f4c859eSApple OSS Distributions // [public for PMRD] quiescePowerTree
2526*0f4c859eSApple OSS Distributions //
2527*0f4c859eSApple OSS Distributions // For root domain to issue a request to quiesce the power tree.
2528*0f4c859eSApple OSS Distributions // Supplied callback invoked upon completion.
2529*0f4c859eSApple OSS Distributions //*********************************************************************************
2530*0f4c859eSApple OSS Distributions
2531*0f4c859eSApple OSS Distributions IOReturn
quiescePowerTree(void * target,IOPMCompletionAction action,void * param)2532*0f4c859eSApple OSS Distributions IOService::quiescePowerTree(
2533*0f4c859eSApple OSS Distributions void * target, IOPMCompletionAction action, void * param )
2534*0f4c859eSApple OSS Distributions {
2535*0f4c859eSApple OSS Distributions IOPMRequest * request;
2536*0f4c859eSApple OSS Distributions
2537*0f4c859eSApple OSS Distributions if (!initialized) {
2538*0f4c859eSApple OSS Distributions return kIOPMNotYetInitialized;
2539*0f4c859eSApple OSS Distributions }
2540*0f4c859eSApple OSS Distributions if (!target || !action) {
2541*0f4c859eSApple OSS Distributions return kIOReturnBadArgument;
2542*0f4c859eSApple OSS Distributions }
2543*0f4c859eSApple OSS Distributions
2544*0f4c859eSApple OSS Distributions OUR_PMLog(kPMLogQuiescePowerTree, 0, 0);
2545*0f4c859eSApple OSS Distributions
2546*0f4c859eSApple OSS Distributions // Target the root node instead of root domain. This is to avoid blocking
2547*0f4c859eSApple OSS Distributions // the quiesce request behind an existing root domain request in the work
2548*0f4c859eSApple OSS Distributions // queue. Root parent and root domain requests in the work queue must not
2549*0f4c859eSApple OSS Distributions // block the completion of the quiesce request.
2550*0f4c859eSApple OSS Distributions
2551*0f4c859eSApple OSS Distributions request = acquirePMRequest(gIOPMRootNode, kIOPMRequestTypeQuiescePowerTree);
2552*0f4c859eSApple OSS Distributions if (!request) {
2553*0f4c859eSApple OSS Distributions return kIOReturnNoMemory;
2554*0f4c859eSApple OSS Distributions }
2555*0f4c859eSApple OSS Distributions
2556*0f4c859eSApple OSS Distributions request->installCompletionAction(target, action, param);
2557*0f4c859eSApple OSS Distributions
2558*0f4c859eSApple OSS Distributions // Submit through the normal request flow. This will make sure any request
2559*0f4c859eSApple OSS Distributions // already in the request queue will get pushed over to the work queue for
2560*0f4c859eSApple OSS Distributions // execution. Any request submitted after this request may not be serviced.
2561*0f4c859eSApple OSS Distributions
2562*0f4c859eSApple OSS Distributions submitPMRequest( request );
2563*0f4c859eSApple OSS Distributions return kIOReturnSuccess;
2564*0f4c859eSApple OSS Distributions }
2565*0f4c859eSApple OSS Distributions
2566*0f4c859eSApple OSS Distributions //*********************************************************************************
2567*0f4c859eSApple OSS Distributions // [private] requestPowerState
2568*0f4c859eSApple OSS Distributions //*********************************************************************************
2569*0f4c859eSApple OSS Distributions
2570*0f4c859eSApple OSS Distributions IOReturn
requestPowerState(const OSSymbol * client,IOPMPowerStateIndex state,IOPMRequestTag tag)2571*0f4c859eSApple OSS Distributions IOService::requestPowerState(
2572*0f4c859eSApple OSS Distributions const OSSymbol * client,
2573*0f4c859eSApple OSS Distributions IOPMPowerStateIndex state,
2574*0f4c859eSApple OSS Distributions IOPMRequestTag tag )
2575*0f4c859eSApple OSS Distributions {
2576*0f4c859eSApple OSS Distributions IOPMRequest * request;
2577*0f4c859eSApple OSS Distributions
2578*0f4c859eSApple OSS Distributions if (!client || (state > UINT_MAX)) {
2579*0f4c859eSApple OSS Distributions return kIOReturnBadArgument;
2580*0f4c859eSApple OSS Distributions }
2581*0f4c859eSApple OSS Distributions if (!initialized) {
2582*0f4c859eSApple OSS Distributions return kIOPMNotYetInitialized;
2583*0f4c859eSApple OSS Distributions }
2584*0f4c859eSApple OSS Distributions
2585*0f4c859eSApple OSS Distributions request = acquirePMRequest( this, kIOPMRequestTypeRequestPowerState );
2586*0f4c859eSApple OSS Distributions if (!request) {
2587*0f4c859eSApple OSS Distributions return kIOReturnNoMemory;
2588*0f4c859eSApple OSS Distributions }
2589*0f4c859eSApple OSS Distributions
2590*0f4c859eSApple OSS Distributions client->retain();
2591*0f4c859eSApple OSS Distributions request->fTag = tag;
2592*0f4c859eSApple OSS Distributions request->fArg0 = (void *)(uintptr_t) state;
2593*0f4c859eSApple OSS Distributions request->fArg1 = (void *) client;
2594*0f4c859eSApple OSS Distributions request->fArg2 = NULL;
2595*0f4c859eSApple OSS Distributions #if NOT_READY
2596*0f4c859eSApple OSS Distributions if (action) {
2597*0f4c859eSApple OSS Distributions request->installCompletionAction( action, target, param );
2598*0f4c859eSApple OSS Distributions }
2599*0f4c859eSApple OSS Distributions #endif
2600*0f4c859eSApple OSS Distributions
2601*0f4c859eSApple OSS Distributions // Prevent needless downwards power transitions by clamping power
2602*0f4c859eSApple OSS Distributions // until the scheduled request is executed.
2603*0f4c859eSApple OSS Distributions
2604*0f4c859eSApple OSS Distributions if (gIOPMWorkLoop->inGate() && (state < fNumberOfPowerStates)) {
2605*0f4c859eSApple OSS Distributions fTempClampPowerState = StateMax(fTempClampPowerState, state);
2606*0f4c859eSApple OSS Distributions fTempClampCount++;
2607*0f4c859eSApple OSS Distributions request->fArg2 = (void *)(uintptr_t) true;
2608*0f4c859eSApple OSS Distributions }
2609*0f4c859eSApple OSS Distributions
2610*0f4c859eSApple OSS Distributions submitPMRequest( request );
2611*0f4c859eSApple OSS Distributions return IOPMNoErr;
2612*0f4c859eSApple OSS Distributions }
2613*0f4c859eSApple OSS Distributions
2614*0f4c859eSApple OSS Distributions //*********************************************************************************
2615*0f4c859eSApple OSS Distributions // [private] handleRequestPowerState
2616*0f4c859eSApple OSS Distributions //*********************************************************************************
2617*0f4c859eSApple OSS Distributions
2618*0f4c859eSApple OSS Distributions void
handleRequestPowerState(IOPMRequest * request)2619*0f4c859eSApple OSS Distributions IOService::handleRequestPowerState( IOPMRequest * request )
2620*0f4c859eSApple OSS Distributions {
2621*0f4c859eSApple OSS Distributions const OSSymbol * client = (const OSSymbol *) request->fArg1;
2622*0f4c859eSApple OSS Distributions IOPMPowerStateIndex state = (IOPMPowerStateIndex) request->fArg0;
2623*0f4c859eSApple OSS Distributions
2624*0f4c859eSApple OSS Distributions PM_ASSERT_IN_GATE();
2625*0f4c859eSApple OSS Distributions if (request->fArg2) {
2626*0f4c859eSApple OSS Distributions assert(fTempClampCount != 0);
2627*0f4c859eSApple OSS Distributions if (fTempClampCount) {
2628*0f4c859eSApple OSS Distributions fTempClampCount--;
2629*0f4c859eSApple OSS Distributions }
2630*0f4c859eSApple OSS Distributions if (!fTempClampCount) {
2631*0f4c859eSApple OSS Distributions fTempClampPowerState = kPowerStateZero;
2632*0f4c859eSApple OSS Distributions }
2633*0f4c859eSApple OSS Distributions }
2634*0f4c859eSApple OSS Distributions
2635*0f4c859eSApple OSS Distributions if (fNumberOfPowerStates && (state >= fNumberOfPowerStates)) {
2636*0f4c859eSApple OSS Distributions state = fHighestPowerState;
2637*0f4c859eSApple OSS Distributions }
2638*0f4c859eSApple OSS Distributions
2639*0f4c859eSApple OSS Distributions // The power suppression due to changePowerStateWithOverrideTo() expires
2640*0f4c859eSApple OSS Distributions // upon the next "device" power request - changePowerStateToPriv().
2641*0f4c859eSApple OSS Distributions
2642*0f4c859eSApple OSS Distributions if ((getPMRequestType() != kIOPMRequestTypeRequestPowerStateOverride) &&
2643*0f4c859eSApple OSS Distributions (client == gIOPMPowerClientDevice)) {
2644*0f4c859eSApple OSS Distributions fOverrideMaxPowerState = kIOPMPowerStateMax;
2645*0f4c859eSApple OSS Distributions }
2646*0f4c859eSApple OSS Distributions
2647*0f4c859eSApple OSS Distributions if ((state == kPowerStateZero) &&
2648*0f4c859eSApple OSS Distributions (client != gIOPMPowerClientDevice) &&
2649*0f4c859eSApple OSS Distributions (client != gIOPMPowerClientDriver) &&
2650*0f4c859eSApple OSS Distributions (client != gIOPMPowerClientChildProxy)) {
2651*0f4c859eSApple OSS Distributions removePowerClient(client);
2652*0f4c859eSApple OSS Distributions } else {
2653*0f4c859eSApple OSS Distributions updatePowerClient(client, state);
2654*0f4c859eSApple OSS Distributions }
2655*0f4c859eSApple OSS Distributions
2656*0f4c859eSApple OSS Distributions adjustPowerState();
2657*0f4c859eSApple OSS Distributions client->release();
2658*0f4c859eSApple OSS Distributions }
2659*0f4c859eSApple OSS Distributions
2660*0f4c859eSApple OSS Distributions //*********************************************************************************
2661*0f4c859eSApple OSS Distributions // [private] Helper functions to update/remove power clients.
2662*0f4c859eSApple OSS Distributions //*********************************************************************************
2663*0f4c859eSApple OSS Distributions
2664*0f4c859eSApple OSS Distributions void
updatePowerClient(const OSSymbol * client,IOPMPowerStateIndex powerState)2665*0f4c859eSApple OSS Distributions IOService::updatePowerClient( const OSSymbol * client, IOPMPowerStateIndex powerState )
2666*0f4c859eSApple OSS Distributions {
2667*0f4c859eSApple OSS Distributions IOPMPowerStateIndex oldPowerState = kPowerStateZero;
2668*0f4c859eSApple OSS Distributions
2669*0f4c859eSApple OSS Distributions if (powerState > UINT_MAX) {
2670*0f4c859eSApple OSS Distributions assert(false);
2671*0f4c859eSApple OSS Distributions return;
2672*0f4c859eSApple OSS Distributions }
2673*0f4c859eSApple OSS Distributions
2674*0f4c859eSApple OSS Distributions if (!fPowerClients) {
2675*0f4c859eSApple OSS Distributions fPowerClients = OSDictionary::withCapacity(4);
2676*0f4c859eSApple OSS Distributions }
2677*0f4c859eSApple OSS Distributions if (fPowerClients && client) {
2678*0f4c859eSApple OSS Distributions OSNumber * num = (OSNumber *) fPowerClients->getObject(client);
2679*0f4c859eSApple OSS Distributions if (num) {
2680*0f4c859eSApple OSS Distributions oldPowerState = num->unsigned32BitValue();
2681*0f4c859eSApple OSS Distributions num->setValue(powerState);
2682*0f4c859eSApple OSS Distributions } else {
2683*0f4c859eSApple OSS Distributions num = OSNumber::withNumber(powerState, 32);
2684*0f4c859eSApple OSS Distributions if (num) {
2685*0f4c859eSApple OSS Distributions fPowerClients->setObject(client, num);
2686*0f4c859eSApple OSS Distributions num->release();
2687*0f4c859eSApple OSS Distributions }
2688*0f4c859eSApple OSS Distributions }
2689*0f4c859eSApple OSS Distributions
2690*0f4c859eSApple OSS Distributions PM_ACTION_CLIENT(actionUpdatePowerClient, client, oldPowerState, powerState);
2691*0f4c859eSApple OSS Distributions }
2692*0f4c859eSApple OSS Distributions }
2693*0f4c859eSApple OSS Distributions
2694*0f4c859eSApple OSS Distributions void
removePowerClient(const OSSymbol * client)2695*0f4c859eSApple OSS Distributions IOService::removePowerClient( const OSSymbol * client )
2696*0f4c859eSApple OSS Distributions {
2697*0f4c859eSApple OSS Distributions if (fPowerClients && client) {
2698*0f4c859eSApple OSS Distributions fPowerClients->removeObject(client);
2699*0f4c859eSApple OSS Distributions }
2700*0f4c859eSApple OSS Distributions }
2701*0f4c859eSApple OSS Distributions
2702*0f4c859eSApple OSS Distributions IOPMPowerStateIndex
getPowerStateForClient(const OSSymbol * client)2703*0f4c859eSApple OSS Distributions IOService::getPowerStateForClient( const OSSymbol * client )
2704*0f4c859eSApple OSS Distributions {
2705*0f4c859eSApple OSS Distributions IOPMPowerStateIndex powerState = kPowerStateZero;
2706*0f4c859eSApple OSS Distributions
2707*0f4c859eSApple OSS Distributions if (fPowerClients && client) {
2708*0f4c859eSApple OSS Distributions OSNumber * num = (OSNumber *) fPowerClients->getObject(client);
2709*0f4c859eSApple OSS Distributions if (num) {
2710*0f4c859eSApple OSS Distributions powerState = num->unsigned32BitValue();
2711*0f4c859eSApple OSS Distributions }
2712*0f4c859eSApple OSS Distributions }
2713*0f4c859eSApple OSS Distributions return powerState;
2714*0f4c859eSApple OSS Distributions }
2715*0f4c859eSApple OSS Distributions
2716*0f4c859eSApple OSS Distributions //*********************************************************************************
2717*0f4c859eSApple OSS Distributions // [protected] powerOverrideOnPriv
2718*0f4c859eSApple OSS Distributions //*********************************************************************************
2719*0f4c859eSApple OSS Distributions
2720*0f4c859eSApple OSS Distributions IOReturn
powerOverrideOnPriv(void)2721*0f4c859eSApple OSS Distributions IOService::powerOverrideOnPriv( void )
2722*0f4c859eSApple OSS Distributions {
2723*0f4c859eSApple OSS Distributions IOPMRequest * request;
2724*0f4c859eSApple OSS Distributions
2725*0f4c859eSApple OSS Distributions if (!initialized) {
2726*0f4c859eSApple OSS Distributions return IOPMNotYetInitialized;
2727*0f4c859eSApple OSS Distributions }
2728*0f4c859eSApple OSS Distributions
2729*0f4c859eSApple OSS Distributions if (gIOPMWorkLoop->inGate()) {
2730*0f4c859eSApple OSS Distributions fDeviceOverrideEnabled = true;
2731*0f4c859eSApple OSS Distributions return IOPMNoErr;
2732*0f4c859eSApple OSS Distributions }
2733*0f4c859eSApple OSS Distributions
2734*0f4c859eSApple OSS Distributions request = acquirePMRequest( this, kIOPMRequestTypePowerOverrideOnPriv );
2735*0f4c859eSApple OSS Distributions if (!request) {
2736*0f4c859eSApple OSS Distributions return kIOReturnNoMemory;
2737*0f4c859eSApple OSS Distributions }
2738*0f4c859eSApple OSS Distributions
2739*0f4c859eSApple OSS Distributions submitPMRequest( request );
2740*0f4c859eSApple OSS Distributions return IOPMNoErr;
2741*0f4c859eSApple OSS Distributions }
2742*0f4c859eSApple OSS Distributions
2743*0f4c859eSApple OSS Distributions //*********************************************************************************
2744*0f4c859eSApple OSS Distributions // [protected] powerOverrideOffPriv
2745*0f4c859eSApple OSS Distributions //*********************************************************************************
2746*0f4c859eSApple OSS Distributions
2747*0f4c859eSApple OSS Distributions IOReturn
powerOverrideOffPriv(void)2748*0f4c859eSApple OSS Distributions IOService::powerOverrideOffPriv( void )
2749*0f4c859eSApple OSS Distributions {
2750*0f4c859eSApple OSS Distributions IOPMRequest * request;
2751*0f4c859eSApple OSS Distributions
2752*0f4c859eSApple OSS Distributions if (!initialized) {
2753*0f4c859eSApple OSS Distributions return IOPMNotYetInitialized;
2754*0f4c859eSApple OSS Distributions }
2755*0f4c859eSApple OSS Distributions
2756*0f4c859eSApple OSS Distributions if (gIOPMWorkLoop->inGate()) {
2757*0f4c859eSApple OSS Distributions fDeviceOverrideEnabled = false;
2758*0f4c859eSApple OSS Distributions return IOPMNoErr;
2759*0f4c859eSApple OSS Distributions }
2760*0f4c859eSApple OSS Distributions
2761*0f4c859eSApple OSS Distributions request = acquirePMRequest( this, kIOPMRequestTypePowerOverrideOffPriv );
2762*0f4c859eSApple OSS Distributions if (!request) {
2763*0f4c859eSApple OSS Distributions return kIOReturnNoMemory;
2764*0f4c859eSApple OSS Distributions }
2765*0f4c859eSApple OSS Distributions
2766*0f4c859eSApple OSS Distributions submitPMRequest( request );
2767*0f4c859eSApple OSS Distributions return IOPMNoErr;
2768*0f4c859eSApple OSS Distributions }
2769*0f4c859eSApple OSS Distributions
2770*0f4c859eSApple OSS Distributions //*********************************************************************************
2771*0f4c859eSApple OSS Distributions // [private] handlePowerOverrideChanged
2772*0f4c859eSApple OSS Distributions //*********************************************************************************
2773*0f4c859eSApple OSS Distributions
2774*0f4c859eSApple OSS Distributions void
handlePowerOverrideChanged(IOPMRequest * request)2775*0f4c859eSApple OSS Distributions IOService::handlePowerOverrideChanged( IOPMRequest * request )
2776*0f4c859eSApple OSS Distributions {
2777*0f4c859eSApple OSS Distributions PM_ASSERT_IN_GATE();
2778*0f4c859eSApple OSS Distributions if (request->getType() == kIOPMRequestTypePowerOverrideOnPriv) {
2779*0f4c859eSApple OSS Distributions OUR_PMLog(kPMLogOverrideOn, 0, 0);
2780*0f4c859eSApple OSS Distributions fDeviceOverrideEnabled = true;
2781*0f4c859eSApple OSS Distributions } else {
2782*0f4c859eSApple OSS Distributions OUR_PMLog(kPMLogOverrideOff, 0, 0);
2783*0f4c859eSApple OSS Distributions fDeviceOverrideEnabled = false;
2784*0f4c859eSApple OSS Distributions }
2785*0f4c859eSApple OSS Distributions
2786*0f4c859eSApple OSS Distributions adjustPowerState();
2787*0f4c859eSApple OSS Distributions }
2788*0f4c859eSApple OSS Distributions
2789*0f4c859eSApple OSS Distributions //*********************************************************************************
2790*0f4c859eSApple OSS Distributions // [private] computeDesiredState
2791*0f4c859eSApple OSS Distributions //*********************************************************************************
2792*0f4c859eSApple OSS Distributions
2793*0f4c859eSApple OSS Distributions void
computeDesiredState(unsigned long localClamp,bool computeOnly)2794*0f4c859eSApple OSS Distributions IOService::computeDesiredState( unsigned long localClamp, bool computeOnly )
2795*0f4c859eSApple OSS Distributions {
2796*0f4c859eSApple OSS Distributions OSIterator * iter;
2797*0f4c859eSApple OSS Distributions OSObject * next;
2798*0f4c859eSApple OSS Distributions IOPowerConnection * connection;
2799*0f4c859eSApple OSS Distributions IOPMPowerStateIndex desiredState = kPowerStateZero;
2800*0f4c859eSApple OSS Distributions IOPMPowerStateIndex newPowerState = kPowerStateZero;
2801*0f4c859eSApple OSS Distributions bool hasChildren = false;
2802*0f4c859eSApple OSS Distributions
2803*0f4c859eSApple OSS Distributions // Desired power state is always 0 without a controlling driver.
2804*0f4c859eSApple OSS Distributions
2805*0f4c859eSApple OSS Distributions if (!fNumberOfPowerStates) {
2806*0f4c859eSApple OSS Distributions fDesiredPowerState = kPowerStateZero;
2807*0f4c859eSApple OSS Distributions return;
2808*0f4c859eSApple OSS Distributions }
2809*0f4c859eSApple OSS Distributions
2810*0f4c859eSApple OSS Distributions // Examine the children's desired power state.
2811*0f4c859eSApple OSS Distributions
2812*0f4c859eSApple OSS Distributions iter = getChildIterator(gIOPowerPlane);
2813*0f4c859eSApple OSS Distributions if (iter) {
2814*0f4c859eSApple OSS Distributions while ((next = iter->getNextObject())) {
2815*0f4c859eSApple OSS Distributions if ((connection = OSDynamicCast(IOPowerConnection, next))) {
2816*0f4c859eSApple OSS Distributions if (connection->getReadyFlag() == false) {
2817*0f4c859eSApple OSS Distributions PM_LOG3("[%s] %s: connection not ready\n",
2818*0f4c859eSApple OSS Distributions getName(), __FUNCTION__);
2819*0f4c859eSApple OSS Distributions continue;
2820*0f4c859eSApple OSS Distributions }
2821*0f4c859eSApple OSS Distributions if (connection->childHasRequestedPower()) {
2822*0f4c859eSApple OSS Distributions hasChildren = true;
2823*0f4c859eSApple OSS Distributions }
2824*0f4c859eSApple OSS Distributions desiredState = StateMax(connection->getDesiredDomainState(), desiredState);
2825*0f4c859eSApple OSS Distributions }
2826*0f4c859eSApple OSS Distributions }
2827*0f4c859eSApple OSS Distributions iter->release();
2828*0f4c859eSApple OSS Distributions }
2829*0f4c859eSApple OSS Distributions if (hasChildren) {
2830*0f4c859eSApple OSS Distributions updatePowerClient(gIOPMPowerClientChildren, desiredState);
2831*0f4c859eSApple OSS Distributions } else {
2832*0f4c859eSApple OSS Distributions removePowerClient(gIOPMPowerClientChildren);
2833*0f4c859eSApple OSS Distributions }
2834*0f4c859eSApple OSS Distributions
2835*0f4c859eSApple OSS Distributions // Iterate through all power clients to determine the min power state.
2836*0f4c859eSApple OSS Distributions
2837*0f4c859eSApple OSS Distributions iter = OSCollectionIterator::withCollection(fPowerClients);
2838*0f4c859eSApple OSS Distributions if (iter) {
2839*0f4c859eSApple OSS Distributions const OSSymbol * client;
2840*0f4c859eSApple OSS Distributions while ((client = (const OSSymbol *) iter->getNextObject())) {
2841*0f4c859eSApple OSS Distributions // Ignore child and driver when override is in effect.
2842*0f4c859eSApple OSS Distributions if ((fDeviceOverrideEnabled ||
2843*0f4c859eSApple OSS Distributions (getPMRequestType() == kIOPMRequestTypeRequestPowerStateOverride)) &&
2844*0f4c859eSApple OSS Distributions ((client == gIOPMPowerClientChildren) ||
2845*0f4c859eSApple OSS Distributions (client == gIOPMPowerClientDriver))) {
2846*0f4c859eSApple OSS Distributions continue;
2847*0f4c859eSApple OSS Distributions }
2848*0f4c859eSApple OSS Distributions
2849*0f4c859eSApple OSS Distributions // Ignore child proxy when children are present.
2850*0f4c859eSApple OSS Distributions if (hasChildren && (client == gIOPMPowerClientChildProxy)) {
2851*0f4c859eSApple OSS Distributions continue;
2852*0f4c859eSApple OSS Distributions }
2853*0f4c859eSApple OSS Distributions
2854*0f4c859eSApple OSS Distributions // Advisory tickles are irrelevant unless system is in full wake
2855*0f4c859eSApple OSS Distributions if (client == gIOPMPowerClientAdvisoryTickle &&
2856*0f4c859eSApple OSS Distributions !gIOPMAdvisoryTickleEnabled) {
2857*0f4c859eSApple OSS Distributions continue;
2858*0f4c859eSApple OSS Distributions }
2859*0f4c859eSApple OSS Distributions
2860*0f4c859eSApple OSS Distributions desiredState = getPowerStateForClient(client);
2861*0f4c859eSApple OSS Distributions assert(desiredState < fNumberOfPowerStates);
2862*0f4c859eSApple OSS Distributions PM_LOG1(" %u %s\n",
2863*0f4c859eSApple OSS Distributions (uint32_t) desiredState, client->getCStringNoCopy());
2864*0f4c859eSApple OSS Distributions
2865*0f4c859eSApple OSS Distributions newPowerState = StateMax(newPowerState, desiredState);
2866*0f4c859eSApple OSS Distributions
2867*0f4c859eSApple OSS Distributions if (client == gIOPMPowerClientDevice) {
2868*0f4c859eSApple OSS Distributions fDeviceDesire = desiredState;
2869*0f4c859eSApple OSS Distributions }
2870*0f4c859eSApple OSS Distributions }
2871*0f4c859eSApple OSS Distributions iter->release();
2872*0f4c859eSApple OSS Distributions }
2873*0f4c859eSApple OSS Distributions
2874*0f4c859eSApple OSS Distributions // Factor in the temporary power desires.
2875*0f4c859eSApple OSS Distributions
2876*0f4c859eSApple OSS Distributions newPowerState = StateMax(newPowerState, localClamp);
2877*0f4c859eSApple OSS Distributions newPowerState = StateMax(newPowerState, fTempClampPowerState);
2878*0f4c859eSApple OSS Distributions
2879*0f4c859eSApple OSS Distributions // Limit check against max power override.
2880*0f4c859eSApple OSS Distributions
2881*0f4c859eSApple OSS Distributions newPowerState = StateMin(newPowerState, fOverrideMaxPowerState);
2882*0f4c859eSApple OSS Distributions
2883*0f4c859eSApple OSS Distributions // Limit check against number of power states.
2884*0f4c859eSApple OSS Distributions
2885*0f4c859eSApple OSS Distributions if (newPowerState >= fNumberOfPowerStates) {
2886*0f4c859eSApple OSS Distributions newPowerState = fHighestPowerState;
2887*0f4c859eSApple OSS Distributions }
2888*0f4c859eSApple OSS Distributions
2889*0f4c859eSApple OSS Distributions if (getPMRootDomain()->isAOTMode()) {
2890*0f4c859eSApple OSS Distributions if ((kIOPMPreventIdleSleep & fPowerStates[newPowerState].capabilityFlags)
2891*0f4c859eSApple OSS Distributions && !(kIOPMPreventIdleSleep & fPowerStates[fDesiredPowerState].capabilityFlags)) {
2892*0f4c859eSApple OSS Distributions getPMRootDomain()->claimSystemWakeEvent(this, kIOPMWakeEventAOTExit, getName(), NULL);
2893*0f4c859eSApple OSS Distributions }
2894*0f4c859eSApple OSS Distributions }
2895*0f4c859eSApple OSS Distributions
2896*0f4c859eSApple OSS Distributions fDesiredPowerState = newPowerState;
2897*0f4c859eSApple OSS Distributions
2898*0f4c859eSApple OSS Distributions PM_LOG1(" temp %u, clamp %u, current %u, new %u\n",
2899*0f4c859eSApple OSS Distributions (uint32_t) localClamp, (uint32_t) fTempClampPowerState,
2900*0f4c859eSApple OSS Distributions (uint32_t) fCurrentPowerState, (uint32_t) newPowerState);
2901*0f4c859eSApple OSS Distributions
2902*0f4c859eSApple OSS Distributions if (!computeOnly) {
2903*0f4c859eSApple OSS Distributions // Restart idle timer if possible when device desire has increased.
2904*0f4c859eSApple OSS Distributions // Or if an advisory desire exists.
2905*0f4c859eSApple OSS Distributions
2906*0f4c859eSApple OSS Distributions if (fIdleTimerPeriod && fIdleTimerStopped) {
2907*0f4c859eSApple OSS Distributions restartIdleTimer();
2908*0f4c859eSApple OSS Distributions }
2909*0f4c859eSApple OSS Distributions
2910*0f4c859eSApple OSS Distributions // Invalidate cached tickle power state when desires change, and not
2911*0f4c859eSApple OSS Distributions // due to a tickle request. In case the driver has requested a lower
2912*0f4c859eSApple OSS Distributions // power state, but the tickle is caching a higher power state which
2913*0f4c859eSApple OSS Distributions // will drop future tickles until the cached value is lowered or in-
2914*0f4c859eSApple OSS Distributions // validated. The invalidation must occur before the power transition
2915*0f4c859eSApple OSS Distributions // to avoid dropping a necessary tickle.
2916*0f4c859eSApple OSS Distributions
2917*0f4c859eSApple OSS Distributions if ((getPMRequestType() != kIOPMRequestTypeActivityTickle) &&
2918*0f4c859eSApple OSS Distributions (fActivityTicklePowerState != kInvalidTicklePowerState)) {
2919*0f4c859eSApple OSS Distributions IOLockLock(fActivityLock);
2920*0f4c859eSApple OSS Distributions fActivityTicklePowerState = kInvalidTicklePowerState;
2921*0f4c859eSApple OSS Distributions IOLockUnlock(fActivityLock);
2922*0f4c859eSApple OSS Distributions }
2923*0f4c859eSApple OSS Distributions }
2924*0f4c859eSApple OSS Distributions }
2925*0f4c859eSApple OSS Distributions
2926*0f4c859eSApple OSS Distributions //*********************************************************************************
2927*0f4c859eSApple OSS Distributions // [public] currentPowerConsumption
2928*0f4c859eSApple OSS Distributions //
2929*0f4c859eSApple OSS Distributions //*********************************************************************************
2930*0f4c859eSApple OSS Distributions
2931*0f4c859eSApple OSS Distributions unsigned long
currentPowerConsumption(void)2932*0f4c859eSApple OSS Distributions IOService::currentPowerConsumption( void )
2933*0f4c859eSApple OSS Distributions {
2934*0f4c859eSApple OSS Distributions if (!initialized) {
2935*0f4c859eSApple OSS Distributions return kIOPMUnknown;
2936*0f4c859eSApple OSS Distributions }
2937*0f4c859eSApple OSS Distributions
2938*0f4c859eSApple OSS Distributions return fCurrentPowerConsumption;
2939*0f4c859eSApple OSS Distributions }
2940*0f4c859eSApple OSS Distributions
2941*0f4c859eSApple OSS Distributions //*********************************************************************************
2942*0f4c859eSApple OSS Distributions // [deprecated] getPMworkloop
2943*0f4c859eSApple OSS Distributions //*********************************************************************************
2944*0f4c859eSApple OSS Distributions
2945*0f4c859eSApple OSS Distributions #ifndef __LP64__
2946*0f4c859eSApple OSS Distributions IOWorkLoop *
getPMworkloop(void)2947*0f4c859eSApple OSS Distributions IOService::getPMworkloop( void )
2948*0f4c859eSApple OSS Distributions {
2949*0f4c859eSApple OSS Distributions return gIOPMWorkLoop;
2950*0f4c859eSApple OSS Distributions }
2951*0f4c859eSApple OSS Distributions #endif
2952*0f4c859eSApple OSS Distributions
2953*0f4c859eSApple OSS Distributions #if NOT_YET
2954*0f4c859eSApple OSS Distributions
2955*0f4c859eSApple OSS Distributions //*********************************************************************************
2956*0f4c859eSApple OSS Distributions // Power Parent/Children Applier
2957*0f4c859eSApple OSS Distributions //*********************************************************************************
2958*0f4c859eSApple OSS Distributions
2959*0f4c859eSApple OSS Distributions static void
applyToPowerChildren(IOService * service,IOServiceApplierFunction applier,void * context,IOOptionBits options)2960*0f4c859eSApple OSS Distributions applyToPowerChildren(
2961*0f4c859eSApple OSS Distributions IOService * service,
2962*0f4c859eSApple OSS Distributions IOServiceApplierFunction applier,
2963*0f4c859eSApple OSS Distributions void * context,
2964*0f4c859eSApple OSS Distributions IOOptionBits options )
2965*0f4c859eSApple OSS Distributions {
2966*0f4c859eSApple OSS Distributions PM_ASSERT_IN_GATE();
2967*0f4c859eSApple OSS Distributions
2968*0f4c859eSApple OSS Distributions IORegistryEntry * entry;
2969*0f4c859eSApple OSS Distributions IORegistryIterator * iter;
2970*0f4c859eSApple OSS Distributions IOPowerConnection * connection;
2971*0f4c859eSApple OSS Distributions IOService * child;
2972*0f4c859eSApple OSS Distributions
2973*0f4c859eSApple OSS Distributions iter = IORegistryIterator::iterateOver(service, gIOPowerPlane, options);
2974*0f4c859eSApple OSS Distributions if (iter) {
2975*0f4c859eSApple OSS Distributions while ((entry = iter->getNextObject())) {
2976*0f4c859eSApple OSS Distributions // Get child of IOPowerConnection objects
2977*0f4c859eSApple OSS Distributions if ((connection = OSDynamicCast(IOPowerConnection, entry))) {
2978*0f4c859eSApple OSS Distributions child = (IOService *) connection->copyChildEntry(gIOPowerPlane);
2979*0f4c859eSApple OSS Distributions if (child) {
2980*0f4c859eSApple OSS Distributions (*applier)(child, context);
2981*0f4c859eSApple OSS Distributions child->release();
2982*0f4c859eSApple OSS Distributions }
2983*0f4c859eSApple OSS Distributions }
2984*0f4c859eSApple OSS Distributions }
2985*0f4c859eSApple OSS Distributions iter->release();
2986*0f4c859eSApple OSS Distributions }
2987*0f4c859eSApple OSS Distributions }
2988*0f4c859eSApple OSS Distributions
2989*0f4c859eSApple OSS Distributions static void
applyToPowerParent(IOService * service,IOServiceApplierFunction applier,void * context,IOOptionBits options)2990*0f4c859eSApple OSS Distributions applyToPowerParent(
2991*0f4c859eSApple OSS Distributions IOService * service,
2992*0f4c859eSApple OSS Distributions IOServiceApplierFunction applier,
2993*0f4c859eSApple OSS Distributions void * context,
2994*0f4c859eSApple OSS Distributions IOOptionBits options )
2995*0f4c859eSApple OSS Distributions {
2996*0f4c859eSApple OSS Distributions PM_ASSERT_IN_GATE();
2997*0f4c859eSApple OSS Distributions
2998*0f4c859eSApple OSS Distributions IORegistryEntry * entry;
2999*0f4c859eSApple OSS Distributions IORegistryIterator * iter;
3000*0f4c859eSApple OSS Distributions IOPowerConnection * connection;
3001*0f4c859eSApple OSS Distributions IOService * parent;
3002*0f4c859eSApple OSS Distributions
3003*0f4c859eSApple OSS Distributions iter = IORegistryIterator::iterateOver(service, gIOPowerPlane,
3004*0f4c859eSApple OSS Distributions options | kIORegistryIterateParents);
3005*0f4c859eSApple OSS Distributions if (iter) {
3006*0f4c859eSApple OSS Distributions while ((entry = iter->getNextObject())) {
3007*0f4c859eSApple OSS Distributions // Get child of IOPowerConnection objects
3008*0f4c859eSApple OSS Distributions if ((connection = OSDynamicCast(IOPowerConnection, entry))) {
3009*0f4c859eSApple OSS Distributions parent = (IOService *) connection->copyParentEntry(gIOPowerPlane);
3010*0f4c859eSApple OSS Distributions if (parent) {
3011*0f4c859eSApple OSS Distributions (*applier)(parent, context);
3012*0f4c859eSApple OSS Distributions parent->release();
3013*0f4c859eSApple OSS Distributions }
3014*0f4c859eSApple OSS Distributions }
3015*0f4c859eSApple OSS Distributions }
3016*0f4c859eSApple OSS Distributions iter->release();
3017*0f4c859eSApple OSS Distributions }
3018*0f4c859eSApple OSS Distributions }
3019*0f4c859eSApple OSS Distributions
3020*0f4c859eSApple OSS Distributions #endif /* NOT_YET */
3021*0f4c859eSApple OSS Distributions
3022*0f4c859eSApple OSS Distributions // MARK: -
3023*0f4c859eSApple OSS Distributions // MARK: Activity Tickle & Idle Timer
3024*0f4c859eSApple OSS Distributions
3025*0f4c859eSApple OSS Distributions void
setAdvisoryTickleEnable(bool enable)3026*0f4c859eSApple OSS Distributions IOService::setAdvisoryTickleEnable( bool enable )
3027*0f4c859eSApple OSS Distributions {
3028*0f4c859eSApple OSS Distributions gIOPMAdvisoryTickleEnabled = enable;
3029*0f4c859eSApple OSS Distributions }
3030*0f4c859eSApple OSS Distributions
3031*0f4c859eSApple OSS Distributions //*********************************************************************************
3032*0f4c859eSApple OSS Distributions // [public] activityTickle
3033*0f4c859eSApple OSS Distributions //
3034*0f4c859eSApple OSS Distributions // The tickle with parameter kIOPMSuperclassPolicy1 causes the activity
3035*0f4c859eSApple OSS Distributions // flag to be set, and the device state checked. If the device has been
3036*0f4c859eSApple OSS Distributions // powered down, it is powered up again.
3037*0f4c859eSApple OSS Distributions // The tickle with parameter kIOPMSubclassPolicy is ignored here and
3038*0f4c859eSApple OSS Distributions // should be intercepted by a subclass.
3039*0f4c859eSApple OSS Distributions //*********************************************************************************
3040*0f4c859eSApple OSS Distributions
3041*0f4c859eSApple OSS Distributions bool
activityTickle(unsigned long type,unsigned long stateNumber)3042*0f4c859eSApple OSS Distributions IOService::activityTickle( unsigned long type, unsigned long stateNumber )
3043*0f4c859eSApple OSS Distributions {
3044*0f4c859eSApple OSS Distributions if (!initialized) {
3045*0f4c859eSApple OSS Distributions return true; // no power change
3046*0f4c859eSApple OSS Distributions }
3047*0f4c859eSApple OSS Distributions
3048*0f4c859eSApple OSS Distributions if (!fPowerStates) {
3049*0f4c859eSApple OSS Distributions // registerPowerDriver may not have completed
3050*0f4c859eSApple OSS Distributions IOPMRequest * request;
3051*0f4c859eSApple OSS Distributions
3052*0f4c859eSApple OSS Distributions request = acquirePMRequest( this, kIOPMRequestTypeDeferredActivityTickle );
3053*0f4c859eSApple OSS Distributions if (request) {
3054*0f4c859eSApple OSS Distributions request->fArg0 = (void *) type;
3055*0f4c859eSApple OSS Distributions request->fArg1 = (void *)(uintptr_t) stateNumber;
3056*0f4c859eSApple OSS Distributions submitPMRequest(request);
3057*0f4c859eSApple OSS Distributions }
3058*0f4c859eSApple OSS Distributions // Returns false if the activityTickle might cause a transition to a
3059*0f4c859eSApple OSS Distributions // higher powered state. We don't know, so this seems safest.
3060*0f4c859eSApple OSS Distributions return false;
3061*0f4c859eSApple OSS Distributions }
3062*0f4c859eSApple OSS Distributions
3063*0f4c859eSApple OSS Distributions return _activityTickle(type, stateNumber);
3064*0f4c859eSApple OSS Distributions }
3065*0f4c859eSApple OSS Distributions
3066*0f4c859eSApple OSS Distributions //*********************************************************************************
3067*0f4c859eSApple OSS Distributions // [private] handleDeferredActivityTickle
3068*0f4c859eSApple OSS Distributions //*********************************************************************************
3069*0f4c859eSApple OSS Distributions
3070*0f4c859eSApple OSS Distributions void
handleDeferredActivityTickle(IOPMRequest * request)3071*0f4c859eSApple OSS Distributions IOService::handleDeferredActivityTickle( IOPMRequest * request )
3072*0f4c859eSApple OSS Distributions {
3073*0f4c859eSApple OSS Distributions unsigned long type = (unsigned long) request->fArg1;
3074*0f4c859eSApple OSS Distributions unsigned long stateNumber = (unsigned long) request->fArg2;
3075*0f4c859eSApple OSS Distributions
3076*0f4c859eSApple OSS Distributions if (!fPowerStates) {
3077*0f4c859eSApple OSS Distributions // registerPowerDriver was not called before activityTickle()
3078*0f4c859eSApple OSS Distributions return;
3079*0f4c859eSApple OSS Distributions }
3080*0f4c859eSApple OSS Distributions (void) _activityTickle(type, stateNumber);
3081*0f4c859eSApple OSS Distributions }
3082*0f4c859eSApple OSS Distributions
3083*0f4c859eSApple OSS Distributions //*********************************************************************************
3084*0f4c859eSApple OSS Distributions // [private] _activityTickle
3085*0f4c859eSApple OSS Distributions //
3086*0f4c859eSApple OSS Distributions // The tickle with parameter kIOPMSuperclassPolicy1 causes the activity
3087*0f4c859eSApple OSS Distributions // flag to be set, and the device state checked. If the device has been
3088*0f4c859eSApple OSS Distributions // powered down, it is powered up again.
3089*0f4c859eSApple OSS Distributions // The tickle with parameter kIOPMSubclassPolicy is ignored here and
3090*0f4c859eSApple OSS Distributions // should be intercepted by a subclass.
3091*0f4c859eSApple OSS Distributions //*********************************************************************************
3092*0f4c859eSApple OSS Distributions
3093*0f4c859eSApple OSS Distributions bool
_activityTickle(unsigned long type,unsigned long stateNumber)3094*0f4c859eSApple OSS Distributions IOService::_activityTickle( unsigned long type, unsigned long stateNumber )
3095*0f4c859eSApple OSS Distributions {
3096*0f4c859eSApple OSS Distributions IOPMRequest * request;
3097*0f4c859eSApple OSS Distributions bool noPowerChange = true;
3098*0f4c859eSApple OSS Distributions uint32_t tickleFlags;
3099*0f4c859eSApple OSS Distributions
3100*0f4c859eSApple OSS Distributions if ((type == kIOPMSuperclassPolicy1) && StateOrder(stateNumber)) {
3101*0f4c859eSApple OSS Distributions IOLockLock(fActivityLock);
3102*0f4c859eSApple OSS Distributions
3103*0f4c859eSApple OSS Distributions // Record device activity for the idle timer handler.
3104*0f4c859eSApple OSS Distributions
3105*0f4c859eSApple OSS Distributions fDeviceWasActive = true;
3106*0f4c859eSApple OSS Distributions fActivityTickleCount++;
3107*0f4c859eSApple OSS Distributions clock_get_uptime(&fDeviceActiveTimestamp);
3108*0f4c859eSApple OSS Distributions
3109*0f4c859eSApple OSS Distributions PM_ACTION_TICKLE(actionActivityTickle);
3110*0f4c859eSApple OSS Distributions
3111*0f4c859eSApple OSS Distributions // Record the last tickle power state.
3112*0f4c859eSApple OSS Distributions // This helps to filter out redundant tickles as
3113*0f4c859eSApple OSS Distributions // this function may be called from the data path.
3114*0f4c859eSApple OSS Distributions
3115*0f4c859eSApple OSS Distributions if ((fActivityTicklePowerState == kInvalidTicklePowerState)
3116*0f4c859eSApple OSS Distributions || StateOrder(fActivityTicklePowerState) < StateOrder(stateNumber)) {
3117*0f4c859eSApple OSS Distributions fActivityTicklePowerState = stateNumber;
3118*0f4c859eSApple OSS Distributions noPowerChange = false;
3119*0f4c859eSApple OSS Distributions
3120*0f4c859eSApple OSS Distributions tickleFlags = kTickleTypeActivity | kTickleTypePowerRise;
3121*0f4c859eSApple OSS Distributions request = acquirePMRequest( this, kIOPMRequestTypeActivityTickle );
3122*0f4c859eSApple OSS Distributions if (request) {
3123*0f4c859eSApple OSS Distributions request->fArg0 = (void *) stateNumber;
3124*0f4c859eSApple OSS Distributions request->fArg1 = (void *)(uintptr_t) tickleFlags;
3125*0f4c859eSApple OSS Distributions request->fArg2 = (void *)(uintptr_t) gIOPMTickleGeneration;
3126*0f4c859eSApple OSS Distributions submitPMRequest(request);
3127*0f4c859eSApple OSS Distributions }
3128*0f4c859eSApple OSS Distributions }
3129*0f4c859eSApple OSS Distributions
3130*0f4c859eSApple OSS Distributions IOLockUnlock(fActivityLock);
3131*0f4c859eSApple OSS Distributions } else if ((type == kIOPMActivityTickleTypeAdvisory) &&
3132*0f4c859eSApple OSS Distributions ((stateNumber = fDeviceUsablePowerState) != kPowerStateZero)) {
3133*0f4c859eSApple OSS Distributions IOLockLock(fActivityLock);
3134*0f4c859eSApple OSS Distributions
3135*0f4c859eSApple OSS Distributions fAdvisoryTickled = true;
3136*0f4c859eSApple OSS Distributions
3137*0f4c859eSApple OSS Distributions if (fAdvisoryTicklePowerState != stateNumber) {
3138*0f4c859eSApple OSS Distributions fAdvisoryTicklePowerState = stateNumber;
3139*0f4c859eSApple OSS Distributions noPowerChange = false;
3140*0f4c859eSApple OSS Distributions
3141*0f4c859eSApple OSS Distributions tickleFlags = kTickleTypeAdvisory | kTickleTypePowerRise;
3142*0f4c859eSApple OSS Distributions request = acquirePMRequest( this, kIOPMRequestTypeActivityTickle );
3143*0f4c859eSApple OSS Distributions if (request) {
3144*0f4c859eSApple OSS Distributions request->fArg0 = (void *) stateNumber;
3145*0f4c859eSApple OSS Distributions request->fArg1 = (void *)(uintptr_t) tickleFlags;
3146*0f4c859eSApple OSS Distributions request->fArg2 = (void *)(uintptr_t) gIOPMTickleGeneration;
3147*0f4c859eSApple OSS Distributions submitPMRequest(request);
3148*0f4c859eSApple OSS Distributions }
3149*0f4c859eSApple OSS Distributions }
3150*0f4c859eSApple OSS Distributions
3151*0f4c859eSApple OSS Distributions IOLockUnlock(fActivityLock);
3152*0f4c859eSApple OSS Distributions }
3153*0f4c859eSApple OSS Distributions
3154*0f4c859eSApple OSS Distributions // Returns false if the activityTickle might cause a transition to a
3155*0f4c859eSApple OSS Distributions // higher powered state, true otherwise.
3156*0f4c859eSApple OSS Distributions
3157*0f4c859eSApple OSS Distributions return noPowerChange;
3158*0f4c859eSApple OSS Distributions }
3159*0f4c859eSApple OSS Distributions
3160*0f4c859eSApple OSS Distributions //*********************************************************************************
3161*0f4c859eSApple OSS Distributions // [private] handleActivityTickle
3162*0f4c859eSApple OSS Distributions //*********************************************************************************
3163*0f4c859eSApple OSS Distributions
3164*0f4c859eSApple OSS Distributions void
handleActivityTickle(IOPMRequest * request)3165*0f4c859eSApple OSS Distributions IOService::handleActivityTickle( IOPMRequest * request )
3166*0f4c859eSApple OSS Distributions {
3167*0f4c859eSApple OSS Distributions IOPMPowerStateIndex ticklePowerState = (IOPMPowerStateIndex) request->fArg0;
3168*0f4c859eSApple OSS Distributions IOPMPowerStateIndex tickleFlags = (IOPMPowerStateIndex) request->fArg1;
3169*0f4c859eSApple OSS Distributions uint32_t tickleGeneration = (uint32_t)(uintptr_t) request->fArg2;
3170*0f4c859eSApple OSS Distributions bool adjustPower = false;
3171*0f4c859eSApple OSS Distributions
3172*0f4c859eSApple OSS Distributions PM_ASSERT_IN_GATE();
3173*0f4c859eSApple OSS Distributions if (fResetPowerStateOnWake && (tickleGeneration != gIOPMTickleGeneration)) {
3174*0f4c859eSApple OSS Distributions // Drivers that don't want power restored on wake will drop any
3175*0f4c859eSApple OSS Distributions // tickles that pre-dates the current system wake. The model is
3176*0f4c859eSApple OSS Distributions // that each wake is a fresh start, with power state depressed
3177*0f4c859eSApple OSS Distributions // until a new tickle or an explicit power up request from the
3178*0f4c859eSApple OSS Distributions // driver. It is possible for the PM work loop to enter the
3179*0f4c859eSApple OSS Distributions // system sleep path with tickle requests queued.
3180*0f4c859eSApple OSS Distributions
3181*0f4c859eSApple OSS Distributions return;
3182*0f4c859eSApple OSS Distributions }
3183*0f4c859eSApple OSS Distributions
3184*0f4c859eSApple OSS Distributions if (tickleFlags & kTickleTypeActivity) {
3185*0f4c859eSApple OSS Distributions IOPMPowerStateIndex deviceDesireOrder = StateOrder(fDeviceDesire);
3186*0f4c859eSApple OSS Distributions IOPMPowerStateIndex idleTimerGeneration = ticklePowerState; // kTickleTypePowerDrop
3187*0f4c859eSApple OSS Distributions
3188*0f4c859eSApple OSS Distributions if (tickleFlags & kTickleTypePowerRise) {
3189*0f4c859eSApple OSS Distributions if ((StateOrder(ticklePowerState) > deviceDesireOrder) &&
3190*0f4c859eSApple OSS Distributions (ticklePowerState < fNumberOfPowerStates)) {
3191*0f4c859eSApple OSS Distributions fIdleTimerMinPowerState = ticklePowerState;
3192*0f4c859eSApple OSS Distributions updatePowerClient(gIOPMPowerClientDevice, ticklePowerState);
3193*0f4c859eSApple OSS Distributions adjustPower = true;
3194*0f4c859eSApple OSS Distributions }
3195*0f4c859eSApple OSS Distributions } else if ((deviceDesireOrder > StateOrder(fIdleTimerMinPowerState)) &&
3196*0f4c859eSApple OSS Distributions (idleTimerGeneration == fIdleTimerGeneration)) {
3197*0f4c859eSApple OSS Distributions // Power drop due to idle timer expiration.
3198*0f4c859eSApple OSS Distributions // Do not allow idle timer to reduce power below tickle power.
3199*0f4c859eSApple OSS Distributions // This prevents the idle timer from decreasing the device desire
3200*0f4c859eSApple OSS Distributions // to zero and cancelling the effect of a pre-sleep tickle when
3201*0f4c859eSApple OSS Distributions // system wakes up to doze state, while the device is unable to
3202*0f4c859eSApple OSS Distributions // raise its power state to satisfy the tickle.
3203*0f4c859eSApple OSS Distributions
3204*0f4c859eSApple OSS Distributions deviceDesireOrder--;
3205*0f4c859eSApple OSS Distributions if (deviceDesireOrder < fNumberOfPowerStates) {
3206*0f4c859eSApple OSS Distributions ticklePowerState = fPowerStates[deviceDesireOrder].stateOrderToIndex;
3207*0f4c859eSApple OSS Distributions updatePowerClient(gIOPMPowerClientDevice, ticklePowerState);
3208*0f4c859eSApple OSS Distributions adjustPower = true;
3209*0f4c859eSApple OSS Distributions }
3210*0f4c859eSApple OSS Distributions }
3211*0f4c859eSApple OSS Distributions } else { // advisory tickle
3212*0f4c859eSApple OSS Distributions if (tickleFlags & kTickleTypePowerRise) {
3213*0f4c859eSApple OSS Distributions if ((ticklePowerState == fDeviceUsablePowerState) &&
3214*0f4c859eSApple OSS Distributions (ticklePowerState < fNumberOfPowerStates)) {
3215*0f4c859eSApple OSS Distributions updatePowerClient(gIOPMPowerClientAdvisoryTickle, ticklePowerState);
3216*0f4c859eSApple OSS Distributions fHasAdvisoryDesire = true;
3217*0f4c859eSApple OSS Distributions fAdvisoryTickleUsed = true;
3218*0f4c859eSApple OSS Distributions adjustPower = true;
3219*0f4c859eSApple OSS Distributions } else {
3220*0f4c859eSApple OSS Distributions IOLockLock(fActivityLock);
3221*0f4c859eSApple OSS Distributions fAdvisoryTicklePowerState = kInvalidTicklePowerState;
3222*0f4c859eSApple OSS Distributions IOLockUnlock(fActivityLock);
3223*0f4c859eSApple OSS Distributions }
3224*0f4c859eSApple OSS Distributions } else if (fHasAdvisoryDesire) {
3225*0f4c859eSApple OSS Distributions removePowerClient(gIOPMPowerClientAdvisoryTickle);
3226*0f4c859eSApple OSS Distributions fHasAdvisoryDesire = false;
3227*0f4c859eSApple OSS Distributions adjustPower = true;
3228*0f4c859eSApple OSS Distributions }
3229*0f4c859eSApple OSS Distributions }
3230*0f4c859eSApple OSS Distributions
3231*0f4c859eSApple OSS Distributions if (adjustPower) {
3232*0f4c859eSApple OSS Distributions adjustPowerState();
3233*0f4c859eSApple OSS Distributions }
3234*0f4c859eSApple OSS Distributions }
3235*0f4c859eSApple OSS Distributions
3236*0f4c859eSApple OSS Distributions //******************************************************************************
3237*0f4c859eSApple OSS Distributions // [public] setIdleTimerPeriod
3238*0f4c859eSApple OSS Distributions //
3239*0f4c859eSApple OSS Distributions // A subclass policy-maker is using our standard idleness detection service.
3240*0f4c859eSApple OSS Distributions // Start the idle timer. Period is in seconds.
3241*0f4c859eSApple OSS Distributions //******************************************************************************
3242*0f4c859eSApple OSS Distributions
3243*0f4c859eSApple OSS Distributions IOReturn
setIdleTimerPeriod(unsigned long period)3244*0f4c859eSApple OSS Distributions IOService::setIdleTimerPeriod( unsigned long period )
3245*0f4c859eSApple OSS Distributions {
3246*0f4c859eSApple OSS Distributions if (!initialized) {
3247*0f4c859eSApple OSS Distributions return IOPMNotYetInitialized;
3248*0f4c859eSApple OSS Distributions }
3249*0f4c859eSApple OSS Distributions
3250*0f4c859eSApple OSS Distributions OUR_PMLog(kPMLogSetIdleTimerPeriod, period, fIdleTimerPeriod);
3251*0f4c859eSApple OSS Distributions
3252*0f4c859eSApple OSS Distributions if (period > INT_MAX) {
3253*0f4c859eSApple OSS Distributions return kIOReturnBadArgument;
3254*0f4c859eSApple OSS Distributions }
3255*0f4c859eSApple OSS Distributions
3256*0f4c859eSApple OSS Distributions IOPMRequest * request =
3257*0f4c859eSApple OSS Distributions acquirePMRequest( this, kIOPMRequestTypeSetIdleTimerPeriod );
3258*0f4c859eSApple OSS Distributions if (!request) {
3259*0f4c859eSApple OSS Distributions return kIOReturnNoMemory;
3260*0f4c859eSApple OSS Distributions }
3261*0f4c859eSApple OSS Distributions
3262*0f4c859eSApple OSS Distributions request->fArg0 = (void *) period;
3263*0f4c859eSApple OSS Distributions submitPMRequest( request );
3264*0f4c859eSApple OSS Distributions
3265*0f4c859eSApple OSS Distributions return kIOReturnSuccess;
3266*0f4c859eSApple OSS Distributions }
3267*0f4c859eSApple OSS Distributions
3268*0f4c859eSApple OSS Distributions IOReturn
setIgnoreIdleTimer(bool ignore)3269*0f4c859eSApple OSS Distributions IOService::setIgnoreIdleTimer( bool ignore )
3270*0f4c859eSApple OSS Distributions {
3271*0f4c859eSApple OSS Distributions if (!initialized) {
3272*0f4c859eSApple OSS Distributions return IOPMNotYetInitialized;
3273*0f4c859eSApple OSS Distributions }
3274*0f4c859eSApple OSS Distributions
3275*0f4c859eSApple OSS Distributions OUR_PMLog(kIOPMRequestTypeIgnoreIdleTimer, ignore, 0);
3276*0f4c859eSApple OSS Distributions
3277*0f4c859eSApple OSS Distributions IOPMRequest * request =
3278*0f4c859eSApple OSS Distributions acquirePMRequest( this, kIOPMRequestTypeIgnoreIdleTimer );
3279*0f4c859eSApple OSS Distributions if (!request) {
3280*0f4c859eSApple OSS Distributions return kIOReturnNoMemory;
3281*0f4c859eSApple OSS Distributions }
3282*0f4c859eSApple OSS Distributions
3283*0f4c859eSApple OSS Distributions request->fArg0 = (void *) ignore;
3284*0f4c859eSApple OSS Distributions submitPMRequest( request );
3285*0f4c859eSApple OSS Distributions
3286*0f4c859eSApple OSS Distributions return kIOReturnSuccess;
3287*0f4c859eSApple OSS Distributions }
3288*0f4c859eSApple OSS Distributions
3289*0f4c859eSApple OSS Distributions //******************************************************************************
3290*0f4c859eSApple OSS Distributions // [public] nextIdleTimeout
3291*0f4c859eSApple OSS Distributions //
3292*0f4c859eSApple OSS Distributions // Returns how many "seconds from now" the device should idle into its
3293*0f4c859eSApple OSS Distributions // next lowest power state.
3294*0f4c859eSApple OSS Distributions //******************************************************************************
3295*0f4c859eSApple OSS Distributions
3296*0f4c859eSApple OSS Distributions SInt32
nextIdleTimeout(AbsoluteTime currentTime,AbsoluteTime lastActivity,unsigned int powerState)3297*0f4c859eSApple OSS Distributions IOService::nextIdleTimeout(
3298*0f4c859eSApple OSS Distributions AbsoluteTime currentTime,
3299*0f4c859eSApple OSS Distributions AbsoluteTime lastActivity,
3300*0f4c859eSApple OSS Distributions unsigned int powerState)
3301*0f4c859eSApple OSS Distributions {
3302*0f4c859eSApple OSS Distributions AbsoluteTime delta;
3303*0f4c859eSApple OSS Distributions UInt64 delta_ns;
3304*0f4c859eSApple OSS Distributions SInt32 delta_secs;
3305*0f4c859eSApple OSS Distributions SInt32 delay_secs;
3306*0f4c859eSApple OSS Distributions
3307*0f4c859eSApple OSS Distributions // Calculate time difference using funky macro from clock.h.
3308*0f4c859eSApple OSS Distributions delta = currentTime;
3309*0f4c859eSApple OSS Distributions SUB_ABSOLUTETIME(&delta, &lastActivity);
3310*0f4c859eSApple OSS Distributions
3311*0f4c859eSApple OSS Distributions // Figure it in seconds.
3312*0f4c859eSApple OSS Distributions absolutetime_to_nanoseconds(delta, &delta_ns);
3313*0f4c859eSApple OSS Distributions delta_secs = (SInt32)(delta_ns / NSEC_PER_SEC);
3314*0f4c859eSApple OSS Distributions
3315*0f4c859eSApple OSS Distributions // Be paranoid about delta somehow exceeding timer period.
3316*0f4c859eSApple OSS Distributions if (delta_secs < (int) fIdleTimerPeriod) {
3317*0f4c859eSApple OSS Distributions delay_secs = (int) fIdleTimerPeriod - delta_secs;
3318*0f4c859eSApple OSS Distributions } else {
3319*0f4c859eSApple OSS Distributions delay_secs = (int) fIdleTimerPeriod;
3320*0f4c859eSApple OSS Distributions }
3321*0f4c859eSApple OSS Distributions
3322*0f4c859eSApple OSS Distributions return (SInt32)delay_secs;
3323*0f4c859eSApple OSS Distributions }
3324*0f4c859eSApple OSS Distributions
3325*0f4c859eSApple OSS Distributions //*********************************************************************************
3326*0f4c859eSApple OSS Distributions // [public] start_PM_idle_timer
3327*0f4c859eSApple OSS Distributions //*********************************************************************************
3328*0f4c859eSApple OSS Distributions
3329*0f4c859eSApple OSS Distributions void
start_PM_idle_timer(void)3330*0f4c859eSApple OSS Distributions IOService::start_PM_idle_timer( void )
3331*0f4c859eSApple OSS Distributions {
3332*0f4c859eSApple OSS Distributions static const int maxTimeout = 100000;
3333*0f4c859eSApple OSS Distributions static const int minTimeout = 1;
3334*0f4c859eSApple OSS Distributions AbsoluteTime uptime, deadline;
3335*0f4c859eSApple OSS Distributions SInt32 idle_in = 0;
3336*0f4c859eSApple OSS Distributions boolean_t pending;
3337*0f4c859eSApple OSS Distributions
3338*0f4c859eSApple OSS Distributions if (!initialized || !fIdleTimerPeriod ||
3339*0f4c859eSApple OSS Distributions ((unsigned int) fCurrentPowerState != fCurrentPowerState)) {
3340*0f4c859eSApple OSS Distributions return;
3341*0f4c859eSApple OSS Distributions }
3342*0f4c859eSApple OSS Distributions
3343*0f4c859eSApple OSS Distributions IOLockLock(fActivityLock);
3344*0f4c859eSApple OSS Distributions
3345*0f4c859eSApple OSS Distributions clock_get_uptime(&uptime);
3346*0f4c859eSApple OSS Distributions
3347*0f4c859eSApple OSS Distributions // Subclasses may modify idle sleep algorithm
3348*0f4c859eSApple OSS Distributions idle_in = nextIdleTimeout(uptime, fDeviceActiveTimestamp, (unsigned int) fCurrentPowerState);
3349*0f4c859eSApple OSS Distributions
3350*0f4c859eSApple OSS Distributions // Check for out-of range responses
3351*0f4c859eSApple OSS Distributions if (idle_in > maxTimeout) {
3352*0f4c859eSApple OSS Distributions // use standard implementation
3353*0f4c859eSApple OSS Distributions idle_in = IOService::nextIdleTimeout(uptime,
3354*0f4c859eSApple OSS Distributions fDeviceActiveTimestamp,
3355*0f4c859eSApple OSS Distributions (unsigned int) fCurrentPowerState);
3356*0f4c859eSApple OSS Distributions } else if (idle_in < minTimeout) {
3357*0f4c859eSApple OSS Distributions idle_in = fIdleTimerPeriod;
3358*0f4c859eSApple OSS Distributions }
3359*0f4c859eSApple OSS Distributions
3360*0f4c859eSApple OSS Distributions IOLockUnlock(fActivityLock);
3361*0f4c859eSApple OSS Distributions
3362*0f4c859eSApple OSS Distributions fNextIdleTimerPeriod = idle_in;
3363*0f4c859eSApple OSS Distributions fIdleTimerStartTime = uptime;
3364*0f4c859eSApple OSS Distributions
3365*0f4c859eSApple OSS Distributions retain();
3366*0f4c859eSApple OSS Distributions clock_interval_to_absolutetime_interval(idle_in, kSecondScale, &deadline);
3367*0f4c859eSApple OSS Distributions ADD_ABSOLUTETIME(&deadline, &uptime);
3368*0f4c859eSApple OSS Distributions pending = thread_call_enter_delayed(fIdleTimer, deadline);
3369*0f4c859eSApple OSS Distributions if (pending) {
3370*0f4c859eSApple OSS Distributions release();
3371*0f4c859eSApple OSS Distributions }
3372*0f4c859eSApple OSS Distributions }
3373*0f4c859eSApple OSS Distributions
3374*0f4c859eSApple OSS Distributions //*********************************************************************************
3375*0f4c859eSApple OSS Distributions // [private] restartIdleTimer
3376*0f4c859eSApple OSS Distributions //*********************************************************************************
3377*0f4c859eSApple OSS Distributions
3378*0f4c859eSApple OSS Distributions void
restartIdleTimer(void)3379*0f4c859eSApple OSS Distributions IOService::restartIdleTimer( void )
3380*0f4c859eSApple OSS Distributions {
3381*0f4c859eSApple OSS Distributions if (fDeviceDesire != kPowerStateZero) {
3382*0f4c859eSApple OSS Distributions fIdleTimerStopped = false;
3383*0f4c859eSApple OSS Distributions fActivityTickleCount = 0;
3384*0f4c859eSApple OSS Distributions start_PM_idle_timer();
3385*0f4c859eSApple OSS Distributions } else if (fHasAdvisoryDesire) {
3386*0f4c859eSApple OSS Distributions fIdleTimerStopped = false;
3387*0f4c859eSApple OSS Distributions start_PM_idle_timer();
3388*0f4c859eSApple OSS Distributions } else {
3389*0f4c859eSApple OSS Distributions fIdleTimerStopped = true;
3390*0f4c859eSApple OSS Distributions }
3391*0f4c859eSApple OSS Distributions }
3392*0f4c859eSApple OSS Distributions
3393*0f4c859eSApple OSS Distributions //*********************************************************************************
3394*0f4c859eSApple OSS Distributions // idle_timer_expired
3395*0f4c859eSApple OSS Distributions //*********************************************************************************
3396*0f4c859eSApple OSS Distributions
3397*0f4c859eSApple OSS Distributions static void
idle_timer_expired(thread_call_param_t arg0,thread_call_param_t arg1)3398*0f4c859eSApple OSS Distributions idle_timer_expired(
3399*0f4c859eSApple OSS Distributions thread_call_param_t arg0, thread_call_param_t arg1 )
3400*0f4c859eSApple OSS Distributions {
3401*0f4c859eSApple OSS Distributions IOService * me = (IOService *) arg0;
3402*0f4c859eSApple OSS Distributions
3403*0f4c859eSApple OSS Distributions if (gIOPMWorkLoop) {
3404*0f4c859eSApple OSS Distributions gIOPMWorkLoop->runAction(
3405*0f4c859eSApple OSS Distributions OSMemberFunctionCast(IOWorkLoop::Action, me,
3406*0f4c859eSApple OSS Distributions &IOService::idleTimerExpired),
3407*0f4c859eSApple OSS Distributions me);
3408*0f4c859eSApple OSS Distributions }
3409*0f4c859eSApple OSS Distributions
3410*0f4c859eSApple OSS Distributions me->release();
3411*0f4c859eSApple OSS Distributions }
3412*0f4c859eSApple OSS Distributions
3413*0f4c859eSApple OSS Distributions //*********************************************************************************
3414*0f4c859eSApple OSS Distributions // [private] idleTimerExpired
3415*0f4c859eSApple OSS Distributions //
3416*0f4c859eSApple OSS Distributions // The idle timer has expired. If there has been activity since the last
3417*0f4c859eSApple OSS Distributions // expiration, just restart the timer and return. If there has not been
3418*0f4c859eSApple OSS Distributions // activity, switch to the next lower power state and restart the timer.
3419*0f4c859eSApple OSS Distributions //*********************************************************************************
3420*0f4c859eSApple OSS Distributions
3421*0f4c859eSApple OSS Distributions void
idleTimerExpired(void)3422*0f4c859eSApple OSS Distributions IOService::idleTimerExpired( void )
3423*0f4c859eSApple OSS Distributions {
3424*0f4c859eSApple OSS Distributions IOPMRequest * request;
3425*0f4c859eSApple OSS Distributions bool restartTimer = true;
3426*0f4c859eSApple OSS Distributions uint32_t tickleFlags;
3427*0f4c859eSApple OSS Distributions
3428*0f4c859eSApple OSS Distributions if (!initialized || !fIdleTimerPeriod || fIdleTimerStopped ||
3429*0f4c859eSApple OSS Distributions fLockedFlags.PMStop) {
3430*0f4c859eSApple OSS Distributions return;
3431*0f4c859eSApple OSS Distributions }
3432*0f4c859eSApple OSS Distributions
3433*0f4c859eSApple OSS Distributions fIdleTimerStartTime = 0;
3434*0f4c859eSApple OSS Distributions
3435*0f4c859eSApple OSS Distributions IOLockLock(fActivityLock);
3436*0f4c859eSApple OSS Distributions
3437*0f4c859eSApple OSS Distributions // Check for device activity (tickles) over last timer period.
3438*0f4c859eSApple OSS Distributions
3439*0f4c859eSApple OSS Distributions if (fDeviceWasActive) {
3440*0f4c859eSApple OSS Distributions // Device was active - do not drop power, restart timer.
3441*0f4c859eSApple OSS Distributions fDeviceWasActive = false;
3442*0f4c859eSApple OSS Distributions } else if (!fIdleTimerIgnored) {
3443*0f4c859eSApple OSS Distributions // No device activity - drop power state by one level.
3444*0f4c859eSApple OSS Distributions // Decrement the cached tickle power state when possible.
3445*0f4c859eSApple OSS Distributions // This value may be kInvalidTicklePowerState before activityTickle()
3446*0f4c859eSApple OSS Distributions // is called, but the power drop request must be issued regardless.
3447*0f4c859eSApple OSS Distributions
3448*0f4c859eSApple OSS Distributions if ((fActivityTicklePowerState != kInvalidTicklePowerState) &&
3449*0f4c859eSApple OSS Distributions (fActivityTicklePowerState != kPowerStateZero)) {
3450*0f4c859eSApple OSS Distributions fActivityTicklePowerState--;
3451*0f4c859eSApple OSS Distributions }
3452*0f4c859eSApple OSS Distributions
3453*0f4c859eSApple OSS Distributions tickleFlags = kTickleTypeActivity | kTickleTypePowerDrop;
3454*0f4c859eSApple OSS Distributions request = acquirePMRequest( this, kIOPMRequestTypeActivityTickle );
3455*0f4c859eSApple OSS Distributions if (request) {
3456*0f4c859eSApple OSS Distributions request->fArg0 = (void *)(uintptr_t) fIdleTimerGeneration;
3457*0f4c859eSApple OSS Distributions request->fArg1 = (void *)(uintptr_t) tickleFlags;
3458*0f4c859eSApple OSS Distributions request->fArg2 = (void *)(uintptr_t) gIOPMTickleGeneration;
3459*0f4c859eSApple OSS Distributions submitPMRequest( request );
3460*0f4c859eSApple OSS Distributions
3461*0f4c859eSApple OSS Distributions // Do not restart timer until after the tickle request has been
3462*0f4c859eSApple OSS Distributions // processed.
3463*0f4c859eSApple OSS Distributions
3464*0f4c859eSApple OSS Distributions restartTimer = false;
3465*0f4c859eSApple OSS Distributions }
3466*0f4c859eSApple OSS Distributions }
3467*0f4c859eSApple OSS Distributions
3468*0f4c859eSApple OSS Distributions if (fAdvisoryTickled) {
3469*0f4c859eSApple OSS Distributions fAdvisoryTickled = false;
3470*0f4c859eSApple OSS Distributions } else if (fHasAdvisoryDesire) {
3471*0f4c859eSApple OSS Distributions // Want new tickles to turn into pm request after we drop the lock
3472*0f4c859eSApple OSS Distributions fAdvisoryTicklePowerState = kInvalidTicklePowerState;
3473*0f4c859eSApple OSS Distributions
3474*0f4c859eSApple OSS Distributions tickleFlags = kTickleTypeAdvisory | kTickleTypePowerDrop;
3475*0f4c859eSApple OSS Distributions request = acquirePMRequest( this, kIOPMRequestTypeActivityTickle );
3476*0f4c859eSApple OSS Distributions if (request) {
3477*0f4c859eSApple OSS Distributions request->fArg0 = (void *)(uintptr_t) fIdleTimerGeneration;
3478*0f4c859eSApple OSS Distributions request->fArg1 = (void *)(uintptr_t) tickleFlags;
3479*0f4c859eSApple OSS Distributions request->fArg2 = (void *)(uintptr_t) gIOPMTickleGeneration;
3480*0f4c859eSApple OSS Distributions submitPMRequest( request );
3481*0f4c859eSApple OSS Distributions
3482*0f4c859eSApple OSS Distributions // Do not restart timer until after the tickle request has been
3483*0f4c859eSApple OSS Distributions // processed.
3484*0f4c859eSApple OSS Distributions
3485*0f4c859eSApple OSS Distributions restartTimer = false;
3486*0f4c859eSApple OSS Distributions }
3487*0f4c859eSApple OSS Distributions }
3488*0f4c859eSApple OSS Distributions
3489*0f4c859eSApple OSS Distributions IOLockUnlock(fActivityLock);
3490*0f4c859eSApple OSS Distributions
3491*0f4c859eSApple OSS Distributions if (restartTimer) {
3492*0f4c859eSApple OSS Distributions start_PM_idle_timer();
3493*0f4c859eSApple OSS Distributions }
3494*0f4c859eSApple OSS Distributions }
3495*0f4c859eSApple OSS Distributions
3496*0f4c859eSApple OSS Distributions #ifndef __LP64__
3497*0f4c859eSApple OSS Distributions //*********************************************************************************
3498*0f4c859eSApple OSS Distributions // [deprecated] PM_idle_timer_expiration
3499*0f4c859eSApple OSS Distributions //*********************************************************************************
3500*0f4c859eSApple OSS Distributions
3501*0f4c859eSApple OSS Distributions void
PM_idle_timer_expiration(void)3502*0f4c859eSApple OSS Distributions IOService::PM_idle_timer_expiration( void )
3503*0f4c859eSApple OSS Distributions {
3504*0f4c859eSApple OSS Distributions }
3505*0f4c859eSApple OSS Distributions
3506*0f4c859eSApple OSS Distributions //*********************************************************************************
3507*0f4c859eSApple OSS Distributions // [deprecated] command_received
3508*0f4c859eSApple OSS Distributions //*********************************************************************************
3509*0f4c859eSApple OSS Distributions
3510*0f4c859eSApple OSS Distributions void
command_received(void * statePtr,void *,void *,void *)3511*0f4c859eSApple OSS Distributions IOService::command_received( void *statePtr, void *, void *, void * )
3512*0f4c859eSApple OSS Distributions {
3513*0f4c859eSApple OSS Distributions }
3514*0f4c859eSApple OSS Distributions #endif /* !__LP64__ */
3515*0f4c859eSApple OSS Distributions
3516*0f4c859eSApple OSS Distributions //*********************************************************************************
3517*0f4c859eSApple OSS Distributions // [public] setAggressiveness
3518*0f4c859eSApple OSS Distributions //
3519*0f4c859eSApple OSS Distributions // Pass on the input parameters to all power domain children. All those which are
3520*0f4c859eSApple OSS Distributions // power domains will pass it on to their children, etc.
3521*0f4c859eSApple OSS Distributions //*********************************************************************************
3522*0f4c859eSApple OSS Distributions
3523*0f4c859eSApple OSS Distributions IOReturn
setAggressiveness(unsigned long type,unsigned long newLevel)3524*0f4c859eSApple OSS Distributions IOService::setAggressiveness( unsigned long type, unsigned long newLevel )
3525*0f4c859eSApple OSS Distributions {
3526*0f4c859eSApple OSS Distributions return kIOReturnSuccess;
3527*0f4c859eSApple OSS Distributions }
3528*0f4c859eSApple OSS Distributions
3529*0f4c859eSApple OSS Distributions //*********************************************************************************
3530*0f4c859eSApple OSS Distributions // [public] getAggressiveness
3531*0f4c859eSApple OSS Distributions //
3532*0f4c859eSApple OSS Distributions // Called by the user client.
3533*0f4c859eSApple OSS Distributions //*********************************************************************************
3534*0f4c859eSApple OSS Distributions
3535*0f4c859eSApple OSS Distributions IOReturn
getAggressiveness(unsigned long type,unsigned long * currentLevel)3536*0f4c859eSApple OSS Distributions IOService::getAggressiveness( unsigned long type, unsigned long * currentLevel )
3537*0f4c859eSApple OSS Distributions {
3538*0f4c859eSApple OSS Distributions IOPMrootDomain * rootDomain = getPMRootDomain();
3539*0f4c859eSApple OSS Distributions
3540*0f4c859eSApple OSS Distributions if (!rootDomain) {
3541*0f4c859eSApple OSS Distributions return kIOReturnNotReady;
3542*0f4c859eSApple OSS Distributions }
3543*0f4c859eSApple OSS Distributions
3544*0f4c859eSApple OSS Distributions return rootDomain->getAggressiveness( type, currentLevel );
3545*0f4c859eSApple OSS Distributions }
3546*0f4c859eSApple OSS Distributions
3547*0f4c859eSApple OSS Distributions //*********************************************************************************
3548*0f4c859eSApple OSS Distributions // [public] getPowerState
3549*0f4c859eSApple OSS Distributions //
3550*0f4c859eSApple OSS Distributions //*********************************************************************************
3551*0f4c859eSApple OSS Distributions
3552*0f4c859eSApple OSS Distributions UInt32
getPowerState(void)3553*0f4c859eSApple OSS Distributions IOService::getPowerState( void )
3554*0f4c859eSApple OSS Distributions {
3555*0f4c859eSApple OSS Distributions if (!initialized) {
3556*0f4c859eSApple OSS Distributions return kPowerStateZero;
3557*0f4c859eSApple OSS Distributions }
3558*0f4c859eSApple OSS Distributions
3559*0f4c859eSApple OSS Distributions return (UInt32) fCurrentPowerState;
3560*0f4c859eSApple OSS Distributions }
3561*0f4c859eSApple OSS Distributions
3562*0f4c859eSApple OSS Distributions #ifndef __LP64__
3563*0f4c859eSApple OSS Distributions //*********************************************************************************
3564*0f4c859eSApple OSS Distributions // [deprecated] systemWake
3565*0f4c859eSApple OSS Distributions //
3566*0f4c859eSApple OSS Distributions // Pass this to all power domain children. All those which are
3567*0f4c859eSApple OSS Distributions // power domains will pass it on to their children, etc.
3568*0f4c859eSApple OSS Distributions //*********************************************************************************
3569*0f4c859eSApple OSS Distributions
3570*0f4c859eSApple OSS Distributions IOReturn
systemWake(void)3571*0f4c859eSApple OSS Distributions IOService::systemWake( void )
3572*0f4c859eSApple OSS Distributions {
3573*0f4c859eSApple OSS Distributions OSIterator * iter;
3574*0f4c859eSApple OSS Distributions OSObject * next;
3575*0f4c859eSApple OSS Distributions IOPowerConnection * connection;
3576*0f4c859eSApple OSS Distributions IOService * theChild;
3577*0f4c859eSApple OSS Distributions
3578*0f4c859eSApple OSS Distributions iter = getChildIterator(gIOPowerPlane);
3579*0f4c859eSApple OSS Distributions if (iter) {
3580*0f4c859eSApple OSS Distributions while ((next = iter->getNextObject())) {
3581*0f4c859eSApple OSS Distributions if ((connection = OSDynamicCast(IOPowerConnection, next))) {
3582*0f4c859eSApple OSS Distributions if (connection->getReadyFlag() == false) {
3583*0f4c859eSApple OSS Distributions PM_LOG3("[%s] %s: connection not ready\n",
3584*0f4c859eSApple OSS Distributions getName(), __FUNCTION__);
3585*0f4c859eSApple OSS Distributions continue;
3586*0f4c859eSApple OSS Distributions }
3587*0f4c859eSApple OSS Distributions
3588*0f4c859eSApple OSS Distributions theChild = (IOService *)connection->copyChildEntry(gIOPowerPlane);
3589*0f4c859eSApple OSS Distributions if (theChild) {
3590*0f4c859eSApple OSS Distributions theChild->systemWake();
3591*0f4c859eSApple OSS Distributions theChild->release();
3592*0f4c859eSApple OSS Distributions }
3593*0f4c859eSApple OSS Distributions }
3594*0f4c859eSApple OSS Distributions }
3595*0f4c859eSApple OSS Distributions iter->release();
3596*0f4c859eSApple OSS Distributions }
3597*0f4c859eSApple OSS Distributions
3598*0f4c859eSApple OSS Distributions if (fControllingDriver != NULL) {
3599*0f4c859eSApple OSS Distributions if (fControllingDriver->didYouWakeSystem()) {
3600*0f4c859eSApple OSS Distributions makeUsable();
3601*0f4c859eSApple OSS Distributions }
3602*0f4c859eSApple OSS Distributions }
3603*0f4c859eSApple OSS Distributions
3604*0f4c859eSApple OSS Distributions return IOPMNoErr;
3605*0f4c859eSApple OSS Distributions }
3606*0f4c859eSApple OSS Distributions
3607*0f4c859eSApple OSS Distributions //*********************************************************************************
3608*0f4c859eSApple OSS Distributions // [deprecated] temperatureCriticalForZone
3609*0f4c859eSApple OSS Distributions //*********************************************************************************
3610*0f4c859eSApple OSS Distributions
3611*0f4c859eSApple OSS Distributions IOReturn
temperatureCriticalForZone(IOService * whichZone)3612*0f4c859eSApple OSS Distributions IOService::temperatureCriticalForZone( IOService * whichZone )
3613*0f4c859eSApple OSS Distributions {
3614*0f4c859eSApple OSS Distributions IOService * theParent;
3615*0f4c859eSApple OSS Distributions IOService * theNub;
3616*0f4c859eSApple OSS Distributions
3617*0f4c859eSApple OSS Distributions OUR_PMLog(kPMLogCriticalTemp, 0, 0);
3618*0f4c859eSApple OSS Distributions
3619*0f4c859eSApple OSS Distributions if (inPlane(gIOPowerPlane) && !IS_PM_ROOT) {
3620*0f4c859eSApple OSS Distributions theNub = (IOService *)copyParentEntry(gIOPowerPlane);
3621*0f4c859eSApple OSS Distributions if (theNub) {
3622*0f4c859eSApple OSS Distributions theParent = (IOService *)theNub->copyParentEntry(gIOPowerPlane);
3623*0f4c859eSApple OSS Distributions theNub->release();
3624*0f4c859eSApple OSS Distributions if (theParent) {
3625*0f4c859eSApple OSS Distributions theParent->temperatureCriticalForZone(whichZone);
3626*0f4c859eSApple OSS Distributions theParent->release();
3627*0f4c859eSApple OSS Distributions }
3628*0f4c859eSApple OSS Distributions }
3629*0f4c859eSApple OSS Distributions }
3630*0f4c859eSApple OSS Distributions return IOPMNoErr;
3631*0f4c859eSApple OSS Distributions }
3632*0f4c859eSApple OSS Distributions #endif /* !__LP64__ */
3633*0f4c859eSApple OSS Distributions
3634*0f4c859eSApple OSS Distributions // MARK: -
3635*0f4c859eSApple OSS Distributions // MARK: Power Change (Common)
3636*0f4c859eSApple OSS Distributions
3637*0f4c859eSApple OSS Distributions //*********************************************************************************
3638*0f4c859eSApple OSS Distributions // [private] startPowerChange
3639*0f4c859eSApple OSS Distributions //
3640*0f4c859eSApple OSS Distributions // All power state changes starts here.
3641*0f4c859eSApple OSS Distributions //*********************************************************************************
3642*0f4c859eSApple OSS Distributions
3643*0f4c859eSApple OSS Distributions IOReturn
startPowerChange(IOPMPowerChangeFlags changeFlags,IOPMPowerStateIndex powerState,IOPMPowerFlags domainFlags,IOPowerConnection * parentConnection,IOPMPowerFlags parentFlags)3644*0f4c859eSApple OSS Distributions IOService::startPowerChange(
3645*0f4c859eSApple OSS Distributions IOPMPowerChangeFlags changeFlags,
3646*0f4c859eSApple OSS Distributions IOPMPowerStateIndex powerState,
3647*0f4c859eSApple OSS Distributions IOPMPowerFlags domainFlags,
3648*0f4c859eSApple OSS Distributions IOPowerConnection * parentConnection,
3649*0f4c859eSApple OSS Distributions IOPMPowerFlags parentFlags )
3650*0f4c859eSApple OSS Distributions {
3651*0f4c859eSApple OSS Distributions uint32_t savedPMActionsState;
3652*0f4c859eSApple OSS Distributions
3653*0f4c859eSApple OSS Distributions PM_ASSERT_IN_GATE();
3654*0f4c859eSApple OSS Distributions assert( fMachineState == kIOPM_Finished );
3655*0f4c859eSApple OSS Distributions assert( powerState < fNumberOfPowerStates );
3656*0f4c859eSApple OSS Distributions
3657*0f4c859eSApple OSS Distributions if (powerState >= fNumberOfPowerStates) {
3658*0f4c859eSApple OSS Distributions return IOPMAckImplied;
3659*0f4c859eSApple OSS Distributions }
3660*0f4c859eSApple OSS Distributions
3661*0f4c859eSApple OSS Distributions fIsPreChange = true;
3662*0f4c859eSApple OSS Distributions savedPMActionsState = fPMActions.state;
3663*0f4c859eSApple OSS Distributions PM_ACTION_CHANGE(actionPowerChangeOverride, &powerState, &changeFlags);
3664*0f4c859eSApple OSS Distributions
3665*0f4c859eSApple OSS Distributions // rdar://problem/55040032
3666*0f4c859eSApple OSS Distributions // Schedule a power adjustment after removing the power clamp
3667*0f4c859eSApple OSS Distributions // to inform our power parent(s) about our latest desired domain
3668*0f4c859eSApple OSS Distributions // power state. For a self-initiated change, let OurChangeStart()
3669*0f4c859eSApple OSS Distributions // automatically request parent power when necessary.
3670*0f4c859eSApple OSS Distributions if (!fAdjustPowerScheduled &&
3671*0f4c859eSApple OSS Distributions ((changeFlags & kIOPMSelfInitiated) == 0) &&
3672*0f4c859eSApple OSS Distributions ((fPMActions.state & kPMActionsStatePowerClamped) == 0) &&
3673*0f4c859eSApple OSS Distributions ((savedPMActionsState & kPMActionsStatePowerClamped) != 0)) {
3674*0f4c859eSApple OSS Distributions IOPMRequest * request = acquirePMRequest(this, kIOPMRequestTypeAdjustPowerState);
3675*0f4c859eSApple OSS Distributions if (request) {
3676*0f4c859eSApple OSS Distributions submitPMRequest(request);
3677*0f4c859eSApple OSS Distributions fAdjustPowerScheduled = true;
3678*0f4c859eSApple OSS Distributions }
3679*0f4c859eSApple OSS Distributions }
3680*0f4c859eSApple OSS Distributions
3681*0f4c859eSApple OSS Distributions if (changeFlags & kIOPMExpireIdleTimer) {
3682*0f4c859eSApple OSS Distributions // Root domain requested removal of tickle influence
3683*0f4c859eSApple OSS Distributions if (StateOrder(fDeviceDesire) > StateOrder(powerState)) {
3684*0f4c859eSApple OSS Distributions // Reset device desire down to the clamped power state
3685*0f4c859eSApple OSS Distributions updatePowerClient(gIOPMPowerClientDevice, powerState);
3686*0f4c859eSApple OSS Distributions computeDesiredState(kPowerStateZero, true);
3687*0f4c859eSApple OSS Distributions
3688*0f4c859eSApple OSS Distributions // Invalidate tickle cache so the next tickle will issue a request
3689*0f4c859eSApple OSS Distributions IOLockLock(fActivityLock);
3690*0f4c859eSApple OSS Distributions fDeviceWasActive = false;
3691*0f4c859eSApple OSS Distributions fActivityTicklePowerState = kInvalidTicklePowerState;
3692*0f4c859eSApple OSS Distributions IOLockUnlock(fActivityLock);
3693*0f4c859eSApple OSS Distributions
3694*0f4c859eSApple OSS Distributions fIdleTimerMinPowerState = kPowerStateZero;
3695*0f4c859eSApple OSS Distributions }
3696*0f4c859eSApple OSS Distributions }
3697*0f4c859eSApple OSS Distributions
3698*0f4c859eSApple OSS Distributions // Root domain's override handler may cancel the power change by
3699*0f4c859eSApple OSS Distributions // setting the kIOPMNotDone flag.
3700*0f4c859eSApple OSS Distributions
3701*0f4c859eSApple OSS Distributions if (changeFlags & kIOPMNotDone) {
3702*0f4c859eSApple OSS Distributions return IOPMAckImplied;
3703*0f4c859eSApple OSS Distributions }
3704*0f4c859eSApple OSS Distributions
3705*0f4c859eSApple OSS Distributions // Forks to either Driver or Parent initiated power change paths.
3706*0f4c859eSApple OSS Distributions
3707*0f4c859eSApple OSS Distributions fHeadNoteChangeFlags = changeFlags;
3708*0f4c859eSApple OSS Distributions fHeadNotePowerState = powerState;
3709*0f4c859eSApple OSS Distributions fHeadNotePowerArrayEntry = &fPowerStates[powerState];
3710*0f4c859eSApple OSS Distributions fHeadNoteParentConnection = NULL;
3711*0f4c859eSApple OSS Distributions
3712*0f4c859eSApple OSS Distributions if (changeFlags & kIOPMSelfInitiated) {
3713*0f4c859eSApple OSS Distributions if (changeFlags & kIOPMSynchronize) {
3714*0f4c859eSApple OSS Distributions OurSyncStart();
3715*0f4c859eSApple OSS Distributions } else {
3716*0f4c859eSApple OSS Distributions OurChangeStart();
3717*0f4c859eSApple OSS Distributions }
3718*0f4c859eSApple OSS Distributions return 0;
3719*0f4c859eSApple OSS Distributions } else {
3720*0f4c859eSApple OSS Distributions assert(changeFlags & kIOPMParentInitiated);
3721*0f4c859eSApple OSS Distributions fHeadNoteDomainFlags = domainFlags;
3722*0f4c859eSApple OSS Distributions fHeadNoteParentFlags = parentFlags;
3723*0f4c859eSApple OSS Distributions fHeadNoteParentConnection = parentConnection;
3724*0f4c859eSApple OSS Distributions return ParentChangeStart();
3725*0f4c859eSApple OSS Distributions }
3726*0f4c859eSApple OSS Distributions }
3727*0f4c859eSApple OSS Distributions
3728*0f4c859eSApple OSS Distributions //*********************************************************************************
3729*0f4c859eSApple OSS Distributions // [private] notifyInterestedDrivers
3730*0f4c859eSApple OSS Distributions //*********************************************************************************
3731*0f4c859eSApple OSS Distributions
3732*0f4c859eSApple OSS Distributions bool
notifyInterestedDrivers(void)3733*0f4c859eSApple OSS Distributions IOService::notifyInterestedDrivers( void )
3734*0f4c859eSApple OSS Distributions {
3735*0f4c859eSApple OSS Distributions IOPMinformee * informee;
3736*0f4c859eSApple OSS Distributions IOPMinformeeList * list = fInterestedDrivers;
3737*0f4c859eSApple OSS Distributions DriverCallParam * param;
3738*0f4c859eSApple OSS Distributions unsigned long numItems;
3739*0f4c859eSApple OSS Distributions uint32_t count;
3740*0f4c859eSApple OSS Distributions uint32_t skipCnt = 0;
3741*0f4c859eSApple OSS Distributions
3742*0f4c859eSApple OSS Distributions PM_ASSERT_IN_GATE();
3743*0f4c859eSApple OSS Distributions assert( fDriverCallParamCount == 0 );
3744*0f4c859eSApple OSS Distributions assert( fHeadNotePendingAcks == 0 );
3745*0f4c859eSApple OSS Distributions
3746*0f4c859eSApple OSS Distributions fHeadNotePendingAcks = 0;
3747*0f4c859eSApple OSS Distributions
3748*0f4c859eSApple OSS Distributions numItems = list->numberOfItems();
3749*0f4c859eSApple OSS Distributions if (!numItems || ((uint32_t) numItems != numItems)) {
3750*0f4c859eSApple OSS Distributions goto done; // interested drivers count out of range
3751*0f4c859eSApple OSS Distributions }
3752*0f4c859eSApple OSS Distributions count = (uint32_t) numItems;
3753*0f4c859eSApple OSS Distributions
3754*0f4c859eSApple OSS Distributions // Allocate an array of interested drivers and their return values
3755*0f4c859eSApple OSS Distributions // for the callout thread. Everything else is still "owned" by the
3756*0f4c859eSApple OSS Distributions // PM work loop, which can run to process acknowledgePowerChange()
3757*0f4c859eSApple OSS Distributions // responses.
3758*0f4c859eSApple OSS Distributions
3759*0f4c859eSApple OSS Distributions param = (DriverCallParam *) fDriverCallParamPtr;
3760*0f4c859eSApple OSS Distributions if (count > fDriverCallParamSlots) {
3761*0f4c859eSApple OSS Distributions if (fDriverCallParamSlots) {
3762*0f4c859eSApple OSS Distributions assert(fDriverCallParamPtr);
3763*0f4c859eSApple OSS Distributions IODelete(fDriverCallParamPtr, DriverCallParam, fDriverCallParamSlots);
3764*0f4c859eSApple OSS Distributions fDriverCallParamPtr = NULL;
3765*0f4c859eSApple OSS Distributions fDriverCallParamSlots = 0;
3766*0f4c859eSApple OSS Distributions }
3767*0f4c859eSApple OSS Distributions
3768*0f4c859eSApple OSS Distributions param = IONew(DriverCallParam, count);
3769*0f4c859eSApple OSS Distributions if (!param) {
3770*0f4c859eSApple OSS Distributions goto done; // no memory
3771*0f4c859eSApple OSS Distributions }
3772*0f4c859eSApple OSS Distributions fDriverCallParamPtr = (void *) param;
3773*0f4c859eSApple OSS Distributions fDriverCallParamSlots = count;
3774*0f4c859eSApple OSS Distributions }
3775*0f4c859eSApple OSS Distributions
3776*0f4c859eSApple OSS Distributions informee = list->firstInList();
3777*0f4c859eSApple OSS Distributions assert(informee);
3778*0f4c859eSApple OSS Distributions for (IOItemCount i = 0, arrayIdx = 0; i < count; i++) {
3779*0f4c859eSApple OSS Distributions if (fInitialSetPowerState || (fHeadNoteChangeFlags & kIOPMInitialPowerChange)) {
3780*0f4c859eSApple OSS Distributions // Skip notifying self, if 'kIOPMInitialDeviceState' is set and
3781*0f4c859eSApple OSS Distributions // this is the initial power state change
3782*0f4c859eSApple OSS Distributions if ((this == informee->whatObject) &&
3783*0f4c859eSApple OSS Distributions (fHeadNotePowerArrayEntry->capabilityFlags & kIOPMInitialDeviceState)) {
3784*0f4c859eSApple OSS Distributions skipCnt++;
3785*0f4c859eSApple OSS Distributions continue;
3786*0f4c859eSApple OSS Distributions }
3787*0f4c859eSApple OSS Distributions }
3788*0f4c859eSApple OSS Distributions informee->timer = -1;
3789*0f4c859eSApple OSS Distributions param[arrayIdx].Target = informee;
3790*0f4c859eSApple OSS Distributions informee->retain();
3791*0f4c859eSApple OSS Distributions informee = list->nextInList( informee );
3792*0f4c859eSApple OSS Distributions arrayIdx++;
3793*0f4c859eSApple OSS Distributions }
3794*0f4c859eSApple OSS Distributions
3795*0f4c859eSApple OSS Distributions count -= skipCnt;
3796*0f4c859eSApple OSS Distributions if (!count) {
3797*0f4c859eSApple OSS Distributions goto done;
3798*0f4c859eSApple OSS Distributions }
3799*0f4c859eSApple OSS Distributions fDriverCallParamCount = count;
3800*0f4c859eSApple OSS Distributions fHeadNotePendingAcks = count;
3801*0f4c859eSApple OSS Distributions
3802*0f4c859eSApple OSS Distributions // Block state machine and wait for callout completion.
3803*0f4c859eSApple OSS Distributions assert(!fDriverCallBusy);
3804*0f4c859eSApple OSS Distributions fDriverCallBusy = true;
3805*0f4c859eSApple OSS Distributions thread_call_enter( fDriverCallEntry );
3806*0f4c859eSApple OSS Distributions return true;
3807*0f4c859eSApple OSS Distributions
3808*0f4c859eSApple OSS Distributions done:
3809*0f4c859eSApple OSS Distributions // Return false if there are no interested drivers or could not schedule
3810*0f4c859eSApple OSS Distributions // callout thread due to error.
3811*0f4c859eSApple OSS Distributions return false;
3812*0f4c859eSApple OSS Distributions }
3813*0f4c859eSApple OSS Distributions
3814*0f4c859eSApple OSS Distributions //*********************************************************************************
3815*0f4c859eSApple OSS Distributions // [private] notifyInterestedDriversDone
3816*0f4c859eSApple OSS Distributions //*********************************************************************************
3817*0f4c859eSApple OSS Distributions
3818*0f4c859eSApple OSS Distributions void
notifyInterestedDriversDone(void)3819*0f4c859eSApple OSS Distributions IOService::notifyInterestedDriversDone( void )
3820*0f4c859eSApple OSS Distributions {
3821*0f4c859eSApple OSS Distributions IOPMinformee * informee;
3822*0f4c859eSApple OSS Distributions IOItemCount count;
3823*0f4c859eSApple OSS Distributions DriverCallParam * param;
3824*0f4c859eSApple OSS Distributions IOReturn result;
3825*0f4c859eSApple OSS Distributions int maxTimeout = 0;
3826*0f4c859eSApple OSS Distributions
3827*0f4c859eSApple OSS Distributions PM_ASSERT_IN_GATE();
3828*0f4c859eSApple OSS Distributions assert( fDriverCallBusy == false );
3829*0f4c859eSApple OSS Distributions assert( fMachineState == kIOPM_DriverThreadCallDone );
3830*0f4c859eSApple OSS Distributions
3831*0f4c859eSApple OSS Distributions param = (DriverCallParam *) fDriverCallParamPtr;
3832*0f4c859eSApple OSS Distributions count = fDriverCallParamCount;
3833*0f4c859eSApple OSS Distributions
3834*0f4c859eSApple OSS Distributions if (param && count) {
3835*0f4c859eSApple OSS Distributions for (IOItemCount i = 0; i < count; i++, param++) {
3836*0f4c859eSApple OSS Distributions informee = (IOPMinformee *) param->Target;
3837*0f4c859eSApple OSS Distributions result = param->Result;
3838*0f4c859eSApple OSS Distributions
3839*0f4c859eSApple OSS Distributions if ((result == IOPMAckImplied) || (result < 0)) {
3840*0f4c859eSApple OSS Distributions // Interested driver return IOPMAckImplied.
3841*0f4c859eSApple OSS Distributions // If informee timer is zero, it must have de-registered
3842*0f4c859eSApple OSS Distributions // interest during the thread callout. That also drops
3843*0f4c859eSApple OSS Distributions // the pending ack count.
3844*0f4c859eSApple OSS Distributions
3845*0f4c859eSApple OSS Distributions if (fHeadNotePendingAcks && informee->timer) {
3846*0f4c859eSApple OSS Distributions fHeadNotePendingAcks--;
3847*0f4c859eSApple OSS Distributions }
3848*0f4c859eSApple OSS Distributions
3849*0f4c859eSApple OSS Distributions informee->timer = 0;
3850*0f4c859eSApple OSS Distributions } else if (informee->timer) {
3851*0f4c859eSApple OSS Distributions assert(informee->timer == -1);
3852*0f4c859eSApple OSS Distributions
3853*0f4c859eSApple OSS Distributions // Driver has not acked, and has returned a positive result.
3854*0f4c859eSApple OSS Distributions // Enforce a minimum permissible timeout value.
3855*0f4c859eSApple OSS Distributions // Make the min value large enough so timeout is less likely
3856*0f4c859eSApple OSS Distributions // to occur if a driver misinterpreted that the return value
3857*0f4c859eSApple OSS Distributions // should be in microsecond units. And make it large enough
3858*0f4c859eSApple OSS Distributions // to be noticeable if a driver neglects to ack.
3859*0f4c859eSApple OSS Distributions
3860*0f4c859eSApple OSS Distributions if (result < kMinAckTimeoutTicks) {
3861*0f4c859eSApple OSS Distributions result = kMinAckTimeoutTicks;
3862*0f4c859eSApple OSS Distributions }
3863*0f4c859eSApple OSS Distributions
3864*0f4c859eSApple OSS Distributions informee->timer = (result / (ACK_TIMER_PERIOD / ns_per_us)) + 1;
3865*0f4c859eSApple OSS Distributions if (result > maxTimeout) {
3866*0f4c859eSApple OSS Distributions maxTimeout = result;
3867*0f4c859eSApple OSS Distributions }
3868*0f4c859eSApple OSS Distributions }
3869*0f4c859eSApple OSS Distributions // else, child has already acked or driver has removed interest,
3870*0f4c859eSApple OSS Distributions // and head_note_pendingAcks decremented.
3871*0f4c859eSApple OSS Distributions // informee may have been removed from the interested drivers list,
3872*0f4c859eSApple OSS Distributions // thus the informee must be retained across the callout.
3873*0f4c859eSApple OSS Distributions
3874*0f4c859eSApple OSS Distributions informee->release();
3875*0f4c859eSApple OSS Distributions }
3876*0f4c859eSApple OSS Distributions
3877*0f4c859eSApple OSS Distributions fDriverCallParamCount = 0;
3878*0f4c859eSApple OSS Distributions
3879*0f4c859eSApple OSS Distributions if (fHeadNotePendingAcks) {
3880*0f4c859eSApple OSS Distributions OUR_PMLog(kPMLogStartAckTimer, 0, 0);
3881*0f4c859eSApple OSS Distributions start_ack_timer();
3882*0f4c859eSApple OSS Distributions getPMRootDomain()->reset_watchdog_timer(this, maxTimeout / USEC_PER_SEC + 1);
3883*0f4c859eSApple OSS Distributions }
3884*0f4c859eSApple OSS Distributions }
3885*0f4c859eSApple OSS Distributions
3886*0f4c859eSApple OSS Distributions MS_POP(); // pop the machine state passed to notifyAll()
3887*0f4c859eSApple OSS Distributions
3888*0f4c859eSApple OSS Distributions // If interest acks are outstanding, block the state machine until
3889*0f4c859eSApple OSS Distributions // fHeadNotePendingAcks drops to zero before notifying root domain.
3890*0f4c859eSApple OSS Distributions // Otherwise notify root domain directly.
3891*0f4c859eSApple OSS Distributions
3892*0f4c859eSApple OSS Distributions if (!fHeadNotePendingAcks) {
3893*0f4c859eSApple OSS Distributions notifyRootDomain();
3894*0f4c859eSApple OSS Distributions } else {
3895*0f4c859eSApple OSS Distributions MS_PUSH(fMachineState);
3896*0f4c859eSApple OSS Distributions fMachineState = kIOPM_NotifyChildrenStart;
3897*0f4c859eSApple OSS Distributions }
3898*0f4c859eSApple OSS Distributions }
3899*0f4c859eSApple OSS Distributions
3900*0f4c859eSApple OSS Distributions //*********************************************************************************
3901*0f4c859eSApple OSS Distributions // [private] notifyRootDomain
3902*0f4c859eSApple OSS Distributions //*********************************************************************************
3903*0f4c859eSApple OSS Distributions
3904*0f4c859eSApple OSS Distributions void
notifyRootDomain(void)3905*0f4c859eSApple OSS Distributions IOService::notifyRootDomain( void )
3906*0f4c859eSApple OSS Distributions {
3907*0f4c859eSApple OSS Distributions assert( fDriverCallBusy == false );
3908*0f4c859eSApple OSS Distributions
3909*0f4c859eSApple OSS Distributions // Only for root domain in the will-change phase.
3910*0f4c859eSApple OSS Distributions // On a power up, don't notify children right after the interested drivers.
3911*0f4c859eSApple OSS Distributions // Perform setPowerState() first, then notify the children.
3912*0f4c859eSApple OSS Distributions if (!IS_ROOT_DOMAIN || (fMachineState != kIOPM_OurChangeSetPowerState)) {
3913*0f4c859eSApple OSS Distributions notifyChildren();
3914*0f4c859eSApple OSS Distributions return;
3915*0f4c859eSApple OSS Distributions }
3916*0f4c859eSApple OSS Distributions
3917*0f4c859eSApple OSS Distributions MS_PUSH(fMachineState); // push notifyAll() machine state
3918*0f4c859eSApple OSS Distributions fMachineState = kIOPM_DriverThreadCallDone;
3919*0f4c859eSApple OSS Distributions
3920*0f4c859eSApple OSS Distributions // Call IOPMrootDomain::willNotifyPowerChildren() on a thread call
3921*0f4c859eSApple OSS Distributions // to avoid a deadlock.
3922*0f4c859eSApple OSS Distributions fDriverCallReason = kRootDomainInformPreChange;
3923*0f4c859eSApple OSS Distributions fDriverCallBusy = true;
3924*0f4c859eSApple OSS Distributions thread_call_enter( fDriverCallEntry );
3925*0f4c859eSApple OSS Distributions }
3926*0f4c859eSApple OSS Distributions
3927*0f4c859eSApple OSS Distributions void
notifyRootDomainDone(void)3928*0f4c859eSApple OSS Distributions IOService::notifyRootDomainDone( void )
3929*0f4c859eSApple OSS Distributions {
3930*0f4c859eSApple OSS Distributions assert( fDriverCallBusy == false );
3931*0f4c859eSApple OSS Distributions assert( fMachineState == kIOPM_DriverThreadCallDone );
3932*0f4c859eSApple OSS Distributions
3933*0f4c859eSApple OSS Distributions MS_POP(); // pop notifyAll() machine state
3934*0f4c859eSApple OSS Distributions notifyChildren();
3935*0f4c859eSApple OSS Distributions }
3936*0f4c859eSApple OSS Distributions
3937*0f4c859eSApple OSS Distributions //*********************************************************************************
3938*0f4c859eSApple OSS Distributions // [private] notifyChildren
3939*0f4c859eSApple OSS Distributions //*********************************************************************************
3940*0f4c859eSApple OSS Distributions
3941*0f4c859eSApple OSS Distributions void
notifyChildren(void)3942*0f4c859eSApple OSS Distributions IOService::notifyChildren( void )
3943*0f4c859eSApple OSS Distributions {
3944*0f4c859eSApple OSS Distributions OSIterator * iter;
3945*0f4c859eSApple OSS Distributions OSObject * next;
3946*0f4c859eSApple OSS Distributions IOPowerConnection * connection;
3947*0f4c859eSApple OSS Distributions OSArray * children = NULL;
3948*0f4c859eSApple OSS Distributions IOPMrootDomain * rootDomain;
3949*0f4c859eSApple OSS Distributions bool delayNotify = false;
3950*0f4c859eSApple OSS Distributions
3951*0f4c859eSApple OSS Distributions if ((fHeadNotePowerState != fCurrentPowerState) &&
3952*0f4c859eSApple OSS Distributions (IS_POWER_DROP == fIsPreChange) &&
3953*0f4c859eSApple OSS Distributions ((rootDomain = getPMRootDomain()) == this)) {
3954*0f4c859eSApple OSS Distributions rootDomain->tracePoint( IS_POWER_DROP ?
3955*0f4c859eSApple OSS Distributions kIOPMTracePointSleepPowerPlaneDrivers :
3956*0f4c859eSApple OSS Distributions kIOPMTracePointWakePowerPlaneDrivers );
3957*0f4c859eSApple OSS Distributions }
3958*0f4c859eSApple OSS Distributions
3959*0f4c859eSApple OSS Distributions if (fStrictTreeOrder) {
3960*0f4c859eSApple OSS Distributions children = OSArray::withCapacity(8);
3961*0f4c859eSApple OSS Distributions }
3962*0f4c859eSApple OSS Distributions
3963*0f4c859eSApple OSS Distributions // Sum child power consumption in notifyChild()
3964*0f4c859eSApple OSS Distributions fHeadNotePowerArrayEntry->staticPower = 0;
3965*0f4c859eSApple OSS Distributions
3966*0f4c859eSApple OSS Distributions iter = getChildIterator(gIOPowerPlane);
3967*0f4c859eSApple OSS Distributions if (iter) {
3968*0f4c859eSApple OSS Distributions while ((next = iter->getNextObject())) {
3969*0f4c859eSApple OSS Distributions if ((connection = OSDynamicCast(IOPowerConnection, next))) {
3970*0f4c859eSApple OSS Distributions if (connection->getReadyFlag() == false) {
3971*0f4c859eSApple OSS Distributions PM_LOG3("[%s] %s: connection not ready\n",
3972*0f4c859eSApple OSS Distributions getName(), __FUNCTION__);
3973*0f4c859eSApple OSS Distributions continue;
3974*0f4c859eSApple OSS Distributions }
3975*0f4c859eSApple OSS Distributions
3976*0f4c859eSApple OSS Distributions // Mechanism to postpone the did-change notification to
3977*0f4c859eSApple OSS Distributions // certain power children to order those children last.
3978*0f4c859eSApple OSS Distributions // Cannot be used together with strict tree ordering.
3979*0f4c859eSApple OSS Distributions
3980*0f4c859eSApple OSS Distributions if (!fIsPreChange &&
3981*0f4c859eSApple OSS Distributions connection->delayChildNotification &&
3982*0f4c859eSApple OSS Distributions getPMRootDomain()->shouldDelayChildNotification(this)) {
3983*0f4c859eSApple OSS Distributions if (!children) {
3984*0f4c859eSApple OSS Distributions children = OSArray::withCapacity(8);
3985*0f4c859eSApple OSS Distributions if (children) {
3986*0f4c859eSApple OSS Distributions delayNotify = true;
3987*0f4c859eSApple OSS Distributions }
3988*0f4c859eSApple OSS Distributions }
3989*0f4c859eSApple OSS Distributions if (delayNotify) {
3990*0f4c859eSApple OSS Distributions children->setObject( connection );
3991*0f4c859eSApple OSS Distributions continue;
3992*0f4c859eSApple OSS Distributions }
3993*0f4c859eSApple OSS Distributions }
3994*0f4c859eSApple OSS Distributions
3995*0f4c859eSApple OSS Distributions if (!delayNotify && children) {
3996*0f4c859eSApple OSS Distributions children->setObject( connection );
3997*0f4c859eSApple OSS Distributions } else {
3998*0f4c859eSApple OSS Distributions notifyChild( connection );
3999*0f4c859eSApple OSS Distributions }
4000*0f4c859eSApple OSS Distributions }
4001*0f4c859eSApple OSS Distributions }
4002*0f4c859eSApple OSS Distributions iter->release();
4003*0f4c859eSApple OSS Distributions }
4004*0f4c859eSApple OSS Distributions
4005*0f4c859eSApple OSS Distributions if (children && (children->getCount() == 0)) {
4006*0f4c859eSApple OSS Distributions children->release();
4007*0f4c859eSApple OSS Distributions children = NULL;
4008*0f4c859eSApple OSS Distributions }
4009*0f4c859eSApple OSS Distributions if (children) {
4010*0f4c859eSApple OSS Distributions assert(fNotifyChildArray == NULL);
4011*0f4c859eSApple OSS Distributions fNotifyChildArray = children;
4012*0f4c859eSApple OSS Distributions MS_PUSH(fMachineState);
4013*0f4c859eSApple OSS Distributions
4014*0f4c859eSApple OSS Distributions if (delayNotify) {
4015*0f4c859eSApple OSS Distributions // Block until all non-delayed children have acked their
4016*0f4c859eSApple OSS Distributions // notification. Then notify the remaining delayed child
4017*0f4c859eSApple OSS Distributions // in the array. This is used to hold off graphics child
4018*0f4c859eSApple OSS Distributions // notification while the rest of the system powers up.
4019*0f4c859eSApple OSS Distributions // If a hid tickle arrives during this time, the delayed
4020*0f4c859eSApple OSS Distributions // children are immediately notified and root domain will
4021*0f4c859eSApple OSS Distributions // not clamp power for dark wake.
4022*0f4c859eSApple OSS Distributions
4023*0f4c859eSApple OSS Distributions fMachineState = kIOPM_NotifyChildrenDelayed;
4024*0f4c859eSApple OSS Distributions PM_LOG2("%s: %d children in delayed array\n",
4025*0f4c859eSApple OSS Distributions getName(), children->getCount());
4026*0f4c859eSApple OSS Distributions } else {
4027*0f4c859eSApple OSS Distributions // Child array created to support strict notification order.
4028*0f4c859eSApple OSS Distributions // Notify children in the array one at a time.
4029*0f4c859eSApple OSS Distributions
4030*0f4c859eSApple OSS Distributions fMachineState = kIOPM_NotifyChildrenOrdered;
4031*0f4c859eSApple OSS Distributions }
4032*0f4c859eSApple OSS Distributions }
4033*0f4c859eSApple OSS Distributions }
4034*0f4c859eSApple OSS Distributions
4035*0f4c859eSApple OSS Distributions //*********************************************************************************
4036*0f4c859eSApple OSS Distributions // [private] notifyChildrenOrdered
4037*0f4c859eSApple OSS Distributions //*********************************************************************************
4038*0f4c859eSApple OSS Distributions
4039*0f4c859eSApple OSS Distributions void
notifyChildrenOrdered(void)4040*0f4c859eSApple OSS Distributions IOService::notifyChildrenOrdered( void )
4041*0f4c859eSApple OSS Distributions {
4042*0f4c859eSApple OSS Distributions PM_ASSERT_IN_GATE();
4043*0f4c859eSApple OSS Distributions assert(fNotifyChildArray);
4044*0f4c859eSApple OSS Distributions assert(fMachineState == kIOPM_NotifyChildrenOrdered);
4045*0f4c859eSApple OSS Distributions
4046*0f4c859eSApple OSS Distributions // Notify one child, wait for it to ack, then repeat for next child.
4047*0f4c859eSApple OSS Distributions // This is a workaround for some drivers with multiple instances at
4048*0f4c859eSApple OSS Distributions // the same branch in the power tree, but the driver is slow to power
4049*0f4c859eSApple OSS Distributions // up unless the tree ordering is observed. Problem observed only on
4050*0f4c859eSApple OSS Distributions // system wake, not on system sleep.
4051*0f4c859eSApple OSS Distributions //
4052*0f4c859eSApple OSS Distributions // We have the ability to power off in reverse child index order.
4053*0f4c859eSApple OSS Distributions // That works nicely on some machines, but not on all HW configs.
4054*0f4c859eSApple OSS Distributions
4055*0f4c859eSApple OSS Distributions if (fNotifyChildArray->getCount()) {
4056*0f4c859eSApple OSS Distributions IOPowerConnection * connection;
4057*0f4c859eSApple OSS Distributions connection = (IOPowerConnection *) fNotifyChildArray->getObject(0);
4058*0f4c859eSApple OSS Distributions notifyChild( connection );
4059*0f4c859eSApple OSS Distributions fNotifyChildArray->removeObject(0);
4060*0f4c859eSApple OSS Distributions } else {
4061*0f4c859eSApple OSS Distributions fNotifyChildArray->release();
4062*0f4c859eSApple OSS Distributions fNotifyChildArray = NULL;
4063*0f4c859eSApple OSS Distributions
4064*0f4c859eSApple OSS Distributions MS_POP(); // pushed by notifyChildren()
4065*0f4c859eSApple OSS Distributions }
4066*0f4c859eSApple OSS Distributions }
4067*0f4c859eSApple OSS Distributions
4068*0f4c859eSApple OSS Distributions //*********************************************************************************
4069*0f4c859eSApple OSS Distributions // [private] notifyChildrenDelayed
4070*0f4c859eSApple OSS Distributions //*********************************************************************************
4071*0f4c859eSApple OSS Distributions
4072*0f4c859eSApple OSS Distributions void
notifyChildrenDelayed(void)4073*0f4c859eSApple OSS Distributions IOService::notifyChildrenDelayed( void )
4074*0f4c859eSApple OSS Distributions {
4075*0f4c859eSApple OSS Distributions IOPowerConnection * connection;
4076*0f4c859eSApple OSS Distributions
4077*0f4c859eSApple OSS Distributions PM_ASSERT_IN_GATE();
4078*0f4c859eSApple OSS Distributions assert(fNotifyChildArray);
4079*0f4c859eSApple OSS Distributions assert(fMachineState == kIOPM_NotifyChildrenDelayed);
4080*0f4c859eSApple OSS Distributions
4081*0f4c859eSApple OSS Distributions // Wait after all non-delayed children and interested drivers have ack'ed,
4082*0f4c859eSApple OSS Distributions // then notify all delayed children. If notify delay is canceled, child
4083*0f4c859eSApple OSS Distributions // acks may be outstanding with PM blocked on fHeadNotePendingAcks != 0.
4084*0f4c859eSApple OSS Distributions // But the handling for either case is identical.
4085*0f4c859eSApple OSS Distributions
4086*0f4c859eSApple OSS Distributions for (int i = 0;; i++) {
4087*0f4c859eSApple OSS Distributions connection = (IOPowerConnection *) fNotifyChildArray->getObject(i);
4088*0f4c859eSApple OSS Distributions if (!connection) {
4089*0f4c859eSApple OSS Distributions break;
4090*0f4c859eSApple OSS Distributions }
4091*0f4c859eSApple OSS Distributions
4092*0f4c859eSApple OSS Distributions notifyChild( connection );
4093*0f4c859eSApple OSS Distributions }
4094*0f4c859eSApple OSS Distributions
4095*0f4c859eSApple OSS Distributions PM_LOG2("%s: notified delayed children\n", getName());
4096*0f4c859eSApple OSS Distributions fNotifyChildArray->release();
4097*0f4c859eSApple OSS Distributions fNotifyChildArray = NULL;
4098*0f4c859eSApple OSS Distributions
4099*0f4c859eSApple OSS Distributions MS_POP(); // pushed by notifyChildren()
4100*0f4c859eSApple OSS Distributions }
4101*0f4c859eSApple OSS Distributions
4102*0f4c859eSApple OSS Distributions //*********************************************************************************
4103*0f4c859eSApple OSS Distributions // [private] notifyAll
4104*0f4c859eSApple OSS Distributions //*********************************************************************************
4105*0f4c859eSApple OSS Distributions
4106*0f4c859eSApple OSS Distributions IOReturn
notifyAll(uint32_t nextMS)4107*0f4c859eSApple OSS Distributions IOService::notifyAll( uint32_t nextMS )
4108*0f4c859eSApple OSS Distributions {
4109*0f4c859eSApple OSS Distributions // Save the machine state to be restored by notifyInterestedDriversDone()
4110*0f4c859eSApple OSS Distributions
4111*0f4c859eSApple OSS Distributions PM_ASSERT_IN_GATE();
4112*0f4c859eSApple OSS Distributions MS_PUSH(nextMS);
4113*0f4c859eSApple OSS Distributions fMachineState = kIOPM_DriverThreadCallDone;
4114*0f4c859eSApple OSS Distributions fDriverCallReason = fIsPreChange ?
4115*0f4c859eSApple OSS Distributions kDriverCallInformPreChange : kDriverCallInformPostChange;
4116*0f4c859eSApple OSS Distributions
4117*0f4c859eSApple OSS Distributions if (!notifyInterestedDrivers()) {
4118*0f4c859eSApple OSS Distributions notifyInterestedDriversDone();
4119*0f4c859eSApple OSS Distributions }
4120*0f4c859eSApple OSS Distributions
4121*0f4c859eSApple OSS Distributions return IOPMWillAckLater;
4122*0f4c859eSApple OSS Distributions }
4123*0f4c859eSApple OSS Distributions
4124*0f4c859eSApple OSS Distributions //*********************************************************************************
4125*0f4c859eSApple OSS Distributions // [private, static] pmDriverCallout
4126*0f4c859eSApple OSS Distributions //
4127*0f4c859eSApple OSS Distributions // Thread call context
4128*0f4c859eSApple OSS Distributions //*********************************************************************************
4129*0f4c859eSApple OSS Distributions
4130*0f4c859eSApple OSS Distributions IOReturn
actionDriverCalloutDone(OSObject * target,void * arg0,void * arg1,void * arg2,void * arg3)4131*0f4c859eSApple OSS Distributions IOService::actionDriverCalloutDone(
4132*0f4c859eSApple OSS Distributions OSObject * target,
4133*0f4c859eSApple OSS Distributions void * arg0, void * arg1,
4134*0f4c859eSApple OSS Distributions void * arg2, void * arg3 )
4135*0f4c859eSApple OSS Distributions {
4136*0f4c859eSApple OSS Distributions IOServicePM * pwrMgt = (IOServicePM *) arg0;
4137*0f4c859eSApple OSS Distributions
4138*0f4c859eSApple OSS Distributions assert( fDriverCallBusy );
4139*0f4c859eSApple OSS Distributions fDriverCallBusy = false;
4140*0f4c859eSApple OSS Distributions
4141*0f4c859eSApple OSS Distributions assert(gIOPMWorkQueue);
4142*0f4c859eSApple OSS Distributions gIOPMWorkQueue->signalWorkAvailable();
4143*0f4c859eSApple OSS Distributions
4144*0f4c859eSApple OSS Distributions return kIOReturnSuccess;
4145*0f4c859eSApple OSS Distributions }
4146*0f4c859eSApple OSS Distributions
4147*0f4c859eSApple OSS Distributions void
pmDriverCallout(IOService * from,__unused thread_call_param_t p)4148*0f4c859eSApple OSS Distributions IOService::pmDriverCallout( IOService * from,
4149*0f4c859eSApple OSS Distributions __unused thread_call_param_t p)
4150*0f4c859eSApple OSS Distributions {
4151*0f4c859eSApple OSS Distributions assert(from);
4152*0f4c859eSApple OSS Distributions from->startDriverCalloutTimer();
4153*0f4c859eSApple OSS Distributions switch (from->fDriverCallReason) {
4154*0f4c859eSApple OSS Distributions case kDriverCallSetPowerState:
4155*0f4c859eSApple OSS Distributions from->driverSetPowerState();
4156*0f4c859eSApple OSS Distributions break;
4157*0f4c859eSApple OSS Distributions
4158*0f4c859eSApple OSS Distributions case kDriverCallInformPreChange:
4159*0f4c859eSApple OSS Distributions case kDriverCallInformPostChange:
4160*0f4c859eSApple OSS Distributions from->driverInformPowerChange();
4161*0f4c859eSApple OSS Distributions break;
4162*0f4c859eSApple OSS Distributions
4163*0f4c859eSApple OSS Distributions case kRootDomainInformPreChange:
4164*0f4c859eSApple OSS Distributions getPMRootDomain()->willNotifyPowerChildren(from->fHeadNotePowerState);
4165*0f4c859eSApple OSS Distributions break;
4166*0f4c859eSApple OSS Distributions
4167*0f4c859eSApple OSS Distributions default:
4168*0f4c859eSApple OSS Distributions panic("IOService::pmDriverCallout bad machine state %x",
4169*0f4c859eSApple OSS Distributions from->fDriverCallReason);
4170*0f4c859eSApple OSS Distributions }
4171*0f4c859eSApple OSS Distributions from->stopDriverCalloutTimer();
4172*0f4c859eSApple OSS Distributions
4173*0f4c859eSApple OSS Distributions gIOPMWorkLoop->runAction(actionDriverCalloutDone,
4174*0f4c859eSApple OSS Distributions /* target */ from,
4175*0f4c859eSApple OSS Distributions /* arg0 */ (void *) from->pwrMgt );
4176*0f4c859eSApple OSS Distributions }
4177*0f4c859eSApple OSS Distributions
4178*0f4c859eSApple OSS Distributions //*********************************************************************************
4179*0f4c859eSApple OSS Distributions // [private] driverSetPowerState
4180*0f4c859eSApple OSS Distributions //
4181*0f4c859eSApple OSS Distributions // Thread call context
4182*0f4c859eSApple OSS Distributions //*********************************************************************************
4183*0f4c859eSApple OSS Distributions
4184*0f4c859eSApple OSS Distributions void
driverSetPowerState(void)4185*0f4c859eSApple OSS Distributions IOService::driverSetPowerState( void )
4186*0f4c859eSApple OSS Distributions {
4187*0f4c859eSApple OSS Distributions IOPMPowerStateIndex powerState;
4188*0f4c859eSApple OSS Distributions DriverCallParam * param;
4189*0f4c859eSApple OSS Distributions IOPMDriverCallEntry callEntry;
4190*0f4c859eSApple OSS Distributions AbsoluteTime end;
4191*0f4c859eSApple OSS Distributions IOReturn result;
4192*0f4c859eSApple OSS Distributions uint32_t oldPowerState = getPowerState();
4193*0f4c859eSApple OSS Distributions const OSMetaClass *controllingDriverMetaClass = NULL;
4194*0f4c859eSApple OSS Distributions uint32_t controllingDriverRegistryEntryID = 0;
4195*0f4c859eSApple OSS Distributions
4196*0f4c859eSApple OSS Distributions assert( fDriverCallBusy );
4197*0f4c859eSApple OSS Distributions assert( fDriverCallParamPtr );
4198*0f4c859eSApple OSS Distributions assert( fDriverCallParamCount == 1 );
4199*0f4c859eSApple OSS Distributions
4200*0f4c859eSApple OSS Distributions param = (DriverCallParam *) fDriverCallParamPtr;
4201*0f4c859eSApple OSS Distributions powerState = fHeadNotePowerState;
4202*0f4c859eSApple OSS Distributions if (fControllingDriver) {
4203*0f4c859eSApple OSS Distributions controllingDriverMetaClass = fControllingDriver->getMetaClass();
4204*0f4c859eSApple OSS Distributions controllingDriverRegistryEntryID = (uint32_t)fControllingDriver->getRegistryEntryID();
4205*0f4c859eSApple OSS Distributions }
4206*0f4c859eSApple OSS Distributions
4207*0f4c859eSApple OSS Distributions if (assertPMDriverCall(&callEntry, kIOPMDriverCallMethodSetPowerState)) {
4208*0f4c859eSApple OSS Distributions SOCD_TRACE_XNU_START(PM_SET_POWER_STATE,
4209*0f4c859eSApple OSS Distributions ADDR(controllingDriverMetaClass),
4210*0f4c859eSApple OSS Distributions ADDR(this->getMetaClass()),
4211*0f4c859eSApple OSS Distributions PACK_2X32(VALUE(this->getRegistryEntryID()), VALUE(controllingDriverRegistryEntryID)),
4212*0f4c859eSApple OSS Distributions PACK_2X32(VALUE(powerState), VALUE(oldPowerState)));
4213*0f4c859eSApple OSS Distributions
4214*0f4c859eSApple OSS Distributions OUR_PMLogFuncStart(kPMLogProgramHardware, (uintptr_t) this, powerState);
4215*0f4c859eSApple OSS Distributions clock_get_uptime(&fDriverCallStartTime);
4216*0f4c859eSApple OSS Distributions
4217*0f4c859eSApple OSS Distributions if (reserved && reserved->uvars && reserved->uvars->userServer) {
4218*0f4c859eSApple OSS Distributions result = reserved->uvars->userServer->serviceSetPowerState(fControllingDriver, this, fHeadNotePowerArrayEntry->capabilityFlags, powerState);
4219*0f4c859eSApple OSS Distributions } else {
4220*0f4c859eSApple OSS Distributions result = fControllingDriver->setPowerState( powerState, this );
4221*0f4c859eSApple OSS Distributions }
4222*0f4c859eSApple OSS Distributions clock_get_uptime(&end);
4223*0f4c859eSApple OSS Distributions OUR_PMLogFuncEnd(kPMLogProgramHardware, (uintptr_t) this, (UInt32) result);
4224*0f4c859eSApple OSS Distributions SOCD_TRACE_XNU_END(PM_SET_POWER_STATE,
4225*0f4c859eSApple OSS Distributions ADDR(controllingDriverMetaClass),
4226*0f4c859eSApple OSS Distributions ADDR(this->getMetaClass()),
4227*0f4c859eSApple OSS Distributions PACK_2X32(VALUE(this->getRegistryEntryID()), VALUE(controllingDriverRegistryEntryID)),
4228*0f4c859eSApple OSS Distributions PACK_2X32(VALUE(powerState), VALUE(result)));
4229*0f4c859eSApple OSS Distributions
4230*0f4c859eSApple OSS Distributions deassertPMDriverCall(&callEntry);
4231*0f4c859eSApple OSS Distributions
4232*0f4c859eSApple OSS Distributions // Record the most recent max power state residency timings.
4233*0f4c859eSApple OSS Distributions // Use with DeviceActiveTimestamp to diagnose tickle issues.
4234*0f4c859eSApple OSS Distributions if (powerState == fHighestPowerState) {
4235*0f4c859eSApple OSS Distributions fMaxPowerStateEntryTime = end;
4236*0f4c859eSApple OSS Distributions } else if (oldPowerState == fHighestPowerState) {
4237*0f4c859eSApple OSS Distributions fMaxPowerStateExitTime = end;
4238*0f4c859eSApple OSS Distributions }
4239*0f4c859eSApple OSS Distributions
4240*0f4c859eSApple OSS Distributions if (result < 0) {
4241*0f4c859eSApple OSS Distributions PM_LOG("%s::setPowerState(%p, %lu -> %lu) returned 0x%x\n",
4242*0f4c859eSApple OSS Distributions fName, OBFUSCATE(this), fCurrentPowerState, powerState, result);
4243*0f4c859eSApple OSS Distributions }
4244*0f4c859eSApple OSS Distributions
4245*0f4c859eSApple OSS Distributions
4246*0f4c859eSApple OSS Distributions if ((result == IOPMAckImplied) || (result < 0)) {
4247*0f4c859eSApple OSS Distributions uint64_t nsec;
4248*0f4c859eSApple OSS Distributions
4249*0f4c859eSApple OSS Distributions SUB_ABSOLUTETIME(&end, &fDriverCallStartTime);
4250*0f4c859eSApple OSS Distributions absolutetime_to_nanoseconds(end, &nsec);
4251*0f4c859eSApple OSS Distributions if (nsec > gIOPMSetPowerStateLogNS) {
4252*0f4c859eSApple OSS Distributions getPMRootDomain()->pmStatsRecordApplicationResponse(
4253*0f4c859eSApple OSS Distributions gIOPMStatsDriverPSChangeSlow,
4254*0f4c859eSApple OSS Distributions fName, kDriverCallSetPowerState, NS_TO_MS(nsec), getRegistryEntryID(),
4255*0f4c859eSApple OSS Distributions NULL, powerState);
4256*0f4c859eSApple OSS Distributions }
4257*0f4c859eSApple OSS Distributions }
4258*0f4c859eSApple OSS Distributions } else {
4259*0f4c859eSApple OSS Distributions result = kIOPMAckImplied;
4260*0f4c859eSApple OSS Distributions }
4261*0f4c859eSApple OSS Distributions
4262*0f4c859eSApple OSS Distributions param->Result = result;
4263*0f4c859eSApple OSS Distributions }
4264*0f4c859eSApple OSS Distributions
4265*0f4c859eSApple OSS Distributions //*********************************************************************************
4266*0f4c859eSApple OSS Distributions // [private] driverInformPowerChange
4267*0f4c859eSApple OSS Distributions //
4268*0f4c859eSApple OSS Distributions // Thread call context
4269*0f4c859eSApple OSS Distributions //*********************************************************************************
4270*0f4c859eSApple OSS Distributions
4271*0f4c859eSApple OSS Distributions void
driverInformPowerChange(void)4272*0f4c859eSApple OSS Distributions IOService::driverInformPowerChange( void )
4273*0f4c859eSApple OSS Distributions {
4274*0f4c859eSApple OSS Distributions IOPMinformee * informee;
4275*0f4c859eSApple OSS Distributions IOService * driver;
4276*0f4c859eSApple OSS Distributions DriverCallParam * param;
4277*0f4c859eSApple OSS Distributions IOPMDriverCallEntry callEntry;
4278*0f4c859eSApple OSS Distributions IOPMPowerFlags powerFlags;
4279*0f4c859eSApple OSS Distributions IOPMPowerStateIndex powerState;
4280*0f4c859eSApple OSS Distributions AbsoluteTime end;
4281*0f4c859eSApple OSS Distributions IOReturn result;
4282*0f4c859eSApple OSS Distributions IOItemCount count;
4283*0f4c859eSApple OSS Distributions IOOptionBits callMethod = (fDriverCallReason == kDriverCallInformPreChange) ?
4284*0f4c859eSApple OSS Distributions kIOPMDriverCallMethodWillChange : kIOPMDriverCallMethodDidChange;
4285*0f4c859eSApple OSS Distributions
4286*0f4c859eSApple OSS Distributions assert( fDriverCallBusy );
4287*0f4c859eSApple OSS Distributions assert( fDriverCallParamPtr );
4288*0f4c859eSApple OSS Distributions assert( fDriverCallParamCount );
4289*0f4c859eSApple OSS Distributions
4290*0f4c859eSApple OSS Distributions param = (DriverCallParam *) fDriverCallParamPtr;
4291*0f4c859eSApple OSS Distributions count = fDriverCallParamCount;
4292*0f4c859eSApple OSS Distributions
4293*0f4c859eSApple OSS Distributions powerFlags = fHeadNotePowerArrayEntry->capabilityFlags;
4294*0f4c859eSApple OSS Distributions powerState = fHeadNotePowerState;
4295*0f4c859eSApple OSS Distributions
4296*0f4c859eSApple OSS Distributions for (IOItemCount i = 0; i < count; i++) {
4297*0f4c859eSApple OSS Distributions informee = (IOPMinformee *) param->Target;
4298*0f4c859eSApple OSS Distributions driver = informee->whatObject;
4299*0f4c859eSApple OSS Distributions
4300*0f4c859eSApple OSS Distributions if (assertPMDriverCall(&callEntry, callMethod, informee)) {
4301*0f4c859eSApple OSS Distributions SOCD_TRACE_XNU_START(PM_INFORM_POWER_CHANGE,
4302*0f4c859eSApple OSS Distributions ADDR(driver->getMetaClass()),
4303*0f4c859eSApple OSS Distributions ADDR(this->getMetaClass()),
4304*0f4c859eSApple OSS Distributions PACK_2X32(VALUE(this->getRegistryEntryID()), VALUE(driver->getRegistryEntryID())),
4305*0f4c859eSApple OSS Distributions PACK_2X32(VALUE(powerState), VALUE(fDriverCallReason)));
4306*0f4c859eSApple OSS Distributions
4307*0f4c859eSApple OSS Distributions if (fDriverCallReason == kDriverCallInformPreChange) {
4308*0f4c859eSApple OSS Distributions OUR_PMLogFuncStart(kPMLogInformDriverPreChange, (uintptr_t) this, powerState);
4309*0f4c859eSApple OSS Distributions clock_get_uptime(&informee->startTime);
4310*0f4c859eSApple OSS Distributions result = driver->powerStateWillChangeTo(powerFlags, powerState, this);
4311*0f4c859eSApple OSS Distributions clock_get_uptime(&end);
4312*0f4c859eSApple OSS Distributions OUR_PMLogFuncEnd(kPMLogInformDriverPreChange, (uintptr_t) this, result);
4313*0f4c859eSApple OSS Distributions } else {
4314*0f4c859eSApple OSS Distributions OUR_PMLogFuncStart(kPMLogInformDriverPostChange, (uintptr_t) this, powerState);
4315*0f4c859eSApple OSS Distributions clock_get_uptime(&informee->startTime);
4316*0f4c859eSApple OSS Distributions result = driver->powerStateDidChangeTo(powerFlags, powerState, this);
4317*0f4c859eSApple OSS Distributions clock_get_uptime(&end);
4318*0f4c859eSApple OSS Distributions OUR_PMLogFuncEnd(kPMLogInformDriverPostChange, (uintptr_t) this, result);
4319*0f4c859eSApple OSS Distributions }
4320*0f4c859eSApple OSS Distributions
4321*0f4c859eSApple OSS Distributions SOCD_TRACE_XNU_END(PM_INFORM_POWER_CHANGE,
4322*0f4c859eSApple OSS Distributions ADDR(driver->getMetaClass()),
4323*0f4c859eSApple OSS Distributions ADDR(this->getMetaClass()),
4324*0f4c859eSApple OSS Distributions PACK_2X32(VALUE(this->getRegistryEntryID()), VALUE(driver->getRegistryEntryID())),
4325*0f4c859eSApple OSS Distributions PACK_2X32(VALUE(result), VALUE(fDriverCallReason)));
4326*0f4c859eSApple OSS Distributions
4327*0f4c859eSApple OSS Distributions deassertPMDriverCall(&callEntry);
4328*0f4c859eSApple OSS Distributions
4329*0f4c859eSApple OSS Distributions
4330*0f4c859eSApple OSS Distributions if ((result == IOPMAckImplied) || (result < 0)) {
4331*0f4c859eSApple OSS Distributions uint64_t nsec;
4332*0f4c859eSApple OSS Distributions
4333*0f4c859eSApple OSS Distributions SUB_ABSOLUTETIME(&end, &informee->startTime);
4334*0f4c859eSApple OSS Distributions absolutetime_to_nanoseconds(end, &nsec);
4335*0f4c859eSApple OSS Distributions if (nsec > gIOPMSetPowerStateLogNS) {
4336*0f4c859eSApple OSS Distributions getPMRootDomain()->pmStatsRecordApplicationResponse(
4337*0f4c859eSApple OSS Distributions gIOPMStatsDriverPSChangeSlow, driver->getName(),
4338*0f4c859eSApple OSS Distributions fDriverCallReason, NS_TO_MS(nsec), driver->getRegistryEntryID(),
4339*0f4c859eSApple OSS Distributions NULL, powerState);
4340*0f4c859eSApple OSS Distributions }
4341*0f4c859eSApple OSS Distributions }
4342*0f4c859eSApple OSS Distributions } else {
4343*0f4c859eSApple OSS Distributions result = kIOPMAckImplied;
4344*0f4c859eSApple OSS Distributions }
4345*0f4c859eSApple OSS Distributions
4346*0f4c859eSApple OSS Distributions param->Result = result;
4347*0f4c859eSApple OSS Distributions param++;
4348*0f4c859eSApple OSS Distributions }
4349*0f4c859eSApple OSS Distributions }
4350*0f4c859eSApple OSS Distributions
4351*0f4c859eSApple OSS Distributions //*********************************************************************************
4352*0f4c859eSApple OSS Distributions // [private, static] pmDriverCalloutTimer
4353*0f4c859eSApple OSS Distributions //
4354*0f4c859eSApple OSS Distributions // Thread call context.
4355*0f4c859eSApple OSS Distributions //*********************************************************************************
4356*0f4c859eSApple OSS Distributions
4357*0f4c859eSApple OSS Distributions void
startDriverCalloutTimer(void)4358*0f4c859eSApple OSS Distributions IOService::startDriverCalloutTimer( void )
4359*0f4c859eSApple OSS Distributions {
4360*0f4c859eSApple OSS Distributions AbsoluteTime deadline;
4361*0f4c859eSApple OSS Distributions boolean_t pending;
4362*0f4c859eSApple OSS Distributions
4363*0f4c859eSApple OSS Distributions clock_interval_to_deadline(gDriverCalloutTimer, kMillisecondScale, &deadline);
4364*0f4c859eSApple OSS Distributions
4365*0f4c859eSApple OSS Distributions retain();
4366*0f4c859eSApple OSS Distributions pending = thread_call_enter_delayed(fDriverCallTimer, deadline);
4367*0f4c859eSApple OSS Distributions if (pending) {
4368*0f4c859eSApple OSS Distributions release();
4369*0f4c859eSApple OSS Distributions }
4370*0f4c859eSApple OSS Distributions }
4371*0f4c859eSApple OSS Distributions
4372*0f4c859eSApple OSS Distributions void
stopDriverCalloutTimer(void)4373*0f4c859eSApple OSS Distributions IOService::stopDriverCalloutTimer( void )
4374*0f4c859eSApple OSS Distributions {
4375*0f4c859eSApple OSS Distributions boolean_t pending;
4376*0f4c859eSApple OSS Distributions
4377*0f4c859eSApple OSS Distributions pending = thread_call_cancel(fDriverCallTimer);
4378*0f4c859eSApple OSS Distributions if (pending) {
4379*0f4c859eSApple OSS Distributions release();
4380*0f4c859eSApple OSS Distributions }
4381*0f4c859eSApple OSS Distributions }
4382*0f4c859eSApple OSS Distributions
4383*0f4c859eSApple OSS Distributions void
pmDriverCalloutTimer(thread_call_param_t arg0,__unused thread_call_param_t arg1)4384*0f4c859eSApple OSS Distributions IOService::pmDriverCalloutTimer( thread_call_param_t arg0,
4385*0f4c859eSApple OSS Distributions __unused thread_call_param_t arg1)
4386*0f4c859eSApple OSS Distributions {
4387*0f4c859eSApple OSS Distributions assert(arg0);
4388*0f4c859eSApple OSS Distributions IOService *from = (IOService *) arg0;
4389*0f4c859eSApple OSS Distributions PM_LOG("PM waiting on pmDriverCallout(0x%x) to %s (%u ms)\n", from->fDriverCallReason, from->fName, gDriverCalloutTimer);
4390*0f4c859eSApple OSS Distributions from->release();
4391*0f4c859eSApple OSS Distributions }
4392*0f4c859eSApple OSS Distributions
4393*0f4c859eSApple OSS Distributions //*********************************************************************************
4394*0f4c859eSApple OSS Distributions // [private] notifyChild
4395*0f4c859eSApple OSS Distributions //
4396*0f4c859eSApple OSS Distributions // Notify a power domain child of an upcoming power change.
4397*0f4c859eSApple OSS Distributions // If the object acknowledges the current change, we return TRUE.
4398*0f4c859eSApple OSS Distributions //*********************************************************************************
4399*0f4c859eSApple OSS Distributions
4400*0f4c859eSApple OSS Distributions bool
notifyChild(IOPowerConnection * theNub)4401*0f4c859eSApple OSS Distributions IOService::notifyChild( IOPowerConnection * theNub )
4402*0f4c859eSApple OSS Distributions {
4403*0f4c859eSApple OSS Distributions IOReturn ret = IOPMAckImplied;
4404*0f4c859eSApple OSS Distributions unsigned long childPower;
4405*0f4c859eSApple OSS Distributions IOService * theChild;
4406*0f4c859eSApple OSS Distributions IOPMRequest * childRequest;
4407*0f4c859eSApple OSS Distributions IOPMPowerChangeFlags requestArg2;
4408*0f4c859eSApple OSS Distributions int requestType;
4409*0f4c859eSApple OSS Distributions
4410*0f4c859eSApple OSS Distributions PM_ASSERT_IN_GATE();
4411*0f4c859eSApple OSS Distributions theChild = (IOService *)(theNub->copyChildEntry(gIOPowerPlane));
4412*0f4c859eSApple OSS Distributions if (!theChild) {
4413*0f4c859eSApple OSS Distributions return true;
4414*0f4c859eSApple OSS Distributions }
4415*0f4c859eSApple OSS Distributions
4416*0f4c859eSApple OSS Distributions // Unless the child handles the notification immediately and returns
4417*0f4c859eSApple OSS Distributions // kIOPMAckImplied, we'll be awaiting their acknowledgement later.
4418*0f4c859eSApple OSS Distributions fHeadNotePendingAcks++;
4419*0f4c859eSApple OSS Distributions theNub->setAwaitingAck(true);
4420*0f4c859eSApple OSS Distributions
4421*0f4c859eSApple OSS Distributions requestArg2 = fHeadNoteChangeFlags;
4422*0f4c859eSApple OSS Distributions if (StateOrder(fHeadNotePowerState) < StateOrder(fCurrentPowerState)) {
4423*0f4c859eSApple OSS Distributions requestArg2 |= kIOPMDomainPowerDrop;
4424*0f4c859eSApple OSS Distributions }
4425*0f4c859eSApple OSS Distributions
4426*0f4c859eSApple OSS Distributions requestType = fIsPreChange ?
4427*0f4c859eSApple OSS Distributions kIOPMRequestTypePowerDomainWillChange :
4428*0f4c859eSApple OSS Distributions kIOPMRequestTypePowerDomainDidChange;
4429*0f4c859eSApple OSS Distributions
4430*0f4c859eSApple OSS Distributions childRequest = acquirePMRequest( theChild, requestType );
4431*0f4c859eSApple OSS Distributions if (childRequest) {
4432*0f4c859eSApple OSS Distributions theNub->retain();
4433*0f4c859eSApple OSS Distributions childRequest->fArg0 = (void *) fHeadNotePowerArrayEntry->outputPowerFlags;
4434*0f4c859eSApple OSS Distributions childRequest->fArg1 = (void *) theNub;
4435*0f4c859eSApple OSS Distributions childRequest->fArg2 = (void *)(uintptr_t) requestArg2;
4436*0f4c859eSApple OSS Distributions theChild->submitPMRequest( childRequest );
4437*0f4c859eSApple OSS Distributions ret = IOPMWillAckLater;
4438*0f4c859eSApple OSS Distributions } else {
4439*0f4c859eSApple OSS Distributions ret = IOPMAckImplied;
4440*0f4c859eSApple OSS Distributions fHeadNotePendingAcks--;
4441*0f4c859eSApple OSS Distributions theNub->setAwaitingAck(false);
4442*0f4c859eSApple OSS Distributions childPower = theChild->currentPowerConsumption();
4443*0f4c859eSApple OSS Distributions if (childPower == kIOPMUnknown) {
4444*0f4c859eSApple OSS Distributions fHeadNotePowerArrayEntry->staticPower = kIOPMUnknown;
4445*0f4c859eSApple OSS Distributions } else {
4446*0f4c859eSApple OSS Distributions if (fHeadNotePowerArrayEntry->staticPower != kIOPMUnknown) {
4447*0f4c859eSApple OSS Distributions fHeadNotePowerArrayEntry->staticPower += childPower;
4448*0f4c859eSApple OSS Distributions }
4449*0f4c859eSApple OSS Distributions }
4450*0f4c859eSApple OSS Distributions }
4451*0f4c859eSApple OSS Distributions
4452*0f4c859eSApple OSS Distributions theChild->release();
4453*0f4c859eSApple OSS Distributions return IOPMAckImplied == ret;
4454*0f4c859eSApple OSS Distributions }
4455*0f4c859eSApple OSS Distributions
4456*0f4c859eSApple OSS Distributions //*********************************************************************************
4457*0f4c859eSApple OSS Distributions // [private] notifyControllingDriver
4458*0f4c859eSApple OSS Distributions //*********************************************************************************
4459*0f4c859eSApple OSS Distributions
4460*0f4c859eSApple OSS Distributions bool
notifyControllingDriver(void)4461*0f4c859eSApple OSS Distributions IOService::notifyControllingDriver( void )
4462*0f4c859eSApple OSS Distributions {
4463*0f4c859eSApple OSS Distributions DriverCallParam * param;
4464*0f4c859eSApple OSS Distributions
4465*0f4c859eSApple OSS Distributions PM_ASSERT_IN_GATE();
4466*0f4c859eSApple OSS Distributions assert( fDriverCallParamCount == 0 );
4467*0f4c859eSApple OSS Distributions assert( fControllingDriver );
4468*0f4c859eSApple OSS Distributions
4469*0f4c859eSApple OSS Distributions if (fInitialSetPowerState) {
4470*0f4c859eSApple OSS Distributions fInitialSetPowerState = false;
4471*0f4c859eSApple OSS Distributions fHeadNoteChangeFlags |= kIOPMInitialPowerChange;
4472*0f4c859eSApple OSS Distributions
4473*0f4c859eSApple OSS Distributions // Driver specified flag to skip the inital setPowerState()
4474*0f4c859eSApple OSS Distributions if (fHeadNotePowerArrayEntry->capabilityFlags & kIOPMInitialDeviceState) {
4475*0f4c859eSApple OSS Distributions return false;
4476*0f4c859eSApple OSS Distributions }
4477*0f4c859eSApple OSS Distributions }
4478*0f4c859eSApple OSS Distributions
4479*0f4c859eSApple OSS Distributions param = (DriverCallParam *) fDriverCallParamPtr;
4480*0f4c859eSApple OSS Distributions if (!param) {
4481*0f4c859eSApple OSS Distributions param = IONew(DriverCallParam, 1);
4482*0f4c859eSApple OSS Distributions if (!param) {
4483*0f4c859eSApple OSS Distributions return false; // no memory
4484*0f4c859eSApple OSS Distributions }
4485*0f4c859eSApple OSS Distributions fDriverCallParamPtr = (void *) param;
4486*0f4c859eSApple OSS Distributions fDriverCallParamSlots = 1;
4487*0f4c859eSApple OSS Distributions }
4488*0f4c859eSApple OSS Distributions
4489*0f4c859eSApple OSS Distributions param->Target = fControllingDriver;
4490*0f4c859eSApple OSS Distributions fDriverCallParamCount = 1;
4491*0f4c859eSApple OSS Distributions fDriverTimer = -1;
4492*0f4c859eSApple OSS Distributions
4493*0f4c859eSApple OSS Distributions // Block state machine and wait for callout completion.
4494*0f4c859eSApple OSS Distributions assert(!fDriverCallBusy);
4495*0f4c859eSApple OSS Distributions fDriverCallBusy = true;
4496*0f4c859eSApple OSS Distributions thread_call_enter( fDriverCallEntry );
4497*0f4c859eSApple OSS Distributions
4498*0f4c859eSApple OSS Distributions return true;
4499*0f4c859eSApple OSS Distributions }
4500*0f4c859eSApple OSS Distributions
4501*0f4c859eSApple OSS Distributions //*********************************************************************************
4502*0f4c859eSApple OSS Distributions // [private] notifyControllingDriverDone
4503*0f4c859eSApple OSS Distributions //*********************************************************************************
4504*0f4c859eSApple OSS Distributions
4505*0f4c859eSApple OSS Distributions void
notifyControllingDriverDone(void)4506*0f4c859eSApple OSS Distributions IOService::notifyControllingDriverDone( void )
4507*0f4c859eSApple OSS Distributions {
4508*0f4c859eSApple OSS Distributions DriverCallParam * param;
4509*0f4c859eSApple OSS Distributions IOReturn result;
4510*0f4c859eSApple OSS Distributions
4511*0f4c859eSApple OSS Distributions PM_ASSERT_IN_GATE();
4512*0f4c859eSApple OSS Distributions param = (DriverCallParam *) fDriverCallParamPtr;
4513*0f4c859eSApple OSS Distributions
4514*0f4c859eSApple OSS Distributions assert( fDriverCallBusy == false );
4515*0f4c859eSApple OSS Distributions assert( fMachineState == kIOPM_DriverThreadCallDone );
4516*0f4c859eSApple OSS Distributions
4517*0f4c859eSApple OSS Distributions if (param && fDriverCallParamCount) {
4518*0f4c859eSApple OSS Distributions assert(fDriverCallParamCount == 1);
4519*0f4c859eSApple OSS Distributions
4520*0f4c859eSApple OSS Distributions // the return value from setPowerState()
4521*0f4c859eSApple OSS Distributions result = param->Result;
4522*0f4c859eSApple OSS Distributions
4523*0f4c859eSApple OSS Distributions if ((result == IOPMAckImplied) || (result < 0)) {
4524*0f4c859eSApple OSS Distributions fDriverTimer = 0;
4525*0f4c859eSApple OSS Distributions } else if (fDriverTimer) {
4526*0f4c859eSApple OSS Distributions assert(fDriverTimer == -1);
4527*0f4c859eSApple OSS Distributions
4528*0f4c859eSApple OSS Distributions // Driver has not acked, and has returned a positive result.
4529*0f4c859eSApple OSS Distributions // Enforce a minimum permissible timeout value.
4530*0f4c859eSApple OSS Distributions // Make the min value large enough so timeout is less likely
4531*0f4c859eSApple OSS Distributions // to occur if a driver misinterpreted that the return value
4532*0f4c859eSApple OSS Distributions // should be in microsecond units. And make it large enough
4533*0f4c859eSApple OSS Distributions // to be noticeable if a driver neglects to ack.
4534*0f4c859eSApple OSS Distributions
4535*0f4c859eSApple OSS Distributions if (result < kMinAckTimeoutTicks) {
4536*0f4c859eSApple OSS Distributions result = kMinAckTimeoutTicks;
4537*0f4c859eSApple OSS Distributions }
4538*0f4c859eSApple OSS Distributions
4539*0f4c859eSApple OSS Distributions fDriverTimer = (result / (ACK_TIMER_PERIOD / ns_per_us)) + 1;
4540*0f4c859eSApple OSS Distributions }
4541*0f4c859eSApple OSS Distributions // else, child has already acked and driver_timer reset to 0.
4542*0f4c859eSApple OSS Distributions
4543*0f4c859eSApple OSS Distributions fDriverCallParamCount = 0;
4544*0f4c859eSApple OSS Distributions
4545*0f4c859eSApple OSS Distributions if (fDriverTimer) {
4546*0f4c859eSApple OSS Distributions OUR_PMLog(kPMLogStartAckTimer, 0, 0);
4547*0f4c859eSApple OSS Distributions start_ack_timer();
4548*0f4c859eSApple OSS Distributions getPMRootDomain()->reset_watchdog_timer(this, result / USEC_PER_SEC + 1);
4549*0f4c859eSApple OSS Distributions }
4550*0f4c859eSApple OSS Distributions }
4551*0f4c859eSApple OSS Distributions
4552*0f4c859eSApple OSS Distributions MS_POP(); // pushed by OurChangeSetPowerState()
4553*0f4c859eSApple OSS Distributions fIsPreChange = false;
4554*0f4c859eSApple OSS Distributions }
4555*0f4c859eSApple OSS Distributions
4556*0f4c859eSApple OSS Distributions //*********************************************************************************
4557*0f4c859eSApple OSS Distributions // [private] all_done
4558*0f4c859eSApple OSS Distributions //
4559*0f4c859eSApple OSS Distributions // A power change is done.
4560*0f4c859eSApple OSS Distributions //*********************************************************************************
4561*0f4c859eSApple OSS Distributions
4562*0f4c859eSApple OSS Distributions void
all_done(void)4563*0f4c859eSApple OSS Distributions IOService::all_done( void )
4564*0f4c859eSApple OSS Distributions {
4565*0f4c859eSApple OSS Distributions IOPMPowerStateIndex prevPowerState;
4566*0f4c859eSApple OSS Distributions const IOPMPSEntry * powerStatePtr;
4567*0f4c859eSApple OSS Distributions IOPMDriverCallEntry callEntry;
4568*0f4c859eSApple OSS Distributions uint32_t prevMachineState = fMachineState;
4569*0f4c859eSApple OSS Distributions bool actionCalled = false;
4570*0f4c859eSApple OSS Distributions uint64_t ts;
4571*0f4c859eSApple OSS Distributions
4572*0f4c859eSApple OSS Distributions fMachineState = kIOPM_Finished;
4573*0f4c859eSApple OSS Distributions
4574*0f4c859eSApple OSS Distributions if ((fHeadNoteChangeFlags & kIOPMSynchronize) &&
4575*0f4c859eSApple OSS Distributions ((prevMachineState == kIOPM_Finished) ||
4576*0f4c859eSApple OSS Distributions (prevMachineState == kIOPM_SyncFinish))) {
4577*0f4c859eSApple OSS Distributions // Sync operation and no power change occurred.
4578*0f4c859eSApple OSS Distributions // Do not inform driver and clients about this request completion,
4579*0f4c859eSApple OSS Distributions // except for the originator (root domain).
4580*0f4c859eSApple OSS Distributions
4581*0f4c859eSApple OSS Distributions PM_ACTION_CHANGE(actionPowerChangeDone,
4582*0f4c859eSApple OSS Distributions fHeadNotePowerState, fHeadNoteChangeFlags);
4583*0f4c859eSApple OSS Distributions
4584*0f4c859eSApple OSS Distributions if (getPMRequestType() == kIOPMRequestTypeSynchronizePowerTree) {
4585*0f4c859eSApple OSS Distributions powerChangeDone(fCurrentPowerState);
4586*0f4c859eSApple OSS Distributions } else if (fAdvisoryTickleUsed) {
4587*0f4c859eSApple OSS Distributions // Not root domain and advisory tickle target.
4588*0f4c859eSApple OSS Distributions // Re-adjust power after power tree sync at the 'did' pass
4589*0f4c859eSApple OSS Distributions // to recompute desire and adjust power state between dark
4590*0f4c859eSApple OSS Distributions // and full wake transitions. Root domain is responsible
4591*0f4c859eSApple OSS Distributions // for calling setAdvisoryTickleEnable() before starting
4592*0f4c859eSApple OSS Distributions // the kIOPMSynchronize power change.
4593*0f4c859eSApple OSS Distributions
4594*0f4c859eSApple OSS Distributions if (!fAdjustPowerScheduled &&
4595*0f4c859eSApple OSS Distributions (fHeadNoteChangeFlags & kIOPMDomainDidChange)) {
4596*0f4c859eSApple OSS Distributions IOPMRequest * request;
4597*0f4c859eSApple OSS Distributions request = acquirePMRequest( this, kIOPMRequestTypeAdjustPowerState );
4598*0f4c859eSApple OSS Distributions if (request) {
4599*0f4c859eSApple OSS Distributions submitPMRequest( request );
4600*0f4c859eSApple OSS Distributions fAdjustPowerScheduled = true;
4601*0f4c859eSApple OSS Distributions }
4602*0f4c859eSApple OSS Distributions }
4603*0f4c859eSApple OSS Distributions }
4604*0f4c859eSApple OSS Distributions
4605*0f4c859eSApple OSS Distributions return;
4606*0f4c859eSApple OSS Distributions }
4607*0f4c859eSApple OSS Distributions
4608*0f4c859eSApple OSS Distributions // our power change
4609*0f4c859eSApple OSS Distributions if (fHeadNoteChangeFlags & kIOPMSelfInitiated) {
4610*0f4c859eSApple OSS Distributions // power state changed
4611*0f4c859eSApple OSS Distributions if ((fHeadNoteChangeFlags & kIOPMNotDone) == 0) {
4612*0f4c859eSApple OSS Distributions trackSystemSleepPreventers(
4613*0f4c859eSApple OSS Distributions fCurrentPowerState, fHeadNotePowerState, fHeadNoteChangeFlags);
4614*0f4c859eSApple OSS Distributions
4615*0f4c859eSApple OSS Distributions // we changed, tell our parent
4616*0f4c859eSApple OSS Distributions requestDomainPower(fHeadNotePowerState);
4617*0f4c859eSApple OSS Distributions
4618*0f4c859eSApple OSS Distributions // yes, did power raise?
4619*0f4c859eSApple OSS Distributions if (StateOrder(fCurrentPowerState) < StateOrder(fHeadNotePowerState)) {
4620*0f4c859eSApple OSS Distributions // yes, inform clients and apps
4621*0f4c859eSApple OSS Distributions tellChangeUp(fHeadNotePowerState);
4622*0f4c859eSApple OSS Distributions }
4623*0f4c859eSApple OSS Distributions prevPowerState = fCurrentPowerState;
4624*0f4c859eSApple OSS Distributions // either way
4625*0f4c859eSApple OSS Distributions fCurrentPowerState = fHeadNotePowerState;
4626*0f4c859eSApple OSS Distributions PM_LOCK();
4627*0f4c859eSApple OSS Distributions if (fReportBuf) {
4628*0f4c859eSApple OSS Distributions ts = mach_absolute_time();
4629*0f4c859eSApple OSS Distributions STATEREPORT_SETSTATE(fReportBuf, (uint16_t) fCurrentPowerState, ts);
4630*0f4c859eSApple OSS Distributions }
4631*0f4c859eSApple OSS Distributions PM_UNLOCK();
4632*0f4c859eSApple OSS Distributions #if PM_VARS_SUPPORT
4633*0f4c859eSApple OSS Distributions fPMVars->myCurrentState = fCurrentPowerState;
4634*0f4c859eSApple OSS Distributions #endif
4635*0f4c859eSApple OSS Distributions OUR_PMLog(kPMLogChangeDone, fCurrentPowerState, prevPowerState);
4636*0f4c859eSApple OSS Distributions PM_ACTION_CHANGE(actionPowerChangeDone,
4637*0f4c859eSApple OSS Distributions prevPowerState, fHeadNoteChangeFlags);
4638*0f4c859eSApple OSS Distributions actionCalled = true;
4639*0f4c859eSApple OSS Distributions
4640*0f4c859eSApple OSS Distributions powerStatePtr = &fPowerStates[fCurrentPowerState];
4641*0f4c859eSApple OSS Distributions fCurrentCapabilityFlags = powerStatePtr->capabilityFlags;
4642*0f4c859eSApple OSS Distributions if (fCurrentCapabilityFlags & kIOPMStaticPowerValid) {
4643*0f4c859eSApple OSS Distributions fCurrentPowerConsumption = powerStatePtr->staticPower;
4644*0f4c859eSApple OSS Distributions }
4645*0f4c859eSApple OSS Distributions
4646*0f4c859eSApple OSS Distributions if (fHeadNoteChangeFlags & kIOPMRootChangeDown) {
4647*0f4c859eSApple OSS Distributions // Bump tickle generation count once the entire tree is down
4648*0f4c859eSApple OSS Distributions gIOPMTickleGeneration++;
4649*0f4c859eSApple OSS Distributions }
4650*0f4c859eSApple OSS Distributions
4651*0f4c859eSApple OSS Distributions // inform subclass policy-maker
4652*0f4c859eSApple OSS Distributions if (fPCDFunctionOverride && fParentsKnowState &&
4653*0f4c859eSApple OSS Distributions assertPMDriverCall(&callEntry, kIOPMDriverCallMethodChangeDone, NULL, kIOPMDriverCallNoInactiveCheck)) {
4654*0f4c859eSApple OSS Distributions powerChangeDone(prevPowerState);
4655*0f4c859eSApple OSS Distributions deassertPMDriverCall(&callEntry);
4656*0f4c859eSApple OSS Distributions }
4657*0f4c859eSApple OSS Distributions } else if (getPMRequestType() == kIOPMRequestTypeRequestPowerStateOverride) {
4658*0f4c859eSApple OSS Distributions // changePowerStateWithOverrideTo() was cancelled
4659*0f4c859eSApple OSS Distributions fOverrideMaxPowerState = kIOPMPowerStateMax;
4660*0f4c859eSApple OSS Distributions }
4661*0f4c859eSApple OSS Distributions }
4662*0f4c859eSApple OSS Distributions
4663*0f4c859eSApple OSS Distributions // parent-initiated power change
4664*0f4c859eSApple OSS Distributions if (fHeadNoteChangeFlags & kIOPMParentInitiated) {
4665*0f4c859eSApple OSS Distributions if (fHeadNoteChangeFlags & kIOPMRootChangeDown) {
4666*0f4c859eSApple OSS Distributions ParentChangeRootChangeDown();
4667*0f4c859eSApple OSS Distributions }
4668*0f4c859eSApple OSS Distributions
4669*0f4c859eSApple OSS Distributions // power state changed
4670*0f4c859eSApple OSS Distributions if ((fHeadNoteChangeFlags & kIOPMNotDone) == 0) {
4671*0f4c859eSApple OSS Distributions trackSystemSleepPreventers(
4672*0f4c859eSApple OSS Distributions fCurrentPowerState, fHeadNotePowerState, fHeadNoteChangeFlags);
4673*0f4c859eSApple OSS Distributions
4674*0f4c859eSApple OSS Distributions // did power raise?
4675*0f4c859eSApple OSS Distributions if (StateOrder(fCurrentPowerState) < StateOrder(fHeadNotePowerState)) {
4676*0f4c859eSApple OSS Distributions // yes, inform clients and apps
4677*0f4c859eSApple OSS Distributions tellChangeUp(fHeadNotePowerState);
4678*0f4c859eSApple OSS Distributions }
4679*0f4c859eSApple OSS Distributions // either way
4680*0f4c859eSApple OSS Distributions prevPowerState = fCurrentPowerState;
4681*0f4c859eSApple OSS Distributions fCurrentPowerState = fHeadNotePowerState;
4682*0f4c859eSApple OSS Distributions PM_LOCK();
4683*0f4c859eSApple OSS Distributions if (fReportBuf) {
4684*0f4c859eSApple OSS Distributions ts = mach_absolute_time();
4685*0f4c859eSApple OSS Distributions STATEREPORT_SETSTATE(fReportBuf, (uint16_t) fCurrentPowerState, ts);
4686*0f4c859eSApple OSS Distributions }
4687*0f4c859eSApple OSS Distributions PM_UNLOCK();
4688*0f4c859eSApple OSS Distributions #if PM_VARS_SUPPORT
4689*0f4c859eSApple OSS Distributions fPMVars->myCurrentState = fCurrentPowerState;
4690*0f4c859eSApple OSS Distributions #endif
4691*0f4c859eSApple OSS Distributions
4692*0f4c859eSApple OSS Distributions OUR_PMLog(kPMLogChangeDone, fCurrentPowerState, prevPowerState);
4693*0f4c859eSApple OSS Distributions PM_ACTION_CHANGE(actionPowerChangeDone,
4694*0f4c859eSApple OSS Distributions prevPowerState, fHeadNoteChangeFlags);
4695*0f4c859eSApple OSS Distributions actionCalled = true;
4696*0f4c859eSApple OSS Distributions
4697*0f4c859eSApple OSS Distributions powerStatePtr = &fPowerStates[fCurrentPowerState];
4698*0f4c859eSApple OSS Distributions fCurrentCapabilityFlags = powerStatePtr->capabilityFlags;
4699*0f4c859eSApple OSS Distributions if (fCurrentCapabilityFlags & kIOPMStaticPowerValid) {
4700*0f4c859eSApple OSS Distributions fCurrentPowerConsumption = powerStatePtr->staticPower;
4701*0f4c859eSApple OSS Distributions }
4702*0f4c859eSApple OSS Distributions
4703*0f4c859eSApple OSS Distributions // inform subclass policy-maker
4704*0f4c859eSApple OSS Distributions if (fPCDFunctionOverride && fParentsKnowState &&
4705*0f4c859eSApple OSS Distributions assertPMDriverCall(&callEntry, kIOPMDriverCallMethodChangeDone, NULL, kIOPMDriverCallNoInactiveCheck)) {
4706*0f4c859eSApple OSS Distributions powerChangeDone(prevPowerState);
4707*0f4c859eSApple OSS Distributions deassertPMDriverCall(&callEntry);
4708*0f4c859eSApple OSS Distributions }
4709*0f4c859eSApple OSS Distributions }
4710*0f4c859eSApple OSS Distributions }
4711*0f4c859eSApple OSS Distributions
4712*0f4c859eSApple OSS Distributions // When power rises enough to satisfy the tickle's desire for more power,
4713*0f4c859eSApple OSS Distributions // the condition preventing idle-timer from dropping power is removed.
4714*0f4c859eSApple OSS Distributions
4715*0f4c859eSApple OSS Distributions if (StateOrder(fCurrentPowerState) >= StateOrder(fIdleTimerMinPowerState)) {
4716*0f4c859eSApple OSS Distributions fIdleTimerMinPowerState = kPowerStateZero;
4717*0f4c859eSApple OSS Distributions }
4718*0f4c859eSApple OSS Distributions
4719*0f4c859eSApple OSS Distributions if (!actionCalled) {
4720*0f4c859eSApple OSS Distributions PM_ACTION_CHANGE(actionPowerChangeDone,
4721*0f4c859eSApple OSS Distributions fHeadNotePowerState, fHeadNoteChangeFlags);
4722*0f4c859eSApple OSS Distributions }
4723*0f4c859eSApple OSS Distributions }
4724*0f4c859eSApple OSS Distributions
4725*0f4c859eSApple OSS Distributions // MARK: -
4726*0f4c859eSApple OSS Distributions // MARK: Power Change Initiated by Driver
4727*0f4c859eSApple OSS Distributions
4728*0f4c859eSApple OSS Distributions //*********************************************************************************
4729*0f4c859eSApple OSS Distributions // [private] OurChangeStart
4730*0f4c859eSApple OSS Distributions //
4731*0f4c859eSApple OSS Distributions // Begin the processing of a power change initiated by us.
4732*0f4c859eSApple OSS Distributions //*********************************************************************************
4733*0f4c859eSApple OSS Distributions
4734*0f4c859eSApple OSS Distributions void
OurChangeStart(void)4735*0f4c859eSApple OSS Distributions IOService::OurChangeStart( void )
4736*0f4c859eSApple OSS Distributions {
4737*0f4c859eSApple OSS Distributions PM_ASSERT_IN_GATE();
4738*0f4c859eSApple OSS Distributions OUR_PMLog( kPMLogStartDeviceChange, fHeadNotePowerState, fCurrentPowerState );
4739*0f4c859eSApple OSS Distributions
4740*0f4c859eSApple OSS Distributions // fMaxPowerState is our maximum possible power state based on the current
4741*0f4c859eSApple OSS Distributions // power state of our parents. If we are trying to raise power beyond the
4742*0f4c859eSApple OSS Distributions // maximum, send an async request for more power to all parents.
4743*0f4c859eSApple OSS Distributions
4744*0f4c859eSApple OSS Distributions if (!IS_PM_ROOT && (StateOrder(fMaxPowerState) < StateOrder(fHeadNotePowerState))) {
4745*0f4c859eSApple OSS Distributions fHeadNoteChangeFlags |= kIOPMNotDone;
4746*0f4c859eSApple OSS Distributions requestDomainPower(fHeadNotePowerState);
4747*0f4c859eSApple OSS Distributions OurChangeFinish();
4748*0f4c859eSApple OSS Distributions return;
4749*0f4c859eSApple OSS Distributions }
4750*0f4c859eSApple OSS Distributions
4751*0f4c859eSApple OSS Distributions // Redundant power changes skips to the end of the state machine.
4752*0f4c859eSApple OSS Distributions
4753*0f4c859eSApple OSS Distributions if (!fInitialPowerChange && (fHeadNotePowerState == fCurrentPowerState)) {
4754*0f4c859eSApple OSS Distributions OurChangeFinish();
4755*0f4c859eSApple OSS Distributions return;
4756*0f4c859eSApple OSS Distributions }
4757*0f4c859eSApple OSS Distributions fInitialPowerChange = false;
4758*0f4c859eSApple OSS Distributions
4759*0f4c859eSApple OSS Distributions // Change started, but may not complete...
4760*0f4c859eSApple OSS Distributions // Can be canceled (power drop) or deferred (power rise).
4761*0f4c859eSApple OSS Distributions
4762*0f4c859eSApple OSS Distributions PM_ACTION_CHANGE(actionPowerChangeStart, fHeadNotePowerState, &fHeadNoteChangeFlags);
4763*0f4c859eSApple OSS Distributions
4764*0f4c859eSApple OSS Distributions // Two separate paths, depending if power is being raised or lowered.
4765*0f4c859eSApple OSS Distributions // Lowering power is subject to approval by clients of this service.
4766*0f4c859eSApple OSS Distributions
4767*0f4c859eSApple OSS Distributions if (IS_POWER_DROP) {
4768*0f4c859eSApple OSS Distributions fDoNotPowerDown = false;
4769*0f4c859eSApple OSS Distributions
4770*0f4c859eSApple OSS Distributions // Ask for persmission to drop power state
4771*0f4c859eSApple OSS Distributions fMachineState = kIOPM_OurChangeTellClientsPowerDown;
4772*0f4c859eSApple OSS Distributions fOutOfBandParameter = kNotifyApps;
4773*0f4c859eSApple OSS Distributions askChangeDown(fHeadNotePowerState);
4774*0f4c859eSApple OSS Distributions } else {
4775*0f4c859eSApple OSS Distributions // This service is raising power and parents are able to support the
4776*0f4c859eSApple OSS Distributions // new power state. However a parent may have already committed to
4777*0f4c859eSApple OSS Distributions // drop power, which might force this object to temporarily drop power.
4778*0f4c859eSApple OSS Distributions // This results in "oscillations" before the state machines converge
4779*0f4c859eSApple OSS Distributions // to a steady state.
4780*0f4c859eSApple OSS Distributions //
4781*0f4c859eSApple OSS Distributions // To prevent this, a child must make a power reservation against all
4782*0f4c859eSApple OSS Distributions // parents before raising power. If the reservation fails, indicating
4783*0f4c859eSApple OSS Distributions // that the child will be unable to sustain the higher power state,
4784*0f4c859eSApple OSS Distributions // then the child will signal the parent to adjust power, and the child
4785*0f4c859eSApple OSS Distributions // will defer its power change.
4786*0f4c859eSApple OSS Distributions
4787*0f4c859eSApple OSS Distributions IOReturn ret;
4788*0f4c859eSApple OSS Distributions
4789*0f4c859eSApple OSS Distributions // Reserve parent power necessary to achieve fHeadNotePowerState.
4790*0f4c859eSApple OSS Distributions ret = requestDomainPower( fHeadNotePowerState, kReserveDomainPower );
4791*0f4c859eSApple OSS Distributions if (ret != kIOReturnSuccess) {
4792*0f4c859eSApple OSS Distributions // Reservation failed, defer power rise.
4793*0f4c859eSApple OSS Distributions fHeadNoteChangeFlags |= kIOPMNotDone;
4794*0f4c859eSApple OSS Distributions OurChangeFinish();
4795*0f4c859eSApple OSS Distributions return;
4796*0f4c859eSApple OSS Distributions }
4797*0f4c859eSApple OSS Distributions
4798*0f4c859eSApple OSS Distributions OurChangeTellCapabilityWillChange();
4799*0f4c859eSApple OSS Distributions }
4800*0f4c859eSApple OSS Distributions }
4801*0f4c859eSApple OSS Distributions
4802*0f4c859eSApple OSS Distributions //*********************************************************************************
4803*0f4c859eSApple OSS Distributions // [private] requestDomainPowerApplier
4804*0f4c859eSApple OSS Distributions //
4805*0f4c859eSApple OSS Distributions // Call requestPowerDomainState() on all power parents.
4806*0f4c859eSApple OSS Distributions //*********************************************************************************
4807*0f4c859eSApple OSS Distributions
4808*0f4c859eSApple OSS Distributions struct IOPMRequestDomainPowerContext {
4809*0f4c859eSApple OSS Distributions IOService * child; // the requesting child
4810*0f4c859eSApple OSS Distributions IOPMPowerFlags requestPowerFlags;// power flags requested by child
4811*0f4c859eSApple OSS Distributions };
4812*0f4c859eSApple OSS Distributions
4813*0f4c859eSApple OSS Distributions static void
requestDomainPowerApplier(IORegistryEntry * entry,void * inContext)4814*0f4c859eSApple OSS Distributions requestDomainPowerApplier(
4815*0f4c859eSApple OSS Distributions IORegistryEntry * entry,
4816*0f4c859eSApple OSS Distributions void * inContext )
4817*0f4c859eSApple OSS Distributions {
4818*0f4c859eSApple OSS Distributions IOPowerConnection * connection;
4819*0f4c859eSApple OSS Distributions IOService * parent;
4820*0f4c859eSApple OSS Distributions IOPMRequestDomainPowerContext * context;
4821*0f4c859eSApple OSS Distributions
4822*0f4c859eSApple OSS Distributions if ((connection = OSDynamicCast(IOPowerConnection, entry)) == NULL) {
4823*0f4c859eSApple OSS Distributions return;
4824*0f4c859eSApple OSS Distributions }
4825*0f4c859eSApple OSS Distributions parent = (IOService *) connection->copyParentEntry(gIOPowerPlane);
4826*0f4c859eSApple OSS Distributions if (!parent) {
4827*0f4c859eSApple OSS Distributions return;
4828*0f4c859eSApple OSS Distributions }
4829*0f4c859eSApple OSS Distributions
4830*0f4c859eSApple OSS Distributions assert(inContext);
4831*0f4c859eSApple OSS Distributions context = (IOPMRequestDomainPowerContext *) inContext;
4832*0f4c859eSApple OSS Distributions
4833*0f4c859eSApple OSS Distributions if (connection->parentKnowsState() && connection->getReadyFlag()) {
4834*0f4c859eSApple OSS Distributions parent->requestPowerDomainState(
4835*0f4c859eSApple OSS Distributions context->requestPowerFlags,
4836*0f4c859eSApple OSS Distributions connection,
4837*0f4c859eSApple OSS Distributions IOPMLowestState);
4838*0f4c859eSApple OSS Distributions }
4839*0f4c859eSApple OSS Distributions
4840*0f4c859eSApple OSS Distributions parent->release();
4841*0f4c859eSApple OSS Distributions }
4842*0f4c859eSApple OSS Distributions
4843*0f4c859eSApple OSS Distributions //*********************************************************************************
4844*0f4c859eSApple OSS Distributions // [private] requestDomainPower
4845*0f4c859eSApple OSS Distributions //
4846*0f4c859eSApple OSS Distributions // Called by a power child to broadcast its desired power state to all parents.
4847*0f4c859eSApple OSS Distributions // If the child self-initiates a power change, it must call this function to
4848*0f4c859eSApple OSS Distributions // allow its parents to adjust power state.
4849*0f4c859eSApple OSS Distributions //*********************************************************************************
4850*0f4c859eSApple OSS Distributions
4851*0f4c859eSApple OSS Distributions IOReturn
requestDomainPower(IOPMPowerStateIndex ourPowerState,IOOptionBits options)4852*0f4c859eSApple OSS Distributions IOService::requestDomainPower(
4853*0f4c859eSApple OSS Distributions IOPMPowerStateIndex ourPowerState,
4854*0f4c859eSApple OSS Distributions IOOptionBits options )
4855*0f4c859eSApple OSS Distributions {
4856*0f4c859eSApple OSS Distributions IOPMPowerFlags requestPowerFlags;
4857*0f4c859eSApple OSS Distributions IOPMPowerStateIndex maxPowerState;
4858*0f4c859eSApple OSS Distributions IOPMRequestDomainPowerContext context;
4859*0f4c859eSApple OSS Distributions
4860*0f4c859eSApple OSS Distributions PM_ASSERT_IN_GATE();
4861*0f4c859eSApple OSS Distributions assert(ourPowerState < fNumberOfPowerStates);
4862*0f4c859eSApple OSS Distributions if (ourPowerState >= fNumberOfPowerStates) {
4863*0f4c859eSApple OSS Distributions return kIOReturnBadArgument;
4864*0f4c859eSApple OSS Distributions }
4865*0f4c859eSApple OSS Distributions if (IS_PM_ROOT) {
4866*0f4c859eSApple OSS Distributions return kIOReturnSuccess;
4867*0f4c859eSApple OSS Distributions }
4868*0f4c859eSApple OSS Distributions
4869*0f4c859eSApple OSS Distributions // Fetch our input power flags for the requested power state.
4870*0f4c859eSApple OSS Distributions // Parent request is stated in terms of required power flags.
4871*0f4c859eSApple OSS Distributions
4872*0f4c859eSApple OSS Distributions requestPowerFlags = fPowerStates[ourPowerState].inputPowerFlags;
4873*0f4c859eSApple OSS Distributions
4874*0f4c859eSApple OSS Distributions // Disregard the "previous request" for power reservation.
4875*0f4c859eSApple OSS Distributions
4876*0f4c859eSApple OSS Distributions if (((options & kReserveDomainPower) == 0) &&
4877*0f4c859eSApple OSS Distributions (fPreviousRequestPowerFlags == requestPowerFlags)) {
4878*0f4c859eSApple OSS Distributions // skip if domain already knows our requirements
4879*0f4c859eSApple OSS Distributions goto done;
4880*0f4c859eSApple OSS Distributions }
4881*0f4c859eSApple OSS Distributions fPreviousRequestPowerFlags = requestPowerFlags;
4882*0f4c859eSApple OSS Distributions
4883*0f4c859eSApple OSS Distributions // The results will be collected by fHeadNoteDomainTargetFlags
4884*0f4c859eSApple OSS Distributions context.child = this;
4885*0f4c859eSApple OSS Distributions context.requestPowerFlags = requestPowerFlags;
4886*0f4c859eSApple OSS Distributions fHeadNoteDomainTargetFlags = 0;
4887*0f4c859eSApple OSS Distributions applyToParents(requestDomainPowerApplier, &context, gIOPowerPlane);
4888*0f4c859eSApple OSS Distributions
4889*0f4c859eSApple OSS Distributions if (options & kReserveDomainPower) {
4890*0f4c859eSApple OSS Distributions maxPowerState = fControllingDriver->maxCapabilityForDomainState(
4891*0f4c859eSApple OSS Distributions fHeadNoteDomainTargetFlags );
4892*0f4c859eSApple OSS Distributions
4893*0f4c859eSApple OSS Distributions if (StateOrder(maxPowerState) < StateOrder(ourPowerState)) {
4894*0f4c859eSApple OSS Distributions PM_LOG1("%s: power desired %u:0x%x got %u:0x%x\n",
4895*0f4c859eSApple OSS Distributions getName(),
4896*0f4c859eSApple OSS Distributions (uint32_t) ourPowerState, (uint32_t) requestPowerFlags,
4897*0f4c859eSApple OSS Distributions (uint32_t) maxPowerState, (uint32_t) fHeadNoteDomainTargetFlags);
4898*0f4c859eSApple OSS Distributions return kIOReturnNoPower;
4899*0f4c859eSApple OSS Distributions }
4900*0f4c859eSApple OSS Distributions }
4901*0f4c859eSApple OSS Distributions
4902*0f4c859eSApple OSS Distributions done:
4903*0f4c859eSApple OSS Distributions return kIOReturnSuccess;
4904*0f4c859eSApple OSS Distributions }
4905*0f4c859eSApple OSS Distributions
4906*0f4c859eSApple OSS Distributions //*********************************************************************************
4907*0f4c859eSApple OSS Distributions // [private] OurSyncStart
4908*0f4c859eSApple OSS Distributions //*********************************************************************************
4909*0f4c859eSApple OSS Distributions
4910*0f4c859eSApple OSS Distributions void
OurSyncStart(void)4911*0f4c859eSApple OSS Distributions IOService::OurSyncStart( void )
4912*0f4c859eSApple OSS Distributions {
4913*0f4c859eSApple OSS Distributions PM_ASSERT_IN_GATE();
4914*0f4c859eSApple OSS Distributions
4915*0f4c859eSApple OSS Distributions if (fInitialPowerChange) {
4916*0f4c859eSApple OSS Distributions return;
4917*0f4c859eSApple OSS Distributions }
4918*0f4c859eSApple OSS Distributions
4919*0f4c859eSApple OSS Distributions PM_ACTION_CHANGE(actionPowerChangeStart, fHeadNotePowerState, &fHeadNoteChangeFlags);
4920*0f4c859eSApple OSS Distributions
4921*0f4c859eSApple OSS Distributions if (fHeadNoteChangeFlags & kIOPMNotDone) {
4922*0f4c859eSApple OSS Distributions OurChangeFinish();
4923*0f4c859eSApple OSS Distributions return;
4924*0f4c859eSApple OSS Distributions }
4925*0f4c859eSApple OSS Distributions
4926*0f4c859eSApple OSS Distributions if (fHeadNoteChangeFlags & kIOPMSyncTellPowerDown) {
4927*0f4c859eSApple OSS Distributions fDoNotPowerDown = false;
4928*0f4c859eSApple OSS Distributions
4929*0f4c859eSApple OSS Distributions // Ask for permission to drop power state
4930*0f4c859eSApple OSS Distributions fMachineState = kIOPM_SyncTellClientsPowerDown;
4931*0f4c859eSApple OSS Distributions fOutOfBandParameter = kNotifyApps;
4932*0f4c859eSApple OSS Distributions askChangeDown(fHeadNotePowerState);
4933*0f4c859eSApple OSS Distributions } else {
4934*0f4c859eSApple OSS Distributions // Only inform capability app and clients.
4935*0f4c859eSApple OSS Distributions tellSystemCapabilityChange( kIOPM_SyncNotifyWillChange );
4936*0f4c859eSApple OSS Distributions }
4937*0f4c859eSApple OSS Distributions }
4938*0f4c859eSApple OSS Distributions
4939*0f4c859eSApple OSS Distributions //*********************************************************************************
4940*0f4c859eSApple OSS Distributions // [private] OurChangeTellClientsPowerDown
4941*0f4c859eSApple OSS Distributions //
4942*0f4c859eSApple OSS Distributions // All applications and kernel clients have acknowledged our permission to drop
4943*0f4c859eSApple OSS Distributions // power. Here we notify them that we will lower the power and wait for acks.
4944*0f4c859eSApple OSS Distributions //*********************************************************************************
4945*0f4c859eSApple OSS Distributions
4946*0f4c859eSApple OSS Distributions void
OurChangeTellClientsPowerDown(void)4947*0f4c859eSApple OSS Distributions IOService::OurChangeTellClientsPowerDown( void )
4948*0f4c859eSApple OSS Distributions {
4949*0f4c859eSApple OSS Distributions if (!IS_ROOT_DOMAIN) {
4950*0f4c859eSApple OSS Distributions fMachineState = kIOPM_OurChangeTellPriorityClientsPowerDown;
4951*0f4c859eSApple OSS Distributions } else {
4952*0f4c859eSApple OSS Distributions fMachineState = kIOPM_OurChangeTellUserPMPolicyPowerDown;
4953*0f4c859eSApple OSS Distributions }
4954*0f4c859eSApple OSS Distributions tellChangeDown1(fHeadNotePowerState);
4955*0f4c859eSApple OSS Distributions }
4956*0f4c859eSApple OSS Distributions
4957*0f4c859eSApple OSS Distributions //*********************************************************************************
4958*0f4c859eSApple OSS Distributions // [private] OurChangeTellUserPMPolicyPowerDown
4959*0f4c859eSApple OSS Distributions //
4960*0f4c859eSApple OSS Distributions // All applications and kernel clients have acknowledged our permission to drop
4961*0f4c859eSApple OSS Distributions // power. Here we notify power management policy in user-space and wait for acks
4962*0f4c859eSApple OSS Distributions // one last time before we lower power
4963*0f4c859eSApple OSS Distributions //*********************************************************************************
4964*0f4c859eSApple OSS Distributions void
OurChangeTellUserPMPolicyPowerDown(void)4965*0f4c859eSApple OSS Distributions IOService::OurChangeTellUserPMPolicyPowerDown( void )
4966*0f4c859eSApple OSS Distributions {
4967*0f4c859eSApple OSS Distributions fMachineState = kIOPM_OurChangeTellPriorityClientsPowerDown;
4968*0f4c859eSApple OSS Distributions fOutOfBandParameter = kNotifyApps;
4969*0f4c859eSApple OSS Distributions
4970*0f4c859eSApple OSS Distributions tellClientsWithResponse(kIOPMMessageLastCallBeforeSleep);
4971*0f4c859eSApple OSS Distributions }
4972*0f4c859eSApple OSS Distributions
4973*0f4c859eSApple OSS Distributions //*********************************************************************************
4974*0f4c859eSApple OSS Distributions // [private] OurChangeTellPriorityClientsPowerDown
4975*0f4c859eSApple OSS Distributions //
4976*0f4c859eSApple OSS Distributions // All applications and kernel clients have acknowledged our intention to drop
4977*0f4c859eSApple OSS Distributions // power. Here we notify "priority" clients that we are lowering power.
4978*0f4c859eSApple OSS Distributions //*********************************************************************************
4979*0f4c859eSApple OSS Distributions
4980*0f4c859eSApple OSS Distributions void
OurChangeTellPriorityClientsPowerDown(void)4981*0f4c859eSApple OSS Distributions IOService::OurChangeTellPriorityClientsPowerDown( void )
4982*0f4c859eSApple OSS Distributions {
4983*0f4c859eSApple OSS Distributions fMachineState = kIOPM_OurChangeNotifyInterestedDriversWillChange;
4984*0f4c859eSApple OSS Distributions tellChangeDown2(fHeadNotePowerState);
4985*0f4c859eSApple OSS Distributions }
4986*0f4c859eSApple OSS Distributions
4987*0f4c859eSApple OSS Distributions //*********************************************************************************
4988*0f4c859eSApple OSS Distributions // [private] OurChangeTellCapabilityWillChange
4989*0f4c859eSApple OSS Distributions //
4990*0f4c859eSApple OSS Distributions // Extra stage for root domain to notify apps and drivers about the
4991*0f4c859eSApple OSS Distributions // system capability change when raising power state.
4992*0f4c859eSApple OSS Distributions //*********************************************************************************
4993*0f4c859eSApple OSS Distributions
4994*0f4c859eSApple OSS Distributions void
OurChangeTellCapabilityWillChange(void)4995*0f4c859eSApple OSS Distributions IOService::OurChangeTellCapabilityWillChange( void )
4996*0f4c859eSApple OSS Distributions {
4997*0f4c859eSApple OSS Distributions if (!IS_ROOT_DOMAIN) {
4998*0f4c859eSApple OSS Distributions return OurChangeNotifyInterestedDriversWillChange();
4999*0f4c859eSApple OSS Distributions }
5000*0f4c859eSApple OSS Distributions
5001*0f4c859eSApple OSS Distributions tellSystemCapabilityChange( kIOPM_OurChangeNotifyInterestedDriversWillChange );
5002*0f4c859eSApple OSS Distributions }
5003*0f4c859eSApple OSS Distributions
5004*0f4c859eSApple OSS Distributions //*********************************************************************************
5005*0f4c859eSApple OSS Distributions // [private] OurChangeNotifyInterestedDriversWillChange
5006*0f4c859eSApple OSS Distributions //
5007*0f4c859eSApple OSS Distributions // All applications and kernel clients have acknowledged our power state change.
5008*0f4c859eSApple OSS Distributions // Here we notify interested drivers pre-change.
5009*0f4c859eSApple OSS Distributions //*********************************************************************************
5010*0f4c859eSApple OSS Distributions
5011*0f4c859eSApple OSS Distributions void
OurChangeNotifyInterestedDriversWillChange(void)5012*0f4c859eSApple OSS Distributions IOService::OurChangeNotifyInterestedDriversWillChange( void )
5013*0f4c859eSApple OSS Distributions {
5014*0f4c859eSApple OSS Distributions IOPMrootDomain * rootDomain;
5015*0f4c859eSApple OSS Distributions if ((rootDomain = getPMRootDomain()) == this) {
5016*0f4c859eSApple OSS Distributions if (IS_POWER_DROP) {
5017*0f4c859eSApple OSS Distributions rootDomain->tracePoint( kIOPMTracePointSleepWillChangeInterests );
5018*0f4c859eSApple OSS Distributions } else {
5019*0f4c859eSApple OSS Distributions rootDomain->tracePoint( kIOPMTracePointWakeWillChangeInterests );
5020*0f4c859eSApple OSS Distributions }
5021*0f4c859eSApple OSS Distributions }
5022*0f4c859eSApple OSS Distributions
5023*0f4c859eSApple OSS Distributions notifyAll( kIOPM_OurChangeSetPowerState );
5024*0f4c859eSApple OSS Distributions }
5025*0f4c859eSApple OSS Distributions
5026*0f4c859eSApple OSS Distributions //*********************************************************************************
5027*0f4c859eSApple OSS Distributions // [private] OurChangeSetPowerState
5028*0f4c859eSApple OSS Distributions //
5029*0f4c859eSApple OSS Distributions // Instruct our controlling driver to program the hardware for the power state
5030*0f4c859eSApple OSS Distributions // change. Wait for async completions.
5031*0f4c859eSApple OSS Distributions //*********************************************************************************
5032*0f4c859eSApple OSS Distributions
5033*0f4c859eSApple OSS Distributions void
OurChangeSetPowerState(void)5034*0f4c859eSApple OSS Distributions IOService::OurChangeSetPowerState( void )
5035*0f4c859eSApple OSS Distributions {
5036*0f4c859eSApple OSS Distributions MS_PUSH( kIOPM_OurChangeWaitForPowerSettle );
5037*0f4c859eSApple OSS Distributions fMachineState = kIOPM_DriverThreadCallDone;
5038*0f4c859eSApple OSS Distributions fDriverCallReason = kDriverCallSetPowerState;
5039*0f4c859eSApple OSS Distributions
5040*0f4c859eSApple OSS Distributions if (notifyControllingDriver() == false) {
5041*0f4c859eSApple OSS Distributions notifyControllingDriverDone();
5042*0f4c859eSApple OSS Distributions }
5043*0f4c859eSApple OSS Distributions }
5044*0f4c859eSApple OSS Distributions
5045*0f4c859eSApple OSS Distributions //*********************************************************************************
5046*0f4c859eSApple OSS Distributions // [private] OurChangeWaitForPowerSettle
5047*0f4c859eSApple OSS Distributions //
5048*0f4c859eSApple OSS Distributions // Our controlling driver has completed the power state change we initiated.
5049*0f4c859eSApple OSS Distributions // Wait for the driver specified settle time to expire.
5050*0f4c859eSApple OSS Distributions //*********************************************************************************
5051*0f4c859eSApple OSS Distributions
5052*0f4c859eSApple OSS Distributions void
OurChangeWaitForPowerSettle(void)5053*0f4c859eSApple OSS Distributions IOService::OurChangeWaitForPowerSettle( void )
5054*0f4c859eSApple OSS Distributions {
5055*0f4c859eSApple OSS Distributions fMachineState = kIOPM_OurChangeNotifyInterestedDriversDidChange;
5056*0f4c859eSApple OSS Distributions startSettleTimer();
5057*0f4c859eSApple OSS Distributions }
5058*0f4c859eSApple OSS Distributions
5059*0f4c859eSApple OSS Distributions //*********************************************************************************
5060*0f4c859eSApple OSS Distributions // [private] OurChangeNotifyInterestedDriversDidChange
5061*0f4c859eSApple OSS Distributions //
5062*0f4c859eSApple OSS Distributions // Power has settled on a power change we initiated. Here we notify
5063*0f4c859eSApple OSS Distributions // all our interested drivers post-change.
5064*0f4c859eSApple OSS Distributions //*********************************************************************************
5065*0f4c859eSApple OSS Distributions
5066*0f4c859eSApple OSS Distributions void
OurChangeNotifyInterestedDriversDidChange(void)5067*0f4c859eSApple OSS Distributions IOService::OurChangeNotifyInterestedDriversDidChange( void )
5068*0f4c859eSApple OSS Distributions {
5069*0f4c859eSApple OSS Distributions IOPMrootDomain * rootDomain;
5070*0f4c859eSApple OSS Distributions if ((rootDomain = getPMRootDomain()) == this) {
5071*0f4c859eSApple OSS Distributions rootDomain->tracePoint( IS_POWER_DROP ?
5072*0f4c859eSApple OSS Distributions kIOPMTracePointSleepDidChangeInterests :
5073*0f4c859eSApple OSS Distributions kIOPMTracePointWakeDidChangeInterests );
5074*0f4c859eSApple OSS Distributions }
5075*0f4c859eSApple OSS Distributions
5076*0f4c859eSApple OSS Distributions notifyAll( kIOPM_OurChangeTellCapabilityDidChange );
5077*0f4c859eSApple OSS Distributions }
5078*0f4c859eSApple OSS Distributions
5079*0f4c859eSApple OSS Distributions //*********************************************************************************
5080*0f4c859eSApple OSS Distributions // [private] OurChangeTellCapabilityDidChange
5081*0f4c859eSApple OSS Distributions //
5082*0f4c859eSApple OSS Distributions // For root domain to notify capability power-change.
5083*0f4c859eSApple OSS Distributions //*********************************************************************************
5084*0f4c859eSApple OSS Distributions
5085*0f4c859eSApple OSS Distributions void
OurChangeTellCapabilityDidChange(void)5086*0f4c859eSApple OSS Distributions IOService::OurChangeTellCapabilityDidChange( void )
5087*0f4c859eSApple OSS Distributions {
5088*0f4c859eSApple OSS Distributions if (!IS_ROOT_DOMAIN) {
5089*0f4c859eSApple OSS Distributions return OurChangeFinish();
5090*0f4c859eSApple OSS Distributions }
5091*0f4c859eSApple OSS Distributions
5092*0f4c859eSApple OSS Distributions if (!IS_POWER_DROP) {
5093*0f4c859eSApple OSS Distributions // Notify root domain immediately after notifying interested
5094*0f4c859eSApple OSS Distributions // drivers and power children.
5095*0f4c859eSApple OSS Distributions getPMRootDomain()->willTellSystemCapabilityDidChange();
5096*0f4c859eSApple OSS Distributions }
5097*0f4c859eSApple OSS Distributions
5098*0f4c859eSApple OSS Distributions getPMRootDomain()->tracePoint( IS_POWER_DROP ?
5099*0f4c859eSApple OSS Distributions kIOPMTracePointSleepCapabilityClients :
5100*0f4c859eSApple OSS Distributions kIOPMTracePointWakeCapabilityClients );
5101*0f4c859eSApple OSS Distributions
5102*0f4c859eSApple OSS Distributions tellSystemCapabilityChange( kIOPM_OurChangeFinish );
5103*0f4c859eSApple OSS Distributions }
5104*0f4c859eSApple OSS Distributions
5105*0f4c859eSApple OSS Distributions //*********************************************************************************
5106*0f4c859eSApple OSS Distributions // [private] OurChangeFinish
5107*0f4c859eSApple OSS Distributions //
5108*0f4c859eSApple OSS Distributions // Done with this self-induced power state change.
5109*0f4c859eSApple OSS Distributions //*********************************************************************************
5110*0f4c859eSApple OSS Distributions
5111*0f4c859eSApple OSS Distributions void
OurChangeFinish(void)5112*0f4c859eSApple OSS Distributions IOService::OurChangeFinish( void )
5113*0f4c859eSApple OSS Distributions {
5114*0f4c859eSApple OSS Distributions all_done();
5115*0f4c859eSApple OSS Distributions }
5116*0f4c859eSApple OSS Distributions
5117*0f4c859eSApple OSS Distributions // MARK: -
5118*0f4c859eSApple OSS Distributions // MARK: Power Change Initiated by Parent
5119*0f4c859eSApple OSS Distributions
5120*0f4c859eSApple OSS Distributions //*********************************************************************************
5121*0f4c859eSApple OSS Distributions // [private] ParentChangeStart
5122*0f4c859eSApple OSS Distributions //
5123*0f4c859eSApple OSS Distributions // Here we begin the processing of a power change initiated by our parent.
5124*0f4c859eSApple OSS Distributions //*********************************************************************************
5125*0f4c859eSApple OSS Distributions
5126*0f4c859eSApple OSS Distributions IOReturn
ParentChangeStart(void)5127*0f4c859eSApple OSS Distributions IOService::ParentChangeStart( void )
5128*0f4c859eSApple OSS Distributions {
5129*0f4c859eSApple OSS Distributions PM_ASSERT_IN_GATE();
5130*0f4c859eSApple OSS Distributions OUR_PMLog( kPMLogStartParentChange, fHeadNotePowerState, fCurrentPowerState );
5131*0f4c859eSApple OSS Distributions
5132*0f4c859eSApple OSS Distributions // Root power domain has transitioned to its max power state
5133*0f4c859eSApple OSS Distributions if ((fHeadNoteChangeFlags & (kIOPMDomainDidChange | kIOPMRootChangeUp)) ==
5134*0f4c859eSApple OSS Distributions (kIOPMDomainDidChange | kIOPMRootChangeUp)) {
5135*0f4c859eSApple OSS Distributions // Restart the idle timer stopped by ParentChangeRootChangeDown()
5136*0f4c859eSApple OSS Distributions if (fIdleTimerPeriod && fIdleTimerStopped) {
5137*0f4c859eSApple OSS Distributions restartIdleTimer();
5138*0f4c859eSApple OSS Distributions }
5139*0f4c859eSApple OSS Distributions }
5140*0f4c859eSApple OSS Distributions
5141*0f4c859eSApple OSS Distributions // Power domain is forcing us to lower power
5142*0f4c859eSApple OSS Distributions if (StateOrder(fHeadNotePowerState) < StateOrder(fCurrentPowerState)) {
5143*0f4c859eSApple OSS Distributions PM_ACTION_CHANGE(actionPowerChangeStart, fHeadNotePowerState, &fHeadNoteChangeFlags);
5144*0f4c859eSApple OSS Distributions
5145*0f4c859eSApple OSS Distributions // Tell apps and kernel clients
5146*0f4c859eSApple OSS Distributions fInitialPowerChange = false;
5147*0f4c859eSApple OSS Distributions fMachineState = kIOPM_ParentChangeTellPriorityClientsPowerDown;
5148*0f4c859eSApple OSS Distributions tellChangeDown1(fHeadNotePowerState);
5149*0f4c859eSApple OSS Distributions return IOPMWillAckLater;
5150*0f4c859eSApple OSS Distributions }
5151*0f4c859eSApple OSS Distributions
5152*0f4c859eSApple OSS Distributions // Power domain is allowing us to raise power up to fHeadNotePowerState
5153*0f4c859eSApple OSS Distributions if (StateOrder(fHeadNotePowerState) > StateOrder(fCurrentPowerState)) {
5154*0f4c859eSApple OSS Distributions if (StateOrder(fDesiredPowerState) > StateOrder(fCurrentPowerState)) {
5155*0f4c859eSApple OSS Distributions if (StateOrder(fDesiredPowerState) < StateOrder(fHeadNotePowerState)) {
5156*0f4c859eSApple OSS Distributions // We power up, but not all the way
5157*0f4c859eSApple OSS Distributions fHeadNotePowerState = fDesiredPowerState;
5158*0f4c859eSApple OSS Distributions fHeadNotePowerArrayEntry = &fPowerStates[fDesiredPowerState];
5159*0f4c859eSApple OSS Distributions OUR_PMLog(kPMLogAmendParentChange, fHeadNotePowerState, 0);
5160*0f4c859eSApple OSS Distributions }
5161*0f4c859eSApple OSS Distributions } else {
5162*0f4c859eSApple OSS Distributions // We don't need to change
5163*0f4c859eSApple OSS Distributions fHeadNotePowerState = fCurrentPowerState;
5164*0f4c859eSApple OSS Distributions fHeadNotePowerArrayEntry = &fPowerStates[fCurrentPowerState];
5165*0f4c859eSApple OSS Distributions OUR_PMLog(kPMLogAmendParentChange, fHeadNotePowerState, 0);
5166*0f4c859eSApple OSS Distributions }
5167*0f4c859eSApple OSS Distributions }
5168*0f4c859eSApple OSS Distributions
5169*0f4c859eSApple OSS Distributions if (fHeadNoteChangeFlags & kIOPMDomainDidChange) {
5170*0f4c859eSApple OSS Distributions if (StateOrder(fHeadNotePowerState) > StateOrder(fCurrentPowerState)) {
5171*0f4c859eSApple OSS Distributions PM_ACTION_CHANGE(actionPowerChangeStart,
5172*0f4c859eSApple OSS Distributions fHeadNotePowerState, &fHeadNoteChangeFlags);
5173*0f4c859eSApple OSS Distributions
5174*0f4c859eSApple OSS Distributions // Parent did change up - start our change up
5175*0f4c859eSApple OSS Distributions fInitialPowerChange = false;
5176*0f4c859eSApple OSS Distributions ParentChangeTellCapabilityWillChange();
5177*0f4c859eSApple OSS Distributions return IOPMWillAckLater;
5178*0f4c859eSApple OSS Distributions } else if (fHeadNoteChangeFlags & kIOPMRootBroadcastFlags) {
5179*0f4c859eSApple OSS Distributions // No need to change power state, but broadcast change
5180*0f4c859eSApple OSS Distributions // to our children.
5181*0f4c859eSApple OSS Distributions fMachineState = kIOPM_SyncNotifyDidChange;
5182*0f4c859eSApple OSS Distributions fDriverCallReason = kDriverCallInformPreChange;
5183*0f4c859eSApple OSS Distributions fHeadNoteChangeFlags |= kIOPMNotDone;
5184*0f4c859eSApple OSS Distributions notifyChildren();
5185*0f4c859eSApple OSS Distributions return IOPMWillAckLater;
5186*0f4c859eSApple OSS Distributions }
5187*0f4c859eSApple OSS Distributions }
5188*0f4c859eSApple OSS Distributions
5189*0f4c859eSApple OSS Distributions // No power state change necessary
5190*0f4c859eSApple OSS Distributions fHeadNoteChangeFlags |= kIOPMNotDone;
5191*0f4c859eSApple OSS Distributions
5192*0f4c859eSApple OSS Distributions all_done();
5193*0f4c859eSApple OSS Distributions return IOPMAckImplied;
5194*0f4c859eSApple OSS Distributions }
5195*0f4c859eSApple OSS Distributions
5196*0f4c859eSApple OSS Distributions //******************************************************************************
5197*0f4c859eSApple OSS Distributions // [private] ParentChangeRootChangeDown
5198*0f4c859eSApple OSS Distributions //
5199*0f4c859eSApple OSS Distributions // Root domain has finished the transition to the system sleep state. And all
5200*0f4c859eSApple OSS Distributions // drivers in the power plane should have powered down. Cancel the idle timer,
5201*0f4c859eSApple OSS Distributions // and also reset the device desire for those drivers that don't want power
5202*0f4c859eSApple OSS Distributions // automatically restored on wake.
5203*0f4c859eSApple OSS Distributions //******************************************************************************
5204*0f4c859eSApple OSS Distributions
5205*0f4c859eSApple OSS Distributions void
ParentChangeRootChangeDown(void)5206*0f4c859eSApple OSS Distributions IOService::ParentChangeRootChangeDown( void )
5207*0f4c859eSApple OSS Distributions {
5208*0f4c859eSApple OSS Distributions // Always stop the idle timer before root power down
5209*0f4c859eSApple OSS Distributions if (fIdleTimerPeriod && !fIdleTimerStopped) {
5210*0f4c859eSApple OSS Distributions fIdleTimerStopped = true;
5211*0f4c859eSApple OSS Distributions if (fIdleTimer && thread_call_cancel(fIdleTimer)) {
5212*0f4c859eSApple OSS Distributions release();
5213*0f4c859eSApple OSS Distributions }
5214*0f4c859eSApple OSS Distributions }
5215*0f4c859eSApple OSS Distributions
5216*0f4c859eSApple OSS Distributions if (fResetPowerStateOnWake) {
5217*0f4c859eSApple OSS Distributions // Reset device desire down to the lowest power state.
5218*0f4c859eSApple OSS Distributions // Advisory tickle desire is intentionally untouched since
5219*0f4c859eSApple OSS Distributions // it has no effect until system is promoted to full wake.
5220*0f4c859eSApple OSS Distributions
5221*0f4c859eSApple OSS Distributions if (fDeviceDesire != kPowerStateZero) {
5222*0f4c859eSApple OSS Distributions updatePowerClient(gIOPMPowerClientDevice, kPowerStateZero);
5223*0f4c859eSApple OSS Distributions computeDesiredState(kPowerStateZero, true);
5224*0f4c859eSApple OSS Distributions requestDomainPower( fDesiredPowerState );
5225*0f4c859eSApple OSS Distributions PM_LOG1("%s: tickle desire removed\n", fName);
5226*0f4c859eSApple OSS Distributions }
5227*0f4c859eSApple OSS Distributions
5228*0f4c859eSApple OSS Distributions // Invalidate tickle cache so the next tickle will issue a request
5229*0f4c859eSApple OSS Distributions IOLockLock(fActivityLock);
5230*0f4c859eSApple OSS Distributions fDeviceWasActive = false;
5231*0f4c859eSApple OSS Distributions fActivityTicklePowerState = kInvalidTicklePowerState;
5232*0f4c859eSApple OSS Distributions IOLockUnlock(fActivityLock);
5233*0f4c859eSApple OSS Distributions
5234*0f4c859eSApple OSS Distributions fIdleTimerMinPowerState = kPowerStateZero;
5235*0f4c859eSApple OSS Distributions } else if (fAdvisoryTickleUsed) {
5236*0f4c859eSApple OSS Distributions // Less aggressive mechanism to accelerate idle timer expiration
5237*0f4c859eSApple OSS Distributions // before system sleep. May not always allow the driver to wake
5238*0f4c859eSApple OSS Distributions // up from system sleep in the min power state.
5239*0f4c859eSApple OSS Distributions
5240*0f4c859eSApple OSS Distributions AbsoluteTime now;
5241*0f4c859eSApple OSS Distributions uint64_t nsec;
5242*0f4c859eSApple OSS Distributions bool dropTickleDesire = false;
5243*0f4c859eSApple OSS Distributions
5244*0f4c859eSApple OSS Distributions if (fIdleTimerPeriod && !fIdleTimerIgnored &&
5245*0f4c859eSApple OSS Distributions (fIdleTimerMinPowerState == kPowerStateZero) &&
5246*0f4c859eSApple OSS Distributions (fDeviceDesire != kPowerStateZero)) {
5247*0f4c859eSApple OSS Distributions IOLockLock(fActivityLock);
5248*0f4c859eSApple OSS Distributions
5249*0f4c859eSApple OSS Distributions if (!fDeviceWasActive) {
5250*0f4c859eSApple OSS Distributions // No tickles since the last idle timer expiration.
5251*0f4c859eSApple OSS Distributions // Safe to drop the device desire to zero.
5252*0f4c859eSApple OSS Distributions dropTickleDesire = true;
5253*0f4c859eSApple OSS Distributions } else {
5254*0f4c859eSApple OSS Distributions // Was tickled since the last idle timer expiration,
5255*0f4c859eSApple OSS Distributions // but not in the last minute.
5256*0f4c859eSApple OSS Distributions clock_get_uptime(&now);
5257*0f4c859eSApple OSS Distributions SUB_ABSOLUTETIME(&now, &fDeviceActiveTimestamp);
5258*0f4c859eSApple OSS Distributions absolutetime_to_nanoseconds(now, &nsec);
5259*0f4c859eSApple OSS Distributions if (nsec >= kNoTickleCancelWindow) {
5260*0f4c859eSApple OSS Distributions dropTickleDesire = true;
5261*0f4c859eSApple OSS Distributions }
5262*0f4c859eSApple OSS Distributions }
5263*0f4c859eSApple OSS Distributions
5264*0f4c859eSApple OSS Distributions if (dropTickleDesire) {
5265*0f4c859eSApple OSS Distributions // Force the next tickle to raise power state
5266*0f4c859eSApple OSS Distributions fDeviceWasActive = false;
5267*0f4c859eSApple OSS Distributions fActivityTicklePowerState = kInvalidTicklePowerState;
5268*0f4c859eSApple OSS Distributions }
5269*0f4c859eSApple OSS Distributions
5270*0f4c859eSApple OSS Distributions IOLockUnlock(fActivityLock);
5271*0f4c859eSApple OSS Distributions }
5272*0f4c859eSApple OSS Distributions
5273*0f4c859eSApple OSS Distributions if (dropTickleDesire) {
5274*0f4c859eSApple OSS Distributions // Advisory tickle desire is intentionally untouched since
5275*0f4c859eSApple OSS Distributions // it has no effect until system is promoted to full wake.
5276*0f4c859eSApple OSS Distributions
5277*0f4c859eSApple OSS Distributions updatePowerClient(gIOPMPowerClientDevice, kPowerStateZero);
5278*0f4c859eSApple OSS Distributions computeDesiredState(kPowerStateZero, true);
5279*0f4c859eSApple OSS Distributions PM_LOG1("%s: tickle desire dropped\n", fName);
5280*0f4c859eSApple OSS Distributions }
5281*0f4c859eSApple OSS Distributions }
5282*0f4c859eSApple OSS Distributions }
5283*0f4c859eSApple OSS Distributions
5284*0f4c859eSApple OSS Distributions //*********************************************************************************
5285*0f4c859eSApple OSS Distributions // [private] ParentChangeTellPriorityClientsPowerDown
5286*0f4c859eSApple OSS Distributions //
5287*0f4c859eSApple OSS Distributions // All applications and kernel clients have acknowledged our intention to drop
5288*0f4c859eSApple OSS Distributions // power. Here we notify "priority" clients that we are lowering power.
5289*0f4c859eSApple OSS Distributions //*********************************************************************************
5290*0f4c859eSApple OSS Distributions
5291*0f4c859eSApple OSS Distributions void
ParentChangeTellPriorityClientsPowerDown(void)5292*0f4c859eSApple OSS Distributions IOService::ParentChangeTellPriorityClientsPowerDown( void )
5293*0f4c859eSApple OSS Distributions {
5294*0f4c859eSApple OSS Distributions fMachineState = kIOPM_ParentChangeNotifyInterestedDriversWillChange;
5295*0f4c859eSApple OSS Distributions tellChangeDown2(fHeadNotePowerState);
5296*0f4c859eSApple OSS Distributions }
5297*0f4c859eSApple OSS Distributions
5298*0f4c859eSApple OSS Distributions //*********************************************************************************
5299*0f4c859eSApple OSS Distributions // [private] ParentChangeTellCapabilityWillChange
5300*0f4c859eSApple OSS Distributions //
5301*0f4c859eSApple OSS Distributions // All (legacy) applications and kernel clients have acknowledged, extra stage for
5302*0f4c859eSApple OSS Distributions // root domain to notify apps and drivers about the system capability change.
5303*0f4c859eSApple OSS Distributions //*********************************************************************************
5304*0f4c859eSApple OSS Distributions
5305*0f4c859eSApple OSS Distributions void
ParentChangeTellCapabilityWillChange(void)5306*0f4c859eSApple OSS Distributions IOService::ParentChangeTellCapabilityWillChange( void )
5307*0f4c859eSApple OSS Distributions {
5308*0f4c859eSApple OSS Distributions if (!IS_ROOT_DOMAIN) {
5309*0f4c859eSApple OSS Distributions return ParentChangeNotifyInterestedDriversWillChange();
5310*0f4c859eSApple OSS Distributions }
5311*0f4c859eSApple OSS Distributions
5312*0f4c859eSApple OSS Distributions tellSystemCapabilityChange( kIOPM_ParentChangeNotifyInterestedDriversWillChange );
5313*0f4c859eSApple OSS Distributions }
5314*0f4c859eSApple OSS Distributions
5315*0f4c859eSApple OSS Distributions //*********************************************************************************
5316*0f4c859eSApple OSS Distributions // [private] ParentChangeNotifyInterestedDriversWillChange
5317*0f4c859eSApple OSS Distributions //
5318*0f4c859eSApple OSS Distributions // All applications and kernel clients have acknowledged our power state change.
5319*0f4c859eSApple OSS Distributions // Here we notify interested drivers pre-change.
5320*0f4c859eSApple OSS Distributions //*********************************************************************************
5321*0f4c859eSApple OSS Distributions
5322*0f4c859eSApple OSS Distributions void
ParentChangeNotifyInterestedDriversWillChange(void)5323*0f4c859eSApple OSS Distributions IOService::ParentChangeNotifyInterestedDriversWillChange( void )
5324*0f4c859eSApple OSS Distributions {
5325*0f4c859eSApple OSS Distributions notifyAll( kIOPM_ParentChangeSetPowerState );
5326*0f4c859eSApple OSS Distributions }
5327*0f4c859eSApple OSS Distributions
5328*0f4c859eSApple OSS Distributions //*********************************************************************************
5329*0f4c859eSApple OSS Distributions // [private] ParentChangeSetPowerState
5330*0f4c859eSApple OSS Distributions //
5331*0f4c859eSApple OSS Distributions // Instruct our controlling driver to program the hardware for the power state
5332*0f4c859eSApple OSS Distributions // change. Wait for async completions.
5333*0f4c859eSApple OSS Distributions //*********************************************************************************
5334*0f4c859eSApple OSS Distributions
5335*0f4c859eSApple OSS Distributions void
ParentChangeSetPowerState(void)5336*0f4c859eSApple OSS Distributions IOService::ParentChangeSetPowerState( void )
5337*0f4c859eSApple OSS Distributions {
5338*0f4c859eSApple OSS Distributions MS_PUSH( kIOPM_ParentChangeWaitForPowerSettle );
5339*0f4c859eSApple OSS Distributions fMachineState = kIOPM_DriverThreadCallDone;
5340*0f4c859eSApple OSS Distributions fDriverCallReason = kDriverCallSetPowerState;
5341*0f4c859eSApple OSS Distributions
5342*0f4c859eSApple OSS Distributions if (notifyControllingDriver() == false) {
5343*0f4c859eSApple OSS Distributions notifyControllingDriverDone();
5344*0f4c859eSApple OSS Distributions }
5345*0f4c859eSApple OSS Distributions }
5346*0f4c859eSApple OSS Distributions
5347*0f4c859eSApple OSS Distributions //*********************************************************************************
5348*0f4c859eSApple OSS Distributions // [private] ParentChangeWaitForPowerSettle
5349*0f4c859eSApple OSS Distributions //
5350*0f4c859eSApple OSS Distributions // Our controlling driver has completed the power state change initiated by our
5351*0f4c859eSApple OSS Distributions // parent. Wait for the driver specified settle time to expire.
5352*0f4c859eSApple OSS Distributions //*********************************************************************************
5353*0f4c859eSApple OSS Distributions
5354*0f4c859eSApple OSS Distributions void
ParentChangeWaitForPowerSettle(void)5355*0f4c859eSApple OSS Distributions IOService::ParentChangeWaitForPowerSettle( void )
5356*0f4c859eSApple OSS Distributions {
5357*0f4c859eSApple OSS Distributions fMachineState = kIOPM_ParentChangeNotifyInterestedDriversDidChange;
5358*0f4c859eSApple OSS Distributions startSettleTimer();
5359*0f4c859eSApple OSS Distributions }
5360*0f4c859eSApple OSS Distributions
5361*0f4c859eSApple OSS Distributions //*********************************************************************************
5362*0f4c859eSApple OSS Distributions // [private] ParentChangeNotifyInterestedDriversDidChange
5363*0f4c859eSApple OSS Distributions //
5364*0f4c859eSApple OSS Distributions // Power has settled on a power change initiated by our parent. Here we notify
5365*0f4c859eSApple OSS Distributions // all our interested drivers post-change.
5366*0f4c859eSApple OSS Distributions //*********************************************************************************
5367*0f4c859eSApple OSS Distributions
5368*0f4c859eSApple OSS Distributions void
ParentChangeNotifyInterestedDriversDidChange(void)5369*0f4c859eSApple OSS Distributions IOService::ParentChangeNotifyInterestedDriversDidChange( void )
5370*0f4c859eSApple OSS Distributions {
5371*0f4c859eSApple OSS Distributions notifyAll( kIOPM_ParentChangeTellCapabilityDidChange );
5372*0f4c859eSApple OSS Distributions }
5373*0f4c859eSApple OSS Distributions
5374*0f4c859eSApple OSS Distributions //*********************************************************************************
5375*0f4c859eSApple OSS Distributions // [private] ParentChangeTellCapabilityDidChange
5376*0f4c859eSApple OSS Distributions //
5377*0f4c859eSApple OSS Distributions // For root domain to notify capability power-change.
5378*0f4c859eSApple OSS Distributions //*********************************************************************************
5379*0f4c859eSApple OSS Distributions
5380*0f4c859eSApple OSS Distributions void
ParentChangeTellCapabilityDidChange(void)5381*0f4c859eSApple OSS Distributions IOService::ParentChangeTellCapabilityDidChange( void )
5382*0f4c859eSApple OSS Distributions {
5383*0f4c859eSApple OSS Distributions if (!IS_ROOT_DOMAIN) {
5384*0f4c859eSApple OSS Distributions return ParentChangeAcknowledgePowerChange();
5385*0f4c859eSApple OSS Distributions }
5386*0f4c859eSApple OSS Distributions
5387*0f4c859eSApple OSS Distributions tellSystemCapabilityChange( kIOPM_ParentChangeAcknowledgePowerChange );
5388*0f4c859eSApple OSS Distributions }
5389*0f4c859eSApple OSS Distributions
5390*0f4c859eSApple OSS Distributions //*********************************************************************************
5391*0f4c859eSApple OSS Distributions // [private] ParentAcknowledgePowerChange
5392*0f4c859eSApple OSS Distributions //
5393*0f4c859eSApple OSS Distributions // Acknowledge our power parent that our power change is done.
5394*0f4c859eSApple OSS Distributions //*********************************************************************************
5395*0f4c859eSApple OSS Distributions
5396*0f4c859eSApple OSS Distributions void
ParentChangeAcknowledgePowerChange(void)5397*0f4c859eSApple OSS Distributions IOService::ParentChangeAcknowledgePowerChange( void )
5398*0f4c859eSApple OSS Distributions {
5399*0f4c859eSApple OSS Distributions IORegistryEntry * nub;
5400*0f4c859eSApple OSS Distributions IOService * parent;
5401*0f4c859eSApple OSS Distributions
5402*0f4c859eSApple OSS Distributions nub = fHeadNoteParentConnection;
5403*0f4c859eSApple OSS Distributions nub->retain();
5404*0f4c859eSApple OSS Distributions all_done();
5405*0f4c859eSApple OSS Distributions parent = (IOService *)nub->copyParentEntry(gIOPowerPlane);
5406*0f4c859eSApple OSS Distributions if (parent) {
5407*0f4c859eSApple OSS Distributions parent->acknowledgePowerChange((IOService *)nub);
5408*0f4c859eSApple OSS Distributions parent->release();
5409*0f4c859eSApple OSS Distributions }
5410*0f4c859eSApple OSS Distributions nub->release();
5411*0f4c859eSApple OSS Distributions }
5412*0f4c859eSApple OSS Distributions
5413*0f4c859eSApple OSS Distributions // MARK: -
5414*0f4c859eSApple OSS Distributions // MARK: Ack and Settle timers
5415*0f4c859eSApple OSS Distributions
5416*0f4c859eSApple OSS Distributions //*********************************************************************************
5417*0f4c859eSApple OSS Distributions // [private] settleTimerExpired
5418*0f4c859eSApple OSS Distributions //
5419*0f4c859eSApple OSS Distributions // Power has settled after our last change. Notify interested parties that
5420*0f4c859eSApple OSS Distributions // there is a new power state.
5421*0f4c859eSApple OSS Distributions //*********************************************************************************
5422*0f4c859eSApple OSS Distributions
5423*0f4c859eSApple OSS Distributions void
settleTimerExpired(void)5424*0f4c859eSApple OSS Distributions IOService::settleTimerExpired( void )
5425*0f4c859eSApple OSS Distributions {
5426*0f4c859eSApple OSS Distributions #if USE_SETTLE_TIMER
5427*0f4c859eSApple OSS Distributions fSettleTimeUS = 0;
5428*0f4c859eSApple OSS Distributions gIOPMWorkQueue->signalWorkAvailable();
5429*0f4c859eSApple OSS Distributions #endif
5430*0f4c859eSApple OSS Distributions }
5431*0f4c859eSApple OSS Distributions
5432*0f4c859eSApple OSS Distributions //*********************************************************************************
5433*0f4c859eSApple OSS Distributions // settle_timer_expired
5434*0f4c859eSApple OSS Distributions //
5435*0f4c859eSApple OSS Distributions // Holds a retain while the settle timer callout is in flight.
5436*0f4c859eSApple OSS Distributions //*********************************************************************************
5437*0f4c859eSApple OSS Distributions
5438*0f4c859eSApple OSS Distributions #if USE_SETTLE_TIMER
5439*0f4c859eSApple OSS Distributions static void
settle_timer_expired(thread_call_param_t arg0,thread_call_param_t arg1)5440*0f4c859eSApple OSS Distributions settle_timer_expired( thread_call_param_t arg0, thread_call_param_t arg1 )
5441*0f4c859eSApple OSS Distributions {
5442*0f4c859eSApple OSS Distributions IOService * me = (IOService *) arg0;
5443*0f4c859eSApple OSS Distributions
5444*0f4c859eSApple OSS Distributions if (gIOPMWorkLoop && gIOPMWorkQueue) {
5445*0f4c859eSApple OSS Distributions gIOPMWorkLoop->runAction(
5446*0f4c859eSApple OSS Distributions OSMemberFunctionCast(IOWorkLoop::Action, me, &IOService::settleTimerExpired),
5447*0f4c859eSApple OSS Distributions me);
5448*0f4c859eSApple OSS Distributions }
5449*0f4c859eSApple OSS Distributions me->release();
5450*0f4c859eSApple OSS Distributions }
5451*0f4c859eSApple OSS Distributions #endif
5452*0f4c859eSApple OSS Distributions
5453*0f4c859eSApple OSS Distributions //*********************************************************************************
5454*0f4c859eSApple OSS Distributions // [private] startSettleTimer
5455*0f4c859eSApple OSS Distributions //
5456*0f4c859eSApple OSS Distributions // Calculate a power-settling delay in microseconds and start a timer.
5457*0f4c859eSApple OSS Distributions //*********************************************************************************
5458*0f4c859eSApple OSS Distributions
5459*0f4c859eSApple OSS Distributions void
startSettleTimer(void)5460*0f4c859eSApple OSS Distributions IOService::startSettleTimer( void )
5461*0f4c859eSApple OSS Distributions {
5462*0f4c859eSApple OSS Distributions #if USE_SETTLE_TIMER
5463*0f4c859eSApple OSS Distributions // This function is broken and serves no useful purpose since it never
5464*0f4c859eSApple OSS Distributions // updates fSettleTimeUS to a non-zero value to stall the state machine,
5465*0f4c859eSApple OSS Distributions // yet it starts a delay timer. It appears no driver relies on a delay
5466*0f4c859eSApple OSS Distributions // from settleUpTime and settleDownTime in the power state table.
5467*0f4c859eSApple OSS Distributions
5468*0f4c859eSApple OSS Distributions AbsoluteTime deadline;
5469*0f4c859eSApple OSS Distributions IOPMPowerStateIndex stateIndex;
5470*0f4c859eSApple OSS Distributions IOPMPowerStateIndex currentOrder, newOrder, i;
5471*0f4c859eSApple OSS Distributions uint32_t settleTime = 0;
5472*0f4c859eSApple OSS Distributions boolean_t pending;
5473*0f4c859eSApple OSS Distributions
5474*0f4c859eSApple OSS Distributions PM_ASSERT_IN_GATE();
5475*0f4c859eSApple OSS Distributions
5476*0f4c859eSApple OSS Distributions currentOrder = StateOrder(fCurrentPowerState);
5477*0f4c859eSApple OSS Distributions newOrder = StateOrder(fHeadNotePowerState);
5478*0f4c859eSApple OSS Distributions
5479*0f4c859eSApple OSS Distributions i = currentOrder;
5480*0f4c859eSApple OSS Distributions
5481*0f4c859eSApple OSS Distributions // lowering power
5482*0f4c859eSApple OSS Distributions if (newOrder < currentOrder) {
5483*0f4c859eSApple OSS Distributions while (i > newOrder) {
5484*0f4c859eSApple OSS Distributions stateIndex = fPowerStates[i].stateOrderToIndex;
5485*0f4c859eSApple OSS Distributions settleTime += (uint32_t) fPowerStates[stateIndex].settleDownTime;
5486*0f4c859eSApple OSS Distributions i--;
5487*0f4c859eSApple OSS Distributions }
5488*0f4c859eSApple OSS Distributions }
5489*0f4c859eSApple OSS Distributions
5490*0f4c859eSApple OSS Distributions // raising power
5491*0f4c859eSApple OSS Distributions if (newOrder > currentOrder) {
5492*0f4c859eSApple OSS Distributions while (i < newOrder) {
5493*0f4c859eSApple OSS Distributions stateIndex = fPowerStates[i + 1].stateOrderToIndex;
5494*0f4c859eSApple OSS Distributions settleTime += (uint32_t) fPowerStates[stateIndex].settleUpTime;
5495*0f4c859eSApple OSS Distributions i++;
5496*0f4c859eSApple OSS Distributions }
5497*0f4c859eSApple OSS Distributions }
5498*0f4c859eSApple OSS Distributions
5499*0f4c859eSApple OSS Distributions if (settleTime) {
5500*0f4c859eSApple OSS Distributions retain();
5501*0f4c859eSApple OSS Distributions clock_interval_to_deadline(settleTime, kMicrosecondScale, &deadline);
5502*0f4c859eSApple OSS Distributions pending = thread_call_enter_delayed(fSettleTimer, deadline);
5503*0f4c859eSApple OSS Distributions if (pending) {
5504*0f4c859eSApple OSS Distributions release();
5505*0f4c859eSApple OSS Distributions }
5506*0f4c859eSApple OSS Distributions }
5507*0f4c859eSApple OSS Distributions #endif
5508*0f4c859eSApple OSS Distributions }
5509*0f4c859eSApple OSS Distributions
5510*0f4c859eSApple OSS Distributions //*********************************************************************************
5511*0f4c859eSApple OSS Distributions // [private] ackTimerTick
5512*0f4c859eSApple OSS Distributions //
5513*0f4c859eSApple OSS Distributions // The acknowledgement timeout periodic timer has ticked.
5514*0f4c859eSApple OSS Distributions // If we are awaiting acks for a power change notification,
5515*0f4c859eSApple OSS Distributions // we decrement the timer word of each interested driver which hasn't acked.
5516*0f4c859eSApple OSS Distributions // If a timer word becomes zero, we pretend the driver aknowledged.
5517*0f4c859eSApple OSS Distributions // If we are waiting for the controlling driver to change the power
5518*0f4c859eSApple OSS Distributions // state of the hardware, we decrement its timer word, and if it becomes
5519*0f4c859eSApple OSS Distributions // zero, we pretend the driver acknowledged.
5520*0f4c859eSApple OSS Distributions //
5521*0f4c859eSApple OSS Distributions // Returns true if the timer tick made it possible to advance to the next
5522*0f4c859eSApple OSS Distributions // machine state, false otherwise.
5523*0f4c859eSApple OSS Distributions //*********************************************************************************
5524*0f4c859eSApple OSS Distributions
5525*0f4c859eSApple OSS Distributions #ifndef __LP64__
5526*0f4c859eSApple OSS Distributions #if MACH_ASSERT
5527*0f4c859eSApple OSS Distributions __dead2
5528*0f4c859eSApple OSS Distributions #endif
5529*0f4c859eSApple OSS Distributions void
ack_timer_ticked(void)5530*0f4c859eSApple OSS Distributions IOService::ack_timer_ticked( void )
5531*0f4c859eSApple OSS Distributions {
5532*0f4c859eSApple OSS Distributions assert(false);
5533*0f4c859eSApple OSS Distributions }
5534*0f4c859eSApple OSS Distributions #endif /* !__LP64__ */
5535*0f4c859eSApple OSS Distributions
5536*0f4c859eSApple OSS Distributions bool
ackTimerTick(void)5537*0f4c859eSApple OSS Distributions IOService::ackTimerTick( void )
5538*0f4c859eSApple OSS Distributions {
5539*0f4c859eSApple OSS Distributions IOPMinformee * nextObject;
5540*0f4c859eSApple OSS Distributions bool done = false;
5541*0f4c859eSApple OSS Distributions
5542*0f4c859eSApple OSS Distributions PM_ASSERT_IN_GATE();
5543*0f4c859eSApple OSS Distributions switch (fMachineState) {
5544*0f4c859eSApple OSS Distributions case kIOPM_OurChangeWaitForPowerSettle:
5545*0f4c859eSApple OSS Distributions case kIOPM_ParentChangeWaitForPowerSettle:
5546*0f4c859eSApple OSS Distributions // are we waiting for controlling driver to acknowledge?
5547*0f4c859eSApple OSS Distributions if (fDriverTimer > 0) {
5548*0f4c859eSApple OSS Distributions // yes, decrement timer tick
5549*0f4c859eSApple OSS Distributions fDriverTimer--;
5550*0f4c859eSApple OSS Distributions if (fDriverTimer == 0) {
5551*0f4c859eSApple OSS Distributions // controlling driver is tardy
5552*0f4c859eSApple OSS Distributions uint64_t nsec = computeTimeDeltaNS(&fDriverCallStartTime);
5553*0f4c859eSApple OSS Distributions OUR_PMLog(kPMLogCtrlDriverTardy, 0, 0);
5554*0f4c859eSApple OSS Distributions setProperty(kIOPMTardyAckSPSKey, kOSBooleanTrue);
5555*0f4c859eSApple OSS Distributions PM_ERROR("%s::setPowerState(%p, %lu -> %lu) timed out after %d ms\n",
5556*0f4c859eSApple OSS Distributions fName, OBFUSCATE(this), fCurrentPowerState, fHeadNotePowerState, NS_TO_MS(nsec));
5557*0f4c859eSApple OSS Distributions
5558*0f4c859eSApple OSS Distributions #if DEBUG || DEVELOPMENT || !defined(XNU_TARGET_OS_OSX)
5559*0f4c859eSApple OSS Distributions bool panic_allowed = false;
5560*0f4c859eSApple OSS Distributions uint32_t setpowerstate_panic = -1;
5561*0f4c859eSApple OSS Distributions PE_parse_boot_argn("setpowerstate_panic", &setpowerstate_panic, sizeof(setpowerstate_panic));
5562*0f4c859eSApple OSS Distributions panic_allowed = setpowerstate_panic != 0;
5563*0f4c859eSApple OSS Distributions #ifdef CONFIG_XNUPOST
5564*0f4c859eSApple OSS Distributions uint64_t kernel_post_args = 0;
5565*0f4c859eSApple OSS Distributions PE_parse_boot_argn("kernPOST", &kernel_post_args, sizeof(kernel_post_args));
5566*0f4c859eSApple OSS Distributions if (kernel_post_args != 0) {
5567*0f4c859eSApple OSS Distributions panic_allowed = false;
5568*0f4c859eSApple OSS Distributions }
5569*0f4c859eSApple OSS Distributions #endif /* CONFIG_XNUPOST */
5570*0f4c859eSApple OSS Distributions if (panic_allowed) {
5571*0f4c859eSApple OSS Distributions // rdar://problem/48743340 - excluding AppleSEPManager from panic
5572*0f4c859eSApple OSS Distributions const char *allowlist = "AppleSEPManager";
5573*0f4c859eSApple OSS Distributions if (strncmp(fName, allowlist, strlen(allowlist))) {
5574*0f4c859eSApple OSS Distributions panic("%s::setPowerState(%p, %lu -> %lu) timed out after %d ms",
5575*0f4c859eSApple OSS Distributions fName, this, fCurrentPowerState, fHeadNotePowerState, NS_TO_MS(nsec));
5576*0f4c859eSApple OSS Distributions }
5577*0f4c859eSApple OSS Distributions } else {
5578*0f4c859eSApple OSS Distributions #ifdef CONFIG_XNUPOST
5579*0f4c859eSApple OSS Distributions if (kernel_post_args != 0) {
5580*0f4c859eSApple OSS Distributions PM_ERROR("setPowerState panic disabled by kernPOST boot-arg\n");
5581*0f4c859eSApple OSS Distributions }
5582*0f4c859eSApple OSS Distributions #endif /* CONFIG_XNUPOST */
5583*0f4c859eSApple OSS Distributions if (setpowerstate_panic != 0) {
5584*0f4c859eSApple OSS Distributions PM_ERROR("setPowerState panic disabled by setpowerstate_panic boot-arg\n");
5585*0f4c859eSApple OSS Distributions }
5586*0f4c859eSApple OSS Distributions }
5587*0f4c859eSApple OSS Distributions #else /* !(DEBUG || DEVELOPMENT || !defined(XNU_TARGET_OS_OSX)) */
5588*0f4c859eSApple OSS Distributions if (gIOKitDebug & kIOLogDebugPower) {
5589*0f4c859eSApple OSS Distributions panic("%s::setPowerState(%p, %lu -> %lu) timed out after %d ms",
5590*0f4c859eSApple OSS Distributions fName, this, fCurrentPowerState, fHeadNotePowerState, NS_TO_MS(nsec));
5591*0f4c859eSApple OSS Distributions } else {
5592*0f4c859eSApple OSS Distributions // panic for first party kexts
5593*0f4c859eSApple OSS Distributions const void *function_addr = NULL;
5594*0f4c859eSApple OSS Distributions OSKext *kext = NULL;
5595*0f4c859eSApple OSS Distributions function_addr = OSMemberFunctionCast(const void *, fControllingDriver, &IOService::setPowerState);
5596*0f4c859eSApple OSS Distributions kext = OSKext::lookupKextWithAddress((vm_address_t)function_addr);
5597*0f4c859eSApple OSS Distributions if (kext) {
5598*0f4c859eSApple OSS Distributions #if __has_feature(ptrauth_calls)
5599*0f4c859eSApple OSS Distributions function_addr = (const void*)VM_KERNEL_STRIP_PTR(function_addr);
5600*0f4c859eSApple OSS Distributions #endif /* __has_feature(ptrauth_calls) */
5601*0f4c859eSApple OSS Distributions const char *bundleID = kext->getIdentifierCString();
5602*0f4c859eSApple OSS Distributions const char *apple_prefix = "com.apple";
5603*0f4c859eSApple OSS Distributions const char *kernel_prefix = "__kernel__";
5604*0f4c859eSApple OSS Distributions if (strncmp(bundleID, apple_prefix, strlen(apple_prefix)) == 0 || strncmp(bundleID, kernel_prefix, strlen(kernel_prefix)) == 0) {
5605*0f4c859eSApple OSS Distributions // first party client
5606*0f4c859eSApple OSS Distributions panic("%s::setPowerState(%p : %p, %lu -> %lu) timed out after %d ms",
5607*0f4c859eSApple OSS Distributions fName, this, function_addr, fCurrentPowerState, fHeadNotePowerState, NS_TO_MS(nsec));
5608*0f4c859eSApple OSS Distributions }
5609*0f4c859eSApple OSS Distributions kext->release();
5610*0f4c859eSApple OSS Distributions }
5611*0f4c859eSApple OSS Distributions }
5612*0f4c859eSApple OSS Distributions #endif /* !(DEBUG || DEVELOPMENT || !defined(XNU_TARGET_OS_OSX)) */
5613*0f4c859eSApple OSS Distributions // Unblock state machine and pretend driver has acked.
5614*0f4c859eSApple OSS Distributions done = true;
5615*0f4c859eSApple OSS Distributions getPMRootDomain()->reset_watchdog_timer(this, 0);
5616*0f4c859eSApple OSS Distributions } else {
5617*0f4c859eSApple OSS Distributions // still waiting, set timer again
5618*0f4c859eSApple OSS Distributions start_ack_timer();
5619*0f4c859eSApple OSS Distributions }
5620*0f4c859eSApple OSS Distributions }
5621*0f4c859eSApple OSS Distributions break;
5622*0f4c859eSApple OSS Distributions
5623*0f4c859eSApple OSS Distributions case kIOPM_NotifyChildrenStart:
5624*0f4c859eSApple OSS Distributions // are we waiting for interested parties to acknowledge?
5625*0f4c859eSApple OSS Distributions if (fHeadNotePendingAcks != 0) {
5626*0f4c859eSApple OSS Distributions // yes, go through the list of interested drivers
5627*0f4c859eSApple OSS Distributions nextObject = fInterestedDrivers->firstInList();
5628*0f4c859eSApple OSS Distributions // and check each one
5629*0f4c859eSApple OSS Distributions while (nextObject != NULL) {
5630*0f4c859eSApple OSS Distributions if (nextObject->timer > 0) {
5631*0f4c859eSApple OSS Distributions nextObject->timer--;
5632*0f4c859eSApple OSS Distributions // this one should have acked by now
5633*0f4c859eSApple OSS Distributions if (nextObject->timer == 0) {
5634*0f4c859eSApple OSS Distributions uint64_t nsec = computeTimeDeltaNS(&nextObject->startTime);
5635*0f4c859eSApple OSS Distributions OUR_PMLog(kPMLogIntDriverTardy, 0, 0);
5636*0f4c859eSApple OSS Distributions nextObject->whatObject->setProperty(kIOPMTardyAckPSCKey, kOSBooleanTrue);
5637*0f4c859eSApple OSS Distributions PM_ERROR("%s::powerState%sChangeTo(%p, %s, %lu -> %lu) timed out after %d ms\n",
5638*0f4c859eSApple OSS Distributions nextObject->whatObject->getName(),
5639*0f4c859eSApple OSS Distributions (fDriverCallReason == kDriverCallInformPreChange) ? "Will" : "Did",
5640*0f4c859eSApple OSS Distributions OBFUSCATE(nextObject->whatObject), fName, fCurrentPowerState, fHeadNotePowerState,
5641*0f4c859eSApple OSS Distributions NS_TO_MS(nsec));
5642*0f4c859eSApple OSS Distributions
5643*0f4c859eSApple OSS Distributions // Pretend driver has acked.
5644*0f4c859eSApple OSS Distributions fHeadNotePendingAcks--;
5645*0f4c859eSApple OSS Distributions }
5646*0f4c859eSApple OSS Distributions }
5647*0f4c859eSApple OSS Distributions nextObject = fInterestedDrivers->nextInList(nextObject);
5648*0f4c859eSApple OSS Distributions }
5649*0f4c859eSApple OSS Distributions
5650*0f4c859eSApple OSS Distributions // is that the last?
5651*0f4c859eSApple OSS Distributions if (fHeadNotePendingAcks == 0) {
5652*0f4c859eSApple OSS Distributions // yes, we can continue
5653*0f4c859eSApple OSS Distributions done = true;
5654*0f4c859eSApple OSS Distributions getPMRootDomain()->reset_watchdog_timer(this, 0);
5655*0f4c859eSApple OSS Distributions } else {
5656*0f4c859eSApple OSS Distributions // no, set timer again
5657*0f4c859eSApple OSS Distributions start_ack_timer();
5658*0f4c859eSApple OSS Distributions }
5659*0f4c859eSApple OSS Distributions }
5660*0f4c859eSApple OSS Distributions break;
5661*0f4c859eSApple OSS Distributions
5662*0f4c859eSApple OSS Distributions // TODO: aggreggate this
5663*0f4c859eSApple OSS Distributions case kIOPM_OurChangeTellClientsPowerDown:
5664*0f4c859eSApple OSS Distributions case kIOPM_OurChangeTellUserPMPolicyPowerDown:
5665*0f4c859eSApple OSS Distributions case kIOPM_OurChangeTellPriorityClientsPowerDown:
5666*0f4c859eSApple OSS Distributions case kIOPM_OurChangeNotifyInterestedDriversWillChange:
5667*0f4c859eSApple OSS Distributions case kIOPM_ParentChangeTellPriorityClientsPowerDown:
5668*0f4c859eSApple OSS Distributions case kIOPM_ParentChangeNotifyInterestedDriversWillChange:
5669*0f4c859eSApple OSS Distributions case kIOPM_SyncTellClientsPowerDown:
5670*0f4c859eSApple OSS Distributions case kIOPM_SyncTellPriorityClientsPowerDown:
5671*0f4c859eSApple OSS Distributions case kIOPM_SyncNotifyWillChange:
5672*0f4c859eSApple OSS Distributions case kIOPM_TellCapabilityChangeDone:
5673*0f4c859eSApple OSS Distributions // apps didn't respond in time
5674*0f4c859eSApple OSS Distributions cleanClientResponses(true);
5675*0f4c859eSApple OSS Distributions OUR_PMLog(kPMLogClientTardy, 0, 1);
5676*0f4c859eSApple OSS Distributions // tardy equates to approval
5677*0f4c859eSApple OSS Distributions done = true;
5678*0f4c859eSApple OSS Distributions break;
5679*0f4c859eSApple OSS Distributions
5680*0f4c859eSApple OSS Distributions default:
5681*0f4c859eSApple OSS Distributions PM_LOG1("%s: unexpected ack timer tick (state = %d)\n",
5682*0f4c859eSApple OSS Distributions getName(), fMachineState);
5683*0f4c859eSApple OSS Distributions break;
5684*0f4c859eSApple OSS Distributions }
5685*0f4c859eSApple OSS Distributions return done;
5686*0f4c859eSApple OSS Distributions }
5687*0f4c859eSApple OSS Distributions
5688*0f4c859eSApple OSS Distributions //*********************************************************************************
5689*0f4c859eSApple OSS Distributions // [private] start_watchdog_timer
5690*0f4c859eSApple OSS Distributions //*********************************************************************************
5691*0f4c859eSApple OSS Distributions void
start_watchdog_timer(void)5692*0f4c859eSApple OSS Distributions IOService::start_watchdog_timer( void )
5693*0f4c859eSApple OSS Distributions {
5694*0f4c859eSApple OSS Distributions int timeout;
5695*0f4c859eSApple OSS Distributions uint64_t deadline;
5696*0f4c859eSApple OSS Distributions
5697*0f4c859eSApple OSS Distributions if (!fWatchdogTimer || (kIOSleepWakeWdogOff & gIOKitDebug)) {
5698*0f4c859eSApple OSS Distributions return;
5699*0f4c859eSApple OSS Distributions }
5700*0f4c859eSApple OSS Distributions
5701*0f4c859eSApple OSS Distributions IOLockLock(fWatchdogLock);
5702*0f4c859eSApple OSS Distributions
5703*0f4c859eSApple OSS Distributions timeout = getPMRootDomain()->getWatchdogTimeout();
5704*0f4c859eSApple OSS Distributions clock_interval_to_deadline(timeout, kSecondScale, &deadline);
5705*0f4c859eSApple OSS Distributions start_watchdog_timer(deadline);
5706*0f4c859eSApple OSS Distributions IOLockUnlock(fWatchdogLock);
5707*0f4c859eSApple OSS Distributions }
5708*0f4c859eSApple OSS Distributions
5709*0f4c859eSApple OSS Distributions void
start_watchdog_timer(uint64_t deadline)5710*0f4c859eSApple OSS Distributions IOService::start_watchdog_timer(uint64_t deadline)
5711*0f4c859eSApple OSS Distributions {
5712*0f4c859eSApple OSS Distributions IOLockAssert(fWatchdogLock, kIOLockAssertOwned);
5713*0f4c859eSApple OSS Distributions fWatchdogDeadline = deadline;
5714*0f4c859eSApple OSS Distributions
5715*0f4c859eSApple OSS Distributions if (!thread_call_isactive(fWatchdogTimer)) {
5716*0f4c859eSApple OSS Distributions thread_call_enter_delayed(fWatchdogTimer, deadline);
5717*0f4c859eSApple OSS Distributions }
5718*0f4c859eSApple OSS Distributions }
5719*0f4c859eSApple OSS Distributions
5720*0f4c859eSApple OSS Distributions //*********************************************************************************
5721*0f4c859eSApple OSS Distributions // [private] stop_watchdog_timer
5722*0f4c859eSApple OSS Distributions //*********************************************************************************
5723*0f4c859eSApple OSS Distributions
5724*0f4c859eSApple OSS Distributions void
stop_watchdog_timer(void)5725*0f4c859eSApple OSS Distributions IOService::stop_watchdog_timer( void )
5726*0f4c859eSApple OSS Distributions {
5727*0f4c859eSApple OSS Distributions if (!fWatchdogTimer || (kIOSleepWakeWdogOff & gIOKitDebug)) {
5728*0f4c859eSApple OSS Distributions return;
5729*0f4c859eSApple OSS Distributions }
5730*0f4c859eSApple OSS Distributions
5731*0f4c859eSApple OSS Distributions IOLockLock(fWatchdogLock);
5732*0f4c859eSApple OSS Distributions
5733*0f4c859eSApple OSS Distributions thread_call_cancel(fWatchdogTimer);
5734*0f4c859eSApple OSS Distributions fWatchdogDeadline = 0;
5735*0f4c859eSApple OSS Distributions
5736*0f4c859eSApple OSS Distributions while (fBlockedArray->getCount()) {
5737*0f4c859eSApple OSS Distributions IOService *obj = OSDynamicCast(IOService, fBlockedArray->getObject(0));
5738*0f4c859eSApple OSS Distributions if (obj) {
5739*0f4c859eSApple OSS Distributions PM_ERROR("WDOG:Object %s unexpected in blocked array\n", obj->fName);
5740*0f4c859eSApple OSS Distributions fBlockedArray->removeObject(0);
5741*0f4c859eSApple OSS Distributions }
5742*0f4c859eSApple OSS Distributions }
5743*0f4c859eSApple OSS Distributions
5744*0f4c859eSApple OSS Distributions IOLockUnlock(fWatchdogLock);
5745*0f4c859eSApple OSS Distributions }
5746*0f4c859eSApple OSS Distributions
5747*0f4c859eSApple OSS Distributions //*********************************************************************************
5748*0f4c859eSApple OSS Distributions // reset_watchdog_timer
5749*0f4c859eSApple OSS Distributions //*********************************************************************************
5750*0f4c859eSApple OSS Distributions
5751*0f4c859eSApple OSS Distributions void
reset_watchdog_timer(IOService * blockedObject,int pendingResponseTimeout)5752*0f4c859eSApple OSS Distributions IOService::reset_watchdog_timer(IOService *blockedObject, int pendingResponseTimeout)
5753*0f4c859eSApple OSS Distributions {
5754*0f4c859eSApple OSS Distributions unsigned int i;
5755*0f4c859eSApple OSS Distributions uint64_t deadline;
5756*0f4c859eSApple OSS Distributions IOService *obj;
5757*0f4c859eSApple OSS Distributions
5758*0f4c859eSApple OSS Distributions if (!fWatchdogTimer || (kIOSleepWakeWdogOff & gIOKitDebug)) {
5759*0f4c859eSApple OSS Distributions return;
5760*0f4c859eSApple OSS Distributions }
5761*0f4c859eSApple OSS Distributions
5762*0f4c859eSApple OSS Distributions
5763*0f4c859eSApple OSS Distributions IOLockLock(fWatchdogLock);
5764*0f4c859eSApple OSS Distributions if (!fWatchdogDeadline) {
5765*0f4c859eSApple OSS Distributions goto exit;
5766*0f4c859eSApple OSS Distributions }
5767*0f4c859eSApple OSS Distributions
5768*0f4c859eSApple OSS Distributions i = fBlockedArray->getNextIndexOfObject(blockedObject, 0);
5769*0f4c859eSApple OSS Distributions if (pendingResponseTimeout == 0) {
5770*0f4c859eSApple OSS Distributions blockedObject->fPendingResponseDeadline = 0;
5771*0f4c859eSApple OSS Distributions if (i == (unsigned int)-1) {
5772*0f4c859eSApple OSS Distributions goto exit;
5773*0f4c859eSApple OSS Distributions }
5774*0f4c859eSApple OSS Distributions fBlockedArray->removeObject(i);
5775*0f4c859eSApple OSS Distributions } else {
5776*0f4c859eSApple OSS Distributions // Set deadline 2secs after the expected response timeout to allow
5777*0f4c859eSApple OSS Distributions // ack timer to handle the timeout.
5778*0f4c859eSApple OSS Distributions clock_interval_to_deadline(pendingResponseTimeout + 2, kSecondScale, &deadline);
5779*0f4c859eSApple OSS Distributions
5780*0f4c859eSApple OSS Distributions if (i != (unsigned int)-1) {
5781*0f4c859eSApple OSS Distributions PM_ERROR("WDOG:Object %s is already blocked for responses. Ignoring timeout %d\n",
5782*0f4c859eSApple OSS Distributions fName, pendingResponseTimeout);
5783*0f4c859eSApple OSS Distributions goto exit;
5784*0f4c859eSApple OSS Distributions }
5785*0f4c859eSApple OSS Distributions
5786*0f4c859eSApple OSS Distributions for (i = 0; i < fBlockedArray->getCount(); i++) {
5787*0f4c859eSApple OSS Distributions obj = OSDynamicCast(IOService, fBlockedArray->getObject(i));
5788*0f4c859eSApple OSS Distributions if (obj && (obj->fPendingResponseDeadline < deadline)) {
5789*0f4c859eSApple OSS Distributions blockedObject->fPendingResponseDeadline = deadline;
5790*0f4c859eSApple OSS Distributions fBlockedArray->setObject(i, blockedObject);
5791*0f4c859eSApple OSS Distributions break;
5792*0f4c859eSApple OSS Distributions }
5793*0f4c859eSApple OSS Distributions }
5794*0f4c859eSApple OSS Distributions if (i == fBlockedArray->getCount()) {
5795*0f4c859eSApple OSS Distributions blockedObject->fPendingResponseDeadline = deadline;
5796*0f4c859eSApple OSS Distributions fBlockedArray->setObject(blockedObject);
5797*0f4c859eSApple OSS Distributions }
5798*0f4c859eSApple OSS Distributions }
5799*0f4c859eSApple OSS Distributions
5800*0f4c859eSApple OSS Distributions obj = OSDynamicCast(IOService, fBlockedArray->getObject(0));
5801*0f4c859eSApple OSS Distributions if (!obj) {
5802*0f4c859eSApple OSS Distributions int timeout = getPMRootDomain()->getWatchdogTimeout();
5803*0f4c859eSApple OSS Distributions clock_interval_to_deadline(timeout, kSecondScale, &deadline);
5804*0f4c859eSApple OSS Distributions } else {
5805*0f4c859eSApple OSS Distributions deadline = obj->fPendingResponseDeadline;
5806*0f4c859eSApple OSS Distributions }
5807*0f4c859eSApple OSS Distributions
5808*0f4c859eSApple OSS Distributions thread_call_cancel(fWatchdogTimer);
5809*0f4c859eSApple OSS Distributions start_watchdog_timer(deadline);
5810*0f4c859eSApple OSS Distributions
5811*0f4c859eSApple OSS Distributions exit:
5812*0f4c859eSApple OSS Distributions IOLockUnlock(fWatchdogLock);
5813*0f4c859eSApple OSS Distributions }
5814*0f4c859eSApple OSS Distributions
5815*0f4c859eSApple OSS Distributions
5816*0f4c859eSApple OSS Distributions //*********************************************************************************
5817*0f4c859eSApple OSS Distributions // [static] watchdog_timer_expired
5818*0f4c859eSApple OSS Distributions //
5819*0f4c859eSApple OSS Distributions // Inside PM work loop's gate.
5820*0f4c859eSApple OSS Distributions //*********************************************************************************
5821*0f4c859eSApple OSS Distributions
5822*0f4c859eSApple OSS Distributions void
watchdog_timer_expired(thread_call_param_t arg0,thread_call_param_t arg1)5823*0f4c859eSApple OSS Distributions IOService::watchdog_timer_expired( thread_call_param_t arg0, thread_call_param_t arg1 )
5824*0f4c859eSApple OSS Distributions {
5825*0f4c859eSApple OSS Distributions IOService * me = (IOService *) arg0;
5826*0f4c859eSApple OSS Distributions bool expired;
5827*0f4c859eSApple OSS Distributions
5828*0f4c859eSApple OSS Distributions IOLockLock(me->fWatchdogLock);
5829*0f4c859eSApple OSS Distributions expired = me->fWatchdogDeadline && (me->fWatchdogDeadline <= mach_absolute_time());
5830*0f4c859eSApple OSS Distributions IOLockUnlock(me->fWatchdogLock);
5831*0f4c859eSApple OSS Distributions if (!expired) {
5832*0f4c859eSApple OSS Distributions return;
5833*0f4c859eSApple OSS Distributions }
5834*0f4c859eSApple OSS Distributions
5835*0f4c859eSApple OSS Distributions gIOPMWatchDogThread = current_thread();
5836*0f4c859eSApple OSS Distributions getPMRootDomain()->sleepWakeDebugTrig(true);
5837*0f4c859eSApple OSS Distributions gIOPMWatchDogThread = NULL;
5838*0f4c859eSApple OSS Distributions thread_call_free(me->fWatchdogTimer);
5839*0f4c859eSApple OSS Distributions me->fWatchdogTimer = NULL;
5840*0f4c859eSApple OSS Distributions
5841*0f4c859eSApple OSS Distributions return;
5842*0f4c859eSApple OSS Distributions }
5843*0f4c859eSApple OSS Distributions
5844*0f4c859eSApple OSS Distributions
5845*0f4c859eSApple OSS Distributions IOWorkLoop *
getIOPMWorkloop(void)5846*0f4c859eSApple OSS Distributions IOService::getIOPMWorkloop( void )
5847*0f4c859eSApple OSS Distributions {
5848*0f4c859eSApple OSS Distributions return gIOPMWorkLoop;
5849*0f4c859eSApple OSS Distributions }
5850*0f4c859eSApple OSS Distributions
5851*0f4c859eSApple OSS Distributions
5852*0f4c859eSApple OSS Distributions
5853*0f4c859eSApple OSS Distributions //*********************************************************************************
5854*0f4c859eSApple OSS Distributions // [private] start_ack_timer
5855*0f4c859eSApple OSS Distributions //*********************************************************************************
5856*0f4c859eSApple OSS Distributions
5857*0f4c859eSApple OSS Distributions void
start_ack_timer(void)5858*0f4c859eSApple OSS Distributions IOService::start_ack_timer( void )
5859*0f4c859eSApple OSS Distributions {
5860*0f4c859eSApple OSS Distributions start_ack_timer( ACK_TIMER_PERIOD, kNanosecondScale );
5861*0f4c859eSApple OSS Distributions }
5862*0f4c859eSApple OSS Distributions
5863*0f4c859eSApple OSS Distributions void
start_ack_timer(UInt32 interval,UInt32 scale)5864*0f4c859eSApple OSS Distributions IOService::start_ack_timer( UInt32 interval, UInt32 scale )
5865*0f4c859eSApple OSS Distributions {
5866*0f4c859eSApple OSS Distributions AbsoluteTime deadline;
5867*0f4c859eSApple OSS Distributions boolean_t pending;
5868*0f4c859eSApple OSS Distributions
5869*0f4c859eSApple OSS Distributions clock_interval_to_deadline(interval, scale, &deadline);
5870*0f4c859eSApple OSS Distributions
5871*0f4c859eSApple OSS Distributions retain();
5872*0f4c859eSApple OSS Distributions pending = thread_call_enter_delayed(fAckTimer, deadline);
5873*0f4c859eSApple OSS Distributions if (pending) {
5874*0f4c859eSApple OSS Distributions release();
5875*0f4c859eSApple OSS Distributions }
5876*0f4c859eSApple OSS Distributions }
5877*0f4c859eSApple OSS Distributions
5878*0f4c859eSApple OSS Distributions //*********************************************************************************
5879*0f4c859eSApple OSS Distributions // [private] stop_ack_timer
5880*0f4c859eSApple OSS Distributions //*********************************************************************************
5881*0f4c859eSApple OSS Distributions
5882*0f4c859eSApple OSS Distributions void
stop_ack_timer(void)5883*0f4c859eSApple OSS Distributions IOService::stop_ack_timer( void )
5884*0f4c859eSApple OSS Distributions {
5885*0f4c859eSApple OSS Distributions boolean_t pending;
5886*0f4c859eSApple OSS Distributions
5887*0f4c859eSApple OSS Distributions pending = thread_call_cancel(fAckTimer);
5888*0f4c859eSApple OSS Distributions if (pending) {
5889*0f4c859eSApple OSS Distributions release();
5890*0f4c859eSApple OSS Distributions }
5891*0f4c859eSApple OSS Distributions }
5892*0f4c859eSApple OSS Distributions
5893*0f4c859eSApple OSS Distributions //*********************************************************************************
5894*0f4c859eSApple OSS Distributions // [static] actionAckTimerExpired
5895*0f4c859eSApple OSS Distributions //
5896*0f4c859eSApple OSS Distributions // Inside PM work loop's gate.
5897*0f4c859eSApple OSS Distributions //*********************************************************************************
5898*0f4c859eSApple OSS Distributions
5899*0f4c859eSApple OSS Distributions IOReturn
actionAckTimerExpired(OSObject * target,void * arg0,void * arg1,void * arg2,void * arg3)5900*0f4c859eSApple OSS Distributions IOService::actionAckTimerExpired(
5901*0f4c859eSApple OSS Distributions OSObject * target,
5902*0f4c859eSApple OSS Distributions void * arg0, void * arg1,
5903*0f4c859eSApple OSS Distributions void * arg2, void * arg3 )
5904*0f4c859eSApple OSS Distributions {
5905*0f4c859eSApple OSS Distributions IOService * me = (IOService *) target;
5906*0f4c859eSApple OSS Distributions bool done;
5907*0f4c859eSApple OSS Distributions
5908*0f4c859eSApple OSS Distributions // done will be true if the timer tick unblocks the machine state,
5909*0f4c859eSApple OSS Distributions // otherwise no need to signal the work loop.
5910*0f4c859eSApple OSS Distributions
5911*0f4c859eSApple OSS Distributions done = me->ackTimerTick();
5912*0f4c859eSApple OSS Distributions if (done && gIOPMWorkQueue) {
5913*0f4c859eSApple OSS Distributions gIOPMWorkQueue->signalWorkAvailable();
5914*0f4c859eSApple OSS Distributions }
5915*0f4c859eSApple OSS Distributions
5916*0f4c859eSApple OSS Distributions return kIOReturnSuccess;
5917*0f4c859eSApple OSS Distributions }
5918*0f4c859eSApple OSS Distributions
5919*0f4c859eSApple OSS Distributions //*********************************************************************************
5920*0f4c859eSApple OSS Distributions // ack_timer_expired
5921*0f4c859eSApple OSS Distributions //
5922*0f4c859eSApple OSS Distributions // Thread call function. Holds a retain while the callout is in flight.
5923*0f4c859eSApple OSS Distributions //*********************************************************************************
5924*0f4c859eSApple OSS Distributions
5925*0f4c859eSApple OSS Distributions void
ack_timer_expired(thread_call_param_t arg0,thread_call_param_t arg1)5926*0f4c859eSApple OSS Distributions IOService::ack_timer_expired( thread_call_param_t arg0, thread_call_param_t arg1 )
5927*0f4c859eSApple OSS Distributions {
5928*0f4c859eSApple OSS Distributions IOService * me = (IOService *) arg0;
5929*0f4c859eSApple OSS Distributions
5930*0f4c859eSApple OSS Distributions if (gIOPMWorkLoop) {
5931*0f4c859eSApple OSS Distributions gIOPMWorkLoop->runAction(&actionAckTimerExpired, me);
5932*0f4c859eSApple OSS Distributions }
5933*0f4c859eSApple OSS Distributions me->release();
5934*0f4c859eSApple OSS Distributions }
5935*0f4c859eSApple OSS Distributions
5936*0f4c859eSApple OSS Distributions
5937*0f4c859eSApple OSS Distributions // MARK: -
5938*0f4c859eSApple OSS Distributions // MARK: Client Messaging
5939*0f4c859eSApple OSS Distributions
5940*0f4c859eSApple OSS Distributions //*********************************************************************************
5941*0f4c859eSApple OSS Distributions // [private] tellSystemCapabilityChange
5942*0f4c859eSApple OSS Distributions //*********************************************************************************
5943*0f4c859eSApple OSS Distributions
5944*0f4c859eSApple OSS Distributions void
tellSystemCapabilityChange(uint32_t nextMS)5945*0f4c859eSApple OSS Distributions IOService::tellSystemCapabilityChange( uint32_t nextMS )
5946*0f4c859eSApple OSS Distributions {
5947*0f4c859eSApple OSS Distributions assert(IS_ROOT_DOMAIN);
5948*0f4c859eSApple OSS Distributions
5949*0f4c859eSApple OSS Distributions MS_PUSH( nextMS );
5950*0f4c859eSApple OSS Distributions fMachineState = kIOPM_TellCapabilityChangeDone;
5951*0f4c859eSApple OSS Distributions fOutOfBandMessage = kIOMessageSystemCapabilityChange;
5952*0f4c859eSApple OSS Distributions
5953*0f4c859eSApple OSS Distributions if (fIsPreChange) {
5954*0f4c859eSApple OSS Distributions // Notify app first on pre-change.
5955*0f4c859eSApple OSS Distributions fOutOfBandParameter = kNotifyCapabilityChangeApps;
5956*0f4c859eSApple OSS Distributions } else {
5957*0f4c859eSApple OSS Distributions // Notify kernel clients first on post-change.
5958*0f4c859eSApple OSS Distributions fOutOfBandParameter = kNotifyCapabilityChangePriority;
5959*0f4c859eSApple OSS Distributions }
5960*0f4c859eSApple OSS Distributions
5961*0f4c859eSApple OSS Distributions tellClientsWithResponse( fOutOfBandMessage );
5962*0f4c859eSApple OSS Distributions }
5963*0f4c859eSApple OSS Distributions
5964*0f4c859eSApple OSS Distributions //*********************************************************************************
5965*0f4c859eSApple OSS Distributions // [public] askChangeDown
5966*0f4c859eSApple OSS Distributions //
5967*0f4c859eSApple OSS Distributions // Ask registered applications and kernel clients if we can change to a lower
5968*0f4c859eSApple OSS Distributions // power state.
5969*0f4c859eSApple OSS Distributions //
5970*0f4c859eSApple OSS Distributions // Subclass can override this to send a different message type. Parameter is
5971*0f4c859eSApple OSS Distributions // the destination state number.
5972*0f4c859eSApple OSS Distributions //
5973*0f4c859eSApple OSS Distributions // Return true if we don't have to wait for acknowledgements
5974*0f4c859eSApple OSS Distributions //*********************************************************************************
5975*0f4c859eSApple OSS Distributions
5976*0f4c859eSApple OSS Distributions bool
askChangeDown(unsigned long stateNum)5977*0f4c859eSApple OSS Distributions IOService::askChangeDown( unsigned long stateNum )
5978*0f4c859eSApple OSS Distributions {
5979*0f4c859eSApple OSS Distributions return tellClientsWithResponse( kIOMessageCanDevicePowerOff );
5980*0f4c859eSApple OSS Distributions }
5981*0f4c859eSApple OSS Distributions
5982*0f4c859eSApple OSS Distributions //*********************************************************************************
5983*0f4c859eSApple OSS Distributions // [private] tellChangeDown1
5984*0f4c859eSApple OSS Distributions //
5985*0f4c859eSApple OSS Distributions // Notify registered applications and kernel clients that we are definitely
5986*0f4c859eSApple OSS Distributions // dropping power.
5987*0f4c859eSApple OSS Distributions //
5988*0f4c859eSApple OSS Distributions // Return true if we don't have to wait for acknowledgements
5989*0f4c859eSApple OSS Distributions //*********************************************************************************
5990*0f4c859eSApple OSS Distributions
5991*0f4c859eSApple OSS Distributions bool
tellChangeDown1(unsigned long stateNum)5992*0f4c859eSApple OSS Distributions IOService::tellChangeDown1( unsigned long stateNum )
5993*0f4c859eSApple OSS Distributions {
5994*0f4c859eSApple OSS Distributions fOutOfBandParameter = kNotifyApps;
5995*0f4c859eSApple OSS Distributions return tellChangeDown(stateNum);
5996*0f4c859eSApple OSS Distributions }
5997*0f4c859eSApple OSS Distributions
5998*0f4c859eSApple OSS Distributions //*********************************************************************************
5999*0f4c859eSApple OSS Distributions // [private] tellChangeDown2
6000*0f4c859eSApple OSS Distributions //
6001*0f4c859eSApple OSS Distributions // Notify priority clients that we are definitely dropping power.
6002*0f4c859eSApple OSS Distributions //
6003*0f4c859eSApple OSS Distributions // Return true if we don't have to wait for acknowledgements
6004*0f4c859eSApple OSS Distributions //*********************************************************************************
6005*0f4c859eSApple OSS Distributions
6006*0f4c859eSApple OSS Distributions bool
tellChangeDown2(unsigned long stateNum)6007*0f4c859eSApple OSS Distributions IOService::tellChangeDown2( unsigned long stateNum )
6008*0f4c859eSApple OSS Distributions {
6009*0f4c859eSApple OSS Distributions fOutOfBandParameter = kNotifyPriority;
6010*0f4c859eSApple OSS Distributions return tellChangeDown(stateNum);
6011*0f4c859eSApple OSS Distributions }
6012*0f4c859eSApple OSS Distributions
6013*0f4c859eSApple OSS Distributions //*********************************************************************************
6014*0f4c859eSApple OSS Distributions // [public] tellChangeDown
6015*0f4c859eSApple OSS Distributions //
6016*0f4c859eSApple OSS Distributions // Notify registered applications and kernel clients that we are definitely
6017*0f4c859eSApple OSS Distributions // dropping power.
6018*0f4c859eSApple OSS Distributions //
6019*0f4c859eSApple OSS Distributions // Subclass can override this to send a different message type. Parameter is
6020*0f4c859eSApple OSS Distributions // the destination state number.
6021*0f4c859eSApple OSS Distributions //
6022*0f4c859eSApple OSS Distributions // Return true if we don't have to wait for acknowledgements
6023*0f4c859eSApple OSS Distributions //*********************************************************************************
6024*0f4c859eSApple OSS Distributions
6025*0f4c859eSApple OSS Distributions bool
tellChangeDown(unsigned long stateNum)6026*0f4c859eSApple OSS Distributions IOService::tellChangeDown( unsigned long stateNum )
6027*0f4c859eSApple OSS Distributions {
6028*0f4c859eSApple OSS Distributions return tellClientsWithResponse( kIOMessageDeviceWillPowerOff );
6029*0f4c859eSApple OSS Distributions }
6030*0f4c859eSApple OSS Distributions
6031*0f4c859eSApple OSS Distributions //*********************************************************************************
6032*0f4c859eSApple OSS Distributions // cleanClientResponses
6033*0f4c859eSApple OSS Distributions //
6034*0f4c859eSApple OSS Distributions //*********************************************************************************
6035*0f4c859eSApple OSS Distributions
6036*0f4c859eSApple OSS Distributions static void
logAppTimeouts(OSObject * object,void * arg)6037*0f4c859eSApple OSS Distributions logAppTimeouts( OSObject * object, void * arg )
6038*0f4c859eSApple OSS Distributions {
6039*0f4c859eSApple OSS Distributions IOPMInterestContext * context = (IOPMInterestContext *) arg;
6040*0f4c859eSApple OSS Distributions OSObject * flag;
6041*0f4c859eSApple OSS Distributions unsigned int clientIndex;
6042*0f4c859eSApple OSS Distributions int pid = 0;
6043*0f4c859eSApple OSS Distributions char name[128];
6044*0f4c859eSApple OSS Distributions
6045*0f4c859eSApple OSS Distributions if (OSDynamicCast(_IOServiceInterestNotifier, object)) {
6046*0f4c859eSApple OSS Distributions // Discover the 'counter' value or index assigned to this client
6047*0f4c859eSApple OSS Distributions // when it was notified, by searching for the array index of the
6048*0f4c859eSApple OSS Distributions // client in an array holding the cached interested clients.
6049*0f4c859eSApple OSS Distributions
6050*0f4c859eSApple OSS Distributions clientIndex = context->notifyClients->getNextIndexOfObject(object, 0);
6051*0f4c859eSApple OSS Distributions
6052*0f4c859eSApple OSS Distributions if ((clientIndex != (unsigned int) -1) &&
6053*0f4c859eSApple OSS Distributions (flag = context->responseArray->getObject(clientIndex)) &&
6054*0f4c859eSApple OSS Distributions (flag != kOSBooleanTrue)) {
6055*0f4c859eSApple OSS Distributions OSNumber *clientID = copyClientIDForNotification(object, context);
6056*0f4c859eSApple OSS Distributions
6057*0f4c859eSApple OSS Distributions name[0] = '\0';
6058*0f4c859eSApple OSS Distributions if (clientID) {
6059*0f4c859eSApple OSS Distributions pid = clientID->unsigned32BitValue();
6060*0f4c859eSApple OSS Distributions proc_name(pid, name, sizeof(name));
6061*0f4c859eSApple OSS Distributions clientID->release();
6062*0f4c859eSApple OSS Distributions }
6063*0f4c859eSApple OSS Distributions
6064*0f4c859eSApple OSS Distributions PM_ERROR("PM notification timeout (pid %d, %s)\n", pid, name);
6065*0f4c859eSApple OSS Distributions
6066*0f4c859eSApple OSS Distributions // TODO: record message type if possible
6067*0f4c859eSApple OSS Distributions IOService::getPMRootDomain()->pmStatsRecordApplicationResponse(
6068*0f4c859eSApple OSS Distributions gIOPMStatsResponseTimedOut,
6069*0f4c859eSApple OSS Distributions name, 0, (30 * 1000), pid, object);
6070*0f4c859eSApple OSS Distributions }
6071*0f4c859eSApple OSS Distributions }
6072*0f4c859eSApple OSS Distributions }
6073*0f4c859eSApple OSS Distributions
6074*0f4c859eSApple OSS Distributions void
cleanClientResponses(bool logErrors)6075*0f4c859eSApple OSS Distributions IOService::cleanClientResponses( bool logErrors )
6076*0f4c859eSApple OSS Distributions {
6077*0f4c859eSApple OSS Distributions if (logErrors && fResponseArray) {
6078*0f4c859eSApple OSS Distributions switch (fOutOfBandParameter) {
6079*0f4c859eSApple OSS Distributions case kNotifyApps:
6080*0f4c859eSApple OSS Distributions case kNotifyCapabilityChangeApps:
6081*0f4c859eSApple OSS Distributions if (fNotifyClientArray) {
6082*0f4c859eSApple OSS Distributions IOPMInterestContext context;
6083*0f4c859eSApple OSS Distributions
6084*0f4c859eSApple OSS Distributions context.responseArray = fResponseArray;
6085*0f4c859eSApple OSS Distributions context.notifyClients = fNotifyClientArray;
6086*0f4c859eSApple OSS Distributions context.serialNumber = fSerialNumber;
6087*0f4c859eSApple OSS Distributions context.messageType = kIOMessageCopyClientID;
6088*0f4c859eSApple OSS Distributions context.notifyType = kNotifyApps;
6089*0f4c859eSApple OSS Distributions context.isPreChange = fIsPreChange;
6090*0f4c859eSApple OSS Distributions context.enableTracing = false;
6091*0f4c859eSApple OSS Distributions context.us = this;
6092*0f4c859eSApple OSS Distributions context.maxTimeRequested = 0;
6093*0f4c859eSApple OSS Distributions context.stateNumber = fHeadNotePowerState;
6094*0f4c859eSApple OSS Distributions context.stateFlags = fHeadNotePowerArrayEntry->capabilityFlags;
6095*0f4c859eSApple OSS Distributions context.changeFlags = fHeadNoteChangeFlags;
6096*0f4c859eSApple OSS Distributions
6097*0f4c859eSApple OSS Distributions applyToInterested(gIOAppPowerStateInterest, logAppTimeouts, (void *) &context);
6098*0f4c859eSApple OSS Distributions }
6099*0f4c859eSApple OSS Distributions break;
6100*0f4c859eSApple OSS Distributions
6101*0f4c859eSApple OSS Distributions default:
6102*0f4c859eSApple OSS Distributions // kNotifyPriority, kNotifyCapabilityChangePriority
6103*0f4c859eSApple OSS Distributions // TODO: identify the priority client that has not acked
6104*0f4c859eSApple OSS Distributions PM_ERROR("PM priority notification timeout\n");
6105*0f4c859eSApple OSS Distributions if (gIOKitDebug & kIOLogDebugPower) {
6106*0f4c859eSApple OSS Distributions panic("PM priority notification timeout");
6107*0f4c859eSApple OSS Distributions }
6108*0f4c859eSApple OSS Distributions break;
6109*0f4c859eSApple OSS Distributions }
6110*0f4c859eSApple OSS Distributions }
6111*0f4c859eSApple OSS Distributions
6112*0f4c859eSApple OSS Distributions if (IS_ROOT_DOMAIN) {
6113*0f4c859eSApple OSS Distributions getPMRootDomain()->reset_watchdog_timer(this, 0);
6114*0f4c859eSApple OSS Distributions }
6115*0f4c859eSApple OSS Distributions if (fResponseArray) {
6116*0f4c859eSApple OSS Distributions fResponseArray->release();
6117*0f4c859eSApple OSS Distributions fResponseArray = NULL;
6118*0f4c859eSApple OSS Distributions }
6119*0f4c859eSApple OSS Distributions if (fNotifyClientArray) {
6120*0f4c859eSApple OSS Distributions fNotifyClientArray->release();
6121*0f4c859eSApple OSS Distributions fNotifyClientArray = NULL;
6122*0f4c859eSApple OSS Distributions }
6123*0f4c859eSApple OSS Distributions }
6124*0f4c859eSApple OSS Distributions
6125*0f4c859eSApple OSS Distributions //*********************************************************************************
6126*0f4c859eSApple OSS Distributions // [protected] tellClientsWithResponse
6127*0f4c859eSApple OSS Distributions //
6128*0f4c859eSApple OSS Distributions // Notify registered applications and kernel clients that we are definitely
6129*0f4c859eSApple OSS Distributions // dropping power.
6130*0f4c859eSApple OSS Distributions //
6131*0f4c859eSApple OSS Distributions // Return true if we don't have to wait for acknowledgements
6132*0f4c859eSApple OSS Distributions //*********************************************************************************
6133*0f4c859eSApple OSS Distributions
6134*0f4c859eSApple OSS Distributions bool
tellClientsWithResponse(int messageType)6135*0f4c859eSApple OSS Distributions IOService::tellClientsWithResponse( int messageType )
6136*0f4c859eSApple OSS Distributions {
6137*0f4c859eSApple OSS Distributions IOPMInterestContext context;
6138*0f4c859eSApple OSS Distributions bool isRootDomain = IS_ROOT_DOMAIN;
6139*0f4c859eSApple OSS Distributions uint32_t maxTimeOut = kMaxTimeRequested;
6140*0f4c859eSApple OSS Distributions
6141*0f4c859eSApple OSS Distributions PM_ASSERT_IN_GATE();
6142*0f4c859eSApple OSS Distributions assert( fResponseArray == NULL );
6143*0f4c859eSApple OSS Distributions assert( fNotifyClientArray == NULL );
6144*0f4c859eSApple OSS Distributions
6145*0f4c859eSApple OSS Distributions RD_LOG("tellClientsWithResponse( %s, %s )\n", getIOMessageString(messageType),
6146*0f4c859eSApple OSS Distributions getNotificationPhaseString(fOutOfBandParameter));
6147*0f4c859eSApple OSS Distributions
6148*0f4c859eSApple OSS Distributions fResponseArray = OSArray::withCapacity( 1 );
6149*0f4c859eSApple OSS Distributions if (!fResponseArray) {
6150*0f4c859eSApple OSS Distributions goto exit;
6151*0f4c859eSApple OSS Distributions }
6152*0f4c859eSApple OSS Distributions
6153*0f4c859eSApple OSS Distributions fResponseArray->setCapacityIncrement(8);
6154*0f4c859eSApple OSS Distributions if (++fSerialNumber == 0) {
6155*0f4c859eSApple OSS Distributions fSerialNumber++;
6156*0f4c859eSApple OSS Distributions }
6157*0f4c859eSApple OSS Distributions
6158*0f4c859eSApple OSS Distributions context.responseArray = fResponseArray;
6159*0f4c859eSApple OSS Distributions context.notifyClients = NULL;
6160*0f4c859eSApple OSS Distributions context.serialNumber = fSerialNumber;
6161*0f4c859eSApple OSS Distributions context.messageType = messageType;
6162*0f4c859eSApple OSS Distributions context.notifyType = fOutOfBandParameter;
6163*0f4c859eSApple OSS Distributions context.skippedInDark = 0;
6164*0f4c859eSApple OSS Distributions context.notSkippedInDark = 0;
6165*0f4c859eSApple OSS Distributions context.isPreChange = fIsPreChange;
6166*0f4c859eSApple OSS Distributions context.enableTracing = false;
6167*0f4c859eSApple OSS Distributions context.us = this;
6168*0f4c859eSApple OSS Distributions context.maxTimeRequested = 0;
6169*0f4c859eSApple OSS Distributions context.stateNumber = fHeadNotePowerState;
6170*0f4c859eSApple OSS Distributions context.stateFlags = fHeadNotePowerArrayEntry->capabilityFlags;
6171*0f4c859eSApple OSS Distributions context.changeFlags = fHeadNoteChangeFlags;
6172*0f4c859eSApple OSS Distributions context.messageFilter = (isRootDomain) ?
6173*0f4c859eSApple OSS Distributions OSMemberFunctionCast(
6174*0f4c859eSApple OSS Distributions IOPMMessageFilter,
6175*0f4c859eSApple OSS Distributions (IOPMrootDomain *)this,
6176*0f4c859eSApple OSS Distributions &IOPMrootDomain::systemMessageFilter) : NULL;
6177*0f4c859eSApple OSS Distributions
6178*0f4c859eSApple OSS Distributions switch (fOutOfBandParameter) {
6179*0f4c859eSApple OSS Distributions case kNotifyApps:
6180*0f4c859eSApple OSS Distributions applyToInterested( gIOAppPowerStateInterest,
6181*0f4c859eSApple OSS Distributions pmTellAppWithResponse, (void *) &context );
6182*0f4c859eSApple OSS Distributions
6183*0f4c859eSApple OSS Distributions if (isRootDomain &&
6184*0f4c859eSApple OSS Distributions (fMachineState != kIOPM_OurChangeTellClientsPowerDown) &&
6185*0f4c859eSApple OSS Distributions (fMachineState != kIOPM_SyncTellClientsPowerDown) &&
6186*0f4c859eSApple OSS Distributions (context.messageType != kIOPMMessageLastCallBeforeSleep)) {
6187*0f4c859eSApple OSS Distributions // Notify capability app for tellChangeDown1()
6188*0f4c859eSApple OSS Distributions // but not for askChangeDown().
6189*0f4c859eSApple OSS Distributions context.notifyType = kNotifyCapabilityChangeApps;
6190*0f4c859eSApple OSS Distributions context.messageType = kIOMessageSystemCapabilityChange;
6191*0f4c859eSApple OSS Distributions applyToInterested( gIOAppPowerStateInterest,
6192*0f4c859eSApple OSS Distributions pmTellCapabilityAppWithResponse, (void *) &context );
6193*0f4c859eSApple OSS Distributions context.notifyType = fOutOfBandParameter;
6194*0f4c859eSApple OSS Distributions context.messageType = messageType;
6195*0f4c859eSApple OSS Distributions }
6196*0f4c859eSApple OSS Distributions if (context.messageType == kIOMessageCanSystemSleep) {
6197*0f4c859eSApple OSS Distributions maxTimeOut = kCanSleepMaxTimeReq;
6198*0f4c859eSApple OSS Distributions if (gSleepAckTimeout) {
6199*0f4c859eSApple OSS Distributions maxTimeOut = (gSleepAckTimeout * us_per_s);
6200*0f4c859eSApple OSS Distributions }
6201*0f4c859eSApple OSS Distributions }
6202*0f4c859eSApple OSS Distributions if (context.messageType == kIOMessageSystemWillSleep) {
6203*0f4c859eSApple OSS Distributions maxTimeOut = kWillSleepMaxTimeReq;
6204*0f4c859eSApple OSS Distributions if (gSleepAckTimeout) {
6205*0f4c859eSApple OSS Distributions maxTimeOut = (gSleepAckTimeout * us_per_s);
6206*0f4c859eSApple OSS Distributions }
6207*0f4c859eSApple OSS Distributions }
6208*0f4c859eSApple OSS Distributions context.maxTimeRequested = maxTimeOut;
6209*0f4c859eSApple OSS Distributions context.enableTracing = isRootDomain;
6210*0f4c859eSApple OSS Distributions applyToInterested( gIOGeneralInterest,
6211*0f4c859eSApple OSS Distributions pmTellClientWithResponse, (void *) &context );
6212*0f4c859eSApple OSS Distributions
6213*0f4c859eSApple OSS Distributions break;
6214*0f4c859eSApple OSS Distributions
6215*0f4c859eSApple OSS Distributions case kNotifyPriority:
6216*0f4c859eSApple OSS Distributions context.enableTracing = isRootDomain;
6217*0f4c859eSApple OSS Distributions applyToInterested( gIOPriorityPowerStateInterest,
6218*0f4c859eSApple OSS Distributions pmTellClientWithResponse, (void *) &context );
6219*0f4c859eSApple OSS Distributions
6220*0f4c859eSApple OSS Distributions if (isRootDomain) {
6221*0f4c859eSApple OSS Distributions // Notify capability clients for tellChangeDown2().
6222*0f4c859eSApple OSS Distributions context.notifyType = kNotifyCapabilityChangePriority;
6223*0f4c859eSApple OSS Distributions context.messageType = kIOMessageSystemCapabilityChange;
6224*0f4c859eSApple OSS Distributions applyToInterested( gIOPriorityPowerStateInterest,
6225*0f4c859eSApple OSS Distributions pmTellCapabilityClientWithResponse, (void *) &context );
6226*0f4c859eSApple OSS Distributions }
6227*0f4c859eSApple OSS Distributions break;
6228*0f4c859eSApple OSS Distributions
6229*0f4c859eSApple OSS Distributions case kNotifyCapabilityChangeApps:
6230*0f4c859eSApple OSS Distributions context.enableTracing = isRootDomain;
6231*0f4c859eSApple OSS Distributions applyToInterested( gIOAppPowerStateInterest,
6232*0f4c859eSApple OSS Distributions pmTellCapabilityAppWithResponse, (void *) &context );
6233*0f4c859eSApple OSS Distributions if (context.messageType == kIOMessageCanSystemSleep) {
6234*0f4c859eSApple OSS Distributions maxTimeOut = kCanSleepMaxTimeReq;
6235*0f4c859eSApple OSS Distributions if (gSleepAckTimeout) {
6236*0f4c859eSApple OSS Distributions maxTimeOut = (gSleepAckTimeout * us_per_s);
6237*0f4c859eSApple OSS Distributions }
6238*0f4c859eSApple OSS Distributions }
6239*0f4c859eSApple OSS Distributions context.maxTimeRequested = maxTimeOut;
6240*0f4c859eSApple OSS Distributions break;
6241*0f4c859eSApple OSS Distributions
6242*0f4c859eSApple OSS Distributions case kNotifyCapabilityChangePriority:
6243*0f4c859eSApple OSS Distributions context.enableTracing = isRootDomain;
6244*0f4c859eSApple OSS Distributions applyToInterested( gIOPriorityPowerStateInterest,
6245*0f4c859eSApple OSS Distributions pmTellCapabilityClientWithResponse, (void *) &context );
6246*0f4c859eSApple OSS Distributions break;
6247*0f4c859eSApple OSS Distributions }
6248*0f4c859eSApple OSS Distributions fNotifyClientArray = context.notifyClients;
6249*0f4c859eSApple OSS Distributions
6250*0f4c859eSApple OSS Distributions if (context.skippedInDark) {
6251*0f4c859eSApple OSS Distributions IOLog("tellClientsWithResponse(%s, %s) %d of %d skipped in dark\n",
6252*0f4c859eSApple OSS Distributions getIOMessageString(messageType), getNotificationPhaseString(fOutOfBandParameter),
6253*0f4c859eSApple OSS Distributions context.skippedInDark, context.skippedInDark + context.notSkippedInDark);
6254*0f4c859eSApple OSS Distributions }
6255*0f4c859eSApple OSS Distributions
6256*0f4c859eSApple OSS Distributions // do we have to wait for somebody?
6257*0f4c859eSApple OSS Distributions if (!checkForDone()) {
6258*0f4c859eSApple OSS Distributions OUR_PMLog(kPMLogStartAckTimer, context.maxTimeRequested, 0);
6259*0f4c859eSApple OSS Distributions if (context.enableTracing) {
6260*0f4c859eSApple OSS Distributions getPMRootDomain()->traceDetail(context.messageType, 0, context.maxTimeRequested / 1000);
6261*0f4c859eSApple OSS Distributions getPMRootDomain()->reset_watchdog_timer(this, context.maxTimeRequested / USEC_PER_SEC + 1);
6262*0f4c859eSApple OSS Distributions }
6263*0f4c859eSApple OSS Distributions start_ack_timer( context.maxTimeRequested / 1000, kMillisecondScale );
6264*0f4c859eSApple OSS Distributions return false;
6265*0f4c859eSApple OSS Distributions }
6266*0f4c859eSApple OSS Distributions
6267*0f4c859eSApple OSS Distributions exit:
6268*0f4c859eSApple OSS Distributions // everybody responded
6269*0f4c859eSApple OSS Distributions if (fResponseArray) {
6270*0f4c859eSApple OSS Distributions fResponseArray->release();
6271*0f4c859eSApple OSS Distributions fResponseArray = NULL;
6272*0f4c859eSApple OSS Distributions }
6273*0f4c859eSApple OSS Distributions if (fNotifyClientArray) {
6274*0f4c859eSApple OSS Distributions fNotifyClientArray->release();
6275*0f4c859eSApple OSS Distributions fNotifyClientArray = NULL;
6276*0f4c859eSApple OSS Distributions }
6277*0f4c859eSApple OSS Distributions
6278*0f4c859eSApple OSS Distributions return true;
6279*0f4c859eSApple OSS Distributions }
6280*0f4c859eSApple OSS Distributions
6281*0f4c859eSApple OSS Distributions //*********************************************************************************
6282*0f4c859eSApple OSS Distributions // [static private] pmTellAppWithResponse
6283*0f4c859eSApple OSS Distributions //
6284*0f4c859eSApple OSS Distributions // We send a message to an application, and we expect a response, so we compute a
6285*0f4c859eSApple OSS Distributions // cookie we can identify the response with.
6286*0f4c859eSApple OSS Distributions //*********************************************************************************
6287*0f4c859eSApple OSS Distributions
6288*0f4c859eSApple OSS Distributions void
pmTellAppWithResponse(OSObject * object,void * arg)6289*0f4c859eSApple OSS Distributions IOService::pmTellAppWithResponse( OSObject * object, void * arg )
6290*0f4c859eSApple OSS Distributions {
6291*0f4c859eSApple OSS Distributions IOPMInterestContext * context = (IOPMInterestContext *) arg;
6292*0f4c859eSApple OSS Distributions IOServicePM * pwrMgt = context->us->pwrMgt;
6293*0f4c859eSApple OSS Distributions uint32_t msgIndex, msgRef, msgType;
6294*0f4c859eSApple OSS Distributions OSNumber *clientID = NULL;
6295*0f4c859eSApple OSS Distributions proc_t proc = NULL;
6296*0f4c859eSApple OSS Distributions boolean_t proc_suspended = FALSE;
6297*0f4c859eSApple OSS Distributions OSObject * waitForReply = kOSBooleanTrue;
6298*0f4c859eSApple OSS Distributions #if LOG_APP_RESPONSE_TIMES
6299*0f4c859eSApple OSS Distributions AbsoluteTime now;
6300*0f4c859eSApple OSS Distributions #endif
6301*0f4c859eSApple OSS Distributions
6302*0f4c859eSApple OSS Distributions if (!OSDynamicCast(_IOServiceInterestNotifier, object)) {
6303*0f4c859eSApple OSS Distributions return;
6304*0f4c859eSApple OSS Distributions }
6305*0f4c859eSApple OSS Distributions
6306*0f4c859eSApple OSS Distributions if (context->us == getPMRootDomain()) {
6307*0f4c859eSApple OSS Distributions if ((clientID = copyClientIDForNotification(object, context))) {
6308*0f4c859eSApple OSS Distributions uint32_t clientPID = clientID->unsigned32BitValue();
6309*0f4c859eSApple OSS Distributions clientID->release();
6310*0f4c859eSApple OSS Distributions proc = proc_find(clientPID);
6311*0f4c859eSApple OSS Distributions
6312*0f4c859eSApple OSS Distributions if (proc) {
6313*0f4c859eSApple OSS Distributions proc_suspended = get_task_pidsuspended((task_t) proc_task(proc));
6314*0f4c859eSApple OSS Distributions if (proc_suspended) {
6315*0f4c859eSApple OSS Distributions logClientIDForNotification(object, context, "PMTellAppWithResponse - Suspended");
6316*0f4c859eSApple OSS Distributions } else if (getPMRootDomain()->isAOTMode() && get_task_suspended((task_t) proc_task(proc))) {
6317*0f4c859eSApple OSS Distributions proc_suspended = true;
6318*0f4c859eSApple OSS Distributions context->skippedInDark++;
6319*0f4c859eSApple OSS Distributions }
6320*0f4c859eSApple OSS Distributions proc_rele(proc);
6321*0f4c859eSApple OSS Distributions if (proc_suspended) {
6322*0f4c859eSApple OSS Distributions return;
6323*0f4c859eSApple OSS Distributions }
6324*0f4c859eSApple OSS Distributions }
6325*0f4c859eSApple OSS Distributions }
6326*0f4c859eSApple OSS Distributions }
6327*0f4c859eSApple OSS Distributions
6328*0f4c859eSApple OSS Distributions if (context->messageFilter &&
6329*0f4c859eSApple OSS Distributions !context->messageFilter(context->us, object, context, NULL, &waitForReply)) {
6330*0f4c859eSApple OSS Distributions if (kIOLogDebugPower & gIOKitDebug) {
6331*0f4c859eSApple OSS Distributions logClientIDForNotification(object, context, "DROP App");
6332*0f4c859eSApple OSS Distributions }
6333*0f4c859eSApple OSS Distributions return;
6334*0f4c859eSApple OSS Distributions }
6335*0f4c859eSApple OSS Distributions context->notSkippedInDark++;
6336*0f4c859eSApple OSS Distributions
6337*0f4c859eSApple OSS Distributions // Create client array (for tracking purposes) only if the service
6338*0f4c859eSApple OSS Distributions // has app clients. Usually only root domain does.
6339*0f4c859eSApple OSS Distributions if (NULL == context->notifyClients) {
6340*0f4c859eSApple OSS Distributions context->notifyClients = OSArray::withCapacity( 32 );
6341*0f4c859eSApple OSS Distributions }
6342*0f4c859eSApple OSS Distributions
6343*0f4c859eSApple OSS Distributions msgType = context->messageType;
6344*0f4c859eSApple OSS Distributions msgIndex = context->responseArray->getCount();
6345*0f4c859eSApple OSS Distributions msgRef = ((context->serialNumber & 0xFFFF) << 16) + (msgIndex & 0xFFFF);
6346*0f4c859eSApple OSS Distributions
6347*0f4c859eSApple OSS Distributions OUR_PMLog(kPMLogAppNotify, msgType, msgRef);
6348*0f4c859eSApple OSS Distributions if (kIOLogDebugPower & gIOKitDebug) {
6349*0f4c859eSApple OSS Distributions logClientIDForNotification(object, context, "MESG App");
6350*0f4c859eSApple OSS Distributions }
6351*0f4c859eSApple OSS Distributions
6352*0f4c859eSApple OSS Distributions if (waitForReply == kOSBooleanTrue) {
6353*0f4c859eSApple OSS Distributions OSNumber * num;
6354*0f4c859eSApple OSS Distributions clock_get_uptime(&now);
6355*0f4c859eSApple OSS Distributions num = OSNumber::withNumber(AbsoluteTime_to_scalar(&now), sizeof(uint64_t) * 8);
6356*0f4c859eSApple OSS Distributions if (num) {
6357*0f4c859eSApple OSS Distributions context->responseArray->setObject(msgIndex, num);
6358*0f4c859eSApple OSS Distributions num->release();
6359*0f4c859eSApple OSS Distributions } else {
6360*0f4c859eSApple OSS Distributions context->responseArray->setObject(msgIndex, kOSBooleanFalse);
6361*0f4c859eSApple OSS Distributions }
6362*0f4c859eSApple OSS Distributions } else {
6363*0f4c859eSApple OSS Distributions context->responseArray->setObject(msgIndex, kOSBooleanTrue);
6364*0f4c859eSApple OSS Distributions if (kIOLogDebugPower & gIOKitDebug) {
6365*0f4c859eSApple OSS Distributions logClientIDForNotification(object, context, "App response ignored");
6366*0f4c859eSApple OSS Distributions }
6367*0f4c859eSApple OSS Distributions }
6368*0f4c859eSApple OSS Distributions
6369*0f4c859eSApple OSS Distributions if (context->notifyClients) {
6370*0f4c859eSApple OSS Distributions context->notifyClients->setObject(msgIndex, object);
6371*0f4c859eSApple OSS Distributions }
6372*0f4c859eSApple OSS Distributions
6373*0f4c859eSApple OSS Distributions context->us->messageClient(msgType, object, (void *)(uintptr_t) msgRef);
6374*0f4c859eSApple OSS Distributions }
6375*0f4c859eSApple OSS Distributions
6376*0f4c859eSApple OSS Distributions //*********************************************************************************
6377*0f4c859eSApple OSS Distributions // [static private] pmTellClientWithResponse
6378*0f4c859eSApple OSS Distributions //
6379*0f4c859eSApple OSS Distributions // We send a message to an in-kernel client, and we expect a response,
6380*0f4c859eSApple OSS Distributions // so we compute a cookie we can identify the response with.
6381*0f4c859eSApple OSS Distributions //*********************************************************************************
6382*0f4c859eSApple OSS Distributions
6383*0f4c859eSApple OSS Distributions void
pmTellClientWithResponse(OSObject * object,void * arg)6384*0f4c859eSApple OSS Distributions IOService::pmTellClientWithResponse( OSObject * object, void * arg )
6385*0f4c859eSApple OSS Distributions {
6386*0f4c859eSApple OSS Distributions IOPowerStateChangeNotification notify;
6387*0f4c859eSApple OSS Distributions IOPMInterestContext * context = (IOPMInterestContext *) arg;
6388*0f4c859eSApple OSS Distributions OSObject * replied = kOSBooleanTrue;
6389*0f4c859eSApple OSS Distributions _IOServiceInterestNotifier * notifier;
6390*0f4c859eSApple OSS Distributions uint32_t msgIndex, msgRef, msgType;
6391*0f4c859eSApple OSS Distributions IOReturn retCode;
6392*0f4c859eSApple OSS Distributions AbsoluteTime start, end;
6393*0f4c859eSApple OSS Distributions uint64_t nsec;
6394*0f4c859eSApple OSS Distributions bool enableTracing;
6395*0f4c859eSApple OSS Distributions
6396*0f4c859eSApple OSS Distributions if (context->messageFilter &&
6397*0f4c859eSApple OSS Distributions !context->messageFilter(context->us, object, context, NULL, NULL)) {
6398*0f4c859eSApple OSS Distributions getPMRootDomain()->traceFilteredNotification(object);
6399*0f4c859eSApple OSS Distributions return;
6400*0f4c859eSApple OSS Distributions }
6401*0f4c859eSApple OSS Distributions
6402*0f4c859eSApple OSS Distributions // Besides interest notifiers this applier function can also be invoked against
6403*0f4c859eSApple OSS Distributions // IOService clients of context->us, so notifier can be NULL. But for tracing
6404*0f4c859eSApple OSS Distributions // purposes the IOService clients can be ignored but each will still consume
6405*0f4c859eSApple OSS Distributions // an entry in the responseArray and also advance msgIndex.
6406*0f4c859eSApple OSS Distributions notifier = OSDynamicCast(_IOServiceInterestNotifier, object);
6407*0f4c859eSApple OSS Distributions msgType = context->messageType;
6408*0f4c859eSApple OSS Distributions msgIndex = context->responseArray->getCount();
6409*0f4c859eSApple OSS Distributions msgRef = ((context->serialNumber & 0xFFFF) << 16) + (msgIndex & 0xFFFF);
6410*0f4c859eSApple OSS Distributions enableTracing = context->enableTracing && (notifier != NULL);
6411*0f4c859eSApple OSS Distributions
6412*0f4c859eSApple OSS Distributions IOServicePM * pwrMgt = context->us->pwrMgt;
6413*0f4c859eSApple OSS Distributions if (gIOKitDebug & kIOLogPower) {
6414*0f4c859eSApple OSS Distributions OUR_PMLog(kPMLogClientNotify, msgRef, msgType);
6415*0f4c859eSApple OSS Distributions if (OSDynamicCast(IOService, object)) {
6416*0f4c859eSApple OSS Distributions const char *who = ((IOService *) object)->getName();
6417*0f4c859eSApple OSS Distributions gPlatform->PMLog(who, kPMLogClientNotify, (uintptr_t) object, 0);
6418*0f4c859eSApple OSS Distributions } else if (notifier) {
6419*0f4c859eSApple OSS Distributions OUR_PMLog(kPMLogClientNotify, (uintptr_t) notifier->handler, 0);
6420*0f4c859eSApple OSS Distributions }
6421*0f4c859eSApple OSS Distributions }
6422*0f4c859eSApple OSS Distributions
6423*0f4c859eSApple OSS Distributions if (NULL == context->notifyClients) {
6424*0f4c859eSApple OSS Distributions context->notifyClients = OSArray::withCapacity(32);
6425*0f4c859eSApple OSS Distributions assert(context->notifyClients != NULL);
6426*0f4c859eSApple OSS Distributions }
6427*0f4c859eSApple OSS Distributions
6428*0f4c859eSApple OSS Distributions notify.powerRef = (void *)(uintptr_t) msgRef;
6429*0f4c859eSApple OSS Distributions notify.returnValue = 0;
6430*0f4c859eSApple OSS Distributions notify.stateNumber = context->stateNumber;
6431*0f4c859eSApple OSS Distributions notify.stateFlags = context->stateFlags;
6432*0f4c859eSApple OSS Distributions
6433*0f4c859eSApple OSS Distributions clock_get_uptime(&start);
6434*0f4c859eSApple OSS Distributions if (enableTracing) {
6435*0f4c859eSApple OSS Distributions getPMRootDomain()->traceNotification(notifier, true, start, msgIndex);
6436*0f4c859eSApple OSS Distributions }
6437*0f4c859eSApple OSS Distributions
6438*0f4c859eSApple OSS Distributions retCode = context->us->messageClient(msgType, object, (void *) ¬ify, sizeof(notify));
6439*0f4c859eSApple OSS Distributions
6440*0f4c859eSApple OSS Distributions clock_get_uptime(&end);
6441*0f4c859eSApple OSS Distributions if (enableTracing) {
6442*0f4c859eSApple OSS Distributions getPMRootDomain()->traceNotification(notifier, false, end);
6443*0f4c859eSApple OSS Distributions }
6444*0f4c859eSApple OSS Distributions
6445*0f4c859eSApple OSS Distributions if (kIOReturnSuccess == retCode) {
6446*0f4c859eSApple OSS Distributions if (0 == notify.returnValue) {
6447*0f4c859eSApple OSS Distributions OUR_PMLog(kPMLogClientAcknowledge, msgRef, (uintptr_t) object);
6448*0f4c859eSApple OSS Distributions context->responseArray->setObject(msgIndex, replied);
6449*0f4c859eSApple OSS Distributions } else {
6450*0f4c859eSApple OSS Distributions replied = kOSBooleanFalse;
6451*0f4c859eSApple OSS Distributions uint32_t ackTimeRequested = (uint32_t) notify.returnValue;
6452*0f4c859eSApple OSS Distributions if (notify.returnValue > context->maxTimeRequested) {
6453*0f4c859eSApple OSS Distributions if (notify.returnValue > kPriorityClientMaxWait) {
6454*0f4c859eSApple OSS Distributions context->maxTimeRequested = ackTimeRequested = kPriorityClientMaxWait;
6455*0f4c859eSApple OSS Distributions PM_ERROR("%s: client %p returned %llu for %s\n",
6456*0f4c859eSApple OSS Distributions context->us->getName(),
6457*0f4c859eSApple OSS Distributions notifier ? (void *) OBFUSCATE(notifier->handler) : OBFUSCATE(object),
6458*0f4c859eSApple OSS Distributions (uint64_t) notify.returnValue,
6459*0f4c859eSApple OSS Distributions getIOMessageString(msgType));
6460*0f4c859eSApple OSS Distributions } else {
6461*0f4c859eSApple OSS Distributions context->maxTimeRequested = (typeof(context->maxTimeRequested))notify.returnValue;
6462*0f4c859eSApple OSS Distributions }
6463*0f4c859eSApple OSS Distributions }
6464*0f4c859eSApple OSS Distributions
6465*0f4c859eSApple OSS Distributions // Track acknowledgements by storing the timestamp of
6466*0f4c859eSApple OSS Distributions // callback completion and requested ack time.
6467*0f4c859eSApple OSS Distributions IOPMClientAck *ackState = new IOPMClientAck;
6468*0f4c859eSApple OSS Distributions if (ackState) {
6469*0f4c859eSApple OSS Distributions ackState->completionTimestamp = AbsoluteTime_to_scalar(&end);
6470*0f4c859eSApple OSS Distributions ackState->maxTimeRequested = ackTimeRequested;
6471*0f4c859eSApple OSS Distributions context->responseArray->setObject(msgIndex, ackState);
6472*0f4c859eSApple OSS Distributions } else {
6473*0f4c859eSApple OSS Distributions context->responseArray->setObject(msgIndex, replied);
6474*0f4c859eSApple OSS Distributions }
6475*0f4c859eSApple OSS Distributions }
6476*0f4c859eSApple OSS Distributions
6477*0f4c859eSApple OSS Distributions if (enableTracing) {
6478*0f4c859eSApple OSS Distributions SUB_ABSOLUTETIME(&end, &start);
6479*0f4c859eSApple OSS Distributions absolutetime_to_nanoseconds(end, &nsec);
6480*0f4c859eSApple OSS Distributions
6481*0f4c859eSApple OSS Distributions if ((nsec > LOG_KEXT_RESPONSE_TIMES) || (notify.returnValue != 0)) {
6482*0f4c859eSApple OSS Distributions getPMRootDomain()->traceNotificationResponse(notifier, NS_TO_MS(nsec), (uint32_t) notify.returnValue);
6483*0f4c859eSApple OSS Distributions }
6484*0f4c859eSApple OSS Distributions }
6485*0f4c859eSApple OSS Distributions } else {
6486*0f4c859eSApple OSS Distributions // not a client of ours
6487*0f4c859eSApple OSS Distributions // so we won't be waiting for response
6488*0f4c859eSApple OSS Distributions OUR_PMLog(kPMLogClientAcknowledge, msgRef, 0);
6489*0f4c859eSApple OSS Distributions context->responseArray->setObject(msgIndex, replied);
6490*0f4c859eSApple OSS Distributions }
6491*0f4c859eSApple OSS Distributions if (context->notifyClients) {
6492*0f4c859eSApple OSS Distributions context->notifyClients->setObject(msgIndex, object);
6493*0f4c859eSApple OSS Distributions }
6494*0f4c859eSApple OSS Distributions }
6495*0f4c859eSApple OSS Distributions
6496*0f4c859eSApple OSS Distributions //*********************************************************************************
6497*0f4c859eSApple OSS Distributions // [static private] pmTellCapabilityAppWithResponse
6498*0f4c859eSApple OSS Distributions //*********************************************************************************
6499*0f4c859eSApple OSS Distributions
6500*0f4c859eSApple OSS Distributions void
pmTellCapabilityAppWithResponse(OSObject * object,void * arg)6501*0f4c859eSApple OSS Distributions IOService::pmTellCapabilityAppWithResponse( OSObject * object, void * arg )
6502*0f4c859eSApple OSS Distributions {
6503*0f4c859eSApple OSS Distributions IOPMSystemCapabilityChangeParameters msgArg;
6504*0f4c859eSApple OSS Distributions IOPMInterestContext * context = (IOPMInterestContext *) arg;
6505*0f4c859eSApple OSS Distributions OSObject * waitForReply = kOSBooleanFalse;
6506*0f4c859eSApple OSS Distributions IOServicePM * pwrMgt = context->us->pwrMgt;
6507*0f4c859eSApple OSS Distributions uint32_t msgIndex, msgRef, msgType;
6508*0f4c859eSApple OSS Distributions #if LOG_APP_RESPONSE_TIMES
6509*0f4c859eSApple OSS Distributions AbsoluteTime now;
6510*0f4c859eSApple OSS Distributions #endif
6511*0f4c859eSApple OSS Distributions
6512*0f4c859eSApple OSS Distributions if (!OSDynamicCast(_IOServiceInterestNotifier, object)) {
6513*0f4c859eSApple OSS Distributions return;
6514*0f4c859eSApple OSS Distributions }
6515*0f4c859eSApple OSS Distributions
6516*0f4c859eSApple OSS Distributions memset(&msgArg, 0, sizeof(msgArg));
6517*0f4c859eSApple OSS Distributions if (context->messageFilter &&
6518*0f4c859eSApple OSS Distributions !context->messageFilter(context->us, object, context, &msgArg, &waitForReply)) {
6519*0f4c859eSApple OSS Distributions return;
6520*0f4c859eSApple OSS Distributions }
6521*0f4c859eSApple OSS Distributions
6522*0f4c859eSApple OSS Distributions if (context->us == getPMRootDomain() &&
6523*0f4c859eSApple OSS Distributions getPMRootDomain()->isAOTMode()
6524*0f4c859eSApple OSS Distributions ) {
6525*0f4c859eSApple OSS Distributions OSNumber *clientID = NULL;
6526*0f4c859eSApple OSS Distributions boolean_t proc_suspended = FALSE;
6527*0f4c859eSApple OSS Distributions proc_t proc = NULL;
6528*0f4c859eSApple OSS Distributions if ((clientID = copyClientIDForNotification(object, context))) {
6529*0f4c859eSApple OSS Distributions uint32_t clientPID = clientID->unsigned32BitValue();
6530*0f4c859eSApple OSS Distributions clientID->release();
6531*0f4c859eSApple OSS Distributions proc = proc_find(clientPID);
6532*0f4c859eSApple OSS Distributions if (proc) {
6533*0f4c859eSApple OSS Distributions proc_suspended = get_task_pidsuspended((task_t) proc_task(proc));
6534*0f4c859eSApple OSS Distributions if (proc_suspended) {
6535*0f4c859eSApple OSS Distributions logClientIDForNotification(object, context, "PMTellCapablityAppWithResponse - Suspended");
6536*0f4c859eSApple OSS Distributions } else if (get_task_suspended((task_t) proc_task(proc))) {
6537*0f4c859eSApple OSS Distributions proc_suspended = true;
6538*0f4c859eSApple OSS Distributions context->skippedInDark++;
6539*0f4c859eSApple OSS Distributions }
6540*0f4c859eSApple OSS Distributions proc_rele(proc);
6541*0f4c859eSApple OSS Distributions if (proc_suspended) {
6542*0f4c859eSApple OSS Distributions return;
6543*0f4c859eSApple OSS Distributions }
6544*0f4c859eSApple OSS Distributions }
6545*0f4c859eSApple OSS Distributions }
6546*0f4c859eSApple OSS Distributions }
6547*0f4c859eSApple OSS Distributions context->notSkippedInDark++;
6548*0f4c859eSApple OSS Distributions
6549*0f4c859eSApple OSS Distributions // Create client array (for tracking purposes) only if the service
6550*0f4c859eSApple OSS Distributions // has app clients. Usually only root domain does.
6551*0f4c859eSApple OSS Distributions if (NULL == context->notifyClients) {
6552*0f4c859eSApple OSS Distributions context->notifyClients = OSArray::withCapacity(32);
6553*0f4c859eSApple OSS Distributions assert(context->notifyClients != NULL);
6554*0f4c859eSApple OSS Distributions }
6555*0f4c859eSApple OSS Distributions
6556*0f4c859eSApple OSS Distributions msgType = context->messageType;
6557*0f4c859eSApple OSS Distributions msgIndex = context->responseArray->getCount();
6558*0f4c859eSApple OSS Distributions msgRef = ((context->serialNumber & 0xFFFF) << 16) + (msgIndex & 0xFFFF);
6559*0f4c859eSApple OSS Distributions
6560*0f4c859eSApple OSS Distributions OUR_PMLog(kPMLogAppNotify, msgType, msgRef);
6561*0f4c859eSApple OSS Distributions if (kIOLogDebugPower & gIOKitDebug) {
6562*0f4c859eSApple OSS Distributions // Log client pid/name and client array index.
6563*0f4c859eSApple OSS Distributions OSNumber * clientID = NULL;
6564*0f4c859eSApple OSS Distributions OSString * clientIDString = NULL;
6565*0f4c859eSApple OSS Distributions context->us->messageClient(kIOMessageCopyClientID, object, &clientID);
6566*0f4c859eSApple OSS Distributions if (clientID) {
6567*0f4c859eSApple OSS Distributions clientIDString = IOCopyLogNameForPID(clientID->unsigned32BitValue());
6568*0f4c859eSApple OSS Distributions }
6569*0f4c859eSApple OSS Distributions
6570*0f4c859eSApple OSS Distributions PM_LOG("%s MESG App(%u) %s, wait %u, %s\n",
6571*0f4c859eSApple OSS Distributions context->us->getName(),
6572*0f4c859eSApple OSS Distributions msgIndex, getIOMessageString(msgType),
6573*0f4c859eSApple OSS Distributions (waitForReply == kOSBooleanTrue),
6574*0f4c859eSApple OSS Distributions clientIDString ? clientIDString->getCStringNoCopy() : "");
6575*0f4c859eSApple OSS Distributions if (clientID) {
6576*0f4c859eSApple OSS Distributions clientID->release();
6577*0f4c859eSApple OSS Distributions }
6578*0f4c859eSApple OSS Distributions if (clientIDString) {
6579*0f4c859eSApple OSS Distributions clientIDString->release();
6580*0f4c859eSApple OSS Distributions }
6581*0f4c859eSApple OSS Distributions }
6582*0f4c859eSApple OSS Distributions
6583*0f4c859eSApple OSS Distributions msgArg.notifyRef = msgRef;
6584*0f4c859eSApple OSS Distributions msgArg.maxWaitForReply = 0;
6585*0f4c859eSApple OSS Distributions
6586*0f4c859eSApple OSS Distributions if (waitForReply == kOSBooleanFalse) {
6587*0f4c859eSApple OSS Distributions msgArg.notifyRef = 0;
6588*0f4c859eSApple OSS Distributions context->responseArray->setObject(msgIndex, kOSBooleanTrue);
6589*0f4c859eSApple OSS Distributions if (context->notifyClients) {
6590*0f4c859eSApple OSS Distributions context->notifyClients->setObject(msgIndex, kOSBooleanTrue);
6591*0f4c859eSApple OSS Distributions }
6592*0f4c859eSApple OSS Distributions } else {
6593*0f4c859eSApple OSS Distributions OSNumber * num;
6594*0f4c859eSApple OSS Distributions clock_get_uptime(&now);
6595*0f4c859eSApple OSS Distributions num = OSNumber::withNumber(AbsoluteTime_to_scalar(&now), sizeof(uint64_t) * 8);
6596*0f4c859eSApple OSS Distributions if (num) {
6597*0f4c859eSApple OSS Distributions context->responseArray->setObject(msgIndex, num);
6598*0f4c859eSApple OSS Distributions num->release();
6599*0f4c859eSApple OSS Distributions } else {
6600*0f4c859eSApple OSS Distributions context->responseArray->setObject(msgIndex, kOSBooleanFalse);
6601*0f4c859eSApple OSS Distributions }
6602*0f4c859eSApple OSS Distributions
6603*0f4c859eSApple OSS Distributions if (context->notifyClients) {
6604*0f4c859eSApple OSS Distributions context->notifyClients->setObject(msgIndex, object);
6605*0f4c859eSApple OSS Distributions }
6606*0f4c859eSApple OSS Distributions }
6607*0f4c859eSApple OSS Distributions
6608*0f4c859eSApple OSS Distributions context->us->messageClient(msgType, object, (void *) &msgArg, sizeof(msgArg));
6609*0f4c859eSApple OSS Distributions }
6610*0f4c859eSApple OSS Distributions
6611*0f4c859eSApple OSS Distributions //*********************************************************************************
6612*0f4c859eSApple OSS Distributions // [static private] pmTellCapabilityClientWithResponse
6613*0f4c859eSApple OSS Distributions //*********************************************************************************
6614*0f4c859eSApple OSS Distributions
6615*0f4c859eSApple OSS Distributions void
pmTellCapabilityClientWithResponse(OSObject * object,void * arg)6616*0f4c859eSApple OSS Distributions IOService::pmTellCapabilityClientWithResponse(
6617*0f4c859eSApple OSS Distributions OSObject * object, void * arg )
6618*0f4c859eSApple OSS Distributions {
6619*0f4c859eSApple OSS Distributions IOPMSystemCapabilityChangeParameters msgArg;
6620*0f4c859eSApple OSS Distributions IOPMInterestContext * context = (IOPMInterestContext *) arg;
6621*0f4c859eSApple OSS Distributions OSObject * replied = kOSBooleanTrue;
6622*0f4c859eSApple OSS Distributions _IOServiceInterestNotifier * notifier;
6623*0f4c859eSApple OSS Distributions uint32_t msgIndex, msgRef, msgType;
6624*0f4c859eSApple OSS Distributions IOReturn retCode;
6625*0f4c859eSApple OSS Distributions AbsoluteTime start, end;
6626*0f4c859eSApple OSS Distributions uint64_t nsec;
6627*0f4c859eSApple OSS Distributions bool enableTracing;
6628*0f4c859eSApple OSS Distributions
6629*0f4c859eSApple OSS Distributions memset(&msgArg, 0, sizeof(msgArg));
6630*0f4c859eSApple OSS Distributions if (context->messageFilter &&
6631*0f4c859eSApple OSS Distributions !context->messageFilter(context->us, object, context, &msgArg, NULL)) {
6632*0f4c859eSApple OSS Distributions getPMRootDomain()->traceFilteredNotification(object);
6633*0f4c859eSApple OSS Distributions return;
6634*0f4c859eSApple OSS Distributions }
6635*0f4c859eSApple OSS Distributions
6636*0f4c859eSApple OSS Distributions if (NULL == context->notifyClients) {
6637*0f4c859eSApple OSS Distributions context->notifyClients = OSArray::withCapacity(32);
6638*0f4c859eSApple OSS Distributions assert(context->notifyClients != NULL);
6639*0f4c859eSApple OSS Distributions }
6640*0f4c859eSApple OSS Distributions
6641*0f4c859eSApple OSS Distributions notifier = OSDynamicCast(_IOServiceInterestNotifier, object);
6642*0f4c859eSApple OSS Distributions msgType = context->messageType;
6643*0f4c859eSApple OSS Distributions msgIndex = context->responseArray->getCount();
6644*0f4c859eSApple OSS Distributions msgRef = ((context->serialNumber & 0xFFFF) << 16) + (msgIndex & 0xFFFF);
6645*0f4c859eSApple OSS Distributions enableTracing = context->enableTracing && (notifier != NULL);
6646*0f4c859eSApple OSS Distributions
6647*0f4c859eSApple OSS Distributions IOServicePM * pwrMgt = context->us->pwrMgt;
6648*0f4c859eSApple OSS Distributions if (gIOKitDebug & kIOLogPower) {
6649*0f4c859eSApple OSS Distributions OUR_PMLog(kPMLogClientNotify, msgRef, msgType);
6650*0f4c859eSApple OSS Distributions if (OSDynamicCast(IOService, object)) {
6651*0f4c859eSApple OSS Distributions const char *who = ((IOService *) object)->getName();
6652*0f4c859eSApple OSS Distributions gPlatform->PMLog(who, kPMLogClientNotify, (uintptr_t) object, 0);
6653*0f4c859eSApple OSS Distributions } else if (notifier) {
6654*0f4c859eSApple OSS Distributions OUR_PMLog(kPMLogClientNotify, (uintptr_t) notifier->handler, 0);
6655*0f4c859eSApple OSS Distributions }
6656*0f4c859eSApple OSS Distributions }
6657*0f4c859eSApple OSS Distributions
6658*0f4c859eSApple OSS Distributions msgArg.notifyRef = msgRef;
6659*0f4c859eSApple OSS Distributions msgArg.maxWaitForReply = 0;
6660*0f4c859eSApple OSS Distributions
6661*0f4c859eSApple OSS Distributions clock_get_uptime(&start);
6662*0f4c859eSApple OSS Distributions if (enableTracing) {
6663*0f4c859eSApple OSS Distributions getPMRootDomain()->traceNotification(notifier, true, start, msgIndex);
6664*0f4c859eSApple OSS Distributions }
6665*0f4c859eSApple OSS Distributions
6666*0f4c859eSApple OSS Distributions retCode = context->us->messageClient(msgType, object, (void *) &msgArg, sizeof(msgArg));
6667*0f4c859eSApple OSS Distributions
6668*0f4c859eSApple OSS Distributions clock_get_uptime(&end);
6669*0f4c859eSApple OSS Distributions if (enableTracing) {
6670*0f4c859eSApple OSS Distributions getPMRootDomain()->traceNotification(notifier, false, end, msgIndex);
6671*0f4c859eSApple OSS Distributions }
6672*0f4c859eSApple OSS Distributions
6673*0f4c859eSApple OSS Distributions if (kIOReturnSuccess == retCode) {
6674*0f4c859eSApple OSS Distributions if (0 == msgArg.maxWaitForReply) {
6675*0f4c859eSApple OSS Distributions // client doesn't want time to respond
6676*0f4c859eSApple OSS Distributions OUR_PMLog(kPMLogClientAcknowledge, msgRef, (uintptr_t) object);
6677*0f4c859eSApple OSS Distributions context->responseArray->setObject(msgIndex, replied);
6678*0f4c859eSApple OSS Distributions } else {
6679*0f4c859eSApple OSS Distributions replied = kOSBooleanFalse;
6680*0f4c859eSApple OSS Distributions uint32_t ackTimeRequested = msgArg.maxWaitForReply;
6681*0f4c859eSApple OSS Distributions if (msgArg.maxWaitForReply > context->maxTimeRequested) {
6682*0f4c859eSApple OSS Distributions if (msgArg.maxWaitForReply > kCapabilityClientMaxWait) {
6683*0f4c859eSApple OSS Distributions context->maxTimeRequested = ackTimeRequested = kCapabilityClientMaxWait;
6684*0f4c859eSApple OSS Distributions PM_ERROR("%s: client %p returned %u for %s\n",
6685*0f4c859eSApple OSS Distributions context->us->getName(),
6686*0f4c859eSApple OSS Distributions notifier ? (void *) OBFUSCATE(notifier->handler) : OBFUSCATE(object),
6687*0f4c859eSApple OSS Distributions msgArg.maxWaitForReply,
6688*0f4c859eSApple OSS Distributions getIOMessageString(msgType));
6689*0f4c859eSApple OSS Distributions } else {
6690*0f4c859eSApple OSS Distributions context->maxTimeRequested = msgArg.maxWaitForReply;
6691*0f4c859eSApple OSS Distributions }
6692*0f4c859eSApple OSS Distributions }
6693*0f4c859eSApple OSS Distributions
6694*0f4c859eSApple OSS Distributions // Track acknowledgements by storing the timestamp of
6695*0f4c859eSApple OSS Distributions // callback completion and requested ack time.
6696*0f4c859eSApple OSS Distributions IOPMClientAck *ackState = new IOPMClientAck;
6697*0f4c859eSApple OSS Distributions if (ackState) {
6698*0f4c859eSApple OSS Distributions ackState->completionTimestamp = AbsoluteTime_to_scalar(&end);
6699*0f4c859eSApple OSS Distributions ackState->maxTimeRequested = ackTimeRequested;
6700*0f4c859eSApple OSS Distributions context->responseArray->setObject(msgIndex, ackState);
6701*0f4c859eSApple OSS Distributions } else {
6702*0f4c859eSApple OSS Distributions context->responseArray->setObject(msgIndex, replied);
6703*0f4c859eSApple OSS Distributions }
6704*0f4c859eSApple OSS Distributions }
6705*0f4c859eSApple OSS Distributions
6706*0f4c859eSApple OSS Distributions if (enableTracing) {
6707*0f4c859eSApple OSS Distributions SUB_ABSOLUTETIME(&end, &start);
6708*0f4c859eSApple OSS Distributions absolutetime_to_nanoseconds(end, &nsec);
6709*0f4c859eSApple OSS Distributions
6710*0f4c859eSApple OSS Distributions if ((nsec > LOG_KEXT_RESPONSE_TIMES) || (msgArg.maxWaitForReply != 0)) {
6711*0f4c859eSApple OSS Distributions getPMRootDomain()->traceNotificationResponse(notifier, NS_TO_MS(nsec), msgArg.maxWaitForReply);
6712*0f4c859eSApple OSS Distributions }
6713*0f4c859eSApple OSS Distributions }
6714*0f4c859eSApple OSS Distributions } else {
6715*0f4c859eSApple OSS Distributions // not a client of ours
6716*0f4c859eSApple OSS Distributions // so we won't be waiting for response
6717*0f4c859eSApple OSS Distributions OUR_PMLog(kPMLogClientAcknowledge, msgRef, 0);
6718*0f4c859eSApple OSS Distributions context->responseArray->setObject(msgIndex, replied);
6719*0f4c859eSApple OSS Distributions }
6720*0f4c859eSApple OSS Distributions if (context->notifyClients) {
6721*0f4c859eSApple OSS Distributions context->notifyClients->setObject(msgIndex, object);
6722*0f4c859eSApple OSS Distributions }
6723*0f4c859eSApple OSS Distributions }
6724*0f4c859eSApple OSS Distributions
6725*0f4c859eSApple OSS Distributions //*********************************************************************************
6726*0f4c859eSApple OSS Distributions // [public] tellNoChangeDown
6727*0f4c859eSApple OSS Distributions //
6728*0f4c859eSApple OSS Distributions // Notify registered applications and kernel clients that we are not
6729*0f4c859eSApple OSS Distributions // dropping power.
6730*0f4c859eSApple OSS Distributions //
6731*0f4c859eSApple OSS Distributions // Subclass can override this to send a different message type. Parameter is
6732*0f4c859eSApple OSS Distributions // the aborted destination state number.
6733*0f4c859eSApple OSS Distributions //*********************************************************************************
6734*0f4c859eSApple OSS Distributions
6735*0f4c859eSApple OSS Distributions void
tellNoChangeDown(unsigned long)6736*0f4c859eSApple OSS Distributions IOService::tellNoChangeDown( unsigned long )
6737*0f4c859eSApple OSS Distributions {
6738*0f4c859eSApple OSS Distributions return tellClients( kIOMessageDeviceWillNotPowerOff );
6739*0f4c859eSApple OSS Distributions }
6740*0f4c859eSApple OSS Distributions
6741*0f4c859eSApple OSS Distributions //*********************************************************************************
6742*0f4c859eSApple OSS Distributions // [public] tellChangeUp
6743*0f4c859eSApple OSS Distributions //
6744*0f4c859eSApple OSS Distributions // Notify registered applications and kernel clients that we are raising power.
6745*0f4c859eSApple OSS Distributions //
6746*0f4c859eSApple OSS Distributions // Subclass can override this to send a different message type. Parameter is
6747*0f4c859eSApple OSS Distributions // the aborted destination state number.
6748*0f4c859eSApple OSS Distributions //*********************************************************************************
6749*0f4c859eSApple OSS Distributions
6750*0f4c859eSApple OSS Distributions void
tellChangeUp(unsigned long)6751*0f4c859eSApple OSS Distributions IOService::tellChangeUp( unsigned long )
6752*0f4c859eSApple OSS Distributions {
6753*0f4c859eSApple OSS Distributions return tellClients( kIOMessageDeviceHasPoweredOn );
6754*0f4c859eSApple OSS Distributions }
6755*0f4c859eSApple OSS Distributions
6756*0f4c859eSApple OSS Distributions //*********************************************************************************
6757*0f4c859eSApple OSS Distributions // [protected] tellClients
6758*0f4c859eSApple OSS Distributions //
6759*0f4c859eSApple OSS Distributions // Notify registered applications and kernel clients of something.
6760*0f4c859eSApple OSS Distributions //*********************************************************************************
6761*0f4c859eSApple OSS Distributions
6762*0f4c859eSApple OSS Distributions void
tellClients(int messageType)6763*0f4c859eSApple OSS Distributions IOService::tellClients( int messageType )
6764*0f4c859eSApple OSS Distributions {
6765*0f4c859eSApple OSS Distributions IOPMInterestContext context;
6766*0f4c859eSApple OSS Distributions
6767*0f4c859eSApple OSS Distributions RD_LOG("tellClients( %s )\n", getIOMessageString(messageType));
6768*0f4c859eSApple OSS Distributions
6769*0f4c859eSApple OSS Distributions memset(&context, 0, sizeof(context));
6770*0f4c859eSApple OSS Distributions context.messageType = messageType;
6771*0f4c859eSApple OSS Distributions context.isPreChange = fIsPreChange;
6772*0f4c859eSApple OSS Distributions context.us = this;
6773*0f4c859eSApple OSS Distributions context.stateNumber = fHeadNotePowerState;
6774*0f4c859eSApple OSS Distributions context.stateFlags = fHeadNotePowerArrayEntry->capabilityFlags;
6775*0f4c859eSApple OSS Distributions context.changeFlags = fHeadNoteChangeFlags;
6776*0f4c859eSApple OSS Distributions context.enableTracing = IS_ROOT_DOMAIN;
6777*0f4c859eSApple OSS Distributions context.messageFilter = (IS_ROOT_DOMAIN) ?
6778*0f4c859eSApple OSS Distributions OSMemberFunctionCast(
6779*0f4c859eSApple OSS Distributions IOPMMessageFilter,
6780*0f4c859eSApple OSS Distributions (IOPMrootDomain *)this,
6781*0f4c859eSApple OSS Distributions &IOPMrootDomain::systemMessageFilter) : NULL;
6782*0f4c859eSApple OSS Distributions
6783*0f4c859eSApple OSS Distributions context.notifyType = kNotifyPriority;
6784*0f4c859eSApple OSS Distributions applyToInterested( gIOPriorityPowerStateInterest,
6785*0f4c859eSApple OSS Distributions tellKernelClientApplier, (void *) &context );
6786*0f4c859eSApple OSS Distributions
6787*0f4c859eSApple OSS Distributions context.notifyType = kNotifyApps;
6788*0f4c859eSApple OSS Distributions applyToInterested( gIOAppPowerStateInterest,
6789*0f4c859eSApple OSS Distributions tellAppClientApplier, (void *) &context );
6790*0f4c859eSApple OSS Distributions
6791*0f4c859eSApple OSS Distributions applyToInterested( gIOGeneralInterest,
6792*0f4c859eSApple OSS Distributions tellKernelClientApplier, (void *) &context );
6793*0f4c859eSApple OSS Distributions }
6794*0f4c859eSApple OSS Distributions
6795*0f4c859eSApple OSS Distributions //*********************************************************************************
6796*0f4c859eSApple OSS Distributions // [private] tellKernelClientApplier
6797*0f4c859eSApple OSS Distributions //
6798*0f4c859eSApple OSS Distributions // Message a kernel client.
6799*0f4c859eSApple OSS Distributions //*********************************************************************************
6800*0f4c859eSApple OSS Distributions
6801*0f4c859eSApple OSS Distributions static void
tellKernelClientApplier(OSObject * object,void * arg)6802*0f4c859eSApple OSS Distributions tellKernelClientApplier( OSObject * object, void * arg )
6803*0f4c859eSApple OSS Distributions {
6804*0f4c859eSApple OSS Distributions IOPowerStateChangeNotification notify;
6805*0f4c859eSApple OSS Distributions IOPMInterestContext * context = (IOPMInterestContext *) arg;
6806*0f4c859eSApple OSS Distributions bool enableTracing = context->enableTracing;
6807*0f4c859eSApple OSS Distributions
6808*0f4c859eSApple OSS Distributions if (context->messageFilter &&
6809*0f4c859eSApple OSS Distributions !context->messageFilter(context->us, object, context, NULL, NULL)) {
6810*0f4c859eSApple OSS Distributions IOService::getPMRootDomain()->traceFilteredNotification(object);
6811*0f4c859eSApple OSS Distributions return;
6812*0f4c859eSApple OSS Distributions }
6813*0f4c859eSApple OSS Distributions
6814*0f4c859eSApple OSS Distributions notify.powerRef = (void *) NULL;
6815*0f4c859eSApple OSS Distributions notify.returnValue = 0;
6816*0f4c859eSApple OSS Distributions notify.stateNumber = context->stateNumber;
6817*0f4c859eSApple OSS Distributions notify.stateFlags = context->stateFlags;
6818*0f4c859eSApple OSS Distributions
6819*0f4c859eSApple OSS Distributions if (enableTracing) {
6820*0f4c859eSApple OSS Distributions IOService::getPMRootDomain()->traceNotification(object, true);
6821*0f4c859eSApple OSS Distributions }
6822*0f4c859eSApple OSS Distributions
6823*0f4c859eSApple OSS Distributions context->us->messageClient(context->messageType, object, ¬ify, sizeof(notify));
6824*0f4c859eSApple OSS Distributions
6825*0f4c859eSApple OSS Distributions if (enableTracing) {
6826*0f4c859eSApple OSS Distributions IOService::getPMRootDomain()->traceNotification(object, false);
6827*0f4c859eSApple OSS Distributions }
6828*0f4c859eSApple OSS Distributions }
6829*0f4c859eSApple OSS Distributions
6830*0f4c859eSApple OSS Distributions static OSNumber *
copyClientIDForNotification(OSObject * object,IOPMInterestContext * context)6831*0f4c859eSApple OSS Distributions copyClientIDForNotification(
6832*0f4c859eSApple OSS Distributions OSObject *object,
6833*0f4c859eSApple OSS Distributions IOPMInterestContext *context)
6834*0f4c859eSApple OSS Distributions {
6835*0f4c859eSApple OSS Distributions OSNumber *clientID = NULL;
6836*0f4c859eSApple OSS Distributions context->us->messageClient(kIOMessageCopyClientID, object, &clientID);
6837*0f4c859eSApple OSS Distributions return clientID;
6838*0f4c859eSApple OSS Distributions }
6839*0f4c859eSApple OSS Distributions
6840*0f4c859eSApple OSS Distributions static void
logClientIDForNotification(OSObject * object,IOPMInterestContext * context,const char * logString)6841*0f4c859eSApple OSS Distributions logClientIDForNotification(
6842*0f4c859eSApple OSS Distributions OSObject *object,
6843*0f4c859eSApple OSS Distributions IOPMInterestContext *context,
6844*0f4c859eSApple OSS Distributions const char *logString)
6845*0f4c859eSApple OSS Distributions {
6846*0f4c859eSApple OSS Distributions OSString *logClientID = NULL;
6847*0f4c859eSApple OSS Distributions OSNumber *clientID = copyClientIDForNotification(object, context);
6848*0f4c859eSApple OSS Distributions
6849*0f4c859eSApple OSS Distributions if (logString) {
6850*0f4c859eSApple OSS Distributions if (clientID) {
6851*0f4c859eSApple OSS Distributions logClientID = IOCopyLogNameForPID(clientID->unsigned32BitValue());
6852*0f4c859eSApple OSS Distributions }
6853*0f4c859eSApple OSS Distributions
6854*0f4c859eSApple OSS Distributions PM_LOG("%s %s %s, %s\n",
6855*0f4c859eSApple OSS Distributions context->us->getName(), logString,
6856*0f4c859eSApple OSS Distributions IOService::getIOMessageString(context->messageType),
6857*0f4c859eSApple OSS Distributions logClientID ? logClientID->getCStringNoCopy() : "");
6858*0f4c859eSApple OSS Distributions
6859*0f4c859eSApple OSS Distributions if (logClientID) {
6860*0f4c859eSApple OSS Distributions logClientID->release();
6861*0f4c859eSApple OSS Distributions }
6862*0f4c859eSApple OSS Distributions }
6863*0f4c859eSApple OSS Distributions
6864*0f4c859eSApple OSS Distributions if (clientID) {
6865*0f4c859eSApple OSS Distributions clientID->release();
6866*0f4c859eSApple OSS Distributions }
6867*0f4c859eSApple OSS Distributions
6868*0f4c859eSApple OSS Distributions return;
6869*0f4c859eSApple OSS Distributions }
6870*0f4c859eSApple OSS Distributions
6871*0f4c859eSApple OSS Distributions static void
tellAppClientApplier(OSObject * object,void * arg)6872*0f4c859eSApple OSS Distributions tellAppClientApplier( OSObject * object, void * arg )
6873*0f4c859eSApple OSS Distributions {
6874*0f4c859eSApple OSS Distributions IOPMInterestContext * context = (IOPMInterestContext *) arg;
6875*0f4c859eSApple OSS Distributions OSNumber * clientID = NULL;
6876*0f4c859eSApple OSS Distributions proc_t proc = NULL;
6877*0f4c859eSApple OSS Distributions boolean_t proc_suspended = FALSE;
6878*0f4c859eSApple OSS Distributions
6879*0f4c859eSApple OSS Distributions if (context->us == IOService::getPMRootDomain()) {
6880*0f4c859eSApple OSS Distributions if ((clientID = copyClientIDForNotification(object, context))) {
6881*0f4c859eSApple OSS Distributions uint32_t clientPID = clientID->unsigned32BitValue();
6882*0f4c859eSApple OSS Distributions clientID->release();
6883*0f4c859eSApple OSS Distributions proc = proc_find(clientPID);
6884*0f4c859eSApple OSS Distributions
6885*0f4c859eSApple OSS Distributions if (proc) {
6886*0f4c859eSApple OSS Distributions proc_suspended = get_task_pidsuspended((task_t) proc_task(proc));
6887*0f4c859eSApple OSS Distributions if (proc_suspended) {
6888*0f4c859eSApple OSS Distributions logClientIDForNotification(object, context, "tellAppClientApplier - Suspended");
6889*0f4c859eSApple OSS Distributions } else if (IOService::getPMRootDomain()->isAOTMode() && get_task_suspended((task_t) proc_task(proc))) {
6890*0f4c859eSApple OSS Distributions proc_suspended = true;
6891*0f4c859eSApple OSS Distributions context->skippedInDark++;
6892*0f4c859eSApple OSS Distributions }
6893*0f4c859eSApple OSS Distributions proc_rele(proc);
6894*0f4c859eSApple OSS Distributions if (proc_suspended) {
6895*0f4c859eSApple OSS Distributions return;
6896*0f4c859eSApple OSS Distributions }
6897*0f4c859eSApple OSS Distributions }
6898*0f4c859eSApple OSS Distributions }
6899*0f4c859eSApple OSS Distributions }
6900*0f4c859eSApple OSS Distributions
6901*0f4c859eSApple OSS Distributions if (context->messageFilter &&
6902*0f4c859eSApple OSS Distributions !context->messageFilter(context->us, object, context, NULL, NULL)) {
6903*0f4c859eSApple OSS Distributions if (kIOLogDebugPower & gIOKitDebug) {
6904*0f4c859eSApple OSS Distributions logClientIDForNotification(object, context, "DROP App");
6905*0f4c859eSApple OSS Distributions }
6906*0f4c859eSApple OSS Distributions return;
6907*0f4c859eSApple OSS Distributions }
6908*0f4c859eSApple OSS Distributions context->notSkippedInDark++;
6909*0f4c859eSApple OSS Distributions
6910*0f4c859eSApple OSS Distributions if (kIOLogDebugPower & gIOKitDebug) {
6911*0f4c859eSApple OSS Distributions logClientIDForNotification(object, context, "MESG App");
6912*0f4c859eSApple OSS Distributions }
6913*0f4c859eSApple OSS Distributions
6914*0f4c859eSApple OSS Distributions context->us->messageClient(context->messageType, object, NULL);
6915*0f4c859eSApple OSS Distributions }
6916*0f4c859eSApple OSS Distributions
6917*0f4c859eSApple OSS Distributions //*********************************************************************************
6918*0f4c859eSApple OSS Distributions // [private] checkForDone
6919*0f4c859eSApple OSS Distributions //*********************************************************************************
6920*0f4c859eSApple OSS Distributions
6921*0f4c859eSApple OSS Distributions bool
checkForDone(void)6922*0f4c859eSApple OSS Distributions IOService::checkForDone( void )
6923*0f4c859eSApple OSS Distributions {
6924*0f4c859eSApple OSS Distributions int i = 0;
6925*0f4c859eSApple OSS Distributions OSObject * theFlag;
6926*0f4c859eSApple OSS Distributions
6927*0f4c859eSApple OSS Distributions if (fResponseArray == NULL) {
6928*0f4c859eSApple OSS Distributions return true;
6929*0f4c859eSApple OSS Distributions }
6930*0f4c859eSApple OSS Distributions
6931*0f4c859eSApple OSS Distributions for (i = 0;; i++) {
6932*0f4c859eSApple OSS Distributions theFlag = fResponseArray->getObject(i);
6933*0f4c859eSApple OSS Distributions
6934*0f4c859eSApple OSS Distributions if (NULL == theFlag) {
6935*0f4c859eSApple OSS Distributions break;
6936*0f4c859eSApple OSS Distributions }
6937*0f4c859eSApple OSS Distributions
6938*0f4c859eSApple OSS Distributions if (kOSBooleanTrue != theFlag) {
6939*0f4c859eSApple OSS Distributions return false;
6940*0f4c859eSApple OSS Distributions }
6941*0f4c859eSApple OSS Distributions }
6942*0f4c859eSApple OSS Distributions return true;
6943*0f4c859eSApple OSS Distributions }
6944*0f4c859eSApple OSS Distributions
6945*0f4c859eSApple OSS Distributions //*********************************************************************************
6946*0f4c859eSApple OSS Distributions // [public] responseValid
6947*0f4c859eSApple OSS Distributions //*********************************************************************************
6948*0f4c859eSApple OSS Distributions
6949*0f4c859eSApple OSS Distributions bool
responseValid(uint32_t refcon,int pid)6950*0f4c859eSApple OSS Distributions IOService::responseValid( uint32_t refcon, int pid )
6951*0f4c859eSApple OSS Distributions {
6952*0f4c859eSApple OSS Distributions UInt16 serialComponent;
6953*0f4c859eSApple OSS Distributions UInt16 ordinalComponent;
6954*0f4c859eSApple OSS Distributions OSObject * theFlag;
6955*0f4c859eSApple OSS Distributions OSObject *object = NULL;
6956*0f4c859eSApple OSS Distributions
6957*0f4c859eSApple OSS Distributions serialComponent = (refcon >> 16) & 0xFFFF;
6958*0f4c859eSApple OSS Distributions ordinalComponent = (refcon & 0xFFFF);
6959*0f4c859eSApple OSS Distributions
6960*0f4c859eSApple OSS Distributions if (serialComponent != fSerialNumber) {
6961*0f4c859eSApple OSS Distributions return false;
6962*0f4c859eSApple OSS Distributions }
6963*0f4c859eSApple OSS Distributions
6964*0f4c859eSApple OSS Distributions if (fResponseArray == NULL) {
6965*0f4c859eSApple OSS Distributions return false;
6966*0f4c859eSApple OSS Distributions }
6967*0f4c859eSApple OSS Distributions
6968*0f4c859eSApple OSS Distributions theFlag = fResponseArray->getObject(ordinalComponent);
6969*0f4c859eSApple OSS Distributions
6970*0f4c859eSApple OSS Distributions if (theFlag == NULL) {
6971*0f4c859eSApple OSS Distributions return false;
6972*0f4c859eSApple OSS Distributions }
6973*0f4c859eSApple OSS Distributions
6974*0f4c859eSApple OSS Distributions if (fNotifyClientArray) {
6975*0f4c859eSApple OSS Distributions object = fNotifyClientArray->getObject(ordinalComponent);
6976*0f4c859eSApple OSS Distributions }
6977*0f4c859eSApple OSS Distributions
6978*0f4c859eSApple OSS Distributions OSNumber * num;
6979*0f4c859eSApple OSS Distributions IOPMClientAck *ack;
6980*0f4c859eSApple OSS Distributions if ((num = OSDynamicCast(OSNumber, theFlag)) || (ack = OSDynamicCast(IOPMClientAck, theFlag))) {
6981*0f4c859eSApple OSS Distributions AbsoluteTime now;
6982*0f4c859eSApple OSS Distributions AbsoluteTime start;
6983*0f4c859eSApple OSS Distributions uint64_t nsec;
6984*0f4c859eSApple OSS Distributions char name[128];
6985*0f4c859eSApple OSS Distributions
6986*0f4c859eSApple OSS Distributions clock_get_uptime(&now);
6987*0f4c859eSApple OSS Distributions AbsoluteTime_to_scalar(&start) = num ? num->unsigned64BitValue() : ack->completionTimestamp;
6988*0f4c859eSApple OSS Distributions SUB_ABSOLUTETIME(&now, &start);
6989*0f4c859eSApple OSS Distributions absolutetime_to_nanoseconds(now, &nsec);
6990*0f4c859eSApple OSS Distributions
6991*0f4c859eSApple OSS Distributions if (pid != 0) {
6992*0f4c859eSApple OSS Distributions name[0] = '\0';
6993*0f4c859eSApple OSS Distributions proc_name(pid, name, sizeof(name));
6994*0f4c859eSApple OSS Distributions
6995*0f4c859eSApple OSS Distributions if (nsec > LOG_APP_RESPONSE_TIMES) {
6996*0f4c859eSApple OSS Distributions IOLog("PM response took %d ms (%d, %s)\n", NS_TO_MS(nsec),
6997*0f4c859eSApple OSS Distributions pid, name);
6998*0f4c859eSApple OSS Distributions }
6999*0f4c859eSApple OSS Distributions
7000*0f4c859eSApple OSS Distributions if (nsec > LOG_APP_RESPONSE_MSG_TRACER) {
7001*0f4c859eSApple OSS Distributions // TODO: populate the messageType argument
7002*0f4c859eSApple OSS Distributions getPMRootDomain()->pmStatsRecordApplicationResponse(
7003*0f4c859eSApple OSS Distributions gIOPMStatsResponseSlow,
7004*0f4c859eSApple OSS Distributions name, 0, NS_TO_MS(nsec), pid, object);
7005*0f4c859eSApple OSS Distributions } else {
7006*0f4c859eSApple OSS Distributions getPMRootDomain()->pmStatsRecordApplicationResponse(
7007*0f4c859eSApple OSS Distributions gIOPMStatsResponsePrompt,
7008*0f4c859eSApple OSS Distributions name, 0, NS_TO_MS(nsec), pid, object);
7009*0f4c859eSApple OSS Distributions }
7010*0f4c859eSApple OSS Distributions } else {
7011*0f4c859eSApple OSS Distributions getPMRootDomain()->traceNotificationAck(object, NS_TO_MS(nsec));
7012*0f4c859eSApple OSS Distributions }
7013*0f4c859eSApple OSS Distributions
7014*0f4c859eSApple OSS Distributions if (kIOLogDebugPower & gIOKitDebug) {
7015*0f4c859eSApple OSS Distributions PM_LOG("Ack(%u) %u ms\n",
7016*0f4c859eSApple OSS Distributions (uint32_t) ordinalComponent,
7017*0f4c859eSApple OSS Distributions NS_TO_MS(nsec));
7018*0f4c859eSApple OSS Distributions }
7019*0f4c859eSApple OSS Distributions theFlag = kOSBooleanFalse;
7020*0f4c859eSApple OSS Distributions } else if (object) {
7021*0f4c859eSApple OSS Distributions getPMRootDomain()->pmStatsRecordApplicationResponse(
7022*0f4c859eSApple OSS Distributions gIOPMStatsResponsePrompt,
7023*0f4c859eSApple OSS Distributions NULL, 0, 0, pid, object);
7024*0f4c859eSApple OSS Distributions }
7025*0f4c859eSApple OSS Distributions
7026*0f4c859eSApple OSS Distributions if (kOSBooleanFalse == theFlag) {
7027*0f4c859eSApple OSS Distributions fResponseArray->replaceObject(ordinalComponent, kOSBooleanTrue);
7028*0f4c859eSApple OSS Distributions }
7029*0f4c859eSApple OSS Distributions
7030*0f4c859eSApple OSS Distributions return true;
7031*0f4c859eSApple OSS Distributions }
7032*0f4c859eSApple OSS Distributions
7033*0f4c859eSApple OSS Distributions //*********************************************************************************
7034*0f4c859eSApple OSS Distributions // [private] updateClientResponses
7035*0f4c859eSApple OSS Distributions //
7036*0f4c859eSApple OSS Distributions // Only affects clients informed in pmTellClientWithResponse() and
7037*0f4c859eSApple OSS Distributions // pmTellCapabilityClientWithResponse().
7038*0f4c859eSApple OSS Distributions //
7039*0f4c859eSApple OSS Distributions // Called upon every client acknowledgement to scan through the response array and
7040*0f4c859eSApple OSS Distributions // update the ack timer based on which clients have yet to acknowledge the power
7041*0f4c859eSApple OSS Distributions // change. If a client hasn't acknowledged by their requested time, make sure not
7042*0f4c859eSApple OSS Distributions // to wait on that client.
7043*0f4c859eSApple OSS Distributions //*********************************************************************************
7044*0f4c859eSApple OSS Distributions
7045*0f4c859eSApple OSS Distributions OSDefineMetaClassAndStructors( IOPMClientAck, OSObject );
7046*0f4c859eSApple OSS Distributions
7047*0f4c859eSApple OSS Distributions void
updateClientResponses(void)7048*0f4c859eSApple OSS Distributions IOService::updateClientResponses( void )
7049*0f4c859eSApple OSS Distributions {
7050*0f4c859eSApple OSS Distributions int i = 0;
7051*0f4c859eSApple OSS Distributions uint32_t maxTimeToAckMS = 0;
7052*0f4c859eSApple OSS Distributions bool editTimer = false;
7053*0f4c859eSApple OSS Distributions OSObject *obj;
7054*0f4c859eSApple OSS Distributions IOPMClientAck *ack;
7055*0f4c859eSApple OSS Distributions
7056*0f4c859eSApple OSS Distributions for (i = 0;; i++) {
7057*0f4c859eSApple OSS Distributions obj = fResponseArray->getObject(i);
7058*0f4c859eSApple OSS Distributions if (obj == NULL) {
7059*0f4c859eSApple OSS Distributions break;
7060*0f4c859eSApple OSS Distributions }
7061*0f4c859eSApple OSS Distributions
7062*0f4c859eSApple OSS Distributions // IOPMClientAck is used for pmTellClientWithResponse and
7063*0f4c859eSApple OSS Distributions // pmTellCapabilityClientWithResponse, no-op otherwise
7064*0f4c859eSApple OSS Distributions if ((ack = OSDynamicCast(IOPMClientAck, obj))) {
7065*0f4c859eSApple OSS Distributions AbsoluteTime now;
7066*0f4c859eSApple OSS Distributions AbsoluteTime start;
7067*0f4c859eSApple OSS Distributions uint64_t nsec;
7068*0f4c859eSApple OSS Distributions uint64_t timeRequestedNS = ack->maxTimeRequested * NSEC_PER_USEC;
7069*0f4c859eSApple OSS Distributions
7070*0f4c859eSApple OSS Distributions editTimer = true;
7071*0f4c859eSApple OSS Distributions
7072*0f4c859eSApple OSS Distributions // Calculate time since completion
7073*0f4c859eSApple OSS Distributions clock_get_uptime(&now);
7074*0f4c859eSApple OSS Distributions AbsoluteTime_to_scalar(&start) = ack->completionTimestamp;
7075*0f4c859eSApple OSS Distributions SUB_ABSOLUTETIME(&now, &start);
7076*0f4c859eSApple OSS Distributions absolutetime_to_nanoseconds(now, &nsec);
7077*0f4c859eSApple OSS Distributions if (nsec >= timeRequestedNS) {
7078*0f4c859eSApple OSS Distributions // Tardy; do not wait for this client
7079*0f4c859eSApple OSS Distributions fResponseArray->replaceObject(i, kOSBooleanTrue);
7080*0f4c859eSApple OSS Distributions } else {
7081*0f4c859eSApple OSS Distributions // Calculate time left to ack
7082*0f4c859eSApple OSS Distributions uint32_t timeToAckMS = NS_TO_MS(timeRequestedNS - nsec);
7083*0f4c859eSApple OSS Distributions maxTimeToAckMS = timeToAckMS > maxTimeToAckMS ? timeToAckMS : maxTimeToAckMS;
7084*0f4c859eSApple OSS Distributions }
7085*0f4c859eSApple OSS Distributions }
7086*0f4c859eSApple OSS Distributions }
7087*0f4c859eSApple OSS Distributions
7088*0f4c859eSApple OSS Distributions if (editTimer) {
7089*0f4c859eSApple OSS Distributions // Reset ack timer, but leave the PM watchdog set at the max client request
7090*0f4c859eSApple OSS Distributions // time.
7091*0f4c859eSApple OSS Distributions RD_LOG("resetting ack timer to %u ms\n", maxTimeToAckMS);
7092*0f4c859eSApple OSS Distributions stop_ack_timer();
7093*0f4c859eSApple OSS Distributions start_ack_timer(maxTimeToAckMS, kMillisecondScale);
7094*0f4c859eSApple OSS Distributions }
7095*0f4c859eSApple OSS Distributions }
7096*0f4c859eSApple OSS Distributions
7097*0f4c859eSApple OSS Distributions //*********************************************************************************
7098*0f4c859eSApple OSS Distributions // [public] allowPowerChange
7099*0f4c859eSApple OSS Distributions //
7100*0f4c859eSApple OSS Distributions // Our power state is about to lower, and we have notified applications
7101*0f4c859eSApple OSS Distributions // and kernel clients, and one of them has acknowledged. If this is the last to do
7102*0f4c859eSApple OSS Distributions // so, and all acknowledgements are positive, we continue with the power change.
7103*0f4c859eSApple OSS Distributions //*********************************************************************************
7104*0f4c859eSApple OSS Distributions
7105*0f4c859eSApple OSS Distributions IOReturn
allowPowerChange(unsigned long refcon)7106*0f4c859eSApple OSS Distributions IOService::allowPowerChange( unsigned long refcon )
7107*0f4c859eSApple OSS Distributions {
7108*0f4c859eSApple OSS Distributions IOPMRequest * request;
7109*0f4c859eSApple OSS Distributions
7110*0f4c859eSApple OSS Distributions if (!initialized) {
7111*0f4c859eSApple OSS Distributions // we're unloading
7112*0f4c859eSApple OSS Distributions return kIOReturnSuccess;
7113*0f4c859eSApple OSS Distributions }
7114*0f4c859eSApple OSS Distributions
7115*0f4c859eSApple OSS Distributions request = acquirePMRequest( this, kIOPMRequestTypeAllowPowerChange );
7116*0f4c859eSApple OSS Distributions if (!request) {
7117*0f4c859eSApple OSS Distributions return kIOReturnNoMemory;
7118*0f4c859eSApple OSS Distributions }
7119*0f4c859eSApple OSS Distributions
7120*0f4c859eSApple OSS Distributions request->fArg0 = (void *) refcon;
7121*0f4c859eSApple OSS Distributions request->fArg1 = (void *)(uintptr_t) proc_selfpid();
7122*0f4c859eSApple OSS Distributions request->fArg2 = (void *) NULL;
7123*0f4c859eSApple OSS Distributions submitPMRequest( request );
7124*0f4c859eSApple OSS Distributions
7125*0f4c859eSApple OSS Distributions return kIOReturnSuccess;
7126*0f4c859eSApple OSS Distributions }
7127*0f4c859eSApple OSS Distributions
7128*0f4c859eSApple OSS Distributions #ifndef __LP64__
7129*0f4c859eSApple OSS Distributions IOReturn
serializedAllowPowerChange2(unsigned long refcon)7130*0f4c859eSApple OSS Distributions IOService::serializedAllowPowerChange2( unsigned long refcon )
7131*0f4c859eSApple OSS Distributions {
7132*0f4c859eSApple OSS Distributions // [deprecated] public
7133*0f4c859eSApple OSS Distributions return kIOReturnUnsupported;
7134*0f4c859eSApple OSS Distributions }
7135*0f4c859eSApple OSS Distributions #endif /* !__LP64__ */
7136*0f4c859eSApple OSS Distributions
7137*0f4c859eSApple OSS Distributions //*********************************************************************************
7138*0f4c859eSApple OSS Distributions // [public] cancelPowerChange
7139*0f4c859eSApple OSS Distributions //
7140*0f4c859eSApple OSS Distributions // Our power state is about to lower, and we have notified applications
7141*0f4c859eSApple OSS Distributions // and kernel clients, and one of them has vetoed the change. If this is the last
7142*0f4c859eSApple OSS Distributions // client to respond, we abandon the power change.
7143*0f4c859eSApple OSS Distributions //*********************************************************************************
7144*0f4c859eSApple OSS Distributions
7145*0f4c859eSApple OSS Distributions IOReturn
cancelPowerChange(unsigned long refcon)7146*0f4c859eSApple OSS Distributions IOService::cancelPowerChange( unsigned long refcon )
7147*0f4c859eSApple OSS Distributions {
7148*0f4c859eSApple OSS Distributions IOPMRequest * request;
7149*0f4c859eSApple OSS Distributions char name[128];
7150*0f4c859eSApple OSS Distributions pid_t pid = proc_selfpid();
7151*0f4c859eSApple OSS Distributions
7152*0f4c859eSApple OSS Distributions if (!initialized) {
7153*0f4c859eSApple OSS Distributions // we're unloading
7154*0f4c859eSApple OSS Distributions return kIOReturnSuccess;
7155*0f4c859eSApple OSS Distributions }
7156*0f4c859eSApple OSS Distributions
7157*0f4c859eSApple OSS Distributions name[0] = '\0';
7158*0f4c859eSApple OSS Distributions proc_name(pid, name, sizeof(name));
7159*0f4c859eSApple OSS Distributions if (pid == 0) {
7160*0f4c859eSApple OSS Distributions const char *serviceName = this->getName();
7161*0f4c859eSApple OSS Distributions size_t len = strlen(name);
7162*0f4c859eSApple OSS Distributions snprintf(name + len, sizeof(name) - len, " (%s)", serviceName ? serviceName : "");
7163*0f4c859eSApple OSS Distributions }
7164*0f4c859eSApple OSS Distributions PM_ERROR("PM notification cancel (pid %d, %s)\n", pid, name);
7165*0f4c859eSApple OSS Distributions
7166*0f4c859eSApple OSS Distributions request = acquirePMRequest( this, kIOPMRequestTypeCancelPowerChange );
7167*0f4c859eSApple OSS Distributions if (!request) {
7168*0f4c859eSApple OSS Distributions return kIOReturnNoMemory;
7169*0f4c859eSApple OSS Distributions }
7170*0f4c859eSApple OSS Distributions
7171*0f4c859eSApple OSS Distributions request->fArg0 = (void *) refcon;
7172*0f4c859eSApple OSS Distributions request->fArg1 = (void *)(uintptr_t) proc_selfpid();
7173*0f4c859eSApple OSS Distributions request->fArg2 = (void *) OSString::withCString(name);
7174*0f4c859eSApple OSS Distributions submitPMRequest( request );
7175*0f4c859eSApple OSS Distributions
7176*0f4c859eSApple OSS Distributions return kIOReturnSuccess;
7177*0f4c859eSApple OSS Distributions }
7178*0f4c859eSApple OSS Distributions
7179*0f4c859eSApple OSS Distributions //*********************************************************************************
7180*0f4c859eSApple OSS Distributions // cancelIdlePowerDown
7181*0f4c859eSApple OSS Distributions //
7182*0f4c859eSApple OSS Distributions // Internal method to trigger an idle cancel or revert
7183*0f4c859eSApple OSS Distributions //*********************************************************************************
7184*0f4c859eSApple OSS Distributions
7185*0f4c859eSApple OSS Distributions void
cancelIdlePowerDown(IOService * service)7186*0f4c859eSApple OSS Distributions IOService::cancelIdlePowerDown( IOService * service )
7187*0f4c859eSApple OSS Distributions {
7188*0f4c859eSApple OSS Distributions IOPMRequest * request;
7189*0f4c859eSApple OSS Distributions
7190*0f4c859eSApple OSS Distributions request = acquirePMRequest(service, kIOPMRequestTypeIdleCancel);
7191*0f4c859eSApple OSS Distributions if (request) {
7192*0f4c859eSApple OSS Distributions submitPMRequest(request);
7193*0f4c859eSApple OSS Distributions }
7194*0f4c859eSApple OSS Distributions }
7195*0f4c859eSApple OSS Distributions
7196*0f4c859eSApple OSS Distributions #ifndef __LP64__
7197*0f4c859eSApple OSS Distributions IOReturn
serializedCancelPowerChange2(unsigned long refcon)7198*0f4c859eSApple OSS Distributions IOService::serializedCancelPowerChange2( unsigned long refcon )
7199*0f4c859eSApple OSS Distributions {
7200*0f4c859eSApple OSS Distributions // [deprecated] public
7201*0f4c859eSApple OSS Distributions return kIOReturnUnsupported;
7202*0f4c859eSApple OSS Distributions }
7203*0f4c859eSApple OSS Distributions
7204*0f4c859eSApple OSS Distributions //*********************************************************************************
7205*0f4c859eSApple OSS Distributions // PM_Clamp_Timer_Expired
7206*0f4c859eSApple OSS Distributions //
7207*0f4c859eSApple OSS Distributions // called when clamp timer expires...set power state to 0.
7208*0f4c859eSApple OSS Distributions //*********************************************************************************
7209*0f4c859eSApple OSS Distributions
7210*0f4c859eSApple OSS Distributions void
PM_Clamp_Timer_Expired(void)7211*0f4c859eSApple OSS Distributions IOService::PM_Clamp_Timer_Expired( void )
7212*0f4c859eSApple OSS Distributions {
7213*0f4c859eSApple OSS Distributions }
7214*0f4c859eSApple OSS Distributions
7215*0f4c859eSApple OSS Distributions //*********************************************************************************
7216*0f4c859eSApple OSS Distributions // clampPowerOn
7217*0f4c859eSApple OSS Distributions //
7218*0f4c859eSApple OSS Distributions // Set to highest available power state for a minimum of duration milliseconds
7219*0f4c859eSApple OSS Distributions //*********************************************************************************
7220*0f4c859eSApple OSS Distributions
7221*0f4c859eSApple OSS Distributions void
clampPowerOn(unsigned long duration)7222*0f4c859eSApple OSS Distributions IOService::clampPowerOn( unsigned long duration )
7223*0f4c859eSApple OSS Distributions {
7224*0f4c859eSApple OSS Distributions }
7225*0f4c859eSApple OSS Distributions #endif /* !__LP64__ */
7226*0f4c859eSApple OSS Distributions
7227*0f4c859eSApple OSS Distributions //*********************************************************************************
7228*0f4c859eSApple OSS Distributions // configurePowerStateReport
7229*0f4c859eSApple OSS Distributions //
7230*0f4c859eSApple OSS Distributions // Configures the IOStateReport for kPMPowerStateChannel
7231*0f4c859eSApple OSS Distributions //*********************************************************************************
7232*0f4c859eSApple OSS Distributions IOReturn
configurePowerStatesReport(IOReportConfigureAction action,void * result)7233*0f4c859eSApple OSS Distributions IOService::configurePowerStatesReport( IOReportConfigureAction action, void *result )
7234*0f4c859eSApple OSS Distributions {
7235*0f4c859eSApple OSS Distributions IOReturn rc = kIOReturnSuccess;
7236*0f4c859eSApple OSS Distributions size_t reportSize;
7237*0f4c859eSApple OSS Distributions unsigned long i;
7238*0f4c859eSApple OSS Distributions uint64_t ts;
7239*0f4c859eSApple OSS Distributions
7240*0f4c859eSApple OSS Distributions if (!pwrMgt) {
7241*0f4c859eSApple OSS Distributions return kIOReturnUnsupported;
7242*0f4c859eSApple OSS Distributions }
7243*0f4c859eSApple OSS Distributions
7244*0f4c859eSApple OSS Distributions if (!fNumberOfPowerStates) {
7245*0f4c859eSApple OSS Distributions return kIOReturnSuccess; // For drivers which are in power plane, but haven't called registerPowerDriver()
7246*0f4c859eSApple OSS Distributions }
7247*0f4c859eSApple OSS Distributions
7248*0f4c859eSApple OSS Distributions if (fNumberOfPowerStates > INT16_MAX) {
7249*0f4c859eSApple OSS Distributions return kIOReturnOverrun;
7250*0f4c859eSApple OSS Distributions }
7251*0f4c859eSApple OSS Distributions PM_LOCK();
7252*0f4c859eSApple OSS Distributions
7253*0f4c859eSApple OSS Distributions switch (action) {
7254*0f4c859eSApple OSS Distributions case kIOReportEnable:
7255*0f4c859eSApple OSS Distributions if (fReportBuf) {
7256*0f4c859eSApple OSS Distributions fReportClientCnt++;
7257*0f4c859eSApple OSS Distributions break;
7258*0f4c859eSApple OSS Distributions }
7259*0f4c859eSApple OSS Distributions reportSize = STATEREPORT_BUFSIZE(fNumberOfPowerStates);
7260*0f4c859eSApple OSS Distributions fReportBuf = IOMallocZeroData(reportSize);
7261*0f4c859eSApple OSS Distributions if (!fReportBuf) {
7262*0f4c859eSApple OSS Distributions rc = kIOReturnNoMemory;
7263*0f4c859eSApple OSS Distributions break;
7264*0f4c859eSApple OSS Distributions }
7265*0f4c859eSApple OSS Distributions
7266*0f4c859eSApple OSS Distributions STATEREPORT_INIT((uint16_t) fNumberOfPowerStates, fReportBuf, reportSize,
7267*0f4c859eSApple OSS Distributions getRegistryEntryID(), kPMPowerStatesChID, kIOReportCategoryPower);
7268*0f4c859eSApple OSS Distributions
7269*0f4c859eSApple OSS Distributions for (i = 0; i < fNumberOfPowerStates; i++) {
7270*0f4c859eSApple OSS Distributions unsigned bits = 0;
7271*0f4c859eSApple OSS Distributions
7272*0f4c859eSApple OSS Distributions if (fPowerStates[i].capabilityFlags & kIOPMPowerOn) {
7273*0f4c859eSApple OSS Distributions bits |= kPMReportPowerOn;
7274*0f4c859eSApple OSS Distributions }
7275*0f4c859eSApple OSS Distributions if (fPowerStates[i].capabilityFlags & kIOPMDeviceUsable) {
7276*0f4c859eSApple OSS Distributions bits |= kPMReportDeviceUsable;
7277*0f4c859eSApple OSS Distributions }
7278*0f4c859eSApple OSS Distributions if (fPowerStates[i].capabilityFlags & kIOPMLowPower) {
7279*0f4c859eSApple OSS Distributions bits |= kPMReportLowPower;
7280*0f4c859eSApple OSS Distributions }
7281*0f4c859eSApple OSS Distributions
7282*0f4c859eSApple OSS Distributions STATEREPORT_SETSTATEID(fReportBuf, i, ((bits & 0xff) << 8) |
7283*0f4c859eSApple OSS Distributions ((StateOrder(fMaxPowerState) & 0xf) << 4) | (StateOrder(i) & 0xf));
7284*0f4c859eSApple OSS Distributions }
7285*0f4c859eSApple OSS Distributions ts = mach_absolute_time();
7286*0f4c859eSApple OSS Distributions STATEREPORT_SETSTATE(fReportBuf, (uint16_t) fCurrentPowerState, ts);
7287*0f4c859eSApple OSS Distributions break;
7288*0f4c859eSApple OSS Distributions
7289*0f4c859eSApple OSS Distributions case kIOReportDisable:
7290*0f4c859eSApple OSS Distributions if (fReportClientCnt == 0) {
7291*0f4c859eSApple OSS Distributions rc = kIOReturnBadArgument;
7292*0f4c859eSApple OSS Distributions break;
7293*0f4c859eSApple OSS Distributions }
7294*0f4c859eSApple OSS Distributions if (fReportClientCnt == 1) {
7295*0f4c859eSApple OSS Distributions IOFreeData(fReportBuf, STATEREPORT_BUFSIZE(fNumberOfPowerStates));
7296*0f4c859eSApple OSS Distributions fReportBuf = NULL;
7297*0f4c859eSApple OSS Distributions }
7298*0f4c859eSApple OSS Distributions fReportClientCnt--;
7299*0f4c859eSApple OSS Distributions break;
7300*0f4c859eSApple OSS Distributions
7301*0f4c859eSApple OSS Distributions case kIOReportGetDimensions:
7302*0f4c859eSApple OSS Distributions if (fReportBuf) {
7303*0f4c859eSApple OSS Distributions STATEREPORT_UPDATERES(fReportBuf, kIOReportGetDimensions, result);
7304*0f4c859eSApple OSS Distributions }
7305*0f4c859eSApple OSS Distributions break;
7306*0f4c859eSApple OSS Distributions }
7307*0f4c859eSApple OSS Distributions
7308*0f4c859eSApple OSS Distributions PM_UNLOCK();
7309*0f4c859eSApple OSS Distributions
7310*0f4c859eSApple OSS Distributions return rc;
7311*0f4c859eSApple OSS Distributions }
7312*0f4c859eSApple OSS Distributions
7313*0f4c859eSApple OSS Distributions //*********************************************************************************
7314*0f4c859eSApple OSS Distributions // updatePowerStateReport
7315*0f4c859eSApple OSS Distributions //
7316*0f4c859eSApple OSS Distributions // Updates the IOStateReport for kPMPowerStateChannel
7317*0f4c859eSApple OSS Distributions //*********************************************************************************
7318*0f4c859eSApple OSS Distributions IOReturn
updatePowerStatesReport(IOReportConfigureAction action,void * result,void * destination)7319*0f4c859eSApple OSS Distributions IOService::updatePowerStatesReport( IOReportConfigureAction action, void *result, void *destination )
7320*0f4c859eSApple OSS Distributions {
7321*0f4c859eSApple OSS Distributions uint32_t size2cpy;
7322*0f4c859eSApple OSS Distributions void *data2cpy;
7323*0f4c859eSApple OSS Distributions uint64_t ts;
7324*0f4c859eSApple OSS Distributions IOReturn rc = kIOReturnSuccess;
7325*0f4c859eSApple OSS Distributions IOBufferMemoryDescriptor *dest = OSDynamicCast(IOBufferMemoryDescriptor, (OSObject *)destination);
7326*0f4c859eSApple OSS Distributions
7327*0f4c859eSApple OSS Distributions
7328*0f4c859eSApple OSS Distributions if (!pwrMgt) {
7329*0f4c859eSApple OSS Distributions return kIOReturnUnsupported;
7330*0f4c859eSApple OSS Distributions }
7331*0f4c859eSApple OSS Distributions if (!fNumberOfPowerStates) {
7332*0f4c859eSApple OSS Distributions return kIOReturnSuccess;
7333*0f4c859eSApple OSS Distributions }
7334*0f4c859eSApple OSS Distributions
7335*0f4c859eSApple OSS Distributions if (!result || !dest) {
7336*0f4c859eSApple OSS Distributions return kIOReturnBadArgument;
7337*0f4c859eSApple OSS Distributions }
7338*0f4c859eSApple OSS Distributions PM_LOCK();
7339*0f4c859eSApple OSS Distributions
7340*0f4c859eSApple OSS Distributions switch (action) {
7341*0f4c859eSApple OSS Distributions case kIOReportCopyChannelData:
7342*0f4c859eSApple OSS Distributions if (!fReportBuf) {
7343*0f4c859eSApple OSS Distributions rc = kIOReturnNotOpen;
7344*0f4c859eSApple OSS Distributions break;
7345*0f4c859eSApple OSS Distributions }
7346*0f4c859eSApple OSS Distributions
7347*0f4c859eSApple OSS Distributions ts = mach_absolute_time();
7348*0f4c859eSApple OSS Distributions STATEREPORT_UPDATEPREP(fReportBuf, ts, data2cpy, size2cpy);
7349*0f4c859eSApple OSS Distributions if (size2cpy > (dest->getCapacity() - dest->getLength())) {
7350*0f4c859eSApple OSS Distributions rc = kIOReturnOverrun;
7351*0f4c859eSApple OSS Distributions break;
7352*0f4c859eSApple OSS Distributions }
7353*0f4c859eSApple OSS Distributions
7354*0f4c859eSApple OSS Distributions STATEREPORT_UPDATERES(fReportBuf, kIOReportCopyChannelData, result);
7355*0f4c859eSApple OSS Distributions dest->appendBytes(data2cpy, size2cpy);
7356*0f4c859eSApple OSS Distributions break;
7357*0f4c859eSApple OSS Distributions
7358*0f4c859eSApple OSS Distributions default:
7359*0f4c859eSApple OSS Distributions break;
7360*0f4c859eSApple OSS Distributions }
7361*0f4c859eSApple OSS Distributions
7362*0f4c859eSApple OSS Distributions PM_UNLOCK();
7363*0f4c859eSApple OSS Distributions
7364*0f4c859eSApple OSS Distributions return rc;
7365*0f4c859eSApple OSS Distributions }
7366*0f4c859eSApple OSS Distributions
7367*0f4c859eSApple OSS Distributions //*********************************************************************************
7368*0f4c859eSApple OSS Distributions // configureSimplePowerReport
7369*0f4c859eSApple OSS Distributions //
7370*0f4c859eSApple OSS Distributions // Configures the IOSimpleReport for given channel id
7371*0f4c859eSApple OSS Distributions //*********************************************************************************
7372*0f4c859eSApple OSS Distributions IOReturn
configureSimplePowerReport(IOReportConfigureAction action,void * result)7373*0f4c859eSApple OSS Distributions IOService::configureSimplePowerReport(IOReportConfigureAction action, void *result )
7374*0f4c859eSApple OSS Distributions {
7375*0f4c859eSApple OSS Distributions IOReturn rc = kIOReturnSuccess;
7376*0f4c859eSApple OSS Distributions
7377*0f4c859eSApple OSS Distributions if (!pwrMgt) {
7378*0f4c859eSApple OSS Distributions return kIOReturnUnsupported;
7379*0f4c859eSApple OSS Distributions }
7380*0f4c859eSApple OSS Distributions
7381*0f4c859eSApple OSS Distributions if (!fNumberOfPowerStates) {
7382*0f4c859eSApple OSS Distributions return rc;
7383*0f4c859eSApple OSS Distributions }
7384*0f4c859eSApple OSS Distributions
7385*0f4c859eSApple OSS Distributions switch (action) {
7386*0f4c859eSApple OSS Distributions case kIOReportEnable:
7387*0f4c859eSApple OSS Distributions case kIOReportDisable:
7388*0f4c859eSApple OSS Distributions break;
7389*0f4c859eSApple OSS Distributions
7390*0f4c859eSApple OSS Distributions case kIOReportGetDimensions:
7391*0f4c859eSApple OSS Distributions SIMPLEREPORT_UPDATERES(kIOReportGetDimensions, result);
7392*0f4c859eSApple OSS Distributions break;
7393*0f4c859eSApple OSS Distributions }
7394*0f4c859eSApple OSS Distributions
7395*0f4c859eSApple OSS Distributions
7396*0f4c859eSApple OSS Distributions return rc;
7397*0f4c859eSApple OSS Distributions }
7398*0f4c859eSApple OSS Distributions
7399*0f4c859eSApple OSS Distributions //*********************************************************************************
7400*0f4c859eSApple OSS Distributions // updateSimplePowerReport
7401*0f4c859eSApple OSS Distributions //
7402*0f4c859eSApple OSS Distributions // Updates the IOSimpleReport for the given chanel id
7403*0f4c859eSApple OSS Distributions //*********************************************************************************
7404*0f4c859eSApple OSS Distributions IOReturn
updateSimplePowerReport(IOReportConfigureAction action,void * result,void * destination)7405*0f4c859eSApple OSS Distributions IOService::updateSimplePowerReport( IOReportConfigureAction action, void *result, void *destination )
7406*0f4c859eSApple OSS Distributions {
7407*0f4c859eSApple OSS Distributions uint32_t size2cpy;
7408*0f4c859eSApple OSS Distributions void *data2cpy;
7409*0f4c859eSApple OSS Distributions uint64_t buf[SIMPLEREPORT_BUFSIZE / sizeof(uint64_t) + 1]; // Force a 8-byte alignment
7410*0f4c859eSApple OSS Distributions IOBufferMemoryDescriptor *dest = OSDynamicCast(IOBufferMemoryDescriptor, (OSObject *)destination);
7411*0f4c859eSApple OSS Distributions IOReturn rc = kIOReturnSuccess;
7412*0f4c859eSApple OSS Distributions unsigned bits = 0;
7413*0f4c859eSApple OSS Distributions
7414*0f4c859eSApple OSS Distributions
7415*0f4c859eSApple OSS Distributions if (!pwrMgt) {
7416*0f4c859eSApple OSS Distributions return kIOReturnUnsupported;
7417*0f4c859eSApple OSS Distributions }
7418*0f4c859eSApple OSS Distributions if (!result || !dest) {
7419*0f4c859eSApple OSS Distributions return kIOReturnBadArgument;
7420*0f4c859eSApple OSS Distributions }
7421*0f4c859eSApple OSS Distributions
7422*0f4c859eSApple OSS Distributions if (!fNumberOfPowerStates) {
7423*0f4c859eSApple OSS Distributions return rc;
7424*0f4c859eSApple OSS Distributions }
7425*0f4c859eSApple OSS Distributions PM_LOCK();
7426*0f4c859eSApple OSS Distributions
7427*0f4c859eSApple OSS Distributions switch (action) {
7428*0f4c859eSApple OSS Distributions case kIOReportCopyChannelData:
7429*0f4c859eSApple OSS Distributions
7430*0f4c859eSApple OSS Distributions SIMPLEREPORT_INIT(buf, sizeof(buf), getRegistryEntryID(), kPMCurrStateChID, kIOReportCategoryPower);
7431*0f4c859eSApple OSS Distributions
7432*0f4c859eSApple OSS Distributions if (fPowerStates[fCurrentPowerState].capabilityFlags & kIOPMPowerOn) {
7433*0f4c859eSApple OSS Distributions bits |= kPMReportPowerOn;
7434*0f4c859eSApple OSS Distributions }
7435*0f4c859eSApple OSS Distributions if (fPowerStates[fCurrentPowerState].capabilityFlags & kIOPMDeviceUsable) {
7436*0f4c859eSApple OSS Distributions bits |= kPMReportDeviceUsable;
7437*0f4c859eSApple OSS Distributions }
7438*0f4c859eSApple OSS Distributions if (fPowerStates[fCurrentPowerState].capabilityFlags & kIOPMLowPower) {
7439*0f4c859eSApple OSS Distributions bits |= kPMReportLowPower;
7440*0f4c859eSApple OSS Distributions }
7441*0f4c859eSApple OSS Distributions
7442*0f4c859eSApple OSS Distributions
7443*0f4c859eSApple OSS Distributions SIMPLEREPORT_SETVALUE(buf, ((bits & 0xff) << 8) | ((StateOrder(fMaxPowerState) & 0xf) << 4) |
7444*0f4c859eSApple OSS Distributions (StateOrder(fCurrentPowerState) & 0xf));
7445*0f4c859eSApple OSS Distributions
7446*0f4c859eSApple OSS Distributions SIMPLEREPORT_UPDATEPREP(buf, data2cpy, size2cpy);
7447*0f4c859eSApple OSS Distributions if (size2cpy > (dest->getCapacity() - dest->getLength())) {
7448*0f4c859eSApple OSS Distributions rc = kIOReturnOverrun;
7449*0f4c859eSApple OSS Distributions break;
7450*0f4c859eSApple OSS Distributions }
7451*0f4c859eSApple OSS Distributions
7452*0f4c859eSApple OSS Distributions SIMPLEREPORT_UPDATERES(kIOReportCopyChannelData, result);
7453*0f4c859eSApple OSS Distributions dest->appendBytes(data2cpy, size2cpy);
7454*0f4c859eSApple OSS Distributions break;
7455*0f4c859eSApple OSS Distributions
7456*0f4c859eSApple OSS Distributions default:
7457*0f4c859eSApple OSS Distributions break;
7458*0f4c859eSApple OSS Distributions }
7459*0f4c859eSApple OSS Distributions
7460*0f4c859eSApple OSS Distributions PM_UNLOCK();
7461*0f4c859eSApple OSS Distributions
7462*0f4c859eSApple OSS Distributions return rc;
7463*0f4c859eSApple OSS Distributions }
7464*0f4c859eSApple OSS Distributions
7465*0f4c859eSApple OSS Distributions
7466*0f4c859eSApple OSS Distributions
7467*0f4c859eSApple OSS Distributions // MARK: -
7468*0f4c859eSApple OSS Distributions // MARK: Driver Overrides
7469*0f4c859eSApple OSS Distributions
7470*0f4c859eSApple OSS Distributions //*********************************************************************************
7471*0f4c859eSApple OSS Distributions // [public] setPowerState
7472*0f4c859eSApple OSS Distributions //
7473*0f4c859eSApple OSS Distributions // Does nothing here. This should be implemented in a subclass driver.
7474*0f4c859eSApple OSS Distributions //*********************************************************************************
7475*0f4c859eSApple OSS Distributions
7476*0f4c859eSApple OSS Distributions IOReturn
setPowerState(unsigned long powerStateOrdinal,IOService * whatDevice)7477*0f4c859eSApple OSS Distributions IOService::setPowerState(
7478*0f4c859eSApple OSS Distributions unsigned long powerStateOrdinal, IOService * whatDevice )
7479*0f4c859eSApple OSS Distributions {
7480*0f4c859eSApple OSS Distributions return IOPMNoErr;
7481*0f4c859eSApple OSS Distributions }
7482*0f4c859eSApple OSS Distributions
7483*0f4c859eSApple OSS Distributions //*********************************************************************************
7484*0f4c859eSApple OSS Distributions // [public] maxCapabilityForDomainState
7485*0f4c859eSApple OSS Distributions //
7486*0f4c859eSApple OSS Distributions // Finds the highest power state in the array whose input power requirement
7487*0f4c859eSApple OSS Distributions // is equal to the input parameter. Where a more intelligent decision is
7488*0f4c859eSApple OSS Distributions // possible, override this in the subclassed driver.
7489*0f4c859eSApple OSS Distributions //*********************************************************************************
7490*0f4c859eSApple OSS Distributions
7491*0f4c859eSApple OSS Distributions IOPMPowerStateIndex
getPowerStateForDomainFlags(IOPMPowerFlags flags)7492*0f4c859eSApple OSS Distributions IOService::getPowerStateForDomainFlags( IOPMPowerFlags flags )
7493*0f4c859eSApple OSS Distributions {
7494*0f4c859eSApple OSS Distributions IOPMPowerStateIndex stateIndex;
7495*0f4c859eSApple OSS Distributions
7496*0f4c859eSApple OSS Distributions if (!fNumberOfPowerStates) {
7497*0f4c859eSApple OSS Distributions return kPowerStateZero;
7498*0f4c859eSApple OSS Distributions }
7499*0f4c859eSApple OSS Distributions
7500*0f4c859eSApple OSS Distributions for (long order = fNumberOfPowerStates - 1; order >= 0; order--) {
7501*0f4c859eSApple OSS Distributions stateIndex = fPowerStates[order].stateOrderToIndex;
7502*0f4c859eSApple OSS Distributions
7503*0f4c859eSApple OSS Distributions if ((flags & fPowerStates[stateIndex].inputPowerFlags) ==
7504*0f4c859eSApple OSS Distributions fPowerStates[stateIndex].inputPowerFlags) {
7505*0f4c859eSApple OSS Distributions return stateIndex;
7506*0f4c859eSApple OSS Distributions }
7507*0f4c859eSApple OSS Distributions }
7508*0f4c859eSApple OSS Distributions return kPowerStateZero;
7509*0f4c859eSApple OSS Distributions }
7510*0f4c859eSApple OSS Distributions
7511*0f4c859eSApple OSS Distributions unsigned long
maxCapabilityForDomainState(IOPMPowerFlags domainState)7512*0f4c859eSApple OSS Distributions IOService::maxCapabilityForDomainState( IOPMPowerFlags domainState )
7513*0f4c859eSApple OSS Distributions {
7514*0f4c859eSApple OSS Distributions return getPowerStateForDomainFlags(domainState);
7515*0f4c859eSApple OSS Distributions }
7516*0f4c859eSApple OSS Distributions
7517*0f4c859eSApple OSS Distributions //*********************************************************************************
7518*0f4c859eSApple OSS Distributions // [public] initialPowerStateForDomainState
7519*0f4c859eSApple OSS Distributions //
7520*0f4c859eSApple OSS Distributions // Called to query the power state for the initial power transition.
7521*0f4c859eSApple OSS Distributions //*********************************************************************************
7522*0f4c859eSApple OSS Distributions
7523*0f4c859eSApple OSS Distributions unsigned long
initialPowerStateForDomainState(IOPMPowerFlags domainState)7524*0f4c859eSApple OSS Distributions IOService::initialPowerStateForDomainState( IOPMPowerFlags domainState )
7525*0f4c859eSApple OSS Distributions {
7526*0f4c859eSApple OSS Distributions if (fResetPowerStateOnWake && (domainState & kIOPMRootDomainState)) {
7527*0f4c859eSApple OSS Distributions // Return lowest power state for any root power domain changes
7528*0f4c859eSApple OSS Distributions return kPowerStateZero;
7529*0f4c859eSApple OSS Distributions }
7530*0f4c859eSApple OSS Distributions
7531*0f4c859eSApple OSS Distributions return getPowerStateForDomainFlags(domainState);
7532*0f4c859eSApple OSS Distributions }
7533*0f4c859eSApple OSS Distributions
7534*0f4c859eSApple OSS Distributions //*********************************************************************************
7535*0f4c859eSApple OSS Distributions // [public] powerStateForDomainState
7536*0f4c859eSApple OSS Distributions //
7537*0f4c859eSApple OSS Distributions // This method is not called from PM.
7538*0f4c859eSApple OSS Distributions //*********************************************************************************
7539*0f4c859eSApple OSS Distributions
7540*0f4c859eSApple OSS Distributions unsigned long
powerStateForDomainState(IOPMPowerFlags domainState)7541*0f4c859eSApple OSS Distributions IOService::powerStateForDomainState( IOPMPowerFlags domainState )
7542*0f4c859eSApple OSS Distributions {
7543*0f4c859eSApple OSS Distributions return getPowerStateForDomainFlags(domainState);
7544*0f4c859eSApple OSS Distributions }
7545*0f4c859eSApple OSS Distributions
7546*0f4c859eSApple OSS Distributions #ifndef __LP64__
7547*0f4c859eSApple OSS Distributions //*********************************************************************************
7548*0f4c859eSApple OSS Distributions // [deprecated] didYouWakeSystem
7549*0f4c859eSApple OSS Distributions //
7550*0f4c859eSApple OSS Distributions // Does nothing here. This should be implemented in a subclass driver.
7551*0f4c859eSApple OSS Distributions //*********************************************************************************
7552*0f4c859eSApple OSS Distributions
7553*0f4c859eSApple OSS Distributions bool
didYouWakeSystem(void)7554*0f4c859eSApple OSS Distributions IOService::didYouWakeSystem( void )
7555*0f4c859eSApple OSS Distributions {
7556*0f4c859eSApple OSS Distributions return false;
7557*0f4c859eSApple OSS Distributions }
7558*0f4c859eSApple OSS Distributions #endif /* !__LP64__ */
7559*0f4c859eSApple OSS Distributions
7560*0f4c859eSApple OSS Distributions //*********************************************************************************
7561*0f4c859eSApple OSS Distributions // [public] powerStateWillChangeTo
7562*0f4c859eSApple OSS Distributions //
7563*0f4c859eSApple OSS Distributions // Does nothing here. This should be implemented in a subclass driver.
7564*0f4c859eSApple OSS Distributions //*********************************************************************************
7565*0f4c859eSApple OSS Distributions
7566*0f4c859eSApple OSS Distributions IOReturn
powerStateWillChangeTo(IOPMPowerFlags,unsigned long,IOService *)7567*0f4c859eSApple OSS Distributions IOService::powerStateWillChangeTo( IOPMPowerFlags, unsigned long, IOService * )
7568*0f4c859eSApple OSS Distributions {
7569*0f4c859eSApple OSS Distributions return kIOPMAckImplied;
7570*0f4c859eSApple OSS Distributions }
7571*0f4c859eSApple OSS Distributions
7572*0f4c859eSApple OSS Distributions //*********************************************************************************
7573*0f4c859eSApple OSS Distributions // [public] powerStateDidChangeTo
7574*0f4c859eSApple OSS Distributions //
7575*0f4c859eSApple OSS Distributions // Does nothing here. This should be implemented in a subclass driver.
7576*0f4c859eSApple OSS Distributions //*********************************************************************************
7577*0f4c859eSApple OSS Distributions
7578*0f4c859eSApple OSS Distributions IOReturn
powerStateDidChangeTo(IOPMPowerFlags,unsigned long,IOService *)7579*0f4c859eSApple OSS Distributions IOService::powerStateDidChangeTo( IOPMPowerFlags, unsigned long, IOService * )
7580*0f4c859eSApple OSS Distributions {
7581*0f4c859eSApple OSS Distributions return kIOPMAckImplied;
7582*0f4c859eSApple OSS Distributions }
7583*0f4c859eSApple OSS Distributions
7584*0f4c859eSApple OSS Distributions //*********************************************************************************
7585*0f4c859eSApple OSS Distributions // [protected] powerChangeDone
7586*0f4c859eSApple OSS Distributions //
7587*0f4c859eSApple OSS Distributions // Called from PM work loop thread.
7588*0f4c859eSApple OSS Distributions // Does nothing here. This should be implemented in a subclass policy-maker.
7589*0f4c859eSApple OSS Distributions //*********************************************************************************
7590*0f4c859eSApple OSS Distributions
7591*0f4c859eSApple OSS Distributions void
powerChangeDone(unsigned long)7592*0f4c859eSApple OSS Distributions IOService::powerChangeDone( unsigned long )
7593*0f4c859eSApple OSS Distributions {
7594*0f4c859eSApple OSS Distributions }
7595*0f4c859eSApple OSS Distributions
7596*0f4c859eSApple OSS Distributions #ifndef __LP64__
7597*0f4c859eSApple OSS Distributions //*********************************************************************************
7598*0f4c859eSApple OSS Distributions // [deprecated] newTemperature
7599*0f4c859eSApple OSS Distributions //
7600*0f4c859eSApple OSS Distributions // Does nothing here. This should be implemented in a subclass driver.
7601*0f4c859eSApple OSS Distributions //*********************************************************************************
7602*0f4c859eSApple OSS Distributions
7603*0f4c859eSApple OSS Distributions IOReturn
newTemperature(long currentTemp,IOService * whichZone)7604*0f4c859eSApple OSS Distributions IOService::newTemperature( long currentTemp, IOService * whichZone )
7605*0f4c859eSApple OSS Distributions {
7606*0f4c859eSApple OSS Distributions return IOPMNoErr;
7607*0f4c859eSApple OSS Distributions }
7608*0f4c859eSApple OSS Distributions #endif /* !__LP64__ */
7609*0f4c859eSApple OSS Distributions
7610*0f4c859eSApple OSS Distributions //*********************************************************************************
7611*0f4c859eSApple OSS Distributions // [public] systemWillShutdown
7612*0f4c859eSApple OSS Distributions //
7613*0f4c859eSApple OSS Distributions // System shutdown and restart notification.
7614*0f4c859eSApple OSS Distributions //*********************************************************************************
7615*0f4c859eSApple OSS Distributions
7616*0f4c859eSApple OSS Distributions void
systemWillShutdown(IOOptionBits specifier)7617*0f4c859eSApple OSS Distributions IOService::systemWillShutdown( IOOptionBits specifier )
7618*0f4c859eSApple OSS Distributions {
7619*0f4c859eSApple OSS Distributions IOPMrootDomain * rootDomain = IOService::getPMRootDomain();
7620*0f4c859eSApple OSS Distributions if (rootDomain) {
7621*0f4c859eSApple OSS Distributions rootDomain->acknowledgeSystemWillShutdown( this );
7622*0f4c859eSApple OSS Distributions }
7623*0f4c859eSApple OSS Distributions }
7624*0f4c859eSApple OSS Distributions
7625*0f4c859eSApple OSS Distributions // MARK: -
7626*0f4c859eSApple OSS Distributions // MARK: PM State Machine
7627*0f4c859eSApple OSS Distributions
7628*0f4c859eSApple OSS Distributions //*********************************************************************************
7629*0f4c859eSApple OSS Distributions // [private static] acquirePMRequest
7630*0f4c859eSApple OSS Distributions //*********************************************************************************
7631*0f4c859eSApple OSS Distributions
7632*0f4c859eSApple OSS Distributions IOPMRequest *
acquirePMRequest(IOService * target,IOOptionBits requestType,IOPMRequest * active)7633*0f4c859eSApple OSS Distributions IOService::acquirePMRequest( IOService * target, IOOptionBits requestType,
7634*0f4c859eSApple OSS Distributions IOPMRequest * active )
7635*0f4c859eSApple OSS Distributions {
7636*0f4c859eSApple OSS Distributions IOPMRequest * request;
7637*0f4c859eSApple OSS Distributions
7638*0f4c859eSApple OSS Distributions assert(target);
7639*0f4c859eSApple OSS Distributions
7640*0f4c859eSApple OSS Distributions request = IOPMRequest::create();
7641*0f4c859eSApple OSS Distributions if (request) {
7642*0f4c859eSApple OSS Distributions request->init( target, requestType );
7643*0f4c859eSApple OSS Distributions if (active) {
7644*0f4c859eSApple OSS Distributions IOPMRequest * root = active->getRootRequest();
7645*0f4c859eSApple OSS Distributions if (root) {
7646*0f4c859eSApple OSS Distributions request->attachRootRequest(root);
7647*0f4c859eSApple OSS Distributions }
7648*0f4c859eSApple OSS Distributions }
7649*0f4c859eSApple OSS Distributions } else {
7650*0f4c859eSApple OSS Distributions PM_ERROR("%s: No memory for PM request type 0x%x\n",
7651*0f4c859eSApple OSS Distributions target->getName(), (uint32_t) requestType);
7652*0f4c859eSApple OSS Distributions }
7653*0f4c859eSApple OSS Distributions return request;
7654*0f4c859eSApple OSS Distributions }
7655*0f4c859eSApple OSS Distributions
7656*0f4c859eSApple OSS Distributions //*********************************************************************************
7657*0f4c859eSApple OSS Distributions // [private static] releasePMRequest
7658*0f4c859eSApple OSS Distributions //*********************************************************************************
7659*0f4c859eSApple OSS Distributions
7660*0f4c859eSApple OSS Distributions void
releasePMRequest(IOPMRequest * request)7661*0f4c859eSApple OSS Distributions IOService::releasePMRequest( IOPMRequest * request )
7662*0f4c859eSApple OSS Distributions {
7663*0f4c859eSApple OSS Distributions if (request) {
7664*0f4c859eSApple OSS Distributions request->reset();
7665*0f4c859eSApple OSS Distributions request->release();
7666*0f4c859eSApple OSS Distributions }
7667*0f4c859eSApple OSS Distributions }
7668*0f4c859eSApple OSS Distributions
7669*0f4c859eSApple OSS Distributions //*********************************************************************************
7670*0f4c859eSApple OSS Distributions // [private static] submitPMRequest
7671*0f4c859eSApple OSS Distributions //*********************************************************************************
7672*0f4c859eSApple OSS Distributions
7673*0f4c859eSApple OSS Distributions void
submitPMRequest(IOPMRequest * request)7674*0f4c859eSApple OSS Distributions IOService::submitPMRequest( IOPMRequest * request )
7675*0f4c859eSApple OSS Distributions {
7676*0f4c859eSApple OSS Distributions assert( request );
7677*0f4c859eSApple OSS Distributions assert( gIOPMReplyQueue );
7678*0f4c859eSApple OSS Distributions assert( gIOPMRequestQueue );
7679*0f4c859eSApple OSS Distributions
7680*0f4c859eSApple OSS Distributions PM_LOG1("[+ %02lx] %p [%p %s] %p %p %p\n",
7681*0f4c859eSApple OSS Distributions (long)request->getType(), OBFUSCATE(request),
7682*0f4c859eSApple OSS Distributions OBFUSCATE(request->getTarget()), request->getTarget()->getName(),
7683*0f4c859eSApple OSS Distributions OBFUSCATE(request->fArg0),
7684*0f4c859eSApple OSS Distributions OBFUSCATE(request->fArg1), OBFUSCATE(request->fArg2));
7685*0f4c859eSApple OSS Distributions
7686*0f4c859eSApple OSS Distributions if (request->isReplyType()) {
7687*0f4c859eSApple OSS Distributions gIOPMReplyQueue->queuePMRequest( request );
7688*0f4c859eSApple OSS Distributions } else {
7689*0f4c859eSApple OSS Distributions gIOPMRequestQueue->queuePMRequest( request );
7690*0f4c859eSApple OSS Distributions }
7691*0f4c859eSApple OSS Distributions }
7692*0f4c859eSApple OSS Distributions
7693*0f4c859eSApple OSS Distributions void
submitPMRequests(IOPMRequest ** requests,IOItemCount count)7694*0f4c859eSApple OSS Distributions IOService::submitPMRequests( IOPMRequest ** requests, IOItemCount count )
7695*0f4c859eSApple OSS Distributions {
7696*0f4c859eSApple OSS Distributions assert( requests );
7697*0f4c859eSApple OSS Distributions assert( count > 0 );
7698*0f4c859eSApple OSS Distributions assert( gIOPMRequestQueue );
7699*0f4c859eSApple OSS Distributions
7700*0f4c859eSApple OSS Distributions for (IOItemCount i = 0; i < count; i++) {
7701*0f4c859eSApple OSS Distributions IOPMRequest * req = requests[i];
7702*0f4c859eSApple OSS Distributions PM_LOG1("[+ %02lx] %p [%p %s] %p %p %p\n",
7703*0f4c859eSApple OSS Distributions (long)req->getType(), OBFUSCATE(req),
7704*0f4c859eSApple OSS Distributions OBFUSCATE(req->getTarget()), req->getTarget()->getName(),
7705*0f4c859eSApple OSS Distributions OBFUSCATE(req->fArg0),
7706*0f4c859eSApple OSS Distributions OBFUSCATE(req->fArg1), OBFUSCATE(req->fArg2));
7707*0f4c859eSApple OSS Distributions }
7708*0f4c859eSApple OSS Distributions
7709*0f4c859eSApple OSS Distributions gIOPMRequestQueue->queuePMRequestChain( requests, count );
7710*0f4c859eSApple OSS Distributions }
7711*0f4c859eSApple OSS Distributions
7712*0f4c859eSApple OSS Distributions //*********************************************************************************
7713*0f4c859eSApple OSS Distributions // [private] actionPMRequestQueue
7714*0f4c859eSApple OSS Distributions //
7715*0f4c859eSApple OSS Distributions // IOPMRequestQueue::checkForWork() passing a new request to the request target.
7716*0f4c859eSApple OSS Distributions //*********************************************************************************
7717*0f4c859eSApple OSS Distributions
7718*0f4c859eSApple OSS Distributions bool
actionPMRequestQueue(IOPMRequest * request,IOPMRequestQueue * queue)7719*0f4c859eSApple OSS Distributions IOService::actionPMRequestQueue(
7720*0f4c859eSApple OSS Distributions IOPMRequest * request,
7721*0f4c859eSApple OSS Distributions IOPMRequestQueue * queue )
7722*0f4c859eSApple OSS Distributions {
7723*0f4c859eSApple OSS Distributions bool more;
7724*0f4c859eSApple OSS Distributions
7725*0f4c859eSApple OSS Distributions if (initialized) {
7726*0f4c859eSApple OSS Distributions // Work queue will immediately execute the request if the per-service
7727*0f4c859eSApple OSS Distributions // request queue is empty. Note pwrMgt is the target's IOServicePM.
7728*0f4c859eSApple OSS Distributions
7729*0f4c859eSApple OSS Distributions more = gIOPMWorkQueue->queuePMRequest(request, pwrMgt);
7730*0f4c859eSApple OSS Distributions } else {
7731*0f4c859eSApple OSS Distributions // Calling PM without PMinit() is not allowed, fail the request.
7732*0f4c859eSApple OSS Distributions // Need to signal more when completing attached requests.
7733*0f4c859eSApple OSS Distributions
7734*0f4c859eSApple OSS Distributions PM_LOG("%s: PM not initialized\n", getName());
7735*0f4c859eSApple OSS Distributions PM_LOG1("[- %02x] %p [%p %s] !initialized\n",
7736*0f4c859eSApple OSS Distributions request->getType(), OBFUSCATE(request),
7737*0f4c859eSApple OSS Distributions OBFUSCATE(this), getName());
7738*0f4c859eSApple OSS Distributions
7739*0f4c859eSApple OSS Distributions more = gIOPMCompletionQueue->queuePMRequest(request);
7740*0f4c859eSApple OSS Distributions if (more) {
7741*0f4c859eSApple OSS Distributions gIOPMWorkQueue->incrementProducerCount();
7742*0f4c859eSApple OSS Distributions }
7743*0f4c859eSApple OSS Distributions }
7744*0f4c859eSApple OSS Distributions
7745*0f4c859eSApple OSS Distributions return more;
7746*0f4c859eSApple OSS Distributions }
7747*0f4c859eSApple OSS Distributions
7748*0f4c859eSApple OSS Distributions //*********************************************************************************
7749*0f4c859eSApple OSS Distributions // [private] actionPMCompletionQueue
7750*0f4c859eSApple OSS Distributions //
7751*0f4c859eSApple OSS Distributions // IOPMCompletionQueue::checkForWork() passing a completed request to the
7752*0f4c859eSApple OSS Distributions // request target.
7753*0f4c859eSApple OSS Distributions //*********************************************************************************
7754*0f4c859eSApple OSS Distributions
7755*0f4c859eSApple OSS Distributions bool
actionPMCompletionQueue(IOPMRequest * request,IOPMCompletionQueue * queue)7756*0f4c859eSApple OSS Distributions IOService::actionPMCompletionQueue(
7757*0f4c859eSApple OSS Distributions IOPMRequest * request,
7758*0f4c859eSApple OSS Distributions IOPMCompletionQueue * queue )
7759*0f4c859eSApple OSS Distributions {
7760*0f4c859eSApple OSS Distributions bool more = (request->getNextRequest() != NULL);
7761*0f4c859eSApple OSS Distributions IOPMRequest * root = request->getRootRequest();
7762*0f4c859eSApple OSS Distributions
7763*0f4c859eSApple OSS Distributions if (root && (root != request)) {
7764*0f4c859eSApple OSS Distributions more = true;
7765*0f4c859eSApple OSS Distributions }
7766*0f4c859eSApple OSS Distributions if (more) {
7767*0f4c859eSApple OSS Distributions gIOPMWorkQueue->incrementProducerCount();
7768*0f4c859eSApple OSS Distributions }
7769*0f4c859eSApple OSS Distributions
7770*0f4c859eSApple OSS Distributions releasePMRequest( request );
7771*0f4c859eSApple OSS Distributions return more;
7772*0f4c859eSApple OSS Distributions }
7773*0f4c859eSApple OSS Distributions
7774*0f4c859eSApple OSS Distributions //*********************************************************************************
7775*0f4c859eSApple OSS Distributions // [private] actionPMWorkQueueRetire
7776*0f4c859eSApple OSS Distributions //
7777*0f4c859eSApple OSS Distributions // IOPMWorkQueue::checkForWork() passing a retired request to the request target.
7778*0f4c859eSApple OSS Distributions //*********************************************************************************
7779*0f4c859eSApple OSS Distributions
7780*0f4c859eSApple OSS Distributions bool
actionPMWorkQueueRetire(IOPMRequest * request,IOPMWorkQueue * queue)7781*0f4c859eSApple OSS Distributions IOService::actionPMWorkQueueRetire( IOPMRequest * request, IOPMWorkQueue * queue )
7782*0f4c859eSApple OSS Distributions {
7783*0f4c859eSApple OSS Distributions assert(request && queue);
7784*0f4c859eSApple OSS Distributions
7785*0f4c859eSApple OSS Distributions PM_LOG1("[- %02x] %p [%p %s] state %d, busy %d\n",
7786*0f4c859eSApple OSS Distributions request->getType(), OBFUSCATE(request),
7787*0f4c859eSApple OSS Distributions OBFUSCATE(this), getName(),
7788*0f4c859eSApple OSS Distributions fMachineState, gIOPMBusyRequestCount);
7789*0f4c859eSApple OSS Distributions
7790*0f4c859eSApple OSS Distributions // Catch requests created by idleTimerExpired()
7791*0f4c859eSApple OSS Distributions if (request->getType() == kIOPMRequestTypeActivityTickle) {
7792*0f4c859eSApple OSS Distributions uint32_t tickleFlags = (uint32_t)(uintptr_t) request->fArg1;
7793*0f4c859eSApple OSS Distributions
7794*0f4c859eSApple OSS Distributions if ((tickleFlags & kTickleTypePowerDrop) && fIdleTimerPeriod) {
7795*0f4c859eSApple OSS Distributions restartIdleTimer();
7796*0f4c859eSApple OSS Distributions } else if (tickleFlags == (kTickleTypeActivity | kTickleTypePowerRise)) {
7797*0f4c859eSApple OSS Distributions // Invalidate any idle power drop that got queued while
7798*0f4c859eSApple OSS Distributions // processing this request.
7799*0f4c859eSApple OSS Distributions fIdleTimerGeneration++;
7800*0f4c859eSApple OSS Distributions }
7801*0f4c859eSApple OSS Distributions }
7802*0f4c859eSApple OSS Distributions
7803*0f4c859eSApple OSS Distributions // When the completed request is linked, tell work queue there is
7804*0f4c859eSApple OSS Distributions // more work pending.
7805*0f4c859eSApple OSS Distributions
7806*0f4c859eSApple OSS Distributions return gIOPMCompletionQueue->queuePMRequest( request );
7807*0f4c859eSApple OSS Distributions }
7808*0f4c859eSApple OSS Distributions
7809*0f4c859eSApple OSS Distributions //*********************************************************************************
7810*0f4c859eSApple OSS Distributions // [private] isPMBlocked
7811*0f4c859eSApple OSS Distributions //
7812*0f4c859eSApple OSS Distributions // Check if machine state transition is blocked.
7813*0f4c859eSApple OSS Distributions //*********************************************************************************
7814*0f4c859eSApple OSS Distributions
7815*0f4c859eSApple OSS Distributions bool
isPMBlocked(IOPMRequest * request,int count)7816*0f4c859eSApple OSS Distributions IOService::isPMBlocked( IOPMRequest * request, int count )
7817*0f4c859eSApple OSS Distributions {
7818*0f4c859eSApple OSS Distributions int reason = 0;
7819*0f4c859eSApple OSS Distributions
7820*0f4c859eSApple OSS Distributions do {
7821*0f4c859eSApple OSS Distributions if (kIOPM_Finished == fMachineState) {
7822*0f4c859eSApple OSS Distributions break;
7823*0f4c859eSApple OSS Distributions }
7824*0f4c859eSApple OSS Distributions
7825*0f4c859eSApple OSS Distributions if (kIOPM_DriverThreadCallDone == fMachineState) {
7826*0f4c859eSApple OSS Distributions // 5 = kDriverCallInformPreChange
7827*0f4c859eSApple OSS Distributions // 6 = kDriverCallInformPostChange
7828*0f4c859eSApple OSS Distributions // 7 = kDriverCallSetPowerState
7829*0f4c859eSApple OSS Distributions // 8 = kRootDomainInformPreChange
7830*0f4c859eSApple OSS Distributions if (fDriverCallBusy) {
7831*0f4c859eSApple OSS Distributions reason = 5 + fDriverCallReason;
7832*0f4c859eSApple OSS Distributions }
7833*0f4c859eSApple OSS Distributions break;
7834*0f4c859eSApple OSS Distributions }
7835*0f4c859eSApple OSS Distributions
7836*0f4c859eSApple OSS Distributions // Waiting on driver's setPowerState() timeout.
7837*0f4c859eSApple OSS Distributions if (fDriverTimer) {
7838*0f4c859eSApple OSS Distributions reason = 1; break;
7839*0f4c859eSApple OSS Distributions }
7840*0f4c859eSApple OSS Distributions
7841*0f4c859eSApple OSS Distributions // Child or interested driver acks pending.
7842*0f4c859eSApple OSS Distributions if (fHeadNotePendingAcks) {
7843*0f4c859eSApple OSS Distributions reason = 2; break;
7844*0f4c859eSApple OSS Distributions }
7845*0f4c859eSApple OSS Distributions
7846*0f4c859eSApple OSS Distributions // Waiting on apps or priority power interest clients.
7847*0f4c859eSApple OSS Distributions if (fResponseArray) {
7848*0f4c859eSApple OSS Distributions reason = 3; break;
7849*0f4c859eSApple OSS Distributions }
7850*0f4c859eSApple OSS Distributions
7851*0f4c859eSApple OSS Distributions #if USE_SETTLE_TIMER
7852*0f4c859eSApple OSS Distributions // Waiting on settle timer expiration.
7853*0f4c859eSApple OSS Distributions if (fSettleTimeUS) {
7854*0f4c859eSApple OSS Distributions reason = 4; break;
7855*0f4c859eSApple OSS Distributions }
7856*0f4c859eSApple OSS Distributions #endif
7857*0f4c859eSApple OSS Distributions } while (false);
7858*0f4c859eSApple OSS Distributions
7859*0f4c859eSApple OSS Distributions fWaitReason = reason;
7860*0f4c859eSApple OSS Distributions
7861*0f4c859eSApple OSS Distributions if (reason) {
7862*0f4c859eSApple OSS Distributions if (count) {
7863*0f4c859eSApple OSS Distributions PM_LOG1("[B %02x] %p [%p %s] state %d, reason %d\n",
7864*0f4c859eSApple OSS Distributions request->getType(), OBFUSCATE(request),
7865*0f4c859eSApple OSS Distributions OBFUSCATE(this), getName(),
7866*0f4c859eSApple OSS Distributions fMachineState, reason);
7867*0f4c859eSApple OSS Distributions }
7868*0f4c859eSApple OSS Distributions
7869*0f4c859eSApple OSS Distributions return true;
7870*0f4c859eSApple OSS Distributions }
7871*0f4c859eSApple OSS Distributions
7872*0f4c859eSApple OSS Distributions return false;
7873*0f4c859eSApple OSS Distributions }
7874*0f4c859eSApple OSS Distributions
7875*0f4c859eSApple OSS Distributions //*********************************************************************************
7876*0f4c859eSApple OSS Distributions // [private] actionPMWorkQueueInvoke
7877*0f4c859eSApple OSS Distributions //
7878*0f4c859eSApple OSS Distributions // IOPMWorkQueue::checkForWork() passing a request to the
7879*0f4c859eSApple OSS Distributions // request target for execution.
7880*0f4c859eSApple OSS Distributions //*********************************************************************************
7881*0f4c859eSApple OSS Distributions
7882*0f4c859eSApple OSS Distributions bool
actionPMWorkQueueInvoke(IOPMRequest * request,IOPMWorkQueue * queue)7883*0f4c859eSApple OSS Distributions IOService::actionPMWorkQueueInvoke( IOPMRequest * request, IOPMWorkQueue * queue )
7884*0f4c859eSApple OSS Distributions {
7885*0f4c859eSApple OSS Distributions bool done = false;
7886*0f4c859eSApple OSS Distributions int loop = 0;
7887*0f4c859eSApple OSS Distributions
7888*0f4c859eSApple OSS Distributions assert(request && queue);
7889*0f4c859eSApple OSS Distributions
7890*0f4c859eSApple OSS Distributions while (isPMBlocked(request, loop++) == false) {
7891*0f4c859eSApple OSS Distributions PM_LOG1("[W %02x] %p [%p %s] state %d\n",
7892*0f4c859eSApple OSS Distributions request->getType(), OBFUSCATE(request),
7893*0f4c859eSApple OSS Distributions OBFUSCATE(this), getName(), fMachineState);
7894*0f4c859eSApple OSS Distributions
7895*0f4c859eSApple OSS Distributions gIOPMRequest = request;
7896*0f4c859eSApple OSS Distributions gIOPMWorkInvokeCount++;
7897*0f4c859eSApple OSS Distributions
7898*0f4c859eSApple OSS Distributions // Every PM machine states must be handled in one of the cases below.
7899*0f4c859eSApple OSS Distributions
7900*0f4c859eSApple OSS Distributions switch (fMachineState) {
7901*0f4c859eSApple OSS Distributions case kIOPM_Finished:
7902*0f4c859eSApple OSS Distributions start_watchdog_timer();
7903*0f4c859eSApple OSS Distributions
7904*0f4c859eSApple OSS Distributions executePMRequest( request );
7905*0f4c859eSApple OSS Distributions break;
7906*0f4c859eSApple OSS Distributions
7907*0f4c859eSApple OSS Distributions case kIOPM_OurChangeTellClientsPowerDown:
7908*0f4c859eSApple OSS Distributions // Root domain might self cancel due to assertions.
7909*0f4c859eSApple OSS Distributions if (IS_ROOT_DOMAIN) {
7910*0f4c859eSApple OSS Distributions bool cancel = (bool) fDoNotPowerDown;
7911*0f4c859eSApple OSS Distributions getPMRootDomain()->askChangeDownDone(
7912*0f4c859eSApple OSS Distributions &fHeadNoteChangeFlags, &cancel);
7913*0f4c859eSApple OSS Distributions fDoNotPowerDown = cancel;
7914*0f4c859eSApple OSS Distributions }
7915*0f4c859eSApple OSS Distributions
7916*0f4c859eSApple OSS Distributions // askChangeDown() done, was it vetoed?
7917*0f4c859eSApple OSS Distributions if (!fDoNotPowerDown) {
7918*0f4c859eSApple OSS Distributions // no, we can continue
7919*0f4c859eSApple OSS Distributions OurChangeTellClientsPowerDown();
7920*0f4c859eSApple OSS Distributions } else {
7921*0f4c859eSApple OSS Distributions OUR_PMLog(kPMLogIdleCancel, (uintptr_t) this, fMachineState);
7922*0f4c859eSApple OSS Distributions PM_ERROR("%s: idle cancel, state %u\n", fName, fMachineState);
7923*0f4c859eSApple OSS Distributions #if DEVELOPMENT || DEBUG
7924*0f4c859eSApple OSS Distributions record_system_event(SYSTEM_EVENT_TYPE_INFO,
7925*0f4c859eSApple OSS Distributions SYSTEM_EVENT_SUBSYSTEM_PMRD,
7926*0f4c859eSApple OSS Distributions "Idle Sleep", "%s idle cancel, state %u", fName, fMachineState
7927*0f4c859eSApple OSS Distributions );
7928*0f4c859eSApple OSS Distributions #endif /* DEVELOPMENT || DEBUG */
7929*0f4c859eSApple OSS Distributions if (IS_ROOT_DOMAIN) {
7930*0f4c859eSApple OSS Distributions // RootDomain already sent "WillSleep" to its clients
7931*0f4c859eSApple OSS Distributions tellChangeUp(fCurrentPowerState);
7932*0f4c859eSApple OSS Distributions } else {
7933*0f4c859eSApple OSS Distributions tellNoChangeDown(fHeadNotePowerState);
7934*0f4c859eSApple OSS Distributions }
7935*0f4c859eSApple OSS Distributions // mark the change note un-actioned
7936*0f4c859eSApple OSS Distributions fHeadNoteChangeFlags |= kIOPMNotDone;
7937*0f4c859eSApple OSS Distributions // and we're done
7938*0f4c859eSApple OSS Distributions OurChangeFinish();
7939*0f4c859eSApple OSS Distributions }
7940*0f4c859eSApple OSS Distributions break;
7941*0f4c859eSApple OSS Distributions
7942*0f4c859eSApple OSS Distributions case kIOPM_OurChangeTellUserPMPolicyPowerDown:
7943*0f4c859eSApple OSS Distributions // PMRD: tellChangeDown/kNotifyApps done, was it cancelled?
7944*0f4c859eSApple OSS Distributions if (fDoNotPowerDown) {
7945*0f4c859eSApple OSS Distributions OUR_PMLog(kPMLogIdleCancel, (uintptr_t) this, fMachineState);
7946*0f4c859eSApple OSS Distributions PM_ERROR("%s: idle cancel, state %u\n", fName, fMachineState);
7947*0f4c859eSApple OSS Distributions #if DEVELOPMENT || DEBUG
7948*0f4c859eSApple OSS Distributions record_system_event(SYSTEM_EVENT_TYPE_INFO,
7949*0f4c859eSApple OSS Distributions SYSTEM_EVENT_SUBSYSTEM_PMRD,
7950*0f4c859eSApple OSS Distributions "Idle Sleep", "%s idle cancel, state %u", fName, fMachineState
7951*0f4c859eSApple OSS Distributions );
7952*0f4c859eSApple OSS Distributions #endif /* DEVELOPMENT || DEBUG */
7953*0f4c859eSApple OSS Distributions if (IS_ROOT_DOMAIN) {
7954*0f4c859eSApple OSS Distributions // RootDomain already sent "WillSleep" to its clients
7955*0f4c859eSApple OSS Distributions tellChangeUp(fCurrentPowerState);
7956*0f4c859eSApple OSS Distributions } else {
7957*0f4c859eSApple OSS Distributions tellNoChangeDown(fHeadNotePowerState);
7958*0f4c859eSApple OSS Distributions }
7959*0f4c859eSApple OSS Distributions // mark the change note un-actioned
7960*0f4c859eSApple OSS Distributions fHeadNoteChangeFlags |= kIOPMNotDone;
7961*0f4c859eSApple OSS Distributions // and we're done
7962*0f4c859eSApple OSS Distributions OurChangeFinish();
7963*0f4c859eSApple OSS Distributions } else {
7964*0f4c859eSApple OSS Distributions OurChangeTellUserPMPolicyPowerDown();
7965*0f4c859eSApple OSS Distributions }
7966*0f4c859eSApple OSS Distributions break;
7967*0f4c859eSApple OSS Distributions
7968*0f4c859eSApple OSS Distributions case kIOPM_OurChangeTellPriorityClientsPowerDown:
7969*0f4c859eSApple OSS Distributions // PMRD: LastCallBeforeSleep notify done
7970*0f4c859eSApple OSS Distributions // Non-PMRD: tellChangeDown/kNotifyApps done
7971*0f4c859eSApple OSS Distributions if (fDoNotPowerDown) {
7972*0f4c859eSApple OSS Distributions OUR_PMLog(kPMLogIdleCancel, (uintptr_t) this, fMachineState);
7973*0f4c859eSApple OSS Distributions PM_ERROR("%s: idle revert, state %u\n", fName, fMachineState);
7974*0f4c859eSApple OSS Distributions // no, tell clients we're back in the old state
7975*0f4c859eSApple OSS Distributions tellChangeUp(fCurrentPowerState);
7976*0f4c859eSApple OSS Distributions // mark the change note un-actioned
7977*0f4c859eSApple OSS Distributions fHeadNoteChangeFlags |= kIOPMNotDone;
7978*0f4c859eSApple OSS Distributions // and we're done
7979*0f4c859eSApple OSS Distributions OurChangeFinish();
7980*0f4c859eSApple OSS Distributions } else {
7981*0f4c859eSApple OSS Distributions // yes, we can continue
7982*0f4c859eSApple OSS Distributions OurChangeTellPriorityClientsPowerDown();
7983*0f4c859eSApple OSS Distributions }
7984*0f4c859eSApple OSS Distributions break;
7985*0f4c859eSApple OSS Distributions
7986*0f4c859eSApple OSS Distributions case kIOPM_OurChangeNotifyInterestedDriversWillChange:
7987*0f4c859eSApple OSS Distributions OurChangeNotifyInterestedDriversWillChange();
7988*0f4c859eSApple OSS Distributions break;
7989*0f4c859eSApple OSS Distributions
7990*0f4c859eSApple OSS Distributions case kIOPM_OurChangeSetPowerState:
7991*0f4c859eSApple OSS Distributions OurChangeSetPowerState();
7992*0f4c859eSApple OSS Distributions break;
7993*0f4c859eSApple OSS Distributions
7994*0f4c859eSApple OSS Distributions case kIOPM_OurChangeWaitForPowerSettle:
7995*0f4c859eSApple OSS Distributions OurChangeWaitForPowerSettle();
7996*0f4c859eSApple OSS Distributions break;
7997*0f4c859eSApple OSS Distributions
7998*0f4c859eSApple OSS Distributions case kIOPM_OurChangeNotifyInterestedDriversDidChange:
7999*0f4c859eSApple OSS Distributions OurChangeNotifyInterestedDriversDidChange();
8000*0f4c859eSApple OSS Distributions break;
8001*0f4c859eSApple OSS Distributions
8002*0f4c859eSApple OSS Distributions case kIOPM_OurChangeTellCapabilityDidChange:
8003*0f4c859eSApple OSS Distributions OurChangeTellCapabilityDidChange();
8004*0f4c859eSApple OSS Distributions break;
8005*0f4c859eSApple OSS Distributions
8006*0f4c859eSApple OSS Distributions case kIOPM_OurChangeFinish:
8007*0f4c859eSApple OSS Distributions OurChangeFinish();
8008*0f4c859eSApple OSS Distributions break;
8009*0f4c859eSApple OSS Distributions
8010*0f4c859eSApple OSS Distributions case kIOPM_ParentChangeTellPriorityClientsPowerDown:
8011*0f4c859eSApple OSS Distributions ParentChangeTellPriorityClientsPowerDown();
8012*0f4c859eSApple OSS Distributions break;
8013*0f4c859eSApple OSS Distributions
8014*0f4c859eSApple OSS Distributions case kIOPM_ParentChangeNotifyInterestedDriversWillChange:
8015*0f4c859eSApple OSS Distributions ParentChangeNotifyInterestedDriversWillChange();
8016*0f4c859eSApple OSS Distributions break;
8017*0f4c859eSApple OSS Distributions
8018*0f4c859eSApple OSS Distributions case kIOPM_ParentChangeSetPowerState:
8019*0f4c859eSApple OSS Distributions ParentChangeSetPowerState();
8020*0f4c859eSApple OSS Distributions break;
8021*0f4c859eSApple OSS Distributions
8022*0f4c859eSApple OSS Distributions case kIOPM_ParentChangeWaitForPowerSettle:
8023*0f4c859eSApple OSS Distributions ParentChangeWaitForPowerSettle();
8024*0f4c859eSApple OSS Distributions break;
8025*0f4c859eSApple OSS Distributions
8026*0f4c859eSApple OSS Distributions case kIOPM_ParentChangeNotifyInterestedDriversDidChange:
8027*0f4c859eSApple OSS Distributions ParentChangeNotifyInterestedDriversDidChange();
8028*0f4c859eSApple OSS Distributions break;
8029*0f4c859eSApple OSS Distributions
8030*0f4c859eSApple OSS Distributions case kIOPM_ParentChangeTellCapabilityDidChange:
8031*0f4c859eSApple OSS Distributions ParentChangeTellCapabilityDidChange();
8032*0f4c859eSApple OSS Distributions break;
8033*0f4c859eSApple OSS Distributions
8034*0f4c859eSApple OSS Distributions case kIOPM_ParentChangeAcknowledgePowerChange:
8035*0f4c859eSApple OSS Distributions ParentChangeAcknowledgePowerChange();
8036*0f4c859eSApple OSS Distributions break;
8037*0f4c859eSApple OSS Distributions
8038*0f4c859eSApple OSS Distributions case kIOPM_DriverThreadCallDone:
8039*0f4c859eSApple OSS Distributions switch (fDriverCallReason) {
8040*0f4c859eSApple OSS Distributions case kDriverCallInformPreChange:
8041*0f4c859eSApple OSS Distributions case kDriverCallInformPostChange:
8042*0f4c859eSApple OSS Distributions notifyInterestedDriversDone();
8043*0f4c859eSApple OSS Distributions break;
8044*0f4c859eSApple OSS Distributions case kDriverCallSetPowerState:
8045*0f4c859eSApple OSS Distributions notifyControllingDriverDone();
8046*0f4c859eSApple OSS Distributions break;
8047*0f4c859eSApple OSS Distributions case kRootDomainInformPreChange:
8048*0f4c859eSApple OSS Distributions notifyRootDomainDone();
8049*0f4c859eSApple OSS Distributions break;
8050*0f4c859eSApple OSS Distributions default:
8051*0f4c859eSApple OSS Distributions panic("%s: bad call reason %x",
8052*0f4c859eSApple OSS Distributions getName(), fDriverCallReason);
8053*0f4c859eSApple OSS Distributions }
8054*0f4c859eSApple OSS Distributions break;
8055*0f4c859eSApple OSS Distributions
8056*0f4c859eSApple OSS Distributions case kIOPM_NotifyChildrenOrdered:
8057*0f4c859eSApple OSS Distributions notifyChildrenOrdered();
8058*0f4c859eSApple OSS Distributions break;
8059*0f4c859eSApple OSS Distributions
8060*0f4c859eSApple OSS Distributions case kIOPM_NotifyChildrenDelayed:
8061*0f4c859eSApple OSS Distributions notifyChildrenDelayed();
8062*0f4c859eSApple OSS Distributions break;
8063*0f4c859eSApple OSS Distributions
8064*0f4c859eSApple OSS Distributions case kIOPM_NotifyChildrenStart:
8065*0f4c859eSApple OSS Distributions // pop notifyAll() state saved by notifyInterestedDriversDone()
8066*0f4c859eSApple OSS Distributions MS_POP();
8067*0f4c859eSApple OSS Distributions notifyRootDomain();
8068*0f4c859eSApple OSS Distributions break;
8069*0f4c859eSApple OSS Distributions
8070*0f4c859eSApple OSS Distributions case kIOPM_SyncTellClientsPowerDown:
8071*0f4c859eSApple OSS Distributions // Root domain might self cancel due to assertions.
8072*0f4c859eSApple OSS Distributions if (IS_ROOT_DOMAIN) {
8073*0f4c859eSApple OSS Distributions bool cancel = (bool) fDoNotPowerDown;
8074*0f4c859eSApple OSS Distributions getPMRootDomain()->askChangeDownDone(
8075*0f4c859eSApple OSS Distributions &fHeadNoteChangeFlags, &cancel);
8076*0f4c859eSApple OSS Distributions fDoNotPowerDown = cancel;
8077*0f4c859eSApple OSS Distributions }
8078*0f4c859eSApple OSS Distributions if (!fDoNotPowerDown) {
8079*0f4c859eSApple OSS Distributions fMachineState = kIOPM_SyncTellPriorityClientsPowerDown;
8080*0f4c859eSApple OSS Distributions fOutOfBandParameter = kNotifyApps;
8081*0f4c859eSApple OSS Distributions tellChangeDown(fHeadNotePowerState);
8082*0f4c859eSApple OSS Distributions } else {
8083*0f4c859eSApple OSS Distributions // Cancelled by IOPMrootDomain::askChangeDownDone() or
8084*0f4c859eSApple OSS Distributions // askChangeDown/kNotifyApps
8085*0f4c859eSApple OSS Distributions OUR_PMLog(kPMLogIdleCancel, (uintptr_t) this, fMachineState);
8086*0f4c859eSApple OSS Distributions PM_ERROR("%s: idle cancel, state %u\n", fName, fMachineState);
8087*0f4c859eSApple OSS Distributions #if DEVELOPMENT || DEBUG
8088*0f4c859eSApple OSS Distributions record_system_event(SYSTEM_EVENT_TYPE_INFO,
8089*0f4c859eSApple OSS Distributions SYSTEM_EVENT_SUBSYSTEM_PMRD,
8090*0f4c859eSApple OSS Distributions "Idle Sleep", "%s idle cancel, state %u", fName, fMachineState
8091*0f4c859eSApple OSS Distributions );
8092*0f4c859eSApple OSS Distributions #endif /* DEVELOPMENT || DEBUG */
8093*0f4c859eSApple OSS Distributions tellNoChangeDown(fHeadNotePowerState);
8094*0f4c859eSApple OSS Distributions fHeadNoteChangeFlags |= kIOPMNotDone;
8095*0f4c859eSApple OSS Distributions OurChangeFinish();
8096*0f4c859eSApple OSS Distributions }
8097*0f4c859eSApple OSS Distributions break;
8098*0f4c859eSApple OSS Distributions
8099*0f4c859eSApple OSS Distributions case kIOPM_SyncTellPriorityClientsPowerDown:
8100*0f4c859eSApple OSS Distributions // PMRD: tellChangeDown/kNotifyApps done, was it cancelled?
8101*0f4c859eSApple OSS Distributions if (!fDoNotPowerDown) {
8102*0f4c859eSApple OSS Distributions fMachineState = kIOPM_SyncNotifyWillChange;
8103*0f4c859eSApple OSS Distributions fOutOfBandParameter = kNotifyPriority;
8104*0f4c859eSApple OSS Distributions tellChangeDown(fHeadNotePowerState);
8105*0f4c859eSApple OSS Distributions } else {
8106*0f4c859eSApple OSS Distributions OUR_PMLog(kPMLogIdleCancel, (uintptr_t) this, fMachineState);
8107*0f4c859eSApple OSS Distributions PM_ERROR("%s: idle revert, state %u\n", fName, fMachineState);
8108*0f4c859eSApple OSS Distributions tellChangeUp(fCurrentPowerState);
8109*0f4c859eSApple OSS Distributions fHeadNoteChangeFlags |= kIOPMNotDone;
8110*0f4c859eSApple OSS Distributions OurChangeFinish();
8111*0f4c859eSApple OSS Distributions }
8112*0f4c859eSApple OSS Distributions break;
8113*0f4c859eSApple OSS Distributions
8114*0f4c859eSApple OSS Distributions case kIOPM_SyncNotifyWillChange:
8115*0f4c859eSApple OSS Distributions if (kIOPMSyncNoChildNotify & fHeadNoteChangeFlags) {
8116*0f4c859eSApple OSS Distributions fMachineState = kIOPM_SyncFinish;
8117*0f4c859eSApple OSS Distributions continue;
8118*0f4c859eSApple OSS Distributions }
8119*0f4c859eSApple OSS Distributions fMachineState = kIOPM_SyncNotifyDidChange;
8120*0f4c859eSApple OSS Distributions fDriverCallReason = kDriverCallInformPreChange;
8121*0f4c859eSApple OSS Distributions notifyChildren();
8122*0f4c859eSApple OSS Distributions break;
8123*0f4c859eSApple OSS Distributions
8124*0f4c859eSApple OSS Distributions case kIOPM_SyncNotifyDidChange:
8125*0f4c859eSApple OSS Distributions fIsPreChange = false;
8126*0f4c859eSApple OSS Distributions
8127*0f4c859eSApple OSS Distributions if (fHeadNoteChangeFlags & kIOPMParentInitiated) {
8128*0f4c859eSApple OSS Distributions fMachineState = kIOPM_SyncFinish;
8129*0f4c859eSApple OSS Distributions } else {
8130*0f4c859eSApple OSS Distributions assert(IS_ROOT_DOMAIN);
8131*0f4c859eSApple OSS Distributions fMachineState = kIOPM_SyncTellCapabilityDidChange;
8132*0f4c859eSApple OSS Distributions }
8133*0f4c859eSApple OSS Distributions
8134*0f4c859eSApple OSS Distributions fDriverCallReason = kDriverCallInformPostChange;
8135*0f4c859eSApple OSS Distributions notifyChildren();
8136*0f4c859eSApple OSS Distributions break;
8137*0f4c859eSApple OSS Distributions
8138*0f4c859eSApple OSS Distributions case kIOPM_SyncTellCapabilityDidChange:
8139*0f4c859eSApple OSS Distributions tellSystemCapabilityChange( kIOPM_SyncFinish );
8140*0f4c859eSApple OSS Distributions break;
8141*0f4c859eSApple OSS Distributions
8142*0f4c859eSApple OSS Distributions case kIOPM_SyncFinish:
8143*0f4c859eSApple OSS Distributions if (fHeadNoteChangeFlags & kIOPMParentInitiated) {
8144*0f4c859eSApple OSS Distributions ParentChangeAcknowledgePowerChange();
8145*0f4c859eSApple OSS Distributions } else {
8146*0f4c859eSApple OSS Distributions OurChangeFinish();
8147*0f4c859eSApple OSS Distributions }
8148*0f4c859eSApple OSS Distributions break;
8149*0f4c859eSApple OSS Distributions
8150*0f4c859eSApple OSS Distributions case kIOPM_TellCapabilityChangeDone:
8151*0f4c859eSApple OSS Distributions if (fIsPreChange) {
8152*0f4c859eSApple OSS Distributions if (fOutOfBandParameter == kNotifyCapabilityChangePriority) {
8153*0f4c859eSApple OSS Distributions MS_POP(); // MS passed to tellSystemCapabilityChange()
8154*0f4c859eSApple OSS Distributions continue;
8155*0f4c859eSApple OSS Distributions }
8156*0f4c859eSApple OSS Distributions fOutOfBandParameter = kNotifyCapabilityChangePriority;
8157*0f4c859eSApple OSS Distributions } else {
8158*0f4c859eSApple OSS Distributions if (fOutOfBandParameter == kNotifyCapabilityChangeApps) {
8159*0f4c859eSApple OSS Distributions MS_POP(); // MS passed to tellSystemCapabilityChange()
8160*0f4c859eSApple OSS Distributions continue;
8161*0f4c859eSApple OSS Distributions }
8162*0f4c859eSApple OSS Distributions fOutOfBandParameter = kNotifyCapabilityChangeApps;
8163*0f4c859eSApple OSS Distributions }
8164*0f4c859eSApple OSS Distributions tellClientsWithResponse( fOutOfBandMessage );
8165*0f4c859eSApple OSS Distributions break;
8166*0f4c859eSApple OSS Distributions
8167*0f4c859eSApple OSS Distributions default:
8168*0f4c859eSApple OSS Distributions panic("PMWorkQueueInvoke: unknown machine state %x",
8169*0f4c859eSApple OSS Distributions fMachineState);
8170*0f4c859eSApple OSS Distributions }
8171*0f4c859eSApple OSS Distributions
8172*0f4c859eSApple OSS Distributions gIOPMRequest = NULL;
8173*0f4c859eSApple OSS Distributions
8174*0f4c859eSApple OSS Distributions if (fMachineState == kIOPM_Finished) {
8175*0f4c859eSApple OSS Distributions stop_watchdog_timer();
8176*0f4c859eSApple OSS Distributions done = true;
8177*0f4c859eSApple OSS Distributions break;
8178*0f4c859eSApple OSS Distributions }
8179*0f4c859eSApple OSS Distributions }
8180*0f4c859eSApple OSS Distributions
8181*0f4c859eSApple OSS Distributions return done;
8182*0f4c859eSApple OSS Distributions }
8183*0f4c859eSApple OSS Distributions
8184*0f4c859eSApple OSS Distributions //*********************************************************************************
8185*0f4c859eSApple OSS Distributions // [private] executePMRequest
8186*0f4c859eSApple OSS Distributions //*********************************************************************************
8187*0f4c859eSApple OSS Distributions
8188*0f4c859eSApple OSS Distributions void
executePMRequest(IOPMRequest * request)8189*0f4c859eSApple OSS Distributions IOService::executePMRequest( IOPMRequest * request )
8190*0f4c859eSApple OSS Distributions {
8191*0f4c859eSApple OSS Distributions assert( kIOPM_Finished == fMachineState );
8192*0f4c859eSApple OSS Distributions
8193*0f4c859eSApple OSS Distributions switch (request->getType()) {
8194*0f4c859eSApple OSS Distributions case kIOPMRequestTypePMStop:
8195*0f4c859eSApple OSS Distributions handlePMstop( request );
8196*0f4c859eSApple OSS Distributions break;
8197*0f4c859eSApple OSS Distributions
8198*0f4c859eSApple OSS Distributions case kIOPMRequestTypeAddPowerChild1:
8199*0f4c859eSApple OSS Distributions addPowerChild1( request );
8200*0f4c859eSApple OSS Distributions break;
8201*0f4c859eSApple OSS Distributions
8202*0f4c859eSApple OSS Distributions case kIOPMRequestTypeAddPowerChild2:
8203*0f4c859eSApple OSS Distributions addPowerChild2( request );
8204*0f4c859eSApple OSS Distributions break;
8205*0f4c859eSApple OSS Distributions
8206*0f4c859eSApple OSS Distributions case kIOPMRequestTypeAddPowerChild3:
8207*0f4c859eSApple OSS Distributions addPowerChild3( request );
8208*0f4c859eSApple OSS Distributions break;
8209*0f4c859eSApple OSS Distributions
8210*0f4c859eSApple OSS Distributions case kIOPMRequestTypeRegisterPowerDriver:
8211*0f4c859eSApple OSS Distributions handleRegisterPowerDriver( request );
8212*0f4c859eSApple OSS Distributions break;
8213*0f4c859eSApple OSS Distributions
8214*0f4c859eSApple OSS Distributions case kIOPMRequestTypeAdjustPowerState:
8215*0f4c859eSApple OSS Distributions fAdjustPowerScheduled = false;
8216*0f4c859eSApple OSS Distributions adjustPowerState();
8217*0f4c859eSApple OSS Distributions break;
8218*0f4c859eSApple OSS Distributions
8219*0f4c859eSApple OSS Distributions case kIOPMRequestTypePowerDomainWillChange:
8220*0f4c859eSApple OSS Distributions handlePowerDomainWillChangeTo( request );
8221*0f4c859eSApple OSS Distributions break;
8222*0f4c859eSApple OSS Distributions
8223*0f4c859eSApple OSS Distributions case kIOPMRequestTypePowerDomainDidChange:
8224*0f4c859eSApple OSS Distributions handlePowerDomainDidChangeTo( request );
8225*0f4c859eSApple OSS Distributions break;
8226*0f4c859eSApple OSS Distributions
8227*0f4c859eSApple OSS Distributions case kIOPMRequestTypeRequestPowerState:
8228*0f4c859eSApple OSS Distributions case kIOPMRequestTypeRequestPowerStateOverride:
8229*0f4c859eSApple OSS Distributions handleRequestPowerState( request );
8230*0f4c859eSApple OSS Distributions break;
8231*0f4c859eSApple OSS Distributions
8232*0f4c859eSApple OSS Distributions case kIOPMRequestTypePowerOverrideOnPriv:
8233*0f4c859eSApple OSS Distributions case kIOPMRequestTypePowerOverrideOffPriv:
8234*0f4c859eSApple OSS Distributions handlePowerOverrideChanged( request );
8235*0f4c859eSApple OSS Distributions break;
8236*0f4c859eSApple OSS Distributions
8237*0f4c859eSApple OSS Distributions case kIOPMRequestTypeActivityTickle:
8238*0f4c859eSApple OSS Distributions handleActivityTickle( request );
8239*0f4c859eSApple OSS Distributions break;
8240*0f4c859eSApple OSS Distributions
8241*0f4c859eSApple OSS Distributions case kIOPMRequestTypeSynchronizePowerTree:
8242*0f4c859eSApple OSS Distributions handleSynchronizePowerTree( request );
8243*0f4c859eSApple OSS Distributions break;
8244*0f4c859eSApple OSS Distributions
8245*0f4c859eSApple OSS Distributions case kIOPMRequestTypeSetIdleTimerPeriod:
8246*0f4c859eSApple OSS Distributions {
8247*0f4c859eSApple OSS Distributions fIdleTimerPeriod = (typeof(fIdleTimerPeriod))(uintptr_t) request->fArg0;
8248*0f4c859eSApple OSS Distributions fNextIdleTimerPeriod = fIdleTimerPeriod;
8249*0f4c859eSApple OSS Distributions if ((false == fLockedFlags.PMStop) && (fIdleTimerPeriod > 0)) {
8250*0f4c859eSApple OSS Distributions restartIdleTimer();
8251*0f4c859eSApple OSS Distributions }
8252*0f4c859eSApple OSS Distributions }
8253*0f4c859eSApple OSS Distributions break;
8254*0f4c859eSApple OSS Distributions
8255*0f4c859eSApple OSS Distributions case kIOPMRequestTypeIgnoreIdleTimer:
8256*0f4c859eSApple OSS Distributions fIdleTimerIgnored = request->fArg0 ? 1 : 0;
8257*0f4c859eSApple OSS Distributions break;
8258*0f4c859eSApple OSS Distributions
8259*0f4c859eSApple OSS Distributions case kIOPMRequestTypeQuiescePowerTree:
8260*0f4c859eSApple OSS Distributions gIOPMWorkQueue->finishQuiesceRequest(request);
8261*0f4c859eSApple OSS Distributions break;
8262*0f4c859eSApple OSS Distributions
8263*0f4c859eSApple OSS Distributions case kIOPMRequestTypeDeferredActivityTickle:
8264*0f4c859eSApple OSS Distributions handleDeferredActivityTickle(request);
8265*0f4c859eSApple OSS Distributions break;
8266*0f4c859eSApple OSS Distributions
8267*0f4c859eSApple OSS Distributions default:
8268*0f4c859eSApple OSS Distributions panic("executePMRequest: unknown request type %x", request->getType());
8269*0f4c859eSApple OSS Distributions }
8270*0f4c859eSApple OSS Distributions }
8271*0f4c859eSApple OSS Distributions
8272*0f4c859eSApple OSS Distributions //*********************************************************************************
8273*0f4c859eSApple OSS Distributions // [private] actionPMReplyQueue
8274*0f4c859eSApple OSS Distributions //
8275*0f4c859eSApple OSS Distributions // IOPMRequestQueue::checkForWork() passing a reply-type request to the
8276*0f4c859eSApple OSS Distributions // request target.
8277*0f4c859eSApple OSS Distributions //*********************************************************************************
8278*0f4c859eSApple OSS Distributions
8279*0f4c859eSApple OSS Distributions bool
actionPMReplyQueue(IOPMRequest * request,IOPMRequestQueue * queue)8280*0f4c859eSApple OSS Distributions IOService::actionPMReplyQueue( IOPMRequest * request, IOPMRequestQueue * queue )
8281*0f4c859eSApple OSS Distributions {
8282*0f4c859eSApple OSS Distributions bool more = false;
8283*0f4c859eSApple OSS Distributions
8284*0f4c859eSApple OSS Distributions assert( request && queue );
8285*0f4c859eSApple OSS Distributions assert( request->isReplyType());
8286*0f4c859eSApple OSS Distributions
8287*0f4c859eSApple OSS Distributions PM_LOG1("[A %02x] %p [%p %s] state %d\n",
8288*0f4c859eSApple OSS Distributions request->getType(), OBFUSCATE(request),
8289*0f4c859eSApple OSS Distributions OBFUSCATE(this), getName(), fMachineState);
8290*0f4c859eSApple OSS Distributions
8291*0f4c859eSApple OSS Distributions switch (request->getType()) {
8292*0f4c859eSApple OSS Distributions case kIOPMRequestTypeAllowPowerChange:
8293*0f4c859eSApple OSS Distributions case kIOPMRequestTypeCancelPowerChange:
8294*0f4c859eSApple OSS Distributions // Check if we are expecting this response.
8295*0f4c859eSApple OSS Distributions if (responseValid((uint32_t)(uintptr_t) request->fArg0,
8296*0f4c859eSApple OSS Distributions (int)(uintptr_t) request->fArg1)) {
8297*0f4c859eSApple OSS Distributions if (kIOPMRequestTypeCancelPowerChange == request->getType()) {
8298*0f4c859eSApple OSS Distributions // Clients are not allowed to cancel when kIOPMSkipAskPowerDown
8299*0f4c859eSApple OSS Distributions // flag is set. Only root domain will set this flag.
8300*0f4c859eSApple OSS Distributions // However, there is one exception to this rule. User-space PM
8301*0f4c859eSApple OSS Distributions // policy may choose to cancel sleep even after all clients have
8302*0f4c859eSApple OSS Distributions // been notified that we will lower power.
8303*0f4c859eSApple OSS Distributions
8304*0f4c859eSApple OSS Distributions if ((fMachineState == kIOPM_OurChangeTellUserPMPolicyPowerDown)
8305*0f4c859eSApple OSS Distributions || (fMachineState == kIOPM_OurChangeTellPriorityClientsPowerDown)
8306*0f4c859eSApple OSS Distributions || ((fHeadNoteChangeFlags & kIOPMSkipAskPowerDown) == 0)) {
8307*0f4c859eSApple OSS Distributions fDoNotPowerDown = true;
8308*0f4c859eSApple OSS Distributions
8309*0f4c859eSApple OSS Distributions OSString * name = (OSString *) request->fArg2;
8310*0f4c859eSApple OSS Distributions getPMRootDomain()->pmStatsRecordApplicationResponse(
8311*0f4c859eSApple OSS Distributions gIOPMStatsResponseCancel,
8312*0f4c859eSApple OSS Distributions name ? name->getCStringNoCopy() : "", 0,
8313*0f4c859eSApple OSS Distributions 0, (int)(uintptr_t) request->fArg1, NULL);
8314*0f4c859eSApple OSS Distributions }
8315*0f4c859eSApple OSS Distributions }
8316*0f4c859eSApple OSS Distributions
8317*0f4c859eSApple OSS Distributions // Update any clients that have exceeded their requested ack periods.
8318*0f4c859eSApple OSS Distributions updateClientResponses();
8319*0f4c859eSApple OSS Distributions
8320*0f4c859eSApple OSS Distributions if (checkForDone()) {
8321*0f4c859eSApple OSS Distributions stop_ack_timer();
8322*0f4c859eSApple OSS Distributions cleanClientResponses(false);
8323*0f4c859eSApple OSS Distributions more = true;
8324*0f4c859eSApple OSS Distributions }
8325*0f4c859eSApple OSS Distributions }
8326*0f4c859eSApple OSS Distributions // OSString containing app name in Arg2 must be released.
8327*0f4c859eSApple OSS Distributions if (request->getType() == kIOPMRequestTypeCancelPowerChange) {
8328*0f4c859eSApple OSS Distributions OSObject * obj = (OSObject *) request->fArg2;
8329*0f4c859eSApple OSS Distributions if (obj) {
8330*0f4c859eSApple OSS Distributions obj->release();
8331*0f4c859eSApple OSS Distributions }
8332*0f4c859eSApple OSS Distributions }
8333*0f4c859eSApple OSS Distributions break;
8334*0f4c859eSApple OSS Distributions
8335*0f4c859eSApple OSS Distributions case kIOPMRequestTypeAckPowerChange:
8336*0f4c859eSApple OSS Distributions more = handleAcknowledgePowerChange( request );
8337*0f4c859eSApple OSS Distributions break;
8338*0f4c859eSApple OSS Distributions
8339*0f4c859eSApple OSS Distributions case kIOPMRequestTypeAckSetPowerState:
8340*0f4c859eSApple OSS Distributions more = handleAcknowledgeSetPowerState( request );
8341*0f4c859eSApple OSS Distributions break;
8342*0f4c859eSApple OSS Distributions
8343*0f4c859eSApple OSS Distributions case kIOPMRequestTypeInterestChanged:
8344*0f4c859eSApple OSS Distributions handleInterestChanged( request );
8345*0f4c859eSApple OSS Distributions more = true;
8346*0f4c859eSApple OSS Distributions break;
8347*0f4c859eSApple OSS Distributions
8348*0f4c859eSApple OSS Distributions case kIOPMRequestTypeIdleCancel:
8349*0f4c859eSApple OSS Distributions if ((fMachineState == kIOPM_OurChangeTellClientsPowerDown)
8350*0f4c859eSApple OSS Distributions || (fMachineState == kIOPM_OurChangeTellUserPMPolicyPowerDown)
8351*0f4c859eSApple OSS Distributions || (fMachineState == kIOPM_OurChangeTellPriorityClientsPowerDown)
8352*0f4c859eSApple OSS Distributions || (fMachineState == kIOPM_SyncTellClientsPowerDown)
8353*0f4c859eSApple OSS Distributions || (fMachineState == kIOPM_SyncTellPriorityClientsPowerDown)) {
8354*0f4c859eSApple OSS Distributions OUR_PMLog(kPMLogIdleCancel, (uintptr_t) this, fMachineState);
8355*0f4c859eSApple OSS Distributions PM_LOG2("%s: cancel from machine state %d\n",
8356*0f4c859eSApple OSS Distributions getName(), fMachineState);
8357*0f4c859eSApple OSS Distributions fDoNotPowerDown = true;
8358*0f4c859eSApple OSS Distributions // Stop waiting for app replys.
8359*0f4c859eSApple OSS Distributions if ((fMachineState == kIOPM_OurChangeTellPriorityClientsPowerDown) ||
8360*0f4c859eSApple OSS Distributions (fMachineState == kIOPM_OurChangeTellUserPMPolicyPowerDown) ||
8361*0f4c859eSApple OSS Distributions (fMachineState == kIOPM_SyncTellPriorityClientsPowerDown) ||
8362*0f4c859eSApple OSS Distributions (fMachineState == kIOPM_SyncTellClientsPowerDown)) {
8363*0f4c859eSApple OSS Distributions cleanClientResponses(false);
8364*0f4c859eSApple OSS Distributions }
8365*0f4c859eSApple OSS Distributions more = true;
8366*0f4c859eSApple OSS Distributions }
8367*0f4c859eSApple OSS Distributions break;
8368*0f4c859eSApple OSS Distributions
8369*0f4c859eSApple OSS Distributions case kIOPMRequestTypeChildNotifyDelayCancel:
8370*0f4c859eSApple OSS Distributions if (fMachineState == kIOPM_NotifyChildrenDelayed) {
8371*0f4c859eSApple OSS Distributions PM_LOG2("%s: delay notify cancelled\n", getName());
8372*0f4c859eSApple OSS Distributions notifyChildrenDelayed();
8373*0f4c859eSApple OSS Distributions }
8374*0f4c859eSApple OSS Distributions break;
8375*0f4c859eSApple OSS Distributions
8376*0f4c859eSApple OSS Distributions default:
8377*0f4c859eSApple OSS Distributions panic("PMReplyQueue: unknown reply type %x", request->getType());
8378*0f4c859eSApple OSS Distributions }
8379*0f4c859eSApple OSS Distributions
8380*0f4c859eSApple OSS Distributions more |= gIOPMCompletionQueue->queuePMRequest(request);
8381*0f4c859eSApple OSS Distributions if (more) {
8382*0f4c859eSApple OSS Distributions gIOPMWorkQueue->incrementProducerCount();
8383*0f4c859eSApple OSS Distributions }
8384*0f4c859eSApple OSS Distributions
8385*0f4c859eSApple OSS Distributions return more;
8386*0f4c859eSApple OSS Distributions }
8387*0f4c859eSApple OSS Distributions
8388*0f4c859eSApple OSS Distributions //*********************************************************************************
8389*0f4c859eSApple OSS Distributions // [private] assertPMDriverCall / deassertPMDriverCall
8390*0f4c859eSApple OSS Distributions //*********************************************************************************
8391*0f4c859eSApple OSS Distributions
8392*0f4c859eSApple OSS Distributions bool
assertPMDriverCall(IOPMDriverCallEntry * entry,IOOptionBits method,const IOPMinformee * inform,IOOptionBits options)8393*0f4c859eSApple OSS Distributions IOService::assertPMDriverCall(
8394*0f4c859eSApple OSS Distributions IOPMDriverCallEntry * entry,
8395*0f4c859eSApple OSS Distributions IOOptionBits method,
8396*0f4c859eSApple OSS Distributions const IOPMinformee * inform,
8397*0f4c859eSApple OSS Distributions IOOptionBits options )
8398*0f4c859eSApple OSS Distributions {
8399*0f4c859eSApple OSS Distributions IOService * target = NULL;
8400*0f4c859eSApple OSS Distributions bool ok = false;
8401*0f4c859eSApple OSS Distributions
8402*0f4c859eSApple OSS Distributions if (!initialized) {
8403*0f4c859eSApple OSS Distributions return false;
8404*0f4c859eSApple OSS Distributions }
8405*0f4c859eSApple OSS Distributions
8406*0f4c859eSApple OSS Distributions PM_LOCK();
8407*0f4c859eSApple OSS Distributions
8408*0f4c859eSApple OSS Distributions if (fLockedFlags.PMStop) {
8409*0f4c859eSApple OSS Distributions goto fail;
8410*0f4c859eSApple OSS Distributions }
8411*0f4c859eSApple OSS Distributions
8412*0f4c859eSApple OSS Distributions if (((options & kIOPMDriverCallNoInactiveCheck) == 0) && isInactive()) {
8413*0f4c859eSApple OSS Distributions goto fail;
8414*0f4c859eSApple OSS Distributions }
8415*0f4c859eSApple OSS Distributions
8416*0f4c859eSApple OSS Distributions if (inform) {
8417*0f4c859eSApple OSS Distributions if (!inform->active) {
8418*0f4c859eSApple OSS Distributions goto fail;
8419*0f4c859eSApple OSS Distributions }
8420*0f4c859eSApple OSS Distributions target = inform->whatObject;
8421*0f4c859eSApple OSS Distributions if (target->isInactive()) {
8422*0f4c859eSApple OSS Distributions goto fail;
8423*0f4c859eSApple OSS Distributions }
8424*0f4c859eSApple OSS Distributions }
8425*0f4c859eSApple OSS Distributions
8426*0f4c859eSApple OSS Distributions // Record calling address for sleep failure diagnostics
8427*0f4c859eSApple OSS Distributions switch (method) {
8428*0f4c859eSApple OSS Distributions case kIOPMDriverCallMethodSetPowerState:
8429*0f4c859eSApple OSS Distributions entry->callMethod = OSMemberFunctionCast(const void *, fControllingDriver, &IOService::setPowerState);
8430*0f4c859eSApple OSS Distributions break;
8431*0f4c859eSApple OSS Distributions case kIOPMDriverCallMethodWillChange:
8432*0f4c859eSApple OSS Distributions entry->callMethod = OSMemberFunctionCast(const void *, target, &IOService::powerStateWillChangeTo);
8433*0f4c859eSApple OSS Distributions break;
8434*0f4c859eSApple OSS Distributions case kIOPMDriverCallMethodDidChange:
8435*0f4c859eSApple OSS Distributions entry->callMethod = OSMemberFunctionCast(const void *, target, &IOService::powerStateDidChangeTo);
8436*0f4c859eSApple OSS Distributions break;
8437*0f4c859eSApple OSS Distributions case kIOPMDriverCallMethodUnknown:
8438*0f4c859eSApple OSS Distributions case kIOPMDriverCallMethodSetAggressive:
8439*0f4c859eSApple OSS Distributions default:
8440*0f4c859eSApple OSS Distributions entry->callMethod = NULL;
8441*0f4c859eSApple OSS Distributions break;
8442*0f4c859eSApple OSS Distributions }
8443*0f4c859eSApple OSS Distributions
8444*0f4c859eSApple OSS Distributions entry->thread = current_thread();
8445*0f4c859eSApple OSS Distributions entry->target = target;
8446*0f4c859eSApple OSS Distributions queue_enter(&fPMDriverCallQueue, entry, IOPMDriverCallEntry *, link);
8447*0f4c859eSApple OSS Distributions ok = true;
8448*0f4c859eSApple OSS Distributions
8449*0f4c859eSApple OSS Distributions fail:
8450*0f4c859eSApple OSS Distributions PM_UNLOCK();
8451*0f4c859eSApple OSS Distributions
8452*0f4c859eSApple OSS Distributions return ok;
8453*0f4c859eSApple OSS Distributions }
8454*0f4c859eSApple OSS Distributions
8455*0f4c859eSApple OSS Distributions void
deassertPMDriverCall(IOPMDriverCallEntry * entry)8456*0f4c859eSApple OSS Distributions IOService::deassertPMDriverCall( IOPMDriverCallEntry * entry )
8457*0f4c859eSApple OSS Distributions {
8458*0f4c859eSApple OSS Distributions bool wakeup = false;
8459*0f4c859eSApple OSS Distributions
8460*0f4c859eSApple OSS Distributions PM_LOCK();
8461*0f4c859eSApple OSS Distributions
8462*0f4c859eSApple OSS Distributions assert( !queue_empty(&fPMDriverCallQueue));
8463*0f4c859eSApple OSS Distributions queue_remove(&fPMDriverCallQueue, entry, IOPMDriverCallEntry *, link);
8464*0f4c859eSApple OSS Distributions if (fLockedFlags.PMDriverCallWait) {
8465*0f4c859eSApple OSS Distributions wakeup = true;
8466*0f4c859eSApple OSS Distributions }
8467*0f4c859eSApple OSS Distributions
8468*0f4c859eSApple OSS Distributions PM_UNLOCK();
8469*0f4c859eSApple OSS Distributions
8470*0f4c859eSApple OSS Distributions if (wakeup) {
8471*0f4c859eSApple OSS Distributions PM_LOCK_WAKEUP(&fPMDriverCallQueue);
8472*0f4c859eSApple OSS Distributions }
8473*0f4c859eSApple OSS Distributions }
8474*0f4c859eSApple OSS Distributions
8475*0f4c859eSApple OSS Distributions bool
getBlockingDriverCall(thread_t * thread,const void ** callMethod)8476*0f4c859eSApple OSS Distributions IOService::getBlockingDriverCall(thread_t *thread, const void **callMethod)
8477*0f4c859eSApple OSS Distributions {
8478*0f4c859eSApple OSS Distributions const IOPMDriverCallEntry * entry = NULL;
8479*0f4c859eSApple OSS Distributions bool blocked = false;
8480*0f4c859eSApple OSS Distributions
8481*0f4c859eSApple OSS Distributions if (!initialized) {
8482*0f4c859eSApple OSS Distributions return false;
8483*0f4c859eSApple OSS Distributions }
8484*0f4c859eSApple OSS Distributions
8485*0f4c859eSApple OSS Distributions if (current_thread() != gIOPMWatchDogThread) {
8486*0f4c859eSApple OSS Distributions // Meant to be accessed only from watchdog thread
8487*0f4c859eSApple OSS Distributions return false;
8488*0f4c859eSApple OSS Distributions }
8489*0f4c859eSApple OSS Distributions
8490*0f4c859eSApple OSS Distributions PM_LOCK();
8491*0f4c859eSApple OSS Distributions entry = qe_queue_first(&fPMDriverCallQueue, IOPMDriverCallEntry, link);
8492*0f4c859eSApple OSS Distributions if (entry) {
8493*0f4c859eSApple OSS Distributions *thread = entry->thread;
8494*0f4c859eSApple OSS Distributions *callMethod = entry->callMethod;
8495*0f4c859eSApple OSS Distributions blocked = true;
8496*0f4c859eSApple OSS Distributions }
8497*0f4c859eSApple OSS Distributions PM_UNLOCK();
8498*0f4c859eSApple OSS Distributions
8499*0f4c859eSApple OSS Distributions return blocked;
8500*0f4c859eSApple OSS Distributions }
8501*0f4c859eSApple OSS Distributions
8502*0f4c859eSApple OSS Distributions
8503*0f4c859eSApple OSS Distributions void
waitForPMDriverCall(IOService * target)8504*0f4c859eSApple OSS Distributions IOService::waitForPMDriverCall( IOService * target )
8505*0f4c859eSApple OSS Distributions {
8506*0f4c859eSApple OSS Distributions const IOPMDriverCallEntry * entry;
8507*0f4c859eSApple OSS Distributions thread_t thread = current_thread();
8508*0f4c859eSApple OSS Distributions AbsoluteTime deadline;
8509*0f4c859eSApple OSS Distributions int waitResult;
8510*0f4c859eSApple OSS Distributions bool log = true;
8511*0f4c859eSApple OSS Distributions bool wait;
8512*0f4c859eSApple OSS Distributions
8513*0f4c859eSApple OSS Distributions do {
8514*0f4c859eSApple OSS Distributions wait = false;
8515*0f4c859eSApple OSS Distributions queue_iterate(&fPMDriverCallQueue, entry, const IOPMDriverCallEntry *, link)
8516*0f4c859eSApple OSS Distributions {
8517*0f4c859eSApple OSS Distributions // Target of interested driver call
8518*0f4c859eSApple OSS Distributions if (target && (target != entry->target)) {
8519*0f4c859eSApple OSS Distributions continue;
8520*0f4c859eSApple OSS Distributions }
8521*0f4c859eSApple OSS Distributions
8522*0f4c859eSApple OSS Distributions if (entry->thread == thread) {
8523*0f4c859eSApple OSS Distributions if (log) {
8524*0f4c859eSApple OSS Distributions PM_LOG("%s: %s(%s) on PM thread\n",
8525*0f4c859eSApple OSS Distributions fName, __FUNCTION__, target ? target->getName() : "");
8526*0f4c859eSApple OSS Distributions OSReportWithBacktrace("%s: %s(%s) on PM thread\n",
8527*0f4c859eSApple OSS Distributions fName, __FUNCTION__, target ? target->getName() : "");
8528*0f4c859eSApple OSS Distributions log = false;
8529*0f4c859eSApple OSS Distributions }
8530*0f4c859eSApple OSS Distributions continue;
8531*0f4c859eSApple OSS Distributions }
8532*0f4c859eSApple OSS Distributions
8533*0f4c859eSApple OSS Distributions wait = true;
8534*0f4c859eSApple OSS Distributions break;
8535*0f4c859eSApple OSS Distributions }
8536*0f4c859eSApple OSS Distributions
8537*0f4c859eSApple OSS Distributions if (wait) {
8538*0f4c859eSApple OSS Distributions fLockedFlags.PMDriverCallWait = true;
8539*0f4c859eSApple OSS Distributions clock_interval_to_deadline(15, kSecondScale, &deadline);
8540*0f4c859eSApple OSS Distributions waitResult = PM_LOCK_SLEEP(&fPMDriverCallQueue, deadline);
8541*0f4c859eSApple OSS Distributions fLockedFlags.PMDriverCallWait = false;
8542*0f4c859eSApple OSS Distributions if (THREAD_TIMED_OUT == waitResult) {
8543*0f4c859eSApple OSS Distributions PM_ERROR("%s: waitForPMDriverCall timeout\n", fName);
8544*0f4c859eSApple OSS Distributions wait = false;
8545*0f4c859eSApple OSS Distributions }
8546*0f4c859eSApple OSS Distributions }
8547*0f4c859eSApple OSS Distributions } while (wait);
8548*0f4c859eSApple OSS Distributions }
8549*0f4c859eSApple OSS Distributions
8550*0f4c859eSApple OSS Distributions //*********************************************************************************
8551*0f4c859eSApple OSS Distributions // [private] Debug helpers
8552*0f4c859eSApple OSS Distributions //*********************************************************************************
8553*0f4c859eSApple OSS Distributions
8554*0f4c859eSApple OSS Distributions const char *
getIOMessageString(uint32_t msg)8555*0f4c859eSApple OSS Distributions IOService::getIOMessageString( uint32_t msg )
8556*0f4c859eSApple OSS Distributions {
8557*0f4c859eSApple OSS Distributions #define MSG_ENTRY(x) {(int) x, #x}
8558*0f4c859eSApple OSS Distributions
8559*0f4c859eSApple OSS Distributions static const IONamedValue msgNames[] = {
8560*0f4c859eSApple OSS Distributions MSG_ENTRY( kIOMessageCanDevicePowerOff ),
8561*0f4c859eSApple OSS Distributions MSG_ENTRY( kIOMessageDeviceWillPowerOff ),
8562*0f4c859eSApple OSS Distributions MSG_ENTRY( kIOMessageDeviceWillNotPowerOff ),
8563*0f4c859eSApple OSS Distributions MSG_ENTRY( kIOMessageDeviceHasPoweredOn ),
8564*0f4c859eSApple OSS Distributions MSG_ENTRY( kIOMessageCanSystemPowerOff ),
8565*0f4c859eSApple OSS Distributions MSG_ENTRY( kIOMessageSystemWillPowerOff ),
8566*0f4c859eSApple OSS Distributions MSG_ENTRY( kIOMessageSystemWillNotPowerOff ),
8567*0f4c859eSApple OSS Distributions MSG_ENTRY( kIOMessageCanSystemSleep ),
8568*0f4c859eSApple OSS Distributions MSG_ENTRY( kIOMessageSystemWillSleep ),
8569*0f4c859eSApple OSS Distributions MSG_ENTRY( kIOMessageSystemWillNotSleep ),
8570*0f4c859eSApple OSS Distributions MSG_ENTRY( kIOMessageSystemHasPoweredOn ),
8571*0f4c859eSApple OSS Distributions MSG_ENTRY( kIOMessageSystemWillRestart ),
8572*0f4c859eSApple OSS Distributions MSG_ENTRY( kIOMessageSystemWillPowerOn ),
8573*0f4c859eSApple OSS Distributions MSG_ENTRY( kIOMessageSystemCapabilityChange ),
8574*0f4c859eSApple OSS Distributions MSG_ENTRY( kIOPMMessageLastCallBeforeSleep ),
8575*0f4c859eSApple OSS Distributions MSG_ENTRY( kIOMessageSystemPagingOff ),
8576*0f4c859eSApple OSS Distributions { 0, NULL }
8577*0f4c859eSApple OSS Distributions };
8578*0f4c859eSApple OSS Distributions
8579*0f4c859eSApple OSS Distributions return IOFindNameForValue(msg, msgNames);
8580*0f4c859eSApple OSS Distributions }
8581*0f4c859eSApple OSS Distributions
8582*0f4c859eSApple OSS Distributions static const char *
getNotificationPhaseString(uint32_t phase)8583*0f4c859eSApple OSS Distributions getNotificationPhaseString( uint32_t phase )
8584*0f4c859eSApple OSS Distributions {
8585*0f4c859eSApple OSS Distributions #define PHASE_ENTRY(x) {(int) x, #x}
8586*0f4c859eSApple OSS Distributions
8587*0f4c859eSApple OSS Distributions static const IONamedValue phaseNames[] = {
8588*0f4c859eSApple OSS Distributions PHASE_ENTRY( kNotifyApps ),
8589*0f4c859eSApple OSS Distributions PHASE_ENTRY( kNotifyPriority ),
8590*0f4c859eSApple OSS Distributions PHASE_ENTRY( kNotifyCapabilityChangeApps ),
8591*0f4c859eSApple OSS Distributions PHASE_ENTRY( kNotifyCapabilityChangePriority ),
8592*0f4c859eSApple OSS Distributions { 0, NULL }
8593*0f4c859eSApple OSS Distributions };
8594*0f4c859eSApple OSS Distributions
8595*0f4c859eSApple OSS Distributions return IOFindNameForValue(phase, phaseNames);
8596*0f4c859eSApple OSS Distributions }
8597*0f4c859eSApple OSS Distributions
8598*0f4c859eSApple OSS Distributions // MARK: -
8599*0f4c859eSApple OSS Distributions // MARK: IOPMRequest
8600*0f4c859eSApple OSS Distributions
8601*0f4c859eSApple OSS Distributions //*********************************************************************************
8602*0f4c859eSApple OSS Distributions // IOPMRequest Class
8603*0f4c859eSApple OSS Distributions //
8604*0f4c859eSApple OSS Distributions // Requests from PM clients, and also used for inter-object messaging within PM.
8605*0f4c859eSApple OSS Distributions //*********************************************************************************
8606*0f4c859eSApple OSS Distributions
8607*0f4c859eSApple OSS Distributions OSDefineMetaClassAndStructors( IOPMRequest, IOCommand );
8608*0f4c859eSApple OSS Distributions
8609*0f4c859eSApple OSS Distributions IOPMRequest *
create(void)8610*0f4c859eSApple OSS Distributions IOPMRequest::create( void )
8611*0f4c859eSApple OSS Distributions {
8612*0f4c859eSApple OSS Distributions IOPMRequest * me = OSTypeAlloc(IOPMRequest);
8613*0f4c859eSApple OSS Distributions if (me && !me->init(NULL, kIOPMRequestTypeInvalid)) {
8614*0f4c859eSApple OSS Distributions me->release();
8615*0f4c859eSApple OSS Distributions me = NULL;
8616*0f4c859eSApple OSS Distributions }
8617*0f4c859eSApple OSS Distributions return me;
8618*0f4c859eSApple OSS Distributions }
8619*0f4c859eSApple OSS Distributions
8620*0f4c859eSApple OSS Distributions bool
init(IOService * target,IOOptionBits type)8621*0f4c859eSApple OSS Distributions IOPMRequest::init( IOService * target, IOOptionBits type )
8622*0f4c859eSApple OSS Distributions {
8623*0f4c859eSApple OSS Distributions if (!IOCommand::init()) {
8624*0f4c859eSApple OSS Distributions return false;
8625*0f4c859eSApple OSS Distributions }
8626*0f4c859eSApple OSS Distributions
8627*0f4c859eSApple OSS Distributions fRequestType = type;
8628*0f4c859eSApple OSS Distributions fTarget = target;
8629*0f4c859eSApple OSS Distributions
8630*0f4c859eSApple OSS Distributions if (fTarget) {
8631*0f4c859eSApple OSS Distributions fTarget->retain();
8632*0f4c859eSApple OSS Distributions }
8633*0f4c859eSApple OSS Distributions
8634*0f4c859eSApple OSS Distributions // Root node and root domain requests does not prevent the power tree from
8635*0f4c859eSApple OSS Distributions // becoming quiescent.
8636*0f4c859eSApple OSS Distributions
8637*0f4c859eSApple OSS Distributions fIsQuiesceBlocker = ((fTarget != gIOPMRootNode) &&
8638*0f4c859eSApple OSS Distributions (fTarget != IOService::getPMRootDomain()));
8639*0f4c859eSApple OSS Distributions
8640*0f4c859eSApple OSS Distributions return true;
8641*0f4c859eSApple OSS Distributions }
8642*0f4c859eSApple OSS Distributions
8643*0f4c859eSApple OSS Distributions void
reset(void)8644*0f4c859eSApple OSS Distributions IOPMRequest::reset( void )
8645*0f4c859eSApple OSS Distributions {
8646*0f4c859eSApple OSS Distributions assert( fWorkWaitCount == 0 );
8647*0f4c859eSApple OSS Distributions assert( fFreeWaitCount == 0 );
8648*0f4c859eSApple OSS Distributions
8649*0f4c859eSApple OSS Distributions detachNextRequest();
8650*0f4c859eSApple OSS Distributions detachRootRequest();
8651*0f4c859eSApple OSS Distributions
8652*0f4c859eSApple OSS Distributions if (fCompletionAction && (fRequestType == kIOPMRequestTypeQuiescePowerTree)) {
8653*0f4c859eSApple OSS Distributions // Call the completion on PM work loop context
8654*0f4c859eSApple OSS Distributions fCompletionAction(fCompletionTarget, fCompletionParam);
8655*0f4c859eSApple OSS Distributions fCompletionAction = NULL;
8656*0f4c859eSApple OSS Distributions }
8657*0f4c859eSApple OSS Distributions
8658*0f4c859eSApple OSS Distributions fRequestType = kIOPMRequestTypeInvalid;
8659*0f4c859eSApple OSS Distributions
8660*0f4c859eSApple OSS Distributions if (fTarget) {
8661*0f4c859eSApple OSS Distributions fTarget->release();
8662*0f4c859eSApple OSS Distributions fTarget = NULL;
8663*0f4c859eSApple OSS Distributions }
8664*0f4c859eSApple OSS Distributions }
8665*0f4c859eSApple OSS Distributions
8666*0f4c859eSApple OSS Distributions bool
attachNextRequest(IOPMRequest * next)8667*0f4c859eSApple OSS Distributions IOPMRequest::attachNextRequest( IOPMRequest * next )
8668*0f4c859eSApple OSS Distributions {
8669*0f4c859eSApple OSS Distributions bool ok = false;
8670*0f4c859eSApple OSS Distributions
8671*0f4c859eSApple OSS Distributions if (!fRequestNext) {
8672*0f4c859eSApple OSS Distributions // Postpone the execution of the next request after
8673*0f4c859eSApple OSS Distributions // this request.
8674*0f4c859eSApple OSS Distributions fRequestNext = next;
8675*0f4c859eSApple OSS Distributions fRequestNext->fWorkWaitCount++;
8676*0f4c859eSApple OSS Distributions #if LOG_REQUEST_ATTACH
8677*0f4c859eSApple OSS Distributions PM_LOG("Attached next: %p [0x%x] -> %p [0x%x, %u] %s\n",
8678*0f4c859eSApple OSS Distributions OBFUSCATE(this), fRequestType, OBFUSCATE(fRequestNext),
8679*0f4c859eSApple OSS Distributions fRequestNext->fRequestType,
8680*0f4c859eSApple OSS Distributions (uint32_t) fRequestNext->fWorkWaitCount,
8681*0f4c859eSApple OSS Distributions fTarget->getName());
8682*0f4c859eSApple OSS Distributions #endif
8683*0f4c859eSApple OSS Distributions ok = true;
8684*0f4c859eSApple OSS Distributions }
8685*0f4c859eSApple OSS Distributions return ok;
8686*0f4c859eSApple OSS Distributions }
8687*0f4c859eSApple OSS Distributions
8688*0f4c859eSApple OSS Distributions bool
detachNextRequest(void)8689*0f4c859eSApple OSS Distributions IOPMRequest::detachNextRequest( void )
8690*0f4c859eSApple OSS Distributions {
8691*0f4c859eSApple OSS Distributions bool ok = false;
8692*0f4c859eSApple OSS Distributions
8693*0f4c859eSApple OSS Distributions if (fRequestNext) {
8694*0f4c859eSApple OSS Distributions assert(fRequestNext->fWorkWaitCount);
8695*0f4c859eSApple OSS Distributions if (fRequestNext->fWorkWaitCount) {
8696*0f4c859eSApple OSS Distributions fRequestNext->fWorkWaitCount--;
8697*0f4c859eSApple OSS Distributions }
8698*0f4c859eSApple OSS Distributions #if LOG_REQUEST_ATTACH
8699*0f4c859eSApple OSS Distributions PM_LOG("Detached next: %p [0x%x] -> %p [0x%x, %u] %s\n",
8700*0f4c859eSApple OSS Distributions OBFUSCATE(this), fRequestType, OBFUSCATE(fRequestNext),
8701*0f4c859eSApple OSS Distributions fRequestNext->fRequestType,
8702*0f4c859eSApple OSS Distributions (uint32_t) fRequestNext->fWorkWaitCount,
8703*0f4c859eSApple OSS Distributions fTarget->getName());
8704*0f4c859eSApple OSS Distributions #endif
8705*0f4c859eSApple OSS Distributions fRequestNext = NULL;
8706*0f4c859eSApple OSS Distributions ok = true;
8707*0f4c859eSApple OSS Distributions }
8708*0f4c859eSApple OSS Distributions return ok;
8709*0f4c859eSApple OSS Distributions }
8710*0f4c859eSApple OSS Distributions
8711*0f4c859eSApple OSS Distributions bool
attachRootRequest(IOPMRequest * root)8712*0f4c859eSApple OSS Distributions IOPMRequest::attachRootRequest( IOPMRequest * root )
8713*0f4c859eSApple OSS Distributions {
8714*0f4c859eSApple OSS Distributions bool ok = false;
8715*0f4c859eSApple OSS Distributions
8716*0f4c859eSApple OSS Distributions if (!fRequestRoot) {
8717*0f4c859eSApple OSS Distributions // Delay the completion of the root request after
8718*0f4c859eSApple OSS Distributions // this request.
8719*0f4c859eSApple OSS Distributions fRequestRoot = root;
8720*0f4c859eSApple OSS Distributions fRequestRoot->fFreeWaitCount++;
8721*0f4c859eSApple OSS Distributions #if LOG_REQUEST_ATTACH
8722*0f4c859eSApple OSS Distributions PM_LOG("Attached root: %p [0x%x] -> %p [0x%x, %u] %s\n",
8723*0f4c859eSApple OSS Distributions OBFUSCATE(this), (uint32_t) fType, OBFUSCATE(fRequestRoot),
8724*0f4c859eSApple OSS Distributions (uint32_t) fRequestRoot->fType,
8725*0f4c859eSApple OSS Distributions (uint32_t) fRequestRoot->fFreeWaitCount,
8726*0f4c859eSApple OSS Distributions fTarget->getName());
8727*0f4c859eSApple OSS Distributions #endif
8728*0f4c859eSApple OSS Distributions ok = true;
8729*0f4c859eSApple OSS Distributions }
8730*0f4c859eSApple OSS Distributions return ok;
8731*0f4c859eSApple OSS Distributions }
8732*0f4c859eSApple OSS Distributions
8733*0f4c859eSApple OSS Distributions bool
detachRootRequest(void)8734*0f4c859eSApple OSS Distributions IOPMRequest::detachRootRequest( void )
8735*0f4c859eSApple OSS Distributions {
8736*0f4c859eSApple OSS Distributions bool ok = false;
8737*0f4c859eSApple OSS Distributions
8738*0f4c859eSApple OSS Distributions if (fRequestRoot) {
8739*0f4c859eSApple OSS Distributions assert(fRequestRoot->fFreeWaitCount);
8740*0f4c859eSApple OSS Distributions if (fRequestRoot->fFreeWaitCount) {
8741*0f4c859eSApple OSS Distributions fRequestRoot->fFreeWaitCount--;
8742*0f4c859eSApple OSS Distributions }
8743*0f4c859eSApple OSS Distributions #if LOG_REQUEST_ATTACH
8744*0f4c859eSApple OSS Distributions PM_LOG("Detached root: %p [0x%x] -> %p [0x%x, %u] %s\n",
8745*0f4c859eSApple OSS Distributions OBFUSCATE(this), (uint32_t) fType, OBFUSCATE(fRequestRoot),
8746*0f4c859eSApple OSS Distributions (uint32_t) fRequestRoot->fType,
8747*0f4c859eSApple OSS Distributions (uint32_t) fRequestRoot->fFreeWaitCount,
8748*0f4c859eSApple OSS Distributions fTarget->getName());
8749*0f4c859eSApple OSS Distributions #endif
8750*0f4c859eSApple OSS Distributions fRequestRoot = NULL;
8751*0f4c859eSApple OSS Distributions ok = true;
8752*0f4c859eSApple OSS Distributions }
8753*0f4c859eSApple OSS Distributions return ok;
8754*0f4c859eSApple OSS Distributions }
8755*0f4c859eSApple OSS Distributions
8756*0f4c859eSApple OSS Distributions // MARK: -
8757*0f4c859eSApple OSS Distributions // MARK: IOPMRequestQueue
8758*0f4c859eSApple OSS Distributions
8759*0f4c859eSApple OSS Distributions //*********************************************************************************
8760*0f4c859eSApple OSS Distributions // IOPMRequestQueue Class
8761*0f4c859eSApple OSS Distributions //
8762*0f4c859eSApple OSS Distributions // Global queues. Queues are created once and never released.
8763*0f4c859eSApple OSS Distributions //*********************************************************************************
8764*0f4c859eSApple OSS Distributions
8765*0f4c859eSApple OSS Distributions OSDefineMetaClassAndStructors( IOPMRequestQueue, IOEventSource );
8766*0f4c859eSApple OSS Distributions
8767*0f4c859eSApple OSS Distributions #pragma clang diagnostic push
8768*0f4c859eSApple OSS Distributions #pragma clang diagnostic ignored "-Wcast-function-type"
8769*0f4c859eSApple OSS Distributions
8770*0f4c859eSApple OSS Distributions IOPMRequestQueue *
create(IOService * inOwner,Action inAction)8771*0f4c859eSApple OSS Distributions IOPMRequestQueue::create( IOService * inOwner, Action inAction )
8772*0f4c859eSApple OSS Distributions {
8773*0f4c859eSApple OSS Distributions IOPMRequestQueue * me = OSTypeAlloc(IOPMRequestQueue);
8774*0f4c859eSApple OSS Distributions if (me && !me->init(inOwner, inAction)) {
8775*0f4c859eSApple OSS Distributions me->release();
8776*0f4c859eSApple OSS Distributions me = NULL;
8777*0f4c859eSApple OSS Distributions }
8778*0f4c859eSApple OSS Distributions return me;
8779*0f4c859eSApple OSS Distributions }
8780*0f4c859eSApple OSS Distributions
8781*0f4c859eSApple OSS Distributions bool
init(IOService * inOwner,Action inAction)8782*0f4c859eSApple OSS Distributions IOPMRequestQueue::init( IOService * inOwner, Action inAction )
8783*0f4c859eSApple OSS Distributions {
8784*0f4c859eSApple OSS Distributions if (!inAction || !IOEventSource::init(inOwner, (IOEventSourceAction)inAction)) {
8785*0f4c859eSApple OSS Distributions return false;
8786*0f4c859eSApple OSS Distributions }
8787*0f4c859eSApple OSS Distributions
8788*0f4c859eSApple OSS Distributions queue_init(&fQueue);
8789*0f4c859eSApple OSS Distributions fLock = IOLockAlloc();
8790*0f4c859eSApple OSS Distributions return fLock != NULL;
8791*0f4c859eSApple OSS Distributions }
8792*0f4c859eSApple OSS Distributions
8793*0f4c859eSApple OSS Distributions #pragma clang diagnostic pop
8794*0f4c859eSApple OSS Distributions
8795*0f4c859eSApple OSS Distributions void
free(void)8796*0f4c859eSApple OSS Distributions IOPMRequestQueue::free( void )
8797*0f4c859eSApple OSS Distributions {
8798*0f4c859eSApple OSS Distributions if (fLock) {
8799*0f4c859eSApple OSS Distributions IOLockFree(fLock);
8800*0f4c859eSApple OSS Distributions fLock = NULL;
8801*0f4c859eSApple OSS Distributions }
8802*0f4c859eSApple OSS Distributions return IOEventSource::free();
8803*0f4c859eSApple OSS Distributions }
8804*0f4c859eSApple OSS Distributions
8805*0f4c859eSApple OSS Distributions void
queuePMRequest(IOPMRequest * request)8806*0f4c859eSApple OSS Distributions IOPMRequestQueue::queuePMRequest( IOPMRequest * request )
8807*0f4c859eSApple OSS Distributions {
8808*0f4c859eSApple OSS Distributions uint64_t now = mach_continuous_time();
8809*0f4c859eSApple OSS Distributions
8810*0f4c859eSApple OSS Distributions assert(request);
8811*0f4c859eSApple OSS Distributions request->setTimestamp(now);
8812*0f4c859eSApple OSS Distributions IOLockLock(fLock);
8813*0f4c859eSApple OSS Distributions queue_enter(&fQueue, request, typeof(request), fCommandChain);
8814*0f4c859eSApple OSS Distributions IOLockUnlock(fLock);
8815*0f4c859eSApple OSS Distributions if (workLoop) {
8816*0f4c859eSApple OSS Distributions signalWorkAvailable();
8817*0f4c859eSApple OSS Distributions }
8818*0f4c859eSApple OSS Distributions }
8819*0f4c859eSApple OSS Distributions
8820*0f4c859eSApple OSS Distributions void
queuePMRequestChain(IOPMRequest ** requests,IOItemCount count)8821*0f4c859eSApple OSS Distributions IOPMRequestQueue::queuePMRequestChain( IOPMRequest ** requests, IOItemCount count )
8822*0f4c859eSApple OSS Distributions {
8823*0f4c859eSApple OSS Distributions IOPMRequest * next;
8824*0f4c859eSApple OSS Distributions uint64_t now = mach_continuous_time();
8825*0f4c859eSApple OSS Distributions
8826*0f4c859eSApple OSS Distributions assert(requests && count);
8827*0f4c859eSApple OSS Distributions IOLockLock(fLock);
8828*0f4c859eSApple OSS Distributions while (count--) {
8829*0f4c859eSApple OSS Distributions next = *requests;
8830*0f4c859eSApple OSS Distributions next->setTimestamp(now);
8831*0f4c859eSApple OSS Distributions requests++;
8832*0f4c859eSApple OSS Distributions queue_enter(&fQueue, next, typeof(next), fCommandChain);
8833*0f4c859eSApple OSS Distributions }
8834*0f4c859eSApple OSS Distributions IOLockUnlock(fLock);
8835*0f4c859eSApple OSS Distributions if (workLoop) {
8836*0f4c859eSApple OSS Distributions signalWorkAvailable();
8837*0f4c859eSApple OSS Distributions }
8838*0f4c859eSApple OSS Distributions }
8839*0f4c859eSApple OSS Distributions
8840*0f4c859eSApple OSS Distributions bool
checkForWork(void)8841*0f4c859eSApple OSS Distributions IOPMRequestQueue::checkForWork( void )
8842*0f4c859eSApple OSS Distributions {
8843*0f4c859eSApple OSS Distributions Action dqAction = (Action) (void (*)(void))action;
8844*0f4c859eSApple OSS Distributions IOPMRequest * request;
8845*0f4c859eSApple OSS Distributions IOService * target;
8846*0f4c859eSApple OSS Distributions int dequeueCount = 0;
8847*0f4c859eSApple OSS Distributions bool more = false;
8848*0f4c859eSApple OSS Distributions
8849*0f4c859eSApple OSS Distributions IOLockLock( fLock );
8850*0f4c859eSApple OSS Distributions
8851*0f4c859eSApple OSS Distributions while (!queue_empty(&fQueue)) {
8852*0f4c859eSApple OSS Distributions if (dequeueCount++ >= kMaxDequeueCount) {
8853*0f4c859eSApple OSS Distributions // Allow other queues a chance to work
8854*0f4c859eSApple OSS Distributions more = true;
8855*0f4c859eSApple OSS Distributions break;
8856*0f4c859eSApple OSS Distributions }
8857*0f4c859eSApple OSS Distributions
8858*0f4c859eSApple OSS Distributions queue_remove_first(&fQueue, request, typeof(request), fCommandChain);
8859*0f4c859eSApple OSS Distributions IOLockUnlock(fLock);
8860*0f4c859eSApple OSS Distributions target = request->getTarget();
8861*0f4c859eSApple OSS Distributions assert(target);
8862*0f4c859eSApple OSS Distributions more |= (*dqAction)( target, request, this );
8863*0f4c859eSApple OSS Distributions IOLockLock( fLock );
8864*0f4c859eSApple OSS Distributions }
8865*0f4c859eSApple OSS Distributions
8866*0f4c859eSApple OSS Distributions IOLockUnlock( fLock );
8867*0f4c859eSApple OSS Distributions return more;
8868*0f4c859eSApple OSS Distributions }
8869*0f4c859eSApple OSS Distributions
8870*0f4c859eSApple OSS Distributions // MARK: -
8871*0f4c859eSApple OSS Distributions // MARK: IOPMWorkQueue
8872*0f4c859eSApple OSS Distributions
8873*0f4c859eSApple OSS Distributions //*********************************************************************************
8874*0f4c859eSApple OSS Distributions // IOPMWorkQueue Class
8875*0f4c859eSApple OSS Distributions //
8876*0f4c859eSApple OSS Distributions // Queue of IOServicePM objects, each with a queue of IOPMRequest sharing the
8877*0f4c859eSApple OSS Distributions // same target.
8878*0f4c859eSApple OSS Distributions //*********************************************************************************
8879*0f4c859eSApple OSS Distributions
8880*0f4c859eSApple OSS Distributions OSDefineMetaClassAndStructors( IOPMWorkQueue, IOEventSource );
8881*0f4c859eSApple OSS Distributions
8882*0f4c859eSApple OSS Distributions IOPMWorkQueue *
create(IOService * inOwner,Action invoke,Action retire)8883*0f4c859eSApple OSS Distributions IOPMWorkQueue::create( IOService * inOwner, Action invoke, Action retire )
8884*0f4c859eSApple OSS Distributions {
8885*0f4c859eSApple OSS Distributions IOPMWorkQueue * me = OSTypeAlloc(IOPMWorkQueue);
8886*0f4c859eSApple OSS Distributions if (me && !me->init(inOwner, invoke, retire)) {
8887*0f4c859eSApple OSS Distributions me->release();
8888*0f4c859eSApple OSS Distributions me = NULL;
8889*0f4c859eSApple OSS Distributions }
8890*0f4c859eSApple OSS Distributions return me;
8891*0f4c859eSApple OSS Distributions }
8892*0f4c859eSApple OSS Distributions
8893*0f4c859eSApple OSS Distributions bool
init(IOService * inOwner,Action invoke,Action retire)8894*0f4c859eSApple OSS Distributions IOPMWorkQueue::init( IOService * inOwner, Action invoke, Action retire )
8895*0f4c859eSApple OSS Distributions {
8896*0f4c859eSApple OSS Distributions if (!invoke || !retire ||
8897*0f4c859eSApple OSS Distributions !IOEventSource::init(inOwner, (IOEventSourceAction)NULL)) {
8898*0f4c859eSApple OSS Distributions return false;
8899*0f4c859eSApple OSS Distributions }
8900*0f4c859eSApple OSS Distributions
8901*0f4c859eSApple OSS Distributions queue_init(&fWorkQueue);
8902*0f4c859eSApple OSS Distributions
8903*0f4c859eSApple OSS Distributions fInvokeAction = invoke;
8904*0f4c859eSApple OSS Distributions fRetireAction = retire;
8905*0f4c859eSApple OSS Distributions fConsumerCount = fProducerCount = 0;
8906*0f4c859eSApple OSS Distributions
8907*0f4c859eSApple OSS Distributions return true;
8908*0f4c859eSApple OSS Distributions }
8909*0f4c859eSApple OSS Distributions
8910*0f4c859eSApple OSS Distributions bool
queuePMRequest(IOPMRequest * request,IOServicePM * pwrMgt)8911*0f4c859eSApple OSS Distributions IOPMWorkQueue::queuePMRequest( IOPMRequest * request, IOServicePM * pwrMgt )
8912*0f4c859eSApple OSS Distributions {
8913*0f4c859eSApple OSS Distributions queue_head_t * requestQueue;
8914*0f4c859eSApple OSS Distributions bool more = false;
8915*0f4c859eSApple OSS Distributions bool empty;
8916*0f4c859eSApple OSS Distributions
8917*0f4c859eSApple OSS Distributions assert( request );
8918*0f4c859eSApple OSS Distributions assert( pwrMgt );
8919*0f4c859eSApple OSS Distributions assert( onThread());
8920*0f4c859eSApple OSS Distributions assert( queue_next(&request->fCommandChain) ==
8921*0f4c859eSApple OSS Distributions queue_prev(&request->fCommandChain));
8922*0f4c859eSApple OSS Distributions
8923*0f4c859eSApple OSS Distributions gIOPMBusyRequestCount++;
8924*0f4c859eSApple OSS Distributions
8925*0f4c859eSApple OSS Distributions if (request->isQuiesceType()) {
8926*0f4c859eSApple OSS Distributions if ((request->getTarget() == gIOPMRootNode) && !fQuiesceStartTime) {
8927*0f4c859eSApple OSS Distributions // Attach new quiesce request to all quiesce blockers in the queue
8928*0f4c859eSApple OSS Distributions fQuiesceStartTime = mach_absolute_time();
8929*0f4c859eSApple OSS Distributions attachQuiesceRequest(request);
8930*0f4c859eSApple OSS Distributions fQuiesceRequest = request;
8931*0f4c859eSApple OSS Distributions }
8932*0f4c859eSApple OSS Distributions } else if (fQuiesceRequest && request->isQuiesceBlocker()) {
8933*0f4c859eSApple OSS Distributions // Attach the new quiesce blocker to the blocked quiesce request
8934*0f4c859eSApple OSS Distributions request->attachNextRequest(fQuiesceRequest);
8935*0f4c859eSApple OSS Distributions }
8936*0f4c859eSApple OSS Distributions
8937*0f4c859eSApple OSS Distributions // Add new request to the tail of the per-service request queue.
8938*0f4c859eSApple OSS Distributions // Then immediately check the request queue to minimize latency
8939*0f4c859eSApple OSS Distributions // if the queue was empty.
8940*0f4c859eSApple OSS Distributions
8941*0f4c859eSApple OSS Distributions requestQueue = &pwrMgt->RequestHead;
8942*0f4c859eSApple OSS Distributions empty = queue_empty(requestQueue);
8943*0f4c859eSApple OSS Distributions queue_enter(requestQueue, request, typeof(request), fCommandChain);
8944*0f4c859eSApple OSS Distributions if (empty) {
8945*0f4c859eSApple OSS Distributions more = checkRequestQueue(requestQueue, &empty);
8946*0f4c859eSApple OSS Distributions if (!empty) {
8947*0f4c859eSApple OSS Distributions // Request just added is blocked, add its target IOServicePM
8948*0f4c859eSApple OSS Distributions // to the work queue.
8949*0f4c859eSApple OSS Distributions assert( queue_next(&pwrMgt->WorkChain) ==
8950*0f4c859eSApple OSS Distributions queue_prev(&pwrMgt->WorkChain));
8951*0f4c859eSApple OSS Distributions
8952*0f4c859eSApple OSS Distributions queue_enter(&fWorkQueue, pwrMgt, typeof(pwrMgt), WorkChain);
8953*0f4c859eSApple OSS Distributions fQueueLength++;
8954*0f4c859eSApple OSS Distributions PM_LOG3("IOPMWorkQueue: [%u] added %s@%p to queue\n",
8955*0f4c859eSApple OSS Distributions fQueueLength, pwrMgt->Name, OBFUSCATE(pwrMgt));
8956*0f4c859eSApple OSS Distributions }
8957*0f4c859eSApple OSS Distributions }
8958*0f4c859eSApple OSS Distributions
8959*0f4c859eSApple OSS Distributions return more;
8960*0f4c859eSApple OSS Distributions }
8961*0f4c859eSApple OSS Distributions
8962*0f4c859eSApple OSS Distributions bool
checkRequestQueue(queue_head_t * requestQueue,bool * empty)8963*0f4c859eSApple OSS Distributions IOPMWorkQueue::checkRequestQueue( queue_head_t * requestQueue, bool * empty )
8964*0f4c859eSApple OSS Distributions {
8965*0f4c859eSApple OSS Distributions IOPMRequest * request;
8966*0f4c859eSApple OSS Distributions IOService * target;
8967*0f4c859eSApple OSS Distributions bool more = false;
8968*0f4c859eSApple OSS Distributions bool done = false;
8969*0f4c859eSApple OSS Distributions
8970*0f4c859eSApple OSS Distributions assert(!queue_empty(requestQueue));
8971*0f4c859eSApple OSS Distributions do {
8972*0f4c859eSApple OSS Distributions request = (typeof(request))queue_first(requestQueue);
8973*0f4c859eSApple OSS Distributions if (request->isWorkBlocked()) {
8974*0f4c859eSApple OSS Distributions break; // request dispatch blocked on attached request
8975*0f4c859eSApple OSS Distributions }
8976*0f4c859eSApple OSS Distributions target = request->getTarget();
8977*0f4c859eSApple OSS Distributions if (fInvokeAction) {
8978*0f4c859eSApple OSS Distributions done = (*fInvokeAction)( target, request, this );
8979*0f4c859eSApple OSS Distributions } else {
8980*0f4c859eSApple OSS Distributions PM_LOG("PM request 0x%x dropped\n", request->getType());
8981*0f4c859eSApple OSS Distributions done = true;
8982*0f4c859eSApple OSS Distributions }
8983*0f4c859eSApple OSS Distributions if (!done) {
8984*0f4c859eSApple OSS Distributions break; // PM state machine blocked
8985*0f4c859eSApple OSS Distributions }
8986*0f4c859eSApple OSS Distributions assert(gIOPMBusyRequestCount > 0);
8987*0f4c859eSApple OSS Distributions if (gIOPMBusyRequestCount) {
8988*0f4c859eSApple OSS Distributions gIOPMBusyRequestCount--;
8989*0f4c859eSApple OSS Distributions }
8990*0f4c859eSApple OSS Distributions
8991*0f4c859eSApple OSS Distributions if (request == fQuiesceRequest) {
8992*0f4c859eSApple OSS Distributions fQuiesceRequest = NULL;
8993*0f4c859eSApple OSS Distributions }
8994*0f4c859eSApple OSS Distributions
8995*0f4c859eSApple OSS Distributions queue_remove_first(requestQueue, request, typeof(request), fCommandChain);
8996*0f4c859eSApple OSS Distributions more |= (*fRetireAction)( target, request, this );
8997*0f4c859eSApple OSS Distributions done = queue_empty(requestQueue);
8998*0f4c859eSApple OSS Distributions } while (!done);
8999*0f4c859eSApple OSS Distributions
9000*0f4c859eSApple OSS Distributions *empty = done;
9001*0f4c859eSApple OSS Distributions
9002*0f4c859eSApple OSS Distributions if (more) {
9003*0f4c859eSApple OSS Distributions // Retired a request that may unblock a previously visited request
9004*0f4c859eSApple OSS Distributions // that is still waiting on the work queue. Must trigger another
9005*0f4c859eSApple OSS Distributions // queue check.
9006*0f4c859eSApple OSS Distributions fProducerCount++;
9007*0f4c859eSApple OSS Distributions }
9008*0f4c859eSApple OSS Distributions
9009*0f4c859eSApple OSS Distributions return more;
9010*0f4c859eSApple OSS Distributions }
9011*0f4c859eSApple OSS Distributions
9012*0f4c859eSApple OSS Distributions bool
checkForWork(void)9013*0f4c859eSApple OSS Distributions IOPMWorkQueue::checkForWork( void )
9014*0f4c859eSApple OSS Distributions {
9015*0f4c859eSApple OSS Distributions IOServicePM * entry;
9016*0f4c859eSApple OSS Distributions IOServicePM * next;
9017*0f4c859eSApple OSS Distributions bool more = false;
9018*0f4c859eSApple OSS Distributions bool empty;
9019*0f4c859eSApple OSS Distributions
9020*0f4c859eSApple OSS Distributions #if WORK_QUEUE_STATS
9021*0f4c859eSApple OSS Distributions fStatCheckForWork++;
9022*0f4c859eSApple OSS Distributions #endif
9023*0f4c859eSApple OSS Distributions
9024*0f4c859eSApple OSS Distributions // Iterate over all IOServicePM entries in the work queue,
9025*0f4c859eSApple OSS Distributions // and check each entry's request queue.
9026*0f4c859eSApple OSS Distributions
9027*0f4c859eSApple OSS Distributions while (fConsumerCount != fProducerCount) {
9028*0f4c859eSApple OSS Distributions PM_LOG3("IOPMWorkQueue: checkForWork %u %u\n",
9029*0f4c859eSApple OSS Distributions fProducerCount, fConsumerCount);
9030*0f4c859eSApple OSS Distributions
9031*0f4c859eSApple OSS Distributions fConsumerCount = fProducerCount;
9032*0f4c859eSApple OSS Distributions
9033*0f4c859eSApple OSS Distributions #if WORK_QUEUE_STATS
9034*0f4c859eSApple OSS Distributions if (queue_empty(&fWorkQueue)) {
9035*0f4c859eSApple OSS Distributions fStatQueueEmpty++;
9036*0f4c859eSApple OSS Distributions break;
9037*0f4c859eSApple OSS Distributions }
9038*0f4c859eSApple OSS Distributions fStatScanEntries++;
9039*0f4c859eSApple OSS Distributions uint32_t cachedWorkCount = gIOPMWorkInvokeCount;
9040*0f4c859eSApple OSS Distributions #endif
9041*0f4c859eSApple OSS Distributions
9042*0f4c859eSApple OSS Distributions __IGNORE_WCASTALIGN(entry = (typeof(entry))queue_first(&fWorkQueue));
9043*0f4c859eSApple OSS Distributions while (!queue_end(&fWorkQueue, (queue_entry_t) entry)) {
9044*0f4c859eSApple OSS Distributions more |= checkRequestQueue(&entry->RequestHead, &empty);
9045*0f4c859eSApple OSS Distributions
9046*0f4c859eSApple OSS Distributions // Get next entry, points to head if current entry is last.
9047*0f4c859eSApple OSS Distributions __IGNORE_WCASTALIGN(next = (typeof(next))queue_next(&entry->WorkChain));
9048*0f4c859eSApple OSS Distributions
9049*0f4c859eSApple OSS Distributions // if request queue is empty, remove IOServicePM from work queue.
9050*0f4c859eSApple OSS Distributions if (empty) {
9051*0f4c859eSApple OSS Distributions assert(fQueueLength);
9052*0f4c859eSApple OSS Distributions if (fQueueLength) {
9053*0f4c859eSApple OSS Distributions fQueueLength--;
9054*0f4c859eSApple OSS Distributions }
9055*0f4c859eSApple OSS Distributions PM_LOG3("IOPMWorkQueue: [%u] removed %s@%p from queue\n",
9056*0f4c859eSApple OSS Distributions fQueueLength, entry->Name, OBFUSCATE(entry));
9057*0f4c859eSApple OSS Distributions queue_remove(&fWorkQueue, entry, typeof(entry), WorkChain);
9058*0f4c859eSApple OSS Distributions }
9059*0f4c859eSApple OSS Distributions entry = next;
9060*0f4c859eSApple OSS Distributions }
9061*0f4c859eSApple OSS Distributions
9062*0f4c859eSApple OSS Distributions #if WORK_QUEUE_STATS
9063*0f4c859eSApple OSS Distributions if (cachedWorkCount == gIOPMWorkInvokeCount) {
9064*0f4c859eSApple OSS Distributions fStatNoWorkDone++;
9065*0f4c859eSApple OSS Distributions }
9066*0f4c859eSApple OSS Distributions #endif
9067*0f4c859eSApple OSS Distributions }
9068*0f4c859eSApple OSS Distributions
9069*0f4c859eSApple OSS Distributions return more;
9070*0f4c859eSApple OSS Distributions }
9071*0f4c859eSApple OSS Distributions
9072*0f4c859eSApple OSS Distributions void
signalWorkAvailable(void)9073*0f4c859eSApple OSS Distributions IOPMWorkQueue::signalWorkAvailable( void )
9074*0f4c859eSApple OSS Distributions {
9075*0f4c859eSApple OSS Distributions fProducerCount++;
9076*0f4c859eSApple OSS Distributions IOEventSource::signalWorkAvailable();
9077*0f4c859eSApple OSS Distributions }
9078*0f4c859eSApple OSS Distributions
9079*0f4c859eSApple OSS Distributions void
incrementProducerCount(void)9080*0f4c859eSApple OSS Distributions IOPMWorkQueue::incrementProducerCount( void )
9081*0f4c859eSApple OSS Distributions {
9082*0f4c859eSApple OSS Distributions fProducerCount++;
9083*0f4c859eSApple OSS Distributions }
9084*0f4c859eSApple OSS Distributions
9085*0f4c859eSApple OSS Distributions void
attachQuiesceRequest(IOPMRequest * quiesceRequest)9086*0f4c859eSApple OSS Distributions IOPMWorkQueue::attachQuiesceRequest( IOPMRequest * quiesceRequest )
9087*0f4c859eSApple OSS Distributions {
9088*0f4c859eSApple OSS Distributions IOServicePM * entry;
9089*0f4c859eSApple OSS Distributions IOPMRequest * request;
9090*0f4c859eSApple OSS Distributions
9091*0f4c859eSApple OSS Distributions if (queue_empty(&fWorkQueue)) {
9092*0f4c859eSApple OSS Distributions return;
9093*0f4c859eSApple OSS Distributions }
9094*0f4c859eSApple OSS Distributions
9095*0f4c859eSApple OSS Distributions queue_iterate(&fWorkQueue, entry, typeof(entry), WorkChain)
9096*0f4c859eSApple OSS Distributions {
9097*0f4c859eSApple OSS Distributions queue_iterate(&entry->RequestHead, request, typeof(request), fCommandChain)
9098*0f4c859eSApple OSS Distributions {
9099*0f4c859eSApple OSS Distributions // Attach the quiesce request to any request in the queue that
9100*0f4c859eSApple OSS Distributions // is not linked to a next request. These requests will block
9101*0f4c859eSApple OSS Distributions // the quiesce request.
9102*0f4c859eSApple OSS Distributions
9103*0f4c859eSApple OSS Distributions if (request->isQuiesceBlocker()) {
9104*0f4c859eSApple OSS Distributions request->attachNextRequest(quiesceRequest);
9105*0f4c859eSApple OSS Distributions }
9106*0f4c859eSApple OSS Distributions }
9107*0f4c859eSApple OSS Distributions }
9108*0f4c859eSApple OSS Distributions }
9109*0f4c859eSApple OSS Distributions
9110*0f4c859eSApple OSS Distributions void
finishQuiesceRequest(IOPMRequest * quiesceRequest)9111*0f4c859eSApple OSS Distributions IOPMWorkQueue::finishQuiesceRequest( IOPMRequest * quiesceRequest )
9112*0f4c859eSApple OSS Distributions {
9113*0f4c859eSApple OSS Distributions if (fQuiesceRequest && (quiesceRequest == fQuiesceRequest) &&
9114*0f4c859eSApple OSS Distributions (fQuiesceStartTime != 0)) {
9115*0f4c859eSApple OSS Distributions fInvokeAction = NULL;
9116*0f4c859eSApple OSS Distributions fQuiesceFinishTime = mach_absolute_time();
9117*0f4c859eSApple OSS Distributions }
9118*0f4c859eSApple OSS Distributions }
9119*0f4c859eSApple OSS Distributions
9120*0f4c859eSApple OSS Distributions // MARK: -
9121*0f4c859eSApple OSS Distributions // MARK: IOPMCompletionQueue
9122*0f4c859eSApple OSS Distributions
9123*0f4c859eSApple OSS Distributions //*********************************************************************************
9124*0f4c859eSApple OSS Distributions // IOPMCompletionQueue Class
9125*0f4c859eSApple OSS Distributions //*********************************************************************************
9126*0f4c859eSApple OSS Distributions
9127*0f4c859eSApple OSS Distributions OSDefineMetaClassAndStructors( IOPMCompletionQueue, IOEventSource );
9128*0f4c859eSApple OSS Distributions
9129*0f4c859eSApple OSS Distributions #pragma clang diagnostic push
9130*0f4c859eSApple OSS Distributions #pragma clang diagnostic ignored "-Wcast-function-type"
9131*0f4c859eSApple OSS Distributions
9132*0f4c859eSApple OSS Distributions IOPMCompletionQueue *
create(IOService * inOwner,Action inAction)9133*0f4c859eSApple OSS Distributions IOPMCompletionQueue::create( IOService * inOwner, Action inAction )
9134*0f4c859eSApple OSS Distributions {
9135*0f4c859eSApple OSS Distributions IOPMCompletionQueue * me = OSTypeAlloc(IOPMCompletionQueue);
9136*0f4c859eSApple OSS Distributions if (me && !me->init(inOwner, inAction)) {
9137*0f4c859eSApple OSS Distributions me->release();
9138*0f4c859eSApple OSS Distributions me = NULL;
9139*0f4c859eSApple OSS Distributions }
9140*0f4c859eSApple OSS Distributions return me;
9141*0f4c859eSApple OSS Distributions }
9142*0f4c859eSApple OSS Distributions
9143*0f4c859eSApple OSS Distributions bool
init(IOService * inOwner,Action inAction)9144*0f4c859eSApple OSS Distributions IOPMCompletionQueue::init( IOService * inOwner, Action inAction )
9145*0f4c859eSApple OSS Distributions {
9146*0f4c859eSApple OSS Distributions if (!inAction || !IOEventSource::init(inOwner, (IOEventSourceAction)inAction)) {
9147*0f4c859eSApple OSS Distributions return false;
9148*0f4c859eSApple OSS Distributions }
9149*0f4c859eSApple OSS Distributions
9150*0f4c859eSApple OSS Distributions queue_init(&fQueue);
9151*0f4c859eSApple OSS Distributions return true;
9152*0f4c859eSApple OSS Distributions }
9153*0f4c859eSApple OSS Distributions
9154*0f4c859eSApple OSS Distributions
9155*0f4c859eSApple OSS Distributions bool
queuePMRequest(IOPMRequest * request)9156*0f4c859eSApple OSS Distributions IOPMCompletionQueue::queuePMRequest( IOPMRequest * request )
9157*0f4c859eSApple OSS Distributions {
9158*0f4c859eSApple OSS Distributions bool more;
9159*0f4c859eSApple OSS Distributions
9160*0f4c859eSApple OSS Distributions assert(request);
9161*0f4c859eSApple OSS Distributions // unblock dependent request
9162*0f4c859eSApple OSS Distributions more = request->detachNextRequest();
9163*0f4c859eSApple OSS Distributions queue_enter(&fQueue, request, typeof(request), fCommandChain);
9164*0f4c859eSApple OSS Distributions return more;
9165*0f4c859eSApple OSS Distributions }
9166*0f4c859eSApple OSS Distributions
9167*0f4c859eSApple OSS Distributions bool
checkForWork(void)9168*0f4c859eSApple OSS Distributions IOPMCompletionQueue::checkForWork( void )
9169*0f4c859eSApple OSS Distributions {
9170*0f4c859eSApple OSS Distributions Action dqAction = (Action) action;
9171*0f4c859eSApple OSS Distributions IOPMRequest * request;
9172*0f4c859eSApple OSS Distributions IOPMRequest * next;
9173*0f4c859eSApple OSS Distributions IOService * target;
9174*0f4c859eSApple OSS Distributions bool more = false;
9175*0f4c859eSApple OSS Distributions
9176*0f4c859eSApple OSS Distributions request = (typeof(request))queue_first(&fQueue);
9177*0f4c859eSApple OSS Distributions while (!queue_end(&fQueue, (queue_entry_t) request)) {
9178*0f4c859eSApple OSS Distributions next = (typeof(next))queue_next(&request->fCommandChain);
9179*0f4c859eSApple OSS Distributions if (!request->isFreeBlocked()) {
9180*0f4c859eSApple OSS Distributions queue_remove(&fQueue, request, typeof(request), fCommandChain);
9181*0f4c859eSApple OSS Distributions target = request->getTarget();
9182*0f4c859eSApple OSS Distributions assert(target);
9183*0f4c859eSApple OSS Distributions more |= (*dqAction)( target, request, this );
9184*0f4c859eSApple OSS Distributions }
9185*0f4c859eSApple OSS Distributions request = next;
9186*0f4c859eSApple OSS Distributions }
9187*0f4c859eSApple OSS Distributions
9188*0f4c859eSApple OSS Distributions return more;
9189*0f4c859eSApple OSS Distributions }
9190*0f4c859eSApple OSS Distributions
9191*0f4c859eSApple OSS Distributions #pragma clang diagnostic pop
9192*0f4c859eSApple OSS Distributions
9193*0f4c859eSApple OSS Distributions // MARK: -
9194*0f4c859eSApple OSS Distributions // MARK: IOServicePM
9195*0f4c859eSApple OSS Distributions
OSDefineMetaClassAndStructors(IOServicePM,OSObject)9196*0f4c859eSApple OSS Distributions OSDefineMetaClassAndStructors(IOServicePM, OSObject)
9197*0f4c859eSApple OSS Distributions
9198*0f4c859eSApple OSS Distributions //*********************************************************************************
9199*0f4c859eSApple OSS Distributions // serialize
9200*0f4c859eSApple OSS Distributions //
9201*0f4c859eSApple OSS Distributions // Serialize IOServicePM for debugging.
9202*0f4c859eSApple OSS Distributions //*********************************************************************************
9203*0f4c859eSApple OSS Distributions
9204*0f4c859eSApple OSS Distributions static void
9205*0f4c859eSApple OSS Distributions setPMProperty( OSDictionary * dict, const char * key, uint64_t value )
9206*0f4c859eSApple OSS Distributions {
9207*0f4c859eSApple OSS Distributions OSNumber * num = OSNumber::withNumber(value, sizeof(value) * 8);
9208*0f4c859eSApple OSS Distributions if (num) {
9209*0f4c859eSApple OSS Distributions dict->setObject(key, num);
9210*0f4c859eSApple OSS Distributions num->release();
9211*0f4c859eSApple OSS Distributions }
9212*0f4c859eSApple OSS Distributions }
9213*0f4c859eSApple OSS Distributions
9214*0f4c859eSApple OSS Distributions IOReturn
gatedSerialize(OSSerialize * s) const9215*0f4c859eSApple OSS Distributions IOServicePM::gatedSerialize( OSSerialize * s ) const
9216*0f4c859eSApple OSS Distributions {
9217*0f4c859eSApple OSS Distributions OSDictionary * dict;
9218*0f4c859eSApple OSS Distributions bool ok = false;
9219*0f4c859eSApple OSS Distributions int powerClamp = -1;
9220*0f4c859eSApple OSS Distributions int dictSize = 6;
9221*0f4c859eSApple OSS Distributions
9222*0f4c859eSApple OSS Distributions if (IdleTimerPeriod) {
9223*0f4c859eSApple OSS Distributions dictSize += 4;
9224*0f4c859eSApple OSS Distributions }
9225*0f4c859eSApple OSS Distributions
9226*0f4c859eSApple OSS Distributions if (PMActions.state & kPMActionsStatePowerClamped) {
9227*0f4c859eSApple OSS Distributions dictSize += 1;
9228*0f4c859eSApple OSS Distributions powerClamp = 0;
9229*0f4c859eSApple OSS Distributions if (PMActions.flags &
9230*0f4c859eSApple OSS Distributions (kPMActionsFlagIsDisplayWrangler | kPMActionsFlagIsGraphicsDriver)) {
9231*0f4c859eSApple OSS Distributions powerClamp++;
9232*0f4c859eSApple OSS Distributions }
9233*0f4c859eSApple OSS Distributions }
9234*0f4c859eSApple OSS Distributions
9235*0f4c859eSApple OSS Distributions #if WORK_QUEUE_STATS
9236*0f4c859eSApple OSS Distributions if (gIOPMRootNode == ControllingDriver) {
9237*0f4c859eSApple OSS Distributions dictSize += 4;
9238*0f4c859eSApple OSS Distributions }
9239*0f4c859eSApple OSS Distributions #endif
9240*0f4c859eSApple OSS Distributions
9241*0f4c859eSApple OSS Distributions if (PowerClients) {
9242*0f4c859eSApple OSS Distributions dict = OSDictionary::withDictionary(
9243*0f4c859eSApple OSS Distributions PowerClients, PowerClients->getCount() + dictSize);
9244*0f4c859eSApple OSS Distributions } else {
9245*0f4c859eSApple OSS Distributions dict = OSDictionary::withCapacity(dictSize);
9246*0f4c859eSApple OSS Distributions }
9247*0f4c859eSApple OSS Distributions
9248*0f4c859eSApple OSS Distributions if (dict) {
9249*0f4c859eSApple OSS Distributions setPMProperty(dict, "CurrentPowerState", CurrentPowerState);
9250*0f4c859eSApple OSS Distributions setPMProperty(dict, "CapabilityFlags", CurrentCapabilityFlags);
9251*0f4c859eSApple OSS Distributions if (NumberOfPowerStates) {
9252*0f4c859eSApple OSS Distributions setPMProperty(dict, "MaxPowerState", NumberOfPowerStates - 1);
9253*0f4c859eSApple OSS Distributions }
9254*0f4c859eSApple OSS Distributions if (DesiredPowerState != CurrentPowerState) {
9255*0f4c859eSApple OSS Distributions setPMProperty(dict, "DesiredPowerState", DesiredPowerState);
9256*0f4c859eSApple OSS Distributions }
9257*0f4c859eSApple OSS Distributions if (kIOPM_Finished != MachineState) {
9258*0f4c859eSApple OSS Distributions setPMProperty(dict, "MachineState", MachineState);
9259*0f4c859eSApple OSS Distributions }
9260*0f4c859eSApple OSS Distributions if (DeviceOverrideEnabled) {
9261*0f4c859eSApple OSS Distributions dict->setObject("PowerOverrideOn", kOSBooleanTrue);
9262*0f4c859eSApple OSS Distributions }
9263*0f4c859eSApple OSS Distributions if (powerClamp >= 0) {
9264*0f4c859eSApple OSS Distributions setPMProperty(dict, "PowerClamp", powerClamp);
9265*0f4c859eSApple OSS Distributions }
9266*0f4c859eSApple OSS Distributions
9267*0f4c859eSApple OSS Distributions if (IdleTimerPeriod) {
9268*0f4c859eSApple OSS Distributions AbsoluteTime now;
9269*0f4c859eSApple OSS Distributions AbsoluteTime delta;
9270*0f4c859eSApple OSS Distributions uint64_t nsecs;
9271*0f4c859eSApple OSS Distributions
9272*0f4c859eSApple OSS Distributions clock_get_uptime(&now);
9273*0f4c859eSApple OSS Distributions
9274*0f4c859eSApple OSS Distributions // The idle timer period in milliseconds
9275*0f4c859eSApple OSS Distributions setPMProperty(dict, "IdleTimerPeriod", NextIdleTimerPeriod * 1000ULL);
9276*0f4c859eSApple OSS Distributions
9277*0f4c859eSApple OSS Distributions // Number of tickles since the last idle timer expiration
9278*0f4c859eSApple OSS Distributions setPMProperty(dict, "ActivityTickles", ActivityTickleCount);
9279*0f4c859eSApple OSS Distributions
9280*0f4c859eSApple OSS Distributions if (AbsoluteTime_to_scalar(&DeviceActiveTimestamp)) {
9281*0f4c859eSApple OSS Distributions // Milliseconds since the last activity tickle
9282*0f4c859eSApple OSS Distributions delta = now;
9283*0f4c859eSApple OSS Distributions SUB_ABSOLUTETIME(&delta, &DeviceActiveTimestamp);
9284*0f4c859eSApple OSS Distributions absolutetime_to_nanoseconds(delta, &nsecs);
9285*0f4c859eSApple OSS Distributions setPMProperty(dict, "TimeSinceLastTickle", NS_TO_MS(nsecs));
9286*0f4c859eSApple OSS Distributions }
9287*0f4c859eSApple OSS Distributions
9288*0f4c859eSApple OSS Distributions if (!IdleTimerStopped && AbsoluteTime_to_scalar(&IdleTimerStartTime)) {
9289*0f4c859eSApple OSS Distributions // Idle timer elapsed time in milliseconds
9290*0f4c859eSApple OSS Distributions delta = now;
9291*0f4c859eSApple OSS Distributions SUB_ABSOLUTETIME(&delta, &IdleTimerStartTime);
9292*0f4c859eSApple OSS Distributions absolutetime_to_nanoseconds(delta, &nsecs);
9293*0f4c859eSApple OSS Distributions setPMProperty(dict, "IdleTimerElapsedTime", NS_TO_MS(nsecs));
9294*0f4c859eSApple OSS Distributions }
9295*0f4c859eSApple OSS Distributions }
9296*0f4c859eSApple OSS Distributions
9297*0f4c859eSApple OSS Distributions #if WORK_QUEUE_STATS
9298*0f4c859eSApple OSS Distributions if (gIOPMRootNode == Owner) {
9299*0f4c859eSApple OSS Distributions setPMProperty(dict, "WQ-CheckForWork",
9300*0f4c859eSApple OSS Distributions gIOPMWorkQueue->fStatCheckForWork);
9301*0f4c859eSApple OSS Distributions setPMProperty(dict, "WQ-ScanEntries",
9302*0f4c859eSApple OSS Distributions gIOPMWorkQueue->fStatScanEntries);
9303*0f4c859eSApple OSS Distributions setPMProperty(dict, "WQ-QueueEmpty",
9304*0f4c859eSApple OSS Distributions gIOPMWorkQueue->fStatQueueEmpty);
9305*0f4c859eSApple OSS Distributions setPMProperty(dict, "WQ-NoWorkDone",
9306*0f4c859eSApple OSS Distributions gIOPMWorkQueue->fStatNoWorkDone);
9307*0f4c859eSApple OSS Distributions }
9308*0f4c859eSApple OSS Distributions #endif
9309*0f4c859eSApple OSS Distributions
9310*0f4c859eSApple OSS Distributions if (HasAdvisoryDesire && !gIOPMAdvisoryTickleEnabled) {
9311*0f4c859eSApple OSS Distributions // Don't report advisory tickle when it has no influence
9312*0f4c859eSApple OSS Distributions dict->removeObject(gIOPMPowerClientAdvisoryTickle);
9313*0f4c859eSApple OSS Distributions }
9314*0f4c859eSApple OSS Distributions
9315*0f4c859eSApple OSS Distributions ok = dict->serialize(s);
9316*0f4c859eSApple OSS Distributions dict->release();
9317*0f4c859eSApple OSS Distributions }
9318*0f4c859eSApple OSS Distributions
9319*0f4c859eSApple OSS Distributions return ok ? kIOReturnSuccess : kIOReturnNoMemory;
9320*0f4c859eSApple OSS Distributions }
9321*0f4c859eSApple OSS Distributions
9322*0f4c859eSApple OSS Distributions bool
serialize(OSSerialize * s) const9323*0f4c859eSApple OSS Distributions IOServicePM::serialize( OSSerialize * s ) const
9324*0f4c859eSApple OSS Distributions {
9325*0f4c859eSApple OSS Distributions IOReturn ret = kIOReturnNotReady;
9326*0f4c859eSApple OSS Distributions
9327*0f4c859eSApple OSS Distributions if (gIOPMWatchDogThread == current_thread()) {
9328*0f4c859eSApple OSS Distributions // Calling without lock as this data is collected for debug purpose, before reboot.
9329*0f4c859eSApple OSS Distributions // The workloop is probably already hung in state machine.
9330*0f4c859eSApple OSS Distributions ret = gatedSerialize(s);
9331*0f4c859eSApple OSS Distributions } else if (gIOPMWorkLoop) {
9332*0f4c859eSApple OSS Distributions ret = gIOPMWorkLoop->runAction(
9333*0f4c859eSApple OSS Distributions OSMemberFunctionCast(IOWorkLoop::Action, this, &IOServicePM::gatedSerialize),
9334*0f4c859eSApple OSS Distributions (OSObject *) this, (void *) s);
9335*0f4c859eSApple OSS Distributions }
9336*0f4c859eSApple OSS Distributions
9337*0f4c859eSApple OSS Distributions return kIOReturnSuccess == ret;
9338*0f4c859eSApple OSS Distributions }
9339*0f4c859eSApple OSS Distributions
9340*0f4c859eSApple OSS Distributions void
pmPrint(uint32_t event,uintptr_t param1,uintptr_t param2) const9341*0f4c859eSApple OSS Distributions IOServicePM::pmPrint(
9342*0f4c859eSApple OSS Distributions uint32_t event,
9343*0f4c859eSApple OSS Distributions uintptr_t param1,
9344*0f4c859eSApple OSS Distributions uintptr_t param2 ) const
9345*0f4c859eSApple OSS Distributions {
9346*0f4c859eSApple OSS Distributions gPlatform->PMLog(Name, event, param1, param2);
9347*0f4c859eSApple OSS Distributions }
9348*0f4c859eSApple OSS Distributions
9349*0f4c859eSApple OSS Distributions void
pmTrace(uint32_t event,uint32_t eventFunc,uintptr_t param1,uintptr_t param2) const9350*0f4c859eSApple OSS Distributions IOServicePM::pmTrace(
9351*0f4c859eSApple OSS Distributions uint32_t event,
9352*0f4c859eSApple OSS Distributions uint32_t eventFunc,
9353*0f4c859eSApple OSS Distributions uintptr_t param1,
9354*0f4c859eSApple OSS Distributions uintptr_t param2 ) const
9355*0f4c859eSApple OSS Distributions {
9356*0f4c859eSApple OSS Distributions uintptr_t nameAsArg = 0;
9357*0f4c859eSApple OSS Distributions
9358*0f4c859eSApple OSS Distributions assert(event < KDBG_CODE_MAX);
9359*0f4c859eSApple OSS Distributions assert((eventFunc & ~KDBG_FUNC_MASK) == 0);
9360*0f4c859eSApple OSS Distributions
9361*0f4c859eSApple OSS Distributions // Copy the first characters of the name into an uintptr_t.
9362*0f4c859eSApple OSS Distributions // NULL termination is not required.
9363*0f4c859eSApple OSS Distributions strncpy((char*)&nameAsArg, Name, sizeof(nameAsArg));
9364*0f4c859eSApple OSS Distributions
9365*0f4c859eSApple OSS Distributions #if defined(XNU_TARGET_OS_OSX)
9366*0f4c859eSApple OSS Distributions KERNEL_DEBUG_CONSTANT_IST(KDEBUG_TRACE, IODBG_POWER(event) | eventFunc, nameAsArg,
9367*0f4c859eSApple OSS Distributions (uintptr_t)Owner->getRegistryEntryID(), (uintptr_t)(OBFUSCATE(param1)),
9368*0f4c859eSApple OSS Distributions (uintptr_t)(OBFUSCATE(param2)), 0);
9369*0f4c859eSApple OSS Distributions #else
9370*0f4c859eSApple OSS Distributions IOTimeStampConstant(IODBG_POWER(event) | eventFunc, nameAsArg, (uintptr_t)Owner->getRegistryEntryID(), (uintptr_t)(OBFUSCATE(param1)), (uintptr_t)(OBFUSCATE(param2)));
9371*0f4c859eSApple OSS Distributions #endif
9372*0f4c859eSApple OSS Distributions }
9373