Author: gonzo
Date: Mon Dec 31 21:00:38 2012
New Revision: 244912
URL: http://svnweb.freebsd.org/changeset/base/244912

Log:
  Merge r234561 from busdma_machdep.c to ARMv6 version of busdma:
  
  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:
  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        Mon Dec 31 16:52:52 2012        
(r244911)
+++ head/sys/arm/arm/busdma_machdep-v6.c        Mon Dec 31 21:00:38 2012        
(r244912)
@@ -1347,35 +1347,49 @@ _bus_dmamap_sync(bus_dma_tag_t dmat, bus
                        while (sl != NULL) {
                                        /* write back the unaligned portions */
                                vm_paddr_t physaddr;
+                               register_t s = 0;
+
                                buf = sl->vaddr;
                                len = sl->datacount;
                                physaddr = sl->busaddr;
                                bbuf = buf & ~arm_dcache_align_mask;
                                ebuf = buf + len;
                                physaddr = physaddr & ~arm_dcache_align_mask;
-                               unalign = buf & arm_dcache_align_mask;
-                               if (unalign) {
-                                       memcpy(_tmp_cl, (void *)bbuf, unalign);
-                                       len += unalign; /* inv entire cache 
line */
-                               }
-                               unalign = ebuf & arm_dcache_align_mask;
-                               if (unalign) {
-                                       unalign = arm_dcache_align - unalign;
-                                       memcpy(_tmp_clend, (void *)ebuf, 
unalign);
-                                       len += unalign; /* inv entire cache 
line */
+
+
+                               if ((buf & arm_dcache_align_mask) ||
+                                   (ebuf & arm_dcache_align_mask)) {
+                                       s = intr_disable();
+                                       unalign = buf & arm_dcache_align_mask;
+                                       if (unalign) {
+                                               memcpy(_tmp_cl, (void *)bbuf, 
unalign);
+                                               len += unalign; /* inv entire 
cache line */
+                                       }
+
+                                       unalign = ebuf & arm_dcache_align_mask;
+                                       if (unalign) {
+                                               unalign = arm_dcache_align - 
unalign;
+                                               memcpy(_tmp_clend, (void 
*)ebuf, unalign);
+                                               len += unalign; /* inv entire 
cache line */
+                                       }
                                }
-                                       /* inv are cache length aligned */
+
+                               /* inv are cache length aligned */
                                cpu_dcache_inv_range(bbuf, len);
                                l2cache_inv_range(bbuf, physaddr, len);
 
-                               unalign = (vm_offset_t)buf & 
arm_dcache_align_mask;
-                               if (unalign) {
-                                       memcpy((void *)bbuf, _tmp_cl, unalign);
-                               }
-                               unalign = ebuf & arm_dcache_align_mask;
-                               if (unalign) {
-                                       unalign = arm_dcache_align - unalign;
-                                       memcpy((void *)ebuf, _tmp_clend, 
unalign);
+                               if ((buf & arm_dcache_align_mask) ||
+                                   (ebuf & arm_dcache_align_mask)) {
+                                       unalign = (vm_offset_t)buf & 
arm_dcache_align_mask;
+                                       if (unalign)
+                                               memcpy((void *)bbuf, _tmp_cl, 
unalign);
+
+                                       unalign = ebuf & arm_dcache_align_mask;
+                                       if (unalign)
+                                               memcpy((void *)ebuf, _tmp_clend,
+                                                   arm_dcache_align - unalign);
+
+                                       intr_restore(s);
                                }
                                sl = STAILQ_NEXT(sl, slinks);
                        }
_______________________________________________
svn-src-head@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-head
To unsubscribe, send any mail to "svn-src-head-unsubscr...@freebsd.org"

Reply via email to