kernel - Fix some rare pmap races in i386 and x86_64.
[dragonfly.git] / sys / platform / pc32 / i386 / est.c
blobd58253d174c77ab4b3d0f9495f9a524ce9e4d2b7
1 /* $NetBSD: est.c,v 1.25 2006/06/18 16:39:56 nonaka Exp $ */
2 /*
3 * Copyright (c) 2003 Michael Eriksson.
4 * All rights reserved.
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * 3. The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 /*-
29 * Copyright (c) 2004 The NetBSD Foundation, Inc.
30 * All rights reserved.
32 * Redistribution and use in source and binary forms, with or without
33 * modification, are permitted provided that the following conditions
34 * are met:
35 * 1. Redistributions of source code must retain the above copyright
36 * notice, this list of conditions and the following disclaimer.
37 * 2. Redistributions in binary form must reproduce the above copyright
38 * notice, this list of conditions and the following disclaimer in the
39 * documentation and/or other materials provided with the distribution.
40 * 3. All advertising materials mentioning features or use of this software
41 * must display the following acknowledgement:
42 * This product includes software developed by the NetBSD
43 * Foundation, Inc. and its contributors.
44 * 4. Neither the name of The NetBSD Foundation nor the names of its
45 * contributors may be used to endorse or promote products derived
46 * from this software without specific prior written permission.
48 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
49 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
50 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
51 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
52 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
53 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
54 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
55 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
56 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
57 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
58 * POSSIBILITY OF SUCH DAMAGE.
62 * This is a driver for Intel's Enhanced SpeedStep Technology (EST),
63 * as implemented in Pentium M processors.
65 * Reference documentation:
67 * - IA-32 Intel Architecture Software Developer's Manual, Volume 3:
68 * System Programming Guide.
69 * Section 13.14, Enhanced Intel SpeedStep technology.
70 * Table B-2, MSRs in Pentium M Processors.
71 * http://www.intel.com/design/pentium4/manuals/253668.htm
73 * - Intel Pentium M Processor Datasheet.
74 * Table 5, Voltage and Current Specifications.
75 * http://www.intel.com/design/mobile/datashts/252612.htm
77 * - Intel Pentium M Processor on 90 nm Process with 2-MB L2 Cache Datasheet
78 * Table 3-4, 3-5, 3-6, Voltage and Current Specifications.
79 * http://www.intel.com/design/mobile/datashts/302189.htm
81 * - Linux cpufreq patches, speedstep-centrino.c.
82 * Encoding of MSR_PERF_CTL and MSR_PERF_STATUS.
83 * http://www.codemonkey.org.uk/projects/cpufreq/cpufreq-2.4.22-pre6-1.gz
85 * ACPI objects: _PCT is MSR location, _PSS is freq/voltage, _PPC is caps.
87 * $NetBSD: est.c,v 1.25 2006/06/18 16:39:56 nonaka Exp $
88 * $DragonFly: src/sys/platform/pc32/i386/est.c,v 1.11 2008/06/05 18:06:32 swildner Exp $
91 #include <sys/param.h>
92 #include <sys/systm.h>
93 #include <sys/malloc.h>
94 #include <sys/kernel.h>
95 #include <sys/module.h>
96 #include <sys/sysctl.h>
98 #include <machine/cpu.h>
99 #include <machine/md_var.h>
100 #include <machine/specialreg.h>
103 struct fq_info {
104 int mhz;
105 int mv;
108 /* Ultra Low Voltage Intel Pentium M processor 900 MHz */
109 static const struct fq_info pentium_m_900[] = {
110 { 900, 1004 },
111 { 800, 988 },
112 { 600, 844 },
115 /* Ultra Low Voltage Intel Pentium M processor 1.00 GHz */
116 static const struct fq_info pentium_m_1000[] = {
117 { 1000, 1004 },
118 { 900, 988 },
119 { 800, 972 },
120 { 600, 844 },
123 /* Low Voltage Intel Pentium M processor 1.10 GHz */
124 static const struct fq_info pentium_m_1100[] = {
125 { 1100, 1180 },
126 { 1000, 1164 },
127 { 900, 1100 },
128 { 800, 1020 },
129 { 600, 956 },
132 /* Low Voltage Intel Pentium M processor 1.20 GHz */
133 static const struct fq_info pentium_m_1200[] = {
134 { 1200, 1180 },
135 { 1100, 1164 },
136 { 1000, 1100 },
137 { 900, 1020 },
138 { 800, 1004 },
139 { 600, 956 },
142 /* Low Voltage Intel Pentium M processor 1.30 GHz */
143 static const struct fq_info pentium_m_1300_lv[] = {
144 { 1300, 1180 },
145 { 1200, 1164 },
146 { 1100, 1100 },
147 { 1000, 1020 },
148 { 900, 1004 },
149 { 800, 988 },
150 { 600, 956 },
153 /* Intel Pentium M processor 1.30 GHz */
154 static const struct fq_info pentium_m_1300[] = {
155 { 1300, 1388 },
156 { 1200, 1356 },
157 { 1000, 1292 },
158 { 800, 1260 },
159 { 600, 956 },
162 /* Intel Pentium M processor 1.40 GHz */
163 static const struct fq_info pentium_m_1400[] = {
164 { 1400, 1484 },
165 { 1200, 1436 },
166 { 1000, 1308 },
167 { 800, 1180 },
168 { 600, 956 }
171 /* Intel Pentium M processor 1.50 GHz */
172 static const struct fq_info pentium_m_1500[] = {
173 { 1500, 1484 },
174 { 1400, 1452 },
175 { 1200, 1356 },
176 { 1000, 1228 },
177 { 800, 1116 },
178 { 600, 956 }
181 /* Intel Pentium M processor 1.60 GHz */
182 static const struct fq_info pentium_m_1600[] = {
183 { 1600, 1484 },
184 { 1400, 1420 },
185 { 1200, 1276 },
186 { 1000, 1164 },
187 { 800, 1036 },
188 { 600, 956 }
191 /* Intel Pentium M processor 1.70 GHz */
192 static const struct fq_info pentium_m_1700[] = {
193 { 1700, 1484 },
194 { 1400, 1308 },
195 { 1200, 1228 },
196 { 1000, 1116 },
197 { 800, 1004 },
198 { 600, 956 }
201 /* Intel Pentium M processor 723 Ultra Low Voltage 1.0 GHz */
202 static const struct fq_info pentium_m_n723[] = {
203 { 1000, 940 },
204 { 900, 908 },
205 { 800, 876 },
206 { 600, 812 }
209 /* Intel Pentium M processor 733 Ultra Low Voltage 1.1 GHz */
210 static const struct fq_info pentium_m_n733[] = {
211 { 1100, 940 },
212 { 1000, 924 },
213 { 900, 892 },
214 { 800, 876 },
215 { 600, 812 }
218 /* Intel Pentium M processor 753 Ultra Low Voltage 1.2 GHz */
219 static const struct fq_info pentium_m_n753[] = {
220 { 1200, 940 },
221 { 1100, 924 },
222 { 1000, 908 },
223 { 900, 876 },
224 { 800, 860 },
225 { 600, 812 }
228 /* Intel Pentium M processor 773 Ultra Low Voltage 1.3 GHz */
229 static const struct fq_info pentium_m_n773[] = {
230 { 1300, 940 },
231 { 1200, 924 },
232 { 1100, 908 },
233 { 1000, 892 },
234 { 900, 876 },
235 { 800, 860 },
236 { 600, 812 }
239 /* Intel Pentium M processor 738 Low Voltage 1.4 GHz */
240 static const struct fq_info pentium_m_n738[] = {
241 { 1400, 1116 },
242 { 1300, 1116 },
243 { 1200, 1100 },
244 { 1100, 1068 },
245 { 1000, 1052 },
246 { 900, 1036 },
247 { 800, 1020 },
248 { 600, 988 }
251 /* Intel Pentium M processor 758 Low Voltage 1.5 GHz */
252 static const struct fq_info pentium_m_n758[] = {
253 { 1500, 1116 },
254 { 1400, 1116 },
255 { 1300, 1100 },
256 { 1200, 1084 },
257 { 1100, 1068 },
258 { 1000, 1052 },
259 { 900, 1036 },
260 { 800, 1020 },
261 { 600, 988 }
264 /* Intel Pentium M processor 778 Low Voltage 1.6 GHz */
265 static const struct fq_info pentium_m_n778[] = {
266 { 1600, 1116 },
267 { 1500, 1116 },
268 { 1400, 1100 },
269 { 1300, 1184 },
270 { 1200, 1068 },
271 { 1100, 1052 },
272 { 1000, 1052 },
273 { 900, 1036 },
274 { 800, 1020 },
275 { 600, 988 }
278 /* Intel Pentium M processor 710 1.4 GHz */
279 static const struct fq_info pentium_m_n710[] = {
280 { 1400, 1340 },
281 { 1200, 1228 },
282 { 1000, 1148 },
283 { 800, 1068 },
284 { 600, 998 }
287 /* Intel Pentium M processor 715 1.5 GHz */
288 static const struct fq_info pentium_m_n715[] = {
289 { 1500, 1340 },
290 { 1200, 1228 },
291 { 1000, 1148 },
292 { 800, 1068 },
293 { 600, 988 }
296 /* Intel Pentium M processor 725 1.6 GHz */
297 static const struct fq_info pentium_m_n725[] = {
298 { 1600, 1340 },
299 { 1400, 1276 },
300 { 1200, 1212 },
301 { 1000, 1132 },
302 { 800, 1068 },
303 { 600, 988 }
306 /* Intel Pentium M processor 730 1.6 GHz */
307 static const struct fq_info pentium_m_n730[] = {
308 { 1600, 1308 },
309 { 1333, 1260 },
310 { 1200, 1212 },
311 { 1067, 1180 },
312 { 800, 988 }
315 /* Intel Pentium M processor 735 1.7 GHz */
316 static const struct fq_info pentium_m_n735[] = {
317 { 1700, 1340 },
318 { 1400, 1244 },
319 { 1200, 1180 },
320 { 1000, 1116 },
321 { 800, 1052 },
322 { 600, 988 }
325 /* Intel Pentium M processor 740 1.73 GHz */
326 static const struct fq_info pentium_m_n740[] = {
327 { 1733, 1356 },
328 { 1333, 1212 },
329 { 1067, 1100 },
330 { 800, 988 },
333 /* Intel Pentium M processor 740 1.73 GHz (988-1308mV version?) */
334 static const struct fq_info pentium_m_n740_2[] = {
335 { 1733, 1308 },
336 { 1333, 1148 },
337 { 1067, 1068 },
338 { 800, 988 }
341 /* Intel Pentium M processor 745 1.8 GHz */
342 static const struct fq_info pentium_m_n745[] = {
343 { 1800, 1340 },
344 { 1600, 1292 },
345 { 1400, 1228 },
346 { 1200, 1164 },
347 { 1000, 1116 },
348 { 800, 1052 },
349 { 600, 988 }
352 /* Intel Pentium M processor 750 1.86 GHz */
353 /* values extracted from \_PR\NPSS (via _PSS) SDST ACPI table */
354 static const struct fq_info pentium_m_n750[] = {
355 { 1867, 1308 },
356 { 1600, 1228 },
357 { 1333, 1148 },
358 { 1067, 1068 },
359 { 800, 988 }
362 static const struct fq_info pentium_m_n750_2[] = {
363 { 1867, 1356 },
364 { 1600, 1228 },
365 { 1333, 1148 },
366 { 1067, 1068 },
367 { 800, 988 }
370 /* Intel Pentium M processor 755 2.0 GHz */
371 static const struct fq_info pentium_m_n755[] = {
372 { 2000, 1340 },
373 { 1800, 1292 },
374 { 1600, 1244 },
375 { 1400, 1196 },
376 { 1200, 1148 },
377 { 1000, 1100 },
378 { 800, 1052 },
379 { 600, 988 }
382 /* Intel Pentium M processor 760 2.0 GHz */
383 static const struct fq_info pentium_m_n760[] = {
384 { 2000, 1356 },
385 { 1600, 1244 },
386 { 1333, 1164 },
387 { 1067, 1084 },
388 { 800, 988 }
391 /* Intel Pentium M processor 760 2.0 GHz */
392 static const struct fq_info pentium_m_n760_2[] = {
393 { 2000, 1308 },
394 { 1600, 1244 },
395 { 1333, 1164 },
396 { 1067, 1084 },
397 { 800, 988 }
400 /* Intel Pentium M processor 765 2.1 GHz */
401 static const struct fq_info pentium_m_n765[] = {
402 { 2100, 1340 },
403 { 1800, 1276 },
404 { 1600, 1228 },
405 { 1400, 1180 },
406 { 1200, 1132 },
407 { 1000, 1084 },
408 { 800, 1036 },
409 { 600, 988 }
412 /* Intel Pentium M processor 770 2.13 GHz */
413 static const struct fq_info pentium_m_n770[] = {
414 { 2133, 1551 },
415 { 1800, 1429 },
416 { 1600, 1356 },
417 { 1400, 1180 },
418 { 1200, 1132 },
419 { 1000, 1084 },
420 { 800, 1036 },
421 { 600, 988 }
424 /* Intel Pentium M processor 770 2.13 GHz */
425 static const struct fq_info pentium_m_n770_2[] = {
426 { 2133, 1356 },
427 { 1867, 1292 },
428 { 1600, 1212 },
429 { 1333, 1148 },
430 { 1067, 1068 },
431 { 800, 988 }
434 /* Intel Pentium Core Duo T2300 */
435 static const struct fq_info pentium_core_duo_t2300[] = {
436 { 1666, 1404 },
437 { 1500, 1404 },
438 { 1333, 1404 },
439 { 1167, 1404 },
440 { 1000, 1004 },
441 { 667, 1004 },
442 { 333, 1004 },
443 { 167, 1004 },
446 static const struct fq_info pentium_core2_duo_t7500[] = {
447 { 2200, 1420 },
448 { 1600, 1212 },
449 { 1200, 1068 },
450 { 800, 988 },
453 struct fqlist {
454 const char *brand_tag;
455 const u_int cpu_id;
456 size_t tablec;
457 const struct fq_info *table;
458 const int fsbmult; /* in multiples of 133 MHz */
461 #define ENTRY(s, i, v, f) { s, i, sizeof(v) / sizeof((v)[0]), v, f }
462 static const struct fqlist pentium_m[] = { /* Banias */
463 ENTRY(" 900", 0x0695, pentium_m_900, 3),
464 ENTRY("1000", 0x0695, pentium_m_1000, 3),
465 ENTRY("1100", 0x0695, pentium_m_1100, 3),
466 ENTRY("1200", 0x0695, pentium_m_1200, 3),
467 ENTRY("1300", 0x0695, pentium_m_1300, 3),
468 ENTRY("1300", 0x0695, pentium_m_1300_lv, 3),
469 ENTRY("1400", 0x0695, pentium_m_1400, 3),
470 ENTRY("1500", 0x0695, pentium_m_1500, 3),
471 ENTRY("1600", 0x0695, pentium_m_1600, 3),
472 ENTRY("1700", 0x0695, pentium_m_1700, 3),
475 static const struct fqlist pentium_m_dothan[] = {
477 /* low voltage CPUs */
478 ENTRY("1.00", 0x06d8, pentium_m_n723, 3),
479 ENTRY("1.10", 0x06d6, pentium_m_n733, 3),
480 ENTRY("1.20", 0x06d8, pentium_m_n753, 3),
481 ENTRY("1.30", 0, pentium_m_n773, 3), /* does this exist? */
483 /* ultra low voltage CPUs */
484 ENTRY("1.40", 0x06d6, pentium_m_n738, 3),
485 ENTRY("1.50", 0x06d8, pentium_m_n758, 3),
486 ENTRY("1.60", 0x06d8, pentium_m_n778, 3),
488 /* 'regular' 400 MHz FSB CPUs */
489 ENTRY("1.40", 0x06d6, pentium_m_n710, 3),
490 ENTRY("1.50", 0x06d6, pentium_m_n715, 3),
491 ENTRY("1.50", 0x06d8, pentium_m_n715, 3),
492 ENTRY("1.60", 0x06d6, pentium_m_n725, 3),
493 ENTRY("1.70", 0x06d6, pentium_m_n735, 3),
494 ENTRY("1.80", 0x06d6, pentium_m_n745, 3),
495 ENTRY("2.00", 0x06d6, pentium_m_n755, 3),
496 ENTRY("2.10", 0x06d6, pentium_m_n765, 3),
498 /* 533 MHz FSB CPUs */
499 ENTRY("1.60", 0x06d8, pentium_m_n730, 4),
500 ENTRY("1.73", 0x06d8, pentium_m_n740, 4),
501 ENTRY("1.73", 0x06d8, pentium_m_n740_2, 4),
502 ENTRY("1.86", 0x06d8, pentium_m_n750, 4),
503 ENTRY("1.86", 0x06d8, pentium_m_n750_2, 4),
504 ENTRY("2.00", 0x06d8, pentium_m_n760, 4),
505 ENTRY("2.00", 0x06d8, pentium_m_n760_2, 4),
506 ENTRY("2.13", 0x06d8, pentium_m_n770, 4),
507 ENTRY("2.13", 0x06d8, pentium_m_n770_2, 4),
512 static const struct fqlist pentium_yonah[] = {
514 /* 666 MHz FSB CPUs */
515 ENTRY("1.66", 0x06e8, pentium_core_duo_t2300, 5 ),
518 static const struct fqlist pentium_merom[] = {
520 /* 800 MHz FSB CPUs */
521 ENTRY("2.20", 0x06fa, pentium_core2_duo_t7500, 6 ),
524 #undef ENTRY
526 struct est_cpu {
527 const char *brand_prefix;
528 const char *brand_suffix;
529 size_t listc;
530 const struct fqlist *list;
533 static const struct est_cpu est_cpus[] = {
535 "Intel(R) Pentium(R) M processor ", "MHz",
536 (sizeof(pentium_m) / sizeof(pentium_m[0])),
537 pentium_m
540 "Intel(R) Pentium(R) M processor ", "GHz",
541 (sizeof(pentium_m_dothan) / sizeof(pentium_m_dothan[0])),
542 pentium_m_dothan
545 "Genuine Intel(R) CPU T2300 @ ", "GHz",
546 (sizeof(pentium_yonah) / sizeof(pentium_yonah[0])),
547 pentium_yonah
550 "Intel(R) Core(TM)2 Duo CPU T7500 @ ", "GHz",
551 (sizeof(pentium_merom) / sizeof(pentium_merom[0])),
552 pentium_merom
556 #define NESTCPUS (sizeof(est_cpus) / sizeof(est_cpus[0]))
558 #define MSR2MV(msr) (((int) (msr) & 0xff) * 16 + 700)
559 #define MSR2MHZ(msr) (((((int) (msr) >> 8) & 0xff) * 100 * fsbmult + 1)/ 3)
560 #define MV2MSR(mv) ((((int) (mv) - 700) >> 4) & 0xff)
561 #define MHZ2MSR(mhz) (((3 * (mhz + 30) / (100 * fsbmult)) & 0xff) << 8)
562 /* XXX 30 is slop to deal with the 33.333 MHz roundoff values */
565 * Names and numbers from IA-32 System Programming Guide
566 * (not found in <machine/specialregs.h>
568 #define MSR_PERF_STATUS 0x198
569 #define MSR_PERF_CTL 0x199
571 static const struct fqlist *est_fqlist; /* not NULL if functional */
572 static int fsbmult;
574 static const char est_desc[] = "Enhanced SpeedStep";
576 static char freqs_available[80];
578 static int
579 est_sysctl_helper(SYSCTL_HANDLER_ARGS)
581 uint64_t msr;
582 int fq, oldfq, err = 0;
583 int i;
585 if (est_fqlist == NULL)
586 return (EOPNOTSUPP);
588 oldfq = MSR2MHZ(rdmsr(MSR_PERF_CTL));
590 if (req->newptr != NULL) {
591 err = SYSCTL_IN(req, &fq, sizeof(fq));
592 if (err)
593 return err;
595 if (fq != oldfq) {
596 for (i = est_fqlist->tablec - 1; i > 0; i--) {
597 if (est_fqlist->table[i].mhz >= fq)
598 break;
600 fq = est_fqlist->table[i].mhz;
601 msr = (rdmsr(MSR_PERF_CTL) & ~0xffffULL) |
602 MV2MSR(est_fqlist->table[i].mv) |
603 MHZ2MSR(est_fqlist->table[i].mhz);
604 wrmsr(MSR_PERF_CTL, msr);
606 } else {
607 err = SYSCTL_OUT(req, &oldfq, sizeof(oldfq));
610 return err;
614 * Look for a CPU matching hw.model
616 static const struct fqlist *
617 findcpu(const char *hwmodel, int mv)
619 const struct est_cpu *ccpu;
620 const struct fqlist *fql;
621 const char *tag;
622 size_t len;
623 size_t i;
624 int k;
626 for (ccpu = est_cpus; ccpu < est_cpus + NESTCPUS; ++ccpu) {
627 len = strlen(ccpu->brand_prefix);
628 if (strncmp(ccpu->brand_prefix, hwmodel, len) != 0)
629 continue;
630 tag = hwmodel + len;
631 for (i = 0; i < ccpu->listc; i++) {
632 fql = &ccpu->list[i];
633 len = strlen(fql->brand_tag);
634 if (strncmp(fql->brand_tag, tag, len) != 0 ||
635 strcmp(ccpu->brand_suffix, tag + len))
636 continue;
638 if (fql->cpu_id == 0 || fql->cpu_id == cpu_id) {
639 /* verify operating point is in table, because
640 CPUID + brand_tag still isn't unique. */
641 for (k = fql->tablec - 1; k >= 0; k--) {
642 if (fql->table[k].mv == mv)
643 return fql;
648 return(NULL);
652 static struct sysctl_ctx_list machdep_est_ctx;
654 static int
655 est_init(void)
657 char hwmodel[128];
658 int mib[] = { CTL_HW, HW_MODEL };
659 size_t modellen = sizeof(hwmodel);
660 struct sysctl_oid *oid, *leaf;
661 uint64_t msr;
662 int mv;
663 size_t len, freq_len;
664 int err;
665 size_t i;
667 if ((cpu_feature2 & CPUID2_EST) == 0) {
668 kprintf("Enhanced SpeedStep unsupported on this hardware.\n");
669 return(EOPNOTSUPP);
672 modellen = sizeof(hwmodel);
673 err = kernel_sysctl(mib, 2, hwmodel, &modellen, NULL, 0, NULL);
674 if (err) {
675 kprintf("kernel_sysctl hw.model failed\n");
676 return(err);
679 msr = rdmsr(MSR_PERF_STATUS);
680 mv = MSR2MV(msr);
681 kprintf("%s (%d mV) ", est_desc, mv);
683 est_fqlist = findcpu(hwmodel, mv);
684 if (est_fqlist == NULL) {
685 kprintf(" - unknown CPU or operating point"
686 "(cpu_id:%#x, msr:%#llx).\n", cpu_id, msr);
687 return(EOPNOTSUPP);
691 * OK, tell the user the available frequencies.
693 fsbmult = est_fqlist->fsbmult;
694 kprintf("%d MHz\n", MSR2MHZ(msr));
696 freq_len = est_fqlist->tablec * (sizeof("9999 ")-1) + 1;
697 if (freq_len >= sizeof(freqs_available)) {
698 kprintf("increase the size of freqs_available[]\n");
699 return(ENOMEM);
701 freqs_available[0] = '\0';
702 len = 0;
703 for (i = 0; i < est_fqlist->tablec; i++) {
704 len += ksnprintf(freqs_available + len, freq_len - len, "%d%s",
705 est_fqlist->table[i].mhz,
706 i < est_fqlist->tablec - 1 ? " " : "");
708 kprintf("%s frequencies available (MHz): %s\n", est_desc,
709 freqs_available);
712 * Setup the sysctl sub-tree machdep.est.*
714 oid = SYSCTL_ADD_NODE(&machdep_est_ctx,
715 SYSCTL_STATIC_CHILDREN(_machdep), OID_AUTO, "est",
716 CTLFLAG_RD, NULL, "");
717 if (oid == NULL)
718 return(EOPNOTSUPP);
719 oid = SYSCTL_ADD_NODE(&machdep_est_ctx, SYSCTL_CHILDREN(oid),
720 OID_AUTO, "frequency", CTLFLAG_RD, NULL, "");
721 if (oid == NULL)
722 return(EOPNOTSUPP);
723 leaf = SYSCTL_ADD_PROC(&machdep_est_ctx, SYSCTL_CHILDREN(oid),
724 OID_AUTO, "target", CTLTYPE_INT | CTLFLAG_RW, NULL, 0,
725 est_sysctl_helper, "I",
726 "Target CPU frequency for Enhanced SpeedStep");
727 if (leaf == NULL)
728 return(EOPNOTSUPP);
729 leaf = SYSCTL_ADD_PROC(&machdep_est_ctx, SYSCTL_CHILDREN(oid),
730 OID_AUTO, "current", CTLTYPE_INT | CTLFLAG_RD, NULL, 0,
731 est_sysctl_helper, "I",
732 "Current CPU frequency for Enhanced SpeedStep");
733 if (leaf == NULL)
734 return(EOPNOTSUPP);
735 leaf = SYSCTL_ADD_STRING(&machdep_est_ctx, SYSCTL_CHILDREN(oid),
736 OID_AUTO, "available", CTLFLAG_RD, freqs_available,
737 sizeof(freqs_available),
738 "CPU frequencies supported by Enhanced SpeedStep");
739 if (leaf == NULL)
740 return(EOPNOTSUPP);
742 return(0);
745 static int
746 est_modevh(struct module *m __unused, int what, void *arg __unused)
748 int error;
750 switch (what) {
751 case MOD_LOAD:
752 error = sysctl_ctx_init(&machdep_est_ctx);
753 if (error != 0)
754 break;
755 error = est_init();
756 break;
757 case MOD_UNLOAD:
758 error = sysctl_ctx_free(&machdep_est_ctx);
759 break;
760 default:
761 error = EINVAL;
762 break;
764 return(error);
767 static moduledata_t est_mod = {
768 "est",
769 est_modevh,
770 NULL,
773 DECLARE_MODULE(est, est_mod, SI_BOOT2_KLD, SI_ORDER_ANY);