From ce4a25729be4ee4ccfd83539350e43424f25fbd5 Mon Sep 17 00:00:00 2001 From: Vivek Pernamitta Date: Thu, 2 Sep 2021 13:03:20 +0530 Subject: [PATCH 1/2] bus: mhi: core: Add device hardware reset support The MHI specification allows to perform a hard reset of the device when writing to the SOC_RESET register. It can be used to completely restart the device (e.g. in case of unrecoverable MHI error). This is up to the MHI controller driver to determine when this hard reset should be used, and in case of MHI errors, should be used as a reset of last resort (after standard MHI stack reset). This function is a stateless function, the MHI layer do nothing except triggering the reset by writing into the right register(s), this is up to the caller to ensure right mhi_controller state (e.g. unregister the controller if necessary). Change-Id: I84a7c02b243301fd6e7d61fe8d23443aa4f8a171 Signed-off-by: Loic Poulain Reviewed-by: Manivannan Sadhasivam Signed-off-by: Manivannan Sadhasivam Git-commit: b5a8d233a588b3acf2a7a3a8da30f8f68f376626 Git-repo: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git Signed-off-by: Bhaumik Bhatt Signed-off-by: Vivek Pernamitta --- drivers/bus/mhi/core/mhi_main.c | 15 ++++++++++++++- include/linux/mhi.h | 9 +++++++++ 2 files changed, 23 insertions(+), 1 deletion(-) diff --git a/drivers/bus/mhi/core/mhi_main.c b/drivers/bus/mhi/core/mhi_main.c index 2315552b831b..0ddbbeec7b8d 100644 --- a/drivers/bus/mhi/core/mhi_main.c +++ b/drivers/bus/mhi/core/mhi_main.c @@ -1,5 +1,5 @@ // SPDX-License-Identifier: GPL-2.0-only -/* Copyright (c) 2018-2020, The Linux Foundation. All rights reserved. */ +/* Copyright (c) 2018-2021, The Linux Foundation. All rights reserved. */ #include #include @@ -266,6 +266,19 @@ enum mhi_dev_state mhi_get_mhi_state(struct mhi_controller *mhi_cntrl) } EXPORT_SYMBOL(mhi_get_mhi_state); +void mhi_soc_reset(struct mhi_controller *mhi_cntrl) +{ + if (mhi_cntrl->reset) { + mhi_cntrl->reset(mhi_cntrl); + return; + } + + /* Generic MHI SoC reset */ + mhi_write_reg(mhi_cntrl, mhi_cntrl->regs, MHI_SOC_RESET_REQ_OFFSET, + MHI_SOC_RESET_REQ); +} +EXPORT_SYMBOL(mhi_soc_reset); + int mhi_queue_sclist(struct mhi_device *mhi_dev, struct mhi_chan *mhi_chan, void *buf, diff --git a/include/linux/mhi.h b/include/linux/mhi.h index 9e96d615dfd5..d4dc08370cf0 100644 --- a/include/linux/mhi.h +++ b/include/linux/mhi.h @@ -258,6 +258,7 @@ struct reg_write_info { * @time_get: Return host time in us * @lpm_disable: Request controller to disable link level low power modes * @lpm_enable: Controller may enable link level low power modes again + * @reset: Controller specific reset function (optional) * @priv_data: Points to bus master's private data */ struct mhi_controller { @@ -390,6 +391,7 @@ struct mhi_controller { struct mhi_link_info *link_info); void (*write_reg)(struct mhi_controller *mhi_cntrl, void __iomem *base, u32 offset, u32 val); + void (*reset)(struct mhi_controller *mhi_cntrl); /* channel to control DTR messaging */ struct mhi_device *dtr_dev; @@ -887,6 +889,13 @@ enum mhi_ee mhi_get_exec_env(struct mhi_controller *mhi_cntrl); */ enum mhi_dev_state mhi_get_mhi_state(struct mhi_controller *mhi_cntrl); +/** + * mhi_soc_reset - Trigger a device reset. This can be used as a last resort + * to reset and recover a device. + * @mhi_cntrl: MHI controller + */ +void mhi_soc_reset(struct mhi_controller *mhi_cntrl); + /** * mhi_set_mhi_state - Set device state * @mhi_cntrl: MHI controller From cc50116c065bb83c9e1106d82198dec9c9db0e02 Mon Sep 17 00:00:00 2001 From: Vivek Pernamitta Date: Wed, 1 Sep 2021 16:38:50 +0530 Subject: [PATCH 2/2] msm: mhi: Provide an API to perform host reset request Adding new API to perform host reset request to device to collect device side dumps. Use mhi_soc_reset() API in place of register write Currently, a direct register write is used when ramdump collection in panic path occurs. Replace that with new mhi_soc_reset() API such that a controller defined reset() function is exercised if one is present and the regular SOC reset is done if it is not. Change-Id: Ibd15b231072a9b811ced0031387d605184806e9a Signed-off-by: Vivek Pernamitta Signed-off-by: Bhaumik Bhatt --- drivers/bus/mhi/core/mhi_boot.c | 76 ++++++++++++++++++++++----------- include/linux/mhi.h | 7 +++ 2 files changed, 58 insertions(+), 25 deletions(-) diff --git a/drivers/bus/mhi/core/mhi_boot.c b/drivers/bus/mhi/core/mhi_boot.c index 56aec98ef89d..fa55209e409d 100644 --- a/drivers/bus/mhi/core/mhi_boot.c +++ b/drivers/bus/mhi/core/mhi_boot.c @@ -204,17 +204,47 @@ void mhi_rddm_prepare(struct mhi_controller *mhi_cntrl, &mhi_buf->dma_addr, mhi_buf->len, sequence_id); } +/* check RDDM image is downloaded */ +static int mhi_rddm_download_status(struct mhi_controller *mhi_cntrl) +{ + u32 rx_status; + enum mhi_ee ee; + const u32 delayms = 5; + void __iomem *base = mhi_cntrl->bhie; + u32 retry = (mhi_cntrl->timeout_ms) / delayms; + int ret = 0; + + while (retry--) { + ret = mhi_read_reg_field(mhi_cntrl, base, BHIE_RXVECSTATUS_OFFS, + BHIE_RXVECSTATUS_STATUS_BMSK, + BHIE_RXVECSTATUS_STATUS_SHFT, + &rx_status); + if (ret) + return -EIO; + + if (rx_status == BHIE_RXVECSTATUS_STATUS_XFER_COMPL) { + MHI_CNTRL_LOG("RDDM dumps collected successfully"); + return 0; + } + + mdelay(delayms); + } + + ee = mhi_get_exec_env(mhi_cntrl); + ret = mhi_read_reg(mhi_cntrl, base, BHIE_RXVECSTATUS_OFFS, &rx_status); + MHI_ERR("RXVEC_STATUS: 0x%x\n", rx_status); + MHI_CNTRL_ERR("Current EE:%s\n", TO_MHI_EXEC_STR(ee)); + return -EIO; +} + /* collect rddm during kernel panic */ static int __mhi_download_rddm_in_panic(struct mhi_controller *mhi_cntrl) { int ret; - u32 rx_status; enum mhi_ee ee; const u32 delayms = 5; - u32 retry = (mhi_cntrl->timeout_ms) / delayms; const u32 rddm_timeout_ms = 250; int rddm_retry = rddm_timeout_ms / delayms; /* time to enter rddm */ - void __iomem *base = mhi_cntrl->bhie; MHI_CNTRL_LOG("Entered with pm_state:%s dev_state:%s ee:%s\n", to_mhi_pm_state_str(mhi_cntrl->pm_state), @@ -269,9 +299,7 @@ static int __mhi_download_rddm_in_panic(struct mhi_controller *mhi_cntrl) /* Hardware reset; force device to enter rddm */ MHI_CNTRL_LOG( "Did not enter RDDM, do a host req. reset\n"); - mhi_cntrl->write_reg(mhi_cntrl, mhi_cntrl->regs, - MHI_SOC_RESET_REQ_OFFSET, - MHI_SOC_RESET_REQ); + mhi_soc_reset(mhi_cntrl); mdelay(delayms); } @@ -280,29 +308,14 @@ static int __mhi_download_rddm_in_panic(struct mhi_controller *mhi_cntrl) MHI_CNTRL_LOG("Waiting for image download completion, current EE:%s\n", TO_MHI_EXEC_STR(ee)); - while (retry--) { - ret = mhi_read_reg_field(mhi_cntrl, base, BHIE_RXVECSTATUS_OFFS, - BHIE_RXVECSTATUS_STATUS_BMSK, - BHIE_RXVECSTATUS_STATUS_SHFT, - &rx_status); - if (ret) - return -EIO; - if (rx_status == BHIE_RXVECSTATUS_STATUS_XFER_COMPL) { - MHI_CNTRL_LOG("RDDM successfully collected\n"); - return 0; - } - - mdelay(delayms); + ret = mhi_rddm_download_status(mhi_cntrl); + if (!ret) { + MHI_CNTRL_LOG("RDDM dumps collected successfully"); + return 0; } - ee = mhi_get_exec_env(mhi_cntrl); - ret = mhi_read_reg(mhi_cntrl, base, BHIE_RXVECSTATUS_OFFS, &rx_status); - - MHI_CNTRL_ERR("RXVEC_STATUS:0x%x, ret:%d\n", rx_status, ret); - err_no_rddm: - MHI_CNTRL_ERR("Current EE:%s\n", TO_MHI_EXEC_STR(ee)); MHI_CNTRL_ERR("Did not complete RDDM transfer\n"); return -EIO; @@ -336,6 +349,19 @@ int mhi_download_rddm_img(struct mhi_controller *mhi_cntrl, bool in_panic) } EXPORT_SYMBOL(mhi_download_rddm_img); +/* MHI host reset request*/ +int mhi_force_reset(struct mhi_controller *mhi_cntrl) +{ + MHI_VERB("Entered with pm_state:%s dev_state:%s ee:%s\n", + to_mhi_pm_state_str(mhi_cntrl->pm_state), + TO_MHI_STATE_STR(mhi_cntrl->dev_state), + TO_MHI_EXEC_STR(mhi_cntrl->ee)); + + mhi_soc_reset(mhi_cntrl); + return mhi_rddm_download_status(mhi_cntrl); +} +EXPORT_SYMBOL(mhi_force_reset); + static int mhi_fw_load_bhie(struct mhi_controller *mhi_cntrl, const struct mhi_buf *mhi_buf) { diff --git a/include/linux/mhi.h b/include/linux/mhi.h index d4dc08370cf0..ed0af557573a 100644 --- a/include/linux/mhi.h +++ b/include/linux/mhi.h @@ -810,6 +810,13 @@ 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_force_reset - does host reset request to collect device side dumps + * for debugging purpose + * @mhi_cntrl: MHI controller + */ +int mhi_force_reset(struct mhi_controller *mhi_cntrl); + /** * mhi_scan_rddm_cookie - Look for supplied cookie value in the BHI debug * registers set by device to indicate rddm readiness for debugging purposes.