Author: mmel
Date: Wed Nov 18 16:07:01 2015
New Revision: 291018
URL: https://svnweb.freebsd.org/changeset/base/291018

Log:
  ARM: Fix dma_dcache_sync() for early allocated memory.
  Drivers can request DMA to buffers that are not in memory represented
  in the vm page arrays. Because of this, store KVA of already mapped
  buffer to synclist and use it in dma_dcache_sync().
  
  Reviewed by:  jah
  Approved by:  kib (mentor)
  Differential Revision: https://reviews.freebsd.org/D4120

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        Wed Nov 18 15:12:24 2015        
(r291017)
+++ head/sys/arm/arm/busdma_machdep-v6.c        Wed Nov 18 16:07:01 2015        
(r291018)
@@ -117,8 +117,8 @@ struct bounce_page {
 
 struct sync_list {
        vm_offset_t     vaddr;          /* kva of client data */
+       bus_addr_t      paddr;          /* physical address */
        vm_page_t       pages;          /* starting page of client data */
-       vm_offset_t     dataoffs;       /* page offset of client data */
        bus_size_t      datacount;      /* client data count */
 };
 
@@ -1076,17 +1076,19 @@ _bus_dmamap_load_phys(bus_dma_tag_t dmat
                            sgsize);
                } else {
                        if (map->sync_count > 0)
-                               sl_end = VM_PAGE_TO_PHYS(sl->pages) +
-                                   sl->dataoffs + sl->datacount;
+                               sl_end = sl->paddr + sl->datacount;
 
                        if (map->sync_count == 0 || curaddr != sl_end) {
                                if (++map->sync_count > dmat->nsegments)
                                        break;
                                sl++;
                                sl->vaddr = 0;
+                               sl->paddr = curaddr;
                                sl->datacount = sgsize;
                                sl->pages = PHYS_TO_VM_PAGE(curaddr);
-                               sl->dataoffs = curaddr & PAGE_MASK;
+                               KASSERT(sl->pages != NULL,
+                                   ("%s: page at PA:0x%08lx is not in "
+                                   "vm_page_array", __func__, curaddr));
                        } else
                                sl->datacount += sgsize;
                }
@@ -1188,8 +1190,7 @@ _bus_dmamap_load_buffer(bus_dma_tag_t dm
                            sgsize);
                } else {
                        if (map->sync_count > 0) {
-                               sl_pend = VM_PAGE_TO_PHYS(sl->pages) +
-                                   sl->dataoffs + sl->datacount;
+                               sl_pend = sl->paddr + sl->datacount;
                                sl_vend = sl->vaddr + sl->datacount;
                        }
 
@@ -1201,9 +1202,17 @@ _bus_dmamap_load_buffer(bus_dma_tag_t dm
                                        goto cleanup;
                                sl++;
                                sl->vaddr = kvaddr;
+                               sl->paddr = curaddr;
+                               if (kvaddr != 0) {
+                                       sl->pages = NULL;
+                               } else {
+                                       sl->pages = PHYS_TO_VM_PAGE(curaddr);
+                                       KASSERT(sl->pages != NULL,
+                                           ("%s: page at PA:0x%08lx is not "
+                                           "in vm_page_array", __func__,
+                                           curaddr));
+                               }
                                sl->datacount = sgsize;
-                               sl->pages = PHYS_TO_VM_PAGE(curaddr);
-                               sl->dataoffs = curaddr & PAGE_MASK;
                        } else
                                sl->datacount += sgsize;
                }
@@ -1299,10 +1308,10 @@ dma_dcache_sync(struct sync_list *sl, bu
        vm_offset_t va, tempva;
        bus_size_t size;
 
-       offset = sl->dataoffs;
+       offset = sl->paddr & PAGE_MASK;
        m = sl->pages;
        size = sl->datacount;
-       pa = VM_PAGE_TO_PHYS(m) | offset;
+       pa = sl->paddr;
 
        for ( ; size != 0; size -= len, pa += len, offset = 0, ++m) {
                tempva = 0;
@@ -1310,13 +1319,13 @@ dma_dcache_sync(struct sync_list *sl, bu
                        len = min(PAGE_SIZE - offset, size);
                        tempva = pmap_quick_enter_page(m);
                        va = tempva | offset;
+                       KASSERT(pa == (VM_PAGE_TO_PHYS(m) | offset),
+                           ("unexpected vm_page_t phys: 0x%08x != 0x%08x",
+                           VM_PAGE_TO_PHYS(m) | offset, pa));
                } else {
                        len = sl->datacount;
                        va = sl->vaddr;
                }
-               KASSERT(pa == (VM_PAGE_TO_PHYS(m) | offset),
-                   ("unexpected vm_page_t phys: 0x%08x != 0x%08x",
-                   VM_PAGE_TO_PHYS(m) | offset, pa));
 
                switch (op) {
                case BUS_DMASYNC_PREWRITE:
_______________________________________________
svn-src-head@freebsd.org mailing list
https://lists.freebsd.org/mailman/listinfo/svn-src-head
To unsubscribe, send any mail to "svn-src-head-unsubscr...@freebsd.org"

Reply via email to