diff mbox series

[08/17] ufs: Expose 'ufshcd_ops_dbg_register_dump' vops to allow dumping debug registers

Message ID 20230814215457.4075025-9-bhupesh.sharma@linaro.org
State New
Headers show
Series Enable UFS on DragonBoard845c | expand

Commit Message

Bhupesh Sharma Aug. 14, 2023, 9:54 p.m. UTC
Add more verbose debug capabilities and vops to allow dumping
UFS debug registers / regions, similar to how the UFS Linux driver
does it.

Signed-off-by: Bhupesh Sharma <bhupesh.sharma@linaro.org>
---
 drivers/ufs/ufs.c | 71 +++++++++++++++++++++++++++++++++++++++++++++++
 drivers/ufs/ufs.h |  9 ++++++
 2 files changed, 80 insertions(+)

Comments

Marek Vasut Aug. 14, 2023, 10:34 p.m. UTC | #1
On 8/14/23 23:54, Bhupesh Sharma wrote:
> Add more verbose debug capabilities and vops to allow dumping
> UFS debug registers / regions, similar to how the UFS Linux driver
> does it.
> 
> Signed-off-by: Bhupesh Sharma <bhupesh.sharma@linaro.org>
> ---
>   drivers/ufs/ufs.c | 71 +++++++++++++++++++++++++++++++++++++++++++++++
>   drivers/ufs/ufs.h |  9 ++++++
>   2 files changed, 80 insertions(+)
> 
> diff --git a/drivers/ufs/ufs.c b/drivers/ufs/ufs.c
> index b2c3af429e..15fa3832b9 100644
> --- a/drivers/ufs/ufs.c
> +++ b/drivers/ufs/ufs.c
> @@ -59,10 +59,81 @@
>   /* maximum bytes per request */
>   #define UFS_MAX_BYTES	(128 * 256 * 1024)
>   
> +#define ufshcd_hex_dump(prefix_str, buf, len) do {                      \
> +	size_t __len = (len);                                           \
> +	print_hex_dump(prefix_str,                             		\
> +		       DUMP_PREFIX_OFFSET,				\
> +		       16, 4, buf, __len, false);                       \
> +} while (0)
> +
>   static inline bool ufshcd_is_hba_active(struct ufs_hba *hba);
>   static inline void ufshcd_hba_stop(struct ufs_hba *hba);
>   static int ufshcd_hba_enable(struct ufs_hba *hba);
>   
> +int ufshcd_dump_regs(struct ufs_hba *hba, size_t offset, size_t len,
> +		     const char *prefix)
> +{
> +	u32 *regs;
> +	size_t pos;
> +
> +	if (offset % 4 != 0 || len % 4 != 0) /* keep readl happy */
> +		return -EINVAL;
> +
> +	regs = kzalloc(len, GFP_KERNEL);
> +	if (!regs)
> +		return -ENOMEM;
> +
> +	for (pos = 0; pos < len; pos += 4) {
> +		if (offset == 0 &&
> +		    pos >= REG_UIC_ERROR_CODE_PHY_ADAPTER_LAYER &&
> +		    pos <= REG_UIC_ERROR_CODE_DME)
> +			continue;
> +		regs[pos / 4] = ufshcd_readl(hba, offset + pos);
> +	}
> +
> +	ufshcd_hex_dump(prefix, regs, len);
> +	kfree(regs);

Why not use variable on stack instead of this malloc-free cycle ?
diff mbox series

Patch

diff --git a/drivers/ufs/ufs.c b/drivers/ufs/ufs.c
index b2c3af429e..15fa3832b9 100644
--- a/drivers/ufs/ufs.c
+++ b/drivers/ufs/ufs.c
@@ -59,10 +59,81 @@ 
 /* maximum bytes per request */
 #define UFS_MAX_BYTES	(128 * 256 * 1024)
 
+#define ufshcd_hex_dump(prefix_str, buf, len) do {                      \
+	size_t __len = (len);                                           \
+	print_hex_dump(prefix_str,                             		\
+		       DUMP_PREFIX_OFFSET,				\
+		       16, 4, buf, __len, false);                       \
+} while (0)
+
 static inline bool ufshcd_is_hba_active(struct ufs_hba *hba);
 static inline void ufshcd_hba_stop(struct ufs_hba *hba);
 static int ufshcd_hba_enable(struct ufs_hba *hba);
 
