diff --git a/src/soc/intel/common/block/cse/Kconfig b/src/soc/intel/common/block/cse/Kconfig index 72e7a8e629..55c9e7999e 100644 --- a/src/soc/intel/common/block/cse/Kconfig +++ b/src/soc/intel/common/block/cse/Kconfig @@ -67,6 +67,25 @@ config SOC_INTEL_CSE_SEND_EOP_LATE Starting with Jasper Lake, coreboot sends EOP before loading payload hence, this config is applicable for those platforms. +config SOC_INTEL_CSE_SEND_EOP_ASYNC + bool + depends on SOC_INTEL_COMMON_BLOCK_CSE + depends on !SOC_INTEL_CSE_SEND_EOP_LATE + depends on !SOC_INTEL_CSE_SEND_EOP_EARLY + help + Use this config to handle End Of Post (EOP) completion + asynchronously. The EOP command is sent first and the result + is checked later leaving time to CSE to complete the + operation while coreboot perform other activities. + Performing EOP asynchronously reduces the time spent + actively waiting for command completion which can have a + significant impact on boot time. + + Using this asynchronous approach comes with the limitation + that no HECI command should be sent between the time the EOP + request is posted (at CSE .final device operation) and the + time coreboot check for its completion (BS_PAYLOAD_LOAD). + config SOC_INTEL_CSE_LITE_SKU bool default n diff --git a/src/soc/intel/common/block/cse/cse.c b/src/soc/intel/common/block/cse/cse.c index 9902094180..6c4bb73cee 100644 --- a/src/soc/intel/common/block/cse/cse.c +++ b/src/soc/intel/common/block/cse/cse.c @@ -1407,7 +1407,8 @@ static void cse_final_end_of_firmware(void) */ void cse_late_finalize(void) { - if (!CONFIG(SOC_INTEL_CSE_SEND_EOP_LATE)) + if (!CONFIG(SOC_INTEL_CSE_SEND_EOP_LATE) && + !CONFIG(SOC_INTEL_CSE_SEND_EOP_ASYNC)) return; if (!CONFIG(USE_FSP_NOTIFY_PHASE_READY_TO_BOOT)) @@ -1431,6 +1432,14 @@ static void cse_final(struct device *dev) if (CONFIG(SOC_INTEL_CSE_SET_EOP)) cse_send_end_of_post(); + /* + * In asynchronous mode, the EOP command has most likely not been + * completed yet. Finalization steps will be run once the EOP command + * has successfully been completed. + */ + if (CONFIG(SOC_INTEL_CSE_SEND_EOP_ASYNC)) + return; + if (!CONFIG(USE_FSP_NOTIFY_PHASE_READY_TO_BOOT)) cse_final_ready_to_boot(); diff --git a/src/soc/intel/common/block/cse/cse_eop.c b/src/soc/intel/common/block/cse/cse_eop.c index 53a4fa555e..16cf5238b3 100644 --- a/src/soc/intel/common/block/cse/cse_eop.c +++ b/src/soc/intel/common/block/cse/cse_eop.c @@ -67,13 +67,54 @@ static enum cse_cmd_result cse_disable_mei_bus(void) return CSE_CMD_RESULT_SUCCESS; } -static enum cse_cmd_result cse_send_eop(void) +static enum cse_cmd_result cse_receive_eop(void) { - enum cse_tx_rx_status ret; enum { EOP_REQUESTED_ACTION_CONTINUE = 0, EOP_REQUESTED_ACTION_GLOBAL_RESET = 1, }; + enum cse_tx_rx_status ret; + struct end_of_post_resp { + struct mkhi_hdr hdr; + uint32_t requested_actions; + } __packed resp = {}; + size_t resp_size = sizeof(resp); + + ret = heci_receive(&resp, &resp_size); + if (ret) + return decode_heci_send_receive_error(ret); + + if (resp.hdr.group_id != MKHI_GROUP_ID_GEN || + resp.hdr.command != MKHI_END_OF_POST) { + printk(BIOS_ERR, "HECI: EOP Unexpected response group or command.\n"); + if (CONFIG(SOC_INTEL_CSE_SEND_EOP_ASYNC)) + printk(BIOS_ERR, "HECI: It could be a HECI command conflict.\n"); + return CSE_CMD_RESULT_ERROR; + } + + if (resp.hdr.result) { + printk(BIOS_ERR, "HECI: EOP Resp Failed: %u\n", resp.hdr.result); + return CSE_CMD_RESULT_ERROR; + } + + printk(BIOS_INFO, "CSE: EOP requested action: "); + + switch (resp.requested_actions) { + case EOP_REQUESTED_ACTION_GLOBAL_RESET: + printk(BIOS_INFO, "global reset\n"); + return CSE_CMD_RESULT_GLOBAL_RESET_REQUESTED; + case EOP_REQUESTED_ACTION_CONTINUE: + printk(BIOS_INFO, "continue boot\n"); + return CSE_CMD_RESULT_SUCCESS; + default: + printk(BIOS_INFO, "unknown %u\n", resp.requested_actions); + return CSE_CMD_RESULT_ERROR; + } +} + +static enum cse_cmd_result cse_send_eop(void) +{ + enum cse_tx_rx_status ret; struct end_of_post_msg { struct mkhi_hdr hdr; } __packed msg = { @@ -82,11 +123,6 @@ static enum cse_cmd_result cse_send_eop(void) .command = MKHI_END_OF_POST, }, }; - struct end_of_post_resp { - struct mkhi_hdr hdr; - uint32_t requested_actions; - } __packed resp = {}; - size_t resp_size = sizeof(resp); /* For a CSE-Lite SKU, if the CSE is running RO FW and the board is running vboot in recovery mode, the CSE is expected to be in SOFT @@ -119,28 +155,22 @@ static enum cse_cmd_result cse_send_eop(void) printk(BIOS_INFO, "HECI: Sending End-of-Post\n"); - ret = heci_send_receive(&msg, sizeof(msg), &resp, &resp_size, HECI_MKHI_ADDR); + ret = heci_send(&msg, sizeof(msg), BIOS_HOST_ADDR, HECI_MKHI_ADDR); if (ret) return decode_heci_send_receive_error(ret); - if (resp.hdr.result) { - printk(BIOS_ERR, "HECI: EOP Resp Failed: %u\n", resp.hdr.result); - return CSE_CMD_RESULT_ERROR; - } + return CSE_CMD_RESULT_SUCCESS; +} - printk(BIOS_INFO, "CSE: EOP requested action: "); +static enum cse_cmd_result cse_send_and_receive_eop(void) +{ + enum cse_cmd_result ret; - switch (resp.requested_actions) { - case EOP_REQUESTED_ACTION_GLOBAL_RESET: - printk(BIOS_INFO, "global reset\n"); - return CSE_CMD_RESULT_GLOBAL_RESET_REQUESTED; - case EOP_REQUESTED_ACTION_CONTINUE: - printk(BIOS_INFO, "continue boot\n"); - return CSE_CMD_RESULT_SUCCESS; - default: - printk(BIOS_INFO, "unknown %u\n", resp.requested_actions); - return CSE_CMD_RESULT_ERROR; - } + ret = cse_send_eop(); + if (ret != CSE_CMD_RESULT_SUCCESS) + return ret; + + return cse_receive_eop(); } static enum cse_cmd_result cse_send_cmd_retries(enum cse_cmd_result (*cse_send_command)(void)) @@ -199,11 +229,12 @@ static void handle_cse_eop_result(enum cse_cmd_result result) } } -static void do_send_end_of_post(void) +static void do_send_end_of_post(bool wait_for_completion) { - static bool eop_sent = false; + static bool eop_sent = false, eop_complete = false; + enum cse_cmd_result ret; - if (eop_sent) { + if (eop_complete) { printk(BIOS_WARNING, "EOP already sent\n"); return; } @@ -222,26 +253,40 @@ static void do_send_end_of_post(void) return; } - set_cse_device_state(PCH_DEVFN_CSE, DEV_ACTIVE); + if (!eop_sent) { + set_cse_device_state(PCH_DEVFN_CSE, DEV_ACTIVE); + timestamp_add_now(TS_ME_END_OF_POST_START); + ret = cse_send_cmd_retries(cse_send_eop); + if (ret == CSE_CMD_RESULT_SUCCESS) + eop_sent = true; + } - timestamp_add_now(TS_ME_END_OF_POST_START); - handle_cse_eop_result(cse_send_cmd_retries(cse_send_eop)); + if (!wait_for_completion) + return; + + set_cse_device_state(PCH_DEVFN_CSE, DEV_ACTIVE); + ret = cse_receive_eop(); + if (ret != CSE_CMD_RESULT_SUCCESS) { + ret = cse_send_cmd_retries(cse_send_and_receive_eop); + handle_cse_eop_result(ret); + } timestamp_add_now(TS_ME_END_OF_POST_END); set_cse_device_state(PCH_DEVFN_CSE, DEV_IDLE); - eop_sent = true; + eop_complete = true; } void cse_send_end_of_post(void) { - return do_send_end_of_post(); + return do_send_end_of_post(!CONFIG(SOC_INTEL_CSE_SEND_EOP_ASYNC)); } static void send_cse_eop_with_late_finalize(void *unused) { - do_send_end_of_post(); - if (CONFIG(SOC_INTEL_CSE_SEND_EOP_LATE)) + do_send_end_of_post(true); + if (CONFIG(SOC_INTEL_CSE_SEND_EOP_LATE) || + CONFIG(SOC_INTEL_CSE_SEND_EOP_ASYNC)) cse_late_finalize(); }