Skip site navigation (1)Skip section navigation (2)
Date:      Mon, 25 Oct 2010 02:16:35 +0000 (UTC)
From:      Nathan Whitehorn <nwhitehorn@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-user@freebsd.org
Subject:   svn commit: r214312 - in user/nwhitehorn/ps3: conf powerpc/include powerpc/powerpc powerpc/ps3
Message-ID:  <201010250216.o9P2GZFj047785@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: nwhitehorn
Date: Mon Oct 25 02:16:35 2010
New Revision: 214312
URL: http://svn.freebsd.org/changeset/base/214312

Log:
  Initial IOMMU support for the PS3 and generic bus dma hooks to allow it.
  USB still doesn't work.

Added:
  user/nwhitehorn/ps3/powerpc/powerpc/iommu_if.m
Modified:
  user/nwhitehorn/ps3/conf/files.powerpc
  user/nwhitehorn/ps3/powerpc/include/bus_dma.h
  user/nwhitehorn/ps3/powerpc/powerpc/busdma_machdep.c
  user/nwhitehorn/ps3/powerpc/ps3/if_glc.c
  user/nwhitehorn/ps3/powerpc/ps3/ps3bus.c

Modified: user/nwhitehorn/ps3/conf/files.powerpc
==============================================================================
--- user/nwhitehorn/ps3/conf/files.powerpc	Mon Oct 25 01:22:36 2010	(r214311)
+++ user/nwhitehorn/ps3/conf/files.powerpc	Mon Oct 25 02:16:35 2010	(r214312)
@@ -174,6 +174,7 @@ powerpc/powerpc/fuswintr.c	standard
 powerpc/powerpc/gdb_machdep.c	optional	gdb
 powerpc/powerpc/in_cksum.c	optional	inet
 powerpc/powerpc/intr_machdep.c	standard
+powerpc/powerpc/iommu_if.m	standard
 powerpc/powerpc/mem.c		optional	mem
 powerpc/powerpc/mmu_if.m	standard
 powerpc/powerpc/mp_machdep.c	optional	smp

Modified: user/nwhitehorn/ps3/powerpc/include/bus_dma.h
==============================================================================
--- user/nwhitehorn/ps3/powerpc/include/bus_dma.h	Mon Oct 25 01:22:36 2010	(r214311)
+++ user/nwhitehorn/ps3/powerpc/include/bus_dma.h	Mon Oct 25 02:16:35 2010	(r214312)
@@ -30,4 +30,8 @@
 
 #include <sys/bus_dma.h>
 
+struct device;
+
+int bus_dma_tag_set_iommu(bus_dma_tag_t, struct device *iommu, void *cookie);
+
 #endif /* _POWERPC_BUS_DMA_H_ */

Modified: user/nwhitehorn/ps3/powerpc/powerpc/busdma_machdep.c
==============================================================================
--- user/nwhitehorn/ps3/powerpc/powerpc/busdma_machdep.c	Mon Oct 25 01:22:36 2010	(r214311)
+++ user/nwhitehorn/ps3/powerpc/powerpc/busdma_machdep.c	Mon Oct 25 02:16:35 2010	(r214312)
@@ -53,6 +53,8 @@ __FBSDID("$FreeBSD$");
 #include <machine/bus.h>
 #include <machine/md_var.h>
 
+#include "iommu_if.h"
+
 #define MAX_BPAGES MIN(8192, physmem/40)
 
 struct bounce_zone;
