forked from rpms/kernel
180 lines
4.9 KiB
Diff
180 lines
4.9 KiB
Diff
|
From 15a76d02ad4df4dbe37ed5bda874deeba2659843 Mon Sep 17 00:00:00 2001
|
||
|
From: Borislav Petkov <bp@suse.de>
|
||
|
Date: Wed, 19 Oct 2022 18:13:06 +0200
|
||
|
Subject: [PATCH 09/36] x86/microcode: Rip out the subsys interface gunk
|
||
|
|
||
|
This is a left-over from the old days when CPU hotplug wasn't as robust
|
||
|
as it is now. Currently, microcode gets loaded early on the CPU init
|
||
|
path and there's no need to attempt to load it again, which that subsys
|
||
|
interface callback is doing.
|
||
|
|
||
|
The only other thing that the subsys interface init path was doing is
|
||
|
adding the
|
||
|
|
||
|
/sys/devices/system/cpu/cpu*/microcode/
|
||
|
|
||
|
hierarchy.
|
||
|
|
||
|
So add a function which gets called on each CPU after all the necessary
|
||
|
driver setup has happened. Use schedule_on_each_cpu() which can block
|
||
|
because the sysfs creating code does kmem_cache_zalloc() which can block
|
||
|
too and the initial version of this where it did that setup in an IPI
|
||
|
handler of on_each_cpu() can cause a deadlock of the sort:
|
||
|
|
||
|
lock(fs_reclaim);
|
||
|
<Interrupt>
|
||
|
lock(fs_reclaim);
|
||
|
|
||
|
as the IPI handler runs in IRQ context.
|
||
|
|
||
|
Signed-off-by: Borislav Petkov <bp@suse.de>
|
||
|
Reviewed-by: Ashok Raj <ashok.raj@intel.com>
|
||
|
Link: https://lore.kernel.org/r/20221028142638.28498-2-bp@alien8.de
|
||
|
(cherry picked from commit b6f86689d5b740f2cc3ac3a1032c7374b24381cc)
|
||
|
Signed-off-by: Mridula Shastry <mridula.c.shastry@oracle.com>
|
||
|
Reviewed-by: Todd Vierling <todd.vierling@oracle.com>
|
||
|
---
|
||
|
arch/x86/kernel/cpu/microcode/core.c | 82 +++++++---------------------
|
||
|
1 file changed, 21 insertions(+), 61 deletions(-)
|
||
|
|
||
|
diff --git a/arch/x86/kernel/cpu/microcode/core.c b/arch/x86/kernel/cpu/microcode/core.c
|
||
|
index 6affa814699d..8a7fc5d8db6e 100644
|
||
|
--- a/arch/x86/kernel/cpu/microcode/core.c
|
||
|
+++ b/arch/x86/kernel/cpu/microcode/core.c
|
||
|
@@ -621,8 +621,8 @@ static enum ucode_state microcode_resume_cpu(int cpu)
|
||
|
|
||
|
static enum ucode_state microcode_init_cpu(int cpu, bool refresh_fw)
|
||
|
{
|
||
|
- enum ucode_state ustate;
|
||
|
struct ucode_cpu_info *uci = ucode_cpu_info + cpu;
|
||
|
+ enum ucode_state ustate;
|
||
|
|
||
|
if (uci->valid)
|
||
|
return UCODE_OK;
|
||
|
@@ -656,44 +656,6 @@ static enum ucode_state microcode_update_cpu(int cpu)
|
||
|
return microcode_init_cpu(cpu, false);
|
||
|
}
|
||
|
|
||
|
-static int mc_device_add(struct device *dev, struct subsys_interface *sif)
|
||
|
-{
|
||
|
- int err, cpu = dev->id;
|
||
|
-
|
||
|
- if (!cpu_online(cpu))
|
||
|
- return 0;
|
||
|
-
|
||
|
- pr_debug("CPU%d added\n", cpu);
|
||
|
-
|
||
|
- err = sysfs_create_group(&dev->kobj, &mc_attr_group);
|
||
|
- if (err)
|
||
|
- return err;
|
||
|
-
|
||
|
- if (microcode_init_cpu(cpu, true) == UCODE_ERROR)
|
||
|
- return -EINVAL;
|
||
|
-
|
||
|
- return err;
|
||
|
-}
|
||
|
-
|
||
|
-static void mc_device_remove(struct device *dev, struct subsys_interface *sif)
|
||
|
-{
|
||
|
- int cpu = dev->id;
|
||
|
-
|
||
|
- if (!cpu_online(cpu))
|
||
|
- return;
|
||
|
-
|
||
|
- pr_debug("CPU%d removed\n", cpu);
|
||
|
- microcode_fini_cpu(cpu);
|
||
|
- sysfs_remove_group(&dev->kobj, &mc_attr_group);
|
||
|
-}
|
||
|
-
|
||
|
-static struct subsys_interface mc_cpu_interface = {
|
||
|
- .name = "microcode",
|
||
|
- .subsys = &cpu_subsys,
|
||
|
- .add_dev = mc_device_add,
|
||
|
- .remove_dev = mc_device_remove,
|
||
|
-};
|
||
|
-
|
||
|
/**
|
||
|
* microcode_bsp_resume - Update boot CPU microcode during resume.
|
||
|
*/
|
||
|
@@ -733,6 +695,9 @@ static int mc_cpu_down_prep(unsigned int cpu)
|
||
|
struct device *dev;
|
||
|
|
||
|
dev = get_cpu_device(cpu);
|
||
|
+
|
||
|
+ microcode_fini_cpu(cpu);
|
||
|
+
|
||
|
/* Suspend is in progress, only remove the interface */
|
||
|
sysfs_remove_group(&dev->kobj, &mc_attr_group);
|
||
|
pr_debug("CPU%d removed\n", cpu);
|
||
|
@@ -740,6 +705,18 @@ static int mc_cpu_down_prep(unsigned int cpu)
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
+static void setup_online_cpu(struct work_struct *work)
|
||
|
+{
|
||
|
+ int cpu = smp_processor_id();
|
||
|
+ struct ucode_cpu_info *uci = ucode_cpu_info + cpu;
|
||
|
+
|
||
|
+ memset(uci, 0, sizeof(*uci));
|
||
|
+
|
||
|
+ microcode_ops->collect_cpu_info(cpu, &uci->cpu_sig);
|
||
|
+
|
||
|
+ mc_cpu_online(cpu);
|
||
|
+}
|
||
|
+
|
||
|
static struct attribute *cpu_root_microcode_attrs[] = {
|
||
|
#ifdef CONFIG_MICROCODE_LATE_LOADING
|
||
|
&dev_attr_reload.attr,
|
||
|
@@ -771,27 +748,19 @@ int __init microcode_init(void)
|
||
|
return -ENODEV;
|
||
|
|
||
|
microcode_pdev = platform_device_register_simple("microcode", -1,
|
||
|
- NULL, 0);
|
||
|
- if (IS_ERR(microcode_pdev))
|
||
|
- return PTR_ERR(microcode_pdev);
|
||
|
-
|
||
|
- get_online_cpus();
|
||
|
- mutex_lock(µcode_mutex);
|
||
|
- error = subsys_interface_register(&mc_cpu_interface);
|
||
|
- mutex_unlock(µcode_mutex);
|
||
|
- put_online_cpus();
|
||
|
-
|
||
|
- if (error)
|
||
|
- goto out_pdev;
|
||
|
+ NULL, 0);
|
||
|
|
||
|
error = sysfs_create_group(&cpu_subsys.dev_root->kobj,
|
||
|
&cpu_root_microcode_group);
|
||
|
|
||
|
if (error) {
|
||
|
pr_err("Error creating microcode group!\n");
|
||
|
- goto out_driver;
|
||
|
+ goto out_pdev;
|
||
|
}
|
||
|
|
||
|
+ /* Do per-CPU setup */
|
||
|
+ schedule_on_each_cpu(setup_online_cpu);
|
||
|
+
|
||
|
register_syscore_ops(&mc_syscore_ops);
|
||
|
cpuhp_setup_state_nocalls(CPUHP_AP_MICROCODE_LOADER, "x86/microcode:starting",
|
||
|
mc_cpu_starting, NULL);
|
||
|
@@ -802,15 +771,6 @@ int __init microcode_init(void)
|
||
|
|
||
|
return 0;
|
||
|
|
||
|
- out_driver:
|
||
|
- get_online_cpus();
|
||
|
- mutex_lock(µcode_mutex);
|
||
|
-
|
||
|
- subsys_interface_unregister(&mc_cpu_interface);
|
||
|
-
|
||
|
- mutex_unlock(µcode_mutex);
|
||
|
- put_online_cpus();
|
||
|
-
|
||
|
out_pdev:
|
||
|
platform_device_unregister(microcode_pdev);
|
||
|
return error;
|
||
|
--
|
||
|
2.39.3
|
||
|
|