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 }