1 /* $NetBSD: isadma_bounce.c,v 1.4 2001/11/14 18:15:14 thorpej Exp $ */ 2 /* NetBSD: isadma_bounce.c,v 1.2 2000/06/01 05:49:36 thorpej Exp */ 3 4 /*- 5 * Copyright (c) 1996, 1997, 1998, 2000 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 #include <sys/cdefs.h> /* RCS ID & Copyright macro defns */ 42 43 __KERNEL_RCSID(0, "$NetBSD: isadma_bounce.c,v 1.4 2001/11/14 18:15:14 thorpej Exp $"); 44 45 #include <sys/param.h> 46 #include <sys/systm.h> 47 #include <sys/syslog.h> 48 #include <sys/device.h> 49 #include <sys/malloc.h> 50 #include <sys/proc.h> 51 #include <sys/mbuf.h> 52 53 #define _ARC_BUS_DMA_PRIVATE 54 #include <machine/bus.h> 55 56 #include <dev/isa/isareg.h> 57 #include <dev/isa/isavar.h> 58 59 #include <uvm/uvm_extern.h> 60 61 extern paddr_t avail_end; /* from pmap.c */ 62 63 /* 64 * ISA can only DMA to 0-16M. 65 */ 66 #define ISA_DMA_BOUNCE_THRESHOLD (16 * 1024 * 1024) 67 68 /* 69 * Cookie used by bouncing ISA DMA. A pointer to one of these is stashed 70 * in the DMA map. 71 */ 72 struct isadma_bounce_cookie { 73 int id_flags; /* flags; see below */ 74 75 /* 76 * Information about the original buffer used during 77 * DMA map syncs. Note that origbuflen is only used 78 * for ID_BUFTYPE_LINEAR. 79 */ 80 void *id_origbuf; /* pointer to orig buffer if 81 bouncing */ 82 bus_size_t id_origbuflen; /* ...and size */ 83 int id_buftype; /* type of buffer */ 84 85 void *id_bouncebuf; /* pointer to the bounce buffer */ 86 bus_size_t id_bouncebuflen; /* ...and size */ 87 int id_nbouncesegs; /* number of valid bounce segs */ 88 bus_dma_segment_t id_bouncesegs[1]; /* array of bounce buffer 89 physical memory segments */ 90 }; 91 92 /* id_flags */ 93 #define ID_MIGHT_NEED_BOUNCE 0x01 /* map could need bounce buffers */ 94 #define ID_HAS_BOUNCE 0x02 /* map currently has bounce buffers */ 95 #define ID_IS_BOUNCING 0x04 /* map is bouncing current xfer */ 96 97 /* id_buftype */ 98 #define ID_BUFTYPE_INVALID 0 99 #define ID_BUFTYPE_LINEAR 1 100 #define ID_BUFTYPE_MBUF 2 101 #define ID_BUFTYPE_UIO 3 102 #define ID_BUFTYPE_RAW 4 103 104 int isadma_bounce_dmamap_create(bus_dma_tag_t, bus_size_t, int, 105 bus_size_t, bus_size_t, int, bus_dmamap_t *); 106 void isadma_bounce_dmamap_destroy(bus_dma_tag_t, bus_dmamap_t); 107 int isadma_bounce_dmamap_load(bus_dma_tag_t, bus_dmamap_t, void *, 108 bus_size_t, struct proc *, int); 109 int isadma_bounce_dmamap_load_mbuf(bus_dma_tag_t, bus_dmamap_t, 110 struct mbuf *, int); 111 int isadma_bounce_dmamap_load_uio(bus_dma_tag_t, bus_dmamap_t, 112 struct uio *, int); 113 int isadma_bounce_dmamap_load_raw(bus_dma_tag_t, bus_dmamap_t, 114 bus_dma_segment_t *, int, bus_size_t, int); 115 void isadma_bounce_dmamap_unload(bus_dma_tag_t, bus_dmamap_t); 116 void isadma_bounce_dmamap_sync(bus_dma_tag_t, bus_dmamap_t, 117 bus_addr_t, bus_size_t, int); 118 int isadma_bounce_dmamem_alloc(bus_dma_tag_t, bus_size_t, bus_size_t, 119 bus_size_t, bus_dma_segment_t *, int, int *, int); 120 121 static int isadma_bounce_alloc_bouncebuf __P((bus_dma_tag_t, bus_dmamap_t, 122 bus_size_t, int)); 123 static void isadma_bounce_free_bouncebuf __P((bus_dma_tag_t, bus_dmamap_t)); 124 125 void 126 isadma_bounce_tag_init(t) 127 bus_dma_tag_t t; 128 { 129 /* 130 * Initialize the DMA tag used for ISA DMA. 131 */ 132 133 _bus_dma_tag_init(t); 134 135 t->_dmamap_create = isadma_bounce_dmamap_create; 136 t->_dmamap_destroy = isadma_bounce_dmamap_destroy; 137 t->_dmamap_load = isadma_bounce_dmamap_load; 138 t->_dmamap_load_mbuf = isadma_bounce_dmamap_load_mbuf; 139 t->_dmamap_load_uio = isadma_bounce_dmamap_load_uio; 140 t->_dmamap_load_raw = isadma_bounce_dmamap_load_raw; 141 t->_dmamap_unload = isadma_bounce_dmamap_unload; 142 t->_dmamap_sync = isadma_bounce_dmamap_sync; 143 t->_dmamem_alloc = isadma_bounce_dmamem_alloc; 144 } 145 146 /* 147 * Create an ISA DMA map. 148 */ 149 int 150 isadma_bounce_dmamap_create(bus_dma_tag_t t, bus_size_t size, int nsegments, 151 bus_size_t maxsegsz, bus_size_t boundary, int flags, bus_dmamap_t *dmamp) 152 { 153 struct isadma_bounce_cookie *cookie; 154 bus_dmamap_t map; 155 int error, cookieflags; 156 void *cookiestore; 157 size_t cookiesize; 158 159 /* Call common function to create the basic map. */ 160 error = _bus_dmamap_create(t, size, nsegments, maxsegsz, boundary, 161 flags, dmamp); 162 if (error) 163 return (error); 164 165 map = *dmamp; 166 map->_dm_cookie = NULL; 167 168 cookiesize = sizeof(*cookie); 169 170 /* 171 * ISA only has 24-bits of address space. This means 172 * we can't DMA to pages over 16M. In order to DMA to 173 * arbitrary buffers, we use "bounce buffers" - pages 174 * in memory below the 16M boundary. On DMA reads, 175 * DMA happens to the bounce buffers, and is copied into 176 * the caller's buffer. On writes, data is copied into 177 * but bounce buffer, and the DMA happens from those 178 * pages. To software using the DMA mapping interface, 179 * this looks simply like a data cache. 180 * 181 * If we have more than 16M of RAM in the system, we may 182 * need bounce buffers. We check and remember that here. 183 * 184 * ...or, there is an opposite case. The most segments 185 * a transfer will require is (maxxfer / PAGE_SIZE) + 1. If 186 * the caller can't handle that many segments (e.g. the 187 * ISA DMA controller), we may have to bounce it as well. 188 */ 189 cookieflags = 0; 190 if (avail_end > ISA_DMA_BOUNCE_THRESHOLD || 191 ((map->_dm_size / PAGE_SIZE) + 1) > map->_dm_segcnt) { 192 cookieflags |= ID_MIGHT_NEED_BOUNCE; 193 cookiesize += (sizeof(bus_dma_segment_t) * 194 (map->_dm_segcnt - 1)); 195 } 196 197 /* 198 * Allocate our cookie. 199 */ 200 if ((cookiestore = malloc(cookiesize, M_DMAMAP, 201 (flags & BUS_DMA_NOWAIT) ? M_NOWAIT : M_WAITOK)) == NULL) { 202 error = ENOMEM; 203 goto out; 204 } 205 memset(cookiestore, 0, cookiesize); 206 cookie = (struct isadma_bounce_cookie *)cookiestore; 207 cookie->id_flags = cookieflags; 208 map->_dm_cookie = cookie; 209 210 if (cookieflags & ID_MIGHT_NEED_BOUNCE) { 211 /* 212 * Allocate the bounce pages now if the caller 213 * wishes us to do so. 214 */ 215 if ((flags & BUS_DMA_ALLOCNOW) == 0) 216 goto out; 217 218 error = isadma_bounce_alloc_bouncebuf(t, map, size, flags); 219 } 220 221 out: 222 if (error) { 223 if (map->_dm_cookie != NULL) 224 free(map->_dm_cookie, M_DMAMAP); 225 _bus_dmamap_destroy(t, map); 226 } 227 return (error); 228 } 229 230 /* 231 * Destroy an ISA DMA map. 232 */ 233 void 234 isadma_bounce_dmamap_destroy(bus_dma_tag_t t, bus_dmamap_t map) 235 { 236 struct isadma_bounce_cookie *cookie = map->_dm_cookie; 237 238 /* 239 * Free any bounce pages this map might hold. 240 */ 241 if (cookie->id_flags & ID_HAS_BOUNCE) 242 isadma_bounce_free_bouncebuf(t, map); 243 244 free(cookie, M_DMAMAP); 245 _bus_dmamap_destroy(t, map); 246 } 247 248 /* 249 * Load an ISA DMA map with a linear buffer. 250 */ 251 int 252 isadma_bounce_dmamap_load(bus_dma_tag_t t, bus_dmamap_t map, void *buf, 253 bus_size_t buflen, struct proc *p, int flags) 254 { 255 struct isadma_bounce_cookie *cookie = map->_dm_cookie; 256 int error; 257 258 /* 259 * Make sure that on error condition we return "no valid mappings." 260 */ 261 map->dm_mapsize = 0; 262 map->dm_nsegs = 0; 263 264 /* 265 * Try to load the map the normal way. If this errors out, 266 * and we can bounce, we will. 267 */ 268 error = _bus_dmamap_load(t, map, buf, buflen, p, flags); 269 if (error == 0 || 270 (error != 0 && (cookie->id_flags & ID_MIGHT_NEED_BOUNCE) == 0)) 271 return (error); 272 273 /* 274 * First attempt failed; bounce it. 275 */ 276 277 /* 278 * Allocate bounce pages, if necessary. 279 */ 280 if ((cookie->id_flags & ID_HAS_BOUNCE) == 0) { 281 error = isadma_bounce_alloc_bouncebuf(t, map, buflen, flags); 282 if (error) 283 return (error); 284 } 285 286 /* 287 * Cache a pointer to the caller's buffer and load the DMA map 288 * with the bounce buffer. 289 */ 290 cookie->id_origbuf = buf; 291 cookie->id_origbuflen = buflen; 292 cookie->id_buftype = ID_BUFTYPE_LINEAR; 293 error = _bus_dmamap_load(t, map, cookie->id_bouncebuf, buflen, 294 p, flags); 295 if (error) { 296 /* 297 * Free the bounce pages, unless our resources 298 * are reserved for our exclusive use. 299 */ 300 if ((map->_dm_flags & BUS_DMA_ALLOCNOW) == 0) 301 isadma_bounce_free_bouncebuf(t, map); 302 return (error); 303 } 304 305 /* ...so isadma_bounce_dmamap_sync() knows we're bouncing */ 306 cookie->id_flags |= ID_IS_BOUNCING; 307 return (0); 308 } 309 310 /* 311 * Like isadma_bounce_dmamap_load(), but for mbufs. 312 */ 313 int 314 isadma_bounce_dmamap_load_mbuf(bus_dma_tag_t t, bus_dmamap_t map, 315 struct mbuf *m0, int flags) 316 { 317 struct isadma_bounce_cookie *cookie = map->_dm_cookie; 318 int error; 319 320 /* 321 * Make sure on error condition we return "no valid mappings." 322 */ 323 map->dm_mapsize = 0; 324 map->dm_nsegs = 0; 325 326 #ifdef DIAGNOSTIC 327 if ((m0->m_flags & M_PKTHDR) == 0) 328 panic("isadma_bounce_dmamap_load_mbuf: no packet header"); 329 #endif 330 331 if (m0->m_pkthdr.len > map->_dm_size) 332 return (EINVAL); 333 334 /* 335 * Try to load the map the normal way. If this errors out, 336 * and we can bounce, we will. 337 */ 338 error = _bus_dmamap_load_mbuf(t, map, m0, flags); 339 if (error == 0 || 340 (error != 0 && (cookie->id_flags & ID_MIGHT_NEED_BOUNCE) == 0)) 341 return (error); 342 343 /* 344 * First attempt failed; bounce it. 345 */ 346 347 /* 348 * Allocate bounce pages, if necessary. 349 */ 350 if ((cookie->id_flags & ID_HAS_BOUNCE) == 0) { 351 error = isadma_bounce_alloc_bouncebuf(t, map, m0->m_pkthdr.len, 352 flags); 353 if (error) 354 return (error); 355 } 356 357 /* 358 * Cache a pointer to the caller's buffer and load the DMA map 359 * with the bounce buffer. 360 */ 361 cookie->id_origbuf = m0; 362 cookie->id_origbuflen = m0->m_pkthdr.len; /* not really used */ 363 cookie->id_buftype = ID_BUFTYPE_MBUF; 364 error = _bus_dmamap_load(t, map, cookie->id_bouncebuf, 365 m0->m_pkthdr.len, NULL, flags); 366 if (error) { 367 /* 368 * Free the bounce pages, unless our resources 369 * are reserved for our exclusive use. 370 */ 371 if ((map->_dm_flags & BUS_DMA_ALLOCNOW) == 0) 372 isadma_bounce_free_bouncebuf(t, map); 373 return (error); 374 } 375 376 /* ...so isadma_bounce_dmamap_sync() knows we're bouncing */ 377 cookie->id_flags |= ID_IS_BOUNCING; 378 return (0); 379 } 380 381 /* 382 * Like isadma_bounce_dmamap_load(), but for uios. 383 */ 384 int 385 isadma_bounce_dmamap_load_uio(bus_dma_tag_t t, bus_dmamap_t map, 386 struct uio *uio, int flags) 387 { 388 389 panic("isadma_bounce_dmamap_load_uio: not implemented"); 390 } 391 392 /* 393 * Like isadma_bounce_dmamap_load(), but for raw memory allocated with 394 * bus_dmamem_alloc(). 395 */ 396 int 397 isadma_bounce_dmamap_load_raw(bus_dma_tag_t t, bus_dmamap_t map, 398 bus_dma_segment_t *segs, int nsegs, bus_size_t size, int flags) 399 { 400 401 panic("isadma_bounce_dmamap_load_raw: not implemented"); 402 } 403 404 /* 405 * Unload an ISA DMA map. 406 */ 407 void 408 isadma_bounce_dmamap_unload(bus_dma_tag_t t, bus_dmamap_t map) 409 { 410 struct isadma_bounce_cookie *cookie = map->_dm_cookie; 411 412 /* 413 * If we have bounce pages, free them, unless they're 414 * reserved for our exclusive use. 415 */ 416 if ((cookie->id_flags & ID_HAS_BOUNCE) && 417 (map->_dm_flags & BUS_DMA_ALLOCNOW) == 0) 418 isadma_bounce_free_bouncebuf(t, map); 419 420 cookie->id_flags &= ~ID_IS_BOUNCING; 421 cookie->id_buftype = ID_BUFTYPE_INVALID; 422 423 /* 424 * Do the generic bits of the unload. 425 */ 426 _bus_dmamap_unload(t, map); 427 } 428 429 /* 430 * Synchronize an ISA DMA map. 431 */ 432 void 433 isadma_bounce_dmamap_sync(bus_dma_tag_t t, bus_dmamap_t map, bus_addr_t offset, 434 bus_size_t len, int ops) 435 { 436 struct isadma_bounce_cookie *cookie = map->_dm_cookie; 437 void (*sync)(bus_dma_tag_t, bus_dmamap_t, bus_addr_t, bus_size_t, int); 438 439 sync = _bus_dmamap_sync; 440 441 /* 442 * Mixing PRE and POST operations is not allowed. 443 */ 444 if ((ops & (BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE)) != 0 && 445 (ops & (BUS_DMASYNC_POSTREAD|BUS_DMASYNC_POSTWRITE)) != 0) 446 panic("isadma_bounce_dmamap_sync: mix PRE and POST"); 447 448 #ifdef DIAGNOSTIC 449 if ((ops & (BUS_DMASYNC_PREWRITE|BUS_DMASYNC_POSTREAD)) != 0) { 450 if (offset >= map->dm_mapsize) 451 panic("isadma_bounce_dmamap_sync: bad offset"); 452 if (len == 0 || (offset + len) > map->dm_mapsize) 453 panic("isadma_bounce_dmamap_sync: bad length"); 454 } 455 #endif 456 457 /* 458 * If we're not bouncing, just drain the write buffer 459 * and flush cache. 460 */ 461 if ((cookie->id_flags & ID_IS_BOUNCING) == 0) { 462 ((*sync)(t, map, offset, len, ops)); 463 return; 464 } 465 466 /* 467 * XXX 468 * This should be needed in BUS_DMASYNC_POSTREAD case only, 469 * if _mips3_bus_dmamap_sync() used "Hit_Invalidate on POSTREAD", 470 * rather than "Hit_Write_Back_Invalidate on PREREAD". 471 */ 472 if (ops & (BUS_DMASYNC_PREREAD|BUS_DMASYNC_POSTREAD)) 473 ((*sync)(t, map, offset, len, ops)); 474 475 switch (cookie->id_buftype) { 476 case ID_BUFTYPE_LINEAR: 477 /* 478 * Nothing to do for pre-read. 479 */ 480 481 if (ops & BUS_DMASYNC_PREWRITE) { 482 /* 483 * Copy the caller's buffer to the bounce buffer. 484 */ 485 memcpy((char *)cookie->id_bouncebuf + offset, 486 (char *)cookie->id_origbuf + offset, len); 487 } 488 489 if (ops & BUS_DMASYNC_POSTREAD) { 490 /* 491 * Copy the bounce buffer to the caller's buffer. 492 */ 493 memcpy((char *)cookie->id_origbuf + offset, 494 (char *)cookie->id_bouncebuf + offset, len); 495 } 496 497 /* 498 * Nothing to do for post-write. 499 */ 500 break; 501 502 case ID_BUFTYPE_MBUF: 503 { 504 struct mbuf *m, *m0 = cookie->id_origbuf; 505 bus_size_t minlen, moff; 506 507 /* 508 * Nothing to do for pre-read. 509 */ 510 511 if (ops & BUS_DMASYNC_PREWRITE) { 512 /* 513 * Copy the caller's buffer to the bounce buffer. 514 */ 515 m_copydata(m0, offset, len, 516 (char *)cookie->id_bouncebuf + offset); 517 } 518 519 if (ops & BUS_DMASYNC_POSTREAD) { 520 /* 521 * Copy the bounce buffer to the caller's buffer. 522 */ 523 for (moff = offset, m = m0; m != NULL && len != 0; 524 m = m->m_next) { 525 /* Find the beginning mbuf. */ 526 if (moff >= m->m_len) { 527 moff -= m->m_len; 528 continue; 529 } 530 531 /* 532 * Now at the first mbuf to sync; nail 533 * each one until we have exhausted the 534 * length. 535 */ 536 minlen = len < m->m_len - moff ? 537 len : m->m_len - moff; 538 539 memcpy(mtod(m, caddr_t) + moff, 540 (char *)cookie->id_bouncebuf + offset, 541 minlen); 542 543 moff = 0; 544 len -= minlen; 545 offset += minlen; 546 } 547 } 548 549 /* 550 * Nothing to do for post-write. 551 */ 552 break; 553 } 554 555 case ID_BUFTYPE_UIO: 556 panic("isadma_bounce_dmamap_sync: ID_BUFTYPE_UIO"); 557 break; 558 559 case ID_BUFTYPE_RAW: 560 panic("isadma_bounce_dmamap_sync: ID_BUFTYPE_RAW"); 561 break; 562 563 case ID_BUFTYPE_INVALID: 564 panic("isadma_bounce_dmamap_sync: ID_BUFTYPE_INVALID"); 565 break; 566 567 default: 568 printf("unknown buffer type %d\n", cookie->id_buftype); 569 panic("isadma_bounce_dmamap_sync"); 570 } 571 572 if (ops & BUS_DMASYNC_PREWRITE) 573 ((*sync)(t, map, offset, len, ops)); 574 } 575 576 /* 577 * Allocate memory safe for ISA DMA. 578 */ 579 int 580 isadma_bounce_dmamem_alloc(bus_dma_tag_t t, bus_size_t size, 581 bus_size_t alignment, bus_size_t boundary, bus_dma_segment_t *segs, 582 int nsegs, int *rsegs, int flags) 583 { 584 paddr_t high; 585 586 if (avail_end > ISA_DMA_BOUNCE_THRESHOLD) 587 high = trunc_page(ISA_DMA_BOUNCE_THRESHOLD); 588 else 589 high = trunc_page(avail_end); 590 591 return (_bus_dmamem_alloc_range(t, size, alignment, boundary, 592 segs, nsegs, rsegs, flags, 0, high)); 593 } 594 595 /********************************************************************** 596 * ISA DMA utility functions 597 **********************************************************************/ 598 599 static int 600 isadma_bounce_alloc_bouncebuf(bus_dma_tag_t t, bus_dmamap_t map, 601 bus_size_t size, int flags) 602 { 603 struct isadma_bounce_cookie *cookie = map->_dm_cookie; 604 int error = 0; 605 606 cookie->id_bouncebuflen = round_page(size); 607 error = isadma_bounce_dmamem_alloc(t, cookie->id_bouncebuflen, 608 PAGE_SIZE, map->_dm_boundary, cookie->id_bouncesegs, 609 map->_dm_segcnt, &cookie->id_nbouncesegs, flags); 610 if (error) 611 goto out; 612 error = _bus_dmamem_map(t, cookie->id_bouncesegs, 613 cookie->id_nbouncesegs, cookie->id_bouncebuflen, 614 (caddr_t *)&cookie->id_bouncebuf, flags); 615 616 out: 617 if (error) { 618 _bus_dmamem_free(t, cookie->id_bouncesegs, 619 cookie->id_nbouncesegs); 620 cookie->id_bouncebuflen = 0; 621 cookie->id_nbouncesegs = 0; 622 } else 623 cookie->id_flags |= ID_HAS_BOUNCE; 624 625 return (error); 626 } 627 628 static void 629 isadma_bounce_free_bouncebuf(bus_dma_tag_t t, bus_dmamap_t map) 630 { 631 struct isadma_bounce_cookie *cookie = map->_dm_cookie; 632 633 _bus_dmamem_unmap(t, cookie->id_bouncebuf, 634 cookie->id_bouncebuflen); 635 _bus_dmamem_free(t, cookie->id_bouncesegs, 636 cookie->id_nbouncesegs); 637 cookie->id_bouncebuflen = 0; 638 cookie->id_nbouncesegs = 0; 639 cookie->id_flags &= ~ID_HAS_BOUNCE; 640 } 641