Subject: Driver for Enhanced SpeedStep
To: None <port-i386@netbsd.org>
From: Michael Eriksson <mer@klockrike.net>
List: port-i386
Date: 11/02/2003 23:25:37
--CdtdLcLzwN
Content-Type: text/plain; charset=us-ascii
Content-Description: message body text
Content-Transfer-Encoding: 7bit

Tjupp!

I have written a driver for Intel's new CPU frequency control
mechanism, Enhanced SpeedStep (EST), which is used in Pentium M
processors.

I have appended the patches, and welcome any feedback. The patches are
against 1.6X, but I think they should apply easily to the latest
-current.

The frequency control is done with sysctl, which gets these new
variables (the values are from my Compaq Presario X1007EA):

machdep.est_target_frequency = 800
machdep.est_current_frequency = 800
machdep.est_min_frequency = 600
machdep.est_max_frequency = 1400

Only machdep.est_target_frequency is writable. The current frequency
may be lower than the target frequency if the thermal monitor is
throttling the CPU to avoid overheating it.

To use the code:
- Apply the patches.
- Add the line below to the kernel config and rebuild.
options		EST		# Enhanced SpeedStep (Pentium M)
- Do "make includes" in /sys/arch/i386/include to install the new
  sysctl list, and rebuild and install sysctl(8).


Some comments:

* Intel processors now put feature flags also in %ecx, including the
flag for Enhanced SpeedStep. Arguably, cpu_feature should be made an
u_int64_t, but for now I've added a cpu_feature2 variable for the %ecx
flags.

* I've made some additions to the boot-time CPU identification
printouts. This is the diff for my laptop:

 cpu0 at mainbus0: (uniprocessor)
 cpu0: Intel Pentium M (Banias) (686-class), 1395.54 MHz, id 0x695
 cpu0: features a7e9f9bf<FPU,VME,DE,PSE,TSC,MSR,MCE,CX8,SEP,MTRR>
 cpu0: features a7e9f9bf<PGE,MCA,CMOV,PAT,CFLUSH,DS,ACPI,MMX>
 cpu0: features a7e9f9bf<FXSR,SSE,SSE2,TM,SBF>
+cpu0: features2 180<TM2,EST>
+cpu0: "Intel(R) Pentium(R) M processor 1400MHz"
+cpu0: using thermal monitor 2
+cpu0: Enhanced SpeedStep running at 1400 MHz (1484 mV)
+cpu0: available speeds: 1400, 1200, 1000, 800, 600 MHz

Note the new features2 flags. The kernel also prints out the processor
brand string, as reported by the CPUID instruction, and the current
thermal monitor mode if the processor has that feature.

* The EST driver uses the brand string for CPU identification, so
there is a kernel-wide global variable for it.

* The CPU brand string is also available with sysctl:
machdep.cpu_brand = Intel(R) Pentium(R) M processor 1400MHz

/Micke


--CdtdLcLzwN
Content-Type: text/plain
Content-Description: Enhanced SpeedStep diffs
Content-Disposition: inline;
	filename="diff"
Content-Transfer-Encoding: 7bit

Index: sys/arch/i386/conf/files.i386
===================================================================
RCS file: /cvsroot/src/sys/arch/i386/conf/files.i386,v
retrieving revision 1.242
diff -u -r1.242 files.i386
--- sys/arch/i386/conf/files.i386	2003/07/27 01:19:26	1.242
+++ sys/arch/i386/conf/files.i386	2003/11/02 11:27:02
@@ -64,6 +64,9 @@
 defparam opt_beep.h		BEEP_ONHALT_COUNT
 defparam opt_beep.h		BEEP_ONHALT_PITCH BEEP_ONHALT_PERIOD
 
+# Enhanced SpeedStep
+defflag			EST
+
 file	arch/i386/i386/autoconf.c
 file	arch/i386/i386/db_dbgreg.S	ddb | kstack_check_dr0
 file	arch/i386/i386/db_disasm.c	ddb
@@ -467,5 +470,8 @@
 device vesatext
 attach vesatext at vesabios
 file	arch/i386/bios/vesa_text.c	vesatext
+
+# Enhanced SpeedStep
+file	arch/i386/i386/est.c		est
 
 include "arch/i386/conf/majors.i386"
