soc/amd/common/block/cpu: Refactor ucode allocation
Move microcode load/unload to pre_mp_init and post_mp_init callbacks. It allows to make sure that ucode is freed only if all APs updated microcode. BUG=b:278264488 TEST=Build and run with additional debug prints added to confirm that data are correctly unmapped Change-Id: I200d24df6157cc6d06bade34809faefea9f0090a Signed-off-by: Grzegorz Bernacki <bernacki@google.com> Reviewed-on: https://review.coreboot.org/c/coreboot/+/74777 Tested-by: build bot (Jenkins) <no-reply@coreboot.org> Reviewed-by: Karthik Ramasubramanian <kramasub@google.com>
This commit is contained in:
parent
9d6008ea5b
commit
d34dbe5888
|
@ -4,6 +4,9 @@
|
||||||
#define CPU_AMD_MICROCODE_H
|
#define CPU_AMD_MICROCODE_H
|
||||||
|
|
||||||
void amd_update_microcode_from_cbfs(void);
|
void amd_update_microcode_from_cbfs(void);
|
||||||
|
void amd_load_microcode_from_cbfs(void);
|
||||||
|
void amd_free_microcode(void);
|
||||||
|
void amd_apply_microcode_patch(void);
|
||||||
void preload_microcode(void);
|
void preload_microcode(void);
|
||||||
|
|
||||||
#endif /* CPU_AMD_MICROCODE_H */
|
#endif /* CPU_AMD_MICROCODE_H */
|
||||||
|
|
|
@ -39,7 +39,7 @@ static void zen_2_3_init(struct device *dev)
|
||||||
check_mca();
|
check_mca();
|
||||||
set_cstate_io_addr();
|
set_cstate_io_addr();
|
||||||
|
|
||||||
amd_update_microcode_from_cbfs();
|
amd_apply_microcode_patch();
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct device_operations cpu_dev_ops = {
|
static struct device_operations cpu_dev_ops = {
|
||||||
|
|
|
@ -6,6 +6,7 @@
|
||||||
#include <amdblocks/smm.h>
|
#include <amdblocks/smm.h>
|
||||||
#include <console/console.h>
|
#include <console/console.h>
|
||||||
#include <cpu/amd/amd64_save_state.h>
|
#include <cpu/amd/amd64_save_state.h>
|
||||||
|
#include <cpu/amd/microcode.h>
|
||||||
#include <cpu/amd/msr.h>
|
#include <cpu/amd/msr.h>
|
||||||
#include <cpu/amd/mtrr.h>
|
#include <cpu/amd/mtrr.h>
|
||||||
#include <cpu/cpu.h>
|
#include <cpu/cpu.h>
|
||||||
|
@ -22,6 +23,8 @@ static void pre_mp_init(void)
|
||||||
else
|
else
|
||||||
x86_setup_mtrrs_with_detect();
|
x86_setup_mtrrs_with_detect();
|
||||||
x86_mtrr_check();
|
x86_mtrr_check();
|
||||||
|
if (CONFIG(SOC_AMD_COMMON_BLOCK_UCODE))
|
||||||
|
amd_load_microcode_from_cbfs();
|
||||||
}
|
}
|
||||||
|
|
||||||
static void get_smm_info(uintptr_t *perm_smbase, size_t *perm_smsize,
|
static void get_smm_info(uintptr_t *perm_smbase, size_t *perm_smsize,
|
||||||
|
@ -83,10 +86,17 @@ static void smm_relocation_handler(void)
|
||||||
lock_smm();
|
lock_smm();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void post_mp_init(void)
|
||||||
|
{
|
||||||
|
if (CONFIG(SOC_AMD_COMMON_BLOCK_UCODE))
|
||||||
|
amd_free_microcode();
|
||||||
|
global_smi_enable();
|
||||||
|
}
|
||||||
|
|
||||||
const struct mp_ops amd_mp_ops_with_smm = {
|
const struct mp_ops amd_mp_ops_with_smm = {
|
||||||
.pre_mp_init = pre_mp_init,
|
.pre_mp_init = pre_mp_init,
|
||||||
.get_cpu_count = get_cpu_count,
|
.get_cpu_count = get_cpu_count,
|
||||||
.get_smm_info = get_smm_info,
|
.get_smm_info = get_smm_info,
|
||||||
.per_cpu_smm_trigger = smm_relocation_handler,
|
.per_cpu_smm_trigger = smm_relocation_handler,
|
||||||
.post_mp_init = global_smi_enable,
|
.post_mp_init = post_mp_init,
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
/* SPDX-License-Identifier: GPL-2.0-only */
|
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||||
|
|
||||||
|
#include <amdblocks/cpu.h>
|
||||||
#include <cbfs.h>
|
#include <cbfs.h>
|
||||||
#include <commonlib/helpers.h>
|
#include <commonlib/helpers.h>
|
||||||
#include <console/console.h>
|
#include <console/console.h>
|
||||||
|
@ -32,21 +33,30 @@ struct microcode {
|
||||||
uint8_t reserved2[4];
|
uint8_t reserved2[4];
|
||||||
} __packed;
|
} __packed;
|
||||||
|
|
||||||
static void apply_microcode_patch(const struct microcode *m)
|
static const struct microcode *ucode;
|
||||||
|
|
||||||
|
/* This function requires the ucode variable to be initialized by amd_load_microcode_from_cbfs()
|
||||||
|
and then allocated memory should be freed by the amd_free_microcode(). */
|
||||||
|
void amd_apply_microcode_patch(void)
|
||||||
{
|
{
|
||||||
uint32_t new_patch_id;
|
uint32_t new_patch_id;
|
||||||
msr_t msr;
|
msr_t msr;
|
||||||
|
|
||||||
msr.raw = (uintptr_t)m;
|
if (!ucode) {
|
||||||
|
printk(BIOS_ERR, "%s: NULL pointer to microcode\n", __func__);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
msr.raw = (uintptr_t)ucode;
|
||||||
|
|
||||||
wrmsr(MSR_PATCH_LOADER, msr);
|
wrmsr(MSR_PATCH_LOADER, msr);
|
||||||
|
|
||||||
printk(BIOS_DEBUG, "microcode: patch id to apply = 0x%08x\n", m->patch_id);
|
printk(BIOS_DEBUG, "microcode: patch id to apply = 0x%08x\n", ucode->patch_id);
|
||||||
|
|
||||||
msr = rdmsr(IA32_BIOS_SIGN_ID);
|
msr = rdmsr(IA32_BIOS_SIGN_ID);
|
||||||
new_patch_id = msr.lo;
|
new_patch_id = msr.lo;
|
||||||
|
|
||||||
if (new_patch_id == m->patch_id)
|
if (new_patch_id == ucode->patch_id)
|
||||||
printk(BIOS_INFO, "microcode: being updated to patch id = 0x%08x succeeded\n",
|
printk(BIOS_INFO, "microcode: being updated to patch id = 0x%08x succeeded\n",
|
||||||
new_patch_id);
|
new_patch_id);
|
||||||
else
|
else
|
||||||
|
@ -61,11 +71,11 @@ static uint16_t get_equivalent_processor_rev_id(void)
|
||||||
return (uint16_t)((cpuid_family & 0xff0000) >> 8 | (cpuid_family & 0xff));
|
return (uint16_t)((cpuid_family & 0xff0000) >> 8 | (cpuid_family & 0xff));
|
||||||
}
|
}
|
||||||
|
|
||||||
static const struct microcode *find_microcode(const struct microcode *ucode,
|
static const struct microcode *find_microcode(const struct microcode *microcode,
|
||||||
uint16_t equivalent_processor_rev_id)
|
uint16_t equivalent_processor_rev_id)
|
||||||
{
|
{
|
||||||
if (ucode->processor_rev_id == equivalent_processor_rev_id)
|
if (microcode->processor_rev_id == equivalent_processor_rev_id)
|
||||||
return ucode;
|
return microcode;
|
||||||
|
|
||||||
printk(BIOS_WARNING, "Failed to find microcode for processor rev: %hx.\n",
|
printk(BIOS_WARNING, "Failed to find microcode for processor rev: %hx.\n",
|
||||||
equivalent_processor_rev_id);
|
equivalent_processor_rev_id);
|
||||||
|
@ -73,39 +83,41 @@ static const struct microcode *find_microcode(const struct microcode *ucode,
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
void amd_update_microcode_from_cbfs(void)
|
void amd_load_microcode_from_cbfs(void)
|
||||||
{
|
{
|
||||||
static const struct microcode *ucode_cache;
|
|
||||||
static bool cache_valid;
|
|
||||||
|
|
||||||
struct microcode *ucode;
|
|
||||||
char name[] = CPU_MICROCODE_BLOB_NAME;
|
char name[] = CPU_MICROCODE_BLOB_NAME;
|
||||||
uint16_t equivalent_processor_rev_id;
|
uint16_t equivalent_processor_rev_id;
|
||||||
|
|
||||||
/* Cache the buffer so each CPU doesn't need to read the uCode from flash */
|
if (ucode)
|
||||||
/* Note that this code assumes all cores are the same */
|
return;
|
||||||
if (!cache_valid) {
|
|
||||||
timestamp_add_now(TS_READ_UCODE_START);
|
|
||||||
equivalent_processor_rev_id = get_equivalent_processor_rev_id();
|
|
||||||
snprintf(name, sizeof(name), CPU_MICROCODE_BLOB_FORMAT, equivalent_processor_rev_id);
|
|
||||||
ucode = cbfs_map(name, NULL);
|
|
||||||
if (!ucode) {
|
|
||||||
printk(BIOS_WARNING, "%s not found. Skipping updates.\n", name);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
ucode_cache = find_microcode(ucode, equivalent_processor_rev_id);
|
/* Store the pointer to the buffer in global variable, so each CPU doesn't need to read
|
||||||
|
* the uCode from flash. Note that this code assumes all cores are the same */
|
||||||
|
timestamp_add_now(TS_READ_UCODE_START);
|
||||||
|
equivalent_processor_rev_id = get_equivalent_processor_rev_id();
|
||||||
|
snprintf(name, sizeof(name), CPU_MICROCODE_BLOB_FORMAT, equivalent_processor_rev_id);
|
||||||
|
|
||||||
if (!ucode_cache) {
|
ucode = cbfs_map(name, NULL);
|
||||||
cbfs_unmap(ucode);
|
if (!ucode) {
|
||||||
return;
|
printk(BIOS_WARNING, "%s not found. Skipping updates.\n", name);
|
||||||
}
|
|
||||||
|
|
||||||
cache_valid = true;
|
|
||||||
timestamp_add_now(TS_READ_UCODE_END);
|
timestamp_add_now(TS_READ_UCODE_END);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
apply_microcode_patch(ucode_cache);
|
if (find_microcode(ucode, equivalent_processor_rev_id) == NULL) {
|
||||||
|
cbfs_unmap((void *)ucode);
|
||||||
|
ucode = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
timestamp_add_now(TS_READ_UCODE_END);
|
||||||
|
}
|
||||||
|
|
||||||
|
void amd_free_microcode(void)
|
||||||
|
{
|
||||||
|
if (ucode) {
|
||||||
|
cbfs_unmap((void *)ucode);
|
||||||
|
ucode = NULL;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void preload_microcode(void)
|
void preload_microcode(void)
|
||||||
|
|
|
@ -42,7 +42,7 @@ static void zen_2_3_init(struct device *dev)
|
||||||
check_mca();
|
check_mca();
|
||||||
set_cstate_io_addr();
|
set_cstate_io_addr();
|
||||||
|
|
||||||
amd_update_microcode_from_cbfs();
|
amd_apply_microcode_patch();
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct device_operations cpu_dev_ops = {
|
static struct device_operations cpu_dev_ops = {
|
||||||
|
|
|
@ -40,7 +40,7 @@ static void zen_2_3_init(struct device *dev)
|
||||||
check_mca();
|
check_mca();
|
||||||
set_cstate_io_addr();
|
set_cstate_io_addr();
|
||||||
|
|
||||||
amd_update_microcode_from_cbfs();
|
amd_apply_microcode_patch();
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct device_operations cpu_dev_ops = {
|
static struct device_operations cpu_dev_ops = {
|
||||||
|
|
|
@ -42,7 +42,7 @@ static void zen_2_3_init(struct device *dev)
|
||||||
check_mca();
|
check_mca();
|
||||||
set_cstate_io_addr();
|
set_cstate_io_addr();
|
||||||
|
|
||||||
amd_update_microcode_from_cbfs();
|
amd_apply_microcode_patch();
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct device_operations cpu_dev_ops = {
|
static struct device_operations cpu_dev_ops = {
|
||||||
|
|
|
@ -40,7 +40,7 @@ static void model_17_init(struct device *dev)
|
||||||
check_mca();
|
check_mca();
|
||||||
set_cstate_io_addr();
|
set_cstate_io_addr();
|
||||||
|
|
||||||
amd_update_microcode_from_cbfs();
|
amd_apply_microcode_patch();
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct device_operations cpu_dev_ops = {
|
static struct device_operations cpu_dev_ops = {
|
||||||
|
|
Loading…
Reference in New Issue