Module Name: src
Committed By: matt
Date: Mon May 2 02:01:33 UTC 2011
Modified Files:
src/sys/arch/powerpc/booke: spe.c trap.c
src/sys/arch/powerpc/conf: files.powerpc
src/sys/arch/powerpc/include: altivec.h fpu.h proc.h psl.h types.h
userret.h
src/sys/arch/powerpc/oea: altivec.c
src/sys/arch/powerpc/pic: ipi.c
src/sys/arch/powerpc/powerpc: compat_16_machdep.c core_machdep.c fpu.c
powerpc_machdep.c process_machdep.c trap.c vm_machdep.c
Log Message:
Move powerpc to use pcu to manage FPU/AltiVec/SPE.
To generate a diff of this commit:
cvs rdiff -u -r1.2 -r1.3 src/sys/arch/powerpc/booke/spe.c
cvs rdiff -u -r1.5 -r1.6 src/sys/arch/powerpc/booke/trap.c
cvs rdiff -u -r1.75 -r1.76 src/sys/arch/powerpc/conf/files.powerpc
cvs rdiff -u -r1.13 -r1.14 src/sys/arch/powerpc/include/altivec.h
cvs rdiff -u -r1.17 -r1.18 src/sys/arch/powerpc/include/fpu.h
cvs rdiff -u -r1.10 -r1.11 src/sys/arch/powerpc/include/proc.h
cvs rdiff -u -r1.16 -r1.17 src/sys/arch/powerpc/include/psl.h
cvs rdiff -u -r1.39 -r1.40 src/sys/arch/powerpc/include/types.h
cvs rdiff -u -r1.19 -r1.20 src/sys/arch/powerpc/include/userret.h
cvs rdiff -u -r1.21 -r1.22 src/sys/arch/powerpc/oea/altivec.c
cvs rdiff -u -r1.7 -r1.8 src/sys/arch/powerpc/pic/ipi.c
cvs rdiff -u -r1.17 -r1.18 src/sys/arch/powerpc/powerpc/compat_16_machdep.c
cvs rdiff -u -r1.6 -r1.7 src/sys/arch/powerpc/powerpc/core_machdep.c
cvs rdiff -u -r1.28 -r1.29 src/sys/arch/powerpc/powerpc/fpu.c
cvs rdiff -u -r1.47 -r1.48 src/sys/arch/powerpc/powerpc/powerpc_machdep.c
cvs rdiff -u -r1.30 -r1.31 src/sys/arch/powerpc/powerpc/process_machdep.c
cvs rdiff -u -r1.139 -r1.140 src/sys/arch/powerpc/powerpc/trap.c
cvs rdiff -u -r1.83 -r1.84 src/sys/arch/powerpc/powerpc/vm_machdep.c
Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.
Modified files:
Index: src/sys/arch/powerpc/booke/spe.c
diff -u src/sys/arch/powerpc/booke/spe.c:1.2 src/sys/arch/powerpc/booke/spe.c:1.3
--- src/sys/arch/powerpc/booke/spe.c:1.2 Tue Jan 18 01:02:52 2011
+++ src/sys/arch/powerpc/booke/spe.c Mon May 2 02:01:32 2011
@@ -1,4 +1,4 @@
-/* $NetBSD: spe.c,v 1.2 2011/01/18 01:02:52 matt Exp $ */
+/* $NetBSD: spe.c,v 1.3 2011/05/02 02:01:32 matt Exp $ */
/*-
* Copyright (c) 2011 The NetBSD Foundation, Inc.
@@ -30,7 +30,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: spe.c,v 1.2 2011/01/18 01:02:52 matt Exp $");
+__KERNEL_RCSID(0, "$NetBSD: spe.c,v 1.3 2011/05/02 02:01:32 matt Exp $");
#include "opt_altivec.h"
@@ -41,6 +41,7 @@
#include <sys/systm.h>
#include <sys/atomic.h>
#include <sys/siginfo.h>
+#include <sys/pcu.h>
#include <powerpc/altivec.h>
#include <powerpc/spr.h>
@@ -48,13 +49,33 @@
#include <powerpc/psl.h>
#include <powerpc/pcb.h>
-void
-vec_enable(void)
+static void vec_state_load(lwp_t *, bool);
+static void vec_state_save(lwp_t *);
+static void vec_state_release(lwp_t *);
+
+const pcu_ops_t vec_ops = {
+ .pcu_id = PCU_VEC,
+ .pcu_state_load = vec_state_load,
+ .pcu_state_save = vec_state_save,
+ .pcu_state_release = vec_state_release,
+};
+
+bool
+vec_used_p(lwp_t *l)
{
- struct cpu_info * const ci = curcpu();
- lwp_t * const l = curlwp;
+ return (l->l_md.md_flags & MDLWP_USEDVEC) != 0;
+}
+void
+vec_mark_used(lwp_t *l)
+{
l->l_md.md_flags |= MDLWP_USEDVEC;
+}
+
+void
+vec_state_load(lwp_t *l, bool used)
+{
+ struct pcb * const pcb = lwp_getpcb(l);
/*
* Enable SPE temporarily (and disable interrupts).
@@ -63,37 +84,30 @@
mtmsr((msr & ~PSL_EE) | PSL_SPV);
__asm volatile ("isync");
- if (ci->ci_veclwp != l) {
- struct pcb * const pcb = lwp_getpcb(l);
- /*
- * Save the existing state (if any).
- */
- vec_save_cpu(VEC_SAVE_AND_RELEASE);
-
- /*
- * Call an assembly routine to do load everything.
- */
- vec_load_from_vreg(&pcb->pcb_vr);
-
- /*
- * Enable SPE when we return to user-mode (we overload the
- * ALTIVEC flags). Record the new ownership of the SPE unit.
- */
- ci->ci_veclwp = l;
- l->l_md.md_veccpu = ci;
- }
+ /*
+ * Call an assembly routine to do load everything.
+ */
+ vec_load_from_vreg(&pcb->pcb_vr);
__asm volatile ("sync");
- l->l_md.md_flags |= MDLWP_OWNVEC;
+
/*
* Restore MSR (turn off SPE)
*/
mtmsr(msr);
+ __asm volatile ("isync");
+
+ /*
+ * Note that vector has now been used.
+ */
+ l->l_md.md_flags |= MDLWP_USEDVEC;
}
void
-vec_save_cpu(enum vec_op op)
+vec_state_save(lwp_t *l)
{
+ struct pcb * const pcb = lwp_getpcb(l);
+
/*
* Turn on SPE, turn off interrupts.
*/
@@ -101,71 +115,27 @@
mtmsr((msr & ~PSL_EE) | PSL_SPV);
__asm volatile ("isync");
- struct cpu_info * const ci = curcpu();
- lwp_t * const l = ci->ci_veclwp;
-
- KASSERTMSG(l->l_md.md_veccpu == ci,
- ("%s: veccpu (%p) != ci (%p)\n", __func__, l->l_md.md_veccpu, ci));
- if (l->l_md.md_flags & MDLWP_OWNVEC) {
- struct pcb * const pcb = lwp_getpcb(l);
-
- /*
- * Save the vector state which is best done in assembly.
- */
- vec_unload_to_vreg(&pcb->pcb_vr);
-
- /*
- * Indicate that VEC unit is unloaded
- */
- l->l_md.md_flags &= ~MDLWP_OWNVEC;
-
- /*
- * If asked to, give up the VEC unit.
- */
- if (op == VEC_SAVE_AND_RELEASE)
- ci->ci_veclwp = ci->ci_data.cpu_idlelwp;
- }
+ /*
+ * Save the vector state which is best done in assembly.
+ */
+ vec_unload_to_vreg(&pcb->pcb_vr);
+ __asm volatile ("sync");
/*
* Restore MSR (turn off SPE)
*/
mtmsr(msr);
+ __asm volatile ("isync");
}
-/*
- * Save a lwp's SPE state to its PCB. The lwp must either be curlwp or traced
- * by curlwp (and stopped). (The point being that the lwp must not be onproc
- * on another CPU during this function).
- */
void
-vec_save_lwp(lwp_t *l, enum vec_op op)
+vec_state_release(lwp_t *l)
{
- struct cpu_info * const ci = curcpu();
-
- /*
- * If it's already in the PCB, there's nothing to do.
- */
- if ((l->l_md.md_flags & MDLWP_OWNVEC) == 0)
- return;
-
/*
- * If we simply need to discard the information, then don't
- * to save anything.
+ * Turn off SPV so the next SPE instruction will cause a
+ * SPE unavailable exception
*/
- if (op == VEC_DISCARD) {
- struct cpu_info * const veccpu = l->l_md.md_veccpu;
-#ifndef MULTIPROCESSOR
- KASSERT(ci == veccpu);
-#endif
- KASSERT(l == veccpu->ci_veclwp);
- KASSERT(l == curlwp || ci == veccpu);
- ci->ci_veclwp = ci->ci_data.cpu_idlelwp;
- atomic_and_uint(&l->l_md.md_flags, ~MDLWP_OWNVEC);
- return;
- }
-
- KASSERT(l == ci->ci_veclwp);
- vec_save_cpu(op);
+ l->l_md.md_utf->tf_srr1 &= ~PSL_SPV;
}
void
@@ -174,7 +144,9 @@
struct pcb * const pcb = lwp_getpcb(l);
const union __vr *vr = mcp->__vrf.__vrs;
- vec_save_lwp(l, VEC_DISCARD);
+ KASSERT(l == curlwp);
+
+ vec_save();
/* grab the accumulator */
pcb->pcb_vr.vreg[8][0] = vr->__vr32[2];
@@ -198,10 +170,12 @@
{
struct pcb * const pcb = lwp_getpcb(l);
- if ((l->l_md.md_flags & MDLWP_USEDVEC) == 0)
+ KASSERT(l == curlwp);
+
+ if (!vec_used_p(l))
return false;
- vec_save_lwp(l, VEC_SAVE);
+ vec_save();
mcp->__gregs[_REG_MSR] |= PSL_SPV;
Index: src/sys/arch/powerpc/booke/trap.c
diff -u src/sys/arch/powerpc/booke/trap.c:1.5 src/sys/arch/powerpc/booke/trap.c:1.6
--- src/sys/arch/powerpc/booke/trap.c:1.5 Thu Feb 17 13:53:32 2011
+++ src/sys/arch/powerpc/booke/trap.c Mon May 2 02:01:32 2011
@@ -1,4 +1,4 @@
-/* $NetBSD: trap.c,v 1.5 2011/02/17 13:53:32 matt Exp $ */
+/* $NetBSD: trap.c,v 1.6 2011/05/02 02:01:32 matt Exp $ */
/*-
* Copyright (c) 2010, 2011 The NetBSD Foundation, Inc.
* All rights reserved.
@@ -39,7 +39,7 @@
#include <sys/cdefs.h>
-__KERNEL_RCSID(1, "$NetBSD: trap.c,v 1.5 2011/02/17 13:53:32 matt Exp $");
+__KERNEL_RCSID(1, "$NetBSD: trap.c,v 1.6 2011/05/02 02:01:32 matt Exp $");
#include <sys/param.h>
#include <sys/systm.h>
@@ -400,7 +400,7 @@
ci->ci_ev_vec.ev_count++;
#ifdef PPC_HAVE_SPE
- vec_enable();
+ vec_load();
return 0;
#else
KSI_INIT_TRAP(ksi);
Index: src/sys/arch/powerpc/conf/files.powerpc
diff -u src/sys/arch/powerpc/conf/files.powerpc:1.75 src/sys/arch/powerpc/conf/files.powerpc:1.76
--- src/sys/arch/powerpc/conf/files.powerpc:1.75 Tue Apr 26 15:51:24 2011
+++ src/sys/arch/powerpc/conf/files.powerpc Mon May 2 02:01:32 2011
@@ -1,4 +1,4 @@
-# $NetBSD: files.powerpc,v 1.75 2011/04/26 15:51:24 joerg Exp $
+# $NetBSD: files.powerpc,v 1.76 2011/05/02 02:01:32 matt Exp $
defflag opt_altivec.h ALTIVEC K_ALTIVEC PPC_HAVE_SPE
defflag opt_openpic.h OPENPIC OPENPIC_SERIAL_MODE
@@ -35,6 +35,7 @@
file arch/powerpc/powerpc/db_disasm.c ddb
file arch/powerpc/powerpc/db_interface.c ddb | kgdb
file arch/powerpc/powerpc/db_trace.c ddb
+file arch/powerpc/powerpc/fpu.c
# IBM 4xx Family files (40x)
file arch/powerpc/ibm4xx/pmap.c ppc_ibm4xx
@@ -53,7 +54,6 @@
file arch/powerpc/oea/pmap64.c ppc_oea64
file arch/powerpc/oea/pmap64_bridge.c ppc_oea64_bridge
file arch/powerpc/oea/pmap_kernel.c ppc_oea | ppc_oea64 | ppc_oea64_bridge | ppc_oea601
-file arch/powerpc/powerpc/fpu.c ppc_oea | ppc_oea64 | ppc_oea64_bridge | ppc_oea601
file arch/powerpc/powerpc/trap.c ppc_oea | ppc_oea64 | ppc_oea64_bridge | ppc_oea601
# PPC BookE (MPC85xx) Family files
Index: src/sys/arch/powerpc/include/altivec.h
diff -u src/sys/arch/powerpc/include/altivec.h:1.13 src/sys/arch/powerpc/include/altivec.h:1.14
--- src/sys/arch/powerpc/include/altivec.h:1.13 Tue Jan 18 01:02:54 2011
+++ src/sys/arch/powerpc/include/altivec.h Mon May 2 02:01:32 2011
@@ -1,4 +1,4 @@
-/* $NetBSD: altivec.h,v 1.13 2011/01/18 01:02:54 matt Exp $ */
+/* $NetBSD: altivec.h,v 1.14 2011/05/02 02:01:32 matt Exp $ */
/*-
* Copyright (c) 1999 The NetBSD Foundation, Inc.
@@ -36,24 +36,44 @@
#define VSCR_NJ 0x00010000 /* Non Java-IEEE-C9X FP mode */
#ifdef _KERNEL
+#include <sys/pcu.h>
#include <powerpc/mcontext.h>
-enum vec_op { VEC_SAVE, VEC_DISCARD, VEC_SAVE_AND_RELEASE };
struct lwp;
struct vreg;
struct trapframe;
-void vec_enable(void);
-void vec_save_cpu(enum vec_op);
-void vec_save_lwp(struct lwp *, enum vec_op);
+extern const pcu_ops_t vec_ops;
+
+bool vec_used_p(struct lwp *);
+void vec_mark_used(struct lwp *);
+
void vec_restore_from_mcontext(struct lwp *, const mcontext_t *);
bool vec_save_to_mcontext(struct lwp *, mcontext_t *, unsigned int *);
+int vec_siginfo_code(const struct trapframe *);
+
+static inline void
+vec_load(void)
+{
+ pcu_load(&vec_ops);
+}
+
+static inline void
+vec_save(void)
+{
+ pcu_load(&vec_ops);
+}
+
+static inline void
+vec_discard(void)
+{
+ pcu_discard(&vec_ops);
+}
+
void vec_load_from_vreg(const struct vreg *);
void vec_unload_to_vreg(struct vreg *);
-int vec_siginfo_code(const struct trapframe *);
-
/* OEA only */
void vzeropage(paddr_t);
void vcopypage(paddr_t, paddr_t); /* dst, src */
Index: src/sys/arch/powerpc/include/fpu.h
diff -u src/sys/arch/powerpc/include/fpu.h:1.17 src/sys/arch/powerpc/include/fpu.h:1.18
--- src/sys/arch/powerpc/include/fpu.h:1.17 Tue Jan 18 01:02:54 2011
+++ src/sys/arch/powerpc/include/fpu.h Mon May 2 02:01:33 2011
@@ -1,4 +1,4 @@
-/* $NetBSD: fpu.h,v 1.17 2011/01/18 01:02:54 matt Exp $ */
+/* $NetBSD: fpu.h,v 1.18 2011/05/02 02:01:33 matt Exp $ */
/*-
* Copyright (C) 1996 Wolfgang Solfrank.
@@ -73,24 +73,47 @@
#include "opt_multiprocessor.h"
#endif
-/* List of PowerPC architectures that support FPUs. */
-#if defined(PPC_OEA) || defined (PPC_OEA64) || defined (PPC_OEA64_BRIDGE)
-#define PPC_HAVE_FPU
+#include <sys/pcu.h>
+#include <powerpc/mcontext.h>
struct lwp;
-struct fpreg;
-enum fpu_op { FPU_SAVE, FPU_DISCARD, FPU_SAVE_AND_RELEASE };
+bool fpu_used_p(struct lwp *);
+void fpu_mark_used(struct lwp *);
-void fpu_enable(void);
-void fpu_save_cpu(enum fpu_op);
-void fpu_save_lwp(struct lwp *, enum fpu_op);
void fpu_restore_from_mcontext(struct lwp *, const mcontext_t *);
bool fpu_save_to_mcontext(struct lwp *, mcontext_t *, unsigned int *);
-int fpu_get_fault_code(void);
+extern const pcu_ops_t fpu_ops;
+
+/* List of PowerPC architectures that support FPUs. */
+#if defined(PPC_OEA) || defined (PPC_OEA64) || defined (PPC_OEA64_BRIDGE)
+#define PPC_HAVE_FPU
+
+struct fpreg;
+
+static inline void
+fpu_load(void)
+{
+ pcu_load(&fpu_ops);
+}
+
+static inline void
+fpu_save(void)
+{
+ pcu_save(&fpu_ops);
+}
+
+static inline void
+fpu_discard(void)
+{
+ pcu_discard(&fpu_ops);
+}
void fpu_load_from_fpreg(const struct fpreg *);
void fpu_unload_to_fpreg(struct fpreg *);
+
+int fpu_get_fault_code(void);
+
#endif /* PPC_HAVE_FPU */
#endif /* _KERNEL */
Index: src/sys/arch/powerpc/include/proc.h
diff -u src/sys/arch/powerpc/include/proc.h:1.10 src/sys/arch/powerpc/include/proc.h:1.11
--- src/sys/arch/powerpc/include/proc.h:1.10 Tue Jan 18 01:02:54 2011
+++ src/sys/arch/powerpc/include/proc.h Mon May 2 02:01:33 2011
@@ -1,4 +1,4 @@
-/* $NetBSD: proc.h,v 1.10 2011/01/18 01:02:54 matt Exp $ */
+/* $NetBSD: proc.h,v 1.11 2011/05/02 02:01:33 matt Exp $ */
/*-
* Copyright (C) 1995, 1996 Wolfgang Solfrank.
@@ -39,14 +39,10 @@
*/
struct mdlwp {
volatile int md_flags;
- struct cpu_info * volatile md_fpucpu; /* last cpu FP was used on */
- struct cpu_info * volatile md_veccpu; /* last cpu VEC was used on */
struct trapframe *md_utf; /* user trampframe */
};
-#define MDLWP_USEDFPU 0x0001 /* this thread has used the FPU */
-#define MDLWP_OWNFPU 0x0002 /* this thread is using the FPU */
-#define MDLWP_USEDVEC 0x0010 /* this thread has used the VEC */
-#define MDLWP_OWNVEC 0x0020 /* this thread is using the VEC */
+#define MDLWP_USEDFPU __BIT(PCU_FPU) /* this thread has used the FPU */
+#define MDLWP_USEDVEC __BIT(PCU_VEC) /* this thread has used the VEC */
struct trapframe;
@@ -58,8 +54,6 @@
#define LWP0_CPU_INFO &cpu_info[0]
#define LWP0_MD_INITIALIZER { \
.md_flags = 0, \
- .md_fpucpu = LWP0_CPU_INFO, \
- .md_veccpu = LWP0_CPU_INFO, \
.md_utf = (void *)0xdeadbeef, \
}
#endif /* _KERNEL */
Index: src/sys/arch/powerpc/include/psl.h
diff -u src/sys/arch/powerpc/include/psl.h:1.16 src/sys/arch/powerpc/include/psl.h:1.17
--- src/sys/arch/powerpc/include/psl.h:1.16 Tue Jan 18 01:02:54 2011
+++ src/sys/arch/powerpc/include/psl.h Mon May 2 02:01:33 2011
@@ -1,4 +1,4 @@
-/* $NetBSD: psl.h,v 1.16 2011/01/18 01:02:54 matt Exp $ */
+/* $NetBSD: psl.h,v 1.17 2011/05/02 02:01:33 matt Exp $ */
/*
* Copyright (C) 1995, 1996 Wolfgang Solfrank.
@@ -109,8 +109,8 @@
#define PSL_USERMOD cpu_pslusermod
#elif defined(PPC_BOOKE)
#define PSL_USERSET (PSL_EE | PSL_PR | PSL_ME | PSL_CE | PSL_DE | PSL_IS | PSL_DS)
-#define PSL_USERSRR1 ((PSL_USERSET|PSL_USERMOD) & (PSL_CE|0xFFFF))
-#define PSL_USERMOD (0)
+#define PSL_USERSRR1 ((PSL_USERSET|PSL_USERMOD) & (PSL_SPV|PSL_CE|0xFFFF))
+#define PSL_USERMOD (PSL_SPV)
#else /* PPC_IBM4XX */
#define PSL_USERSET (PSL_EE | PSL_PR | PSL_ME | PSL_IR | PSL_DR)
#define PSL_USERMOD (0)
Index: src/sys/arch/powerpc/include/types.h
diff -u src/sys/arch/powerpc/include/types.h:1.39 src/sys/arch/powerpc/include/types.h:1.40
--- src/sys/arch/powerpc/include/types.h:1.39 Thu Apr 7 02:04:06 2011
+++ src/sys/arch/powerpc/include/types.h Mon May 2 02:01:33 2011
@@ -1,4 +1,4 @@
-/* $NetBSD: types.h,v 1.39 2011/04/07 02:04:06 matt Exp $ */
+/* $NetBSD: types.h,v 1.40 2011/05/02 02:01:33 matt Exp $ */
/*-
* Copyright (C) 1995 Wolfgang Solfrank.
@@ -82,4 +82,10 @@
#define __HAVE___LWP_SETTCB
#define __HAVE_TLS_VARIANT_I
+#if defined(_KERNEL) || defined(_KMEMUSER)
+#define PCU_FPU 0 /* FPU */
+#define PCU_VEC 1 /* AltiVec/SPE */
+#define PCU_UNIT_COUNT 2
+#endif
+
#endif /* _MACHTYPES_H_ */
Index: src/sys/arch/powerpc/include/userret.h
diff -u src/sys/arch/powerpc/include/userret.h:1.19 src/sys/arch/powerpc/include/userret.h:1.20
--- src/sys/arch/powerpc/include/userret.h:1.19 Sat Feb 19 19:18:11 2011
+++ src/sys/arch/powerpc/include/userret.h Mon May 2 02:01:33 2011
@@ -1,4 +1,4 @@
-/* $NetBSD: userret.h,v 1.19 2011/02/19 19:18:11 matt Exp $ */
+/* $NetBSD: userret.h,v 1.20 2011/05/02 02:01:33 matt Exp $ */
/*
* Copyright (C) 1995, 1996 Wolfgang Solfrank.
@@ -50,50 +50,21 @@
static __inline void
userret(struct lwp *l, struct trapframe *tf)
{
-#if defined(PPC_HAVE_FPU) || defined(ALTIVEC) || defined(PPC_HAVE_SPE)
- struct cpu_info * const ci = curcpu();
-#endif
-
KASSERTMSG((tf == trapframe(curlwp)),
- ("tf=%p, trapframe(curlwp)=%p\n", tf, trapframe(curlwp)));
+ ("tf=%p, trapframe(curlwp)=%p\n", tf, trapframe(curlwp)));
/* Invoke MI userret code */
mi_userret(l);
tf->tf_srr1 &= PSL_USERSRR1; /* clear SRR1 status bits */
- /*
- * If someone stole the fp or vector unit while we were away,
- * disable it. Note that if the PSL FP/VEC bits aren't set, then
- * we don't own it.
- */
-#ifdef PPC_HAVE_FPU
- if ((tf->tf_srr1 & PSL_FP) &&
- (l != ci->ci_fpulwp || l->l_md.md_fpucpu != ci)) {
- tf->tf_srr1 &= ~(PSL_FP|PSL_FE0|PSL_FE1);
- }
-#endif
#ifdef ALTIVEC
/*
* We need to manually restore PSL_VEC each time we return
- * to user mode since PSL_VEC is not preserved in SRR1.
+ * to user mode since PSL_VEC isn't always preserved in SRR1.
+ * We keep a copy of it in md_flags to make restoring easier.
*/
- if (tf->tf_srr1 & PSL_VEC) {
- if (l != ci->ci_veclwp)
- tf->tf_srr1 &= ~PSL_VEC;
- } else {
- if (l == ci->ci_veclwp)
- tf->tf_srr1 |= PSL_VEC;
- }
-
- /*
- * If the new process isn't the current AltiVec process on this
- * CPU, we need to stop any data streams that are active (since
- * it will be a different address space).
- */
- if (ci->ci_veclwp != &lwp0 && ci->ci_veclwp != l) {
- __asm volatile("dssall;sync");
- }
+ tf->tf_srr1 |= l->l_md.md_flags & PSL_VEC;
#endif
#ifdef PPC_BOOKE
/*
@@ -107,18 +78,4 @@
booke_sstep(tf);
}
#endif
-#ifdef PPC_HAVE_SPE
- /*
- * We need to manually restore PSL_SPV each time we return
- * to user mode since PSL_SPV is not preserved in SRR1 since
- * we don't include it in PSL_USERSRR1 to control its setting.
- */
- if (tf->tf_srr1 & PSL_SPV) {
- if (l != ci->ci_veclwp)
- tf->tf_srr1 &= ~PSL_SPV;
- } else {
- if (l == ci->ci_veclwp)
- tf->tf_srr1 |= PSL_SPV;
- }
-#endif
}
Index: src/sys/arch/powerpc/oea/altivec.c
diff -u src/sys/arch/powerpc/oea/altivec.c:1.21 src/sys/arch/powerpc/oea/altivec.c:1.22
--- src/sys/arch/powerpc/oea/altivec.c:1.21 Tue Feb 8 06:14:50 2011
+++ src/sys/arch/powerpc/oea/altivec.c Mon May 2 02:01:33 2011
@@ -1,4 +1,4 @@
-/* $NetBSD: altivec.c,v 1.21 2011/02/08 06:14:50 matt Exp $ */
+/* $NetBSD: altivec.c,v 1.22 2011/05/02 02:01:33 matt Exp $ */
/*
* Copyright (C) 1996 Wolfgang Solfrank.
@@ -32,7 +32,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: altivec.c,v 1.21 2011/02/08 06:14:50 matt Exp $");
+__KERNEL_RCSID(0, "$NetBSD: altivec.c,v 1.22 2011/05/02 02:01:33 matt Exp $");
#include "opt_multiprocessor.h"
@@ -49,198 +49,105 @@
#include <powerpc/oea/spr.h>
#include <powerpc/psl.h>
-#ifdef MULTIPROCESSOR
-#include <arch/powerpc/pic/picvar.h>
-#include <arch/powerpc/pic/ipivar.h>
-static void vec_mp_save_lwp(struct lwp *);
-#endif
+static void vec_state_load(lwp_t *, bool);
+static void vec_state_save(lwp_t *);
+static void vec_state_release(lwp_t *);
+
+const pcu_ops_t vec_ops = {
+ .pcu_id = PCU_VEC,
+ .pcu_state_load = vec_state_load,
+ .pcu_state_save = vec_state_save,
+ .pcu_state_release = vec_state_release,
+};
-void
-vec_enable(void)
+bool
+vec_used_p(lwp_t *l)
{
- struct cpu_info *ci = curcpu();
- struct lwp *l = curlwp;
- register_t msr;
-
- KASSERT(l->l_md.md_veccpu != NULL);
+ return (l->l_md.md_flags & MDLWP_USEDVEC) != 0;
+}
+void
+vec_mark_used(lwp_t *l)
+{
l->l_md.md_flags |= MDLWP_USEDVEC;
+}
+
+void
+vec_state_load(lwp_t *l, bool used)
+{
+ struct pcb * const pcb = lwp_getpcb(l);
/*
* Enable AltiVec temporarily (and disable interrupts).
*/
- msr = mfmsr();
+ const register_t msr = mfmsr();
mtmsr((msr & ~PSL_EE) | PSL_VEC);
__asm volatile ("isync");
- if (ci->ci_veclwp != l) {
- struct pcb * const pcb = lwp_getpcb(l);
- struct trapframe * const tf = l->l_md.md_utf;
-
- vec_save_cpu(VEC_SAVE_AND_RELEASE);
-
- /*
- * Load the vector unit from vreg which is best done in
- * assembly.
- */
- vec_load_from_vreg(&pcb->pcb_vr);
-
- /*
- * VRSAVE will be restored when trap frame returns
- */
- tf->tf_vrsave = pcb->pcb_vr.vrsave;
-
- /*
- * Enable AltiVec when we return to user-mode.
- * Record the new ownership of the AltiVec unit.
- */
- ci->ci_veclwp = l;
- l->l_md.md_veccpu = ci;
- __asm volatile ("sync");
- }
- l->l_md.md_flags |= MDLWP_OWNVEC;
-
/*
- * Restore MSR (turn off AltiVec)
+ * Load the vector unit from vreg which is best done in
+ * assembly.
*/
- mtmsr(msr);
-}
+ vec_load_from_vreg(&pcb->pcb_vr);
-void
-vec_save_cpu(enum vec_op op)
-{
/*
- * Turn on AltiVEC, turn off interrupts.
+ * VRSAVE will be restored when trap frame returns
*/
- const register_t msr = mfmsr();
- mtmsr((msr & ~PSL_EE) | PSL_VEC);
- __asm volatile ("isync");
-
- struct cpu_info * const ci = curcpu();
- lwp_t * const l = ci->ci_veclwp;
-
- if (l->l_md.md_flags & MDLWP_OWNVEC) {
- struct pcb * const pcb = lwp_getpcb(l);
- struct trapframe * const tf = l->l_md.md_utf;
-
- /*
- * Grab contents of vector unit.
- */
- vec_unload_to_vreg(&pcb->pcb_vr);
-
- /*
- * Save VRSAVE
- */
- pcb->pcb_vr.vrsave = tf->tf_vrsave;
-
- /*
- * Note that we aren't using any CPU resources and stop any
- * data streams.
- */
- __asm volatile ("dssall; sync");
-
- /*
- * Disclaim ownership.
- */
- l->l_md.md_flags &= ~MDLWP_OWNVEC;
-
- /*
- * Give up the VEC unit if are releasing it too.
- */
- if (op == VEC_SAVE_AND_RELEASE)
- ci->ci_veclwp = ci->ci_data.cpu_idlelwp;
- }
+ l->l_md.md_utf->tf_vrsave = pcb->pcb_vr.vrsave;
/*
* Restore MSR (turn off AltiVec)
*/
mtmsr(msr);
-}
+ __asm volatile ("isync");
-#ifdef MULTIPROCESSOR
-/*
- * Save a process's AltiVEC state to its PCB. The state may be in any CPU.
- * The process must either be curproc or traced by curproc (and stopped).
- * (The point being that the process must not run on another CPU during
- * this function).
- */
-static void
-vec_mp_save_lwp(struct lwp *l)
-{
/*
- * Send an IPI to the other CPU with the data and wait for that CPU
- * to flush the data. Note that the other CPU might have switched
- * to a different proc's AltiVEC state by the time it receives the IPI,
- * but that will only result in an unnecessary reload.
- */
-
- if ((l->l_md.md_flags & MDLWP_OWNVEC) == 0)
- return;
-
- ppc_send_ipi(l->l_md.md_veccpu->ci_cpuid, PPC_IPI_FLUSH_VEC);
-
- /* Wait for flush. */
- for (u_int i = 0; i < 0x3fffffff; i++) {
- if ((l->l_md.md_flags & MDLWP_OWNVEC) == 0)
- return;
- }
-
- panic("%s/%d timed out: pid = %d.%d, veccpu->ci_cpuid = %d\n",
- __func__, cpu_number(), l->l_proc->p_pid, l->l_lid,
- l->l_md.md_veccpu->ci_cpuid);
+ * Mark vector registers as modified.
+ */
+ l->l_md.md_flags |= MDLWP_USEDVEC;
}
-#endif /*MULTIPROCESSOR*/
-/*
- * Save a process's AltiVEC state to its PCB. The state may be in any CPU.
- * The process must either be curproc or traced by curproc (and stopped).
- * (The point being that the process must not run on another CPU during
- * this function).
- */
void
-vec_save_lwp(struct lwp *l, enum vec_op op)
+vec_state_save(lwp_t *l)
{
- struct cpu_info * const ci = curcpu();
-
- KASSERT(l->l_md.md_veccpu != NULL);
+ struct pcb * const pcb = lwp_getpcb(l);
/*
- * If it's already in the PCB, there's nothing to do.
+ * Turn on AltiVEC, turn off interrupts.
*/
- if ((l->l_md.md_flags & MDLWP_OWNVEC) == 0)
- return;
+ const register_t msr = mfmsr();
+ mtmsr((msr & ~PSL_EE) | PSL_VEC);
+ __asm volatile ("isync");
/*
- * If we simply need to discard the information, then don't
- * to save anything.
+ * Grab contents of vector unit.
*/
- if (op == VEC_DISCARD) {
-#ifndef MULTIPROCESSOR
- KASSERT(ci == l->l_md.md_veccpu);
-#endif
- KASSERT(l == l->l_md.md_veccpu->ci_veclwp);
- KASSERT(l == curlwp || ci == l->l_md.md_veccpu);
- ci->ci_veclwp = ci->ci_data.cpu_idlelwp;
- atomic_and_uint(&l->l_md.md_flags, ~MDLWP_OWNVEC);
- return;
- }
+ vec_unload_to_vreg(&pcb->pcb_vr);
/*
- * If the state is in the current CPU, just flush the current CPU's
- * state.
+ * Save VRSAVE
*/
- if (l == ci->ci_veclwp) {
- vec_save_cpu(op);
- return;
- }
+ pcb->pcb_vr.vrsave = l->l_md.md_utf->tf_vrsave;
+ /*
+ * Note that we aren't using any CPU resources and stop any
+ * data streams.
+ */
+ __asm volatile ("dssall; sync");
-#ifdef MULTIPROCESSOR
/*
- * It must be on another CPU, flush it from there.
+ * Restore MSR (turn off AltiVec)
*/
- vec_mp_save_lwp(l);
-#endif
+ mtmsr(msr);
+ __asm volatile ("isync");
+}
+
+void
+vec_state_release(lwp_t *l)
+{
+ __asm volatile("dssall;sync");
+ l->l_md.md_utf->tf_srr1 &= ~PSL_VEC;
+ l->l_md.md_flags &= ~PSL_VEC;
}
void
@@ -248,8 +155,10 @@
{
struct pcb * const pcb = lwp_getpcb(l);
+ KASSERT(l == curlwp);
+
/* we don't need to save the state, just drop it */
- vec_save_lwp(l, VEC_DISCARD);
+ pcu_discard(&vec_ops);
memcpy(pcb->pcb_vr.vreg, &mcp->__vrf.__vrs, sizeof (pcb->pcb_vr.vreg));
pcb->pcb_vr.vscr = mcp->__vrf.__vscr;
pcb->pcb_vr.vrsave = mcp->__vrf.__vrsave;
@@ -259,16 +168,18 @@
bool
vec_save_to_mcontext(struct lwp *l, mcontext_t *mcp, unsigned int *flagp)
{
+ struct pcb * const pcb = lwp_getpcb(l);
+
+ KASSERT(l == curlwp);
+
/* Save AltiVec context, if any. */
- if ((l->l_md.md_flags & MDLWP_USEDVEC) == 0)
+ if (!vec_used_p(l))
return false;
- struct pcb * const pcb = lwp_getpcb(l);
-
/*
* If we're the AltiVec owner, dump its context to the PCB first.
*/
- vec_save_lwp(l, VEC_SAVE);
+ pcu_save(&vec_ops);
mcp->__gregs[_REG_MSR] |= PSL_VEC;
mcp->__vrf.__vscr = pcb->pcb_vr.vscr;
Index: src/sys/arch/powerpc/pic/ipi.c
diff -u src/sys/arch/powerpc/pic/ipi.c:1.7 src/sys/arch/powerpc/pic/ipi.c:1.8
--- src/sys/arch/powerpc/pic/ipi.c:1.7 Tue Jan 18 02:25:42 2011
+++ src/sys/arch/powerpc/pic/ipi.c Mon May 2 02:01:33 2011
@@ -1,4 +1,4 @@
-/* $NetBSD: ipi.c,v 1.7 2011/01/18 02:25:42 matt Exp $ */
+/* $NetBSD: ipi.c,v 1.8 2011/05/02 02:01:33 matt Exp $ */
/*-
* Copyright (c) 2007 The NetBSD Foundation, Inc.
* All rights reserved.
@@ -29,7 +29,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: ipi.c,v 1.7 2011/01/18 02:25:42 matt Exp $");
+__KERNEL_RCSID(0, "$NetBSD: ipi.c,v 1.8 2011/05/02 02:01:33 matt Exp $");
#include "opt_multiprocessor.h"
#include "opt_pic.h"
@@ -68,14 +68,6 @@
if (ipi == PPC_IPI_NOMESG)
return 1;
- if (ipi & PPC_IPI_FLUSH_FPU)
- fpu_save_cpu(FPU_SAVE_AND_RELEASE);
-
-#ifdef ALTIVEC
- if (ipi & PPC_IPI_FLUSH_VEC)
- vec_save_cpu(VEC_SAVE_AND_RELEASE);
-#endif
-
if (ipi & PPC_IPI_XCALL)
xc_ipi_handler();
Index: src/sys/arch/powerpc/powerpc/compat_16_machdep.c
diff -u src/sys/arch/powerpc/powerpc/compat_16_machdep.c:1.17 src/sys/arch/powerpc/powerpc/compat_16_machdep.c:1.18
--- src/sys/arch/powerpc/powerpc/compat_16_machdep.c:1.17 Wed Mar 16 21:15:29 2011
+++ src/sys/arch/powerpc/powerpc/compat_16_machdep.c Mon May 2 02:01:33 2011
@@ -1,4 +1,4 @@
-/* $NetBSD: compat_16_machdep.c,v 1.17 2011/03/16 21:15:29 matt Exp $ */
+/* $NetBSD: compat_16_machdep.c,v 1.18 2011/05/02 02:01:33 matt Exp $ */
/*
* Copyright (C) 1995, 1996 Wolfgang Solfrank.
@@ -32,7 +32,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: compat_16_machdep.c,v 1.17 2011/03/16 21:15:29 matt Exp $");
+__KERNEL_RCSID(0, "$NetBSD: compat_16_machdep.c,v 1.18 2011/05/02 02:01:33 matt Exp $");
#ifdef _KERNEL_OPT
#include "opt_compat_netbsd.h"
@@ -54,6 +54,9 @@
#include <powerpc/pcb.h>
#include <powerpc/fpu.h>
+#if defined(ALTIVEC) || defined(PPC_HAVE_SPE)
+#include <powerpc/altivec.h>
+#endif
/*
* Send a signal to process.
@@ -100,7 +103,7 @@
utf->srr1 |= pcb->pcb_flags & (PCB_FE0|PCB_FE1);
#endif
#if defined(ALTIVEC) || defined(PPC_HAVE_SPE)
- utf->srr1 |= l->l_md.md_flags & MDLWP_USEDVEC ? PSL_VEC : 0;
+ utf->srr1 |= vec_used_p(l) ? PSL_VEC : 0;
#endif
#ifdef PPC_OEA
utf->vrsave = tf->tf_vrsave;
Index: src/sys/arch/powerpc/powerpc/core_machdep.c
diff -u src/sys/arch/powerpc/powerpc/core_machdep.c:1.6 src/sys/arch/powerpc/powerpc/core_machdep.c:1.7
--- src/sys/arch/powerpc/powerpc/core_machdep.c:1.6 Wed Mar 16 21:15:30 2011
+++ src/sys/arch/powerpc/powerpc/core_machdep.c Mon May 2 02:01:33 2011
@@ -1,4 +1,4 @@
-/* $NetBSD: core_machdep.c,v 1.6 2011/03/16 21:15:30 matt Exp $ */
+/* $NetBSD: core_machdep.c,v 1.7 2011/05/02 02:01:33 matt Exp $ */
/*
* Copyright (C) 1995, 1996 Wolfgang Solfrank.
@@ -32,7 +32,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: core_machdep.c,v 1.6 2011/03/16 21:15:30 matt Exp $");
+__KERNEL_RCSID(0, "$NetBSD: core_machdep.c,v 1.7 2011/05/02 02:01:33 matt Exp $");
#ifdef _KERNEL_OPT
#include "opt_altivec.h"
@@ -77,17 +77,19 @@
}
md_core.frame = *l->l_md.md_utf;
- if (l->l_md.md_flags & MDLWP_OWNFPU) {
+ if (fpu_used_p(l)) {
#ifdef PPC_HAVE_FPU
- fpu_save_lwp(l, FPU_SAVE);
+ KASSERT(l == curlwp);
+ fpu_save();
#endif
md_core.fpstate = pcb->pcb_fpu;
} else
memset(&md_core.fpstate, 0, sizeof(md_core.fpstate));
#if defined(ALTIVEC) || defined(PPC_HAVE_SPE)
- if (l->l_md.md_flags & MDLWP_OWNVEC) {
- vec_save_lwp(l, VEC_SAVE);
+ if (vec_used_p(l)) {
+ KASSERT(l == curlwp);
+ vec_save();
md_core.vstate = pcb->pcb_vr;
} else
#endif
Index: src/sys/arch/powerpc/powerpc/fpu.c
diff -u src/sys/arch/powerpc/powerpc/fpu.c:1.28 src/sys/arch/powerpc/powerpc/fpu.c:1.29
--- src/sys/arch/powerpc/powerpc/fpu.c:1.28 Tue Feb 8 06:14:50 2011
+++ src/sys/arch/powerpc/powerpc/fpu.c Mon May 2 02:01:33 2011
@@ -1,4 +1,4 @@
-/* $NetBSD: fpu.c,v 1.28 2011/02/08 06:14:50 matt Exp $ */
+/* $NetBSD: fpu.c,v 1.29 2011/05/02 02:01:33 matt Exp $ */
/*
* Copyright (C) 1996 Wolfgang Solfrank.
@@ -32,7 +32,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: fpu.c,v 1.28 2011/02/08 06:14:50 matt Exp $");
+__KERNEL_RCSID(0, "$NetBSD: fpu.c,v 1.29 2011/05/02 02:01:33 matt Exp $");
#include "opt_multiprocessor.h"
@@ -41,179 +41,182 @@
#include <sys/systm.h>
#include <sys/atomic.h>
#include <sys/siginfo.h>
-
-//#include <uvm/uvm_extern.h>
+#include <sys/pcu.h>
#include <machine/pcb.h>
#include <machine/fpu.h>
#include <machine/psl.h>
-#ifdef MULTIPROCESSOR
-#include <arch/powerpc/pic/picvar.h>
-#include <arch/powerpc/pic/ipivar.h>
-static void fpu_mp_save_lwp(struct lwp *);
+#ifdef PPC_HAVE_FPU
+static void fpu_state_load(lwp_t *, bool);
+static void fpu_state_save(lwp_t *);
+static void fpu_state_release(lwp_t *);
+#endif
+
+const pcu_ops_t fpu_ops = {
+ .pcu_id = PCU_FPU,
+#ifdef PPC_HAVE_FPU
+ .pcu_state_load = fpu_state_load,
+ .pcu_state_save = fpu_state_save,
+ .pcu_state_release = fpu_state_release,
#endif
+};
+
+bool
+fpu_used_p(lwp_t *l)
+{
+ return (l->l_md.md_flags & MDLWP_USEDFPU) != 0;
+}
void
-fpu_enable(void)
+fpu_mark_used(lwp_t *l)
{
- struct cpu_info * const ci = curcpu();
- struct lwp * const l = curlwp;
- struct pcb * const pcb = lwp_getpcb(l);
- struct trapframe * const tf = l->l_md.md_utf;
+ l->l_md.md_flags |= MDLWP_USEDFPU;
+}
- if (!(l->l_md.md_flags & MDLWP_USEDFPU)) {
- memset(&pcb->pcb_fpu, 0, sizeof pcb->pcb_fpu);
- l->l_md.md_flags |= MDLWP_USEDFPU;
- }
+#ifdef PPC_HAVE_FPU
+void
+fpu_state_load(lwp_t *l, bool used)
+{
+ struct pcb * const pcb = lwp_getpcb(l);
const register_t msr = mfmsr();
mtmsr((msr & ~PSL_EE) | PSL_FP);
__asm volatile ("isync");
- if (ci->ci_fpulwp != l) {
- fpu_save_cpu(FPU_SAVE_AND_RELEASE);
-
- fpu_load_from_fpreg(&pcb->pcb_fpu);
-
- __asm volatile ("isync");
-
- ci->ci_fpulwp = l;
- l->l_md.md_fpucpu = ci;
- ci->ci_ev_fpusw.ev_count++;
- }
-
- tf->tf_srr1 |= PSL_FP | (pcb->pcb_flags & (PCB_FE0|PCB_FE1));
- l->l_md.md_flags |= MDLWP_OWNFPU;
+ fpu_load_from_fpreg(&pcb->pcb_fpu);
__asm volatile ("sync");
+
mtmsr(msr);
+ __asm volatile ("isync");
+
+ curcpu()->ci_ev_fpusw.ev_count++;
+ l->l_md.md_utf->tf_srr1 |= PSL_FP|(pcb->pcb_flags & (PCB_FE0|PCB_FE1));
+ l->l_md.md_flags |= MDLWP_USEDFPU;
}
/*
* Save the contents of the current CPU's FPU to its PCB.
*/
void
-fpu_save_cpu(enum fpu_op op)
+fpu_state_save(lwp_t *l)
{
+ struct pcb * const pcb = lwp_getpcb(l);
+
const register_t msr = mfmsr();
mtmsr((msr & ~PSL_EE) | PSL_FP);
__asm volatile ("isync");
- struct cpu_info * const ci = curcpu();
- lwp_t * const l = ci->ci_fpulwp;
-
- if (l->l_md.md_flags & MDLWP_OWNFPU) {
- struct pcb * const pcb = lwp_getpcb(l);
-
- fpu_unload_to_fpreg(&pcb->pcb_fpu);
-
- /*
- * Disclaim ownership.
- */
- l->l_md.md_flags &= ~MDLWP_OWNFPU;
+ fpu_unload_to_fpreg(&pcb->pcb_fpu);
+ __asm volatile ("sync");
- if (op == FPU_SAVE_AND_RELEASE)
- ci->ci_fpulwp = ci->ci_data.cpu_idlelwp;
- __asm volatile ("sync");
- }
mtmsr(msr);
+ __asm volatile ("isync");
}
-#ifdef MULTIPROCESSOR
-
-/*
- * Save a process's FPU state to its PCB. The state is in another CPU
- * (though by the time our IPI is processed, it may have been flushed already).
- */
-static void
-fpu_mp_save_lwp(struct lwp *l)
+void
+fpu_state_release(lwp_t *l)
{
- /*
- * Send an IPI to the other CPU with the data and wait for that CP * to flush the data. Note that the other CPU might have switched
- * to a different proc's FPU state by the time it receives the IPI,
- * but that will only result in an unnecessary reload.
- */
-
- struct cpu_info *fpucpu;
- fpucpu = l->l_md.md_fpucpu;
- if (fpucpu == NULL)
- return;
-
- ppc_send_ipi(fpucpu->ci_cpuid, PPC_IPI_FLUSH_FPU);
-
- /* Wait for flush. */
- for (u_int i = 0; i < 0x3fffffff; i++) {
- if ((l->l_md.md_flags & MDLWP_OWNFPU) == 0)
- return;
- }
-
- aprint_error("%s/%d pid = %d.%d, fpucpu->ci_cpuid = %d\n", __func__,
- cpu_number(), l->l_proc->p_pid, l->l_lid, fpucpu->ci_cpuid);
- panic("mp_save_fpu_proc: timed out");
+ l->l_md.md_utf->tf_srr1 &= ~PSL_FP;
}
-#endif /* MULTIPROCESSOR */
-/*
- * Save a process's FPU state to its PCB. The state may be in any CPU.
- * The process must either be curproc or traced by curproc (and stopped).
- * (The point being that the process must not run on another CPU during
- * this function).
- */
-void
-fpu_save_lwp(struct lwp *l, enum fpu_op op)
-{
- struct cpu_info * const ci = curcpu();
+#define STICKYBITS (FPSCR_VX|FPSCR_OX|FPSCR_UX|FPSCR_ZX|FPSCR_XX)
+#define STICKYSHIFT 25
+#define MASKBITS (FPSCR_VE|FPSCR_OE|FPSCR_UE|FPSCR_ZE|FPSCR_XE)
+#define MASKSHIFT 3
- KASSERT(l->l_md.md_fpucpu != NULL);
+int
+fpu_get_fault_code(void)
+{
+ lwp_t * const l = curlwp;
+ struct pcb * const pcb = lwp_getpcb(l);
+ uint64_t fpscr64;
+ uint32_t fpscr, ofpscr;
+ int code;
- /*
- * If it's already in the PCB, there's nothing to do.
- */
- if ((l->l_md.md_flags & MDLWP_OWNFPU) == 0)
- return;
+ int s = splsoftclock(); /* disable preemption */
+ struct cpu_info * const ci = curcpu();
/*
- * If we simply need to discard the information, then don't
- * to save anything.
+ * If we got preempted, we may be running on a different CPU. So we
+ * need to check for that.
*/
- if (op == FPU_DISCARD) {
-#ifndef MULTIPROCESSOR
- KASSERT(ci == l->l_md.md_fpucpu);
-#endif
- KASSERT(l == l->l_md.md_fpucpu->ci_fpulwp);
- atomic_cas_ptr(&l->l_md.md_fpucpu->ci_fpulwp, l,
- l->l_md.md_fpucpu->ci_data.cpu_idlelwp);
- atomic_and_uint(&l->l_md.md_flags, ~MDLWP_OWNFPU);
- return;
+ KASSERT(fpu_used_p(l));
+ if (__predict_true(l->l_pcu_cpu[PCU_FPU] == ci)) {
+ uint64_t tmp;
+ const register_t msr = mfmsr();
+ mtmsr((msr & ~PSL_EE) | PSL_FP);
+ __asm volatile ("isync");
+ __asm volatile (
+ "stfd 0,0(%[tmp])\n" /* save f0 */
+ "mffs 0\n" /* get FPSCR */
+ "stfd 0,0(%[fpscr64])\n" /* store a temp copy */
+ "mtfsb0 0\n" /* clear FPSCR_FX */
+ "mtfsb0 24\n" /* clear FPSCR_VE */
+ "mtfsb0 25\n" /* clear FPSCR_OE */
+ "mtfsb0 26\n" /* clear FPSCR_UE */
+ "mtfsb0 27\n" /* clear FPSCR_ZE */
+ "mtfsb0 28\n" /* clear FPSCR_XE */
+ "mffs 0\n" /* get FPSCR */
+ "stfd 0,0(%[fpscr])\n" /* store it */
+ "lfd 0,0(%[tmp])\n" /* restore f0 */
+ :: [tmp] "b"(&tmp),
+ [fpscr] "b"(&pcb->pcb_fpu.fpscr),
+ [fpscr64] "b"(&fpscr64));
+ mtmsr(msr);
+ __asm volatile ("isync");
+ } else {
+ /*
+ * We got preempted to a different CPU so we need to save
+ * our FPU state.
+ */
+ fpu_save();
+ fpscr64 = *(uint64_t *)&pcb->pcb_fpu.fpscr;
+ ((uint32_t *)&pcb->pcb_fpu.fpscr)[_QUAD_LOWWORD] &= ~MASKBITS;
}
+ splx(s); /* allow preemption */
+
/*
- * If the state is in the current CPU, just flush the current CPU's
- * state.
+ * Now determine the fault type. First we test to see if any of sticky
+ * bits correspond to the enabled exceptions. If so, we only test
+ * those bits. If not, we look at all the bits. (In reality, we only
+ * could get an exception if FPSCR_FEX changed state. So we should
+ * have at least one bit that corresponds).
*/
- if (l == ci->ci_fpulwp) {
- fpu_save_cpu(op);
- return;
- }
+ ofpscr = (uint32_t)fpscr64;
+ ofpscr &= ofpscr << (STICKYSHIFT - MASKSHIFT);
+ fpscr = ((uint32_t *)&pcb->pcb_fpu.fpscr)[_QUAD_LOWWORD];
+ if (fpscr & ofpscr & STICKYBITS)
+ fpscr &= ofpscr;
-#ifdef MULTIPROCESSOR
/*
- * It must be on another CPU, flush it from there.
+ * Let's determine what the appropriate code is.
*/
- fpu_mp_save_lwp(l);
-#endif
+ if (fpscr & FPSCR_VX) code = FPE_FLTINV;
+ else if (fpscr & FPSCR_OX) code = FPE_FLTOVF;
+ else if (fpscr & FPSCR_UX) code = FPE_FLTUND;
+ else if (fpscr & FPSCR_ZX) code = FPE_FLTDIV;
+ else if (fpscr & FPSCR_XX) code = FPE_FLTRES;
+ else code = 0;
+ return code;
}
+#endif /* PPC_HAVE_FPU */
bool
fpu_save_to_mcontext(lwp_t *l, mcontext_t *mcp, unsigned int *flagp)
{
- if ((l->l_md.md_flags & MDLWP_USEDFPU) != 0)
+ KASSERT(l == curlwp);
+
+ if (!pcu_used_p(&fpu_ops))
return false;
struct pcb * const pcb = lwp_getpcb(l);
+#ifdef PPC_HAVE_FPU
/* If we're the FPU owner, dump its context to the PCB first. */
- fpu_save_lwp(l, FPU_SAVE);
+ pcu_save(&fpu_ops);
+#endif
(void)memcpy(mcp->__fpregs.__fpu_regs, pcb->pcb_fpu.fpreg,
sizeof (mcp->__fpregs.__fpu_regs));
mcp->__fpregs.__fpu_fpscr =
@@ -231,74 +234,12 @@
struct pcb * const pcb = lwp_getpcb(l);
+#ifdef PPC_HAVE_FPU
/* we don't need to save the state, just drop it */
- fpu_save_lwp(l, FPU_DISCARD);
+ if (l == curlwp)
+ pcu_discard(&fpu_ops);
+#endif
(void)memcpy(&pcb->pcb_fpu.fpreg, &mcp->__fpregs.__fpu_regs,
sizeof (pcb->pcb_fpu.fpreg));
((int *)&pcb->pcb_fpu.fpscr)[_QUAD_LOWWORD] = mcp->__fpregs.__fpu_fpscr;
}
-
-#define STICKYBITS (FPSCR_VX|FPSCR_OX|FPSCR_UX|FPSCR_ZX|FPSCR_XX)
-#define STICKYSHIFT 25
-#define MASKBITS (FPSCR_VE|FPSCR_OE|FPSCR_UE|FPSCR_ZE|FPSCR_XE)
-#define MASKSHIFT 3
-
-int
-fpu_get_fault_code(void)
-{
-#ifdef DIAGNOSTIC
- struct cpu_info * const ci = curcpu();
-#endif
- struct pcb * const pcb = curpcb;
- register_t msr;
- uint64_t tmp, fpscr64;
- uint32_t fpscr, ofpscr;
- int code;
-
- KASSERT(curlwp->l_md.md_fpucpu == ci);
- KASSERT(curlwp->l_md.md_flags & MDLWP_USEDFPU);
- KASSERT(curlwp->l_md.md_flags & MDLWP_OWNFPU);
- KASSERT(ci->ci_fpulwp == curlwp);
- msr = mfmsr();
- mtmsr((msr & ~PSL_EE) | PSL_FP);
- __asm volatile ("isync");
- __asm volatile (
- "stfd 0,0(%0)\n" /* save f0 */
- "mffs 0\n" /* get FPSCR */
- "stfd 0,0(%2)\n" /* store a temp copy */
- "mtfsb0 0\n" /* clear FPSCR_FX */
- "mtfsb0 24\n" /* clear FPSCR_VE */
- "mtfsb0 25\n" /* clear FPSCR_OE */
- "mtfsb0 26\n" /* clear FPSCR_UE */
- "mtfsb0 27\n" /* clear FPSCR_ZE */
- "mtfsb0 28\n" /* clear FPSCR_XE */
- "mffs 0\n" /* get FPSCR */
- "stfd 0,0(%1)\n" /* store it */
- "lfd 0,0(%0)\n" /* restore f0 */
- :: "b"(&tmp), "b"(&pcb->pcb_fpu.fpscr), "b"(&fpscr64));
- mtmsr(msr);
- __asm volatile ("isync");
- /*
- * Now determine the fault type. First we test to see if any of sticky
- * bits correspond to the enabled exceptions. If so, we only test
- * those bits. If not, we look at all the bits. (In reality, we only
- * could get an exception if FPSCR_FEX changed state. So we should
- * have at least one bit that corresponds).
- */
- ofpscr = (uint32_t)fpscr64;
- ofpscr &= ofpscr << (STICKYSHIFT - MASKSHIFT);
- fpscr = (uint32_t)(*(uint64_t *)&pcb->pcb_fpu.fpscr);
- if (fpscr & ofpscr & STICKYBITS)
- fpscr &= ofpscr;
-
- /*
- * Let's determine what the appropriate code is.
- */
- if (fpscr & FPSCR_VX) code = FPE_FLTINV;
- else if (fpscr & FPSCR_OX) code = FPE_FLTOVF;
- else if (fpscr & FPSCR_UX) code = FPE_FLTUND;
- else if (fpscr & FPSCR_ZX) code = FPE_FLTDIV;
- else if (fpscr & FPSCR_XX) code = FPE_FLTRES;
- else code = 0;
- return code;
-}
Index: src/sys/arch/powerpc/powerpc/powerpc_machdep.c
diff -u src/sys/arch/powerpc/powerpc/powerpc_machdep.c:1.47 src/sys/arch/powerpc/powerpc/powerpc_machdep.c:1.48
--- src/sys/arch/powerpc/powerpc/powerpc_machdep.c:1.47 Wed Mar 16 21:15:30 2011
+++ src/sys/arch/powerpc/powerpc/powerpc_machdep.c Mon May 2 02:01:33 2011
@@ -1,4 +1,4 @@
-/* $NetBSD: powerpc_machdep.c,v 1.47 2011/03/16 21:15:30 matt Exp $ */
+/* $NetBSD: powerpc_machdep.c,v 1.48 2011/05/02 02:01:33 matt Exp $ */
/*
* Copyright (C) 1995, 1996 Wolfgang Solfrank.
@@ -32,10 +32,11 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: powerpc_machdep.c,v 1.47 2011/03/16 21:15:30 matt Exp $");
+__KERNEL_RCSID(0, "$NetBSD: powerpc_machdep.c,v 1.48 2011/05/02 02:01:33 matt Exp $");
#include "opt_altivec.h"
#include "opt_modular.h"
+#include "opt_ppcarch.h"
#include <sys/param.h>
#include <sys/conf.h>
@@ -51,8 +52,13 @@
#include <sys/cpu.h>
#include <sys/module.h>
#include <sys/device.h>
+#include <sys/pcu.h>
-#include <machine/pcb.h>
+#include <powerpc/pcb.h>
+#include <powerpc/fpu.h>
+#if defined(ALTIVEC) || defined(PPC_HAVE_SPE)
+#include <powerpc/altivec.h>
+#endif
int cpu_timebase;
int cpu_printfataltraps = 1;
@@ -63,6 +69,15 @@
/* exported variable to be filled in by the bootloaders */
char *booted_kernel;
+const pcu_ops_t * const pcu_ops_md_defs[PCU_UNIT_COUNT] = {
+#if defined(PPC_HAVE_FPU)
+ [PCU_FPU] = &fpu_ops,
+#endif
+#if defined(ALTIVEC) || defined(PPC_HAVE_SPE)
+ [PCU_VEC] = &vec_ops,
+#endif
+};
+
/*
* Set set up registers on exec.
*/
@@ -110,6 +125,10 @@
tf->tf_vrsave = 0;
#endif
pcb->pcb_flags = PSL_FE_DFLT;
+ memset(&pcb->pcb_fpu, 0, sizeof(&pcb->pcb_fpu));
+#if defined(ALTIVEC) || defined(PPC_SAVE_SPE)
+ memset(&pcb->pcb_vr, 0, sizeof(&pcb->pcb_vr));
+#endif
}
/*
Index: src/sys/arch/powerpc/powerpc/process_machdep.c
diff -u src/sys/arch/powerpc/powerpc/process_machdep.c:1.30 src/sys/arch/powerpc/powerpc/process_machdep.c:1.31
--- src/sys/arch/powerpc/powerpc/process_machdep.c:1.30 Wed Mar 16 21:15:30 2011
+++ src/sys/arch/powerpc/powerpc/process_machdep.c Mon May 2 02:01:33 2011
@@ -1,4 +1,4 @@
-/* $NetBSD: process_machdep.c,v 1.30 2011/03/16 21:15:30 matt Exp $ */
+/* $NetBSD: process_machdep.c,v 1.31 2011/05/02 02:01:33 matt Exp $ */
/*
* Copyright (C) 1995, 1996 Wolfgang Solfrank.
@@ -32,7 +32,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: process_machdep.c,v 1.30 2011/03/16 21:15:30 matt Exp $");
+__KERNEL_RCSID(0, "$NetBSD: process_machdep.c,v 1.31 2011/05/02 02:01:33 matt Exp $");
#include "opt_altivec.h"
@@ -47,7 +47,7 @@
#include <uvm/uvm_extern.h>
-#include <powerpc/altivec.h>
+#include <powerpc/altivec.h> /* also for e500 SPE */
int
process_read_regs(struct lwp *l, struct reg *regs)
@@ -85,15 +85,16 @@
struct pcb * const pcb = lwp_getpcb(l);
/* Is the process using the fpu? */
- if ((l->l_md.md_flags & MDLWP_USEDFPU) == 0) {
+ if (!fpu_used_p(l)) {
memset(fpregs, 0, sizeof (*fpregs));
- return 0;
- }
-
#ifdef PPC_HAVE_FPU
- fpu_save_lwp(l, FPU_SAVE_AND_RELEASE);
+ } else {
+ KASSERT(l == curlwp);
+ fpu_save();
#endif
+ }
*fpregs = pcb->pcb_fpu;
+ fpu_mark_used(l);
return 0;
}
@@ -104,13 +105,11 @@
struct pcb * const pcb = lwp_getpcb(l);
#ifdef PPC_HAVE_FPU
- fpu_save_lwp(l, FPU_DISCARD);
+ KASSERT(l == curlwp);
+ fpu_discard();
#endif
-
pcb->pcb_fpu = *fpregs;
-
- /* pcb_fpu is initialized now. */
- l->l_md.md_flags |= MDLWP_USEDFPU;
+ fpu_mark_used(l); /* pcb_fpu is initialized now. */
return 0;
}
@@ -147,20 +146,22 @@
{
struct pcb * const pcb = lwp_getpcb(l);
+ KASSERT(l == curlwp);
#ifdef ALTIVEC
if (cpu_altivec == 0)
- return (EINVAL);
+ return EINVAL;
#endif
/* Is the process using AltiVEC? */
- if ((l->l_md.md_flags & MDLWP_USEDVEC) == 0) {
+ if (!vec_used_p(l)) {
memset(vregs, 0, sizeof (*vregs));
- return 0;
+ } else {
+ vec_save();
+ *vregs = pcb->pcb_vr;
}
- vec_save_lwp(l, VEC_SAVE_AND_RELEASE);
- *vregs = pcb->pcb_vr;
+ vec_mark_used(l);
- return (0);
+ return 0;
}
static int
@@ -168,14 +169,18 @@
{
struct pcb * const pcb = lwp_getpcb(l);
+ KASSERT(l == curlwp);
+
#ifdef ALTIVEC
if (cpu_altivec == 0)
return (EINVAL);
#endif
- vec_save_lwp(l, VEC_DISCARD);
- pcb->pcb_vr = *vregs;
- l->l_md.md_flags |= MDLWP_USEDVEC; /* pcb_vr is initialized now. */
+#if defined(ALTIVEC) || defined(PPC_HAVE_SPE)
+ vec_discard();
+#endif
+ pcb->pcb_vr = *vregs; /* pcb_vr is initialized now. */
+ vec_mark_used(l);
return (0);
}
Index: src/sys/arch/powerpc/powerpc/trap.c
diff -u src/sys/arch/powerpc/powerpc/trap.c:1.139 src/sys/arch/powerpc/powerpc/trap.c:1.140
--- src/sys/arch/powerpc/powerpc/trap.c:1.139 Wed Mar 16 21:15:30 2011
+++ src/sys/arch/powerpc/powerpc/trap.c Mon May 2 02:01:33 2011
@@ -1,4 +1,4 @@
-/* $NetBSD: trap.c,v 1.139 2011/03/16 21:15:30 matt Exp $ */
+/* $NetBSD: trap.c,v 1.140 2011/05/02 02:01:33 matt Exp $ */
/*
* Copyright (C) 1995, 1996 Wolfgang Solfrank.
@@ -32,7 +32,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: trap.c,v 1.139 2011/03/16 21:15:30 matt Exp $");
+__KERNEL_RCSID(0, "$NetBSD: trap.c,v 1.140 2011/05/02 02:01:33 matt Exp $");
#include "opt_altivec.h"
#include "opt_ddb.h"
@@ -343,7 +343,7 @@
case EXC_FPU|EXC_USER:
ci->ci_ev_fpu.ev_count++;
- fpu_enable();
+ fpu_load();
break;
case EXC_AST|EXC_USER:
@@ -383,7 +383,7 @@
case EXC_VEC|EXC_USER:
ci->ci_ev_vec.ev_count++;
#ifdef ALTIVEC
- vec_enable();
+ vec_load();
break;
#else
if (cpu_printfataltraps) {
@@ -746,22 +746,23 @@
* the PCB.
*/
- if ((l->l_md.md_flags & MDLWP_USEDFPU) == 0) {
+ KASSERT(l == curlwp);
+ if (!fpu_used_p(l)) {
memset(&pcb->pcb_fpu, 0, sizeof(pcb->pcb_fpu));
- l->l_md.md_flags |= MDLWP_USEDFPU;
+ fpu_mark_used(l);
+ } else {
+ fpu_save();
}
if (indicator == EXC_ALI_LFD) {
- fpu_save_lwp(l, FPU_SAVE_AND_RELEASE);
if (copyin((void *)tf->tf_dar, fpreg,
sizeof(double)) != 0)
return -1;
} else {
- fpu_save_lwp(l, FPU_SAVE);
if (copyout(fpreg, (void *)tf->tf_dar,
sizeof(double)) != 0)
return -1;
}
- fpu_enable();
+ fpu_load();
return 0;
}
break;
@@ -786,11 +787,11 @@
struct pcb * const pcb = lwp_getpcb(l);
register_t msr = tf->tf_srr1 & PSL_USERSRR1;
- if (l->l_md.md_flags & MDLWP_USEDFPU)
+ if (fpu_used_p(l))
msr |= PSL_FP;
msr |= (pcb->pcb_flags & (PCB_FE0|PCB_FE1));
#ifdef ALTIVEC
- if (l->l_md.md_flags & MDLWP_USEDVEC)
+ if (vec_used_p(l))
msr |= PSL_VEC;
#endif
tf->tf_fixreg[OPC_MFMSR_REG(opcode)] = msr;
Index: src/sys/arch/powerpc/powerpc/vm_machdep.c
diff -u src/sys/arch/powerpc/powerpc/vm_machdep.c:1.83 src/sys/arch/powerpc/powerpc/vm_machdep.c:1.84
--- src/sys/arch/powerpc/powerpc/vm_machdep.c:1.83 Thu Feb 10 14:46:47 2011
+++ src/sys/arch/powerpc/powerpc/vm_machdep.c Mon May 2 02:01:33 2011
@@ -1,4 +1,4 @@
-/* $NetBSD: vm_machdep.c,v 1.83 2011/02/10 14:46:47 pooka Exp $ */
+/* $NetBSD: vm_machdep.c,v 1.84 2011/05/02 02:01:33 matt Exp $ */
/*
* Copyright (C) 1995, 1996 Wolfgang Solfrank.
@@ -32,7 +32,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: vm_machdep.c,v 1.83 2011/02/10 14:46:47 pooka Exp $");
+__KERNEL_RCSID(0, "$NetBSD: vm_machdep.c,v 1.84 2011/05/02 02:01:33 matt Exp $");
#include "opt_altivec.h"
#include "opt_multiprocessor.h"
@@ -93,10 +93,10 @@
struct pcb * const pcb2 = lwp_getpcb(l2);
#ifdef PPC_HAVE_FPU
- fpu_save_lwp(l1, FPU_SAVE);
+ fpu_save();
#endif
#if defined(ALTIVEC) || defined(PPC_HAVE_SPE)
- vec_save_lwp(l1, VEC_SAVE);
+ vec_save();
#endif
/* Copy MD part of lwp and set up user trapframe pointer. */
@@ -167,13 +167,14 @@
void
cpu_lwp_free(struct lwp *l, int proc)
{
+ KASSERT(l == curlwp);
#ifdef PPC_HAVE_FPU
/* release the FPU */
- fpu_save_lwp(l, FPU_DISCARD);
+ fpu_discard();
#endif
#if defined(ALTIVEC) || defined(PPC_HAVE_SPE)
/* release the vector unit */
- vec_save_lwp(l, VEC_DISCARD);
+ vec_discard();
#endif
}