Commit 03e8cb53 authored by James Hogan's avatar James Hogan Committed by Chris Ball

mmc: dw_mmc: fix stop when fallen back to PIO

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: default avatarJames Hogan <james.hogan@imgtec.com>
Acked-by: default avatarWill Newton <will.newton@imgtec.com>
Tested-by: default avatarJaehoon Chung <jh80.chung@samsung.com>
Signed-off-by: default avatarChris Ball <cjb@laptop.org>
parent 65d13516
...@@ -287,7 +287,7 @@ static void send_stop_cmd(struct dw_mci *host, struct mmc_data *data) ...@@ -287,7 +287,7 @@ static void send_stop_cmd(struct dw_mci *host, struct mmc_data *data)
/* DMA interface functions */ /* DMA interface functions */
static void dw_mci_stop_dma(struct dw_mci *host) 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->stop(host);
host->dma_ops->cleanup(host); host->dma_ops->cleanup(host);
} else { } else {
...@@ -435,6 +435,8 @@ static int dw_mci_submit_data_dma(struct dw_mci *host, struct mmc_data *data) ...@@ -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; unsigned int i, direction, sg_len;
u32 temp; u32 temp;
host->using_dma = 0;
/* If we don't have a channel, we can't do DMA */ /* If we don't have a channel, we can't do DMA */
if (!host->use_dma) if (!host->use_dma)
return -ENODEV; return -ENODEV;
...@@ -454,6 +456,8 @@ static int dw_mci_submit_data_dma(struct dw_mci *host, struct mmc_data *data) ...@@ -454,6 +456,8 @@ static int dw_mci_submit_data_dma(struct dw_mci *host, struct mmc_data *data)
return -EINVAL; return -EINVAL;
} }
host->using_dma = 1;
if (data->flags & MMC_DATA_READ) if (data->flags & MMC_DATA_READ)
direction = DMA_FROM_DEVICE; direction = DMA_FROM_DEVICE;
else else
......
...@@ -48,6 +48,7 @@ struct mmc_data; ...@@ -48,6 +48,7 @@ struct mmc_data;
* @data: The data currently being transferred, or NULL if no data * @data: The data currently being transferred, or NULL if no data
* transfer is in progress. * transfer is in progress.
* @use_dma: Whether DMA channel is initialized or not. * @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_dma: Bus address of DMA buffer.
* @sg_cpu: Virtual address of DMA buffer. * @sg_cpu: Virtual address of DMA buffer.
* @dma_ops: Pointer to platform-specific DMA callbacks. * @dma_ops: Pointer to platform-specific DMA callbacks.
...@@ -121,6 +122,7 @@ struct dw_mci { ...@@ -121,6 +122,7 @@ struct dw_mci {
/* DMA interface members*/ /* DMA interface members*/
int use_dma; int use_dma;
int using_dma;
dma_addr_t sg_dma; dma_addr_t sg_dma;
void *sg_cpu; void *sg_cpu;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment