x86, fpu: decouple non-lazy/eager fpu restore from xsave
Decouple non-lazy/eager fpu restore policy from the existence of the xsave feature. Introduce a synthetic CPUID flag to represent the eagerfpu policy. "eagerfpu=on" boot paramter will enable the policy. Requested-by: H. Peter Anvin <hpa@zytor.com> Requested-by: Linus Torvalds <torvalds@linux-foundation.org> Signed-off-by: Suresh Siddha <suresh.b.siddha@intel.com> Link: http://lkml.kernel.org/r/1347300665-6209-2-git-send-email-suresh.b.siddha@intel.com Signed-off-by: H. Peter Anvin <hpa@linux.intel.com>
This commit is contained in:
parent
304bceda6a
commit
5d2bd7009f
@ -1833,6 +1833,10 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
|
|||||||
and restore using xsave. The kernel will fallback to
|
and restore using xsave. The kernel will fallback to
|
||||||
enabling legacy floating-point and sse state.
|
enabling legacy floating-point and sse state.
|
||||||
|
|
||||||
|
eagerfpu= [X86]
|
||||||
|
on enable eager fpu restore
|
||||||
|
off disable eager fpu restore
|
||||||
|
|
||||||
nohlt [BUGS=ARM,SH] Tells the kernel that the sleep(SH) or
|
nohlt [BUGS=ARM,SH] Tells the kernel that the sleep(SH) or
|
||||||
wfi(ARM) instruction doesn't work correctly and not to
|
wfi(ARM) instruction doesn't work correctly and not to
|
||||||
use it. This is also useful when using JTAG debugger.
|
use it. This is also useful when using JTAG debugger.
|
||||||
|
@ -97,6 +97,7 @@
|
|||||||
#define X86_FEATURE_EXTD_APICID (3*32+26) /* has extended APICID (8 bits) */
|
#define X86_FEATURE_EXTD_APICID (3*32+26) /* has extended APICID (8 bits) */
|
||||||
#define X86_FEATURE_AMD_DCM (3*32+27) /* multi-node processor */
|
#define X86_FEATURE_AMD_DCM (3*32+27) /* multi-node processor */
|
||||||
#define X86_FEATURE_APERFMPERF (3*32+28) /* APERFMPERF */
|
#define X86_FEATURE_APERFMPERF (3*32+28) /* APERFMPERF */
|
||||||
|
#define X86_FEATURE_EAGER_FPU (3*32+29) /* "eagerfpu" Non lazy FPU restore */
|
||||||
|
|
||||||
/* Intel-defined CPU features, CPUID level 0x00000001 (ecx), word 4 */
|
/* Intel-defined CPU features, CPUID level 0x00000001 (ecx), word 4 */
|
||||||
#define X86_FEATURE_XMM3 (4*32+ 0) /* "pni" SSE-3 */
|
#define X86_FEATURE_XMM3 (4*32+ 0) /* "pni" SSE-3 */
|
||||||
@ -305,6 +306,7 @@ extern const char * const x86_power_flags[32];
|
|||||||
#define cpu_has_perfctr_core boot_cpu_has(X86_FEATURE_PERFCTR_CORE)
|
#define cpu_has_perfctr_core boot_cpu_has(X86_FEATURE_PERFCTR_CORE)
|
||||||
#define cpu_has_cx8 boot_cpu_has(X86_FEATURE_CX8)
|
#define cpu_has_cx8 boot_cpu_has(X86_FEATURE_CX8)
|
||||||
#define cpu_has_cx16 boot_cpu_has(X86_FEATURE_CX16)
|
#define cpu_has_cx16 boot_cpu_has(X86_FEATURE_CX16)
|
||||||
|
#define cpu_has_eager_fpu boot_cpu_has(X86_FEATURE_EAGER_FPU)
|
||||||
|
|
||||||
#if defined(CONFIG_X86_INVLPG) || defined(CONFIG_X86_64)
|
#if defined(CONFIG_X86_INVLPG) || defined(CONFIG_X86_64)
|
||||||
# define cpu_has_invlpg 1
|
# define cpu_has_invlpg 1
|
||||||
|
@ -38,6 +38,7 @@ int ia32_setup_frame(int sig, struct k_sigaction *ka,
|
|||||||
|
|
||||||
extern unsigned int mxcsr_feature_mask;
|
extern unsigned int mxcsr_feature_mask;
|
||||||
extern void fpu_init(void);
|
extern void fpu_init(void);
|
||||||
|
extern void eager_fpu_init(void);
|
||||||
|
|
||||||
DECLARE_PER_CPU(struct task_struct *, fpu_owner_task);
|
DECLARE_PER_CPU(struct task_struct *, fpu_owner_task);
|
||||||
|
|
||||||
@ -84,6 +85,11 @@ static inline int is_x32_frame(void)
|
|||||||
|
|
||||||
#define X87_FSW_ES (1 << 7) /* Exception Summary */
|
#define X87_FSW_ES (1 << 7) /* Exception Summary */
|
||||||
|
|
||||||
|
static __always_inline __pure bool use_eager_fpu(void)
|
||||||
|
{
|
||||||
|
return static_cpu_has(X86_FEATURE_EAGER_FPU);
|
||||||
|
}
|
||||||
|
|
||||||
static __always_inline __pure bool use_xsaveopt(void)
|
static __always_inline __pure bool use_xsaveopt(void)
|
||||||
{
|
{
|
||||||
return static_cpu_has(X86_FEATURE_XSAVEOPT);
|
return static_cpu_has(X86_FEATURE_XSAVEOPT);
|
||||||
@ -99,6 +105,14 @@ static __always_inline __pure bool use_fxsr(void)
|
|||||||
return static_cpu_has(X86_FEATURE_FXSR);
|
return static_cpu_has(X86_FEATURE_FXSR);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline void fx_finit(struct i387_fxsave_struct *fx)
|
||||||
|
{
|
||||||
|
memset(fx, 0, xstate_size);
|
||||||
|
fx->cwd = 0x37f;
|
||||||
|
if (cpu_has_xmm)
|
||||||
|
fx->mxcsr = MXCSR_DEFAULT;
|
||||||
|
}
|
||||||
|
|
||||||
extern void __sanitize_i387_state(struct task_struct *);
|
extern void __sanitize_i387_state(struct task_struct *);
|
||||||
|
|
||||||
static inline void sanitize_i387_state(struct task_struct *tsk)
|
static inline void sanitize_i387_state(struct task_struct *tsk)
|
||||||
@ -291,13 +305,13 @@ static inline void __thread_set_has_fpu(struct task_struct *tsk)
|
|||||||
static inline void __thread_fpu_end(struct task_struct *tsk)
|
static inline void __thread_fpu_end(struct task_struct *tsk)
|
||||||
{
|
{
|
||||||
__thread_clear_has_fpu(tsk);
|
__thread_clear_has_fpu(tsk);
|
||||||
if (!use_xsave())
|
if (!use_eager_fpu())
|
||||||
stts();
|
stts();
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void __thread_fpu_begin(struct task_struct *tsk)
|
static inline void __thread_fpu_begin(struct task_struct *tsk)
|
||||||
{
|
{
|
||||||
if (!use_xsave())
|
if (!use_eager_fpu())
|
||||||
clts();
|
clts();
|
||||||
__thread_set_has_fpu(tsk);
|
__thread_set_has_fpu(tsk);
|
||||||
}
|
}
|
||||||
@ -327,10 +341,14 @@ static inline void drop_fpu(struct task_struct *tsk)
|
|||||||
|
|
||||||
static inline void drop_init_fpu(struct task_struct *tsk)
|
static inline void drop_init_fpu(struct task_struct *tsk)
|
||||||
{
|
{
|
||||||
if (!use_xsave())
|
if (!use_eager_fpu())
|
||||||
drop_fpu(tsk);
|
drop_fpu(tsk);
|
||||||
else
|
else {
|
||||||
|
if (use_xsave())
|
||||||
xrstor_state(init_xstate_buf, -1);
|
xrstor_state(init_xstate_buf, -1);
|
||||||
|
else
|
||||||
|
fxrstor_checking(&init_xstate_buf->i387);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -370,7 +388,7 @@ static inline fpu_switch_t switch_fpu_prepare(struct task_struct *old, struct ta
|
|||||||
* If the task has used the math, pre-load the FPU on xsave processors
|
* If the task has used the math, pre-load the FPU on xsave processors
|
||||||
* or if the past 5 consecutive context-switches used math.
|
* or if the past 5 consecutive context-switches used math.
|
||||||
*/
|
*/
|
||||||
fpu.preload = tsk_used_math(new) && (use_xsave() ||
|
fpu.preload = tsk_used_math(new) && (use_eager_fpu() ||
|
||||||
new->fpu_counter > 5);
|
new->fpu_counter > 5);
|
||||||
if (__thread_has_fpu(old)) {
|
if (__thread_has_fpu(old)) {
|
||||||
if (!__save_init_fpu(old))
|
if (!__save_init_fpu(old))
|
||||||
@ -383,14 +401,14 @@ static inline fpu_switch_t switch_fpu_prepare(struct task_struct *old, struct ta
|
|||||||
new->fpu_counter++;
|
new->fpu_counter++;
|
||||||
__thread_set_has_fpu(new);
|
__thread_set_has_fpu(new);
|
||||||
prefetch(new->thread.fpu.state);
|
prefetch(new->thread.fpu.state);
|
||||||
} else if (!use_xsave())
|
} else if (!use_eager_fpu())
|
||||||
stts();
|
stts();
|
||||||
} else {
|
} else {
|
||||||
old->fpu_counter = 0;
|
old->fpu_counter = 0;
|
||||||
old->thread.fpu.last_cpu = ~0;
|
old->thread.fpu.last_cpu = ~0;
|
||||||
if (fpu.preload) {
|
if (fpu.preload) {
|
||||||
new->fpu_counter++;
|
new->fpu_counter++;
|
||||||
if (!use_xsave() && fpu_lazy_restore(new, cpu))
|
if (!use_eager_fpu() && fpu_lazy_restore(new, cpu))
|
||||||
fpu.preload = 0;
|
fpu.preload = 0;
|
||||||
else
|
else
|
||||||
prefetch(new->thread.fpu.state);
|
prefetch(new->thread.fpu.state);
|
||||||
@ -452,6 +470,14 @@ static inline void user_fpu_begin(void)
|
|||||||
preempt_enable();
|
preempt_enable();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline void __save_fpu(struct task_struct *tsk)
|
||||||
|
{
|
||||||
|
if (use_xsave())
|
||||||
|
xsave_state(&tsk->thread.fpu.state->xsave, -1);
|
||||||
|
else
|
||||||
|
fpu_fxsave(&tsk->thread.fpu);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* These disable preemption on their own and are safe
|
* These disable preemption on their own and are safe
|
||||||
*/
|
*/
|
||||||
@ -459,8 +485,8 @@ static inline void save_init_fpu(struct task_struct *tsk)
|
|||||||
{
|
{
|
||||||
WARN_ON_ONCE(!__thread_has_fpu(tsk));
|
WARN_ON_ONCE(!__thread_has_fpu(tsk));
|
||||||
|
|
||||||
if (use_xsave()) {
|
if (use_eager_fpu()) {
|
||||||
xsave_state(&tsk->thread.fpu.state->xsave, -1);
|
__save_fpu(tsk);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -526,11 +552,9 @@ static inline void fpu_free(struct fpu *fpu)
|
|||||||
|
|
||||||
static inline void fpu_copy(struct task_struct *dst, struct task_struct *src)
|
static inline void fpu_copy(struct task_struct *dst, struct task_struct *src)
|
||||||
{
|
{
|
||||||
if (use_xsave()) {
|
if (use_eager_fpu()) {
|
||||||
struct xsave_struct *xsave = &dst->thread.fpu.state->xsave;
|
memset(&dst->thread.fpu.state->xsave, 0, xstate_size);
|
||||||
|
__save_fpu(dst);
|
||||||
memset(&xsave->xsave_hdr, 0, sizeof(struct xsave_hdr_struct));
|
|
||||||
xsave_state(xsave, -1);
|
|
||||||
} else {
|
} else {
|
||||||
struct fpu *dfpu = &dst->thread.fpu;
|
struct fpu *dfpu = &dst->thread.fpu;
|
||||||
struct fpu *sfpu = &src->thread.fpu;
|
struct fpu *sfpu = &src->thread.fpu;
|
||||||
|
@ -1297,7 +1297,6 @@ void __cpuinit cpu_init(void)
|
|||||||
dbg_restore_debug_regs();
|
dbg_restore_debug_regs();
|
||||||
|
|
||||||
fpu_init();
|
fpu_init();
|
||||||
xsave_init();
|
|
||||||
|
|
||||||
raw_local_save_flags(kernel_eflags);
|
raw_local_save_flags(kernel_eflags);
|
||||||
|
|
||||||
@ -1352,6 +1351,5 @@ void __cpuinit cpu_init(void)
|
|||||||
dbg_restore_debug_regs();
|
dbg_restore_debug_regs();
|
||||||
|
|
||||||
fpu_init();
|
fpu_init();
|
||||||
xsave_init();
|
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
@ -22,9 +22,8 @@
|
|||||||
/*
|
/*
|
||||||
* Were we in an interrupt that interrupted kernel mode?
|
* Were we in an interrupt that interrupted kernel mode?
|
||||||
*
|
*
|
||||||
* For now, on xsave platforms we will return interrupted
|
* For now, with eagerfpu we will return interrupted kernel FPU
|
||||||
* kernel FPU as not-idle. TBD: As we use non-lazy FPU restore
|
* state as not-idle. TBD: Ideally we can change the return value
|
||||||
* for xsave platforms, ideally we can change the return value
|
|
||||||
* to something like __thread_has_fpu(current). But we need to
|
* to something like __thread_has_fpu(current). But we need to
|
||||||
* be careful of doing __thread_clear_has_fpu() before saving
|
* be careful of doing __thread_clear_has_fpu() before saving
|
||||||
* the FPU etc for supporting nested uses etc. For now, take
|
* the FPU etc for supporting nested uses etc. For now, take
|
||||||
@ -38,7 +37,7 @@
|
|||||||
*/
|
*/
|
||||||
static inline bool interrupted_kernel_fpu_idle(void)
|
static inline bool interrupted_kernel_fpu_idle(void)
|
||||||
{
|
{
|
||||||
if (use_xsave())
|
if (use_eager_fpu())
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
return !__thread_has_fpu(current) &&
|
return !__thread_has_fpu(current) &&
|
||||||
@ -84,7 +83,7 @@ void kernel_fpu_begin(void)
|
|||||||
__save_init_fpu(me);
|
__save_init_fpu(me);
|
||||||
__thread_clear_has_fpu(me);
|
__thread_clear_has_fpu(me);
|
||||||
/* We do 'stts()' in kernel_fpu_end() */
|
/* We do 'stts()' in kernel_fpu_end() */
|
||||||
} else if (!use_xsave()) {
|
} else if (!use_eager_fpu()) {
|
||||||
this_cpu_write(fpu_owner_task, NULL);
|
this_cpu_write(fpu_owner_task, NULL);
|
||||||
clts();
|
clts();
|
||||||
}
|
}
|
||||||
@ -93,7 +92,7 @@ EXPORT_SYMBOL(kernel_fpu_begin);
|
|||||||
|
|
||||||
void kernel_fpu_end(void)
|
void kernel_fpu_end(void)
|
||||||
{
|
{
|
||||||
if (use_xsave())
|
if (use_eager_fpu())
|
||||||
math_state_restore();
|
math_state_restore();
|
||||||
else
|
else
|
||||||
stts();
|
stts();
|
||||||
@ -122,7 +121,6 @@ static void __cpuinit mxcsr_feature_mask_init(void)
|
|||||||
{
|
{
|
||||||
unsigned long mask = 0;
|
unsigned long mask = 0;
|
||||||
|
|
||||||
clts();
|
|
||||||
if (cpu_has_fxsr) {
|
if (cpu_has_fxsr) {
|
||||||
memset(&fx_scratch, 0, sizeof(struct i387_fxsave_struct));
|
memset(&fx_scratch, 0, sizeof(struct i387_fxsave_struct));
|
||||||
asm volatile("fxsave %0" : : "m" (fx_scratch));
|
asm volatile("fxsave %0" : : "m" (fx_scratch));
|
||||||
@ -131,7 +129,6 @@ static void __cpuinit mxcsr_feature_mask_init(void)
|
|||||||
mask = 0x0000ffbf;
|
mask = 0x0000ffbf;
|
||||||
}
|
}
|
||||||
mxcsr_feature_mask &= mask;
|
mxcsr_feature_mask &= mask;
|
||||||
stts();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void __cpuinit init_thread_xstate(void)
|
static void __cpuinit init_thread_xstate(void)
|
||||||
@ -185,9 +182,8 @@ void __cpuinit fpu_init(void)
|
|||||||
init_thread_xstate();
|
init_thread_xstate();
|
||||||
|
|
||||||
mxcsr_feature_mask_init();
|
mxcsr_feature_mask_init();
|
||||||
/* clean state in init */
|
xsave_init();
|
||||||
current_thread_info()->status = 0;
|
eager_fpu_init();
|
||||||
clear_used_math();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void fpu_finit(struct fpu *fpu)
|
void fpu_finit(struct fpu *fpu)
|
||||||
@ -198,12 +194,7 @@ void fpu_finit(struct fpu *fpu)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (cpu_has_fxsr) {
|
if (cpu_has_fxsr) {
|
||||||
struct i387_fxsave_struct *fx = &fpu->state->fxsave;
|
fx_finit(&fpu->state->fxsave);
|
||||||
|
|
||||||
memset(fx, 0, xstate_size);
|
|
||||||
fx->cwd = 0x37f;
|
|
||||||
if (cpu_has_xmm)
|
|
||||||
fx->mxcsr = MXCSR_DEFAULT;
|
|
||||||
} else {
|
} else {
|
||||||
struct i387_fsave_struct *fp = &fpu->state->fsave;
|
struct i387_fsave_struct *fp = &fpu->state->fsave;
|
||||||
memset(fp, 0, xstate_size);
|
memset(fp, 0, xstate_size);
|
||||||
|
@ -156,7 +156,7 @@ void flush_thread(void)
|
|||||||
* Free the FPU state for non xsave platforms. They get reallocated
|
* Free the FPU state for non xsave platforms. They get reallocated
|
||||||
* lazily at the first use.
|
* lazily at the first use.
|
||||||
*/
|
*/
|
||||||
if (!use_xsave())
|
if (!use_eager_fpu())
|
||||||
free_thread_xstate(tsk);
|
free_thread_xstate(tsk);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -630,7 +630,7 @@ EXPORT_SYMBOL_GPL(math_state_restore);
|
|||||||
dotraplinkage void __kprobes
|
dotraplinkage void __kprobes
|
||||||
do_device_not_available(struct pt_regs *regs, long error_code)
|
do_device_not_available(struct pt_regs *regs, long error_code)
|
||||||
{
|
{
|
||||||
BUG_ON(use_xsave());
|
BUG_ON(use_eager_fpu());
|
||||||
|
|
||||||
#ifdef CONFIG_MATH_EMULATION
|
#ifdef CONFIG_MATH_EMULATION
|
||||||
if (read_cr0() & X86_CR0_EM) {
|
if (read_cr0() & X86_CR0_EM) {
|
||||||
|
@ -400,7 +400,7 @@ int __restore_xstate_sig(void __user *buf, void __user *buf_fx, int size)
|
|||||||
set_used_math();
|
set_used_math();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (use_xsave())
|
if (use_eager_fpu())
|
||||||
math_state_restore();
|
math_state_restore();
|
||||||
|
|
||||||
return err;
|
return err;
|
||||||
@ -450,28 +450,10 @@ static void prepare_fx_sw_frame(void)
|
|||||||
*/
|
*/
|
||||||
static inline void xstate_enable(void)
|
static inline void xstate_enable(void)
|
||||||
{
|
{
|
||||||
clts();
|
|
||||||
set_in_cr4(X86_CR4_OSXSAVE);
|
set_in_cr4(X86_CR4_OSXSAVE);
|
||||||
xsetbv(XCR_XFEATURE_ENABLED_MASK, pcntxt_mask);
|
xsetbv(XCR_XFEATURE_ENABLED_MASK, pcntxt_mask);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* This is same as math_state_restore(). But use_xsave() is not yet
|
|
||||||
* patched to use math_state_restore().
|
|
||||||
*/
|
|
||||||
static inline void init_restore_xstate(void)
|
|
||||||
{
|
|
||||||
init_fpu(current);
|
|
||||||
__thread_fpu_begin(current);
|
|
||||||
xrstor_state(init_xstate_buf, -1);
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline void xstate_enable_ap(void)
|
|
||||||
{
|
|
||||||
xstate_enable();
|
|
||||||
init_restore_xstate();
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Record the offsets and sizes of different state managed by the xsave
|
* Record the offsets and sizes of different state managed by the xsave
|
||||||
* memory layout.
|
* memory layout.
|
||||||
@ -500,17 +482,20 @@ static void __init setup_xstate_features(void)
|
|||||||
/*
|
/*
|
||||||
* setup the xstate image representing the init state
|
* setup the xstate image representing the init state
|
||||||
*/
|
*/
|
||||||
static void __init setup_xstate_init(void)
|
static void __init setup_init_fpu_buf(void)
|
||||||
{
|
{
|
||||||
setup_xstate_features();
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Setup init_xstate_buf to represent the init state of
|
* Setup init_xstate_buf to represent the init state of
|
||||||
* all the features managed by the xsave
|
* all the features managed by the xsave
|
||||||
*/
|
*/
|
||||||
init_xstate_buf = alloc_bootmem_align(xstate_size,
|
init_xstate_buf = alloc_bootmem_align(xstate_size,
|
||||||
__alignof__(struct xsave_struct));
|
__alignof__(struct xsave_struct));
|
||||||
init_xstate_buf->i387.mxcsr = MXCSR_DEFAULT;
|
fx_finit(&init_xstate_buf->i387);
|
||||||
|
|
||||||
|
if (!cpu_has_xsave)
|
||||||
|
return;
|
||||||
|
|
||||||
|
setup_xstate_features();
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Init all the features state with header_bv being 0x0
|
* Init all the features state with header_bv being 0x0
|
||||||
@ -523,6 +508,17 @@ static void __init setup_xstate_init(void)
|
|||||||
xsave_state(init_xstate_buf, -1);
|
xsave_state(init_xstate_buf, -1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int disable_eagerfpu;
|
||||||
|
static int __init eager_fpu_setup(char *s)
|
||||||
|
{
|
||||||
|
if (!strcmp(s, "on"))
|
||||||
|
setup_force_cpu_cap(X86_FEATURE_EAGER_FPU);
|
||||||
|
else if (!strcmp(s, "off"))
|
||||||
|
disable_eagerfpu = 1;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
__setup("eagerfpu=", eager_fpu_setup);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Enable and initialize the xsave feature.
|
* Enable and initialize the xsave feature.
|
||||||
*/
|
*/
|
||||||
@ -559,15 +555,10 @@ static void __init xstate_enable_boot_cpu(void)
|
|||||||
|
|
||||||
update_regset_xstate_info(xstate_size, pcntxt_mask);
|
update_regset_xstate_info(xstate_size, pcntxt_mask);
|
||||||
prepare_fx_sw_frame();
|
prepare_fx_sw_frame();
|
||||||
|
setup_init_fpu_buf();
|
||||||
setup_xstate_init();
|
|
||||||
|
|
||||||
pr_info("enabled xstate_bv 0x%llx, cntxt size 0x%x\n",
|
pr_info("enabled xstate_bv 0x%llx, cntxt size 0x%x\n",
|
||||||
pcntxt_mask, xstate_size);
|
pcntxt_mask, xstate_size);
|
||||||
|
|
||||||
current->thread.fpu.state =
|
|
||||||
alloc_bootmem_align(xstate_size, __alignof__(struct xsave_struct));
|
|
||||||
init_restore_xstate();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -586,6 +577,42 @@ void __cpuinit xsave_init(void)
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
this_func = next_func;
|
this_func = next_func;
|
||||||
next_func = xstate_enable_ap;
|
next_func = xstate_enable;
|
||||||
this_func();
|
this_func();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline void __init eager_fpu_init_bp(void)
|
||||||
|
{
|
||||||
|
current->thread.fpu.state =
|
||||||
|
alloc_bootmem_align(xstate_size, __alignof__(struct xsave_struct));
|
||||||
|
if (!init_xstate_buf)
|
||||||
|
setup_init_fpu_buf();
|
||||||
|
}
|
||||||
|
|
||||||
|
void __cpuinit eager_fpu_init(void)
|
||||||
|
{
|
||||||
|
static __refdata void (*boot_func)(void) = eager_fpu_init_bp;
|
||||||
|
|
||||||
|
clear_used_math();
|
||||||
|
current_thread_info()->status = 0;
|
||||||
|
if (!cpu_has_eager_fpu) {
|
||||||
|
stts();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (boot_func) {
|
||||||
|
boot_func();
|
||||||
|
boot_func = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This is same as math_state_restore(). But use_xsave() is
|
||||||
|
* not yet patched to use math_state_restore().
|
||||||
|
*/
|
||||||
|
init_fpu(current);
|
||||||
|
__thread_fpu_begin(current);
|
||||||
|
if (cpu_has_xsave)
|
||||||
|
xrstor_state(init_xstate_buf, -1);
|
||||||
|
else
|
||||||
|
fxrstor_checking(&init_xstate_buf->i387);
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user