Commit eae30983 authored by Teppei Kamijou's avatar Teppei Kamijou Committed by Chris Ball

mmc: sh_mmcif: Terminate DMA transactions when detecting timeout or error

If a DMA transaction fails, terminate all outstanding DMA transfers and
unmap buffers.
Signed-off-by: default avatarTeppei Kamijou <teppei.kamijou.yb@renesas.com>
Signed-off-by: default avatarShinya Kuribayashi <shinya.kuribayashi.px@renesas.com>
[g.liakhovetski@gmx.de: forward-port, add dma_unmap_sg() in error cases]
Signed-off-by: default avatarGuennadi Liakhovetski <g.liakhovetski@gmx.de>
Signed-off-by: default avatarChris Ball <cjb@laptop.org>
parent 5df460b1
...@@ -263,15 +263,6 @@ static void mmcif_dma_complete(void *arg) ...@@ -263,15 +263,6 @@ static void mmcif_dma_complete(void *arg)
dev_name(&host->pd->dev))) dev_name(&host->pd->dev)))
return; return;
if (data->flags & MMC_DATA_READ)
dma_unmap_sg(host->chan_rx->device->dev,
data->sg, data->sg_len,
DMA_FROM_DEVICE);
else
dma_unmap_sg(host->chan_tx->device->dev,
data->sg, data->sg_len,
DMA_TO_DEVICE);
complete(&host->dma_complete); complete(&host->dma_complete);
} }
...@@ -1088,14 +1079,20 @@ static bool sh_mmcif_end_cmd(struct sh_mmcif_host *host) ...@@ -1088,14 +1079,20 @@ static bool sh_mmcif_end_cmd(struct sh_mmcif_host *host)
/* Running in the IRQ thread, can sleep */ /* Running in the IRQ thread, can sleep */
time = wait_for_completion_interruptible_timeout(&host->dma_complete, time = wait_for_completion_interruptible_timeout(&host->dma_complete,
host->timeout); host->timeout);
if (data->flags & MMC_DATA_READ)
dma_unmap_sg(host->chan_rx->device->dev,
data->sg, data->sg_len,
DMA_FROM_DEVICE);
else
dma_unmap_sg(host->chan_tx->device->dev,
data->sg, data->sg_len,
DMA_TO_DEVICE);
if (host->sd_error) { if (host->sd_error) {
dev_err(host->mmc->parent, dev_err(host->mmc->parent,
"Error IRQ while waiting for DMA completion!\n"); "Error IRQ while waiting for DMA completion!\n");
/* Woken up by an error IRQ: abort DMA */ /* Woken up by an error IRQ: abort DMA */
if (data->flags & MMC_DATA_READ)
dmaengine_terminate_all(host->chan_rx);
else
dmaengine_terminate_all(host->chan_tx);
data->error = sh_mmcif_error_manage(host); data->error = sh_mmcif_error_manage(host);
} else if (!time) { } else if (!time) {
data->error = -ETIMEDOUT; data->error = -ETIMEDOUT;
...@@ -1106,8 +1103,14 @@ static bool sh_mmcif_end_cmd(struct sh_mmcif_host *host) ...@@ -1106,8 +1103,14 @@ static bool sh_mmcif_end_cmd(struct sh_mmcif_host *host)
BUF_ACC_DMAREN | BUF_ACC_DMAWEN); BUF_ACC_DMAREN | BUF_ACC_DMAWEN);
host->dma_active = false; host->dma_active = false;
if (data->error) if (data->error) {
data->bytes_xfered = 0; data->bytes_xfered = 0;
/* Abort DMA */
if (data->flags & MMC_DATA_READ)
dmaengine_terminate_all(host->chan_rx);
else
dmaengine_terminate_all(host->chan_tx);
}
return false; return false;
} }
......
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