1 /*- 2 * Copyright (c) 1997, 1998 Justin T. Gibbs. 3 * Copyright (c) 2015-2016 The FreeBSD Foundation 4 * All rights reserved. 5 * 6 * Portions of this software were developed by Andrew Turner 7 * under sponsorship of the FreeBSD Foundation. 8 * 9 * Portions of this software were developed by Semihalf 10 * under sponsorship of the FreeBSD Foundation. 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 * without modification, immediately at the beginning of the file. 18 * 2. The name of the author may not be used to endorse or promote products 19 * derived from this software without specific prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR 25 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31 * SUCH DAMAGE. 32 */ 33 34 #include <sys/cdefs.h> 35 #include <sys/param.h> 36 #include <sys/systm.h> 37 #include <sys/malloc.h> 38 #include <sys/bus.h> 39 #include <sys/interrupt.h> 40 #include <sys/kernel.h> 41 #include <sys/ktr.h> 42 #include <sys/lock.h> 43 #include <sys/proc.h> 44 #include <sys/memdesc.h> 45 #include <sys/mutex.h> 46 #include <sys/sysctl.h> 47 #include <sys/uio.h> 48 49 #include <vm/vm.h> 50 #include <vm/vm_extern.h> 51 #include <vm/vm_kern.h> 52 #include <vm/vm_page.h> 53 #include <vm/vm_map.h> 54 55 #include <machine/atomic.h> 56 #include <machine/bus.h> 57 #include <machine/md_var.h> 58 #include <machine/bus_dma_impl.h> 59 60 #define MAX_BPAGES 4096 61 62 enum { 63 BF_COULD_BOUNCE = 0x01, 64 BF_MIN_ALLOC_COMP = 0x02, 65 BF_KMEM_ALLOC = 0x04, 66 BF_COHERENT = 0x10, 67 }; 68 69 struct bounce_page; 70 struct bounce_zone; 71 72 struct bus_dma_tag { 73 struct bus_dma_tag_common common; 74 int map_count; 75 int bounce_flags; 76 bus_dma_segment_t *segments; 77 struct bounce_zone *bounce_zone; 78 }; 79 80 static SYSCTL_NODE(_hw, OID_AUTO, busdma, CTLFLAG_RD | CTLFLAG_MPSAFE, 0, 81 "Busdma parameters"); 82 83 struct sync_list { 84 vm_offset_t vaddr; /* kva of client data */ 85 bus_addr_t paddr; /* physical address */ 86 vm_page_t pages; /* starting page of client data */ 87 bus_size_t datacount; /* client data count */ 88 }; 89 90 struct bus_dmamap { 91 STAILQ_HEAD(, bounce_page) bpages; 92 int pagesneeded; 93 int pagesreserved; 94 bus_dma_tag_t dmat; 95 struct memdesc mem; 96 bus_dmamap_callback_t *callback; 97 void *callback_arg; 98 STAILQ_ENTRY(bus_dmamap) links; 99 u_int flags; 100 #define DMAMAP_COULD_BOUNCE (1 << 0) 101 #define DMAMAP_FROM_DMAMEM (1 << 1) 102 int sync_count; 103 struct sync_list slist[]; 104 }; 105 106 int run_filter(bus_dma_tag_t dmat, bus_addr_t paddr); 107 static void _bus_dmamap_count_pages(bus_dma_tag_t dmat, bus_dmamap_t map, 108 pmap_t pmap, void *buf, bus_size_t buflen, int flags); 109 static void _bus_dmamap_count_phys(bus_dma_tag_t dmat, bus_dmamap_t map, 110 vm_paddr_t buf, bus_size_t buflen, int flags); 111 112 static MALLOC_DEFINE(M_BUSDMA, "busdma", "busdma metadata"); 113 114 #define dmat_alignment(dmat) ((dmat)->common.alignment) 115 #define dmat_flags(dmat) ((dmat)->common.flags) 116 #define dmat_lowaddr(dmat) ((dmat)->common.lowaddr) 117 #define dmat_lockfunc(dmat) ((dmat)->common.lockfunc) 118 #define dmat_lockfuncarg(dmat) ((dmat)->common.lockfuncarg) 119 120 #include "../../kern/subr_busdma_bounce.c" 121 122 /* 123 * Allocate a device specific dma_tag. 124 */ 125 static int 126 bounce_bus_dma_tag_create(bus_dma_tag_t parent, bus_size_t alignment, 127 bus_addr_t boundary, bus_addr_t lowaddr, bus_addr_t highaddr, 128 bus_dma_filter_t *filter, void *filterarg, bus_size_t maxsize, 129 int nsegments, bus_size_t maxsegsz, int flags, bus_dma_lock_t *lockfunc, 130 void *lockfuncarg, bus_dma_tag_t *dmat) 131 { 132 bus_dma_tag_t newtag; 133 int error; 134 135 *dmat = NULL; 136 error = common_bus_dma_tag_create(parent != NULL ? &parent->common : 137 NULL, alignment, boundary, lowaddr, highaddr, filter, filterarg, 138 maxsize, nsegments, maxsegsz, flags, lockfunc, lockfuncarg, 139 sizeof (struct bus_dma_tag), (void **)&newtag); 140 if (error != 0) 141 return (error); 142 143 newtag->common.impl = &bus_dma_bounce_impl; 144 newtag->map_count = 0; 145 newtag->segments = NULL; 146 147 if ((flags & BUS_DMA_COHERENT) != 0) 148 newtag->bounce_flags |= BF_COHERENT; 149 150 if (parent != NULL) { 151 if ((newtag->common.filter != NULL || 152 (parent->bounce_flags & BF_COULD_BOUNCE) != 0)) 153 newtag->bounce_flags |= BF_COULD_BOUNCE; 154 155 /* Copy some flags from the parent */ 156 newtag->bounce_flags |= parent->bounce_flags & BF_COHERENT; 157 } 158 159 if (newtag->common.lowaddr < ptoa((vm_paddr_t)Maxmem) || 160 newtag->common.alignment > 1) 161 newtag->bounce_flags |= BF_COULD_BOUNCE; 162 163 if (((newtag->bounce_flags & BF_COULD_BOUNCE) != 0) && 164 (flags & BUS_DMA_ALLOCNOW) != 0) { 165 struct bounce_zone *bz; 166 167 /* Must bounce */ 168 if ((error = alloc_bounce_zone(newtag)) != 0) { 169 free(newtag, M_DEVBUF); 170 return (error); 171 } 172 bz = newtag->bounce_zone; 173 174 if (ptoa(bz->total_bpages) < maxsize) { 175 int pages; 176 177 pages = atop(round_page(maxsize)) - bz->total_bpages; 178 179 /* Add pages to our bounce pool */ 180 if (alloc_bounce_pages(newtag, pages) < pages) 181 error = ENOMEM; 182 } 183 /* Performed initial allocation */ 184 newtag->bounce_flags |= BF_MIN_ALLOC_COMP; 185 } else 186 error = 0; 187 188 if (error != 0) 189 free(newtag, M_DEVBUF); 190 else 191 *dmat = newtag; 192 CTR4(KTR_BUSDMA, "%s returned tag %p tag flags 0x%x error %d", 193 __func__, newtag, (newtag != NULL ? newtag->common.flags : 0), 194 error); 195 return (error); 196 } 197 198 static int 199 bounce_bus_dma_tag_destroy(bus_dma_tag_t dmat) 200 { 201 #ifdef KTR 202 bus_dma_tag_t dmat_copy = dmat; 203 #endif 204 bus_dma_tag_t parent; 205 int error; 206 207 error = 0; 208 209 if (dmat != NULL) { 210 if (dmat->map_count != 0) { 211 error = EBUSY; 212 goto out; 213 } 214 while (dmat != NULL) { 215 parent = (bus_dma_tag_t)dmat->common.parent; 216 atomic_subtract_int(&dmat->common.ref_count, 1); 217 if (dmat->common.ref_count == 0) { 218 if (dmat->segments != NULL) 219 free(dmat->segments, M_DEVBUF); 220 free(dmat, M_DEVBUF); 221 /* 222 * Last reference count, so 223 * release our reference 224 * count on our parent. 225 */ 226 dmat = parent; 227 } else 228 dmat = NULL; 229 } 230 } 231 out: 232 CTR3(KTR_BUSDMA, "%s tag %p error %d", __func__, dmat_copy, error); 233 return (error); 234 } 235 236 static bus_dmamap_t 237 alloc_dmamap(bus_dma_tag_t dmat, int flags) 238 { 239 u_long mapsize; 240 bus_dmamap_t map; 241 242 mapsize = sizeof(*map); 243 mapsize += sizeof(struct sync_list) * dmat->common.nsegments; 244 map = malloc(mapsize, M_DEVBUF, flags | M_ZERO); 245 if (map == NULL) 246 return (NULL); 247 248 /* Initialize the new map */ 249 STAILQ_INIT(&map->bpages); 250 251 return (map); 252 } 253 254 /* 255 * Allocate a handle for mapping from kva/uva/physical 256 * address space into bus device space. 257 */ 258 static int 259 bounce_bus_dmamap_create(bus_dma_tag_t dmat, int flags, bus_dmamap_t *mapp) 260 { 261 struct bounce_zone *bz; 262 int error, maxpages, pages; 263 264 error = 0; 265 266 if (dmat->segments == NULL) { 267 dmat->segments = (bus_dma_segment_t *)malloc( 268 sizeof(bus_dma_segment_t) * dmat->common.nsegments, 269 M_DEVBUF, M_NOWAIT); 270 if (dmat->segments == NULL) { 271 CTR3(KTR_BUSDMA, "%s: tag %p error %d", 272 __func__, dmat, ENOMEM); 273 return (ENOMEM); 274 } 275 } 276 277 *mapp = alloc_dmamap(dmat, M_NOWAIT); 278 if (*mapp == NULL) { 279 CTR3(KTR_BUSDMA, "%s: tag %p error %d", 280 __func__, dmat, ENOMEM); 281 return (ENOMEM); 282 } 283 284 /* 285 * Bouncing might be required if the driver asks for an active 286 * exclusion region, a data alignment that is stricter than 1, and/or 287 * an active address boundary. 288 */ 289 if (dmat->bounce_flags & BF_COULD_BOUNCE) { 290 /* Must bounce */ 291 if (dmat->bounce_zone == NULL) { 292 if ((error = alloc_bounce_zone(dmat)) != 0) { 293 free(*mapp, M_DEVBUF); 294 return (error); 295 } 296 } 297 bz = dmat->bounce_zone; 298 299 (*mapp)->flags = DMAMAP_COULD_BOUNCE; 300 301 /* 302 * Attempt to add pages to our pool on a per-instance 303 * basis up to a sane limit. 304 */ 305 if (dmat->common.alignment > 1) 306 maxpages = MAX_BPAGES; 307 else 308 maxpages = MIN(MAX_BPAGES, Maxmem - 309 atop(dmat->common.lowaddr)); 310 if ((dmat->bounce_flags & BF_MIN_ALLOC_COMP) == 0 || 311 (bz->map_count > 0 && bz->total_bpages < maxpages)) { 312 pages = MAX(atop(dmat->common.maxsize), 1); 313 pages = MIN(maxpages - bz->total_bpages, pages); 314 pages = MAX(pages, 1); 315 if (alloc_bounce_pages(dmat, pages) < pages) 316 error = ENOMEM; 317 if ((dmat->bounce_flags & BF_MIN_ALLOC_COMP) 318 == 0) { 319 if (error == 0) { 320 dmat->bounce_flags |= 321 BF_MIN_ALLOC_COMP; 322 } 323 } else 324 error = 0; 325 } 326 bz->map_count++; 327 } 328 if (error == 0) 329 dmat->map_count++; 330 else 331 free(*mapp, M_DEVBUF); 332 CTR4(KTR_BUSDMA, "%s: tag %p tag flags 0x%x error %d", 333 __func__, dmat, dmat->common.flags, error); 334 return (error); 335 } 336 337 /* 338 * Destroy a handle for mapping from kva/uva/physical 339 * address space into bus device space. 340 */ 341 static int 342 bounce_bus_dmamap_destroy(bus_dma_tag_t dmat, bus_dmamap_t map) 343 { 344 345 /* Check we are destroying the correct map type */ 346 if ((map->flags & DMAMAP_FROM_DMAMEM) != 0) 347 panic("bounce_bus_dmamap_destroy: Invalid map freed\n"); 348 349 if (STAILQ_FIRST(&map->bpages) != NULL || map->sync_count != 0) { 350 CTR3(KTR_BUSDMA, "%s: tag %p error %d", __func__, dmat, EBUSY); 351 return (EBUSY); 352 } 353 if (dmat->bounce_zone) { 354 KASSERT((map->flags & DMAMAP_COULD_BOUNCE) != 0, 355 ("%s: Bounce zone when cannot bounce", __func__)); 356 dmat->bounce_zone->map_count--; 357 } 358 free(map, M_DEVBUF); 359 dmat->map_count--; 360 CTR2(KTR_BUSDMA, "%s: tag %p error 0", __func__, dmat); 361 return (0); 362 } 363 364 /* 365 * Allocate a piece of memory that can be efficiently mapped into 366 * bus device space based on the constraints lited in the dma tag. 367 * A dmamap to for use with dmamap_load is also allocated. 368 */ 369 static int 370 bounce_bus_dmamem_alloc(bus_dma_tag_t dmat, void** vaddr, int flags, 371 bus_dmamap_t *mapp) 372 { 373 /* 374 * XXX ARM64TODO: 375 * This bus_dma implementation requires IO-Coherent architecutre. 376 * If IO-Coherency is not guaranteed, the BUS_DMA_COHERENT flag has 377 * to be implented using non-cacheable memory. 378 */ 379 380 vm_memattr_t attr; 381 int mflags; 382 383 if (flags & BUS_DMA_NOWAIT) 384 mflags = M_NOWAIT; 385 else 386 mflags = M_WAITOK; 387 388 if (dmat->segments == NULL) { 389 dmat->segments = (bus_dma_segment_t *)malloc( 390 sizeof(bus_dma_segment_t) * dmat->common.nsegments, 391 M_DEVBUF, mflags); 392 if (dmat->segments == NULL) { 393 CTR4(KTR_BUSDMA, "%s: tag %p tag flags 0x%x error %d", 394 __func__, dmat, dmat->common.flags, ENOMEM); 395 return (ENOMEM); 396 } 397 } 398 if (flags & BUS_DMA_ZERO) 399 mflags |= M_ZERO; 400 if (flags & BUS_DMA_NOCACHE) 401 attr = VM_MEMATTR_UNCACHEABLE; 402 else if ((flags & BUS_DMA_COHERENT) != 0 && 403 (dmat->bounce_flags & BF_COHERENT) == 0) 404 /* 405 * If we have a non-coherent tag, and are trying to allocate 406 * a coherent block of memory it needs to be uncached. 407 */ 408 attr = VM_MEMATTR_UNCACHEABLE; 409 else 410 attr = VM_MEMATTR_DEFAULT; 411 412 /* 413 * Create the map, but don't set the could bounce flag as 414 * this allocation should never bounce; 415 */ 416 *mapp = alloc_dmamap(dmat, mflags); 417 if (*mapp == NULL) { 418 CTR4(KTR_BUSDMA, "%s: tag %p tag flags 0x%x error %d", 419 __func__, dmat, dmat->common.flags, ENOMEM); 420 return (ENOMEM); 421 } 422 (*mapp)->flags = DMAMAP_FROM_DMAMEM; 423 424 /* 425 * Allocate the buffer from the malloc(9) allocator if... 426 * - It's small enough to fit into a single power of two sized bucket. 427 * - The alignment is less than or equal to the maximum size 428 * - The low address requirement is fulfilled. 429 * else allocate non-contiguous pages if... 430 * - The page count that could get allocated doesn't exceed 431 * nsegments also when the maximum segment size is less 432 * than PAGE_SIZE. 433 * - The alignment constraint isn't larger than a page boundary. 434 * - There are no boundary-crossing constraints. 435 * else allocate a block of contiguous pages because one or more of the 436 * constraints is something that only the contig allocator can fulfill. 437 * 438 * NOTE: The (dmat->common.alignment <= dmat->maxsize) check 439 * below is just a quick hack. The exact alignment guarantees 440 * of malloc(9) need to be nailed down, and the code below 441 * should be rewritten to take that into account. 442 * 443 * In the meantime warn the user if malloc gets it wrong. 444 */ 445 if ((dmat->common.maxsize <= PAGE_SIZE) && 446 (dmat->common.alignment <= dmat->common.maxsize) && 447 dmat->common.lowaddr >= ptoa((vm_paddr_t)Maxmem) && 448 attr == VM_MEMATTR_DEFAULT) { 449 *vaddr = malloc(dmat->common.maxsize, M_DEVBUF, mflags); 450 } else if (dmat->common.nsegments >= 451 howmany(dmat->common.maxsize, MIN(dmat->common.maxsegsz, PAGE_SIZE)) && 452 dmat->common.alignment <= PAGE_SIZE && 453 (dmat->common.boundary % PAGE_SIZE) == 0) { 454 /* Page-based multi-segment allocations allowed */ 455 *vaddr = kmem_alloc_attr(dmat->common.maxsize, mflags, 456 0ul, dmat->common.lowaddr, attr); 457 dmat->bounce_flags |= BF_KMEM_ALLOC; 458 } else { 459 *vaddr = kmem_alloc_contig(dmat->common.maxsize, mflags, 460 0ul, dmat->common.lowaddr, dmat->common.alignment != 0 ? 461 dmat->common.alignment : 1ul, dmat->common.boundary, attr); 462 dmat->bounce_flags |= BF_KMEM_ALLOC; 463 } 464 if (*vaddr == NULL) { 465 CTR4(KTR_BUSDMA, "%s: tag %p tag flags 0x%x error %d", 466 __func__, dmat, dmat->common.flags, ENOMEM); 467 free(*mapp, M_DEVBUF); 468 return (ENOMEM); 469 } else if (!vm_addr_align_ok(vtophys(*vaddr), dmat->common.alignment)) { 470 printf("bus_dmamem_alloc failed to align memory properly.\n"); 471 } 472 dmat->map_count++; 473 CTR4(KTR_BUSDMA, "%s: tag %p tag flags 0x%x error %d", 474 __func__, dmat, dmat->common.flags, 0); 475 return (0); 476 } 477 478 /* 479 * Free a piece of memory and it's allociated dmamap, that was allocated 480 * via bus_dmamem_alloc. Make the same choice for free/contigfree. 481 */ 482 static void 483 bounce_bus_dmamem_free(bus_dma_tag_t dmat, void *vaddr, bus_dmamap_t map) 484 { 485 486 /* 487 * Check the map came from bounce_bus_dmamem_alloc, so the map 488 * should be NULL and the BF_KMEM_ALLOC flag cleared if malloc() 489 * was used and set if kmem_alloc_contig() was used. 490 */ 491 if ((map->flags & DMAMAP_FROM_DMAMEM) == 0) 492 panic("bus_dmamem_free: Invalid map freed\n"); 493 if ((dmat->bounce_flags & BF_KMEM_ALLOC) == 0) 494 free(vaddr, M_DEVBUF); 495 else 496 kmem_free(vaddr, dmat->common.maxsize); 497 free(map, M_DEVBUF); 498 dmat->map_count--; 499 CTR3(KTR_BUSDMA, "%s: tag %p flags 0x%x", __func__, dmat, 500 dmat->bounce_flags); 501 } 502 503 static void 504 _bus_dmamap_count_phys(bus_dma_tag_t dmat, bus_dmamap_t map, vm_paddr_t buf, 505 bus_size_t buflen, int flags) 506 { 507 bus_addr_t curaddr; 508 bus_size_t sgsize; 509 510 if ((map->flags & DMAMAP_COULD_BOUNCE) != 0 && map->pagesneeded == 0) { 511 /* 512 * Count the number of bounce pages 513 * needed in order to complete this transfer 514 */ 515 curaddr = buf; 516 while (buflen != 0) { 517 sgsize = MIN(buflen, dmat->common.maxsegsz); 518 if (bus_dma_run_filter(&dmat->common, curaddr)) { 519 sgsize = MIN(sgsize, 520 PAGE_SIZE - (curaddr & PAGE_MASK)); 521 map->pagesneeded++; 522 } 523 curaddr += sgsize; 524 buflen -= sgsize; 525 } 526 CTR1(KTR_BUSDMA, "pagesneeded= %d\n", map->pagesneeded); 527 } 528 } 529 530 static void 531 _bus_dmamap_count_pages(bus_dma_tag_t dmat, bus_dmamap_t map, pmap_t pmap, 532 void *buf, bus_size_t buflen, int flags) 533 { 534 vm_offset_t vaddr; 535 vm_offset_t vendaddr; 536 bus_addr_t paddr; 537 bus_size_t sg_len; 538 539 if ((map->flags & DMAMAP_COULD_BOUNCE) != 0 && map->pagesneeded == 0) { 540 CTR4(KTR_BUSDMA, "lowaddr= %d Maxmem= %d, boundary= %d, " 541 "alignment= %d", dmat->common.lowaddr, 542 ptoa((vm_paddr_t)Maxmem), 543 dmat->common.boundary, dmat->common.alignment); 544 CTR2(KTR_BUSDMA, "map= %p, pagesneeded= %d", map, 545 map->pagesneeded); 546 /* 547 * Count the number of bounce pages 548 * needed in order to complete this transfer 549 */ 550 vaddr = (vm_offset_t)buf; 551 vendaddr = (vm_offset_t)buf + buflen; 552 553 while (vaddr < vendaddr) { 554 sg_len = PAGE_SIZE - ((vm_offset_t)vaddr & PAGE_MASK); 555 if (pmap == kernel_pmap) 556 paddr = pmap_kextract(vaddr); 557 else 558 paddr = pmap_extract(pmap, vaddr); 559 if (bus_dma_run_filter(&dmat->common, paddr) != 0) { 560 sg_len = roundup2(sg_len, 561 dmat->common.alignment); 562 map->pagesneeded++; 563 } 564 vaddr += sg_len; 565 } 566 CTR1(KTR_BUSDMA, "pagesneeded= %d\n", map->pagesneeded); 567 } 568 } 569 570 /* 571 * Add a single contiguous physical range to the segment list. 572 */ 573 static bus_size_t 574 _bus_dmamap_addseg(bus_dma_tag_t dmat, bus_dmamap_t map, bus_addr_t curaddr, 575 bus_size_t sgsize, bus_dma_segment_t *segs, int *segp) 576 { 577 int seg; 578 579 /* 580 * Make sure we don't cross any boundaries. 581 */ 582 if (!vm_addr_bound_ok(curaddr, sgsize, dmat->common.boundary)) 583 sgsize = roundup2(curaddr, dmat->common.boundary) - curaddr; 584 585 /* 586 * Insert chunk into a segment, coalescing with 587 * previous segment if possible. 588 */ 589 seg = *segp; 590 if (seg == -1) { 591 seg = 0; 592 segs[seg].ds_addr = curaddr; 593 segs[seg].ds_len = sgsize; 594 } else { 595 if (curaddr == segs[seg].ds_addr + segs[seg].ds_len && 596 (segs[seg].ds_len + sgsize) <= dmat->common.maxsegsz && 597 vm_addr_bound_ok(segs[seg].ds_addr, 598 segs[seg].ds_len + sgsize, dmat->common.boundary)) 599 segs[seg].ds_len += sgsize; 600 else { 601 if (++seg >= dmat->common.nsegments) 602 return (0); 603 segs[seg].ds_addr = curaddr; 604 segs[seg].ds_len = sgsize; 605 } 606 } 607 *segp = seg; 608 return (sgsize); 609 } 610 611 /* 612 * Utility function to load a physical buffer. segp contains 613 * the starting segment on entrace, and the ending segment on exit. 614 */ 615 static int 616 bounce_bus_dmamap_load_phys(bus_dma_tag_t dmat, bus_dmamap_t map, 617 vm_paddr_t buf, bus_size_t buflen, int flags, bus_dma_segment_t *segs, 618 int *segp) 619 { 620 struct sync_list *sl; 621 bus_size_t sgsize; 622 bus_addr_t curaddr, sl_end; 623 int error; 624 625 if (segs == NULL) 626 segs = dmat->segments; 627 628 if ((dmat->bounce_flags & BF_COULD_BOUNCE) != 0) { 629 _bus_dmamap_count_phys(dmat, map, buf, buflen, flags); 630 if (map->pagesneeded != 0) { 631 error = _bus_dmamap_reserve_pages(dmat, map, flags); 632 if (error) 633 return (error); 634 } 635 } 636 637 sl = map->slist + map->sync_count - 1; 638 sl_end = 0; 639 640 while (buflen > 0) { 641 curaddr = buf; 642 sgsize = MIN(buflen, dmat->common.maxsegsz); 643 if (((dmat->bounce_flags & BF_COULD_BOUNCE) != 0) && 644 map->pagesneeded != 0 && 645 bus_dma_run_filter(&dmat->common, curaddr)) { 646 sgsize = MIN(sgsize, PAGE_SIZE - (curaddr & PAGE_MASK)); 647 curaddr = add_bounce_page(dmat, map, 0, curaddr, 648 sgsize); 649 } else if ((dmat->bounce_flags & BF_COHERENT) == 0) { 650 if (map->sync_count > 0) 651 sl_end = sl->paddr + sl->datacount; 652 653 if (map->sync_count == 0 || curaddr != sl_end) { 654 if (++map->sync_count > dmat->common.nsegments) 655 break; 656 sl++; 657 sl->vaddr = 0; 658 sl->paddr = curaddr; 659 sl->datacount = sgsize; 660 sl->pages = PHYS_TO_VM_PAGE(curaddr); 661 KASSERT(sl->pages != NULL, 662 ("%s: page at PA:0x%08lx is not in " 663 "vm_page_array", __func__, curaddr)); 664 } else 665 sl->datacount += sgsize; 666 } 667 sgsize = _bus_dmamap_addseg(dmat, map, curaddr, sgsize, segs, 668 segp); 669 if (sgsize == 0) 670 break; 671 buf += sgsize; 672 buflen -= sgsize; 673 } 674 675 /* 676 * Did we fit? 677 */ 678 return (buflen != 0 ? EFBIG : 0); /* XXX better return value here? */ 679 } 680 681 /* 682 * Utility function to load a linear buffer. segp contains 683 * the starting segment on entrace, and the ending segment on exit. 684 */ 685 static int 686 bounce_bus_dmamap_load_buffer(bus_dma_tag_t dmat, bus_dmamap_t map, void *buf, 687 bus_size_t buflen, pmap_t pmap, int flags, bus_dma_segment_t *segs, 688 int *segp) 689 { 690 struct sync_list *sl; 691 bus_size_t sgsize, max_sgsize; 692 bus_addr_t curaddr, sl_pend; 693 vm_offset_t kvaddr, vaddr, sl_vend; 694 int error; 695 696 if (segs == NULL) 697 segs = dmat->segments; 698 699 if ((dmat->bounce_flags & BF_COULD_BOUNCE) != 0) { 700 _bus_dmamap_count_pages(dmat, map, pmap, buf, buflen, flags); 701 if (map->pagesneeded != 0) { 702 error = _bus_dmamap_reserve_pages(dmat, map, flags); 703 if (error) 704 return (error); 705 } 706 } 707 708 sl = map->slist + map->sync_count - 1; 709 vaddr = (vm_offset_t)buf; 710 sl_pend = 0; 711 sl_vend = 0; 712 713 while (buflen > 0) { 714 /* 715 * Get the physical address for this segment. 716 */ 717 if (pmap == kernel_pmap) { 718 curaddr = pmap_kextract(vaddr); 719 kvaddr = vaddr; 720 } else { 721 curaddr = pmap_extract(pmap, vaddr); 722 kvaddr = 0; 723 } 724 725 /* 726 * Compute the segment size, and adjust counts. 727 */ 728 max_sgsize = MIN(buflen, dmat->common.maxsegsz); 729 sgsize = PAGE_SIZE - (curaddr & PAGE_MASK); 730 if (((dmat->bounce_flags & BF_COULD_BOUNCE) != 0) && 731 map->pagesneeded != 0 && 732 bus_dma_run_filter(&dmat->common, curaddr)) { 733 sgsize = roundup2(sgsize, dmat->common.alignment); 734 sgsize = MIN(sgsize, max_sgsize); 735 curaddr = add_bounce_page(dmat, map, kvaddr, curaddr, 736 sgsize); 737 } else if ((dmat->bounce_flags & BF_COHERENT) == 0) { 738 sgsize = MIN(sgsize, max_sgsize); 739 if (map->sync_count > 0) { 740 sl_pend = sl->paddr + sl->datacount; 741 sl_vend = sl->vaddr + sl->datacount; 742 } 743 744 if (map->sync_count == 0 || 745 (kvaddr != 0 && kvaddr != sl_vend) || 746 (curaddr != sl_pend)) { 747 if (++map->sync_count > dmat->common.nsegments) 748 goto cleanup; 749 sl++; 750 sl->vaddr = kvaddr; 751 sl->paddr = curaddr; 752 if (kvaddr != 0) { 753 sl->pages = NULL; 754 } else { 755 sl->pages = PHYS_TO_VM_PAGE(curaddr); 756 KASSERT(sl->pages != NULL, 757 ("%s: page at PA:0x%08lx is not " 758 "in vm_page_array", __func__, 759 curaddr)); 760 } 761 sl->datacount = sgsize; 762 } else 763 sl->datacount += sgsize; 764 } else { 765 sgsize = MIN(sgsize, max_sgsize); 766 } 767 sgsize = _bus_dmamap_addseg(dmat, map, curaddr, sgsize, segs, 768 segp); 769 if (sgsize == 0) 770 break; 771 vaddr += sgsize; 772 buflen -= sgsize; 773 } 774 775 cleanup: 776 /* 777 * Did we fit? 778 */ 779 return (buflen != 0 ? EFBIG : 0); /* XXX better return value here? */ 780 } 781 782 static void 783 bounce_bus_dmamap_waitok(bus_dma_tag_t dmat, bus_dmamap_t map, 784 struct memdesc *mem, bus_dmamap_callback_t *callback, void *callback_arg) 785 { 786 787 if ((map->flags & DMAMAP_COULD_BOUNCE) == 0) 788 return; 789 map->mem = *mem; 790 map->dmat = dmat; 791 map->callback = callback; 792 map->callback_arg = callback_arg; 793 } 794 795 static bus_dma_segment_t * 796 bounce_bus_dmamap_complete(bus_dma_tag_t dmat, bus_dmamap_t map, 797 bus_dma_segment_t *segs, int nsegs, int error) 798 { 799 800 if (segs == NULL) 801 segs = dmat->segments; 802 return (segs); 803 } 804 805 /* 806 * Release the mapping held by map. 807 */ 808 static void 809 bounce_bus_dmamap_unload(bus_dma_tag_t dmat, bus_dmamap_t map) 810 { 811 free_bounce_pages(dmat, map); 812 map->sync_count = 0; 813 } 814 815 static void 816 dma_preread_safe(vm_offset_t va, vm_size_t size) 817 { 818 /* 819 * Write back any partial cachelines immediately before and 820 * after the DMA region. 821 */ 822 if (va & (dcache_line_size - 1)) 823 cpu_dcache_wb_range(va, 1); 824 if ((va + size) & (dcache_line_size - 1)) 825 cpu_dcache_wb_range(va + size, 1); 826 827 cpu_dcache_inv_range(va, size); 828 } 829 830 static void 831 dma_dcache_sync(struct sync_list *sl, bus_dmasync_op_t op) 832 { 833 uint32_t len, offset; 834 vm_page_t m; 835 vm_paddr_t pa; 836 vm_offset_t va, tempva; 837 bus_size_t size; 838 839 offset = sl->paddr & PAGE_MASK; 840 m = sl->pages; 841 size = sl->datacount; 842 pa = sl->paddr; 843 844 for ( ; size != 0; size -= len, pa += len, offset = 0, ++m) { 845 tempva = 0; 846 if (sl->vaddr == 0) { 847 len = min(PAGE_SIZE - offset, size); 848 tempva = pmap_quick_enter_page(m); 849 va = tempva | offset; 850 KASSERT(pa == (VM_PAGE_TO_PHYS(m) | offset), 851 ("unexpected vm_page_t phys: 0x%16lx != 0x%16lx", 852 VM_PAGE_TO_PHYS(m) | offset, pa)); 853 } else { 854 len = sl->datacount; 855 va = sl->vaddr; 856 } 857 858 switch (op) { 859 case BUS_DMASYNC_PREWRITE: 860 case BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD: 861 cpu_dcache_wb_range(va, len); 862 break; 863 case BUS_DMASYNC_PREREAD: 864 /* 865 * An mbuf may start in the middle of a cacheline. There 866 * will be no cpu writes to the beginning of that line 867 * (which contains the mbuf header) while dma is in 868 * progress. Handle that case by doing a writeback of 869 * just the first cacheline before invalidating the 870 * overall buffer. Any mbuf in a chain may have this 871 * misalignment. Buffers which are not mbufs bounce if 872 * they are not aligned to a cacheline. 873 */ 874 dma_preread_safe(va, len); 875 break; 876 case BUS_DMASYNC_POSTREAD: 877 case BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE: 878 cpu_dcache_inv_range(va, len); 879 break; 880 default: 881 panic("unsupported combination of sync operations: " 882 "0x%08x\n", op); 883 } 884 885 if (tempva != 0) 886 pmap_quick_remove_page(tempva); 887 } 888 } 889 890 static void 891 bounce_bus_dmamap_sync(bus_dma_tag_t dmat, bus_dmamap_t map, 892 bus_dmasync_op_t op) 893 { 894 struct bounce_page *bpage; 895 struct sync_list *sl, *end; 896 vm_offset_t datavaddr, tempvaddr; 897 898 if (op == BUS_DMASYNC_POSTWRITE) 899 return; 900 901 if ((op & BUS_DMASYNC_POSTREAD) != 0) { 902 /* 903 * Wait for any DMA operations to complete before the bcopy. 904 */ 905 fence(); 906 } 907 908 if ((bpage = STAILQ_FIRST(&map->bpages)) != NULL) { 909 CTR4(KTR_BUSDMA, "%s: tag %p tag flags 0x%x op 0x%x " 910 "performing bounce", __func__, dmat, dmat->common.flags, 911 op); 912 913 if ((op & BUS_DMASYNC_PREWRITE) != 0) { 914 while (bpage != NULL) { 915 tempvaddr = 0; 916 datavaddr = bpage->datavaddr; 917 if (datavaddr == 0) { 918 tempvaddr = pmap_quick_enter_page( 919 bpage->datapage); 920 datavaddr = tempvaddr | bpage->dataoffs; 921 } 922 923 bcopy((void *)datavaddr, 924 (void *)bpage->vaddr, bpage->datacount); 925 if (tempvaddr != 0) 926 pmap_quick_remove_page(tempvaddr); 927 if ((dmat->bounce_flags & BF_COHERENT) == 0) 928 cpu_dcache_wb_range(bpage->vaddr, 929 bpage->datacount); 930 bpage = STAILQ_NEXT(bpage, links); 931 } 932 dmat->bounce_zone->total_bounced++; 933 } else if ((op & BUS_DMASYNC_PREREAD) != 0) { 934 while (bpage != NULL) { 935 if ((dmat->bounce_flags & BF_COHERENT) == 0) 936 cpu_dcache_wbinv_range(bpage->vaddr, 937 bpage->datacount); 938 bpage = STAILQ_NEXT(bpage, links); 939 } 940 } 941 942 if ((op & BUS_DMASYNC_POSTREAD) != 0) { 943 while (bpage != NULL) { 944 if ((dmat->bounce_flags & BF_COHERENT) == 0) 945 cpu_dcache_inv_range(bpage->vaddr, 946 bpage->datacount); 947 tempvaddr = 0; 948 datavaddr = bpage->datavaddr; 949 if (datavaddr == 0) { 950 tempvaddr = pmap_quick_enter_page( 951 bpage->datapage); 952 datavaddr = tempvaddr | bpage->dataoffs; 953 } 954 955 bcopy((void *)bpage->vaddr, 956 (void *)datavaddr, bpage->datacount); 957 958 if (tempvaddr != 0) 959 pmap_quick_remove_page(tempvaddr); 960 bpage = STAILQ_NEXT(bpage, links); 961 } 962 dmat->bounce_zone->total_bounced++; 963 } 964 } 965 966 /* 967 * Cache maintenance for normal (non-COHERENT non-bounce) buffers. 968 */ 969 if (map->sync_count != 0) { 970 sl = &map->slist[0]; 971 end = &map->slist[map->sync_count]; 972 CTR3(KTR_BUSDMA, "%s: tag %p op 0x%x " 973 "performing sync", __func__, dmat, op); 974 975 for ( ; sl != end; ++sl) 976 dma_dcache_sync(sl, op); 977 } 978 979 if ((op & (BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE)) != 0) { 980 /* 981 * Wait for the bcopy to complete before any DMA operations. 982 */ 983 fence(); 984 } 985 } 986 987 struct bus_dma_impl bus_dma_bounce_impl = { 988 .tag_create = bounce_bus_dma_tag_create, 989 .tag_destroy = bounce_bus_dma_tag_destroy, 990 .map_create = bounce_bus_dmamap_create, 991 .map_destroy = bounce_bus_dmamap_destroy, 992 .mem_alloc = bounce_bus_dmamem_alloc, 993 .mem_free = bounce_bus_dmamem_free, 994 .load_phys = bounce_bus_dmamap_load_phys, 995 .load_buffer = bounce_bus_dmamap_load_buffer, 996 .load_ma = bus_dmamap_load_ma_triv, 997 .map_waitok = bounce_bus_dmamap_waitok, 998 .map_complete = bounce_bus_dmamap_complete, 999 .map_unload = bounce_bus_dmamap_unload, 1000 .map_sync = bounce_bus_dmamap_sync 1001 }; 1002