busdma_machdep.c revision 112196
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 112196 2003-03-13 17:18:48Z mux $"; 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, 213111119Simp (flags & BUS_DMA_NOWAIT) ? M_NOWAIT : M_WAITOK); 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 */ 220112196Smux mtx_lock(&Giant); 22199657Sbenno *vaddr = contigmalloc(dmat->maxsize, M_DEVBUF, 222111119Simp (flags & BUS_DMA_NOWAIT) ? M_NOWAIT : M_WAITOK, 22399657Sbenno 0ul, dmat->lowaddr, dmat->alignment? dmat->alignment : 1ul, 22499657Sbenno dmat->boundary); 225112196Smux mtx_unlock(&Giant); 22699657Sbenno } 22799657Sbenno 22899657Sbenno if (*vaddr == NULL) 22999657Sbenno return (ENOMEM); 23099657Sbenno 23199657Sbenno return (0); 23299657Sbenno} 23399657Sbenno 23499657Sbenno/* 235108939Sgrehan * Free a piece of memory and it's allocated dmamap, that was allocated 23699657Sbenno * via bus_dmamem_alloc. Make the same choice for free/contigfree. 23799657Sbenno */ 23878342Sbennovoid 23999657Sbennobus_dmamem_free(bus_dma_tag_t dmat, void *vaddr, bus_dmamap_t map) 24078342Sbenno{ 24199657Sbenno if (map != NULL) 24299657Sbenno panic("bus_dmamem_free: Invalid map freed\n"); 24399657Sbenno if (dmat->maxsize <= PAGE_SIZE) 24499657Sbenno free(vaddr, M_DEVBUF); 245112196Smux else { 246112196Smux mtx_lock(&Giant); 24799657Sbenno contigfree(vaddr, dmat->maxsize, M_DEVBUF); 248112196Smux mtx_unlock(&Giant); 249112196Smux } 25099657Sbenno} 25178342Sbenno 25299657Sbenno/* 25399657Sbenno * Map the buffer buf into bus space using the dmamap map. 25499657Sbenno */ 25599657Sbennoint 25699657Sbennobus_dmamap_load(bus_dma_tag_t dmat, bus_dmamap_t map, void *buf, 25799657Sbenno bus_size_t buflen, bus_dmamap_callback_t *callback, 25899657Sbenno void *callback_arg, int flags) 25999657Sbenno{ 26099657Sbenno vm_offset_t vaddr; 26199657Sbenno vm_offset_t paddr; 26299657Sbenno#ifdef __GNUC__ 26399657Sbenno bus_dma_segment_t dm_segments[dmat->nsegments]; 26499657Sbenno#else 26599657Sbenno bus_dma_segment_t dm_segments[BUS_DMAMAP_NSEGS]; 26699657Sbenno#endif 26799657Sbenno bus_dma_segment_t *sg; 26899657Sbenno int seg; 26999657Sbenno int error = 0; 27099657Sbenno vm_offset_t nextpaddr; 27199657Sbenno 27299657Sbenno if (map != NULL) 27399657Sbenno panic("bus_dmamap_load: Invalid map\n"); 27499657Sbenno 27599657Sbenno vaddr = (vm_offset_t)buf; 27699657Sbenno sg = &dm_segments[0]; 27799657Sbenno seg = 1; 27899657Sbenno sg->ds_len = 0; 27999657Sbenno nextpaddr = 0; 28099657Sbenno 28199657Sbenno do { 28299657Sbenno bus_size_t size; 28399657Sbenno 28499657Sbenno paddr = pmap_kextract(vaddr); 28599657Sbenno size = PAGE_SIZE - (paddr & PAGE_MASK); 28699657Sbenno if (size > buflen) 28799657Sbenno size = buflen; 28899657Sbenno 28999657Sbenno if (sg->ds_len == 0) { 29099657Sbenno sg->ds_addr = paddr; 29199657Sbenno sg->ds_len = size; 29299657Sbenno } else if (paddr == nextpaddr) { 29399657Sbenno sg->ds_len += size; 29499657Sbenno } else { 29599657Sbenno /* Go to the next segment */ 29699657Sbenno sg++; 29799657Sbenno seg++; 29899657Sbenno if (seg > dmat->nsegments) 29999657Sbenno break; 30099657Sbenno sg->ds_addr = paddr; 30199657Sbenno sg->ds_len = size; 30299657Sbenno } 30399657Sbenno vaddr += size; 30499657Sbenno nextpaddr = paddr + size; 30599657Sbenno buflen -= size; 306108939Sgrehan 307108939Sgrehan } while (buflen > 0); 30899657Sbenno 309108939Sgrehan if (buflen != 0) { 310108939Sgrehan printf("bus_dmamap_load: Too many segs! buf_len = 0x%lx\n", 311108939Sgrehan (u_long)buflen); 312108939Sgrehan error = EFBIG; 313108939Sgrehan } 31499657Sbenno 315108939Sgrehan (*callback)(callback_arg, dm_segments, seg, error); 31699657Sbenno 317108939Sgrehan return (0); 31878342Sbenno} 31999657Sbenno 32099657Sbenno/* 321108939Sgrehan * Utility function to load a linear buffer. lastaddrp holds state 322108939Sgrehan * between invocations (for multiple-buffer loads). segp contains 323108939Sgrehan * the starting segment on entrance, and the ending segment on exit. 324108939Sgrehan * first indicates if this is the first invocation of this function. 32599657Sbenno */ 326108939Sgrehanstatic int 327108939Sgrehanbus_dmamap_load_buffer(bus_dma_tag_t dmat, bus_dma_segment_t segs[], 328108939Sgrehan void *buf, bus_size_t buflen, struct thread *td, 329108939Sgrehan int flags, vm_offset_t *lastaddrp, int *segp, 330108939Sgrehan int first) 331108939Sgrehan{ 332108939Sgrehan bus_size_t sgsize; 333108939Sgrehan bus_addr_t curaddr, lastaddr, baddr, bmask; 334108939Sgrehan vm_offset_t vaddr = (vm_offset_t)buf; 335108939Sgrehan int seg; 336108939Sgrehan pmap_t pmap; 337108939Sgrehan 338108939Sgrehan if (td != NULL) 339108939Sgrehan pmap = vmspace_pmap(td->td_proc->p_vmspace); 340108939Sgrehan else 341108939Sgrehan pmap = NULL; 342108939Sgrehan 343108939Sgrehan lastaddr = *lastaddrp; 344108939Sgrehan bmask = ~(dmat->boundary - 1); 345108939Sgrehan 346108939Sgrehan for (seg = *segp; buflen > 0 ; ) { 347108939Sgrehan /* 348108939Sgrehan * Get the physical address for this segment. 349108939Sgrehan */ 350108939Sgrehan if (pmap) 351108939Sgrehan curaddr = pmap_extract(pmap, vaddr); 352108939Sgrehan else 353108939Sgrehan curaddr = pmap_kextract(vaddr); 354108939Sgrehan 355108939Sgrehan /* 356108939Sgrehan * Compute the segment size, and adjust counts. 357108939Sgrehan */ 358108939Sgrehan sgsize = PAGE_SIZE - ((u_long)curaddr & PAGE_MASK); 359108939Sgrehan if (buflen < sgsize) 360108939Sgrehan sgsize = buflen; 361108939Sgrehan 362108939Sgrehan /* 363108939Sgrehan * Make sure we don't cross any boundaries. 364108939Sgrehan */ 365108939Sgrehan if (dmat->boundary > 0) { 366108939Sgrehan baddr = (curaddr + dmat->boundary) & bmask; 367108939Sgrehan if (sgsize > (baddr - curaddr)) 368108939Sgrehan sgsize = (baddr - curaddr); 369108939Sgrehan } 370108939Sgrehan 371108939Sgrehan /* 372108939Sgrehan * Insert chunk into a segment, coalescing with 373108939Sgrehan * the previous segment if possible. 374108939Sgrehan */ 375108939Sgrehan if (first) { 376108939Sgrehan segs[seg].ds_addr = curaddr; 377108939Sgrehan segs[seg].ds_len = sgsize; 378108939Sgrehan first = 0; 379108939Sgrehan } else { 380108939Sgrehan if (curaddr == lastaddr && 381108939Sgrehan (segs[seg].ds_len + sgsize) <= dmat->maxsegsz && 382108939Sgrehan (dmat->boundary == 0 || 383108939Sgrehan (segs[seg].ds_addr & bmask) == (curaddr & bmask))) 384108939Sgrehan segs[seg].ds_len += sgsize; 385108939Sgrehan else { 386108939Sgrehan if (++seg >= dmat->nsegments) 387108939Sgrehan break; 388108939Sgrehan segs[seg].ds_addr = curaddr; 389108939Sgrehan segs[seg].ds_len = sgsize; 390108939Sgrehan } 391108939Sgrehan } 392108939Sgrehan 393108939Sgrehan lastaddr = curaddr + sgsize; 394108939Sgrehan vaddr += sgsize; 395108939Sgrehan buflen -= sgsize; 396108939Sgrehan } 397108939Sgrehan 398108939Sgrehan *segp = seg; 399108939Sgrehan *lastaddrp = lastaddr; 400108939Sgrehan 401108939Sgrehan /* 402108939Sgrehan * Did we fit? 403108939Sgrehan */ 404108939Sgrehan return (buflen != 0 ? EFBIG : 0); /* XXX better return value here? */ 405108939Sgrehan} 406108939Sgrehan 407108939Sgrehan/* 408108939Sgrehan * Like bus_dmamap_load(), but for mbufs. 409108939Sgrehan */ 410108939Sgrehanint 411108939Sgrehanbus_dmamap_load_mbuf(bus_dma_tag_t dmat, bus_dmamap_t map, struct mbuf *m0, 412108939Sgrehan bus_dmamap_callback2_t *callback, void *callback_arg, 413108939Sgrehan int flags) 414108939Sgrehan{ 415108939Sgrehan#ifdef __GNUC__ 416108939Sgrehan bus_dma_segment_t dm_segments[dmat->nsegments]; 417108939Sgrehan#else 418108939Sgrehan bus_dma_segment_t dm_segments[BUS_DMAMAP_NSEGS]; 419108939Sgrehan#endif 420108939Sgrehan int nsegs = 0, error = 0; 421108939Sgrehan 422108939Sgrehan KASSERT(m0->m_flags & M_PKTHDR, 423108939Sgrehan ("bus_dmamap_load_mbuf: no packet header")); 424108939Sgrehan 425108939Sgrehan if (m0->m_pkthdr.len <= dmat->maxsize) { 426108939Sgrehan int first = 1; 427108939Sgrehan vm_offset_t lastaddr = 0; 428108939Sgrehan struct mbuf *m; 429108939Sgrehan 430108939Sgrehan for (m = m0; m != NULL && error == 0; m = m->m_next) { 431110335Sharti if (m->m_len > 0) { 432110335Sharti error = bus_dmamap_load_buffer(dmat, 433110335Sharti dm_segments, m->m_data, m->m_len, NULL, 434110335Sharti flags, &lastaddr, &nsegs, first); 435110335Sharti first = 0; 436110335Sharti } 437108939Sgrehan } 438108939Sgrehan } else { 439108939Sgrehan error = EINVAL; 440108939Sgrehan } 441108939Sgrehan 442108939Sgrehan if (error) { 443108939Sgrehan /* 444108939Sgrehan * force "no valid mappings" on error in callback. 445108939Sgrehan */ 446108939Sgrehan (*callback)(callback_arg, dm_segments, 0, 0, error); 447108939Sgrehan } else { 448108939Sgrehan (*callback)(callback_arg, dm_segments, nsegs+1, 449108939Sgrehan m0->m_pkthdr.len, error); 450108939Sgrehan } 451108939Sgrehan return (error); 452108939Sgrehan} 453108939Sgrehan 454108939Sgrehan/* 455108939Sgrehan * Like bus_dmamap_load(), but for uios. 456108939Sgrehan */ 457108939Sgrehanint 458108939Sgrehanbus_dmamap_load_uio(bus_dma_tag_t dmat, bus_dmamap_t map, struct uio *uio, 459108939Sgrehan bus_dmamap_callback2_t *callback, void *callback_arg, 460108939Sgrehan int flags) 461108939Sgrehan{ 462108939Sgrehan vm_offset_t lastaddr; 463108939Sgrehan#ifdef __GNUC__ 464108939Sgrehan bus_dma_segment_t dm_segments[dmat->nsegments]; 465108939Sgrehan#else 466108939Sgrehan bus_dma_segment_t dm_segments[BUS_DMAMAP_NSEGS]; 467108939Sgrehan#endif 468108939Sgrehan int nsegs, i, error, first; 469108939Sgrehan bus_size_t resid; 470108939Sgrehan struct iovec *iov; 471108939Sgrehan struct proc *td = NULL; 472108939Sgrehan 473108939Sgrehan resid = uio->uio_resid; 474108939Sgrehan iov = uio->uio_iov; 475108939Sgrehan 476108939Sgrehan if (uio->uio_segflg == UIO_USERSPACE) { 477108939Sgrehan td = uio->uio_td; 478108939Sgrehan KASSERT(td != NULL, 479108939Sgrehan ("bus_dmamap_load_uio: USERSPACE but no proc")); 480108939Sgrehan } 481108939Sgrehan 482108939Sgrehan first = 1; 483108939Sgrehan nsegs = error = 0; 484108939Sgrehan for (i = 0; i < uio->uio_iovcnt && resid != 0 && !error; i++) { 485108939Sgrehan /* 486108939Sgrehan * Now at the first iovec to load. Load each iovec 487108939Sgrehan * until we have exhausted the residual count. 488108939Sgrehan */ 489108939Sgrehan bus_size_t minlen = 490108939Sgrehan resid < iov[i].iov_len ? resid : iov[i].iov_len; 491108939Sgrehan caddr_t addr = (caddr_t) iov[i].iov_base; 492108939Sgrehan 493110335Sharti if (minlen > 0) { 494110335Sharti error = bus_dmamap_load_buffer(dmat, dm_segments, addr, 495110335Sharti minlen, td, flags, &lastaddr, &nsegs, first); 496108939Sgrehan 497110335Sharti first = 0; 498108939Sgrehan 499110335Sharti resid -= minlen; 500110335Sharti } 501108939Sgrehan } 502108939Sgrehan 503108939Sgrehan if (error) { 504108939Sgrehan /* 505108939Sgrehan * force "no valid mappings" on error in callback. 506108939Sgrehan */ 507108939Sgrehan (*callback)(callback_arg, dm_segments, 0, 0, error); 508108939Sgrehan } else { 509108939Sgrehan (*callback)(callback_arg, dm_segments, nsegs+1, 510108939Sgrehan uio->uio_resid, error); 511108939Sgrehan } 512108939Sgrehan 513108939Sgrehan return (error); 514108939Sgrehan} 515108939Sgrehan 516108939Sgrehan/* 517108939Sgrehan * Release the mapping held by map. A no-op on PowerPC. 518108939Sgrehan */ 51999657Sbennovoid 52099657Sbennobus_dmamap_unload(bus_dma_tag_t dmat, bus_dmamap_t map) 521109935Sbenno{ 52299657Sbenno 523109935Sbenno return; 524109935Sbenno} 525109935Sbenno 52699657Sbennovoid 52799657Sbennobus_dmamap_sync(bus_dma_tag_t dmat, bus_dmamap_t map, bus_dmasync_op_t op) 528109919Sbenno{ 529109919Sbenno 530109935Sbenno return; 531109919Sbenno} 532