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 <arm64/include/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 size_t alloc_size; 75 size_t alloc_alignment; 76 int map_count; 77 int bounce_flags; 78 bus_dma_segment_t *segments; 79 struct bounce_zone *bounce_zone; 80 }; 81 82 static SYSCTL_NODE(_hw, OID_AUTO, busdma, CTLFLAG_RD | CTLFLAG_MPSAFE, 0, 83 "Busdma parameters"); 84 85 struct sync_list { 86 vm_offset_t vaddr; /* kva of client data */ 87 bus_addr_t paddr; /* physical address */ 88 vm_page_t pages; /* starting page of client data */ 89 bus_size_t datacount; /* client data count */ 90 }; 91 92 struct bus_dmamap { 93 STAILQ_HEAD(, bounce_page) bpages; 94 int pagesneeded; 95 int pagesreserved; 96 bus_dma_tag_t dmat; 97 struct memdesc mem; 98 bus_dmamap_callback_t *callback; 99 void *callback_arg; 100 STAILQ_ENTRY(bus_dmamap) links; 101 u_int flags; 102 #define DMAMAP_COHERENT (1 << 0) 103 #define DMAMAP_FROM_DMAMEM (1 << 1) 104 #define DMAMAP_MBUF (1 << 2) 105 int sync_count; 106 struct sync_list slist[]; 107 }; 108 109 int run_filter(bus_dma_tag_t dmat, bus_addr_t paddr); 110 static bool _bus_dmamap_pagesneeded(bus_dma_tag_t dmat, bus_dmamap_t map, 111 vm_paddr_t buf, bus_size_t buflen, int *pagesneeded); 112 static void _bus_dmamap_count_pages(bus_dma_tag_t dmat, bus_dmamap_t map, 113 pmap_t pmap, void *buf, bus_size_t buflen, int flags); 114 static void _bus_dmamap_count_phys(bus_dma_tag_t dmat, bus_dmamap_t map, 115 vm_paddr_t buf, bus_size_t buflen, int flags); 116 117 static MALLOC_DEFINE(M_BUSDMA, "busdma", "busdma metadata"); 118 119 #define dmat_alignment(dmat) ((dmat)->common.alignment) 120 #define dmat_flags(dmat) ((dmat)->common.flags) 121 #define dmat_lowaddr(dmat) ((dmat)->common.lowaddr) 122 #define dmat_lockfunc(dmat) ((dmat)->common.lockfunc) 123 #define dmat_lockfuncarg(dmat) ((dmat)->common.lockfuncarg) 124 125 #include "../../kern/subr_busdma_bounce.c" 126 127 /* 128 * Return true if the DMA should bounce because the start or end does not fall 129 * on a cacheline boundary (which would require a partial cacheline flush). 130 * COHERENT memory doesn't trigger cacheline flushes. Memory allocated by 131 * bus_dmamem_alloc() is always aligned to cacheline boundaries, and there's a 132 * strict rule that such memory cannot be accessed by the CPU while DMA is in 133 * progress (or by multiple DMA engines at once), so that it's always safe to do 134 * full cacheline flushes even if that affects memory outside the range of a 135 * given DMA operation that doesn't involve the full allocated buffer. If we're 136 * mapping an mbuf, that follows the same rules as a buffer we allocated. 137 */ 138 static bool 139 cacheline_bounce(bus_dma_tag_t dmat, bus_dmamap_t map, bus_addr_t paddr, 140 bus_size_t size) 141 { 142 143 #define DMAMAP_CACHELINE_FLAGS \ 144 (DMAMAP_FROM_DMAMEM | DMAMAP_COHERENT | DMAMAP_MBUF) 145 if ((dmat->bounce_flags & BF_COHERENT) != 0) 146 return (false); 147 if (map != NULL && (map->flags & DMAMAP_CACHELINE_FLAGS) != 0) 148 return (false); 149 return (((paddr | size) & (dcache_line_size - 1)) != 0); 150 #undef DMAMAP_CACHELINE_FLAGS 151 } 152 153 /* 154 * Return true if the given address does not fall on the alignment boundary. 155 */ 156 static bool 157 alignment_bounce(bus_dma_tag_t dmat, bus_addr_t addr) 158 { 159 160 return (!vm_addr_align_ok(addr, dmat->common.alignment)); 161 } 162 163 static bool 164 might_bounce(bus_dma_tag_t dmat, bus_dmamap_t map, bus_addr_t paddr, 165 bus_size_t size) 166 { 167 168 /* Memory allocated by bounce_bus_dmamem_alloc won't bounce */ 169 if (map && (map->flags & DMAMAP_FROM_DMAMEM) != 0) 170 return (false); 171 172 if ((dmat->bounce_flags & BF_COULD_BOUNCE) != 0) 173 return (true); 174 175 if (cacheline_bounce(dmat, map, paddr, size)) 176 return (true); 177 178 if (alignment_bounce(dmat, paddr)) 179 return (true); 180 181 return (false); 182 } 183 184 static bool 185 must_bounce(bus_dma_tag_t dmat, bus_dmamap_t map, bus_addr_t paddr, 186 bus_size_t size) 187 { 188 189 if (cacheline_bounce(dmat, map, paddr, size)) 190 return (true); 191 192 if (alignment_bounce(dmat, paddr)) 193 return (true); 194 195 if ((dmat->bounce_flags & BF_COULD_BOUNCE) != 0 && 196 bus_dma_run_filter(&dmat->common, paddr)) 197 return (true); 198 199 return (false); 200 } 201 202 /* 203 * Allocate a device specific dma_tag. 204 */ 205 static int 206 bounce_bus_dma_tag_create(bus_dma_tag_t parent, bus_size_t alignment, 207 bus_addr_t boundary, bus_addr_t lowaddr, bus_addr_t highaddr, 208 bus_dma_filter_t *filter, void *filterarg, bus_size_t maxsize, 209 int nsegments, bus_size_t maxsegsz, int flags, bus_dma_lock_t *lockfunc, 210 void *lockfuncarg, bus_dma_tag_t *dmat) 211 { 212 bus_dma_tag_t newtag; 213 int error; 214 215 *dmat = NULL; 216 error = common_bus_dma_tag_create(parent != NULL ? &parent->common : 217 NULL, alignment, boundary, lowaddr, highaddr, filter, filterarg, 218 maxsize, nsegments, maxsegsz, flags, lockfunc, lockfuncarg, 219 sizeof (struct bus_dma_tag), (void **)&newtag); 220 if (error != 0) 221 return (error); 222 223 newtag->common.impl = &bus_dma_bounce_impl; 224 newtag->map_count = 0; 225 newtag->segments = NULL; 226 227 if ((flags & BUS_DMA_COHERENT) != 0) { 228 newtag->bounce_flags |= BF_COHERENT; 229 } 230 231 if (parent != NULL) { 232 if ((newtag->common.filter != NULL || 233 (parent->bounce_flags & BF_COULD_BOUNCE) != 0)) 234 newtag->bounce_flags |= BF_COULD_BOUNCE; 235 236 /* Copy some flags from the parent */ 237 newtag->bounce_flags |= parent->bounce_flags & BF_COHERENT; 238 } 239 240 if ((newtag->bounce_flags & BF_COHERENT) != 0) { 241 newtag->alloc_alignment = newtag->common.alignment; 242 newtag->alloc_size = newtag->common.maxsize; 243 } else { 244 /* 245 * Ensure the buffer is aligned to a cacheline when allocating 246 * a non-coherent buffer. This is so we don't have any data 247 * that another CPU may be accessing around DMA buffer 248 * causing the cache to become dirty. 249 */ 250 newtag->alloc_alignment = MAX(newtag->common.alignment, 251 dcache_line_size); 252 newtag->alloc_size = roundup2(newtag->common.maxsize, 253 dcache_line_size); 254 } 255 256 if (newtag->common.lowaddr < ptoa((vm_paddr_t)Maxmem) || 257 newtag->common.alignment > 1) 258 newtag->bounce_flags |= BF_COULD_BOUNCE; 259 260 if ((flags & BUS_DMA_ALLOCNOW) != 0) { 261 struct bounce_zone *bz; 262 /* 263 * Round size up to a full page, and add one more page because 264 * there can always be one more boundary crossing than the 265 * number of pages in a transfer. 266 */ 267 maxsize = roundup2(maxsize, PAGE_SIZE) + PAGE_SIZE; 268 269 /* Must bounce */ 270 if ((error = alloc_bounce_zone(newtag)) != 0) { 271 free(newtag, M_DEVBUF); 272 return (error); 273 } 274 bz = newtag->bounce_zone; 275 276 if (ptoa(bz->total_bpages) < maxsize) { 277 int pages; 278 279 pages = atop(maxsize) + 1 - bz->total_bpages; 280 281 /* Add pages to our bounce pool */ 282 if (alloc_bounce_pages(newtag, pages) < pages) 283 error = ENOMEM; 284 } 285 /* Performed initial allocation */ 286 newtag->bounce_flags |= BF_MIN_ALLOC_COMP; 287 } else 288 error = 0; 289 290 if (error != 0) 291 free(newtag, M_DEVBUF); 292 else 293 *dmat = newtag; 294 CTR4(KTR_BUSDMA, "%s returned tag %p tag flags 0x%x error %d", 295 __func__, newtag, (newtag != NULL ? newtag->common.flags : 0), 296 error); 297 return (error); 298 } 299 300 static int 301 bounce_bus_dma_tag_destroy(bus_dma_tag_t dmat) 302 { 303 #ifdef KTR 304 bus_dma_tag_t dmat_copy; 305 #endif 306 bus_dma_tag_t parent; 307 int error; 308 309 error = 0; 310 #ifdef KTR 311 dmat_copy = dmat; 312 #endif 313 314 315 if (dmat != NULL) { 316 if (dmat->map_count != 0) { 317 error = EBUSY; 318 goto out; 319 } 320 while (dmat != NULL) { 321 parent = (bus_dma_tag_t)dmat->common.parent; 322 atomic_subtract_int(&dmat->common.ref_count, 1); 323 if (dmat->common.ref_count == 0) { 324 if (dmat->segments != NULL) 325 free(dmat->segments, M_DEVBUF); 326 free(dmat, M_DEVBUF); 327 /* 328 * Last reference count, so 329 * release our reference 330 * count on our parent. 331 */ 332 dmat = parent; 333 } else 334 dmat = NULL; 335 } 336 } 337 out: 338 CTR3(KTR_BUSDMA, "%s tag %p error %d", __func__, dmat_copy, error); 339 return (error); 340 } 341 342 static bool 343 bounce_bus_dma_id_mapped(bus_dma_tag_t dmat, vm_paddr_t buf, bus_size_t buflen) 344 { 345 346 if (!might_bounce(dmat, NULL, buf, buflen)) 347 return (true); 348 return (!_bus_dmamap_pagesneeded(dmat, NULL, buf, buflen, NULL)); 349 } 350 351 static bus_dmamap_t 352 alloc_dmamap(bus_dma_tag_t dmat, int flags) 353 { 354 u_long mapsize; 355 bus_dmamap_t map; 356 357 mapsize = sizeof(*map); 358 mapsize += sizeof(struct sync_list) * dmat->common.nsegments; 359 map = malloc(mapsize, M_DEVBUF, flags | M_ZERO); 360 if (map == NULL) 361 return (NULL); 362 363 /* Initialize the new map */ 364 STAILQ_INIT(&map->bpages); 365 366 return (map); 367 } 368 369 /* 370 * Allocate a handle for mapping from kva/uva/physical 371 * address space into bus device space. 372 */ 373 static int 374 bounce_bus_dmamap_create(bus_dma_tag_t dmat, int flags, bus_dmamap_t *mapp) 375 { 376 struct bounce_zone *bz; 377 int error, maxpages, pages; 378 379 error = 0; 380 381 if (dmat->segments == NULL) { 382 dmat->segments = (bus_dma_segment_t *)malloc( 383 sizeof(bus_dma_segment_t) * dmat->common.nsegments, 384 M_DEVBUF, M_NOWAIT); 385 if (dmat->segments == NULL) { 386 CTR3(KTR_BUSDMA, "%s: tag %p error %d", 387 __func__, dmat, ENOMEM); 388 return (ENOMEM); 389 } 390 } 391 392 *mapp = alloc_dmamap(dmat, M_NOWAIT); 393 if (*mapp == NULL) { 394 CTR3(KTR_BUSDMA, "%s: tag %p error %d", 395 __func__, dmat, ENOMEM); 396 return (ENOMEM); 397 } 398 399 /* 400 * Bouncing might be required if the driver asks for an active 401 * exclusion region, a data alignment that is stricter than 1, and/or 402 * an active address boundary. 403 */ 404 if (dmat->bounce_zone == NULL) { 405 if ((error = alloc_bounce_zone(dmat)) != 0) { 406 free(*mapp, M_DEVBUF); 407 return (error); 408 } 409 } 410 bz = dmat->bounce_zone; 411 412 /* 413 * Attempt to add pages to our pool on a per-instance basis up to a sane 414 * limit. Even if the tag isn't subject of bouncing due to alignment 415 * and boundary constraints, it could still auto-bounce due to 416 * cacheline alignment, which requires at most two bounce pages. 417 */ 418 if (dmat->common.alignment > 1) 419 maxpages = MAX_BPAGES; 420 else 421 maxpages = MIN(MAX_BPAGES, Maxmem - 422 atop(dmat->common.lowaddr)); 423 if ((dmat->bounce_flags & BF_MIN_ALLOC_COMP) == 0 || 424 (bz->map_count > 0 && bz->total_bpages < maxpages)) { 425 pages = atop(roundup2(dmat->common.maxsize, PAGE_SIZE)) + 1; 426 pages = MIN(maxpages - bz->total_bpages, pages); 427 pages = MAX(pages, 2); 428 if (alloc_bounce_pages(dmat, pages) < pages) 429 error = ENOMEM; 430 if ((dmat->bounce_flags & BF_MIN_ALLOC_COMP) == 0) { 431 if (error == 0) { 432 dmat->bounce_flags |= BF_MIN_ALLOC_COMP; 433 } 434 } else 435 error = 0; 436 } 437 bz->map_count++; 438 439 if (error == 0) { 440 dmat->map_count++; 441 if ((dmat->bounce_flags & BF_COHERENT) != 0) 442 (*mapp)->flags |= DMAMAP_COHERENT; 443 } else { 444 free(*mapp, M_DEVBUF); 445 } 446 CTR4(KTR_BUSDMA, "%s: tag %p tag flags 0x%x error %d", 447 __func__, dmat, dmat->common.flags, error); 448 return (error); 449 } 450 451 /* 452 * Destroy a handle for mapping from kva/uva/physical 453 * address space into bus device space. 454 */ 455 static int 456 bounce_bus_dmamap_destroy(bus_dma_tag_t dmat, bus_dmamap_t map) 457 { 458 459 /* Check we are destroying the correct map type */ 460 if ((map->flags & DMAMAP_FROM_DMAMEM) != 0) 461 panic("bounce_bus_dmamap_destroy: Invalid map freed\n"); 462 463 if (STAILQ_FIRST(&map->bpages) != NULL || map->sync_count != 0) { 464 CTR3(KTR_BUSDMA, "%s: tag %p error %d", __func__, dmat, EBUSY); 465 return (EBUSY); 466 } 467 if (dmat->bounce_zone) 468 dmat->bounce_zone->map_count--; 469 free(map, M_DEVBUF); 470 dmat->map_count--; 471 CTR2(KTR_BUSDMA, "%s: tag %p error 0", __func__, dmat); 472 return (0); 473 } 474 475 /* 476 * Allocate a piece of memory that can be efficiently mapped into 477 * bus device space based on the constraints lited in the dma tag. 478 * A dmamap to for use with dmamap_load is also allocated. 479 */ 480 static int 481 bounce_bus_dmamem_alloc(bus_dma_tag_t dmat, void** vaddr, int flags, 482 bus_dmamap_t *mapp) 483 { 484 vm_memattr_t attr; 485 int mflags; 486 487 if (flags & BUS_DMA_NOWAIT) 488 mflags = M_NOWAIT; 489 else 490 mflags = M_WAITOK; 491 492 if (dmat->segments == NULL) { 493 dmat->segments = (bus_dma_segment_t *)malloc( 494 sizeof(bus_dma_segment_t) * dmat->common.nsegments, 495 M_DEVBUF, mflags); 496 if (dmat->segments == NULL) { 497 CTR4(KTR_BUSDMA, "%s: tag %p tag flags 0x%x error %d", 498 __func__, dmat, dmat->common.flags, ENOMEM); 499 return (ENOMEM); 500 } 501 } 502 if (flags & BUS_DMA_ZERO) 503 mflags |= M_ZERO; 504 if (flags & BUS_DMA_NOCACHE) 505 attr = VM_MEMATTR_UNCACHEABLE; 506 else if ((flags & BUS_DMA_COHERENT) != 0 && 507 (dmat->bounce_flags & BF_COHERENT) == 0) 508 /* 509 * If we have a non-coherent tag, and are trying to allocate 510 * a coherent block of memory it needs to be uncached. 511 */ 512 attr = VM_MEMATTR_UNCACHEABLE; 513 else 514 attr = VM_MEMATTR_DEFAULT; 515 516 /* 517 * Create the map, but don't set the could bounce flag as 518 * this allocation should never bounce; 519 */ 520 *mapp = alloc_dmamap(dmat, mflags); 521 if (*mapp == NULL) { 522 CTR4(KTR_BUSDMA, "%s: tag %p tag flags 0x%x error %d", 523 __func__, dmat, dmat->common.flags, ENOMEM); 524 return (ENOMEM); 525 } 526 527 /* 528 * Mark the map as coherent if we used uncacheable memory or the 529 * tag was already marked as coherent. 530 */ 531 if (attr == VM_MEMATTR_UNCACHEABLE || 532 (dmat->bounce_flags & BF_COHERENT) != 0) 533 (*mapp)->flags |= DMAMAP_COHERENT; 534 535 (*mapp)->flags |= DMAMAP_FROM_DMAMEM; 536 537 /* 538 * Allocate the buffer from the malloc(9) allocator if... 539 * - It's small enough to fit into a single power of two sized bucket. 540 * - The alignment is less than or equal to the maximum size 541 * - The low address requirement is fulfilled. 542 * else allocate non-contiguous pages if... 543 * - The page count that could get allocated doesn't exceed 544 * nsegments also when the maximum segment size is less 545 * than PAGE_SIZE. 546 * - The alignment constraint isn't larger than a page boundary. 547 * - There are no boundary-crossing constraints. 548 * else allocate a block of contiguous pages because one or more of the 549 * constraints is something that only the contig allocator can fulfill. 550 * 551 * NOTE: The (dmat->common.alignment <= dmat->maxsize) check 552 * below is just a quick hack. The exact alignment guarantees 553 * of malloc(9) need to be nailed down, and the code below 554 * should be rewritten to take that into account. 555 * 556 * In the meantime warn the user if malloc gets it wrong. 557 */ 558 if ((dmat->alloc_size <= PAGE_SIZE) && 559 (dmat->alloc_alignment <= dmat->alloc_size) && 560 dmat->common.lowaddr >= ptoa((vm_paddr_t)Maxmem) && 561 attr == VM_MEMATTR_DEFAULT) { 562 *vaddr = malloc(dmat->alloc_size, M_DEVBUF, mflags); 563 } else if (dmat->common.nsegments >= 564 howmany(dmat->alloc_size, MIN(dmat->common.maxsegsz, PAGE_SIZE)) && 565 dmat->alloc_alignment <= PAGE_SIZE && 566 (dmat->common.boundary % PAGE_SIZE) == 0) { 567 /* Page-based multi-segment allocations allowed */ 568 *vaddr = kmem_alloc_attr(dmat->alloc_size, mflags, 569 0ul, dmat->common.lowaddr, attr); 570 dmat->bounce_flags |= BF_KMEM_ALLOC; 571 } else { 572 *vaddr = kmem_alloc_contig(dmat->alloc_size, mflags, 573 0ul, dmat->common.lowaddr, dmat->alloc_alignment != 0 ? 574 dmat->alloc_alignment : 1ul, dmat->common.boundary, attr); 575 dmat->bounce_flags |= BF_KMEM_ALLOC; 576 } 577 if (*vaddr == NULL) { 578 CTR4(KTR_BUSDMA, "%s: tag %p tag flags 0x%x error %d", 579 __func__, dmat, dmat->common.flags, ENOMEM); 580 free(*mapp, M_DEVBUF); 581 return (ENOMEM); 582 } else if (!vm_addr_align_ok(vtophys(*vaddr), dmat->alloc_alignment)) { 583 printf("bus_dmamem_alloc failed to align memory properly.\n"); 584 } 585 dmat->map_count++; 586 CTR4(KTR_BUSDMA, "%s: tag %p tag flags 0x%x error %d", 587 __func__, dmat, dmat->common.flags, 0); 588 return (0); 589 } 590 591 /* 592 * Free a piece of memory and it's allociated dmamap, that was allocated 593 * via bus_dmamem_alloc. Make the same choice for free/contigfree. 594 */ 595 static void 596 bounce_bus_dmamem_free(bus_dma_tag_t dmat, void *vaddr, bus_dmamap_t map) 597 { 598 599 /* 600 * Check the map came from bounce_bus_dmamem_alloc, so the map 601 * should be NULL and the BF_KMEM_ALLOC flag cleared if malloc() 602 * was used and set if kmem_alloc_contig() was used. 603 */ 604 if ((map->flags & DMAMAP_FROM_DMAMEM) == 0) 605 panic("bus_dmamem_free: Invalid map freed\n"); 606 if ((dmat->bounce_flags & BF_KMEM_ALLOC) == 0) 607 free(vaddr, M_DEVBUF); 608 else 609 kmem_free(vaddr, dmat->alloc_size); 610 free(map, M_DEVBUF); 611 dmat->map_count--; 612 CTR3(KTR_BUSDMA, "%s: tag %p flags 0x%x", __func__, dmat, 613 dmat->bounce_flags); 614 } 615 616 static bool 617 _bus_dmamap_pagesneeded(bus_dma_tag_t dmat, bus_dmamap_t map, vm_paddr_t buf, 618 bus_size_t buflen, int *pagesneeded) 619 { 620 bus_addr_t curaddr; 621 bus_size_t sgsize; 622 int count; 623 624 /* 625 * Count the number of bounce pages needed in order to 626 * complete this transfer 627 */ 628 count = 0; 629 curaddr = buf; 630 while (buflen != 0) { 631 sgsize = MIN(buflen, dmat->common.maxsegsz); 632 if (must_bounce(dmat, map, curaddr, sgsize)) { 633 sgsize = MIN(sgsize, 634 PAGE_SIZE - (curaddr & PAGE_MASK)); 635 if (pagesneeded == NULL) 636 return (true); 637 count++; 638 } 639 curaddr += sgsize; 640 buflen -= sgsize; 641 } 642 643 if (pagesneeded != NULL) 644 *pagesneeded = count; 645 return (count != 0); 646 } 647 648 static void 649 _bus_dmamap_count_phys(bus_dma_tag_t dmat, bus_dmamap_t map, vm_paddr_t buf, 650 bus_size_t buflen, int flags) 651 { 652 653 if (map->pagesneeded == 0) { 654 _bus_dmamap_pagesneeded(dmat, map, buf, buflen, 655 &map->pagesneeded); 656 CTR1(KTR_BUSDMA, "pagesneeded= %d\n", map->pagesneeded); 657 } 658 } 659 660 static void 661 _bus_dmamap_count_pages(bus_dma_tag_t dmat, bus_dmamap_t map, pmap_t pmap, 662 void *buf, bus_size_t buflen, int flags) 663 { 664 vm_offset_t vaddr; 665 vm_offset_t vendaddr; 666 bus_addr_t paddr; 667 bus_size_t sg_len; 668 669 if (map->pagesneeded == 0) { 670 CTR4(KTR_BUSDMA, "lowaddr= %d Maxmem= %d, boundary= %d, " 671 "alignment= %d", dmat->common.lowaddr, 672 ptoa((vm_paddr_t)Maxmem), 673 dmat->common.boundary, dmat->common.alignment); 674 CTR2(KTR_BUSDMA, "map= %p, pagesneeded= %d", map, 675 map->pagesneeded); 676 /* 677 * Count the number of bounce pages 678 * needed in order to complete this transfer 679 */ 680 vaddr = (vm_offset_t)buf; 681 vendaddr = (vm_offset_t)buf + buflen; 682 683 while (vaddr < vendaddr) { 684 sg_len = PAGE_SIZE - ((vm_offset_t)vaddr & PAGE_MASK); 685 if (pmap == kernel_pmap) 686 paddr = pmap_kextract(vaddr); 687 else 688 paddr = pmap_extract(pmap, vaddr); 689 if (must_bounce(dmat, map, paddr, 690 min(vendaddr - vaddr, (PAGE_SIZE - ((vm_offset_t)vaddr & 691 PAGE_MASK)))) != 0) { 692 sg_len = roundup2(sg_len, 693 dmat->common.alignment); 694 map->pagesneeded++; 695 } 696 vaddr += sg_len; 697 } 698 CTR1(KTR_BUSDMA, "pagesneeded= %d\n", map->pagesneeded); 699 } 700 } 701 702 /* 703 * Add a single contiguous physical range to the segment list. 704 */ 705 static bus_size_t 706 _bus_dmamap_addseg(bus_dma_tag_t dmat, bus_dmamap_t map, bus_addr_t curaddr, 707 bus_size_t sgsize, bus_dma_segment_t *segs, int *segp) 708 { 709 int seg; 710 711 /* 712 * Make sure we don't cross any boundaries. 713 */ 714 if (!vm_addr_bound_ok(curaddr, sgsize, dmat->common.boundary)) 715 sgsize = roundup2(curaddr, dmat->common.boundary) - curaddr; 716 717 /* 718 * Insert chunk into a segment, coalescing with 719 * previous segment if possible. 720 */ 721 seg = *segp; 722 if (seg == -1) { 723 seg = 0; 724 segs[seg].ds_addr = curaddr; 725 segs[seg].ds_len = sgsize; 726 } else { 727 if (curaddr == segs[seg].ds_addr + segs[seg].ds_len && 728 (segs[seg].ds_len + sgsize) <= dmat->common.maxsegsz && 729 vm_addr_bound_ok(segs[seg].ds_addr, 730 segs[seg].ds_len + sgsize, dmat->common.boundary)) 731 segs[seg].ds_len += sgsize; 732 else { 733 if (++seg >= dmat->common.nsegments) 734 return (0); 735 segs[seg].ds_addr = curaddr; 736 segs[seg].ds_len = sgsize; 737 } 738 } 739 *segp = seg; 740 return (sgsize); 741 } 742 743 /* 744 * Utility function to load a physical buffer. segp contains 745 * the starting segment on entrace, and the ending segment on exit. 746 */ 747 static int 748 bounce_bus_dmamap_load_phys(bus_dma_tag_t dmat, bus_dmamap_t map, 749 vm_paddr_t buf, bus_size_t buflen, int flags, bus_dma_segment_t *segs, 750 int *segp) 751 { 752 struct sync_list *sl; 753 bus_size_t sgsize; 754 bus_addr_t curaddr, sl_end; 755 int error; 756 757 if (segs == NULL) 758 segs = dmat->segments; 759 760 if (might_bounce(dmat, map, (bus_addr_t)buf, buflen)) { 761 _bus_dmamap_count_phys(dmat, map, buf, buflen, flags); 762 if (map->pagesneeded != 0) { 763 error = _bus_dmamap_reserve_pages(dmat, map, flags); 764 if (error) 765 return (error); 766 } 767 } 768 769 sl = map->slist + map->sync_count - 1; 770 sl_end = 0; 771 772 while (buflen > 0) { 773 curaddr = buf; 774 sgsize = MIN(buflen, dmat->common.maxsegsz); 775 if (map->pagesneeded != 0 && 776 must_bounce(dmat, map, curaddr, sgsize)) { 777 /* 778 * The attempt to split a physically continuous buffer 779 * seems very controversial, it's unclear whether we 780 * can do this in all cases. Also, memory for bounced 781 * buffers is allocated as pages, so we cannot 782 * guarantee multipage alignment. 783 */ 784 KASSERT(dmat->common.alignment <= PAGE_SIZE, 785 ("bounced buffer cannot have alignment bigger " 786 "than PAGE_SIZE: %lu", dmat->common.alignment)); 787 sgsize = MIN(sgsize, PAGE_SIZE - (curaddr & PAGE_MASK)); 788 curaddr = add_bounce_page(dmat, map, 0, curaddr, 789 sgsize); 790 } else if ((map->flags & DMAMAP_COHERENT) == 0) { 791 if (map->sync_count > 0) 792 sl_end = sl->paddr + sl->datacount; 793 794 if (map->sync_count == 0 || curaddr != sl_end) { 795 if (++map->sync_count > dmat->common.nsegments) 796 break; 797 sl++; 798 sl->vaddr = 0; 799 sl->paddr = curaddr; 800 sl->pages = PHYS_TO_VM_PAGE(curaddr); 801 KASSERT(sl->pages != NULL, 802 ("%s: page at PA:0x%08lx is not in " 803 "vm_page_array", __func__, curaddr)); 804 sl->datacount = sgsize; 805 } else 806 sl->datacount += sgsize; 807 } 808 sgsize = _bus_dmamap_addseg(dmat, map, curaddr, sgsize, segs, 809 segp); 810 if (sgsize == 0) 811 break; 812 buf += sgsize; 813 buflen -= sgsize; 814 } 815 816 /* 817 * Did we fit? 818 */ 819 if (buflen != 0) { 820 bus_dmamap_unload(dmat, map); 821 return (EFBIG); /* XXX better return value here? */ 822 } 823 return (0); 824 } 825 826 /* 827 * Utility function to load a linear buffer. segp contains 828 * the starting segment on entrace, and the ending segment on exit. 829 */ 830 static int 831 bounce_bus_dmamap_load_buffer(bus_dma_tag_t dmat, bus_dmamap_t map, void *buf, 832 bus_size_t buflen, pmap_t pmap, int flags, bus_dma_segment_t *segs, 833 int *segp) 834 { 835 struct sync_list *sl; 836 bus_size_t sgsize; 837 bus_addr_t curaddr, sl_pend; 838 vm_offset_t kvaddr, vaddr, sl_vend; 839 int error; 840 841 KASSERT((map->flags & DMAMAP_FROM_DMAMEM) != 0 || 842 dmat->common.alignment <= PAGE_SIZE, 843 ("loading user buffer with alignment bigger than PAGE_SIZE is not " 844 "supported")); 845 846 if (segs == NULL) 847 segs = dmat->segments; 848 849 if (flags & BUS_DMA_LOAD_MBUF) 850 map->flags |= DMAMAP_MBUF; 851 852 if (might_bounce(dmat, map, (bus_addr_t)buf, buflen)) { 853 _bus_dmamap_count_pages(dmat, map, pmap, buf, buflen, flags); 854 if (map->pagesneeded != 0) { 855 error = _bus_dmamap_reserve_pages(dmat, map, flags); 856 if (error) 857 return (error); 858 } 859 } 860 861 /* 862 * XXX Optimally we should parse input buffer for physically 863 * continuous segments first and then pass these segment into 864 * load loop. 865 */ 866 sl = map->slist + map->sync_count - 1; 867 vaddr = (vm_offset_t)buf; 868 sl_pend = 0; 869 sl_vend = 0; 870 871 while (buflen > 0) { 872 /* 873 * Get the physical address for this segment. 874 */ 875 if (__predict_true(pmap == kernel_pmap)) { 876 curaddr = pmap_kextract(vaddr); 877 kvaddr = vaddr; 878 } else { 879 curaddr = pmap_extract(pmap, vaddr); 880 kvaddr = 0; 881 } 882 883 /* 884 * Compute the segment size, and adjust counts. 885 */ 886 sgsize = MIN(buflen, dmat->common.maxsegsz); 887 if ((map->flags & DMAMAP_FROM_DMAMEM) == 0) 888 sgsize = MIN(sgsize, PAGE_SIZE - (curaddr & PAGE_MASK)); 889 890 if (map->pagesneeded != 0 && 891 must_bounce(dmat, map, curaddr, sgsize)) { 892 /* See comment in bounce_bus_dmamap_load_phys */ 893 KASSERT(dmat->common.alignment <= PAGE_SIZE, 894 ("bounced buffer cannot have alignment bigger " 895 "than PAGE_SIZE: %lu", dmat->common.alignment)); 896 curaddr = add_bounce_page(dmat, map, kvaddr, curaddr, 897 sgsize); 898 } else if ((map->flags & DMAMAP_COHERENT) == 0) { 899 if (map->sync_count > 0) { 900 sl_pend = sl->paddr + sl->datacount; 901 sl_vend = sl->vaddr + sl->datacount; 902 } 903 904 if (map->sync_count == 0 || 905 (kvaddr != 0 && kvaddr != sl_vend) || 906 (curaddr != sl_pend)) { 907 if (++map->sync_count > dmat->common.nsegments) 908 break; 909 sl++; 910 sl->vaddr = kvaddr; 911 sl->paddr = curaddr; 912 if (kvaddr != 0) { 913 sl->pages = NULL; 914 } else { 915 sl->pages = PHYS_TO_VM_PAGE(curaddr); 916 KASSERT(sl->pages != NULL, 917 ("%s: page at PA:0x%08lx is not " 918 "in vm_page_array", __func__, 919 curaddr)); 920 } 921 sl->datacount = sgsize; 922 } else 923 sl->datacount += sgsize; 924 } 925 sgsize = _bus_dmamap_addseg(dmat, map, curaddr, sgsize, segs, 926 segp); 927 if (sgsize == 0) 928 break; 929 vaddr += sgsize; 930 buflen -= sgsize; 931 } 932 933 /* 934 * Did we fit? 935 */ 936 if (buflen != 0) { 937 bus_dmamap_unload(dmat, map); 938 return (EFBIG); /* XXX better return value here? */ 939 } 940 return (0); 941 } 942 943 static void 944 bounce_bus_dmamap_waitok(bus_dma_tag_t dmat, bus_dmamap_t map, 945 struct memdesc *mem, bus_dmamap_callback_t *callback, void *callback_arg) 946 { 947 948 map->mem = *mem; 949 map->dmat = dmat; 950 map->callback = callback; 951 map->callback_arg = callback_arg; 952 } 953 954 static bus_dma_segment_t * 955 bounce_bus_dmamap_complete(bus_dma_tag_t dmat, bus_dmamap_t map, 956 bus_dma_segment_t *segs, int nsegs, int error) 957 { 958 959 if (segs == NULL) 960 segs = dmat->segments; 961 return (segs); 962 } 963 964 /* 965 * Release the mapping held by map. 966 */ 967 static void 968 bounce_bus_dmamap_unload(bus_dma_tag_t dmat, bus_dmamap_t map) 969 { 970 free_bounce_pages(dmat, map); 971 map->sync_count = 0; 972 map->flags &= ~DMAMAP_MBUF; 973 } 974 975 static void 976 dma_preread_safe(vm_offset_t va, vm_size_t size) 977 { 978 /* 979 * Write back any partial cachelines immediately before and 980 * after the DMA region. 981 */ 982 if (va & (dcache_line_size - 1)) 983 cpu_dcache_wb_range(va, 1); 984 if ((va + size) & (dcache_line_size - 1)) 985 cpu_dcache_wb_range(va + size, 1); 986 987 cpu_dcache_inv_range(va, size); 988 } 989 990 static void 991 dma_dcache_sync(struct sync_list *sl, bus_dmasync_op_t op) 992 { 993 uint32_t len, offset; 994 vm_page_t m; 995 vm_paddr_t pa; 996 vm_offset_t va, tempva; 997 bus_size_t size; 998 999 offset = sl->paddr & PAGE_MASK; 1000 m = sl->pages; 1001 size = sl->datacount; 1002 pa = sl->paddr; 1003 1004 for ( ; size != 0; size -= len, pa += len, offset = 0, ++m) { 1005 tempva = 0; 1006 if (sl->vaddr == 0) { 1007 len = min(PAGE_SIZE - offset, size); 1008 tempva = pmap_quick_enter_page(m); 1009 va = tempva | offset; 1010 KASSERT(pa == (VM_PAGE_TO_PHYS(m) | offset), 1011 ("unexpected vm_page_t phys: 0x%16lx != 0x%16lx", 1012 VM_PAGE_TO_PHYS(m) | offset, pa)); 1013 } else { 1014 len = sl->datacount; 1015 va = sl->vaddr; 1016 } 1017 1018 switch (op) { 1019 case BUS_DMASYNC_PREWRITE: 1020 case BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD: 1021 cpu_dcache_wb_range(va, len); 1022 break; 1023 case BUS_DMASYNC_PREREAD: 1024 /* 1025 * An mbuf may start in the middle of a cacheline. There 1026 * will be no cpu writes to the beginning of that line 1027 * (which contains the mbuf header) while dma is in 1028 * progress. Handle that case by doing a writeback of 1029 * just the first cacheline before invalidating the 1030 * overall buffer. Any mbuf in a chain may have this 1031 * misalignment. Buffers which are not mbufs bounce if 1032 * they are not aligned to a cacheline. 1033 */ 1034 dma_preread_safe(va, len); 1035 break; 1036 case BUS_DMASYNC_POSTREAD: 1037 case BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE: 1038 cpu_dcache_inv_range(va, len); 1039 break; 1040 default: 1041 panic("unsupported combination of sync operations: " 1042 "0x%08x\n", op); 1043 } 1044 1045 if (tempva != 0) 1046 pmap_quick_remove_page(tempva); 1047 } 1048 } 1049 1050 static void 1051 bounce_bus_dmamap_sync(bus_dma_tag_t dmat, bus_dmamap_t map, 1052 bus_dmasync_op_t op) 1053 { 1054 struct bounce_page *bpage; 1055 struct sync_list *sl, *end; 1056 vm_offset_t datavaddr, tempvaddr; 1057 1058 if (op == BUS_DMASYNC_POSTWRITE) 1059 return; 1060 1061 if ((op & BUS_DMASYNC_POSTREAD) != 0) { 1062 /* 1063 * Wait for any DMA operations to complete before the bcopy. 1064 */ 1065 dsb(sy); 1066 } 1067 1068 if ((bpage = STAILQ_FIRST(&map->bpages)) != NULL) { 1069 CTR4(KTR_BUSDMA, "%s: tag %p tag flags 0x%x op 0x%x " 1070 "performing bounce", __func__, dmat, dmat->common.flags, 1071 op); 1072 1073 if ((op & BUS_DMASYNC_PREWRITE) != 0) { 1074 while (bpage != NULL) { 1075 tempvaddr = 0; 1076 datavaddr = bpage->datavaddr; 1077 if (datavaddr == 0) { 1078 tempvaddr = pmap_quick_enter_page( 1079 bpage->datapage); 1080 datavaddr = tempvaddr | bpage->dataoffs; 1081 } 1082 1083 bcopy((void *)datavaddr, 1084 (void *)bpage->vaddr, bpage->datacount); 1085 if (tempvaddr != 0) 1086 pmap_quick_remove_page(tempvaddr); 1087 if ((map->flags & DMAMAP_COHERENT) == 0) 1088 cpu_dcache_wb_range(bpage->vaddr, 1089 bpage->datacount); 1090 bpage = STAILQ_NEXT(bpage, links); 1091 } 1092 dmat->bounce_zone->total_bounced++; 1093 } else if ((op & BUS_DMASYNC_PREREAD) != 0) { 1094 while (bpage != NULL) { 1095 if ((map->flags & DMAMAP_COHERENT) == 0) 1096 cpu_dcache_wbinv_range(bpage->vaddr, 1097 bpage->datacount); 1098 bpage = STAILQ_NEXT(bpage, links); 1099 } 1100 } 1101 1102 if ((op & BUS_DMASYNC_POSTREAD) != 0) { 1103 while (bpage != NULL) { 1104 if ((map->flags & DMAMAP_COHERENT) == 0) 1105 cpu_dcache_inv_range(bpage->vaddr, 1106 bpage->datacount); 1107 tempvaddr = 0; 1108 datavaddr = bpage->datavaddr; 1109 if (datavaddr == 0) { 1110 tempvaddr = pmap_quick_enter_page( 1111 bpage->datapage); 1112 datavaddr = tempvaddr | bpage->dataoffs; 1113 } 1114 1115 bcopy((void *)bpage->vaddr, 1116 (void *)datavaddr, bpage->datacount); 1117 1118 if (tempvaddr != 0) 1119 pmap_quick_remove_page(tempvaddr); 1120 bpage = STAILQ_NEXT(bpage, links); 1121 } 1122 dmat->bounce_zone->total_bounced++; 1123 } 1124 } 1125 1126 /* 1127 * Cache maintenance for normal (non-COHERENT non-bounce) buffers. 1128 */ 1129 if (map->sync_count != 0) { 1130 sl = &map->slist[0]; 1131 end = &map->slist[map->sync_count]; 1132 CTR3(KTR_BUSDMA, "%s: tag %p op 0x%x " 1133 "performing sync", __func__, dmat, op); 1134 1135 for ( ; sl != end; ++sl) 1136 dma_dcache_sync(sl, op); 1137 } 1138 1139 if ((op & (BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE)) != 0) { 1140 /* 1141 * Wait for the bcopy to complete before any DMA operations. 1142 */ 1143 dsb(sy); 1144 } 1145 } 1146 1147 struct bus_dma_impl bus_dma_bounce_impl = { 1148 .tag_create = bounce_bus_dma_tag_create, 1149 .tag_destroy = bounce_bus_dma_tag_destroy, 1150 .id_mapped = bounce_bus_dma_id_mapped, 1151 .map_create = bounce_bus_dmamap_create, 1152 .map_destroy = bounce_bus_dmamap_destroy, 1153 .mem_alloc = bounce_bus_dmamem_alloc, 1154 .mem_free = bounce_bus_dmamem_free, 1155 .load_phys = bounce_bus_dmamap_load_phys, 1156 .load_buffer = bounce_bus_dmamap_load_buffer, 1157 .load_ma = bus_dmamap_load_ma_triv, 1158 .map_waitok = bounce_bus_dmamap_waitok, 1159 .map_complete = bounce_bus_dmamap_complete, 1160 .map_unload = bounce_bus_dmamap_unload, 1161 .map_sync = bounce_bus_dmamap_sync 1162 }; 1163