diff options
author | Gordon Willem Klok <gwk@cvs.openbsd.org> | 2009-06-06 23:21:44 +0000 |
---|---|---|
committer | Gordon Willem Klok <gwk@cvs.openbsd.org> | 2009-06-06 23:21:44 +0000 |
commit | d0ca62a445230166bc924e68e43e6e53ceebac82 (patch) | |
tree | 98dcc0ab0af09ba05a467252c3e4b9047abe38da /sys/arch/amd64 | |
parent | 9cb1e5ced8a3c4590f197ee60a7b0464a8533d07 (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.c | 227 |
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; } |