summaryrefslogtreecommitdiffstats
path: root/arch/x86/cpu
diff options
context:
space:
mode:
authorSimon Glass <sjg@chromium.org>2015-01-01 16:18:14 -0700
committerSimon Glass <sjg@chromium.org>2015-01-13 07:25:02 -0800
commitc72f74e2780350f16795dc4d69145b9c87cb3e97 (patch)
tree7a9b2cfce7be84f60e9e692049983a1c506da819 /arch/x86/cpu
parent801d70ce026be4595e595fb6790621a6a898cee9 (diff)
downloadtalos-obmc-uboot-c72f74e2780350f16795dc4d69145b9c87cb3e97.tar.gz
talos-obmc-uboot-c72f74e2780350f16795dc4d69145b9c87cb3e97.zip
x86: ivybridge: Update microcode early in boot
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>
Diffstat (limited to 'arch/x86/cpu')
-rw-r--r--arch/x86/cpu/ivybridge/car.S16
-rw-r--r--arch/x86/cpu/ivybridge/cpu.c2
-rw-r--r--arch/x86/cpu/ivybridge/microcode_intel.c26
3 files changed, 34 insertions, 10 deletions
diff --git a/arch/x86/cpu/ivybridge/car.S b/arch/x86/cpu/ivybridge/car.S
index d5f1acfe3d..9441666f5a 100644
--- a/arch/x86/cpu/ivybridge/car.S
+++ b/arch/x86/cpu/ivybridge/car.S
@@ -12,9 +12,11 @@
*/
#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 */
diff --git a/arch/x86/cpu/ivybridge/cpu.c b/arch/x86/cpu/ivybridge/cpu.c
index 0543e06aef..e9253100f6 100644
--- a/arch/x86/cpu/ivybridge/cpu.c
+++ b/arch/x86/cpu/ivybridge/cpu.c
@@ -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 */
diff --git a/arch/x86/cpu/ivybridge/microcode_intel.c b/arch/x86/cpu/ivybridge/microcode_intel.c
index 08177510ab..2440a97c48 100644
--- a/arch/x86/cpu/ivybridge/microcode_intel.c
+++ b/arch/x86/cpu/ivybridge/microcode_intel.c
@@ -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);
}
OpenPOWER on IntegriCloud