Index: sys/arch/i386/i386/cpu.c
===================================================================
RCS file: /cvsroot/src/sys/arch/i386/i386/cpu.c,v
retrieving revision 1.15
diff -u -r1.15 cpu.c
--- sys/arch/i386/i386/cpu.c	2003/07/14 22:13:10	1.15
+++ sys/arch/i386/i386/cpu.c	2003/11/02 11:27:05
@@ -578,6 +578,7 @@
 
 	cpu_probe_features(ci);
 	cpu_feature &= ci->ci_feature_flags;
+	cpu_feature2 &= ci->ci_feature2_flags;
 
 #ifdef DEBUG
 	if (ci->ci_flags & CPUF_PRESENT)
--- /dev/null	2003-09-02 21:07:04.000000000 +0200
+++ sys/arch/i386/i386/est.c	2003-11-02 12:15:06.000000000 +0100
@@ -0,0 +1,309 @@
+/*
+ * Copyright (c) 2003 Michael Eriksson.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+
+/*
+ * This is a driver for Intel's Enhanced SpeedStep, as implemented in
+ * Pentium M processors.
+ *
+ * Reference documentation:
+ *   
+ * - IA-32 Intel Architecture Software Developer's Manual, Volume 3:
+ *   System Programming Guide.
+ *   Section 13.14, Enhanced Intel SpeedStep technology.
+ *   Table B-2, MSRs in Pentium M Processors.
+ *   http://www.intel.com/design/pentium4/manuals/245472.htm
+ *
+ * - Intel Pentium M Processor Datasheet.
+ *   Table 5, Voltage and Current Specifications.
+ *   http://www.intel.com/design/mobile/datashts/252612.htm
+ *
+ * - Linux cpufreq patches, speedstep-centrino.c.
+ *   Encoding of MSR_PERF_CTL and MSR_PERF_STATUS.
+ *   http://www.codemonkey.org.uk/projects/cpufreq/cpufreq-2.4.22-pre6-1.gz
+ */
+ 
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <machine/cpu.h>
+#include <machine/specialreg.h>
+
+
+struct fq_info {
+	int mhz;
+	int mv;
+};
+
+/* Ultra Low Voltage Intel Pentium M processor 900 MHz */
+static const struct fq_info pentium_m_900[] = {
+	{  900, 1004 },
+	{  800,  988 },
+	{  600,  844 },
+};
+
+/* Ultra Low Voltage Intel Pentium M processor 1.00 GHz */
+static const struct fq_info pentium_m_1000[] = {
+	{ 1000, 1004 },
+	{  900,  988 },
+	{  800,  972 },
+	{  600,  844 },
+};
+
+/* Low Voltage Intel Pentium M processor 1.10 GHz */
+static const struct fq_info pentium_m_1100[] = {
+	{ 1100, 1180 },
+	{ 1000, 1164 },
+	{  900, 1100 },
+	{  800, 1020 },
+	{  600,  956 },
+};
+
+/* Low Voltage Intel Pentium M processor 1.20 GHz */
+static const struct fq_info pentium_m_1200[] = {
+	{ 1200, 1180 },
+	{ 1100, 1164 },
+	{ 1000, 1100 },
+	{  900, 1020 },
+	{  800, 1004 },
+	{  600,  956 },
+};
+
+/* Intel Pentium M processor 1.30 GHz */
+static const struct fq_info pentium_m_1300[] = {
+	{ 1300, 1388 },
+	{ 1200, 1356 },
+	{ 1000, 1292 },
+	{  800, 1260 },
+	{  600,  956 },
+};
+
+/* Intel Pentium M processor 1.40 GHz */
+static const struct fq_info pentium_m_1400[] = {
+	{ 1400, 1484 },
+	{ 1200, 1436 },
+	{ 1000, 1308 },
+	{  800, 1180 },
+	{  600,  956 }
+};
+
+/* Intel Pentium M processor 1.50 GHz */
+static const struct fq_info pentium_m_1500[] = {
+	{ 1500, 1484 },
+	{ 1400, 1452 },
+	{ 1200, 1356 },
+	{ 1000, 1228 },
+	{  800, 1116 },
+	{  600,  956 }
+};
+
+/* Intel Pentium M processor 1.60 GHz */
+static const struct fq_info pentium_m_1600[] = {
+	{ 1600, 1484 },
+	{ 1400, 1420 },
+	{ 1200, 1276 },
+	{ 1000, 1164 },
+	{  800, 1036 },
+	{  600,  956 }
+};
+
+/* Intel Pentium M processor 1.70 GHz */
+static const struct fq_info pentium_m_1700[] = {
+	{ 1700, 1484 },
+	{ 1400, 1308 },
+	{ 1200, 1228 },
+	{ 1000, 1116 },
+	{  800, 1004 },
+	{  600,  956 }
+};
+
+
+struct fqlist {
+	const char *brand_tag;
+	int n;
+	const struct fq_info *table;
+};
+
+static const struct fqlist pentium_m[] = {
+#define ENTRY(s, v)	{ s, sizeof(v) / sizeof((v)[0]), v }
+	ENTRY(" 900", pentium_m_900),
+	ENTRY("1000", pentium_m_1000),
+	ENTRY("1100", pentium_m_1100),
+	ENTRY("1200", pentium_m_1200),
+	ENTRY("1300", pentium_m_1300),
+	ENTRY("1400", pentium_m_1400),
+	ENTRY("1500", pentium_m_1500),
+	ENTRY("1600", pentium_m_1600),
+	ENTRY("1700", pentium_m_1700),
+#undef ENTRY
+};
+
+
+struct est_cpu {
+	const char *brand_prefix;
+	const char *brand_suffix;
+	int n;
+	const struct fqlist *list;
+};
+
+static const struct est_cpu est_cpus[] = {
+	{
+		"Intel(R) Pentium(R) M processor ", "MHz",
+		(sizeof(pentium_m) / sizeof(pentium_m[0])),
+		pentium_m
+	},
+};
+
+#define NCPUS	  (sizeof(est_cpus) / sizeof(est_cpus[0]))
+
+
+#define MSRVALUE(mhz, mv)	((((mhz) / 100) << 8) | (((mv) - 700) / 16))
+#define MSR2MHZ(msr)		((((int) (msr) >> 8) & 0xff) * 100)
+#define MSR2MV(msr)		(((int) (msr) & 0xff) * 16 + 700)
+
+static const struct fqlist *est_fqlist;
+
+
+void
+est_init(ci)
+	struct cpu_info *ci;
+{
+	int i, j, n, mhz, mv;
+	const struct est_cpu *cpu;
+	u_int64_t msr;
+	char *tag;
+	const struct fqlist *fql;
+
+	if ((cpu_feature2 & CPUID2_EST) == 0)
+		return;
+
+	msr = rdmsr(MSR_PERF_STATUS);
+	mhz = MSR2MHZ(msr);
+	mv = MSR2MV(msr);
+	printf("%s: Enhanced SpeedStep running at %d MHz (%d mV)\n",
+	       ci->ci_dev->dv_xname, mhz, mv);
+
+	/*
+	 * Look for a CPU matching cpu_brand_string.
+	 */
+	for (i = 0; est_fqlist == NULL && i < NCPUS; i++) {
+		cpu = &est_cpus[i];
+		n = strlen(cpu->brand_prefix);
+		if (strncmp(cpu->brand_prefix, cpu_brand_string, n) != 0)
+			continue;
+		tag = cpu_brand_string + n;
+		for (j = 0; j < cpu->n; j++) {
+			fql = &cpu->list[j];
+			n = strlen(fql->brand_tag);
+			if (!strncmp(fql->brand_tag, tag, n) &&
+			    !strcmp(cpu->brand_suffix, tag + n)) {
+				est_fqlist = fql;
+				break;
+			}
+		}
+	}
+	if (est_fqlist == NULL) {
+		printf("%s: unknown EST cpu\n", ci->ci_dev->dv_xname);
+		return;
+	}
+
+	/*
+	 * Check that the current operating point is in our list.
+	 */
+	for (i = est_fqlist->n - 1; i >= 0; i--)
+		if (est_fqlist->table[i].mhz == mhz &&
+		    est_fqlist->table[i].mv == mv)
+			break;
+	if (i < 0) {
+		printf("%s: EST operating point not in table\n",
+		    ci->ci_dev->dv_xname);
+		return;
+	}
+
+	/*
+	 * OK, set the flag and tell the user the available frequencies.
+	 */
+	i386_has_est = 1;
+	printf("%s: available speeds: ", ci->ci_dev->dv_xname);
+	for (i = 0; i < est_fqlist->n; i++)
+		printf("%d%s", est_fqlist->table[i].mhz,
+		    i < est_fqlist->n - 1 ? ", " : " MHz\n");
+}
+
+
+int
+est_get_target_fq()
+{
+	return MSR2MHZ(rdmsr(MSR_PERF_CTL));
+}
+
+
+int
+est_set_target_fq(fq)
+	int fq;
+{
+	int i;
+	u_int64_t msr;
+
+	if (est_fqlist == NULL)
+		return EOPNOTSUPP;
+
+	for (i = est_fqlist->n - 1; i > 0; i--)
+		if (est_fqlist->table[i].mhz >= fq)
+			break;
+	fq = est_fqlist->table[i].mhz;
+	msr = (rdmsr(MSR_PERF_CTL) & ~0xffffULL) |
+	    MSRVALUE(est_fqlist->table[i].mhz, est_fqlist->table[i].mv);
+	wrmsr(MSR_PERF_CTL, msr);
+	
+	return 0;
+}
+
+
+int
+est_get_current_fq()
+{
+	return MSR2MHZ(rdmsr(MSR_PERF_STATUS));
+}
+
+
+int
+est_get_min_fq()
+{
+	if (est_fqlist == NULL)
+		return 0;
+	return est_fqlist->table[est_fqlist->n - 1].mhz;
+}
+
+
+int
+est_get_max_fq()
+{
+	if (est_fqlist == NULL)
+		return 0;
+	return est_fqlist->table[0].mhz;
+}
Index: sys/arch/i386/i386/identcpu.c
===================================================================
RCS file: /cvsroot/src/sys/arch/i386/i386/identcpu.c,v
retrieving revision 1.5
diff -u -r1.5 identcpu.c
--- sys/arch/i386/i386/identcpu.c	2003/07/14 22:13:10	1.5
+++ sys/arch/i386/i386/identcpu.c	2003/11/02 11:27:08
@@ -40,6 +40,7 @@
 __KERNEL_RCSID(0, "$NetBSD: identcpu.c,v 1.5 2003/07/14 22:13:10 lukem Exp $");
 
 #include "opt_cputype.h"
