diff options
| -rw-r--r-- | arch/x86/include/asm/cpufeatures.h | 2 | ||||
| -rw-r--r-- | arch/x86/include/asm/fpu/internal.h | 10 | ||||
| -rw-r--r-- | arch/x86/kernel/cpu/common.c | 34 | ||||
| -rw-r--r-- | arch/x86/kernel/fpu/core.c | 9 | ||||
| -rw-r--r-- | arch/x86/kernel/fpu/init.c | 29 | ||||
| -rw-r--r-- | arch/x86/kernel/fpu/xstate.c | 8 |
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 |
| 88 | static inline void fpstate_init_soft(struct swregs_state *soft) {} | 88 | static inline void fpstate_init_soft(struct swregs_state *soft) {} |
| 89 | #endif | 89 | #endif |
| 90 | |||
| 91 | static 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 | |||
| 90 | static inline void fpstate_init_fxstate(struct fxregs_state *fx) | 100 | static 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 | ||
| 662 | static 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 | |||
| 662 | void get_cpu_cap(struct cpuinfo_x86 *c) | 672 | void 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 | ||
| 757 | static void identify_cpu_without_cpuid(struct cpuinfo_x86 *c) | 774 | 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 | 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 | /* | 51 | static 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 | */ | ||
| 57 | static 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 | |||
| 69 | static 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 | ||
