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