+#include "opt_est.h"
 
 #include <sys/param.h>
 #include <sys/systm.h>
@@ -125,6 +126,7 @@
 };
 
 u_int cpu_serial[3];
+char cpu_brand_string[49];
 static char amd_brand_name[48];
 
 void cyrix6x86_cpu_setup __P((struct cpu_info *));
@@ -683,6 +685,7 @@
 	int iterations, i, j;
 	u_int8_t desc;
 	u_int32_t dummy1, dummy2, miscbytes;
+	u_int32_t brand[12];
 
 	if (ci->ci_cpuid_level < 0)
 		return;
@@ -693,10 +696,22 @@
 	    ci->ci_vendor[1]);
 	ci->ci_vendor[3] = 0;
 
+	CPUID(0x80000000, brand[0], brand[1], brand[2], brand[3]);
+	if (brand[0] >= 0x80000004) {
+		CPUID(0x80000002, brand[0], brand[1], brand[2], brand[3]);
+		CPUID(0x80000003, brand[4], brand[5], brand[6], brand[7]);
+		CPUID(0x80000004, brand[8], brand[9], brand[10], brand[11]);
+		for (i = 0; i < 48; i++)
+			if (((char *) brand)[i] != ' ')
+				break;
+		memcpy(cpu_brand_string, ((char *) brand) + i, 48 - i);
+	}
+
 	if (ci->ci_cpuid_level < 1)
 		return;
 
