[#4335] DMA / data cache issues

Document created by Aaronwu Employee on Aug 29, 2013
Version 1Show Document
  • View in full screen mode

[#4335] DMA / data cache issues

Submitted By: Yi Li

Open Date

2008-08-11 05:09:21     Close Date

2009-01-08 10:00:09

Priority:

Medium     Assignee:

Nobody

Status:

Closed     Fixed In Release:

N/A

Found In Release:

N/A     Release:

svn branch, trunk

Category:

N/A     Board:

N/A

Processor:

N/A     Silicon Revision:

Is this bug repeatable?:

Yes     Resolution:

Rejected

Uboot version or rev.:

    Toolchain version or rev.:

App binary format:

N/A     

Summary: DMA / data cache issues

Details:

 

See forum thread:

  blackfin.uclinux.org/gf/project/uclinux-dist/forum/?action=ForumBrowse&forum_id=39&_forum_action=ForumMessageBrowse&thread_id=29097

 

Michael McTernan reported:

"In the case of a DMA read from the peripheral to a non-aligned buffer with dcache enabled and some other thread making access", access data adjacent to the buffer may corrupt the buffer.

 

Robin:

"Then if the data A and buf are in the same cache line, the FLUSHINV will write things out, and mark the line as invalid. If the data A is used before the DMA transfer is complete - the cache line will be read before the DMA is done, and a bogus buf will be living in the cache..."

 

Follow-ups

 

--- Michael McTernan                                         2008-08-11 06:30:06

I'd suggest the sport driver page

(  docs.blackfin.uclinux.org/doku.php?id=sport_driver&s[]=sport) be

ammended with something like:

 

"Caveats

 

If using DMA transfers to read from the SPORT in a system with dcache enabled,

it is prudent to ensure that buffers passed to the SPORT driver by read() are

aligned to a dcache line of 32 bytes and similarly end or are padded upto a

cache line.  This ensures that no other data shares a cache line with the start

or end of the DMA buffer there by avoiding the risk that access to nearby data

during a DMA transfer could cause a cache line to be fetched before the DMA is

complete; in such a case the read data may not be seen by the application.

 

For simple structures or buffers, the gcc aligned attribute can acomplish

this:

 

    struct S { short f[64]; } __attribute__ ((aligned (32)));"

 

I also suggest that the bfin_sport driver be changed to either:

 

- return an error in the case this problem could occur (e.g. if dcache enabled

& a non-aligned write, return -EIO or -EINVAL

- use a non-DMA transfer for bytes upto a cache line, then DMA anything

aligned, finally using non-DMA if needed for any tail bytes

 

The first option is quick to implement, but may break things (although it may

also flush out some very hard bugs), while the second is more friendly but adds

a hidden performance penalty.

 

--- Mike Frysinger                                           2008-08-11 16:07:25

it isnt a bug in dma or the cache functions.  this is something that cannot be

addressed in any core code.  end users need to be aware of the issue as there

are plenty of cases where using these functions will not result in any problems

(any single-threaded application).  for this same reason, i think WARN_ON or

returning errors of any sort would not be OK.

 

we'll tweak the documentation when possible (sport/dma/cache pages), but that's

about all we can do.

 

--- Robin Getz                                               2008-08-11 20:30:20

Yeah, I think I agree with Mike.

 

This really has nothing to do with the specific dma infrastructure, or cache

functions or SPORT - it is littered all over the place.

 

For example - in linux-2.6.x/arch/blackfin/kernel/bfin_dma_5xx.c in

dma_outsb/dma_outsw/dma_outsl() we do a :

    local_irq_save()

    blackfin_dcache_flush_range()

    dma_transfer()

    local_irq_restore()

 

which should be OK - we turn off interrupts and make sure things are atomic.

 

in dma_insb/dma_insw/dma_insl() we do:

    blackfin_dcache_invalidate_range()

    local_irq_save()

    dma_transfer()

    local_irq_restore()

 

Which could cause a problem, since we could get interrupted during the

blackfin_dcache_invalidate_range(), and a line could get pulled back into the

cache...

 

I think some WARN_ON when CONFIG_DEBUG_KERNEL is set might be reasonable - but

may not actually help track down things - since you would need more info.

 

We might want something like:

 

#ifdef CONFIG_DEBUG_KERNEL

    if (buf & 0x1F)) {  /* start of buffer doesn't start at 32 byte aligned

*/

        show_stack(NULL, NULL);

        printk(KERN_ERR "potential issue - start of pointer not aligned to

cache line -  %s:%d/%s()!\n", __FILE__, __LINE__, __FUNCTION__);

    }

    if (buf+len & 0x1F != 1F) { /* end of buffer doesn't end at 32 byte

aligned */

        show_stack(NULL, NULL);

        printk(KERN_ERR "end of buffer not aligned to cache line -

%s:%d/%s()!\n", __FILE__, __LINE__, __FUNCTION__);

    }

#endif

 

But - as Mike indicated - it might throw out lots of false positives...

 

-Robin

 

 

 

    Files

    Changes

    Commits

    Dependencies

    Duplicates

    Associations

    Tags

 

File Name     File Type     File Size     Posted By

No Files Were Found

Attachments

    Outcomes