Re: Applied "spi: omap2-mcspi: Undo broken fix for dma transfer of vmalloced buffer" to the spi tree

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



2016-04-12 11:01 GMT+09:00 Mark Brown <broonie@xxxxxxxxxx>:
> The patch
>
>    spi: omap2-mcspi: Undo broken fix for dma transfer of vmalloced buffer
>
> has been applied to the spi tree at
>
>    git://git.kernel.org/pub/scm/linux/kernel/git/broonie/spi.git

I realized that this undo patch has not been merged to Linus' tree yet.
I have a fix for this issue (attached patch).  But the change is not
small and also v4.6 release is soon.  So I think this undo patch
should go into 4.6 release.
From 5abc589ab08e239e884fb2e8937d74f81fb0b888 Mon Sep 17 00:00:00 2001
From: Akinobu Mita <akinobu.mita@xxxxxxxxx>
Date: Mon, 21 Mar 2016 01:16:06 +0900
Subject: [PATCH] spi: omap2-mcspi: fix dma transfer

This fixes the problem introduced by the commit 3525e0aac91c ("spi:
omap2-mcspi: fix dma transfer for vmalloced buffer")

The actual DMA transfer length by dmaengine can be smaller than SPI
transfer length in the specific condition.  In that case, the last
word needs to be filled after DMA transfer completion.

This fixes it by detecting that case and remap the scatterlist with
correct DMA transfer length.

Signed-off-by: Akinobu Mita <akinobu.mita@xxxxxxxxx>
Cc: Mark Brown <broonie@xxxxxxxxxx>
---
 drivers/spi/spi-omap2-mcspi.c | 47 +++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 47 insertions(+)

diff --git a/drivers/spi/spi-omap2-mcspi.c b/drivers/spi/spi-omap2-mcspi.c
index 43a02e3..a7fafd0 100644
--- a/drivers/spi/spi-omap2-mcspi.c
+++ b/drivers/spi/spi-omap2-mcspi.c
@@ -439,7 +439,41 @@ static void omap2_mcspi_tx_dma(struct spi_device *spi,
 	}
 	dma_async_issue_pending(mcspi_dma->dma_tx);
 	omap2_mcspi_set_dma_req(spi, 0, 1);
+}
+
+static int
+omap2_mcspi_rx_dma_remap(struct spi_device *spi, struct spi_transfer *xfer,
+			 unsigned int dma_count)
+{
+	int i;
+	struct scatterlist *sg;
+	struct omap2_mcspi *mcspi;
+	unsigned int nents = 0;
+	unsigned int count = 0;
+	int ret;
+
+	mcspi = spi_master_get_devdata(spi->master);
+
+	dma_unmap_sg(mcspi->dev, xfer->rx_sg.sgl, xfer->rx_sg.nents,
+		     DMA_FROM_DEVICE);
+
+	for_each_sg(xfer->rx_sg.sgl, sg, xfer->rx_sg.nents, i) {
+		nents++;
+		if (count + sg->length < dma_count) {
+			count += sg->length;
+			continue;
+		}
+		sg->length = dma_count - count;
+		break;
+	}
 
+	ret = dma_map_sg(mcspi->dev, xfer->rx_sg.sgl, nents, DMA_FROM_DEVICE);
+	if (!ret)
+		return -ENOMEM;
+
+	xfer->rx_sg.nents = ret;
+
+	return 0;
 }
 
 static unsigned
@@ -480,6 +514,16 @@ omap2_mcspi_rx_dma(struct spi_device *spi, struct spi_transfer *xfer,
 		if ((l & OMAP2_MCSPI_CHCONF_TURBO) && mcspi->fifo_depth == 0)
 			dma_count -= es;
 
+		if (xfer->len != dma_count) {
+			int ret;
+
+			ret = omap2_mcspi_rx_dma_remap(spi, xfer, dma_count);
+			if (ret) {
+				dev_err(&spi->dev, "failed to map rx buf\n");
+				return 0;
+			}
+		}
+
 		tx = dmaengine_prep_slave_sg(mcspi_dma->dma_rx, xfer->rx_sg.sgl,
 					     xfer->rx_sg.nents, DMA_DEV_TO_MEM,
 					     DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
@@ -496,6 +540,9 @@ omap2_mcspi_rx_dma(struct spi_device *spi, struct spi_transfer *xfer,
 	omap2_mcspi_set_dma_req(spi, 1, 1);
 
 	wait_for_completion(&mcspi_dma->dma_rx_completion);
+	dma_unmap_sg(mcspi->dev, xfer->rx_sg.sgl, xfer->rx_sg.nents,
+		     DMA_FROM_DEVICE);
+	sg_free_table(&xfer->rx_sg);
 
 	if (mcspi->fifo_depth > 0)
 		return count;
-- 
2.7.4


[Index of Archives]     [Linux Kernel]     [Linux ARM (vger)]     [Linux ARM MSM]     [Linux Omap]     [Linux Arm]     [Linux Tegra]     [Fedora ARM]     [Linux for Samsung SOC]     [eCos]     [Linux Fastboot]     [Gcc Help]     [Git]     [DCCP]     [IETF Announce]     [Security]     [Linux MIPS]     [Yosemite Campsites]

  Powered by Linux