Skip site navigation (1)Skip section navigation (2)
Date:      Sat, 29 Dec 2012 22:26:01 +0000 (UTC)
From:      Jeff Roberson <jeff@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-projects@freebsd.org
Subject:   svn commit: r244839 - projects/physbio/sys/sparc64/sparc64
Message-ID:  <201212292226.qBTMQ1HV061933@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: jeff
Date: Sat Dec 29 22:26:01 2012
New Revision: 244839
URL: http://svnweb.freebsd.org/changeset/base/244839

Log:
   - Make an attempt at loading physical addresses on iommu enabled sparcs.
     This is mostly a copy and paste of the virtual load function but I
     don't fully understand this code.
  
  Sponsored by:	EMC / Isilon Storage Division

Modified:
  projects/physbio/sys/sparc64/sparc64/iommu.c

Modified: projects/physbio/sys/sparc64/sparc64/iommu.c
==============================================================================
--- projects/physbio/sys/sparc64/sparc64/iommu.c	Sat Dec 29 22:18:02 2012	(r244838)
+++ projects/physbio/sys/sparc64/sparc64/iommu.c	Sat Dec 29 22:26:01 2012	(r244839)
@@ -854,11 +854,112 @@ static int
 iommu_dvmamap_load_phys(bus_dma_tag_t dmat, bus_dmamap_t map, vm_paddr_t buf,
     bus_size_t buflen, int flags, bus_dma_segment_t *segs, int *segp)
 {
+	bus_addr_t amask, dvmaddr, dvmoffs;
+	bus_size_t sgsize, esize;
+	struct iommu_state *is;
+	vm_offset_t voffs;
+	vm_paddr_t curaddr;
+	int error, firstpg, sgcnt;
+	u_int slot;
+
+	is = dt->dt_cookie;
+	if (*segp == -1) {
+		if ((map->dm_flags & DMF_LOADED) != 0) {
+#ifdef DIAGNOSTIC
+			printf("%s: map still in use\n", __func__);
+#endif
+			bus_dmamap_unload(dt, map);
+		}
+
+		/*
+		 * Make sure that the map is not on a queue so that the
+		 * resource list may be safely accessed and modified without
+		 * needing the lock to cover the whole operation.
+		 */
+		IS_LOCK(is);
+		iommu_map_remq(is, map);
+		IS_UNLOCK(is);
+
+		amask = dt->dt_alignment - 1;
+	} else
+		amask = 0;
+	KASSERT(buflen != 0, ("%s: buflen == 0!", __func__));
+	if (buflen > dt->dt_maxsize)
+		return (EINVAL);
+
+	if (segs == NULL)
+		segs = dt->dt_segments;
+
+	voffs = buf & IO_PAGE_MASK;
+
+	/* Try to find a slab that is large enough. */
+	error = iommu_dvma_vallocseg(dt, is, map, voffs, buflen, amask,
+	    &dvmaddr);
+	if (error != 0)
+		return (error);
+
+	sgcnt = *segp;
+	firstpg = 1;
+	map->dm_flags &= ~DMF_STREAMED;
+	map->dm_flags |= iommu_use_streaming(is, map, buflen) != 0 ?
+	    DMF_STREAMED : 0;
+	for (; buflen > 0; ) {
+		curaddr = buf;
+
+		/*
+		 * Compute the segment size, and adjust counts.
+		 */
+		sgsize = IO_PAGE_SIZE - ((u_long)buf & IO_PAGE_MASK);
+		if (buflen < sgsize)
+			sgsize = buflen;
+
+		buflen -= sgsize;
+		buf += sgsize;
+
+		dvmoffs = trunc_io_page(dvmaddr);
+		iommu_enter(is, dvmoffs, trunc_io_page(curaddr),
+		    (map->dm_flags & DMF_STREAMED) != 0, flags);
+		if ((is->is_flags & IOMMU_FLUSH_CACHE) != 0) {
+			slot = IOTSBSLOT(dvmoffs);
+			if (buflen <= 0 || slot % 8 == 7)
+				IOMMU_WRITE8(is, is_iommu, IMR_CACHE_FLUSH,
+				    is->is_ptsb + slot * 8);
+		}
+
+		/*
+		 * Chop the chunk up into segments of at most maxsegsz, but try
+		 * to fill each segment as well as possible.
+		 */
+		if (!firstpg) {
+			esize = ulmin(sgsize,
+			    dt->dt_maxsegsz - segs[sgcnt].ds_len);
+			segs[sgcnt].ds_len += esize;
+			sgsize -= esize;
+			dvmaddr += esize;
+		}
+		while (sgsize > 0) {
+			sgcnt++;
+			if (sgcnt >= dt->dt_nsegments)
+				return (EFBIG);
+			/*
+			 * No extra alignment here - the common practice in
+			 * the busdma code seems to be that only the first
+			 * segment needs to satisfy the alignment constraints
+			 * (and that only for bus_dmamem_alloc()ed maps).
+			 * It is assumed that such tags have maxsegsize >=
+			 * maxsize.
+			 */
+			esize = ulmin(sgsize, dt->dt_maxsegsz);
+			segs[sgcnt].ds_addr = dvmaddr;
+			segs[sgcnt].ds_len = esize;
+			sgsize -= esize;
+			dvmaddr += esize;
+		}
 
-	/*
-	 * Did we fit?
-	 */
-	return (buflen != 0 ? EFBIG : 0);
+		firstpg = 0;
+	}
+	*segp = sgcnt;
+	return (0);
 }
 
 /*



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201212292226.qBTMQ1HV061933>