summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--drivers/scsi/ufs/debugfs.c32
-rw-r--r--drivers/scsi/ufs/debugfs.h8
-rw-r--r--drivers/scsi/ufs/qcom-debugfs.c45
-rw-r--r--drivers/scsi/ufs/ufs-qcom.c68
-rw-r--r--include/linux/scsi/ufs/ufs-qcom.h4
5 files changed, 119 insertions, 38 deletions
diff --git a/drivers/scsi/ufs/debugfs.c b/drivers/scsi/ufs/debugfs.c
index 4fd197cace5c..4ee7d8379602 100644
--- a/drivers/scsi/ufs/debugfs.c
+++ b/drivers/scsi/ufs/debugfs.c
@@ -181,7 +181,7 @@ static void ufsdbg_setup_fault_injection(struct ufs_hba *hba)
}
#endif /* CONFIG_UFS_FAULT_INJECTION */
-#define BUFF_LINE_CAPACITY 16
+#define BUFF_LINE_SIZE 16 /* Must be a multiplication of sizeof(u32) */
#define TAB_CHARS 8
static int ufsdbg_tag_stats_show(struct seq_file *file, void *data)
@@ -436,20 +436,28 @@ exit:
return ret;
}
-static void
-ufsdbg_pr_buf_to_std(struct seq_file *file, void *buff, int size, char *str)
+void ufsdbg_pr_buf_to_std(struct ufs_hba *hba, int offset, int num_regs,
+ char *str, void *priv)
{
int i;
char linebuf[38];
- int lines = size/BUFF_LINE_CAPACITY +
- (size % BUFF_LINE_CAPACITY ? 1 : 0);
+ int size = num_regs * sizeof(u32);
+ int lines = size / BUFF_LINE_SIZE +
+ (size % BUFF_LINE_SIZE ? 1 : 0);
+ struct seq_file *file = priv;
+
+ if (!hba || !file) {
+ pr_err("%s called with NULL pointer\n", __func__);
+ return;
+ }
for (i = 0; i < lines; i++) {
- hex_dump_to_buffer(buff + i * BUFF_LINE_CAPACITY,
- BUFF_LINE_CAPACITY, BUFF_LINE_CAPACITY, 4,
+ hex_dump_to_buffer(hba->mmio_base + offset + i * BUFF_LINE_SIZE,
+ min(BUFF_LINE_SIZE, size), BUFF_LINE_SIZE, 4,
linebuf, sizeof(linebuf), false);
- seq_printf(file, "%s [%x]: %s\n", str, i * BUFF_LINE_CAPACITY,
+ seq_printf(file, "%s [%x]: %s\n", str, i * BUFF_LINE_SIZE,
linebuf);
+ size -= BUFF_LINE_SIZE/sizeof(u32);
}
}
@@ -459,8 +467,8 @@ static int ufsdbg_host_regs_show(struct seq_file *file, void *data)
ufshcd_hold(hba, false);
pm_runtime_get_sync(hba->dev);
- ufsdbg_pr_buf_to_std(file, hba->mmio_base, UFSHCI_REG_SPACE_SIZE,
- "host regs");
+ ufsdbg_pr_buf_to_std(hba, 0, UFSHCI_REG_SPACE_SIZE / sizeof(u32),
+ "host regs", file);
pm_runtime_put_sync(hba->dev);
ufshcd_release(hba, false);
return 0;
@@ -778,12 +786,12 @@ static ssize_t ufsdbg_power_mode_write(struct file *file,
struct ufs_hba *hba = file->f_mapping->host->i_private;
struct ufs_pa_layer_attr pwr_mode;
struct ufs_pa_layer_attr final_pwr_mode;
- char pwr_mode_str[BUFF_LINE_CAPACITY] = {0};
+ char pwr_mode_str[BUFF_LINE_SIZE] = {0};
loff_t buff_pos = 0;
int ret;
int idx = 0;
- ret = simple_write_to_buffer(pwr_mode_str, BUFF_LINE_CAPACITY,
+ ret = simple_write_to_buffer(pwr_mode_str, BUFF_LINE_SIZE,
&buff_pos, ubuf, cnt);
pwr_mode.gear_rx = pwr_mode_str[idx++] - '0';
diff --git a/drivers/scsi/ufs/debugfs.h b/drivers/scsi/ufs/debugfs.h
index 0c481310921c..cf82be23fb47 100644
--- a/drivers/scsi/ufs/debugfs.h
+++ b/drivers/scsi/ufs/debugfs.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2013-2014, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2013-2015, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -28,6 +28,8 @@ void ufsdbg_add_debugfs(struct ufs_hba *hba);
void ufsdbg_remove_debugfs(struct ufs_hba *hba);
void ufsdbg_fail_request(struct ufs_hba *hba, u32 *intr_status);
+void ufsdbg_pr_buf_to_std(struct ufs_hba *hba, int offset, int num_regs,
+ char *str, void *priv);
#else
void ufsdbg_add_debugfs(struct ufs_hba *hba)
{
@@ -38,5 +40,9 @@ void ufsdbg_remove_debugfs(struct ufs_hba *hba)
void ufsdbg_fail_request(struct ufs_hba *hba, u32 *intr_status)
{
}
+void ufsdbg_pr_buf_to_std(struct ufs_hba *hba, int offset, int num_regs,
+ char *str, void *priv)
+{
+}
#endif
#endif /* End of Header */
diff --git a/drivers/scsi/ufs/qcom-debugfs.c b/drivers/scsi/ufs/qcom-debugfs.c
index 835ea46d88e5..4cfa5a5a3ed3 100644
--- a/drivers/scsi/ufs/qcom-debugfs.c
+++ b/drivers/scsi/ufs/qcom-debugfs.c
@@ -15,6 +15,7 @@
#include <linux/debugfs.h>
#include <linux/scsi/ufs/ufs-qcom.h>
#include "qcom-debugfs.h"
+#include "debugfs.h"
#define TESTBUS_CFG_BUFF_LINE_SIZE sizeof("0xXY, 0xXY")
@@ -184,6 +185,39 @@ DEFINE_SIMPLE_ATTRIBUTE(ufs_qcom_dbg_testbus_bus_ops,
NULL,
"%llu\n");
+static int ufs_qcom_dbg_dbg_regs_show(struct seq_file *file, void *data)
+{
+ struct ufs_qcom_host *host = (struct ufs_qcom_host *)file->private;
+ bool dbg_print_reg = !!(host->dbg_print_en &
+ UFS_QCOM_DBG_PRINT_REGS_EN);
+
+ ufshcd_hold(host->hba, false);
+ pm_runtime_get_sync(host->hba->dev);
+
+ /* Temporarily override the debug print enable */
+ host->dbg_print_en |= UFS_QCOM_DBG_PRINT_REGS_EN;
+ ufs_qcom_print_hw_debug_reg_all(host->hba, file, ufsdbg_pr_buf_to_std);
+ /* Restore previous debug print enable value */
+ if (!dbg_print_reg)
+ host->dbg_print_en &= ~UFS_QCOM_DBG_PRINT_REGS_EN;
+
+ pm_runtime_put_sync(host->hba->dev);
+ ufshcd_release(host->hba, false);
+
+ return 0;
+}
+
+static int ufs_qcom_dbg_dbg_regs_open(struct inode *inode,
+ struct file *file)
+{
+ return single_open(file, ufs_qcom_dbg_dbg_regs_show,
+ inode->i_private);
+}
+
+static const struct file_operations ufs_qcom_dbg_dbg_regs_desc = {
+ .open = ufs_qcom_dbg_dbg_regs_open,
+ .read = seq_read,
+};
void ufs_qcom_dbg_add_debugfs(struct ufs_hba *hba, struct dentry *root)
{
@@ -262,6 +296,17 @@ void ufs_qcom_dbg_add_debugfs(struct ufs_hba *hba, struct dentry *root)
goto err;
}
+ host->debugfs_files.dbg_regs =
+ debugfs_create_file("debug-regs", S_IRUSR,
+ host->debugfs_files.debugfs_root, host,
+ &ufs_qcom_dbg_dbg_regs_desc);
+ if (!host->debugfs_files.dbg_regs) {
+ dev_err(host->hba->dev,
+ "%s: failed create dbg_regs debugfs entry\n",
+ __func__);
+ goto err;
+ }
+
return;
err:
diff --git a/drivers/scsi/ufs/ufs-qcom.c b/drivers/scsi/ufs/ufs-qcom.c
index 482873d98c11..69077678a198 100644
--- a/drivers/scsi/ufs/ufs-qcom.c
+++ b/drivers/scsi/ufs/ufs-qcom.c
@@ -72,6 +72,12 @@ static void ufs_qcom_dump_regs(struct ufs_hba *hba, int offset, int len,
16, 4, hba->mmio_base + offset, len * 4, false);
}
+static void ufs_qcom_dump_regs_wrapper(struct ufs_hba *hba, int offset, int len,
+ char *prefix, void *priv)
+{
+ ufs_qcom_dump_regs(hba, offset, len, prefix);
+}
+
static int ufs_qcom_get_connected_tx_lanes(struct ufs_hba *hba, u32 *tx_lanes)
{
int err = 0;
@@ -1398,44 +1404,56 @@ out:
return ret;
}
-static void ufs_qcom_print_hw_debug_reg_all(struct ufs_hba *hba)
+void ufs_qcom_print_hw_debug_reg_all(struct ufs_hba *hba, void *priv,
+ void (*print_fn)(struct ufs_hba *hba, int offset, int num_regs,
+ char *str, void *priv))
{
u32 reg;
- struct ufs_qcom_host *host = hba->priv;
+ struct ufs_qcom_host *host;
+
+ if (unlikely(!hba)) {
+ pr_err("%s: hba is NULL\n", __func__);
+ return;
+ }
+ if (unlikely(!print_fn)) {
+ dev_err(hba->dev, "%s: print_fn is NULL\n", __func__);
+ return;
+ }
+ host = hba->priv;
if (!(host->dbg_print_en & UFS_QCOM_DBG_PRINT_REGS_EN))
return;
- ufs_qcom_dump_regs(hba, UFS_UFS_DBG_RD_REG_OCSC, 44,
- "UFS_UFS_DBG_RD_REG_OCSC ");
+ print_fn(hba, UFS_UFS_DBG_RD_REG_OCSC, 44,
+ "UFS_UFS_DBG_RD_REG_OCSC ", priv);
reg = ufshcd_readl(hba, REG_UFS_CFG1);
reg |= UFS_BIT(17);
ufshcd_writel(hba, reg, REG_UFS_CFG1);
- ufs_qcom_dump_regs(hba, UFS_UFS_DBG_RD_EDTL_RAM, 32,
- "UFS_UFS_DBG_RD_EDTL_RAM ");
- ufs_qcom_dump_regs(hba, UFS_UFS_DBG_RD_DESC_RAM, 128,
- "UFS_UFS_DBG_RD_DESC_RAM ");
- ufs_qcom_dump_regs(hba, UFS_UFS_DBG_RD_PRDT_RAM, 64,
- "UFS_UFS_DBG_RD_PRDT_RAM ");
+ print_fn(hba, UFS_UFS_DBG_RD_EDTL_RAM, 32,
+ "UFS_UFS_DBG_RD_EDTL_RAM ", priv);
+ print_fn(hba, UFS_UFS_DBG_RD_DESC_RAM, 128,
+ "UFS_UFS_DBG_RD_DESC_RAM ", priv);
+ print_fn(hba, UFS_UFS_DBG_RD_PRDT_RAM, 64,
+ "UFS_UFS_DBG_RD_PRDT_RAM ", priv);
ufshcd_writel(hba, (reg & ~UFS_BIT(17)), REG_UFS_CFG1);
- ufs_qcom_dump_regs(hba, UFS_DBG_RD_REG_UAWM, 4,
- "UFS_DBG_RD_REG_UAWM ");
- ufs_qcom_dump_regs(hba, UFS_DBG_RD_REG_UARM, 4,
- "UFS_DBG_RD_REG_UARM ");
- ufs_qcom_dump_regs(hba, UFS_DBG_RD_REG_TXUC, 48,
- "UFS_DBG_RD_REG_TXUC ");
- ufs_qcom_dump_regs(hba, UFS_DBG_RD_REG_RXUC, 27,
- "UFS_DBG_RD_REG_RXUC ");
- ufs_qcom_dump_regs(hba, UFS_DBG_RD_REG_DFC, 19,
- "UFS_DBG_RD_REG_DFC ");
- ufs_qcom_dump_regs(hba, UFS_DBG_RD_REG_TRLUT, 34,
- "UFS_DBG_RD_REG_TRLUT ");
- ufs_qcom_dump_regs(hba, UFS_DBG_RD_REG_TMRLUT, 9,
- "UFS_DBG_RD_REG_TMRLUT ");
+ print_fn(hba, UFS_DBG_RD_REG_UAWM, 4,
+ "UFS_DBG_RD_REG_UAWM ", priv);
+ print_fn(hba, UFS_DBG_RD_REG_UARM, 4,
+ "UFS_DBG_RD_REG_UARM ", priv);
+ print_fn(hba, UFS_DBG_RD_REG_TXUC, 48,
+ "UFS_DBG_RD_REG_TXUC ", priv);
+ print_fn(hba, UFS_DBG_RD_REG_RXUC, 27,
+ "UFS_DBG_RD_REG_RXUC ", priv);
+ print_fn(hba, UFS_DBG_RD_REG_DFC, 19,
+ "UFS_DBG_RD_REG_DFC ", priv);
+ print_fn(hba, UFS_DBG_RD_REG_TRLUT, 34,
+ "UFS_DBG_RD_REG_TRLUT ", priv);
+ print_fn(hba, UFS_DBG_RD_REG_TMRLUT, 9,
+ "UFS_DBG_RD_REG_TMRLUT ", priv);
}
static void ufs_qcom_enable_test_bus(struct ufs_qcom_host *host)
@@ -1574,7 +1592,7 @@ static void ufs_qcom_dump_dbg_regs(struct ufs_hba *hba)
ufs_qcom_dump_regs(hba, REG_UFS_SYS1CLK_1US, 16,
"HCI Vendor Specific Registers ");
- ufs_qcom_print_hw_debug_reg_all(hba);
+ ufs_qcom_print_hw_debug_reg_all(hba, NULL, ufs_qcom_dump_regs_wrapper);
ufs_qcom_testbus_read(hba);
ufs_qcom_ice_print_regs(host);
}
diff --git a/include/linux/scsi/ufs/ufs-qcom.h b/include/linux/scsi/ufs/ufs-qcom.h
index c2df38d4f559..fc8b2c98f191 100644
--- a/include/linux/scsi/ufs/ufs-qcom.h
+++ b/include/linux/scsi/ufs/ufs-qcom.h
@@ -218,6 +218,7 @@ struct qcom_debugfs_files {
struct dentry *testbus_en;
struct dentry *testbus_cfg;
struct dentry *testbus_bus;
+ struct dentry *dbg_regs;
};
#endif
@@ -263,6 +264,9 @@ struct ufs_qcom_host {
#define ufs_qcom_is_link_hibern8(hba) ufshcd_is_link_hibern8(hba)
int ufs_qcom_testbus_config(struct ufs_qcom_host *host);
+void ufs_qcom_print_hw_debug_reg_all(struct ufs_hba *hba, void *priv,
+ void (*print_fn)(struct ufs_hba *hba, int offset, int num_regs,
+ char *str, void *priv));
#define MAX_PROP_NAME 32
#define VDDA_PHY_MIN_UV 1000000