busdma_machdep.c revision 115343
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 30113038Sobrien#include <sys/cdefs.h> 31113038Sobrien__FBSDID("$FreeBSD: head/sys/powerpc/powerpc/busdma_machdep.c 115343 2003-05-27 04:59:59Z scottl $"); 3278342Sbenno 3399657Sbenno/* 3499657Sbenno * MacPPC bus dma support routines 3599657Sbenno */ 3678342Sbenno 3799657Sbenno#include <sys/param.h> 3899657Sbenno#include <sys/systm.h> 3999657Sbenno#include <sys/malloc.h> 4099657Sbenno#include <sys/bus.h> 4199657Sbenno#include <sys/interrupt.h> 4299657Sbenno#include <sys/lock.h> 4399657Sbenno#include <sys/proc.h> 4499657Sbenno#include <sys/mutex.h> 45108939Sgrehan#include <sys/mbuf.h> 46108939Sgrehan#include <sys/uio.h> 4799657Sbenno 4899657Sbenno#include <vm/vm.h> 4999657Sbenno#include <vm/vm_page.h> 50108939Sgrehan#include <vm/vm_map.h> 5199657Sbenno 52112436Smux#include <machine/atomic.h> 5399657Sbenno#include <machine/bus.h> 54109919Sbenno#include <machine/cpufunc.h> 5599657Sbenno 5699657Sbennostruct bus_dma_tag { 5799657Sbenno bus_dma_tag_t parent; 5899657Sbenno bus_size_t alignment; 5999657Sbenno bus_size_t boundary; 6099657Sbenno bus_addr_t lowaddr; 6199657Sbenno bus_addr_t highaddr; 6299657Sbenno bus_dma_filter_t *filter; 6399657Sbenno void *filterarg; 6499657Sbenno bus_size_t maxsize; 6599657Sbenno u_int nsegments; 6699657Sbenno bus_size_t maxsegsz; 6799657Sbenno int flags; 6899657Sbenno int ref_count; 6999657Sbenno int map_count; 7099657Sbenno}; 7199657Sbenno 7299657Sbennostruct bus_dmamap { 7399657Sbenno bus_dma_tag_t dmat; 7499657Sbenno void *buf; /* unmapped buffer pointer */ 7599657Sbenno bus_size_t buflen; /* unmapped buffer length */ 7699657Sbenno bus_dmamap_callback_t *callback; 7799657Sbenno void *callback_arg; 7899657Sbenno}; 7999657Sbenno 8099657Sbenno/* 8199657Sbenno * Allocate a device specific dma_tag. 8299657Sbenno */ 8399657Sbennoint 8499657Sbennobus_dma_tag_create(bus_dma_tag_t parent, bus_size_t alignment, 8599657Sbenno bus_size_t boundary, bus_addr_t lowaddr, 8699657Sbenno bus_addr_t highaddr, bus_dma_filter_t *filter, 8799657Sbenno void *filterarg, bus_size_t maxsize, int nsegments, 8899657Sbenno bus_size_t maxsegsz, int flags, bus_dma_tag_t *dmat) 8999657Sbenno{ 9099657Sbenno bus_dma_tag_t newtag; 9199657Sbenno int error = 0; 9299657Sbenno 9399657Sbenno /* Return a NULL tag on failure */ 9499657Sbenno *dmat = NULL; 9599657Sbenno 9699657Sbenno newtag = (bus_dma_tag_t)malloc(sizeof(*newtag), M_DEVBUF, M_NOWAIT); 9799657Sbenno if (newtag == NULL) 9899657Sbenno return (ENOMEM); 9999657Sbenno 10099657Sbenno newtag->parent = parent; 10199657Sbenno newtag->alignment = alignment; 10299657Sbenno newtag->boundary = boundary; 10399657Sbenno newtag->lowaddr = trunc_page((vm_offset_t)lowaddr) + (PAGE_SIZE - 1); 10499657Sbenno newtag->highaddr = trunc_page((vm_offset_t)highaddr) + (PAGE_SIZE - 1); 10599657Sbenno newtag->filter = filter; 10699657Sbenno newtag->filterarg = filterarg; 10799657Sbenno newtag->maxsize = maxsize; 10899657Sbenno newtag->nsegments = nsegments; 10999657Sbenno newtag->maxsegsz = maxsegsz; 11099657Sbenno newtag->flags = flags; 11199657Sbenno newtag->ref_count = 1; /* Count ourself */ 11299657Sbenno newtag->map_count = 0; 11399657Sbenno 11499657Sbenno /* 11599657Sbenno * Take into account any restrictions imposed by our parent tag 11699657Sbenno */ 11799657Sbenno if (parent != NULL) { 11899657Sbenno newtag->lowaddr = min(parent->lowaddr, newtag->lowaddr); 11999657Sbenno newtag->highaddr = max(parent->highaddr, newtag->highaddr); 12099657Sbenno 12199657Sbenno /* 12299657Sbenno * XXX Not really correct??? Probably need to honor boundary 12399657Sbenno * all the way up the inheritence chain. 12499657Sbenno */ 12599657Sbenno newtag->boundary = max(parent->boundary, newtag->boundary); 12699657Sbenno if (newtag->filter == NULL) { 12799657Sbenno /* 12899657Sbenno * Short circuit looking at our parent directly 12999657Sbenno * since we have encapsulated all of its information 13099657Sbenno */ 13199657Sbenno newtag->filter = parent->filter; 13299657Sbenno newtag->filterarg = parent->filterarg; 13399657Sbenno newtag->parent = parent->parent; 13499657Sbenno } 135112436Smux if (newtag->parent != NULL) 136112436Smux atomic_add_int(&parent->ref_count, 1); 13799657Sbenno } 13899657Sbenno 13999657Sbenno *dmat = newtag; 14099657Sbenno return (error); 14199657Sbenno} 14299657Sbenno 14399657Sbennoint 14499657Sbennobus_dma_tag_destroy(bus_dma_tag_t dmat) 14599657Sbenno{ 14699657Sbenno if (dmat != NULL) { 14799657Sbenno 14899657Sbenno if (dmat->map_count != 0) 14999657Sbenno return (EBUSY); 15099657Sbenno 15199657Sbenno while (dmat != NULL) { 15299657Sbenno bus_dma_tag_t parent; 15399657Sbenno 15499657Sbenno parent = dmat->parent; 155112436Smux atomic_subtract_int(&dmat->ref_count, 1); 15699657Sbenno if (dmat->ref_count == 0) { 15799657Sbenno free(dmat, M_DEVBUF); 15899657Sbenno /* 15999657Sbenno * Last reference count, so 16099657Sbenno * release our reference 16199657Sbenno * count on our parent. 16299657Sbenno */ 16399657Sbenno dmat = parent; 16499657Sbenno } else 16599657Sbenno dmat = NULL; 16699657Sbenno } 16799657Sbenno } 16899657Sbenno return (0); 16999657Sbenno} 17099657Sbenno 17199657Sbenno/* 17299657Sbenno * Allocate a handle for mapping from kva/uva/physical 17399657Sbenno * address space into bus device space. 17499657Sbenno */ 17599657Sbennoint 17699657Sbennobus_dmamap_create(bus_dma_tag_t dmat, int flags, bus_dmamap_t *mapp) 17799657Sbenno{ 17899657Sbenno *mapp = NULL; 17999657Sbenno dmat->map_count++; 18099657Sbenno 18199657Sbenno return (0); 18299657Sbenno} 18399657Sbenno 18499657Sbenno/* 18599657Sbenno * Destroy a handle for mapping from kva/uva/physical 18699657Sbenno * address space into bus device space. 18799657Sbenno */ 18899657Sbennoint 18999657Sbennobus_dmamap_destroy(bus_dma_tag_t dmat, bus_dmamap_t map) 19099657Sbenno{ 19199657Sbenno if (map != NULL) { 19299657Sbenno panic("dmamap_destroy: NULL?\n"); 19399657Sbenno } 19499657Sbenno dmat->map_count--; 19599657Sbenno return (0); 19699657Sbenno} 19799657Sbenno 19899657Sbenno/* 19999657Sbenno * Allocate a piece of memory that can be efficiently mapped into 20099657Sbenno * bus device space based on the constraints lited in the dma tag. 20199657Sbenno * A dmamap to for use with dmamap_load is also allocated. 20299657Sbenno */ 20399657Sbennoint 20499657Sbennobus_dmamem_alloc(bus_dma_tag_t dmat, void** vaddr, int flags, 20599657Sbenno bus_dmamap_t *mapp) 20699657Sbenno{ 20799657Sbenno *mapp = NULL; 20899657Sbenno 20999657Sbenno if (dmat->maxsize <= PAGE_SIZE) { 21099657Sbenno *vaddr = malloc(dmat->maxsize, M_DEVBUF, 211111119Simp (flags & BUS_DMA_NOWAIT) ? M_NOWAIT : M_WAITOK); 21299657Sbenno } else { 21399657Sbenno /* 21499657Sbenno * XXX Use Contigmalloc until it is merged into this facility 21599657Sbenno * and handles multi-seg allocations. Nobody is doing 21699657Sbenno * multi-seg allocations yet though. 21799657Sbenno */ 218112196Smux mtx_lock(&Giant); 21999657Sbenno *vaddr = contigmalloc(dmat->maxsize, M_DEVBUF, 220111119Simp (flags & BUS_DMA_NOWAIT) ? M_NOWAIT : M_WAITOK, 22199657Sbenno 0ul, dmat->lowaddr, dmat->alignment? dmat->alignment : 1ul, 22299657Sbenno dmat->boundary); 223112196Smux mtx_unlock(&Giant); 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); 243112196Smux else { 244112196Smux mtx_lock(&Giant); 24599657Sbenno contigfree(vaddr, dmat->maxsize, M_DEVBUF); 246112196Smux mtx_unlock(&Giant); 247112196Smux } 24899657Sbenno} 24978342Sbenno 25099657Sbenno/* 25199657Sbenno * Map the buffer buf into bus space using the dmamap map. 25299657Sbenno */ 25399657Sbennoint 25499657Sbennobus_dmamap_load(bus_dma_tag_t dmat, bus_dmamap_t map, void *buf, 25599657Sbenno bus_size_t buflen, bus_dmamap_callback_t *callback, 25699657Sbenno void *callback_arg, int flags) 25799657Sbenno{ 25899657Sbenno vm_offset_t vaddr; 25999657Sbenno vm_offset_t paddr; 26099657Sbenno#ifdef __GNUC__ 26199657Sbenno bus_dma_segment_t dm_segments[dmat->nsegments]; 26299657Sbenno#else 26399657Sbenno bus_dma_segment_t dm_segments[BUS_DMAMAP_NSEGS]; 26499657Sbenno#endif 26599657Sbenno bus_dma_segment_t *sg; 26699657Sbenno int seg; 26799657Sbenno int error = 0; 26899657Sbenno vm_offset_t nextpaddr; 26999657Sbenno 27099657Sbenno if (map != NULL) 27199657Sbenno panic("bus_dmamap_load: Invalid map\n"); 27299657Sbenno 27399657Sbenno vaddr = (vm_offset_t)buf; 27499657Sbenno sg = &dm_segments[0]; 27599657Sbenno seg = 1; 27699657Sbenno sg->ds_len = 0; 27799657Sbenno nextpaddr = 0; 27899657Sbenno 27999657Sbenno do { 28099657Sbenno bus_size_t size; 28199657Sbenno 28299657Sbenno paddr = pmap_kextract(vaddr); 28399657Sbenno size = PAGE_SIZE - (paddr & PAGE_MASK); 28499657Sbenno if (size > buflen) 28599657Sbenno size = buflen; 28699657Sbenno 28799657Sbenno if (sg->ds_len == 0) { 28899657Sbenno sg->ds_addr = paddr; 28999657Sbenno sg->ds_len = size; 29099657Sbenno } else if (paddr == nextpaddr) { 29199657Sbenno sg->ds_len += size; 29299657Sbenno } else { 29399657Sbenno /* Go to the next segment */ 29499657Sbenno sg++; 29599657Sbenno seg++; 29699657Sbenno if (seg > dmat->nsegments) 29799657Sbenno break; 29899657Sbenno sg->ds_addr = paddr; 29999657Sbenno sg->ds_len = size; 30099657Sbenno } 30199657Sbenno vaddr += size; 30299657Sbenno nextpaddr = paddr + size; 30399657Sbenno buflen -= size; 304108939Sgrehan 305108939Sgrehan } while (buflen > 0); 30699657Sbenno 307108939Sgrehan if (buflen != 0) { 308108939Sgrehan printf("bus_dmamap_load: Too many segs! buf_len = 0x%lx\n", 309108939Sgrehan (u_long)buflen); 310108939Sgrehan error = EFBIG; 311108939Sgrehan } 31299657Sbenno 313108939Sgrehan (*callback)(callback_arg, dm_segments, seg, error); 31499657Sbenno 315108939Sgrehan return (0); 31678342Sbenno} 31799657Sbenno 31899657Sbenno/* 319108939Sgrehan * Utility function to load a linear buffer. lastaddrp holds state 320108939Sgrehan * between invocations (for multiple-buffer loads). segp contains 321108939Sgrehan * the starting segment on entrance, and the ending segment on exit. 322108939Sgrehan * first indicates if this is the first invocation of this function. 32399657Sbenno */ 324108939Sgrehanstatic int 325108939Sgrehanbus_dmamap_load_buffer(bus_dma_tag_t dmat, bus_dma_segment_t segs[], 326108939Sgrehan void *buf, bus_size_t buflen, struct thread *td, 327108939Sgrehan int flags, vm_offset_t *lastaddrp, int *segp, 328108939Sgrehan int first) 329108939Sgrehan{ 330108939Sgrehan bus_size_t sgsize; 331108939Sgrehan bus_addr_t curaddr, lastaddr, baddr, bmask; 332108939Sgrehan vm_offset_t vaddr = (vm_offset_t)buf; 333108939Sgrehan int seg; 334108939Sgrehan pmap_t pmap; 335108939Sgrehan 336108939Sgrehan if (td != NULL) 337108939Sgrehan pmap = vmspace_pmap(td->td_proc->p_vmspace); 338108939Sgrehan else 339108939Sgrehan pmap = NULL; 340108939Sgrehan 341108939Sgrehan lastaddr = *lastaddrp; 342108939Sgrehan bmask = ~(dmat->boundary - 1); 343108939Sgrehan 344108939Sgrehan for (seg = *segp; buflen > 0 ; ) { 345108939Sgrehan /* 346108939Sgrehan * Get the physical address for this segment. 347108939Sgrehan */ 348108939Sgrehan if (pmap) 349108939Sgrehan curaddr = pmap_extract(pmap, vaddr); 350108939Sgrehan else 351108939Sgrehan curaddr = pmap_kextract(vaddr); 352108939Sgrehan 353108939Sgrehan /* 354108939Sgrehan * Compute the segment size, and adjust counts. 355108939Sgrehan */ 356108939Sgrehan sgsize = PAGE_SIZE - ((u_long)curaddr & PAGE_MASK); 357108939Sgrehan if (buflen < sgsize) 358108939Sgrehan sgsize = buflen; 359108939Sgrehan 360108939Sgrehan /* 361108939Sgrehan * Make sure we don't cross any boundaries. 362108939Sgrehan */ 363108939Sgrehan if (dmat->boundary > 0) { 364108939Sgrehan baddr = (curaddr + dmat->boundary) & bmask; 365108939Sgrehan if (sgsize > (baddr - curaddr)) 366108939Sgrehan sgsize = (baddr - curaddr); 367108939Sgrehan } 368108939Sgrehan 369108939Sgrehan /* 370108939Sgrehan * Insert chunk into a segment, coalescing with 371108939Sgrehan * the previous segment if possible. 372108939Sgrehan */ 373108939Sgrehan if (first) { 374108939Sgrehan segs[seg].ds_addr = curaddr; 375108939Sgrehan segs[seg].ds_len = sgsize; 376108939Sgrehan first = 0; 377108939Sgrehan } else { 378108939Sgrehan if (curaddr == lastaddr && 379108939Sgrehan (segs[seg].ds_len + sgsize) <= dmat->maxsegsz && 380108939Sgrehan (dmat->boundary == 0 || 381108939Sgrehan (segs[seg].ds_addr & bmask) == (curaddr & bmask))) 382108939Sgrehan segs[seg].ds_len += sgsize; 383108939Sgrehan else { 384108939Sgrehan if (++seg >= dmat->nsegments) 385108939Sgrehan break; 386108939Sgrehan segs[seg].ds_addr = curaddr; 387108939Sgrehan segs[seg].ds_len = sgsize; 388108939Sgrehan } 389108939Sgrehan } 390108939Sgrehan 391108939Sgrehan lastaddr = curaddr + sgsize; 392108939Sgrehan vaddr += sgsize; 393108939Sgrehan buflen -= sgsize; 394108939Sgrehan } 395108939Sgrehan 396108939Sgrehan *segp = seg; 397108939Sgrehan *lastaddrp = lastaddr; 398108939Sgrehan 399108939Sgrehan /* 400108939Sgrehan * Did we fit? 401108939Sgrehan */ 402108939Sgrehan return (buflen != 0 ? EFBIG : 0); /* XXX better return value here? */ 403108939Sgrehan} 404108939Sgrehan 405108939Sgrehan/* 406108939Sgrehan * Like bus_dmamap_load(), but for mbufs. 407108939Sgrehan */ 408108939Sgrehanint 409108939Sgrehanbus_dmamap_load_mbuf(bus_dma_tag_t dmat, bus_dmamap_t map, struct mbuf *m0, 410108939Sgrehan bus_dmamap_callback2_t *callback, void *callback_arg, 411108939Sgrehan int flags) 412108939Sgrehan{ 413108939Sgrehan#ifdef __GNUC__ 414108939Sgrehan bus_dma_segment_t dm_segments[dmat->nsegments]; 415108939Sgrehan#else 416108939Sgrehan bus_dma_segment_t dm_segments[BUS_DMAMAP_NSEGS]; 417108939Sgrehan#endif 418108939Sgrehan int nsegs = 0, error = 0; 419108939Sgrehan 420113255Sdes M_ASSERTPKTHDR(m0); 421108939Sgrehan 422108939Sgrehan if (m0->m_pkthdr.len <= dmat->maxsize) { 423108939Sgrehan int first = 1; 424108939Sgrehan vm_offset_t lastaddr = 0; 425108939Sgrehan struct mbuf *m; 426108939Sgrehan 427108939Sgrehan for (m = m0; m != NULL && error == 0; m = m->m_next) { 428110335Sharti if (m->m_len > 0) { 429110335Sharti error = bus_dmamap_load_buffer(dmat, 430110335Sharti dm_segments, m->m_data, m->m_len, NULL, 431110335Sharti flags, &lastaddr, &nsegs, first); 432110335Sharti first = 0; 433110335Sharti } 434108939Sgrehan } 435108939Sgrehan } else { 436108939Sgrehan error = EINVAL; 437108939Sgrehan } 438108939Sgrehan 439108939Sgrehan if (error) { 440108939Sgrehan /* 441108939Sgrehan * force "no valid mappings" on error in callback. 442108939Sgrehan */ 443108939Sgrehan (*callback)(callback_arg, dm_segments, 0, 0, error); 444108939Sgrehan } else { 445108939Sgrehan (*callback)(callback_arg, dm_segments, nsegs+1, 446108939Sgrehan m0->m_pkthdr.len, error); 447108939Sgrehan } 448108939Sgrehan return (error); 449108939Sgrehan} 450108939Sgrehan 451108939Sgrehan/* 452108939Sgrehan * Like bus_dmamap_load(), but for uios. 453108939Sgrehan */ 454108939Sgrehanint 455108939Sgrehanbus_dmamap_load_uio(bus_dma_tag_t dmat, bus_dmamap_t map, struct uio *uio, 456108939Sgrehan bus_dmamap_callback2_t *callback, void *callback_arg, 457108939Sgrehan int flags) 458108939Sgrehan{ 459108939Sgrehan vm_offset_t lastaddr; 460108939Sgrehan#ifdef __GNUC__ 461108939Sgrehan bus_dma_segment_t dm_segments[dmat->nsegments]; 462108939Sgrehan#else 463108939Sgrehan bus_dma_segment_t dm_segments[BUS_DMAMAP_NSEGS]; 464108939Sgrehan#endif 465108939Sgrehan int nsegs, i, error, first; 466108939Sgrehan bus_size_t resid; 467108939Sgrehan struct iovec *iov; 468113703Sgrehan struct thread *td = NULL; 469108939Sgrehan 470108939Sgrehan resid = uio->uio_resid; 471108939Sgrehan iov = uio->uio_iov; 472108939Sgrehan 473108939Sgrehan if (uio->uio_segflg == UIO_USERSPACE) { 474108939Sgrehan td = uio->uio_td; 475108939Sgrehan KASSERT(td != NULL, 476108939Sgrehan ("bus_dmamap_load_uio: USERSPACE but no proc")); 477108939Sgrehan } 478108939Sgrehan 479108939Sgrehan first = 1; 480108939Sgrehan nsegs = error = 0; 481108939Sgrehan for (i = 0; i < uio->uio_iovcnt && resid != 0 && !error; i++) { 482108939Sgrehan /* 483108939Sgrehan * Now at the first iovec to load. Load each iovec 484108939Sgrehan * until we have exhausted the residual count. 485108939Sgrehan */ 486108939Sgrehan bus_size_t minlen = 487108939Sgrehan resid < iov[i].iov_len ? resid : iov[i].iov_len; 488108939Sgrehan caddr_t addr = (caddr_t) iov[i].iov_base; 489108939Sgrehan 490110335Sharti if (minlen > 0) { 491110335Sharti error = bus_dmamap_load_buffer(dmat, dm_segments, addr, 492110335Sharti minlen, td, flags, &lastaddr, &nsegs, first); 493108939Sgrehan 494110335Sharti first = 0; 495108939Sgrehan 496110335Sharti resid -= minlen; 497110335Sharti } 498108939Sgrehan } 499108939Sgrehan 500108939Sgrehan if (error) { 501108939Sgrehan /* 502108939Sgrehan * force "no valid mappings" on error in callback. 503108939Sgrehan */ 504108939Sgrehan (*callback)(callback_arg, dm_segments, 0, 0, error); 505108939Sgrehan } else { 506108939Sgrehan (*callback)(callback_arg, dm_segments, nsegs+1, 507108939Sgrehan uio->uio_resid, error); 508108939Sgrehan } 509108939Sgrehan 510108939Sgrehan return (error); 511108939Sgrehan} 512108939Sgrehan 513108939Sgrehan/* 514108939Sgrehan * Release the mapping held by map. A no-op on PowerPC. 515108939Sgrehan */ 51699657Sbennovoid 51799657Sbennobus_dmamap_unload(bus_dma_tag_t dmat, bus_dmamap_t map) 518109935Sbenno{ 51999657Sbenno 520109935Sbenno return; 521109935Sbenno} 522109935Sbenno 52399657Sbennovoid 524115343Sscottlbus_dmamap_sync(bus_dma_tag_t dmat, bus_dmamap_t map, bus_dmasync_op_t op) 525109919Sbenno{ 526109919Sbenno 527109935Sbenno return; 528109919Sbenno} 529