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.

...
 
> Here the updated diff including i386 support.

Updated version with some minor cleanups in the k1x-pstate.c code.
Anyone willing to OK this?
-- 
: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       21 May 2011 10:36:12 -0000
@@ -0,0 +1,207 @@
+/*     $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);
+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);
+}
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 21 May 2011 10:36:55 -0000
@@ -0,0 +1,207 @@
+/*     $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);
+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);
+}
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