Author: ian
Date: Sun Nov 16 21:22:42 2014
New Revision: 274604
URL: https://svnweb.freebsd.org/changeset/base/274604

Log:
  Correct the sequence of busdma sync ops involved with PRE/POSTREAD syncs.
  
  We used to invalidate the cache for PREREAD alone, or writeback+invalidate
  for PREREAD with PREWRITE, then treat POSTREAD as a no-op.  Prefetching on
  modern systems can lead to parts of a DMA buffer getting pulled into the
  caches while DMA is in progress (due to access of "nearby" data), so it's
  mandatory to invalidate during the POSTREAD sync even if a PREREAD
  invalidate also happened.
  
  In the PREREAD case the invalidate is done to ensure that there are no
  dirty cache lines that might get automatically evicted during the DMA,
  corrupting the buffer.  In a PREREAD+PREWRITE case the writeback which is
  required for PREWRITE handling is suffficient to avoid corruption caused
  by eviction and no invalidate need be done until POSTREAD time.
  
  Submitted by: Michal Meloun <[email protected]>

Modified:
  head/sys/arm/arm/busdma_machdep-v6.c

Modified: head/sys/arm/arm/busdma_machdep-v6.c
==============================================================================
--- head/sys/arm/arm/busdma_machdep-v6.c        Sun Nov 16 20:59:27 2014        
(r274603)
+++ head/sys/arm/arm/busdma_machdep-v6.c        Sun Nov 16 21:22:42 2014        
(r274604)
@@ -1416,6 +1416,7 @@ _bus_dmamap_sync(bus_dma_tag_t dmat, bus
 
                switch (op) {
                case BUS_DMASYNC_PREWRITE:
+               case BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD:
                        while (sl != end) {
                                cpu_dcache_wb_range(sl->vaddr, sl->datacount);
                                l2cache_wb_range(sl->vaddr, sl->busaddr,
@@ -1433,19 +1434,19 @@ _bus_dmamap_sync(bus_dma_tag_t dmat, bus
                        }
                        break;
 
-               case BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD:
-                       while (sl != end) {
-                               cpu_dcache_wbinv_range(sl->vaddr, 
sl->datacount);
-                               l2cache_wbinv_range(sl->vaddr,
-                                   sl->busaddr, sl->datacount);
-                               sl++;
-                       }
+               case BUS_DMASYNC_POSTWRITE:
                        break;
 
                case BUS_DMASYNC_POSTREAD:
-               case BUS_DMASYNC_POSTWRITE:
                case BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE:
+                       while (sl != end) {
+                               l2cache_inv_range(sl->vaddr, sl->busaddr, 
+                                   sl->datacount);
+                               cpu_dcache_inv_range(sl->vaddr, sl->datacount);
+                               sl++;
+                       }
                        break;
+
                default:
                        panic("unsupported combination of sync operations: 
0x%08x\n", op);
                        break;
_______________________________________________
[email protected] mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-head
To unsubscribe, send any mail to "[email protected]"

Reply via email to