Thread (25 messages) flat view 25 messages, 5 authors, 2017-03-15
STALE3476d

Revision v2 of 4 in this series.

Revisions (4)
  1. v2 [diff vs current]
  2. v2 current
  3. v2 [diff vs current]
  4. v2 [diff vs current]

[PATCH v2 4/6] spi: davinci: flush caches when performing DMA

From: vigneshr@ti.com (Vignesh R)
Date: 2017-02-17 10:57:28
Also in: linux-spi


On Friday 17 February 2017 04:08 PM, Frode Isaksen wrote:
quoted hunk ↗ jump to hunk
This CPU has VIVT caches, so need to flush the cache
for vmalloc'ed buffers, since the address may be aliased
(same phyiscal address used by multiple virtual addresses).
This fixes errors when mounting and reading/writing UBIFS
volumes with SPI NOR flash.

Signed-off-by: Frode Isaksen <redacted>
---
 drivers/spi/spi-davinci.c | 15 +++++++++++++--
 1 file changed, 13 insertions(+), 2 deletions(-)
diff --git a/drivers/spi/spi-davinci.c b/drivers/spi/spi-davinci.c
index 2632ae0..b69a370 100644
--- a/drivers/spi/spi-davinci.c
+++ b/drivers/spi/spi-davinci.c
@@ -29,6 +29,7 @@
 #include <linux/spi/spi.h>
 #include <linux/spi/spi_bitbang.h>
 #include <linux/slab.h>
+#include <asm/cacheflush.h>
 
 #include <linux/platform_data/spi-davinci.h>
 
@@ -650,6 +651,10 @@ static int davinci_spi_bufs(struct spi_device *spi, struct spi_transfer *t)
 		dmaengine_slave_config(dspi->dma_rx, &dma_rx_conf);
 		dmaengine_slave_config(dspi->dma_tx, &dma_tx_conf);
 
+		if (is_vmalloc_addr(t->rx_buf))
+			/* VIVT cache: flush since addr. may be aliased */
+			flush_kernel_vmap_range((void *)t->rx_buf, t->len);
+
 		rxdesc = dmaengine_prep_slave_sg(dspi->dma_rx,
 				t->rx_sg.sgl, t->rx_sg.nents, DMA_DEV_TO_MEM,
 				DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
@@ -660,7 +665,9 @@ static int davinci_spi_bufs(struct spi_device *spi, struct spi_transfer *t)
 			/* use rx buffer as dummy tx buffer */
 			t->tx_sg.sgl = t->rx_sg.sgl;
 			t->tx_sg.nents = t->rx_sg.nents;
-		}
+		} else if (is_vmalloc_addr(t->tx_buf))
+			/* VIVT cache: flush since addr. may be aliased */
+			flush_kernel_vmap_range((void *)t->tx_buf, t->len);
 
SPI core calls dma_unmap_sg(), that is supposed to flush caches.
If flush_kernel_vmap_range() call is required here to flush actual cache
lines, then what does dma_unmap_* calls in SPI core end up flushing?
Will it flush a different alias of same physical address? If so, isn't
that undesired?
quoted hunk ↗ jump to hunk
 		txdesc = dmaengine_prep_slave_sg(dspi->dma_tx,
 				t->tx_sg.sgl, t->tx_sg.nents, DMA_MEM_TO_DEV,
@@ -699,8 +706,12 @@ static int davinci_spi_bufs(struct spi_device *spi, struct spi_transfer *t)
 	}
 
 	clear_io_bits(dspi->base + SPIINT, SPIINT_MASKALL);
-	if (spicfg->io_type == SPI_IO_TYPE_DMA)
+	if (spicfg->io_type == SPI_IO_TYPE_DMA) {
 		clear_io_bits(dspi->base + SPIINT, SPIINT_DMA_REQ_EN);
+		if (is_vmalloc_addr(t->rx_buf))
+			/* VIVT cache: invalidate since addr. may be aliased */
+			invalidate_kernel_vmap_range((void *)t->rx_buf, t->len);
+	}
 
 	clear_io_bits(dspi->base + SPIGCR1, SPIGCR1_SPIENA_MASK);
 	set_io_bits(dspi->base + SPIGCR1, SPIGCR1_POWERDOWN_MASK);
-- 
Regards
Vignesh
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help