summaryrefslogtreecommitdiff
path: root/sys
diff options
context:
space:
mode:
authorGordon Willem Klok <gwk@cvs.openbsd.org>2008-11-22 16:03:32 +0000
committerGordon Willem Klok <gwk@cvs.openbsd.org>2008-11-22 16:03:32 +0000
commitd240be81552782584f41049a9957e5d0cf7274b3 (patch)
treefe754b70ce1dad3138bfa357b227c4c49a2a7f10 /sys
parent0efa14f6cf6cbfcdd1a67229519a692860cc2849 (diff)
Re-enable ACPI PDC support and fetching cpu performance states
from ACPI for est on amd64. This incorporates a few changes from krw@ to fix minor nits, its unlikely to fix the problems with some machines from acer and dell but lots of machines benefit. ok krw@
Diffstat (limited to 'sys')
-rw-r--r--sys/arch/amd64/amd64/est.c275
-rw-r--r--sys/dev/acpi/acpicpu.c50
2 files changed, 157 insertions, 168 deletions
diff --git a/sys/arch/amd64/amd64/est.c b/sys/arch/amd64/amd64/est.c
index f31c0a4f72d..c2cb44133d1 100644
--- a/sys/arch/amd64/amd64/est.c
+++ b/sys/arch/amd64/amd64/est.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: est.c,v 1.7 2008/08/06 05:24:44 gwk Exp $ */
+/* $OpenBSD: est.c,v 1.8 2008/11/22 16:03:31 gwk Exp $ */
/*
* Copyright (c) 2003 Michael Eriksson.
* All rights reserved.
@@ -56,148 +56,129 @@
#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) \
- ((((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 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;
-int bus_clock;
+#if NACPICPU > 0
+struct fqlist * est_acpi_init(void);
+void est_acpi_pss_changed(struct acpicpu_pss *, int);
-void p4_get_bus_clock(struct cpu_info *);
-void p3_get_bus_clock(struct cpu_info *);
-
-void
-p4_get_bus_clock(struct cpu_info *ci)
+struct fqlist *
+est_acpi_init()
{
- 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;
- }
+ struct acpicpu_pss *pss;
+ struct fqlist *acpilist;
+ int nstates, i;
+
+ nstates = acpicpu_fetch_pss(&pss);
+ if (nstates <= 0 || nstates > 31)
+ 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
-p3_get_bus_clock(struct cpu_info *ci)
+est_acpi_pss_changed(struct acpicpu_pss *pss, int nstates)
{
+ struct fqlist *acpilist;
+ int needtran = 1, i;
u_int64_t msr;
- 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);
+ u_int16_t cur;
+
+ msr = rdmsr(MSR_PERF_STATUS);
+ cur = msr & 0xffff;
+
+ if (nstates <= 0 || nstates > 31) {
+ printf("est_acpi_pss_changed: nstates invalid (%d)", nstates);
+ return;
+ }
+
+ if ((acpilist = malloc(sizeof(struct fqlist), M_DEVBUF, M_NOWAIT))
+ == NULL) {
+ printf("est_acpi_pss_changed: cannot allocate memory for new est state");
+ return;
+ }
+
+ acpilist->n = nstates;
+ 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;
u_int64_t msr;
u_int16_t idhi, idlo, cur;
u_int8_t crhi, crlo, crcur;
@@ -205,17 +186,6 @@ 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;
@@ -223,6 +193,7 @@ 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:
@@ -233,58 +204,27 @@ est_init(struct cpu_info *ci)
*/
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 (est_fqlist == NULL) {
- 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 (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;
- }
- mhz = MSR2MHZ(cur, bus_clock);
- mv = MSR2MV(cur);
- printf("%s: Enhanced SpeedStep %d MHz (%d mV)", cpu_device, mhz, mv);
+#if NACPICPU > 0
+ est_fqlist = est_acpi_init();
+#endif
+ if (est_fqlist == NULL)
+ return;
- 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);
+ printf("%s: Enhanced SpeedStep %d MHz", cpu_device, cpuspeed);
+
+ 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;
@@ -306,7 +246,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;
}
diff --git a/sys/dev/acpi/acpicpu.c b/sys/dev/acpi/acpicpu.c
index 431bfba009d..1240a08c6b7 100644
--- a/sys/dev/acpi/acpicpu.c
+++ b/sys/dev/acpi/acpicpu.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: acpicpu.c,v 1.47 2008/10/11 20:31:50 miod Exp $ */
+/* $OpenBSD: acpicpu.c,v 1.48 2008/11/22 16:03:31 gwk Exp $ */
/*
* Copyright (c) 2005 Marco Peereboom <marco@openbsd.org>
*
@@ -47,6 +47,22 @@ 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
@@ -121,6 +137,8 @@ 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);
@@ -170,6 +188,28 @@ 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(cmd));
+ 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)
@@ -268,6 +308,13 @@ 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
@@ -298,6 +345,7 @@ 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 {