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 <[email protected]>
+ *
+ * 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 <[email protected]>
+ *
+ * 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 */