Changeset View
Changeset View
Standalone View
Standalone View
sys/arm64/arm64/vfp.c
Show All 32 Lines | |||||
#include <sys/param.h> | #include <sys/param.h> | ||||
#include <sys/systm.h> | #include <sys/systm.h> | ||||
#include <sys/limits.h> | #include <sys/limits.h> | ||||
#include <sys/kernel.h> | #include <sys/kernel.h> | ||||
#include <sys/malloc.h> | #include <sys/malloc.h> | ||||
#include <sys/pcpu.h> | #include <sys/pcpu.h> | ||||
#include <sys/proc.h> | #include <sys/proc.h> | ||||
#include <vm/uma.h> | |||||
#include <machine/armreg.h> | #include <machine/armreg.h> | ||||
#include <machine/md_var.h> | #include <machine/md_var.h> | ||||
#include <machine/pcb.h> | #include <machine/pcb.h> | ||||
#include <machine/vfp.h> | #include <machine/vfp.h> | ||||
/* Sanity check we can store all the VFP registers */ | /* Sanity check we can store all the VFP registers */ | ||||
CTASSERT(sizeof(((struct pcb *)0)->pcb_fpustate.vfp_regs) == 16 * 32); | CTASSERT(sizeof(((struct pcb *)0)->pcb_fpustate.vfp_regs) == 16 * 32); | ||||
static MALLOC_DEFINE(M_FPUKERN_CTX, "fpukern_ctx", | static MALLOC_DEFINE(M_FPUKERN_CTX, "fpukern_ctx", | ||||
"Kernel contexts for VFP state"); | "Kernel contexts for VFP state"); | ||||
struct fpu_kern_ctx { | struct fpu_kern_ctx { | ||||
struct vfpstate *prev; | struct vfpstate *prev; | ||||
#define FPU_KERN_CTX_DUMMY 0x01 /* avoided save for the kern thread */ | #define FPU_KERN_CTX_DUMMY 0x01 /* avoided save for the kern thread */ | ||||
#define FPU_KERN_CTX_INUSE 0x02 | #define FPU_KERN_CTX_INUSE 0x02 | ||||
uint32_t flags; | uint32_t flags; | ||||
struct vfpstate state; | struct vfpstate state; | ||||
}; | }; | ||||
static uma_zone_t fpu_save_area_zone; | |||||
static struct vfpstate *fpu_initialstate; | |||||
markj: The whitespace after `static` looks odd. | |||||
void | void | ||||
vfp_enable(void) | vfp_enable(void) | ||||
{ | { | ||||
uint32_t cpacr; | uint32_t cpacr; | ||||
cpacr = READ_SPECIALREG(cpacr_el1); | cpacr = READ_SPECIALREG(cpacr_el1); | ||||
cpacr = (cpacr & ~CPACR_FPEN_MASK) | CPACR_FPEN_TRAP_NONE; | cpacr = (cpacr & ~CPACR_FPEN_MASK) | CPACR_FPEN_TRAP_NONE; | ||||
WRITE_SPECIALREG(cpacr_el1, cpacr); | WRITE_SPECIALREG(cpacr_el1, cpacr); | ||||
▲ Show 20 Lines • Show All 207 Lines • ▼ Show 20 Lines | if (PCPU_GET(fpcurthread) != curthread || cpu != curpcb->pcb_vfpcpu) { | ||||
PCPU_SET(fpcurthread, curthread); | PCPU_SET(fpcurthread, curthread); | ||||
curpcb->pcb_vfpcpu = cpu; | curpcb->pcb_vfpcpu = cpu; | ||||
} | } | ||||
critical_exit(); | critical_exit(); | ||||
} | } | ||||
void | void | ||||
vfp_init(void) | vfp_init_secondary(void) | ||||
Not Done Inline ActionsNow this is only called from APs, so the name is a bit misleading. Maybe vfp_init_secondary() (and plain vfp_init() below)? markj: Now this is only called from APs, so the name is a bit misleading. Maybe vfp_init_secondary()… | |||||
{ | { | ||||
uint64_t pfr; | uint64_t pfr; | ||||
/* Check if there is a vfp unit present */ | /* Check if there is a vfp unit present */ | ||||
pfr = READ_SPECIALREG(id_aa64pfr0_el1); | pfr = READ_SPECIALREG(id_aa64pfr0_el1); | ||||
if ((pfr & ID_AA64PFR0_FP_MASK) == ID_AA64PFR0_FP_NONE) | if ((pfr & ID_AA64PFR0_FP_MASK) == ID_AA64PFR0_FP_NONE) | ||||
return; | return; | ||||
/* Disable to be enabled when it's used */ | /* Disable to be enabled when it's used */ | ||||
vfp_disable(); | vfp_disable(); | ||||
} | |||||
if (PCPU_GET(cpuid) == 0) | static void | ||||
vfp_init(const void *dummy __unused) | |||||
{ | |||||
uint64_t pfr; | |||||
/* Check if there is a vfp unit present */ | |||||
pfr = READ_SPECIALREG(id_aa64pfr0_el1); | |||||
if ((pfr & ID_AA64PFR0_FP_MASK) == ID_AA64PFR0_FP_NONE) | |||||
return; | |||||
fpu_save_area_zone = uma_zcreate("VFP_save_area", | |||||
sizeof(struct vfpstate), NULL, NULL, NULL, NULL, | |||||
_Alignof(struct vfpstate) - 1, 0); | |||||
Not Done Inline ActionsI think we prefer _Alignof. markj: I think we prefer _Alignof. | |||||
fpu_initialstate = uma_zalloc(fpu_save_area_zone, M_WAITOK | M_ZERO); | |||||
/* Ensure the VFP is enabled before accessing it in vfp_store */ | |||||
vfp_enable(); | |||||
vfp_store(fpu_initialstate); | |||||
/* Disable to be enabled when it's used */ | |||||
vfp_disable(); | |||||
/* Zero the VFP registers but keep fpcr and fpsr */ | |||||
bzero(fpu_initialstate->vfp_regs, sizeof(fpu_initialstate->vfp_regs)); | |||||
thread0.td_pcb->pcb_fpusaved->vfp_fpcr = VFPCR_INIT; | thread0.td_pcb->pcb_fpusaved->vfp_fpcr = VFPCR_INIT; | ||||
} | } | ||||
SYSINIT(vfp, SI_SUB_CPU, SI_ORDER_ANY, vfp_init, NULL); | SYSINIT(vfp, SI_SUB_CPU, SI_ORDER_ANY, vfp_init, NULL); | ||||
struct fpu_kern_ctx * | struct fpu_kern_ctx * | ||||
fpu_kern_alloc_ctx(u_int flags) | fpu_kern_alloc_ctx(u_int flags) | ||||
{ | { | ||||
struct fpu_kern_ctx *res; | struct fpu_kern_ctx *res; | ||||
▲ Show 20 Lines • Show All 122 Lines • ▼ Show 20 Lines | |||||
is_fpu_kern_thread(u_int flags __unused) | is_fpu_kern_thread(u_int flags __unused) | ||||
{ | { | ||||
struct pcb *curpcb; | struct pcb *curpcb; | ||||
if ((curthread->td_pflags & TDP_KTHREAD) == 0) | if ((curthread->td_pflags & TDP_KTHREAD) == 0) | ||||
return (0); | return (0); | ||||
curpcb = curthread->td_pcb; | curpcb = curthread->td_pcb; | ||||
return ((curpcb->pcb_fpflags & PCB_FP_KERN) != 0); | return ((curpcb->pcb_fpflags & PCB_FP_KERN) != 0); | ||||
} | |||||
/* | |||||
* FPU save area alloc/free/init utility routines | |||||
*/ | |||||
struct vfpstate * | |||||
fpu_save_area_alloc(void) | |||||
{ | |||||
return (uma_zalloc(fpu_save_area_zone, M_WAITOK)); | |||||
Not Done Inline ActionsNo need for blank lines at the beginning of functions. markj: No need for blank lines at the beginning of functions. | |||||
} | |||||
void | |||||
fpu_save_area_free(struct vfpstate *fsa) | |||||
{ | |||||
uma_zfree(fpu_save_area_zone, fsa); | |||||
} | |||||
void | |||||
fpu_save_area_reset(struct vfpstate *fsa) | |||||
{ | |||||
memcpy(fsa, fpu_initialstate, sizeof(*fsa)); | |||||
} | } | ||||
#endif | #endif |
The whitespace after static looks odd.