Kernel: only reset/reload FPU state when necessary
This commit is contained in:
parent
a615a7d4d2
commit
c8c9565a03
@ -274,24 +274,27 @@ PUBLIC void fpu_init(void)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
PUBLIC void save_local_fpu(struct proc *pr)
|
PUBLIC void save_local_fpu(struct proc *pr, int retain)
|
||||||
{
|
{
|
||||||
|
/* Save process FPU context. If the 'retain' flag is set, keep the FPU
|
||||||
|
* state as is. If the flag is not set, the state is undefined upon
|
||||||
|
* return, and the caller is responsible for reloading a proper state.
|
||||||
|
*/
|
||||||
|
|
||||||
if(!is_fpu())
|
if(!is_fpu())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
/* Save changed FPU context. */
|
|
||||||
if(osfxsr_feature) {
|
if(osfxsr_feature) {
|
||||||
fxsave(pr->p_fpu_state.fpu_save_area_p);
|
fxsave(pr->p_fpu_state.fpu_save_area_p);
|
||||||
fninit();
|
|
||||||
} else {
|
} else {
|
||||||
fnsave(pr->p_fpu_state.fpu_save_area_p);
|
fnsave(pr->p_fpu_state.fpu_save_area_p);
|
||||||
|
if (retain)
|
||||||
|
(void) frstor(pr->p_fpu_state.fpu_save_area_p);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
PUBLIC void save_fpu(struct proc *pr)
|
PUBLIC void save_fpu(struct proc *pr)
|
||||||
{
|
{
|
||||||
int r;
|
|
||||||
|
|
||||||
#ifdef CONFIG_SMP
|
#ifdef CONFIG_SMP
|
||||||
if (cpuid != pr->p_cpu) {
|
if (cpuid != pr->p_cpu) {
|
||||||
int stopped;
|
int stopped;
|
||||||
@ -316,13 +319,7 @@ PUBLIC void save_fpu(struct proc *pr)
|
|||||||
|
|
||||||
if (get_cpulocal_var(fpu_owner) == pr) {
|
if (get_cpulocal_var(fpu_owner) == pr) {
|
||||||
disable_fpu_exception();
|
disable_fpu_exception();
|
||||||
save_local_fpu(pr);
|
save_local_fpu(pr, TRUE /*retain*/);
|
||||||
|
|
||||||
/* The state may now be reset, and the caller does not expect
|
|
||||||
* this. Immediately restore the saved state.
|
|
||||||
*/
|
|
||||||
r = restore_fpu(pr);
|
|
||||||
assert(r == OK);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1878,7 +1878,7 @@ PUBLIC void copr_not_available_handler(void)
|
|||||||
local_fpu_owner = get_cpulocal_var_ptr(fpu_owner);
|
local_fpu_owner = get_cpulocal_var_ptr(fpu_owner);
|
||||||
if (*local_fpu_owner != NULL) {
|
if (*local_fpu_owner != NULL) {
|
||||||
assert(*local_fpu_owner != p);
|
assert(*local_fpu_owner != p);
|
||||||
save_local_fpu(*local_fpu_owner);
|
save_local_fpu(*local_fpu_owner, FALSE /*retain*/);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -1889,7 +1889,7 @@ PUBLIC void copr_not_available_handler(void)
|
|||||||
/* Restoring FPU state failed. This is always the process's own
|
/* Restoring FPU state failed. This is always the process's own
|
||||||
* fault. Send a signal, and schedule another process instead.
|
* fault. Send a signal, and schedule another process instead.
|
||||||
*/
|
*/
|
||||||
*local_fpu_owner = NULL;
|
*local_fpu_owner = NULL; /* release FPU */
|
||||||
cause_sig(proc_nr(p), SIGFPE);
|
cause_sig(proc_nr(p), SIGFPE);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -34,7 +34,7 @@ _PROTOTYPE( void context_stop, (struct proc * p) );
|
|||||||
_PROTOTYPE( void context_stop_idle, (void) );
|
_PROTOTYPE( void context_stop_idle, (void) );
|
||||||
_PROTOTYPE( int restore_fpu, (struct proc *) );
|
_PROTOTYPE( int restore_fpu, (struct proc *) );
|
||||||
_PROTOTYPE( void save_fpu, (struct proc *) );
|
_PROTOTYPE( void save_fpu, (struct proc *) );
|
||||||
_PROTOTYPE( void save_local_fpu, (struct proc *) );
|
_PROTOTYPE( void save_local_fpu, (struct proc *, int retain) );
|
||||||
_PROTOTYPE( void fpu_sigcontext, (struct proc *, struct sigframe *fr, struct sigcontext *sc) );
|
_PROTOTYPE( void fpu_sigcontext, (struct proc *, struct sigframe *fr, struct sigcontext *sc) );
|
||||||
|
|
||||||
/* main.c */
|
/* main.c */
|
||||||
|
@ -168,12 +168,12 @@ PUBLIC void smp_sched_handler(void)
|
|||||||
RTS_SET(p, RTS_PROC_STOP);
|
RTS_SET(p, RTS_PROC_STOP);
|
||||||
}
|
}
|
||||||
if (flgs & SCHED_IPI_SAVE_CTX) {
|
if (flgs & SCHED_IPI_SAVE_CTX) {
|
||||||
/* all context have been save already, FPU remains */
|
/* all context has been saved already, FPU remains */
|
||||||
if (proc_used_fpu(p) &&
|
if (proc_used_fpu(p) &&
|
||||||
get_cpulocal_var(fpu_owner) == p) {
|
get_cpulocal_var(fpu_owner) == p) {
|
||||||
disable_fpu_exception();
|
disable_fpu_exception();
|
||||||
save_local_fpu(p);
|
save_local_fpu(p, FALSE /*retain*/);
|
||||||
/* we re preparing to migrate somewhere else */
|
/* we're preparing to migrate somewhere else */
|
||||||
release_fpu(p);
|
release_fpu(p);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user