summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGordon Willem Klok <gwk@cvs.openbsd.org>2007-05-06 03:37:09 +0000
committerGordon Willem Klok <gwk@cvs.openbsd.org>2007-05-06 03:37:09 +0000
commit1b2ae2b4f3c14eba0c4feb7613aee2680e95da48 (patch)
tree5fda8ab9ed6001ec707c053bb08d7070ab1f6000
parentd75a8852352203fde00f2db0d61476a4a5afd9dc (diff)
Add the mp setperf mechanism to AMD64, like its i386 counterpart it allows
all cpus in a system supporting frequency and voltage scaling to be scaled by the same amount corresponding to the user (or apmd on their behalf) performance level. This diff also teaches amd64 about acpi_hasprocfvs (ACPI has processor frequency and voltage scaling). It also moves initilization of the underlying setperf mechanism such as powernow to mainbus from the cpu indentification and initilization code inspired by similar changes dim@ made to i386 durring h2k6. This is necessary to implement the AMD recommended method for retreiving p_state data from the ACPI _PSS object (a diff comming soon). It will also simplify the potential addition of enhanced speedstep as found on newer intel processors with EMT64 capable of running OpenBSD/amd64. MP setperf functionality verifed by myself and Johan M:son Lindman <tybolt AT solace DOT miun DOT se> on opteron 265 and 270 systems respectively. General testing done by many others thanks! ok tedu, dim
-rw-r--r--sys/arch/amd64/amd64/identcpu.c12
-rw-r--r--sys/arch/amd64/amd64/ipifuncs.c3
-rw-r--r--sys/arch/amd64/amd64/mainbus.c23
-rw-r--r--sys/arch/amd64/amd64/mp_setperf.c139
-rw-r--r--sys/arch/amd64/amd64/powernow-k8.c6
-rw-r--r--sys/arch/amd64/conf/files.amd643
-rw-r--r--sys/arch/amd64/include/cpu.h15
-rw-r--r--sys/arch/amd64/include/intr.h7
-rw-r--r--sys/arch/amd64/include/intrdefs.h8
9 files changed, 191 insertions, 25 deletions
diff --git a/sys/arch/amd64/amd64/identcpu.c b/sys/arch/amd64/amd64/identcpu.c
index 030a36504aa..5d6695e7e2b 100644
--- a/sys/arch/amd64/amd64/identcpu.c
+++ b/sys/arch/amd64/amd64/identcpu.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: identcpu.c,v 1.11 2007/02/17 17:35:43 tom Exp $ */
+/* $OpenBSD: identcpu.c,v 1.12 2007/05/06 03:37:08 gwk Exp $ */
/* $NetBSD: identcpu.c,v 1.1 2003/04/26 18:39:28 fvdl Exp $ */
/*
@@ -109,6 +109,8 @@ cpu_amd64speed(int *freq)
return (0);
}
+void (*setperf_setup)(struct cpu_info *);
+
void
identifycpu(struct cpu_info *ci)
{
@@ -181,16 +183,14 @@ identifycpu(struct cpu_info *ci)
x86_print_cacheinfo(ci);
-#ifndef MULTIPROCESSOR
if (pnfeatset > 0x80000007) {
- CPUID(0x80000007, dummy, dummy, dummy, pnfeatset);
-
+ CPUID(0x80000007, dummy, dummy, dummy, pnfeatset);
+
if (pnfeatset & 0x06) {
if ((ci->ci_signature & 0xF00) == 0xf00)
- k8_powernow_init();
+ setperf_setup = k8_powernow_init;
}
}
-#endif
/* AuthenticAMD: h t u A i t n e */
if (vendor[0] == 0x68747541 && vendor[1] == 0x69746e65 &&
diff --git a/sys/arch/amd64/amd64/ipifuncs.c b/sys/arch/amd64/amd64/ipifuncs.c
index 7d7ac55a1c9..22248e3ff5b 100644
--- a/sys/arch/amd64/amd64/ipifuncs.c
+++ b/sys/arch/amd64/amd64/ipifuncs.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: ipifuncs.c,v 1.5 2007/03/23 16:44:38 gwk Exp $ */
+/* $OpenBSD: ipifuncs.c,v 1.6 2007/05/06 03:37:08 gwk Exp $ */
/* $NetBSD: ipifuncs.c,v 1.1 2003/04/26 18:39:28 fvdl Exp $ */
/*-
@@ -91,6 +91,7 @@ void (*ipifunc[X86_NIPI])(struct cpu_info *) =
#else
NULL,
#endif
+ x86_setperf_ipi,
};
void
diff --git a/sys/arch/amd64/amd64/mainbus.c b/sys/arch/amd64/amd64/mainbus.c
index d665280cd60..ff51813cd17 100644
--- a/sys/arch/amd64/amd64/mainbus.c
+++ b/sys/arch/amd64/amd64/mainbus.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: mainbus.c,v 1.11 2006/12/14 17:36:12 kettenis Exp $ */
+/* $OpenBSD: mainbus.c,v 1.12 2007/05/06 03:37:08 gwk Exp $ */
/* $NetBSD: mainbus.c,v 1.1 2003/04/26 18:39:29 fvdl Exp $ */
/*
@@ -86,7 +86,7 @@ union mainbus_attach_args {
struct apic_attach_args aaa_caa;
#if NACPI > 0
struct acpi_attach_args mba_aaa;
-#endif
+#endif
#if NIPMI > 0
struct ipmi_attach_args mba_iaa;
#endif
@@ -117,7 +117,7 @@ struct mp_bus *mp_busses;
int mp_nbus;
struct mp_intr_map *mp_intrs;
int mp_nintr;
-
+
struct mp_bus *mp_isa_bus;
struct mp_bus *mp_eisa_bus;
@@ -150,6 +150,7 @@ mainbus_attach(struct device *parent, struct device *self, void *aux)
#ifdef MPBIOS
int mpbios_present = 0;
#endif
+ extern void (*setperf_setup)(struct cpu_info *);
printf("\n");
@@ -203,16 +204,28 @@ mainbus_attach(struct device *parent, struct device *self, void *aux)
if ((cpu_info_primary.ci_flags & CPUF_PRESENT) == 0) {
struct cpu_attach_args caa;
-
+
memset(&caa, 0, sizeof(caa));
caa.caa_name = "cpu";
caa.cpu_number = 0;
caa.cpu_role = CPU_ROLE_SP;
caa.cpu_func = 0;
-
+
config_found(self, &caa, mainbus_print);
}
+#if NACPI > 0
+ if (!acpi_hasprocfvs)
+#endif
+ {
+ if (setperf_setup != NULL)
+ setperf_setup(&cpu_info_primary);
+ }
+
+#ifdef MULTIPROCESSOR
+ mp_setperf_init();
+#endif
+
#if NPCI > 0
if (pci_mode != 0) {
mba.mba_pba.pba_busname = "pci";
diff --git a/sys/arch/amd64/amd64/mp_setperf.c b/sys/arch/amd64/amd64/mp_setperf.c
new file mode 100644
index 00000000000..80f0a06de96
--- /dev/null
+++ b/sys/arch/amd64/amd64/mp_setperf.c
@@ -0,0 +1,139 @@
+/* $OpenBSD: mp_setperf.c,v 1.1 2007/05/06 03:37:08 gwk Exp $ */
+/*
+ * Copyright (c) 2007 Gordon Willem Klok <gwk@openbsd.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/sysctl.h>
+#include <sys/mutex.h>
+
+#include <machine/cpu.h>
+
+#include <machine/intr.h>
+
+struct mutex setperf_mp_mutex = MUTEX_INITIALIZER(IPL_HIGH);
+
+/* underlying setperf mechanism e.g. k8_powernow_setperf() */
+void (*ul_setperf)(int);
+
+#define MP_SETPERF_STEADY 0 /* steady state - normal operation */
+#define MP_SETPERF_INTRANSIT 1 /* in transition */
+#define MP_SETPERF_PROCEED 2 /* proceed with transition */
+#define MP_SETPERF_FINISH 3 /* return from IPI */
+
+
+/* protected by setperf_mp_mutex */
+volatile int mp_setperf_state = MP_SETPERF_STEADY;
+volatile int mp_perflevel;
+
+void mp_setperf(int);
+
+void
+mp_setperf(int level)
+{
+ CPU_INFO_ITERATOR cii;
+ struct cpu_info *ci;
+ int notready, s;
+
+ if (mp_setperf_state == MP_SETPERF_STEADY) {
+ mtx_enter(&setperf_mp_mutex);
+ mp_perflevel = level;
+
+ curcpu()->ci_setperf_state = CI_SETPERF_INTRANSIT;
+ /* ask all other processors to drop what they are doing */
+ CPU_INFO_FOREACH(cii, ci) {
+ if (ci->ci_setperf_state != CI_SETPERF_INTRANSIT) {
+ ci->ci_setperf_state =
+ CI_SETPERF_SHOULDSTOP;
+ x86_send_ipi(ci, X86_IPI_SETPERF);
+ }
+ }
+
+
+ /* Loop until all processors report ready */
+ do {
+ CPU_INFO_FOREACH(cii, ci) {
+ if ((notready = (ci->ci_setperf_state
+ != CI_SETPERF_INTRANSIT)))
+ break;
+ }
+ } while (notready);
+
+ mp_setperf_state = MP_SETPERF_PROCEED; /* release the hounds */
+
+ s = splipi();
+
+ ul_setperf(mp_perflevel);
+
+ splx(s);
+
+ curcpu()->ci_setperf_state = CI_SETPERF_DONE;
+ /* Loop until all processors report done */
+ do {
+ CPU_INFO_FOREACH(cii, ci) {
+ if ((notready = (ci->ci_setperf_state
+ != CI_SETPERF_DONE)))
+ break;
+ }
+ } while (notready);
+
+ mp_setperf_state = MP_SETPERF_FINISH;
+ /* delay a little for potential straglers */
+ DELAY(2);
+ curcpu()->ci_setperf_state = CI_SETPERF_READY;
+ mp_setperf_state = MP_SETPERF_STEADY; /* restore normallity */
+ mtx_leave(&setperf_mp_mutex);
+ }
+
+}
+
+void
+x86_setperf_ipi(struct cpu_info *ci)
+{
+
+ if (ci->ci_setperf_state == CI_SETPERF_SHOULDSTOP)
+ ci->ci_setperf_state = CI_SETPERF_INTRANSIT;
+
+ while (mp_setperf_state != MP_SETPERF_PROCEED)
+ ;
+
+ ul_setperf(mp_perflevel);
+
+ ci->ci_setperf_state = CI_SETPERF_DONE;
+
+ while (mp_setperf_state != MP_SETPERF_FINISH)
+ ;
+ ci->ci_setperf_state = CI_SETPERF_READY;
+}
+
+void
+mp_setperf_init()
+{
+ CPU_INFO_ITERATOR cii;
+ struct cpu_info *ci;
+
+
+ if (!cpu_setperf)
+ return;
+ ul_setperf = cpu_setperf;
+
+ cpu_setperf = mp_setperf;
+
+ CPU_INFO_FOREACH(cii, ci) {
+ ci->ci_setperf_state = CI_SETPERF_READY;
+ }
+ mtx_init(&setperf_mp_mutex, IPL_HIGH);
+}
diff --git a/sys/arch/amd64/amd64/powernow-k8.c b/sys/arch/amd64/amd64/powernow-k8.c
index b17d15d4c93..81674890924 100644
--- a/sys/arch/amd64/amd64/powernow-k8.c
+++ b/sys/arch/amd64/amd64/powernow-k8.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: powernow-k8.c,v 1.17 2007/04/25 00:27:43 gwk Exp $ */
+/* $OpenBSD: powernow-k8.c,v 1.18 2007/05/06 03:37:08 gwk Exp $ */
/*
* Copyright (c) 2004 Martin Végiard.
* Copyright (c) 2004-2005 Bruno Ducrot
@@ -327,16 +327,14 @@ k8pnow_states(struct k8pnow_cpu_state *cstate, uint32_t cpusig,
}
void
-k8_powernow_init(void)
+k8_powernow_init(struct cpu_info *ci)
{
uint64_t status;
u_int maxfid, maxvid, i;
u_int32_t extcpuid, dummy;
struct k8pnow_cpu_state *cstate;
struct k8pnow_state *state;
- struct cpu_info * ci;
char * techname = NULL;
- ci = curcpu();
if (setperf_prio > 1)
return;
diff --git a/sys/arch/amd64/conf/files.amd64 b/sys/arch/amd64/conf/files.amd64
index 48321aba388..451a29610c8 100644
--- a/sys/arch/amd64/conf/files.amd64
+++ b/sys/arch/amd64/conf/files.amd64
@@ -1,4 +1,4 @@
-# $OpenBSD: files.amd64,v 1.26 2007/02/17 17:35:43 tom Exp $
+# $OpenBSD: files.amd64,v 1.27 2007/05/06 03:37:08 gwk Exp $
maxpartitions 16
maxusers 2 16 128
@@ -31,6 +31,7 @@ file arch/amd64/amd64/bus_dma.c
file arch/amd64/amd64/mptramp.S multiprocessor
file arch/amd64/amd64/ipifuncs.c multiprocessor
file arch/amd64/amd64/ipi.c multiprocessor
+file arch/amd64/amd64/mp_setperf.c multiprocessor
file arch/amd64/amd64/apic.c ioapic | lapic
diff --git a/sys/arch/amd64/include/cpu.h b/sys/arch/amd64/include/cpu.h
index 55ef0ec6bd5..f07e3935b32 100644
--- a/sys/arch/amd64/include/cpu.h
+++ b/sys/arch/amd64/include/cpu.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: cpu.h,v 1.26 2007/03/15 10:22:29 art Exp $ */
+/* $OpenBSD: cpu.h,v 1.27 2007/05/06 03:37:08 gwk Exp $ */
/* $NetBSD: cpu.h,v 1.1 2003/04/26 18:39:39 fvdl Exp $ */
/*-
@@ -119,6 +119,12 @@ struct cpu_info {
#define CI_DDB_ENTERDDB 3
#define CI_DDB_INDDB 4
+ volatile int ci_setperf_state;
+#define CI_SETPERF_READY 0
+#define CI_SETPERF_SHOULDSTOP 1
+#define CI_SETPERF_INTRANSIT 2
+#define CI_SETPERF_DONE 3
+
struct x86_64_tss ci_doubleflt_tss;
char *ci_doubleflt_stack;
@@ -302,9 +308,14 @@ void x86_bus_space_init(void);
void x86_bus_space_mallocok(void);
/* powernow-k8.c */
-void k8_powernow_init(void);
+void k8_powernow_init(struct cpu_info *);
void k8_powernow_setperf(int);
+#ifdef MULTIPROCESSOR
+/* mp_setperf.c */
+void mp_setperf_init(void);
+#endif
+
#endif /* _KERNEL */
/*
diff --git a/sys/arch/amd64/include/intr.h b/sys/arch/amd64/include/intr.h
index 5ff681d5b9d..0aadd1e8edf 100644
--- a/sys/arch/amd64/include/intr.h
+++ b/sys/arch/amd64/include/intr.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: intr.h,v 1.7 2006/03/12 02:34:39 brad Exp $ */
+/* $OpenBSD: intr.h,v 1.8 2007/05/06 03:37:08 gwk Exp $ */
/* $NetBSD: intr.h,v 1.2 2003/05/04 22:01:56 fvdl Exp $ */
/*-
@@ -67,7 +67,7 @@
struct intrstub {
void *ist_entry;
- void *ist_recurse;
+ void *ist_recurse;
void *ist_resume;
};
@@ -231,6 +231,7 @@ void x86_intlock(struct intrframe);
void x86_intunlock(struct intrframe);
void x86_softintlock(void);
void x86_softintunlock(void);
+void x86_setperf_ipi(struct cpu_info *);
extern void (*ipifunc[X86_NIPI])(struct cpu_info *);
#endif
@@ -243,7 +244,7 @@ extern void (*ipifunc[X86_NIPI])(struct cpu_info *);
#define X86_SOFTINTR_SOFTCLOCK 0
#define X86_SOFTINTR_SOFTNET 1
-#define X86_SOFTINTR_SOFTSERIAL 2
+#define X86_SOFTINTR_SOFTSERIAL 2
#define X86_NSOFTINTR 3
#ifndef _LOCORE
diff --git a/sys/arch/amd64/include/intrdefs.h b/sys/arch/amd64/include/intrdefs.h
index 2f62f2b3b16..64a6d3394a9 100644
--- a/sys/arch/amd64/include/intrdefs.h
+++ b/sys/arch/amd64/include/intrdefs.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: intrdefs.h,v 1.4 2007/02/01 20:39:42 art Exp $ */
+/* $OpenBSD: intrdefs.h,v 1.5 2007/05/06 03:37:08 gwk Exp $ */
/* $NetBSD: intrdefs.h,v 1.2 2003/05/04 22:01:56 fvdl Exp $ */
#ifndef _i386_INTRDEFS_H
@@ -81,12 +81,14 @@
#define X86_IPI_MTRR 0x00000020
#define X86_IPI_GDT 0x00000040
#define X86_IPI_DDB 0x00000080
+#define X86_IPI_SETPERF 0x00000100
-#define X86_NIPI 8
+#define X86_NIPI 9
#define X86_IPI_NAMES { "halt IPI", "nop IPI", "FPU flush IPI", \
"FPU synch IPI", "TLB shootdown IPI", \
- "MTRR update IPI", "GDT update IPI", "ddb IPI" }
+ "MTRR update IPI", "GDT update IPI", "ddb IPI", \
+ "setperf IPI"}
#define IREENT_MAGIC 0x18041969