mmc: msm_sdcc: Reset SPS BAM on error recovery
In the current soft reset sequence performed as part of
CMD/DATA error recovery we do the following:
1) Write 1 to DML_SW_RESET
2) Reset CPSM/DPSM by clearing MCI_CMD and MCI_DATA_CTL
or by writing to MCI_SW_RST_CONFIG.
3) Re-init DML
4) Reconfigure both consumer and producer BAM pipes.
The BAM pipe reset does not reset the sideband signals, since
only SDCC side is reset SDCC - BAM communication will go out
of sync and cause DML to be stuck without transferring data.
Hence reset BAM core every time SDCC is reset (which is on
error recovery).
Fix error handling for sps pipe or device reset.
(cherry picked from commit 3ca90f02963ddbbdb300eb55c49aca18091c3f49)
Change-Id: I82bd6c5f3db6ac71da912cef935dfd179b099ed4
Signed-off-by: Venkat Gopalakrishnan <venkatg@codeaurora.org>
Signed-off-by: Krishna Konda <kkonda@codeaurora.org>
(cherry picked from commit 9b2f00f099f4f17025a9834eb38fc67254164608)
Signed-off-by: Maya Erez <merez@codeaurora.org>
diff --git a/drivers/mmc/host/msm_sdcc.c b/drivers/mmc/host/msm_sdcc.c
index f0d6a37..71d89ef 100644
--- a/drivers/mmc/host/msm_sdcc.c
+++ b/drivers/mmc/host/msm_sdcc.c
@@ -213,9 +213,9 @@
#endif /* CONFIG_MMC_MSM_SPS_SUPPORT */
/**
- * Apply soft reset to all SDCC BAM pipes
+ * Apply reset
*
- * This function applies soft reset to SDCC BAM pipe.
+ * This function resets SPS BAM and DML cores.
*
* This function should be called to recover from error
* conditions encountered during CMD/DATA tranfsers with card.
@@ -223,43 +223,64 @@
* @host - Pointer to driver's host structure
*
*/
-static void msmsdcc_sps_pipes_reset_and_restore(struct msmsdcc_host *host)
+static int msmsdcc_bam_dml_reset_and_restore(struct msmsdcc_host *host)
{
int rc;
+ /* Reset and init DML */
+ rc = msmsdcc_dml_init(host);
+ if (rc) {
+ pr_err("%s: msmsdcc_dml_init error=%d\n",
+ mmc_hostname(host->mmc), rc);
+ goto out;
+ }
+
/* Reset all SDCC BAM pipes */
rc = msmsdcc_sps_reset_ep(host, &host->sps.prod);
- if (rc)
- pr_err("%s:msmsdcc_sps_reset_ep(prod) error=%d\n",
+ if (rc) {
+ pr_err("%s: msmsdcc_sps_reset_ep(prod) error=%d\n",
mmc_hostname(host->mmc), rc);
- rc = msmsdcc_sps_reset_ep(host, &host->sps.cons);
- if (rc)
- pr_err("%s:msmsdcc_sps_reset_ep(cons) error=%d\n",
- mmc_hostname(host->mmc), rc);
+ goto out;
+ }
- if (host->sps.reset_device) {
- rc = sps_device_reset(host->sps.bam_handle);
- if (rc)
- pr_err("%s: sps_device_reset error=%d\n",
+ rc = msmsdcc_sps_reset_ep(host, &host->sps.cons);
+ if (rc) {
+ pr_err("%s: msmsdcc_sps_reset_ep(cons) error=%d\n",
mmc_hostname(host->mmc), rc);
- host->sps.reset_device = false;
+ goto out;
+ }
+
+ /* Reset BAM */
+ rc = sps_device_reset(host->sps.bam_handle);
+ if (rc) {
+ pr_err("%s: sps_device_reset error=%d\n",
+ mmc_hostname(host->mmc), rc);
+ goto out;
}
/* Restore all BAM pipes connections */
rc = msmsdcc_sps_restore_ep(host, &host->sps.prod);
- if (rc)
- pr_err("%s:msmsdcc_sps_restore_ep(prod) error=%d\n",
+ if (rc) {
+ pr_err("%s: msmsdcc_sps_restore_ep(prod) error=%d\n",
mmc_hostname(host->mmc), rc);
+ goto out;
+ }
+
rc = msmsdcc_sps_restore_ep(host, &host->sps.cons);
if (rc)
- pr_err("%s:msmsdcc_sps_restore_ep(cons) error=%d\n",
+ pr_err("%s: msmsdcc_sps_restore_ep(cons) error=%d\n",
mmc_hostname(host->mmc), rc);
+ else
+ host->sps.reset_bam = false;
+
+out:
+ return rc;
}
/**
* Apply soft reset
*
- * This function applies soft reset to SDCC core and DML core.
+ * This function applies soft reset to SDCC core.
*
* This function should be called to recover from error
* conditions encountered with CMD/DATA tranfsers with card.
@@ -354,25 +375,25 @@
static void msmsdcc_reset_and_restore(struct msmsdcc_host *host)
{
if (is_soft_reset(host)) {
- if (is_sps_mode(host)) {
- /* Reset DML first */
- msmsdcc_dml_reset(host);
+ if (is_sps_mode(host))
/*
- * delay the SPS pipe reset in thread context as
+ * delay the SPS BAM reset in thread context as
* sps_connect/sps_disconnect APIs can be called
* only from non-atomic context.
*/
- host->sps.pipe_reset_pending = true;
- }
- mb();
+ host->sps.reset_bam = true;
+
msmsdcc_soft_reset(host);
pr_debug("%s: Applied soft reset to Controller\n",
mmc_hostname(host->mmc));
-
- if (is_sps_mode(host))
- msmsdcc_dml_init(host);
} else {
+ /*
+ * When there is a requirement to use this hard reset,
+ * BAM needs to be reconfigured as well by calling
+ * msmsdcc_sps_exit and msmsdcc_sps_init.
+ */
+
/* Give Clock reset (hard reset) to controller */
u32 mci_clk = 0;
u32 mci_mask0 = 0;
@@ -2067,6 +2088,7 @@
{
struct msmsdcc_host *host = mmc_priv(mmc);
unsigned long flags;
+ int retries = 5;
/*
* Get the SDIO AL client out of LPM.
@@ -2075,10 +2097,14 @@
if (host->plat->is_sdio_al_client)
msmsdcc_sdio_al_lpm(mmc, false);
- /* check if sps pipe reset is pending? */
- if (is_sps_mode(host) && host->sps.pipe_reset_pending) {
- msmsdcc_sps_pipes_reset_and_restore(host);
- host->sps.pipe_reset_pending = false;
+ /* check if sps bam needs to be reset */
+ if (is_sps_mode(host) && host->sps.reset_bam) {
+ while (retries) {
+ if (!msmsdcc_bam_dml_reset_and_restore(host))
+ break;
+ pr_err("%s: msmsdcc_bam_dml_reset_and_restore returned error. %d attempts left.\n",
+ mmc_hostname(host->mmc), --retries);
+ }
}
spin_lock_irqsave(&host->lock, flags);
@@ -2099,8 +2125,9 @@
/*
* Don't start the request if SDCC is not in proper state to handle it
*/
- if (!host->pwr || !atomic_read(&host->clks_on)
- || host->sdcc_irq_disabled) {
+ if (!host->pwr || !atomic_read(&host->clks_on) ||
+ host->sdcc_irq_disabled ||
+ host->sps.reset_bam) {
WARN(1, "%s: %s: SDCC is in bad state. don't process"
" new request (CMD%d)\n", mmc_hostname(host->mmc),
__func__, mrq->cmd->opcode);
@@ -4569,11 +4596,8 @@
BUG_ON(!is_sps_mode(host));
if (sps_cb_case == SPS_CALLBACK_BAM_ERROR_IRQ) {
- /**
- * Reset the all endpoints along with reseting the sps device.
- */
- host->sps.pipe_reset_pending = true;
- host->sps.reset_device = true;
+ /* Reset all endpoints along with resetting bam. */
+ host->sps.reset_bam = true;
pr_err("%s: BAM Global ERROR IRQ happened\n",
mmc_hostname(host->mmc));
@@ -4928,7 +4952,11 @@
host->curr.data_xfered, host->curr.xfer_remain);
}
- pr_info("%s: got_dataend=%d, prog_enable=%d,"
+ if (host->sps.reset_bam)
+ pr_err("%s: SPS BAM reset failed: sps reset_bam=%d\n",
+ mmc_hostname(host->mmc), host->sps.reset_bam);
+
+ pr_err("%s: got_dataend=%d, prog_enable=%d,"
" wait_for_auto_prog_done=%d, got_auto_prog_done=%d,"
" req_tout_ms=%d\n", mmc_hostname(host->mmc),
host->curr.got_dataend, host->prog_enable,
diff --git a/drivers/mmc/host/msm_sdcc.h b/drivers/mmc/host/msm_sdcc.h
index 236785d..d690c7a 100644
--- a/drivers/mmc/host/msm_sdcc.h
+++ b/drivers/mmc/host/msm_sdcc.h
@@ -2,7 +2,7 @@
* linux/drivers/mmc/host/msmsdcc.h - QCT MSM7K SDC Controller
*
* Copyright (C) 2008 Google, All Rights Reserved.
- * Copyright (c) 2009-2012, Code Aurora Forum. All rights reserved.
+ * Copyright (c) 2009-2012, 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 as
@@ -320,8 +320,7 @@
unsigned int dest_pipe_index;
unsigned int busy;
unsigned int xfer_req_cnt;
- bool pipe_reset_pending;
- bool reset_device;
+ bool reset_bam;
struct tasklet_struct tlet;
};