On Thu, May 19, 2011 at 10:35:55PM +0200, Claudio Jeker wrote: > On Thu, May 19, 2011 at 03:52:02PM -0400, Brynet wrote: > > Adds support for family 10h/11h AMD processors, not sure if it's the > > best way to do this.. but it works and noticably lowers the temperatures > > reported by the die sensors. > > > > # sysctl hw.setperf=0 # echo "apmd_flags=\"-C\"" >> /etc/rc.conf.local > > > > Just putting it here again for testing, could also be easily adapted for > > amd64 running on i386, but I don't do that. > > > > Since my new amd64 runs i386 at the moment I ported the code over. >
Tested on my low-end Sempron and it seems ok, amd64. -ml > cpu0: AMD Phenom(tm) II X6 1055T Processor ("AuthenticAMD" 686-class, > 512KB L2 cache) 2.81 GHz > cpu0: > FPU,V86,DE,PSE,TSC,MSR,PAE,MCE,CX8,APIC,SEP,MTRR,PGE,MCA,CMOV,PAT,PSE36,CFLUSH,MMX,FXSR,SSE,SSE2,HTT,SSE3,MWAIT,CX16,POPCNT > cpu0 at mainbus0: apid 0 (boot processor) > cpu0: apic clock running at 200MHz > acpicpu0 at acpi0: C2, PSS > cpu0: 2810 MHz: speeds: 2800 2200 1500 800 MHz > > According to md5 -tt it seems to work. > sysctl hw.setperf=100 > MD5 time trial. Processing 100000 10000-byte blocks... > Digest = 766a2bb5d24bddae466c572bcabca3ee > Time = 2.118649 seconds > Speed = 471998901.186558 bytes/second > sysctl hw.setperf=0 > MD5 time trial. Processing 100000 10000-byte blocks... > Digest = 766a2bb5d24bddae466c572bcabca3ee > Time = 7.416370 seconds > Speed = 134836854.148323 bytes/second > > Here the updated diff including i386 support. > -- > :wq Claudio > > Index: arch/amd64/amd64/identcpu.c > =================================================================== > RCS file: /cvs/src/sys/arch/amd64/amd64/identcpu.c,v > retrieving revision 1.30 > diff -u -p -r1.30 identcpu.c > --- arch/amd64/amd64/identcpu.c 7 Sep 2010 16:22:48 -0000 1.30 > +++ arch/amd64/amd64/identcpu.c 19 May 2011 20:00:02 -0000 > @@ -364,6 +364,8 @@ identifycpu(struct cpu_info *ci) > if ((ci->ci_signature & 0xF00) == 0xf00) > setperf_setup = k8_powernow_init; > } > + if (ci->ci_family == 0x10 || ci->ci_family == 0x11) > + setperf_setup = k1x_init; > } > > if (cpu_ecxfeature & CPUIDECX_EST) { > Index: arch/amd64/amd64/k1x-pstate.c > =================================================================== > RCS file: arch/amd64/amd64/k1x-pstate.c > diff -N arch/amd64/amd64/k1x-pstate.c > --- /dev/null 1 Jan 1970 00:00:00 -0000 > +++ arch/amd64/amd64/k1x-pstate.c 19 May 2011 20:00:02 -0000 > @@ -0,0 +1,215 @@ > +/* $OpenBSD$ */ > +/* > + * Copyright (c) 2011 Bryan Steele <bry...@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); > +int 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 > + > +int > +k1x_acpi_states(struct k1x_cpu_state *cstate, struct acpicpu_pss *pss, > + int nstates, u_int64_t msr) > +{ > + struct k1x_state state; > + int j, k, n; > + u_int32_t ctrl; > + > + k = -1; > + > + for (n = 0; n < cstate->n_states; n++) { > + if ((K1X_FID(msr) == K1X_FID(pss[n].pss_status))) > + k = 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)); > + } > + > + return k; > +} > + > +void > +k1x_acpi_init(struct k1x_cpu_state *cstate, u_int64_t msr) > +{ > + int curs; > + u_int32_t ctrl; > + struct acpicpu_pss *pss; > + > + cstate->n_states = acpicpu_fetch_pss(&pss); > + if (cstate->n_states == 0) > + return; > + > + curs = k1x_acpi_states(cstate, pss, cstate->n_states, msr); > + ctrl = pss[curs].pss_ctrl; > + > + 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); > +} > Index: arch/amd64/conf/files.amd64 > =================================================================== > RCS file: /cvs/src/sys/arch/amd64/conf/files.amd64,v > retrieving revision 1.61 > diff -u -p -r1.61 files.amd64 > --- arch/amd64/conf/files.amd64 2 Apr 2011 18:16:50 -0000 1.61 > +++ arch/amd64/conf/files.amd64 19 May 2011 20:00:02 -0000 > @@ -64,6 +64,7 @@ file arch/amd64/isa/clock.c > > file arch/amd64/amd64/powernow-k8.c !small_kernel > file arch/amd64/amd64/est.c !small_kernel > +file arch/amd64/amd64/k1x-pstate.c !small_kernel > > include "dev/rasops/files.rasops" > include "dev/wsfont/files.wsfont" > Index: arch/amd64/include/cpu.h > =================================================================== > RCS file: /cvs/src/sys/arch/amd64/include/cpu.h,v > retrieving revision 1.66 > diff -u -p -r1.66 cpu.h > --- arch/amd64/include/cpu.h 13 Apr 2011 02:49:12 -0000 1.66 > +++ arch/amd64/include/cpu.h 19 May 2011 20:00:02 -0000 > @@ -318,6 +318,10 @@ void x86_bus_space_mallocok(void); > void k8_powernow_init(struct cpu_info *); > void k8_powernow_setperf(int); > > +/* k1x-pstate.c */ > +void k1x_init(struct cpu_info *); > +void k1x_setperf(int); > + > void est_init(struct cpu_info *); > void est_setperf(int); > > Index: arch/i386/conf/files.i386 > =================================================================== > RCS file: /cvs/src/sys/arch/i386/conf/files.i386,v > retrieving revision 1.202 > diff -u -p -r1.202 files.i386 > --- arch/i386/conf/files.i386 30 Apr 2011 15:33:18 -0000 1.202 > +++ arch/i386/conf/files.i386 19 May 2011 20:01:57 -0000 > @@ -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 > Index: arch/i386/i386/k1x-pstate.c > =================================================================== > RCS file: arch/i386/i386/k1x-pstate.c > diff -N arch/i386/i386/k1x-pstate.c > --- /dev/null 1 Jan 1970 00:00:00 -0000 > +++ arch/i386/i386/k1x-pstate.c 19 May 2011 20:13:56 -0000 > @@ -0,0 +1,215 @@ > +/* $OpenBSD$ */ > +/* > + * Copyright (c) 2011 Bryan Steele <bry...@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); > +int 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 > + > +int > +k1x_acpi_states(struct k1x_cpu_state *cstate, struct acpicpu_pss *pss, > + int nstates, u_int64_t msr) > +{ > + struct k1x_state state; > + int j, k, n; > + u_int32_t ctrl; > + > + k = -1; > + > + for (n = 0; n < cstate->n_states; n++) { > + if ((K1X_FID(msr) == K1X_FID(pss[n].pss_status))) > + k = 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)); > + } > + > + return k; > +} > + > +void > +k1x_acpi_init(struct k1x_cpu_state *cstate, u_int64_t msr) > +{ > + int curs; > + u_int32_t ctrl; > + struct acpicpu_pss *pss; > + > + cstate->n_states = acpicpu_fetch_pss(&pss); > + if (cstate->n_states == 0) > + return; > + > + curs = k1x_acpi_states(cstate, pss, cstate->n_states, msr); > + ctrl = pss[curs].pss_ctrl; > + > + 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); > +} > Index: arch/i386/i386/machdep.c > =================================================================== > RCS file: /cvs/src/sys/arch/i386/i386/machdep.c,v > retrieving revision 1.494 > diff -u -p -r1.494 machdep.c > --- arch/i386/i386/machdep.c 30 Apr 2011 15:33:18 -0000 1.494 > +++ arch/i386/i386/machdep.c 19 May 2011 20:10:07 -0000 > @@ -1345,6 +1345,8 @@ amd_family6_setperf_setup(struct cpu_inf > k8_powernow_init(); > break; > } > + if (ci->ci_family == 0x10 || ci->ci_family == 0x11) > + k1x_init(ci); > } > #endif > > Index: arch/i386/include/cpu.h > =================================================================== > RCS file: /cvs/src/sys/arch/i386/include/cpu.h,v > retrieving revision 1.119 > diff -u -p -r1.119 cpu.h > --- arch/i386/include/cpu.h 22 Apr 2011 15:48:43 -0000 1.119 > +++ arch/i386/include/cpu.h 19 May 2011 20:02:38 -0000 > @@ -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 */