Commit 5071ec24 authored by Borislav Petkov's avatar Borislav Petkov Committed by Aichun Shi
Browse files

x86/microcode: Simplify init path even more

mainline inclusion
from mainline-v6.2-rc1
commit 2071c0ae
category: feature
feature: Backport Intel In Field Scan(IFS) multi-blob images support
bugzilla: https://gitee.com/openeuler/intel-kernel/issues/I6L337
CVE: N/A
Reference: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/


commit/?id=2071c0ae

Intel-SIG: commit 2071c0ae ("x86/microcode: Simplify init path even more")

-------------------------------------

x86/microcode: Simplify init path even more

Get rid of all the IPI-sending functions and their wrappers and use
those which are supposed to be called on each CPU.

Thus:

- microcode_init_cpu() gets called on each CPU on init, applying any new
  microcode that the driver might've found on the filesystem.

- mc_cpu_starting() simply tries to apply cached microcode as this is
  the cpuhp starting callback which gets called on CPU resume too.

Even if the driver init function is a late initcall, there is no
filesystem by then (not even a hdd driver has been loaded yet) so a new
firmware load attempt cannot simply be done.

It is pointless anyway - for that there's late loading if one really
needs it.

Signed-off-by: default avatarBorislav Petkov <bp@suse.de>
Reviewed-by: default avatarAshok Raj <ashok.raj@intel.com>
Link: https://lore.kernel.org/r/20221028142638.28498-3-bp@alien8.de


Signed-off-by: default avatarAichun Shi <aichun.shi@intel.com>
parent 6499df46
Loading
Loading
Loading
Loading
+16 −104
Original line number Diff line number Diff line
@@ -336,60 +336,6 @@ void reload_early_microcode(void)
	}
}

static void collect_cpu_info_local(void *arg)
{
	struct cpu_info_ctx *ctx = arg;

	ctx->err = microcode_ops->collect_cpu_info(smp_processor_id(),
						   ctx->cpu_sig);
}

static int collect_cpu_info_on_target(int cpu, struct cpu_signature *cpu_sig)
{
	struct cpu_info_ctx ctx = { .cpu_sig = cpu_sig, .err = 0 };
	int ret;

	ret = smp_call_function_single(cpu, collect_cpu_info_local, &ctx, 1);
	if (!ret)
		ret = ctx.err;

	return ret;
}

static int collect_cpu_info(int cpu)
{
	struct ucode_cpu_info *uci = ucode_cpu_info + cpu;
	int ret;

	memset(uci, 0, sizeof(*uci));

	ret = collect_cpu_info_on_target(cpu, &uci->cpu_sig);
	if (!ret)
		uci->valid = 1;

	return ret;
}

static void apply_microcode_local(void *arg)
{
	enum ucode_state *err = arg;

	*err = microcode_ops->apply_microcode(smp_processor_id());
}

static int apply_microcode_on_target(int cpu)
{
	enum ucode_state err;
	int ret;

	ret = smp_call_function_single(cpu, apply_microcode_local, &err, 1);
	if (!ret) {
		if (err == UCODE_ERROR)
			ret = 1;
	}
	return ret;
}

/* fake device for request_firmware */
static struct platform_device	*microcode_pdev;

@@ -475,7 +421,7 @@ static int __reload_late(void *info)
	 * below.
	 */
	if (cpumask_first(topology_sibling_cpumask(cpu)) == cpu)
		apply_microcode_local(&err);
		err = microcode_ops->apply_microcode(cpu);
	else
		goto wait_for_siblings;

@@ -497,7 +443,7 @@ static int __reload_late(void *info)
	 * revision.
	 */
	if (cpumask_first(topology_sibling_cpumask(cpu)) != cpu)
		apply_microcode_local(&err);
		err = microcode_ops->apply_microcode(cpu);

	return ret;
}
@@ -606,51 +552,15 @@ static void microcode_fini_cpu(int cpu)
		microcode_ops->microcode_fini_cpu(cpu);
}

static enum ucode_state microcode_resume_cpu(int cpu)
{
	if (apply_microcode_on_target(cpu))
		return UCODE_ERROR;

	pr_debug("CPU%d updated upon resume\n", cpu);

	return UCODE_OK;
}

static enum ucode_state microcode_init_cpu(int cpu, bool refresh_fw)
{
	struct ucode_cpu_info *uci = ucode_cpu_info + cpu;
	enum ucode_state ustate;

	if (uci->valid)
		return UCODE_OK;

	if (collect_cpu_info(cpu))
		return UCODE_ERROR;

	/* --dimm. Trigger a delayed update? */
	if (system_state != SYSTEM_RUNNING)
		return UCODE_NFOUND;

	ustate = microcode_ops->request_microcode_fw(cpu, &microcode_pdev->dev, refresh_fw);
	if (ustate == UCODE_NEW) {
		pr_debug("CPU%d updated upon init\n", cpu);
		apply_microcode_on_target(cpu);
	}

	return ustate;
}

static enum ucode_state microcode_update_cpu(int cpu)
static enum ucode_state microcode_init_cpu(int cpu)
{
	struct ucode_cpu_info *uci = ucode_cpu_info + cpu;

	/* Refresh CPU microcode revision after resume. */
	collect_cpu_info(cpu);
	memset(uci, 0, sizeof(*uci));

	if (uci->valid)
		return microcode_resume_cpu(cpu);
	microcode_ops->collect_cpu_info(cpu, &uci->cpu_sig);

	return microcode_init_cpu(cpu, false);
	return microcode_ops->apply_microcode(cpu);
}

/**
@@ -673,9 +583,9 @@ static struct syscore_ops mc_syscore_ops = {

static int mc_cpu_starting(unsigned int cpu)
{
	microcode_update_cpu(cpu);
	pr_debug("CPU%d added\n", cpu);
	return 0;
	enum ucode_state err = microcode_ops->apply_microcode(cpu);

	return err == UCODE_ERROR;
}

static int mc_cpu_online(unsigned int cpu)
@@ -705,11 +615,13 @@ static int mc_cpu_down_prep(unsigned int cpu)
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));
	enum ucode_state err;

	microcode_ops->collect_cpu_info(cpu, &uci->cpu_sig);
	err = microcode_init_cpu(cpu);
	if (err == UCODE_ERROR) {
		pr_err("Error applying microcode on CPU%d\n", cpu);
		return;
	}

	mc_cpu_online(cpu);
}