busdma_machdep.c revision 109935
178342Sbenno/*
299657Sbenno * Copyright (c) 2002 Peter Grehan
399657Sbenno * Copyright (c) 1997, 1998 Justin T. Gibbs.
478342Sbenno * All rights reserved.
578342Sbenno *
678342Sbenno * Redistribution and use in source and binary forms, with or without
778342Sbenno * modification, are permitted provided that the following conditions
878342Sbenno * are met:
978342Sbenno * 1. Redistributions of source code must retain the above copyright
1099657Sbenno *    notice, this list of conditions, and the following disclaimer,
1199657Sbenno *    without modification, immediately at the beginning of the file.
1299657Sbenno * 2. The name of the author may not be used to endorse or promote products
1399657Sbenno *    derived from this software without specific prior written permission.
1478342Sbenno *
1599657Sbenno * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
1699657Sbenno * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1799657Sbenno * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1899657Sbenno * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
1999657Sbenno * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2099657Sbenno * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2199657Sbenno * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2299657Sbenno * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2399657Sbenno * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2499657Sbenno * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2599657Sbenno * SUCH DAMAGE.
2699657Sbenno *
2799657Sbenno *   From i386/busdma_machdep.c,v 1.26 2002/04/19 22:58:09 alfred
2878342Sbenno */
2978342Sbenno
3078342Sbenno#ifndef lint
3178342Sbennostatic const char rcsid[] =
3278342Sbenno  "$FreeBSD: head/sys/powerpc/powerpc/busdma_machdep.c 109935 2003-01-27 12:59:52Z benno $";
3378342Sbenno#endif /* not lint */
3478342Sbenno
3599657Sbenno/*
3699657Sbenno * MacPPC bus dma support routines
3799657Sbenno */
3878342Sbenno
3999657Sbenno#include <sys/param.h>
4099657Sbenno#include <sys/systm.h>
4199657Sbenno#include <sys/malloc.h>
4299657Sbenno#include <sys/bus.h>
4399657Sbenno#include <sys/interrupt.h>
4499657Sbenno#include <sys/lock.h>
4599657Sbenno#include <sys/proc.h>
4699657Sbenno#include <sys/mutex.h>
47108939Sgrehan#include <sys/mbuf.h>
48108939Sgrehan#include <sys/uio.h>
4999657Sbenno
5099657Sbenno#include <vm/vm.h>
5199657Sbenno#include <vm/vm_page.h>
52108939Sgrehan#include <vm/vm_map.h>
5399657Sbenno
5499657Sbenno#include <machine/bus.h>
55109919Sbenno#include <machine/cpufunc.h>
5699657Sbenno
5799657Sbennostruct bus_dma_tag {
5899657Sbenno	bus_dma_tag_t     parent;
5999657Sbenno	bus_size_t        alignment;
6099657Sbenno	bus_size_t        boundary;
6199657Sbenno	bus_addr_t        lowaddr;
6299657Sbenno	bus_addr_t        highaddr;
6399657Sbenno	bus_dma_filter_t *filter;
6499657Sbenno	void             *filterarg;
6599657Sbenno	bus_size_t        maxsize;
6699657Sbenno	u_int             nsegments;
6799657Sbenno	bus_size_t        maxsegsz;
6899657Sbenno	int               flags;
6999657Sbenno	int               ref_count;
7099657Sbenno	int               map_count;
7199657Sbenno};
7299657Sbenno
7399657Sbennostruct bus_dmamap {
7499657Sbenno        bus_dma_tag_t          dmat;
7599657Sbenno        void                  *buf;             /* unmapped buffer pointer */
7699657Sbenno        bus_size_t             buflen;          /* unmapped buffer length */
7799657Sbenno        bus_dmamap_callback_t *callback;
7899657Sbenno        void                  *callback_arg;
7999657Sbenno};
8099657Sbenno
8199657Sbenno/*
8299657Sbenno * Allocate a device specific dma_tag.
8399657Sbenno */
8499657Sbennoint
8599657Sbennobus_dma_tag_create(bus_dma_tag_t parent, bus_size_t alignment,
8699657Sbenno		   bus_size_t boundary, bus_addr_t lowaddr,
8799657Sbenno		   bus_addr_t highaddr, bus_dma_filter_t *filter,
8899657Sbenno		   void *filterarg, bus_size_t maxsize, int nsegments,
8999657Sbenno		   bus_size_t maxsegsz, int flags, bus_dma_tag_t *dmat)
9099657Sbenno{
9199657Sbenno	bus_dma_tag_t newtag;
9299657Sbenno	int error = 0;
9399657Sbenno
9499657Sbenno	/* Return a NULL tag on failure */
9599657Sbenno	*dmat = NULL;
9699657Sbenno
9799657Sbenno	newtag = (bus_dma_tag_t)malloc(sizeof(*newtag), M_DEVBUF, M_NOWAIT);
9899657Sbenno	if (newtag == NULL)
9999657Sbenno		return (ENOMEM);
10099657Sbenno
10199657Sbenno	newtag->parent = parent;
10299657Sbenno	newtag->alignment = alignment;
10399657Sbenno	newtag->boundary = boundary;
10499657Sbenno	newtag->lowaddr = trunc_page((vm_offset_t)lowaddr) + (PAGE_SIZE - 1);
10599657Sbenno	newtag->highaddr = trunc_page((vm_offset_t)highaddr) + (PAGE_SIZE - 1);
10699657Sbenno	newtag->filter = filter;
10799657Sbenno	newtag->filterarg = filterarg;
10899657Sbenno        newtag->maxsize = maxsize;
10999657Sbenno        newtag->nsegments = nsegments;
11099657Sbenno	newtag->maxsegsz = maxsegsz;
11199657Sbenno	newtag->flags = flags;
11299657Sbenno	newtag->ref_count = 1; /* Count ourself */
11399657Sbenno	newtag->map_count = 0;
11499657Sbenno
11599657Sbenno        /*
11699657Sbenno	 * Take into account any restrictions imposed by our parent tag
11799657Sbenno	 */
11899657Sbenno        if (parent != NULL) {
11999657Sbenno                newtag->lowaddr = min(parent->lowaddr, newtag->lowaddr);
12099657Sbenno                newtag->highaddr = max(parent->highaddr, newtag->highaddr);
12199657Sbenno
12299657Sbenno                /*
12399657Sbenno                 * XXX Not really correct??? Probably need to honor boundary
12499657Sbenno                 *     all the way up the inheritence chain.
12599657Sbenno                 */
12699657Sbenno                newtag->boundary = max(parent->boundary, newtag->boundary);
12799657Sbenno                if (newtag->filter == NULL) {
12899657Sbenno                        /*
12999657Sbenno                         * Short circuit looking at our parent directly
13099657Sbenno                         * since we have encapsulated all of its information
13199657Sbenno                         */
13299657Sbenno                        newtag->filter = parent->filter;
13399657Sbenno                        newtag->filterarg = parent->filterarg;
13499657Sbenno                        newtag->parent = parent->parent;
13599657Sbenno		}
13699657Sbenno                if (newtag->parent != NULL) {
13799657Sbenno                        parent->ref_count++;
13899657Sbenno		}
13999657Sbenno	}
14099657Sbenno
14199657Sbenno	*dmat = newtag;
14299657Sbenno	return (error);
14399657Sbenno}
14499657Sbenno
14599657Sbennoint
14699657Sbennobus_dma_tag_destroy(bus_dma_tag_t dmat)
14799657Sbenno{
14899657Sbenno	if (dmat != NULL) {
14999657Sbenno
15099657Sbenno                if (dmat->map_count != 0)
15199657Sbenno                        return (EBUSY);
15299657Sbenno
15399657Sbenno                while (dmat != NULL) {
15499657Sbenno                        bus_dma_tag_t parent;
15599657Sbenno
15699657Sbenno                        parent = dmat->parent;
15799657Sbenno                        dmat->ref_count--;
15899657Sbenno                        if (dmat->ref_count == 0) {
15999657Sbenno                                free(dmat, M_DEVBUF);
16099657Sbenno                                /*
16199657Sbenno                                 * Last reference count, so
16299657Sbenno                                 * release our reference
16399657Sbenno                                 * count on our parent.
16499657Sbenno                                 */
16599657Sbenno                                dmat = parent;
16699657Sbenno                        } else
16799657Sbenno                                dmat = NULL;
16899657Sbenno                }
16999657Sbenno        }
17099657Sbenno        return (0);
17199657Sbenno}
17299657Sbenno
17399657Sbenno/*
17499657Sbenno * Allocate a handle for mapping from kva/uva/physical
17599657Sbenno * address space into bus device space.
17699657Sbenno */
17799657Sbennoint
17899657Sbennobus_dmamap_create(bus_dma_tag_t dmat, int flags, bus_dmamap_t *mapp)
17999657Sbenno{
18099657Sbenno	*mapp = NULL;
18199657Sbenno	dmat->map_count++;
18299657Sbenno
18399657Sbenno	return (0);
18499657Sbenno}
18599657Sbenno
18699657Sbenno/*
18799657Sbenno * Destroy a handle for mapping from kva/uva/physical
18899657Sbenno * address space into bus device space.
18999657Sbenno */
19099657Sbennoint
19199657Sbennobus_dmamap_destroy(bus_dma_tag_t dmat, bus_dmamap_t map)
19299657Sbenno{
19399657Sbenno        if (map != NULL) {
19499657Sbenno		panic("dmamap_destroy: NULL?\n");
19599657Sbenno        }
19699657Sbenno        dmat->map_count--;
19799657Sbenno        return (0);
19899657Sbenno}
19999657Sbenno
20099657Sbenno/*
20199657Sbenno * Allocate a piece of memory that can be efficiently mapped into
20299657Sbenno * bus device space based on the constraints lited in the dma tag.
20399657Sbenno * A dmamap to for use with dmamap_load is also allocated.
20499657Sbenno */
20599657Sbennoint
20699657Sbennobus_dmamem_alloc(bus_dma_tag_t dmat, void** vaddr, int flags,
20799657Sbenno                 bus_dmamap_t *mapp)
20899657Sbenno{
20999657Sbenno        *mapp = NULL;
21099657Sbenno
21199657Sbenno        if (dmat->maxsize <= PAGE_SIZE) {
21299657Sbenno                *vaddr = malloc(dmat->maxsize, M_DEVBUF,
213109623Salfred                             (flags & BUS_DMA_NOWAIT) ? M_NOWAIT : 0);
21499657Sbenno        } else {
21599657Sbenno                /*
21699657Sbenno                 * XXX Use Contigmalloc until it is merged into this facility
21799657Sbenno                 *     and handles multi-seg allocations.  Nobody is doing
21899657Sbenno                 *     multi-seg allocations yet though.
21999657Sbenno                 */
22099657Sbenno                *vaddr = contigmalloc(dmat->maxsize, M_DEVBUF,
221109623Salfred                    (flags & BUS_DMA_NOWAIT) ? M_NOWAIT : 0,
22299657Sbenno                    0ul, dmat->lowaddr, dmat->alignment? dmat->alignment : 1ul,
22399657Sbenno                    dmat->boundary);
22499657Sbenno        }
22599657Sbenno
22699657Sbenno        if (*vaddr == NULL)
22799657Sbenno                return (ENOMEM);
22899657Sbenno
22999657Sbenno        return (0);
23099657Sbenno}
23199657Sbenno
23299657Sbenno/*
233108939Sgrehan * Free a piece of memory and it's allocated dmamap, that was allocated
23499657Sbenno * via bus_dmamem_alloc.  Make the same choice for free/contigfree.
23599657Sbenno */
23678342Sbennovoid
23799657Sbennobus_dmamem_free(bus_dma_tag_t dmat, void *vaddr, bus_dmamap_t map)
23878342Sbenno{
23999657Sbenno        if (map != NULL)
24099657Sbenno                panic("bus_dmamem_free: Invalid map freed\n");
24199657Sbenno        if (dmat->maxsize <= PAGE_SIZE)
24299657Sbenno		free(vaddr, M_DEVBUF);
24399657Sbenno        else
24499657Sbenno		contigfree(vaddr, dmat->maxsize, M_DEVBUF);
24599657Sbenno}
24678342Sbenno
24799657Sbenno/*
24899657Sbenno * Map the buffer buf into bus space using the dmamap map.
24999657Sbenno */
25099657Sbennoint
25199657Sbennobus_dmamap_load(bus_dma_tag_t dmat, bus_dmamap_t map, void *buf,
25299657Sbenno                bus_size_t buflen, bus_dmamap_callback_t *callback,
25399657Sbenno                void *callback_arg, int flags)
25499657Sbenno{
25599657Sbenno        vm_offset_t             vaddr;
25699657Sbenno        vm_offset_t             paddr;
25799657Sbenno#ifdef __GNUC__
25899657Sbenno        bus_dma_segment_t       dm_segments[dmat->nsegments];
25999657Sbenno#else
26099657Sbenno        bus_dma_segment_t       dm_segments[BUS_DMAMAP_NSEGS];
26199657Sbenno#endif
26299657Sbenno        bus_dma_segment_t      *sg;
26399657Sbenno        int                     seg;
26499657Sbenno        int                     error = 0;
26599657Sbenno        vm_offset_t             nextpaddr;
26699657Sbenno
26799657Sbenno        if (map != NULL)
26899657Sbenno		panic("bus_dmamap_load: Invalid map\n");
26999657Sbenno
27099657Sbenno        vaddr = (vm_offset_t)buf;
27199657Sbenno        sg = &dm_segments[0];
27299657Sbenno        seg = 1;
27399657Sbenno        sg->ds_len = 0;
27499657Sbenno        nextpaddr = 0;
27599657Sbenno
27699657Sbenno        do {
27799657Sbenno		bus_size_t      size;
27899657Sbenno
27999657Sbenno                paddr = pmap_kextract(vaddr);
28099657Sbenno                size = PAGE_SIZE - (paddr & PAGE_MASK);
28199657Sbenno                if (size > buflen)
28299657Sbenno                        size = buflen;
28399657Sbenno
28499657Sbenno                if (sg->ds_len == 0) {
28599657Sbenno                        sg->ds_addr = paddr;
28699657Sbenno                        sg->ds_len = size;
28799657Sbenno                } else if (paddr == nextpaddr) {
28899657Sbenno                        sg->ds_len += size;
28999657Sbenno                } else {
29099657Sbenno                        /* Go to the next segment */
29199657Sbenno                        sg++;
29299657Sbenno                        seg++;
29399657Sbenno                        if (seg > dmat->nsegments)
29499657Sbenno				break;
29599657Sbenno                        sg->ds_addr = paddr;
29699657Sbenno                        sg->ds_len = size;
29799657Sbenno                }
29899657Sbenno                vaddr += size;
29999657Sbenno                nextpaddr = paddr + size;
30099657Sbenno                buflen -= size;
301108939Sgrehan
302108939Sgrehan	} while (buflen > 0);
30399657Sbenno
304108939Sgrehan	if (buflen != 0) {
305108939Sgrehan		printf("bus_dmamap_load: Too many segs! buf_len = 0x%lx\n",
306108939Sgrehan		    (u_long)buflen);
307108939Sgrehan		error = EFBIG;
308108939Sgrehan	}
30999657Sbenno
310108939Sgrehan	(*callback)(callback_arg, dm_segments, seg, error);
31199657Sbenno
312108939Sgrehan	return (0);
31378342Sbenno}
31499657Sbenno
31599657Sbenno/*
316108939Sgrehan * Utility function to load a linear buffer.  lastaddrp holds state
317108939Sgrehan * between invocations (for multiple-buffer loads).  segp contains
318108939Sgrehan * the starting segment on entrance, and the ending segment on exit.
319108939Sgrehan * first indicates if this is the first invocation of this function.
32099657Sbenno */
321108939Sgrehanstatic int
322108939Sgrehanbus_dmamap_load_buffer(bus_dma_tag_t dmat, bus_dma_segment_t segs[],
323108939Sgrehan    void *buf, bus_size_t buflen, struct thread *td,
324108939Sgrehan    int flags, vm_offset_t *lastaddrp, int *segp,
325108939Sgrehan    int first)
326108939Sgrehan{
327108939Sgrehan	bus_size_t sgsize;
328108939Sgrehan	bus_addr_t curaddr, lastaddr, baddr, bmask;
329108939Sgrehan	vm_offset_t vaddr = (vm_offset_t)buf;
330108939Sgrehan	int seg;
331108939Sgrehan	pmap_t pmap;
332108939Sgrehan
333108939Sgrehan	if (td != NULL)
334108939Sgrehan		pmap = vmspace_pmap(td->td_proc->p_vmspace);
335108939Sgrehan	else
336108939Sgrehan		pmap = NULL;
337108939Sgrehan
338108939Sgrehan	lastaddr = *lastaddrp;
339108939Sgrehan	bmask = ~(dmat->boundary - 1);
340108939Sgrehan
341108939Sgrehan	for (seg = *segp; buflen > 0 ; ) {
342108939Sgrehan		/*
343108939Sgrehan		 * Get the physical address for this segment.
344108939Sgrehan		 */
345108939Sgrehan		if (pmap)
346108939Sgrehan			curaddr = pmap_extract(pmap, vaddr);
347108939Sgrehan		else
348108939Sgrehan			curaddr = pmap_kextract(vaddr);
349108939Sgrehan
350108939Sgrehan		/*
351108939Sgrehan		 * Compute the segment size, and adjust counts.
352108939Sgrehan		 */
353108939Sgrehan		sgsize = PAGE_SIZE - ((u_long)curaddr & PAGE_MASK);
354108939Sgrehan		if (buflen < sgsize)
355108939Sgrehan			sgsize = buflen;
356108939Sgrehan
357108939Sgrehan		/*
358108939Sgrehan		 * Make sure we don't cross any boundaries.
359108939Sgrehan		 */
360108939Sgrehan		if (dmat->boundary > 0) {
361108939Sgrehan			baddr = (curaddr + dmat->boundary) & bmask;
362108939Sgrehan			if (sgsize > (baddr - curaddr))
363108939Sgrehan				sgsize = (baddr - curaddr);
364108939Sgrehan		}
365108939Sgrehan
366108939Sgrehan		/*
367108939Sgrehan		 * Insert chunk into a segment, coalescing with
368108939Sgrehan		 * the previous segment if possible.
369108939Sgrehan		 */
370108939Sgrehan		if (first) {
371108939Sgrehan			segs[seg].ds_addr = curaddr;
372108939Sgrehan			segs[seg].ds_len = sgsize;
373108939Sgrehan			first = 0;
374108939Sgrehan		} else {
375108939Sgrehan			if (curaddr == lastaddr &&
376108939Sgrehan			    (segs[seg].ds_len + sgsize) <= dmat->maxsegsz &&
377108939Sgrehan			    (dmat->boundary == 0 ||
378108939Sgrehan			     (segs[seg].ds_addr & bmask) == (curaddr & bmask)))
379108939Sgrehan				segs[seg].ds_len += sgsize;
380108939Sgrehan			else {
381108939Sgrehan				if (++seg >= dmat->nsegments)
382108939Sgrehan					break;
383108939Sgrehan				segs[seg].ds_addr = curaddr;
384108939Sgrehan				segs[seg].ds_len = sgsize;
385108939Sgrehan			}
386108939Sgrehan		}
387108939Sgrehan
388108939Sgrehan		lastaddr = curaddr + sgsize;
389108939Sgrehan		vaddr += sgsize;
390108939Sgrehan		buflen -= sgsize;
391108939Sgrehan	}
392108939Sgrehan
393108939Sgrehan	*segp = seg;
394108939Sgrehan	*lastaddrp = lastaddr;
395108939Sgrehan
396108939Sgrehan	/*
397108939Sgrehan	 * Did we fit?
398108939Sgrehan	 */
399108939Sgrehan	return (buflen != 0 ? EFBIG : 0); /* XXX better return value here? */
400108939Sgrehan}
401108939Sgrehan
402108939Sgrehan/*
403108939Sgrehan * Like bus_dmamap_load(), but for mbufs.
404108939Sgrehan */
405108939Sgrehanint
406108939Sgrehanbus_dmamap_load_mbuf(bus_dma_tag_t dmat, bus_dmamap_t map, struct mbuf *m0,
407108939Sgrehan		     bus_dmamap_callback2_t *callback, void *callback_arg,
408108939Sgrehan		     int flags)
409108939Sgrehan{
410108939Sgrehan#ifdef __GNUC__
411108939Sgrehan	bus_dma_segment_t dm_segments[dmat->nsegments];
412108939Sgrehan#else
413108939Sgrehan	bus_dma_segment_t dm_segments[BUS_DMAMAP_NSEGS];
414108939Sgrehan#endif
415108939Sgrehan	int nsegs = 0, error = 0;
416108939Sgrehan
417108939Sgrehan	KASSERT(m0->m_flags & M_PKTHDR,
418108939Sgrehan	    ("bus_dmamap_load_mbuf: no packet header"));
419108939Sgrehan
420108939Sgrehan	if (m0->m_pkthdr.len <= dmat->maxsize) {
421108939Sgrehan		int first = 1;
422108939Sgrehan		vm_offset_t lastaddr = 0;
423108939Sgrehan		struct mbuf *m;
424108939Sgrehan
425108939Sgrehan		for (m = m0; m != NULL && error == 0; m = m->m_next) {
426108939Sgrehan			error = bus_dmamap_load_buffer(dmat, dm_segments,
427108939Sgrehan			    m->m_data, m->m_len, NULL, flags,
428108939Sgrehan			    &lastaddr, &nsegs, first);
429108939Sgrehan			first = 0;
430108939Sgrehan		}
431108939Sgrehan	} else {
432108939Sgrehan		error = EINVAL;
433108939Sgrehan	}
434108939Sgrehan
435108939Sgrehan	if (error) {
436108939Sgrehan		/*
437108939Sgrehan		 * force "no valid mappings" on error in callback.
438108939Sgrehan		 */
439108939Sgrehan		(*callback)(callback_arg, dm_segments, 0, 0, error);
440108939Sgrehan	} else {
441108939Sgrehan		(*callback)(callback_arg, dm_segments, nsegs+1,
442108939Sgrehan		    m0->m_pkthdr.len, error);
443108939Sgrehan	}
444108939Sgrehan	return (error);
445108939Sgrehan}
446108939Sgrehan
447108939Sgrehan/*
448108939Sgrehan * Like bus_dmamap_load(), but for uios.
449108939Sgrehan */
450108939Sgrehanint
451108939Sgrehanbus_dmamap_load_uio(bus_dma_tag_t dmat, bus_dmamap_t map, struct uio *uio,
452108939Sgrehan    bus_dmamap_callback2_t *callback, void *callback_arg,
453108939Sgrehan    int flags)
454108939Sgrehan{
455108939Sgrehan	vm_offset_t lastaddr;
456108939Sgrehan#ifdef __GNUC__
457108939Sgrehan	bus_dma_segment_t dm_segments[dmat->nsegments];
458108939Sgrehan#else
459108939Sgrehan	bus_dma_segment_t dm_segments[BUS_DMAMAP_NSEGS];
460108939Sgrehan#endif
461108939Sgrehan	int nsegs, i, error, first;
462108939Sgrehan	bus_size_t resid;
463108939Sgrehan	struct iovec *iov;
464108939Sgrehan	struct proc *td = NULL;
465108939Sgrehan
466108939Sgrehan	resid = uio->uio_resid;
467108939Sgrehan	iov = uio->uio_iov;
468108939Sgrehan
469108939Sgrehan	if (uio->uio_segflg == UIO_USERSPACE) {
470108939Sgrehan		td = uio->uio_td;
471108939Sgrehan		KASSERT(td != NULL,
472108939Sgrehan		    ("bus_dmamap_load_uio: USERSPACE but no proc"));
473108939Sgrehan	}
474108939Sgrehan
475108939Sgrehan	first = 1;
476108939Sgrehan	nsegs = error = 0;
477108939Sgrehan	for (i = 0; i < uio->uio_iovcnt && resid != 0 && !error; i++) {
478108939Sgrehan		/*
479108939Sgrehan		 * Now at the first iovec to load.  Load each iovec
480108939Sgrehan		 * until we have exhausted the residual count.
481108939Sgrehan		 */
482108939Sgrehan		bus_size_t minlen =
483108939Sgrehan		    resid < iov[i].iov_len ? resid : iov[i].iov_len;
484108939Sgrehan		caddr_t addr = (caddr_t) iov[i].iov_base;
485108939Sgrehan
486108939Sgrehan		error = bus_dmamap_load_buffer(dmat, dm_segments, addr,
487108939Sgrehan		    minlen, td, flags, &lastaddr, &nsegs, first);
488108939Sgrehan
489108939Sgrehan		first = 0;
490108939Sgrehan
491108939Sgrehan		resid -= minlen;
492108939Sgrehan	}
493108939Sgrehan
494108939Sgrehan	if (error) {
495108939Sgrehan		/*
496108939Sgrehan		 * force "no valid mappings" on error in callback.
497108939Sgrehan		 */
498108939Sgrehan		(*callback)(callback_arg, dm_segments, 0, 0, error);
499108939Sgrehan	} else {
500108939Sgrehan		(*callback)(callback_arg, dm_segments, nsegs+1,
501108939Sgrehan		    uio->uio_resid, error);
502108939Sgrehan	}
503108939Sgrehan
504108939Sgrehan	return (error);
505108939Sgrehan}
506108939Sgrehan
507108939Sgrehan/*
508108939Sgrehan * Release the mapping held by map. A no-op on PowerPC.
509108939Sgrehan */
51099657Sbennovoid
51199657Sbennobus_dmamap_unload(bus_dma_tag_t dmat, bus_dmamap_t map)
512109935Sbenno{
51399657Sbenno
514109935Sbenno	return;
515109935Sbenno}
516109935Sbenno
51799657Sbennovoid
51899657Sbennobus_dmamap_sync(bus_dma_tag_t dmat, bus_dmamap_t map, bus_dmasync_op_t op)
519109919Sbenno{
520109919Sbenno
521109935Sbenno	return;
522109919Sbenno}
523