For the problem when using swiotlb

Russell King - ARM Linux
2014-11-25T11:29:05Z

On Tue, Nov 25, 2014 at 10:58:15AM +0000, Catalin Marinas wrote:
> Since we don't have a coherent_dma_supported() function, we defer the
> validity check of coherent_dma_mask to dma_alloc_coherent() (and here we
> can remove bouncing since swiotlb has relatively small buffers).

Bouncing of coherent DMA buffers is insane; if you have to bounce them,
they're by definition not coherent.

Think about one of the common uses of coherent DMA buffers: ring buffers,
where both the CPU and the DMA agent write to the ring:

- CPU writes to ring, loading address and length, then writing to the
status word for the ring entry.
- DMA reads the ring status word, sees it owns the entry, processes it,
DMA writes to the ring status word to give it back.

What this means is that if you are bouncing the buffer, you are copying
it whole-sale between the CPU visible version and the DMA visible
version, which means that you can miss DMA updates to it. So, bouncing
a coherent DMA buffer is simply not an acceptable implementation for
dma_alloc_coherent().

As for validity of masks, it is defined in the DMA API documentation that
if a DMA mask is suitable for the streaming APIs, then it is also suitable
for the coherent APIs. The reverse is left open, and so may not
necessarily be true.

In other words:

err = dma_set_mask(dev, mask);
if (err == 0)
assert(dma_set_coherent_mask(dev, mask) == 0);

must always succeed, but reversing the two calls has no guarantee.

Note that there seems to be only one driver which has different coherent
and streaming DMA masks today:

drivers/media/pci/sta2x11/sta2x11_vip.c:
if (dma_set_mask(&pdev->dev, DMA_BIT_MASK(26))) {
err = dma_set_coherent_mask(&vip->pdev->dev, DMA_BIT_MASK(29));

--
FTTC broadband for 0.8mile line: currently at 9.5Mbps down 400kbps up
according to speedtest.net.