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

Frode Isaksen fisaksen at baylibre.com
Fri Feb 17 03:36:17 PST 2017



On 17/02/2017 12:22, Russell King - ARM Linux wrote:
> On Fri, Feb 17, 2017 at 04:27:28PM +0530, Vignesh R wrote:
>> On Friday 17 February 2017 04:08 PM, Frode Isaksen wrote:
>>> @@ -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.
>
>




More information about the linux-arm-kernel mailing list