mmc: msm_sdcc: Send CMD52 after every CMD53 write
On a completion of a CMD53 write, send a dummy CMD52
before reporting completion to client.
Signed-off-by: Oluwafemi Adeyemi <aadeyemi@codeaurora.org>
Signed-off-by: Sahitya Tummala <stummala@codeaurora.org>
diff --git a/drivers/mmc/host/msm_sdcc.c b/drivers/mmc/host/msm_sdcc.c
index 4702c6c..69cf69e 100644
--- a/drivers/mmc/host/msm_sdcc.c
+++ b/drivers/mmc/host/msm_sdcc.c
@@ -80,9 +80,6 @@
static unsigned int msmsdcc_pwrsave = 1;
-#define DUMMY_52_STATE_NONE 0
-#define DUMMY_52_STATE_SENT 1
-
static struct mmc_command dummy52cmd;
static struct mmc_request dummy52mrq = {
.cmd = &dummy52cmd,
@@ -261,6 +258,8 @@
host->clk_rate, ret);
mb();
}
+ if (host->dummy_52_needed)
+ host->dummy_52_needed = 0;
}
static int
@@ -400,12 +399,19 @@
* If we've already gotten our DATAEND / DATABLKEND
* for this request, then complete it through here.
*/
- msmsdcc_stop_data(host);
if (!mrq->data->error) {
host->curr.data_xfered = host->curr.xfer_size;
host->curr.xfer_remain -= host->curr.xfer_size;
}
+ if (host->dummy_52_needed) {
+ mrq->data->bytes_xfered = host->curr.data_xfered;
+ host->dummy_52_sent = 1;
+ msmsdcc_start_command(host, &dummy52cmd,
+ MCI_CPSM_PROGENA);
+ goto out;
+ }
+ msmsdcc_stop_data(host);
if (!mrq->data->stop || mrq->cmd->error) {
host->curr.mrq = NULL;
host->curr.cmd = NULL;
@@ -544,12 +550,19 @@
* If we've already gotten our DATAEND / DATABLKEND
* for this request, then complete it through here.
*/
- msmsdcc_stop_data(host);
if (!mrq->data->error) {
host->curr.data_xfered = host->curr.xfer_size;
host->curr.xfer_remain -= host->curr.xfer_size;
}
+ if (host->dummy_52_needed) {
+ mrq->data->bytes_xfered = host->curr.data_xfered;
+ host->dummy_52_sent = 1;
+ msmsdcc_start_command(host, &dummy52cmd,
+ MCI_CPSM_PROGENA);
+ return;
+ }
+ msmsdcc_stop_data(host);
if (!mrq->data->stop || mrq->cmd->error) {
host->curr.mrq = NULL;
host->curr.cmd = NULL;
@@ -1057,7 +1070,7 @@
}
/* Dummy CMD52 is not needed when CMD53 has errors */
- if (host->plat->dummy52_required && host->dummy_52_needed)
+ if (host->dummy_52_needed)
host->dummy_52_needed = 0;
}
@@ -1119,6 +1132,7 @@
uint32_t status;
status = readl_relaxed(base + MMCISTATUS);
+
if (((readl_relaxed(host->base + MMCIMASK0) & status) &
(MCI_IRQ_PIO)) == 0)
return IRQ_NONE;
@@ -1283,12 +1297,10 @@
host->prog_scan = 0;
host->prog_enable = 0;
}
- if (cmd->data && cmd->error) {
+ if (host->dummy_52_needed)
+ host->dummy_52_needed = 0;
+ if (cmd->data && cmd->error)
msmsdcc_reset_and_restore(host);
- if (host->plat->dummy52_required &&
- host->dummy_52_needed)
- host->dummy_52_needed = 0;
- }
msmsdcc_request_end(host, cmd->mrq);
}
}
@@ -1346,6 +1358,7 @@
#if IRQ_DEBUG
msmsdcc_print_status(host, "irq0-p", status);
#endif
+
#ifdef CONFIG_MMC_MSM_SDIO_SUPPORT
if (status & MCI_SDIOINTROPE) {
if (host->sdcc_suspending)
@@ -1353,8 +1366,9 @@
mmc_signal_sdio_irq(host->mmc);
}
#endif
- if ((host->plat->dummy52_required) &&
- (host->dummy_52_state == DUMMY_52_STATE_SENT)) {
+ data = host->curr.data;
+
+ if (host->dummy_52_sent) {
if (status & (MCI_PROGDONE | MCI_CMDCRCFAIL |
MCI_CMDTIMEOUT)) {
if (status & MCI_CMDTIMEOUT)
@@ -1363,17 +1377,19 @@
if (status & MCI_CMDCRCFAIL)
pr_debug("%s: dummy CMD52 CRC failed\n",
mmc_hostname(host->mmc));
- host->dummy_52_state = DUMMY_52_STATE_NONE;
- host->curr.cmd = NULL;
- msmsdcc_request_start(host, host->curr.mrq);
+ host->dummy_52_sent = 0;
+ host->dummy_52_needed = 0;
+ if (data) {
+ msmsdcc_stop_data(host);
+ msmsdcc_request_end(host, data->mrq);
+ }
+ WARN(!data, "No data cmd for dummy CMD52\n");
spin_unlock(&host->lock);
return IRQ_HANDLED;
}
break;
}
- data = host->curr.data;
-
/*
* Check for proper command response
*/
@@ -1437,7 +1453,6 @@
if (data->flags & MMC_DATA_READ)
msmsdcc_wait_for_rxdata(host,
data);
- msmsdcc_stop_data(host);
if (!data->error) {
host->curr.data_xfered =
host->curr.xfer_size;
@@ -1445,13 +1460,23 @@
host->curr.xfer_size;
}
- if (!data->stop)
- timer |= msmsdcc_request_end(
- host, data->mrq);
- else {
+ if (!host->dummy_52_needed) {
+ msmsdcc_stop_data(host);
+ if (!data->stop) {
+ msmsdcc_request_end(
+ host,
+ data->mrq);
+ } else {
+ msmsdcc_start_command(
+ host,
+ data->stop, 0);
+ timer = 1;
+ }
+ } else {
+ host->dummy_52_sent = 1;
msmsdcc_start_command(host,
- data->stop, 0);
- timer = 1;
+ &dummy52cmd,
+ MCI_CPSM_PROGENA);
}
}
}
@@ -1485,6 +1510,7 @@
/*
* Get the SDIO AL client out of LPM.
*/
+ WARN(host->dummy_52_sent, "Dummy CMD52 in progress\n");
if (host->plat->is_sdio_al_client)
msmsdcc_sdio_al_lpm(mmc, false);
@@ -1510,24 +1536,11 @@
host->curr.mrq = mrq;
if (host->plat->dummy52_required) {
- if (host->dummy_52_needed) {
- host->dummy_52_state = DUMMY_52_STATE_SENT;
- msmsdcc_start_command(host, &dummy52cmd,
- MCI_CPSM_PROGENA);
- spin_unlock_irqrestore(&host->lock, flags);
- if (mrq->data && mrq->data->flags == MMC_DATA_WRITE) {
- if (mrq->cmd->opcode == SD_IO_RW_EXTENDED ||
- mrq->cmd->opcode == 54)
- host->dummy_52_needed = 1;
- } else {
- host->dummy_52_needed = 0;
- }
- return;
- }
if (mrq->data && mrq->data->flags == MMC_DATA_WRITE) {
if (mrq->cmd->opcode == SD_IO_RW_EXTENDED ||
- mrq->cmd->opcode == 54)
+ mrq->cmd->opcode == 54) {
host->dummy_52_needed = 1;
+ }
}
}
msmsdcc_request_start(host, mrq);
@@ -3208,11 +3221,10 @@
unsigned long flags;
spin_lock_irqsave(&host->lock, flags);
- if ((host->plat->dummy52_required) &&
- (host->dummy_52_state == DUMMY_52_STATE_SENT)) {
+ if (host->dummy_52_sent) {
pr_info("%s: %s: dummy CMD52 timeout\n",
mmc_hostname(host->mmc), __func__);
- host->dummy_52_state = DUMMY_52_STATE_NONE;
+ host->dummy_52_sent = 0;
}
mrq = host->curr.mrq;
@@ -3222,7 +3234,7 @@
__func__, mrq->cmd->opcode);
if (!mrq->cmd->error)
mrq->cmd->error = -ETIMEDOUT;
- if (host->plat->dummy52_required && host->dummy_52_needed)
+ if (host->dummy_52_needed)
host->dummy_52_needed = 0;
if (host->curr.data) {
pr_info("%s: %s Request timeout\n",
diff --git a/drivers/mmc/host/msm_sdcc.h b/drivers/mmc/host/msm_sdcc.h
index c6acea9..9ad0bfa 100644
--- a/drivers/mmc/host/msm_sdcc.h
+++ b/drivers/mmc/host/msm_sdcc.h
@@ -335,7 +335,8 @@
unsigned int mci_irqenable;
unsigned int dummy_52_needed;
- unsigned int dummy_52_state;
+ unsigned int dummy_52_sent;
+
unsigned int sdio_irq_disabled;
struct wake_lock sdio_wlock;
struct wake_lock sdio_suspend_wlock;