summaryrefslogtreecommitdiff
path: root/sys/arch/amd64
diff options
context:
space:
mode:
authorGordon Willem Klok <gwk@cvs.openbsd.org>2008-08-06 05:24:45 +0000
committerGordon Willem Klok <gwk@cvs.openbsd.org>2008-08-06 05:24:45 +0000
commit372faf6c60a9e4a72f255a4887f18d2d410eabe4 (patch)
tree19063b1fd086b9fee3c7ec59309b93dfc14c3433 /sys/arch/amd64
parent40613a758145b6927c82e7002fe08e6df850ed47 (diff)
Backout the acpicpu_setpdc code and the code to allow est to use acpicpu
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@
Diffstat (limited to 'sys/arch/amd64')
-rw-r--r--sys/arch/amd64/amd64/est.c268
1 files changed, 167 insertions, 101 deletions
diff --git a/sys/arch/amd64/amd64/est.c b/sys/arch/amd64/amd64/est.c
index c1fcd87d753..f31c0a4f72d 100644
--- a/sys/arch/amd64/amd64/est.c
+++ b/sys/arch/amd64/amd64/est.c
@@ -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.
@@ -56,122 +56,148 @@
#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);
}