From 739281396c972c489bb1af115b38c6cb2913076d Mon Sep 17 00:00:00 2001 From: Bhaumik Bhatt Date: Mon, 3 Aug 2020 12:50:54 -0700 Subject: [PATCH 1/2] mhi: core: Move to error state if firmware could not be loaded Move MHI to a firmware download error state for any bootup failures such as unable to find firmware files or load images via BHI/BHIe. This helps detect an error state sooner and shortens the wait for a synchronous power up timeout. It also negates the need to provide additional callbacks due to any intermediate bootup failures. Change-Id: I3307e432063f59e978f1e055453155803a6475b2 Signed-off-by: Bhaumik Bhatt --- drivers/bus/mhi/core/mhi_boot.c | 50 ++++++++++++++++++++------------- drivers/bus/mhi/core/mhi_pm.c | 5 +++- 2 files changed, 34 insertions(+), 21 deletions(-) diff --git a/drivers/bus/mhi/core/mhi_boot.c b/drivers/bus/mhi/core/mhi_boot.c index 5df5ad6f985e..53de26ec464e 100644 --- a/drivers/bus/mhi/core/mhi_boot.c +++ b/drivers/bus/mhi/core/mhi_boot.c @@ -444,6 +444,9 @@ void mhi_free_bhie_table(struct mhi_controller *mhi_cntrl, int i; struct mhi_buf *mhi_buf = image_info->mhi_buf; + if (!image_info) + return; + for (i = 0; i < image_info->entries; i++, mhi_buf++) mhi_free_contig_coherent(mhi_cntrl, mhi_buf->len, mhi_buf->buf, mhi_buf->dma_addr); @@ -571,14 +574,14 @@ void mhi_fw_load_handler(struct mhi_controller *mhi_cntrl) !mhi_cntrl->seg_len))) { MHI_CNTRL_ERR( "No firmware image defined or !sbl_size || !seg_len\n"); - return; + goto fw_load_error; } ret = request_firmware(&firmware, fw_name, mhi_cntrl->dev); if (ret) { if (!mhi_cntrl->fw_image_fallback) { MHI_CNTRL_ERR("Error loading fw, ret:%d\n", ret); - return; + goto fw_load_error; } /* re-try with fall back fw image */ @@ -586,7 +589,7 @@ void mhi_fw_load_handler(struct mhi_controller *mhi_cntrl) mhi_cntrl->dev); if (ret) { MHI_CNTRL_ERR("Error loading fw_fb, ret:%d\n", ret); - return; + goto fw_load_error; } mhi_cntrl->status_cb(mhi_cntrl, mhi_cntrl->priv_data, @@ -602,8 +605,7 @@ void mhi_fw_load_handler(struct mhi_controller *mhi_cntrl) buf = mhi_alloc_coherent(mhi_cntrl, size, &dma_addr, GFP_KERNEL); if (!buf) { MHI_CNTRL_ERR("Could not allocate memory for image\n"); - release_firmware(firmware); - return; + goto fw_load_error_release; } /* load sbl or edl image via BHI */ @@ -611,17 +613,16 @@ void mhi_fw_load_handler(struct mhi_controller *mhi_cntrl) ret = mhi_fw_load_bhi(mhi_cntrl, dma_addr, size); mhi_free_coherent(mhi_cntrl, size, buf, dma_addr); - if (!mhi_cntrl->fbc_download || ret || mhi_cntrl->ee == MHI_EE_EDL) - release_firmware(firmware); - if (ret) { MHI_CNTRL_ERR("MHI did not load SBL/EDL image, ret:%d\n", ret); - return; + goto fw_load_error_release; } /* we are done with FW load is EE is EDL */ - if (mhi_cntrl->ee == MHI_EE_EDL) + if (mhi_cntrl->ee == MHI_EE_EDL) { + release_firmware(firmware); return; + } write_lock_irq(&mhi_cntrl->pm_lock); mhi_cntrl->dev_state = MHI_STATE_RESET; @@ -636,7 +637,7 @@ void mhi_fw_load_handler(struct mhi_controller *mhi_cntrl) firmware->size); if (ret) { MHI_CNTRL_ERR("Error alloc size:%zu\n", firmware->size); - goto error_alloc_fw_table; + goto fw_load_error_ready; } MHI_CNTRL_LOG("Copying firmware image into vector table\n"); @@ -645,6 +646,9 @@ void mhi_fw_load_handler(struct mhi_controller *mhi_cntrl) mhi_firmware_copy(mhi_cntrl, firmware, mhi_cntrl->fbc_image); } + release_firmware(firmware); + firmware = NULL; + fw_load_ee_pthru: /* transitioning into MHI RESET->READY state */ ret = mhi_ready_state_transition(mhi_cntrl); @@ -653,15 +657,14 @@ fw_load_ee_pthru: to_mhi_pm_state_str(mhi_cntrl->pm_state), TO_MHI_STATE_STR(mhi_cntrl->dev_state), TO_MHI_EXEC_STR(mhi_cntrl->ee), ret); - - if (!mhi_cntrl->fbc_download) - return; - if (ret) { MHI_CNTRL_ERR("Did not transition to READY state\n"); - goto error_read; + goto fw_load_error_ready; } + if (!mhi_cntrl->fbc_download || mhi_cntrl->ee == MHI_EE_PTHRU) + return; + /* wait for SBL event */ ret = wait_event_timeout(mhi_cntrl->state_event, mhi_cntrl->ee == MHI_EE_SBL || @@ -670,7 +673,7 @@ fw_load_ee_pthru: if (!ret || MHI_PM_IN_ERROR_STATE(mhi_cntrl->pm_state)) { MHI_CNTRL_ERR("MHI did not enter BHIE\n"); - goto error_read; + goto fw_load_error_ready; } /* start full firmware image download */ @@ -681,16 +684,23 @@ fw_load_ee_pthru: MHI_CNTRL_LOG("amss fw_load ret:%d\n", ret); - release_firmware(firmware); + if (ret) + goto fw_load_error; return; -error_read: +fw_load_error_ready: mhi_free_bhie_table(mhi_cntrl, mhi_cntrl->fbc_image); mhi_cntrl->fbc_image = NULL; -error_alloc_fw_table: +fw_load_error_release: release_firmware(firmware); + +fw_load_error: + write_lock_irq(&mhi_cntrl->pm_lock); + mhi_cntrl->pm_state = MHI_PM_FW_DL_ERR; + wake_up_all(&mhi_cntrl->state_event); + write_unlock_irq(&mhi_cntrl->pm_lock); } void mhi_perform_soc_reset(struct mhi_controller *mhi_cntrl) diff --git a/drivers/bus/mhi/core/mhi_pm.c b/drivers/bus/mhi/core/mhi_pm.c index 9189e1b66ae2..43b19267a860 100644 --- a/drivers/bus/mhi/core/mhi_pm.c +++ b/drivers/bus/mhi/core/mhi_pm.c @@ -481,12 +481,15 @@ static int mhi_pm_mission_mode_transition(struct mhi_controller *mhi_cntrl) write_lock_irq(&mhi_cntrl->pm_lock); if (MHI_REG_ACCESS_VALID(mhi_cntrl->pm_state)) ee = mhi_get_exec_env(mhi_cntrl); - write_unlock_irq(&mhi_cntrl->pm_lock); if (!MHI_IN_MISSION_MODE(ee)) { MHI_CNTRL_ERR("Invalid EE:%s\n", TO_MHI_EXEC_STR(ee)); + mhi_cntrl->pm_state = MHI_PM_FW_DL_ERR; + wake_up_all(&mhi_cntrl->state_event); + write_unlock_irq(&mhi_cntrl->pm_lock); return -EIO; } + write_unlock_irq(&mhi_cntrl->pm_lock); mhi_cntrl->status_cb(mhi_cntrl, mhi_cntrl->priv_data, MHI_CB_EE_MISSION_MODE); From 0e5a6b80ffa6017696ac3e0a8a9f6c68e2dddbab Mon Sep 17 00:00:00 2001 From: Bhaumik Bhatt Date: Thu, 30 Jul 2020 10:27:59 -0700 Subject: [PATCH 2/2] mhi: core: Check for RDDM cookie set by device to indicate readiness If the device is unable to send the mission mode execution environment change event but has already entered mission mode with the ability to allow ramdump collection, it can set a unique cookie pattern to indicate the availability of ramdumps. Allow the controller to query for this unique pattern upon any bootup failure or timeout. Change-Id: Id1f58b75d3f22e9e21b142cbea74d61cc65615b4 Signed-off-by: Bhaumik Bhatt --- drivers/bus/mhi/core/mhi_boot.c | 25 +++++++++++++++++++++++++ include/linux/mhi.h | 8 ++++++++ 2 files changed, 33 insertions(+) diff --git a/drivers/bus/mhi/core/mhi_boot.c b/drivers/bus/mhi/core/mhi_boot.c index 53de26ec464e..d5a90cb2ecb7 100644 --- a/drivers/bus/mhi/core/mhi_boot.c +++ b/drivers/bus/mhi/core/mhi_boot.c @@ -139,6 +139,31 @@ void mhi_dump_sfr(struct mhi_controller *mhi_cntrl) } EXPORT_SYMBOL(mhi_dump_sfr); +bool mhi_scan_rddm_cookie(struct mhi_controller *mhi_cntrl, u32 cookie) +{ + int ret; + u32 val; + + if (!mhi_cntrl->rddm_supported || !cookie) + return false; + + MHI_CNTRL_LOG("Checking BHI debug register for 0x%x\n", cookie); + + if (!MHI_REG_ACCESS_VALID(mhi_cntrl->pm_state)) + return false; + + ret = mhi_read_reg(mhi_cntrl, mhi_cntrl->bhi, BHI_ERRDBG2, &val); + if (ret) + return false; + + MHI_CNTRL_LOG("BHI_ERRDBG2 value:0x%x\n", val); + if (val == cookie) + return true; + + return false; +} +EXPORT_SYMBOL(mhi_scan_rddm_cookie); + /* setup rddm vector table for rddm transfer and program rxvec */ void mhi_rddm_prepare(struct mhi_controller *mhi_cntrl, struct image_info *img_info) diff --git a/include/linux/mhi.h b/include/linux/mhi.h index 84e4d5dcdafe..6e79d52d7050 100644 --- a/include/linux/mhi.h +++ b/include/linux/mhi.h @@ -797,6 +797,14 @@ int mhi_pm_fast_resume(struct mhi_controller *mhi_cntrl, bool notify_client); */ int mhi_download_rddm_img(struct mhi_controller *mhi_cntrl, bool in_panic); +/** + * mhi_scan_rddm_cookie - Look for supplied cookie value in the BHI debug + * registers set by device to indicate rddm readiness for debugging purposes. + * @mhi_cntrl: MHI controller + * @cookie: cookie/pattern value to match + */ +bool mhi_scan_rddm_cookie(struct mhi_controller *mhi_cntrl, u32 cookie); + /** * mhi_force_rddm_mode - Force external device into rddm mode * to collect device ramdump. This is useful if host driver assert