From b78e1b402589663b584111e24b6756beccef4797 Mon Sep 17 00:00:00 2001 From: Venkat Gopalakrishnan Date: Tue, 15 Sep 2015 15:57:35 -0700 Subject: mmc: debugfs: add debugfs entry to force raise host errors The SDHC spec allows to force raise errors that is useful for debugging error handler routines. Add debugfs entry force_error to trigger host errors from userspace. Check SDHCI_SET_INT_ERROR register for error bitmask info. Usage: echo 0x1 > /sys/kernel/debug/mmcX/force_error X - denotes the slot id Change-Id: I9f67442a79b2645cbdc3020d1a10c0b32840ce32 Signed-off-by: Venkat Gopalakrishnan [subhashj@codeaurora.org: fixed trivial merge conflicts] Signed-off-by: Subhash Jadavani --- drivers/mmc/core/debugfs.c | 19 +++++++++++++++++++ drivers/mmc/host/sdhci.c | 13 +++++++++++++ include/linux/mmc/host.h | 1 + 3 files changed, 33 insertions(+) diff --git a/drivers/mmc/core/debugfs.c b/drivers/mmc/core/debugfs.c index 98b9e90e667a..7e3d82f658e7 100644 --- a/drivers/mmc/core/debugfs.c +++ b/drivers/mmc/core/debugfs.c @@ -313,6 +313,21 @@ out: DEFINE_SIMPLE_ATTRIBUTE(mmc_max_clock_fops, mmc_max_clock_get, mmc_max_clock_set, "%llu\n"); +static int mmc_force_err_set(void *data, u64 val) +{ + struct mmc_host *host = data; + + if (host && host->ops && host->ops->force_err_irq) { + mmc_host_clk_hold(host); + host->ops->force_err_irq(host, val); + mmc_host_clk_release(host); + } + + return 0; +} + +DEFINE_SIMPLE_ATTRIBUTE(mmc_force_err_fops, NULL, mmc_force_err_set, "%llu\n"); + void mmc_add_host_debugfs(struct mmc_host *host) { struct dentry *root; @@ -362,6 +377,10 @@ void mmc_add_host_debugfs(struct mmc_host *host) &host->fail_mmc_request))) goto err_node; #endif + if (!debugfs_create_file("force_error", S_IWUSR, root, host, + &mmc_force_err_fops)) + goto err_node; + return; err_node: diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c index 999bd8e839de..9761cd7f5a80 100644 --- a/drivers/mmc/host/sdhci.c +++ b/drivers/mmc/host/sdhci.c @@ -2603,6 +2603,18 @@ static int sdhci_late_init(struct mmc_host *mmc) return 0; } + +static void sdhci_force_err_irq(struct mmc_host *mmc, u64 errmask) +{ + struct sdhci_host *host = mmc_priv(mmc); + u16 mask = errmask & 0xFFFF; + + pr_err("%s: Force raise error mask:0x%04x\n", __func__, mask); + sdhci_runtime_pm_get(host); + sdhci_writew(host, mask, SDHCI_SET_INT_ERROR); + sdhci_runtime_pm_put(host); +} + static const struct mmc_host_ops sdhci_ops = { .init = sdhci_late_init, .request = sdhci_request, @@ -2625,6 +2637,7 @@ static const struct mmc_host_ops sdhci_ops = { .notify_load = sdhci_notify_load, .notify_halt = sdhci_notify_halt, .detect = sdhci_detect, + .force_err_irq = sdhci_force_err_irq, }; /*****************************************************************************\ diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h index 87f90a7d061a..a312467be721 100644 --- a/include/linux/mmc/host.h +++ b/include/linux/mmc/host.h @@ -182,6 +182,7 @@ struct mmc_host_ops { int (*notify_load)(struct mmc_host *, enum mmc_load); void (*notify_halt)(struct mmc_host *mmc, bool halt); void (*detect)(struct mmc_host *host, bool detected); + void (*force_err_irq)(struct mmc_host *host, u64 errmask); }; struct mmc_card; -- cgit v1.2.3