Merge "mmc: mmc-debugfs: add error state"
diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c
index ef7252b..e75444a 100644
--- a/drivers/mmc/core/core.c
+++ b/drivers/mmc/core/core.c
@@ -2240,6 +2240,38 @@
EXPORT_SYMBOL(__mmc_claim_host);
/**
+ * mmc_try_claim_host - try exclusively to claim a host
+ * and keep trying for given time, with a gap of 10ms
+ * @host: mmc host to claim
+ * @dealy_ms: delay in ms
+ *
+ * Returns %1 if the host is claimed, %0 otherwise.
+ */
+int mmc_try_claim_host(struct mmc_host *host, unsigned int delay_ms)
+{
+ int claimed_host = 0;
+ unsigned long flags;
+ int retry_cnt = delay_ms/10;
+
+ do {
+ spin_lock_irqsave(&host->lock, flags);
+ if (!host->claimed || host->claimer == current) {
+ host->claimed = 1;
+ host->claimer = current;
+ host->claim_cnt += 1;
+ claimed_host = 1;
+ }
+ spin_unlock_irqrestore(&host->lock, flags);
+ if (!claimed_host)
+ mmc_delay(10);
+ } while (!claimed_host && retry_cnt--);
+ if (host->ops->enable && claimed_host && host->claim_cnt == 1)
+ host->ops->enable(host);
+ return claimed_host;
+}
+EXPORT_SYMBOL(mmc_try_claim_host);
+
+/**
* mmc_release_host - release a host
* @host: mmc host to release
*
diff --git a/drivers/mmc/core/debugfs.c b/drivers/mmc/core/debugfs.c
index 0c8ff86..d1a0235 100644
--- a/drivers/mmc/core/debugfs.c
+++ b/drivers/mmc/core/debugfs.c
@@ -354,6 +354,33 @@
DEFINE_SIMPLE_ATTRIBUTE(mmc_force_err_fops, NULL, mmc_force_err_set, "%llu\n");
+static int mmc_err_state_get(void *data, u64 *val)
+{
+ struct mmc_host *host = data;
+
+ if (!host)
+ return -EINVAL;
+
+ *val = host->err_occurred ? 1 : 0;
+
+ return 0;
+}
+
+static int mmc_err_state_clear(void *data, u64 val)
+{
+ struct mmc_host *host = data;
+
+ if (!host)
+ return -EINVAL;
+
+ host->err_occurred = false;
+
+ return 0;
+}
+
+DEFINE_SIMPLE_ATTRIBUTE(mmc_err_state, mmc_err_state_get,
+ mmc_err_state_clear, "%llu\n");
+
void mmc_add_host_debugfs(struct mmc_host *host)
{
struct dentry *root;
@@ -399,6 +426,10 @@
root, host, &mmc_ring_buffer_fops))
goto err_node;
#endif
+ if (!debugfs_create_file("err_state", S_IRUSR | S_IWUSR, root, host,
+ &mmc_err_state))
+ goto err_node;
+
#ifdef CONFIG_MMC_CLKGATE
if (!debugfs_create_u32("clk_delay", (S_IRUSR | S_IWUSR),
root, &host->clk_delay))
diff --git a/drivers/mmc/core/sd.c b/drivers/mmc/core/sd.c
index 7112f9f..650f658 100644
--- a/drivers/mmc/core/sd.c
+++ b/drivers/mmc/core/sd.c
@@ -1185,7 +1185,17 @@
BUG_ON(!host);
BUG_ON(!host->card);
- mmc_get_card(host->card);
+ /*
+ * Try to acquire claim host. If failed to get the lock in 2 sec,
+ * just return; This is to ensure that when this call is invoked
+ * due to pm_suspend, not to block suspend for longer duration.
+ */
+ pm_runtime_get_sync(&host->card->dev);
+ if (!mmc_try_claim_host(host, 2000)) {
+ pm_runtime_mark_last_busy(&host->card->dev);
+ pm_runtime_put_autosuspend(&host->card->dev);
+ return;
+ }
/*
* Just check if our card has been removed.
diff --git a/drivers/mmc/host/sdhci-msm.c b/drivers/mmc/host/sdhci-msm.c
index caf8dd1..05d8a52 100644
--- a/drivers/mmc/host/sdhci-msm.c
+++ b/drivers/mmc/host/sdhci-msm.c
@@ -3270,6 +3270,21 @@
pr_err("-------------------------\n");
}
+static void sdhci_msm_cache_debug_data(struct sdhci_host *host)
+{
+ struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
+ struct sdhci_msm_host *msm_host = pltfm_host->priv;
+ struct sdhci_msm_debug_data *cached_data = &msm_host->cached_data;
+
+ memcpy(&cached_data->copy_mmc, msm_host->mmc,
+ sizeof(struct mmc_host));
+ if (msm_host->mmc->card)
+ memcpy(&cached_data->copy_card, msm_host->mmc->card,
+ sizeof(struct mmc_card));
+ memcpy(&cached_data->copy_host, host,
+ sizeof(struct sdhci_host));
+}
+
void sdhci_msm_dump_vendor_regs(struct sdhci_host *host)
{
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
@@ -3281,6 +3296,7 @@
u32 test_bus_val = 0;
u32 debug_reg[MAX_TEST_BUS] = {0};
+ sdhci_msm_cache_debug_data(host);
pr_info("----------- VENDOR REGISTER DUMP -----------\n");
if (host->cq_host)
sdhci_msm_cmdq_dump_debug_ram(host);
diff --git a/drivers/mmc/host/sdhci-msm.h b/drivers/mmc/host/sdhci-msm.h
index a7577d9..2b907e9 100644
--- a/drivers/mmc/host/sdhci-msm.h
+++ b/drivers/mmc/host/sdhci-msm.h
@@ -170,6 +170,12 @@
int state;
};
+struct sdhci_msm_debug_data {
+ struct mmc_host copy_mmc;
+ struct mmc_card copy_card;
+ struct sdhci_host copy_host;
+};
+
struct sdhci_msm_host {
struct platform_device *pdev;
void __iomem *core_mem; /* MSM SDCC mapped address */
@@ -185,6 +191,7 @@
atomic_t clks_on; /* Set if clocks are enabled */
struct sdhci_msm_pltfm_data *pdata;
struct mmc_host *mmc;
+ struct sdhci_msm_debug_data cached_data;
struct sdhci_pltfm_data sdhci_msm_pdata;
u32 curr_pwr_state;
u32 curr_io_level;
diff --git a/include/linux/mmc/core.h b/include/linux/mmc/core.h
index 959414b..0f2e651 100644
--- a/include/linux/mmc/core.h
+++ b/include/linux/mmc/core.h
@@ -214,6 +214,7 @@
extern int __mmc_claim_host(struct mmc_host *host, atomic_t *abort);
extern void mmc_release_host(struct mmc_host *host);
+extern int mmc_try_claim_host(struct mmc_host *host, unsigned int delay);
extern void mmc_get_card(struct mmc_card *card);
extern void mmc_put_card(struct mmc_card *card);
diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h
index df841cf..9200069 100644
--- a/include/linux/mmc/host.h
+++ b/include/linux/mmc/host.h
@@ -559,6 +559,8 @@
struct dentry *debugfs_root;
+ bool err_occurred;
+
struct mmc_async_req *areq; /* active async req */
struct mmc_context_info context_info; /* async synchronization info */