svn commit: r214312 - in user/nwhitehorn/ps3: conf powerpc/include
powerpc/powerpc powerpc/ps3
Nathan Whitehorn
nwhitehorn at FreeBSD.org
Mon Oct 25 02:16:35 UTC 2010
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(®ions, &rcount, ®ions, &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(®ions, &rcount, ®ions, &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);
+}
+
More information about the svn-src-user
mailing list