[MTD/NAND] Blackfin NFC driver DMA bug ?

Ivan Djelic ivan.djelic at parrot.com
Fri Feb 22 03:45:33 EST 2008


On Fri, Feb 22, 2008 at 10:52:49AM +0800, Bryan Wu wrote:
> >         /*
> >          * Before starting a dma transfer, be sure to invalidate/flush
> >          * the cache over the address range of your DMA buffer to
> >          * prevent cache coherency problems. Otherwise very subtle bugs
> >          * can be introduced to your driver.
> >          */
> >         if (is_read)
> >                 invalidate_dcache_range((unsigned int)buf,
> >                                 (unsigned int)(buf + page_size));
> >         else
> >                 flush_dcache_range((unsigned int)buf,
> >                                 (unsigned int)(buf + page_size));
> >
> >  Since 'buf' is allocated outside MTD, are we allowed to assume it is
> >  cache-aligned ? Because if it's not, invalidating dcache on read is not enough
> >  to prevent cache coherency problems. For instance, a cache line partially
> >  spanning across the buffer address range could be flushed just after DMA has
> >  completed, corrupting DMA data in the process...
> 
> Oh, I am not fully understand your concern.  The code is invalidating
> or flushing buf before DMA operation.
> And invalidate and flush operation is OK for buf which is not
> cache-aligned on Blackfin arch. it also should be
> OK for other arch.

Well, consider the following scenario, in which 'buf' is not cache-aligned:

1) function bf5xx_nand_dma_rw() is called for reading data.

2) dcache is partially invalidated on a range containing 'buf': this range is
cache-aligned, of course.

3) at this point, imagine some variable residing nearby 'buf' (in the same
cache line interval) is read and modified, resulting in a cache line being
fetched and modified (hence becoming dirty).

4) DMA transfer happens, modifying data in memory.

5) now, the dirty cache line from 3) can be flushed to memory anytime...
corrupting DMA data, because its contents were read *before* the DMA transfer !

Or consider this other scenario:

1) and 2) same as above.

3) some variable residing nearby 'buf' (in the same cache line interval) is
read (not modified), resulting in a cache line being fetched. Cache line is not
dirty.

4) DMA transfer happens.

5) now, if you read data from 'buf', you will get wrong (stale) data because the
cache line contents were read *before* the DMA transfer.


To avoid those kind of problems you would need a reliable way to prevent the
cache from messing with your buffer during the whole DMA transfer.

Ivan



More information about the linux-mtd mailing list