diff options
author | Gordon Willem Klok <gwk@cvs.openbsd.org> | 2008-11-22 16:03:32 +0000 |
---|---|---|
committer | Gordon Willem Klok <gwk@cvs.openbsd.org> | 2008-11-22 16:03:32 +0000 |
commit | d240be81552782584f41049a9957e5d0cf7274b3 (patch) | |
tree | fe754b70ce1dad3138bfa357b227c4c49a2a7f10 /sys | |
parent | 0efa14f6cf6cbfcdd1a67229519a692860cc2849 (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.c | 275 | ||||
-rw-r--r-- | sys/dev/acpi/acpicpu.c | 50 |
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 { |