Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/net-next
[pandora-kernel.git] / drivers / mmc / host / dw_mmc.c
index fcff3c0..0c839d3 100644 (file)
@@ -496,15 +496,16 @@ static void dw_mci_submit_data(struct dw_mci *host, struct mmc_data *data)
        host->sg = NULL;
        host->data = data;
 
+       if (data->flags & MMC_DATA_READ)
+               host->dir_status = DW_MCI_RECV_STATUS;
+       else
+               host->dir_status = DW_MCI_SEND_STATUS;
+
        if (dw_mci_submit_data_dma(host, data)) {
                host->sg = data->sg;
                host->pio_offset = 0;
                host->part_buf_start = 0;
                host->part_buf_count = 0;
-               if (data->flags & MMC_DATA_READ)
-                       host->dir_status = DW_MCI_RECV_STATUS;
-               else
-                       host->dir_status = DW_MCI_SEND_STATUS;
 
                mci_writel(host, RINTSTS, SDMMC_INT_TXDR | SDMMC_INT_RXDR);
                temp = mci_readl(host, INTMASK);
@@ -848,7 +849,7 @@ static void dw_mci_tasklet_func(unsigned long priv)
        struct mmc_command *cmd;
        enum dw_mci_state state;
        enum dw_mci_state prev_state;
-       u32 status;
+       u32 status, ctrl;
 
        spin_lock(&host->lock);
 
@@ -908,13 +909,19 @@ static void dw_mci_tasklet_func(unsigned long priv)
 
                        if (status & DW_MCI_DATA_ERROR_FLAGS) {
                                if (status & SDMMC_INT_DTO) {
-                                       dev_err(&host->pdev->dev,
-                                               "data timeout error\n");
                                        data->error = -ETIMEDOUT;
                                } else if (status & SDMMC_INT_DCRC) {
-                                       dev_err(&host->pdev->dev,
-                                               "data CRC error\n");
                                        data->error = -EILSEQ;
+                               } else if (status & SDMMC_INT_EBE &&
+                                          host->dir_status ==
+                                                       DW_MCI_SEND_STATUS) {
+                                       /*
+                                        * No data CRC status was returned.
+                                        * The number of bytes transferred will
+                                        * be exaggerated in PIO mode.
+                                        */
+                                       data->bytes_xfered = 0;
+                                       data->error = -ETIMEDOUT;
                                } else {
                                        dev_err(&host->pdev->dev,
                                                "data FIFO error "
@@ -922,6 +929,16 @@ static void dw_mci_tasklet_func(unsigned long priv)
                                                status);
                                        data->error = -EIO;
                                }
+                               /*
+                                * After an error, there may be data lingering
+                                * in the FIFO, so reset it - doing so
+                                * generates a block interrupt, hence setting
+                                * the scatter-gather pointer to NULL.
+                                */
+                               host->sg = NULL;
+                               ctrl = mci_readl(host, CTRL);
+                               ctrl |= SDMMC_CTRL_FIFO_RESET;
+                               mci_writel(host, CTRL, ctrl);
                        } else {
                                data->bytes_xfered = data->blocks * data->blksz;
                                data->error = 0;