diff options
Diffstat (limited to 'arch/x86/kernel/cpu/common.c')
-rw-r--r-- | arch/x86/kernel/cpu/common.c | 74 |
1 files changed, 58 insertions, 16 deletions
diff --git a/arch/x86/kernel/cpu/common.c b/arch/x86/kernel/cpu/common.c index 652fdc9a757a..275e2cb43b91 100644 --- a/arch/x86/kernel/cpu/common.c +++ b/arch/x86/kernel/cpu/common.c | |||
@@ -224,6 +224,49 @@ static inline void squash_the_stupid_serial_number(struct cpuinfo_x86 *c) | |||
224 | #endif | 224 | #endif |
225 | 225 | ||
226 | /* | 226 | /* |
227 | * Some CPU features depend on higher CPUID levels, which may not always | ||
228 | * be available due to CPUID level capping or broken virtualization | ||
229 | * software. Add those features to this table to auto-disable them. | ||
230 | */ | ||
231 | struct cpuid_dependent_feature { | ||
232 | u32 feature; | ||
233 | u32 level; | ||
234 | }; | ||
235 | static const struct cpuid_dependent_feature __cpuinitconst | ||
236 | cpuid_dependent_features[] = { | ||
237 | { X86_FEATURE_MWAIT, 0x00000005 }, | ||
238 | { X86_FEATURE_DCA, 0x00000009 }, | ||
239 | { X86_FEATURE_XSAVE, 0x0000000d }, | ||
240 | { 0, 0 } | ||
241 | }; | ||
242 | |||
243 | static void __cpuinit filter_cpuid_features(struct cpuinfo_x86 *c, bool warn) | ||
244 | { | ||
245 | const struct cpuid_dependent_feature *df; | ||
246 | for (df = cpuid_dependent_features; df->feature; df++) { | ||
247 | /* | ||
248 | * Note: cpuid_level is set to -1 if unavailable, but | ||
249 | * extended_extended_level is set to 0 if unavailable | ||
250 | * and the legitimate extended levels are all negative | ||
251 | * when signed; hence the weird messing around with | ||
252 | * signs here... | ||
253 | */ | ||
254 | if (cpu_has(c, df->feature) && | ||
255 | ((s32)df->feature < 0 ? | ||
256 | (u32)df->feature > (u32)c->extended_cpuid_level : | ||
257 | (s32)df->feature > (s32)c->cpuid_level)) { | ||
258 | clear_cpu_cap(c, df->feature); | ||
259 | if (warn) | ||
260 | printk(KERN_WARNING | ||
261 | "CPU: CPU feature %s disabled " | ||
262 | "due to lack of CPUID level 0x%x\n", | ||
263 | x86_cap_flags[df->feature], | ||
264 | df->level); | ||
265 | } | ||
266 | } | ||
267 | } | ||
268 | |||
269 | /* | ||
227 | * Naming convention should be: <Name> [(<Codename>)] | 270 | * Naming convention should be: <Name> [(<Codename>)] |
228 | * This table only is used unless init_<vendor>() below doesn't set it; | 271 | * This table only is used unless init_<vendor>() below doesn't set it; |
229 | * in particular, if CPUID levels 0x80000002..4 are supported, this isn't used | 272 | * in particular, if CPUID levels 0x80000002..4 are supported, this isn't used |
@@ -586,11 +629,10 @@ static void __init early_identify_cpu(struct cpuinfo_x86 *c) | |||
586 | if (this_cpu->c_early_init) | 629 | if (this_cpu->c_early_init) |
587 | this_cpu->c_early_init(c); | 630 | this_cpu->c_early_init(c); |
588 | 631 | ||
589 | validate_pat_support(c); | ||
590 | |||
591 | #ifdef CONFIG_SMP | 632 | #ifdef CONFIG_SMP |
592 | c->cpu_index = boot_cpu_id; | 633 | c->cpu_index = boot_cpu_id; |
593 | #endif | 634 | #endif |
635 | filter_cpuid_features(c, false); | ||
594 | } | 636 | } |
595 | 637 | ||
596 | void __init early_cpu_init(void) | 638 | void __init early_cpu_init(void) |
@@ -724,6 +766,9 @@ static void __cpuinit identify_cpu(struct cpuinfo_x86 *c) | |||
724 | * we do "generic changes." | 766 | * we do "generic changes." |
725 | */ | 767 | */ |
726 | 768 | ||
769 | /* Filter out anything that depends on CPUID levels we don't have */ | ||
770 | filter_cpuid_features(c, true); | ||
771 | |||
727 | /* If the model name is still unset, do table lookup. */ | 772 | /* If the model name is still unset, do table lookup. */ |
728 | if (!c->x86_model_id[0]) { | 773 | if (!c->x86_model_id[0]) { |
729 | char *p; | 774 | char *p; |
@@ -1053,22 +1098,19 @@ void __cpuinit cpu_init(void) | |||
1053 | */ | 1098 | */ |
1054 | if (kgdb_connected && arch_kgdb_ops.correct_hw_break) | 1099 | if (kgdb_connected && arch_kgdb_ops.correct_hw_break) |
1055 | arch_kgdb_ops.correct_hw_break(); | 1100 | arch_kgdb_ops.correct_hw_break(); |
1056 | else { | 1101 | else |
1057 | #endif | 1102 | #endif |
1058 | /* | 1103 | { |
1059 | * Clear all 6 debug registers: | 1104 | /* |
1060 | */ | 1105 | * Clear all 6 debug registers: |
1061 | 1106 | */ | |
1062 | set_debugreg(0UL, 0); | 1107 | set_debugreg(0UL, 0); |
1063 | set_debugreg(0UL, 1); | 1108 | set_debugreg(0UL, 1); |
1064 | set_debugreg(0UL, 2); | 1109 | set_debugreg(0UL, 2); |
1065 | set_debugreg(0UL, 3); | 1110 | set_debugreg(0UL, 3); |
1066 | set_debugreg(0UL, 6); | 1111 | set_debugreg(0UL, 6); |
1067 | set_debugreg(0UL, 7); | 1112 | set_debugreg(0UL, 7); |
1068 | #ifdef CONFIG_KGDB | ||
1069 | /* If the kgdb is connected no debug regs should be altered. */ | ||
1070 | } | 1113 | } |
1071 | #endif | ||
1072 | 1114 | ||
1073 | fpu_init(); | 1115 | fpu_init(); |
1074 | 1116 | ||