@@ -73,8 +75,9 @@ struct bus_dma_tag {
 	int		  map_count;
 	bus_dma_lock_t	 *lockfunc;
 	void		 *lockfuncarg;
-	bus_dma_segment_t *segments;
 	struct bounce_zone *bounce_zone;
+	device_t	  iommu;
+	void		 *iommu_cookie;
 };
 
 struct bounce_page {
@@ -121,6 +124,8 @@ struct bus_dmamap {
 	bus_dma_tag_t	       dmat;
 	void		      *buf;		/* unmapped buffer pointer */
 	bus_size_t	       buflen;		/* unmapped buffer length */
+	bus_dma_segment_t     *segments;
+	int		       nsegs;
 	bus_dmamap_callback_t *callback;
 	void		      *callback_arg;
 	STAILQ_ENTRY(bus_dmamap) links;
@@ -128,7 +133,6 @@ struct bus_dmamap {
 
 static STAILQ_HEAD(, bus_dmamap) bounce_map_waitinglist;
 static STAILQ_HEAD(, bus_dmamap) bounce_map_callbacklist;
-static struct bus_dmamap nobounce_dmamap;
 
 static void init_bounce_pages(void *dummy);
 static int alloc_bounce_zone(bus_dma_tag_t dmat);
@@ -258,7 +262,6 @@ bus_dma_tag_create(bus_dma_tag_t parent,
 		newtag->lockfunc = dflt_lock;
 		newtag->lockfuncarg = NULL;
 	}
-	newtag->segments = NULL;
 
 	/* Take into account any restrictions imposed by our parent tag */
 	if (parent != NULL) {
@@ -280,6 +283,8 @@ bus_dma_tag_create(bus_dma_tag_t parent,
 		}
 		if (newtag->parent != NULL)
 			atomic_add_int(&parent->ref_count, 1);
+		newtag->iommu = parent->iommu;
+		newtag->iommu_cookie = parent->iommu_cookie;
 	}
 
 	if (newtag->lowaddr < ptoa((vm_paddr_t)Maxmem)
@@ -343,8 +348,6 @@ bus_dma_tag_destroy(bus_dma_tag_t dmat)
 			parent = dmat->parent;
 			atomic_subtract_int(&dmat->ref_count, 1);
 			if (dmat->ref_count == 0) {
-				if (dmat->segments != NULL)
-					free(dmat->segments, M_DEVBUF);
 				free(dmat, M_DEVBUF);
 				/*
 				 * Last reference count, so
@@ -372,17 +375,15 @@ bus_dmamap_create(bus_dma_tag_t dmat, in
 
 	error = 0;
 
-	if (dmat->segments == NULL) {
-		dmat->segments = (bus_dma_segment_t *)malloc(
-		    sizeof(bus_dma_segment_t) * dmat->nsegments, M_DEVBUF,
-		    M_NOWAIT);
-		if (dmat->segments == NULL) {
-			CTR3(KTR_BUSDMA, "%s: tag %p error %d",
-			    __func__, dmat, ENOMEM);
-			return (ENOMEM);
-		}
+	*mapp = (bus_dmamap_t)malloc(sizeof(**mapp), M_DEVBUF,
+				     M_NOWAIT | M_ZERO);
+	if (*mapp == NULL) {
+		CTR3(KTR_BUSDMA, "%s: tag %p error %d",
+		    __func__, dmat, ENOMEM);
+		return (ENOMEM);
 	}
 
+
 	/*
 	 * Bouncing might be required if the driver asks for an active
 	 * exclusion region, a data alignment that is stricter than 1, and/or
@@ -400,14 +401,6 @@ bus_dmamap_create(bus_dma_tag_t dmat, in
 		}
 		bz = dmat->bounce_zone;
 
-		*mapp = (bus_dmamap_t)malloc(sizeof(**mapp), M_DEVBUF,
-					     M_NOWAIT | M_ZERO);
-		if (*mapp == NULL) {
-			CTR3(KTR_BUSDMA, "%s: tag %p error %d",
-			    __func__, dmat, ENOMEM);
-			return (ENOMEM);
-		}
-
 		/* Initialize the new map */
 		STAILQ_INIT(&((*mapp)->bpages));
 
@@ -437,9 +430,18 @@ bus_dmamap_create(bus_dma_tag_t dmat, in
 			}
 		}
 		bz->map_count++;
-	} else {
-		*mapp = NULL;
 	}
+
+	(*mapp)->nsegs = 0;
+	(*mapp)->segments = (bus_dma_segment_t *)malloc(
+	    sizeof(bus_dma_segment_t) * dmat->nsegments, M_DEVBUF,
+	    M_NOWAIT);
+	if ((*mapp)->segments == NULL) {
+		CTR3(KTR_BUSDMA, "%s: tag %p error %d",
+		    __func__, dmat, ENOMEM);
+		return (ENOMEM);
+	}
+
 	if (error == 0)
 		dmat->map_count++;
 	CTR4(KTR_BUSDMA, "%s: tag %p tag flags 0x%x error %d",
@@ -454,7 +456,7 @@ bus_dmamap_create(bus_dma_tag_t dmat, in
 int
 bus_dmamap_destroy(bus_dma_tag_t dmat, bus_dmamap_t map)
 {
-	if (map != NULL && map != &nobounce_dmamap) {
+	if (dmat->flags & BUS_DMA_COULD_BOUNCE) {
 		if (STAILQ_FIRST(&map->bpages) != NULL) {
 			CTR3(KTR_BUSDMA, "%s: tag %p error %d",
 			    __func__, dmat, EBUSY);
@@ -462,8 +464,9 @@ bus_dmamap_destroy(bus_dma_tag_t dmat, b
 		}
 		if (dmat->bounce_zone)
 			dmat->bounce_zone->map_count--;
-		free(map, M_DEVBUF);
 	}
+	free(map->segments, M_DEVBUF);
+	free(map, M_DEVBUF);
 	dmat->map_count--;
 	CTR2(KTR_BUSDMA, "%s: tag %p error 0", __func__, dmat);
 	return (0);
@@ -486,19 +489,8 @@ bus_dmamem_alloc(bus_dma_tag_t dmat, voi
 	else
 		mflags = M_WAITOK;
 
-	/* If we succeed, no mapping/bouncing will be required */
-	*mapp = NULL;
+	bus_dmamap_create(dmat, flags, mapp);
 
-	if (dmat->segments == NULL) {
-		dmat->segments = (bus_dma_segment_t *)malloc(
-		    sizeof(bus_dma_segment_t) * dmat->nsegments, M_DEVBUF,
-		    mflags);
-		if (dmat->segments == NULL) {
-			CTR4(KTR_BUSDMA, "%s: tag %p tag flags 0x%x error %d",
-			    __func__, dmat, dmat->flags, ENOMEM);
-			return (ENOMEM);
-		}
-	}
 	if (flags & BUS_DMA_ZERO)
 		mflags |= M_ZERO;
 
@@ -535,7 +527,7 @@ bus_dmamem_alloc(bus_dma_tag_t dmat, voi
 #ifdef NOTYET
 	if (flags & BUS_DMA_NOCACHE)
 		pmap_change_attr((vm_offset_t)*vaddr, dmat->maxsize,
-		    PAT_UNCACHEABLE);
+		    VM_MEMATTR_UNCACHEABLE);
 #endif
 	CTR4(KTR_BUSDMA, "%s: tag %p tag flags 0x%x error %d",
 	    __func__, dmat, dmat->flags, 0);
@@ -549,14 +541,10 @@ bus_dmamem_alloc(bus_dma_tag_t dmat, voi
 void
 bus_dmamem_free(bus_dma_tag_t dmat, void *vaddr, bus_dmamap_t map)
 {
-	/*
-	 * dmamem does not need to be bounced, so the map should be
-	 * NULL
-	 */
-	if (map != NULL)
-		panic("bus_dmamem_free: Invalid map freed\n");
+	bus_dmamap_destroy(dmat, map);
+
 #ifdef NOTYET
-	pmap_change_attr((vm_offset_t)vaddr, dmat->maxsize, PAT_WRITE_BACK);
+	pmap_change_attr((vm_offset_t)vaddr, dmat->maxsize, VM_MEMATTR_DEFAULT);
 #endif
 	if ((dmat->maxsize <= PAGE_SIZE) &&
 	   (dmat->alignment < dmat->maxsize) &&
@@ -591,18 +579,13 @@ _bus_dmamap_load_buffer(bus_dma_tag_t dm
 	bus_addr_t paddr;
 	int seg;
 
-	if (map == NULL)
-		map = &nobounce_dmamap;
-
-	if ((map != &nobounce_dmamap && map->pagesneeded == 0) 
-	 && ((dmat->flags & BUS_DMA_COULD_BOUNCE) != 0)) {
+	if (map->pagesneeded == 0 && ((dmat->flags & BUS_DMA_COULD_BOUNCE) != 0)) {
 		vm_offset_t	vendaddr;
 
 		CTR4(KTR_BUSDMA, "lowaddr= %d Maxmem= %d, boundary= %d, "
 		    "alignment= %d", dmat->lowaddr, ptoa((vm_paddr_t)Maxmem),
 		    dmat->boundary, dmat->alignment);
-		CTR3(KTR_BUSDMA, "map= %p, nobouncemap= %p, pagesneeded= %d",
-		    map, &nobounce_dmamap, map->pagesneeded);
+		CTR2(KTR_BUSDMA, "map= %p, pagesneeded= %d", map, map->pagesneeded);
 		/*
 		 * Count the number of bounce pages
 		 * needed in order to complete this transfer
@@ -731,29 +714,36 @@ bus_dmamap_load(bus_dma_tag_t dmat, bus_
 		bus_size_t buflen, bus_dmamap_callback_t *callback,
 		void *callback_arg, int flags)
 {
-	bus_addr_t		lastaddr = 0;
-	int			error, nsegs = 0;
+	bus_addr_t	lastaddr = 0;
+	int		error;
 
-	if (map != NULL) {
+	if (dmat->flags & BUS_DMA_COULD_BOUNCE) {
 		flags |= BUS_DMA_WAITOK;
 		map->callback = callback;
 		map->callback_arg = callback_arg;
 	}
 
+	map->nsegs = 0;
 	error = _bus_dmamap_load_buffer(dmat, map, buf, buflen, NULL, flags,
-	     &lastaddr, dmat->segments, &nsegs, 1);
+	     &lastaddr, map->segments, &map->nsegs, 1);
+	map->nsegs++;
 
 	CTR5(KTR_BUSDMA, "%s: tag %p tag flags 0x%x error %d nsegs %d",
-	    __func__, dmat, dmat->flags, error, nsegs + 1);
+	    __func__, dmat, dmat->flags, error, map->nsegs);
 
 	if (error == EINPROGRESS) {
 		return (error);
 	}
 
+	if (dmat->iommu != NULL)
+		IOMMU_MAP(dmat->iommu, map->segments, &map->nsegs, dmat->lowaddr,
+		    dmat->highaddr, dmat->alignment, dmat->boundary,
+		    dmat->iommu_cookie);
+
 	if (error)
-		(*callback)(callback_arg, dmat->segments, 0, error);
+		(*callback)(callback_arg, map->segments, 0, error);
 	else
-		(*callback)(callback_arg, dmat->segments, nsegs + 1, 0);
+		(*callback)(callback_arg, map->segments, map->nsegs, 0);
 
 	/*
 	 * Return ENOMEM to the caller so that it can pass it up the stack.
@@ -775,12 +765,12 @@ bus_dmamap_load_mbuf(bus_dma_tag_t dmat,
 		     bus_dmamap_callback2_t *callback, void *callback_arg,
 		     int flags)
 {
-	int nsegs, error;
+	int error;
 
 	M_ASSERTPKTHDR(m0);
 
 	flags |= BUS_DMA_NOWAIT;
-	nsegs = 0;
+	map->nsegs = 0;
 	error = 0;
 	if (m0->m_pkthdr.len <= dmat->maxsize) {
 		int first = 1;
@@ -792,7 +782,7 @@ bus_dmamap_load_mbuf(bus_dma_tag_t dmat,
 				error = _bus_dmamap_load_buffer(dmat, map,
 						m->m_data, m->m_len,
 						NULL, flags, &lastaddr,
-						dmat->segments, &nsegs, first);
+						map->segments, &map->nsegs, first);
 				first = 0;
 			}
 		}
@@ -800,15 +790,21 @@ bus_dmamap_load_mbuf(bus_dma_tag_t dmat,
 		error = EINVAL;
 	}
 
+	map->nsegs++;
+	if (dmat->iommu != NULL)
+		IOMMU_MAP(dmat->iommu, map->segments, &map->nsegs, dmat->lowaddr,
+		    dmat->highaddr, dmat->alignment, dmat->boundary,
+		    dmat->iommu_cookie);
+
 	if (error) {
 		/* force "no valid mappings" in callback */
-		(*callback)(callback_arg, dmat->segments, 0, 0, error);
+		(*callback)(callback_arg, map->segments, 0, 0, error);
 	} else {
-		(*callback)(callback_arg, dmat->segments,
-			    nsegs+1, m0->m_pkthdr.len, error);
+		(*callback)(callback_arg, map->segments,
+			    map->nsegs, m0->m_pkthdr.len, error);
 	}
 	CTR5(KTR_BUSDMA, "%s: tag %p tag flags 0x%x error %d nsegs %d",
-	    __func__, dmat, dmat->flags, error, nsegs + 1);
+	    __func__, dmat, dmat->flags, error, map->nsegs);
 	return (error);
 }
 
@@ -844,6 +840,15 @@ bus_dmamap_load_mbuf_sg(bus_dma_tag_t dm
 
 	/* XXX FIXME: Having to increment nsegs is really annoying */
 	++*nsegs;
+
+	if (dmat->iommu != NULL)
+		IOMMU_MAP(dmat->iommu, segs, nsegs, dmat->lowaddr,
+		    dmat->highaddr, dmat->alignment, dmat->boundary,
+		    dmat->iommu_cookie);
+
+	map->nsegs = *nsegs;
+	memcpy(map->segments, segs, map->nsegs*sizeof(segs[0]));
+
 	CTR5(KTR_BUSDMA, "%s: tag %p tag flags 0x%x error %d nsegs %d",
 	    __func__, dmat, dmat->flags, error, *nsegs);
 	return (error);
@@ -859,7 +864,7 @@ bus_dmamap_load_uio(bus_dma_tag_t dmat, 
 		    int flags)
 {
 	bus_addr_t lastaddr = 0;
-	int nsegs, error, first, i;
+	int error, first, i;
 	bus_size_t resid;
 	struct iovec *iov;
 	pmap_t pmap;
@@ -875,7 +880,7 @@ bus_dmamap_load_uio(bus_dma_tag_t dmat, 
 	} else
 		pmap = NULL;
 
-	nsegs = 0;
+	map->nsegs = 0;
 	error = 0;
 	first = 1;
 	for (i = 0; i < uio->uio_iovcnt && resid != 0 && !error; i++) {
@@ -890,22 +895,28 @@ bus_dmamap_load_uio(bus_dma_tag_t dmat, 
 		if (minlen > 0) {
 			error = _bus_dmamap_load_buffer(dmat, map,
 					addr, minlen, pmap, flags, &lastaddr,
-					dmat->segments, &nsegs, first);
+					map->segments, &map->nsegs, first);
 			first = 0;
 
 			resid -= minlen;
 		}
 	}
 
+	map->nsegs++;
+	if (dmat->iommu != NULL)
+		IOMMU_MAP(dmat->iommu, map->segments, &map->nsegs, dmat->lowaddr,
+		    dmat->highaddr, dmat->alignment, dmat->boundary,
+		    dmat->iommu_cookie);
+
 	if (error) {
 		/* force "no valid mappings" in callback */
-		(*callback)(callback_arg, dmat->segments, 0, 0, error);
+		(*callback)(callback_arg, map->segments, 0, 0, error);
 	} else {
-		(*callback)(callback_arg, dmat->segments,
-			    nsegs+1, uio->uio_resid, error);
+		(*callback)(callback_arg, map->segments,
+			    map->nsegs, uio->uio_resid, error);
 	}
 	CTR5(KTR_BUSDMA, "%s: tag %p tag flags 0x%x error %d nsegs %d",
-	    __func__, dmat, dmat->flags, error, nsegs + 1);
+	    __func__, dmat, dmat->flags, error, map->nsegs);
 	return (error);
 }
 
@@ -917,6 +928,11 @@ _bus_dmamap_unload(bus_dma_tag_t dmat, b
 {
 	struct bounce_page *bpage;
 
+	if (dmat->iommu) {
+		IOMMU_UNMAP(dmat->iommu, map->segments, map->nsegs, dmat->iommu_cookie);
+		map->nsegs = 0;
+	}
+
 	while ((bpage = STAILQ_FIRST(&map->bpages)) != NULL) {
 		STAILQ_REMOVE_HEAD(&map->bpages, links);
 		free_bounce_page(dmat, bpage);
@@ -1122,8 +1138,6 @@ add_bounce_page(bus_dma_tag_t dmat, bus_
 	struct bounce_page *bpage;
 
 	KASSERT(dmat->bounce_zone != NULL, ("no bounce zone in dma tag"));
-	KASSERT(map != NULL && map != &nobounce_dmamap,
-	    ("add_bounce_page: bad map %p", map));
 
 	bz = dmat->bounce_zone;
 	if (map->pagesneeded == 0)
@@ -1210,3 +1224,13 @@ busdma_swi(void)
 	}
 	mtx_unlock(&bounce_lock);
 }
+
+int
+bus_dma_tag_set_iommu(bus_dma_tag_t tag, struct device *iommu, void *cookie)
+{
+	tag->iommu = iommu;
+	tag->iommu_cookie = cookie;
+
+	return (0);
+}
+

Added: user/nwhitehorn/ps3/powerpc/powerpc/iommu_if.m
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ user/nwhitehorn/ps3/powerpc/powerpc/iommu_if.m	Mon Oct 25 02:16:35 2010	(r214312)
@@ -0,0 +1,54 @@
+#-
+# Copyright (c) 2010 Nathan Whitehorn
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 1. Redistributions of source code must retain the above copyright
+#    notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+#    notice, this list of conditions and the following disclaimer in the
+#    documentation and/or other materials provided with the distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+# ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+# SUCH DAMAGE.
+#
+# from: src/sys/kern/bus_if.m,v 1.21 2002/04/21 11:16:10 markm Exp
+# $FreeBSD: user/nwhitehorn/ps3/powerpc/powerpc/pic_if.m 209486 2010-06-23 22:33:03Z nwhitehorn $
+#
+
+#include <machine/bus.h>
+
+#include <sys/bus.h>
+#include <sys/bus_dma.h>
+
+INTERFACE iommu;
+
+METHOD int map {
+	device_t	iommu;
+	bus_dma_segment_t *segs;
+	int		*nsegs;
+	bus_addr_t	lowaddr;
+	bus_addr_t	highaddr;
+	bus_size_t	alignment;
+	bus_size_t	boundary;
+	void		*cookie;
+};
+
+METHOD int unmap {
+	device_t	iommu;
+	bus_dma_segment_t *segs;
+	int		nsegs;
+	void		*cookie;
+};
+

Modified: user/nwhitehorn/ps3/powerpc/ps3/if_glc.c
==============================================================================
--- user/nwhitehorn/ps3/powerpc/ps3/if_glc.c	Mon Oct 25 01:22:36 2010	(r214311)
+++ user/nwhitehorn/ps3/powerpc/ps3/if_glc.c	Mon Oct 25 02:16:35 2010	(r214312)
@@ -116,36 +116,13 @@ glc_getphys(void *xaddr, bus_dma_segment
 	*(bus_addr_t *)xaddr = segs[0].ds_addr;
 }
 
-static bus_addr_t
-glc_map_addr(struct glc_softc *sc, bus_addr_t lpar_addr)
-{
-	static struct mem_region *regions = NULL;
-	static int rcount;
-	int i;
-
-	if (regions == NULL)
-		mem_regions(&regions, &rcount, &regions, &rcount);
-
-	for (i = 0; i < rcount; i++) {
-		if (lpar_addr >= regions[i].mr_start &&
-		    lpar_addr < regions[i].mr_start + regions[i].mr_size)
-			break;
-	}
-
-	if (i == rcount)
-		panic("glc: unable to map address %#lx", lpar_addr);
-
-	return (sc->sc_dma_base[i] + (lpar_addr - regions[i].mr_start));
-}
-
 static int 
 glc_attach(device_t dev) 
 {
 	struct glc_softc *sc;
 	struct glc_txsoft *txs;
-	struct mem_region *regions;
 	uint64_t mac64, val, junk;
-	int i, err, rcount;
+	int i, err;
 
 	sc = device_get_softc(dev);
 
@@ -214,28 +191,6 @@ glc_attach(device_t dev) 
 	 * Set up DMA.
 	 */
 
-	/* XXX: following should be integrated to busdma */
-	mem_regions(&regions, &rcount, &regions, &rcount);
-	for (i = 0; i < rcount; i++) {
-		err = lv1_allocate_device_dma_region(sc->sc_bus, sc->sc_dev,
-		    regions[i].mr_size, 24 /* log_2(16 MB) */,
-		    0 /* 32-bit transfers */, &sc->sc_dma_base[i]);
-		if (err != 0) {
-			device_printf(dev,
-			    "could not allocate DMA region %d: %d\n", i, err);
-			goto fail;
-		}
-
-		err = lv1_map_device_dma_region(sc->sc_bus, sc->sc_dev,
-		    regions[i].mr_start, sc->sc_dma_base[i], regions[i].mr_size,
-		    0xf800000000000000UL /* see Cell IO/MMU docs */);
-		if (err != 0) {
-			device_printf(dev,
-			    "could not map DMA region %d: %d\n", i, err);
-			goto fail;
-		}
-	}
-
 	err = bus_dma_tag_create(bus_get_dma_tag(dev), 32, 0,
 	    BUS_SPACE_MAXADDR, BUS_SPACE_MAXADDR, NULL, NULL,
 	    129*sizeof(struct glc_dmadesc), 1, 128*sizeof(struct glc_dmadesc),
@@ -326,7 +281,6 @@ glc_attach(device_t dev) 
 
 	return (0);
 
-fail:
 	mtx_destroy(&sc->sc_mtx);
 	if_free(sc->sc_ifp);
 	return (ENXIO);
@@ -367,8 +321,8 @@ glc_init_locked(struct glc_softc *sc)
 	txs = STAILQ_FIRST(&sc->sc_txdirtyq);
 	if (txs != NULL) {
 		lv1_net_start_tx_dma(sc->sc_bus, sc->sc_dev,
-		    glc_map_addr(sc, sc->sc_txdmadesc_phys +
-		    txs->txs_firstdesc*sizeof(struct glc_dmadesc)), 0);
+		    sc->sc_txdmadesc_phys +
+		    txs->txs_firstdesc*sizeof(struct glc_dmadesc), 0);
 	}
 
 	lv1_net_start_rx_dma(sc->sc_bus, sc->sc_dev,
@@ -613,15 +567,14 @@ glc_add_rxbuf_dma(struct glc_softc *sc, 
 	struct glc_rxsoft *rxs = &sc->sc_rxsoft[idx];
 	
 	bzero(&sc->sc_rxdmadesc[idx], sizeof(sc->sc_rxdmadesc[idx]));
-	sc->sc_rxdmadesc[idx].paddr = glc_map_addr(sc, rxs->segment.ds_addr);
+	sc->sc_rxdmadesc[idx].paddr = rxs->segment.ds_addr;
 	sc->sc_rxdmadesc[idx].len = rxs->segment.ds_len;
-	sc->sc_rxdmadesc[idx].next = glc_map_addr(sc, sc->sc_rxdmadesc_phys +
-	    ((idx + 1) % GLC_MAX_RX_PACKETS)*sizeof(sc->sc_rxdmadesc[idx]));
+	sc->sc_rxdmadesc[idx].next = sc->sc_rxdmadesc_phys +
+	    ((idx + 1) % GLC_MAX_RX_PACKETS)*sizeof(sc->sc_rxdmadesc[idx]);
 	sc->sc_rxdmadesc[idx].cmd_stat = GELIC_DESCR_OWNED;
 
 	rxs->rxs_desc_slot = idx;
-	rxs->rxs_desc = glc_map_addr(sc, sc->sc_rxdmadesc_phys +
-	    idx*sizeof(struct glc_dmadesc));
+	rxs->rxs_desc = sc->sc_rxdmadesc_phys + idx*sizeof(struct glc_dmadesc);
 
         return (0);
 }
@@ -684,16 +637,15 @@ glc_encap(struct glc_softc *sc, struct m
 	txs->txs_firstdesc = sc->next_txdma_slot;
 
 	idx = txs->txs_firstdesc;
-	firstslotphys = glc_map_addr(sc, sc->sc_txdmadesc_phys +
-	    txs->txs_firstdesc*sizeof(struct glc_dmadesc));
+	firstslotphys = sc->sc_txdmadesc_phys +
+	    txs->txs_firstdesc*sizeof(struct glc_dmadesc);
 
 	for (i = 0; i < nsegs; i++) {
 		bzero(&sc->sc_txdmadesc[idx], sizeof(sc->sc_txdmadesc[idx]));
-		sc->sc_txdmadesc[idx].paddr = glc_map_addr(sc, segs[i].ds_addr);
+		sc->sc_txdmadesc[idx].paddr = segs[i].ds_addr;
 		sc->sc_txdmadesc[idx].len = segs[i].ds_len;
-		sc->sc_txdmadesc[idx].next = glc_map_addr(sc,
-		    sc->sc_txdmadesc_phys +
-		    ((idx + 1) % GLC_MAX_TX_PACKETS)*sizeof(struct glc_dmadesc));
+		sc->sc_txdmadesc[idx].next = sc->sc_txdmadesc_phys +
+		    ((idx + 1) % GLC_MAX_TX_PACKETS)*sizeof(struct glc_dmadesc);
 		sc->sc_txdmadesc[idx].cmd_stat |= GELIC_CMDSTAT_NOIPSEC;
 
 		if (i+1 == nsegs) {
@@ -836,8 +788,8 @@ glc_txintr(struct glc_softc *sc)
 
 	if (kickstart && txs != NULL) {
 		lv1_net_start_tx_dma(sc->sc_bus, sc->sc_dev,
-		    glc_map_addr(sc, sc->sc_txdmadesc_phys +
-		    txs->txs_firstdesc*sizeof(struct glc_dmadesc)), 0);
+		    sc->sc_txdmadesc_phys +
+		    txs->txs_firstdesc*sizeof(struct glc_dmadesc), 0);
 	}
 
 	if (progress) {

Modified: user/nwhitehorn/ps3/powerpc/ps3/ps3bus.c
==============================================================================
--- user/nwhitehorn/ps3/powerpc/ps3/ps3bus.c	Mon Oct 25 01:22:36 2010	(r214311)
+++ user/nwhitehorn/ps3/powerpc/ps3/ps3bus.c	Mon Oct 25 02:16:35 2010	(r214312)
@@ -45,6 +45,7 @@
 
 #include "ps3bus.h"
 #include "ps3-hvcall.h"
+#include "iommu_if.h"
 
 static void	ps3bus_identify(driver_t *, device_t);
 static int	ps3bus_probe(device_t);
@@ -57,6 +58,11 @@ static struct resource *ps3bus_alloc_res
 		    u_long count, u_int flags);
 static int	ps3bus_activate_resource(device_t bus, device_t child, int type,
 		    int rid, struct resource *res);
+static bus_dma_tag_t ps3bus_get_dma_tag(device_t dev, device_t child);
+static int	ps3_iommu_map(device_t dev, bus_dma_segment_t *segs, int *nsegs,		    bus_addr_t min, bus_addr_t max, bus_size_t alignment,
+		    bus_size_t boundary, void *cookie);
+static int	ps3_iommu_unmap(device_t dev, bus_dma_segment_t *segs,
+		    int nsegs, void *cookie);
 
 struct ps3bus_devinfo {
 	int bus;
@@ -65,6 +71,10 @@ struct ps3bus_devinfo {
 	uint64_t devtype;
 
 	struct resource_list resources;
+	bus_dma_tag_t dma_tag;
+
+	struct mtx iommu_mtx;
+	bus_addr_t dma_base[4];
 };
 
 static MALLOC_DEFINE(M_PS3BUS, "ps3bus", "PS3 system bus device information");
@@ -84,6 +94,7 @@ static device_method_t ps3bus_methods[] 
 	/* Bus interface */
 	DEVMETHOD(bus_driver_added,	bus_generic_driver_added),
 	DEVMETHOD(bus_add_child,	bus_generic_add_child),
+	DEVMETHOD(bus_get_dma_tag,	ps3bus_get_dma_tag),
 	DEVMETHOD(bus_print_child,	ps3bus_print_child),
 	DEVMETHOD(bus_read_ivar,	ps3bus_read_ivar),
 	DEVMETHOD(bus_alloc_resource,	ps3bus_alloc_resource),
@@ -91,11 +102,17 @@ static device_method_t ps3bus_methods[] 
 	DEVMETHOD(bus_setup_intr,	bus_generic_setup_intr),
 	DEVMETHOD(bus_teardown_intr,	bus_generic_teardown_intr),
 
+	/* IOMMU interface */
+	DEVMETHOD(iommu_map,		ps3_iommu_map),
+	DEVMETHOD(iommu_unmap,		ps3_iommu_unmap),
+
 	{ 0, 0 }
 };
 
 struct ps3bus_softc {
 	struct rman sc_mem_rman;
+	struct mem_region *regions;
+	int rcount;
 };
 
 static driver_t ps3bus_driver = {
@@ -226,6 +243,9 @@ ps3bus_attach(device_t self) 
 	sc->sc_mem_rman.rm_descr = "PS3Bus Memory Mapped I/O";
 	rman_init(&sc->sc_mem_rman);
 
+	/* Get memory regions for DMA */
+	mem_regions(&sc->regions, &sc->rcount, &sc->regions, &sc->rcount);
+
 	/*
 	 * Probe all the PS3's buses.
 	 */
@@ -287,6 +307,8 @@ ps3bus_attach(device_t self) 
 				free(dinfo, M_PS3BUS);
 				continue;
 			}
+
+			mtx_init(&dinfo->iommu_mtx, "iommu", NULL, MTX_DEF);
 			device_set_ivars(cdev, dinfo);
 		}
 	}
@@ -444,3 +466,90 @@ ps3bus_activate_resource(device_t bus, d
 	return (rman_activate_resource(res));
 }
 
+static bus_dma_tag_t
+ps3bus_get_dma_tag(device_t dev, device_t child)
+{
+	struct ps3bus_devinfo *dinfo = device_get_ivars(child);
+	struct ps3bus_softc *sc = device_get_softc(dev);
+	int i, err;
+
+	mtx_lock(&dinfo->iommu_mtx);
+	if (dinfo->dma_tag != NULL) {
+		mtx_unlock(&dinfo->iommu_mtx);
+		return (dinfo->dma_tag);
+	}
+printf("Allocating tag for device %d.%d:\n", dinfo->bus, dinfo->dev);
+
+	for (i = 0; i < sc->rcount; i++) {
+		err = lv1_allocate_device_dma_region(dinfo->bus, dinfo->dev,
+		    sc->regions[i].mr_size, 24 /* log_2(16 MB) */,
+		    0 /* 32-bit transfers */, &dinfo->dma_base[i]);
+		if (err != 0) {
+			device_printf(child,
+			    "could not allocate DMA region %d: %d\n", i, err);
+			goto fail;
+		}
+
+		err = lv1_map_device_dma_region(dinfo->bus, dinfo->dev,
+		    sc->regions[i].mr_start, dinfo->dma_base[i],
+		    sc->regions[i].mr_size,
+		    0xf800000000000000UL /* see Cell IO/MMU docs */);
+		if (err != 0) {
+			device_printf(child,
+			    "could not map DMA region %d: %d\n", i, err);
+			goto fail;
+		}
+printf("\tPhys mem %#lx mapped to %#lx\n", sc->regions[i].mr_start, dinfo->dma_base[i]);
+	}
+
+	err = bus_dma_tag_create(bus_get_dma_tag(dev),
+	    1, 0, BUS_SPACE_MAXADDR, BUS_SPACE_MAXADDR,
+	    NULL, NULL, BUS_SPACE_MAXSIZE_32BIT, 0, BUS_SPACE_MAXSIZE_32BIT,
+	    0, NULL, NULL, &dinfo->dma_tag);
+
+	bus_dma_tag_set_iommu(dinfo->dma_tag, dev, dinfo);
+
+fail:
+	mtx_unlock(&dinfo->iommu_mtx);
+
+	if (err)
+		return (NULL);
+
+	return (dinfo->dma_tag);
+}
+
+static int
+ps3_iommu_map(device_t dev, bus_dma_segment_t *segs, int *nsegs,
+    bus_addr_t min, bus_addr_t max, bus_size_t alignment, bus_size_t boundary,
+    void *cookie)
+{
+	struct ps3bus_devinfo *dinfo = cookie;
+	struct ps3bus_softc *sc = device_get_softc(dev);
+	int i, j;
+
+	for (i = 0; i < *nsegs; i++) {
+		for (j = 0; j < sc->rcount; j++) {
+			if (segs[i].ds_addr >= sc->regions[j].mr_start &&
+			    segs[i].ds_addr < sc->regions[j].mr_start +
+			      sc->regions[j].mr_size)
+				break;
+		}
+		KASSERT(j < sc->rcount,
+		    ("Trying to map address %#lx not in physical memory",
+		    segs[i].ds_addr));
+
+		segs[i].ds_addr = dinfo->dma_base[j] +
+		    (segs[i].ds_addr - sc->regions[j].mr_start);
+	}
+
+	return (0);
+}
+
+
+static int
+ps3_iommu_unmap(device_t dev, bus_dma_segment_t *segs, int nsegs, void *cookie)
+{
+
+	return (0);
+}
+



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