Skip site navigation (1)Skip section navigation (2)
Date:      Mon, 28 Jan 2013 00:15:45 +0000 (UTC)
From:      Marcel Moolenaar <marcel@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-projects@freebsd.org
Subject:   svn commit: r246017 - in projects/altix2/sys: ia64/sgisn kern
Message-ID:  <201301280015.r0S0Fjq1043634@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: marcel
Date: Mon Jan 28 00:15:44 2013
New Revision: 246017
URL: http://svnweb.freebsd.org/changeset/base/246017

Log:
  o   Call BUSDMA_IOMMU_UNMAP for each segment, just like BUSDMA_IOMMU_MAP.
  o   Implememt BUSDMA_UOMMU_UNMAP in sgisn_pcib.
  o   Keep a bitmap of IOMMU entry (ATEs) for allocation purposes.

Modified:
  projects/altix2/sys/ia64/sgisn/sgisn_pcib.c
  projects/altix2/sys/kern/busdma_if.m
  projects/altix2/sys/kern/subr_busdma.c

Modified: projects/altix2/sys/ia64/sgisn/sgisn_pcib.c
==============================================================================
--- projects/altix2/sys/ia64/sgisn/sgisn_pcib.c	Sun Jan 27 23:33:42 2013	(r246016)
+++ projects/altix2/sys/ia64/sgisn/sgisn_pcib.c	Mon Jan 28 00:15:44 2013	(r246017)
@@ -30,8 +30,10 @@ __FBSDID("$FreeBSD$");
 #include <sys/param.h>
 #include <sys/systm.h>
 #include <sys/kernel.h>
+#include <sys/lock.h>
 #include <sys/module.h>
 #include <sys/malloc.h>
+#include <sys/mutex.h>
 #include <sys/bus.h>
 #include <sys/busdma.h>
 #include <sys/pcpu.h>
@@ -75,6 +77,8 @@ struct sgisn_pcib_softc {
 	struct rman	sc_iomem;
 	uint32_t	*sc_flush_intr[PCI_SLOTMAX + 1];
 	uint64_t	*sc_flush_addr[PCI_SLOTMAX + 1];
+	uint64_t	sc_ate[PIC_REG_ATE_SIZE / 64];
+	struct mtx	sc_ate_mtx;
 };
 
 static int sgisn_pcib_attach(device_t);
