From 3f1f576a195aa266813cbd4ca70291deb61e0129 Mon Sep 17 00:00:00 2001 | |
From: Borislav Petkov <bp@suse.de> | |
Date: Fri, 16 Feb 2018 12:26:38 +0100 | |
Subject: x86/microcode: Propagate return value from updating functions | |
... so that callers can know when microcode was updated and act | |
accordingly. | |
Tested-by: Ashok Raj <ashok.raj@intel.com> | |
Signed-off-by: Borislav Petkov <bp@suse.de> | |
Reviewed-by: Ashok Raj <ashok.raj@intel.com> | |
Cc: Andy Lutomirski <luto@kernel.org> | |
Cc: Arjan van de Ven <arjan@linux.intel.com> | |
Cc: Borislav Petkov <bp@alien8.de> | |
Cc: Dan Williams <dan.j.williams@intel.com> | |
Cc: Dave Hansen <dave.hansen@linux.intel.com> | |
Cc: David Woodhouse <dwmw2@infradead.org> | |
Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org> | |
Cc: Josh Poimboeuf <jpoimboe@redhat.com> | |
Cc: Linus Torvalds <torvalds@linux-foundation.org> | |
Cc: Peter Zijlstra <peterz@infradead.org> | |
Cc: Thomas Gleixner <tglx@linutronix.de> | |
Link: http://lkml.kernel.org/r/20180216112640.11554-2-bp@alien8.de | |
Signed-off-by: Ingo Molnar <mingo@kernel.org> | |
--- | |
arch/x86/include/asm/microcode.h | 9 +++++++-- | |
arch/x86/kernel/cpu/microcode/amd.c | 10 +++++----- | |
arch/x86/kernel/cpu/microcode/core.c | 33 +++++++++++++++++---------------- | |
arch/x86/kernel/cpu/microcode/intel.c | 10 +++++----- | |
4 files changed, 34 insertions(+), 28 deletions(-) | |
diff --git a/arch/x86/include/asm/microcode.h b/arch/x86/include/asm/microcode.h | |
index 55520cec..7fb1047 100644 | |
--- a/arch/x86/include/asm/microcode.h | |
+++ b/arch/x86/include/asm/microcode.h | |
@@ -37,7 +37,12 @@ struct cpu_signature { | |
struct device; | |
-enum ucode_state { UCODE_ERROR, UCODE_OK, UCODE_NFOUND }; | |
+enum ucode_state { | |
+ UCODE_OK = 0, | |
+ UCODE_UPDATED, | |
+ UCODE_NFOUND, | |
+ UCODE_ERROR, | |
+}; | |
struct microcode_ops { | |
enum ucode_state (*request_microcode_user) (int cpu, | |
@@ -54,7 +59,7 @@ struct microcode_ops { | |
* are being called. | |
* See also the "Synchronization" section in microcode_core.c. | |
*/ | |
- int (*apply_microcode) (int cpu); | |
+ enum ucode_state (*apply_microcode) (int cpu); | |
int (*collect_cpu_info) (int cpu, struct cpu_signature *csig); | |
}; | |
diff --git a/arch/x86/kernel/cpu/microcode/amd.c b/arch/x86/kernel/cpu/microcode/amd.c | |
index 330b846..a998e1a 100644 | |
--- a/arch/x86/kernel/cpu/microcode/amd.c | |
+++ b/arch/x86/kernel/cpu/microcode/amd.c | |
@@ -498,7 +498,7 @@ static unsigned int verify_patch_size(u8 family, u32 patch_size, | |
return patch_size; | |
} | |
-static int apply_microcode_amd(int cpu) | |
+static enum ucode_state apply_microcode_amd(int cpu) | |
{ | |
struct cpuinfo_x86 *c = &cpu_data(cpu); | |
struct microcode_amd *mc_amd; | |
@@ -512,7 +512,7 @@ static int apply_microcode_amd(int cpu) | |
p = find_patch(cpu); | |
if (!p) | |
- return 0; | |
+ return UCODE_NFOUND; | |
mc_amd = p->data; | |
uci->mc = p->data; | |
@@ -523,13 +523,13 @@ static int apply_microcode_amd(int cpu) | |
if (rev >= mc_amd->hdr.patch_id) { | |
c->microcode = rev; | |
uci->cpu_sig.rev = rev; | |
- return 0; | |
+ return UCODE_OK; | |
} | |
if (__apply_microcode_amd(mc_amd)) { | |
pr_err("CPU%d: update failed for patch_level=0x%08x\n", | |
cpu, mc_amd->hdr.patch_id); | |
- return -1; | |
+ return UCODE_ERROR; | |
} | |
pr_info("CPU%d: new patch_level=0x%08x\n", cpu, | |
mc_amd->hdr.patch_id); | |
@@ -537,7 +537,7 @@ static int apply_microcode_amd(int cpu) | |
uci->cpu_sig.rev = mc_amd->hdr.patch_id; | |
c->microcode = mc_amd->hdr.patch_id; | |
- return 0; | |
+ return UCODE_UPDATED; | |
} | |
static int install_equiv_cpu_table(const u8 *buf) | |
diff --git a/arch/x86/kernel/cpu/microcode/core.c b/arch/x86/kernel/cpu/microcode/core.c | |
index 319dd65..6fdaf7c 100644 | |
--- a/arch/x86/kernel/cpu/microcode/core.c | |
+++ b/arch/x86/kernel/cpu/microcode/core.c | |
@@ -374,7 +374,7 @@ static int collect_cpu_info(int cpu) | |
} | |
struct apply_microcode_ctx { | |
- int err; | |
+ enum ucode_state err; | |
}; | |
static void apply_microcode_local(void *arg) | |
@@ -489,31 +489,29 @@ static void __exit microcode_dev_exit(void) | |
/* fake device for request_firmware */ | |
static struct platform_device *microcode_pdev; | |
-static int reload_for_cpu(int cpu) | |
+static enum ucode_state reload_for_cpu(int cpu) | |
{ | |
struct ucode_cpu_info *uci = ucode_cpu_info + cpu; | |
enum ucode_state ustate; | |
- int err = 0; | |
if (!uci->valid) | |
- return err; | |
+ return UCODE_OK; | |
ustate = microcode_ops->request_microcode_fw(cpu, µcode_pdev->dev, true); | |
- if (ustate == UCODE_OK) | |
- apply_microcode_on_target(cpu); | |
- else | |
- if (ustate == UCODE_ERROR) | |
- err = -EINVAL; | |
- return err; | |
+ if (ustate != UCODE_OK) | |
+ return ustate; | |
+ | |
+ return apply_microcode_on_target(cpu); | |
} | |
static ssize_t reload_store(struct device *dev, | |
struct device_attribute *attr, | |
const char *buf, size_t size) | |
{ | |
+ enum ucode_state tmp_ret = UCODE_OK; | |
unsigned long val; | |
+ ssize_t ret = 0; | |
int cpu; | |
- ssize_t ret = 0, tmp_ret; | |
ret = kstrtoul(buf, 0, &val); | |
if (ret) | |
@@ -526,15 +524,18 @@ static ssize_t reload_store(struct device *dev, | |
mutex_lock(µcode_mutex); | |
for_each_online_cpu(cpu) { | |
tmp_ret = reload_for_cpu(cpu); | |
- if (tmp_ret != 0) | |
+ if (tmp_ret > UCODE_NFOUND) { | |
pr_warn("Error reloading microcode on CPU %d\n", cpu); | |
- /* save retval of the first encountered reload error */ | |
- if (!ret) | |
- ret = tmp_ret; | |
+ /* set retval for the first encountered reload error */ | |
+ if (!ret) | |
+ ret = -EINVAL; | |
+ } | |
} | |
- if (!ret) | |
+ | |
+ if (!ret && tmp_ret == UCODE_UPDATED) | |
perf_check_microcode(); | |
+ | |
mutex_unlock(µcode_mutex); | |
put_online_cpus(); | |
diff --git a/arch/x86/kernel/cpu/microcode/intel.c b/arch/x86/kernel/cpu/microcode/intel.c | |
index a15db2b..923054a 100644 | |
--- a/arch/x86/kernel/cpu/microcode/intel.c | |
+++ b/arch/x86/kernel/cpu/microcode/intel.c | |
@@ -772,7 +772,7 @@ static int collect_cpu_info(int cpu_num, struct cpu_signature *csig) | |
return 0; | |
} | |
-static int apply_microcode_intel(int cpu) | |
+static enum ucode_state apply_microcode_intel(int cpu) | |
{ | |
struct microcode_intel *mc; | |
struct ucode_cpu_info *uci; | |
@@ -782,7 +782,7 @@ static int apply_microcode_intel(int cpu) | |
/* We should bind the task to the CPU */ | |
if (WARN_ON(raw_smp_processor_id() != cpu)) | |
- return -1; | |
+ return UCODE_ERROR; | |
uci = ucode_cpu_info + cpu; | |
mc = uci->mc; | |
@@ -790,7 +790,7 @@ static int apply_microcode_intel(int cpu) | |
/* Look for a newer patch in our cache: */ | |
mc = find_patch(uci); | |
if (!mc) | |
- return 0; | |
+ return UCODE_NFOUND; | |
} | |
/* write microcode via MSR 0x79 */ | |
@@ -801,7 +801,7 @@ static int apply_microcode_intel(int cpu) | |
if (rev != mc->hdr.rev) { | |
pr_err("CPU%d update to revision 0x%x failed\n", | |
cpu, mc->hdr.rev); | |
- return -1; | |
+ return UCODE_ERROR; | |
} | |
if (rev != prev_rev) { | |
@@ -818,7 +818,7 @@ static int apply_microcode_intel(int cpu) | |
uci->cpu_sig.rev = rev; | |
c->microcode = rev; | |
- return 0; | |
+ return UCODE_UPDATED; | |
} | |
static enum ucode_state generic_load_microcode(int cpu, void *data, size_t size, | |
-- | |
cgit v1.1 | |