mmc: msm_sdcc: reset wait_for_auto_prog_done flag in case of an error
"wait_for_auto_prog_done" flag is set when CMD53, single block write
(CMD24) or pre-defined (prefixed with CMD23) multi block write
(CMD25) need to be sent to card. This flag tells the
msmsdcc_start_data() to set the AUTO_PROG_DONE bit in MCI_DATA_CTL
register. If AUTO_PROG_DONE bit is set, SDCC controller will raise
the PROG_DONE at the end of above mentioned write transfers
(command + data) and "wait_for_auto_prog_done" gets cleared at
the end of transfer.
But if we get the error during the command transfer phase itself,
there is a chance that "wait_for_auto_prog_done" remains set which
means it remains sticky during next SDCC transfer request as well.
And if next data transfer is data read operation, having this
"wait_for_auto_prog_done" flag set will not allow the transfer to
end which may cause SDCC driver to raise request timeout.
Following is one such error condition:
<6>[ 667.001892] mmc1: CMD6: Request timeout
<6>[ 667.004700] mmc1: SDCC PWR is ON
<6>[ 667.007904] mmc1: SDCC clks are ON, MCLK rate=400000
<6>[ 667.012848] mmc1: SDCC irq is enabled
<6>[ 667.067633] mmc1: SPS mode: busy=0
<6>[ 667.071020] mmc1: xfer_size=64, data_xfered=64, xfer_remain=0
<6>[ 667.076758] mmc1: got_dataend=1, prog_enable=0,
wait_for_auto_prog_done=1, got_auto_prog_done=0
This patch ensures that "wait_for_auto_prog_done" gets cleared even when
error is seen during command transfer phase itself.
CRs-fixed: 342901
Change-Id: I27f635775ca488826fb46995784b544772fd8e16
Signed-off-by: Subhash Jadavani <subhashj@codeaurora.org>
diff --git a/drivers/mmc/host/msm_sdcc.c b/drivers/mmc/host/msm_sdcc.c
index 6a02f48..ff12eb1 100644
--- a/drivers/mmc/host/msm_sdcc.c
+++ b/drivers/mmc/host/msm_sdcc.c
@@ -342,9 +342,6 @@
BUG_ON(host->curr.data);
- host->curr.mrq = NULL;
- host->curr.cmd = NULL;
-
del_timer(&host->req_tout_timer);
if (mrq->data)
@@ -352,6 +349,9 @@
if (mrq->cmd->error == -ETIMEDOUT)
mdelay(5);
+ /* Clear current request information as current request has ended */
+ memset(&host->curr, 0, sizeof(struct msmsdcc_curr_req));
+
/*
* Need to drop the host lock here; mmc_request_done may call
* back into the driver...
@@ -511,10 +511,13 @@
msmsdcc_stop_data(host);
if (!mrq->data->stop || mrq->cmd->error ||
(mrq->sbc && !mrq->data->error)) {
- host->curr.mrq = NULL;
- host->curr.cmd = NULL;
mrq->data->bytes_xfered = host->curr.data_xfered;
del_timer(&host->req_tout_timer);
+ /*
+ * Clear current request information as current
+ * request has ended
+ */
+ memset(&host->curr, 0, sizeof(struct msmsdcc_curr_req));
spin_unlock_irqrestore(&host->lock, flags);
mmc_request_done(host->mmc, mrq);
@@ -668,10 +671,13 @@
msmsdcc_stop_data(host);
if (!mrq->data->stop || mrq->cmd->error ||
(mrq->sbc && !mrq->data->error)) {
- host->curr.mrq = NULL;
- host->curr.cmd = NULL;
mrq->data->bytes_xfered = host->curr.data_xfered;
del_timer(&host->req_tout_timer);
+ /*
+ * Clear current request information as current
+ * request has ended
+ */
+ memset(&host->curr, 0, sizeof(struct msmsdcc_curr_req));
spin_unlock_irqrestore(&host->lock, flags);
mmc_request_done(host->mmc, mrq);
@@ -1561,6 +1567,7 @@
host->curr.cmd = cmd;
} else {
host->prog_enable = 0;
+ host->curr.wait_for_auto_prog_done = 0;
if (host->dummy_52_needed)
host->dummy_52_needed = 0;
if (cmd->data && cmd->error)
@@ -3981,6 +3988,7 @@
}
} else {
host->prog_enable = 0;
+ host->curr.wait_for_auto_prog_done = 0;
msmsdcc_reset_and_restore(host);
msmsdcc_request_end(host, mrq);
}