Backout the acpicpu_setpdc code and the code to allow est to use acpicpu
authorgwk <gwk@openbsd.org>
Wed, 6 Aug 2008 05:24:44 +0000 (05:24 +0000)
committergwk <gwk@openbsd.org>
Wed, 6 Aug 2008 05:24:44 +0000 (05:24 +0000)
on amd64.
Evaluating the _PDC seems to lead to instability (PR5878 and a report by
jmc@) on lower end machines its too close to release and I don't have
enough nickels.

ok deraadt@

sys/arch/amd64/amd64/est.c
sys/dev/acpi/acpicpu.c

index c1fcd87..f31c0a4 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: est.c,v 1.6 2008/06/15 05:24:07 gwk Exp $ */
+/*     $OpenBSD: est.c,v 1.7 2008/08/06 05:24:44 gwk Exp $ */
 /*
  * Copyright (c) 2003 Michael Eriksson.
  * All rights reserved.
 #include <sys/param.h>
 #include <sys/systm.h>
 #include <sys/sysctl.h>
-#include <sys/malloc.h>
 
 #include <machine/cpu.h>
 #include <machine/cpufunc.h>
 #include <machine/specialreg.h>
-#include <machine/bus.h>
 
-#include "acpicpu.h"
+#define CPUVENDOR_INTEL 0
+#define CPUVENDOR_VIA 8
 
-#if NACPICPU > 0
-#include <dev/acpi/acpidev.h>
-#include <dev/acpi/acpivar.h>
-#endif
 
-struct est_op {
-       uint16_t ctrl;
-       uint16_t mhz;
-};
+/* Convert MHz and mV into IDs for passing to the MSR. */
+#define ID16(MHz, mV, bus_clk) \
+       ((((MHz * 100 + 50) / bus_clk) << 8) | ((mV ? mV - 700 : 0) >> 4))
+
+/* Possible bus speeds (multiplied by 100 for rounding) */
+#define BUS100 10000
+#define BUS133 13333
+#define BUS166 16667
+#define BUS200 20000
+#define BUS266 26667
+#define BUS333 33333
+
+#define MSR2MHZ(msr, bus) \
+       (((((int) (msr) >> 8) & 0xff) * (bus) + 50) / 100)
+#define MSR2MV(msr) \
+       (((int) (msr) & 0xff) * 16 + 700)
 
 struct fqlist {
+       int vendor: 5;
+       unsigned bus_clk : 1;
        unsigned n : 5;
-       struct est_op *table;
+       const u_int16_t *table;
 };
 
+static const struct fqlist *est_fqlist;
 
-static struct fqlist *est_fqlist;
+static u_int16_t fake_table[3];
+static struct fqlist fake_fqlist;
 
 extern int setperf_prio;
 extern int perflevel;
 
