soc/amd/common/block/cpu: Cache the uCode to avoid multiple SPI reads

We are currently reading the uCode for each CPU. This is unnecessary
since the uCode never changes.

BUG=b:177909625
TEST=Boot guybrush and see "microcode: being updated to patch id" for
each CPU. I no longer see CBFS access for each CPU. This drops device
initialization time by 32 ms.
Also boot Ezkinil and verify microcode was also updated.

Signed-off-by: Raul E Rangel <rrangel@chromium.org>
Change-Id: I98b9d4ce8290a1f08063176809e903e671663208
Reviewed-on: https://review.coreboot.org/c/coreboot/+/55987
Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
Reviewed-by: Furquan Shaikh <furquan@google.com>
Reviewed-by: Karthik Ramasubramanian <kramasub@google.com>
This commit is contained in:
Raul E Rangel 2021-06-30 14:39:29 -06:00 committed by Raul Rangel
parent 9942af2b5b
commit 35e27b34f5
1 changed files with 37 additions and 13 deletions

View File

@ -34,6 +34,8 @@ struct microcode {
uint8_t m_patch_data[MPB_MAX_SIZE-MPB_DATA_OFFSET];
} __packed;
_Static_assert(sizeof(struct microcode) == MPB_MAX_SIZE, "microcode size is invalid");
static void apply_microcode_patch(const struct microcode *m)
{
uint32_t new_patch_id;
@ -65,29 +67,51 @@ static uint16_t get_equivalent_processor_rev_id(void)
return (uint16_t)((cpuid_family & 0xff0000) >> 8 | (cpuid_family & 0xff));
}
static void amd_update_microcode(const void *ucode, size_t ucode_len,
uint16_t equivalent_processor_rev_id)
static const struct microcode *find_microcode(const struct microcode *ucode, size_t ucode_len)
{
uint16_t equivalent_processor_rev_id = get_equivalent_processor_rev_id();
const struct microcode *m;
for (m = (struct microcode *)ucode;
m < (struct microcode *)ucode + ucode_len/MPB_MAX_SIZE; m++) {
for (m = ucode; m < ucode + ucode_len / MPB_MAX_SIZE; m++) {
if (m->processor_rev_id == equivalent_processor_rev_id)
apply_microcode_patch(m);
return m;
}
printk(BIOS_WARNING, "Failed to find microcode for processor rev: %hx.\n",
equivalent_processor_rev_id);
return NULL;
}
void amd_update_microcode_from_cbfs(void)
{
const void *ucode;
size_t ucode_len;
uint16_t equivalent_processor_rev_id = get_equivalent_processor_rev_id();
static struct microcode ucode_cache;
static bool cache_valid;
ucode = cbfs_map("cpu_microcode_blob.bin", &ucode_len);
if (!ucode) {
printk(BIOS_WARNING, "cpu_microcode_blob.bin not found. Skipping updates.\n");
return;
struct microcode *ucode_list;
const struct microcode *matching_ucode;
size_t ucode_len;
/* Cache the buffer so each CPU doesn't need to read the uCode from flash */
if (!cache_valid) {
ucode_list = cbfs_map("cpu_microcode_blob.bin", &ucode_len);
if (!ucode_list) {
printk(BIOS_WARNING, "cpu_microcode_blob.bin not found. Skipping updates.\n");
return;
}
matching_ucode = find_microcode(ucode_list, ucode_len);
if (!matching_ucode) {
cbfs_unmap(ucode_list);
return;
}
ucode_cache = *matching_ucode;
cache_valid = true;
cbfs_unmap(ucode_list);
}
amd_update_microcode(ucode, ucode_len, equivalent_processor_rev_id);
apply_microcode_patch(&ucode_cache);
}