ERRCODE and ERRDBG registers are dumped during BHI failure. Extend this to BHIe and RDDM failures. Also, add additional status registers essential for debug and make this debug function available for client driver. Co-developed-by: Vignesh Viswanathan <quic_viswanat@xxxxxxxxxxx> Signed-off-by: Vignesh Viswanathan <quic_viswanat@xxxxxxxxxxx> Signed-off-by: Gokul Sriram Palanisamy <quic_gokulsri@xxxxxxxxxxx> --- drivers/bus/mhi/host/boot.c | 53 +++++++++++++++++------------- drivers/bus/mhi/host/main.c | 65 +++++++++++++++++++++++++++++++++++++ drivers/bus/mhi/host/pm.c | 4 ++- include/linux/mhi.h | 5 +++ 4 files changed, 103 insertions(+), 24 deletions(-) diff --git a/drivers/bus/mhi/host/boot.c b/drivers/bus/mhi/host/boot.c index 324510d2c7fd..b403890d873b 100644 --- a/drivers/bus/mhi/host/boot.c +++ b/drivers/bus/mhi/host/boot.c @@ -159,6 +159,7 @@ static int __mhi_download_rddm_in_panic(struct mhi_controller *mhi_cntrl) error_exit_rddm: dev_err(dev, "RDDM transfer failed. Current EE: %s\n", TO_MHI_EXEC_STR(ee)); + mhi_debug_reg_dump(mhi_cntrl); return -EIO; } @@ -168,6 +169,7 @@ int mhi_download_rddm_image(struct mhi_controller *mhi_cntrl, bool in_panic) { void __iomem *base = mhi_cntrl->bhie; struct device *dev = &mhi_cntrl->mhi_dev->dev; + rwlock_t *pm_lock = &mhi_cntrl->pm_lock; struct mhi_buf *mhi_buf = NULL; u32 rx_status; int ret; @@ -217,6 +219,15 @@ int mhi_download_rddm_image(struct mhi_controller *mhi_cntrl, bool in_panic) dma_unmap_single(mhi_cntrl->cntrl_dev, mhi_buf->dma_addr, mhi_buf->len, DMA_TO_DEVICE); + if (ret) { + dev_err(dev, "RDDM transfer failed. RXVEC_STATUS: 0x%x\n", + rx_status); + read_lock_bh(pm_lock); + if (MHI_REG_ACCESS_VALID(mhi_cntrl->pm_state)) + mhi_debug_reg_dump(mhi_cntrl); + read_unlock_bh(pm_lock); + } + return ret; } EXPORT_SYMBOL_GPL(mhi_download_rddm_image); @@ -263,8 +274,22 @@ static int mhi_fw_load_bhie(struct mhi_controller *mhi_cntrl, &tx_status) || tx_status, msecs_to_jiffies(mhi_cntrl->timeout_ms)); if (MHI_PM_IN_ERROR_STATE(mhi_cntrl->pm_state) || - tx_status != BHIE_TXVECSTATUS_STATUS_XFER_COMPL) + tx_status != BHIE_TXVECSTATUS_STATUS_XFER_COMPL) { + dev_err(dev, "Upper:0x%x Lower:0x%x len:0x%zx sequence:%u\n", + upper_32_bits(mhi_buf->dma_addr), + lower_32_bits(mhi_buf->dma_addr), + mhi_buf->len, sequence_id); + + dev_err(dev, "MHI pm_state: %s tx_status: %d ee: %s\n", + to_mhi_pm_state_str(mhi_cntrl->pm_state), tx_status, + TO_MHI_EXEC_STR(mhi_get_exec_env(mhi_cntrl))); + + read_lock_bh(pm_lock); + if (MHI_REG_ACCESS_VALID(mhi_cntrl->pm_state)) + mhi_debug_reg_dump(mhi_cntrl); + read_unlock_bh(pm_lock); return -EIO; + } return (!ret) ? -ETIMEDOUT : 0; } @@ -273,21 +298,11 @@ static int mhi_fw_load_bhi(struct mhi_controller *mhi_cntrl, dma_addr_t dma_addr, size_t size) { - u32 tx_status, val, session_id; - int i, ret; + u32 tx_status, session_id; + int ret; void __iomem *base = mhi_cntrl->bhi; rwlock_t *pm_lock = &mhi_cntrl->pm_lock; struct device *dev = &mhi_cntrl->mhi_dev->dev; - struct { - char *name; - u32 offset; - } error_reg[] = { - { "ERROR_CODE", BHI_ERRCODE }, - { "ERROR_DBG1", BHI_ERRDBG1 }, - { "ERROR_DBG2", BHI_ERRDBG2 }, - { "ERROR_DBG3", BHI_ERRDBG3 }, - { NULL }, - }; read_lock_bh(pm_lock); if (!MHI_REG_ACCESS_VALID(mhi_cntrl->pm_state)) { @@ -319,16 +334,8 @@ static int mhi_fw_load_bhi(struct mhi_controller *mhi_cntrl, if (tx_status == BHI_STATUS_ERROR) { dev_err(dev, "Image transfer failed\n"); read_lock_bh(pm_lock); - if (MHI_REG_ACCESS_VALID(mhi_cntrl->pm_state)) { - for (i = 0; error_reg[i].name; i++) { - ret = mhi_read_reg(mhi_cntrl, base, - error_reg[i].offset, &val); - if (ret) - break; - dev_err(dev, "Reg: %s value: 0x%x\n", - error_reg[i].name, val); - } - } + if (MHI_REG_ACCESS_VALID(mhi_cntrl->pm_state)) + mhi_debug_reg_dump(mhi_cntrl); read_unlock_bh(pm_lock); goto invalid_pm_state; } diff --git a/drivers/bus/mhi/host/main.c b/drivers/bus/mhi/host/main.c index 2f44f11fa5a6..26baa04badf4 100644 --- a/drivers/bus/mhi/host/main.c +++ b/drivers/bus/mhi/host/main.c @@ -1707,3 +1707,68 @@ int mhi_get_channel_doorbell_offset(struct mhi_controller *mhi_cntrl, u32 *chdb_ return 0; } EXPORT_SYMBOL_GPL(mhi_get_channel_doorbell_offset); + +void mhi_debug_reg_dump(struct mhi_controller *mhi_cntrl) +{ + enum mhi_state state; + enum mhi_ee_type ee; + int i, ret; + u32 val; + void __iomem *mhi_base = mhi_cntrl->regs; + void __iomem *bhi_base = mhi_cntrl->bhi; + void __iomem *bhie_base = mhi_cntrl->bhie; + void __iomem *wake_db = mhi_cntrl->wake_db; + struct { + const char *name; + int offset; + void *base; + } debug_reg[] = { + { "MHI_CNTRL", MHICTRL, mhi_base}, + { "MHI_STATUS", MHISTATUS, mhi_base}, + { "MHI_WAKE_DB", 0, wake_db}, + { "BHI_EXECENV", BHI_EXECENV, bhi_base}, + { "BHI_STATUS", BHI_STATUS, bhi_base}, + { "BHI_ERRCODE", BHI_ERRCODE, bhi_base}, + { "BHI_ERRDBG1", BHI_ERRDBG1, bhi_base}, + { "BHI_ERRDBG2", BHI_ERRDBG2, bhi_base}, + { "BHI_ERRDBG3", BHI_ERRDBG3, bhi_base}, + { "BHIE_TXVEC_DB", BHIE_TXVECDB_OFFS, bhie_base}, + { "BHIE_TXVEC_STATUS", BHIE_TXVECSTATUS_OFFS, bhie_base}, + { "BHIE_RXVEC_DB", BHIE_RXVECDB_OFFS, bhie_base}, + { "BHIE_RXVEC_STATUS", BHIE_RXVECSTATUS_OFFS, bhie_base}, + { "BHIE_IMGTXDB", BHI_IMGTXDB, bhie_base}, + { NULL }, + }; + + dev_info(&mhi_cntrl->mhi_dev->dev, + "host pm_state:%s dev_state:%s ee:%s\n", + to_mhi_pm_state_str(mhi_cntrl->pm_state), + mhi_state_str(mhi_cntrl->dev_state), + TO_MHI_EXEC_STR(mhi_cntrl->ee)); + + state = mhi_get_mhi_state(mhi_cntrl); + + if (!mhi_cntrl->bhi) { + dev_err(&mhi_cntrl->mhi_dev->dev, + "BHI not initialized, failed to dump debug registers\n"); + return; + } + + ee = mhi_get_exec_env(mhi_cntrl); + + dev_info(&mhi_cntrl->mhi_dev->dev, + "device ee:%s dev_state:%s\n", TO_MHI_EXEC_STR(ee), + mhi_state_str(state)); + + for (i = 0; debug_reg[i].name; i++) { + if (!debug_reg[i].base) + continue; + + ret = mhi_read_reg(mhi_cntrl, debug_reg[i].base, + debug_reg[i].offset, &val); + dev_info(&mhi_cntrl->mhi_dev->dev, + "reg:%s val:0x%x, ret:%d\n", debug_reg[i].name, val, + ret); + } +} +EXPORT_SYMBOL_GPL(mhi_debug_reg_dump); diff --git a/drivers/bus/mhi/host/pm.c b/drivers/bus/mhi/host/pm.c index 68524e27e76c..5db99e092dbe 100644 --- a/drivers/bus/mhi/host/pm.c +++ b/drivers/bus/mhi/host/pm.c @@ -1267,8 +1267,10 @@ int mhi_sync_power_up(struct mhi_controller *mhi_cntrl) msecs_to_jiffies(timeout_ms)); ret = (MHI_IN_MISSION_MODE(mhi_cntrl->ee)) ? 0 : -ETIMEDOUT; - if (ret) + if (ret) { + mhi_debug_reg_dump(mhi_cntrl); mhi_power_down(mhi_cntrl, false); + } return ret; } diff --git a/include/linux/mhi.h b/include/linux/mhi.h index ce229a6a2b9a..c0c9bfc28e4a 100644 --- a/include/linux/mhi.h +++ b/include/linux/mhi.h @@ -834,4 +834,9 @@ bool mhi_queue_is_full(struct mhi_device *mhi_dev, enum dma_data_direction dir); */ int mhi_get_channel_doorbell_offset(struct mhi_controller *mhi_cntrl, u32 *chdb_offset); +/** + * mhi_debug_reg_dump - dump MHI registers for debug purpose + * @mhi_cntrl: MHI controller + */ +void mhi_debug_reg_dump(struct mhi_controller *mhi_cntrl); #endif /* _MHI_H_ */ -- 2.34.1