x86: ivybridge: Update microcode early in boot
authorSimon Glass <sjg@chromium.org>
Thu, 1 Jan 2015 23:18:14 +0000 (16:18 -0700)
committerSimon Glass <sjg@chromium.org>
Tue, 13 Jan 2015 15:25:02 +0000 (07:25 -0800)
At present the normal update (which happens much later) does not work. This
seems to have something to do with the 'no eviction' mode in the CAR, or at
least moving the microcode update after that causes it not to work.

For now, do an update early on so that it definitely works. Also refuse to
continue unless the microcode update check (later in boot) is successful.

Signed-off-by: Simon Glass <sjg@chromium.org>
arch/x86/cpu/ivybridge/car.S
arch/x86/cpu/ivybridge/cpu.c
arch/x86/cpu/ivybridge/microcode_intel.c
arch/x86/dts/link.dts
arch/x86/include/asm/arch-ivybridge/microcode.h

index d5f1acfe3dae3f1253966bda1af373e8628e44f8..9441666f5aa037b99bd40e1fea5dba2a349feab9 100644 (file)
  */
 
 #include <common.h>
+#include <asm/msr-index.h>
 #include <asm/mtrr.h>
 #include <asm/post.h>
 #include <asm/processor-flags.h>
+#include <asm/arch/microcode.h>
 
 #define MTRR_PHYS_BASE_MSR(reg) (0x200 + 2 * (reg))
 #define MTRR_PHYS_MASK_MSR(reg) (0x200 + 2 * (reg) + 1)
@@ -45,6 +47,14 @@ car_init:
        movl    $0xFEE00300, %esi
        movl    %eax, (%esi)
 
+       /* TODO: Load microcode later - the 'no eviction' mode breaks this */
+       movl    $MSR_IA32_UCODE_WRITE, %ecx
+       xorl    %edx, %edx
+       movl    $_dt_ucode_base_size, %eax
+       movl    (%eax), %eax
+       addl    $UCODE_HEADER_LEN, %eax
+       wrmsr
+
        post_code(POST_CAR_SIPI)
        /* Zero out all fixed range and variable range MTRRs */
        movl    $mtrr_table, %esi
@@ -222,3 +232,9 @@ mtrr_table:
        .word 0x20C, 0x20D, 0x20E, 0x20F
        .word 0x210, 0x211, 0x212, 0x213
 mtrr_table_end:
+
+       .align 4
+_dt_ucode_base_size:
+       /* These next two fields are filled in by ifdtool */
+       .long   0                       /* microcode base */
+       .long   0                       /* microcode size */
index 0543e06aef68bd714a2926e219829b40517b57cf..e9253100f6e051987ad6995e49836a5c0e0d3b68 100644 (file)
@@ -263,7 +263,7 @@ int print_cpuinfo(void)
        enable_lapic();
 
        ret = microcode_update_intel();
-       if (ret && ret != -ENOENT && ret != -EEXIST)
+       if (ret)
                return ret;
 
        /* Enable upper 128bytes of CMOS */
index 08177510ab6c825ef0bd42a095c6f04206e00ef3..2440a97c484ba801698f2cf1003b924d06161b3b 100644 (file)
@@ -13,7 +13,9 @@
 #include <libfdt.h>
 #include <asm/cpu.h>
 #include <asm/msr.h>
+#include <asm/msr-index.h>
 #include <asm/processor.h>
+#include <asm/arch/microcode.h>
 
 /**
  * struct microcode_update - standard microcode header from Intel
@@ -40,8 +42,8 @@ static int microcode_decode_node(const void *blob, int node,
        update->data = fdt_getprop(blob, node, "data", &update->size);
        if (!update->data)
                return -EINVAL;
-       update->data += 48;
-       update->size -= 48;
+       update->data += UCODE_HEADER_LEN;
+       update->size -= UCODE_HEADER_LEN;
 
        update->header_version = fdtdec_get_int(blob, node,
                                                "intel,header-version", 0);
@@ -71,15 +73,16 @@ static inline uint32_t microcode_read_rev(void)
        asm volatile (
                "xorl %%eax, %%eax\n"
                "xorl %%edx, %%edx\n"
-               "movl $0x8b, %%ecx\n"
+               "movl %2, %%ecx\n"
                "wrmsr\n"
                "movl $0x01, %%eax\n"
                "cpuid\n"
-               "movl $0x8b, %%ecx\n"
+               "movl %2, %%ecx\n"
                "rdmsr\n"
                : /* outputs */
                "=a" (low), "=d" (high)
                : /* inputs */
+               "i" (MSR_IA32_UCODE_REV)
                : /* clobbers */
                 "ebx", "ecx"
        );
@@ -94,9 +97,9 @@ static void microcode_read_cpu(struct microcode_update *cpu)
        struct cpuid_result result;
        uint32_t low, high;
 
-       wrmsr(0x8b, 0, 0);
+       wrmsr(MSR_IA32_UCODE_REV, 0, 0);
        result = cpuid(1);
-       rdmsr(0x8b, low, cpu->update_revision);
+       rdmsr(MSR_IA32_UCODE_REV, low, cpu->update_revision);
        x86_model = (result.eax >> 4) & 0x0f;
        x86_family = (result.eax >> 8) & 0x0f;
        cpu->processor_signature = result.eax;
@@ -120,6 +123,7 @@ int microcode_update_intel(void)
        int count;
        int node;
        int ret;
+       int rev;
 
        microcode_read_cpu(&cpu);
        node = 0;
@@ -147,12 +151,16 @@ int microcode_update_intel(void)
                        skipped++;
                        continue;
                }
-               ret = microcode_read_rev();
-               wrmsr(0x79, (ulong)update.data, 0);
+               wrmsr(MSR_IA32_UCODE_WRITE, (ulong)update.data, 0);
+               rev = microcode_read_rev();
                debug("microcode: updated to revision 0x%x date=%04x-%02x-%02x\n",
-                     microcode_read_rev(), update.date_code & 0xffff,
+                     rev, update.date_code & 0xffff,
                      (update.date_code >> 24) & 0xff,
                      (update.date_code >> 16) & 0xff);
+               if (update.update_revision != rev) {
+                       printf("Microcode update failed\n");
+                       return -EFAULT;
+               }
                count++;
        } while (1);
 }
index 107af60004c4d811671dca927fa20520509151ff..9490b169fb52a3e30c48adca4bef6ffdb148d1f3 100644 (file)
 
        microcode {
                update@0 {
-#include "microcode/m12206a7_00000029.dtsi"
-               };
-               update@1 {
 #include "microcode/m12306a9_0000001b.dtsi"
                };
        };
index bc9b87c44c47729c9f858ec9a741b02318fd1822..b86828376175b67563c5e19a7500c1ed96a1be8b 100644 (file)
@@ -7,6 +7,11 @@
 #ifndef __ASM_ARCH_MICROCODE_H
 #define __ASM_ARCH_MICROCODE_H
 
+/* Length of the public header on Intel microcode blobs */
+#define UCODE_HEADER_LEN       0x30
+
+#ifndef __ASSEMBLY__
+
 /**
  * microcode_update_intel() - Apply microcode updates
  *
@@ -16,5 +21,6 @@
  * not updates were found, -EINVAL if an update was invalid
  */
 int microcode_update_intel(void);
+#endif /* __ASSEMBLY__ */
 
 #endif