Blame linux-kernel-patches/10-a5321aec6412b20b5ad15db2d6b916c05349dbff.patch

Packit Service c9fe53
From a5321aec6412b20b5ad15db2d6b916c05349dbff Mon Sep 17 00:00:00 2001
Packit Service c9fe53
From: Ashok Raj <ashok.raj@intel.com>
Packit Service c9fe53
Date: Wed, 28 Feb 2018 11:28:46 +0100
Packit Service c9fe53
Subject: x86/microcode: Synchronize late microcode loading
Packit Service c9fe53

Packit Service c9fe53
Original idea by Ashok, completely rewritten by Borislav.
Packit Service c9fe53

Packit Service c9fe53
Before you read any further: the early loading method is still the
Packit Service c9fe53
preferred one and you should always do that. The following patch is
Packit Service c9fe53
improving the late loading mechanism for long running jobs and cloud use
Packit Service c9fe53
cases.
Packit Service c9fe53

Packit Service c9fe53
Gather all cores and serialize the microcode update on them by doing it
Packit Service c9fe53
one-by-one to make the late update process as reliable as possible and
Packit Service c9fe53
avoid potential issues caused by the microcode update.
Packit Service c9fe53

Packit Service c9fe53
[ Borislav: Rewrite completely. ]
Packit Service c9fe53

Packit Service c9fe53
Co-developed-by: Borislav Petkov <bp@suse.de>
Packit Service c9fe53
Signed-off-by: Ashok Raj <ashok.raj@intel.com>
Packit Service c9fe53
Signed-off-by: Borislav Petkov <bp@suse.de>
Packit Service c9fe53
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Packit Service c9fe53
Tested-by: Tom Lendacky <thomas.lendacky@amd.com>
Packit Service c9fe53
Tested-by: Ashok Raj <ashok.raj@intel.com>
Packit Service c9fe53
Reviewed-by: Tom Lendacky <thomas.lendacky@amd.com>
Packit Service c9fe53
Cc: Arjan Van De Ven <arjan.van.de.ven@intel.com>
Packit Service c9fe53
Link: https://lkml.kernel.org/r/20180228102846.13447-8-bp@alien8.de
Packit Service c9fe53
---
Packit Service c9fe53
 arch/x86/kernel/cpu/microcode/core.c | 118 +++++++++++++++++++++++++++--------
Packit Service c9fe53
 1 file changed, 92 insertions(+), 26 deletions(-)
Packit Service c9fe53

Packit Service c9fe53
diff --git a/arch/x86/kernel/cpu/microcode/core.c b/arch/x86/kernel/cpu/microcode/core.c
Packit Service c9fe53
index 5dd157d..70ecbc8 100644
Packit Service c9fe53
--- a/arch/x86/kernel/cpu/microcode/core.c
Packit Service c9fe53
+++ b/arch/x86/kernel/cpu/microcode/core.c
Packit Service c9fe53
@@ -22,13 +22,16 @@
Packit Service c9fe53
 #define pr_fmt(fmt) "microcode: " fmt
Packit Service c9fe53
 
Packit Service c9fe53
 #include <linux/platform_device.h>
Packit Service c9fe53
+#include <linux/stop_machine.h>
Packit Service c9fe53
 #include <linux/syscore_ops.h>
Packit Service c9fe53
 #include <linux/miscdevice.h>
Packit Service c9fe53
 #include <linux/capability.h>
Packit Service c9fe53
 #include <linux/firmware.h>
Packit Service c9fe53
 #include <linux/kernel.h>
Packit Service c9fe53
+#include <linux/delay.h>
Packit Service c9fe53
 #include <linux/mutex.h>
Packit Service c9fe53
 #include <linux/cpu.h>
Packit Service c9fe53
+#include <linux/nmi.h>
Packit Service c9fe53
 #include <linux/fs.h>
Packit Service c9fe53
 #include <linux/mm.h>
Packit Service c9fe53
 
Packit Service c9fe53
@@ -64,6 +67,11 @@ LIST_HEAD(microcode_cache);
Packit Service c9fe53
  */
Packit Service c9fe53
 static DEFINE_MUTEX(microcode_mutex);
Packit Service c9fe53
 
Packit Service c9fe53
+/*
Packit Service c9fe53
+ * Serialize late loading so that CPUs get updated one-by-one.
Packit Service c9fe53
+ */
Packit Service c9fe53
+static DEFINE_SPINLOCK(update_lock);
Packit Service c9fe53
+
Packit Service c9fe53
 struct ucode_cpu_info		ucode_cpu_info[NR_CPUS];
