]> git.proxmox.com Git - mirror_ubuntu-hirsute-kernel.git/blobdiff - arch/x86/kernel/cpu/microcode/intel.c
Merge branches 'x86/amd', 'x86/vt-d', 'arm/rockchip', 'arm/omap', 'arm/mediatek'...
[mirror_ubuntu-hirsute-kernel.git] / arch / x86 / kernel / cpu / microcode / intel.c
index 923054a6b76013a1474372b7810749f577b0c811..32b8e5724f966abbc67153065dd17b5ddcfd6d70 100644 (file)
@@ -589,6 +589,23 @@ static int apply_microcode_early(struct ucode_cpu_info *uci, bool early)
        if (!mc)
                return 0;
 
+       /*
+        * 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) {
+               uci->cpu_sig.rev = rev;
+               return UCODE_OK;
+       }
+
+       /*
+        * 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 */
        native_wrmsrl(MSR_IA32_UCODE_WRITE, (unsigned long)mc->bits);
 
@@ -774,9 +791,9 @@ static int collect_cpu_info(int cpu_num, struct cpu_signature *csig)
 
 static enum ucode_state apply_microcode_intel(int cpu)
 {
+       struct ucode_cpu_info *uci = ucode_cpu_info + cpu;
+       struct cpuinfo_x86 *c = &cpu_data(cpu);
        struct microcode_intel *mc;
-       struct ucode_cpu_info *uci;
-       struct cpuinfo_x86 *c;
        static int prev_rev;
        u32 rev;
 
@@ -784,15 +801,32 @@ static enum ucode_state apply_microcode_intel(int cpu)
        if (WARN_ON(raw_smp_processor_id() != cpu))
                return UCODE_ERROR;
 
-       uci = ucode_cpu_info + cpu;
-       mc = uci->mc;
+       /* Look for a newer patch in our cache: */
+       mc = find_patch(uci);
        if (!mc) {
-               /* Look for a newer patch in our cache: */
-               mc = find_patch(uci);
+               mc = uci->mc;
                if (!mc)
                        return UCODE_NFOUND;
        }
 
+       /*
+        * 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) {
+               uci->cpu_sig.rev = rev;
+               c->microcode = rev;
+               return UCODE_OK;
+       }
+
+       /*
+        * 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);
 
@@ -813,8 +847,6 @@ static enum ucode_state apply_microcode_intel(int cpu)
                prev_rev = rev;
        }
 
-       c = &cpu_data(cpu);
-
        uci->cpu_sig.rev = rev;
        c->microcode = rev;
 
@@ -830,6 +862,7 @@ static enum ucode_state generic_load_microcode(int cpu, void *data, size_t size,
        unsigned int leftover = size;
        unsigned int curr_mc_size = 0, new_mc_size = 0;
        unsigned int csig, cpf;
+       enum ucode_state ret = UCODE_OK;
 
        while (leftover) {
                struct microcode_header_intel mc_header;
@@ -871,6 +904,7 @@ static enum ucode_state generic_load_microcode(int cpu, void *data, size_t size,
                        new_mc  = mc;
                        new_mc_size = mc_size;
                        mc = NULL;      /* trigger new vmalloc */
+                       ret = UCODE_NEW;
                }
 
                ucode_ptr += mc_size;
@@ -900,7 +934,7 @@ static enum ucode_state generic_load_microcode(int cpu, void *data, size_t size,
        pr_debug("CPU%d found a matching microcode update with version 0x%x (current=0x%x)\n",
                 cpu, new_rev, uci->cpu_sig.rev);
 
-       return UCODE_OK;
+       return ret;
 }
 
 static int get_ucode_fw(void *to, const void *from, size_t n)