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>
This commit is contained in:
Anil Kumar 2023-04-18 11:03:34 -07:00 committed by Subrata Banik
parent 98fb5ffd6b
commit 7b2edc3b6b
2 changed files with 102 additions and 0 deletions

View File

@ -995,6 +995,10 @@ static enum cb_err cse_prep_for_rw_update(enum cse_update_status status)
return CB_ERR; return CB_ERR;
if ((status == CSE_UPDATE_DOWNGRADE) || (status == CSE_UPDATE_CORRUPTED)) { 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) { if (cse_data_clear_request() != CB_SUCCESS) {
printk(BIOS_ERR, "cse_lite: CSE data clear failed!\n"); printk(BIOS_ERR, "cse_lite: CSE data clear failed!\n");
return CB_ERR; return CB_ERR;
@ -1055,6 +1059,78 @@ error_exit:
return rv; 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) static uint8_t cse_fw_update(void)
{ {
struct region_device target_rdev; struct region_device target_rdev;
@ -1070,6 +1146,8 @@ static uint8_t cse_fw_update(void)
return CSE_NO_ERROR; return CSE_NO_ERROR;
if (status == CSE_UPDATE_METADATA_ERROR) if (status == CSE_UPDATE_METADATA_ERROR)
return CSE_LITE_SKU_RW_METADATA_NOT_FOUND; 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"); printk(BIOS_DEBUG, "cse_lite: CSE RW update is initiated\n");
return cse_trigger_fw_update(status, &target_rdev); return cse_trigger_fw_update(status, &target_rdev);

View File

@ -80,6 +80,9 @@ enum me_fw_sku {
/* Number of cse boot performance data */ /* Number of cse boot performance data */
#define NUM_CSE_BOOT_PERF_DATA 64 #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 */ /* HFSTS register offsets in PCI config space */
enum { enum {
PCI_ME_HFSTS1 = 0x40, PCI_ME_HFSTS1 = 0x40,
@ -105,6 +108,24 @@ struct mkhi_hdr {
uint8_t result; uint8_t result;
} __packed; } __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 */ /* CSE FW Version */
struct fw_version { struct fw_version {
uint16_t major; uint16_t major;
@ -398,6 +419,9 @@ int cse_hmrfpo_get_status(void);
/* Fixed Address MEI Header's ME Address field value */ /* Fixed Address MEI Header's ME Address field value */
#define HECI_MKHI_ADDR 0x07 #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 */ /* Fixed Address MEI Header's ME Address for MEI bus messages */
#define HECI_MEI_ADDR 0x00 #define HECI_MEI_ADDR 0x00