diff mbox

[U-Boot,v2,21/22] x86: ivybridge: Update microcode early in boot

Message ID 1420154295-16633-22-git-send-email-sjg@chromium.org
State Accepted
Delegated to: Simon Glass
Headers show

Commit Message

Simon Glass Jan. 1, 2015, 11:18 p.m. UTC
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>
---

Changes in v2:
- Use constants for microcode MSRs and header length

 arch/x86/cpu/ivybridge/car.S                    | 16 +++++++++++++++
 arch/x86/cpu/ivybridge/cpu.c                    |  2 +-
 arch/x86/cpu/ivybridge/microcode_intel.c        | 26 ++++++++++++++++---------
 arch/x86/dts/link.dts                           |  3 ---
 arch/x86/include/asm/arch-ivybridge/microcode.h |  6 ++++++
 5 files changed, 40 insertions(+), 13 deletions(-)

Comments

Simon Glass Jan. 5, 2015, 5:41 p.m. UTC | #1
On 1 January 2015 at 16:18, Simon Glass <sjg@chromium.org> wrote:
> 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>
> ---
>
> Changes in v2:
> - Use constants for microcode MSRs and header length

Applied to u-boot-x86/next.

>
>  arch/x86/cpu/ivybridge/car.S                    | 16 +++++++++++++++
>  arch/x86/cpu/ivybridge/cpu.c                    |  2 +-
>  arch/x86/cpu/ivybridge/microcode_intel.c        | 26 ++++++++++++++++---------
>  arch/x86/dts/link.dts                           |  3 ---
>  arch/x86/include/asm/arch-ivybridge/microcode.h |  6 ++++++
>  5 files changed, 40 insertions(+), 13 deletions(-)
diff mbox

Patch

diff --git a/arch/x86/cpu/ivybridge/car.S b/arch/x86/cpu/ivybridge/car.S
index d5f1acf..9441666 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 0543e06..e925310 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 0817751..2440a97 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);
 }
diff --git a/arch/x86/dts/link.dts b/arch/x86/dts/link.dts
index a739080..1ebc334 100644
--- a/arch/x86/dts/link.dts
+++ b/arch/x86/dts/link.dts
@@ -214,9 +214,6 @@ 
 
 	microcode {
 		update@0 {
-#include "microcode/m12206a7_00000029.dtsi"
-		};
-		update@1 {
 #include "microcode/m12306a9_0000001b.dtsi"
 		};
 	};
diff --git a/arch/x86/include/asm/arch-ivybridge/microcode.h b/arch/x86/include/asm/arch-ivybridge/microcode.h
index bc9b87c..b868283 100644
--- a/arch/x86/include/asm/arch-ivybridge/microcode.h
+++ b/arch/x86/include/asm/arch-ivybridge/microcode.h
@@ -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