intel microcode: split up microcode loading stages

This patch only applies to CONFIG_MICROCODE_IN_CBFS. The intel microcode
update routine would always walk the CBFS for the microcode file. Then
it would loop through the whole file looking for a match then load the
microcode. This process was maintained for intel_update_microcode_from_cbfs(),
however 2 new functions were exported:
	1.  const void *intel_microcode_find(void)
	2.  void intel_microcode_load_unlocked(const void *microcode_patch)

The first locates a matching microcode while the second loads that
mircocode. These new functions can then be used to cache the found
microcode blob w/o having to re-walk the CBFS.

Booted baskingridge board to Linux and noted that all microcode
revisions match on all the CPUs.

Change-Id: Ifde3f3e5c100911c4f984dd56d36664a8acdf7d5
Signed-off-by: Aaron Durbin <adurbin@chromium.org>
Reviewed-on: http://review.coreboot.org/2778
Tested-by: build bot (Jenkins)
Reviewed-by: Ronald G. Minnich <rminnich@gmail.com>
This commit is contained in:
Aaron Durbin 2013-01-15 15:15:32 -06:00 committed by Ronald G. Minnich
parent 3c734bb355
commit 98ffb426f4
2 changed files with 117 additions and 18 deletions

View File

@ -82,8 +82,117 @@ static inline u32 read_microcode_rev(void)
}
#if CONFIG_CPU_MICROCODE_IN_CBFS
static
#define MICROCODE_CBFS_FILE "cpu_microcode_blob.bin"
void intel_microcode_load_unlocked(const void *microcode_patch)
{
u32 current_rev;
msr_t msr;
const struct microcode *m = microcode_patch;
if (!m)
return;
current_rev = read_microcode_rev();
/* No use loading the same revision. */
if (current_rev == m->rev)
return;
msr.lo = (unsigned long)m + sizeof(struct microcode);
msr.hi = 0;
wrmsr(0x79, msr);
#if !defined(__ROMCC__)
printk(BIOS_DEBUG, "microcode: updated to revision "
"0x%x date=%04x-%02x-%02x\n", read_microcode_rev(),
m->date & 0xffff, (m->date >> 24) & 0xff,
(m->date >> 16) & 0xff);
#endif
}
const void *intel_microcode_find(void)
{
void *microcode_updates;
u32 eax;
u32 pf, rev, sig;
unsigned int x86_model, x86_family;
const struct microcode *m;
const char *c;
msr_t msr;
#ifdef __PRE_RAM__
microcode_updates = walkcbfs((char *) MICROCODE_CBFS_FILE);
#else
microcode_updates = cbfs_get_file_content(CBFS_DEFAULT_MEDIA,
MICROCODE_CBFS_FILE,
CBFS_TYPE_MICROCODE);
#endif
if (!microcode_updates)
return microcode_updates;
/* CPUID sets MSR 0x8B iff a microcode update has been loaded. */
msr.lo = 0;
msr.hi = 0;
wrmsr(0x8B, msr);
eax = cpuid_eax(1);
msr = rdmsr(0x8B);
rev = msr.hi;
x86_model = (eax >>4) & 0x0f;
x86_family = (eax >>8) & 0x0f;
sig = eax;
pf = 0;
if ((x86_model >= 5)||(x86_family>6)) {
msr = rdmsr(0x17);
pf = 1 << ((msr.hi >> 18) & 7);
}
#if !defined(__ROMCC__)
/* If this code is compiled with ROMCC we're probably in
* the bootblock and don't have console output yet.
*/
printk(BIOS_DEBUG, "microcode: sig=0x%x pf=0x%x revision=0x%x\n",
sig, pf, rev);
#endif
m = microcode_updates;
for(c = microcode_updates; m->hdrver; m = (const struct microcode *)c) {
if ((m->sig == sig) && (m->pf & pf))
return m;
if (m->total_size) {
c += m->total_size;
} else {
#if !defined(__ROMCC__)
printk(BIOS_WARNING, "Microcode has no valid size field!\n");
#endif
c += 2048;
}
}
/* ROMCC doesn't like NULL. */
return (void *)0;
}
void intel_update_microcode_from_cbfs(void)
{
const void *patch = intel_microcode_find();
#if !defined(__ROMCC__) && !defined(__PRE_RAM__)
spin_lock(&microcode_lock);
#endif
intel_microcode_load_unlocked(patch);
#if !defined(__ROMCC__) && !defined(__PRE_RAM__)
spin_unlock(&microcode_lock);
#endif
}
#else /* !CONFIG_CPU_MICROCODE_IN_CBFS */
void intel_update_microcode(const void *microcode_updates)
{
u32 eax;
@ -155,21 +264,4 @@ void intel_update_microcode(const void *microcode_updates)
#endif
}
#if CONFIG_CPU_MICROCODE_IN_CBFS
#define MICROCODE_CBFS_FILE "cpu_microcode_blob.bin"
void intel_update_microcode_from_cbfs(void)
{
void *microcode_blob;
#ifdef __PRE_RAM__
microcode_blob = walkcbfs((char *) MICROCODE_CBFS_FILE);
#else
microcode_blob = cbfs_get_file_content(CBFS_DEFAULT_MEDIA,
MICROCODE_CBFS_FILE,
CBFS_TYPE_MICROCODE);
#endif
intel_update_microcode(microcode_blob);
}
#endif

View File

@ -23,6 +23,13 @@
#ifndef __PRE_RAM__
#if CONFIG_CPU_MICROCODE_IN_CBFS
void intel_update_microcode_from_cbfs(void);
/* Find a microcode that matches the revision and platform family returning
* NULL if none found. */
const void *intel_microcode_find(void);
/* It is up to the caller to determine if parallel loading is possible as
* well as ensuring the micrcode matches the family and revision (i.e. with
* intel_microcode_find()). */
void intel_microcode_load_unlocked(const void *microcode_patch);
#else
void intel_update_microcode(const void *microcode_updates);
#endif