diff options
author | Gordon Willem Klok <gwk@cvs.openbsd.org> | 2007-05-06 03:37:09 +0000 |
---|---|---|
committer | Gordon Willem Klok <gwk@cvs.openbsd.org> | 2007-05-06 03:37:09 +0000 |
commit | 1b2ae2b4f3c14eba0c4feb7613aee2680e95da48 (patch) | |
tree | 5fda8ab9ed6001ec707c053bb08d7070ab1f6000 | |
parent | d75a8852352203fde00f2db0d61476a4a5afd9dc (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.c | 12 | ||||
-rw-r--r-- | sys/arch/amd64/amd64/ipifuncs.c | 3 | ||||
-rw-r--r-- | sys/arch/amd64/amd64/mainbus.c | 23 | ||||
-rw-r--r-- | sys/arch/amd64/amd64/mp_setperf.c | 139 | ||||
-rw-r--r-- | sys/arch/amd64/amd64/powernow-k8.c | 6 | ||||
-rw-r--r-- | sys/arch/amd64/conf/files.amd64 | 3 | ||||
-rw-r--r-- | sys/arch/amd64/include/cpu.h | 15 | ||||
-rw-r--r-- | sys/arch/amd64/include/intr.h | 7 | ||||
-rw-r--r-- | sys/arch/amd64/include/intrdefs.h | 8 |
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 |