-	CPUID(1, ci->ci_signature, miscbytes, dummy1, ci->ci_feature_flags);
+	CPUID(1, ci->ci_signature, miscbytes, ci->ci_feature2_flags,
+	    ci->ci_feature_flags);
 
 	/* Brand is low order 8 bits of ebx */
 	ci->ci_brand_id = miscbytes & 0xff;
@@ -792,7 +807,6 @@
 {
 	u_int32_t lfunc;
 	u_int32_t descs[4];
-	u_int32_t brand[12];
 	char *p;
 	int i;
 
@@ -806,15 +820,11 @@
 		ci->ci_feature_flags |= descs[3];
 	}
 
-	if (lfunc < 0x80000004)
+	if (*cpu_brand_string == '\0')
 		return;
 	
-	CPUID(0x80000002, brand[0], brand[1], brand[2], brand[3]);
-	CPUID(0x80000003, brand[4], brand[5], brand[6], brand[7]);
-	CPUID(0x80000004, brand[8], brand[9], brand[10], brand[11]);
-
 	for (i = 1; i < sizeof(amd_brand) / sizeof(amd_brand[0]); i++)
-		if ((p = strstr((char *)brand, amd_brand[i])) != NULL) {
+		if ((p = strstr(cpu_brand_string, amd_brand[i])) != NULL) {
 			ci->ci_brand_id = i;
 			strcpy(amd_brand_name, p);
 			break;
@@ -1202,8 +1212,31 @@
 		}
 	}
 
