[PATCH v2 4/6] spi: davinci: flush caches when performing DMA
Vignesh R
vigneshr at ti.com
Fri Feb 17 02:57:28 PST 2017
On Friday 17 February 2017 04:08 PM, Frode Isaksen wrote:
> 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 <fisaksen at baylibre.com>
> ---
> 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?
> 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
More information about the linux-arm-kernel
mailing list