Commit 280d7a1e authored by Linus Torvalds's avatar Linus Torvalds

Merge branch 'x86-fpu-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip

Pull x86 fpu updates from Ingo Molnar:
 "The main changes relate to fixes between (lack of) CPUID and FPU
  detection that should only affect old or weird CPUs, by Andy
  Lutomirski"

* 'x86-fpu-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip:
  x86/fpu: Fix the "Giving up, no FPU found" test
  x86/fpu: Fix CPUID-less FPU detection
  x86/fpu: Fix "x86/fpu: Legacy x87 FPU detected" message
  x86/cpu: Re-apply forced caps every time CPU caps are re-read
  x86/cpu: Factor out application of forced CPU caps
  x86/cpu: Add X86_FEATURE_CPUID
  x86/fpu/xstate: Move XSAVES state init to a function
parents 8a9365a4 9729017f
...@@ -100,7 +100,7 @@ ...@@ -100,7 +100,7 @@
#define X86_FEATURE_XTOPOLOGY ( 3*32+22) /* cpu topology enum extensions */ #define X86_FEATURE_XTOPOLOGY ( 3*32+22) /* cpu topology enum extensions */
#define X86_FEATURE_TSC_RELIABLE ( 3*32+23) /* TSC is known to be reliable */ #define X86_FEATURE_TSC_RELIABLE ( 3*32+23) /* TSC is known to be reliable */
#define X86_FEATURE_NONSTOP_TSC ( 3*32+24) /* TSC does not stop in C states */ #define X86_FEATURE_NONSTOP_TSC ( 3*32+24) /* TSC does not stop in C states */
/* free, was #define X86_FEATURE_CLFLUSH_MONITOR ( 3*32+25) * "" clflush reqd with monitor */ #define X86_FEATURE_CPUID ( 3*32+25) /* CPU has CPUID instruction itself */
#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 */
......
...@@ -87,6 +87,16 @@ extern void fpstate_init_soft(struct swregs_state *soft); ...@@ -87,6 +87,16 @@ extern void fpstate_init_soft(struct swregs_state *soft);
#else #else
static inline void fpstate_init_soft(struct swregs_state *soft) {} static inline void fpstate_init_soft(struct swregs_state *soft) {}
#endif #endif
static inline void fpstate_init_xstate(struct xregs_state *xsave)
{
/*
* XRSTORS requires these bits set in xcomp_bv, or it will
* trigger #GP:
*/
xsave->header.xcomp_bv = XCOMP_BV_COMPACTED_FORMAT | xfeatures_mask;
}
static inline void fpstate_init_fxstate(struct fxregs_state *fx) static inline void fpstate_init_fxstate(struct fxregs_state *fx)
{ {
fx->cwd = 0x37f; fx->cwd = 0x37f;
......
...@@ -659,6 +659,16 @@ void cpu_detect(struct cpuinfo_x86 *c) ...@@ -659,6 +659,16 @@ void cpu_detect(struct cpuinfo_x86 *c)
} }
} }
static void apply_forced_caps(struct cpuinfo_x86 *c)
{
int i;
for (i = 0; i < NCAPINTS; i++) {
c->x86_capability[i] &= ~cpu_caps_cleared[i];
c->x86_capability[i] |= cpu_caps_set[i];
}
}
void get_cpu_cap(struct cpuinfo_x86 *c) void get_cpu_cap(struct cpuinfo_x86 *c)
{ {
u32 eax, ebx, ecx, edx; u32 eax, ebx, ecx, edx;
...@@ -752,6 +762,13 @@ void get_cpu_cap(struct cpuinfo_x86 *c) ...@@ -752,6 +762,13 @@ void get_cpu_cap(struct cpuinfo_x86 *c)
c->x86_capability[CPUID_8000_000A_EDX] = cpuid_edx(0x8000000a); c->x86_capability[CPUID_8000_000A_EDX] = cpuid_edx(0x8000000a);
init_scattered_cpuid_features(c); init_scattered_cpuid_features(c);
/*
* Clear/Set all flags overridden by options, after probe.
* This needs to happen each time we re-probe, which may happen
* several times during CPU initialization.
*/
apply_forced_caps(c);
} }
static void identify_cpu_without_cpuid(struct cpuinfo_x86 *c) static void identify_cpu_without_cpuid(struct cpuinfo_x86 *c)
...@@ -805,14 +822,12 @@ static void __init early_identify_cpu(struct cpuinfo_x86 *c) ...@@ -805,14 +822,12 @@ static void __init early_identify_cpu(struct cpuinfo_x86 *c)
memset(&c->x86_capability, 0, sizeof c->x86_capability); memset(&c->x86_capability, 0, sizeof c->x86_capability);
c->extended_cpuid_level = 0; c->extended_cpuid_level = 0;
if (!have_cpuid_p())
identify_cpu_without_cpuid(c);
/* cyrix could have cpuid enabled via c_identify()*/ /* cyrix could have cpuid enabled via c_identify()*/
if (have_cpuid_p()) { if (have_cpuid_p()) {
cpu_detect(c); cpu_detect(c);
get_cpu_vendor(c); get_cpu_vendor(c);
get_cpu_cap(c); get_cpu_cap(c);
setup_force_cpu_cap(X86_FEATURE_CPUID);
if (this_cpu->c_early_init) if (this_cpu->c_early_init)
this_cpu->c_early_init(c); this_cpu->c_early_init(c);
...@@ -822,6 +837,9 @@ static void __init early_identify_cpu(struct cpuinfo_x86 *c) ...@@ -822,6 +837,9 @@ static void __init early_identify_cpu(struct cpuinfo_x86 *c)
if (this_cpu->c_bsp_init) if (this_cpu->c_bsp_init)
this_cpu->c_bsp_init(c); this_cpu->c_bsp_init(c);
} else {
identify_cpu_without_cpuid(c);
setup_clear_cpu_cap(X86_FEATURE_CPUID);
} }
setup_force_cpu_cap(X86_FEATURE_ALWAYS); setup_force_cpu_cap(X86_FEATURE_ALWAYS);
...@@ -1039,10 +1057,7 @@ static void identify_cpu(struct cpuinfo_x86 *c) ...@@ -1039,10 +1057,7 @@ static void identify_cpu(struct cpuinfo_x86 *c)
this_cpu->c_identify(c); this_cpu->c_identify(c);
/* Clear/Set all flags overridden by options, after probe */ /* Clear/Set all flags overridden by options, after probe */
for (i = 0; i < NCAPINTS; i++) { apply_forced_caps(c);
c->x86_capability[i] &= ~cpu_caps_cleared[i];
c->x86_capability[i] |= cpu_caps_set[i];
}
#ifdef CONFIG_X86_64 #ifdef CONFIG_X86_64
c->apicid = apic->phys_pkg_id(c->initial_apicid, 0); c->apicid = apic->phys_pkg_id(c->initial_apicid, 0);
...@@ -1103,10 +1118,7 @@ static void identify_cpu(struct cpuinfo_x86 *c) ...@@ -1103,10 +1118,7 @@ static void identify_cpu(struct cpuinfo_x86 *c)
* Clear/Set all flags overridden by options, need do it * Clear/Set all flags overridden by options, need do it
* before following smp all cpus cap AND. * before following smp all cpus cap AND.
*/ */
for (i = 0; i < NCAPINTS; i++) { apply_forced_caps(c);
c->x86_capability[i] &= ~cpu_caps_cleared[i];
c->x86_capability[i] |= cpu_caps_set[i];
}
/* /*
* On SMP, boot_cpu_data holds the common feature set between * On SMP, boot_cpu_data holds the common feature set between
......
...@@ -9,7 +9,6 @@ ...@@ -9,7 +9,6 @@
#include <asm/fpu/regset.h> #include <asm/fpu/regset.h>
#include <asm/fpu/signal.h> #include <asm/fpu/signal.h>
#include <asm/fpu/types.h> #include <asm/fpu/types.h>
#include <asm/fpu/xstate.h>
#include <asm/traps.h> #include <asm/traps.h>
#include <linux/hardirq.h> #include <linux/hardirq.h>
...@@ -179,14 +178,8 @@ void fpstate_init(union fpregs_state *state) ...@@ -179,14 +178,8 @@ void fpstate_init(union fpregs_state *state)
memset(state, 0, fpu_kernel_xstate_size); memset(state, 0, fpu_kernel_xstate_size);
/*
* XRSTORS requires that this bit is set in xcomp_bv, or
* it will #GP. Make sure it is replaced after the memset().
*/
if (static_cpu_has(X86_FEATURE_XSAVES)) if (static_cpu_has(X86_FEATURE_XSAVES))
state->xsave.header.xcomp_bv = XCOMP_BV_COMPACTED_FORMAT | fpstate_init_xstate(&state->xsave);
xfeatures_mask;
if (static_cpu_has(X86_FEATURE_FXSR)) if (static_cpu_has(X86_FEATURE_FXSR))
fpstate_init_fxstate(&state->fxsave); fpstate_init_fxstate(&state->fxsave);
else else
......
...@@ -48,13 +48,7 @@ void fpu__init_cpu(void) ...@@ -48,13 +48,7 @@ void fpu__init_cpu(void)
fpu__init_cpu_xstate(); fpu__init_cpu_xstate();
} }
/* static bool fpu__probe_without_cpuid(void)
* The earliest FPU detection code.
*
* Set the X86_FEATURE_FPU CPU-capability bit based on
* trying to execute an actual sequence of FPU instructions:
*/
static void fpu__init_system_early_generic(struct cpuinfo_x86 *c)
{ {
unsigned long cr0; unsigned long cr0;
u16 fsw, fcw; u16 fsw, fcw;
...@@ -65,18 +59,25 @@ static void fpu__init_system_early_generic(struct cpuinfo_x86 *c) ...@@ -65,18 +59,25 @@ static void fpu__init_system_early_generic(struct cpuinfo_x86 *c)
cr0 &= ~(X86_CR0_TS | X86_CR0_EM); cr0 &= ~(X86_CR0_TS | X86_CR0_EM);
write_cr0(cr0); write_cr0(cr0);
if (!test_bit(X86_FEATURE_FPU, (unsigned long *)cpu_caps_cleared)) { asm volatile("fninit ; fnstsw %0 ; fnstcw %1" : "+m" (fsw), "+m" (fcw));
asm volatile("fninit ; fnstsw %0 ; fnstcw %1"
: "+m" (fsw), "+m" (fcw)); pr_info("x86/fpu: Probing for FPU: FSW=0x%04hx FCW=0x%04hx\n", fsw, fcw);
if (fsw == 0 && (fcw & 0x103f) == 0x003f) return fsw == 0 && (fcw & 0x103f) == 0x003f;
set_cpu_cap(c, X86_FEATURE_FPU); }
static void fpu__init_system_early_generic(struct cpuinfo_x86 *c)
{
if (!boot_cpu_has(X86_FEATURE_CPUID) &&
!test_bit(X86_FEATURE_FPU, (unsigned long *)cpu_caps_cleared)) {
if (fpu__probe_without_cpuid())
setup_force_cpu_cap(X86_FEATURE_FPU);
else else
clear_cpu_cap(c, X86_FEATURE_FPU); setup_clear_cpu_cap(X86_FEATURE_FPU);
} }
#ifndef CONFIG_MATH_EMULATION #ifndef CONFIG_MATH_EMULATION
if (!boot_cpu_has(X86_FEATURE_FPU)) { if (!test_cpu_cap(&boot_cpu_data, X86_FEATURE_FPU)) {
pr_emerg("x86/fpu: Giving up, no FPU found and no math emulation present\n"); pr_emerg("x86/fpu: Giving up, no FPU found and no math emulation present\n");
for (;;) for (;;)
asm volatile("hlt"); asm volatile("hlt");
......
...@@ -706,8 +706,14 @@ void __init fpu__init_system_xstate(void) ...@@ -706,8 +706,14 @@ void __init fpu__init_system_xstate(void)
WARN_ON_FPU(!on_boot_cpu); WARN_ON_FPU(!on_boot_cpu);
on_boot_cpu = 0; on_boot_cpu = 0;
if (!boot_cpu_has(X86_FEATURE_FPU)) {
pr_info("x86/fpu: No FPU detected\n");
return;
}
if (!boot_cpu_has(X86_FEATURE_XSAVE)) { if (!boot_cpu_has(X86_FEATURE_XSAVE)) {
pr_info("x86/fpu: Legacy x87 FPU detected.\n"); pr_info("x86/fpu: x87 FPU will use %s\n",
boot_cpu_has(X86_FEATURE_FXSR) ? "FXSAVE" : "FSAVE");
return; return;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment