From 4f062ec34b6e344e88ceaf7460675a860f10a2b6 Mon Sep 17 00:00:00 2001 From: Krishna Prasad Bhat Date: Thu, 21 Sep 2023 23:33:34 +0530 Subject: [PATCH] soc/intel/cse: Add function to get cse_bp_info early PSR data is created and stored in CSE data partition. In platforms that employ CSE Lite SKU firmware, a firmware downgrade involves clearing of CSE data partition which results in PSR data being lost. The PSR data needs to be preserved across the firmware downgrade flow. CSE Lite SKU firmware supports command to backup PSR data, and this command can be sent only in post-RAM stages. So the cse_fw_sync actions needs to be moved to ramstage. Sending cse_get_bp_info command in ramstage takes additional boot time of ~45-55ms on rex. To avoid the boot time penalty, this patch provides an API to get the cse_bp_info in early romstage. The response data is then migrated to cbmem once memory is initialized. The same data in cbmem can be utilized in ramstage to perform other cse_fw_sync actions. This patch also adds check to validate cse_bp_info in cbmem and avoids sending the command again if the data is valid. BUG=b:273207144 TEST=Verify the command works in early romstage, data is migrated to cbmem and valid data is available in ramstage on rex. Change-Id: Ib1e72c950ba0f4911924805f501ec1bd54b6ba3c Signed-off-by: Krishna Prasad Bhat Signed-off-by: Rizwan Qureshi Reviewed-on: https://review.coreboot.org/c/coreboot/+/78053 Reviewed-by: Subrata Banik Tested-by: build bot (Jenkins) --- src/soc/intel/common/block/cse/cse_lite.c | 82 ++++++++++++++++++- .../common/block/include/intelblocks/cse.h | 3 + 2 files changed, 84 insertions(+), 1 deletion(-) diff --git a/src/soc/intel/common/block/cse/cse_lite.c b/src/soc/intel/common/block/cse/cse_lite.c index 140a56d06f..9ea6c78225 100644 --- a/src/soc/intel/common/block/cse/cse_lite.c +++ b/src/soc/intel/common/block/cse/cse_lite.c @@ -12,6 +12,7 @@ #include #include #include +#include #include #include #include @@ -420,6 +421,38 @@ static bool cse_is_bp_cmd_info_possible(void) return false; } +static struct get_bp_info_rsp *sync_cse_bp_info_to_cbmem(void) +{ + struct get_bp_info_rsp *cse_bp_info_in_cbmem = cbmem_find(CBMEM_ID_CSE_BP_INFO); + + if (cse_bp_info_in_cbmem != NULL) + return cse_bp_info_in_cbmem; + + cse_bp_info_in_cbmem = cbmem_add(CBMEM_ID_CSE_BP_INFO, + sizeof(struct get_bp_info_rsp)); + + if (!cse_bp_info_in_cbmem) { + printk(BIOS_ERR, "Unable to store Boot Parition Info in cbmem\n"); + return NULL; + } + + /* Copy the CSE Boot Partition Info command response to cbmem */ + memcpy(cse_bp_info_in_cbmem, &cse_bp_info_rsp, sizeof(struct get_bp_info_rsp)); + + return cse_bp_info_in_cbmem; +} + +static bool is_cse_bp_info_valid(struct get_bp_info_rsp *bp_info_rsp) +{ + /* + * In case the cse_bp_info_rsp header group ID, command is incorrect or is_resp is 0, + * then return false to indicate cse_bp_info is not valid. + */ + return (bp_info_rsp->hdr.group_id != MKHI_GROUP_ID_BUP_COMMON || + bp_info_rsp->hdr.command != MKHI_BUP_COMMON_GET_BOOT_PARTITION_INFO || + !bp_info_rsp->hdr.is_resp) ? false : true; +} + static enum cb_err cse_get_bp_info(void) { struct get_bp_info_req { @@ -433,6 +466,33 @@ static enum cb_err cse_get_bp_info(void) .reserved = {0}, }; + /* + * If SOC_INTEL_CSE_LITE_SYNC_IN_RAMSTAGE config is selected and memory has been + * initialized, check if there is cse bp info response stored in cbmem. Once the data + * is validated, copy it to the global cse_bp_info_rsp so that it can be used by other + * functions. In case, data is not available in cbmem or invalid, continue to send the + * GET_BOOT_PARTITION_INFO command, else return. + */ + if (CONFIG(SOC_INTEL_CSE_LITE_SYNC_IN_RAMSTAGE) && cbmem_online()) { + struct get_bp_info_rsp *cse_bp_info_in_cbmem = sync_cse_bp_info_to_cbmem(); + if (cse_bp_info_in_cbmem) { + if (is_cse_bp_info_valid(cse_bp_info_in_cbmem)) { + memcpy(&cse_bp_info_rsp, cse_bp_info_in_cbmem, + sizeof(struct get_bp_info_rsp)); + return CB_SUCCESS; + } + } + } else { + /* + * If SOC_INTEL_CSE_LITE_SYNC_IN_ROMSTAGE config is selected, check if the + * global cse bp info response stored in global cse_bp_info_rsp is valid. + * In case, it is not valid, continue to send the GET_BOOT_PARTITION_INFO + * command, else return. + */ + if (is_cse_bp_info_valid(&cse_bp_info_rsp)) + return CB_SUCCESS; + } + if (!cse_is_bp_cmd_info_possible()) { printk(BIOS_ERR, "cse_lite: CSE does not meet prerequisites\n"); return CB_ERR; @@ -453,9 +513,29 @@ static enum cb_err cse_get_bp_info(void) } cse_print_boot_partition_info(); - return CB_SUCCESS; } + +void cse_fill_bp_info(void) +{ + if (vboot_recovery_mode_enabled()) + return; + + if (cse_get_bp_info() != CB_SUCCESS) + cse_trigger_vboot_recovery(CSE_COMMUNICATION_ERROR); +} + +/* Function to copy PRERAM CSE BP info to pertinent CBMEM. */ +static void preram_cse_bp_info_sync_to_cbmem(int is_recovery) +{ + if (vboot_recovery_mode_enabled()) + return; + + sync_cse_bp_info_to_cbmem(); +} + +CBMEM_CREATION_HOOK(preram_cse_bp_info_sync_to_cbmem); + /* * It sends HECI command to notify CSE about its next boot partition. When coreboot wants * CSE to boot from certain partition (BP1 or BP2 ), then this command can be used. diff --git a/src/soc/intel/common/block/include/intelblocks/cse.h b/src/soc/intel/common/block/include/intelblocks/cse.h index ae9fe941c6..0f7356854d 100644 --- a/src/soc/intel/common/block/include/intelblocks/cse.h +++ b/src/soc/intel/common/block/include/intelblocks/cse.h @@ -572,4 +572,7 @@ void cse_enable_ptt(bool state); */ enum cb_err cse_get_fw_feature_state(uint32_t *feature_state); +/* Fills the CSE Boot Partition Info response */ +void cse_fill_bp_info(void); + #endif // SOC_INTEL_COMMON_CSE_H