| From 7ff6edf4fef38ab404ee7861f257e28eaaeed35f Mon Sep 17 00:00:00 2001 |
| From: "Borislav Petkov (AMD)" <bp@alien8.de> |
| Date: Thu, 26 Jan 2023 16:26:17 +0100 |
| Subject: x86/microcode/AMD: Fix mixed steppings support |
| |
| From: Borislav Petkov (AMD) <bp@alien8.de> |
| |
| commit 7ff6edf4fef38ab404ee7861f257e28eaaeed35f upstream. |
| |
| The AMD side of the loader has always claimed to support mixed |
| steppings. But somewhere along the way, it broke that by assuming that |
| the cached patch blob is a single one instead of it being one per |
| *node*. |
| |
| So turn it into a per-node one so that each node can stash the blob |
| relevant for it. |
| |
| [ NB: Fixes tag is not really the exactly correct one but it is good |
| enough. ] |
| |
| Fixes: fe055896c040 ("x86/microcode: Merge the early microcode loader") |
| Signed-off-by: Borislav Petkov (AMD) <bp@alien8.de> |
| Cc: <stable@kernel.org> # 2355370cd941 ("x86/microcode/amd: Remove load_microcode_amd()'s bsp parameter") |
| Cc: <stable@kernel.org> # a5ad92134bd1 ("x86/microcode/AMD: Add a @cpu parameter to the reloading functions") |
| Link: https://lore.kernel.org/r/20230130161709.11615-4-bp@alien8.de |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| --- |
| arch/x86/kernel/cpu/microcode/amd.c | 34 +++++++++++++++++++++------------- |
| 1 file changed, 21 insertions(+), 13 deletions(-) |
| |
| --- a/arch/x86/kernel/cpu/microcode/amd.c |
| +++ b/arch/x86/kernel/cpu/microcode/amd.c |
| @@ -55,7 +55,9 @@ struct cont_desc { |
| }; |
| |
| 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 |
| @@ -429,7 +431,7 @@ apply_microcode_early_amd(u32 cpuid_1_ea |
| patch = (u8 (*)[PATCH_MAX_SIZE])__pa_nodebug(&amd_ucode_patch); |
| #else |
| new_rev = &ucode_new_rev; |
| - patch = &amd_ucode_patch; |
| + patch = &amd_ucode_patch[0]; |
| #endif |
| |
| desc.cpuid_1_eax = cpuid_1_eax; |
| @@ -575,10 +577,10 @@ int __init save_microcode_in_initrd_amd( |
| |
| void reload_ucode_amd(unsigned int cpu) |
| { |
| - struct microcode_amd *mc; |
| 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); |
| |
| @@ -846,6 +848,8 @@ static enum ucode_state __load_microcode |
| |
| static enum ucode_state load_microcode_amd(u8 family, const u8 *data, size_t size) |
| { |
| + struct cpuinfo_x86 *c; |
| + unsigned int nid, cpu; |
| struct ucode_patch *p; |
| enum ucode_state ret; |
| |
| @@ -858,18 +862,22 @@ static enum ucode_state load_microcode_a |
| return ret; |
| } |
| |
| - p = find_patch(0); |
| - if (!p) { |
| - return ret; |
| - } else { |
| - if (boot_cpu_data.microcode >= p->patch_id) |
| - return ret; |
| + for_each_node(nid) { |
| + cpu = cpumask_first(cpumask_of_node(nid)); |
| + c = &cpu_data(cpu); |
| + |
| + p = find_patch(cpu); |
| + if (!p) |
| + continue; |
| + |
| + if (c->microcode >= p->patch_id) |
| + continue; |
| |
| ret = UCODE_NEW; |
| - } |
| |
| - memset(amd_ucode_patch, 0, PATCH_MAX_SIZE); |
| - 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; |
| } |