diff options
author | Jason Wright <jason@cvs.openbsd.org> | 2001-12-12 19:18:24 +0000 |
---|---|---|
committer | Jason Wright <jason@cvs.openbsd.org> | 2001-12-12 19:18:24 +0000 |
commit | 018ee021078abdaf33a0e4d21a39e9064a3236fe (patch) | |
tree | 7e23ac3ceb99b697f8ee19cde15fc369e246b002 /sys/arch/macppc | |
parent | d5e6e059f60c76132da18a9bd58d384f0a204529 (diff) |
Full suite of bus_dma functions (except bus_dmamap_load_raw)... this allows
the crypto layer and drivers using bus_dmamap_load_mbuf() to work (tested
with hifn and dc); Mostly from NetBSD
Diffstat (limited to 'sys/arch/macppc')
-rw-r--r-- | sys/arch/macppc/macppc/dma.c | 176 |
1 files changed, 137 insertions, 39 deletions
diff --git a/sys/arch/macppc/macppc/dma.c b/sys/arch/macppc/macppc/dma.c index 05692de52e6..5c27994b736 100644 --- a/sys/arch/macppc/macppc/dma.c +++ b/sys/arch/macppc/macppc/dma.c @@ -1,4 +1,4 @@ -/* $OpenBSD: dma.c,v 1.8 2001/12/08 02:24:06 art Exp $ */ +/* $OpenBSD: dma.c,v 1.9 2001/12/12 19:18:23 jason Exp $ */ /* $NetBSD: machdep.c,v 1.214 1996/11/10 03:16:17 thorpej Exp $ */ /*- @@ -122,49 +122,38 @@ _dmamap_destroy(t, map) free(map, M_DEVBUF); } -/* - * Common function for loading a DMA map with a linear buffer. May - * be called by bus-specific DMA map load functions. - */ +int _dmamap_load_buffer __P((bus_dma_tag_t, bus_dmamap_t, void *, bus_size_t, + struct proc *, int, paddr_t *, int *, int)); + int -_dmamap_load(t, map, buf, buflen, p, flags) +_dmamap_load_buffer(t, map, buf, buflen, p, flags, lastaddrp, segp, first) 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 curaddr, lastaddr, baddr, bmask; - caddr_t vaddr = buf; - int first, seg; - pmap_t pmap; - bus_size_t saved_buflen; + vaddr_t vaddr = (vaddr_t)buf; + int seg; - /* - * Make sure that on error condition we return "no valid mappings". - */ - map->dm_nsegs = 0; - map->dm_mapsize = 0; - - if (buflen > map->_dm_size) - return (EINVAL); - - if (p != NULL) - pmap = p->p_vmspace->vm_map.pmap; - else - pmap = pmap_kernel(); + lastaddr = *lastaddrp; + bmask = ~(map->_dm_boundary - 1); - lastaddr = ~0; /* XXX gcc */ - bmask = ~(map->_dm_boundary - 1); - - saved_buflen = buflen; - for (first = 1, seg = 0; buflen > 0; ) { + for (seg = *segp; buflen > 0; ) { /* * Get the physical address for this segment. */ - pmap_extract(pmap, (vm_offset_t)vaddr, (paddr_t *)&curaddr); + if (p != NULL) + (void) pmap_extract(p->p_vmspace->vm_map.pmap, + vaddr, (paddr_t *)&curaddr); + else + curaddr = vtophys(vaddr); /* * Compute the segment size, and adjust counts. @@ -183,7 +172,7 @@ _dmamap_load(t, map, buf, buflen, p, flags) } /* - * Insert chunk into a segment, coalescing with + * Insert chunk into a segment, coalescing with the * previous segment if possible. */ if (first) { @@ -194,7 +183,7 @@ _dmamap_load(t, map, buf, buflen, p, flags) if (curaddr == lastaddr && (map->dm_segs[seg].ds_len + sgsize) <= map->_dm_maxsegsz && - (map->_dm_boundary == 0 || + (map->_dm_boundary == 0 || (map->dm_segs[seg].ds_addr & bmask) == (curaddr & bmask))) map->dm_segs[seg].ds_len += sgsize; @@ -211,29 +200,94 @@ _dmamap_load(t, map, buf, buflen, p, flags) buflen -= sgsize; } + *segp = seg; + *lastaddrp = lastaddr; + /* * Did we fit? */ if (buflen != 0) - return (EFBIG); /* XXX better return value here? */ + return (EFBIG); /* XX better return value here? */ - map->dm_nsegs = seg + 1; - map->dm_mapsize = saved_buflen; return (0); } /* + * Common function for loading a DMA map with a linear buffer. May + * 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; +{ + paddr_t lastaddr; + int seg, error; + + /* + * Make sure that on error condition we return "no valid mappings". + */ + map->dm_mapsize = 0; + map->dm_nsegs = 0; + + if (buflen > map->_dm_size) + return (EINVAL); + + seg = 0; + error = _dmamap_load_buffer(t, map, buf, buflen, p, flags, + &lastaddr, &seg, 1); + if (error == 0) { + map->dm_mapsize = buflen; + map->dm_nsegs = seg + 1; + } + return (error); +} + +/* * Like _bus_dmamap_load(), but for mbufs. */ int -_dmamap_load_mbuf(t, map, m, flags) +_dmamap_load_mbuf(t, map, m0, flags) bus_dma_tag_t t; bus_dmamap_t map; - struct mbuf *m; + struct mbuf *m0; int flags; { + paddr_t lastaddr; + int seg, error, first; + struct mbuf *m; - panic("_bus_dmamap_load: not implemented"); + /* + * Make sure that on error condition we return "no valid mappings". + */ + map->dm_mapsize = 0; + map->dm_nsegs = 0; + +#ifdef DIAGNOSTIC + if ((m0->m_flags & M_PKTHDR) == 0) + panic("_bus_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) { + error = _dmamap_load_buffer(t, map, m->m_data, m->m_len, + NULL, flags, &lastaddr, &seg, first); + first = 0; + } + if (error == 0) { + map->dm_mapsize = m0->m_pkthdr.len; + map->dm_nsegs = seg + 1; + } + return (error); } /* @@ -246,8 +300,52 @@ _dmamap_load_uio(t, map, uio, flags) struct uio *uio; int flags; { - /* XXX Need a real implementation. */ - return (EOPNOTSUPP); + paddr_t lastaddr; + int seg, i, error, first; + bus_size_t minlen, resid; + struct proc *p = NULL; + struct iovec *iov; + caddr_t addr; + + /* + * Make sure that on error condition we return "no valid mappings". + */ + map->dm_mapsize = 0; + map->dm_nsegs = 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("_bus_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 = (caddr_t)iov[i].iov_base; + + error = _dmamap_load_buffer(t, map, addr, minlen, + p, flags, &lastaddr, &seg, first); + first = 0; + + resid -= minlen; + } + if (error == 0) { + map->dm_mapsize = uio->uio_resid; + map->dm_nsegs = seg + 1; + } + return (error); } /* |