diff options
author | Gordon Willem Klok <gwk@cvs.openbsd.org> | 2008-08-06 05:24:45 +0000 |
---|---|---|
committer | Gordon Willem Klok <gwk@cvs.openbsd.org> | 2008-08-06 05:24:45 +0000 |
commit | 372faf6c60a9e4a72f255a4887f18d2d410eabe4 (patch) | |
tree | 19063b1fd086b9fee3c7ec59309b93dfc14c3433 /sys/arch/amd64 | |
parent | 40613a758145b6927c82e7002fe08e6df850ed47 (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.c | 268 |
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); } |