diff mbox

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

Message ID CAC5umyg2fJxYKOB4J96+3igkNx+eJs5MET8S8NnafZ3hcPPEag@mail.gmail.com (mailing list archive)
State Not Applicable
Headers show

Commit Message

Akinobu Mita May 11, 2016, 3:39 p.m. UTC
2016-04-12 11:01 GMT+09:00 Mark Brown <broonie@kernel.org>:
> 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.

Comments

Mark Brown May 11, 2016, 4:20 p.m. UTC | #1
On Thu, May 12, 2016 at 12:39:35AM +0900, Akinobu Mita wrote:

> 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.

I actually just sent that a few minutes ago anyway.

> 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.

This feels like it should be in the framework, I imagine other devices
will have similar limiations.  Especially if the limitation comes from
the DMA engine I'd hope we can arrange to query it somehow...  can you
provide a bit more detail on what the restriction is please?
Akinobu Mita May 12, 2016, 1:49 p.m. UTC | #2
2016-05-12 1:20 GMT+09:00 Mark Brown <broonie@kernel.org>:
> On Thu, May 12, 2016 at 12:39:35AM +0900, Akinobu Mita wrote:
>
>> 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.
>
> I actually just sent that a few minutes ago anyway.
>
>> 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.
>
> This feels like it should be in the framework, I imagine other devices
> will have similar limiations.  Especially if the limitation comes from
> the DMA engine I'd hope we can arrange to query it somehow...  can you
> provide a bit more detail on what the restriction is please?

According to the source code (I couldn't find out the reason from TRM
yet), the last word (or two words if TURBO mode is used) of RX data
needs to be transferred by PIO transfer instead of DMA transfer.

But if FIFO buffer support[*] is used, the whole RX data can be
transferred by DMA transfer.  The use of FIFO buffer is determined by
omap2_mcspi_set_fifo() with the total transfer length, bits per words,
TX/RX only or both, and etc.

[*] commit d33f473dcd8e ("spi: omap2-mcspi: Add FIFO buffer support")

If we have an optional callback to get the actual DMA transfer length
instead of using spi_transfer->len for each spi_transfer in the
framework, we can use it to determine the correct map size used by
spi_map_buf() in spi.c.
--
To unsubscribe from this list: send the line "unsubscribe linux-spi" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Mark Brown May 12, 2016, 3:44 p.m. UTC | #3
On Thu, May 12, 2016 at 10:49:15PM +0900, Akinobu Mita wrote:

> If we have an optional callback to get the actual DMA transfer length
> instead of using spi_transfer->len for each spi_transfer in the
> framework, we can use it to determine the correct map size used by
> spi_map_buf() in spi.c.

That sounds plausible, we can also do some querying of the dmaengine at
the same place we call that when we get around to that.  Can you try to
come up with an implementation?
Akinobu Mita May 12, 2016, 4:47 p.m. UTC | #4
2016-05-13 0:44 GMT+09:00 Mark Brown <broonie@kernel.org>:
> On Thu, May 12, 2016 at 10:49:15PM +0900, Akinobu Mita wrote:
>
>> If we have an optional callback to get the actual DMA transfer length
>> instead of using spi_transfer->len for each spi_transfer in the
>> framework, we can use it to determine the correct map size used by
>> spi_map_buf() in spi.c.
>
> That sounds plausible, we can also do some querying of the dmaengine at
> the same place we call that when we get around to that.  Can you try to
> come up with an implementation?

OK, I'll try and see how it looks like.
--
To unsubscribe from this list: send the line "unsubscribe linux-spi" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
diff mbox

Patch

From 5abc589ab08e239e884fb2e8937d74f81fb0b888 Mon Sep 17 00:00:00 2001
From: Akinobu Mita <akinobu.mita@gmail.com>
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@gmail.com>
Cc: Mark Brown <broonie@kernel.org>
---
 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