Subject: Re: Driver for Enhanced SpeedStep
To: Michael Eriksson <mer@klockrike.net>
From: Luke Mewburn <lukem@NetBSD.org>
List: port-i386
Date: 04/27/2004 01:48:12
--ECfFjUQjeBf+wxqf
Content-Type: multipart/mixed; boundary="xrRZJmfMt0dTT4Ad"
Content-Disposition: inline


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

On Mon, Apr 26, 2004 at 03:56:40PM +1000, Luke Mewburn wrote:
  | 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.
  |=20
  | Excellent work!
  |=20
  | 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.

Here's an update.  I've made the changes less intrusive to machdep.c
by moving the sysctl setup to est.c, and reworking the sysctl MIB to
hw.est.  E.g.:

	hw.est.cpu_brand =3D Intel(R) Pentium(R) M processor 1400MHz
	hw.est.frequency.target =3D 600
	hw.est.frequency.current =3D 600
	hw.est.frequency.available =3D 1400 1200 1000 800 600

Frank; Is there any reason that this shouldn't go in ?

Cheers,
Luke.

--xrRZJmfMt0dTT4Ad
Content-Type: text/plain; charset=us-ascii
Content-Description: est.diffs
Content-Disposition: attachment; filename=difz
Content-Transfer-Encoding: quoted-printable

