[#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