Subject: Re: Driver for Enhanced SpeedStep
To: Michael Eriksson <mer@klockrike.net>
From: Luke Mewburn <lukem@NetBSD.org>
List: port-i386
Date: 04/26/2004 15:56:40
--waoCbV9fObw3XsrB
Content-Type: multipart/mixed; boundary="6L4qsSZ7qhfB8xIa"
Content-Disposition: inline


--6L4qsSZ7qhfB8xIa
Content-Type: text/plain; charset=us-ascii
Content-Disposition: inline
Content-Transfer-Encoding: quoted-printable

On Sun, Nov 02, 2003 at 11:25:37PM +0100, Michael Eriksson wrote:
  | I have written a driver for Intel's new CPU frequency control
  | mechanism, Enhanced SpeedStep (EST), which is used in Pentium M
  | processors.
  |=20
  | 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.

Excellent work!

I've ported these to -current (2.0E, 26 April 2004) and I've attached
the diffs below.  I made some minor changes:
    *	The kernel option is "ENHANCED_SPEEDSTEP" instead of "EST".
    *	Minor variable name & type tweaks in est.c, partially inspired
	by the OpenBSD port of your driver.
(I haven't included any changes to sys/arch/xen)

Stuff that I haven't done which could be done as a separate cleanup
of how power consumption/management works in general:
    *	Provide a sysmon interface.  (The documentation is woeful;
	I have no idea where to start).
    *	Cleaned up the uint32_t cpu_features & cpu_features2 into
	a single uint64_t cpu_features.
    *	Store the info on a per-CPU basis and implement a
	"machdep.cpu.<N>.*" subtree in sysctl that contains
	information such as: Enhanced SpeedStep, CPU brand,
	FPU, SSE, SSE2, ...

I'd be happy enough if this stuff went in without the above resolved,
since they're really a separate issue.  No point in bogging down
useful functionality in a bikeshed discussion.


Cheers,
Luke.

--6L4qsSZ7qhfB8xIa
Content-Type: text/plain; charset=us-ascii
Content-Description: enhanced_speedstep.diff
Content-Disposition: attachment; filename=difz
Content-Transfer-Encoding: quoted-printable

Index: arch/i386/conf/files.i386
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
RCS file: /cvsroot/src/sys/arch/i386/conf/files.i386,v
retrieving revision 1.255
diff -p -p -u -r1.255 files.i386
--- arch/i386/conf/files.i386	18 Apr 2004 18:36:56 -0000	1.255
+++ arch/i386/conf/files.i386	26 Apr 2004 05:43:49 -0000
@@ -61,6 +61,9 @@ defflag opt_beep.h		BEEP_ONHALT
 defparam opt_beep.h		BEEP_ONHALT_COUNT
 defparam opt_beep.h		BEEP_ONHALT_PITCH BEEP_ONHALT_PERIOD
=20
+# Enhanced SpeedStep
+defflag			ENHANCED_SPEEDSTEP
+
 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
@@ -470,4 +473,7 @@ device vesatext
 attach vesatext at vesabios
 file	arch/i386/bios/vesa_text.c	vesatext
=20
+# Enhanced SpeedStep
+file	arch/i386/i386/est.c		enhanced_speedstep
+
 include "arch/i386/conf/majors.i386"
Index: arch/i386/i386/cpu.c
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
RCS file: /cvsroot/src/sys/arch/i386/i386/cpu.c,v
retrieving revision 1.18
diff -p -p -u -r1.18 cpu.c
--- arch/i386/i386/cpu.c	20 Feb 2004 17:35:01 -0000	1.18
+++ arch/i386/i386/cpu.c	26 Apr 2004 05:43:49 -0000
@@ -580,6 +580,7 @@ cpu_hatch(void *v)
=20
 	cpu_probe_features(ci);
 	cpu_feature &=3D ci->ci_feature_flags;
+	cpu_feature2 &=3D ci->ci_feature2_flags;
=20
 #ifdef DEBUG
 	if (ci->ci_flags & CPUF_PRESENT)
Index: arch/i386/i386/est.c
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
RCS file: arch/i386/i386/est.c
diff -N arch/i386/i386/est.c
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ arch/i386/i386/est.c	26 Apr 2004 05:43:49 -0000
@@ -0,0 +1,310 @@
+/*
+ * 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 WARRANTI=
ES
+ * 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 US=
E,
+ * 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:
+ *  =20
+ * - 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
+ */
+=20
+
+#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[] =3D {
+	{  900, 1004 },
+	{  800,  988 },
+	{  600,  844 },
+};
+
+/* Ultra Low Voltage Intel Pentium M processor 1.00 GHz */
+static const struct fq_info pentium_m_1000[] =3D {
+	{ 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[] =3D {
+	{ 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[] =3D {
+	{ 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[] =3D {
+	{ 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[] =3D {
+	{ 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[] =3D {
+	{ 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[] =3D {
+	{ 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[] =3D {
+	{ 1700, 1484 },
+	{ 1400, 1308 },
+	{ 1200, 1228 },
+	{ 1000, 1116 },
+	{  800, 1004 },
+	{  600,  956 }
+};
+
+
+struct fqlist {
+	const char *brand_tag;
+	size_t tablec;
+	const struct fq_info *table;
+};
+
+static const struct fqlist pentium_m[] =3D {
+#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;
+	size_t listc;
+	const struct fqlist *list;
+};
+
+static const struct est_cpu est_cpus[] =3D {
+	{
+		"Intel(R) Pentium(R) M processor ", "MHz",
+		(sizeof(pentium_m) / sizeof(pentium_m[0])),
+		pentium_m
+	},
+};
+
+#define NESTCPUS  (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) =3D=3D 0)
+		return;
+
+	msr =3D rdmsr(MSR_PERF_STATUS);
+	mhz =3D MSR2MHZ(msr);
+	mv =3D 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 =3D 0; est_fqlist =3D=3D NULL && i < NESTCPUS; i++) {
+		cpu =3D &est_cpus[i];
+		n =3D strlen(cpu->brand_prefix);
+		if (strncmp(cpu->brand_prefix, cpu_brand_string, n) !=3D 0)
+			continue;
+		tag =3D cpu_brand_string + n;
+		for (j =3D 0; j < cpu->listc; j++) {
+			fql =3D &cpu->list[j];
+			n =3D strlen(fql->brand_tag);
+			if (!strncmp(fql->brand_tag, tag, n) &&
+			    !strcmp(cpu->brand_suffix, tag + n)) {
+				est_fqlist =3D fql;
+				break;
+			}
+		}
+	}
+	if (est_fqlist =3D=3D NULL) {
+		printf("%s: unknown Enhanced SpeedStep CPU\n",
+		    ci->ci_dev->dv_xname);
+		return;
+	}
+
+	/*
+	 * Check that the current operating point is in our list.
+	 */
+	for (i =3D est_fqlist->tablec - 1; i >=3D 0; i--)
+		if (est_fqlist->table[i].mhz =3D=3D mhz &&
+		    est_fqlist->table[i].mv =3D=3D mv)
+			break;
+	if (i < 0) {
+		printf("%s: Enhanced SpeedStep 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 =3D 1;
+	printf("%s: available speeds: ", ci->ci_dev->dv_xname);
+	for (i =3D 0; i < est_fqlist->tablec; i++)
+		printf("%d%s", est_fqlist->table[i].mhz,
+		    i < est_fqlist->tablec - 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 =3D=3D NULL)
+		return EOPNOTSUPP;
+
+	for (i =3D est_fqlist->tablec - 1; i > 0; i--)
+		if (est_fqlist->table[i].mhz >=3D fq)
+			break;
+	fq =3D est_fqlist->table[i].mhz;
+	msr =3D (rdmsr(MSR_PERF_CTL) & ~0xffffULL) |
+	    MSRVALUE(est_fqlist->table[i].mhz, est_fqlist->table[i].mv);
+	wrmsr(MSR_PERF_CTL, msr);
+=09
+	return 0;
+}
+
+
+int
+est_get_current_fq()
+{
+	return MSR2MHZ(rdmsr(MSR_PERF_STATUS));
+}
+
+
+int
+est_get_min_fq()
+{
+	if (est_fqlist =3D=3D NULL)
+		return 0;
+	return est_fqlist->table[est_fqlist->tablec - 1].mhz;
+}
+
+
+int
+est_get_max_fq()
+{
+	if (est_fqlist =3D=3D NULL)
+		return 0;
+	return est_fqlist->table[0].mhz;
+}
Index: arch/i386/i386/identcpu.c
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
RCS file: /cvsroot/src/sys/arch/i386/i386/identcpu.c,v
retrieving revision 1.12
diff -p -p -u -r1.12 identcpu.c
--- arch/i386/i386/identcpu.c	22 Apr 2004 00:34:52 -0000	1.12
+++ arch/i386/i386/identcpu.c	26 Apr 2004 05:43:50 -0000
@@ -40,6 +40,7 @@
 __KERNEL_RCSID(0, "$NetBSD: identcpu.c,v 1.12 2004/04/22 00:34:52 itojun E=
xp $");
=20
 #include "opt_cputype.h"
+#include "opt_enhanced_speedstep.h"
=20
 #include <sys/param.h>
 #include <sys/systm.h>
@@ -126,6 +127,7 @@ static const char * const amd_brand[] =3D=20
 };
=20
 u_int cpu_serial[3];
+char cpu_brand_string[49];
 static char amd_brand_name[48];
=20
 void cyrix6x86_cpu_setup(struct cpu_info *);
@@ -688,6 +690,7 @@ cpu_probe_base_features(struct cpu_info=20
 	int iterations, i, j;
 	u_int8_t desc;
 	u_int32_t dummy1, dummy2, miscbytes;
+	u_int32_t brand[12];
=20
 	if (ci->ci_cpuid_level < 0)
 		return;
@@ -698,10 +701,22 @@ cpu_probe_base_features(struct cpu_info=20
 	    ci->ci_vendor[1]);
 	ci->ci_vendor[3] =3D 0;
=20
+	CPUID(0x80000000, brand[0], brand[1], brand[2], brand[3]);
+	if (brand[0] >=3D 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 =3D 0; i < 48; i++)
+			if (((char *) brand)[i] !=3D ' ')
+				break;
+		memcpy(cpu_brand_string, ((char *) brand) + i, 48 - i);
+	}
+
 	if (ci->ci_cpuid_level < 1)
 		return;
=20
-	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);
=20
 	/* Brand is low order 8 bits of ebx */
 	ci->ci_brand_id =3D miscbytes & 0xff;
@@ -797,7 +812,6 @@ amd_family6_probe(struct cpu_info *ci)
 {
 	u_int32_t lfunc;
 	u_int32_t descs[4];
-	u_int32_t brand[12];
 	char *p;
 	int i;
=20
@@ -811,15 +825,11 @@ amd_family6_probe(struct cpu_info *ci)
 		ci->ci_feature_flags |=3D descs[3];
 	}
=20
-	if (lfunc < 0x80000004)
+	if (*cpu_brand_string =3D=3D '\0')
 		return;
 =09
-	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 =3D 1; i < sizeof(amd_brand) / sizeof(amd_brand[0]); i++)
-		if ((p =3D strstr((char *)brand, amd_brand[i])) !=3D NULL) {
+		if ((p =3D strstr(cpu_brand_string, amd_brand[i])) !=3D NULL) {
 			ci->ci_brand_id =3D i;
 			strlcpy(amd_brand_name, p, sizeof(amd_brand_name));
 			break;
@@ -1217,8 +1227,31 @@ identifycpu(struct cpu_info *ci)
 		}
 	}
=20
+	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 !=3D '\0')
+		printf("%s: \"%s\"\n", cpuname, cpu_brand_string);
+
 	x86_print_cacheinfo(ci);
=20
+	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 >=3D 3 && (ci->ci_feature_flags & CPUID_PN)) {
 		printf("%s: serial number %04X-%04X-%04X-%04X-%04X-%04X\n",
 		    cpuname,
@@ -1328,4 +1361,15 @@ identifycpu(struct cpu_info *ci)
 	} else
 		i386_use_fxsave =3D 0;
 #endif /* I686_CPU */
+
+#ifdef ENHANCED_SPEEDSTEP
+	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 /* ENHANCED_SPEEDSTEP */
+
 }
Index: arch/i386/i386/machdep.c
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
RCS file: /cvsroot/src/sys/arch/i386/i386/machdep.c,v
retrieving revision 1.552
diff -p -p -u -r1.552 machdep.c
--- arch/i386/i386/machdep.c	24 Mar 2004 15:34:49 -0000	1.552
+++ arch/i386/i386/machdep.c	26 Apr 2004 05:43:50 -0000
@@ -82,6 +82,7 @@ __KERNEL_RCSID(0, "$NetBSD: machdep.c,v=20
 #include "opt_cpureset_delay.h"
 #include "opt_cputype.h"
 #include "opt_ddb.h"
+#include "opt_enhanced_speedstep.h"
 #include "opt_ipkdb.h"
 #include "opt_kgdb.h"
 #include "opt_mtrr.h"
@@ -226,6 +227,7 @@ int	physmem;
 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;
@@ -234,6 +236,7 @@ int	i386_fpu_fdivbug;
 int	i386_use_fxsave;
 int	i386_has_sse;
 int	i386_has_sse2;
+int	i386_has_est;
=20
 int	tmx86_has_longrun;
=20
@@ -441,6 +444,55 @@ sysctl_machdep_tm_longrun(SYSCTLFN_ARGS)
 	return (0);
 }
=20
+#ifdef ENHANCED_SPEEDSTEP
+/*
+ * sysctl helper routine for machdep.est_* nodes.
+ */
+static int
+sysctl_machdep_est(SYSCTLFN_ARGS)
+{
+	struct sysctlnode node;
+	int fq, oldfq, error;
+
+	if (!i386_has_est)
+		return (EOPNOTSUPP);
+
+	node =3D *rnode;
+	node.sysctl_data =3D &fq;
+
+	oldfq =3D 0;
+	switch (rnode->sysctl_num) {
+	case CPU_EST_TARG_FREQUENCY:
+		fq =3D oldfq =3D est_get_target_fq();
+		break;
+	case CPU_EST_CURR_FREQUENCY:
+		fq =3D est_get_current_fq();
+		break;
+	case CPU_EST_MIN_FREQUENCY:
+		fq =3D est_get_min_fq();
+		break;
+	case CPU_EST_MAX_FREQUENCY:
+		fq =3D est_get_max_fq();
+		break;
+	default:
+		return (EOPNOTSUPP);
+	}
+
+	error =3D sysctl_lookup(SYSCTLFN_CALL(&node));
+	if (error || newp =3D=3D NULL)
+		return (error);
+
+	if (rnode->sysctl_num =3D=3D CPU_EST_TARG_FREQUENCY) {
+		if (fq !=3D oldfq)
+			error =3D est_set_target_fq(fq);
+		if (error !=3D 0)
+			return (error);
+	}
+
+	return (0);
+}
+#endif /* ENHANCED_SPEEDSTEP */
+
 /*
  * sysctl helper routine for machdep.booted_kernel
  */
@@ -557,6 +609,36 @@ SYSCTL_SETUP(sysctl_machdep_setup, "sysc
 		       CTLTYPE_INT, "tm_longrun_percentage", NULL,
 		       sysctl_machdep_tm_longrun, 0, NULL, 0,
 		       CTL_MACHDEP, CPU_TMLR_PERCENTAGE, CTL_EOL);
+
+#ifdef ENHANCED_SPEEDSTEP
+	sysctl_createv(clog, 0, NULL, NULL,
+		       CTLFLAG_PERMANENT|CTLFLAG_READWRITE,
+		       CTLTYPE_INT, "est_target_frequency", NULL,
+		       sysctl_machdep_est, 0, NULL, 0,
+		       CTL_MACHDEP, CPU_EST_TARG_FREQUENCY, CTL_EOL);
+	sysctl_createv(clog, 0, NULL, NULL,
+		       CTLFLAG_PERMANENT,
+		       CTLTYPE_INT, "est_current_frequency", NULL,
+		       sysctl_machdep_est, 0, NULL, 0,
+		       CTL_MACHDEP, CPU_EST_CURR_FREQUENCY, CTL_EOL);
+	sysctl_createv(clog, 0, NULL, NULL,
+		       CTLFLAG_PERMANENT,
+		       CTLTYPE_INT, "est_min_frequency", NULL,
+		       sysctl_machdep_est, 0, NULL, 0,
+		       CTL_MACHDEP, CPU_EST_MIN_FREQUENCY, CTL_EOL);
+	sysctl_createv(clog, 0, NULL, NULL,
+		       CTLFLAG_PERMANENT,
+		       CTLTYPE_INT, "est_max_frequency", NULL,
+		       sysctl_machdep_est, 0, NULL, 0,
+		       CTL_MACHDEP, CPU_EST_MAX_FREQUENCY, CTL_EOL);
+#endif /* ENHANCED_SPEEDSTEP */
+
+	    // XXXLM: should return EOPNOTSUPP if cpu_brand_string[0] =3D=3D '\0'
+	sysctl_createv(clog, 0, NULL, NULL,
+		       CTLFLAG_PERMANENT,
+		       CTLTYPE_STRING, "cpu_brand", NULL,
+                       NULL, 0, &cpu_brand_string, 0,
+                       CTL_MACHDEP, CPU_BRAND, CTL_EOL);
 }
=20
 void *
@@ -1354,6 +1436,7 @@ init386(paddr_t first_avail)
=20
 	cpu_probe_features(&cpu_info_primary);
 	cpu_feature =3D cpu_info_primary.ci_feature_flags;
+	cpu_feature2 =3D cpu_info_primary.ci_feature2_flags;
=20
 	lwp0.l_addr =3D proc0paddr;
 	cpu_info_primary.ci_curpcb =3D &lwp0.l_addr->u_pcb;
Index: arch/i386/include/cpu.h
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
RCS file: /cvsroot/src/sys/arch/i386/include/cpu.h,v
retrieving revision 1.113
diff -p -p -u -r1.113 cpu.h
--- arch/i386/include/cpu.h	20 Feb 2004 17:35:01 -0000	1.113
+++ arch/i386/include/cpu.h	26 Apr 2004 05:43:50 -0000
@@ -118,7 +118,8 @@ struct cpu_info {
=20
 	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 */
@@ -338,14 +339,17 @@ struct cpu_cpuid_nameclass {
 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[];
=20
 extern int i386_use_fxsave;
 extern int i386_has_sse;
 extern int i386_has_sse2;
+extern int i386_has_est;
=20
 /* machdep.c */
 void	dumpconf(void);
@@ -430,6 +434,14 @@ void x86_bus_space_mallocok(void);
=20
 #include <machine/psl.h>	/* Must be after struct cpu_info declaration */
=20
+/* est.c */
+void	est_init(struct cpu_info *);
+int	est_get_target_fq(void);
+int	est_set_target_fq(int);
+int	est_get_current_fq(void);
+int	est_get_min_fq(void);
+int	est_get_max_fq(void);
+
 #endif /* _KERNEL */
=20
 /*
@@ -455,7 +467,12 @@ void x86_bus_space_mallocok(void);
 #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 */
=20
 #define	CTL_MACHDEP_NAMES { \
 	{ 0, 0 }, \
@@ -473,6 +490,11 @@ void x86_bus_space_mallocok(void);
 	{ "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 }, \
 }
=20
 /*

--6L4qsSZ7qhfB8xIa--

--waoCbV9fObw3XsrB
Content-Type: application/pgp-signature
Content-Disposition: inline

-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.2.4 (NetBSD)

iD8DBQFAjKSYpBhtmn8zJHIRAqWMAJ0crqqW8gniddBZsLADegT4U9hG3ACgsy8E
O+w2UI28M31a1/t+FnthkZ8=
=nU5q
-----END PGP SIGNATURE-----

--waoCbV9fObw3XsrB--