summaryrefslogtreecommitdiff
path: root/sys
diff options
context:
space:
mode:
Diffstat (limited to 'sys')
-rw-r--r--sys/arch/powerpc64/dev/opal.c101
-rw-r--r--sys/arch/powerpc64/include/cpu.h9
-rw-r--r--sys/arch/powerpc64/include/cpufunc.h3
-rw-r--r--sys/arch/powerpc64/include/trap.h1
-rw-r--r--sys/arch/powerpc64/powerpc64/cpu.c30
-rw-r--r--sys/arch/powerpc64/powerpc64/genassym.cf3
-rw-r--r--sys/arch/powerpc64/powerpc64/locore.S101
-rw-r--r--sys/arch/powerpc64/powerpc64/machdep.c8
-rw-r--r--sys/arch/powerpc64/powerpc64/trap_subr.S26
-rw-r--r--sys/dev/ofw/fdt.c18
-rw-r--r--sys/dev/ofw/openfirm.h3
11 files changed, 283 insertions, 20 deletions
diff --git a/sys/arch/powerpc64/dev/opal.c b/sys/arch/powerpc64/dev/opal.c
index a3ec08afa92..096412b778f 100644
--- a/sys/arch/powerpc64/dev/opal.c
+++ b/sys/arch/powerpc64/dev/opal.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: opal.c,v 1.10 2020/09/23 03:03:11 gkoehler Exp $ */
+/* $OpenBSD: opal.c,v 1.11 2020/12/30 06:06:30 gkoehler Exp $ */
/*
* Copyright (c) 2020 Mark Kettenis <kettenis@openbsd.org>
*
@@ -76,6 +76,8 @@ void opal_attach_deferred(struct device *);
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 *);
+void opal_configure_idle_states(struct opal_softc *, int);
+void opal_found_stop_state(struct opal_softc *, uint64_t);
extern int perflevel;
@@ -146,7 +148,11 @@ 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, "power-mgt");
+ if (node) {
+ opal_configure_idle_states(sc, node);
+ opalpm_init(sc, node);
+ }
node = OF_getnodebyname(faa->fa_node, "consoles");
if (node) {
@@ -322,19 +328,100 @@ opal_settime(struct todr_chip_handle *ch, struct timeval *tv)
return 0;
}
+#define OPAL_PM_LOSE_USER_CONTEXT 0x00001000
+#define OPAL_PM_STOP_INST_FAST 0x00100000
+
+void
+opal_configure_idle_states(struct opal_softc *sc, int node)
+{
+ uint64_t *states;
+ uint32_t accept, *flags;
+ int count, flen, i, slen;
+ char *prop;
+
+ prop = "ibm,cpu-idle-state-flags";
+ flen = OF_getproplen(node, prop);
+ if (flen <= 0 || flen % sizeof(flags[0]) != 0)
+ return;
+ count = flen / sizeof(flags[0]);
+ slen = count * sizeof(states[0]);
+
+ flags = malloc(flen, M_DEVBUF, M_WAITOK);
+ states = malloc(slen, M_DEVBUF, M_WAITOK);
+ OF_getpropintarray(node, prop, flags, flen);
+
+ /* Power ISA v3 uses the psscr with the stop instruction. */
+ prop = "ibm,cpu-idle-state-psscr";
+ if (OF_getpropint64array(node, prop, states, slen) == slen) {
+ /*
+ * Find the deepest idle state that doesn't lose too
+ * much context.
+ */
+ accept = OPAL_PM_LOSE_USER_CONTEXT | OPAL_PM_STOP_INST_FAST;
+ for (i = count - 1; i >= 0; i--) {
+ if ((flags[i] & ~accept) == 0) {
+ opal_found_stop_state(sc, states[i]);
+ break;
+ }
+ }
+ }
+
+ free(flags, M_DEVBUF, flen);
+ free(states, M_DEVBUF, slen);
+}
+
+void cpu_idle_stop(void);
+#ifdef MULTIPROCESSOR
+void cpu_hatch_and_stop(void);
+#endif
+
+void
+opal_found_stop_state(struct opal_softc *sc, uint64_t state)
+{
+#ifdef MULTIPROCESSOR
+ uint32_t pirs[8];
+ int i, len, node;
+ char buf[32];
+#endif
+
+ cpu_idle_state_psscr = state;
+ cpu_idle_cycle_fcn = &cpu_idle_stop;
+ printf("%s: idle psscr %llx\n", sc->sc_dev.dv_xname,
+ (unsigned long long)state);
+
+#ifdef MULTIPROCESSOR
+ /*
+ * Idle the other hardware threads. We use only one thread of
+ * each cpu core. The other threads are idle in OPAL. If we
+ * move them to a deeper idle state, then the core might
+ * switch to single-thread mode, increase performance.
+ */
+ node = OF_parent(curcpu()->ci_node);
+ for (node = OF_child(node); node != 0; node = OF_peer(node)) {
+ if (OF_getprop(node, "device_type", buf, sizeof(buf)) <= 0 ||
+ strcmp(buf, "cpu") != 0)
+ continue;
+ len = OF_getpropintarray(node, "ibm,ppc-interrupt-server#s",
+ pirs, sizeof(pirs));
+ if (len > 0 && len % 4 == 0) {
+ /* Skip i = 0, the first hardware thread. */
+ for (i = 1; i < len / 4; i++)
+ opal_start_cpu(pirs[i],
+ (vaddr_t)cpu_hatch_and_stop);
+ }
+ }
+#endif
+}
+
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);
+ printf("%s: can't parse pstates\n", sc->sc_dev.dv_xname);
return;
}
sc->sc_pstate = malloc(len, M_DEVBUF, M_WAITOK);
diff --git a/sys/arch/powerpc64/include/cpu.h b/sys/arch/powerpc64/include/cpu.h
index 7a95344f554..0a1fc75a3f2 100644
--- a/sys/arch/powerpc64/include/cpu.h
+++ b/sys/arch/powerpc64/include/cpu.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: cpu.h,v 1.28 2020/09/23 03:03:12 gkoehler Exp $ */
+/* $OpenBSD: cpu.h,v 1.29 2020/12/30 06:06:30 gkoehler Exp $ */
/*
* Copyright (c) 2020 Mark Kettenis <kettenis@openbsd.org>
@@ -69,6 +69,7 @@ struct cpu_info {
#define CPUSAVE_LEN 9
register_t ci_tempsave[CPUSAVE_LEN];
+ register_t ci_idle_sp_save;
uint64_t ci_lasttb;
uint64_t ci_nexttimerevent;
@@ -135,6 +136,7 @@ curcpu(void)
for (cii = 0, ci = curcpu(); ci != NULL; ci = NULL)
#define cpu_kick(ci)
+#define cpu_unidle(ci)
#else
@@ -147,6 +149,7 @@ curcpu(void)
for (cii = 0, ci = &cpu_info[0]; cii < ncpus; cii++, ci++)
void cpu_kick(struct cpu_info *);
+void cpu_unidle(struct cpu_info *);
void cpu_boot_secondary_processors(void);
void cpu_startclock(void);
@@ -166,7 +169,6 @@ void mp_setperf(int);
void signotify(struct proc *);
-#define cpu_unidle(ci)
#define CPU_BUSY_CYCLE() do {} while (0)
#define curpcb curcpu()->ci_curpcb
@@ -180,6 +182,9 @@ extern uint32_t cpu_features2;
void cpu_init_features(void);
void cpu_init(void);
+extern uint64_t cpu_idle_state_psscr;
+extern void (*cpu_idle_cycle_fcn)(void);
+
static inline unsigned int
cpu_rnd_messybits(void)
{
diff --git a/sys/arch/powerpc64/include/cpufunc.h b/sys/arch/powerpc64/include/cpufunc.h
index a3a6e485c29..d2ba98b630f 100644
--- a/sys/arch/powerpc64/include/cpufunc.h
+++ b/sys/arch/powerpc64/include/cpufunc.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: cpufunc.h,v 1.9 2020/12/22 11:55:44 kettenis Exp $ */
+/* $OpenBSD: cpufunc.h,v 1.10 2020/12/30 06:06:30 gkoehler Exp $ */
/*
* Copyright (c) 2020 Mark Kettenis <kettenis@openbsd.org>
@@ -165,6 +165,7 @@ mtlpcr(uint64_t value)
__asm volatile ("mtspr 318, %0" :: "r"(value));
}
+#define LPCR_PECE 0x000040000001f000UL
#define LPCR_LPES 0x0000000000000008UL
#define LPCR_HVICE 0x0000000000000002UL
diff --git a/sys/arch/powerpc64/include/trap.h b/sys/arch/powerpc64/include/trap.h
index e79a967b078..8078cff5931 100644
--- a/sys/arch/powerpc64/include/trap.h
+++ b/sys/arch/powerpc64/include/trap.h
@@ -152,5 +152,6 @@
#define TRAP_ENTRY 0x1f8
#define TRAP_HVENTRY 0x1f0
#define TRAP_SLBENTRY 0x1e8
+#define TRAP_RSTENTRY 0x1e0
#endif /* _MACHINE_TRAP_H_ */
diff --git a/sys/arch/powerpc64/powerpc64/cpu.c b/sys/arch/powerpc64/powerpc64/cpu.c
index e36c67e66b0..d86fac2d777 100644
--- a/sys/arch/powerpc64/powerpc64/cpu.c
+++ b/sys/arch/powerpc64/powerpc64/cpu.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: cpu.c,v 1.21 2020/12/22 11:55:44 kettenis Exp $ */
+/* $OpenBSD: cpu.c,v 1.22 2020/12/30 06:06:30 gkoehler Exp $ */
/*
* Copyright (c) 2020 Mark Kettenis <kettenis@openbsd.org>
@@ -236,7 +236,7 @@ cpu_init(void)
uint64_t lpcr = LPCR_LPES;
if (cpu_features2 & PPC_FEATURE2_ARCH_3_00)
- lpcr |= LPCR_HVICE;
+ lpcr |= LPCR_PECE | LPCR_HVICE;
mtlpcr(lpcr);
isync();
@@ -259,6 +259,25 @@ cpu_darn(void *arg)
timeout_add_msec(&cpu_darn_to, 10);
}
+uint64_t cpu_idle_state_psscr;
+void cpu_idle_spin(void);
+void (*cpu_idle_cycle_fcn)(void) = &cpu_idle_spin;
+
+void
+cpu_idle_cycle(void)
+{
+ intr_disable();
+
+ if (!cpu_is_idle(curcpu())) {
+ intr_enable();
+ return;
+ }
+
+ (*cpu_idle_cycle_fcn)();
+
+ intr_enable();
+}
+
#ifdef MULTIPROCESSOR
volatile int mp_perflevel;
@@ -378,6 +397,13 @@ cpu_kick(struct cpu_info *ci)
intr_send_ipi(ci, IPI_NOP);
}
+void
+cpu_unidle(struct cpu_info *ci)
+{
+ if (ci != curcpu())
+ intr_send_ipi(ci, IPI_NOP);
+}
+
/*
* Run ul_setperf(level) on every core.
*/
diff --git a/sys/arch/powerpc64/powerpc64/genassym.cf b/sys/arch/powerpc64/powerpc64/genassym.cf
index 96988f4c900..135fe585c7d 100644
--- a/sys/arch/powerpc64/powerpc64/genassym.cf
+++ b/sys/arch/powerpc64/powerpc64/genassym.cf
@@ -1,4 +1,4 @@
-# $OpenBSD: genassym.cf,v 1.13 2020/09/05 19:21:10 kettenis Exp $
+# $OpenBSD: genassym.cf,v 1.14 2020/12/30 06:06:30 gkoehler Exp $
#
# Copyright (c) 1982, 1990 The Regents of the University of California.
# All rights reserved.
@@ -41,6 +41,7 @@ struct cpu_info
member ci_curpcb
member ci_curproc
member ci_tempsave
+member ci_idle_sp_save
member ci_slbsave
member ci_slbstack
member ci_kernel_slb
diff --git a/sys/arch/powerpc64/powerpc64/locore.S b/sys/arch/powerpc64/powerpc64/locore.S
index 56e73e806f0..5d83bb28000 100644
--- a/sys/arch/powerpc64/powerpc64/locore.S
+++ b/sys/arch/powerpc64/powerpc64/locore.S
@@ -1,4 +1,4 @@
-/* $OpenBSD: locore.S,v 1.41 2020/10/22 23:35:43 mortimer Exp $ */
+/* $OpenBSD: locore.S,v 1.42 2020/12/30 06:06:30 gkoehler Exp $ */
/*
* Copyright (c) 2020 Mark Kettenis <kettenis@openbsd.org>
@@ -86,16 +86,111 @@ tmpstack_end:
.text
+/* For Power ISA v3, stop a hardware thread forever. */
+ .globl cpu_hatch_and_stop
+cpu_hatch_and_stop:
+ bl 1f
+1: mflr %r2
+ addis %r2, %r2, (.TOC. - 1b)@ha
+ addi %r2, %r2, (.TOC. - 1b)@l
+ /* Clear PECE bits to disable exiting from idle. */
+ li %r3, 0
+ mtspr 318, %r3 /* lpcr = 0 */
+ /* Set psscr to request idle state. */
+ addis %r3, %r2, cpu_idle_state_psscr@toc@ha
+ ld %r3, cpu_idle_state_psscr@toc@l(%r3)
+ mtspr 823, %r3
+1: stop
+ b 1b /* Lighter states might not use PECE. */
+
#endif
.globl cpu_idle_enter
cpu_idle_enter:
blr
- .globl cpu_idle_cycle
-cpu_idle_cycle:
+ .globl cpu_idle_spin
+cpu_idle_spin:
blr
+/* Idle for Power ISA v3. */
+ .globl cpu_idle_stop
+cpu_idle_stop:
+ /* Set psscr to request idle state. */
+ addis %r3, %r2, cpu_idle_state_psscr@toc@ha
+ ld %r3, cpu_idle_state_psscr@toc@l(%r3)
+ mtspr 823, %r3
+ /*
+ * POWER9 23.5.9.2 State Loss and Restoration: We may lose
+ * "any nonhypervisor thread context (such as, GPRs, VSRs,
+ * FPRs)" and "the following SPRs: CR, FPSCR, VSCR, XER, DSCR,
+ * AMR, IAMR, UAMOR, AMOR, DAWR, DAWRX."
+ */
+ mflr %r3
+ mfcr %r4
+ std %r3, 16(%r1)
+ stw %r4, 8(%r1)
+ std %r31, -8(%r1)
+ std %r30, -16(%r1)
+ std %r29, -24(%r1)
+ std %r28, -32(%r1)
+ std %r27, -40(%r1)
+ std %r26, -48(%r1)
+ std %r25, -56(%r1)
+ std %r24, -64(%r1)
+ std %r23, -72(%r1)
+ std %r22, -80(%r1)
+ std %r21, -88(%r1)
+ std %r20, -96(%r1)
+ std %r19, -104(%r1)
+ std %r18, -112(%r1)
+ std %r17, -120(%r1)
+ std %r16, -128(%r1)
+ std %r15, -136(%r1)
+ std %r14, -144(%r1)
+ /* Red zone ends at -288(%r1). */
+ mfsprg0 %r3
+ std %r1, CI_IDLE_SP_SAVE(%r3)
+ stop
+ /* If we continue here, then we lost no context. */
+ blr
+
+/* Come here from the system reset vector (rsttrapcode). */
+ .globl cpu_idle_restore_context
+cpu_idle_restore_context:
+ bl 1f
+1: mflr %r2
+ addis %r2, %r2, (.TOC. - 1b)@ha
+ addi %r2, %r2, (.TOC. - 1b)@l /* TOC pointer */
+ mfsprg0 %r3
+ ld %r1, CI_IDLE_SP_SAVE(%r3) /* stack pointer */
+ mfmsr %r4
+ ori %r4, %r4, PSL_DR@l /* data relocation on */
+ mtmsr %r4
+ ld %r14, -144(%r1)
+ ld %r15, -136(%r1)
+ ld %r16, -128(%r1)
+ ld %r17, -120(%r1)
+ ld %r18, -112(%r1)
+ ld %r19, -104(%r1)
+ ld %r20, -96(%r1)
+ ld %r21, -88(%r1)
+ ld %r22, -80(%r1)
+ ld %r23, -72(%r1)
+ ld %r24, -64(%r1)
+ ld %r25, -56(%r1)
+ ld %r26, -48(%r1)
+ ld %r27, -40(%r1)
+ ld %r28, -32(%r1)
+ ld %r29, -24(%r1)
+ ld %r30, -16(%r1)
+ ld %r31, -8(%r1)
+ lwz %r4, 8(%r1) /* cr */
+ ld %r5, 16(%r1) /* lr */
+ mtcr %r4
+ mtsrr0 %r5
+ rfid /* return from system reset interrupt */
+
.globl cpu_idle_leave
cpu_idle_leave:
blr
diff --git a/sys/arch/powerpc64/powerpc64/machdep.c b/sys/arch/powerpc64/powerpc64/machdep.c
index 2aa77e28269..0ffbd3aee5c 100644
--- a/sys/arch/powerpc64/powerpc64/machdep.c
+++ b/sys/arch/powerpc64/powerpc64/machdep.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: machdep.c,v 1.65 2020/11/08 20:37:24 mpi Exp $ */
+/* $OpenBSD: machdep.c,v 1.66 2020/12/30 06:06:30 gkoehler Exp $ */
/*
* Copyright (c) 2020 Mark Kettenis <kettenis@openbsd.org>
@@ -78,10 +78,12 @@ int opal_have_console_flush;
extern char trapcode[], trapcodeend[];
extern char hvtrapcode[], hvtrapcodeend[];
+extern char rsttrapcode[], rsttrapcodeend[];
extern char slbtrapcode[], slbtrapcodeend[];
extern char generictrap[];
extern char generichvtrap[];
extern char kern_slbtrap[];
+extern char cpu_idle_restore_context[];
extern char initstack[];
@@ -248,12 +250,16 @@ init_powernv(void *fdt, void *tocbase)
memcpy((void *)EXC_HFAC, hvtrapcode, hvtrapcodeend - hvtrapcode);
memcpy((void *)EXC_HVI, hvtrapcode, hvtrapcodeend - hvtrapcode);
+ /* System reset trap needs special handling. */
+ memcpy((void *)EXC_RST, rsttrapcode, rsttrapcodeend - rsttrapcode);
+
/* SLB trap needs special handling as well. */
memcpy((void *)EXC_DSE, slbtrapcode, slbtrapcodeend - slbtrapcode);
*((void **)TRAP_ENTRY) = generictrap;
*((void **)TRAP_HVENTRY) = generichvtrap;
*((void **)TRAP_SLBENTRY) = kern_slbtrap;
+ *((void **)TRAP_RSTENTRY) = cpu_idle_restore_context;
/* Make the stubs visible to the CPU. */
__syncicache(EXC_RSVD, EXC_LAST - EXC_RSVD);
diff --git a/sys/arch/powerpc64/powerpc64/trap_subr.S b/sys/arch/powerpc64/powerpc64/trap_subr.S
index 23e918a86d2..4a1c67b563e 100644
--- a/sys/arch/powerpc64/powerpc64/trap_subr.S
+++ b/sys/arch/powerpc64/powerpc64/trap_subr.S
@@ -1,4 +1,4 @@
-/* $OpenBSD: trap_subr.S,v 1.18 2020/09/25 17:31:27 kettenis Exp $ */
+/* $OpenBSD: trap_subr.S,v 1.19 2020/12/30 06:06:30 gkoehler Exp $ */
/* $NetBSD: trap_subr.S,v 1.20 2002/04/22 23:20:08 kleink Exp $ */
/*-
@@ -305,6 +305,30 @@ hvtrapcode:
blrl
hvtrapcodeend:
+/* System reset might be an exit from power-saving mode. */
+ .globl rsttrapcode, rsttrapcodeend
+rsttrapcode:
+ mtsprg1 %r1
+ mfcr %r1
+ mtsprg2 %r1 /* save cr */
+ mfsrr1 %r1
+ andis. %r1, %r1, 0x3 /* test srr1 bits 46:47 */
+ beq 1f
+ /* This is an exit from power-saving mode. */
+ ld %r1, TRAP_RSTENTRY(0) /* cpu_idle_restore_context */
+ mtctr %r1
+ bctr
+1: /* This is something else. */
+ mfsprg2 %r1
+ mtcr %r1 /* restore cr */
+ mflr %r1
+ mtsprg2 %r1
+ ld %r1, TRAP_ENTRY(0) /* generictrap */
+ mtlr %r1
+ li %r1, 0xe0
+ blrl
+rsttrapcodeend:
+
/*
* For SLB misses: do special things for the kernel
*
diff --git a/sys/dev/ofw/fdt.c b/sys/dev/ofw/fdt.c
index 9646d74eeb8..62ca7392c45 100644
--- a/sys/dev/ofw/fdt.c
+++ b/sys/dev/ofw/fdt.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: fdt.c,v 1.25 2020/07/18 09:44:59 kettenis Exp $ */
+/* $OpenBSD: fdt.c,v 1.26 2020/12/30 06:06:31 gkoehler Exp $ */
/*
* Copyright (c) 2009 Dariusz Swiderski <sfires@sfires.net>
@@ -1005,6 +1005,22 @@ OF_getpropint64(int handle, char *prop, uint64_t defval)
}
int
+OF_getpropint64array(int handle, char *prop, uint64_t *buf, int buflen)
+{
+ int len;
+ int i;
+
+ len = OF_getprop(handle, prop, buf, buflen);
+ if (len < 0 || (len % sizeof(uint64_t)))
+ return -1;
+
+ for (i = 0; i < len / sizeof(uint64_t); i++)
+ buf[i] = betoh64(buf[i]);
+
+ return len;
+}
+
+int
OF_nextprop(int handle, char *prop, void *nextprop)
{
void *node = (char *)tree.header + handle;
diff --git a/sys/dev/ofw/openfirm.h b/sys/dev/ofw/openfirm.h
index 57022b05c85..ea631c2f0e4 100644
--- a/sys/dev/ofw/openfirm.h
+++ b/sys/dev/ofw/openfirm.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: openfirm.h,v 1.16 2020/07/06 15:18:03 kettenis Exp $ */
+/* $OpenBSD: openfirm.h,v 1.17 2020/12/30 06:06:31 gkoehler Exp $ */
/* $NetBSD: openfirm.h,v 1.1 1996/09/30 16:35:10 ws Exp $ */
/*
@@ -53,6 +53,7 @@ int OF_getprop(int handle, char *prop, void *buf, int buflen);
uint32_t OF_getpropint(int handle, char *, uint32_t);
int OF_getpropintarray(int, char *, uint32_t *, int);
uint64_t OF_getpropint64(int handle, char *, uint64_t);
+int OF_getpropint64array(int, char *, uint64_t *, int);
int OF_setprop(int, char *, const void *, int);
int OF_nextprop(int, char *, void *);
int OF_finddevice(char *name);