Commit efebca0b authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'x86_microcode_for_v6.3_rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip

Pull x86 microcode loader updates from Borislav Petkov:

 - Fix mixed steppings support on AMD which got broken somewhere along
   the way

 - Improve revision reporting

 - Properly check CPUID capabilities after late microcode upgrade to
   avoid false positives

 - A garden variety of other small fixes

* tag 'x86_microcode_for_v6.3_rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip:
  x86/microcode/core: Return an error only when necessary
  x86/microcode/AMD: Fix mixed steppings support
  x86/microcode/AMD: Add a @cpu parameter to the reloading functions
  x86/microcode/amd: Remove load_microcode_amd()'s bsp parameter
  x86/microcode: Allow only "1" as a late reload trigger value
  x86/microcode/intel: Print old and new revision during early boot
  x86/microcode/intel: Pass the microcode revision to print_ucode_info() directly
  x86/microcode: Adjust late loading result reporting message
  x86/microcode: Check CPU capabilities after late microcode update correctly
  x86/microcode: Add a parameter to microcode_check() to store CPU capabilities
  x86/microcode: Use the DEVICE_ATTR_RO() macro
  x86/microcode/AMD: Handle multiple glued containers properly
  x86/microcode/AMD: Rename a couple of functions
parents aa8c3db4 f33e0c89
...@@ -125,13 +125,13 @@ static inline unsigned int x86_cpuid_family(void) ...@@ -125,13 +125,13 @@ static inline unsigned int x86_cpuid_family(void)
#ifdef CONFIG_MICROCODE #ifdef CONFIG_MICROCODE
extern void __init load_ucode_bsp(void); extern void __init load_ucode_bsp(void);
extern void load_ucode_ap(void); extern void load_ucode_ap(void);
void reload_early_microcode(void); void reload_early_microcode(unsigned int cpu);
extern bool initrd_gone; extern bool initrd_gone;
void microcode_bsp_resume(void); void microcode_bsp_resume(void);
#else #else
static inline void __init load_ucode_bsp(void) { } static inline void __init load_ucode_bsp(void) { }
static inline void load_ucode_ap(void) { } static inline void load_ucode_ap(void) { }
static inline void reload_early_microcode(void) { } static inline void reload_early_microcode(unsigned int cpu) { }
static inline void microcode_bsp_resume(void) { } static inline void microcode_bsp_resume(void) { }
#endif #endif
......
...@@ -47,12 +47,12 @@ struct microcode_amd { ...@@ -47,12 +47,12 @@ struct microcode_amd {
extern void __init load_ucode_amd_bsp(unsigned int family); extern void __init load_ucode_amd_bsp(unsigned int family);
extern void load_ucode_amd_ap(unsigned int family); extern void load_ucode_amd_ap(unsigned int family);
extern int __init save_microcode_in_initrd_amd(unsigned int family); extern int __init save_microcode_in_initrd_amd(unsigned int family);
void reload_ucode_amd(void); void reload_ucode_amd(unsigned int cpu);
#else #else
static inline void __init load_ucode_amd_bsp(unsigned int family) {} static inline void __init load_ucode_amd_bsp(unsigned int family) {}
static inline void load_ucode_amd_ap(unsigned int family) {} static inline void load_ucode_amd_ap(unsigned int family) {}
static inline int __init static inline int __init
save_microcode_in_initrd_amd(unsigned int family) { return -EINVAL; } save_microcode_in_initrd_amd(unsigned int family) { return -EINVAL; }
static inline void reload_ucode_amd(void) {} static inline void reload_ucode_amd(unsigned int cpu) {}
#endif #endif
#endif /* _ASM_X86_MICROCODE_AMD_H */ #endif /* _ASM_X86_MICROCODE_AMD_H */
...@@ -697,7 +697,8 @@ bool xen_set_default_idle(void); ...@@ -697,7 +697,8 @@ bool xen_set_default_idle(void);
#endif #endif
void __noreturn stop_this_cpu(void *dummy); void __noreturn stop_this_cpu(void *dummy);
void microcode_check(void); void microcode_check(struct cpuinfo_x86 *prev_info);
void store_cpu_caps(struct cpuinfo_x86 *info);
enum l1tf_mitigations { enum l1tf_mitigations {
L1TF_MITIGATION_OFF, L1TF_MITIGATION_OFF,
......
...@@ -2302,30 +2302,45 @@ void cpu_init_secondary(void) ...@@ -2302,30 +2302,45 @@ void cpu_init_secondary(void)
#endif #endif
#ifdef CONFIG_MICROCODE_LATE_LOADING #ifdef CONFIG_MICROCODE_LATE_LOADING
/* /**
* store_cpu_caps() - Store a snapshot of CPU capabilities
* @curr_info: Pointer where to store it
*
* Returns: None
*/
void store_cpu_caps(struct cpuinfo_x86 *curr_info)
{
/* Reload CPUID max function as it might've changed. */
curr_info->cpuid_level = cpuid_eax(0);
/* Copy all capability leafs and pick up the synthetic ones. */
memcpy(&curr_info->x86_capability, &boot_cpu_data.x86_capability,
sizeof(curr_info->x86_capability));
/* Get the hardware CPUID leafs */
get_cpu_cap(curr_info);
}
/**
* microcode_check() - Check if any CPU capabilities changed after an update.
* @prev_info: CPU capabilities stored before an update.
*
* The microcode loader calls this upon late microcode load to recheck features, * The microcode loader calls this upon late microcode load to recheck features,
* only when microcode has been updated. Caller holds microcode_mutex and CPU * only when microcode has been updated. Caller holds microcode_mutex and CPU
* hotplug lock. * hotplug lock.
*
* Return: None
*/ */
void microcode_check(void) void microcode_check(struct cpuinfo_x86 *prev_info)
{ {
struct cpuinfo_x86 info; struct cpuinfo_x86 curr_info;
perf_check_microcode(); perf_check_microcode();
/* Reload CPUID max function as it might've changed. */ store_cpu_caps(&curr_info);
info.cpuid_level = cpuid_eax(0);
/*
* Copy all capability leafs to pick up the synthetic ones so that
* memcmp() below doesn't fail on that. The ones coming from CPUID will
* get overwritten in get_cpu_cap().
*/
memcpy(&info.x86_capability, &boot_cpu_data.x86_capability, sizeof(info.x86_capability));
get_cpu_cap(&info);
if (!memcmp(&info.x86_capability, &boot_cpu_data.x86_capability, sizeof(info.x86_capability))) if (!memcmp(&prev_info->x86_capability, &curr_info.x86_capability,
sizeof(prev_info->x86_capability)))
return; return;
pr_warn("x86/CPU: CPU features have changed after loading microcode, but might not take effect.\n"); pr_warn("x86/CPU: CPU features have changed after loading microcode, but might not take effect.\n");
......
...@@ -55,7 +55,9 @@ struct cont_desc { ...@@ -55,7 +55,9 @@ struct cont_desc {
}; };
static u32 ucode_new_rev; static u32 ucode_new_rev;
static u8 amd_ucode_patch[PATCH_MAX_SIZE];
/* One blob per node. */
static u8 amd_ucode_patch[MAX_NUMNODES][PATCH_MAX_SIZE];
/* /*
* Microcode patch container file is prepended to the initrd in cpio * Microcode patch container file is prepended to the initrd in cpio
...@@ -330,8 +332,9 @@ static size_t parse_container(u8 *ucode, size_t size, struct cont_desc *desc) ...@@ -330,8 +332,9 @@ static size_t parse_container(u8 *ucode, size_t size, struct cont_desc *desc)
ret = verify_patch(x86_family(desc->cpuid_1_eax), buf, size, &patch_size, true); ret = verify_patch(x86_family(desc->cpuid_1_eax), buf, size, &patch_size, true);
if (ret < 0) { if (ret < 0) {
/* /*
* Patch verification failed, skip to the next * Patch verification failed, skip to the next container, if
* container, if there's one: * there is one. Before exit, check whether that container has
* found a patch already. If so, use it.
*/ */
goto out; goto out;
} else if (ret > 0) { } else if (ret > 0) {
...@@ -350,6 +353,7 @@ static size_t parse_container(u8 *ucode, size_t size, struct cont_desc *desc) ...@@ -350,6 +353,7 @@ static size_t parse_container(u8 *ucode, size_t size, struct cont_desc *desc)
size -= patch_size + SECTION_HDR_SIZE; size -= patch_size + SECTION_HDR_SIZE;
} }
out:
/* /*
* If we have found a patch (desc->mc), it means we're looking at the * If we have found a patch (desc->mc), it means we're looking at the
* container which has a patch for this CPU so return 0 to mean, @ucode * container which has a patch for this CPU so return 0 to mean, @ucode
...@@ -364,7 +368,6 @@ static size_t parse_container(u8 *ucode, size_t size, struct cont_desc *desc) ...@@ -364,7 +368,6 @@ static size_t parse_container(u8 *ucode, size_t size, struct cont_desc *desc)
return 0; return 0;
} }
out:
return orig_size - size; return orig_size - size;
} }
...@@ -414,8 +417,7 @@ static int __apply_microcode_amd(struct microcode_amd *mc) ...@@ -414,8 +417,7 @@ static int __apply_microcode_amd(struct microcode_amd *mc)
* *
* Returns true if container found (sets @desc), false otherwise. * Returns true if container found (sets @desc), false otherwise.
*/ */
static bool static bool early_apply_microcode(u32 cpuid_1_eax, void *ucode, size_t size, bool save_patch)
apply_microcode_early_amd(u32 cpuid_1_eax, void *ucode, size_t size, bool save_patch)
{ {
struct cont_desc desc = { 0 }; struct cont_desc desc = { 0 };
u8 (*patch)[PATCH_MAX_SIZE]; u8 (*patch)[PATCH_MAX_SIZE];
...@@ -428,7 +430,7 @@ apply_microcode_early_amd(u32 cpuid_1_eax, void *ucode, size_t size, bool save_p ...@@ -428,7 +430,7 @@ apply_microcode_early_amd(u32 cpuid_1_eax, void *ucode, size_t size, bool save_p
patch = (u8 (*)[PATCH_MAX_SIZE])__pa_nodebug(&amd_ucode_patch); patch = (u8 (*)[PATCH_MAX_SIZE])__pa_nodebug(&amd_ucode_patch);
#else #else
new_rev = &ucode_new_rev; new_rev = &ucode_new_rev;
patch = &amd_ucode_patch; patch = &amd_ucode_patch[0];
#endif #endif
desc.cpuid_1_eax = cpuid_1_eax; desc.cpuid_1_eax = cpuid_1_eax;
...@@ -481,7 +483,7 @@ static bool get_builtin_microcode(struct cpio_data *cp, unsigned int family) ...@@ -481,7 +483,7 @@ static bool get_builtin_microcode(struct cpio_data *cp, unsigned int family)
return false; return false;
} }
static void __load_ucode_amd(unsigned int cpuid_1_eax, struct cpio_data *ret) static void find_blobs_in_containers(unsigned int cpuid_1_eax, struct cpio_data *ret)
{ {
struct ucode_cpu_info *uci; struct ucode_cpu_info *uci;
struct cpio_data cp; struct cpio_data cp;
...@@ -511,11 +513,11 @@ void __init load_ucode_amd_bsp(unsigned int cpuid_1_eax) ...@@ -511,11 +513,11 @@ void __init load_ucode_amd_bsp(unsigned int cpuid_1_eax)
{ {
struct cpio_data cp = { }; struct cpio_data cp = { };
__load_ucode_amd(cpuid_1_eax, &cp); find_blobs_in_containers(cpuid_1_eax, &cp);
if (!(cp.data && cp.size)) if (!(cp.data && cp.size))
return; return;
apply_microcode_early_amd(cpuid_1_eax, cp.data, cp.size, true); early_apply_microcode(cpuid_1_eax, cp.data, cp.size, true);
} }
void load_ucode_amd_ap(unsigned int cpuid_1_eax) void load_ucode_amd_ap(unsigned int cpuid_1_eax)
...@@ -546,15 +548,14 @@ void load_ucode_amd_ap(unsigned int cpuid_1_eax) ...@@ -546,15 +548,14 @@ void load_ucode_amd_ap(unsigned int cpuid_1_eax)
} }
} }
__load_ucode_amd(cpuid_1_eax, &cp); find_blobs_in_containers(cpuid_1_eax, &cp);
if (!(cp.data && cp.size)) if (!(cp.data && cp.size))
return; return;
apply_microcode_early_amd(cpuid_1_eax, cp.data, cp.size, false); early_apply_microcode(cpuid_1_eax, cp.data, cp.size, false);
} }
static enum ucode_state static enum ucode_state load_microcode_amd(u8 family, const u8 *data, size_t size);
load_microcode_amd(bool save, u8 family, const u8 *data, size_t size);
int __init save_microcode_in_initrd_amd(unsigned int cpuid_1_eax) int __init save_microcode_in_initrd_amd(unsigned int cpuid_1_eax)
{ {
...@@ -572,19 +573,19 @@ int __init save_microcode_in_initrd_amd(unsigned int cpuid_1_eax) ...@@ -572,19 +573,19 @@ int __init save_microcode_in_initrd_amd(unsigned int cpuid_1_eax)
if (!desc.mc) if (!desc.mc)
return -EINVAL; return -EINVAL;
ret = load_microcode_amd(true, x86_family(cpuid_1_eax), desc.data, desc.size); ret = load_microcode_amd(x86_family(cpuid_1_eax), desc.data, desc.size);
if (ret > UCODE_UPDATED) if (ret > UCODE_UPDATED)
return -EINVAL; return -EINVAL;
return 0; return 0;
} }
void reload_ucode_amd(void) void reload_ucode_amd(unsigned int cpu)
{ {
struct microcode_amd *mc;
u32 rev, dummy __always_unused; u32 rev, dummy __always_unused;
struct microcode_amd *mc;
mc = (struct microcode_amd *)amd_ucode_patch; mc = (struct microcode_amd *)amd_ucode_patch[cpu_to_node(cpu)];
rdmsr(MSR_AMD64_PATCH_LEVEL, rev, dummy); rdmsr(MSR_AMD64_PATCH_LEVEL, rev, dummy);
...@@ -816,6 +817,7 @@ static int verify_and_add_patch(u8 family, u8 *fw, unsigned int leftover, ...@@ -816,6 +817,7 @@ static int verify_and_add_patch(u8 family, u8 *fw, unsigned int leftover,
return 0; return 0;
} }
/* Scan the blob in @data and add microcode patches to the cache. */
static enum ucode_state __load_microcode_amd(u8 family, const u8 *data, static enum ucode_state __load_microcode_amd(u8 family, const u8 *data,
size_t size) size_t size)
{ {
...@@ -850,9 +852,10 @@ static enum ucode_state __load_microcode_amd(u8 family, const u8 *data, ...@@ -850,9 +852,10 @@ static enum ucode_state __load_microcode_amd(u8 family, const u8 *data,
return UCODE_OK; return UCODE_OK;
} }
static enum ucode_state static enum ucode_state load_microcode_amd(u8 family, const u8 *data, size_t size)
load_microcode_amd(bool save, u8 family, const u8 *data, size_t size)
{ {
struct cpuinfo_x86 *c;
unsigned int nid, cpu;
struct ucode_patch *p; struct ucode_patch *p;
enum ucode_state ret; enum ucode_state ret;
...@@ -865,22 +868,22 @@ load_microcode_amd(bool save, u8 family, const u8 *data, size_t size) ...@@ -865,22 +868,22 @@ load_microcode_amd(bool save, u8 family, const u8 *data, size_t size)
return ret; return ret;
} }
p = find_patch(0); for_each_node(nid) {
if (!p) { cpu = cpumask_first(cpumask_of_node(nid));
return ret; c = &cpu_data(cpu);
} else {
if (boot_cpu_data.microcode >= p->patch_id)
return ret;
ret = UCODE_NEW; p = find_patch(cpu);
} if (!p)
continue;
/* save BSP's matching patch for early load */ if (c->microcode >= p->patch_id)
if (!save) continue;
return ret;
memset(amd_ucode_patch, 0, PATCH_MAX_SIZE); ret = UCODE_NEW;
memcpy(amd_ucode_patch, p->data, min_t(u32, p->size, PATCH_MAX_SIZE));
memset(&amd_ucode_patch[nid], 0, PATCH_MAX_SIZE);
memcpy(&amd_ucode_patch[nid], p->data, min_t(u32, p->size, PATCH_MAX_SIZE));
}
return ret; return ret;
} }
...@@ -905,14 +908,9 @@ static enum ucode_state request_microcode_amd(int cpu, struct device *device) ...@@ -905,14 +908,9 @@ static enum ucode_state request_microcode_amd(int cpu, struct device *device)
{ {
char fw_name[36] = "amd-ucode/microcode_amd.bin"; char fw_name[36] = "amd-ucode/microcode_amd.bin";
struct cpuinfo_x86 *c = &cpu_data(cpu); struct cpuinfo_x86 *c = &cpu_data(cpu);
bool bsp = c->cpu_index == boot_cpu_data.cpu_index;
enum ucode_state ret = UCODE_NFOUND; enum ucode_state ret = UCODE_NFOUND;
const struct firmware *fw; const struct firmware *fw;
/* reload ucode container only on the boot cpu */
if (!bsp)
return UCODE_OK;
if (c->x86 >= 0x15) if (c->x86 >= 0x15)
snprintf(fw_name, sizeof(fw_name), "amd-ucode/microcode_amd_fam%.2xh.bin", c->x86); snprintf(fw_name, sizeof(fw_name), "amd-ucode/microcode_amd_fam%.2xh.bin", c->x86);
...@@ -925,7 +923,7 @@ static enum ucode_state request_microcode_amd(int cpu, struct device *device) ...@@ -925,7 +923,7 @@ static enum ucode_state request_microcode_amd(int cpu, struct device *device)
if (!verify_container(fw->data, fw->size, false)) if (!verify_container(fw->data, fw->size, false))
goto fw_release; goto fw_release;
ret = load_microcode_amd(bsp, c->x86, fw->data, fw->size); ret = load_microcode_amd(c->x86, fw->data, fw->size);
fw_release: fw_release:
release_firmware(fw); release_firmware(fw);
......
...@@ -298,7 +298,7 @@ struct cpio_data find_microcode_in_initrd(const char *path, bool use_pa) ...@@ -298,7 +298,7 @@ struct cpio_data find_microcode_in_initrd(const char *path, bool use_pa)
#endif #endif
} }
void reload_early_microcode(void) void reload_early_microcode(unsigned int cpu)
{ {
int vendor, family; int vendor, family;
...@@ -312,7 +312,7 @@ void reload_early_microcode(void) ...@@ -312,7 +312,7 @@ void reload_early_microcode(void)
break; break;
case X86_VENDOR_AMD: case X86_VENDOR_AMD:
if (family >= 0x10) if (family >= 0x10)
reload_ucode_amd(); reload_ucode_amd(cpu);
break; break;
default: default:
break; break;
...@@ -409,11 +409,11 @@ static int __reload_late(void *info) ...@@ -409,11 +409,11 @@ static int __reload_late(void *info)
goto wait_for_siblings; goto wait_for_siblings;
if (err >= UCODE_NFOUND) { if (err >= UCODE_NFOUND) {
if (err == UCODE_ERROR) if (err == UCODE_ERROR) {
pr_warn("Error reloading microcode on CPU %d\n", cpu); pr_warn("Error reloading microcode on CPU %d\n", cpu);
ret = -1; ret = -1;
} }
}
wait_for_siblings: wait_for_siblings:
if (__wait_for_cpus(&late_cpus_out, NSEC_PER_SEC)) if (__wait_for_cpus(&late_cpus_out, NSEC_PER_SEC))
...@@ -438,6 +438,7 @@ static int __reload_late(void *info) ...@@ -438,6 +438,7 @@ static int __reload_late(void *info)
static int microcode_reload_late(void) static int microcode_reload_late(void)
{ {
int old = boot_cpu_data.microcode, ret; int old = boot_cpu_data.microcode, ret;
struct cpuinfo_x86 prev_info;
pr_err("Attempting late microcode loading - it is dangerous and taints the kernel.\n"); pr_err("Attempting late microcode loading - it is dangerous and taints the kernel.\n");
pr_err("You should switch to early loading, if possible.\n"); pr_err("You should switch to early loading, if possible.\n");
...@@ -445,12 +446,21 @@ static int microcode_reload_late(void) ...@@ -445,12 +446,21 @@ static int microcode_reload_late(void)
atomic_set(&late_cpus_in, 0); atomic_set(&late_cpus_in, 0);
atomic_set(&late_cpus_out, 0); atomic_set(&late_cpus_out, 0);
ret = stop_machine_cpuslocked(__reload_late, NULL, cpu_online_mask); /*
if (ret == 0) * Take a snapshot before the microcode update in order to compare and
microcode_check(); * check whether any bits changed after an update.
*/
store_cpu_caps(&prev_info);
pr_info("Reload completed, microcode revision: 0x%x -> 0x%x\n", ret = stop_machine_cpuslocked(__reload_late, NULL, cpu_online_mask);
if (!ret) {
pr_info("Reload succeeded, microcode revision: 0x%x -> 0x%x\n",
old, boot_cpu_data.microcode); old, boot_cpu_data.microcode);
microcode_check(&prev_info);
} else {
pr_info("Reload failed, current microcode revision: 0x%x\n",
boot_cpu_data.microcode);
}
return ret; return ret;
} }
...@@ -465,11 +475,8 @@ static ssize_t reload_store(struct device *dev, ...@@ -465,11 +475,8 @@ static ssize_t reload_store(struct device *dev,
ssize_t ret = 0; ssize_t ret = 0;
ret = kstrtoul(buf, 0, &val); ret = kstrtoul(buf, 0, &val);
if (ret) if (ret || val != 1)
return ret; return -EINVAL;
if (val != 1)
return size;
cpus_read_lock(); cpus_read_lock();
...@@ -507,7 +514,7 @@ static ssize_t version_show(struct device *dev, ...@@ -507,7 +514,7 @@ static ssize_t version_show(struct device *dev,
return sprintf(buf, "0x%x\n", uci->cpu_sig.rev); return sprintf(buf, "0x%x\n", uci->cpu_sig.rev);
} }
static ssize_t pf_show(struct device *dev, static ssize_t processor_flags_show(struct device *dev,
struct device_attribute *attr, char *buf) struct device_attribute *attr, char *buf)
{ {
struct ucode_cpu_info *uci = ucode_cpu_info + dev->id; struct ucode_cpu_info *uci = ucode_cpu_info + dev->id;
...@@ -515,8 +522,8 @@ static ssize_t pf_show(struct device *dev, ...@@ -515,8 +522,8 @@ static ssize_t pf_show(struct device *dev,
return sprintf(buf, "0x%x\n", uci->cpu_sig.pf); return sprintf(buf, "0x%x\n", uci->cpu_sig.pf);
} }
static DEVICE_ATTR(version, 0444, version_show, NULL); static DEVICE_ATTR_RO(version);
static DEVICE_ATTR(processor_flags, 0444, pf_show, NULL); static DEVICE_ATTR_RO(processor_flags);
static struct attribute *mc_default_attrs[] = { static struct attribute *mc_default_attrs[] = {
&dev_attr_version.attr, &dev_attr_version.attr,
...@@ -557,7 +564,7 @@ void microcode_bsp_resume(void) ...@@ -557,7 +564,7 @@ void microcode_bsp_resume(void)
if (uci->mc) if (uci->mc)
microcode_ops->apply_microcode(cpu); microcode_ops->apply_microcode(cpu);
else else
reload_early_microcode(); reload_early_microcode(cpu);
} }
static struct syscore_ops mc_syscore_ops = { static struct syscore_ops mc_syscore_ops = {
......
...@@ -305,14 +305,11 @@ static bool load_builtin_intel_microcode(struct cpio_data *cp) ...@@ -305,14 +305,11 @@ static bool load_builtin_intel_microcode(struct cpio_data *cp)
return false; return false;
} }
/* static void print_ucode_info(int old_rev, int new_rev, unsigned int date)
* Print ucode update info.
*/
static void
print_ucode_info(struct ucode_cpu_info *uci, unsigned int date)
{ {
pr_info_once("microcode updated early to revision 0x%x, date = %04x-%02x-%02x\n", pr_info_once("updated early: 0x%x -> 0x%x, date = %04x-%02x-%02x\n",
uci->cpu_sig.rev, old_rev,
new_rev,
date & 0xffff, date & 0xffff,
date >> 24, date >> 24,
(date >> 16) & 0xff); (date >> 16) & 0xff);
...@@ -322,6 +319,7 @@ print_ucode_info(struct ucode_cpu_info *uci, unsigned int date) ...@@ -322,6 +319,7 @@ print_ucode_info(struct ucode_cpu_info *uci, unsigned int date)
static int delay_ucode_info; static int delay_ucode_info;
static int current_mc_date; static int current_mc_date;
static int early_old_rev;
/* /*
* Print early updated ucode info after printk works. This is delayed info dump. * Print early updated ucode info after printk works. This is delayed info dump.
...@@ -332,7 +330,7 @@ void show_ucode_info_early(void) ...@@ -332,7 +330,7 @@ void show_ucode_info_early(void)
if (delay_ucode_info) { if (delay_ucode_info) {
intel_cpu_collect_info(&uci); intel_cpu_collect_info(&uci);
print_ucode_info(&uci, current_mc_date); print_ucode_info(early_old_rev, uci.cpu_sig.rev, current_mc_date);
delay_ucode_info = 0; delay_ucode_info = 0;
} }
} }
...@@ -341,40 +339,32 @@ void show_ucode_info_early(void) ...@@ -341,40 +339,32 @@ void show_ucode_info_early(void)
* At this point, we can not call printk() yet. Delay printing microcode info in * At this point, we can not call printk() yet. Delay printing microcode info in
* show_ucode_info_early() until printk() works. * show_ucode_info_early() until printk() works.
*/ */
static void print_ucode(struct ucode_cpu_info *uci) static void print_ucode(int old_rev, int new_rev, int date)
{ {
struct microcode_intel *mc;
int *delay_ucode_info_p; int *delay_ucode_info_p;
int *current_mc_date_p; int *current_mc_date_p;
int *early_old_rev_p;
mc = uci->mc;
if (!mc)
return;
delay_ucode_info_p = (int *)__pa_nodebug(&delay_ucode_info); delay_ucode_info_p = (int *)__pa_nodebug(&delay_ucode_info);
current_mc_date_p = (int *)__pa_nodebug(&current_mc_date); current_mc_date_p = (int *)__pa_nodebug(&current_mc_date);
early_old_rev_p = (int *)__pa_nodebug(&early_old_rev);
*delay_ucode_info_p = 1; *delay_ucode_info_p = 1;
*current_mc_date_p = mc->hdr.date; *current_mc_date_p = date;
*early_old_rev_p = old_rev;
} }
#else #else
static inline void print_ucode(struct ucode_cpu_info *uci) static inline void print_ucode(int old_rev, int new_rev, int date)
{ {
struct microcode_intel *mc; print_ucode_info(old_rev, new_rev, date);
mc = uci->mc;
if (!mc)
return;
print_ucode_info(uci, mc->hdr.date);
} }
#endif #endif
static int apply_microcode_early(struct ucode_cpu_info *uci, bool early) static int apply_microcode_early(struct ucode_cpu_info *uci, bool early)
{ {
struct microcode_intel *mc; struct microcode_intel *mc;
u32 rev; u32 rev, old_rev;
mc = uci->mc; mc = uci->mc;
if (!mc) if (!mc)
...@@ -391,6 +381,8 @@ static int apply_microcode_early(struct ucode_cpu_info *uci, bool early) ...@@ -391,6 +381,8 @@ static int apply_microcode_early(struct ucode_cpu_info *uci, bool early)
return UCODE_OK; return UCODE_OK;
} }
old_rev = rev;
/* /*
* Writeback and invalidate caches before updating microcode to avoid * Writeback and invalidate caches before updating microcode to avoid
* internal issues depending on what the microcode is updating. * internal issues depending on what the microcode is updating.
...@@ -407,9 +399,9 @@ static int apply_microcode_early(struct ucode_cpu_info *uci, bool early) ...@@ -407,9 +399,9 @@ static int apply_microcode_early(struct ucode_cpu_info *uci, bool early)
uci->cpu_sig.rev = rev; uci->cpu_sig.rev = rev;
if (early) if (early)
print_ucode(uci); print_ucode(old_rev, uci->cpu_sig.rev, mc->hdr.date);
else else
print_ucode_info(uci, mc->hdr.date); print_ucode_info(old_rev, uci->cpu_sig.rev, mc->hdr.date);
return 0; return 0;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment