More improvements and fixes for the Synopsys DesignWare MCI driver so
that it passes the mmc_test suite:
[PATCH 1/4] mmc: dw_mmc: fix stop when fallen back to PIO
Fixes a hang after an error/timeout in PIO mode.
[PATCH 2/4] mmc: dw_mmc: remove unnecessary error messages
Removes some dev_err's since an errno is sufficient.
[PATCH 3/4] mmc: dw_mmc: handle "no CRC status" error
Fixes "Correct xfer_size at write" tests.
[PATCH 4/4] mmc: dw_mmc: reset FIFO after an error
Fixes modified "Correct xfer_size at write" tests (3 blocks
instead of 2).
drivers/mmc/host/dw_mmc.c | 41 +++++++++++++++++++++++++++++++----------
include/linux/mmc/dw_mmc.h | 2 ++
2 files changed, 33 insertions(+), 10 deletions(-)
There are several situations when dw_mci_submit_data_dma() decides to
fall back to PIO mode instead of using DMA, due to a short (to avoid
overhead) or "complex" (e.g. with unaligned buffers) transaction, even
though host->use_dma is set. However dw_mci_stop_dma() decides whether
to stop DMA or set the EVENT_XFER_COMPLETE event based on host->use_dma.
When falling back to PIO mode this results in data timeout errors
getting missed and the driver locking up.
Therefore add host->using_dma to indicate whether the current
transaction is using dma or not, and adjust dw_mci_stop_dma() to use
that instead.
Signed-off-by: James Hogan <[email protected]>
---
drivers/mmc/host/dw_mmc.c | 6 +++++-
include/linux/mmc/dw_mmc.h | 2 ++
2 files changed, 7 insertions(+), 1 deletions(-)
diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c
index 10b6979..fcff3c0 100644
--- a/drivers/mmc/host/dw_mmc.c
+++ b/drivers/mmc/host/dw_mmc.c
@@ -287,7 +287,7 @@ static void send_stop_cmd(struct dw_mci *host, struct mmc_data *data)
/* DMA interface functions */
static void dw_mci_stop_dma(struct dw_mci *host)
{
- if (host->use_dma) {
+ if (host->using_dma) {
host->dma_ops->stop(host);
host->dma_ops->cleanup(host);
} else {
@@ -435,6 +435,8 @@ static int dw_mci_submit_data_dma(struct dw_mci *host, struct mmc_data *data)
unsigned int i, direction, sg_len;
u32 temp;
+ host->using_dma = 0;
+
/* If we don't have a channel, we can't do DMA */
if (!host->use_dma)
return -ENODEV;
@@ -454,6 +456,8 @@ static int dw_mci_submit_data_dma(struct dw_mci *host, struct mmc_data *data)
return -EINVAL;
}
+ host->using_dma = 1;
+
if (data->flags & MMC_DATA_READ)
direction = DMA_FROM_DEVICE;
else
diff --git a/include/linux/mmc/dw_mmc.h b/include/linux/mmc/dw_mmc.h
index f3f68ee..6b46819 100644
--- a/include/linux/mmc/dw_mmc.h
+++ b/include/linux/mmc/dw_mmc.h
@@ -48,6 +48,7 @@ struct mmc_data;
* @data: The data currently being transferred, or NULL if no data
* transfer is in progress.
* @use_dma: Whether DMA channel is initialized or not.
+ * @using_dma: Whether DMA is in use for the current transfer.
* @sg_dma: Bus address of DMA buffer.
* @sg_cpu: Virtual address of DMA buffer.
* @dma_ops: Pointer to platform-specific DMA callbacks.
@@ -121,6 +122,7 @@ struct dw_mci {
/* DMA interface members*/
int use_dma;
+ int using_dma;
dma_addr_t sg_dma;
void *sg_cpu;
--
1.7.2.3
Remove error messages for timeout and CRC failure, since the error code
already indicates the problem.
Signed-off-by: James Hogan <[email protected]>
---
drivers/mmc/host/dw_mmc.c | 4 ----
1 files changed, 0 insertions(+), 4 deletions(-)
diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c
index fcff3c0..bf2157a 100644
--- a/drivers/mmc/host/dw_mmc.c
+++ b/drivers/mmc/host/dw_mmc.c
@@ -908,12 +908,8 @@ 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 {
dev_err(&host->pdev->dev,
--
1.7.2.3
When a data write isn't acknowledged by the card (so no CRC status token
is detected after the data), the error -EIO is returned instead of the
-ETIMEDOUT expected by mmc_test 15 - "Correct xfer_size at write (start
failure)" and 17 "Correct xfer_size at write (midway failure)". In PIO
mode the reported number of bytes transferred is also exaggerated since
the last block actually failed.
Handle the "Write no CRC" error specially, setting the error to
-ETIMEDOUT and setting the bytes_xferred to 0.
Signed-off-by: James Hogan <[email protected]>
---
drivers/mmc/host/dw_mmc.c | 19 +++++++++++++++----
1 files changed, 15 insertions(+), 4 deletions(-)
diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c
index bf2157a..0dac397 100644
--- a/drivers/mmc/host/dw_mmc.c
+++ b/drivers/mmc/host/dw_mmc.c
@@ -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);
@@ -911,6 +912,16 @@ static void dw_mci_tasklet_func(unsigned long priv)
data->error = -ETIMEDOUT;
} else if (status & SDMMC_INT_DCRC) {
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 "
--
1.7.2.3
If an error occurs mid way through a transaction (such as a missing CRC
status response after the 2nd block written out of 3), then the FIFO may
still contain data which will interfere with the next transaction.
Therefore after an error has been detected, reset the fifo using the
CTRL register.
Signed-off-by: James Hogan <[email protected]>
---
drivers/mmc/host/dw_mmc.c | 12 +++++++++++-
1 files changed, 11 insertions(+), 1 deletions(-)
diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c
index 0dac397..0c839d3 100644
--- a/drivers/mmc/host/dw_mmc.c
+++ b/drivers/mmc/host/dw_mmc.c
@@ -849,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);
@@ -929,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;
--
1.7.2.3
On Wed, Jun 29, 2011 at 9:27 AM, James Hogan <[email protected]> wrote:
> More improvements and fixes for the Synopsys DesignWare MCI driver so
> that it passes the mmc_test suite:
>
> [PATCH 1/4] mmc: dw_mmc: fix stop when fallen back to PIO
> ? ? ? ?Fixes a hang after an error/timeout in PIO mode.
> [PATCH 2/4] mmc: dw_mmc: remove unnecessary error messages
> ? ? ? ?Removes some dev_err's since an errno is sufficient.
> [PATCH 3/4] mmc: dw_mmc: handle "no CRC status" error
> ? ? ? ?Fixes "Correct xfer_size at write" tests.
> [PATCH 4/4] mmc: dw_mmc: reset FIFO after an error
> ? ? ? ?Fixes modified "Correct xfer_size at write" tests (3 blocks
> ? ? ? ?instead of 2).
>
> ?drivers/mmc/host/dw_mmc.c ?| ? 41 +++++++++++++++++++++++++++++++----------
> ?include/linux/mmc/dw_mmc.h | ? ?2 ++
> ?2 files changed, 33 insertions(+), 10 deletions(-)
These all look good to me.
Acked-by: Will Newton <[email protected]>
Tested-by: Jaehoon Chung <[email protected]>
Will Newton wrote:
> On Wed, Jun 29, 2011 at 9:27 AM, James Hogan <[email protected]> wrote:
>> More improvements and fixes for the Synopsys DesignWare MCI driver so
>> that it passes the mmc_test suite:
>>
>> [PATCH 1/4] mmc: dw_mmc: fix stop when fallen back to PIO
>> Fixes a hang after an error/timeout in PIO mode.
>> [PATCH 2/4] mmc: dw_mmc: remove unnecessary error messages
>> Removes some dev_err's since an errno is sufficient.
>> [PATCH 3/4] mmc: dw_mmc: handle "no CRC status" error
>> Fixes "Correct xfer_size at write" tests.
>> [PATCH 4/4] mmc: dw_mmc: reset FIFO after an error
>> Fixes modified "Correct xfer_size at write" tests (3 blocks
>> instead of 2).
>>
>> drivers/mmc/host/dw_mmc.c | 41 +++++++++++++++++++++++++++++++----------
>> include/linux/mmc/dw_mmc.h | 2 ++
>> 2 files changed, 33 insertions(+), 10 deletions(-)
>
> These all look good to me.
>
> Acked-by: Will Newton <[email protected]>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-mmc" in
> the body of a message to [email protected]
> More majordomo info at http://vger.kernel.org/majordomo-info.html
>
On 06/30/2011 06:26 AM, Jaehoon Chung wrote:
> Tested-by: Jaehoon Chung <[email protected]>
Thanks for testing
Cheers
James
>
> Will Newton wrote:
>> On Wed, Jun 29, 2011 at 9:27 AM, James Hogan <[email protected]> wrote:
>>> More improvements and fixes for the Synopsys DesignWare MCI driver so
>>> that it passes the mmc_test suite:
>>>
>>> [PATCH 1/4] mmc: dw_mmc: fix stop when fallen back to PIO
>>> Fixes a hang after an error/timeout in PIO mode.
>>> [PATCH 2/4] mmc: dw_mmc: remove unnecessary error messages
>>> Removes some dev_err's since an errno is sufficient.
>>> [PATCH 3/4] mmc: dw_mmc: handle "no CRC status" error
>>> Fixes "Correct xfer_size at write" tests.
>>> [PATCH 4/4] mmc: dw_mmc: reset FIFO after an error
>>> Fixes modified "Correct xfer_size at write" tests (3 blocks
>>> instead of 2).
>>>
>>> drivers/mmc/host/dw_mmc.c | 41 +++++++++++++++++++++++++++++++----------
>>> include/linux/mmc/dw_mmc.h | 2 ++
>>> 2 files changed, 33 insertions(+), 10 deletions(-)
>>
>> These all look good to me.
>>
>> Acked-by: Will Newton <[email protected]>
>> --
>> To unsubscribe from this list: send the line "unsubscribe linux-mmc" in
>> the body of a message to [email protected]
>> More majordomo info at http://vger.kernel.org/majordomo-info.html
>>
>