From: David Brownell <[email protected]>
Clean up MMC/SD fault handling for transfers with data stages:
- After DMA errors, always issue any STOP needed; aborting DMA
on the host is not sufficient to reset the card's state.
- It does that already after data or command errors; but also:
* Always reset the data and command state machines, instead
of just the command machine (and just for data "CRC" errors)
* Report how many blocks were transferred (resolving FIXMEs)
There are probably still a few holes in fault handling, but these
updates resolved some problems I was (briefly) able to reproduce
by running a DM6446 quite a bit faster than it's supposed to be
able to handle.
Signed-off-by: David Brownell <[email protected]>
---
drivers/mmc/host/davinci_mmc.c | 50 ++++++++++++++++++++++++---------------
1 file changed, 32 insertions(+), 18 deletions(-)
--- a/drivers/mmc/host/davinci_mmc.c
+++ b/drivers/mmc/host/davinci_mmc.c
@@ -423,6 +423,9 @@ static void davinci_abort_dma(struct mmc
edma_clean_channel(sync_dev);
}
+static void
+mmc_davinci_xfer_done(struct mmc_davinci_host *host, struct mmc_data *data);
+
static void mmc_davinci_dma_cb(unsigned channel, u16 ch_status, void *data)
{
if (DMA_COMPLETE != ch_status) {
@@ -435,8 +438,8 @@ static void mmc_davinci_dma_cb(unsigned
dev_warn(mmc_dev(host->mmc), "DMA %s error\n",
(host->data->flags & MMC_DATA_WRITE)
? "write" : "read");
- davinci_abort_dma(host);
host->data->error = -EIO;
+ mmc_davinci_xfer_done(host, host->data);
}
}
@@ -868,6 +871,25 @@ static void mmc_davinci_cmd_done(struct
}
}
+static void
+davinci_abort_data(struct mmc_davinci_host *host, struct mmc_data *data)
+{
+ u32 temp;
+
+ /* record how much data we transferred */
+ temp = readl(host->base + DAVINCI_MMCNBLC);
+ data->bytes_xfered += (data->blocks - temp) * data->blksz;
+
+ /* reset command and data state machines */
+ temp = readl(host->base + DAVINCI_MMCCTL);
+ writel(temp | MMCCTL_CMDRST | MMCCTL_DATRST,
+ host->base + DAVINCI_MMCCTL);
+
+ temp &= ~(MMCCTL_CMDRST | MMCCTL_DATRST);
+ udelay(10);
+ writel(temp, host->base + DAVINCI_MMCCTL);
+}
+
static inline int handle_core_command(
struct mmc_davinci_host *host, unsigned int status)
{
@@ -906,30 +928,18 @@ static inline int handle_core_command(
data->error = -ETIMEDOUT;
end_transfer = 1;
- /* REVISIT report *actual* bytecount on errors */
-
dev_dbg(mmc_dev(host->mmc),
"read data timeout, status %x\n",
qstatus);
+
+ davinci_abort_data(host, data);
}
if (qstatus & (MMCST0_CRCWR | MMCST0_CRCRD)) {
- u32 temp;
-
- /* DAT line portion is disabled and in reset state */
- temp = readl(host->base + DAVINCI_MMCCTL);
- writel(temp | MMCCTL_CMDRST,
- host->base + DAVINCI_MMCCTL);
- udelay(10);
- writel(temp & ~MMCCTL_CMDRST,
- host->base + DAVINCI_MMCCTL);
-
/* Data CRC error */
data->error = -EILSEQ;
end_transfer = 1;
- /* REVISIT report *actual* bytecount on errors */
-
/* NOTE: this controller uses CRCWR to report both CRC
* errors and timeouts (on writes). MMCDRSP values are
* only weakly documented, but 0x9f was clearly a timeout
@@ -937,13 +947,16 @@ static inline int handle_core_command(
* (101, 010) aren't part of it ...
*/
if (qstatus & MMCST0_CRCWR) {
- temp = readb(host->base + DAVINCI_MMCDRSP);
+ u32 temp = readb(host->base + DAVINCI_MMCDRSP);
+
if (temp == 0x9f)
data->error = -ETIMEDOUT;
}
dev_dbg(mmc_dev(host->mmc), "data %s %s error\n",
(qstatus & MMCST0_CRCWR) ? "write" : "read",
(data->error == -ETIMEDOUT) ? "timeout" : "CRC");
+
+ davinci_abort_data(host, data);
}
if (qstatus & MMCST0_TOUTRS) {
@@ -953,9 +966,10 @@ static inline int handle_core_command(
"timeout, status %x\n",
host->cmd->opcode, qstatus);
host->cmd->error = -ETIMEDOUT;
- if (data)
+ if (data) {
end_transfer = 1;
- else
+ davinci_abort_data(host, data);
+ } else
end_command = 1;
}
}
_______________________________________________
Davinci-linux-open-source mailing list
[email protected]
http://linux.davincidsp.com/mailman/listinfo/davinci-linux-open-source