1 /* $NetBSD: isa_dma.c,v 1.1 2001/03/09 20:55:47 leo Exp $ */ 2 3 #define ISA_DMA_STATS 4 5 /*- 6 * Copyright (c) 1996, 1997, 1998 The NetBSD Foundation, Inc. 7 * All rights reserved. 8 * 9 * This code is derived from software contributed to The NetBSD Foundation 10 * by Charles M. Hannum and by Jason R. Thorpe of the Numerical Aerospace 11 * Simulation Facility, NASA Ames Research Center. 12 * 13 * Redistribution and use in source and binary forms, with or without 14 * modification, are permitted provided that the following conditions 15 * are met: 16 * 1. Redistributions of source code must retain the above copyright 17 * notice, this list of conditions and the following disclaimer. 18 * 2. Redistributions in binary form must reproduce the above copyright 19 * notice, this list of conditions and the following disclaimer in the 20 * documentation and/or other materials provided with the distribution. 21 * 3. All advertising materials mentioning features or use of this software 22 * must display the following acknowledgement: 23 * This product includes software developed by the NetBSD 24 * Foundation, Inc. and its contributors. 25 * 4. Neither the name of The NetBSD Foundation nor the names of its 26 * contributors may be used to endorse or promote products derived 27 * from this software without specific prior written permission. 28 * 29 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 30 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 31 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 32 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 33 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 34 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 35 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 36 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 37 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 38 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 39 * POSSIBILITY OF SUCH DAMAGE. 40 */ 41 #include <sys/param.h> 42 #include <sys/systm.h> 43 #include <sys/kernel.h> 44 #include <sys/syslog.h> 45 #include <sys/device.h> 46 #include <sys/malloc.h> 47 #include <sys/proc.h> 48 #include <sys/mbuf.h> 49 50 #define _ATARI_BUS_DMA_PRIVATE 51 #include <machine/bus.h> 52 53 #include <dev/isa/isareg.h> 54 #include <dev/isa/isavar.h> 55 56 #include <uvm/uvm_extern.h> 57 58 /* 59 * ISA can only DMA to 0-16M. 60 */ 61 #define ISA_DMA_BOUNCE_THRESHOLD (16 * 1024 * 1024) 62 63 extern paddr_t avail_end; 64 65 /* 66 * Cookie used by ISA dma. A pointer to one of these it stashed in 67 * the DMA map. 68 */ 69 struct atari_isa_dma_cookie { 70 int id_flags; /* flags; see below */ 71 72 /* 73 * Information about the original buffer used during 74 * DMA map syncs. Note that origibuflen is only used 75 * for ID_BUFTYPE_LINEAR. 76 */ 77 void *id_origbuf; /* pointer to orig buffer if 78 bouncing */ 79 bus_size_t id_origbuflen; /* ...and size */ 80 int id_buftype; /* type of buffer */ 81 82 void *id_bouncebuf; /* pointer to the bounce buffer */ 83 bus_size_t id_bouncebuflen; /* ...and size */ 84 int id_nbouncesegs; /* number of valid bounce segs */ 85 bus_dma_segment_t id_bouncesegs[0]; /* array of bounce buffer 86 physical memory segments */ 87 }; 88 89 /* id_flags */ 90 #define ID_MIGHT_NEED_BOUNCE 0x01 /* map could need bounce buffers */ 91 #define ID_HAS_BOUNCE 0x02 /* map currently has bounce buffers */ 92 #define ID_IS_BOUNCING 0x04 /* map is bouncing current xfer */ 93 94 /* id_buftype */ 95 #define ID_BUFTYPE_INVALID 0 96 #define ID_BUFTYPE_LINEAR 1 97 #define ID_BUFTYPE_MBUF 2 98 #define ID_BUFTYPE_UIO 3 99 #define ID_BUFTYPE_RAW 4 100 101 int _isa_bus_dmamap_create __P((bus_dma_tag_t, bus_size_t, int, 102 bus_size_t, bus_size_t, int, bus_dmamap_t *)); 103 void _isa_bus_dmamap_destroy __P((bus_dma_tag_t, bus_dmamap_t)); 104 int _isa_bus_dmamap_load __P((bus_dma_tag_t, bus_dmamap_t, void *, 105 bus_size_t, struct proc *, int)); 106 int _isa_bus_dmamap_load_mbuf __P((bus_dma_tag_t, bus_dmamap_t, 107 struct mbuf *, int)); 108 int _isa_bus_dmamap_load_uio __P((bus_dma_tag_t, bus_dmamap_t, 109 struct uio *, int)); 110 int _isa_bus_dmamap_load_raw __P((bus_dma_tag_t, bus_dmamap_t, 111 bus_dma_segment_t *, int, bus_size_t, int)); 112 void _isa_bus_dmamap_unload __P((bus_dma_tag_t, bus_dmamap_t)); 113 void _isa_bus_dmamap_sync __P((bus_dma_tag_t, bus_dmamap_t, 114 bus_addr_t, bus_size_t, int)); 115 116 int _isa_bus_dmamem_alloc __P((bus_dma_tag_t, bus_size_t, bus_size_t, 117 bus_size_t, bus_dma_segment_t *, int, int *, int)); 118 119 int _isa_dma_alloc_bouncebuf __P((bus_dma_tag_t, bus_dmamap_t, 120 bus_size_t, int)); 121 void _isa_dma_free_bouncebuf __P((bus_dma_tag_t, bus_dmamap_t)); 122 123 /* 124 * Entry points for ISA DMA. These are mostly wrappers around 125 * the generic functions that understand how to deal with bounce 126 * buffers, if necessary. 127 */ 128 struct atari_bus_dma_tag isa_bus_dma_tag = { 129 ISA_DMA_BOUNCE_THRESHOLD, 130 0, 131 _isa_bus_dmamap_create, 132 _isa_bus_dmamap_destroy, 133 _isa_bus_dmamap_load, 134 _isa_bus_dmamap_load_mbuf, 135 _isa_bus_dmamap_load_uio, 136 _isa_bus_dmamap_load_raw, 137 _isa_bus_dmamap_unload, 138 _isa_bus_dmamap_sync, 139 }; 140 141 /********************************************************************** 142 * bus.h dma interface entry points 143 **********************************************************************/ 144 145 #ifdef ISA_DMA_STATS 146 #define STAT_INCR(v) (v)++ 147 #define STAT_DECR(v) do { \ 148 if ((v) == 0) \ 149 printf("%s:%d -- Already 0!\n", __FILE__, __LINE__); \ 150 else \ 151 (v)--; \ 152 } while (0) 153 u_long isa_dma_stats_loads; 154 u_long isa_dma_stats_bounces; 155 u_long isa_dma_stats_nbouncebufs; 156 #else 157 #define STAT_INCR(v) 158 #define STAT_DECR(v) 159 #endif 160 161 /* 162 * Create an ISA DMA map. 163 */ 164 int 165 _isa_bus_dmamap_create(t, size, nsegments, maxsegsz, boundary, flags, dmamp) 166 bus_dma_tag_t t; 167 bus_size_t size; 168 int nsegments; 169 bus_size_t maxsegsz; 170 bus_size_t boundary; 171 int flags; 172 bus_dmamap_t *dmamp; 173 { 174 struct atari_isa_dma_cookie *cookie; 175 bus_dmamap_t map; 176 int error, cookieflags; 177 void *cookiestore; 178 size_t cookiesize; 179 180 /* Call common function to create the basic map. */ 181 error = _bus_dmamap_create(t, size, nsegments, maxsegsz, boundary, 182 flags, dmamp); 183 if (error) 184 return (error); 185 186 map = *dmamp; 187 map->_dm_cookie = NULL; 188 189 cookiesize = sizeof(struct atari_isa_dma_cookie); 190 191 /* 192 * ISA only has 24-bits of address space. This means 193 * we can't DMA to pages over 16M. In order to DMA to 194 * arbitrary buffers, we use "bounce buffers" - pages 195 * in memory below the 16M boundary. On DMA reads, 196 * DMA happens to the bounce buffers, and is copied into 197 * the caller's buffer. On writes, data is copied into 198 * but bounce buffer, and the DMA happens from those 199 * pages. To software using the DMA mapping interface, 200 * this looks simply like a data cache. 201 * 202 * If we have more than 16M of RAM in the system, we may 203 * need bounce buffers. We check and remember that here. 204 * 205 * There are exceptions, however. VLB devices can do 206 * 32-bit DMA, and indicate that here. 207 * 208 * ...or, there is an opposite case. The most segments 209 * a transfer will require is (maxxfer / PAGE_SIZE) + 1. If 210 * the caller can't handle that many segments (e.g. the 211 * ISA DMA controller), we may have to bounce it as well. 212 */ 213 if (avail_end <= t->_bounce_thresh || 214 (flags & ISABUS_DMA_32BIT) != 0) { 215 /* Bouncing not necessary due to memory size. */ 216 map->_dm_bounce_thresh = 0; 217 } 218 cookieflags = 0; 219 if (map->_dm_bounce_thresh != 0 || 220 ((map->_dm_size / PAGE_SIZE) + 1) > map->_dm_segcnt) { 221 cookieflags |= ID_MIGHT_NEED_BOUNCE; 222 cookiesize += (sizeof(bus_dma_segment_t) * map->_dm_segcnt); 223 } 224 225 /* 226 * Allocate our cookie. 227 */ 228 if ((cookiestore = malloc(cookiesize, M_DMAMAP, 229 (flags & BUS_DMA_NOWAIT) ? M_NOWAIT : M_WAITOK)) == NULL) { 230 error = ENOMEM; 231 goto out; 232 } 233 memset(cookiestore, 0, cookiesize); 234 cookie = (struct atari_isa_dma_cookie *)cookiestore; 235 cookie->id_flags = cookieflags; 236 map->_dm_cookie = cookie; 237 238 if (cookieflags & ID_MIGHT_NEED_BOUNCE) { 239 /* 240 * Allocate the bounce pages now if the caller 241 * wishes us to do so. 242 */ 243 if ((flags & BUS_DMA_ALLOCNOW) == 0) 244 goto out; 245 246 error = _isa_dma_alloc_bouncebuf(t, map, size, flags); 247 } 248 249 out: 250 if (error) { 251 if (map->_dm_cookie != NULL) 252 free(map->_dm_cookie, M_DMAMAP); 253 _bus_dmamap_destroy(t, map); 254 } 255 return (error); 256 } 257 258 /* 259 * Destroy an ISA DMA map. 260 */ 261 void 262 _isa_bus_dmamap_destroy(t, map) 263 bus_dma_tag_t t; 264 bus_dmamap_t map; 265 { 266 struct atari_isa_dma_cookie *cookie = map->_dm_cookie; 267 268 /* 269 * Free any bounce pages this map might hold. 270 */ 271 if (cookie->id_flags & ID_HAS_BOUNCE) 272 _isa_dma_free_bouncebuf(t, map); 273 274 free(cookie, M_DMAMAP); 275 _bus_dmamap_destroy(t, map); 276 } 277 278 /* 279 * Load an ISA DMA map with a linear buffer. 280 */ 281 int 282 _isa_bus_dmamap_load(t, map, buf, buflen, p, flags) 283 bus_dma_tag_t t; 284 bus_dmamap_t map; 285 void *buf; 286 bus_size_t buflen; 287 struct proc *p; 288 int flags; 289 { 290 struct atari_isa_dma_cookie *cookie = map->_dm_cookie; 291 int error; 292 293 STAT_INCR(isa_dma_stats_loads); 294 295 /* 296 * Make sure that on error condition we return "no valid mappings." 297 */ 298 map->dm_mapsize = 0; 299 map->dm_nsegs = 0; 300 301 /* 302 * Try to load the map the normal way. If this errors out, 303 * and we can bounce, we will. 304 */ 305 error = _bus_dmamap_load(t, map, buf, buflen, p, flags); 306 if (error == 0 || 307 (error != 0 && (cookie->id_flags & ID_MIGHT_NEED_BOUNCE) == 0)) 308 return (error); 309 310 /* 311 * First attempt failed; bounce it. 312 */ 313 314 STAT_INCR(isa_dma_stats_bounces); 315 316 /* 317 * Allocate bounce pages, if necessary. 318 */ 319 if ((cookie->id_flags & ID_HAS_BOUNCE) == 0) { 320 error = _isa_dma_alloc_bouncebuf(t, map, buflen, flags); 321 if (error) 322 return (error); 323 } 324 325 /* 326 * Cache a pointer to the caller's buffer and load the DMA map 327 * with the bounce buffer. 328 */ 329 cookie->id_origbuf = buf; 330 cookie->id_origbuflen = buflen; 331 cookie->id_buftype = ID_BUFTYPE_LINEAR; 332 error = _bus_dmamap_load(t, map, cookie->id_bouncebuf, buflen, 333 p, flags); 334 if (error) { 335 /* 336 * Free the bounce pages, unless our resources 337 * are reserved for our exclusive use. 338 */ 339 if ((map->_dm_flags & BUS_DMA_ALLOCNOW) == 0) 340 _isa_dma_free_bouncebuf(t, map); 341 return (error); 342 } 343 344 /* ...so _isa_bus_dmamap_sync() knows we're bouncing */ 345 cookie->id_flags |= ID_IS_BOUNCING; 346 return (0); 347 } 348 349 /* 350 * Like _isa_bus_dmamap_load(), but for mbufs. 351 */ 352 int 353 _isa_bus_dmamap_load_mbuf(t, map, m0, flags) 354 bus_dma_tag_t t; 355 bus_dmamap_t map; 356 struct mbuf *m0; 357 int flags; 358 { 359 struct atari_isa_dma_cookie *cookie = map->_dm_cookie; 360 int error; 361 362 /* 363 * Make sure on error condition we return "no valid mappings." 364 */ 365 map->dm_mapsize = 0; 366 map->dm_nsegs = 0; 367 368 #ifdef DIAGNOSTIC 369 if ((m0->m_flags & M_PKTHDR) == 0) 370 panic("_isa_bus_dmamap_load_mbuf: no packet header"); 371 #endif 372 373 if (m0->m_pkthdr.len > map->_dm_size) 374 return (EINVAL); 375 376 /* 377 * Try to load the map the normal way. If this errors out, 378 * and we can bounce, we will. 379 */ 380 error = _bus_dmamap_load_mbuf(t, map, m0, flags); 381 if (error == 0 || 382 (error != 0 && (cookie->id_flags & ID_MIGHT_NEED_BOUNCE) == 0)) 383 return (error); 384 385 /* 386 * First attempt failed; bounce it. 387 */ 388 389 STAT_INCR(isa_dma_stats_bounces); 390 391 /* 392 * Allocate bounce pages, if necessary. 393 */ 394 if ((cookie->id_flags & ID_HAS_BOUNCE) == 0) { 395 error = _isa_dma_alloc_bouncebuf(t, map, m0->m_pkthdr.len, 396 flags); 397 if (error) 398 return (error); 399 } 400 401 /* 402 * Cache a pointer to the caller's buffer and load the DMA map 403 * with the bounce buffer. 404 */ 405 cookie->id_origbuf = m0; 406 cookie->id_origbuflen = m0->m_pkthdr.len; /* not really used */ 407 cookie->id_buftype = ID_BUFTYPE_MBUF; 408 error = _bus_dmamap_load(t, map, cookie->id_bouncebuf, 409 m0->m_pkthdr.len, NULL, flags); 410 if (error) { 411 /* 412 * Free the bounce pages, unless our resources 413 * are reserved for our exclusive use. 414 */ 415 if ((map->_dm_flags & BUS_DMA_ALLOCNOW) == 0) 416 _isa_dma_free_bouncebuf(t, map); 417 return (error); 418 } 419 420 /* ...so _isa_bus_dmamap_sync() knows we're bouncing */ 421 cookie->id_flags |= ID_IS_BOUNCING; 422 return (0); 423 } 424 425 /* 426 * Like _isa_bus_dmamap_load(), but for uios. 427 */ 428 int 429 _isa_bus_dmamap_load_uio(t, map, uio, flags) 430 bus_dma_tag_t t; 431 bus_dmamap_t map; 432 struct uio *uio; 433 int flags; 434 { 435 436 panic("_isa_bus_dmamap_load_uio: not implemented"); 437 } 438 439 /* 440 * Like _isa_bus_dmamap_load(), but for raw memory allocated with 441 * bus_dmamem_alloc(). 442 */ 443 int 444 _isa_bus_dmamap_load_raw(t, map, segs, nsegs, size, flags) 445 bus_dma_tag_t t; 446 bus_dmamap_t map; 447 bus_dma_segment_t *segs; 448 int nsegs; 449 bus_size_t size; 450 int flags; 451 { 452 453 panic("_isa_bus_dmamap_load_raw: not implemented"); 454 } 455 456 /* 457 * Unload an ISA DMA map. 458 */ 459 void 460 _isa_bus_dmamap_unload(t, map) 461 bus_dma_tag_t t; 462 bus_dmamap_t map; 463 { 464 struct atari_isa_dma_cookie *cookie = map->_dm_cookie; 465 466 /* 467 * If we have bounce pages, free them, unless they're 468 * reserved for our exclusive use. 469 */ 470 if ((cookie->id_flags & ID_HAS_BOUNCE) && 471 (map->_dm_flags & BUS_DMA_ALLOCNOW) == 0) 472 _isa_dma_free_bouncebuf(t, map); 473 474 cookie->id_flags &= ~ID_IS_BOUNCING; 475 cookie->id_buftype = ID_BUFTYPE_INVALID; 476 477 /* 478 * Do the generic bits of the unload. 479 */ 480 _bus_dmamap_unload(t, map); 481 } 482 483 /* 484 * Synchronize an ISA DMA map. 485 */ 486 void 487 _isa_bus_dmamap_sync(t, map, offset, len, ops) 488 bus_dma_tag_t t; 489 bus_dmamap_t map; 490 bus_addr_t offset; 491 bus_size_t len; 492 int ops; 493 { 494 struct atari_isa_dma_cookie *cookie = map->_dm_cookie; 495 496 /* 497 * Mixing PRE and POST operations is not allowed. 498 */ 499 if ((ops & (BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE)) != 0 && 500 (ops & (BUS_DMASYNC_POSTREAD|BUS_DMASYNC_POSTWRITE)) != 0) 501 panic("_isa_bus_dmamap_sync: mix PRE and POST"); 502 503 #ifdef DIAGNOSTIC 504 if ((ops & (BUS_DMASYNC_PREWRITE|BUS_DMASYNC_POSTREAD)) != 0) { 505 if (offset >= map->dm_mapsize) 506 panic("_isa_bus_dmamap_sync: bad offset"); 507 if (len == 0 || (offset + len) > map->dm_mapsize) 508 panic("_isa_bus_dmamap_sync: bad length"); 509 } 510 #endif 511 512 /* 513 * If we're not bouncing, just return; nothing to do. 514 */ 515 if ((cookie->id_flags & ID_IS_BOUNCING) == 0) 516 return; 517 518 switch (cookie->id_buftype) { 519 case ID_BUFTYPE_LINEAR: 520 /* 521 * Nothing to do for pre-read. 522 */ 523 524 if (ops & BUS_DMASYNC_PREWRITE) { 525 /* 526 * Copy the caller's buffer to the bounce buffer. 527 */ 528 memcpy((char *)cookie->id_bouncebuf + offset, 529 (char *)cookie->id_origbuf + offset, len); 530 } 531 532 if (ops & BUS_DMASYNC_POSTREAD) { 533 /* 534 * Copy the bounce buffer to the caller's buffer. 535 */ 536 memcpy((char *)cookie->id_origbuf + offset, 537 (char *)cookie->id_bouncebuf + offset, len); 538 } 539 540 /* 541 * Nothing to do for post-write. 542 */ 543 break; 544 545 case ID_BUFTYPE_MBUF: 546 { 547 struct mbuf *m, *m0 = cookie->id_origbuf; 548 bus_size_t minlen, moff; 549 550 /* 551 * Nothing to do for pre-read. 552 */ 553 554 if (ops & BUS_DMASYNC_PREWRITE) { 555 /* 556 * Copy the caller's buffer to the bounce buffer. 557 */ 558 m_copydata(m0, offset, len, 559 (char *)cookie->id_bouncebuf + offset); 560 } 561 562 if (ops & BUS_DMASYNC_POSTREAD) { 563 /* 564 * Copy the bounce buffer to the caller's buffer. 565 */ 566 for (moff = offset, m = m0; m != NULL && len != 0; 567 m = m->m_next) { 568 /* Find the beginning mbuf. */ 569 if (moff >= m->m_len) { 570 moff -= m->m_len; 571 continue; 572 } 573 574 /* 575 * Now at the first mbuf to sync; nail 576 * each one until we have exhausted the 577 * length. 578 */ 579 minlen = len < m->m_len - moff ? 580 len : m->m_len - moff; 581 582 memcpy(mtod(m, caddr_t) + moff, 583 (char *)cookie->id_bouncebuf + offset, 584 minlen); 585 586 moff = 0; 587 len -= minlen; 588 offset += minlen; 589 } 590 } 591 592 /* 593 * Nothing to do for post-write. 594 */ 595 break; 596 } 597 598 case ID_BUFTYPE_UIO: 599 panic("_isa_bus_dmamap_sync: ID_BUFTYPE_UIO"); 600 break; 601 602 case ID_BUFTYPE_RAW: 603 panic("_isa_bus_dmamap_sync: ID_BUFTYPE_RAW"); 604 break; 605 606 case ID_BUFTYPE_INVALID: 607 panic("_isa_bus_dmamap_sync: ID_BUFTYPE_INVALID"); 608 break; 609 610 default: 611 printf("unknown buffer type %d\n", cookie->id_buftype); 612 panic("_isa_bus_dmamap_sync"); 613 } 614 } 615 616 /* 617 * Allocate memory safe for ISA DMA. 618 */ 619 int 620 _isa_bus_dmamem_alloc(t, size, alignment, boundary, segs, nsegs, rsegs, flags) 621 bus_dma_tag_t t; 622 bus_size_t size, alignment, boundary; 623 bus_dma_segment_t *segs; 624 int nsegs; 625 int *rsegs; 626 int flags; 627 { 628 paddr_t high; 629 630 if (avail_end > ISA_DMA_BOUNCE_THRESHOLD) 631 high = trunc_page(ISA_DMA_BOUNCE_THRESHOLD); 632 else 633 high = trunc_page(avail_end); 634 635 return (bus_dmamem_alloc_range(t, size, alignment, boundary, 636 segs, nsegs, rsegs, flags, 0, high)); 637 } 638 639 /********************************************************************** 640 * ISA DMA utility functions 641 **********************************************************************/ 642 643 int 644 _isa_dma_alloc_bouncebuf(t, map, size, flags) 645 bus_dma_tag_t t; 646 bus_dmamap_t map; 647 bus_size_t size; 648 int flags; 649 { 650 struct atari_isa_dma_cookie *cookie = map->_dm_cookie; 651 int error = 0; 652 653 cookie->id_bouncebuflen = round_page(size); 654 error = _isa_bus_dmamem_alloc(t, cookie->id_bouncebuflen, 655 PAGE_SIZE, map->_dm_boundary, cookie->id_bouncesegs, 656 map->_dm_segcnt, &cookie->id_nbouncesegs, flags); 657 if (error) 658 goto out; 659 error = bus_dmamem_map(t, cookie->id_bouncesegs, 660 cookie->id_nbouncesegs, cookie->id_bouncebuflen, 661 (caddr_t *)&cookie->id_bouncebuf, flags); 662 663 out: 664 if (error) { 665 bus_dmamem_free(t, cookie->id_bouncesegs, 666 cookie->id_nbouncesegs); 667 cookie->id_bouncebuflen = 0; 668 cookie->id_nbouncesegs = 0; 669 } else { 670 cookie->id_flags |= ID_HAS_BOUNCE; 671 STAT_INCR(isa_dma_stats_nbouncebufs); 672 } 673 674 return (error); 675 } 676 677 void 678 _isa_dma_free_bouncebuf(t, map) 679 bus_dma_tag_t t; 680 bus_dmamap_t map; 681 { 682 struct atari_isa_dma_cookie *cookie = map->_dm_cookie; 683 684 STAT_DECR(isa_dma_stats_nbouncebufs); 685 686 bus_dmamem_unmap(t, cookie->id_bouncebuf, 687 cookie->id_bouncebuflen); 688 bus_dmamem_free(t, cookie->id_bouncesegs, 689 cookie->id_nbouncesegs); 690 cookie->id_bouncebuflen = 0; 691 cookie->id_nbouncesegs = 0; 692 cookie->id_flags &= ~ID_HAS_BOUNCE; 693 } 694