1 /* $NetBSD: est.c,v 1.24 2006/03/15 22:56:38 dogcow Exp $ */
3 * Copyright (c) 2003 Michael Eriksson.
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
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.
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
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.24 2006/03/15 22:56:38 dogcow Exp $
88 * $DragonFly: src/sys/platform/pc32/i386/est.c,v 1.2 2006/06/30 07:34:59 y0netan1 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>
108 /* Ultra Low Voltage Intel Pentium M processor 900 MHz */
109 static const struct fq_info pentium_m_900[] = {
115 /* Ultra Low Voltage Intel Pentium M processor 1.00 GHz */
116 static const struct fq_info pentium_m_1000[] = {
123 /* Low Voltage Intel Pentium M processor 1.10 GHz */
124 static const struct fq_info pentium_m_1100[] = {
132 /* Low Voltage Intel Pentium M processor 1.20 GHz */
133 static const struct fq_info pentium_m_1200[] = {
142 /* Intel Pentium M processor 1.30 GHz */
143 static const struct fq_info pentium_m_1300[] = {
151 /* Intel Pentium M processor 1.40 GHz */
152 static const struct fq_info pentium_m_1400[] = {
160 /* Intel Pentium M processor 1.50 GHz */
161 static const struct fq_info pentium_m_1500[] = {
170 /* Intel Pentium M processor 1.60 GHz */
171 static const struct fq_info pentium_m_1600[] = {
180 /* Intel Pentium M processor 1.70 GHz */
181 static const struct fq_info pentium_m_1700[] = {
190 /* Intel Pentium M processor 723 Ultra Low Voltage 1.0 GHz */
191 static const struct fq_info pentium_m_n723[] = {
198 /* Intel Pentium M processor 733 Ultra Low Voltage 1.1 GHz */
199 static const struct fq_info pentium_m_n733[] = {
207 /* Intel Pentium M processor 753 Ultra Low Voltage 1.2 GHz */
208 static const struct fq_info pentium_m_n753[] = {
217 /* Intel Pentium M processor 773 Ultra Low Voltage 1.3 GHz */
218 static const struct fq_info pentium_m_n773[] = {
228 /* Intel Pentium M processor 738 Low Voltage 1.4 GHz */
229 static const struct fq_info pentium_m_n738[] = {
240 /* Intel Pentium M processor 758 Low Voltage 1.5 GHz */
241 static const struct fq_info pentium_m_n758[] = {
253 /* Intel Pentium M processor 778 Low Voltage 1.6 GHz */
254 static const struct fq_info pentium_m_n778[] = {
267 /* Intel Pentium M processor 710 1.4 GHz */
268 static const struct fq_info pentium_m_n710[] = {
276 /* Intel Pentium M processor 715 1.5 GHz */
277 static const struct fq_info pentium_m_n715[] = {
285 /* Intel Pentium M processor 725 1.6 GHz */
286 static const struct fq_info pentium_m_n725[] = {
295 /* Intel Pentium M processor 730 1.6 GHz */
296 static const struct fq_info pentium_m_n730[] = {
304 /* Intel Pentium M processor 735 1.7 GHz */
305 static const struct fq_info pentium_m_n735[] = {
314 /* Intel Pentium M processor 740 1.73 GHz */
315 static const struct fq_info pentium_m_n740[] = {
322 /* Intel Pentium M processor 740 1.73 GHz (988-1308mV version?) */
323 static const struct fq_info pentium_m_n740_2[] = {
330 /* Intel Pentium M processor 745 1.8 GHz */
331 static const struct fq_info pentium_m_n745[] = {
341 /* Intel Pentium M processor 750 1.86 GHz */
342 /* values extracted from \_PR\NPSS (via _PSS) SDST ACPI table */
343 static const struct fq_info pentium_m_n750[] = {
351 /* Intel Pentium M processor 755 2.0 GHz */
352 static const struct fq_info pentium_m_n755[] = {
363 /* Intel Pentium M processor 760 2.0 GHz */
364 static const struct fq_info pentium_m_n760[] = {
372 /* Intel Pentium M processor 765 2.1 GHz */
373 static const struct fq_info pentium_m_n765[] = {
384 /* Intel Pentium M processor 770 2.13 GHz */
385 static const struct fq_info pentium_m_n770[] = {
397 const char *brand_tag;
400 const struct fq_info *table;
401 const int fsbmult; /* in multiples of 133 MHz */
404 #define ENTRY(s, i, v, f) { s, i, sizeof(v) / sizeof((v)[0]), v, f }
405 static const struct fqlist pentium_m[] = { /* Banias */
406 ENTRY(" 900", 0x0695, pentium_m_900, 3),
407 ENTRY("1000", 0x0695, pentium_m_1000, 3),
408 ENTRY("1100", 0x0695, pentium_m_1100, 3),
409 ENTRY("1200", 0x0695, pentium_m_1200, 3),
410 ENTRY("1300", 0x0695, pentium_m_1300, 3),
411 ENTRY("1400", 0x0695, pentium_m_1400, 3),
412 ENTRY("1500", 0x0695, pentium_m_1500, 3),
413 ENTRY("1600", 0x0695, pentium_m_1600, 3),
414 ENTRY("1700", 0x0695, pentium_m_1700, 3),
417 static const struct fqlist pentium_m_dothan[] = {
419 /* low voltage CPUs */
420 ENTRY("1.00", 0x06d8, pentium_m_n723, 3),
421 ENTRY("1.10", 0x06d6, pentium_m_n733, 3),
422 ENTRY("1.20", 0x06d8, pentium_m_n753, 3),
423 ENTRY("1.30", 0, pentium_m_n773, 3), /* does this exist? */
425 /* ultra low voltage CPUs */
426 ENTRY("1.40", 0x06d6, pentium_m_n738, 3),
427 ENTRY("1.50", 0x06d8, pentium_m_n758, 3),
428 ENTRY("1.60", 0x06d8, pentium_m_n778, 3),
430 /* 'regular' 400 MHz FSB CPUs */
431 ENTRY("1.40", 0x06d6, pentium_m_n710, 3),
432 ENTRY("1.50", 0x06d6, pentium_m_n715, 3),
433 ENTRY("1.60", 0x06d6, pentium_m_n725, 3),
434 ENTRY("1.70", 0x06d6, pentium_m_n735, 3),
435 ENTRY("1.80", 0x06d6, pentium_m_n745, 3),
436 ENTRY("2.00", 0x06d6, pentium_m_n755, 3),
437 ENTRY("2.10", 0x06d6, pentium_m_n765, 3),
439 /* 533 MHz FSB CPUs */
440 ENTRY("1.60", 0x06d8, pentium_m_n730, 4),
441 ENTRY("1.73", 0x06d8, pentium_m_n740, 4),
442 ENTRY("1.73", 0x06d8, pentium_m_n740_2, 4),
443 ENTRY("1.86", 0x06d8, pentium_m_n750, 4),
444 ENTRY("2.00", 0x06d8, pentium_m_n760, 4),
445 ENTRY("2.13", 0x06d8, pentium_m_n770, 4),
451 const char *brand_prefix;
452 const char *brand_suffix;
454 const struct fqlist *list;
457 static const struct est_cpu est_cpus[] = {
459 "Intel(R) Pentium(R) M processor ", "MHz",
460 (sizeof(pentium_m) / sizeof(pentium_m[0])),
464 "Intel(R) Pentium(R) M processor ", "GHz",
465 (sizeof(pentium_m_dothan) / sizeof(pentium_m_dothan[0])),
470 #define NESTCPUS (sizeof(est_cpus) / sizeof(est_cpus[0]))
472 #define MSR2MV(msr) (((int) (msr) & 0xff) * 16 + 700)
473 #define MSR2MHZ(msr) (((((int) (msr) >> 8) & 0xff) * 100 * fsbmult + 1)/ 3)
474 #define MV2MSR(mv) ((((int) (mv) - 700) >> 4) & 0xff)
475 #define MHZ2MSR(mhz) (((3 * (mhz + 30) / (100 * fsbmult)) & 0xff) << 8)
476 /* XXX 30 is slop to deal with the 33.333 MHz roundoff values */
479 * Names and numbers from IA-32 System Programming Guide
480 * (not found in <machine/specialregs.h>
482 #define MSR_PERF_STATUS 0x198
483 #define MSR_PERF_CTL 0x199
485 static const struct fqlist *est_fqlist; /* not NULL if functional */
488 static const char est_desc[] = "Enhanced SpeedStep";
490 static char freqs_available[80];
493 est_sysctl_helper(SYSCTL_HANDLER_ARGS)
496 int fq, oldfq, err = 0;
499 if (est_fqlist == NULL)
502 oldfq = MSR2MHZ(rdmsr(MSR_PERF_CTL));
504 if (req->newptr != NULL) {
505 err = SYSCTL_IN(req, &fq, sizeof(fq));
510 for (i = est_fqlist->tablec - 1; i > 0; i--) {
511 if (est_fqlist->table[i].mhz >= fq)
514 fq = est_fqlist->table[i].mhz;
515 msr = (rdmsr(MSR_PERF_CTL) & ~0xffffULL) |
516 MV2MSR(est_fqlist->table[i].mv) |
517 MHZ2MSR(est_fqlist->table[i].mhz);
518 wrmsr(MSR_PERF_CTL, msr);
521 err = SYSCTL_OUT(req, &oldfq, sizeof(oldfq));
528 * Look for a CPU matching hw.model
530 static const struct fqlist *
531 findcpu(const char *hwmodel, int mv)
533 const struct est_cpu *ccpu;
534 const struct fqlist *fql;
540 for (ccpu = est_cpus; ccpu < est_cpus + NESTCPUS; ++ccpu) {
541 len = strlen(ccpu->brand_prefix);
542 if (strncmp(ccpu->brand_prefix, hwmodel, len) != 0)
545 for (i = 0; i < ccpu->listc; i++) {
546 fql = &ccpu->list[i];
547 len = strlen(fql->brand_tag);
548 if (strncmp(fql->brand_tag, tag, len) != 0 ||
549 strcmp(ccpu->brand_suffix, tag + len))
552 if (fql->cpu_id == 0 || fql->cpu_id == cpu_id) {
553 /* verify operating point is in table, because
554 CPUID + brand_tag still isn't unique. */
555 for (k = fql->tablec - 1; k >= 0; k--) {
556 if (fql->table[k].mv == mv)
566 static struct sysctl_ctx_list machdep_est_ctx;
572 int mib[] = { CTL_HW, HW_MODEL };
573 size_t modellen = sizeof(hwmodel);
574 struct sysctl_oid *oid, *leaf;
577 size_t len, freq_len;
584 #define cpu_feature2 regs[2]
585 #define CPUID2_EST 0x00000080
589 if ((cpu_feature2 & CPUID2_EST) == 0) {
590 printf("Enhanced SpeedStep unsupported on this hardware.\n");
594 modellen = sizeof(hwmodel);
595 err = kernel_sysctl(mib, 2, hwmodel, &modellen, NULL, 0, NULL);
597 printf("kernel_sysctl hw.model failed\n");
601 msr = rdmsr(MSR_PERF_STATUS);
603 printf("%s (%d mV) ", est_desc, mv);
605 est_fqlist = findcpu(hwmodel, mv);
606 if (est_fqlist == NULL) {
607 printf(" - unknown CPU or operating point"
608 "(cpu_id:%#x, msr:%#llx).\n", cpu_id, msr);
613 * OK, tell the user the available frequencies.
615 fsbmult = est_fqlist->fsbmult;
616 printf("%d MHz\n", MSR2MHZ(msr));
618 freq_len = est_fqlist->tablec * (sizeof("9999 ")-1) + 1;
619 if (freq_len >= sizeof(freqs_available)) {
620 printf("increase the size of freqs_available[]\n");
623 freqs_available[0] = '\0';
625 for (i = 0; i < est_fqlist->tablec; i++) {
626 len += snprintf(freqs_available + len, freq_len - len, "%d%s",
627 est_fqlist->table[i].mhz,
628 i < est_fqlist->tablec - 1 ? " " : "");
630 printf("%s frequencies available (MHz): %s\n", est_desc,
634 * Setup the sysctl sub-tree machdep.est.*
636 oid = SYSCTL_ADD_NODE(&machdep_est_ctx,
637 SYSCTL_STATIC_CHILDREN(_machdep), OID_AUTO, "est",
638 CTLFLAG_RD, NULL, "");
641 oid = SYSCTL_ADD_NODE(&machdep_est_ctx, SYSCTL_CHILDREN(oid),
642 OID_AUTO, "frequency", CTLFLAG_RD, NULL, "");
645 leaf = SYSCTL_ADD_PROC(&machdep_est_ctx, SYSCTL_CHILDREN(oid),
646 OID_AUTO, "target", CTLTYPE_INT | CTLFLAG_RW, NULL, NULL,
647 est_sysctl_helper, "I",
648 "Target CPU frequency for Enhanced SpeedStep");
651 leaf = SYSCTL_ADD_PROC(&machdep_est_ctx, SYSCTL_CHILDREN(oid),
652 OID_AUTO, "current", CTLTYPE_INT | CTLFLAG_RD, NULL, NULL,
653 est_sysctl_helper, "I",
654 "Current CPU frequency for Enhanced SpeedStep");
657 leaf = SYSCTL_ADD_STRING(&machdep_est_ctx, SYSCTL_CHILDREN(oid),
658 OID_AUTO, "available", CTLFLAG_RD, freqs_available,
659 sizeof(freqs_available),
660 "CPU frequencies supported by Enhanced SpeedStep");
668 est_modevh(struct module *m __unused, int what, void *arg __unused)
674 error = sysctl_ctx_init(&machdep_est_ctx);
680 error = sysctl_ctx_free(&machdep_est_ctx);
689 static moduledata_t est_mod = {
695 DECLARE_MODULE(est, est_mod, SI_SUB_KLD, SI_ORDER_ANY);