aboutsummaryrefslogtreecommitdiffstats
path: root/arch/powerpc/lib
diff options
context:
space:
mode:
authorAndrew Lewis <andrew-lewis@netspace.net.au>2008-06-26 05:29:05 -0400
committerPaul Mackerras <paulus@samba.org>2008-06-30 21:28:54 -0400
commit03d70617b8a789c3721afaafde06fcbba7c7ebf1 (patch)
tree36d43d9ec14d21cb74813b4aeb0d784e3f0b7303 /arch/powerpc/lib
parent9d4ae9fc92f347b93b42c9c0ccde7138c1202e36 (diff)
powerpc: Prevent memory corruption due to cache invalidation of unaligned DMA buffer
On PowerPC processors with non-coherent cache architectures the DMA subsystem calls invalidate_dcache_range() before performing a DMA read operation. If the address and length of the DMA buffer are not aligned to a cache-line boundary this can result in memory outside of the DMA buffer being invalidated in the cache. If this memory has an uncommitted store then the data will be lost and a subsequent read of that address will result in an old value being returned from main memory. Only when the DMA buffer starts on a cache-line boundary and is an exact mutiple of the cache-line size can invalidate_dcache_range() be called, otherwise flush_dcache_range() must be called. flush_dcache_range() will first flush uncommitted writes, and then invalidate the cache. Signed-off-by: Andrew Lewis <andrew-lewis at netspace.net.au> Signed-off-by: Paul Mackerras <paulus@samba.org>
Diffstat (limited to 'arch/powerpc/lib')
-rw-r--r--arch/powerpc/lib/dma-noncoherent.c11
1 files changed, 9 insertions, 2 deletions
diff --git a/arch/powerpc/lib/dma-noncoherent.c b/arch/powerpc/lib/dma-noncoherent.c
index 6656d47841d0..5d83907f6591 100644
--- a/arch/powerpc/lib/dma-noncoherent.c
+++ b/arch/powerpc/lib/dma-noncoherent.c
@@ -348,8 +348,15 @@ void __dma_sync(void *vaddr, size_t size, int direction)
348 switch (direction) { 348 switch (direction) {
349 case DMA_NONE: 349 case DMA_NONE:
350 BUG(); 350 BUG();
351 case DMA_FROM_DEVICE: /* invalidate only */ 351 case DMA_FROM_DEVICE:
352 invalidate_dcache_range(start, end); 352 /*
353 * invalidate only when cache-line aligned otherwise there is
354 * the potential for discarding uncommitted data from the cache
355 */
356 if ((start & (L1_CACHE_BYTES - 1)) || (size & (L1_CACHE_BYTES - 1)))
357 flush_dcache_range(start, end);
358 else
359 invalidate_dcache_range(start, end);
353 break; 360 break;
354 case DMA_TO_DEVICE: /* writeback only */ 361 case DMA_TO_DEVICE: /* writeback only */
355 clean_dcache_range(start, end); 362 clean_dcache_range(start, end);