diff options
Diffstat (limited to 'arch/x86/kernel/cpu/microcode/intel.c')
-rw-r--r-- | arch/x86/kernel/cpu/microcode/intel.c | 43 |
1 files changed, 43 insertions, 0 deletions
diff --git a/arch/x86/kernel/cpu/microcode/intel.c b/arch/x86/kernel/cpu/microcode/intel.c index ac8975a65280..2f38a99cdb98 100644 --- a/arch/x86/kernel/cpu/microcode/intel.c +++ b/arch/x86/kernel/cpu/microcode/intel.c | |||
@@ -39,6 +39,9 @@ | |||
39 | #include <asm/setup.h> | 39 | #include <asm/setup.h> |
40 | #include <asm/msr.h> | 40 | #include <asm/msr.h> |
41 | 41 | ||
42 | /* last level cache size per core */ | ||
43 | static int llc_size_per_core; | ||
44 | |||
42 | static unsigned long mc_saved_in_initrd[MAX_UCODE_COUNT]; | 45 | static unsigned long mc_saved_in_initrd[MAX_UCODE_COUNT]; |
43 | static struct mc_saved_data { | 46 | static struct mc_saved_data { |
44 | unsigned int mc_saved_count; | 47 | unsigned int mc_saved_count; |
@@ -990,6 +993,29 @@ static int get_ucode_fw(void *to, const void *from, size_t n) | |||
990 | return 0; | 993 | return 0; |
991 | } | 994 | } |
992 | 995 | ||
996 | static bool is_blacklisted(unsigned int cpu) | ||
997 | { | ||
998 | struct cpuinfo_x86 *c = &cpu_data(cpu); | ||
999 | |||
1000 | /* | ||
1001 | * Late loading on model 79 with microcode revision less than 0x0b000021 | ||
1002 | * and LLC size per core bigger than 2.5MB may result in a system hang. | ||
1003 | * This behavior is documented in item BDF90, #334165 (Intel Xeon | ||
1004 | * Processor E7-8800/4800 v4 Product Family). | ||
1005 | */ | ||
1006 | if (c->x86 == 6 && | ||
1007 | c->x86_model == 79 && | ||
1008 | c->x86_mask == 0x01 && | ||
1009 | llc_size_per_core > 2621440 && | ||
1010 | c->microcode < 0x0b000021) { | ||
1011 | pr_err_once("Erratum BDF90: late loading with revision < 0x0b000021 (0x%x) disabled.\n", c->microcode); | ||
1012 | pr_err_once("Please consider either early loading through initrd/built-in or a potential BIOS update.\n"); | ||
1013 | return true; | ||
1014 | } | ||
1015 | |||
1016 | return false; | ||
1017 | } | ||
1018 | |||
993 | static enum ucode_state request_microcode_fw(int cpu, struct device *device, | 1019 | static enum ucode_state request_microcode_fw(int cpu, struct device *device, |
994 | bool refresh_fw) | 1020 | bool refresh_fw) |
995 | { | 1021 | { |
@@ -998,6 +1024,9 @@ static enum ucode_state request_microcode_fw(int cpu, struct device *device, | |||
998 | const struct firmware *firmware; | 1024 | const struct firmware *firmware; |
999 | enum ucode_state ret; | 1025 | enum ucode_state ret; |
1000 | 1026 | ||
1027 | if (is_blacklisted(cpu)) | ||
1028 | return UCODE_NFOUND; | ||
1029 | |||
1001 | sprintf(name, "intel-ucode/%02x-%02x-%02x", | 1030 | sprintf(name, "intel-ucode/%02x-%02x-%02x", |
1002 | c->x86, c->x86_model, c->x86_mask); | 1031 | c->x86, c->x86_model, c->x86_mask); |
1003 | 1032 | ||
@@ -1022,6 +1051,9 @@ static int get_ucode_user(void *to, const void *from, size_t n) | |||
1022 | static enum ucode_state | 1051 | static enum ucode_state |
1023 | request_microcode_user(int cpu, const void __user *buf, size_t size) | 1052 | request_microcode_user(int cpu, const void __user *buf, size_t size) |
1024 | { | 1053 | { |
1054 | if (is_blacklisted(cpu)) | ||
1055 | return UCODE_NFOUND; | ||
1056 | |||
1025 | return generic_load_microcode(cpu, (void *)buf, size, &get_ucode_user); | 1057 | return generic_load_microcode(cpu, (void *)buf, size, &get_ucode_user); |
1026 | } | 1058 | } |
1027 | 1059 | ||
@@ -1041,6 +1073,15 @@ static struct microcode_ops microcode_intel_ops = { | |||
1041 | .microcode_fini_cpu = microcode_fini_cpu, | 1073 | .microcode_fini_cpu = microcode_fini_cpu, |
1042 | }; | 1074 | }; |
1043 | 1075 | ||
1076 | static int __init calc_llc_size_per_core(struct cpuinfo_x86 *c) | ||
1077 | { | ||
1078 | u64 llc_size = c->x86_cache_size * 1024ULL; | ||
1079 | |||
1080 | do_div(llc_size, c->x86_max_cores); | ||
1081 | |||
1082 | return (int)llc_size; | ||
1083 | } | ||
1084 | |||
1044 | struct microcode_ops * __init init_intel_microcode(void) | 1085 | struct microcode_ops * __init init_intel_microcode(void) |
1045 | { | 1086 | { |
1046 | struct cpuinfo_x86 *c = &boot_cpu_data; | 1087 | struct cpuinfo_x86 *c = &boot_cpu_data; |
@@ -1051,6 +1092,8 @@ struct microcode_ops * __init init_intel_microcode(void) | |||
1051 | return NULL; | 1092 | return NULL; |
1052 | } | 1093 | } |
1053 | 1094 | ||
1095 | llc_size_per_core = calc_llc_size_per_core(c); | ||
1096 | |||
1054 | return µcode_intel_ops; | 1097 | return µcode_intel_ops; |
1055 | } | 1098 | } |
1056 | 1099 | ||