Index: sys/arch/hppa/conf/files.hppa
===================================================================
RCS file: /cvsroot/src/sys/arch/hppa/conf/files.hppa,v
retrieving revision 1.29
diff -u -r1.29 files.hppa
--- sys/arch/hppa/conf/files.hppa 20 Oct 2025 09:42:46 -0000 1.29
+++ sys/arch/hppa/conf/files.hppa 17 Aug 2026 04:58:12 -0000
@@ -111,6 +111,7 @@
device fpu
attach fpu at gedoens
file arch/hppa/dev/fpu.c fpu
+defflag opt_hppa_fpu.h HPPA_FPU_EAGER
# Phantom PseudoBC GSC+ Port
device phantomas: gedoens
Index: sys/arch/hppa/hppa/fpu.c
===================================================================
RCS file: /cvsroot/src/sys/arch/hppa/hppa/fpu.c,v
retrieving revision 1.27
diff -u -r1.27 fpu.c
--- sys/arch/hppa/hppa/fpu.c 16 Apr 2020 05:44:43 -0000 1.27
+++ sys/arch/hppa/hppa/fpu.c 17 Aug 2026 04:58:12 -0000
@@ -36,6 +36,10 @@
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: fpu.c,v 1.27 2020/04/16 05:44:43 skrll Exp $");
+#ifdef _KERNEL_OPT
+#include "opt_hppa_fpu.h"
+#endif
+
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/proc.h>
@@ -78,10 +82,15 @@
/* The number of times we have had to switch the FPU context. */
u_int fpu_csw;
+/* Don't use the default lazy FPU switching */
+int fpu_eager;
+
/* In locore.S, this swaps states in and out of the FPU. */
void hppa_fpu_swapout(struct pcb *);
void hppa_fpu_swap(struct fpreg *, struct fpreg *);
+void hppa_fpu_switch(struct lwp *);
+
static int hppa_fpu_ls(struct trapframe *, struct lwp *);
/*
@@ -139,14 +148,16 @@
void
hppa_fpu_bootstrap(u_int ccr_enable)
{
- uint32_t junk[2];
- uint32_t vers[2];
+ uint32_t junk[2] __aligned(8);
+ uint32_t vers[2] __aligned(8);
+ u_int ccr;
/* See if we have a present and functioning hardware FPU. */
fpu_present = (ccr_enable & HPPA_FPUS) == HPPA_FPUS;
if (!fpu_present) {
fpu_csw = 0;
curcpu()->ci_fpu_state = 0;
+ curcpu()->ci_fpu_lwp = NULL;
return;
}
@@ -182,9 +193,32 @@
*/
fpu_csw = 0;
curcpu()->ci_fpu_state = 0;
+ curcpu()->ci_fpu_lwp = NULL;
mtctl(ccr_enable & (CCR_MASK ^ HPPA_FPUS), CR_CCR);
fpu_version = vers[0];
+
+#ifdef HPPA_FPU_EAGER
+ fpu_eager = 1;
+ aprint_normal("fpu: eager switching\n");
+#else
+ /*
+ * Handle QEMU, which does not check whether the FPU
+ * is disabled before trying to run instructions on it,
+ * thus never traps, thus never triggers our lazy FPU
+ * switching scheme.
+ */
+ mtctl(0, CR_CCR);
+ __asm volatile("fstds %%fr0, 0(%0)" :: "r" (junk) : "memory");
+ mfctl(CR_CCR, ccr);
+ if (!(ccr & HPPA_FPUS)) {
+ fpu_eager = 1;
+ /* No trap, so no trap handler, so re-enable FPU ourselves. */
+ mtctl(HPPA_FPUS, CR_CCR);
+ aprint_normal("fpu: emulation trap failure; "
+ "using eager switching\n");
+ }
+#endif
}
/*
@@ -212,6 +246,14 @@
hppa_fpu_swapout(pcb);
ci->ci_fpu_state = 0;
+ /*
+ * If we are doing eager FPU switching, hang onto the
+ * LWP - if it uses the FPU again, the regs will need to be
+ * saved again.
+ */
+ if (!fpu_eager) {
+ ci->ci_fpu_lwp = NULL;
+ }
}
/*
@@ -424,3 +466,28 @@
trapsignal(l, &ksi);
}
}
+/*
+ * Immediately switch current LWP's FP regs for those of the new LWP's;
+ * called from cpu_switchto if hppa_fpu_switch is set (if we are avoiding
+ * lazy FPU switching).
+ */
+void
+hppa_fpu_switch(struct lwp *newl)
+{
+ struct cpu_info *ci = curcpu();
+ struct pcb *oldpcb, *newpcb;
+ struct fpreg *oldregs = NULL, *newregs;
+
+ if (!fpu_present) return;
+ if (ci->ci_fpu_lwp == newl) return;
+
+ if (ci->ci_fpu_lwp != NULL) {
+ oldpcb = lwp_getpcb(ci->ci_fpu_lwp);
+ oldregs = oldpcb->pcb_fpregs;
+ }
+
+ newpcb = lwp_getpcb(newl);
+ newregs = newpcb->pcb_fpregs;
+
+ hppa_fpu_swap(oldregs, newregs);
+}
Index: sys/arch/hppa/hppa/locore.S
===================================================================
RCS file: /cvsroot/src/sys/arch/hppa/hppa/locore.S,v
retrieving revision 1.7
diff -u -r1.7 locore.S
--- sys/arch/hppa/hppa/locore.S 3 Apr 2025 17:49:49 -0000 1.7
+++ sys/arch/hppa/hppa/locore.S 17 Aug 2026 04:58:12 -0000
@@ -945,13 +945,35 @@
noras:
/*
- * We do have a hardware FPU. If the LWP
+ * We do have a hardware FPU. Two paths: eager
+ * (if selected by kernel config, or if emulation trap broken),
+ * or lazy.
+ */
+ .import fpu_eager, data
+ ldil L%fpu_eager, %t1
+ ldw R%fpu_eager(%t1), %t1
+ comib,=,n 0, %t1, L$fpu_lazy
+
+ /*
+ * Eager path - via C helper
+ */
+ stw %arg0, HPPA_FRAME_ARG(0)(%r3)
+ stw %arg1, HPPA_FRAME_ARG(1)(%r3)
+ copy %arg1, %arg0
+ CALL(hppa_fpu_switch, %r1)
+ ldw HPPA_FRAME_ARG(1)(%r3), %arg1
+ ldw HPPA_FRAME_ARG(0)(%r3), %arg0
+ b,n switch_return
+
+ /*
+ * Lazy path. If the LWP
* that we just switched to has its state in the
* FPU, enable the FPU, else disable it, so if
* the LWP does try to use the coprocessor
* we'll get an assist emulation trap to swap
* states.
*/
+L$fpu_lazy:
GET_CURCPU(%t1)
mfctl CR_CCR, %r1
mfctl CR_FPPADDR, %t2
Index: sys/arch/hppa/include/cpu.h
===================================================================
RCS file: /cvsroot/src/sys/arch/hppa/include/cpu.h,v
retrieving revision 1.13
diff -u -r1.13 cpu.h
--- sys/arch/hppa/include/cpu.h 23 Feb 2023 14:55:36 -0000 1.13
+++ sys/arch/hppa/include/cpu.h 17 Aug 2026 04:58:12 -0000
@@ -290,6 +290,8 @@
hppa_hpa_t ci_hpa;
register_t ci_psw; /* Processor Status Word. */
paddr_t ci_fpu_state; /* LWP FPU state address, or zero. */
+ struct lwp *ci_fpu_lwp; /* If eager mode, LWP vaddr or NULL */
+
u_long ci_itmr;
int ci_cpuid; /* CPU index (see cpus[] array) */