Packit Service c9fe53
 
Packit Service c9fe53
 struct cpu_info_ctx {
Packit Service c9fe53
@@ -486,6 +494,19 @@ static void __exit microcode_dev_exit(void)
Packit Service c9fe53
 /* fake device for request_firmware */
Packit Service c9fe53
 static struct platform_device	*microcode_pdev;
Packit Service c9fe53
 
Packit Service c9fe53
+/*
Packit Service c9fe53
+ * Late loading dance. Why the heavy-handed stomp_machine effort?
Packit Service c9fe53
+ *
Packit Service c9fe53
+ * - HT siblings must be idle and not execute other code while the other sibling
Packit Service c9fe53
+ *   is loading microcode in order to avoid any negative interactions caused by
Packit Service c9fe53
+ *   the loading.
Packit Service c9fe53
+ *
Packit Service c9fe53
+ * - In addition, microcode update on the cores must be serialized until this
Packit Service c9fe53
+ *   requirement can be relaxed in the future. Right now, this is conservative
Packit Service c9fe53
+ *   and good.
Packit Service c9fe53
+ */
Packit Service c9fe53
+#define SPINUNIT 100 /* 100 nsec */
Packit Service c9fe53
+
Packit Service c9fe53
 static int check_online_cpus(void)
Packit Service c9fe53
 {
Packit Service c9fe53
 	if (num_online_cpus() == num_present_cpus())
Packit Service c9fe53
@@ -496,23 +517,85 @@ static int check_online_cpus(void)
Packit Service c9fe53
 	return -EINVAL;
Packit Service c9fe53
 }
Packit Service c9fe53
 
Packit Service c9fe53
-static enum ucode_state reload_for_cpu(int cpu)
Packit Service c9fe53
+static atomic_t late_cpus;
Packit Service c9fe53
+
Packit Service c9fe53
+/*
Packit Service c9fe53
+ * Returns:
Packit Service c9fe53
+ * < 0 - on error
Packit Service c9fe53
+ *   0 - no update done
Packit Service c9fe53
+ *   1 - microcode was updated
Packit Service c9fe53
+ */
Packit Service c9fe53
+static int __reload_late(void *info)
Packit Service c9fe53
 {
Packit Service c9fe53
-	struct ucode_cpu_info *uci = ucode_cpu_info + cpu;
Packit Service c9fe53
+	unsigned int timeout = NSEC_PER_SEC;
Packit Service c9fe53
+	int all_cpus = num_online_cpus();
Packit Service c9fe53
+	int cpu = smp_processor_id();
Packit Service c9fe53
+	enum ucode_state err;
Packit Service c9fe53
+	int ret = 0;
Packit Service c9fe53
 
Packit Service c9fe53
-	if (!uci->valid)
Packit Service c9fe53
-		return UCODE_OK;
Packit Service c9fe53
+	atomic_dec(&late_cpus);
Packit Service c9fe53
+
Packit Service c9fe53
+	/*
Packit Service c9fe53
+	 * Wait for all CPUs to arrive. A load will not be attempted unless all
Packit Service c9fe53
+	 * CPUs show up.
Packit Service c9fe53
+	 * */
Packit Service c9fe53
+	while (atomic_read(&late_cpus)) {
Packit Service c9fe53
+		if (timeout < SPINUNIT) {
Packit Service c9fe53
+			pr_err("Timeout while waiting for CPUs rendezvous, remaining: %d\n",
Packit Service c9fe53
+				atomic_read(&late_cpus));
Packit Service c9fe53
+			return -1;
Packit Service c9fe53
+		}
Packit Service c9fe53
+
Packit Service c9fe53
+		ndelay(SPINUNIT);
Packit Service c9fe53
+		timeout -= SPINUNIT;
Packit Service c9fe53
+
Packit Service c9fe53
+		touch_nmi_watchdog();
Packit Service c9fe53
+	}
Packit Service c9fe53
+
Packit Service c9fe53
+	spin_lock(&update_lock);
Packit Service c9fe53
+	apply_microcode_local(&err;;
Packit Service c9fe53
+	spin_unlock(&update_lock);
Packit Service c9fe53
+
Packit Service c9fe53
+	if (err > UCODE_NFOUND) {
Packit Service c9fe53
+		pr_warn("Error reloading microcode on CPU %d\n", cpu);
Packit Service c9fe53
+		ret = -1;
Packit Service c9fe53
+	} else if (err == UCODE_UPDATED) {
Packit Service c9fe53
+		ret = 1;
Packit Service c9fe53
+	}
Packit Service c9fe53
 
Packit Service c9fe53
-	return apply_microcode_on_target(cpu);
Packit Service c9fe53
+	atomic_inc(&late_cpus);
Packit Service c9fe53
+
Packit Service c9fe53
+	while (atomic_read(&late_cpus) != all_cpus)
Packit Service c9fe53
+		cpu_relax();
Packit Service c9fe53
+
Packit Service c9fe53
+	return ret;
Packit Service c9fe53
+}
Packit Service c9fe53
+
Packit Service c9fe53
+/*
Packit Service c9fe53
+ * Reload microcode late on all CPUs. Wait for a sec until they
Packit Service c9fe53
+ * all gather together.
Packit Service c9fe53
+ */
Packit Service c9fe53
+static int microcode_reload_late(void)
Packit Service c9fe53
+{
Packit Service c9fe53
+	int ret;
Packit Service c9fe53
+
Packit Service c9fe53
+	atomic_set(&late_cpus, num_online_cpus());
Packit Service c9fe53
+
Packit Service c9fe53
+	ret = stop_machine_cpuslocked(__reload_late, NULL, cpu_online_mask);
Packit Service c9fe53
+	if (ret < 0)
Packit Service c9fe53
+		return ret;
Packit Service c9fe53
+	else if (ret > 0)
Packit Service c9fe53
+		microcode_check();
Packit Service c9fe53
+
Packit Service c9fe53
+	return ret;
Packit Service c9fe53
 }
Packit Service c9fe53
 
Packit Service c9fe53
 static ssize_t reload_store(struct device *dev,
Packit Service c9fe53
 			    struct device_attribute *attr,
Packit Service c9fe53
 			    const char *buf, size_t size)
Packit Service c9fe53
 {
Packit Service c9fe53
-	int cpu, bsp = boot_cpu_data.cpu_index;
Packit Service c9fe53
 	enum ucode_state tmp_ret = UCODE_OK;
Packit Service c9fe53
-	bool do_callback = false;
Packit Service c9fe53
+	int bsp = boot_cpu_data.cpu_index;
Packit Service c9fe53
 	unsigned long val;
Packit Service c9fe53
 	ssize_t ret = 0;
Packit Service c9fe53
 
Packit Service c9fe53
@@ -534,30 +617,13 @@ static ssize_t reload_store(struct device *dev,
Packit Service c9fe53
 		goto put;
Packit Service c9fe53
 
Packit Service c9fe53
 	mutex_lock(&microcode_mutex);
Packit Service c9fe53
-
Packit Service c9fe53
-	for_each_online_cpu(cpu) {
Packit Service c9fe53
-		tmp_ret = reload_for_cpu(cpu);
Packit Service c9fe53
-		if (tmp_ret > UCODE_NFOUND) {
Packit Service c9fe53
-			pr_warn("Error reloading microcode on CPU %d\n", cpu);
Packit Service c9fe53
-
Packit Service c9fe53
-			/* set retval for the first encountered reload error */
Packit Service c9fe53
-			if (!ret)
Packit Service c9fe53
-				ret = -EINVAL;
Packit Service c9fe53
-		}
Packit Service c9fe53
-
Packit Service c9fe53
-		if (tmp_ret == UCODE_UPDATED)
Packit Service c9fe53
-			do_callback = true;
Packit Service c9fe53
-	}
Packit Service c9fe53
-
Packit Service c9fe53
-	if (!ret && do_callback)
Packit Service c9fe53
-		microcode_check();
Packit Service c9fe53
-
Packit Service c9fe53
+	ret = microcode_reload_late();
Packit Service c9fe53
 	mutex_unlock(&microcode_mutex);
Packit Service c9fe53
 
Packit Service c9fe53
 put:
Packit Service c9fe53
 	put_online_cpus();
Packit Service c9fe53
 
Packit Service c9fe53
-	if (!ret)
Packit Service c9fe53
+	if (ret >= 0)
Packit Service c9fe53
 		ret = size;
Packit Service c9fe53
 
Packit Service c9fe53
 	return ret;
Packit Service c9fe53
-- 
Packit Service c9fe53
cgit v1.1
Packit Service c9fe53