scsi: ufs-qcom: add print suppressing debugfs mechanism

Provide a mechanism for the userspace to suppress specific
debug prints via debugfs. This is useful in order to avoid
cases where too much printing would cause watchdog timers
to expire.

Change-Id: I2500b7621b631e260d98595ed8cfe7d5a496dc10
Signed-off-by: Dov Levenglick <dovl@codeaurora.org>
This commit is contained in:
Dov Levenglick 2015-01-05 17:48:45 +02:00 committed by David Keitel
parent a422990e68
commit 6021822eca
7 changed files with 167 additions and 4 deletions

View file

@ -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

View file

@ -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);

View file

@ -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;
}

View file

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

View file

@ -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
};
/**

View file

@ -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)

View file

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