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

Reply via email to