[PATCH v2 4/6] spi: davinci: flush caches when performing DMA
From: Frode Isaksen <hidden>
Date: 2017-02-17 11:36:17
Also in:
linux-spi
On 17/02/2017 12:22, Russell King - ARM Linux wrote:
On Fri, Feb 17, 2017 at 04:27:28PM +0530, Vignesh R wrote:quoted
On Friday 17 February 2017 04:08 PM, Frode Isaksen wrote:quoted
@@ -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?The DMA API deals with the _kernel_ lowmem mapping. It has no knowledge of any other aliases in the system. When you have a VIVT cache (as all old ARM CPUs have) then if you access the memory through a different alias from the kernel lowmem mapping (iow, vmalloc) then the DMA API can't help you. However, the correct place to use flush_kernel_vmap_range() etc is not in drivers - it's supposed to be done in the callers that know that the memory is aliased.
OK, so this should be done in the ubifs layer instead ? xfs already does this, but no other fs. Thanks, Frode
For full details on these flushing functions, see cachetlb.txt. This
does not remove the requirement to also use the DMA API.
=== cachetlb.txt ===
The final category of APIs is for I/O to deliberately aliased address
ranges inside the kernel. Such aliases are set up by use of the
vmap/vmalloc API. Since kernel I/O goes via physical pages, the I/O
subsystem assumes that the user mapping and kernel offset mapping are
the only aliases. This isn't true for vmap aliases, so anything in
the kernel trying to do I/O to vmap areas must manually manage
coherency. It must do this by flushing the vmap range before doing
I/O and invalidating it after the I/O returns.
void flush_kernel_vmap_range(void *vaddr, int size)
flushes the kernel cache for a given virtual address range in
the vmap area. This is to make sure that any data the kernel
modified in the vmap range is made visible to the physical
page. The design is to make this area safe to perform I/O on.
Note that this API does *not* also flush the offset map alias
of the area.
void invalidate_kernel_vmap_range(void *vaddr, int size) invalidates
the cache for a given virtual address range in the vmap area
which prevents the processor from making the cache stale by
speculatively reading data while the I/O was occurring to the
physical pages. This is only necessary for data reads into the
vmap area.