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