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
 
 }

Reply via email to