svn commit: r367268 - head/sys/arm64/arm64

Michal Meloun mmel at FreeBSD.org
Mon Nov 2 08:26:20 UTC 2020


Author: mmel
Date: Mon Nov  2 08:26:19 2020
New Revision: 367268
URL: https://svnweb.freebsd.org/changeset/base/367268

Log:
  Improve loading of multipage aligned buffers.
  
  The multipage alignment requirements is incompatible with many aspects
  of actual busdma code. Multi-page alignment requests are incompatible
  with many aspects of current busdma code. Mainly with partially bounced
  buffer segments and per-page loop in bus_dmamap_load_buffer(). Because
  proper implementation would be a major restructuring of the code, add
  the fix only for already known uses and do KASSERT for all other cases.
  
  For this reason, bus_dmamap_load_buffer () should take the memory allocated
  by bus_dmam_alloc () as one segment bypassing per page segmentation. We can
  do this because it is guaranteed that the memory is physically continuous.
  
  Reviewed by:	bz
  Tested by: 	imp, mv, daniel.engberg.lists_pyret.net, kjopek_gmail.com
  Differential Revision: https://reviews.freebsd.org/D26735

Modified:
  head/sys/arm64/arm64/busdma_bounce.c

Modified: head/sys/arm64/arm64/busdma_bounce.c
==============================================================================
--- head/sys/arm64/arm64/busdma_bounce.c	Mon Nov  2 06:16:11 2020	(r367267)
+++ head/sys/arm64/arm64/busdma_bounce.c	Mon Nov  2 08:26:19 2020	(r367268)
@@ -501,13 +501,6 @@ static int
 bounce_bus_dmamem_alloc(bus_dma_tag_t dmat, void** vaddr, int flags,
     bus_dmamap_t *mapp)
 {
-	/*
-	 * XXX ARM64TODO:
-	 * This bus_dma implementation requires IO-Coherent architecutre.
-	 * If IO-Coherency is not guaranteed, the BUS_DMA_COHERENT flag has
-	 * to be implented using non-cacheable memory.
-	 */
-
 	vm_memattr_t attr;
 	int mflags;
 
@@ -830,7 +823,19 @@ bounce_bus_dmamap_load_phys(bus_dma_tag_t dmat, bus_dm
 		sgsize = MIN(buflen, dmat->common.maxsegsz);
 		if (map->pagesneeded != 0 &&
 		    must_bounce(dmat, map, curaddr, sgsize)) {
-			sgsize = MIN(sgsize, PAGE_SIZE - (curaddr & PAGE_MASK));
+			/*
+			 * The attempt to split a physically continuous buffer
+			 * seems very controversial, it's unclear whether we
+			 * can do this in all cases. Also, memory for bounced
+			 * buffers is allocated as pages, so we cannot
+			 * guarantee multipage alignment.
+			 */
+			KASSERT(dmat->common.alignment <= PAGE_SIZE,
+			    ("bounced buffer cannot have alignment bigger "
+			    "than PAGE_SIZE: %lu", dmat->common.alignment));
+			sgsize = PAGE_SIZE - (curaddr & PAGE_MASK);
+			sgsize = roundup2(sgsize, dmat->common.alignment);
+			sgsize = MIN(sgsize, dmat->common.maxsegsz);
 			curaddr = add_bounce_page(dmat, map, 0, curaddr,
 			    sgsize);
 		} else if ((map->flags & DMAMAP_COHERENT) == 0) {
@@ -843,11 +848,11 @@ bounce_bus_dmamap_load_phys(bus_dma_tag_t dmat, bus_dm
 				sl++;
 				sl->vaddr = 0;
 				sl->paddr = curaddr;
-				sl->datacount = sgsize;
 				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;
 			} else
 				sl->datacount += sgsize;
 		}
@@ -880,6 +885,11 @@ bounce_bus_dmamap_load_buffer(bus_dma_tag_t dmat, bus_
 	vm_offset_t kvaddr, vaddr, sl_vend;
 	int error;
 
+	KASSERT((map->flags & DMAMAP_FROM_DMAMEM) != 0 ||
+	    dmat->common.alignment <= PAGE_SIZE,
+	    ("loading user buffer with alignment bigger than PAGE_SIZE is not "
+	    "supported"));
+
 	if (segs == NULL)
 		segs = dmat->segments;
 
@@ -895,6 +905,11 @@ bounce_bus_dmamap_load_buffer(bus_dma_tag_t dmat, bus_
 		}
 	}
 
+	/*
+	 * XXX Optimally we should parse input buffer for physically
+	 * continuous segments first and then pass these segment into
+	 * load loop.
+	 */
 	sl = map->slist + map->sync_count - 1;
 	vaddr = (vm_offset_t)buf;
 	sl_pend = 0;
@@ -916,15 +931,25 @@ bounce_bus_dmamap_load_buffer(bus_dma_tag_t dmat, bus_
 		 * Compute the segment size, and adjust counts.
 		 */
 		max_sgsize = MIN(buflen, dmat->common.maxsegsz);
-		sgsize = PAGE_SIZE - (curaddr & PAGE_MASK);
+		if ((map->flags & DMAMAP_FROM_DMAMEM) != 0) {
+			sgsize = max_sgsize;
+		} else {
+			sgsize = PAGE_SIZE - (curaddr & PAGE_MASK);
+			sgsize = MIN(sgsize, max_sgsize);
+		}
+
 		if (map->pagesneeded != 0 &&
 		    must_bounce(dmat, map, curaddr, sgsize)) {
+			/* See comment in bounce_bus_dmamap_load_phys */
+			KASSERT(dmat->common.alignment <= PAGE_SIZE,
+			    ("bounced buffer cannot have alignment bigger "
+			    "than PAGE_SIZE: %lu", dmat->common.alignment));
+			sgsize = PAGE_SIZE - (curaddr & PAGE_MASK);
 			sgsize = roundup2(sgsize, dmat->common.alignment);
 			sgsize = MIN(sgsize, max_sgsize);
 			curaddr = add_bounce_page(dmat, map, kvaddr, curaddr,
 			    sgsize);
 		} else if ((map->flags & DMAMAP_COHERENT) == 0) {
-			sgsize = MIN(sgsize, max_sgsize);
 			if (map->sync_count > 0) {
 				sl_pend = sl->paddr + sl->datacount;
 				sl_vend = sl->vaddr + sl->datacount;
@@ -934,7 +959,7 @@ bounce_bus_dmamap_load_buffer(bus_dma_tag_t dmat, bus_
 			    (kvaddr != 0 && kvaddr != sl_vend) ||
 			    (curaddr != sl_pend)) {
 				if (++map->sync_count > dmat->common.nsegments)
-					goto cleanup;
+					break;
 				sl++;
 				sl->vaddr = kvaddr;
 				sl->paddr = curaddr;
@@ -950,8 +975,6 @@ bounce_bus_dmamap_load_buffer(bus_dma_tag_t dmat, bus_
 				sl->datacount = sgsize;
 			} else
 				sl->datacount += sgsize;
-		} else {
-			sgsize = MIN(sgsize, max_sgsize);
 		}
 		sgsize = _bus_dmamap_addseg(dmat, map, curaddr, sgsize, segs,
 		    segp);
@@ -961,7 +984,6 @@ bounce_bus_dmamap_load_buffer(bus_dma_tag_t dmat, bus_
 		buflen -= sgsize;
 	}
 
-cleanup:
 	/*
 	 * Did we fit?
 	 */


More information about the svn-src-all mailing list