summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--drivers/scsi/ufs/Makefile2
-rw-r--r--drivers/scsi/ufs/debugfs.c7
-rw-r--r--drivers/scsi/ufs/qcom-debugfs.c98
-rw-r--r--drivers/scsi/ufs/qcom-debugfs.h24
-rw-r--r--drivers/scsi/ufs/ufs-qcom.c16
-rw-r--r--include/linux/scsi/ufs/ufs-qcom.h18
-rw-r--r--include/linux/scsi/ufs/ufshcd.h6
7 files changed, 167 insertions, 4 deletions
diff --git a/drivers/scsi/ufs/Makefile b/drivers/scsi/ufs/Makefile
index 535244fe714f..58ee7fef70b2 100644
--- a/drivers/scsi/ufs/Makefile
+++ b/drivers/scsi/ufs/Makefile
@@ -5,4 +5,4 @@ obj-$(CONFIG_SCSI_UFSHCD) += ufshcd.o ufs_quirks.o
obj-$(CONFIG_SCSI_UFSHCD_PCI) += ufshcd-pci.o
obj-$(CONFIG_SCSI_UFSHCD_PLATFORM) += ufshcd-pltfrm.o
obj-$(CONFIG_SCSI_UFS_TEST) += ufs_test.o
-obj-$(CONFIG_DEBUG_FS) += debugfs.o
+obj-$(CONFIG_DEBUG_FS) += debugfs.o qcom-debugfs.o
diff --git a/drivers/scsi/ufs/debugfs.c b/drivers/scsi/ufs/debugfs.c
index fd682fbdbc30..4fd197cace5c 100644
--- a/drivers/scsi/ufs/debugfs.c
+++ b/drivers/scsi/ufs/debugfs.c
@@ -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
@@ -1065,6 +1065,9 @@ void ufsdbg_add_debugfs(struct ufs_hba *hba)
ufsdbg_setup_fault_injection(hba);
+ if (hba->vops && hba->vops->add_debugfs)
+ hba->vops->add_debugfs(hba, hba->debugfs_files.debugfs_root);
+
return;
err:
@@ -1076,6 +1079,8 @@ err_no_root:
void ufsdbg_remove_debugfs(struct ufs_hba *hba)
{
+ if (hba->vops && hba->vops->remove_debugfs)
+ hba->vops->remove_debugfs(hba);
debugfs_remove_recursive(hba->debugfs_files.debugfs_root);
kfree(hba->ufs_stats.tag_stats);
diff --git a/drivers/scsi/ufs/qcom-debugfs.c b/drivers/scsi/ufs/qcom-debugfs.c
new file mode 100644
index 000000000000..24f164312c21
--- /dev/null
+++ b/drivers/scsi/ufs/qcom-debugfs.c
@@ -0,0 +1,98 @@
+/*
+ * Copyright (c) 2015, 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
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/debugfs.h>
+#include <linux/scsi/ufs/ufs-qcom.h>
+#include "qcom-debugfs.h"
+
+static void ufs_qcom_dbg_remove_debugfs(struct ufs_qcom_host *host);
+
+static int ufs_qcom_dbg_print_en_read(void *data, u64 *attr_val)
+{
+ struct ufs_qcom_host *host = data;
+
+ if (!host)
+ return -EINVAL;
+
+ *attr_val = (u64)host->dbg_print_en;
+ return 0;
+}
+
+static int ufs_qcom_dbg_print_en_set(void *data, u64 attr_id)
+{
+ struct ufs_qcom_host *host = data;
+
+ if (!host)
+ return -EINVAL;
+
+ if (attr_id & ~UFS_QCOM_DBG_PRINT_ALL)
+ return -EINVAL;
+
+ host->dbg_print_en = (u32)attr_id;
+ return 0;
+}
+
+DEFINE_SIMPLE_ATTRIBUTE(ufs_qcom_dbg_print_en_ops,
+ ufs_qcom_dbg_print_en_read,
+ ufs_qcom_dbg_print_en_set,
+ "%llu\n");
+
+
+void ufs_qcom_dbg_add_debugfs(struct ufs_hba *hba, struct dentry *root)
+{
+ struct ufs_qcom_host *host;
+
+ if (!hba || !hba->priv) {
+ pr_err("%s: NULL host, exiting\n", __func__);
+ return;
+ }
+
+ host = hba->priv;
+ host->debugfs_files.debugfs_root = debugfs_create_dir("qcom", root);
+ if (IS_ERR(host->debugfs_files.debugfs_root))
+ /* Don't complain -- debugfs just isn't enabled */
+ goto err_no_root;
+ if (!host->debugfs_files.debugfs_root) {
+ /*
+ * Complain -- debugfs is enabled, but it failed to
+ * create the directory
+ */
+ dev_err(host->hba->dev,
+ "%s: NULL debugfs root directory, exiting", __func__);
+ goto err_no_root;
+ }
+
+ host->debugfs_files.dbg_print_en =
+ debugfs_create_file("dbg_print_en", S_IRUSR | S_IWUSR,
+ host->debugfs_files.debugfs_root, host,
+ &ufs_qcom_dbg_print_en_ops);
+ if (!host->debugfs_files.dbg_print_en) {
+ dev_err(host->hba->dev,
+ "%s: failed to create dbg_print_en debugfs entry\n",
+ __func__);
+ goto err;
+ }
+ return;
+
+err:
+ ufs_qcom_dbg_remove_debugfs(host);
+err_no_root:
+ dev_err(host->hba->dev, "%s: failed to initialize debugfs\n", __func__);
+}
+
+static void ufs_qcom_dbg_remove_debugfs(struct ufs_qcom_host *host)
+{
+ debugfs_remove_recursive(host->debugfs_files.debugfs_root);
+ host->debugfs_files.debugfs_root = NULL;
+}
diff --git a/drivers/scsi/ufs/qcom-debugfs.h b/drivers/scsi/ufs/qcom-debugfs.h
new file mode 100644
index 000000000000..03341711e11e
--- /dev/null
+++ b/drivers/scsi/ufs/qcom-debugfs.h
@@ -0,0 +1,24 @@
+/*
+ * Copyright (c) 2015, 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
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#ifndef QCOM_DEBUGFS_H_
+#define QCOM_DEBUGFS_H_
+
+#include <linux/scsi/ufs/ufshcd.h>
+
+#ifdef CONFIG_DEBUG_FS
+void ufs_qcom_dbg_add_debugfs(struct ufs_hba *hba, struct dentry *root);
+#endif
+
+#endif /* End of Header */
diff --git a/drivers/scsi/ufs/ufs-qcom.c b/drivers/scsi/ufs/ufs-qcom.c
index 1d47641a02f7..d7eafc3bb8ce 100644
--- a/drivers/scsi/ufs/ufs-qcom.c
+++ b/drivers/scsi/ufs/ufs-qcom.c
@@ -34,6 +34,9 @@
#include "ufs-qcom.h"
#include "ufshci.h"
#include "ufs-qcom-ice.h"
+#include "qcom-debugfs.h"
+
+#define DEFAULT_UFS_QCOM_DBG_PRINT_EN UFS_QCOM_DBG_PRINT_REGS_EN
static struct ufs_qcom_host *ufs_qcom_hosts[MAX_UFS_QCOM_HOSTS];
@@ -1268,6 +1271,8 @@ static int ufs_qcom_init(struct ufs_hba *hba)
if (hba->dev->id < MAX_UFS_QCOM_HOSTS)
ufs_qcom_hosts[hba->dev->id] = host;
+ host->dbg_print_en |= DEFAULT_UFS_QCOM_DBG_PRINT_EN;
+
goto out;
out_disable_phy:
@@ -1371,6 +1376,10 @@ out:
static void ufs_qcom_print_hw_debug_reg_all(struct ufs_hba *hba)
{
u32 reg;
+ struct ufs_qcom_host *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 ");
@@ -1406,8 +1415,8 @@ static void ufs_qcom_print_hw_debug_reg_all(struct ufs_hba *hba)
static void ufs_qcom_dump_dbg_regs(struct ufs_hba *hba)
{
- ufs_qcom_dump_regs(hba, REG_UFS_SYS1CLK_1US, 5,
- "REG_UFS_SYS1CLK_1US ");
+ ufs_qcom_dump_regs(hba, REG_UFS_SYS1CLK_1US, 16,
+ "HCI Vendor Specific Registers ");
ufs_qcom_print_hw_debug_reg_all(hba);
}
@@ -1437,6 +1446,9 @@ const struct ufs_hba_variant_ops ufs_hba_qcom_vops = {
.crypto_engine_get_err = ufs_qcom_crypto_engine_get_err,
.crypto_engine_reset_err = ufs_qcom_crypto_engine_reset_err,
.dbg_register_dump = ufs_qcom_dump_dbg_regs,
+#ifdef CONFIG_DEBUG_FS
+ .add_debugfs = ufs_qcom_dbg_add_debugfs,
+#endif
};
/**
diff --git a/include/linux/scsi/ufs/ufs-qcom.h b/include/linux/scsi/ufs/ufs-qcom.h
index dee92b9ee54f..e00f0b935227 100644
--- a/include/linux/scsi/ufs/ufs-qcom.h
+++ b/include/linux/scsi/ufs/ufs-qcom.h
@@ -15,6 +15,7 @@
#define UFS_QCOM_H_
#include <linux/phy/phy.h>
+#include <linux/scsi/ufs/ufshcd.h>
#define MAX_UFS_QCOM_HOSTS 1
#define MAX_U32 (~(u32)0)
@@ -120,6 +121,11 @@ struct ufs_qcom_phy_vreg {
bool enabled;
};
+/* QCOM UFS debug print bit mask */
+#define UFS_QCOM_DBG_PRINT_REGS_EN BIT(0)
+
+#define UFS_QCOM_DBG_PRINT_ALL UFS_QCOM_DBG_PRINT_REGS_EN
+
static inline void
ufs_qcom_get_controller_revision(struct ufs_hba *hba,
u8 *major, u16 *minor, u16 *step)
@@ -189,6 +195,13 @@ struct ufs_hw_version {
u8 major;
};
+#ifdef CONFIG_DEBUG_FS
+struct qcom_debugfs_files {
+ struct dentry *debugfs_root;
+ struct dentry *dbg_print_en;
+};
+#endif
+
struct ufs_qcom_host {
/*
* Set this capability if host controller supports the QUniPro mode
@@ -213,6 +226,11 @@ struct ufs_qcom_host {
void __iomem *dev_ref_clk_ctrl_mmio;
bool is_dev_ref_clk_enabled;
struct ufs_hw_version hw_ver;
+#ifdef CONFIG_DEBUG_FS
+ struct qcom_debugfs_files debugfs_files;
+#endif
+ /* Bitmask for enabling debug prints */
+ u32 dbg_print_en;
};
#define ufs_qcom_is_link_off(hba) ufshcd_is_link_off(hba)
diff --git a/include/linux/scsi/ufs/ufshcd.h b/include/linux/scsi/ufs/ufshcd.h
index b4d7b5f60995..ad3d250a7018 100644
--- a/include/linux/scsi/ufs/ufshcd.h
+++ b/include/linux/scsi/ufs/ufshcd.h
@@ -312,6 +312,8 @@ struct ufs_pwr_mode_info {
* @crypto_engine_reset_err: resets the saved error status of
* the cryptographic engine
* @dbg_register_dump: used to dump controller debug information
+ * @add_debugfs: used to add debugfs entries
+ * @remove_debugfs: used to remove debugfs entries
*/
struct ufs_hba_variant_ops {
const char *name;
@@ -340,6 +342,10 @@ struct ufs_hba_variant_ops {
int (*crypto_engine_get_err)(struct ufs_hba *);
void (*crypto_engine_reset_err)(struct ufs_hba *);
void (*dbg_register_dump)(struct ufs_hba *hba);
+#ifdef CONFIG_DEBUG_FS
+ void (*add_debugfs)(struct ufs_hba *hba, struct dentry *root);
+ void (*remove_debugfs)(struct ufs_hba *hba);
+#endif
};
/* clock gating state */