summaryrefslogtreecommitdiff
path: root/sys/arch/amd64
diff options
context:
space:
mode:
authorGordon Willem Klok <gwk@cvs.openbsd.org>2009-06-06 23:21:44 +0000
committerGordon Willem Klok <gwk@cvs.openbsd.org>2009-06-06 23:21:44 +0000
commitd0ca62a445230166bc924e68e43e6e53ceebac82 (patch)
tree98dcc0ab0af09ba05a467252c3e4b9047abe38da /sys/arch/amd64
parent9cb1e5ced8a3c4590f197ee60a7b0464a8533d07 (diff)
Update est.c, make it capable of using ACPI if the PSS is available but
still support all different methods of getting states without e.g. (highest/lowest state), and on i386 use the tables. The only change should be the deletion of the mV from the printf at boot. ok jsg@
Diffstat (limited to 'sys/arch/amd64')
-rw-r--r--sys/arch/amd64/amd64/est.c227
1 files changed, 176 insertions, 51 deletions
diff --git a/sys/arch/amd64/amd64/est.c b/sys/arch/amd64/amd64/est.c
index 7f54997c322..082f89bd05c 100644
--- a/sys/arch/amd64/amd64/est.c
+++ b/sys/arch/amd64/amd64/est.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: est.c,v 1.11 2009/04/23 07:30:03 jsg Exp $ */
+/* $OpenBSD: est.c,v 1.12 2009/06/06 23:21:43 gwk Exp $ */
/*
* Copyright (c) 2003 Michael Eriksson.
* All rights reserved.
@@ -56,14 +56,22 @@
#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>
#define CPUVENDOR_INTEL 0
#define CPUVENDOR_VIA 8
+#include "acpicpu.h"
+
+#if NACPICPU > 0
+#include <dev/acpi/acpidev.h>
+#include <dev/acpi/acpivar.h>
+#endif
/* Convert MHz and mV into IDs for passing to the MSR. */
#define ID16(MHz, mV, bus_clk) \
@@ -78,21 +86,22 @@
#define BUS333 33333
#define MSR2MHZ(msr, bus) \
- (((((int) (msr) >> 8) & 0xff) * (bus) + 50) / 100)
-#define MSR2MV(msr) \
- (((int) (msr) & 0xff) * 16 + 700)
+ (((((int)(msr) >> 8) & 0xff) * (bus) + 50) / 100)
+
+struct est_op {
+ uint16_t ctrl;
+ uint16_t mhz;
+};
struct fqlist {
int vendor: 5;
unsigned bus_clk : 1;
unsigned n : 5;
- const u_int16_t *table;
+ struct est_op *table;
};
-static const struct fqlist *est_fqlist;
-static u_int16_t fake_table[3];
-static struct fqlist fake_fqlist;
+static struct fqlist *est_fqlist;
extern int setperf_prio;
extern int perflevel;
@@ -206,21 +215,106 @@ p3_get_bus_clock(struct cpu_info *ci)
break;
}
break;
- default:
+ default:
printf("%s: unknown i686 model 0x%x, can't get bus clock\n",
ci->ci_dev->dv_xname, ci->ci_model);
}
}
+#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;
+
+ if ((acpilist = malloc(sizeof(struct fqlist), M_DEVBUF, M_NOWAIT))
+ == NULL)
+ goto nolist;
+
+ 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;
+ }
+
+ 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)
+{
+ 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);
+ }
+}
+#endif
+
void
est_init(struct cpu_info *ci)
{
const char *cpu_device = ci->ci_dev->dv_xname;
int vendor = -1;
- int i, mhz, mv, low, high, family;
+ int i, low, high, family;
u_int64_t msr;
u_int16_t idhi, idlo, cur;
u_int8_t crhi, crlo, crcur;
+ struct fqlist *fake_fqlist;
+ struct est_op *fake_table;
if (setperf_prio > 3)
return;
@@ -243,68 +337,98 @@ 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:
- * - A lowest clock ratio of 0, which seems to happen on all
- * Pentium 4's that report EST.
- * - An equal highest and lowest clock ratio, which happens on
- * at least the Core 2 Duo X6800, maybe on newer models too.
- */
- return;
- }
- 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 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 (crlo == 0 || crhi == crlo) {
+ /*
+ * Don't complain about these cases, and silently
+ * disable EST: - A lowest clock ratio of 0, which
+ * seems to happen on all Pentium 4's that report EST.
+ * - An equal highest and lowest clock ratio, which
+ * happens on at least the Core 2 Duo X6800, maybe on
+ * newer models too.
+ */
+ return;
+ }
+
printf("%s: unknown Enhanced SpeedStep CPU, msr 0x%016llx\n",
cpu_device, msr);
-
/*
* Generate a fake table with the power states we know.
*/
- fake_table[0] = idhi;
+
+ if ((fake_fqlist = malloc(sizeof(struct fqlist), M_DEVBUF,
+ M_NOWAIT)) == NULL) {
+ printf("%s: cannot allocate memory for fake list",
+ cpu_device);
+ return;
+ }
+
+
+ if ((fake_table = malloc(sizeof(struct est_op) * 3, M_DEVBUF,
+ M_NOWAIT)) == NULL) {
+ free(fake_fqlist, M_DEVBUF);
+ printf("%s: cannot allocate memory for fake table",
+ cpu_device);
+ return;
+ }
+ fake_table[0].ctrl = idhi;
+ fake_table[0].mhz = MSR2MHZ(idhi, bus_clock);
if (cur == idhi || cur == idlo) {
printf("%s: using only highest and lowest power "
- "states\n", cpu_device);
+ "states\n", cpu_device);
- fake_table[1] = idlo;
- fake_fqlist.n = 2;
+ fake_table[1].ctrl = idlo;
+ fake_table[1].mhz = MSR2MHZ(idlo, bus_clock);
+ 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_table[1].ctrl = cur;
+ fake_table[1].mhz = MSR2MHZ(cur, bus_clock);
+
+ fake_table[2].ctrl = idlo;
+ fake_table[2].mhz = MSR2MHZ(idlo, bus_clock);
+ fake_fqlist->n = 3;
}
- fake_fqlist.vendor = vendor;
- fake_fqlist.table = fake_table;
- est_fqlist = &fake_fqlist;
+
+ fake_fqlist->vendor = vendor;
+ fake_fqlist->table = fake_table;
+ est_fqlist = fake_fqlist;
}
- mhz = MSR2MHZ(cur, bus_clock);
- mv = MSR2MV(cur);
- printf("%s: Enhanced SpeedStep %d MHz (%d mV)", cpu_device, mhz, mv);
+ if (est_fqlist == NULL)
+ return;
+
+ printf("%s: Enhanced SpeedStep %d MHz", cpu_device, cpuspeed);
- 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);
+ low = est_fqlist->table[est_fqlist->n - 1].mhz;
+ high = est_fqlist->table[0].mhz;
+ perflevel = (cpuspeed - low) * 100 / (high - low);
/*
* OK, tell the user the available frequencies.
*/
printf(": speeds: ");
for (i = 0; i < est_fqlist->n; i++)
- printf("%d%s", MSR2MHZ(est_fqlist->table[i], bus_clock),
- i < est_fqlist->n - 1 ? ", " : " MHz\n");
+ printf("%d%s", est_fqlist->table[i].mhz, i < est_fqlist->n - 1
+ ? ", " : " MHz\n");
cpu_setperf = est_setperf;
setperf_prio = 3;
@@ -326,7 +450,8 @@ est_setperf(int level)
msr = rdmsr(MSR_PERF_CTL);
msr &= ~0xffffULL;
- msr |= est_fqlist->table[i];
+ msr |= est_fqlist->table[i].ctrl;
+
wrmsr(MSR_PERF_CTL, msr);
- cpuspeed = MSR2MHZ(est_fqlist->table[i], bus_clock);
+ cpuspeed = est_fqlist->table[i].mhz;
}