]> git.saurik.com Git - apple/xnu.git/blame - osfmk/i386/pmCPU.c
xnu-792.18.15.tar.gz
[apple/xnu.git] / osfmk / i386 / pmCPU.c
CommitLineData
89b3af67
A
1/*
2 * Copyright (c) 2004-2006 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
14 *
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
17 *
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
25 *
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27 */
28
29/*
30 * CPU-specific power management support.
31 *
32 * Implements the "wrappers" to the KEXT.
33 */
34#include <i386/machine_routines.h>
35#include <i386/machine_cpu.h>
36#include <i386/misc_protos.h>
37#include <i386/pmap.h>
38#include <i386/asm.h>
39#include <i386/mp.h>
40#include <i386/proc_reg.h>
41#include <kern/pms.h>
42#include <kern/processor.h>
43#include <i386/pmCPU.h>
44#include <i386/cpuid.h>
45#include <i386/rtclock.h>
46#if MACH_KDB
47#include <i386/db_machdep.h>
48#include <ddb/db_aout.h>
49#include <ddb/db_access.h>
50#include <ddb/db_sym.h>
51#include <ddb/db_variables.h>
52#include <ddb/db_command.h>
53#include <ddb/db_output.h>
54#include <ddb/db_expr.h>
55#endif
56
57extern int disableConsoleOutput;
58
59decl_simple_lock_data(,pm_init_lock);
60
61/*
62 * The following is set when the KEXT loads and initializes.
63 */
64pmDispatch_t *pmDispatch = NULL;
65
66/*
67 * Current power management states (for use until KEXT is loaded).
68 */
69static pmInitState_t pmInitState;
70
71/*
72 * Nap control variables:
73 */
74uint32_t napCtl = 0; /* Defaults to neither napping
75 nor halting */
76uint32_t forcenap = 0; /* Force nap (fn) boot-arg controls */
77uint32_t maxBusDelay = 0xFFFFFFFF; /* Maximum memory bus delay that
78 I/O devices can tolerate
79 before errors (nanoseconds) */
80uint32_t C4C2SnoopDelay = 0; /* C4 to C2 transition time -
81 time before a C4 system
82 can snoop (nanoseconds) */
83
84/*
85 * We are being asked to set PState (sel).
86 */
87void
88pmsCPUSet(uint32_t sel)
89{
90 if (pmDispatch != NULL && pmDispatch->pmsCPUSet != NULL)
91 (*pmDispatch->pmsCPUSet)(sel);
92 else
93 pmInitState.PState = sel;
94}
95
96/*
97 * This code configures the initial step tables. It should be called after
98 * the timebase frequency is initialized.
99 *
100 * Note that this is not used in normal operation. It is strictly for
101 * debugging/testing purposes.
102 */
103void
104pmsCPUConf(void)
105{
106
107 if (pmDispatch != NULL && pmDispatch->pmsCPUConf != NULL)
108 (*pmDispatch->pmsCPUConf)();
109}
110
111/*
112 * Machine-dependent initialization.
113 */
114void
115pmsCPUMachineInit(void)
116{
117 /*
118 * Initialize some of the initial state to "uninitialized" until
119 * it gets set with something more useful. This allows the KEXT
120 * to determine if the initial value was actually set to something.
121 */
122 pmInitState.PState = -1;
123 pmInitState.PLimit = -1;
124
125 if (pmDispatch != NULL && pmDispatch->pmsCPUMachineInit != NULL)
126 (*pmDispatch->pmsCPUMachineInit)();
127}
128
129/*
130 * This function should be called once for each processor to force the
131 * processor to the correct initial voltage and frequency.
132 */
133void
134pmsCPUInit(void)
135{
136 pmsCPUMachineInit();
137 if (pmDispatch != NULL && pmDispatch->pmsCPUInit != NULL)
138 (*pmDispatch->pmsCPUInit)();
139}
140
141/*
142 * Broadcast a change to all processing including ourselves.
143 */
144void
145pmsCPURun(uint32_t nstep)
146{
147 if (pmDispatch != NULL && pmDispatch->pmsCPURun != NULL)
148 (*pmDispatch->pmsCPURun)(nstep);
149}
150
151/*
152 * Return the current state of a core.
153 */
154uint32_t
155pmsCPUQuery(void)
156{
157 if (pmDispatch != NULL && pmDispatch->pmsCPUQuery != NULL)
158 return((*pmDispatch->pmsCPUQuery)());
159
160 /*
161 * Return a non-sense value.
162 */
163 return((~0) << 16);
164}
165
166/*
167 * Return the current state of the package.
168 */
169uint32_t
170pmsCPUPackageQuery(void)
171{
172 if (pmDispatch != NULL && pmDispatch->pmsCPUPackageQuery != NULL)
173 return((*pmDispatch->pmsCPUPackageQuery)());
174
175 /*
176 * Return a non-sense value.
177 */
178 return((~0) << 16);
179}
180
181/*
182 * Force the CPU package to the lowest power level. This is a low-level
183 * interface meant to be called from the panic or debugger code to bring
184 * the CPU to a safe power level for unmanaged operation.
185 *
186 * Note that while this will bring an entire package to a safe level, it
187 * cannot affect other packages. As a general rule, this should be run on
188 * every code as part of entering the debugger or on the panic path.
189 */
190void
191pmsCPUYellowFlag(void)
192{
193 if (pmDispatch != NULL && pmDispatch->pmsCPUYellowFlag != NULL)
194 (*pmDispatch->pmsCPUYellowFlag)();
195}
196
197/*
198 * Restore the CPU to the power state it was in before a yellow flag.
199 */
200void
201pmsCPUGreenFlag(void)
202{
203 if (pmDispatch != NULL && pmDispatch->pmsCPUGreenFlag != NULL)
204 (*pmDispatch->pmsCPUGreenFlag)();
205}
206
207/*
208 * Load a new ratio/VID table.
209 *
210 * Note that this interface is specific to the Intel SpeedStep implementation.
211 * It is expected that this will only be called once to override the default
212 * ratio/VID table when the platform starts.
213 *
214 * Normally, the table will need to be replaced at the same time that the
215 * stepper program proper is replaced, as the PState indices from an old
216 * program may no longer be valid. When replacing the default program this
217 * should not be a problem as any new table will have at least two PState
218 * entries and the default program only references P0 and P1.
219 */
220kern_return_t
221pmsCPULoadVIDTable(uint16_t *tablep, int nstates)
222{
223 if (pmDispatch != NULL && pmDispatch->pmsCPULoadVIDTable != NULL)
224 return((*pmDispatch->pmsCPULoadVIDTable)(tablep, nstates));
225 else {
226 int i;
227
228 if (nstates > MAX_PSTATES)
229 return(KERN_FAILURE);
230
231 for (i = 0; i < nstates; i += 1)
232 pmInitState.VIDTable[i] = tablep[i];
233 }
234 return(KERN_SUCCESS);
235}
236
237/*
238 * Set the (global) PState limit. CPUs will not be permitted to run at
239 * a lower (more performant) PState than this.
240 */
241kern_return_t
242pmsCPUSetPStateLimit(uint32_t limit)
243{
244 if (pmDispatch != NULL && pmDispatch->pmsCPUSetPStateLimit != NULL)
245 return((*pmDispatch->pmsCPUSetPStateLimit)(limit));
246
247 pmInitState.PLimit = limit;
248 return(KERN_SUCCESS);
249}
250
251/*
252 * Initialize the Cstate change code.
253 */
254void
255power_management_init(void)
256{
257 uint32_t cpuModel;
258 uint32_t cpuFamily;
259 uint32_t xcpuid[4];
260
261 /*
262 * Initialize the lock for the KEXT initialization.
263 */
264 simple_lock_init(&pm_init_lock, 0);
265
266 /*
267 * XXX
268 *
269 * The following is a hack to disable power management on some systems
270 * until the KEXT is done. This is strictly temporary!!!
271 */
272 do_cpuid(1, xcpuid);
273 cpuFamily = (xcpuid[eax] >> 8) & 0xf;
274 cpuModel = (xcpuid[eax] >> 4) & 0xf;
275
276 if (cpuFamily != 0x6 || cpuModel < 0xe)
277 pmDispatch = NULL;
278
279 if (pmDispatch != NULL && pmDispatch->cstateInit != NULL)
280 (*pmDispatch->cstateInit)();
281}
282
283/*
284 * This function will update the system nap policy. It should be called
285 * whenever conditions change: when the system is ready to being napping
286 * and if something changes the rules (e.g. a sysctl altering the policy
287 * for debugging).
288 */
289void
290machine_nap_policy(void)
291{
292 if (pmDispatch != NULL && pmDispatch->cstateNapPolicy != NULL)
293 napCtl = (*pmDispatch->cstateNapPolicy)(forcenap, napCtl);
294}
295
296/*
297 * ACPI calls the following routine to set/update mwait hints. A table
298 * (possibly null) specifies the available Cstates and their hints, all
299 * other states are assumed to be invalid. ACPI may update available
300 * states to change the nap policy (for example, while AC power is
301 * available).
302 */
303kern_return_t
304Cstate_table_set(Cstate_hint_t *tablep, unsigned int nstates)
305{
306 if (forcenap)
307 return(KERN_SUCCESS);
308
309 if (pmDispatch != NULL && pmDispatch->cstateTableSet != NULL)
310 return((*pmDispatch->cstateTableSet)(tablep, nstates));
311 else {
312 unsigned int i;
313
314 for (i = 0; i < nstates; i += 1) {
315 pmInitState.CStates[i].number = tablep[i].number;
316 pmInitState.CStates[i].hint = tablep[i].hint;
317 }
318
319 pmInitState.CStatesCount = nstates;
320 }
321 return(KERN_SUCCESS);
322}
323
324static inline void
325sti(void) {
326 __asm__ volatile ( "sti" : : : "memory");
327}
328
329/*
330 * Called when the CPU is idle. It will choose the best C state to
331 * be in.
332 */
333void
334machine_idle_cstate(void)
335{
336 if (pmDispatch != NULL && pmDispatch->cstateMachineIdle != NULL)
337 (*pmDispatch->cstateMachineIdle)(napCtl);
338 else {
339 sti();
340 }
341}
342
343static pmStats_t *
344pmsCPUStats(void)
345{
346 cpu_data_t *pp;
347
348 pp = current_cpu_datap();
349 return(&pp->cpu_pmStats);
350}
351
352static pmsd *
353pmsCPUStepperData(void)
354{
355 cpu_data_t *pp;
356
357 pp = current_cpu_datap();
358 return(&pp->pms);
359}
360
361static uint64_t *
362CPUHPETAddr(void)
363{
364 cpu_data_t *pp;
365 pp = current_cpu_datap();
366 return(pp->cpu_pmHpet);
367}
368
369/*
370 * Called by the power management kext to register itself and to get the
371 * callbacks it might need into other power management functions.
372 */
373void
374pmRegister(pmDispatch_t *cpuFuncs, pmCallBacks_t *callbacks)
375{
376 if (callbacks != NULL) {
377 callbacks->Park = pmsPark;
378 callbacks->Run = pmsRun;
379 callbacks->RunLocal = pmsRunLocal;
380 callbacks->SetStep = pmsSetStep;
381 callbacks->NapPolicy = machine_nap_policy;
382 callbacks->Build = pmsBuild;
383 callbacks->Stats = pmsCPUStats;
384 callbacks->StepperData = pmsCPUStepperData;
385 callbacks->HPETAddr = CPUHPETAddr;
386 callbacks->InitState = &pmInitState;
387 callbacks->resetPop = resetPop;
388 }
389
390 if (cpuFuncs != NULL)
391 pmDispatch = cpuFuncs;
392}
393
394/*
395 * Unregisters the power management functions from the kext.
396 */
397void
398pmUnRegister(pmDispatch_t *cpuFuncs)
399{
400 if (cpuFuncs != NULL && pmDispatch == cpuFuncs)
401 pmDispatch = NULL;
402}
403
404#if MACH_KDB
405/*
406 * XXX stubs for now
407 */
408void
409db_cfg(__unused db_expr_t addr,
410 __unused int have_addr,
411 __unused db_expr_t count,
412 __unused char *modif)
413{
414 return;
415}
416
417void
418db_display_iokit(__unused db_expr_t addr,
419 __unused int have_addr,
420 __unused db_expr_t count,
421 __unused char *modif)
422{
423 return;
424}
425
426void
427db_dtimers(__unused db_expr_t addr,
428 __unused int have_addr,
429 __unused db_expr_t count,
430 __unused char *modif)
431{
432 return;
433}
434
435void
436db_intcnt(__unused db_expr_t addr,
437 __unused int have_addr,
438 __unused db_expr_t count,
439 __unused char *modif)
440{
441 return;
442}
443
444void
445db_nap(__unused db_expr_t addr,
446 __unused int have_addr,
447 __unused db_expr_t count,
448 __unused char *modif)
449{
450 return;
451}
452
453void
454db_pmgr(__unused db_expr_t addr,
455 __unused int have_addr,
456 __unused db_expr_t count,
457 __unused char *modif)
458{
459 return;
460}
461
462void
463db_test(__unused db_expr_t addr,
464 __unused int have_addr,
465 __unused db_expr_t count,
466 __unused char *modif)
467{
468 return;
469}
470
471void
472db_getpmgr(__unused pmData_t *pmj)
473{
474}
475#endif