diff options
Diffstat (limited to 'sys/arch/sgi')
-rw-r--r-- | sys/arch/sgi/include/bus.h | 6 | ||||
-rw-r--r-- | sys/arch/sgi/localbus/macebus.c | 3 | ||||
-rw-r--r-- | sys/arch/sgi/pci/macepcibridge.c | 3 | ||||
-rw-r--r-- | sys/arch/sgi/sgi/bus_dma.c | 441 | ||||
-rw-r--r-- | sys/arch/sgi/xbow/xbridge.c | 165 |
5 files changed, 271 insertions, 347 deletions
diff --git a/sys/arch/sgi/include/bus.h b/sys/arch/sgi/include/bus.h index 6b5d7490712..1f6e5585f5c 100644 --- a/sys/arch/sgi/include/bus.h +++ b/sys/arch/sgi/include/bus.h @@ -1,4 +1,4 @@ -/* $OpenBSD: bus.h,v 1.15 2009/05/31 17:42:13 miod Exp $ */ +/* $OpenBSD: bus.h,v 1.16 2009/07/17 18:06:49 miod Exp $ */ /* * Copyright (c) 2003-2004 Opsycon AB Sweden. All rights reserved. @@ -370,6 +370,8 @@ struct machine_bus_dma_tag { struct uio *, int); int (*_dmamap_load_raw)(bus_dma_tag_t , bus_dmamap_t, bus_dma_segment_t *, int, bus_size_t, int); + int (*_dmamap_load_buffer)(bus_dma_tag_t, bus_dmamap_t, void *, + bus_size_t, struct proc *, int, paddr_t *, int *, int); void (*_dmamap_unload)(bus_dma_tag_t , bus_dmamap_t); void (*_dmamap_sync)(bus_dma_tag_t , bus_dmamap_t, bus_addr_t, bus_size_t, int); @@ -432,6 +434,8 @@ int _dmamap_load_mbuf(bus_dma_tag_t, bus_dmamap_t, struct mbuf *, int); int _dmamap_load_uio(bus_dma_tag_t, bus_dmamap_t, struct uio *, int); int _dmamap_load_raw(bus_dma_tag_t, bus_dmamap_t, bus_dma_segment_t *, int, bus_size_t, int); +int _dmamap_load_buffer(bus_dma_tag_t, bus_dmamap_t, void *, + bus_size_t, struct proc *, int, paddr_t *, int *, int); void _dmamap_unload(bus_dma_tag_t, bus_dmamap_t); void _dmamap_sync(bus_dma_tag_t, bus_dmamap_t, bus_addr_t, bus_size_t, int); diff --git a/sys/arch/sgi/localbus/macebus.c b/sys/arch/sgi/localbus/macebus.c index 01c769f9624..64e069dc9e2 100644 --- a/sys/arch/sgi/localbus/macebus.c +++ b/sys/arch/sgi/localbus/macebus.c @@ -1,4 +1,4 @@ -/* $OpenBSD: macebus.c,v 1.38 2009/03/20 18:41:07 miod Exp $ */ +/* $OpenBSD: macebus.c,v 1.39 2009/07/17 18:06:51 miod Exp $ */ /* * Copyright (c) 2000-2004 Opsycon AB (www.opsycon.se) @@ -151,6 +151,7 @@ struct machine_bus_dma_tag mace_bus_dma_tag = { _dmamap_load_mbuf, _dmamap_load_uio, _dmamap_load_raw, + _dmamap_load_buffer, _dmamap_unload, _dmamap_sync, _dmamem_alloc, diff --git a/sys/arch/sgi/pci/macepcibridge.c b/sys/arch/sgi/pci/macepcibridge.c index 2c6653810ad..cdf4b5247ce 100644 --- a/sys/arch/sgi/pci/macepcibridge.c +++ b/sys/arch/sgi/pci/macepcibridge.c @@ -1,4 +1,4 @@ -/* $OpenBSD: macepcibridge.c,v 1.23 2009/07/16 21:02:56 miod Exp $ */ +/* $OpenBSD: macepcibridge.c,v 1.24 2009/07/17 18:06:51 miod Exp $ */ /* * Copyright (c) 2001-2004 Opsycon AB (www.opsycon.se) @@ -133,6 +133,7 @@ struct machine_bus_dma_tag pci_bus_dma_tag = { _dmamap_load_mbuf, _dmamap_load_uio, _dmamap_load_raw, + _dmamap_load_buffer, _dmamap_unload, _dmamap_sync, _dmamem_alloc, diff --git a/sys/arch/sgi/sgi/bus_dma.c b/sys/arch/sgi/sgi/bus_dma.c index a3969275f41..a9f52aa0194 100644 --- a/sys/arch/sgi/sgi/bus_dma.c +++ b/sys/arch/sgi/sgi/bus_dma.c @@ -1,4 +1,4 @@ -/* $OpenBSD: bus_dma.c,v 1.13 2009/05/24 17:31:07 miod Exp $ */ +/* $OpenBSD: bus_dma.c,v 1.14 2009/07/17 18:06:51 miod Exp $ */ /* * Copyright (c) 2003-2004 Opsycon AB (www.opsycon.se / www.opsycon.com) @@ -25,6 +25,35 @@ * SUCH DAMAGE. * */ +/*- + * Copyright (c) 1996, 1997, 1998 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility, + * NASA Ames Research Center. + * + * 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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. + */ #include <sys/param.h> #include <sys/systm.h> #include <sys/kernel.h> @@ -40,21 +69,14 @@ #include <machine/autoconf.h> #include <machine/bus.h> -#include <sgi/sgi/ip30.h> /* * Common function for DMA map creation. May be called by bus-specific * DMA map creation functions. */ int -_dmamap_create(t, size, nsegments, maxsegsz, boundary, flags, dmamp) - bus_dma_tag_t t; - bus_size_t size; - int nsegments; - bus_size_t maxsegsz; - bus_size_t boundary; - int flags; - bus_dmamap_t *dmamp; +_dmamap_create(bus_dma_tag_t t, bus_size_t size, int nsegments, + bus_size_t maxsegsz, bus_size_t boundary, int flags, bus_dmamap_t *dmamp) { struct machine_bus_dmamap *map; void *mapstore; @@ -104,20 +126,11 @@ _dmamap_destroy(bus_dma_tag_t t, bus_dmamap_t map) * be called by bus-specific DMA map load functions. */ int -_dmamap_load(t, map, buf, buflen, p, flags) - bus_dma_tag_t t; - bus_dmamap_t map; - void *buf; - bus_size_t buflen; - struct proc *p; - int flags; +_dmamap_load(bus_dma_tag_t t, bus_dmamap_t map, void *buf, bus_size_t buflen, + struct proc *p, int flags) { - bus_size_t sgsize; - bus_addr_t curaddr, lastaddr, baddr, bmask; - caddr_t vaddr = buf; - int first, seg; - pmap_t pmap; - bus_size_t saved_buflen; + paddr_t lastaddr; + int seg, error; /* * Make sure that on error condition we return "no valid mappings". @@ -128,154 +141,112 @@ _dmamap_load(t, map, buf, buflen, p, flags) if (buflen > map->_dm_size) return (EINVAL); - if (p != NULL) - pmap = p->p_vmspace->vm_map.pmap; - else - pmap = pmap_kernel(); - - lastaddr = ~0; /* XXX gcc */ - bmask = ~(map->_dm_boundary - 1); - if (t->_dma_mask != 0) - bmask &= t->_dma_mask; - - saved_buflen = buflen; - for (first = 1, seg = 0; buflen > 0; ) { - /* - * Get the physical address for this segment. - */ - if (pmap_extract(pmap, (vaddr_t)vaddr, (paddr_t *)&curaddr) == - FALSE) - panic("_dmapmap_load: pmap_extract(%x, %x) failed!", - pmap, vaddr); - - /* - * Compute the segment size, and adjust counts. - */ - sgsize = NBPG - ((u_long)vaddr & PGOFSET); - if (buflen < sgsize) - sgsize = buflen; - - /* - * Make sure we don't cross any boundaries. - */ - if (map->_dm_boundary > 0) { - baddr = (curaddr + map->_dm_boundary) & bmask; - if (sgsize > (baddr - curaddr)) - sgsize = (baddr - curaddr); - } - - /* - * Insert chunk into a segment, coalescing with - * previous segment if possible. - */ - if (first) { - map->dm_segs[seg].ds_addr = - (*t->_pa_to_device)(curaddr); - map->dm_segs[seg].ds_len = sgsize; - map->dm_segs[seg]._ds_vaddr = (vaddr_t)vaddr; - first = 0; - } else { - if (curaddr == lastaddr && - (map->dm_segs[seg].ds_len + sgsize) <= - map->_dm_maxsegsz && - (map->_dm_boundary == 0 || - (map->dm_segs[seg].ds_addr & bmask) == - (curaddr & bmask))) - map->dm_segs[seg].ds_len += sgsize; - else { - if (++seg >= map->_dm_segcnt) - break; - map->dm_segs[seg].ds_addr = - (*t->_pa_to_device)(curaddr); - map->dm_segs[seg].ds_len = sgsize; - map->dm_segs[seg]._ds_vaddr = (vaddr_t)vaddr; - } - } - - lastaddr = curaddr + sgsize; - vaddr += sgsize; - buflen -= sgsize; + seg = 0; + error = (*t->_dmamap_load_buffer)(t, map, buf, buflen, p, flags, + &lastaddr, &seg, 1); + if (error == 0) { + map->dm_nsegs = seg + 1; + map->dm_mapsize = buflen; } - /* - * Did we fit? - */ - if (buflen != 0) - return (EFBIG); /* XXX better return value here? */ - - map->dm_nsegs = seg + 1; - map->dm_mapsize = saved_buflen; - return (0); + return (error); } /* * Like _bus_dmamap_load(), but for mbufs. */ int -_dmamap_load_mbuf(t, map, m, flags) - bus_dma_tag_t t; - bus_dmamap_t map; - struct mbuf *m; - int flags; +_dmamap_load_mbuf(bus_dma_tag_t t, bus_dmamap_t map, struct mbuf *m0, int flags) { - int i; - size_t len; + paddr_t lastaddr; + int seg, error, first; + struct mbuf *m; + /* + * Make sure that on error condition we return "no valid mappings". + */ map->dm_nsegs = 0; map->dm_mapsize = 0; - i = 0; - len = 0; - while (m) { - vaddr_t vaddr = mtod(m, vaddr_t); - long buflen = (long)m->m_len; - - len += buflen; - while (buflen > 0 && i < map->_dm_segcnt) { - paddr_t pa; - long incr; - - incr = min(buflen, NBPG); - buflen -= incr; - if (pmap_extract(pmap_kernel(), vaddr, &pa) == FALSE) - panic("_dmamap_load_mbuf: pmap_extract(%x, %x) failed!", - pmap_kernel(), vaddr); - - if (i > 0 && pa == (*t->_device_to_pa)(map->dm_segs[i-1].ds_addr + map->dm_segs[i-1].ds_len) - && ((map->dm_segs[i-1].ds_len + incr) < map->_dm_maxsegsz)) { - /* Hey, waddyaknow, they're contiguous */ - map->dm_segs[i-1].ds_len += incr; - continue; - } - map->dm_segs[i].ds_addr = - (*t->_pa_to_device)(pa); - map->dm_segs[i]._ds_vaddr = vaddr; - map->dm_segs[i].ds_len = incr; - i++; - vaddr += incr; - } - m = m->m_next; - if (m && i >= map->_dm_segcnt) { - /* Exceeded the size of our dmamap */ - return EFBIG; - } +#ifdef DIAGNOSTIC + if ((m0->m_flags & M_PKTHDR) == 0) + panic("_dmamap_load_mbuf: no packet header"); +#endif + + if (m0->m_pkthdr.len > map->_dm_size) + return (EINVAL); + + first = 1; + seg = 0; + error = 0; + for (m = m0; m != NULL && error == 0; m = m->m_next) { + if (m->m_len == 0) + continue; + error = (*t->_dmamap_load_buffer)(t, map, m->m_data, m->m_len, + NULL, flags, &lastaddr, &seg, first); + first = 0; } - map->dm_nsegs = i; - map->dm_mapsize = len; - return (0); + if (error == 0) { + map->dm_nsegs = seg + 1; + map->dm_mapsize = m0->m_pkthdr.len; + } + + return (error); } /* * Like _dmamap_load(), but for uios. */ int -_dmamap_load_uio(t, map, uio, flags) - bus_dma_tag_t t; - bus_dmamap_t map; - struct uio *uio; - int flags; +_dmamap_load_uio(bus_dma_tag_t t, bus_dmamap_t map, struct uio *uio, int flags) { - return (EOPNOTSUPP); + paddr_t lastaddr; + int seg, i, error, first; + bus_size_t minlen, resid; + struct proc *p = NULL; + struct iovec *iov; + void *addr; + + /* + * Make sure that on error condition we return "no valid mappings". + */ + map->dm_nsegs = 0; + map->dm_mapsize = 0; + + resid = uio->uio_resid; + iov = uio->uio_iov; + + if (uio->uio_segflg == UIO_USERSPACE) { + p = uio->uio_procp; +#ifdef DIAGNOSTIC + if (p == NULL) + panic("_dmamap_load_uio: USERSPACE but no proc"); +#endif + } + + first = 1; + seg = 0; + error = 0; + for (i = 0; i < uio->uio_iovcnt && resid != 0 && error == 0; i++) { + /* + * Now at the first iovec to load. Load each iovec + * until we have exhausted the residual count. + */ + minlen = resid < iov[i].iov_len ? resid : iov[i].iov_len; + addr = (void *)iov[i].iov_base; + + error = (*t->_dmamap_load_buffer)(t, map, addr, minlen, + p, flags, &lastaddr, &seg, first); + first = 0; + + resid -= minlen; + } + if (error == 0) { + map->dm_nsegs = seg + 1; + map->dm_mapsize = uio->uio_resid; + } + + return (error); } /* @@ -283,13 +254,8 @@ _dmamap_load_uio(t, map, uio, flags) * bus_dmamem_alloc(). */ int -_dmamap_load_raw(t, map, segs, nsegs, size, flags) - bus_dma_tag_t t; - bus_dmamap_t map; - bus_dma_segment_t *segs; - int nsegs; - bus_size_t size; - int flags; +_dmamap_load_raw(bus_dma_tag_t t, bus_dmamap_t map, bus_dma_segment_t *segs, + int nsegs, bus_size_t size, int flags) { if (nsegs > map->_dm_segcnt || size > map->_dm_size) return (EINVAL); @@ -323,11 +289,8 @@ _dmamap_load_raw(t, map, segs, nsegs, size, flags) * bus-specific DMA map unload functions. */ void -_dmamap_unload(t, map) - bus_dma_tag_t t; - bus_dmamap_t map; +_dmamap_unload(bus_dma_tag_t t, bus_dmamap_t map) { - /* * No resources to free; just mark the mappings as * invalid. @@ -341,12 +304,8 @@ _dmamap_unload(t, map) * by bus-specific DMA map synchronization functions. */ void -_dmamap_sync(t, map, addr, size, op) - bus_dma_tag_t t; - bus_dmamap_t map; - bus_addr_t addr; - bus_size_t size; - int op; +_dmamap_sync(bus_dma_tag_t t, bus_dmamap_t map, bus_addr_t addr, + bus_size_t size, int op) { #define SYNC_R 0 /* WB invalidate, WT invalidate */ #define SYNC_W 1 /* WB writeback + invalidate, WT unaffected */ @@ -432,13 +391,9 @@ _dmamap_sync(t, map, addr, size, op) * by bus-specific DMA memory allocation functions. */ int -_dmamem_alloc(t, size, alignment, boundary, segs, nsegs, rsegs, flags) - bus_dma_tag_t t; - bus_size_t size, alignment, boundary; - bus_dma_segment_t *segs; - int nsegs; - int *rsegs; - int flags; +_dmamem_alloc(bus_dma_tag_t t, bus_size_t size, bus_size_t alignment, + bus_size_t boundary, bus_dma_segment_t *segs, int nsegs, int *rsegs, + int flags) { return _dmamem_alloc_range(t, size, alignment, boundary, segs, nsegs, rsegs, flags, (vaddr_t)0, (vaddr_t)-1); @@ -449,10 +404,7 @@ _dmamem_alloc(t, size, alignment, boundary, segs, nsegs, rsegs, flags) * bus-specific DMA memory free functions. */ void -_dmamem_free(t, segs, nsegs) - bus_dma_tag_t t; - bus_dma_segment_t *segs; - int nsegs; +_dmamem_free(bus_dma_tag_t t, bus_dma_segment_t *segs, int nsegs) { vm_page_t m; bus_addr_t addr; @@ -480,13 +432,8 @@ _dmamem_free(t, segs, nsegs) * bus-specific DMA memory map functions. */ int -_dmamem_map(t, segs, nsegs, size, kvap, flags) - bus_dma_tag_t t; - bus_dma_segment_t *segs; - int nsegs; - size_t size; - caddr_t *kvap; - int flags; +_dmamem_map(bus_dma_tag_t t, bus_dma_segment_t *segs, int nsegs, size_t size, + caddr_t *kvap, int flags) { vaddr_t va; paddr_t pa; @@ -540,10 +487,7 @@ _dmamem_map(t, segs, nsegs, size, kvap, flags) * bus-specific DMA memory unmapping functions. */ void -_dmamem_unmap(t, kva, size) - bus_dma_tag_t t; - caddr_t kva; - size_t size; +_dmamem_unmap(bus_dma_tag_t t, caddr_t kva, size_t size) { if (IS_XKPHYS((vaddr_t)kva)) return; @@ -559,12 +503,8 @@ _dmamem_unmap(t, kva, size) * bus-specific DMA mmap(2)'ing functions. */ paddr_t -_dmamem_mmap(t, segs, nsegs, off, prot, flags) - bus_dma_tag_t t; - bus_dma_segment_t *segs; - int nsegs; - off_t off; - int prot, flags; +_dmamem_mmap(bus_dma_tag_t t, bus_dma_segment_t *segs, int nsegs, off_t off, + int prot, int flags) { int i; @@ -595,20 +535,111 @@ _dmamem_mmap(t, segs, nsegs, off, prot, flags) **********************************************************************/ /* + * Utility function to load a linear buffer. lastaddrp holds state + * between invocations (for multiple-buffer loads). segp contains + * the starting segment on entrance, and the ending segment on exit. + * first indicates if this is the first invocation of this function. + */ +int +_dmamap_load_buffer(bus_dma_tag_t t, bus_dmamap_t map, void *buf, + bus_size_t buflen, struct proc *p, int flags, paddr_t *lastaddrp, + int *segp, int first) +{ + bus_size_t sgsize; + bus_addr_t lastaddr, baddr, bmask; + paddr_t curaddr; + vaddr_t vaddr = (vaddr_t)buf; + int seg; + pmap_t pmap; + + if (p != NULL) + pmap = p->p_vmspace->vm_map.pmap; + else + pmap = pmap_kernel(); + + lastaddr = *lastaddrp; + bmask = ~(map->_dm_boundary - 1); + if (t->_dma_mask != 0) + bmask &= t->_dma_mask; + + for (seg = *segp; buflen > 0; ) { + /* + * Get the physical address for this segment. + */ + if (pmap_extract(pmap, vaddr, &curaddr) == FALSE) + panic("_dmapmap_load_buffer: pmap_extract(%x, %x) failed!", + pmap, vaddr); + + /* + * Compute the segment size, and adjust counts. + */ + sgsize = NBPG - ((u_long)vaddr & PGOFSET); + if (buflen < sgsize) + sgsize = buflen; + + /* + * Make sure we don't cross any boundaries. + */ + if (map->_dm_boundary > 0) { + baddr = ((bus_addr_t)curaddr + map->_dm_boundary) & + bmask; + if (sgsize > (baddr - (bus_addr_t)curaddr)) + sgsize = (baddr - (bus_addr_t)curaddr); + } + + /* + * Insert chunk into a segment, coalescing with + * previous segment if possible. + */ + if (first) { + map->dm_segs[seg].ds_addr = + (*t->_pa_to_device)(curaddr); + map->dm_segs[seg].ds_len = sgsize; + map->dm_segs[seg]._ds_vaddr = (vaddr_t)vaddr; + first = 0; + } else { + if ((bus_addr_t)curaddr == lastaddr && + (map->dm_segs[seg].ds_len + sgsize) <= + map->_dm_maxsegsz && + (map->_dm_boundary == 0 || + (map->dm_segs[seg].ds_addr & bmask) == + ((bus_addr_t)curaddr & bmask))) + map->dm_segs[seg].ds_len += sgsize; + else { + if (++seg >= map->_dm_segcnt) + break; + map->dm_segs[seg].ds_addr = + (*t->_pa_to_device)(curaddr); + map->dm_segs[seg].ds_len = sgsize; + map->dm_segs[seg]._ds_vaddr = (vaddr_t)vaddr; + } + } + + lastaddr = (bus_addr_t)curaddr + sgsize; + vaddr += sgsize; + buflen -= sgsize; + } + + *segp = seg; + *lastaddrp = lastaddr; + + /* + * Did we fit? + */ + if (buflen != 0) + return (EFBIG); /* XXX better return value here? */ + + return (0); +} + +/* * Allocate physical memory from the given physical address range. * Called by DMA-safe memory allocation methods. */ int -_dmamem_alloc_range(t, size, alignment, boundary, segs, nsegs, rsegs, - flags, low, high) - bus_dma_tag_t t; - bus_size_t size, alignment, boundary; - bus_dma_segment_t *segs; - int nsegs; - int *rsegs; - int flags; - vaddr_t low; - vaddr_t high; +_dmamem_alloc_range(bus_dma_tag_t t, bus_size_t size, bus_size_t alignment, + bus_size_t boundary, bus_dma_segment_t *segs, int nsegs, int *rsegs, + int flags, vaddr_t low, vaddr_t high) { vaddr_t curaddr, lastaddr; vm_page_t m; diff --git a/sys/arch/sgi/xbow/xbridge.c b/sys/arch/sgi/xbow/xbridge.c index da6ba7e3e63..d1c65e0552f 100644 --- a/sys/arch/sgi/xbow/xbridge.c +++ b/sys/arch/sgi/xbow/xbridge.c @@ -1,4 +1,4 @@ -/* $OpenBSD: xbridge.c,v 1.36 2009/07/17 07:14:00 miod Exp $ */ +/* $OpenBSD: xbridge.c,v 1.37 2009/07/17 18:06:51 miod Exp $ */ /* * Copyright (c) 2008, 2009 Miodrag Vallat. @@ -154,11 +154,8 @@ int xbridge_space_map_io(bus_space_tag_t, bus_addr_t, bus_size_t, int, int xbridge_space_map_mem(bus_space_tag_t, bus_addr_t, bus_size_t, int, bus_space_handle_t *); -int xbridge_dmamap_load(bus_dma_tag_t, bus_dmamap_t, void *, bus_size_t, - struct proc *, int); -int xbridge_dmamap_load_mbuf(bus_dma_tag_t, bus_dmamap_t, struct mbuf *, - int); -int xbridge_dmamap_load_uio(bus_dma_tag_t, bus_dmamap_t, struct uio *, int); +int xbridge_dmamap_load_buffer(bus_dma_tag_t, bus_dmamap_t, void *, + bus_size_t, struct proc *, int, paddr_t *, int *, int); void xbridge_dmamap_unload(bus_dma_tag_t, bus_dmamap_t); int xbridge_dmamem_alloc(bus_dma_tag_t, bus_size_t, bus_size_t, bus_size_t, bus_dma_segment_t *, int, int *, int); @@ -195,10 +192,11 @@ const struct machine_bus_dma_tag xbridge_dma_tag = { NULL, /* _cookie */ _dmamap_create, _dmamap_destroy, - xbridge_dmamap_load, - xbridge_dmamap_load_mbuf, - xbridge_dmamap_load_uio, + _dmamap_load, + _dmamap_load_mbuf, + _dmamap_load_uio, _dmamap_load_raw, + xbridge_dmamap_load_buffer, xbridge_dmamap_unload, _dmamap_sync, xbridge_dmamem_alloc, @@ -1351,49 +1349,43 @@ xbridge_address_unmap(struct xbridge_softc *sc, bus_addr_t ba, bus_size_t len) } /* - * bus_dmamap_load() implementation. + * bus_dmamap_loadXXX() bowels implementation. */ int -xbridge_dmamap_load(bus_dma_tag_t t, bus_dmamap_t map, void *buf, - bus_size_t buflen, struct proc *p, int flags) +xbridge_dmamap_load_buffer(bus_dma_tag_t t, bus_dmamap_t map, void *buf, + bus_size_t buflen, struct proc *p, int flags, paddr_t *lastaddrp, + int *segp, int first) { struct xbridge_softc *sc = t->_cookie; - paddr_t pa; - bus_addr_t lastaddr, busaddr, endaddr; bus_size_t sgsize; - bus_addr_t baddr, bmask; - caddr_t vaddr = buf; - int first, seg; + bus_addr_t lastaddr, baddr, bmask; + bus_addr_t busaddr, endaddr; + paddr_t pa; + vaddr_t vaddr = (vaddr_t)buf; + int seg; pmap_t pmap; - bus_size_t saved_buflen; int rc; - /* - * Make sure that on error condition we return "no valid mappings". - */ - map->dm_nsegs = 0; - map->dm_mapsize = 0; - for (seg = 0; seg < map->_dm_segcnt; seg++) - map->dm_segs[seg].ds_addr = 0; - - if (buflen > map->_dm_size) - return EINVAL; + if (first) { + for (seg = 0; seg < map->_dm_segcnt; seg++) + map->dm_segs[seg].ds_addr = 0; + } if (p != NULL) pmap = p->p_vmspace->vm_map.pmap; else pmap = pmap_kernel(); + lastaddr = *lastaddrp; bmask = ~(map->_dm_boundary - 1); if (t->_dma_mask != 0) bmask &= t->_dma_mask; - saved_buflen = buflen; - for (first = 1, seg = 0; buflen > 0; ) { + for (seg = *segp; buflen > 0; ) { /* * Get the physical address for this segment. */ - if (pmap_extract(pmap, (vaddr_t)vaddr, &pa) == FALSE) + if (pmap_extract(pmap, vaddr, &pa) == FALSE) panic("%s: pmap_extract(%x, %x) failed", __func__, pmap, vaddr); @@ -1461,6 +1453,9 @@ xbridge_dmamap_load(bus_dma_tag_t t, bus_dmamap_t map, void *buf, buflen -= sgsize; } + *segp = seg; + *lastaddrp = lastaddr; + /* * Did we fit? */ @@ -1469,8 +1464,6 @@ xbridge_dmamap_load(bus_dma_tag_t t, bus_dmamap_t map, void *buf, goto fail_unmap; } - map->dm_nsegs = seg + 1; - map->dm_mapsize = saved_buflen; return 0; fail_unmap: @@ -1487,112 +1480,6 @@ fail_unmap: } /* - * bus_dmamap_load_mbuf() implementation. - */ -int -xbridge_dmamap_load_mbuf(bus_dma_tag_t t, bus_dmamap_t map, struct mbuf *m, - int flags) -{ - struct xbridge_softc *sc = t->_cookie; - bus_addr_t lastaddr, busaddr, endaddr; - bus_size_t sgsize; - paddr_t pa; - vaddr_t lastva; - int seg; - size_t len; - int rc; - - map->dm_nsegs = 0; - map->dm_mapsize = 0; - for (seg = 0; seg < map->_dm_segcnt; seg++) - map->dm_segs[seg].ds_addr = 0; - - seg = 0; - len = 0; - while (m != NULL) { - vaddr_t vaddr = mtod(m, vaddr_t); - long buflen = (long)m->m_len; - - len += buflen; - while (buflen > 0 && seg < map->_dm_segcnt) { - if (pmap_extract(pmap_kernel(), vaddr, &pa) == FALSE) - panic("%s: pmap_extract(%x, %x) failed", - __func__, pmap_kernel(), vaddr); - - /* - * Compute the DMA address and the physical range - * this mapping can cover. - */ - if (xbridge_address_map(sc, pa, &busaddr, - &endaddr) != 0) { - rc = ENOMEM; - goto fail_unmap; - } - - sgsize = PAGE_SIZE - ((u_long)vaddr & PGOFSET); - sgsize = min(buflen, sgsize); - sgsize = min(endaddr - busaddr, sgsize); - - /* - * Try to coalesce with previous entry. - * We need both the physical addresses and - * the virtual address to be contiguous, for - * bus_dmamap_sync() to behave correctly. - */ - if (seg > 0 && - busaddr == lastaddr && vaddr == lastva && - (map->dm_segs[seg - 1].ds_len + sgsize <= - map->_dm_maxsegsz)) - map->dm_segs[seg - 1].ds_len += sgsize; - else { - map->dm_segs[seg].ds_addr = busaddr; - map->dm_segs[seg].ds_len = sgsize; - map->dm_segs[seg]._ds_vaddr = vaddr; - seg++; - } - - lastaddr = busaddr + sgsize; - if (lastaddr == endaddr) - lastaddr = ~0; /* can't coalesce */ - vaddr += sgsize; - lastva = vaddr; - buflen -= sgsize; - } - m = m->m_next; - if (m && seg >= map->_dm_segcnt) { - /* Exceeded the size of our dmamap */ - rc = EFBIG; - goto fail_unmap; - } - } - map->dm_nsegs = seg; - map->dm_mapsize = len; - return 0; - -fail_unmap: - /* - * If control goes there, we need to unref all our ATE, if any. - */ - for (seg = 0; seg < map->_dm_segcnt; seg++) { - xbridge_address_unmap(sc, map->dm_segs[seg].ds_addr, - map->dm_segs[seg].ds_len); - map->dm_segs[seg].ds_addr = 0; - } - - return rc; -} - -/* - * bus_dmamap_load_uio() non-implementation. - */ -int -xbridge_dmamap_load_uio(bus_dma_tag_t t, bus_dmamap_t map, struct uio *uio, - int flags) -{ - return EOPNOTSUPP; -} - -/* * bus_dmamap_unload() implementation. */ void |