1 /* $NetBSD: int_bus_dma.c,v 1.17 2010/11/04 12:16:15 uebayasi Exp $ */ 2 3 /* 4 * Copyright (c) 2002 Wasabi Systems, Inc. 5 * All rights reserved. 6 * 7 * Written by Jason R. Thorpe for Wasabi Systems, Inc. 8 * 9 * Redistribution and use in source and binary forms, with or without 10 * modification, are permitted provided that the following conditions 11 * are met: 12 * 1. Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer. 14 * 2. Redistributions in binary form must reproduce the above copyright 15 * notice, this list of conditions and the following disclaimer in the 16 * documentation and/or other materials provided with the distribution. 17 * 3. All advertising materials mentioning features or use of this software 18 * must display the following acknowledgement: 19 * This product includes software developed for the NetBSD Project by 20 * Wasabi Systems, Inc. 21 * 4. The name of Wasabi Systems, Inc. may not be used to endorse 22 * or promote products derived from this software without specific prior 23 * written permission. 24 * 25 * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND 26 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 27 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 28 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL WASABI SYSTEMS, INC 29 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 30 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 31 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 32 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 33 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 34 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 35 * POSSIBILITY OF SUCH DAMAGE. 36 */ 37 38 /* 39 * PCI DMA support for the ARM Integrator. 40 */ 41 42 #define _ARM32_BUS_DMA_PRIVATE 43 44 #include <sys/cdefs.h> 45 __KERNEL_RCSID(0, "$NetBSD: int_bus_dma.c,v 1.17 2010/11/04 12:16:15 uebayasi Exp $"); 46 47 #include <sys/param.h> 48 #include <sys/systm.h> 49 #include <sys/device.h> 50 #include <sys/malloc.h> 51 #include <sys/mbuf.h> 52 53 #include <uvm/uvm_extern.h> 54 55 #include <machine/bootconfig.h> 56 57 #include <evbarm/integrator/int_bus_dma.h> 58 59 struct integrator_dma_cookie { 60 int id_flags; /* flags; see below */ 61 62 /* 63 * Information about the original buffer used during 64 * DMA map syncs. Note that origbuflen is only used 65 * for ID_BUFTYPE_LINEAR. 66 */ 67 void *id_origbuf; /* pointer to orig buffer if 68 bouncing */ 69 bus_size_t id_origbuflen; /* ...and size */ 70 int id_buftype; /* type of buffer */ 71 72 void *id_bouncebuf; /* pointer to the bounce buffer */ 73 bus_size_t id_bouncebuflen; /* ...and size */ 74 int id_nbouncesegs; /* number of valid bounce segs */ 75 bus_dma_segment_t id_bouncesegs[0]; /* array of bounce buffer 76 physical memory segments */ 77 }; 78 /* id_flags */ 79 #define ID_MIGHT_NEED_BOUNCE 0x01 /* map could need bounce buffers */ 80 #define ID_HAS_BOUNCE 0x02 /* map currently has bounce buffers */ 81 #define ID_IS_BOUNCING 0x04 /* map is bouncing current xfer */ 82 83 /* id_buftype */ 84 #define ID_BUFTYPE_INVALID 0 85 #define ID_BUFTYPE_LINEAR 1 86 #define ID_BUFTYPE_MBUF 2 87 #define ID_BUFTYPE_UIO 3 88 #define ID_BUFTYPE_RAW 4 89 90 #undef DEBUG 91 #define DEBUG(x) 92 93 static struct arm32_dma_range integrator_dma_ranges[DRAM_BLOCKS]; 94 95 extern BootConfig bootconfig; 96 97 static int integrator_bus_dmamap_create(bus_dma_tag_t, bus_size_t, int, 98 bus_size_t, bus_size_t, int, bus_dmamap_t *); 99 static void integrator_bus_dmamap_destroy(bus_dma_tag_t, bus_dmamap_t); 100 static int integrator_bus_dmamap_load(bus_dma_tag_t, bus_dmamap_t, void *, 101 bus_size_t, struct proc *, int); 102 static int integrator_bus_dmamap_load_mbuf(bus_dma_tag_t, bus_dmamap_t, 103 struct mbuf *, int); 104 static int integrator_bus_dmamap_load_uio(bus_dma_tag_t, bus_dmamap_t, 105 struct uio *, int); 106 static int integrator_bus_dmamap_load_raw(bus_dma_tag_t, bus_dmamap_t, 107 bus_dma_segment_t *, int, bus_size_t, int); 108 static void integrator_bus_dmamap_unload(bus_dma_tag_t, bus_dmamap_t); 109 static void integrator_bus_dmamap_sync(bus_dma_tag_t, bus_dmamap_t, 110 bus_addr_t, bus_size_t, int); 111 static int integrator_bus_dmamem_alloc(bus_dma_tag_t, bus_size_t, 112 bus_size_t, bus_size_t, bus_dma_segment_t *, int, int *, int); 113 static int integrator_dma_alloc_bouncebuf(bus_dma_tag_t, bus_dmamap_t, 114 bus_size_t, int); 115 static void integrator_dma_free_bouncebuf(bus_dma_tag_t, bus_dmamap_t); 116 117 118 /* 119 * Create an Integrator DMA map. 120 */ 121 static int 122 integrator_bus_dmamap_create(bus_dma_tag_t t, bus_size_t size, int nsegments, 123 bus_size_t maxsegsz, bus_size_t boundary, int flags, bus_dmamap_t *dmamp) 124 { 125 struct integrator_dma_cookie *cookie; 126 bus_dmamap_t map; 127 int error, cookieflags; 128 void *cookiestore; 129 size_t cookiesize; 130 131 DEBUG(printf("I_bus_dmamap_create(tag %x, size %x, nseg %d, max %x," 132 " boundary %x, flags %x, dmamap %p)\n", (unsigned) t, 133 (unsigned) size, nsegments, (unsigned) maxsegsz, 134 (unsigned)boundary, flags, dmamp)); 135 136 /* Call common function to create the basic map. */ 137 error = _bus_dmamap_create(t, size, nsegments, maxsegsz, boundary, 138 flags, dmamp); 139 if (error) 140 return (error); 141 142 map = *dmamp; 143 map->_dm_cookie = NULL; 144 145 cookiesize = sizeof(struct integrator_dma_cookie); 146 147 /* 148 * Some CM boards have private memory which is significantly 149 * faster than the normal memory stick. To support this 150 * memory we have to bounce any DMA transfers. 151 * 152 * In order to DMA to arbitrary buffers, we use "bounce 153 * buffers" - pages in in the main PCI visible memory. On DMA 154 * reads, DMA happens to the bounce buffers, and is copied 155 * into the caller's buffer. On writes, data is copied into 156 * but bounce buffer, and the DMA happens from those pages. 157 * To software using the DMA mapping interface, this looks 158 * simply like a data cache. 159 * 160 * If we have private RAM in the system, we may need bounce 161 * buffers. We check and remember that here. 162 */ 163 #if 0 164 cookieflags = ID_MIGHT_NEED_BOUNCE; 165 #else 166 cookieflags = 0; 167 #endif 168 cookiesize += (sizeof(bus_dma_segment_t) * map->_dm_segcnt); 169 170 /* 171 * Allocate our cookie. 172 */ 173 if ((cookiestore = malloc(cookiesize, M_DMAMAP, 174 (flags & BUS_DMA_NOWAIT) ? M_NOWAIT : M_WAITOK)) == NULL) { 175 error = ENOMEM; 176 goto out; 177 } 178 memset(cookiestore, 0, cookiesize); 179 cookie = (struct integrator_dma_cookie *)cookiestore; 180 cookie->id_flags = cookieflags; 181 map->_dm_cookie = cookie; 182 183 if (cookieflags & ID_MIGHT_NEED_BOUNCE) { 184 /* 185 * Allocate the bounce pages now if the caller 186 * wishes us to do so. 187 */ 188 if ((flags & BUS_DMA_ALLOCNOW) == 0) 189 goto out; 190 191 DEBUG(printf("I_bus_dmamap_create bouncebuf alloc\n")); 192 error = integrator_dma_alloc_bouncebuf(t, map, size, flags); 193 } 194 195 out: 196 if (error) { 197 if (map->_dm_cookie != NULL) 198 free(map->_dm_cookie, M_DMAMAP); 199 _bus_dmamap_destroy(t, map); 200 printf("I_bus_dmamap_create failed (%d)\n", error); 201 } 202 return (error); 203 } 204 205 /* 206 * Destroy an ISA DMA map. 207 */ 208 static void 209 integrator_bus_dmamap_destroy(bus_dma_tag_t t, bus_dmamap_t map) 210 { 211 struct integrator_dma_cookie *cookie = map->_dm_cookie; 212 213 DEBUG(printf("I_bus_dmamap_destroy (tag %x, map %x)\n", (unsigned) t, 214 (unsigned) map)); 215 /* 216 * Free any bounce pages this map might hold. 217 */ 218 if (cookie->id_flags & ID_HAS_BOUNCE) { 219 DEBUG(printf("I_bus_dmamap_destroy bouncebuf\n")); 220 integrator_dma_free_bouncebuf(t, map); 221 } 222 223 free(cookie, M_DMAMAP); 224 _bus_dmamap_destroy(t, map); 225 } 226 227 /* 228 * Load an Integrator DMA map with a linear buffer. 229 */ 230 static int 231 integrator_bus_dmamap_load(bus_dma_tag_t t, bus_dmamap_t map, void *buf, 232 bus_size_t buflen, struct proc *p, int flags) 233 { 234 struct integrator_dma_cookie *cookie = map->_dm_cookie; 235 int error; 236 237 DEBUG(printf("I_bus_dmamap_load (tag %x, map %x, buf %p, len %u," 238 " proc %p, flags %d)\n", (unsigned) t, (unsigned) map, buf, 239 (unsigned) buflen, p, flags)); 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 /* 247 * Try to load the map the normal way. If this errors out, 248 * and we can bounce, we will. 249 */ 250 error = _bus_dmamap_load(t, map, buf, buflen, p, flags); 251 if (error == 0 || 252 (error != 0 && (cookie->id_flags & ID_MIGHT_NEED_BOUNCE) == 0)) 253 return (error); 254 255 /* 256 * First attempt failed; bounce it. 257 */ 258 259 /* 260 * Allocate bounce pages, if necessary. 261 */ 262 if ((cookie->id_flags & ID_HAS_BOUNCE) == 0) { 263 DEBUG(printf("I_bus_dmamap_load alloc bouncebuf\n")); 264 error = integrator_dma_alloc_bouncebuf(t, map, buflen, flags); 265 if (error) 266 return (error); 267 } 268 269 /* 270 * Cache a pointer to the caller's buffer and load the DMA map 271 * with the bounce buffer. 272 */ 273 cookie->id_origbuf = buf; 274 cookie->id_origbuflen = buflen; 275 cookie->id_buftype = ID_BUFTYPE_LINEAR; 276 error = _bus_dmamap_load(t, map, cookie->id_bouncebuf, buflen, 277 NULL, flags); 278 if (error) { 279 /* 280 * Free the bounce pages, unless our resources 281 * are reserved for our exclusive use. 282 */ 283 if ((map->_dm_flags & BUS_DMA_ALLOCNOW) == 0) 284 integrator_dma_free_bouncebuf(t, map); 285 return (error); 286 } 287 288 /* ...so integrator_bus_dmamap_sync() knows we're bouncing */ 289 cookie->id_flags |= ID_IS_BOUNCING; 290 return (0); 291 } 292 293 /* 294 * Like integrator_bus_dmamap_load(), but for mbufs. 295 */ 296 static int 297 integrator_bus_dmamap_load_mbuf(bus_dma_tag_t t, bus_dmamap_t map, 298 struct mbuf *m0, int flags) 299 { 300 struct integrator_dma_cookie *cookie = map->_dm_cookie; 301 int error; 302 303 /* 304 * Make sure that on error condition we return "no valid mappings." 305 */ 306 map->dm_mapsize = 0; 307 map->dm_nsegs = 0; 308 309 #ifdef DIAGNOSTIC 310 if ((m0->m_flags & M_PKTHDR) == 0) 311 panic("integrator_bus_dmamap_load_mbuf: no packet header"); 312 #endif 313 314 if (m0->m_pkthdr.len > map->_dm_size) 315 return (EINVAL); 316 317 /* 318 * Try to load the map the normal way. If this errors out, 319 * and we can bounce, we will. 320 */ 321 error = _bus_dmamap_load_mbuf(t, map, m0, flags); 322 if (error == 0 || 323 (error != 0 && (cookie->id_flags & ID_MIGHT_NEED_BOUNCE) == 0)) 324 return (error); 325 326 /* 327 * First attempt failed; bounce it. 328 * 329 * Allocate bounce pages, if necessary. 330 */ 331 if ((cookie->id_flags & ID_HAS_BOUNCE) == 0) { 332 error = integrator_dma_alloc_bouncebuf(t, map, 333 m0->m_pkthdr.len, flags); 334 if (error) 335 return (error); 336 } 337 338 /* 339 * Cache a pointer to the caller's buffer and load the DMA map 340 * with the bounce buffer. 341 */ 342 cookie->id_origbuf = m0; 343 cookie->id_origbuflen = m0->m_pkthdr.len; /* not really used */ 344 cookie->id_buftype = ID_BUFTYPE_MBUF; 345 error = _bus_dmamap_load(t, map, cookie->id_bouncebuf, 346 m0->m_pkthdr.len, NULL, flags); 347 if (error) { 348 /* 349 * Free the bounce pages, unless our resources 350 * are reserved for our exclusive use. 351 */ 352 if ((map->_dm_flags & BUS_DMA_ALLOCNOW) == 0) 353 integrator_dma_free_bouncebuf(t, map); 354 return (error); 355 } 356 357 /* ...so integrator_bus_dmamap_sync() knows we're bouncing */ 358 cookie->id_flags |= ID_IS_BOUNCING; 359 return (0); 360 } 361 362 /* 363 * Like integrator_bus_dmamap_load(), but for uios. 364 */ 365 static int 366 integrator_bus_dmamap_load_uio(bus_dma_tag_t t, bus_dmamap_t map, 367 struct uio *uio, int flags) 368 { 369 370 panic("integrator_bus_dmamap_load_uio: not implemented"); 371 } 372 373 /* 374 * Like intgrator_bus_dmamap_load(), but for raw memory allocated with 375 * bus_dmamem_alloc(). 376 */ 377 static int 378 integrator_bus_dmamap_load_raw(bus_dma_tag_t t, bus_dmamap_t map, 379 bus_dma_segment_t *segs, int nsegs, bus_size_t size, int flags) 380 { 381 382 panic("integrator_bus_dmamap_load_raw: not implemented"); 383 } 384 385 /* 386 * Unload an Integrator DMA map. 387 */ 388 static void 389 integrator_bus_dmamap_unload(bus_dma_tag_t t, bus_dmamap_t map) 390 { 391 struct integrator_dma_cookie *cookie = map->_dm_cookie; 392 393 /* 394 * If we have bounce pages, free them, unless they're 395 * reserved for our exclusive use. 396 */ 397 if ((cookie->id_flags & ID_HAS_BOUNCE) && 398 (map->_dm_flags & BUS_DMA_ALLOCNOW) == 0) 399 integrator_dma_free_bouncebuf(t, map); 400 401 cookie->id_flags &= ~ID_IS_BOUNCING; 402 cookie->id_buftype = ID_BUFTYPE_INVALID; 403 404 /* 405 * Do the generic bits of the unload. 406 */ 407 _bus_dmamap_unload(t, map); 408 } 409 410 /* 411 * Synchronize an Integrator DMA map. 412 */ 413 static void 414 integrator_bus_dmamap_sync(bus_dma_tag_t t, bus_dmamap_t map, 415 bus_addr_t offset, bus_size_t len, int ops) 416 { 417 struct integrator_dma_cookie *cookie = map->_dm_cookie; 418 419 DEBUG(printf("I_bus_dmamap_sync (tag %x, map %x, offset %x, size %u," 420 " ops %d\n", (unsigned)t, (unsigned)map, (unsigned)offset , 421 (unsigned)len, ops)); 422 /* 423 * Mixing PRE and POST operations is not allowed. 424 */ 425 if ((ops & (BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE)) != 0 && 426 (ops & (BUS_DMASYNC_POSTREAD|BUS_DMASYNC_POSTWRITE)) != 0) 427 panic("integrator_bus_dmamap_sync: mix PRE and POST"); 428 429 #ifdef DIAGNOSTIC 430 if ((ops & (BUS_DMASYNC_PREWRITE|BUS_DMASYNC_POSTREAD)) != 0) { 431 if (offset >= map->dm_mapsize) 432 panic("integrator_bus_dmamap_sync: bad offset"); 433 if (len == 0 || (offset + len) > map->dm_mapsize) 434 panic("integrator_bus_dmamap_sync: bad length"); 435 } 436 #endif 437 438 /* 439 * If we're not bouncing then use the standard code. 440 */ 441 if ((cookie->id_flags & ID_IS_BOUNCING) == 0) { 442 _bus_dmamap_sync(t, map, offset, len, ops); 443 return; 444 } 445 446 DEBUG(printf("dmamap_sync("); 447 if (ops & BUS_DMASYNC_PREREAD) 448 printf("preread "); 449 if (ops & BUS_DMASYNC_PREWRITE) 450 printf("prewrite "); 451 if (ops & BUS_DMASYNC_POSTREAD) 452 printf("postread "); 453 if (ops & BUS_DMASYNC_POSTWRITE) 454 printf("postwrite ");) 455 456 switch (cookie->id_buftype) { 457 case ID_BUFTYPE_LINEAR: 458 if (ops & BUS_DMASYNC_PREWRITE) { 459 /* 460 * Copy the caller's buffer to the bounce buffer. 461 */ 462 memcpy((uint8_t *)cookie->id_bouncebuf + offset, 463 (uint8_t *)cookie->id_origbuf + offset, len); 464 cpu_dcache_wbinv_range((vaddr_t)cookie->id_bouncebuf + 465 offset, len); 466 } 467 if (ops & BUS_DMASYNC_PREREAD) { 468 cpu_dcache_wbinv_range((vaddr_t)cookie->id_bouncebuf + 469 offset, len); 470 } 471 if (ops & BUS_DMASYNC_POSTREAD) { 472 /* 473 * Copy the bounce buffer to the caller's buffer. 474 */ 475 memcpy((uint8_t *)cookie->id_origbuf + offset, 476 (uint8_t *)cookie->id_bouncebuf + offset, len); 477 } 478 479 /* 480 * Nothing to do for post-write. 481 */ 482 break; 483 484 case ID_BUFTYPE_MBUF: 485 { 486 struct mbuf *m, *m0 = cookie->id_origbuf; 487 bus_size_t minlen, moff; 488 489 if (ops & BUS_DMASYNC_PREWRITE) { 490 /* 491 * Copy the caller's buffer to the bounce buffer. 492 */ 493 m_copydata(m0, offset, len, 494 (uint8_t *)cookie->id_bouncebuf + offset); 495 cpu_dcache_wb_range((vaddr_t)cookie->id_bouncebuf + 496 offset, len); 497 } 498 if (ops & BUS_DMASYNC_PREREAD) { 499 cpu_dcache_wbinv_range ((vaddr_t)cookie->id_bouncebuf + 500 offset, len); 501 } 502 if (ops & BUS_DMASYNC_POSTREAD) { 503 /* 504 * Copy the bounce buffer to the caller's buffer. 505 */ 506 for (moff = offset, m = m0; m != NULL && len != 0; 507 m = m->m_next) { 508 /* Find the beginning mbuf. */ 509 if (moff >= m->m_len) { 510 moff -= m->m_len; 511 continue; 512 } 513 514 /* 515 * Now at the first mbuf to sync; nail 516 * each one until we have exhausted the 517 * length. 518 */ 519 minlen = len < m->m_len - moff ? 520 len : m->m_len - moff; 521 522 memcpy(mtod(m, uint8_t *) + moff, 523 (uint8_t *)cookie->id_bouncebuf + offset, 524 minlen); 525 526 moff = 0; 527 len -= minlen; 528 offset += minlen; 529 } 530 } 531 /* 532 * Nothing to do for post-write. 533 */ 534 break; 535 } 536 537 case ID_BUFTYPE_UIO: 538 panic("integrator_bus_dmamap_sync: ID_BUFTYPE_UIO"); 539 break; 540 541 case ID_BUFTYPE_RAW: 542 panic("integrator_bus_dmamap_sync: ID_BUFTYPE_RAW"); 543 break; 544 545 case ID_BUFTYPE_INVALID: 546 panic("integrator_bus_dmamap_sync: ID_BUFTYPE_INVALID"); 547 break; 548 549 default: 550 printf("unknown buffer type %d\n", cookie->id_buftype); 551 panic("integrator_bus_dmamap_sync"); 552 } 553 } 554 555 /* 556 * Allocate memory safe for Integrator DMA. 557 */ 558 static int 559 integrator_bus_dmamem_alloc(bus_dma_tag_t t, bus_size_t size, 560 bus_size_t alignment, bus_size_t boundary, bus_dma_segment_t *segs, 561 int nsegs, int *rsegs, int flags) 562 { 563 564 if (t->_ranges == NULL) 565 return (ENOMEM); 566 567 /* _bus_dmamem_alloc() does the range checks for us. */ 568 return (_bus_dmamem_alloc(t, size, alignment, boundary, segs, nsegs, 569 rsegs, flags)); 570 } 571 572 /********************************************************************** 573 * Integrator DMA utility functions 574 **********************************************************************/ 575 576 static int 577 integrator_dma_alloc_bouncebuf(bus_dma_tag_t t, bus_dmamap_t map, 578 bus_size_t size, int flags) 579 { 580 struct integrator_dma_cookie *cookie = map->_dm_cookie; 581 int error = 0; 582 583 DEBUG(printf("Alloc bouncebuf\n")); 584 cookie->id_bouncebuflen = round_page(size); 585 error = integrator_bus_dmamem_alloc(t, cookie->id_bouncebuflen, 586 NBPG, map->_dm_boundary, cookie->id_bouncesegs, 587 map->_dm_segcnt, &cookie->id_nbouncesegs, flags); 588 if (error) 589 goto out; 590 { 591 int seg; 592 593 for (seg = 0; seg < cookie->id_nbouncesegs; seg++) 594 DEBUG(printf("Seg %d @ PA 0x%08x+0x%x\n", seg, 595 (unsigned) cookie->id_bouncesegs[seg].ds_addr, 596 (unsigned) cookie->id_bouncesegs[seg].ds_len)); 597 } 598 error = _bus_dmamem_map(t, cookie->id_bouncesegs, 599 cookie->id_nbouncesegs, cookie->id_bouncebuflen, 600 (void **)&cookie->id_bouncebuf, flags); 601 602 out: 603 if (error) { 604 _bus_dmamem_free(t, cookie->id_bouncesegs, 605 cookie->id_nbouncesegs); 606 cookie->id_bouncebuflen = 0; 607 cookie->id_nbouncesegs = 0; 608 } else { 609 DEBUG(printf("Alloc bouncebuf OK\n")); 610 cookie->id_flags |= ID_HAS_BOUNCE; 611 } 612 613 return (error); 614 } 615 616 static void 617 integrator_dma_free_bouncebuf(bus_dma_tag_t t, bus_dmamap_t map) 618 { 619 struct integrator_dma_cookie *cookie = map->_dm_cookie; 620 621 _bus_dmamem_unmap(t, cookie->id_bouncebuf, 622 cookie->id_bouncebuflen); 623 _bus_dmamem_free(t, cookie->id_bouncesegs, 624 cookie->id_nbouncesegs); 625 cookie->id_bouncebuflen = 0; 626 cookie->id_nbouncesegs = 0; 627 cookie->id_flags &= ~ID_HAS_BOUNCE; 628 } 629 630 void 631 integrator_pci_dma_init(bus_dma_tag_t dmat) 632 { 633 struct arm32_dma_range *dr = integrator_dma_ranges; 634 int i; 635 int nranges = 0; 636 637 for (i = 0; i < bootconfig.dramblocks; i++) 638 if (bootconfig.dram[i].flags & BOOT_DRAM_CAN_DMA) { 639 dr[nranges].dr_sysbase = bootconfig.dram[i].address; 640 dr[nranges].dr_busbase = 641 LOCAL_TO_CM_ALIAS(dr[nranges].dr_sysbase); 642 dr[nranges].dr_len = bootconfig.dram[i].pages * NBPG; 643 nranges++; 644 } 645 646 if (nranges == 0) 647 panic ("integrator_pci_dma_init: No DMA capable memory"); 648 649 dmat->_ranges = dr; 650 dmat->_nranges = nranges; 651 652 dmat->_dmamap_create = integrator_bus_dmamap_create; 653 dmat->_dmamap_destroy = integrator_bus_dmamap_destroy; 654 dmat->_dmamap_load = integrator_bus_dmamap_load; 655 dmat->_dmamap_load_mbuf = integrator_bus_dmamap_load_mbuf; 656 dmat->_dmamap_load_uio = integrator_bus_dmamap_load_uio; 657 dmat->_dmamap_load_raw = integrator_bus_dmamap_load_raw; 658 dmat->_dmamap_unload = integrator_bus_dmamap_unload; 659 dmat->_dmamap_sync_pre = integrator_bus_dmamap_sync; 660 dmat->_dmamap_sync_post = integrator_bus_dmamap_sync; 661 662 dmat->_dmamem_alloc = integrator_bus_dmamem_alloc; 663 dmat->_dmamem_free = _bus_dmamem_free; 664 dmat->_dmamem_map = _bus_dmamem_map; 665 dmat->_dmamem_unmap = _bus_dmamem_unmap; 666 dmat->_dmamem_mmap = _bus_dmamem_mmap; 667 } 668