Source-Changes-HG archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

[src/trunk]: src/sys/arch/i386/i386 Add driver for Enhanced SpeedStep (in Pen...



details:   https://anonhg.NetBSD.org/src/rev/13c4f7a23511
branches:  trunk
changeset: 566179:13c4f7a23511
user:      lukem <lukem%NetBSD.org@localhost>
date:      Fri Apr 30 01:56:12 2004 +0000

description:
Add driver for Enhanced SpeedStep (in Pentium M processors),
written by Michael Eriksson and posted to port-i386 on 20031102.
(This is the driver "as is" - I'll commit the code to integrate it
into -current separately)

diffstat:

 sys/arch/i386/i386/est.c |  309 +++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 309 insertions(+), 0 deletions(-)

diffs (truncated from 313 to 300 lines):

diff -r 0c89d67474dc -r 13c4f7a23511 sys/arch/i386/i386/est.c
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/sys/arch/i386/i386/est.c  Fri Apr 30 01:56:12 2004 +0000
@@ -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()
+{



Home | Main Index | Thread Index | Old Index