+int ufshcd_dump_regs(struct ufs_hba *hba, size_t offset, size_t len,
+		     const char *prefix)
+{
+	u32 *regs;
+	size_t pos;
+
+	if (offset % 4 != 0 || len % 4 != 0) /* keep readl happy */
+		return -EINVAL;
+
+	regs = kzalloc(len, GFP_KERNEL);
+	if (!regs)
+		return -ENOMEM;
+
+	for (pos = 0; pos < len; pos += 4) {
+		if (offset == 0 &&
+		    pos >= REG_UIC_ERROR_CODE_PHY_ADAPTER_LAYER &&
+		    pos <= REG_UIC_ERROR_CODE_DME)
+			continue;
+		regs[pos / 4] = ufshcd_readl(hba, offset + pos);
+	}
+
+	ufshcd_hex_dump(prefix, regs, len);
+	kfree(regs);
+
+	return 0;
+}
+
+void ufshcd_print_tr(struct ufs_hba *hba, int tag, bool pr_prdt)
+{
+	int prdt_length;
+	struct utp_transfer_req_desc *req_desc = hba->utrdl;
+
+	dev_info(hba->dev,
+		"UPIU[%d] - Transfer Request Descriptor phys@0x%llx\n",
+		tag, (u64)hba->utrdl);
+
+	ufshcd_hex_dump("UPIU TRD: ", hba->utrdl,
+			sizeof(struct utp_transfer_req_desc));
+	dev_info(hba->dev, "UPIU[%d] - Request UPIU phys@0x%llx\n", tag,
+		(u64)hba->ucd_req_ptr);
+	ufshcd_hex_dump("UPIU REQ: ", hba->ucd_req_ptr,
+			sizeof(struct utp_upiu_req));
+	dev_info(hba->dev, "UPIU[%d] - Response UPIU phys@0x%llx\n", tag,
+		(u64)hba->ucd_rsp_ptr);
+	ufshcd_hex_dump("UPIU RSP: ", hba->ucd_rsp_ptr,
+			sizeof(struct utp_upiu_rsp));
+
+	prdt_length = le16_to_cpu(req_desc->prd_table_length);
+
+	dev_info(hba->dev,
+		"UPIU[%d] - PRDT - %d entries  phys@0x%llx\n",
+		tag, prdt_length,
+		(u64)hba->ucd_prdt_ptr);
+
+	if (pr_prdt)
+		ufshcd_hex_dump("UPIU PRDT: ", hba->ucd_prdt_ptr,
+			sizeof(struct ufshcd_sg_entry) * prdt_length);
+}
+
+void ufshcd_dbg_register_dump(struct ufs_hba *hba)
+{
+	ufshcd_ops_dbg_register_dump(hba);
+}
+
 /*
  * ufshcd_wait_for_register - wait for register value to change
  */
diff --git a/drivers/ufs/ufs.h b/drivers/ufs/ufs.h
index c9320a905e..b3d2bd0368 100644
--- a/drivers/ufs/ufs.h
+++ b/drivers/ufs/ufs.h
@@ -695,6 +695,7 @@  struct ufs_dev_cmd {
 
 struct ufs_hba_ops {
 	int (*init)(struct ufs_hba *hba);
+	void (*dbg_register_dump)(struct ufs_hba *hba);
 	int (*hce_enable_notify)(struct ufs_hba *hba,
 				 enum ufs_notify_change_status);
 	int (*link_startup_notify)(struct ufs_hba *hba,
@@ -746,6 +747,12 @@  static inline int ufshcd_ops_init(struct ufs_hba *hba)
 	return 0;
 }
 
+static inline void ufshcd_ops_dbg_register_dump(struct ufs_hba *hba)
+{
+	if (hba->ops && hba->ops->dbg_register_dump)
+		hba->ops->dbg_register_dump(hba);
+}
+
 static inline int ufshcd_ops_hce_enable_notify(struct ufs_hba *hba,
 						bool status)
 {
@@ -931,5 +938,7 @@  static inline void ufshcd_rmwl(struct ufs_hba *hba, u32 mask, u32 val, u32 reg)
 #define UTP_TASK_REQ_LIST_RUN_STOP_BIT		0x1
 
 int ufshcd_probe(struct udevice *dev, struct ufs_hba_ops *hba_ops);
+int ufshcd_dump_regs(struct ufs_hba *hba, size_t offset, size_t len,
+		     const char *prefix);
 
 #endif