? arch/i386/i386/est.c.1
? arch/i386/i386/est.c.bork1
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 15:44:51 -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 15:44:52 -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 15:44:52 -0000
@@ -0,0 +1,369 @@
+/*
+ * 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 Technology (EST),
+ * 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 <sys/malloc.h>
+#include <sys/sysctl.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;	/* not NULL if functional */
+static char	est_frequencies[sizeof("9999 ") * 10];	/* up to 10 freqs */
+static int	est_node_target, est_node_current;
+
+static int	est_sysctl_helper(SYSCTLFN_PROTO);
+
+void
+est_init(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);
+		est_fqlist =3D NULL;	/* flag as not functional */
+		return;
+	}
+
+	/*
+	 * OK, tell the user the available frequencies.
+	 */
+	n =3D sizeof(est_frequencies);
+	j =3D 0;
+	for (i =3D 0; i < est_fqlist->tablec; i++) {
+		j +=3D snprintf(est_frequencies + j, n - j, "%d%s",
+		    est_fqlist->table[i].mhz,
+		    i < est_fqlist->tablec - 1 ? " " : "");
+	}
+	printf("%s: available speeds (MHz): %s\n",
+	    ci->ci_dev->dv_xname, est_frequencies);
+}
+
+
+SYSCTL_SETUP(sysctl_machdep_speedstep, "sysctl speedstep subtree setup")
+{
+	int rc, est_nodenum, freq_nodenum;
+	struct sysctlnode *node;
+
+	if ((rc =3D sysctl_createv(clog, 0, NULL, NULL,
+	    CTLFLAG_PERMANENT, CTLTYPE_NODE, "hw", NULL,
+	    NULL, 0, NULL, 0, CTL_HW, CTL_EOL)) !=3D 0)
+		goto err;
+
+		/* hw.est */
+	if ((rc =3D sysctl_createv(clog, 0, NULL, &node,
+	    CTLFLAG_PERMANENT, CTLTYPE_NODE, "est", NULL,
+	    NULL, 0, NULL, 0,
+	    CTL_HW, CTL_CREATE, CTL_EOL)) !=3D 0)
+		goto err;
+	est_nodenum =3D node->sysctl_num;
+
+		/* hw.est.cpu_brand */
+	if ((rc =3D sysctl_createv(clog, 0, NULL, &node,
+	    CTLFLAG_PERMANENT, CTLTYPE_STRING, "cpu_brand", NULL,
+	    NULL, 0, &cpu_brand_string, 0,
+	    CTL_HW, est_nodenum, CTL_CREATE, CTL_EOL)) !=3D 0)
+		goto err;
+
+		/* hw.est.frequency */
+	if ((rc =3D sysctl_createv(clog, 0, NULL, &node,
+	    CTLFLAG_PERMANENT, CTLTYPE_NODE, "frequency", NULL,
+	    NULL, 0, NULL, 0,
+	    CTL_HW, est_nodenum, CTL_CREATE, CTL_EOL)) !=3D 0)
+		goto err;
+	freq_nodenum =3D node->sysctl_num;
+
+		/* hw.est.frequency.target */
+	if ((rc =3D sysctl_createv(clog, 0, NULL, &node,
+	    CTLFLAG_PERMANENT|CTLFLAG_READWRITE, CTLTYPE_INT, "target", NULL,
+	    est_sysctl_helper, 0, NULL, 0,
+	    CTL_HW, est_nodenum, freq_nodenum, CTL_CREATE, CTL_EOL)) !=3D 0)
+		goto err;
+	est_node_target =3D node->sysctl_num;
+
+		/* hw.est.frequency.current */
+	if ((rc =3D sysctl_createv(clog, 0, NULL, &node,
+	    CTLFLAG_PERMANENT, CTLTYPE_INT, "current", NULL,
+	    est_sysctl_helper, 0, NULL, 0,
+	    CTL_HW, est_nodenum, freq_nodenum, CTL_CREATE, CTL_EOL)) !=3D 0)
+		goto err;
+	est_node_current =3D node->sysctl_num;
+
+		/* hw.est.frequency.available */
+	if ((rc =3D sysctl_createv(clog, 0, NULL, &node,
+	    CTLFLAG_PERMANENT, CTLTYPE_STRING, "available", NULL,
+	    NULL, 0, &est_frequencies, sizeof(est_frequencies),
+	    CTL_HW, est_nodenum, freq_nodenum, CTL_CREATE, CTL_EOL)) !=3D 0)
+		goto err;
+
+	return;
+ err:
+	printf("%s: sysctl_createv failed (rc =3D %d)\n", __func__, rc);
+}
+
+static int
+est_sysctl_helper(SYSCTLFN_ARGS)
+{
+	struct sysctlnode node;
+	int fq, oldfq, error;
+
+	if (est_fqlist =3D=3D NULL)
+		return (EOPNOTSUPP);
+
+	node =3D *rnode;
+	node.sysctl_data =3D &fq;
+
+	oldfq =3D 0;
+	if (rnode->sysctl_num =3D=3D est_node_target)
+		fq =3D oldfq =3D MSR2MHZ(rdmsr(MSR_PERF_CTL));
+	else if (rnode->sysctl_num =3D=3D est_node_current)
+		fq =3D MSR2MHZ(rdmsr(MSR_PERF_STATUS));
+	else
+		return (EOPNOTSUPP);
+
+	error =3D sysctl_lookup(SYSCTLFN_CALL(&node));
+	if (error || newp =3D=3D NULL)
+		return (error);
+
+	if (rnode->sysctl_num =3D=3D est_node_target && fq !=3D oldfq) {
+		int		i;
+		u_int64_t	msr;
+
+		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);
+	}
+
+	return (0);
+}
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 15:44:52 -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 15:44:53 -0000
@@ -226,6 +226,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;
@@ -1354,6 +1355,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 15:44:53 -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,8 +339,10 @@ 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
@@ -430,6 +433,9 @@ 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 *);
+
 #endif /* _KERNEL */
=20
 /*

--xrRZJmfMt0dTT4Ad--

--ECfFjUQjeBf+wxqf
Content-Type: application/pgp-signature
Content-Disposition: inline

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

iD8DBQFAjS88pBhtmn8zJHIRAg10AKDHq1f5WdR9qWfeBqyvc7r/7/v6DgCeLpLC
ZoqXxy4COv9YLG4ew0MyJCg=
=CaB1
-----END PGP SIGNATURE-----

--ECfFjUQjeBf+wxqf--