+	if (ci->ci_feature2_flags) {
+		bitmask_snprintf(ci->ci_feature2_flags,
+		    CPUID2_FLAGS, buf, sizeof(buf));
+		printf("%s: features2 %s\n", cpuname, buf);
+	}
+
+	if (*cpu_brand_string != '\0')
+		printf("%s: \"%s\"\n", cpuname, cpu_brand_string);
+
 	x86_print_cacheinfo(ci);
 
+	if (cpu_feature & CPUID_TM) {
+		if (rdmsr(MSR_MISC_ENABLE) & (1 << 3)) {
+			if ((cpu_feature2 & CPUID2_TM2) &&
+			    (rdmsr(MSR_THERM2_CTL) & (1 << 16)))
+				printf("%s: using thermal monitor 2\n",
+				    cpuname);
+			else
+				printf("%s: using thermal monitor 1\n",
+				    cpuname);
+		} else
+			printf("%s: running without thermal monitor!\n",
+			    cpuname);
+	}
+
 	if (ci->ci_cpuid_level >= 3 && (ci->ci_feature_flags & CPUID_PN)) {
 		printf("%s: serial number %04X-%04X-%04X-%04X-%04X-%04X\n",
 		    cpuname,
@@ -1313,4 +1346,15 @@
 	} else
 		i386_use_fxsave = 0;
 #endif /* I686_CPU */
+
+#ifdef EST
+	if (cpu_feature2 & CPUID2_EST) {
+		if (rdmsr(MSR_MISC_ENABLE) & (1 << 16))
+			est_init(ci);
+		else
+			printf("%s: Enhanced SpeedStep disabled by BIOS\n",
+			    cpuname);
+	}
+#endif /* EST */
+
 }
Index: sys/arch/i386/i386/machdep.c
===================================================================
RCS file: /cvsroot/src/sys/arch/i386/i386/machdep.c,v
retrieving revision 1.533
diff -u -r1.533 machdep.c
--- sys/arch/i386/i386/machdep.c	2003/08/24 17:52:30	1.533
+++ sys/arch/i386/i386/machdep.c	2003/11/02 11:27:12
@@ -88,6 +88,7 @@
 #include "opt_mtrr.h"
 #include "opt_multiprocessor.h"
 #include "opt_beep.h"
+#include "opt_est.h"
 
 #include <sys/param.h>
 #include <sys/systm.h>
@@ -225,6 +226,7 @@
 int	dumpmem_low;
 int	dumpmem_high;
 unsigned int cpu_feature;
+unsigned int cpu_feature2;
 int	cpu_class;
 int	i386_fpu_present;
 int	i386_fpu_exception;
@@ -233,6 +235,7 @@
 int	i386_use_fxsave;
 int	i386_has_sse;
 int	i386_has_sse2;
+int	i386_has_est;
 
 int	tmx86_has_longrun;
 
@@ -505,6 +508,9 @@
 	dev_t consdev;
 	struct btinfo_bootpath *bibp;
 	int error, mode;
