Changeset View
Changeset View
Standalone View
Standalone View
sys/arm64/arm64/vfp.c
Show First 20 Lines • Show All 96 Lines • ▼ Show 20 Lines | if (PCPU_GET(fpcurthread) == td) | ||||
PCPU_SET(fpcurthread, NULL); | PCPU_SET(fpcurthread, NULL); | ||||
vfp_disable(); | vfp_disable(); | ||||
} | } | ||||
static void | static void | ||||
vfp_store(struct vfpstate *state) | vfp_store(struct vfpstate *state) | ||||
{ | { | ||||
__int128_t *vfp_state; | __uint128_t *vfp_state; | ||||
uint64_t fpcr, fpsr; | uint64_t fpcr, fpsr; | ||||
vfp_state = state->vfp_regs; | vfp_state = state->vfp_regs; | ||||
__asm __volatile( | __asm __volatile( | ||||
"mrs %0, fpcr \n" | "mrs %0, fpcr \n" | ||||
"mrs %1, fpsr \n" | "mrs %1, fpsr \n" | ||||
"stp q0, q1, [%2, #16 * 0]\n" | "stp q0, q1, [%2, #16 * 0]\n" | ||||
"stp q2, q3, [%2, #16 * 2]\n" | "stp q2, q3, [%2, #16 * 2]\n" | ||||
Show All 15 Lines | vfp_store(struct vfpstate *state) | ||||
state->vfp_fpcr = fpcr; | state->vfp_fpcr = fpcr; | ||||
state->vfp_fpsr = fpsr; | state->vfp_fpsr = fpsr; | ||||
} | } | ||||
static void | static void | ||||
vfp_restore(struct vfpstate *state) | vfp_restore(struct vfpstate *state) | ||||
{ | { | ||||
__int128_t *vfp_state; | __uint128_t *vfp_state; | ||||
uint64_t fpcr, fpsr; | uint64_t fpcr, fpsr; | ||||
vfp_state = state->vfp_regs; | vfp_state = state->vfp_regs; | ||||
fpcr = state->vfp_fpcr; | fpcr = state->vfp_fpcr; | ||||
fpsr = state->vfp_fpsr; | fpsr = state->vfp_fpsr; | ||||
__asm __volatile( | __asm __volatile( | ||||
"ldp q0, q1, [%2, #16 * 0]\n" | "ldp q0, q1, [%2, #16 * 0]\n" | ||||
▲ Show 20 Lines • Show All 206 Lines • ▼ Show 20 Lines | if (pcb->pcb_fpusaved == &pcb->pcb_fpustate) { | ||||
KASSERT((pcb->pcb_fpflags & PCB_FP_KERN) != 0, | KASSERT((pcb->pcb_fpflags & PCB_FP_KERN) != 0, | ||||
("unpaired fpu_kern_leave")); | ("unpaired fpu_kern_leave")); | ||||
} | } | ||||
return (0); | return (0); | ||||
} | } | ||||
int | int | ||||
fpu_kern_thread(u_int flags) | fpu_kern_thread(u_int flags __unused) | ||||
{ | { | ||||
struct pcb *pcb = curthread->td_pcb; | struct pcb *pcb = curthread->td_pcb; | ||||
KASSERT((curthread->td_pflags & TDP_KTHREAD) != 0, | KASSERT((curthread->td_pflags & TDP_KTHREAD) != 0, | ||||
("Only kthread may use fpu_kern_thread")); | ("Only kthread may use fpu_kern_thread")); | ||||
KASSERT(pcb->pcb_fpusaved == &pcb->pcb_fpustate, | KASSERT(pcb->pcb_fpusaved == &pcb->pcb_fpustate, | ||||
("Mangled pcb_fpusaved")); | ("Mangled pcb_fpusaved")); | ||||
KASSERT((pcb->pcb_fpflags & PCB_FP_KERN) == 0, | KASSERT((pcb->pcb_fpflags & PCB_FP_KERN) == 0, | ||||
("Thread already setup for the VFP")); | ("Thread already setup for the VFP")); | ||||
pcb->pcb_fpflags |= PCB_FP_KERN; | pcb->pcb_fpflags |= PCB_FP_KERN; | ||||
return (0); | return (0); | ||||
} | } | ||||
int | int | ||||
is_fpu_kern_thread(u_int flags) | 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); | ||||
} | } | ||||
#endif | #endif | ||||
andrew: I don't think this is needed in the `!VFP` case. It resets values that should only ever be used… | |||||
Done Inline ActionsIf an interrupt that causes the thread to switch to a new CPU we could end up with an inconsistent state. The simplest fix is to move this critical_enter call to above the bzero. I think it would also work to call vfp_discard first, then clear the state as this will ensure the VFP unit is off. andrew: If an interrupt that causes the thread to switch to a new CPU we could end up with an… |
I don't think this is needed in the !VFP case. It resets values that should only ever be used when the VFP is present and the kernel is built to use it.
If this is the case it could be renamed to vfp_reset_state and moved to be near vfp_save_state.