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(®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); +} +
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201010250216.o9P2GZFj047785>