Author: marius
Date: Sat May 26 09:13:38 2012
New Revision: 236086
URL: http://svn.freebsd.org/changeset/base/236086

Log:
  MFC: r234561
  
  Interrupts must be disabled while handling a partial cache line flush,
  as otherwise the interrupt handling code may modify data in the non-DMA
  part of the cache line while we have it stashed away in the temporary
  stack buffer, then we end up restoring a stale value.
  
  PR:           160431
  Submitted by: Ian Lepore

Modified:
  stable/8/sys/arm/arm/busdma_machdep.c
Directory Properties:
  stable/8/sys/   (props changed)
  stable/8/sys/amd64/include/xen/   (props changed)
  stable/8/sys/boot/   (props changed)
  stable/8/sys/cddl/contrib/opensolaris/   (props changed)
  stable/8/sys/contrib/dev/acpica/   (props changed)
  stable/8/sys/contrib/pf/   (props changed)
  stable/8/sys/dev/e1000/   (props changed)

Modified: stable/8/sys/arm/arm/busdma_machdep.c
==============================================================================
--- stable/8/sys/arm/arm/busdma_machdep.c       Sat May 26 09:13:24 2012        
(r236085)
+++ stable/8/sys/arm/arm/busdma_machdep.c       Sat May 26 09:13:38 2012        
(r236086)
@@ -1091,14 +1091,16 @@ static void
 bus_dmamap_sync_buf(void *buf, int len, bus_dmasync_op_t op)
 {
        char _tmp_cl[arm_dcache_align], _tmp_clend[arm_dcache_align];
+       register_t s;
+       int partial; 
 
        if ((op & BUS_DMASYNC_PREWRITE) && !(op & BUS_DMASYNC_PREREAD)) {
                cpu_dcache_wb_range((vm_offset_t)buf, len);
                cpu_l2cache_wb_range((vm_offset_t)buf, len);
        }
+       partial = (((vm_offset_t)buf) | len) & arm_dcache_align_mask;
        if (op & BUS_DMASYNC_PREREAD) {
-               if (!(op & BUS_DMASYNC_PREWRITE) &&
-                   ((((vm_offset_t)(buf) | len) & arm_dcache_align_mask) == 
0)) {
+               if (!(op & BUS_DMASYNC_PREWRITE) && !partial) {
                        cpu_dcache_inv_range((vm_offset_t)buf, len);
                        cpu_l2cache_inv_range((vm_offset_t)buf, len);
                } else {
@@ -1107,27 +1109,32 @@ bus_dmamap_sync_buf(void *buf, int len, 
                }
        }
        if (op & BUS_DMASYNC_POSTREAD) {
-               if ((vm_offset_t)buf & arm_dcache_align_mask) {
-                       memcpy(_tmp_cl, (void *)((vm_offset_t)buf & ~
-                           arm_dcache_align_mask),
-                           (vm_offset_t)buf & arm_dcache_align_mask);
-               }
-               if (((vm_offset_t)buf + len) & arm_dcache_align_mask) {
-                       memcpy(_tmp_clend, (void *)((vm_offset_t)buf + len),
-                           arm_dcache_align - (((vm_offset_t)(buf) + len) &
-                          arm_dcache_align_mask));
+               if (partial) {
+                       s = intr_disable();
+                       if ((vm_offset_t)buf & arm_dcache_align_mask)
+                               memcpy(_tmp_cl, (void *)((vm_offset_t)buf &
+                                   ~arm_dcache_align_mask),
+                                   (vm_offset_t)buf & arm_dcache_align_mask);
+                       if (((vm_offset_t)buf + len) & arm_dcache_align_mask)
+                               memcpy(_tmp_clend, 
+                                   (void *)((vm_offset_t)buf + len),
+                                   arm_dcache_align - (((vm_offset_t)(buf) +
+                                   len) & arm_dcache_align_mask));
                }
                cpu_dcache_inv_range((vm_offset_t)buf, len);
                cpu_l2cache_inv_range((vm_offset_t)buf, len);
-
-               if ((vm_offset_t)buf & arm_dcache_align_mask)
-                       memcpy((void *)((vm_offset_t)buf &
-                           ~arm_dcache_align_mask), _tmp_cl, 
-                           (vm_offset_t)buf & arm_dcache_align_mask);
-               if (((vm_offset_t)buf + len) & arm_dcache_align_mask)
-                       memcpy((void *)((vm_offset_t)buf + len), _tmp_clend,
-                           arm_dcache_align - (((vm_offset_t)(buf) + len) &
-                          arm_dcache_align_mask));
+               if (partial) {
+                       if ((vm_offset_t)buf & arm_dcache_align_mask)
+                               memcpy((void *)((vm_offset_t)buf &
+                                   ~arm_dcache_align_mask), _tmp_cl, 
+                                   (vm_offset_t)buf & arm_dcache_align_mask);
+                       if (((vm_offset_t)buf + len) & arm_dcache_align_mask)
+                               memcpy((void *)((vm_offset_t)buf + len), 
+                                   _tmp_clend, arm_dcache_align - 
+                                   (((vm_offset_t)(buf) + len) &
+                                   arm_dcache_align_mask));
+                       intr_restore(s);
+               }
        }
 }
 
_______________________________________________
svn-src-all@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "svn-src-all-unsubscr...@freebsd.org"

Reply via email to