diff mbox series

[4/6] bus: mhi: dump debug registers in critical sections

Message ID 20240718061344.575653-5-quic_gokulsri@quicinc.com
State New
Headers show
Series add improvements to mhi driver | expand

Commit Message

Gokul Sriram Palanisamy July 18, 2024, 6:13 a.m. UTC
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@quicinc.com>
Signed-off-by: Vignesh Viswanathan <quic_viswanat@quicinc.com>
Signed-off-by: Gokul Sriram Palanisamy <quic_gokulsri@quicinc.com>
---
 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(-)

Comments

Jeffrey Hugo July 29, 2024, 2:13 p.m. UTC | #1
On 7/28/2024 11:47 PM, Gokul Sriram P wrote:
> 
> On 7/18/2024 9:55 PM, Jeffrey Hugo wrote:
>> On 7/18/2024 12:13 AM, Gokul Sriram Palanisamy wrote:
>>> --- 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_ */
>>
>> NACK.  This is not used.
> mhi_debug_reg_dump - this is added in 3 places, mhi_fw_load_bhi( ), 
> mhi_fw_load_bhie( ) and mhi_download_rddm_image( ) to print error codes 
> on failure scenarios.

You add this to the MHI API and export it as a symbol.  Nothing outside 
MHI uses this.
diff mbox series

Patch

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_ */