Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

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

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
Loading
Loading
Loading
Loading
+17 −14
Original line number Original line Diff line number Diff line
@@ -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)
	/* 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)
			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;
}
}