diff options
author | Claudio Jeker <claudio@cvs.openbsd.org> | 2011-05-23 09:54:21 +0000 |
---|---|---|
committer | Claudio Jeker <claudio@cvs.openbsd.org> | 2011-05-23 09:54:21 +0000 |
commit | 959ee871e781f5295e5401b183447c669d28aa44 (patch) | |
tree | 9ed1e841edcae3a1ed42a37db9ac2709ebc37c2b /sys/arch/i386 | |
parent | 1c62370d57329d26ffe2c6fb203f87c82bbe7214 (diff) |
AMD K10/K11 pstate driver allows setperf and apm to change CPU
frequencies on newer AMD systems.
Driver written by Bryan Steele / brynet gmail.com adjusted for i386
by myself. Put it in deraadt@
Diffstat (limited to 'sys/arch/i386')
-rw-r--r-- | sys/arch/i386/conf/files.i386 | 3 | ||||
-rw-r--r-- | sys/arch/i386/i386/k1x-pstate.c | 207 | ||||
-rw-r--r-- | sys/arch/i386/i386/machdep.c | 4 | ||||
-rw-r--r-- | sys/arch/i386/include/cpu.h | 5 |
4 files changed, 216 insertions, 3 deletions
diff --git a/sys/arch/i386/conf/files.i386 b/sys/arch/i386/conf/files.i386 index b4943512159..6c655e0d050 100644 --- a/sys/arch/i386/conf/files.i386 +++ b/sys/arch/i386/conf/files.i386 @@ -1,4 +1,4 @@ -# $OpenBSD: files.i386,v 1.202 2011/04/30 15:33:18 mlarkin Exp $ +# $OpenBSD: files.i386,v 1.203 2011/05/23 09:54:20 claudio Exp $ # # new style config file for i386 architecture # @@ -37,6 +37,7 @@ file arch/i386/i386/pmap.c file arch/i386/i386/powernow.c !small_kernel file arch/i386/i386/powernow-k7.c !small_kernel file arch/i386/i386/powernow-k8.c !small_kernel +file arch/i386/i386/k1x-pstate.c !small_kernel file arch/i386/i386/process_machdep.c file arch/i386/i386/procfs_machdep.c procfs file arch/i386/i386/sys_machdep.c diff --git a/sys/arch/i386/i386/k1x-pstate.c b/sys/arch/i386/i386/k1x-pstate.c new file mode 100644 index 00000000000..875c9a23d6c --- /dev/null +++ b/sys/arch/i386/i386/k1x-pstate.c @@ -0,0 +1,207 @@ +/* $OpenBSD: k1x-pstate.c,v 1.1 2011/05/23 09:54:20 claudio Exp $ */ +/* + * Copyright (c) 2011 Bryan Steele <brynet@gmail.com> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +/* AMD K10/K11 pstate driver */ + +#include <sys/types.h> +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/malloc.h> +#include <sys/proc.h> +#include <sys/sysctl.h> + +#include <machine/cpu.h> +#include <machine/cpufunc.h> +#include <machine/bus.h> + +#include "acpicpu.h" + +#if NACPICPU > 0 +#include <dev/acpi/acpidev.h> +#include <dev/acpi/acpivar.h> +#endif + +extern int setperf_prio; + +#define MSR_K1X_LIMIT 0xc0010061 +#define MSR_K1X_CONTROL 0xc0010062 +#define MSR_K1X_STATUS 0xc0010063 +#define MSR_K1X_CONFIG 0xc0010064 + +/* MSR_K1X_LIMIT */ +#define K1X_PSTATE_MAX_VAL(x) (((x) >> 4) & 0x7) +#define K1X_PSTATE_LIMIT(x) (((x)) & 0x7) + +/* MSR_K1X_CONFIG */ +#define K1X_FID(x) ((x) & 0x3f) +#define K1X_DID(x) (((x) >> 6) & 0x07) + +/* Maximum pstates */ +#define K1X_MAX_STATES 16 + +struct k1x_state { + int freq; + u_int8_t fid; +}; + +struct k1x_cpu_state { + struct k1x_state state_table[K1X_MAX_STATES]; + u_int n_states; +}; + +struct k1x_cpu_state *k1x_current_state; + +void k1x_transition(struct k1x_cpu_state *, int); + +#if NACPICPU > 0 +void k1x_acpi_init(struct k1x_cpu_state *, u_int64_t); +void k1x_acpi_states(struct k1x_cpu_state *, struct acpicpu_pss *, int, + u_int64_t); +#endif + +void +k1x_setperf(int level) +{ + u_int i = 0; + struct k1x_cpu_state *cstate; + + cstate = k1x_current_state; + + i = ((level * cstate->n_states) + 1) / 101; + if (i >= cstate->n_states) + i = cstate->n_states - 1; + + k1x_transition(cstate, i); +} + +void +k1x_transition(struct k1x_cpu_state *cstate, int level) +{ + u_int64_t msr; + int i, cfid, fid = cstate->state_table[level].fid; + + msr = rdmsr(MSR_K1X_STATUS); + cfid = K1X_FID(msr); + + if (fid == cfid) + return; + + if (cfid != fid) { + wrmsr(MSR_K1X_CONTROL, fid); + for (i = 0; i < 100; i++) { + msr = rdmsr(MSR_K1X_STATUS); + if (msr == fid) + break; + DELAY(100); + } + cfid = K1X_FID(msr); + } + if (cfid == fid) { + cpuspeed = cstate->state_table[level].freq; +#if 0 + (void)printf("Target: %d Current: %d Pstate: %d\n", + cstate->state_table[level].freq, + cpuspeed, cfid); +#endif + } +} + +#if NACPICPU > 0 + +void +k1x_acpi_states(struct k1x_cpu_state *cstate, struct acpicpu_pss *pss, + int nstates, u_int64_t msr) +{ + struct k1x_state state; + int j, n; + u_int32_t ctrl; + + for (n = 0; n < cstate->n_states; n++) { + ctrl = pss[n].pss_ctrl; + state.fid = K1X_FID(ctrl); + state.freq = pss[n].pss_core_freq; + j = n; + while (j > 0 && cstate->state_table[j - 1].freq > state.freq) { + memcpy(&cstate->state_table[j], + &cstate->state_table[j - 1], + sizeof(struct k1x_state)); + --j; + } + memcpy(&cstate->state_table[j], &state, + sizeof(struct k1x_state)); + } +} + +void +k1x_acpi_init(struct k1x_cpu_state *cstate, u_int64_t msr) +{ + struct acpicpu_pss *pss; + + cstate->n_states = acpicpu_fetch_pss(&pss); + if (cstate->n_states == 0) + return; + + k1x_acpi_states(cstate, pss, cstate->n_states, msr); + + return; +} + +#endif /* NACPICPU */ + +void +k1x_init(struct cpu_info *ci) +{ + u_int64_t msr; + u_int i; + struct k1x_cpu_state *cstate; + struct k1x_state *state; + + if (setperf_prio > 1) + return; + + cstate = malloc(sizeof(struct k1x_cpu_state), M_DEVBUF, M_NOWAIT); + if (!cstate) + return; + + cstate->n_states = 0; + +#if NACPICPU > 0 + msr = rdmsr(MSR_K1X_STATUS); + k1x_acpi_init(cstate, msr); +#endif + if (cstate->n_states) { + printf("%s: %d MHz: speeds:", + ci->ci_dev.dv_xname, cpuspeed); + for (i = cstate->n_states; i > 0; i--) { + state = &cstate->state_table[i-1]; + printf(" %d", state->freq); + } + printf(" MHz\n"); + k1x_current_state = cstate; + cpu_setperf = k1x_setperf; + setperf_prio = 1; + return; + } + free(cstate, M_DEVBUF); +} diff --git a/sys/arch/i386/i386/machdep.c b/sys/arch/i386/i386/machdep.c index 41d902601ac..355dd681b59 100644 --- a/sys/arch/i386/i386/machdep.c +++ b/sys/arch/i386/i386/machdep.c @@ -1,4 +1,4 @@ -/* $OpenBSD: machdep.c,v 1.494 2011/04/30 15:33:18 mlarkin Exp $ */ +/* $OpenBSD: machdep.c,v 1.495 2011/05/23 09:54:20 claudio Exp $ */ /* $NetBSD: machdep.c,v 1.214 1996/11/10 03:16:17 thorpej Exp $ */ /*- @@ -1345,6 +1345,8 @@ amd_family6_setperf_setup(struct cpu_info *ci) k8_powernow_init(); break; } + if (ci->ci_family == 0x10 || ci->ci_family == 0x11) + k1x_init(ci); } #endif diff --git a/sys/arch/i386/include/cpu.h b/sys/arch/i386/include/cpu.h index 112f0f3b604..bf6481b2c70 100644 --- a/sys/arch/i386/include/cpu.h +++ b/sys/arch/i386/include/cpu.h @@ -1,4 +1,4 @@ -/* $OpenBSD: cpu.h,v 1.119 2011/04/22 15:48:43 kettenis Exp $ */ +/* $OpenBSD: cpu.h,v 1.120 2011/05/23 09:54:20 claudio Exp $ */ /* $NetBSD: cpu.h,v 1.35 1996/05/05 19:29:26 christos Exp $ */ /*- @@ -403,6 +403,9 @@ void k7_powernow_setperf(int); /* powernow-k8.c */ void k8_powernow_init(void); void k8_powernow_setperf(int); +/* k1x-pstate.c */ +void k1x_init(struct cpu_info *); +void k1x_setperf(int); #endif /* npx.c */ |