Annotation of sys/arch/vax/vax/bus_dma.c, Revision 1.1
1.1 ! nbrk 1: /* $OpenBSD: bus_dma.c,v 1.16 2005/11/08 15:05:56 martin Exp $ */
! 2: /* $NetBSD: bus_dma.c,v 1.5 1999/11/13 00:32:20 thorpej Exp $ */
! 3:
! 4: /*-
! 5: * Copyright (c) 1996, 1997, 1998 The NetBSD Foundation, Inc.
! 6: * All rights reserved.
! 7: *
! 8: * This code is derived from software contributed to The NetBSD Foundation
! 9: * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility,
! 10: * NASA Ames Research Center.
! 11: *
! 12: * Redistribution and use in source and binary forms, with or without
! 13: * modification, are permitted provided that the following conditions
! 14: * are met:
! 15: * 1. Redistributions of source code must retain the above copyright
! 16: * notice, this list of conditions and the following disclaimer.
! 17: * 2. Redistributions in binary form must reproduce the above copyright
! 18: * notice, this list of conditions and the following disclaimer in the
! 19: * documentation and/or other materials provided with the distribution.
! 20: * 3. All advertising materials mentioning features or use of this software
! 21: * must display the following acknowledgement:
! 22: * This product includes software developed by the NetBSD
! 23: * Foundation, Inc. and its contributors.
! 24: * 4. Neither the name of The NetBSD Foundation nor the names of its
! 25: * contributors may be used to endorse or promote products derived
! 26: * from this software without specific prior written permission.
! 27: *
! 28: * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
! 29: * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
! 30: * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
! 31: * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
! 32: * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
! 33: * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
! 34: * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
! 35: * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
! 36: * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
! 37: * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
! 38: * POSSIBILITY OF SUCH DAMAGE.
! 39: */
! 40: /*
! 41: * bus_dma routines for vax. File copied from arm32/bus_dma.c.
! 42: * NetBSD: bus_dma.c,v 1.11 1998/09/21 22:53:35 thorpej Exp
! 43: */
! 44:
! 45: #include <sys/param.h>
! 46: #include <sys/systm.h>
! 47: #include <sys/kernel.h>
! 48: #include <sys/proc.h>
! 49: #include <sys/buf.h>
! 50: #include <sys/reboot.h>
! 51: #include <sys/conf.h>
! 52: #include <sys/file.h>
! 53: #include <sys/malloc.h>
! 54: #include <sys/mbuf.h>
! 55: #include <sys/vnode.h>
! 56: #include <sys/device.h>
! 57:
! 58: #include <uvm/uvm_extern.h>
! 59:
! 60: #define _VAX_BUS_DMA_PRIVATE
! 61: #include <machine/bus.h>
! 62:
! 63: #include <machine/ka43.h>
! 64: #include <machine/sid.h>
! 65:
! 66: extern vaddr_t avail_start, avail_end, virtual_avail;
! 67:
! 68: int _bus_dmamap_load_buffer(bus_dma_tag_t, bus_dmamap_t, void *,
! 69: bus_size_t, struct proc *, int, paddr_t *, int *, int);
! 70: int _bus_dma_inrange(bus_dma_segment_t *, int, bus_addr_t);
! 71: int _bus_dmamem_alloc_range(bus_dma_tag_t, bus_size_t, bus_size_t,
! 72: bus_size_t, bus_dma_segment_t*, int, int *, int, vaddr_t, vaddr_t);
! 73: /*
! 74: * Common function for DMA map creation. May be called by bus-specific
! 75: * DMA map creation functions.
! 76: */
! 77: int
! 78: _bus_dmamap_create(t, size, nsegments, maxsegsz, boundary, flags, dmamp)
! 79: bus_dma_tag_t t;
! 80: bus_size_t size;
! 81: int nsegments;
! 82: bus_size_t maxsegsz;
! 83: bus_size_t boundary;
! 84: int flags;
! 85: bus_dmamap_t *dmamp;
! 86: {
! 87: struct vax_bus_dmamap *map;
! 88: void *mapstore;
! 89: size_t mapsize;
! 90:
! 91: #ifdef DEBUG_DMA
! 92: printf("dmamap_create: t=%p size=%lx nseg=%x msegsz=%lx boundary=%lx flags=%x\n",
! 93: t, size, nsegments, maxsegsz, boundary, flags);
! 94: #endif /* DEBUG_DMA */
! 95:
! 96: /*
! 97: * Allocate and initialize the DMA map. The end of the map
! 98: * is a variable-sized array of segments, so we allocate enough
! 99: * room for them in one shot.
! 100: *
! 101: * Note we don't preserve the WAITOK or NOWAIT flags. Preservation
! 102: * of ALLOCNOW notifies others that we've reserved these resources,
! 103: * and they are not to be freed.
! 104: *
! 105: * The bus_dmamap_t includes one bus_dma_segment_t, hence
! 106: * the (nsegments - 1).
! 107: */
! 108: mapsize = sizeof(struct vax_bus_dmamap) +
! 109: (sizeof(bus_dma_segment_t) * (nsegments - 1));
! 110: if ((mapstore = malloc(mapsize, M_DEVBUF,
! 111: (flags & BUS_DMA_NOWAIT) ? M_NOWAIT : M_WAITOK)) == NULL)
! 112: return (ENOMEM);
! 113:
! 114: bzero(mapstore, mapsize);
! 115: map = (struct vax_bus_dmamap *)mapstore;
! 116: map->_dm_size = size;
! 117: map->_dm_segcnt = nsegments;
! 118: map->_dm_maxsegsz = maxsegsz;
! 119: map->_dm_boundary = boundary;
! 120: map->_dm_flags = flags & ~(BUS_DMA_WAITOK|BUS_DMA_NOWAIT);
! 121: map->dm_mapsize = 0; /* no valid mappings */
! 122: map->dm_nsegs = 0;
! 123:
! 124: *dmamp = map;
! 125: #ifdef DEBUG_DMA
! 126: printf("dmamap_create:map=%p\n", map);
! 127: #endif /* DEBUG_DMA */
! 128: return (0);
! 129: }
! 130:
! 131: /*
! 132: * Common function for DMA map destruction. May be called by bus-specific
! 133: * DMA map destruction functions.
! 134: */
! 135: void
! 136: _bus_dmamap_destroy(t, map)
! 137: bus_dma_tag_t t;
! 138: bus_dmamap_t map;
! 139: {
! 140:
! 141: #ifdef DEBUG_DMA
! 142: printf("dmamap_destroy: t=%p map=%p\n", t, map);
! 143: #endif /* DEBUG_DMA */
! 144: #ifdef DIAGNOSTIC
! 145: if (map->dm_nsegs > 0)
! 146: printf("bus_dmamap_destroy() called for map with valid mappings\n");
! 147: #endif /* DIAGNOSTIC */
! 148: free(map, M_DEVBUF);
! 149: }
! 150:
! 151: /*
! 152: * Common function for loading a DMA map with a linear buffer. May
! 153: * be called by bus-specific DMA map load functions.
! 154: */
! 155: int
! 156: _bus_dmamap_load(t, map, buf, buflen, p, flags)
! 157: bus_dma_tag_t t;
! 158: bus_dmamap_t map;
! 159: void *buf;
! 160: bus_size_t buflen;
! 161: struct proc *p;
! 162: int flags;
! 163: {
! 164: paddr_t lastaddr;
! 165: int seg, error;
! 166:
! 167: #ifdef DEBUG_DMA
! 168: printf("dmamap_load: t=%p map=%p buf=%p len=%lx p=%p f=%d\n",
! 169: t, map, buf, buflen, p, flags);
! 170: #endif /* DEBUG_DMA */
! 171:
! 172: /*
! 173: * Make sure that on error condition we return "no valid mappings".
! 174: */
! 175: map->dm_mapsize = 0;
! 176: map->dm_nsegs = 0;
! 177:
! 178: if (buflen > map->_dm_size)
! 179: return (EINVAL);
! 180:
! 181: seg = 0;
! 182: error = _bus_dmamap_load_buffer(t, map, buf, buflen, p, flags,
! 183: &lastaddr, &seg, 1);
! 184: if (error == 0) {
! 185: map->dm_mapsize = buflen;
! 186: map->dm_nsegs = seg + 1;
! 187: }
! 188: #ifdef DEBUG_DMA
! 189: printf("dmamap_load: error=%d\n", error);
! 190: #endif /* DEBUG_DMA */
! 191: return (error);
! 192: }
! 193:
! 194: /*
! 195: * Like _bus_dmamap_load(), but for mbufs.
! 196: */
! 197: int
! 198: _bus_dmamap_load_mbuf(t, map, m0, flags)
! 199: bus_dma_tag_t t;
! 200: bus_dmamap_t map;
! 201: struct mbuf *m0;
! 202: int flags;
! 203: {
! 204: paddr_t lastaddr;
! 205: int seg, error, first;
! 206: struct mbuf *m;
! 207:
! 208: #ifdef DEBUG_DMA
! 209: printf("dmamap_load_mbuf: t=%p map=%p m0=%p f=%d\n",
! 210: t, map, m0, flags);
! 211: #endif /* DEBUG_DMA */
! 212:
! 213: /*
! 214: * Make sure that on error condition we return "no valid mappings."
! 215: */
! 216: map->dm_mapsize = 0;
! 217: map->dm_nsegs = 0;
! 218:
! 219: #ifdef DIAGNOSTIC
! 220: if ((m0->m_flags & M_PKTHDR) == 0)
! 221: panic("_bus_dmamap_load_mbuf: no packet header");
! 222: #endif /* DIAGNOSTIC */
! 223:
! 224: if (m0->m_pkthdr.len > map->_dm_size)
! 225: return (EINVAL);
! 226:
! 227: first = 1;
! 228: seg = 0;
! 229: error = 0;
! 230: for (m = m0; m != NULL && error == 0; m = m->m_next) {
! 231: if (m->m_len == 0)
! 232: continue;
! 233: error = _bus_dmamap_load_buffer(t, map, m->m_data, m->m_len,
! 234: NULL, flags, &lastaddr, &seg, first);
! 235: first = 0;
! 236: }
! 237: if (error == 0) {
! 238: map->dm_mapsize = m0->m_pkthdr.len;
! 239: map->dm_nsegs = seg + 1;
! 240: }
! 241: #ifdef DEBUG_DMA
! 242: printf("dmamap_load_mbuf: error=%d\n", error);
! 243: #endif /* DEBUG_DMA */
! 244: return (error);
! 245: }
! 246:
! 247: /*
! 248: * Like _bus_dmamap_load(), but for uios.
! 249: */
! 250: int
! 251: _bus_dmamap_load_uio(t, map, uio, flags)
! 252: bus_dma_tag_t t;
! 253: bus_dmamap_t map;
! 254: struct uio *uio;
! 255: int flags;
! 256: {
! 257: paddr_t lastaddr;
! 258: int seg, i, error, first;
! 259: bus_size_t minlen, resid;
! 260: struct proc *p = NULL;
! 261: struct iovec *iov;
! 262: caddr_t addr;
! 263:
! 264: /*
! 265: * Make sure that on error condition we return "no valid mappings."
! 266: */
! 267: map->dm_mapsize = 0;
! 268: map->dm_nsegs = 0;
! 269:
! 270: resid = uio->uio_resid;
! 271: iov = uio->uio_iov;
! 272:
! 273: if (uio->uio_segflg == UIO_USERSPACE) {
! 274: p = uio->uio_procp;
! 275: #ifdef DIAGNOSTIC
! 276: if (p == NULL)
! 277: panic("_bus_dmamap_load_uio: USERSPACE but no proc");
! 278: #endif
! 279: }
! 280:
! 281: first = 1;
! 282: seg = 0;
! 283: error = 0;
! 284: for (i = 0; i < uio->uio_iovcnt && resid != 0 && error == 0; i++) {
! 285: /*
! 286: * Now at the first iovec to load. Load each iovec
! 287: * until we have exhausted the residual count.
! 288: */
! 289: minlen = resid < iov[i].iov_len ? resid : iov[i].iov_len;
! 290: addr = (caddr_t)iov[i].iov_base;
! 291:
! 292: error = _bus_dmamap_load_buffer(t, map, addr, minlen,
! 293: p, flags, &lastaddr, &seg, first);
! 294: first = 0;
! 295:
! 296: resid -= minlen;
! 297: }
! 298: if (error == 0) {
! 299: map->dm_mapsize = uio->uio_resid;
! 300: map->dm_nsegs = seg + 1;
! 301: }
! 302: return (error);
! 303: }
! 304:
! 305: /*
! 306: * Like _bus_dmamap_load(), but for raw memory allocated with
! 307: * bus_dmamem_alloc().
! 308: */
! 309: int
! 310: _bus_dmamap_load_raw(t, map, segs, nsegs, size, flags)
! 311: bus_dma_tag_t t;
! 312: bus_dmamap_t map;
! 313: bus_dma_segment_t *segs;
! 314: int nsegs;
! 315: bus_size_t size;
! 316: int flags;
! 317: {
! 318:
! 319: panic("_bus_dmamap_load_raw: not implemented");
! 320: }
! 321:
! 322: /*
! 323: * Common function for unloading a DMA map. May be called by
! 324: * bus-specific DMA map unload functions.
! 325: */
! 326: void
! 327: _bus_dmamap_unload(t, map)
! 328: bus_dma_tag_t t;
! 329: bus_dmamap_t map;
! 330: {
! 331:
! 332: #ifdef DEBUG_DMA
! 333: printf("dmamap_unload: t=%p map=%p\n", t, map);
! 334: #endif /* DEBUG_DMA */
! 335:
! 336: /*
! 337: * No resources to free; just mark the mappings as
! 338: * invalid.
! 339: */
! 340: map->dm_mapsize = 0;
! 341: map->dm_nsegs = 0;
! 342: }
! 343:
! 344: /*
! 345: * Common function for DMA map synchronization. May be called
! 346: * by bus-specific DMA map synchronization functions.
! 347: */
! 348: void
! 349: _bus_dmamap_sync(t, map, offset, len, ops)
! 350: bus_dma_tag_t t;
! 351: bus_dmamap_t map;
! 352: bus_addr_t offset;
! 353: bus_size_t len;
! 354: int ops;
! 355: {
! 356: #ifdef DEBUG_DMA
! 357: printf("dmamap_sync: t=%p map=%p offset=%lx len=%lx ops=%x\n",
! 358: t, map, offset, len, ops);
! 359: #endif /* DEBUG_DMA */
! 360: /*
! 361: * A vax only has snoop-cache, so this routine is a no-op.
! 362: */
! 363: return;
! 364: }
! 365:
! 366: /*
! 367: * Common function for DMA-safe memory allocation. May be called
! 368: * by bus-specific DMA memory allocation functions.
! 369: */
! 370:
! 371: int
! 372: _bus_dmamem_alloc(t, size, alignment, boundary, segs, nsegs, rsegs, flags)
! 373: bus_dma_tag_t t;
! 374: bus_size_t size, alignment, boundary;
! 375: bus_dma_segment_t *segs;
! 376: int nsegs;
! 377: int *rsegs;
! 378: int flags;
! 379: {
! 380: int error;
! 381:
! 382: error = (_bus_dmamem_alloc_range(t, size, alignment, boundary,
! 383: segs, nsegs, rsegs, flags, round_page(avail_start),
! 384: trunc_page(avail_end)));
! 385: return(error);
! 386: }
! 387:
! 388: /*
! 389: * Common function for freeing DMA-safe memory. May be called by
! 390: * bus-specific DMA memory free functions.
! 391: */
! 392: void
! 393: _bus_dmamem_free(t, segs, nsegs)
! 394: bus_dma_tag_t t;
! 395: bus_dma_segment_t *segs;
! 396: int nsegs;
! 397: {
! 398: struct vm_page *m;
! 399: bus_addr_t addr;
! 400: struct pglist mlist;
! 401: int curseg;
! 402:
! 403: #ifdef DEBUG_DMA
! 404: printf("dmamem_free: t=%p segs=%p nsegs=%x\n", t, segs, nsegs);
! 405: #endif /* DEBUG_DMA */
! 406:
! 407: /*
! 408: * Build a list of pages to free back to the VM system.
! 409: */
! 410: TAILQ_INIT(&mlist);
! 411: for (curseg = 0; curseg < nsegs; curseg++) {
! 412: for (addr = segs[curseg].ds_addr;
! 413: addr < (segs[curseg].ds_addr + segs[curseg].ds_len);
! 414: addr += PAGE_SIZE) {
! 415: m = PHYS_TO_VM_PAGE(addr);
! 416: TAILQ_INSERT_TAIL(&mlist, m, pageq);
! 417: }
! 418: }
! 419: uvm_pglistfree(&mlist);
! 420: }
! 421:
! 422: /*
! 423: * Common function for mapping DMA-safe memory. May be called by
! 424: * bus-specific DMA memory map functions.
! 425: */
! 426: int
! 427: _bus_dmamem_map(t, segs, nsegs, size, kvap, flags)
! 428: bus_dma_tag_t t;
! 429: bus_dma_segment_t *segs;
! 430: int nsegs;
! 431: size_t size;
! 432: caddr_t *kvap;
! 433: int flags;
! 434: {
! 435: vaddr_t va;
! 436: bus_addr_t addr;
! 437: int curseg;
! 438:
! 439: /*
! 440: * Special case (but common):
! 441: * If there is only one physical segment then the already-mapped
! 442: * virtual address is returned, since all physical memory is already
! 443: * in the beginning of kernel virtual memory.
! 444: */
! 445: if (nsegs == 1) {
! 446: *kvap = (caddr_t)(segs[0].ds_addr | KERNBASE);
! 447: /*
! 448: * KA43 (3100/m76) must have its DMA-safe memory accessed
! 449: * through DIAGMEM. Remap it here.
! 450: */
! 451: if (vax_boardtype == VAX_BTYP_43) {
! 452: pmap_map((vaddr_t)*kvap, segs[0].ds_addr|KA43_DIAGMEM,
! 453: (segs[0].ds_addr|KA43_DIAGMEM) + size,
! 454: VM_PROT_READ|VM_PROT_WRITE);
! 455: }
! 456: return 0;
! 457: }
! 458: size = round_page(size);
! 459: va = uvm_km_valloc(kernel_map, size);
! 460:
! 461: if (va == 0)
! 462: return (ENOMEM);
! 463:
! 464: *kvap = (caddr_t)va;
! 465:
! 466: for (curseg = 0; curseg < nsegs; curseg++) {
! 467: for (addr = segs[curseg].ds_addr;
! 468: addr < (segs[curseg].ds_addr + segs[curseg].ds_len);
! 469: addr += NBPG, va += NBPG, size -= NBPG) {
! 470: if (size == 0)
! 471: panic("_bus_dmamem_map: size botch");
! 472: if (vax_boardtype == VAX_BTYP_43)
! 473: addr |= KA43_DIAGMEM;
! 474: pmap_enter(pmap_kernel(), va, addr,
! 475: VM_PROT_READ | VM_PROT_WRITE,
! 476: VM_PROT_READ | VM_PROT_WRITE | PMAP_WIRED);
! 477: }
! 478: }
! 479: pmap_update(pmap_kernel());
! 480: return (0);
! 481: }
! 482:
! 483: /*
! 484: * Common function for unmapping DMA-safe memory. May be called by
! 485: * bus-specific DMA memory unmapping functions.
! 486: */
! 487: void
! 488: _bus_dmamem_unmap(t, kva, size)
! 489: bus_dma_tag_t t;
! 490: caddr_t kva;
! 491: size_t size;
! 492: {
! 493:
! 494: #ifdef DEBUG_DMA
! 495: printf("dmamem_unmap: t=%p kva=%p size=%x\n", t, kva, size);
! 496: #endif /* DEBUG_DMA */
! 497: #ifdef DIAGNOSTIC
! 498: if ((u_long)kva & PGOFSET)
! 499: panic("_bus_dmamem_unmap");
! 500: #endif /* DIAGNOSTIC */
! 501:
! 502: /* Avoid free'ing if not mapped */
! 503: if (kva >= (caddr_t)virtual_avail)
! 504: uvm_km_free(kernel_map, (vaddr_t)kva, round_page(size));
! 505: }
! 506:
! 507: /*
! 508: * Common functin for mmap(2)'ing DMA-safe memory. May be called by
! 509: * bus-specific DMA mmap(2)'ing functions.
! 510: */
! 511: paddr_t
! 512: _bus_dmamem_mmap(t, segs, nsegs, off, prot, flags)
! 513: bus_dma_tag_t t;
! 514: bus_dma_segment_t *segs;
! 515: int nsegs;
! 516: off_t off;
! 517: int prot, flags;
! 518: {
! 519: int i;
! 520:
! 521: for (i = 0; i < nsegs; i++) {
! 522: #ifdef DIAGNOSTIC
! 523: if (off & PGOFSET)
! 524: panic("_bus_dmamem_mmap: offset unaligned");
! 525: if (segs[i].ds_addr & PGOFSET)
! 526: panic("_bus_dmamem_mmap: segment unaligned");
! 527: if (segs[i].ds_len & PGOFSET)
! 528: panic("_bus_dmamem_mmap: segment size not multiple"
! 529: " of page size");
! 530: #endif /* DIAGNOSTIC */
! 531: if (off >= segs[i].ds_len) {
! 532: off -= segs[i].ds_len;
! 533: continue;
! 534: }
! 535:
! 536: return (atop(segs[i].ds_addr + off));
! 537: }
! 538:
! 539: /* Page not found. */
! 540: return (-1);
! 541: }
! 542:
! 543: /**********************************************************************
! 544: * DMA utility functions
! 545: **********************************************************************/
! 546:
! 547: /*
! 548: * Utility function to load a linear buffer. lastaddrp holds state
! 549: * between invocations (for multiple-buffer loads). segp contains
! 550: * the starting segment on entrance, and the ending segment on exit.
! 551: * first indicates if this is the first invocation of this function.
! 552: */
! 553: int
! 554: _bus_dmamap_load_buffer(t, map, buf, buflen, p, flags, lastaddrp, segp, first)
! 555: bus_dma_tag_t t;
! 556: bus_dmamap_t map;
! 557: void *buf;
! 558: bus_size_t buflen;
! 559: struct proc *p;
! 560: int flags;
! 561: paddr_t *lastaddrp;
! 562: int *segp;
! 563: int first;
! 564: {
! 565: bus_size_t sgsize;
! 566: bus_addr_t curaddr, lastaddr, baddr, bmask;
! 567: vaddr_t vaddr = (vaddr_t)buf;
! 568: int seg;
! 569: pmap_t pmap;
! 570:
! 571: #ifdef DEBUG_DMA
! 572: printf("_bus_dmamem_load_buffer(buf=%p, len=%lx, flags=%d, 1st=%d)\n",
! 573: buf, buflen, flags, first);
! 574: #endif /* DEBUG_DMA */
! 575:
! 576: if (p != NULL)
! 577: pmap = p->p_vmspace->vm_map.pmap;
! 578: else
! 579: pmap = pmap_kernel();
! 580:
! 581: lastaddr = *lastaddrp;
! 582: bmask = ~(map->_dm_boundary - 1);
! 583:
! 584: for (seg = *segp; buflen > 0; ) {
! 585: /*
! 586: * Get the physical address for this segment.
! 587: */
! 588: pmap_extract(pmap, (vaddr_t)vaddr, &curaddr);
! 589: #if 0
! 590: /*
! 591: * Make sure we're in an allowed DMA range.
! 592: */
! 593: if (t->_ranges != NULL &&
! 594: _bus_dma_inrange(t->_ranges, t->_nranges, curaddr) == 0)
! 595: return (EINVAL);
! 596: #endif
! 597:
! 598: /*
! 599: * Compute the segment size, and adjust counts.
! 600: */
! 601: sgsize = NBPG - ((u_long)vaddr & PGOFSET);
! 602: if (buflen < sgsize)
! 603: sgsize = buflen;
! 604:
! 605: /*
! 606: * Make sure we don't cross any boundaries.
! 607: */
! 608: if (map->_dm_boundary > 0) {
! 609: baddr = (curaddr + map->_dm_boundary) & bmask;
! 610: if (sgsize > (baddr - curaddr))
! 611: sgsize = (baddr - curaddr);
! 612: }
! 613:
! 614: /*
! 615: * Insert chunk into a segment, coalescing with
! 616: * previous segment if possible.
! 617: */
! 618: if (first) {
! 619: map->dm_segs[seg].ds_addr = curaddr;
! 620: map->dm_segs[seg].ds_len = sgsize;
! 621: first = 0;
! 622: } else {
! 623: if (curaddr == lastaddr &&
! 624: (map->dm_segs[seg].ds_len + sgsize) <=
! 625: map->_dm_maxsegsz &&
! 626: (map->_dm_boundary == 0 ||
! 627: (map->dm_segs[seg].ds_addr & bmask) ==
! 628: (curaddr & bmask)))
! 629: map->dm_segs[seg].ds_len += sgsize;
! 630: else {
! 631: if (++seg >= map->_dm_segcnt)
! 632: break;
! 633: map->dm_segs[seg].ds_addr = curaddr;
! 634: map->dm_segs[seg].ds_len = sgsize;
! 635: }
! 636: }
! 637:
! 638: lastaddr = curaddr + sgsize;
! 639: vaddr += sgsize;
! 640: buflen -= sgsize;
! 641: }
! 642:
! 643: *segp = seg;
! 644: *lastaddrp = lastaddr;
! 645:
! 646: /*
! 647: * Did we fit?
! 648: */
! 649: if (buflen != 0)
! 650: return (EFBIG); /* XXX better return value here? */
! 651: return (0);
! 652: }
! 653:
! 654: /*
! 655: * Check to see if the specified page is in an allowed DMA range.
! 656: */
! 657: int
! 658: _bus_dma_inrange(ranges, nranges, curaddr)
! 659: bus_dma_segment_t *ranges;
! 660: int nranges;
! 661: bus_addr_t curaddr;
! 662: {
! 663: bus_dma_segment_t *ds;
! 664: int i;
! 665:
! 666: for (i = 0, ds = ranges; i < nranges; i++, ds++) {
! 667: if (curaddr >= ds->ds_addr &&
! 668: round_page(curaddr) <= (ds->ds_addr + ds->ds_len))
! 669: return (1);
! 670: }
! 671:
! 672: return (0);
! 673: }
! 674:
! 675: /*
! 676: * Allocate physical memory from the given physical address range.
! 677: * Called by DMA-safe memory allocation methods.
! 678: */
! 679: int
! 680: _bus_dmamem_alloc_range(t, size, alignment, boundary, segs, nsegs, rsegs,
! 681: flags, low, high)
! 682: bus_dma_tag_t t;
! 683: bus_size_t size, alignment, boundary;
! 684: bus_dma_segment_t *segs;
! 685: int nsegs;
! 686: int *rsegs;
! 687: int flags;
! 688: vaddr_t low;
! 689: vaddr_t high;
! 690: {
! 691: paddr_t curaddr, lastaddr;
! 692: struct vm_page *m;
! 693: struct pglist mlist;
! 694: int curseg, error;
! 695:
! 696: #ifdef DEBUG_DMA
! 697: printf("alloc_range: t=%p size=%lx align=%lx boundary=%lx segs=%p nsegs=%x rsegs=%p flags=%x lo=%lx hi=%lx\n",
! 698: t, size, alignment, boundary, segs, nsegs, rsegs, flags, low, high);
! 699: #endif /* DEBUG_DMA */
! 700:
! 701: /* Always round the size. */
! 702: size = round_page(size);
! 703:
! 704: /*
! 705: * Allocate pages from the VM system.
! 706: */
! 707: TAILQ_INIT(&mlist);
! 708: error = uvm_pglistalloc(size, low, high, alignment, boundary,
! 709: &mlist, nsegs, (flags & BUS_DMA_NOWAIT) == 0);
! 710: if (error)
! 711: return (error);
! 712:
! 713: /*
! 714: * Compute the location, size, and number of segments actually
! 715: * returned by the VM code.
! 716: */
! 717: m = TAILQ_FIRST(&mlist);
! 718: curseg = 0;
! 719: lastaddr = segs[curseg].ds_addr = VM_PAGE_TO_PHYS(m);
! 720: segs[curseg].ds_len = PAGE_SIZE;
! 721: #ifdef DEBUG_DMA
! 722: printf("alloc: page %lx\n", lastaddr);
! 723: #endif /* DEBUG_DMA */
! 724: m = TAILQ_NEXT(m, pageq);
! 725:
! 726: for (; m != TAILQ_END(&mlist); m = TAILQ_NEXT(m, pageq)) {
! 727: curaddr = VM_PAGE_TO_PHYS(m);
! 728: #ifdef DIAGNOSTIC
! 729: if (curaddr < low || curaddr >= high) {
! 730: printf("vm_page_alloc_memory returned non-sensical"
! 731: " address 0x%lx\n", curaddr);
! 732: panic("_bus_dmamem_alloc_range");
! 733: }
! 734: #endif /* DIAGNOSTIC */
! 735: #ifdef DEBUG_DMA
! 736: printf("alloc: page %lx\n", curaddr);
! 737: #endif /* DEBUG_DMA */
! 738: if (curaddr == (lastaddr + PAGE_SIZE))
! 739: segs[curseg].ds_len += PAGE_SIZE;
! 740: else {
! 741: curseg++;
! 742: segs[curseg].ds_addr = curaddr;
! 743: segs[curseg].ds_len = PAGE_SIZE;
! 744: }
! 745: lastaddr = curaddr;
! 746: }
! 747:
! 748: *rsegs = curseg + 1;
! 749:
! 750: return (0);
! 751: }
! 752:
! 753: /*
! 754: * "generic" DMA struct, nothing special.
! 755: */
! 756: struct vax_bus_dma_tag vax_bus_dma_tag = {
! 757: NULL,
! 758: 0,
! 759: 0,
! 760: 0,
! 761: 0,
! 762: 0,
! 763: _bus_dmamap_create,
! 764: _bus_dmamap_destroy,
! 765: _bus_dmamap_load,
! 766: _bus_dmamap_load_mbuf,
! 767: _bus_dmamap_load_uio,
! 768: _bus_dmamap_load_raw,
! 769: _bus_dmamap_unload,
! 770: _bus_dmamap_sync,
! 771: _bus_dmamem_alloc,
! 772: _bus_dmamem_free,
! 773: _bus_dmamem_map,
! 774: _bus_dmamem_unmap,
! 775: _bus_dmamem_mmap,
! 776: };
CVSweb