mmc: msm_sdcc: Send CMD12 even if r/w command has errors
In SD/eMMC cards read/write multi block commands (CMD18/CMD25)
cause state transition from Transfer state to Data/Receive
state. If there are errors in recieving the response for
these commands the driver doesn't send CMD12 to stop the
transaction and hence the card forever be in Data/Rcv
state until further CMD7 or CMD12 is issued. Fix this by
sending CMD12 (STOP_TRANSMISSION) to change the state back to
transfer mode aborting data transfers.
Note: With current r/w command response it is impossible to
determine if the card has actually transitioned to Data/Rcv
state since the actual card status is reflected at execution
time. Also, there may be errors in "sending" CMD18/25 itself.
Sending CMD12 in this case doesn't cause any harm except one
more command timeout error which is non-fatal.
Change-Id: I1e298260d39cfac796113a4276652626c4011fc3
Signed-off-by: Sujit Reddy Thumma <sthumma@codeaurora.org>
diff --git a/drivers/mmc/host/msm_sdcc.c b/drivers/mmc/host/msm_sdcc.c
index cdfe10e..e853699 100644
--- a/drivers/mmc/host/msm_sdcc.c
+++ b/drivers/mmc/host/msm_sdcc.c
@@ -477,7 +477,11 @@
goto out;
}
msmsdcc_stop_data(host);
- if (!mrq->data->stop || mrq->cmd->error ||
+
+ if (mrq->data->stop && ((mrq->sbc && mrq->data->error)
+ || !mrq->sbc)) {
+ msmsdcc_start_command(host, mrq->data->stop, 0);
+ } else if (!mrq->data->stop || mrq->cmd->error ||
(mrq->sbc && !mrq->data->error)) {
host->curr.mrq = NULL;
host->curr.cmd = NULL;
@@ -487,9 +491,6 @@
mmc_request_done(host->mmc, mrq);
return;
- } else if (mrq->data->stop && ((mrq->sbc && mrq->data->error)
- || !mrq->sbc)) {
- msmsdcc_start_command(host, mrq->data->stop, 0);
}
}
@@ -634,7 +635,10 @@
return;
}
msmsdcc_stop_data(host);
- if (!mrq->data->stop || mrq->cmd->error ||
+ if (mrq->data->stop && ((mrq->sbc && mrq->data->error)
+ || !mrq->sbc)) {
+ msmsdcc_start_command(host, mrq->data->stop, 0);
+ } else if (!mrq->data->stop || mrq->cmd->error ||
(mrq->sbc && !mrq->data->error)) {
host->curr.mrq = NULL;
host->curr.cmd = NULL;
@@ -644,9 +648,6 @@
mmc_request_done(host->mmc, mrq);
return;
- } else if (mrq->data->stop && ((mrq->sbc && mrq->data->error)
- || !mrq->sbc)) {
- msmsdcc_start_command(host, mrq->data->stop, 0);
}
}
spin_unlock_irqrestore(&host->lock, flags);
@@ -943,7 +944,7 @@
msmsdcc_start_command_deferred(struct msmsdcc_host *host,
struct mmc_command *cmd, u32 *c)
{
- DBG(host, "op %02x arg %08x flags %08x\n",
+ DBG(host, "op %d arg %08x flags %08x\n",
cmd->opcode, cmd->arg, cmd->flags);
*c |= (cmd->opcode | MCI_CPSM_ENABLE);
@@ -1392,9 +1393,16 @@
else if (host->curr.data) { /* Non DMA */
msmsdcc_reset_and_restore(host);
msmsdcc_stop_data(host);
- msmsdcc_request_end(host, cmd->mrq);
+ if (cmd->data && cmd->data->stop)
+ msmsdcc_start_command(host,
+ cmd->data->stop, 0);
+ else
+ msmsdcc_request_end(host, cmd->mrq);
} else { /* host->data == NULL */
- if (!cmd->error && host->prog_enable) {
+ if (cmd->data && cmd->data->stop) {
+ msmsdcc_start_command(host,
+ cmd->data->stop, 0);
+ } else if (!cmd->error && host->prog_enable) {
if (status & MCI_PROGDONE) {
host->prog_enable = 0;
msmsdcc_request_end(host, cmd->mrq);