From eae309836509496c981ceaebdef57041de86ecd4 Mon Sep 17 00:00:00 2001 From: Teppei Kamijou Date: Wed, 12 Dec 2012 15:38:12 +0100 Subject: 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 Signed-off-by: Shinya Kuribayashi [g.liakhovetski@gmx.de: forward-port, add dma_unmap_sg() in error cases] Signed-off-by: Guennadi Liakhovetski Signed-off-by: Chris Ball --- drivers/mmc/host/sh_mmcif.c | 31 +++++++++++++++++-------------- 1 file changed, 17 insertions(+), 14 deletions(-) (limited to 'drivers/mmc') diff --git a/drivers/mmc/host/sh_mmcif.c b/drivers/mmc/host/sh_mmcif.c index f4b10c8f638..8aa7b0e6dec 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) dev_name(&host->pd->dev))) 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); } @@ -1088,14 +1079,20 @@ static bool sh_mmcif_end_cmd(struct sh_mmcif_host *host) /* Running in the IRQ thread, can sleep */ time = wait_for_completion_interruptible_timeout(&host->dma_complete, 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) { dev_err(host->mmc->parent, "Error IRQ while waiting for DMA completion!\n"); /* 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); } else if (!time) { data->error = -ETIMEDOUT; @@ -1106,8 +1103,14 @@ static bool sh_mmcif_end_cmd(struct sh_mmcif_host *host) BUF_ACC_DMAREN | BUF_ACC_DMAWEN); host->dma_active = false; - if (data->error) + if (data->error) { 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; } -- cgit v1.2.3-70-g09d2