aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--arch/x86/include/asm/cpufeatures.h2
-rw-r--r--arch/x86/include/asm/fpu/internal.h10
-rw-r--r--arch/x86/kernel/cpu/common.c34
-rw-r--r--arch/x86/kernel/fpu/core.c9
-rw-r--r--arch/x86/kernel/fpu/init.c29
-rw-r--r--arch/x86/kernel/fpu/xstate.c8
6 files changed, 57 insertions, 35 deletions
diff --git a/arch/x86/include/asm/cpufeatures.h b/arch/x86/include/asm/cpufeatures.h
index 43c4ea9cd907..4e7772387c6e 100644
--- a/arch/x86/include/asm/cpufeatures.h
+++ b/arch/x86/include/asm/cpufeatures.h
@@ -100,7 +100,7 @@
100#define X86_FEATURE_XTOPOLOGY ( 3*32+22) /* cpu topology enum extensions */ 100#define X86_FEATURE_XTOPOLOGY ( 3*32+22) /* cpu topology enum extensions */
101#define X86_FEATURE_TSC_RELIABLE ( 3*32+23) /* TSC is known to be reliable */ 101#define X86_FEATURE_TSC_RELIABLE ( 3*32+23) /* TSC is known to be reliable */
102#define X86_FEATURE_NONSTOP_TSC ( 3*32+24) /* TSC does not stop in C states */ 102#define X86_FEATURE_NONSTOP_TSC ( 3*32+24) /* TSC does not stop in C states */
103/* free, was #define X86_FEATURE_CLFLUSH_MONITOR ( 3*32+25) * "" clflush reqd with monitor */ 103#define X86_FEATURE_CPUID ( 3*32+25) /* CPU has CPUID instruction itself */
104#define X86_FEATURE_EXTD_APICID ( 3*32+26) /* has extended APICID (8 bits) */ 104#define X86_FEATURE_EXTD_APICID ( 3*32+26) /* has extended APICID (8 bits) */
105#define X86_FEATURE_AMD_DCM ( 3*32+27) /* multi-node processor */ 105#define X86_FEATURE_AMD_DCM ( 3*32+27) /* multi-node processor */
106#define X86_FEATURE_APERFMPERF ( 3*32+28) /* APERFMPERF */ 106#define X86_FEATURE_APERFMPERF ( 3*32+28) /* APERFMPERF */
diff --git a/arch/x86/include/asm/fpu/internal.h b/arch/x86/include/asm/fpu/internal.h
index d4a684997497..255645f60ca2 100644
--- a/arch/x86/include/asm/fpu/internal.h
+++ b/arch/x86/include/asm/fpu/internal.h
@@ -87,6 +87,16 @@ extern void fpstate_init_soft(struct swregs_state *soft);
87#else 87#else
88static inline void fpstate_init_soft(struct swregs_state *soft) {} 88static inline void fpstate_init_soft(struct swregs_state *soft) {}
89#endif 89#endif
90
91static inline void fpstate_init_xstate(struct xregs_state *xsave)
92{
93 /*
94 * XRSTORS requires these bits set in xcomp_bv, or it will
95 * trigger #GP:
96 */
97 xsave->header.xcomp_bv = XCOMP_BV_COMPACTED_FORMAT | xfeatures_mask;
98}
99
90static inline void fpstate_init_fxstate(struct fxregs_state *fx) 100static inline void fpstate_init_fxstate(struct fxregs_state *fx)
91{ 101{
92 fx->cwd = 0x37f; 102 fx->cwd = 0x37f;
diff --git a/arch/x86/kernel/cpu/common.c b/arch/x86/kernel/cpu/common.c
index 5200adcaaac3..f07005e6f461 100644
--- a/arch/x86/kernel/cpu/common.c
+++ b/arch/x86/kernel/cpu/common.c
@@ -659,6 +659,16 @@ void cpu_detect(struct cpuinfo_x86 *c)
659 } 659 }
660} 660}
661 661
662static void apply_forced_caps(struct cpuinfo_x86 *c)
663{
664 int i;
665
666 for (i = 0; i < NCAPINTS; i++) {
667 c->x86_capability[i] &= ~cpu_caps_cleared[i];
668 c->x86_capability[i] |= cpu_caps_set[i];
669 }
670}
671
662void get_cpu_cap(struct cpuinfo_x86 *c) 672void get_cpu_cap(struct cpuinfo_x86 *c)
663{ 673{
664 u32 eax, ebx, ecx, edx; 674 u32 eax, ebx, ecx, edx;
@@ -752,6 +762,13 @@ void get_cpu_cap(struct cpuinfo_x86 *c)
752 c->x86_capability[CPUID_8000_000A_EDX] = cpuid_edx(0x8000000a); 762 c->x86_capability[CPUID_8000_000A_EDX] = cpuid_edx(0x8000000a);
753 763
754 init_scattered_cpuid_features(c); 764 init_scattered_cpuid_features(c);
765
766 /*
767 * Clear/Set all flags overridden by options, after probe.
768 * This needs to happen each time we re-probe, which may happen
769 * several times during CPU initialization.
770 */
771 apply_forced_caps(c);
755} 772}
756 773
757static void identify_cpu_without_cpuid(struct cpuinfo_x86 *c) 774static void identify_cpu_without_cpuid(struct cpuinfo_x86 *c)
@@ -805,14 +822,12 @@ static void __init early_identify_cpu(struct cpuinfo_x86 *c)
805 memset(&c->x86_capability, 0, sizeof c->x86_capability); 822 memset(&c->x86_capability, 0, sizeof c->x86_capability);
806 c->extended_cpuid_level = 0; 823 c->extended_cpuid_level = 0;
807 824
808 if (!have_cpuid_p())
809 identify_cpu_without_cpuid(c);
810
811 /* cyrix could have cpuid enabled via c_identify()*/ 825 /* cyrix could have cpuid enabled via c_identify()*/
812 if (have_cpuid_p()) { 826 if (have_cpuid_p()) {
813 cpu_detect(c); 827 cpu_detect(c);
814 get_cpu_vendor(c); 828 get_cpu_vendor(c);
815 get_cpu_cap(c); 829 get_cpu_cap(c);
830 setup_force_cpu_cap(X86_FEATURE_CPUID);
816 831
817 if (this_cpu->c_early_init) 832 if (this_cpu->c_early_init)
818 this_cpu->c_early_init(c); 833 this_cpu->c_early_init(c);
@@ -822,6 +837,9 @@ static void __init early_identify_cpu(struct cpuinfo_x86 *c)
822 837
823 if (this_cpu->c_bsp_init) 838 if (this_cpu->c_bsp_init)
824 this_cpu->c_bsp_init(c); 839 this_cpu->c_bsp_init(c);
840 } else {
841 identify_cpu_without_cpuid(c);
842 setup_clear_cpu_cap(X86_FEATURE_CPUID);
825 } 843 }
826 844
827 setup_force_cpu_cap(X86_FEATURE_ALWAYS); 845 setup_force_cpu_cap(X86_FEATURE_ALWAYS);
@@ -1039,10 +1057,7 @@ static void identify_cpu(struct cpuinfo_x86 *c)
1039 this_cpu->c_identify(c); 1057 this_cpu->c_identify(c);
1040 1058
1041 /* Clear/Set all flags overridden by options, after probe */ 1059 /* Clear/Set all flags overridden by options, after probe */
1042 for (i = 0; i < NCAPINTS; i++) { 1060 apply_forced_caps(c);
1043 c->x86_capability[i] &= ~cpu_caps_cleared[i];
1044 c->x86_capability[i] |= cpu_caps_set[i];
1045 }
1046 1061
1047#ifdef CONFIG_X86_64 1062#ifdef CONFIG_X86_64
1048 c->apicid = apic->phys_pkg_id(c->initial_apicid, 0); 1063 c->apicid = apic->phys_pkg_id(c->initial_apicid, 0);
@@ -1103,10 +1118,7 @@ static void identify_cpu(struct cpuinfo_x86 *c)
1103 * Clear/Set all flags overridden by options, need do it 1118 * Clear/Set all flags overridden by options, need do it
1104 * before following smp all cpus cap AND. 1119 * before following smp all cpus cap AND.
1105 */ 1120 */
1106 for (i = 0; i < NCAPINTS; i++) { 1121 apply_forced_caps(c);
1107 c->x86_capability[i] &= ~cpu_caps_cleared[i];
1108 c->x86_capability[i] |= cpu_caps_set[i];
1109 }
1110 1122
1111 /* 1123 /*
1112 * On SMP, boot_cpu_data holds the common feature set between 1124 * On SMP, boot_cpu_data holds the common feature set between
diff --git a/arch/x86/kernel/fpu/core.c b/arch/x86/kernel/fpu/core.c
index de7234401275..e1114f070c2d 100644
--- a/arch/x86/kernel/fpu/core.c
+++ b/arch/x86/kernel/fpu/core.c
@@ -9,7 +9,6 @@
9#include <asm/fpu/regset.h> 9#include <asm/fpu/regset.h>
10#include <asm/fpu/signal.h> 10#include <asm/fpu/signal.h>
11#include <asm/fpu/types.h> 11#include <asm/fpu/types.h>
12#include <asm/fpu/xstate.h>
13#include <asm/traps.h> 12#include <asm/traps.h>
14 13
15#include <linux/hardirq.h> 14#include <linux/hardirq.h>
@@ -179,14 +178,8 @@ void fpstate_init(union fpregs_state *state)
179 178
180 memset(state, 0, fpu_kernel_xstate_size); 179 memset(state, 0, fpu_kernel_xstate_size);
181 180
182 /*
183 * XRSTORS requires that this bit is set in xcomp_bv, or
184 * it will #GP. Make sure it is replaced after the memset().
185 */
186 if (static_cpu_has(X86_FEATURE_XSAVES)) 181 if (static_cpu_has(X86_FEATURE_XSAVES))
187 state->xsave.header.xcomp_bv = XCOMP_BV_COMPACTED_FORMAT | 182 fpstate_init_xstate(&state->xsave);
188 xfeatures_mask;
189
190 if (static_cpu_has(X86_FEATURE_FXSR)) 183 if (static_cpu_has(X86_FEATURE_FXSR))
191 fpstate_init_fxstate(&state->fxsave); 184 fpstate_init_fxstate(&state->fxsave);
192 else 185 else
diff --git a/arch/x86/kernel/fpu/init.c b/arch/x86/kernel/fpu/init.c
index 60dece392b3a..19bdd1bf8160 100644
--- a/arch/x86/kernel/fpu/init.c
+++ b/arch/x86/kernel/fpu/init.c
@@ -48,13 +48,7 @@ void fpu__init_cpu(void)
48 fpu__init_cpu_xstate(); 48 fpu__init_cpu_xstate();
49} 49}
50 50
51/* 51static bool fpu__probe_without_cpuid(void)
52 * The earliest FPU detection code.
53 *
54 * Set the X86_FEATURE_FPU CPU-capability bit based on
55 * trying to execute an actual sequence of FPU instructions:
56 */
57static void fpu__init_system_early_generic(struct cpuinfo_x86 *c)
58{ 52{
59 unsigned long cr0; 53 unsigned long cr0;
60 u16 fsw, fcw; 54 u16 fsw, fcw;
@@ -65,18 +59,25 @@ static void fpu__init_system_early_generic(struct cpuinfo_x86 *c)
65 cr0 &= ~(X86_CR0_TS | X86_CR0_EM); 59 cr0 &= ~(X86_CR0_TS | X86_CR0_EM);
66 write_cr0(cr0); 60 write_cr0(cr0);
67 61
68 if (!test_bit(X86_FEATURE_FPU, (unsigned long *)cpu_caps_cleared)) { 62 asm volatile("fninit ; fnstsw %0 ; fnstcw %1" : "+m" (fsw), "+m" (fcw));
69 asm volatile("fninit ; fnstsw %0 ; fnstcw %1" 63
70 : "+m" (fsw), "+m" (fcw)); 64 pr_info("x86/fpu: Probing for FPU: FSW=0x%04hx FCW=0x%04hx\n", fsw, fcw);
71 65
72 if (fsw == 0 && (fcw & 0x103f) == 0x003f) 66 return fsw == 0 && (fcw & 0x103f) == 0x003f;
73 set_cpu_cap(c, X86_FEATURE_FPU); 67}
68
69static void fpu__init_system_early_generic(struct cpuinfo_x86 *c)
70{
71 if (!boot_cpu_has(X86_FEATURE_CPUID) &&
72 !test_bit(X86_FEATURE_FPU, (unsigned long *)cpu_caps_cleared)) {
73 if (fpu__probe_without_cpuid())
74 setup_force_cpu_cap(X86_FEATURE_FPU);
74 else 75 else
75 clear_cpu_cap(c, X86_FEATURE_FPU); 76 setup_clear_cpu_cap(X86_FEATURE_FPU);
76 } 77 }
77 78
78#ifndef CONFIG_MATH_EMULATION 79#ifndef CONFIG_MATH_EMULATION
79 if (!boot_cpu_has(X86_FEATURE_FPU)) { 80 if (!test_cpu_cap(&boot_cpu_data, X86_FEATURE_FPU)) {
80 pr_emerg("x86/fpu: Giving up, no FPU found and no math emulation present\n"); 81 pr_emerg("x86/fpu: Giving up, no FPU found and no math emulation present\n");
81 for (;;) 82 for (;;)
82 asm volatile("hlt"); 83 asm volatile("hlt");
diff --git a/arch/x86/kernel/fpu/xstate.c b/arch/x86/kernel/fpu/xstate.c
index 35f7024aace5..c24ac1efb12d 100644
--- a/arch/x86/kernel/fpu/xstate.c
+++ b/arch/x86/kernel/fpu/xstate.c
@@ -706,8 +706,14 @@ void __init fpu__init_system_xstate(void)
706 WARN_ON_FPU(!on_boot_cpu); 706 WARN_ON_FPU(!on_boot_cpu);
707 on_boot_cpu = 0; 707 on_boot_cpu = 0;
708 708
709 if (!boot_cpu_has(X86_FEATURE_FPU)) {
710 pr_info("x86/fpu: No FPU detected\n");
711 return;
712 }
713
709 if (!boot_cpu_has(X86_FEATURE_XSAVE)) { 714 if (!boot_cpu_has(X86_FEATURE_XSAVE)) {
710 pr_info("x86/fpu: Legacy x87 FPU detected.\n"); 715 pr_info("x86/fpu: x87 FPU will use %s\n",
716 boot_cpu_has(X86_FEATURE_FXSR) ? "FXSAVE" : "FSAVE");
711 return; 717 return;
712 } 718 }
713 719