1*1031c584SApple OSS Distributions /*
2*1031c584SApple OSS Distributions * Copyright (c) 1998-2020 Apple Inc. All rights reserved.
3*1031c584SApple OSS Distributions *
4*1031c584SApple OSS Distributions * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5*1031c584SApple OSS Distributions *
6*1031c584SApple OSS Distributions * This file contains Original Code and/or Modifications of Original Code
7*1031c584SApple OSS Distributions * as defined in and that are subject to the Apple Public Source License
8*1031c584SApple OSS Distributions * Version 2.0 (the 'License'). You may not use this file except in
9*1031c584SApple OSS Distributions * compliance with the License. The rights granted to you under the License
10*1031c584SApple OSS Distributions * may not be used to create, or enable the creation or redistribution of,
11*1031c584SApple OSS Distributions * unlawful or unlicensed copies of an Apple operating system, or to
12*1031c584SApple OSS Distributions * circumvent, violate, or enable the circumvention or violation of, any
13*1031c584SApple OSS Distributions * terms of an Apple operating system software license agreement.
14*1031c584SApple OSS Distributions *
15*1031c584SApple OSS Distributions * Please obtain a copy of the License at
16*1031c584SApple OSS Distributions * http://www.opensource.apple.com/apsl/ and read it before using this file.
17*1031c584SApple OSS Distributions *
18*1031c584SApple OSS Distributions * The Original Code and all software distributed under the License are
19*1031c584SApple OSS Distributions * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20*1031c584SApple OSS Distributions * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21*1031c584SApple OSS Distributions * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22*1031c584SApple OSS Distributions * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23*1031c584SApple OSS Distributions * Please see the License for the specific language governing rights and
24*1031c584SApple OSS Distributions * limitations under the License.
25*1031c584SApple OSS Distributions *
26*1031c584SApple OSS Distributions * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27*1031c584SApple OSS Distributions */
28*1031c584SApple OSS Distributions
29*1031c584SApple OSS Distributions #include <IOKit/assert.h>
30*1031c584SApple OSS Distributions #include <IOKit/IOKitDebug.h>
31*1031c584SApple OSS Distributions #include <IOKit/IOLib.h>
32*1031c584SApple OSS Distributions #include <IOKit/IOMessage.h>
33*1031c584SApple OSS Distributions #include <IOKit/IOPlatformExpert.h>
34*1031c584SApple OSS Distributions #include <IOKit/IOService.h>
35*1031c584SApple OSS Distributions #include <IOKit/IOUserServer.h>
36*1031c584SApple OSS Distributions #include <IOKit/IOEventSource.h>
37*1031c584SApple OSS Distributions #include <IOKit/IOWorkLoop.h>
38*1031c584SApple OSS Distributions #include <IOKit/IOCommand.h>
39*1031c584SApple OSS Distributions #include <IOKit/IOTimeStamp.h>
40*1031c584SApple OSS Distributions #include <IOKit/IOReportMacros.h>
41*1031c584SApple OSS Distributions #include <IOKit/IODeviceTreeSupport.h>
42*1031c584SApple OSS Distributions
43*1031c584SApple OSS Distributions #include <IOKit/pwr_mgt/IOPMlog.h>
44*1031c584SApple OSS Distributions #include <IOKit/pwr_mgt/IOPMinformee.h>
45*1031c584SApple OSS Distributions #include <IOKit/pwr_mgt/IOPMinformeeList.h>
46*1031c584SApple OSS Distributions #include <IOKit/pwr_mgt/IOPowerConnection.h>
47*1031c584SApple OSS Distributions #include <IOKit/pwr_mgt/RootDomain.h>
48*1031c584SApple OSS Distributions #include <IOKit/pwr_mgt/IOPMPrivate.h>
49*1031c584SApple OSS Distributions
50*1031c584SApple OSS Distributions #include <sys/proc.h>
51*1031c584SApple OSS Distributions #include <sys/proc_internal.h>
52*1031c584SApple OSS Distributions #include <sys/sysctl.h>
53*1031c584SApple OSS Distributions #include <libkern/OSDebug.h>
54*1031c584SApple OSS Distributions #include <kern/thread.h>
55*1031c584SApple OSS Distributions #if DEVELOPMENT || DEBUG
56*1031c584SApple OSS Distributions #include <os/system_event_log.h>
57*1031c584SApple OSS Distributions #endif /* DEVELOPMENT || DEBUG */
58*1031c584SApple OSS Distributions
59*1031c584SApple OSS Distributions // Required for notification instrumentation
60*1031c584SApple OSS Distributions #include "IOServicePrivate.h"
61*1031c584SApple OSS Distributions #include "IOServicePMPrivate.h"
62*1031c584SApple OSS Distributions #include "IOKitKernelInternal.h"
63*1031c584SApple OSS Distributions
64*1031c584SApple OSS Distributions #if USE_SETTLE_TIMER
65*1031c584SApple OSS Distributions static void settle_timer_expired(thread_call_param_t, thread_call_param_t);
66*1031c584SApple OSS Distributions #endif
67*1031c584SApple OSS Distributions static void idle_timer_expired(thread_call_param_t, thread_call_param_t);
68*1031c584SApple OSS Distributions static void tellKernelClientApplier(OSObject * object, void * arg);
69*1031c584SApple OSS Distributions static void tellAppClientApplier(OSObject * object, void * arg);
70*1031c584SApple OSS Distributions static const char * getNotificationPhaseString(uint32_t phase);
71*1031c584SApple OSS Distributions
72*1031c584SApple OSS Distributions static uint64_t
computeTimeDeltaNS(const AbsoluteTime * start)73*1031c584SApple OSS Distributions computeTimeDeltaNS( const AbsoluteTime * start )
74*1031c584SApple OSS Distributions {
75*1031c584SApple OSS Distributions AbsoluteTime now;
76*1031c584SApple OSS Distributions uint64_t nsec;
77*1031c584SApple OSS Distributions
78*1031c584SApple OSS Distributions clock_get_uptime(&now);
79*1031c584SApple OSS Distributions SUB_ABSOLUTETIME(&now, start);
80*1031c584SApple OSS Distributions absolutetime_to_nanoseconds(now, &nsec);
81*1031c584SApple OSS Distributions return nsec;
82*1031c584SApple OSS Distributions }
83*1031c584SApple OSS Distributions
84*1031c584SApple OSS Distributions #if PM_VARS_SUPPORT
85*1031c584SApple OSS Distributions OSDefineMetaClassAndStructors(IOPMprot, OSObject)
86*1031c584SApple OSS Distributions #endif
87*1031c584SApple OSS Distributions
88*1031c584SApple OSS Distributions //******************************************************************************
89*1031c584SApple OSS Distributions // Globals
90*1031c584SApple OSS Distributions //******************************************************************************
91*1031c584SApple OSS Distributions
92*1031c584SApple OSS Distributions static bool gIOPMInitialized = false;
93*1031c584SApple OSS Distributions static uint32_t gIOPMBusyRequestCount = 0;
94*1031c584SApple OSS Distributions static uint32_t gIOPMWorkInvokeCount = 0;
95*1031c584SApple OSS Distributions static uint32_t gIOPMTickleGeneration = 0;
96*1031c584SApple OSS Distributions static IOWorkLoop * gIOPMWorkLoop = NULL;
97*1031c584SApple OSS Distributions static IOPMRequestQueue * gIOPMRequestQueue = NULL;
98*1031c584SApple OSS Distributions static IOPMRequestQueue * gIOPMReplyQueue = NULL;
99*1031c584SApple OSS Distributions static IOPMWorkQueue * gIOPMWorkQueue = NULL;
100*1031c584SApple OSS Distributions static IOPMCompletionQueue * gIOPMCompletionQueue = NULL;
101*1031c584SApple OSS Distributions static IOPMRequest * gIOPMRequest = NULL;
102*1031c584SApple OSS Distributions static IOService * gIOPMRootNode = NULL;
103*1031c584SApple OSS Distributions static IOPlatformExpert * gPlatform = NULL;
104*1031c584SApple OSS Distributions static IOLock * gIOPMInitLock = NULL;
105*1031c584SApple OSS Distributions
106*1031c584SApple OSS Distributions // log setPowerStates and powerStateChange longer than (ns):
107*1031c584SApple OSS Distributions static uint64_t gIOPMSetPowerStateLogNS =
108*1031c584SApple OSS Distributions #if defined(__i386__) || defined(__x86_64__)
109*1031c584SApple OSS Distributions (300ULL * 1000ULL * 1000ULL)
110*1031c584SApple OSS Distributions #else
111*1031c584SApple OSS Distributions (50ULL * 1000ULL * 1000ULL)
112*1031c584SApple OSS Distributions #endif
113*1031c584SApple OSS Distributions ;
114*1031c584SApple OSS Distributions
115*1031c584SApple OSS Distributions const OSSymbol * gIOPMPowerClientDevice = NULL;
116*1031c584SApple OSS Distributions const OSSymbol * gIOPMPowerClientDriver = NULL;
117*1031c584SApple OSS Distributions const OSSymbol * gIOPMPowerClientChildProxy = NULL;
118*1031c584SApple OSS Distributions const OSSymbol * gIOPMPowerClientChildren = NULL;
119*1031c584SApple OSS Distributions const OSSymbol * gIOPMPowerClientRootDomain = NULL;
120*1031c584SApple OSS Distributions
121*1031c584SApple OSS Distributions static const OSSymbol * gIOPMPowerClientAdvisoryTickle = NULL;
122*1031c584SApple OSS Distributions static bool gIOPMAdvisoryTickleEnabled = true;
123*1031c584SApple OSS Distributions static thread_t gIOPMWatchDogThread = NULL;
124*1031c584SApple OSS Distributions TUNABLE_WRITEABLE(uint32_t, gSleepAckTimeout, "pmtimeout", 0);
125*1031c584SApple OSS Distributions
126*1031c584SApple OSS Distributions /*
127*1031c584SApple OSS Distributions * While waiting for a driver callout to complete, we log any instances
128*1031c584SApple OSS Distributions * that have taken longer than the below period (in milliseconds) to return.
129*1031c584SApple OSS Distributions */
130*1031c584SApple OSS Distributions TUNABLE_WRITEABLE(uint32_t, gDriverCalloutTimer, "pmcallouttimer", 2000);
131*1031c584SApple OSS Distributions
132*1031c584SApple OSS Distributions static uint32_t
getPMRequestType(void)133*1031c584SApple OSS Distributions getPMRequestType( void )
134*1031c584SApple OSS Distributions {
135*1031c584SApple OSS Distributions uint32_t type = kIOPMRequestTypeInvalid;
136*1031c584SApple OSS Distributions if (gIOPMRequest) {
137*1031c584SApple OSS Distributions type = gIOPMRequest->getType();
138*1031c584SApple OSS Distributions }
139*1031c584SApple OSS Distributions return type;
140*1031c584SApple OSS Distributions }
141*1031c584SApple OSS Distributions
142*1031c584SApple OSS Distributions SYSCTL_UINT(_kern, OID_AUTO, pmtimeout, CTLFLAG_RW | CTLFLAG_LOCKED, &gSleepAckTimeout, 0, "Power Management Timeout");
143*1031c584SApple OSS Distributions SYSCTL_UINT(_kern, OID_AUTO, pmcallouttimer, CTLFLAG_RW | CTLFLAG_LOCKED, &gDriverCalloutTimer, 0, "Power Management Driver Callout Log Timer");
144*1031c584SApple OSS Distributions
145*1031c584SApple OSS Distributions //******************************************************************************
146*1031c584SApple OSS Distributions // Macros
147*1031c584SApple OSS Distributions //******************************************************************************
148*1031c584SApple OSS Distributions
149*1031c584SApple OSS Distributions #define PM_ERROR(x...) do { kprintf(x);IOLog(x); \
150*1031c584SApple OSS Distributions } while (false)
151*1031c584SApple OSS Distributions #define PM_LOG(x...) do { kprintf(x); } while (false)
152*1031c584SApple OSS Distributions
153*1031c584SApple OSS Distributions #define PM_LOG1(x...) do { \
154*1031c584SApple OSS Distributions if (kIOLogDebugPower & gIOKitDebug) \
155*1031c584SApple OSS Distributions kprintf(x); } while (false)
156*1031c584SApple OSS Distributions
157*1031c584SApple OSS Distributions #define PM_LOG2(x...) do { \
158*1031c584SApple OSS Distributions if (kIOLogDebugPower & gIOKitDebug) \
159*1031c584SApple OSS Distributions kprintf(x); } while (false)
160*1031c584SApple OSS Distributions
161*1031c584SApple OSS Distributions #if 0
162*1031c584SApple OSS Distributions #define PM_LOG3(x...) do { kprintf(x); } while (false)
163*1031c584SApple OSS Distributions #else
164*1031c584SApple OSS Distributions #define PM_LOG3(x...)
165*1031c584SApple OSS Distributions #endif
166*1031c584SApple OSS Distributions
167*1031c584SApple OSS Distributions #define RD_LOG(x...) do { \
168*1031c584SApple OSS Distributions if ((kIOLogPMRootDomain & gIOKitDebug) && \
169*1031c584SApple OSS Distributions (getPMRootDomain() == this)) { \
170*1031c584SApple OSS Distributions kprintf("PMRD: " x); \
171*1031c584SApple OSS Distributions }} while (false)
172*1031c584SApple OSS Distributions #define PM_ASSERT_IN_GATE(x) \
173*1031c584SApple OSS Distributions do { \
174*1031c584SApple OSS Distributions assert(gIOPMWorkLoop->inGate()); \
175*1031c584SApple OSS Distributions } while(false)
176*1031c584SApple OSS Distributions
177*1031c584SApple OSS Distributions #define PM_LOCK() IOLockLock(fPMLock)
178*1031c584SApple OSS Distributions #define PM_UNLOCK() IOLockUnlock(fPMLock)
179*1031c584SApple OSS Distributions #define PM_LOCK_SLEEP(event, dl) IOLockSleepDeadline(fPMLock, event, dl, THREAD_UNINT)
180*1031c584SApple OSS Distributions #define PM_LOCK_WAKEUP(event) IOLockWakeup(fPMLock, event, false)
181*1031c584SApple OSS Distributions
182*1031c584SApple OSS Distributions #define us_per_s 1000000
183*1031c584SApple OSS Distributions #define ns_per_us 1000
184*1031c584SApple OSS Distributions #define k30Seconds (30*us_per_s)
185*1031c584SApple OSS Distributions #define k5Seconds ( 5*us_per_s)
186*1031c584SApple OSS Distributions #define k7Seconds ( 7*us_per_s)
187*1031c584SApple OSS Distributions #if !defined(XNU_TARGET_OS_OSX)
188*1031c584SApple OSS Distributions #define kCanSleepMaxTimeReq k5Seconds
189*1031c584SApple OSS Distributions #define kWillSleepMaxTimeReq k7Seconds
190*1031c584SApple OSS Distributions #else /* defined(XNU_TARGET_OS_OSX) */
191*1031c584SApple OSS Distributions #define kCanSleepMaxTimeReq k30Seconds
192*1031c584SApple OSS Distributions #define kWillSleepMaxTimeReq k30Seconds
193*1031c584SApple OSS Distributions #endif /* defined(XNU_TARGET_OS_OSX) */
194*1031c584SApple OSS Distributions #define kMaxTimeRequested k30Seconds
195*1031c584SApple OSS Distributions #define kMinAckTimeoutTicks (10*1000000)
196*1031c584SApple OSS Distributions #define kIOPMTardyAckSPSKey "IOPMTardyAckSetPowerState"
197*1031c584SApple OSS Distributions #define kIOPMTardyAckPSCKey "IOPMTardyAckPowerStateChange"
198*1031c584SApple OSS Distributions #define kPwrMgtKey "IOPowerManagement"
199*1031c584SApple OSS Distributions
200*1031c584SApple OSS Distributions #define OUR_PMLog(t, a, b) do { \
201*1031c584SApple OSS Distributions if (pwrMgt) { \
202*1031c584SApple OSS Distributions if (gIOKitDebug & kIOLogPower) \
203*1031c584SApple OSS Distributions pwrMgt->pmPrint(t, a, b); \
204*1031c584SApple OSS Distributions if (gIOKitTrace & kIOTracePowerMgmt) \
205*1031c584SApple OSS Distributions pwrMgt->pmTrace(t, DBG_FUNC_NONE, a, b); \
206*1031c584SApple OSS Distributions } \
207*1031c584SApple OSS Distributions } while(0)
208*1031c584SApple OSS Distributions
209*1031c584SApple OSS Distributions #define OUR_PMLogFuncStart(t, a, b) do { \
210*1031c584SApple OSS Distributions if (pwrMgt) { \
211*1031c584SApple OSS Distributions if (gIOKitDebug & kIOLogPower) \
212*1031c584SApple OSS Distributions pwrMgt->pmPrint(t, a, b); \
213*1031c584SApple OSS Distributions if (gIOKitTrace & kIOTracePowerMgmt) \
214*1031c584SApple OSS Distributions pwrMgt->pmTrace(t, DBG_FUNC_START, a, b); \
215*1031c584SApple OSS Distributions } \
216*1031c584SApple OSS Distributions } while(0)
217*1031c584SApple OSS Distributions
218*1031c584SApple OSS Distributions #define OUR_PMLogFuncEnd(t, a, b) do { \
219*1031c584SApple OSS Distributions if (pwrMgt) { \
220*1031c584SApple OSS Distributions if (gIOKitDebug & kIOLogPower) \
221*1031c584SApple OSS Distributions pwrMgt->pmPrint(-t, a, b); \
222*1031c584SApple OSS Distributions if (gIOKitTrace & kIOTracePowerMgmt) \
223*1031c584SApple OSS Distributions pwrMgt->pmTrace(t, DBG_FUNC_END, a, b); \
224*1031c584SApple OSS Distributions } \
225*1031c584SApple OSS Distributions } while(0)
226*1031c584SApple OSS Distributions
227*1031c584SApple OSS Distributions #define NS_TO_MS(nsec) ((int)((nsec) / 1000000ULL))
228*1031c584SApple OSS Distributions #define NS_TO_US(nsec) ((int)((nsec) / 1000ULL))
229*1031c584SApple OSS Distributions
230*1031c584SApple OSS Distributions #define SUPPORT_IDLE_CANCEL 1
231*1031c584SApple OSS Distributions
232*1031c584SApple OSS Distributions #define kIOPMPowerStateMax 0xFFFFFFFF
233*1031c584SApple OSS Distributions #define kInvalidTicklePowerState kIOPMPowerStateMax
234*1031c584SApple OSS Distributions
235*1031c584SApple OSS Distributions #define kNoTickleCancelWindow (60ULL * 1000ULL * 1000ULL * 1000ULL)
236*1031c584SApple OSS Distributions
237*1031c584SApple OSS Distributions #define IS_PM_ROOT (this == gIOPMRootNode)
238*1031c584SApple OSS Distributions #define IS_ROOT_DOMAIN (getPMRootDomain() == this)
239*1031c584SApple OSS Distributions #define IS_POWER_DROP (StateOrder(fHeadNotePowerState) < StateOrder(fCurrentPowerState))
240*1031c584SApple OSS Distributions #define IS_POWER_RISE (StateOrder(fHeadNotePowerState) > StateOrder(fCurrentPowerState))
241*1031c584SApple OSS Distributions
242*1031c584SApple OSS Distributions // log app responses longer than (ns):
243*1031c584SApple OSS Distributions #define LOG_APP_RESPONSE_TIMES (100ULL * 1000ULL * 1000ULL)
244*1031c584SApple OSS Distributions // use message tracer to log messages longer than (ns):
245*1031c584SApple OSS Distributions #define LOG_APP_RESPONSE_MSG_TRACER (3 * 1000ULL * 1000ULL * 1000ULL)
246*1031c584SApple OSS Distributions
247*1031c584SApple OSS Distributions // log kext responses longer than (ns):
248*1031c584SApple OSS Distributions #define LOG_KEXT_RESPONSE_TIMES (100ULL * 1000ULL * 1000ULL)
249*1031c584SApple OSS Distributions
250*1031c584SApple OSS Distributions enum {
251*1031c584SApple OSS Distributions kReserveDomainPower = 1
252*1031c584SApple OSS Distributions };
253*1031c584SApple OSS Distributions
254*1031c584SApple OSS Distributions #define MS_PUSH(n) \
255*1031c584SApple OSS Distributions do { assert(kIOPM_BadMachineState == fSavedMachineState); \
256*1031c584SApple OSS Distributions assert(kIOPM_BadMachineState != n); \
257*1031c584SApple OSS Distributions fSavedMachineState = n; } while (false)
258*1031c584SApple OSS Distributions
259*1031c584SApple OSS Distributions #define MS_POP() \
260*1031c584SApple OSS Distributions do { assert(kIOPM_BadMachineState != fSavedMachineState); \
261*1031c584SApple OSS Distributions fMachineState = fSavedMachineState; \
262*1031c584SApple OSS Distributions fSavedMachineState = kIOPM_BadMachineState; } while (false)
263*1031c584SApple OSS Distributions
264*1031c584SApple OSS Distributions #define PM_ACTION_TICKLE(a) \
265*1031c584SApple OSS Distributions do { if (fPMActions.a) { \
266*1031c584SApple OSS Distributions (fPMActions.a)(fPMActions.target, this, &fPMActions); } \
267*1031c584SApple OSS Distributions } while (false)
268*1031c584SApple OSS Distributions
269*1031c584SApple OSS Distributions #define PM_ACTION_CHANGE(a, x, y) \
270*1031c584SApple OSS Distributions do { if (fPMActions.a) { \
271*1031c584SApple OSS Distributions (fPMActions.a)(fPMActions.target, this, &fPMActions, gIOPMRequest, x, y); } \
272*1031c584SApple OSS Distributions } while (false)
273*1031c584SApple OSS Distributions
274*1031c584SApple OSS Distributions #define PM_ACTION_CLIENT(a, x, y, z) \
275*1031c584SApple OSS Distributions do { if (fPMActions.a) { \
276*1031c584SApple OSS Distributions (fPMActions.a)(fPMActions.target, this, &fPMActions, x, y, z); } \
277*1031c584SApple OSS Distributions } while (false)
278*1031c584SApple OSS Distributions
279*1031c584SApple OSS Distributions static OSNumber * copyClientIDForNotification(
280*1031c584SApple OSS Distributions OSObject *object,
281*1031c584SApple OSS Distributions IOPMInterestContext *context);
282*1031c584SApple OSS Distributions
283*1031c584SApple OSS Distributions static void logClientIDForNotification(
284*1031c584SApple OSS Distributions OSObject *object,
285*1031c584SApple OSS Distributions IOPMInterestContext *context,
286*1031c584SApple OSS Distributions const char *logString);
287*1031c584SApple OSS Distributions
288*1031c584SApple OSS Distributions //*********************************************************************************
289*1031c584SApple OSS Distributions // PM machine states
290*1031c584SApple OSS Distributions //
291*1031c584SApple OSS Distributions // Check kgmacros after modifying machine states.
292*1031c584SApple OSS Distributions //*********************************************************************************
293*1031c584SApple OSS Distributions
294*1031c584SApple OSS Distributions enum {
295*1031c584SApple OSS Distributions kIOPM_Finished = 0,
296*1031c584SApple OSS Distributions
297*1031c584SApple OSS Distributions kIOPM_OurChangeTellClientsPowerDown = 1,
298*1031c584SApple OSS Distributions kIOPM_OurChangeTellUserPMPolicyPowerDown = 2,
299*1031c584SApple OSS Distributions kIOPM_OurChangeTellPriorityClientsPowerDown = 3,
300*1031c584SApple OSS Distributions kIOPM_OurChangeNotifyInterestedDriversWillChange = 4,
301*1031c584SApple OSS Distributions kIOPM_OurChangeSetPowerState = 5,
302*1031c584SApple OSS Distributions kIOPM_OurChangeWaitForPowerSettle = 6,
303*1031c584SApple OSS Distributions kIOPM_OurChangeNotifyInterestedDriversDidChange = 7,
304*1031c584SApple OSS Distributions kIOPM_OurChangeTellCapabilityDidChange = 8,
305*1031c584SApple OSS Distributions kIOPM_OurChangeFinish = 9,
306*1031c584SApple OSS Distributions
307*1031c584SApple OSS Distributions kIOPM_ParentChangeTellPriorityClientsPowerDown = 10,
308*1031c584SApple OSS Distributions kIOPM_ParentChangeNotifyInterestedDriversWillChange = 11,
309*1031c584SApple OSS Distributions kIOPM_ParentChangeSetPowerState = 12,
310*1031c584SApple OSS Distributions kIOPM_ParentChangeWaitForPowerSettle = 13,
311*1031c584SApple OSS Distributions kIOPM_ParentChangeNotifyInterestedDriversDidChange = 14,
312*1031c584SApple OSS Distributions kIOPM_ParentChangeTellCapabilityDidChange = 15,
313*1031c584SApple OSS Distributions kIOPM_ParentChangeAcknowledgePowerChange = 16,
314*1031c584SApple OSS Distributions
315*1031c584SApple OSS Distributions kIOPM_NotifyChildrenStart = 17,
316*1031c584SApple OSS Distributions kIOPM_NotifyChildrenOrdered = 18,
317*1031c584SApple OSS Distributions kIOPM_NotifyChildrenDelayed = 19,
318*1031c584SApple OSS Distributions kIOPM_SyncTellClientsPowerDown = 20,
319*1031c584SApple OSS Distributions kIOPM_SyncTellPriorityClientsPowerDown = 21,
320*1031c584SApple OSS Distributions kIOPM_SyncNotifyWillChange = 22,
321*1031c584SApple OSS Distributions kIOPM_SyncNotifyDidChange = 23,
322*1031c584SApple OSS Distributions kIOPM_SyncTellCapabilityDidChange = 24,
323*1031c584SApple OSS Distributions kIOPM_SyncFinish = 25,
324*1031c584SApple OSS Distributions kIOPM_TellCapabilityChangeDone = 26,
325*1031c584SApple OSS Distributions kIOPM_DriverThreadCallDone = 27,
326*1031c584SApple OSS Distributions
327*1031c584SApple OSS Distributions kIOPM_BadMachineState = 0xFFFFFFFF
328*1031c584SApple OSS Distributions };
329*1031c584SApple OSS Distributions
330*1031c584SApple OSS Distributions //*********************************************************************************
331*1031c584SApple OSS Distributions // [private static] allocPMInitLock
332*1031c584SApple OSS Distributions //
333*1031c584SApple OSS Distributions // Allocate gIOPMInitLock prior to gIOPMWorkLoop initialization.
334*1031c584SApple OSS Distributions //*********************************************************************************
335*1031c584SApple OSS Distributions
336*1031c584SApple OSS Distributions void
allocPMInitLock(void)337*1031c584SApple OSS Distributions IOService::allocPMInitLock( void )
338*1031c584SApple OSS Distributions {
339*1031c584SApple OSS Distributions gIOPMInitLock = IOLockAlloc();
340*1031c584SApple OSS Distributions assert(gIOPMInitLock);
341*1031c584SApple OSS Distributions }
342*1031c584SApple OSS Distributions
343*1031c584SApple OSS Distributions //*********************************************************************************
344*1031c584SApple OSS Distributions // [public] PMinit
345*1031c584SApple OSS Distributions //
346*1031c584SApple OSS Distributions // Initialize power management.
347*1031c584SApple OSS Distributions //*********************************************************************************
348*1031c584SApple OSS Distributions
349*1031c584SApple OSS Distributions void
PMinit(void)350*1031c584SApple OSS Distributions IOService::PMinit( void )
351*1031c584SApple OSS Distributions {
352*1031c584SApple OSS Distributions if (!initialized) {
353*1031c584SApple OSS Distributions IOLockLock(gIOPMInitLock);
354*1031c584SApple OSS Distributions if (!gIOPMInitialized) {
355*1031c584SApple OSS Distributions gPlatform = getPlatform();
356*1031c584SApple OSS Distributions gIOPMWorkLoop = IOWorkLoop::workLoop();
357*1031c584SApple OSS Distributions if (gIOPMWorkLoop) {
358*1031c584SApple OSS Distributions assert(OSDynamicCast(IOPMrootDomain, this));
359*1031c584SApple OSS Distributions gIOPMRequestQueue = IOPMRequestQueue::create(
360*1031c584SApple OSS Distributions this, OSMemberFunctionCast(IOPMRequestQueue::Action,
361*1031c584SApple OSS Distributions this, &IOService::actionPMRequestQueue));
362*1031c584SApple OSS Distributions
363*1031c584SApple OSS Distributions gIOPMReplyQueue = IOPMRequestQueue::create(
364*1031c584SApple OSS Distributions this, OSMemberFunctionCast(IOPMRequestQueue::Action,
365*1031c584SApple OSS Distributions this, &IOService::actionPMReplyQueue));
366*1031c584SApple OSS Distributions
367*1031c584SApple OSS Distributions gIOPMWorkQueue = IOPMWorkQueue::create(this,
368*1031c584SApple OSS Distributions OSMemberFunctionCast(IOPMWorkQueue::Action, this,
369*1031c584SApple OSS Distributions &IOService::actionPMWorkQueueInvoke),
370*1031c584SApple OSS Distributions OSMemberFunctionCast(IOPMWorkQueue::Action, this,
371*1031c584SApple OSS Distributions &IOService::actionPMWorkQueueRetire));
372*1031c584SApple OSS Distributions
373*1031c584SApple OSS Distributions gIOPMCompletionQueue = IOPMCompletionQueue::create(
374*1031c584SApple OSS Distributions this, OSMemberFunctionCast(IOPMCompletionQueue::Action,
375*1031c584SApple OSS Distributions this, &IOService::actionPMCompletionQueue));
376*1031c584SApple OSS Distributions
377*1031c584SApple OSS Distributions if (gIOPMWorkLoop->addEventSource(gIOPMRequestQueue) !=
378*1031c584SApple OSS Distributions kIOReturnSuccess) {
379*1031c584SApple OSS Distributions gIOPMRequestQueue->release();
380*1031c584SApple OSS Distributions gIOPMRequestQueue = NULL;
381*1031c584SApple OSS Distributions }
382*1031c584SApple OSS Distributions
383*1031c584SApple OSS Distributions if (gIOPMWorkLoop->addEventSource(gIOPMReplyQueue) !=
384*1031c584SApple OSS Distributions kIOReturnSuccess) {
385*1031c584SApple OSS Distributions gIOPMReplyQueue->release();
386*1031c584SApple OSS Distributions gIOPMReplyQueue = NULL;
387*1031c584SApple OSS Distributions }
388*1031c584SApple OSS Distributions
389*1031c584SApple OSS Distributions if (gIOPMWorkLoop->addEventSource(gIOPMWorkQueue) !=
390*1031c584SApple OSS Distributions kIOReturnSuccess) {
391*1031c584SApple OSS Distributions gIOPMWorkQueue->release();
392*1031c584SApple OSS Distributions gIOPMWorkQueue = NULL;
393*1031c584SApple OSS Distributions }
394*1031c584SApple OSS Distributions
395*1031c584SApple OSS Distributions // Must be added after the work queue, which pushes request
396*1031c584SApple OSS Distributions // to the completion queue without signaling the work loop.
397*1031c584SApple OSS Distributions if (gIOPMWorkLoop->addEventSource(gIOPMCompletionQueue) !=
398*1031c584SApple OSS Distributions kIOReturnSuccess) {
399*1031c584SApple OSS Distributions gIOPMCompletionQueue->release();
400*1031c584SApple OSS Distributions gIOPMCompletionQueue = NULL;
401*1031c584SApple OSS Distributions }
402*1031c584SApple OSS Distributions
403*1031c584SApple OSS Distributions gIOPMPowerClientDevice =
404*1031c584SApple OSS Distributions OSSymbol::withCStringNoCopy( "DevicePowerState" );
405*1031c584SApple OSS Distributions
406*1031c584SApple OSS Distributions gIOPMPowerClientDriver =
407*1031c584SApple OSS Distributions OSSymbol::withCStringNoCopy( "DriverPowerState" );
408*1031c584SApple OSS Distributions
409*1031c584SApple OSS Distributions gIOPMPowerClientChildProxy =
410*1031c584SApple OSS Distributions OSSymbol::withCStringNoCopy( "ChildProxyPowerState" );
411*1031c584SApple OSS Distributions
412*1031c584SApple OSS Distributions gIOPMPowerClientChildren =
413*1031c584SApple OSS Distributions OSSymbol::withCStringNoCopy( "ChildrenPowerState" );
414*1031c584SApple OSS Distributions
415*1031c584SApple OSS Distributions gIOPMPowerClientAdvisoryTickle =
416*1031c584SApple OSS Distributions OSSymbol::withCStringNoCopy( "AdvisoryTicklePowerState" );
417*1031c584SApple OSS Distributions
418*1031c584SApple OSS Distributions gIOPMPowerClientRootDomain =
419*1031c584SApple OSS Distributions OSSymbol::withCStringNoCopy( "RootDomainPower" );
420*1031c584SApple OSS Distributions }
421*1031c584SApple OSS Distributions
422*1031c584SApple OSS Distributions if (gIOPMRequestQueue && gIOPMReplyQueue && gIOPMCompletionQueue) {
423*1031c584SApple OSS Distributions gIOPMInitialized = true;
424*1031c584SApple OSS Distributions }
425*1031c584SApple OSS Distributions
426*1031c584SApple OSS Distributions #if (DEVELOPMENT || DEBUG)
427*1031c584SApple OSS Distributions uint32_t setPowerStateLogMS = 0;
428*1031c584SApple OSS Distributions if (PE_parse_boot_argn("setpowerstate_log", &setPowerStateLogMS, sizeof(setPowerStateLogMS))) {
429*1031c584SApple OSS Distributions gIOPMSetPowerStateLogNS = setPowerStateLogMS * 1000000ULL;
430*1031c584SApple OSS Distributions }
431*1031c584SApple OSS Distributions #endif
432*1031c584SApple OSS Distributions }
433*1031c584SApple OSS Distributions
434*1031c584SApple OSS Distributions IOLockUnlock(gIOPMInitLock);
435*1031c584SApple OSS Distributions
436*1031c584SApple OSS Distributions if (!gIOPMInitialized) {
437*1031c584SApple OSS Distributions return;
438*1031c584SApple OSS Distributions }
439*1031c584SApple OSS Distributions
440*1031c584SApple OSS Distributions pwrMgt = new IOServicePM;
441*1031c584SApple OSS Distributions pwrMgt->init();
442*1031c584SApple OSS Distributions setProperty(kPwrMgtKey, pwrMgt);
443*1031c584SApple OSS Distributions
444*1031c584SApple OSS Distributions queue_init(&pwrMgt->WorkChain);
445*1031c584SApple OSS Distributions queue_init(&pwrMgt->RequestHead);
446*1031c584SApple OSS Distributions queue_init(&pwrMgt->PMDriverCallQueue);
447*1031c584SApple OSS Distributions
448*1031c584SApple OSS Distributions fOwner = this;
449*1031c584SApple OSS Distributions fPMLock = IOLockAlloc();
450*1031c584SApple OSS Distributions fInterestedDrivers = new IOPMinformeeList;
451*1031c584SApple OSS Distributions fInterestedDrivers->initialize();
452*1031c584SApple OSS Distributions fDesiredPowerState = kPowerStateZero;
453*1031c584SApple OSS Distributions fDeviceDesire = kPowerStateZero;
454*1031c584SApple OSS Distributions fInitialPowerChange = true;
455*1031c584SApple OSS Distributions fInitialSetPowerState = true;
456*1031c584SApple OSS Distributions fPreviousRequestPowerFlags = 0;
457*1031c584SApple OSS Distributions fDeviceOverrideEnabled = false;
458*1031c584SApple OSS Distributions fMachineState = kIOPM_Finished;
459*1031c584SApple OSS Distributions fSavedMachineState = kIOPM_BadMachineState;
460*1031c584SApple OSS Distributions fIdleTimerMinPowerState = kPowerStateZero;
461*1031c584SApple OSS Distributions fActivityLock = IOLockAlloc();
462*1031c584SApple OSS Distributions fStrictTreeOrder = false;
463*1031c584SApple OSS Distributions fActivityTicklePowerState = kInvalidTicklePowerState;
464*1031c584SApple OSS Distributions fAdvisoryTicklePowerState = kInvalidTicklePowerState;
465*1031c584SApple OSS Distributions fControllingDriver = NULL;
466*1031c584SApple OSS Distributions fPowerStates = NULL;
467*1031c584SApple OSS Distributions fNumberOfPowerStates = 0;
468*1031c584SApple OSS Distributions fCurrentPowerState = kPowerStateZero;
469*1031c584SApple OSS Distributions fParentsCurrentPowerFlags = 0;
470*1031c584SApple OSS Distributions fMaxPowerState = kPowerStateZero;
471*1031c584SApple OSS Distributions fName = getName();
472*1031c584SApple OSS Distributions fParentsKnowState = false;
473*1031c584SApple OSS Distributions fSerialNumber = 0;
474*1031c584SApple OSS Distributions fResponseArray = NULL;
475*1031c584SApple OSS Distributions fNotifyClientArray = NULL;
476*1031c584SApple OSS Distributions fCurrentPowerConsumption = kIOPMUnknown;
477*1031c584SApple OSS Distributions fOverrideMaxPowerState = kIOPMPowerStateMax;
478*1031c584SApple OSS Distributions
479*1031c584SApple OSS Distributions if (!gIOPMRootNode && (getParentEntry(gIOPowerPlane) == getRegistryRoot())) {
480*1031c584SApple OSS Distributions gIOPMRootNode = this;
481*1031c584SApple OSS Distributions fParentsKnowState = true;
482*1031c584SApple OSS Distributions } else if (getProperty(kIOPMResetPowerStateOnWakeKey) == kOSBooleanTrue) {
483*1031c584SApple OSS Distributions fResetPowerStateOnWake = true;
484*1031c584SApple OSS Distributions }
485*1031c584SApple OSS Distributions
486*1031c584SApple OSS Distributions if (IS_ROOT_DOMAIN) {
487*1031c584SApple OSS Distributions fWatchdogTimer = thread_call_allocate(
488*1031c584SApple OSS Distributions &IOService::watchdog_timer_expired, (thread_call_param_t)this);
489*1031c584SApple OSS Distributions fWatchdogLock = IOLockAlloc();
490*1031c584SApple OSS Distributions
491*1031c584SApple OSS Distributions fBlockedArray = OSArray::withCapacity(4);
492*1031c584SApple OSS Distributions }
493*1031c584SApple OSS Distributions
494*1031c584SApple OSS Distributions fAckTimer = thread_call_allocate(
495*1031c584SApple OSS Distributions &IOService::ack_timer_expired, (thread_call_param_t)this);
496*1031c584SApple OSS Distributions #if USE_SETTLE_TIMER
497*1031c584SApple OSS Distributions fSettleTimer = thread_call_allocate(
498*1031c584SApple OSS Distributions &settle_timer_expired, (thread_call_param_t)this);
499*1031c584SApple OSS Distributions #endif
500*1031c584SApple OSS Distributions fIdleTimer = thread_call_allocate(
501*1031c584SApple OSS Distributions &idle_timer_expired, (thread_call_param_t)this);
502*1031c584SApple OSS Distributions fDriverCallTimer = thread_call_allocate(
503*1031c584SApple OSS Distributions &IOService::pmDriverCalloutTimer, (thread_call_param_t)this);
504*1031c584SApple OSS Distributions fDriverCallEntry = thread_call_allocate(
505*1031c584SApple OSS Distributions (thread_call_func_t) &IOService::pmDriverCallout, this);
506*1031c584SApple OSS Distributions assert(fDriverCallEntry);
507*1031c584SApple OSS Distributions
508*1031c584SApple OSS Distributions // Check for powerChangeDone override.
509*1031c584SApple OSS Distributions if (OSMemberFunctionCast(void (*)(void),
510*1031c584SApple OSS Distributions getResourceService(), &IOService::powerChangeDone) !=
511*1031c584SApple OSS Distributions OSMemberFunctionCast(void (*)(void),
512*1031c584SApple OSS Distributions this, &IOService::powerChangeDone)) {
513*1031c584SApple OSS Distributions fPCDFunctionOverride = true;
514*1031c584SApple OSS Distributions }
515*1031c584SApple OSS Distributions
516*1031c584SApple OSS Distributions #if PM_VARS_SUPPORT
517*1031c584SApple OSS Distributions IOPMprot * prot = new IOPMprot;
518*1031c584SApple OSS Distributions if (prot) {
519*1031c584SApple OSS Distributions prot->init();
520*1031c584SApple OSS Distributions prot->ourName = fName;
521*1031c584SApple OSS Distributions prot->thePlatform = gPlatform;
522*1031c584SApple OSS Distributions fPMVars = prot;
523*1031c584SApple OSS Distributions pm_vars = prot;
524*1031c584SApple OSS Distributions }
525*1031c584SApple OSS Distributions #else
526*1031c584SApple OSS Distributions pm_vars = (void *) (uintptr_t) true;
527*1031c584SApple OSS Distributions #endif
528*1031c584SApple OSS Distributions
529*1031c584SApple OSS Distributions initialized = true;
530*1031c584SApple OSS Distributions }
531*1031c584SApple OSS Distributions }
532*1031c584SApple OSS Distributions
533*1031c584SApple OSS Distributions //*********************************************************************************
534*1031c584SApple OSS Distributions // [private] PMfree
535*1031c584SApple OSS Distributions //
536*1031c584SApple OSS Distributions // Free the data created by PMinit. Only called from IOService::free().
537*1031c584SApple OSS Distributions //*********************************************************************************
538*1031c584SApple OSS Distributions
539*1031c584SApple OSS Distributions void
PMfree(void)540*1031c584SApple OSS Distributions IOService::PMfree( void )
541*1031c584SApple OSS Distributions {
542*1031c584SApple OSS Distributions initialized = false;
543*1031c584SApple OSS Distributions pm_vars = NULL;
544*1031c584SApple OSS Distributions
545*1031c584SApple OSS Distributions if (pwrMgt) {
546*1031c584SApple OSS Distributions assert(fMachineState == kIOPM_Finished);
547*1031c584SApple OSS Distributions assert(fInsertInterestSet == NULL);
548*1031c584SApple OSS Distributions assert(fRemoveInterestSet == NULL);
549*1031c584SApple OSS Distributions assert(fNotifyChildArray == NULL);
550*1031c584SApple OSS Distributions assert(queue_empty(&pwrMgt->RequestHead));
551*1031c584SApple OSS Distributions assert(queue_empty(&fPMDriverCallQueue));
552*1031c584SApple OSS Distributions
553*1031c584SApple OSS Distributions if (fWatchdogTimer) {
554*1031c584SApple OSS Distributions thread_call_cancel(fWatchdogTimer);
555*1031c584SApple OSS Distributions thread_call_free(fWatchdogTimer);
556*1031c584SApple OSS Distributions fWatchdogTimer = NULL;
557*1031c584SApple OSS Distributions }
558*1031c584SApple OSS Distributions
559*1031c584SApple OSS Distributions if (fWatchdogLock) {
560*1031c584SApple OSS Distributions IOLockFree(fWatchdogLock);
561*1031c584SApple OSS Distributions fWatchdogLock = NULL;
562*1031c584SApple OSS Distributions }
563*1031c584SApple OSS Distributions
564*1031c584SApple OSS Distributions if (fBlockedArray) {
565*1031c584SApple OSS Distributions fBlockedArray->release();
566*1031c584SApple OSS Distributions fBlockedArray = NULL;
567*1031c584SApple OSS Distributions }
568*1031c584SApple OSS Distributions #if USE_SETTLE_TIMER
569*1031c584SApple OSS Distributions if (fSettleTimer) {
570*1031c584SApple OSS Distributions thread_call_cancel(fSettleTimer);
571*1031c584SApple OSS Distributions thread_call_free(fSettleTimer);
572*1031c584SApple OSS Distributions fSettleTimer = NULL;
573*1031c584SApple OSS Distributions }
574*1031c584SApple OSS Distributions #endif
575*1031c584SApple OSS Distributions if (fAckTimer) {
576*1031c584SApple OSS Distributions thread_call_cancel(fAckTimer);
577*1031c584SApple OSS Distributions thread_call_free(fAckTimer);
578*1031c584SApple OSS Distributions fAckTimer = NULL;
579*1031c584SApple OSS Distributions }
580*1031c584SApple OSS Distributions if (fIdleTimer) {
581*1031c584SApple OSS Distributions thread_call_cancel(fIdleTimer);
582*1031c584SApple OSS Distributions thread_call_free(fIdleTimer);
583*1031c584SApple OSS Distributions fIdleTimer = NULL;
584*1031c584SApple OSS Distributions }
585*1031c584SApple OSS Distributions if (fDriverCallEntry) {
586*1031c584SApple OSS Distributions thread_call_free(fDriverCallEntry);
587*1031c584SApple OSS Distributions fDriverCallEntry = NULL;
588*1031c584SApple OSS Distributions }
589*1031c584SApple OSS Distributions if (fDriverCallTimer) {
590*1031c584SApple OSS Distributions thread_call_free(fDriverCallTimer);
591*1031c584SApple OSS Distributions fDriverCallTimer = NULL;
592*1031c584SApple OSS Distributions }
593*1031c584SApple OSS Distributions if (fPMLock) {
594*1031c584SApple OSS Distributions IOLockFree(fPMLock);
595*1031c584SApple OSS Distributions fPMLock = NULL;
596*1031c584SApple OSS Distributions }
597*1031c584SApple OSS Distributions if (fActivityLock) {
598*1031c584SApple OSS Distributions IOLockFree(fActivityLock);
599*1031c584SApple OSS Distributions fActivityLock = NULL;
600*1031c584SApple OSS Distributions }
601*1031c584SApple OSS Distributions if (fInterestedDrivers) {
602*1031c584SApple OSS Distributions fInterestedDrivers->release();
603*1031c584SApple OSS Distributions fInterestedDrivers = NULL;
604*1031c584SApple OSS Distributions }
605*1031c584SApple OSS Distributions if (fDriverCallParamSlots && fDriverCallParamPtr) {
606*1031c584SApple OSS Distributions IODelete(fDriverCallParamPtr, DriverCallParam, fDriverCallParamSlots);
607*1031c584SApple OSS Distributions fDriverCallParamPtr = NULL;
608*1031c584SApple OSS Distributions fDriverCallParamSlots = 0;
609*1031c584SApple OSS Distributions }
610*1031c584SApple OSS Distributions if (fResponseArray) {
611*1031c584SApple OSS Distributions fResponseArray->release();
612*1031c584SApple OSS Distributions fResponseArray = NULL;
613*1031c584SApple OSS Distributions }
614*1031c584SApple OSS Distributions if (fNotifyClientArray) {
615*1031c584SApple OSS Distributions fNotifyClientArray->release();
616*1031c584SApple OSS Distributions fNotifyClientArray = NULL;
617*1031c584SApple OSS Distributions }
618*1031c584SApple OSS Distributions if (fReportBuf && fNumberOfPowerStates) {
619*1031c584SApple OSS Distributions IOFreeData(fReportBuf, STATEREPORT_BUFSIZE(fNumberOfPowerStates));
620*1031c584SApple OSS Distributions fReportBuf = NULL;
621*1031c584SApple OSS Distributions }
622*1031c584SApple OSS Distributions if (fPowerStates && fNumberOfPowerStates) {
623*1031c584SApple OSS Distributions IODeleteData(fPowerStates, IOPMPSEntry, fNumberOfPowerStates);
624*1031c584SApple OSS Distributions fNumberOfPowerStates = 0;
625*1031c584SApple OSS Distributions fPowerStates = NULL;
626*1031c584SApple OSS Distributions }
627*1031c584SApple OSS Distributions if (fPowerClients) {
628*1031c584SApple OSS Distributions fPowerClients->release();
629*1031c584SApple OSS Distributions fPowerClients = NULL;
630*1031c584SApple OSS Distributions }
631*1031c584SApple OSS Distributions
632*1031c584SApple OSS Distributions #if PM_VARS_SUPPORT
633*1031c584SApple OSS Distributions if (fPMVars) {
634*1031c584SApple OSS Distributions fPMVars->release();
635*1031c584SApple OSS Distributions fPMVars = NULL;
636*1031c584SApple OSS Distributions }
637*1031c584SApple OSS Distributions #endif
638*1031c584SApple OSS Distributions
639*1031c584SApple OSS Distributions pwrMgt->release();
640*1031c584SApple OSS Distributions pwrMgt = NULL;
641*1031c584SApple OSS Distributions }
642*1031c584SApple OSS Distributions }
643*1031c584SApple OSS Distributions
644*1031c584SApple OSS Distributions void
PMDebug(uint32_t event,uintptr_t param1,uintptr_t param2)645*1031c584SApple OSS Distributions IOService::PMDebug( uint32_t event, uintptr_t param1, uintptr_t param2 )
646*1031c584SApple OSS Distributions {
647*1031c584SApple OSS Distributions OUR_PMLog(event, param1, param2);
648*1031c584SApple OSS Distributions }
649*1031c584SApple OSS Distributions
650*1031c584SApple OSS Distributions //*********************************************************************************
651*1031c584SApple OSS Distributions // [public] joinPMtree
652*1031c584SApple OSS Distributions //
653*1031c584SApple OSS Distributions // A policy-maker calls its nub here when initializing, to be attached into
654*1031c584SApple OSS Distributions // the power management hierarchy. The default function is to call the
655*1031c584SApple OSS Distributions // platform expert, which knows how to do it. This method is overridden
656*1031c584SApple OSS Distributions // by a nub subclass which may either know how to do it, or may need to
657*1031c584SApple OSS Distributions // take other action.
658*1031c584SApple OSS Distributions //
659*1031c584SApple OSS Distributions // This may be the only "power management" method used in a nub,
660*1031c584SApple OSS Distributions // meaning it may not be initialized for power management.
661*1031c584SApple OSS Distributions //*********************************************************************************
662*1031c584SApple OSS Distributions
663*1031c584SApple OSS Distributions void
joinPMtree(IOService * driver)664*1031c584SApple OSS Distributions IOService::joinPMtree( IOService * driver )
665*1031c584SApple OSS Distributions {
666*1031c584SApple OSS Distributions IOPlatformExpert * platform;
667*1031c584SApple OSS Distributions
668*1031c584SApple OSS Distributions platform = getPlatform();
669*1031c584SApple OSS Distributions assert(platform != NULL);
670*1031c584SApple OSS Distributions platform->PMRegisterDevice(this, driver);
671*1031c584SApple OSS Distributions }
672*1031c584SApple OSS Distributions
673*1031c584SApple OSS Distributions #ifndef __LP64__
674*1031c584SApple OSS Distributions //*********************************************************************************
675*1031c584SApple OSS Distributions // [deprecated] youAreRoot
676*1031c584SApple OSS Distributions //
677*1031c584SApple OSS Distributions // Power Managment is informing us that we are the root power domain.
678*1031c584SApple OSS Distributions //*********************************************************************************
679*1031c584SApple OSS Distributions
680*1031c584SApple OSS Distributions IOReturn
youAreRoot(void)681*1031c584SApple OSS Distributions IOService::youAreRoot( void )
682*1031c584SApple OSS Distributions {
683*1031c584SApple OSS Distributions return IOPMNoErr;
684*1031c584SApple OSS Distributions }
685*1031c584SApple OSS Distributions #endif /* !__LP64__ */
686*1031c584SApple OSS Distributions
687*1031c584SApple OSS Distributions //*********************************************************************************
688*1031c584SApple OSS Distributions // [public] PMstop
689*1031c584SApple OSS Distributions //
690*1031c584SApple OSS Distributions // Immediately stop driver callouts. Schedule an async stop request to detach
691*1031c584SApple OSS Distributions // from power plane.
692*1031c584SApple OSS Distributions //*********************************************************************************
693*1031c584SApple OSS Distributions
694*1031c584SApple OSS Distributions void
PMstop(void)695*1031c584SApple OSS Distributions IOService::PMstop( void )
696*1031c584SApple OSS Distributions {
697*1031c584SApple OSS Distributions IOPMRequest * request;
698*1031c584SApple OSS Distributions
699*1031c584SApple OSS Distributions if (!initialized) {
700*1031c584SApple OSS Distributions return;
701*1031c584SApple OSS Distributions }
702*1031c584SApple OSS Distributions
703*1031c584SApple OSS Distributions PM_LOCK();
704*1031c584SApple OSS Distributions
705*1031c584SApple OSS Distributions if (fLockedFlags.PMStop) {
706*1031c584SApple OSS Distributions PM_LOG2("%s: PMstop() already stopped\n", fName);
707*1031c584SApple OSS Distributions PM_UNLOCK();
708*1031c584SApple OSS Distributions return;
709*1031c584SApple OSS Distributions }
710*1031c584SApple OSS Distributions
711*1031c584SApple OSS Distributions // Inhibit future driver calls.
712*1031c584SApple OSS Distributions fLockedFlags.PMStop = true;
713*1031c584SApple OSS Distributions
714*1031c584SApple OSS Distributions // Wait for all prior driver calls to finish.
715*1031c584SApple OSS Distributions waitForPMDriverCall();
716*1031c584SApple OSS Distributions
717*1031c584SApple OSS Distributions PM_UNLOCK();
718*1031c584SApple OSS Distributions
719*1031c584SApple OSS Distributions // The rest of the work is performed async.
720*1031c584SApple OSS Distributions request = acquirePMRequest( this, kIOPMRequestTypePMStop );
721*1031c584SApple OSS Distributions if (request) {
722*1031c584SApple OSS Distributions PM_LOG2("%s: %p PMstop\n", getName(), OBFUSCATE(this));
723*1031c584SApple OSS Distributions submitPMRequest( request );
724*1031c584SApple OSS Distributions }
725*1031c584SApple OSS Distributions }
726*1031c584SApple OSS Distributions
727*1031c584SApple OSS Distributions //*********************************************************************************
728*1031c584SApple OSS Distributions // [private] handlePMstop
729*1031c584SApple OSS Distributions //
730*1031c584SApple OSS Distributions // Disconnect the node from all parents and children in the power plane.
731*1031c584SApple OSS Distributions //*********************************************************************************
732*1031c584SApple OSS Distributions
733*1031c584SApple OSS Distributions void
handlePMstop(IOPMRequest * request)734*1031c584SApple OSS Distributions IOService::handlePMstop( IOPMRequest * request )
735*1031c584SApple OSS Distributions {
736*1031c584SApple OSS Distributions OSIterator * iter;
737*1031c584SApple OSS Distributions OSObject * next;
738*1031c584SApple OSS Distributions IOPowerConnection * connection;
739*1031c584SApple OSS Distributions IOService * theChild;
740*1031c584SApple OSS Distributions IOService * theParent;
741*1031c584SApple OSS Distributions
742*1031c584SApple OSS Distributions PM_ASSERT_IN_GATE();
743*1031c584SApple OSS Distributions PM_LOG2("%s: %p %s start\n", getName(), OBFUSCATE(this), __FUNCTION__);
744*1031c584SApple OSS Distributions
745*1031c584SApple OSS Distributions // remove driver from prevent system sleep lists
746*1031c584SApple OSS Distributions getPMRootDomain()->updatePreventIdleSleepList(this, false);
747*1031c584SApple OSS Distributions getPMRootDomain()->updatePreventSystemSleepList(this, false);
748*1031c584SApple OSS Distributions
749*1031c584SApple OSS Distributions // remove the property
750*1031c584SApple OSS Distributions removeProperty(kPwrMgtKey);
751*1031c584SApple OSS Distributions
752*1031c584SApple OSS Distributions // detach parents
753*1031c584SApple OSS Distributions iter = getParentIterator(gIOPowerPlane);
754*1031c584SApple OSS Distributions if (iter) {
755*1031c584SApple OSS Distributions while ((next = iter->getNextObject())) {
756*1031c584SApple OSS Distributions if ((connection = OSDynamicCast(IOPowerConnection, next))) {
757*1031c584SApple OSS Distributions theParent = (IOService *)connection->copyParentEntry(gIOPowerPlane);
758*1031c584SApple OSS Distributions if (theParent) {
759*1031c584SApple OSS Distributions theParent->removePowerChild(connection);
760*1031c584SApple OSS Distributions theParent->release();
761*1031c584SApple OSS Distributions }
762*1031c584SApple OSS Distributions }
763*1031c584SApple OSS Distributions }
764*1031c584SApple OSS Distributions iter->release();
765*1031c584SApple OSS Distributions }
766*1031c584SApple OSS Distributions
767*1031c584SApple OSS Distributions // detach IOConnections
768*1031c584SApple OSS Distributions detachAbove( gIOPowerPlane );
769*1031c584SApple OSS Distributions
770*1031c584SApple OSS Distributions // no more power state changes
771*1031c584SApple OSS Distributions fParentsKnowState = false;
772*1031c584SApple OSS Distributions
773*1031c584SApple OSS Distributions // detach children
774*1031c584SApple OSS Distributions iter = getChildIterator(gIOPowerPlane);
775*1031c584SApple OSS Distributions if (iter) {
776*1031c584SApple OSS Distributions while ((next = iter->getNextObject())) {
777*1031c584SApple OSS Distributions if ((connection = OSDynamicCast(IOPowerConnection, next))) {
778*1031c584SApple OSS Distributions theChild = ((IOService *)(connection->copyChildEntry(gIOPowerPlane)));
779*1031c584SApple OSS Distributions if (theChild) {
780*1031c584SApple OSS Distributions // detach nub from child
781*1031c584SApple OSS Distributions connection->detachFromChild(theChild, gIOPowerPlane);
782*1031c584SApple OSS Distributions theChild->release();
783*1031c584SApple OSS Distributions }
784*1031c584SApple OSS Distributions // detach us from nub
785*1031c584SApple OSS Distributions detachFromChild(connection, gIOPowerPlane);
786*1031c584SApple OSS Distributions }
787*1031c584SApple OSS Distributions }
788*1031c584SApple OSS Distributions iter->release();
789*1031c584SApple OSS Distributions }
790*1031c584SApple OSS Distributions
791*1031c584SApple OSS Distributions // Remove all interested drivers from the list, including the power
792*1031c584SApple OSS Distributions // controlling driver.
793*1031c584SApple OSS Distributions //
794*1031c584SApple OSS Distributions // Usually, the controlling driver and the policy-maker functionality
795*1031c584SApple OSS Distributions // are implemented by the same object, and without the deregistration,
796*1031c584SApple OSS Distributions // the object will be holding an extra retain on itself, and cannot
797*1031c584SApple OSS Distributions // be freed.
798*1031c584SApple OSS Distributions
799*1031c584SApple OSS Distributions if (fInterestedDrivers) {
800*1031c584SApple OSS Distributions IOPMinformeeList * list = fInterestedDrivers;
801*1031c584SApple OSS Distributions IOPMinformee * item;
802*1031c584SApple OSS Distributions
803*1031c584SApple OSS Distributions PM_LOCK();
804*1031c584SApple OSS Distributions while ((item = list->firstInList())) {
805*1031c584SApple OSS Distributions list->removeFromList(item->whatObject);
806*1031c584SApple OSS Distributions }
807*1031c584SApple OSS Distributions PM_UNLOCK();
808*1031c584SApple OSS Distributions }
809*1031c584SApple OSS Distributions
810*1031c584SApple OSS Distributions // Clear idle period to prevent idleTimerExpired() from servicing
811*1031c584SApple OSS Distributions // idle timer expirations.
812*1031c584SApple OSS Distributions
813*1031c584SApple OSS Distributions fIdleTimerPeriod = 0;
814*1031c584SApple OSS Distributions if (fIdleTimer && thread_call_cancel(fIdleTimer)) {
815*1031c584SApple OSS Distributions release();
816*1031c584SApple OSS Distributions }
817*1031c584SApple OSS Distributions
818*1031c584SApple OSS Distributions PM_LOG2("%s: %p %s done\n", getName(), OBFUSCATE(this), __FUNCTION__);
819*1031c584SApple OSS Distributions }
820*1031c584SApple OSS Distributions
821*1031c584SApple OSS Distributions //*********************************************************************************
822*1031c584SApple OSS Distributions // [public] addPowerChild
823*1031c584SApple OSS Distributions //
824*1031c584SApple OSS Distributions // Power Management is informing us who our children are.
825*1031c584SApple OSS Distributions //*********************************************************************************
826*1031c584SApple OSS Distributions
827*1031c584SApple OSS Distributions IOReturn
addPowerChild(IOService * child)828*1031c584SApple OSS Distributions IOService::addPowerChild( IOService * child )
829*1031c584SApple OSS Distributions {
830*1031c584SApple OSS Distributions IOPowerConnection * connection = NULL;
831*1031c584SApple OSS Distributions IOPMRequest * requests[3] = {NULL, NULL, NULL};
832*1031c584SApple OSS Distributions OSIterator * iter;
833*1031c584SApple OSS Distributions bool ok = true;
834*1031c584SApple OSS Distributions
835*1031c584SApple OSS Distributions if (!child) {
836*1031c584SApple OSS Distributions return kIOReturnBadArgument;
837*1031c584SApple OSS Distributions }
838*1031c584SApple OSS Distributions
839*1031c584SApple OSS Distributions if (!initialized || !child->initialized) {
840*1031c584SApple OSS Distributions return IOPMNotYetInitialized;
841*1031c584SApple OSS Distributions }
842*1031c584SApple OSS Distributions
843*1031c584SApple OSS Distributions OUR_PMLog( kPMLogAddChild, (uintptr_t) child, 0 );
844*1031c584SApple OSS Distributions
845*1031c584SApple OSS Distributions do {
846*1031c584SApple OSS Distributions // Is this child already one of our children?
847*1031c584SApple OSS Distributions
848*1031c584SApple OSS Distributions iter = child->getParentIterator( gIOPowerPlane );
849*1031c584SApple OSS Distributions if (iter) {
850*1031c584SApple OSS Distributions IORegistryEntry * entry;
851*1031c584SApple OSS Distributions OSObject * next;
852*1031c584SApple OSS Distributions
853*1031c584SApple OSS Distributions while ((next = iter->getNextObject())) {
854*1031c584SApple OSS Distributions if ((entry = OSDynamicCast(IORegistryEntry, next)) &&
855*1031c584SApple OSS Distributions isChild(entry, gIOPowerPlane)) {
856*1031c584SApple OSS Distributions ok = false;
857*1031c584SApple OSS Distributions break;
858*1031c584SApple OSS Distributions }
859*1031c584SApple OSS Distributions }
860*1031c584SApple OSS Distributions iter->release();
861*1031c584SApple OSS Distributions }
862*1031c584SApple OSS Distributions if (!ok) {
863*1031c584SApple OSS Distributions PM_LOG2("%s: %s (%p) is already a child\n",
864*1031c584SApple OSS Distributions getName(), child->getName(), OBFUSCATE(child));
865*1031c584SApple OSS Distributions break;
866*1031c584SApple OSS Distributions }
867*1031c584SApple OSS Distributions
868*1031c584SApple OSS Distributions // Add the child to the power plane immediately, but the
869*1031c584SApple OSS Distributions // joining connection is marked as not ready.
870*1031c584SApple OSS Distributions // We want the child to appear in the power plane before
871*1031c584SApple OSS Distributions // returning to the caller, but don't want the caller to
872*1031c584SApple OSS Distributions // block on the PM work loop.
873*1031c584SApple OSS Distributions
874*1031c584SApple OSS Distributions connection = new IOPowerConnection;
875*1031c584SApple OSS Distributions if (!connection) {
876*1031c584SApple OSS Distributions break;
877*1031c584SApple OSS Distributions }
878*1031c584SApple OSS Distributions
879*1031c584SApple OSS Distributions // Create a chain of PM requests to perform the bottom-half
880*1031c584SApple OSS Distributions // work from the PM work loop.
881*1031c584SApple OSS Distributions
882*1031c584SApple OSS Distributions requests[0] = acquirePMRequest(
883*1031c584SApple OSS Distributions /* target */ this,
884*1031c584SApple OSS Distributions /* type */ kIOPMRequestTypeAddPowerChild1 );
885*1031c584SApple OSS Distributions
886*1031c584SApple OSS Distributions requests[1] = acquirePMRequest(
887*1031c584SApple OSS Distributions /* target */ child,
888*1031c584SApple OSS Distributions /* type */ kIOPMRequestTypeAddPowerChild2 );
889*1031c584SApple OSS Distributions
890*1031c584SApple OSS Distributions requests[2] = acquirePMRequest(
891*1031c584SApple OSS Distributions /* target */ this,
892*1031c584SApple OSS Distributions /* type */ kIOPMRequestTypeAddPowerChild3 );
893*1031c584SApple OSS Distributions
894*1031c584SApple OSS Distributions if (!requests[0] || !requests[1] || !requests[2]) {
895*1031c584SApple OSS Distributions break;
896*1031c584SApple OSS Distributions }
897*1031c584SApple OSS Distributions
898*1031c584SApple OSS Distributions requests[0]->attachNextRequest( requests[1] );
899*1031c584SApple OSS Distributions requests[1]->attachNextRequest( requests[2] );
900*1031c584SApple OSS Distributions
901*1031c584SApple OSS Distributions connection->init();
902*1031c584SApple OSS Distributions connection->start(this);
903*1031c584SApple OSS Distributions connection->setAwaitingAck(false);
904*1031c584SApple OSS Distributions connection->setReadyFlag(false);
905*1031c584SApple OSS Distributions
906*1031c584SApple OSS Distributions attachToChild( connection, gIOPowerPlane );
907*1031c584SApple OSS Distributions connection->attachToChild( child, gIOPowerPlane );
908*1031c584SApple OSS Distributions
909*1031c584SApple OSS Distributions // connection needs to be released
910*1031c584SApple OSS Distributions requests[0]->fArg0 = connection;
911*1031c584SApple OSS Distributions requests[1]->fArg0 = connection;
912*1031c584SApple OSS Distributions requests[2]->fArg0 = connection;
913*1031c584SApple OSS Distributions
914*1031c584SApple OSS Distributions submitPMRequests( requests, 3 );
915*1031c584SApple OSS Distributions return kIOReturnSuccess;
916*1031c584SApple OSS Distributions }while (false);
917*1031c584SApple OSS Distributions
918*1031c584SApple OSS Distributions if (connection) {
919*1031c584SApple OSS Distributions connection->release();
920*1031c584SApple OSS Distributions }
921*1031c584SApple OSS Distributions if (requests[0]) {
922*1031c584SApple OSS Distributions releasePMRequest(requests[0]);
923*1031c584SApple OSS Distributions }
924*1031c584SApple OSS Distributions if (requests[1]) {
925*1031c584SApple OSS Distributions releasePMRequest(requests[1]);
926*1031c584SApple OSS Distributions }
927*1031c584SApple OSS Distributions if (requests[2]) {
928*1031c584SApple OSS Distributions releasePMRequest(requests[2]);
929*1031c584SApple OSS Distributions }
930*1031c584SApple OSS Distributions
931*1031c584SApple OSS Distributions // Silent failure, to prevent platform drivers from adding the child
932*1031c584SApple OSS Distributions // to the root domain.
933*1031c584SApple OSS Distributions
934*1031c584SApple OSS Distributions return kIOReturnSuccess;
935*1031c584SApple OSS Distributions }
936*1031c584SApple OSS Distributions
937*1031c584SApple OSS Distributions //*********************************************************************************
938*1031c584SApple OSS Distributions // [private] addPowerChild1
939*1031c584SApple OSS Distributions //
940*1031c584SApple OSS Distributions // Step 1/3 of adding a power child. Called on the power parent.
941*1031c584SApple OSS Distributions //*********************************************************************************
942*1031c584SApple OSS Distributions
943*1031c584SApple OSS Distributions void
addPowerChild1(IOPMRequest * request)944*1031c584SApple OSS Distributions IOService::addPowerChild1( IOPMRequest * request )
945*1031c584SApple OSS Distributions {
946*1031c584SApple OSS Distributions IOPMPowerStateIndex tempDesire = kPowerStateZero;
947*1031c584SApple OSS Distributions
948*1031c584SApple OSS Distributions // Make us temporary usable before adding the child.
949*1031c584SApple OSS Distributions
950*1031c584SApple OSS Distributions PM_ASSERT_IN_GATE();
951*1031c584SApple OSS Distributions OUR_PMLog( kPMLogMakeUsable, kPMLogMakeUsable, 0 );
952*1031c584SApple OSS Distributions
953*1031c584SApple OSS Distributions if (fControllingDriver && inPlane(gIOPowerPlane) && fParentsKnowState) {
954*1031c584SApple OSS Distributions tempDesire = fHighestPowerState;
955*1031c584SApple OSS Distributions }
956*1031c584SApple OSS Distributions
957*1031c584SApple OSS Distributions if ((tempDesire != kPowerStateZero) &&
958*1031c584SApple OSS Distributions (IS_PM_ROOT || (StateOrder(fMaxPowerState) >= StateOrder(tempDesire)))) {
959*1031c584SApple OSS Distributions adjustPowerState(tempDesire);
960*1031c584SApple OSS Distributions }
961*1031c584SApple OSS Distributions }
962*1031c584SApple OSS Distributions
963*1031c584SApple OSS Distributions //*********************************************************************************
964*1031c584SApple OSS Distributions // [private] addPowerChild2
965*1031c584SApple OSS Distributions //
966*1031c584SApple OSS Distributions // Step 2/3 of adding a power child. Called on the joining child.
967*1031c584SApple OSS Distributions // Execution blocked behind addPowerChild1.
968*1031c584SApple OSS Distributions //*********************************************************************************
969*1031c584SApple OSS Distributions
970*1031c584SApple OSS Distributions void
addPowerChild2(IOPMRequest * request)971*1031c584SApple OSS Distributions IOService::addPowerChild2( IOPMRequest * request )
972*1031c584SApple OSS Distributions {
973*1031c584SApple OSS Distributions IOPowerConnection * connection = (IOPowerConnection *) request->fArg0;
974*1031c584SApple OSS Distributions IOService * parent;
975*1031c584SApple OSS Distributions IOPMPowerFlags powerFlags;
976*1031c584SApple OSS Distributions bool knowsState;
977*1031c584SApple OSS Distributions IOPMPowerStateIndex powerState;
978*1031c584SApple OSS Distributions IOPMPowerStateIndex tempDesire;
979*1031c584SApple OSS Distributions
980*1031c584SApple OSS Distributions PM_ASSERT_IN_GATE();
981*1031c584SApple OSS Distributions parent = (IOService *) connection->getParentEntry(gIOPowerPlane);
982*1031c584SApple OSS Distributions
983*1031c584SApple OSS Distributions if (!parent || !inPlane(gIOPowerPlane)) {
984*1031c584SApple OSS Distributions PM_LOG("%s: addPowerChild2 not in power plane\n", getName());
985*1031c584SApple OSS Distributions return;
986*1031c584SApple OSS Distributions }
987*1031c584SApple OSS Distributions
988*1031c584SApple OSS Distributions // Parent will be waiting for us to complete this stage.
989*1031c584SApple OSS Distributions // It is safe to directly access parent's vars.
990*1031c584SApple OSS Distributions
991*1031c584SApple OSS Distributions knowsState = (parent->fPowerStates) && (parent->fParentsKnowState);
992*1031c584SApple OSS Distributions powerState = parent->fCurrentPowerState;
993*1031c584SApple OSS Distributions
994*1031c584SApple OSS Distributions if (knowsState) {
995*1031c584SApple OSS Distributions powerFlags = parent->fPowerStates[powerState].outputPowerFlags;
996*1031c584SApple OSS Distributions } else {
997*1031c584SApple OSS Distributions powerFlags = 0;
998*1031c584SApple OSS Distributions }
999*1031c584SApple OSS Distributions
1000*1031c584SApple OSS Distributions // Set our power parent.
1001*1031c584SApple OSS Distributions
1002*1031c584SApple OSS Distributions OUR_PMLog(kPMLogSetParent, knowsState, powerFlags);
1003*1031c584SApple OSS Distributions
1004*1031c584SApple OSS Distributions setParentInfo( powerFlags, connection, knowsState );
1005*1031c584SApple OSS Distributions
1006*1031c584SApple OSS Distributions connection->setReadyFlag(true);
1007*1031c584SApple OSS Distributions
1008*1031c584SApple OSS Distributions if (fControllingDriver && fParentsKnowState) {
1009*1031c584SApple OSS Distributions fMaxPowerState = fControllingDriver->maxCapabilityForDomainState(fParentsCurrentPowerFlags);
1010*1031c584SApple OSS Distributions // initially change into the state we are already in
1011*1031c584SApple OSS Distributions tempDesire = fControllingDriver->initialPowerStateForDomainState(fParentsCurrentPowerFlags);
1012*1031c584SApple OSS Distributions fPreviousRequestPowerFlags = (IOPMPowerFlags)(-1);
1013*1031c584SApple OSS Distributions adjustPowerState(tempDesire);
1014*1031c584SApple OSS Distributions }
1015*1031c584SApple OSS Distributions }
1016*1031c584SApple OSS Distributions
1017*1031c584SApple OSS Distributions //*********************************************************************************
1018*1031c584SApple OSS Distributions // [private] addPowerChild3
1019*1031c584SApple OSS Distributions //
1020*1031c584SApple OSS Distributions // Step 3/3 of adding a power child. Called on the parent.
1021*1031c584SApple OSS Distributions // Execution blocked behind addPowerChild2.
1022*1031c584SApple OSS Distributions //*********************************************************************************
1023*1031c584SApple OSS Distributions
1024*1031c584SApple OSS Distributions void
addPowerChild3(IOPMRequest * request)1025*1031c584SApple OSS Distributions IOService::addPowerChild3( IOPMRequest * request )
1026*1031c584SApple OSS Distributions {
1027*1031c584SApple OSS Distributions IOPowerConnection * connection = (IOPowerConnection *) request->fArg0;
1028*1031c584SApple OSS Distributions IOService * child;
1029*1031c584SApple OSS Distributions IOPMrootDomain * rootDomain = getPMRootDomain();
1030*1031c584SApple OSS Distributions
1031*1031c584SApple OSS Distributions PM_ASSERT_IN_GATE();
1032*1031c584SApple OSS Distributions child = (IOService *) connection->getChildEntry(gIOPowerPlane);
1033*1031c584SApple OSS Distributions
1034*1031c584SApple OSS Distributions if (child && inPlane(gIOPowerPlane)) {
1035*1031c584SApple OSS Distributions if ((this != rootDomain) && child->getProperty("IOPMStrictTreeOrder")) {
1036*1031c584SApple OSS Distributions PM_LOG1("%s: strict PM order enforced\n", getName());
1037*1031c584SApple OSS Distributions fStrictTreeOrder = true;
1038*1031c584SApple OSS Distributions }
1039*1031c584SApple OSS Distributions
1040*1031c584SApple OSS Distributions if (rootDomain) {
1041*1031c584SApple OSS Distributions rootDomain->joinAggressiveness( child );
1042*1031c584SApple OSS Distributions }
1043*1031c584SApple OSS Distributions } else {
1044*1031c584SApple OSS Distributions PM_LOG("%s: addPowerChild3 not in power plane\n", getName());
1045*1031c584SApple OSS Distributions }
1046*1031c584SApple OSS Distributions
1047*1031c584SApple OSS Distributions connection->release();
1048*1031c584SApple OSS Distributions }
1049*1031c584SApple OSS Distributions
1050*1031c584SApple OSS Distributions #ifndef __LP64__
1051*1031c584SApple OSS Distributions //*********************************************************************************
1052*1031c584SApple OSS Distributions // [deprecated] setPowerParent
1053*1031c584SApple OSS Distributions //
1054*1031c584SApple OSS Distributions // Power Management is informing us who our parent is.
1055*1031c584SApple OSS Distributions // If we have a controlling driver, find out, given our newly-informed
1056*1031c584SApple OSS Distributions // power domain state, what state it would be in, and then tell it
1057*1031c584SApple OSS Distributions // to assume that state.
1058*1031c584SApple OSS Distributions //*********************************************************************************
1059*1031c584SApple OSS Distributions
1060*1031c584SApple OSS Distributions IOReturn
setPowerParent(IOPowerConnection * theParent,bool stateKnown,IOPMPowerFlags powerFlags)1061*1031c584SApple OSS Distributions IOService::setPowerParent(
1062*1031c584SApple OSS Distributions IOPowerConnection * theParent, bool stateKnown, IOPMPowerFlags powerFlags )
1063*1031c584SApple OSS Distributions {
1064*1031c584SApple OSS Distributions return kIOReturnUnsupported;
1065*1031c584SApple OSS Distributions }
1066*1031c584SApple OSS Distributions #endif /* !__LP64__ */
1067*1031c584SApple OSS Distributions
1068*1031c584SApple OSS Distributions //*********************************************************************************
1069*1031c584SApple OSS Distributions // [public] removePowerChild
1070*1031c584SApple OSS Distributions //
1071*1031c584SApple OSS Distributions // Called on a parent whose child is being removed by PMstop().
1072*1031c584SApple OSS Distributions //*********************************************************************************
1073*1031c584SApple OSS Distributions
1074*1031c584SApple OSS Distributions IOReturn
removePowerChild(IOPowerConnection * theNub)1075*1031c584SApple OSS Distributions IOService::removePowerChild( IOPowerConnection * theNub )
1076*1031c584SApple OSS Distributions {
1077*1031c584SApple OSS Distributions IORegistryEntry * theChild;
1078*1031c584SApple OSS Distributions
1079*1031c584SApple OSS Distributions PM_ASSERT_IN_GATE();
1080*1031c584SApple OSS Distributions OUR_PMLog( kPMLogRemoveChild, 0, 0 );
1081*1031c584SApple OSS Distributions
1082*1031c584SApple OSS Distributions theNub->retain();
1083*1031c584SApple OSS Distributions
1084*1031c584SApple OSS Distributions // detach nub from child
1085*1031c584SApple OSS Distributions theChild = theNub->copyChildEntry(gIOPowerPlane);
1086*1031c584SApple OSS Distributions if (theChild) {
1087*1031c584SApple OSS Distributions theNub->detachFromChild(theChild, gIOPowerPlane);
1088*1031c584SApple OSS Distributions theChild->release();
1089*1031c584SApple OSS Distributions }
1090*1031c584SApple OSS Distributions // detach from the nub
1091*1031c584SApple OSS Distributions detachFromChild(theNub, gIOPowerPlane);
1092*1031c584SApple OSS Distributions
1093*1031c584SApple OSS Distributions // Are we awaiting an ack from this child?
1094*1031c584SApple OSS Distributions if (theNub->getAwaitingAck()) {
1095*1031c584SApple OSS Distributions // yes, pretend we got one
1096*1031c584SApple OSS Distributions theNub->setAwaitingAck(false);
1097*1031c584SApple OSS Distributions if (fHeadNotePendingAcks != 0) {
1098*1031c584SApple OSS Distributions // that's one fewer ack to worry about
1099*1031c584SApple OSS Distributions fHeadNotePendingAcks--;
1100*1031c584SApple OSS Distributions
1101*1031c584SApple OSS Distributions // is that the last?
1102*1031c584SApple OSS Distributions if (fHeadNotePendingAcks == 0) {
1103*1031c584SApple OSS Distributions stop_ack_timer();
1104*1031c584SApple OSS Distributions getPMRootDomain()->reset_watchdog_timer(this, 0);
1105*1031c584SApple OSS Distributions
1106*1031c584SApple OSS Distributions // This parent may have a request in the work queue that is
1107*1031c584SApple OSS Distributions // blocked on fHeadNotePendingAcks=0. And removePowerChild()
1108*1031c584SApple OSS Distributions // is called while executing the child's PMstop request so they
1109*1031c584SApple OSS Distributions // can occur simultaneously. IOPMWorkQueue::checkForWork() must
1110*1031c584SApple OSS Distributions // restart and check all request queues again.
1111*1031c584SApple OSS Distributions
1112*1031c584SApple OSS Distributions gIOPMWorkQueue->incrementProducerCount();
1113*1031c584SApple OSS Distributions }
1114*1031c584SApple OSS Distributions }
1115*1031c584SApple OSS Distributions }
1116*1031c584SApple OSS Distributions
1117*1031c584SApple OSS Distributions theNub->release();
1118*1031c584SApple OSS Distributions
1119*1031c584SApple OSS Distributions // A child has gone away, re-scan children desires and clamp bits.
1120*1031c584SApple OSS Distributions // The fPendingAdjustPowerRequest helps to reduce redundant parent work.
1121*1031c584SApple OSS Distributions
1122*1031c584SApple OSS Distributions if (!fAdjustPowerScheduled) {
1123*1031c584SApple OSS Distributions IOPMRequest * request;
1124*1031c584SApple OSS Distributions request = acquirePMRequest( this, kIOPMRequestTypeAdjustPowerState );
1125*1031c584SApple OSS Distributions if (request) {
1126*1031c584SApple OSS Distributions submitPMRequest( request );
1127*1031c584SApple OSS Distributions fAdjustPowerScheduled = true;
1128*1031c584SApple OSS Distributions }
1129*1031c584SApple OSS Distributions }
1130*1031c584SApple OSS Distributions
1131*1031c584SApple OSS Distributions return IOPMNoErr;
1132*1031c584SApple OSS Distributions }
1133*1031c584SApple OSS Distributions
1134*1031c584SApple OSS Distributions //*********************************************************************************
1135*1031c584SApple OSS Distributions // [public] registerPowerDriver
1136*1031c584SApple OSS Distributions //
1137*1031c584SApple OSS Distributions // A driver has called us volunteering to control power to our device.
1138*1031c584SApple OSS Distributions //*********************************************************************************
1139*1031c584SApple OSS Distributions
1140*1031c584SApple OSS Distributions IOReturn
registerPowerDriver(IOService * powerDriver,IOPMPowerState * powerStates,unsigned long numberOfStates)1141*1031c584SApple OSS Distributions IOService::registerPowerDriver(
1142*1031c584SApple OSS Distributions IOService * powerDriver,
1143*1031c584SApple OSS Distributions IOPMPowerState * powerStates,
1144*1031c584SApple OSS Distributions unsigned long numberOfStates )
1145*1031c584SApple OSS Distributions {
1146*1031c584SApple OSS Distributions IOPMRequest * request;
1147*1031c584SApple OSS Distributions IOPMPSEntry * powerStatesCopy = NULL;
1148*1031c584SApple OSS Distributions IOPMPowerStateIndex stateOrder;
1149*1031c584SApple OSS Distributions IOReturn error = kIOReturnSuccess;
1150*1031c584SApple OSS Distributions
1151*1031c584SApple OSS Distributions if (!initialized) {
1152*1031c584SApple OSS Distributions return IOPMNotYetInitialized;
1153*1031c584SApple OSS Distributions }
1154*1031c584SApple OSS Distributions
1155*1031c584SApple OSS Distributions if (!powerStates || (numberOfStates < 2)) {
1156*1031c584SApple OSS Distributions OUR_PMLog(kPMLogControllingDriverErr5, numberOfStates, 0);
1157*1031c584SApple OSS Distributions return kIOReturnBadArgument;
1158*1031c584SApple OSS Distributions }
1159*1031c584SApple OSS Distributions
1160*1031c584SApple OSS Distributions if (!powerDriver || !powerDriver->initialized) {
1161*1031c584SApple OSS Distributions OUR_PMLog(kPMLogControllingDriverErr4, 0, 0);
1162*1031c584SApple OSS Distributions return kIOReturnBadArgument;
1163*1031c584SApple OSS Distributions }
1164*1031c584SApple OSS Distributions
1165*1031c584SApple OSS Distributions if (powerStates[0].version > kIOPMPowerStateVersion2) {
1166*1031c584SApple OSS Distributions OUR_PMLog(kPMLogControllingDriverErr1, powerStates[0].version, 0);
1167*1031c584SApple OSS Distributions return kIOReturnBadArgument;
1168*1031c584SApple OSS Distributions }
1169*1031c584SApple OSS Distributions
1170*1031c584SApple OSS Distributions do {
1171*1031c584SApple OSS Distributions // Make a copy of the supplied power state array.
1172*1031c584SApple OSS Distributions powerStatesCopy = IONewData(IOPMPSEntry, numberOfStates);
1173*1031c584SApple OSS Distributions if (!powerStatesCopy) {
1174*1031c584SApple OSS Distributions error = kIOReturnNoMemory;
1175*1031c584SApple OSS Distributions break;
1176*1031c584SApple OSS Distributions }
1177*1031c584SApple OSS Distributions
1178*1031c584SApple OSS Distributions // Initialize to bogus values
1179*1031c584SApple OSS Distributions for (IOPMPowerStateIndex i = 0; i < numberOfStates; i++) {
1180*1031c584SApple OSS Distributions powerStatesCopy[i].stateOrderToIndex = kIOPMPowerStateMax;
1181*1031c584SApple OSS Distributions }
1182*1031c584SApple OSS Distributions
1183*1031c584SApple OSS Distributions for (uint32_t i = 0; i < numberOfStates; i++) {
1184*1031c584SApple OSS Distributions powerStatesCopy[i].capabilityFlags = powerStates[i].capabilityFlags;
1185*1031c584SApple OSS Distributions powerStatesCopy[i].outputPowerFlags = powerStates[i].outputPowerCharacter;
1186*1031c584SApple OSS Distributions powerStatesCopy[i].inputPowerFlags = powerStates[i].inputPowerRequirement;
1187*1031c584SApple OSS Distributions powerStatesCopy[i].staticPower = powerStates[i].staticPower;
1188*1031c584SApple OSS Distributions #if USE_SETTLE_TIMER
1189*1031c584SApple OSS Distributions powerStatesCopy[i].settleUpTime = powerStates[i].settleUpTime;
1190*1031c584SApple OSS Distributions powerStatesCopy[i].settleDownTime = powerStates[i].settleDownTime;
1191*1031c584SApple OSS Distributions #endif
1192*1031c584SApple OSS Distributions if (powerStates[i].version >= kIOPMPowerStateVersion2) {
1193*1031c584SApple OSS Distributions stateOrder = powerStates[i].stateOrder;
1194*1031c584SApple OSS Distributions } else {
1195*1031c584SApple OSS Distributions stateOrder = i;
1196*1031c584SApple OSS Distributions }
1197*1031c584SApple OSS Distributions
1198*1031c584SApple OSS Distributions if (stateOrder < numberOfStates) {
1199*1031c584SApple OSS Distributions powerStatesCopy[i].stateOrder = stateOrder;
1200*1031c584SApple OSS Distributions powerStatesCopy[stateOrder].stateOrderToIndex = i;
1201*1031c584SApple OSS Distributions }
1202*1031c584SApple OSS Distributions }
1203*1031c584SApple OSS Distributions
1204*1031c584SApple OSS Distributions for (IOPMPowerStateIndex i = 0; i < numberOfStates; i++) {
1205*1031c584SApple OSS Distributions if (powerStatesCopy[i].stateOrderToIndex == kIOPMPowerStateMax) {
1206*1031c584SApple OSS Distributions // power state order missing
1207*1031c584SApple OSS Distributions error = kIOReturnBadArgument;
1208*1031c584SApple OSS Distributions break;
1209*1031c584SApple OSS Distributions }
1210*1031c584SApple OSS Distributions }
1211*1031c584SApple OSS Distributions if (kIOReturnSuccess != error) {
1212*1031c584SApple OSS Distributions break;
1213*1031c584SApple OSS Distributions }
1214*1031c584SApple OSS Distributions
1215*1031c584SApple OSS Distributions request = acquirePMRequest( this, kIOPMRequestTypeRegisterPowerDriver );
1216*1031c584SApple OSS Distributions if (!request) {
1217*1031c584SApple OSS Distributions error = kIOReturnNoMemory;
1218*1031c584SApple OSS Distributions break;
1219*1031c584SApple OSS Distributions }
1220*1031c584SApple OSS Distributions
1221*1031c584SApple OSS Distributions powerDriver->retain();
1222*1031c584SApple OSS Distributions request->fArg0 = (void *) powerDriver;
1223*1031c584SApple OSS Distributions request->fArg1 = (void *) powerStatesCopy;
1224*1031c584SApple OSS Distributions request->fArg2 = (void *) numberOfStates;
1225*1031c584SApple OSS Distributions
1226*1031c584SApple OSS Distributions submitPMRequest( request );
1227*1031c584SApple OSS Distributions return kIOReturnSuccess;
1228*1031c584SApple OSS Distributions }while (false);
1229*1031c584SApple OSS Distributions
1230*1031c584SApple OSS Distributions if (powerStatesCopy) {
1231*1031c584SApple OSS Distributions IODeleteData(powerStatesCopy, IOPMPSEntry, numberOfStates);
1232*1031c584SApple OSS Distributions }
1233*1031c584SApple OSS Distributions
1234*1031c584SApple OSS Distributions return error;
1235*1031c584SApple OSS Distributions }
1236*1031c584SApple OSS Distributions
1237*1031c584SApple OSS Distributions //*********************************************************************************
1238*1031c584SApple OSS Distributions // [private] handleRegisterPowerDriver
1239*1031c584SApple OSS Distributions //*********************************************************************************
1240*1031c584SApple OSS Distributions
1241*1031c584SApple OSS Distributions void
handleRegisterPowerDriver(IOPMRequest * request)1242*1031c584SApple OSS Distributions IOService::handleRegisterPowerDriver( IOPMRequest * request )
1243*1031c584SApple OSS Distributions {
1244*1031c584SApple OSS Distributions IOService * powerDriver = (IOService *) request->fArg0;
1245*1031c584SApple OSS Distributions IOPMPSEntry * powerStates = (IOPMPSEntry *) request->fArg1;
1246*1031c584SApple OSS Distributions IOPMPowerStateIndex numberOfStates = (IOPMPowerStateIndex) request->fArg2;
1247*1031c584SApple OSS Distributions IOPMPowerStateIndex i, stateIndex;
1248*1031c584SApple OSS Distributions IOPMPowerStateIndex lowestPowerState;
1249*1031c584SApple OSS Distributions IOService * root;
1250*1031c584SApple OSS Distributions OSIterator * iter;
1251*1031c584SApple OSS Distributions
1252*1031c584SApple OSS Distributions PM_ASSERT_IN_GATE();
1253*1031c584SApple OSS Distributions assert(powerStates);
1254*1031c584SApple OSS Distributions assert(powerDriver);
1255*1031c584SApple OSS Distributions assert(numberOfStates > 1);
1256*1031c584SApple OSS Distributions
1257*1031c584SApple OSS Distributions if (!fNumberOfPowerStates) {
1258*1031c584SApple OSS Distributions OUR_PMLog(kPMLogControllingDriver, numberOfStates, kIOPMPowerStateVersion1);
1259*1031c584SApple OSS Distributions
1260*1031c584SApple OSS Distributions fPowerStates = powerStates;
1261*1031c584SApple OSS Distributions fNumberOfPowerStates = numberOfStates;
1262*1031c584SApple OSS Distributions fControllingDriver = powerDriver;
1263*1031c584SApple OSS Distributions fCurrentCapabilityFlags = fPowerStates[0].capabilityFlags;
1264*1031c584SApple OSS Distributions
1265*1031c584SApple OSS Distributions lowestPowerState = fPowerStates[0].stateOrderToIndex;
1266*1031c584SApple OSS Distributions fHighestPowerState = fPowerStates[numberOfStates - 1].stateOrderToIndex;
1267*1031c584SApple OSS Distributions
1268*1031c584SApple OSS Distributions {
1269*1031c584SApple OSS Distributions uint32_t aotFlags;
1270*1031c584SApple OSS Distributions IOService * service;
1271*1031c584SApple OSS Distributions OSObject * object;
1272*1031c584SApple OSS Distributions OSData * data;
1273*1031c584SApple OSS Distributions
1274*1031c584SApple OSS Distributions // Disallow kIOPMAOTPower states unless device tree enabled
1275*1031c584SApple OSS Distributions
1276*1031c584SApple OSS Distributions aotFlags = 0;
1277*1031c584SApple OSS Distributions service = this;
1278*1031c584SApple OSS Distributions while (service && !service->inPlane(gIODTPlane)) {
1279*1031c584SApple OSS Distributions service = service->getProvider();
1280*1031c584SApple OSS Distributions }
1281*1031c584SApple OSS Distributions if (service) {
1282*1031c584SApple OSS Distributions object = service->copyProperty(kIOPMAOTPowerKey, gIODTPlane);
1283*1031c584SApple OSS Distributions data = OSDynamicCast(OSData, object);
1284*1031c584SApple OSS Distributions if (data && (data->getLength() >= sizeof(uint32_t))) {
1285*1031c584SApple OSS Distributions aotFlags = ((uint32_t *)data->getBytesNoCopy())[0];
1286*1031c584SApple OSS Distributions }
1287*1031c584SApple OSS Distributions OSSafeReleaseNULL(object);
1288*1031c584SApple OSS Distributions }
1289*1031c584SApple OSS Distributions if (!aotFlags) {
1290*1031c584SApple OSS Distributions for (i = 0; i < numberOfStates; i++) {
1291*1031c584SApple OSS Distributions if (kIOPMAOTPower & fPowerStates[i].inputPowerFlags) {
1292*1031c584SApple OSS Distributions fPowerStates[i].inputPowerFlags = 0xFFFFFFFF;
1293*1031c584SApple OSS Distributions fPowerStates[i].capabilityFlags = 0;
1294*1031c584SApple OSS Distributions fPowerStates[i].outputPowerFlags = 0;
1295*1031c584SApple OSS Distributions }
1296*1031c584SApple OSS Distributions }
1297*1031c584SApple OSS Distributions }
1298*1031c584SApple OSS Distributions }
1299*1031c584SApple OSS Distributions
1300*1031c584SApple OSS Distributions // OR'in all the output power flags
1301*1031c584SApple OSS Distributions fMergedOutputPowerFlags = 0;
1302*1031c584SApple OSS Distributions fDeviceUsablePowerState = lowestPowerState;
1303*1031c584SApple OSS Distributions for (i = 0; i < numberOfStates; i++) {
1304*1031c584SApple OSS Distributions fMergedOutputPowerFlags |= fPowerStates[i].outputPowerFlags;
1305*1031c584SApple OSS Distributions
1306*1031c584SApple OSS Distributions stateIndex = fPowerStates[i].stateOrderToIndex;
1307*1031c584SApple OSS Distributions assert(stateIndex < numberOfStates);
1308*1031c584SApple OSS Distributions if ((fDeviceUsablePowerState == lowestPowerState) &&
1309*1031c584SApple OSS Distributions (fPowerStates[stateIndex].capabilityFlags & IOPMDeviceUsable)) {
1310*1031c584SApple OSS Distributions // The minimum power state that the device is usable
1311*1031c584SApple OSS Distributions fDeviceUsablePowerState = stateIndex;
1312*1031c584SApple OSS Distributions }
1313*1031c584SApple OSS Distributions }
1314*1031c584SApple OSS Distributions
1315*1031c584SApple OSS Distributions // Register powerDriver as interested, unless already done.
1316*1031c584SApple OSS Distributions // We don't want to register the default implementation since
1317*1031c584SApple OSS Distributions // it does nothing. One ramification of not always registering
1318*1031c584SApple OSS Distributions // is the one fewer retain count held.
1319*1031c584SApple OSS Distributions
1320*1031c584SApple OSS Distributions root = getPlatform()->getProvider();
1321*1031c584SApple OSS Distributions assert(root);
1322*1031c584SApple OSS Distributions if (!root ||
1323*1031c584SApple OSS Distributions ((OSMemberFunctionCast(void (*)(void),
1324*1031c584SApple OSS Distributions root, &IOService::powerStateDidChangeTo)) !=
1325*1031c584SApple OSS Distributions ((OSMemberFunctionCast(void (*)(void),
1326*1031c584SApple OSS Distributions this, &IOService::powerStateDidChangeTo)))) ||
1327*1031c584SApple OSS Distributions ((OSMemberFunctionCast(void (*)(void),
1328*1031c584SApple OSS Distributions root, &IOService::powerStateWillChangeTo)) !=
1329*1031c584SApple OSS Distributions ((OSMemberFunctionCast(void (*)(void),
1330*1031c584SApple OSS Distributions this, &IOService::powerStateWillChangeTo))))) {
1331*1031c584SApple OSS Distributions if (fInterestedDrivers->findItem(powerDriver) == NULL) {
1332*1031c584SApple OSS Distributions PM_LOCK();
1333*1031c584SApple OSS Distributions fInterestedDrivers->appendNewInformee(powerDriver);
1334*1031c584SApple OSS Distributions PM_UNLOCK();
1335*1031c584SApple OSS Distributions }
1336*1031c584SApple OSS Distributions }
1337*1031c584SApple OSS Distributions
1338*1031c584SApple OSS Distributions // Examine all existing power clients and perform limit check.
1339*1031c584SApple OSS Distributions
1340*1031c584SApple OSS Distributions if (fPowerClients &&
1341*1031c584SApple OSS Distributions (iter = OSCollectionIterator::withCollection(fPowerClients))) {
1342*1031c584SApple OSS Distributions const OSSymbol * client;
1343*1031c584SApple OSS Distributions while ((client = (const OSSymbol *) iter->getNextObject())) {
1344*1031c584SApple OSS Distributions IOPMPowerStateIndex powerState = getPowerStateForClient(client);
1345*1031c584SApple OSS Distributions if (powerState >= numberOfStates) {
1346*1031c584SApple OSS Distributions updatePowerClient(client, fHighestPowerState);
1347*1031c584SApple OSS Distributions }
1348*1031c584SApple OSS Distributions }
1349*1031c584SApple OSS Distributions iter->release();
1350*1031c584SApple OSS Distributions }
1351*1031c584SApple OSS Distributions
1352*1031c584SApple OSS Distributions // Populate IOPMActions for a few special services
1353*1031c584SApple OSS Distributions getPMRootDomain()->tagPowerPlaneService(this, &fPMActions, fNumberOfPowerStates - 1);
1354*1031c584SApple OSS Distributions
1355*1031c584SApple OSS Distributions if (inPlane(gIOPowerPlane) && fParentsKnowState) {
1356*1031c584SApple OSS Distributions IOPMPowerStateIndex tempDesire;
1357*1031c584SApple OSS Distributions fMaxPowerState = fControllingDriver->maxCapabilityForDomainState(fParentsCurrentPowerFlags);
1358*1031c584SApple OSS Distributions // initially change into the state we are already in
1359*1031c584SApple OSS Distributions tempDesire = fControllingDriver->initialPowerStateForDomainState(fParentsCurrentPowerFlags);
1360*1031c584SApple OSS Distributions adjustPowerState(tempDesire);
1361*1031c584SApple OSS Distributions }
1362*1031c584SApple OSS Distributions } else {
1363*1031c584SApple OSS Distributions OUR_PMLog(kPMLogControllingDriverErr2, numberOfStates, 0);
1364*1031c584SApple OSS Distributions IODeleteData(powerStates, IOPMPSEntry, numberOfStates);
1365*1031c584SApple OSS Distributions }
1366*1031c584SApple OSS Distributions
1367*1031c584SApple OSS Distributions powerDriver->release();
1368*1031c584SApple OSS Distributions }
1369*1031c584SApple OSS Distributions
1370*1031c584SApple OSS Distributions //*********************************************************************************
1371*1031c584SApple OSS Distributions // [public] registerInterestedDriver
1372*1031c584SApple OSS Distributions //
1373*1031c584SApple OSS Distributions // Add the caller to our list of interested drivers and return our current
1374*1031c584SApple OSS Distributions // power state. If we don't have a power-controlling driver yet, we will
1375*1031c584SApple OSS Distributions // call this interested driver again later when we do get a driver and find
1376*1031c584SApple OSS Distributions // out what the current power state of the device is.
1377*1031c584SApple OSS Distributions //*********************************************************************************
1378*1031c584SApple OSS Distributions
1379*1031c584SApple OSS Distributions IOPMPowerFlags
registerInterestedDriver(IOService * driver)1380*1031c584SApple OSS Distributions IOService::registerInterestedDriver( IOService * driver )
1381*1031c584SApple OSS Distributions {
1382*1031c584SApple OSS Distributions IOPMRequest * request;
1383*1031c584SApple OSS Distributions bool signal;
1384*1031c584SApple OSS Distributions
1385*1031c584SApple OSS Distributions if (!driver || !initialized || !fInterestedDrivers) {
1386*1031c584SApple OSS Distributions return 0;
1387*1031c584SApple OSS Distributions }
1388*1031c584SApple OSS Distributions
1389*1031c584SApple OSS Distributions PM_LOCK();
1390*1031c584SApple OSS Distributions signal = (!fInsertInterestSet && !fRemoveInterestSet);
1391*1031c584SApple OSS Distributions if (fInsertInterestSet == NULL) {
1392*1031c584SApple OSS Distributions fInsertInterestSet = OSSet::withCapacity(4);
1393*1031c584SApple OSS Distributions }
1394*1031c584SApple OSS Distributions if (fInsertInterestSet) {
1395*1031c584SApple OSS Distributions fInsertInterestSet->setObject(driver);
1396*1031c584SApple OSS Distributions if (fRemoveInterestSet) {
1397*1031c584SApple OSS Distributions fRemoveInterestSet->removeObject(driver);
1398*1031c584SApple OSS Distributions }
1399*1031c584SApple OSS Distributions }
1400*1031c584SApple OSS Distributions PM_UNLOCK();
1401*1031c584SApple OSS Distributions
1402*1031c584SApple OSS Distributions if (signal) {
1403*1031c584SApple OSS Distributions request = acquirePMRequest( this, kIOPMRequestTypeInterestChanged );
1404*1031c584SApple OSS Distributions if (request) {
1405*1031c584SApple OSS Distributions submitPMRequest( request );
1406*1031c584SApple OSS Distributions }
1407*1031c584SApple OSS Distributions }
1408*1031c584SApple OSS Distributions
1409*1031c584SApple OSS Distributions // This return value cannot be trusted, but return a value
1410*1031c584SApple OSS Distributions // for those clients that care.
1411*1031c584SApple OSS Distributions
1412*1031c584SApple OSS Distributions OUR_PMLog(kPMLogInterestedDriver, kIOPMDeviceUsable, 2);
1413*1031c584SApple OSS Distributions return kIOPMDeviceUsable;
1414*1031c584SApple OSS Distributions }
1415*1031c584SApple OSS Distributions
1416*1031c584SApple OSS Distributions //*********************************************************************************
1417*1031c584SApple OSS Distributions // [public] deRegisterInterestedDriver
1418*1031c584SApple OSS Distributions //*********************************************************************************
1419*1031c584SApple OSS Distributions
1420*1031c584SApple OSS Distributions IOReturn
deRegisterInterestedDriver(IOService * driver)1421*1031c584SApple OSS Distributions IOService::deRegisterInterestedDriver( IOService * driver )
1422*1031c584SApple OSS Distributions {
1423*1031c584SApple OSS Distributions IOPMinformee * item;
1424*1031c584SApple OSS Distributions IOPMRequest * request;
1425*1031c584SApple OSS Distributions bool signal;
1426*1031c584SApple OSS Distributions
1427*1031c584SApple OSS Distributions if (!driver) {
1428*1031c584SApple OSS Distributions return kIOReturnBadArgument;
1429*1031c584SApple OSS Distributions }
1430*1031c584SApple OSS Distributions if (!initialized || !fInterestedDrivers) {
1431*1031c584SApple OSS Distributions return IOPMNotPowerManaged;
1432*1031c584SApple OSS Distributions }
1433*1031c584SApple OSS Distributions
1434*1031c584SApple OSS Distributions PM_LOCK();
1435*1031c584SApple OSS Distributions if (fInsertInterestSet) {
1436*1031c584SApple OSS Distributions fInsertInterestSet->removeObject(driver);
1437*1031c584SApple OSS Distributions }
1438*1031c584SApple OSS Distributions
1439*1031c584SApple OSS Distributions item = fInterestedDrivers->findItem(driver);
1440*1031c584SApple OSS Distributions if (!item) {
1441*1031c584SApple OSS Distributions PM_UNLOCK();
1442*1031c584SApple OSS Distributions return kIOReturnNotFound;
1443*1031c584SApple OSS Distributions }
1444*1031c584SApple OSS Distributions
1445*1031c584SApple OSS Distributions signal = (!fRemoveInterestSet && !fInsertInterestSet);
1446*1031c584SApple OSS Distributions if (fRemoveInterestSet == NULL) {
1447*1031c584SApple OSS Distributions fRemoveInterestSet = OSSet::withCapacity(4);
1448*1031c584SApple OSS Distributions }
1449*1031c584SApple OSS Distributions if (fRemoveInterestSet) {
1450*1031c584SApple OSS Distributions fRemoveInterestSet->setObject(driver);
1451*1031c584SApple OSS Distributions if (item->active) {
1452*1031c584SApple OSS Distributions item->active = false;
1453*1031c584SApple OSS Distributions waitForPMDriverCall( driver );
1454*1031c584SApple OSS Distributions }
1455*1031c584SApple OSS Distributions }
1456*1031c584SApple OSS Distributions PM_UNLOCK();
1457*1031c584SApple OSS Distributions
1458*1031c584SApple OSS Distributions if (signal) {
1459*1031c584SApple OSS Distributions request = acquirePMRequest( this, kIOPMRequestTypeInterestChanged );
1460*1031c584SApple OSS Distributions if (request) {
1461*1031c584SApple OSS Distributions submitPMRequest( request );
1462*1031c584SApple OSS Distributions }
1463*1031c584SApple OSS Distributions }
1464*1031c584SApple OSS Distributions
1465*1031c584SApple OSS Distributions return IOPMNoErr;
1466*1031c584SApple OSS Distributions }
1467*1031c584SApple OSS Distributions
1468*1031c584SApple OSS Distributions //*********************************************************************************
1469*1031c584SApple OSS Distributions // [private] handleInterestChanged
1470*1031c584SApple OSS Distributions //
1471*1031c584SApple OSS Distributions // Handle interest added or removed.
1472*1031c584SApple OSS Distributions //*********************************************************************************
1473*1031c584SApple OSS Distributions
1474*1031c584SApple OSS Distributions void
handleInterestChanged(IOPMRequest * request)1475*1031c584SApple OSS Distributions IOService::handleInterestChanged( IOPMRequest * request )
1476*1031c584SApple OSS Distributions {
1477*1031c584SApple OSS Distributions IOService * driver;
1478*1031c584SApple OSS Distributions IOPMinformee * informee;
1479*1031c584SApple OSS Distributions IOPMinformeeList * list = fInterestedDrivers;
1480*1031c584SApple OSS Distributions
1481*1031c584SApple OSS Distributions PM_LOCK();
1482*1031c584SApple OSS Distributions
1483*1031c584SApple OSS Distributions if (fInsertInterestSet) {
1484*1031c584SApple OSS Distributions while ((driver = (IOService *) fInsertInterestSet->getAnyObject())) {
1485*1031c584SApple OSS Distributions if (list->findItem(driver) == NULL) {
1486*1031c584SApple OSS Distributions list->appendNewInformee(driver);
1487*1031c584SApple OSS Distributions }
1488*1031c584SApple OSS Distributions fInsertInterestSet->removeObject(driver);
1489*1031c584SApple OSS Distributions }
1490*1031c584SApple OSS Distributions fInsertInterestSet->release();
1491*1031c584SApple OSS Distributions fInsertInterestSet = NULL;
1492*1031c584SApple OSS Distributions }
1493*1031c584SApple OSS Distributions
1494*1031c584SApple OSS Distributions if (fRemoveInterestSet) {
1495*1031c584SApple OSS Distributions while ((driver = (IOService *) fRemoveInterestSet->getAnyObject())) {
1496*1031c584SApple OSS Distributions informee = list->findItem(driver);
1497*1031c584SApple OSS Distributions if (informee) {
1498*1031c584SApple OSS Distributions // Clean-up async interest acknowledgement
1499*1031c584SApple OSS Distributions if (fHeadNotePendingAcks && informee->timer) {
1500*1031c584SApple OSS Distributions informee->timer = 0;
1501*1031c584SApple OSS Distributions fHeadNotePendingAcks--;
1502*1031c584SApple OSS Distributions }
1503*1031c584SApple OSS Distributions list->removeFromList(driver);
1504*1031c584SApple OSS Distributions }
1505*1031c584SApple OSS Distributions fRemoveInterestSet->removeObject(driver);
1506*1031c584SApple OSS Distributions }
1507*1031c584SApple OSS Distributions fRemoveInterestSet->release();
1508*1031c584SApple OSS Distributions fRemoveInterestSet = NULL;
1509*1031c584SApple OSS Distributions }
1510*1031c584SApple OSS Distributions
1511*1031c584SApple OSS Distributions PM_UNLOCK();
1512*1031c584SApple OSS Distributions }
1513*1031c584SApple OSS Distributions
1514*1031c584SApple OSS Distributions //*********************************************************************************
1515*1031c584SApple OSS Distributions // [public] acknowledgePowerChange
1516*1031c584SApple OSS Distributions //
1517*1031c584SApple OSS Distributions // After we notified one of the interested drivers or a power-domain child
1518*1031c584SApple OSS Distributions // of an impending change in power, it has called to say it is now
1519*1031c584SApple OSS Distributions // prepared for the change. If this object is the last to
1520*1031c584SApple OSS Distributions // acknowledge this change, we take whatever action we have been waiting
1521*1031c584SApple OSS Distributions // for.
1522*1031c584SApple OSS Distributions // That may include acknowledging to our parent. In this case, we do it
1523*1031c584SApple OSS Distributions // last of all to insure that this doesn't cause the parent to call us some-
1524*1031c584SApple OSS Distributions // where else and alter data we are relying on here (like the very existance
1525*1031c584SApple OSS Distributions // of a "current change note".)
1526*1031c584SApple OSS Distributions //*********************************************************************************
1527*1031c584SApple OSS Distributions
1528*1031c584SApple OSS Distributions IOReturn
acknowledgePowerChange(IOService * whichObject)1529*1031c584SApple OSS Distributions IOService::acknowledgePowerChange( IOService * whichObject )
1530*1031c584SApple OSS Distributions {
1531*1031c584SApple OSS Distributions IOPMRequest * request;
1532*1031c584SApple OSS Distributions
1533*1031c584SApple OSS Distributions if (!initialized) {
1534*1031c584SApple OSS Distributions return IOPMNotYetInitialized;
1535*1031c584SApple OSS Distributions }
1536*1031c584SApple OSS Distributions if (!whichObject) {
1537*1031c584SApple OSS Distributions return kIOReturnBadArgument;
1538*1031c584SApple OSS Distributions }
1539*1031c584SApple OSS Distributions
1540*1031c584SApple OSS Distributions request = acquirePMRequest( this, kIOPMRequestTypeAckPowerChange );
1541*1031c584SApple OSS Distributions if (!request) {
1542*1031c584SApple OSS Distributions return kIOReturnNoMemory;
1543*1031c584SApple OSS Distributions }
1544*1031c584SApple OSS Distributions
1545*1031c584SApple OSS Distributions whichObject->retain();
1546*1031c584SApple OSS Distributions request->fArg0 = whichObject;
1547*1031c584SApple OSS Distributions
1548*1031c584SApple OSS Distributions submitPMRequest( request );
1549*1031c584SApple OSS Distributions return IOPMNoErr;
1550*1031c584SApple OSS Distributions }
1551*1031c584SApple OSS Distributions
1552*1031c584SApple OSS Distributions //*********************************************************************************
1553*1031c584SApple OSS Distributions // [private] handleAcknowledgePowerChange
1554*1031c584SApple OSS Distributions //*********************************************************************************
1555*1031c584SApple OSS Distributions
1556*1031c584SApple OSS Distributions bool
handleAcknowledgePowerChange(IOPMRequest * request)1557*1031c584SApple OSS Distributions IOService::handleAcknowledgePowerChange( IOPMRequest * request )
1558*1031c584SApple OSS Distributions {
1559*1031c584SApple OSS Distributions IOPMinformee * informee;
1560*1031c584SApple OSS Distributions IOPMPowerStateIndex childPower = kIOPMUnknown;
1561*1031c584SApple OSS Distributions IOService * theChild;
1562*1031c584SApple OSS Distributions IOService * whichObject;
1563*1031c584SApple OSS Distributions bool all_acked = false;
1564*1031c584SApple OSS Distributions
1565*1031c584SApple OSS Distributions PM_ASSERT_IN_GATE();
1566*1031c584SApple OSS Distributions whichObject = (IOService *) request->fArg0;
1567*1031c584SApple OSS Distributions assert(whichObject);
1568*1031c584SApple OSS Distributions
1569*1031c584SApple OSS Distributions // one of our interested drivers?
1570*1031c584SApple OSS Distributions informee = fInterestedDrivers->findItem( whichObject );
1571*1031c584SApple OSS Distributions if (informee == NULL) {
1572*1031c584SApple OSS Distributions if (!isChild(whichObject, gIOPowerPlane)) {
1573*1031c584SApple OSS Distributions OUR_PMLog(kPMLogAcknowledgeErr1, 0, 0);
1574*1031c584SApple OSS Distributions goto no_err;
1575*1031c584SApple OSS Distributions } else {
1576*1031c584SApple OSS Distributions OUR_PMLog(kPMLogChildAcknowledge, fHeadNotePendingAcks, 0);
1577*1031c584SApple OSS Distributions }
1578*1031c584SApple OSS Distributions } else {
1579*1031c584SApple OSS Distributions OUR_PMLog(kPMLogDriverAcknowledge, fHeadNotePendingAcks, 0);
1580*1031c584SApple OSS Distributions }
1581*1031c584SApple OSS Distributions
1582*1031c584SApple OSS Distributions if (fHeadNotePendingAcks != 0) {
1583*1031c584SApple OSS Distributions assert(fPowerStates != NULL);
1584*1031c584SApple OSS Distributions
1585*1031c584SApple OSS Distributions // yes, make sure we're expecting acks
1586*1031c584SApple OSS Distributions if (informee != NULL) {
1587*1031c584SApple OSS Distributions // it's an interested driver
1588*1031c584SApple OSS Distributions // make sure we're expecting this ack
1589*1031c584SApple OSS Distributions if (informee->timer != 0) {
1590*1031c584SApple OSS Distributions SOCD_TRACE_XNU(PM_INFORM_POWER_CHANGE_ACK,
1591*1031c584SApple OSS Distributions ADDR(informee->whatObject->getMetaClass()),
1592*1031c584SApple OSS Distributions ADDR(this->getMetaClass()),
1593*1031c584SApple OSS Distributions PACK_2X32(VALUE(this->getRegistryEntryID()), VALUE(informee->whatObject->getRegistryEntryID())),
1594*1031c584SApple OSS Distributions PACK_2X32(VALUE(0), VALUE(fDriverCallReason)));
1595*1031c584SApple OSS Distributions
1596*1031c584SApple OSS Distributions if (informee->timer > 0) {
1597*1031c584SApple OSS Distributions uint64_t nsec = computeTimeDeltaNS(&informee->startTime);
1598*1031c584SApple OSS Distributions if (nsec > gIOPMSetPowerStateLogNS) {
1599*1031c584SApple OSS Distributions getPMRootDomain()->pmStatsRecordApplicationResponse(
1600*1031c584SApple OSS Distributions gIOPMStatsDriverPSChangeSlow, informee->whatObject->getName(),
1601*1031c584SApple OSS Distributions fDriverCallReason, NS_TO_MS(nsec), informee->whatObject->getRegistryEntryID(),
1602*1031c584SApple OSS Distributions NULL, fHeadNotePowerState, true);
1603*1031c584SApple OSS Distributions }
1604*1031c584SApple OSS Distributions }
1605*1031c584SApple OSS Distributions
1606*1031c584SApple OSS Distributions // mark it acked
1607*1031c584SApple OSS Distributions informee->timer = 0;
1608*1031c584SApple OSS Distributions // that's one fewer to worry about
1609*1031c584SApple OSS Distributions fHeadNotePendingAcks--;
1610*1031c584SApple OSS Distributions } else {
1611*1031c584SApple OSS Distributions // this driver has already acked
1612*1031c584SApple OSS Distributions OUR_PMLog(kPMLogAcknowledgeErr2, 0, 0);
1613*1031c584SApple OSS Distributions }
1614*1031c584SApple OSS Distributions } else {
1615*1031c584SApple OSS Distributions // it's a child
1616*1031c584SApple OSS Distributions // make sure we're expecting this ack
1617*1031c584SApple OSS Distributions if (((IOPowerConnection *)whichObject)->getAwaitingAck()) {
1618*1031c584SApple OSS Distributions // that's one fewer to worry about
1619*1031c584SApple OSS Distributions fHeadNotePendingAcks--;
1620*1031c584SApple OSS Distributions ((IOPowerConnection *)whichObject)->setAwaitingAck(false);
1621*1031c584SApple OSS Distributions theChild = (IOService *)whichObject->copyChildEntry(gIOPowerPlane);
1622*1031c584SApple OSS Distributions if (theChild) {
1623*1031c584SApple OSS Distributions childPower = theChild->currentPowerConsumption();
1624*1031c584SApple OSS Distributions theChild->release();
1625*1031c584SApple OSS Distributions }
1626*1031c584SApple OSS Distributions if (childPower == kIOPMUnknown) {
1627*1031c584SApple OSS Distributions fHeadNotePowerArrayEntry->staticPower = kIOPMUnknown;
1628*1031c584SApple OSS Distributions } else {
1629*1031c584SApple OSS Distributions if (fHeadNotePowerArrayEntry->staticPower != kIOPMUnknown) {
1630*1031c584SApple OSS Distributions fHeadNotePowerArrayEntry->staticPower += childPower;
1631*1031c584SApple OSS Distributions }
1632*1031c584SApple OSS Distributions }
1633*1031c584SApple OSS Distributions }
1634*1031c584SApple OSS Distributions }
1635*1031c584SApple OSS Distributions
1636*1031c584SApple OSS Distributions if (fHeadNotePendingAcks == 0) {
1637*1031c584SApple OSS Distributions // yes, stop the timer
1638*1031c584SApple OSS Distributions stop_ack_timer();
1639*1031c584SApple OSS Distributions // and now we can continue
1640*1031c584SApple OSS Distributions all_acked = true;
1641*1031c584SApple OSS Distributions getPMRootDomain()->reset_watchdog_timer(this, 0);
1642*1031c584SApple OSS Distributions }
1643*1031c584SApple OSS Distributions } else {
1644*1031c584SApple OSS Distributions OUR_PMLog(kPMLogAcknowledgeErr3, 0, 0); // not expecting anybody to ack
1645*1031c584SApple OSS Distributions }
1646*1031c584SApple OSS Distributions
1647*1031c584SApple OSS Distributions no_err:
1648*1031c584SApple OSS Distributions if (whichObject) {
1649*1031c584SApple OSS Distributions whichObject->release();
1650*1031c584SApple OSS Distributions }
1651*1031c584SApple OSS Distributions
1652*1031c584SApple OSS Distributions return all_acked;
1653*1031c584SApple OSS Distributions }
1654*1031c584SApple OSS Distributions
1655*1031c584SApple OSS Distributions //*********************************************************************************
1656*1031c584SApple OSS Distributions // [public] acknowledgeSetPowerState
1657*1031c584SApple OSS Distributions //
1658*1031c584SApple OSS Distributions // After we instructed our controlling driver to change power states,
1659*1031c584SApple OSS Distributions // it has called to say it has finished doing so.
1660*1031c584SApple OSS Distributions // We continue to process the power state change.
1661*1031c584SApple OSS Distributions //*********************************************************************************
1662*1031c584SApple OSS Distributions
1663*1031c584SApple OSS Distributions IOReturn
acknowledgeSetPowerState(void)1664*1031c584SApple OSS Distributions IOService::acknowledgeSetPowerState( void )
1665*1031c584SApple OSS Distributions {
1666*1031c584SApple OSS Distributions IOPMRequest * request;
1667*1031c584SApple OSS Distributions
1668*1031c584SApple OSS Distributions if (!initialized) {
1669*1031c584SApple OSS Distributions return IOPMNotYetInitialized;
1670*1031c584SApple OSS Distributions }
1671*1031c584SApple OSS Distributions
1672*1031c584SApple OSS Distributions request = acquirePMRequest( this, kIOPMRequestTypeAckSetPowerState );
1673*1031c584SApple OSS Distributions if (!request) {
1674*1031c584SApple OSS Distributions return kIOReturnNoMemory;
1675*1031c584SApple OSS Distributions }
1676*1031c584SApple OSS Distributions
1677*1031c584SApple OSS Distributions submitPMRequest( request );
1678*1031c584SApple OSS Distributions return kIOReturnSuccess;
1679*1031c584SApple OSS Distributions }
1680*1031c584SApple OSS Distributions
1681*1031c584SApple OSS Distributions //*********************************************************************************
1682*1031c584SApple OSS Distributions // [private] handleAcknowledgeSetPowerState
1683*1031c584SApple OSS Distributions //*********************************************************************************
1684*1031c584SApple OSS Distributions
1685*1031c584SApple OSS Distributions bool
handleAcknowledgeSetPowerState(IOPMRequest * request __unused)1686*1031c584SApple OSS Distributions IOService::handleAcknowledgeSetPowerState( IOPMRequest * request __unused)
1687*1031c584SApple OSS Distributions {
1688*1031c584SApple OSS Distributions const OSMetaClass *controllingDriverMetaClass = NULL;
1689*1031c584SApple OSS Distributions uint32_t controllingDriverRegistryEntryID = 0;
1690*1031c584SApple OSS Distributions bool more = false;
1691*1031c584SApple OSS Distributions bool trace_this_ack = true;
1692*1031c584SApple OSS Distributions
1693*1031c584SApple OSS Distributions if (fDriverTimer == -1) {
1694*1031c584SApple OSS Distributions // driver acked while setPowerState() call is in-flight.
1695*1031c584SApple OSS Distributions // take this ack, return value from setPowerState() is irrelevant.
1696*1031c584SApple OSS Distributions OUR_PMLog(kPMLogDriverAcknowledgeSet,
1697*1031c584SApple OSS Distributions (uintptr_t) this, fDriverTimer);
1698*1031c584SApple OSS Distributions fDriverTimer = 0;
1699*1031c584SApple OSS Distributions } else if (fDriverTimer > 0) {
1700*1031c584SApple OSS Distributions // expected ack, stop the timer
1701*1031c584SApple OSS Distributions stop_ack_timer();
1702*1031c584SApple OSS Distributions
1703*1031c584SApple OSS Distributions getPMRootDomain()->reset_watchdog_timer(this, 0);
1704*1031c584SApple OSS Distributions
1705*1031c584SApple OSS Distributions uint64_t nsec = computeTimeDeltaNS(&fDriverCallStartTime);
1706*1031c584SApple OSS Distributions if (nsec > gIOPMSetPowerStateLogNS) {
1707*1031c584SApple OSS Distributions getPMRootDomain()->pmStatsRecordApplicationResponse(
1708*1031c584SApple OSS Distributions gIOPMStatsDriverPSChangeSlow,
1709*1031c584SApple OSS Distributions fName, kDriverCallSetPowerState, NS_TO_MS(nsec), getRegistryEntryID(),
1710*1031c584SApple OSS Distributions NULL, fHeadNotePowerState, true);
1711*1031c584SApple OSS Distributions }
1712*1031c584SApple OSS Distributions
1713*1031c584SApple OSS Distributions OUR_PMLog(kPMLogDriverAcknowledgeSet, (uintptr_t) this, fDriverTimer);
1714*1031c584SApple OSS Distributions fDriverTimer = 0;
1715*1031c584SApple OSS Distributions more = true;
1716*1031c584SApple OSS Distributions } else {
1717*1031c584SApple OSS Distributions // unexpected ack
1718*1031c584SApple OSS Distributions OUR_PMLog(kPMLogAcknowledgeErr4, (uintptr_t) this, 0);
1719*1031c584SApple OSS Distributions trace_this_ack = false;
1720*1031c584SApple OSS Distributions }
1721*1031c584SApple OSS Distributions
1722*1031c584SApple OSS Distributions if (trace_this_ack) {
1723*1031c584SApple OSS Distributions if (fControllingDriver) {
1724*1031c584SApple OSS Distributions controllingDriverMetaClass = fControllingDriver->getMetaClass();
1725*1031c584SApple OSS Distributions controllingDriverRegistryEntryID = (uint32_t)fControllingDriver->getRegistryEntryID();
1726*1031c584SApple OSS Distributions }
1727*1031c584SApple OSS Distributions
1728*1031c584SApple OSS Distributions SOCD_TRACE_XNU(PM_SET_POWER_STATE_ACK,
1729*1031c584SApple OSS Distributions ADDR(controllingDriverMetaClass),
1730*1031c584SApple OSS Distributions ADDR(this->getMetaClass()),
1731*1031c584SApple OSS Distributions PACK_2X32(VALUE(this->getRegistryEntryID()), VALUE(controllingDriverRegistryEntryID)),
1732*1031c584SApple OSS Distributions PACK_2X32(VALUE(fHeadNotePowerState), VALUE(0)));
1733*1031c584SApple OSS Distributions }
1734*1031c584SApple OSS Distributions
1735*1031c584SApple OSS Distributions return more;
1736*1031c584SApple OSS Distributions }
1737*1031c584SApple OSS Distributions
1738*1031c584SApple OSS Distributions //*********************************************************************************
1739*1031c584SApple OSS Distributions // [private] adjustPowerState
1740*1031c584SApple OSS Distributions //*********************************************************************************
1741*1031c584SApple OSS Distributions
1742*1031c584SApple OSS Distributions void
adjustPowerState(IOPMPowerStateIndex clamp)1743*1031c584SApple OSS Distributions IOService::adjustPowerState( IOPMPowerStateIndex clamp )
1744*1031c584SApple OSS Distributions {
1745*1031c584SApple OSS Distributions PM_ASSERT_IN_GATE();
1746*1031c584SApple OSS Distributions computeDesiredState(clamp, false);
1747*1031c584SApple OSS Distributions if (fControllingDriver && fParentsKnowState && inPlane(gIOPowerPlane)) {
1748*1031c584SApple OSS Distributions IOPMPowerChangeFlags changeFlags = kIOPMSelfInitiated;
1749*1031c584SApple OSS Distributions
1750*1031c584SApple OSS Distributions // Indicate that children desires must be ignored, and do not ask
1751*1031c584SApple OSS Distributions // apps for permission to drop power. This is used by root domain
1752*1031c584SApple OSS Distributions // for demand sleep.
1753*1031c584SApple OSS Distributions
1754*1031c584SApple OSS Distributions if (getPMRequestType() == kIOPMRequestTypeRequestPowerStateOverride) {
1755*1031c584SApple OSS Distributions changeFlags |= (kIOPMIgnoreChildren | kIOPMSkipAskPowerDown);
1756*1031c584SApple OSS Distributions }
1757*1031c584SApple OSS Distributions
1758*1031c584SApple OSS Distributions startPowerChange(
1759*1031c584SApple OSS Distributions /* flags */ changeFlags,
1760*1031c584SApple OSS Distributions /* power state */ fDesiredPowerState,
1761*1031c584SApple OSS Distributions /* domain flags */ 0,
1762*1031c584SApple OSS Distributions /* connection */ NULL,
1763*1031c584SApple OSS Distributions /* parent flags */ 0);
1764*1031c584SApple OSS Distributions }
1765*1031c584SApple OSS Distributions }
1766*1031c584SApple OSS Distributions
1767*1031c584SApple OSS Distributions //*********************************************************************************
1768*1031c584SApple OSS Distributions // [public] synchronizePowerTree
1769*1031c584SApple OSS Distributions //*********************************************************************************
1770*1031c584SApple OSS Distributions
1771*1031c584SApple OSS Distributions IOReturn
synchronizePowerTree(IOOptionBits options,IOService * notifyRoot)1772*1031c584SApple OSS Distributions IOService::synchronizePowerTree(
1773*1031c584SApple OSS Distributions IOOptionBits options,
1774*1031c584SApple OSS Distributions IOService * notifyRoot )
1775*1031c584SApple OSS Distributions {
1776*1031c584SApple OSS Distributions IOPMRequest * request_c = NULL;
1777*1031c584SApple OSS Distributions IOPMRequest * request_s;
1778*1031c584SApple OSS Distributions
1779*1031c584SApple OSS Distributions if (this != getPMRootDomain()) {
1780*1031c584SApple OSS Distributions return kIOReturnBadArgument;
1781*1031c584SApple OSS Distributions }
1782*1031c584SApple OSS Distributions if (!initialized) {
1783*1031c584SApple OSS Distributions return kIOPMNotYetInitialized;
1784*1031c584SApple OSS Distributions }
1785*1031c584SApple OSS Distributions
1786*1031c584SApple OSS Distributions OUR_PMLog(kPMLogCSynchronizePowerTree, options, (notifyRoot != NULL));
1787*1031c584SApple OSS Distributions
1788*1031c584SApple OSS Distributions if (notifyRoot) {
1789*1031c584SApple OSS Distributions IOPMRequest * nr;
1790*1031c584SApple OSS Distributions
1791*1031c584SApple OSS Distributions // Cancels don't need to be synchronized.
1792*1031c584SApple OSS Distributions nr = acquirePMRequest(notifyRoot, kIOPMRequestTypeChildNotifyDelayCancel);
1793*1031c584SApple OSS Distributions if (nr) {
1794*1031c584SApple OSS Distributions submitPMRequest(nr);
1795*1031c584SApple OSS Distributions }
1796*1031c584SApple OSS Distributions
1797*1031c584SApple OSS Distributions // For display wrangler or any other delay-eligible (dark wake clamped)
1798*1031c584SApple OSS Distributions // drivers attached to root domain in the power plane.
1799*1031c584SApple OSS Distributions nr = acquirePMRequest(getPMRootDomain(), kIOPMRequestTypeChildNotifyDelayCancel);
1800*1031c584SApple OSS Distributions if (nr) {
1801*1031c584SApple OSS Distributions submitPMRequest(nr);
1802*1031c584SApple OSS Distributions }
1803*1031c584SApple OSS Distributions }
1804*1031c584SApple OSS Distributions
1805*1031c584SApple OSS Distributions request_s = acquirePMRequest( this, kIOPMRequestTypeSynchronizePowerTree );
1806*1031c584SApple OSS Distributions if (!request_s) {
1807*1031c584SApple OSS Distributions goto error_no_memory;
1808*1031c584SApple OSS Distributions }
1809*1031c584SApple OSS Distributions
1810*1031c584SApple OSS Distributions if (options & kIOPMSyncCancelPowerDown) {
1811*1031c584SApple OSS Distributions request_c = acquirePMRequest( this, kIOPMRequestTypeIdleCancel );
1812*1031c584SApple OSS Distributions }
1813*1031c584SApple OSS Distributions if (request_c) {
1814*1031c584SApple OSS Distributions request_c->attachNextRequest( request_s );
1815*1031c584SApple OSS Distributions submitPMRequest(request_c);
1816*1031c584SApple OSS Distributions }
1817*1031c584SApple OSS Distributions
1818*1031c584SApple OSS Distributions request_s->fArg0 = (void *)(uintptr_t) options;
1819*1031c584SApple OSS Distributions submitPMRequest(request_s);
1820*1031c584SApple OSS Distributions
1821*1031c584SApple OSS Distributions return kIOReturnSuccess;
1822*1031c584SApple OSS Distributions
1823*1031c584SApple OSS Distributions error_no_memory:
1824*1031c584SApple OSS Distributions if (request_c) {
1825*1031c584SApple OSS Distributions releasePMRequest(request_c);
1826*1031c584SApple OSS Distributions }
1827*1031c584SApple OSS Distributions if (request_s) {
1828*1031c584SApple OSS Distributions releasePMRequest(request_s);
1829*1031c584SApple OSS Distributions }
1830*1031c584SApple OSS Distributions return kIOReturnNoMemory;
1831*1031c584SApple OSS Distributions }
1832*1031c584SApple OSS Distributions
1833*1031c584SApple OSS Distributions //*********************************************************************************
1834*1031c584SApple OSS Distributions // [private] handleSynchronizePowerTree
1835*1031c584SApple OSS Distributions //*********************************************************************************
1836*1031c584SApple OSS Distributions
1837*1031c584SApple OSS Distributions void
handleSynchronizePowerTree(IOPMRequest * request)1838*1031c584SApple OSS Distributions IOService::handleSynchronizePowerTree( IOPMRequest * request )
1839*1031c584SApple OSS Distributions {
1840*1031c584SApple OSS Distributions PM_ASSERT_IN_GATE();
1841*1031c584SApple OSS Distributions if (fControllingDriver && fParentsKnowState && inPlane(gIOPowerPlane) &&
1842*1031c584SApple OSS Distributions (fCurrentPowerState == fHighestPowerState)) {
1843*1031c584SApple OSS Distributions IOPMPowerChangeFlags options = (IOPMPowerChangeFlags)(uintptr_t) request->fArg0;
1844*1031c584SApple OSS Distributions
1845*1031c584SApple OSS Distributions startPowerChange(
1846*1031c584SApple OSS Distributions /* flags */ kIOPMSelfInitiated | kIOPMSynchronize |
1847*1031c584SApple OSS Distributions (options & kIOPMSyncNoChildNotify),
1848*1031c584SApple OSS Distributions /* power state */ fCurrentPowerState,
1849*1031c584SApple OSS Distributions /* domain flags */ 0,
1850*1031c584SApple OSS Distributions /* connection */ NULL,
1851*1031c584SApple OSS Distributions /* parent flags */ 0);
1852*1031c584SApple OSS Distributions }
1853*1031c584SApple OSS Distributions }
1854*1031c584SApple OSS Distributions
1855*1031c584SApple OSS Distributions #ifndef __LP64__
1856*1031c584SApple OSS Distributions //*********************************************************************************
1857*1031c584SApple OSS Distributions // [deprecated] powerDomainWillChangeTo
1858*1031c584SApple OSS Distributions //
1859*1031c584SApple OSS Distributions // Called by the power-hierarchy parent notifying of a new power state
1860*1031c584SApple OSS Distributions // in the power domain.
1861*1031c584SApple OSS Distributions // We enqueue a parent power-change to our queue of power changes.
1862*1031c584SApple OSS Distributions // This may or may not cause us to change power, depending on what
1863*1031c584SApple OSS Distributions // kind of change is occuring in the domain.
1864*1031c584SApple OSS Distributions //*********************************************************************************
1865*1031c584SApple OSS Distributions
1866*1031c584SApple OSS Distributions IOReturn
powerDomainWillChangeTo(IOPMPowerFlags newPowerFlags,IOPowerConnection * whichParent)1867*1031c584SApple OSS Distributions IOService::powerDomainWillChangeTo(
1868*1031c584SApple OSS Distributions IOPMPowerFlags newPowerFlags,
1869*1031c584SApple OSS Distributions IOPowerConnection * whichParent )
1870*1031c584SApple OSS Distributions {
1871*1031c584SApple OSS Distributions assert(false);
1872*1031c584SApple OSS Distributions return kIOReturnUnsupported;
1873*1031c584SApple OSS Distributions }
1874*1031c584SApple OSS Distributions #endif /* !__LP64__ */
1875*1031c584SApple OSS Distributions
1876*1031c584SApple OSS Distributions //*********************************************************************************
1877*1031c584SApple OSS Distributions // [private] handlePowerDomainWillChangeTo
1878*1031c584SApple OSS Distributions //*********************************************************************************
1879*1031c584SApple OSS Distributions
1880*1031c584SApple OSS Distributions void
handlePowerDomainWillChangeTo(IOPMRequest * request)1881*1031c584SApple OSS Distributions IOService::handlePowerDomainWillChangeTo( IOPMRequest * request )
1882*1031c584SApple OSS Distributions {
1883*1031c584SApple OSS Distributions IOPMPowerFlags parentPowerFlags = (IOPMPowerFlags) request->fArg0;
1884*1031c584SApple OSS Distributions IOPowerConnection * whichParent = (IOPowerConnection *) request->fArg1;
1885*1031c584SApple OSS Distributions IOPMPowerChangeFlags parentChangeFlags = (IOPMPowerChangeFlags)(uintptr_t) request->fArg2;
1886*1031c584SApple OSS Distributions IOPMPowerChangeFlags myChangeFlags;
1887*1031c584SApple OSS Distributions OSIterator * iter;
1888*1031c584SApple OSS Distributions OSObject * next;
1889*1031c584SApple OSS Distributions IOPowerConnection * connection;
1890*1031c584SApple OSS Distributions IOPMPowerStateIndex maxPowerState;
1891*1031c584SApple OSS Distributions IOPMPowerFlags combinedPowerFlags;
1892*1031c584SApple OSS Distributions IOReturn result = IOPMAckImplied;
1893*1031c584SApple OSS Distributions
1894*1031c584SApple OSS Distributions PM_ASSERT_IN_GATE();
1895*1031c584SApple OSS Distributions OUR_PMLog(kPMLogWillChange, parentPowerFlags, 0);
1896*1031c584SApple OSS Distributions
1897*1031c584SApple OSS Distributions if (!inPlane(gIOPowerPlane) || !whichParent || !whichParent->getAwaitingAck()) {
1898*1031c584SApple OSS Distributions PM_LOG("%s::%s not in power tree\n", getName(), __FUNCTION__);
1899*1031c584SApple OSS Distributions goto exit_no_ack;
1900*1031c584SApple OSS Distributions }
1901*1031c584SApple OSS Distributions
1902*1031c584SApple OSS Distributions // Combine parents' output power flags.
1903*1031c584SApple OSS Distributions
1904*1031c584SApple OSS Distributions combinedPowerFlags = 0;
1905*1031c584SApple OSS Distributions
1906*1031c584SApple OSS Distributions iter = getParentIterator(gIOPowerPlane);
1907*1031c584SApple OSS Distributions if (iter) {
1908*1031c584SApple OSS Distributions while ((next = iter->getNextObject())) {
1909*1031c584SApple OSS Distributions if ((connection = OSDynamicCast(IOPowerConnection, next))) {
1910*1031c584SApple OSS Distributions if (connection == whichParent) {
1911*1031c584SApple OSS Distributions combinedPowerFlags |= parentPowerFlags;
1912*1031c584SApple OSS Distributions } else {
1913*1031c584SApple OSS Distributions combinedPowerFlags |= connection->parentCurrentPowerFlags();
1914*1031c584SApple OSS Distributions }
1915*1031c584SApple OSS Distributions }
1916*1031c584SApple OSS Distributions }
1917*1031c584SApple OSS Distributions iter->release();
1918*1031c584SApple OSS Distributions }
1919*1031c584SApple OSS Distributions
1920*1031c584SApple OSS Distributions // If our initial change has yet to occur, then defer the power change
1921*1031c584SApple OSS Distributions // until after the power domain has completed its power transition.
1922*1031c584SApple OSS Distributions
1923*1031c584SApple OSS Distributions if (fControllingDriver && !fInitialPowerChange) {
1924*1031c584SApple OSS Distributions maxPowerState = fControllingDriver->maxCapabilityForDomainState(
1925*1031c584SApple OSS Distributions combinedPowerFlags);
1926*1031c584SApple OSS Distributions
1927*1031c584SApple OSS Distributions if (parentChangeFlags & kIOPMDomainPowerDrop) {
1928*1031c584SApple OSS Distributions // fMaxPowerState set a limit on self-initiated power changes.
1929*1031c584SApple OSS Distributions // Update it before a parent power drop.
1930*1031c584SApple OSS Distributions fMaxPowerState = maxPowerState;
1931*1031c584SApple OSS Distributions }
1932*1031c584SApple OSS Distributions
1933*1031c584SApple OSS Distributions // Use kIOPMSynchronize below instead of kIOPMRootBroadcastFlags
1934*1031c584SApple OSS Distributions // to avoid propagating the root change flags if any service must
1935*1031c584SApple OSS Distributions // change power state due to root's will-change notification.
1936*1031c584SApple OSS Distributions // Root does not change power state for kIOPMSynchronize.
1937*1031c584SApple OSS Distributions
1938*1031c584SApple OSS Distributions myChangeFlags = kIOPMParentInitiated | kIOPMDomainWillChange |
1939*1031c584SApple OSS Distributions (parentChangeFlags & kIOPMSynchronize);
1940*1031c584SApple OSS Distributions
1941*1031c584SApple OSS Distributions result = startPowerChange(
1942*1031c584SApple OSS Distributions /* flags */ myChangeFlags,
1943*1031c584SApple OSS Distributions /* power state */ maxPowerState,
1944*1031c584SApple OSS Distributions /* domain flags */ combinedPowerFlags,
1945*1031c584SApple OSS Distributions /* connection */ whichParent,
1946*1031c584SApple OSS Distributions /* parent flags */ parentPowerFlags);
1947*1031c584SApple OSS Distributions }
1948*1031c584SApple OSS Distributions
1949*1031c584SApple OSS Distributions // If parent is dropping power, immediately update the parent's
1950*1031c584SApple OSS Distributions // capability flags. Any future merging of parent(s) combined
1951*1031c584SApple OSS Distributions // power flags should account for this power drop.
1952*1031c584SApple OSS Distributions
1953*1031c584SApple OSS Distributions if (parentChangeFlags & kIOPMDomainPowerDrop) {
1954*1031c584SApple OSS Distributions setParentInfo(parentPowerFlags, whichParent, true);
1955*1031c584SApple OSS Distributions }
1956*1031c584SApple OSS Distributions
1957*1031c584SApple OSS Distributions // Parent is expecting an ACK from us. If we did not embark on a state
1958*1031c584SApple OSS Distributions // transition, i.e. startPowerChange() returned IOPMAckImplied. We are
1959*1031c584SApple OSS Distributions // still required to issue an ACK to our parent.
1960*1031c584SApple OSS Distributions
1961*1031c584SApple OSS Distributions if (IOPMAckImplied == result) {
1962*1031c584SApple OSS Distributions IOService * parent;
1963*1031c584SApple OSS Distributions parent = (IOService *) whichParent->copyParentEntry(gIOPowerPlane);
1964*1031c584SApple OSS Distributions assert(parent);
1965*1031c584SApple OSS Distributions if (parent) {
1966*1031c584SApple OSS Distributions parent->acknowledgePowerChange( whichParent );
1967*1031c584SApple OSS Distributions parent->release();
1968*1031c584SApple OSS Distributions }
1969*1031c584SApple OSS Distributions }
1970*1031c584SApple OSS Distributions
1971*1031c584SApple OSS Distributions exit_no_ack:
1972*1031c584SApple OSS Distributions // Drop the retain from notifyChild().
1973*1031c584SApple OSS Distributions if (whichParent) {
1974*1031c584SApple OSS Distributions whichParent->release();
1975*1031c584SApple OSS Distributions }
1976*1031c584SApple OSS Distributions }
1977*1031c584SApple OSS Distributions
1978*1031c584SApple OSS Distributions #ifndef __LP64__
1979*1031c584SApple OSS Distributions //*********************************************************************************
1980*1031c584SApple OSS Distributions // [deprecated] powerDomainDidChangeTo
1981*1031c584SApple OSS Distributions //
1982*1031c584SApple OSS Distributions // Called by the power-hierarchy parent after the power state of the power domain
1983*1031c584SApple OSS Distributions // has settled at a new level.
1984*1031c584SApple OSS Distributions // We enqueue a parent power-change to our queue of power changes.
1985*1031c584SApple OSS Distributions // This may or may not cause us to change power, depending on what
1986*1031c584SApple OSS Distributions // kind of change is occuring in the domain.
1987*1031c584SApple OSS Distributions //*********************************************************************************
1988*1031c584SApple OSS Distributions
1989*1031c584SApple OSS Distributions IOReturn
powerDomainDidChangeTo(IOPMPowerFlags newPowerFlags,IOPowerConnection * whichParent)1990*1031c584SApple OSS Distributions IOService::powerDomainDidChangeTo(
1991*1031c584SApple OSS Distributions IOPMPowerFlags newPowerFlags,
1992*1031c584SApple OSS Distributions IOPowerConnection * whichParent )
1993*1031c584SApple OSS Distributions {
1994*1031c584SApple OSS Distributions assert(false);
1995*1031c584SApple OSS Distributions return kIOReturnUnsupported;
1996*1031c584SApple OSS Distributions }
1997*1031c584SApple OSS Distributions #endif /* !__LP64__ */
1998*1031c584SApple OSS Distributions
1999*1031c584SApple OSS Distributions //*********************************************************************************
2000*1031c584SApple OSS Distributions // [private] handlePowerDomainDidChangeTo
2001*1031c584SApple OSS Distributions //*********************************************************************************
2002*1031c584SApple OSS Distributions
2003*1031c584SApple OSS Distributions void
handlePowerDomainDidChangeTo(IOPMRequest * request)2004*1031c584SApple OSS Distributions IOService::handlePowerDomainDidChangeTo( IOPMRequest * request )
2005*1031c584SApple OSS Distributions {
2006*1031c584SApple OSS Distributions IOPMPowerFlags parentPowerFlags = (IOPMPowerFlags) request->fArg0;
2007*1031c584SApple OSS Distributions IOPowerConnection * whichParent = (IOPowerConnection *) request->fArg1;
2008*1031c584SApple OSS Distributions IOPMPowerChangeFlags parentChangeFlags = (IOPMPowerChangeFlags)(uintptr_t) request->fArg2;
2009*1031c584SApple OSS Distributions IOPMPowerChangeFlags myChangeFlags;
2010*1031c584SApple OSS Distributions IOPMPowerStateIndex maxPowerState;
2011*1031c584SApple OSS Distributions IOPMPowerStateIndex initialDesire = kPowerStateZero;
2012*1031c584SApple OSS Distributions bool computeDesire = false;
2013*1031c584SApple OSS Distributions bool desireChanged = false;
2014*1031c584SApple OSS Distributions bool savedParentsKnowState;
2015*1031c584SApple OSS Distributions IOReturn result = IOPMAckImplied;
2016*1031c584SApple OSS Distributions
2017*1031c584SApple OSS Distributions PM_ASSERT_IN_GATE();
2018*1031c584SApple OSS Distributions OUR_PMLog(kPMLogDidChange, parentPowerFlags, 0);
2019*1031c584SApple OSS Distributions
2020*1031c584SApple OSS Distributions if (!inPlane(gIOPowerPlane) || !whichParent || !whichParent->getAwaitingAck()) {
2021*1031c584SApple OSS Distributions PM_LOG("%s::%s not in power tree\n", getName(), __FUNCTION__);
2022*1031c584SApple OSS Distributions goto exit_no_ack;
2023*1031c584SApple OSS Distributions }
2024*1031c584SApple OSS Distributions
2025*1031c584SApple OSS Distributions savedParentsKnowState = fParentsKnowState;
2026*1031c584SApple OSS Distributions
2027*1031c584SApple OSS Distributions setParentInfo(parentPowerFlags, whichParent, true);
2028*1031c584SApple OSS Distributions
2029*1031c584SApple OSS Distributions if (fControllingDriver) {
2030*1031c584SApple OSS Distributions maxPowerState = fControllingDriver->maxCapabilityForDomainState(
2031*1031c584SApple OSS Distributions fParentsCurrentPowerFlags);
2032*1031c584SApple OSS Distributions
2033*1031c584SApple OSS Distributions if ((parentChangeFlags & kIOPMDomainPowerDrop) == 0) {
2034*1031c584SApple OSS Distributions // fMaxPowerState set a limit on self-initiated power changes.
2035*1031c584SApple OSS Distributions // Update it after a parent power rise.
2036*1031c584SApple OSS Distributions fMaxPowerState = maxPowerState;
2037*1031c584SApple OSS Distributions }
2038*1031c584SApple OSS Distributions
2039*1031c584SApple OSS Distributions if (fInitialPowerChange) {
2040*1031c584SApple OSS Distributions computeDesire = true;
2041*1031c584SApple OSS Distributions initialDesire = fControllingDriver->initialPowerStateForDomainState(
2042*1031c584SApple OSS Distributions fParentsCurrentPowerFlags);
2043*1031c584SApple OSS Distributions } else if (parentChangeFlags & kIOPMRootChangeUp) {
2044*1031c584SApple OSS Distributions if (fAdvisoryTickleUsed) {
2045*1031c584SApple OSS Distributions // On system wake, re-compute the desired power state since
2046*1031c584SApple OSS Distributions // gIOPMAdvisoryTickleEnabled will change for a full wake,
2047*1031c584SApple OSS Distributions // which is an input to computeDesiredState(). This is not
2048*1031c584SApple OSS Distributions // necessary for a dark wake because powerChangeDone() will
2049*1031c584SApple OSS Distributions // handle the dark to full wake case, but it does no harm.
2050*1031c584SApple OSS Distributions
2051*1031c584SApple OSS Distributions desireChanged = true;
2052*1031c584SApple OSS Distributions }
2053*1031c584SApple OSS Distributions
2054*1031c584SApple OSS Distributions if (fResetPowerStateOnWake) {
2055*1031c584SApple OSS Distributions // Query the driver for the desired power state on system wake.
2056*1031c584SApple OSS Distributions // Default implementation returns the lowest power state.
2057*1031c584SApple OSS Distributions
2058*1031c584SApple OSS Distributions IOPMPowerStateIndex wakePowerState =
2059*1031c584SApple OSS Distributions fControllingDriver->initialPowerStateForDomainState(
2060*1031c584SApple OSS Distributions kIOPMRootDomainState | kIOPMPowerOn );
2061*1031c584SApple OSS Distributions
2062*1031c584SApple OSS Distributions // fDesiredPowerState was adjusted before going to sleep
2063*1031c584SApple OSS Distributions // with fDeviceDesire at min.
2064*1031c584SApple OSS Distributions
2065*1031c584SApple OSS Distributions if (StateOrder(wakePowerState) > StateOrder(fDesiredPowerState)) {
2066*1031c584SApple OSS Distributions // Must schedule a power adjustment if we changed the
2067*1031c584SApple OSS Distributions // device desire. That will update the desired domain
2068*1031c584SApple OSS Distributions // power on the parent power connection and ping the
2069*1031c584SApple OSS Distributions // power parent if necessary.
2070*1031c584SApple OSS Distributions
2071*1031c584SApple OSS Distributions updatePowerClient(gIOPMPowerClientDevice, wakePowerState);
2072*1031c584SApple OSS Distributions desireChanged = true;
2073*1031c584SApple OSS Distributions }
2074*1031c584SApple OSS Distributions }
2075*1031c584SApple OSS Distributions }
2076*1031c584SApple OSS Distributions
2077*1031c584SApple OSS Distributions if (computeDesire || desireChanged) {
2078*1031c584SApple OSS Distributions computeDesiredState(initialDesire, false);
2079*1031c584SApple OSS Distributions }
2080*1031c584SApple OSS Distributions
2081*1031c584SApple OSS Distributions // Absorb and propagate parent's broadcast flags
2082*1031c584SApple OSS Distributions myChangeFlags = kIOPMParentInitiated | kIOPMDomainDidChange |
2083*1031c584SApple OSS Distributions (parentChangeFlags & kIOPMRootBroadcastFlags);
2084*1031c584SApple OSS Distributions
2085*1031c584SApple OSS Distributions if (kIOPMAOTPower & fPowerStates[maxPowerState].inputPowerFlags) {
2086*1031c584SApple OSS Distributions IOLog("aotPS %s0x%qx[%ld]\n", getName(), getRegistryEntryID(), maxPowerState);
2087*1031c584SApple OSS Distributions }
2088*1031c584SApple OSS Distributions
2089*1031c584SApple OSS Distributions result = startPowerChange(
2090*1031c584SApple OSS Distributions /* flags */ myChangeFlags,
2091*1031c584SApple OSS Distributions /* power state */ maxPowerState,
2092*1031c584SApple OSS Distributions /* domain flags */ fParentsCurrentPowerFlags,
2093*1031c584SApple OSS Distributions /* connection */ whichParent,
2094*1031c584SApple OSS Distributions /* parent flags */ 0);
2095*1031c584SApple OSS Distributions }
2096*1031c584SApple OSS Distributions
2097*1031c584SApple OSS Distributions // Parent is expecting an ACK from us. If we did not embark on a state
2098*1031c584SApple OSS Distributions // transition, i.e. startPowerChange() returned IOPMAckImplied. We are
2099*1031c584SApple OSS Distributions // still required to issue an ACK to our parent.
2100*1031c584SApple OSS Distributions
2101*1031c584SApple OSS Distributions if (IOPMAckImplied == result) {
2102*1031c584SApple OSS Distributions IOService * parent;
2103*1031c584SApple OSS Distributions parent = (IOService *) whichParent->copyParentEntry(gIOPowerPlane);
2104*1031c584SApple OSS Distributions assert(parent);
2105*1031c584SApple OSS Distributions if (parent) {
2106*1031c584SApple OSS Distributions parent->acknowledgePowerChange( whichParent );
2107*1031c584SApple OSS Distributions parent->release();
2108*1031c584SApple OSS Distributions }
2109*1031c584SApple OSS Distributions }
2110*1031c584SApple OSS Distributions
2111*1031c584SApple OSS Distributions // If the parent registers its power driver late, then this is the
2112*1031c584SApple OSS Distributions // first opportunity to tell our parent about our desire. Or if the
2113*1031c584SApple OSS Distributions // child's desire changed during a parent change notify.
2114*1031c584SApple OSS Distributions
2115*1031c584SApple OSS Distributions if (fControllingDriver &&
2116*1031c584SApple OSS Distributions ((!savedParentsKnowState && fParentsKnowState) || desireChanged)) {
2117*1031c584SApple OSS Distributions PM_LOG1("%s::powerDomainDidChangeTo parentsKnowState %d\n",
2118*1031c584SApple OSS Distributions getName(), fParentsKnowState);
2119*1031c584SApple OSS Distributions requestDomainPower( fDesiredPowerState );
2120*1031c584SApple OSS Distributions }
2121*1031c584SApple OSS Distributions
2122*1031c584SApple OSS Distributions exit_no_ack:
2123*1031c584SApple OSS Distributions // Drop the retain from notifyChild().
2124*1031c584SApple OSS Distributions if (whichParent) {
2125*1031c584SApple OSS Distributions whichParent->release();
2126*1031c584SApple OSS Distributions }
2127*1031c584SApple OSS Distributions }
2128*1031c584SApple OSS Distributions
2129*1031c584SApple OSS Distributions //*********************************************************************************
2130*1031c584SApple OSS Distributions // [private] setParentInfo
2131*1031c584SApple OSS Distributions //
2132*1031c584SApple OSS Distributions // Set our connection data for one specific parent, and then combine all the parent
2133*1031c584SApple OSS Distributions // data together.
2134*1031c584SApple OSS Distributions //*********************************************************************************
2135*1031c584SApple OSS Distributions
2136*1031c584SApple OSS Distributions void
setParentInfo(IOPMPowerFlags newPowerFlags,IOPowerConnection * whichParent,bool knowsState)2137*1031c584SApple OSS Distributions IOService::setParentInfo(
2138*1031c584SApple OSS Distributions IOPMPowerFlags newPowerFlags,
2139*1031c584SApple OSS Distributions IOPowerConnection * whichParent,
2140*1031c584SApple OSS Distributions bool knowsState )
2141*1031c584SApple OSS Distributions {
2142*1031c584SApple OSS Distributions OSIterator * iter;
2143*1031c584SApple OSS Distributions OSObject * next;
2144*1031c584SApple OSS Distributions IOPowerConnection * conn;
2145*1031c584SApple OSS Distributions
2146*1031c584SApple OSS Distributions PM_ASSERT_IN_GATE();
2147*1031c584SApple OSS Distributions
2148*1031c584SApple OSS Distributions // set our connection data
2149*1031c584SApple OSS Distributions whichParent->setParentCurrentPowerFlags(newPowerFlags);
2150*1031c584SApple OSS Distributions whichParent->setParentKnowsState(knowsState);
2151*1031c584SApple OSS Distributions
2152*1031c584SApple OSS Distributions // recompute our parent info
2153*1031c584SApple OSS Distributions fParentsCurrentPowerFlags = 0;
2154*1031c584SApple OSS Distributions fParentsKnowState = true;
2155*1031c584SApple OSS Distributions
2156*1031c584SApple OSS Distributions iter = getParentIterator(gIOPowerPlane);
2157*1031c584SApple OSS Distributions if (iter) {
2158*1031c584SApple OSS Distributions while ((next = iter->getNextObject())) {
2159*1031c584SApple OSS Distributions if ((conn = OSDynamicCast(IOPowerConnection, next))) {
2160*1031c584SApple OSS Distributions fParentsKnowState &= conn->parentKnowsState();
2161*1031c584SApple OSS Distributions fParentsCurrentPowerFlags |= conn->parentCurrentPowerFlags();
2162*1031c584SApple OSS Distributions }
2163*1031c584SApple OSS Distributions }
2164*1031c584SApple OSS Distributions iter->release();
2165*1031c584SApple OSS Distributions }
2166*1031c584SApple OSS Distributions }
2167*1031c584SApple OSS Distributions
2168*1031c584SApple OSS Distributions //******************************************************************************
2169*1031c584SApple OSS Distributions // [private] trackSystemSleepPreventers
2170*1031c584SApple OSS Distributions //******************************************************************************
2171*1031c584SApple OSS Distributions
2172*1031c584SApple OSS Distributions void
trackSystemSleepPreventers(IOPMPowerStateIndex oldPowerState,IOPMPowerStateIndex newPowerState,IOPMPowerChangeFlags changeFlags __unused)2173*1031c584SApple OSS Distributions IOService::trackSystemSleepPreventers(
2174*1031c584SApple OSS Distributions IOPMPowerStateIndex oldPowerState,
2175*1031c584SApple OSS Distributions IOPMPowerStateIndex newPowerState,
2176*1031c584SApple OSS Distributions IOPMPowerChangeFlags changeFlags __unused )
2177*1031c584SApple OSS Distributions {
2178*1031c584SApple OSS Distributions IOPMPowerFlags oldCapability, newCapability;
2179*1031c584SApple OSS Distributions
2180*1031c584SApple OSS Distributions oldCapability = fPowerStates[oldPowerState].capabilityFlags &
2181*1031c584SApple OSS Distributions (kIOPMPreventIdleSleep | kIOPMPreventSystemSleep);
2182*1031c584SApple OSS Distributions newCapability = fPowerStates[newPowerState].capabilityFlags &
2183*1031c584SApple OSS Distributions (kIOPMPreventIdleSleep | kIOPMPreventSystemSleep);
2184*1031c584SApple OSS Distributions
2185*1031c584SApple OSS Distributions if (fHeadNoteChangeFlags & kIOPMInitialPowerChange) {
2186*1031c584SApple OSS Distributions oldCapability = 0;
2187*1031c584SApple OSS Distributions }
2188*1031c584SApple OSS Distributions if (oldCapability == newCapability) {
2189*1031c584SApple OSS Distributions return;
2190*1031c584SApple OSS Distributions }
2191*1031c584SApple OSS Distributions
2192*1031c584SApple OSS Distributions if ((oldCapability ^ newCapability) & kIOPMPreventIdleSleep) {
2193*1031c584SApple OSS Distributions bool enablePrevention = ((oldCapability & kIOPMPreventIdleSleep) == 0);
2194*1031c584SApple OSS Distributions bool idleCancelAllowed = getPMRootDomain()->updatePreventIdleSleepList(
2195*1031c584SApple OSS Distributions this, enablePrevention);
2196*1031c584SApple OSS Distributions #if SUPPORT_IDLE_CANCEL
2197*1031c584SApple OSS Distributions if (idleCancelAllowed && enablePrevention) {
2198*1031c584SApple OSS Distributions IOPMRequest * cancelRequest;
2199*1031c584SApple OSS Distributions
2200*1031c584SApple OSS Distributions cancelRequest = acquirePMRequest( getPMRootDomain(), kIOPMRequestTypeIdleCancel );
2201*1031c584SApple OSS Distributions if (cancelRequest) {
2202*1031c584SApple OSS Distributions submitPMRequest( cancelRequest );
2203*1031c584SApple OSS Distributions }
2204*1031c584SApple OSS Distributions }
2205*1031c584SApple OSS Distributions #endif
2206*1031c584SApple OSS Distributions }
2207*1031c584SApple OSS Distributions
2208*1031c584SApple OSS Distributions if ((oldCapability ^ newCapability) & kIOPMPreventSystemSleep) {
2209*1031c584SApple OSS Distributions getPMRootDomain()->updatePreventSystemSleepList(this,
2210*1031c584SApple OSS Distributions ((oldCapability & kIOPMPreventSystemSleep) == 0));
2211*1031c584SApple OSS Distributions }
2212*1031c584SApple OSS Distributions }
2213*1031c584SApple OSS Distributions
2214*1031c584SApple OSS Distributions //*********************************************************************************
2215*1031c584SApple OSS Distributions // [public] requestPowerDomainState
2216*1031c584SApple OSS Distributions //
2217*1031c584SApple OSS Distributions // Called on a power parent when a child's power requirement changes.
2218*1031c584SApple OSS Distributions //*********************************************************************************
2219*1031c584SApple OSS Distributions
2220*1031c584SApple OSS Distributions IOReturn
requestPowerDomainState(IOPMPowerFlags childRequestPowerFlags,IOPowerConnection * childConnection,unsigned long specification)2221*1031c584SApple OSS Distributions IOService::requestPowerDomainState(
2222*1031c584SApple OSS Distributions IOPMPowerFlags childRequestPowerFlags,
2223*1031c584SApple OSS Distributions IOPowerConnection * childConnection,
2224*1031c584SApple OSS Distributions unsigned long specification )
2225*1031c584SApple OSS Distributions {
2226*1031c584SApple OSS Distributions IOPMPowerStateIndex order, powerState;
2227*1031c584SApple OSS Distributions IOPMPowerFlags outputPowerFlags;
2228*1031c584SApple OSS Distributions IOService * child;
2229*1031c584SApple OSS Distributions IOPMRequest * subRequest;
2230*1031c584SApple OSS Distributions bool adjustPower = false;
2231*1031c584SApple OSS Distributions
2232*1031c584SApple OSS Distributions if (!initialized) {
2233*1031c584SApple OSS Distributions return IOPMNotYetInitialized;
2234*1031c584SApple OSS Distributions }
2235*1031c584SApple OSS Distributions
2236*1031c584SApple OSS Distributions if (gIOPMWorkLoop->onThread() == false) {
2237*1031c584SApple OSS Distributions PM_LOG("%s::requestPowerDomainState\n", getName());
2238*1031c584SApple OSS Distributions return kIOReturnSuccess;
2239*1031c584SApple OSS Distributions }
2240*1031c584SApple OSS Distributions
2241*1031c584SApple OSS Distributions OUR_PMLog(kPMLogRequestDomain, childRequestPowerFlags, specification);
2242*1031c584SApple OSS Distributions
2243*1031c584SApple OSS Distributions if (!isChild(childConnection, gIOPowerPlane)) {
2244*1031c584SApple OSS Distributions return kIOReturnNotAttached;
2245*1031c584SApple OSS Distributions }
2246*1031c584SApple OSS Distributions
2247*1031c584SApple OSS Distributions if (!fControllingDriver || !fNumberOfPowerStates) {
2248*1031c584SApple OSS Distributions return kIOReturnNotReady;
2249*1031c584SApple OSS Distributions }
2250*1031c584SApple OSS Distributions
2251*1031c584SApple OSS Distributions child = (IOService *) childConnection->getChildEntry(gIOPowerPlane);
2252*1031c584SApple OSS Distributions assert(child);
2253*1031c584SApple OSS Distributions
2254*1031c584SApple OSS Distributions // Remove flags from child request which we can't possibly supply
2255*1031c584SApple OSS Distributions childRequestPowerFlags &= fMergedOutputPowerFlags;
2256*1031c584SApple OSS Distributions
2257*1031c584SApple OSS Distributions // Merge in the power flags contributed by this power parent
2258*1031c584SApple OSS Distributions // at its current or impending power state.
2259*1031c584SApple OSS Distributions
2260*1031c584SApple OSS Distributions outputPowerFlags = fPowerStates[fCurrentPowerState].outputPowerFlags;
2261*1031c584SApple OSS Distributions if (fMachineState != kIOPM_Finished) {
2262*1031c584SApple OSS Distributions if (IS_POWER_DROP && !IS_ROOT_DOMAIN) {
2263*1031c584SApple OSS Distributions // Use the lower power state when dropping power.
2264*1031c584SApple OSS Distributions // Must be careful since a power drop can be cancelled
2265*1031c584SApple OSS Distributions // from the following states:
2266*1031c584SApple OSS Distributions // - kIOPM_OurChangeTellClientsPowerDown
2267*1031c584SApple OSS Distributions // - kIOPM_OurChangeTellPriorityClientsPowerDown
2268*1031c584SApple OSS Distributions //
2269*1031c584SApple OSS Distributions // The child must not wait for this parent to raise power
2270*1031c584SApple OSS Distributions // if the power drop was cancelled. The solution is to cancel
2271*1031c584SApple OSS Distributions // the power drop if possible, then schedule an adjustment to
2272*1031c584SApple OSS Distributions // re-evaluate the parent's power state.
2273*1031c584SApple OSS Distributions //
2274*1031c584SApple OSS Distributions // Root domain is excluded to avoid idle sleep issues. And allow
2275*1031c584SApple OSS Distributions // root domain children to pop up when system is going to sleep.
2276*1031c584SApple OSS Distributions
2277*1031c584SApple OSS Distributions if ((fMachineState == kIOPM_OurChangeTellClientsPowerDown) ||
2278*1031c584SApple OSS Distributions (fMachineState == kIOPM_OurChangeTellPriorityClientsPowerDown)) {
2279*1031c584SApple OSS Distributions fDoNotPowerDown = true; // cancel power drop
2280*1031c584SApple OSS Distributions adjustPower = true;// schedule an adjustment
2281*1031c584SApple OSS Distributions PM_LOG1("%s: power drop cancelled in state %u by %s\n",
2282*1031c584SApple OSS Distributions getName(), fMachineState, child->getName());
2283*1031c584SApple OSS Distributions } else {
2284*1031c584SApple OSS Distributions // Beyond cancellation point, report the impending state.
2285*1031c584SApple OSS Distributions outputPowerFlags =
2286*1031c584SApple OSS Distributions fPowerStates[fHeadNotePowerState].outputPowerFlags;
2287*1031c584SApple OSS Distributions }
2288*1031c584SApple OSS Distributions } else if (IS_POWER_RISE) {
2289*1031c584SApple OSS Distributions // When raising power, must report the output power flags from
2290*1031c584SApple OSS Distributions // child's perspective. A child power request may arrive while
2291*1031c584SApple OSS Distributions // parent is transitioning upwards. If a request arrives after
2292*1031c584SApple OSS Distributions // setParentInfo() has already recorded the output power flags
2293*1031c584SApple OSS Distributions // for the next power state, then using the power supplied by
2294*1031c584SApple OSS Distributions // fCurrentPowerState is incorrect, and might cause the child
2295*1031c584SApple OSS Distributions // to wait when it should not.
2296*1031c584SApple OSS Distributions
2297*1031c584SApple OSS Distributions outputPowerFlags = childConnection->parentCurrentPowerFlags();
2298*1031c584SApple OSS Distributions }
2299*1031c584SApple OSS Distributions }
2300*1031c584SApple OSS Distributions child->fHeadNoteDomainTargetFlags |= outputPowerFlags;
2301*1031c584SApple OSS Distributions
2302*1031c584SApple OSS Distributions // Map child's requested power flags to one of our power state.
2303*1031c584SApple OSS Distributions
2304*1031c584SApple OSS Distributions for (order = 0; order < fNumberOfPowerStates; order++) {
2305*1031c584SApple OSS Distributions powerState = fPowerStates[order].stateOrderToIndex;
2306*1031c584SApple OSS Distributions if ((fPowerStates[powerState].outputPowerFlags & childRequestPowerFlags)
2307*1031c584SApple OSS Distributions == childRequestPowerFlags) {
2308*1031c584SApple OSS Distributions break;
2309*1031c584SApple OSS Distributions }
2310*1031c584SApple OSS Distributions }
2311*1031c584SApple OSS Distributions if (order >= fNumberOfPowerStates) {
2312*1031c584SApple OSS Distributions powerState = kPowerStateZero;
2313*1031c584SApple OSS Distributions }
2314*1031c584SApple OSS Distributions
2315*1031c584SApple OSS Distributions // Conditions that warrants a power adjustment on this parent.
2316*1031c584SApple OSS Distributions // Adjust power will also propagate any changes to the child's
2317*1031c584SApple OSS Distributions // prevent idle/sleep flags towards the root domain.
2318*1031c584SApple OSS Distributions
2319*1031c584SApple OSS Distributions if (!childConnection->childHasRequestedPower() ||
2320*1031c584SApple OSS Distributions (powerState != childConnection->getDesiredDomainState())) {
2321*1031c584SApple OSS Distributions adjustPower = true;
2322*1031c584SApple OSS Distributions }
2323*1031c584SApple OSS Distributions
2324*1031c584SApple OSS Distributions #if ENABLE_DEBUG_LOGS
2325*1031c584SApple OSS Distributions if (adjustPower) {
2326*1031c584SApple OSS Distributions PM_LOG("requestPowerDomainState[%s]: %s, init %d, %u->%u\n",
2327*1031c584SApple OSS Distributions getName(), child->getName(),
2328*1031c584SApple OSS Distributions !childConnection->childHasRequestedPower(),
2329*1031c584SApple OSS Distributions (uint32_t) childConnection->getDesiredDomainState(),
2330*1031c584SApple OSS Distributions (uint32_t) powerState);
2331*1031c584SApple OSS Distributions }
2332*1031c584SApple OSS Distributions #endif
2333*1031c584SApple OSS Distributions
2334*1031c584SApple OSS Distributions // Record the child's desires on the connection.
2335*1031c584SApple OSS Distributions childConnection->setChildHasRequestedPower();
2336*1031c584SApple OSS Distributions childConnection->setDesiredDomainState( powerState );
2337*1031c584SApple OSS Distributions
2338*1031c584SApple OSS Distributions // Schedule a request to re-evaluate all children desires and
2339*1031c584SApple OSS Distributions // adjust power state. Submit a request if one wasn't pending,
2340*1031c584SApple OSS Distributions // or if the current request is part of a call tree.
2341*1031c584SApple OSS Distributions
2342*1031c584SApple OSS Distributions if (adjustPower && !fDeviceOverrideEnabled &&
2343*1031c584SApple OSS Distributions (!fAdjustPowerScheduled || gIOPMRequest->getRootRequest())) {
2344*1031c584SApple OSS Distributions subRequest = acquirePMRequest(
2345*1031c584SApple OSS Distributions this, kIOPMRequestTypeAdjustPowerState, gIOPMRequest );
2346*1031c584SApple OSS Distributions if (subRequest) {
2347*1031c584SApple OSS Distributions submitPMRequest( subRequest );
2348*1031c584SApple OSS Distributions fAdjustPowerScheduled = true;
2349*1031c584SApple OSS Distributions }
2350*1031c584SApple OSS Distributions }
2351*1031c584SApple OSS Distributions
2352*1031c584SApple OSS Distributions return kIOReturnSuccess;
2353*1031c584SApple OSS Distributions }
2354*1031c584SApple OSS Distributions
2355*1031c584SApple OSS Distributions //*********************************************************************************
2356*1031c584SApple OSS Distributions // [public] temporaryPowerClampOn
2357*1031c584SApple OSS Distributions //
2358*1031c584SApple OSS Distributions // A power domain wants to be clamped to max power until it has children which
2359*1031c584SApple OSS Distributions // will then determine the power domain state.
2360*1031c584SApple OSS Distributions //
2361*1031c584SApple OSS Distributions // We enter the highest state until addPowerChild is called.
2362*1031c584SApple OSS Distributions //*********************************************************************************
2363*1031c584SApple OSS Distributions
2364*1031c584SApple OSS Distributions IOReturn
temporaryPowerClampOn(void)2365*1031c584SApple OSS Distributions IOService::temporaryPowerClampOn( void )
2366*1031c584SApple OSS Distributions {
2367*1031c584SApple OSS Distributions return requestPowerState( gIOPMPowerClientChildProxy, kIOPMPowerStateMax );
2368*1031c584SApple OSS Distributions }
2369*1031c584SApple OSS Distributions
2370*1031c584SApple OSS Distributions //*********************************************************************************
2371*1031c584SApple OSS Distributions // [public] makeUsable
2372*1031c584SApple OSS Distributions //
2373*1031c584SApple OSS Distributions // Some client of our device is asking that we become usable. Although
2374*1031c584SApple OSS Distributions // this has not come from a subclassed device object, treat it exactly
2375*1031c584SApple OSS Distributions // as if it had. In this way, subsequent requests for lower power from
2376*1031c584SApple OSS Distributions // a subclassed device object will pre-empt this request.
2377*1031c584SApple OSS Distributions //
2378*1031c584SApple OSS Distributions // We treat this as a subclass object request to switch to the
2379*1031c584SApple OSS Distributions // highest power state.
2380*1031c584SApple OSS Distributions //*********************************************************************************
2381*1031c584SApple OSS Distributions
2382*1031c584SApple OSS Distributions IOReturn
makeUsable(void)2383*1031c584SApple OSS Distributions IOService::makeUsable( void )
2384*1031c584SApple OSS Distributions {
2385*1031c584SApple OSS Distributions OUR_PMLog(kPMLogMakeUsable, 0, 0);
2386*1031c584SApple OSS Distributions return requestPowerState( gIOPMPowerClientDevice, kIOPMPowerStateMax );
2387*1031c584SApple OSS Distributions }
2388*1031c584SApple OSS Distributions
2389*1031c584SApple OSS Distributions //*********************************************************************************
2390*1031c584SApple OSS Distributions // [public] currentCapability
2391*1031c584SApple OSS Distributions //*********************************************************************************
2392*1031c584SApple OSS Distributions
2393*1031c584SApple OSS Distributions IOPMPowerFlags
currentCapability(void)2394*1031c584SApple OSS Distributions IOService::currentCapability( void )
2395*1031c584SApple OSS Distributions {
2396*1031c584SApple OSS Distributions if (!initialized) {
2397*1031c584SApple OSS Distributions return IOPMNotPowerManaged;
2398*1031c584SApple OSS Distributions }
2399*1031c584SApple OSS Distributions
2400*1031c584SApple OSS Distributions return fCurrentCapabilityFlags;
2401*1031c584SApple OSS Distributions }
2402*1031c584SApple OSS Distributions
2403*1031c584SApple OSS Distributions //*********************************************************************************
2404*1031c584SApple OSS Distributions // [public] changePowerStateTo
2405*1031c584SApple OSS Distributions //
2406*1031c584SApple OSS Distributions // Called by our power-controlling driver to change power state. The new desired
2407*1031c584SApple OSS Distributions // power state is computed and compared against the current power state. If those
2408*1031c584SApple OSS Distributions // power states differ, then a power state change is initiated.
2409*1031c584SApple OSS Distributions //*********************************************************************************
2410*1031c584SApple OSS Distributions
2411*1031c584SApple OSS Distributions IOReturn
changePowerStateTo(unsigned long ordinal)2412*1031c584SApple OSS Distributions IOService::changePowerStateTo( unsigned long ordinal )
2413*1031c584SApple OSS Distributions {
2414*1031c584SApple OSS Distributions OUR_PMLog(kPMLogChangeStateTo, ordinal, 0);
2415*1031c584SApple OSS Distributions return requestPowerState( gIOPMPowerClientDriver, ordinal );
2416*1031c584SApple OSS Distributions }
2417*1031c584SApple OSS Distributions
2418*1031c584SApple OSS Distributions //*********************************************************************************
2419*1031c584SApple OSS Distributions // [protected] changePowerStateToPriv
2420*1031c584SApple OSS Distributions //
2421*1031c584SApple OSS Distributions // Called by our driver subclass to change power state. The new desired power
2422*1031c584SApple OSS Distributions // state is computed and compared against the current power state. If those
2423*1031c584SApple OSS Distributions // power states differ, then a power state change is initiated.
2424*1031c584SApple OSS Distributions //*********************************************************************************
2425*1031c584SApple OSS Distributions
2426*1031c584SApple OSS Distributions IOReturn
changePowerStateToPriv(unsigned long ordinal)2427*1031c584SApple OSS Distributions IOService::changePowerStateToPriv( unsigned long ordinal )
2428*1031c584SApple OSS Distributions {
2429*1031c584SApple OSS Distributions OUR_PMLog(kPMLogChangeStateToPriv, ordinal, 0);
2430*1031c584SApple OSS Distributions return requestPowerState( gIOPMPowerClientDevice, ordinal );
2431*1031c584SApple OSS Distributions }
2432*1031c584SApple OSS Distributions
2433*1031c584SApple OSS Distributions //*********************************************************************************
2434*1031c584SApple OSS Distributions // [public] changePowerStateWithOverrideTo
2435*1031c584SApple OSS Distributions //
2436*1031c584SApple OSS Distributions // Called by our driver subclass to change power state. The new desired power
2437*1031c584SApple OSS Distributions // state is computed and compared against the current power state. If those
2438*1031c584SApple OSS Distributions // power states differ, then a power state change is initiated.
2439*1031c584SApple OSS Distributions // Override enforced - Children and Driver desires are ignored.
2440*1031c584SApple OSS Distributions //*********************************************************************************
2441*1031c584SApple OSS Distributions
2442*1031c584SApple OSS Distributions IOReturn
changePowerStateWithOverrideTo(IOPMPowerStateIndex ordinal,IOPMRequestTag tag)2443*1031c584SApple OSS Distributions IOService::changePowerStateWithOverrideTo( IOPMPowerStateIndex ordinal,
2444*1031c584SApple OSS Distributions IOPMRequestTag tag )
2445*1031c584SApple OSS Distributions {
2446*1031c584SApple OSS Distributions IOPMRequest * request;
2447*1031c584SApple OSS Distributions
2448*1031c584SApple OSS Distributions if (!initialized) {
2449*1031c584SApple OSS Distributions return kIOPMNotYetInitialized;
2450*1031c584SApple OSS Distributions }
2451*1031c584SApple OSS Distributions
2452*1031c584SApple OSS Distributions OUR_PMLog(kPMLogChangeStateToPriv, ordinal, 0);
2453*1031c584SApple OSS Distributions
2454*1031c584SApple OSS Distributions request = acquirePMRequest( this, kIOPMRequestTypeRequestPowerStateOverride );
2455*1031c584SApple OSS Distributions if (!request) {
2456*1031c584SApple OSS Distributions return kIOReturnNoMemory;
2457*1031c584SApple OSS Distributions }
2458*1031c584SApple OSS Distributions
2459*1031c584SApple OSS Distributions gIOPMPowerClientDevice->retain();
2460*1031c584SApple OSS Distributions request->fTag = tag;
2461*1031c584SApple OSS Distributions request->fArg0 = (void *) ordinal;
2462*1031c584SApple OSS Distributions request->fArg1 = (void *) gIOPMPowerClientDevice;
2463*1031c584SApple OSS Distributions request->fArg2 = NULL;
2464*1031c584SApple OSS Distributions #if NOT_READY
2465*1031c584SApple OSS Distributions if (action) {
2466*1031c584SApple OSS Distributions request->installCompletionAction( action, target, param );
2467*1031c584SApple OSS Distributions }
2468*1031c584SApple OSS Distributions #endif
2469*1031c584SApple OSS Distributions
2470*1031c584SApple OSS Distributions // Prevent needless downwards power transitions by clamping power
2471*1031c584SApple OSS Distributions // until the scheduled request is executed.
2472*1031c584SApple OSS Distributions //
2473*1031c584SApple OSS Distributions // TODO: review fOverrideMaxPowerState
2474*1031c584SApple OSS Distributions
2475*1031c584SApple OSS Distributions if (gIOPMWorkLoop->inGate() && (ordinal < fNumberOfPowerStates)) {
2476*1031c584SApple OSS Distributions fTempClampPowerState = StateMax(fTempClampPowerState, ordinal);
2477*1031c584SApple OSS Distributions fTempClampCount++;
2478*1031c584SApple OSS Distributions request->fArg2 = (void *)(uintptr_t) true;
2479*1031c584SApple OSS Distributions
2480*1031c584SApple OSS Distributions // Place a power state ceiling to prevent any transition to a
2481*1031c584SApple OSS Distributions // power state higher than fOverrideMaxPowerState.
2482*1031c584SApple OSS Distributions fOverrideMaxPowerState = ordinal;
2483*1031c584SApple OSS Distributions }
2484*1031c584SApple OSS Distributions
2485*1031c584SApple OSS Distributions submitPMRequest( request );
2486*1031c584SApple OSS Distributions return IOPMNoErr;
2487*1031c584SApple OSS Distributions }
2488*1031c584SApple OSS Distributions
2489*1031c584SApple OSS Distributions //*********************************************************************************
2490*1031c584SApple OSS Distributions // Tagged form of changePowerStateTo()
2491*1031c584SApple OSS Distributions //*********************************************************************************
2492*1031c584SApple OSS Distributions
2493*1031c584SApple OSS Distributions IOReturn
changePowerStateWithTagTo(IOPMPowerStateIndex ordinal,IOPMRequestTag tag)2494*1031c584SApple OSS Distributions IOService::changePowerStateWithTagTo( IOPMPowerStateIndex ordinal, IOPMRequestTag tag )
2495*1031c584SApple OSS Distributions {
2496*1031c584SApple OSS Distributions OUR_PMLog(kPMLogChangeStateTo, ordinal, tag);
2497*1031c584SApple OSS Distributions return requestPowerState(gIOPMPowerClientDriver, ordinal, tag);
2498*1031c584SApple OSS Distributions }
2499*1031c584SApple OSS Distributions
2500*1031c584SApple OSS Distributions //*********************************************************************************
2501*1031c584SApple OSS Distributions // Tagged form of changePowerStateToPriv()
2502*1031c584SApple OSS Distributions //*********************************************************************************
2503*1031c584SApple OSS Distributions
2504*1031c584SApple OSS Distributions IOReturn
changePowerStateWithTagToPriv(unsigned long ordinal,IOPMRequestTag tag)2505*1031c584SApple OSS Distributions IOService::changePowerStateWithTagToPriv( unsigned long ordinal, IOPMRequestTag tag )
2506*1031c584SApple OSS Distributions {
2507*1031c584SApple OSS Distributions OUR_PMLog(kPMLogChangeStateToPriv, ordinal, tag);
2508*1031c584SApple OSS Distributions return requestPowerState(gIOPMPowerClientDevice, ordinal, tag);
2509*1031c584SApple OSS Distributions }
2510*1031c584SApple OSS Distributions
2511*1031c584SApple OSS Distributions //*********************************************************************************
2512*1031c584SApple OSS Distributions // [public] changePowerStateForRootDomain
2513*1031c584SApple OSS Distributions //
2514*1031c584SApple OSS Distributions // Adjust the root domain's power desire on the target
2515*1031c584SApple OSS Distributions //*********************************************************************************
2516*1031c584SApple OSS Distributions
2517*1031c584SApple OSS Distributions IOReturn
changePowerStateForRootDomain(IOPMPowerStateIndex ordinal)2518*1031c584SApple OSS Distributions IOService::changePowerStateForRootDomain( IOPMPowerStateIndex ordinal )
2519*1031c584SApple OSS Distributions {
2520*1031c584SApple OSS Distributions OUR_PMLog(kPMLogChangeStateForRootDomain, ordinal, 0);
2521*1031c584SApple OSS Distributions return requestPowerState( gIOPMPowerClientRootDomain, ordinal );
2522*1031c584SApple OSS Distributions }
2523*1031c584SApple OSS Distributions
2524*1031c584SApple OSS Distributions //*********************************************************************************
2525*1031c584SApple OSS Distributions // [public for PMRD] quiescePowerTree
2526*1031c584SApple OSS Distributions //
2527*1031c584SApple OSS Distributions // For root domain to issue a request to quiesce the power tree.
2528*1031c584SApple OSS Distributions // Supplied callback invoked upon completion.
2529*1031c584SApple OSS Distributions //*********************************************************************************
2530*1031c584SApple OSS Distributions
2531*1031c584SApple OSS Distributions IOReturn
quiescePowerTree(void * target,IOPMCompletionAction action,void * param)2532*1031c584SApple OSS Distributions IOService::quiescePowerTree(
2533*1031c584SApple OSS Distributions void * target, IOPMCompletionAction action, void * param )
2534*1031c584SApple OSS Distributions {
2535*1031c584SApple OSS Distributions IOPMRequest * request;
2536*1031c584SApple OSS Distributions
2537*1031c584SApple OSS Distributions if (!initialized) {
2538*1031c584SApple OSS Distributions return kIOPMNotYetInitialized;
2539*1031c584SApple OSS Distributions }
2540*1031c584SApple OSS Distributions if (!target || !action) {
2541*1031c584SApple OSS Distributions return kIOReturnBadArgument;
2542*1031c584SApple OSS Distributions }
2543*1031c584SApple OSS Distributions
2544*1031c584SApple OSS Distributions OUR_PMLog(kPMLogQuiescePowerTree, 0, 0);
2545*1031c584SApple OSS Distributions
2546*1031c584SApple OSS Distributions // Target the root node instead of root domain. This is to avoid blocking
2547*1031c584SApple OSS Distributions // the quiesce request behind an existing root domain request in the work
2548*1031c584SApple OSS Distributions // queue. Root parent and root domain requests in the work queue must not
2549*1031c584SApple OSS Distributions // block the completion of the quiesce request.
2550*1031c584SApple OSS Distributions
2551*1031c584SApple OSS Distributions request = acquirePMRequest(gIOPMRootNode, kIOPMRequestTypeQuiescePowerTree);
2552*1031c584SApple OSS Distributions if (!request) {
2553*1031c584SApple OSS Distributions return kIOReturnNoMemory;
2554*1031c584SApple OSS Distributions }
2555*1031c584SApple OSS Distributions
2556*1031c584SApple OSS Distributions request->installCompletionAction(target, action, param);
2557*1031c584SApple OSS Distributions
2558*1031c584SApple OSS Distributions // Submit through the normal request flow. This will make sure any request
2559*1031c584SApple OSS Distributions // already in the request queue will get pushed over to the work queue for
2560*1031c584SApple OSS Distributions // execution. Any request submitted after this request may not be serviced.
2561*1031c584SApple OSS Distributions
2562*1031c584SApple OSS Distributions submitPMRequest( request );
2563*1031c584SApple OSS Distributions return kIOReturnSuccess;
2564*1031c584SApple OSS Distributions }
2565*1031c584SApple OSS Distributions
2566*1031c584SApple OSS Distributions //*********************************************************************************
2567*1031c584SApple OSS Distributions // [private] requestPowerState
2568*1031c584SApple OSS Distributions //*********************************************************************************
2569*1031c584SApple OSS Distributions
2570*1031c584SApple OSS Distributions IOReturn
requestPowerState(const OSSymbol * client,IOPMPowerStateIndex state,IOPMRequestTag tag)2571*1031c584SApple OSS Distributions IOService::requestPowerState(
2572*1031c584SApple OSS Distributions const OSSymbol * client,
2573*1031c584SApple OSS Distributions IOPMPowerStateIndex state,
2574*1031c584SApple OSS Distributions IOPMRequestTag tag )
2575*1031c584SApple OSS Distributions {
2576*1031c584SApple OSS Distributions IOPMRequest * request;
2577*1031c584SApple OSS Distributions
2578*1031c584SApple OSS Distributions if (!client || (state > UINT_MAX)) {
2579*1031c584SApple OSS Distributions return kIOReturnBadArgument;
2580*1031c584SApple OSS Distributions }
2581*1031c584SApple OSS Distributions if (!initialized) {
2582*1031c584SApple OSS Distributions return kIOPMNotYetInitialized;
2583*1031c584SApple OSS Distributions }
2584*1031c584SApple OSS Distributions
2585*1031c584SApple OSS Distributions request = acquirePMRequest( this, kIOPMRequestTypeRequestPowerState );
2586*1031c584SApple OSS Distributions if (!request) {
2587*1031c584SApple OSS Distributions return kIOReturnNoMemory;
2588*1031c584SApple OSS Distributions }
2589*1031c584SApple OSS Distributions
2590*1031c584SApple OSS Distributions client->retain();
2591*1031c584SApple OSS Distributions request->fTag = tag;
2592*1031c584SApple OSS Distributions request->fArg0 = (void *)(uintptr_t) state;
2593*1031c584SApple OSS Distributions request->fArg1 = (void *) client;
2594*1031c584SApple OSS Distributions request->fArg2 = NULL;
2595*1031c584SApple OSS Distributions #if NOT_READY
2596*1031c584SApple OSS Distributions if (action) {
2597*1031c584SApple OSS Distributions request->installCompletionAction( action, target, param );
2598*1031c584SApple OSS Distributions }
2599*1031c584SApple OSS Distributions #endif
2600*1031c584SApple OSS Distributions
2601*1031c584SApple OSS Distributions // Prevent needless downwards power transitions by clamping power
2602*1031c584SApple OSS Distributions // until the scheduled request is executed.
2603*1031c584SApple OSS Distributions
2604*1031c584SApple OSS Distributions if (gIOPMWorkLoop->inGate() && (state < fNumberOfPowerStates)) {
2605*1031c584SApple OSS Distributions fTempClampPowerState = StateMax(fTempClampPowerState, state);
2606*1031c584SApple OSS Distributions fTempClampCount++;
2607*1031c584SApple OSS Distributions request->fArg2 = (void *)(uintptr_t) true;
2608*1031c584SApple OSS Distributions }
2609*1031c584SApple OSS Distributions
2610*1031c584SApple OSS Distributions submitPMRequest( request );
2611*1031c584SApple OSS Distributions return IOPMNoErr;
2612*1031c584SApple OSS Distributions }
2613*1031c584SApple OSS Distributions
2614*1031c584SApple OSS Distributions //*********************************************************************************
2615*1031c584SApple OSS Distributions // [private] handleRequestPowerState
2616*1031c584SApple OSS Distributions //*********************************************************************************
2617*1031c584SApple OSS Distributions
2618*1031c584SApple OSS Distributions void
handleRequestPowerState(IOPMRequest * request)2619*1031c584SApple OSS Distributions IOService::handleRequestPowerState( IOPMRequest * request )
2620*1031c584SApple OSS Distributions {
2621*1031c584SApple OSS Distributions const OSSymbol * client = (const OSSymbol *) request->fArg1;
2622*1031c584SApple OSS Distributions IOPMPowerStateIndex state = (IOPMPowerStateIndex) request->fArg0;
2623*1031c584SApple OSS Distributions
2624*1031c584SApple OSS Distributions PM_ASSERT_IN_GATE();
2625*1031c584SApple OSS Distributions if (request->fArg2) {
2626*1031c584SApple OSS Distributions assert(fTempClampCount != 0);
2627*1031c584SApple OSS Distributions if (fTempClampCount) {
2628*1031c584SApple OSS Distributions fTempClampCount--;
2629*1031c584SApple OSS Distributions }
2630*1031c584SApple OSS Distributions if (!fTempClampCount) {
2631*1031c584SApple OSS Distributions fTempClampPowerState = kPowerStateZero;
2632*1031c584SApple OSS Distributions }
2633*1031c584SApple OSS Distributions }
2634*1031c584SApple OSS Distributions
2635*1031c584SApple OSS Distributions if (fNumberOfPowerStates && (state >= fNumberOfPowerStates)) {
2636*1031c584SApple OSS Distributions state = fHighestPowerState;
2637*1031c584SApple OSS Distributions }
2638*1031c584SApple OSS Distributions
2639*1031c584SApple OSS Distributions // The power suppression due to changePowerStateWithOverrideTo() expires
2640*1031c584SApple OSS Distributions // upon the next "device" power request - changePowerStateToPriv().
2641*1031c584SApple OSS Distributions
2642*1031c584SApple OSS Distributions if ((getPMRequestType() != kIOPMRequestTypeRequestPowerStateOverride) &&
2643*1031c584SApple OSS Distributions (client == gIOPMPowerClientDevice)) {
2644*1031c584SApple OSS Distributions fOverrideMaxPowerState = kIOPMPowerStateMax;
2645*1031c584SApple OSS Distributions }
2646*1031c584SApple OSS Distributions
2647*1031c584SApple OSS Distributions if ((state == kPowerStateZero) &&
2648*1031c584SApple OSS Distributions (client != gIOPMPowerClientDevice) &&
2649*1031c584SApple OSS Distributions (client != gIOPMPowerClientDriver) &&
2650*1031c584SApple OSS Distributions (client != gIOPMPowerClientChildProxy)) {
2651*1031c584SApple OSS Distributions removePowerClient(client);
2652*1031c584SApple OSS Distributions } else {
2653*1031c584SApple OSS Distributions updatePowerClient(client, state);
2654*1031c584SApple OSS Distributions }
2655*1031c584SApple OSS Distributions
2656*1031c584SApple OSS Distributions adjustPowerState();
2657*1031c584SApple OSS Distributions client->release();
2658*1031c584SApple OSS Distributions }
2659*1031c584SApple OSS Distributions
2660*1031c584SApple OSS Distributions //*********************************************************************************
2661*1031c584SApple OSS Distributions // [private] Helper functions to update/remove power clients.
2662*1031c584SApple OSS Distributions //*********************************************************************************
2663*1031c584SApple OSS Distributions
2664*1031c584SApple OSS Distributions void
updatePowerClient(const OSSymbol * client,IOPMPowerStateIndex powerState)2665*1031c584SApple OSS Distributions IOService::updatePowerClient( const OSSymbol * client, IOPMPowerStateIndex powerState )
2666*1031c584SApple OSS Distributions {
2667*1031c584SApple OSS Distributions IOPMPowerStateIndex oldPowerState = kPowerStateZero;
2668*1031c584SApple OSS Distributions
2669*1031c584SApple OSS Distributions if (powerState > UINT_MAX) {
2670*1031c584SApple OSS Distributions assert(false);
2671*1031c584SApple OSS Distributions return;
2672*1031c584SApple OSS Distributions }
2673*1031c584SApple OSS Distributions
2674*1031c584SApple OSS Distributions if (!fPowerClients) {
2675*1031c584SApple OSS Distributions fPowerClients = OSDictionary::withCapacity(4);
2676*1031c584SApple OSS Distributions }
2677*1031c584SApple OSS Distributions if (fPowerClients && client) {
2678*1031c584SApple OSS Distributions OSNumber * num = (OSNumber *) fPowerClients->getObject(client);
2679*1031c584SApple OSS Distributions if (num) {
2680*1031c584SApple OSS Distributions oldPowerState = num->unsigned32BitValue();
2681*1031c584SApple OSS Distributions num->setValue(powerState);
2682*1031c584SApple OSS Distributions } else {
2683*1031c584SApple OSS Distributions num = OSNumber::withNumber(powerState, 32);
2684*1031c584SApple OSS Distributions if (num) {
2685*1031c584SApple OSS Distributions fPowerClients->setObject(client, num);
2686*1031c584SApple OSS Distributions num->release();
2687*1031c584SApple OSS Distributions }
2688*1031c584SApple OSS Distributions }
2689*1031c584SApple OSS Distributions
2690*1031c584SApple OSS Distributions PM_ACTION_CLIENT(actionUpdatePowerClient, client, oldPowerState, powerState);
2691*1031c584SApple OSS Distributions }
2692*1031c584SApple OSS Distributions }
2693*1031c584SApple OSS Distributions
2694*1031c584SApple OSS Distributions void
removePowerClient(const OSSymbol * client)2695*1031c584SApple OSS Distributions IOService::removePowerClient( const OSSymbol * client )
2696*1031c584SApple OSS Distributions {
2697*1031c584SApple OSS Distributions if (fPowerClients && client) {
2698*1031c584SApple OSS Distributions fPowerClients->removeObject(client);
2699*1031c584SApple OSS Distributions }
2700*1031c584SApple OSS Distributions }
2701*1031c584SApple OSS Distributions
2702*1031c584SApple OSS Distributions IOPMPowerStateIndex
getPowerStateForClient(const OSSymbol * client)2703*1031c584SApple OSS Distributions IOService::getPowerStateForClient( const OSSymbol * client )
2704*1031c584SApple OSS Distributions {
2705*1031c584SApple OSS Distributions IOPMPowerStateIndex powerState = kPowerStateZero;
2706*1031c584SApple OSS Distributions
2707*1031c584SApple OSS Distributions if (fPowerClients && client) {
2708*1031c584SApple OSS Distributions OSNumber * num = (OSNumber *) fPowerClients->getObject(client);
2709*1031c584SApple OSS Distributions if (num) {
2710*1031c584SApple OSS Distributions powerState = num->unsigned32BitValue();
2711*1031c584SApple OSS Distributions }
2712*1031c584SApple OSS Distributions }
2713*1031c584SApple OSS Distributions return powerState;
2714*1031c584SApple OSS Distributions }
2715*1031c584SApple OSS Distributions
2716*1031c584SApple OSS Distributions //*********************************************************************************
2717*1031c584SApple OSS Distributions // [protected] powerOverrideOnPriv
2718*1031c584SApple OSS Distributions //*********************************************************************************
2719*1031c584SApple OSS Distributions
2720*1031c584SApple OSS Distributions IOReturn
powerOverrideOnPriv(void)2721*1031c584SApple OSS Distributions IOService::powerOverrideOnPriv( void )
2722*1031c584SApple OSS Distributions {
2723*1031c584SApple OSS Distributions IOPMRequest * request;
2724*1031c584SApple OSS Distributions
2725*1031c584SApple OSS Distributions if (!initialized) {
2726*1031c584SApple OSS Distributions return IOPMNotYetInitialized;
2727*1031c584SApple OSS Distributions }
2728*1031c584SApple OSS Distributions
2729*1031c584SApple OSS Distributions if (gIOPMWorkLoop->inGate()) {
2730*1031c584SApple OSS Distributions fDeviceOverrideEnabled = true;
2731*1031c584SApple OSS Distributions return IOPMNoErr;
2732*1031c584SApple OSS Distributions }
2733*1031c584SApple OSS Distributions
2734*1031c584SApple OSS Distributions request = acquirePMRequest( this, kIOPMRequestTypePowerOverrideOnPriv );
2735*1031c584SApple OSS Distributions if (!request) {
2736*1031c584SApple OSS Distributions return kIOReturnNoMemory;
2737*1031c584SApple OSS Distributions }
2738*1031c584SApple OSS Distributions
2739*1031c584SApple OSS Distributions submitPMRequest( request );
2740*1031c584SApple OSS Distributions return IOPMNoErr;
2741*1031c584SApple OSS Distributions }
2742*1031c584SApple OSS Distributions
2743*1031c584SApple OSS Distributions //*********************************************************************************
2744*1031c584SApple OSS Distributions // [protected] powerOverrideOffPriv
2745*1031c584SApple OSS Distributions //*********************************************************************************
2746*1031c584SApple OSS Distributions
2747*1031c584SApple OSS Distributions IOReturn
powerOverrideOffPriv(void)2748*1031c584SApple OSS Distributions IOService::powerOverrideOffPriv( void )
2749*1031c584SApple OSS Distributions {
2750*1031c584SApple OSS Distributions IOPMRequest * request;
2751*1031c584SApple OSS Distributions
2752*1031c584SApple OSS Distributions if (!initialized) {
2753*1031c584SApple OSS Distributions return IOPMNotYetInitialized;
2754*1031c584SApple OSS Distributions }
2755*1031c584SApple OSS Distributions
2756*1031c584SApple OSS Distributions if (gIOPMWorkLoop->inGate()) {
2757*1031c584SApple OSS Distributions fDeviceOverrideEnabled = false;
2758*1031c584SApple OSS Distributions return IOPMNoErr;
2759*1031c584SApple OSS Distributions }
2760*1031c584SApple OSS Distributions
2761*1031c584SApple OSS Distributions request = acquirePMRequest( this, kIOPMRequestTypePowerOverrideOffPriv );
2762*1031c584SApple OSS Distributions if (!request) {
2763*1031c584SApple OSS Distributions return kIOReturnNoMemory;
2764*1031c584SApple OSS Distributions }
2765*1031c584SApple OSS Distributions
2766*1031c584SApple OSS Distributions submitPMRequest( request );
2767*1031c584SApple OSS Distributions return IOPMNoErr;
2768*1031c584SApple OSS Distributions }
2769*1031c584SApple OSS Distributions
2770*1031c584SApple OSS Distributions //*********************************************************************************
2771*1031c584SApple OSS Distributions // [private] handlePowerOverrideChanged
2772*1031c584SApple OSS Distributions //*********************************************************************************
2773*1031c584SApple OSS Distributions
2774*1031c584SApple OSS Distributions void
handlePowerOverrideChanged(IOPMRequest * request)2775*1031c584SApple OSS Distributions IOService::handlePowerOverrideChanged( IOPMRequest * request )
2776*1031c584SApple OSS Distributions {
2777*1031c584SApple OSS Distributions PM_ASSERT_IN_GATE();
2778*1031c584SApple OSS Distributions if (request->getType() == kIOPMRequestTypePowerOverrideOnPriv) {
2779*1031c584SApple OSS Distributions OUR_PMLog(kPMLogOverrideOn, 0, 0);
2780*1031c584SApple OSS Distributions fDeviceOverrideEnabled = true;
2781*1031c584SApple OSS Distributions } else {
2782*1031c584SApple OSS Distributions OUR_PMLog(kPMLogOverrideOff, 0, 0);
2783*1031c584SApple OSS Distributions fDeviceOverrideEnabled = false;
2784*1031c584SApple OSS Distributions }
2785*1031c584SApple OSS Distributions
2786*1031c584SApple OSS Distributions adjustPowerState();
2787*1031c584SApple OSS Distributions }
2788*1031c584SApple OSS Distributions
2789*1031c584SApple OSS Distributions //*********************************************************************************
2790*1031c584SApple OSS Distributions // [private] computeDesiredState
2791*1031c584SApple OSS Distributions //*********************************************************************************
2792*1031c584SApple OSS Distributions
2793*1031c584SApple OSS Distributions void
computeDesiredState(unsigned long localClamp,bool computeOnly)2794*1031c584SApple OSS Distributions IOService::computeDesiredState( unsigned long localClamp, bool computeOnly )
2795*1031c584SApple OSS Distributions {
2796*1031c584SApple OSS Distributions OSIterator * iter;
2797*1031c584SApple OSS Distributions OSObject * next;
2798*1031c584SApple OSS Distributions IOPowerConnection * connection;
2799*1031c584SApple OSS Distributions IOPMPowerStateIndex desiredState = kPowerStateZero;
2800*1031c584SApple OSS Distributions IOPMPowerStateIndex newPowerState = kPowerStateZero;
2801*1031c584SApple OSS Distributions bool hasChildren = false;
2802*1031c584SApple OSS Distributions
2803*1031c584SApple OSS Distributions // Desired power state is always 0 without a controlling driver.
2804*1031c584SApple OSS Distributions
2805*1031c584SApple OSS Distributions if (!fNumberOfPowerStates) {
2806*1031c584SApple OSS Distributions fDesiredPowerState = kPowerStateZero;
2807*1031c584SApple OSS Distributions return;
2808*1031c584SApple OSS Distributions }
2809*1031c584SApple OSS Distributions
2810*1031c584SApple OSS Distributions // Examine the children's desired power state.
2811*1031c584SApple OSS Distributions
2812*1031c584SApple OSS Distributions iter = getChildIterator(gIOPowerPlane);
2813*1031c584SApple OSS Distributions if (iter) {
2814*1031c584SApple OSS Distributions while ((next = iter->getNextObject())) {
2815*1031c584SApple OSS Distributions if ((connection = OSDynamicCast(IOPowerConnection, next))) {
2816*1031c584SApple OSS Distributions if (connection->getReadyFlag() == false) {
2817*1031c584SApple OSS Distributions PM_LOG3("[%s] %s: connection not ready\n",
2818*1031c584SApple OSS Distributions getName(), __FUNCTION__);
2819*1031c584SApple OSS Distributions continue;
2820*1031c584SApple OSS Distributions }
2821*1031c584SApple OSS Distributions if (connection->childHasRequestedPower()) {
2822*1031c584SApple OSS Distributions hasChildren = true;
2823*1031c584SApple OSS Distributions }
2824*1031c584SApple OSS Distributions desiredState = StateMax(connection->getDesiredDomainState(), desiredState);
2825*1031c584SApple OSS Distributions }
2826*1031c584SApple OSS Distributions }
2827*1031c584SApple OSS Distributions iter->release();
2828*1031c584SApple OSS Distributions }
2829*1031c584SApple OSS Distributions if (hasChildren) {
2830*1031c584SApple OSS Distributions updatePowerClient(gIOPMPowerClientChildren, desiredState);
2831*1031c584SApple OSS Distributions } else {
2832*1031c584SApple OSS Distributions removePowerClient(gIOPMPowerClientChildren);
2833*1031c584SApple OSS Distributions }
2834*1031c584SApple OSS Distributions
2835*1031c584SApple OSS Distributions // Iterate through all power clients to determine the min power state.
2836*1031c584SApple OSS Distributions
2837*1031c584SApple OSS Distributions iter = OSCollectionIterator::withCollection(fPowerClients);
2838*1031c584SApple OSS Distributions if (iter) {
2839*1031c584SApple OSS Distributions const OSSymbol * client;
2840*1031c584SApple OSS Distributions while ((client = (const OSSymbol *) iter->getNextObject())) {
2841*1031c584SApple OSS Distributions // Ignore child and driver when override is in effect.
2842*1031c584SApple OSS Distributions if ((fDeviceOverrideEnabled ||
2843*1031c584SApple OSS Distributions (getPMRequestType() == kIOPMRequestTypeRequestPowerStateOverride)) &&
2844*1031c584SApple OSS Distributions ((client == gIOPMPowerClientChildren) ||
2845*1031c584SApple OSS Distributions (client == gIOPMPowerClientDriver))) {
2846*1031c584SApple OSS Distributions continue;
2847*1031c584SApple OSS Distributions }
2848*1031c584SApple OSS Distributions
2849*1031c584SApple OSS Distributions // Ignore child proxy when children are present.
2850*1031c584SApple OSS Distributions if (hasChildren && (client == gIOPMPowerClientChildProxy)) {
2851*1031c584SApple OSS Distributions continue;
2852*1031c584SApple OSS Distributions }
2853*1031c584SApple OSS Distributions
2854*1031c584SApple OSS Distributions // Advisory tickles are irrelevant unless system is in full wake
2855*1031c584SApple OSS Distributions if (client == gIOPMPowerClientAdvisoryTickle &&
2856*1031c584SApple OSS Distributions !gIOPMAdvisoryTickleEnabled) {
2857*1031c584SApple OSS Distributions continue;
2858*1031c584SApple OSS Distributions }
2859*1031c584SApple OSS Distributions
2860*1031c584SApple OSS Distributions desiredState = getPowerStateForClient(client);
2861*1031c584SApple OSS Distributions assert(desiredState < fNumberOfPowerStates);
2862*1031c584SApple OSS Distributions PM_LOG1(" %u %s\n",
2863*1031c584SApple OSS Distributions (uint32_t) desiredState, client->getCStringNoCopy());
2864*1031c584SApple OSS Distributions
2865*1031c584SApple OSS Distributions newPowerState = StateMax(newPowerState, desiredState);
2866*1031c584SApple OSS Distributions
2867*1031c584SApple OSS Distributions if (client == gIOPMPowerClientDevice) {
2868*1031c584SApple OSS Distributions fDeviceDesire = desiredState;
2869*1031c584SApple OSS Distributions }
2870*1031c584SApple OSS Distributions }
2871*1031c584SApple OSS Distributions iter->release();
2872*1031c584SApple OSS Distributions }
2873*1031c584SApple OSS Distributions
2874*1031c584SApple OSS Distributions // Factor in the temporary power desires.
2875*1031c584SApple OSS Distributions
2876*1031c584SApple OSS Distributions newPowerState = StateMax(newPowerState, localClamp);
2877*1031c584SApple OSS Distributions newPowerState = StateMax(newPowerState, fTempClampPowerState);
2878*1031c584SApple OSS Distributions
2879*1031c584SApple OSS Distributions // Limit check against max power override.
2880*1031c584SApple OSS Distributions
2881*1031c584SApple OSS Distributions newPowerState = StateMin(newPowerState, fOverrideMaxPowerState);
2882*1031c584SApple OSS Distributions
2883*1031c584SApple OSS Distributions // Limit check against number of power states.
2884*1031c584SApple OSS Distributions
2885*1031c584SApple OSS Distributions if (newPowerState >= fNumberOfPowerStates) {
2886*1031c584SApple OSS Distributions newPowerState = fHighestPowerState;
2887*1031c584SApple OSS Distributions }
2888*1031c584SApple OSS Distributions
2889*1031c584SApple OSS Distributions if (getPMRootDomain()->isAOTMode()) {
2890*1031c584SApple OSS Distributions if ((kIOPMPreventIdleSleep & fPowerStates[newPowerState].capabilityFlags)
2891*1031c584SApple OSS Distributions && !(kIOPMPreventIdleSleep & fPowerStates[fDesiredPowerState].capabilityFlags)) {
2892*1031c584SApple OSS Distributions getPMRootDomain()->claimSystemWakeEvent(this, kIOPMWakeEventAOTExit, getName(), NULL);
2893*1031c584SApple OSS Distributions }
2894*1031c584SApple OSS Distributions }
2895*1031c584SApple OSS Distributions
2896*1031c584SApple OSS Distributions fDesiredPowerState = newPowerState;
2897*1031c584SApple OSS Distributions
2898*1031c584SApple OSS Distributions PM_LOG1(" temp %u, clamp %u, current %u, new %u\n",
2899*1031c584SApple OSS Distributions (uint32_t) localClamp, (uint32_t) fTempClampPowerState,
2900*1031c584SApple OSS Distributions (uint32_t) fCurrentPowerState, (uint32_t) newPowerState);
2901*1031c584SApple OSS Distributions
2902*1031c584SApple OSS Distributions if (!computeOnly) {
2903*1031c584SApple OSS Distributions // Restart idle timer if possible when device desire has increased.
2904*1031c584SApple OSS Distributions // Or if an advisory desire exists.
2905*1031c584SApple OSS Distributions
2906*1031c584SApple OSS Distributions if (fIdleTimerPeriod && fIdleTimerStopped) {
2907*1031c584SApple OSS Distributions restartIdleTimer();
2908*1031c584SApple OSS Distributions }
2909*1031c584SApple OSS Distributions
2910*1031c584SApple OSS Distributions // Invalidate cached tickle power state when desires change, and not
2911*1031c584SApple OSS Distributions // due to a tickle request. In case the driver has requested a lower
2912*1031c584SApple OSS Distributions // power state, but the tickle is caching a higher power state which
2913*1031c584SApple OSS Distributions // will drop future tickles until the cached value is lowered or in-
2914*1031c584SApple OSS Distributions // validated. The invalidation must occur before the power transition
2915*1031c584SApple OSS Distributions // to avoid dropping a necessary tickle.
2916*1031c584SApple OSS Distributions
2917*1031c584SApple OSS Distributions if ((getPMRequestType() != kIOPMRequestTypeActivityTickle) &&
2918*1031c584SApple OSS Distributions (fActivityTicklePowerState != kInvalidTicklePowerState)) {
2919*1031c584SApple OSS Distributions IOLockLock(fActivityLock);
2920*1031c584SApple OSS Distributions fActivityTicklePowerState = kInvalidTicklePowerState;
2921*1031c584SApple OSS Distributions IOLockUnlock(fActivityLock);
2922*1031c584SApple OSS Distributions }
2923*1031c584SApple OSS Distributions }
2924*1031c584SApple OSS Distributions }
2925*1031c584SApple OSS Distributions
2926*1031c584SApple OSS Distributions //*********************************************************************************
2927*1031c584SApple OSS Distributions // [public] currentPowerConsumption
2928*1031c584SApple OSS Distributions //
2929*1031c584SApple OSS Distributions //*********************************************************************************
2930*1031c584SApple OSS Distributions
2931*1031c584SApple OSS Distributions unsigned long
currentPowerConsumption(void)2932*1031c584SApple OSS Distributions IOService::currentPowerConsumption( void )
2933*1031c584SApple OSS Distributions {
2934*1031c584SApple OSS Distributions if (!initialized) {
2935*1031c584SApple OSS Distributions return kIOPMUnknown;
2936*1031c584SApple OSS Distributions }
2937*1031c584SApple OSS Distributions
2938*1031c584SApple OSS Distributions return fCurrentPowerConsumption;
2939*1031c584SApple OSS Distributions }
2940*1031c584SApple OSS Distributions
2941*1031c584SApple OSS Distributions //*********************************************************************************
2942*1031c584SApple OSS Distributions // [deprecated] getPMworkloop
2943*1031c584SApple OSS Distributions //*********************************************************************************
2944*1031c584SApple OSS Distributions
2945*1031c584SApple OSS Distributions #ifndef __LP64__
2946*1031c584SApple OSS Distributions IOWorkLoop *
getPMworkloop(void)2947*1031c584SApple OSS Distributions IOService::getPMworkloop( void )
2948*1031c584SApple OSS Distributions {
2949*1031c584SApple OSS Distributions return gIOPMWorkLoop;
2950*1031c584SApple OSS Distributions }
2951*1031c584SApple OSS Distributions #endif
2952*1031c584SApple OSS Distributions
2953*1031c584SApple OSS Distributions #if NOT_YET
2954*1031c584SApple OSS Distributions
2955*1031c584SApple OSS Distributions //*********************************************************************************
2956*1031c584SApple OSS Distributions // Power Parent/Children Applier
2957*1031c584SApple OSS Distributions //*********************************************************************************
2958*1031c584SApple OSS Distributions
2959*1031c584SApple OSS Distributions static void
applyToPowerChildren(IOService * service,IOServiceApplierFunction applier,void * context,IOOptionBits options)2960*1031c584SApple OSS Distributions applyToPowerChildren(
2961*1031c584SApple OSS Distributions IOService * service,
2962*1031c584SApple OSS Distributions IOServiceApplierFunction applier,
2963*1031c584SApple OSS Distributions void * context,
2964*1031c584SApple OSS Distributions IOOptionBits options )
2965*1031c584SApple OSS Distributions {
2966*1031c584SApple OSS Distributions PM_ASSERT_IN_GATE();
2967*1031c584SApple OSS Distributions
2968*1031c584SApple OSS Distributions IORegistryEntry * entry;
2969*1031c584SApple OSS Distributions IORegistryIterator * iter;
2970*1031c584SApple OSS Distributions IOPowerConnection * connection;
2971*1031c584SApple OSS Distributions IOService * child;
2972*1031c584SApple OSS Distributions
2973*1031c584SApple OSS Distributions iter = IORegistryIterator::iterateOver(service, gIOPowerPlane, options);
2974*1031c584SApple OSS Distributions if (iter) {
2975*1031c584SApple OSS Distributions while ((entry = iter->getNextObject())) {
2976*1031c584SApple OSS Distributions // Get child of IOPowerConnection objects
2977*1031c584SApple OSS Distributions if ((connection = OSDynamicCast(IOPowerConnection, entry))) {
2978*1031c584SApple OSS Distributions child = (IOService *) connection->copyChildEntry(gIOPowerPlane);
2979*1031c584SApple OSS Distributions if (child) {
2980*1031c584SApple OSS Distributions (*applier)(child, context);
2981*1031c584SApple OSS Distributions child->release();
2982*1031c584SApple OSS Distributions }
2983*1031c584SApple OSS Distributions }
2984*1031c584SApple OSS Distributions }
2985*1031c584SApple OSS Distributions iter->release();
2986*1031c584SApple OSS Distributions }
2987*1031c584SApple OSS Distributions }
2988*1031c584SApple OSS Distributions
2989*1031c584SApple OSS Distributions static void
applyToPowerParent(IOService * service,IOServiceApplierFunction applier,void * context,IOOptionBits options)2990*1031c584SApple OSS Distributions applyToPowerParent(
2991*1031c584SApple OSS Distributions IOService * service,
2992*1031c584SApple OSS Distributions IOServiceApplierFunction applier,
2993*1031c584SApple OSS Distributions void * context,
2994*1031c584SApple OSS Distributions IOOptionBits options )
2995*1031c584SApple OSS Distributions {
2996*1031c584SApple OSS Distributions PM_ASSERT_IN_GATE();
2997*1031c584SApple OSS Distributions
2998*1031c584SApple OSS Distributions IORegistryEntry * entry;
2999*1031c584SApple OSS Distributions IORegistryIterator * iter;
3000*1031c584SApple OSS Distributions IOPowerConnection * connection;
3001*1031c584SApple OSS Distributions IOService * parent;
3002*1031c584SApple OSS Distributions
3003*1031c584SApple OSS Distributions iter = IORegistryIterator::iterateOver(service, gIOPowerPlane,
3004*1031c584SApple OSS Distributions options | kIORegistryIterateParents);
3005*1031c584SApple OSS Distributions if (iter) {
3006*1031c584SApple OSS Distributions while ((entry = iter->getNextObject())) {
3007*1031c584SApple OSS Distributions // Get child of IOPowerConnection objects
3008*1031c584SApple OSS Distributions if ((connection = OSDynamicCast(IOPowerConnection, entry))) {
3009*1031c584SApple OSS Distributions parent = (IOService *) connection->copyParentEntry(gIOPowerPlane);
3010*1031c584SApple OSS Distributions if (parent) {
3011*1031c584SApple OSS Distributions (*applier)(parent, context);
3012*1031c584SApple OSS Distributions parent->release();
3013*1031c584SApple OSS Distributions }
3014*1031c584SApple OSS Distributions }
3015*1031c584SApple OSS Distributions }
3016*1031c584SApple OSS Distributions iter->release();
3017*1031c584SApple OSS Distributions }
3018*1031c584SApple OSS Distributions }
3019*1031c584SApple OSS Distributions
3020*1031c584SApple OSS Distributions #endif /* NOT_YET */
3021*1031c584SApple OSS Distributions
3022*1031c584SApple OSS Distributions // MARK: -
3023*1031c584SApple OSS Distributions // MARK: Activity Tickle & Idle Timer
3024*1031c584SApple OSS Distributions
3025*1031c584SApple OSS Distributions void
setAdvisoryTickleEnable(bool enable)3026*1031c584SApple OSS Distributions IOService::setAdvisoryTickleEnable( bool enable )
3027*1031c584SApple OSS Distributions {
3028*1031c584SApple OSS Distributions gIOPMAdvisoryTickleEnabled = enable;
3029*1031c584SApple OSS Distributions }
3030*1031c584SApple OSS Distributions
3031*1031c584SApple OSS Distributions //*********************************************************************************
3032*1031c584SApple OSS Distributions // [public] activityTickle
3033*1031c584SApple OSS Distributions //
3034*1031c584SApple OSS Distributions // The tickle with parameter kIOPMSuperclassPolicy1 causes the activity
3035*1031c584SApple OSS Distributions // flag to be set, and the device state checked. If the device has been
3036*1031c584SApple OSS Distributions // powered down, it is powered up again.
3037*1031c584SApple OSS Distributions // The tickle with parameter kIOPMSubclassPolicy is ignored here and
3038*1031c584SApple OSS Distributions // should be intercepted by a subclass.
3039*1031c584SApple OSS Distributions //*********************************************************************************
3040*1031c584SApple OSS Distributions
3041*1031c584SApple OSS Distributions bool
activityTickle(unsigned long type,unsigned long stateNumber)3042*1031c584SApple OSS Distributions IOService::activityTickle( unsigned long type, unsigned long stateNumber )
3043*1031c584SApple OSS Distributions {
3044*1031c584SApple OSS Distributions if (!initialized) {
3045*1031c584SApple OSS Distributions return true; // no power change
3046*1031c584SApple OSS Distributions }
3047*1031c584SApple OSS Distributions
3048*1031c584SApple OSS Distributions if (!fPowerStates) {
3049*1031c584SApple OSS Distributions // registerPowerDriver may not have completed
3050*1031c584SApple OSS Distributions IOPMRequest * request;
3051*1031c584SApple OSS Distributions
3052*1031c584SApple OSS Distributions request = acquirePMRequest( this, kIOPMRequestTypeDeferredActivityTickle );
3053*1031c584SApple OSS Distributions if (request) {
3054*1031c584SApple OSS Distributions request->fArg0 = (void *) type;
3055*1031c584SApple OSS Distributions request->fArg1 = (void *)(uintptr_t) stateNumber;
3056*1031c584SApple OSS Distributions submitPMRequest(request);
3057*1031c584SApple OSS Distributions }
3058*1031c584SApple OSS Distributions // Returns false if the activityTickle might cause a transition to a
3059*1031c584SApple OSS Distributions // higher powered state. We don't know, so this seems safest.
3060*1031c584SApple OSS Distributions return false;
3061*1031c584SApple OSS Distributions }
3062*1031c584SApple OSS Distributions
3063*1031c584SApple OSS Distributions return _activityTickle(type, stateNumber);
3064*1031c584SApple OSS Distributions }
3065*1031c584SApple OSS Distributions
3066*1031c584SApple OSS Distributions //*********************************************************************************
3067*1031c584SApple OSS Distributions // [private] handleDeferredActivityTickle
3068*1031c584SApple OSS Distributions //*********************************************************************************
3069*1031c584SApple OSS Distributions
3070*1031c584SApple OSS Distributions void
handleDeferredActivityTickle(IOPMRequest * request)3071*1031c584SApple OSS Distributions IOService::handleDeferredActivityTickle( IOPMRequest * request )
3072*1031c584SApple OSS Distributions {
3073*1031c584SApple OSS Distributions unsigned long type = (unsigned long) request->fArg1;
3074*1031c584SApple OSS Distributions unsigned long stateNumber = (unsigned long) request->fArg2;
3075*1031c584SApple OSS Distributions
3076*1031c584SApple OSS Distributions if (!fPowerStates) {
3077*1031c584SApple OSS Distributions // registerPowerDriver was not called before activityTickle()
3078*1031c584SApple OSS Distributions return;
3079*1031c584SApple OSS Distributions }
3080*1031c584SApple OSS Distributions (void) _activityTickle(type, stateNumber);
3081*1031c584SApple OSS Distributions }
3082*1031c584SApple OSS Distributions
3083*1031c584SApple OSS Distributions //*********************************************************************************
3084*1031c584SApple OSS Distributions // [private] _activityTickle
3085*1031c584SApple OSS Distributions //
3086*1031c584SApple OSS Distributions // The tickle with parameter kIOPMSuperclassPolicy1 causes the activity
3087*1031c584SApple OSS Distributions // flag to be set, and the device state checked. If the device has been
3088*1031c584SApple OSS Distributions // powered down, it is powered up again.
3089*1031c584SApple OSS Distributions // The tickle with parameter kIOPMSubclassPolicy is ignored here and
3090*1031c584SApple OSS Distributions // should be intercepted by a subclass.
3091*1031c584SApple OSS Distributions //*********************************************************************************
3092*1031c584SApple OSS Distributions
3093*1031c584SApple OSS Distributions bool
_activityTickle(unsigned long type,unsigned long stateNumber)3094*1031c584SApple OSS Distributions IOService::_activityTickle( unsigned long type, unsigned long stateNumber )
3095*1031c584SApple OSS Distributions {
3096*1031c584SApple OSS Distributions IOPMRequest * request;
3097*1031c584SApple OSS Distributions bool noPowerChange = true;
3098*1031c584SApple OSS Distributions uint32_t tickleFlags;
3099*1031c584SApple OSS Distributions
3100*1031c584SApple OSS Distributions if ((type == kIOPMSuperclassPolicy1) && StateOrder(stateNumber)) {
3101*1031c584SApple OSS Distributions IOLockLock(fActivityLock);
3102*1031c584SApple OSS Distributions
3103*1031c584SApple OSS Distributions // Record device activity for the idle timer handler.
3104*1031c584SApple OSS Distributions
3105*1031c584SApple OSS Distributions fDeviceWasActive = true;
3106*1031c584SApple OSS Distributions fActivityTickleCount++;
3107*1031c584SApple OSS Distributions clock_get_uptime(&fDeviceActiveTimestamp);
3108*1031c584SApple OSS Distributions
3109*1031c584SApple OSS Distributions PM_ACTION_TICKLE(actionActivityTickle);
3110*1031c584SApple OSS Distributions
3111*1031c584SApple OSS Distributions // Record the last tickle power state.
3112*1031c584SApple OSS Distributions // This helps to filter out redundant tickles as
3113*1031c584SApple OSS Distributions // this function may be called from the data path.
3114*1031c584SApple OSS Distributions
3115*1031c584SApple OSS Distributions if ((fActivityTicklePowerState == kInvalidTicklePowerState)
3116*1031c584SApple OSS Distributions || StateOrder(fActivityTicklePowerState) < StateOrder(stateNumber)) {
3117*1031c584SApple OSS Distributions fActivityTicklePowerState = stateNumber;
3118*1031c584SApple OSS Distributions noPowerChange = false;
3119*1031c584SApple OSS Distributions
3120*1031c584SApple OSS Distributions tickleFlags = kTickleTypeActivity | kTickleTypePowerRise;
3121*1031c584SApple OSS Distributions request = acquirePMRequest( this, kIOPMRequestTypeActivityTickle );
3122*1031c584SApple OSS Distributions if (request) {
3123*1031c584SApple OSS Distributions request->fArg0 = (void *) stateNumber;
3124*1031c584SApple OSS Distributions request->fArg1 = (void *)(uintptr_t) tickleFlags;
3125*1031c584SApple OSS Distributions request->fArg2 = (void *)(uintptr_t) gIOPMTickleGeneration;
3126*1031c584SApple OSS Distributions submitPMRequest(request);
3127*1031c584SApple OSS Distributions }
3128*1031c584SApple OSS Distributions }
3129*1031c584SApple OSS Distributions
3130*1031c584SApple OSS Distributions IOLockUnlock(fActivityLock);
3131*1031c584SApple OSS Distributions } else if ((type == kIOPMActivityTickleTypeAdvisory) &&
3132*1031c584SApple OSS Distributions ((stateNumber = fDeviceUsablePowerState) != kPowerStateZero)) {
3133*1031c584SApple OSS Distributions IOLockLock(fActivityLock);
3134*1031c584SApple OSS Distributions
3135*1031c584SApple OSS Distributions fAdvisoryTickled = true;
3136*1031c584SApple OSS Distributions
3137*1031c584SApple OSS Distributions if (fAdvisoryTicklePowerState != stateNumber) {
3138*1031c584SApple OSS Distributions fAdvisoryTicklePowerState = stateNumber;
3139*1031c584SApple OSS Distributions noPowerChange = false;
3140*1031c584SApple OSS Distributions
3141*1031c584SApple OSS Distributions tickleFlags = kTickleTypeAdvisory | kTickleTypePowerRise;
3142*1031c584SApple OSS Distributions request = acquirePMRequest( this, kIOPMRequestTypeActivityTickle );
3143*1031c584SApple OSS Distributions if (request) {
3144*1031c584SApple OSS Distributions request->fArg0 = (void *) stateNumber;
3145*1031c584SApple OSS Distributions request->fArg1 = (void *)(uintptr_t) tickleFlags;
3146*1031c584SApple OSS Distributions request->fArg2 = (void *)(uintptr_t) gIOPMTickleGeneration;
3147*1031c584SApple OSS Distributions submitPMRequest(request);
3148*1031c584SApple OSS Distributions }
3149*1031c584SApple OSS Distributions }
3150*1031c584SApple OSS Distributions
3151*1031c584SApple OSS Distributions IOLockUnlock(fActivityLock);
3152*1031c584SApple OSS Distributions }
3153*1031c584SApple OSS Distributions
3154*1031c584SApple OSS Distributions // Returns false if the activityTickle might cause a transition to a
3155*1031c584SApple OSS Distributions // higher powered state, true otherwise.
3156*1031c584SApple OSS Distributions
3157*1031c584SApple OSS Distributions return noPowerChange;
3158*1031c584SApple OSS Distributions }
3159*1031c584SApple OSS Distributions
3160*1031c584SApple OSS Distributions //*********************************************************************************
3161*1031c584SApple OSS Distributions // [private] handleActivityTickle
3162*1031c584SApple OSS Distributions //*********************************************************************************
3163*1031c584SApple OSS Distributions
3164*1031c584SApple OSS Distributions void
handleActivityTickle(IOPMRequest * request)3165*1031c584SApple OSS Distributions IOService::handleActivityTickle( IOPMRequest * request )
3166*1031c584SApple OSS Distributions {
3167*1031c584SApple OSS Distributions IOPMPowerStateIndex ticklePowerState = (IOPMPowerStateIndex) request->fArg0;
3168*1031c584SApple OSS Distributions IOPMPowerStateIndex tickleFlags = (IOPMPowerStateIndex) request->fArg1;
3169*1031c584SApple OSS Distributions uint32_t tickleGeneration = (uint32_t)(uintptr_t) request->fArg2;
3170*1031c584SApple OSS Distributions bool adjustPower = false;
3171*1031c584SApple OSS Distributions
3172*1031c584SApple OSS Distributions PM_ASSERT_IN_GATE();
3173*1031c584SApple OSS Distributions if (fResetPowerStateOnWake && (tickleGeneration != gIOPMTickleGeneration)) {
3174*1031c584SApple OSS Distributions // Drivers that don't want power restored on wake will drop any
3175*1031c584SApple OSS Distributions // tickles that pre-dates the current system wake. The model is
3176*1031c584SApple OSS Distributions // that each wake is a fresh start, with power state depressed
3177*1031c584SApple OSS Distributions // until a new tickle or an explicit power up request from the
3178*1031c584SApple OSS Distributions // driver. It is possible for the PM work loop to enter the
3179*1031c584SApple OSS Distributions // system sleep path with tickle requests queued.
3180*1031c584SApple OSS Distributions
3181*1031c584SApple OSS Distributions return;
3182*1031c584SApple OSS Distributions }
3183*1031c584SApple OSS Distributions
3184*1031c584SApple OSS Distributions if (tickleFlags & kTickleTypeActivity) {
3185*1031c584SApple OSS Distributions IOPMPowerStateIndex deviceDesireOrder = StateOrder(fDeviceDesire);
3186*1031c584SApple OSS Distributions IOPMPowerStateIndex idleTimerGeneration = ticklePowerState; // kTickleTypePowerDrop
3187*1031c584SApple OSS Distributions
3188*1031c584SApple OSS Distributions if (tickleFlags & kTickleTypePowerRise) {
3189*1031c584SApple OSS Distributions if ((StateOrder(ticklePowerState) > deviceDesireOrder) &&
3190*1031c584SApple OSS Distributions (ticklePowerState < fNumberOfPowerStates)) {
3191*1031c584SApple OSS Distributions fIdleTimerMinPowerState = ticklePowerState;
3192*1031c584SApple OSS Distributions updatePowerClient(gIOPMPowerClientDevice, ticklePowerState);
3193*1031c584SApple OSS Distributions adjustPower = true;
3194*1031c584SApple OSS Distributions }
3195*1031c584SApple OSS Distributions } else if ((deviceDesireOrder > StateOrder(fIdleTimerMinPowerState)) &&
3196*1031c584SApple OSS Distributions (idleTimerGeneration == fIdleTimerGeneration)) {
3197*1031c584SApple OSS Distributions // Power drop due to idle timer expiration.
3198*1031c584SApple OSS Distributions // Do not allow idle timer to reduce power below tickle power.
3199*1031c584SApple OSS Distributions // This prevents the idle timer from decreasing the device desire
3200*1031c584SApple OSS Distributions // to zero and cancelling the effect of a pre-sleep tickle when
3201*1031c584SApple OSS Distributions // system wakes up to doze state, while the device is unable to
3202*1031c584SApple OSS Distributions // raise its power state to satisfy the tickle.
3203*1031c584SApple OSS Distributions
3204*1031c584SApple OSS Distributions deviceDesireOrder--;
3205*1031c584SApple OSS Distributions if (deviceDesireOrder < fNumberOfPowerStates) {
3206*1031c584SApple OSS Distributions ticklePowerState = fPowerStates[deviceDesireOrder].stateOrderToIndex;
3207*1031c584SApple OSS Distributions updatePowerClient(gIOPMPowerClientDevice, ticklePowerState);
3208*1031c584SApple OSS Distributions adjustPower = true;
3209*1031c584SApple OSS Distributions }
3210*1031c584SApple OSS Distributions }
3211*1031c584SApple OSS Distributions } else { // advisory tickle
3212*1031c584SApple OSS Distributions if (tickleFlags & kTickleTypePowerRise) {
3213*1031c584SApple OSS Distributions if ((ticklePowerState == fDeviceUsablePowerState) &&
3214*1031c584SApple OSS Distributions (ticklePowerState < fNumberOfPowerStates)) {
3215*1031c584SApple OSS Distributions updatePowerClient(gIOPMPowerClientAdvisoryTickle, ticklePowerState);
3216*1031c584SApple OSS Distributions fHasAdvisoryDesire = true;
3217*1031c584SApple OSS Distributions fAdvisoryTickleUsed = true;
3218*1031c584SApple OSS Distributions adjustPower = true;
3219*1031c584SApple OSS Distributions } else {
3220*1031c584SApple OSS Distributions IOLockLock(fActivityLock);
3221*1031c584SApple OSS Distributions fAdvisoryTicklePowerState = kInvalidTicklePowerState;
3222*1031c584SApple OSS Distributions IOLockUnlock(fActivityLock);
3223*1031c584SApple OSS Distributions }
3224*1031c584SApple OSS Distributions } else if (fHasAdvisoryDesire) {
3225*1031c584SApple OSS Distributions removePowerClient(gIOPMPowerClientAdvisoryTickle);
3226*1031c584SApple OSS Distributions fHasAdvisoryDesire = false;
3227*1031c584SApple OSS Distributions adjustPower = true;
3228*1031c584SApple OSS Distributions }
3229*1031c584SApple OSS Distributions }
3230*1031c584SApple OSS Distributions
3231*1031c584SApple OSS Distributions if (adjustPower) {
3232*1031c584SApple OSS Distributions adjustPowerState();
3233*1031c584SApple OSS Distributions }
3234*1031c584SApple OSS Distributions }
3235*1031c584SApple OSS Distributions
3236*1031c584SApple OSS Distributions //******************************************************************************
3237*1031c584SApple OSS Distributions // [public] setIdleTimerPeriod
3238*1031c584SApple OSS Distributions //
3239*1031c584SApple OSS Distributions // A subclass policy-maker is using our standard idleness detection service.
3240*1031c584SApple OSS Distributions // Start the idle timer. Period is in seconds.
3241*1031c584SApple OSS Distributions //******************************************************************************
3242*1031c584SApple OSS Distributions
3243*1031c584SApple OSS Distributions IOReturn
setIdleTimerPeriod(unsigned long period)3244*1031c584SApple OSS Distributions IOService::setIdleTimerPeriod( unsigned long period )
3245*1031c584SApple OSS Distributions {
3246*1031c584SApple OSS Distributions if (!initialized) {
3247*1031c584SApple OSS Distributions return IOPMNotYetInitialized;
3248*1031c584SApple OSS Distributions }
3249*1031c584SApple OSS Distributions
3250*1031c584SApple OSS Distributions OUR_PMLog(kPMLogSetIdleTimerPeriod, period, fIdleTimerPeriod);
3251*1031c584SApple OSS Distributions
3252*1031c584SApple OSS Distributions if (period > INT_MAX) {
3253*1031c584SApple OSS Distributions return kIOReturnBadArgument;
3254*1031c584SApple OSS Distributions }
3255*1031c584SApple OSS Distributions
3256*1031c584SApple OSS Distributions IOPMRequest * request =
3257*1031c584SApple OSS Distributions acquirePMRequest( this, kIOPMRequestTypeSetIdleTimerPeriod );
3258*1031c584SApple OSS Distributions if (!request) {
3259*1031c584SApple OSS Distributions return kIOReturnNoMemory;
3260*1031c584SApple OSS Distributions }
3261*1031c584SApple OSS Distributions
3262*1031c584SApple OSS Distributions request->fArg0 = (void *) period;
3263*1031c584SApple OSS Distributions submitPMRequest( request );
3264*1031c584SApple OSS Distributions
3265*1031c584SApple OSS Distributions return kIOReturnSuccess;
3266*1031c584SApple OSS Distributions }
3267*1031c584SApple OSS Distributions
3268*1031c584SApple OSS Distributions IOReturn
setIgnoreIdleTimer(bool ignore)3269*1031c584SApple OSS Distributions IOService::setIgnoreIdleTimer( bool ignore )
3270*1031c584SApple OSS Distributions {
3271*1031c584SApple OSS Distributions if (!initialized) {
3272*1031c584SApple OSS Distributions return IOPMNotYetInitialized;
3273*1031c584SApple OSS Distributions }
3274*1031c584SApple OSS Distributions
3275*1031c584SApple OSS Distributions OUR_PMLog(kIOPMRequestTypeIgnoreIdleTimer, ignore, 0);
3276*1031c584SApple OSS Distributions
3277*1031c584SApple OSS Distributions IOPMRequest * request =
3278*1031c584SApple OSS Distributions acquirePMRequest( this, kIOPMRequestTypeIgnoreIdleTimer );
3279*1031c584SApple OSS Distributions if (!request) {
3280*1031c584SApple OSS Distributions return kIOReturnNoMemory;
3281*1031c584SApple OSS Distributions }
3282*1031c584SApple OSS Distributions
3283*1031c584SApple OSS Distributions request->fArg0 = (void *) ignore;
3284*1031c584SApple OSS Distributions submitPMRequest( request );
3285*1031c584SApple OSS Distributions
3286*1031c584SApple OSS Distributions return kIOReturnSuccess;
3287*1031c584SApple OSS Distributions }
3288*1031c584SApple OSS Distributions
3289*1031c584SApple OSS Distributions //******************************************************************************
3290*1031c584SApple OSS Distributions // [public] nextIdleTimeout
3291*1031c584SApple OSS Distributions //
3292*1031c584SApple OSS Distributions // Returns how many "seconds from now" the device should idle into its
3293*1031c584SApple OSS Distributions // next lowest power state.
3294*1031c584SApple OSS Distributions //******************************************************************************
3295*1031c584SApple OSS Distributions
3296*1031c584SApple OSS Distributions SInt32
nextIdleTimeout(AbsoluteTime currentTime,AbsoluteTime lastActivity,unsigned int powerState)3297*1031c584SApple OSS Distributions IOService::nextIdleTimeout(
3298*1031c584SApple OSS Distributions AbsoluteTime currentTime,
3299*1031c584SApple OSS Distributions AbsoluteTime lastActivity,
3300*1031c584SApple OSS Distributions unsigned int powerState)
3301*1031c584SApple OSS Distributions {
3302*1031c584SApple OSS Distributions AbsoluteTime delta;
3303*1031c584SApple OSS Distributions UInt64 delta_ns;
3304*1031c584SApple OSS Distributions SInt32 delta_secs;
3305*1031c584SApple OSS Distributions SInt32 delay_secs;
3306*1031c584SApple OSS Distributions
3307*1031c584SApple OSS Distributions // Calculate time difference using funky macro from clock.h.
3308*1031c584SApple OSS Distributions delta = currentTime;
3309*1031c584SApple OSS Distributions SUB_ABSOLUTETIME(&delta, &lastActivity);
3310*1031c584SApple OSS Distributions
3311*1031c584SApple OSS Distributions // Figure it in seconds.
3312*1031c584SApple OSS Distributions absolutetime_to_nanoseconds(delta, &delta_ns);
3313*1031c584SApple OSS Distributions delta_secs = (SInt32)(delta_ns / NSEC_PER_SEC);
3314*1031c584SApple OSS Distributions
3315*1031c584SApple OSS Distributions // Be paranoid about delta somehow exceeding timer period.
3316*1031c584SApple OSS Distributions if (delta_secs < (int) fIdleTimerPeriod) {
3317*1031c584SApple OSS Distributions delay_secs = (int) fIdleTimerPeriod - delta_secs;
3318*1031c584SApple OSS Distributions } else {
3319*1031c584SApple OSS Distributions delay_secs = (int) fIdleTimerPeriod;
3320*1031c584SApple OSS Distributions }
3321*1031c584SApple OSS Distributions
3322*1031c584SApple OSS Distributions return (SInt32)delay_secs;
3323*1031c584SApple OSS Distributions }
3324*1031c584SApple OSS Distributions
3325*1031c584SApple OSS Distributions //*********************************************************************************
3326*1031c584SApple OSS Distributions // [public] start_PM_idle_timer
3327*1031c584SApple OSS Distributions //*********************************************************************************
3328*1031c584SApple OSS Distributions
3329*1031c584SApple OSS Distributions void
start_PM_idle_timer(void)3330*1031c584SApple OSS Distributions IOService::start_PM_idle_timer( void )
3331*1031c584SApple OSS Distributions {
3332*1031c584SApple OSS Distributions static const int maxTimeout = 100000;
3333*1031c584SApple OSS Distributions static const int minTimeout = 1;
3334*1031c584SApple OSS Distributions AbsoluteTime uptime, deadline;
3335*1031c584SApple OSS Distributions SInt32 idle_in = 0;
3336*1031c584SApple OSS Distributions boolean_t pending;
3337*1031c584SApple OSS Distributions
3338*1031c584SApple OSS Distributions if (!initialized || !fIdleTimerPeriod ||
3339*1031c584SApple OSS Distributions ((unsigned int) fCurrentPowerState != fCurrentPowerState)) {
3340*1031c584SApple OSS Distributions return;
3341*1031c584SApple OSS Distributions }
3342*1031c584SApple OSS Distributions
3343*1031c584SApple OSS Distributions IOLockLock(fActivityLock);
3344*1031c584SApple OSS Distributions
3345*1031c584SApple OSS Distributions clock_get_uptime(&uptime);
3346*1031c584SApple OSS Distributions
3347*1031c584SApple OSS Distributions // Subclasses may modify idle sleep algorithm
3348*1031c584SApple OSS Distributions idle_in = nextIdleTimeout(uptime, fDeviceActiveTimestamp, (unsigned int) fCurrentPowerState);
3349*1031c584SApple OSS Distributions
3350*1031c584SApple OSS Distributions // Check for out-of range responses
3351*1031c584SApple OSS Distributions if (idle_in > maxTimeout) {
3352*1031c584SApple OSS Distributions // use standard implementation
3353*1031c584SApple OSS Distributions idle_in = IOService::nextIdleTimeout(uptime,
3354*1031c584SApple OSS Distributions fDeviceActiveTimestamp,
3355*1031c584SApple OSS Distributions (unsigned int) fCurrentPowerState);
3356*1031c584SApple OSS Distributions } else if (idle_in < minTimeout) {
3357*1031c584SApple OSS Distributions idle_in = fIdleTimerPeriod;
3358*1031c584SApple OSS Distributions }
3359*1031c584SApple OSS Distributions
3360*1031c584SApple OSS Distributions IOLockUnlock(fActivityLock);
3361*1031c584SApple OSS Distributions
3362*1031c584SApple OSS Distributions fNextIdleTimerPeriod = idle_in;
3363*1031c584SApple OSS Distributions fIdleTimerStartTime = uptime;
3364*1031c584SApple OSS Distributions
3365*1031c584SApple OSS Distributions retain();
3366*1031c584SApple OSS Distributions clock_interval_to_absolutetime_interval(idle_in, kSecondScale, &deadline);
3367*1031c584SApple OSS Distributions ADD_ABSOLUTETIME(&deadline, &uptime);
3368*1031c584SApple OSS Distributions pending = thread_call_enter_delayed(fIdleTimer, deadline);
3369*1031c584SApple OSS Distributions if (pending) {
3370*1031c584SApple OSS Distributions release();
3371*1031c584SApple OSS Distributions }
3372*1031c584SApple OSS Distributions }
3373*1031c584SApple OSS Distributions
3374*1031c584SApple OSS Distributions //*********************************************************************************
3375*1031c584SApple OSS Distributions // [private] restartIdleTimer
3376*1031c584SApple OSS Distributions //*********************************************************************************
3377*1031c584SApple OSS Distributions
3378*1031c584SApple OSS Distributions void
restartIdleTimer(void)3379*1031c584SApple OSS Distributions IOService::restartIdleTimer( void )
3380*1031c584SApple OSS Distributions {
3381*1031c584SApple OSS Distributions if (fDeviceDesire != kPowerStateZero) {
3382*1031c584SApple OSS Distributions fIdleTimerStopped = false;
3383*1031c584SApple OSS Distributions fActivityTickleCount = 0;
3384*1031c584SApple OSS Distributions start_PM_idle_timer();
3385*1031c584SApple OSS Distributions } else if (fHasAdvisoryDesire) {
3386*1031c584SApple OSS Distributions fIdleTimerStopped = false;
3387*1031c584SApple OSS Distributions start_PM_idle_timer();
3388*1031c584SApple OSS Distributions } else {
3389*1031c584SApple OSS Distributions fIdleTimerStopped = true;
3390*1031c584SApple OSS Distributions }
3391*1031c584SApple OSS Distributions }
3392*1031c584SApple OSS Distributions
3393*1031c584SApple OSS Distributions //*********************************************************************************
3394*1031c584SApple OSS Distributions // idle_timer_expired
3395*1031c584SApple OSS Distributions //*********************************************************************************
3396*1031c584SApple OSS Distributions
3397*1031c584SApple OSS Distributions static void
idle_timer_expired(thread_call_param_t arg0,thread_call_param_t arg1)3398*1031c584SApple OSS Distributions idle_timer_expired(
3399*1031c584SApple OSS Distributions thread_call_param_t arg0, thread_call_param_t arg1 )
3400*1031c584SApple OSS Distributions {
3401*1031c584SApple OSS Distributions IOService * me = (IOService *) arg0;
3402*1031c584SApple OSS Distributions
3403*1031c584SApple OSS Distributions if (gIOPMWorkLoop) {
3404*1031c584SApple OSS Distributions gIOPMWorkLoop->runAction(
3405*1031c584SApple OSS Distributions OSMemberFunctionCast(IOWorkLoop::Action, me,
3406*1031c584SApple OSS Distributions &IOService::idleTimerExpired),
3407*1031c584SApple OSS Distributions me);
3408*1031c584SApple OSS Distributions }
3409*1031c584SApple OSS Distributions
3410*1031c584SApple OSS Distributions me->release();
3411*1031c584SApple OSS Distributions }
3412*1031c584SApple OSS Distributions
3413*1031c584SApple OSS Distributions //*********************************************************************************
3414*1031c584SApple OSS Distributions // [private] idleTimerExpired
3415*1031c584SApple OSS Distributions //
3416*1031c584SApple OSS Distributions // The idle timer has expired. If there has been activity since the last
3417*1031c584SApple OSS Distributions // expiration, just restart the timer and return. If there has not been
3418*1031c584SApple OSS Distributions // activity, switch to the next lower power state and restart the timer.
3419*1031c584SApple OSS Distributions //*********************************************************************************
3420*1031c584SApple OSS Distributions
3421*1031c584SApple OSS Distributions void
idleTimerExpired(void)3422*1031c584SApple OSS Distributions IOService::idleTimerExpired( void )
3423*1031c584SApple OSS Distributions {
3424*1031c584SApple OSS Distributions IOPMRequest * request;
3425*1031c584SApple OSS Distributions bool restartTimer = true;
3426*1031c584SApple OSS Distributions uint32_t tickleFlags;
3427*1031c584SApple OSS Distributions
3428*1031c584SApple OSS Distributions if (!initialized || !fIdleTimerPeriod || fIdleTimerStopped ||
3429*1031c584SApple OSS Distributions fLockedFlags.PMStop) {
3430*1031c584SApple OSS Distributions return;
3431*1031c584SApple OSS Distributions }
3432*1031c584SApple OSS Distributions
3433*1031c584SApple OSS Distributions fIdleTimerStartTime = 0;
3434*1031c584SApple OSS Distributions
3435*1031c584SApple OSS Distributions IOLockLock(fActivityLock);
3436*1031c584SApple OSS Distributions
3437*1031c584SApple OSS Distributions // Check for device activity (tickles) over last timer period.
3438*1031c584SApple OSS Distributions
3439*1031c584SApple OSS Distributions if (fDeviceWasActive) {
3440*1031c584SApple OSS Distributions // Device was active - do not drop power, restart timer.
3441*1031c584SApple OSS Distributions fDeviceWasActive = false;
3442*1031c584SApple OSS Distributions } else if (!fIdleTimerIgnored) {
3443*1031c584SApple OSS Distributions // No device activity - drop power state by one level.
3444*1031c584SApple OSS Distributions // Decrement the cached tickle power state when possible.
3445*1031c584SApple OSS Distributions // This value may be kInvalidTicklePowerState before activityTickle()
3446*1031c584SApple OSS Distributions // is called, but the power drop request must be issued regardless.
3447*1031c584SApple OSS Distributions
3448*1031c584SApple OSS Distributions if ((fActivityTicklePowerState != kInvalidTicklePowerState) &&
3449*1031c584SApple OSS Distributions (fActivityTicklePowerState != kPowerStateZero)) {
3450*1031c584SApple OSS Distributions fActivityTicklePowerState--;
3451*1031c584SApple OSS Distributions }
3452*1031c584SApple OSS Distributions
3453*1031c584SApple OSS Distributions tickleFlags = kTickleTypeActivity | kTickleTypePowerDrop;
3454*1031c584SApple OSS Distributions request = acquirePMRequest( this, kIOPMRequestTypeActivityTickle );
3455*1031c584SApple OSS Distributions if (request) {
3456*1031c584SApple OSS Distributions request->fArg0 = (void *)(uintptr_t) fIdleTimerGeneration;
3457*1031c584SApple OSS Distributions request->fArg1 = (void *)(uintptr_t) tickleFlags;
3458*1031c584SApple OSS Distributions request->fArg2 = (void *)(uintptr_t) gIOPMTickleGeneration;
3459*1031c584SApple OSS Distributions submitPMRequest( request );
3460*1031c584SApple OSS Distributions
3461*1031c584SApple OSS Distributions // Do not restart timer until after the tickle request has been
3462*1031c584SApple OSS Distributions // processed.
3463*1031c584SApple OSS Distributions
3464*1031c584SApple OSS Distributions restartTimer = false;
3465*1031c584SApple OSS Distributions }
3466*1031c584SApple OSS Distributions }
3467*1031c584SApple OSS Distributions
3468*1031c584SApple OSS Distributions if (fAdvisoryTickled) {
3469*1031c584SApple OSS Distributions fAdvisoryTickled = false;
3470*1031c584SApple OSS Distributions } else if (fHasAdvisoryDesire) {
3471*1031c584SApple OSS Distributions // Want new tickles to turn into pm request after we drop the lock
3472*1031c584SApple OSS Distributions fAdvisoryTicklePowerState = kInvalidTicklePowerState;
3473*1031c584SApple OSS Distributions
3474*1031c584SApple OSS Distributions tickleFlags = kTickleTypeAdvisory | kTickleTypePowerDrop;
3475*1031c584SApple OSS Distributions request = acquirePMRequest( this, kIOPMRequestTypeActivityTickle );
3476*1031c584SApple OSS Distributions if (request) {
3477*1031c584SApple OSS Distributions request->fArg0 = (void *)(uintptr_t) fIdleTimerGeneration;
3478*1031c584SApple OSS Distributions request->fArg1 = (void *)(uintptr_t) tickleFlags;
3479*1031c584SApple OSS Distributions request->fArg2 = (void *)(uintptr_t) gIOPMTickleGeneration;
3480*1031c584SApple OSS Distributions submitPMRequest( request );
3481*1031c584SApple OSS Distributions
3482*1031c584SApple OSS Distributions // Do not restart timer until after the tickle request has been
3483*1031c584SApple OSS Distributions // processed.
3484*1031c584SApple OSS Distributions
3485*1031c584SApple OSS Distributions restartTimer = false;
3486*1031c584SApple OSS Distributions }
3487*1031c584SApple OSS Distributions }
3488*1031c584SApple OSS Distributions
3489*1031c584SApple OSS Distributions IOLockUnlock(fActivityLock);
3490*1031c584SApple OSS Distributions
3491*1031c584SApple OSS Distributions if (restartTimer) {
3492*1031c584SApple OSS Distributions start_PM_idle_timer();
3493*1031c584SApple OSS Distributions }
3494*1031c584SApple OSS Distributions }
3495*1031c584SApple OSS Distributions
3496*1031c584SApple OSS Distributions #ifndef __LP64__
3497*1031c584SApple OSS Distributions //*********************************************************************************
3498*1031c584SApple OSS Distributions // [deprecated] PM_idle_timer_expiration
3499*1031c584SApple OSS Distributions //*********************************************************************************
3500*1031c584SApple OSS Distributions
3501*1031c584SApple OSS Distributions void
PM_idle_timer_expiration(void)3502*1031c584SApple OSS Distributions IOService::PM_idle_timer_expiration( void )
3503*1031c584SApple OSS Distributions {
3504*1031c584SApple OSS Distributions }
3505*1031c584SApple OSS Distributions
3506*1031c584SApple OSS Distributions //*********************************************************************************
3507*1031c584SApple OSS Distributions // [deprecated] command_received
3508*1031c584SApple OSS Distributions //*********************************************************************************
3509*1031c584SApple OSS Distributions
3510*1031c584SApple OSS Distributions void
command_received(void * statePtr,void *,void *,void *)3511*1031c584SApple OSS Distributions IOService::command_received( void *statePtr, void *, void *, void * )
3512*1031c584SApple OSS Distributions {
3513*1031c584SApple OSS Distributions }
3514*1031c584SApple OSS Distributions #endif /* !__LP64__ */
3515*1031c584SApple OSS Distributions
3516*1031c584SApple OSS Distributions //*********************************************************************************
3517*1031c584SApple OSS Distributions // [public] setAggressiveness
3518*1031c584SApple OSS Distributions //
3519*1031c584SApple OSS Distributions // Pass on the input parameters to all power domain children. All those which are
3520*1031c584SApple OSS Distributions // power domains will pass it on to their children, etc.
3521*1031c584SApple OSS Distributions //*********************************************************************************
3522*1031c584SApple OSS Distributions
3523*1031c584SApple OSS Distributions IOReturn
setAggressiveness(unsigned long type,unsigned long newLevel)3524*1031c584SApple OSS Distributions IOService::setAggressiveness( unsigned long type, unsigned long newLevel )
3525*1031c584SApple OSS Distributions {
3526*1031c584SApple OSS Distributions return kIOReturnSuccess;
3527*1031c584SApple OSS Distributions }
3528*1031c584SApple OSS Distributions
3529*1031c584SApple OSS Distributions //*********************************************************************************
3530*1031c584SApple OSS Distributions // [public] getAggressiveness
3531*1031c584SApple OSS Distributions //
3532*1031c584SApple OSS Distributions // Called by the user client.
3533*1031c584SApple OSS Distributions //*********************************************************************************
3534*1031c584SApple OSS Distributions
3535*1031c584SApple OSS Distributions IOReturn
getAggressiveness(unsigned long type,unsigned long * currentLevel)3536*1031c584SApple OSS Distributions IOService::getAggressiveness( unsigned long type, unsigned long * currentLevel )
3537*1031c584SApple OSS Distributions {
3538*1031c584SApple OSS Distributions IOPMrootDomain * rootDomain = getPMRootDomain();
3539*1031c584SApple OSS Distributions
3540*1031c584SApple OSS Distributions if (!rootDomain) {
3541*1031c584SApple OSS Distributions return kIOReturnNotReady;
3542*1031c584SApple OSS Distributions }
3543*1031c584SApple OSS Distributions
3544*1031c584SApple OSS Distributions return rootDomain->getAggressiveness( type, currentLevel );
3545*1031c584SApple OSS Distributions }
3546*1031c584SApple OSS Distributions
3547*1031c584SApple OSS Distributions //*********************************************************************************
3548*1031c584SApple OSS Distributions // [public] getPowerState
3549*1031c584SApple OSS Distributions //
3550*1031c584SApple OSS Distributions //*********************************************************************************
3551*1031c584SApple OSS Distributions
3552*1031c584SApple OSS Distributions UInt32
getPowerState(void)3553*1031c584SApple OSS Distributions IOService::getPowerState( void )
3554*1031c584SApple OSS Distributions {
3555*1031c584SApple OSS Distributions if (!initialized) {
3556*1031c584SApple OSS Distributions return kPowerStateZero;
3557*1031c584SApple OSS Distributions }
3558*1031c584SApple OSS Distributions
3559*1031c584SApple OSS Distributions return (UInt32) fCurrentPowerState;
3560*1031c584SApple OSS Distributions }
3561*1031c584SApple OSS Distributions
3562*1031c584SApple OSS Distributions #ifndef __LP64__
3563*1031c584SApple OSS Distributions //*********************************************************************************
3564*1031c584SApple OSS Distributions // [deprecated] systemWake
3565*1031c584SApple OSS Distributions //
3566*1031c584SApple OSS Distributions // Pass this to all power domain children. All those which are
3567*1031c584SApple OSS Distributions // power domains will pass it on to their children, etc.
3568*1031c584SApple OSS Distributions //*********************************************************************************
3569*1031c584SApple OSS Distributions
3570*1031c584SApple OSS Distributions IOReturn
systemWake(void)3571*1031c584SApple OSS Distributions IOService::systemWake( void )
3572*1031c584SApple OSS Distributions {
3573*1031c584SApple OSS Distributions OSIterator * iter;
3574*1031c584SApple OSS Distributions OSObject * next;
3575*1031c584SApple OSS Distributions IOPowerConnection * connection;
3576*1031c584SApple OSS Distributions IOService * theChild;
3577*1031c584SApple OSS Distributions
3578*1031c584SApple OSS Distributions iter = getChildIterator(gIOPowerPlane);
3579*1031c584SApple OSS Distributions if (iter) {
3580*1031c584SApple OSS Distributions while ((next = iter->getNextObject())) {
3581*1031c584SApple OSS Distributions if ((connection = OSDynamicCast(IOPowerConnection, next))) {
3582*1031c584SApple OSS Distributions if (connection->getReadyFlag() == false) {
3583*1031c584SApple OSS Distributions PM_LOG3("[%s] %s: connection not ready\n",
3584*1031c584SApple OSS Distributions getName(), __FUNCTION__);
3585*1031c584SApple OSS Distributions continue;
3586*1031c584SApple OSS Distributions }
3587*1031c584SApple OSS Distributions
3588*1031c584SApple OSS Distributions theChild = (IOService *)connection->copyChildEntry(gIOPowerPlane);
3589*1031c584SApple OSS Distributions if (theChild) {
3590*1031c584SApple OSS Distributions theChild->systemWake();
3591*1031c584SApple OSS Distributions theChild->release();
3592*1031c584SApple OSS Distributions }
3593*1031c584SApple OSS Distributions }
3594*1031c584SApple OSS Distributions }
3595*1031c584SApple OSS Distributions iter->release();
3596*1031c584SApple OSS Distributions }
3597*1031c584SApple OSS Distributions
3598*1031c584SApple OSS Distributions if (fControllingDriver != NULL) {
3599*1031c584SApple OSS Distributions if (fControllingDriver->didYouWakeSystem()) {
3600*1031c584SApple OSS Distributions makeUsable();
3601*1031c584SApple OSS Distributions }
3602*1031c584SApple OSS Distributions }
3603*1031c584SApple OSS Distributions
3604*1031c584SApple OSS Distributions return IOPMNoErr;
3605*1031c584SApple OSS Distributions }
3606*1031c584SApple OSS Distributions
3607*1031c584SApple OSS Distributions //*********************************************************************************
3608*1031c584SApple OSS Distributions // [deprecated] temperatureCriticalForZone
3609*1031c584SApple OSS Distributions //*********************************************************************************
3610*1031c584SApple OSS Distributions
3611*1031c584SApple OSS Distributions IOReturn
temperatureCriticalForZone(IOService * whichZone)3612*1031c584SApple OSS Distributions IOService::temperatureCriticalForZone( IOService * whichZone )
3613*1031c584SApple OSS Distributions {
3614*1031c584SApple OSS Distributions IOService * theParent;
3615*1031c584SApple OSS Distributions IOService * theNub;
3616*1031c584SApple OSS Distributions
3617*1031c584SApple OSS Distributions OUR_PMLog(kPMLogCriticalTemp, 0, 0);
3618*1031c584SApple OSS Distributions
3619*1031c584SApple OSS Distributions if (inPlane(gIOPowerPlane) && !IS_PM_ROOT) {
3620*1031c584SApple OSS Distributions theNub = (IOService *)copyParentEntry(gIOPowerPlane);
3621*1031c584SApple OSS Distributions if (theNub) {
3622*1031c584SApple OSS Distributions theParent = (IOService *)theNub->copyParentEntry(gIOPowerPlane);
3623*1031c584SApple OSS Distributions theNub->release();
3624*1031c584SApple OSS Distributions if (theParent) {
3625*1031c584SApple OSS Distributions theParent->temperatureCriticalForZone(whichZone);
3626*1031c584SApple OSS Distributions theParent->release();
3627*1031c584SApple OSS Distributions }
3628*1031c584SApple OSS Distributions }
3629*1031c584SApple OSS Distributions }
3630*1031c584SApple OSS Distributions return IOPMNoErr;
3631*1031c584SApple OSS Distributions }
3632*1031c584SApple OSS Distributions #endif /* !__LP64__ */
3633*1031c584SApple OSS Distributions
3634*1031c584SApple OSS Distributions // MARK: -
3635*1031c584SApple OSS Distributions // MARK: Power Change (Common)
3636*1031c584SApple OSS Distributions
3637*1031c584SApple OSS Distributions //*********************************************************************************
3638*1031c584SApple OSS Distributions // [private] startPowerChange
3639*1031c584SApple OSS Distributions //
3640*1031c584SApple OSS Distributions // All power state changes starts here.
3641*1031c584SApple OSS Distributions //*********************************************************************************
3642*1031c584SApple OSS Distributions
3643*1031c584SApple OSS Distributions IOReturn
startPowerChange(IOPMPowerChangeFlags changeFlags,IOPMPowerStateIndex powerState,IOPMPowerFlags domainFlags,IOPowerConnection * parentConnection,IOPMPowerFlags parentFlags)3644*1031c584SApple OSS Distributions IOService::startPowerChange(
3645*1031c584SApple OSS Distributions IOPMPowerChangeFlags changeFlags,
3646*1031c584SApple OSS Distributions IOPMPowerStateIndex powerState,
3647*1031c584SApple OSS Distributions IOPMPowerFlags domainFlags,
3648*1031c584SApple OSS Distributions IOPowerConnection * parentConnection,
3649*1031c584SApple OSS Distributions IOPMPowerFlags parentFlags )
3650*1031c584SApple OSS Distributions {
3651*1031c584SApple OSS Distributions uint32_t savedPMActionsState;
3652*1031c584SApple OSS Distributions
3653*1031c584SApple OSS Distributions PM_ASSERT_IN_GATE();
3654*1031c584SApple OSS Distributions assert( fMachineState == kIOPM_Finished );
3655*1031c584SApple OSS Distributions assert( powerState < fNumberOfPowerStates );
3656*1031c584SApple OSS Distributions
3657*1031c584SApple OSS Distributions if (powerState >= fNumberOfPowerStates) {
3658*1031c584SApple OSS Distributions return IOPMAckImplied;
3659*1031c584SApple OSS Distributions }
3660*1031c584SApple OSS Distributions
3661*1031c584SApple OSS Distributions fIsPreChange = true;
3662*1031c584SApple OSS Distributions savedPMActionsState = fPMActions.state;
3663*1031c584SApple OSS Distributions PM_ACTION_CHANGE(actionPowerChangeOverride, &powerState, &changeFlags);
3664*1031c584SApple OSS Distributions
3665*1031c584SApple OSS Distributions // rdar://problem/55040032
3666*1031c584SApple OSS Distributions // Schedule a power adjustment after removing the power clamp
3667*1031c584SApple OSS Distributions // to inform our power parent(s) about our latest desired domain
3668*1031c584SApple OSS Distributions // power state. For a self-initiated change, let OurChangeStart()
3669*1031c584SApple OSS Distributions // automatically request parent power when necessary.
3670*1031c584SApple OSS Distributions if (!fAdjustPowerScheduled &&
3671*1031c584SApple OSS Distributions ((changeFlags & kIOPMSelfInitiated) == 0) &&
3672*1031c584SApple OSS Distributions ((fPMActions.state & kPMActionsStatePowerClamped) == 0) &&
3673*1031c584SApple OSS Distributions ((savedPMActionsState & kPMActionsStatePowerClamped) != 0)) {
3674*1031c584SApple OSS Distributions IOPMRequest * request = acquirePMRequest(this, kIOPMRequestTypeAdjustPowerState);
3675*1031c584SApple OSS Distributions if (request) {
3676*1031c584SApple OSS Distributions submitPMRequest(request);
3677*1031c584SApple OSS Distributions fAdjustPowerScheduled = true;
3678*1031c584SApple OSS Distributions }
3679*1031c584SApple OSS Distributions }
3680*1031c584SApple OSS Distributions
3681*1031c584SApple OSS Distributions if (changeFlags & kIOPMExpireIdleTimer) {
3682*1031c584SApple OSS Distributions // Root domain requested removal of tickle influence
3683*1031c584SApple OSS Distributions if (StateOrder(fDeviceDesire) > StateOrder(powerState)) {
3684*1031c584SApple OSS Distributions // Reset device desire down to the clamped power state
3685*1031c584SApple OSS Distributions updatePowerClient(gIOPMPowerClientDevice, powerState);
3686*1031c584SApple OSS Distributions computeDesiredState(kPowerStateZero, true);
3687*1031c584SApple OSS Distributions
3688*1031c584SApple OSS Distributions // Invalidate tickle cache so the next tickle will issue a request
3689*1031c584SApple OSS Distributions IOLockLock(fActivityLock);
3690*1031c584SApple OSS Distributions fDeviceWasActive = false;
3691*1031c584SApple OSS Distributions fActivityTicklePowerState = kInvalidTicklePowerState;
3692*1031c584SApple OSS Distributions IOLockUnlock(fActivityLock);
3693*1031c584SApple OSS Distributions
3694*1031c584SApple OSS Distributions fIdleTimerMinPowerState = kPowerStateZero;
3695*1031c584SApple OSS Distributions }
3696*1031c584SApple OSS Distributions }
3697*1031c584SApple OSS Distributions
3698*1031c584SApple OSS Distributions // Root domain's override handler may cancel the power change by
3699*1031c584SApple OSS Distributions // setting the kIOPMNotDone flag.
3700*1031c584SApple OSS Distributions
3701*1031c584SApple OSS Distributions if (changeFlags & kIOPMNotDone) {
3702*1031c584SApple OSS Distributions return IOPMAckImplied;
3703*1031c584SApple OSS Distributions }
3704*1031c584SApple OSS Distributions
3705*1031c584SApple OSS Distributions // Forks to either Driver or Parent initiated power change paths.
3706*1031c584SApple OSS Distributions
3707*1031c584SApple OSS Distributions fHeadNoteChangeFlags = changeFlags;
3708*1031c584SApple OSS Distributions fHeadNotePowerState = powerState;
3709*1031c584SApple OSS Distributions fHeadNotePowerArrayEntry = &fPowerStates[powerState];
3710*1031c584SApple OSS Distributions fHeadNoteParentConnection = NULL;
3711*1031c584SApple OSS Distributions
3712*1031c584SApple OSS Distributions if (changeFlags & kIOPMSelfInitiated) {
3713*1031c584SApple OSS Distributions if (changeFlags & kIOPMSynchronize) {
3714*1031c584SApple OSS Distributions OurSyncStart();
3715*1031c584SApple OSS Distributions } else {
3716*1031c584SApple OSS Distributions OurChangeStart();
3717*1031c584SApple OSS Distributions }
3718*1031c584SApple OSS Distributions return 0;
3719*1031c584SApple OSS Distributions } else {
3720*1031c584SApple OSS Distributions assert(changeFlags & kIOPMParentInitiated);
3721*1031c584SApple OSS Distributions fHeadNoteDomainFlags = domainFlags;
3722*1031c584SApple OSS Distributions fHeadNoteParentFlags = parentFlags;
3723*1031c584SApple OSS Distributions fHeadNoteParentConnection = parentConnection;
3724*1031c584SApple OSS Distributions return ParentChangeStart();
3725*1031c584SApple OSS Distributions }
3726*1031c584SApple OSS Distributions }
3727*1031c584SApple OSS Distributions
3728*1031c584SApple OSS Distributions //*********************************************************************************
3729*1031c584SApple OSS Distributions // [private] notifyInterestedDrivers
3730*1031c584SApple OSS Distributions //*********************************************************************************
3731*1031c584SApple OSS Distributions
3732*1031c584SApple OSS Distributions bool
notifyInterestedDrivers(void)3733*1031c584SApple OSS Distributions IOService::notifyInterestedDrivers( void )
3734*1031c584SApple OSS Distributions {
3735*1031c584SApple OSS Distributions IOPMinformee * informee;
3736*1031c584SApple OSS Distributions IOPMinformeeList * list = fInterestedDrivers;
3737*1031c584SApple OSS Distributions DriverCallParam * param;
3738*1031c584SApple OSS Distributions unsigned long numItems;
3739*1031c584SApple OSS Distributions uint32_t count;
3740*1031c584SApple OSS Distributions uint32_t skipCnt = 0;
3741*1031c584SApple OSS Distributions
3742*1031c584SApple OSS Distributions PM_ASSERT_IN_GATE();
3743*1031c584SApple OSS Distributions assert( fDriverCallParamCount == 0 );
3744*1031c584SApple OSS Distributions assert( fHeadNotePendingAcks == 0 );
3745*1031c584SApple OSS Distributions
3746*1031c584SApple OSS Distributions fHeadNotePendingAcks = 0;
3747*1031c584SApple OSS Distributions
3748*1031c584SApple OSS Distributions numItems = list->numberOfItems();
3749*1031c584SApple OSS Distributions if (!numItems || ((uint32_t) numItems != numItems)) {
3750*1031c584SApple OSS Distributions goto done; // interested drivers count out of range
3751*1031c584SApple OSS Distributions }
3752*1031c584SApple OSS Distributions count = (uint32_t) numItems;
3753*1031c584SApple OSS Distributions
3754*1031c584SApple OSS Distributions // Allocate an array of interested drivers and their return values
3755*1031c584SApple OSS Distributions // for the callout thread. Everything else is still "owned" by the
3756*1031c584SApple OSS Distributions // PM work loop, which can run to process acknowledgePowerChange()
3757*1031c584SApple OSS Distributions // responses.
3758*1031c584SApple OSS Distributions
3759*1031c584SApple OSS Distributions param = (DriverCallParam *) fDriverCallParamPtr;
3760*1031c584SApple OSS Distributions if (count > fDriverCallParamSlots) {
3761*1031c584SApple OSS Distributions if (fDriverCallParamSlots) {
3762*1031c584SApple OSS Distributions assert(fDriverCallParamPtr);
3763*1031c584SApple OSS Distributions IODelete(fDriverCallParamPtr, DriverCallParam, fDriverCallParamSlots);
3764*1031c584SApple OSS Distributions fDriverCallParamPtr = NULL;
3765*1031c584SApple OSS Distributions fDriverCallParamSlots = 0;
3766*1031c584SApple OSS Distributions }
3767*1031c584SApple OSS Distributions
3768*1031c584SApple OSS Distributions param = IONew(DriverCallParam, count);
3769*1031c584SApple OSS Distributions if (!param) {
3770*1031c584SApple OSS Distributions goto done; // no memory
3771*1031c584SApple OSS Distributions }
3772*1031c584SApple OSS Distributions fDriverCallParamPtr = (void *) param;
3773*1031c584SApple OSS Distributions fDriverCallParamSlots = count;
3774*1031c584SApple OSS Distributions }
3775*1031c584SApple OSS Distributions
3776*1031c584SApple OSS Distributions informee = list->firstInList();
3777*1031c584SApple OSS Distributions assert(informee);
3778*1031c584SApple OSS Distributions for (IOItemCount i = 0, arrayIdx = 0; i < count; i++) {
3779*1031c584SApple OSS Distributions if (fInitialSetPowerState || (fHeadNoteChangeFlags & kIOPMInitialPowerChange)) {
3780*1031c584SApple OSS Distributions // Skip notifying self, if 'kIOPMInitialDeviceState' is set and
3781*1031c584SApple OSS Distributions // this is the initial power state change
3782*1031c584SApple OSS Distributions if ((this == informee->whatObject) &&
3783*1031c584SApple OSS Distributions (fHeadNotePowerArrayEntry->capabilityFlags & kIOPMInitialDeviceState)) {
3784*1031c584SApple OSS Distributions skipCnt++;
3785*1031c584SApple OSS Distributions continue;
3786*1031c584SApple OSS Distributions }
3787*1031c584SApple OSS Distributions }
3788*1031c584SApple OSS Distributions informee->timer = -1;
3789*1031c584SApple OSS Distributions param[arrayIdx].Target = informee;
3790*1031c584SApple OSS Distributions informee->retain();
3791*1031c584SApple OSS Distributions informee = list->nextInList( informee );
3792*1031c584SApple OSS Distributions arrayIdx++;
3793*1031c584SApple OSS Distributions }
3794*1031c584SApple OSS Distributions
3795*1031c584SApple OSS Distributions count -= skipCnt;
3796*1031c584SApple OSS Distributions if (!count) {
3797*1031c584SApple OSS Distributions goto done;
3798*1031c584SApple OSS Distributions }
3799*1031c584SApple OSS Distributions fDriverCallParamCount = count;
3800*1031c584SApple OSS Distributions fHeadNotePendingAcks = count;
3801*1031c584SApple OSS Distributions
3802*1031c584SApple OSS Distributions // Block state machine and wait for callout completion.
3803*1031c584SApple OSS Distributions assert(!fDriverCallBusy);
3804*1031c584SApple OSS Distributions fDriverCallBusy = true;
3805*1031c584SApple OSS Distributions thread_call_enter( fDriverCallEntry );
3806*1031c584SApple OSS Distributions return true;
3807*1031c584SApple OSS Distributions
3808*1031c584SApple OSS Distributions done:
3809*1031c584SApple OSS Distributions // Return false if there are no interested drivers or could not schedule
3810*1031c584SApple OSS Distributions // callout thread due to error.
3811*1031c584SApple OSS Distributions return false;
3812*1031c584SApple OSS Distributions }
3813*1031c584SApple OSS Distributions
3814*1031c584SApple OSS Distributions //*********************************************************************************
3815*1031c584SApple OSS Distributions // [private] notifyInterestedDriversDone
3816*1031c584SApple OSS Distributions //*********************************************************************************
3817*1031c584SApple OSS Distributions
3818*1031c584SApple OSS Distributions void
notifyInterestedDriversDone(void)3819*1031c584SApple OSS Distributions IOService::notifyInterestedDriversDone( void )
3820*1031c584SApple OSS Distributions {
3821*1031c584SApple OSS Distributions IOPMinformee * informee;
3822*1031c584SApple OSS Distributions IOItemCount count;
3823*1031c584SApple OSS Distributions DriverCallParam * param;
3824*1031c584SApple OSS Distributions IOReturn result;
3825*1031c584SApple OSS Distributions int maxTimeout = 0;
3826*1031c584SApple OSS Distributions
3827*1031c584SApple OSS Distributions PM_ASSERT_IN_GATE();
3828*1031c584SApple OSS Distributions assert( fDriverCallBusy == false );
3829*1031c584SApple OSS Distributions assert( fMachineState == kIOPM_DriverThreadCallDone );
3830*1031c584SApple OSS Distributions
3831*1031c584SApple OSS Distributions param = (DriverCallParam *) fDriverCallParamPtr;
3832*1031c584SApple OSS Distributions count = fDriverCallParamCount;
3833*1031c584SApple OSS Distributions
3834*1031c584SApple OSS Distributions if (param && count) {
3835*1031c584SApple OSS Distributions for (IOItemCount i = 0; i < count; i++, param++) {
3836*1031c584SApple OSS Distributions informee = (IOPMinformee *) param->Target;
3837*1031c584SApple OSS Distributions result = param->Result;
3838*1031c584SApple OSS Distributions
3839*1031c584SApple OSS Distributions if ((result == IOPMAckImplied) || (result < 0)) {
3840*1031c584SApple OSS Distributions // Interested driver return IOPMAckImplied.
3841*1031c584SApple OSS Distributions // If informee timer is zero, it must have de-registered
3842*1031c584SApple OSS Distributions // interest during the thread callout. That also drops
3843*1031c584SApple OSS Distributions // the pending ack count.
3844*1031c584SApple OSS Distributions
3845*1031c584SApple OSS Distributions if (fHeadNotePendingAcks && informee->timer) {
3846*1031c584SApple OSS Distributions fHeadNotePendingAcks--;
3847*1031c584SApple OSS Distributions }
3848*1031c584SApple OSS Distributions
3849*1031c584SApple OSS Distributions informee->timer = 0;
3850*1031c584SApple OSS Distributions } else if (informee->timer) {
3851*1031c584SApple OSS Distributions assert(informee->timer == -1);
3852*1031c584SApple OSS Distributions
3853*1031c584SApple OSS Distributions // Driver has not acked, and has returned a positive result.
3854*1031c584SApple OSS Distributions // Enforce a minimum permissible timeout value.
3855*1031c584SApple OSS Distributions // Make the min value large enough so timeout is less likely
3856*1031c584SApple OSS Distributions // to occur if a driver misinterpreted that the return value
3857*1031c584SApple OSS Distributions // should be in microsecond units. And make it large enough
3858*1031c584SApple OSS Distributions // to be noticeable if a driver neglects to ack.
3859*1031c584SApple OSS Distributions
3860*1031c584SApple OSS Distributions if (result < kMinAckTimeoutTicks) {
3861*1031c584SApple OSS Distributions result = kMinAckTimeoutTicks;
3862*1031c584SApple OSS Distributions }
3863*1031c584SApple OSS Distributions
3864*1031c584SApple OSS Distributions informee->timer = (result / (ACK_TIMER_PERIOD / ns_per_us)) + 1;
3865*1031c584SApple OSS Distributions if (result > maxTimeout) {
3866*1031c584SApple OSS Distributions maxTimeout = result;
3867*1031c584SApple OSS Distributions }
3868*1031c584SApple OSS Distributions }
3869*1031c584SApple OSS Distributions // else, child has already acked or driver has removed interest,
3870*1031c584SApple OSS Distributions // and head_note_pendingAcks decremented.
3871*1031c584SApple OSS Distributions // informee may have been removed from the interested drivers list,
3872*1031c584SApple OSS Distributions // thus the informee must be retained across the callout.
3873*1031c584SApple OSS Distributions
3874*1031c584SApple OSS Distributions informee->release();
3875*1031c584SApple OSS Distributions }
3876*1031c584SApple OSS Distributions
3877*1031c584SApple OSS Distributions fDriverCallParamCount = 0;
3878*1031c584SApple OSS Distributions
3879*1031c584SApple OSS Distributions if (fHeadNotePendingAcks) {
3880*1031c584SApple OSS Distributions OUR_PMLog(kPMLogStartAckTimer, 0, 0);
3881*1031c584SApple OSS Distributions start_ack_timer();
3882*1031c584SApple OSS Distributions getPMRootDomain()->reset_watchdog_timer(this, maxTimeout / USEC_PER_SEC + 1);
3883*1031c584SApple OSS Distributions }
3884*1031c584SApple OSS Distributions }
3885*1031c584SApple OSS Distributions
3886*1031c584SApple OSS Distributions MS_POP(); // pop the machine state passed to notifyAll()
3887*1031c584SApple OSS Distributions
3888*1031c584SApple OSS Distributions // If interest acks are outstanding, block the state machine until
3889*1031c584SApple OSS Distributions // fHeadNotePendingAcks drops to zero before notifying root domain.
3890*1031c584SApple OSS Distributions // Otherwise notify root domain directly.
3891*1031c584SApple OSS Distributions
3892*1031c584SApple OSS Distributions if (!fHeadNotePendingAcks) {
3893*1031c584SApple OSS Distributions notifyRootDomain();
3894*1031c584SApple OSS Distributions } else {
3895*1031c584SApple OSS Distributions MS_PUSH(fMachineState);
3896*1031c584SApple OSS Distributions fMachineState = kIOPM_NotifyChildrenStart;
3897*1031c584SApple OSS Distributions }
3898*1031c584SApple OSS Distributions }
3899*1031c584SApple OSS Distributions
3900*1031c584SApple OSS Distributions //*********************************************************************************
3901*1031c584SApple OSS Distributions // [private] notifyRootDomain
3902*1031c584SApple OSS Distributions //*********************************************************************************
3903*1031c584SApple OSS Distributions
3904*1031c584SApple OSS Distributions void
notifyRootDomain(void)3905*1031c584SApple OSS Distributions IOService::notifyRootDomain( void )
3906*1031c584SApple OSS Distributions {
3907*1031c584SApple OSS Distributions assert( fDriverCallBusy == false );
3908*1031c584SApple OSS Distributions
3909*1031c584SApple OSS Distributions // Only for root domain in the will-change phase.
3910*1031c584SApple OSS Distributions // On a power up, don't notify children right after the interested drivers.
3911*1031c584SApple OSS Distributions // Perform setPowerState() first, then notify the children.
3912*1031c584SApple OSS Distributions if (!IS_ROOT_DOMAIN || (fMachineState != kIOPM_OurChangeSetPowerState)) {
3913*1031c584SApple OSS Distributions notifyChildren();
3914*1031c584SApple OSS Distributions return;
3915*1031c584SApple OSS Distributions }
3916*1031c584SApple OSS Distributions
3917*1031c584SApple OSS Distributions MS_PUSH(fMachineState); // push notifyAll() machine state
3918*1031c584SApple OSS Distributions fMachineState = kIOPM_DriverThreadCallDone;
3919*1031c584SApple OSS Distributions
3920*1031c584SApple OSS Distributions // Call IOPMrootDomain::willNotifyPowerChildren() on a thread call
3921*1031c584SApple OSS Distributions // to avoid a deadlock.
3922*1031c584SApple OSS Distributions fDriverCallReason = kRootDomainInformPreChange;
3923*1031c584SApple OSS Distributions fDriverCallBusy = true;
3924*1031c584SApple OSS Distributions thread_call_enter( fDriverCallEntry );
3925*1031c584SApple OSS Distributions }
3926*1031c584SApple OSS Distributions
3927*1031c584SApple OSS Distributions void
notifyRootDomainDone(void)3928*1031c584SApple OSS Distributions IOService::notifyRootDomainDone( void )
3929*1031c584SApple OSS Distributions {
3930*1031c584SApple OSS Distributions assert( fDriverCallBusy == false );
3931*1031c584SApple OSS Distributions assert( fMachineState == kIOPM_DriverThreadCallDone );
3932*1031c584SApple OSS Distributions
3933*1031c584SApple OSS Distributions MS_POP(); // pop notifyAll() machine state
3934*1031c584SApple OSS Distributions notifyChildren();
3935*1031c584SApple OSS Distributions }
3936*1031c584SApple OSS Distributions
3937*1031c584SApple OSS Distributions //*********************************************************************************
3938*1031c584SApple OSS Distributions // [private] notifyChildren
3939*1031c584SApple OSS Distributions //*********************************************************************************
3940*1031c584SApple OSS Distributions
3941*1031c584SApple OSS Distributions void
notifyChildren(void)3942*1031c584SApple OSS Distributions IOService::notifyChildren( void )
3943*1031c584SApple OSS Distributions {
3944*1031c584SApple OSS Distributions OSIterator * iter;
3945*1031c584SApple OSS Distributions OSObject * next;
3946*1031c584SApple OSS Distributions IOPowerConnection * connection;
3947*1031c584SApple OSS Distributions OSArray * children = NULL;
3948*1031c584SApple OSS Distributions IOPMrootDomain * rootDomain;
3949*1031c584SApple OSS Distributions bool delayNotify = false;
3950*1031c584SApple OSS Distributions
3951*1031c584SApple OSS Distributions if ((fHeadNotePowerState != fCurrentPowerState) &&
3952*1031c584SApple OSS Distributions (IS_POWER_DROP == fIsPreChange) &&
3953*1031c584SApple OSS Distributions ((rootDomain = getPMRootDomain()) == this)) {
3954*1031c584SApple OSS Distributions rootDomain->tracePoint( IS_POWER_DROP ?
3955*1031c584SApple OSS Distributions kIOPMTracePointSleepPowerPlaneDrivers :
3956*1031c584SApple OSS Distributions kIOPMTracePointWakePowerPlaneDrivers );
3957*1031c584SApple OSS Distributions }
3958*1031c584SApple OSS Distributions
3959*1031c584SApple OSS Distributions if (fStrictTreeOrder) {
3960*1031c584SApple OSS Distributions children = OSArray::withCapacity(8);
3961*1031c584SApple OSS Distributions }
3962*1031c584SApple OSS Distributions
3963*1031c584SApple OSS Distributions // Sum child power consumption in notifyChild()
3964*1031c584SApple OSS Distributions fHeadNotePowerArrayEntry->staticPower = 0;
3965*1031c584SApple OSS Distributions
3966*1031c584SApple OSS Distributions iter = getChildIterator(gIOPowerPlane);
3967*1031c584SApple OSS Distributions if (iter) {
3968*1031c584SApple OSS Distributions while ((next = iter->getNextObject())) {
3969*1031c584SApple OSS Distributions if ((connection = OSDynamicCast(IOPowerConnection, next))) {
3970*1031c584SApple OSS Distributions if (connection->getReadyFlag() == false) {
3971*1031c584SApple OSS Distributions PM_LOG3("[%s] %s: connection not ready\n",
3972*1031c584SApple OSS Distributions getName(), __FUNCTION__);
3973*1031c584SApple OSS Distributions continue;
3974*1031c584SApple OSS Distributions }
3975*1031c584SApple OSS Distributions
3976*1031c584SApple OSS Distributions // Mechanism to postpone the did-change notification to
3977*1031c584SApple OSS Distributions // certain power children to order those children last.
3978*1031c584SApple OSS Distributions // Cannot be used together with strict tree ordering.
3979*1031c584SApple OSS Distributions
3980*1031c584SApple OSS Distributions if (!fIsPreChange &&
3981*1031c584SApple OSS Distributions connection->delayChildNotification &&
3982*1031c584SApple OSS Distributions getPMRootDomain()->shouldDelayChildNotification(this)) {
3983*1031c584SApple OSS Distributions if (!children) {
3984*1031c584SApple OSS Distributions children = OSArray::withCapacity(8);
3985*1031c584SApple OSS Distributions if (children) {
3986*1031c584SApple OSS Distributions delayNotify = true;
3987*1031c584SApple OSS Distributions }
3988*1031c584SApple OSS Distributions }
3989*1031c584SApple OSS Distributions if (delayNotify) {
3990*1031c584SApple OSS Distributions children->setObject( connection );
3991*1031c584SApple OSS Distributions continue;
3992*1031c584SApple OSS Distributions }
3993*1031c584SApple OSS Distributions }
3994*1031c584SApple OSS Distributions
3995*1031c584SApple OSS Distributions if (!delayNotify && children) {
3996*1031c584SApple OSS Distributions children->setObject( connection );
3997*1031c584SApple OSS Distributions } else {
3998*1031c584SApple OSS Distributions notifyChild( connection );
3999*1031c584SApple OSS Distributions }
4000*1031c584SApple OSS Distributions }
4001*1031c584SApple OSS Distributions }
4002*1031c584SApple OSS Distributions iter->release();
4003*1031c584SApple OSS Distributions }
4004*1031c584SApple OSS Distributions
4005*1031c584SApple OSS Distributions if (children && (children->getCount() == 0)) {
4006*1031c584SApple OSS Distributions children->release();
4007*1031c584SApple OSS Distributions children = NULL;
4008*1031c584SApple OSS Distributions }
4009*1031c584SApple OSS Distributions if (children) {
4010*1031c584SApple OSS Distributions assert(fNotifyChildArray == NULL);
4011*1031c584SApple OSS Distributions fNotifyChildArray = children;
4012*1031c584SApple OSS Distributions MS_PUSH(fMachineState);
4013*1031c584SApple OSS Distributions
4014*1031c584SApple OSS Distributions if (delayNotify) {
4015*1031c584SApple OSS Distributions // Block until all non-delayed children have acked their
4016*1031c584SApple OSS Distributions // notification. Then notify the remaining delayed child
4017*1031c584SApple OSS Distributions // in the array. This is used to hold off graphics child
4018*1031c584SApple OSS Distributions // notification while the rest of the system powers up.
4019*1031c584SApple OSS Distributions // If a hid tickle arrives during this time, the delayed
4020*1031c584SApple OSS Distributions // children are immediately notified and root domain will
4021*1031c584SApple OSS Distributions // not clamp power for dark wake.
4022*1031c584SApple OSS Distributions
4023*1031c584SApple OSS Distributions fMachineState = kIOPM_NotifyChildrenDelayed;
4024*1031c584SApple OSS Distributions PM_LOG2("%s: %d children in delayed array\n",
4025*1031c584SApple OSS Distributions getName(), children->getCount());
4026*1031c584SApple OSS Distributions } else {
4027*1031c584SApple OSS Distributions // Child array created to support strict notification order.
4028*1031c584SApple OSS Distributions // Notify children in the array one at a time.
4029*1031c584SApple OSS Distributions
4030*1031c584SApple OSS Distributions fMachineState = kIOPM_NotifyChildrenOrdered;
4031*1031c584SApple OSS Distributions }
4032*1031c584SApple OSS Distributions }
4033*1031c584SApple OSS Distributions }
4034*1031c584SApple OSS Distributions
4035*1031c584SApple OSS Distributions //*********************************************************************************
4036*1031c584SApple OSS Distributions // [private] notifyChildrenOrdered
4037*1031c584SApple OSS Distributions //*********************************************************************************
4038*1031c584SApple OSS Distributions
4039*1031c584SApple OSS Distributions void
notifyChildrenOrdered(void)4040*1031c584SApple OSS Distributions IOService::notifyChildrenOrdered( void )
4041*1031c584SApple OSS Distributions {
4042*1031c584SApple OSS Distributions PM_ASSERT_IN_GATE();
4043*1031c584SApple OSS Distributions assert(fNotifyChildArray);
4044*1031c584SApple OSS Distributions assert(fMachineState == kIOPM_NotifyChildrenOrdered);
4045*1031c584SApple OSS Distributions
4046*1031c584SApple OSS Distributions // Notify one child, wait for it to ack, then repeat for next child.
4047*1031c584SApple OSS Distributions // This is a workaround for some drivers with multiple instances at
4048*1031c584SApple OSS Distributions // the same branch in the power tree, but the driver is slow to power
4049*1031c584SApple OSS Distributions // up unless the tree ordering is observed. Problem observed only on
4050*1031c584SApple OSS Distributions // system wake, not on system sleep.
4051*1031c584SApple OSS Distributions //
4052*1031c584SApple OSS Distributions // We have the ability to power off in reverse child index order.
4053*1031c584SApple OSS Distributions // That works nicely on some machines, but not on all HW configs.
4054*1031c584SApple OSS Distributions
4055*1031c584SApple OSS Distributions if (fNotifyChildArray->getCount()) {
4056*1031c584SApple OSS Distributions IOPowerConnection * connection;
4057*1031c584SApple OSS Distributions connection = (IOPowerConnection *) fNotifyChildArray->getObject(0);
4058*1031c584SApple OSS Distributions notifyChild( connection );
4059*1031c584SApple OSS Distributions fNotifyChildArray->removeObject(0);
4060*1031c584SApple OSS Distributions } else {
4061*1031c584SApple OSS Distributions fNotifyChildArray->release();
4062*1031c584SApple OSS Distributions fNotifyChildArray = NULL;
4063*1031c584SApple OSS Distributions
4064*1031c584SApple OSS Distributions MS_POP(); // pushed by notifyChildren()
4065*1031c584SApple OSS Distributions }
4066*1031c584SApple OSS Distributions }
4067*1031c584SApple OSS Distributions
4068*1031c584SApple OSS Distributions //*********************************************************************************
4069*1031c584SApple OSS Distributions // [private] notifyChildrenDelayed
4070*1031c584SApple OSS Distributions //*********************************************************************************
4071*1031c584SApple OSS Distributions
4072*1031c584SApple OSS Distributions void
notifyChildrenDelayed(void)4073*1031c584SApple OSS Distributions IOService::notifyChildrenDelayed( void )
4074*1031c584SApple OSS Distributions {
4075*1031c584SApple OSS Distributions IOPowerConnection * connection;
4076*1031c584SApple OSS Distributions
4077*1031c584SApple OSS Distributions PM_ASSERT_IN_GATE();
4078*1031c584SApple OSS Distributions assert(fNotifyChildArray);
4079*1031c584SApple OSS Distributions assert(fMachineState == kIOPM_NotifyChildrenDelayed);
4080*1031c584SApple OSS Distributions
4081*1031c584SApple OSS Distributions // Wait after all non-delayed children and interested drivers have ack'ed,
4082*1031c584SApple OSS Distributions // then notify all delayed children. If notify delay is canceled, child
4083*1031c584SApple OSS Distributions // acks may be outstanding with PM blocked on fHeadNotePendingAcks != 0.
4084*1031c584SApple OSS Distributions // But the handling for either case is identical.
4085*1031c584SApple OSS Distributions
4086*1031c584SApple OSS Distributions for (int i = 0;; i++) {
4087*1031c584SApple OSS Distributions connection = (IOPowerConnection *) fNotifyChildArray->getObject(i);
4088*1031c584SApple OSS Distributions if (!connection) {
4089*1031c584SApple OSS Distributions break;
4090*1031c584SApple OSS Distributions }
4091*1031c584SApple OSS Distributions
4092*1031c584SApple OSS Distributions notifyChild( connection );
4093*1031c584SApple OSS Distributions }
4094*1031c584SApple OSS Distributions
4095*1031c584SApple OSS Distributions PM_LOG2("%s: notified delayed children\n", getName());
4096*1031c584SApple OSS Distributions fNotifyChildArray->release();
4097*1031c584SApple OSS Distributions fNotifyChildArray = NULL;
4098*1031c584SApple OSS Distributions
4099*1031c584SApple OSS Distributions MS_POP(); // pushed by notifyChildren()
4100*1031c584SApple OSS Distributions }
4101*1031c584SApple OSS Distributions
4102*1031c584SApple OSS Distributions //*********************************************************************************
4103*1031c584SApple OSS Distributions // [private] notifyAll
4104*1031c584SApple OSS Distributions //*********************************************************************************
4105*1031c584SApple OSS Distributions
4106*1031c584SApple OSS Distributions IOReturn
notifyAll(uint32_t nextMS)4107*1031c584SApple OSS Distributions IOService::notifyAll( uint32_t nextMS )
4108*1031c584SApple OSS Distributions {
4109*1031c584SApple OSS Distributions // Save the machine state to be restored by notifyInterestedDriversDone()
4110*1031c584SApple OSS Distributions
4111*1031c584SApple OSS Distributions PM_ASSERT_IN_GATE();
4112*1031c584SApple OSS Distributions MS_PUSH(nextMS);
4113*1031c584SApple OSS Distributions fMachineState = kIOPM_DriverThreadCallDone;
4114*1031c584SApple OSS Distributions fDriverCallReason = fIsPreChange ?
4115*1031c584SApple OSS Distributions kDriverCallInformPreChange : kDriverCallInformPostChange;
4116*1031c584SApple OSS Distributions
4117*1031c584SApple OSS Distributions if (!notifyInterestedDrivers()) {
4118*1031c584SApple OSS Distributions notifyInterestedDriversDone();
4119*1031c584SApple OSS Distributions }
4120*1031c584SApple OSS Distributions
4121*1031c584SApple OSS Distributions return IOPMWillAckLater;
4122*1031c584SApple OSS Distributions }
4123*1031c584SApple OSS Distributions
4124*1031c584SApple OSS Distributions //*********************************************************************************
4125*1031c584SApple OSS Distributions // [private, static] pmDriverCallout
4126*1031c584SApple OSS Distributions //
4127*1031c584SApple OSS Distributions // Thread call context
4128*1031c584SApple OSS Distributions //*********************************************************************************
4129*1031c584SApple OSS Distributions
4130*1031c584SApple OSS Distributions IOReturn
actionDriverCalloutDone(OSObject * target,void * arg0,void * arg1,void * arg2,void * arg3)4131*1031c584SApple OSS Distributions IOService::actionDriverCalloutDone(
4132*1031c584SApple OSS Distributions OSObject * target,
4133*1031c584SApple OSS Distributions void * arg0, void * arg1,
4134*1031c584SApple OSS Distributions void * arg2, void * arg3 )
4135*1031c584SApple OSS Distributions {
4136*1031c584SApple OSS Distributions IOServicePM * pwrMgt = (IOServicePM *) arg0;
4137*1031c584SApple OSS Distributions
4138*1031c584SApple OSS Distributions assert( fDriverCallBusy );
4139*1031c584SApple OSS Distributions fDriverCallBusy = false;
4140*1031c584SApple OSS Distributions
4141*1031c584SApple OSS Distributions assert(gIOPMWorkQueue);
4142*1031c584SApple OSS Distributions gIOPMWorkQueue->signalWorkAvailable();
4143*1031c584SApple OSS Distributions
4144*1031c584SApple OSS Distributions return kIOReturnSuccess;
4145*1031c584SApple OSS Distributions }
4146*1031c584SApple OSS Distributions
4147*1031c584SApple OSS Distributions void
pmDriverCallout(IOService * from,__unused thread_call_param_t p)4148*1031c584SApple OSS Distributions IOService::pmDriverCallout( IOService * from,
4149*1031c584SApple OSS Distributions __unused thread_call_param_t p)
4150*1031c584SApple OSS Distributions {
4151*1031c584SApple OSS Distributions assert(from);
4152*1031c584SApple OSS Distributions from->startDriverCalloutTimer();
4153*1031c584SApple OSS Distributions switch (from->fDriverCallReason) {
4154*1031c584SApple OSS Distributions case kDriverCallSetPowerState:
4155*1031c584SApple OSS Distributions from->driverSetPowerState();
4156*1031c584SApple OSS Distributions break;
4157*1031c584SApple OSS Distributions
4158*1031c584SApple OSS Distributions case kDriverCallInformPreChange:
4159*1031c584SApple OSS Distributions case kDriverCallInformPostChange:
4160*1031c584SApple OSS Distributions from->driverInformPowerChange();
4161*1031c584SApple OSS Distributions break;
4162*1031c584SApple OSS Distributions
4163*1031c584SApple OSS Distributions case kRootDomainInformPreChange:
4164*1031c584SApple OSS Distributions getPMRootDomain()->willNotifyPowerChildren(from->fHeadNotePowerState);
4165*1031c584SApple OSS Distributions break;
4166*1031c584SApple OSS Distributions
4167*1031c584SApple OSS Distributions default:
4168*1031c584SApple OSS Distributions panic("IOService::pmDriverCallout bad machine state %x",
4169*1031c584SApple OSS Distributions from->fDriverCallReason);
4170*1031c584SApple OSS Distributions }
4171*1031c584SApple OSS Distributions from->stopDriverCalloutTimer();
4172*1031c584SApple OSS Distributions
4173*1031c584SApple OSS Distributions gIOPMWorkLoop->runAction(actionDriverCalloutDone,
4174*1031c584SApple OSS Distributions /* target */ from,
4175*1031c584SApple OSS Distributions /* arg0 */ (void *) from->pwrMgt );
4176*1031c584SApple OSS Distributions }
4177*1031c584SApple OSS Distributions
4178*1031c584SApple OSS Distributions //*********************************************************************************
4179*1031c584SApple OSS Distributions // [private] driverSetPowerState
4180*1031c584SApple OSS Distributions //
4181*1031c584SApple OSS Distributions // Thread call context
4182*1031c584SApple OSS Distributions //*********************************************************************************
4183*1031c584SApple OSS Distributions
4184*1031c584SApple OSS Distributions void
driverSetPowerState(void)4185*1031c584SApple OSS Distributions IOService::driverSetPowerState( void )
4186*1031c584SApple OSS Distributions {
4187*1031c584SApple OSS Distributions IOPMPowerStateIndex powerState;
4188*1031c584SApple OSS Distributions DriverCallParam * param;
4189*1031c584SApple OSS Distributions IOPMDriverCallEntry callEntry;
4190*1031c584SApple OSS Distributions AbsoluteTime end;
4191*1031c584SApple OSS Distributions IOReturn result;
4192*1031c584SApple OSS Distributions uint32_t oldPowerState = getPowerState();
4193*1031c584SApple OSS Distributions const OSMetaClass *controllingDriverMetaClass = NULL;
4194*1031c584SApple OSS Distributions uint32_t controllingDriverRegistryEntryID = 0;
4195*1031c584SApple OSS Distributions
4196*1031c584SApple OSS Distributions assert( fDriverCallBusy );
4197*1031c584SApple OSS Distributions assert( fDriverCallParamPtr );
4198*1031c584SApple OSS Distributions assert( fDriverCallParamCount == 1 );
4199*1031c584SApple OSS Distributions
4200*1031c584SApple OSS Distributions param = (DriverCallParam *) fDriverCallParamPtr;
4201*1031c584SApple OSS Distributions powerState = fHeadNotePowerState;
4202*1031c584SApple OSS Distributions if (fControllingDriver) {
4203*1031c584SApple OSS Distributions controllingDriverMetaClass = fControllingDriver->getMetaClass();
4204*1031c584SApple OSS Distributions controllingDriverRegistryEntryID = (uint32_t)fControllingDriver->getRegistryEntryID();
4205*1031c584SApple OSS Distributions }
4206*1031c584SApple OSS Distributions
4207*1031c584SApple OSS Distributions if (assertPMDriverCall(&callEntry, kIOPMDriverCallMethodSetPowerState)) {
4208*1031c584SApple OSS Distributions SOCD_TRACE_XNU_START(PM_SET_POWER_STATE,
4209*1031c584SApple OSS Distributions ADDR(controllingDriverMetaClass),
4210*1031c584SApple OSS Distributions ADDR(this->getMetaClass()),
4211*1031c584SApple OSS Distributions PACK_2X32(VALUE(this->getRegistryEntryID()), VALUE(controllingDriverRegistryEntryID)),
4212*1031c584SApple OSS Distributions PACK_2X32(VALUE(powerState), VALUE(oldPowerState)));
4213*1031c584SApple OSS Distributions
4214*1031c584SApple OSS Distributions OUR_PMLogFuncStart(kPMLogProgramHardware, (uintptr_t) this, powerState);
4215*1031c584SApple OSS Distributions clock_get_uptime(&fDriverCallStartTime);
4216*1031c584SApple OSS Distributions
4217*1031c584SApple OSS Distributions if (reserved && reserved->uvars && reserved->uvars->userServer) {
4218*1031c584SApple OSS Distributions result = reserved->uvars->userServer->serviceSetPowerState(fControllingDriver, this, fHeadNotePowerArrayEntry->capabilityFlags, powerState);
4219*1031c584SApple OSS Distributions } else {
4220*1031c584SApple OSS Distributions result = fControllingDriver->setPowerState( powerState, this );
4221*1031c584SApple OSS Distributions }
4222*1031c584SApple OSS Distributions clock_get_uptime(&end);
4223*1031c584SApple OSS Distributions OUR_PMLogFuncEnd(kPMLogProgramHardware, (uintptr_t) this, (UInt32) result);
4224*1031c584SApple OSS Distributions SOCD_TRACE_XNU_END(PM_SET_POWER_STATE,
4225*1031c584SApple OSS Distributions ADDR(controllingDriverMetaClass),
4226*1031c584SApple OSS Distributions ADDR(this->getMetaClass()),
4227*1031c584SApple OSS Distributions PACK_2X32(VALUE(this->getRegistryEntryID()), VALUE(controllingDriverRegistryEntryID)),
4228*1031c584SApple OSS Distributions PACK_2X32(VALUE(powerState), VALUE(result)));
4229*1031c584SApple OSS Distributions
4230*1031c584SApple OSS Distributions deassertPMDriverCall(&callEntry);
4231*1031c584SApple OSS Distributions
4232*1031c584SApple OSS Distributions // Record the most recent max power state residency timings.
4233*1031c584SApple OSS Distributions // Use with DeviceActiveTimestamp to diagnose tickle issues.
4234*1031c584SApple OSS Distributions if (powerState == fHighestPowerState) {
4235*1031c584SApple OSS Distributions fMaxPowerStateEntryTime = end;
4236*1031c584SApple OSS Distributions } else if (oldPowerState == fHighestPowerState) {
4237*1031c584SApple OSS Distributions fMaxPowerStateExitTime = end;
4238*1031c584SApple OSS Distributions }
4239*1031c584SApple OSS Distributions
4240*1031c584SApple OSS Distributions if (result < 0) {
4241*1031c584SApple OSS Distributions PM_LOG("%s::setPowerState(%p, %lu -> %lu) returned 0x%x\n",
4242*1031c584SApple OSS Distributions fName, OBFUSCATE(this), fCurrentPowerState, powerState, result);
4243*1031c584SApple OSS Distributions }
4244*1031c584SApple OSS Distributions
4245*1031c584SApple OSS Distributions
4246*1031c584SApple OSS Distributions if ((result == IOPMAckImplied) || (result < 0)) {
4247*1031c584SApple OSS Distributions uint64_t nsec;
4248*1031c584SApple OSS Distributions
4249*1031c584SApple OSS Distributions SUB_ABSOLUTETIME(&end, &fDriverCallStartTime);
4250*1031c584SApple OSS Distributions absolutetime_to_nanoseconds(end, &nsec);
4251*1031c584SApple OSS Distributions if (nsec > gIOPMSetPowerStateLogNS) {
4252*1031c584SApple OSS Distributions getPMRootDomain()->pmStatsRecordApplicationResponse(
4253*1031c584SApple OSS Distributions gIOPMStatsDriverPSChangeSlow,
4254*1031c584SApple OSS Distributions fName, kDriverCallSetPowerState, NS_TO_MS(nsec), getRegistryEntryID(),
4255*1031c584SApple OSS Distributions NULL, powerState);
4256*1031c584SApple OSS Distributions }
4257*1031c584SApple OSS Distributions }
4258*1031c584SApple OSS Distributions } else {
4259*1031c584SApple OSS Distributions result = kIOPMAckImplied;
4260*1031c584SApple OSS Distributions }
4261*1031c584SApple OSS Distributions
4262*1031c584SApple OSS Distributions param->Result = result;
4263*1031c584SApple OSS Distributions }
4264*1031c584SApple OSS Distributions
4265*1031c584SApple OSS Distributions //*********************************************************************************
4266*1031c584SApple OSS Distributions // [private] driverInformPowerChange
4267*1031c584SApple OSS Distributions //
4268*1031c584SApple OSS Distributions // Thread call context
4269*1031c584SApple OSS Distributions //*********************************************************************************
4270*1031c584SApple OSS Distributions
4271*1031c584SApple OSS Distributions void
driverInformPowerChange(void)4272*1031c584SApple OSS Distributions IOService::driverInformPowerChange( void )
4273*1031c584SApple OSS Distributions {
4274*1031c584SApple OSS Distributions IOPMinformee * informee;
4275*1031c584SApple OSS Distributions IOService * driver;
4276*1031c584SApple OSS Distributions DriverCallParam * param;
4277*1031c584SApple OSS Distributions IOPMDriverCallEntry callEntry;
4278*1031c584SApple OSS Distributions IOPMPowerFlags powerFlags;
4279*1031c584SApple OSS Distributions IOPMPowerStateIndex powerState;
4280*1031c584SApple OSS Distributions AbsoluteTime end;
4281*1031c584SApple OSS Distributions IOReturn result;
4282*1031c584SApple OSS Distributions IOItemCount count;
4283*1031c584SApple OSS Distributions IOOptionBits callMethod = (fDriverCallReason == kDriverCallInformPreChange) ?
4284*1031c584SApple OSS Distributions kIOPMDriverCallMethodWillChange : kIOPMDriverCallMethodDidChange;
4285*1031c584SApple OSS Distributions
4286*1031c584SApple OSS Distributions assert( fDriverCallBusy );
4287*1031c584SApple OSS Distributions assert( fDriverCallParamPtr );
4288*1031c584SApple OSS Distributions assert( fDriverCallParamCount );
4289*1031c584SApple OSS Distributions
4290*1031c584SApple OSS Distributions param = (DriverCallParam *) fDriverCallParamPtr;
4291*1031c584SApple OSS Distributions count = fDriverCallParamCount;
4292*1031c584SApple OSS Distributions
4293*1031c584SApple OSS Distributions powerFlags = fHeadNotePowerArrayEntry->capabilityFlags;
4294*1031c584SApple OSS Distributions powerState = fHeadNotePowerState;
4295*1031c584SApple OSS Distributions
4296*1031c584SApple OSS Distributions for (IOItemCount i = 0; i < count; i++) {
4297*1031c584SApple OSS Distributions informee = (IOPMinformee *) param->Target;
4298*1031c584SApple OSS Distributions driver = informee->whatObject;
4299*1031c584SApple OSS Distributions
4300*1031c584SApple OSS Distributions if (assertPMDriverCall(&callEntry, callMethod, informee)) {
4301*1031c584SApple OSS Distributions SOCD_TRACE_XNU_START(PM_INFORM_POWER_CHANGE,
4302*1031c584SApple OSS Distributions ADDR(driver->getMetaClass()),
4303*1031c584SApple OSS Distributions ADDR(this->getMetaClass()),
4304*1031c584SApple OSS Distributions PACK_2X32(VALUE(this->getRegistryEntryID()), VALUE(driver->getRegistryEntryID())),
4305*1031c584SApple OSS Distributions PACK_2X32(VALUE(powerState), VALUE(fDriverCallReason)));
4306*1031c584SApple OSS Distributions
4307*1031c584SApple OSS Distributions if (fDriverCallReason == kDriverCallInformPreChange) {
4308*1031c584SApple OSS Distributions OUR_PMLogFuncStart(kPMLogInformDriverPreChange, (uintptr_t) this, powerState);
4309*1031c584SApple OSS Distributions clock_get_uptime(&informee->startTime);
4310*1031c584SApple OSS Distributions result = driver->powerStateWillChangeTo(powerFlags, powerState, this);
4311*1031c584SApple OSS Distributions clock_get_uptime(&end);
4312*1031c584SApple OSS Distributions OUR_PMLogFuncEnd(kPMLogInformDriverPreChange, (uintptr_t) this, result);
4313*1031c584SApple OSS Distributions } else {
4314*1031c584SApple OSS Distributions OUR_PMLogFuncStart(kPMLogInformDriverPostChange, (uintptr_t) this, powerState);
4315*1031c584SApple OSS Distributions clock_get_uptime(&informee->startTime);
4316*1031c584SApple OSS Distributions result = driver->powerStateDidChangeTo(powerFlags, powerState, this);
4317*1031c584SApple OSS Distributions clock_get_uptime(&end);
4318*1031c584SApple OSS Distributions OUR_PMLogFuncEnd(kPMLogInformDriverPostChange, (uintptr_t) this, result);
4319*1031c584SApple OSS Distributions }
4320*1031c584SApple OSS Distributions
4321*1031c584SApple OSS Distributions SOCD_TRACE_XNU_END(PM_INFORM_POWER_CHANGE,
4322*1031c584SApple OSS Distributions ADDR(driver->getMetaClass()),
4323*1031c584SApple OSS Distributions ADDR(this->getMetaClass()),
4324*1031c584SApple OSS Distributions PACK_2X32(VALUE(this->getRegistryEntryID()), VALUE(driver->getRegistryEntryID())),
4325*1031c584SApple OSS Distributions PACK_2X32(VALUE(result), VALUE(fDriverCallReason)));
4326*1031c584SApple OSS Distributions
4327*1031c584SApple OSS Distributions deassertPMDriverCall(&callEntry);
4328*1031c584SApple OSS Distributions
4329*1031c584SApple OSS Distributions
4330*1031c584SApple OSS Distributions if ((result == IOPMAckImplied) || (result < 0)) {
4331*1031c584SApple OSS Distributions uint64_t nsec;
4332*1031c584SApple OSS Distributions
4333*1031c584SApple OSS Distributions SUB_ABSOLUTETIME(&end, &informee->startTime);
4334*1031c584SApple OSS Distributions absolutetime_to_nanoseconds(end, &nsec);
4335*1031c584SApple OSS Distributions if (nsec > gIOPMSetPowerStateLogNS) {
4336*1031c584SApple OSS Distributions getPMRootDomain()->pmStatsRecordApplicationResponse(
4337*1031c584SApple OSS Distributions gIOPMStatsDriverPSChangeSlow, driver->getName(),
4338*1031c584SApple OSS Distributions fDriverCallReason, NS_TO_MS(nsec), driver->getRegistryEntryID(),
4339*1031c584SApple OSS Distributions NULL, powerState);
4340*1031c584SApple OSS Distributions }
4341*1031c584SApple OSS Distributions }
4342*1031c584SApple OSS Distributions } else {
4343*1031c584SApple OSS Distributions result = kIOPMAckImplied;
4344*1031c584SApple OSS Distributions }
4345*1031c584SApple OSS Distributions
4346*1031c584SApple OSS Distributions param->Result = result;
4347*1031c584SApple OSS Distributions param++;
4348*1031c584SApple OSS Distributions }
4349*1031c584SApple OSS Distributions }
4350*1031c584SApple OSS Distributions
4351*1031c584SApple OSS Distributions //*********************************************************************************
4352*1031c584SApple OSS Distributions // [private, static] pmDriverCalloutTimer
4353*1031c584SApple OSS Distributions //
4354*1031c584SApple OSS Distributions // Thread call context.
4355*1031c584SApple OSS Distributions //*********************************************************************************
4356*1031c584SApple OSS Distributions
4357*1031c584SApple OSS Distributions void
startDriverCalloutTimer(void)4358*1031c584SApple OSS Distributions IOService::startDriverCalloutTimer( void )
4359*1031c584SApple OSS Distributions {
4360*1031c584SApple OSS Distributions AbsoluteTime deadline;
4361*1031c584SApple OSS Distributions boolean_t pending;
4362*1031c584SApple OSS Distributions
4363*1031c584SApple OSS Distributions clock_interval_to_deadline(gDriverCalloutTimer, kMillisecondScale, &deadline);
4364*1031c584SApple OSS Distributions
4365*1031c584SApple OSS Distributions retain();
4366*1031c584SApple OSS Distributions pending = thread_call_enter_delayed(fDriverCallTimer, deadline);
4367*1031c584SApple OSS Distributions if (pending) {
4368*1031c584SApple OSS Distributions release();
4369*1031c584SApple OSS Distributions }
4370*1031c584SApple OSS Distributions }
4371*1031c584SApple OSS Distributions
4372*1031c584SApple OSS Distributions void
stopDriverCalloutTimer(void)4373*1031c584SApple OSS Distributions IOService::stopDriverCalloutTimer( void )
4374*1031c584SApple OSS Distributions {
4375*1031c584SApple OSS Distributions boolean_t pending;
4376*1031c584SApple OSS Distributions
4377*1031c584SApple OSS Distributions pending = thread_call_cancel(fDriverCallTimer);
4378*1031c584SApple OSS Distributions if (pending) {
4379*1031c584SApple OSS Distributions release();
4380*1031c584SApple OSS Distributions }
4381*1031c584SApple OSS Distributions }
4382*1031c584SApple OSS Distributions
4383*1031c584SApple OSS Distributions void
pmDriverCalloutTimer(thread_call_param_t arg0,__unused thread_call_param_t arg1)4384*1031c584SApple OSS Distributions IOService::pmDriverCalloutTimer( thread_call_param_t arg0,
4385*1031c584SApple OSS Distributions __unused thread_call_param_t arg1)
4386*1031c584SApple OSS Distributions {
4387*1031c584SApple OSS Distributions assert(arg0);
4388*1031c584SApple OSS Distributions IOService *from = (IOService *) arg0;
4389*1031c584SApple OSS Distributions PM_LOG("PM waiting on pmDriverCallout(0x%x) to %s (%u ms)\n", from->fDriverCallReason, from->fName, gDriverCalloutTimer);
4390*1031c584SApple OSS Distributions from->release();
4391*1031c584SApple OSS Distributions }
4392*1031c584SApple OSS Distributions
4393*1031c584SApple OSS Distributions //*********************************************************************************
4394*1031c584SApple OSS Distributions // [private] notifyChild
4395*1031c584SApple OSS Distributions //
4396*1031c584SApple OSS Distributions // Notify a power domain child of an upcoming power change.
4397*1031c584SApple OSS Distributions // If the object acknowledges the current change, we return TRUE.
4398*1031c584SApple OSS Distributions //*********************************************************************************
4399*1031c584SApple OSS Distributions
4400*1031c584SApple OSS Distributions bool
notifyChild(IOPowerConnection * theNub)4401*1031c584SApple OSS Distributions IOService::notifyChild( IOPowerConnection * theNub )
4402*1031c584SApple OSS Distributions {
4403*1031c584SApple OSS Distributions IOReturn ret = IOPMAckImplied;
4404*1031c584SApple OSS Distributions unsigned long childPower;
4405*1031c584SApple OSS Distributions IOService * theChild;
4406*1031c584SApple OSS Distributions IOPMRequest * childRequest;
4407*1031c584SApple OSS Distributions IOPMPowerChangeFlags requestArg2;
4408*1031c584SApple OSS Distributions int requestType;
4409*1031c584SApple OSS Distributions
4410*1031c584SApple OSS Distributions PM_ASSERT_IN_GATE();
4411*1031c584SApple OSS Distributions theChild = (IOService *)(theNub->copyChildEntry(gIOPowerPlane));
4412*1031c584SApple OSS Distributions if (!theChild) {
4413*1031c584SApple OSS Distributions return true;
4414*1031c584SApple OSS Distributions }
4415*1031c584SApple OSS Distributions
4416*1031c584SApple OSS Distributions // Unless the child handles the notification immediately and returns
4417*1031c584SApple OSS Distributions // kIOPMAckImplied, we'll be awaiting their acknowledgement later.
4418*1031c584SApple OSS Distributions fHeadNotePendingAcks++;
4419*1031c584SApple OSS Distributions theNub->setAwaitingAck(true);
4420*1031c584SApple OSS Distributions
4421*1031c584SApple OSS Distributions requestArg2 = fHeadNoteChangeFlags;
4422*1031c584SApple OSS Distributions if (StateOrder(fHeadNotePowerState) < StateOrder(fCurrentPowerState)) {
4423*1031c584SApple OSS Distributions requestArg2 |= kIOPMDomainPowerDrop;
4424*1031c584SApple OSS Distributions }
4425*1031c584SApple OSS Distributions
4426*1031c584SApple OSS Distributions requestType = fIsPreChange ?
4427*1031c584SApple OSS Distributions kIOPMRequestTypePowerDomainWillChange :
4428*1031c584SApple OSS Distributions kIOPMRequestTypePowerDomainDidChange;
4429*1031c584SApple OSS Distributions
4430*1031c584SApple OSS Distributions childRequest = acquirePMRequest( theChild, requestType );
4431*1031c584SApple OSS Distributions if (childRequest) {
4432*1031c584SApple OSS Distributions theNub->retain();
4433*1031c584SApple OSS Distributions childRequest->fArg0 = (void *) fHeadNotePowerArrayEntry->outputPowerFlags;
4434*1031c584SApple OSS Distributions childRequest->fArg1 = (void *) theNub;
4435*1031c584SApple OSS Distributions childRequest->fArg2 = (void *)(uintptr_t) requestArg2;
4436*1031c584SApple OSS Distributions theChild->submitPMRequest( childRequest );
4437*1031c584SApple OSS Distributions ret = IOPMWillAckLater;
4438*1031c584SApple OSS Distributions } else {
4439*1031c584SApple OSS Distributions ret = IOPMAckImplied;
4440*1031c584SApple OSS Distributions fHeadNotePendingAcks--;
4441*1031c584SApple OSS Distributions theNub->setAwaitingAck(false);
4442*1031c584SApple OSS Distributions childPower = theChild->currentPowerConsumption();
4443*1031c584SApple OSS Distributions if (childPower == kIOPMUnknown) {
4444*1031c584SApple OSS Distributions fHeadNotePowerArrayEntry->staticPower = kIOPMUnknown;
4445*1031c584SApple OSS Distributions } else {
4446*1031c584SApple OSS Distributions if (fHeadNotePowerArrayEntry->staticPower != kIOPMUnknown) {
4447*1031c584SApple OSS Distributions fHeadNotePowerArrayEntry->staticPower += childPower;
4448*1031c584SApple OSS Distributions }
4449*1031c584SApple OSS Distributions }
4450*1031c584SApple OSS Distributions }
4451*1031c584SApple OSS Distributions
4452*1031c584SApple OSS Distributions theChild->release();
4453*1031c584SApple OSS Distributions return IOPMAckImplied == ret;
4454*1031c584SApple OSS Distributions }
4455*1031c584SApple OSS Distributions
4456*1031c584SApple OSS Distributions //*********************************************************************************
4457*1031c584SApple OSS Distributions // [private] notifyControllingDriver
4458*1031c584SApple OSS Distributions //*********************************************************************************
4459*1031c584SApple OSS Distributions
4460*1031c584SApple OSS Distributions bool
notifyControllingDriver(void)4461*1031c584SApple OSS Distributions IOService::notifyControllingDriver( void )
4462*1031c584SApple OSS Distributions {
4463*1031c584SApple OSS Distributions DriverCallParam * param;
4464*1031c584SApple OSS Distributions
4465*1031c584SApple OSS Distributions PM_ASSERT_IN_GATE();
4466*1031c584SApple OSS Distributions assert( fDriverCallParamCount == 0 );
4467*1031c584SApple OSS Distributions assert( fControllingDriver );
4468*1031c584SApple OSS Distributions
4469*1031c584SApple OSS Distributions if (fInitialSetPowerState) {
4470*1031c584SApple OSS Distributions fInitialSetPowerState = false;
4471*1031c584SApple OSS Distributions fHeadNoteChangeFlags |= kIOPMInitialPowerChange;
4472*1031c584SApple OSS Distributions
4473*1031c584SApple OSS Distributions // Driver specified flag to skip the inital setPowerState()
4474*1031c584SApple OSS Distributions if (fHeadNotePowerArrayEntry->capabilityFlags & kIOPMInitialDeviceState) {
4475*1031c584SApple OSS Distributions return false;
4476*1031c584SApple OSS Distributions }
4477*1031c584SApple OSS Distributions }
4478*1031c584SApple OSS Distributions
4479*1031c584SApple OSS Distributions param = (DriverCallParam *) fDriverCallParamPtr;
4480*1031c584SApple OSS Distributions if (!param) {
4481*1031c584SApple OSS Distributions param = IONew(DriverCallParam, 1);
4482*1031c584SApple OSS Distributions if (!param) {
4483*1031c584SApple OSS Distributions return false; // no memory
4484*1031c584SApple OSS Distributions }
4485*1031c584SApple OSS Distributions fDriverCallParamPtr = (void *) param;
4486*1031c584SApple OSS Distributions fDriverCallParamSlots = 1;
4487*1031c584SApple OSS Distributions }
4488*1031c584SApple OSS Distributions
4489*1031c584SApple OSS Distributions param->Target = fControllingDriver;
4490*1031c584SApple OSS Distributions fDriverCallParamCount = 1;
4491*1031c584SApple OSS Distributions fDriverTimer = -1;
4492*1031c584SApple OSS Distributions
4493*1031c584SApple OSS Distributions // Block state machine and wait for callout completion.
4494*1031c584SApple OSS Distributions assert(!fDriverCallBusy);
4495*1031c584SApple OSS Distributions fDriverCallBusy = true;
4496*1031c584SApple OSS Distributions thread_call_enter( fDriverCallEntry );
4497*1031c584SApple OSS Distributions
4498*1031c584SApple OSS Distributions return true;
4499*1031c584SApple OSS Distributions }
4500*1031c584SApple OSS Distributions
4501*1031c584SApple OSS Distributions //*********************************************************************************
4502*1031c584SApple OSS Distributions // [private] notifyControllingDriverDone
4503*1031c584SApple OSS Distributions //*********************************************************************************
4504*1031c584SApple OSS Distributions
4505*1031c584SApple OSS Distributions void
notifyControllingDriverDone(void)4506*1031c584SApple OSS Distributions IOService::notifyControllingDriverDone( void )
4507*1031c584SApple OSS Distributions {
4508*1031c584SApple OSS Distributions DriverCallParam * param;
4509*1031c584SApple OSS Distributions IOReturn result;
4510*1031c584SApple OSS Distributions
4511*1031c584SApple OSS Distributions PM_ASSERT_IN_GATE();
4512*1031c584SApple OSS Distributions param = (DriverCallParam *) fDriverCallParamPtr;
4513*1031c584SApple OSS Distributions
4514*1031c584SApple OSS Distributions assert( fDriverCallBusy == false );
4515*1031c584SApple OSS Distributions assert( fMachineState == kIOPM_DriverThreadCallDone );
4516*1031c584SApple OSS Distributions
4517*1031c584SApple OSS Distributions if (param && fDriverCallParamCount) {
4518*1031c584SApple OSS Distributions assert(fDriverCallParamCount == 1);
4519*1031c584SApple OSS Distributions
4520*1031c584SApple OSS Distributions // the return value from setPowerState()
4521*1031c584SApple OSS Distributions result = param->Result;
4522*1031c584SApple OSS Distributions
4523*1031c584SApple OSS Distributions if ((result == IOPMAckImplied) || (result < 0)) {
4524*1031c584SApple OSS Distributions fDriverTimer = 0;
4525*1031c584SApple OSS Distributions } else if (fDriverTimer) {
4526*1031c584SApple OSS Distributions assert(fDriverTimer == -1);
4527*1031c584SApple OSS Distributions
4528*1031c584SApple OSS Distributions // Driver has not acked, and has returned a positive result.
4529*1031c584SApple OSS Distributions // Enforce a minimum permissible timeout value.
4530*1031c584SApple OSS Distributions // Make the min value large enough so timeout is less likely
4531*1031c584SApple OSS Distributions // to occur if a driver misinterpreted that the return value
4532*1031c584SApple OSS Distributions // should be in microsecond units. And make it large enough
4533*1031c584SApple OSS Distributions // to be noticeable if a driver neglects to ack.
4534*1031c584SApple OSS Distributions
4535*1031c584SApple OSS Distributions if (result < kMinAckTimeoutTicks) {
4536*1031c584SApple OSS Distributions result = kMinAckTimeoutTicks;
4537*1031c584SApple OSS Distributions }
4538*1031c584SApple OSS Distributions
4539*1031c584SApple OSS Distributions fDriverTimer = (result / (ACK_TIMER_PERIOD / ns_per_us)) + 1;
4540*1031c584SApple OSS Distributions }
4541*1031c584SApple OSS Distributions // else, child has already acked and driver_timer reset to 0.
4542*1031c584SApple OSS Distributions
4543*1031c584SApple OSS Distributions fDriverCallParamCount = 0;
4544*1031c584SApple OSS Distributions
4545*1031c584SApple OSS Distributions if (fDriverTimer) {
4546*1031c584SApple OSS Distributions OUR_PMLog(kPMLogStartAckTimer, 0, 0);
4547*1031c584SApple OSS Distributions start_ack_timer();
4548*1031c584SApple OSS Distributions getPMRootDomain()->reset_watchdog_timer(this, result / USEC_PER_SEC + 1);
4549*1031c584SApple OSS Distributions }
4550*1031c584SApple OSS Distributions }
4551*1031c584SApple OSS Distributions
4552*1031c584SApple OSS Distributions MS_POP(); // pushed by OurChangeSetPowerState()
4553*1031c584SApple OSS Distributions fIsPreChange = false;
4554*1031c584SApple OSS Distributions }
4555*1031c584SApple OSS Distributions
4556*1031c584SApple OSS Distributions //*********************************************************************************
4557*1031c584SApple OSS Distributions // [private] all_done
4558*1031c584SApple OSS Distributions //
4559*1031c584SApple OSS Distributions // A power change is done.
4560*1031c584SApple OSS Distributions //*********************************************************************************
4561*1031c584SApple OSS Distributions
4562*1031c584SApple OSS Distributions void
all_done(void)4563*1031c584SApple OSS Distributions IOService::all_done( void )
4564*1031c584SApple OSS Distributions {
4565*1031c584SApple OSS Distributions IOPMPowerStateIndex prevPowerState;
4566*1031c584SApple OSS Distributions const IOPMPSEntry * powerStatePtr;
4567*1031c584SApple OSS Distributions IOPMDriverCallEntry callEntry;
4568*1031c584SApple OSS Distributions uint32_t prevMachineState = fMachineState;
4569*1031c584SApple OSS Distributions bool actionCalled = false;
4570*1031c584SApple OSS Distributions uint64_t ts;
4571*1031c584SApple OSS Distributions
4572*1031c584SApple OSS Distributions fMachineState = kIOPM_Finished;
4573*1031c584SApple OSS Distributions
4574*1031c584SApple OSS Distributions if ((fHeadNoteChangeFlags & kIOPMSynchronize) &&
4575*1031c584SApple OSS Distributions ((prevMachineState == kIOPM_Finished) ||
4576*1031c584SApple OSS Distributions (prevMachineState == kIOPM_SyncFinish))) {
4577*1031c584SApple OSS Distributions // Sync operation and no power change occurred.
4578*1031c584SApple OSS Distributions // Do not inform driver and clients about this request completion,
4579*1031c584SApple OSS Distributions // except for the originator (root domain).
4580*1031c584SApple OSS Distributions
4581*1031c584SApple OSS Distributions PM_ACTION_CHANGE(actionPowerChangeDone,
4582*1031c584SApple OSS Distributions fHeadNotePowerState, fHeadNoteChangeFlags);
4583*1031c584SApple OSS Distributions
4584*1031c584SApple OSS Distributions if (getPMRequestType() == kIOPMRequestTypeSynchronizePowerTree) {
4585*1031c584SApple OSS Distributions powerChangeDone(fCurrentPowerState);
4586*1031c584SApple OSS Distributions } else if (fAdvisoryTickleUsed) {
4587*1031c584SApple OSS Distributions // Not root domain and advisory tickle target.
4588*1031c584SApple OSS Distributions // Re-adjust power after power tree sync at the 'did' pass
4589*1031c584SApple OSS Distributions // to recompute desire and adjust power state between dark
4590*1031c584SApple OSS Distributions // and full wake transitions. Root domain is responsible
4591*1031c584SApple OSS Distributions // for calling setAdvisoryTickleEnable() before starting
4592*1031c584SApple OSS Distributions // the kIOPMSynchronize power change.
4593*1031c584SApple OSS Distributions
4594*1031c584SApple OSS Distributions if (!fAdjustPowerScheduled &&
4595*1031c584SApple OSS Distributions (fHeadNoteChangeFlags & kIOPMDomainDidChange)) {
4596*1031c584SApple OSS Distributions IOPMRequest * request;
4597*1031c584SApple OSS Distributions request = acquirePMRequest( this, kIOPMRequestTypeAdjustPowerState );
4598*1031c584SApple OSS Distributions if (request) {
4599*1031c584SApple OSS Distributions submitPMRequest( request );
4600*1031c584SApple OSS Distributions fAdjustPowerScheduled = true;
4601*1031c584SApple OSS Distributions }
4602*1031c584SApple OSS Distributions }
4603*1031c584SApple OSS Distributions }
4604*1031c584SApple OSS Distributions
4605*1031c584SApple OSS Distributions return;
4606*1031c584SApple OSS Distributions }
4607*1031c584SApple OSS Distributions
4608*1031c584SApple OSS Distributions // our power change
4609*1031c584SApple OSS Distributions if (fHeadNoteChangeFlags & kIOPMSelfInitiated) {
4610*1031c584SApple OSS Distributions // power state changed
4611*1031c584SApple OSS Distributions if ((fHeadNoteChangeFlags & kIOPMNotDone) == 0) {
4612*1031c584SApple OSS Distributions trackSystemSleepPreventers(
4613*1031c584SApple OSS Distributions fCurrentPowerState, fHeadNotePowerState, fHeadNoteChangeFlags);
4614*1031c584SApple OSS Distributions
4615*1031c584SApple OSS Distributions // we changed, tell our parent
4616*1031c584SApple OSS Distributions requestDomainPower(fHeadNotePowerState);
4617*1031c584SApple OSS Distributions
4618*1031c584SApple OSS Distributions // yes, did power raise?
4619*1031c584SApple OSS Distributions if (StateOrder(fCurrentPowerState) < StateOrder(fHeadNotePowerState)) {
4620*1031c584SApple OSS Distributions // yes, inform clients and apps
4621*1031c584SApple OSS Distributions tellChangeUp(fHeadNotePowerState);
4622*1031c584SApple OSS Distributions }
4623*1031c584SApple OSS Distributions prevPowerState = fCurrentPowerState;
4624*1031c584SApple OSS Distributions // either way
4625*1031c584SApple OSS Distributions fCurrentPowerState = fHeadNotePowerState;
4626*1031c584SApple OSS Distributions PM_LOCK();
4627*1031c584SApple OSS Distributions if (fReportBuf) {
4628*1031c584SApple OSS Distributions ts = mach_absolute_time();
4629*1031c584SApple OSS Distributions STATEREPORT_SETSTATE(fReportBuf, (uint16_t) fCurrentPowerState, ts);
4630*1031c584SApple OSS Distributions }
4631*1031c584SApple OSS Distributions PM_UNLOCK();
4632*1031c584SApple OSS Distributions #if PM_VARS_SUPPORT
4633*1031c584SApple OSS Distributions fPMVars->myCurrentState = fCurrentPowerState;
4634*1031c584SApple OSS Distributions #endif
4635*1031c584SApple OSS Distributions OUR_PMLog(kPMLogChangeDone, fCurrentPowerState, prevPowerState);
4636*1031c584SApple OSS Distributions PM_ACTION_CHANGE(actionPowerChangeDone,
4637*1031c584SApple OSS Distributions prevPowerState, fHeadNoteChangeFlags);
4638*1031c584SApple OSS Distributions actionCalled = true;
4639*1031c584SApple OSS Distributions
4640*1031c584SApple OSS Distributions powerStatePtr = &fPowerStates[fCurrentPowerState];
4641*1031c584SApple OSS Distributions fCurrentCapabilityFlags = powerStatePtr->capabilityFlags;
4642*1031c584SApple OSS Distributions if (fCurrentCapabilityFlags & kIOPMStaticPowerValid) {
4643*1031c584SApple OSS Distributions fCurrentPowerConsumption = powerStatePtr->staticPower;
4644*1031c584SApple OSS Distributions }
4645*1031c584SApple OSS Distributions
4646*1031c584SApple OSS Distributions if (fHeadNoteChangeFlags & kIOPMRootChangeDown) {
4647*1031c584SApple OSS Distributions // Bump tickle generation count once the entire tree is down
4648*1031c584SApple OSS Distributions gIOPMTickleGeneration++;
4649*1031c584SApple OSS Distributions }
4650*1031c584SApple OSS Distributions
4651*1031c584SApple OSS Distributions // inform subclass policy-maker
4652*1031c584SApple OSS Distributions if (fPCDFunctionOverride && fParentsKnowState &&
4653*1031c584SApple OSS Distributions assertPMDriverCall(&callEntry, kIOPMDriverCallMethodChangeDone, NULL, kIOPMDriverCallNoInactiveCheck)) {
4654*1031c584SApple OSS Distributions powerChangeDone(prevPowerState);
4655*1031c584SApple OSS Distributions deassertPMDriverCall(&callEntry);
4656*1031c584SApple OSS Distributions }
4657*1031c584SApple OSS Distributions } else if (getPMRequestType() == kIOPMRequestTypeRequestPowerStateOverride) {
4658*1031c584SApple OSS Distributions // changePowerStateWithOverrideTo() was cancelled
4659*1031c584SApple OSS Distributions fOverrideMaxPowerState = kIOPMPowerStateMax;
4660*1031c584SApple OSS Distributions }
4661*1031c584SApple OSS Distributions }
4662*1031c584SApple OSS Distributions
4663*1031c584SApple OSS Distributions // parent-initiated power change
4664*1031c584SApple OSS Distributions if (fHeadNoteChangeFlags & kIOPMParentInitiated) {
4665*1031c584SApple OSS Distributions if (fHeadNoteChangeFlags & kIOPMRootChangeDown) {
4666*1031c584SApple OSS Distributions ParentChangeRootChangeDown();
4667*1031c584SApple OSS Distributions }
4668*1031c584SApple OSS Distributions
4669*1031c584SApple OSS Distributions // power state changed
4670*1031c584SApple OSS Distributions if ((fHeadNoteChangeFlags & kIOPMNotDone) == 0) {
4671*1031c584SApple OSS Distributions trackSystemSleepPreventers(
4672*1031c584SApple OSS Distributions fCurrentPowerState, fHeadNotePowerState, fHeadNoteChangeFlags);
4673*1031c584SApple OSS Distributions
4674*1031c584SApple OSS Distributions // did power raise?
4675*1031c584SApple OSS Distributions if (StateOrder(fCurrentPowerState) < StateOrder(fHeadNotePowerState)) {
4676*1031c584SApple OSS Distributions // yes, inform clients and apps
4677*1031c584SApple OSS Distributions tellChangeUp(fHeadNotePowerState);
4678*1031c584SApple OSS Distributions }
4679*1031c584SApple OSS Distributions // either way
4680*1031c584SApple OSS Distributions prevPowerState = fCurrentPowerState;
4681*1031c584SApple OSS Distributions fCurrentPowerState = fHeadNotePowerState;
4682*1031c584SApple OSS Distributions PM_LOCK();
4683*1031c584SApple OSS Distributions if (fReportBuf) {
4684*1031c584SApple OSS Distributions ts = mach_absolute_time();
4685*1031c584SApple OSS Distributions STATEREPORT_SETSTATE(fReportBuf, (uint16_t) fCurrentPowerState, ts);
4686*1031c584SApple OSS Distributions }
4687*1031c584SApple OSS Distributions PM_UNLOCK();
4688*1031c584SApple OSS Distributions #if PM_VARS_SUPPORT
4689*1031c584SApple OSS Distributions fPMVars->myCurrentState = fCurrentPowerState;
4690*1031c584SApple OSS Distributions #endif
4691*1031c584SApple OSS Distributions
4692*1031c584SApple OSS Distributions OUR_PMLog(kPMLogChangeDone, fCurrentPowerState, prevPowerState);
4693*1031c584SApple OSS Distributions PM_ACTION_CHANGE(actionPowerChangeDone,
4694*1031c584SApple OSS Distributions prevPowerState, fHeadNoteChangeFlags);
4695*1031c584SApple OSS Distributions actionCalled = true;
4696*1031c584SApple OSS Distributions
4697*1031c584SApple OSS Distributions powerStatePtr = &fPowerStates[fCurrentPowerState];
4698*1031c584SApple OSS Distributions fCurrentCapabilityFlags = powerStatePtr->capabilityFlags;
4699*1031c584SApple OSS Distributions if (fCurrentCapabilityFlags & kIOPMStaticPowerValid) {
4700*1031c584SApple OSS Distributions fCurrentPowerConsumption = powerStatePtr->staticPower;
4701*1031c584SApple OSS Distributions }
4702*1031c584SApple OSS Distributions
4703*1031c584SApple OSS Distributions // inform subclass policy-maker
4704*1031c584SApple OSS Distributions if (fPCDFunctionOverride && fParentsKnowState &&
4705*1031c584SApple OSS Distributions assertPMDriverCall(&callEntry, kIOPMDriverCallMethodChangeDone, NULL, kIOPMDriverCallNoInactiveCheck)) {
4706*1031c584SApple OSS Distributions powerChangeDone(prevPowerState);
4707*1031c584SApple OSS Distributions deassertPMDriverCall(&callEntry);
4708*1031c584SApple OSS Distributions }
4709*1031c584SApple OSS Distributions }
4710*1031c584SApple OSS Distributions }
4711*1031c584SApple OSS Distributions
4712*1031c584SApple OSS Distributions // When power rises enough to satisfy the tickle's desire for more power,
4713*1031c584SApple OSS Distributions // the condition preventing idle-timer from dropping power is removed.
4714*1031c584SApple OSS Distributions
4715*1031c584SApple OSS Distributions if (StateOrder(fCurrentPowerState) >= StateOrder(fIdleTimerMinPowerState)) {
4716*1031c584SApple OSS Distributions fIdleTimerMinPowerState = kPowerStateZero;
4717*1031c584SApple OSS Distributions }
4718*1031c584SApple OSS Distributions
4719*1031c584SApple OSS Distributions if (!actionCalled) {
4720*1031c584SApple OSS Distributions PM_ACTION_CHANGE(actionPowerChangeDone,
4721*1031c584SApple OSS Distributions fHeadNotePowerState, fHeadNoteChangeFlags);
4722*1031c584SApple OSS Distributions }
4723*1031c584SApple OSS Distributions }
4724*1031c584SApple OSS Distributions
4725*1031c584SApple OSS Distributions // MARK: -
4726*1031c584SApple OSS Distributions // MARK: Power Change Initiated by Driver
4727*1031c584SApple OSS Distributions
4728*1031c584SApple OSS Distributions //*********************************************************************************
4729*1031c584SApple OSS Distributions // [private] OurChangeStart
4730*1031c584SApple OSS Distributions //
4731*1031c584SApple OSS Distributions // Begin the processing of a power change initiated by us.
4732*1031c584SApple OSS Distributions //*********************************************************************************
4733*1031c584SApple OSS Distributions
4734*1031c584SApple OSS Distributions void
OurChangeStart(void)4735*1031c584SApple OSS Distributions IOService::OurChangeStart( void )
4736*1031c584SApple OSS Distributions {
4737*1031c584SApple OSS Distributions PM_ASSERT_IN_GATE();
4738*1031c584SApple OSS Distributions OUR_PMLog( kPMLogStartDeviceChange, fHeadNotePowerState, fCurrentPowerState );
4739*1031c584SApple OSS Distributions
4740*1031c584SApple OSS Distributions // fMaxPowerState is our maximum possible power state based on the current
4741*1031c584SApple OSS Distributions // power state of our parents. If we are trying to raise power beyond the
4742*1031c584SApple OSS Distributions // maximum, send an async request for more power to all parents.
4743*1031c584SApple OSS Distributions
4744*1031c584SApple OSS Distributions if (!IS_PM_ROOT && (StateOrder(fMaxPowerState) < StateOrder(fHeadNotePowerState))) {
4745*1031c584SApple OSS Distributions fHeadNoteChangeFlags |= kIOPMNotDone;
4746*1031c584SApple OSS Distributions requestDomainPower(fHeadNotePowerState);
4747*1031c584SApple OSS Distributions OurChangeFinish();
4748*1031c584SApple OSS Distributions return;
4749*1031c584SApple OSS Distributions }
4750*1031c584SApple OSS Distributions
4751*1031c584SApple OSS Distributions // Redundant power changes skips to the end of the state machine.
4752*1031c584SApple OSS Distributions
4753*1031c584SApple OSS Distributions if (!fInitialPowerChange && (fHeadNotePowerState == fCurrentPowerState)) {
4754*1031c584SApple OSS Distributions OurChangeFinish();
4755*1031c584SApple OSS Distributions return;
4756*1031c584SApple OSS Distributions }
4757*1031c584SApple OSS Distributions fInitialPowerChange = false;
4758*1031c584SApple OSS Distributions
4759*1031c584SApple OSS Distributions // Change started, but may not complete...
4760*1031c584SApple OSS Distributions // Can be canceled (power drop) or deferred (power rise).
4761*1031c584SApple OSS Distributions
4762*1031c584SApple OSS Distributions PM_ACTION_CHANGE(actionPowerChangeStart, fHeadNotePowerState, &fHeadNoteChangeFlags);
4763*1031c584SApple OSS Distributions
4764*1031c584SApple OSS Distributions // Two separate paths, depending if power is being raised or lowered.
4765*1031c584SApple OSS Distributions // Lowering power is subject to approval by clients of this service.
4766*1031c584SApple OSS Distributions
4767*1031c584SApple OSS Distributions if (IS_POWER_DROP) {
4768*1031c584SApple OSS Distributions fDoNotPowerDown = false;
4769*1031c584SApple OSS Distributions
4770*1031c584SApple OSS Distributions // Ask for persmission to drop power state
4771*1031c584SApple OSS Distributions fMachineState = kIOPM_OurChangeTellClientsPowerDown;
4772*1031c584SApple OSS Distributions fOutOfBandParameter = kNotifyApps;
4773*1031c584SApple OSS Distributions askChangeDown(fHeadNotePowerState);
4774*1031c584SApple OSS Distributions } else {
4775*1031c584SApple OSS Distributions // This service is raising power and parents are able to support the
4776*1031c584SApple OSS Distributions // new power state. However a parent may have already committed to
4777*1031c584SApple OSS Distributions // drop power, which might force this object to temporarily drop power.
4778*1031c584SApple OSS Distributions // This results in "oscillations" before the state machines converge
4779*1031c584SApple OSS Distributions // to a steady state.
4780*1031c584SApple OSS Distributions //
4781*1031c584SApple OSS Distributions // To prevent this, a child must make a power reservation against all
4782*1031c584SApple OSS Distributions // parents before raising power. If the reservation fails, indicating
4783*1031c584SApple OSS Distributions // that the child will be unable to sustain the higher power state,
4784*1031c584SApple OSS Distributions // then the child will signal the parent to adjust power, and the child
4785*1031c584SApple OSS Distributions // will defer its power change.
4786*1031c584SApple OSS Distributions
4787*1031c584SApple OSS Distributions IOReturn ret;
4788*1031c584SApple OSS Distributions
4789*1031c584SApple OSS Distributions // Reserve parent power necessary to achieve fHeadNotePowerState.
4790*1031c584SApple OSS Distributions ret = requestDomainPower( fHeadNotePowerState, kReserveDomainPower );
4791*1031c584SApple OSS Distributions if (ret != kIOReturnSuccess) {
4792*1031c584SApple OSS Distributions // Reservation failed, defer power rise.
4793*1031c584SApple OSS Distributions fHeadNoteChangeFlags |= kIOPMNotDone;
4794*1031c584SApple OSS Distributions OurChangeFinish();
4795*1031c584SApple OSS Distributions return;
4796*1031c584SApple OSS Distributions }
4797*1031c584SApple OSS Distributions
4798*1031c584SApple OSS Distributions OurChangeTellCapabilityWillChange();
4799*1031c584SApple OSS Distributions }
4800*1031c584SApple OSS Distributions }
4801*1031c584SApple OSS Distributions
4802*1031c584SApple OSS Distributions //*********************************************************************************
4803*1031c584SApple OSS Distributions // [private] requestDomainPowerApplier
4804*1031c584SApple OSS Distributions //
4805*1031c584SApple OSS Distributions // Call requestPowerDomainState() on all power parents.
4806*1031c584SApple OSS Distributions //*********************************************************************************
4807*1031c584SApple OSS Distributions
4808*1031c584SApple OSS Distributions struct IOPMRequestDomainPowerContext {
4809*1031c584SApple OSS Distributions IOService * child; // the requesting child
4810*1031c584SApple OSS Distributions IOPMPowerFlags requestPowerFlags;// power flags requested by child
4811*1031c584SApple OSS Distributions };
4812*1031c584SApple OSS Distributions
4813*1031c584SApple OSS Distributions static void
requestDomainPowerApplier(IORegistryEntry * entry,void * inContext)4814*1031c584SApple OSS Distributions requestDomainPowerApplier(
4815*1031c584SApple OSS Distributions IORegistryEntry * entry,
4816*1031c584SApple OSS Distributions void * inContext )
4817*1031c584SApple OSS Distributions {
4818*1031c584SApple OSS Distributions IOPowerConnection * connection;
4819*1031c584SApple OSS Distributions IOService * parent;
4820*1031c584SApple OSS Distributions IOPMRequestDomainPowerContext * context;
4821*1031c584SApple OSS Distributions
4822*1031c584SApple OSS Distributions if ((connection = OSDynamicCast(IOPowerConnection, entry)) == NULL) {
4823*1031c584SApple OSS Distributions return;
4824*1031c584SApple OSS Distributions }
4825*1031c584SApple OSS Distributions parent = (IOService *) connection->copyParentEntry(gIOPowerPlane);
4826*1031c584SApple OSS Distributions if (!parent) {
4827*1031c584SApple OSS Distributions return;
4828*1031c584SApple OSS Distributions }
4829*1031c584SApple OSS Distributions
4830*1031c584SApple OSS Distributions assert(inContext);
4831*1031c584SApple OSS Distributions context = (IOPMRequestDomainPowerContext *) inContext;
4832*1031c584SApple OSS Distributions
4833*1031c584SApple OSS Distributions if (connection->parentKnowsState() && connection->getReadyFlag()) {
4834*1031c584SApple OSS Distributions parent->requestPowerDomainState(
4835*1031c584SApple OSS Distributions context->requestPowerFlags,
4836*1031c584SApple OSS Distributions connection,
4837*1031c584SApple OSS Distributions IOPMLowestState);
4838*1031c584SApple OSS Distributions }
4839*1031c584SApple OSS Distributions
4840*1031c584SApple OSS Distributions parent->release();
4841*1031c584SApple OSS Distributions }
4842*1031c584SApple OSS Distributions
4843*1031c584SApple OSS Distributions //*********************************************************************************
4844*1031c584SApple OSS Distributions // [private] requestDomainPower
4845*1031c584SApple OSS Distributions //
4846*1031c584SApple OSS Distributions // Called by a power child to broadcast its desired power state to all parents.
4847*1031c584SApple OSS Distributions // If the child self-initiates a power change, it must call this function to
4848*1031c584SApple OSS Distributions // allow its parents to adjust power state.
4849*1031c584SApple OSS Distributions //*********************************************************************************
4850*1031c584SApple OSS Distributions
4851*1031c584SApple OSS Distributions IOReturn
requestDomainPower(IOPMPowerStateIndex ourPowerState,IOOptionBits options)4852*1031c584SApple OSS Distributions IOService::requestDomainPower(
4853*1031c584SApple OSS Distributions IOPMPowerStateIndex ourPowerState,
4854*1031c584SApple OSS Distributions IOOptionBits options )
4855*1031c584SApple OSS Distributions {
4856*1031c584SApple OSS Distributions IOPMPowerFlags requestPowerFlags;
4857*1031c584SApple OSS Distributions IOPMPowerStateIndex maxPowerState;
4858*1031c584SApple OSS Distributions IOPMRequestDomainPowerContext context;
4859*1031c584SApple OSS Distributions
4860*1031c584SApple OSS Distributions PM_ASSERT_IN_GATE();
4861*1031c584SApple OSS Distributions assert(ourPowerState < fNumberOfPowerStates);
4862*1031c584SApple OSS Distributions if (ourPowerState >= fNumberOfPowerStates) {
4863*1031c584SApple OSS Distributions return kIOReturnBadArgument;
4864*1031c584SApple OSS Distributions }
4865*1031c584SApple OSS Distributions if (IS_PM_ROOT) {
4866*1031c584SApple OSS Distributions return kIOReturnSuccess;
4867*1031c584SApple OSS Distributions }
4868*1031c584SApple OSS Distributions
4869*1031c584SApple OSS Distributions // Fetch our input power flags for the requested power state.
4870*1031c584SApple OSS Distributions // Parent request is stated in terms of required power flags.
4871*1031c584SApple OSS Distributions
4872*1031c584SApple OSS Distributions requestPowerFlags = fPowerStates[ourPowerState].inputPowerFlags;
4873*1031c584SApple OSS Distributions
4874*1031c584SApple OSS Distributions // Disregard the "previous request" for power reservation.
4875*1031c584SApple OSS Distributions
4876*1031c584SApple OSS Distributions if (((options & kReserveDomainPower) == 0) &&
4877*1031c584SApple OSS Distributions (fPreviousRequestPowerFlags == requestPowerFlags)) {
4878*1031c584SApple OSS Distributions // skip if domain already knows our requirements
4879*1031c584SApple OSS Distributions goto done;
4880*1031c584SApple OSS Distributions }
4881*1031c584SApple OSS Distributions fPreviousRequestPowerFlags = requestPowerFlags;
4882*1031c584SApple OSS Distributions
4883*1031c584SApple OSS Distributions // The results will be collected by fHeadNoteDomainTargetFlags
4884*1031c584SApple OSS Distributions context.child = this;
4885*1031c584SApple OSS Distributions context.requestPowerFlags = requestPowerFlags;
4886*1031c584SApple OSS Distributions fHeadNoteDomainTargetFlags = 0;
4887*1031c584SApple OSS Distributions applyToParents(requestDomainPowerApplier, &context, gIOPowerPlane);
4888*1031c584SApple OSS Distributions
4889*1031c584SApple OSS Distributions if (options & kReserveDomainPower) {
4890*1031c584SApple OSS Distributions maxPowerState = fControllingDriver->maxCapabilityForDomainState(
4891*1031c584SApple OSS Distributions fHeadNoteDomainTargetFlags );
4892*1031c584SApple OSS Distributions
4893*1031c584SApple OSS Distributions if (StateOrder(maxPowerState) < StateOrder(ourPowerState)) {
4894*1031c584SApple OSS Distributions PM_LOG1("%s: power desired %u:0x%x got %u:0x%x\n",
4895*1031c584SApple OSS Distributions getName(),
4896*1031c584SApple OSS Distributions (uint32_t) ourPowerState, (uint32_t) requestPowerFlags,
4897*1031c584SApple OSS Distributions (uint32_t) maxPowerState, (uint32_t) fHeadNoteDomainTargetFlags);
4898*1031c584SApple OSS Distributions return kIOReturnNoPower;
4899*1031c584SApple OSS Distributions }
4900*1031c584SApple OSS Distributions }
4901*1031c584SApple OSS Distributions
4902*1031c584SApple OSS Distributions done:
4903*1031c584SApple OSS Distributions return kIOReturnSuccess;
4904*1031c584SApple OSS Distributions }
4905*1031c584SApple OSS Distributions
4906*1031c584SApple OSS Distributions //*********************************************************************************
4907*1031c584SApple OSS Distributions // [private] OurSyncStart
4908*1031c584SApple OSS Distributions //*********************************************************************************
4909*1031c584SApple OSS Distributions
4910*1031c584SApple OSS Distributions void
OurSyncStart(void)4911*1031c584SApple OSS Distributions IOService::OurSyncStart( void )
4912*1031c584SApple OSS Distributions {
4913*1031c584SApple OSS Distributions PM_ASSERT_IN_GATE();
4914*1031c584SApple OSS Distributions
4915*1031c584SApple OSS Distributions if (fInitialPowerChange) {
4916*1031c584SApple OSS Distributions return;
4917*1031c584SApple OSS Distributions }
4918*1031c584SApple OSS Distributions
4919*1031c584SApple OSS Distributions PM_ACTION_CHANGE(actionPowerChangeStart, fHeadNotePowerState, &fHeadNoteChangeFlags);
4920*1031c584SApple OSS Distributions
4921*1031c584SApple OSS Distributions if (fHeadNoteChangeFlags & kIOPMNotDone) {
4922*1031c584SApple OSS Distributions OurChangeFinish();
4923*1031c584SApple OSS Distributions return;
4924*1031c584SApple OSS Distributions }
4925*1031c584SApple OSS Distributions
4926*1031c584SApple OSS Distributions if (fHeadNoteChangeFlags & kIOPMSyncTellPowerDown) {
4927*1031c584SApple OSS Distributions fDoNotPowerDown = false;
4928*1031c584SApple OSS Distributions
4929*1031c584SApple OSS Distributions // Ask for permission to drop power state
4930*1031c584SApple OSS Distributions fMachineState = kIOPM_SyncTellClientsPowerDown;
4931*1031c584SApple OSS Distributions fOutOfBandParameter = kNotifyApps;
4932*1031c584SApple OSS Distributions askChangeDown(fHeadNotePowerState);
4933*1031c584SApple OSS Distributions } else {
4934*1031c584SApple OSS Distributions // Only inform capability app and clients.
4935*1031c584SApple OSS Distributions tellSystemCapabilityChange( kIOPM_SyncNotifyWillChange );
4936*1031c584SApple OSS Distributions }
4937*1031c584SApple OSS Distributions }
4938*1031c584SApple OSS Distributions
4939*1031c584SApple OSS Distributions //*********************************************************************************
4940*1031c584SApple OSS Distributions // [private] OurChangeTellClientsPowerDown
4941*1031c584SApple OSS Distributions //
4942*1031c584SApple OSS Distributions // All applications and kernel clients have acknowledged our permission to drop
4943*1031c584SApple OSS Distributions // power. Here we notify them that we will lower the power and wait for acks.
4944*1031c584SApple OSS Distributions //*********************************************************************************
4945*1031c584SApple OSS Distributions
4946*1031c584SApple OSS Distributions void
OurChangeTellClientsPowerDown(void)4947*1031c584SApple OSS Distributions IOService::OurChangeTellClientsPowerDown( void )
4948*1031c584SApple OSS Distributions {
4949*1031c584SApple OSS Distributions if (!IS_ROOT_DOMAIN) {
4950*1031c584SApple OSS Distributions fMachineState = kIOPM_OurChangeTellPriorityClientsPowerDown;
4951*1031c584SApple OSS Distributions } else {
4952*1031c584SApple OSS Distributions fMachineState = kIOPM_OurChangeTellUserPMPolicyPowerDown;
4953*1031c584SApple OSS Distributions }
4954*1031c584SApple OSS Distributions tellChangeDown1(fHeadNotePowerState);
4955*1031c584SApple OSS Distributions }
4956*1031c584SApple OSS Distributions
4957*1031c584SApple OSS Distributions //*********************************************************************************
4958*1031c584SApple OSS Distributions // [private] OurChangeTellUserPMPolicyPowerDown
4959*1031c584SApple OSS Distributions //
4960*1031c584SApple OSS Distributions // All applications and kernel clients have acknowledged our permission to drop
4961*1031c584SApple OSS Distributions // power. Here we notify power management policy in user-space and wait for acks
4962*1031c584SApple OSS Distributions // one last time before we lower power
4963*1031c584SApple OSS Distributions //*********************************************************************************
4964*1031c584SApple OSS Distributions void
OurChangeTellUserPMPolicyPowerDown(void)4965*1031c584SApple OSS Distributions IOService::OurChangeTellUserPMPolicyPowerDown( void )
4966*1031c584SApple OSS Distributions {
4967*1031c584SApple OSS Distributions fMachineState = kIOPM_OurChangeTellPriorityClientsPowerDown;
4968*1031c584SApple OSS Distributions fOutOfBandParameter = kNotifyApps;
4969*1031c584SApple OSS Distributions
4970*1031c584SApple OSS Distributions tellClientsWithResponse(kIOPMMessageLastCallBeforeSleep);
4971*1031c584SApple OSS Distributions }
4972*1031c584SApple OSS Distributions
4973*1031c584SApple OSS Distributions //*********************************************************************************
4974*1031c584SApple OSS Distributions // [private] OurChangeTellPriorityClientsPowerDown
4975*1031c584SApple OSS Distributions //
4976*1031c584SApple OSS Distributions // All applications and kernel clients have acknowledged our intention to drop
4977*1031c584SApple OSS Distributions // power. Here we notify "priority" clients that we are lowering power.
4978*1031c584SApple OSS Distributions //*********************************************************************************
4979*1031c584SApple OSS Distributions
4980*1031c584SApple OSS Distributions void
OurChangeTellPriorityClientsPowerDown(void)4981*1031c584SApple OSS Distributions IOService::OurChangeTellPriorityClientsPowerDown( void )
4982*1031c584SApple OSS Distributions {
4983*1031c584SApple OSS Distributions fMachineState = kIOPM_OurChangeNotifyInterestedDriversWillChange;
4984*1031c584SApple OSS Distributions tellChangeDown2(fHeadNotePowerState);
4985*1031c584SApple OSS Distributions }
4986*1031c584SApple OSS Distributions
4987*1031c584SApple OSS Distributions //*********************************************************************************
4988*1031c584SApple OSS Distributions // [private] OurChangeTellCapabilityWillChange
4989*1031c584SApple OSS Distributions //
4990*1031c584SApple OSS Distributions // Extra stage for root domain to notify apps and drivers about the
4991*1031c584SApple OSS Distributions // system capability change when raising power state.
4992*1031c584SApple OSS Distributions //*********************************************************************************
4993*1031c584SApple OSS Distributions
4994*1031c584SApple OSS Distributions void
OurChangeTellCapabilityWillChange(void)4995*1031c584SApple OSS Distributions IOService::OurChangeTellCapabilityWillChange( void )
4996*1031c584SApple OSS Distributions {
4997*1031c584SApple OSS Distributions if (!IS_ROOT_DOMAIN) {
4998*1031c584SApple OSS Distributions return OurChangeNotifyInterestedDriversWillChange();
4999*1031c584SApple OSS Distributions }
5000*1031c584SApple OSS Distributions
5001*1031c584SApple OSS Distributions tellSystemCapabilityChange( kIOPM_OurChangeNotifyInterestedDriversWillChange );
5002*1031c584SApple OSS Distributions }
5003*1031c584SApple OSS Distributions
5004*1031c584SApple OSS Distributions //*********************************************************************************
5005*1031c584SApple OSS Distributions // [private] OurChangeNotifyInterestedDriversWillChange
5006*1031c584SApple OSS Distributions //
5007*1031c584SApple OSS Distributions // All applications and kernel clients have acknowledged our power state change.
5008*1031c584SApple OSS Distributions // Here we notify interested drivers pre-change.
5009*1031c584SApple OSS Distributions //*********************************************************************************
5010*1031c584SApple OSS Distributions
5011*1031c584SApple OSS Distributions void
OurChangeNotifyInterestedDriversWillChange(void)5012*1031c584SApple OSS Distributions IOService::OurChangeNotifyInterestedDriversWillChange( void )
5013*1031c584SApple OSS Distributions {
5014*1031c584SApple OSS Distributions IOPMrootDomain * rootDomain;
5015*1031c584SApple OSS Distributions if ((rootDomain = getPMRootDomain()) == this) {
5016*1031c584SApple OSS Distributions if (IS_POWER_DROP) {
5017*1031c584SApple OSS Distributions rootDomain->tracePoint( kIOPMTracePointSleepWillChangeInterests );
5018*1031c584SApple OSS Distributions } else {
5019*1031c584SApple OSS Distributions rootDomain->tracePoint( kIOPMTracePointWakeWillChangeInterests );
5020*1031c584SApple OSS Distributions }
5021*1031c584SApple OSS Distributions }
5022*1031c584SApple OSS Distributions
5023*1031c584SApple OSS Distributions notifyAll( kIOPM_OurChangeSetPowerState );
5024*1031c584SApple OSS Distributions }
5025*1031c584SApple OSS Distributions
5026*1031c584SApple OSS Distributions //*********************************************************************************
5027*1031c584SApple OSS Distributions // [private] OurChangeSetPowerState
5028*1031c584SApple OSS Distributions //
5029*1031c584SApple OSS Distributions // Instruct our controlling driver to program the hardware for the power state
5030*1031c584SApple OSS Distributions // change. Wait for async completions.
5031*1031c584SApple OSS Distributions //*********************************************************************************
5032*1031c584SApple OSS Distributions
5033*1031c584SApple OSS Distributions void
OurChangeSetPowerState(void)5034*1031c584SApple OSS Distributions IOService::OurChangeSetPowerState( void )
5035*1031c584SApple OSS Distributions {
5036*1031c584SApple OSS Distributions MS_PUSH( kIOPM_OurChangeWaitForPowerSettle );
5037*1031c584SApple OSS Distributions fMachineState = kIOPM_DriverThreadCallDone;
5038*1031c584SApple OSS Distributions fDriverCallReason = kDriverCallSetPowerState;
5039*1031c584SApple OSS Distributions
5040*1031c584SApple OSS Distributions if (notifyControllingDriver() == false) {
5041*1031c584SApple OSS Distributions notifyControllingDriverDone();
5042*1031c584SApple OSS Distributions }
5043*1031c584SApple OSS Distributions }
5044*1031c584SApple OSS Distributions
5045*1031c584SApple OSS Distributions //*********************************************************************************
5046*1031c584SApple OSS Distributions // [private] OurChangeWaitForPowerSettle
5047*1031c584SApple OSS Distributions //
5048*1031c584SApple OSS Distributions // Our controlling driver has completed the power state change we initiated.
5049*1031c584SApple OSS Distributions // Wait for the driver specified settle time to expire.
5050*1031c584SApple OSS Distributions //*********************************************************************************
5051*1031c584SApple OSS Distributions
5052*1031c584SApple OSS Distributions void
OurChangeWaitForPowerSettle(void)5053*1031c584SApple OSS Distributions IOService::OurChangeWaitForPowerSettle( void )
5054*1031c584SApple OSS Distributions {
5055*1031c584SApple OSS Distributions fMachineState = kIOPM_OurChangeNotifyInterestedDriversDidChange;
5056*1031c584SApple OSS Distributions startSettleTimer();
5057*1031c584SApple OSS Distributions }
5058*1031c584SApple OSS Distributions
5059*1031c584SApple OSS Distributions //*********************************************************************************
5060*1031c584SApple OSS Distributions // [private] OurChangeNotifyInterestedDriversDidChange
5061*1031c584SApple OSS Distributions //
5062*1031c584SApple OSS Distributions // Power has settled on a power change we initiated. Here we notify
5063*1031c584SApple OSS Distributions // all our interested drivers post-change.
5064*1031c584SApple OSS Distributions //*********************************************************************************
5065*1031c584SApple OSS Distributions
5066*1031c584SApple OSS Distributions void
OurChangeNotifyInterestedDriversDidChange(void)5067*1031c584SApple OSS Distributions IOService::OurChangeNotifyInterestedDriversDidChange( void )
5068*1031c584SApple OSS Distributions {
5069*1031c584SApple OSS Distributions IOPMrootDomain * rootDomain;
5070*1031c584SApple OSS Distributions if ((rootDomain = getPMRootDomain()) == this) {
5071*1031c584SApple OSS Distributions rootDomain->tracePoint( IS_POWER_DROP ?
5072*1031c584SApple OSS Distributions kIOPMTracePointSleepDidChangeInterests :
5073*1031c584SApple OSS Distributions kIOPMTracePointWakeDidChangeInterests );
5074*1031c584SApple OSS Distributions }
5075*1031c584SApple OSS Distributions
5076*1031c584SApple OSS Distributions notifyAll( kIOPM_OurChangeTellCapabilityDidChange );
5077*1031c584SApple OSS Distributions }
5078*1031c584SApple OSS Distributions
5079*1031c584SApple OSS Distributions //*********************************************************************************
5080*1031c584SApple OSS Distributions // [private] OurChangeTellCapabilityDidChange
5081*1031c584SApple OSS Distributions //
5082*1031c584SApple OSS Distributions // For root domain to notify capability power-change.
5083*1031c584SApple OSS Distributions //*********************************************************************************
5084*1031c584SApple OSS Distributions
5085*1031c584SApple OSS Distributions void
OurChangeTellCapabilityDidChange(void)5086*1031c584SApple OSS Distributions IOService::OurChangeTellCapabilityDidChange( void )
5087*1031c584SApple OSS Distributions {
5088*1031c584SApple OSS Distributions if (!IS_ROOT_DOMAIN) {
5089*1031c584SApple OSS Distributions return OurChangeFinish();
5090*1031c584SApple OSS Distributions }
5091*1031c584SApple OSS Distributions
5092*1031c584SApple OSS Distributions if (!IS_POWER_DROP) {
5093*1031c584SApple OSS Distributions // Notify root domain immediately after notifying interested
5094*1031c584SApple OSS Distributions // drivers and power children.
5095*1031c584SApple OSS Distributions getPMRootDomain()->willTellSystemCapabilityDidChange();
5096*1031c584SApple OSS Distributions }
5097*1031c584SApple OSS Distributions
5098*1031c584SApple OSS Distributions getPMRootDomain()->tracePoint( IS_POWER_DROP ?
5099*1031c584SApple OSS Distributions kIOPMTracePointSleepCapabilityClients :
5100*1031c584SApple OSS Distributions kIOPMTracePointWakeCapabilityClients );
5101*1031c584SApple OSS Distributions
5102*1031c584SApple OSS Distributions tellSystemCapabilityChange( kIOPM_OurChangeFinish );
5103*1031c584SApple OSS Distributions }
5104*1031c584SApple OSS Distributions
5105*1031c584SApple OSS Distributions //*********************************************************************************
5106*1031c584SApple OSS Distributions // [private] OurChangeFinish
5107*1031c584SApple OSS Distributions //
5108*1031c584SApple OSS Distributions // Done with this self-induced power state change.
5109*1031c584SApple OSS Distributions //*********************************************************************************
5110*1031c584SApple OSS Distributions
5111*1031c584SApple OSS Distributions void
OurChangeFinish(void)5112*1031c584SApple OSS Distributions IOService::OurChangeFinish( void )
5113*1031c584SApple OSS Distributions {
5114*1031c584SApple OSS Distributions all_done();
5115*1031c584SApple OSS Distributions }
5116*1031c584SApple OSS Distributions
5117*1031c584SApple OSS Distributions // MARK: -
5118*1031c584SApple OSS Distributions // MARK: Power Change Initiated by Parent
5119*1031c584SApple OSS Distributions
5120*1031c584SApple OSS Distributions //*********************************************************************************
5121*1031c584SApple OSS Distributions // [private] ParentChangeStart
5122*1031c584SApple OSS Distributions //
5123*1031c584SApple OSS Distributions // Here we begin the processing of a power change initiated by our parent.
5124*1031c584SApple OSS Distributions //*********************************************************************************
5125*1031c584SApple OSS Distributions
5126*1031c584SApple OSS Distributions IOReturn
ParentChangeStart(void)5127*1031c584SApple OSS Distributions IOService::ParentChangeStart( void )
5128*1031c584SApple OSS Distributions {
5129*1031c584SApple OSS Distributions PM_ASSERT_IN_GATE();
5130*1031c584SApple OSS Distributions OUR_PMLog( kPMLogStartParentChange, fHeadNotePowerState, fCurrentPowerState );
5131*1031c584SApple OSS Distributions
5132*1031c584SApple OSS Distributions // Root power domain has transitioned to its max power state
5133*1031c584SApple OSS Distributions if ((fHeadNoteChangeFlags & (kIOPMDomainDidChange | kIOPMRootChangeUp)) ==
5134*1031c584SApple OSS Distributions (kIOPMDomainDidChange | kIOPMRootChangeUp)) {
5135*1031c584SApple OSS Distributions // Restart the idle timer stopped by ParentChangeRootChangeDown()
5136*1031c584SApple OSS Distributions if (fIdleTimerPeriod && fIdleTimerStopped) {
5137*1031c584SApple OSS Distributions restartIdleTimer();
5138*1031c584SApple OSS Distributions }
5139*1031c584SApple OSS Distributions }
5140*1031c584SApple OSS Distributions
5141*1031c584SApple OSS Distributions // Power domain is forcing us to lower power
5142*1031c584SApple OSS Distributions if (StateOrder(fHeadNotePowerState) < StateOrder(fCurrentPowerState)) {
5143*1031c584SApple OSS Distributions PM_ACTION_CHANGE(actionPowerChangeStart, fHeadNotePowerState, &fHeadNoteChangeFlags);
5144*1031c584SApple OSS Distributions
5145*1031c584SApple OSS Distributions // Tell apps and kernel clients
5146*1031c584SApple OSS Distributions fInitialPowerChange = false;
5147*1031c584SApple OSS Distributions fMachineState = kIOPM_ParentChangeTellPriorityClientsPowerDown;
5148*1031c584SApple OSS Distributions tellChangeDown1(fHeadNotePowerState);
5149*1031c584SApple OSS Distributions return IOPMWillAckLater;
5150*1031c584SApple OSS Distributions }
5151*1031c584SApple OSS Distributions
5152*1031c584SApple OSS Distributions // Power domain is allowing us to raise power up to fHeadNotePowerState
5153*1031c584SApple OSS Distributions if (StateOrder(fHeadNotePowerState) > StateOrder(fCurrentPowerState)) {
5154*1031c584SApple OSS Distributions if (StateOrder(fDesiredPowerState) > StateOrder(fCurrentPowerState)) {
5155*1031c584SApple OSS Distributions if (StateOrder(fDesiredPowerState) < StateOrder(fHeadNotePowerState)) {
5156*1031c584SApple OSS Distributions // We power up, but not all the way
5157*1031c584SApple OSS Distributions fHeadNotePowerState = fDesiredPowerState;
5158*1031c584SApple OSS Distributions fHeadNotePowerArrayEntry = &fPowerStates[fDesiredPowerState];
5159*1031c584SApple OSS Distributions OUR_PMLog(kPMLogAmendParentChange, fHeadNotePowerState, 0);
5160*1031c584SApple OSS Distributions }
5161*1031c584SApple OSS Distributions } else {
5162*1031c584SApple OSS Distributions // We don't need to change
5163*1031c584SApple OSS Distributions fHeadNotePowerState = fCurrentPowerState;
5164*1031c584SApple OSS Distributions fHeadNotePowerArrayEntry = &fPowerStates[fCurrentPowerState];
5165*1031c584SApple OSS Distributions OUR_PMLog(kPMLogAmendParentChange, fHeadNotePowerState, 0);
5166*1031c584SApple OSS Distributions }
5167*1031c584SApple OSS Distributions }
5168*1031c584SApple OSS Distributions
5169*1031c584SApple OSS Distributions if (fHeadNoteChangeFlags & kIOPMDomainDidChange) {
5170*1031c584SApple OSS Distributions if (StateOrder(fHeadNotePowerState) > StateOrder(fCurrentPowerState)) {
5171*1031c584SApple OSS Distributions PM_ACTION_CHANGE(actionPowerChangeStart,
5172*1031c584SApple OSS Distributions fHeadNotePowerState, &fHeadNoteChangeFlags);
5173*1031c584SApple OSS Distributions
5174*1031c584SApple OSS Distributions // Parent did change up - start our change up
5175*1031c584SApple OSS Distributions fInitialPowerChange = false;
5176*1031c584SApple OSS Distributions ParentChangeTellCapabilityWillChange();
5177*1031c584SApple OSS Distributions return IOPMWillAckLater;
5178*1031c584SApple OSS Distributions } else if (fHeadNoteChangeFlags & kIOPMRootBroadcastFlags) {
5179*1031c584SApple OSS Distributions // No need to change power state, but broadcast change
5180*1031c584SApple OSS Distributions // to our children.
5181*1031c584SApple OSS Distributions fMachineState = kIOPM_SyncNotifyDidChange;
5182*1031c584SApple OSS Distributions fDriverCallReason = kDriverCallInformPreChange;
5183*1031c584SApple OSS Distributions fHeadNoteChangeFlags |= kIOPMNotDone;
5184*1031c584SApple OSS Distributions notifyChildren();
5185*1031c584SApple OSS Distributions return IOPMWillAckLater;
5186*1031c584SApple OSS Distributions }
5187*1031c584SApple OSS Distributions }
5188*1031c584SApple OSS Distributions
5189*1031c584SApple OSS Distributions // No power state change necessary
5190*1031c584SApple OSS Distributions fHeadNoteChangeFlags |= kIOPMNotDone;
5191*1031c584SApple OSS Distributions
5192*1031c584SApple OSS Distributions all_done();
5193*1031c584SApple OSS Distributions return IOPMAckImplied;
5194*1031c584SApple OSS Distributions }
5195*1031c584SApple OSS Distributions
5196*1031c584SApple OSS Distributions //******************************************************************************
5197*1031c584SApple OSS Distributions // [private] ParentChangeRootChangeDown
5198*1031c584SApple OSS Distributions //
5199*1031c584SApple OSS Distributions // Root domain has finished the transition to the system sleep state. And all
5200*1031c584SApple OSS Distributions // drivers in the power plane should have powered down. Cancel the idle timer,
5201*1031c584SApple OSS Distributions // and also reset the device desire for those drivers that don't want power
5202*1031c584SApple OSS Distributions // automatically restored on wake.
5203*1031c584SApple OSS Distributions //******************************************************************************
5204*1031c584SApple OSS Distributions
5205*1031c584SApple OSS Distributions void
ParentChangeRootChangeDown(void)5206*1031c584SApple OSS Distributions IOService::ParentChangeRootChangeDown( void )
5207*1031c584SApple OSS Distributions {
5208*1031c584SApple OSS Distributions // Always stop the idle timer before root power down
5209*1031c584SApple OSS Distributions if (fIdleTimerPeriod && !fIdleTimerStopped) {
5210*1031c584SApple OSS Distributions fIdleTimerStopped = true;
5211*1031c584SApple OSS Distributions if (fIdleTimer && thread_call_cancel(fIdleTimer)) {
5212*1031c584SApple OSS Distributions release();
5213*1031c584SApple OSS Distributions }
5214*1031c584SApple OSS Distributions }
5215*1031c584SApple OSS Distributions
5216*1031c584SApple OSS Distributions if (fResetPowerStateOnWake) {
5217*1031c584SApple OSS Distributions // Reset device desire down to the lowest power state.
5218*1031c584SApple OSS Distributions // Advisory tickle desire is intentionally untouched since
5219*1031c584SApple OSS Distributions // it has no effect until system is promoted to full wake.
5220*1031c584SApple OSS Distributions
5221*1031c584SApple OSS Distributions if (fDeviceDesire != kPowerStateZero) {
5222*1031c584SApple OSS Distributions updatePowerClient(gIOPMPowerClientDevice, kPowerStateZero);
5223*1031c584SApple OSS Distributions computeDesiredState(kPowerStateZero, true);
5224*1031c584SApple OSS Distributions requestDomainPower( fDesiredPowerState );
5225*1031c584SApple OSS Distributions PM_LOG1("%s: tickle desire removed\n", fName);
5226*1031c584SApple OSS Distributions }
5227*1031c584SApple OSS Distributions
5228*1031c584SApple OSS Distributions // Invalidate tickle cache so the next tickle will issue a request
5229*1031c584SApple OSS Distributions IOLockLock(fActivityLock);
5230*1031c584SApple OSS Distributions fDeviceWasActive = false;
5231*1031c584SApple OSS Distributions fActivityTicklePowerState = kInvalidTicklePowerState;
5232*1031c584SApple OSS Distributions IOLockUnlock(fActivityLock);
5233*1031c584SApple OSS Distributions
5234*1031c584SApple OSS Distributions fIdleTimerMinPowerState = kPowerStateZero;
5235*1031c584SApple OSS Distributions } else if (fAdvisoryTickleUsed) {
5236*1031c584SApple OSS Distributions // Less aggressive mechanism to accelerate idle timer expiration
5237*1031c584SApple OSS Distributions // before system sleep. May not always allow the driver to wake
5238*1031c584SApple OSS Distributions // up from system sleep in the min power state.
5239*1031c584SApple OSS Distributions
5240*1031c584SApple OSS Distributions AbsoluteTime now;
5241*1031c584SApple OSS Distributions uint64_t nsec;
5242*1031c584SApple OSS Distributions bool dropTickleDesire = false;
5243*1031c584SApple OSS Distributions
5244*1031c584SApple OSS Distributions if (fIdleTimerPeriod && !fIdleTimerIgnored &&
5245*1031c584SApple OSS Distributions (fIdleTimerMinPowerState == kPowerStateZero) &&
5246*1031c584SApple OSS Distributions (fDeviceDesire != kPowerStateZero)) {
5247*1031c584SApple OSS Distributions IOLockLock(fActivityLock);
5248*1031c584SApple OSS Distributions
5249*1031c584SApple OSS Distributions if (!fDeviceWasActive) {
5250*1031c584SApple OSS Distributions // No tickles since the last idle timer expiration.
5251*1031c584SApple OSS Distributions // Safe to drop the device desire to zero.
5252*1031c584SApple OSS Distributions dropTickleDesire = true;
5253*1031c584SApple OSS Distributions } else {
5254*1031c584SApple OSS Distributions // Was tickled since the last idle timer expiration,
5255*1031c584SApple OSS Distributions // but not in the last minute.
5256*1031c584SApple OSS Distributions clock_get_uptime(&now);
5257*1031c584SApple OSS Distributions SUB_ABSOLUTETIME(&now, &fDeviceActiveTimestamp);
5258*1031c584SApple OSS Distributions absolutetime_to_nanoseconds(now, &nsec);
5259*1031c584SApple OSS Distributions if (nsec >= kNoTickleCancelWindow) {
5260*1031c584SApple OSS Distributions dropTickleDesire = true;
5261*1031c584SApple OSS Distributions }
5262*1031c584SApple OSS Distributions }
5263*1031c584SApple OSS Distributions
5264*1031c584SApple OSS Distributions if (dropTickleDesire) {
5265*1031c584SApple OSS Distributions // Force the next tickle to raise power state
5266*1031c584SApple OSS Distributions fDeviceWasActive = false;
5267*1031c584SApple OSS Distributions fActivityTicklePowerState = kInvalidTicklePowerState;
5268*1031c584SApple OSS Distributions }
5269*1031c584SApple OSS Distributions
5270*1031c584SApple OSS Distributions IOLockUnlock(fActivityLock);
5271*1031c584SApple OSS Distributions }
5272*1031c584SApple OSS Distributions
5273*1031c584SApple OSS Distributions if (dropTickleDesire) {
5274*1031c584SApple OSS Distributions // Advisory tickle desire is intentionally untouched since
5275*1031c584SApple OSS Distributions // it has no effect until system is promoted to full wake.
5276*1031c584SApple OSS Distributions
5277*1031c584SApple OSS Distributions updatePowerClient(gIOPMPowerClientDevice, kPowerStateZero);
5278*1031c584SApple OSS Distributions computeDesiredState(kPowerStateZero, true);
5279*1031c584SApple OSS Distributions PM_LOG1("%s: tickle desire dropped\n", fName);
5280*1031c584SApple OSS Distributions }
5281*1031c584SApple OSS Distributions }
5282*1031c584SApple OSS Distributions }
5283*1031c584SApple OSS Distributions
5284*1031c584SApple OSS Distributions //*********************************************************************************
5285*1031c584SApple OSS Distributions // [private] ParentChangeTellPriorityClientsPowerDown
5286*1031c584SApple OSS Distributions //
5287*1031c584SApple OSS Distributions // All applications and kernel clients have acknowledged our intention to drop
5288*1031c584SApple OSS Distributions // power. Here we notify "priority" clients that we are lowering power.
5289*1031c584SApple OSS Distributions //*********************************************************************************
5290*1031c584SApple OSS Distributions
5291*1031c584SApple OSS Distributions void
ParentChangeTellPriorityClientsPowerDown(void)5292*1031c584SApple OSS Distributions IOService::ParentChangeTellPriorityClientsPowerDown( void )
5293*1031c584SApple OSS Distributions {
5294*1031c584SApple OSS Distributions fMachineState = kIOPM_ParentChangeNotifyInterestedDriversWillChange;
5295*1031c584SApple OSS Distributions tellChangeDown2(fHeadNotePowerState);
5296*1031c584SApple OSS Distributions }
5297*1031c584SApple OSS Distributions
5298*1031c584SApple OSS Distributions //*********************************************************************************
5299*1031c584SApple OSS Distributions // [private] ParentChangeTellCapabilityWillChange
5300*1031c584SApple OSS Distributions //
5301*1031c584SApple OSS Distributions // All (legacy) applications and kernel clients have acknowledged, extra stage for
5302*1031c584SApple OSS Distributions // root domain to notify apps and drivers about the system capability change.
5303*1031c584SApple OSS Distributions //*********************************************************************************
5304*1031c584SApple OSS Distributions
5305*1031c584SApple OSS Distributions void
ParentChangeTellCapabilityWillChange(void)5306*1031c584SApple OSS Distributions IOService::ParentChangeTellCapabilityWillChange( void )
5307*1031c584SApple OSS Distributions {
5308*1031c584SApple OSS Distributions if (!IS_ROOT_DOMAIN) {
5309*1031c584SApple OSS Distributions return ParentChangeNotifyInterestedDriversWillChange();
5310*1031c584SApple OSS Distributions }
5311*1031c584SApple OSS Distributions
5312*1031c584SApple OSS Distributions tellSystemCapabilityChange( kIOPM_ParentChangeNotifyInterestedDriversWillChange );
5313*1031c584SApple OSS Distributions }
5314*1031c584SApple OSS Distributions
5315*1031c584SApple OSS Distributions //*********************************************************************************
5316*1031c584SApple OSS Distributions // [private] ParentChangeNotifyInterestedDriversWillChange
5317*1031c584SApple OSS Distributions //
5318*1031c584SApple OSS Distributions // All applications and kernel clients have acknowledged our power state change.
5319*1031c584SApple OSS Distributions // Here we notify interested drivers pre-change.
5320*1031c584SApple OSS Distributions //*********************************************************************************
5321*1031c584SApple OSS Distributions
5322*1031c584SApple OSS Distributions void
ParentChangeNotifyInterestedDriversWillChange(void)5323*1031c584SApple OSS Distributions IOService::ParentChangeNotifyInterestedDriversWillChange( void )
5324*1031c584SApple OSS Distributions {
5325*1031c584SApple OSS Distributions notifyAll( kIOPM_ParentChangeSetPowerState );
5326*1031c584SApple OSS Distributions }
5327*1031c584SApple OSS Distributions
5328*1031c584SApple OSS Distributions //*********************************************************************************
5329*1031c584SApple OSS Distributions // [private] ParentChangeSetPowerState
5330*1031c584SApple OSS Distributions //
5331*1031c584SApple OSS Distributions // Instruct our controlling driver to program the hardware for the power state
5332*1031c584SApple OSS Distributions // change. Wait for async completions.
5333*1031c584SApple OSS Distributions //*********************************************************************************
5334*1031c584SApple OSS Distributions
5335*1031c584SApple OSS Distributions void
ParentChangeSetPowerState(void)5336*1031c584SApple OSS Distributions IOService::ParentChangeSetPowerState( void )
5337*1031c584SApple OSS Distributions {
5338*1031c584SApple OSS Distributions MS_PUSH( kIOPM_ParentChangeWaitForPowerSettle );
5339*1031c584SApple OSS Distributions fMachineState = kIOPM_DriverThreadCallDone;
5340*1031c584SApple OSS Distributions fDriverCallReason = kDriverCallSetPowerState;
5341*1031c584SApple OSS Distributions
5342*1031c584SApple OSS Distributions if (notifyControllingDriver() == false) {
5343*1031c584SApple OSS Distributions notifyControllingDriverDone();
5344*1031c584SApple OSS Distributions }
5345*1031c584SApple OSS Distributions }
5346*1031c584SApple OSS Distributions
5347*1031c584SApple OSS Distributions //*********************************************************************************
5348*1031c584SApple OSS Distributions // [private] ParentChangeWaitForPowerSettle
5349*1031c584SApple OSS Distributions //
5350*1031c584SApple OSS Distributions // Our controlling driver has completed the power state change initiated by our
5351*1031c584SApple OSS Distributions // parent. Wait for the driver specified settle time to expire.
5352*1031c584SApple OSS Distributions //*********************************************************************************
5353*1031c584SApple OSS Distributions
5354*1031c584SApple OSS Distributions void
ParentChangeWaitForPowerSettle(void)5355*1031c584SApple OSS Distributions IOService::ParentChangeWaitForPowerSettle( void )
5356*1031c584SApple OSS Distributions {
5357*1031c584SApple OSS Distributions fMachineState = kIOPM_ParentChangeNotifyInterestedDriversDidChange;
5358*1031c584SApple OSS Distributions startSettleTimer();
5359*1031c584SApple OSS Distributions }
5360*1031c584SApple OSS Distributions
5361*1031c584SApple OSS Distributions //*********************************************************************************
5362*1031c584SApple OSS Distributions // [private] ParentChangeNotifyInterestedDriversDidChange
5363*1031c584SApple OSS Distributions //
5364*1031c584SApple OSS Distributions // Power has settled on a power change initiated by our parent. Here we notify
5365*1031c584SApple OSS Distributions // all our interested drivers post-change.
5366*1031c584SApple OSS Distributions //*********************************************************************************
5367*1031c584SApple OSS Distributions
5368*1031c584SApple OSS Distributions void
ParentChangeNotifyInterestedDriversDidChange(void)5369*1031c584SApple OSS Distributions IOService::ParentChangeNotifyInterestedDriversDidChange( void )
5370*1031c584SApple OSS Distributions {
5371*1031c584SApple OSS Distributions notifyAll( kIOPM_ParentChangeTellCapabilityDidChange );
5372*1031c584SApple OSS Distributions }
5373*1031c584SApple OSS Distributions
5374*1031c584SApple OSS Distributions //*********************************************************************************
5375*1031c584SApple OSS Distributions // [private] ParentChangeTellCapabilityDidChange
5376*1031c584SApple OSS Distributions //
5377*1031c584SApple OSS Distributions // For root domain to notify capability power-change.
5378*1031c584SApple OSS Distributions //*********************************************************************************
5379*1031c584SApple OSS Distributions
5380*1031c584SApple OSS Distributions void
ParentChangeTellCapabilityDidChange(void)5381*1031c584SApple OSS Distributions IOService::ParentChangeTellCapabilityDidChange( void )
5382*1031c584SApple OSS Distributions {
5383*1031c584SApple OSS Distributions if (!IS_ROOT_DOMAIN) {
5384*1031c584SApple OSS Distributions return ParentChangeAcknowledgePowerChange();
5385*1031c584SApple OSS Distributions }
5386*1031c584SApple OSS Distributions
5387*1031c584SApple OSS Distributions tellSystemCapabilityChange( kIOPM_ParentChangeAcknowledgePowerChange );
5388*1031c584SApple OSS Distributions }
5389*1031c584SApple OSS Distributions
5390*1031c584SApple OSS Distributions //*********************************************************************************
5391*1031c584SApple OSS Distributions // [private] ParentAcknowledgePowerChange
5392*1031c584SApple OSS Distributions //
5393*1031c584SApple OSS Distributions // Acknowledge our power parent that our power change is done.
5394*1031c584SApple OSS Distributions //*********************************************************************************
5395*1031c584SApple OSS Distributions
5396*1031c584SApple OSS Distributions void
ParentChangeAcknowledgePowerChange(void)5397*1031c584SApple OSS Distributions IOService::ParentChangeAcknowledgePowerChange( void )
5398*1031c584SApple OSS Distributions {
5399*1031c584SApple OSS Distributions IORegistryEntry * nub;
5400*1031c584SApple OSS Distributions IOService * parent;
5401*1031c584SApple OSS Distributions
5402*1031c584SApple OSS Distributions nub = fHeadNoteParentConnection;
5403*1031c584SApple OSS Distributions nub->retain();
5404*1031c584SApple OSS Distributions all_done();
5405*1031c584SApple OSS Distributions parent = (IOService *)nub->copyParentEntry(gIOPowerPlane);
5406*1031c584SApple OSS Distributions if (parent) {
5407*1031c584SApple OSS Distributions parent->acknowledgePowerChange((IOService *)nub);
5408*1031c584SApple OSS Distributions parent->release();
5409*1031c584SApple OSS Distributions }
5410*1031c584SApple OSS Distributions nub->release();
5411*1031c584SApple OSS Distributions }
5412*1031c584SApple OSS Distributions
5413*1031c584SApple OSS Distributions // MARK: -
5414*1031c584SApple OSS Distributions // MARK: Ack and Settle timers
5415*1031c584SApple OSS Distributions
5416*1031c584SApple OSS Distributions //*********************************************************************************
5417*1031c584SApple OSS Distributions // [private] settleTimerExpired
5418*1031c584SApple OSS Distributions //
5419*1031c584SApple OSS Distributions // Power has settled after our last change. Notify interested parties that
5420*1031c584SApple OSS Distributions // there is a new power state.
5421*1031c584SApple OSS Distributions //*********************************************************************************
5422*1031c584SApple OSS Distributions
5423*1031c584SApple OSS Distributions void
settleTimerExpired(void)5424*1031c584SApple OSS Distributions IOService::settleTimerExpired( void )
5425*1031c584SApple OSS Distributions {
5426*1031c584SApple OSS Distributions #if USE_SETTLE_TIMER
5427*1031c584SApple OSS Distributions fSettleTimeUS = 0;
5428*1031c584SApple OSS Distributions gIOPMWorkQueue->signalWorkAvailable();
5429*1031c584SApple OSS Distributions #endif
5430*1031c584SApple OSS Distributions }
5431*1031c584SApple OSS Distributions
5432*1031c584SApple OSS Distributions //*********************************************************************************
5433*1031c584SApple OSS Distributions // settle_timer_expired
5434*1031c584SApple OSS Distributions //
5435*1031c584SApple OSS Distributions // Holds a retain while the settle timer callout is in flight.
5436*1031c584SApple OSS Distributions //*********************************************************************************
5437*1031c584SApple OSS Distributions
5438*1031c584SApple OSS Distributions #if USE_SETTLE_TIMER
5439*1031c584SApple OSS Distributions static void
settle_timer_expired(thread_call_param_t arg0,thread_call_param_t arg1)5440*1031c584SApple OSS Distributions settle_timer_expired( thread_call_param_t arg0, thread_call_param_t arg1 )
5441*1031c584SApple OSS Distributions {
5442*1031c584SApple OSS Distributions IOService * me = (IOService *) arg0;
5443*1031c584SApple OSS Distributions
5444*1031c584SApple OSS Distributions if (gIOPMWorkLoop && gIOPMWorkQueue) {
5445*1031c584SApple OSS Distributions gIOPMWorkLoop->runAction(
5446*1031c584SApple OSS Distributions OSMemberFunctionCast(IOWorkLoop::Action, me, &IOService::settleTimerExpired),
5447*1031c584SApple OSS Distributions me);
5448*1031c584SApple OSS Distributions }
5449*1031c584SApple OSS Distributions me->release();
5450*1031c584SApple OSS Distributions }
5451*1031c584SApple OSS Distributions #endif
5452*1031c584SApple OSS Distributions
5453*1031c584SApple OSS Distributions //*********************************************************************************
5454*1031c584SApple OSS Distributions // [private] startSettleTimer
5455*1031c584SApple OSS Distributions //
5456*1031c584SApple OSS Distributions // Calculate a power-settling delay in microseconds and start a timer.
5457*1031c584SApple OSS Distributions //*********************************************************************************
5458*1031c584SApple OSS Distributions
5459*1031c584SApple OSS Distributions void
startSettleTimer(void)5460*1031c584SApple OSS Distributions IOService::startSettleTimer( void )
5461*1031c584SApple OSS Distributions {
5462*1031c584SApple OSS Distributions #if USE_SETTLE_TIMER
5463*1031c584SApple OSS Distributions // This function is broken and serves no useful purpose since it never
5464*1031c584SApple OSS Distributions // updates fSettleTimeUS to a non-zero value to stall the state machine,
5465*1031c584SApple OSS Distributions // yet it starts a delay timer. It appears no driver relies on a delay
5466*1031c584SApple OSS Distributions // from settleUpTime and settleDownTime in the power state table.
5467*1031c584SApple OSS Distributions
5468*1031c584SApple OSS Distributions AbsoluteTime deadline;
5469*1031c584SApple OSS Distributions IOPMPowerStateIndex stateIndex;
5470*1031c584SApple OSS Distributions IOPMPowerStateIndex currentOrder, newOrder, i;
5471*1031c584SApple OSS Distributions uint32_t settleTime = 0;
5472*1031c584SApple OSS Distributions boolean_t pending;
5473*1031c584SApple OSS Distributions
5474*1031c584SApple OSS Distributions PM_ASSERT_IN_GATE();
5475*1031c584SApple OSS Distributions
5476*1031c584SApple OSS Distributions currentOrder = StateOrder(fCurrentPowerState);
5477*1031c584SApple OSS Distributions newOrder = StateOrder(fHeadNotePowerState);
5478*1031c584SApple OSS Distributions
5479*1031c584SApple OSS Distributions i = currentOrder;
5480*1031c584SApple OSS Distributions
5481*1031c584SApple OSS Distributions // lowering power
5482*1031c584SApple OSS Distributions if (newOrder < currentOrder) {
5483*1031c584SApple OSS Distributions while (i > newOrder) {
5484*1031c584SApple OSS Distributions stateIndex = fPowerStates[i].stateOrderToIndex;
5485*1031c584SApple OSS Distributions settleTime += (uint32_t) fPowerStates[stateIndex].settleDownTime;
5486*1031c584SApple OSS Distributions i--;
5487*1031c584SApple OSS Distributions }
5488*1031c584SApple OSS Distributions }
5489*1031c584SApple OSS Distributions
5490*1031c584SApple OSS Distributions // raising power
5491*1031c584SApple OSS Distributions if (newOrder > currentOrder) {
5492*1031c584SApple OSS Distributions while (i < newOrder) {
5493*1031c584SApple OSS Distributions stateIndex = fPowerStates[i + 1].stateOrderToIndex;
5494*1031c584SApple OSS Distributions settleTime += (uint32_t) fPowerStates[stateIndex].settleUpTime;
5495*1031c584SApple OSS Distributions i++;
5496*1031c584SApple OSS Distributions }
5497*1031c584SApple OSS Distributions }
5498*1031c584SApple OSS Distributions
5499*1031c584SApple OSS Distributions if (settleTime) {
5500*1031c584SApple OSS Distributions retain();
5501*1031c584SApple OSS Distributions clock_interval_to_deadline(settleTime, kMicrosecondScale, &deadline);
5502*1031c584SApple OSS Distributions pending = thread_call_enter_delayed(fSettleTimer, deadline);
5503*1031c584SApple OSS Distributions if (pending) {
5504*1031c584SApple OSS Distributions release();
5505*1031c584SApple OSS Distributions }
5506*1031c584SApple OSS Distributions }
5507*1031c584SApple OSS Distributions #endif
5508*1031c584SApple OSS Distributions }
5509*1031c584SApple OSS Distributions
5510*1031c584SApple OSS Distributions //*********************************************************************************
5511*1031c584SApple OSS Distributions // [private] ackTimerTick
5512*1031c584SApple OSS Distributions //
5513*1031c584SApple OSS Distributions // The acknowledgement timeout periodic timer has ticked.
5514*1031c584SApple OSS Distributions // If we are awaiting acks for a power change notification,
5515*1031c584SApple OSS Distributions // we decrement the timer word of each interested driver which hasn't acked.
5516*1031c584SApple OSS Distributions // If a timer word becomes zero, we pretend the driver aknowledged.
5517*1031c584SApple OSS Distributions // If we are waiting for the controlling driver to change the power
5518*1031c584SApple OSS Distributions // state of the hardware, we decrement its timer word, and if it becomes
5519*1031c584SApple OSS Distributions // zero, we pretend the driver acknowledged.
5520*1031c584SApple OSS Distributions //
5521*1031c584SApple OSS Distributions // Returns true if the timer tick made it possible to advance to the next
5522*1031c584SApple OSS Distributions // machine state, false otherwise.
5523*1031c584SApple OSS Distributions //*********************************************************************************
5524*1031c584SApple OSS Distributions
5525*1031c584SApple OSS Distributions #ifndef __LP64__
5526*1031c584SApple OSS Distributions #if MACH_ASSERT
5527*1031c584SApple OSS Distributions __dead2
5528*1031c584SApple OSS Distributions #endif
5529*1031c584SApple OSS Distributions void
ack_timer_ticked(void)5530*1031c584SApple OSS Distributions IOService::ack_timer_ticked( void )
5531*1031c584SApple OSS Distributions {
5532*1031c584SApple OSS Distributions assert(false);
5533*1031c584SApple OSS Distributions }
5534*1031c584SApple OSS Distributions #endif /* !__LP64__ */
5535*1031c584SApple OSS Distributions
5536*1031c584SApple OSS Distributions bool
ackTimerTick(void)5537*1031c584SApple OSS Distributions IOService::ackTimerTick( void )
5538*1031c584SApple OSS Distributions {
5539*1031c584SApple OSS Distributions IOPMinformee * nextObject;
5540*1031c584SApple OSS Distributions bool done = false;
5541*1031c584SApple OSS Distributions
5542*1031c584SApple OSS Distributions PM_ASSERT_IN_GATE();
5543*1031c584SApple OSS Distributions switch (fMachineState) {
5544*1031c584SApple OSS Distributions case kIOPM_OurChangeWaitForPowerSettle:
5545*1031c584SApple OSS Distributions case kIOPM_ParentChangeWaitForPowerSettle:
5546*1031c584SApple OSS Distributions // are we waiting for controlling driver to acknowledge?
5547*1031c584SApple OSS Distributions if (fDriverTimer > 0) {
5548*1031c584SApple OSS Distributions // yes, decrement timer tick
5549*1031c584SApple OSS Distributions fDriverTimer--;
5550*1031c584SApple OSS Distributions if (fDriverTimer == 0) {
5551*1031c584SApple OSS Distributions // controlling driver is tardy
5552*1031c584SApple OSS Distributions uint64_t nsec = computeTimeDeltaNS(&fDriverCallStartTime);
5553*1031c584SApple OSS Distributions OUR_PMLog(kPMLogCtrlDriverTardy, 0, 0);
5554*1031c584SApple OSS Distributions setProperty(kIOPMTardyAckSPSKey, kOSBooleanTrue);
5555*1031c584SApple OSS Distributions PM_ERROR("%s::setPowerState(%p, %lu -> %lu) timed out after %d ms\n",
5556*1031c584SApple OSS Distributions fName, OBFUSCATE(this), fCurrentPowerState, fHeadNotePowerState, NS_TO_MS(nsec));
5557*1031c584SApple OSS Distributions
5558*1031c584SApple OSS Distributions #if DEBUG || DEVELOPMENT || !defined(XNU_TARGET_OS_OSX)
5559*1031c584SApple OSS Distributions bool panic_allowed = false;
5560*1031c584SApple OSS Distributions uint32_t setpowerstate_panic = -1;
5561*1031c584SApple OSS Distributions PE_parse_boot_argn("setpowerstate_panic", &setpowerstate_panic, sizeof(setpowerstate_panic));
5562*1031c584SApple OSS Distributions panic_allowed = setpowerstate_panic != 0;
5563*1031c584SApple OSS Distributions #ifdef CONFIG_XNUPOST
5564*1031c584SApple OSS Distributions uint64_t kernel_post_args = 0;
5565*1031c584SApple OSS Distributions PE_parse_boot_argn("kernPOST", &kernel_post_args, sizeof(kernel_post_args));
5566*1031c584SApple OSS Distributions if (kernel_post_args != 0) {
5567*1031c584SApple OSS Distributions panic_allowed = false;
5568*1031c584SApple OSS Distributions }
5569*1031c584SApple OSS Distributions #endif /* CONFIG_XNUPOST */
5570*1031c584SApple OSS Distributions if (panic_allowed) {
5571*1031c584SApple OSS Distributions // rdar://problem/48743340 - excluding AppleSEPManager from panic
5572*1031c584SApple OSS Distributions const char *allowlist = "AppleSEPManager";
5573*1031c584SApple OSS Distributions if (strncmp(fName, allowlist, strlen(allowlist))) {
5574*1031c584SApple OSS Distributions panic("%s::setPowerState(%p, %lu -> %lu) timed out after %d ms",
5575*1031c584SApple OSS Distributions fName, this, fCurrentPowerState, fHeadNotePowerState, NS_TO_MS(nsec));
5576*1031c584SApple OSS Distributions }
5577*1031c584SApple OSS Distributions } else {
5578*1031c584SApple OSS Distributions #ifdef CONFIG_XNUPOST
5579*1031c584SApple OSS Distributions if (kernel_post_args != 0) {
5580*1031c584SApple OSS Distributions PM_ERROR("setPowerState panic disabled by kernPOST boot-arg\n");
5581*1031c584SApple OSS Distributions }
5582*1031c584SApple OSS Distributions #endif /* CONFIG_XNUPOST */
5583*1031c584SApple OSS Distributions if (setpowerstate_panic != 0) {
5584*1031c584SApple OSS Distributions PM_ERROR("setPowerState panic disabled by setpowerstate_panic boot-arg\n");
5585*1031c584SApple OSS Distributions }
5586*1031c584SApple OSS Distributions }
5587*1031c584SApple OSS Distributions #else /* !(DEBUG || DEVELOPMENT || !defined(XNU_TARGET_OS_OSX)) */
5588*1031c584SApple OSS Distributions if (gIOKitDebug & kIOLogDebugPower) {
5589*1031c584SApple OSS Distributions panic("%s::setPowerState(%p, %lu -> %lu) timed out after %d ms",
5590*1031c584SApple OSS Distributions fName, this, fCurrentPowerState, fHeadNotePowerState, NS_TO_MS(nsec));
5591*1031c584SApple OSS Distributions } else {
5592*1031c584SApple OSS Distributions // panic for first party kexts
5593*1031c584SApple OSS Distributions const void *function_addr = NULL;
5594*1031c584SApple OSS Distributions OSKext *kext = NULL;
5595*1031c584SApple OSS Distributions function_addr = OSMemberFunctionCast(const void *, fControllingDriver, &IOService::setPowerState);
5596*1031c584SApple OSS Distributions kext = OSKext::lookupKextWithAddress((vm_address_t)function_addr);
5597*1031c584SApple OSS Distributions if (kext) {
5598*1031c584SApple OSS Distributions #if __has_feature(ptrauth_calls)
5599*1031c584SApple OSS Distributions function_addr = (const void*)VM_KERNEL_STRIP_PTR(function_addr);
5600*1031c584SApple OSS Distributions #endif /* __has_feature(ptrauth_calls) */
5601*1031c584SApple OSS Distributions const char *bundleID = kext->getIdentifierCString();
5602*1031c584SApple OSS Distributions const char *apple_prefix = "com.apple";
5603*1031c584SApple OSS Distributions const char *kernel_prefix = "__kernel__";
5604*1031c584SApple OSS Distributions if (strncmp(bundleID, apple_prefix, strlen(apple_prefix)) == 0 || strncmp(bundleID, kernel_prefix, strlen(kernel_prefix)) == 0) {
5605*1031c584SApple OSS Distributions // first party client
5606*1031c584SApple OSS Distributions panic("%s::setPowerState(%p : %p, %lu -> %lu) timed out after %d ms",
5607*1031c584SApple OSS Distributions fName, this, function_addr, fCurrentPowerState, fHeadNotePowerState, NS_TO_MS(nsec));
5608*1031c584SApple OSS Distributions }
5609*1031c584SApple OSS Distributions kext->release();
5610*1031c584SApple OSS Distributions }
5611*1031c584SApple OSS Distributions }
5612*1031c584SApple OSS Distributions #endif /* !(DEBUG || DEVELOPMENT || !defined(XNU_TARGET_OS_OSX)) */
5613*1031c584SApple OSS Distributions // Unblock state machine and pretend driver has acked.
5614*1031c584SApple OSS Distributions done = true;
5615*1031c584SApple OSS Distributions getPMRootDomain()->reset_watchdog_timer(this, 0);
5616*1031c584SApple OSS Distributions } else {
5617*1031c584SApple OSS Distributions // still waiting, set timer again
5618*1031c584SApple OSS Distributions start_ack_timer();
5619*1031c584SApple OSS Distributions }
5620*1031c584SApple OSS Distributions }
5621*1031c584SApple OSS Distributions break;
5622*1031c584SApple OSS Distributions
5623*1031c584SApple OSS Distributions case kIOPM_NotifyChildrenStart:
5624*1031c584SApple OSS Distributions // are we waiting for interested parties to acknowledge?
5625*1031c584SApple OSS Distributions if (fHeadNotePendingAcks != 0) {
5626*1031c584SApple OSS Distributions // yes, go through the list of interested drivers
5627*1031c584SApple OSS Distributions nextObject = fInterestedDrivers->firstInList();
5628*1031c584SApple OSS Distributions // and check each one
5629*1031c584SApple OSS Distributions while (nextObject != NULL) {
5630*1031c584SApple OSS Distributions if (nextObject->timer > 0) {
5631*1031c584SApple OSS Distributions nextObject->timer--;
5632*1031c584SApple OSS Distributions // this one should have acked by now
5633*1031c584SApple OSS Distributions if (nextObject->timer == 0) {
5634*1031c584SApple OSS Distributions uint64_t nsec = computeTimeDeltaNS(&nextObject->startTime);
5635*1031c584SApple OSS Distributions OUR_PMLog(kPMLogIntDriverTardy, 0, 0);
5636*1031c584SApple OSS Distributions nextObject->whatObject->setProperty(kIOPMTardyAckPSCKey, kOSBooleanTrue);
5637*1031c584SApple OSS Distributions PM_ERROR("%s::powerState%sChangeTo(%p, %s, %lu -> %lu) timed out after %d ms\n",
5638*1031c584SApple OSS Distributions nextObject->whatObject->getName(),
5639*1031c584SApple OSS Distributions (fDriverCallReason == kDriverCallInformPreChange) ? "Will" : "Did",
5640*1031c584SApple OSS Distributions OBFUSCATE(nextObject->whatObject), fName, fCurrentPowerState, fHeadNotePowerState,
5641*1031c584SApple OSS Distributions NS_TO_MS(nsec));
5642*1031c584SApple OSS Distributions
5643*1031c584SApple OSS Distributions // Pretend driver has acked.
5644*1031c584SApple OSS Distributions fHeadNotePendingAcks--;
5645*1031c584SApple OSS Distributions }
5646*1031c584SApple OSS Distributions }
5647*1031c584SApple OSS Distributions nextObject = fInterestedDrivers->nextInList(nextObject);
5648*1031c584SApple OSS Distributions }
5649*1031c584SApple OSS Distributions
5650*1031c584SApple OSS Distributions // is that the last?
5651*1031c584SApple OSS Distributions if (fHeadNotePendingAcks == 0) {
5652*1031c584SApple OSS Distributions // yes, we can continue
5653*1031c584SApple OSS Distributions done = true;
5654*1031c584SApple OSS Distributions getPMRootDomain()->reset_watchdog_timer(this, 0);
5655*1031c584SApple OSS Distributions } else {
5656*1031c584SApple OSS Distributions // no, set timer again
5657*1031c584SApple OSS Distributions start_ack_timer();
5658*1031c584SApple OSS Distributions }
5659*1031c584SApple OSS Distributions }
5660*1031c584SApple OSS Distributions break;
5661*1031c584SApple OSS Distributions
5662*1031c584SApple OSS Distributions // TODO: aggreggate this
5663*1031c584SApple OSS Distributions case kIOPM_OurChangeTellClientsPowerDown:
5664*1031c584SApple OSS Distributions case kIOPM_OurChangeTellUserPMPolicyPowerDown:
5665*1031c584SApple OSS Distributions case kIOPM_OurChangeTellPriorityClientsPowerDown:
5666*1031c584SApple OSS Distributions case kIOPM_OurChangeNotifyInterestedDriversWillChange:
5667*1031c584SApple OSS Distributions case kIOPM_ParentChangeTellPriorityClientsPowerDown:
5668*1031c584SApple OSS Distributions case kIOPM_ParentChangeNotifyInterestedDriversWillChange:
5669*1031c584SApple OSS Distributions case kIOPM_SyncTellClientsPowerDown:
5670*1031c584SApple OSS Distributions case kIOPM_SyncTellPriorityClientsPowerDown:
5671*1031c584SApple OSS Distributions case kIOPM_SyncNotifyWillChange:
5672*1031c584SApple OSS Distributions case kIOPM_TellCapabilityChangeDone:
5673*1031c584SApple OSS Distributions // apps didn't respond in time
5674*1031c584SApple OSS Distributions cleanClientResponses(true);
5675*1031c584SApple OSS Distributions OUR_PMLog(kPMLogClientTardy, 0, 1);
5676*1031c584SApple OSS Distributions // tardy equates to approval
5677*1031c584SApple OSS Distributions done = true;
5678*1031c584SApple OSS Distributions break;
5679*1031c584SApple OSS Distributions
5680*1031c584SApple OSS Distributions default:
5681*1031c584SApple OSS Distributions PM_LOG1("%s: unexpected ack timer tick (state = %d)\n",
5682*1031c584SApple OSS Distributions getName(), fMachineState);
5683*1031c584SApple OSS Distributions break;
5684*1031c584SApple OSS Distributions }
5685*1031c584SApple OSS Distributions return done;
5686*1031c584SApple OSS Distributions }
5687*1031c584SApple OSS Distributions
5688*1031c584SApple OSS Distributions //*********************************************************************************
5689*1031c584SApple OSS Distributions // [private] start_watchdog_timer
5690*1031c584SApple OSS Distributions //*********************************************************************************
5691*1031c584SApple OSS Distributions void
start_watchdog_timer(void)5692*1031c584SApple OSS Distributions IOService::start_watchdog_timer( void )
5693*1031c584SApple OSS Distributions {
5694*1031c584SApple OSS Distributions int timeout;
5695*1031c584SApple OSS Distributions uint64_t deadline;
5696*1031c584SApple OSS Distributions
5697*1031c584SApple OSS Distributions if (!fWatchdogTimer || (kIOSleepWakeWdogOff & gIOKitDebug)) {
5698*1031c584SApple OSS Distributions return;
5699*1031c584SApple OSS Distributions }
5700*1031c584SApple OSS Distributions
5701*1031c584SApple OSS Distributions IOLockLock(fWatchdogLock);
5702*1031c584SApple OSS Distributions
5703*1031c584SApple OSS Distributions timeout = getPMRootDomain()->getWatchdogTimeout();
5704*1031c584SApple OSS Distributions clock_interval_to_deadline(timeout, kSecondScale, &deadline);
5705*1031c584SApple OSS Distributions start_watchdog_timer(deadline);
5706*1031c584SApple OSS Distributions IOLockUnlock(fWatchdogLock);
5707*1031c584SApple OSS Distributions }
5708*1031c584SApple OSS Distributions
5709*1031c584SApple OSS Distributions void
start_watchdog_timer(uint64_t deadline)5710*1031c584SApple OSS Distributions IOService::start_watchdog_timer(uint64_t deadline)
5711*1031c584SApple OSS Distributions {
5712*1031c584SApple OSS Distributions IOLockAssert(fWatchdogLock, kIOLockAssertOwned);
5713*1031c584SApple OSS Distributions fWatchdogDeadline = deadline;
5714*1031c584SApple OSS Distributions
5715*1031c584SApple OSS Distributions if (!thread_call_isactive(fWatchdogTimer)) {
5716*1031c584SApple OSS Distributions thread_call_enter_delayed(fWatchdogTimer, deadline);
5717*1031c584SApple OSS Distributions }
5718*1031c584SApple OSS Distributions }
5719*1031c584SApple OSS Distributions
5720*1031c584SApple OSS Distributions //*********************************************************************************
5721*1031c584SApple OSS Distributions // [private] stop_watchdog_timer
5722*1031c584SApple OSS Distributions //*********************************************************************************
5723*1031c584SApple OSS Distributions
5724*1031c584SApple OSS Distributions void
stop_watchdog_timer(void)5725*1031c584SApple OSS Distributions IOService::stop_watchdog_timer( void )
5726*1031c584SApple OSS Distributions {
5727*1031c584SApple OSS Distributions if (!fWatchdogTimer || (kIOSleepWakeWdogOff & gIOKitDebug)) {
5728*1031c584SApple OSS Distributions return;
5729*1031c584SApple OSS Distributions }
5730*1031c584SApple OSS Distributions
5731*1031c584SApple OSS Distributions IOLockLock(fWatchdogLock);
5732*1031c584SApple OSS Distributions
5733*1031c584SApple OSS Distributions thread_call_cancel(fWatchdogTimer);
5734*1031c584SApple OSS Distributions fWatchdogDeadline = 0;
5735*1031c584SApple OSS Distributions
5736*1031c584SApple OSS Distributions while (fBlockedArray->getCount()) {
5737*1031c584SApple OSS Distributions IOService *obj = OSDynamicCast(IOService, fBlockedArray->getObject(0));
5738*1031c584SApple OSS Distributions if (obj) {
5739*1031c584SApple OSS Distributions PM_ERROR("WDOG:Object %s unexpected in blocked array\n", obj->fName);
5740*1031c584SApple OSS Distributions fBlockedArray->removeObject(0);
5741*1031c584SApple OSS Distributions }
5742*1031c584SApple OSS Distributions }
5743*1031c584SApple OSS Distributions
5744*1031c584SApple OSS Distributions IOLockUnlock(fWatchdogLock);
5745*1031c584SApple OSS Distributions }
5746*1031c584SApple OSS Distributions
5747*1031c584SApple OSS Distributions //*********************************************************************************
5748*1031c584SApple OSS Distributions // reset_watchdog_timer
5749*1031c584SApple OSS Distributions //*********************************************************************************
5750*1031c584SApple OSS Distributions
5751*1031c584SApple OSS Distributions void
reset_watchdog_timer(IOService * blockedObject,int pendingResponseTimeout)5752*1031c584SApple OSS Distributions IOService::reset_watchdog_timer(IOService *blockedObject, int pendingResponseTimeout)
5753*1031c584SApple OSS Distributions {
5754*1031c584SApple OSS Distributions unsigned int i;
5755*1031c584SApple OSS Distributions uint64_t deadline;
5756*1031c584SApple OSS Distributions IOService *obj;
5757*1031c584SApple OSS Distributions
5758*1031c584SApple OSS Distributions if (!fWatchdogTimer || (kIOSleepWakeWdogOff & gIOKitDebug)) {
5759*1031c584SApple OSS Distributions return;
5760*1031c584SApple OSS Distributions }
5761*1031c584SApple OSS Distributions
5762*1031c584SApple OSS Distributions
5763*1031c584SApple OSS Distributions IOLockLock(fWatchdogLock);
5764*1031c584SApple OSS Distributions if (!fWatchdogDeadline) {
5765*1031c584SApple OSS Distributions goto exit;
5766*1031c584SApple OSS Distributions }
5767*1031c584SApple OSS Distributions
5768*1031c584SApple OSS Distributions i = fBlockedArray->getNextIndexOfObject(blockedObject, 0);
5769*1031c584SApple OSS Distributions if (pendingResponseTimeout == 0) {
5770*1031c584SApple OSS Distributions blockedObject->fPendingResponseDeadline = 0;
5771*1031c584SApple OSS Distributions if (i == (unsigned int)-1) {
5772*1031c584SApple OSS Distributions goto exit;
5773*1031c584SApple OSS Distributions }
5774*1031c584SApple OSS Distributions fBlockedArray->removeObject(i);
5775*1031c584SApple OSS Distributions } else {
5776*1031c584SApple OSS Distributions // Set deadline 2secs after the expected response timeout to allow
5777*1031c584SApple OSS Distributions // ack timer to handle the timeout.
5778*1031c584SApple OSS Distributions clock_interval_to_deadline(pendingResponseTimeout + 2, kSecondScale, &deadline);
5779*1031c584SApple OSS Distributions
5780*1031c584SApple OSS Distributions if (i != (unsigned int)-1) {
5781*1031c584SApple OSS Distributions PM_ERROR("WDOG:Object %s is already blocked for responses. Ignoring timeout %d\n",
5782*1031c584SApple OSS Distributions fName, pendingResponseTimeout);
5783*1031c584SApple OSS Distributions goto exit;
5784*1031c584SApple OSS Distributions }
5785*1031c584SApple OSS Distributions
5786*1031c584SApple OSS Distributions for (i = 0; i < fBlockedArray->getCount(); i++) {
5787*1031c584SApple OSS Distributions obj = OSDynamicCast(IOService, fBlockedArray->getObject(i));
5788*1031c584SApple OSS Distributions if (obj && (obj->fPendingResponseDeadline < deadline)) {
5789*1031c584SApple OSS Distributions blockedObject->fPendingResponseDeadline = deadline;
5790*1031c584SApple OSS Distributions fBlockedArray->setObject(i, blockedObject);
5791*1031c584SApple OSS Distributions break;
5792*1031c584SApple OSS Distributions }
5793*1031c584SApple OSS Distributions }
5794*1031c584SApple OSS Distributions if (i == fBlockedArray->getCount()) {
5795*1031c584SApple OSS Distributions blockedObject->fPendingResponseDeadline = deadline;
5796*1031c584SApple OSS Distributions fBlockedArray->setObject(blockedObject);
5797*1031c584SApple OSS Distributions }
5798*1031c584SApple OSS Distributions }
5799*1031c584SApple OSS Distributions
5800*1031c584SApple OSS Distributions obj = OSDynamicCast(IOService, fBlockedArray->getObject(0));
5801*1031c584SApple OSS Distributions if (!obj) {
5802*1031c584SApple OSS Distributions int timeout = getPMRootDomain()->getWatchdogTimeout();
5803*1031c584SApple OSS Distributions clock_interval_to_deadline(timeout, kSecondScale, &deadline);
5804*1031c584SApple OSS Distributions } else {
5805*1031c584SApple OSS Distributions deadline = obj->fPendingResponseDeadline;
5806*1031c584SApple OSS Distributions }
5807*1031c584SApple OSS Distributions
5808*1031c584SApple OSS Distributions thread_call_cancel(fWatchdogTimer);
5809*1031c584SApple OSS Distributions start_watchdog_timer(deadline);
5810*1031c584SApple OSS Distributions
5811*1031c584SApple OSS Distributions exit:
5812*1031c584SApple OSS Distributions IOLockUnlock(fWatchdogLock);
5813*1031c584SApple OSS Distributions }
5814*1031c584SApple OSS Distributions
5815*1031c584SApple OSS Distributions
5816*1031c584SApple OSS Distributions //*********************************************************************************
5817*1031c584SApple OSS Distributions // [static] watchdog_timer_expired
5818*1031c584SApple OSS Distributions //
5819*1031c584SApple OSS Distributions // Inside PM work loop's gate.
5820*1031c584SApple OSS Distributions //*********************************************************************************
5821*1031c584SApple OSS Distributions
5822*1031c584SApple OSS Distributions void
watchdog_timer_expired(thread_call_param_t arg0,thread_call_param_t arg1)5823*1031c584SApple OSS Distributions IOService::watchdog_timer_expired( thread_call_param_t arg0, thread_call_param_t arg1 )
5824*1031c584SApple OSS Distributions {
5825*1031c584SApple OSS Distributions IOService * me = (IOService *) arg0;
5826*1031c584SApple OSS Distributions bool expired;
5827*1031c584SApple OSS Distributions
5828*1031c584SApple OSS Distributions IOLockLock(me->fWatchdogLock);
5829*1031c584SApple OSS Distributions expired = me->fWatchdogDeadline && (me->fWatchdogDeadline <= mach_absolute_time());
5830*1031c584SApple OSS Distributions IOLockUnlock(me->fWatchdogLock);
5831*1031c584SApple OSS Distributions if (!expired) {
5832*1031c584SApple OSS Distributions return;
5833*1031c584SApple OSS Distributions }
5834*1031c584SApple OSS Distributions
5835*1031c584SApple OSS Distributions gIOPMWatchDogThread = current_thread();
5836*1031c584SApple OSS Distributions getPMRootDomain()->sleepWakeDebugTrig(true);
5837*1031c584SApple OSS Distributions gIOPMWatchDogThread = NULL;
5838*1031c584SApple OSS Distributions thread_call_free(me->fWatchdogTimer);
5839*1031c584SApple OSS Distributions me->fWatchdogTimer = NULL;
5840*1031c584SApple OSS Distributions
5841*1031c584SApple OSS Distributions return;
5842*1031c584SApple OSS Distributions }
5843*1031c584SApple OSS Distributions
5844*1031c584SApple OSS Distributions
5845*1031c584SApple OSS Distributions IOWorkLoop *
getIOPMWorkloop(void)5846*1031c584SApple OSS Distributions IOService::getIOPMWorkloop( void )
5847*1031c584SApple OSS Distributions {
5848*1031c584SApple OSS Distributions return gIOPMWorkLoop;
5849*1031c584SApple OSS Distributions }
5850*1031c584SApple OSS Distributions
5851*1031c584SApple OSS Distributions
5852*1031c584SApple OSS Distributions
5853*1031c584SApple OSS Distributions //*********************************************************************************
5854*1031c584SApple OSS Distributions // [private] start_ack_timer
5855*1031c584SApple OSS Distributions //*********************************************************************************
5856*1031c584SApple OSS Distributions
5857*1031c584SApple OSS Distributions void
start_ack_timer(void)5858*1031c584SApple OSS Distributions IOService::start_ack_timer( void )
5859*1031c584SApple OSS Distributions {
5860*1031c584SApple OSS Distributions start_ack_timer( ACK_TIMER_PERIOD, kNanosecondScale );
5861*1031c584SApple OSS Distributions }
5862*1031c584SApple OSS Distributions
5863*1031c584SApple OSS Distributions void
start_ack_timer(UInt32 interval,UInt32 scale)5864*1031c584SApple OSS Distributions IOService::start_ack_timer( UInt32 interval, UInt32 scale )
5865*1031c584SApple OSS Distributions {
5866*1031c584SApple OSS Distributions AbsoluteTime deadline;
5867*1031c584SApple OSS Distributions boolean_t pending;
5868*1031c584SApple OSS Distributions
5869*1031c584SApple OSS Distributions clock_interval_to_deadline(interval, scale, &deadline);
5870*1031c584SApple OSS Distributions
5871*1031c584SApple OSS Distributions retain();
5872*1031c584SApple OSS Distributions pending = thread_call_enter_delayed(fAckTimer, deadline);
5873*1031c584SApple OSS Distributions if (pending) {
5874*1031c584SApple OSS Distributions release();
5875*1031c584SApple OSS Distributions }
5876*1031c584SApple OSS Distributions }
5877*1031c584SApple OSS Distributions
5878*1031c584SApple OSS Distributions //*********************************************************************************
5879*1031c584SApple OSS Distributions // [private] stop_ack_timer
5880*1031c584SApple OSS Distributions //*********************************************************************************
5881*1031c584SApple OSS Distributions
5882*1031c584SApple OSS Distributions void
stop_ack_timer(void)5883*1031c584SApple OSS Distributions IOService::stop_ack_timer( void )
5884*1031c584SApple OSS Distributions {
5885*1031c584SApple OSS Distributions boolean_t pending;
5886*1031c584SApple OSS Distributions
5887*1031c584SApple OSS Distributions pending = thread_call_cancel(fAckTimer);
5888*1031c584SApple OSS Distributions if (pending) {
5889*1031c584SApple OSS Distributions release();
5890*1031c584SApple OSS Distributions }
5891*1031c584SApple OSS Distributions }
5892*1031c584SApple OSS Distributions
5893*1031c584SApple OSS Distributions //*********************************************************************************
5894*1031c584SApple OSS Distributions // [static] actionAckTimerExpired
5895*1031c584SApple OSS Distributions //
5896*1031c584SApple OSS Distributions // Inside PM work loop's gate.
5897*1031c584SApple OSS Distributions //*********************************************************************************
5898*1031c584SApple OSS Distributions
5899*1031c584SApple OSS Distributions IOReturn
actionAckTimerExpired(OSObject * target,void * arg0,void * arg1,void * arg2,void * arg3)5900*1031c584SApple OSS Distributions IOService::actionAckTimerExpired(
5901*1031c584SApple OSS Distributions OSObject * target,
5902*1031c584SApple OSS Distributions void * arg0, void * arg1,
5903*1031c584SApple OSS Distributions void * arg2, void * arg3 )
5904*1031c584SApple OSS Distributions {
5905*1031c584SApple OSS Distributions IOService * me = (IOService *) target;
5906*1031c584SApple OSS Distributions bool done;
5907*1031c584SApple OSS Distributions
5908*1031c584SApple OSS Distributions // done will be true if the timer tick unblocks the machine state,
5909*1031c584SApple OSS Distributions // otherwise no need to signal the work loop.
5910*1031c584SApple OSS Distributions
5911*1031c584SApple OSS Distributions done = me->ackTimerTick();
5912*1031c584SApple OSS Distributions if (done && gIOPMWorkQueue) {
5913*1031c584SApple OSS Distributions gIOPMWorkQueue->signalWorkAvailable();
5914*1031c584SApple OSS Distributions }
5915*1031c584SApple OSS Distributions
5916*1031c584SApple OSS Distributions return kIOReturnSuccess;
5917*1031c584SApple OSS Distributions }
5918*1031c584SApple OSS Distributions
5919*1031c584SApple OSS Distributions //*********************************************************************************
5920*1031c584SApple OSS Distributions // ack_timer_expired
5921*1031c584SApple OSS Distributions //
5922*1031c584SApple OSS Distributions // Thread call function. Holds a retain while the callout is in flight.
5923*1031c584SApple OSS Distributions //*********************************************************************************
5924*1031c584SApple OSS Distributions
5925*1031c584SApple OSS Distributions void
ack_timer_expired(thread_call_param_t arg0,thread_call_param_t arg1)5926*1031c584SApple OSS Distributions IOService::ack_timer_expired( thread_call_param_t arg0, thread_call_param_t arg1 )
5927*1031c584SApple OSS Distributions {
5928*1031c584SApple OSS Distributions IOService * me = (IOService *) arg0;
5929*1031c584SApple OSS Distributions
5930*1031c584SApple OSS Distributions if (gIOPMWorkLoop) {
5931*1031c584SApple OSS Distributions gIOPMWorkLoop->runAction(&actionAckTimerExpired, me);
5932*1031c584SApple OSS Distributions }
5933*1031c584SApple OSS Distributions me->release();
5934*1031c584SApple OSS Distributions }
5935*1031c584SApple OSS Distributions
5936*1031c584SApple OSS Distributions
5937*1031c584SApple OSS Distributions // MARK: -
5938*1031c584SApple OSS Distributions // MARK: Client Messaging
5939*1031c584SApple OSS Distributions
5940*1031c584SApple OSS Distributions //*********************************************************************************
5941*1031c584SApple OSS Distributions // [private] tellSystemCapabilityChange
5942*1031c584SApple OSS Distributions //*********************************************************************************
5943*1031c584SApple OSS Distributions
5944*1031c584SApple OSS Distributions void
tellSystemCapabilityChange(uint32_t nextMS)5945*1031c584SApple OSS Distributions IOService::tellSystemCapabilityChange( uint32_t nextMS )
5946*1031c584SApple OSS Distributions {
5947*1031c584SApple OSS Distributions assert(IS_ROOT_DOMAIN);
5948*1031c584SApple OSS Distributions
5949*1031c584SApple OSS Distributions MS_PUSH( nextMS );
5950*1031c584SApple OSS Distributions fMachineState = kIOPM_TellCapabilityChangeDone;
5951*1031c584SApple OSS Distributions fOutOfBandMessage = kIOMessageSystemCapabilityChange;
5952*1031c584SApple OSS Distributions
5953*1031c584SApple OSS Distributions if (fIsPreChange) {
5954*1031c584SApple OSS Distributions // Notify app first on pre-change.
5955*1031c584SApple OSS Distributions fOutOfBandParameter = kNotifyCapabilityChangeApps;
5956*1031c584SApple OSS Distributions } else {
5957*1031c584SApple OSS Distributions // Notify kernel clients first on post-change.
5958*1031c584SApple OSS Distributions fOutOfBandParameter = kNotifyCapabilityChangePriority;
5959*1031c584SApple OSS Distributions }
5960*1031c584SApple OSS Distributions
5961*1031c584SApple OSS Distributions tellClientsWithResponse( fOutOfBandMessage );
5962*1031c584SApple OSS Distributions }
5963*1031c584SApple OSS Distributions
5964*1031c584SApple OSS Distributions //*********************************************************************************
5965*1031c584SApple OSS Distributions // [public] askChangeDown
5966*1031c584SApple OSS Distributions //
5967*1031c584SApple OSS Distributions // Ask registered applications and kernel clients if we can change to a lower
5968*1031c584SApple OSS Distributions // power state.
5969*1031c584SApple OSS Distributions //
5970*1031c584SApple OSS Distributions // Subclass can override this to send a different message type. Parameter is
5971*1031c584SApple OSS Distributions // the destination state number.
5972*1031c584SApple OSS Distributions //
5973*1031c584SApple OSS Distributions // Return true if we don't have to wait for acknowledgements
5974*1031c584SApple OSS Distributions //*********************************************************************************
5975*1031c584SApple OSS Distributions
5976*1031c584SApple OSS Distributions bool
askChangeDown(unsigned long stateNum)5977*1031c584SApple OSS Distributions IOService::askChangeDown( unsigned long stateNum )
5978*1031c584SApple OSS Distributions {
5979*1031c584SApple OSS Distributions return tellClientsWithResponse( kIOMessageCanDevicePowerOff );
5980*1031c584SApple OSS Distributions }
5981*1031c584SApple OSS Distributions
5982*1031c584SApple OSS Distributions //*********************************************************************************
5983*1031c584SApple OSS Distributions // [private] tellChangeDown1
5984*1031c584SApple OSS Distributions //
5985*1031c584SApple OSS Distributions // Notify registered applications and kernel clients that we are definitely
5986*1031c584SApple OSS Distributions // dropping power.
5987*1031c584SApple OSS Distributions //
5988*1031c584SApple OSS Distributions // Return true if we don't have to wait for acknowledgements
5989*1031c584SApple OSS Distributions //*********************************************************************************
5990*1031c584SApple OSS Distributions
5991*1031c584SApple OSS Distributions bool
tellChangeDown1(unsigned long stateNum)5992*1031c584SApple OSS Distributions IOService::tellChangeDown1( unsigned long stateNum )
5993*1031c584SApple OSS Distributions {
5994*1031c584SApple OSS Distributions fOutOfBandParameter = kNotifyApps;
5995*1031c584SApple OSS Distributions return tellChangeDown(stateNum);
5996*1031c584SApple OSS Distributions }
5997*1031c584SApple OSS Distributions
5998*1031c584SApple OSS Distributions //*********************************************************************************
5999*1031c584SApple OSS Distributions // [private] tellChangeDown2
6000*1031c584SApple OSS Distributions //
6001*1031c584SApple OSS Distributions // Notify priority clients that we are definitely dropping power.
6002*1031c584SApple OSS Distributions //
6003*1031c584SApple OSS Distributions // Return true if we don't have to wait for acknowledgements
6004*1031c584SApple OSS Distributions //*********************************************************************************
6005*1031c584SApple OSS Distributions
6006*1031c584SApple OSS Distributions bool
tellChangeDown2(unsigned long stateNum)6007*1031c584SApple OSS Distributions IOService::tellChangeDown2( unsigned long stateNum )
6008*1031c584SApple OSS Distributions {
6009*1031c584SApple OSS Distributions fOutOfBandParameter = kNotifyPriority;
6010*1031c584SApple OSS Distributions return tellChangeDown(stateNum);
6011*1031c584SApple OSS Distributions }
6012*1031c584SApple OSS Distributions
6013*1031c584SApple OSS Distributions //*********************************************************************************
6014*1031c584SApple OSS Distributions // [public] tellChangeDown
6015*1031c584SApple OSS Distributions //
6016*1031c584SApple OSS Distributions // Notify registered applications and kernel clients that we are definitely
6017*1031c584SApple OSS Distributions // dropping power.
6018*1031c584SApple OSS Distributions //
6019*1031c584SApple OSS Distributions // Subclass can override this to send a different message type. Parameter is
6020*1031c584SApple OSS Distributions // the destination state number.
6021*1031c584SApple OSS Distributions //
6022*1031c584SApple OSS Distributions // Return true if we don't have to wait for acknowledgements
6023*1031c584SApple OSS Distributions //*********************************************************************************
6024*1031c584SApple OSS Distributions
6025*1031c584SApple OSS Distributions bool
tellChangeDown(unsigned long stateNum)6026*1031c584SApple OSS Distributions IOService::tellChangeDown( unsigned long stateNum )
6027*1031c584SApple OSS Distributions {
6028*1031c584SApple OSS Distributions return tellClientsWithResponse( kIOMessageDeviceWillPowerOff );
6029*1031c584SApple OSS Distributions }
6030*1031c584SApple OSS Distributions
6031*1031c584SApple OSS Distributions //*********************************************************************************
6032*1031c584SApple OSS Distributions // cleanClientResponses
6033*1031c584SApple OSS Distributions //
6034*1031c584SApple OSS Distributions //*********************************************************************************
6035*1031c584SApple OSS Distributions
6036*1031c584SApple OSS Distributions static void
logAppTimeouts(OSObject * object,void * arg)6037*1031c584SApple OSS Distributions logAppTimeouts( OSObject * object, void * arg )
6038*1031c584SApple OSS Distributions {
6039*1031c584SApple OSS Distributions IOPMInterestContext * context = (IOPMInterestContext *) arg;
6040*1031c584SApple OSS Distributions OSObject * flag;
6041*1031c584SApple OSS Distributions unsigned int clientIndex;
6042*1031c584SApple OSS Distributions int pid = 0;
6043*1031c584SApple OSS Distributions char name[128];
6044*1031c584SApple OSS Distributions
6045*1031c584SApple OSS Distributions if (OSDynamicCast(_IOServiceInterestNotifier, object)) {
6046*1031c584SApple OSS Distributions // Discover the 'counter' value or index assigned to this client
6047*1031c584SApple OSS Distributions // when it was notified, by searching for the array index of the
6048*1031c584SApple OSS Distributions // client in an array holding the cached interested clients.
6049*1031c584SApple OSS Distributions
6050*1031c584SApple OSS Distributions clientIndex = context->notifyClients->getNextIndexOfObject(object, 0);
6051*1031c584SApple OSS Distributions
6052*1031c584SApple OSS Distributions if ((clientIndex != (unsigned int) -1) &&
6053*1031c584SApple OSS Distributions (flag = context->responseArray->getObject(clientIndex)) &&
6054*1031c584SApple OSS Distributions (flag != kOSBooleanTrue)) {
6055*1031c584SApple OSS Distributions OSNumber *clientID = copyClientIDForNotification(object, context);
6056*1031c584SApple OSS Distributions
6057*1031c584SApple OSS Distributions name[0] = '\0';
6058*1031c584SApple OSS Distributions if (clientID) {
6059*1031c584SApple OSS Distributions pid = clientID->unsigned32BitValue();
6060*1031c584SApple OSS Distributions proc_name(pid, name, sizeof(name));
6061*1031c584SApple OSS Distributions clientID->release();
6062*1031c584SApple OSS Distributions }
6063*1031c584SApple OSS Distributions
6064*1031c584SApple OSS Distributions PM_ERROR("PM notification timeout (pid %d, %s)\n", pid, name);
6065*1031c584SApple OSS Distributions
6066*1031c584SApple OSS Distributions // TODO: record message type if possible
6067*1031c584SApple OSS Distributions IOService::getPMRootDomain()->pmStatsRecordApplicationResponse(
6068*1031c584SApple OSS Distributions gIOPMStatsResponseTimedOut,
6069*1031c584SApple OSS Distributions name, 0, (30 * 1000), pid, object);
6070*1031c584SApple OSS Distributions }
6071*1031c584SApple OSS Distributions }
6072*1031c584SApple OSS Distributions }
6073*1031c584SApple OSS Distributions
6074*1031c584SApple OSS Distributions void
cleanClientResponses(bool logErrors)6075*1031c584SApple OSS Distributions IOService::cleanClientResponses( bool logErrors )
6076*1031c584SApple OSS Distributions {
6077*1031c584SApple OSS Distributions if (logErrors && fResponseArray) {
6078*1031c584SApple OSS Distributions switch (fOutOfBandParameter) {
6079*1031c584SApple OSS Distributions case kNotifyApps:
6080*1031c584SApple OSS Distributions case kNotifyCapabilityChangeApps:
6081*1031c584SApple OSS Distributions if (fNotifyClientArray) {
6082*1031c584SApple OSS Distributions IOPMInterestContext context;
6083*1031c584SApple OSS Distributions
6084*1031c584SApple OSS Distributions context.responseArray = fResponseArray;
6085*1031c584SApple OSS Distributions context.notifyClients = fNotifyClientArray;
6086*1031c584SApple OSS Distributions context.serialNumber = fSerialNumber;
6087*1031c584SApple OSS Distributions context.messageType = kIOMessageCopyClientID;
6088*1031c584SApple OSS Distributions context.notifyType = kNotifyApps;
6089*1031c584SApple OSS Distributions context.isPreChange = fIsPreChange;
6090*1031c584SApple OSS Distributions context.enableTracing = false;
6091*1031c584SApple OSS Distributions context.us = this;
6092*1031c584SApple OSS Distributions context.maxTimeRequested = 0;
6093*1031c584SApple OSS Distributions context.stateNumber = fHeadNotePowerState;
6094*1031c584SApple OSS Distributions context.stateFlags = fHeadNotePowerArrayEntry->capabilityFlags;
6095*1031c584SApple OSS Distributions context.changeFlags = fHeadNoteChangeFlags;
6096*1031c584SApple OSS Distributions
6097*1031c584SApple OSS Distributions applyToInterested(gIOAppPowerStateInterest, logAppTimeouts, (void *) &context);
6098*1031c584SApple OSS Distributions }
6099*1031c584SApple OSS Distributions break;
6100*1031c584SApple OSS Distributions
6101*1031c584SApple OSS Distributions default:
6102*1031c584SApple OSS Distributions // kNotifyPriority, kNotifyCapabilityChangePriority
6103*1031c584SApple OSS Distributions // TODO: identify the priority client that has not acked
6104*1031c584SApple OSS Distributions PM_ERROR("PM priority notification timeout\n");
6105*1031c584SApple OSS Distributions if (gIOKitDebug & kIOLogDebugPower) {
6106*1031c584SApple OSS Distributions panic("PM priority notification timeout");
6107*1031c584SApple OSS Distributions }
6108*1031c584SApple OSS Distributions break;
6109*1031c584SApple OSS Distributions }
6110*1031c584SApple OSS Distributions }
6111*1031c584SApple OSS Distributions
6112*1031c584SApple OSS Distributions if (IS_ROOT_DOMAIN) {
6113*1031c584SApple OSS Distributions getPMRootDomain()->reset_watchdog_timer(this, 0);
6114*1031c584SApple OSS Distributions }
6115*1031c584SApple OSS Distributions if (fResponseArray) {
6116*1031c584SApple OSS Distributions fResponseArray->release();
6117*1031c584SApple OSS Distributions fResponseArray = NULL;
6118*1031c584SApple OSS Distributions }
6119*1031c584SApple OSS Distributions if (fNotifyClientArray) {
6120*1031c584SApple OSS Distributions fNotifyClientArray->release();
6121*1031c584SApple OSS Distributions fNotifyClientArray = NULL;
6122*1031c584SApple OSS Distributions }
6123*1031c584SApple OSS Distributions }
6124*1031c584SApple OSS Distributions
6125*1031c584SApple OSS Distributions //*********************************************************************************
6126*1031c584SApple OSS Distributions // [protected] tellClientsWithResponse
6127*1031c584SApple OSS Distributions //
6128*1031c584SApple OSS Distributions // Notify registered applications and kernel clients that we are definitely
6129*1031c584SApple OSS Distributions // dropping power.
6130*1031c584SApple OSS Distributions //
6131*1031c584SApple OSS Distributions // Return true if we don't have to wait for acknowledgements
6132*1031c584SApple OSS Distributions //*********************************************************************************
6133*1031c584SApple OSS Distributions
6134*1031c584SApple OSS Distributions bool
tellClientsWithResponse(int messageType)6135*1031c584SApple OSS Distributions IOService::tellClientsWithResponse( int messageType )
6136*1031c584SApple OSS Distributions {
6137*1031c584SApple OSS Distributions IOPMInterestContext context;
6138*1031c584SApple OSS Distributions bool isRootDomain = IS_ROOT_DOMAIN;
6139*1031c584SApple OSS Distributions uint32_t maxTimeOut = kMaxTimeRequested;
6140*1031c584SApple OSS Distributions
6141*1031c584SApple OSS Distributions PM_ASSERT_IN_GATE();
6142*1031c584SApple OSS Distributions assert( fResponseArray == NULL );
6143*1031c584SApple OSS Distributions assert( fNotifyClientArray == NULL );
6144*1031c584SApple OSS Distributions
6145*1031c584SApple OSS Distributions RD_LOG("tellClientsWithResponse( %s, %s )\n", getIOMessageString(messageType),
6146*1031c584SApple OSS Distributions getNotificationPhaseString(fOutOfBandParameter));
6147*1031c584SApple OSS Distributions
6148*1031c584SApple OSS Distributions fResponseArray = OSArray::withCapacity( 1 );
6149*1031c584SApple OSS Distributions if (!fResponseArray) {
6150*1031c584SApple OSS Distributions goto exit;
6151*1031c584SApple OSS Distributions }
6152*1031c584SApple OSS Distributions
6153*1031c584SApple OSS Distributions fResponseArray->setCapacityIncrement(8);
6154*1031c584SApple OSS Distributions if (++fSerialNumber == 0) {
6155*1031c584SApple OSS Distributions fSerialNumber++;
6156*1031c584SApple OSS Distributions }
6157*1031c584SApple OSS Distributions
6158*1031c584SApple OSS Distributions context.responseArray = fResponseArray;
6159*1031c584SApple OSS Distributions context.notifyClients = NULL;
6160*1031c584SApple OSS Distributions context.serialNumber = fSerialNumber;
6161*1031c584SApple OSS Distributions context.messageType = messageType;
6162*1031c584SApple OSS Distributions context.notifyType = fOutOfBandParameter;
6163*1031c584SApple OSS Distributions context.skippedInDark = 0;
6164*1031c584SApple OSS Distributions context.notSkippedInDark = 0;
6165*1031c584SApple OSS Distributions context.isPreChange = fIsPreChange;
6166*1031c584SApple OSS Distributions context.enableTracing = false;
6167*1031c584SApple OSS Distributions context.us = this;
6168*1031c584SApple OSS Distributions context.maxTimeRequested = 0;
6169*1031c584SApple OSS Distributions context.stateNumber = fHeadNotePowerState;
6170*1031c584SApple OSS Distributions context.stateFlags = fHeadNotePowerArrayEntry->capabilityFlags;
6171*1031c584SApple OSS Distributions context.changeFlags = fHeadNoteChangeFlags;
6172*1031c584SApple OSS Distributions context.messageFilter = (isRootDomain) ?
6173*1031c584SApple OSS Distributions OSMemberFunctionCast(
6174*1031c584SApple OSS Distributions IOPMMessageFilter,
6175*1031c584SApple OSS Distributions (IOPMrootDomain *)this,
6176*1031c584SApple OSS Distributions &IOPMrootDomain::systemMessageFilter) : NULL;
6177*1031c584SApple OSS Distributions
6178*1031c584SApple OSS Distributions switch (fOutOfBandParameter) {
6179*1031c584SApple OSS Distributions case kNotifyApps:
6180*1031c584SApple OSS Distributions applyToInterested( gIOAppPowerStateInterest,
6181*1031c584SApple OSS Distributions pmTellAppWithResponse, (void *) &context );
6182*1031c584SApple OSS Distributions
6183*1031c584SApple OSS Distributions if (isRootDomain &&
6184*1031c584SApple OSS Distributions (fMachineState != kIOPM_OurChangeTellClientsPowerDown) &&
6185*1031c584SApple OSS Distributions (fMachineState != kIOPM_SyncTellClientsPowerDown) &&
6186*1031c584SApple OSS Distributions (context.messageType != kIOPMMessageLastCallBeforeSleep)) {
6187*1031c584SApple OSS Distributions // Notify capability app for tellChangeDown1()
6188*1031c584SApple OSS Distributions // but not for askChangeDown().
6189*1031c584SApple OSS Distributions context.notifyType = kNotifyCapabilityChangeApps;
6190*1031c584SApple OSS Distributions context.messageType = kIOMessageSystemCapabilityChange;
6191*1031c584SApple OSS Distributions applyToInterested( gIOAppPowerStateInterest,
6192*1031c584SApple OSS Distributions pmTellCapabilityAppWithResponse, (void *) &context );
6193*1031c584SApple OSS Distributions context.notifyType = fOutOfBandParameter;
6194*1031c584SApple OSS Distributions context.messageType = messageType;
6195*1031c584SApple OSS Distributions }
6196*1031c584SApple OSS Distributions if (context.messageType == kIOMessageCanSystemSleep) {
6197*1031c584SApple OSS Distributions maxTimeOut = kCanSleepMaxTimeReq;
6198*1031c584SApple OSS Distributions if (gSleepAckTimeout) {
6199*1031c584SApple OSS Distributions maxTimeOut = (gSleepAckTimeout * us_per_s);
6200*1031c584SApple OSS Distributions }
6201*1031c584SApple OSS Distributions }
6202*1031c584SApple OSS Distributions if (context.messageType == kIOMessageSystemWillSleep) {
6203*1031c584SApple OSS Distributions maxTimeOut = kWillSleepMaxTimeReq;
6204*1031c584SApple OSS Distributions if (gSleepAckTimeout) {
6205*1031c584SApple OSS Distributions maxTimeOut = (gSleepAckTimeout * us_per_s);
6206*1031c584SApple OSS Distributions }
6207*1031c584SApple OSS Distributions }
6208*1031c584SApple OSS Distributions context.maxTimeRequested = maxTimeOut;
6209*1031c584SApple OSS Distributions context.enableTracing = isRootDomain;
6210*1031c584SApple OSS Distributions applyToInterested( gIOGeneralInterest,
6211*1031c584SApple OSS Distributions pmTellClientWithResponse, (void *) &context );
6212*1031c584SApple OSS Distributions
6213*1031c584SApple OSS Distributions break;
6214*1031c584SApple OSS Distributions
6215*1031c584SApple OSS Distributions case kNotifyPriority:
6216*1031c584SApple OSS Distributions context.enableTracing = isRootDomain;
6217*1031c584SApple OSS Distributions applyToInterested( gIOPriorityPowerStateInterest,
6218*1031c584SApple OSS Distributions pmTellClientWithResponse, (void *) &context );
6219*1031c584SApple OSS Distributions
6220*1031c584SApple OSS Distributions if (isRootDomain) {
6221*1031c584SApple OSS Distributions // Notify capability clients for tellChangeDown2().
6222*1031c584SApple OSS Distributions context.notifyType = kNotifyCapabilityChangePriority;
6223*1031c584SApple OSS Distributions context.messageType = kIOMessageSystemCapabilityChange;
6224*1031c584SApple OSS Distributions applyToInterested( gIOPriorityPowerStateInterest,
6225*1031c584SApple OSS Distributions pmTellCapabilityClientWithResponse, (void *) &context );
6226*1031c584SApple OSS Distributions }
6227*1031c584SApple OSS Distributions break;
6228*1031c584SApple OSS Distributions
6229*1031c584SApple OSS Distributions case kNotifyCapabilityChangeApps:
6230*1031c584SApple OSS Distributions context.enableTracing = isRootDomain;
6231*1031c584SApple OSS Distributions applyToInterested( gIOAppPowerStateInterest,
6232*1031c584SApple OSS Distributions pmTellCapabilityAppWithResponse, (void *) &context );
6233*1031c584SApple OSS Distributions if (context.messageType == kIOMessageCanSystemSleep) {
6234*1031c584SApple OSS Distributions maxTimeOut = kCanSleepMaxTimeReq;
6235*1031c584SApple OSS Distributions if (gSleepAckTimeout) {
6236*1031c584SApple OSS Distributions maxTimeOut = (gSleepAckTimeout * us_per_s);
6237*1031c584SApple OSS Distributions }
6238*1031c584SApple OSS Distributions }
6239*1031c584SApple OSS Distributions context.maxTimeRequested = maxTimeOut;
6240*1031c584SApple OSS Distributions break;
6241*1031c584SApple OSS Distributions
6242*1031c584SApple OSS Distributions case kNotifyCapabilityChangePriority:
6243*1031c584SApple OSS Distributions context.enableTracing = isRootDomain;
6244*1031c584SApple OSS Distributions applyToInterested( gIOPriorityPowerStateInterest,
6245*1031c584SApple OSS Distributions pmTellCapabilityClientWithResponse, (void *) &context );
6246*1031c584SApple OSS Distributions break;
6247*1031c584SApple OSS Distributions }
6248*1031c584SApple OSS Distributions fNotifyClientArray = context.notifyClients;
6249*1031c584SApple OSS Distributions
6250*1031c584SApple OSS Distributions if (context.skippedInDark) {
6251*1031c584SApple OSS Distributions IOLog("tellClientsWithResponse(%s, %s) %d of %d skipped in dark\n",
6252*1031c584SApple OSS Distributions getIOMessageString(messageType), getNotificationPhaseString(fOutOfBandParameter),
6253*1031c584SApple OSS Distributions context.skippedInDark, context.skippedInDark + context.notSkippedInDark);
6254*1031c584SApple OSS Distributions }
6255*1031c584SApple OSS Distributions
6256*1031c584SApple OSS Distributions // do we have to wait for somebody?
6257*1031c584SApple OSS Distributions if (!checkForDone()) {
6258*1031c584SApple OSS Distributions OUR_PMLog(kPMLogStartAckTimer, context.maxTimeRequested, 0);
6259*1031c584SApple OSS Distributions if (context.enableTracing) {
6260*1031c584SApple OSS Distributions getPMRootDomain()->traceDetail(context.messageType, 0, context.maxTimeRequested / 1000);
6261*1031c584SApple OSS Distributions getPMRootDomain()->reset_watchdog_timer(this, context.maxTimeRequested / USEC_PER_SEC + 1);
6262*1031c584SApple OSS Distributions }
6263*1031c584SApple OSS Distributions start_ack_timer( context.maxTimeRequested / 1000, kMillisecondScale );
6264*1031c584SApple OSS Distributions return false;
6265*1031c584SApple OSS Distributions }
6266*1031c584SApple OSS Distributions
6267*1031c584SApple OSS Distributions exit:
6268*1031c584SApple OSS Distributions // everybody responded
6269*1031c584SApple OSS Distributions if (fResponseArray) {
6270*1031c584SApple OSS Distributions fResponseArray->release();
6271*1031c584SApple OSS Distributions fResponseArray = NULL;
6272*1031c584SApple OSS Distributions }
6273*1031c584SApple OSS Distributions if (fNotifyClientArray) {
6274*1031c584SApple OSS Distributions fNotifyClientArray->release();
6275*1031c584SApple OSS Distributions fNotifyClientArray = NULL;
6276*1031c584SApple OSS Distributions }
6277*1031c584SApple OSS Distributions
6278*1031c584SApple OSS Distributions return true;
6279*1031c584SApple OSS Distributions }
6280*1031c584SApple OSS Distributions
6281*1031c584SApple OSS Distributions //*********************************************************************************
6282*1031c584SApple OSS Distributions // [static private] pmTellAppWithResponse
6283*1031c584SApple OSS Distributions //
6284*1031c584SApple OSS Distributions // We send a message to an application, and we expect a response, so we compute a
6285*1031c584SApple OSS Distributions // cookie we can identify the response with.
6286*1031c584SApple OSS Distributions //*********************************************************************************
6287*1031c584SApple OSS Distributions
6288*1031c584SApple OSS Distributions void
pmTellAppWithResponse(OSObject * object,void * arg)6289*1031c584SApple OSS Distributions IOService::pmTellAppWithResponse( OSObject * object, void * arg )
6290*1031c584SApple OSS Distributions {
6291*1031c584SApple OSS Distributions IOPMInterestContext * context = (IOPMInterestContext *) arg;
6292*1031c584SApple OSS Distributions IOServicePM * pwrMgt = context->us->pwrMgt;
6293*1031c584SApple OSS Distributions uint32_t msgIndex, msgRef, msgType;
6294*1031c584SApple OSS Distributions OSNumber *clientID = NULL;
6295*1031c584SApple OSS Distributions proc_t proc = NULL;
6296*1031c584SApple OSS Distributions boolean_t proc_suspended = FALSE;
6297*1031c584SApple OSS Distributions OSObject * waitForReply = kOSBooleanTrue;
6298*1031c584SApple OSS Distributions #if LOG_APP_RESPONSE_TIMES
6299*1031c584SApple OSS Distributions AbsoluteTime now;
6300*1031c584SApple OSS Distributions #endif
6301*1031c584SApple OSS Distributions
6302*1031c584SApple OSS Distributions if (!OSDynamicCast(_IOServiceInterestNotifier, object)) {
6303*1031c584SApple OSS Distributions return;
6304*1031c584SApple OSS Distributions }
6305*1031c584SApple OSS Distributions
6306*1031c584SApple OSS Distributions if (context->us == getPMRootDomain()) {
6307*1031c584SApple OSS Distributions if ((clientID = copyClientIDForNotification(object, context))) {
6308*1031c584SApple OSS Distributions uint32_t clientPID = clientID->unsigned32BitValue();
6309*1031c584SApple OSS Distributions clientID->release();
6310*1031c584SApple OSS Distributions proc = proc_find(clientPID);
6311*1031c584SApple OSS Distributions
6312*1031c584SApple OSS Distributions if (proc) {
6313*1031c584SApple OSS Distributions proc_suspended = get_task_pidsuspended((task_t) proc_task(proc));
6314*1031c584SApple OSS Distributions if (proc_suspended) {
6315*1031c584SApple OSS Distributions logClientIDForNotification(object, context, "PMTellAppWithResponse - Suspended");
6316*1031c584SApple OSS Distributions } else if (getPMRootDomain()->isAOTMode() && get_task_suspended((task_t) proc_task(proc))) {
6317*1031c584SApple OSS Distributions proc_suspended = true;
6318*1031c584SApple OSS Distributions context->skippedInDark++;
6319*1031c584SApple OSS Distributions }
6320*1031c584SApple OSS Distributions proc_rele(proc);
6321*1031c584SApple OSS Distributions if (proc_suspended) {
6322*1031c584SApple OSS Distributions return;
6323*1031c584SApple OSS Distributions }
6324*1031c584SApple OSS Distributions }
6325*1031c584SApple OSS Distributions }
6326*1031c584SApple OSS Distributions }
6327*1031c584SApple OSS Distributions
6328*1031c584SApple OSS Distributions if (context->messageFilter &&
6329*1031c584SApple OSS Distributions !context->messageFilter(context->us, object, context, NULL, &waitForReply)) {
6330*1031c584SApple OSS Distributions if (kIOLogDebugPower & gIOKitDebug) {
6331*1031c584SApple OSS Distributions logClientIDForNotification(object, context, "DROP App");
6332*1031c584SApple OSS Distributions }
6333*1031c584SApple OSS Distributions return;
6334*1031c584SApple OSS Distributions }
6335*1031c584SApple OSS Distributions context->notSkippedInDark++;
6336*1031c584SApple OSS Distributions
6337*1031c584SApple OSS Distributions // Create client array (for tracking purposes) only if the service
6338*1031c584SApple OSS Distributions // has app clients. Usually only root domain does.
6339*1031c584SApple OSS Distributions if (NULL == context->notifyClients) {
6340*1031c584SApple OSS Distributions context->notifyClients = OSArray::withCapacity( 32 );
6341*1031c584SApple OSS Distributions }
6342*1031c584SApple OSS Distributions
6343*1031c584SApple OSS Distributions msgType = context->messageType;
6344*1031c584SApple OSS Distributions msgIndex = context->responseArray->getCount();
6345*1031c584SApple OSS Distributions msgRef = ((context->serialNumber & 0xFFFF) << 16) + (msgIndex & 0xFFFF);
6346*1031c584SApple OSS Distributions
6347*1031c584SApple OSS Distributions OUR_PMLog(kPMLogAppNotify, msgType, msgRef);
6348*1031c584SApple OSS Distributions if (kIOLogDebugPower & gIOKitDebug) {
6349*1031c584SApple OSS Distributions logClientIDForNotification(object, context, "MESG App");
6350*1031c584SApple OSS Distributions }
6351*1031c584SApple OSS Distributions
6352*1031c584SApple OSS Distributions if (waitForReply == kOSBooleanTrue) {
6353*1031c584SApple OSS Distributions OSNumber * num;
6354*1031c584SApple OSS Distributions clock_get_uptime(&now);
6355*1031c584SApple OSS Distributions num = OSNumber::withNumber(AbsoluteTime_to_scalar(&now), sizeof(uint64_t) * 8);
6356*1031c584SApple OSS Distributions if (num) {
6357*1031c584SApple OSS Distributions context->responseArray->setObject(msgIndex, num);
6358*1031c584SApple OSS Distributions num->release();
6359*1031c584SApple OSS Distributions } else {
6360*1031c584SApple OSS Distributions context->responseArray->setObject(msgIndex, kOSBooleanFalse);
6361*1031c584SApple OSS Distributions }
6362*1031c584SApple OSS Distributions } else {
6363*1031c584SApple OSS Distributions context->responseArray->setObject(msgIndex, kOSBooleanTrue);
6364*1031c584SApple OSS Distributions if (kIOLogDebugPower & gIOKitDebug) {
6365*1031c584SApple OSS Distributions logClientIDForNotification(object, context, "App response ignored");
6366*1031c584SApple OSS Distributions }
6367*1031c584SApple OSS Distributions }
6368*1031c584SApple OSS Distributions
6369*1031c584SApple OSS Distributions if (context->notifyClients) {
6370*1031c584SApple OSS Distributions context->notifyClients->setObject(msgIndex, object);
6371*1031c584SApple OSS Distributions }
6372*1031c584SApple OSS Distributions
6373*1031c584SApple OSS Distributions context->us->messageClient(msgType, object, (void *)(uintptr_t) msgRef);
6374*1031c584SApple OSS Distributions }
6375*1031c584SApple OSS Distributions
6376*1031c584SApple OSS Distributions //*********************************************************************************
6377*1031c584SApple OSS Distributions // [static private] pmTellClientWithResponse
6378*1031c584SApple OSS Distributions //
6379*1031c584SApple OSS Distributions // We send a message to an in-kernel client, and we expect a response,
6380*1031c584SApple OSS Distributions // so we compute a cookie we can identify the response with.
6381*1031c584SApple OSS Distributions //*********************************************************************************
6382*1031c584SApple OSS Distributions
6383*1031c584SApple OSS Distributions void
pmTellClientWithResponse(OSObject * object,void * arg)6384*1031c584SApple OSS Distributions IOService::pmTellClientWithResponse( OSObject * object, void * arg )
6385*1031c584SApple OSS Distributions {
6386*1031c584SApple OSS Distributions IOPowerStateChangeNotification notify;
6387*1031c584SApple OSS Distributions IOPMInterestContext * context = (IOPMInterestContext *) arg;
6388*1031c584SApple OSS Distributions OSObject * replied = kOSBooleanTrue;
6389*1031c584SApple OSS Distributions _IOServiceInterestNotifier * notifier;
6390*1031c584SApple OSS Distributions uint32_t msgIndex, msgRef, msgType;
6391*1031c584SApple OSS Distributions IOReturn retCode;
6392*1031c584SApple OSS Distributions AbsoluteTime start, end;
6393*1031c584SApple OSS Distributions uint64_t nsec;
6394*1031c584SApple OSS Distributions bool enableTracing;
6395*1031c584SApple OSS Distributions
6396*1031c584SApple OSS Distributions if (context->messageFilter &&
6397*1031c584SApple OSS Distributions !context->messageFilter(context->us, object, context, NULL, NULL)) {
6398*1031c584SApple OSS Distributions getPMRootDomain()->traceFilteredNotification(object);
6399*1031c584SApple OSS Distributions return;
6400*1031c584SApple OSS Distributions }
6401*1031c584SApple OSS Distributions
6402*1031c584SApple OSS Distributions // Besides interest notifiers this applier function can also be invoked against
6403*1031c584SApple OSS Distributions // IOService clients of context->us, so notifier can be NULL. But for tracing
6404*1031c584SApple OSS Distributions // purposes the IOService clients can be ignored but each will still consume
6405*1031c584SApple OSS Distributions // an entry in the responseArray and also advance msgIndex.
6406*1031c584SApple OSS Distributions notifier = OSDynamicCast(_IOServiceInterestNotifier, object);
6407*1031c584SApple OSS Distributions msgType = context->messageType;
6408*1031c584SApple OSS Distributions msgIndex = context->responseArray->getCount();
6409*1031c584SApple OSS Distributions msgRef = ((context->serialNumber & 0xFFFF) << 16) + (msgIndex & 0xFFFF);
6410*1031c584SApple OSS Distributions enableTracing = context->enableTracing && (notifier != NULL);
6411*1031c584SApple OSS Distributions
6412*1031c584SApple OSS Distributions IOServicePM * pwrMgt = context->us->pwrMgt;
6413*1031c584SApple OSS Distributions if (gIOKitDebug & kIOLogPower) {
6414*1031c584SApple OSS Distributions OUR_PMLog(kPMLogClientNotify, msgRef, msgType);
6415*1031c584SApple OSS Distributions if (OSDynamicCast(IOService, object)) {
6416*1031c584SApple OSS Distributions const char *who = ((IOService *) object)->getName();
6417*1031c584SApple OSS Distributions gPlatform->PMLog(who, kPMLogClientNotify, (uintptr_t) object, 0);
6418*1031c584SApple OSS Distributions } else if (notifier) {
6419*1031c584SApple OSS Distributions OUR_PMLog(kPMLogClientNotify, (uintptr_t) notifier->handler, 0);
6420*1031c584SApple OSS Distributions }
6421*1031c584SApple OSS Distributions }
6422*1031c584SApple OSS Distributions
6423*1031c584SApple OSS Distributions if (NULL == context->notifyClients) {
6424*1031c584SApple OSS Distributions context->notifyClients = OSArray::withCapacity(32);
6425*1031c584SApple OSS Distributions assert(context->notifyClients != NULL);
6426*1031c584SApple OSS Distributions }
6427*1031c584SApple OSS Distributions
6428*1031c584SApple OSS Distributions notify.powerRef = (void *)(uintptr_t) msgRef;
6429*1031c584SApple OSS Distributions notify.returnValue = 0;
6430*1031c584SApple OSS Distributions notify.stateNumber = context->stateNumber;
6431*1031c584SApple OSS Distributions notify.stateFlags = context->stateFlags;
6432*1031c584SApple OSS Distributions
6433*1031c584SApple OSS Distributions clock_get_uptime(&start);
6434*1031c584SApple OSS Distributions if (enableTracing) {
6435*1031c584SApple OSS Distributions getPMRootDomain()->traceNotification(notifier, true, start, msgIndex);
6436*1031c584SApple OSS Distributions }
6437*1031c584SApple OSS Distributions
6438*1031c584SApple OSS Distributions retCode = context->us->messageClient(msgType, object, (void *) ¬ify, sizeof(notify));
6439*1031c584SApple OSS Distributions
6440*1031c584SApple OSS Distributions clock_get_uptime(&end);
6441*1031c584SApple OSS Distributions if (enableTracing) {
6442*1031c584SApple OSS Distributions getPMRootDomain()->traceNotification(notifier, false, end);
6443*1031c584SApple OSS Distributions }
6444*1031c584SApple OSS Distributions
6445*1031c584SApple OSS Distributions if (kIOReturnSuccess == retCode) {
6446*1031c584SApple OSS Distributions if (0 == notify.returnValue) {
6447*1031c584SApple OSS Distributions OUR_PMLog(kPMLogClientAcknowledge, msgRef, (uintptr_t) object);
6448*1031c584SApple OSS Distributions context->responseArray->setObject(msgIndex, replied);
6449*1031c584SApple OSS Distributions } else {
6450*1031c584SApple OSS Distributions replied = kOSBooleanFalse;
6451*1031c584SApple OSS Distributions if (notify.returnValue > context->maxTimeRequested) {
6452*1031c584SApple OSS Distributions if (notify.returnValue > kPriorityClientMaxWait) {
6453*1031c584SApple OSS Distributions context->maxTimeRequested = kPriorityClientMaxWait;
6454*1031c584SApple OSS Distributions PM_ERROR("%s: client %p returned %llu for %s\n",
6455*1031c584SApple OSS Distributions context->us->getName(),
6456*1031c584SApple OSS Distributions notifier ? (void *) OBFUSCATE(notifier->handler) : OBFUSCATE(object),
6457*1031c584SApple OSS Distributions (uint64_t) notify.returnValue,
6458*1031c584SApple OSS Distributions getIOMessageString(msgType));
6459*1031c584SApple OSS Distributions } else {
6460*1031c584SApple OSS Distributions context->maxTimeRequested = (typeof(context->maxTimeRequested))notify.returnValue;
6461*1031c584SApple OSS Distributions }
6462*1031c584SApple OSS Distributions }
6463*1031c584SApple OSS Distributions //
6464*1031c584SApple OSS Distributions // Track time taken to ack, by storing the timestamp of
6465*1031c584SApple OSS Distributions // callback completion
6466*1031c584SApple OSS Distributions OSNumber * num;
6467*1031c584SApple OSS Distributions num = OSNumber::withNumber(AbsoluteTime_to_scalar(&end), sizeof(uint64_t) * 8);
6468*1031c584SApple OSS Distributions if (num) {
6469*1031c584SApple OSS Distributions context->responseArray->setObject(msgIndex, num);
6470*1031c584SApple OSS Distributions num->release();
6471*1031c584SApple OSS Distributions } else {
6472*1031c584SApple OSS Distributions context->responseArray->setObject(msgIndex, replied);
6473*1031c584SApple OSS Distributions }
6474*1031c584SApple OSS Distributions }
6475*1031c584SApple OSS Distributions
6476*1031c584SApple OSS Distributions if (enableTracing) {
6477*1031c584SApple OSS Distributions SUB_ABSOLUTETIME(&end, &start);
6478*1031c584SApple OSS Distributions absolutetime_to_nanoseconds(end, &nsec);
6479*1031c584SApple OSS Distributions
6480*1031c584SApple OSS Distributions if ((nsec > LOG_KEXT_RESPONSE_TIMES) || (notify.returnValue != 0)) {
6481*1031c584SApple OSS Distributions getPMRootDomain()->traceNotificationResponse(notifier, NS_TO_MS(nsec), (uint32_t) notify.returnValue);
6482*1031c584SApple OSS Distributions }
6483*1031c584SApple OSS Distributions }
6484*1031c584SApple OSS Distributions } else {
6485*1031c584SApple OSS Distributions // not a client of ours
6486*1031c584SApple OSS Distributions // so we won't be waiting for response
6487*1031c584SApple OSS Distributions OUR_PMLog(kPMLogClientAcknowledge, msgRef, 0);
6488*1031c584SApple OSS Distributions context->responseArray->setObject(msgIndex, replied);
6489*1031c584SApple OSS Distributions }
6490*1031c584SApple OSS Distributions if (context->notifyClients) {
6491*1031c584SApple OSS Distributions context->notifyClients->setObject(msgIndex, object);
6492*1031c584SApple OSS Distributions }
6493*1031c584SApple OSS Distributions }
6494*1031c584SApple OSS Distributions
6495*1031c584SApple OSS Distributions //*********************************************************************************
6496*1031c584SApple OSS Distributions // [static private] pmTellCapabilityAppWithResponse
6497*1031c584SApple OSS Distributions //*********************************************************************************
6498*1031c584SApple OSS Distributions
6499*1031c584SApple OSS Distributions void
pmTellCapabilityAppWithResponse(OSObject * object,void * arg)6500*1031c584SApple OSS Distributions IOService::pmTellCapabilityAppWithResponse( OSObject * object, void * arg )
6501*1031c584SApple OSS Distributions {
6502*1031c584SApple OSS Distributions IOPMSystemCapabilityChangeParameters msgArg;
6503*1031c584SApple OSS Distributions IOPMInterestContext * context = (IOPMInterestContext *) arg;
6504*1031c584SApple OSS Distributions OSObject * waitForReply = kOSBooleanFalse;
6505*1031c584SApple OSS Distributions IOServicePM * pwrMgt = context->us->pwrMgt;
6506*1031c584SApple OSS Distributions uint32_t msgIndex, msgRef, msgType;
6507*1031c584SApple OSS Distributions #if LOG_APP_RESPONSE_TIMES
6508*1031c584SApple OSS Distributions AbsoluteTime now;
6509*1031c584SApple OSS Distributions #endif
6510*1031c584SApple OSS Distributions
6511*1031c584SApple OSS Distributions if (!OSDynamicCast(_IOServiceInterestNotifier, object)) {
6512*1031c584SApple OSS Distributions return;
6513*1031c584SApple OSS Distributions }
6514*1031c584SApple OSS Distributions
6515*1031c584SApple OSS Distributions memset(&msgArg, 0, sizeof(msgArg));
6516*1031c584SApple OSS Distributions if (context->messageFilter &&
6517*1031c584SApple OSS Distributions !context->messageFilter(context->us, object, context, &msgArg, &waitForReply)) {
6518*1031c584SApple OSS Distributions return;
6519*1031c584SApple OSS Distributions }
6520*1031c584SApple OSS Distributions
6521*1031c584SApple OSS Distributions if (context->us == getPMRootDomain() &&
6522*1031c584SApple OSS Distributions getPMRootDomain()->isAOTMode()
6523*1031c584SApple OSS Distributions ) {
6524*1031c584SApple OSS Distributions OSNumber *clientID = NULL;
6525*1031c584SApple OSS Distributions boolean_t proc_suspended = FALSE;
6526*1031c584SApple OSS Distributions proc_t proc = NULL;
6527*1031c584SApple OSS Distributions if ((clientID = copyClientIDForNotification(object, context))) {
6528*1031c584SApple OSS Distributions uint32_t clientPID = clientID->unsigned32BitValue();
6529*1031c584SApple OSS Distributions clientID->release();
6530*1031c584SApple OSS Distributions proc = proc_find(clientPID);
6531*1031c584SApple OSS Distributions if (proc) {
6532*1031c584SApple OSS Distributions proc_suspended = get_task_pidsuspended((task_t) proc_task(proc));
6533*1031c584SApple OSS Distributions if (proc_suspended) {
6534*1031c584SApple OSS Distributions logClientIDForNotification(object, context, "PMTellCapablityAppWithResponse - Suspended");
6535*1031c584SApple OSS Distributions } else if (get_task_suspended((task_t) proc_task(proc))) {
6536*1031c584SApple OSS Distributions proc_suspended = true;
6537*1031c584SApple OSS Distributions context->skippedInDark++;
6538*1031c584SApple OSS Distributions }
6539*1031c584SApple OSS Distributions proc_rele(proc);
6540*1031c584SApple OSS Distributions if (proc_suspended) {
6541*1031c584SApple OSS Distributions return;
6542*1031c584SApple OSS Distributions }
6543*1031c584SApple OSS Distributions }
6544*1031c584SApple OSS Distributions }
6545*1031c584SApple OSS Distributions }
6546*1031c584SApple OSS Distributions context->notSkippedInDark++;
6547*1031c584SApple OSS Distributions
6548*1031c584SApple OSS Distributions // Create client array (for tracking purposes) only if the service
6549*1031c584SApple OSS Distributions // has app clients. Usually only root domain does.
6550*1031c584SApple OSS Distributions if (NULL == context->notifyClients) {
6551*1031c584SApple OSS Distributions context->notifyClients = OSArray::withCapacity(32);
6552*1031c584SApple OSS Distributions assert(context->notifyClients != NULL);
6553*1031c584SApple OSS Distributions }
6554*1031c584SApple OSS Distributions
6555*1031c584SApple OSS Distributions msgType = context->messageType;
6556*1031c584SApple OSS Distributions msgIndex = context->responseArray->getCount();
6557*1031c584SApple OSS Distributions msgRef = ((context->serialNumber & 0xFFFF) << 16) + (msgIndex & 0xFFFF);
6558*1031c584SApple OSS Distributions
6559*1031c584SApple OSS Distributions OUR_PMLog(kPMLogAppNotify, msgType, msgRef);
6560*1031c584SApple OSS Distributions if (kIOLogDebugPower & gIOKitDebug) {
6561*1031c584SApple OSS Distributions // Log client pid/name and client array index.
6562*1031c584SApple OSS Distributions OSNumber * clientID = NULL;
6563*1031c584SApple OSS Distributions OSString * clientIDString = NULL;
6564*1031c584SApple OSS Distributions context->us->messageClient(kIOMessageCopyClientID, object, &clientID);
6565*1031c584SApple OSS Distributions if (clientID) {
6566*1031c584SApple OSS Distributions clientIDString = IOCopyLogNameForPID(clientID->unsigned32BitValue());
6567*1031c584SApple OSS Distributions }
6568*1031c584SApple OSS Distributions
6569*1031c584SApple OSS Distributions PM_LOG("%s MESG App(%u) %s, wait %u, %s\n",
6570*1031c584SApple OSS Distributions context->us->getName(),
6571*1031c584SApple OSS Distributions msgIndex, getIOMessageString(msgType),
6572*1031c584SApple OSS Distributions (waitForReply == kOSBooleanTrue),
6573*1031c584SApple OSS Distributions clientIDString ? clientIDString->getCStringNoCopy() : "");
6574*1031c584SApple OSS Distributions if (clientID) {
6575*1031c584SApple OSS Distributions clientID->release();
6576*1031c584SApple OSS Distributions }
6577*1031c584SApple OSS Distributions if (clientIDString) {
6578*1031c584SApple OSS Distributions clientIDString->release();
6579*1031c584SApple OSS Distributions }
6580*1031c584SApple OSS Distributions }
6581*1031c584SApple OSS Distributions
6582*1031c584SApple OSS Distributions msgArg.notifyRef = msgRef;
6583*1031c584SApple OSS Distributions msgArg.maxWaitForReply = 0;
6584*1031c584SApple OSS Distributions
6585*1031c584SApple OSS Distributions if (waitForReply == kOSBooleanFalse) {
6586*1031c584SApple OSS Distributions msgArg.notifyRef = 0;
6587*1031c584SApple OSS Distributions context->responseArray->setObject(msgIndex, kOSBooleanTrue);
6588*1031c584SApple OSS Distributions if (context->notifyClients) {
6589*1031c584SApple OSS Distributions context->notifyClients->setObject(msgIndex, kOSBooleanTrue);
6590*1031c584SApple OSS Distributions }
6591*1031c584SApple OSS Distributions } else {
6592*1031c584SApple OSS Distributions OSNumber * num;
6593*1031c584SApple OSS Distributions clock_get_uptime(&now);
6594*1031c584SApple OSS Distributions num = OSNumber::withNumber(AbsoluteTime_to_scalar(&now), sizeof(uint64_t) * 8);
6595*1031c584SApple OSS Distributions if (num) {
6596*1031c584SApple OSS Distributions context->responseArray->setObject(msgIndex, num);
6597*1031c584SApple OSS Distributions num->release();
6598*1031c584SApple OSS Distributions } else {
6599*1031c584SApple OSS Distributions context->responseArray->setObject(msgIndex, kOSBooleanFalse);
6600*1031c584SApple OSS Distributions }
6601*1031c584SApple OSS Distributions
6602*1031c584SApple OSS Distributions if (context->notifyClients) {
6603*1031c584SApple OSS Distributions context->notifyClients->setObject(msgIndex, object);
6604*1031c584SApple OSS Distributions }
6605*1031c584SApple OSS Distributions }
6606*1031c584SApple OSS Distributions
6607*1031c584SApple OSS Distributions context->us->messageClient(msgType, object, (void *) &msgArg, sizeof(msgArg));
6608*1031c584SApple OSS Distributions }
6609*1031c584SApple OSS Distributions
6610*1031c584SApple OSS Distributions //*********************************************************************************
6611*1031c584SApple OSS Distributions // [static private] pmTellCapabilityClientWithResponse
6612*1031c584SApple OSS Distributions //*********************************************************************************
6613*1031c584SApple OSS Distributions
6614*1031c584SApple OSS Distributions void
pmTellCapabilityClientWithResponse(OSObject * object,void * arg)6615*1031c584SApple OSS Distributions IOService::pmTellCapabilityClientWithResponse(
6616*1031c584SApple OSS Distributions OSObject * object, void * arg )
6617*1031c584SApple OSS Distributions {
6618*1031c584SApple OSS Distributions IOPMSystemCapabilityChangeParameters msgArg;
6619*1031c584SApple OSS Distributions IOPMInterestContext * context = (IOPMInterestContext *) arg;
6620*1031c584SApple OSS Distributions OSObject * replied = kOSBooleanTrue;
6621*1031c584SApple OSS Distributions _IOServiceInterestNotifier * notifier;
6622*1031c584SApple OSS Distributions uint32_t msgIndex, msgRef, msgType;
6623*1031c584SApple OSS Distributions IOReturn retCode;
6624*1031c584SApple OSS Distributions AbsoluteTime start, end;
6625*1031c584SApple OSS Distributions uint64_t nsec;
6626*1031c584SApple OSS Distributions bool enableTracing;
6627*1031c584SApple OSS Distributions
6628*1031c584SApple OSS Distributions memset(&msgArg, 0, sizeof(msgArg));
6629*1031c584SApple OSS Distributions if (context->messageFilter &&
6630*1031c584SApple OSS Distributions !context->messageFilter(context->us, object, context, &msgArg, NULL)) {
6631*1031c584SApple OSS Distributions getPMRootDomain()->traceFilteredNotification(object);
6632*1031c584SApple OSS Distributions return;
6633*1031c584SApple OSS Distributions }
6634*1031c584SApple OSS Distributions
6635*1031c584SApple OSS Distributions if (NULL == context->notifyClients) {
6636*1031c584SApple OSS Distributions context->notifyClients = OSArray::withCapacity(32);
6637*1031c584SApple OSS Distributions assert(context->notifyClients != NULL);
6638*1031c584SApple OSS Distributions }
6639*1031c584SApple OSS Distributions
6640*1031c584SApple OSS Distributions notifier = OSDynamicCast(_IOServiceInterestNotifier, object);
6641*1031c584SApple OSS Distributions msgType = context->messageType;
6642*1031c584SApple OSS Distributions msgIndex = context->responseArray->getCount();
6643*1031c584SApple OSS Distributions msgRef = ((context->serialNumber & 0xFFFF) << 16) + (msgIndex & 0xFFFF);
6644*1031c584SApple OSS Distributions enableTracing = context->enableTracing && (notifier != NULL);
6645*1031c584SApple OSS Distributions
6646*1031c584SApple OSS Distributions IOServicePM * pwrMgt = context->us->pwrMgt;
6647*1031c584SApple OSS Distributions if (gIOKitDebug & kIOLogPower) {
6648*1031c584SApple OSS Distributions OUR_PMLog(kPMLogClientNotify, msgRef, msgType);
6649*1031c584SApple OSS Distributions if (OSDynamicCast(IOService, object)) {
6650*1031c584SApple OSS Distributions const char *who = ((IOService *) object)->getName();
6651*1031c584SApple OSS Distributions gPlatform->PMLog(who, kPMLogClientNotify, (uintptr_t) object, 0);
6652*1031c584SApple OSS Distributions } else if (notifier) {
6653*1031c584SApple OSS Distributions OUR_PMLog(kPMLogClientNotify, (uintptr_t) notifier->handler, 0);
6654*1031c584SApple OSS Distributions }
6655*1031c584SApple OSS Distributions }
6656*1031c584SApple OSS Distributions
6657*1031c584SApple OSS Distributions msgArg.notifyRef = msgRef;
6658*1031c584SApple OSS Distributions msgArg.maxWaitForReply = 0;
6659*1031c584SApple OSS Distributions
6660*1031c584SApple OSS Distributions clock_get_uptime(&start);
6661*1031c584SApple OSS Distributions if (enableTracing) {
6662*1031c584SApple OSS Distributions getPMRootDomain()->traceNotification(notifier, true, start, msgIndex);
6663*1031c584SApple OSS Distributions }
6664*1031c584SApple OSS Distributions
6665*1031c584SApple OSS Distributions retCode = context->us->messageClient(msgType, object, (void *) &msgArg, sizeof(msgArg));
6666*1031c584SApple OSS Distributions
6667*1031c584SApple OSS Distributions clock_get_uptime(&end);
6668*1031c584SApple OSS Distributions if (enableTracing) {
6669*1031c584SApple OSS Distributions getPMRootDomain()->traceNotification(notifier, false, end, msgIndex);
6670*1031c584SApple OSS Distributions }
6671*1031c584SApple OSS Distributions
6672*1031c584SApple OSS Distributions if (kIOReturnSuccess == retCode) {
6673*1031c584SApple OSS Distributions if (0 == msgArg.maxWaitForReply) {
6674*1031c584SApple OSS Distributions // client doesn't want time to respond
6675*1031c584SApple OSS Distributions OUR_PMLog(kPMLogClientAcknowledge, msgRef, (uintptr_t) object);
6676*1031c584SApple OSS Distributions context->responseArray->setObject(msgIndex, replied);
6677*1031c584SApple OSS Distributions } else {
6678*1031c584SApple OSS Distributions replied = kOSBooleanFalse;
6679*1031c584SApple OSS Distributions if (msgArg.maxWaitForReply > context->maxTimeRequested) {
6680*1031c584SApple OSS Distributions if (msgArg.maxWaitForReply > kCapabilityClientMaxWait) {
6681*1031c584SApple OSS Distributions context->maxTimeRequested = kCapabilityClientMaxWait;
6682*1031c584SApple OSS Distributions PM_ERROR("%s: client %p returned %u for %s\n",
6683*1031c584SApple OSS Distributions context->us->getName(),
6684*1031c584SApple OSS Distributions notifier ? (void *) OBFUSCATE(notifier->handler) : OBFUSCATE(object),
6685*1031c584SApple OSS Distributions msgArg.maxWaitForReply,
6686*1031c584SApple OSS Distributions getIOMessageString(msgType));
6687*1031c584SApple OSS Distributions } else {
6688*1031c584SApple OSS Distributions context->maxTimeRequested = msgArg.maxWaitForReply;
6689*1031c584SApple OSS Distributions }
6690*1031c584SApple OSS Distributions }
6691*1031c584SApple OSS Distributions
6692*1031c584SApple OSS Distributions // Track time taken to ack, by storing the timestamp of
6693*1031c584SApple OSS Distributions // callback completion
6694*1031c584SApple OSS Distributions OSNumber * num;
6695*1031c584SApple OSS Distributions num = OSNumber::withNumber(AbsoluteTime_to_scalar(&end), sizeof(uint64_t) * 8);
6696*1031c584SApple OSS Distributions if (num) {
6697*1031c584SApple OSS Distributions context->responseArray->setObject(msgIndex, num);
6698*1031c584SApple OSS Distributions num->release();
6699*1031c584SApple OSS Distributions } else {
6700*1031c584SApple OSS Distributions context->responseArray->setObject(msgIndex, replied);
6701*1031c584SApple OSS Distributions }
6702*1031c584SApple OSS Distributions }
6703*1031c584SApple OSS Distributions
6704*1031c584SApple OSS Distributions if (enableTracing) {
6705*1031c584SApple OSS Distributions SUB_ABSOLUTETIME(&end, &start);
6706*1031c584SApple OSS Distributions absolutetime_to_nanoseconds(end, &nsec);
6707*1031c584SApple OSS Distributions
6708*1031c584SApple OSS Distributions if ((nsec > LOG_KEXT_RESPONSE_TIMES) || (msgArg.maxWaitForReply != 0)) {
6709*1031c584SApple OSS Distributions getPMRootDomain()->traceNotificationResponse(notifier, NS_TO_MS(nsec), msgArg.maxWaitForReply);
6710*1031c584SApple OSS Distributions }
6711*1031c584SApple OSS Distributions }
6712*1031c584SApple OSS Distributions } else {
6713*1031c584SApple OSS Distributions // not a client of ours
6714*1031c584SApple OSS Distributions // so we won't be waiting for response
6715*1031c584SApple OSS Distributions OUR_PMLog(kPMLogClientAcknowledge, msgRef, 0);
6716*1031c584SApple OSS Distributions context->responseArray->setObject(msgIndex, replied);
6717*1031c584SApple OSS Distributions }
6718*1031c584SApple OSS Distributions if (context->notifyClients) {
6719*1031c584SApple OSS Distributions context->notifyClients->setObject(msgIndex, object);
6720*1031c584SApple OSS Distributions }
6721*1031c584SApple OSS Distributions }
6722*1031c584SApple OSS Distributions
6723*1031c584SApple OSS Distributions //*********************************************************************************
6724*1031c584SApple OSS Distributions // [public] tellNoChangeDown
6725*1031c584SApple OSS Distributions //
6726*1031c584SApple OSS Distributions // Notify registered applications and kernel clients that we are not
6727*1031c584SApple OSS Distributions // dropping power.
6728*1031c584SApple OSS Distributions //
6729*1031c584SApple OSS Distributions // Subclass can override this to send a different message type. Parameter is
6730*1031c584SApple OSS Distributions // the aborted destination state number.
6731*1031c584SApple OSS Distributions //*********************************************************************************
6732*1031c584SApple OSS Distributions
6733*1031c584SApple OSS Distributions void
tellNoChangeDown(unsigned long)6734*1031c584SApple OSS Distributions IOService::tellNoChangeDown( unsigned long )
6735*1031c584SApple OSS Distributions {
6736*1031c584SApple OSS Distributions return tellClients( kIOMessageDeviceWillNotPowerOff );
6737*1031c584SApple OSS Distributions }
6738*1031c584SApple OSS Distributions
6739*1031c584SApple OSS Distributions //*********************************************************************************
6740*1031c584SApple OSS Distributions // [public] tellChangeUp
6741*1031c584SApple OSS Distributions //
6742*1031c584SApple OSS Distributions // Notify registered applications and kernel clients that we are raising power.
6743*1031c584SApple OSS Distributions //
6744*1031c584SApple OSS Distributions // Subclass can override this to send a different message type. Parameter is
6745*1031c584SApple OSS Distributions // the aborted destination state number.
6746*1031c584SApple OSS Distributions //*********************************************************************************
6747*1031c584SApple OSS Distributions
6748*1031c584SApple OSS Distributions void
tellChangeUp(unsigned long)6749*1031c584SApple OSS Distributions IOService::tellChangeUp( unsigned long )
6750*1031c584SApple OSS Distributions {
6751*1031c584SApple OSS Distributions return tellClients( kIOMessageDeviceHasPoweredOn );
6752*1031c584SApple OSS Distributions }
6753*1031c584SApple OSS Distributions
6754*1031c584SApple OSS Distributions //*********************************************************************************
6755*1031c584SApple OSS Distributions // [protected] tellClients
6756*1031c584SApple OSS Distributions //
6757*1031c584SApple OSS Distributions // Notify registered applications and kernel clients of something.
6758*1031c584SApple OSS Distributions //*********************************************************************************
6759*1031c584SApple OSS Distributions
6760*1031c584SApple OSS Distributions void
tellClients(int messageType)6761*1031c584SApple OSS Distributions IOService::tellClients( int messageType )
6762*1031c584SApple OSS Distributions {
6763*1031c584SApple OSS Distributions IOPMInterestContext context;
6764*1031c584SApple OSS Distributions
6765*1031c584SApple OSS Distributions RD_LOG("tellClients( %s )\n", getIOMessageString(messageType));
6766*1031c584SApple OSS Distributions
6767*1031c584SApple OSS Distributions memset(&context, 0, sizeof(context));
6768*1031c584SApple OSS Distributions context.messageType = messageType;
6769*1031c584SApple OSS Distributions context.isPreChange = fIsPreChange;
6770*1031c584SApple OSS Distributions context.us = this;
6771*1031c584SApple OSS Distributions context.stateNumber = fHeadNotePowerState;
6772*1031c584SApple OSS Distributions context.stateFlags = fHeadNotePowerArrayEntry->capabilityFlags;
6773*1031c584SApple OSS Distributions context.changeFlags = fHeadNoteChangeFlags;
6774*1031c584SApple OSS Distributions context.enableTracing = IS_ROOT_DOMAIN;
6775*1031c584SApple OSS Distributions context.messageFilter = (IS_ROOT_DOMAIN) ?
6776*1031c584SApple OSS Distributions OSMemberFunctionCast(
6777*1031c584SApple OSS Distributions IOPMMessageFilter,
6778*1031c584SApple OSS Distributions (IOPMrootDomain *)this,
6779*1031c584SApple OSS Distributions &IOPMrootDomain::systemMessageFilter) : NULL;
6780*1031c584SApple OSS Distributions
6781*1031c584SApple OSS Distributions context.notifyType = kNotifyPriority;
6782*1031c584SApple OSS Distributions applyToInterested( gIOPriorityPowerStateInterest,
6783*1031c584SApple OSS Distributions tellKernelClientApplier, (void *) &context );
6784*1031c584SApple OSS Distributions
6785*1031c584SApple OSS Distributions context.notifyType = kNotifyApps;
6786*1031c584SApple OSS Distributions applyToInterested( gIOAppPowerStateInterest,
6787*1031c584SApple OSS Distributions tellAppClientApplier, (void *) &context );
6788*1031c584SApple OSS Distributions
6789*1031c584SApple OSS Distributions applyToInterested( gIOGeneralInterest,
6790*1031c584SApple OSS Distributions tellKernelClientApplier, (void *) &context );
6791*1031c584SApple OSS Distributions }
6792*1031c584SApple OSS Distributions
6793*1031c584SApple OSS Distributions //*********************************************************************************
6794*1031c584SApple OSS Distributions // [private] tellKernelClientApplier
6795*1031c584SApple OSS Distributions //
6796*1031c584SApple OSS Distributions // Message a kernel client.
6797*1031c584SApple OSS Distributions //*********************************************************************************
6798*1031c584SApple OSS Distributions
6799*1031c584SApple OSS Distributions static void
tellKernelClientApplier(OSObject * object,void * arg)6800*1031c584SApple OSS Distributions tellKernelClientApplier( OSObject * object, void * arg )
6801*1031c584SApple OSS Distributions {
6802*1031c584SApple OSS Distributions IOPowerStateChangeNotification notify;
6803*1031c584SApple OSS Distributions IOPMInterestContext * context = (IOPMInterestContext *) arg;
6804*1031c584SApple OSS Distributions bool enableTracing = context->enableTracing;
6805*1031c584SApple OSS Distributions
6806*1031c584SApple OSS Distributions if (context->messageFilter &&
6807*1031c584SApple OSS Distributions !context->messageFilter(context->us, object, context, NULL, NULL)) {
6808*1031c584SApple OSS Distributions IOService::getPMRootDomain()->traceFilteredNotification(object);
6809*1031c584SApple OSS Distributions return;
6810*1031c584SApple OSS Distributions }
6811*1031c584SApple OSS Distributions
6812*1031c584SApple OSS Distributions notify.powerRef = (void *) NULL;
6813*1031c584SApple OSS Distributions notify.returnValue = 0;
6814*1031c584SApple OSS Distributions notify.stateNumber = context->stateNumber;
6815*1031c584SApple OSS Distributions notify.stateFlags = context->stateFlags;
6816*1031c584SApple OSS Distributions
6817*1031c584SApple OSS Distributions if (enableTracing) {
6818*1031c584SApple OSS Distributions IOService::getPMRootDomain()->traceNotification(object, true);
6819*1031c584SApple OSS Distributions }
6820*1031c584SApple OSS Distributions
6821*1031c584SApple OSS Distributions context->us->messageClient(context->messageType, object, ¬ify, sizeof(notify));
6822*1031c584SApple OSS Distributions
6823*1031c584SApple OSS Distributions if (enableTracing) {
6824*1031c584SApple OSS Distributions IOService::getPMRootDomain()->traceNotification(object, false);
6825*1031c584SApple OSS Distributions }
6826*1031c584SApple OSS Distributions }
6827*1031c584SApple OSS Distributions
6828*1031c584SApple OSS Distributions static OSNumber *
copyClientIDForNotification(OSObject * object,IOPMInterestContext * context)6829*1031c584SApple OSS Distributions copyClientIDForNotification(
6830*1031c584SApple OSS Distributions OSObject *object,
6831*1031c584SApple OSS Distributions IOPMInterestContext *context)
6832*1031c584SApple OSS Distributions {
6833*1031c584SApple OSS Distributions OSNumber *clientID = NULL;
6834*1031c584SApple OSS Distributions context->us->messageClient(kIOMessageCopyClientID, object, &clientID);
6835*1031c584SApple OSS Distributions return clientID;
6836*1031c584SApple OSS Distributions }
6837*1031c584SApple OSS Distributions
6838*1031c584SApple OSS Distributions static void
logClientIDForNotification(OSObject * object,IOPMInterestContext * context,const char * logString)6839*1031c584SApple OSS Distributions logClientIDForNotification(
6840*1031c584SApple OSS Distributions OSObject *object,
6841*1031c584SApple OSS Distributions IOPMInterestContext *context,
6842*1031c584SApple OSS Distributions const char *logString)
6843*1031c584SApple OSS Distributions {
6844*1031c584SApple OSS Distributions OSString *logClientID = NULL;
6845*1031c584SApple OSS Distributions OSNumber *clientID = copyClientIDForNotification(object, context);
6846*1031c584SApple OSS Distributions
6847*1031c584SApple OSS Distributions if (logString) {
6848*1031c584SApple OSS Distributions if (clientID) {
6849*1031c584SApple OSS Distributions logClientID = IOCopyLogNameForPID(clientID->unsigned32BitValue());
6850*1031c584SApple OSS Distributions }
6851*1031c584SApple OSS Distributions
6852*1031c584SApple OSS Distributions PM_LOG("%s %s %s, %s\n",
6853*1031c584SApple OSS Distributions context->us->getName(), logString,
6854*1031c584SApple OSS Distributions IOService::getIOMessageString(context->messageType),
6855*1031c584SApple OSS Distributions logClientID ? logClientID->getCStringNoCopy() : "");
6856*1031c584SApple OSS Distributions
6857*1031c584SApple OSS Distributions if (logClientID) {
6858*1031c584SApple OSS Distributions logClientID->release();
6859*1031c584SApple OSS Distributions }
6860*1031c584SApple OSS Distributions }
6861*1031c584SApple OSS Distributions
6862*1031c584SApple OSS Distributions if (clientID) {
6863*1031c584SApple OSS Distributions clientID->release();
6864*1031c584SApple OSS Distributions }
6865*1031c584SApple OSS Distributions
6866*1031c584SApple OSS Distributions return;
6867*1031c584SApple OSS Distributions }
6868*1031c584SApple OSS Distributions
6869*1031c584SApple OSS Distributions static void
tellAppClientApplier(OSObject * object,void * arg)6870*1031c584SApple OSS Distributions tellAppClientApplier( OSObject * object, void * arg )
6871*1031c584SApple OSS Distributions {
6872*1031c584SApple OSS Distributions IOPMInterestContext * context = (IOPMInterestContext *) arg;
6873*1031c584SApple OSS Distributions OSNumber * clientID = NULL;
6874*1031c584SApple OSS Distributions proc_t proc = NULL;
6875*1031c584SApple OSS Distributions boolean_t proc_suspended = FALSE;
6876*1031c584SApple OSS Distributions
6877*1031c584SApple OSS Distributions if (context->us == IOService::getPMRootDomain()) {
6878*1031c584SApple OSS Distributions if ((clientID = copyClientIDForNotification(object, context))) {
6879*1031c584SApple OSS Distributions uint32_t clientPID = clientID->unsigned32BitValue();
6880*1031c584SApple OSS Distributions clientID->release();
6881*1031c584SApple OSS Distributions proc = proc_find(clientPID);
6882*1031c584SApple OSS Distributions
6883*1031c584SApple OSS Distributions if (proc) {
6884*1031c584SApple OSS Distributions proc_suspended = get_task_pidsuspended((task_t) proc_task(proc));
6885*1031c584SApple OSS Distributions if (proc_suspended) {
6886*1031c584SApple OSS Distributions logClientIDForNotification(object, context, "tellAppClientApplier - Suspended");
6887*1031c584SApple OSS Distributions } else if (IOService::getPMRootDomain()->isAOTMode() && get_task_suspended((task_t) proc_task(proc))) {
6888*1031c584SApple OSS Distributions proc_suspended = true;
6889*1031c584SApple OSS Distributions context->skippedInDark++;
6890*1031c584SApple OSS Distributions }
6891*1031c584SApple OSS Distributions proc_rele(proc);
6892*1031c584SApple OSS Distributions if (proc_suspended) {
6893*1031c584SApple OSS Distributions return;
6894*1031c584SApple OSS Distributions }
6895*1031c584SApple OSS Distributions }
6896*1031c584SApple OSS Distributions }
6897*1031c584SApple OSS Distributions }
6898*1031c584SApple OSS Distributions
6899*1031c584SApple OSS Distributions if (context->messageFilter &&
6900*1031c584SApple OSS Distributions !context->messageFilter(context->us, object, context, NULL, NULL)) {
6901*1031c584SApple OSS Distributions if (kIOLogDebugPower & gIOKitDebug) {
6902*1031c584SApple OSS Distributions logClientIDForNotification(object, context, "DROP App");
6903*1031c584SApple OSS Distributions }
6904*1031c584SApple OSS Distributions return;
6905*1031c584SApple OSS Distributions }
6906*1031c584SApple OSS Distributions context->notSkippedInDark++;
6907*1031c584SApple OSS Distributions
6908*1031c584SApple OSS Distributions if (kIOLogDebugPower & gIOKitDebug) {
6909*1031c584SApple OSS Distributions logClientIDForNotification(object, context, "MESG App");
6910*1031c584SApple OSS Distributions }
6911*1031c584SApple OSS Distributions
6912*1031c584SApple OSS Distributions context->us->messageClient(context->messageType, object, NULL);
6913*1031c584SApple OSS Distributions }
6914*1031c584SApple OSS Distributions
6915*1031c584SApple OSS Distributions //*********************************************************************************
6916*1031c584SApple OSS Distributions // [private] checkForDone
6917*1031c584SApple OSS Distributions //*********************************************************************************
6918*1031c584SApple OSS Distributions
6919*1031c584SApple OSS Distributions bool
checkForDone(void)6920*1031c584SApple OSS Distributions IOService::checkForDone( void )
6921*1031c584SApple OSS Distributions {
6922*1031c584SApple OSS Distributions int i = 0;
6923*1031c584SApple OSS Distributions OSObject * theFlag;
6924*1031c584SApple OSS Distributions
6925*1031c584SApple OSS Distributions if (fResponseArray == NULL) {
6926*1031c584SApple OSS Distributions return true;
6927*1031c584SApple OSS Distributions }
6928*1031c584SApple OSS Distributions
6929*1031c584SApple OSS Distributions for (i = 0;; i++) {
6930*1031c584SApple OSS Distributions theFlag = fResponseArray->getObject(i);
6931*1031c584SApple OSS Distributions
6932*1031c584SApple OSS Distributions if (NULL == theFlag) {
6933*1031c584SApple OSS Distributions break;
6934*1031c584SApple OSS Distributions }
6935*1031c584SApple OSS Distributions
6936*1031c584SApple OSS Distributions if (kOSBooleanTrue != theFlag) {
6937*1031c584SApple OSS Distributions return false;
6938*1031c584SApple OSS Distributions }
6939*1031c584SApple OSS Distributions }
6940*1031c584SApple OSS Distributions return true;
6941*1031c584SApple OSS Distributions }
6942*1031c584SApple OSS Distributions
6943*1031c584SApple OSS Distributions //*********************************************************************************
6944*1031c584SApple OSS Distributions // [public] responseValid
6945*1031c584SApple OSS Distributions //*********************************************************************************
6946*1031c584SApple OSS Distributions
6947*1031c584SApple OSS Distributions bool
responseValid(uint32_t refcon,int pid)6948*1031c584SApple OSS Distributions IOService::responseValid( uint32_t refcon, int pid )
6949*1031c584SApple OSS Distributions {
6950*1031c584SApple OSS Distributions UInt16 serialComponent;
6951*1031c584SApple OSS Distributions UInt16 ordinalComponent;
6952*1031c584SApple OSS Distributions OSObject * theFlag;
6953*1031c584SApple OSS Distributions OSObject *object = NULL;
6954*1031c584SApple OSS Distributions
6955*1031c584SApple OSS Distributions serialComponent = (refcon >> 16) & 0xFFFF;
6956*1031c584SApple OSS Distributions ordinalComponent = (refcon & 0xFFFF);
6957*1031c584SApple OSS Distributions
6958*1031c584SApple OSS Distributions if (serialComponent != fSerialNumber) {
6959*1031c584SApple OSS Distributions return false;
6960*1031c584SApple OSS Distributions }
6961*1031c584SApple OSS Distributions
6962*1031c584SApple OSS Distributions if (fResponseArray == NULL) {
6963*1031c584SApple OSS Distributions return false;
6964*1031c584SApple OSS Distributions }
6965*1031c584SApple OSS Distributions
6966*1031c584SApple OSS Distributions theFlag = fResponseArray->getObject(ordinalComponent);
6967*1031c584SApple OSS Distributions
6968*1031c584SApple OSS Distributions if (theFlag == NULL) {
6969*1031c584SApple OSS Distributions return false;
6970*1031c584SApple OSS Distributions }
6971*1031c584SApple OSS Distributions
6972*1031c584SApple OSS Distributions if (fNotifyClientArray) {
6973*1031c584SApple OSS Distributions object = fNotifyClientArray->getObject(ordinalComponent);
6974*1031c584SApple OSS Distributions }
6975*1031c584SApple OSS Distributions
6976*1031c584SApple OSS Distributions OSNumber * num;
6977*1031c584SApple OSS Distributions if ((num = OSDynamicCast(OSNumber, theFlag))) {
6978*1031c584SApple OSS Distributions AbsoluteTime now;
6979*1031c584SApple OSS Distributions AbsoluteTime start;
6980*1031c584SApple OSS Distributions uint64_t nsec;
6981*1031c584SApple OSS Distributions char name[128];
6982*1031c584SApple OSS Distributions
6983*1031c584SApple OSS Distributions clock_get_uptime(&now);
6984*1031c584SApple OSS Distributions AbsoluteTime_to_scalar(&start) = num->unsigned64BitValue();
6985*1031c584SApple OSS Distributions SUB_ABSOLUTETIME(&now, &start);
6986*1031c584SApple OSS Distributions absolutetime_to_nanoseconds(now, &nsec);
6987*1031c584SApple OSS Distributions
6988*1031c584SApple OSS Distributions if (pid != 0) {
6989*1031c584SApple OSS Distributions name[0] = '\0';
6990*1031c584SApple OSS Distributions proc_name(pid, name, sizeof(name));
6991*1031c584SApple OSS Distributions
6992*1031c584SApple OSS Distributions if (nsec > LOG_APP_RESPONSE_TIMES) {
6993*1031c584SApple OSS Distributions IOLog("PM response took %d ms (%d, %s)\n", NS_TO_MS(nsec),
6994*1031c584SApple OSS Distributions pid, name);
6995*1031c584SApple OSS Distributions }
6996*1031c584SApple OSS Distributions
6997*1031c584SApple OSS Distributions if (nsec > LOG_APP_RESPONSE_MSG_TRACER) {
6998*1031c584SApple OSS Distributions // TODO: populate the messageType argument
6999*1031c584SApple OSS Distributions getPMRootDomain()->pmStatsRecordApplicationResponse(
7000*1031c584SApple OSS Distributions gIOPMStatsResponseSlow,
7001*1031c584SApple OSS Distributions name, 0, NS_TO_MS(nsec), pid, object);
7002*1031c584SApple OSS Distributions } else {
7003*1031c584SApple OSS Distributions getPMRootDomain()->pmStatsRecordApplicationResponse(
7004*1031c584SApple OSS Distributions gIOPMStatsResponsePrompt,
7005*1031c584SApple OSS Distributions name, 0, NS_TO_MS(nsec), pid, object);
7006*1031c584SApple OSS Distributions }
7007*1031c584SApple OSS Distributions } else {
7008*1031c584SApple OSS Distributions getPMRootDomain()->traceNotificationAck(object, NS_TO_MS(nsec));
7009*1031c584SApple OSS Distributions }
7010*1031c584SApple OSS Distributions
7011*1031c584SApple OSS Distributions if (kIOLogDebugPower & gIOKitDebug) {
7012*1031c584SApple OSS Distributions PM_LOG("Ack(%u) %u ms\n",
7013*1031c584SApple OSS Distributions (uint32_t) ordinalComponent,
7014*1031c584SApple OSS Distributions NS_TO_MS(nsec));
7015*1031c584SApple OSS Distributions }
7016*1031c584SApple OSS Distributions theFlag = kOSBooleanFalse;
7017*1031c584SApple OSS Distributions } else if (object) {
7018*1031c584SApple OSS Distributions getPMRootDomain()->pmStatsRecordApplicationResponse(
7019*1031c584SApple OSS Distributions gIOPMStatsResponsePrompt,
7020*1031c584SApple OSS Distributions NULL, 0, 0, pid, object);
7021*1031c584SApple OSS Distributions }
7022*1031c584SApple OSS Distributions
7023*1031c584SApple OSS Distributions if (kOSBooleanFalse == theFlag) {
7024*1031c584SApple OSS Distributions fResponseArray->replaceObject(ordinalComponent, kOSBooleanTrue);
7025*1031c584SApple OSS Distributions }
7026*1031c584SApple OSS Distributions
7027*1031c584SApple OSS Distributions return true;
7028*1031c584SApple OSS Distributions }
7029*1031c584SApple OSS Distributions
7030*1031c584SApple OSS Distributions //*********************************************************************************
7031*1031c584SApple OSS Distributions // [public] allowPowerChange
7032*1031c584SApple OSS Distributions //
7033*1031c584SApple OSS Distributions // Our power state is about to lower, and we have notified applications
7034*1031c584SApple OSS Distributions // and kernel clients, and one of them has acknowledged. If this is the last to do
7035*1031c584SApple OSS Distributions // so, and all acknowledgements are positive, we continue with the power change.
7036*1031c584SApple OSS Distributions //*********************************************************************************
7037*1031c584SApple OSS Distributions
7038*1031c584SApple OSS Distributions IOReturn
allowPowerChange(unsigned long refcon)7039*1031c584SApple OSS Distributions IOService::allowPowerChange( unsigned long refcon )
7040*1031c584SApple OSS Distributions {
7041*1031c584SApple OSS Distributions IOPMRequest * request;
7042*1031c584SApple OSS Distributions
7043*1031c584SApple OSS Distributions if (!initialized) {
7044*1031c584SApple OSS Distributions // we're unloading
7045*1031c584SApple OSS Distributions return kIOReturnSuccess;
7046*1031c584SApple OSS Distributions }
7047*1031c584SApple OSS Distributions
7048*1031c584SApple OSS Distributions request = acquirePMRequest( this, kIOPMRequestTypeAllowPowerChange );
7049*1031c584SApple OSS Distributions if (!request) {
7050*1031c584SApple OSS Distributions return kIOReturnNoMemory;
7051*1031c584SApple OSS Distributions }
7052*1031c584SApple OSS Distributions
7053*1031c584SApple OSS Distributions request->fArg0 = (void *) refcon;
7054*1031c584SApple OSS Distributions request->fArg1 = (void *)(uintptr_t) proc_selfpid();
7055*1031c584SApple OSS Distributions request->fArg2 = (void *) NULL;
7056*1031c584SApple OSS Distributions submitPMRequest( request );
7057*1031c584SApple OSS Distributions
7058*1031c584SApple OSS Distributions return kIOReturnSuccess;
7059*1031c584SApple OSS Distributions }
7060*1031c584SApple OSS Distributions
7061*1031c584SApple OSS Distributions #ifndef __LP64__
7062*1031c584SApple OSS Distributions IOReturn
serializedAllowPowerChange2(unsigned long refcon)7063*1031c584SApple OSS Distributions IOService::serializedAllowPowerChange2( unsigned long refcon )
7064*1031c584SApple OSS Distributions {
7065*1031c584SApple OSS Distributions // [deprecated] public
7066*1031c584SApple OSS Distributions return kIOReturnUnsupported;
7067*1031c584SApple OSS Distributions }
7068*1031c584SApple OSS Distributions #endif /* !__LP64__ */
7069*1031c584SApple OSS Distributions
7070*1031c584SApple OSS Distributions //*********************************************************************************
7071*1031c584SApple OSS Distributions // [public] cancelPowerChange
7072*1031c584SApple OSS Distributions //
7073*1031c584SApple OSS Distributions // Our power state is about to lower, and we have notified applications
7074*1031c584SApple OSS Distributions // and kernel clients, and one of them has vetoed the change. If this is the last
7075*1031c584SApple OSS Distributions // client to respond, we abandon the power change.
7076*1031c584SApple OSS Distributions //*********************************************************************************
7077*1031c584SApple OSS Distributions
7078*1031c584SApple OSS Distributions IOReturn
cancelPowerChange(unsigned long refcon)7079*1031c584SApple OSS Distributions IOService::cancelPowerChange( unsigned long refcon )
7080*1031c584SApple OSS Distributions {
7081*1031c584SApple OSS Distributions IOPMRequest * request;
7082*1031c584SApple OSS Distributions char name[128];
7083*1031c584SApple OSS Distributions pid_t pid = proc_selfpid();
7084*1031c584SApple OSS Distributions
7085*1031c584SApple OSS Distributions if (!initialized) {
7086*1031c584SApple OSS Distributions // we're unloading
7087*1031c584SApple OSS Distributions return kIOReturnSuccess;
7088*1031c584SApple OSS Distributions }
7089*1031c584SApple OSS Distributions
7090*1031c584SApple OSS Distributions name[0] = '\0';
7091*1031c584SApple OSS Distributions proc_name(pid, name, sizeof(name));
7092*1031c584SApple OSS Distributions if (pid == 0) {
7093*1031c584SApple OSS Distributions const char *serviceName = this->getName();
7094*1031c584SApple OSS Distributions size_t len = strlen(name);
7095*1031c584SApple OSS Distributions snprintf(name + len, sizeof(name) - len, " (%s)", serviceName ? serviceName : "");
7096*1031c584SApple OSS Distributions }
7097*1031c584SApple OSS Distributions PM_ERROR("PM notification cancel (pid %d, %s)\n", pid, name);
7098*1031c584SApple OSS Distributions
7099*1031c584SApple OSS Distributions request = acquirePMRequest( this, kIOPMRequestTypeCancelPowerChange );
7100*1031c584SApple OSS Distributions if (!request) {
7101*1031c584SApple OSS Distributions return kIOReturnNoMemory;
7102*1031c584SApple OSS Distributions }
7103*1031c584SApple OSS Distributions
7104*1031c584SApple OSS Distributions request->fArg0 = (void *) refcon;
7105*1031c584SApple OSS Distributions request->fArg1 = (void *)(uintptr_t) proc_selfpid();
7106*1031c584SApple OSS Distributions request->fArg2 = (void *) OSString::withCString(name);
7107*1031c584SApple OSS Distributions submitPMRequest( request );
7108*1031c584SApple OSS Distributions
7109*1031c584SApple OSS Distributions return kIOReturnSuccess;
7110*1031c584SApple OSS Distributions }
7111*1031c584SApple OSS Distributions
7112*1031c584SApple OSS Distributions //*********************************************************************************
7113*1031c584SApple OSS Distributions // cancelIdlePowerDown
7114*1031c584SApple OSS Distributions //
7115*1031c584SApple OSS Distributions // Internal method to trigger an idle cancel or revert
7116*1031c584SApple OSS Distributions //*********************************************************************************
7117*1031c584SApple OSS Distributions
7118*1031c584SApple OSS Distributions void
cancelIdlePowerDown(IOService * service)7119*1031c584SApple OSS Distributions IOService::cancelIdlePowerDown( IOService * service )
7120*1031c584SApple OSS Distributions {
7121*1031c584SApple OSS Distributions IOPMRequest * request;
7122*1031c584SApple OSS Distributions
7123*1031c584SApple OSS Distributions request = acquirePMRequest(service, kIOPMRequestTypeIdleCancel);
7124*1031c584SApple OSS Distributions if (request) {
7125*1031c584SApple OSS Distributions submitPMRequest(request);
7126*1031c584SApple OSS Distributions }
7127*1031c584SApple OSS Distributions }
7128*1031c584SApple OSS Distributions
7129*1031c584SApple OSS Distributions #ifndef __LP64__
7130*1031c584SApple OSS Distributions IOReturn
serializedCancelPowerChange2(unsigned long refcon)7131*1031c584SApple OSS Distributions IOService::serializedCancelPowerChange2( unsigned long refcon )
7132*1031c584SApple OSS Distributions {
7133*1031c584SApple OSS Distributions // [deprecated] public
7134*1031c584SApple OSS Distributions return kIOReturnUnsupported;
7135*1031c584SApple OSS Distributions }
7136*1031c584SApple OSS Distributions
7137*1031c584SApple OSS Distributions //*********************************************************************************
7138*1031c584SApple OSS Distributions // PM_Clamp_Timer_Expired
7139*1031c584SApple OSS Distributions //
7140*1031c584SApple OSS Distributions // called when clamp timer expires...set power state to 0.
7141*1031c584SApple OSS Distributions //*********************************************************************************
7142*1031c584SApple OSS Distributions
7143*1031c584SApple OSS Distributions void
PM_Clamp_Timer_Expired(void)7144*1031c584SApple OSS Distributions IOService::PM_Clamp_Timer_Expired( void )
7145*1031c584SApple OSS Distributions {
7146*1031c584SApple OSS Distributions }
7147*1031c584SApple OSS Distributions
7148*1031c584SApple OSS Distributions //*********************************************************************************
7149*1031c584SApple OSS Distributions // clampPowerOn
7150*1031c584SApple OSS Distributions //
7151*1031c584SApple OSS Distributions // Set to highest available power state for a minimum of duration milliseconds
7152*1031c584SApple OSS Distributions //*********************************************************************************
7153*1031c584SApple OSS Distributions
7154*1031c584SApple OSS Distributions void
clampPowerOn(unsigned long duration)7155*1031c584SApple OSS Distributions IOService::clampPowerOn( unsigned long duration )
7156*1031c584SApple OSS Distributions {
7157*1031c584SApple OSS Distributions }
7158*1031c584SApple OSS Distributions #endif /* !__LP64__ */
7159*1031c584SApple OSS Distributions
7160*1031c584SApple OSS Distributions //*********************************************************************************
7161*1031c584SApple OSS Distributions // configurePowerStateReport
7162*1031c584SApple OSS Distributions //
7163*1031c584SApple OSS Distributions // Configures the IOStateReport for kPMPowerStateChannel
7164*1031c584SApple OSS Distributions //*********************************************************************************
7165*1031c584SApple OSS Distributions IOReturn
configurePowerStatesReport(IOReportConfigureAction action,void * result)7166*1031c584SApple OSS Distributions IOService::configurePowerStatesReport( IOReportConfigureAction action, void *result )
7167*1031c584SApple OSS Distributions {
7168*1031c584SApple OSS Distributions IOReturn rc = kIOReturnSuccess;
7169*1031c584SApple OSS Distributions size_t reportSize;
7170*1031c584SApple OSS Distributions unsigned long i;
7171*1031c584SApple OSS Distributions uint64_t ts;
7172*1031c584SApple OSS Distributions
7173*1031c584SApple OSS Distributions if (!pwrMgt) {
7174*1031c584SApple OSS Distributions return kIOReturnUnsupported;
7175*1031c584SApple OSS Distributions }
7176*1031c584SApple OSS Distributions
7177*1031c584SApple OSS Distributions if (!fNumberOfPowerStates) {
7178*1031c584SApple OSS Distributions return kIOReturnSuccess; // For drivers which are in power plane, but haven't called registerPowerDriver()
7179*1031c584SApple OSS Distributions }
7180*1031c584SApple OSS Distributions
7181*1031c584SApple OSS Distributions if (fNumberOfPowerStates > INT16_MAX) {
7182*1031c584SApple OSS Distributions return kIOReturnOverrun;
7183*1031c584SApple OSS Distributions }
7184*1031c584SApple OSS Distributions PM_LOCK();
7185*1031c584SApple OSS Distributions
7186*1031c584SApple OSS Distributions switch (action) {
7187*1031c584SApple OSS Distributions case kIOReportEnable:
7188*1031c584SApple OSS Distributions if (fReportBuf) {
7189*1031c584SApple OSS Distributions fReportClientCnt++;
7190*1031c584SApple OSS Distributions break;
7191*1031c584SApple OSS Distributions }
7192*1031c584SApple OSS Distributions reportSize = STATEREPORT_BUFSIZE(fNumberOfPowerStates);
7193*1031c584SApple OSS Distributions fReportBuf = IOMallocZeroData(reportSize);
7194*1031c584SApple OSS Distributions if (!fReportBuf) {
7195*1031c584SApple OSS Distributions rc = kIOReturnNoMemory;
7196*1031c584SApple OSS Distributions break;
7197*1031c584SApple OSS Distributions }
7198*1031c584SApple OSS Distributions
7199*1031c584SApple OSS Distributions STATEREPORT_INIT((uint16_t) fNumberOfPowerStates, fReportBuf, reportSize,
7200*1031c584SApple OSS Distributions getRegistryEntryID(), kPMPowerStatesChID, kIOReportCategoryPower);
7201*1031c584SApple OSS Distributions
7202*1031c584SApple OSS Distributions for (i = 0; i < fNumberOfPowerStates; i++) {
7203*1031c584SApple OSS Distributions unsigned bits = 0;
7204*1031c584SApple OSS Distributions
7205*1031c584SApple OSS Distributions if (fPowerStates[i].capabilityFlags & kIOPMPowerOn) {
7206*1031c584SApple OSS Distributions bits |= kPMReportPowerOn;
7207*1031c584SApple OSS Distributions }
7208*1031c584SApple OSS Distributions if (fPowerStates[i].capabilityFlags & kIOPMDeviceUsable) {
7209*1031c584SApple OSS Distributions bits |= kPMReportDeviceUsable;
7210*1031c584SApple OSS Distributions }
7211*1031c584SApple OSS Distributions if (fPowerStates[i].capabilityFlags & kIOPMLowPower) {
7212*1031c584SApple OSS Distributions bits |= kPMReportLowPower;
7213*1031c584SApple OSS Distributions }
7214*1031c584SApple OSS Distributions
7215*1031c584SApple OSS Distributions STATEREPORT_SETSTATEID(fReportBuf, i, ((bits & 0xff) << 8) |
7216*1031c584SApple OSS Distributions ((StateOrder(fMaxPowerState) & 0xf) << 4) | (StateOrder(i) & 0xf));
7217*1031c584SApple OSS Distributions }
7218*1031c584SApple OSS Distributions ts = mach_absolute_time();
7219*1031c584SApple OSS Distributions STATEREPORT_SETSTATE(fReportBuf, (uint16_t) fCurrentPowerState, ts);
7220*1031c584SApple OSS Distributions break;
7221*1031c584SApple OSS Distributions
7222*1031c584SApple OSS Distributions case kIOReportDisable:
7223*1031c584SApple OSS Distributions if (fReportClientCnt == 0) {
7224*1031c584SApple OSS Distributions rc = kIOReturnBadArgument;
7225*1031c584SApple OSS Distributions break;
7226*1031c584SApple OSS Distributions }
7227*1031c584SApple OSS Distributions if (fReportClientCnt == 1) {
7228*1031c584SApple OSS Distributions IOFreeData(fReportBuf, STATEREPORT_BUFSIZE(fNumberOfPowerStates));
7229*1031c584SApple OSS Distributions fReportBuf = NULL;
7230*1031c584SApple OSS Distributions }
7231*1031c584SApple OSS Distributions fReportClientCnt--;
7232*1031c584SApple OSS Distributions break;
7233*1031c584SApple OSS Distributions
7234*1031c584SApple OSS Distributions case kIOReportGetDimensions:
7235*1031c584SApple OSS Distributions if (fReportBuf) {
7236*1031c584SApple OSS Distributions STATEREPORT_UPDATERES(fReportBuf, kIOReportGetDimensions, result);
7237*1031c584SApple OSS Distributions }
7238*1031c584SApple OSS Distributions break;
7239*1031c584SApple OSS Distributions }
7240*1031c584SApple OSS Distributions
7241*1031c584SApple OSS Distributions PM_UNLOCK();
7242*1031c584SApple OSS Distributions
7243*1031c584SApple OSS Distributions return rc;
7244*1031c584SApple OSS Distributions }
7245*1031c584SApple OSS Distributions
7246*1031c584SApple OSS Distributions //*********************************************************************************
7247*1031c584SApple OSS Distributions // updatePowerStateReport
7248*1031c584SApple OSS Distributions //
7249*1031c584SApple OSS Distributions // Updates the IOStateReport for kPMPowerStateChannel
7250*1031c584SApple OSS Distributions //*********************************************************************************
7251*1031c584SApple OSS Distributions IOReturn
updatePowerStatesReport(IOReportConfigureAction action,void * result,void * destination)7252*1031c584SApple OSS Distributions IOService::updatePowerStatesReport( IOReportConfigureAction action, void *result, void *destination )
7253*1031c584SApple OSS Distributions {
7254*1031c584SApple OSS Distributions uint32_t size2cpy;
7255*1031c584SApple OSS Distributions void *data2cpy;
7256*1031c584SApple OSS Distributions uint64_t ts;
7257*1031c584SApple OSS Distributions IOReturn rc = kIOReturnSuccess;
7258*1031c584SApple OSS Distributions IOBufferMemoryDescriptor *dest = OSDynamicCast(IOBufferMemoryDescriptor, (OSObject *)destination);
7259*1031c584SApple OSS Distributions
7260*1031c584SApple OSS Distributions
7261*1031c584SApple OSS Distributions if (!pwrMgt) {
7262*1031c584SApple OSS Distributions return kIOReturnUnsupported;
7263*1031c584SApple OSS Distributions }
7264*1031c584SApple OSS Distributions if (!fNumberOfPowerStates) {
7265*1031c584SApple OSS Distributions return kIOReturnSuccess;
7266*1031c584SApple OSS Distributions }
7267*1031c584SApple OSS Distributions
7268*1031c584SApple OSS Distributions if (!result || !dest) {
7269*1031c584SApple OSS Distributions return kIOReturnBadArgument;
7270*1031c584SApple OSS Distributions }
7271*1031c584SApple OSS Distributions PM_LOCK();
7272*1031c584SApple OSS Distributions
7273*1031c584SApple OSS Distributions switch (action) {
7274*1031c584SApple OSS Distributions case kIOReportCopyChannelData:
7275*1031c584SApple OSS Distributions if (!fReportBuf) {
7276*1031c584SApple OSS Distributions rc = kIOReturnNotOpen;
7277*1031c584SApple OSS Distributions break;
7278*1031c584SApple OSS Distributions }
7279*1031c584SApple OSS Distributions
7280*1031c584SApple OSS Distributions ts = mach_absolute_time();
7281*1031c584SApple OSS Distributions STATEREPORT_UPDATEPREP(fReportBuf, ts, data2cpy, size2cpy);
7282*1031c584SApple OSS Distributions if (size2cpy > (dest->getCapacity() - dest->getLength())) {
7283*1031c584SApple OSS Distributions rc = kIOReturnOverrun;
7284*1031c584SApple OSS Distributions break;
7285*1031c584SApple OSS Distributions }
7286*1031c584SApple OSS Distributions
7287*1031c584SApple OSS Distributions STATEREPORT_UPDATERES(fReportBuf, kIOReportCopyChannelData, result);
7288*1031c584SApple OSS Distributions dest->appendBytes(data2cpy, size2cpy);
7289*1031c584SApple OSS Distributions break;
7290*1031c584SApple OSS Distributions
7291*1031c584SApple OSS Distributions default:
7292*1031c584SApple OSS Distributions break;
7293*1031c584SApple OSS Distributions }
7294*1031c584SApple OSS Distributions
7295*1031c584SApple OSS Distributions PM_UNLOCK();
7296*1031c584SApple OSS Distributions
7297*1031c584SApple OSS Distributions return rc;
7298*1031c584SApple OSS Distributions }
7299*1031c584SApple OSS Distributions
7300*1031c584SApple OSS Distributions //*********************************************************************************
7301*1031c584SApple OSS Distributions // configureSimplePowerReport
7302*1031c584SApple OSS Distributions //
7303*1031c584SApple OSS Distributions // Configures the IOSimpleReport for given channel id
7304*1031c584SApple OSS Distributions //*********************************************************************************
7305*1031c584SApple OSS Distributions IOReturn
configureSimplePowerReport(IOReportConfigureAction action,void * result)7306*1031c584SApple OSS Distributions IOService::configureSimplePowerReport(IOReportConfigureAction action, void *result )
7307*1031c584SApple OSS Distributions {
7308*1031c584SApple OSS Distributions IOReturn rc = kIOReturnSuccess;
7309*1031c584SApple OSS Distributions
7310*1031c584SApple OSS Distributions if (!pwrMgt) {
7311*1031c584SApple OSS Distributions return kIOReturnUnsupported;
7312*1031c584SApple OSS Distributions }
7313*1031c584SApple OSS Distributions
7314*1031c584SApple OSS Distributions if (!fNumberOfPowerStates) {
7315*1031c584SApple OSS Distributions return rc;
7316*1031c584SApple OSS Distributions }
7317*1031c584SApple OSS Distributions
7318*1031c584SApple OSS Distributions switch (action) {
7319*1031c584SApple OSS Distributions case kIOReportEnable:
7320*1031c584SApple OSS Distributions case kIOReportDisable:
7321*1031c584SApple OSS Distributions break;
7322*1031c584SApple OSS Distributions
7323*1031c584SApple OSS Distributions case kIOReportGetDimensions:
7324*1031c584SApple OSS Distributions SIMPLEREPORT_UPDATERES(kIOReportGetDimensions, result);
7325*1031c584SApple OSS Distributions break;
7326*1031c584SApple OSS Distributions }
7327*1031c584SApple OSS Distributions
7328*1031c584SApple OSS Distributions
7329*1031c584SApple OSS Distributions return rc;
7330*1031c584SApple OSS Distributions }
7331*1031c584SApple OSS Distributions
7332*1031c584SApple OSS Distributions //*********************************************************************************
7333*1031c584SApple OSS Distributions // updateSimplePowerReport
7334*1031c584SApple OSS Distributions //
7335*1031c584SApple OSS Distributions // Updates the IOSimpleReport for the given chanel id
7336*1031c584SApple OSS Distributions //*********************************************************************************
7337*1031c584SApple OSS Distributions IOReturn
updateSimplePowerReport(IOReportConfigureAction action,void * result,void * destination)7338*1031c584SApple OSS Distributions IOService::updateSimplePowerReport( IOReportConfigureAction action, void *result, void *destination )
7339*1031c584SApple OSS Distributions {
7340*1031c584SApple OSS Distributions uint32_t size2cpy;
7341*1031c584SApple OSS Distributions void *data2cpy;
7342*1031c584SApple OSS Distributions uint64_t buf[SIMPLEREPORT_BUFSIZE / sizeof(uint64_t) + 1]; // Force a 8-byte alignment
7343*1031c584SApple OSS Distributions IOBufferMemoryDescriptor *dest = OSDynamicCast(IOBufferMemoryDescriptor, (OSObject *)destination);
7344*1031c584SApple OSS Distributions IOReturn rc = kIOReturnSuccess;
7345*1031c584SApple OSS Distributions unsigned bits = 0;
7346*1031c584SApple OSS Distributions
7347*1031c584SApple OSS Distributions
7348*1031c584SApple OSS Distributions if (!pwrMgt) {
7349*1031c584SApple OSS Distributions return kIOReturnUnsupported;
7350*1031c584SApple OSS Distributions }
7351*1031c584SApple OSS Distributions if (!result || !dest) {
7352*1031c584SApple OSS Distributions return kIOReturnBadArgument;
7353*1031c584SApple OSS Distributions }
7354*1031c584SApple OSS Distributions
7355*1031c584SApple OSS Distributions if (!fNumberOfPowerStates) {
7356*1031c584SApple OSS Distributions return rc;
7357*1031c584SApple OSS Distributions }
7358*1031c584SApple OSS Distributions PM_LOCK();
7359*1031c584SApple OSS Distributions
7360*1031c584SApple OSS Distributions switch (action) {
7361*1031c584SApple OSS Distributions case kIOReportCopyChannelData:
7362*1031c584SApple OSS Distributions
7363*1031c584SApple OSS Distributions SIMPLEREPORT_INIT(buf, sizeof(buf), getRegistryEntryID(), kPMCurrStateChID, kIOReportCategoryPower);
7364*1031c584SApple OSS Distributions
7365*1031c584SApple OSS Distributions if (fPowerStates[fCurrentPowerState].capabilityFlags & kIOPMPowerOn) {
7366*1031c584SApple OSS Distributions bits |= kPMReportPowerOn;
7367*1031c584SApple OSS Distributions }
7368*1031c584SApple OSS Distributions if (fPowerStates[fCurrentPowerState].capabilityFlags & kIOPMDeviceUsable) {
7369*1031c584SApple OSS Distributions bits |= kPMReportDeviceUsable;
7370*1031c584SApple OSS Distributions }
7371*1031c584SApple OSS Distributions if (fPowerStates[fCurrentPowerState].capabilityFlags & kIOPMLowPower) {
7372*1031c584SApple OSS Distributions bits |= kPMReportLowPower;
7373*1031c584SApple OSS Distributions }
7374*1031c584SApple OSS Distributions
7375*1031c584SApple OSS Distributions
7376*1031c584SApple OSS Distributions SIMPLEREPORT_SETVALUE(buf, ((bits & 0xff) << 8) | ((StateOrder(fMaxPowerState) & 0xf) << 4) |
7377*1031c584SApple OSS Distributions (StateOrder(fCurrentPowerState) & 0xf));
7378*1031c584SApple OSS Distributions
7379*1031c584SApple OSS Distributions SIMPLEREPORT_UPDATEPREP(buf, data2cpy, size2cpy);
7380*1031c584SApple OSS Distributions if (size2cpy > (dest->getCapacity() - dest->getLength())) {
7381*1031c584SApple OSS Distributions rc = kIOReturnOverrun;
7382*1031c584SApple OSS Distributions break;
7383*1031c584SApple OSS Distributions }
7384*1031c584SApple OSS Distributions
7385*1031c584SApple OSS Distributions SIMPLEREPORT_UPDATERES(kIOReportCopyChannelData, result);
7386*1031c584SApple OSS Distributions dest->appendBytes(data2cpy, size2cpy);
7387*1031c584SApple OSS Distributions break;
7388*1031c584SApple OSS Distributions
7389*1031c584SApple OSS Distributions default:
7390*1031c584SApple OSS Distributions break;
7391*1031c584SApple OSS Distributions }
7392*1031c584SApple OSS Distributions
7393*1031c584SApple OSS Distributions PM_UNLOCK();
7394*1031c584SApple OSS Distributions
7395*1031c584SApple OSS Distributions return rc;
7396*1031c584SApple OSS Distributions }
7397*1031c584SApple OSS Distributions
7398*1031c584SApple OSS Distributions
7399*1031c584SApple OSS Distributions
7400*1031c584SApple OSS Distributions // MARK: -
7401*1031c584SApple OSS Distributions // MARK: Driver Overrides
7402*1031c584SApple OSS Distributions
7403*1031c584SApple OSS Distributions //*********************************************************************************
7404*1031c584SApple OSS Distributions // [public] setPowerState
7405*1031c584SApple OSS Distributions //
7406*1031c584SApple OSS Distributions // Does nothing here. This should be implemented in a subclass driver.
7407*1031c584SApple OSS Distributions //*********************************************************************************
7408*1031c584SApple OSS Distributions
7409*1031c584SApple OSS Distributions IOReturn
setPowerState(unsigned long powerStateOrdinal,IOService * whatDevice)7410*1031c584SApple OSS Distributions IOService::setPowerState(
7411*1031c584SApple OSS Distributions unsigned long powerStateOrdinal, IOService * whatDevice )
7412*1031c584SApple OSS Distributions {
7413*1031c584SApple OSS Distributions return IOPMNoErr;
7414*1031c584SApple OSS Distributions }
7415*1031c584SApple OSS Distributions
7416*1031c584SApple OSS Distributions //*********************************************************************************
7417*1031c584SApple OSS Distributions // [public] maxCapabilityForDomainState
7418*1031c584SApple OSS Distributions //
7419*1031c584SApple OSS Distributions // Finds the highest power state in the array whose input power requirement
7420*1031c584SApple OSS Distributions // is equal to the input parameter. Where a more intelligent decision is
7421*1031c584SApple OSS Distributions // possible, override this in the subclassed driver.
7422*1031c584SApple OSS Distributions //*********************************************************************************
7423*1031c584SApple OSS Distributions
7424*1031c584SApple OSS Distributions IOPMPowerStateIndex
getPowerStateForDomainFlags(IOPMPowerFlags flags)7425*1031c584SApple OSS Distributions IOService::getPowerStateForDomainFlags( IOPMPowerFlags flags )
7426*1031c584SApple OSS Distributions {
7427*1031c584SApple OSS Distributions IOPMPowerStateIndex stateIndex;
7428*1031c584SApple OSS Distributions
7429*1031c584SApple OSS Distributions if (!fNumberOfPowerStates) {
7430*1031c584SApple OSS Distributions return kPowerStateZero;
7431*1031c584SApple OSS Distributions }
7432*1031c584SApple OSS Distributions
7433*1031c584SApple OSS Distributions for (long order = fNumberOfPowerStates - 1; order >= 0; order--) {
7434*1031c584SApple OSS Distributions stateIndex = fPowerStates[order].stateOrderToIndex;
7435*1031c584SApple OSS Distributions
7436*1031c584SApple OSS Distributions if ((flags & fPowerStates[stateIndex].inputPowerFlags) ==
7437*1031c584SApple OSS Distributions fPowerStates[stateIndex].inputPowerFlags) {
7438*1031c584SApple OSS Distributions return stateIndex;
7439*1031c584SApple OSS Distributions }
7440*1031c584SApple OSS Distributions }
7441*1031c584SApple OSS Distributions return kPowerStateZero;
7442*1031c584SApple OSS Distributions }
7443*1031c584SApple OSS Distributions
7444*1031c584SApple OSS Distributions unsigned long
maxCapabilityForDomainState(IOPMPowerFlags domainState)7445*1031c584SApple OSS Distributions IOService::maxCapabilityForDomainState( IOPMPowerFlags domainState )
7446*1031c584SApple OSS Distributions {
7447*1031c584SApple OSS Distributions return getPowerStateForDomainFlags(domainState);
7448*1031c584SApple OSS Distributions }
7449*1031c584SApple OSS Distributions
7450*1031c584SApple OSS Distributions //*********************************************************************************
7451*1031c584SApple OSS Distributions // [public] initialPowerStateForDomainState
7452*1031c584SApple OSS Distributions //
7453*1031c584SApple OSS Distributions // Called to query the power state for the initial power transition.
7454*1031c584SApple OSS Distributions //*********************************************************************************
7455*1031c584SApple OSS Distributions
7456*1031c584SApple OSS Distributions unsigned long
initialPowerStateForDomainState(IOPMPowerFlags domainState)7457*1031c584SApple OSS Distributions IOService::initialPowerStateForDomainState( IOPMPowerFlags domainState )
7458*1031c584SApple OSS Distributions {
7459*1031c584SApple OSS Distributions if (fResetPowerStateOnWake && (domainState & kIOPMRootDomainState)) {
7460*1031c584SApple OSS Distributions // Return lowest power state for any root power domain changes
7461*1031c584SApple OSS Distributions return kPowerStateZero;
7462*1031c584SApple OSS Distributions }
7463*1031c584SApple OSS Distributions
7464*1031c584SApple OSS Distributions return getPowerStateForDomainFlags(domainState);
7465*1031c584SApple OSS Distributions }
7466*1031c584SApple OSS Distributions
7467*1031c584SApple OSS Distributions //*********************************************************************************
7468*1031c584SApple OSS Distributions // [public] powerStateForDomainState
7469*1031c584SApple OSS Distributions //
7470*1031c584SApple OSS Distributions // This method is not called from PM.
7471*1031c584SApple OSS Distributions //*********************************************************************************
7472*1031c584SApple OSS Distributions
7473*1031c584SApple OSS Distributions unsigned long
powerStateForDomainState(IOPMPowerFlags domainState)7474*1031c584SApple OSS Distributions IOService::powerStateForDomainState( IOPMPowerFlags domainState )
7475*1031c584SApple OSS Distributions {
7476*1031c584SApple OSS Distributions return getPowerStateForDomainFlags(domainState);
7477*1031c584SApple OSS Distributions }
7478*1031c584SApple OSS Distributions
7479*1031c584SApple OSS Distributions #ifndef __LP64__
7480*1031c584SApple OSS Distributions //*********************************************************************************
7481*1031c584SApple OSS Distributions // [deprecated] didYouWakeSystem
7482*1031c584SApple OSS Distributions //
7483*1031c584SApple OSS Distributions // Does nothing here. This should be implemented in a subclass driver.
7484*1031c584SApple OSS Distributions //*********************************************************************************
7485*1031c584SApple OSS Distributions
7486*1031c584SApple OSS Distributions bool
didYouWakeSystem(void)7487*1031c584SApple OSS Distributions IOService::didYouWakeSystem( void )
7488*1031c584SApple OSS Distributions {
7489*1031c584SApple OSS Distributions return false;
7490*1031c584SApple OSS Distributions }
7491*1031c584SApple OSS Distributions #endif /* !__LP64__ */
7492*1031c584SApple OSS Distributions
7493*1031c584SApple OSS Distributions //*********************************************************************************
7494*1031c584SApple OSS Distributions // [public] powerStateWillChangeTo
7495*1031c584SApple OSS Distributions //
7496*1031c584SApple OSS Distributions // Does nothing here. This should be implemented in a subclass driver.
7497*1031c584SApple OSS Distributions //*********************************************************************************
7498*1031c584SApple OSS Distributions
7499*1031c584SApple OSS Distributions IOReturn
powerStateWillChangeTo(IOPMPowerFlags,unsigned long,IOService *)7500*1031c584SApple OSS Distributions IOService::powerStateWillChangeTo( IOPMPowerFlags, unsigned long, IOService * )
7501*1031c584SApple OSS Distributions {
7502*1031c584SApple OSS Distributions return kIOPMAckImplied;
7503*1031c584SApple OSS Distributions }
7504*1031c584SApple OSS Distributions
7505*1031c584SApple OSS Distributions //*********************************************************************************
7506*1031c584SApple OSS Distributions // [public] powerStateDidChangeTo
7507*1031c584SApple OSS Distributions //
7508*1031c584SApple OSS Distributions // Does nothing here. This should be implemented in a subclass driver.
7509*1031c584SApple OSS Distributions //*********************************************************************************
7510*1031c584SApple OSS Distributions
7511*1031c584SApple OSS Distributions IOReturn
powerStateDidChangeTo(IOPMPowerFlags,unsigned long,IOService *)7512*1031c584SApple OSS Distributions IOService::powerStateDidChangeTo( IOPMPowerFlags, unsigned long, IOService * )
7513*1031c584SApple OSS Distributions {
7514*1031c584SApple OSS Distributions return kIOPMAckImplied;
7515*1031c584SApple OSS Distributions }
7516*1031c584SApple OSS Distributions
7517*1031c584SApple OSS Distributions //*********************************************************************************
7518*1031c584SApple OSS Distributions // [protected] powerChangeDone
7519*1031c584SApple OSS Distributions //
7520*1031c584SApple OSS Distributions // Called from PM work loop thread.
7521*1031c584SApple OSS Distributions // Does nothing here. This should be implemented in a subclass policy-maker.
7522*1031c584SApple OSS Distributions //*********************************************************************************
7523*1031c584SApple OSS Distributions
7524*1031c584SApple OSS Distributions void
powerChangeDone(unsigned long)7525*1031c584SApple OSS Distributions IOService::powerChangeDone( unsigned long )
7526*1031c584SApple OSS Distributions {
7527*1031c584SApple OSS Distributions }
7528*1031c584SApple OSS Distributions
7529*1031c584SApple OSS Distributions #ifndef __LP64__
7530*1031c584SApple OSS Distributions //*********************************************************************************
7531*1031c584SApple OSS Distributions // [deprecated] newTemperature
7532*1031c584SApple OSS Distributions //
7533*1031c584SApple OSS Distributions // Does nothing here. This should be implemented in a subclass driver.
7534*1031c584SApple OSS Distributions //*********************************************************************************
7535*1031c584SApple OSS Distributions
7536*1031c584SApple OSS Distributions IOReturn
newTemperature(long currentTemp,IOService * whichZone)7537*1031c584SApple OSS Distributions IOService::newTemperature( long currentTemp, IOService * whichZone )
7538*1031c584SApple OSS Distributions {
7539*1031c584SApple OSS Distributions return IOPMNoErr;
7540*1031c584SApple OSS Distributions }
7541*1031c584SApple OSS Distributions #endif /* !__LP64__ */
7542*1031c584SApple OSS Distributions
7543*1031c584SApple OSS Distributions //*********************************************************************************
7544*1031c584SApple OSS Distributions // [public] systemWillShutdown
7545*1031c584SApple OSS Distributions //
7546*1031c584SApple OSS Distributions // System shutdown and restart notification.
7547*1031c584SApple OSS Distributions //*********************************************************************************
7548*1031c584SApple OSS Distributions
7549*1031c584SApple OSS Distributions void
systemWillShutdown(IOOptionBits specifier)7550*1031c584SApple OSS Distributions IOService::systemWillShutdown( IOOptionBits specifier )
7551*1031c584SApple OSS Distributions {
7552*1031c584SApple OSS Distributions IOPMrootDomain * rootDomain = IOService::getPMRootDomain();
7553*1031c584SApple OSS Distributions if (rootDomain) {
7554*1031c584SApple OSS Distributions rootDomain->acknowledgeSystemWillShutdown( this );
7555*1031c584SApple OSS Distributions }
7556*1031c584SApple OSS Distributions }
7557*1031c584SApple OSS Distributions
7558*1031c584SApple OSS Distributions // MARK: -
7559*1031c584SApple OSS Distributions // MARK: PM State Machine
7560*1031c584SApple OSS Distributions
7561*1031c584SApple OSS Distributions //*********************************************************************************
7562*1031c584SApple OSS Distributions // [private static] acquirePMRequest
7563*1031c584SApple OSS Distributions //*********************************************************************************
7564*1031c584SApple OSS Distributions
7565*1031c584SApple OSS Distributions IOPMRequest *
acquirePMRequest(IOService * target,IOOptionBits requestType,IOPMRequest * active)7566*1031c584SApple OSS Distributions IOService::acquirePMRequest( IOService * target, IOOptionBits requestType,
7567*1031c584SApple OSS Distributions IOPMRequest * active )
7568*1031c584SApple OSS Distributions {
7569*1031c584SApple OSS Distributions IOPMRequest * request;
7570*1031c584SApple OSS Distributions
7571*1031c584SApple OSS Distributions assert(target);
7572*1031c584SApple OSS Distributions
7573*1031c584SApple OSS Distributions request = IOPMRequest::create();
7574*1031c584SApple OSS Distributions if (request) {
7575*1031c584SApple OSS Distributions request->init( target, requestType );
7576*1031c584SApple OSS Distributions if (active) {
7577*1031c584SApple OSS Distributions IOPMRequest * root = active->getRootRequest();
7578*1031c584SApple OSS Distributions if (root) {
7579*1031c584SApple OSS Distributions request->attachRootRequest(root);
7580*1031c584SApple OSS Distributions }
7581*1031c584SApple OSS Distributions }
7582*1031c584SApple OSS Distributions } else {
7583*1031c584SApple OSS Distributions PM_ERROR("%s: No memory for PM request type 0x%x\n",
7584*1031c584SApple OSS Distributions target->getName(), (uint32_t) requestType);
7585*1031c584SApple OSS Distributions }
7586*1031c584SApple OSS Distributions return request;
7587*1031c584SApple OSS Distributions }
7588*1031c584SApple OSS Distributions
7589*1031c584SApple OSS Distributions //*********************************************************************************
7590*1031c584SApple OSS Distributions // [private static] releasePMRequest
7591*1031c584SApple OSS Distributions //*********************************************************************************
7592*1031c584SApple OSS Distributions
7593*1031c584SApple OSS Distributions void
releasePMRequest(IOPMRequest * request)7594*1031c584SApple OSS Distributions IOService::releasePMRequest( IOPMRequest * request )
7595*1031c584SApple OSS Distributions {
7596*1031c584SApple OSS Distributions if (request) {
7597*1031c584SApple OSS Distributions request->reset();
7598*1031c584SApple OSS Distributions request->release();
7599*1031c584SApple OSS Distributions }
7600*1031c584SApple OSS Distributions }
7601*1031c584SApple OSS Distributions
7602*1031c584SApple OSS Distributions //*********************************************************************************
7603*1031c584SApple OSS Distributions // [private static] submitPMRequest
7604*1031c584SApple OSS Distributions //*********************************************************************************
7605*1031c584SApple OSS Distributions
7606*1031c584SApple OSS Distributions void
submitPMRequest(IOPMRequest * request)7607*1031c584SApple OSS Distributions IOService::submitPMRequest( IOPMRequest * request )
7608*1031c584SApple OSS Distributions {
7609*1031c584SApple OSS Distributions assert( request );
7610*1031c584SApple OSS Distributions assert( gIOPMReplyQueue );
7611*1031c584SApple OSS Distributions assert( gIOPMRequestQueue );
7612*1031c584SApple OSS Distributions
7613*1031c584SApple OSS Distributions PM_LOG1("[+ %02lx] %p [%p %s] %p %p %p\n",
7614*1031c584SApple OSS Distributions (long)request->getType(), OBFUSCATE(request),
7615*1031c584SApple OSS Distributions OBFUSCATE(request->getTarget()), request->getTarget()->getName(),
7616*1031c584SApple OSS Distributions OBFUSCATE(request->fArg0),
7617*1031c584SApple OSS Distributions OBFUSCATE(request->fArg1), OBFUSCATE(request->fArg2));
7618*1031c584SApple OSS Distributions
7619*1031c584SApple OSS Distributions if (request->isReplyType()) {
7620*1031c584SApple OSS Distributions gIOPMReplyQueue->queuePMRequest( request );
7621*1031c584SApple OSS Distributions } else {
7622*1031c584SApple OSS Distributions gIOPMRequestQueue->queuePMRequest( request );
7623*1031c584SApple OSS Distributions }
7624*1031c584SApple OSS Distributions }
7625*1031c584SApple OSS Distributions
7626*1031c584SApple OSS Distributions void
submitPMRequests(IOPMRequest ** requests,IOItemCount count)7627*1031c584SApple OSS Distributions IOService::submitPMRequests( IOPMRequest ** requests, IOItemCount count )
7628*1031c584SApple OSS Distributions {
7629*1031c584SApple OSS Distributions assert( requests );
7630*1031c584SApple OSS Distributions assert( count > 0 );
7631*1031c584SApple OSS Distributions assert( gIOPMRequestQueue );
7632*1031c584SApple OSS Distributions
7633*1031c584SApple OSS Distributions for (IOItemCount i = 0; i < count; i++) {
7634*1031c584SApple OSS Distributions IOPMRequest * req = requests[i];
7635*1031c584SApple OSS Distributions PM_LOG1("[+ %02lx] %p [%p %s] %p %p %p\n",
7636*1031c584SApple OSS Distributions (long)req->getType(), OBFUSCATE(req),
7637*1031c584SApple OSS Distributions OBFUSCATE(req->getTarget()), req->getTarget()->getName(),
7638*1031c584SApple OSS Distributions OBFUSCATE(req->fArg0),
7639*1031c584SApple OSS Distributions OBFUSCATE(req->fArg1), OBFUSCATE(req->fArg2));
7640*1031c584SApple OSS Distributions }
7641*1031c584SApple OSS Distributions
7642*1031c584SApple OSS Distributions gIOPMRequestQueue->queuePMRequestChain( requests, count );
7643*1031c584SApple OSS Distributions }
7644*1031c584SApple OSS Distributions
7645*1031c584SApple OSS Distributions //*********************************************************************************
7646*1031c584SApple OSS Distributions // [private] actionPMRequestQueue
7647*1031c584SApple OSS Distributions //
7648*1031c584SApple OSS Distributions // IOPMRequestQueue::checkForWork() passing a new request to the request target.
7649*1031c584SApple OSS Distributions //*********************************************************************************
7650*1031c584SApple OSS Distributions
7651*1031c584SApple OSS Distributions bool
actionPMRequestQueue(IOPMRequest * request,IOPMRequestQueue * queue)7652*1031c584SApple OSS Distributions IOService::actionPMRequestQueue(
7653*1031c584SApple OSS Distributions IOPMRequest * request,
7654*1031c584SApple OSS Distributions IOPMRequestQueue * queue )
7655*1031c584SApple OSS Distributions {
7656*1031c584SApple OSS Distributions bool more;
7657*1031c584SApple OSS Distributions
7658*1031c584SApple OSS Distributions if (initialized) {
7659*1031c584SApple OSS Distributions // Work queue will immediately execute the request if the per-service
7660*1031c584SApple OSS Distributions // request queue is empty. Note pwrMgt is the target's IOServicePM.
7661*1031c584SApple OSS Distributions
7662*1031c584SApple OSS Distributions more = gIOPMWorkQueue->queuePMRequest(request, pwrMgt);
7663*1031c584SApple OSS Distributions } else {
7664*1031c584SApple OSS Distributions // Calling PM without PMinit() is not allowed, fail the request.
7665*1031c584SApple OSS Distributions // Need to signal more when completing attached requests.
7666*1031c584SApple OSS Distributions
7667*1031c584SApple OSS Distributions PM_LOG("%s: PM not initialized\n", getName());
7668*1031c584SApple OSS Distributions PM_LOG1("[- %02x] %p [%p %s] !initialized\n",
7669*1031c584SApple OSS Distributions request->getType(), OBFUSCATE(request),
7670*1031c584SApple OSS Distributions OBFUSCATE(this), getName());
7671*1031c584SApple OSS Distributions
7672*1031c584SApple OSS Distributions more = gIOPMCompletionQueue->queuePMRequest(request);
7673*1031c584SApple OSS Distributions if (more) {
7674*1031c584SApple OSS Distributions gIOPMWorkQueue->incrementProducerCount();
7675*1031c584SApple OSS Distributions }
7676*1031c584SApple OSS Distributions }
7677*1031c584SApple OSS Distributions
7678*1031c584SApple OSS Distributions return more;
7679*1031c584SApple OSS Distributions }
7680*1031c584SApple OSS Distributions
7681*1031c584SApple OSS Distributions //*********************************************************************************
7682*1031c584SApple OSS Distributions // [private] actionPMCompletionQueue
7683*1031c584SApple OSS Distributions //
7684*1031c584SApple OSS Distributions // IOPMCompletionQueue::checkForWork() passing a completed request to the
7685*1031c584SApple OSS Distributions // request target.
7686*1031c584SApple OSS Distributions //*********************************************************************************
7687*1031c584SApple OSS Distributions
7688*1031c584SApple OSS Distributions bool
actionPMCompletionQueue(IOPMRequest * request,IOPMCompletionQueue * queue)7689*1031c584SApple OSS Distributions IOService::actionPMCompletionQueue(
7690*1031c584SApple OSS Distributions IOPMRequest * request,
7691*1031c584SApple OSS Distributions IOPMCompletionQueue * queue )
7692*1031c584SApple OSS Distributions {
7693*1031c584SApple OSS Distributions bool more = (request->getNextRequest() != NULL);
7694*1031c584SApple OSS Distributions IOPMRequest * root = request->getRootRequest();
7695*1031c584SApple OSS Distributions
7696*1031c584SApple OSS Distributions if (root && (root != request)) {
7697*1031c584SApple OSS Distributions more = true;
7698*1031c584SApple OSS Distributions }
7699*1031c584SApple OSS Distributions if (more) {
7700*1031c584SApple OSS Distributions gIOPMWorkQueue->incrementProducerCount();
7701*1031c584SApple OSS Distributions }
7702*1031c584SApple OSS Distributions
7703*1031c584SApple OSS Distributions releasePMRequest( request );
7704*1031c584SApple OSS Distributions return more;
7705*1031c584SApple OSS Distributions }
7706*1031c584SApple OSS Distributions
7707*1031c584SApple OSS Distributions //*********************************************************************************
7708*1031c584SApple OSS Distributions // [private] actionPMWorkQueueRetire
7709*1031c584SApple OSS Distributions //
7710*1031c584SApple OSS Distributions // IOPMWorkQueue::checkForWork() passing a retired request to the request target.
7711*1031c584SApple OSS Distributions //*********************************************************************************
7712*1031c584SApple OSS Distributions
7713*1031c584SApple OSS Distributions bool
actionPMWorkQueueRetire(IOPMRequest * request,IOPMWorkQueue * queue)7714*1031c584SApple OSS Distributions IOService::actionPMWorkQueueRetire( IOPMRequest * request, IOPMWorkQueue * queue )
7715*1031c584SApple OSS Distributions {
7716*1031c584SApple OSS Distributions assert(request && queue);
7717*1031c584SApple OSS Distributions
7718*1031c584SApple OSS Distributions PM_LOG1("[- %02x] %p [%p %s] state %d, busy %d\n",
7719*1031c584SApple OSS Distributions request->getType(), OBFUSCATE(request),
7720*1031c584SApple OSS Distributions OBFUSCATE(this), getName(),
7721*1031c584SApple OSS Distributions fMachineState, gIOPMBusyRequestCount);
7722*1031c584SApple OSS Distributions
7723*1031c584SApple OSS Distributions // Catch requests created by idleTimerExpired()
7724*1031c584SApple OSS Distributions if (request->getType() == kIOPMRequestTypeActivityTickle) {
7725*1031c584SApple OSS Distributions uint32_t tickleFlags = (uint32_t)(uintptr_t) request->fArg1;
7726*1031c584SApple OSS Distributions
7727*1031c584SApple OSS Distributions if ((tickleFlags & kTickleTypePowerDrop) && fIdleTimerPeriod) {
7728*1031c584SApple OSS Distributions restartIdleTimer();
7729*1031c584SApple OSS Distributions } else if (tickleFlags == (kTickleTypeActivity | kTickleTypePowerRise)) {
7730*1031c584SApple OSS Distributions // Invalidate any idle power drop that got queued while
7731*1031c584SApple OSS Distributions // processing this request.
7732*1031c584SApple OSS Distributions fIdleTimerGeneration++;
7733*1031c584SApple OSS Distributions }
7734*1031c584SApple OSS Distributions }
7735*1031c584SApple OSS Distributions
7736*1031c584SApple OSS Distributions // When the completed request is linked, tell work queue there is
7737*1031c584SApple OSS Distributions // more work pending.
7738*1031c584SApple OSS Distributions
7739*1031c584SApple OSS Distributions return gIOPMCompletionQueue->queuePMRequest( request );
7740*1031c584SApple OSS Distributions }
7741*1031c584SApple OSS Distributions
7742*1031c584SApple OSS Distributions //*********************************************************************************
7743*1031c584SApple OSS Distributions // [private] isPMBlocked
7744*1031c584SApple OSS Distributions //
7745*1031c584SApple OSS Distributions // Check if machine state transition is blocked.
7746*1031c584SApple OSS Distributions //*********************************************************************************
7747*1031c584SApple OSS Distributions
7748*1031c584SApple OSS Distributions bool
isPMBlocked(IOPMRequest * request,int count)7749*1031c584SApple OSS Distributions IOService::isPMBlocked( IOPMRequest * request, int count )
7750*1031c584SApple OSS Distributions {
7751*1031c584SApple OSS Distributions int reason = 0;
7752*1031c584SApple OSS Distributions
7753*1031c584SApple OSS Distributions do {
7754*1031c584SApple OSS Distributions if (kIOPM_Finished == fMachineState) {
7755*1031c584SApple OSS Distributions break;
7756*1031c584SApple OSS Distributions }
7757*1031c584SApple OSS Distributions
7758*1031c584SApple OSS Distributions if (kIOPM_DriverThreadCallDone == fMachineState) {
7759*1031c584SApple OSS Distributions // 5 = kDriverCallInformPreChange
7760*1031c584SApple OSS Distributions // 6 = kDriverCallInformPostChange
7761*1031c584SApple OSS Distributions // 7 = kDriverCallSetPowerState
7762*1031c584SApple OSS Distributions // 8 = kRootDomainInformPreChange
7763*1031c584SApple OSS Distributions if (fDriverCallBusy) {
7764*1031c584SApple OSS Distributions reason = 5 + fDriverCallReason;
7765*1031c584SApple OSS Distributions }
7766*1031c584SApple OSS Distributions break;
7767*1031c584SApple OSS Distributions }
7768*1031c584SApple OSS Distributions
7769*1031c584SApple OSS Distributions // Waiting on driver's setPowerState() timeout.
7770*1031c584SApple OSS Distributions if (fDriverTimer) {
7771*1031c584SApple OSS Distributions reason = 1; break;
7772*1031c584SApple OSS Distributions }
7773*1031c584SApple OSS Distributions
7774*1031c584SApple OSS Distributions // Child or interested driver acks pending.
7775*1031c584SApple OSS Distributions if (fHeadNotePendingAcks) {
7776*1031c584SApple OSS Distributions reason = 2; break;
7777*1031c584SApple OSS Distributions }
7778*1031c584SApple OSS Distributions
7779*1031c584SApple OSS Distributions // Waiting on apps or priority power interest clients.
7780*1031c584SApple OSS Distributions if (fResponseArray) {
7781*1031c584SApple OSS Distributions reason = 3; break;
7782*1031c584SApple OSS Distributions }
7783*1031c584SApple OSS Distributions
7784*1031c584SApple OSS Distributions #if USE_SETTLE_TIMER
7785*1031c584SApple OSS Distributions // Waiting on settle timer expiration.
7786*1031c584SApple OSS Distributions if (fSettleTimeUS) {
7787*1031c584SApple OSS Distributions reason = 4; break;
7788*1031c584SApple OSS Distributions }
7789*1031c584SApple OSS Distributions #endif
7790*1031c584SApple OSS Distributions } while (false);
7791*1031c584SApple OSS Distributions
7792*1031c584SApple OSS Distributions fWaitReason = reason;
7793*1031c584SApple OSS Distributions
7794*1031c584SApple OSS Distributions if (reason) {
7795*1031c584SApple OSS Distributions if (count) {
7796*1031c584SApple OSS Distributions PM_LOG1("[B %02x] %p [%p %s] state %d, reason %d\n",
7797*1031c584SApple OSS Distributions request->getType(), OBFUSCATE(request),
7798*1031c584SApple OSS Distributions OBFUSCATE(this), getName(),
7799*1031c584SApple OSS Distributions fMachineState, reason);
7800*1031c584SApple OSS Distributions }
7801*1031c584SApple OSS Distributions
7802*1031c584SApple OSS Distributions return true;
7803*1031c584SApple OSS Distributions }
7804*1031c584SApple OSS Distributions
7805*1031c584SApple OSS Distributions return false;
7806*1031c584SApple OSS Distributions }
7807*1031c584SApple OSS Distributions
7808*1031c584SApple OSS Distributions //*********************************************************************************
7809*1031c584SApple OSS Distributions // [private] actionPMWorkQueueInvoke
7810*1031c584SApple OSS Distributions //
7811*1031c584SApple OSS Distributions // IOPMWorkQueue::checkForWork() passing a request to the
7812*1031c584SApple OSS Distributions // request target for execution.
7813*1031c584SApple OSS Distributions //*********************************************************************************
7814*1031c584SApple OSS Distributions
7815*1031c584SApple OSS Distributions bool
actionPMWorkQueueInvoke(IOPMRequest * request,IOPMWorkQueue * queue)7816*1031c584SApple OSS Distributions IOService::actionPMWorkQueueInvoke( IOPMRequest * request, IOPMWorkQueue * queue )
7817*1031c584SApple OSS Distributions {
7818*1031c584SApple OSS Distributions bool done = false;
7819*1031c584SApple OSS Distributions int loop = 0;
7820*1031c584SApple OSS Distributions
7821*1031c584SApple OSS Distributions assert(request && queue);
7822*1031c584SApple OSS Distributions
7823*1031c584SApple OSS Distributions while (isPMBlocked(request, loop++) == false) {
7824*1031c584SApple OSS Distributions PM_LOG1("[W %02x] %p [%p %s] state %d\n",
7825*1031c584SApple OSS Distributions request->getType(), OBFUSCATE(request),
7826*1031c584SApple OSS Distributions OBFUSCATE(this), getName(), fMachineState);
7827*1031c584SApple OSS Distributions
7828*1031c584SApple OSS Distributions gIOPMRequest = request;
7829*1031c584SApple OSS Distributions gIOPMWorkInvokeCount++;
7830*1031c584SApple OSS Distributions
7831*1031c584SApple OSS Distributions // Every PM machine states must be handled in one of the cases below.
7832*1031c584SApple OSS Distributions
7833*1031c584SApple OSS Distributions switch (fMachineState) {
7834*1031c584SApple OSS Distributions case kIOPM_Finished:
7835*1031c584SApple OSS Distributions start_watchdog_timer();
7836*1031c584SApple OSS Distributions
7837*1031c584SApple OSS Distributions executePMRequest( request );
7838*1031c584SApple OSS Distributions break;
7839*1031c584SApple OSS Distributions
7840*1031c584SApple OSS Distributions case kIOPM_OurChangeTellClientsPowerDown:
7841*1031c584SApple OSS Distributions // Root domain might self cancel due to assertions.
7842*1031c584SApple OSS Distributions if (IS_ROOT_DOMAIN) {
7843*1031c584SApple OSS Distributions bool cancel = (bool) fDoNotPowerDown;
7844*1031c584SApple OSS Distributions getPMRootDomain()->askChangeDownDone(
7845*1031c584SApple OSS Distributions &fHeadNoteChangeFlags, &cancel);
7846*1031c584SApple OSS Distributions fDoNotPowerDown = cancel;
7847*1031c584SApple OSS Distributions }
7848*1031c584SApple OSS Distributions
7849*1031c584SApple OSS Distributions // askChangeDown() done, was it vetoed?
7850*1031c584SApple OSS Distributions if (!fDoNotPowerDown) {
7851*1031c584SApple OSS Distributions // no, we can continue
7852*1031c584SApple OSS Distributions OurChangeTellClientsPowerDown();
7853*1031c584SApple OSS Distributions } else {
7854*1031c584SApple OSS Distributions OUR_PMLog(kPMLogIdleCancel, (uintptr_t) this, fMachineState);
7855*1031c584SApple OSS Distributions PM_ERROR("%s: idle cancel, state %u\n", fName, fMachineState);
7856*1031c584SApple OSS Distributions #if DEVELOPMENT || DEBUG
7857*1031c584SApple OSS Distributions record_system_event(SYSTEM_EVENT_TYPE_INFO,
7858*1031c584SApple OSS Distributions SYSTEM_EVENT_SUBSYSTEM_PMRD,
7859*1031c584SApple OSS Distributions "Idle Sleep", "%s idle cancel, state %u", fName, fMachineState
7860*1031c584SApple OSS Distributions );
7861*1031c584SApple OSS Distributions #endif /* DEVELOPMENT || DEBUG */
7862*1031c584SApple OSS Distributions if (IS_ROOT_DOMAIN) {
7863*1031c584SApple OSS Distributions // RootDomain already sent "WillSleep" to its clients
7864*1031c584SApple OSS Distributions tellChangeUp(fCurrentPowerState);
7865*1031c584SApple OSS Distributions } else {
7866*1031c584SApple OSS Distributions tellNoChangeDown(fHeadNotePowerState);
7867*1031c584SApple OSS Distributions }
7868*1031c584SApple OSS Distributions // mark the change note un-actioned
7869*1031c584SApple OSS Distributions fHeadNoteChangeFlags |= kIOPMNotDone;
7870*1031c584SApple OSS Distributions // and we're done
7871*1031c584SApple OSS Distributions OurChangeFinish();
7872*1031c584SApple OSS Distributions }
7873*1031c584SApple OSS Distributions break;
7874*1031c584SApple OSS Distributions
7875*1031c584SApple OSS Distributions case kIOPM_OurChangeTellUserPMPolicyPowerDown:
7876*1031c584SApple OSS Distributions // PMRD: tellChangeDown/kNotifyApps done, was it cancelled?
7877*1031c584SApple OSS Distributions if (fDoNotPowerDown) {
7878*1031c584SApple OSS Distributions OUR_PMLog(kPMLogIdleCancel, (uintptr_t) this, fMachineState);
7879*1031c584SApple OSS Distributions PM_ERROR("%s: idle cancel, state %u\n", fName, fMachineState);
7880*1031c584SApple OSS Distributions #if DEVELOPMENT || DEBUG
7881*1031c584SApple OSS Distributions record_system_event(SYSTEM_EVENT_TYPE_INFO,
7882*1031c584SApple OSS Distributions SYSTEM_EVENT_SUBSYSTEM_PMRD,
7883*1031c584SApple OSS Distributions "Idle Sleep", "%s idle cancel, state %u", fName, fMachineState
7884*1031c584SApple OSS Distributions );
7885*1031c584SApple OSS Distributions #endif /* DEVELOPMENT || DEBUG */
7886*1031c584SApple OSS Distributions if (IS_ROOT_DOMAIN) {
7887*1031c584SApple OSS Distributions // RootDomain already sent "WillSleep" to its clients
7888*1031c584SApple OSS Distributions tellChangeUp(fCurrentPowerState);
7889*1031c584SApple OSS Distributions } else {
7890*1031c584SApple OSS Distributions tellNoChangeDown(fHeadNotePowerState);
7891*1031c584SApple OSS Distributions }
7892*1031c584SApple OSS Distributions // mark the change note un-actioned
7893*1031c584SApple OSS Distributions fHeadNoteChangeFlags |= kIOPMNotDone;
7894*1031c584SApple OSS Distributions // and we're done
7895*1031c584SApple OSS Distributions OurChangeFinish();
7896*1031c584SApple OSS Distributions } else {
7897*1031c584SApple OSS Distributions OurChangeTellUserPMPolicyPowerDown();
7898*1031c584SApple OSS Distributions }
7899*1031c584SApple OSS Distributions break;
7900*1031c584SApple OSS Distributions
7901*1031c584SApple OSS Distributions case kIOPM_OurChangeTellPriorityClientsPowerDown:
7902*1031c584SApple OSS Distributions // PMRD: LastCallBeforeSleep notify done
7903*1031c584SApple OSS Distributions // Non-PMRD: tellChangeDown/kNotifyApps done
7904*1031c584SApple OSS Distributions if (fDoNotPowerDown) {
7905*1031c584SApple OSS Distributions OUR_PMLog(kPMLogIdleCancel, (uintptr_t) this, fMachineState);
7906*1031c584SApple OSS Distributions PM_ERROR("%s: idle revert, state %u\n", fName, fMachineState);
7907*1031c584SApple OSS Distributions // no, tell clients we're back in the old state
7908*1031c584SApple OSS Distributions tellChangeUp(fCurrentPowerState);
7909*1031c584SApple OSS Distributions // mark the change note un-actioned
7910*1031c584SApple OSS Distributions fHeadNoteChangeFlags |= kIOPMNotDone;
7911*1031c584SApple OSS Distributions // and we're done
7912*1031c584SApple OSS Distributions OurChangeFinish();
7913*1031c584SApple OSS Distributions } else {
7914*1031c584SApple OSS Distributions // yes, we can continue
7915*1031c584SApple OSS Distributions OurChangeTellPriorityClientsPowerDown();
7916*1031c584SApple OSS Distributions }
7917*1031c584SApple OSS Distributions break;
7918*1031c584SApple OSS Distributions
7919*1031c584SApple OSS Distributions case kIOPM_OurChangeNotifyInterestedDriversWillChange:
7920*1031c584SApple OSS Distributions OurChangeNotifyInterestedDriversWillChange();
7921*1031c584SApple OSS Distributions break;
7922*1031c584SApple OSS Distributions
7923*1031c584SApple OSS Distributions case kIOPM_OurChangeSetPowerState:
7924*1031c584SApple OSS Distributions OurChangeSetPowerState();
7925*1031c584SApple OSS Distributions break;
7926*1031c584SApple OSS Distributions
7927*1031c584SApple OSS Distributions case kIOPM_OurChangeWaitForPowerSettle:
7928*1031c584SApple OSS Distributions OurChangeWaitForPowerSettle();
7929*1031c584SApple OSS Distributions break;
7930*1031c584SApple OSS Distributions
7931*1031c584SApple OSS Distributions case kIOPM_OurChangeNotifyInterestedDriversDidChange:
7932*1031c584SApple OSS Distributions OurChangeNotifyInterestedDriversDidChange();
7933*1031c584SApple OSS Distributions break;
7934*1031c584SApple OSS Distributions
7935*1031c584SApple OSS Distributions case kIOPM_OurChangeTellCapabilityDidChange:
7936*1031c584SApple OSS Distributions OurChangeTellCapabilityDidChange();
7937*1031c584SApple OSS Distributions break;
7938*1031c584SApple OSS Distributions
7939*1031c584SApple OSS Distributions case kIOPM_OurChangeFinish:
7940*1031c584SApple OSS Distributions OurChangeFinish();
7941*1031c584SApple OSS Distributions break;
7942*1031c584SApple OSS Distributions
7943*1031c584SApple OSS Distributions case kIOPM_ParentChangeTellPriorityClientsPowerDown:
7944*1031c584SApple OSS Distributions ParentChangeTellPriorityClientsPowerDown();
7945*1031c584SApple OSS Distributions break;
7946*1031c584SApple OSS Distributions
7947*1031c584SApple OSS Distributions case kIOPM_ParentChangeNotifyInterestedDriversWillChange:
7948*1031c584SApple OSS Distributions ParentChangeNotifyInterestedDriversWillChange();
7949*1031c584SApple OSS Distributions break;
7950*1031c584SApple OSS Distributions
7951*1031c584SApple OSS Distributions case kIOPM_ParentChangeSetPowerState:
7952*1031c584SApple OSS Distributions ParentChangeSetPowerState();
7953*1031c584SApple OSS Distributions break;
7954*1031c584SApple OSS Distributions
7955*1031c584SApple OSS Distributions case kIOPM_ParentChangeWaitForPowerSettle:
7956*1031c584SApple OSS Distributions ParentChangeWaitForPowerSettle();
7957*1031c584SApple OSS Distributions break;
7958*1031c584SApple OSS Distributions
7959*1031c584SApple OSS Distributions case kIOPM_ParentChangeNotifyInterestedDriversDidChange:
7960*1031c584SApple OSS Distributions ParentChangeNotifyInterestedDriversDidChange();
7961*1031c584SApple OSS Distributions break;
7962*1031c584SApple OSS Distributions
7963*1031c584SApple OSS Distributions case kIOPM_ParentChangeTellCapabilityDidChange:
7964*1031c584SApple OSS Distributions ParentChangeTellCapabilityDidChange();
7965*1031c584SApple OSS Distributions break;
7966*1031c584SApple OSS Distributions
7967*1031c584SApple OSS Distributions case kIOPM_ParentChangeAcknowledgePowerChange:
7968*1031c584SApple OSS Distributions ParentChangeAcknowledgePowerChange();
7969*1031c584SApple OSS Distributions break;
7970*1031c584SApple OSS Distributions
7971*1031c584SApple OSS Distributions case kIOPM_DriverThreadCallDone:
7972*1031c584SApple OSS Distributions switch (fDriverCallReason) {
7973*1031c584SApple OSS Distributions case kDriverCallInformPreChange:
7974*1031c584SApple OSS Distributions case kDriverCallInformPostChange:
7975*1031c584SApple OSS Distributions notifyInterestedDriversDone();
7976*1031c584SApple OSS Distributions break;
7977*1031c584SApple OSS Distributions case kDriverCallSetPowerState:
7978*1031c584SApple OSS Distributions notifyControllingDriverDone();
7979*1031c584SApple OSS Distributions break;
7980*1031c584SApple OSS Distributions case kRootDomainInformPreChange:
7981*1031c584SApple OSS Distributions notifyRootDomainDone();
7982*1031c584SApple OSS Distributions break;
7983*1031c584SApple OSS Distributions default:
7984*1031c584SApple OSS Distributions panic("%s: bad call reason %x",
7985*1031c584SApple OSS Distributions getName(), fDriverCallReason);
7986*1031c584SApple OSS Distributions }
7987*1031c584SApple OSS Distributions break;
7988*1031c584SApple OSS Distributions
7989*1031c584SApple OSS Distributions case kIOPM_NotifyChildrenOrdered:
7990*1031c584SApple OSS Distributions notifyChildrenOrdered();
7991*1031c584SApple OSS Distributions break;
7992*1031c584SApple OSS Distributions
7993*1031c584SApple OSS Distributions case kIOPM_NotifyChildrenDelayed:
7994*1031c584SApple OSS Distributions notifyChildrenDelayed();
7995*1031c584SApple OSS Distributions break;
7996*1031c584SApple OSS Distributions
7997*1031c584SApple OSS Distributions case kIOPM_NotifyChildrenStart:
7998*1031c584SApple OSS Distributions // pop notifyAll() state saved by notifyInterestedDriversDone()
7999*1031c584SApple OSS Distributions MS_POP();
8000*1031c584SApple OSS Distributions notifyRootDomain();
8001*1031c584SApple OSS Distributions break;
8002*1031c584SApple OSS Distributions
8003*1031c584SApple OSS Distributions case kIOPM_SyncTellClientsPowerDown:
8004*1031c584SApple OSS Distributions // Root domain might self cancel due to assertions.
8005*1031c584SApple OSS Distributions if (IS_ROOT_DOMAIN) {
8006*1031c584SApple OSS Distributions bool cancel = (bool) fDoNotPowerDown;
8007*1031c584SApple OSS Distributions getPMRootDomain()->askChangeDownDone(
8008*1031c584SApple OSS Distributions &fHeadNoteChangeFlags, &cancel);
8009*1031c584SApple OSS Distributions fDoNotPowerDown = cancel;
8010*1031c584SApple OSS Distributions }
8011*1031c584SApple OSS Distributions if (!fDoNotPowerDown) {
8012*1031c584SApple OSS Distributions fMachineState = kIOPM_SyncTellPriorityClientsPowerDown;
8013*1031c584SApple OSS Distributions fOutOfBandParameter = kNotifyApps;
8014*1031c584SApple OSS Distributions tellChangeDown(fHeadNotePowerState);
8015*1031c584SApple OSS Distributions } else {
8016*1031c584SApple OSS Distributions // Cancelled by IOPMrootDomain::askChangeDownDone() or
8017*1031c584SApple OSS Distributions // askChangeDown/kNotifyApps
8018*1031c584SApple OSS Distributions OUR_PMLog(kPMLogIdleCancel, (uintptr_t) this, fMachineState);
8019*1031c584SApple OSS Distributions PM_ERROR("%s: idle cancel, state %u\n", fName, fMachineState);
8020*1031c584SApple OSS Distributions #if DEVELOPMENT || DEBUG
8021*1031c584SApple OSS Distributions record_system_event(SYSTEM_EVENT_TYPE_INFO,
8022*1031c584SApple OSS Distributions SYSTEM_EVENT_SUBSYSTEM_PMRD,
8023*1031c584SApple OSS Distributions "Idle Sleep", "%s idle cancel, state %u", fName, fMachineState
8024*1031c584SApple OSS Distributions );
8025*1031c584SApple OSS Distributions #endif /* DEVELOPMENT || DEBUG */
8026*1031c584SApple OSS Distributions tellNoChangeDown(fHeadNotePowerState);
8027*1031c584SApple OSS Distributions fHeadNoteChangeFlags |= kIOPMNotDone;
8028*1031c584SApple OSS Distributions OurChangeFinish();
8029*1031c584SApple OSS Distributions }
8030*1031c584SApple OSS Distributions break;
8031*1031c584SApple OSS Distributions
8032*1031c584SApple OSS Distributions case kIOPM_SyncTellPriorityClientsPowerDown:
8033*1031c584SApple OSS Distributions // PMRD: tellChangeDown/kNotifyApps done, was it cancelled?
8034*1031c584SApple OSS Distributions if (!fDoNotPowerDown) {
8035*1031c584SApple OSS Distributions fMachineState = kIOPM_SyncNotifyWillChange;
8036*1031c584SApple OSS Distributions fOutOfBandParameter = kNotifyPriority;
8037*1031c584SApple OSS Distributions tellChangeDown(fHeadNotePowerState);
8038*1031c584SApple OSS Distributions } else {
8039*1031c584SApple OSS Distributions OUR_PMLog(kPMLogIdleCancel, (uintptr_t) this, fMachineState);
8040*1031c584SApple OSS Distributions PM_ERROR("%s: idle revert, state %u\n", fName, fMachineState);
8041*1031c584SApple OSS Distributions tellChangeUp(fCurrentPowerState);
8042*1031c584SApple OSS Distributions fHeadNoteChangeFlags |= kIOPMNotDone;
8043*1031c584SApple OSS Distributions OurChangeFinish();
8044*1031c584SApple OSS Distributions }
8045*1031c584SApple OSS Distributions break;
8046*1031c584SApple OSS Distributions
8047*1031c584SApple OSS Distributions case kIOPM_SyncNotifyWillChange:
8048*1031c584SApple OSS Distributions if (kIOPMSyncNoChildNotify & fHeadNoteChangeFlags) {
8049*1031c584SApple OSS Distributions fMachineState = kIOPM_SyncFinish;
8050*1031c584SApple OSS Distributions continue;
8051*1031c584SApple OSS Distributions }
8052*1031c584SApple OSS Distributions fMachineState = kIOPM_SyncNotifyDidChange;
8053*1031c584SApple OSS Distributions fDriverCallReason = kDriverCallInformPreChange;
8054*1031c584SApple OSS Distributions notifyChildren();
8055*1031c584SApple OSS Distributions break;
8056*1031c584SApple OSS Distributions
8057*1031c584SApple OSS Distributions case kIOPM_SyncNotifyDidChange:
8058*1031c584SApple OSS Distributions fIsPreChange = false;
8059*1031c584SApple OSS Distributions
8060*1031c584SApple OSS Distributions if (fHeadNoteChangeFlags & kIOPMParentInitiated) {
8061*1031c584SApple OSS Distributions fMachineState = kIOPM_SyncFinish;
8062*1031c584SApple OSS Distributions } else {
8063*1031c584SApple OSS Distributions assert(IS_ROOT_DOMAIN);
8064*1031c584SApple OSS Distributions fMachineState = kIOPM_SyncTellCapabilityDidChange;
8065*1031c584SApple OSS Distributions }
8066*1031c584SApple OSS Distributions
8067*1031c584SApple OSS Distributions fDriverCallReason = kDriverCallInformPostChange;
8068*1031c584SApple OSS Distributions notifyChildren();
8069*1031c584SApple OSS Distributions break;
8070*1031c584SApple OSS Distributions
8071*1031c584SApple OSS Distributions case kIOPM_SyncTellCapabilityDidChange:
8072*1031c584SApple OSS Distributions tellSystemCapabilityChange( kIOPM_SyncFinish );
8073*1031c584SApple OSS Distributions break;
8074*1031c584SApple OSS Distributions
8075*1031c584SApple OSS Distributions case kIOPM_SyncFinish:
8076*1031c584SApple OSS Distributions if (fHeadNoteChangeFlags & kIOPMParentInitiated) {
8077*1031c584SApple OSS Distributions ParentChangeAcknowledgePowerChange();
8078*1031c584SApple OSS Distributions } else {
8079*1031c584SApple OSS Distributions OurChangeFinish();
8080*1031c584SApple OSS Distributions }
8081*1031c584SApple OSS Distributions break;
8082*1031c584SApple OSS Distributions
8083*1031c584SApple OSS Distributions case kIOPM_TellCapabilityChangeDone:
8084*1031c584SApple OSS Distributions if (fIsPreChange) {
8085*1031c584SApple OSS Distributions if (fOutOfBandParameter == kNotifyCapabilityChangePriority) {
8086*1031c584SApple OSS Distributions MS_POP(); // MS passed to tellSystemCapabilityChange()
8087*1031c584SApple OSS Distributions continue;
8088*1031c584SApple OSS Distributions }
8089*1031c584SApple OSS Distributions fOutOfBandParameter = kNotifyCapabilityChangePriority;
8090*1031c584SApple OSS Distributions } else {
8091*1031c584SApple OSS Distributions if (fOutOfBandParameter == kNotifyCapabilityChangeApps) {
8092*1031c584SApple OSS Distributions MS_POP(); // MS passed to tellSystemCapabilityChange()
8093*1031c584SApple OSS Distributions continue;
8094*1031c584SApple OSS Distributions }
8095*1031c584SApple OSS Distributions fOutOfBandParameter = kNotifyCapabilityChangeApps;
8096*1031c584SApple OSS Distributions }
8097*1031c584SApple OSS Distributions tellClientsWithResponse( fOutOfBandMessage );
8098*1031c584SApple OSS Distributions break;
8099*1031c584SApple OSS Distributions
8100*1031c584SApple OSS Distributions default:
8101*1031c584SApple OSS Distributions panic("PMWorkQueueInvoke: unknown machine state %x",
8102*1031c584SApple OSS Distributions fMachineState);
8103*1031c584SApple OSS Distributions }
8104*1031c584SApple OSS Distributions
8105*1031c584SApple OSS Distributions gIOPMRequest = NULL;
8106*1031c584SApple OSS Distributions
8107*1031c584SApple OSS Distributions if (fMachineState == kIOPM_Finished) {
8108*1031c584SApple OSS Distributions stop_watchdog_timer();
8109*1031c584SApple OSS Distributions done = true;
8110*1031c584SApple OSS Distributions break;
8111*1031c584SApple OSS Distributions }
8112*1031c584SApple OSS Distributions }
8113*1031c584SApple OSS Distributions
8114*1031c584SApple OSS Distributions return done;
8115*1031c584SApple OSS Distributions }
8116*1031c584SApple OSS Distributions
8117*1031c584SApple OSS Distributions //*********************************************************************************
8118*1031c584SApple OSS Distributions // [private] executePMRequest
8119*1031c584SApple OSS Distributions //*********************************************************************************
8120*1031c584SApple OSS Distributions
8121*1031c584SApple OSS Distributions void
executePMRequest(IOPMRequest * request)8122*1031c584SApple OSS Distributions IOService::executePMRequest( IOPMRequest * request )
8123*1031c584SApple OSS Distributions {
8124*1031c584SApple OSS Distributions assert( kIOPM_Finished == fMachineState );
8125*1031c584SApple OSS Distributions
8126*1031c584SApple OSS Distributions switch (request->getType()) {
8127*1031c584SApple OSS Distributions case kIOPMRequestTypePMStop:
8128*1031c584SApple OSS Distributions handlePMstop( request );
8129*1031c584SApple OSS Distributions break;
8130*1031c584SApple OSS Distributions
8131*1031c584SApple OSS Distributions case kIOPMRequestTypeAddPowerChild1:
8132*1031c584SApple OSS Distributions addPowerChild1( request );
8133*1031c584SApple OSS Distributions break;
8134*1031c584SApple OSS Distributions
8135*1031c584SApple OSS Distributions case kIOPMRequestTypeAddPowerChild2:
8136*1031c584SApple OSS Distributions addPowerChild2( request );
8137*1031c584SApple OSS Distributions break;
8138*1031c584SApple OSS Distributions
8139*1031c584SApple OSS Distributions case kIOPMRequestTypeAddPowerChild3:
8140*1031c584SApple OSS Distributions addPowerChild3( request );
8141*1031c584SApple OSS Distributions break;
8142*1031c584SApple OSS Distributions
8143*1031c584SApple OSS Distributions case kIOPMRequestTypeRegisterPowerDriver:
8144*1031c584SApple OSS Distributions handleRegisterPowerDriver( request );
8145*1031c584SApple OSS Distributions break;
8146*1031c584SApple OSS Distributions
8147*1031c584SApple OSS Distributions case kIOPMRequestTypeAdjustPowerState:
8148*1031c584SApple OSS Distributions fAdjustPowerScheduled = false;
8149*1031c584SApple OSS Distributions adjustPowerState();
8150*1031c584SApple OSS Distributions break;
8151*1031c584SApple OSS Distributions
8152*1031c584SApple OSS Distributions case kIOPMRequestTypePowerDomainWillChange:
8153*1031c584SApple OSS Distributions handlePowerDomainWillChangeTo( request );
8154*1031c584SApple OSS Distributions break;
8155*1031c584SApple OSS Distributions
8156*1031c584SApple OSS Distributions case kIOPMRequestTypePowerDomainDidChange:
8157*1031c584SApple OSS Distributions handlePowerDomainDidChangeTo( request );
8158*1031c584SApple OSS Distributions break;
8159*1031c584SApple OSS Distributions
8160*1031c584SApple OSS Distributions case kIOPMRequestTypeRequestPowerState:
8161*1031c584SApple OSS Distributions case kIOPMRequestTypeRequestPowerStateOverride:
8162*1031c584SApple OSS Distributions handleRequestPowerState( request );
8163*1031c584SApple OSS Distributions break;
8164*1031c584SApple OSS Distributions
8165*1031c584SApple OSS Distributions case kIOPMRequestTypePowerOverrideOnPriv:
8166*1031c584SApple OSS Distributions case kIOPMRequestTypePowerOverrideOffPriv:
8167*1031c584SApple OSS Distributions handlePowerOverrideChanged( request );
8168*1031c584SApple OSS Distributions break;
8169*1031c584SApple OSS Distributions
8170*1031c584SApple OSS Distributions case kIOPMRequestTypeActivityTickle:
8171*1031c584SApple OSS Distributions handleActivityTickle( request );
8172*1031c584SApple OSS Distributions break;
8173*1031c584SApple OSS Distributions
8174*1031c584SApple OSS Distributions case kIOPMRequestTypeSynchronizePowerTree:
8175*1031c584SApple OSS Distributions handleSynchronizePowerTree( request );
8176*1031c584SApple OSS Distributions break;
8177*1031c584SApple OSS Distributions
8178*1031c584SApple OSS Distributions case kIOPMRequestTypeSetIdleTimerPeriod:
8179*1031c584SApple OSS Distributions {
8180*1031c584SApple OSS Distributions fIdleTimerPeriod = (typeof(fIdleTimerPeriod))(uintptr_t) request->fArg0;
8181*1031c584SApple OSS Distributions fNextIdleTimerPeriod = fIdleTimerPeriod;
8182*1031c584SApple OSS Distributions if ((false == fLockedFlags.PMStop) && (fIdleTimerPeriod > 0)) {
8183*1031c584SApple OSS Distributions restartIdleTimer();
8184*1031c584SApple OSS Distributions }
8185*1031c584SApple OSS Distributions }
8186*1031c584SApple OSS Distributions break;
8187*1031c584SApple OSS Distributions
8188*1031c584SApple OSS Distributions case kIOPMRequestTypeIgnoreIdleTimer:
8189*1031c584SApple OSS Distributions fIdleTimerIgnored = request->fArg0 ? 1 : 0;
8190*1031c584SApple OSS Distributions break;
8191*1031c584SApple OSS Distributions
8192*1031c584SApple OSS Distributions case kIOPMRequestTypeQuiescePowerTree:
8193*1031c584SApple OSS Distributions gIOPMWorkQueue->finishQuiesceRequest(request);
8194*1031c584SApple OSS Distributions break;
8195*1031c584SApple OSS Distributions
8196*1031c584SApple OSS Distributions case kIOPMRequestTypeDeferredActivityTickle:
8197*1031c584SApple OSS Distributions handleDeferredActivityTickle(request);
8198*1031c584SApple OSS Distributions break;
8199*1031c584SApple OSS Distributions
8200*1031c584SApple OSS Distributions default:
8201*1031c584SApple OSS Distributions panic("executePMRequest: unknown request type %x", request->getType());
8202*1031c584SApple OSS Distributions }
8203*1031c584SApple OSS Distributions }
8204*1031c584SApple OSS Distributions
8205*1031c584SApple OSS Distributions //*********************************************************************************
8206*1031c584SApple OSS Distributions // [private] actionPMReplyQueue
8207*1031c584SApple OSS Distributions //
8208*1031c584SApple OSS Distributions // IOPMRequestQueue::checkForWork() passing a reply-type request to the
8209*1031c584SApple OSS Distributions // request target.
8210*1031c584SApple OSS Distributions //*********************************************************************************
8211*1031c584SApple OSS Distributions
8212*1031c584SApple OSS Distributions bool
actionPMReplyQueue(IOPMRequest * request,IOPMRequestQueue * queue)8213*1031c584SApple OSS Distributions IOService::actionPMReplyQueue( IOPMRequest * request, IOPMRequestQueue * queue )
8214*1031c584SApple OSS Distributions {
8215*1031c584SApple OSS Distributions bool more = false;
8216*1031c584SApple OSS Distributions
8217*1031c584SApple OSS Distributions assert( request && queue );
8218*1031c584SApple OSS Distributions assert( request->isReplyType());
8219*1031c584SApple OSS Distributions
8220*1031c584SApple OSS Distributions PM_LOG1("[A %02x] %p [%p %s] state %d\n",
8221*1031c584SApple OSS Distributions request->getType(), OBFUSCATE(request),
8222*1031c584SApple OSS Distributions OBFUSCATE(this), getName(), fMachineState);
8223*1031c584SApple OSS Distributions
8224*1031c584SApple OSS Distributions switch (request->getType()) {
8225*1031c584SApple OSS Distributions case kIOPMRequestTypeAllowPowerChange:
8226*1031c584SApple OSS Distributions case kIOPMRequestTypeCancelPowerChange:
8227*1031c584SApple OSS Distributions // Check if we are expecting this response.
8228*1031c584SApple OSS Distributions if (responseValid((uint32_t)(uintptr_t) request->fArg0,
8229*1031c584SApple OSS Distributions (int)(uintptr_t) request->fArg1)) {
8230*1031c584SApple OSS Distributions if (kIOPMRequestTypeCancelPowerChange == request->getType()) {
8231*1031c584SApple OSS Distributions // Clients are not allowed to cancel when kIOPMSkipAskPowerDown
8232*1031c584SApple OSS Distributions // flag is set. Only root domain will set this flag.
8233*1031c584SApple OSS Distributions // However, there is one exception to this rule. User-space PM
8234*1031c584SApple OSS Distributions // policy may choose to cancel sleep even after all clients have
8235*1031c584SApple OSS Distributions // been notified that we will lower power.
8236*1031c584SApple OSS Distributions
8237*1031c584SApple OSS Distributions if ((fMachineState == kIOPM_OurChangeTellUserPMPolicyPowerDown)
8238*1031c584SApple OSS Distributions || (fMachineState == kIOPM_OurChangeTellPriorityClientsPowerDown)
8239*1031c584SApple OSS Distributions || ((fHeadNoteChangeFlags & kIOPMSkipAskPowerDown) == 0)) {
8240*1031c584SApple OSS Distributions fDoNotPowerDown = true;
8241*1031c584SApple OSS Distributions
8242*1031c584SApple OSS Distributions OSString * name = (OSString *) request->fArg2;
8243*1031c584SApple OSS Distributions getPMRootDomain()->pmStatsRecordApplicationResponse(
8244*1031c584SApple OSS Distributions gIOPMStatsResponseCancel,
8245*1031c584SApple OSS Distributions name ? name->getCStringNoCopy() : "", 0,
8246*1031c584SApple OSS Distributions 0, (int)(uintptr_t) request->fArg1, NULL);
8247*1031c584SApple OSS Distributions }
8248*1031c584SApple OSS Distributions }
8249*1031c584SApple OSS Distributions
8250*1031c584SApple OSS Distributions if (checkForDone()) {
8251*1031c584SApple OSS Distributions stop_ack_timer();
8252*1031c584SApple OSS Distributions cleanClientResponses(false);
8253*1031c584SApple OSS Distributions more = true;
8254*1031c584SApple OSS Distributions }
8255*1031c584SApple OSS Distributions }
8256*1031c584SApple OSS Distributions // OSString containing app name in Arg2 must be released.
8257*1031c584SApple OSS Distributions if (request->getType() == kIOPMRequestTypeCancelPowerChange) {
8258*1031c584SApple OSS Distributions OSObject * obj = (OSObject *) request->fArg2;
8259*1031c584SApple OSS Distributions if (obj) {
8260*1031c584SApple OSS Distributions obj->release();
8261*1031c584SApple OSS Distributions }
8262*1031c584SApple OSS Distributions }
8263*1031c584SApple OSS Distributions break;
8264*1031c584SApple OSS Distributions
8265*1031c584SApple OSS Distributions case kIOPMRequestTypeAckPowerChange:
8266*1031c584SApple OSS Distributions more = handleAcknowledgePowerChange( request );
8267*1031c584SApple OSS Distributions break;
8268*1031c584SApple OSS Distributions
8269*1031c584SApple OSS Distributions case kIOPMRequestTypeAckSetPowerState:
8270*1031c584SApple OSS Distributions more = handleAcknowledgeSetPowerState( request );
8271*1031c584SApple OSS Distributions break;
8272*1031c584SApple OSS Distributions
8273*1031c584SApple OSS Distributions case kIOPMRequestTypeInterestChanged:
8274*1031c584SApple OSS Distributions handleInterestChanged( request );
8275*1031c584SApple OSS Distributions more = true;
8276*1031c584SApple OSS Distributions break;
8277*1031c584SApple OSS Distributions
8278*1031c584SApple OSS Distributions case kIOPMRequestTypeIdleCancel:
8279*1031c584SApple OSS Distributions if ((fMachineState == kIOPM_OurChangeTellClientsPowerDown)
8280*1031c584SApple OSS Distributions || (fMachineState == kIOPM_OurChangeTellUserPMPolicyPowerDown)
8281*1031c584SApple OSS Distributions || (fMachineState == kIOPM_OurChangeTellPriorityClientsPowerDown)
8282*1031c584SApple OSS Distributions || (fMachineState == kIOPM_SyncTellClientsPowerDown)
8283*1031c584SApple OSS Distributions || (fMachineState == kIOPM_SyncTellPriorityClientsPowerDown)) {
8284*1031c584SApple OSS Distributions OUR_PMLog(kPMLogIdleCancel, (uintptr_t) this, fMachineState);
8285*1031c584SApple OSS Distributions PM_LOG2("%s: cancel from machine state %d\n",
8286*1031c584SApple OSS Distributions getName(), fMachineState);
8287*1031c584SApple OSS Distributions fDoNotPowerDown = true;
8288*1031c584SApple OSS Distributions // Stop waiting for app replys.
8289*1031c584SApple OSS Distributions if ((fMachineState == kIOPM_OurChangeTellPriorityClientsPowerDown) ||
8290*1031c584SApple OSS Distributions (fMachineState == kIOPM_OurChangeTellUserPMPolicyPowerDown) ||
8291*1031c584SApple OSS Distributions (fMachineState == kIOPM_SyncTellPriorityClientsPowerDown) ||
8292*1031c584SApple OSS Distributions (fMachineState == kIOPM_SyncTellClientsPowerDown)) {
8293*1031c584SApple OSS Distributions cleanClientResponses(false);
8294*1031c584SApple OSS Distributions }
8295*1031c584SApple OSS Distributions more = true;
8296*1031c584SApple OSS Distributions }
8297*1031c584SApple OSS Distributions break;
8298*1031c584SApple OSS Distributions
8299*1031c584SApple OSS Distributions case kIOPMRequestTypeChildNotifyDelayCancel:
8300*1031c584SApple OSS Distributions if (fMachineState == kIOPM_NotifyChildrenDelayed) {
8301*1031c584SApple OSS Distributions PM_LOG2("%s: delay notify cancelled\n", getName());
8302*1031c584SApple OSS Distributions notifyChildrenDelayed();
8303*1031c584SApple OSS Distributions }
8304*1031c584SApple OSS Distributions break;
8305*1031c584SApple OSS Distributions
8306*1031c584SApple OSS Distributions default:
8307*1031c584SApple OSS Distributions panic("PMReplyQueue: unknown reply type %x", request->getType());
8308*1031c584SApple OSS Distributions }
8309*1031c584SApple OSS Distributions
8310*1031c584SApple OSS Distributions more |= gIOPMCompletionQueue->queuePMRequest(request);
8311*1031c584SApple OSS Distributions if (more) {
8312*1031c584SApple OSS Distributions gIOPMWorkQueue->incrementProducerCount();
8313*1031c584SApple OSS Distributions }
8314*1031c584SApple OSS Distributions
8315*1031c584SApple OSS Distributions return more;
8316*1031c584SApple OSS Distributions }
8317*1031c584SApple OSS Distributions
8318*1031c584SApple OSS Distributions //*********************************************************************************
8319*1031c584SApple OSS Distributions // [private] assertPMDriverCall / deassertPMDriverCall
8320*1031c584SApple OSS Distributions //*********************************************************************************
8321*1031c584SApple OSS Distributions
8322*1031c584SApple OSS Distributions bool
assertPMDriverCall(IOPMDriverCallEntry * entry,IOOptionBits method,const IOPMinformee * inform,IOOptionBits options)8323*1031c584SApple OSS Distributions IOService::assertPMDriverCall(
8324*1031c584SApple OSS Distributions IOPMDriverCallEntry * entry,
8325*1031c584SApple OSS Distributions IOOptionBits method,
8326*1031c584SApple OSS Distributions const IOPMinformee * inform,
8327*1031c584SApple OSS Distributions IOOptionBits options )
8328*1031c584SApple OSS Distributions {
8329*1031c584SApple OSS Distributions IOService * target = NULL;
8330*1031c584SApple OSS Distributions bool ok = false;
8331*1031c584SApple OSS Distributions
8332*1031c584SApple OSS Distributions if (!initialized) {
8333*1031c584SApple OSS Distributions return false;
8334*1031c584SApple OSS Distributions }
8335*1031c584SApple OSS Distributions
8336*1031c584SApple OSS Distributions PM_LOCK();
8337*1031c584SApple OSS Distributions
8338*1031c584SApple OSS Distributions if (fLockedFlags.PMStop) {
8339*1031c584SApple OSS Distributions goto fail;
8340*1031c584SApple OSS Distributions }
8341*1031c584SApple OSS Distributions
8342*1031c584SApple OSS Distributions if (((options & kIOPMDriverCallNoInactiveCheck) == 0) && isInactive()) {
8343*1031c584SApple OSS Distributions goto fail;
8344*1031c584SApple OSS Distributions }
8345*1031c584SApple OSS Distributions
8346*1031c584SApple OSS Distributions if (inform) {
8347*1031c584SApple OSS Distributions if (!inform->active) {
8348*1031c584SApple OSS Distributions goto fail;
8349*1031c584SApple OSS Distributions }
8350*1031c584SApple OSS Distributions target = inform->whatObject;
8351*1031c584SApple OSS Distributions if (target->isInactive()) {
8352*1031c584SApple OSS Distributions goto fail;
8353*1031c584SApple OSS Distributions }
8354*1031c584SApple OSS Distributions }
8355*1031c584SApple OSS Distributions
8356*1031c584SApple OSS Distributions // Record calling address for sleep failure diagnostics
8357*1031c584SApple OSS Distributions switch (method) {
8358*1031c584SApple OSS Distributions case kIOPMDriverCallMethodSetPowerState:
8359*1031c584SApple OSS Distributions entry->callMethod = OSMemberFunctionCast(const void *, fControllingDriver, &IOService::setPowerState);
8360*1031c584SApple OSS Distributions break;
8361*1031c584SApple OSS Distributions case kIOPMDriverCallMethodWillChange:
8362*1031c584SApple OSS Distributions entry->callMethod = OSMemberFunctionCast(const void *, target, &IOService::powerStateWillChangeTo);
8363*1031c584SApple OSS Distributions break;
8364*1031c584SApple OSS Distributions case kIOPMDriverCallMethodDidChange:
8365*1031c584SApple OSS Distributions entry->callMethod = OSMemberFunctionCast(const void *, target, &IOService::powerStateDidChangeTo);
8366*1031c584SApple OSS Distributions break;
8367*1031c584SApple OSS Distributions case kIOPMDriverCallMethodUnknown:
8368*1031c584SApple OSS Distributions case kIOPMDriverCallMethodSetAggressive:
8369*1031c584SApple OSS Distributions default:
8370*1031c584SApple OSS Distributions entry->callMethod = NULL;
8371*1031c584SApple OSS Distributions break;
8372*1031c584SApple OSS Distributions }
8373*1031c584SApple OSS Distributions
8374*1031c584SApple OSS Distributions entry->thread = current_thread();
8375*1031c584SApple OSS Distributions entry->target = target;
8376*1031c584SApple OSS Distributions queue_enter(&fPMDriverCallQueue, entry, IOPMDriverCallEntry *, link);
8377*1031c584SApple OSS Distributions ok = true;
8378*1031c584SApple OSS Distributions
8379*1031c584SApple OSS Distributions fail:
8380*1031c584SApple OSS Distributions PM_UNLOCK();
8381*1031c584SApple OSS Distributions
8382*1031c584SApple OSS Distributions return ok;
8383*1031c584SApple OSS Distributions }
8384*1031c584SApple OSS Distributions
8385*1031c584SApple OSS Distributions void
deassertPMDriverCall(IOPMDriverCallEntry * entry)8386*1031c584SApple OSS Distributions IOService::deassertPMDriverCall( IOPMDriverCallEntry * entry )
8387*1031c584SApple OSS Distributions {
8388*1031c584SApple OSS Distributions bool wakeup = false;
8389*1031c584SApple OSS Distributions
8390*1031c584SApple OSS Distributions PM_LOCK();
8391*1031c584SApple OSS Distributions
8392*1031c584SApple OSS Distributions assert( !queue_empty(&fPMDriverCallQueue));
8393*1031c584SApple OSS Distributions queue_remove(&fPMDriverCallQueue, entry, IOPMDriverCallEntry *, link);
8394*1031c584SApple OSS Distributions if (fLockedFlags.PMDriverCallWait) {
8395*1031c584SApple OSS Distributions wakeup = true;
8396*1031c584SApple OSS Distributions }
8397*1031c584SApple OSS Distributions
8398*1031c584SApple OSS Distributions PM_UNLOCK();
8399*1031c584SApple OSS Distributions
8400*1031c584SApple OSS Distributions if (wakeup) {
8401*1031c584SApple OSS Distributions PM_LOCK_WAKEUP(&fPMDriverCallQueue);
8402*1031c584SApple OSS Distributions }
8403*1031c584SApple OSS Distributions }
8404*1031c584SApple OSS Distributions
8405*1031c584SApple OSS Distributions bool
getBlockingDriverCall(thread_t * thread,const void ** callMethod)8406*1031c584SApple OSS Distributions IOService::getBlockingDriverCall(thread_t *thread, const void **callMethod)
8407*1031c584SApple OSS Distributions {
8408*1031c584SApple OSS Distributions const IOPMDriverCallEntry * entry = NULL;
8409*1031c584SApple OSS Distributions bool blocked = false;
8410*1031c584SApple OSS Distributions
8411*1031c584SApple OSS Distributions if (!initialized) {
8412*1031c584SApple OSS Distributions return false;
8413*1031c584SApple OSS Distributions }
8414*1031c584SApple OSS Distributions
8415*1031c584SApple OSS Distributions if (current_thread() != gIOPMWatchDogThread) {
8416*1031c584SApple OSS Distributions // Meant to be accessed only from watchdog thread
8417*1031c584SApple OSS Distributions return false;
8418*1031c584SApple OSS Distributions }
8419*1031c584SApple OSS Distributions
8420*1031c584SApple OSS Distributions PM_LOCK();
8421*1031c584SApple OSS Distributions entry = qe_queue_first(&fPMDriverCallQueue, IOPMDriverCallEntry, link);
8422*1031c584SApple OSS Distributions if (entry) {
8423*1031c584SApple OSS Distributions *thread = entry->thread;
8424*1031c584SApple OSS Distributions *callMethod = entry->callMethod;
8425*1031c584SApple OSS Distributions blocked = true;
8426*1031c584SApple OSS Distributions }
8427*1031c584SApple OSS Distributions PM_UNLOCK();
8428*1031c584SApple OSS Distributions
8429*1031c584SApple OSS Distributions return blocked;
8430*1031c584SApple OSS Distributions }
8431*1031c584SApple OSS Distributions
8432*1031c584SApple OSS Distributions
8433*1031c584SApple OSS Distributions void
waitForPMDriverCall(IOService * target)8434*1031c584SApple OSS Distributions IOService::waitForPMDriverCall( IOService * target )
8435*1031c584SApple OSS Distributions {
8436*1031c584SApple OSS Distributions const IOPMDriverCallEntry * entry;
8437*1031c584SApple OSS Distributions thread_t thread = current_thread();
8438*1031c584SApple OSS Distributions AbsoluteTime deadline;
8439*1031c584SApple OSS Distributions int waitResult;
8440*1031c584SApple OSS Distributions bool log = true;
8441*1031c584SApple OSS Distributions bool wait;
8442*1031c584SApple OSS Distributions
8443*1031c584SApple OSS Distributions do {
8444*1031c584SApple OSS Distributions wait = false;
8445*1031c584SApple OSS Distributions queue_iterate(&fPMDriverCallQueue, entry, const IOPMDriverCallEntry *, link)
8446*1031c584SApple OSS Distributions {
8447*1031c584SApple OSS Distributions // Target of interested driver call
8448*1031c584SApple OSS Distributions if (target && (target != entry->target)) {
8449*1031c584SApple OSS Distributions continue;
8450*1031c584SApple OSS Distributions }
8451*1031c584SApple OSS Distributions
8452*1031c584SApple OSS Distributions if (entry->thread == thread) {
8453*1031c584SApple OSS Distributions if (log) {
8454*1031c584SApple OSS Distributions PM_LOG("%s: %s(%s) on PM thread\n",
8455*1031c584SApple OSS Distributions fName, __FUNCTION__, target ? target->getName() : "");
8456*1031c584SApple OSS Distributions OSReportWithBacktrace("%s: %s(%s) on PM thread\n",
8457*1031c584SApple OSS Distributions fName, __FUNCTION__, target ? target->getName() : "");
8458*1031c584SApple OSS Distributions log = false;
8459*1031c584SApple OSS Distributions }
8460*1031c584SApple OSS Distributions continue;
8461*1031c584SApple OSS Distributions }
8462*1031c584SApple OSS Distributions
8463*1031c584SApple OSS Distributions wait = true;
8464*1031c584SApple OSS Distributions break;
8465*1031c584SApple OSS Distributions }
8466*1031c584SApple OSS Distributions
8467*1031c584SApple OSS Distributions if (wait) {
8468*1031c584SApple OSS Distributions fLockedFlags.PMDriverCallWait = true;
8469*1031c584SApple OSS Distributions clock_interval_to_deadline(15, kSecondScale, &deadline);
8470*1031c584SApple OSS Distributions waitResult = PM_LOCK_SLEEP(&fPMDriverCallQueue, deadline);
8471*1031c584SApple OSS Distributions fLockedFlags.PMDriverCallWait = false;
8472*1031c584SApple OSS Distributions if (THREAD_TIMED_OUT == waitResult) {
8473*1031c584SApple OSS Distributions PM_ERROR("%s: waitForPMDriverCall timeout\n", fName);
8474*1031c584SApple OSS Distributions wait = false;
8475*1031c584SApple OSS Distributions }
8476*1031c584SApple OSS Distributions }
8477*1031c584SApple OSS Distributions } while (wait);
8478*1031c584SApple OSS Distributions }
8479*1031c584SApple OSS Distributions
8480*1031c584SApple OSS Distributions //*********************************************************************************
8481*1031c584SApple OSS Distributions // [private] Debug helpers
8482*1031c584SApple OSS Distributions //*********************************************************************************
8483*1031c584SApple OSS Distributions
8484*1031c584SApple OSS Distributions const char *
getIOMessageString(uint32_t msg)8485*1031c584SApple OSS Distributions IOService::getIOMessageString( uint32_t msg )
8486*1031c584SApple OSS Distributions {
8487*1031c584SApple OSS Distributions #define MSG_ENTRY(x) {(int) x, #x}
8488*1031c584SApple OSS Distributions
8489*1031c584SApple OSS Distributions static const IONamedValue msgNames[] = {
8490*1031c584SApple OSS Distributions MSG_ENTRY( kIOMessageCanDevicePowerOff ),
8491*1031c584SApple OSS Distributions MSG_ENTRY( kIOMessageDeviceWillPowerOff ),
8492*1031c584SApple OSS Distributions MSG_ENTRY( kIOMessageDeviceWillNotPowerOff ),
8493*1031c584SApple OSS Distributions MSG_ENTRY( kIOMessageDeviceHasPoweredOn ),
8494*1031c584SApple OSS Distributions MSG_ENTRY( kIOMessageCanSystemPowerOff ),
8495*1031c584SApple OSS Distributions MSG_ENTRY( kIOMessageSystemWillPowerOff ),
8496*1031c584SApple OSS Distributions MSG_ENTRY( kIOMessageSystemWillNotPowerOff ),
8497*1031c584SApple OSS Distributions MSG_ENTRY( kIOMessageCanSystemSleep ),
8498*1031c584SApple OSS Distributions MSG_ENTRY( kIOMessageSystemWillSleep ),
8499*1031c584SApple OSS Distributions MSG_ENTRY( kIOMessageSystemWillNotSleep ),
8500*1031c584SApple OSS Distributions MSG_ENTRY( kIOMessageSystemHasPoweredOn ),
8501*1031c584SApple OSS Distributions MSG_ENTRY( kIOMessageSystemWillRestart ),
8502*1031c584SApple OSS Distributions MSG_ENTRY( kIOMessageSystemWillPowerOn ),
8503*1031c584SApple OSS Distributions MSG_ENTRY( kIOMessageSystemCapabilityChange ),
8504*1031c584SApple OSS Distributions MSG_ENTRY( kIOPMMessageLastCallBeforeSleep ),
8505*1031c584SApple OSS Distributions MSG_ENTRY( kIOMessageSystemPagingOff ),
8506*1031c584SApple OSS Distributions { 0, NULL }
8507*1031c584SApple OSS Distributions };
8508*1031c584SApple OSS Distributions
8509*1031c584SApple OSS Distributions return IOFindNameForValue(msg, msgNames);
8510*1031c584SApple OSS Distributions }
8511*1031c584SApple OSS Distributions
8512*1031c584SApple OSS Distributions static const char *
getNotificationPhaseString(uint32_t phase)8513*1031c584SApple OSS Distributions getNotificationPhaseString( uint32_t phase )
8514*1031c584SApple OSS Distributions {
8515*1031c584SApple OSS Distributions #define PHASE_ENTRY(x) {(int) x, #x}
8516*1031c584SApple OSS Distributions
8517*1031c584SApple OSS Distributions static const IONamedValue phaseNames[] = {
8518*1031c584SApple OSS Distributions PHASE_ENTRY( kNotifyApps ),
8519*1031c584SApple OSS Distributions PHASE_ENTRY( kNotifyPriority ),
8520*1031c584SApple OSS Distributions PHASE_ENTRY( kNotifyCapabilityChangeApps ),
8521*1031c584SApple OSS Distributions PHASE_ENTRY( kNotifyCapabilityChangePriority ),
8522*1031c584SApple OSS Distributions { 0, NULL }
8523*1031c584SApple OSS Distributions };
8524*1031c584SApple OSS Distributions
8525*1031c584SApple OSS Distributions return IOFindNameForValue(phase, phaseNames);
8526*1031c584SApple OSS Distributions }
8527*1031c584SApple OSS Distributions
8528*1031c584SApple OSS Distributions // MARK: -
8529*1031c584SApple OSS Distributions // MARK: IOPMRequest
8530*1031c584SApple OSS Distributions
8531*1031c584SApple OSS Distributions //*********************************************************************************
8532*1031c584SApple OSS Distributions // IOPMRequest Class
8533*1031c584SApple OSS Distributions //
8534*1031c584SApple OSS Distributions // Requests from PM clients, and also used for inter-object messaging within PM.
8535*1031c584SApple OSS Distributions //*********************************************************************************
8536*1031c584SApple OSS Distributions
8537*1031c584SApple OSS Distributions OSDefineMetaClassAndStructors( IOPMRequest, IOCommand );
8538*1031c584SApple OSS Distributions
8539*1031c584SApple OSS Distributions IOPMRequest *
create(void)8540*1031c584SApple OSS Distributions IOPMRequest::create( void )
8541*1031c584SApple OSS Distributions {
8542*1031c584SApple OSS Distributions IOPMRequest * me = OSTypeAlloc(IOPMRequest);
8543*1031c584SApple OSS Distributions if (me && !me->init(NULL, kIOPMRequestTypeInvalid)) {
8544*1031c584SApple OSS Distributions me->release();
8545*1031c584SApple OSS Distributions me = NULL;
8546*1031c584SApple OSS Distributions }
8547*1031c584SApple OSS Distributions return me;
8548*1031c584SApple OSS Distributions }
8549*1031c584SApple OSS Distributions
8550*1031c584SApple OSS Distributions bool
init(IOService * target,IOOptionBits type)8551*1031c584SApple OSS Distributions IOPMRequest::init( IOService * target, IOOptionBits type )
8552*1031c584SApple OSS Distributions {
8553*1031c584SApple OSS Distributions if (!IOCommand::init()) {
8554*1031c584SApple OSS Distributions return false;
8555*1031c584SApple OSS Distributions }
8556*1031c584SApple OSS Distributions
8557*1031c584SApple OSS Distributions fRequestType = type;
8558*1031c584SApple OSS Distributions fTarget = target;
8559*1031c584SApple OSS Distributions
8560*1031c584SApple OSS Distributions if (fTarget) {
8561*1031c584SApple OSS Distributions fTarget->retain();
8562*1031c584SApple OSS Distributions }
8563*1031c584SApple OSS Distributions
8564*1031c584SApple OSS Distributions // Root node and root domain requests does not prevent the power tree from
8565*1031c584SApple OSS Distributions // becoming quiescent.
8566*1031c584SApple OSS Distributions
8567*1031c584SApple OSS Distributions fIsQuiesceBlocker = ((fTarget != gIOPMRootNode) &&
8568*1031c584SApple OSS Distributions (fTarget != IOService::getPMRootDomain()));
8569*1031c584SApple OSS Distributions
8570*1031c584SApple OSS Distributions return true;
8571*1031c584SApple OSS Distributions }
8572*1031c584SApple OSS Distributions
8573*1031c584SApple OSS Distributions void
reset(void)8574*1031c584SApple OSS Distributions IOPMRequest::reset( void )
8575*1031c584SApple OSS Distributions {
8576*1031c584SApple OSS Distributions assert( fWorkWaitCount == 0 );
8577*1031c584SApple OSS Distributions assert( fFreeWaitCount == 0 );
8578*1031c584SApple OSS Distributions
8579*1031c584SApple OSS Distributions detachNextRequest();
8580*1031c584SApple OSS Distributions detachRootRequest();
8581*1031c584SApple OSS Distributions
8582*1031c584SApple OSS Distributions if (fCompletionAction && (fRequestType == kIOPMRequestTypeQuiescePowerTree)) {
8583*1031c584SApple OSS Distributions // Call the completion on PM work loop context
8584*1031c584SApple OSS Distributions fCompletionAction(fCompletionTarget, fCompletionParam);
8585*1031c584SApple OSS Distributions fCompletionAction = NULL;
8586*1031c584SApple OSS Distributions }
8587*1031c584SApple OSS Distributions
8588*1031c584SApple OSS Distributions fRequestType = kIOPMRequestTypeInvalid;
8589*1031c584SApple OSS Distributions
8590*1031c584SApple OSS Distributions if (fTarget) {
8591*1031c584SApple OSS Distributions fTarget->release();
8592*1031c584SApple OSS Distributions fTarget = NULL;
8593*1031c584SApple OSS Distributions }
8594*1031c584SApple OSS Distributions }
8595*1031c584SApple OSS Distributions
8596*1031c584SApple OSS Distributions bool
attachNextRequest(IOPMRequest * next)8597*1031c584SApple OSS Distributions IOPMRequest::attachNextRequest( IOPMRequest * next )
8598*1031c584SApple OSS Distributions {
8599*1031c584SApple OSS Distributions bool ok = false;
8600*1031c584SApple OSS Distributions
8601*1031c584SApple OSS Distributions if (!fRequestNext) {
8602*1031c584SApple OSS Distributions // Postpone the execution of the next request after
8603*1031c584SApple OSS Distributions // this request.
8604*1031c584SApple OSS Distributions fRequestNext = next;
8605*1031c584SApple OSS Distributions fRequestNext->fWorkWaitCount++;
8606*1031c584SApple OSS Distributions #if LOG_REQUEST_ATTACH
8607*1031c584SApple OSS Distributions PM_LOG("Attached next: %p [0x%x] -> %p [0x%x, %u] %s\n",
8608*1031c584SApple OSS Distributions OBFUSCATE(this), fRequestType, OBFUSCATE(fRequestNext),
8609*1031c584SApple OSS Distributions fRequestNext->fRequestType,
8610*1031c584SApple OSS Distributions (uint32_t) fRequestNext->fWorkWaitCount,
8611*1031c584SApple OSS Distributions fTarget->getName());
8612*1031c584SApple OSS Distributions #endif
8613*1031c584SApple OSS Distributions ok = true;
8614*1031c584SApple OSS Distributions }
8615*1031c584SApple OSS Distributions return ok;
8616*1031c584SApple OSS Distributions }
8617*1031c584SApple OSS Distributions
8618*1031c584SApple OSS Distributions bool
detachNextRequest(void)8619*1031c584SApple OSS Distributions IOPMRequest::detachNextRequest( void )
8620*1031c584SApple OSS Distributions {
8621*1031c584SApple OSS Distributions bool ok = false;
8622*1031c584SApple OSS Distributions
8623*1031c584SApple OSS Distributions if (fRequestNext) {
8624*1031c584SApple OSS Distributions assert(fRequestNext->fWorkWaitCount);
8625*1031c584SApple OSS Distributions if (fRequestNext->fWorkWaitCount) {
8626*1031c584SApple OSS Distributions fRequestNext->fWorkWaitCount--;
8627*1031c584SApple OSS Distributions }
8628*1031c584SApple OSS Distributions #if LOG_REQUEST_ATTACH
8629*1031c584SApple OSS Distributions PM_LOG("Detached next: %p [0x%x] -> %p [0x%x, %u] %s\n",
8630*1031c584SApple OSS Distributions OBFUSCATE(this), fRequestType, OBFUSCATE(fRequestNext),
8631*1031c584SApple OSS Distributions fRequestNext->fRequestType,
8632*1031c584SApple OSS Distributions (uint32_t) fRequestNext->fWorkWaitCount,
8633*1031c584SApple OSS Distributions fTarget->getName());
8634*1031c584SApple OSS Distributions #endif
8635*1031c584SApple OSS Distributions fRequestNext = NULL;
8636*1031c584SApple OSS Distributions ok = true;
8637*1031c584SApple OSS Distributions }
8638*1031c584SApple OSS Distributions return ok;
8639*1031c584SApple OSS Distributions }
8640*1031c584SApple OSS Distributions
8641*1031c584SApple OSS Distributions bool
attachRootRequest(IOPMRequest * root)8642*1031c584SApple OSS Distributions IOPMRequest::attachRootRequest( IOPMRequest * root )
8643*1031c584SApple OSS Distributions {
8644*1031c584SApple OSS Distributions bool ok = false;
8645*1031c584SApple OSS Distributions
8646*1031c584SApple OSS Distributions if (!fRequestRoot) {
8647*1031c584SApple OSS Distributions // Delay the completion of the root request after
8648*1031c584SApple OSS Distributions // this request.
8649*1031c584SApple OSS Distributions fRequestRoot = root;
8650*1031c584SApple OSS Distributions fRequestRoot->fFreeWaitCount++;
8651*1031c584SApple OSS Distributions #if LOG_REQUEST_ATTACH
8652*1031c584SApple OSS Distributions PM_LOG("Attached root: %p [0x%x] -> %p [0x%x, %u] %s\n",
8653*1031c584SApple OSS Distributions OBFUSCATE(this), (uint32_t) fType, OBFUSCATE(fRequestRoot),
8654*1031c584SApple OSS Distributions (uint32_t) fRequestRoot->fType,
8655*1031c584SApple OSS Distributions (uint32_t) fRequestRoot->fFreeWaitCount,
8656*1031c584SApple OSS Distributions fTarget->getName());
8657*1031c584SApple OSS Distributions #endif
8658*1031c584SApple OSS Distributions ok = true;
8659*1031c584SApple OSS Distributions }
8660*1031c584SApple OSS Distributions return ok;
8661*1031c584SApple OSS Distributions }
8662*1031c584SApple OSS Distributions
8663*1031c584SApple OSS Distributions bool
detachRootRequest(void)8664*1031c584SApple OSS Distributions IOPMRequest::detachRootRequest( void )
8665*1031c584SApple OSS Distributions {
8666*1031c584SApple OSS Distributions bool ok = false;
8667*1031c584SApple OSS Distributions
8668*1031c584SApple OSS Distributions if (fRequestRoot) {
8669*1031c584SApple OSS Distributions assert(fRequestRoot->fFreeWaitCount);
8670*1031c584SApple OSS Distributions if (fRequestRoot->fFreeWaitCount) {
8671*1031c584SApple OSS Distributions fRequestRoot->fFreeWaitCount--;
8672*1031c584SApple OSS Distributions }
8673*1031c584SApple OSS Distributions #if LOG_REQUEST_ATTACH
8674*1031c584SApple OSS Distributions PM_LOG("Detached root: %p [0x%x] -> %p [0x%x, %u] %s\n",
8675*1031c584SApple OSS Distributions OBFUSCATE(this), (uint32_t) fType, OBFUSCATE(fRequestRoot),
8676*1031c584SApple OSS Distributions (uint32_t) fRequestRoot->fType,
8677*1031c584SApple OSS Distributions (uint32_t) fRequestRoot->fFreeWaitCount,
8678*1031c584SApple OSS Distributions fTarget->getName());
8679*1031c584SApple OSS Distributions #endif
8680*1031c584SApple OSS Distributions fRequestRoot = NULL;
8681*1031c584SApple OSS Distributions ok = true;
8682*1031c584SApple OSS Distributions }
8683*1031c584SApple OSS Distributions return ok;
8684*1031c584SApple OSS Distributions }
8685*1031c584SApple OSS Distributions
8686*1031c584SApple OSS Distributions // MARK: -
8687*1031c584SApple OSS Distributions // MARK: IOPMRequestQueue
8688*1031c584SApple OSS Distributions
8689*1031c584SApple OSS Distributions //*********************************************************************************
8690*1031c584SApple OSS Distributions // IOPMRequestQueue Class
8691*1031c584SApple OSS Distributions //
8692*1031c584SApple OSS Distributions // Global queues. Queues are created once and never released.
8693*1031c584SApple OSS Distributions //*********************************************************************************
8694*1031c584SApple OSS Distributions
8695*1031c584SApple OSS Distributions OSDefineMetaClassAndStructors( IOPMRequestQueue, IOEventSource );
8696*1031c584SApple OSS Distributions
8697*1031c584SApple OSS Distributions #pragma clang diagnostic push
8698*1031c584SApple OSS Distributions #pragma clang diagnostic ignored "-Wcast-function-type"
8699*1031c584SApple OSS Distributions
8700*1031c584SApple OSS Distributions IOPMRequestQueue *
create(IOService * inOwner,Action inAction)8701*1031c584SApple OSS Distributions IOPMRequestQueue::create( IOService * inOwner, Action inAction )
8702*1031c584SApple OSS Distributions {
8703*1031c584SApple OSS Distributions IOPMRequestQueue * me = OSTypeAlloc(IOPMRequestQueue);
8704*1031c584SApple OSS Distributions if (me && !me->init(inOwner, inAction)) {
8705*1031c584SApple OSS Distributions me->release();
8706*1031c584SApple OSS Distributions me = NULL;
8707*1031c584SApple OSS Distributions }
8708*1031c584SApple OSS Distributions return me;
8709*1031c584SApple OSS Distributions }
8710*1031c584SApple OSS Distributions
8711*1031c584SApple OSS Distributions bool
init(IOService * inOwner,Action inAction)8712*1031c584SApple OSS Distributions IOPMRequestQueue::init( IOService * inOwner, Action inAction )
8713*1031c584SApple OSS Distributions {
8714*1031c584SApple OSS Distributions if (!inAction || !IOEventSource::init(inOwner, (IOEventSourceAction)inAction)) {
8715*1031c584SApple OSS Distributions return false;
8716*1031c584SApple OSS Distributions }
8717*1031c584SApple OSS Distributions
8718*1031c584SApple OSS Distributions queue_init(&fQueue);
8719*1031c584SApple OSS Distributions fLock = IOLockAlloc();
8720*1031c584SApple OSS Distributions return fLock != NULL;
8721*1031c584SApple OSS Distributions }
8722*1031c584SApple OSS Distributions
8723*1031c584SApple OSS Distributions #pragma clang diagnostic pop
8724*1031c584SApple OSS Distributions
8725*1031c584SApple OSS Distributions void
free(void)8726*1031c584SApple OSS Distributions IOPMRequestQueue::free( void )
8727*1031c584SApple OSS Distributions {
8728*1031c584SApple OSS Distributions if (fLock) {
8729*1031c584SApple OSS Distributions IOLockFree(fLock);
8730*1031c584SApple OSS Distributions fLock = NULL;
8731*1031c584SApple OSS Distributions }
8732*1031c584SApple OSS Distributions return IOEventSource::free();
8733*1031c584SApple OSS Distributions }
8734*1031c584SApple OSS Distributions
8735*1031c584SApple OSS Distributions void
queuePMRequest(IOPMRequest * request)8736*1031c584SApple OSS Distributions IOPMRequestQueue::queuePMRequest( IOPMRequest * request )
8737*1031c584SApple OSS Distributions {
8738*1031c584SApple OSS Distributions uint64_t now = mach_continuous_time();
8739*1031c584SApple OSS Distributions
8740*1031c584SApple OSS Distributions assert(request);
8741*1031c584SApple OSS Distributions request->setTimestamp(now);
8742*1031c584SApple OSS Distributions IOLockLock(fLock);
8743*1031c584SApple OSS Distributions queue_enter(&fQueue, request, typeof(request), fCommandChain);
8744*1031c584SApple OSS Distributions IOLockUnlock(fLock);
8745*1031c584SApple OSS Distributions if (workLoop) {
8746*1031c584SApple OSS Distributions signalWorkAvailable();
8747*1031c584SApple OSS Distributions }
8748*1031c584SApple OSS Distributions }
8749*1031c584SApple OSS Distributions
8750*1031c584SApple OSS Distributions void
queuePMRequestChain(IOPMRequest ** requests,IOItemCount count)8751*1031c584SApple OSS Distributions IOPMRequestQueue::queuePMRequestChain( IOPMRequest ** requests, IOItemCount count )
8752*1031c584SApple OSS Distributions {
8753*1031c584SApple OSS Distributions IOPMRequest * next;
8754*1031c584SApple OSS Distributions uint64_t now = mach_continuous_time();
8755*1031c584SApple OSS Distributions
8756*1031c584SApple OSS Distributions assert(requests && count);
8757*1031c584SApple OSS Distributions IOLockLock(fLock);
8758*1031c584SApple OSS Distributions while (count--) {
8759*1031c584SApple OSS Distributions next = *requests;
8760*1031c584SApple OSS Distributions next->setTimestamp(now);
8761*1031c584SApple OSS Distributions requests++;
8762*1031c584SApple OSS Distributions queue_enter(&fQueue, next, typeof(next), fCommandChain);
8763*1031c584SApple OSS Distributions }
8764*1031c584SApple OSS Distributions IOLockUnlock(fLock);
8765*1031c584SApple OSS Distributions if (workLoop) {
8766*1031c584SApple OSS Distributions signalWorkAvailable();
8767*1031c584SApple OSS Distributions }
8768*1031c584SApple OSS Distributions }
8769*1031c584SApple OSS Distributions
8770*1031c584SApple OSS Distributions bool
checkForWork(void)8771*1031c584SApple OSS Distributions IOPMRequestQueue::checkForWork( void )
8772*1031c584SApple OSS Distributions {
8773*1031c584SApple OSS Distributions Action dqAction = (Action) (void (*)(void))action;
8774*1031c584SApple OSS Distributions IOPMRequest * request;
8775*1031c584SApple OSS Distributions IOService * target;
8776*1031c584SApple OSS Distributions int dequeueCount = 0;
8777*1031c584SApple OSS Distributions bool more = false;
8778*1031c584SApple OSS Distributions
8779*1031c584SApple OSS Distributions IOLockLock( fLock );
8780*1031c584SApple OSS Distributions
8781*1031c584SApple OSS Distributions while (!queue_empty(&fQueue)) {
8782*1031c584SApple OSS Distributions if (dequeueCount++ >= kMaxDequeueCount) {
8783*1031c584SApple OSS Distributions // Allow other queues a chance to work
8784*1031c584SApple OSS Distributions more = true;
8785*1031c584SApple OSS Distributions break;
8786*1031c584SApple OSS Distributions }
8787*1031c584SApple OSS Distributions
8788*1031c584SApple OSS Distributions queue_remove_first(&fQueue, request, typeof(request), fCommandChain);
8789*1031c584SApple OSS Distributions IOLockUnlock(fLock);
8790*1031c584SApple OSS Distributions target = request->getTarget();
8791*1031c584SApple OSS Distributions assert(target);
8792*1031c584SApple OSS Distributions more |= (*dqAction)( target, request, this );
8793*1031c584SApple OSS Distributions IOLockLock( fLock );
8794*1031c584SApple OSS Distributions }
8795*1031c584SApple OSS Distributions
8796*1031c584SApple OSS Distributions IOLockUnlock( fLock );
8797*1031c584SApple OSS Distributions return more;
8798*1031c584SApple OSS Distributions }
8799*1031c584SApple OSS Distributions
8800*1031c584SApple OSS Distributions // MARK: -
8801*1031c584SApple OSS Distributions // MARK: IOPMWorkQueue
8802*1031c584SApple OSS Distributions
8803*1031c584SApple OSS Distributions //*********************************************************************************
8804*1031c584SApple OSS Distributions // IOPMWorkQueue Class
8805*1031c584SApple OSS Distributions //
8806*1031c584SApple OSS Distributions // Queue of IOServicePM objects, each with a queue of IOPMRequest sharing the
8807*1031c584SApple OSS Distributions // same target.
8808*1031c584SApple OSS Distributions //*********************************************************************************
8809*1031c584SApple OSS Distributions
8810*1031c584SApple OSS Distributions OSDefineMetaClassAndStructors( IOPMWorkQueue, IOEventSource );
8811*1031c584SApple OSS Distributions
8812*1031c584SApple OSS Distributions IOPMWorkQueue *
create(IOService * inOwner,Action invoke,Action retire)8813*1031c584SApple OSS Distributions IOPMWorkQueue::create( IOService * inOwner, Action invoke, Action retire )
8814*1031c584SApple OSS Distributions {
8815*1031c584SApple OSS Distributions IOPMWorkQueue * me = OSTypeAlloc(IOPMWorkQueue);
8816*1031c584SApple OSS Distributions if (me && !me->init(inOwner, invoke, retire)) {
8817*1031c584SApple OSS Distributions me->release();
8818*1031c584SApple OSS Distributions me = NULL;
8819*1031c584SApple OSS Distributions }
8820*1031c584SApple OSS Distributions return me;
8821*1031c584SApple OSS Distributions }
8822*1031c584SApple OSS Distributions
8823*1031c584SApple OSS Distributions bool
init(IOService * inOwner,Action invoke,Action retire)8824*1031c584SApple OSS Distributions IOPMWorkQueue::init( IOService * inOwner, Action invoke, Action retire )
8825*1031c584SApple OSS Distributions {
8826*1031c584SApple OSS Distributions if (!invoke || !retire ||
8827*1031c584SApple OSS Distributions !IOEventSource::init(inOwner, (IOEventSourceAction)NULL)) {
8828*1031c584SApple OSS Distributions return false;
8829*1031c584SApple OSS Distributions }
8830*1031c584SApple OSS Distributions
8831*1031c584SApple OSS Distributions queue_init(&fWorkQueue);
8832*1031c584SApple OSS Distributions
8833*1031c584SApple OSS Distributions fInvokeAction = invoke;
8834*1031c584SApple OSS Distributions fRetireAction = retire;
8835*1031c584SApple OSS Distributions fConsumerCount = fProducerCount = 0;
8836*1031c584SApple OSS Distributions
8837*1031c584SApple OSS Distributions return true;
8838*1031c584SApple OSS Distributions }
8839*1031c584SApple OSS Distributions
8840*1031c584SApple OSS Distributions bool
queuePMRequest(IOPMRequest * request,IOServicePM * pwrMgt)8841*1031c584SApple OSS Distributions IOPMWorkQueue::queuePMRequest( IOPMRequest * request, IOServicePM * pwrMgt )
8842*1031c584SApple OSS Distributions {
8843*1031c584SApple OSS Distributions queue_head_t * requestQueue;
8844*1031c584SApple OSS Distributions bool more = false;
8845*1031c584SApple OSS Distributions bool empty;
8846*1031c584SApple OSS Distributions
8847*1031c584SApple OSS Distributions assert( request );
8848*1031c584SApple OSS Distributions assert( pwrMgt );
8849*1031c584SApple OSS Distributions assert( onThread());
8850*1031c584SApple OSS Distributions assert( queue_next(&request->fCommandChain) ==
8851*1031c584SApple OSS Distributions queue_prev(&request->fCommandChain));
8852*1031c584SApple OSS Distributions
8853*1031c584SApple OSS Distributions gIOPMBusyRequestCount++;
8854*1031c584SApple OSS Distributions
8855*1031c584SApple OSS Distributions if (request->isQuiesceType()) {
8856*1031c584SApple OSS Distributions if ((request->getTarget() == gIOPMRootNode) && !fQuiesceStartTime) {
8857*1031c584SApple OSS Distributions // Attach new quiesce request to all quiesce blockers in the queue
8858*1031c584SApple OSS Distributions fQuiesceStartTime = mach_absolute_time();
8859*1031c584SApple OSS Distributions attachQuiesceRequest(request);
8860*1031c584SApple OSS Distributions fQuiesceRequest = request;
8861*1031c584SApple OSS Distributions }
8862*1031c584SApple OSS Distributions } else if (fQuiesceRequest && request->isQuiesceBlocker()) {
8863*1031c584SApple OSS Distributions // Attach the new quiesce blocker to the blocked quiesce request
8864*1031c584SApple OSS Distributions request->attachNextRequest(fQuiesceRequest);
8865*1031c584SApple OSS Distributions }
8866*1031c584SApple OSS Distributions
8867*1031c584SApple OSS Distributions // Add new request to the tail of the per-service request queue.
8868*1031c584SApple OSS Distributions // Then immediately check the request queue to minimize latency
8869*1031c584SApple OSS Distributions // if the queue was empty.
8870*1031c584SApple OSS Distributions
8871*1031c584SApple OSS Distributions requestQueue = &pwrMgt->RequestHead;
8872*1031c584SApple OSS Distributions empty = queue_empty(requestQueue);
8873*1031c584SApple OSS Distributions queue_enter(requestQueue, request, typeof(request), fCommandChain);
8874*1031c584SApple OSS Distributions if (empty) {
8875*1031c584SApple OSS Distributions more = checkRequestQueue(requestQueue, &empty);
8876*1031c584SApple OSS Distributions if (!empty) {
8877*1031c584SApple OSS Distributions // Request just added is blocked, add its target IOServicePM
8878*1031c584SApple OSS Distributions // to the work queue.
8879*1031c584SApple OSS Distributions assert( queue_next(&pwrMgt->WorkChain) ==
8880*1031c584SApple OSS Distributions queue_prev(&pwrMgt->WorkChain));
8881*1031c584SApple OSS Distributions
8882*1031c584SApple OSS Distributions queue_enter(&fWorkQueue, pwrMgt, typeof(pwrMgt), WorkChain);
8883*1031c584SApple OSS Distributions fQueueLength++;
8884*1031c584SApple OSS Distributions PM_LOG3("IOPMWorkQueue: [%u] added %s@%p to queue\n",
8885*1031c584SApple OSS Distributions fQueueLength, pwrMgt->Name, OBFUSCATE(pwrMgt));
8886*1031c584SApple OSS Distributions }
8887*1031c584SApple OSS Distributions }
8888*1031c584SApple OSS Distributions
8889*1031c584SApple OSS Distributions return more;
8890*1031c584SApple OSS Distributions }
8891*1031c584SApple OSS Distributions
8892*1031c584SApple OSS Distributions bool
checkRequestQueue(queue_head_t * requestQueue,bool * empty)8893*1031c584SApple OSS Distributions IOPMWorkQueue::checkRequestQueue( queue_head_t * requestQueue, bool * empty )
8894*1031c584SApple OSS Distributions {
8895*1031c584SApple OSS Distributions IOPMRequest * request;
8896*1031c584SApple OSS Distributions IOService * target;
8897*1031c584SApple OSS Distributions bool more = false;
8898*1031c584SApple OSS Distributions bool done = false;
8899*1031c584SApple OSS Distributions
8900*1031c584SApple OSS Distributions assert(!queue_empty(requestQueue));
8901*1031c584SApple OSS Distributions do {
8902*1031c584SApple OSS Distributions request = (typeof(request))queue_first(requestQueue);
8903*1031c584SApple OSS Distributions if (request->isWorkBlocked()) {
8904*1031c584SApple OSS Distributions break; // request dispatch blocked on attached request
8905*1031c584SApple OSS Distributions }
8906*1031c584SApple OSS Distributions target = request->getTarget();
8907*1031c584SApple OSS Distributions if (fInvokeAction) {
8908*1031c584SApple OSS Distributions done = (*fInvokeAction)( target, request, this );
8909*1031c584SApple OSS Distributions } else {
8910*1031c584SApple OSS Distributions PM_LOG("PM request 0x%x dropped\n", request->getType());
8911*1031c584SApple OSS Distributions done = true;
8912*1031c584SApple OSS Distributions }
8913*1031c584SApple OSS Distributions if (!done) {
8914*1031c584SApple OSS Distributions break; // PM state machine blocked
8915*1031c584SApple OSS Distributions }
8916*1031c584SApple OSS Distributions assert(gIOPMBusyRequestCount > 0);
8917*1031c584SApple OSS Distributions if (gIOPMBusyRequestCount) {
8918*1031c584SApple OSS Distributions gIOPMBusyRequestCount--;
8919*1031c584SApple OSS Distributions }
8920*1031c584SApple OSS Distributions
8921*1031c584SApple OSS Distributions if (request == fQuiesceRequest) {
8922*1031c584SApple OSS Distributions fQuiesceRequest = NULL;
8923*1031c584SApple OSS Distributions }
8924*1031c584SApple OSS Distributions
8925*1031c584SApple OSS Distributions queue_remove_first(requestQueue, request, typeof(request), fCommandChain);
8926*1031c584SApple OSS Distributions more |= (*fRetireAction)( target, request, this );
8927*1031c584SApple OSS Distributions done = queue_empty(requestQueue);
8928*1031c584SApple OSS Distributions } while (!done);
8929*1031c584SApple OSS Distributions
8930*1031c584SApple OSS Distributions *empty = done;
8931*1031c584SApple OSS Distributions
8932*1031c584SApple OSS Distributions if (more) {
8933*1031c584SApple OSS Distributions // Retired a request that may unblock a previously visited request
8934*1031c584SApple OSS Distributions // that is still waiting on the work queue. Must trigger another
8935*1031c584SApple OSS Distributions // queue check.
8936*1031c584SApple OSS Distributions fProducerCount++;
8937*1031c584SApple OSS Distributions }
8938*1031c584SApple OSS Distributions
8939*1031c584SApple OSS Distributions return more;
8940*1031c584SApple OSS Distributions }
8941*1031c584SApple OSS Distributions
8942*1031c584SApple OSS Distributions bool
checkForWork(void)8943*1031c584SApple OSS Distributions IOPMWorkQueue::checkForWork( void )
8944*1031c584SApple OSS Distributions {
8945*1031c584SApple OSS Distributions IOServicePM * entry;
8946*1031c584SApple OSS Distributions IOServicePM * next;
8947*1031c584SApple OSS Distributions bool more = false;
8948*1031c584SApple OSS Distributions bool empty;
8949*1031c584SApple OSS Distributions
8950*1031c584SApple OSS Distributions #if WORK_QUEUE_STATS
8951*1031c584SApple OSS Distributions fStatCheckForWork++;
8952*1031c584SApple OSS Distributions #endif
8953*1031c584SApple OSS Distributions
8954*1031c584SApple OSS Distributions // Iterate over all IOServicePM entries in the work queue,
8955*1031c584SApple OSS Distributions // and check each entry's request queue.
8956*1031c584SApple OSS Distributions
8957*1031c584SApple OSS Distributions while (fConsumerCount != fProducerCount) {
8958*1031c584SApple OSS Distributions PM_LOG3("IOPMWorkQueue: checkForWork %u %u\n",
8959*1031c584SApple OSS Distributions fProducerCount, fConsumerCount);
8960*1031c584SApple OSS Distributions
8961*1031c584SApple OSS Distributions fConsumerCount = fProducerCount;
8962*1031c584SApple OSS Distributions
8963*1031c584SApple OSS Distributions #if WORK_QUEUE_STATS
8964*1031c584SApple OSS Distributions if (queue_empty(&fWorkQueue)) {
8965*1031c584SApple OSS Distributions fStatQueueEmpty++;
8966*1031c584SApple OSS Distributions break;
8967*1031c584SApple OSS Distributions }
8968*1031c584SApple OSS Distributions fStatScanEntries++;
8969*1031c584SApple OSS Distributions uint32_t cachedWorkCount = gIOPMWorkInvokeCount;
8970*1031c584SApple OSS Distributions #endif
8971*1031c584SApple OSS Distributions
8972*1031c584SApple OSS Distributions __IGNORE_WCASTALIGN(entry = (typeof(entry))queue_first(&fWorkQueue));
8973*1031c584SApple OSS Distributions while (!queue_end(&fWorkQueue, (queue_entry_t) entry)) {
8974*1031c584SApple OSS Distributions more |= checkRequestQueue(&entry->RequestHead, &empty);
8975*1031c584SApple OSS Distributions
8976*1031c584SApple OSS Distributions // Get next entry, points to head if current entry is last.
8977*1031c584SApple OSS Distributions __IGNORE_WCASTALIGN(next = (typeof(next))queue_next(&entry->WorkChain));
8978*1031c584SApple OSS Distributions
8979*1031c584SApple OSS Distributions // if request queue is empty, remove IOServicePM from work queue.
8980*1031c584SApple OSS Distributions if (empty) {
8981*1031c584SApple OSS Distributions assert(fQueueLength);
8982*1031c584SApple OSS Distributions if (fQueueLength) {
8983*1031c584SApple OSS Distributions fQueueLength--;
8984*1031c584SApple OSS Distributions }
8985*1031c584SApple OSS Distributions PM_LOG3("IOPMWorkQueue: [%u] removed %s@%p from queue\n",
8986*1031c584SApple OSS Distributions fQueueLength, entry->Name, OBFUSCATE(entry));
8987*1031c584SApple OSS Distributions queue_remove(&fWorkQueue, entry, typeof(entry), WorkChain);
8988*1031c584SApple OSS Distributions }
8989*1031c584SApple OSS Distributions entry = next;
8990*1031c584SApple OSS Distributions }
8991*1031c584SApple OSS Distributions
8992*1031c584SApple OSS Distributions #if WORK_QUEUE_STATS
8993*1031c584SApple OSS Distributions if (cachedWorkCount == gIOPMWorkInvokeCount) {
8994*1031c584SApple OSS Distributions fStatNoWorkDone++;
8995*1031c584SApple OSS Distributions }
8996*1031c584SApple OSS Distributions #endif
8997*1031c584SApple OSS Distributions }
8998*1031c584SApple OSS Distributions
8999*1031c584SApple OSS Distributions return more;
9000*1031c584SApple OSS Distributions }
9001*1031c584SApple OSS Distributions
9002*1031c584SApple OSS Distributions void
signalWorkAvailable(void)9003*1031c584SApple OSS Distributions IOPMWorkQueue::signalWorkAvailable( void )
9004*1031c584SApple OSS Distributions {
9005*1031c584SApple OSS Distributions fProducerCount++;
9006*1031c584SApple OSS Distributions IOEventSource::signalWorkAvailable();
9007*1031c584SApple OSS Distributions }
9008*1031c584SApple OSS Distributions
9009*1031c584SApple OSS Distributions void
incrementProducerCount(void)9010*1031c584SApple OSS Distributions IOPMWorkQueue::incrementProducerCount( void )
9011*1031c584SApple OSS Distributions {
9012*1031c584SApple OSS Distributions fProducerCount++;
9013*1031c584SApple OSS Distributions }
9014*1031c584SApple OSS Distributions
9015*1031c584SApple OSS Distributions void
attachQuiesceRequest(IOPMRequest * quiesceRequest)9016*1031c584SApple OSS Distributions IOPMWorkQueue::attachQuiesceRequest( IOPMRequest * quiesceRequest )
9017*1031c584SApple OSS Distributions {
9018*1031c584SApple OSS Distributions IOServicePM * entry;
9019*1031c584SApple OSS Distributions IOPMRequest * request;
9020*1031c584SApple OSS Distributions
9021*1031c584SApple OSS Distributions if (queue_empty(&fWorkQueue)) {
9022*1031c584SApple OSS Distributions return;
9023*1031c584SApple OSS Distributions }
9024*1031c584SApple OSS Distributions
9025*1031c584SApple OSS Distributions queue_iterate(&fWorkQueue, entry, typeof(entry), WorkChain)
9026*1031c584SApple OSS Distributions {
9027*1031c584SApple OSS Distributions queue_iterate(&entry->RequestHead, request, typeof(request), fCommandChain)
9028*1031c584SApple OSS Distributions {
9029*1031c584SApple OSS Distributions // Attach the quiesce request to any request in the queue that
9030*1031c584SApple OSS Distributions // is not linked to a next request. These requests will block
9031*1031c584SApple OSS Distributions // the quiesce request.
9032*1031c584SApple OSS Distributions
9033*1031c584SApple OSS Distributions if (request->isQuiesceBlocker()) {
9034*1031c584SApple OSS Distributions request->attachNextRequest(quiesceRequest);
9035*1031c584SApple OSS Distributions }
9036*1031c584SApple OSS Distributions }
9037*1031c584SApple OSS Distributions }
9038*1031c584SApple OSS Distributions }
9039*1031c584SApple OSS Distributions
9040*1031c584SApple OSS Distributions void
finishQuiesceRequest(IOPMRequest * quiesceRequest)9041*1031c584SApple OSS Distributions IOPMWorkQueue::finishQuiesceRequest( IOPMRequest * quiesceRequest )
9042*1031c584SApple OSS Distributions {
9043*1031c584SApple OSS Distributions if (fQuiesceRequest && (quiesceRequest == fQuiesceRequest) &&
9044*1031c584SApple OSS Distributions (fQuiesceStartTime != 0)) {
9045*1031c584SApple OSS Distributions fInvokeAction = NULL;
9046*1031c584SApple OSS Distributions fQuiesceFinishTime = mach_absolute_time();
9047*1031c584SApple OSS Distributions }
9048*1031c584SApple OSS Distributions }
9049*1031c584SApple OSS Distributions
9050*1031c584SApple OSS Distributions // MARK: -
9051*1031c584SApple OSS Distributions // MARK: IOPMCompletionQueue
9052*1031c584SApple OSS Distributions
9053*1031c584SApple OSS Distributions //*********************************************************************************
9054*1031c584SApple OSS Distributions // IOPMCompletionQueue Class
9055*1031c584SApple OSS Distributions //*********************************************************************************
9056*1031c584SApple OSS Distributions
9057*1031c584SApple OSS Distributions OSDefineMetaClassAndStructors( IOPMCompletionQueue, IOEventSource );
9058*1031c584SApple OSS Distributions
9059*1031c584SApple OSS Distributions #pragma clang diagnostic push
9060*1031c584SApple OSS Distributions #pragma clang diagnostic ignored "-Wcast-function-type"
9061*1031c584SApple OSS Distributions
9062*1031c584SApple OSS Distributions IOPMCompletionQueue *
create(IOService * inOwner,Action inAction)9063*1031c584SApple OSS Distributions IOPMCompletionQueue::create( IOService * inOwner, Action inAction )
9064*1031c584SApple OSS Distributions {
9065*1031c584SApple OSS Distributions IOPMCompletionQueue * me = OSTypeAlloc(IOPMCompletionQueue);
9066*1031c584SApple OSS Distributions if (me && !me->init(inOwner, inAction)) {
9067*1031c584SApple OSS Distributions me->release();
9068*1031c584SApple OSS Distributions me = NULL;
9069*1031c584SApple OSS Distributions }
9070*1031c584SApple OSS Distributions return me;
9071*1031c584SApple OSS Distributions }
9072*1031c584SApple OSS Distributions
9073*1031c584SApple OSS Distributions bool
init(IOService * inOwner,Action inAction)9074*1031c584SApple OSS Distributions IOPMCompletionQueue::init( IOService * inOwner, Action inAction )
9075*1031c584SApple OSS Distributions {
9076*1031c584SApple OSS Distributions if (!inAction || !IOEventSource::init(inOwner, (IOEventSourceAction)inAction)) {
9077*1031c584SApple OSS Distributions return false;
9078*1031c584SApple OSS Distributions }
9079*1031c584SApple OSS Distributions
9080*1031c584SApple OSS Distributions queue_init(&fQueue);
9081*1031c584SApple OSS Distributions return true;
9082*1031c584SApple OSS Distributions }
9083*1031c584SApple OSS Distributions
9084*1031c584SApple OSS Distributions
9085*1031c584SApple OSS Distributions bool
queuePMRequest(IOPMRequest * request)9086*1031c584SApple OSS Distributions IOPMCompletionQueue::queuePMRequest( IOPMRequest * request )
9087*1031c584SApple OSS Distributions {
9088*1031c584SApple OSS Distributions bool more;
9089*1031c584SApple OSS Distributions
9090*1031c584SApple OSS Distributions assert(request);
9091*1031c584SApple OSS Distributions // unblock dependent request
9092*1031c584SApple OSS Distributions more = request->detachNextRequest();
9093*1031c584SApple OSS Distributions queue_enter(&fQueue, request, typeof(request), fCommandChain);
9094*1031c584SApple OSS Distributions return more;
9095*1031c584SApple OSS Distributions }
9096*1031c584SApple OSS Distributions
9097*1031c584SApple OSS Distributions bool
checkForWork(void)9098*1031c584SApple OSS Distributions IOPMCompletionQueue::checkForWork( void )
9099*1031c584SApple OSS Distributions {
9100*1031c584SApple OSS Distributions Action dqAction = (Action) action;
9101*1031c584SApple OSS Distributions IOPMRequest * request;
9102*1031c584SApple OSS Distributions IOPMRequest * next;
9103*1031c584SApple OSS Distributions IOService * target;
9104*1031c584SApple OSS Distributions bool more = false;
9105*1031c584SApple OSS Distributions
9106*1031c584SApple OSS Distributions request = (typeof(request))queue_first(&fQueue);
9107*1031c584SApple OSS Distributions while (!queue_end(&fQueue, (queue_entry_t) request)) {
9108*1031c584SApple OSS Distributions next = (typeof(next))queue_next(&request->fCommandChain);
9109*1031c584SApple OSS Distributions if (!request->isFreeBlocked()) {
9110*1031c584SApple OSS Distributions queue_remove(&fQueue, request, typeof(request), fCommandChain);
9111*1031c584SApple OSS Distributions target = request->getTarget();
9112*1031c584SApple OSS Distributions assert(target);
9113*1031c584SApple OSS Distributions more |= (*dqAction)( target, request, this );
9114*1031c584SApple OSS Distributions }
9115*1031c584SApple OSS Distributions request = next;
9116*1031c584SApple OSS Distributions }
9117*1031c584SApple OSS Distributions
9118*1031c584SApple OSS Distributions return more;
9119*1031c584SApple OSS Distributions }
9120*1031c584SApple OSS Distributions
9121*1031c584SApple OSS Distributions #pragma clang diagnostic pop
9122*1031c584SApple OSS Distributions
9123*1031c584SApple OSS Distributions // MARK: -
9124*1031c584SApple OSS Distributions // MARK: IOServicePM
9125*1031c584SApple OSS Distributions
OSDefineMetaClassAndStructors(IOServicePM,OSObject)9126*1031c584SApple OSS Distributions OSDefineMetaClassAndStructors(IOServicePM, OSObject)
9127*1031c584SApple OSS Distributions
9128*1031c584SApple OSS Distributions //*********************************************************************************
9129*1031c584SApple OSS Distributions // serialize
9130*1031c584SApple OSS Distributions //
9131*1031c584SApple OSS Distributions // Serialize IOServicePM for debugging.
9132*1031c584SApple OSS Distributions //*********************************************************************************
9133*1031c584SApple OSS Distributions
9134*1031c584SApple OSS Distributions static void
9135*1031c584SApple OSS Distributions setPMProperty( OSDictionary * dict, const char * key, uint64_t value )
9136*1031c584SApple OSS Distributions {
9137*1031c584SApple OSS Distributions OSNumber * num = OSNumber::withNumber(value, sizeof(value) * 8);
9138*1031c584SApple OSS Distributions if (num) {
9139*1031c584SApple OSS Distributions dict->setObject(key, num);
9140*1031c584SApple OSS Distributions num->release();
9141*1031c584SApple OSS Distributions }
9142*1031c584SApple OSS Distributions }
9143*1031c584SApple OSS Distributions
9144*1031c584SApple OSS Distributions IOReturn
gatedSerialize(OSSerialize * s) const9145*1031c584SApple OSS Distributions IOServicePM::gatedSerialize( OSSerialize * s ) const
9146*1031c584SApple OSS Distributions {
9147*1031c584SApple OSS Distributions OSDictionary * dict;
9148*1031c584SApple OSS Distributions bool ok = false;
9149*1031c584SApple OSS Distributions int powerClamp = -1;
9150*1031c584SApple OSS Distributions int dictSize = 6;
9151*1031c584SApple OSS Distributions
9152*1031c584SApple OSS Distributions if (IdleTimerPeriod) {
9153*1031c584SApple OSS Distributions dictSize += 4;
9154*1031c584SApple OSS Distributions }
9155*1031c584SApple OSS Distributions
9156*1031c584SApple OSS Distributions if (PMActions.state & kPMActionsStatePowerClamped) {
9157*1031c584SApple OSS Distributions dictSize += 1;
9158*1031c584SApple OSS Distributions powerClamp = 0;
9159*1031c584SApple OSS Distributions if (PMActions.flags &
9160*1031c584SApple OSS Distributions (kPMActionsFlagIsDisplayWrangler | kPMActionsFlagIsGraphicsDriver)) {
9161*1031c584SApple OSS Distributions powerClamp++;
9162*1031c584SApple OSS Distributions }
9163*1031c584SApple OSS Distributions }
9164*1031c584SApple OSS Distributions
9165*1031c584SApple OSS Distributions #if WORK_QUEUE_STATS
9166*1031c584SApple OSS Distributions if (gIOPMRootNode == ControllingDriver) {
9167*1031c584SApple OSS Distributions dictSize += 4;
9168*1031c584SApple OSS Distributions }
9169*1031c584SApple OSS Distributions #endif
9170*1031c584SApple OSS Distributions
9171*1031c584SApple OSS Distributions if (PowerClients) {
9172*1031c584SApple OSS Distributions dict = OSDictionary::withDictionary(
9173*1031c584SApple OSS Distributions PowerClients, PowerClients->getCount() + dictSize);
9174*1031c584SApple OSS Distributions } else {
9175*1031c584SApple OSS Distributions dict = OSDictionary::withCapacity(dictSize);
9176*1031c584SApple OSS Distributions }
9177*1031c584SApple OSS Distributions
9178*1031c584SApple OSS Distributions if (dict) {
9179*1031c584SApple OSS Distributions setPMProperty(dict, "CurrentPowerState", CurrentPowerState);
9180*1031c584SApple OSS Distributions setPMProperty(dict, "CapabilityFlags", CurrentCapabilityFlags);
9181*1031c584SApple OSS Distributions if (NumberOfPowerStates) {
9182*1031c584SApple OSS Distributions setPMProperty(dict, "MaxPowerState", NumberOfPowerStates - 1);
9183*1031c584SApple OSS Distributions }
9184*1031c584SApple OSS Distributions if (DesiredPowerState != CurrentPowerState) {
9185*1031c584SApple OSS Distributions setPMProperty(dict, "DesiredPowerState", DesiredPowerState);
9186*1031c584SApple OSS Distributions }
9187*1031c584SApple OSS Distributions if (kIOPM_Finished != MachineState) {
9188*1031c584SApple OSS Distributions setPMProperty(dict, "MachineState", MachineState);
9189*1031c584SApple OSS Distributions }
9190*1031c584SApple OSS Distributions if (DeviceOverrideEnabled) {
9191*1031c584SApple OSS Distributions dict->setObject("PowerOverrideOn", kOSBooleanTrue);
9192*1031c584SApple OSS Distributions }
9193*1031c584SApple OSS Distributions if (powerClamp >= 0) {
9194*1031c584SApple OSS Distributions setPMProperty(dict, "PowerClamp", powerClamp);
9195*1031c584SApple OSS Distributions }
9196*1031c584SApple OSS Distributions
9197*1031c584SApple OSS Distributions if (IdleTimerPeriod) {
9198*1031c584SApple OSS Distributions AbsoluteTime now;
9199*1031c584SApple OSS Distributions AbsoluteTime delta;
9200*1031c584SApple OSS Distributions uint64_t nsecs;
9201*1031c584SApple OSS Distributions
9202*1031c584SApple OSS Distributions clock_get_uptime(&now);
9203*1031c584SApple OSS Distributions
9204*1031c584SApple OSS Distributions // The idle timer period in milliseconds
9205*1031c584SApple OSS Distributions setPMProperty(dict, "IdleTimerPeriod", NextIdleTimerPeriod * 1000ULL);
9206*1031c584SApple OSS Distributions
9207*1031c584SApple OSS Distributions // Number of tickles since the last idle timer expiration
9208*1031c584SApple OSS Distributions setPMProperty(dict, "ActivityTickles", ActivityTickleCount);
9209*1031c584SApple OSS Distributions
9210*1031c584SApple OSS Distributions if (AbsoluteTime_to_scalar(&DeviceActiveTimestamp)) {
9211*1031c584SApple OSS Distributions // Milliseconds since the last activity tickle
9212*1031c584SApple OSS Distributions delta = now;
9213*1031c584SApple OSS Distributions SUB_ABSOLUTETIME(&delta, &DeviceActiveTimestamp);
9214*1031c584SApple OSS Distributions absolutetime_to_nanoseconds(delta, &nsecs);
9215*1031c584SApple OSS Distributions setPMProperty(dict, "TimeSinceLastTickle", NS_TO_MS(nsecs));
9216*1031c584SApple OSS Distributions }
9217*1031c584SApple OSS Distributions
9218*1031c584SApple OSS Distributions if (!IdleTimerStopped && AbsoluteTime_to_scalar(&IdleTimerStartTime)) {
9219*1031c584SApple OSS Distributions // Idle timer elapsed time in milliseconds
9220*1031c584SApple OSS Distributions delta = now;
9221*1031c584SApple OSS Distributions SUB_ABSOLUTETIME(&delta, &IdleTimerStartTime);
9222*1031c584SApple OSS Distributions absolutetime_to_nanoseconds(delta, &nsecs);
9223*1031c584SApple OSS Distributions setPMProperty(dict, "IdleTimerElapsedTime", NS_TO_MS(nsecs));
9224*1031c584SApple OSS Distributions }
9225*1031c584SApple OSS Distributions }
9226*1031c584SApple OSS Distributions
9227*1031c584SApple OSS Distributions #if WORK_QUEUE_STATS
9228*1031c584SApple OSS Distributions if (gIOPMRootNode == Owner) {
9229*1031c584SApple OSS Distributions setPMProperty(dict, "WQ-CheckForWork",
9230*1031c584SApple OSS Distributions gIOPMWorkQueue->fStatCheckForWork);
9231*1031c584SApple OSS Distributions setPMProperty(dict, "WQ-ScanEntries",
9232*1031c584SApple OSS Distributions gIOPMWorkQueue->fStatScanEntries);
9233*1031c584SApple OSS Distributions setPMProperty(dict, "WQ-QueueEmpty",
9234*1031c584SApple OSS Distributions gIOPMWorkQueue->fStatQueueEmpty);
9235*1031c584SApple OSS Distributions setPMProperty(dict, "WQ-NoWorkDone",
9236*1031c584SApple OSS Distributions gIOPMWorkQueue->fStatNoWorkDone);
9237*1031c584SApple OSS Distributions }
9238*1031c584SApple OSS Distributions #endif
9239*1031c584SApple OSS Distributions
9240*1031c584SApple OSS Distributions if (HasAdvisoryDesire && !gIOPMAdvisoryTickleEnabled) {
9241*1031c584SApple OSS Distributions // Don't report advisory tickle when it has no influence
9242*1031c584SApple OSS Distributions dict->removeObject(gIOPMPowerClientAdvisoryTickle);
9243*1031c584SApple OSS Distributions }
9244*1031c584SApple OSS Distributions
9245*1031c584SApple OSS Distributions ok = dict->serialize(s);
9246*1031c584SApple OSS Distributions dict->release();
9247*1031c584SApple OSS Distributions }
9248*1031c584SApple OSS Distributions
9249*1031c584SApple OSS Distributions return ok ? kIOReturnSuccess : kIOReturnNoMemory;
9250*1031c584SApple OSS Distributions }
9251*1031c584SApple OSS Distributions
9252*1031c584SApple OSS Distributions bool
serialize(OSSerialize * s) const9253*1031c584SApple OSS Distributions IOServicePM::serialize( OSSerialize * s ) const
9254*1031c584SApple OSS Distributions {
9255*1031c584SApple OSS Distributions IOReturn ret = kIOReturnNotReady;
9256*1031c584SApple OSS Distributions
9257*1031c584SApple OSS Distributions if (gIOPMWatchDogThread == current_thread()) {
9258*1031c584SApple OSS Distributions // Calling without lock as this data is collected for debug purpose, before reboot.
9259*1031c584SApple OSS Distributions // The workloop is probably already hung in state machine.
9260*1031c584SApple OSS Distributions ret = gatedSerialize(s);
9261*1031c584SApple OSS Distributions } else if (gIOPMWorkLoop) {
9262*1031c584SApple OSS Distributions ret = gIOPMWorkLoop->runAction(
9263*1031c584SApple OSS Distributions OSMemberFunctionCast(IOWorkLoop::Action, this, &IOServicePM::gatedSerialize),
9264*1031c584SApple OSS Distributions (OSObject *) this, (void *) s);
9265*1031c584SApple OSS Distributions }
9266*1031c584SApple OSS Distributions
9267*1031c584SApple OSS Distributions return kIOReturnSuccess == ret;
9268*1031c584SApple OSS Distributions }
9269*1031c584SApple OSS Distributions
9270*1031c584SApple OSS Distributions void
pmPrint(uint32_t event,uintptr_t param1,uintptr_t param2) const9271*1031c584SApple OSS Distributions IOServicePM::pmPrint(
9272*1031c584SApple OSS Distributions uint32_t event,
9273*1031c584SApple OSS Distributions uintptr_t param1,
9274*1031c584SApple OSS Distributions uintptr_t param2 ) const
9275*1031c584SApple OSS Distributions {
9276*1031c584SApple OSS Distributions gPlatform->PMLog(Name, event, param1, param2);
9277*1031c584SApple OSS Distributions }
9278*1031c584SApple OSS Distributions
9279*1031c584SApple OSS Distributions void
pmTrace(uint32_t event,uint32_t eventFunc,uintptr_t param1,uintptr_t param2) const9280*1031c584SApple OSS Distributions IOServicePM::pmTrace(
9281*1031c584SApple OSS Distributions uint32_t event,
9282*1031c584SApple OSS Distributions uint32_t eventFunc,
9283*1031c584SApple OSS Distributions uintptr_t param1,
9284*1031c584SApple OSS Distributions uintptr_t param2 ) const
9285*1031c584SApple OSS Distributions {
9286*1031c584SApple OSS Distributions uintptr_t nameAsArg = 0;
9287*1031c584SApple OSS Distributions
9288*1031c584SApple OSS Distributions assert(event < KDBG_CODE_MAX);
9289*1031c584SApple OSS Distributions assert((eventFunc & ~KDBG_FUNC_MASK) == 0);
9290*1031c584SApple OSS Distributions
9291*1031c584SApple OSS Distributions // Copy the first characters of the name into an uintptr_t.
9292*1031c584SApple OSS Distributions // NULL termination is not required.
9293*1031c584SApple OSS Distributions strncpy((char*)&nameAsArg, Name, sizeof(nameAsArg));
9294*1031c584SApple OSS Distributions
9295*1031c584SApple OSS Distributions #if defined(XNU_TARGET_OS_OSX)
9296*1031c584SApple OSS Distributions KERNEL_DEBUG_CONSTANT_IST(KDEBUG_TRACE, IODBG_POWER(event) | eventFunc, nameAsArg,
9297*1031c584SApple OSS Distributions (uintptr_t)Owner->getRegistryEntryID(), (uintptr_t)(OBFUSCATE(param1)),
9298*1031c584SApple OSS Distributions (uintptr_t)(OBFUSCATE(param2)), 0);
9299*1031c584SApple OSS Distributions #else
9300*1031c584SApple OSS Distributions IOTimeStampConstant(IODBG_POWER(event) | eventFunc, nameAsArg, (uintptr_t)Owner->getRegistryEntryID(), (uintptr_t)(OBFUSCATE(param1)), (uintptr_t)(OBFUSCATE(param2)));
9301*1031c584SApple OSS Distributions #endif
9302*1031c584SApple OSS Distributions }
9303