summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAnil Kumar <anil.kumar.k@intel.corp-partner.google.com>2023-04-18 11:03:34 -0700
committerSubrata Banik <subratabanik@google.com>2023-10-04 05:50:56 +0000
commit7b2edc3b6b5ecd37112d5e07f4601b68b2aea038 (patch)
tree6098aa9178929601cf78e8171b3ea15c17357762
parent98fb5ffd6b934edd5be7c9ac753d2763dfbafba9 (diff)
downloadcoreboot-7b2edc3b6b5ecd37112d5e07f4601b68b2aea038.tar.gz
coreboot-7b2edc3b6b5ecd37112d5e07f4601b68b2aea038.tar.bz2
coreboot-7b2edc3b6b5ecd37112d5e07f4601b68b2aea038.zip
soc/intel/cse: Back up PSR data during CSE FW downgrade
During CSE FW downgrade we erase CSE data. This would result in Platform Service Record(PSR) data also to be erased. To avoid losing PSR data we need to make a backup before data clear. This patch sends PSR_HECI_FW_DOWNGRADE_BACKUP HECI command to CSE, informing the CSE to backup PSR data before a data clear operation during downgrade. CMOS memory is used to track the backup status. PENDING is the default state, it is updated to DONE once PSR_HECI_FW_DOWNGRADE_BACKUP HECI command is sent. PSR data can be backed up only post DRAM is initialized. The idea is to perform cse_fw_sync actions in ramstage when PSR is enabled on a platform. As part of the cse_fw_sync actions, when a firmware downgrade is requested the command to back-up data is sent. Once the backup has been done, trigger the firmware downgrade. BRANCH=None BUG=b:273207144 TEST=build CB image for google/rex board and check PSR backup command is being sent during a CSE FW downgrade. Also check PSR data is not lost/erased after a downgrade using intel PSR tool. Change-Id: I135d197b5df0a20def823fe615860b5ead4391f8 Signed-off-by: Anil Kumar <anil.kumar.k@intel.com> Signed-off-by: Krishna Prasad Bhat <krishna.p.bhat.d@intel.com> Signed-off-by: Rizwan Qureshi <rizwan.qureshi@intel.com> Reviewed-on: https://review.coreboot.org/c/coreboot/+/74577 Reviewed-by: Subrata Banik <subratabanik@google.com> Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
-rw-r--r--src/soc/intel/common/block/cse/cse_lite.c78
-rw-r--r--src/soc/intel/common/block/include/intelblocks/cse.h24
2 files changed, 102 insertions, 0 deletions
diff --git a/src/soc/intel/common/block/cse/cse_lite.c b/src/soc/intel/common/block/cse/cse_lite.c
index 9ea6c782254c..d0b287368bdd 100644
--- a/src/soc/intel/common/block/cse/cse_lite.c
+++ b/src/soc/intel/common/block/cse/cse_lite.c
@@ -995,6 +995,10 @@ static enum cb_err cse_prep_for_rw_update(enum cse_update_status status)
return CB_ERR;
if ((status == CSE_UPDATE_DOWNGRADE) || (status == CSE_UPDATE_CORRUPTED)) {
+ /* Reset the PSR backup command status in CMOS */
+ if (CONFIG(SOC_INTEL_CSE_LITE_PSR))
+ update_psr_backup_status(PSR_BACKUP_PENDING);
+
if (cse_data_clear_request() != CB_SUCCESS) {
printk(BIOS_ERR, "cse_lite: CSE data clear failed!\n");
return CB_ERR;
@@ -1055,6 +1059,78 @@ error_exit:
return rv;
}
+static bool is_psr_data_backed_up(void)
+{
+ /* Track PSR backup status in CMOS */
+ return (get_psr_backup_status() == PSR_BACKUP_DONE);
+}
+
+/*
+ * PSR data needs to be backed up prior to downgrade. So switch the CSE boot mode to RW, send
+ * PSR back-up command to CSE and update the PSR back-up state in CMOS.
+ */
+static void backup_psr_data(void)
+{
+ printk(BIOS_DEBUG, "cse_lite: Initiate PSR data backup flow\n");
+ /* Switch CSE to RW to send PSR_HECI_FW_DOWNGRADE_BACKUP command */
+ if (cse_boot_to_rw() != CB_SUCCESS)
+ goto update_and_exit;
+
+ /*
+ * Prerequisites:
+ * 1) HFSTS1 Current Working State is Normal
+ * 2) HFSTS1 Current Operation Mode is Normal
+ */
+ if (!cse_is_hfs1_cws_normal() || !cse_is_hfs1_com_normal()) {
+ printk(BIOS_DEBUG, "cse_lite: PSR_HECI_FW_DOWNGRADE_BACKUP command "
+ "prerequisites not met!\n");
+ goto update_and_exit;
+ }
+
+ /* Send PSR_HECI_FW_DOWNGRADE_BACKUP command */
+ struct psr_heci_fw_downgrade_backup_req {
+ struct psr_heci_header header;
+ } __packed;
+
+ struct psr_heci_fw_downgrade_backup_req req = {
+ .header.command = PSR_HECI_FW_DOWNGRADE_BACKUP,
+ };
+
+ struct psr_heci_fw_downgrade_backup_res {
+ struct psr_heci_header header;
+ uint32_t status;
+ } __packed;
+
+ struct psr_heci_fw_downgrade_backup_res backup_psr_resp;
+ size_t resp_size = sizeof(backup_psr_resp);
+
+ printk(BIOS_DEBUG, "cse_lite: Send PSR_HECI_FW_DOWNGRADE_BACKUP command\n");
+ if (heci_send_receive(&req, sizeof(req),
+ &backup_psr_resp, &resp_size, HECI_PSR_ADDR))
+ printk(BIOS_ERR, "cse_lite: could not backup PSR data\n");
+ else
+ if (backup_psr_resp.status != PSR_STATUS_SUCCESS)
+ printk(BIOS_ERR, "cse_lite: PSR_HECI_FW_DOWNGRADE_BACKUP command "
+ "returned %u\n", backup_psr_resp.status);
+
+update_and_exit:
+ /*
+ * An attempt to send PSR back-up command has been made. Update this info in CMOS and
+ * send success once backup_psr_data() has been called. We do not want to put the system
+ * into recovery for PSR data backup command pre-requisites not being met.
+ */
+ update_psr_backup_status(PSR_BACKUP_DONE);
+ return;
+}
+
+static void initiate_psr_data_backup(void)
+{
+ if (is_psr_data_backed_up())
+ return;
+
+ backup_psr_data();
+}
+
static uint8_t cse_fw_update(void)
{
struct region_device target_rdev;
@@ -1070,6 +1146,8 @@ static uint8_t cse_fw_update(void)
return CSE_NO_ERROR;
if (status == CSE_UPDATE_METADATA_ERROR)
return CSE_LITE_SKU_RW_METADATA_NOT_FOUND;
+ if (CONFIG(SOC_INTEL_CSE_LITE_PSR) && status == CSE_UPDATE_DOWNGRADE)
+ initiate_psr_data_backup();
printk(BIOS_DEBUG, "cse_lite: CSE RW update is initiated\n");
return cse_trigger_fw_update(status, &target_rdev);
diff --git a/src/soc/intel/common/block/include/intelblocks/cse.h b/src/soc/intel/common/block/include/intelblocks/cse.h
index ebf20ed85732..b177e1364fd7 100644
--- a/src/soc/intel/common/block/include/intelblocks/cse.h
+++ b/src/soc/intel/common/block/include/intelblocks/cse.h
@@ -80,6 +80,9 @@ enum me_fw_sku {
/* Number of cse boot performance data */
#define NUM_CSE_BOOT_PERF_DATA 64
+/* PSR_HECI_FW_DOWNGRADE_BACKUP Command */
+#define PSR_HECI_FW_DOWNGRADE_BACKUP 0x3
+
/* HFSTS register offsets in PCI config space */
enum {
PCI_ME_HFSTS1 = 0x40,
@@ -105,6 +108,24 @@ struct mkhi_hdr {
uint8_t result;
} __packed;
+/* PSR HECI message status */
+enum psr_status {
+ PSR_STATUS_SUCCESS,
+ PSR_STATUS_FEATURE_NOT_SUPPORTED,
+ PSR_STATUS_UPID_DISABLED,
+ PSR_STATUS_ACTION_NOT_ALLOWED,
+ PSR_STATUS_INVALID_INPUT_PARAMETER,
+ PSR_STATUS_INTERNAL_ERROR,
+ PSR_STATUS_NOT_ALLOWED_AFTER_EOP,
+};
+
+/* PSR HECI message header */
+struct psr_heci_header {
+ uint8_t command;
+ uint8_t reserved;
+ uint16_t length;
+} __packed;
+
/* CSE FW Version */
struct fw_version {
uint16_t major;
@@ -398,6 +419,9 @@ int cse_hmrfpo_get_status(void);
/* Fixed Address MEI Header's ME Address field value */
#define HECI_MKHI_ADDR 0x07
+/* Fixed Address MEI Header's ME Address field value for PSR messages */
+#define HECI_PSR_ADDR 0x04
+
/* Fixed Address MEI Header's ME Address for MEI bus messages */
#define HECI_MEI_ADDR 0x00