+#ifdef EST
+	int fq, oldfq;
+#endif
 
 	/* all sysctl names at this level are terminal */
 	if (namelen != 1)
@@ -576,6 +582,36 @@
 			return (EOPNOTSUPP);
 		tmx86_get_longrun_status_all();
 		return (sysctl_rdint(oldp, oldlenp, newp, crusoe_percentage));
+#ifdef EST
+	case CPU_EST_TARG_FREQUENCY:
+		if (!i386_has_est)
+			return (EOPNOTSUPP);
+		fq = oldfq = est_get_target_fq();
+		error = sysctl_int(oldp, oldlenp, newp, newlen, &fq);
+		if (error)
+			return (error);
+		if (fq != oldfq)
+			error = est_set_target_fq(fq);
+		return (error);
+	case CPU_EST_CURR_FREQUENCY:
+		if (!i386_has_est)
+			return (EOPNOTSUPP);
+		return (sysctl_rdint(oldp, oldlenp, newp,
+			    est_get_current_fq()));
+	case CPU_EST_MIN_FREQUENCY:
+		if (!i386_has_est)
+			return (EOPNOTSUPP);
+		return (sysctl_rdint(oldp, oldlenp, newp, est_get_min_fq()));
+	case CPU_EST_MAX_FREQUENCY:
+		if (!i386_has_est)
+			return (EOPNOTSUPP);
+		return (sysctl_rdint(oldp, oldlenp, newp, est_get_max_fq()));
+#endif
+	case CPU_BRAND:
+		if (*cpu_brand_string == '\0')
+			return (EOPNOTSUPP);
+		return (sysctl_rdstring(oldp, oldlenp, newp,
+			    cpu_brand_string));
 	default:
 		return (EOPNOTSUPP);
 	}
@@ -1514,6 +1550,7 @@
 
 	cpu_probe_features(&cpu_info_primary);
 	cpu_feature = cpu_info_primary.ci_feature_flags;
+	cpu_feature2 = cpu_info_primary.ci_feature2_flags;
 
 	lwp0.l_addr = proc0paddr;
 	cpu_info_primary.ci_curpcb = &lwp0.l_addr->u_pcb;
Index: sys/arch/i386/include/cpu.h
===================================================================
RCS file: /cvsroot/src/sys/arch/i386/include/cpu.h,v
retrieving revision 1.103
diff -u -r1.103 cpu.h
--- sys/arch/i386/include/cpu.h	2003/08/07 16:27:58	1.103
+++ sys/arch/i386/include/cpu.h	2003/11/02 11:27:15
@@ -104,7 +104,8 @@
 
 	int32_t		ci_cpuid_level;
 	u_int32_t	ci_signature;	 /* X86 cpuid type */
-	u_int32_t	ci_feature_flags;/* X86 CPUID feature bits */
+	u_int32_t	ci_feature_flags;/* X86 %edx CPUID feature bits */
+	u_int32_t	ci_feature2_flags;/* X86 %ecx CPUID feature bits */
 	u_int32_t	ci_cpu_class;	 /* CPU class */
 	u_int32_t	ci_brand_id;	 /* Intel brand id */
 	u_int32_t	ci_vendor[4];	 /* vendor string */
@@ -325,14 +326,17 @@
 extern int biosbasemem;
 extern int biosextmem;
 extern unsigned int cpu_feature;
+extern unsigned int cpu_feature2;
 extern int cpu;
 extern int cpu_class;
+extern char cpu_brand_string[];
 extern const struct cpu_nocpuid_nameclass i386_nocpuid_cpus[];
 extern const struct cpu_cpuid_nameclass i386_cpuid_cpus[];
 
 extern int i386_use_fxsave;
 extern int i386_has_sse;
 extern int i386_has_sse2;
+extern int i386_has_est;
 
 /* machdep.c */
 void	dumpconf __P((void));
@@ -426,6 +430,14 @@
 void x86_bus_space_init __P((void));
 void x86_bus_space_mallocok __P((void));
 
+/* est.c */
+void est_init __P((struct cpu_info *));
+int est_get_target_fq __P((void));
+int est_set_target_fq __P((int));
+int est_get_current_fq __P((void));
+int est_get_min_fq __P((void));
+int est_get_max_fq __P((void));
+
 #endif /* _KERNEL */
 
 #include <machine/psl.h>
