aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
Diffstat (limited to 'arch/x86/kernel/cpu/microcode/intel.c')
-rw-r--r--arch/x86/kernel/cpu/microcode/intel.c43
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 */
43static int llc_size_per_core;
44
42static unsigned long mc_saved_in_initrd[MAX_UCODE_COUNT]; 45static unsigned long mc_saved_in_initrd[MAX_UCODE_COUNT];
43static struct mc_saved_data { 46static 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
996static 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
993static enum ucode_state request_microcode_fw(int cpu, struct device *device, 1019static 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)
1022static enum ucode_state 1051static enum ucode_state
1023request_microcode_user(int cpu, const void __user *buf, size_t size) 1052request_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
1076static 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
1044struct microcode_ops * __init init_intel_microcode(void) 1085struct 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 &microcode_intel_ops; 1097 return &microcode_intel_ops;
1055} 1098}
1056 1099