summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorgkoehler <gkoehler@openbsd.org>2020-07-10 23:22:48 +0000
committergkoehler <gkoehler@openbsd.org>2020-07-10 23:22:48 +0000
commitb286a873946927e7fab0393032ce5db5051b5b75 (patch)
treee919723014d950fb5be48f2208addc94971d833e
parenttable fix; (diff)
downloadwireguard-openbsd-b286a873946927e7fab0393032ce5db5051b5b75.tar.xz
wireguard-openbsd-b286a873946927e7fab0393032ce5db5051b5b75.zip
Add hw.cpuspeed and hw.setperf
Get the list of Pstates from OPAL, and use special registers to request a Pstate or check the current Pstate. The turbo Pstates are higher than the cpu's nominal speed, but the OCC's firmware should throttle down the cpu if it would overheat. ok kettenis@
-rw-r--r--sys/arch/powerpc64/dev/opal.c95
-rw-r--r--sys/arch/powerpc64/include/cpufunc.h16
-rw-r--r--sys/arch/powerpc64/powerpc64/cpu.c12
3 files changed, 117 insertions, 6 deletions
diff --git a/sys/arch/powerpc64/dev/opal.c b/sys/arch/powerpc64/dev/opal.c
index 13ab766f29e..72a645a8163 100644
--- a/sys/arch/powerpc64/dev/opal.c
+++ b/sys/arch/powerpc64/dev/opal.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: opal.c,v 1.7 2020/07/07 22:43:29 kettenis Exp $ */
+/* $OpenBSD: opal.c,v 1.8 2020/07/10 23:22:48 gkoehler Exp $ */
/*
* Copyright (c) 2020 Mark Kettenis <kettenis@openbsd.org>
*
@@ -18,6 +18,7 @@
#include <sys/param.h>
#include <sys/device.h>
#include <sys/malloc.h>
+#include <sys/sysctl.h>
#include <sys/systm.h>
#include <machine/bus.h>
@@ -51,6 +52,10 @@ struct opal_softc {
struct intrhand *sc_handler[OPAL_NUM_HANDLERS];
struct todr_chip_handle sc_todr;
+
+ int *sc_pstate;
+ int *sc_freq;
+ int sc_npstate;
};
struct opal_softc *opal_sc;
@@ -71,6 +76,13 @@ void opal_attach_node(struct opal_softc *, int);
int opal_gettime(struct todr_chip_handle *, struct timeval *);
int opal_settime(struct todr_chip_handle *, struct timeval *);
+extern int perflevel;
+
+void opalpm_init(struct opal_softc *, int);
+int opalpm_find_index(struct opal_softc *);
+int opalpm_cpuspeed(int *);
+void opalpm_setperf(int);
+
int
opal_match(struct device *parent, void *match, void *aux)
{
@@ -133,6 +145,8 @@ opal_attach(struct device *parent, struct device *self, void *aux)
sc->sc_todr.todr_settime = opal_settime;
todr_attach(&sc->sc_todr);
+ opalpm_init(sc, OF_getnodebyname(faa->fa_node, "power-mgt"));
+
node = OF_getnodebyname(faa->fa_node, "consoles");
if (node) {
for (node = OF_child(node); node; node = OF_peer(node))
@@ -306,3 +320,82 @@ opal_settime(struct todr_chip_handle *ch, struct timeval *tv)
return 0;
}
+
+void
+opalpm_init(struct opal_softc *sc, int node)
+{
+ int i, len;
+
+ if (!node) {
+ printf("%s: no power-mgt\n", sc->sc_dev.dv_xname);
+ return;
+ }
+ len = OF_getproplen(node, "ibm,pstate-ids");
+ if (len <= 0 || len % sizeof(int) != 0 ||
+ len != OF_getproplen(node, "ibm,pstate-frequencies-mhz")) {
+ printf("%s: can't parse power-mgt\n", sc->sc_dev.dv_xname);
+ return;
+ }
+ sc->sc_pstate = malloc(len, M_DEVBUF, M_WAITOK);
+ sc->sc_freq = malloc(len, M_DEVBUF, M_WAITOK);
+ sc->sc_npstate = len / sizeof(int);
+ OF_getprop(node, "ibm,pstate-ids", sc->sc_pstate, len);
+ OF_getprop(node, "ibm,pstate-frequencies-mhz", sc->sc_freq, len);
+
+ if ((i = opalpm_find_index(sc)) != -1)
+ perflevel = (sc->sc_npstate - 1 - i) * 100 / sc->sc_npstate;
+ cpu_cpuspeed = opalpm_cpuspeed;
+ cpu_setperf = opalpm_setperf;
+}
+
+int
+opalpm_find_index(struct opal_softc *sc)
+{
+ int i, pstate;
+
+ /*
+ * POWER9 23.5.8.3 Power Management Status Register (PMSR)
+ * 8:15 Local Actual Pstate
+ */
+ pstate = (mfpmsr() >> 48) & 0xff;
+ for (i = 0; i < sc->sc_npstate; i++) {
+ if (sc->sc_pstate[i] == pstate)
+ return i;
+ }
+ return -1;
+}
+
+int
+opalpm_cpuspeed(int *freq)
+{
+ struct opal_softc *sc = opal_sc;
+ int i;
+
+ if ((i = opalpm_find_index(sc)) == -1)
+ return 1;
+ *freq = sc->sc_freq[i];
+ return 0;
+}
+
+void
+opalpm_setperf(int level)
+{
+ struct opal_softc *sc = opal_sc;
+ uint64_t pstate;
+ int i;
+
+ /*
+ * Assume that "ibm,pstate-frequencies-mhz" is sorted from
+ * fastest to slowest.
+ */
+ i = (100 - level) * (sc->sc_npstate - 1) / 100;
+ pstate = sc->sc_pstate[i];
+
+ /*
+ * POWER9 23.5.8.1 Power Management Control Register (PMCR)
+ * 0:7 Upper Pstate request
+ * 8:15 Lower Pstate request
+ * 60:63 Version
+ */
+ mtpmcr((pstate << 56) | (pstate << 48) | 0);
+}
diff --git a/sys/arch/powerpc64/include/cpufunc.h b/sys/arch/powerpc64/include/cpufunc.h
index 3143e564abe..e9228587f3e 100644
--- a/sys/arch/powerpc64/include/cpufunc.h
+++ b/sys/arch/powerpc64/include/cpufunc.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: cpufunc.h,v 1.6 2020/06/26 11:29:48 kettenis Exp $ */
+/* $OpenBSD: cpufunc.h,v 1.7 2020/07/10 23:22:48 gkoehler Exp $ */
/*
* Copyright (c) 2020 Mark Kettenis <kettenis@openbsd.org>
@@ -159,6 +159,20 @@ mtptcr(uint64_t value)
__asm volatile ("mtspr 464, %0" :: "r"(value));
}
+static inline uint64_t
+mfpmsr(void)
+{
+ uint64_t value;
+ __asm volatile ("mfspr %0, 853" : "=r"(value));
+ return value;
+}
+
+static inline void
+mtpmcr(uint64_t value)
+{
+ __asm volatile ("mtspr 884, %0" :: "r"(value));
+}
+
static inline uint32_t
mfpir(void)
{
diff --git a/sys/arch/powerpc64/powerpc64/cpu.c b/sys/arch/powerpc64/powerpc64/cpu.c
index 5f7162f8ea6..771a2634488 100644
--- a/sys/arch/powerpc64/powerpc64/cpu.c
+++ b/sys/arch/powerpc64/powerpc64/cpu.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: cpu.c,v 1.10 2020/07/10 18:34:24 kettenis Exp $ */
+/* $OpenBSD: cpu.c,v 1.11 2020/07/10 23:22:48 gkoehler Exp $ */
/*
* Copyright (c) 2020 Mark Kettenis <kettenis@openbsd.org>
@@ -87,9 +87,7 @@ cpu_attach(struct device *parent, struct device *dev, void *aux)
{
struct fdt_attach_args *faa = aux;
const char *name = NULL;
- uint32_t pvr;
- uint32_t iline;
- uint32_t dline;
+ uint32_t pvr, clock_freq, iline, dline;
int node, level, i;
printf(" pir %llx", faa->fa_reg[0].addr);
@@ -113,6 +111,12 @@ cpu_attach(struct device *parent, struct device *dev, void *aux)
}
node = faa->fa_node;
+ clock_freq = OF_getpropint(node, "clock-frequency", 0);
+ if (clock_freq != 0) {
+ clock_freq /= 1000000; /* Hz to MHz */
+ printf(", %u MHz", clock_freq);
+ }
+
iline = OF_getpropint(node, "i-cache-block-size", 128);
dline = OF_getpropint(node, "d-cache-block-size", 128);
level = 1;