busdma_machdep.c revision 109919
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 109919 2003-01-27 04:27:01Z 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) 51299657Sbenno{} 51399657Sbenno 51499657Sbennovoid 51599657Sbennobus_dmamap_sync(bus_dma_tag_t dmat, bus_dmamap_t map, bus_dmasync_op_t op) 516109919Sbenno{ 517109919Sbenno 518109919Sbenno if ((op == BUS_DMASYNC_PREREAD) || (op == BUS_DMASYNC_PREWRITE)) 519109919Sbenno powerpc_mb(); 520109919Sbenno} 521