pxa2xx_spi: bugfix full duplex dma data corruption

Previous message: [thread] [date] [author]
Next message: [thread] [date] [author]
From: Linux Kernel Mailing List
Date: Wednesday, November 19, 2008 - 8:59 pm

Gitweb:     http://git.kernel.org/git/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commit;h=393df7...
Commit:     393df744e056ba24e9531d0657d09fc3c7c0dd22
Parent:     f652c521e0bec2e70cf123f47e80117a7e6ed139
Author:     Ned Forrester <nforrester@whoi.edu>
AuthorDate: Wed Nov 19 15:36:21 2008 -0800
Committer:  Linus Torvalds <torvalds@linux-foundation.org>
CommitDate: Wed Nov 19 18:49:58 2008 -0800

    pxa2xx_spi: bugfix full duplex dma data corruption
    
    Fixes a data corruption bug in pxa2xx_spi.c when operating in full duplex
    mode with DMA and using buffers that overlap.
    
    SPI transmit and receive buffers are allowed to be the same or to overlap.
     However, this driver fails if such overlap is attempted in DMA mode
    because it maps the rx and tx buffers in the wrong order.  By mapping
    DMA_FROM_DEVICE (read) before DMA_TO_DEVICE (write), it invalidates the
    cache before flushing it, thus discarding data which should have been
    transmitted.
    
    The patch corrects the order of mapping.  This bug exists in all versions
    of pxa2xx_spi.c; similar bugs are in the drivers for two other SPI
    controllers (au1500, imx).
    
    A version of this patch has been tested on kernel 2.6.20 using
    verification of loopback data with: random transfer length, random
    bits-per-word, random positive offsets (both larger and smaller than
    transfer length) between the start of the rx and tx buffers, and varying
    clock rates.
    
    Signed-off-by: Ned Forrester <nforrester@whoi.edu>
    Cc: Vernon Sauder <vernoninhand@gmail.com>
    Cc: J. Scott Merritt <merrij3@rpi.edu>
    Signed-off-by: David Brownell <dbrownell@users.sourceforge.net>
    Cc: <stable@kernel.org>		[2.6.27.x]
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
---
 drivers/spi/pxa2xx_spi.c |   24 ++++++++++++------------
 1 files changed, 12 insertions(+), 12 deletions(-)

diff --git a/drivers/spi/pxa2xx_spi.c b/drivers/spi/pxa2xx_spi.c
index dae87b1..cf12f2d 100644
--- a/drivers/spi/pxa2xx_spi.c
+++ b/drivers/spi/pxa2xx_spi.c
@@ -352,21 +352,21 @@ static int map_dma_buffers(struct driver_data *drv_data)
 	} else
 		drv_data->tx_map_len = drv_data->len;
 
-	/* Stream map the rx buffer */
-	drv_data->rx_dma = dma_map_single(dev, drv_data->rx,
-						drv_data->rx_map_len,
-						DMA_FROM_DEVICE);
-	if (dma_mapping_error(dev, drv_data->rx_dma))
-		return 0;
-
-	/* Stream map the tx buffer */
+	/* Stream map the tx buffer. Always do DMA_TO_DEVICE first
+	 * so we flush the cache *before* invalidating it, in case
+	 * the tx and rx buffers overlap.
+	 */
 	drv_data->tx_dma = dma_map_single(dev, drv_data->tx,
-						drv_data->tx_map_len,
-						DMA_TO_DEVICE);
+					drv_data->tx_map_len, DMA_TO_DEVICE);
+	if (dma_mapping_error(dev, drv_data->tx_dma))
+		return 0;
 
-	if (dma_mapping_error(dev, drv_data->tx_dma)) {
-		dma_unmap_single(dev, drv_data->rx_dma,
+	/* Stream map the rx buffer */
+	drv_data->rx_dma = dma_map_single(dev, drv_data->rx,
 					drv_data->rx_map_len, DMA_FROM_DEVICE);
+	if (dma_mapping_error(dev, drv_data->rx_dma)) {
+		dma_unmap_single(dev, drv_data->tx_dma,
+					drv_data->tx_map_len, DMA_TO_DEVICE);
 		return 0;
 	}
 
--
To unsubscribe from this list: send the line "unsubscribe git-commits-head" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Previous message: [thread] [date] [author]
Next message: [thread] [date] [author]

Messages in current thread:
pxa2xx_spi: bugfix full duplex dma data corruption, Linux Kernel Mailing ..., (Wed Nov 19, 8:59 pm)