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 */

Reply via email to