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.

"Works for me", tease me about my last name and I'll cut you.
-Bryan.

--- /dev/null   Wed Feb  2 02:26:51 2011
+++ arch/amd64/amd64/k1x-pstate.c       Wed Feb  2 02:26:49 2011
@@ -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/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 31 Jan 2011 05:05:48 -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/conf/files.amd64
===================================================================
RCS file: /cvs/src/sys/arch/amd64/conf/files.amd64,v
retrieving revision 1.60
diff -u -p -r1.60 files.amd64
--- arch/amd64/conf/files.amd64 6 Dec 2010 20:10:17 -0000       1.60
+++ arch/amd64/conf/files.amd64 31 Jan 2011 05:05:48 -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.62
diff -u -p -r1.62 cpu.h
--- arch/amd64/include/cpu.h    29 Nov 2010 00:04:09 -0000      1.62
+++ arch/amd64/include/cpu.h    31 Jan 2011 05:05:48 -0000
@@ -317,6 +317,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);

Reply via email to