diff options
author | Jason Wright <jason@cvs.openbsd.org> | 2001-05-08 18:19:45 +0000 |
---|---|---|
committer | Jason Wright <jason@cvs.openbsd.org> | 2001-05-08 18:19:45 +0000 |
commit | a3e0598e6d2ed14810f2d1fc8b9ed360ee7be8ec (patch) | |
tree | e41152c3afd0856fbb13a157ec858c787b225e0d /sys | |
parent | 862af5aef1600fc408b2a00a4c77587d2c918827 (diff) |
From netbsd: implementations of _bus_dmamap_load_mbuf() and
_bus_dmamap_load_uio().
Diffstat (limited to 'sys')
-rw-r--r-- | sys/arch/i386/i386/machdep.c | 259 | ||||
-rw-r--r-- | sys/arch/i386/include/bus.h | 3 |
2 files changed, 185 insertions, 77 deletions
diff --git a/sys/arch/i386/i386/machdep.c b/sys/arch/i386/i386/machdep.c index 2d06dc4c7d3..08bebc6137a 100644 --- a/sys/arch/i386/i386/machdep.c +++ b/sys/arch/i386/i386/machdep.c @@ -1,4 +1,4 @@ -/* $OpenBSD: machdep.c,v 1.159 2001/05/05 23:25:37 art Exp $ */ +/* $OpenBSD: machdep.c,v 1.160 2001/05/08 18:19:43 jason Exp $ */ /* $NetBSD: machdep.c,v 1.214 1996/11/10 03:16:17 thorpej Exp $ */ /*- @@ -281,6 +281,8 @@ void consinit __P((void)); int bus_mem_add_mapping __P((bus_addr_t, bus_size_t, int, bus_space_handle_t *)); +int _bus_dmamap_load_buffer __P((bus_dma_tag_t, bus_dmamap_t, void *, + bus_size_t, struct proc *, int, paddr_t *, int *, int)); #ifdef KGDB #ifndef KGDB_DEVNAME @@ -2850,101 +2852,69 @@ _bus_dmamap_load(t, map, buf, buflen, p, flags) struct proc *p; int flags; { - bus_size_t sgsize; - bus_addr_t curaddr, lastaddr, baddr, bmask; - vaddr_t vaddr = (vaddr_t)buf; - int first, seg; - pmap_t pmap; + bus_addr_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); - if (p != NULL) - pmap = p->p_vmspace->vm_map.pmap; - else - pmap = pmap_kernel(); - - lastaddr = ~0; /* XXX gcc */ - bmask = ~(map->_dm_boundary - 1); - - for (first = 1, seg = 0; buflen > 0; ) { - /* - * Get the physical address for this segment. - */ - curaddr = (bus_addr_t)pmap_extract(pmap, (vm_offset_t)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 = curaddr; - map->dm_segs[seg].ds_len = sgsize; - 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 = curaddr; - map->dm_segs[seg].ds_len = sgsize; - } - } - - lastaddr = curaddr + sgsize; - vaddr += sgsize; - buflen -= sgsize; + seg = 0; + error = _bus_dmamap_load_buffer(t, map, buf, buflen, p, flags, + &lastaddr, &seg, 1); + if (error == 0) { + map->dm_mapsize = buflen; + map->dm_nsegs = seg + 1; } - - /* - * Did we fit? - */ - if (buflen != 0) - return (EFBIG); /* XXX better return value here? */ - - map->dm_nsegs = seg + 1; - return (0); + return (error); } /* * Like _bus_dmamap_load(), but for mbufs. */ int -_bus_dmamap_load_mbuf(t, map, m, flags) +_bus_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; + + /* + * 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); - panic("_bus_dmamap_load: not implemented"); + first = 1; + seg = 1; + error = 0; + for (m = m0; m != NULL && error == 0; m = m->m_next) { + error = _bus_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); } /* @@ -2957,8 +2927,52 @@ _bus_dmamap_load_uio(t, map, uio, flags) struct uio *uio; int flags; { + 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; - panic("_bus_dmamap_load_uio: not implemented"); + error = _bus_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); } /* @@ -3154,6 +3168,99 @@ _bus_dmamem_mmap(t, segs, nsegs, off, prot, flags) /********************************************************************** * DMA utility functions **********************************************************************/ +/* + * Utility function to load a linear buffer. lastaddrp holds state + * between invocations (for multiple-buffer loads). segp contains + * the starting segment on entrace, and the ending segment on exit. + * first indicates if this is the first invocation of this function. + */ +int +_bus_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; + 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); + + for (seg = *segp; buflen > 0 ; ) { + /* + * Get the physical address for this segment. + */ + curaddr = (bus_addr_t)pmap_extract(pmap, (vm_offset_t)vaddr); + + /* + * Compute the segment size, and adjust counts. + */ + sgsize = PAGE_SIZE - ((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 = curaddr; + map->dm_segs[seg].ds_len = sgsize; + 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 = curaddr; + map->dm_segs[seg].ds_len = sgsize; + } + } + + lastaddr = 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. diff --git a/sys/arch/i386/include/bus.h b/sys/arch/i386/include/bus.h index 50aa7cd6452..d6a73c8b9bb 100644 --- a/sys/arch/i386/include/bus.h +++ b/sys/arch/i386/include/bus.h @@ -1,4 +1,4 @@ -/* $OpenBSD: bus.h,v 1.27 2001/02/06 23:13:31 mickey Exp $ */ +/* $OpenBSD: bus.h,v 1.28 2001/05/08 18:19:44 jason Exp $ */ /* $NetBSD: bus.h,v 1.6 1996/11/10 03:19:25 thorpej Exp $ */ /*- @@ -891,6 +891,7 @@ struct i386_bus_dmamap { /* * PUBLIC MEMBERS: these are used by machine-independent code. */ + bus_size_t dm_mapsize; /* size of the mapping */ int dm_nsegs; /* # valid segments in mapping */ bus_dma_segment_t dm_segs[1]; /* segments; variable length */ }; |