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--