diff options
author | Theo de Raadt <deraadt@cvs.openbsd.org> | 2009-02-24 13:20:03 +0000 |
---|---|---|
committer | Theo de Raadt <deraadt@cvs.openbsd.org> | 2009-02-24 13:20:03 +0000 |
commit | fe4e4baedee4cddd29dea2b7a0ec92f4a8a8143e (patch) | |
tree | e2fcfd36676b4270b63898a9b9878a65fe4ae2d2 /sys/arch | |
parent | 0c89a3940f4f8cf8eec242b429efdb56d5dd0d9c (diff) |
back out est.c 1.8 and bring acpicpu.c all the way back to 1.47 because of
hanging machines. backed out correctly this time, as pointed out by tedu.
Diffstat (limited to 'sys/arch')
-rw-r--r-- | sys/arch/amd64/amd64/est.c | 275 |
1 files changed, 167 insertions, 108 deletions
diff --git a/sys/arch/amd64/amd64/est.c b/sys/arch/amd64/amd64/est.c index c2cb44133d1..985df92eda9 100644 --- a/sys/arch/amd64/amd64/est.c +++ b/sys/arch/amd64/amd64/est.c @@ -1,4 +1,4 @@ -/* $OpenBSD: est.c,v 1.8 2008/11/22 16:03:31 gwk Exp $ */ +/* $OpenBSD: est.c,v 1.9 2009/02/24 13:19:59 deraadt Exp $ */ /* * Copyright (c) 2003 Michael Eriksson. * All rights reserved. @@ -56,129 +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; - - nstates = acpicpu_fetch_pss(&pss); - if (nstates <= 0 || nstates > 31) - 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 nstates) +p3_get_bus_clock(struct cpu_info *ci) { - struct fqlist *acpilist; - int needtran = 1, i; u_int64_t msr; - 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); + 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; @@ -186,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; @@ -193,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: @@ -204,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; @@ -246,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); } |