x86/microcode/intel: Unify microcode apply() functions
authorThomas Gleixner <tglx@linutronix.de>
Tue, 17 Oct 2023 21:23:44 +0000 (23:23 +0200)
committerBorislav Petkov (AMD) <bp@alien8.de>
Tue, 24 Oct 2023 13:05:53 +0000 (15:05 +0200)
Deduplicate the early and late apply() functions.

  [ bp: Rename the function which does the actual application to
      __apply_microcode() to differentiate it from
      microcode_ops.apply_microcode(). ]

Signed-off-by: Borislav Petkov (AMD) <bp@alien8.de>
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Link: https://lore.kernel.org/r/20231017211722.795508212@linutronix.de
arch/x86/kernel/cpu/microcode/intel.c

index dd2d3fde8d062d80ebe4b3f6d8fec5587af424a7..4235c95f17cf568b228ee1cbf292633dfa83e080 100644 (file)
@@ -307,12 +307,12 @@ static __init struct microcode_intel *scan_microcode(void *data, size_t size,
        return size ? NULL : patch;
 }
 
-static enum ucode_state apply_microcode_early(struct ucode_cpu_info *uci)
+static enum ucode_state __apply_microcode(struct ucode_cpu_info *uci,
+                                         struct microcode_intel *mc,
+                                         u32 *cur_rev)
 {
-       struct microcode_intel *mc;
-       u32 rev, old_rev, date;
+       u32 rev;
 
-       mc = uci->mc;
        if (!mc)
                return UCODE_NFOUND;
 
@@ -321,14 +321,12 @@ static enum ucode_state apply_microcode_early(struct ucode_cpu_info *uci)
         * operation - when the other hyperthread has updated the microcode
         * already.
         */
-       rev = intel_get_microcode_revision();
-       if (rev >= mc->hdr.rev) {
-               uci->cpu_sig.rev = rev;
+       *cur_rev = intel_get_microcode_revision();
+       if (*cur_rev >= mc->hdr.rev) {
+               uci->cpu_sig.rev = *cur_rev;
                return UCODE_OK;
        }
 
-       old_rev = rev;
-
        /*
         * Writeback and invalidate caches before updating microcode to avoid
         * internal issues depending on what the microcode is updating.
@@ -343,13 +341,24 @@ static enum ucode_state apply_microcode_early(struct ucode_cpu_info *uci)
                return UCODE_ERROR;
 
        uci->cpu_sig.rev = rev;
-
-       date = mc->hdr.date;
-       pr_info_once("updated early: 0x%x -> 0x%x, date = %04x-%02x-%02x\n",
-                    old_rev, rev, date & 0xffff, date >> 24, (date >> 16) & 0xff);
        return UCODE_UPDATED;
 }
 
+static enum ucode_state apply_microcode_early(struct ucode_cpu_info *uci)
+{
+       struct microcode_intel *mc = uci->mc;
+       enum ucode_state ret;
+       u32 cur_rev, date;
+
+       ret = __apply_microcode(uci, mc, &cur_rev);
+       if (ret == UCODE_UPDATED) {
+               date = mc->hdr.date;
+               pr_info_once("updated early: 0x%x -> 0x%x, date = %04x-%02x-%02x\n",
+                            cur_rev, mc->hdr.rev, date & 0xffff, date >> 24, (date >> 16) & 0xff);
+       }
+       return ret;
+}
+
 static __init bool load_builtin_intel_microcode(struct cpio_data *cp)
 {
        unsigned int eax = 1, ebx, ecx = 0, edx;
@@ -459,70 +468,29 @@ static int collect_cpu_info(int cpu_num, struct cpu_signature *csig)
        return 0;
 }
 
-static enum ucode_state apply_microcode_intel(int cpu)
+static enum ucode_state apply_microcode_late(int cpu)
 {
        struct ucode_cpu_info *uci = ucode_cpu_info + cpu;
-       struct cpuinfo_x86 *c = &cpu_data(cpu);
-       bool bsp = c->cpu_index == boot_cpu_data.cpu_index;
-       struct microcode_intel *mc;
+       struct microcode_intel *mc = ucode_patch_late;
        enum ucode_state ret;
-       static int prev_rev;
-       u32 rev;
+       u32 cur_rev;
 
-       /* We should bind the task to the CPU */
-       if (WARN_ON(raw_smp_processor_id() != cpu))
+       if (WARN_ON_ONCE(smp_processor_id() != cpu))
                return UCODE_ERROR;
 
-       mc = ucode_patch_late;
-       if (!mc)
-               return UCODE_NFOUND;
+       ret = __apply_microcode(uci, mc, &cur_rev);
+       if (ret != UCODE_UPDATED && ret != UCODE_OK)
+               return ret;
 
-       /*
-        * Save us the MSR write below - which is a particular expensive
-        * operation - when the other hyperthread has updated the microcode
-        * already.
-        */
-       rev = intel_get_microcode_revision();
-       if (rev >= mc->hdr.rev) {
-               ret = UCODE_OK;
-               goto out;
-       }
-
-       /*
-        * Writeback and invalidate caches before updating microcode to avoid
-        * internal issues depending on what the microcode is updating.
-        */
-       native_wbinvd();
-
-       /* write microcode via MSR 0x79 */
-       wrmsrl(MSR_IA32_UCODE_WRITE, (unsigned long)mc->bits);
-
-       rev = intel_get_microcode_revision();
-
-       if (rev != mc->hdr.rev) {
-               pr_err("CPU%d update to revision 0x%x failed\n",
-                      cpu, mc->hdr.rev);
-               return UCODE_ERROR;
-       }
-
-       if (bsp && rev != prev_rev) {
-               pr_info("updated to revision 0x%x, date = %04x-%02x-%02x\n",
-                       rev,
-                       mc->hdr.date & 0xffff,
-                       mc->hdr.date >> 24,
+       if (!cpu && uci->cpu_sig.rev != cur_rev) {
+               pr_info("Updated to revision 0x%x, date = %04x-%02x-%02x\n",
+                       uci->cpu_sig.rev, mc->hdr.date & 0xffff, mc->hdr.date >> 24,
                        (mc->hdr.date >> 16) & 0xff);
-               prev_rev = rev;
        }
 
-       ret = UCODE_UPDATED;
-
-out:
-       uci->cpu_sig.rev = rev;
-       c->microcode     = rev;
-
-       /* Update boot_cpu_data's revision too, if we're on the BSP: */
-       if (bsp)
-               boot_cpu_data.microcode = rev;
+       cpu_data(cpu).microcode  = uci->cpu_sig.rev;
+       if (!cpu)
+               boot_cpu_data.microcode = uci->cpu_sig.rev;
 
        return ret;
 }
@@ -663,7 +631,7 @@ static void finalize_late_load(int result)
 static struct microcode_ops microcode_intel_ops = {
        .request_microcode_fw   = request_microcode_fw,
        .collect_cpu_info       = collect_cpu_info,
-       .apply_microcode        = apply_microcode_intel,
+       .apply_microcode        = apply_microcode_late,
        .finalize_late_load     = finalize_late_load,
 };