summaryrefslogtreecommitdiff
path: root/sys/arch/i386
diff options
context:
space:
mode:
authorClaudio Jeker <claudio@cvs.openbsd.org>2011-05-23 09:54:21 +0000
committerClaudio Jeker <claudio@cvs.openbsd.org>2011-05-23 09:54:21 +0000
commit959ee871e781f5295e5401b183447c669d28aa44 (patch)
tree9ed1e841edcae3a1ed42a37db9ac2709ebc37c2b /sys/arch/i386
parent1c62370d57329d26ffe2c6fb203f87c82bbe7214 (diff)
AMD K10/K11 pstate driver allows setperf and apm to change CPU
frequencies on newer AMD systems. Driver written by Bryan Steele / brynet gmail.com adjusted for i386 by myself. Put it in deraadt@
Diffstat (limited to 'sys/arch/i386')
-rw-r--r--sys/arch/i386/conf/files.i3863
-rw-r--r--sys/arch/i386/i386/k1x-pstate.c207
-rw-r--r--sys/arch/i386/i386/machdep.c4
-rw-r--r--sys/arch/i386/include/cpu.h5
4 files changed, 216 insertions, 3 deletions
diff --git a/sys/arch/i386/conf/files.i386 b/sys/arch/i386/conf/files.i386
index b4943512159..6c655e0d050 100644
--- a/sys/arch/i386/conf/files.i386
+++ b/sys/arch/i386/conf/files.i386
@@ -1,4 +1,4 @@
-# $OpenBSD: files.i386,v 1.202 2011/04/30 15:33:18 mlarkin Exp $
+# $OpenBSD: files.i386,v 1.203 2011/05/23 09:54:20 claudio Exp $
#
# new style config file for i386 architecture
#
@@ -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
diff --git a/sys/arch/i386/i386/k1x-pstate.c b/sys/arch/i386/i386/k1x-pstate.c
new file mode 100644
index 00000000000..875c9a23d6c
--- /dev/null
+++ b/sys/arch/i386/i386/k1x-pstate.c
@@ -0,0 +1,207 @@
+/* $OpenBSD: k1x-pstate.c,v 1.1 2011/05/23 09:54:20 claudio Exp $ */
+/*
+ * Copyright (c) 2011 Bryan Steele <brynet@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);
+}
diff --git a/sys/arch/i386/i386/machdep.c b/sys/arch/i386/i386/machdep.c
index 41d902601ac..355dd681b59 100644
--- a/sys/arch/i386/i386/machdep.c
+++ b/sys/arch/i386/i386/machdep.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: machdep.c,v 1.494 2011/04/30 15:33:18 mlarkin Exp $ */
+/* $OpenBSD: machdep.c,v 1.495 2011/05/23 09:54:20 claudio Exp $ */
/* $NetBSD: machdep.c,v 1.214 1996/11/10 03:16:17 thorpej Exp $ */
/*-
@@ -1345,6 +1345,8 @@ amd_family6_setperf_setup(struct cpu_info *ci)
k8_powernow_init();
break;
}
+ if (ci->ci_family == 0x10 || ci->ci_family == 0x11)
+ k1x_init(ci);
}
#endif
diff --git a/sys/arch/i386/include/cpu.h b/sys/arch/i386/include/cpu.h
index 112f0f3b604..bf6481b2c70 100644
--- a/sys/arch/i386/include/cpu.h
+++ b/sys/arch/i386/include/cpu.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: cpu.h,v 1.119 2011/04/22 15:48:43 kettenis Exp $ */
+/* $OpenBSD: cpu.h,v 1.120 2011/05/23 09:54:20 claudio Exp $ */
/* $NetBSD: cpu.h,v 1.35 1996/05/05 19:29:26 christos Exp $ */
/*-
@@ -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 */