-#if NACPICPU > 0
-struct fqlist * est_acpi_init(void);
-void est_acpi_pss_changed(struct acpicpu_pss *, int);
-
-struct fqlist *
-est_acpi_init()
-{
-       struct acpicpu_pss *pss;
-       struct fqlist *acpilist;
-       int nstates, i;
-
-       if ((nstates = acpicpu_fetch_pss(&pss)) == 0)
-               goto nolist;
+int bus_clock;
 
-       if ((acpilist = malloc(sizeof(struct fqlist), M_DEVBUF, M_NOWAIT))
-           == NULL)
-               goto nolist;
+void p4_get_bus_clock(struct cpu_info *);
+void p3_get_bus_clock(struct cpu_info *);
 
-       if ((acpilist->table = malloc(sizeof(struct est_op) * nstates, M_DEVBUF,
-          M_NOWAIT)) == NULL)
-               goto notable;
-
-       acpilist->n = nstates;
-
-       for (i = 0; i < nstates; i++) {
-               acpilist->table[i].mhz = pss[i].pss_core_freq;
-               acpilist->table[i].ctrl = pss[i].pss_ctrl;
+void
+p4_get_bus_clock(struct cpu_info *ci)
+{
+       u_int64_t msr;
+       int model, bus;
+
+       model = (ci->ci_signature >> 4) & 15;
+       msr = rdmsr(MSR_EBC_FREQUENCY_ID);
+       if (model < 2) {
+               bus = (msr >> 21) & 0x7;
+               switch (bus) {
+               case 0:
+                       bus_clock = BUS100;
+                       break;
+               case 1:
+                       bus_clock = BUS133;
+                       break;
+               default:
+                       printf("%s: unknown Pentium 4 (model %d) "
+                           "EBC_FREQUENCY_ID value %d\n",
+                           ci->ci_dev->dv_xname, model, bus);
+                       break;
+               }
+       } else {
+               bus = (msr >> 16) & 0x7;
+               switch (bus) {
+               case 0:
+                       bus_clock = (model == 2) ? BUS100 : BUS266;
+                       break;
+               case 1:
+                       bus_clock = BUS133;
+                       break;
+               case 2:
+                       bus_clock = BUS200;
+                       break;
+               case 3:
+                       bus_clock = BUS166;
+                       break;
+               default:
+                       printf("%s: unknown Pentium 4 (model %d) "
+                           "EBC_FREQUENCY_ID value %d\n",
+                           ci->ci_dev->dv_xname, model, bus);
+                       break;
+               }
        }
-
-       acpicpu_set_notify(est_acpi_pss_changed);
-
-       return acpilist;
-
-notable:
-       free(acpilist, M_DEVBUF);
-       acpilist = NULL;
-nolist:
-       return NULL;
 }
 
 void
-est_acpi_pss_changed(struct acpicpu_pss *pss, int npss)
+p3_get_bus_clock(struct cpu_info *ci)
 {
-       struct fqlist *acpilist;
-       int needtran = 1, nstates, i;
        u_int64_t msr;
-       u_int16_t cur;
-
-       msr = rdmsr(MSR_PERF_STATUS);
-       cur = msr & 0xffff;
-
-       if ((acpilist = malloc(sizeof(struct fqlist), M_DEVBUF, M_NOWAIT))
-           == NULL) {
-               printf("est_acpi_pss_changed: cannot allocate memory for new est state");
-               return;
-       }
-
-       if ((acpilist->table = malloc(sizeof(struct est_op) * nstates, M_DEVBUF,
-          M_NOWAIT)) == NULL) {
-               printf("est_acpi_pss_changed: cannot allocate memory for new operating points");
-               free(acpilist, M_DEVBUF);
-               return;
-       }
-
-       for (i = 0; i < nstates; i++) {
-               acpilist->table[i].mhz = pss[i].pss_core_freq;
-               acpilist->table[i].ctrl = pss[i].pss_ctrl;
-               if (pss[i].pss_ctrl == cur)
-                       needtran = 0;
-       }
-
-       free(est_fqlist->table, M_DEVBUF);
-       free(est_fqlist, M_DEVBUF);
-       est_fqlist = acpilist;
-
-       if (needtran) {
-               est_setperf(perflevel);
+       int model, bus;
+
+       model = (ci->ci_signature >> 4) & 15;
+       switch (model) {
+       case 0xe: /* Core Duo/Solo */
+       case 0xf: /* Core Xeon */
+               msr = rdmsr(MSR_FSB_FREQ);
+               bus = (msr >> 0) & 0x7;
+               switch (bus) {
+               case 5:
+                       bus_clock = BUS100;
+                       break;
+               case 1:
+                       bus_clock = BUS133;
+                       break;
+               case 3:
+                       bus_clock = BUS166;
+                       break;
+               case 2:
+                       bus_clock = BUS200;
+                       break;
+               case 0:
+                       bus_clock = BUS266;
+                       break;
+               case 4:
+                       bus_clock = BUS333;
+                       break;
+               default:
+                       printf("%s: unknown Core FSB_FREQ value %d",
+                           ci->ci_dev->dv_xname, bus);
+                       break;
+               }
+               break;
+       default: 
+               printf("%s: unknown i686 model %d, can't get bus clock",
+                   ci->ci_dev->dv_xname, model);
        }
 }
-#endif
 
 void
 est_init(struct cpu_info *ci)
 {
        const char *cpu_device = ci->ci_dev->dv_xname;
-       int i, low, high;
+       int vendor = -1;
+       int i, mhz, mv, low, high, family;
        u_int64_t msr;
        u_int16_t idhi, idlo, cur;
        u_int8_t crhi, crlo, crcur;
@@ -179,6 +205,17 @@ est_init(struct cpu_info *ci)
        if (setperf_prio > 3)
                return;
 
+       family = (ci->ci_signature >> 8) & 15;
+       if (family == 0xf) {
+               p4_get_bus_clock(ci);
+       } else if (family == 6) {
+               p3_get_bus_clock(ci);
+       }
+       if (bus_clock == 0) {
+               printf("%s: EST: unknown system bus clock\n", cpu_device);
+               return;
+       }
+
        msr = rdmsr(MSR_PERF_STATUS);
        idhi = (msr >> 32) & 0xffff;
        idlo = (msr >> 48) & 0xffff;
@@ -186,7 +223,6 @@ est_init(struct cpu_info *ci)
        crhi = (idhi  >> 8) & 0xff;
        crlo = (idlo  >> 8) & 0xff;
        crcur = (cur >> 8) & 0xff;
-
        if (crlo == 0 || crhi == crlo) {
                /*
                 * Don't complain about these cases, and silently disable EST:
@@ -197,27 +233,58 @@ est_init(struct cpu_info *ci)
                 */
                return;
        }
-
-
-#if NACPICPU > 0
-               est_fqlist = est_acpi_init();
-#endif
-       if (est_fqlist == NULL)
+       if (crhi == 0 || crcur == 0 || crlo > crhi ||
+           crcur < crlo || crcur > crhi) {
+               /*
+                * Do complain about other weirdness, because we first want to
+                * know about it, before we decide what to do with it.
+                */
+               printf("%s: EST: strange msr value 0x%016llx\n",
+                   cpu_device, msr);
                return;
+       }
+       if (est_fqlist == NULL) {
+               printf("%s: unknown Enhanced SpeedStep CPU, msr 0x%016llx\n",
+                   cpu_device, msr);
 
-       printf("%s: Enhanced SpeedStep %d MHz", cpu_device, cpuspeed);
+               /*
+                * Generate a fake table with the power states we know.
+                */
+               fake_table[0] = idhi;
+               if (cur == idhi || cur == idlo) {
+                       printf("%s: using only highest and lowest power "
+                           "states\n", cpu_device);
+
+                       fake_table[1] = idlo;
+                       fake_fqlist.n = 2;
+               } else {
+                       printf("%s: using only highest, current and lowest "
+                           "power states\n", cpu_device);
+
+                       fake_table[1] = cur;
+                       fake_table[2] = idlo;
+                       fake_fqlist.n = 3;
+               }
+               fake_fqlist.vendor = vendor;
+               fake_fqlist.table = fake_table;
+               est_fqlist = &fake_fqlist;
+       }
 
-       low = est_fqlist->table[est_fqlist->n - 1].mhz;
-       high = est_fqlist->table[0].mhz;
-       perflevel = (cpuspeed - low) * 100 / (high - low);
+       mhz = MSR2MHZ(cur, bus_clock);
+       mv = MSR2MV(cur);
+       printf("%s: Enhanced SpeedStep %d MHz (%d mV)", cpu_device, mhz, mv);
+
+       low = MSR2MHZ(est_fqlist->table[est_fqlist->n - 1], bus_clock);
+       high = MSR2MHZ(est_fqlist->table[0], bus_clock);
+       perflevel = (mhz - low) * 100 / (high - low);
 
        /*
         * OK, tell the user the available frequencies.
         */
        printf(": speeds: ");
        for (i = 0; i < est_fqlist->n; i++)
-               printf("%d%s", est_fqlist->table[i].mhz, i < est_fqlist->n - 1 ?
-                   ", " : " MHz\n");
+               printf("%d%s", MSR2MHZ(est_fqlist->table[i], bus_clock),
+                   i < est_fqlist->n - 1 ? ", " : " MHz\n");
 
        cpu_setperf = est_setperf;
        setperf_prio = 3;
@@ -239,8 +306,7 @@ est_setperf(int level)
 
        msr = rdmsr(MSR_PERF_CTL);
        msr &= ~0xffffULL;
-       msr |= est_fqlist->table[i].ctrl;
-
+       msr |= est_fqlist->table[i];
        wrmsr(MSR_PERF_CTL, msr);
-       cpuspeed = est_fqlist->table[i].mhz;
+       cpuspeed = MSR2MHZ(est_fqlist->table[i], bus_clock);
 }
index 47c275b..2e9ee2d 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: acpicpu.c,v 1.44 2008/06/15 05:24:07 gwk Exp $ */
+/* $OpenBSD: acpicpu.c,v 1.45 2008/08/06 05:24:44 gwk Exp $ */
 /*
  * Copyright (c) 2005 Marco Peereboom <marco@openbsd.org>
  *
@@ -47,22 +47,6 @@ void acpicpu_setperf(int);
 #define ACPI_STATE_C2          0x02
 #define ACPI_STATE_C3          0x03
 
-#define ACPI_PDC_REVID         0x1
-#define ACPI_PDC_SMP           0xa
-#define ACPI_PDC_MSR           0x1
-
-/* _PDC Intel capabilities flags from linux */
-#define ACPI_PDC_P_FFH         0x0001
-#define ACPI_PDC_C_C1_HALT     0x0002
-#define ACPI_PDC_T_FFH         0x0004
-#define ACPI_PDC_SMP_C1PT      0x0008
-#define ACPI_PDC_SMP_C2C3      0x0010
-#define ACPI_PDC_SMP_P_SWCOORD 0x0020
-#define ACPI_PDC_SMP_C_SWCOORD 0x0040
-#define ACPI_PDC_SMP_T_SWCOORD 0x0080
-#define ACPI_PDC_C_C1_FFH      0x0100
-#define ACPI_PDC_C_C2C3_FFH    0x0200
-
 #define FLAGS_NO_C2            0x01
 #define FLAGS_NO_C3            0x02
 #define FLAGS_BMCHECK          0x04
@@ -137,8 +121,6 @@ int acpicpu_getpct(struct acpicpu_softc *);
 int    acpicpu_getpss(struct acpicpu_softc *);
 struct acpi_cstate *acpicpu_add_cstate(struct acpicpu_softc *, int, int, int,
     int);
-void   acpicpu_set_pdc(struct acpicpu_softc *);
-
 #if 0
 void    acpicpu_set_throttle(struct acpicpu_softc *, int);
 struct acpi_cstate *acpicpu_find_cstate(struct acpicpu_softc *, int);
@@ -188,28 +170,6 @@ acpicpu_find_cstate(struct acpicpu_softc *sc, int type)
 }
 #endif
 
-
-void
-acpicpu_set_pdc(struct acpicpu_softc *sc) {
-       struct aml_value cmd;
-       struct aml_value res;
-       uint32_t buf[3];
-
-       memset(&cmd, 0, sizeof(buf));
-       cmd.type = AML_OBJTYPE_BUFFER;
-       cmd.v_buffer = (uint8_t *)&buf;
-       cmd.length = sizeof(buf);
-
-       buf[0] = ACPI_PDC_REVID;
-       buf[1] = 1;
-       buf[2] = ACPI_PDC_C_C1_HALT | ACPI_PDC_P_FFH | ACPI_PDC_C_C1_FFH
-           | ACPI_PDC_C_C2C3_FFH | ACPI_PDC_SMP_P_SWCOORD | ACPI_PDC_SMP_C2C3
-           | ACPI_PDC_SMP_C1PT;
-
-       aml_evalname(sc->sc_acpi, sc->sc_devnode, "_PDC", 1, &cmd, &res);
-}
-
-
 struct acpi_cstate *
 acpicpu_add_cstate(struct acpicpu_softc *sc, int type, int latency, int power,
     int address)
@@ -308,13 +268,6 @@ acpicpu_attach(struct device *parent, struct device *self, void *aux)
        }
        sc->sc_duty_off = sc->sc_acpi->sc_fadt->duty_offset;
        sc->sc_duty_wid = sc->sc_acpi->sc_fadt->duty_width;
-
-#if defined(amd64)
-       if (strcmp(cpu_vendor, "GenuineIntel") == 0)
-               if (cpu_ecxfeature & CPUIDECX_EST)
-                       acpicpu_set_pdc(sc);
-#endif
-
        if (!valid_throttle(sc->sc_duty_off, sc->sc_duty_wid, sc->sc_pblk_addr))
                sc->sc_flags |= FLAGS_NOTHROTTLE;
 #ifdef ACPI_DEBUG
@@ -345,7 +298,6 @@ acpicpu_attach(struct device *parent, struct device *self, void *aux)
                    sc->sc_acpi->sc_fadt->p_lvl3_lat, -1,
                    sc->sc_pblk_addr + 5);
        }
-
        if (acpicpu_getpss(sc)) {
                sc->sc_flags |= FLAGS_NOPSS;
        } else {