1*c54f35caSApple OSS Distributions /*
2*c54f35caSApple OSS Distributions * Copyright (c) 1998-2020 Apple Inc. All rights reserved.
3*c54f35caSApple OSS Distributions *
4*c54f35caSApple OSS Distributions * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5*c54f35caSApple OSS Distributions *
6*c54f35caSApple OSS Distributions * This file contains Original Code and/or Modifications of Original Code
7*c54f35caSApple OSS Distributions * as defined in and that are subject to the Apple Public Source License
8*c54f35caSApple OSS Distributions * Version 2.0 (the 'License'). You may not use this file except in
9*c54f35caSApple OSS Distributions * compliance with the License. The rights granted to you under the License
10*c54f35caSApple OSS Distributions * may not be used to create, or enable the creation or redistribution of,
11*c54f35caSApple OSS Distributions * unlawful or unlicensed copies of an Apple operating system, or to
12*c54f35caSApple OSS Distributions * circumvent, violate, or enable the circumvention or violation of, any
13*c54f35caSApple OSS Distributions * terms of an Apple operating system software license agreement.
14*c54f35caSApple OSS Distributions *
15*c54f35caSApple OSS Distributions * Please obtain a copy of the License at
16*c54f35caSApple OSS Distributions * http://www.opensource.apple.com/apsl/ and read it before using this file.
17*c54f35caSApple OSS Distributions *
18*c54f35caSApple OSS Distributions * The Original Code and all software distributed under the License are
19*c54f35caSApple OSS Distributions * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20*c54f35caSApple OSS Distributions * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21*c54f35caSApple OSS Distributions * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22*c54f35caSApple OSS Distributions * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23*c54f35caSApple OSS Distributions * Please see the License for the specific language governing rights and
24*c54f35caSApple OSS Distributions * limitations under the License.
25*c54f35caSApple OSS Distributions *
26*c54f35caSApple OSS Distributions * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27*c54f35caSApple OSS Distributions */
28*c54f35caSApple OSS Distributions
29*c54f35caSApple OSS Distributions #include <IOKit/assert.h>
30*c54f35caSApple OSS Distributions #include <IOKit/IOKitDebug.h>
31*c54f35caSApple OSS Distributions #include <IOKit/IOLib.h>
32*c54f35caSApple OSS Distributions #include <IOKit/IOMessage.h>
33*c54f35caSApple OSS Distributions #include <IOKit/IOPlatformExpert.h>
34*c54f35caSApple OSS Distributions #include <IOKit/IOService.h>
35*c54f35caSApple OSS Distributions #include <IOKit/IOUserServer.h>
36*c54f35caSApple OSS Distributions #include <IOKit/IOEventSource.h>
37*c54f35caSApple OSS Distributions #include <IOKit/IOWorkLoop.h>
38*c54f35caSApple OSS Distributions #include <IOKit/IOCommand.h>
39*c54f35caSApple OSS Distributions #include <IOKit/IOTimeStamp.h>
40*c54f35caSApple OSS Distributions #include <IOKit/IOReportMacros.h>
41*c54f35caSApple OSS Distributions #include <IOKit/IODeviceTreeSupport.h>
42*c54f35caSApple OSS Distributions
43*c54f35caSApple OSS Distributions #include <IOKit/pwr_mgt/IOPMlog.h>
44*c54f35caSApple OSS Distributions #include <IOKit/pwr_mgt/IOPMinformee.h>
45*c54f35caSApple OSS Distributions #include <IOKit/pwr_mgt/IOPMinformeeList.h>
46*c54f35caSApple OSS Distributions #include <IOKit/pwr_mgt/IOPowerConnection.h>
47*c54f35caSApple OSS Distributions #include <IOKit/pwr_mgt/RootDomain.h>
48*c54f35caSApple OSS Distributions #include <IOKit/pwr_mgt/IOPMPrivate.h>
49*c54f35caSApple OSS Distributions
50*c54f35caSApple OSS Distributions #include <sys/proc.h>
51*c54f35caSApple OSS Distributions #include <sys/proc_internal.h>
52*c54f35caSApple OSS Distributions #include <sys/sysctl.h>
53*c54f35caSApple OSS Distributions #include <libkern/OSDebug.h>
54*c54f35caSApple OSS Distributions #include <kern/thread.h>
55*c54f35caSApple OSS Distributions
56*c54f35caSApple OSS Distributions // Required for notification instrumentation
57*c54f35caSApple OSS Distributions #include "IOServicePrivate.h"
58*c54f35caSApple OSS Distributions #include "IOServicePMPrivate.h"
59*c54f35caSApple OSS Distributions #include "IOKitKernelInternal.h"
60*c54f35caSApple OSS Distributions
61*c54f35caSApple OSS Distributions #if USE_SETTLE_TIMER
62*c54f35caSApple OSS Distributions static void settle_timer_expired(thread_call_param_t, thread_call_param_t);
63*c54f35caSApple OSS Distributions #endif
64*c54f35caSApple OSS Distributions static void idle_timer_expired(thread_call_param_t, thread_call_param_t);
65*c54f35caSApple OSS Distributions static void tellKernelClientApplier(OSObject * object, void * arg);
66*c54f35caSApple OSS Distributions static void tellAppClientApplier(OSObject * object, void * arg);
67*c54f35caSApple OSS Distributions static const char * getNotificationPhaseString(uint32_t phase);
68*c54f35caSApple OSS Distributions
69*c54f35caSApple OSS Distributions static uint64_t
computeTimeDeltaNS(const AbsoluteTime * start)70*c54f35caSApple OSS Distributions computeTimeDeltaNS( const AbsoluteTime * start )
71*c54f35caSApple OSS Distributions {
72*c54f35caSApple OSS Distributions AbsoluteTime now;
73*c54f35caSApple OSS Distributions uint64_t nsec;
74*c54f35caSApple OSS Distributions
75*c54f35caSApple OSS Distributions clock_get_uptime(&now);
76*c54f35caSApple OSS Distributions SUB_ABSOLUTETIME(&now, start);
77*c54f35caSApple OSS Distributions absolutetime_to_nanoseconds(now, &nsec);
78*c54f35caSApple OSS Distributions return nsec;
79*c54f35caSApple OSS Distributions }
80*c54f35caSApple OSS Distributions
81*c54f35caSApple OSS Distributions #if PM_VARS_SUPPORT
82*c54f35caSApple OSS Distributions OSDefineMetaClassAndStructors(IOPMprot, OSObject)
83*c54f35caSApple OSS Distributions #endif
84*c54f35caSApple OSS Distributions
85*c54f35caSApple OSS Distributions //******************************************************************************
86*c54f35caSApple OSS Distributions // Globals
87*c54f35caSApple OSS Distributions //******************************************************************************
88*c54f35caSApple OSS Distributions
89*c54f35caSApple OSS Distributions static bool gIOPMInitialized = false;
90*c54f35caSApple OSS Distributions static uint32_t gIOPMBusyRequestCount = 0;
91*c54f35caSApple OSS Distributions static uint32_t gIOPMWorkInvokeCount = 0;
92*c54f35caSApple OSS Distributions static uint32_t gIOPMTickleGeneration = 0;
93*c54f35caSApple OSS Distributions static IOWorkLoop * gIOPMWorkLoop = NULL;
94*c54f35caSApple OSS Distributions static IOPMRequestQueue * gIOPMRequestQueue = NULL;
95*c54f35caSApple OSS Distributions static IOPMRequestQueue * gIOPMReplyQueue = NULL;
96*c54f35caSApple OSS Distributions static IOPMWorkQueue * gIOPMWorkQueue = NULL;
97*c54f35caSApple OSS Distributions static IOPMCompletionQueue * gIOPMCompletionQueue = NULL;
98*c54f35caSApple OSS Distributions static IOPMRequest * gIOPMRequest = NULL;
99*c54f35caSApple OSS Distributions static IOService * gIOPMRootNode = NULL;
100*c54f35caSApple OSS Distributions static IOPlatformExpert * gPlatform = NULL;
101*c54f35caSApple OSS Distributions static IOLock * gIOPMInitLock = NULL;
102*c54f35caSApple OSS Distributions
103*c54f35caSApple OSS Distributions // log setPowerStates and powerStateChange longer than (ns):
104*c54f35caSApple OSS Distributions static uint64_t gIOPMSetPowerStateLogNS =
105*c54f35caSApple OSS Distributions #if defined(__i386__) || defined(__x86_64__)
106*c54f35caSApple OSS Distributions (300ULL * 1000ULL * 1000ULL)
107*c54f35caSApple OSS Distributions #else
108*c54f35caSApple OSS Distributions (50ULL * 1000ULL * 1000ULL)
109*c54f35caSApple OSS Distributions #endif
110*c54f35caSApple OSS Distributions ;
111*c54f35caSApple OSS Distributions
112*c54f35caSApple OSS Distributions const OSSymbol * gIOPMPowerClientDevice = NULL;
113*c54f35caSApple OSS Distributions const OSSymbol * gIOPMPowerClientDriver = NULL;
114*c54f35caSApple OSS Distributions const OSSymbol * gIOPMPowerClientChildProxy = NULL;
115*c54f35caSApple OSS Distributions const OSSymbol * gIOPMPowerClientChildren = NULL;
116*c54f35caSApple OSS Distributions const OSSymbol * gIOPMPowerClientRootDomain = NULL;
117*c54f35caSApple OSS Distributions
118*c54f35caSApple OSS Distributions static const OSSymbol * gIOPMPowerClientAdvisoryTickle = NULL;
119*c54f35caSApple OSS Distributions static bool gIOPMAdvisoryTickleEnabled = true;
120*c54f35caSApple OSS Distributions static thread_t gIOPMWatchDogThread = NULL;
121*c54f35caSApple OSS Distributions TUNABLE_WRITEABLE(uint32_t, gSleepAckTimeout, "pmtimeout", 0);
122*c54f35caSApple OSS Distributions
123*c54f35caSApple OSS Distributions /*
124*c54f35caSApple OSS Distributions * While waiting for a driver callout to complete, we log any instances
125*c54f35caSApple OSS Distributions * that have taken longer than the below period (in milliseconds) to return.
126*c54f35caSApple OSS Distributions */
127*c54f35caSApple OSS Distributions TUNABLE_WRITEABLE(uint32_t, gDriverCalloutTimer, "pmcallouttimer", 2000);
128*c54f35caSApple OSS Distributions
129*c54f35caSApple OSS Distributions static uint32_t
getPMRequestType(void)130*c54f35caSApple OSS Distributions getPMRequestType( void )
131*c54f35caSApple OSS Distributions {
132*c54f35caSApple OSS Distributions uint32_t type = kIOPMRequestTypeInvalid;
133*c54f35caSApple OSS Distributions if (gIOPMRequest) {
134*c54f35caSApple OSS Distributions type = gIOPMRequest->getType();
135*c54f35caSApple OSS Distributions }
136*c54f35caSApple OSS Distributions return type;
137*c54f35caSApple OSS Distributions }
138*c54f35caSApple OSS Distributions
139*c54f35caSApple OSS Distributions SYSCTL_UINT(_kern, OID_AUTO, pmtimeout, CTLFLAG_RW | CTLFLAG_LOCKED, &gSleepAckTimeout, 0, "Power Management Timeout");
140*c54f35caSApple OSS Distributions SYSCTL_UINT(_kern, OID_AUTO, pmcallouttimer, CTLFLAG_RW | CTLFLAG_LOCKED, &gDriverCalloutTimer, 0, "Power Management Driver Callout Log Timer");
141*c54f35caSApple OSS Distributions
142*c54f35caSApple OSS Distributions //******************************************************************************
143*c54f35caSApple OSS Distributions // Macros
144*c54f35caSApple OSS Distributions //******************************************************************************
145*c54f35caSApple OSS Distributions
146*c54f35caSApple OSS Distributions #define PM_ERROR(x...) do { kprintf(x);IOLog(x); \
147*c54f35caSApple OSS Distributions } while (false)
148*c54f35caSApple OSS Distributions #define PM_LOG(x...) do { kprintf(x); } while (false)
149*c54f35caSApple OSS Distributions
150*c54f35caSApple OSS Distributions #define PM_LOG1(x...) do { \
151*c54f35caSApple OSS Distributions if (kIOLogDebugPower & gIOKitDebug) \
152*c54f35caSApple OSS Distributions kprintf(x); } while (false)
153*c54f35caSApple OSS Distributions
154*c54f35caSApple OSS Distributions #define PM_LOG2(x...) do { \
155*c54f35caSApple OSS Distributions if (kIOLogDebugPower & gIOKitDebug) \
156*c54f35caSApple OSS Distributions kprintf(x); } while (false)
157*c54f35caSApple OSS Distributions
158*c54f35caSApple OSS Distributions #if 0
159*c54f35caSApple OSS Distributions #define PM_LOG3(x...) do { kprintf(x); } while (false)
160*c54f35caSApple OSS Distributions #else
161*c54f35caSApple OSS Distributions #define PM_LOG3(x...)
162*c54f35caSApple OSS Distributions #endif
163*c54f35caSApple OSS Distributions
164*c54f35caSApple OSS Distributions #define RD_LOG(x...) do { \
165*c54f35caSApple OSS Distributions if ((kIOLogPMRootDomain & gIOKitDebug) && \
166*c54f35caSApple OSS Distributions (getPMRootDomain() == this)) { \
167*c54f35caSApple OSS Distributions kprintf("PMRD: " x); \
168*c54f35caSApple OSS Distributions }} while (false)
169*c54f35caSApple OSS Distributions #define PM_ASSERT_IN_GATE(x) \
170*c54f35caSApple OSS Distributions do { \
171*c54f35caSApple OSS Distributions assert(gIOPMWorkLoop->inGate()); \
172*c54f35caSApple OSS Distributions } while(false)
173*c54f35caSApple OSS Distributions
174*c54f35caSApple OSS Distributions #define PM_LOCK() IOLockLock(fPMLock)
175*c54f35caSApple OSS Distributions #define PM_UNLOCK() IOLockUnlock(fPMLock)
176*c54f35caSApple OSS Distributions #define PM_LOCK_SLEEP(event, dl) IOLockSleepDeadline(fPMLock, event, dl, THREAD_UNINT)
177*c54f35caSApple OSS Distributions #define PM_LOCK_WAKEUP(event) IOLockWakeup(fPMLock, event, false)
178*c54f35caSApple OSS Distributions
179*c54f35caSApple OSS Distributions #define us_per_s 1000000
180*c54f35caSApple OSS Distributions #define ns_per_us 1000
181*c54f35caSApple OSS Distributions #define k30Seconds (30*us_per_s)
182*c54f35caSApple OSS Distributions #define k5Seconds ( 5*us_per_s)
183*c54f35caSApple OSS Distributions #define k7Seconds ( 7*us_per_s)
184*c54f35caSApple OSS Distributions #if !defined(XNU_TARGET_OS_OSX)
185*c54f35caSApple OSS Distributions #define kCanSleepMaxTimeReq k5Seconds
186*c54f35caSApple OSS Distributions #define kWillSleepMaxTimeReq k7Seconds
187*c54f35caSApple OSS Distributions #else /* defined(XNU_TARGET_OS_OSX) */
188*c54f35caSApple OSS Distributions #define kCanSleepMaxTimeReq k30Seconds
189*c54f35caSApple OSS Distributions #define kWillSleepMaxTimeReq k30Seconds
190*c54f35caSApple OSS Distributions #endif /* defined(XNU_TARGET_OS_OSX) */
191*c54f35caSApple OSS Distributions #define kMaxTimeRequested k30Seconds
192*c54f35caSApple OSS Distributions #define kMinAckTimeoutTicks (10*1000000)
193*c54f35caSApple OSS Distributions #define kIOPMTardyAckSPSKey "IOPMTardyAckSetPowerState"
194*c54f35caSApple OSS Distributions #define kIOPMTardyAckPSCKey "IOPMTardyAckPowerStateChange"
195*c54f35caSApple OSS Distributions #define kPwrMgtKey "IOPowerManagement"
196*c54f35caSApple OSS Distributions
197*c54f35caSApple OSS Distributions #define OUR_PMLog(t, a, b) do { \
198*c54f35caSApple OSS Distributions if (pwrMgt) { \
199*c54f35caSApple OSS Distributions if (gIOKitDebug & kIOLogPower) \
200*c54f35caSApple OSS Distributions pwrMgt->pmPrint(t, a, b); \
201*c54f35caSApple OSS Distributions if (gIOKitTrace & kIOTracePowerMgmt) \
202*c54f35caSApple OSS Distributions pwrMgt->pmTrace(t, DBG_FUNC_NONE, a, b); \
203*c54f35caSApple OSS Distributions } \
204*c54f35caSApple OSS Distributions } while(0)
205*c54f35caSApple OSS Distributions
206*c54f35caSApple OSS Distributions #define OUR_PMLogFuncStart(t, a, b) do { \
207*c54f35caSApple OSS Distributions if (pwrMgt) { \
208*c54f35caSApple OSS Distributions if (gIOKitDebug & kIOLogPower) \
209*c54f35caSApple OSS Distributions pwrMgt->pmPrint(t, a, b); \
210*c54f35caSApple OSS Distributions if (gIOKitTrace & kIOTracePowerMgmt) \
211*c54f35caSApple OSS Distributions pwrMgt->pmTrace(t, DBG_FUNC_START, a, b); \
212*c54f35caSApple OSS Distributions } \
213*c54f35caSApple OSS Distributions } while(0)
214*c54f35caSApple OSS Distributions
215*c54f35caSApple OSS Distributions #define OUR_PMLogFuncEnd(t, a, b) do { \
216*c54f35caSApple OSS Distributions if (pwrMgt) { \
217*c54f35caSApple OSS Distributions if (gIOKitDebug & kIOLogPower) \
218*c54f35caSApple OSS Distributions pwrMgt->pmPrint(-t, a, b); \
219*c54f35caSApple OSS Distributions if (gIOKitTrace & kIOTracePowerMgmt) \
220*c54f35caSApple OSS Distributions pwrMgt->pmTrace(t, DBG_FUNC_END, a, b); \
221*c54f35caSApple OSS Distributions } \
222*c54f35caSApple OSS Distributions } while(0)
223*c54f35caSApple OSS Distributions
224*c54f35caSApple OSS Distributions #define NS_TO_MS(nsec) ((int)((nsec) / 1000000ULL))
225*c54f35caSApple OSS Distributions #define NS_TO_US(nsec) ((int)((nsec) / 1000ULL))
226*c54f35caSApple OSS Distributions
227*c54f35caSApple OSS Distributions #define SUPPORT_IDLE_CANCEL 1
228*c54f35caSApple OSS Distributions
229*c54f35caSApple OSS Distributions #define kIOPMPowerStateMax 0xFFFFFFFF
230*c54f35caSApple OSS Distributions #define kInvalidTicklePowerState kIOPMPowerStateMax
231*c54f35caSApple OSS Distributions
232*c54f35caSApple OSS Distributions #define kNoTickleCancelWindow (60ULL * 1000ULL * 1000ULL * 1000ULL)
233*c54f35caSApple OSS Distributions
234*c54f35caSApple OSS Distributions #define IS_PM_ROOT (this == gIOPMRootNode)
235*c54f35caSApple OSS Distributions #define IS_ROOT_DOMAIN (getPMRootDomain() == this)
236*c54f35caSApple OSS Distributions #define IS_POWER_DROP (StateOrder(fHeadNotePowerState) < StateOrder(fCurrentPowerState))
237*c54f35caSApple OSS Distributions #define IS_POWER_RISE (StateOrder(fHeadNotePowerState) > StateOrder(fCurrentPowerState))
238*c54f35caSApple OSS Distributions
239*c54f35caSApple OSS Distributions // log app responses longer than (ns):
240*c54f35caSApple OSS Distributions #define LOG_APP_RESPONSE_TIMES (100ULL * 1000ULL * 1000ULL)
241*c54f35caSApple OSS Distributions // use message tracer to log messages longer than (ns):
242*c54f35caSApple OSS Distributions #define LOG_APP_RESPONSE_MSG_TRACER (3 * 1000ULL * 1000ULL * 1000ULL)
243*c54f35caSApple OSS Distributions
244*c54f35caSApple OSS Distributions // log kext responses longer than (ns):
245*c54f35caSApple OSS Distributions #define LOG_KEXT_RESPONSE_TIMES (100ULL * 1000ULL * 1000ULL)
246*c54f35caSApple OSS Distributions
247*c54f35caSApple OSS Distributions enum {
248*c54f35caSApple OSS Distributions kReserveDomainPower = 1
249*c54f35caSApple OSS Distributions };
250*c54f35caSApple OSS Distributions
251*c54f35caSApple OSS Distributions #define MS_PUSH(n) \
252*c54f35caSApple OSS Distributions do { assert(kIOPM_BadMachineState == fSavedMachineState); \
253*c54f35caSApple OSS Distributions assert(kIOPM_BadMachineState != n); \
254*c54f35caSApple OSS Distributions fSavedMachineState = n; } while (false)
255*c54f35caSApple OSS Distributions
256*c54f35caSApple OSS Distributions #define MS_POP() \
257*c54f35caSApple OSS Distributions do { assert(kIOPM_BadMachineState != fSavedMachineState); \
258*c54f35caSApple OSS Distributions fMachineState = fSavedMachineState; \
259*c54f35caSApple OSS Distributions fSavedMachineState = kIOPM_BadMachineState; } while (false)
260*c54f35caSApple OSS Distributions
261*c54f35caSApple OSS Distributions #define PM_ACTION_TICKLE(a) \
262*c54f35caSApple OSS Distributions do { if (fPMActions.a) { \
263*c54f35caSApple OSS Distributions (fPMActions.a)(fPMActions.target, this, &fPMActions); } \
264*c54f35caSApple OSS Distributions } while (false)
265*c54f35caSApple OSS Distributions
266*c54f35caSApple OSS Distributions #define PM_ACTION_CHANGE(a, x, y) \
267*c54f35caSApple OSS Distributions do { if (fPMActions.a) { \
268*c54f35caSApple OSS Distributions (fPMActions.a)(fPMActions.target, this, &fPMActions, gIOPMRequest, x, y); } \
269*c54f35caSApple OSS Distributions } while (false)
270*c54f35caSApple OSS Distributions
271*c54f35caSApple OSS Distributions #define PM_ACTION_CLIENT(a, x, y, z) \
272*c54f35caSApple OSS Distributions do { if (fPMActions.a) { \
273*c54f35caSApple OSS Distributions (fPMActions.a)(fPMActions.target, this, &fPMActions, x, y, z); } \
274*c54f35caSApple OSS Distributions } while (false)
275*c54f35caSApple OSS Distributions
276*c54f35caSApple OSS Distributions static OSNumber * copyClientIDForNotification(
277*c54f35caSApple OSS Distributions OSObject *object,
278*c54f35caSApple OSS Distributions IOPMInterestContext *context);
279*c54f35caSApple OSS Distributions
280*c54f35caSApple OSS Distributions static void logClientIDForNotification(
281*c54f35caSApple OSS Distributions OSObject *object,
282*c54f35caSApple OSS Distributions IOPMInterestContext *context,
283*c54f35caSApple OSS Distributions const char *logString);
284*c54f35caSApple OSS Distributions
285*c54f35caSApple OSS Distributions //*********************************************************************************
286*c54f35caSApple OSS Distributions // PM machine states
287*c54f35caSApple OSS Distributions //
288*c54f35caSApple OSS Distributions // Check kgmacros after modifying machine states.
289*c54f35caSApple OSS Distributions //*********************************************************************************
290*c54f35caSApple OSS Distributions
291*c54f35caSApple OSS Distributions enum {
292*c54f35caSApple OSS Distributions kIOPM_Finished = 0,
293*c54f35caSApple OSS Distributions
294*c54f35caSApple OSS Distributions kIOPM_OurChangeTellClientsPowerDown = 1,
295*c54f35caSApple OSS Distributions kIOPM_OurChangeTellUserPMPolicyPowerDown = 2,
296*c54f35caSApple OSS Distributions kIOPM_OurChangeTellPriorityClientsPowerDown = 3,
297*c54f35caSApple OSS Distributions kIOPM_OurChangeNotifyInterestedDriversWillChange = 4,
298*c54f35caSApple OSS Distributions kIOPM_OurChangeSetPowerState = 5,
299*c54f35caSApple OSS Distributions kIOPM_OurChangeWaitForPowerSettle = 6,
300*c54f35caSApple OSS Distributions kIOPM_OurChangeNotifyInterestedDriversDidChange = 7,
301*c54f35caSApple OSS Distributions kIOPM_OurChangeTellCapabilityDidChange = 8,
302*c54f35caSApple OSS Distributions kIOPM_OurChangeFinish = 9,
303*c54f35caSApple OSS Distributions
304*c54f35caSApple OSS Distributions kIOPM_ParentChangeTellPriorityClientsPowerDown = 10,
305*c54f35caSApple OSS Distributions kIOPM_ParentChangeNotifyInterestedDriversWillChange = 11,
306*c54f35caSApple OSS Distributions kIOPM_ParentChangeSetPowerState = 12,
307*c54f35caSApple OSS Distributions kIOPM_ParentChangeWaitForPowerSettle = 13,
308*c54f35caSApple OSS Distributions kIOPM_ParentChangeNotifyInterestedDriversDidChange = 14,
309*c54f35caSApple OSS Distributions kIOPM_ParentChangeTellCapabilityDidChange = 15,
310*c54f35caSApple OSS Distributions kIOPM_ParentChangeAcknowledgePowerChange = 16,
311*c54f35caSApple OSS Distributions
312*c54f35caSApple OSS Distributions kIOPM_NotifyChildrenStart = 17,
313*c54f35caSApple OSS Distributions kIOPM_NotifyChildrenOrdered = 18,
314*c54f35caSApple OSS Distributions kIOPM_NotifyChildrenDelayed = 19,
315*c54f35caSApple OSS Distributions kIOPM_SyncTellClientsPowerDown = 20,
316*c54f35caSApple OSS Distributions kIOPM_SyncTellPriorityClientsPowerDown = 21,
317*c54f35caSApple OSS Distributions kIOPM_SyncNotifyWillChange = 22,
318*c54f35caSApple OSS Distributions kIOPM_SyncNotifyDidChange = 23,
319*c54f35caSApple OSS Distributions kIOPM_SyncTellCapabilityDidChange = 24,
320*c54f35caSApple OSS Distributions kIOPM_SyncFinish = 25,
321*c54f35caSApple OSS Distributions kIOPM_TellCapabilityChangeDone = 26,
322*c54f35caSApple OSS Distributions kIOPM_DriverThreadCallDone = 27,
323*c54f35caSApple OSS Distributions
324*c54f35caSApple OSS Distributions kIOPM_BadMachineState = 0xFFFFFFFF
325*c54f35caSApple OSS Distributions };
326*c54f35caSApple OSS Distributions
327*c54f35caSApple OSS Distributions //*********************************************************************************
328*c54f35caSApple OSS Distributions // [private static] allocPMInitLock
329*c54f35caSApple OSS Distributions //
330*c54f35caSApple OSS Distributions // Allocate gIOPMInitLock prior to gIOPMWorkLoop initialization.
331*c54f35caSApple OSS Distributions //*********************************************************************************
332*c54f35caSApple OSS Distributions
333*c54f35caSApple OSS Distributions void
allocPMInitLock(void)334*c54f35caSApple OSS Distributions IOService::allocPMInitLock( void )
335*c54f35caSApple OSS Distributions {
336*c54f35caSApple OSS Distributions gIOPMInitLock = IOLockAlloc();
337*c54f35caSApple OSS Distributions assert(gIOPMInitLock);
338*c54f35caSApple OSS Distributions }
339*c54f35caSApple OSS Distributions
340*c54f35caSApple OSS Distributions //*********************************************************************************
341*c54f35caSApple OSS Distributions // [public] PMinit
342*c54f35caSApple OSS Distributions //
343*c54f35caSApple OSS Distributions // Initialize power management.
344*c54f35caSApple OSS Distributions //*********************************************************************************
345*c54f35caSApple OSS Distributions
346*c54f35caSApple OSS Distributions void
PMinit(void)347*c54f35caSApple OSS Distributions IOService::PMinit( void )
348*c54f35caSApple OSS Distributions {
349*c54f35caSApple OSS Distributions if (!initialized) {
350*c54f35caSApple OSS Distributions IOLockLock(gIOPMInitLock);
351*c54f35caSApple OSS Distributions if (!gIOPMInitialized) {
352*c54f35caSApple OSS Distributions gPlatform = getPlatform();
353*c54f35caSApple OSS Distributions gIOPMWorkLoop = IOWorkLoop::workLoop();
354*c54f35caSApple OSS Distributions if (gIOPMWorkLoop) {
355*c54f35caSApple OSS Distributions assert(OSDynamicCast(IOPMrootDomain, this));
356*c54f35caSApple OSS Distributions gIOPMRequestQueue = IOPMRequestQueue::create(
357*c54f35caSApple OSS Distributions this, OSMemberFunctionCast(IOPMRequestQueue::Action,
358*c54f35caSApple OSS Distributions this, &IOService::actionPMRequestQueue));
359*c54f35caSApple OSS Distributions
360*c54f35caSApple OSS Distributions gIOPMReplyQueue = IOPMRequestQueue::create(
361*c54f35caSApple OSS Distributions this, OSMemberFunctionCast(IOPMRequestQueue::Action,
362*c54f35caSApple OSS Distributions this, &IOService::actionPMReplyQueue));
363*c54f35caSApple OSS Distributions
364*c54f35caSApple OSS Distributions gIOPMWorkQueue = IOPMWorkQueue::create(this,
365*c54f35caSApple OSS Distributions OSMemberFunctionCast(IOPMWorkQueue::Action, this,
366*c54f35caSApple OSS Distributions &IOService::actionPMWorkQueueInvoke),
367*c54f35caSApple OSS Distributions OSMemberFunctionCast(IOPMWorkQueue::Action, this,
368*c54f35caSApple OSS Distributions &IOService::actionPMWorkQueueRetire));
369*c54f35caSApple OSS Distributions
370*c54f35caSApple OSS Distributions gIOPMCompletionQueue = IOPMCompletionQueue::create(
371*c54f35caSApple OSS Distributions this, OSMemberFunctionCast(IOPMCompletionQueue::Action,
372*c54f35caSApple OSS Distributions this, &IOService::actionPMCompletionQueue));
373*c54f35caSApple OSS Distributions
374*c54f35caSApple OSS Distributions if (gIOPMWorkLoop->addEventSource(gIOPMRequestQueue) !=
375*c54f35caSApple OSS Distributions kIOReturnSuccess) {
376*c54f35caSApple OSS Distributions gIOPMRequestQueue->release();
377*c54f35caSApple OSS Distributions gIOPMRequestQueue = NULL;
378*c54f35caSApple OSS Distributions }
379*c54f35caSApple OSS Distributions
380*c54f35caSApple OSS Distributions if (gIOPMWorkLoop->addEventSource(gIOPMReplyQueue) !=
381*c54f35caSApple OSS Distributions kIOReturnSuccess) {
382*c54f35caSApple OSS Distributions gIOPMReplyQueue->release();
383*c54f35caSApple OSS Distributions gIOPMReplyQueue = NULL;
384*c54f35caSApple OSS Distributions }
385*c54f35caSApple OSS Distributions
386*c54f35caSApple OSS Distributions if (gIOPMWorkLoop->addEventSource(gIOPMWorkQueue) !=
387*c54f35caSApple OSS Distributions kIOReturnSuccess) {
388*c54f35caSApple OSS Distributions gIOPMWorkQueue->release();
389*c54f35caSApple OSS Distributions gIOPMWorkQueue = NULL;
390*c54f35caSApple OSS Distributions }
391*c54f35caSApple OSS Distributions
392*c54f35caSApple OSS Distributions // Must be added after the work queue, which pushes request
393*c54f35caSApple OSS Distributions // to the completion queue without signaling the work loop.
394*c54f35caSApple OSS Distributions if (gIOPMWorkLoop->addEventSource(gIOPMCompletionQueue) !=
395*c54f35caSApple OSS Distributions kIOReturnSuccess) {
396*c54f35caSApple OSS Distributions gIOPMCompletionQueue->release();
397*c54f35caSApple OSS Distributions gIOPMCompletionQueue = NULL;
398*c54f35caSApple OSS Distributions }
399*c54f35caSApple OSS Distributions
400*c54f35caSApple OSS Distributions gIOPMPowerClientDevice =
401*c54f35caSApple OSS Distributions OSSymbol::withCStringNoCopy( "DevicePowerState" );
402*c54f35caSApple OSS Distributions
403*c54f35caSApple OSS Distributions gIOPMPowerClientDriver =
404*c54f35caSApple OSS Distributions OSSymbol::withCStringNoCopy( "DriverPowerState" );
405*c54f35caSApple OSS Distributions
406*c54f35caSApple OSS Distributions gIOPMPowerClientChildProxy =
407*c54f35caSApple OSS Distributions OSSymbol::withCStringNoCopy( "ChildProxyPowerState" );
408*c54f35caSApple OSS Distributions
409*c54f35caSApple OSS Distributions gIOPMPowerClientChildren =
410*c54f35caSApple OSS Distributions OSSymbol::withCStringNoCopy( "ChildrenPowerState" );
411*c54f35caSApple OSS Distributions
412*c54f35caSApple OSS Distributions gIOPMPowerClientAdvisoryTickle =
413*c54f35caSApple OSS Distributions OSSymbol::withCStringNoCopy( "AdvisoryTicklePowerState" );
414*c54f35caSApple OSS Distributions
415*c54f35caSApple OSS Distributions gIOPMPowerClientRootDomain =
416*c54f35caSApple OSS Distributions OSSymbol::withCStringNoCopy( "RootDomainPower" );
417*c54f35caSApple OSS Distributions }
418*c54f35caSApple OSS Distributions
419*c54f35caSApple OSS Distributions if (gIOPMRequestQueue && gIOPMReplyQueue && gIOPMCompletionQueue) {
420*c54f35caSApple OSS Distributions gIOPMInitialized = true;
421*c54f35caSApple OSS Distributions }
422*c54f35caSApple OSS Distributions
423*c54f35caSApple OSS Distributions #if (DEVELOPMENT || DEBUG)
424*c54f35caSApple OSS Distributions uint32_t setPowerStateLogMS = 0;
425*c54f35caSApple OSS Distributions if (PE_parse_boot_argn("setpowerstate_log", &setPowerStateLogMS, sizeof(setPowerStateLogMS))) {
426*c54f35caSApple OSS Distributions gIOPMSetPowerStateLogNS = setPowerStateLogMS * 1000000ULL;
427*c54f35caSApple OSS Distributions }
428*c54f35caSApple OSS Distributions #endif
429*c54f35caSApple OSS Distributions }
430*c54f35caSApple OSS Distributions
431*c54f35caSApple OSS Distributions IOLockUnlock(gIOPMInitLock);
432*c54f35caSApple OSS Distributions
433*c54f35caSApple OSS Distributions if (!gIOPMInitialized) {
434*c54f35caSApple OSS Distributions return;
435*c54f35caSApple OSS Distributions }
436*c54f35caSApple OSS Distributions
437*c54f35caSApple OSS Distributions pwrMgt = new IOServicePM;
438*c54f35caSApple OSS Distributions pwrMgt->init();
439*c54f35caSApple OSS Distributions setProperty(kPwrMgtKey, pwrMgt);
440*c54f35caSApple OSS Distributions
441*c54f35caSApple OSS Distributions queue_init(&pwrMgt->WorkChain);
442*c54f35caSApple OSS Distributions queue_init(&pwrMgt->RequestHead);
443*c54f35caSApple OSS Distributions queue_init(&pwrMgt->PMDriverCallQueue);
444*c54f35caSApple OSS Distributions
445*c54f35caSApple OSS Distributions fOwner = this;
446*c54f35caSApple OSS Distributions fPMLock = IOLockAlloc();
447*c54f35caSApple OSS Distributions fInterestedDrivers = new IOPMinformeeList;
448*c54f35caSApple OSS Distributions fInterestedDrivers->initialize();
449*c54f35caSApple OSS Distributions fDesiredPowerState = kPowerStateZero;
450*c54f35caSApple OSS Distributions fDeviceDesire = kPowerStateZero;
451*c54f35caSApple OSS Distributions fInitialPowerChange = true;
452*c54f35caSApple OSS Distributions fInitialSetPowerState = true;
453*c54f35caSApple OSS Distributions fPreviousRequestPowerFlags = 0;
454*c54f35caSApple OSS Distributions fDeviceOverrideEnabled = false;
455*c54f35caSApple OSS Distributions fMachineState = kIOPM_Finished;
456*c54f35caSApple OSS Distributions fSavedMachineState = kIOPM_BadMachineState;
457*c54f35caSApple OSS Distributions fIdleTimerMinPowerState = kPowerStateZero;
458*c54f35caSApple OSS Distributions fActivityLock = IOLockAlloc();
459*c54f35caSApple OSS Distributions fStrictTreeOrder = false;
460*c54f35caSApple OSS Distributions fActivityTicklePowerState = kInvalidTicklePowerState;
461*c54f35caSApple OSS Distributions fAdvisoryTicklePowerState = kInvalidTicklePowerState;
462*c54f35caSApple OSS Distributions fControllingDriver = NULL;
463*c54f35caSApple OSS Distributions fPowerStates = NULL;
464*c54f35caSApple OSS Distributions fNumberOfPowerStates = 0;
465*c54f35caSApple OSS Distributions fCurrentPowerState = kPowerStateZero;
466*c54f35caSApple OSS Distributions fParentsCurrentPowerFlags = 0;
467*c54f35caSApple OSS Distributions fMaxPowerState = kPowerStateZero;
468*c54f35caSApple OSS Distributions fName = getName();
469*c54f35caSApple OSS Distributions fParentsKnowState = false;
470*c54f35caSApple OSS Distributions fSerialNumber = 0;
471*c54f35caSApple OSS Distributions fResponseArray = NULL;
472*c54f35caSApple OSS Distributions fNotifyClientArray = NULL;
473*c54f35caSApple OSS Distributions fCurrentPowerConsumption = kIOPMUnknown;
474*c54f35caSApple OSS Distributions fOverrideMaxPowerState = kIOPMPowerStateMax;
475*c54f35caSApple OSS Distributions
476*c54f35caSApple OSS Distributions if (!gIOPMRootNode && (getParentEntry(gIOPowerPlane) == getRegistryRoot())) {
477*c54f35caSApple OSS Distributions gIOPMRootNode = this;
478*c54f35caSApple OSS Distributions fParentsKnowState = true;
479*c54f35caSApple OSS Distributions } else if (getProperty(kIOPMResetPowerStateOnWakeKey) == kOSBooleanTrue) {
480*c54f35caSApple OSS Distributions fResetPowerStateOnWake = true;
481*c54f35caSApple OSS Distributions }
482*c54f35caSApple OSS Distributions
483*c54f35caSApple OSS Distributions if (IS_ROOT_DOMAIN) {
484*c54f35caSApple OSS Distributions fWatchdogTimer = thread_call_allocate(
485*c54f35caSApple OSS Distributions &IOService::watchdog_timer_expired, (thread_call_param_t)this);
486*c54f35caSApple OSS Distributions fWatchdogLock = IOLockAlloc();
487*c54f35caSApple OSS Distributions
488*c54f35caSApple OSS Distributions fBlockedArray = OSArray::withCapacity(4);
489*c54f35caSApple OSS Distributions }
490*c54f35caSApple OSS Distributions
491*c54f35caSApple OSS Distributions fAckTimer = thread_call_allocate(
492*c54f35caSApple OSS Distributions &IOService::ack_timer_expired, (thread_call_param_t)this);
493*c54f35caSApple OSS Distributions #if USE_SETTLE_TIMER
494*c54f35caSApple OSS Distributions fSettleTimer = thread_call_allocate(
495*c54f35caSApple OSS Distributions &settle_timer_expired, (thread_call_param_t)this);
496*c54f35caSApple OSS Distributions #endif
497*c54f35caSApple OSS Distributions fIdleTimer = thread_call_allocate(
498*c54f35caSApple OSS Distributions &idle_timer_expired, (thread_call_param_t)this);
499*c54f35caSApple OSS Distributions fDriverCallTimer = thread_call_allocate(
500*c54f35caSApple OSS Distributions &IOService::pmDriverCalloutTimer, (thread_call_param_t)this);
501*c54f35caSApple OSS Distributions fDriverCallEntry = thread_call_allocate(
502*c54f35caSApple OSS Distributions (thread_call_func_t) &IOService::pmDriverCallout, this);
503*c54f35caSApple OSS Distributions assert(fDriverCallEntry);
504*c54f35caSApple OSS Distributions
505*c54f35caSApple OSS Distributions // Check for powerChangeDone override.
506*c54f35caSApple OSS Distributions if (OSMemberFunctionCast(void (*)(void),
507*c54f35caSApple OSS Distributions getResourceService(), &IOService::powerChangeDone) !=
508*c54f35caSApple OSS Distributions OSMemberFunctionCast(void (*)(void),
509*c54f35caSApple OSS Distributions this, &IOService::powerChangeDone)) {
510*c54f35caSApple OSS Distributions fPCDFunctionOverride = true;
511*c54f35caSApple OSS Distributions }
512*c54f35caSApple OSS Distributions
513*c54f35caSApple OSS Distributions #if PM_VARS_SUPPORT
514*c54f35caSApple OSS Distributions IOPMprot * prot = new IOPMprot;
515*c54f35caSApple OSS Distributions if (prot) {
516*c54f35caSApple OSS Distributions prot->init();
517*c54f35caSApple OSS Distributions prot->ourName = fName;
518*c54f35caSApple OSS Distributions prot->thePlatform = gPlatform;
519*c54f35caSApple OSS Distributions fPMVars = prot;
520*c54f35caSApple OSS Distributions pm_vars = prot;
521*c54f35caSApple OSS Distributions }
522*c54f35caSApple OSS Distributions #else
523*c54f35caSApple OSS Distributions pm_vars = (void *) (uintptr_t) true;
524*c54f35caSApple OSS Distributions #endif
525*c54f35caSApple OSS Distributions
526*c54f35caSApple OSS Distributions initialized = true;
527*c54f35caSApple OSS Distributions }
528*c54f35caSApple OSS Distributions }
529*c54f35caSApple OSS Distributions
530*c54f35caSApple OSS Distributions //*********************************************************************************
531*c54f35caSApple OSS Distributions // [private] PMfree
532*c54f35caSApple OSS Distributions //
533*c54f35caSApple OSS Distributions // Free the data created by PMinit. Only called from IOService::free().
534*c54f35caSApple OSS Distributions //*********************************************************************************
535*c54f35caSApple OSS Distributions
536*c54f35caSApple OSS Distributions void
PMfree(void)537*c54f35caSApple OSS Distributions IOService::PMfree( void )
538*c54f35caSApple OSS Distributions {
539*c54f35caSApple OSS Distributions initialized = false;
540*c54f35caSApple OSS Distributions pm_vars = NULL;
541*c54f35caSApple OSS Distributions
542*c54f35caSApple OSS Distributions if (pwrMgt) {
543*c54f35caSApple OSS Distributions assert(fMachineState == kIOPM_Finished);
544*c54f35caSApple OSS Distributions assert(fInsertInterestSet == NULL);
545*c54f35caSApple OSS Distributions assert(fRemoveInterestSet == NULL);
546*c54f35caSApple OSS Distributions assert(fNotifyChildArray == NULL);
547*c54f35caSApple OSS Distributions assert(queue_empty(&pwrMgt->RequestHead));
548*c54f35caSApple OSS Distributions assert(queue_empty(&fPMDriverCallQueue));
549*c54f35caSApple OSS Distributions
550*c54f35caSApple OSS Distributions if (fWatchdogTimer) {
551*c54f35caSApple OSS Distributions thread_call_cancel(fWatchdogTimer);
552*c54f35caSApple OSS Distributions thread_call_free(fWatchdogTimer);
553*c54f35caSApple OSS Distributions fWatchdogTimer = NULL;
554*c54f35caSApple OSS Distributions }
555*c54f35caSApple OSS Distributions
556*c54f35caSApple OSS Distributions if (fWatchdogLock) {
557*c54f35caSApple OSS Distributions IOLockFree(fWatchdogLock);
558*c54f35caSApple OSS Distributions fWatchdogLock = NULL;
559*c54f35caSApple OSS Distributions }
560*c54f35caSApple OSS Distributions
561*c54f35caSApple OSS Distributions if (fBlockedArray) {
562*c54f35caSApple OSS Distributions fBlockedArray->release();
563*c54f35caSApple OSS Distributions fBlockedArray = NULL;
564*c54f35caSApple OSS Distributions }
565*c54f35caSApple OSS Distributions #if USE_SETTLE_TIMER
566*c54f35caSApple OSS Distributions if (fSettleTimer) {
567*c54f35caSApple OSS Distributions thread_call_cancel(fSettleTimer);
568*c54f35caSApple OSS Distributions thread_call_free(fSettleTimer);
569*c54f35caSApple OSS Distributions fSettleTimer = NULL;
570*c54f35caSApple OSS Distributions }
571*c54f35caSApple OSS Distributions #endif
572*c54f35caSApple OSS Distributions if (fAckTimer) {
573*c54f35caSApple OSS Distributions thread_call_cancel(fAckTimer);
574*c54f35caSApple OSS Distributions thread_call_free(fAckTimer);
575*c54f35caSApple OSS Distributions fAckTimer = NULL;
576*c54f35caSApple OSS Distributions }
577*c54f35caSApple OSS Distributions if (fIdleTimer) {
578*c54f35caSApple OSS Distributions thread_call_cancel(fIdleTimer);
579*c54f35caSApple OSS Distributions thread_call_free(fIdleTimer);
580*c54f35caSApple OSS Distributions fIdleTimer = NULL;
581*c54f35caSApple OSS Distributions }
582*c54f35caSApple OSS Distributions if (fDriverCallEntry) {
583*c54f35caSApple OSS Distributions thread_call_free(fDriverCallEntry);
584*c54f35caSApple OSS Distributions fDriverCallEntry = NULL;
585*c54f35caSApple OSS Distributions }
586*c54f35caSApple OSS Distributions if (fDriverCallTimer) {
587*c54f35caSApple OSS Distributions thread_call_free(fDriverCallTimer);
588*c54f35caSApple OSS Distributions fDriverCallTimer = NULL;
589*c54f35caSApple OSS Distributions }
590*c54f35caSApple OSS Distributions if (fPMLock) {
591*c54f35caSApple OSS Distributions IOLockFree(fPMLock);
592*c54f35caSApple OSS Distributions fPMLock = NULL;
593*c54f35caSApple OSS Distributions }
594*c54f35caSApple OSS Distributions if (fActivityLock) {
595*c54f35caSApple OSS Distributions IOLockFree(fActivityLock);
596*c54f35caSApple OSS Distributions fActivityLock = NULL;
597*c54f35caSApple OSS Distributions }
598*c54f35caSApple OSS Distributions if (fInterestedDrivers) {
599*c54f35caSApple OSS Distributions fInterestedDrivers->release();
600*c54f35caSApple OSS Distributions fInterestedDrivers = NULL;
601*c54f35caSApple OSS Distributions }
602*c54f35caSApple OSS Distributions if (fDriverCallParamSlots && fDriverCallParamPtr) {
603*c54f35caSApple OSS Distributions IODelete(fDriverCallParamPtr, DriverCallParam, fDriverCallParamSlots);
604*c54f35caSApple OSS Distributions fDriverCallParamPtr = NULL;
605*c54f35caSApple OSS Distributions fDriverCallParamSlots = 0;
606*c54f35caSApple OSS Distributions }
607*c54f35caSApple OSS Distributions if (fResponseArray) {
608*c54f35caSApple OSS Distributions fResponseArray->release();
609*c54f35caSApple OSS Distributions fResponseArray = NULL;
610*c54f35caSApple OSS Distributions }
611*c54f35caSApple OSS Distributions if (fNotifyClientArray) {
612*c54f35caSApple OSS Distributions fNotifyClientArray->release();
613*c54f35caSApple OSS Distributions fNotifyClientArray = NULL;
614*c54f35caSApple OSS Distributions }
615*c54f35caSApple OSS Distributions if (fReportBuf && fNumberOfPowerStates) {
616*c54f35caSApple OSS Distributions IOFreeData(fReportBuf, STATEREPORT_BUFSIZE(fNumberOfPowerStates));
617*c54f35caSApple OSS Distributions fReportBuf = NULL;
618*c54f35caSApple OSS Distributions }
619*c54f35caSApple OSS Distributions if (fPowerStates && fNumberOfPowerStates) {
620*c54f35caSApple OSS Distributions IODeleteData(fPowerStates, IOPMPSEntry, fNumberOfPowerStates);
621*c54f35caSApple OSS Distributions fNumberOfPowerStates = 0;
622*c54f35caSApple OSS Distributions fPowerStates = NULL;
623*c54f35caSApple OSS Distributions }
624*c54f35caSApple OSS Distributions if (fPowerClients) {
625*c54f35caSApple OSS Distributions fPowerClients->release();
626*c54f35caSApple OSS Distributions fPowerClients = NULL;
627*c54f35caSApple OSS Distributions }
628*c54f35caSApple OSS Distributions
629*c54f35caSApple OSS Distributions #if PM_VARS_SUPPORT
630*c54f35caSApple OSS Distributions if (fPMVars) {
631*c54f35caSApple OSS Distributions fPMVars->release();
632*c54f35caSApple OSS Distributions fPMVars = NULL;
633*c54f35caSApple OSS Distributions }
634*c54f35caSApple OSS Distributions #endif
635*c54f35caSApple OSS Distributions
636*c54f35caSApple OSS Distributions pwrMgt->release();
637*c54f35caSApple OSS Distributions pwrMgt = NULL;
638*c54f35caSApple OSS Distributions }
639*c54f35caSApple OSS Distributions }
640*c54f35caSApple OSS Distributions
641*c54f35caSApple OSS Distributions void
PMDebug(uint32_t event,uintptr_t param1,uintptr_t param2)642*c54f35caSApple OSS Distributions IOService::PMDebug( uint32_t event, uintptr_t param1, uintptr_t param2 )
643*c54f35caSApple OSS Distributions {
644*c54f35caSApple OSS Distributions OUR_PMLog(event, param1, param2);
645*c54f35caSApple OSS Distributions }
646*c54f35caSApple OSS Distributions
647*c54f35caSApple OSS Distributions //*********************************************************************************
648*c54f35caSApple OSS Distributions // [public] joinPMtree
649*c54f35caSApple OSS Distributions //
650*c54f35caSApple OSS Distributions // A policy-maker calls its nub here when initializing, to be attached into
651*c54f35caSApple OSS Distributions // the power management hierarchy. The default function is to call the
652*c54f35caSApple OSS Distributions // platform expert, which knows how to do it. This method is overridden
653*c54f35caSApple OSS Distributions // by a nub subclass which may either know how to do it, or may need to
654*c54f35caSApple OSS Distributions // take other action.
655*c54f35caSApple OSS Distributions //
656*c54f35caSApple OSS Distributions // This may be the only "power management" method used in a nub,
657*c54f35caSApple OSS Distributions // meaning it may not be initialized for power management.
658*c54f35caSApple OSS Distributions //*********************************************************************************
659*c54f35caSApple OSS Distributions
660*c54f35caSApple OSS Distributions void
joinPMtree(IOService * driver)661*c54f35caSApple OSS Distributions IOService::joinPMtree( IOService * driver )
662*c54f35caSApple OSS Distributions {
663*c54f35caSApple OSS Distributions IOPlatformExpert * platform;
664*c54f35caSApple OSS Distributions
665*c54f35caSApple OSS Distributions platform = getPlatform();
666*c54f35caSApple OSS Distributions assert(platform != NULL);
667*c54f35caSApple OSS Distributions platform->PMRegisterDevice(this, driver);
668*c54f35caSApple OSS Distributions }
669*c54f35caSApple OSS Distributions
670*c54f35caSApple OSS Distributions #ifndef __LP64__
671*c54f35caSApple OSS Distributions //*********************************************************************************
672*c54f35caSApple OSS Distributions // [deprecated] youAreRoot
673*c54f35caSApple OSS Distributions //
674*c54f35caSApple OSS Distributions // Power Managment is informing us that we are the root power domain.
675*c54f35caSApple OSS Distributions //*********************************************************************************
676*c54f35caSApple OSS Distributions
677*c54f35caSApple OSS Distributions IOReturn
youAreRoot(void)678*c54f35caSApple OSS Distributions IOService::youAreRoot( void )
679*c54f35caSApple OSS Distributions {
680*c54f35caSApple OSS Distributions return IOPMNoErr;
681*c54f35caSApple OSS Distributions }
682*c54f35caSApple OSS Distributions #endif /* !__LP64__ */
683*c54f35caSApple OSS Distributions
684*c54f35caSApple OSS Distributions //*********************************************************************************
685*c54f35caSApple OSS Distributions // [public] PMstop
686*c54f35caSApple OSS Distributions //
687*c54f35caSApple OSS Distributions // Immediately stop driver callouts. Schedule an async stop request to detach
688*c54f35caSApple OSS Distributions // from power plane.
689*c54f35caSApple OSS Distributions //*********************************************************************************
690*c54f35caSApple OSS Distributions
691*c54f35caSApple OSS Distributions void
PMstop(void)692*c54f35caSApple OSS Distributions IOService::PMstop( void )
693*c54f35caSApple OSS Distributions {
694*c54f35caSApple OSS Distributions IOPMRequest * request;
695*c54f35caSApple OSS Distributions
696*c54f35caSApple OSS Distributions if (!initialized) {
697*c54f35caSApple OSS Distributions return;
698*c54f35caSApple OSS Distributions }
699*c54f35caSApple OSS Distributions
700*c54f35caSApple OSS Distributions PM_LOCK();
701*c54f35caSApple OSS Distributions
702*c54f35caSApple OSS Distributions if (fLockedFlags.PMStop) {
703*c54f35caSApple OSS Distributions PM_LOG2("%s: PMstop() already stopped\n", fName);
704*c54f35caSApple OSS Distributions PM_UNLOCK();
705*c54f35caSApple OSS Distributions return;
706*c54f35caSApple OSS Distributions }
707*c54f35caSApple OSS Distributions
708*c54f35caSApple OSS Distributions // Inhibit future driver calls.
709*c54f35caSApple OSS Distributions fLockedFlags.PMStop = true;
710*c54f35caSApple OSS Distributions
711*c54f35caSApple OSS Distributions // Wait for all prior driver calls to finish.
712*c54f35caSApple OSS Distributions waitForPMDriverCall();
713*c54f35caSApple OSS Distributions
714*c54f35caSApple OSS Distributions PM_UNLOCK();
715*c54f35caSApple OSS Distributions
716*c54f35caSApple OSS Distributions // The rest of the work is performed async.
717*c54f35caSApple OSS Distributions request = acquirePMRequest( this, kIOPMRequestTypePMStop );
718*c54f35caSApple OSS Distributions if (request) {
719*c54f35caSApple OSS Distributions PM_LOG2("%s: %p PMstop\n", getName(), OBFUSCATE(this));
720*c54f35caSApple OSS Distributions submitPMRequest( request );
721*c54f35caSApple OSS Distributions }
722*c54f35caSApple OSS Distributions }
723*c54f35caSApple OSS Distributions
724*c54f35caSApple OSS Distributions //*********************************************************************************
725*c54f35caSApple OSS Distributions // [private] handlePMstop
726*c54f35caSApple OSS Distributions //
727*c54f35caSApple OSS Distributions // Disconnect the node from all parents and children in the power plane.
728*c54f35caSApple OSS Distributions //*********************************************************************************
729*c54f35caSApple OSS Distributions
730*c54f35caSApple OSS Distributions void
handlePMstop(IOPMRequest * request)731*c54f35caSApple OSS Distributions IOService::handlePMstop( IOPMRequest * request )
732*c54f35caSApple OSS Distributions {
733*c54f35caSApple OSS Distributions OSIterator * iter;
734*c54f35caSApple OSS Distributions OSObject * next;
735*c54f35caSApple OSS Distributions IOPowerConnection * connection;
736*c54f35caSApple OSS Distributions IOService * theChild;
737*c54f35caSApple OSS Distributions IOService * theParent;
738*c54f35caSApple OSS Distributions
739*c54f35caSApple OSS Distributions PM_ASSERT_IN_GATE();
740*c54f35caSApple OSS Distributions PM_LOG2("%s: %p %s start\n", getName(), OBFUSCATE(this), __FUNCTION__);
741*c54f35caSApple OSS Distributions
742*c54f35caSApple OSS Distributions // remove driver from prevent system sleep lists
743*c54f35caSApple OSS Distributions getPMRootDomain()->updatePreventIdleSleepList(this, false);
744*c54f35caSApple OSS Distributions getPMRootDomain()->updatePreventSystemSleepList(this, false);
745*c54f35caSApple OSS Distributions
746*c54f35caSApple OSS Distributions // remove the property
747*c54f35caSApple OSS Distributions removeProperty(kPwrMgtKey);
748*c54f35caSApple OSS Distributions
749*c54f35caSApple OSS Distributions // detach parents
750*c54f35caSApple OSS Distributions iter = getParentIterator(gIOPowerPlane);
751*c54f35caSApple OSS Distributions if (iter) {
752*c54f35caSApple OSS Distributions while ((next = iter->getNextObject())) {
753*c54f35caSApple OSS Distributions if ((connection = OSDynamicCast(IOPowerConnection, next))) {
754*c54f35caSApple OSS Distributions theParent = (IOService *)connection->copyParentEntry(gIOPowerPlane);
755*c54f35caSApple OSS Distributions if (theParent) {
756*c54f35caSApple OSS Distributions theParent->removePowerChild(connection);
757*c54f35caSApple OSS Distributions theParent->release();
758*c54f35caSApple OSS Distributions }
759*c54f35caSApple OSS Distributions }
760*c54f35caSApple OSS Distributions }
761*c54f35caSApple OSS Distributions iter->release();
762*c54f35caSApple OSS Distributions }
763*c54f35caSApple OSS Distributions
764*c54f35caSApple OSS Distributions // detach IOConnections
765*c54f35caSApple OSS Distributions detachAbove( gIOPowerPlane );
766*c54f35caSApple OSS Distributions
767*c54f35caSApple OSS Distributions // no more power state changes
768*c54f35caSApple OSS Distributions fParentsKnowState = false;
769*c54f35caSApple OSS Distributions
770*c54f35caSApple OSS Distributions // detach children
771*c54f35caSApple OSS Distributions iter = getChildIterator(gIOPowerPlane);
772*c54f35caSApple OSS Distributions if (iter) {
773*c54f35caSApple OSS Distributions while ((next = iter->getNextObject())) {
774*c54f35caSApple OSS Distributions if ((connection = OSDynamicCast(IOPowerConnection, next))) {
775*c54f35caSApple OSS Distributions theChild = ((IOService *)(connection->copyChildEntry(gIOPowerPlane)));
776*c54f35caSApple OSS Distributions if (theChild) {
777*c54f35caSApple OSS Distributions // detach nub from child
778*c54f35caSApple OSS Distributions connection->detachFromChild(theChild, gIOPowerPlane);
779*c54f35caSApple OSS Distributions theChild->release();
780*c54f35caSApple OSS Distributions }
781*c54f35caSApple OSS Distributions // detach us from nub
782*c54f35caSApple OSS Distributions detachFromChild(connection, gIOPowerPlane);
783*c54f35caSApple OSS Distributions }
784*c54f35caSApple OSS Distributions }
785*c54f35caSApple OSS Distributions iter->release();
786*c54f35caSApple OSS Distributions }
787*c54f35caSApple OSS Distributions
788*c54f35caSApple OSS Distributions // Remove all interested drivers from the list, including the power
789*c54f35caSApple OSS Distributions // controlling driver.
790*c54f35caSApple OSS Distributions //
791*c54f35caSApple OSS Distributions // Usually, the controlling driver and the policy-maker functionality
792*c54f35caSApple OSS Distributions // are implemented by the same object, and without the deregistration,
793*c54f35caSApple OSS Distributions // the object will be holding an extra retain on itself, and cannot
794*c54f35caSApple OSS Distributions // be freed.
795*c54f35caSApple OSS Distributions
796*c54f35caSApple OSS Distributions if (fInterestedDrivers) {
797*c54f35caSApple OSS Distributions IOPMinformeeList * list = fInterestedDrivers;
798*c54f35caSApple OSS Distributions IOPMinformee * item;
799*c54f35caSApple OSS Distributions
800*c54f35caSApple OSS Distributions PM_LOCK();
801*c54f35caSApple OSS Distributions while ((item = list->firstInList())) {
802*c54f35caSApple OSS Distributions list->removeFromList(item->whatObject);
803*c54f35caSApple OSS Distributions }
804*c54f35caSApple OSS Distributions PM_UNLOCK();
805*c54f35caSApple OSS Distributions }
806*c54f35caSApple OSS Distributions
807*c54f35caSApple OSS Distributions // Clear idle period to prevent idleTimerExpired() from servicing
808*c54f35caSApple OSS Distributions // idle timer expirations.
809*c54f35caSApple OSS Distributions
810*c54f35caSApple OSS Distributions fIdleTimerPeriod = 0;
811*c54f35caSApple OSS Distributions if (fIdleTimer && thread_call_cancel(fIdleTimer)) {
812*c54f35caSApple OSS Distributions release();
813*c54f35caSApple OSS Distributions }
814*c54f35caSApple OSS Distributions
815*c54f35caSApple OSS Distributions PM_LOG2("%s: %p %s done\n", getName(), OBFUSCATE(this), __FUNCTION__);
816*c54f35caSApple OSS Distributions }
817*c54f35caSApple OSS Distributions
818*c54f35caSApple OSS Distributions //*********************************************************************************
819*c54f35caSApple OSS Distributions // [public] addPowerChild
820*c54f35caSApple OSS Distributions //
821*c54f35caSApple OSS Distributions // Power Management is informing us who our children are.
822*c54f35caSApple OSS Distributions //*********************************************************************************
823*c54f35caSApple OSS Distributions
824*c54f35caSApple OSS Distributions IOReturn
addPowerChild(IOService * child)825*c54f35caSApple OSS Distributions IOService::addPowerChild( IOService * child )
826*c54f35caSApple OSS Distributions {
827*c54f35caSApple OSS Distributions IOPowerConnection * connection = NULL;
828*c54f35caSApple OSS Distributions IOPMRequest * requests[3] = {NULL, NULL, NULL};
829*c54f35caSApple OSS Distributions OSIterator * iter;
830*c54f35caSApple OSS Distributions bool ok = true;
831*c54f35caSApple OSS Distributions
832*c54f35caSApple OSS Distributions if (!child) {
833*c54f35caSApple OSS Distributions return kIOReturnBadArgument;
834*c54f35caSApple OSS Distributions }
835*c54f35caSApple OSS Distributions
836*c54f35caSApple OSS Distributions if (!initialized || !child->initialized) {
837*c54f35caSApple OSS Distributions return IOPMNotYetInitialized;
838*c54f35caSApple OSS Distributions }
839*c54f35caSApple OSS Distributions
840*c54f35caSApple OSS Distributions OUR_PMLog( kPMLogAddChild, (uintptr_t) child, 0 );
841*c54f35caSApple OSS Distributions
842*c54f35caSApple OSS Distributions do {
843*c54f35caSApple OSS Distributions // Is this child already one of our children?
844*c54f35caSApple OSS Distributions
845*c54f35caSApple OSS Distributions iter = child->getParentIterator( gIOPowerPlane );
846*c54f35caSApple OSS Distributions if (iter) {
847*c54f35caSApple OSS Distributions IORegistryEntry * entry;
848*c54f35caSApple OSS Distributions OSObject * next;
849*c54f35caSApple OSS Distributions
850*c54f35caSApple OSS Distributions while ((next = iter->getNextObject())) {
851*c54f35caSApple OSS Distributions if ((entry = OSDynamicCast(IORegistryEntry, next)) &&
852*c54f35caSApple OSS Distributions isChild(entry, gIOPowerPlane)) {
853*c54f35caSApple OSS Distributions ok = false;
854*c54f35caSApple OSS Distributions break;
855*c54f35caSApple OSS Distributions }
856*c54f35caSApple OSS Distributions }
857*c54f35caSApple OSS Distributions iter->release();
858*c54f35caSApple OSS Distributions }
859*c54f35caSApple OSS Distributions if (!ok) {
860*c54f35caSApple OSS Distributions PM_LOG2("%s: %s (%p) is already a child\n",
861*c54f35caSApple OSS Distributions getName(), child->getName(), OBFUSCATE(child));
862*c54f35caSApple OSS Distributions break;
863*c54f35caSApple OSS Distributions }
864*c54f35caSApple OSS Distributions
865*c54f35caSApple OSS Distributions // Add the child to the power plane immediately, but the
866*c54f35caSApple OSS Distributions // joining connection is marked as not ready.
867*c54f35caSApple OSS Distributions // We want the child to appear in the power plane before
868*c54f35caSApple OSS Distributions // returning to the caller, but don't want the caller to
869*c54f35caSApple OSS Distributions // block on the PM work loop.
870*c54f35caSApple OSS Distributions
871*c54f35caSApple OSS Distributions connection = new IOPowerConnection;
872*c54f35caSApple OSS Distributions if (!connection) {
873*c54f35caSApple OSS Distributions break;
874*c54f35caSApple OSS Distributions }
875*c54f35caSApple OSS Distributions
876*c54f35caSApple OSS Distributions // Create a chain of PM requests to perform the bottom-half
877*c54f35caSApple OSS Distributions // work from the PM work loop.
878*c54f35caSApple OSS Distributions
879*c54f35caSApple OSS Distributions requests[0] = acquirePMRequest(
880*c54f35caSApple OSS Distributions /* target */ this,
881*c54f35caSApple OSS Distributions /* type */ kIOPMRequestTypeAddPowerChild1 );
882*c54f35caSApple OSS Distributions
883*c54f35caSApple OSS Distributions requests[1] = acquirePMRequest(
884*c54f35caSApple OSS Distributions /* target */ child,
885*c54f35caSApple OSS Distributions /* type */ kIOPMRequestTypeAddPowerChild2 );
886*c54f35caSApple OSS Distributions
887*c54f35caSApple OSS Distributions requests[2] = acquirePMRequest(
888*c54f35caSApple OSS Distributions /* target */ this,
889*c54f35caSApple OSS Distributions /* type */ kIOPMRequestTypeAddPowerChild3 );
890*c54f35caSApple OSS Distributions
891*c54f35caSApple OSS Distributions if (!requests[0] || !requests[1] || !requests[2]) {
892*c54f35caSApple OSS Distributions break;
893*c54f35caSApple OSS Distributions }
894*c54f35caSApple OSS Distributions
895*c54f35caSApple OSS Distributions requests[0]->attachNextRequest( requests[1] );
896*c54f35caSApple OSS Distributions requests[1]->attachNextRequest( requests[2] );
897*c54f35caSApple OSS Distributions
898*c54f35caSApple OSS Distributions connection->init();
899*c54f35caSApple OSS Distributions connection->start(this);
900*c54f35caSApple OSS Distributions connection->setAwaitingAck(false);
901*c54f35caSApple OSS Distributions connection->setReadyFlag(false);
902*c54f35caSApple OSS Distributions
903*c54f35caSApple OSS Distributions attachToChild( connection, gIOPowerPlane );
904*c54f35caSApple OSS Distributions connection->attachToChild( child, gIOPowerPlane );
905*c54f35caSApple OSS Distributions
906*c54f35caSApple OSS Distributions // connection needs to be released
907*c54f35caSApple OSS Distributions requests[0]->fArg0 = connection;
908*c54f35caSApple OSS Distributions requests[1]->fArg0 = connection;
909*c54f35caSApple OSS Distributions requests[2]->fArg0 = connection;
910*c54f35caSApple OSS Distributions
911*c54f35caSApple OSS Distributions submitPMRequests( requests, 3 );
912*c54f35caSApple OSS Distributions return kIOReturnSuccess;
913*c54f35caSApple OSS Distributions }while (false);
914*c54f35caSApple OSS Distributions
915*c54f35caSApple OSS Distributions if (connection) {
916*c54f35caSApple OSS Distributions connection->release();
917*c54f35caSApple OSS Distributions }
918*c54f35caSApple OSS Distributions if (requests[0]) {
919*c54f35caSApple OSS Distributions releasePMRequest(requests[0]);
920*c54f35caSApple OSS Distributions }
921*c54f35caSApple OSS Distributions if (requests[1]) {
922*c54f35caSApple OSS Distributions releasePMRequest(requests[1]);
923*c54f35caSApple OSS Distributions }
924*c54f35caSApple OSS Distributions if (requests[2]) {
925*c54f35caSApple OSS Distributions releasePMRequest(requests[2]);
926*c54f35caSApple OSS Distributions }
927*c54f35caSApple OSS Distributions
928*c54f35caSApple OSS Distributions // Silent failure, to prevent platform drivers from adding the child
929*c54f35caSApple OSS Distributions // to the root domain.
930*c54f35caSApple OSS Distributions
931*c54f35caSApple OSS Distributions return kIOReturnSuccess;
932*c54f35caSApple OSS Distributions }
933*c54f35caSApple OSS Distributions
934*c54f35caSApple OSS Distributions //*********************************************************************************
935*c54f35caSApple OSS Distributions // [private] addPowerChild1
936*c54f35caSApple OSS Distributions //
937*c54f35caSApple OSS Distributions // Step 1/3 of adding a power child. Called on the power parent.
938*c54f35caSApple OSS Distributions //*********************************************************************************
939*c54f35caSApple OSS Distributions
940*c54f35caSApple OSS Distributions void
addPowerChild1(IOPMRequest * request)941*c54f35caSApple OSS Distributions IOService::addPowerChild1( IOPMRequest * request )
942*c54f35caSApple OSS Distributions {
943*c54f35caSApple OSS Distributions IOPMPowerStateIndex tempDesire = kPowerStateZero;
944*c54f35caSApple OSS Distributions
945*c54f35caSApple OSS Distributions // Make us temporary usable before adding the child.
946*c54f35caSApple OSS Distributions
947*c54f35caSApple OSS Distributions PM_ASSERT_IN_GATE();
948*c54f35caSApple OSS Distributions OUR_PMLog( kPMLogMakeUsable, kPMLogMakeUsable, 0 );
949*c54f35caSApple OSS Distributions
950*c54f35caSApple OSS Distributions if (fControllingDriver && inPlane(gIOPowerPlane) && fParentsKnowState) {
951*c54f35caSApple OSS Distributions tempDesire = fHighestPowerState;
952*c54f35caSApple OSS Distributions }
953*c54f35caSApple OSS Distributions
954*c54f35caSApple OSS Distributions if ((tempDesire != kPowerStateZero) &&
955*c54f35caSApple OSS Distributions (IS_PM_ROOT || (StateOrder(fMaxPowerState) >= StateOrder(tempDesire)))) {
956*c54f35caSApple OSS Distributions adjustPowerState(tempDesire);
957*c54f35caSApple OSS Distributions }
958*c54f35caSApple OSS Distributions }
959*c54f35caSApple OSS Distributions
960*c54f35caSApple OSS Distributions //*********************************************************************************
961*c54f35caSApple OSS Distributions // [private] addPowerChild2
962*c54f35caSApple OSS Distributions //
963*c54f35caSApple OSS Distributions // Step 2/3 of adding a power child. Called on the joining child.
964*c54f35caSApple OSS Distributions // Execution blocked behind addPowerChild1.
965*c54f35caSApple OSS Distributions //*********************************************************************************
966*c54f35caSApple OSS Distributions
967*c54f35caSApple OSS Distributions void
addPowerChild2(IOPMRequest * request)968*c54f35caSApple OSS Distributions IOService::addPowerChild2( IOPMRequest * request )
969*c54f35caSApple OSS Distributions {
970*c54f35caSApple OSS Distributions IOPowerConnection * connection = (IOPowerConnection *) request->fArg0;
971*c54f35caSApple OSS Distributions IOService * parent;
972*c54f35caSApple OSS Distributions IOPMPowerFlags powerFlags;
973*c54f35caSApple OSS Distributions bool knowsState;
974*c54f35caSApple OSS Distributions IOPMPowerStateIndex powerState;
975*c54f35caSApple OSS Distributions IOPMPowerStateIndex tempDesire;
976*c54f35caSApple OSS Distributions
977*c54f35caSApple OSS Distributions PM_ASSERT_IN_GATE();
978*c54f35caSApple OSS Distributions parent = (IOService *) connection->getParentEntry(gIOPowerPlane);
979*c54f35caSApple OSS Distributions
980*c54f35caSApple OSS Distributions if (!parent || !inPlane(gIOPowerPlane)) {
981*c54f35caSApple OSS Distributions PM_LOG("%s: addPowerChild2 not in power plane\n", getName());
982*c54f35caSApple OSS Distributions return;
983*c54f35caSApple OSS Distributions }
984*c54f35caSApple OSS Distributions
985*c54f35caSApple OSS Distributions // Parent will be waiting for us to complete this stage.
986*c54f35caSApple OSS Distributions // It is safe to directly access parent's vars.
987*c54f35caSApple OSS Distributions
988*c54f35caSApple OSS Distributions knowsState = (parent->fPowerStates) && (parent->fParentsKnowState);
989*c54f35caSApple OSS Distributions powerState = parent->fCurrentPowerState;
990*c54f35caSApple OSS Distributions
991*c54f35caSApple OSS Distributions if (knowsState) {
992*c54f35caSApple OSS Distributions powerFlags = parent->fPowerStates[powerState].outputPowerFlags;
993*c54f35caSApple OSS Distributions } else {
994*c54f35caSApple OSS Distributions powerFlags = 0;
995*c54f35caSApple OSS Distributions }
996*c54f35caSApple OSS Distributions
997*c54f35caSApple OSS Distributions // Set our power parent.
998*c54f35caSApple OSS Distributions
999*c54f35caSApple OSS Distributions OUR_PMLog(kPMLogSetParent, knowsState, powerFlags);
1000*c54f35caSApple OSS Distributions
1001*c54f35caSApple OSS Distributions setParentInfo( powerFlags, connection, knowsState );
1002*c54f35caSApple OSS Distributions
1003*c54f35caSApple OSS Distributions connection->setReadyFlag(true);
1004*c54f35caSApple OSS Distributions
1005*c54f35caSApple OSS Distributions if (fControllingDriver && fParentsKnowState) {
1006*c54f35caSApple OSS Distributions fMaxPowerState = fControllingDriver->maxCapabilityForDomainState(fParentsCurrentPowerFlags);
1007*c54f35caSApple OSS Distributions // initially change into the state we are already in
1008*c54f35caSApple OSS Distributions tempDesire = fControllingDriver->initialPowerStateForDomainState(fParentsCurrentPowerFlags);
1009*c54f35caSApple OSS Distributions fPreviousRequestPowerFlags = (IOPMPowerFlags)(-1);
1010*c54f35caSApple OSS Distributions adjustPowerState(tempDesire);
1011*c54f35caSApple OSS Distributions }
1012*c54f35caSApple OSS Distributions }
1013*c54f35caSApple OSS Distributions
1014*c54f35caSApple OSS Distributions //*********************************************************************************
1015*c54f35caSApple OSS Distributions // [private] addPowerChild3
1016*c54f35caSApple OSS Distributions //
1017*c54f35caSApple OSS Distributions // Step 3/3 of adding a power child. Called on the parent.
1018*c54f35caSApple OSS Distributions // Execution blocked behind addPowerChild2.
1019*c54f35caSApple OSS Distributions //*********************************************************************************
1020*c54f35caSApple OSS Distributions
1021*c54f35caSApple OSS Distributions void
addPowerChild3(IOPMRequest * request)1022*c54f35caSApple OSS Distributions IOService::addPowerChild3( IOPMRequest * request )
1023*c54f35caSApple OSS Distributions {
1024*c54f35caSApple OSS Distributions IOPowerConnection * connection = (IOPowerConnection *) request->fArg0;
1025*c54f35caSApple OSS Distributions IOService * child;
1026*c54f35caSApple OSS Distributions IOPMrootDomain * rootDomain = getPMRootDomain();
1027*c54f35caSApple OSS Distributions
1028*c54f35caSApple OSS Distributions PM_ASSERT_IN_GATE();
1029*c54f35caSApple OSS Distributions child = (IOService *) connection->getChildEntry(gIOPowerPlane);
1030*c54f35caSApple OSS Distributions
1031*c54f35caSApple OSS Distributions if (child && inPlane(gIOPowerPlane)) {
1032*c54f35caSApple OSS Distributions if ((this != rootDomain) && child->getProperty("IOPMStrictTreeOrder")) {
1033*c54f35caSApple OSS Distributions PM_LOG1("%s: strict PM order enforced\n", getName());
1034*c54f35caSApple OSS Distributions fStrictTreeOrder = true;
1035*c54f35caSApple OSS Distributions }
1036*c54f35caSApple OSS Distributions
1037*c54f35caSApple OSS Distributions if (rootDomain) {
1038*c54f35caSApple OSS Distributions rootDomain->joinAggressiveness( child );
1039*c54f35caSApple OSS Distributions }
1040*c54f35caSApple OSS Distributions } else {
1041*c54f35caSApple OSS Distributions PM_LOG("%s: addPowerChild3 not in power plane\n", getName());
1042*c54f35caSApple OSS Distributions }
1043*c54f35caSApple OSS Distributions
1044*c54f35caSApple OSS Distributions connection->release();
1045*c54f35caSApple OSS Distributions }
1046*c54f35caSApple OSS Distributions
1047*c54f35caSApple OSS Distributions #ifndef __LP64__
1048*c54f35caSApple OSS Distributions //*********************************************************************************
1049*c54f35caSApple OSS Distributions // [deprecated] setPowerParent
1050*c54f35caSApple OSS Distributions //
1051*c54f35caSApple OSS Distributions // Power Management is informing us who our parent is.
1052*c54f35caSApple OSS Distributions // If we have a controlling driver, find out, given our newly-informed
1053*c54f35caSApple OSS Distributions // power domain state, what state it would be in, and then tell it
1054*c54f35caSApple OSS Distributions // to assume that state.
1055*c54f35caSApple OSS Distributions //*********************************************************************************
1056*c54f35caSApple OSS Distributions
1057*c54f35caSApple OSS Distributions IOReturn
setPowerParent(IOPowerConnection * theParent,bool stateKnown,IOPMPowerFlags powerFlags)1058*c54f35caSApple OSS Distributions IOService::setPowerParent(
1059*c54f35caSApple OSS Distributions IOPowerConnection * theParent, bool stateKnown, IOPMPowerFlags powerFlags )
1060*c54f35caSApple OSS Distributions {
1061*c54f35caSApple OSS Distributions return kIOReturnUnsupported;
1062*c54f35caSApple OSS Distributions }
1063*c54f35caSApple OSS Distributions #endif /* !__LP64__ */
1064*c54f35caSApple OSS Distributions
1065*c54f35caSApple OSS Distributions //*********************************************************************************
1066*c54f35caSApple OSS Distributions // [public] removePowerChild
1067*c54f35caSApple OSS Distributions //
1068*c54f35caSApple OSS Distributions // Called on a parent whose child is being removed by PMstop().
1069*c54f35caSApple OSS Distributions //*********************************************************************************
1070*c54f35caSApple OSS Distributions
1071*c54f35caSApple OSS Distributions IOReturn
removePowerChild(IOPowerConnection * theNub)1072*c54f35caSApple OSS Distributions IOService::removePowerChild( IOPowerConnection * theNub )
1073*c54f35caSApple OSS Distributions {
1074*c54f35caSApple OSS Distributions IORegistryEntry * theChild;
1075*c54f35caSApple OSS Distributions
1076*c54f35caSApple OSS Distributions PM_ASSERT_IN_GATE();
1077*c54f35caSApple OSS Distributions OUR_PMLog( kPMLogRemoveChild, 0, 0 );
1078*c54f35caSApple OSS Distributions
1079*c54f35caSApple OSS Distributions theNub->retain();
1080*c54f35caSApple OSS Distributions
1081*c54f35caSApple OSS Distributions // detach nub from child
1082*c54f35caSApple OSS Distributions theChild = theNub->copyChildEntry(gIOPowerPlane);
1083*c54f35caSApple OSS Distributions if (theChild) {
1084*c54f35caSApple OSS Distributions theNub->detachFromChild(theChild, gIOPowerPlane);
1085*c54f35caSApple OSS Distributions theChild->release();
1086*c54f35caSApple OSS Distributions }
1087*c54f35caSApple OSS Distributions // detach from the nub
1088*c54f35caSApple OSS Distributions detachFromChild(theNub, gIOPowerPlane);
1089*c54f35caSApple OSS Distributions
1090*c54f35caSApple OSS Distributions // Are we awaiting an ack from this child?
1091*c54f35caSApple OSS Distributions if (theNub->getAwaitingAck()) {
1092*c54f35caSApple OSS Distributions // yes, pretend we got one
1093*c54f35caSApple OSS Distributions theNub->setAwaitingAck(false);
1094*c54f35caSApple OSS Distributions if (fHeadNotePendingAcks != 0) {
1095*c54f35caSApple OSS Distributions // that's one fewer ack to worry about
1096*c54f35caSApple OSS Distributions fHeadNotePendingAcks--;
1097*c54f35caSApple OSS Distributions
1098*c54f35caSApple OSS Distributions // is that the last?
1099*c54f35caSApple OSS Distributions if (fHeadNotePendingAcks == 0) {
1100*c54f35caSApple OSS Distributions stop_ack_timer();
1101*c54f35caSApple OSS Distributions getPMRootDomain()->reset_watchdog_timer(this, 0);
1102*c54f35caSApple OSS Distributions
1103*c54f35caSApple OSS Distributions // This parent may have a request in the work queue that is
1104*c54f35caSApple OSS Distributions // blocked on fHeadNotePendingAcks=0. And removePowerChild()
1105*c54f35caSApple OSS Distributions // is called while executing the child's PMstop request so they
1106*c54f35caSApple OSS Distributions // can occur simultaneously. IOPMWorkQueue::checkForWork() must
1107*c54f35caSApple OSS Distributions // restart and check all request queues again.
1108*c54f35caSApple OSS Distributions
1109*c54f35caSApple OSS Distributions gIOPMWorkQueue->incrementProducerCount();
1110*c54f35caSApple OSS Distributions }
1111*c54f35caSApple OSS Distributions }
1112*c54f35caSApple OSS Distributions }
1113*c54f35caSApple OSS Distributions
1114*c54f35caSApple OSS Distributions theNub->release();
1115*c54f35caSApple OSS Distributions
1116*c54f35caSApple OSS Distributions // A child has gone away, re-scan children desires and clamp bits.
1117*c54f35caSApple OSS Distributions // The fPendingAdjustPowerRequest helps to reduce redundant parent work.
1118*c54f35caSApple OSS Distributions
1119*c54f35caSApple OSS Distributions if (!fAdjustPowerScheduled) {
1120*c54f35caSApple OSS Distributions IOPMRequest * request;
1121*c54f35caSApple OSS Distributions request = acquirePMRequest( this, kIOPMRequestTypeAdjustPowerState );
1122*c54f35caSApple OSS Distributions if (request) {
1123*c54f35caSApple OSS Distributions submitPMRequest( request );
1124*c54f35caSApple OSS Distributions fAdjustPowerScheduled = true;
1125*c54f35caSApple OSS Distributions }
1126*c54f35caSApple OSS Distributions }
1127*c54f35caSApple OSS Distributions
1128*c54f35caSApple OSS Distributions return IOPMNoErr;
1129*c54f35caSApple OSS Distributions }
1130*c54f35caSApple OSS Distributions
1131*c54f35caSApple OSS Distributions //*********************************************************************************
1132*c54f35caSApple OSS Distributions // [public] registerPowerDriver
1133*c54f35caSApple OSS Distributions //
1134*c54f35caSApple OSS Distributions // A driver has called us volunteering to control power to our device.
1135*c54f35caSApple OSS Distributions //*********************************************************************************
1136*c54f35caSApple OSS Distributions
1137*c54f35caSApple OSS Distributions IOReturn
registerPowerDriver(IOService * powerDriver,IOPMPowerState * powerStates,unsigned long numberOfStates)1138*c54f35caSApple OSS Distributions IOService::registerPowerDriver(
1139*c54f35caSApple OSS Distributions IOService * powerDriver,
1140*c54f35caSApple OSS Distributions IOPMPowerState * powerStates,
1141*c54f35caSApple OSS Distributions unsigned long numberOfStates )
1142*c54f35caSApple OSS Distributions {
1143*c54f35caSApple OSS Distributions IOPMRequest * request;
1144*c54f35caSApple OSS Distributions IOPMPSEntry * powerStatesCopy = NULL;
1145*c54f35caSApple OSS Distributions IOPMPowerStateIndex stateOrder;
1146*c54f35caSApple OSS Distributions IOReturn error = kIOReturnSuccess;
1147*c54f35caSApple OSS Distributions
1148*c54f35caSApple OSS Distributions if (!initialized) {
1149*c54f35caSApple OSS Distributions return IOPMNotYetInitialized;
1150*c54f35caSApple OSS Distributions }
1151*c54f35caSApple OSS Distributions
1152*c54f35caSApple OSS Distributions if (!powerStates || (numberOfStates < 2)) {
1153*c54f35caSApple OSS Distributions OUR_PMLog(kPMLogControllingDriverErr5, numberOfStates, 0);
1154*c54f35caSApple OSS Distributions return kIOReturnBadArgument;
1155*c54f35caSApple OSS Distributions }
1156*c54f35caSApple OSS Distributions
1157*c54f35caSApple OSS Distributions if (!powerDriver || !powerDriver->initialized) {
1158*c54f35caSApple OSS Distributions OUR_PMLog(kPMLogControllingDriverErr4, 0, 0);
1159*c54f35caSApple OSS Distributions return kIOReturnBadArgument;
1160*c54f35caSApple OSS Distributions }
1161*c54f35caSApple OSS Distributions
1162*c54f35caSApple OSS Distributions if (powerStates[0].version > kIOPMPowerStateVersion2) {
1163*c54f35caSApple OSS Distributions OUR_PMLog(kPMLogControllingDriverErr1, powerStates[0].version, 0);
1164*c54f35caSApple OSS Distributions return kIOReturnBadArgument;
1165*c54f35caSApple OSS Distributions }
1166*c54f35caSApple OSS Distributions
1167*c54f35caSApple OSS Distributions do {
1168*c54f35caSApple OSS Distributions // Make a copy of the supplied power state array.
1169*c54f35caSApple OSS Distributions powerStatesCopy = IONewData(IOPMPSEntry, numberOfStates);
1170*c54f35caSApple OSS Distributions if (!powerStatesCopy) {
1171*c54f35caSApple OSS Distributions error = kIOReturnNoMemory;
1172*c54f35caSApple OSS Distributions break;
1173*c54f35caSApple OSS Distributions }
1174*c54f35caSApple OSS Distributions
1175*c54f35caSApple OSS Distributions // Initialize to bogus values
1176*c54f35caSApple OSS Distributions for (IOPMPowerStateIndex i = 0; i < numberOfStates; i++) {
1177*c54f35caSApple OSS Distributions powerStatesCopy[i].stateOrderToIndex = kIOPMPowerStateMax;
1178*c54f35caSApple OSS Distributions }
1179*c54f35caSApple OSS Distributions
1180*c54f35caSApple OSS Distributions for (uint32_t i = 0; i < numberOfStates; i++) {
1181*c54f35caSApple OSS Distributions powerStatesCopy[i].capabilityFlags = powerStates[i].capabilityFlags;
1182*c54f35caSApple OSS Distributions powerStatesCopy[i].outputPowerFlags = powerStates[i].outputPowerCharacter;
1183*c54f35caSApple OSS Distributions powerStatesCopy[i].inputPowerFlags = powerStates[i].inputPowerRequirement;
1184*c54f35caSApple OSS Distributions powerStatesCopy[i].staticPower = powerStates[i].staticPower;
1185*c54f35caSApple OSS Distributions #if USE_SETTLE_TIMER
1186*c54f35caSApple OSS Distributions powerStatesCopy[i].settleUpTime = powerStates[i].settleUpTime;
1187*c54f35caSApple OSS Distributions powerStatesCopy[i].settleDownTime = powerStates[i].settleDownTime;
1188*c54f35caSApple OSS Distributions #endif
1189*c54f35caSApple OSS Distributions if (powerStates[i].version >= kIOPMPowerStateVersion2) {
1190*c54f35caSApple OSS Distributions stateOrder = powerStates[i].stateOrder;
1191*c54f35caSApple OSS Distributions } else {
1192*c54f35caSApple OSS Distributions stateOrder = i;
1193*c54f35caSApple OSS Distributions }
1194*c54f35caSApple OSS Distributions
1195*c54f35caSApple OSS Distributions if (stateOrder < numberOfStates) {
1196*c54f35caSApple OSS Distributions powerStatesCopy[i].stateOrder = stateOrder;
1197*c54f35caSApple OSS Distributions powerStatesCopy[stateOrder].stateOrderToIndex = i;
1198*c54f35caSApple OSS Distributions }
1199*c54f35caSApple OSS Distributions }
1200*c54f35caSApple OSS Distributions
1201*c54f35caSApple OSS Distributions for (IOPMPowerStateIndex i = 0; i < numberOfStates; i++) {
1202*c54f35caSApple OSS Distributions if (powerStatesCopy[i].stateOrderToIndex == kIOPMPowerStateMax) {
1203*c54f35caSApple OSS Distributions // power state order missing
1204*c54f35caSApple OSS Distributions error = kIOReturnBadArgument;
1205*c54f35caSApple OSS Distributions break;
1206*c54f35caSApple OSS Distributions }
1207*c54f35caSApple OSS Distributions }
1208*c54f35caSApple OSS Distributions if (kIOReturnSuccess != error) {
1209*c54f35caSApple OSS Distributions break;
1210*c54f35caSApple OSS Distributions }
1211*c54f35caSApple OSS Distributions
1212*c54f35caSApple OSS Distributions request = acquirePMRequest( this, kIOPMRequestTypeRegisterPowerDriver );
1213*c54f35caSApple OSS Distributions if (!request) {
1214*c54f35caSApple OSS Distributions error = kIOReturnNoMemory;
1215*c54f35caSApple OSS Distributions break;
1216*c54f35caSApple OSS Distributions }
1217*c54f35caSApple OSS Distributions
1218*c54f35caSApple OSS Distributions powerDriver->retain();
1219*c54f35caSApple OSS Distributions request->fArg0 = (void *) powerDriver;
1220*c54f35caSApple OSS Distributions request->fArg1 = (void *) powerStatesCopy;
1221*c54f35caSApple OSS Distributions request->fArg2 = (void *) numberOfStates;
1222*c54f35caSApple OSS Distributions
1223*c54f35caSApple OSS Distributions submitPMRequest( request );
1224*c54f35caSApple OSS Distributions return kIOReturnSuccess;
1225*c54f35caSApple OSS Distributions }while (false);
1226*c54f35caSApple OSS Distributions
1227*c54f35caSApple OSS Distributions if (powerStatesCopy) {
1228*c54f35caSApple OSS Distributions IODeleteData(powerStatesCopy, IOPMPSEntry, numberOfStates);
1229*c54f35caSApple OSS Distributions }
1230*c54f35caSApple OSS Distributions
1231*c54f35caSApple OSS Distributions return error;
1232*c54f35caSApple OSS Distributions }
1233*c54f35caSApple OSS Distributions
1234*c54f35caSApple OSS Distributions //*********************************************************************************
1235*c54f35caSApple OSS Distributions // [private] handleRegisterPowerDriver
1236*c54f35caSApple OSS Distributions //*********************************************************************************
1237*c54f35caSApple OSS Distributions
1238*c54f35caSApple OSS Distributions void
handleRegisterPowerDriver(IOPMRequest * request)1239*c54f35caSApple OSS Distributions IOService::handleRegisterPowerDriver( IOPMRequest * request )
1240*c54f35caSApple OSS Distributions {
1241*c54f35caSApple OSS Distributions IOService * powerDriver = (IOService *) request->fArg0;
1242*c54f35caSApple OSS Distributions IOPMPSEntry * powerStates = (IOPMPSEntry *) request->fArg1;
1243*c54f35caSApple OSS Distributions IOPMPowerStateIndex numberOfStates = (IOPMPowerStateIndex) request->fArg2;
1244*c54f35caSApple OSS Distributions IOPMPowerStateIndex i, stateIndex;
1245*c54f35caSApple OSS Distributions IOPMPowerStateIndex lowestPowerState;
1246*c54f35caSApple OSS Distributions IOService * root;
1247*c54f35caSApple OSS Distributions OSIterator * iter;
1248*c54f35caSApple OSS Distributions
1249*c54f35caSApple OSS Distributions PM_ASSERT_IN_GATE();
1250*c54f35caSApple OSS Distributions assert(powerStates);
1251*c54f35caSApple OSS Distributions assert(powerDriver);
1252*c54f35caSApple OSS Distributions assert(numberOfStates > 1);
1253*c54f35caSApple OSS Distributions
1254*c54f35caSApple OSS Distributions if (!fNumberOfPowerStates) {
1255*c54f35caSApple OSS Distributions OUR_PMLog(kPMLogControllingDriver, numberOfStates, kIOPMPowerStateVersion1);
1256*c54f35caSApple OSS Distributions
1257*c54f35caSApple OSS Distributions fPowerStates = powerStates;
1258*c54f35caSApple OSS Distributions fNumberOfPowerStates = numberOfStates;
1259*c54f35caSApple OSS Distributions fControllingDriver = powerDriver;
1260*c54f35caSApple OSS Distributions fCurrentCapabilityFlags = fPowerStates[0].capabilityFlags;
1261*c54f35caSApple OSS Distributions
1262*c54f35caSApple OSS Distributions lowestPowerState = fPowerStates[0].stateOrderToIndex;
1263*c54f35caSApple OSS Distributions fHighestPowerState = fPowerStates[numberOfStates - 1].stateOrderToIndex;
1264*c54f35caSApple OSS Distributions
1265*c54f35caSApple OSS Distributions {
1266*c54f35caSApple OSS Distributions uint32_t aotFlags;
1267*c54f35caSApple OSS Distributions IOService * service;
1268*c54f35caSApple OSS Distributions OSObject * object;
1269*c54f35caSApple OSS Distributions OSData * data;
1270*c54f35caSApple OSS Distributions
1271*c54f35caSApple OSS Distributions // Disallow kIOPMAOTPower states unless device tree enabled
1272*c54f35caSApple OSS Distributions
1273*c54f35caSApple OSS Distributions aotFlags = 0;
1274*c54f35caSApple OSS Distributions service = this;
1275*c54f35caSApple OSS Distributions while (service && !service->inPlane(gIODTPlane)) {
1276*c54f35caSApple OSS Distributions service = service->getProvider();
1277*c54f35caSApple OSS Distributions }
1278*c54f35caSApple OSS Distributions if (service) {
1279*c54f35caSApple OSS Distributions object = service->copyProperty(kIOPMAOTPowerKey, gIODTPlane);
1280*c54f35caSApple OSS Distributions data = OSDynamicCast(OSData, object);
1281*c54f35caSApple OSS Distributions if (data && (data->getLength() >= sizeof(uint32_t))) {
1282*c54f35caSApple OSS Distributions aotFlags = ((uint32_t *)data->getBytesNoCopy())[0];
1283*c54f35caSApple OSS Distributions }
1284*c54f35caSApple OSS Distributions OSSafeReleaseNULL(object);
1285*c54f35caSApple OSS Distributions }
1286*c54f35caSApple OSS Distributions if (!aotFlags) {
1287*c54f35caSApple OSS Distributions for (i = 0; i < numberOfStates; i++) {
1288*c54f35caSApple OSS Distributions if (kIOPMAOTPower & fPowerStates[i].inputPowerFlags) {
1289*c54f35caSApple OSS Distributions fPowerStates[i].inputPowerFlags = 0xFFFFFFFF;
1290*c54f35caSApple OSS Distributions fPowerStates[i].capabilityFlags = 0;
1291*c54f35caSApple OSS Distributions fPowerStates[i].outputPowerFlags = 0;
1292*c54f35caSApple OSS Distributions }
1293*c54f35caSApple OSS Distributions }
1294*c54f35caSApple OSS Distributions }
1295*c54f35caSApple OSS Distributions }
1296*c54f35caSApple OSS Distributions
1297*c54f35caSApple OSS Distributions // OR'in all the output power flags
1298*c54f35caSApple OSS Distributions fMergedOutputPowerFlags = 0;
1299*c54f35caSApple OSS Distributions fDeviceUsablePowerState = lowestPowerState;
1300*c54f35caSApple OSS Distributions for (i = 0; i < numberOfStates; i++) {
1301*c54f35caSApple OSS Distributions fMergedOutputPowerFlags |= fPowerStates[i].outputPowerFlags;
1302*c54f35caSApple OSS Distributions
1303*c54f35caSApple OSS Distributions stateIndex = fPowerStates[i].stateOrderToIndex;
1304*c54f35caSApple OSS Distributions assert(stateIndex < numberOfStates);
1305*c54f35caSApple OSS Distributions if ((fDeviceUsablePowerState == lowestPowerState) &&
1306*c54f35caSApple OSS Distributions (fPowerStates[stateIndex].capabilityFlags & IOPMDeviceUsable)) {
1307*c54f35caSApple OSS Distributions // The minimum power state that the device is usable
1308*c54f35caSApple OSS Distributions fDeviceUsablePowerState = stateIndex;
1309*c54f35caSApple OSS Distributions }
1310*c54f35caSApple OSS Distributions }
1311*c54f35caSApple OSS Distributions
1312*c54f35caSApple OSS Distributions // Register powerDriver as interested, unless already done.
1313*c54f35caSApple OSS Distributions // We don't want to register the default implementation since
1314*c54f35caSApple OSS Distributions // it does nothing. One ramification of not always registering
1315*c54f35caSApple OSS Distributions // is the one fewer retain count held.
1316*c54f35caSApple OSS Distributions
1317*c54f35caSApple OSS Distributions root = getPlatform()->getProvider();
1318*c54f35caSApple OSS Distributions assert(root);
1319*c54f35caSApple OSS Distributions if (!root ||
1320*c54f35caSApple OSS Distributions ((OSMemberFunctionCast(void (*)(void),
1321*c54f35caSApple OSS Distributions root, &IOService::powerStateDidChangeTo)) !=
1322*c54f35caSApple OSS Distributions ((OSMemberFunctionCast(void (*)(void),
1323*c54f35caSApple OSS Distributions this, &IOService::powerStateDidChangeTo)))) ||
1324*c54f35caSApple OSS Distributions ((OSMemberFunctionCast(void (*)(void),
1325*c54f35caSApple OSS Distributions root, &IOService::powerStateWillChangeTo)) !=
1326*c54f35caSApple OSS Distributions ((OSMemberFunctionCast(void (*)(void),
1327*c54f35caSApple OSS Distributions this, &IOService::powerStateWillChangeTo))))) {
1328*c54f35caSApple OSS Distributions if (fInterestedDrivers->findItem(powerDriver) == NULL) {
1329*c54f35caSApple OSS Distributions PM_LOCK();
1330*c54f35caSApple OSS Distributions fInterestedDrivers->appendNewInformee(powerDriver);
1331*c54f35caSApple OSS Distributions PM_UNLOCK();
1332*c54f35caSApple OSS Distributions }
1333*c54f35caSApple OSS Distributions }
1334*c54f35caSApple OSS Distributions
1335*c54f35caSApple OSS Distributions // Examine all existing power clients and perform limit check.
1336*c54f35caSApple OSS Distributions
1337*c54f35caSApple OSS Distributions if (fPowerClients &&
1338*c54f35caSApple OSS Distributions (iter = OSCollectionIterator::withCollection(fPowerClients))) {
1339*c54f35caSApple OSS Distributions const OSSymbol * client;
1340*c54f35caSApple OSS Distributions while ((client = (const OSSymbol *) iter->getNextObject())) {
1341*c54f35caSApple OSS Distributions IOPMPowerStateIndex powerState = getPowerStateForClient(client);
1342*c54f35caSApple OSS Distributions if (powerState >= numberOfStates) {
1343*c54f35caSApple OSS Distributions updatePowerClient(client, fHighestPowerState);
1344*c54f35caSApple OSS Distributions }
1345*c54f35caSApple OSS Distributions }
1346*c54f35caSApple OSS Distributions iter->release();
1347*c54f35caSApple OSS Distributions }
1348*c54f35caSApple OSS Distributions
1349*c54f35caSApple OSS Distributions // Populate IOPMActions for a few special services
1350*c54f35caSApple OSS Distributions getPMRootDomain()->tagPowerPlaneService(this, &fPMActions, fNumberOfPowerStates - 1);
1351*c54f35caSApple OSS Distributions
1352*c54f35caSApple OSS Distributions if (inPlane(gIOPowerPlane) && fParentsKnowState) {
1353*c54f35caSApple OSS Distributions IOPMPowerStateIndex tempDesire;
1354*c54f35caSApple OSS Distributions fMaxPowerState = fControllingDriver->maxCapabilityForDomainState(fParentsCurrentPowerFlags);
1355*c54f35caSApple OSS Distributions // initially change into the state we are already in
1356*c54f35caSApple OSS Distributions tempDesire = fControllingDriver->initialPowerStateForDomainState(fParentsCurrentPowerFlags);
1357*c54f35caSApple OSS Distributions adjustPowerState(tempDesire);
1358*c54f35caSApple OSS Distributions }
1359*c54f35caSApple OSS Distributions } else {
1360*c54f35caSApple OSS Distributions OUR_PMLog(kPMLogControllingDriverErr2, numberOfStates, 0);
1361*c54f35caSApple OSS Distributions IODeleteData(powerStates, IOPMPSEntry, numberOfStates);
1362*c54f35caSApple OSS Distributions }
1363*c54f35caSApple OSS Distributions
1364*c54f35caSApple OSS Distributions powerDriver->release();
1365*c54f35caSApple OSS Distributions }
1366*c54f35caSApple OSS Distributions
1367*c54f35caSApple OSS Distributions //*********************************************************************************
1368*c54f35caSApple OSS Distributions // [public] registerInterestedDriver
1369*c54f35caSApple OSS Distributions //
1370*c54f35caSApple OSS Distributions // Add the caller to our list of interested drivers and return our current
1371*c54f35caSApple OSS Distributions // power state. If we don't have a power-controlling driver yet, we will
1372*c54f35caSApple OSS Distributions // call this interested driver again later when we do get a driver and find
1373*c54f35caSApple OSS Distributions // out what the current power state of the device is.
1374*c54f35caSApple OSS Distributions //*********************************************************************************
1375*c54f35caSApple OSS Distributions
1376*c54f35caSApple OSS Distributions IOPMPowerFlags
registerInterestedDriver(IOService * driver)1377*c54f35caSApple OSS Distributions IOService::registerInterestedDriver( IOService * driver )
1378*c54f35caSApple OSS Distributions {
1379*c54f35caSApple OSS Distributions IOPMRequest * request;
1380*c54f35caSApple OSS Distributions bool signal;
1381*c54f35caSApple OSS Distributions
1382*c54f35caSApple OSS Distributions if (!driver || !initialized || !fInterestedDrivers) {
1383*c54f35caSApple OSS Distributions return 0;
1384*c54f35caSApple OSS Distributions }
1385*c54f35caSApple OSS Distributions
1386*c54f35caSApple OSS Distributions PM_LOCK();
1387*c54f35caSApple OSS Distributions signal = (!fInsertInterestSet && !fRemoveInterestSet);
1388*c54f35caSApple OSS Distributions if (fInsertInterestSet == NULL) {
1389*c54f35caSApple OSS Distributions fInsertInterestSet = OSSet::withCapacity(4);
1390*c54f35caSApple OSS Distributions }
1391*c54f35caSApple OSS Distributions if (fInsertInterestSet) {
1392*c54f35caSApple OSS Distributions fInsertInterestSet->setObject(driver);
1393*c54f35caSApple OSS Distributions if (fRemoveInterestSet) {
1394*c54f35caSApple OSS Distributions fRemoveInterestSet->removeObject(driver);
1395*c54f35caSApple OSS Distributions }
1396*c54f35caSApple OSS Distributions }
1397*c54f35caSApple OSS Distributions PM_UNLOCK();
1398*c54f35caSApple OSS Distributions
1399*c54f35caSApple OSS Distributions if (signal) {
1400*c54f35caSApple OSS Distributions request = acquirePMRequest( this, kIOPMRequestTypeInterestChanged );
1401*c54f35caSApple OSS Distributions if (request) {
1402*c54f35caSApple OSS Distributions submitPMRequest( request );
1403*c54f35caSApple OSS Distributions }
1404*c54f35caSApple OSS Distributions }
1405*c54f35caSApple OSS Distributions
1406*c54f35caSApple OSS Distributions // This return value cannot be trusted, but return a value
1407*c54f35caSApple OSS Distributions // for those clients that care.
1408*c54f35caSApple OSS Distributions
1409*c54f35caSApple OSS Distributions OUR_PMLog(kPMLogInterestedDriver, kIOPMDeviceUsable, 2);
1410*c54f35caSApple OSS Distributions return kIOPMDeviceUsable;
1411*c54f35caSApple OSS Distributions }
1412*c54f35caSApple OSS Distributions
1413*c54f35caSApple OSS Distributions //*********************************************************************************
1414*c54f35caSApple OSS Distributions // [public] deRegisterInterestedDriver
1415*c54f35caSApple OSS Distributions //*********************************************************************************
1416*c54f35caSApple OSS Distributions
1417*c54f35caSApple OSS Distributions IOReturn
deRegisterInterestedDriver(IOService * driver)1418*c54f35caSApple OSS Distributions IOService::deRegisterInterestedDriver( IOService * driver )
1419*c54f35caSApple OSS Distributions {
1420*c54f35caSApple OSS Distributions IOPMinformee * item;
1421*c54f35caSApple OSS Distributions IOPMRequest * request;
1422*c54f35caSApple OSS Distributions bool signal;
1423*c54f35caSApple OSS Distributions
1424*c54f35caSApple OSS Distributions if (!driver) {
1425*c54f35caSApple OSS Distributions return kIOReturnBadArgument;
1426*c54f35caSApple OSS Distributions }
1427*c54f35caSApple OSS Distributions if (!initialized || !fInterestedDrivers) {
1428*c54f35caSApple OSS Distributions return IOPMNotPowerManaged;
1429*c54f35caSApple OSS Distributions }
1430*c54f35caSApple OSS Distributions
1431*c54f35caSApple OSS Distributions PM_LOCK();
1432*c54f35caSApple OSS Distributions if (fInsertInterestSet) {
1433*c54f35caSApple OSS Distributions fInsertInterestSet->removeObject(driver);
1434*c54f35caSApple OSS Distributions }
1435*c54f35caSApple OSS Distributions
1436*c54f35caSApple OSS Distributions item = fInterestedDrivers->findItem(driver);
1437*c54f35caSApple OSS Distributions if (!item) {
1438*c54f35caSApple OSS Distributions PM_UNLOCK();
1439*c54f35caSApple OSS Distributions return kIOReturnNotFound;
1440*c54f35caSApple OSS Distributions }
1441*c54f35caSApple OSS Distributions
1442*c54f35caSApple OSS Distributions signal = (!fRemoveInterestSet && !fInsertInterestSet);
1443*c54f35caSApple OSS Distributions if (fRemoveInterestSet == NULL) {
1444*c54f35caSApple OSS Distributions fRemoveInterestSet = OSSet::withCapacity(4);
1445*c54f35caSApple OSS Distributions }
1446*c54f35caSApple OSS Distributions if (fRemoveInterestSet) {
1447*c54f35caSApple OSS Distributions fRemoveInterestSet->setObject(driver);
1448*c54f35caSApple OSS Distributions if (item->active) {
1449*c54f35caSApple OSS Distributions item->active = false;
1450*c54f35caSApple OSS Distributions waitForPMDriverCall( driver );
1451*c54f35caSApple OSS Distributions }
1452*c54f35caSApple OSS Distributions }
1453*c54f35caSApple OSS Distributions PM_UNLOCK();
1454*c54f35caSApple OSS Distributions
1455*c54f35caSApple OSS Distributions if (signal) {
1456*c54f35caSApple OSS Distributions request = acquirePMRequest( this, kIOPMRequestTypeInterestChanged );
1457*c54f35caSApple OSS Distributions if (request) {
1458*c54f35caSApple OSS Distributions submitPMRequest( request );
1459*c54f35caSApple OSS Distributions }
1460*c54f35caSApple OSS Distributions }
1461*c54f35caSApple OSS Distributions
1462*c54f35caSApple OSS Distributions return IOPMNoErr;
1463*c54f35caSApple OSS Distributions }
1464*c54f35caSApple OSS Distributions
1465*c54f35caSApple OSS Distributions //*********************************************************************************
1466*c54f35caSApple OSS Distributions // [private] handleInterestChanged
1467*c54f35caSApple OSS Distributions //
1468*c54f35caSApple OSS Distributions // Handle interest added or removed.
1469*c54f35caSApple OSS Distributions //*********************************************************************************
1470*c54f35caSApple OSS Distributions
1471*c54f35caSApple OSS Distributions void
handleInterestChanged(IOPMRequest * request)1472*c54f35caSApple OSS Distributions IOService::handleInterestChanged( IOPMRequest * request )
1473*c54f35caSApple OSS Distributions {
1474*c54f35caSApple OSS Distributions IOService * driver;
1475*c54f35caSApple OSS Distributions IOPMinformee * informee;
1476*c54f35caSApple OSS Distributions IOPMinformeeList * list = fInterestedDrivers;
1477*c54f35caSApple OSS Distributions
1478*c54f35caSApple OSS Distributions PM_LOCK();
1479*c54f35caSApple OSS Distributions
1480*c54f35caSApple OSS Distributions if (fInsertInterestSet) {
1481*c54f35caSApple OSS Distributions while ((driver = (IOService *) fInsertInterestSet->getAnyObject())) {
1482*c54f35caSApple OSS Distributions if (list->findItem(driver) == NULL) {
1483*c54f35caSApple OSS Distributions list->appendNewInformee(driver);
1484*c54f35caSApple OSS Distributions }
1485*c54f35caSApple OSS Distributions fInsertInterestSet->removeObject(driver);
1486*c54f35caSApple OSS Distributions }
1487*c54f35caSApple OSS Distributions fInsertInterestSet->release();
1488*c54f35caSApple OSS Distributions fInsertInterestSet = NULL;
1489*c54f35caSApple OSS Distributions }
1490*c54f35caSApple OSS Distributions
1491*c54f35caSApple OSS Distributions if (fRemoveInterestSet) {
1492*c54f35caSApple OSS Distributions while ((driver = (IOService *) fRemoveInterestSet->getAnyObject())) {
1493*c54f35caSApple OSS Distributions informee = list->findItem(driver);
1494*c54f35caSApple OSS Distributions if (informee) {
1495*c54f35caSApple OSS Distributions // Clean-up async interest acknowledgement
1496*c54f35caSApple OSS Distributions if (fHeadNotePendingAcks && informee->timer) {
1497*c54f35caSApple OSS Distributions informee->timer = 0;
1498*c54f35caSApple OSS Distributions fHeadNotePendingAcks--;
1499*c54f35caSApple OSS Distributions }
1500*c54f35caSApple OSS Distributions list->removeFromList(driver);
1501*c54f35caSApple OSS Distributions }
1502*c54f35caSApple OSS Distributions fRemoveInterestSet->removeObject(driver);
1503*c54f35caSApple OSS Distributions }
1504*c54f35caSApple OSS Distributions fRemoveInterestSet->release();
1505*c54f35caSApple OSS Distributions fRemoveInterestSet = NULL;
1506*c54f35caSApple OSS Distributions }
1507*c54f35caSApple OSS Distributions
1508*c54f35caSApple OSS Distributions PM_UNLOCK();
1509*c54f35caSApple OSS Distributions }
1510*c54f35caSApple OSS Distributions
1511*c54f35caSApple OSS Distributions //*********************************************************************************
1512*c54f35caSApple OSS Distributions // [public] acknowledgePowerChange
1513*c54f35caSApple OSS Distributions //
1514*c54f35caSApple OSS Distributions // After we notified one of the interested drivers or a power-domain child
1515*c54f35caSApple OSS Distributions // of an impending change in power, it has called to say it is now
1516*c54f35caSApple OSS Distributions // prepared for the change. If this object is the last to
1517*c54f35caSApple OSS Distributions // acknowledge this change, we take whatever action we have been waiting
1518*c54f35caSApple OSS Distributions // for.
1519*c54f35caSApple OSS Distributions // That may include acknowledging to our parent. In this case, we do it
1520*c54f35caSApple OSS Distributions // last of all to insure that this doesn't cause the parent to call us some-
1521*c54f35caSApple OSS Distributions // where else and alter data we are relying on here (like the very existance
1522*c54f35caSApple OSS Distributions // of a "current change note".)
1523*c54f35caSApple OSS Distributions //*********************************************************************************
1524*c54f35caSApple OSS Distributions
1525*c54f35caSApple OSS Distributions IOReturn
acknowledgePowerChange(IOService * whichObject)1526*c54f35caSApple OSS Distributions IOService::acknowledgePowerChange( IOService * whichObject )
1527*c54f35caSApple OSS Distributions {
1528*c54f35caSApple OSS Distributions IOPMRequest * request;
1529*c54f35caSApple OSS Distributions
1530*c54f35caSApple OSS Distributions if (!initialized) {
1531*c54f35caSApple OSS Distributions return IOPMNotYetInitialized;
1532*c54f35caSApple OSS Distributions }
1533*c54f35caSApple OSS Distributions if (!whichObject) {
1534*c54f35caSApple OSS Distributions return kIOReturnBadArgument;
1535*c54f35caSApple OSS Distributions }
1536*c54f35caSApple OSS Distributions
1537*c54f35caSApple OSS Distributions request = acquirePMRequest( this, kIOPMRequestTypeAckPowerChange );
1538*c54f35caSApple OSS Distributions if (!request) {
1539*c54f35caSApple OSS Distributions return kIOReturnNoMemory;
1540*c54f35caSApple OSS Distributions }
1541*c54f35caSApple OSS Distributions
1542*c54f35caSApple OSS Distributions whichObject->retain();
1543*c54f35caSApple OSS Distributions request->fArg0 = whichObject;
1544*c54f35caSApple OSS Distributions
1545*c54f35caSApple OSS Distributions submitPMRequest( request );
1546*c54f35caSApple OSS Distributions return IOPMNoErr;
1547*c54f35caSApple OSS Distributions }
1548*c54f35caSApple OSS Distributions
1549*c54f35caSApple OSS Distributions //*********************************************************************************
1550*c54f35caSApple OSS Distributions // [private] handleAcknowledgePowerChange
1551*c54f35caSApple OSS Distributions //*********************************************************************************
1552*c54f35caSApple OSS Distributions
1553*c54f35caSApple OSS Distributions bool
handleAcknowledgePowerChange(IOPMRequest * request)1554*c54f35caSApple OSS Distributions IOService::handleAcknowledgePowerChange( IOPMRequest * request )
1555*c54f35caSApple OSS Distributions {
1556*c54f35caSApple OSS Distributions IOPMinformee * informee;
1557*c54f35caSApple OSS Distributions IOPMPowerStateIndex childPower = kIOPMUnknown;
1558*c54f35caSApple OSS Distributions IOService * theChild;
1559*c54f35caSApple OSS Distributions IOService * whichObject;
1560*c54f35caSApple OSS Distributions bool all_acked = false;
1561*c54f35caSApple OSS Distributions
1562*c54f35caSApple OSS Distributions PM_ASSERT_IN_GATE();
1563*c54f35caSApple OSS Distributions whichObject = (IOService *) request->fArg0;
1564*c54f35caSApple OSS Distributions assert(whichObject);
1565*c54f35caSApple OSS Distributions
1566*c54f35caSApple OSS Distributions // one of our interested drivers?
1567*c54f35caSApple OSS Distributions informee = fInterestedDrivers->findItem( whichObject );
1568*c54f35caSApple OSS Distributions if (informee == NULL) {
1569*c54f35caSApple OSS Distributions if (!isChild(whichObject, gIOPowerPlane)) {
1570*c54f35caSApple OSS Distributions OUR_PMLog(kPMLogAcknowledgeErr1, 0, 0);
1571*c54f35caSApple OSS Distributions goto no_err;
1572*c54f35caSApple OSS Distributions } else {
1573*c54f35caSApple OSS Distributions OUR_PMLog(kPMLogChildAcknowledge, fHeadNotePendingAcks, 0);
1574*c54f35caSApple OSS Distributions }
1575*c54f35caSApple OSS Distributions } else {
1576*c54f35caSApple OSS Distributions OUR_PMLog(kPMLogDriverAcknowledge, fHeadNotePendingAcks, 0);
1577*c54f35caSApple OSS Distributions }
1578*c54f35caSApple OSS Distributions
1579*c54f35caSApple OSS Distributions if (fHeadNotePendingAcks != 0) {
1580*c54f35caSApple OSS Distributions assert(fPowerStates != NULL);
1581*c54f35caSApple OSS Distributions
1582*c54f35caSApple OSS Distributions // yes, make sure we're expecting acks
1583*c54f35caSApple OSS Distributions if (informee != NULL) {
1584*c54f35caSApple OSS Distributions // it's an interested driver
1585*c54f35caSApple OSS Distributions // make sure we're expecting this ack
1586*c54f35caSApple OSS Distributions if (informee->timer != 0) {
1587*c54f35caSApple OSS Distributions SOCD_TRACE_XNU(PM_INFORM_POWER_CHANGE_ACK,
1588*c54f35caSApple OSS Distributions ADDR(informee->whatObject->getMetaClass()),
1589*c54f35caSApple OSS Distributions ADDR(this->getMetaClass()),
1590*c54f35caSApple OSS Distributions PACK_2X32(VALUE(this->getRegistryEntryID()), VALUE(informee->whatObject->getRegistryEntryID())),
1591*c54f35caSApple OSS Distributions PACK_2X32(VALUE(0), VALUE(fDriverCallReason)));
1592*c54f35caSApple OSS Distributions
1593*c54f35caSApple OSS Distributions if (informee->timer > 0) {
1594*c54f35caSApple OSS Distributions uint64_t nsec = computeTimeDeltaNS(&informee->startTime);
1595*c54f35caSApple OSS Distributions if (nsec > gIOPMSetPowerStateLogNS) {
1596*c54f35caSApple OSS Distributions getPMRootDomain()->pmStatsRecordApplicationResponse(
1597*c54f35caSApple OSS Distributions gIOPMStatsDriverPSChangeSlow, informee->whatObject->getName(),
1598*c54f35caSApple OSS Distributions fDriverCallReason, NS_TO_MS(nsec), informee->whatObject->getRegistryEntryID(),
1599*c54f35caSApple OSS Distributions NULL, fHeadNotePowerState, true);
1600*c54f35caSApple OSS Distributions }
1601*c54f35caSApple OSS Distributions }
1602*c54f35caSApple OSS Distributions
1603*c54f35caSApple OSS Distributions // mark it acked
1604*c54f35caSApple OSS Distributions informee->timer = 0;
1605*c54f35caSApple OSS Distributions // that's one fewer to worry about
1606*c54f35caSApple OSS Distributions fHeadNotePendingAcks--;
1607*c54f35caSApple OSS Distributions } else {
1608*c54f35caSApple OSS Distributions // this driver has already acked
1609*c54f35caSApple OSS Distributions OUR_PMLog(kPMLogAcknowledgeErr2, 0, 0);
1610*c54f35caSApple OSS Distributions }
1611*c54f35caSApple OSS Distributions } else {
1612*c54f35caSApple OSS Distributions // it's a child
1613*c54f35caSApple OSS Distributions // make sure we're expecting this ack
1614*c54f35caSApple OSS Distributions if (((IOPowerConnection *)whichObject)->getAwaitingAck()) {
1615*c54f35caSApple OSS Distributions // that's one fewer to worry about
1616*c54f35caSApple OSS Distributions fHeadNotePendingAcks--;
1617*c54f35caSApple OSS Distributions ((IOPowerConnection *)whichObject)->setAwaitingAck(false);
1618*c54f35caSApple OSS Distributions theChild = (IOService *)whichObject->copyChildEntry(gIOPowerPlane);
1619*c54f35caSApple OSS Distributions if (theChild) {
1620*c54f35caSApple OSS Distributions childPower = theChild->currentPowerConsumption();
1621*c54f35caSApple OSS Distributions theChild->release();
1622*c54f35caSApple OSS Distributions }
1623*c54f35caSApple OSS Distributions if (childPower == kIOPMUnknown) {
1624*c54f35caSApple OSS Distributions fHeadNotePowerArrayEntry->staticPower = kIOPMUnknown;
1625*c54f35caSApple OSS Distributions } else {
1626*c54f35caSApple OSS Distributions if (fHeadNotePowerArrayEntry->staticPower != kIOPMUnknown) {
1627*c54f35caSApple OSS Distributions fHeadNotePowerArrayEntry->staticPower += childPower;
1628*c54f35caSApple OSS Distributions }
1629*c54f35caSApple OSS Distributions }
1630*c54f35caSApple OSS Distributions }
1631*c54f35caSApple OSS Distributions }
1632*c54f35caSApple OSS Distributions
1633*c54f35caSApple OSS Distributions if (fHeadNotePendingAcks == 0) {
1634*c54f35caSApple OSS Distributions // yes, stop the timer
1635*c54f35caSApple OSS Distributions stop_ack_timer();
1636*c54f35caSApple OSS Distributions // and now we can continue
1637*c54f35caSApple OSS Distributions all_acked = true;
1638*c54f35caSApple OSS Distributions getPMRootDomain()->reset_watchdog_timer(this, 0);
1639*c54f35caSApple OSS Distributions }
1640*c54f35caSApple OSS Distributions } else {
1641*c54f35caSApple OSS Distributions OUR_PMLog(kPMLogAcknowledgeErr3, 0, 0); // not expecting anybody to ack
1642*c54f35caSApple OSS Distributions }
1643*c54f35caSApple OSS Distributions
1644*c54f35caSApple OSS Distributions no_err:
1645*c54f35caSApple OSS Distributions if (whichObject) {
1646*c54f35caSApple OSS Distributions whichObject->release();
1647*c54f35caSApple OSS Distributions }
1648*c54f35caSApple OSS Distributions
1649*c54f35caSApple OSS Distributions return all_acked;
1650*c54f35caSApple OSS Distributions }
1651*c54f35caSApple OSS Distributions
1652*c54f35caSApple OSS Distributions //*********************************************************************************
1653*c54f35caSApple OSS Distributions // [public] acknowledgeSetPowerState
1654*c54f35caSApple OSS Distributions //
1655*c54f35caSApple OSS Distributions // After we instructed our controlling driver to change power states,
1656*c54f35caSApple OSS Distributions // it has called to say it has finished doing so.
1657*c54f35caSApple OSS Distributions // We continue to process the power state change.
1658*c54f35caSApple OSS Distributions //*********************************************************************************
1659*c54f35caSApple OSS Distributions
1660*c54f35caSApple OSS Distributions IOReturn
acknowledgeSetPowerState(void)1661*c54f35caSApple OSS Distributions IOService::acknowledgeSetPowerState( void )
1662*c54f35caSApple OSS Distributions {
1663*c54f35caSApple OSS Distributions IOPMRequest * request;
1664*c54f35caSApple OSS Distributions
1665*c54f35caSApple OSS Distributions if (!initialized) {
1666*c54f35caSApple OSS Distributions return IOPMNotYetInitialized;
1667*c54f35caSApple OSS Distributions }
1668*c54f35caSApple OSS Distributions
1669*c54f35caSApple OSS Distributions request = acquirePMRequest( this, kIOPMRequestTypeAckSetPowerState );
1670*c54f35caSApple OSS Distributions if (!request) {
1671*c54f35caSApple OSS Distributions return kIOReturnNoMemory;
1672*c54f35caSApple OSS Distributions }
1673*c54f35caSApple OSS Distributions
1674*c54f35caSApple OSS Distributions submitPMRequest( request );
1675*c54f35caSApple OSS Distributions return kIOReturnSuccess;
1676*c54f35caSApple OSS Distributions }
1677*c54f35caSApple OSS Distributions
1678*c54f35caSApple OSS Distributions //*********************************************************************************
1679*c54f35caSApple OSS Distributions // [private] handleAcknowledgeSetPowerState
1680*c54f35caSApple OSS Distributions //*********************************************************************************
1681*c54f35caSApple OSS Distributions
1682*c54f35caSApple OSS Distributions bool
handleAcknowledgeSetPowerState(IOPMRequest * request __unused)1683*c54f35caSApple OSS Distributions IOService::handleAcknowledgeSetPowerState( IOPMRequest * request __unused)
1684*c54f35caSApple OSS Distributions {
1685*c54f35caSApple OSS Distributions const OSMetaClass *controllingDriverMetaClass = NULL;
1686*c54f35caSApple OSS Distributions uint32_t controllingDriverRegistryEntryID = 0;
1687*c54f35caSApple OSS Distributions bool more = false;
1688*c54f35caSApple OSS Distributions bool trace_this_ack = true;
1689*c54f35caSApple OSS Distributions
1690*c54f35caSApple OSS Distributions if (fDriverTimer == -1) {
1691*c54f35caSApple OSS Distributions // driver acked while setPowerState() call is in-flight.
1692*c54f35caSApple OSS Distributions // take this ack, return value from setPowerState() is irrelevant.
1693*c54f35caSApple OSS Distributions OUR_PMLog(kPMLogDriverAcknowledgeSet,
1694*c54f35caSApple OSS Distributions (uintptr_t) this, fDriverTimer);
1695*c54f35caSApple OSS Distributions fDriverTimer = 0;
1696*c54f35caSApple OSS Distributions } else if (fDriverTimer > 0) {
1697*c54f35caSApple OSS Distributions // expected ack, stop the timer
1698*c54f35caSApple OSS Distributions stop_ack_timer();
1699*c54f35caSApple OSS Distributions
1700*c54f35caSApple OSS Distributions getPMRootDomain()->reset_watchdog_timer(this, 0);
1701*c54f35caSApple OSS Distributions
1702*c54f35caSApple OSS Distributions uint64_t nsec = computeTimeDeltaNS(&fDriverCallStartTime);
1703*c54f35caSApple OSS Distributions if (nsec > gIOPMSetPowerStateLogNS) {
1704*c54f35caSApple OSS Distributions getPMRootDomain()->pmStatsRecordApplicationResponse(
1705*c54f35caSApple OSS Distributions gIOPMStatsDriverPSChangeSlow,
1706*c54f35caSApple OSS Distributions fName, kDriverCallSetPowerState, NS_TO_MS(nsec), getRegistryEntryID(),
1707*c54f35caSApple OSS Distributions NULL, fHeadNotePowerState, true);
1708*c54f35caSApple OSS Distributions }
1709*c54f35caSApple OSS Distributions
1710*c54f35caSApple OSS Distributions OUR_PMLog(kPMLogDriverAcknowledgeSet, (uintptr_t) this, fDriverTimer);
1711*c54f35caSApple OSS Distributions fDriverTimer = 0;
1712*c54f35caSApple OSS Distributions more = true;
1713*c54f35caSApple OSS Distributions } else {
1714*c54f35caSApple OSS Distributions // unexpected ack
1715*c54f35caSApple OSS Distributions OUR_PMLog(kPMLogAcknowledgeErr4, (uintptr_t) this, 0);
1716*c54f35caSApple OSS Distributions trace_this_ack = false;
1717*c54f35caSApple OSS Distributions }
1718*c54f35caSApple OSS Distributions
1719*c54f35caSApple OSS Distributions if (trace_this_ack) {
1720*c54f35caSApple OSS Distributions if (fControllingDriver) {
1721*c54f35caSApple OSS Distributions controllingDriverMetaClass = fControllingDriver->getMetaClass();
1722*c54f35caSApple OSS Distributions controllingDriverRegistryEntryID = (uint32_t)fControllingDriver->getRegistryEntryID();
1723*c54f35caSApple OSS Distributions }
1724*c54f35caSApple OSS Distributions
1725*c54f35caSApple OSS Distributions SOCD_TRACE_XNU(PM_SET_POWER_STATE_ACK,
1726*c54f35caSApple OSS Distributions ADDR(controllingDriverMetaClass),
1727*c54f35caSApple OSS Distributions ADDR(this->getMetaClass()),
1728*c54f35caSApple OSS Distributions PACK_2X32(VALUE(this->getRegistryEntryID()), VALUE(controllingDriverRegistryEntryID)),
1729*c54f35caSApple OSS Distributions PACK_2X32(VALUE(fHeadNotePowerState), VALUE(0)));
1730*c54f35caSApple OSS Distributions }
1731*c54f35caSApple OSS Distributions
1732*c54f35caSApple OSS Distributions return more;
1733*c54f35caSApple OSS Distributions }
1734*c54f35caSApple OSS Distributions
1735*c54f35caSApple OSS Distributions //*********************************************************************************
1736*c54f35caSApple OSS Distributions // [private] adjustPowerState
1737*c54f35caSApple OSS Distributions //*********************************************************************************
1738*c54f35caSApple OSS Distributions
1739*c54f35caSApple OSS Distributions void
adjustPowerState(IOPMPowerStateIndex clamp)1740*c54f35caSApple OSS Distributions IOService::adjustPowerState( IOPMPowerStateIndex clamp )
1741*c54f35caSApple OSS Distributions {
1742*c54f35caSApple OSS Distributions PM_ASSERT_IN_GATE();
1743*c54f35caSApple OSS Distributions computeDesiredState(clamp, false);
1744*c54f35caSApple OSS Distributions if (fControllingDriver && fParentsKnowState && inPlane(gIOPowerPlane)) {
1745*c54f35caSApple OSS Distributions IOPMPowerChangeFlags changeFlags = kIOPMSelfInitiated;
1746*c54f35caSApple OSS Distributions
1747*c54f35caSApple OSS Distributions // Indicate that children desires must be ignored, and do not ask
1748*c54f35caSApple OSS Distributions // apps for permission to drop power. This is used by root domain
1749*c54f35caSApple OSS Distributions // for demand sleep.
1750*c54f35caSApple OSS Distributions
1751*c54f35caSApple OSS Distributions if (getPMRequestType() == kIOPMRequestTypeRequestPowerStateOverride) {
1752*c54f35caSApple OSS Distributions changeFlags |= (kIOPMIgnoreChildren | kIOPMSkipAskPowerDown);
1753*c54f35caSApple OSS Distributions }
1754*c54f35caSApple OSS Distributions
1755*c54f35caSApple OSS Distributions startPowerChange(
1756*c54f35caSApple OSS Distributions /* flags */ changeFlags,
1757*c54f35caSApple OSS Distributions /* power state */ fDesiredPowerState,
1758*c54f35caSApple OSS Distributions /* domain flags */ 0,
1759*c54f35caSApple OSS Distributions /* connection */ NULL,
1760*c54f35caSApple OSS Distributions /* parent flags */ 0);
1761*c54f35caSApple OSS Distributions }
1762*c54f35caSApple OSS Distributions }
1763*c54f35caSApple OSS Distributions
1764*c54f35caSApple OSS Distributions //*********************************************************************************
1765*c54f35caSApple OSS Distributions // [public] synchronizePowerTree
1766*c54f35caSApple OSS Distributions //*********************************************************************************
1767*c54f35caSApple OSS Distributions
1768*c54f35caSApple OSS Distributions IOReturn
synchronizePowerTree(IOOptionBits options,IOService * notifyRoot)1769*c54f35caSApple OSS Distributions IOService::synchronizePowerTree(
1770*c54f35caSApple OSS Distributions IOOptionBits options,
1771*c54f35caSApple OSS Distributions IOService * notifyRoot )
1772*c54f35caSApple OSS Distributions {
1773*c54f35caSApple OSS Distributions IOPMRequest * request_c = NULL;
1774*c54f35caSApple OSS Distributions IOPMRequest * request_s;
1775*c54f35caSApple OSS Distributions
1776*c54f35caSApple OSS Distributions if (this != getPMRootDomain()) {
1777*c54f35caSApple OSS Distributions return kIOReturnBadArgument;
1778*c54f35caSApple OSS Distributions }
1779*c54f35caSApple OSS Distributions if (!initialized) {
1780*c54f35caSApple OSS Distributions return kIOPMNotYetInitialized;
1781*c54f35caSApple OSS Distributions }
1782*c54f35caSApple OSS Distributions
1783*c54f35caSApple OSS Distributions OUR_PMLog(kPMLogCSynchronizePowerTree, options, (notifyRoot != NULL));
1784*c54f35caSApple OSS Distributions
1785*c54f35caSApple OSS Distributions if (notifyRoot) {
1786*c54f35caSApple OSS Distributions IOPMRequest * nr;
1787*c54f35caSApple OSS Distributions
1788*c54f35caSApple OSS Distributions // Cancels don't need to be synchronized.
1789*c54f35caSApple OSS Distributions nr = acquirePMRequest(notifyRoot, kIOPMRequestTypeChildNotifyDelayCancel);
1790*c54f35caSApple OSS Distributions if (nr) {
1791*c54f35caSApple OSS Distributions submitPMRequest(nr);
1792*c54f35caSApple OSS Distributions }
1793*c54f35caSApple OSS Distributions
1794*c54f35caSApple OSS Distributions // For display wrangler or any other delay-eligible (dark wake clamped)
1795*c54f35caSApple OSS Distributions // drivers attached to root domain in the power plane.
1796*c54f35caSApple OSS Distributions nr = acquirePMRequest(getPMRootDomain(), kIOPMRequestTypeChildNotifyDelayCancel);
1797*c54f35caSApple OSS Distributions if (nr) {
1798*c54f35caSApple OSS Distributions submitPMRequest(nr);
1799*c54f35caSApple OSS Distributions }
1800*c54f35caSApple OSS Distributions }
1801*c54f35caSApple OSS Distributions
1802*c54f35caSApple OSS Distributions request_s = acquirePMRequest( this, kIOPMRequestTypeSynchronizePowerTree );
1803*c54f35caSApple OSS Distributions if (!request_s) {
1804*c54f35caSApple OSS Distributions goto error_no_memory;
1805*c54f35caSApple OSS Distributions }
1806*c54f35caSApple OSS Distributions
1807*c54f35caSApple OSS Distributions if (options & kIOPMSyncCancelPowerDown) {
1808*c54f35caSApple OSS Distributions request_c = acquirePMRequest( this, kIOPMRequestTypeIdleCancel );
1809*c54f35caSApple OSS Distributions }
1810*c54f35caSApple OSS Distributions if (request_c) {
1811*c54f35caSApple OSS Distributions request_c->attachNextRequest( request_s );
1812*c54f35caSApple OSS Distributions submitPMRequest(request_c);
1813*c54f35caSApple OSS Distributions }
1814*c54f35caSApple OSS Distributions
1815*c54f35caSApple OSS Distributions request_s->fArg0 = (void *)(uintptr_t) options;
1816*c54f35caSApple OSS Distributions submitPMRequest(request_s);
1817*c54f35caSApple OSS Distributions
1818*c54f35caSApple OSS Distributions return kIOReturnSuccess;
1819*c54f35caSApple OSS Distributions
1820*c54f35caSApple OSS Distributions error_no_memory:
1821*c54f35caSApple OSS Distributions if (request_c) {
1822*c54f35caSApple OSS Distributions releasePMRequest(request_c);
1823*c54f35caSApple OSS Distributions }
1824*c54f35caSApple OSS Distributions if (request_s) {
1825*c54f35caSApple OSS Distributions releasePMRequest(request_s);
1826*c54f35caSApple OSS Distributions }
1827*c54f35caSApple OSS Distributions return kIOReturnNoMemory;
1828*c54f35caSApple OSS Distributions }
1829*c54f35caSApple OSS Distributions
1830*c54f35caSApple OSS Distributions //*********************************************************************************
1831*c54f35caSApple OSS Distributions // [private] handleSynchronizePowerTree
1832*c54f35caSApple OSS Distributions //*********************************************************************************
1833*c54f35caSApple OSS Distributions
1834*c54f35caSApple OSS Distributions void
handleSynchronizePowerTree(IOPMRequest * request)1835*c54f35caSApple OSS Distributions IOService::handleSynchronizePowerTree( IOPMRequest * request )
1836*c54f35caSApple OSS Distributions {
1837*c54f35caSApple OSS Distributions PM_ASSERT_IN_GATE();
1838*c54f35caSApple OSS Distributions if (fControllingDriver && fParentsKnowState && inPlane(gIOPowerPlane) &&
1839*c54f35caSApple OSS Distributions (fCurrentPowerState == fHighestPowerState)) {
1840*c54f35caSApple OSS Distributions IOPMPowerChangeFlags options = (IOPMPowerChangeFlags)(uintptr_t) request->fArg0;
1841*c54f35caSApple OSS Distributions
1842*c54f35caSApple OSS Distributions startPowerChange(
1843*c54f35caSApple OSS Distributions /* flags */ kIOPMSelfInitiated | kIOPMSynchronize |
1844*c54f35caSApple OSS Distributions (options & kIOPMSyncNoChildNotify),
1845*c54f35caSApple OSS Distributions /* power state */ fCurrentPowerState,
1846*c54f35caSApple OSS Distributions /* domain flags */ 0,
1847*c54f35caSApple OSS Distributions /* connection */ NULL,
1848*c54f35caSApple OSS Distributions /* parent flags */ 0);
1849*c54f35caSApple OSS Distributions }
1850*c54f35caSApple OSS Distributions }
1851*c54f35caSApple OSS Distributions
1852*c54f35caSApple OSS Distributions #ifndef __LP64__
1853*c54f35caSApple OSS Distributions //*********************************************************************************
1854*c54f35caSApple OSS Distributions // [deprecated] powerDomainWillChangeTo
1855*c54f35caSApple OSS Distributions //
1856*c54f35caSApple OSS Distributions // Called by the power-hierarchy parent notifying of a new power state
1857*c54f35caSApple OSS Distributions // in the power domain.
1858*c54f35caSApple OSS Distributions // We enqueue a parent power-change to our queue of power changes.
1859*c54f35caSApple OSS Distributions // This may or may not cause us to change power, depending on what
1860*c54f35caSApple OSS Distributions // kind of change is occuring in the domain.
1861*c54f35caSApple OSS Distributions //*********************************************************************************
1862*c54f35caSApple OSS Distributions
1863*c54f35caSApple OSS Distributions IOReturn
powerDomainWillChangeTo(IOPMPowerFlags newPowerFlags,IOPowerConnection * whichParent)1864*c54f35caSApple OSS Distributions IOService::powerDomainWillChangeTo(
1865*c54f35caSApple OSS Distributions IOPMPowerFlags newPowerFlags,
1866*c54f35caSApple OSS Distributions IOPowerConnection * whichParent )
1867*c54f35caSApple OSS Distributions {
1868*c54f35caSApple OSS Distributions assert(false);
1869*c54f35caSApple OSS Distributions return kIOReturnUnsupported;
1870*c54f35caSApple OSS Distributions }
1871*c54f35caSApple OSS Distributions #endif /* !__LP64__ */
1872*c54f35caSApple OSS Distributions
1873*c54f35caSApple OSS Distributions //*********************************************************************************
1874*c54f35caSApple OSS Distributions // [private] handlePowerDomainWillChangeTo
1875*c54f35caSApple OSS Distributions //*********************************************************************************
1876*c54f35caSApple OSS Distributions
1877*c54f35caSApple OSS Distributions void
handlePowerDomainWillChangeTo(IOPMRequest * request)1878*c54f35caSApple OSS Distributions IOService::handlePowerDomainWillChangeTo( IOPMRequest * request )
1879*c54f35caSApple OSS Distributions {
1880*c54f35caSApple OSS Distributions IOPMPowerFlags parentPowerFlags = (IOPMPowerFlags) request->fArg0;
1881*c54f35caSApple OSS Distributions IOPowerConnection * whichParent = (IOPowerConnection *) request->fArg1;
1882*c54f35caSApple OSS Distributions IOPMPowerChangeFlags parentChangeFlags = (IOPMPowerChangeFlags)(uintptr_t) request->fArg2;
1883*c54f35caSApple OSS Distributions IOPMPowerChangeFlags myChangeFlags;
1884*c54f35caSApple OSS Distributions OSIterator * iter;
1885*c54f35caSApple OSS Distributions OSObject * next;
1886*c54f35caSApple OSS Distributions IOPowerConnection * connection;
1887*c54f35caSApple OSS Distributions IOPMPowerStateIndex maxPowerState;
1888*c54f35caSApple OSS Distributions IOPMPowerFlags combinedPowerFlags;
1889*c54f35caSApple OSS Distributions IOReturn result = IOPMAckImplied;
1890*c54f35caSApple OSS Distributions
1891*c54f35caSApple OSS Distributions PM_ASSERT_IN_GATE();
1892*c54f35caSApple OSS Distributions OUR_PMLog(kPMLogWillChange, parentPowerFlags, 0);
1893*c54f35caSApple OSS Distributions
1894*c54f35caSApple OSS Distributions if (!inPlane(gIOPowerPlane) || !whichParent || !whichParent->getAwaitingAck()) {
1895*c54f35caSApple OSS Distributions PM_LOG("%s::%s not in power tree\n", getName(), __FUNCTION__);
1896*c54f35caSApple OSS Distributions goto exit_no_ack;
1897*c54f35caSApple OSS Distributions }
1898*c54f35caSApple OSS Distributions
1899*c54f35caSApple OSS Distributions // Combine parents' output power flags.
1900*c54f35caSApple OSS Distributions
1901*c54f35caSApple OSS Distributions combinedPowerFlags = 0;
1902*c54f35caSApple OSS Distributions
1903*c54f35caSApple OSS Distributions iter = getParentIterator(gIOPowerPlane);
1904*c54f35caSApple OSS Distributions if (iter) {
1905*c54f35caSApple OSS Distributions while ((next = iter->getNextObject())) {
1906*c54f35caSApple OSS Distributions if ((connection = OSDynamicCast(IOPowerConnection, next))) {
1907*c54f35caSApple OSS Distributions if (connection == whichParent) {
1908*c54f35caSApple OSS Distributions combinedPowerFlags |= parentPowerFlags;
1909*c54f35caSApple OSS Distributions } else {
1910*c54f35caSApple OSS Distributions combinedPowerFlags |= connection->parentCurrentPowerFlags();
1911*c54f35caSApple OSS Distributions }
1912*c54f35caSApple OSS Distributions }
1913*c54f35caSApple OSS Distributions }
1914*c54f35caSApple OSS Distributions iter->release();
1915*c54f35caSApple OSS Distributions }
1916*c54f35caSApple OSS Distributions
1917*c54f35caSApple OSS Distributions // If our initial change has yet to occur, then defer the power change
1918*c54f35caSApple OSS Distributions // until after the power domain has completed its power transition.
1919*c54f35caSApple OSS Distributions
1920*c54f35caSApple OSS Distributions if (fControllingDriver && !fInitialPowerChange) {
1921*c54f35caSApple OSS Distributions maxPowerState = fControllingDriver->maxCapabilityForDomainState(
1922*c54f35caSApple OSS Distributions combinedPowerFlags);
1923*c54f35caSApple OSS Distributions
1924*c54f35caSApple OSS Distributions if (parentChangeFlags & kIOPMDomainPowerDrop) {
1925*c54f35caSApple OSS Distributions // fMaxPowerState set a limit on self-initiated power changes.
1926*c54f35caSApple OSS Distributions // Update it before a parent power drop.
1927*c54f35caSApple OSS Distributions fMaxPowerState = maxPowerState;
1928*c54f35caSApple OSS Distributions }
1929*c54f35caSApple OSS Distributions
1930*c54f35caSApple OSS Distributions // Use kIOPMSynchronize below instead of kIOPMRootBroadcastFlags
1931*c54f35caSApple OSS Distributions // to avoid propagating the root change flags if any service must
1932*c54f35caSApple OSS Distributions // change power state due to root's will-change notification.
1933*c54f35caSApple OSS Distributions // Root does not change power state for kIOPMSynchronize.
1934*c54f35caSApple OSS Distributions
1935*c54f35caSApple OSS Distributions myChangeFlags = kIOPMParentInitiated | kIOPMDomainWillChange |
1936*c54f35caSApple OSS Distributions (parentChangeFlags & kIOPMSynchronize);
1937*c54f35caSApple OSS Distributions
1938*c54f35caSApple OSS Distributions result = startPowerChange(
1939*c54f35caSApple OSS Distributions /* flags */ myChangeFlags,
1940*c54f35caSApple OSS Distributions /* power state */ maxPowerState,
1941*c54f35caSApple OSS Distributions /* domain flags */ combinedPowerFlags,
1942*c54f35caSApple OSS Distributions /* connection */ whichParent,
1943*c54f35caSApple OSS Distributions /* parent flags */ parentPowerFlags);
1944*c54f35caSApple OSS Distributions }
1945*c54f35caSApple OSS Distributions
1946*c54f35caSApple OSS Distributions // If parent is dropping power, immediately update the parent's
1947*c54f35caSApple OSS Distributions // capability flags. Any future merging of parent(s) combined
1948*c54f35caSApple OSS Distributions // power flags should account for this power drop.
1949*c54f35caSApple OSS Distributions
1950*c54f35caSApple OSS Distributions if (parentChangeFlags & kIOPMDomainPowerDrop) {
1951*c54f35caSApple OSS Distributions setParentInfo(parentPowerFlags, whichParent, true);
1952*c54f35caSApple OSS Distributions }
1953*c54f35caSApple OSS Distributions
1954*c54f35caSApple OSS Distributions // Parent is expecting an ACK from us. If we did not embark on a state
1955*c54f35caSApple OSS Distributions // transition, i.e. startPowerChange() returned IOPMAckImplied. We are
1956*c54f35caSApple OSS Distributions // still required to issue an ACK to our parent.
1957*c54f35caSApple OSS Distributions
1958*c54f35caSApple OSS Distributions if (IOPMAckImplied == result) {
1959*c54f35caSApple OSS Distributions IOService * parent;
1960*c54f35caSApple OSS Distributions parent = (IOService *) whichParent->copyParentEntry(gIOPowerPlane);
1961*c54f35caSApple OSS Distributions assert(parent);
1962*c54f35caSApple OSS Distributions if (parent) {
1963*c54f35caSApple OSS Distributions parent->acknowledgePowerChange( whichParent );
1964*c54f35caSApple OSS Distributions parent->release();
1965*c54f35caSApple OSS Distributions }
1966*c54f35caSApple OSS Distributions }
1967*c54f35caSApple OSS Distributions
1968*c54f35caSApple OSS Distributions exit_no_ack:
1969*c54f35caSApple OSS Distributions // Drop the retain from notifyChild().
1970*c54f35caSApple OSS Distributions if (whichParent) {
1971*c54f35caSApple OSS Distributions whichParent->release();
1972*c54f35caSApple OSS Distributions }
1973*c54f35caSApple OSS Distributions }
1974*c54f35caSApple OSS Distributions
1975*c54f35caSApple OSS Distributions #ifndef __LP64__
1976*c54f35caSApple OSS Distributions //*********************************************************************************
1977*c54f35caSApple OSS Distributions // [deprecated] powerDomainDidChangeTo
1978*c54f35caSApple OSS Distributions //
1979*c54f35caSApple OSS Distributions // Called by the power-hierarchy parent after the power state of the power domain
1980*c54f35caSApple OSS Distributions // has settled at a new level.
1981*c54f35caSApple OSS Distributions // We enqueue a parent power-change to our queue of power changes.
1982*c54f35caSApple OSS Distributions // This may or may not cause us to change power, depending on what
1983*c54f35caSApple OSS Distributions // kind of change is occuring in the domain.
1984*c54f35caSApple OSS Distributions //*********************************************************************************
1985*c54f35caSApple OSS Distributions
1986*c54f35caSApple OSS Distributions IOReturn
powerDomainDidChangeTo(IOPMPowerFlags newPowerFlags,IOPowerConnection * whichParent)1987*c54f35caSApple OSS Distributions IOService::powerDomainDidChangeTo(
1988*c54f35caSApple OSS Distributions IOPMPowerFlags newPowerFlags,
1989*c54f35caSApple OSS Distributions IOPowerConnection * whichParent )
1990*c54f35caSApple OSS Distributions {
1991*c54f35caSApple OSS Distributions assert(false);
1992*c54f35caSApple OSS Distributions return kIOReturnUnsupported;
1993*c54f35caSApple OSS Distributions }
1994*c54f35caSApple OSS Distributions #endif /* !__LP64__ */
1995*c54f35caSApple OSS Distributions
1996*c54f35caSApple OSS Distributions //*********************************************************************************
1997*c54f35caSApple OSS Distributions // [private] handlePowerDomainDidChangeTo
1998*c54f35caSApple OSS Distributions //*********************************************************************************
1999*c54f35caSApple OSS Distributions
2000*c54f35caSApple OSS Distributions void
handlePowerDomainDidChangeTo(IOPMRequest * request)2001*c54f35caSApple OSS Distributions IOService::handlePowerDomainDidChangeTo( IOPMRequest * request )
2002*c54f35caSApple OSS Distributions {
2003*c54f35caSApple OSS Distributions IOPMPowerFlags parentPowerFlags = (IOPMPowerFlags) request->fArg0;
2004*c54f35caSApple OSS Distributions IOPowerConnection * whichParent = (IOPowerConnection *) request->fArg1;
2005*c54f35caSApple OSS Distributions IOPMPowerChangeFlags parentChangeFlags = (IOPMPowerChangeFlags)(uintptr_t) request->fArg2;
2006*c54f35caSApple OSS Distributions IOPMPowerChangeFlags myChangeFlags;
2007*c54f35caSApple OSS Distributions IOPMPowerStateIndex maxPowerState;
2008*c54f35caSApple OSS Distributions IOPMPowerStateIndex initialDesire = kPowerStateZero;
2009*c54f35caSApple OSS Distributions bool computeDesire = false;
2010*c54f35caSApple OSS Distributions bool desireChanged = false;
2011*c54f35caSApple OSS Distributions bool savedParentsKnowState;
2012*c54f35caSApple OSS Distributions IOReturn result = IOPMAckImplied;
2013*c54f35caSApple OSS Distributions
2014*c54f35caSApple OSS Distributions PM_ASSERT_IN_GATE();
2015*c54f35caSApple OSS Distributions OUR_PMLog(kPMLogDidChange, parentPowerFlags, 0);
2016*c54f35caSApple OSS Distributions
2017*c54f35caSApple OSS Distributions if (!inPlane(gIOPowerPlane) || !whichParent || !whichParent->getAwaitingAck()) {
2018*c54f35caSApple OSS Distributions PM_LOG("%s::%s not in power tree\n", getName(), __FUNCTION__);
2019*c54f35caSApple OSS Distributions goto exit_no_ack;
2020*c54f35caSApple OSS Distributions }
2021*c54f35caSApple OSS Distributions
2022*c54f35caSApple OSS Distributions savedParentsKnowState = fParentsKnowState;
2023*c54f35caSApple OSS Distributions
2024*c54f35caSApple OSS Distributions setParentInfo(parentPowerFlags, whichParent, true);
2025*c54f35caSApple OSS Distributions
2026*c54f35caSApple OSS Distributions if (fControllingDriver) {
2027*c54f35caSApple OSS Distributions maxPowerState = fControllingDriver->maxCapabilityForDomainState(
2028*c54f35caSApple OSS Distributions fParentsCurrentPowerFlags);
2029*c54f35caSApple OSS Distributions
2030*c54f35caSApple OSS Distributions if ((parentChangeFlags & kIOPMDomainPowerDrop) == 0) {
2031*c54f35caSApple OSS Distributions // fMaxPowerState set a limit on self-initiated power changes.
2032*c54f35caSApple OSS Distributions // Update it after a parent power rise.
2033*c54f35caSApple OSS Distributions fMaxPowerState = maxPowerState;
2034*c54f35caSApple OSS Distributions }
2035*c54f35caSApple OSS Distributions
2036*c54f35caSApple OSS Distributions if (fInitialPowerChange) {
2037*c54f35caSApple OSS Distributions computeDesire = true;
2038*c54f35caSApple OSS Distributions initialDesire = fControllingDriver->initialPowerStateForDomainState(
2039*c54f35caSApple OSS Distributions fParentsCurrentPowerFlags);
2040*c54f35caSApple OSS Distributions } else if (parentChangeFlags & kIOPMRootChangeUp) {
2041*c54f35caSApple OSS Distributions if (fAdvisoryTickleUsed) {
2042*c54f35caSApple OSS Distributions // On system wake, re-compute the desired power state since
2043*c54f35caSApple OSS Distributions // gIOPMAdvisoryTickleEnabled will change for a full wake,
2044*c54f35caSApple OSS Distributions // which is an input to computeDesiredState(). This is not
2045*c54f35caSApple OSS Distributions // necessary for a dark wake because powerChangeDone() will
2046*c54f35caSApple OSS Distributions // handle the dark to full wake case, but it does no harm.
2047*c54f35caSApple OSS Distributions
2048*c54f35caSApple OSS Distributions desireChanged = true;
2049*c54f35caSApple OSS Distributions }
2050*c54f35caSApple OSS Distributions
2051*c54f35caSApple OSS Distributions if (fResetPowerStateOnWake) {
2052*c54f35caSApple OSS Distributions // Query the driver for the desired power state on system wake.
2053*c54f35caSApple OSS Distributions // Default implementation returns the lowest power state.
2054*c54f35caSApple OSS Distributions
2055*c54f35caSApple OSS Distributions IOPMPowerStateIndex wakePowerState =
2056*c54f35caSApple OSS Distributions fControllingDriver->initialPowerStateForDomainState(
2057*c54f35caSApple OSS Distributions kIOPMRootDomainState | kIOPMPowerOn );
2058*c54f35caSApple OSS Distributions
2059*c54f35caSApple OSS Distributions // fDesiredPowerState was adjusted before going to sleep
2060*c54f35caSApple OSS Distributions // with fDeviceDesire at min.
2061*c54f35caSApple OSS Distributions
2062*c54f35caSApple OSS Distributions if (StateOrder(wakePowerState) > StateOrder(fDesiredPowerState)) {
2063*c54f35caSApple OSS Distributions // Must schedule a power adjustment if we changed the
2064*c54f35caSApple OSS Distributions // device desire. That will update the desired domain
2065*c54f35caSApple OSS Distributions // power on the parent power connection and ping the
2066*c54f35caSApple OSS Distributions // power parent if necessary.
2067*c54f35caSApple OSS Distributions
2068*c54f35caSApple OSS Distributions updatePowerClient(gIOPMPowerClientDevice, wakePowerState);
2069*c54f35caSApple OSS Distributions desireChanged = true;
2070*c54f35caSApple OSS Distributions }
2071*c54f35caSApple OSS Distributions }
2072*c54f35caSApple OSS Distributions }
2073*c54f35caSApple OSS Distributions
2074*c54f35caSApple OSS Distributions if (computeDesire || desireChanged) {
2075*c54f35caSApple OSS Distributions computeDesiredState(initialDesire, false);
2076*c54f35caSApple OSS Distributions }
2077*c54f35caSApple OSS Distributions
2078*c54f35caSApple OSS Distributions // Absorb and propagate parent's broadcast flags
2079*c54f35caSApple OSS Distributions myChangeFlags = kIOPMParentInitiated | kIOPMDomainDidChange |
2080*c54f35caSApple OSS Distributions (parentChangeFlags & kIOPMRootBroadcastFlags);
2081*c54f35caSApple OSS Distributions
2082*c54f35caSApple OSS Distributions if (kIOPMAOTPower & fPowerStates[maxPowerState].inputPowerFlags) {
2083*c54f35caSApple OSS Distributions IOLog("aotPS %s0x%qx[%ld]\n", getName(), getRegistryEntryID(), maxPowerState);
2084*c54f35caSApple OSS Distributions }
2085*c54f35caSApple OSS Distributions
2086*c54f35caSApple OSS Distributions result = startPowerChange(
2087*c54f35caSApple OSS Distributions /* flags */ myChangeFlags,
2088*c54f35caSApple OSS Distributions /* power state */ maxPowerState,
2089*c54f35caSApple OSS Distributions /* domain flags */ fParentsCurrentPowerFlags,
2090*c54f35caSApple OSS Distributions /* connection */ whichParent,
2091*c54f35caSApple OSS Distributions /* parent flags */ 0);
2092*c54f35caSApple OSS Distributions }
2093*c54f35caSApple OSS Distributions
2094*c54f35caSApple OSS Distributions // Parent is expecting an ACK from us. If we did not embark on a state
2095*c54f35caSApple OSS Distributions // transition, i.e. startPowerChange() returned IOPMAckImplied. We are
2096*c54f35caSApple OSS Distributions // still required to issue an ACK to our parent.
2097*c54f35caSApple OSS Distributions
2098*c54f35caSApple OSS Distributions if (IOPMAckImplied == result) {
2099*c54f35caSApple OSS Distributions IOService * parent;
2100*c54f35caSApple OSS Distributions parent = (IOService *) whichParent->copyParentEntry(gIOPowerPlane);
2101*c54f35caSApple OSS Distributions assert(parent);
2102*c54f35caSApple OSS Distributions if (parent) {
2103*c54f35caSApple OSS Distributions parent->acknowledgePowerChange( whichParent );
2104*c54f35caSApple OSS Distributions parent->release();
2105*c54f35caSApple OSS Distributions }
2106*c54f35caSApple OSS Distributions }
2107*c54f35caSApple OSS Distributions
2108*c54f35caSApple OSS Distributions // If the parent registers its power driver late, then this is the
2109*c54f35caSApple OSS Distributions // first opportunity to tell our parent about our desire. Or if the
2110*c54f35caSApple OSS Distributions // child's desire changed during a parent change notify.
2111*c54f35caSApple OSS Distributions
2112*c54f35caSApple OSS Distributions if (fControllingDriver &&
2113*c54f35caSApple OSS Distributions ((!savedParentsKnowState && fParentsKnowState) || desireChanged)) {
2114*c54f35caSApple OSS Distributions PM_LOG1("%s::powerDomainDidChangeTo parentsKnowState %d\n",
2115*c54f35caSApple OSS Distributions getName(), fParentsKnowState);
2116*c54f35caSApple OSS Distributions requestDomainPower( fDesiredPowerState );
2117*c54f35caSApple OSS Distributions }
2118*c54f35caSApple OSS Distributions
2119*c54f35caSApple OSS Distributions exit_no_ack:
2120*c54f35caSApple OSS Distributions // Drop the retain from notifyChild().
2121*c54f35caSApple OSS Distributions if (whichParent) {
2122*c54f35caSApple OSS Distributions whichParent->release();
2123*c54f35caSApple OSS Distributions }
2124*c54f35caSApple OSS Distributions }
2125*c54f35caSApple OSS Distributions
2126*c54f35caSApple OSS Distributions //*********************************************************************************
2127*c54f35caSApple OSS Distributions // [private] setParentInfo
2128*c54f35caSApple OSS Distributions //
2129*c54f35caSApple OSS Distributions // Set our connection data for one specific parent, and then combine all the parent
2130*c54f35caSApple OSS Distributions // data together.
2131*c54f35caSApple OSS Distributions //*********************************************************************************
2132*c54f35caSApple OSS Distributions
2133*c54f35caSApple OSS Distributions void
setParentInfo(IOPMPowerFlags newPowerFlags,IOPowerConnection * whichParent,bool knowsState)2134*c54f35caSApple OSS Distributions IOService::setParentInfo(
2135*c54f35caSApple OSS Distributions IOPMPowerFlags newPowerFlags,
2136*c54f35caSApple OSS Distributions IOPowerConnection * whichParent,
2137*c54f35caSApple OSS Distributions bool knowsState )
2138*c54f35caSApple OSS Distributions {
2139*c54f35caSApple OSS Distributions OSIterator * iter;
2140*c54f35caSApple OSS Distributions OSObject * next;
2141*c54f35caSApple OSS Distributions IOPowerConnection * conn;
2142*c54f35caSApple OSS Distributions
2143*c54f35caSApple OSS Distributions PM_ASSERT_IN_GATE();
2144*c54f35caSApple OSS Distributions
2145*c54f35caSApple OSS Distributions // set our connection data
2146*c54f35caSApple OSS Distributions whichParent->setParentCurrentPowerFlags(newPowerFlags);
2147*c54f35caSApple OSS Distributions whichParent->setParentKnowsState(knowsState);
2148*c54f35caSApple OSS Distributions
2149*c54f35caSApple OSS Distributions // recompute our parent info
2150*c54f35caSApple OSS Distributions fParentsCurrentPowerFlags = 0;
2151*c54f35caSApple OSS Distributions fParentsKnowState = true;
2152*c54f35caSApple OSS Distributions
2153*c54f35caSApple OSS Distributions iter = getParentIterator(gIOPowerPlane);
2154*c54f35caSApple OSS Distributions if (iter) {
2155*c54f35caSApple OSS Distributions while ((next = iter->getNextObject())) {
2156*c54f35caSApple OSS Distributions if ((conn = OSDynamicCast(IOPowerConnection, next))) {
2157*c54f35caSApple OSS Distributions fParentsKnowState &= conn->parentKnowsState();
2158*c54f35caSApple OSS Distributions fParentsCurrentPowerFlags |= conn->parentCurrentPowerFlags();
2159*c54f35caSApple OSS Distributions }
2160*c54f35caSApple OSS Distributions }
2161*c54f35caSApple OSS Distributions iter->release();
2162*c54f35caSApple OSS Distributions }
2163*c54f35caSApple OSS Distributions }
2164*c54f35caSApple OSS Distributions
2165*c54f35caSApple OSS Distributions //******************************************************************************
2166*c54f35caSApple OSS Distributions // [private] trackSystemSleepPreventers
2167*c54f35caSApple OSS Distributions //******************************************************************************
2168*c54f35caSApple OSS Distributions
2169*c54f35caSApple OSS Distributions void
trackSystemSleepPreventers(IOPMPowerStateIndex oldPowerState,IOPMPowerStateIndex newPowerState,IOPMPowerChangeFlags changeFlags __unused)2170*c54f35caSApple OSS Distributions IOService::trackSystemSleepPreventers(
2171*c54f35caSApple OSS Distributions IOPMPowerStateIndex oldPowerState,
2172*c54f35caSApple OSS Distributions IOPMPowerStateIndex newPowerState,
2173*c54f35caSApple OSS Distributions IOPMPowerChangeFlags changeFlags __unused )
2174*c54f35caSApple OSS Distributions {
2175*c54f35caSApple OSS Distributions IOPMPowerFlags oldCapability, newCapability;
2176*c54f35caSApple OSS Distributions
2177*c54f35caSApple OSS Distributions oldCapability = fPowerStates[oldPowerState].capabilityFlags &
2178*c54f35caSApple OSS Distributions (kIOPMPreventIdleSleep | kIOPMPreventSystemSleep);
2179*c54f35caSApple OSS Distributions newCapability = fPowerStates[newPowerState].capabilityFlags &
2180*c54f35caSApple OSS Distributions (kIOPMPreventIdleSleep | kIOPMPreventSystemSleep);
2181*c54f35caSApple OSS Distributions
2182*c54f35caSApple OSS Distributions if (fHeadNoteChangeFlags & kIOPMInitialPowerChange) {
2183*c54f35caSApple OSS Distributions oldCapability = 0;
2184*c54f35caSApple OSS Distributions }
2185*c54f35caSApple OSS Distributions if (oldCapability == newCapability) {
2186*c54f35caSApple OSS Distributions return;
2187*c54f35caSApple OSS Distributions }
2188*c54f35caSApple OSS Distributions
2189*c54f35caSApple OSS Distributions if ((oldCapability ^ newCapability) & kIOPMPreventIdleSleep) {
2190*c54f35caSApple OSS Distributions bool enablePrevention = ((oldCapability & kIOPMPreventIdleSleep) == 0);
2191*c54f35caSApple OSS Distributions bool idleCancelAllowed = getPMRootDomain()->updatePreventIdleSleepList(
2192*c54f35caSApple OSS Distributions this, enablePrevention);
2193*c54f35caSApple OSS Distributions #if SUPPORT_IDLE_CANCEL
2194*c54f35caSApple OSS Distributions if (idleCancelAllowed && enablePrevention) {
2195*c54f35caSApple OSS Distributions IOPMRequest * cancelRequest;
2196*c54f35caSApple OSS Distributions
2197*c54f35caSApple OSS Distributions cancelRequest = acquirePMRequest( getPMRootDomain(), kIOPMRequestTypeIdleCancel );
2198*c54f35caSApple OSS Distributions if (cancelRequest) {
2199*c54f35caSApple OSS Distributions submitPMRequest( cancelRequest );
2200*c54f35caSApple OSS Distributions }
2201*c54f35caSApple OSS Distributions }
2202*c54f35caSApple OSS Distributions #endif
2203*c54f35caSApple OSS Distributions }
2204*c54f35caSApple OSS Distributions
2205*c54f35caSApple OSS Distributions if ((oldCapability ^ newCapability) & kIOPMPreventSystemSleep) {
2206*c54f35caSApple OSS Distributions getPMRootDomain()->updatePreventSystemSleepList(this,
2207*c54f35caSApple OSS Distributions ((oldCapability & kIOPMPreventSystemSleep) == 0));
2208*c54f35caSApple OSS Distributions }
2209*c54f35caSApple OSS Distributions }
2210*c54f35caSApple OSS Distributions
2211*c54f35caSApple OSS Distributions //*********************************************************************************
2212*c54f35caSApple OSS Distributions // [public] requestPowerDomainState
2213*c54f35caSApple OSS Distributions //
2214*c54f35caSApple OSS Distributions // Called on a power parent when a child's power requirement changes.
2215*c54f35caSApple OSS Distributions //*********************************************************************************
2216*c54f35caSApple OSS Distributions
2217*c54f35caSApple OSS Distributions IOReturn
requestPowerDomainState(IOPMPowerFlags childRequestPowerFlags,IOPowerConnection * childConnection,unsigned long specification)2218*c54f35caSApple OSS Distributions IOService::requestPowerDomainState(
2219*c54f35caSApple OSS Distributions IOPMPowerFlags childRequestPowerFlags,
2220*c54f35caSApple OSS Distributions IOPowerConnection * childConnection,
2221*c54f35caSApple OSS Distributions unsigned long specification )
2222*c54f35caSApple OSS Distributions {
2223*c54f35caSApple OSS Distributions IOPMPowerStateIndex order, powerState;
2224*c54f35caSApple OSS Distributions IOPMPowerFlags outputPowerFlags;
2225*c54f35caSApple OSS Distributions IOService * child;
2226*c54f35caSApple OSS Distributions IOPMRequest * subRequest;
2227*c54f35caSApple OSS Distributions bool adjustPower = false;
2228*c54f35caSApple OSS Distributions
2229*c54f35caSApple OSS Distributions if (!initialized) {
2230*c54f35caSApple OSS Distributions return IOPMNotYetInitialized;
2231*c54f35caSApple OSS Distributions }
2232*c54f35caSApple OSS Distributions
2233*c54f35caSApple OSS Distributions if (gIOPMWorkLoop->onThread() == false) {
2234*c54f35caSApple OSS Distributions PM_LOG("%s::requestPowerDomainState\n", getName());
2235*c54f35caSApple OSS Distributions return kIOReturnSuccess;
2236*c54f35caSApple OSS Distributions }
2237*c54f35caSApple OSS Distributions
2238*c54f35caSApple OSS Distributions OUR_PMLog(kPMLogRequestDomain, childRequestPowerFlags, specification);
2239*c54f35caSApple OSS Distributions
2240*c54f35caSApple OSS Distributions if (!isChild(childConnection, gIOPowerPlane)) {
2241*c54f35caSApple OSS Distributions return kIOReturnNotAttached;
2242*c54f35caSApple OSS Distributions }
2243*c54f35caSApple OSS Distributions
2244*c54f35caSApple OSS Distributions if (!fControllingDriver || !fNumberOfPowerStates) {
2245*c54f35caSApple OSS Distributions return kIOReturnNotReady;
2246*c54f35caSApple OSS Distributions }
2247*c54f35caSApple OSS Distributions
2248*c54f35caSApple OSS Distributions child = (IOService *) childConnection->getChildEntry(gIOPowerPlane);
2249*c54f35caSApple OSS Distributions assert(child);
2250*c54f35caSApple OSS Distributions
2251*c54f35caSApple OSS Distributions // Remove flags from child request which we can't possibly supply
2252*c54f35caSApple OSS Distributions childRequestPowerFlags &= fMergedOutputPowerFlags;
2253*c54f35caSApple OSS Distributions
2254*c54f35caSApple OSS Distributions // Merge in the power flags contributed by this power parent
2255*c54f35caSApple OSS Distributions // at its current or impending power state.
2256*c54f35caSApple OSS Distributions
2257*c54f35caSApple OSS Distributions outputPowerFlags = fPowerStates[fCurrentPowerState].outputPowerFlags;
2258*c54f35caSApple OSS Distributions if (fMachineState != kIOPM_Finished) {
2259*c54f35caSApple OSS Distributions if (IS_POWER_DROP && !IS_ROOT_DOMAIN) {
2260*c54f35caSApple OSS Distributions // Use the lower power state when dropping power.
2261*c54f35caSApple OSS Distributions // Must be careful since a power drop can be cancelled
2262*c54f35caSApple OSS Distributions // from the following states:
2263*c54f35caSApple OSS Distributions // - kIOPM_OurChangeTellClientsPowerDown
2264*c54f35caSApple OSS Distributions // - kIOPM_OurChangeTellPriorityClientsPowerDown
2265*c54f35caSApple OSS Distributions //
2266*c54f35caSApple OSS Distributions // The child must not wait for this parent to raise power
2267*c54f35caSApple OSS Distributions // if the power drop was cancelled. The solution is to cancel
2268*c54f35caSApple OSS Distributions // the power drop if possible, then schedule an adjustment to
2269*c54f35caSApple OSS Distributions // re-evaluate the parent's power state.
2270*c54f35caSApple OSS Distributions //
2271*c54f35caSApple OSS Distributions // Root domain is excluded to avoid idle sleep issues. And allow
2272*c54f35caSApple OSS Distributions // root domain children to pop up when system is going to sleep.
2273*c54f35caSApple OSS Distributions
2274*c54f35caSApple OSS Distributions if ((fMachineState == kIOPM_OurChangeTellClientsPowerDown) ||
2275*c54f35caSApple OSS Distributions (fMachineState == kIOPM_OurChangeTellPriorityClientsPowerDown)) {
2276*c54f35caSApple OSS Distributions fDoNotPowerDown = true; // cancel power drop
2277*c54f35caSApple OSS Distributions adjustPower = true;// schedule an adjustment
2278*c54f35caSApple OSS Distributions PM_LOG1("%s: power drop cancelled in state %u by %s\n",
2279*c54f35caSApple OSS Distributions getName(), fMachineState, child->getName());
2280*c54f35caSApple OSS Distributions } else {
2281*c54f35caSApple OSS Distributions // Beyond cancellation point, report the impending state.
2282*c54f35caSApple OSS Distributions outputPowerFlags =
2283*c54f35caSApple OSS Distributions fPowerStates[fHeadNotePowerState].outputPowerFlags;
2284*c54f35caSApple OSS Distributions }
2285*c54f35caSApple OSS Distributions } else if (IS_POWER_RISE) {
2286*c54f35caSApple OSS Distributions // When raising power, must report the output power flags from
2287*c54f35caSApple OSS Distributions // child's perspective. A child power request may arrive while
2288*c54f35caSApple OSS Distributions // parent is transitioning upwards. If a request arrives after
2289*c54f35caSApple OSS Distributions // setParentInfo() has already recorded the output power flags
2290*c54f35caSApple OSS Distributions // for the next power state, then using the power supplied by
2291*c54f35caSApple OSS Distributions // fCurrentPowerState is incorrect, and might cause the child
2292*c54f35caSApple OSS Distributions // to wait when it should not.
2293*c54f35caSApple OSS Distributions
2294*c54f35caSApple OSS Distributions outputPowerFlags = childConnection->parentCurrentPowerFlags();
2295*c54f35caSApple OSS Distributions }
2296*c54f35caSApple OSS Distributions }
2297*c54f35caSApple OSS Distributions child->fHeadNoteDomainTargetFlags |= outputPowerFlags;
2298*c54f35caSApple OSS Distributions
2299*c54f35caSApple OSS Distributions // Map child's requested power flags to one of our power state.
2300*c54f35caSApple OSS Distributions
2301*c54f35caSApple OSS Distributions for (order = 0; order < fNumberOfPowerStates; order++) {
2302*c54f35caSApple OSS Distributions powerState = fPowerStates[order].stateOrderToIndex;
2303*c54f35caSApple OSS Distributions if ((fPowerStates[powerState].outputPowerFlags & childRequestPowerFlags)
2304*c54f35caSApple OSS Distributions == childRequestPowerFlags) {
2305*c54f35caSApple OSS Distributions break;
2306*c54f35caSApple OSS Distributions }
2307*c54f35caSApple OSS Distributions }
2308*c54f35caSApple OSS Distributions if (order >= fNumberOfPowerStates) {
2309*c54f35caSApple OSS Distributions powerState = kPowerStateZero;
2310*c54f35caSApple OSS Distributions }
2311*c54f35caSApple OSS Distributions
2312*c54f35caSApple OSS Distributions // Conditions that warrants a power adjustment on this parent.
2313*c54f35caSApple OSS Distributions // Adjust power will also propagate any changes to the child's
2314*c54f35caSApple OSS Distributions // prevent idle/sleep flags towards the root domain.
2315*c54f35caSApple OSS Distributions
2316*c54f35caSApple OSS Distributions if (!childConnection->childHasRequestedPower() ||
2317*c54f35caSApple OSS Distributions (powerState != childConnection->getDesiredDomainState())) {
2318*c54f35caSApple OSS Distributions adjustPower = true;
2319*c54f35caSApple OSS Distributions }
2320*c54f35caSApple OSS Distributions
2321*c54f35caSApple OSS Distributions #if ENABLE_DEBUG_LOGS
2322*c54f35caSApple OSS Distributions if (adjustPower) {
2323*c54f35caSApple OSS Distributions PM_LOG("requestPowerDomainState[%s]: %s, init %d, %u->%u\n",
2324*c54f35caSApple OSS Distributions getName(), child->getName(),
2325*c54f35caSApple OSS Distributions !childConnection->childHasRequestedPower(),
2326*c54f35caSApple OSS Distributions (uint32_t) childConnection->getDesiredDomainState(),
2327*c54f35caSApple OSS Distributions (uint32_t) powerState);
2328*c54f35caSApple OSS Distributions }
2329*c54f35caSApple OSS Distributions #endif
2330*c54f35caSApple OSS Distributions
2331*c54f35caSApple OSS Distributions // Record the child's desires on the connection.
2332*c54f35caSApple OSS Distributions childConnection->setChildHasRequestedPower();
2333*c54f35caSApple OSS Distributions childConnection->setDesiredDomainState( powerState );
2334*c54f35caSApple OSS Distributions
2335*c54f35caSApple OSS Distributions // Schedule a request to re-evaluate all children desires and
2336*c54f35caSApple OSS Distributions // adjust power state. Submit a request if one wasn't pending,
2337*c54f35caSApple OSS Distributions // or if the current request is part of a call tree.
2338*c54f35caSApple OSS Distributions
2339*c54f35caSApple OSS Distributions if (adjustPower && !fDeviceOverrideEnabled &&
2340*c54f35caSApple OSS Distributions (!fAdjustPowerScheduled || gIOPMRequest->getRootRequest())) {
2341*c54f35caSApple OSS Distributions subRequest = acquirePMRequest(
2342*c54f35caSApple OSS Distributions this, kIOPMRequestTypeAdjustPowerState, gIOPMRequest );
2343*c54f35caSApple OSS Distributions if (subRequest) {
2344*c54f35caSApple OSS Distributions submitPMRequest( subRequest );
2345*c54f35caSApple OSS Distributions fAdjustPowerScheduled = true;
2346*c54f35caSApple OSS Distributions }
2347*c54f35caSApple OSS Distributions }
2348*c54f35caSApple OSS Distributions
2349*c54f35caSApple OSS Distributions return kIOReturnSuccess;
2350*c54f35caSApple OSS Distributions }
2351*c54f35caSApple OSS Distributions
2352*c54f35caSApple OSS Distributions //*********************************************************************************
2353*c54f35caSApple OSS Distributions // [public] temporaryPowerClampOn
2354*c54f35caSApple OSS Distributions //
2355*c54f35caSApple OSS Distributions // A power domain wants to be clamped to max power until it has children which
2356*c54f35caSApple OSS Distributions // will then determine the power domain state.
2357*c54f35caSApple OSS Distributions //
2358*c54f35caSApple OSS Distributions // We enter the highest state until addPowerChild is called.
2359*c54f35caSApple OSS Distributions //*********************************************************************************
2360*c54f35caSApple OSS Distributions
2361*c54f35caSApple OSS Distributions IOReturn
temporaryPowerClampOn(void)2362*c54f35caSApple OSS Distributions IOService::temporaryPowerClampOn( void )
2363*c54f35caSApple OSS Distributions {
2364*c54f35caSApple OSS Distributions return requestPowerState( gIOPMPowerClientChildProxy, kIOPMPowerStateMax );
2365*c54f35caSApple OSS Distributions }
2366*c54f35caSApple OSS Distributions
2367*c54f35caSApple OSS Distributions //*********************************************************************************
2368*c54f35caSApple OSS Distributions // [public] makeUsable
2369*c54f35caSApple OSS Distributions //
2370*c54f35caSApple OSS Distributions // Some client of our device is asking that we become usable. Although
2371*c54f35caSApple OSS Distributions // this has not come from a subclassed device object, treat it exactly
2372*c54f35caSApple OSS Distributions // as if it had. In this way, subsequent requests for lower power from
2373*c54f35caSApple OSS Distributions // a subclassed device object will pre-empt this request.
2374*c54f35caSApple OSS Distributions //
2375*c54f35caSApple OSS Distributions // We treat this as a subclass object request to switch to the
2376*c54f35caSApple OSS Distributions // highest power state.
2377*c54f35caSApple OSS Distributions //*********************************************************************************
2378*c54f35caSApple OSS Distributions
2379*c54f35caSApple OSS Distributions IOReturn
makeUsable(void)2380*c54f35caSApple OSS Distributions IOService::makeUsable( void )
2381*c54f35caSApple OSS Distributions {
2382*c54f35caSApple OSS Distributions OUR_PMLog(kPMLogMakeUsable, 0, 0);
2383*c54f35caSApple OSS Distributions return requestPowerState( gIOPMPowerClientDevice, kIOPMPowerStateMax );
2384*c54f35caSApple OSS Distributions }
2385*c54f35caSApple OSS Distributions
2386*c54f35caSApple OSS Distributions //*********************************************************************************
2387*c54f35caSApple OSS Distributions // [public] currentCapability
2388*c54f35caSApple OSS Distributions //*********************************************************************************
2389*c54f35caSApple OSS Distributions
2390*c54f35caSApple OSS Distributions IOPMPowerFlags
currentCapability(void)2391*c54f35caSApple OSS Distributions IOService::currentCapability( void )
2392*c54f35caSApple OSS Distributions {
2393*c54f35caSApple OSS Distributions if (!initialized) {
2394*c54f35caSApple OSS Distributions return IOPMNotPowerManaged;
2395*c54f35caSApple OSS Distributions }
2396*c54f35caSApple OSS Distributions
2397*c54f35caSApple OSS Distributions return fCurrentCapabilityFlags;
2398*c54f35caSApple OSS Distributions }
2399*c54f35caSApple OSS Distributions
2400*c54f35caSApple OSS Distributions //*********************************************************************************
2401*c54f35caSApple OSS Distributions // [public] changePowerStateTo
2402*c54f35caSApple OSS Distributions //
2403*c54f35caSApple OSS Distributions // Called by our power-controlling driver to change power state. The new desired
2404*c54f35caSApple OSS Distributions // power state is computed and compared against the current power state. If those
2405*c54f35caSApple OSS Distributions // power states differ, then a power state change is initiated.
2406*c54f35caSApple OSS Distributions //*********************************************************************************
2407*c54f35caSApple OSS Distributions
2408*c54f35caSApple OSS Distributions IOReturn
changePowerStateTo(unsigned long ordinal)2409*c54f35caSApple OSS Distributions IOService::changePowerStateTo( unsigned long ordinal )
2410*c54f35caSApple OSS Distributions {
2411*c54f35caSApple OSS Distributions OUR_PMLog(kPMLogChangeStateTo, ordinal, 0);
2412*c54f35caSApple OSS Distributions return requestPowerState( gIOPMPowerClientDriver, ordinal );
2413*c54f35caSApple OSS Distributions }
2414*c54f35caSApple OSS Distributions
2415*c54f35caSApple OSS Distributions //*********************************************************************************
2416*c54f35caSApple OSS Distributions // [protected] changePowerStateToPriv
2417*c54f35caSApple OSS Distributions //
2418*c54f35caSApple OSS Distributions // Called by our driver subclass to change power state. The new desired power
2419*c54f35caSApple OSS Distributions // state is computed and compared against the current power state. If those
2420*c54f35caSApple OSS Distributions // power states differ, then a power state change is initiated.
2421*c54f35caSApple OSS Distributions //*********************************************************************************
2422*c54f35caSApple OSS Distributions
2423*c54f35caSApple OSS Distributions IOReturn
changePowerStateToPriv(unsigned long ordinal)2424*c54f35caSApple OSS Distributions IOService::changePowerStateToPriv( unsigned long ordinal )
2425*c54f35caSApple OSS Distributions {
2426*c54f35caSApple OSS Distributions OUR_PMLog(kPMLogChangeStateToPriv, ordinal, 0);
2427*c54f35caSApple OSS Distributions return requestPowerState( gIOPMPowerClientDevice, ordinal );
2428*c54f35caSApple OSS Distributions }
2429*c54f35caSApple OSS Distributions
2430*c54f35caSApple OSS Distributions //*********************************************************************************
2431*c54f35caSApple OSS Distributions // [public] changePowerStateWithOverrideTo
2432*c54f35caSApple OSS Distributions //
2433*c54f35caSApple OSS Distributions // Called by our driver subclass to change power state. The new desired power
2434*c54f35caSApple OSS Distributions // state is computed and compared against the current power state. If those
2435*c54f35caSApple OSS Distributions // power states differ, then a power state change is initiated.
2436*c54f35caSApple OSS Distributions // Override enforced - Children and Driver desires are ignored.
2437*c54f35caSApple OSS Distributions //*********************************************************************************
2438*c54f35caSApple OSS Distributions
2439*c54f35caSApple OSS Distributions IOReturn
changePowerStateWithOverrideTo(IOPMPowerStateIndex ordinal,IOPMRequestTag tag)2440*c54f35caSApple OSS Distributions IOService::changePowerStateWithOverrideTo( IOPMPowerStateIndex ordinal,
2441*c54f35caSApple OSS Distributions IOPMRequestTag tag )
2442*c54f35caSApple OSS Distributions {
2443*c54f35caSApple OSS Distributions IOPMRequest * request;
2444*c54f35caSApple OSS Distributions
2445*c54f35caSApple OSS Distributions if (!initialized) {
2446*c54f35caSApple OSS Distributions return kIOPMNotYetInitialized;
2447*c54f35caSApple OSS Distributions }
2448*c54f35caSApple OSS Distributions
2449*c54f35caSApple OSS Distributions OUR_PMLog(kPMLogChangeStateToPriv, ordinal, 0);
2450*c54f35caSApple OSS Distributions
2451*c54f35caSApple OSS Distributions request = acquirePMRequest( this, kIOPMRequestTypeRequestPowerStateOverride );
2452*c54f35caSApple OSS Distributions if (!request) {
2453*c54f35caSApple OSS Distributions return kIOReturnNoMemory;
2454*c54f35caSApple OSS Distributions }
2455*c54f35caSApple OSS Distributions
2456*c54f35caSApple OSS Distributions gIOPMPowerClientDevice->retain();
2457*c54f35caSApple OSS Distributions request->fTag = tag;
2458*c54f35caSApple OSS Distributions request->fArg0 = (void *) ordinal;
2459*c54f35caSApple OSS Distributions request->fArg1 = (void *) gIOPMPowerClientDevice;
2460*c54f35caSApple OSS Distributions request->fArg2 = NULL;
2461*c54f35caSApple OSS Distributions #if NOT_READY
2462*c54f35caSApple OSS Distributions if (action) {
2463*c54f35caSApple OSS Distributions request->installCompletionAction( action, target, param );
2464*c54f35caSApple OSS Distributions }
2465*c54f35caSApple OSS Distributions #endif
2466*c54f35caSApple OSS Distributions
2467*c54f35caSApple OSS Distributions // Prevent needless downwards power transitions by clamping power
2468*c54f35caSApple OSS Distributions // until the scheduled request is executed.
2469*c54f35caSApple OSS Distributions //
2470*c54f35caSApple OSS Distributions // TODO: review fOverrideMaxPowerState
2471*c54f35caSApple OSS Distributions
2472*c54f35caSApple OSS Distributions if (gIOPMWorkLoop->inGate() && (ordinal < fNumberOfPowerStates)) {
2473*c54f35caSApple OSS Distributions fTempClampPowerState = StateMax(fTempClampPowerState, ordinal);
2474*c54f35caSApple OSS Distributions fTempClampCount++;
2475*c54f35caSApple OSS Distributions request->fArg2 = (void *)(uintptr_t) true;
2476*c54f35caSApple OSS Distributions
2477*c54f35caSApple OSS Distributions // Place a power state ceiling to prevent any transition to a
2478*c54f35caSApple OSS Distributions // power state higher than fOverrideMaxPowerState.
2479*c54f35caSApple OSS Distributions fOverrideMaxPowerState = ordinal;
2480*c54f35caSApple OSS Distributions }
2481*c54f35caSApple OSS Distributions
2482*c54f35caSApple OSS Distributions submitPMRequest( request );
2483*c54f35caSApple OSS Distributions return IOPMNoErr;
2484*c54f35caSApple OSS Distributions }
2485*c54f35caSApple OSS Distributions
2486*c54f35caSApple OSS Distributions //*********************************************************************************
2487*c54f35caSApple OSS Distributions // Tagged form of changePowerStateTo()
2488*c54f35caSApple OSS Distributions //*********************************************************************************
2489*c54f35caSApple OSS Distributions
2490*c54f35caSApple OSS Distributions IOReturn
changePowerStateWithTagTo(IOPMPowerStateIndex ordinal,IOPMRequestTag tag)2491*c54f35caSApple OSS Distributions IOService::changePowerStateWithTagTo( IOPMPowerStateIndex ordinal, IOPMRequestTag tag )
2492*c54f35caSApple OSS Distributions {
2493*c54f35caSApple OSS Distributions OUR_PMLog(kPMLogChangeStateTo, ordinal, tag);
2494*c54f35caSApple OSS Distributions return requestPowerState(gIOPMPowerClientDriver, ordinal, tag);
2495*c54f35caSApple OSS Distributions }
2496*c54f35caSApple OSS Distributions
2497*c54f35caSApple OSS Distributions //*********************************************************************************
2498*c54f35caSApple OSS Distributions // Tagged form of changePowerStateToPriv()
2499*c54f35caSApple OSS Distributions //*********************************************************************************
2500*c54f35caSApple OSS Distributions
2501*c54f35caSApple OSS Distributions IOReturn
changePowerStateWithTagToPriv(unsigned long ordinal,IOPMRequestTag tag)2502*c54f35caSApple OSS Distributions IOService::changePowerStateWithTagToPriv( unsigned long ordinal, IOPMRequestTag tag )
2503*c54f35caSApple OSS Distributions {
2504*c54f35caSApple OSS Distributions OUR_PMLog(kPMLogChangeStateToPriv, ordinal, tag);
2505*c54f35caSApple OSS Distributions return requestPowerState(gIOPMPowerClientDevice, ordinal, tag);
2506*c54f35caSApple OSS Distributions }
2507*c54f35caSApple OSS Distributions
2508*c54f35caSApple OSS Distributions //*********************************************************************************
2509*c54f35caSApple OSS Distributions // [public] changePowerStateForRootDomain
2510*c54f35caSApple OSS Distributions //
2511*c54f35caSApple OSS Distributions // Adjust the root domain's power desire on the target
2512*c54f35caSApple OSS Distributions //*********************************************************************************
2513*c54f35caSApple OSS Distributions
2514*c54f35caSApple OSS Distributions IOReturn
changePowerStateForRootDomain(IOPMPowerStateIndex ordinal)2515*c54f35caSApple OSS Distributions IOService::changePowerStateForRootDomain( IOPMPowerStateIndex ordinal )
2516*c54f35caSApple OSS Distributions {
2517*c54f35caSApple OSS Distributions OUR_PMLog(kPMLogChangeStateForRootDomain, ordinal, 0);
2518*c54f35caSApple OSS Distributions return requestPowerState( gIOPMPowerClientRootDomain, ordinal );
2519*c54f35caSApple OSS Distributions }
2520*c54f35caSApple OSS Distributions
2521*c54f35caSApple OSS Distributions //*********************************************************************************
2522*c54f35caSApple OSS Distributions // [public for PMRD] quiescePowerTree
2523*c54f35caSApple OSS Distributions //
2524*c54f35caSApple OSS Distributions // For root domain to issue a request to quiesce the power tree.
2525*c54f35caSApple OSS Distributions // Supplied callback invoked upon completion.
2526*c54f35caSApple OSS Distributions //*********************************************************************************
2527*c54f35caSApple OSS Distributions
2528*c54f35caSApple OSS Distributions IOReturn
quiescePowerTree(void * target,IOPMCompletionAction action,void * param)2529*c54f35caSApple OSS Distributions IOService::quiescePowerTree(
2530*c54f35caSApple OSS Distributions void * target, IOPMCompletionAction action, void * param )
2531*c54f35caSApple OSS Distributions {
2532*c54f35caSApple OSS Distributions IOPMRequest * request;
2533*c54f35caSApple OSS Distributions
2534*c54f35caSApple OSS Distributions if (!initialized) {
2535*c54f35caSApple OSS Distributions return kIOPMNotYetInitialized;
2536*c54f35caSApple OSS Distributions }
2537*c54f35caSApple OSS Distributions if (!target || !action) {
2538*c54f35caSApple OSS Distributions return kIOReturnBadArgument;
2539*c54f35caSApple OSS Distributions }
2540*c54f35caSApple OSS Distributions
2541*c54f35caSApple OSS Distributions OUR_PMLog(kPMLogQuiescePowerTree, 0, 0);
2542*c54f35caSApple OSS Distributions
2543*c54f35caSApple OSS Distributions // Target the root node instead of root domain. This is to avoid blocking
2544*c54f35caSApple OSS Distributions // the quiesce request behind an existing root domain request in the work
2545*c54f35caSApple OSS Distributions // queue. Root parent and root domain requests in the work queue must not
2546*c54f35caSApple OSS Distributions // block the completion of the quiesce request.
2547*c54f35caSApple OSS Distributions
2548*c54f35caSApple OSS Distributions request = acquirePMRequest(gIOPMRootNode, kIOPMRequestTypeQuiescePowerTree);
2549*c54f35caSApple OSS Distributions if (!request) {
2550*c54f35caSApple OSS Distributions return kIOReturnNoMemory;
2551*c54f35caSApple OSS Distributions }
2552*c54f35caSApple OSS Distributions
2553*c54f35caSApple OSS Distributions request->installCompletionAction(target, action, param);
2554*c54f35caSApple OSS Distributions
2555*c54f35caSApple OSS Distributions // Submit through the normal request flow. This will make sure any request
2556*c54f35caSApple OSS Distributions // already in the request queue will get pushed over to the work queue for
2557*c54f35caSApple OSS Distributions // execution. Any request submitted after this request may not be serviced.
2558*c54f35caSApple OSS Distributions
2559*c54f35caSApple OSS Distributions submitPMRequest( request );
2560*c54f35caSApple OSS Distributions return kIOReturnSuccess;
2561*c54f35caSApple OSS Distributions }
2562*c54f35caSApple OSS Distributions
2563*c54f35caSApple OSS Distributions //*********************************************************************************
2564*c54f35caSApple OSS Distributions // [private] requestPowerState
2565*c54f35caSApple OSS Distributions //*********************************************************************************
2566*c54f35caSApple OSS Distributions
2567*c54f35caSApple OSS Distributions IOReturn
requestPowerState(const OSSymbol * client,IOPMPowerStateIndex state,IOPMRequestTag tag)2568*c54f35caSApple OSS Distributions IOService::requestPowerState(
2569*c54f35caSApple OSS Distributions const OSSymbol * client,
2570*c54f35caSApple OSS Distributions IOPMPowerStateIndex state,
2571*c54f35caSApple OSS Distributions IOPMRequestTag tag )
2572*c54f35caSApple OSS Distributions {
2573*c54f35caSApple OSS Distributions IOPMRequest * request;
2574*c54f35caSApple OSS Distributions
2575*c54f35caSApple OSS Distributions if (!client || (state > UINT_MAX)) {
2576*c54f35caSApple OSS Distributions return kIOReturnBadArgument;
2577*c54f35caSApple OSS Distributions }
2578*c54f35caSApple OSS Distributions if (!initialized) {
2579*c54f35caSApple OSS Distributions return kIOPMNotYetInitialized;
2580*c54f35caSApple OSS Distributions }
2581*c54f35caSApple OSS Distributions
2582*c54f35caSApple OSS Distributions request = acquirePMRequest( this, kIOPMRequestTypeRequestPowerState );
2583*c54f35caSApple OSS Distributions if (!request) {
2584*c54f35caSApple OSS Distributions return kIOReturnNoMemory;
2585*c54f35caSApple OSS Distributions }
2586*c54f35caSApple OSS Distributions
2587*c54f35caSApple OSS Distributions client->retain();
2588*c54f35caSApple OSS Distributions request->fTag = tag;
2589*c54f35caSApple OSS Distributions request->fArg0 = (void *)(uintptr_t) state;
2590*c54f35caSApple OSS Distributions request->fArg1 = (void *) client;
2591*c54f35caSApple OSS Distributions request->fArg2 = NULL;
2592*c54f35caSApple OSS Distributions #if NOT_READY
2593*c54f35caSApple OSS Distributions if (action) {
2594*c54f35caSApple OSS Distributions request->installCompletionAction( action, target, param );
2595*c54f35caSApple OSS Distributions }
2596*c54f35caSApple OSS Distributions #endif
2597*c54f35caSApple OSS Distributions
2598*c54f35caSApple OSS Distributions // Prevent needless downwards power transitions by clamping power
2599*c54f35caSApple OSS Distributions // until the scheduled request is executed.
2600*c54f35caSApple OSS Distributions
2601*c54f35caSApple OSS Distributions if (gIOPMWorkLoop->inGate() && (state < fNumberOfPowerStates)) {
2602*c54f35caSApple OSS Distributions fTempClampPowerState = StateMax(fTempClampPowerState, state);
2603*c54f35caSApple OSS Distributions fTempClampCount++;
2604*c54f35caSApple OSS Distributions request->fArg2 = (void *)(uintptr_t) true;
2605*c54f35caSApple OSS Distributions }
2606*c54f35caSApple OSS Distributions
2607*c54f35caSApple OSS Distributions submitPMRequest( request );
2608*c54f35caSApple OSS Distributions return IOPMNoErr;
2609*c54f35caSApple OSS Distributions }
2610*c54f35caSApple OSS Distributions
2611*c54f35caSApple OSS Distributions //*********************************************************************************
2612*c54f35caSApple OSS Distributions // [private] handleRequestPowerState
2613*c54f35caSApple OSS Distributions //*********************************************************************************
2614*c54f35caSApple OSS Distributions
2615*c54f35caSApple OSS Distributions void
handleRequestPowerState(IOPMRequest * request)2616*c54f35caSApple OSS Distributions IOService::handleRequestPowerState( IOPMRequest * request )
2617*c54f35caSApple OSS Distributions {
2618*c54f35caSApple OSS Distributions const OSSymbol * client = (const OSSymbol *) request->fArg1;
2619*c54f35caSApple OSS Distributions IOPMPowerStateIndex state = (IOPMPowerStateIndex) request->fArg0;
2620*c54f35caSApple OSS Distributions
2621*c54f35caSApple OSS Distributions PM_ASSERT_IN_GATE();
2622*c54f35caSApple OSS Distributions if (request->fArg2) {
2623*c54f35caSApple OSS Distributions assert(fTempClampCount != 0);
2624*c54f35caSApple OSS Distributions if (fTempClampCount) {
2625*c54f35caSApple OSS Distributions fTempClampCount--;
2626*c54f35caSApple OSS Distributions }
2627*c54f35caSApple OSS Distributions if (!fTempClampCount) {
2628*c54f35caSApple OSS Distributions fTempClampPowerState = kPowerStateZero;
2629*c54f35caSApple OSS Distributions }
2630*c54f35caSApple OSS Distributions }
2631*c54f35caSApple OSS Distributions
2632*c54f35caSApple OSS Distributions if (fNumberOfPowerStates && (state >= fNumberOfPowerStates)) {
2633*c54f35caSApple OSS Distributions state = fHighestPowerState;
2634*c54f35caSApple OSS Distributions }
2635*c54f35caSApple OSS Distributions
2636*c54f35caSApple OSS Distributions // The power suppression due to changePowerStateWithOverrideTo() expires
2637*c54f35caSApple OSS Distributions // upon the next "device" power request - changePowerStateToPriv().
2638*c54f35caSApple OSS Distributions
2639*c54f35caSApple OSS Distributions if ((getPMRequestType() != kIOPMRequestTypeRequestPowerStateOverride) &&
2640*c54f35caSApple OSS Distributions (client == gIOPMPowerClientDevice)) {
2641*c54f35caSApple OSS Distributions fOverrideMaxPowerState = kIOPMPowerStateMax;
2642*c54f35caSApple OSS Distributions }
2643*c54f35caSApple OSS Distributions
2644*c54f35caSApple OSS Distributions if ((state == kPowerStateZero) &&
2645*c54f35caSApple OSS Distributions (client != gIOPMPowerClientDevice) &&
2646*c54f35caSApple OSS Distributions (client != gIOPMPowerClientDriver) &&
2647*c54f35caSApple OSS Distributions (client != gIOPMPowerClientChildProxy)) {
2648*c54f35caSApple OSS Distributions removePowerClient(client);
2649*c54f35caSApple OSS Distributions } else {
2650*c54f35caSApple OSS Distributions updatePowerClient(client, state);
2651*c54f35caSApple OSS Distributions }
2652*c54f35caSApple OSS Distributions
2653*c54f35caSApple OSS Distributions adjustPowerState();
2654*c54f35caSApple OSS Distributions client->release();
2655*c54f35caSApple OSS Distributions }
2656*c54f35caSApple OSS Distributions
2657*c54f35caSApple OSS Distributions //*********************************************************************************
2658*c54f35caSApple OSS Distributions // [private] Helper functions to update/remove power clients.
2659*c54f35caSApple OSS Distributions //*********************************************************************************
2660*c54f35caSApple OSS Distributions
2661*c54f35caSApple OSS Distributions void
updatePowerClient(const OSSymbol * client,IOPMPowerStateIndex powerState)2662*c54f35caSApple OSS Distributions IOService::updatePowerClient( const OSSymbol * client, IOPMPowerStateIndex powerState )
2663*c54f35caSApple OSS Distributions {
2664*c54f35caSApple OSS Distributions IOPMPowerStateIndex oldPowerState = kPowerStateZero;
2665*c54f35caSApple OSS Distributions
2666*c54f35caSApple OSS Distributions if (powerState > UINT_MAX) {
2667*c54f35caSApple OSS Distributions assert(false);
2668*c54f35caSApple OSS Distributions return;
2669*c54f35caSApple OSS Distributions }
2670*c54f35caSApple OSS Distributions
2671*c54f35caSApple OSS Distributions if (!fPowerClients) {
2672*c54f35caSApple OSS Distributions fPowerClients = OSDictionary::withCapacity(4);
2673*c54f35caSApple OSS Distributions }
2674*c54f35caSApple OSS Distributions if (fPowerClients && client) {
2675*c54f35caSApple OSS Distributions OSNumber * num = (OSNumber *) fPowerClients->getObject(client);
2676*c54f35caSApple OSS Distributions if (num) {
2677*c54f35caSApple OSS Distributions oldPowerState = num->unsigned32BitValue();
2678*c54f35caSApple OSS Distributions num->setValue(powerState);
2679*c54f35caSApple OSS Distributions } else {
2680*c54f35caSApple OSS Distributions num = OSNumber::withNumber(powerState, 32);
2681*c54f35caSApple OSS Distributions if (num) {
2682*c54f35caSApple OSS Distributions fPowerClients->setObject(client, num);
2683*c54f35caSApple OSS Distributions num->release();
2684*c54f35caSApple OSS Distributions }
2685*c54f35caSApple OSS Distributions }
2686*c54f35caSApple OSS Distributions
2687*c54f35caSApple OSS Distributions PM_ACTION_CLIENT(actionUpdatePowerClient, client, oldPowerState, powerState);
2688*c54f35caSApple OSS Distributions }
2689*c54f35caSApple OSS Distributions }
2690*c54f35caSApple OSS Distributions
2691*c54f35caSApple OSS Distributions void
removePowerClient(const OSSymbol * client)2692*c54f35caSApple OSS Distributions IOService::removePowerClient( const OSSymbol * client )
2693*c54f35caSApple OSS Distributions {
2694*c54f35caSApple OSS Distributions if (fPowerClients && client) {
2695*c54f35caSApple OSS Distributions fPowerClients->removeObject(client);
2696*c54f35caSApple OSS Distributions }
2697*c54f35caSApple OSS Distributions }
2698*c54f35caSApple OSS Distributions
2699*c54f35caSApple OSS Distributions IOPMPowerStateIndex
getPowerStateForClient(const OSSymbol * client)2700*c54f35caSApple OSS Distributions IOService::getPowerStateForClient( const OSSymbol * client )
2701*c54f35caSApple OSS Distributions {
2702*c54f35caSApple OSS Distributions IOPMPowerStateIndex powerState = kPowerStateZero;
2703*c54f35caSApple OSS Distributions
2704*c54f35caSApple OSS Distributions if (fPowerClients && client) {
2705*c54f35caSApple OSS Distributions OSNumber * num = (OSNumber *) fPowerClients->getObject(client);
2706*c54f35caSApple OSS Distributions if (num) {
2707*c54f35caSApple OSS Distributions powerState = num->unsigned32BitValue();
2708*c54f35caSApple OSS Distributions }
2709*c54f35caSApple OSS Distributions }
2710*c54f35caSApple OSS Distributions return powerState;
2711*c54f35caSApple OSS Distributions }
2712*c54f35caSApple OSS Distributions
2713*c54f35caSApple OSS Distributions //*********************************************************************************
2714*c54f35caSApple OSS Distributions // [protected] powerOverrideOnPriv
2715*c54f35caSApple OSS Distributions //*********************************************************************************
2716*c54f35caSApple OSS Distributions
2717*c54f35caSApple OSS Distributions IOReturn
powerOverrideOnPriv(void)2718*c54f35caSApple OSS Distributions IOService::powerOverrideOnPriv( void )
2719*c54f35caSApple OSS Distributions {
2720*c54f35caSApple OSS Distributions IOPMRequest * request;
2721*c54f35caSApple OSS Distributions
2722*c54f35caSApple OSS Distributions if (!initialized) {
2723*c54f35caSApple OSS Distributions return IOPMNotYetInitialized;
2724*c54f35caSApple OSS Distributions }
2725*c54f35caSApple OSS Distributions
2726*c54f35caSApple OSS Distributions if (gIOPMWorkLoop->inGate()) {
2727*c54f35caSApple OSS Distributions fDeviceOverrideEnabled = true;
2728*c54f35caSApple OSS Distributions return IOPMNoErr;
2729*c54f35caSApple OSS Distributions }
2730*c54f35caSApple OSS Distributions
2731*c54f35caSApple OSS Distributions request = acquirePMRequest( this, kIOPMRequestTypePowerOverrideOnPriv );
2732*c54f35caSApple OSS Distributions if (!request) {
2733*c54f35caSApple OSS Distributions return kIOReturnNoMemory;
2734*c54f35caSApple OSS Distributions }
2735*c54f35caSApple OSS Distributions
2736*c54f35caSApple OSS Distributions submitPMRequest( request );
2737*c54f35caSApple OSS Distributions return IOPMNoErr;
2738*c54f35caSApple OSS Distributions }
2739*c54f35caSApple OSS Distributions
2740*c54f35caSApple OSS Distributions //*********************************************************************************
2741*c54f35caSApple OSS Distributions // [protected] powerOverrideOffPriv
2742*c54f35caSApple OSS Distributions //*********************************************************************************
2743*c54f35caSApple OSS Distributions
2744*c54f35caSApple OSS Distributions IOReturn
powerOverrideOffPriv(void)2745*c54f35caSApple OSS Distributions IOService::powerOverrideOffPriv( void )
2746*c54f35caSApple OSS Distributions {
2747*c54f35caSApple OSS Distributions IOPMRequest * request;
2748*c54f35caSApple OSS Distributions
2749*c54f35caSApple OSS Distributions if (!initialized) {
2750*c54f35caSApple OSS Distributions return IOPMNotYetInitialized;
2751*c54f35caSApple OSS Distributions }
2752*c54f35caSApple OSS Distributions
2753*c54f35caSApple OSS Distributions if (gIOPMWorkLoop->inGate()) {
2754*c54f35caSApple OSS Distributions fDeviceOverrideEnabled = false;
2755*c54f35caSApple OSS Distributions return IOPMNoErr;
2756*c54f35caSApple OSS Distributions }
2757*c54f35caSApple OSS Distributions
2758*c54f35caSApple OSS Distributions request = acquirePMRequest( this, kIOPMRequestTypePowerOverrideOffPriv );
2759*c54f35caSApple OSS Distributions if (!request) {
2760*c54f35caSApple OSS Distributions return kIOReturnNoMemory;
2761*c54f35caSApple OSS Distributions }
2762*c54f35caSApple OSS Distributions
2763*c54f35caSApple OSS Distributions submitPMRequest( request );
2764*c54f35caSApple OSS Distributions return IOPMNoErr;
2765*c54f35caSApple OSS Distributions }
2766*c54f35caSApple OSS Distributions
2767*c54f35caSApple OSS Distributions //*********************************************************************************
2768*c54f35caSApple OSS Distributions // [private] handlePowerOverrideChanged
2769*c54f35caSApple OSS Distributions //*********************************************************************************
2770*c54f35caSApple OSS Distributions
2771*c54f35caSApple OSS Distributions void
handlePowerOverrideChanged(IOPMRequest * request)2772*c54f35caSApple OSS Distributions IOService::handlePowerOverrideChanged( IOPMRequest * request )
2773*c54f35caSApple OSS Distributions {
2774*c54f35caSApple OSS Distributions PM_ASSERT_IN_GATE();
2775*c54f35caSApple OSS Distributions if (request->getType() == kIOPMRequestTypePowerOverrideOnPriv) {
2776*c54f35caSApple OSS Distributions OUR_PMLog(kPMLogOverrideOn, 0, 0);
2777*c54f35caSApple OSS Distributions fDeviceOverrideEnabled = true;
2778*c54f35caSApple OSS Distributions } else {
2779*c54f35caSApple OSS Distributions OUR_PMLog(kPMLogOverrideOff, 0, 0);
2780*c54f35caSApple OSS Distributions fDeviceOverrideEnabled = false;
2781*c54f35caSApple OSS Distributions }
2782*c54f35caSApple OSS Distributions
2783*c54f35caSApple OSS Distributions adjustPowerState();
2784*c54f35caSApple OSS Distributions }
2785*c54f35caSApple OSS Distributions
2786*c54f35caSApple OSS Distributions //*********************************************************************************
2787*c54f35caSApple OSS Distributions // [private] computeDesiredState
2788*c54f35caSApple OSS Distributions //*********************************************************************************
2789*c54f35caSApple OSS Distributions
2790*c54f35caSApple OSS Distributions void
computeDesiredState(unsigned long localClamp,bool computeOnly)2791*c54f35caSApple OSS Distributions IOService::computeDesiredState( unsigned long localClamp, bool computeOnly )
2792*c54f35caSApple OSS Distributions {
2793*c54f35caSApple OSS Distributions OSIterator * iter;
2794*c54f35caSApple OSS Distributions OSObject * next;
2795*c54f35caSApple OSS Distributions IOPowerConnection * connection;
2796*c54f35caSApple OSS Distributions IOPMPowerStateIndex desiredState = kPowerStateZero;
2797*c54f35caSApple OSS Distributions IOPMPowerStateIndex newPowerState = kPowerStateZero;
2798*c54f35caSApple OSS Distributions bool hasChildren = false;
2799*c54f35caSApple OSS Distributions
2800*c54f35caSApple OSS Distributions // Desired power state is always 0 without a controlling driver.
2801*c54f35caSApple OSS Distributions
2802*c54f35caSApple OSS Distributions if (!fNumberOfPowerStates) {
2803*c54f35caSApple OSS Distributions fDesiredPowerState = kPowerStateZero;
2804*c54f35caSApple OSS Distributions return;
2805*c54f35caSApple OSS Distributions }
2806*c54f35caSApple OSS Distributions
2807*c54f35caSApple OSS Distributions // Examine the children's desired power state.
2808*c54f35caSApple OSS Distributions
2809*c54f35caSApple OSS Distributions iter = getChildIterator(gIOPowerPlane);
2810*c54f35caSApple OSS Distributions if (iter) {
2811*c54f35caSApple OSS Distributions while ((next = iter->getNextObject())) {
2812*c54f35caSApple OSS Distributions if ((connection = OSDynamicCast(IOPowerConnection, next))) {
2813*c54f35caSApple OSS Distributions if (connection->getReadyFlag() == false) {
2814*c54f35caSApple OSS Distributions PM_LOG3("[%s] %s: connection not ready\n",
2815*c54f35caSApple OSS Distributions getName(), __FUNCTION__);
2816*c54f35caSApple OSS Distributions continue;
2817*c54f35caSApple OSS Distributions }
2818*c54f35caSApple OSS Distributions if (connection->childHasRequestedPower()) {
2819*c54f35caSApple OSS Distributions hasChildren = true;
2820*c54f35caSApple OSS Distributions }
2821*c54f35caSApple OSS Distributions desiredState = StateMax(connection->getDesiredDomainState(), desiredState);
2822*c54f35caSApple OSS Distributions }
2823*c54f35caSApple OSS Distributions }
2824*c54f35caSApple OSS Distributions iter->release();
2825*c54f35caSApple OSS Distributions }
2826*c54f35caSApple OSS Distributions if (hasChildren) {
2827*c54f35caSApple OSS Distributions updatePowerClient(gIOPMPowerClientChildren, desiredState);
2828*c54f35caSApple OSS Distributions } else {
2829*c54f35caSApple OSS Distributions removePowerClient(gIOPMPowerClientChildren);
2830*c54f35caSApple OSS Distributions }
2831*c54f35caSApple OSS Distributions
2832*c54f35caSApple OSS Distributions // Iterate through all power clients to determine the min power state.
2833*c54f35caSApple OSS Distributions
2834*c54f35caSApple OSS Distributions iter = OSCollectionIterator::withCollection(fPowerClients);
2835*c54f35caSApple OSS Distributions if (iter) {
2836*c54f35caSApple OSS Distributions const OSSymbol * client;
2837*c54f35caSApple OSS Distributions while ((client = (const OSSymbol *) iter->getNextObject())) {
2838*c54f35caSApple OSS Distributions // Ignore child and driver when override is in effect.
2839*c54f35caSApple OSS Distributions if ((fDeviceOverrideEnabled ||
2840*c54f35caSApple OSS Distributions (getPMRequestType() == kIOPMRequestTypeRequestPowerStateOverride)) &&
2841*c54f35caSApple OSS Distributions ((client == gIOPMPowerClientChildren) ||
2842*c54f35caSApple OSS Distributions (client == gIOPMPowerClientDriver))) {
2843*c54f35caSApple OSS Distributions continue;
2844*c54f35caSApple OSS Distributions }
2845*c54f35caSApple OSS Distributions
2846*c54f35caSApple OSS Distributions // Ignore child proxy when children are present.
2847*c54f35caSApple OSS Distributions if (hasChildren && (client == gIOPMPowerClientChildProxy)) {
2848*c54f35caSApple OSS Distributions continue;
2849*c54f35caSApple OSS Distributions }
2850*c54f35caSApple OSS Distributions
2851*c54f35caSApple OSS Distributions // Advisory tickles are irrelevant unless system is in full wake
2852*c54f35caSApple OSS Distributions if (client == gIOPMPowerClientAdvisoryTickle &&
2853*c54f35caSApple OSS Distributions !gIOPMAdvisoryTickleEnabled) {
2854*c54f35caSApple OSS Distributions continue;
2855*c54f35caSApple OSS Distributions }
2856*c54f35caSApple OSS Distributions
2857*c54f35caSApple OSS Distributions desiredState = getPowerStateForClient(client);
2858*c54f35caSApple OSS Distributions assert(desiredState < fNumberOfPowerStates);
2859*c54f35caSApple OSS Distributions PM_LOG1(" %u %s\n",
2860*c54f35caSApple OSS Distributions (uint32_t) desiredState, client->getCStringNoCopy());
2861*c54f35caSApple OSS Distributions
2862*c54f35caSApple OSS Distributions newPowerState = StateMax(newPowerState, desiredState);
2863*c54f35caSApple OSS Distributions
2864*c54f35caSApple OSS Distributions if (client == gIOPMPowerClientDevice) {
2865*c54f35caSApple OSS Distributions fDeviceDesire = desiredState;
2866*c54f35caSApple OSS Distributions }
2867*c54f35caSApple OSS Distributions }
2868*c54f35caSApple OSS Distributions iter->release();
2869*c54f35caSApple OSS Distributions }
2870*c54f35caSApple OSS Distributions
2871*c54f35caSApple OSS Distributions // Factor in the temporary power desires.
2872*c54f35caSApple OSS Distributions
2873*c54f35caSApple OSS Distributions newPowerState = StateMax(newPowerState, localClamp);
2874*c54f35caSApple OSS Distributions newPowerState = StateMax(newPowerState, fTempClampPowerState);
2875*c54f35caSApple OSS Distributions
2876*c54f35caSApple OSS Distributions // Limit check against max power override.
2877*c54f35caSApple OSS Distributions
2878*c54f35caSApple OSS Distributions newPowerState = StateMin(newPowerState, fOverrideMaxPowerState);
2879*c54f35caSApple OSS Distributions
2880*c54f35caSApple OSS Distributions // Limit check against number of power states.
2881*c54f35caSApple OSS Distributions
2882*c54f35caSApple OSS Distributions if (newPowerState >= fNumberOfPowerStates) {
2883*c54f35caSApple OSS Distributions newPowerState = fHighestPowerState;
2884*c54f35caSApple OSS Distributions }
2885*c54f35caSApple OSS Distributions
2886*c54f35caSApple OSS Distributions if (getPMRootDomain()->isAOTMode()) {
2887*c54f35caSApple OSS Distributions if ((kIOPMPreventIdleSleep & fPowerStates[newPowerState].capabilityFlags)
2888*c54f35caSApple OSS Distributions && !(kIOPMPreventIdleSleep & fPowerStates[fDesiredPowerState].capabilityFlags)) {
2889*c54f35caSApple OSS Distributions getPMRootDomain()->claimSystemWakeEvent(this, kIOPMWakeEventAOTExit, getName(), NULL);
2890*c54f35caSApple OSS Distributions }
2891*c54f35caSApple OSS Distributions }
2892*c54f35caSApple OSS Distributions
2893*c54f35caSApple OSS Distributions fDesiredPowerState = newPowerState;
2894*c54f35caSApple OSS Distributions
2895*c54f35caSApple OSS Distributions PM_LOG1(" temp %u, clamp %u, current %u, new %u\n",
2896*c54f35caSApple OSS Distributions (uint32_t) localClamp, (uint32_t) fTempClampPowerState,
2897*c54f35caSApple OSS Distributions (uint32_t) fCurrentPowerState, (uint32_t) newPowerState);
2898*c54f35caSApple OSS Distributions
2899*c54f35caSApple OSS Distributions if (!computeOnly) {
2900*c54f35caSApple OSS Distributions // Restart idle timer if possible when device desire has increased.
2901*c54f35caSApple OSS Distributions // Or if an advisory desire exists.
2902*c54f35caSApple OSS Distributions
2903*c54f35caSApple OSS Distributions if (fIdleTimerPeriod && fIdleTimerStopped) {
2904*c54f35caSApple OSS Distributions restartIdleTimer();
2905*c54f35caSApple OSS Distributions }
2906*c54f35caSApple OSS Distributions
2907*c54f35caSApple OSS Distributions // Invalidate cached tickle power state when desires change, and not
2908*c54f35caSApple OSS Distributions // due to a tickle request. In case the driver has requested a lower
2909*c54f35caSApple OSS Distributions // power state, but the tickle is caching a higher power state which
2910*c54f35caSApple OSS Distributions // will drop future tickles until the cached value is lowered or in-
2911*c54f35caSApple OSS Distributions // validated. The invalidation must occur before the power transition
2912*c54f35caSApple OSS Distributions // to avoid dropping a necessary tickle.
2913*c54f35caSApple OSS Distributions
2914*c54f35caSApple OSS Distributions if ((getPMRequestType() != kIOPMRequestTypeActivityTickle) &&
2915*c54f35caSApple OSS Distributions (fActivityTicklePowerState != kInvalidTicklePowerState)) {
2916*c54f35caSApple OSS Distributions IOLockLock(fActivityLock);
2917*c54f35caSApple OSS Distributions fActivityTicklePowerState = kInvalidTicklePowerState;
2918*c54f35caSApple OSS Distributions IOLockUnlock(fActivityLock);
2919*c54f35caSApple OSS Distributions }
2920*c54f35caSApple OSS Distributions }
2921*c54f35caSApple OSS Distributions }
2922*c54f35caSApple OSS Distributions
2923*c54f35caSApple OSS Distributions //*********************************************************************************
2924*c54f35caSApple OSS Distributions // [public] currentPowerConsumption
2925*c54f35caSApple OSS Distributions //
2926*c54f35caSApple OSS Distributions //*********************************************************************************
2927*c54f35caSApple OSS Distributions
2928*c54f35caSApple OSS Distributions unsigned long
currentPowerConsumption(void)2929*c54f35caSApple OSS Distributions IOService::currentPowerConsumption( void )
2930*c54f35caSApple OSS Distributions {
2931*c54f35caSApple OSS Distributions if (!initialized) {
2932*c54f35caSApple OSS Distributions return kIOPMUnknown;
2933*c54f35caSApple OSS Distributions }
2934*c54f35caSApple OSS Distributions
2935*c54f35caSApple OSS Distributions return fCurrentPowerConsumption;
2936*c54f35caSApple OSS Distributions }
2937*c54f35caSApple OSS Distributions
2938*c54f35caSApple OSS Distributions //*********************************************************************************
2939*c54f35caSApple OSS Distributions // [deprecated] getPMworkloop
2940*c54f35caSApple OSS Distributions //*********************************************************************************
2941*c54f35caSApple OSS Distributions
2942*c54f35caSApple OSS Distributions #ifndef __LP64__
2943*c54f35caSApple OSS Distributions IOWorkLoop *
getPMworkloop(void)2944*c54f35caSApple OSS Distributions IOService::getPMworkloop( void )
2945*c54f35caSApple OSS Distributions {
2946*c54f35caSApple OSS Distributions return gIOPMWorkLoop;
2947*c54f35caSApple OSS Distributions }
2948*c54f35caSApple OSS Distributions #endif
2949*c54f35caSApple OSS Distributions
2950*c54f35caSApple OSS Distributions #if NOT_YET
2951*c54f35caSApple OSS Distributions
2952*c54f35caSApple OSS Distributions //*********************************************************************************
2953*c54f35caSApple OSS Distributions // Power Parent/Children Applier
2954*c54f35caSApple OSS Distributions //*********************************************************************************
2955*c54f35caSApple OSS Distributions
2956*c54f35caSApple OSS Distributions static void
applyToPowerChildren(IOService * service,IOServiceApplierFunction applier,void * context,IOOptionBits options)2957*c54f35caSApple OSS Distributions applyToPowerChildren(
2958*c54f35caSApple OSS Distributions IOService * service,
2959*c54f35caSApple OSS Distributions IOServiceApplierFunction applier,
2960*c54f35caSApple OSS Distributions void * context,
2961*c54f35caSApple OSS Distributions IOOptionBits options )
2962*c54f35caSApple OSS Distributions {
2963*c54f35caSApple OSS Distributions PM_ASSERT_IN_GATE();
2964*c54f35caSApple OSS Distributions
2965*c54f35caSApple OSS Distributions IORegistryEntry * entry;
2966*c54f35caSApple OSS Distributions IORegistryIterator * iter;
2967*c54f35caSApple OSS Distributions IOPowerConnection * connection;
2968*c54f35caSApple OSS Distributions IOService * child;
2969*c54f35caSApple OSS Distributions
2970*c54f35caSApple OSS Distributions iter = IORegistryIterator::iterateOver(service, gIOPowerPlane, options);
2971*c54f35caSApple OSS Distributions if (iter) {
2972*c54f35caSApple OSS Distributions while ((entry = iter->getNextObject())) {
2973*c54f35caSApple OSS Distributions // Get child of IOPowerConnection objects
2974*c54f35caSApple OSS Distributions if ((connection = OSDynamicCast(IOPowerConnection, entry))) {
2975*c54f35caSApple OSS Distributions child = (IOService *) connection->copyChildEntry(gIOPowerPlane);
2976*c54f35caSApple OSS Distributions if (child) {
2977*c54f35caSApple OSS Distributions (*applier)(child, context);
2978*c54f35caSApple OSS Distributions child->release();
2979*c54f35caSApple OSS Distributions }
2980*c54f35caSApple OSS Distributions }
2981*c54f35caSApple OSS Distributions }
2982*c54f35caSApple OSS Distributions iter->release();
2983*c54f35caSApple OSS Distributions }
2984*c54f35caSApple OSS Distributions }
2985*c54f35caSApple OSS Distributions
2986*c54f35caSApple OSS Distributions static void
applyToPowerParent(IOService * service,IOServiceApplierFunction applier,void * context,IOOptionBits options)2987*c54f35caSApple OSS Distributions applyToPowerParent(
2988*c54f35caSApple OSS Distributions IOService * service,
2989*c54f35caSApple OSS Distributions IOServiceApplierFunction applier,
2990*c54f35caSApple OSS Distributions void * context,
2991*c54f35caSApple OSS Distributions IOOptionBits options )
2992*c54f35caSApple OSS Distributions {
2993*c54f35caSApple OSS Distributions PM_ASSERT_IN_GATE();
2994*c54f35caSApple OSS Distributions
2995*c54f35caSApple OSS Distributions IORegistryEntry * entry;
2996*c54f35caSApple OSS Distributions IORegistryIterator * iter;
2997*c54f35caSApple OSS Distributions IOPowerConnection * connection;
2998*c54f35caSApple OSS Distributions IOService * parent;
2999*c54f35caSApple OSS Distributions
3000*c54f35caSApple OSS Distributions iter = IORegistryIterator::iterateOver(service, gIOPowerPlane,
3001*c54f35caSApple OSS Distributions options | kIORegistryIterateParents);
3002*c54f35caSApple OSS Distributions if (iter) {
3003*c54f35caSApple OSS Distributions while ((entry = iter->getNextObject())) {
3004*c54f35caSApple OSS Distributions // Get child of IOPowerConnection objects
3005*c54f35caSApple OSS Distributions if ((connection = OSDynamicCast(IOPowerConnection, entry))) {
3006*c54f35caSApple OSS Distributions parent = (IOService *) connection->copyParentEntry(gIOPowerPlane);
3007*c54f35caSApple OSS Distributions if (parent) {
3008*c54f35caSApple OSS Distributions (*applier)(parent, context);
3009*c54f35caSApple OSS Distributions parent->release();
3010*c54f35caSApple OSS Distributions }
3011*c54f35caSApple OSS Distributions }
3012*c54f35caSApple OSS Distributions }
3013*c54f35caSApple OSS Distributions iter->release();
3014*c54f35caSApple OSS Distributions }
3015*c54f35caSApple OSS Distributions }
3016*c54f35caSApple OSS Distributions
3017*c54f35caSApple OSS Distributions #endif /* NOT_YET */
3018*c54f35caSApple OSS Distributions
3019*c54f35caSApple OSS Distributions // MARK: -
3020*c54f35caSApple OSS Distributions // MARK: Activity Tickle & Idle Timer
3021*c54f35caSApple OSS Distributions
3022*c54f35caSApple OSS Distributions void
setAdvisoryTickleEnable(bool enable)3023*c54f35caSApple OSS Distributions IOService::setAdvisoryTickleEnable( bool enable )
3024*c54f35caSApple OSS Distributions {
3025*c54f35caSApple OSS Distributions gIOPMAdvisoryTickleEnabled = enable;
3026*c54f35caSApple OSS Distributions }
3027*c54f35caSApple OSS Distributions
3028*c54f35caSApple OSS Distributions //*********************************************************************************
3029*c54f35caSApple OSS Distributions // [public] activityTickle
3030*c54f35caSApple OSS Distributions //
3031*c54f35caSApple OSS Distributions // The tickle with parameter kIOPMSuperclassPolicy1 causes the activity
3032*c54f35caSApple OSS Distributions // flag to be set, and the device state checked. If the device has been
3033*c54f35caSApple OSS Distributions // powered down, it is powered up again.
3034*c54f35caSApple OSS Distributions // The tickle with parameter kIOPMSubclassPolicy is ignored here and
3035*c54f35caSApple OSS Distributions // should be intercepted by a subclass.
3036*c54f35caSApple OSS Distributions //*********************************************************************************
3037*c54f35caSApple OSS Distributions
3038*c54f35caSApple OSS Distributions bool
activityTickle(unsigned long type,unsigned long stateNumber)3039*c54f35caSApple OSS Distributions IOService::activityTickle( unsigned long type, unsigned long stateNumber )
3040*c54f35caSApple OSS Distributions {
3041*c54f35caSApple OSS Distributions if (!initialized) {
3042*c54f35caSApple OSS Distributions return true; // no power change
3043*c54f35caSApple OSS Distributions }
3044*c54f35caSApple OSS Distributions
3045*c54f35caSApple OSS Distributions if (!fPowerStates) {
3046*c54f35caSApple OSS Distributions // registerPowerDriver may not have completed
3047*c54f35caSApple OSS Distributions IOPMRequest * request;
3048*c54f35caSApple OSS Distributions
3049*c54f35caSApple OSS Distributions request = acquirePMRequest( this, kIOPMRequestTypeDeferredActivityTickle );
3050*c54f35caSApple OSS Distributions if (request) {
3051*c54f35caSApple OSS Distributions request->fArg0 = (void *) type;
3052*c54f35caSApple OSS Distributions request->fArg1 = (void *)(uintptr_t) stateNumber;
3053*c54f35caSApple OSS Distributions submitPMRequest(request);
3054*c54f35caSApple OSS Distributions }
3055*c54f35caSApple OSS Distributions // Returns false if the activityTickle might cause a transition to a
3056*c54f35caSApple OSS Distributions // higher powered state. We don't know, so this seems safest.
3057*c54f35caSApple OSS Distributions return false;
3058*c54f35caSApple OSS Distributions }
3059*c54f35caSApple OSS Distributions
3060*c54f35caSApple OSS Distributions return _activityTickle(type, stateNumber);
3061*c54f35caSApple OSS Distributions }
3062*c54f35caSApple OSS Distributions
3063*c54f35caSApple OSS Distributions //*********************************************************************************
3064*c54f35caSApple OSS Distributions // [private] handleDeferredActivityTickle
3065*c54f35caSApple OSS Distributions //*********************************************************************************
3066*c54f35caSApple OSS Distributions
3067*c54f35caSApple OSS Distributions void
handleDeferredActivityTickle(IOPMRequest * request)3068*c54f35caSApple OSS Distributions IOService::handleDeferredActivityTickle( IOPMRequest * request )
3069*c54f35caSApple OSS Distributions {
3070*c54f35caSApple OSS Distributions unsigned long type = (unsigned long) request->fArg1;
3071*c54f35caSApple OSS Distributions unsigned long stateNumber = (unsigned long) request->fArg2;
3072*c54f35caSApple OSS Distributions
3073*c54f35caSApple OSS Distributions if (!fPowerStates) {
3074*c54f35caSApple OSS Distributions // registerPowerDriver was not called before activityTickle()
3075*c54f35caSApple OSS Distributions return;
3076*c54f35caSApple OSS Distributions }
3077*c54f35caSApple OSS Distributions (void) _activityTickle(type, stateNumber);
3078*c54f35caSApple OSS Distributions }
3079*c54f35caSApple OSS Distributions
3080*c54f35caSApple OSS Distributions //*********************************************************************************
3081*c54f35caSApple OSS Distributions // [private] _activityTickle
3082*c54f35caSApple OSS Distributions //
3083*c54f35caSApple OSS Distributions // The tickle with parameter kIOPMSuperclassPolicy1 causes the activity
3084*c54f35caSApple OSS Distributions // flag to be set, and the device state checked. If the device has been
3085*c54f35caSApple OSS Distributions // powered down, it is powered up again.
3086*c54f35caSApple OSS Distributions // The tickle with parameter kIOPMSubclassPolicy is ignored here and
3087*c54f35caSApple OSS Distributions // should be intercepted by a subclass.
3088*c54f35caSApple OSS Distributions //*********************************************************************************
3089*c54f35caSApple OSS Distributions
3090*c54f35caSApple OSS Distributions bool
_activityTickle(unsigned long type,unsigned long stateNumber)3091*c54f35caSApple OSS Distributions IOService::_activityTickle( unsigned long type, unsigned long stateNumber )
3092*c54f35caSApple OSS Distributions {
3093*c54f35caSApple OSS Distributions IOPMRequest * request;
3094*c54f35caSApple OSS Distributions bool noPowerChange = true;
3095*c54f35caSApple OSS Distributions uint32_t tickleFlags;
3096*c54f35caSApple OSS Distributions
3097*c54f35caSApple OSS Distributions if ((type == kIOPMSuperclassPolicy1) && StateOrder(stateNumber)) {
3098*c54f35caSApple OSS Distributions IOLockLock(fActivityLock);
3099*c54f35caSApple OSS Distributions
3100*c54f35caSApple OSS Distributions // Record device activity for the idle timer handler.
3101*c54f35caSApple OSS Distributions
3102*c54f35caSApple OSS Distributions fDeviceWasActive = true;
3103*c54f35caSApple OSS Distributions fActivityTickleCount++;
3104*c54f35caSApple OSS Distributions clock_get_uptime(&fDeviceActiveTimestamp);
3105*c54f35caSApple OSS Distributions
3106*c54f35caSApple OSS Distributions PM_ACTION_TICKLE(actionActivityTickle);
3107*c54f35caSApple OSS Distributions
3108*c54f35caSApple OSS Distributions // Record the last tickle power state.
3109*c54f35caSApple OSS Distributions // This helps to filter out redundant tickles as
3110*c54f35caSApple OSS Distributions // this function may be called from the data path.
3111*c54f35caSApple OSS Distributions
3112*c54f35caSApple OSS Distributions if ((fActivityTicklePowerState == kInvalidTicklePowerState)
3113*c54f35caSApple OSS Distributions || StateOrder(fActivityTicklePowerState) < StateOrder(stateNumber)) {
3114*c54f35caSApple OSS Distributions fActivityTicklePowerState = stateNumber;
3115*c54f35caSApple OSS Distributions noPowerChange = false;
3116*c54f35caSApple OSS Distributions
3117*c54f35caSApple OSS Distributions tickleFlags = kTickleTypeActivity | kTickleTypePowerRise;
3118*c54f35caSApple OSS Distributions request = acquirePMRequest( this, kIOPMRequestTypeActivityTickle );
3119*c54f35caSApple OSS Distributions if (request) {
3120*c54f35caSApple OSS Distributions request->fArg0 = (void *) stateNumber;
3121*c54f35caSApple OSS Distributions request->fArg1 = (void *)(uintptr_t) tickleFlags;
3122*c54f35caSApple OSS Distributions request->fArg2 = (void *)(uintptr_t) gIOPMTickleGeneration;
3123*c54f35caSApple OSS Distributions submitPMRequest(request);
3124*c54f35caSApple OSS Distributions }
3125*c54f35caSApple OSS Distributions }
3126*c54f35caSApple OSS Distributions
3127*c54f35caSApple OSS Distributions IOLockUnlock(fActivityLock);
3128*c54f35caSApple OSS Distributions } else if ((type == kIOPMActivityTickleTypeAdvisory) &&
3129*c54f35caSApple OSS Distributions ((stateNumber = fDeviceUsablePowerState) != kPowerStateZero)) {
3130*c54f35caSApple OSS Distributions IOLockLock(fActivityLock);
3131*c54f35caSApple OSS Distributions
3132*c54f35caSApple OSS Distributions fAdvisoryTickled = true;
3133*c54f35caSApple OSS Distributions
3134*c54f35caSApple OSS Distributions if (fAdvisoryTicklePowerState != stateNumber) {
3135*c54f35caSApple OSS Distributions fAdvisoryTicklePowerState = stateNumber;
3136*c54f35caSApple OSS Distributions noPowerChange = false;
3137*c54f35caSApple OSS Distributions
3138*c54f35caSApple OSS Distributions tickleFlags = kTickleTypeAdvisory | kTickleTypePowerRise;
3139*c54f35caSApple OSS Distributions request = acquirePMRequest( this, kIOPMRequestTypeActivityTickle );
3140*c54f35caSApple OSS Distributions if (request) {
3141*c54f35caSApple OSS Distributions request->fArg0 = (void *) stateNumber;
3142*c54f35caSApple OSS Distributions request->fArg1 = (void *)(uintptr_t) tickleFlags;
3143*c54f35caSApple OSS Distributions request->fArg2 = (void *)(uintptr_t) gIOPMTickleGeneration;
3144*c54f35caSApple OSS Distributions submitPMRequest(request);
3145*c54f35caSApple OSS Distributions }
3146*c54f35caSApple OSS Distributions }
3147*c54f35caSApple OSS Distributions
3148*c54f35caSApple OSS Distributions IOLockUnlock(fActivityLock);
3149*c54f35caSApple OSS Distributions }
3150*c54f35caSApple OSS Distributions
3151*c54f35caSApple OSS Distributions // Returns false if the activityTickle might cause a transition to a
3152*c54f35caSApple OSS Distributions // higher powered state, true otherwise.
3153*c54f35caSApple OSS Distributions
3154*c54f35caSApple OSS Distributions return noPowerChange;
3155*c54f35caSApple OSS Distributions }
3156*c54f35caSApple OSS Distributions
3157*c54f35caSApple OSS Distributions //*********************************************************************************
3158*c54f35caSApple OSS Distributions // [private] handleActivityTickle
3159*c54f35caSApple OSS Distributions //*********************************************************************************
3160*c54f35caSApple OSS Distributions
3161*c54f35caSApple OSS Distributions void
handleActivityTickle(IOPMRequest * request)3162*c54f35caSApple OSS Distributions IOService::handleActivityTickle( IOPMRequest * request )
3163*c54f35caSApple OSS Distributions {
3164*c54f35caSApple OSS Distributions IOPMPowerStateIndex ticklePowerState = (IOPMPowerStateIndex) request->fArg0;
3165*c54f35caSApple OSS Distributions IOPMPowerStateIndex tickleFlags = (IOPMPowerStateIndex) request->fArg1;
3166*c54f35caSApple OSS Distributions uint32_t tickleGeneration = (uint32_t)(uintptr_t) request->fArg2;
3167*c54f35caSApple OSS Distributions bool adjustPower = false;
3168*c54f35caSApple OSS Distributions
3169*c54f35caSApple OSS Distributions PM_ASSERT_IN_GATE();
3170*c54f35caSApple OSS Distributions if (fResetPowerStateOnWake && (tickleGeneration != gIOPMTickleGeneration)) {
3171*c54f35caSApple OSS Distributions // Drivers that don't want power restored on wake will drop any
3172*c54f35caSApple OSS Distributions // tickles that pre-dates the current system wake. The model is
3173*c54f35caSApple OSS Distributions // that each wake is a fresh start, with power state depressed
3174*c54f35caSApple OSS Distributions // until a new tickle or an explicit power up request from the
3175*c54f35caSApple OSS Distributions // driver. It is possible for the PM work loop to enter the
3176*c54f35caSApple OSS Distributions // system sleep path with tickle requests queued.
3177*c54f35caSApple OSS Distributions
3178*c54f35caSApple OSS Distributions return;
3179*c54f35caSApple OSS Distributions }
3180*c54f35caSApple OSS Distributions
3181*c54f35caSApple OSS Distributions if (tickleFlags & kTickleTypeActivity) {
3182*c54f35caSApple OSS Distributions IOPMPowerStateIndex deviceDesireOrder = StateOrder(fDeviceDesire);
3183*c54f35caSApple OSS Distributions IOPMPowerStateIndex idleTimerGeneration = ticklePowerState; // kTickleTypePowerDrop
3184*c54f35caSApple OSS Distributions
3185*c54f35caSApple OSS Distributions if (tickleFlags & kTickleTypePowerRise) {
3186*c54f35caSApple OSS Distributions if ((StateOrder(ticklePowerState) > deviceDesireOrder) &&
3187*c54f35caSApple OSS Distributions (ticklePowerState < fNumberOfPowerStates)) {
3188*c54f35caSApple OSS Distributions fIdleTimerMinPowerState = ticklePowerState;
3189*c54f35caSApple OSS Distributions updatePowerClient(gIOPMPowerClientDevice, ticklePowerState);
3190*c54f35caSApple OSS Distributions adjustPower = true;
3191*c54f35caSApple OSS Distributions }
3192*c54f35caSApple OSS Distributions } else if ((deviceDesireOrder > StateOrder(fIdleTimerMinPowerState)) &&
3193*c54f35caSApple OSS Distributions (idleTimerGeneration == fIdleTimerGeneration)) {
3194*c54f35caSApple OSS Distributions // Power drop due to idle timer expiration.
3195*c54f35caSApple OSS Distributions // Do not allow idle timer to reduce power below tickle power.
3196*c54f35caSApple OSS Distributions // This prevents the idle timer from decreasing the device desire
3197*c54f35caSApple OSS Distributions // to zero and cancelling the effect of a pre-sleep tickle when
3198*c54f35caSApple OSS Distributions // system wakes up to doze state, while the device is unable to
3199*c54f35caSApple OSS Distributions // raise its power state to satisfy the tickle.
3200*c54f35caSApple OSS Distributions
3201*c54f35caSApple OSS Distributions deviceDesireOrder--;
3202*c54f35caSApple OSS Distributions if (deviceDesireOrder < fNumberOfPowerStates) {
3203*c54f35caSApple OSS Distributions ticklePowerState = fPowerStates[deviceDesireOrder].stateOrderToIndex;
3204*c54f35caSApple OSS Distributions updatePowerClient(gIOPMPowerClientDevice, ticklePowerState);
3205*c54f35caSApple OSS Distributions adjustPower = true;
3206*c54f35caSApple OSS Distributions }
3207*c54f35caSApple OSS Distributions }
3208*c54f35caSApple OSS Distributions } else { // advisory tickle
3209*c54f35caSApple OSS Distributions if (tickleFlags & kTickleTypePowerRise) {
3210*c54f35caSApple OSS Distributions if ((ticklePowerState == fDeviceUsablePowerState) &&
3211*c54f35caSApple OSS Distributions (ticklePowerState < fNumberOfPowerStates)) {
3212*c54f35caSApple OSS Distributions updatePowerClient(gIOPMPowerClientAdvisoryTickle, ticklePowerState);
3213*c54f35caSApple OSS Distributions fHasAdvisoryDesire = true;
3214*c54f35caSApple OSS Distributions fAdvisoryTickleUsed = true;
3215*c54f35caSApple OSS Distributions adjustPower = true;
3216*c54f35caSApple OSS Distributions } else {
3217*c54f35caSApple OSS Distributions IOLockLock(fActivityLock);
3218*c54f35caSApple OSS Distributions fAdvisoryTicklePowerState = kInvalidTicklePowerState;
3219*c54f35caSApple OSS Distributions IOLockUnlock(fActivityLock);
3220*c54f35caSApple OSS Distributions }
3221*c54f35caSApple OSS Distributions } else if (fHasAdvisoryDesire) {
3222*c54f35caSApple OSS Distributions removePowerClient(gIOPMPowerClientAdvisoryTickle);
3223*c54f35caSApple OSS Distributions fHasAdvisoryDesire = false;
3224*c54f35caSApple OSS Distributions adjustPower = true;
3225*c54f35caSApple OSS Distributions }
3226*c54f35caSApple OSS Distributions }
3227*c54f35caSApple OSS Distributions
3228*c54f35caSApple OSS Distributions if (adjustPower) {
3229*c54f35caSApple OSS Distributions adjustPowerState();
3230*c54f35caSApple OSS Distributions }
3231*c54f35caSApple OSS Distributions }
3232*c54f35caSApple OSS Distributions
3233*c54f35caSApple OSS Distributions //******************************************************************************
3234*c54f35caSApple OSS Distributions // [public] setIdleTimerPeriod
3235*c54f35caSApple OSS Distributions //
3236*c54f35caSApple OSS Distributions // A subclass policy-maker is using our standard idleness detection service.
3237*c54f35caSApple OSS Distributions // Start the idle timer. Period is in seconds.
3238*c54f35caSApple OSS Distributions //******************************************************************************
3239*c54f35caSApple OSS Distributions
3240*c54f35caSApple OSS Distributions IOReturn
setIdleTimerPeriod(unsigned long period)3241*c54f35caSApple OSS Distributions IOService::setIdleTimerPeriod( unsigned long period )
3242*c54f35caSApple OSS Distributions {
3243*c54f35caSApple OSS Distributions if (!initialized) {
3244*c54f35caSApple OSS Distributions return IOPMNotYetInitialized;
3245*c54f35caSApple OSS Distributions }
3246*c54f35caSApple OSS Distributions
3247*c54f35caSApple OSS Distributions OUR_PMLog(kPMLogSetIdleTimerPeriod, period, fIdleTimerPeriod);
3248*c54f35caSApple OSS Distributions
3249*c54f35caSApple OSS Distributions if (period > INT_MAX) {
3250*c54f35caSApple OSS Distributions return kIOReturnBadArgument;
3251*c54f35caSApple OSS Distributions }
3252*c54f35caSApple OSS Distributions
3253*c54f35caSApple OSS Distributions IOPMRequest * request =
3254*c54f35caSApple OSS Distributions acquirePMRequest( this, kIOPMRequestTypeSetIdleTimerPeriod );
3255*c54f35caSApple OSS Distributions if (!request) {
3256*c54f35caSApple OSS Distributions return kIOReturnNoMemory;
3257*c54f35caSApple OSS Distributions }
3258*c54f35caSApple OSS Distributions
3259*c54f35caSApple OSS Distributions request->fArg0 = (void *) period;
3260*c54f35caSApple OSS Distributions submitPMRequest( request );
3261*c54f35caSApple OSS Distributions
3262*c54f35caSApple OSS Distributions return kIOReturnSuccess;
3263*c54f35caSApple OSS Distributions }
3264*c54f35caSApple OSS Distributions
3265*c54f35caSApple OSS Distributions IOReturn
setIgnoreIdleTimer(bool ignore)3266*c54f35caSApple OSS Distributions IOService::setIgnoreIdleTimer( bool ignore )
3267*c54f35caSApple OSS Distributions {
3268*c54f35caSApple OSS Distributions if (!initialized) {
3269*c54f35caSApple OSS Distributions return IOPMNotYetInitialized;
3270*c54f35caSApple OSS Distributions }
3271*c54f35caSApple OSS Distributions
3272*c54f35caSApple OSS Distributions OUR_PMLog(kIOPMRequestTypeIgnoreIdleTimer, ignore, 0);
3273*c54f35caSApple OSS Distributions
3274*c54f35caSApple OSS Distributions IOPMRequest * request =
3275*c54f35caSApple OSS Distributions acquirePMRequest( this, kIOPMRequestTypeIgnoreIdleTimer );
3276*c54f35caSApple OSS Distributions if (!request) {
3277*c54f35caSApple OSS Distributions return kIOReturnNoMemory;
3278*c54f35caSApple OSS Distributions }
3279*c54f35caSApple OSS Distributions
3280*c54f35caSApple OSS Distributions request->fArg0 = (void *) ignore;
3281*c54f35caSApple OSS Distributions submitPMRequest( request );
3282*c54f35caSApple OSS Distributions
3283*c54f35caSApple OSS Distributions return kIOReturnSuccess;
3284*c54f35caSApple OSS Distributions }
3285*c54f35caSApple OSS Distributions
3286*c54f35caSApple OSS Distributions //******************************************************************************
3287*c54f35caSApple OSS Distributions // [public] nextIdleTimeout
3288*c54f35caSApple OSS Distributions //
3289*c54f35caSApple OSS Distributions // Returns how many "seconds from now" the device should idle into its
3290*c54f35caSApple OSS Distributions // next lowest power state.
3291*c54f35caSApple OSS Distributions //******************************************************************************
3292*c54f35caSApple OSS Distributions
3293*c54f35caSApple OSS Distributions SInt32
nextIdleTimeout(AbsoluteTime currentTime,AbsoluteTime lastActivity,unsigned int powerState)3294*c54f35caSApple OSS Distributions IOService::nextIdleTimeout(
3295*c54f35caSApple OSS Distributions AbsoluteTime currentTime,
3296*c54f35caSApple OSS Distributions AbsoluteTime lastActivity,
3297*c54f35caSApple OSS Distributions unsigned int powerState)
3298*c54f35caSApple OSS Distributions {
3299*c54f35caSApple OSS Distributions AbsoluteTime delta;
3300*c54f35caSApple OSS Distributions UInt64 delta_ns;
3301*c54f35caSApple OSS Distributions SInt32 delta_secs;
3302*c54f35caSApple OSS Distributions SInt32 delay_secs;
3303*c54f35caSApple OSS Distributions
3304*c54f35caSApple OSS Distributions // Calculate time difference using funky macro from clock.h.
3305*c54f35caSApple OSS Distributions delta = currentTime;
3306*c54f35caSApple OSS Distributions SUB_ABSOLUTETIME(&delta, &lastActivity);
3307*c54f35caSApple OSS Distributions
3308*c54f35caSApple OSS Distributions // Figure it in seconds.
3309*c54f35caSApple OSS Distributions absolutetime_to_nanoseconds(delta, &delta_ns);
3310*c54f35caSApple OSS Distributions delta_secs = (SInt32)(delta_ns / NSEC_PER_SEC);
3311*c54f35caSApple OSS Distributions
3312*c54f35caSApple OSS Distributions // Be paranoid about delta somehow exceeding timer period.
3313*c54f35caSApple OSS Distributions if (delta_secs < (int) fIdleTimerPeriod) {
3314*c54f35caSApple OSS Distributions delay_secs = (int) fIdleTimerPeriod - delta_secs;
3315*c54f35caSApple OSS Distributions } else {
3316*c54f35caSApple OSS Distributions delay_secs = (int) fIdleTimerPeriod;
3317*c54f35caSApple OSS Distributions }
3318*c54f35caSApple OSS Distributions
3319*c54f35caSApple OSS Distributions return (SInt32)delay_secs;
3320*c54f35caSApple OSS Distributions }
3321*c54f35caSApple OSS Distributions
3322*c54f35caSApple OSS Distributions //*********************************************************************************
3323*c54f35caSApple OSS Distributions // [public] start_PM_idle_timer
3324*c54f35caSApple OSS Distributions //*********************************************************************************
3325*c54f35caSApple OSS Distributions
3326*c54f35caSApple OSS Distributions void
start_PM_idle_timer(void)3327*c54f35caSApple OSS Distributions IOService::start_PM_idle_timer( void )
3328*c54f35caSApple OSS Distributions {
3329*c54f35caSApple OSS Distributions static const int maxTimeout = 100000;
3330*c54f35caSApple OSS Distributions static const int minTimeout = 1;
3331*c54f35caSApple OSS Distributions AbsoluteTime uptime, deadline;
3332*c54f35caSApple OSS Distributions SInt32 idle_in = 0;
3333*c54f35caSApple OSS Distributions boolean_t pending;
3334*c54f35caSApple OSS Distributions
3335*c54f35caSApple OSS Distributions if (!initialized || !fIdleTimerPeriod ||
3336*c54f35caSApple OSS Distributions ((unsigned int) fCurrentPowerState != fCurrentPowerState)) {
3337*c54f35caSApple OSS Distributions return;
3338*c54f35caSApple OSS Distributions }
3339*c54f35caSApple OSS Distributions
3340*c54f35caSApple OSS Distributions IOLockLock(fActivityLock);
3341*c54f35caSApple OSS Distributions
3342*c54f35caSApple OSS Distributions clock_get_uptime(&uptime);
3343*c54f35caSApple OSS Distributions
3344*c54f35caSApple OSS Distributions // Subclasses may modify idle sleep algorithm
3345*c54f35caSApple OSS Distributions idle_in = nextIdleTimeout(uptime, fDeviceActiveTimestamp, (unsigned int) fCurrentPowerState);
3346*c54f35caSApple OSS Distributions
3347*c54f35caSApple OSS Distributions // Check for out-of range responses
3348*c54f35caSApple OSS Distributions if (idle_in > maxTimeout) {
3349*c54f35caSApple OSS Distributions // use standard implementation
3350*c54f35caSApple OSS Distributions idle_in = IOService::nextIdleTimeout(uptime,
3351*c54f35caSApple OSS Distributions fDeviceActiveTimestamp,
3352*c54f35caSApple OSS Distributions (unsigned int) fCurrentPowerState);
3353*c54f35caSApple OSS Distributions } else if (idle_in < minTimeout) {
3354*c54f35caSApple OSS Distributions idle_in = fIdleTimerPeriod;
3355*c54f35caSApple OSS Distributions }
3356*c54f35caSApple OSS Distributions
3357*c54f35caSApple OSS Distributions IOLockUnlock(fActivityLock);
3358*c54f35caSApple OSS Distributions
3359*c54f35caSApple OSS Distributions fNextIdleTimerPeriod = idle_in;
3360*c54f35caSApple OSS Distributions fIdleTimerStartTime = uptime;
3361*c54f35caSApple OSS Distributions
3362*c54f35caSApple OSS Distributions retain();
3363*c54f35caSApple OSS Distributions clock_interval_to_absolutetime_interval(idle_in, kSecondScale, &deadline);
3364*c54f35caSApple OSS Distributions ADD_ABSOLUTETIME(&deadline, &uptime);
3365*c54f35caSApple OSS Distributions pending = thread_call_enter_delayed(fIdleTimer, deadline);
3366*c54f35caSApple OSS Distributions if (pending) {
3367*c54f35caSApple OSS Distributions release();
3368*c54f35caSApple OSS Distributions }
3369*c54f35caSApple OSS Distributions }
3370*c54f35caSApple OSS Distributions
3371*c54f35caSApple OSS Distributions //*********************************************************************************
3372*c54f35caSApple OSS Distributions // [private] restartIdleTimer
3373*c54f35caSApple OSS Distributions //*********************************************************************************
3374*c54f35caSApple OSS Distributions
3375*c54f35caSApple OSS Distributions void
restartIdleTimer(void)3376*c54f35caSApple OSS Distributions IOService::restartIdleTimer( void )
3377*c54f35caSApple OSS Distributions {
3378*c54f35caSApple OSS Distributions if (fDeviceDesire != kPowerStateZero) {
3379*c54f35caSApple OSS Distributions fIdleTimerStopped = false;
3380*c54f35caSApple OSS Distributions fActivityTickleCount = 0;
3381*c54f35caSApple OSS Distributions start_PM_idle_timer();
3382*c54f35caSApple OSS Distributions } else if (fHasAdvisoryDesire) {
3383*c54f35caSApple OSS Distributions fIdleTimerStopped = false;
3384*c54f35caSApple OSS Distributions start_PM_idle_timer();
3385*c54f35caSApple OSS Distributions } else {
3386*c54f35caSApple OSS Distributions fIdleTimerStopped = true;
3387*c54f35caSApple OSS Distributions }
3388*c54f35caSApple OSS Distributions }
3389*c54f35caSApple OSS Distributions
3390*c54f35caSApple OSS Distributions //*********************************************************************************
3391*c54f35caSApple OSS Distributions // idle_timer_expired
3392*c54f35caSApple OSS Distributions //*********************************************************************************
3393*c54f35caSApple OSS Distributions
3394*c54f35caSApple OSS Distributions static void
idle_timer_expired(thread_call_param_t arg0,thread_call_param_t arg1)3395*c54f35caSApple OSS Distributions idle_timer_expired(
3396*c54f35caSApple OSS Distributions thread_call_param_t arg0, thread_call_param_t arg1 )
3397*c54f35caSApple OSS Distributions {
3398*c54f35caSApple OSS Distributions IOService * me = (IOService *) arg0;
3399*c54f35caSApple OSS Distributions
3400*c54f35caSApple OSS Distributions if (gIOPMWorkLoop) {
3401*c54f35caSApple OSS Distributions gIOPMWorkLoop->runAction(
3402*c54f35caSApple OSS Distributions OSMemberFunctionCast(IOWorkLoop::Action, me,
3403*c54f35caSApple OSS Distributions &IOService::idleTimerExpired),
3404*c54f35caSApple OSS Distributions me);
3405*c54f35caSApple OSS Distributions }
3406*c54f35caSApple OSS Distributions
3407*c54f35caSApple OSS Distributions me->release();
3408*c54f35caSApple OSS Distributions }
3409*c54f35caSApple OSS Distributions
3410*c54f35caSApple OSS Distributions //*********************************************************************************
3411*c54f35caSApple OSS Distributions // [private] idleTimerExpired
3412*c54f35caSApple OSS Distributions //
3413*c54f35caSApple OSS Distributions // The idle timer has expired. If there has been activity since the last
3414*c54f35caSApple OSS Distributions // expiration, just restart the timer and return. If there has not been
3415*c54f35caSApple OSS Distributions // activity, switch to the next lower power state and restart the timer.
3416*c54f35caSApple OSS Distributions //*********************************************************************************
3417*c54f35caSApple OSS Distributions
3418*c54f35caSApple OSS Distributions void
idleTimerExpired(void)3419*c54f35caSApple OSS Distributions IOService::idleTimerExpired( void )
3420*c54f35caSApple OSS Distributions {
3421*c54f35caSApple OSS Distributions IOPMRequest * request;
3422*c54f35caSApple OSS Distributions bool restartTimer = true;
3423*c54f35caSApple OSS Distributions uint32_t tickleFlags;
3424*c54f35caSApple OSS Distributions
3425*c54f35caSApple OSS Distributions if (!initialized || !fIdleTimerPeriod || fIdleTimerStopped ||
3426*c54f35caSApple OSS Distributions fLockedFlags.PMStop) {
3427*c54f35caSApple OSS Distributions return;
3428*c54f35caSApple OSS Distributions }
3429*c54f35caSApple OSS Distributions
3430*c54f35caSApple OSS Distributions fIdleTimerStartTime = 0;
3431*c54f35caSApple OSS Distributions
3432*c54f35caSApple OSS Distributions IOLockLock(fActivityLock);
3433*c54f35caSApple OSS Distributions
3434*c54f35caSApple OSS Distributions // Check for device activity (tickles) over last timer period.
3435*c54f35caSApple OSS Distributions
3436*c54f35caSApple OSS Distributions if (fDeviceWasActive) {
3437*c54f35caSApple OSS Distributions // Device was active - do not drop power, restart timer.
3438*c54f35caSApple OSS Distributions fDeviceWasActive = false;
3439*c54f35caSApple OSS Distributions } else if (!fIdleTimerIgnored) {
3440*c54f35caSApple OSS Distributions // No device activity - drop power state by one level.
3441*c54f35caSApple OSS Distributions // Decrement the cached tickle power state when possible.
3442*c54f35caSApple OSS Distributions // This value may be kInvalidTicklePowerState before activityTickle()
3443*c54f35caSApple OSS Distributions // is called, but the power drop request must be issued regardless.
3444*c54f35caSApple OSS Distributions
3445*c54f35caSApple OSS Distributions if ((fActivityTicklePowerState != kInvalidTicklePowerState) &&
3446*c54f35caSApple OSS Distributions (fActivityTicklePowerState != kPowerStateZero)) {
3447*c54f35caSApple OSS Distributions fActivityTicklePowerState--;
3448*c54f35caSApple OSS Distributions }
3449*c54f35caSApple OSS Distributions
3450*c54f35caSApple OSS Distributions tickleFlags = kTickleTypeActivity | kTickleTypePowerDrop;
3451*c54f35caSApple OSS Distributions request = acquirePMRequest( this, kIOPMRequestTypeActivityTickle );
3452*c54f35caSApple OSS Distributions if (request) {
3453*c54f35caSApple OSS Distributions request->fArg0 = (void *)(uintptr_t) fIdleTimerGeneration;
3454*c54f35caSApple OSS Distributions request->fArg1 = (void *)(uintptr_t) tickleFlags;
3455*c54f35caSApple OSS Distributions request->fArg2 = (void *)(uintptr_t) gIOPMTickleGeneration;
3456*c54f35caSApple OSS Distributions submitPMRequest( request );
3457*c54f35caSApple OSS Distributions
3458*c54f35caSApple OSS Distributions // Do not restart timer until after the tickle request has been
3459*c54f35caSApple OSS Distributions // processed.
3460*c54f35caSApple OSS Distributions
3461*c54f35caSApple OSS Distributions restartTimer = false;
3462*c54f35caSApple OSS Distributions }
3463*c54f35caSApple OSS Distributions }
3464*c54f35caSApple OSS Distributions
3465*c54f35caSApple OSS Distributions if (fAdvisoryTickled) {
3466*c54f35caSApple OSS Distributions fAdvisoryTickled = false;
3467*c54f35caSApple OSS Distributions } else if (fHasAdvisoryDesire) {
3468*c54f35caSApple OSS Distributions // Want new tickles to turn into pm request after we drop the lock
3469*c54f35caSApple OSS Distributions fAdvisoryTicklePowerState = kInvalidTicklePowerState;
3470*c54f35caSApple OSS Distributions
3471*c54f35caSApple OSS Distributions tickleFlags = kTickleTypeAdvisory | kTickleTypePowerDrop;
3472*c54f35caSApple OSS Distributions request = acquirePMRequest( this, kIOPMRequestTypeActivityTickle );
3473*c54f35caSApple OSS Distributions if (request) {
3474*c54f35caSApple OSS Distributions request->fArg0 = (void *)(uintptr_t) fIdleTimerGeneration;
3475*c54f35caSApple OSS Distributions request->fArg1 = (void *)(uintptr_t) tickleFlags;
3476*c54f35caSApple OSS Distributions request->fArg2 = (void *)(uintptr_t) gIOPMTickleGeneration;
3477*c54f35caSApple OSS Distributions submitPMRequest( request );
3478*c54f35caSApple OSS Distributions
3479*c54f35caSApple OSS Distributions // Do not restart timer until after the tickle request has been
3480*c54f35caSApple OSS Distributions // processed.
3481*c54f35caSApple OSS Distributions
3482*c54f35caSApple OSS Distributions restartTimer = false;
3483*c54f35caSApple OSS Distributions }
3484*c54f35caSApple OSS Distributions }
3485*c54f35caSApple OSS Distributions
3486*c54f35caSApple OSS Distributions IOLockUnlock(fActivityLock);
3487*c54f35caSApple OSS Distributions
3488*c54f35caSApple OSS Distributions if (restartTimer) {
3489*c54f35caSApple OSS Distributions start_PM_idle_timer();
3490*c54f35caSApple OSS Distributions }
3491*c54f35caSApple OSS Distributions }
3492*c54f35caSApple OSS Distributions
3493*c54f35caSApple OSS Distributions #ifndef __LP64__
3494*c54f35caSApple OSS Distributions //*********************************************************************************
3495*c54f35caSApple OSS Distributions // [deprecated] PM_idle_timer_expiration
3496*c54f35caSApple OSS Distributions //*********************************************************************************
3497*c54f35caSApple OSS Distributions
3498*c54f35caSApple OSS Distributions void
PM_idle_timer_expiration(void)3499*c54f35caSApple OSS Distributions IOService::PM_idle_timer_expiration( void )
3500*c54f35caSApple OSS Distributions {
3501*c54f35caSApple OSS Distributions }
3502*c54f35caSApple OSS Distributions
3503*c54f35caSApple OSS Distributions //*********************************************************************************
3504*c54f35caSApple OSS Distributions // [deprecated] command_received
3505*c54f35caSApple OSS Distributions //*********************************************************************************
3506*c54f35caSApple OSS Distributions
3507*c54f35caSApple OSS Distributions void
command_received(void * statePtr,void *,void *,void *)3508*c54f35caSApple OSS Distributions IOService::command_received( void *statePtr, void *, void *, void * )
3509*c54f35caSApple OSS Distributions {
3510*c54f35caSApple OSS Distributions }
3511*c54f35caSApple OSS Distributions #endif /* !__LP64__ */
3512*c54f35caSApple OSS Distributions
3513*c54f35caSApple OSS Distributions //*********************************************************************************
3514*c54f35caSApple OSS Distributions // [public] setAggressiveness
3515*c54f35caSApple OSS Distributions //
3516*c54f35caSApple OSS Distributions // Pass on the input parameters to all power domain children. All those which are
3517*c54f35caSApple OSS Distributions // power domains will pass it on to their children, etc.
3518*c54f35caSApple OSS Distributions //*********************************************************************************
3519*c54f35caSApple OSS Distributions
3520*c54f35caSApple OSS Distributions IOReturn
setAggressiveness(unsigned long type,unsigned long newLevel)3521*c54f35caSApple OSS Distributions IOService::setAggressiveness( unsigned long type, unsigned long newLevel )
3522*c54f35caSApple OSS Distributions {
3523*c54f35caSApple OSS Distributions return kIOReturnSuccess;
3524*c54f35caSApple OSS Distributions }
3525*c54f35caSApple OSS Distributions
3526*c54f35caSApple OSS Distributions //*********************************************************************************
3527*c54f35caSApple OSS Distributions // [public] getAggressiveness
3528*c54f35caSApple OSS Distributions //
3529*c54f35caSApple OSS Distributions // Called by the user client.
3530*c54f35caSApple OSS Distributions //*********************************************************************************
3531*c54f35caSApple OSS Distributions
3532*c54f35caSApple OSS Distributions IOReturn
getAggressiveness(unsigned long type,unsigned long * currentLevel)3533*c54f35caSApple OSS Distributions IOService::getAggressiveness( unsigned long type, unsigned long * currentLevel )
3534*c54f35caSApple OSS Distributions {
3535*c54f35caSApple OSS Distributions IOPMrootDomain * rootDomain = getPMRootDomain();
3536*c54f35caSApple OSS Distributions
3537*c54f35caSApple OSS Distributions if (!rootDomain) {
3538*c54f35caSApple OSS Distributions return kIOReturnNotReady;
3539*c54f35caSApple OSS Distributions }
3540*c54f35caSApple OSS Distributions
3541*c54f35caSApple OSS Distributions return rootDomain->getAggressiveness( type, currentLevel );
3542*c54f35caSApple OSS Distributions }
3543*c54f35caSApple OSS Distributions
3544*c54f35caSApple OSS Distributions //*********************************************************************************
3545*c54f35caSApple OSS Distributions // [public] getPowerState
3546*c54f35caSApple OSS Distributions //
3547*c54f35caSApple OSS Distributions //*********************************************************************************
3548*c54f35caSApple OSS Distributions
3549*c54f35caSApple OSS Distributions UInt32
getPowerState(void)3550*c54f35caSApple OSS Distributions IOService::getPowerState( void )
3551*c54f35caSApple OSS Distributions {
3552*c54f35caSApple OSS Distributions if (!initialized) {
3553*c54f35caSApple OSS Distributions return kPowerStateZero;
3554*c54f35caSApple OSS Distributions }
3555*c54f35caSApple OSS Distributions
3556*c54f35caSApple OSS Distributions return (UInt32) fCurrentPowerState;
3557*c54f35caSApple OSS Distributions }
3558*c54f35caSApple OSS Distributions
3559*c54f35caSApple OSS Distributions #ifndef __LP64__
3560*c54f35caSApple OSS Distributions //*********************************************************************************
3561*c54f35caSApple OSS Distributions // [deprecated] systemWake
3562*c54f35caSApple OSS Distributions //
3563*c54f35caSApple OSS Distributions // Pass this to all power domain children. All those which are
3564*c54f35caSApple OSS Distributions // power domains will pass it on to their children, etc.
3565*c54f35caSApple OSS Distributions //*********************************************************************************
3566*c54f35caSApple OSS Distributions
3567*c54f35caSApple OSS Distributions IOReturn
systemWake(void)3568*c54f35caSApple OSS Distributions IOService::systemWake( void )
3569*c54f35caSApple OSS Distributions {
3570*c54f35caSApple OSS Distributions OSIterator * iter;
3571*c54f35caSApple OSS Distributions OSObject * next;
3572*c54f35caSApple OSS Distributions IOPowerConnection * connection;
3573*c54f35caSApple OSS Distributions IOService * theChild;
3574*c54f35caSApple OSS Distributions
3575*c54f35caSApple OSS Distributions iter = getChildIterator(gIOPowerPlane);
3576*c54f35caSApple OSS Distributions if (iter) {
3577*c54f35caSApple OSS Distributions while ((next = iter->getNextObject())) {
3578*c54f35caSApple OSS Distributions if ((connection = OSDynamicCast(IOPowerConnection, next))) {
3579*c54f35caSApple OSS Distributions if (connection->getReadyFlag() == false) {
3580*c54f35caSApple OSS Distributions PM_LOG3("[%s] %s: connection not ready\n",
3581*c54f35caSApple OSS Distributions getName(), __FUNCTION__);
3582*c54f35caSApple OSS Distributions continue;
3583*c54f35caSApple OSS Distributions }
3584*c54f35caSApple OSS Distributions
3585*c54f35caSApple OSS Distributions theChild = (IOService *)connection->copyChildEntry(gIOPowerPlane);
3586*c54f35caSApple OSS Distributions if (theChild) {
3587*c54f35caSApple OSS Distributions theChild->systemWake();
3588*c54f35caSApple OSS Distributions theChild->release();
3589*c54f35caSApple OSS Distributions }
3590*c54f35caSApple OSS Distributions }
3591*c54f35caSApple OSS Distributions }
3592*c54f35caSApple OSS Distributions iter->release();
3593*c54f35caSApple OSS Distributions }
3594*c54f35caSApple OSS Distributions
3595*c54f35caSApple OSS Distributions if (fControllingDriver != NULL) {
3596*c54f35caSApple OSS Distributions if (fControllingDriver->didYouWakeSystem()) {
3597*c54f35caSApple OSS Distributions makeUsable();
3598*c54f35caSApple OSS Distributions }
3599*c54f35caSApple OSS Distributions }
3600*c54f35caSApple OSS Distributions
3601*c54f35caSApple OSS Distributions return IOPMNoErr;
3602*c54f35caSApple OSS Distributions }
3603*c54f35caSApple OSS Distributions
3604*c54f35caSApple OSS Distributions //*********************************************************************************
3605*c54f35caSApple OSS Distributions // [deprecated] temperatureCriticalForZone
3606*c54f35caSApple OSS Distributions //*********************************************************************************
3607*c54f35caSApple OSS Distributions
3608*c54f35caSApple OSS Distributions IOReturn
temperatureCriticalForZone(IOService * whichZone)3609*c54f35caSApple OSS Distributions IOService::temperatureCriticalForZone( IOService * whichZone )
3610*c54f35caSApple OSS Distributions {
3611*c54f35caSApple OSS Distributions IOService * theParent;
3612*c54f35caSApple OSS Distributions IOService * theNub;
3613*c54f35caSApple OSS Distributions
3614*c54f35caSApple OSS Distributions OUR_PMLog(kPMLogCriticalTemp, 0, 0);
3615*c54f35caSApple OSS Distributions
3616*c54f35caSApple OSS Distributions if (inPlane(gIOPowerPlane) && !IS_PM_ROOT) {
3617*c54f35caSApple OSS Distributions theNub = (IOService *)copyParentEntry(gIOPowerPlane);
3618*c54f35caSApple OSS Distributions if (theNub) {
3619*c54f35caSApple OSS Distributions theParent = (IOService *)theNub->copyParentEntry(gIOPowerPlane);
3620*c54f35caSApple OSS Distributions theNub->release();
3621*c54f35caSApple OSS Distributions if (theParent) {
3622*c54f35caSApple OSS Distributions theParent->temperatureCriticalForZone(whichZone);
3623*c54f35caSApple OSS Distributions theParent->release();
3624*c54f35caSApple OSS Distributions }
3625*c54f35caSApple OSS Distributions }
3626*c54f35caSApple OSS Distributions }
3627*c54f35caSApple OSS Distributions return IOPMNoErr;
3628*c54f35caSApple OSS Distributions }
3629*c54f35caSApple OSS Distributions #endif /* !__LP64__ */
3630*c54f35caSApple OSS Distributions
3631*c54f35caSApple OSS Distributions // MARK: -
3632*c54f35caSApple OSS Distributions // MARK: Power Change (Common)
3633*c54f35caSApple OSS Distributions
3634*c54f35caSApple OSS Distributions //*********************************************************************************
3635*c54f35caSApple OSS Distributions // [private] startPowerChange
3636*c54f35caSApple OSS Distributions //
3637*c54f35caSApple OSS Distributions // All power state changes starts here.
3638*c54f35caSApple OSS Distributions //*********************************************************************************
3639*c54f35caSApple OSS Distributions
3640*c54f35caSApple OSS Distributions IOReturn
startPowerChange(IOPMPowerChangeFlags changeFlags,IOPMPowerStateIndex powerState,IOPMPowerFlags domainFlags,IOPowerConnection * parentConnection,IOPMPowerFlags parentFlags)3641*c54f35caSApple OSS Distributions IOService::startPowerChange(
3642*c54f35caSApple OSS Distributions IOPMPowerChangeFlags changeFlags,
3643*c54f35caSApple OSS Distributions IOPMPowerStateIndex powerState,
3644*c54f35caSApple OSS Distributions IOPMPowerFlags domainFlags,
3645*c54f35caSApple OSS Distributions IOPowerConnection * parentConnection,
3646*c54f35caSApple OSS Distributions IOPMPowerFlags parentFlags )
3647*c54f35caSApple OSS Distributions {
3648*c54f35caSApple OSS Distributions uint32_t savedPMActionsState;
3649*c54f35caSApple OSS Distributions
3650*c54f35caSApple OSS Distributions PM_ASSERT_IN_GATE();
3651*c54f35caSApple OSS Distributions assert( fMachineState == kIOPM_Finished );
3652*c54f35caSApple OSS Distributions assert( powerState < fNumberOfPowerStates );
3653*c54f35caSApple OSS Distributions
3654*c54f35caSApple OSS Distributions if (powerState >= fNumberOfPowerStates) {
3655*c54f35caSApple OSS Distributions return IOPMAckImplied;
3656*c54f35caSApple OSS Distributions }
3657*c54f35caSApple OSS Distributions
3658*c54f35caSApple OSS Distributions fIsPreChange = true;
3659*c54f35caSApple OSS Distributions savedPMActionsState = fPMActions.state;
3660*c54f35caSApple OSS Distributions PM_ACTION_CHANGE(actionPowerChangeOverride, &powerState, &changeFlags);
3661*c54f35caSApple OSS Distributions
3662*c54f35caSApple OSS Distributions // rdar://problem/55040032
3663*c54f35caSApple OSS Distributions // Schedule a power adjustment after removing the power clamp
3664*c54f35caSApple OSS Distributions // to inform our power parent(s) about our latest desired domain
3665*c54f35caSApple OSS Distributions // power state. For a self-initiated change, let OurChangeStart()
3666*c54f35caSApple OSS Distributions // automatically request parent power when necessary.
3667*c54f35caSApple OSS Distributions if (!fAdjustPowerScheduled &&
3668*c54f35caSApple OSS Distributions ((changeFlags & kIOPMSelfInitiated) == 0) &&
3669*c54f35caSApple OSS Distributions ((fPMActions.state & kPMActionsStatePowerClamped) == 0) &&
3670*c54f35caSApple OSS Distributions ((savedPMActionsState & kPMActionsStatePowerClamped) != 0)) {
3671*c54f35caSApple OSS Distributions IOPMRequest * request = acquirePMRequest(this, kIOPMRequestTypeAdjustPowerState);
3672*c54f35caSApple OSS Distributions if (request) {
3673*c54f35caSApple OSS Distributions submitPMRequest(request);
3674*c54f35caSApple OSS Distributions fAdjustPowerScheduled = true;
3675*c54f35caSApple OSS Distributions }
3676*c54f35caSApple OSS Distributions }
3677*c54f35caSApple OSS Distributions
3678*c54f35caSApple OSS Distributions if (changeFlags & kIOPMExpireIdleTimer) {
3679*c54f35caSApple OSS Distributions // Root domain requested removal of tickle influence
3680*c54f35caSApple OSS Distributions if (StateOrder(fDeviceDesire) > StateOrder(powerState)) {
3681*c54f35caSApple OSS Distributions // Reset device desire down to the clamped power state
3682*c54f35caSApple OSS Distributions updatePowerClient(gIOPMPowerClientDevice, powerState);
3683*c54f35caSApple OSS Distributions computeDesiredState(kPowerStateZero, true);
3684*c54f35caSApple OSS Distributions
3685*c54f35caSApple OSS Distributions // Invalidate tickle cache so the next tickle will issue a request
3686*c54f35caSApple OSS Distributions IOLockLock(fActivityLock);
3687*c54f35caSApple OSS Distributions fDeviceWasActive = false;
3688*c54f35caSApple OSS Distributions fActivityTicklePowerState = kInvalidTicklePowerState;
3689*c54f35caSApple OSS Distributions IOLockUnlock(fActivityLock);
3690*c54f35caSApple OSS Distributions
3691*c54f35caSApple OSS Distributions fIdleTimerMinPowerState = kPowerStateZero;
3692*c54f35caSApple OSS Distributions }
3693*c54f35caSApple OSS Distributions }
3694*c54f35caSApple OSS Distributions
3695*c54f35caSApple OSS Distributions // Root domain's override handler may cancel the power change by
3696*c54f35caSApple OSS Distributions // setting the kIOPMNotDone flag.
3697*c54f35caSApple OSS Distributions
3698*c54f35caSApple OSS Distributions if (changeFlags & kIOPMNotDone) {
3699*c54f35caSApple OSS Distributions return IOPMAckImplied;
3700*c54f35caSApple OSS Distributions }
3701*c54f35caSApple OSS Distributions
3702*c54f35caSApple OSS Distributions // Forks to either Driver or Parent initiated power change paths.
3703*c54f35caSApple OSS Distributions
3704*c54f35caSApple OSS Distributions fHeadNoteChangeFlags = changeFlags;
3705*c54f35caSApple OSS Distributions fHeadNotePowerState = powerState;
3706*c54f35caSApple OSS Distributions fHeadNotePowerArrayEntry = &fPowerStates[powerState];
3707*c54f35caSApple OSS Distributions fHeadNoteParentConnection = NULL;
3708*c54f35caSApple OSS Distributions
3709*c54f35caSApple OSS Distributions if (changeFlags & kIOPMSelfInitiated) {
3710*c54f35caSApple OSS Distributions if (changeFlags & kIOPMSynchronize) {
3711*c54f35caSApple OSS Distributions OurSyncStart();
3712*c54f35caSApple OSS Distributions } else {
3713*c54f35caSApple OSS Distributions OurChangeStart();
3714*c54f35caSApple OSS Distributions }
3715*c54f35caSApple OSS Distributions return 0;
3716*c54f35caSApple OSS Distributions } else {
3717*c54f35caSApple OSS Distributions assert(changeFlags & kIOPMParentInitiated);
3718*c54f35caSApple OSS Distributions fHeadNoteDomainFlags = domainFlags;
3719*c54f35caSApple OSS Distributions fHeadNoteParentFlags = parentFlags;
3720*c54f35caSApple OSS Distributions fHeadNoteParentConnection = parentConnection;
3721*c54f35caSApple OSS Distributions return ParentChangeStart();
3722*c54f35caSApple OSS Distributions }
3723*c54f35caSApple OSS Distributions }
3724*c54f35caSApple OSS Distributions
3725*c54f35caSApple OSS Distributions //*********************************************************************************
3726*c54f35caSApple OSS Distributions // [private] notifyInterestedDrivers
3727*c54f35caSApple OSS Distributions //*********************************************************************************
3728*c54f35caSApple OSS Distributions
3729*c54f35caSApple OSS Distributions bool
notifyInterestedDrivers(void)3730*c54f35caSApple OSS Distributions IOService::notifyInterestedDrivers( void )
3731*c54f35caSApple OSS Distributions {
3732*c54f35caSApple OSS Distributions IOPMinformee * informee;
3733*c54f35caSApple OSS Distributions IOPMinformeeList * list = fInterestedDrivers;
3734*c54f35caSApple OSS Distributions DriverCallParam * param;
3735*c54f35caSApple OSS Distributions unsigned long numItems;
3736*c54f35caSApple OSS Distributions uint32_t count;
3737*c54f35caSApple OSS Distributions uint32_t skipCnt = 0;
3738*c54f35caSApple OSS Distributions
3739*c54f35caSApple OSS Distributions PM_ASSERT_IN_GATE();
3740*c54f35caSApple OSS Distributions assert( fDriverCallParamCount == 0 );
3741*c54f35caSApple OSS Distributions assert( fHeadNotePendingAcks == 0 );
3742*c54f35caSApple OSS Distributions
3743*c54f35caSApple OSS Distributions fHeadNotePendingAcks = 0;
3744*c54f35caSApple OSS Distributions
3745*c54f35caSApple OSS Distributions numItems = list->numberOfItems();
3746*c54f35caSApple OSS Distributions if (!numItems || ((uint32_t) numItems != numItems)) {
3747*c54f35caSApple OSS Distributions goto done; // interested drivers count out of range
3748*c54f35caSApple OSS Distributions }
3749*c54f35caSApple OSS Distributions count = (uint32_t) numItems;
3750*c54f35caSApple OSS Distributions
3751*c54f35caSApple OSS Distributions // Allocate an array of interested drivers and their return values
3752*c54f35caSApple OSS Distributions // for the callout thread. Everything else is still "owned" by the
3753*c54f35caSApple OSS Distributions // PM work loop, which can run to process acknowledgePowerChange()
3754*c54f35caSApple OSS Distributions // responses.
3755*c54f35caSApple OSS Distributions
3756*c54f35caSApple OSS Distributions param = (DriverCallParam *) fDriverCallParamPtr;
3757*c54f35caSApple OSS Distributions if (count > fDriverCallParamSlots) {
3758*c54f35caSApple OSS Distributions if (fDriverCallParamSlots) {
3759*c54f35caSApple OSS Distributions assert(fDriverCallParamPtr);
3760*c54f35caSApple OSS Distributions IODelete(fDriverCallParamPtr, DriverCallParam, fDriverCallParamSlots);
3761*c54f35caSApple OSS Distributions fDriverCallParamPtr = NULL;
3762*c54f35caSApple OSS Distributions fDriverCallParamSlots = 0;
3763*c54f35caSApple OSS Distributions }
3764*c54f35caSApple OSS Distributions
3765*c54f35caSApple OSS Distributions param = IONew(DriverCallParam, count);
3766*c54f35caSApple OSS Distributions if (!param) {
3767*c54f35caSApple OSS Distributions goto done; // no memory
3768*c54f35caSApple OSS Distributions }
3769*c54f35caSApple OSS Distributions fDriverCallParamPtr = (void *) param;
3770*c54f35caSApple OSS Distributions fDriverCallParamSlots = count;
3771*c54f35caSApple OSS Distributions }
3772*c54f35caSApple OSS Distributions
3773*c54f35caSApple OSS Distributions informee = list->firstInList();
3774*c54f35caSApple OSS Distributions assert(informee);
3775*c54f35caSApple OSS Distributions for (IOItemCount i = 0, arrayIdx = 0; i < count; i++) {
3776*c54f35caSApple OSS Distributions if (fInitialSetPowerState || (fHeadNoteChangeFlags & kIOPMInitialPowerChange)) {
3777*c54f35caSApple OSS Distributions // Skip notifying self, if 'kIOPMInitialDeviceState' is set and
3778*c54f35caSApple OSS Distributions // this is the initial power state change
3779*c54f35caSApple OSS Distributions if ((this == informee->whatObject) &&
3780*c54f35caSApple OSS Distributions (fHeadNotePowerArrayEntry->capabilityFlags & kIOPMInitialDeviceState)) {
3781*c54f35caSApple OSS Distributions skipCnt++;
3782*c54f35caSApple OSS Distributions continue;
3783*c54f35caSApple OSS Distributions }
3784*c54f35caSApple OSS Distributions }
3785*c54f35caSApple OSS Distributions informee->timer = -1;
3786*c54f35caSApple OSS Distributions param[arrayIdx].Target = informee;
3787*c54f35caSApple OSS Distributions informee->retain();
3788*c54f35caSApple OSS Distributions informee = list->nextInList( informee );
3789*c54f35caSApple OSS Distributions arrayIdx++;
3790*c54f35caSApple OSS Distributions }
3791*c54f35caSApple OSS Distributions
3792*c54f35caSApple OSS Distributions count -= skipCnt;
3793*c54f35caSApple OSS Distributions if (!count) {
3794*c54f35caSApple OSS Distributions goto done;
3795*c54f35caSApple OSS Distributions }
3796*c54f35caSApple OSS Distributions fDriverCallParamCount = count;
3797*c54f35caSApple OSS Distributions fHeadNotePendingAcks = count;
3798*c54f35caSApple OSS Distributions
3799*c54f35caSApple OSS Distributions // Block state machine and wait for callout completion.
3800*c54f35caSApple OSS Distributions assert(!fDriverCallBusy);
3801*c54f35caSApple OSS Distributions fDriverCallBusy = true;
3802*c54f35caSApple OSS Distributions thread_call_enter( fDriverCallEntry );
3803*c54f35caSApple OSS Distributions return true;
3804*c54f35caSApple OSS Distributions
3805*c54f35caSApple OSS Distributions done:
3806*c54f35caSApple OSS Distributions // Return false if there are no interested drivers or could not schedule
3807*c54f35caSApple OSS Distributions // callout thread due to error.
3808*c54f35caSApple OSS Distributions return false;
3809*c54f35caSApple OSS Distributions }
3810*c54f35caSApple OSS Distributions
3811*c54f35caSApple OSS Distributions //*********************************************************************************
3812*c54f35caSApple OSS Distributions // [private] notifyInterestedDriversDone
3813*c54f35caSApple OSS Distributions //*********************************************************************************
3814*c54f35caSApple OSS Distributions
3815*c54f35caSApple OSS Distributions void
notifyInterestedDriversDone(void)3816*c54f35caSApple OSS Distributions IOService::notifyInterestedDriversDone( void )
3817*c54f35caSApple OSS Distributions {
3818*c54f35caSApple OSS Distributions IOPMinformee * informee;
3819*c54f35caSApple OSS Distributions IOItemCount count;
3820*c54f35caSApple OSS Distributions DriverCallParam * param;
3821*c54f35caSApple OSS Distributions IOReturn result;
3822*c54f35caSApple OSS Distributions int maxTimeout = 0;
3823*c54f35caSApple OSS Distributions
3824*c54f35caSApple OSS Distributions PM_ASSERT_IN_GATE();
3825*c54f35caSApple OSS Distributions assert( fDriverCallBusy == false );
3826*c54f35caSApple OSS Distributions assert( fMachineState == kIOPM_DriverThreadCallDone );
3827*c54f35caSApple OSS Distributions
3828*c54f35caSApple OSS Distributions param = (DriverCallParam *) fDriverCallParamPtr;
3829*c54f35caSApple OSS Distributions count = fDriverCallParamCount;
3830*c54f35caSApple OSS Distributions
3831*c54f35caSApple OSS Distributions if (param && count) {
3832*c54f35caSApple OSS Distributions for (IOItemCount i = 0; i < count; i++, param++) {
3833*c54f35caSApple OSS Distributions informee = (IOPMinformee *) param->Target;
3834*c54f35caSApple OSS Distributions result = param->Result;
3835*c54f35caSApple OSS Distributions
3836*c54f35caSApple OSS Distributions if ((result == IOPMAckImplied) || (result < 0)) {
3837*c54f35caSApple OSS Distributions // Interested driver return IOPMAckImplied.
3838*c54f35caSApple OSS Distributions // If informee timer is zero, it must have de-registered
3839*c54f35caSApple OSS Distributions // interest during the thread callout. That also drops
3840*c54f35caSApple OSS Distributions // the pending ack count.
3841*c54f35caSApple OSS Distributions
3842*c54f35caSApple OSS Distributions if (fHeadNotePendingAcks && informee->timer) {
3843*c54f35caSApple OSS Distributions fHeadNotePendingAcks--;
3844*c54f35caSApple OSS Distributions }
3845*c54f35caSApple OSS Distributions
3846*c54f35caSApple OSS Distributions informee->timer = 0;
3847*c54f35caSApple OSS Distributions } else if (informee->timer) {
3848*c54f35caSApple OSS Distributions assert(informee->timer == -1);
3849*c54f35caSApple OSS Distributions
3850*c54f35caSApple OSS Distributions // Driver has not acked, and has returned a positive result.
3851*c54f35caSApple OSS Distributions // Enforce a minimum permissible timeout value.
3852*c54f35caSApple OSS Distributions // Make the min value large enough so timeout is less likely
3853*c54f35caSApple OSS Distributions // to occur if a driver misinterpreted that the return value
3854*c54f35caSApple OSS Distributions // should be in microsecond units. And make it large enough
3855*c54f35caSApple OSS Distributions // to be noticeable if a driver neglects to ack.
3856*c54f35caSApple OSS Distributions
3857*c54f35caSApple OSS Distributions if (result < kMinAckTimeoutTicks) {
3858*c54f35caSApple OSS Distributions result = kMinAckTimeoutTicks;
3859*c54f35caSApple OSS Distributions }
3860*c54f35caSApple OSS Distributions
3861*c54f35caSApple OSS Distributions informee->timer = (result / (ACK_TIMER_PERIOD / ns_per_us)) + 1;
3862*c54f35caSApple OSS Distributions if (result > maxTimeout) {
3863*c54f35caSApple OSS Distributions maxTimeout = result;
3864*c54f35caSApple OSS Distributions }
3865*c54f35caSApple OSS Distributions }
3866*c54f35caSApple OSS Distributions // else, child has already acked or driver has removed interest,
3867*c54f35caSApple OSS Distributions // and head_note_pendingAcks decremented.
3868*c54f35caSApple OSS Distributions // informee may have been removed from the interested drivers list,
3869*c54f35caSApple OSS Distributions // thus the informee must be retained across the callout.
3870*c54f35caSApple OSS Distributions
3871*c54f35caSApple OSS Distributions informee->release();
3872*c54f35caSApple OSS Distributions }
3873*c54f35caSApple OSS Distributions
3874*c54f35caSApple OSS Distributions fDriverCallParamCount = 0;
3875*c54f35caSApple OSS Distributions
3876*c54f35caSApple OSS Distributions if (fHeadNotePendingAcks) {
3877*c54f35caSApple OSS Distributions OUR_PMLog(kPMLogStartAckTimer, 0, 0);
3878*c54f35caSApple OSS Distributions start_ack_timer();
3879*c54f35caSApple OSS Distributions getPMRootDomain()->reset_watchdog_timer(this, maxTimeout / USEC_PER_SEC + 1);
3880*c54f35caSApple OSS Distributions }
3881*c54f35caSApple OSS Distributions }
3882*c54f35caSApple OSS Distributions
3883*c54f35caSApple OSS Distributions MS_POP(); // pop the machine state passed to notifyAll()
3884*c54f35caSApple OSS Distributions
3885*c54f35caSApple OSS Distributions // If interest acks are outstanding, block the state machine until
3886*c54f35caSApple OSS Distributions // fHeadNotePendingAcks drops to zero before notifying root domain.
3887*c54f35caSApple OSS Distributions // Otherwise notify root domain directly.
3888*c54f35caSApple OSS Distributions
3889*c54f35caSApple OSS Distributions if (!fHeadNotePendingAcks) {
3890*c54f35caSApple OSS Distributions notifyRootDomain();
3891*c54f35caSApple OSS Distributions } else {
3892*c54f35caSApple OSS Distributions MS_PUSH(fMachineState);
3893*c54f35caSApple OSS Distributions fMachineState = kIOPM_NotifyChildrenStart;
3894*c54f35caSApple OSS Distributions }
3895*c54f35caSApple OSS Distributions }
3896*c54f35caSApple OSS Distributions
3897*c54f35caSApple OSS Distributions //*********************************************************************************
3898*c54f35caSApple OSS Distributions // [private] notifyRootDomain
3899*c54f35caSApple OSS Distributions //*********************************************************************************
3900*c54f35caSApple OSS Distributions
3901*c54f35caSApple OSS Distributions void
notifyRootDomain(void)3902*c54f35caSApple OSS Distributions IOService::notifyRootDomain( void )
3903*c54f35caSApple OSS Distributions {
3904*c54f35caSApple OSS Distributions assert( fDriverCallBusy == false );
3905*c54f35caSApple OSS Distributions
3906*c54f35caSApple OSS Distributions // Only for root domain in the will-change phase.
3907*c54f35caSApple OSS Distributions // On a power up, don't notify children right after the interested drivers.
3908*c54f35caSApple OSS Distributions // Perform setPowerState() first, then notify the children.
3909*c54f35caSApple OSS Distributions if (!IS_ROOT_DOMAIN || (fMachineState != kIOPM_OurChangeSetPowerState)) {
3910*c54f35caSApple OSS Distributions notifyChildren();
3911*c54f35caSApple OSS Distributions return;
3912*c54f35caSApple OSS Distributions }
3913*c54f35caSApple OSS Distributions
3914*c54f35caSApple OSS Distributions MS_PUSH(fMachineState); // push notifyAll() machine state
3915*c54f35caSApple OSS Distributions fMachineState = kIOPM_DriverThreadCallDone;
3916*c54f35caSApple OSS Distributions
3917*c54f35caSApple OSS Distributions // Call IOPMrootDomain::willNotifyPowerChildren() on a thread call
3918*c54f35caSApple OSS Distributions // to avoid a deadlock.
3919*c54f35caSApple OSS Distributions fDriverCallReason = kRootDomainInformPreChange;
3920*c54f35caSApple OSS Distributions fDriverCallBusy = true;
3921*c54f35caSApple OSS Distributions thread_call_enter( fDriverCallEntry );
3922*c54f35caSApple OSS Distributions }
3923*c54f35caSApple OSS Distributions
3924*c54f35caSApple OSS Distributions void
notifyRootDomainDone(void)3925*c54f35caSApple OSS Distributions IOService::notifyRootDomainDone( void )
3926*c54f35caSApple OSS Distributions {
3927*c54f35caSApple OSS Distributions assert( fDriverCallBusy == false );
3928*c54f35caSApple OSS Distributions assert( fMachineState == kIOPM_DriverThreadCallDone );
3929*c54f35caSApple OSS Distributions
3930*c54f35caSApple OSS Distributions MS_POP(); // pop notifyAll() machine state
3931*c54f35caSApple OSS Distributions notifyChildren();
3932*c54f35caSApple OSS Distributions }
3933*c54f35caSApple OSS Distributions
3934*c54f35caSApple OSS Distributions //*********************************************************************************
3935*c54f35caSApple OSS Distributions // [private] notifyChildren
3936*c54f35caSApple OSS Distributions //*********************************************************************************
3937*c54f35caSApple OSS Distributions
3938*c54f35caSApple OSS Distributions void
notifyChildren(void)3939*c54f35caSApple OSS Distributions IOService::notifyChildren( void )
3940*c54f35caSApple OSS Distributions {
3941*c54f35caSApple OSS Distributions OSIterator * iter;
3942*c54f35caSApple OSS Distributions OSObject * next;
3943*c54f35caSApple OSS Distributions IOPowerConnection * connection;
3944*c54f35caSApple OSS Distributions OSArray * children = NULL;
3945*c54f35caSApple OSS Distributions IOPMrootDomain * rootDomain;
3946*c54f35caSApple OSS Distributions bool delayNotify = false;
3947*c54f35caSApple OSS Distributions
3948*c54f35caSApple OSS Distributions if ((fHeadNotePowerState != fCurrentPowerState) &&
3949*c54f35caSApple OSS Distributions (IS_POWER_DROP == fIsPreChange) &&
3950*c54f35caSApple OSS Distributions ((rootDomain = getPMRootDomain()) == this)) {
3951*c54f35caSApple OSS Distributions rootDomain->tracePoint( IS_POWER_DROP ?
3952*c54f35caSApple OSS Distributions kIOPMTracePointSleepPowerPlaneDrivers :
3953*c54f35caSApple OSS Distributions kIOPMTracePointWakePowerPlaneDrivers );
3954*c54f35caSApple OSS Distributions }
3955*c54f35caSApple OSS Distributions
3956*c54f35caSApple OSS Distributions if (fStrictTreeOrder) {
3957*c54f35caSApple OSS Distributions children = OSArray::withCapacity(8);
3958*c54f35caSApple OSS Distributions }
3959*c54f35caSApple OSS Distributions
3960*c54f35caSApple OSS Distributions // Sum child power consumption in notifyChild()
3961*c54f35caSApple OSS Distributions fHeadNotePowerArrayEntry->staticPower = 0;
3962*c54f35caSApple OSS Distributions
3963*c54f35caSApple OSS Distributions iter = getChildIterator(gIOPowerPlane);
3964*c54f35caSApple OSS Distributions if (iter) {
3965*c54f35caSApple OSS Distributions while ((next = iter->getNextObject())) {
3966*c54f35caSApple OSS Distributions if ((connection = OSDynamicCast(IOPowerConnection, next))) {
3967*c54f35caSApple OSS Distributions if (connection->getReadyFlag() == false) {
3968*c54f35caSApple OSS Distributions PM_LOG3("[%s] %s: connection not ready\n",
3969*c54f35caSApple OSS Distributions getName(), __FUNCTION__);
3970*c54f35caSApple OSS Distributions continue;
3971*c54f35caSApple OSS Distributions }
3972*c54f35caSApple OSS Distributions
3973*c54f35caSApple OSS Distributions // Mechanism to postpone the did-change notification to
3974*c54f35caSApple OSS Distributions // certain power children to order those children last.
3975*c54f35caSApple OSS Distributions // Cannot be used together with strict tree ordering.
3976*c54f35caSApple OSS Distributions
3977*c54f35caSApple OSS Distributions if (!fIsPreChange &&
3978*c54f35caSApple OSS Distributions connection->delayChildNotification &&
3979*c54f35caSApple OSS Distributions getPMRootDomain()->shouldDelayChildNotification(this)) {
3980*c54f35caSApple OSS Distributions if (!children) {
3981*c54f35caSApple OSS Distributions children = OSArray::withCapacity(8);
3982*c54f35caSApple OSS Distributions if (children) {
3983*c54f35caSApple OSS Distributions delayNotify = true;
3984*c54f35caSApple OSS Distributions }
3985*c54f35caSApple OSS Distributions }
3986*c54f35caSApple OSS Distributions if (delayNotify) {
3987*c54f35caSApple OSS Distributions children->setObject( connection );
3988*c54f35caSApple OSS Distributions continue;
3989*c54f35caSApple OSS Distributions }
3990*c54f35caSApple OSS Distributions }
3991*c54f35caSApple OSS Distributions
3992*c54f35caSApple OSS Distributions if (!delayNotify && children) {
3993*c54f35caSApple OSS Distributions children->setObject( connection );
3994*c54f35caSApple OSS Distributions } else {
3995*c54f35caSApple OSS Distributions notifyChild( connection );
3996*c54f35caSApple OSS Distributions }
3997*c54f35caSApple OSS Distributions }
3998*c54f35caSApple OSS Distributions }
3999*c54f35caSApple OSS Distributions iter->release();
4000*c54f35caSApple OSS Distributions }
4001*c54f35caSApple OSS Distributions
4002*c54f35caSApple OSS Distributions if (children && (children->getCount() == 0)) {
4003*c54f35caSApple OSS Distributions children->release();
4004*c54f35caSApple OSS Distributions children = NULL;
4005*c54f35caSApple OSS Distributions }
4006*c54f35caSApple OSS Distributions if (children) {
4007*c54f35caSApple OSS Distributions assert(fNotifyChildArray == NULL);
4008*c54f35caSApple OSS Distributions fNotifyChildArray = children;
4009*c54f35caSApple OSS Distributions MS_PUSH(fMachineState);
4010*c54f35caSApple OSS Distributions
4011*c54f35caSApple OSS Distributions if (delayNotify) {
4012*c54f35caSApple OSS Distributions // Block until all non-delayed children have acked their
4013*c54f35caSApple OSS Distributions // notification. Then notify the remaining delayed child
4014*c54f35caSApple OSS Distributions // in the array. This is used to hold off graphics child
4015*c54f35caSApple OSS Distributions // notification while the rest of the system powers up.
4016*c54f35caSApple OSS Distributions // If a hid tickle arrives during this time, the delayed
4017*c54f35caSApple OSS Distributions // children are immediately notified and root domain will
4018*c54f35caSApple OSS Distributions // not clamp power for dark wake.
4019*c54f35caSApple OSS Distributions
4020*c54f35caSApple OSS Distributions fMachineState = kIOPM_NotifyChildrenDelayed;
4021*c54f35caSApple OSS Distributions PM_LOG2("%s: %d children in delayed array\n",
4022*c54f35caSApple OSS Distributions getName(), children->getCount());
4023*c54f35caSApple OSS Distributions } else {
4024*c54f35caSApple OSS Distributions // Child array created to support strict notification order.
4025*c54f35caSApple OSS Distributions // Notify children in the array one at a time.
4026*c54f35caSApple OSS Distributions
4027*c54f35caSApple OSS Distributions fMachineState = kIOPM_NotifyChildrenOrdered;
4028*c54f35caSApple OSS Distributions }
4029*c54f35caSApple OSS Distributions }
4030*c54f35caSApple OSS Distributions }
4031*c54f35caSApple OSS Distributions
4032*c54f35caSApple OSS Distributions //*********************************************************************************
4033*c54f35caSApple OSS Distributions // [private] notifyChildrenOrdered
4034*c54f35caSApple OSS Distributions //*********************************************************************************
4035*c54f35caSApple OSS Distributions
4036*c54f35caSApple OSS Distributions void
notifyChildrenOrdered(void)4037*c54f35caSApple OSS Distributions IOService::notifyChildrenOrdered( void )
4038*c54f35caSApple OSS Distributions {
4039*c54f35caSApple OSS Distributions PM_ASSERT_IN_GATE();
4040*c54f35caSApple OSS Distributions assert(fNotifyChildArray);
4041*c54f35caSApple OSS Distributions assert(fMachineState == kIOPM_NotifyChildrenOrdered);
4042*c54f35caSApple OSS Distributions
4043*c54f35caSApple OSS Distributions // Notify one child, wait for it to ack, then repeat for next child.
4044*c54f35caSApple OSS Distributions // This is a workaround for some drivers with multiple instances at
4045*c54f35caSApple OSS Distributions // the same branch in the power tree, but the driver is slow to power
4046*c54f35caSApple OSS Distributions // up unless the tree ordering is observed. Problem observed only on
4047*c54f35caSApple OSS Distributions // system wake, not on system sleep.
4048*c54f35caSApple OSS Distributions //
4049*c54f35caSApple OSS Distributions // We have the ability to power off in reverse child index order.
4050*c54f35caSApple OSS Distributions // That works nicely on some machines, but not on all HW configs.
4051*c54f35caSApple OSS Distributions
4052*c54f35caSApple OSS Distributions if (fNotifyChildArray->getCount()) {
4053*c54f35caSApple OSS Distributions IOPowerConnection * connection;
4054*c54f35caSApple OSS Distributions connection = (IOPowerConnection *) fNotifyChildArray->getObject(0);
4055*c54f35caSApple OSS Distributions notifyChild( connection );
4056*c54f35caSApple OSS Distributions fNotifyChildArray->removeObject(0);
4057*c54f35caSApple OSS Distributions } else {
4058*c54f35caSApple OSS Distributions fNotifyChildArray->release();
4059*c54f35caSApple OSS Distributions fNotifyChildArray = NULL;
4060*c54f35caSApple OSS Distributions
4061*c54f35caSApple OSS Distributions MS_POP(); // pushed by notifyChildren()
4062*c54f35caSApple OSS Distributions }
4063*c54f35caSApple OSS Distributions }
4064*c54f35caSApple OSS Distributions
4065*c54f35caSApple OSS Distributions //*********************************************************************************
4066*c54f35caSApple OSS Distributions // [private] notifyChildrenDelayed
4067*c54f35caSApple OSS Distributions //*********************************************************************************
4068*c54f35caSApple OSS Distributions
4069*c54f35caSApple OSS Distributions void
notifyChildrenDelayed(void)4070*c54f35caSApple OSS Distributions IOService::notifyChildrenDelayed( void )
4071*c54f35caSApple OSS Distributions {
4072*c54f35caSApple OSS Distributions IOPowerConnection * connection;
4073*c54f35caSApple OSS Distributions
4074*c54f35caSApple OSS Distributions PM_ASSERT_IN_GATE();
4075*c54f35caSApple OSS Distributions assert(fNotifyChildArray);
4076*c54f35caSApple OSS Distributions assert(fMachineState == kIOPM_NotifyChildrenDelayed);
4077*c54f35caSApple OSS Distributions
4078*c54f35caSApple OSS Distributions // Wait after all non-delayed children and interested drivers have ack'ed,
4079*c54f35caSApple OSS Distributions // then notify all delayed children. If notify delay is canceled, child
4080*c54f35caSApple OSS Distributions // acks may be outstanding with PM blocked on fHeadNotePendingAcks != 0.
4081*c54f35caSApple OSS Distributions // But the handling for either case is identical.
4082*c54f35caSApple OSS Distributions
4083*c54f35caSApple OSS Distributions for (int i = 0;; i++) {
4084*c54f35caSApple OSS Distributions connection = (IOPowerConnection *) fNotifyChildArray->getObject(i);
4085*c54f35caSApple OSS Distributions if (!connection) {
4086*c54f35caSApple OSS Distributions break;
4087*c54f35caSApple OSS Distributions }
4088*c54f35caSApple OSS Distributions
4089*c54f35caSApple OSS Distributions notifyChild( connection );
4090*c54f35caSApple OSS Distributions }
4091*c54f35caSApple OSS Distributions
4092*c54f35caSApple OSS Distributions PM_LOG2("%s: notified delayed children\n", getName());
4093*c54f35caSApple OSS Distributions fNotifyChildArray->release();
4094*c54f35caSApple OSS Distributions fNotifyChildArray = NULL;
4095*c54f35caSApple OSS Distributions
4096*c54f35caSApple OSS Distributions MS_POP(); // pushed by notifyChildren()
4097*c54f35caSApple OSS Distributions }
4098*c54f35caSApple OSS Distributions
4099*c54f35caSApple OSS Distributions //*********************************************************************************
4100*c54f35caSApple OSS Distributions // [private] notifyAll
4101*c54f35caSApple OSS Distributions //*********************************************************************************
4102*c54f35caSApple OSS Distributions
4103*c54f35caSApple OSS Distributions IOReturn
notifyAll(uint32_t nextMS)4104*c54f35caSApple OSS Distributions IOService::notifyAll( uint32_t nextMS )
4105*c54f35caSApple OSS Distributions {
4106*c54f35caSApple OSS Distributions // Save the machine state to be restored by notifyInterestedDriversDone()
4107*c54f35caSApple OSS Distributions
4108*c54f35caSApple OSS Distributions PM_ASSERT_IN_GATE();
4109*c54f35caSApple OSS Distributions MS_PUSH(nextMS);
4110*c54f35caSApple OSS Distributions fMachineState = kIOPM_DriverThreadCallDone;
4111*c54f35caSApple OSS Distributions fDriverCallReason = fIsPreChange ?
4112*c54f35caSApple OSS Distributions kDriverCallInformPreChange : kDriverCallInformPostChange;
4113*c54f35caSApple OSS Distributions
4114*c54f35caSApple OSS Distributions if (!notifyInterestedDrivers()) {
4115*c54f35caSApple OSS Distributions notifyInterestedDriversDone();
4116*c54f35caSApple OSS Distributions }
4117*c54f35caSApple OSS Distributions
4118*c54f35caSApple OSS Distributions return IOPMWillAckLater;
4119*c54f35caSApple OSS Distributions }
4120*c54f35caSApple OSS Distributions
4121*c54f35caSApple OSS Distributions //*********************************************************************************
4122*c54f35caSApple OSS Distributions // [private, static] pmDriverCallout
4123*c54f35caSApple OSS Distributions //
4124*c54f35caSApple OSS Distributions // Thread call context
4125*c54f35caSApple OSS Distributions //*********************************************************************************
4126*c54f35caSApple OSS Distributions
4127*c54f35caSApple OSS Distributions IOReturn
actionDriverCalloutDone(OSObject * target,void * arg0,void * arg1,void * arg2,void * arg3)4128*c54f35caSApple OSS Distributions IOService::actionDriverCalloutDone(
4129*c54f35caSApple OSS Distributions OSObject * target,
4130*c54f35caSApple OSS Distributions void * arg0, void * arg1,
4131*c54f35caSApple OSS Distributions void * arg2, void * arg3 )
4132*c54f35caSApple OSS Distributions {
4133*c54f35caSApple OSS Distributions IOServicePM * pwrMgt = (IOServicePM *) arg0;
4134*c54f35caSApple OSS Distributions
4135*c54f35caSApple OSS Distributions assert( fDriverCallBusy );
4136*c54f35caSApple OSS Distributions fDriverCallBusy = false;
4137*c54f35caSApple OSS Distributions
4138*c54f35caSApple OSS Distributions assert(gIOPMWorkQueue);
4139*c54f35caSApple OSS Distributions gIOPMWorkQueue->signalWorkAvailable();
4140*c54f35caSApple OSS Distributions
4141*c54f35caSApple OSS Distributions return kIOReturnSuccess;
4142*c54f35caSApple OSS Distributions }
4143*c54f35caSApple OSS Distributions
4144*c54f35caSApple OSS Distributions void
pmDriverCallout(IOService * from,__unused thread_call_param_t p)4145*c54f35caSApple OSS Distributions IOService::pmDriverCallout( IOService * from,
4146*c54f35caSApple OSS Distributions __unused thread_call_param_t p)
4147*c54f35caSApple OSS Distributions {
4148*c54f35caSApple OSS Distributions assert(from);
4149*c54f35caSApple OSS Distributions from->startDriverCalloutTimer();
4150*c54f35caSApple OSS Distributions switch (from->fDriverCallReason) {
4151*c54f35caSApple OSS Distributions case kDriverCallSetPowerState:
4152*c54f35caSApple OSS Distributions from->driverSetPowerState();
4153*c54f35caSApple OSS Distributions break;
4154*c54f35caSApple OSS Distributions
4155*c54f35caSApple OSS Distributions case kDriverCallInformPreChange:
4156*c54f35caSApple OSS Distributions case kDriverCallInformPostChange:
4157*c54f35caSApple OSS Distributions from->driverInformPowerChange();
4158*c54f35caSApple OSS Distributions break;
4159*c54f35caSApple OSS Distributions
4160*c54f35caSApple OSS Distributions case kRootDomainInformPreChange:
4161*c54f35caSApple OSS Distributions getPMRootDomain()->willNotifyPowerChildren(from->fHeadNotePowerState);
4162*c54f35caSApple OSS Distributions break;
4163*c54f35caSApple OSS Distributions
4164*c54f35caSApple OSS Distributions default:
4165*c54f35caSApple OSS Distributions panic("IOService::pmDriverCallout bad machine state %x",
4166*c54f35caSApple OSS Distributions from->fDriverCallReason);
4167*c54f35caSApple OSS Distributions }
4168*c54f35caSApple OSS Distributions from->stopDriverCalloutTimer();
4169*c54f35caSApple OSS Distributions
4170*c54f35caSApple OSS Distributions gIOPMWorkLoop->runAction(actionDriverCalloutDone,
4171*c54f35caSApple OSS Distributions /* target */ from,
4172*c54f35caSApple OSS Distributions /* arg0 */ (void *) from->pwrMgt );
4173*c54f35caSApple OSS Distributions }
4174*c54f35caSApple OSS Distributions
4175*c54f35caSApple OSS Distributions //*********************************************************************************
4176*c54f35caSApple OSS Distributions // [private] driverSetPowerState
4177*c54f35caSApple OSS Distributions //
4178*c54f35caSApple OSS Distributions // Thread call context
4179*c54f35caSApple OSS Distributions //*********************************************************************************
4180*c54f35caSApple OSS Distributions
4181*c54f35caSApple OSS Distributions void
driverSetPowerState(void)4182*c54f35caSApple OSS Distributions IOService::driverSetPowerState( void )
4183*c54f35caSApple OSS Distributions {
4184*c54f35caSApple OSS Distributions IOPMPowerStateIndex powerState;
4185*c54f35caSApple OSS Distributions DriverCallParam * param;
4186*c54f35caSApple OSS Distributions IOPMDriverCallEntry callEntry;
4187*c54f35caSApple OSS Distributions AbsoluteTime end;
4188*c54f35caSApple OSS Distributions IOReturn result;
4189*c54f35caSApple OSS Distributions uint32_t oldPowerState = getPowerState();
4190*c54f35caSApple OSS Distributions const OSMetaClass *controllingDriverMetaClass = NULL;
4191*c54f35caSApple OSS Distributions uint32_t controllingDriverRegistryEntryID = 0;
4192*c54f35caSApple OSS Distributions
4193*c54f35caSApple OSS Distributions assert( fDriverCallBusy );
4194*c54f35caSApple OSS Distributions assert( fDriverCallParamPtr );
4195*c54f35caSApple OSS Distributions assert( fDriverCallParamCount == 1 );
4196*c54f35caSApple OSS Distributions
4197*c54f35caSApple OSS Distributions param = (DriverCallParam *) fDriverCallParamPtr;
4198*c54f35caSApple OSS Distributions powerState = fHeadNotePowerState;
4199*c54f35caSApple OSS Distributions if (fControllingDriver) {
4200*c54f35caSApple OSS Distributions controllingDriverMetaClass = fControllingDriver->getMetaClass();
4201*c54f35caSApple OSS Distributions controllingDriverRegistryEntryID = (uint32_t)fControllingDriver->getRegistryEntryID();
4202*c54f35caSApple OSS Distributions }
4203*c54f35caSApple OSS Distributions
4204*c54f35caSApple OSS Distributions if (assertPMDriverCall(&callEntry, kIOPMDriverCallMethodSetPowerState)) {
4205*c54f35caSApple OSS Distributions SOCD_TRACE_XNU_START(PM_SET_POWER_STATE,
4206*c54f35caSApple OSS Distributions ADDR(controllingDriverMetaClass),
4207*c54f35caSApple OSS Distributions ADDR(this->getMetaClass()),
4208*c54f35caSApple OSS Distributions PACK_2X32(VALUE(this->getRegistryEntryID()), VALUE(controllingDriverRegistryEntryID)),
4209*c54f35caSApple OSS Distributions PACK_2X32(VALUE(powerState), VALUE(oldPowerState)));
4210*c54f35caSApple OSS Distributions
4211*c54f35caSApple OSS Distributions OUR_PMLogFuncStart(kPMLogProgramHardware, (uintptr_t) this, powerState);
4212*c54f35caSApple OSS Distributions clock_get_uptime(&fDriverCallStartTime);
4213*c54f35caSApple OSS Distributions
4214*c54f35caSApple OSS Distributions if (reserved && reserved->uvars && reserved->uvars->userServer) {
4215*c54f35caSApple OSS Distributions result = reserved->uvars->userServer->serviceSetPowerState(fControllingDriver, this, fHeadNotePowerArrayEntry->capabilityFlags, powerState);
4216*c54f35caSApple OSS Distributions } else {
4217*c54f35caSApple OSS Distributions result = fControllingDriver->setPowerState( powerState, this );
4218*c54f35caSApple OSS Distributions }
4219*c54f35caSApple OSS Distributions clock_get_uptime(&end);
4220*c54f35caSApple OSS Distributions OUR_PMLogFuncEnd(kPMLogProgramHardware, (uintptr_t) this, (UInt32) result);
4221*c54f35caSApple OSS Distributions SOCD_TRACE_XNU_END(PM_SET_POWER_STATE,
4222*c54f35caSApple OSS Distributions ADDR(controllingDriverMetaClass),
4223*c54f35caSApple OSS Distributions ADDR(this->getMetaClass()),
4224*c54f35caSApple OSS Distributions PACK_2X32(VALUE(this->getRegistryEntryID()), VALUE(controllingDriverRegistryEntryID)),
4225*c54f35caSApple OSS Distributions PACK_2X32(VALUE(powerState), VALUE(result)));
4226*c54f35caSApple OSS Distributions
4227*c54f35caSApple OSS Distributions deassertPMDriverCall(&callEntry);
4228*c54f35caSApple OSS Distributions
4229*c54f35caSApple OSS Distributions // Record the most recent max power state residency timings.
4230*c54f35caSApple OSS Distributions // Use with DeviceActiveTimestamp to diagnose tickle issues.
4231*c54f35caSApple OSS Distributions if (powerState == fHighestPowerState) {
4232*c54f35caSApple OSS Distributions fMaxPowerStateEntryTime = end;
4233*c54f35caSApple OSS Distributions } else if (oldPowerState == fHighestPowerState) {
4234*c54f35caSApple OSS Distributions fMaxPowerStateExitTime = end;
4235*c54f35caSApple OSS Distributions }
4236*c54f35caSApple OSS Distributions
4237*c54f35caSApple OSS Distributions if (result < 0) {
4238*c54f35caSApple OSS Distributions PM_LOG("%s::setPowerState(%p, %lu -> %lu) returned 0x%x\n",
4239*c54f35caSApple OSS Distributions fName, OBFUSCATE(this), fCurrentPowerState, powerState, result);
4240*c54f35caSApple OSS Distributions }
4241*c54f35caSApple OSS Distributions
4242*c54f35caSApple OSS Distributions
4243*c54f35caSApple OSS Distributions if ((result == IOPMAckImplied) || (result < 0)) {
4244*c54f35caSApple OSS Distributions uint64_t nsec;
4245*c54f35caSApple OSS Distributions
4246*c54f35caSApple OSS Distributions SUB_ABSOLUTETIME(&end, &fDriverCallStartTime);
4247*c54f35caSApple OSS Distributions absolutetime_to_nanoseconds(end, &nsec);
4248*c54f35caSApple OSS Distributions if (nsec > gIOPMSetPowerStateLogNS) {
4249*c54f35caSApple OSS Distributions getPMRootDomain()->pmStatsRecordApplicationResponse(
4250*c54f35caSApple OSS Distributions gIOPMStatsDriverPSChangeSlow,
4251*c54f35caSApple OSS Distributions fName, kDriverCallSetPowerState, NS_TO_MS(nsec), getRegistryEntryID(),
4252*c54f35caSApple OSS Distributions NULL, powerState);
4253*c54f35caSApple OSS Distributions }
4254*c54f35caSApple OSS Distributions }
4255*c54f35caSApple OSS Distributions } else {
4256*c54f35caSApple OSS Distributions result = kIOPMAckImplied;
4257*c54f35caSApple OSS Distributions }
4258*c54f35caSApple OSS Distributions
4259*c54f35caSApple OSS Distributions param->Result = result;
4260*c54f35caSApple OSS Distributions }
4261*c54f35caSApple OSS Distributions
4262*c54f35caSApple OSS Distributions //*********************************************************************************
4263*c54f35caSApple OSS Distributions // [private] driverInformPowerChange
4264*c54f35caSApple OSS Distributions //
4265*c54f35caSApple OSS Distributions // Thread call context
4266*c54f35caSApple OSS Distributions //*********************************************************************************
4267*c54f35caSApple OSS Distributions
4268*c54f35caSApple OSS Distributions void
driverInformPowerChange(void)4269*c54f35caSApple OSS Distributions IOService::driverInformPowerChange( void )
4270*c54f35caSApple OSS Distributions {
4271*c54f35caSApple OSS Distributions IOPMinformee * informee;
4272*c54f35caSApple OSS Distributions IOService * driver;
4273*c54f35caSApple OSS Distributions DriverCallParam * param;
4274*c54f35caSApple OSS Distributions IOPMDriverCallEntry callEntry;
4275*c54f35caSApple OSS Distributions IOPMPowerFlags powerFlags;
4276*c54f35caSApple OSS Distributions IOPMPowerStateIndex powerState;
4277*c54f35caSApple OSS Distributions AbsoluteTime end;
4278*c54f35caSApple OSS Distributions IOReturn result;
4279*c54f35caSApple OSS Distributions IOItemCount count;
4280*c54f35caSApple OSS Distributions IOOptionBits callMethod = (fDriverCallReason == kDriverCallInformPreChange) ?
4281*c54f35caSApple OSS Distributions kIOPMDriverCallMethodWillChange : kIOPMDriverCallMethodDidChange;
4282*c54f35caSApple OSS Distributions
4283*c54f35caSApple OSS Distributions assert( fDriverCallBusy );
4284*c54f35caSApple OSS Distributions assert( fDriverCallParamPtr );
4285*c54f35caSApple OSS Distributions assert( fDriverCallParamCount );
4286*c54f35caSApple OSS Distributions
4287*c54f35caSApple OSS Distributions param = (DriverCallParam *) fDriverCallParamPtr;
4288*c54f35caSApple OSS Distributions count = fDriverCallParamCount;
4289*c54f35caSApple OSS Distributions
4290*c54f35caSApple OSS Distributions powerFlags = fHeadNotePowerArrayEntry->capabilityFlags;
4291*c54f35caSApple OSS Distributions powerState = fHeadNotePowerState;
4292*c54f35caSApple OSS Distributions
4293*c54f35caSApple OSS Distributions for (IOItemCount i = 0; i < count; i++) {
4294*c54f35caSApple OSS Distributions informee = (IOPMinformee *) param->Target;
4295*c54f35caSApple OSS Distributions driver = informee->whatObject;
4296*c54f35caSApple OSS Distributions
4297*c54f35caSApple OSS Distributions if (assertPMDriverCall(&callEntry, callMethod, informee)) {
4298*c54f35caSApple OSS Distributions SOCD_TRACE_XNU_START(PM_INFORM_POWER_CHANGE,
4299*c54f35caSApple OSS Distributions ADDR(driver->getMetaClass()),
4300*c54f35caSApple OSS Distributions ADDR(this->getMetaClass()),
4301*c54f35caSApple OSS Distributions PACK_2X32(VALUE(this->getRegistryEntryID()), VALUE(driver->getRegistryEntryID())),
4302*c54f35caSApple OSS Distributions PACK_2X32(VALUE(powerState), VALUE(fDriverCallReason)));
4303*c54f35caSApple OSS Distributions
4304*c54f35caSApple OSS Distributions if (fDriverCallReason == kDriverCallInformPreChange) {
4305*c54f35caSApple OSS Distributions OUR_PMLogFuncStart(kPMLogInformDriverPreChange, (uintptr_t) this, powerState);
4306*c54f35caSApple OSS Distributions clock_get_uptime(&informee->startTime);
4307*c54f35caSApple OSS Distributions result = driver->powerStateWillChangeTo(powerFlags, powerState, this);
4308*c54f35caSApple OSS Distributions clock_get_uptime(&end);
4309*c54f35caSApple OSS Distributions OUR_PMLogFuncEnd(kPMLogInformDriverPreChange, (uintptr_t) this, result);
4310*c54f35caSApple OSS Distributions } else {
4311*c54f35caSApple OSS Distributions OUR_PMLogFuncStart(kPMLogInformDriverPostChange, (uintptr_t) this, powerState);
4312*c54f35caSApple OSS Distributions clock_get_uptime(&informee->startTime);
4313*c54f35caSApple OSS Distributions result = driver->powerStateDidChangeTo(powerFlags, powerState, this);
4314*c54f35caSApple OSS Distributions clock_get_uptime(&end);
4315*c54f35caSApple OSS Distributions OUR_PMLogFuncEnd(kPMLogInformDriverPostChange, (uintptr_t) this, result);
4316*c54f35caSApple OSS Distributions }
4317*c54f35caSApple OSS Distributions
4318*c54f35caSApple OSS Distributions SOCD_TRACE_XNU_END(PM_INFORM_POWER_CHANGE,
4319*c54f35caSApple OSS Distributions ADDR(driver->getMetaClass()),
4320*c54f35caSApple OSS Distributions ADDR(this->getMetaClass()),
4321*c54f35caSApple OSS Distributions PACK_2X32(VALUE(this->getRegistryEntryID()), VALUE(driver->getRegistryEntryID())),
4322*c54f35caSApple OSS Distributions PACK_2X32(VALUE(result), VALUE(fDriverCallReason)));
4323*c54f35caSApple OSS Distributions
4324*c54f35caSApple OSS Distributions deassertPMDriverCall(&callEntry);
4325*c54f35caSApple OSS Distributions
4326*c54f35caSApple OSS Distributions
4327*c54f35caSApple OSS Distributions if ((result == IOPMAckImplied) || (result < 0)) {
4328*c54f35caSApple OSS Distributions uint64_t nsec;
4329*c54f35caSApple OSS Distributions
4330*c54f35caSApple OSS Distributions SUB_ABSOLUTETIME(&end, &informee->startTime);
4331*c54f35caSApple OSS Distributions absolutetime_to_nanoseconds(end, &nsec);
4332*c54f35caSApple OSS Distributions if (nsec > gIOPMSetPowerStateLogNS) {
4333*c54f35caSApple OSS Distributions getPMRootDomain()->pmStatsRecordApplicationResponse(
4334*c54f35caSApple OSS Distributions gIOPMStatsDriverPSChangeSlow, driver->getName(),
4335*c54f35caSApple OSS Distributions fDriverCallReason, NS_TO_MS(nsec), driver->getRegistryEntryID(),
4336*c54f35caSApple OSS Distributions NULL, powerState);
4337*c54f35caSApple OSS Distributions }
4338*c54f35caSApple OSS Distributions }
4339*c54f35caSApple OSS Distributions } else {
4340*c54f35caSApple OSS Distributions result = kIOPMAckImplied;
4341*c54f35caSApple OSS Distributions }
4342*c54f35caSApple OSS Distributions
4343*c54f35caSApple OSS Distributions param->Result = result;
4344*c54f35caSApple OSS Distributions param++;
4345*c54f35caSApple OSS Distributions }
4346*c54f35caSApple OSS Distributions }
4347*c54f35caSApple OSS Distributions
4348*c54f35caSApple OSS Distributions //*********************************************************************************
4349*c54f35caSApple OSS Distributions // [private, static] pmDriverCalloutTimer
4350*c54f35caSApple OSS Distributions //
4351*c54f35caSApple OSS Distributions // Thread call context.
4352*c54f35caSApple OSS Distributions //*********************************************************************************
4353*c54f35caSApple OSS Distributions
4354*c54f35caSApple OSS Distributions void
startDriverCalloutTimer(void)4355*c54f35caSApple OSS Distributions IOService::startDriverCalloutTimer( void )
4356*c54f35caSApple OSS Distributions {
4357*c54f35caSApple OSS Distributions AbsoluteTime deadline;
4358*c54f35caSApple OSS Distributions boolean_t pending;
4359*c54f35caSApple OSS Distributions
4360*c54f35caSApple OSS Distributions clock_interval_to_deadline(gDriverCalloutTimer, kMillisecondScale, &deadline);
4361*c54f35caSApple OSS Distributions
4362*c54f35caSApple OSS Distributions retain();
4363*c54f35caSApple OSS Distributions pending = thread_call_enter_delayed(fDriverCallTimer, deadline);
4364*c54f35caSApple OSS Distributions if (pending) {
4365*c54f35caSApple OSS Distributions release();
4366*c54f35caSApple OSS Distributions }
4367*c54f35caSApple OSS Distributions }
4368*c54f35caSApple OSS Distributions
4369*c54f35caSApple OSS Distributions void
stopDriverCalloutTimer(void)4370*c54f35caSApple OSS Distributions IOService::stopDriverCalloutTimer( void )
4371*c54f35caSApple OSS Distributions {
4372*c54f35caSApple OSS Distributions boolean_t pending;
4373*c54f35caSApple OSS Distributions
4374*c54f35caSApple OSS Distributions pending = thread_call_cancel(fDriverCallTimer);
4375*c54f35caSApple OSS Distributions if (pending) {
4376*c54f35caSApple OSS Distributions release();
4377*c54f35caSApple OSS Distributions }
4378*c54f35caSApple OSS Distributions }
4379*c54f35caSApple OSS Distributions
4380*c54f35caSApple OSS Distributions void
pmDriverCalloutTimer(thread_call_param_t arg0,__unused thread_call_param_t arg1)4381*c54f35caSApple OSS Distributions IOService::pmDriverCalloutTimer( thread_call_param_t arg0,
4382*c54f35caSApple OSS Distributions __unused thread_call_param_t arg1)
4383*c54f35caSApple OSS Distributions {
4384*c54f35caSApple OSS Distributions assert(arg0);
4385*c54f35caSApple OSS Distributions IOService *from = (IOService *) arg0;
4386*c54f35caSApple OSS Distributions PM_LOG("PM waiting on pmDriverCallout(0x%x) to %s (%u ms)\n", from->fDriverCallReason, from->fName, gDriverCalloutTimer);
4387*c54f35caSApple OSS Distributions from->release();
4388*c54f35caSApple OSS Distributions }
4389*c54f35caSApple OSS Distributions
4390*c54f35caSApple OSS Distributions //*********************************************************************************
4391*c54f35caSApple OSS Distributions // [private] notifyChild
4392*c54f35caSApple OSS Distributions //
4393*c54f35caSApple OSS Distributions // Notify a power domain child of an upcoming power change.
4394*c54f35caSApple OSS Distributions // If the object acknowledges the current change, we return TRUE.
4395*c54f35caSApple OSS Distributions //*********************************************************************************
4396*c54f35caSApple OSS Distributions
4397*c54f35caSApple OSS Distributions bool
notifyChild(IOPowerConnection * theNub)4398*c54f35caSApple OSS Distributions IOService::notifyChild( IOPowerConnection * theNub )
4399*c54f35caSApple OSS Distributions {
4400*c54f35caSApple OSS Distributions IOReturn ret = IOPMAckImplied;
4401*c54f35caSApple OSS Distributions unsigned long childPower;
4402*c54f35caSApple OSS Distributions IOService * theChild;
4403*c54f35caSApple OSS Distributions IOPMRequest * childRequest;
4404*c54f35caSApple OSS Distributions IOPMPowerChangeFlags requestArg2;
4405*c54f35caSApple OSS Distributions int requestType;
4406*c54f35caSApple OSS Distributions
4407*c54f35caSApple OSS Distributions PM_ASSERT_IN_GATE();
4408*c54f35caSApple OSS Distributions theChild = (IOService *)(theNub->copyChildEntry(gIOPowerPlane));
4409*c54f35caSApple OSS Distributions if (!theChild) {
4410*c54f35caSApple OSS Distributions return true;
4411*c54f35caSApple OSS Distributions }
4412*c54f35caSApple OSS Distributions
4413*c54f35caSApple OSS Distributions // Unless the child handles the notification immediately and returns
4414*c54f35caSApple OSS Distributions // kIOPMAckImplied, we'll be awaiting their acknowledgement later.
4415*c54f35caSApple OSS Distributions fHeadNotePendingAcks++;
4416*c54f35caSApple OSS Distributions theNub->setAwaitingAck(true);
4417*c54f35caSApple OSS Distributions
4418*c54f35caSApple OSS Distributions requestArg2 = fHeadNoteChangeFlags;
4419*c54f35caSApple OSS Distributions if (StateOrder(fHeadNotePowerState) < StateOrder(fCurrentPowerState)) {
4420*c54f35caSApple OSS Distributions requestArg2 |= kIOPMDomainPowerDrop;
4421*c54f35caSApple OSS Distributions }
4422*c54f35caSApple OSS Distributions
4423*c54f35caSApple OSS Distributions requestType = fIsPreChange ?
4424*c54f35caSApple OSS Distributions kIOPMRequestTypePowerDomainWillChange :
4425*c54f35caSApple OSS Distributions kIOPMRequestTypePowerDomainDidChange;
4426*c54f35caSApple OSS Distributions
4427*c54f35caSApple OSS Distributions childRequest = acquirePMRequest( theChild, requestType );
4428*c54f35caSApple OSS Distributions if (childRequest) {
4429*c54f35caSApple OSS Distributions theNub->retain();
4430*c54f35caSApple OSS Distributions childRequest->fArg0 = (void *) fHeadNotePowerArrayEntry->outputPowerFlags;
4431*c54f35caSApple OSS Distributions childRequest->fArg1 = (void *) theNub;
4432*c54f35caSApple OSS Distributions childRequest->fArg2 = (void *)(uintptr_t) requestArg2;
4433*c54f35caSApple OSS Distributions theChild->submitPMRequest( childRequest );
4434*c54f35caSApple OSS Distributions ret = IOPMWillAckLater;
4435*c54f35caSApple OSS Distributions } else {
4436*c54f35caSApple OSS Distributions ret = IOPMAckImplied;
4437*c54f35caSApple OSS Distributions fHeadNotePendingAcks--;
4438*c54f35caSApple OSS Distributions theNub->setAwaitingAck(false);
4439*c54f35caSApple OSS Distributions childPower = theChild->currentPowerConsumption();
4440*c54f35caSApple OSS Distributions if (childPower == kIOPMUnknown) {
4441*c54f35caSApple OSS Distributions fHeadNotePowerArrayEntry->staticPower = kIOPMUnknown;
4442*c54f35caSApple OSS Distributions } else {
4443*c54f35caSApple OSS Distributions if (fHeadNotePowerArrayEntry->staticPower != kIOPMUnknown) {
4444*c54f35caSApple OSS Distributions fHeadNotePowerArrayEntry->staticPower += childPower;
4445*c54f35caSApple OSS Distributions }
4446*c54f35caSApple OSS Distributions }
4447*c54f35caSApple OSS Distributions }
4448*c54f35caSApple OSS Distributions
4449*c54f35caSApple OSS Distributions theChild->release();
4450*c54f35caSApple OSS Distributions return IOPMAckImplied == ret;
4451*c54f35caSApple OSS Distributions }
4452*c54f35caSApple OSS Distributions
4453*c54f35caSApple OSS Distributions //*********************************************************************************
4454*c54f35caSApple OSS Distributions // [private] notifyControllingDriver
4455*c54f35caSApple OSS Distributions //*********************************************************************************
4456*c54f35caSApple OSS Distributions
4457*c54f35caSApple OSS Distributions bool
notifyControllingDriver(void)4458*c54f35caSApple OSS Distributions IOService::notifyControllingDriver( void )
4459*c54f35caSApple OSS Distributions {
4460*c54f35caSApple OSS Distributions DriverCallParam * param;
4461*c54f35caSApple OSS Distributions
4462*c54f35caSApple OSS Distributions PM_ASSERT_IN_GATE();
4463*c54f35caSApple OSS Distributions assert( fDriverCallParamCount == 0 );
4464*c54f35caSApple OSS Distributions assert( fControllingDriver );
4465*c54f35caSApple OSS Distributions
4466*c54f35caSApple OSS Distributions if (fInitialSetPowerState) {
4467*c54f35caSApple OSS Distributions fInitialSetPowerState = false;
4468*c54f35caSApple OSS Distributions fHeadNoteChangeFlags |= kIOPMInitialPowerChange;
4469*c54f35caSApple OSS Distributions
4470*c54f35caSApple OSS Distributions // Driver specified flag to skip the inital setPowerState()
4471*c54f35caSApple OSS Distributions if (fHeadNotePowerArrayEntry->capabilityFlags & kIOPMInitialDeviceState) {
4472*c54f35caSApple OSS Distributions return false;
4473*c54f35caSApple OSS Distributions }
4474*c54f35caSApple OSS Distributions }
4475*c54f35caSApple OSS Distributions
4476*c54f35caSApple OSS Distributions param = (DriverCallParam *) fDriverCallParamPtr;
4477*c54f35caSApple OSS Distributions if (!param) {
4478*c54f35caSApple OSS Distributions param = IONew(DriverCallParam, 1);
4479*c54f35caSApple OSS Distributions if (!param) {
4480*c54f35caSApple OSS Distributions return false; // no memory
4481*c54f35caSApple OSS Distributions }
4482*c54f35caSApple OSS Distributions fDriverCallParamPtr = (void *) param;
4483*c54f35caSApple OSS Distributions fDriverCallParamSlots = 1;
4484*c54f35caSApple OSS Distributions }
4485*c54f35caSApple OSS Distributions
4486*c54f35caSApple OSS Distributions param->Target = fControllingDriver;
4487*c54f35caSApple OSS Distributions fDriverCallParamCount = 1;
4488*c54f35caSApple OSS Distributions fDriverTimer = -1;
4489*c54f35caSApple OSS Distributions
4490*c54f35caSApple OSS Distributions // Block state machine and wait for callout completion.
4491*c54f35caSApple OSS Distributions assert(!fDriverCallBusy);
4492*c54f35caSApple OSS Distributions fDriverCallBusy = true;
4493*c54f35caSApple OSS Distributions thread_call_enter( fDriverCallEntry );
4494*c54f35caSApple OSS Distributions
4495*c54f35caSApple OSS Distributions return true;
4496*c54f35caSApple OSS Distributions }
4497*c54f35caSApple OSS Distributions
4498*c54f35caSApple OSS Distributions //*********************************************************************************
4499*c54f35caSApple OSS Distributions // [private] notifyControllingDriverDone
4500*c54f35caSApple OSS Distributions //*********************************************************************************
4501*c54f35caSApple OSS Distributions
4502*c54f35caSApple OSS Distributions void
notifyControllingDriverDone(void)4503*c54f35caSApple OSS Distributions IOService::notifyControllingDriverDone( void )
4504*c54f35caSApple OSS Distributions {
4505*c54f35caSApple OSS Distributions DriverCallParam * param;
4506*c54f35caSApple OSS Distributions IOReturn result;
4507*c54f35caSApple OSS Distributions
4508*c54f35caSApple OSS Distributions PM_ASSERT_IN_GATE();
4509*c54f35caSApple OSS Distributions param = (DriverCallParam *) fDriverCallParamPtr;
4510*c54f35caSApple OSS Distributions
4511*c54f35caSApple OSS Distributions assert( fDriverCallBusy == false );
4512*c54f35caSApple OSS Distributions assert( fMachineState == kIOPM_DriverThreadCallDone );
4513*c54f35caSApple OSS Distributions
4514*c54f35caSApple OSS Distributions if (param && fDriverCallParamCount) {
4515*c54f35caSApple OSS Distributions assert(fDriverCallParamCount == 1);
4516*c54f35caSApple OSS Distributions
4517*c54f35caSApple OSS Distributions // the return value from setPowerState()
4518*c54f35caSApple OSS Distributions result = param->Result;
4519*c54f35caSApple OSS Distributions
4520*c54f35caSApple OSS Distributions if ((result == IOPMAckImplied) || (result < 0)) {
4521*c54f35caSApple OSS Distributions fDriverTimer = 0;
4522*c54f35caSApple OSS Distributions } else if (fDriverTimer) {
4523*c54f35caSApple OSS Distributions assert(fDriverTimer == -1);
4524*c54f35caSApple OSS Distributions
4525*c54f35caSApple OSS Distributions // Driver has not acked, and has returned a positive result.
4526*c54f35caSApple OSS Distributions // Enforce a minimum permissible timeout value.
4527*c54f35caSApple OSS Distributions // Make the min value large enough so timeout is less likely
4528*c54f35caSApple OSS Distributions // to occur if a driver misinterpreted that the return value
4529*c54f35caSApple OSS Distributions // should be in microsecond units. And make it large enough
4530*c54f35caSApple OSS Distributions // to be noticeable if a driver neglects to ack.
4531*c54f35caSApple OSS Distributions
4532*c54f35caSApple OSS Distributions if (result < kMinAckTimeoutTicks) {
4533*c54f35caSApple OSS Distributions result = kMinAckTimeoutTicks;
4534*c54f35caSApple OSS Distributions }
4535*c54f35caSApple OSS Distributions
4536*c54f35caSApple OSS Distributions fDriverTimer = (result / (ACK_TIMER_PERIOD / ns_per_us)) + 1;
4537*c54f35caSApple OSS Distributions }
4538*c54f35caSApple OSS Distributions // else, child has already acked and driver_timer reset to 0.
4539*c54f35caSApple OSS Distributions
4540*c54f35caSApple OSS Distributions fDriverCallParamCount = 0;
4541*c54f35caSApple OSS Distributions
4542*c54f35caSApple OSS Distributions if (fDriverTimer) {
4543*c54f35caSApple OSS Distributions OUR_PMLog(kPMLogStartAckTimer, 0, 0);
4544*c54f35caSApple OSS Distributions start_ack_timer();
4545*c54f35caSApple OSS Distributions getPMRootDomain()->reset_watchdog_timer(this, result / USEC_PER_SEC + 1);
4546*c54f35caSApple OSS Distributions }
4547*c54f35caSApple OSS Distributions }
4548*c54f35caSApple OSS Distributions
4549*c54f35caSApple OSS Distributions MS_POP(); // pushed by OurChangeSetPowerState()
4550*c54f35caSApple OSS Distributions fIsPreChange = false;
4551*c54f35caSApple OSS Distributions }
4552*c54f35caSApple OSS Distributions
4553*c54f35caSApple OSS Distributions //*********************************************************************************
4554*c54f35caSApple OSS Distributions // [private] all_done
4555*c54f35caSApple OSS Distributions //
4556*c54f35caSApple OSS Distributions // A power change is done.
4557*c54f35caSApple OSS Distributions //*********************************************************************************
4558*c54f35caSApple OSS Distributions
4559*c54f35caSApple OSS Distributions void
all_done(void)4560*c54f35caSApple OSS Distributions IOService::all_done( void )
4561*c54f35caSApple OSS Distributions {
4562*c54f35caSApple OSS Distributions IOPMPowerStateIndex prevPowerState;
4563*c54f35caSApple OSS Distributions const IOPMPSEntry * powerStatePtr;
4564*c54f35caSApple OSS Distributions IOPMDriverCallEntry callEntry;
4565*c54f35caSApple OSS Distributions uint32_t prevMachineState = fMachineState;
4566*c54f35caSApple OSS Distributions bool actionCalled = false;
4567*c54f35caSApple OSS Distributions uint64_t ts;
4568*c54f35caSApple OSS Distributions
4569*c54f35caSApple OSS Distributions fMachineState = kIOPM_Finished;
4570*c54f35caSApple OSS Distributions
4571*c54f35caSApple OSS Distributions if ((fHeadNoteChangeFlags & kIOPMSynchronize) &&
4572*c54f35caSApple OSS Distributions ((prevMachineState == kIOPM_Finished) ||
4573*c54f35caSApple OSS Distributions (prevMachineState == kIOPM_SyncFinish))) {
4574*c54f35caSApple OSS Distributions // Sync operation and no power change occurred.
4575*c54f35caSApple OSS Distributions // Do not inform driver and clients about this request completion,
4576*c54f35caSApple OSS Distributions // except for the originator (root domain).
4577*c54f35caSApple OSS Distributions
4578*c54f35caSApple OSS Distributions PM_ACTION_CHANGE(actionPowerChangeDone,
4579*c54f35caSApple OSS Distributions fHeadNotePowerState, fHeadNoteChangeFlags);
4580*c54f35caSApple OSS Distributions
4581*c54f35caSApple OSS Distributions if (getPMRequestType() == kIOPMRequestTypeSynchronizePowerTree) {
4582*c54f35caSApple OSS Distributions powerChangeDone(fCurrentPowerState);
4583*c54f35caSApple OSS Distributions } else if (fAdvisoryTickleUsed) {
4584*c54f35caSApple OSS Distributions // Not root domain and advisory tickle target.
4585*c54f35caSApple OSS Distributions // Re-adjust power after power tree sync at the 'did' pass
4586*c54f35caSApple OSS Distributions // to recompute desire and adjust power state between dark
4587*c54f35caSApple OSS Distributions // and full wake transitions. Root domain is responsible
4588*c54f35caSApple OSS Distributions // for calling setAdvisoryTickleEnable() before starting
4589*c54f35caSApple OSS Distributions // the kIOPMSynchronize power change.
4590*c54f35caSApple OSS Distributions
4591*c54f35caSApple OSS Distributions if (!fAdjustPowerScheduled &&
4592*c54f35caSApple OSS Distributions (fHeadNoteChangeFlags & kIOPMDomainDidChange)) {
4593*c54f35caSApple OSS Distributions IOPMRequest * request;
4594*c54f35caSApple OSS Distributions request = acquirePMRequest( this, kIOPMRequestTypeAdjustPowerState );
4595*c54f35caSApple OSS Distributions if (request) {
4596*c54f35caSApple OSS Distributions submitPMRequest( request );
4597*c54f35caSApple OSS Distributions fAdjustPowerScheduled = true;
4598*c54f35caSApple OSS Distributions }
4599*c54f35caSApple OSS Distributions }
4600*c54f35caSApple OSS Distributions }
4601*c54f35caSApple OSS Distributions
4602*c54f35caSApple OSS Distributions return;
4603*c54f35caSApple OSS Distributions }
4604*c54f35caSApple OSS Distributions
4605*c54f35caSApple OSS Distributions // our power change
4606*c54f35caSApple OSS Distributions if (fHeadNoteChangeFlags & kIOPMSelfInitiated) {
4607*c54f35caSApple OSS Distributions // power state changed
4608*c54f35caSApple OSS Distributions if ((fHeadNoteChangeFlags & kIOPMNotDone) == 0) {
4609*c54f35caSApple OSS Distributions trackSystemSleepPreventers(
4610*c54f35caSApple OSS Distributions fCurrentPowerState, fHeadNotePowerState, fHeadNoteChangeFlags);
4611*c54f35caSApple OSS Distributions
4612*c54f35caSApple OSS Distributions // we changed, tell our parent
4613*c54f35caSApple OSS Distributions requestDomainPower(fHeadNotePowerState);
4614*c54f35caSApple OSS Distributions
4615*c54f35caSApple OSS Distributions // yes, did power raise?
4616*c54f35caSApple OSS Distributions if (StateOrder(fCurrentPowerState) < StateOrder(fHeadNotePowerState)) {
4617*c54f35caSApple OSS Distributions // yes, inform clients and apps
4618*c54f35caSApple OSS Distributions tellChangeUp(fHeadNotePowerState);
4619*c54f35caSApple OSS Distributions }
4620*c54f35caSApple OSS Distributions prevPowerState = fCurrentPowerState;
4621*c54f35caSApple OSS Distributions // either way
4622*c54f35caSApple OSS Distributions fCurrentPowerState = fHeadNotePowerState;
4623*c54f35caSApple OSS Distributions PM_LOCK();
4624*c54f35caSApple OSS Distributions if (fReportBuf) {
4625*c54f35caSApple OSS Distributions ts = mach_absolute_time();
4626*c54f35caSApple OSS Distributions STATEREPORT_SETSTATE(fReportBuf, (uint16_t) fCurrentPowerState, ts);
4627*c54f35caSApple OSS Distributions }
4628*c54f35caSApple OSS Distributions PM_UNLOCK();
4629*c54f35caSApple OSS Distributions #if PM_VARS_SUPPORT
4630*c54f35caSApple OSS Distributions fPMVars->myCurrentState = fCurrentPowerState;
4631*c54f35caSApple OSS Distributions #endif
4632*c54f35caSApple OSS Distributions OUR_PMLog(kPMLogChangeDone, fCurrentPowerState, prevPowerState);
4633*c54f35caSApple OSS Distributions PM_ACTION_CHANGE(actionPowerChangeDone,
4634*c54f35caSApple OSS Distributions prevPowerState, fHeadNoteChangeFlags);
4635*c54f35caSApple OSS Distributions actionCalled = true;
4636*c54f35caSApple OSS Distributions
4637*c54f35caSApple OSS Distributions powerStatePtr = &fPowerStates[fCurrentPowerState];
4638*c54f35caSApple OSS Distributions fCurrentCapabilityFlags = powerStatePtr->capabilityFlags;
4639*c54f35caSApple OSS Distributions if (fCurrentCapabilityFlags & kIOPMStaticPowerValid) {
4640*c54f35caSApple OSS Distributions fCurrentPowerConsumption = powerStatePtr->staticPower;
4641*c54f35caSApple OSS Distributions }
4642*c54f35caSApple OSS Distributions
4643*c54f35caSApple OSS Distributions if (fHeadNoteChangeFlags & kIOPMRootChangeDown) {
4644*c54f35caSApple OSS Distributions // Bump tickle generation count once the entire tree is down
4645*c54f35caSApple OSS Distributions gIOPMTickleGeneration++;
4646*c54f35caSApple OSS Distributions }
4647*c54f35caSApple OSS Distributions
4648*c54f35caSApple OSS Distributions // inform subclass policy-maker
4649*c54f35caSApple OSS Distributions if (fPCDFunctionOverride && fParentsKnowState &&
4650*c54f35caSApple OSS Distributions assertPMDriverCall(&callEntry, kIOPMDriverCallMethodChangeDone, NULL, kIOPMDriverCallNoInactiveCheck)) {
4651*c54f35caSApple OSS Distributions powerChangeDone(prevPowerState);
4652*c54f35caSApple OSS Distributions deassertPMDriverCall(&callEntry);
4653*c54f35caSApple OSS Distributions }
4654*c54f35caSApple OSS Distributions } else if (getPMRequestType() == kIOPMRequestTypeRequestPowerStateOverride) {
4655*c54f35caSApple OSS Distributions // changePowerStateWithOverrideTo() was cancelled
4656*c54f35caSApple OSS Distributions fOverrideMaxPowerState = kIOPMPowerStateMax;
4657*c54f35caSApple OSS Distributions }
4658*c54f35caSApple OSS Distributions }
4659*c54f35caSApple OSS Distributions
4660*c54f35caSApple OSS Distributions // parent-initiated power change
4661*c54f35caSApple OSS Distributions if (fHeadNoteChangeFlags & kIOPMParentInitiated) {
4662*c54f35caSApple OSS Distributions if (fHeadNoteChangeFlags & kIOPMRootChangeDown) {
4663*c54f35caSApple OSS Distributions ParentChangeRootChangeDown();
4664*c54f35caSApple OSS Distributions }
4665*c54f35caSApple OSS Distributions
4666*c54f35caSApple OSS Distributions // power state changed
4667*c54f35caSApple OSS Distributions if ((fHeadNoteChangeFlags & kIOPMNotDone) == 0) {
4668*c54f35caSApple OSS Distributions trackSystemSleepPreventers(
4669*c54f35caSApple OSS Distributions fCurrentPowerState, fHeadNotePowerState, fHeadNoteChangeFlags);
4670*c54f35caSApple OSS Distributions
4671*c54f35caSApple OSS Distributions // did power raise?
4672*c54f35caSApple OSS Distributions if (StateOrder(fCurrentPowerState) < StateOrder(fHeadNotePowerState)) {
4673*c54f35caSApple OSS Distributions // yes, inform clients and apps
4674*c54f35caSApple OSS Distributions tellChangeUp(fHeadNotePowerState);
4675*c54f35caSApple OSS Distributions }
4676*c54f35caSApple OSS Distributions // either way
4677*c54f35caSApple OSS Distributions prevPowerState = fCurrentPowerState;
4678*c54f35caSApple OSS Distributions fCurrentPowerState = fHeadNotePowerState;
4679*c54f35caSApple OSS Distributions PM_LOCK();
4680*c54f35caSApple OSS Distributions if (fReportBuf) {
4681*c54f35caSApple OSS Distributions ts = mach_absolute_time();
4682*c54f35caSApple OSS Distributions STATEREPORT_SETSTATE(fReportBuf, (uint16_t) fCurrentPowerState, ts);
4683*c54f35caSApple OSS Distributions }
4684*c54f35caSApple OSS Distributions PM_UNLOCK();
4685*c54f35caSApple OSS Distributions #if PM_VARS_SUPPORT
4686*c54f35caSApple OSS Distributions fPMVars->myCurrentState = fCurrentPowerState;
4687*c54f35caSApple OSS Distributions #endif
4688*c54f35caSApple OSS Distributions
4689*c54f35caSApple OSS Distributions OUR_PMLog(kPMLogChangeDone, fCurrentPowerState, prevPowerState);
4690*c54f35caSApple OSS Distributions PM_ACTION_CHANGE(actionPowerChangeDone,
4691*c54f35caSApple OSS Distributions prevPowerState, fHeadNoteChangeFlags);
4692*c54f35caSApple OSS Distributions actionCalled = true;
4693*c54f35caSApple OSS Distributions
4694*c54f35caSApple OSS Distributions powerStatePtr = &fPowerStates[fCurrentPowerState];
4695*c54f35caSApple OSS Distributions fCurrentCapabilityFlags = powerStatePtr->capabilityFlags;
4696*c54f35caSApple OSS Distributions if (fCurrentCapabilityFlags & kIOPMStaticPowerValid) {
4697*c54f35caSApple OSS Distributions fCurrentPowerConsumption = powerStatePtr->staticPower;
4698*c54f35caSApple OSS Distributions }
4699*c54f35caSApple OSS Distributions
4700*c54f35caSApple OSS Distributions // inform subclass policy-maker
4701*c54f35caSApple OSS Distributions if (fPCDFunctionOverride && fParentsKnowState &&
4702*c54f35caSApple OSS Distributions assertPMDriverCall(&callEntry, kIOPMDriverCallMethodChangeDone, NULL, kIOPMDriverCallNoInactiveCheck)) {
4703*c54f35caSApple OSS Distributions powerChangeDone(prevPowerState);
4704*c54f35caSApple OSS Distributions deassertPMDriverCall(&callEntry);
4705*c54f35caSApple OSS Distributions }
4706*c54f35caSApple OSS Distributions }
4707*c54f35caSApple OSS Distributions }
4708*c54f35caSApple OSS Distributions
4709*c54f35caSApple OSS Distributions // When power rises enough to satisfy the tickle's desire for more power,
4710*c54f35caSApple OSS Distributions // the condition preventing idle-timer from dropping power is removed.
4711*c54f35caSApple OSS Distributions
4712*c54f35caSApple OSS Distributions if (StateOrder(fCurrentPowerState) >= StateOrder(fIdleTimerMinPowerState)) {
4713*c54f35caSApple OSS Distributions fIdleTimerMinPowerState = kPowerStateZero;
4714*c54f35caSApple OSS Distributions }
4715*c54f35caSApple OSS Distributions
4716*c54f35caSApple OSS Distributions if (!actionCalled) {
4717*c54f35caSApple OSS Distributions PM_ACTION_CHANGE(actionPowerChangeDone,
4718*c54f35caSApple OSS Distributions fHeadNotePowerState, fHeadNoteChangeFlags);
4719*c54f35caSApple OSS Distributions }
4720*c54f35caSApple OSS Distributions }
4721*c54f35caSApple OSS Distributions
4722*c54f35caSApple OSS Distributions // MARK: -
4723*c54f35caSApple OSS Distributions // MARK: Power Change Initiated by Driver
4724*c54f35caSApple OSS Distributions
4725*c54f35caSApple OSS Distributions //*********************************************************************************
4726*c54f35caSApple OSS Distributions // [private] OurChangeStart
4727*c54f35caSApple OSS Distributions //
4728*c54f35caSApple OSS Distributions // Begin the processing of a power change initiated by us.
4729*c54f35caSApple OSS Distributions //*********************************************************************************
4730*c54f35caSApple OSS Distributions
4731*c54f35caSApple OSS Distributions void
OurChangeStart(void)4732*c54f35caSApple OSS Distributions IOService::OurChangeStart( void )
4733*c54f35caSApple OSS Distributions {
4734*c54f35caSApple OSS Distributions PM_ASSERT_IN_GATE();
4735*c54f35caSApple OSS Distributions OUR_PMLog( kPMLogStartDeviceChange, fHeadNotePowerState, fCurrentPowerState );
4736*c54f35caSApple OSS Distributions
4737*c54f35caSApple OSS Distributions // fMaxPowerState is our maximum possible power state based on the current
4738*c54f35caSApple OSS Distributions // power state of our parents. If we are trying to raise power beyond the
4739*c54f35caSApple OSS Distributions // maximum, send an async request for more power to all parents.
4740*c54f35caSApple OSS Distributions
4741*c54f35caSApple OSS Distributions if (!IS_PM_ROOT && (StateOrder(fMaxPowerState) < StateOrder(fHeadNotePowerState))) {
4742*c54f35caSApple OSS Distributions fHeadNoteChangeFlags |= kIOPMNotDone;
4743*c54f35caSApple OSS Distributions requestDomainPower(fHeadNotePowerState);
4744*c54f35caSApple OSS Distributions OurChangeFinish();
4745*c54f35caSApple OSS Distributions return;
4746*c54f35caSApple OSS Distributions }
4747*c54f35caSApple OSS Distributions
4748*c54f35caSApple OSS Distributions // Redundant power changes skips to the end of the state machine.
4749*c54f35caSApple OSS Distributions
4750*c54f35caSApple OSS Distributions if (!fInitialPowerChange && (fHeadNotePowerState == fCurrentPowerState)) {
4751*c54f35caSApple OSS Distributions OurChangeFinish();
4752*c54f35caSApple OSS Distributions return;
4753*c54f35caSApple OSS Distributions }
4754*c54f35caSApple OSS Distributions fInitialPowerChange = false;
4755*c54f35caSApple OSS Distributions
4756*c54f35caSApple OSS Distributions // Change started, but may not complete...
4757*c54f35caSApple OSS Distributions // Can be canceled (power drop) or deferred (power rise).
4758*c54f35caSApple OSS Distributions
4759*c54f35caSApple OSS Distributions PM_ACTION_CHANGE(actionPowerChangeStart, fHeadNotePowerState, &fHeadNoteChangeFlags);
4760*c54f35caSApple OSS Distributions
4761*c54f35caSApple OSS Distributions // Two separate paths, depending if power is being raised or lowered.
4762*c54f35caSApple OSS Distributions // Lowering power is subject to approval by clients of this service.
4763*c54f35caSApple OSS Distributions
4764*c54f35caSApple OSS Distributions if (IS_POWER_DROP) {
4765*c54f35caSApple OSS Distributions fDoNotPowerDown = false;
4766*c54f35caSApple OSS Distributions
4767*c54f35caSApple OSS Distributions // Ask for persmission to drop power state
4768*c54f35caSApple OSS Distributions fMachineState = kIOPM_OurChangeTellClientsPowerDown;
4769*c54f35caSApple OSS Distributions fOutOfBandParameter = kNotifyApps;
4770*c54f35caSApple OSS Distributions askChangeDown(fHeadNotePowerState);
4771*c54f35caSApple OSS Distributions } else {
4772*c54f35caSApple OSS Distributions // This service is raising power and parents are able to support the
4773*c54f35caSApple OSS Distributions // new power state. However a parent may have already committed to
4774*c54f35caSApple OSS Distributions // drop power, which might force this object to temporarily drop power.
4775*c54f35caSApple OSS Distributions // This results in "oscillations" before the state machines converge
4776*c54f35caSApple OSS Distributions // to a steady state.
4777*c54f35caSApple OSS Distributions //
4778*c54f35caSApple OSS Distributions // To prevent this, a child must make a power reservation against all
4779*c54f35caSApple OSS Distributions // parents before raising power. If the reservation fails, indicating
4780*c54f35caSApple OSS Distributions // that the child will be unable to sustain the higher power state,
4781*c54f35caSApple OSS Distributions // then the child will signal the parent to adjust power, and the child
4782*c54f35caSApple OSS Distributions // will defer its power change.
4783*c54f35caSApple OSS Distributions
4784*c54f35caSApple OSS Distributions IOReturn ret;
4785*c54f35caSApple OSS Distributions
4786*c54f35caSApple OSS Distributions // Reserve parent power necessary to achieve fHeadNotePowerState.
4787*c54f35caSApple OSS Distributions ret = requestDomainPower( fHeadNotePowerState, kReserveDomainPower );
4788*c54f35caSApple OSS Distributions if (ret != kIOReturnSuccess) {
4789*c54f35caSApple OSS Distributions // Reservation failed, defer power rise.
4790*c54f35caSApple OSS Distributions fHeadNoteChangeFlags |= kIOPMNotDone;
4791*c54f35caSApple OSS Distributions OurChangeFinish();
4792*c54f35caSApple OSS Distributions return;
4793*c54f35caSApple OSS Distributions }
4794*c54f35caSApple OSS Distributions
4795*c54f35caSApple OSS Distributions OurChangeTellCapabilityWillChange();
4796*c54f35caSApple OSS Distributions }
4797*c54f35caSApple OSS Distributions }
4798*c54f35caSApple OSS Distributions
4799*c54f35caSApple OSS Distributions //*********************************************************************************
4800*c54f35caSApple OSS Distributions // [private] requestDomainPowerApplier
4801*c54f35caSApple OSS Distributions //
4802*c54f35caSApple OSS Distributions // Call requestPowerDomainState() on all power parents.
4803*c54f35caSApple OSS Distributions //*********************************************************************************
4804*c54f35caSApple OSS Distributions
4805*c54f35caSApple OSS Distributions struct IOPMRequestDomainPowerContext {
4806*c54f35caSApple OSS Distributions IOService * child; // the requesting child
4807*c54f35caSApple OSS Distributions IOPMPowerFlags requestPowerFlags;// power flags requested by child
4808*c54f35caSApple OSS Distributions };
4809*c54f35caSApple OSS Distributions
4810*c54f35caSApple OSS Distributions static void
requestDomainPowerApplier(IORegistryEntry * entry,void * inContext)4811*c54f35caSApple OSS Distributions requestDomainPowerApplier(
4812*c54f35caSApple OSS Distributions IORegistryEntry * entry,
4813*c54f35caSApple OSS Distributions void * inContext )
4814*c54f35caSApple OSS Distributions {
4815*c54f35caSApple OSS Distributions IOPowerConnection * connection;
4816*c54f35caSApple OSS Distributions IOService * parent;
4817*c54f35caSApple OSS Distributions IOPMRequestDomainPowerContext * context;
4818*c54f35caSApple OSS Distributions
4819*c54f35caSApple OSS Distributions if ((connection = OSDynamicCast(IOPowerConnection, entry)) == NULL) {
4820*c54f35caSApple OSS Distributions return;
4821*c54f35caSApple OSS Distributions }
4822*c54f35caSApple OSS Distributions parent = (IOService *) connection->copyParentEntry(gIOPowerPlane);
4823*c54f35caSApple OSS Distributions if (!parent) {
4824*c54f35caSApple OSS Distributions return;
4825*c54f35caSApple OSS Distributions }
4826*c54f35caSApple OSS Distributions
4827*c54f35caSApple OSS Distributions assert(inContext);
4828*c54f35caSApple OSS Distributions context = (IOPMRequestDomainPowerContext *) inContext;
4829*c54f35caSApple OSS Distributions
4830*c54f35caSApple OSS Distributions if (connection->parentKnowsState() && connection->getReadyFlag()) {
4831*c54f35caSApple OSS Distributions parent->requestPowerDomainState(
4832*c54f35caSApple OSS Distributions context->requestPowerFlags,
4833*c54f35caSApple OSS Distributions connection,
4834*c54f35caSApple OSS Distributions IOPMLowestState);
4835*c54f35caSApple OSS Distributions }
4836*c54f35caSApple OSS Distributions
4837*c54f35caSApple OSS Distributions parent->release();
4838*c54f35caSApple OSS Distributions }
4839*c54f35caSApple OSS Distributions
4840*c54f35caSApple OSS Distributions //*********************************************************************************
4841*c54f35caSApple OSS Distributions // [private] requestDomainPower
4842*c54f35caSApple OSS Distributions //
4843*c54f35caSApple OSS Distributions // Called by a power child to broadcast its desired power state to all parents.
4844*c54f35caSApple OSS Distributions // If the child self-initiates a power change, it must call this function to
4845*c54f35caSApple OSS Distributions // allow its parents to adjust power state.
4846*c54f35caSApple OSS Distributions //*********************************************************************************
4847*c54f35caSApple OSS Distributions
4848*c54f35caSApple OSS Distributions IOReturn
requestDomainPower(IOPMPowerStateIndex ourPowerState,IOOptionBits options)4849*c54f35caSApple OSS Distributions IOService::requestDomainPower(
4850*c54f35caSApple OSS Distributions IOPMPowerStateIndex ourPowerState,
4851*c54f35caSApple OSS Distributions IOOptionBits options )
4852*c54f35caSApple OSS Distributions {
4853*c54f35caSApple OSS Distributions IOPMPowerFlags requestPowerFlags;
4854*c54f35caSApple OSS Distributions IOPMPowerStateIndex maxPowerState;
4855*c54f35caSApple OSS Distributions IOPMRequestDomainPowerContext context;
4856*c54f35caSApple OSS Distributions
4857*c54f35caSApple OSS Distributions PM_ASSERT_IN_GATE();
4858*c54f35caSApple OSS Distributions assert(ourPowerState < fNumberOfPowerStates);
4859*c54f35caSApple OSS Distributions if (ourPowerState >= fNumberOfPowerStates) {
4860*c54f35caSApple OSS Distributions return kIOReturnBadArgument;
4861*c54f35caSApple OSS Distributions }
4862*c54f35caSApple OSS Distributions if (IS_PM_ROOT) {
4863*c54f35caSApple OSS Distributions return kIOReturnSuccess;
4864*c54f35caSApple OSS Distributions }
4865*c54f35caSApple OSS Distributions
4866*c54f35caSApple OSS Distributions // Fetch our input power flags for the requested power state.
4867*c54f35caSApple OSS Distributions // Parent request is stated in terms of required power flags.
4868*c54f35caSApple OSS Distributions
4869*c54f35caSApple OSS Distributions requestPowerFlags = fPowerStates[ourPowerState].inputPowerFlags;
4870*c54f35caSApple OSS Distributions
4871*c54f35caSApple OSS Distributions // Disregard the "previous request" for power reservation.
4872*c54f35caSApple OSS Distributions
4873*c54f35caSApple OSS Distributions if (((options & kReserveDomainPower) == 0) &&
4874*c54f35caSApple OSS Distributions (fPreviousRequestPowerFlags == requestPowerFlags)) {
4875*c54f35caSApple OSS Distributions // skip if domain already knows our requirements
4876*c54f35caSApple OSS Distributions goto done;
4877*c54f35caSApple OSS Distributions }
4878*c54f35caSApple OSS Distributions fPreviousRequestPowerFlags = requestPowerFlags;
4879*c54f35caSApple OSS Distributions
4880*c54f35caSApple OSS Distributions // The results will be collected by fHeadNoteDomainTargetFlags
4881*c54f35caSApple OSS Distributions context.child = this;
4882*c54f35caSApple OSS Distributions context.requestPowerFlags = requestPowerFlags;
4883*c54f35caSApple OSS Distributions fHeadNoteDomainTargetFlags = 0;
4884*c54f35caSApple OSS Distributions applyToParents(requestDomainPowerApplier, &context, gIOPowerPlane);
4885*c54f35caSApple OSS Distributions
4886*c54f35caSApple OSS Distributions if (options & kReserveDomainPower) {
4887*c54f35caSApple OSS Distributions maxPowerState = fControllingDriver->maxCapabilityForDomainState(
4888*c54f35caSApple OSS Distributions fHeadNoteDomainTargetFlags );
4889*c54f35caSApple OSS Distributions
4890*c54f35caSApple OSS Distributions if (StateOrder(maxPowerState) < StateOrder(ourPowerState)) {
4891*c54f35caSApple OSS Distributions PM_LOG1("%s: power desired %u:0x%x got %u:0x%x\n",
4892*c54f35caSApple OSS Distributions getName(),
4893*c54f35caSApple OSS Distributions (uint32_t) ourPowerState, (uint32_t) requestPowerFlags,
4894*c54f35caSApple OSS Distributions (uint32_t) maxPowerState, (uint32_t) fHeadNoteDomainTargetFlags);
4895*c54f35caSApple OSS Distributions return kIOReturnNoPower;
4896*c54f35caSApple OSS Distributions }
4897*c54f35caSApple OSS Distributions }
4898*c54f35caSApple OSS Distributions
4899*c54f35caSApple OSS Distributions done:
4900*c54f35caSApple OSS Distributions return kIOReturnSuccess;
4901*c54f35caSApple OSS Distributions }
4902*c54f35caSApple OSS Distributions
4903*c54f35caSApple OSS Distributions //*********************************************************************************
4904*c54f35caSApple OSS Distributions // [private] OurSyncStart
4905*c54f35caSApple OSS Distributions //*********************************************************************************
4906*c54f35caSApple OSS Distributions
4907*c54f35caSApple OSS Distributions void
OurSyncStart(void)4908*c54f35caSApple OSS Distributions IOService::OurSyncStart( void )
4909*c54f35caSApple OSS Distributions {
4910*c54f35caSApple OSS Distributions PM_ASSERT_IN_GATE();
4911*c54f35caSApple OSS Distributions
4912*c54f35caSApple OSS Distributions if (fInitialPowerChange) {
4913*c54f35caSApple OSS Distributions return;
4914*c54f35caSApple OSS Distributions }
4915*c54f35caSApple OSS Distributions
4916*c54f35caSApple OSS Distributions PM_ACTION_CHANGE(actionPowerChangeStart, fHeadNotePowerState, &fHeadNoteChangeFlags);
4917*c54f35caSApple OSS Distributions
4918*c54f35caSApple OSS Distributions if (fHeadNoteChangeFlags & kIOPMNotDone) {
4919*c54f35caSApple OSS Distributions OurChangeFinish();
4920*c54f35caSApple OSS Distributions return;
4921*c54f35caSApple OSS Distributions }
4922*c54f35caSApple OSS Distributions
4923*c54f35caSApple OSS Distributions if (fHeadNoteChangeFlags & kIOPMSyncTellPowerDown) {
4924*c54f35caSApple OSS Distributions fDoNotPowerDown = false;
4925*c54f35caSApple OSS Distributions
4926*c54f35caSApple OSS Distributions // Ask for permission to drop power state
4927*c54f35caSApple OSS Distributions fMachineState = kIOPM_SyncTellClientsPowerDown;
4928*c54f35caSApple OSS Distributions fOutOfBandParameter = kNotifyApps;
4929*c54f35caSApple OSS Distributions askChangeDown(fHeadNotePowerState);
4930*c54f35caSApple OSS Distributions } else {
4931*c54f35caSApple OSS Distributions // Only inform capability app and clients.
4932*c54f35caSApple OSS Distributions tellSystemCapabilityChange( kIOPM_SyncNotifyWillChange );
4933*c54f35caSApple OSS Distributions }
4934*c54f35caSApple OSS Distributions }
4935*c54f35caSApple OSS Distributions
4936*c54f35caSApple OSS Distributions //*********************************************************************************
4937*c54f35caSApple OSS Distributions // [private] OurChangeTellClientsPowerDown
4938*c54f35caSApple OSS Distributions //
4939*c54f35caSApple OSS Distributions // All applications and kernel clients have acknowledged our permission to drop
4940*c54f35caSApple OSS Distributions // power. Here we notify them that we will lower the power and wait for acks.
4941*c54f35caSApple OSS Distributions //*********************************************************************************
4942*c54f35caSApple OSS Distributions
4943*c54f35caSApple OSS Distributions void
OurChangeTellClientsPowerDown(void)4944*c54f35caSApple OSS Distributions IOService::OurChangeTellClientsPowerDown( void )
4945*c54f35caSApple OSS Distributions {
4946*c54f35caSApple OSS Distributions if (!IS_ROOT_DOMAIN) {
4947*c54f35caSApple OSS Distributions fMachineState = kIOPM_OurChangeTellPriorityClientsPowerDown;
4948*c54f35caSApple OSS Distributions } else {
4949*c54f35caSApple OSS Distributions fMachineState = kIOPM_OurChangeTellUserPMPolicyPowerDown;
4950*c54f35caSApple OSS Distributions }
4951*c54f35caSApple OSS Distributions tellChangeDown1(fHeadNotePowerState);
4952*c54f35caSApple OSS Distributions }
4953*c54f35caSApple OSS Distributions
4954*c54f35caSApple OSS Distributions //*********************************************************************************
4955*c54f35caSApple OSS Distributions // [private] OurChangeTellUserPMPolicyPowerDown
4956*c54f35caSApple OSS Distributions //
4957*c54f35caSApple OSS Distributions // All applications and kernel clients have acknowledged our permission to drop
4958*c54f35caSApple OSS Distributions // power. Here we notify power management policy in user-space and wait for acks
4959*c54f35caSApple OSS Distributions // one last time before we lower power
4960*c54f35caSApple OSS Distributions //*********************************************************************************
4961*c54f35caSApple OSS Distributions void
OurChangeTellUserPMPolicyPowerDown(void)4962*c54f35caSApple OSS Distributions IOService::OurChangeTellUserPMPolicyPowerDown( void )
4963*c54f35caSApple OSS Distributions {
4964*c54f35caSApple OSS Distributions fMachineState = kIOPM_OurChangeTellPriorityClientsPowerDown;
4965*c54f35caSApple OSS Distributions fOutOfBandParameter = kNotifyApps;
4966*c54f35caSApple OSS Distributions
4967*c54f35caSApple OSS Distributions tellClientsWithResponse(kIOPMMessageLastCallBeforeSleep);
4968*c54f35caSApple OSS Distributions }
4969*c54f35caSApple OSS Distributions
4970*c54f35caSApple OSS Distributions //*********************************************************************************
4971*c54f35caSApple OSS Distributions // [private] OurChangeTellPriorityClientsPowerDown
4972*c54f35caSApple OSS Distributions //
4973*c54f35caSApple OSS Distributions // All applications and kernel clients have acknowledged our intention to drop
4974*c54f35caSApple OSS Distributions // power. Here we notify "priority" clients that we are lowering power.
4975*c54f35caSApple OSS Distributions //*********************************************************************************
4976*c54f35caSApple OSS Distributions
4977*c54f35caSApple OSS Distributions void
OurChangeTellPriorityClientsPowerDown(void)4978*c54f35caSApple OSS Distributions IOService::OurChangeTellPriorityClientsPowerDown( void )
4979*c54f35caSApple OSS Distributions {
4980*c54f35caSApple OSS Distributions fMachineState = kIOPM_OurChangeNotifyInterestedDriversWillChange;
4981*c54f35caSApple OSS Distributions tellChangeDown2(fHeadNotePowerState);
4982*c54f35caSApple OSS Distributions }
4983*c54f35caSApple OSS Distributions
4984*c54f35caSApple OSS Distributions //*********************************************************************************
4985*c54f35caSApple OSS Distributions // [private] OurChangeTellCapabilityWillChange
4986*c54f35caSApple OSS Distributions //
4987*c54f35caSApple OSS Distributions // Extra stage for root domain to notify apps and drivers about the
4988*c54f35caSApple OSS Distributions // system capability change when raising power state.
4989*c54f35caSApple OSS Distributions //*********************************************************************************
4990*c54f35caSApple OSS Distributions
4991*c54f35caSApple OSS Distributions void
OurChangeTellCapabilityWillChange(void)4992*c54f35caSApple OSS Distributions IOService::OurChangeTellCapabilityWillChange( void )
4993*c54f35caSApple OSS Distributions {
4994*c54f35caSApple OSS Distributions if (!IS_ROOT_DOMAIN) {
4995*c54f35caSApple OSS Distributions return OurChangeNotifyInterestedDriversWillChange();
4996*c54f35caSApple OSS Distributions }
4997*c54f35caSApple OSS Distributions
4998*c54f35caSApple OSS Distributions tellSystemCapabilityChange( kIOPM_OurChangeNotifyInterestedDriversWillChange );
4999*c54f35caSApple OSS Distributions }
5000*c54f35caSApple OSS Distributions
5001*c54f35caSApple OSS Distributions //*********************************************************************************
5002*c54f35caSApple OSS Distributions // [private] OurChangeNotifyInterestedDriversWillChange
5003*c54f35caSApple OSS Distributions //
5004*c54f35caSApple OSS Distributions // All applications and kernel clients have acknowledged our power state change.
5005*c54f35caSApple OSS Distributions // Here we notify interested drivers pre-change.
5006*c54f35caSApple OSS Distributions //*********************************************************************************
5007*c54f35caSApple OSS Distributions
5008*c54f35caSApple OSS Distributions void
OurChangeNotifyInterestedDriversWillChange(void)5009*c54f35caSApple OSS Distributions IOService::OurChangeNotifyInterestedDriversWillChange( void )
5010*c54f35caSApple OSS Distributions {
5011*c54f35caSApple OSS Distributions IOPMrootDomain * rootDomain;
5012*c54f35caSApple OSS Distributions if ((rootDomain = getPMRootDomain()) == this) {
5013*c54f35caSApple OSS Distributions if (IS_POWER_DROP) {
5014*c54f35caSApple OSS Distributions rootDomain->tracePoint( kIOPMTracePointSleepWillChangeInterests );
5015*c54f35caSApple OSS Distributions } else {
5016*c54f35caSApple OSS Distributions rootDomain->tracePoint( kIOPMTracePointWakeWillChangeInterests );
5017*c54f35caSApple OSS Distributions }
5018*c54f35caSApple OSS Distributions }
5019*c54f35caSApple OSS Distributions
5020*c54f35caSApple OSS Distributions notifyAll( kIOPM_OurChangeSetPowerState );
5021*c54f35caSApple OSS Distributions }
5022*c54f35caSApple OSS Distributions
5023*c54f35caSApple OSS Distributions //*********************************************************************************
5024*c54f35caSApple OSS Distributions // [private] OurChangeSetPowerState
5025*c54f35caSApple OSS Distributions //
5026*c54f35caSApple OSS Distributions // Instruct our controlling driver to program the hardware for the power state
5027*c54f35caSApple OSS Distributions // change. Wait for async completions.
5028*c54f35caSApple OSS Distributions //*********************************************************************************
5029*c54f35caSApple OSS Distributions
5030*c54f35caSApple OSS Distributions void
OurChangeSetPowerState(void)5031*c54f35caSApple OSS Distributions IOService::OurChangeSetPowerState( void )
5032*c54f35caSApple OSS Distributions {
5033*c54f35caSApple OSS Distributions MS_PUSH( kIOPM_OurChangeWaitForPowerSettle );
5034*c54f35caSApple OSS Distributions fMachineState = kIOPM_DriverThreadCallDone;
5035*c54f35caSApple OSS Distributions fDriverCallReason = kDriverCallSetPowerState;
5036*c54f35caSApple OSS Distributions
5037*c54f35caSApple OSS Distributions if (notifyControllingDriver() == false) {
5038*c54f35caSApple OSS Distributions notifyControllingDriverDone();
5039*c54f35caSApple OSS Distributions }
5040*c54f35caSApple OSS Distributions }
5041*c54f35caSApple OSS Distributions
5042*c54f35caSApple OSS Distributions //*********************************************************************************
5043*c54f35caSApple OSS Distributions // [private] OurChangeWaitForPowerSettle
5044*c54f35caSApple OSS Distributions //
5045*c54f35caSApple OSS Distributions // Our controlling driver has completed the power state change we initiated.
5046*c54f35caSApple OSS Distributions // Wait for the driver specified settle time to expire.
5047*c54f35caSApple OSS Distributions //*********************************************************************************
5048*c54f35caSApple OSS Distributions
5049*c54f35caSApple OSS Distributions void
OurChangeWaitForPowerSettle(void)5050*c54f35caSApple OSS Distributions IOService::OurChangeWaitForPowerSettle( void )
5051*c54f35caSApple OSS Distributions {
5052*c54f35caSApple OSS Distributions fMachineState = kIOPM_OurChangeNotifyInterestedDriversDidChange;
5053*c54f35caSApple OSS Distributions startSettleTimer();
5054*c54f35caSApple OSS Distributions }
5055*c54f35caSApple OSS Distributions
5056*c54f35caSApple OSS Distributions //*********************************************************************************
5057*c54f35caSApple OSS Distributions // [private] OurChangeNotifyInterestedDriversDidChange
5058*c54f35caSApple OSS Distributions //
5059*c54f35caSApple OSS Distributions // Power has settled on a power change we initiated. Here we notify
5060*c54f35caSApple OSS Distributions // all our interested drivers post-change.
5061*c54f35caSApple OSS Distributions //*********************************************************************************
5062*c54f35caSApple OSS Distributions
5063*c54f35caSApple OSS Distributions void
OurChangeNotifyInterestedDriversDidChange(void)5064*c54f35caSApple OSS Distributions IOService::OurChangeNotifyInterestedDriversDidChange( void )
5065*c54f35caSApple OSS Distributions {
5066*c54f35caSApple OSS Distributions IOPMrootDomain * rootDomain;
5067*c54f35caSApple OSS Distributions if ((rootDomain = getPMRootDomain()) == this) {
5068*c54f35caSApple OSS Distributions rootDomain->tracePoint( IS_POWER_DROP ?
5069*c54f35caSApple OSS Distributions kIOPMTracePointSleepDidChangeInterests :
5070*c54f35caSApple OSS Distributions kIOPMTracePointWakeDidChangeInterests );
5071*c54f35caSApple OSS Distributions }
5072*c54f35caSApple OSS Distributions
5073*c54f35caSApple OSS Distributions notifyAll( kIOPM_OurChangeTellCapabilityDidChange );
5074*c54f35caSApple OSS Distributions }
5075*c54f35caSApple OSS Distributions
5076*c54f35caSApple OSS Distributions //*********************************************************************************
5077*c54f35caSApple OSS Distributions // [private] OurChangeTellCapabilityDidChange
5078*c54f35caSApple OSS Distributions //
5079*c54f35caSApple OSS Distributions // For root domain to notify capability power-change.
5080*c54f35caSApple OSS Distributions //*********************************************************************************
5081*c54f35caSApple OSS Distributions
5082*c54f35caSApple OSS Distributions void
OurChangeTellCapabilityDidChange(void)5083*c54f35caSApple OSS Distributions IOService::OurChangeTellCapabilityDidChange( void )
5084*c54f35caSApple OSS Distributions {
5085*c54f35caSApple OSS Distributions if (!IS_ROOT_DOMAIN) {
5086*c54f35caSApple OSS Distributions return OurChangeFinish();
5087*c54f35caSApple OSS Distributions }
5088*c54f35caSApple OSS Distributions
5089*c54f35caSApple OSS Distributions if (!IS_POWER_DROP) {
5090*c54f35caSApple OSS Distributions // Notify root domain immediately after notifying interested
5091*c54f35caSApple OSS Distributions // drivers and power children.
5092*c54f35caSApple OSS Distributions getPMRootDomain()->willTellSystemCapabilityDidChange();
5093*c54f35caSApple OSS Distributions }
5094*c54f35caSApple OSS Distributions
5095*c54f35caSApple OSS Distributions getPMRootDomain()->tracePoint( IS_POWER_DROP ?
5096*c54f35caSApple OSS Distributions kIOPMTracePointSleepCapabilityClients :
5097*c54f35caSApple OSS Distributions kIOPMTracePointWakeCapabilityClients );
5098*c54f35caSApple OSS Distributions
5099*c54f35caSApple OSS Distributions tellSystemCapabilityChange( kIOPM_OurChangeFinish );
5100*c54f35caSApple OSS Distributions }
5101*c54f35caSApple OSS Distributions
5102*c54f35caSApple OSS Distributions //*********************************************************************************
5103*c54f35caSApple OSS Distributions // [private] OurChangeFinish
5104*c54f35caSApple OSS Distributions //
5105*c54f35caSApple OSS Distributions // Done with this self-induced power state change.
5106*c54f35caSApple OSS Distributions //*********************************************************************************
5107*c54f35caSApple OSS Distributions
5108*c54f35caSApple OSS Distributions void
OurChangeFinish(void)5109*c54f35caSApple OSS Distributions IOService::OurChangeFinish( void )
5110*c54f35caSApple OSS Distributions {
5111*c54f35caSApple OSS Distributions all_done();
5112*c54f35caSApple OSS Distributions }
5113*c54f35caSApple OSS Distributions
5114*c54f35caSApple OSS Distributions // MARK: -
5115*c54f35caSApple OSS Distributions // MARK: Power Change Initiated by Parent
5116*c54f35caSApple OSS Distributions
5117*c54f35caSApple OSS Distributions //*********************************************************************************
5118*c54f35caSApple OSS Distributions // [private] ParentChangeStart
5119*c54f35caSApple OSS Distributions //
5120*c54f35caSApple OSS Distributions // Here we begin the processing of a power change initiated by our parent.
5121*c54f35caSApple OSS Distributions //*********************************************************************************
5122*c54f35caSApple OSS Distributions
5123*c54f35caSApple OSS Distributions IOReturn
ParentChangeStart(void)5124*c54f35caSApple OSS Distributions IOService::ParentChangeStart( void )
5125*c54f35caSApple OSS Distributions {
5126*c54f35caSApple OSS Distributions PM_ASSERT_IN_GATE();
5127*c54f35caSApple OSS Distributions OUR_PMLog( kPMLogStartParentChange, fHeadNotePowerState, fCurrentPowerState );
5128*c54f35caSApple OSS Distributions
5129*c54f35caSApple OSS Distributions // Root power domain has transitioned to its max power state
5130*c54f35caSApple OSS Distributions if ((fHeadNoteChangeFlags & (kIOPMDomainDidChange | kIOPMRootChangeUp)) ==
5131*c54f35caSApple OSS Distributions (kIOPMDomainDidChange | kIOPMRootChangeUp)) {
5132*c54f35caSApple OSS Distributions // Restart the idle timer stopped by ParentChangeRootChangeDown()
5133*c54f35caSApple OSS Distributions if (fIdleTimerPeriod && fIdleTimerStopped) {
5134*c54f35caSApple OSS Distributions restartIdleTimer();
5135*c54f35caSApple OSS Distributions }
5136*c54f35caSApple OSS Distributions }
5137*c54f35caSApple OSS Distributions
5138*c54f35caSApple OSS Distributions // Power domain is forcing us to lower power
5139*c54f35caSApple OSS Distributions if (StateOrder(fHeadNotePowerState) < StateOrder(fCurrentPowerState)) {
5140*c54f35caSApple OSS Distributions PM_ACTION_CHANGE(actionPowerChangeStart, fHeadNotePowerState, &fHeadNoteChangeFlags);
5141*c54f35caSApple OSS Distributions
5142*c54f35caSApple OSS Distributions // Tell apps and kernel clients
5143*c54f35caSApple OSS Distributions fInitialPowerChange = false;
5144*c54f35caSApple OSS Distributions fMachineState = kIOPM_ParentChangeTellPriorityClientsPowerDown;
5145*c54f35caSApple OSS Distributions tellChangeDown1(fHeadNotePowerState);
5146*c54f35caSApple OSS Distributions return IOPMWillAckLater;
5147*c54f35caSApple OSS Distributions }
5148*c54f35caSApple OSS Distributions
5149*c54f35caSApple OSS Distributions // Power domain is allowing us to raise power up to fHeadNotePowerState
5150*c54f35caSApple OSS Distributions if (StateOrder(fHeadNotePowerState) > StateOrder(fCurrentPowerState)) {
5151*c54f35caSApple OSS Distributions if (StateOrder(fDesiredPowerState) > StateOrder(fCurrentPowerState)) {
5152*c54f35caSApple OSS Distributions if (StateOrder(fDesiredPowerState) < StateOrder(fHeadNotePowerState)) {
5153*c54f35caSApple OSS Distributions // We power up, but not all the way
5154*c54f35caSApple OSS Distributions fHeadNotePowerState = fDesiredPowerState;
5155*c54f35caSApple OSS Distributions fHeadNotePowerArrayEntry = &fPowerStates[fDesiredPowerState];
5156*c54f35caSApple OSS Distributions OUR_PMLog(kPMLogAmendParentChange, fHeadNotePowerState, 0);
5157*c54f35caSApple OSS Distributions }
5158*c54f35caSApple OSS Distributions } else {
5159*c54f35caSApple OSS Distributions // We don't need to change
5160*c54f35caSApple OSS Distributions fHeadNotePowerState = fCurrentPowerState;
5161*c54f35caSApple OSS Distributions fHeadNotePowerArrayEntry = &fPowerStates[fCurrentPowerState];
5162*c54f35caSApple OSS Distributions OUR_PMLog(kPMLogAmendParentChange, fHeadNotePowerState, 0);
5163*c54f35caSApple OSS Distributions }
5164*c54f35caSApple OSS Distributions }
5165*c54f35caSApple OSS Distributions
5166*c54f35caSApple OSS Distributions if (fHeadNoteChangeFlags & kIOPMDomainDidChange) {
5167*c54f35caSApple OSS Distributions if (StateOrder(fHeadNotePowerState) > StateOrder(fCurrentPowerState)) {
5168*c54f35caSApple OSS Distributions PM_ACTION_CHANGE(actionPowerChangeStart,
5169*c54f35caSApple OSS Distributions fHeadNotePowerState, &fHeadNoteChangeFlags);
5170*c54f35caSApple OSS Distributions
5171*c54f35caSApple OSS Distributions // Parent did change up - start our change up
5172*c54f35caSApple OSS Distributions fInitialPowerChange = false;
5173*c54f35caSApple OSS Distributions ParentChangeTellCapabilityWillChange();
5174*c54f35caSApple OSS Distributions return IOPMWillAckLater;
5175*c54f35caSApple OSS Distributions } else if (fHeadNoteChangeFlags & kIOPMRootBroadcastFlags) {
5176*c54f35caSApple OSS Distributions // No need to change power state, but broadcast change
5177*c54f35caSApple OSS Distributions // to our children.
5178*c54f35caSApple OSS Distributions fMachineState = kIOPM_SyncNotifyDidChange;
5179*c54f35caSApple OSS Distributions fDriverCallReason = kDriverCallInformPreChange;
5180*c54f35caSApple OSS Distributions fHeadNoteChangeFlags |= kIOPMNotDone;
5181*c54f35caSApple OSS Distributions notifyChildren();
5182*c54f35caSApple OSS Distributions return IOPMWillAckLater;
5183*c54f35caSApple OSS Distributions }
5184*c54f35caSApple OSS Distributions }
5185*c54f35caSApple OSS Distributions
5186*c54f35caSApple OSS Distributions // No power state change necessary
5187*c54f35caSApple OSS Distributions fHeadNoteChangeFlags |= kIOPMNotDone;
5188*c54f35caSApple OSS Distributions
5189*c54f35caSApple OSS Distributions all_done();
5190*c54f35caSApple OSS Distributions return IOPMAckImplied;
5191*c54f35caSApple OSS Distributions }
5192*c54f35caSApple OSS Distributions
5193*c54f35caSApple OSS Distributions //******************************************************************************
5194*c54f35caSApple OSS Distributions // [private] ParentChangeRootChangeDown
5195*c54f35caSApple OSS Distributions //
5196*c54f35caSApple OSS Distributions // Root domain has finished the transition to the system sleep state. And all
5197*c54f35caSApple OSS Distributions // drivers in the power plane should have powered down. Cancel the idle timer,
5198*c54f35caSApple OSS Distributions // and also reset the device desire for those drivers that don't want power
5199*c54f35caSApple OSS Distributions // automatically restored on wake.
5200*c54f35caSApple OSS Distributions //******************************************************************************
5201*c54f35caSApple OSS Distributions
5202*c54f35caSApple OSS Distributions void
ParentChangeRootChangeDown(void)5203*c54f35caSApple OSS Distributions IOService::ParentChangeRootChangeDown( void )
5204*c54f35caSApple OSS Distributions {
5205*c54f35caSApple OSS Distributions // Always stop the idle timer before root power down
5206*c54f35caSApple OSS Distributions if (fIdleTimerPeriod && !fIdleTimerStopped) {
5207*c54f35caSApple OSS Distributions fIdleTimerStopped = true;
5208*c54f35caSApple OSS Distributions if (fIdleTimer && thread_call_cancel(fIdleTimer)) {
5209*c54f35caSApple OSS Distributions release();
5210*c54f35caSApple OSS Distributions }
5211*c54f35caSApple OSS Distributions }
5212*c54f35caSApple OSS Distributions
5213*c54f35caSApple OSS Distributions if (fResetPowerStateOnWake) {
5214*c54f35caSApple OSS Distributions // Reset device desire down to the lowest power state.
5215*c54f35caSApple OSS Distributions // Advisory tickle desire is intentionally untouched since
5216*c54f35caSApple OSS Distributions // it has no effect until system is promoted to full wake.
5217*c54f35caSApple OSS Distributions
5218*c54f35caSApple OSS Distributions if (fDeviceDesire != kPowerStateZero) {
5219*c54f35caSApple OSS Distributions updatePowerClient(gIOPMPowerClientDevice, kPowerStateZero);
5220*c54f35caSApple OSS Distributions computeDesiredState(kPowerStateZero, true);
5221*c54f35caSApple OSS Distributions requestDomainPower( fDesiredPowerState );
5222*c54f35caSApple OSS Distributions PM_LOG1("%s: tickle desire removed\n", fName);
5223*c54f35caSApple OSS Distributions }
5224*c54f35caSApple OSS Distributions
5225*c54f35caSApple OSS Distributions // Invalidate tickle cache so the next tickle will issue a request
5226*c54f35caSApple OSS Distributions IOLockLock(fActivityLock);
5227*c54f35caSApple OSS Distributions fDeviceWasActive = false;
5228*c54f35caSApple OSS Distributions fActivityTicklePowerState = kInvalidTicklePowerState;
5229*c54f35caSApple OSS Distributions IOLockUnlock(fActivityLock);
5230*c54f35caSApple OSS Distributions
5231*c54f35caSApple OSS Distributions fIdleTimerMinPowerState = kPowerStateZero;
5232*c54f35caSApple OSS Distributions } else if (fAdvisoryTickleUsed) {
5233*c54f35caSApple OSS Distributions // Less aggressive mechanism to accelerate idle timer expiration
5234*c54f35caSApple OSS Distributions // before system sleep. May not always allow the driver to wake
5235*c54f35caSApple OSS Distributions // up from system sleep in the min power state.
5236*c54f35caSApple OSS Distributions
5237*c54f35caSApple OSS Distributions AbsoluteTime now;
5238*c54f35caSApple OSS Distributions uint64_t nsec;
5239*c54f35caSApple OSS Distributions bool dropTickleDesire = false;
5240*c54f35caSApple OSS Distributions
5241*c54f35caSApple OSS Distributions if (fIdleTimerPeriod && !fIdleTimerIgnored &&
5242*c54f35caSApple OSS Distributions (fIdleTimerMinPowerState == kPowerStateZero) &&
5243*c54f35caSApple OSS Distributions (fDeviceDesire != kPowerStateZero)) {
5244*c54f35caSApple OSS Distributions IOLockLock(fActivityLock);
5245*c54f35caSApple OSS Distributions
5246*c54f35caSApple OSS Distributions if (!fDeviceWasActive) {
5247*c54f35caSApple OSS Distributions // No tickles since the last idle timer expiration.
5248*c54f35caSApple OSS Distributions // Safe to drop the device desire to zero.
5249*c54f35caSApple OSS Distributions dropTickleDesire = true;
5250*c54f35caSApple OSS Distributions } else {
5251*c54f35caSApple OSS Distributions // Was tickled since the last idle timer expiration,
5252*c54f35caSApple OSS Distributions // but not in the last minute.
5253*c54f35caSApple OSS Distributions clock_get_uptime(&now);
5254*c54f35caSApple OSS Distributions SUB_ABSOLUTETIME(&now, &fDeviceActiveTimestamp);
5255*c54f35caSApple OSS Distributions absolutetime_to_nanoseconds(now, &nsec);
5256*c54f35caSApple OSS Distributions if (nsec >= kNoTickleCancelWindow) {
5257*c54f35caSApple OSS Distributions dropTickleDesire = true;
5258*c54f35caSApple OSS Distributions }
5259*c54f35caSApple OSS Distributions }
5260*c54f35caSApple OSS Distributions
5261*c54f35caSApple OSS Distributions if (dropTickleDesire) {
5262*c54f35caSApple OSS Distributions // Force the next tickle to raise power state
5263*c54f35caSApple OSS Distributions fDeviceWasActive = false;
5264*c54f35caSApple OSS Distributions fActivityTicklePowerState = kInvalidTicklePowerState;
5265*c54f35caSApple OSS Distributions }
5266*c54f35caSApple OSS Distributions
5267*c54f35caSApple OSS Distributions IOLockUnlock(fActivityLock);
5268*c54f35caSApple OSS Distributions }
5269*c54f35caSApple OSS Distributions
5270*c54f35caSApple OSS Distributions if (dropTickleDesire) {
5271*c54f35caSApple OSS Distributions // Advisory tickle desire is intentionally untouched since
5272*c54f35caSApple OSS Distributions // it has no effect until system is promoted to full wake.
5273*c54f35caSApple OSS Distributions
5274*c54f35caSApple OSS Distributions updatePowerClient(gIOPMPowerClientDevice, kPowerStateZero);
5275*c54f35caSApple OSS Distributions computeDesiredState(kPowerStateZero, true);
5276*c54f35caSApple OSS Distributions PM_LOG1("%s: tickle desire dropped\n", fName);
5277*c54f35caSApple OSS Distributions }
5278*c54f35caSApple OSS Distributions }
5279*c54f35caSApple OSS Distributions }
5280*c54f35caSApple OSS Distributions
5281*c54f35caSApple OSS Distributions //*********************************************************************************
5282*c54f35caSApple OSS Distributions // [private] ParentChangeTellPriorityClientsPowerDown
5283*c54f35caSApple OSS Distributions //
5284*c54f35caSApple OSS Distributions // All applications and kernel clients have acknowledged our intention to drop
5285*c54f35caSApple OSS Distributions // power. Here we notify "priority" clients that we are lowering power.
5286*c54f35caSApple OSS Distributions //*********************************************************************************
5287*c54f35caSApple OSS Distributions
5288*c54f35caSApple OSS Distributions void
ParentChangeTellPriorityClientsPowerDown(void)5289*c54f35caSApple OSS Distributions IOService::ParentChangeTellPriorityClientsPowerDown( void )
5290*c54f35caSApple OSS Distributions {
5291*c54f35caSApple OSS Distributions fMachineState = kIOPM_ParentChangeNotifyInterestedDriversWillChange;
5292*c54f35caSApple OSS Distributions tellChangeDown2(fHeadNotePowerState);
5293*c54f35caSApple OSS Distributions }
5294*c54f35caSApple OSS Distributions
5295*c54f35caSApple OSS Distributions //*********************************************************************************
5296*c54f35caSApple OSS Distributions // [private] ParentChangeTellCapabilityWillChange
5297*c54f35caSApple OSS Distributions //
5298*c54f35caSApple OSS Distributions // All (legacy) applications and kernel clients have acknowledged, extra stage for
5299*c54f35caSApple OSS Distributions // root domain to notify apps and drivers about the system capability change.
5300*c54f35caSApple OSS Distributions //*********************************************************************************
5301*c54f35caSApple OSS Distributions
5302*c54f35caSApple OSS Distributions void
ParentChangeTellCapabilityWillChange(void)5303*c54f35caSApple OSS Distributions IOService::ParentChangeTellCapabilityWillChange( void )
5304*c54f35caSApple OSS Distributions {
5305*c54f35caSApple OSS Distributions if (!IS_ROOT_DOMAIN) {
5306*c54f35caSApple OSS Distributions return ParentChangeNotifyInterestedDriversWillChange();
5307*c54f35caSApple OSS Distributions }
5308*c54f35caSApple OSS Distributions
5309*c54f35caSApple OSS Distributions tellSystemCapabilityChange( kIOPM_ParentChangeNotifyInterestedDriversWillChange );
5310*c54f35caSApple OSS Distributions }
5311*c54f35caSApple OSS Distributions
5312*c54f35caSApple OSS Distributions //*********************************************************************************
5313*c54f35caSApple OSS Distributions // [private] ParentChangeNotifyInterestedDriversWillChange
5314*c54f35caSApple OSS Distributions //
5315*c54f35caSApple OSS Distributions // All applications and kernel clients have acknowledged our power state change.
5316*c54f35caSApple OSS Distributions // Here we notify interested drivers pre-change.
5317*c54f35caSApple OSS Distributions //*********************************************************************************
5318*c54f35caSApple OSS Distributions
5319*c54f35caSApple OSS Distributions void
ParentChangeNotifyInterestedDriversWillChange(void)5320*c54f35caSApple OSS Distributions IOService::ParentChangeNotifyInterestedDriversWillChange( void )
5321*c54f35caSApple OSS Distributions {
5322*c54f35caSApple OSS Distributions notifyAll( kIOPM_ParentChangeSetPowerState );
5323*c54f35caSApple OSS Distributions }
5324*c54f35caSApple OSS Distributions
5325*c54f35caSApple OSS Distributions //*********************************************************************************
5326*c54f35caSApple OSS Distributions // [private] ParentChangeSetPowerState
5327*c54f35caSApple OSS Distributions //
5328*c54f35caSApple OSS Distributions // Instruct our controlling driver to program the hardware for the power state
5329*c54f35caSApple OSS Distributions // change. Wait for async completions.
5330*c54f35caSApple OSS Distributions //*********************************************************************************
5331*c54f35caSApple OSS Distributions
5332*c54f35caSApple OSS Distributions void
ParentChangeSetPowerState(void)5333*c54f35caSApple OSS Distributions IOService::ParentChangeSetPowerState( void )
5334*c54f35caSApple OSS Distributions {
5335*c54f35caSApple OSS Distributions MS_PUSH( kIOPM_ParentChangeWaitForPowerSettle );
5336*c54f35caSApple OSS Distributions fMachineState = kIOPM_DriverThreadCallDone;
5337*c54f35caSApple OSS Distributions fDriverCallReason = kDriverCallSetPowerState;
5338*c54f35caSApple OSS Distributions
5339*c54f35caSApple OSS Distributions if (notifyControllingDriver() == false) {
5340*c54f35caSApple OSS Distributions notifyControllingDriverDone();
5341*c54f35caSApple OSS Distributions }
5342*c54f35caSApple OSS Distributions }
5343*c54f35caSApple OSS Distributions
5344*c54f35caSApple OSS Distributions //*********************************************************************************
5345*c54f35caSApple OSS Distributions // [private] ParentChangeWaitForPowerSettle
5346*c54f35caSApple OSS Distributions //
5347*c54f35caSApple OSS Distributions // Our controlling driver has completed the power state change initiated by our
5348*c54f35caSApple OSS Distributions // parent. Wait for the driver specified settle time to expire.
5349*c54f35caSApple OSS Distributions //*********************************************************************************
5350*c54f35caSApple OSS Distributions
5351*c54f35caSApple OSS Distributions void
ParentChangeWaitForPowerSettle(void)5352*c54f35caSApple OSS Distributions IOService::ParentChangeWaitForPowerSettle( void )
5353*c54f35caSApple OSS Distributions {
5354*c54f35caSApple OSS Distributions fMachineState = kIOPM_ParentChangeNotifyInterestedDriversDidChange;
5355*c54f35caSApple OSS Distributions startSettleTimer();
5356*c54f35caSApple OSS Distributions }
5357*c54f35caSApple OSS Distributions
5358*c54f35caSApple OSS Distributions //*********************************************************************************
5359*c54f35caSApple OSS Distributions // [private] ParentChangeNotifyInterestedDriversDidChange
5360*c54f35caSApple OSS Distributions //
5361*c54f35caSApple OSS Distributions // Power has settled on a power change initiated by our parent. Here we notify
5362*c54f35caSApple OSS Distributions // all our interested drivers post-change.
5363*c54f35caSApple OSS Distributions //*********************************************************************************
5364*c54f35caSApple OSS Distributions
5365*c54f35caSApple OSS Distributions void
ParentChangeNotifyInterestedDriversDidChange(void)5366*c54f35caSApple OSS Distributions IOService::ParentChangeNotifyInterestedDriversDidChange( void )
5367*c54f35caSApple OSS Distributions {
5368*c54f35caSApple OSS Distributions notifyAll( kIOPM_ParentChangeTellCapabilityDidChange );
5369*c54f35caSApple OSS Distributions }
5370*c54f35caSApple OSS Distributions
5371*c54f35caSApple OSS Distributions //*********************************************************************************
5372*c54f35caSApple OSS Distributions // [private] ParentChangeTellCapabilityDidChange
5373*c54f35caSApple OSS Distributions //
5374*c54f35caSApple OSS Distributions // For root domain to notify capability power-change.
5375*c54f35caSApple OSS Distributions //*********************************************************************************
5376*c54f35caSApple OSS Distributions
5377*c54f35caSApple OSS Distributions void
ParentChangeTellCapabilityDidChange(void)5378*c54f35caSApple OSS Distributions IOService::ParentChangeTellCapabilityDidChange( void )
5379*c54f35caSApple OSS Distributions {
5380*c54f35caSApple OSS Distributions if (!IS_ROOT_DOMAIN) {
5381*c54f35caSApple OSS Distributions return ParentChangeAcknowledgePowerChange();
5382*c54f35caSApple OSS Distributions }
5383*c54f35caSApple OSS Distributions
5384*c54f35caSApple OSS Distributions tellSystemCapabilityChange( kIOPM_ParentChangeAcknowledgePowerChange );
5385*c54f35caSApple OSS Distributions }
5386*c54f35caSApple OSS Distributions
5387*c54f35caSApple OSS Distributions //*********************************************************************************
5388*c54f35caSApple OSS Distributions // [private] ParentAcknowledgePowerChange
5389*c54f35caSApple OSS Distributions //
5390*c54f35caSApple OSS Distributions // Acknowledge our power parent that our power change is done.
5391*c54f35caSApple OSS Distributions //*********************************************************************************
5392*c54f35caSApple OSS Distributions
5393*c54f35caSApple OSS Distributions void
ParentChangeAcknowledgePowerChange(void)5394*c54f35caSApple OSS Distributions IOService::ParentChangeAcknowledgePowerChange( void )
5395*c54f35caSApple OSS Distributions {
5396*c54f35caSApple OSS Distributions IORegistryEntry * nub;
5397*c54f35caSApple OSS Distributions IOService * parent;
5398*c54f35caSApple OSS Distributions
5399*c54f35caSApple OSS Distributions nub = fHeadNoteParentConnection;
5400*c54f35caSApple OSS Distributions nub->retain();
5401*c54f35caSApple OSS Distributions all_done();
5402*c54f35caSApple OSS Distributions parent = (IOService *)nub->copyParentEntry(gIOPowerPlane);
5403*c54f35caSApple OSS Distributions if (parent) {
5404*c54f35caSApple OSS Distributions parent->acknowledgePowerChange((IOService *)nub);
5405*c54f35caSApple OSS Distributions parent->release();
5406*c54f35caSApple OSS Distributions }
5407*c54f35caSApple OSS Distributions nub->release();
5408*c54f35caSApple OSS Distributions }
5409*c54f35caSApple OSS Distributions
5410*c54f35caSApple OSS Distributions // MARK: -
5411*c54f35caSApple OSS Distributions // MARK: Ack and Settle timers
5412*c54f35caSApple OSS Distributions
5413*c54f35caSApple OSS Distributions //*********************************************************************************
5414*c54f35caSApple OSS Distributions // [private] settleTimerExpired
5415*c54f35caSApple OSS Distributions //
5416*c54f35caSApple OSS Distributions // Power has settled after our last change. Notify interested parties that
5417*c54f35caSApple OSS Distributions // there is a new power state.
5418*c54f35caSApple OSS Distributions //*********************************************************************************
5419*c54f35caSApple OSS Distributions
5420*c54f35caSApple OSS Distributions void
settleTimerExpired(void)5421*c54f35caSApple OSS Distributions IOService::settleTimerExpired( void )
5422*c54f35caSApple OSS Distributions {
5423*c54f35caSApple OSS Distributions #if USE_SETTLE_TIMER
5424*c54f35caSApple OSS Distributions fSettleTimeUS = 0;
5425*c54f35caSApple OSS Distributions gIOPMWorkQueue->signalWorkAvailable();
5426*c54f35caSApple OSS Distributions #endif
5427*c54f35caSApple OSS Distributions }
5428*c54f35caSApple OSS Distributions
5429*c54f35caSApple OSS Distributions //*********************************************************************************
5430*c54f35caSApple OSS Distributions // settle_timer_expired
5431*c54f35caSApple OSS Distributions //
5432*c54f35caSApple OSS Distributions // Holds a retain while the settle timer callout is in flight.
5433*c54f35caSApple OSS Distributions //*********************************************************************************
5434*c54f35caSApple OSS Distributions
5435*c54f35caSApple OSS Distributions #if USE_SETTLE_TIMER
5436*c54f35caSApple OSS Distributions static void
settle_timer_expired(thread_call_param_t arg0,thread_call_param_t arg1)5437*c54f35caSApple OSS Distributions settle_timer_expired( thread_call_param_t arg0, thread_call_param_t arg1 )
5438*c54f35caSApple OSS Distributions {
5439*c54f35caSApple OSS Distributions IOService * me = (IOService *) arg0;
5440*c54f35caSApple OSS Distributions
5441*c54f35caSApple OSS Distributions if (gIOPMWorkLoop && gIOPMWorkQueue) {
5442*c54f35caSApple OSS Distributions gIOPMWorkLoop->runAction(
5443*c54f35caSApple OSS Distributions OSMemberFunctionCast(IOWorkLoop::Action, me, &IOService::settleTimerExpired),
5444*c54f35caSApple OSS Distributions me);
5445*c54f35caSApple OSS Distributions }
5446*c54f35caSApple OSS Distributions me->release();
5447*c54f35caSApple OSS Distributions }
5448*c54f35caSApple OSS Distributions #endif
5449*c54f35caSApple OSS Distributions
5450*c54f35caSApple OSS Distributions //*********************************************************************************
5451*c54f35caSApple OSS Distributions // [private] startSettleTimer
5452*c54f35caSApple OSS Distributions //
5453*c54f35caSApple OSS Distributions // Calculate a power-settling delay in microseconds and start a timer.
5454*c54f35caSApple OSS Distributions //*********************************************************************************
5455*c54f35caSApple OSS Distributions
5456*c54f35caSApple OSS Distributions void
startSettleTimer(void)5457*c54f35caSApple OSS Distributions IOService::startSettleTimer( void )
5458*c54f35caSApple OSS Distributions {
5459*c54f35caSApple OSS Distributions #if USE_SETTLE_TIMER
5460*c54f35caSApple OSS Distributions // This function is broken and serves no useful purpose since it never
5461*c54f35caSApple OSS Distributions // updates fSettleTimeUS to a non-zero value to stall the state machine,
5462*c54f35caSApple OSS Distributions // yet it starts a delay timer. It appears no driver relies on a delay
5463*c54f35caSApple OSS Distributions // from settleUpTime and settleDownTime in the power state table.
5464*c54f35caSApple OSS Distributions
5465*c54f35caSApple OSS Distributions AbsoluteTime deadline;
5466*c54f35caSApple OSS Distributions IOPMPowerStateIndex stateIndex;
5467*c54f35caSApple OSS Distributions IOPMPowerStateIndex currentOrder, newOrder, i;
5468*c54f35caSApple OSS Distributions uint32_t settleTime = 0;
5469*c54f35caSApple OSS Distributions boolean_t pending;
5470*c54f35caSApple OSS Distributions
5471*c54f35caSApple OSS Distributions PM_ASSERT_IN_GATE();
5472*c54f35caSApple OSS Distributions
5473*c54f35caSApple OSS Distributions currentOrder = StateOrder(fCurrentPowerState);
5474*c54f35caSApple OSS Distributions newOrder = StateOrder(fHeadNotePowerState);
5475*c54f35caSApple OSS Distributions
5476*c54f35caSApple OSS Distributions i = currentOrder;
5477*c54f35caSApple OSS Distributions
5478*c54f35caSApple OSS Distributions // lowering power
5479*c54f35caSApple OSS Distributions if (newOrder < currentOrder) {
5480*c54f35caSApple OSS Distributions while (i > newOrder) {
5481*c54f35caSApple OSS Distributions stateIndex = fPowerStates[i].stateOrderToIndex;
5482*c54f35caSApple OSS Distributions settleTime += (uint32_t) fPowerStates[stateIndex].settleDownTime;
5483*c54f35caSApple OSS Distributions i--;
5484*c54f35caSApple OSS Distributions }
5485*c54f35caSApple OSS Distributions }
5486*c54f35caSApple OSS Distributions
5487*c54f35caSApple OSS Distributions // raising power
5488*c54f35caSApple OSS Distributions if (newOrder > currentOrder) {
5489*c54f35caSApple OSS Distributions while (i < newOrder) {
5490*c54f35caSApple OSS Distributions stateIndex = fPowerStates[i + 1].stateOrderToIndex;
5491*c54f35caSApple OSS Distributions settleTime += (uint32_t) fPowerStates[stateIndex].settleUpTime;
5492*c54f35caSApple OSS Distributions i++;
5493*c54f35caSApple OSS Distributions }
5494*c54f35caSApple OSS Distributions }
5495*c54f35caSApple OSS Distributions
5496*c54f35caSApple OSS Distributions if (settleTime) {
5497*c54f35caSApple OSS Distributions retain();
5498*c54f35caSApple OSS Distributions clock_interval_to_deadline(settleTime, kMicrosecondScale, &deadline);
5499*c54f35caSApple OSS Distributions pending = thread_call_enter_delayed(fSettleTimer, deadline);
5500*c54f35caSApple OSS Distributions if (pending) {
5501*c54f35caSApple OSS Distributions release();
5502*c54f35caSApple OSS Distributions }
5503*c54f35caSApple OSS Distributions }
5504*c54f35caSApple OSS Distributions #endif
5505*c54f35caSApple OSS Distributions }
5506*c54f35caSApple OSS Distributions
5507*c54f35caSApple OSS Distributions //*********************************************************************************
5508*c54f35caSApple OSS Distributions // [private] ackTimerTick
5509*c54f35caSApple OSS Distributions //
5510*c54f35caSApple OSS Distributions // The acknowledgement timeout periodic timer has ticked.
5511*c54f35caSApple OSS Distributions // If we are awaiting acks for a power change notification,
5512*c54f35caSApple OSS Distributions // we decrement the timer word of each interested driver which hasn't acked.
5513*c54f35caSApple OSS Distributions // If a timer word becomes zero, we pretend the driver aknowledged.
5514*c54f35caSApple OSS Distributions // If we are waiting for the controlling driver to change the power
5515*c54f35caSApple OSS Distributions // state of the hardware, we decrement its timer word, and if it becomes
5516*c54f35caSApple OSS Distributions // zero, we pretend the driver acknowledged.
5517*c54f35caSApple OSS Distributions //
5518*c54f35caSApple OSS Distributions // Returns true if the timer tick made it possible to advance to the next
5519*c54f35caSApple OSS Distributions // machine state, false otherwise.
5520*c54f35caSApple OSS Distributions //*********************************************************************************
5521*c54f35caSApple OSS Distributions
5522*c54f35caSApple OSS Distributions #ifndef __LP64__
5523*c54f35caSApple OSS Distributions #if MACH_ASSERT
5524*c54f35caSApple OSS Distributions __dead2
5525*c54f35caSApple OSS Distributions #endif
5526*c54f35caSApple OSS Distributions void
ack_timer_ticked(void)5527*c54f35caSApple OSS Distributions IOService::ack_timer_ticked( void )
5528*c54f35caSApple OSS Distributions {
5529*c54f35caSApple OSS Distributions assert(false);
5530*c54f35caSApple OSS Distributions }
5531*c54f35caSApple OSS Distributions #endif /* !__LP64__ */
5532*c54f35caSApple OSS Distributions
5533*c54f35caSApple OSS Distributions bool
ackTimerTick(void)5534*c54f35caSApple OSS Distributions IOService::ackTimerTick( void )
5535*c54f35caSApple OSS Distributions {
5536*c54f35caSApple OSS Distributions IOPMinformee * nextObject;
5537*c54f35caSApple OSS Distributions bool done = false;
5538*c54f35caSApple OSS Distributions
5539*c54f35caSApple OSS Distributions PM_ASSERT_IN_GATE();
5540*c54f35caSApple OSS Distributions switch (fMachineState) {
5541*c54f35caSApple OSS Distributions case kIOPM_OurChangeWaitForPowerSettle:
5542*c54f35caSApple OSS Distributions case kIOPM_ParentChangeWaitForPowerSettle:
5543*c54f35caSApple OSS Distributions // are we waiting for controlling driver to acknowledge?
5544*c54f35caSApple OSS Distributions if (fDriverTimer > 0) {
5545*c54f35caSApple OSS Distributions // yes, decrement timer tick
5546*c54f35caSApple OSS Distributions fDriverTimer--;
5547*c54f35caSApple OSS Distributions if (fDriverTimer == 0) {
5548*c54f35caSApple OSS Distributions // controlling driver is tardy
5549*c54f35caSApple OSS Distributions uint64_t nsec = computeTimeDeltaNS(&fDriverCallStartTime);
5550*c54f35caSApple OSS Distributions OUR_PMLog(kPMLogCtrlDriverTardy, 0, 0);
5551*c54f35caSApple OSS Distributions setProperty(kIOPMTardyAckSPSKey, kOSBooleanTrue);
5552*c54f35caSApple OSS Distributions PM_ERROR("%s::setPowerState(%p, %lu -> %lu) timed out after %d ms\n",
5553*c54f35caSApple OSS Distributions fName, OBFUSCATE(this), fCurrentPowerState, fHeadNotePowerState, NS_TO_MS(nsec));
5554*c54f35caSApple OSS Distributions
5555*c54f35caSApple OSS Distributions #if DEBUG || DEVELOPMENT || !defined(XNU_TARGET_OS_OSX)
5556*c54f35caSApple OSS Distributions bool panic_allowed = false;
5557*c54f35caSApple OSS Distributions uint32_t setpowerstate_panic = -1;
5558*c54f35caSApple OSS Distributions PE_parse_boot_argn("setpowerstate_panic", &setpowerstate_panic, sizeof(setpowerstate_panic));
5559*c54f35caSApple OSS Distributions panic_allowed = setpowerstate_panic != 0;
5560*c54f35caSApple OSS Distributions #ifdef CONFIG_XNUPOST
5561*c54f35caSApple OSS Distributions uint64_t kernel_post_args = 0;
5562*c54f35caSApple OSS Distributions PE_parse_boot_argn("kernPOST", &kernel_post_args, sizeof(kernel_post_args));
5563*c54f35caSApple OSS Distributions if (kernel_post_args != 0) {
5564*c54f35caSApple OSS Distributions panic_allowed = false;
5565*c54f35caSApple OSS Distributions }
5566*c54f35caSApple OSS Distributions #endif /* CONFIG_XNUPOST */
5567*c54f35caSApple OSS Distributions if (panic_allowed) {
5568*c54f35caSApple OSS Distributions // rdar://problem/48743340 - excluding AppleSEPManager from panic
5569*c54f35caSApple OSS Distributions const char *allowlist = "AppleSEPManager";
5570*c54f35caSApple OSS Distributions if (strncmp(fName, allowlist, strlen(allowlist))) {
5571*c54f35caSApple OSS Distributions panic("%s::setPowerState(%p, %lu -> %lu) timed out after %d ms",
5572*c54f35caSApple OSS Distributions fName, this, fCurrentPowerState, fHeadNotePowerState, NS_TO_MS(nsec));
5573*c54f35caSApple OSS Distributions }
5574*c54f35caSApple OSS Distributions } else {
5575*c54f35caSApple OSS Distributions #ifdef CONFIG_XNUPOST
5576*c54f35caSApple OSS Distributions if (kernel_post_args != 0) {
5577*c54f35caSApple OSS Distributions PM_ERROR("setPowerState panic disabled by kernPOST boot-arg\n");
5578*c54f35caSApple OSS Distributions }
5579*c54f35caSApple OSS Distributions #endif /* CONFIG_XNUPOST */
5580*c54f35caSApple OSS Distributions if (setpowerstate_panic != 0) {
5581*c54f35caSApple OSS Distributions PM_ERROR("setPowerState panic disabled by setpowerstate_panic boot-arg\n");
5582*c54f35caSApple OSS Distributions }
5583*c54f35caSApple OSS Distributions }
5584*c54f35caSApple OSS Distributions #else /* !(DEBUG || DEVELOPMENT || !defined(XNU_TARGET_OS_OSX)) */
5585*c54f35caSApple OSS Distributions if (gIOKitDebug & kIOLogDebugPower) {
5586*c54f35caSApple OSS Distributions panic("%s::setPowerState(%p, %lu -> %lu) timed out after %d ms",
5587*c54f35caSApple OSS Distributions fName, this, fCurrentPowerState, fHeadNotePowerState, NS_TO_MS(nsec));
5588*c54f35caSApple OSS Distributions } else {
5589*c54f35caSApple OSS Distributions // panic for first party kexts
5590*c54f35caSApple OSS Distributions const void *function_addr = NULL;
5591*c54f35caSApple OSS Distributions OSKext *kext = NULL;
5592*c54f35caSApple OSS Distributions function_addr = OSMemberFunctionCast(const void *, fControllingDriver, &IOService::setPowerState);
5593*c54f35caSApple OSS Distributions kext = OSKext::lookupKextWithAddress((vm_address_t)function_addr);
5594*c54f35caSApple OSS Distributions if (kext) {
5595*c54f35caSApple OSS Distributions #if __has_feature(ptrauth_calls)
5596*c54f35caSApple OSS Distributions function_addr = (const void*)VM_KERNEL_STRIP_PTR(function_addr);
5597*c54f35caSApple OSS Distributions #endif /* __has_feature(ptrauth_calls) */
5598*c54f35caSApple OSS Distributions const char *bundleID = kext->getIdentifierCString();
5599*c54f35caSApple OSS Distributions const char *apple_prefix = "com.apple";
5600*c54f35caSApple OSS Distributions const char *kernel_prefix = "__kernel__";
5601*c54f35caSApple OSS Distributions if (strncmp(bundleID, apple_prefix, strlen(apple_prefix)) == 0 || strncmp(bundleID, kernel_prefix, strlen(kernel_prefix)) == 0) {
5602*c54f35caSApple OSS Distributions // first party client
5603*c54f35caSApple OSS Distributions panic("%s::setPowerState(%p : %p, %lu -> %lu) timed out after %d ms",
5604*c54f35caSApple OSS Distributions fName, this, function_addr, fCurrentPowerState, fHeadNotePowerState, NS_TO_MS(nsec));
5605*c54f35caSApple OSS Distributions }
5606*c54f35caSApple OSS Distributions kext->release();
5607*c54f35caSApple OSS Distributions }
5608*c54f35caSApple OSS Distributions }
5609*c54f35caSApple OSS Distributions #endif /* !(DEBUG || DEVELOPMENT || !defined(XNU_TARGET_OS_OSX)) */
5610*c54f35caSApple OSS Distributions // Unblock state machine and pretend driver has acked.
5611*c54f35caSApple OSS Distributions done = true;
5612*c54f35caSApple OSS Distributions getPMRootDomain()->reset_watchdog_timer(this, 0);
5613*c54f35caSApple OSS Distributions } else {
5614*c54f35caSApple OSS Distributions // still waiting, set timer again
5615*c54f35caSApple OSS Distributions start_ack_timer();
5616*c54f35caSApple OSS Distributions }
5617*c54f35caSApple OSS Distributions }
5618*c54f35caSApple OSS Distributions break;
5619*c54f35caSApple OSS Distributions
5620*c54f35caSApple OSS Distributions case kIOPM_NotifyChildrenStart:
5621*c54f35caSApple OSS Distributions // are we waiting for interested parties to acknowledge?
5622*c54f35caSApple OSS Distributions if (fHeadNotePendingAcks != 0) {
5623*c54f35caSApple OSS Distributions // yes, go through the list of interested drivers
5624*c54f35caSApple OSS Distributions nextObject = fInterestedDrivers->firstInList();
5625*c54f35caSApple OSS Distributions // and check each one
5626*c54f35caSApple OSS Distributions while (nextObject != NULL) {
5627*c54f35caSApple OSS Distributions if (nextObject->timer > 0) {
5628*c54f35caSApple OSS Distributions nextObject->timer--;
5629*c54f35caSApple OSS Distributions // this one should have acked by now
5630*c54f35caSApple OSS Distributions if (nextObject->timer == 0) {
5631*c54f35caSApple OSS Distributions uint64_t nsec = computeTimeDeltaNS(&nextObject->startTime);
5632*c54f35caSApple OSS Distributions OUR_PMLog(kPMLogIntDriverTardy, 0, 0);
5633*c54f35caSApple OSS Distributions nextObject->whatObject->setProperty(kIOPMTardyAckPSCKey, kOSBooleanTrue);
5634*c54f35caSApple OSS Distributions PM_ERROR("%s::powerState%sChangeTo(%p, %s, %lu -> %lu) timed out after %d ms\n",
5635*c54f35caSApple OSS Distributions nextObject->whatObject->getName(),
5636*c54f35caSApple OSS Distributions (fDriverCallReason == kDriverCallInformPreChange) ? "Will" : "Did",
5637*c54f35caSApple OSS Distributions OBFUSCATE(nextObject->whatObject), fName, fCurrentPowerState, fHeadNotePowerState,
5638*c54f35caSApple OSS Distributions NS_TO_MS(nsec));
5639*c54f35caSApple OSS Distributions
5640*c54f35caSApple OSS Distributions // Pretend driver has acked.
5641*c54f35caSApple OSS Distributions fHeadNotePendingAcks--;
5642*c54f35caSApple OSS Distributions }
5643*c54f35caSApple OSS Distributions }
5644*c54f35caSApple OSS Distributions nextObject = fInterestedDrivers->nextInList(nextObject);
5645*c54f35caSApple OSS Distributions }
5646*c54f35caSApple OSS Distributions
5647*c54f35caSApple OSS Distributions // is that the last?
5648*c54f35caSApple OSS Distributions if (fHeadNotePendingAcks == 0) {
5649*c54f35caSApple OSS Distributions // yes, we can continue
5650*c54f35caSApple OSS Distributions done = true;
5651*c54f35caSApple OSS Distributions getPMRootDomain()->reset_watchdog_timer(this, 0);
5652*c54f35caSApple OSS Distributions } else {
5653*c54f35caSApple OSS Distributions // no, set timer again
5654*c54f35caSApple OSS Distributions start_ack_timer();
5655*c54f35caSApple OSS Distributions }
5656*c54f35caSApple OSS Distributions }
5657*c54f35caSApple OSS Distributions break;
5658*c54f35caSApple OSS Distributions
5659*c54f35caSApple OSS Distributions // TODO: aggreggate this
5660*c54f35caSApple OSS Distributions case kIOPM_OurChangeTellClientsPowerDown:
5661*c54f35caSApple OSS Distributions case kIOPM_OurChangeTellUserPMPolicyPowerDown:
5662*c54f35caSApple OSS Distributions case kIOPM_OurChangeTellPriorityClientsPowerDown:
5663*c54f35caSApple OSS Distributions case kIOPM_OurChangeNotifyInterestedDriversWillChange:
5664*c54f35caSApple OSS Distributions case kIOPM_ParentChangeTellPriorityClientsPowerDown:
5665*c54f35caSApple OSS Distributions case kIOPM_ParentChangeNotifyInterestedDriversWillChange:
5666*c54f35caSApple OSS Distributions case kIOPM_SyncTellClientsPowerDown:
5667*c54f35caSApple OSS Distributions case kIOPM_SyncTellPriorityClientsPowerDown:
5668*c54f35caSApple OSS Distributions case kIOPM_SyncNotifyWillChange:
5669*c54f35caSApple OSS Distributions case kIOPM_TellCapabilityChangeDone:
5670*c54f35caSApple OSS Distributions // apps didn't respond in time
5671*c54f35caSApple OSS Distributions cleanClientResponses(true);
5672*c54f35caSApple OSS Distributions OUR_PMLog(kPMLogClientTardy, 0, 1);
5673*c54f35caSApple OSS Distributions // tardy equates to approval
5674*c54f35caSApple OSS Distributions done = true;
5675*c54f35caSApple OSS Distributions break;
5676*c54f35caSApple OSS Distributions
5677*c54f35caSApple OSS Distributions default:
5678*c54f35caSApple OSS Distributions PM_LOG1("%s: unexpected ack timer tick (state = %d)\n",
5679*c54f35caSApple OSS Distributions getName(), fMachineState);
5680*c54f35caSApple OSS Distributions break;
5681*c54f35caSApple OSS Distributions }
5682*c54f35caSApple OSS Distributions return done;
5683*c54f35caSApple OSS Distributions }
5684*c54f35caSApple OSS Distributions
5685*c54f35caSApple OSS Distributions //*********************************************************************************
5686*c54f35caSApple OSS Distributions // [private] start_watchdog_timer
5687*c54f35caSApple OSS Distributions //*********************************************************************************
5688*c54f35caSApple OSS Distributions void
start_watchdog_timer(void)5689*c54f35caSApple OSS Distributions IOService::start_watchdog_timer( void )
5690*c54f35caSApple OSS Distributions {
5691*c54f35caSApple OSS Distributions int timeout;
5692*c54f35caSApple OSS Distributions uint64_t deadline;
5693*c54f35caSApple OSS Distributions
5694*c54f35caSApple OSS Distributions if (!fWatchdogTimer || (kIOSleepWakeWdogOff & gIOKitDebug)) {
5695*c54f35caSApple OSS Distributions return;
5696*c54f35caSApple OSS Distributions }
5697*c54f35caSApple OSS Distributions
5698*c54f35caSApple OSS Distributions IOLockLock(fWatchdogLock);
5699*c54f35caSApple OSS Distributions
5700*c54f35caSApple OSS Distributions timeout = getPMRootDomain()->getWatchdogTimeout();
5701*c54f35caSApple OSS Distributions clock_interval_to_deadline(timeout, kSecondScale, &deadline);
5702*c54f35caSApple OSS Distributions start_watchdog_timer(deadline);
5703*c54f35caSApple OSS Distributions IOLockUnlock(fWatchdogLock);
5704*c54f35caSApple OSS Distributions }
5705*c54f35caSApple OSS Distributions
5706*c54f35caSApple OSS Distributions void
start_watchdog_timer(uint64_t deadline)5707*c54f35caSApple OSS Distributions IOService::start_watchdog_timer(uint64_t deadline)
5708*c54f35caSApple OSS Distributions {
5709*c54f35caSApple OSS Distributions IOLockAssert(fWatchdogLock, kIOLockAssertOwned);
5710*c54f35caSApple OSS Distributions fWatchdogDeadline = deadline;
5711*c54f35caSApple OSS Distributions
5712*c54f35caSApple OSS Distributions if (!thread_call_isactive(fWatchdogTimer)) {
5713*c54f35caSApple OSS Distributions thread_call_enter_delayed(fWatchdogTimer, deadline);
5714*c54f35caSApple OSS Distributions }
5715*c54f35caSApple OSS Distributions }
5716*c54f35caSApple OSS Distributions
5717*c54f35caSApple OSS Distributions //*********************************************************************************
5718*c54f35caSApple OSS Distributions // [private] stop_watchdog_timer
5719*c54f35caSApple OSS Distributions //*********************************************************************************
5720*c54f35caSApple OSS Distributions
5721*c54f35caSApple OSS Distributions void
stop_watchdog_timer(void)5722*c54f35caSApple OSS Distributions IOService::stop_watchdog_timer( void )
5723*c54f35caSApple OSS Distributions {
5724*c54f35caSApple OSS Distributions if (!fWatchdogTimer || (kIOSleepWakeWdogOff & gIOKitDebug)) {
5725*c54f35caSApple OSS Distributions return;
5726*c54f35caSApple OSS Distributions }
5727*c54f35caSApple OSS Distributions
5728*c54f35caSApple OSS Distributions IOLockLock(fWatchdogLock);
5729*c54f35caSApple OSS Distributions
5730*c54f35caSApple OSS Distributions thread_call_cancel(fWatchdogTimer);
5731*c54f35caSApple OSS Distributions fWatchdogDeadline = 0;
5732*c54f35caSApple OSS Distributions
5733*c54f35caSApple OSS Distributions while (fBlockedArray->getCount()) {
5734*c54f35caSApple OSS Distributions IOService *obj = OSDynamicCast(IOService, fBlockedArray->getObject(0));
5735*c54f35caSApple OSS Distributions if (obj) {
5736*c54f35caSApple OSS Distributions PM_ERROR("WDOG:Object %s unexpected in blocked array\n", obj->fName);
5737*c54f35caSApple OSS Distributions fBlockedArray->removeObject(0);
5738*c54f35caSApple OSS Distributions }
5739*c54f35caSApple OSS Distributions }
5740*c54f35caSApple OSS Distributions
5741*c54f35caSApple OSS Distributions IOLockUnlock(fWatchdogLock);
5742*c54f35caSApple OSS Distributions }
5743*c54f35caSApple OSS Distributions
5744*c54f35caSApple OSS Distributions //*********************************************************************************
5745*c54f35caSApple OSS Distributions // reset_watchdog_timer
5746*c54f35caSApple OSS Distributions //*********************************************************************************
5747*c54f35caSApple OSS Distributions
5748*c54f35caSApple OSS Distributions void
reset_watchdog_timer(IOService * blockedObject,int pendingResponseTimeout)5749*c54f35caSApple OSS Distributions IOService::reset_watchdog_timer(IOService *blockedObject, int pendingResponseTimeout)
5750*c54f35caSApple OSS Distributions {
5751*c54f35caSApple OSS Distributions unsigned int i;
5752*c54f35caSApple OSS Distributions uint64_t deadline;
5753*c54f35caSApple OSS Distributions IOService *obj;
5754*c54f35caSApple OSS Distributions
5755*c54f35caSApple OSS Distributions if (!fWatchdogTimer || (kIOSleepWakeWdogOff & gIOKitDebug)) {
5756*c54f35caSApple OSS Distributions return;
5757*c54f35caSApple OSS Distributions }
5758*c54f35caSApple OSS Distributions
5759*c54f35caSApple OSS Distributions
5760*c54f35caSApple OSS Distributions IOLockLock(fWatchdogLock);
5761*c54f35caSApple OSS Distributions if (!fWatchdogDeadline) {
5762*c54f35caSApple OSS Distributions goto exit;
5763*c54f35caSApple OSS Distributions }
5764*c54f35caSApple OSS Distributions
5765*c54f35caSApple OSS Distributions i = fBlockedArray->getNextIndexOfObject(blockedObject, 0);
5766*c54f35caSApple OSS Distributions if (pendingResponseTimeout == 0) {
5767*c54f35caSApple OSS Distributions blockedObject->fPendingResponseDeadline = 0;
5768*c54f35caSApple OSS Distributions if (i == (unsigned int)-1) {
5769*c54f35caSApple OSS Distributions goto exit;
5770*c54f35caSApple OSS Distributions }
5771*c54f35caSApple OSS Distributions fBlockedArray->removeObject(i);
5772*c54f35caSApple OSS Distributions } else {
5773*c54f35caSApple OSS Distributions // Set deadline 2secs after the expected response timeout to allow
5774*c54f35caSApple OSS Distributions // ack timer to handle the timeout.
5775*c54f35caSApple OSS Distributions clock_interval_to_deadline(pendingResponseTimeout + 2, kSecondScale, &deadline);
5776*c54f35caSApple OSS Distributions
5777*c54f35caSApple OSS Distributions if (i != (unsigned int)-1) {
5778*c54f35caSApple OSS Distributions PM_ERROR("WDOG:Object %s is already blocked for responses. Ignoring timeout %d\n",
5779*c54f35caSApple OSS Distributions fName, pendingResponseTimeout);
5780*c54f35caSApple OSS Distributions goto exit;
5781*c54f35caSApple OSS Distributions }
5782*c54f35caSApple OSS Distributions
5783*c54f35caSApple OSS Distributions for (i = 0; i < fBlockedArray->getCount(); i++) {
5784*c54f35caSApple OSS Distributions obj = OSDynamicCast(IOService, fBlockedArray->getObject(i));
5785*c54f35caSApple OSS Distributions if (obj && (obj->fPendingResponseDeadline < deadline)) {
5786*c54f35caSApple OSS Distributions blockedObject->fPendingResponseDeadline = deadline;
5787*c54f35caSApple OSS Distributions fBlockedArray->setObject(i, blockedObject);
5788*c54f35caSApple OSS Distributions break;
5789*c54f35caSApple OSS Distributions }
5790*c54f35caSApple OSS Distributions }
5791*c54f35caSApple OSS Distributions if (i == fBlockedArray->getCount()) {
5792*c54f35caSApple OSS Distributions blockedObject->fPendingResponseDeadline = deadline;
5793*c54f35caSApple OSS Distributions fBlockedArray->setObject(blockedObject);
5794*c54f35caSApple OSS Distributions }
5795*c54f35caSApple OSS Distributions }
5796*c54f35caSApple OSS Distributions
5797*c54f35caSApple OSS Distributions obj = OSDynamicCast(IOService, fBlockedArray->getObject(0));
5798*c54f35caSApple OSS Distributions if (!obj) {
5799*c54f35caSApple OSS Distributions int timeout = getPMRootDomain()->getWatchdogTimeout();
5800*c54f35caSApple OSS Distributions clock_interval_to_deadline(timeout, kSecondScale, &deadline);
5801*c54f35caSApple OSS Distributions } else {
5802*c54f35caSApple OSS Distributions deadline = obj->fPendingResponseDeadline;
5803*c54f35caSApple OSS Distributions }
5804*c54f35caSApple OSS Distributions
5805*c54f35caSApple OSS Distributions thread_call_cancel(fWatchdogTimer);
5806*c54f35caSApple OSS Distributions start_watchdog_timer(deadline);
5807*c54f35caSApple OSS Distributions
5808*c54f35caSApple OSS Distributions exit:
5809*c54f35caSApple OSS Distributions IOLockUnlock(fWatchdogLock);
5810*c54f35caSApple OSS Distributions }
5811*c54f35caSApple OSS Distributions
5812*c54f35caSApple OSS Distributions
5813*c54f35caSApple OSS Distributions //*********************************************************************************
5814*c54f35caSApple OSS Distributions // [static] watchdog_timer_expired
5815*c54f35caSApple OSS Distributions //
5816*c54f35caSApple OSS Distributions // Inside PM work loop's gate.
5817*c54f35caSApple OSS Distributions //*********************************************************************************
5818*c54f35caSApple OSS Distributions
5819*c54f35caSApple OSS Distributions void
watchdog_timer_expired(thread_call_param_t arg0,thread_call_param_t arg1)5820*c54f35caSApple OSS Distributions IOService::watchdog_timer_expired( thread_call_param_t arg0, thread_call_param_t arg1 )
5821*c54f35caSApple OSS Distributions {
5822*c54f35caSApple OSS Distributions IOService * me = (IOService *) arg0;
5823*c54f35caSApple OSS Distributions bool expired;
5824*c54f35caSApple OSS Distributions
5825*c54f35caSApple OSS Distributions IOLockLock(me->fWatchdogLock);
5826*c54f35caSApple OSS Distributions expired = me->fWatchdogDeadline && (me->fWatchdogDeadline <= mach_absolute_time());
5827*c54f35caSApple OSS Distributions IOLockUnlock(me->fWatchdogLock);
5828*c54f35caSApple OSS Distributions if (!expired) {
5829*c54f35caSApple OSS Distributions return;
5830*c54f35caSApple OSS Distributions }
5831*c54f35caSApple OSS Distributions
5832*c54f35caSApple OSS Distributions gIOPMWatchDogThread = current_thread();
5833*c54f35caSApple OSS Distributions getPMRootDomain()->sleepWakeDebugTrig(true);
5834*c54f35caSApple OSS Distributions gIOPMWatchDogThread = NULL;
5835*c54f35caSApple OSS Distributions thread_call_free(me->fWatchdogTimer);
5836*c54f35caSApple OSS Distributions me->fWatchdogTimer = NULL;
5837*c54f35caSApple OSS Distributions
5838*c54f35caSApple OSS Distributions return;
5839*c54f35caSApple OSS Distributions }
5840*c54f35caSApple OSS Distributions
5841*c54f35caSApple OSS Distributions
5842*c54f35caSApple OSS Distributions IOWorkLoop *
getIOPMWorkloop(void)5843*c54f35caSApple OSS Distributions IOService::getIOPMWorkloop( void )
5844*c54f35caSApple OSS Distributions {
5845*c54f35caSApple OSS Distributions return gIOPMWorkLoop;
5846*c54f35caSApple OSS Distributions }
5847*c54f35caSApple OSS Distributions
5848*c54f35caSApple OSS Distributions
5849*c54f35caSApple OSS Distributions
5850*c54f35caSApple OSS Distributions //*********************************************************************************
5851*c54f35caSApple OSS Distributions // [private] start_ack_timer
5852*c54f35caSApple OSS Distributions //*********************************************************************************
5853*c54f35caSApple OSS Distributions
5854*c54f35caSApple OSS Distributions void
start_ack_timer(void)5855*c54f35caSApple OSS Distributions IOService::start_ack_timer( void )
5856*c54f35caSApple OSS Distributions {
5857*c54f35caSApple OSS Distributions start_ack_timer( ACK_TIMER_PERIOD, kNanosecondScale );
5858*c54f35caSApple OSS Distributions }
5859*c54f35caSApple OSS Distributions
5860*c54f35caSApple OSS Distributions void
start_ack_timer(UInt32 interval,UInt32 scale)5861*c54f35caSApple OSS Distributions IOService::start_ack_timer( UInt32 interval, UInt32 scale )
5862*c54f35caSApple OSS Distributions {
5863*c54f35caSApple OSS Distributions AbsoluteTime deadline;
5864*c54f35caSApple OSS Distributions boolean_t pending;
5865*c54f35caSApple OSS Distributions
5866*c54f35caSApple OSS Distributions clock_interval_to_deadline(interval, scale, &deadline);
5867*c54f35caSApple OSS Distributions
5868*c54f35caSApple OSS Distributions retain();
5869*c54f35caSApple OSS Distributions pending = thread_call_enter_delayed(fAckTimer, deadline);
5870*c54f35caSApple OSS Distributions if (pending) {
5871*c54f35caSApple OSS Distributions release();
5872*c54f35caSApple OSS Distributions }
5873*c54f35caSApple OSS Distributions }
5874*c54f35caSApple OSS Distributions
5875*c54f35caSApple OSS Distributions //*********************************************************************************
5876*c54f35caSApple OSS Distributions // [private] stop_ack_timer
5877*c54f35caSApple OSS Distributions //*********************************************************************************
5878*c54f35caSApple OSS Distributions
5879*c54f35caSApple OSS Distributions void
stop_ack_timer(void)5880*c54f35caSApple OSS Distributions IOService::stop_ack_timer( void )
5881*c54f35caSApple OSS Distributions {
5882*c54f35caSApple OSS Distributions boolean_t pending;
5883*c54f35caSApple OSS Distributions
5884*c54f35caSApple OSS Distributions pending = thread_call_cancel(fAckTimer);
5885*c54f35caSApple OSS Distributions if (pending) {
5886*c54f35caSApple OSS Distributions release();
5887*c54f35caSApple OSS Distributions }
5888*c54f35caSApple OSS Distributions }
5889*c54f35caSApple OSS Distributions
5890*c54f35caSApple OSS Distributions //*********************************************************************************
5891*c54f35caSApple OSS Distributions // [static] actionAckTimerExpired
5892*c54f35caSApple OSS Distributions //
5893*c54f35caSApple OSS Distributions // Inside PM work loop's gate.
5894*c54f35caSApple OSS Distributions //*********************************************************************************
5895*c54f35caSApple OSS Distributions
5896*c54f35caSApple OSS Distributions IOReturn
actionAckTimerExpired(OSObject * target,void * arg0,void * arg1,void * arg2,void * arg3)5897*c54f35caSApple OSS Distributions IOService::actionAckTimerExpired(
5898*c54f35caSApple OSS Distributions OSObject * target,
5899*c54f35caSApple OSS Distributions void * arg0, void * arg1,
5900*c54f35caSApple OSS Distributions void * arg2, void * arg3 )
5901*c54f35caSApple OSS Distributions {
5902*c54f35caSApple OSS Distributions IOService * me = (IOService *) target;
5903*c54f35caSApple OSS Distributions bool done;
5904*c54f35caSApple OSS Distributions
5905*c54f35caSApple OSS Distributions // done will be true if the timer tick unblocks the machine state,
5906*c54f35caSApple OSS Distributions // otherwise no need to signal the work loop.
5907*c54f35caSApple OSS Distributions
5908*c54f35caSApple OSS Distributions done = me->ackTimerTick();
5909*c54f35caSApple OSS Distributions if (done && gIOPMWorkQueue) {
5910*c54f35caSApple OSS Distributions gIOPMWorkQueue->signalWorkAvailable();
5911*c54f35caSApple OSS Distributions }
5912*c54f35caSApple OSS Distributions
5913*c54f35caSApple OSS Distributions return kIOReturnSuccess;
5914*c54f35caSApple OSS Distributions }
5915*c54f35caSApple OSS Distributions
5916*c54f35caSApple OSS Distributions //*********************************************************************************
5917*c54f35caSApple OSS Distributions // ack_timer_expired
5918*c54f35caSApple OSS Distributions //
5919*c54f35caSApple OSS Distributions // Thread call function. Holds a retain while the callout is in flight.
5920*c54f35caSApple OSS Distributions //*********************************************************************************
5921*c54f35caSApple OSS Distributions
5922*c54f35caSApple OSS Distributions void
ack_timer_expired(thread_call_param_t arg0,thread_call_param_t arg1)5923*c54f35caSApple OSS Distributions IOService::ack_timer_expired( thread_call_param_t arg0, thread_call_param_t arg1 )
5924*c54f35caSApple OSS Distributions {
5925*c54f35caSApple OSS Distributions IOService * me = (IOService *) arg0;
5926*c54f35caSApple OSS Distributions
5927*c54f35caSApple OSS Distributions if (gIOPMWorkLoop) {
5928*c54f35caSApple OSS Distributions gIOPMWorkLoop->runAction(&actionAckTimerExpired, me);
5929*c54f35caSApple OSS Distributions }
5930*c54f35caSApple OSS Distributions me->release();
5931*c54f35caSApple OSS Distributions }
5932*c54f35caSApple OSS Distributions
5933*c54f35caSApple OSS Distributions
5934*c54f35caSApple OSS Distributions // MARK: -
5935*c54f35caSApple OSS Distributions // MARK: Client Messaging
5936*c54f35caSApple OSS Distributions
5937*c54f35caSApple OSS Distributions //*********************************************************************************
5938*c54f35caSApple OSS Distributions // [private] tellSystemCapabilityChange
5939*c54f35caSApple OSS Distributions //*********************************************************************************
5940*c54f35caSApple OSS Distributions
5941*c54f35caSApple OSS Distributions void
tellSystemCapabilityChange(uint32_t nextMS)5942*c54f35caSApple OSS Distributions IOService::tellSystemCapabilityChange( uint32_t nextMS )
5943*c54f35caSApple OSS Distributions {
5944*c54f35caSApple OSS Distributions assert(IS_ROOT_DOMAIN);
5945*c54f35caSApple OSS Distributions
5946*c54f35caSApple OSS Distributions MS_PUSH( nextMS );
5947*c54f35caSApple OSS Distributions fMachineState = kIOPM_TellCapabilityChangeDone;
5948*c54f35caSApple OSS Distributions fOutOfBandMessage = kIOMessageSystemCapabilityChange;
5949*c54f35caSApple OSS Distributions
5950*c54f35caSApple OSS Distributions if (fIsPreChange) {
5951*c54f35caSApple OSS Distributions // Notify app first on pre-change.
5952*c54f35caSApple OSS Distributions fOutOfBandParameter = kNotifyCapabilityChangeApps;
5953*c54f35caSApple OSS Distributions } else {
5954*c54f35caSApple OSS Distributions // Notify kernel clients first on post-change.
5955*c54f35caSApple OSS Distributions fOutOfBandParameter = kNotifyCapabilityChangePriority;
5956*c54f35caSApple OSS Distributions }
5957*c54f35caSApple OSS Distributions
5958*c54f35caSApple OSS Distributions tellClientsWithResponse( fOutOfBandMessage );
5959*c54f35caSApple OSS Distributions }
5960*c54f35caSApple OSS Distributions
5961*c54f35caSApple OSS Distributions //*********************************************************************************
5962*c54f35caSApple OSS Distributions // [public] askChangeDown
5963*c54f35caSApple OSS Distributions //
5964*c54f35caSApple OSS Distributions // Ask registered applications and kernel clients if we can change to a lower
5965*c54f35caSApple OSS Distributions // power state.
5966*c54f35caSApple OSS Distributions //
5967*c54f35caSApple OSS Distributions // Subclass can override this to send a different message type. Parameter is
5968*c54f35caSApple OSS Distributions // the destination state number.
5969*c54f35caSApple OSS Distributions //
5970*c54f35caSApple OSS Distributions // Return true if we don't have to wait for acknowledgements
5971*c54f35caSApple OSS Distributions //*********************************************************************************
5972*c54f35caSApple OSS Distributions
5973*c54f35caSApple OSS Distributions bool
askChangeDown(unsigned long stateNum)5974*c54f35caSApple OSS Distributions IOService::askChangeDown( unsigned long stateNum )
5975*c54f35caSApple OSS Distributions {
5976*c54f35caSApple OSS Distributions return tellClientsWithResponse( kIOMessageCanDevicePowerOff );
5977*c54f35caSApple OSS Distributions }
5978*c54f35caSApple OSS Distributions
5979*c54f35caSApple OSS Distributions //*********************************************************************************
5980*c54f35caSApple OSS Distributions // [private] tellChangeDown1
5981*c54f35caSApple OSS Distributions //
5982*c54f35caSApple OSS Distributions // Notify registered applications and kernel clients that we are definitely
5983*c54f35caSApple OSS Distributions // dropping power.
5984*c54f35caSApple OSS Distributions //
5985*c54f35caSApple OSS Distributions // Return true if we don't have to wait for acknowledgements
5986*c54f35caSApple OSS Distributions //*********************************************************************************
5987*c54f35caSApple OSS Distributions
5988*c54f35caSApple OSS Distributions bool
tellChangeDown1(unsigned long stateNum)5989*c54f35caSApple OSS Distributions IOService::tellChangeDown1( unsigned long stateNum )
5990*c54f35caSApple OSS Distributions {
5991*c54f35caSApple OSS Distributions fOutOfBandParameter = kNotifyApps;
5992*c54f35caSApple OSS Distributions return tellChangeDown(stateNum);
5993*c54f35caSApple OSS Distributions }
5994*c54f35caSApple OSS Distributions
5995*c54f35caSApple OSS Distributions //*********************************************************************************
5996*c54f35caSApple OSS Distributions // [private] tellChangeDown2
5997*c54f35caSApple OSS Distributions //
5998*c54f35caSApple OSS Distributions // Notify priority clients that we are definitely dropping power.
5999*c54f35caSApple OSS Distributions //
6000*c54f35caSApple OSS Distributions // Return true if we don't have to wait for acknowledgements
6001*c54f35caSApple OSS Distributions //*********************************************************************************
6002*c54f35caSApple OSS Distributions
6003*c54f35caSApple OSS Distributions bool
tellChangeDown2(unsigned long stateNum)6004*c54f35caSApple OSS Distributions IOService::tellChangeDown2( unsigned long stateNum )
6005*c54f35caSApple OSS Distributions {
6006*c54f35caSApple OSS Distributions fOutOfBandParameter = kNotifyPriority;
6007*c54f35caSApple OSS Distributions return tellChangeDown(stateNum);
6008*c54f35caSApple OSS Distributions }
6009*c54f35caSApple OSS Distributions
6010*c54f35caSApple OSS Distributions //*********************************************************************************
6011*c54f35caSApple OSS Distributions // [public] tellChangeDown
6012*c54f35caSApple OSS Distributions //
6013*c54f35caSApple OSS Distributions // Notify registered applications and kernel clients that we are definitely
6014*c54f35caSApple OSS Distributions // dropping power.
6015*c54f35caSApple OSS Distributions //
6016*c54f35caSApple OSS Distributions // Subclass can override this to send a different message type. Parameter is
6017*c54f35caSApple OSS Distributions // the destination state number.
6018*c54f35caSApple OSS Distributions //
6019*c54f35caSApple OSS Distributions // Return true if we don't have to wait for acknowledgements
6020*c54f35caSApple OSS Distributions //*********************************************************************************
6021*c54f35caSApple OSS Distributions
6022*c54f35caSApple OSS Distributions bool
tellChangeDown(unsigned long stateNum)6023*c54f35caSApple OSS Distributions IOService::tellChangeDown( unsigned long stateNum )
6024*c54f35caSApple OSS Distributions {
6025*c54f35caSApple OSS Distributions return tellClientsWithResponse( kIOMessageDeviceWillPowerOff );
6026*c54f35caSApple OSS Distributions }
6027*c54f35caSApple OSS Distributions
6028*c54f35caSApple OSS Distributions //*********************************************************************************
6029*c54f35caSApple OSS Distributions // cleanClientResponses
6030*c54f35caSApple OSS Distributions //
6031*c54f35caSApple OSS Distributions //*********************************************************************************
6032*c54f35caSApple OSS Distributions
6033*c54f35caSApple OSS Distributions static void
logAppTimeouts(OSObject * object,void * arg)6034*c54f35caSApple OSS Distributions logAppTimeouts( OSObject * object, void * arg )
6035*c54f35caSApple OSS Distributions {
6036*c54f35caSApple OSS Distributions IOPMInterestContext * context = (IOPMInterestContext *) arg;
6037*c54f35caSApple OSS Distributions OSObject * flag;
6038*c54f35caSApple OSS Distributions unsigned int clientIndex;
6039*c54f35caSApple OSS Distributions int pid = 0;
6040*c54f35caSApple OSS Distributions char name[128];
6041*c54f35caSApple OSS Distributions
6042*c54f35caSApple OSS Distributions if (OSDynamicCast(_IOServiceInterestNotifier, object)) {
6043*c54f35caSApple OSS Distributions // Discover the 'counter' value or index assigned to this client
6044*c54f35caSApple OSS Distributions // when it was notified, by searching for the array index of the
6045*c54f35caSApple OSS Distributions // client in an array holding the cached interested clients.
6046*c54f35caSApple OSS Distributions
6047*c54f35caSApple OSS Distributions clientIndex = context->notifyClients->getNextIndexOfObject(object, 0);
6048*c54f35caSApple OSS Distributions
6049*c54f35caSApple OSS Distributions if ((clientIndex != (unsigned int) -1) &&
6050*c54f35caSApple OSS Distributions (flag = context->responseArray->getObject(clientIndex)) &&
6051*c54f35caSApple OSS Distributions (flag != kOSBooleanTrue)) {
6052*c54f35caSApple OSS Distributions OSNumber *clientID = copyClientIDForNotification(object, context);
6053*c54f35caSApple OSS Distributions
6054*c54f35caSApple OSS Distributions name[0] = '\0';
6055*c54f35caSApple OSS Distributions if (clientID) {
6056*c54f35caSApple OSS Distributions pid = clientID->unsigned32BitValue();
6057*c54f35caSApple OSS Distributions proc_name(pid, name, sizeof(name));
6058*c54f35caSApple OSS Distributions clientID->release();
6059*c54f35caSApple OSS Distributions }
6060*c54f35caSApple OSS Distributions
6061*c54f35caSApple OSS Distributions PM_ERROR("PM notification timeout (pid %d, %s)\n", pid, name);
6062*c54f35caSApple OSS Distributions
6063*c54f35caSApple OSS Distributions // TODO: record message type if possible
6064*c54f35caSApple OSS Distributions IOService::getPMRootDomain()->pmStatsRecordApplicationResponse(
6065*c54f35caSApple OSS Distributions gIOPMStatsResponseTimedOut,
6066*c54f35caSApple OSS Distributions name, 0, (30 * 1000), pid, object);
6067*c54f35caSApple OSS Distributions }
6068*c54f35caSApple OSS Distributions }
6069*c54f35caSApple OSS Distributions }
6070*c54f35caSApple OSS Distributions
6071*c54f35caSApple OSS Distributions void
cleanClientResponses(bool logErrors)6072*c54f35caSApple OSS Distributions IOService::cleanClientResponses( bool logErrors )
6073*c54f35caSApple OSS Distributions {
6074*c54f35caSApple OSS Distributions if (logErrors && fResponseArray) {
6075*c54f35caSApple OSS Distributions switch (fOutOfBandParameter) {
6076*c54f35caSApple OSS Distributions case kNotifyApps:
6077*c54f35caSApple OSS Distributions case kNotifyCapabilityChangeApps:
6078*c54f35caSApple OSS Distributions if (fNotifyClientArray) {
6079*c54f35caSApple OSS Distributions IOPMInterestContext context;
6080*c54f35caSApple OSS Distributions
6081*c54f35caSApple OSS Distributions context.responseArray = fResponseArray;
6082*c54f35caSApple OSS Distributions context.notifyClients = fNotifyClientArray;
6083*c54f35caSApple OSS Distributions context.serialNumber = fSerialNumber;
6084*c54f35caSApple OSS Distributions context.messageType = kIOMessageCopyClientID;
6085*c54f35caSApple OSS Distributions context.notifyType = kNotifyApps;
6086*c54f35caSApple OSS Distributions context.isPreChange = fIsPreChange;
6087*c54f35caSApple OSS Distributions context.enableTracing = false;
6088*c54f35caSApple OSS Distributions context.us = this;
6089*c54f35caSApple OSS Distributions context.maxTimeRequested = 0;
6090*c54f35caSApple OSS Distributions context.stateNumber = fHeadNotePowerState;
6091*c54f35caSApple OSS Distributions context.stateFlags = fHeadNotePowerArrayEntry->capabilityFlags;
6092*c54f35caSApple OSS Distributions context.changeFlags = fHeadNoteChangeFlags;
6093*c54f35caSApple OSS Distributions
6094*c54f35caSApple OSS Distributions applyToInterested(gIOAppPowerStateInterest, logAppTimeouts, (void *) &context);
6095*c54f35caSApple OSS Distributions }
6096*c54f35caSApple OSS Distributions break;
6097*c54f35caSApple OSS Distributions
6098*c54f35caSApple OSS Distributions default:
6099*c54f35caSApple OSS Distributions // kNotifyPriority, kNotifyCapabilityChangePriority
6100*c54f35caSApple OSS Distributions // TODO: identify the priority client that has not acked
6101*c54f35caSApple OSS Distributions PM_ERROR("PM priority notification timeout\n");
6102*c54f35caSApple OSS Distributions if (gIOKitDebug & kIOLogDebugPower) {
6103*c54f35caSApple OSS Distributions panic("PM priority notification timeout");
6104*c54f35caSApple OSS Distributions }
6105*c54f35caSApple OSS Distributions break;
6106*c54f35caSApple OSS Distributions }
6107*c54f35caSApple OSS Distributions }
6108*c54f35caSApple OSS Distributions
6109*c54f35caSApple OSS Distributions if (IS_ROOT_DOMAIN) {
6110*c54f35caSApple OSS Distributions getPMRootDomain()->reset_watchdog_timer(this, 0);
6111*c54f35caSApple OSS Distributions }
6112*c54f35caSApple OSS Distributions if (fResponseArray) {
6113*c54f35caSApple OSS Distributions fResponseArray->release();
6114*c54f35caSApple OSS Distributions fResponseArray = NULL;
6115*c54f35caSApple OSS Distributions }
6116*c54f35caSApple OSS Distributions if (fNotifyClientArray) {
6117*c54f35caSApple OSS Distributions fNotifyClientArray->release();
6118*c54f35caSApple OSS Distributions fNotifyClientArray = NULL;
6119*c54f35caSApple OSS Distributions }
6120*c54f35caSApple OSS Distributions }
6121*c54f35caSApple OSS Distributions
6122*c54f35caSApple OSS Distributions //*********************************************************************************
6123*c54f35caSApple OSS Distributions // [protected] tellClientsWithResponse
6124*c54f35caSApple OSS Distributions //
6125*c54f35caSApple OSS Distributions // Notify registered applications and kernel clients that we are definitely
6126*c54f35caSApple OSS Distributions // dropping power.
6127*c54f35caSApple OSS Distributions //
6128*c54f35caSApple OSS Distributions // Return true if we don't have to wait for acknowledgements
6129*c54f35caSApple OSS Distributions //*********************************************************************************
6130*c54f35caSApple OSS Distributions
6131*c54f35caSApple OSS Distributions bool
tellClientsWithResponse(int messageType)6132*c54f35caSApple OSS Distributions IOService::tellClientsWithResponse( int messageType )
6133*c54f35caSApple OSS Distributions {
6134*c54f35caSApple OSS Distributions IOPMInterestContext context;
6135*c54f35caSApple OSS Distributions bool isRootDomain = IS_ROOT_DOMAIN;
6136*c54f35caSApple OSS Distributions uint32_t maxTimeOut = kMaxTimeRequested;
6137*c54f35caSApple OSS Distributions
6138*c54f35caSApple OSS Distributions PM_ASSERT_IN_GATE();
6139*c54f35caSApple OSS Distributions assert( fResponseArray == NULL );
6140*c54f35caSApple OSS Distributions assert( fNotifyClientArray == NULL );
6141*c54f35caSApple OSS Distributions
6142*c54f35caSApple OSS Distributions RD_LOG("tellClientsWithResponse( %s, %s )\n", getIOMessageString(messageType),
6143*c54f35caSApple OSS Distributions getNotificationPhaseString(fOutOfBandParameter));
6144*c54f35caSApple OSS Distributions
6145*c54f35caSApple OSS Distributions fResponseArray = OSArray::withCapacity( 1 );
6146*c54f35caSApple OSS Distributions if (!fResponseArray) {
6147*c54f35caSApple OSS Distributions goto exit;
6148*c54f35caSApple OSS Distributions }
6149*c54f35caSApple OSS Distributions
6150*c54f35caSApple OSS Distributions fResponseArray->setCapacityIncrement(8);
6151*c54f35caSApple OSS Distributions if (++fSerialNumber == 0) {
6152*c54f35caSApple OSS Distributions fSerialNumber++;
6153*c54f35caSApple OSS Distributions }
6154*c54f35caSApple OSS Distributions
6155*c54f35caSApple OSS Distributions context.responseArray = fResponseArray;
6156*c54f35caSApple OSS Distributions context.notifyClients = NULL;
6157*c54f35caSApple OSS Distributions context.serialNumber = fSerialNumber;
6158*c54f35caSApple OSS Distributions context.messageType = messageType;
6159*c54f35caSApple OSS Distributions context.notifyType = fOutOfBandParameter;
6160*c54f35caSApple OSS Distributions context.skippedInDark = 0;
6161*c54f35caSApple OSS Distributions context.notSkippedInDark = 0;
6162*c54f35caSApple OSS Distributions context.isPreChange = fIsPreChange;
6163*c54f35caSApple OSS Distributions context.enableTracing = false;
6164*c54f35caSApple OSS Distributions context.us = this;
6165*c54f35caSApple OSS Distributions context.maxTimeRequested = 0;
6166*c54f35caSApple OSS Distributions context.stateNumber = fHeadNotePowerState;
6167*c54f35caSApple OSS Distributions context.stateFlags = fHeadNotePowerArrayEntry->capabilityFlags;
6168*c54f35caSApple OSS Distributions context.changeFlags = fHeadNoteChangeFlags;
6169*c54f35caSApple OSS Distributions context.messageFilter = (isRootDomain) ?
6170*c54f35caSApple OSS Distributions OSMemberFunctionCast(
6171*c54f35caSApple OSS Distributions IOPMMessageFilter,
6172*c54f35caSApple OSS Distributions (IOPMrootDomain *)this,
6173*c54f35caSApple OSS Distributions &IOPMrootDomain::systemMessageFilter) : NULL;
6174*c54f35caSApple OSS Distributions
6175*c54f35caSApple OSS Distributions switch (fOutOfBandParameter) {
6176*c54f35caSApple OSS Distributions case kNotifyApps:
6177*c54f35caSApple OSS Distributions applyToInterested( gIOAppPowerStateInterest,
6178*c54f35caSApple OSS Distributions pmTellAppWithResponse, (void *) &context );
6179*c54f35caSApple OSS Distributions
6180*c54f35caSApple OSS Distributions if (isRootDomain &&
6181*c54f35caSApple OSS Distributions (fMachineState != kIOPM_OurChangeTellClientsPowerDown) &&
6182*c54f35caSApple OSS Distributions (fMachineState != kIOPM_SyncTellClientsPowerDown) &&
6183*c54f35caSApple OSS Distributions (context.messageType != kIOPMMessageLastCallBeforeSleep)) {
6184*c54f35caSApple OSS Distributions // Notify capability app for tellChangeDown1()
6185*c54f35caSApple OSS Distributions // but not for askChangeDown().
6186*c54f35caSApple OSS Distributions context.notifyType = kNotifyCapabilityChangeApps;
6187*c54f35caSApple OSS Distributions context.messageType = kIOMessageSystemCapabilityChange;
6188*c54f35caSApple OSS Distributions applyToInterested( gIOAppPowerStateInterest,
6189*c54f35caSApple OSS Distributions pmTellCapabilityAppWithResponse, (void *) &context );
6190*c54f35caSApple OSS Distributions context.notifyType = fOutOfBandParameter;
6191*c54f35caSApple OSS Distributions context.messageType = messageType;
6192*c54f35caSApple OSS Distributions }
6193*c54f35caSApple OSS Distributions if (context.messageType == kIOMessageCanSystemSleep) {
6194*c54f35caSApple OSS Distributions maxTimeOut = kCanSleepMaxTimeReq;
6195*c54f35caSApple OSS Distributions if (gSleepAckTimeout) {
6196*c54f35caSApple OSS Distributions maxTimeOut = (gSleepAckTimeout * us_per_s);
6197*c54f35caSApple OSS Distributions }
6198*c54f35caSApple OSS Distributions }
6199*c54f35caSApple OSS Distributions if (context.messageType == kIOMessageSystemWillSleep) {
6200*c54f35caSApple OSS Distributions maxTimeOut = kWillSleepMaxTimeReq;
6201*c54f35caSApple OSS Distributions if (gSleepAckTimeout) {
6202*c54f35caSApple OSS Distributions maxTimeOut = (gSleepAckTimeout * us_per_s);
6203*c54f35caSApple OSS Distributions }
6204*c54f35caSApple OSS Distributions }
6205*c54f35caSApple OSS Distributions context.maxTimeRequested = maxTimeOut;
6206*c54f35caSApple OSS Distributions context.enableTracing = isRootDomain;
6207*c54f35caSApple OSS Distributions applyToInterested( gIOGeneralInterest,
6208*c54f35caSApple OSS Distributions pmTellClientWithResponse, (void *) &context );
6209*c54f35caSApple OSS Distributions
6210*c54f35caSApple OSS Distributions break;
6211*c54f35caSApple OSS Distributions
6212*c54f35caSApple OSS Distributions case kNotifyPriority:
6213*c54f35caSApple OSS Distributions context.enableTracing = isRootDomain;
6214*c54f35caSApple OSS Distributions applyToInterested( gIOPriorityPowerStateInterest,
6215*c54f35caSApple OSS Distributions pmTellClientWithResponse, (void *) &context );
6216*c54f35caSApple OSS Distributions
6217*c54f35caSApple OSS Distributions if (isRootDomain) {
6218*c54f35caSApple OSS Distributions // Notify capability clients for tellChangeDown2().
6219*c54f35caSApple OSS Distributions context.notifyType = kNotifyCapabilityChangePriority;
6220*c54f35caSApple OSS Distributions context.messageType = kIOMessageSystemCapabilityChange;
6221*c54f35caSApple OSS Distributions applyToInterested( gIOPriorityPowerStateInterest,
6222*c54f35caSApple OSS Distributions pmTellCapabilityClientWithResponse, (void *) &context );
6223*c54f35caSApple OSS Distributions }
6224*c54f35caSApple OSS Distributions break;
6225*c54f35caSApple OSS Distributions
6226*c54f35caSApple OSS Distributions case kNotifyCapabilityChangeApps:
6227*c54f35caSApple OSS Distributions context.enableTracing = isRootDomain;
6228*c54f35caSApple OSS Distributions applyToInterested( gIOAppPowerStateInterest,
6229*c54f35caSApple OSS Distributions pmTellCapabilityAppWithResponse, (void *) &context );
6230*c54f35caSApple OSS Distributions if (context.messageType == kIOMessageCanSystemSleep) {
6231*c54f35caSApple OSS Distributions maxTimeOut = kCanSleepMaxTimeReq;
6232*c54f35caSApple OSS Distributions if (gSleepAckTimeout) {
6233*c54f35caSApple OSS Distributions maxTimeOut = (gSleepAckTimeout * us_per_s);
6234*c54f35caSApple OSS Distributions }
6235*c54f35caSApple OSS Distributions }
6236*c54f35caSApple OSS Distributions context.maxTimeRequested = maxTimeOut;
6237*c54f35caSApple OSS Distributions break;
6238*c54f35caSApple OSS Distributions
6239*c54f35caSApple OSS Distributions case kNotifyCapabilityChangePriority:
6240*c54f35caSApple OSS Distributions context.enableTracing = isRootDomain;
6241*c54f35caSApple OSS Distributions applyToInterested( gIOPriorityPowerStateInterest,
6242*c54f35caSApple OSS Distributions pmTellCapabilityClientWithResponse, (void *) &context );
6243*c54f35caSApple OSS Distributions break;
6244*c54f35caSApple OSS Distributions }
6245*c54f35caSApple OSS Distributions fNotifyClientArray = context.notifyClients;
6246*c54f35caSApple OSS Distributions
6247*c54f35caSApple OSS Distributions if (context.skippedInDark) {
6248*c54f35caSApple OSS Distributions IOLog("tellClientsWithResponse(%s, %s) %d of %d skipped in dark\n",
6249*c54f35caSApple OSS Distributions getIOMessageString(messageType), getNotificationPhaseString(fOutOfBandParameter),
6250*c54f35caSApple OSS Distributions context.skippedInDark, context.skippedInDark + context.notSkippedInDark);
6251*c54f35caSApple OSS Distributions }
6252*c54f35caSApple OSS Distributions
6253*c54f35caSApple OSS Distributions // do we have to wait for somebody?
6254*c54f35caSApple OSS Distributions if (!checkForDone()) {
6255*c54f35caSApple OSS Distributions OUR_PMLog(kPMLogStartAckTimer, context.maxTimeRequested, 0);
6256*c54f35caSApple OSS Distributions if (context.enableTracing) {
6257*c54f35caSApple OSS Distributions getPMRootDomain()->traceDetail(context.messageType, 0, context.maxTimeRequested / 1000);
6258*c54f35caSApple OSS Distributions getPMRootDomain()->reset_watchdog_timer(this, context.maxTimeRequested / USEC_PER_SEC + 1);
6259*c54f35caSApple OSS Distributions }
6260*c54f35caSApple OSS Distributions start_ack_timer( context.maxTimeRequested / 1000, kMillisecondScale );
6261*c54f35caSApple OSS Distributions return false;
6262*c54f35caSApple OSS Distributions }
6263*c54f35caSApple OSS Distributions
6264*c54f35caSApple OSS Distributions exit:
6265*c54f35caSApple OSS Distributions // everybody responded
6266*c54f35caSApple OSS Distributions if (fResponseArray) {
6267*c54f35caSApple OSS Distributions fResponseArray->release();
6268*c54f35caSApple OSS Distributions fResponseArray = NULL;
6269*c54f35caSApple OSS Distributions }
6270*c54f35caSApple OSS Distributions if (fNotifyClientArray) {
6271*c54f35caSApple OSS Distributions fNotifyClientArray->release();
6272*c54f35caSApple OSS Distributions fNotifyClientArray = NULL;
6273*c54f35caSApple OSS Distributions }
6274*c54f35caSApple OSS Distributions
6275*c54f35caSApple OSS Distributions return true;
6276*c54f35caSApple OSS Distributions }
6277*c54f35caSApple OSS Distributions
6278*c54f35caSApple OSS Distributions //*********************************************************************************
6279*c54f35caSApple OSS Distributions // [static private] pmTellAppWithResponse
6280*c54f35caSApple OSS Distributions //
6281*c54f35caSApple OSS Distributions // We send a message to an application, and we expect a response, so we compute a
6282*c54f35caSApple OSS Distributions // cookie we can identify the response with.
6283*c54f35caSApple OSS Distributions //*********************************************************************************
6284*c54f35caSApple OSS Distributions
6285*c54f35caSApple OSS Distributions void
pmTellAppWithResponse(OSObject * object,void * arg)6286*c54f35caSApple OSS Distributions IOService::pmTellAppWithResponse( OSObject * object, void * arg )
6287*c54f35caSApple OSS Distributions {
6288*c54f35caSApple OSS Distributions IOPMInterestContext * context = (IOPMInterestContext *) arg;
6289*c54f35caSApple OSS Distributions IOServicePM * pwrMgt = context->us->pwrMgt;
6290*c54f35caSApple OSS Distributions uint32_t msgIndex, msgRef, msgType;
6291*c54f35caSApple OSS Distributions OSNumber *clientID = NULL;
6292*c54f35caSApple OSS Distributions proc_t proc = NULL;
6293*c54f35caSApple OSS Distributions boolean_t proc_suspended = FALSE;
6294*c54f35caSApple OSS Distributions OSObject * waitForReply = kOSBooleanTrue;
6295*c54f35caSApple OSS Distributions #if LOG_APP_RESPONSE_TIMES
6296*c54f35caSApple OSS Distributions AbsoluteTime now;
6297*c54f35caSApple OSS Distributions #endif
6298*c54f35caSApple OSS Distributions
6299*c54f35caSApple OSS Distributions if (!OSDynamicCast(_IOServiceInterestNotifier, object)) {
6300*c54f35caSApple OSS Distributions return;
6301*c54f35caSApple OSS Distributions }
6302*c54f35caSApple OSS Distributions
6303*c54f35caSApple OSS Distributions if (context->us == getPMRootDomain()) {
6304*c54f35caSApple OSS Distributions if ((clientID = copyClientIDForNotification(object, context))) {
6305*c54f35caSApple OSS Distributions uint32_t clientPID = clientID->unsigned32BitValue();
6306*c54f35caSApple OSS Distributions clientID->release();
6307*c54f35caSApple OSS Distributions proc = proc_find(clientPID);
6308*c54f35caSApple OSS Distributions
6309*c54f35caSApple OSS Distributions if (proc) {
6310*c54f35caSApple OSS Distributions proc_suspended = get_task_pidsuspended((task_t) proc_task(proc));
6311*c54f35caSApple OSS Distributions if (proc_suspended) {
6312*c54f35caSApple OSS Distributions logClientIDForNotification(object, context, "PMTellAppWithResponse - Suspended");
6313*c54f35caSApple OSS Distributions } else if (getPMRootDomain()->isAOTMode() && get_task_suspended((task_t) proc_task(proc))) {
6314*c54f35caSApple OSS Distributions proc_suspended = true;
6315*c54f35caSApple OSS Distributions context->skippedInDark++;
6316*c54f35caSApple OSS Distributions }
6317*c54f35caSApple OSS Distributions proc_rele(proc);
6318*c54f35caSApple OSS Distributions if (proc_suspended) {
6319*c54f35caSApple OSS Distributions return;
6320*c54f35caSApple OSS Distributions }
6321*c54f35caSApple OSS Distributions }
6322*c54f35caSApple OSS Distributions }
6323*c54f35caSApple OSS Distributions }
6324*c54f35caSApple OSS Distributions
6325*c54f35caSApple OSS Distributions if (context->messageFilter &&
6326*c54f35caSApple OSS Distributions !context->messageFilter(context->us, object, context, NULL, &waitForReply)) {
6327*c54f35caSApple OSS Distributions if (kIOLogDebugPower & gIOKitDebug) {
6328*c54f35caSApple OSS Distributions logClientIDForNotification(object, context, "DROP App");
6329*c54f35caSApple OSS Distributions }
6330*c54f35caSApple OSS Distributions return;
6331*c54f35caSApple OSS Distributions }
6332*c54f35caSApple OSS Distributions context->notSkippedInDark++;
6333*c54f35caSApple OSS Distributions
6334*c54f35caSApple OSS Distributions // Create client array (for tracking purposes) only if the service
6335*c54f35caSApple OSS Distributions // has app clients. Usually only root domain does.
6336*c54f35caSApple OSS Distributions if (NULL == context->notifyClients) {
6337*c54f35caSApple OSS Distributions context->notifyClients = OSArray::withCapacity( 32 );
6338*c54f35caSApple OSS Distributions }
6339*c54f35caSApple OSS Distributions
6340*c54f35caSApple OSS Distributions msgType = context->messageType;
6341*c54f35caSApple OSS Distributions msgIndex = context->responseArray->getCount();
6342*c54f35caSApple OSS Distributions msgRef = ((context->serialNumber & 0xFFFF) << 16) + (msgIndex & 0xFFFF);
6343*c54f35caSApple OSS Distributions
6344*c54f35caSApple OSS Distributions OUR_PMLog(kPMLogAppNotify, msgType, msgRef);
6345*c54f35caSApple OSS Distributions if (kIOLogDebugPower & gIOKitDebug) {
6346*c54f35caSApple OSS Distributions logClientIDForNotification(object, context, "MESG App");
6347*c54f35caSApple OSS Distributions }
6348*c54f35caSApple OSS Distributions
6349*c54f35caSApple OSS Distributions if (waitForReply == kOSBooleanTrue) {
6350*c54f35caSApple OSS Distributions OSNumber * num;
6351*c54f35caSApple OSS Distributions clock_get_uptime(&now);
6352*c54f35caSApple OSS Distributions num = OSNumber::withNumber(AbsoluteTime_to_scalar(&now), sizeof(uint64_t) * 8);
6353*c54f35caSApple OSS Distributions if (num) {
6354*c54f35caSApple OSS Distributions context->responseArray->setObject(msgIndex, num);
6355*c54f35caSApple OSS Distributions num->release();
6356*c54f35caSApple OSS Distributions } else {
6357*c54f35caSApple OSS Distributions context->responseArray->setObject(msgIndex, kOSBooleanFalse);
6358*c54f35caSApple OSS Distributions }
6359*c54f35caSApple OSS Distributions } else {
6360*c54f35caSApple OSS Distributions context->responseArray->setObject(msgIndex, kOSBooleanTrue);
6361*c54f35caSApple OSS Distributions if (kIOLogDebugPower & gIOKitDebug) {
6362*c54f35caSApple OSS Distributions logClientIDForNotification(object, context, "App response ignored");
6363*c54f35caSApple OSS Distributions }
6364*c54f35caSApple OSS Distributions }
6365*c54f35caSApple OSS Distributions
6366*c54f35caSApple OSS Distributions if (context->notifyClients) {
6367*c54f35caSApple OSS Distributions context->notifyClients->setObject(msgIndex, object);
6368*c54f35caSApple OSS Distributions }
6369*c54f35caSApple OSS Distributions
6370*c54f35caSApple OSS Distributions context->us->messageClient(msgType, object, (void *)(uintptr_t) msgRef);
6371*c54f35caSApple OSS Distributions }
6372*c54f35caSApple OSS Distributions
6373*c54f35caSApple OSS Distributions //*********************************************************************************
6374*c54f35caSApple OSS Distributions // [static private] pmTellClientWithResponse
6375*c54f35caSApple OSS Distributions //
6376*c54f35caSApple OSS Distributions // We send a message to an in-kernel client, and we expect a response,
6377*c54f35caSApple OSS Distributions // so we compute a cookie we can identify the response with.
6378*c54f35caSApple OSS Distributions //*********************************************************************************
6379*c54f35caSApple OSS Distributions
6380*c54f35caSApple OSS Distributions void
pmTellClientWithResponse(OSObject * object,void * arg)6381*c54f35caSApple OSS Distributions IOService::pmTellClientWithResponse( OSObject * object, void * arg )
6382*c54f35caSApple OSS Distributions {
6383*c54f35caSApple OSS Distributions IOPowerStateChangeNotification notify;
6384*c54f35caSApple OSS Distributions IOPMInterestContext * context = (IOPMInterestContext *) arg;
6385*c54f35caSApple OSS Distributions OSObject * replied = kOSBooleanTrue;
6386*c54f35caSApple OSS Distributions _IOServiceInterestNotifier * notifier;
6387*c54f35caSApple OSS Distributions uint32_t msgIndex, msgRef, msgType;
6388*c54f35caSApple OSS Distributions IOReturn retCode;
6389*c54f35caSApple OSS Distributions AbsoluteTime start, end;
6390*c54f35caSApple OSS Distributions uint64_t nsec;
6391*c54f35caSApple OSS Distributions bool enableTracing;
6392*c54f35caSApple OSS Distributions
6393*c54f35caSApple OSS Distributions if (context->messageFilter &&
6394*c54f35caSApple OSS Distributions !context->messageFilter(context->us, object, context, NULL, NULL)) {
6395*c54f35caSApple OSS Distributions getPMRootDomain()->traceFilteredNotification(object);
6396*c54f35caSApple OSS Distributions return;
6397*c54f35caSApple OSS Distributions }
6398*c54f35caSApple OSS Distributions
6399*c54f35caSApple OSS Distributions // Besides interest notifiers this applier function can also be invoked against
6400*c54f35caSApple OSS Distributions // IOService clients of context->us, so notifier can be NULL. But for tracing
6401*c54f35caSApple OSS Distributions // purposes the IOService clients can be ignored but each will still consume
6402*c54f35caSApple OSS Distributions // an entry in the responseArray and also advance msgIndex.
6403*c54f35caSApple OSS Distributions notifier = OSDynamicCast(_IOServiceInterestNotifier, object);
6404*c54f35caSApple OSS Distributions msgType = context->messageType;
6405*c54f35caSApple OSS Distributions msgIndex = context->responseArray->getCount();
6406*c54f35caSApple OSS Distributions msgRef = ((context->serialNumber & 0xFFFF) << 16) + (msgIndex & 0xFFFF);
6407*c54f35caSApple OSS Distributions enableTracing = context->enableTracing && (notifier != NULL);
6408*c54f35caSApple OSS Distributions
6409*c54f35caSApple OSS Distributions IOServicePM * pwrMgt = context->us->pwrMgt;
6410*c54f35caSApple OSS Distributions if (gIOKitDebug & kIOLogPower) {
6411*c54f35caSApple OSS Distributions OUR_PMLog(kPMLogClientNotify, msgRef, msgType);
6412*c54f35caSApple OSS Distributions if (OSDynamicCast(IOService, object)) {
6413*c54f35caSApple OSS Distributions const char *who = ((IOService *) object)->getName();
6414*c54f35caSApple OSS Distributions gPlatform->PMLog(who, kPMLogClientNotify, (uintptr_t) object, 0);
6415*c54f35caSApple OSS Distributions } else if (notifier) {
6416*c54f35caSApple OSS Distributions OUR_PMLog(kPMLogClientNotify, (uintptr_t) notifier->handler, 0);
6417*c54f35caSApple OSS Distributions }
6418*c54f35caSApple OSS Distributions }
6419*c54f35caSApple OSS Distributions
6420*c54f35caSApple OSS Distributions if (NULL == context->notifyClients) {
6421*c54f35caSApple OSS Distributions context->notifyClients = OSArray::withCapacity(32);
6422*c54f35caSApple OSS Distributions assert(context->notifyClients != NULL);
6423*c54f35caSApple OSS Distributions }
6424*c54f35caSApple OSS Distributions
6425*c54f35caSApple OSS Distributions notify.powerRef = (void *)(uintptr_t) msgRef;
6426*c54f35caSApple OSS Distributions notify.returnValue = 0;
6427*c54f35caSApple OSS Distributions notify.stateNumber = context->stateNumber;
6428*c54f35caSApple OSS Distributions notify.stateFlags = context->stateFlags;
6429*c54f35caSApple OSS Distributions
6430*c54f35caSApple OSS Distributions clock_get_uptime(&start);
6431*c54f35caSApple OSS Distributions if (enableTracing) {
6432*c54f35caSApple OSS Distributions getPMRootDomain()->traceNotification(notifier, true, start, msgIndex);
6433*c54f35caSApple OSS Distributions }
6434*c54f35caSApple OSS Distributions
6435*c54f35caSApple OSS Distributions retCode = context->us->messageClient(msgType, object, (void *) ¬ify, sizeof(notify));
6436*c54f35caSApple OSS Distributions
6437*c54f35caSApple OSS Distributions clock_get_uptime(&end);
6438*c54f35caSApple OSS Distributions if (enableTracing) {
6439*c54f35caSApple OSS Distributions getPMRootDomain()->traceNotification(notifier, false, end);
6440*c54f35caSApple OSS Distributions }
6441*c54f35caSApple OSS Distributions
6442*c54f35caSApple OSS Distributions if (kIOReturnSuccess == retCode) {
6443*c54f35caSApple OSS Distributions if (0 == notify.returnValue) {
6444*c54f35caSApple OSS Distributions OUR_PMLog(kPMLogClientAcknowledge, msgRef, (uintptr_t) object);
6445*c54f35caSApple OSS Distributions context->responseArray->setObject(msgIndex, replied);
6446*c54f35caSApple OSS Distributions } else {
6447*c54f35caSApple OSS Distributions replied = kOSBooleanFalse;
6448*c54f35caSApple OSS Distributions if (notify.returnValue > context->maxTimeRequested) {
6449*c54f35caSApple OSS Distributions if (notify.returnValue > kPriorityClientMaxWait) {
6450*c54f35caSApple OSS Distributions context->maxTimeRequested = kPriorityClientMaxWait;
6451*c54f35caSApple OSS Distributions PM_ERROR("%s: client %p returned %llu for %s\n",
6452*c54f35caSApple OSS Distributions context->us->getName(),
6453*c54f35caSApple OSS Distributions notifier ? (void *) OBFUSCATE(notifier->handler) : OBFUSCATE(object),
6454*c54f35caSApple OSS Distributions (uint64_t) notify.returnValue,
6455*c54f35caSApple OSS Distributions getIOMessageString(msgType));
6456*c54f35caSApple OSS Distributions } else {
6457*c54f35caSApple OSS Distributions context->maxTimeRequested = (typeof(context->maxTimeRequested))notify.returnValue;
6458*c54f35caSApple OSS Distributions }
6459*c54f35caSApple OSS Distributions }
6460*c54f35caSApple OSS Distributions //
6461*c54f35caSApple OSS Distributions // Track time taken to ack, by storing the timestamp of
6462*c54f35caSApple OSS Distributions // callback completion
6463*c54f35caSApple OSS Distributions OSNumber * num;
6464*c54f35caSApple OSS Distributions num = OSNumber::withNumber(AbsoluteTime_to_scalar(&end), sizeof(uint64_t) * 8);
6465*c54f35caSApple OSS Distributions if (num) {
6466*c54f35caSApple OSS Distributions context->responseArray->setObject(msgIndex, num);
6467*c54f35caSApple OSS Distributions num->release();
6468*c54f35caSApple OSS Distributions } else {
6469*c54f35caSApple OSS Distributions context->responseArray->setObject(msgIndex, replied);
6470*c54f35caSApple OSS Distributions }
6471*c54f35caSApple OSS Distributions }
6472*c54f35caSApple OSS Distributions
6473*c54f35caSApple OSS Distributions if (enableTracing) {
6474*c54f35caSApple OSS Distributions SUB_ABSOLUTETIME(&end, &start);
6475*c54f35caSApple OSS Distributions absolutetime_to_nanoseconds(end, &nsec);
6476*c54f35caSApple OSS Distributions
6477*c54f35caSApple OSS Distributions if ((nsec > LOG_KEXT_RESPONSE_TIMES) || (notify.returnValue != 0)) {
6478*c54f35caSApple OSS Distributions getPMRootDomain()->traceNotificationResponse(notifier, NS_TO_MS(nsec), (uint32_t) notify.returnValue);
6479*c54f35caSApple OSS Distributions }
6480*c54f35caSApple OSS Distributions }
6481*c54f35caSApple OSS Distributions } else {
6482*c54f35caSApple OSS Distributions // not a client of ours
6483*c54f35caSApple OSS Distributions // so we won't be waiting for response
6484*c54f35caSApple OSS Distributions OUR_PMLog(kPMLogClientAcknowledge, msgRef, 0);
6485*c54f35caSApple OSS Distributions context->responseArray->setObject(msgIndex, replied);
6486*c54f35caSApple OSS Distributions }
6487*c54f35caSApple OSS Distributions if (context->notifyClients) {
6488*c54f35caSApple OSS Distributions context->notifyClients->setObject(msgIndex, object);
6489*c54f35caSApple OSS Distributions }
6490*c54f35caSApple OSS Distributions }
6491*c54f35caSApple OSS Distributions
6492*c54f35caSApple OSS Distributions //*********************************************************************************
6493*c54f35caSApple OSS Distributions // [static private] pmTellCapabilityAppWithResponse
6494*c54f35caSApple OSS Distributions //*********************************************************************************
6495*c54f35caSApple OSS Distributions
6496*c54f35caSApple OSS Distributions void
pmTellCapabilityAppWithResponse(OSObject * object,void * arg)6497*c54f35caSApple OSS Distributions IOService::pmTellCapabilityAppWithResponse( OSObject * object, void * arg )
6498*c54f35caSApple OSS Distributions {
6499*c54f35caSApple OSS Distributions IOPMSystemCapabilityChangeParameters msgArg;
6500*c54f35caSApple OSS Distributions IOPMInterestContext * context = (IOPMInterestContext *) arg;
6501*c54f35caSApple OSS Distributions OSObject * waitForReply = kOSBooleanFalse;
6502*c54f35caSApple OSS Distributions IOServicePM * pwrMgt = context->us->pwrMgt;
6503*c54f35caSApple OSS Distributions uint32_t msgIndex, msgRef, msgType;
6504*c54f35caSApple OSS Distributions #if LOG_APP_RESPONSE_TIMES
6505*c54f35caSApple OSS Distributions AbsoluteTime now;
6506*c54f35caSApple OSS Distributions #endif
6507*c54f35caSApple OSS Distributions
6508*c54f35caSApple OSS Distributions if (!OSDynamicCast(_IOServiceInterestNotifier, object)) {
6509*c54f35caSApple OSS Distributions return;
6510*c54f35caSApple OSS Distributions }
6511*c54f35caSApple OSS Distributions
6512*c54f35caSApple OSS Distributions memset(&msgArg, 0, sizeof(msgArg));
6513*c54f35caSApple OSS Distributions if (context->messageFilter &&
6514*c54f35caSApple OSS Distributions !context->messageFilter(context->us, object, context, &msgArg, &waitForReply)) {
6515*c54f35caSApple OSS Distributions return;
6516*c54f35caSApple OSS Distributions }
6517*c54f35caSApple OSS Distributions
6518*c54f35caSApple OSS Distributions if (context->us == getPMRootDomain() &&
6519*c54f35caSApple OSS Distributions getPMRootDomain()->isAOTMode()
6520*c54f35caSApple OSS Distributions ) {
6521*c54f35caSApple OSS Distributions OSNumber *clientID = NULL;
6522*c54f35caSApple OSS Distributions boolean_t proc_suspended = FALSE;
6523*c54f35caSApple OSS Distributions proc_t proc = NULL;
6524*c54f35caSApple OSS Distributions if ((clientID = copyClientIDForNotification(object, context))) {
6525*c54f35caSApple OSS Distributions uint32_t clientPID = clientID->unsigned32BitValue();
6526*c54f35caSApple OSS Distributions clientID->release();
6527*c54f35caSApple OSS Distributions proc = proc_find(clientPID);
6528*c54f35caSApple OSS Distributions if (proc) {
6529*c54f35caSApple OSS Distributions proc_suspended = get_task_pidsuspended((task_t) proc_task(proc));
6530*c54f35caSApple OSS Distributions if (proc_suspended) {
6531*c54f35caSApple OSS Distributions logClientIDForNotification(object, context, "PMTellCapablityAppWithResponse - Suspended");
6532*c54f35caSApple OSS Distributions } else if (get_task_suspended((task_t) proc_task(proc))) {
6533*c54f35caSApple OSS Distributions proc_suspended = true;
6534*c54f35caSApple OSS Distributions context->skippedInDark++;
6535*c54f35caSApple OSS Distributions }
6536*c54f35caSApple OSS Distributions proc_rele(proc);
6537*c54f35caSApple OSS Distributions if (proc_suspended) {
6538*c54f35caSApple OSS Distributions return;
6539*c54f35caSApple OSS Distributions }
6540*c54f35caSApple OSS Distributions }
6541*c54f35caSApple OSS Distributions }
6542*c54f35caSApple OSS Distributions }
6543*c54f35caSApple OSS Distributions context->notSkippedInDark++;
6544*c54f35caSApple OSS Distributions
6545*c54f35caSApple OSS Distributions // Create client array (for tracking purposes) only if the service
6546*c54f35caSApple OSS Distributions // has app clients. Usually only root domain does.
6547*c54f35caSApple OSS Distributions if (NULL == context->notifyClients) {
6548*c54f35caSApple OSS Distributions context->notifyClients = OSArray::withCapacity(32);
6549*c54f35caSApple OSS Distributions assert(context->notifyClients != NULL);
6550*c54f35caSApple OSS Distributions }
6551*c54f35caSApple OSS Distributions
6552*c54f35caSApple OSS Distributions msgType = context->messageType;
6553*c54f35caSApple OSS Distributions msgIndex = context->responseArray->getCount();
6554*c54f35caSApple OSS Distributions msgRef = ((context->serialNumber & 0xFFFF) << 16) + (msgIndex & 0xFFFF);
6555*c54f35caSApple OSS Distributions
6556*c54f35caSApple OSS Distributions OUR_PMLog(kPMLogAppNotify, msgType, msgRef);
6557*c54f35caSApple OSS Distributions if (kIOLogDebugPower & gIOKitDebug) {
6558*c54f35caSApple OSS Distributions // Log client pid/name and client array index.
6559*c54f35caSApple OSS Distributions OSNumber * clientID = NULL;
6560*c54f35caSApple OSS Distributions OSString * clientIDString = NULL;
6561*c54f35caSApple OSS Distributions context->us->messageClient(kIOMessageCopyClientID, object, &clientID);
6562*c54f35caSApple OSS Distributions if (clientID) {
6563*c54f35caSApple OSS Distributions clientIDString = IOCopyLogNameForPID(clientID->unsigned32BitValue());
6564*c54f35caSApple OSS Distributions }
6565*c54f35caSApple OSS Distributions
6566*c54f35caSApple OSS Distributions PM_LOG("%s MESG App(%u) %s, wait %u, %s\n",
6567*c54f35caSApple OSS Distributions context->us->getName(),
6568*c54f35caSApple OSS Distributions msgIndex, getIOMessageString(msgType),
6569*c54f35caSApple OSS Distributions (waitForReply == kOSBooleanTrue),
6570*c54f35caSApple OSS Distributions clientIDString ? clientIDString->getCStringNoCopy() : "");
6571*c54f35caSApple OSS Distributions if (clientID) {
6572*c54f35caSApple OSS Distributions clientID->release();
6573*c54f35caSApple OSS Distributions }
6574*c54f35caSApple OSS Distributions if (clientIDString) {
6575*c54f35caSApple OSS Distributions clientIDString->release();
6576*c54f35caSApple OSS Distributions }
6577*c54f35caSApple OSS Distributions }
6578*c54f35caSApple OSS Distributions
6579*c54f35caSApple OSS Distributions msgArg.notifyRef = msgRef;
6580*c54f35caSApple OSS Distributions msgArg.maxWaitForReply = 0;
6581*c54f35caSApple OSS Distributions
6582*c54f35caSApple OSS Distributions if (waitForReply == kOSBooleanFalse) {
6583*c54f35caSApple OSS Distributions msgArg.notifyRef = 0;
6584*c54f35caSApple OSS Distributions context->responseArray->setObject(msgIndex, kOSBooleanTrue);
6585*c54f35caSApple OSS Distributions if (context->notifyClients) {
6586*c54f35caSApple OSS Distributions context->notifyClients->setObject(msgIndex, kOSBooleanTrue);
6587*c54f35caSApple OSS Distributions }
6588*c54f35caSApple OSS Distributions } else {
6589*c54f35caSApple OSS Distributions OSNumber * num;
6590*c54f35caSApple OSS Distributions clock_get_uptime(&now);
6591*c54f35caSApple OSS Distributions num = OSNumber::withNumber(AbsoluteTime_to_scalar(&now), sizeof(uint64_t) * 8);
6592*c54f35caSApple OSS Distributions if (num) {
6593*c54f35caSApple OSS Distributions context->responseArray->setObject(msgIndex, num);
6594*c54f35caSApple OSS Distributions num->release();
6595*c54f35caSApple OSS Distributions } else {
6596*c54f35caSApple OSS Distributions context->responseArray->setObject(msgIndex, kOSBooleanFalse);
6597*c54f35caSApple OSS Distributions }
6598*c54f35caSApple OSS Distributions
6599*c54f35caSApple OSS Distributions if (context->notifyClients) {
6600*c54f35caSApple OSS Distributions context->notifyClients->setObject(msgIndex, object);
6601*c54f35caSApple OSS Distributions }
6602*c54f35caSApple OSS Distributions }
6603*c54f35caSApple OSS Distributions
6604*c54f35caSApple OSS Distributions context->us->messageClient(msgType, object, (void *) &msgArg, sizeof(msgArg));
6605*c54f35caSApple OSS Distributions }
6606*c54f35caSApple OSS Distributions
6607*c54f35caSApple OSS Distributions //*********************************************************************************
6608*c54f35caSApple OSS Distributions // [static private] pmTellCapabilityClientWithResponse
6609*c54f35caSApple OSS Distributions //*********************************************************************************
6610*c54f35caSApple OSS Distributions
6611*c54f35caSApple OSS Distributions void
pmTellCapabilityClientWithResponse(OSObject * object,void * arg)6612*c54f35caSApple OSS Distributions IOService::pmTellCapabilityClientWithResponse(
6613*c54f35caSApple OSS Distributions OSObject * object, void * arg )
6614*c54f35caSApple OSS Distributions {
6615*c54f35caSApple OSS Distributions IOPMSystemCapabilityChangeParameters msgArg;
6616*c54f35caSApple OSS Distributions IOPMInterestContext * context = (IOPMInterestContext *) arg;
6617*c54f35caSApple OSS Distributions OSObject * replied = kOSBooleanTrue;
6618*c54f35caSApple OSS Distributions _IOServiceInterestNotifier * notifier;
6619*c54f35caSApple OSS Distributions uint32_t msgIndex, msgRef, msgType;
6620*c54f35caSApple OSS Distributions IOReturn retCode;
6621*c54f35caSApple OSS Distributions AbsoluteTime start, end;
6622*c54f35caSApple OSS Distributions uint64_t nsec;
6623*c54f35caSApple OSS Distributions bool enableTracing;
6624*c54f35caSApple OSS Distributions
6625*c54f35caSApple OSS Distributions memset(&msgArg, 0, sizeof(msgArg));
6626*c54f35caSApple OSS Distributions if (context->messageFilter &&
6627*c54f35caSApple OSS Distributions !context->messageFilter(context->us, object, context, &msgArg, NULL)) {
6628*c54f35caSApple OSS Distributions getPMRootDomain()->traceFilteredNotification(object);
6629*c54f35caSApple OSS Distributions return;
6630*c54f35caSApple OSS Distributions }
6631*c54f35caSApple OSS Distributions
6632*c54f35caSApple OSS Distributions if (NULL == context->notifyClients) {
6633*c54f35caSApple OSS Distributions context->notifyClients = OSArray::withCapacity(32);
6634*c54f35caSApple OSS Distributions assert(context->notifyClients != NULL);
6635*c54f35caSApple OSS Distributions }
6636*c54f35caSApple OSS Distributions
6637*c54f35caSApple OSS Distributions notifier = OSDynamicCast(_IOServiceInterestNotifier, object);
6638*c54f35caSApple OSS Distributions msgType = context->messageType;
6639*c54f35caSApple OSS Distributions msgIndex = context->responseArray->getCount();
6640*c54f35caSApple OSS Distributions msgRef = ((context->serialNumber & 0xFFFF) << 16) + (msgIndex & 0xFFFF);
6641*c54f35caSApple OSS Distributions enableTracing = context->enableTracing && (notifier != NULL);
6642*c54f35caSApple OSS Distributions
6643*c54f35caSApple OSS Distributions IOServicePM * pwrMgt = context->us->pwrMgt;
6644*c54f35caSApple OSS Distributions if (gIOKitDebug & kIOLogPower) {
6645*c54f35caSApple OSS Distributions OUR_PMLog(kPMLogClientNotify, msgRef, msgType);
6646*c54f35caSApple OSS Distributions if (OSDynamicCast(IOService, object)) {
6647*c54f35caSApple OSS Distributions const char *who = ((IOService *) object)->getName();
6648*c54f35caSApple OSS Distributions gPlatform->PMLog(who, kPMLogClientNotify, (uintptr_t) object, 0);
6649*c54f35caSApple OSS Distributions } else if (notifier) {
6650*c54f35caSApple OSS Distributions OUR_PMLog(kPMLogClientNotify, (uintptr_t) notifier->handler, 0);
6651*c54f35caSApple OSS Distributions }
6652*c54f35caSApple OSS Distributions }
6653*c54f35caSApple OSS Distributions
6654*c54f35caSApple OSS Distributions msgArg.notifyRef = msgRef;
6655*c54f35caSApple OSS Distributions msgArg.maxWaitForReply = 0;
6656*c54f35caSApple OSS Distributions
6657*c54f35caSApple OSS Distributions clock_get_uptime(&start);
6658*c54f35caSApple OSS Distributions if (enableTracing) {
6659*c54f35caSApple OSS Distributions getPMRootDomain()->traceNotification(notifier, true, start, msgIndex);
6660*c54f35caSApple OSS Distributions }
6661*c54f35caSApple OSS Distributions
6662*c54f35caSApple OSS Distributions retCode = context->us->messageClient(msgType, object, (void *) &msgArg, sizeof(msgArg));
6663*c54f35caSApple OSS Distributions
6664*c54f35caSApple OSS Distributions clock_get_uptime(&end);
6665*c54f35caSApple OSS Distributions if (enableTracing) {
6666*c54f35caSApple OSS Distributions getPMRootDomain()->traceNotification(notifier, false, end, msgIndex);
6667*c54f35caSApple OSS Distributions }
6668*c54f35caSApple OSS Distributions
6669*c54f35caSApple OSS Distributions if (kIOReturnSuccess == retCode) {
6670*c54f35caSApple OSS Distributions if (0 == msgArg.maxWaitForReply) {
6671*c54f35caSApple OSS Distributions // client doesn't want time to respond
6672*c54f35caSApple OSS Distributions OUR_PMLog(kPMLogClientAcknowledge, msgRef, (uintptr_t) object);
6673*c54f35caSApple OSS Distributions context->responseArray->setObject(msgIndex, replied);
6674*c54f35caSApple OSS Distributions } else {
6675*c54f35caSApple OSS Distributions replied = kOSBooleanFalse;
6676*c54f35caSApple OSS Distributions if (msgArg.maxWaitForReply > context->maxTimeRequested) {
6677*c54f35caSApple OSS Distributions if (msgArg.maxWaitForReply > kCapabilityClientMaxWait) {
6678*c54f35caSApple OSS Distributions context->maxTimeRequested = kCapabilityClientMaxWait;
6679*c54f35caSApple OSS Distributions PM_ERROR("%s: client %p returned %u for %s\n",
6680*c54f35caSApple OSS Distributions context->us->getName(),
6681*c54f35caSApple OSS Distributions notifier ? (void *) OBFUSCATE(notifier->handler) : OBFUSCATE(object),
6682*c54f35caSApple OSS Distributions msgArg.maxWaitForReply,
6683*c54f35caSApple OSS Distributions getIOMessageString(msgType));
6684*c54f35caSApple OSS Distributions } else {
6685*c54f35caSApple OSS Distributions context->maxTimeRequested = msgArg.maxWaitForReply;
6686*c54f35caSApple OSS Distributions }
6687*c54f35caSApple OSS Distributions }
6688*c54f35caSApple OSS Distributions
6689*c54f35caSApple OSS Distributions // Track time taken to ack, by storing the timestamp of
6690*c54f35caSApple OSS Distributions // callback completion
6691*c54f35caSApple OSS Distributions OSNumber * num;
6692*c54f35caSApple OSS Distributions num = OSNumber::withNumber(AbsoluteTime_to_scalar(&end), sizeof(uint64_t) * 8);
6693*c54f35caSApple OSS Distributions if (num) {
6694*c54f35caSApple OSS Distributions context->responseArray->setObject(msgIndex, num);
6695*c54f35caSApple OSS Distributions num->release();
6696*c54f35caSApple OSS Distributions } else {
6697*c54f35caSApple OSS Distributions context->responseArray->setObject(msgIndex, replied);
6698*c54f35caSApple OSS Distributions }
6699*c54f35caSApple OSS Distributions }
6700*c54f35caSApple OSS Distributions
6701*c54f35caSApple OSS Distributions if (enableTracing) {
6702*c54f35caSApple OSS Distributions SUB_ABSOLUTETIME(&end, &start);
6703*c54f35caSApple OSS Distributions absolutetime_to_nanoseconds(end, &nsec);
6704*c54f35caSApple OSS Distributions
6705*c54f35caSApple OSS Distributions if ((nsec > LOG_KEXT_RESPONSE_TIMES) || (msgArg.maxWaitForReply != 0)) {
6706*c54f35caSApple OSS Distributions getPMRootDomain()->traceNotificationResponse(notifier, NS_TO_MS(nsec), msgArg.maxWaitForReply);
6707*c54f35caSApple OSS Distributions }
6708*c54f35caSApple OSS Distributions }
6709*c54f35caSApple OSS Distributions } else {
6710*c54f35caSApple OSS Distributions // not a client of ours
6711*c54f35caSApple OSS Distributions // so we won't be waiting for response
6712*c54f35caSApple OSS Distributions OUR_PMLog(kPMLogClientAcknowledge, msgRef, 0);
6713*c54f35caSApple OSS Distributions context->responseArray->setObject(msgIndex, replied);
6714*c54f35caSApple OSS Distributions }
6715*c54f35caSApple OSS Distributions if (context->notifyClients) {
6716*c54f35caSApple OSS Distributions context->notifyClients->setObject(msgIndex, object);
6717*c54f35caSApple OSS Distributions }
6718*c54f35caSApple OSS Distributions }
6719*c54f35caSApple OSS Distributions
6720*c54f35caSApple OSS Distributions //*********************************************************************************
6721*c54f35caSApple OSS Distributions // [public] tellNoChangeDown
6722*c54f35caSApple OSS Distributions //
6723*c54f35caSApple OSS Distributions // Notify registered applications and kernel clients that we are not
6724*c54f35caSApple OSS Distributions // dropping power.
6725*c54f35caSApple OSS Distributions //
6726*c54f35caSApple OSS Distributions // Subclass can override this to send a different message type. Parameter is
6727*c54f35caSApple OSS Distributions // the aborted destination state number.
6728*c54f35caSApple OSS Distributions //*********************************************************************************
6729*c54f35caSApple OSS Distributions
6730*c54f35caSApple OSS Distributions void
tellNoChangeDown(unsigned long)6731*c54f35caSApple OSS Distributions IOService::tellNoChangeDown( unsigned long )
6732*c54f35caSApple OSS Distributions {
6733*c54f35caSApple OSS Distributions return tellClients( kIOMessageDeviceWillNotPowerOff );
6734*c54f35caSApple OSS Distributions }
6735*c54f35caSApple OSS Distributions
6736*c54f35caSApple OSS Distributions //*********************************************************************************
6737*c54f35caSApple OSS Distributions // [public] tellChangeUp
6738*c54f35caSApple OSS Distributions //
6739*c54f35caSApple OSS Distributions // Notify registered applications and kernel clients that we are raising power.
6740*c54f35caSApple OSS Distributions //
6741*c54f35caSApple OSS Distributions // Subclass can override this to send a different message type. Parameter is
6742*c54f35caSApple OSS Distributions // the aborted destination state number.
6743*c54f35caSApple OSS Distributions //*********************************************************************************
6744*c54f35caSApple OSS Distributions
6745*c54f35caSApple OSS Distributions void
tellChangeUp(unsigned long)6746*c54f35caSApple OSS Distributions IOService::tellChangeUp( unsigned long )
6747*c54f35caSApple OSS Distributions {
6748*c54f35caSApple OSS Distributions return tellClients( kIOMessageDeviceHasPoweredOn );
6749*c54f35caSApple OSS Distributions }
6750*c54f35caSApple OSS Distributions
6751*c54f35caSApple OSS Distributions //*********************************************************************************
6752*c54f35caSApple OSS Distributions // [protected] tellClients
6753*c54f35caSApple OSS Distributions //
6754*c54f35caSApple OSS Distributions // Notify registered applications and kernel clients of something.
6755*c54f35caSApple OSS Distributions //*********************************************************************************
6756*c54f35caSApple OSS Distributions
6757*c54f35caSApple OSS Distributions void
tellClients(int messageType)6758*c54f35caSApple OSS Distributions IOService::tellClients( int messageType )
6759*c54f35caSApple OSS Distributions {
6760*c54f35caSApple OSS Distributions IOPMInterestContext context;
6761*c54f35caSApple OSS Distributions
6762*c54f35caSApple OSS Distributions RD_LOG("tellClients( %s )\n", getIOMessageString(messageType));
6763*c54f35caSApple OSS Distributions
6764*c54f35caSApple OSS Distributions memset(&context, 0, sizeof(context));
6765*c54f35caSApple OSS Distributions context.messageType = messageType;
6766*c54f35caSApple OSS Distributions context.isPreChange = fIsPreChange;
6767*c54f35caSApple OSS Distributions context.us = this;
6768*c54f35caSApple OSS Distributions context.stateNumber = fHeadNotePowerState;
6769*c54f35caSApple OSS Distributions context.stateFlags = fHeadNotePowerArrayEntry->capabilityFlags;
6770*c54f35caSApple OSS Distributions context.changeFlags = fHeadNoteChangeFlags;
6771*c54f35caSApple OSS Distributions context.enableTracing = IS_ROOT_DOMAIN;
6772*c54f35caSApple OSS Distributions context.messageFilter = (IS_ROOT_DOMAIN) ?
6773*c54f35caSApple OSS Distributions OSMemberFunctionCast(
6774*c54f35caSApple OSS Distributions IOPMMessageFilter,
6775*c54f35caSApple OSS Distributions (IOPMrootDomain *)this,
6776*c54f35caSApple OSS Distributions &IOPMrootDomain::systemMessageFilter) : NULL;
6777*c54f35caSApple OSS Distributions
6778*c54f35caSApple OSS Distributions context.notifyType = kNotifyPriority;
6779*c54f35caSApple OSS Distributions applyToInterested( gIOPriorityPowerStateInterest,
6780*c54f35caSApple OSS Distributions tellKernelClientApplier, (void *) &context );
6781*c54f35caSApple OSS Distributions
6782*c54f35caSApple OSS Distributions context.notifyType = kNotifyApps;
6783*c54f35caSApple OSS Distributions applyToInterested( gIOAppPowerStateInterest,
6784*c54f35caSApple OSS Distributions tellAppClientApplier, (void *) &context );
6785*c54f35caSApple OSS Distributions
6786*c54f35caSApple OSS Distributions applyToInterested( gIOGeneralInterest,
6787*c54f35caSApple OSS Distributions tellKernelClientApplier, (void *) &context );
6788*c54f35caSApple OSS Distributions }
6789*c54f35caSApple OSS Distributions
6790*c54f35caSApple OSS Distributions //*********************************************************************************
6791*c54f35caSApple OSS Distributions // [private] tellKernelClientApplier
6792*c54f35caSApple OSS Distributions //
6793*c54f35caSApple OSS Distributions // Message a kernel client.
6794*c54f35caSApple OSS Distributions //*********************************************************************************
6795*c54f35caSApple OSS Distributions
6796*c54f35caSApple OSS Distributions static void
tellKernelClientApplier(OSObject * object,void * arg)6797*c54f35caSApple OSS Distributions tellKernelClientApplier( OSObject * object, void * arg )
6798*c54f35caSApple OSS Distributions {
6799*c54f35caSApple OSS Distributions IOPowerStateChangeNotification notify;
6800*c54f35caSApple OSS Distributions IOPMInterestContext * context = (IOPMInterestContext *) arg;
6801*c54f35caSApple OSS Distributions bool enableTracing = context->enableTracing;
6802*c54f35caSApple OSS Distributions
6803*c54f35caSApple OSS Distributions if (context->messageFilter &&
6804*c54f35caSApple OSS Distributions !context->messageFilter(context->us, object, context, NULL, NULL)) {
6805*c54f35caSApple OSS Distributions IOService::getPMRootDomain()->traceFilteredNotification(object);
6806*c54f35caSApple OSS Distributions return;
6807*c54f35caSApple OSS Distributions }
6808*c54f35caSApple OSS Distributions
6809*c54f35caSApple OSS Distributions notify.powerRef = (void *) NULL;
6810*c54f35caSApple OSS Distributions notify.returnValue = 0;
6811*c54f35caSApple OSS Distributions notify.stateNumber = context->stateNumber;
6812*c54f35caSApple OSS Distributions notify.stateFlags = context->stateFlags;
6813*c54f35caSApple OSS Distributions
6814*c54f35caSApple OSS Distributions if (enableTracing) {
6815*c54f35caSApple OSS Distributions IOService::getPMRootDomain()->traceNotification(object, true);
6816*c54f35caSApple OSS Distributions }
6817*c54f35caSApple OSS Distributions
6818*c54f35caSApple OSS Distributions context->us->messageClient(context->messageType, object, ¬ify, sizeof(notify));
6819*c54f35caSApple OSS Distributions
6820*c54f35caSApple OSS Distributions if (enableTracing) {
6821*c54f35caSApple OSS Distributions IOService::getPMRootDomain()->traceNotification(object, false);
6822*c54f35caSApple OSS Distributions }
6823*c54f35caSApple OSS Distributions }
6824*c54f35caSApple OSS Distributions
6825*c54f35caSApple OSS Distributions static OSNumber *
copyClientIDForNotification(OSObject * object,IOPMInterestContext * context)6826*c54f35caSApple OSS Distributions copyClientIDForNotification(
6827*c54f35caSApple OSS Distributions OSObject *object,
6828*c54f35caSApple OSS Distributions IOPMInterestContext *context)
6829*c54f35caSApple OSS Distributions {
6830*c54f35caSApple OSS Distributions OSNumber *clientID = NULL;
6831*c54f35caSApple OSS Distributions context->us->messageClient(kIOMessageCopyClientID, object, &clientID);
6832*c54f35caSApple OSS Distributions return clientID;
6833*c54f35caSApple OSS Distributions }
6834*c54f35caSApple OSS Distributions
6835*c54f35caSApple OSS Distributions static void
logClientIDForNotification(OSObject * object,IOPMInterestContext * context,const char * logString)6836*c54f35caSApple OSS Distributions logClientIDForNotification(
6837*c54f35caSApple OSS Distributions OSObject *object,
6838*c54f35caSApple OSS Distributions IOPMInterestContext *context,
6839*c54f35caSApple OSS Distributions const char *logString)
6840*c54f35caSApple OSS Distributions {
6841*c54f35caSApple OSS Distributions OSString *logClientID = NULL;
6842*c54f35caSApple OSS Distributions OSNumber *clientID = copyClientIDForNotification(object, context);
6843*c54f35caSApple OSS Distributions
6844*c54f35caSApple OSS Distributions if (logString) {
6845*c54f35caSApple OSS Distributions if (clientID) {
6846*c54f35caSApple OSS Distributions logClientID = IOCopyLogNameForPID(clientID->unsigned32BitValue());
6847*c54f35caSApple OSS Distributions }
6848*c54f35caSApple OSS Distributions
6849*c54f35caSApple OSS Distributions PM_LOG("%s %s %s, %s\n",
6850*c54f35caSApple OSS Distributions context->us->getName(), logString,
6851*c54f35caSApple OSS Distributions IOService::getIOMessageString(context->messageType),
6852*c54f35caSApple OSS Distributions logClientID ? logClientID->getCStringNoCopy() : "");
6853*c54f35caSApple OSS Distributions
6854*c54f35caSApple OSS Distributions if (logClientID) {
6855*c54f35caSApple OSS Distributions logClientID->release();
6856*c54f35caSApple OSS Distributions }
6857*c54f35caSApple OSS Distributions }
6858*c54f35caSApple OSS Distributions
6859*c54f35caSApple OSS Distributions if (clientID) {
6860*c54f35caSApple OSS Distributions clientID->release();
6861*c54f35caSApple OSS Distributions }
6862*c54f35caSApple OSS Distributions
6863*c54f35caSApple OSS Distributions return;
6864*c54f35caSApple OSS Distributions }
6865*c54f35caSApple OSS Distributions
6866*c54f35caSApple OSS Distributions static void
tellAppClientApplier(OSObject * object,void * arg)6867*c54f35caSApple OSS Distributions tellAppClientApplier( OSObject * object, void * arg )
6868*c54f35caSApple OSS Distributions {
6869*c54f35caSApple OSS Distributions IOPMInterestContext * context = (IOPMInterestContext *) arg;
6870*c54f35caSApple OSS Distributions OSNumber * clientID = NULL;
6871*c54f35caSApple OSS Distributions proc_t proc = NULL;
6872*c54f35caSApple OSS Distributions boolean_t proc_suspended = FALSE;
6873*c54f35caSApple OSS Distributions
6874*c54f35caSApple OSS Distributions if (context->us == IOService::getPMRootDomain()) {
6875*c54f35caSApple OSS Distributions if ((clientID = copyClientIDForNotification(object, context))) {
6876*c54f35caSApple OSS Distributions uint32_t clientPID = clientID->unsigned32BitValue();
6877*c54f35caSApple OSS Distributions clientID->release();
6878*c54f35caSApple OSS Distributions proc = proc_find(clientPID);
6879*c54f35caSApple OSS Distributions
6880*c54f35caSApple OSS Distributions if (proc) {
6881*c54f35caSApple OSS Distributions proc_suspended = get_task_pidsuspended((task_t) proc_task(proc));
6882*c54f35caSApple OSS Distributions if (proc_suspended) {
6883*c54f35caSApple OSS Distributions logClientIDForNotification(object, context, "tellAppClientApplier - Suspended");
6884*c54f35caSApple OSS Distributions } else if (IOService::getPMRootDomain()->isAOTMode() && get_task_suspended((task_t) proc_task(proc))) {
6885*c54f35caSApple OSS Distributions proc_suspended = true;
6886*c54f35caSApple OSS Distributions context->skippedInDark++;
6887*c54f35caSApple OSS Distributions }
6888*c54f35caSApple OSS Distributions proc_rele(proc);
6889*c54f35caSApple OSS Distributions if (proc_suspended) {
6890*c54f35caSApple OSS Distributions return;
6891*c54f35caSApple OSS Distributions }
6892*c54f35caSApple OSS Distributions }
6893*c54f35caSApple OSS Distributions }
6894*c54f35caSApple OSS Distributions }
6895*c54f35caSApple OSS Distributions
6896*c54f35caSApple OSS Distributions if (context->messageFilter &&
6897*c54f35caSApple OSS Distributions !context->messageFilter(context->us, object, context, NULL, NULL)) {
6898*c54f35caSApple OSS Distributions if (kIOLogDebugPower & gIOKitDebug) {
6899*c54f35caSApple OSS Distributions logClientIDForNotification(object, context, "DROP App");
6900*c54f35caSApple OSS Distributions }
6901*c54f35caSApple OSS Distributions return;
6902*c54f35caSApple OSS Distributions }
6903*c54f35caSApple OSS Distributions context->notSkippedInDark++;
6904*c54f35caSApple OSS Distributions
6905*c54f35caSApple OSS Distributions if (kIOLogDebugPower & gIOKitDebug) {
6906*c54f35caSApple OSS Distributions logClientIDForNotification(object, context, "MESG App");
6907*c54f35caSApple OSS Distributions }
6908*c54f35caSApple OSS Distributions
6909*c54f35caSApple OSS Distributions context->us->messageClient(context->messageType, object, NULL);
6910*c54f35caSApple OSS Distributions }
6911*c54f35caSApple OSS Distributions
6912*c54f35caSApple OSS Distributions //*********************************************************************************
6913*c54f35caSApple OSS Distributions // [private] checkForDone
6914*c54f35caSApple OSS Distributions //*********************************************************************************
6915*c54f35caSApple OSS Distributions
6916*c54f35caSApple OSS Distributions bool
checkForDone(void)6917*c54f35caSApple OSS Distributions IOService::checkForDone( void )
6918*c54f35caSApple OSS Distributions {
6919*c54f35caSApple OSS Distributions int i = 0;
6920*c54f35caSApple OSS Distributions OSObject * theFlag;
6921*c54f35caSApple OSS Distributions
6922*c54f35caSApple OSS Distributions if (fResponseArray == NULL) {
6923*c54f35caSApple OSS Distributions return true;
6924*c54f35caSApple OSS Distributions }
6925*c54f35caSApple OSS Distributions
6926*c54f35caSApple OSS Distributions for (i = 0;; i++) {
6927*c54f35caSApple OSS Distributions theFlag = fResponseArray->getObject(i);
6928*c54f35caSApple OSS Distributions
6929*c54f35caSApple OSS Distributions if (NULL == theFlag) {
6930*c54f35caSApple OSS Distributions break;
6931*c54f35caSApple OSS Distributions }
6932*c54f35caSApple OSS Distributions
6933*c54f35caSApple OSS Distributions if (kOSBooleanTrue != theFlag) {
6934*c54f35caSApple OSS Distributions return false;
6935*c54f35caSApple OSS Distributions }
6936*c54f35caSApple OSS Distributions }
6937*c54f35caSApple OSS Distributions return true;
6938*c54f35caSApple OSS Distributions }
6939*c54f35caSApple OSS Distributions
6940*c54f35caSApple OSS Distributions //*********************************************************************************
6941*c54f35caSApple OSS Distributions // [public] responseValid
6942*c54f35caSApple OSS Distributions //*********************************************************************************
6943*c54f35caSApple OSS Distributions
6944*c54f35caSApple OSS Distributions bool
responseValid(uint32_t refcon,int pid)6945*c54f35caSApple OSS Distributions IOService::responseValid( uint32_t refcon, int pid )
6946*c54f35caSApple OSS Distributions {
6947*c54f35caSApple OSS Distributions UInt16 serialComponent;
6948*c54f35caSApple OSS Distributions UInt16 ordinalComponent;
6949*c54f35caSApple OSS Distributions OSObject * theFlag;
6950*c54f35caSApple OSS Distributions OSObject *object = NULL;
6951*c54f35caSApple OSS Distributions
6952*c54f35caSApple OSS Distributions serialComponent = (refcon >> 16) & 0xFFFF;
6953*c54f35caSApple OSS Distributions ordinalComponent = (refcon & 0xFFFF);
6954*c54f35caSApple OSS Distributions
6955*c54f35caSApple OSS Distributions if (serialComponent != fSerialNumber) {
6956*c54f35caSApple OSS Distributions return false;
6957*c54f35caSApple OSS Distributions }
6958*c54f35caSApple OSS Distributions
6959*c54f35caSApple OSS Distributions if (fResponseArray == NULL) {
6960*c54f35caSApple OSS Distributions return false;
6961*c54f35caSApple OSS Distributions }
6962*c54f35caSApple OSS Distributions
6963*c54f35caSApple OSS Distributions theFlag = fResponseArray->getObject(ordinalComponent);
6964*c54f35caSApple OSS Distributions
6965*c54f35caSApple OSS Distributions if (theFlag == NULL) {
6966*c54f35caSApple OSS Distributions return false;
6967*c54f35caSApple OSS Distributions }
6968*c54f35caSApple OSS Distributions
6969*c54f35caSApple OSS Distributions if (fNotifyClientArray) {
6970*c54f35caSApple OSS Distributions object = fNotifyClientArray->getObject(ordinalComponent);
6971*c54f35caSApple OSS Distributions }
6972*c54f35caSApple OSS Distributions
6973*c54f35caSApple OSS Distributions OSNumber * num;
6974*c54f35caSApple OSS Distributions if ((num = OSDynamicCast(OSNumber, theFlag))) {
6975*c54f35caSApple OSS Distributions AbsoluteTime now;
6976*c54f35caSApple OSS Distributions AbsoluteTime start;
6977*c54f35caSApple OSS Distributions uint64_t nsec;
6978*c54f35caSApple OSS Distributions char name[128];
6979*c54f35caSApple OSS Distributions
6980*c54f35caSApple OSS Distributions clock_get_uptime(&now);
6981*c54f35caSApple OSS Distributions AbsoluteTime_to_scalar(&start) = num->unsigned64BitValue();
6982*c54f35caSApple OSS Distributions SUB_ABSOLUTETIME(&now, &start);
6983*c54f35caSApple OSS Distributions absolutetime_to_nanoseconds(now, &nsec);
6984*c54f35caSApple OSS Distributions
6985*c54f35caSApple OSS Distributions if (pid != 0) {
6986*c54f35caSApple OSS Distributions name[0] = '\0';
6987*c54f35caSApple OSS Distributions proc_name(pid, name, sizeof(name));
6988*c54f35caSApple OSS Distributions
6989*c54f35caSApple OSS Distributions if (nsec > LOG_APP_RESPONSE_TIMES) {
6990*c54f35caSApple OSS Distributions IOLog("PM response took %d ms (%d, %s)\n", NS_TO_MS(nsec),
6991*c54f35caSApple OSS Distributions pid, name);
6992*c54f35caSApple OSS Distributions }
6993*c54f35caSApple OSS Distributions
6994*c54f35caSApple OSS Distributions if (nsec > LOG_APP_RESPONSE_MSG_TRACER) {
6995*c54f35caSApple OSS Distributions // TODO: populate the messageType argument
6996*c54f35caSApple OSS Distributions getPMRootDomain()->pmStatsRecordApplicationResponse(
6997*c54f35caSApple OSS Distributions gIOPMStatsResponseSlow,
6998*c54f35caSApple OSS Distributions name, 0, NS_TO_MS(nsec), pid, object);
6999*c54f35caSApple OSS Distributions } else {
7000*c54f35caSApple OSS Distributions getPMRootDomain()->pmStatsRecordApplicationResponse(
7001*c54f35caSApple OSS Distributions gIOPMStatsResponsePrompt,
7002*c54f35caSApple OSS Distributions name, 0, NS_TO_MS(nsec), pid, object);
7003*c54f35caSApple OSS Distributions }
7004*c54f35caSApple OSS Distributions } else {
7005*c54f35caSApple OSS Distributions getPMRootDomain()->traceNotificationAck(object, NS_TO_MS(nsec));
7006*c54f35caSApple OSS Distributions }
7007*c54f35caSApple OSS Distributions
7008*c54f35caSApple OSS Distributions if (kIOLogDebugPower & gIOKitDebug) {
7009*c54f35caSApple OSS Distributions PM_LOG("Ack(%u) %u ms\n",
7010*c54f35caSApple OSS Distributions (uint32_t) ordinalComponent,
7011*c54f35caSApple OSS Distributions NS_TO_MS(nsec));
7012*c54f35caSApple OSS Distributions }
7013*c54f35caSApple OSS Distributions theFlag = kOSBooleanFalse;
7014*c54f35caSApple OSS Distributions } else if (object) {
7015*c54f35caSApple OSS Distributions getPMRootDomain()->pmStatsRecordApplicationResponse(
7016*c54f35caSApple OSS Distributions gIOPMStatsResponsePrompt,
7017*c54f35caSApple OSS Distributions NULL, 0, 0, pid, object);
7018*c54f35caSApple OSS Distributions }
7019*c54f35caSApple OSS Distributions
7020*c54f35caSApple OSS Distributions if (kOSBooleanFalse == theFlag) {
7021*c54f35caSApple OSS Distributions fResponseArray->replaceObject(ordinalComponent, kOSBooleanTrue);
7022*c54f35caSApple OSS Distributions }
7023*c54f35caSApple OSS Distributions
7024*c54f35caSApple OSS Distributions return true;
7025*c54f35caSApple OSS Distributions }
7026*c54f35caSApple OSS Distributions
7027*c54f35caSApple OSS Distributions //*********************************************************************************
7028*c54f35caSApple OSS Distributions // [public] allowPowerChange
7029*c54f35caSApple OSS Distributions //
7030*c54f35caSApple OSS Distributions // Our power state is about to lower, and we have notified applications
7031*c54f35caSApple OSS Distributions // and kernel clients, and one of them has acknowledged. If this is the last to do
7032*c54f35caSApple OSS Distributions // so, and all acknowledgements are positive, we continue with the power change.
7033*c54f35caSApple OSS Distributions //*********************************************************************************
7034*c54f35caSApple OSS Distributions
7035*c54f35caSApple OSS Distributions IOReturn
allowPowerChange(unsigned long refcon)7036*c54f35caSApple OSS Distributions IOService::allowPowerChange( unsigned long refcon )
7037*c54f35caSApple OSS Distributions {
7038*c54f35caSApple OSS Distributions IOPMRequest * request;
7039*c54f35caSApple OSS Distributions
7040*c54f35caSApple OSS Distributions if (!initialized) {
7041*c54f35caSApple OSS Distributions // we're unloading
7042*c54f35caSApple OSS Distributions return kIOReturnSuccess;
7043*c54f35caSApple OSS Distributions }
7044*c54f35caSApple OSS Distributions
7045*c54f35caSApple OSS Distributions request = acquirePMRequest( this, kIOPMRequestTypeAllowPowerChange );
7046*c54f35caSApple OSS Distributions if (!request) {
7047*c54f35caSApple OSS Distributions return kIOReturnNoMemory;
7048*c54f35caSApple OSS Distributions }
7049*c54f35caSApple OSS Distributions
7050*c54f35caSApple OSS Distributions request->fArg0 = (void *) refcon;
7051*c54f35caSApple OSS Distributions request->fArg1 = (void *)(uintptr_t) proc_selfpid();
7052*c54f35caSApple OSS Distributions request->fArg2 = (void *) NULL;
7053*c54f35caSApple OSS Distributions submitPMRequest( request );
7054*c54f35caSApple OSS Distributions
7055*c54f35caSApple OSS Distributions return kIOReturnSuccess;
7056*c54f35caSApple OSS Distributions }
7057*c54f35caSApple OSS Distributions
7058*c54f35caSApple OSS Distributions #ifndef __LP64__
7059*c54f35caSApple OSS Distributions IOReturn
serializedAllowPowerChange2(unsigned long refcon)7060*c54f35caSApple OSS Distributions IOService::serializedAllowPowerChange2( unsigned long refcon )
7061*c54f35caSApple OSS Distributions {
7062*c54f35caSApple OSS Distributions // [deprecated] public
7063*c54f35caSApple OSS Distributions return kIOReturnUnsupported;
7064*c54f35caSApple OSS Distributions }
7065*c54f35caSApple OSS Distributions #endif /* !__LP64__ */
7066*c54f35caSApple OSS Distributions
7067*c54f35caSApple OSS Distributions //*********************************************************************************
7068*c54f35caSApple OSS Distributions // [public] cancelPowerChange
7069*c54f35caSApple OSS Distributions //
7070*c54f35caSApple OSS Distributions // Our power state is about to lower, and we have notified applications
7071*c54f35caSApple OSS Distributions // and kernel clients, and one of them has vetoed the change. If this is the last
7072*c54f35caSApple OSS Distributions // client to respond, we abandon the power change.
7073*c54f35caSApple OSS Distributions //*********************************************************************************
7074*c54f35caSApple OSS Distributions
7075*c54f35caSApple OSS Distributions IOReturn
cancelPowerChange(unsigned long refcon)7076*c54f35caSApple OSS Distributions IOService::cancelPowerChange( unsigned long refcon )
7077*c54f35caSApple OSS Distributions {
7078*c54f35caSApple OSS Distributions IOPMRequest * request;
7079*c54f35caSApple OSS Distributions char name[128];
7080*c54f35caSApple OSS Distributions pid_t pid = proc_selfpid();
7081*c54f35caSApple OSS Distributions
7082*c54f35caSApple OSS Distributions if (!initialized) {
7083*c54f35caSApple OSS Distributions // we're unloading
7084*c54f35caSApple OSS Distributions return kIOReturnSuccess;
7085*c54f35caSApple OSS Distributions }
7086*c54f35caSApple OSS Distributions
7087*c54f35caSApple OSS Distributions name[0] = '\0';
7088*c54f35caSApple OSS Distributions proc_name(pid, name, sizeof(name));
7089*c54f35caSApple OSS Distributions PM_ERROR("PM notification cancel (pid %d, %s)\n", pid, name);
7090*c54f35caSApple OSS Distributions
7091*c54f35caSApple OSS Distributions request = acquirePMRequest( this, kIOPMRequestTypeCancelPowerChange );
7092*c54f35caSApple OSS Distributions if (!request) {
7093*c54f35caSApple OSS Distributions return kIOReturnNoMemory;
7094*c54f35caSApple OSS Distributions }
7095*c54f35caSApple OSS Distributions
7096*c54f35caSApple OSS Distributions request->fArg0 = (void *) refcon;
7097*c54f35caSApple OSS Distributions request->fArg1 = (void *)(uintptr_t) proc_selfpid();
7098*c54f35caSApple OSS Distributions request->fArg2 = (void *) OSString::withCString(name);
7099*c54f35caSApple OSS Distributions submitPMRequest( request );
7100*c54f35caSApple OSS Distributions
7101*c54f35caSApple OSS Distributions return kIOReturnSuccess;
7102*c54f35caSApple OSS Distributions }
7103*c54f35caSApple OSS Distributions
7104*c54f35caSApple OSS Distributions //*********************************************************************************
7105*c54f35caSApple OSS Distributions // cancelIdlePowerDown
7106*c54f35caSApple OSS Distributions //
7107*c54f35caSApple OSS Distributions // Internal method to trigger an idle cancel or revert
7108*c54f35caSApple OSS Distributions //*********************************************************************************
7109*c54f35caSApple OSS Distributions
7110*c54f35caSApple OSS Distributions void
cancelIdlePowerDown(IOService * service)7111*c54f35caSApple OSS Distributions IOService::cancelIdlePowerDown( IOService * service )
7112*c54f35caSApple OSS Distributions {
7113*c54f35caSApple OSS Distributions IOPMRequest * request;
7114*c54f35caSApple OSS Distributions
7115*c54f35caSApple OSS Distributions request = acquirePMRequest(service, kIOPMRequestTypeIdleCancel);
7116*c54f35caSApple OSS Distributions if (request) {
7117*c54f35caSApple OSS Distributions submitPMRequest(request);
7118*c54f35caSApple OSS Distributions }
7119*c54f35caSApple OSS Distributions }
7120*c54f35caSApple OSS Distributions
7121*c54f35caSApple OSS Distributions #ifndef __LP64__
7122*c54f35caSApple OSS Distributions IOReturn
serializedCancelPowerChange2(unsigned long refcon)7123*c54f35caSApple OSS Distributions IOService::serializedCancelPowerChange2( unsigned long refcon )
7124*c54f35caSApple OSS Distributions {
7125*c54f35caSApple OSS Distributions // [deprecated] public
7126*c54f35caSApple OSS Distributions return kIOReturnUnsupported;
7127*c54f35caSApple OSS Distributions }
7128*c54f35caSApple OSS Distributions
7129*c54f35caSApple OSS Distributions //*********************************************************************************
7130*c54f35caSApple OSS Distributions // PM_Clamp_Timer_Expired
7131*c54f35caSApple OSS Distributions //
7132*c54f35caSApple OSS Distributions // called when clamp timer expires...set power state to 0.
7133*c54f35caSApple OSS Distributions //*********************************************************************************
7134*c54f35caSApple OSS Distributions
7135*c54f35caSApple OSS Distributions void
PM_Clamp_Timer_Expired(void)7136*c54f35caSApple OSS Distributions IOService::PM_Clamp_Timer_Expired( void )
7137*c54f35caSApple OSS Distributions {
7138*c54f35caSApple OSS Distributions }
7139*c54f35caSApple OSS Distributions
7140*c54f35caSApple OSS Distributions //*********************************************************************************
7141*c54f35caSApple OSS Distributions // clampPowerOn
7142*c54f35caSApple OSS Distributions //
7143*c54f35caSApple OSS Distributions // Set to highest available power state for a minimum of duration milliseconds
7144*c54f35caSApple OSS Distributions //*********************************************************************************
7145*c54f35caSApple OSS Distributions
7146*c54f35caSApple OSS Distributions void
clampPowerOn(unsigned long duration)7147*c54f35caSApple OSS Distributions IOService::clampPowerOn( unsigned long duration )
7148*c54f35caSApple OSS Distributions {
7149*c54f35caSApple OSS Distributions }
7150*c54f35caSApple OSS Distributions #endif /* !__LP64__ */
7151*c54f35caSApple OSS Distributions
7152*c54f35caSApple OSS Distributions //*********************************************************************************
7153*c54f35caSApple OSS Distributions // configurePowerStateReport
7154*c54f35caSApple OSS Distributions //
7155*c54f35caSApple OSS Distributions // Configures the IOStateReport for kPMPowerStateChannel
7156*c54f35caSApple OSS Distributions //*********************************************************************************
7157*c54f35caSApple OSS Distributions IOReturn
configurePowerStatesReport(IOReportConfigureAction action,void * result)7158*c54f35caSApple OSS Distributions IOService::configurePowerStatesReport( IOReportConfigureAction action, void *result )
7159*c54f35caSApple OSS Distributions {
7160*c54f35caSApple OSS Distributions IOReturn rc = kIOReturnSuccess;
7161*c54f35caSApple OSS Distributions size_t reportSize;
7162*c54f35caSApple OSS Distributions unsigned long i;
7163*c54f35caSApple OSS Distributions uint64_t ts;
7164*c54f35caSApple OSS Distributions
7165*c54f35caSApple OSS Distributions if (!pwrMgt) {
7166*c54f35caSApple OSS Distributions return kIOReturnUnsupported;
7167*c54f35caSApple OSS Distributions }
7168*c54f35caSApple OSS Distributions
7169*c54f35caSApple OSS Distributions if (!fNumberOfPowerStates) {
7170*c54f35caSApple OSS Distributions return kIOReturnSuccess; // For drivers which are in power plane, but haven't called registerPowerDriver()
7171*c54f35caSApple OSS Distributions }
7172*c54f35caSApple OSS Distributions
7173*c54f35caSApple OSS Distributions if (fNumberOfPowerStates > INT16_MAX) {
7174*c54f35caSApple OSS Distributions return kIOReturnOverrun;
7175*c54f35caSApple OSS Distributions }
7176*c54f35caSApple OSS Distributions PM_LOCK();
7177*c54f35caSApple OSS Distributions
7178*c54f35caSApple OSS Distributions switch (action) {
7179*c54f35caSApple OSS Distributions case kIOReportEnable:
7180*c54f35caSApple OSS Distributions if (fReportBuf) {
7181*c54f35caSApple OSS Distributions fReportClientCnt++;
7182*c54f35caSApple OSS Distributions break;
7183*c54f35caSApple OSS Distributions }
7184*c54f35caSApple OSS Distributions reportSize = STATEREPORT_BUFSIZE(fNumberOfPowerStates);
7185*c54f35caSApple OSS Distributions fReportBuf = IOMallocZeroData(reportSize);
7186*c54f35caSApple OSS Distributions if (!fReportBuf) {
7187*c54f35caSApple OSS Distributions rc = kIOReturnNoMemory;
7188*c54f35caSApple OSS Distributions break;
7189*c54f35caSApple OSS Distributions }
7190*c54f35caSApple OSS Distributions
7191*c54f35caSApple OSS Distributions STATEREPORT_INIT((uint16_t) fNumberOfPowerStates, fReportBuf, reportSize,
7192*c54f35caSApple OSS Distributions getRegistryEntryID(), kPMPowerStatesChID, kIOReportCategoryPower);
7193*c54f35caSApple OSS Distributions
7194*c54f35caSApple OSS Distributions for (i = 0; i < fNumberOfPowerStates; i++) {
7195*c54f35caSApple OSS Distributions unsigned bits = 0;
7196*c54f35caSApple OSS Distributions
7197*c54f35caSApple OSS Distributions if (fPowerStates[i].capabilityFlags & kIOPMPowerOn) {
7198*c54f35caSApple OSS Distributions bits |= kPMReportPowerOn;
7199*c54f35caSApple OSS Distributions }
7200*c54f35caSApple OSS Distributions if (fPowerStates[i].capabilityFlags & kIOPMDeviceUsable) {
7201*c54f35caSApple OSS Distributions bits |= kPMReportDeviceUsable;
7202*c54f35caSApple OSS Distributions }
7203*c54f35caSApple OSS Distributions if (fPowerStates[i].capabilityFlags & kIOPMLowPower) {
7204*c54f35caSApple OSS Distributions bits |= kPMReportLowPower;
7205*c54f35caSApple OSS Distributions }
7206*c54f35caSApple OSS Distributions
7207*c54f35caSApple OSS Distributions STATEREPORT_SETSTATEID(fReportBuf, i, ((bits & 0xff) << 8) |
7208*c54f35caSApple OSS Distributions ((StateOrder(fMaxPowerState) & 0xf) << 4) | (StateOrder(i) & 0xf));
7209*c54f35caSApple OSS Distributions }
7210*c54f35caSApple OSS Distributions ts = mach_absolute_time();
7211*c54f35caSApple OSS Distributions STATEREPORT_SETSTATE(fReportBuf, (uint16_t) fCurrentPowerState, ts);
7212*c54f35caSApple OSS Distributions break;
7213*c54f35caSApple OSS Distributions
7214*c54f35caSApple OSS Distributions case kIOReportDisable:
7215*c54f35caSApple OSS Distributions if (fReportClientCnt == 0) {
7216*c54f35caSApple OSS Distributions rc = kIOReturnBadArgument;
7217*c54f35caSApple OSS Distributions break;
7218*c54f35caSApple OSS Distributions }
7219*c54f35caSApple OSS Distributions if (fReportClientCnt == 1) {
7220*c54f35caSApple OSS Distributions IOFreeData(fReportBuf, STATEREPORT_BUFSIZE(fNumberOfPowerStates));
7221*c54f35caSApple OSS Distributions fReportBuf = NULL;
7222*c54f35caSApple OSS Distributions }
7223*c54f35caSApple OSS Distributions fReportClientCnt--;
7224*c54f35caSApple OSS Distributions break;
7225*c54f35caSApple OSS Distributions
7226*c54f35caSApple OSS Distributions case kIOReportGetDimensions:
7227*c54f35caSApple OSS Distributions if (fReportBuf) {
7228*c54f35caSApple OSS Distributions STATEREPORT_UPDATERES(fReportBuf, kIOReportGetDimensions, result);
7229*c54f35caSApple OSS Distributions }
7230*c54f35caSApple OSS Distributions break;
7231*c54f35caSApple OSS Distributions }
7232*c54f35caSApple OSS Distributions
7233*c54f35caSApple OSS Distributions PM_UNLOCK();
7234*c54f35caSApple OSS Distributions
7235*c54f35caSApple OSS Distributions return rc;
7236*c54f35caSApple OSS Distributions }
7237*c54f35caSApple OSS Distributions
7238*c54f35caSApple OSS Distributions //*********************************************************************************
7239*c54f35caSApple OSS Distributions // updatePowerStateReport
7240*c54f35caSApple OSS Distributions //
7241*c54f35caSApple OSS Distributions // Updates the IOStateReport for kPMPowerStateChannel
7242*c54f35caSApple OSS Distributions //*********************************************************************************
7243*c54f35caSApple OSS Distributions IOReturn
updatePowerStatesReport(IOReportConfigureAction action,void * result,void * destination)7244*c54f35caSApple OSS Distributions IOService::updatePowerStatesReport( IOReportConfigureAction action, void *result, void *destination )
7245*c54f35caSApple OSS Distributions {
7246*c54f35caSApple OSS Distributions uint32_t size2cpy;
7247*c54f35caSApple OSS Distributions void *data2cpy;
7248*c54f35caSApple OSS Distributions uint64_t ts;
7249*c54f35caSApple OSS Distributions IOReturn rc = kIOReturnSuccess;
7250*c54f35caSApple OSS Distributions IOBufferMemoryDescriptor *dest = OSDynamicCast(IOBufferMemoryDescriptor, (OSObject *)destination);
7251*c54f35caSApple OSS Distributions
7252*c54f35caSApple OSS Distributions
7253*c54f35caSApple OSS Distributions if (!pwrMgt) {
7254*c54f35caSApple OSS Distributions return kIOReturnUnsupported;
7255*c54f35caSApple OSS Distributions }
7256*c54f35caSApple OSS Distributions if (!fNumberOfPowerStates) {
7257*c54f35caSApple OSS Distributions return kIOReturnSuccess;
7258*c54f35caSApple OSS Distributions }
7259*c54f35caSApple OSS Distributions
7260*c54f35caSApple OSS Distributions if (!result || !dest) {
7261*c54f35caSApple OSS Distributions return kIOReturnBadArgument;
7262*c54f35caSApple OSS Distributions }
7263*c54f35caSApple OSS Distributions PM_LOCK();
7264*c54f35caSApple OSS Distributions
7265*c54f35caSApple OSS Distributions switch (action) {
7266*c54f35caSApple OSS Distributions case kIOReportCopyChannelData:
7267*c54f35caSApple OSS Distributions if (!fReportBuf) {
7268*c54f35caSApple OSS Distributions rc = kIOReturnNotOpen;
7269*c54f35caSApple OSS Distributions break;
7270*c54f35caSApple OSS Distributions }
7271*c54f35caSApple OSS Distributions
7272*c54f35caSApple OSS Distributions ts = mach_absolute_time();
7273*c54f35caSApple OSS Distributions STATEREPORT_UPDATEPREP(fReportBuf, ts, data2cpy, size2cpy);
7274*c54f35caSApple OSS Distributions if (size2cpy > (dest->getCapacity() - dest->getLength())) {
7275*c54f35caSApple OSS Distributions rc = kIOReturnOverrun;
7276*c54f35caSApple OSS Distributions break;
7277*c54f35caSApple OSS Distributions }
7278*c54f35caSApple OSS Distributions
7279*c54f35caSApple OSS Distributions STATEREPORT_UPDATERES(fReportBuf, kIOReportCopyChannelData, result);
7280*c54f35caSApple OSS Distributions dest->appendBytes(data2cpy, size2cpy);
7281*c54f35caSApple OSS Distributions break;
7282*c54f35caSApple OSS Distributions
7283*c54f35caSApple OSS Distributions default:
7284*c54f35caSApple OSS Distributions break;
7285*c54f35caSApple OSS Distributions }
7286*c54f35caSApple OSS Distributions
7287*c54f35caSApple OSS Distributions PM_UNLOCK();
7288*c54f35caSApple OSS Distributions
7289*c54f35caSApple OSS Distributions return rc;
7290*c54f35caSApple OSS Distributions }
7291*c54f35caSApple OSS Distributions
7292*c54f35caSApple OSS Distributions //*********************************************************************************
7293*c54f35caSApple OSS Distributions // configureSimplePowerReport
7294*c54f35caSApple OSS Distributions //
7295*c54f35caSApple OSS Distributions // Configures the IOSimpleReport for given channel id
7296*c54f35caSApple OSS Distributions //*********************************************************************************
7297*c54f35caSApple OSS Distributions IOReturn
configureSimplePowerReport(IOReportConfigureAction action,void * result)7298*c54f35caSApple OSS Distributions IOService::configureSimplePowerReport(IOReportConfigureAction action, void *result )
7299*c54f35caSApple OSS Distributions {
7300*c54f35caSApple OSS Distributions IOReturn rc = kIOReturnSuccess;
7301*c54f35caSApple OSS Distributions
7302*c54f35caSApple OSS Distributions if (!pwrMgt) {
7303*c54f35caSApple OSS Distributions return kIOReturnUnsupported;
7304*c54f35caSApple OSS Distributions }
7305*c54f35caSApple OSS Distributions
7306*c54f35caSApple OSS Distributions if (!fNumberOfPowerStates) {
7307*c54f35caSApple OSS Distributions return rc;
7308*c54f35caSApple OSS Distributions }
7309*c54f35caSApple OSS Distributions
7310*c54f35caSApple OSS Distributions switch (action) {
7311*c54f35caSApple OSS Distributions case kIOReportEnable:
7312*c54f35caSApple OSS Distributions case kIOReportDisable:
7313*c54f35caSApple OSS Distributions break;
7314*c54f35caSApple OSS Distributions
7315*c54f35caSApple OSS Distributions case kIOReportGetDimensions:
7316*c54f35caSApple OSS Distributions SIMPLEREPORT_UPDATERES(kIOReportGetDimensions, result);
7317*c54f35caSApple OSS Distributions break;
7318*c54f35caSApple OSS Distributions }
7319*c54f35caSApple OSS Distributions
7320*c54f35caSApple OSS Distributions
7321*c54f35caSApple OSS Distributions return rc;
7322*c54f35caSApple OSS Distributions }
7323*c54f35caSApple OSS Distributions
7324*c54f35caSApple OSS Distributions //*********************************************************************************
7325*c54f35caSApple OSS Distributions // updateSimplePowerReport
7326*c54f35caSApple OSS Distributions //
7327*c54f35caSApple OSS Distributions // Updates the IOSimpleReport for the given chanel id
7328*c54f35caSApple OSS Distributions //*********************************************************************************
7329*c54f35caSApple OSS Distributions IOReturn
updateSimplePowerReport(IOReportConfigureAction action,void * result,void * destination)7330*c54f35caSApple OSS Distributions IOService::updateSimplePowerReport( IOReportConfigureAction action, void *result, void *destination )
7331*c54f35caSApple OSS Distributions {
7332*c54f35caSApple OSS Distributions uint32_t size2cpy;
7333*c54f35caSApple OSS Distributions void *data2cpy;
7334*c54f35caSApple OSS Distributions uint64_t buf[SIMPLEREPORT_BUFSIZE / sizeof(uint64_t) + 1]; // Force a 8-byte alignment
7335*c54f35caSApple OSS Distributions IOBufferMemoryDescriptor *dest = OSDynamicCast(IOBufferMemoryDescriptor, (OSObject *)destination);
7336*c54f35caSApple OSS Distributions IOReturn rc = kIOReturnSuccess;
7337*c54f35caSApple OSS Distributions unsigned bits = 0;
7338*c54f35caSApple OSS Distributions
7339*c54f35caSApple OSS Distributions
7340*c54f35caSApple OSS Distributions if (!pwrMgt) {
7341*c54f35caSApple OSS Distributions return kIOReturnUnsupported;
7342*c54f35caSApple OSS Distributions }
7343*c54f35caSApple OSS Distributions if (!result || !dest) {
7344*c54f35caSApple OSS Distributions return kIOReturnBadArgument;
7345*c54f35caSApple OSS Distributions }
7346*c54f35caSApple OSS Distributions
7347*c54f35caSApple OSS Distributions if (!fNumberOfPowerStates) {
7348*c54f35caSApple OSS Distributions return rc;
7349*c54f35caSApple OSS Distributions }
7350*c54f35caSApple OSS Distributions PM_LOCK();
7351*c54f35caSApple OSS Distributions
7352*c54f35caSApple OSS Distributions switch (action) {
7353*c54f35caSApple OSS Distributions case kIOReportCopyChannelData:
7354*c54f35caSApple OSS Distributions
7355*c54f35caSApple OSS Distributions SIMPLEREPORT_INIT(buf, sizeof(buf), getRegistryEntryID(), kPMCurrStateChID, kIOReportCategoryPower);
7356*c54f35caSApple OSS Distributions
7357*c54f35caSApple OSS Distributions if (fPowerStates[fCurrentPowerState].capabilityFlags & kIOPMPowerOn) {
7358*c54f35caSApple OSS Distributions bits |= kPMReportPowerOn;
7359*c54f35caSApple OSS Distributions }
7360*c54f35caSApple OSS Distributions if (fPowerStates[fCurrentPowerState].capabilityFlags & kIOPMDeviceUsable) {
7361*c54f35caSApple OSS Distributions bits |= kPMReportDeviceUsable;
7362*c54f35caSApple OSS Distributions }
7363*c54f35caSApple OSS Distributions if (fPowerStates[fCurrentPowerState].capabilityFlags & kIOPMLowPower) {
7364*c54f35caSApple OSS Distributions bits |= kPMReportLowPower;
7365*c54f35caSApple OSS Distributions }
7366*c54f35caSApple OSS Distributions
7367*c54f35caSApple OSS Distributions
7368*c54f35caSApple OSS Distributions SIMPLEREPORT_SETVALUE(buf, ((bits & 0xff) << 8) | ((StateOrder(fMaxPowerState) & 0xf) << 4) |
7369*c54f35caSApple OSS Distributions (StateOrder(fCurrentPowerState) & 0xf));
7370*c54f35caSApple OSS Distributions
7371*c54f35caSApple OSS Distributions SIMPLEREPORT_UPDATEPREP(buf, data2cpy, size2cpy);
7372*c54f35caSApple OSS Distributions if (size2cpy > (dest->getCapacity() - dest->getLength())) {
7373*c54f35caSApple OSS Distributions rc = kIOReturnOverrun;
7374*c54f35caSApple OSS Distributions break;
7375*c54f35caSApple OSS Distributions }
7376*c54f35caSApple OSS Distributions
7377*c54f35caSApple OSS Distributions SIMPLEREPORT_UPDATERES(kIOReportCopyChannelData, result);
7378*c54f35caSApple OSS Distributions dest->appendBytes(data2cpy, size2cpy);
7379*c54f35caSApple OSS Distributions break;
7380*c54f35caSApple OSS Distributions
7381*c54f35caSApple OSS Distributions default:
7382*c54f35caSApple OSS Distributions break;
7383*c54f35caSApple OSS Distributions }
7384*c54f35caSApple OSS Distributions
7385*c54f35caSApple OSS Distributions PM_UNLOCK();
7386*c54f35caSApple OSS Distributions
7387*c54f35caSApple OSS Distributions return rc;
7388*c54f35caSApple OSS Distributions }
7389*c54f35caSApple OSS Distributions
7390*c54f35caSApple OSS Distributions
7391*c54f35caSApple OSS Distributions
7392*c54f35caSApple OSS Distributions // MARK: -
7393*c54f35caSApple OSS Distributions // MARK: Driver Overrides
7394*c54f35caSApple OSS Distributions
7395*c54f35caSApple OSS Distributions //*********************************************************************************
7396*c54f35caSApple OSS Distributions // [public] setPowerState
7397*c54f35caSApple OSS Distributions //
7398*c54f35caSApple OSS Distributions // Does nothing here. This should be implemented in a subclass driver.
7399*c54f35caSApple OSS Distributions //*********************************************************************************
7400*c54f35caSApple OSS Distributions
7401*c54f35caSApple OSS Distributions IOReturn
setPowerState(unsigned long powerStateOrdinal,IOService * whatDevice)7402*c54f35caSApple OSS Distributions IOService::setPowerState(
7403*c54f35caSApple OSS Distributions unsigned long powerStateOrdinal, IOService * whatDevice )
7404*c54f35caSApple OSS Distributions {
7405*c54f35caSApple OSS Distributions return IOPMNoErr;
7406*c54f35caSApple OSS Distributions }
7407*c54f35caSApple OSS Distributions
7408*c54f35caSApple OSS Distributions //*********************************************************************************
7409*c54f35caSApple OSS Distributions // [public] maxCapabilityForDomainState
7410*c54f35caSApple OSS Distributions //
7411*c54f35caSApple OSS Distributions // Finds the highest power state in the array whose input power requirement
7412*c54f35caSApple OSS Distributions // is equal to the input parameter. Where a more intelligent decision is
7413*c54f35caSApple OSS Distributions // possible, override this in the subclassed driver.
7414*c54f35caSApple OSS Distributions //*********************************************************************************
7415*c54f35caSApple OSS Distributions
7416*c54f35caSApple OSS Distributions IOPMPowerStateIndex
getPowerStateForDomainFlags(IOPMPowerFlags flags)7417*c54f35caSApple OSS Distributions IOService::getPowerStateForDomainFlags( IOPMPowerFlags flags )
7418*c54f35caSApple OSS Distributions {
7419*c54f35caSApple OSS Distributions IOPMPowerStateIndex stateIndex;
7420*c54f35caSApple OSS Distributions
7421*c54f35caSApple OSS Distributions if (!fNumberOfPowerStates) {
7422*c54f35caSApple OSS Distributions return kPowerStateZero;
7423*c54f35caSApple OSS Distributions }
7424*c54f35caSApple OSS Distributions
7425*c54f35caSApple OSS Distributions for (long order = fNumberOfPowerStates - 1; order >= 0; order--) {
7426*c54f35caSApple OSS Distributions stateIndex = fPowerStates[order].stateOrderToIndex;
7427*c54f35caSApple OSS Distributions
7428*c54f35caSApple OSS Distributions if ((flags & fPowerStates[stateIndex].inputPowerFlags) ==
7429*c54f35caSApple OSS Distributions fPowerStates[stateIndex].inputPowerFlags) {
7430*c54f35caSApple OSS Distributions return stateIndex;
7431*c54f35caSApple OSS Distributions }
7432*c54f35caSApple OSS Distributions }
7433*c54f35caSApple OSS Distributions return kPowerStateZero;
7434*c54f35caSApple OSS Distributions }
7435*c54f35caSApple OSS Distributions
7436*c54f35caSApple OSS Distributions unsigned long
maxCapabilityForDomainState(IOPMPowerFlags domainState)7437*c54f35caSApple OSS Distributions IOService::maxCapabilityForDomainState( IOPMPowerFlags domainState )
7438*c54f35caSApple OSS Distributions {
7439*c54f35caSApple OSS Distributions return getPowerStateForDomainFlags(domainState);
7440*c54f35caSApple OSS Distributions }
7441*c54f35caSApple OSS Distributions
7442*c54f35caSApple OSS Distributions //*********************************************************************************
7443*c54f35caSApple OSS Distributions // [public] initialPowerStateForDomainState
7444*c54f35caSApple OSS Distributions //
7445*c54f35caSApple OSS Distributions // Called to query the power state for the initial power transition.
7446*c54f35caSApple OSS Distributions //*********************************************************************************
7447*c54f35caSApple OSS Distributions
7448*c54f35caSApple OSS Distributions unsigned long
initialPowerStateForDomainState(IOPMPowerFlags domainState)7449*c54f35caSApple OSS Distributions IOService::initialPowerStateForDomainState( IOPMPowerFlags domainState )
7450*c54f35caSApple OSS Distributions {
7451*c54f35caSApple OSS Distributions if (fResetPowerStateOnWake && (domainState & kIOPMRootDomainState)) {
7452*c54f35caSApple OSS Distributions // Return lowest power state for any root power domain changes
7453*c54f35caSApple OSS Distributions return kPowerStateZero;
7454*c54f35caSApple OSS Distributions }
7455*c54f35caSApple OSS Distributions
7456*c54f35caSApple OSS Distributions return getPowerStateForDomainFlags(domainState);
7457*c54f35caSApple OSS Distributions }
7458*c54f35caSApple OSS Distributions
7459*c54f35caSApple OSS Distributions //*********************************************************************************
7460*c54f35caSApple OSS Distributions // [public] powerStateForDomainState
7461*c54f35caSApple OSS Distributions //
7462*c54f35caSApple OSS Distributions // This method is not called from PM.
7463*c54f35caSApple OSS Distributions //*********************************************************************************
7464*c54f35caSApple OSS Distributions
7465*c54f35caSApple OSS Distributions unsigned long
powerStateForDomainState(IOPMPowerFlags domainState)7466*c54f35caSApple OSS Distributions IOService::powerStateForDomainState( IOPMPowerFlags domainState )
7467*c54f35caSApple OSS Distributions {
7468*c54f35caSApple OSS Distributions return getPowerStateForDomainFlags(domainState);
7469*c54f35caSApple OSS Distributions }
7470*c54f35caSApple OSS Distributions
7471*c54f35caSApple OSS Distributions #ifndef __LP64__
7472*c54f35caSApple OSS Distributions //*********************************************************************************
7473*c54f35caSApple OSS Distributions // [deprecated] didYouWakeSystem
7474*c54f35caSApple OSS Distributions //
7475*c54f35caSApple OSS Distributions // Does nothing here. This should be implemented in a subclass driver.
7476*c54f35caSApple OSS Distributions //*********************************************************************************
7477*c54f35caSApple OSS Distributions
7478*c54f35caSApple OSS Distributions bool
didYouWakeSystem(void)7479*c54f35caSApple OSS Distributions IOService::didYouWakeSystem( void )
7480*c54f35caSApple OSS Distributions {
7481*c54f35caSApple OSS Distributions return false;
7482*c54f35caSApple OSS Distributions }
7483*c54f35caSApple OSS Distributions #endif /* !__LP64__ */
7484*c54f35caSApple OSS Distributions
7485*c54f35caSApple OSS Distributions //*********************************************************************************
7486*c54f35caSApple OSS Distributions // [public] powerStateWillChangeTo
7487*c54f35caSApple OSS Distributions //
7488*c54f35caSApple OSS Distributions // Does nothing here. This should be implemented in a subclass driver.
7489*c54f35caSApple OSS Distributions //*********************************************************************************
7490*c54f35caSApple OSS Distributions
7491*c54f35caSApple OSS Distributions IOReturn
powerStateWillChangeTo(IOPMPowerFlags,unsigned long,IOService *)7492*c54f35caSApple OSS Distributions IOService::powerStateWillChangeTo( IOPMPowerFlags, unsigned long, IOService * )
7493*c54f35caSApple OSS Distributions {
7494*c54f35caSApple OSS Distributions return kIOPMAckImplied;
7495*c54f35caSApple OSS Distributions }
7496*c54f35caSApple OSS Distributions
7497*c54f35caSApple OSS Distributions //*********************************************************************************
7498*c54f35caSApple OSS Distributions // [public] powerStateDidChangeTo
7499*c54f35caSApple OSS Distributions //
7500*c54f35caSApple OSS Distributions // Does nothing here. This should be implemented in a subclass driver.
7501*c54f35caSApple OSS Distributions //*********************************************************************************
7502*c54f35caSApple OSS Distributions
7503*c54f35caSApple OSS Distributions IOReturn
powerStateDidChangeTo(IOPMPowerFlags,unsigned long,IOService *)7504*c54f35caSApple OSS Distributions IOService::powerStateDidChangeTo( IOPMPowerFlags, unsigned long, IOService * )
7505*c54f35caSApple OSS Distributions {
7506*c54f35caSApple OSS Distributions return kIOPMAckImplied;
7507*c54f35caSApple OSS Distributions }
7508*c54f35caSApple OSS Distributions
7509*c54f35caSApple OSS Distributions //*********************************************************************************
7510*c54f35caSApple OSS Distributions // [protected] powerChangeDone
7511*c54f35caSApple OSS Distributions //
7512*c54f35caSApple OSS Distributions // Called from PM work loop thread.
7513*c54f35caSApple OSS Distributions // Does nothing here. This should be implemented in a subclass policy-maker.
7514*c54f35caSApple OSS Distributions //*********************************************************************************
7515*c54f35caSApple OSS Distributions
7516*c54f35caSApple OSS Distributions void
powerChangeDone(unsigned long)7517*c54f35caSApple OSS Distributions IOService::powerChangeDone( unsigned long )
7518*c54f35caSApple OSS Distributions {
7519*c54f35caSApple OSS Distributions }
7520*c54f35caSApple OSS Distributions
7521*c54f35caSApple OSS Distributions #ifndef __LP64__
7522*c54f35caSApple OSS Distributions //*********************************************************************************
7523*c54f35caSApple OSS Distributions // [deprecated] newTemperature
7524*c54f35caSApple OSS Distributions //
7525*c54f35caSApple OSS Distributions // Does nothing here. This should be implemented in a subclass driver.
7526*c54f35caSApple OSS Distributions //*********************************************************************************
7527*c54f35caSApple OSS Distributions
7528*c54f35caSApple OSS Distributions IOReturn
newTemperature(long currentTemp,IOService * whichZone)7529*c54f35caSApple OSS Distributions IOService::newTemperature( long currentTemp, IOService * whichZone )
7530*c54f35caSApple OSS Distributions {
7531*c54f35caSApple OSS Distributions return IOPMNoErr;
7532*c54f35caSApple OSS Distributions }
7533*c54f35caSApple OSS Distributions #endif /* !__LP64__ */
7534*c54f35caSApple OSS Distributions
7535*c54f35caSApple OSS Distributions //*********************************************************************************
7536*c54f35caSApple OSS Distributions // [public] systemWillShutdown
7537*c54f35caSApple OSS Distributions //
7538*c54f35caSApple OSS Distributions // System shutdown and restart notification.
7539*c54f35caSApple OSS Distributions //*********************************************************************************
7540*c54f35caSApple OSS Distributions
7541*c54f35caSApple OSS Distributions void
systemWillShutdown(IOOptionBits specifier)7542*c54f35caSApple OSS Distributions IOService::systemWillShutdown( IOOptionBits specifier )
7543*c54f35caSApple OSS Distributions {
7544*c54f35caSApple OSS Distributions IOPMrootDomain * rootDomain = IOService::getPMRootDomain();
7545*c54f35caSApple OSS Distributions if (rootDomain) {
7546*c54f35caSApple OSS Distributions rootDomain->acknowledgeSystemWillShutdown( this );
7547*c54f35caSApple OSS Distributions }
7548*c54f35caSApple OSS Distributions }
7549*c54f35caSApple OSS Distributions
7550*c54f35caSApple OSS Distributions // MARK: -
7551*c54f35caSApple OSS Distributions // MARK: PM State Machine
7552*c54f35caSApple OSS Distributions
7553*c54f35caSApple OSS Distributions //*********************************************************************************
7554*c54f35caSApple OSS Distributions // [private static] acquirePMRequest
7555*c54f35caSApple OSS Distributions //*********************************************************************************
7556*c54f35caSApple OSS Distributions
7557*c54f35caSApple OSS Distributions IOPMRequest *
acquirePMRequest(IOService * target,IOOptionBits requestType,IOPMRequest * active)7558*c54f35caSApple OSS Distributions IOService::acquirePMRequest( IOService * target, IOOptionBits requestType,
7559*c54f35caSApple OSS Distributions IOPMRequest * active )
7560*c54f35caSApple OSS Distributions {
7561*c54f35caSApple OSS Distributions IOPMRequest * request;
7562*c54f35caSApple OSS Distributions
7563*c54f35caSApple OSS Distributions assert(target);
7564*c54f35caSApple OSS Distributions
7565*c54f35caSApple OSS Distributions request = IOPMRequest::create();
7566*c54f35caSApple OSS Distributions if (request) {
7567*c54f35caSApple OSS Distributions request->init( target, requestType );
7568*c54f35caSApple OSS Distributions if (active) {
7569*c54f35caSApple OSS Distributions IOPMRequest * root = active->getRootRequest();
7570*c54f35caSApple OSS Distributions if (root) {
7571*c54f35caSApple OSS Distributions request->attachRootRequest(root);
7572*c54f35caSApple OSS Distributions }
7573*c54f35caSApple OSS Distributions }
7574*c54f35caSApple OSS Distributions } else {
7575*c54f35caSApple OSS Distributions PM_ERROR("%s: No memory for PM request type 0x%x\n",
7576*c54f35caSApple OSS Distributions target->getName(), (uint32_t) requestType);
7577*c54f35caSApple OSS Distributions }
7578*c54f35caSApple OSS Distributions return request;
7579*c54f35caSApple OSS Distributions }
7580*c54f35caSApple OSS Distributions
7581*c54f35caSApple OSS Distributions //*********************************************************************************
7582*c54f35caSApple OSS Distributions // [private static] releasePMRequest
7583*c54f35caSApple OSS Distributions //*********************************************************************************
7584*c54f35caSApple OSS Distributions
7585*c54f35caSApple OSS Distributions void
releasePMRequest(IOPMRequest * request)7586*c54f35caSApple OSS Distributions IOService::releasePMRequest( IOPMRequest * request )
7587*c54f35caSApple OSS Distributions {
7588*c54f35caSApple OSS Distributions if (request) {
7589*c54f35caSApple OSS Distributions request->reset();
7590*c54f35caSApple OSS Distributions request->release();
7591*c54f35caSApple OSS Distributions }
7592*c54f35caSApple OSS Distributions }
7593*c54f35caSApple OSS Distributions
7594*c54f35caSApple OSS Distributions //*********************************************************************************
7595*c54f35caSApple OSS Distributions // [private static] submitPMRequest
7596*c54f35caSApple OSS Distributions //*********************************************************************************
7597*c54f35caSApple OSS Distributions
7598*c54f35caSApple OSS Distributions void
submitPMRequest(IOPMRequest * request)7599*c54f35caSApple OSS Distributions IOService::submitPMRequest( IOPMRequest * request )
7600*c54f35caSApple OSS Distributions {
7601*c54f35caSApple OSS Distributions assert( request );
7602*c54f35caSApple OSS Distributions assert( gIOPMReplyQueue );
7603*c54f35caSApple OSS Distributions assert( gIOPMRequestQueue );
7604*c54f35caSApple OSS Distributions
7605*c54f35caSApple OSS Distributions PM_LOG1("[+ %02lx] %p [%p %s] %p %p %p\n",
7606*c54f35caSApple OSS Distributions (long)request->getType(), OBFUSCATE(request),
7607*c54f35caSApple OSS Distributions OBFUSCATE(request->getTarget()), request->getTarget()->getName(),
7608*c54f35caSApple OSS Distributions OBFUSCATE(request->fArg0),
7609*c54f35caSApple OSS Distributions OBFUSCATE(request->fArg1), OBFUSCATE(request->fArg2));
7610*c54f35caSApple OSS Distributions
7611*c54f35caSApple OSS Distributions if (request->isReplyType()) {
7612*c54f35caSApple OSS Distributions gIOPMReplyQueue->queuePMRequest( request );
7613*c54f35caSApple OSS Distributions } else {
7614*c54f35caSApple OSS Distributions gIOPMRequestQueue->queuePMRequest( request );
7615*c54f35caSApple OSS Distributions }
7616*c54f35caSApple OSS Distributions }
7617*c54f35caSApple OSS Distributions
7618*c54f35caSApple OSS Distributions void
submitPMRequests(IOPMRequest ** requests,IOItemCount count)7619*c54f35caSApple OSS Distributions IOService::submitPMRequests( IOPMRequest ** requests, IOItemCount count )
7620*c54f35caSApple OSS Distributions {
7621*c54f35caSApple OSS Distributions assert( requests );
7622*c54f35caSApple OSS Distributions assert( count > 0 );
7623*c54f35caSApple OSS Distributions assert( gIOPMRequestQueue );
7624*c54f35caSApple OSS Distributions
7625*c54f35caSApple OSS Distributions for (IOItemCount i = 0; i < count; i++) {
7626*c54f35caSApple OSS Distributions IOPMRequest * req = requests[i];
7627*c54f35caSApple OSS Distributions PM_LOG1("[+ %02lx] %p [%p %s] %p %p %p\n",
7628*c54f35caSApple OSS Distributions (long)req->getType(), OBFUSCATE(req),
7629*c54f35caSApple OSS Distributions OBFUSCATE(req->getTarget()), req->getTarget()->getName(),
7630*c54f35caSApple OSS Distributions OBFUSCATE(req->fArg0),
7631*c54f35caSApple OSS Distributions OBFUSCATE(req->fArg1), OBFUSCATE(req->fArg2));
7632*c54f35caSApple OSS Distributions }
7633*c54f35caSApple OSS Distributions
7634*c54f35caSApple OSS Distributions gIOPMRequestQueue->queuePMRequestChain( requests, count );
7635*c54f35caSApple OSS Distributions }
7636*c54f35caSApple OSS Distributions
7637*c54f35caSApple OSS Distributions //*********************************************************************************
7638*c54f35caSApple OSS Distributions // [private] actionPMRequestQueue
7639*c54f35caSApple OSS Distributions //
7640*c54f35caSApple OSS Distributions // IOPMRequestQueue::checkForWork() passing a new request to the request target.
7641*c54f35caSApple OSS Distributions //*********************************************************************************
7642*c54f35caSApple OSS Distributions
7643*c54f35caSApple OSS Distributions bool
actionPMRequestQueue(IOPMRequest * request,IOPMRequestQueue * queue)7644*c54f35caSApple OSS Distributions IOService::actionPMRequestQueue(
7645*c54f35caSApple OSS Distributions IOPMRequest * request,
7646*c54f35caSApple OSS Distributions IOPMRequestQueue * queue )
7647*c54f35caSApple OSS Distributions {
7648*c54f35caSApple OSS Distributions bool more;
7649*c54f35caSApple OSS Distributions
7650*c54f35caSApple OSS Distributions if (initialized) {
7651*c54f35caSApple OSS Distributions // Work queue will immediately execute the request if the per-service
7652*c54f35caSApple OSS Distributions // request queue is empty. Note pwrMgt is the target's IOServicePM.
7653*c54f35caSApple OSS Distributions
7654*c54f35caSApple OSS Distributions more = gIOPMWorkQueue->queuePMRequest(request, pwrMgt);
7655*c54f35caSApple OSS Distributions } else {
7656*c54f35caSApple OSS Distributions // Calling PM without PMinit() is not allowed, fail the request.
7657*c54f35caSApple OSS Distributions // Need to signal more when completing attached requests.
7658*c54f35caSApple OSS Distributions
7659*c54f35caSApple OSS Distributions PM_LOG("%s: PM not initialized\n", getName());
7660*c54f35caSApple OSS Distributions PM_LOG1("[- %02x] %p [%p %s] !initialized\n",
7661*c54f35caSApple OSS Distributions request->getType(), OBFUSCATE(request),
7662*c54f35caSApple OSS Distributions OBFUSCATE(this), getName());
7663*c54f35caSApple OSS Distributions
7664*c54f35caSApple OSS Distributions more = gIOPMCompletionQueue->queuePMRequest(request);
7665*c54f35caSApple OSS Distributions if (more) {
7666*c54f35caSApple OSS Distributions gIOPMWorkQueue->incrementProducerCount();
7667*c54f35caSApple OSS Distributions }
7668*c54f35caSApple OSS Distributions }
7669*c54f35caSApple OSS Distributions
7670*c54f35caSApple OSS Distributions return more;
7671*c54f35caSApple OSS Distributions }
7672*c54f35caSApple OSS Distributions
7673*c54f35caSApple OSS Distributions //*********************************************************************************
7674*c54f35caSApple OSS Distributions // [private] actionPMCompletionQueue
7675*c54f35caSApple OSS Distributions //
7676*c54f35caSApple OSS Distributions // IOPMCompletionQueue::checkForWork() passing a completed request to the
7677*c54f35caSApple OSS Distributions // request target.
7678*c54f35caSApple OSS Distributions //*********************************************************************************
7679*c54f35caSApple OSS Distributions
7680*c54f35caSApple OSS Distributions bool
actionPMCompletionQueue(IOPMRequest * request,IOPMCompletionQueue * queue)7681*c54f35caSApple OSS Distributions IOService::actionPMCompletionQueue(
7682*c54f35caSApple OSS Distributions IOPMRequest * request,
7683*c54f35caSApple OSS Distributions IOPMCompletionQueue * queue )
7684*c54f35caSApple OSS Distributions {
7685*c54f35caSApple OSS Distributions bool more = (request->getNextRequest() != NULL);
7686*c54f35caSApple OSS Distributions IOPMRequest * root = request->getRootRequest();
7687*c54f35caSApple OSS Distributions
7688*c54f35caSApple OSS Distributions if (root && (root != request)) {
7689*c54f35caSApple OSS Distributions more = true;
7690*c54f35caSApple OSS Distributions }
7691*c54f35caSApple OSS Distributions if (more) {
7692*c54f35caSApple OSS Distributions gIOPMWorkQueue->incrementProducerCount();
7693*c54f35caSApple OSS Distributions }
7694*c54f35caSApple OSS Distributions
7695*c54f35caSApple OSS Distributions releasePMRequest( request );
7696*c54f35caSApple OSS Distributions return more;
7697*c54f35caSApple OSS Distributions }
7698*c54f35caSApple OSS Distributions
7699*c54f35caSApple OSS Distributions //*********************************************************************************
7700*c54f35caSApple OSS Distributions // [private] actionPMWorkQueueRetire
7701*c54f35caSApple OSS Distributions //
7702*c54f35caSApple OSS Distributions // IOPMWorkQueue::checkForWork() passing a retired request to the request target.
7703*c54f35caSApple OSS Distributions //*********************************************************************************
7704*c54f35caSApple OSS Distributions
7705*c54f35caSApple OSS Distributions bool
actionPMWorkQueueRetire(IOPMRequest * request,IOPMWorkQueue * queue)7706*c54f35caSApple OSS Distributions IOService::actionPMWorkQueueRetire( IOPMRequest * request, IOPMWorkQueue * queue )
7707*c54f35caSApple OSS Distributions {
7708*c54f35caSApple OSS Distributions assert(request && queue);
7709*c54f35caSApple OSS Distributions
7710*c54f35caSApple OSS Distributions PM_LOG1("[- %02x] %p [%p %s] state %d, busy %d\n",
7711*c54f35caSApple OSS Distributions request->getType(), OBFUSCATE(request),
7712*c54f35caSApple OSS Distributions OBFUSCATE(this), getName(),
7713*c54f35caSApple OSS Distributions fMachineState, gIOPMBusyRequestCount);
7714*c54f35caSApple OSS Distributions
7715*c54f35caSApple OSS Distributions // Catch requests created by idleTimerExpired()
7716*c54f35caSApple OSS Distributions if (request->getType() == kIOPMRequestTypeActivityTickle) {
7717*c54f35caSApple OSS Distributions uint32_t tickleFlags = (uint32_t)(uintptr_t) request->fArg1;
7718*c54f35caSApple OSS Distributions
7719*c54f35caSApple OSS Distributions if ((tickleFlags & kTickleTypePowerDrop) && fIdleTimerPeriod) {
7720*c54f35caSApple OSS Distributions restartIdleTimer();
7721*c54f35caSApple OSS Distributions } else if (tickleFlags == (kTickleTypeActivity | kTickleTypePowerRise)) {
7722*c54f35caSApple OSS Distributions // Invalidate any idle power drop that got queued while
7723*c54f35caSApple OSS Distributions // processing this request.
7724*c54f35caSApple OSS Distributions fIdleTimerGeneration++;
7725*c54f35caSApple OSS Distributions }
7726*c54f35caSApple OSS Distributions }
7727*c54f35caSApple OSS Distributions
7728*c54f35caSApple OSS Distributions // When the completed request is linked, tell work queue there is
7729*c54f35caSApple OSS Distributions // more work pending.
7730*c54f35caSApple OSS Distributions
7731*c54f35caSApple OSS Distributions return gIOPMCompletionQueue->queuePMRequest( request );
7732*c54f35caSApple OSS Distributions }
7733*c54f35caSApple OSS Distributions
7734*c54f35caSApple OSS Distributions //*********************************************************************************
7735*c54f35caSApple OSS Distributions // [private] isPMBlocked
7736*c54f35caSApple OSS Distributions //
7737*c54f35caSApple OSS Distributions // Check if machine state transition is blocked.
7738*c54f35caSApple OSS Distributions //*********************************************************************************
7739*c54f35caSApple OSS Distributions
7740*c54f35caSApple OSS Distributions bool
isPMBlocked(IOPMRequest * request,int count)7741*c54f35caSApple OSS Distributions IOService::isPMBlocked( IOPMRequest * request, int count )
7742*c54f35caSApple OSS Distributions {
7743*c54f35caSApple OSS Distributions int reason = 0;
7744*c54f35caSApple OSS Distributions
7745*c54f35caSApple OSS Distributions do {
7746*c54f35caSApple OSS Distributions if (kIOPM_Finished == fMachineState) {
7747*c54f35caSApple OSS Distributions break;
7748*c54f35caSApple OSS Distributions }
7749*c54f35caSApple OSS Distributions
7750*c54f35caSApple OSS Distributions if (kIOPM_DriverThreadCallDone == fMachineState) {
7751*c54f35caSApple OSS Distributions // 5 = kDriverCallInformPreChange
7752*c54f35caSApple OSS Distributions // 6 = kDriverCallInformPostChange
7753*c54f35caSApple OSS Distributions // 7 = kDriverCallSetPowerState
7754*c54f35caSApple OSS Distributions // 8 = kRootDomainInformPreChange
7755*c54f35caSApple OSS Distributions if (fDriverCallBusy) {
7756*c54f35caSApple OSS Distributions reason = 5 + fDriverCallReason;
7757*c54f35caSApple OSS Distributions }
7758*c54f35caSApple OSS Distributions break;
7759*c54f35caSApple OSS Distributions }
7760*c54f35caSApple OSS Distributions
7761*c54f35caSApple OSS Distributions // Waiting on driver's setPowerState() timeout.
7762*c54f35caSApple OSS Distributions if (fDriverTimer) {
7763*c54f35caSApple OSS Distributions reason = 1; break;
7764*c54f35caSApple OSS Distributions }
7765*c54f35caSApple OSS Distributions
7766*c54f35caSApple OSS Distributions // Child or interested driver acks pending.
7767*c54f35caSApple OSS Distributions if (fHeadNotePendingAcks) {
7768*c54f35caSApple OSS Distributions reason = 2; break;
7769*c54f35caSApple OSS Distributions }
7770*c54f35caSApple OSS Distributions
7771*c54f35caSApple OSS Distributions // Waiting on apps or priority power interest clients.
7772*c54f35caSApple OSS Distributions if (fResponseArray) {
7773*c54f35caSApple OSS Distributions reason = 3; break;
7774*c54f35caSApple OSS Distributions }
7775*c54f35caSApple OSS Distributions
7776*c54f35caSApple OSS Distributions #if USE_SETTLE_TIMER
7777*c54f35caSApple OSS Distributions // Waiting on settle timer expiration.
7778*c54f35caSApple OSS Distributions if (fSettleTimeUS) {
7779*c54f35caSApple OSS Distributions reason = 4; break;
7780*c54f35caSApple OSS Distributions }
7781*c54f35caSApple OSS Distributions #endif
7782*c54f35caSApple OSS Distributions } while (false);
7783*c54f35caSApple OSS Distributions
7784*c54f35caSApple OSS Distributions fWaitReason = reason;
7785*c54f35caSApple OSS Distributions
7786*c54f35caSApple OSS Distributions if (reason) {
7787*c54f35caSApple OSS Distributions if (count) {
7788*c54f35caSApple OSS Distributions PM_LOG1("[B %02x] %p [%p %s] state %d, reason %d\n",
7789*c54f35caSApple OSS Distributions request->getType(), OBFUSCATE(request),
7790*c54f35caSApple OSS Distributions OBFUSCATE(this), getName(),
7791*c54f35caSApple OSS Distributions fMachineState, reason);
7792*c54f35caSApple OSS Distributions }
7793*c54f35caSApple OSS Distributions
7794*c54f35caSApple OSS Distributions return true;
7795*c54f35caSApple OSS Distributions }
7796*c54f35caSApple OSS Distributions
7797*c54f35caSApple OSS Distributions return false;
7798*c54f35caSApple OSS Distributions }
7799*c54f35caSApple OSS Distributions
7800*c54f35caSApple OSS Distributions //*********************************************************************************
7801*c54f35caSApple OSS Distributions // [private] actionPMWorkQueueInvoke
7802*c54f35caSApple OSS Distributions //
7803*c54f35caSApple OSS Distributions // IOPMWorkQueue::checkForWork() passing a request to the
7804*c54f35caSApple OSS Distributions // request target for execution.
7805*c54f35caSApple OSS Distributions //*********************************************************************************
7806*c54f35caSApple OSS Distributions
7807*c54f35caSApple OSS Distributions bool
actionPMWorkQueueInvoke(IOPMRequest * request,IOPMWorkQueue * queue)7808*c54f35caSApple OSS Distributions IOService::actionPMWorkQueueInvoke( IOPMRequest * request, IOPMWorkQueue * queue )
7809*c54f35caSApple OSS Distributions {
7810*c54f35caSApple OSS Distributions bool done = false;
7811*c54f35caSApple OSS Distributions int loop = 0;
7812*c54f35caSApple OSS Distributions
7813*c54f35caSApple OSS Distributions assert(request && queue);
7814*c54f35caSApple OSS Distributions
7815*c54f35caSApple OSS Distributions while (isPMBlocked(request, loop++) == false) {
7816*c54f35caSApple OSS Distributions PM_LOG1("[W %02x] %p [%p %s] state %d\n",
7817*c54f35caSApple OSS Distributions request->getType(), OBFUSCATE(request),
7818*c54f35caSApple OSS Distributions OBFUSCATE(this), getName(), fMachineState);
7819*c54f35caSApple OSS Distributions
7820*c54f35caSApple OSS Distributions gIOPMRequest = request;
7821*c54f35caSApple OSS Distributions gIOPMWorkInvokeCount++;
7822*c54f35caSApple OSS Distributions
7823*c54f35caSApple OSS Distributions // Every PM machine states must be handled in one of the cases below.
7824*c54f35caSApple OSS Distributions
7825*c54f35caSApple OSS Distributions switch (fMachineState) {
7826*c54f35caSApple OSS Distributions case kIOPM_Finished:
7827*c54f35caSApple OSS Distributions start_watchdog_timer();
7828*c54f35caSApple OSS Distributions
7829*c54f35caSApple OSS Distributions executePMRequest( request );
7830*c54f35caSApple OSS Distributions break;
7831*c54f35caSApple OSS Distributions
7832*c54f35caSApple OSS Distributions case kIOPM_OurChangeTellClientsPowerDown:
7833*c54f35caSApple OSS Distributions // Root domain might self cancel due to assertions.
7834*c54f35caSApple OSS Distributions if (IS_ROOT_DOMAIN) {
7835*c54f35caSApple OSS Distributions bool cancel = (bool) fDoNotPowerDown;
7836*c54f35caSApple OSS Distributions getPMRootDomain()->askChangeDownDone(
7837*c54f35caSApple OSS Distributions &fHeadNoteChangeFlags, &cancel);
7838*c54f35caSApple OSS Distributions fDoNotPowerDown = cancel;
7839*c54f35caSApple OSS Distributions }
7840*c54f35caSApple OSS Distributions
7841*c54f35caSApple OSS Distributions // askChangeDown() done, was it vetoed?
7842*c54f35caSApple OSS Distributions if (!fDoNotPowerDown) {
7843*c54f35caSApple OSS Distributions // no, we can continue
7844*c54f35caSApple OSS Distributions OurChangeTellClientsPowerDown();
7845*c54f35caSApple OSS Distributions } else {
7846*c54f35caSApple OSS Distributions OUR_PMLog(kPMLogIdleCancel, (uintptr_t) this, fMachineState);
7847*c54f35caSApple OSS Distributions PM_ERROR("%s: idle cancel, state %u\n", fName, fMachineState);
7848*c54f35caSApple OSS Distributions if (IS_ROOT_DOMAIN) {
7849*c54f35caSApple OSS Distributions // RootDomain already sent "WillSleep" to its clients
7850*c54f35caSApple OSS Distributions tellChangeUp(fCurrentPowerState);
7851*c54f35caSApple OSS Distributions } else {
7852*c54f35caSApple OSS Distributions tellNoChangeDown(fHeadNotePowerState);
7853*c54f35caSApple OSS Distributions }
7854*c54f35caSApple OSS Distributions // mark the change note un-actioned
7855*c54f35caSApple OSS Distributions fHeadNoteChangeFlags |= kIOPMNotDone;
7856*c54f35caSApple OSS Distributions // and we're done
7857*c54f35caSApple OSS Distributions OurChangeFinish();
7858*c54f35caSApple OSS Distributions }
7859*c54f35caSApple OSS Distributions break;
7860*c54f35caSApple OSS Distributions
7861*c54f35caSApple OSS Distributions case kIOPM_OurChangeTellUserPMPolicyPowerDown:
7862*c54f35caSApple OSS Distributions // PMRD: tellChangeDown/kNotifyApps done, was it cancelled?
7863*c54f35caSApple OSS Distributions if (fDoNotPowerDown) {
7864*c54f35caSApple OSS Distributions OUR_PMLog(kPMLogIdleCancel, (uintptr_t) this, fMachineState);
7865*c54f35caSApple OSS Distributions PM_ERROR("%s: idle cancel, state %u\n", fName, fMachineState);
7866*c54f35caSApple OSS Distributions if (IS_ROOT_DOMAIN) {
7867*c54f35caSApple OSS Distributions // RootDomain already sent "WillSleep" to its clients
7868*c54f35caSApple OSS Distributions tellChangeUp(fCurrentPowerState);
7869*c54f35caSApple OSS Distributions } else {
7870*c54f35caSApple OSS Distributions tellNoChangeDown(fHeadNotePowerState);
7871*c54f35caSApple OSS Distributions }
7872*c54f35caSApple OSS Distributions // mark the change note un-actioned
7873*c54f35caSApple OSS Distributions fHeadNoteChangeFlags |= kIOPMNotDone;
7874*c54f35caSApple OSS Distributions // and we're done
7875*c54f35caSApple OSS Distributions OurChangeFinish();
7876*c54f35caSApple OSS Distributions } else {
7877*c54f35caSApple OSS Distributions OurChangeTellUserPMPolicyPowerDown();
7878*c54f35caSApple OSS Distributions }
7879*c54f35caSApple OSS Distributions break;
7880*c54f35caSApple OSS Distributions
7881*c54f35caSApple OSS Distributions case kIOPM_OurChangeTellPriorityClientsPowerDown:
7882*c54f35caSApple OSS Distributions // PMRD: LastCallBeforeSleep notify done
7883*c54f35caSApple OSS Distributions // Non-PMRD: tellChangeDown/kNotifyApps done
7884*c54f35caSApple OSS Distributions if (fDoNotPowerDown) {
7885*c54f35caSApple OSS Distributions OUR_PMLog(kPMLogIdleCancel, (uintptr_t) this, fMachineState);
7886*c54f35caSApple OSS Distributions PM_ERROR("%s: idle revert, state %u\n", fName, fMachineState);
7887*c54f35caSApple OSS Distributions // no, tell clients we're back in the old state
7888*c54f35caSApple OSS Distributions tellChangeUp(fCurrentPowerState);
7889*c54f35caSApple OSS Distributions // mark the change note un-actioned
7890*c54f35caSApple OSS Distributions fHeadNoteChangeFlags |= kIOPMNotDone;
7891*c54f35caSApple OSS Distributions // and we're done
7892*c54f35caSApple OSS Distributions OurChangeFinish();
7893*c54f35caSApple OSS Distributions } else {
7894*c54f35caSApple OSS Distributions // yes, we can continue
7895*c54f35caSApple OSS Distributions OurChangeTellPriorityClientsPowerDown();
7896*c54f35caSApple OSS Distributions }
7897*c54f35caSApple OSS Distributions break;
7898*c54f35caSApple OSS Distributions
7899*c54f35caSApple OSS Distributions case kIOPM_OurChangeNotifyInterestedDriversWillChange:
7900*c54f35caSApple OSS Distributions OurChangeNotifyInterestedDriversWillChange();
7901*c54f35caSApple OSS Distributions break;
7902*c54f35caSApple OSS Distributions
7903*c54f35caSApple OSS Distributions case kIOPM_OurChangeSetPowerState:
7904*c54f35caSApple OSS Distributions OurChangeSetPowerState();
7905*c54f35caSApple OSS Distributions break;
7906*c54f35caSApple OSS Distributions
7907*c54f35caSApple OSS Distributions case kIOPM_OurChangeWaitForPowerSettle:
7908*c54f35caSApple OSS Distributions OurChangeWaitForPowerSettle();
7909*c54f35caSApple OSS Distributions break;
7910*c54f35caSApple OSS Distributions
7911*c54f35caSApple OSS Distributions case kIOPM_OurChangeNotifyInterestedDriversDidChange:
7912*c54f35caSApple OSS Distributions OurChangeNotifyInterestedDriversDidChange();
7913*c54f35caSApple OSS Distributions break;
7914*c54f35caSApple OSS Distributions
7915*c54f35caSApple OSS Distributions case kIOPM_OurChangeTellCapabilityDidChange:
7916*c54f35caSApple OSS Distributions OurChangeTellCapabilityDidChange();
7917*c54f35caSApple OSS Distributions break;
7918*c54f35caSApple OSS Distributions
7919*c54f35caSApple OSS Distributions case kIOPM_OurChangeFinish:
7920*c54f35caSApple OSS Distributions OurChangeFinish();
7921*c54f35caSApple OSS Distributions break;
7922*c54f35caSApple OSS Distributions
7923*c54f35caSApple OSS Distributions case kIOPM_ParentChangeTellPriorityClientsPowerDown:
7924*c54f35caSApple OSS Distributions ParentChangeTellPriorityClientsPowerDown();
7925*c54f35caSApple OSS Distributions break;
7926*c54f35caSApple OSS Distributions
7927*c54f35caSApple OSS Distributions case kIOPM_ParentChangeNotifyInterestedDriversWillChange:
7928*c54f35caSApple OSS Distributions ParentChangeNotifyInterestedDriversWillChange();
7929*c54f35caSApple OSS Distributions break;
7930*c54f35caSApple OSS Distributions
7931*c54f35caSApple OSS Distributions case kIOPM_ParentChangeSetPowerState:
7932*c54f35caSApple OSS Distributions ParentChangeSetPowerState();
7933*c54f35caSApple OSS Distributions break;
7934*c54f35caSApple OSS Distributions
7935*c54f35caSApple OSS Distributions case kIOPM_ParentChangeWaitForPowerSettle:
7936*c54f35caSApple OSS Distributions ParentChangeWaitForPowerSettle();
7937*c54f35caSApple OSS Distributions break;
7938*c54f35caSApple OSS Distributions
7939*c54f35caSApple OSS Distributions case kIOPM_ParentChangeNotifyInterestedDriversDidChange:
7940*c54f35caSApple OSS Distributions ParentChangeNotifyInterestedDriversDidChange();
7941*c54f35caSApple OSS Distributions break;
7942*c54f35caSApple OSS Distributions
7943*c54f35caSApple OSS Distributions case kIOPM_ParentChangeTellCapabilityDidChange:
7944*c54f35caSApple OSS Distributions ParentChangeTellCapabilityDidChange();
7945*c54f35caSApple OSS Distributions break;
7946*c54f35caSApple OSS Distributions
7947*c54f35caSApple OSS Distributions case kIOPM_ParentChangeAcknowledgePowerChange:
7948*c54f35caSApple OSS Distributions ParentChangeAcknowledgePowerChange();
7949*c54f35caSApple OSS Distributions break;
7950*c54f35caSApple OSS Distributions
7951*c54f35caSApple OSS Distributions case kIOPM_DriverThreadCallDone:
7952*c54f35caSApple OSS Distributions switch (fDriverCallReason) {
7953*c54f35caSApple OSS Distributions case kDriverCallInformPreChange:
7954*c54f35caSApple OSS Distributions case kDriverCallInformPostChange:
7955*c54f35caSApple OSS Distributions notifyInterestedDriversDone();
7956*c54f35caSApple OSS Distributions break;
7957*c54f35caSApple OSS Distributions case kDriverCallSetPowerState:
7958*c54f35caSApple OSS Distributions notifyControllingDriverDone();
7959*c54f35caSApple OSS Distributions break;
7960*c54f35caSApple OSS Distributions case kRootDomainInformPreChange:
7961*c54f35caSApple OSS Distributions notifyRootDomainDone();
7962*c54f35caSApple OSS Distributions break;
7963*c54f35caSApple OSS Distributions default:
7964*c54f35caSApple OSS Distributions panic("%s: bad call reason %x",
7965*c54f35caSApple OSS Distributions getName(), fDriverCallReason);
7966*c54f35caSApple OSS Distributions }
7967*c54f35caSApple OSS Distributions break;
7968*c54f35caSApple OSS Distributions
7969*c54f35caSApple OSS Distributions case kIOPM_NotifyChildrenOrdered:
7970*c54f35caSApple OSS Distributions notifyChildrenOrdered();
7971*c54f35caSApple OSS Distributions break;
7972*c54f35caSApple OSS Distributions
7973*c54f35caSApple OSS Distributions case kIOPM_NotifyChildrenDelayed:
7974*c54f35caSApple OSS Distributions notifyChildrenDelayed();
7975*c54f35caSApple OSS Distributions break;
7976*c54f35caSApple OSS Distributions
7977*c54f35caSApple OSS Distributions case kIOPM_NotifyChildrenStart:
7978*c54f35caSApple OSS Distributions // pop notifyAll() state saved by notifyInterestedDriversDone()
7979*c54f35caSApple OSS Distributions MS_POP();
7980*c54f35caSApple OSS Distributions notifyRootDomain();
7981*c54f35caSApple OSS Distributions break;
7982*c54f35caSApple OSS Distributions
7983*c54f35caSApple OSS Distributions case kIOPM_SyncTellClientsPowerDown:
7984*c54f35caSApple OSS Distributions // Root domain might self cancel due to assertions.
7985*c54f35caSApple OSS Distributions if (IS_ROOT_DOMAIN) {
7986*c54f35caSApple OSS Distributions bool cancel = (bool) fDoNotPowerDown;
7987*c54f35caSApple OSS Distributions getPMRootDomain()->askChangeDownDone(
7988*c54f35caSApple OSS Distributions &fHeadNoteChangeFlags, &cancel);
7989*c54f35caSApple OSS Distributions fDoNotPowerDown = cancel;
7990*c54f35caSApple OSS Distributions }
7991*c54f35caSApple OSS Distributions if (!fDoNotPowerDown) {
7992*c54f35caSApple OSS Distributions fMachineState = kIOPM_SyncTellPriorityClientsPowerDown;
7993*c54f35caSApple OSS Distributions fOutOfBandParameter = kNotifyApps;
7994*c54f35caSApple OSS Distributions tellChangeDown(fHeadNotePowerState);
7995*c54f35caSApple OSS Distributions } else {
7996*c54f35caSApple OSS Distributions // Cancelled by IOPMrootDomain::askChangeDownDone() or
7997*c54f35caSApple OSS Distributions // askChangeDown/kNotifyApps
7998*c54f35caSApple OSS Distributions OUR_PMLog(kPMLogIdleCancel, (uintptr_t) this, fMachineState);
7999*c54f35caSApple OSS Distributions PM_ERROR("%s: idle cancel, state %u\n", fName, fMachineState);
8000*c54f35caSApple OSS Distributions tellNoChangeDown(fHeadNotePowerState);
8001*c54f35caSApple OSS Distributions fHeadNoteChangeFlags |= kIOPMNotDone;
8002*c54f35caSApple OSS Distributions OurChangeFinish();
8003*c54f35caSApple OSS Distributions }
8004*c54f35caSApple OSS Distributions break;
8005*c54f35caSApple OSS Distributions
8006*c54f35caSApple OSS Distributions case kIOPM_SyncTellPriorityClientsPowerDown:
8007*c54f35caSApple OSS Distributions // PMRD: tellChangeDown/kNotifyApps done, was it cancelled?
8008*c54f35caSApple OSS Distributions if (!fDoNotPowerDown) {
8009*c54f35caSApple OSS Distributions fMachineState = kIOPM_SyncNotifyWillChange;
8010*c54f35caSApple OSS Distributions fOutOfBandParameter = kNotifyPriority;
8011*c54f35caSApple OSS Distributions tellChangeDown(fHeadNotePowerState);
8012*c54f35caSApple OSS Distributions } else {
8013*c54f35caSApple OSS Distributions OUR_PMLog(kPMLogIdleCancel, (uintptr_t) this, fMachineState);
8014*c54f35caSApple OSS Distributions PM_ERROR("%s: idle revert, state %u\n", fName, fMachineState);
8015*c54f35caSApple OSS Distributions tellChangeUp(fCurrentPowerState);
8016*c54f35caSApple OSS Distributions fHeadNoteChangeFlags |= kIOPMNotDone;
8017*c54f35caSApple OSS Distributions OurChangeFinish();
8018*c54f35caSApple OSS Distributions }
8019*c54f35caSApple OSS Distributions break;
8020*c54f35caSApple OSS Distributions
8021*c54f35caSApple OSS Distributions case kIOPM_SyncNotifyWillChange:
8022*c54f35caSApple OSS Distributions if (kIOPMSyncNoChildNotify & fHeadNoteChangeFlags) {
8023*c54f35caSApple OSS Distributions fMachineState = kIOPM_SyncFinish;
8024*c54f35caSApple OSS Distributions continue;
8025*c54f35caSApple OSS Distributions }
8026*c54f35caSApple OSS Distributions fMachineState = kIOPM_SyncNotifyDidChange;
8027*c54f35caSApple OSS Distributions fDriverCallReason = kDriverCallInformPreChange;
8028*c54f35caSApple OSS Distributions notifyChildren();
8029*c54f35caSApple OSS Distributions break;
8030*c54f35caSApple OSS Distributions
8031*c54f35caSApple OSS Distributions case kIOPM_SyncNotifyDidChange:
8032*c54f35caSApple OSS Distributions fIsPreChange = false;
8033*c54f35caSApple OSS Distributions
8034*c54f35caSApple OSS Distributions if (fHeadNoteChangeFlags & kIOPMParentInitiated) {
8035*c54f35caSApple OSS Distributions fMachineState = kIOPM_SyncFinish;
8036*c54f35caSApple OSS Distributions } else {
8037*c54f35caSApple OSS Distributions assert(IS_ROOT_DOMAIN);
8038*c54f35caSApple OSS Distributions fMachineState = kIOPM_SyncTellCapabilityDidChange;
8039*c54f35caSApple OSS Distributions }
8040*c54f35caSApple OSS Distributions
8041*c54f35caSApple OSS Distributions fDriverCallReason = kDriverCallInformPostChange;
8042*c54f35caSApple OSS Distributions notifyChildren();
8043*c54f35caSApple OSS Distributions break;
8044*c54f35caSApple OSS Distributions
8045*c54f35caSApple OSS Distributions case kIOPM_SyncTellCapabilityDidChange:
8046*c54f35caSApple OSS Distributions tellSystemCapabilityChange( kIOPM_SyncFinish );
8047*c54f35caSApple OSS Distributions break;
8048*c54f35caSApple OSS Distributions
8049*c54f35caSApple OSS Distributions case kIOPM_SyncFinish:
8050*c54f35caSApple OSS Distributions if (fHeadNoteChangeFlags & kIOPMParentInitiated) {
8051*c54f35caSApple OSS Distributions ParentChangeAcknowledgePowerChange();
8052*c54f35caSApple OSS Distributions } else {
8053*c54f35caSApple OSS Distributions OurChangeFinish();
8054*c54f35caSApple OSS Distributions }
8055*c54f35caSApple OSS Distributions break;
8056*c54f35caSApple OSS Distributions
8057*c54f35caSApple OSS Distributions case kIOPM_TellCapabilityChangeDone:
8058*c54f35caSApple OSS Distributions if (fIsPreChange) {
8059*c54f35caSApple OSS Distributions if (fOutOfBandParameter == kNotifyCapabilityChangePriority) {
8060*c54f35caSApple OSS Distributions MS_POP(); // MS passed to tellSystemCapabilityChange()
8061*c54f35caSApple OSS Distributions continue;
8062*c54f35caSApple OSS Distributions }
8063*c54f35caSApple OSS Distributions fOutOfBandParameter = kNotifyCapabilityChangePriority;
8064*c54f35caSApple OSS Distributions } else {
8065*c54f35caSApple OSS Distributions if (fOutOfBandParameter == kNotifyCapabilityChangeApps) {
8066*c54f35caSApple OSS Distributions MS_POP(); // MS passed to tellSystemCapabilityChange()
8067*c54f35caSApple OSS Distributions continue;
8068*c54f35caSApple OSS Distributions }
8069*c54f35caSApple OSS Distributions fOutOfBandParameter = kNotifyCapabilityChangeApps;
8070*c54f35caSApple OSS Distributions }
8071*c54f35caSApple OSS Distributions tellClientsWithResponse( fOutOfBandMessage );
8072*c54f35caSApple OSS Distributions break;
8073*c54f35caSApple OSS Distributions
8074*c54f35caSApple OSS Distributions default:
8075*c54f35caSApple OSS Distributions panic("PMWorkQueueInvoke: unknown machine state %x",
8076*c54f35caSApple OSS Distributions fMachineState);
8077*c54f35caSApple OSS Distributions }
8078*c54f35caSApple OSS Distributions
8079*c54f35caSApple OSS Distributions gIOPMRequest = NULL;
8080*c54f35caSApple OSS Distributions
8081*c54f35caSApple OSS Distributions if (fMachineState == kIOPM_Finished) {
8082*c54f35caSApple OSS Distributions stop_watchdog_timer();
8083*c54f35caSApple OSS Distributions done = true;
8084*c54f35caSApple OSS Distributions break;
8085*c54f35caSApple OSS Distributions }
8086*c54f35caSApple OSS Distributions }
8087*c54f35caSApple OSS Distributions
8088*c54f35caSApple OSS Distributions return done;
8089*c54f35caSApple OSS Distributions }
8090*c54f35caSApple OSS Distributions
8091*c54f35caSApple OSS Distributions //*********************************************************************************
8092*c54f35caSApple OSS Distributions // [private] executePMRequest
8093*c54f35caSApple OSS Distributions //*********************************************************************************
8094*c54f35caSApple OSS Distributions
8095*c54f35caSApple OSS Distributions void
executePMRequest(IOPMRequest * request)8096*c54f35caSApple OSS Distributions IOService::executePMRequest( IOPMRequest * request )
8097*c54f35caSApple OSS Distributions {
8098*c54f35caSApple OSS Distributions assert( kIOPM_Finished == fMachineState );
8099*c54f35caSApple OSS Distributions
8100*c54f35caSApple OSS Distributions switch (request->getType()) {
8101*c54f35caSApple OSS Distributions case kIOPMRequestTypePMStop:
8102*c54f35caSApple OSS Distributions handlePMstop( request );
8103*c54f35caSApple OSS Distributions break;
8104*c54f35caSApple OSS Distributions
8105*c54f35caSApple OSS Distributions case kIOPMRequestTypeAddPowerChild1:
8106*c54f35caSApple OSS Distributions addPowerChild1( request );
8107*c54f35caSApple OSS Distributions break;
8108*c54f35caSApple OSS Distributions
8109*c54f35caSApple OSS Distributions case kIOPMRequestTypeAddPowerChild2:
8110*c54f35caSApple OSS Distributions addPowerChild2( request );
8111*c54f35caSApple OSS Distributions break;
8112*c54f35caSApple OSS Distributions
8113*c54f35caSApple OSS Distributions case kIOPMRequestTypeAddPowerChild3:
8114*c54f35caSApple OSS Distributions addPowerChild3( request );
8115*c54f35caSApple OSS Distributions break;
8116*c54f35caSApple OSS Distributions
8117*c54f35caSApple OSS Distributions case kIOPMRequestTypeRegisterPowerDriver:
8118*c54f35caSApple OSS Distributions handleRegisterPowerDriver( request );
8119*c54f35caSApple OSS Distributions break;
8120*c54f35caSApple OSS Distributions
8121*c54f35caSApple OSS Distributions case kIOPMRequestTypeAdjustPowerState:
8122*c54f35caSApple OSS Distributions fAdjustPowerScheduled = false;
8123*c54f35caSApple OSS Distributions adjustPowerState();
8124*c54f35caSApple OSS Distributions break;
8125*c54f35caSApple OSS Distributions
8126*c54f35caSApple OSS Distributions case kIOPMRequestTypePowerDomainWillChange:
8127*c54f35caSApple OSS Distributions handlePowerDomainWillChangeTo( request );
8128*c54f35caSApple OSS Distributions break;
8129*c54f35caSApple OSS Distributions
8130*c54f35caSApple OSS Distributions case kIOPMRequestTypePowerDomainDidChange:
8131*c54f35caSApple OSS Distributions handlePowerDomainDidChangeTo( request );
8132*c54f35caSApple OSS Distributions break;
8133*c54f35caSApple OSS Distributions
8134*c54f35caSApple OSS Distributions case kIOPMRequestTypeRequestPowerState:
8135*c54f35caSApple OSS Distributions case kIOPMRequestTypeRequestPowerStateOverride:
8136*c54f35caSApple OSS Distributions handleRequestPowerState( request );
8137*c54f35caSApple OSS Distributions break;
8138*c54f35caSApple OSS Distributions
8139*c54f35caSApple OSS Distributions case kIOPMRequestTypePowerOverrideOnPriv:
8140*c54f35caSApple OSS Distributions case kIOPMRequestTypePowerOverrideOffPriv:
8141*c54f35caSApple OSS Distributions handlePowerOverrideChanged( request );
8142*c54f35caSApple OSS Distributions break;
8143*c54f35caSApple OSS Distributions
8144*c54f35caSApple OSS Distributions case kIOPMRequestTypeActivityTickle:
8145*c54f35caSApple OSS Distributions handleActivityTickle( request );
8146*c54f35caSApple OSS Distributions break;
8147*c54f35caSApple OSS Distributions
8148*c54f35caSApple OSS Distributions case kIOPMRequestTypeSynchronizePowerTree:
8149*c54f35caSApple OSS Distributions handleSynchronizePowerTree( request );
8150*c54f35caSApple OSS Distributions break;
8151*c54f35caSApple OSS Distributions
8152*c54f35caSApple OSS Distributions case kIOPMRequestTypeSetIdleTimerPeriod:
8153*c54f35caSApple OSS Distributions {
8154*c54f35caSApple OSS Distributions fIdleTimerPeriod = (typeof(fIdleTimerPeriod))(uintptr_t) request->fArg0;
8155*c54f35caSApple OSS Distributions fNextIdleTimerPeriod = fIdleTimerPeriod;
8156*c54f35caSApple OSS Distributions if ((false == fLockedFlags.PMStop) && (fIdleTimerPeriod > 0)) {
8157*c54f35caSApple OSS Distributions restartIdleTimer();
8158*c54f35caSApple OSS Distributions }
8159*c54f35caSApple OSS Distributions }
8160*c54f35caSApple OSS Distributions break;
8161*c54f35caSApple OSS Distributions
8162*c54f35caSApple OSS Distributions case kIOPMRequestTypeIgnoreIdleTimer:
8163*c54f35caSApple OSS Distributions fIdleTimerIgnored = request->fArg0 ? 1 : 0;
8164*c54f35caSApple OSS Distributions break;
8165*c54f35caSApple OSS Distributions
8166*c54f35caSApple OSS Distributions case kIOPMRequestTypeQuiescePowerTree:
8167*c54f35caSApple OSS Distributions gIOPMWorkQueue->finishQuiesceRequest(request);
8168*c54f35caSApple OSS Distributions break;
8169*c54f35caSApple OSS Distributions
8170*c54f35caSApple OSS Distributions case kIOPMRequestTypeDeferredActivityTickle:
8171*c54f35caSApple OSS Distributions handleDeferredActivityTickle(request);
8172*c54f35caSApple OSS Distributions break;
8173*c54f35caSApple OSS Distributions
8174*c54f35caSApple OSS Distributions default:
8175*c54f35caSApple OSS Distributions panic("executePMRequest: unknown request type %x", request->getType());
8176*c54f35caSApple OSS Distributions }
8177*c54f35caSApple OSS Distributions }
8178*c54f35caSApple OSS Distributions
8179*c54f35caSApple OSS Distributions //*********************************************************************************
8180*c54f35caSApple OSS Distributions // [private] actionPMReplyQueue
8181*c54f35caSApple OSS Distributions //
8182*c54f35caSApple OSS Distributions // IOPMRequestQueue::checkForWork() passing a reply-type request to the
8183*c54f35caSApple OSS Distributions // request target.
8184*c54f35caSApple OSS Distributions //*********************************************************************************
8185*c54f35caSApple OSS Distributions
8186*c54f35caSApple OSS Distributions bool
actionPMReplyQueue(IOPMRequest * request,IOPMRequestQueue * queue)8187*c54f35caSApple OSS Distributions IOService::actionPMReplyQueue( IOPMRequest * request, IOPMRequestQueue * queue )
8188*c54f35caSApple OSS Distributions {
8189*c54f35caSApple OSS Distributions bool more = false;
8190*c54f35caSApple OSS Distributions
8191*c54f35caSApple OSS Distributions assert( request && queue );
8192*c54f35caSApple OSS Distributions assert( request->isReplyType());
8193*c54f35caSApple OSS Distributions
8194*c54f35caSApple OSS Distributions PM_LOG1("[A %02x] %p [%p %s] state %d\n",
8195*c54f35caSApple OSS Distributions request->getType(), OBFUSCATE(request),
8196*c54f35caSApple OSS Distributions OBFUSCATE(this), getName(), fMachineState);
8197*c54f35caSApple OSS Distributions
8198*c54f35caSApple OSS Distributions switch (request->getType()) {
8199*c54f35caSApple OSS Distributions case kIOPMRequestTypeAllowPowerChange:
8200*c54f35caSApple OSS Distributions case kIOPMRequestTypeCancelPowerChange:
8201*c54f35caSApple OSS Distributions // Check if we are expecting this response.
8202*c54f35caSApple OSS Distributions if (responseValid((uint32_t)(uintptr_t) request->fArg0,
8203*c54f35caSApple OSS Distributions (int)(uintptr_t) request->fArg1)) {
8204*c54f35caSApple OSS Distributions if (kIOPMRequestTypeCancelPowerChange == request->getType()) {
8205*c54f35caSApple OSS Distributions // Clients are not allowed to cancel when kIOPMSkipAskPowerDown
8206*c54f35caSApple OSS Distributions // flag is set. Only root domain will set this flag.
8207*c54f35caSApple OSS Distributions // However, there is one exception to this rule. User-space PM
8208*c54f35caSApple OSS Distributions // policy may choose to cancel sleep even after all clients have
8209*c54f35caSApple OSS Distributions // been notified that we will lower power.
8210*c54f35caSApple OSS Distributions
8211*c54f35caSApple OSS Distributions if ((fMachineState == kIOPM_OurChangeTellUserPMPolicyPowerDown)
8212*c54f35caSApple OSS Distributions || (fMachineState == kIOPM_OurChangeTellPriorityClientsPowerDown)
8213*c54f35caSApple OSS Distributions || ((fHeadNoteChangeFlags & kIOPMSkipAskPowerDown) == 0)) {
8214*c54f35caSApple OSS Distributions fDoNotPowerDown = true;
8215*c54f35caSApple OSS Distributions
8216*c54f35caSApple OSS Distributions OSString * name = (OSString *) request->fArg2;
8217*c54f35caSApple OSS Distributions getPMRootDomain()->pmStatsRecordApplicationResponse(
8218*c54f35caSApple OSS Distributions gIOPMStatsResponseCancel,
8219*c54f35caSApple OSS Distributions name ? name->getCStringNoCopy() : "", 0,
8220*c54f35caSApple OSS Distributions 0, (int)(uintptr_t) request->fArg1, NULL);
8221*c54f35caSApple OSS Distributions }
8222*c54f35caSApple OSS Distributions }
8223*c54f35caSApple OSS Distributions
8224*c54f35caSApple OSS Distributions if (checkForDone()) {
8225*c54f35caSApple OSS Distributions stop_ack_timer();
8226*c54f35caSApple OSS Distributions cleanClientResponses(false);
8227*c54f35caSApple OSS Distributions more = true;
8228*c54f35caSApple OSS Distributions }
8229*c54f35caSApple OSS Distributions }
8230*c54f35caSApple OSS Distributions // OSString containing app name in Arg2 must be released.
8231*c54f35caSApple OSS Distributions if (request->getType() == kIOPMRequestTypeCancelPowerChange) {
8232*c54f35caSApple OSS Distributions OSObject * obj = (OSObject *) request->fArg2;
8233*c54f35caSApple OSS Distributions if (obj) {
8234*c54f35caSApple OSS Distributions obj->release();
8235*c54f35caSApple OSS Distributions }
8236*c54f35caSApple OSS Distributions }
8237*c54f35caSApple OSS Distributions break;
8238*c54f35caSApple OSS Distributions
8239*c54f35caSApple OSS Distributions case kIOPMRequestTypeAckPowerChange:
8240*c54f35caSApple OSS Distributions more = handleAcknowledgePowerChange( request );
8241*c54f35caSApple OSS Distributions break;
8242*c54f35caSApple OSS Distributions
8243*c54f35caSApple OSS Distributions case kIOPMRequestTypeAckSetPowerState:
8244*c54f35caSApple OSS Distributions more = handleAcknowledgeSetPowerState( request );
8245*c54f35caSApple OSS Distributions break;
8246*c54f35caSApple OSS Distributions
8247*c54f35caSApple OSS Distributions case kIOPMRequestTypeInterestChanged:
8248*c54f35caSApple OSS Distributions handleInterestChanged( request );
8249*c54f35caSApple OSS Distributions more = true;
8250*c54f35caSApple OSS Distributions break;
8251*c54f35caSApple OSS Distributions
8252*c54f35caSApple OSS Distributions case kIOPMRequestTypeIdleCancel:
8253*c54f35caSApple OSS Distributions if ((fMachineState == kIOPM_OurChangeTellClientsPowerDown)
8254*c54f35caSApple OSS Distributions || (fMachineState == kIOPM_OurChangeTellUserPMPolicyPowerDown)
8255*c54f35caSApple OSS Distributions || (fMachineState == kIOPM_OurChangeTellPriorityClientsPowerDown)
8256*c54f35caSApple OSS Distributions || (fMachineState == kIOPM_SyncTellClientsPowerDown)
8257*c54f35caSApple OSS Distributions || (fMachineState == kIOPM_SyncTellPriorityClientsPowerDown)) {
8258*c54f35caSApple OSS Distributions OUR_PMLog(kPMLogIdleCancel, (uintptr_t) this, fMachineState);
8259*c54f35caSApple OSS Distributions PM_LOG2("%s: cancel from machine state %d\n",
8260*c54f35caSApple OSS Distributions getName(), fMachineState);
8261*c54f35caSApple OSS Distributions fDoNotPowerDown = true;
8262*c54f35caSApple OSS Distributions // Stop waiting for app replys.
8263*c54f35caSApple OSS Distributions if ((fMachineState == kIOPM_OurChangeTellPriorityClientsPowerDown) ||
8264*c54f35caSApple OSS Distributions (fMachineState == kIOPM_OurChangeTellUserPMPolicyPowerDown) ||
8265*c54f35caSApple OSS Distributions (fMachineState == kIOPM_SyncTellPriorityClientsPowerDown) ||
8266*c54f35caSApple OSS Distributions (fMachineState == kIOPM_SyncTellClientsPowerDown)) {
8267*c54f35caSApple OSS Distributions cleanClientResponses(false);
8268*c54f35caSApple OSS Distributions }
8269*c54f35caSApple OSS Distributions more = true;
8270*c54f35caSApple OSS Distributions }
8271*c54f35caSApple OSS Distributions break;
8272*c54f35caSApple OSS Distributions
8273*c54f35caSApple OSS Distributions case kIOPMRequestTypeChildNotifyDelayCancel:
8274*c54f35caSApple OSS Distributions if (fMachineState == kIOPM_NotifyChildrenDelayed) {
8275*c54f35caSApple OSS Distributions PM_LOG2("%s: delay notify cancelled\n", getName());
8276*c54f35caSApple OSS Distributions notifyChildrenDelayed();
8277*c54f35caSApple OSS Distributions }
8278*c54f35caSApple OSS Distributions break;
8279*c54f35caSApple OSS Distributions
8280*c54f35caSApple OSS Distributions default:
8281*c54f35caSApple OSS Distributions panic("PMReplyQueue: unknown reply type %x", request->getType());
8282*c54f35caSApple OSS Distributions }
8283*c54f35caSApple OSS Distributions
8284*c54f35caSApple OSS Distributions more |= gIOPMCompletionQueue->queuePMRequest(request);
8285*c54f35caSApple OSS Distributions if (more) {
8286*c54f35caSApple OSS Distributions gIOPMWorkQueue->incrementProducerCount();
8287*c54f35caSApple OSS Distributions }
8288*c54f35caSApple OSS Distributions
8289*c54f35caSApple OSS Distributions return more;
8290*c54f35caSApple OSS Distributions }
8291*c54f35caSApple OSS Distributions
8292*c54f35caSApple OSS Distributions //*********************************************************************************
8293*c54f35caSApple OSS Distributions // [private] assertPMDriverCall / deassertPMDriverCall
8294*c54f35caSApple OSS Distributions //*********************************************************************************
8295*c54f35caSApple OSS Distributions
8296*c54f35caSApple OSS Distributions bool
assertPMDriverCall(IOPMDriverCallEntry * entry,IOOptionBits method,const IOPMinformee * inform,IOOptionBits options)8297*c54f35caSApple OSS Distributions IOService::assertPMDriverCall(
8298*c54f35caSApple OSS Distributions IOPMDriverCallEntry * entry,
8299*c54f35caSApple OSS Distributions IOOptionBits method,
8300*c54f35caSApple OSS Distributions const IOPMinformee * inform,
8301*c54f35caSApple OSS Distributions IOOptionBits options )
8302*c54f35caSApple OSS Distributions {
8303*c54f35caSApple OSS Distributions IOService * target = NULL;
8304*c54f35caSApple OSS Distributions bool ok = false;
8305*c54f35caSApple OSS Distributions
8306*c54f35caSApple OSS Distributions if (!initialized) {
8307*c54f35caSApple OSS Distributions return false;
8308*c54f35caSApple OSS Distributions }
8309*c54f35caSApple OSS Distributions
8310*c54f35caSApple OSS Distributions PM_LOCK();
8311*c54f35caSApple OSS Distributions
8312*c54f35caSApple OSS Distributions if (fLockedFlags.PMStop) {
8313*c54f35caSApple OSS Distributions goto fail;
8314*c54f35caSApple OSS Distributions }
8315*c54f35caSApple OSS Distributions
8316*c54f35caSApple OSS Distributions if (((options & kIOPMDriverCallNoInactiveCheck) == 0) && isInactive()) {
8317*c54f35caSApple OSS Distributions goto fail;
8318*c54f35caSApple OSS Distributions }
8319*c54f35caSApple OSS Distributions
8320*c54f35caSApple OSS Distributions if (inform) {
8321*c54f35caSApple OSS Distributions if (!inform->active) {
8322*c54f35caSApple OSS Distributions goto fail;
8323*c54f35caSApple OSS Distributions }
8324*c54f35caSApple OSS Distributions target = inform->whatObject;
8325*c54f35caSApple OSS Distributions if (target->isInactive()) {
8326*c54f35caSApple OSS Distributions goto fail;
8327*c54f35caSApple OSS Distributions }
8328*c54f35caSApple OSS Distributions }
8329*c54f35caSApple OSS Distributions
8330*c54f35caSApple OSS Distributions // Record calling address for sleep failure diagnostics
8331*c54f35caSApple OSS Distributions switch (method) {
8332*c54f35caSApple OSS Distributions case kIOPMDriverCallMethodSetPowerState:
8333*c54f35caSApple OSS Distributions entry->callMethod = OSMemberFunctionCast(const void *, fControllingDriver, &IOService::setPowerState);
8334*c54f35caSApple OSS Distributions break;
8335*c54f35caSApple OSS Distributions case kIOPMDriverCallMethodWillChange:
8336*c54f35caSApple OSS Distributions entry->callMethod = OSMemberFunctionCast(const void *, target, &IOService::powerStateWillChangeTo);
8337*c54f35caSApple OSS Distributions break;
8338*c54f35caSApple OSS Distributions case kIOPMDriverCallMethodDidChange:
8339*c54f35caSApple OSS Distributions entry->callMethod = OSMemberFunctionCast(const void *, target, &IOService::powerStateDidChangeTo);
8340*c54f35caSApple OSS Distributions break;
8341*c54f35caSApple OSS Distributions case kIOPMDriverCallMethodUnknown:
8342*c54f35caSApple OSS Distributions case kIOPMDriverCallMethodSetAggressive:
8343*c54f35caSApple OSS Distributions default:
8344*c54f35caSApple OSS Distributions entry->callMethod = NULL;
8345*c54f35caSApple OSS Distributions break;
8346*c54f35caSApple OSS Distributions }
8347*c54f35caSApple OSS Distributions
8348*c54f35caSApple OSS Distributions entry->thread = current_thread();
8349*c54f35caSApple OSS Distributions entry->target = target;
8350*c54f35caSApple OSS Distributions queue_enter(&fPMDriverCallQueue, entry, IOPMDriverCallEntry *, link);
8351*c54f35caSApple OSS Distributions ok = true;
8352*c54f35caSApple OSS Distributions
8353*c54f35caSApple OSS Distributions fail:
8354*c54f35caSApple OSS Distributions PM_UNLOCK();
8355*c54f35caSApple OSS Distributions
8356*c54f35caSApple OSS Distributions return ok;
8357*c54f35caSApple OSS Distributions }
8358*c54f35caSApple OSS Distributions
8359*c54f35caSApple OSS Distributions void
deassertPMDriverCall(IOPMDriverCallEntry * entry)8360*c54f35caSApple OSS Distributions IOService::deassertPMDriverCall( IOPMDriverCallEntry * entry )
8361*c54f35caSApple OSS Distributions {
8362*c54f35caSApple OSS Distributions bool wakeup = false;
8363*c54f35caSApple OSS Distributions
8364*c54f35caSApple OSS Distributions PM_LOCK();
8365*c54f35caSApple OSS Distributions
8366*c54f35caSApple OSS Distributions assert( !queue_empty(&fPMDriverCallQueue));
8367*c54f35caSApple OSS Distributions queue_remove(&fPMDriverCallQueue, entry, IOPMDriverCallEntry *, link);
8368*c54f35caSApple OSS Distributions if (fLockedFlags.PMDriverCallWait) {
8369*c54f35caSApple OSS Distributions wakeup = true;
8370*c54f35caSApple OSS Distributions }
8371*c54f35caSApple OSS Distributions
8372*c54f35caSApple OSS Distributions PM_UNLOCK();
8373*c54f35caSApple OSS Distributions
8374*c54f35caSApple OSS Distributions if (wakeup) {
8375*c54f35caSApple OSS Distributions PM_LOCK_WAKEUP(&fPMDriverCallQueue);
8376*c54f35caSApple OSS Distributions }
8377*c54f35caSApple OSS Distributions }
8378*c54f35caSApple OSS Distributions
8379*c54f35caSApple OSS Distributions bool
getBlockingDriverCall(thread_t * thread,const void ** callMethod)8380*c54f35caSApple OSS Distributions IOService::getBlockingDriverCall(thread_t *thread, const void **callMethod)
8381*c54f35caSApple OSS Distributions {
8382*c54f35caSApple OSS Distributions const IOPMDriverCallEntry * entry = NULL;
8383*c54f35caSApple OSS Distributions bool blocked = false;
8384*c54f35caSApple OSS Distributions
8385*c54f35caSApple OSS Distributions if (!initialized) {
8386*c54f35caSApple OSS Distributions return false;
8387*c54f35caSApple OSS Distributions }
8388*c54f35caSApple OSS Distributions
8389*c54f35caSApple OSS Distributions if (current_thread() != gIOPMWatchDogThread) {
8390*c54f35caSApple OSS Distributions // Meant to be accessed only from watchdog thread
8391*c54f35caSApple OSS Distributions return false;
8392*c54f35caSApple OSS Distributions }
8393*c54f35caSApple OSS Distributions
8394*c54f35caSApple OSS Distributions PM_LOCK();
8395*c54f35caSApple OSS Distributions entry = qe_queue_first(&fPMDriverCallQueue, IOPMDriverCallEntry, link);
8396*c54f35caSApple OSS Distributions if (entry) {
8397*c54f35caSApple OSS Distributions *thread = entry->thread;
8398*c54f35caSApple OSS Distributions *callMethod = entry->callMethod;
8399*c54f35caSApple OSS Distributions blocked = true;
8400*c54f35caSApple OSS Distributions }
8401*c54f35caSApple OSS Distributions PM_UNLOCK();
8402*c54f35caSApple OSS Distributions
8403*c54f35caSApple OSS Distributions return blocked;
8404*c54f35caSApple OSS Distributions }
8405*c54f35caSApple OSS Distributions
8406*c54f35caSApple OSS Distributions
8407*c54f35caSApple OSS Distributions void
waitForPMDriverCall(IOService * target)8408*c54f35caSApple OSS Distributions IOService::waitForPMDriverCall( IOService * target )
8409*c54f35caSApple OSS Distributions {
8410*c54f35caSApple OSS Distributions const IOPMDriverCallEntry * entry;
8411*c54f35caSApple OSS Distributions thread_t thread = current_thread();
8412*c54f35caSApple OSS Distributions AbsoluteTime deadline;
8413*c54f35caSApple OSS Distributions int waitResult;
8414*c54f35caSApple OSS Distributions bool log = true;
8415*c54f35caSApple OSS Distributions bool wait;
8416*c54f35caSApple OSS Distributions
8417*c54f35caSApple OSS Distributions do {
8418*c54f35caSApple OSS Distributions wait = false;
8419*c54f35caSApple OSS Distributions queue_iterate(&fPMDriverCallQueue, entry, const IOPMDriverCallEntry *, link)
8420*c54f35caSApple OSS Distributions {
8421*c54f35caSApple OSS Distributions // Target of interested driver call
8422*c54f35caSApple OSS Distributions if (target && (target != entry->target)) {
8423*c54f35caSApple OSS Distributions continue;
8424*c54f35caSApple OSS Distributions }
8425*c54f35caSApple OSS Distributions
8426*c54f35caSApple OSS Distributions if (entry->thread == thread) {
8427*c54f35caSApple OSS Distributions if (log) {
8428*c54f35caSApple OSS Distributions PM_LOG("%s: %s(%s) on PM thread\n",
8429*c54f35caSApple OSS Distributions fName, __FUNCTION__, target ? target->getName() : "");
8430*c54f35caSApple OSS Distributions OSReportWithBacktrace("%s: %s(%s) on PM thread\n",
8431*c54f35caSApple OSS Distributions fName, __FUNCTION__, target ? target->getName() : "");
8432*c54f35caSApple OSS Distributions log = false;
8433*c54f35caSApple OSS Distributions }
8434*c54f35caSApple OSS Distributions continue;
8435*c54f35caSApple OSS Distributions }
8436*c54f35caSApple OSS Distributions
8437*c54f35caSApple OSS Distributions wait = true;
8438*c54f35caSApple OSS Distributions break;
8439*c54f35caSApple OSS Distributions }
8440*c54f35caSApple OSS Distributions
8441*c54f35caSApple OSS Distributions if (wait) {
8442*c54f35caSApple OSS Distributions fLockedFlags.PMDriverCallWait = true;
8443*c54f35caSApple OSS Distributions clock_interval_to_deadline(15, kSecondScale, &deadline);
8444*c54f35caSApple OSS Distributions waitResult = PM_LOCK_SLEEP(&fPMDriverCallQueue, deadline);
8445*c54f35caSApple OSS Distributions fLockedFlags.PMDriverCallWait = false;
8446*c54f35caSApple OSS Distributions if (THREAD_TIMED_OUT == waitResult) {
8447*c54f35caSApple OSS Distributions PM_ERROR("%s: waitForPMDriverCall timeout\n", fName);
8448*c54f35caSApple OSS Distributions wait = false;
8449*c54f35caSApple OSS Distributions }
8450*c54f35caSApple OSS Distributions }
8451*c54f35caSApple OSS Distributions } while (wait);
8452*c54f35caSApple OSS Distributions }
8453*c54f35caSApple OSS Distributions
8454*c54f35caSApple OSS Distributions //*********************************************************************************
8455*c54f35caSApple OSS Distributions // [private] Debug helpers
8456*c54f35caSApple OSS Distributions //*********************************************************************************
8457*c54f35caSApple OSS Distributions
8458*c54f35caSApple OSS Distributions const char *
getIOMessageString(uint32_t msg)8459*c54f35caSApple OSS Distributions IOService::getIOMessageString( uint32_t msg )
8460*c54f35caSApple OSS Distributions {
8461*c54f35caSApple OSS Distributions #define MSG_ENTRY(x) {(int) x, #x}
8462*c54f35caSApple OSS Distributions
8463*c54f35caSApple OSS Distributions static const IONamedValue msgNames[] = {
8464*c54f35caSApple OSS Distributions MSG_ENTRY( kIOMessageCanDevicePowerOff ),
8465*c54f35caSApple OSS Distributions MSG_ENTRY( kIOMessageDeviceWillPowerOff ),
8466*c54f35caSApple OSS Distributions MSG_ENTRY( kIOMessageDeviceWillNotPowerOff ),
8467*c54f35caSApple OSS Distributions MSG_ENTRY( kIOMessageDeviceHasPoweredOn ),
8468*c54f35caSApple OSS Distributions MSG_ENTRY( kIOMessageCanSystemPowerOff ),
8469*c54f35caSApple OSS Distributions MSG_ENTRY( kIOMessageSystemWillPowerOff ),
8470*c54f35caSApple OSS Distributions MSG_ENTRY( kIOMessageSystemWillNotPowerOff ),
8471*c54f35caSApple OSS Distributions MSG_ENTRY( kIOMessageCanSystemSleep ),
8472*c54f35caSApple OSS Distributions MSG_ENTRY( kIOMessageSystemWillSleep ),
8473*c54f35caSApple OSS Distributions MSG_ENTRY( kIOMessageSystemWillNotSleep ),
8474*c54f35caSApple OSS Distributions MSG_ENTRY( kIOMessageSystemHasPoweredOn ),
8475*c54f35caSApple OSS Distributions MSG_ENTRY( kIOMessageSystemWillRestart ),
8476*c54f35caSApple OSS Distributions MSG_ENTRY( kIOMessageSystemWillPowerOn ),
8477*c54f35caSApple OSS Distributions MSG_ENTRY( kIOMessageSystemCapabilityChange ),
8478*c54f35caSApple OSS Distributions MSG_ENTRY( kIOPMMessageLastCallBeforeSleep ),
8479*c54f35caSApple OSS Distributions MSG_ENTRY( kIOMessageSystemPagingOff ),
8480*c54f35caSApple OSS Distributions { 0, NULL }
8481*c54f35caSApple OSS Distributions };
8482*c54f35caSApple OSS Distributions
8483*c54f35caSApple OSS Distributions return IOFindNameForValue(msg, msgNames);
8484*c54f35caSApple OSS Distributions }
8485*c54f35caSApple OSS Distributions
8486*c54f35caSApple OSS Distributions static const char *
getNotificationPhaseString(uint32_t phase)8487*c54f35caSApple OSS Distributions getNotificationPhaseString( uint32_t phase )
8488*c54f35caSApple OSS Distributions {
8489*c54f35caSApple OSS Distributions #define PHASE_ENTRY(x) {(int) x, #x}
8490*c54f35caSApple OSS Distributions
8491*c54f35caSApple OSS Distributions static const IONamedValue phaseNames[] = {
8492*c54f35caSApple OSS Distributions PHASE_ENTRY( kNotifyApps ),
8493*c54f35caSApple OSS Distributions PHASE_ENTRY( kNotifyPriority ),
8494*c54f35caSApple OSS Distributions PHASE_ENTRY( kNotifyCapabilityChangeApps ),
8495*c54f35caSApple OSS Distributions PHASE_ENTRY( kNotifyCapabilityChangePriority ),
8496*c54f35caSApple OSS Distributions { 0, NULL }
8497*c54f35caSApple OSS Distributions };
8498*c54f35caSApple OSS Distributions
8499*c54f35caSApple OSS Distributions return IOFindNameForValue(phase, phaseNames);
8500*c54f35caSApple OSS Distributions }
8501*c54f35caSApple OSS Distributions
8502*c54f35caSApple OSS Distributions // MARK: -
8503*c54f35caSApple OSS Distributions // MARK: IOPMRequest
8504*c54f35caSApple OSS Distributions
8505*c54f35caSApple OSS Distributions //*********************************************************************************
8506*c54f35caSApple OSS Distributions // IOPMRequest Class
8507*c54f35caSApple OSS Distributions //
8508*c54f35caSApple OSS Distributions // Requests from PM clients, and also used for inter-object messaging within PM.
8509*c54f35caSApple OSS Distributions //*********************************************************************************
8510*c54f35caSApple OSS Distributions
8511*c54f35caSApple OSS Distributions OSDefineMetaClassAndStructors( IOPMRequest, IOCommand );
8512*c54f35caSApple OSS Distributions
8513*c54f35caSApple OSS Distributions IOPMRequest *
create(void)8514*c54f35caSApple OSS Distributions IOPMRequest::create( void )
8515*c54f35caSApple OSS Distributions {
8516*c54f35caSApple OSS Distributions IOPMRequest * me = OSTypeAlloc(IOPMRequest);
8517*c54f35caSApple OSS Distributions if (me && !me->init(NULL, kIOPMRequestTypeInvalid)) {
8518*c54f35caSApple OSS Distributions me->release();
8519*c54f35caSApple OSS Distributions me = NULL;
8520*c54f35caSApple OSS Distributions }
8521*c54f35caSApple OSS Distributions return me;
8522*c54f35caSApple OSS Distributions }
8523*c54f35caSApple OSS Distributions
8524*c54f35caSApple OSS Distributions bool
init(IOService * target,IOOptionBits type)8525*c54f35caSApple OSS Distributions IOPMRequest::init( IOService * target, IOOptionBits type )
8526*c54f35caSApple OSS Distributions {
8527*c54f35caSApple OSS Distributions if (!IOCommand::init()) {
8528*c54f35caSApple OSS Distributions return false;
8529*c54f35caSApple OSS Distributions }
8530*c54f35caSApple OSS Distributions
8531*c54f35caSApple OSS Distributions fRequestType = type;
8532*c54f35caSApple OSS Distributions fTarget = target;
8533*c54f35caSApple OSS Distributions
8534*c54f35caSApple OSS Distributions if (fTarget) {
8535*c54f35caSApple OSS Distributions fTarget->retain();
8536*c54f35caSApple OSS Distributions }
8537*c54f35caSApple OSS Distributions
8538*c54f35caSApple OSS Distributions // Root node and root domain requests does not prevent the power tree from
8539*c54f35caSApple OSS Distributions // becoming quiescent.
8540*c54f35caSApple OSS Distributions
8541*c54f35caSApple OSS Distributions fIsQuiesceBlocker = ((fTarget != gIOPMRootNode) &&
8542*c54f35caSApple OSS Distributions (fTarget != IOService::getPMRootDomain()));
8543*c54f35caSApple OSS Distributions
8544*c54f35caSApple OSS Distributions return true;
8545*c54f35caSApple OSS Distributions }
8546*c54f35caSApple OSS Distributions
8547*c54f35caSApple OSS Distributions void
reset(void)8548*c54f35caSApple OSS Distributions IOPMRequest::reset( void )
8549*c54f35caSApple OSS Distributions {
8550*c54f35caSApple OSS Distributions assert( fWorkWaitCount == 0 );
8551*c54f35caSApple OSS Distributions assert( fFreeWaitCount == 0 );
8552*c54f35caSApple OSS Distributions
8553*c54f35caSApple OSS Distributions detachNextRequest();
8554*c54f35caSApple OSS Distributions detachRootRequest();
8555*c54f35caSApple OSS Distributions
8556*c54f35caSApple OSS Distributions if (fCompletionAction && (fRequestType == kIOPMRequestTypeQuiescePowerTree)) {
8557*c54f35caSApple OSS Distributions // Call the completion on PM work loop context
8558*c54f35caSApple OSS Distributions fCompletionAction(fCompletionTarget, fCompletionParam);
8559*c54f35caSApple OSS Distributions fCompletionAction = NULL;
8560*c54f35caSApple OSS Distributions }
8561*c54f35caSApple OSS Distributions
8562*c54f35caSApple OSS Distributions fRequestType = kIOPMRequestTypeInvalid;
8563*c54f35caSApple OSS Distributions
8564*c54f35caSApple OSS Distributions if (fTarget) {
8565*c54f35caSApple OSS Distributions fTarget->release();
8566*c54f35caSApple OSS Distributions fTarget = NULL;
8567*c54f35caSApple OSS Distributions }
8568*c54f35caSApple OSS Distributions }
8569*c54f35caSApple OSS Distributions
8570*c54f35caSApple OSS Distributions bool
attachNextRequest(IOPMRequest * next)8571*c54f35caSApple OSS Distributions IOPMRequest::attachNextRequest( IOPMRequest * next )
8572*c54f35caSApple OSS Distributions {
8573*c54f35caSApple OSS Distributions bool ok = false;
8574*c54f35caSApple OSS Distributions
8575*c54f35caSApple OSS Distributions if (!fRequestNext) {
8576*c54f35caSApple OSS Distributions // Postpone the execution of the next request after
8577*c54f35caSApple OSS Distributions // this request.
8578*c54f35caSApple OSS Distributions fRequestNext = next;
8579*c54f35caSApple OSS Distributions fRequestNext->fWorkWaitCount++;
8580*c54f35caSApple OSS Distributions #if LOG_REQUEST_ATTACH
8581*c54f35caSApple OSS Distributions PM_LOG("Attached next: %p [0x%x] -> %p [0x%x, %u] %s\n",
8582*c54f35caSApple OSS Distributions OBFUSCATE(this), fRequestType, OBFUSCATE(fRequestNext),
8583*c54f35caSApple OSS Distributions fRequestNext->fRequestType,
8584*c54f35caSApple OSS Distributions (uint32_t) fRequestNext->fWorkWaitCount,
8585*c54f35caSApple OSS Distributions fTarget->getName());
8586*c54f35caSApple OSS Distributions #endif
8587*c54f35caSApple OSS Distributions ok = true;
8588*c54f35caSApple OSS Distributions }
8589*c54f35caSApple OSS Distributions return ok;
8590*c54f35caSApple OSS Distributions }
8591*c54f35caSApple OSS Distributions
8592*c54f35caSApple OSS Distributions bool
detachNextRequest(void)8593*c54f35caSApple OSS Distributions IOPMRequest::detachNextRequest( void )
8594*c54f35caSApple OSS Distributions {
8595*c54f35caSApple OSS Distributions bool ok = false;
8596*c54f35caSApple OSS Distributions
8597*c54f35caSApple OSS Distributions if (fRequestNext) {
8598*c54f35caSApple OSS Distributions assert(fRequestNext->fWorkWaitCount);
8599*c54f35caSApple OSS Distributions if (fRequestNext->fWorkWaitCount) {
8600*c54f35caSApple OSS Distributions fRequestNext->fWorkWaitCount--;
8601*c54f35caSApple OSS Distributions }
8602*c54f35caSApple OSS Distributions #if LOG_REQUEST_ATTACH
8603*c54f35caSApple OSS Distributions PM_LOG("Detached next: %p [0x%x] -> %p [0x%x, %u] %s\n",
8604*c54f35caSApple OSS Distributions OBFUSCATE(this), fRequestType, OBFUSCATE(fRequestNext),
8605*c54f35caSApple OSS Distributions fRequestNext->fRequestType,
8606*c54f35caSApple OSS Distributions (uint32_t) fRequestNext->fWorkWaitCount,
8607*c54f35caSApple OSS Distributions fTarget->getName());
8608*c54f35caSApple OSS Distributions #endif
8609*c54f35caSApple OSS Distributions fRequestNext = NULL;
8610*c54f35caSApple OSS Distributions ok = true;
8611*c54f35caSApple OSS Distributions }
8612*c54f35caSApple OSS Distributions return ok;
8613*c54f35caSApple OSS Distributions }
8614*c54f35caSApple OSS Distributions
8615*c54f35caSApple OSS Distributions bool
attachRootRequest(IOPMRequest * root)8616*c54f35caSApple OSS Distributions IOPMRequest::attachRootRequest( IOPMRequest * root )
8617*c54f35caSApple OSS Distributions {
8618*c54f35caSApple OSS Distributions bool ok = false;
8619*c54f35caSApple OSS Distributions
8620*c54f35caSApple OSS Distributions if (!fRequestRoot) {
8621*c54f35caSApple OSS Distributions // Delay the completion of the root request after
8622*c54f35caSApple OSS Distributions // this request.
8623*c54f35caSApple OSS Distributions fRequestRoot = root;
8624*c54f35caSApple OSS Distributions fRequestRoot->fFreeWaitCount++;
8625*c54f35caSApple OSS Distributions #if LOG_REQUEST_ATTACH
8626*c54f35caSApple OSS Distributions PM_LOG("Attached root: %p [0x%x] -> %p [0x%x, %u] %s\n",
8627*c54f35caSApple OSS Distributions OBFUSCATE(this), (uint32_t) fType, OBFUSCATE(fRequestRoot),
8628*c54f35caSApple OSS Distributions (uint32_t) fRequestRoot->fType,
8629*c54f35caSApple OSS Distributions (uint32_t) fRequestRoot->fFreeWaitCount,
8630*c54f35caSApple OSS Distributions fTarget->getName());
8631*c54f35caSApple OSS Distributions #endif
8632*c54f35caSApple OSS Distributions ok = true;
8633*c54f35caSApple OSS Distributions }
8634*c54f35caSApple OSS Distributions return ok;
8635*c54f35caSApple OSS Distributions }
8636*c54f35caSApple OSS Distributions
8637*c54f35caSApple OSS Distributions bool
detachRootRequest(void)8638*c54f35caSApple OSS Distributions IOPMRequest::detachRootRequest( void )
8639*c54f35caSApple OSS Distributions {
8640*c54f35caSApple OSS Distributions bool ok = false;
8641*c54f35caSApple OSS Distributions
8642*c54f35caSApple OSS Distributions if (fRequestRoot) {
8643*c54f35caSApple OSS Distributions assert(fRequestRoot->fFreeWaitCount);
8644*c54f35caSApple OSS Distributions if (fRequestRoot->fFreeWaitCount) {
8645*c54f35caSApple OSS Distributions fRequestRoot->fFreeWaitCount--;
8646*c54f35caSApple OSS Distributions }
8647*c54f35caSApple OSS Distributions #if LOG_REQUEST_ATTACH
8648*c54f35caSApple OSS Distributions PM_LOG("Detached root: %p [0x%x] -> %p [0x%x, %u] %s\n",
8649*c54f35caSApple OSS Distributions OBFUSCATE(this), (uint32_t) fType, OBFUSCATE(fRequestRoot),
8650*c54f35caSApple OSS Distributions (uint32_t) fRequestRoot->fType,
8651*c54f35caSApple OSS Distributions (uint32_t) fRequestRoot->fFreeWaitCount,
8652*c54f35caSApple OSS Distributions fTarget->getName());
8653*c54f35caSApple OSS Distributions #endif
8654*c54f35caSApple OSS Distributions fRequestRoot = NULL;
8655*c54f35caSApple OSS Distributions ok = true;
8656*c54f35caSApple OSS Distributions }
8657*c54f35caSApple OSS Distributions return ok;
8658*c54f35caSApple OSS Distributions }
8659*c54f35caSApple OSS Distributions
8660*c54f35caSApple OSS Distributions // MARK: -
8661*c54f35caSApple OSS Distributions // MARK: IOPMRequestQueue
8662*c54f35caSApple OSS Distributions
8663*c54f35caSApple OSS Distributions //*********************************************************************************
8664*c54f35caSApple OSS Distributions // IOPMRequestQueue Class
8665*c54f35caSApple OSS Distributions //
8666*c54f35caSApple OSS Distributions // Global queues. Queues are created once and never released.
8667*c54f35caSApple OSS Distributions //*********************************************************************************
8668*c54f35caSApple OSS Distributions
8669*c54f35caSApple OSS Distributions OSDefineMetaClassAndStructors( IOPMRequestQueue, IOEventSource );
8670*c54f35caSApple OSS Distributions
8671*c54f35caSApple OSS Distributions #pragma clang diagnostic push
8672*c54f35caSApple OSS Distributions #pragma clang diagnostic ignored "-Wcast-function-type"
8673*c54f35caSApple OSS Distributions
8674*c54f35caSApple OSS Distributions IOPMRequestQueue *
create(IOService * inOwner,Action inAction)8675*c54f35caSApple OSS Distributions IOPMRequestQueue::create( IOService * inOwner, Action inAction )
8676*c54f35caSApple OSS Distributions {
8677*c54f35caSApple OSS Distributions IOPMRequestQueue * me = OSTypeAlloc(IOPMRequestQueue);
8678*c54f35caSApple OSS Distributions if (me && !me->init(inOwner, inAction)) {
8679*c54f35caSApple OSS Distributions me->release();
8680*c54f35caSApple OSS Distributions me = NULL;
8681*c54f35caSApple OSS Distributions }
8682*c54f35caSApple OSS Distributions return me;
8683*c54f35caSApple OSS Distributions }
8684*c54f35caSApple OSS Distributions
8685*c54f35caSApple OSS Distributions bool
init(IOService * inOwner,Action inAction)8686*c54f35caSApple OSS Distributions IOPMRequestQueue::init( IOService * inOwner, Action inAction )
8687*c54f35caSApple OSS Distributions {
8688*c54f35caSApple OSS Distributions if (!inAction || !IOEventSource::init(inOwner, (IOEventSourceAction)inAction)) {
8689*c54f35caSApple OSS Distributions return false;
8690*c54f35caSApple OSS Distributions }
8691*c54f35caSApple OSS Distributions
8692*c54f35caSApple OSS Distributions queue_init(&fQueue);
8693*c54f35caSApple OSS Distributions fLock = IOLockAlloc();
8694*c54f35caSApple OSS Distributions return fLock != NULL;
8695*c54f35caSApple OSS Distributions }
8696*c54f35caSApple OSS Distributions
8697*c54f35caSApple OSS Distributions #pragma clang diagnostic pop
8698*c54f35caSApple OSS Distributions
8699*c54f35caSApple OSS Distributions void
free(void)8700*c54f35caSApple OSS Distributions IOPMRequestQueue::free( void )
8701*c54f35caSApple OSS Distributions {
8702*c54f35caSApple OSS Distributions if (fLock) {
8703*c54f35caSApple OSS Distributions IOLockFree(fLock);
8704*c54f35caSApple OSS Distributions fLock = NULL;
8705*c54f35caSApple OSS Distributions }
8706*c54f35caSApple OSS Distributions return IOEventSource::free();
8707*c54f35caSApple OSS Distributions }
8708*c54f35caSApple OSS Distributions
8709*c54f35caSApple OSS Distributions void
queuePMRequest(IOPMRequest * request)8710*c54f35caSApple OSS Distributions IOPMRequestQueue::queuePMRequest( IOPMRequest * request )
8711*c54f35caSApple OSS Distributions {
8712*c54f35caSApple OSS Distributions uint64_t now = mach_continuous_time();
8713*c54f35caSApple OSS Distributions
8714*c54f35caSApple OSS Distributions assert(request);
8715*c54f35caSApple OSS Distributions request->setTimestamp(now);
8716*c54f35caSApple OSS Distributions IOLockLock(fLock);
8717*c54f35caSApple OSS Distributions queue_enter(&fQueue, request, typeof(request), fCommandChain);
8718*c54f35caSApple OSS Distributions IOLockUnlock(fLock);
8719*c54f35caSApple OSS Distributions if (workLoop) {
8720*c54f35caSApple OSS Distributions signalWorkAvailable();
8721*c54f35caSApple OSS Distributions }
8722*c54f35caSApple OSS Distributions }
8723*c54f35caSApple OSS Distributions
8724*c54f35caSApple OSS Distributions void
queuePMRequestChain(IOPMRequest ** requests,IOItemCount count)8725*c54f35caSApple OSS Distributions IOPMRequestQueue::queuePMRequestChain( IOPMRequest ** requests, IOItemCount count )
8726*c54f35caSApple OSS Distributions {
8727*c54f35caSApple OSS Distributions IOPMRequest * next;
8728*c54f35caSApple OSS Distributions uint64_t now = mach_continuous_time();
8729*c54f35caSApple OSS Distributions
8730*c54f35caSApple OSS Distributions assert(requests && count);
8731*c54f35caSApple OSS Distributions IOLockLock(fLock);
8732*c54f35caSApple OSS Distributions while (count--) {
8733*c54f35caSApple OSS Distributions next = *requests;
8734*c54f35caSApple OSS Distributions next->setTimestamp(now);
8735*c54f35caSApple OSS Distributions requests++;
8736*c54f35caSApple OSS Distributions queue_enter(&fQueue, next, typeof(next), fCommandChain);
8737*c54f35caSApple OSS Distributions }
8738*c54f35caSApple OSS Distributions IOLockUnlock(fLock);
8739*c54f35caSApple OSS Distributions if (workLoop) {
8740*c54f35caSApple OSS Distributions signalWorkAvailable();
8741*c54f35caSApple OSS Distributions }
8742*c54f35caSApple OSS Distributions }
8743*c54f35caSApple OSS Distributions
8744*c54f35caSApple OSS Distributions bool
checkForWork(void)8745*c54f35caSApple OSS Distributions IOPMRequestQueue::checkForWork( void )
8746*c54f35caSApple OSS Distributions {
8747*c54f35caSApple OSS Distributions Action dqAction = (Action) (void (*)(void))action;
8748*c54f35caSApple OSS Distributions IOPMRequest * request;
8749*c54f35caSApple OSS Distributions IOService * target;
8750*c54f35caSApple OSS Distributions int dequeueCount = 0;
8751*c54f35caSApple OSS Distributions bool more = false;
8752*c54f35caSApple OSS Distributions
8753*c54f35caSApple OSS Distributions IOLockLock( fLock );
8754*c54f35caSApple OSS Distributions
8755*c54f35caSApple OSS Distributions while (!queue_empty(&fQueue)) {
8756*c54f35caSApple OSS Distributions if (dequeueCount++ >= kMaxDequeueCount) {
8757*c54f35caSApple OSS Distributions // Allow other queues a chance to work
8758*c54f35caSApple OSS Distributions more = true;
8759*c54f35caSApple OSS Distributions break;
8760*c54f35caSApple OSS Distributions }
8761*c54f35caSApple OSS Distributions
8762*c54f35caSApple OSS Distributions queue_remove_first(&fQueue, request, typeof(request), fCommandChain);
8763*c54f35caSApple OSS Distributions IOLockUnlock(fLock);
8764*c54f35caSApple OSS Distributions target = request->getTarget();
8765*c54f35caSApple OSS Distributions assert(target);
8766*c54f35caSApple OSS Distributions more |= (*dqAction)( target, request, this );
8767*c54f35caSApple OSS Distributions IOLockLock( fLock );
8768*c54f35caSApple OSS Distributions }
8769*c54f35caSApple OSS Distributions
8770*c54f35caSApple OSS Distributions IOLockUnlock( fLock );
8771*c54f35caSApple OSS Distributions return more;
8772*c54f35caSApple OSS Distributions }
8773*c54f35caSApple OSS Distributions
8774*c54f35caSApple OSS Distributions // MARK: -
8775*c54f35caSApple OSS Distributions // MARK: IOPMWorkQueue
8776*c54f35caSApple OSS Distributions
8777*c54f35caSApple OSS Distributions //*********************************************************************************
8778*c54f35caSApple OSS Distributions // IOPMWorkQueue Class
8779*c54f35caSApple OSS Distributions //
8780*c54f35caSApple OSS Distributions // Queue of IOServicePM objects, each with a queue of IOPMRequest sharing the
8781*c54f35caSApple OSS Distributions // same target.
8782*c54f35caSApple OSS Distributions //*********************************************************************************
8783*c54f35caSApple OSS Distributions
8784*c54f35caSApple OSS Distributions OSDefineMetaClassAndStructors( IOPMWorkQueue, IOEventSource );
8785*c54f35caSApple OSS Distributions
8786*c54f35caSApple OSS Distributions IOPMWorkQueue *
create(IOService * inOwner,Action invoke,Action retire)8787*c54f35caSApple OSS Distributions IOPMWorkQueue::create( IOService * inOwner, Action invoke, Action retire )
8788*c54f35caSApple OSS Distributions {
8789*c54f35caSApple OSS Distributions IOPMWorkQueue * me = OSTypeAlloc(IOPMWorkQueue);
8790*c54f35caSApple OSS Distributions if (me && !me->init(inOwner, invoke, retire)) {
8791*c54f35caSApple OSS Distributions me->release();
8792*c54f35caSApple OSS Distributions me = NULL;
8793*c54f35caSApple OSS Distributions }
8794*c54f35caSApple OSS Distributions return me;
8795*c54f35caSApple OSS Distributions }
8796*c54f35caSApple OSS Distributions
8797*c54f35caSApple OSS Distributions bool
init(IOService * inOwner,Action invoke,Action retire)8798*c54f35caSApple OSS Distributions IOPMWorkQueue::init( IOService * inOwner, Action invoke, Action retire )
8799*c54f35caSApple OSS Distributions {
8800*c54f35caSApple OSS Distributions if (!invoke || !retire ||
8801*c54f35caSApple OSS Distributions !IOEventSource::init(inOwner, (IOEventSourceAction)NULL)) {
8802*c54f35caSApple OSS Distributions return false;
8803*c54f35caSApple OSS Distributions }
8804*c54f35caSApple OSS Distributions
8805*c54f35caSApple OSS Distributions queue_init(&fWorkQueue);
8806*c54f35caSApple OSS Distributions
8807*c54f35caSApple OSS Distributions fInvokeAction = invoke;
8808*c54f35caSApple OSS Distributions fRetireAction = retire;
8809*c54f35caSApple OSS Distributions fConsumerCount = fProducerCount = 0;
8810*c54f35caSApple OSS Distributions
8811*c54f35caSApple OSS Distributions return true;
8812*c54f35caSApple OSS Distributions }
8813*c54f35caSApple OSS Distributions
8814*c54f35caSApple OSS Distributions bool
queuePMRequest(IOPMRequest * request,IOServicePM * pwrMgt)8815*c54f35caSApple OSS Distributions IOPMWorkQueue::queuePMRequest( IOPMRequest * request, IOServicePM * pwrMgt )
8816*c54f35caSApple OSS Distributions {
8817*c54f35caSApple OSS Distributions queue_head_t * requestQueue;
8818*c54f35caSApple OSS Distributions bool more = false;
8819*c54f35caSApple OSS Distributions bool empty;
8820*c54f35caSApple OSS Distributions
8821*c54f35caSApple OSS Distributions assert( request );
8822*c54f35caSApple OSS Distributions assert( pwrMgt );
8823*c54f35caSApple OSS Distributions assert( onThread());
8824*c54f35caSApple OSS Distributions assert( queue_next(&request->fCommandChain) ==
8825*c54f35caSApple OSS Distributions queue_prev(&request->fCommandChain));
8826*c54f35caSApple OSS Distributions
8827*c54f35caSApple OSS Distributions gIOPMBusyRequestCount++;
8828*c54f35caSApple OSS Distributions
8829*c54f35caSApple OSS Distributions if (request->isQuiesceType()) {
8830*c54f35caSApple OSS Distributions if ((request->getTarget() == gIOPMRootNode) && !fQuiesceStartTime) {
8831*c54f35caSApple OSS Distributions // Attach new quiesce request to all quiesce blockers in the queue
8832*c54f35caSApple OSS Distributions fQuiesceStartTime = mach_absolute_time();
8833*c54f35caSApple OSS Distributions attachQuiesceRequest(request);
8834*c54f35caSApple OSS Distributions fQuiesceRequest = request;
8835*c54f35caSApple OSS Distributions }
8836*c54f35caSApple OSS Distributions } else if (fQuiesceRequest && request->isQuiesceBlocker()) {
8837*c54f35caSApple OSS Distributions // Attach the new quiesce blocker to the blocked quiesce request
8838*c54f35caSApple OSS Distributions request->attachNextRequest(fQuiesceRequest);
8839*c54f35caSApple OSS Distributions }
8840*c54f35caSApple OSS Distributions
8841*c54f35caSApple OSS Distributions // Add new request to the tail of the per-service request queue.
8842*c54f35caSApple OSS Distributions // Then immediately check the request queue to minimize latency
8843*c54f35caSApple OSS Distributions // if the queue was empty.
8844*c54f35caSApple OSS Distributions
8845*c54f35caSApple OSS Distributions requestQueue = &pwrMgt->RequestHead;
8846*c54f35caSApple OSS Distributions empty = queue_empty(requestQueue);
8847*c54f35caSApple OSS Distributions queue_enter(requestQueue, request, typeof(request), fCommandChain);
8848*c54f35caSApple OSS Distributions if (empty) {
8849*c54f35caSApple OSS Distributions more = checkRequestQueue(requestQueue, &empty);
8850*c54f35caSApple OSS Distributions if (!empty) {
8851*c54f35caSApple OSS Distributions // Request just added is blocked, add its target IOServicePM
8852*c54f35caSApple OSS Distributions // to the work queue.
8853*c54f35caSApple OSS Distributions assert( queue_next(&pwrMgt->WorkChain) ==
8854*c54f35caSApple OSS Distributions queue_prev(&pwrMgt->WorkChain));
8855*c54f35caSApple OSS Distributions
8856*c54f35caSApple OSS Distributions queue_enter(&fWorkQueue, pwrMgt, typeof(pwrMgt), WorkChain);
8857*c54f35caSApple OSS Distributions fQueueLength++;
8858*c54f35caSApple OSS Distributions PM_LOG3("IOPMWorkQueue: [%u] added %s@%p to queue\n",
8859*c54f35caSApple OSS Distributions fQueueLength, pwrMgt->Name, OBFUSCATE(pwrMgt));
8860*c54f35caSApple OSS Distributions }
8861*c54f35caSApple OSS Distributions }
8862*c54f35caSApple OSS Distributions
8863*c54f35caSApple OSS Distributions return more;
8864*c54f35caSApple OSS Distributions }
8865*c54f35caSApple OSS Distributions
8866*c54f35caSApple OSS Distributions bool
checkRequestQueue(queue_head_t * requestQueue,bool * empty)8867*c54f35caSApple OSS Distributions IOPMWorkQueue::checkRequestQueue( queue_head_t * requestQueue, bool * empty )
8868*c54f35caSApple OSS Distributions {
8869*c54f35caSApple OSS Distributions IOPMRequest * request;
8870*c54f35caSApple OSS Distributions IOService * target;
8871*c54f35caSApple OSS Distributions bool more = false;
8872*c54f35caSApple OSS Distributions bool done = false;
8873*c54f35caSApple OSS Distributions
8874*c54f35caSApple OSS Distributions assert(!queue_empty(requestQueue));
8875*c54f35caSApple OSS Distributions do {
8876*c54f35caSApple OSS Distributions request = (typeof(request))queue_first(requestQueue);
8877*c54f35caSApple OSS Distributions if (request->isWorkBlocked()) {
8878*c54f35caSApple OSS Distributions break; // request dispatch blocked on attached request
8879*c54f35caSApple OSS Distributions }
8880*c54f35caSApple OSS Distributions target = request->getTarget();
8881*c54f35caSApple OSS Distributions if (fInvokeAction) {
8882*c54f35caSApple OSS Distributions done = (*fInvokeAction)( target, request, this );
8883*c54f35caSApple OSS Distributions } else {
8884*c54f35caSApple OSS Distributions PM_LOG("PM request 0x%x dropped\n", request->getType());
8885*c54f35caSApple OSS Distributions done = true;
8886*c54f35caSApple OSS Distributions }
8887*c54f35caSApple OSS Distributions if (!done) {
8888*c54f35caSApple OSS Distributions break; // PM state machine blocked
8889*c54f35caSApple OSS Distributions }
8890*c54f35caSApple OSS Distributions assert(gIOPMBusyRequestCount > 0);
8891*c54f35caSApple OSS Distributions if (gIOPMBusyRequestCount) {
8892*c54f35caSApple OSS Distributions gIOPMBusyRequestCount--;
8893*c54f35caSApple OSS Distributions }
8894*c54f35caSApple OSS Distributions
8895*c54f35caSApple OSS Distributions if (request == fQuiesceRequest) {
8896*c54f35caSApple OSS Distributions fQuiesceRequest = NULL;
8897*c54f35caSApple OSS Distributions }
8898*c54f35caSApple OSS Distributions
8899*c54f35caSApple OSS Distributions queue_remove_first(requestQueue, request, typeof(request), fCommandChain);
8900*c54f35caSApple OSS Distributions more |= (*fRetireAction)( target, request, this );
8901*c54f35caSApple OSS Distributions done = queue_empty(requestQueue);
8902*c54f35caSApple OSS Distributions } while (!done);
8903*c54f35caSApple OSS Distributions
8904*c54f35caSApple OSS Distributions *empty = done;
8905*c54f35caSApple OSS Distributions
8906*c54f35caSApple OSS Distributions if (more) {
8907*c54f35caSApple OSS Distributions // Retired a request that may unblock a previously visited request
8908*c54f35caSApple OSS Distributions // that is still waiting on the work queue. Must trigger another
8909*c54f35caSApple OSS Distributions // queue check.
8910*c54f35caSApple OSS Distributions fProducerCount++;
8911*c54f35caSApple OSS Distributions }
8912*c54f35caSApple OSS Distributions
8913*c54f35caSApple OSS Distributions return more;
8914*c54f35caSApple OSS Distributions }
8915*c54f35caSApple OSS Distributions
8916*c54f35caSApple OSS Distributions bool
checkForWork(void)8917*c54f35caSApple OSS Distributions IOPMWorkQueue::checkForWork( void )
8918*c54f35caSApple OSS Distributions {
8919*c54f35caSApple OSS Distributions IOServicePM * entry;
8920*c54f35caSApple OSS Distributions IOServicePM * next;
8921*c54f35caSApple OSS Distributions bool more = false;
8922*c54f35caSApple OSS Distributions bool empty;
8923*c54f35caSApple OSS Distributions
8924*c54f35caSApple OSS Distributions #if WORK_QUEUE_STATS
8925*c54f35caSApple OSS Distributions fStatCheckForWork++;
8926*c54f35caSApple OSS Distributions #endif
8927*c54f35caSApple OSS Distributions
8928*c54f35caSApple OSS Distributions // Iterate over all IOServicePM entries in the work queue,
8929*c54f35caSApple OSS Distributions // and check each entry's request queue.
8930*c54f35caSApple OSS Distributions
8931*c54f35caSApple OSS Distributions while (fConsumerCount != fProducerCount) {
8932*c54f35caSApple OSS Distributions PM_LOG3("IOPMWorkQueue: checkForWork %u %u\n",
8933*c54f35caSApple OSS Distributions fProducerCount, fConsumerCount);
8934*c54f35caSApple OSS Distributions
8935*c54f35caSApple OSS Distributions fConsumerCount = fProducerCount;
8936*c54f35caSApple OSS Distributions
8937*c54f35caSApple OSS Distributions #if WORK_QUEUE_STATS
8938*c54f35caSApple OSS Distributions if (queue_empty(&fWorkQueue)) {
8939*c54f35caSApple OSS Distributions fStatQueueEmpty++;
8940*c54f35caSApple OSS Distributions break;
8941*c54f35caSApple OSS Distributions }
8942*c54f35caSApple OSS Distributions fStatScanEntries++;
8943*c54f35caSApple OSS Distributions uint32_t cachedWorkCount = gIOPMWorkInvokeCount;
8944*c54f35caSApple OSS Distributions #endif
8945*c54f35caSApple OSS Distributions
8946*c54f35caSApple OSS Distributions __IGNORE_WCASTALIGN(entry = (typeof(entry))queue_first(&fWorkQueue));
8947*c54f35caSApple OSS Distributions while (!queue_end(&fWorkQueue, (queue_entry_t) entry)) {
8948*c54f35caSApple OSS Distributions more |= checkRequestQueue(&entry->RequestHead, &empty);
8949*c54f35caSApple OSS Distributions
8950*c54f35caSApple OSS Distributions // Get next entry, points to head if current entry is last.
8951*c54f35caSApple OSS Distributions __IGNORE_WCASTALIGN(next = (typeof(next))queue_next(&entry->WorkChain));
8952*c54f35caSApple OSS Distributions
8953*c54f35caSApple OSS Distributions // if request queue is empty, remove IOServicePM from work queue.
8954*c54f35caSApple OSS Distributions if (empty) {
8955*c54f35caSApple OSS Distributions assert(fQueueLength);
8956*c54f35caSApple OSS Distributions if (fQueueLength) {
8957*c54f35caSApple OSS Distributions fQueueLength--;
8958*c54f35caSApple OSS Distributions }
8959*c54f35caSApple OSS Distributions PM_LOG3("IOPMWorkQueue: [%u] removed %s@%p from queue\n",
8960*c54f35caSApple OSS Distributions fQueueLength, entry->Name, OBFUSCATE(entry));
8961*c54f35caSApple OSS Distributions queue_remove(&fWorkQueue, entry, typeof(entry), WorkChain);
8962*c54f35caSApple OSS Distributions }
8963*c54f35caSApple OSS Distributions entry = next;
8964*c54f35caSApple OSS Distributions }
8965*c54f35caSApple OSS Distributions
8966*c54f35caSApple OSS Distributions #if WORK_QUEUE_STATS
8967*c54f35caSApple OSS Distributions if (cachedWorkCount == gIOPMWorkInvokeCount) {
8968*c54f35caSApple OSS Distributions fStatNoWorkDone++;
8969*c54f35caSApple OSS Distributions }
8970*c54f35caSApple OSS Distributions #endif
8971*c54f35caSApple OSS Distributions }
8972*c54f35caSApple OSS Distributions
8973*c54f35caSApple OSS Distributions return more;
8974*c54f35caSApple OSS Distributions }
8975*c54f35caSApple OSS Distributions
8976*c54f35caSApple OSS Distributions void
signalWorkAvailable(void)8977*c54f35caSApple OSS Distributions IOPMWorkQueue::signalWorkAvailable( void )
8978*c54f35caSApple OSS Distributions {
8979*c54f35caSApple OSS Distributions fProducerCount++;
8980*c54f35caSApple OSS Distributions IOEventSource::signalWorkAvailable();
8981*c54f35caSApple OSS Distributions }
8982*c54f35caSApple OSS Distributions
8983*c54f35caSApple OSS Distributions void
incrementProducerCount(void)8984*c54f35caSApple OSS Distributions IOPMWorkQueue::incrementProducerCount( void )
8985*c54f35caSApple OSS Distributions {
8986*c54f35caSApple OSS Distributions fProducerCount++;
8987*c54f35caSApple OSS Distributions }
8988*c54f35caSApple OSS Distributions
8989*c54f35caSApple OSS Distributions void
attachQuiesceRequest(IOPMRequest * quiesceRequest)8990*c54f35caSApple OSS Distributions IOPMWorkQueue::attachQuiesceRequest( IOPMRequest * quiesceRequest )
8991*c54f35caSApple OSS Distributions {
8992*c54f35caSApple OSS Distributions IOServicePM * entry;
8993*c54f35caSApple OSS Distributions IOPMRequest * request;
8994*c54f35caSApple OSS Distributions
8995*c54f35caSApple OSS Distributions if (queue_empty(&fWorkQueue)) {
8996*c54f35caSApple OSS Distributions return;
8997*c54f35caSApple OSS Distributions }
8998*c54f35caSApple OSS Distributions
8999*c54f35caSApple OSS Distributions queue_iterate(&fWorkQueue, entry, typeof(entry), WorkChain)
9000*c54f35caSApple OSS Distributions {
9001*c54f35caSApple OSS Distributions queue_iterate(&entry->RequestHead, request, typeof(request), fCommandChain)
9002*c54f35caSApple OSS Distributions {
9003*c54f35caSApple OSS Distributions // Attach the quiesce request to any request in the queue that
9004*c54f35caSApple OSS Distributions // is not linked to a next request. These requests will block
9005*c54f35caSApple OSS Distributions // the quiesce request.
9006*c54f35caSApple OSS Distributions
9007*c54f35caSApple OSS Distributions if (request->isQuiesceBlocker()) {
9008*c54f35caSApple OSS Distributions request->attachNextRequest(quiesceRequest);
9009*c54f35caSApple OSS Distributions }
9010*c54f35caSApple OSS Distributions }
9011*c54f35caSApple OSS Distributions }
9012*c54f35caSApple OSS Distributions }
9013*c54f35caSApple OSS Distributions
9014*c54f35caSApple OSS Distributions void
finishQuiesceRequest(IOPMRequest * quiesceRequest)9015*c54f35caSApple OSS Distributions IOPMWorkQueue::finishQuiesceRequest( IOPMRequest * quiesceRequest )
9016*c54f35caSApple OSS Distributions {
9017*c54f35caSApple OSS Distributions if (fQuiesceRequest && (quiesceRequest == fQuiesceRequest) &&
9018*c54f35caSApple OSS Distributions (fQuiesceStartTime != 0)) {
9019*c54f35caSApple OSS Distributions fInvokeAction = NULL;
9020*c54f35caSApple OSS Distributions fQuiesceFinishTime = mach_absolute_time();
9021*c54f35caSApple OSS Distributions }
9022*c54f35caSApple OSS Distributions }
9023*c54f35caSApple OSS Distributions
9024*c54f35caSApple OSS Distributions // MARK: -
9025*c54f35caSApple OSS Distributions // MARK: IOPMCompletionQueue
9026*c54f35caSApple OSS Distributions
9027*c54f35caSApple OSS Distributions //*********************************************************************************
9028*c54f35caSApple OSS Distributions // IOPMCompletionQueue Class
9029*c54f35caSApple OSS Distributions //*********************************************************************************
9030*c54f35caSApple OSS Distributions
9031*c54f35caSApple OSS Distributions OSDefineMetaClassAndStructors( IOPMCompletionQueue, IOEventSource );
9032*c54f35caSApple OSS Distributions
9033*c54f35caSApple OSS Distributions #pragma clang diagnostic push
9034*c54f35caSApple OSS Distributions #pragma clang diagnostic ignored "-Wcast-function-type"
9035*c54f35caSApple OSS Distributions
9036*c54f35caSApple OSS Distributions IOPMCompletionQueue *
create(IOService * inOwner,Action inAction)9037*c54f35caSApple OSS Distributions IOPMCompletionQueue::create( IOService * inOwner, Action inAction )
9038*c54f35caSApple OSS Distributions {
9039*c54f35caSApple OSS Distributions IOPMCompletionQueue * me = OSTypeAlloc(IOPMCompletionQueue);
9040*c54f35caSApple OSS Distributions if (me && !me->init(inOwner, inAction)) {
9041*c54f35caSApple OSS Distributions me->release();
9042*c54f35caSApple OSS Distributions me = NULL;
9043*c54f35caSApple OSS Distributions }
9044*c54f35caSApple OSS Distributions return me;
9045*c54f35caSApple OSS Distributions }
9046*c54f35caSApple OSS Distributions
9047*c54f35caSApple OSS Distributions bool
init(IOService * inOwner,Action inAction)9048*c54f35caSApple OSS Distributions IOPMCompletionQueue::init( IOService * inOwner, Action inAction )
9049*c54f35caSApple OSS Distributions {
9050*c54f35caSApple OSS Distributions if (!inAction || !IOEventSource::init(inOwner, (IOEventSourceAction)inAction)) {
9051*c54f35caSApple OSS Distributions return false;
9052*c54f35caSApple OSS Distributions }
9053*c54f35caSApple OSS Distributions
9054*c54f35caSApple OSS Distributions queue_init(&fQueue);
9055*c54f35caSApple OSS Distributions return true;
9056*c54f35caSApple OSS Distributions }
9057*c54f35caSApple OSS Distributions
9058*c54f35caSApple OSS Distributions
9059*c54f35caSApple OSS Distributions bool
queuePMRequest(IOPMRequest * request)9060*c54f35caSApple OSS Distributions IOPMCompletionQueue::queuePMRequest( IOPMRequest * request )
9061*c54f35caSApple OSS Distributions {
9062*c54f35caSApple OSS Distributions bool more;
9063*c54f35caSApple OSS Distributions
9064*c54f35caSApple OSS Distributions assert(request);
9065*c54f35caSApple OSS Distributions // unblock dependent request
9066*c54f35caSApple OSS Distributions more = request->detachNextRequest();
9067*c54f35caSApple OSS Distributions queue_enter(&fQueue, request, typeof(request), fCommandChain);
9068*c54f35caSApple OSS Distributions return more;
9069*c54f35caSApple OSS Distributions }
9070*c54f35caSApple OSS Distributions
9071*c54f35caSApple OSS Distributions bool
checkForWork(void)9072*c54f35caSApple OSS Distributions IOPMCompletionQueue::checkForWork( void )
9073*c54f35caSApple OSS Distributions {
9074*c54f35caSApple OSS Distributions Action dqAction = (Action) action;
9075*c54f35caSApple OSS Distributions IOPMRequest * request;
9076*c54f35caSApple OSS Distributions IOPMRequest * next;
9077*c54f35caSApple OSS Distributions IOService * target;
9078*c54f35caSApple OSS Distributions bool more = false;
9079*c54f35caSApple OSS Distributions
9080*c54f35caSApple OSS Distributions request = (typeof(request))queue_first(&fQueue);
9081*c54f35caSApple OSS Distributions while (!queue_end(&fQueue, (queue_entry_t) request)) {
9082*c54f35caSApple OSS Distributions next = (typeof(next))queue_next(&request->fCommandChain);
9083*c54f35caSApple OSS Distributions if (!request->isFreeBlocked()) {
9084*c54f35caSApple OSS Distributions queue_remove(&fQueue, request, typeof(request), fCommandChain);
9085*c54f35caSApple OSS Distributions target = request->getTarget();
9086*c54f35caSApple OSS Distributions assert(target);
9087*c54f35caSApple OSS Distributions more |= (*dqAction)( target, request, this );
9088*c54f35caSApple OSS Distributions }
9089*c54f35caSApple OSS Distributions request = next;
9090*c54f35caSApple OSS Distributions }
9091*c54f35caSApple OSS Distributions
9092*c54f35caSApple OSS Distributions return more;
9093*c54f35caSApple OSS Distributions }
9094*c54f35caSApple OSS Distributions
9095*c54f35caSApple OSS Distributions #pragma clang diagnostic pop
9096*c54f35caSApple OSS Distributions
9097*c54f35caSApple OSS Distributions // MARK: -
9098*c54f35caSApple OSS Distributions // MARK: IOServicePM
9099*c54f35caSApple OSS Distributions
OSDefineMetaClassAndStructors(IOServicePM,OSObject)9100*c54f35caSApple OSS Distributions OSDefineMetaClassAndStructors(IOServicePM, OSObject)
9101*c54f35caSApple OSS Distributions
9102*c54f35caSApple OSS Distributions //*********************************************************************************
9103*c54f35caSApple OSS Distributions // serialize
9104*c54f35caSApple OSS Distributions //
9105*c54f35caSApple OSS Distributions // Serialize IOServicePM for debugging.
9106*c54f35caSApple OSS Distributions //*********************************************************************************
9107*c54f35caSApple OSS Distributions
9108*c54f35caSApple OSS Distributions static void
9109*c54f35caSApple OSS Distributions setPMProperty( OSDictionary * dict, const char * key, uint64_t value )
9110*c54f35caSApple OSS Distributions {
9111*c54f35caSApple OSS Distributions OSNumber * num = OSNumber::withNumber(value, sizeof(value) * 8);
9112*c54f35caSApple OSS Distributions if (num) {
9113*c54f35caSApple OSS Distributions dict->setObject(key, num);
9114*c54f35caSApple OSS Distributions num->release();
9115*c54f35caSApple OSS Distributions }
9116*c54f35caSApple OSS Distributions }
9117*c54f35caSApple OSS Distributions
9118*c54f35caSApple OSS Distributions IOReturn
gatedSerialize(OSSerialize * s) const9119*c54f35caSApple OSS Distributions IOServicePM::gatedSerialize( OSSerialize * s ) const
9120*c54f35caSApple OSS Distributions {
9121*c54f35caSApple OSS Distributions OSDictionary * dict;
9122*c54f35caSApple OSS Distributions bool ok = false;
9123*c54f35caSApple OSS Distributions int powerClamp = -1;
9124*c54f35caSApple OSS Distributions int dictSize = 6;
9125*c54f35caSApple OSS Distributions
9126*c54f35caSApple OSS Distributions if (IdleTimerPeriod) {
9127*c54f35caSApple OSS Distributions dictSize += 4;
9128*c54f35caSApple OSS Distributions }
9129*c54f35caSApple OSS Distributions
9130*c54f35caSApple OSS Distributions if (PMActions.state & kPMActionsStatePowerClamped) {
9131*c54f35caSApple OSS Distributions dictSize += 1;
9132*c54f35caSApple OSS Distributions powerClamp = 0;
9133*c54f35caSApple OSS Distributions if (PMActions.flags &
9134*c54f35caSApple OSS Distributions (kPMActionsFlagIsDisplayWrangler | kPMActionsFlagIsGraphicsDriver)) {
9135*c54f35caSApple OSS Distributions powerClamp++;
9136*c54f35caSApple OSS Distributions }
9137*c54f35caSApple OSS Distributions }
9138*c54f35caSApple OSS Distributions
9139*c54f35caSApple OSS Distributions #if WORK_QUEUE_STATS
9140*c54f35caSApple OSS Distributions if (gIOPMRootNode == ControllingDriver) {
9141*c54f35caSApple OSS Distributions dictSize += 4;
9142*c54f35caSApple OSS Distributions }
9143*c54f35caSApple OSS Distributions #endif
9144*c54f35caSApple OSS Distributions
9145*c54f35caSApple OSS Distributions if (PowerClients) {
9146*c54f35caSApple OSS Distributions dict = OSDictionary::withDictionary(
9147*c54f35caSApple OSS Distributions PowerClients, PowerClients->getCount() + dictSize);
9148*c54f35caSApple OSS Distributions } else {
9149*c54f35caSApple OSS Distributions dict = OSDictionary::withCapacity(dictSize);
9150*c54f35caSApple OSS Distributions }
9151*c54f35caSApple OSS Distributions
9152*c54f35caSApple OSS Distributions if (dict) {
9153*c54f35caSApple OSS Distributions setPMProperty(dict, "CurrentPowerState", CurrentPowerState);
9154*c54f35caSApple OSS Distributions setPMProperty(dict, "CapabilityFlags", CurrentCapabilityFlags);
9155*c54f35caSApple OSS Distributions if (NumberOfPowerStates) {
9156*c54f35caSApple OSS Distributions setPMProperty(dict, "MaxPowerState", NumberOfPowerStates - 1);
9157*c54f35caSApple OSS Distributions }
9158*c54f35caSApple OSS Distributions if (DesiredPowerState != CurrentPowerState) {
9159*c54f35caSApple OSS Distributions setPMProperty(dict, "DesiredPowerState", DesiredPowerState);
9160*c54f35caSApple OSS Distributions }
9161*c54f35caSApple OSS Distributions if (kIOPM_Finished != MachineState) {
9162*c54f35caSApple OSS Distributions setPMProperty(dict, "MachineState", MachineState);
9163*c54f35caSApple OSS Distributions }
9164*c54f35caSApple OSS Distributions if (DeviceOverrideEnabled) {
9165*c54f35caSApple OSS Distributions dict->setObject("PowerOverrideOn", kOSBooleanTrue);
9166*c54f35caSApple OSS Distributions }
9167*c54f35caSApple OSS Distributions if (powerClamp >= 0) {
9168*c54f35caSApple OSS Distributions setPMProperty(dict, "PowerClamp", powerClamp);
9169*c54f35caSApple OSS Distributions }
9170*c54f35caSApple OSS Distributions
9171*c54f35caSApple OSS Distributions if (IdleTimerPeriod) {
9172*c54f35caSApple OSS Distributions AbsoluteTime now;
9173*c54f35caSApple OSS Distributions AbsoluteTime delta;
9174*c54f35caSApple OSS Distributions uint64_t nsecs;
9175*c54f35caSApple OSS Distributions
9176*c54f35caSApple OSS Distributions clock_get_uptime(&now);
9177*c54f35caSApple OSS Distributions
9178*c54f35caSApple OSS Distributions // The idle timer period in milliseconds
9179*c54f35caSApple OSS Distributions setPMProperty(dict, "IdleTimerPeriod", NextIdleTimerPeriod * 1000ULL);
9180*c54f35caSApple OSS Distributions
9181*c54f35caSApple OSS Distributions // Number of tickles since the last idle timer expiration
9182*c54f35caSApple OSS Distributions setPMProperty(dict, "ActivityTickles", ActivityTickleCount);
9183*c54f35caSApple OSS Distributions
9184*c54f35caSApple OSS Distributions if (AbsoluteTime_to_scalar(&DeviceActiveTimestamp)) {
9185*c54f35caSApple OSS Distributions // Milliseconds since the last activity tickle
9186*c54f35caSApple OSS Distributions delta = now;
9187*c54f35caSApple OSS Distributions SUB_ABSOLUTETIME(&delta, &DeviceActiveTimestamp);
9188*c54f35caSApple OSS Distributions absolutetime_to_nanoseconds(delta, &nsecs);
9189*c54f35caSApple OSS Distributions setPMProperty(dict, "TimeSinceLastTickle", NS_TO_MS(nsecs));
9190*c54f35caSApple OSS Distributions }
9191*c54f35caSApple OSS Distributions
9192*c54f35caSApple OSS Distributions if (!IdleTimerStopped && AbsoluteTime_to_scalar(&IdleTimerStartTime)) {
9193*c54f35caSApple OSS Distributions // Idle timer elapsed time in milliseconds
9194*c54f35caSApple OSS Distributions delta = now;
9195*c54f35caSApple OSS Distributions SUB_ABSOLUTETIME(&delta, &IdleTimerStartTime);
9196*c54f35caSApple OSS Distributions absolutetime_to_nanoseconds(delta, &nsecs);
9197*c54f35caSApple OSS Distributions setPMProperty(dict, "IdleTimerElapsedTime", NS_TO_MS(nsecs));
9198*c54f35caSApple OSS Distributions }
9199*c54f35caSApple OSS Distributions }
9200*c54f35caSApple OSS Distributions
9201*c54f35caSApple OSS Distributions #if WORK_QUEUE_STATS
9202*c54f35caSApple OSS Distributions if (gIOPMRootNode == Owner) {
9203*c54f35caSApple OSS Distributions setPMProperty(dict, "WQ-CheckForWork",
9204*c54f35caSApple OSS Distributions gIOPMWorkQueue->fStatCheckForWork);
9205*c54f35caSApple OSS Distributions setPMProperty(dict, "WQ-ScanEntries",
9206*c54f35caSApple OSS Distributions gIOPMWorkQueue->fStatScanEntries);
9207*c54f35caSApple OSS Distributions setPMProperty(dict, "WQ-QueueEmpty",
9208*c54f35caSApple OSS Distributions gIOPMWorkQueue->fStatQueueEmpty);
9209*c54f35caSApple OSS Distributions setPMProperty(dict, "WQ-NoWorkDone",
9210*c54f35caSApple OSS Distributions gIOPMWorkQueue->fStatNoWorkDone);
9211*c54f35caSApple OSS Distributions }
9212*c54f35caSApple OSS Distributions #endif
9213*c54f35caSApple OSS Distributions
9214*c54f35caSApple OSS Distributions if (HasAdvisoryDesire && !gIOPMAdvisoryTickleEnabled) {
9215*c54f35caSApple OSS Distributions // Don't report advisory tickle when it has no influence
9216*c54f35caSApple OSS Distributions dict->removeObject(gIOPMPowerClientAdvisoryTickle);
9217*c54f35caSApple OSS Distributions }
9218*c54f35caSApple OSS Distributions
9219*c54f35caSApple OSS Distributions ok = dict->serialize(s);
9220*c54f35caSApple OSS Distributions dict->release();
9221*c54f35caSApple OSS Distributions }
9222*c54f35caSApple OSS Distributions
9223*c54f35caSApple OSS Distributions return ok ? kIOReturnSuccess : kIOReturnNoMemory;
9224*c54f35caSApple OSS Distributions }
9225*c54f35caSApple OSS Distributions
9226*c54f35caSApple OSS Distributions bool
serialize(OSSerialize * s) const9227*c54f35caSApple OSS Distributions IOServicePM::serialize( OSSerialize * s ) const
9228*c54f35caSApple OSS Distributions {
9229*c54f35caSApple OSS Distributions IOReturn ret = kIOReturnNotReady;
9230*c54f35caSApple OSS Distributions
9231*c54f35caSApple OSS Distributions if (gIOPMWatchDogThread == current_thread()) {
9232*c54f35caSApple OSS Distributions // Calling without lock as this data is collected for debug purpose, before reboot.
9233*c54f35caSApple OSS Distributions // The workloop is probably already hung in state machine.
9234*c54f35caSApple OSS Distributions ret = gatedSerialize(s);
9235*c54f35caSApple OSS Distributions } else if (gIOPMWorkLoop) {
9236*c54f35caSApple OSS Distributions ret = gIOPMWorkLoop->runAction(
9237*c54f35caSApple OSS Distributions OSMemberFunctionCast(IOWorkLoop::Action, this, &IOServicePM::gatedSerialize),
9238*c54f35caSApple OSS Distributions (OSObject *) this, (void *) s);
9239*c54f35caSApple OSS Distributions }
9240*c54f35caSApple OSS Distributions
9241*c54f35caSApple OSS Distributions return kIOReturnSuccess == ret;
9242*c54f35caSApple OSS Distributions }
9243*c54f35caSApple OSS Distributions
9244*c54f35caSApple OSS Distributions void
pmPrint(uint32_t event,uintptr_t param1,uintptr_t param2) const9245*c54f35caSApple OSS Distributions IOServicePM::pmPrint(
9246*c54f35caSApple OSS Distributions uint32_t event,
9247*c54f35caSApple OSS Distributions uintptr_t param1,
9248*c54f35caSApple OSS Distributions uintptr_t param2 ) const
9249*c54f35caSApple OSS Distributions {
9250*c54f35caSApple OSS Distributions gPlatform->PMLog(Name, event, param1, param2);
9251*c54f35caSApple OSS Distributions }
9252*c54f35caSApple OSS Distributions
9253*c54f35caSApple OSS Distributions void
pmTrace(uint32_t event,uint32_t eventFunc,uintptr_t param1,uintptr_t param2) const9254*c54f35caSApple OSS Distributions IOServicePM::pmTrace(
9255*c54f35caSApple OSS Distributions uint32_t event,
9256*c54f35caSApple OSS Distributions uint32_t eventFunc,
9257*c54f35caSApple OSS Distributions uintptr_t param1,
9258*c54f35caSApple OSS Distributions uintptr_t param2 ) const
9259*c54f35caSApple OSS Distributions {
9260*c54f35caSApple OSS Distributions uintptr_t nameAsArg = 0;
9261*c54f35caSApple OSS Distributions
9262*c54f35caSApple OSS Distributions assert(event < KDBG_CODE_MAX);
9263*c54f35caSApple OSS Distributions assert((eventFunc & ~KDBG_FUNC_MASK) == 0);
9264*c54f35caSApple OSS Distributions
9265*c54f35caSApple OSS Distributions // Copy the first characters of the name into an uintptr_t.
9266*c54f35caSApple OSS Distributions // NULL termination is not required.
9267*c54f35caSApple OSS Distributions strncpy((char*)&nameAsArg, Name, sizeof(nameAsArg));
9268*c54f35caSApple OSS Distributions
9269*c54f35caSApple OSS Distributions #if defined(XNU_TARGET_OS_OSX)
9270*c54f35caSApple OSS Distributions KERNEL_DEBUG_CONSTANT_IST(KDEBUG_TRACE, IODBG_POWER(event) | eventFunc, nameAsArg,
9271*c54f35caSApple OSS Distributions (uintptr_t)Owner->getRegistryEntryID(), (uintptr_t)(OBFUSCATE(param1)),
9272*c54f35caSApple OSS Distributions (uintptr_t)(OBFUSCATE(param2)), 0);
9273*c54f35caSApple OSS Distributions #else
9274*c54f35caSApple OSS Distributions IOTimeStampConstant(IODBG_POWER(event) | eventFunc, nameAsArg, (uintptr_t)Owner->getRegistryEntryID(), (uintptr_t)(OBFUSCATE(param1)), (uintptr_t)(OBFUSCATE(param2)));
9275*c54f35caSApple OSS Distributions #endif
9276*c54f35caSApple OSS Distributions }
9277