diff options
author | Teppei Kamijou <teppei.kamijou.yb@renesas.com> | 2012-12-12 09:38:12 -0500 |
---|---|---|
committer | Chris Ball <cjb@laptop.org> | 2013-02-11 13:28:21 -0500 |
commit | eae309836509496c981ceaebdef57041de86ecd4 (patch) | |
tree | 1c9422ea98f6f831d85665abd79226b4af257f29 /drivers/mmc/host | |
parent | 5df460b15e10ffcf2c9a05d0c55b309568d330ea (diff) |
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: Teppei Kamijou <teppei.kamijou.yb@renesas.com>
Signed-off-by: Shinya Kuribayashi <shinya.kuribayashi.px@renesas.com>
[g.liakhovetski@gmx.de: forward-port, add dma_unmap_sg() in error cases]
Signed-off-by: Guennadi Liakhovetski <g.liakhovetski@gmx.de>
Signed-off-by: Chris Ball <cjb@laptop.org>
Diffstat (limited to 'drivers/mmc/host')
-rw-r--r-- | drivers/mmc/host/sh_mmcif.c | 31 |
1 files changed, 17 insertions, 14 deletions
diff --git a/drivers/mmc/host/sh_mmcif.c b/drivers/mmc/host/sh_mmcif.c index f4b10c8f6384..8aa7b0e6dec2 100644 --- a/drivers/mmc/host/sh_mmcif.c +++ b/drivers/mmc/host/sh_mmcif.c | |||
@@ -263,15 +263,6 @@ static void mmcif_dma_complete(void *arg) | |||
263 | dev_name(&host->pd->dev))) | 263 | dev_name(&host->pd->dev))) |
264 | return; | 264 | return; |
265 | 265 | ||
266 | if (data->flags & MMC_DATA_READ) | ||
267 | dma_unmap_sg(host->chan_rx->device->dev, | ||
268 | data->sg, data->sg_len, | ||
269 | DMA_FROM_DEVICE); | ||
270 | else | ||
271 | dma_unmap_sg(host->chan_tx->device->dev, | ||
272 | data->sg, data->sg_len, | ||
273 | DMA_TO_DEVICE); | ||
274 | |||
275 | complete(&host->dma_complete); | 266 | complete(&host->dma_complete); |
276 | } | 267 | } |
277 | 268 | ||
@@ -1088,14 +1079,20 @@ static bool sh_mmcif_end_cmd(struct sh_mmcif_host *host) | |||
1088 | /* Running in the IRQ thread, can sleep */ | 1079 | /* Running in the IRQ thread, can sleep */ |
1089 | time = wait_for_completion_interruptible_timeout(&host->dma_complete, | 1080 | time = wait_for_completion_interruptible_timeout(&host->dma_complete, |
1090 | host->timeout); | 1081 | host->timeout); |
1082 | |||
1083 | if (data->flags & MMC_DATA_READ) | ||
1084 | dma_unmap_sg(host->chan_rx->device->dev, | ||
1085 | data->sg, data->sg_len, | ||
1086 | DMA_FROM_DEVICE); | ||
1087 | else | ||
1088 | dma_unmap_sg(host->chan_tx->device->dev, | ||
1089 | data->sg, data->sg_len, | ||
1090 | DMA_TO_DEVICE); | ||
1091 | |||
1091 | if (host->sd_error) { | 1092 | if (host->sd_error) { |
1092 | dev_err(host->mmc->parent, | 1093 | dev_err(host->mmc->parent, |
1093 | "Error IRQ while waiting for DMA completion!\n"); | 1094 | "Error IRQ while waiting for DMA completion!\n"); |
1094 | /* Woken up by an error IRQ: abort DMA */ | 1095 | /* Woken up by an error IRQ: abort DMA */ |
1095 | if (data->flags & MMC_DATA_READ) | ||
1096 | dmaengine_terminate_all(host->chan_rx); | ||
1097 | else | ||
1098 | dmaengine_terminate_all(host->chan_tx); | ||
1099 | data->error = sh_mmcif_error_manage(host); | 1096 | data->error = sh_mmcif_error_manage(host); |
1100 | } else if (!time) { | 1097 | } else if (!time) { |
1101 | data->error = -ETIMEDOUT; | 1098 | data->error = -ETIMEDOUT; |
@@ -1106,8 +1103,14 @@ static bool sh_mmcif_end_cmd(struct sh_mmcif_host *host) | |||
1106 | BUF_ACC_DMAREN | BUF_ACC_DMAWEN); | 1103 | BUF_ACC_DMAREN | BUF_ACC_DMAWEN); |
1107 | host->dma_active = false; | 1104 | host->dma_active = false; |
1108 | 1105 | ||
1109 | if (data->error) | 1106 | if (data->error) { |
1110 | data->bytes_xfered = 0; | 1107 | data->bytes_xfered = 0; |
1108 | /* Abort DMA */ | ||
1109 | if (data->flags & MMC_DATA_READ) | ||
1110 | dmaengine_terminate_all(host->chan_rx); | ||
1111 | else | ||
1112 | dmaengine_terminate_all(host->chan_tx); | ||
1113 | } | ||
1111 | 1114 | ||
1112 | return false; | 1115 | return false; |
1113 | } | 1116 | } |