@@ -453,7 +465,12 @@
 #define CPU_TMLR_FREQUENCY	12 	/* int: current frequency */
 #define CPU_TMLR_VOLTAGE	13 	/* int: curret voltage */
 #define CPU_TMLR_PERCENTAGE	14	/* int: current clock percentage */
-#define	CPU_MAXID		15	/* number of valid machdep ids */
+#define CPU_EST_TARG_FREQUENCY	15	/* int: target frequency */
+#define CPU_EST_CURR_FREQUENCY	16	/* int: current frequency */
+#define CPU_EST_MIN_FREQUENCY	17	/* int: min frequency */
+#define CPU_EST_MAX_FREQUENCY	18	/* int: max frequency */
+#define CPU_BRAND		19	/* string: cpu brand */
+#define	CPU_MAXID		20	/* number of valid machdep ids */
 
 #define	CTL_MACHDEP_NAMES { \
 	{ 0, 0 }, \
@@ -471,6 +488,11 @@
 	{ "tm_longrun_frequency", CTLTYPE_INT }, \
 	{ "tm_longrun_voltage", CTLTYPE_INT }, \
 	{ "tm_longrun_percentage", CTLTYPE_INT }, \
+	{ "est_target_frequency",  CTLTYPE_INT }, \
+	{ "est_current_frequency",  CTLTYPE_INT }, \
+	{ "est_min_frequency",  CTLTYPE_INT }, \
+	{ "est_max_frequency",  CTLTYPE_INT }, \
+	{ "cpu_brand", CTLTYPE_STRING }, \
 }
 
 
Index: sys/arch/x86/include/specialreg.h
===================================================================
RCS file: /cvsroot/src/sys/arch/x86/include/specialreg.h,v
retrieving revision 1.3
diff -u -r1.3 specialreg.h
--- sys/arch/x86/include/specialreg.h	2003/08/07 16:30:33	1.3
+++ sys/arch/x86/include/specialreg.h	2003/11/02 11:27:19
@@ -84,7 +84,7 @@
 #define CR4_OSXMMEXCPT	0x00000400	/* enable unmasked SSE exceptions */
 
 /*
- * CPUID "features" bits:
+ * CPUID "features" bits in %edx
  */
 
 #define	CPUID_FPU	0x00000001	/* processor has an FPU? */
@@ -143,6 +143,16 @@
 #define CPUID_EXT_FLAGS3	"\20\31FXSR\32SSE\33SSE2\34B27\35B28\36LONG" \
 				    "\0373DNOW2\0403DNOW"
 
+/*
+ * CPUID "features" bits in %ecx
+ */
+
+#define	CPUID2_TM2	0x00000080	/* Thermal Monitor 2 */
+#define	CPUID2_EST	0x00000100	/* Enhanced SpeedStep Technology */
+#define	CPUID2_CID	0x00000400	/* Context ID */
+
+#define CPUID2_FLAGS	"\20\10TM2\11EST\13CID"
+
 #define CPUID2FAMILY(cpuid)	(((cpuid) >> 8) & 15)
 #define CPUID2MODEL(cpuid)	(((cpuid) >> 4) & 15)
 #define CPUID2STEPPING(cpuid)	((cpuid) & 15)
@@ -187,6 +197,13 @@
 #define MSR_MCG_CTL		0x17b
 #define MSR_EVNTSEL0		0x186
 #define MSR_EVNTSEL1		0x187
+#define MSR_PERF_STATUS		0x198	/* Pentium M */
+#define MSR_PERF_CTL		0x199	/* Pentium M */
+#define MSR_THERM_CONTROL	0x19a
+#define MSR_THERM_INTERRUPT	0x19b
+#define MSR_THERM_STATUS	0x19c
+#define MSR_THERM2_CTL		0x19d	/* Pentium M */
+#define MSR_MISC_ENABLE		0x1a0
 #define MSR_DEBUGCTLMSR		0x1d9
 #define MSR_LASTBRANCHFROMIP	0x1db
 #define MSR_LASTBRANCHTOIP	0x1dc

--CdtdLcLzwN--