@@ -109,6 +113,7 @@ static void sgisn_pcib_cfgwrite(device_t
 static int sgisn_pcib_iommu_xlate(device_t, device_t, busdma_mtag_t);
 static int sgisn_pcib_iommu_map(device_t, device_t, busdma_md_t, u_int,
     bus_addr_t *);
+static int sgisn_pcib_iommu_unmap(device_t, device_t, busdma_md_t, u_int);
 static int sgisn_pcib_iommu_sync(device_t, device_t, busdma_md_t, u_int,
     bus_addr_t, bus_size_t);
 
@@ -144,6 +149,7 @@ static device_method_t sgisn_pcib_method
 	/* busdma interface */
 	DEVMETHOD(busdma_iommu_xlate,	sgisn_pcib_iommu_xlate),
 	DEVMETHOD(busdma_iommu_map,	sgisn_pcib_iommu_map),
+	DEVMETHOD(busdma_iommu_unmap,	sgisn_pcib_iommu_unmap),
 	DEVMETHOD(busdma_iommu_sync,	sgisn_pcib_iommu_sync),
 
 	{ 0, 0 }
@@ -475,6 +481,8 @@ sgisn_pcib_attach(device_t dev)
 #endif
 	bus_space_write_8(sc->sc_tag, sc->sc_hndl, PIC_REG_WGT_CTRL, ctrl);
 
+	mtx_init(&sc->sc_ate_mtx, device_get_nameunit(dev), NULL, MTX_SPIN);
+
 	fwflushsz = (PCI_SLOTMAX + 1) * sizeof(struct sgisn_fwflush);
 	fwflush = contigmalloc(fwflushsz, M_TEMP, M_ZERO, 0UL, ~0UL, 16, 0);
 	BUS_READ_IVAR(parent, dev, SHUB_IVAR_NASID, &ivar);
@@ -574,8 +582,9 @@ sgisn_pcib_iommu_map(device_t bus, devic
 	struct sgisn_pcib_softc *sc = device_get_softc(bus);
 	busdma_tag_t tag;
 	bus_addr_t maxaddr = 0x80000000UL;
-	bus_addr_t ba;
-	u_int flags;
+	bus_addr_t ba, size;
+	uint64_t bits;
+	u_int ate, bitshft, count, entry, flags;
 
 	ba = *ba_p;
 
@@ -595,39 +604,133 @@ sgisn_pcib_iommu_map(device_t bus, devic
 
 	/*
 	 * 32-bit mapped DMA.
-	 *
-	 * XXX HACK START XXX
 	 */
-	{
-		bus_addr_t size;
-		size_t count;
-		u_int entry;
-
-		size = busdma_md_get_size(md, idx);
-		count = ((ba & SGISN_PCIB_PAGE_MASK) + size +
-		    SGISN_PCIB_PAGE_MASK) >> SGISN_PCIB_PAGE_SHIFT;
-
-		entry = 0;
-
-		*ba_p = (1UL << 30) | (ba & SGISN_PCIB_PAGE_MASK) |
-		    (SGISN_PCIB_PAGE_SIZE * entry);
-
-		ba &= ~SGISN_PCIB_PAGE_MASK;
-		ba |= 1 << 0; /* valid */
-		ba |= 1 << ((flags & BUSDMA_ALLOC_CONSISTENT) ? 4 : 3);
-		ba |= (u_long)sc->sc_fwbus->fw_hub_xid << 8;
-
-		while (count > 0) {
-			bus_space_write_8(sc->sc_tag, sc->sc_hndl,
-			    PIC_REG_ATE(entry), ba);
-			ba += SGISN_PCIB_PAGE_SIZE;
-			entry++;
-			count--;
+	size = busdma_md_get_size(md, idx);
+	count = ((ba & SGISN_PCIB_PAGE_MASK) + size +
+	    SGISN_PCIB_PAGE_MASK) >> SGISN_PCIB_PAGE_SHIFT;
+
+	/* Our bitmap allocation routine doesn't handle straddling longs. */
+	if (count > 64) {
+		device_printf(sc->sc_dev, "IOMMU: more than 64 entries needed "
+		    "for DMA\n");
+		return (E2BIG);
+	}
+
+	mtx_lock_spin(&sc->sc_ate_mtx);
+
+	ate = 0;
+	entry = ~0;
+	while (ate < (PIC_REG_ATE_SIZE / 64) && entry == ~0) {
+		bits = sc->sc_ate[ate];
+		/* Move to the next long if this one is full. */
+		if (bits == ~0UL) {
+			ate++;
+			continue;
 		}
+		/* If this long is empty, take it (catches count == 64). */
+		if (bits == 0UL) {
+			bitshft = 0;
+			entry = ate * 64;
+			break;
+		}
+		/* Avoid undefined behaviour below for 1 << count. */
+		if (count == 64) {
+			ate++;
+			continue;
+		}
+		bitshft = 0;
+		do {
+			if ((bits & ((1UL << count) - 1UL)) == 0) {
+				entry = ate * 64 + bitshft;
+				break;
+			}
+			while ((bits & 1UL) == 0) {
+				bits >>= 1;
+				bitshft++;
+			}
+			while (bitshft <= (64 - count) && (bits & 1UL) != 0) {
+				bits >>= 1;
+				bitshft++;
+			}
+		} while (bitshft <= (64 - count));
+		if (entry == ~0)
+			ate++;
+	}
+	if (entry != ~0) {
+		KASSERT(ate < (PIC_REG_ATE_SIZE / 64), ("foo: ate"));
+		KASSERT(bitshft <= (64 - count), ("foo: bitshft"));
+		KASSERT(entry == (ate * 64 + bitshft), ("foo: math"));
+		bits = (count < 64) ? ((1UL << count) - 1UL) << bitshft : ~0UL;
+		KASSERT((sc->sc_ate[ate] & bits) == 0UL, ("foo: bits"));
+		sc->sc_ate[ate] |= bits;
 	}
+
+	mtx_unlock_spin(&sc->sc_ate_mtx);
+
+	if (entry == ~0) {
+		device_printf(sc->sc_dev, "IOMMU: cannot find %u free entries "
+		    "for DMA\n", count);
+		return (ENOSPC);
+	}
+
+	*ba_p = (1UL << 30) | (ba & SGISN_PCIB_PAGE_MASK) |
+	    (SGISN_PCIB_PAGE_SIZE * entry);
+
+	ba &= ~SGISN_PCIB_PAGE_MASK;
+	ba |= 1 << 0; /* valid */
+	ba |= 1 << ((flags & BUSDMA_ALLOC_CONSISTENT) ? 4 : 3);
+	ba |= (u_long)sc->sc_fwbus->fw_hub_xid << 8;
+	while (count > 0) {
+		bus_space_write_8(sc->sc_tag, sc->sc_hndl,
+		    PIC_REG_ATE(entry), ba);
+		ba += SGISN_PCIB_PAGE_SIZE;
+		entry++;
+		count--;
+	}
+	return (0);
+}
+
+static int
+sgisn_pcib_iommu_unmap(device_t bus, device_t dev, busdma_md_t md, u_int idx)
+{
+	struct sgisn_pcib_softc *sc = device_get_softc(bus);
+	bus_addr_t ba, size;
+	uint64_t bits;
+	u_int ate, bitshft, count, entry;
+
+	ba = busdma_md_get_busaddr(md, idx);
+	if ((ba >> 30) != 1)
+		return (0);
+
 	/*
-	 * XXX HACK END XXX
+	 * 32-bit mapped DMA
 	 */
+	size = busdma_md_get_size(md, idx);
+	count = ((ba & SGISN_PCIB_PAGE_MASK) + size +
+	    SGISN_PCIB_PAGE_MASK) >> SGISN_PCIB_PAGE_SHIFT;
+	ba &= (1 << 29) - 1;
+	entry = (ba >> SGISN_PCIB_PAGE_SHIFT);
+
+	KASSERT(count <= 64, ("foo: count"));
+	KASSERT((entry + count) <= PIC_REG_ATE_SIZE, ("foo"));
+	bitshft = entry & 64;
+	KASSERT(bitshft <= (64 - count), ("foo: bitshft"));
+	bits = (count < 64) ? ((1UL << count) - 1UL) << bitshft : ~0UL;
+	ate = entry / 64;
+
+	while (count > 0) {
+		bus_space_write_8(sc->sc_tag, sc->sc_hndl,
+		    PIC_REG_ATE(entry), 0);
+		entry++;
+		count--;
+	}
+
+	mtx_lock_spin(&sc->sc_ate_mtx);
+
+	sc->sc_ate[ate] &= ~bits;
+
+	mtx_unlock_spin(&sc->sc_ate_mtx);
+
 	return (0);
 }
 

Modified: projects/altix2/sys/kern/busdma_if.m
==============================================================================
--- projects/altix2/sys/kern/busdma_if.m	Sun Jan 27 23:33:42 2013	(r246016)
+++ projects/altix2/sys/kern/busdma_if.m	Mon Jan 28 00:15:44 2013	(r246017)
@@ -47,7 +47,8 @@ CODE {
 	}
 
 	static int
-	default_iommu_unmap(device_t bus, device_t dev, busdma_md_t md)
+	default_iommu_unmap(device_t bus, device_t dev, busdma_md_t md,
+	    u_int idx)
 	{
 		return (0);
 	}
@@ -78,6 +79,7 @@ METHOD int iommu_unmap {
 	device_t	bus;
 	device_t	dev;
 	busdma_md_t	md;
+	u_int		idx;
 } DEFAULT default_iommu_unmap;
 
 METHOD int iommu_sync {

Modified: projects/altix2/sys/kern/subr_busdma.c
==============================================================================
--- projects/altix2/sys/kern/subr_busdma.c	Sun Jan 27 23:33:42 2013	(r246016)
+++ projects/altix2/sys/kern/subr_busdma.c	Mon Jan 28 00:15:44 2013	(r246017)
@@ -430,11 +430,17 @@ _busdma_iommu_map(device_t dev, struct b
 static int
 _busdma_iommu_unmap(device_t dev, struct busdma_md *md)
 {
+	struct busdma_md_seg *seg;
 	device_t bus;
 	int error;
 
 	bus = device_get_parent(dev);
-	error = BUSDMA_IOMMU_UNMAP(bus, dev, md);
+	error = 0;
+	TAILQ_FOREACH(seg, &md->md_seg, mds_chain) {
+		error = BUSDMA_IOMMU_UNMAP(bus, dev, md, seg->mds_idx);
+		if (error)
+			break;
+	}
 	if (error)
 		printf("%s: error=%d\n", __func__, error);
 



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