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 __FBSDID("$FreeBSD$"); 36 37 #include <sys/param.h> 38 #include <sys/systm.h> 39 #include <sys/malloc.h> 40 #include <sys/bus.h> 41 #include <sys/interrupt.h> 42 #include <sys/kernel.h> 43 #include <sys/ktr.h> 44 #include <sys/lock.h> 45 #include <sys/proc.h> 46 #include <sys/memdesc.h> 47 #include <sys/mutex.h> 48 #include <sys/sysctl.h> 49 #include <sys/uio.h> 50 51 #include <vm/vm.h> 52 #include <vm/vm_extern.h> 53 #include <vm/vm_kern.h> 54 #include <vm/vm_page.h> 55 #include <vm/vm_map.h> 56 57 #include <machine/atomic.h> 58 #include <machine/bus.h> 59 #include <machine/md_var.h> 60 #include <arm64/include/bus_dma_impl.h> 61 62 #define MAX_BPAGES 4096 63 64 enum { 65 BF_COULD_BOUNCE = 0x01, 66 BF_MIN_ALLOC_COMP = 0x02, 67 BF_KMEM_ALLOC = 0x04, 68 BF_COHERENT = 0x10, 69 }; 70 71 struct bounce_zone; 72 73 struct bus_dma_tag { 74 struct bus_dma_tag_common common; 75 size_t alloc_size; 76 size_t alloc_alignment; 77 int map_count; 78 int bounce_flags; 79 bus_dma_segment_t *segments; 80 struct bounce_zone *bounce_zone; 81 }; 82 83 struct bounce_page { 84 vm_offset_t vaddr; /* kva of bounce buffer */ 85 bus_addr_t busaddr; /* Physical address */ 86 vm_offset_t datavaddr; /* kva of client data */ 87 vm_page_t datapage; /* physical page of client data */ 88 vm_offset_t dataoffs; /* page offset of client data */ 89 bus_size_t datacount; /* client data count */ 90 STAILQ_ENTRY(bounce_page) links; 91 }; 92 93 int busdma_swi_pending; 94 95 struct bounce_zone { 96 STAILQ_ENTRY(bounce_zone) links; 97 STAILQ_HEAD(bp_list, bounce_page) bounce_page_list; 98 int total_bpages; 99 int free_bpages; 100 int reserved_bpages; 101 int active_bpages; 102 int total_bounced; 103 int total_deferred; 104 int map_count; 105 bus_size_t alignment; 106 bus_addr_t lowaddr; 107 char zoneid[8]; 108 char lowaddrid[20]; 109 struct sysctl_ctx_list sysctl_tree; 110 struct sysctl_oid *sysctl_tree_top; 111 }; 112 113 static struct mtx bounce_lock; 114 static int total_bpages; 115 static int busdma_zonecount; 116 static STAILQ_HEAD(, bounce_zone) bounce_zone_list; 117 118 static SYSCTL_NODE(_hw, OID_AUTO, busdma, CTLFLAG_RD | CTLFLAG_MPSAFE, 0, 119 "Busdma parameters"); 120 SYSCTL_INT(_hw_busdma, OID_AUTO, total_bpages, CTLFLAG_RD, &total_bpages, 0, 121 "Total bounce pages"); 122 123 struct sync_list { 124 vm_offset_t vaddr; /* kva of client data */ 125 bus_addr_t paddr; /* physical address */ 126 vm_page_t pages; /* starting page of client data */ 127 bus_size_t datacount; /* client data count */ 128 }; 129 130 struct bus_dmamap { 131 struct bp_list bpages; 132 int pagesneeded; 133 int pagesreserved; 134 bus_dma_tag_t dmat; 135 struct memdesc mem; 136 bus_dmamap_callback_t *callback; 137 void *callback_arg; 138 STAILQ_ENTRY(bus_dmamap) links; 139 u_int flags; 140 #define DMAMAP_COHERENT (1 << 0) 141 #define DMAMAP_FROM_DMAMEM (1 << 1) 142 #define DMAMAP_MBUF (1 << 2) 143 int sync_count; 144 struct sync_list slist[]; 145 }; 146 147 static STAILQ_HEAD(, bus_dmamap) bounce_map_waitinglist; 148 static STAILQ_HEAD(, bus_dmamap) bounce_map_callbacklist; 149 150 static void init_bounce_pages(void *dummy); 151 static int alloc_bounce_zone(bus_dma_tag_t dmat); 152 static int alloc_bounce_pages(bus_dma_tag_t dmat, u_int numpages); 153 static int reserve_bounce_pages(bus_dma_tag_t dmat, bus_dmamap_t map, 154 int commit); 155 static bus_addr_t add_bounce_page(bus_dma_tag_t dmat, bus_dmamap_t map, 156 vm_offset_t vaddr, bus_addr_t addr, bus_size_t size); 157 static void free_bounce_page(bus_dma_tag_t dmat, struct bounce_page *bpage); 158 int run_filter(bus_dma_tag_t dmat, bus_addr_t paddr); 159 static bool _bus_dmamap_pagesneeded(bus_dma_tag_t dmat, bus_dmamap_t map, 160 vm_paddr_t buf, bus_size_t buflen, int *pagesneeded); 161 static void _bus_dmamap_count_pages(bus_dma_tag_t dmat, bus_dmamap_t map, 162 pmap_t pmap, void *buf, bus_size_t buflen, int flags); 163 static void _bus_dmamap_count_phys(bus_dma_tag_t dmat, bus_dmamap_t map, 164 vm_paddr_t buf, bus_size_t buflen, int flags); 165 static int _bus_dmamap_reserve_pages(bus_dma_tag_t dmat, bus_dmamap_t map, 166 int flags); 167 168 /* 169 * Return true if the DMA should bounce because the start or end does not fall 170 * on a cacheline boundary (which would require a partial cacheline flush). 171 * COHERENT memory doesn't trigger cacheline flushes. Memory allocated by 172 * bus_dmamem_alloc() is always aligned to cacheline boundaries, and there's a 173 * strict rule that such memory cannot be accessed by the CPU while DMA is in 174 * progress (or by multiple DMA engines at once), so that it's always safe to do 175 * full cacheline flushes even if that affects memory outside the range of a 176 * given DMA operation that doesn't involve the full allocated buffer. If we're 177 * mapping an mbuf, that follows the same rules as a buffer we allocated. 178 */ 179 static bool 180 cacheline_bounce(bus_dma_tag_t dmat, bus_dmamap_t map, bus_addr_t paddr, 181 bus_size_t size) 182 { 183 184 #define DMAMAP_CACHELINE_FLAGS \ 185 (DMAMAP_FROM_DMAMEM | DMAMAP_COHERENT | DMAMAP_MBUF) 186 if ((dmat->bounce_flags & BF_COHERENT) != 0) 187 return (false); 188 if (map != NULL && (map->flags & DMAMAP_CACHELINE_FLAGS) != 0) 189 return (false); 190 return (((paddr | size) & (dcache_line_size - 1)) != 0); 191 #undef DMAMAP_CACHELINE_FLAGS 192 } 193 194 /* 195 * Return true if the given address does not fall on the alignment boundary. 196 */ 197 static bool 198 alignment_bounce(bus_dma_tag_t dmat, bus_addr_t addr) 199 { 200 201 return ((addr & (dmat->common.alignment - 1)) != 0); 202 } 203 204 static bool 205 might_bounce(bus_dma_tag_t dmat, bus_dmamap_t map, bus_addr_t paddr, 206 bus_size_t size) 207 { 208 209 /* Memory allocated by bounce_bus_dmamem_alloc won't bounce */ 210 if (map && (map->flags & DMAMAP_FROM_DMAMEM) != 0) 211 return (false); 212 213 if ((dmat->bounce_flags & BF_COULD_BOUNCE) != 0) 214 return (true); 215 216 if (cacheline_bounce(dmat, map, paddr, size)) 217 return (true); 218 219 if (alignment_bounce(dmat, paddr)) 220 return (true); 221 222 return (false); 223 } 224 225 static bool 226 must_bounce(bus_dma_tag_t dmat, bus_dmamap_t map, bus_addr_t paddr, 227 bus_size_t size) 228 { 229 230 if (cacheline_bounce(dmat, map, paddr, size)) 231 return (true); 232 233 if (alignment_bounce(dmat, paddr)) 234 return (true); 235 236 if ((dmat->bounce_flags & BF_COULD_BOUNCE) != 0 && 237 bus_dma_run_filter(&dmat->common, paddr)) 238 return (true); 239 240 return (false); 241 } 242 243 /* 244 * Allocate a device specific dma_tag. 245 */ 246 static int 247 bounce_bus_dma_tag_create(bus_dma_tag_t parent, bus_size_t alignment, 248 bus_addr_t boundary, bus_addr_t lowaddr, bus_addr_t highaddr, 249 bus_dma_filter_t *filter, void *filterarg, bus_size_t maxsize, 250 int nsegments, bus_size_t maxsegsz, int flags, bus_dma_lock_t *lockfunc, 251 void *lockfuncarg, bus_dma_tag_t *dmat) 252 { 253 bus_dma_tag_t newtag; 254 int error; 255 256 *dmat = NULL; 257 error = common_bus_dma_tag_create(parent != NULL ? &parent->common : 258 NULL, alignment, boundary, lowaddr, highaddr, filter, filterarg, 259 maxsize, nsegments, maxsegsz, flags, lockfunc, lockfuncarg, 260 sizeof (struct bus_dma_tag), (void **)&newtag); 261 if (error != 0) 262 return (error); 263 264 newtag->common.impl = &bus_dma_bounce_impl; 265 newtag->map_count = 0; 266 newtag->segments = NULL; 267 268 if ((flags & BUS_DMA_COHERENT) != 0) { 269 newtag->bounce_flags |= BF_COHERENT; 270 newtag->alloc_alignment = newtag->common.alignment; 271 newtag->alloc_size = newtag->common.maxsize; 272 } else { 273 /* 274 * Ensure the buffer is aligned to a cacheline when allocating 275 * a non-coherent buffer. This is so we don't have any data 276 * that another CPU may be accessing around DMA buffer 277 * causing the cache to become dirty. 278 */ 279 newtag->alloc_alignment = MAX(newtag->common.alignment, 280 dcache_line_size); 281 newtag->alloc_size = roundup2(newtag->common.maxsize, 282 dcache_line_size); 283 } 284 285 if (parent != NULL) { 286 if ((newtag->common.filter != NULL || 287 (parent->bounce_flags & BF_COULD_BOUNCE) != 0)) 288 newtag->bounce_flags |= BF_COULD_BOUNCE; 289 290 /* Copy some flags from the parent */ 291 newtag->bounce_flags |= parent->bounce_flags & BF_COHERENT; 292 } 293 294 if (newtag->common.lowaddr < ptoa((vm_paddr_t)Maxmem) || 295 newtag->common.alignment > 1) 296 newtag->bounce_flags |= BF_COULD_BOUNCE; 297 298 if ((flags & BUS_DMA_ALLOCNOW) != 0) { 299 struct bounce_zone *bz; 300 /* 301 * Round size up to a full page, and add one more page because 302 * there can always be one more boundary crossing than the 303 * number of pages in a transfer. 304 */ 305 maxsize = roundup2(maxsize, PAGE_SIZE) + PAGE_SIZE; 306 307 /* Must bounce */ 308 if ((error = alloc_bounce_zone(newtag)) != 0) { 309 free(newtag, M_DEVBUF); 310 return (error); 311 } 312 bz = newtag->bounce_zone; 313 314 if (ptoa(bz->total_bpages) < maxsize) { 315 int pages; 316 317 pages = atop(maxsize) + 1 - bz->total_bpages; 318 319 /* Add pages to our bounce pool */ 320 if (alloc_bounce_pages(newtag, pages) < pages) 321 error = ENOMEM; 322 } 323 /* Performed initial allocation */ 324 newtag->bounce_flags |= BF_MIN_ALLOC_COMP; 325 } else 326 error = 0; 327 328 if (error != 0) 329 free(newtag, M_DEVBUF); 330 else 331 *dmat = newtag; 332 CTR4(KTR_BUSDMA, "%s returned tag %p tag flags 0x%x error %d", 333 __func__, newtag, (newtag != NULL ? newtag->common.flags : 0), 334 error); 335 return (error); 336 } 337 338 static int 339 bounce_bus_dma_tag_destroy(bus_dma_tag_t dmat) 340 { 341 #ifdef KTR 342 bus_dma_tag_t dmat_copy; 343 #endif 344 bus_dma_tag_t parent; 345 int error; 346 347 error = 0; 348 #ifdef KTR 349 dmat_copy = dmat; 350 #endif 351 352 353 if (dmat != NULL) { 354 if (dmat->map_count != 0) { 355 error = EBUSY; 356 goto out; 357 } 358 while (dmat != NULL) { 359 parent = (bus_dma_tag_t)dmat->common.parent; 360 atomic_subtract_int(&dmat->common.ref_count, 1); 361 if (dmat->common.ref_count == 0) { 362 if (dmat->segments != NULL) 363 free(dmat->segments, M_DEVBUF); 364 free(dmat, M_DEVBUF); 365 /* 366 * Last reference count, so 367 * release our reference 368 * count on our parent. 369 */ 370 dmat = parent; 371 } else 372 dmat = NULL; 373 } 374 } 375 out: 376 CTR3(KTR_BUSDMA, "%s tag %p error %d", __func__, dmat_copy, error); 377 return (error); 378 } 379 380 static bool 381 bounce_bus_dma_id_mapped(bus_dma_tag_t dmat, vm_paddr_t buf, bus_size_t buflen) 382 { 383 384 if (!might_bounce(dmat, NULL, buf, buflen)) 385 return (true); 386 return (!_bus_dmamap_pagesneeded(dmat, NULL, buf, buflen, NULL)); 387 } 388 389 static bus_dmamap_t 390 alloc_dmamap(bus_dma_tag_t dmat, int flags) 391 { 392 u_long mapsize; 393 bus_dmamap_t map; 394 395 mapsize = sizeof(*map); 396 mapsize += sizeof(struct sync_list) * dmat->common.nsegments; 397 map = malloc(mapsize, M_DEVBUF, flags | M_ZERO); 398 if (map == NULL) 399 return (NULL); 400 401 /* Initialize the new map */ 402 STAILQ_INIT(&map->bpages); 403 404 return (map); 405 } 406 407 /* 408 * Allocate a handle for mapping from kva/uva/physical 409 * address space into bus device space. 410 */ 411 static int 412 bounce_bus_dmamap_create(bus_dma_tag_t dmat, int flags, bus_dmamap_t *mapp) 413 { 414 struct bounce_zone *bz; 415 int error, maxpages, pages; 416 417 error = 0; 418 419 if (dmat->segments == NULL) { 420 dmat->segments = (bus_dma_segment_t *)malloc( 421 sizeof(bus_dma_segment_t) * dmat->common.nsegments, 422 M_DEVBUF, M_NOWAIT); 423 if (dmat->segments == NULL) { 424 CTR3(KTR_BUSDMA, "%s: tag %p error %d", 425 __func__, dmat, ENOMEM); 426 return (ENOMEM); 427 } 428 } 429 430 *mapp = alloc_dmamap(dmat, M_NOWAIT); 431 if (*mapp == NULL) { 432 CTR3(KTR_BUSDMA, "%s: tag %p error %d", 433 __func__, dmat, ENOMEM); 434 return (ENOMEM); 435 } 436 437 /* 438 * Bouncing might be required if the driver asks for an active 439 * exclusion region, a data alignment that is stricter than 1, and/or 440 * an active address boundary. 441 */ 442 if (dmat->bounce_zone == NULL) { 443 if ((error = alloc_bounce_zone(dmat)) != 0) { 444 free(*mapp, M_DEVBUF); 445 return (error); 446 } 447 } 448 bz = dmat->bounce_zone; 449 450 /* 451 * Attempt to add pages to our pool on a per-instance basis up to a sane 452 * limit. Even if the tag isn't subject of bouncing due to alignment 453 * and boundary constraints, it could still auto-bounce due to 454 * cacheline alignment, which requires at most two bounce pages. 455 */ 456 if (dmat->common.alignment > 1) 457 maxpages = MAX_BPAGES; 458 else 459 maxpages = MIN(MAX_BPAGES, Maxmem - 460 atop(dmat->common.lowaddr)); 461 if ((dmat->bounce_flags & BF_MIN_ALLOC_COMP) == 0 || 462 (bz->map_count > 0 && bz->total_bpages < maxpages)) { 463 pages = atop(roundup2(dmat->common.maxsize, PAGE_SIZE)) + 1; 464 pages = MIN(maxpages - bz->total_bpages, pages); 465 pages = MAX(pages, 2); 466 if (alloc_bounce_pages(dmat, pages) < pages) 467 error = ENOMEM; 468 if ((dmat->bounce_flags & BF_MIN_ALLOC_COMP) == 0) { 469 if (error == 0) { 470 dmat->bounce_flags |= BF_MIN_ALLOC_COMP; 471 } 472 } else 473 error = 0; 474 } 475 bz->map_count++; 476 477 if (error == 0) { 478 dmat->map_count++; 479 if ((dmat->bounce_flags & BF_COHERENT) != 0) 480 (*mapp)->flags |= DMAMAP_COHERENT; 481 } else { 482 free(*mapp, M_DEVBUF); 483 } 484 CTR4(KTR_BUSDMA, "%s: tag %p tag flags 0x%x error %d", 485 __func__, dmat, dmat->common.flags, error); 486 return (error); 487 } 488 489 /* 490 * Destroy a handle for mapping from kva/uva/physical 491 * address space into bus device space. 492 */ 493 static int 494 bounce_bus_dmamap_destroy(bus_dma_tag_t dmat, bus_dmamap_t map) 495 { 496 497 /* Check we are destroying the correct map type */ 498 if ((map->flags & DMAMAP_FROM_DMAMEM) != 0) 499 panic("bounce_bus_dmamap_destroy: Invalid map freed\n"); 500 501 if (STAILQ_FIRST(&map->bpages) != NULL || map->sync_count != 0) { 502 CTR3(KTR_BUSDMA, "%s: tag %p error %d", __func__, dmat, EBUSY); 503 return (EBUSY); 504 } 505 if (dmat->bounce_zone) 506 dmat->bounce_zone->map_count--; 507 free(map, M_DEVBUF); 508 dmat->map_count--; 509 CTR2(KTR_BUSDMA, "%s: tag %p error 0", __func__, dmat); 510 return (0); 511 } 512 513 /* 514 * Allocate a piece of memory that can be efficiently mapped into 515 * bus device space based on the constraints lited in the dma tag. 516 * A dmamap to for use with dmamap_load is also allocated. 517 */ 518 static int 519 bounce_bus_dmamem_alloc(bus_dma_tag_t dmat, void** vaddr, int flags, 520 bus_dmamap_t *mapp) 521 { 522 vm_memattr_t attr; 523 int mflags; 524 525 if (flags & BUS_DMA_NOWAIT) 526 mflags = M_NOWAIT; 527 else 528 mflags = M_WAITOK; 529 530 if (dmat->segments == NULL) { 531 dmat->segments = (bus_dma_segment_t *)malloc( 532 sizeof(bus_dma_segment_t) * dmat->common.nsegments, 533 M_DEVBUF, mflags); 534 if (dmat->segments == NULL) { 535 CTR4(KTR_BUSDMA, "%s: tag %p tag flags 0x%x error %d", 536 __func__, dmat, dmat->common.flags, ENOMEM); 537 return (ENOMEM); 538 } 539 } 540 if (flags & BUS_DMA_ZERO) 541 mflags |= M_ZERO; 542 if (flags & BUS_DMA_NOCACHE) 543 attr = VM_MEMATTR_UNCACHEABLE; 544 else if ((flags & BUS_DMA_COHERENT) != 0 && 545 (dmat->bounce_flags & BF_COHERENT) == 0) 546 /* 547 * If we have a non-coherent tag, and are trying to allocate 548 * a coherent block of memory it needs to be uncached. 549 */ 550 attr = VM_MEMATTR_UNCACHEABLE; 551 else 552 attr = VM_MEMATTR_DEFAULT; 553 554 /* 555 * Create the map, but don't set the could bounce flag as 556 * this allocation should never bounce; 557 */ 558 *mapp = alloc_dmamap(dmat, mflags); 559 if (*mapp == NULL) { 560 CTR4(KTR_BUSDMA, "%s: tag %p tag flags 0x%x error %d", 561 __func__, dmat, dmat->common.flags, ENOMEM); 562 return (ENOMEM); 563 } 564 565 /* 566 * Mark the map as coherent if we used uncacheable memory or the 567 * tag was already marked as coherent. 568 */ 569 if (attr == VM_MEMATTR_UNCACHEABLE || 570 (dmat->bounce_flags & BF_COHERENT) != 0) 571 (*mapp)->flags |= DMAMAP_COHERENT; 572 573 (*mapp)->flags |= DMAMAP_FROM_DMAMEM; 574 575 /* 576 * Allocate the buffer from the malloc(9) allocator if... 577 * - It's small enough to fit into a single power of two sized bucket. 578 * - The alignment is less than or equal to the maximum size 579 * - The low address requirement is fulfilled. 580 * else allocate non-contiguous pages if... 581 * - The page count that could get allocated doesn't exceed 582 * nsegments also when the maximum segment size is less 583 * than PAGE_SIZE. 584 * - The alignment constraint isn't larger than a page boundary. 585 * - There are no boundary-crossing constraints. 586 * else allocate a block of contiguous pages because one or more of the 587 * constraints is something that only the contig allocator can fulfill. 588 * 589 * NOTE: The (dmat->common.alignment <= dmat->maxsize) check 590 * below is just a quick hack. The exact alignment guarantees 591 * of malloc(9) need to be nailed down, and the code below 592 * should be rewritten to take that into account. 593 * 594 * In the meantime warn the user if malloc gets it wrong. 595 */ 596 if ((dmat->alloc_size <= PAGE_SIZE) && 597 (dmat->alloc_alignment <= dmat->alloc_size) && 598 dmat->common.lowaddr >= ptoa((vm_paddr_t)Maxmem) && 599 attr == VM_MEMATTR_DEFAULT) { 600 *vaddr = malloc(dmat->alloc_size, M_DEVBUF, mflags); 601 } else if (dmat->common.nsegments >= 602 howmany(dmat->alloc_size, MIN(dmat->common.maxsegsz, PAGE_SIZE)) && 603 dmat->alloc_alignment <= PAGE_SIZE && 604 (dmat->common.boundary % PAGE_SIZE) == 0) { 605 /* Page-based multi-segment allocations allowed */ 606 *vaddr = (void *)kmem_alloc_attr(dmat->alloc_size, mflags, 607 0ul, dmat->common.lowaddr, attr); 608 dmat->bounce_flags |= BF_KMEM_ALLOC; 609 } else { 610 *vaddr = (void *)kmem_alloc_contig(dmat->alloc_size, mflags, 611 0ul, dmat->common.lowaddr, dmat->alloc_alignment != 0 ? 612 dmat->alloc_alignment : 1ul, dmat->common.boundary, attr); 613 dmat->bounce_flags |= BF_KMEM_ALLOC; 614 } 615 if (*vaddr == NULL) { 616 CTR4(KTR_BUSDMA, "%s: tag %p tag flags 0x%x error %d", 617 __func__, dmat, dmat->common.flags, ENOMEM); 618 free(*mapp, M_DEVBUF); 619 return (ENOMEM); 620 } else if (vtophys(*vaddr) & (dmat->alloc_alignment - 1)) { 621 printf("bus_dmamem_alloc failed to align memory properly.\n"); 622 } 623 dmat->map_count++; 624 CTR4(KTR_BUSDMA, "%s: tag %p tag flags 0x%x error %d", 625 __func__, dmat, dmat->common.flags, 0); 626 return (0); 627 } 628 629 /* 630 * Free a piece of memory and it's allociated dmamap, that was allocated 631 * via bus_dmamem_alloc. Make the same choice for free/contigfree. 632 */ 633 static void 634 bounce_bus_dmamem_free(bus_dma_tag_t dmat, void *vaddr, bus_dmamap_t map) 635 { 636 637 /* 638 * Check the map came from bounce_bus_dmamem_alloc, so the map 639 * should be NULL and the BF_KMEM_ALLOC flag cleared if malloc() 640 * was used and set if kmem_alloc_contig() was used. 641 */ 642 if ((map->flags & DMAMAP_FROM_DMAMEM) == 0) 643 panic("bus_dmamem_free: Invalid map freed\n"); 644 if ((dmat->bounce_flags & BF_KMEM_ALLOC) == 0) 645 free(vaddr, M_DEVBUF); 646 else 647 kmem_free((vm_offset_t)vaddr, dmat->alloc_size); 648 free(map, M_DEVBUF); 649 dmat->map_count--; 650 CTR3(KTR_BUSDMA, "%s: tag %p flags 0x%x", __func__, dmat, 651 dmat->bounce_flags); 652 } 653 654 static bool 655 _bus_dmamap_pagesneeded(bus_dma_tag_t dmat, bus_dmamap_t map, vm_paddr_t buf, 656 bus_size_t buflen, int *pagesneeded) 657 { 658 bus_addr_t curaddr; 659 bus_size_t sgsize; 660 int count; 661 662 /* 663 * Count the number of bounce pages needed in order to 664 * complete this transfer 665 */ 666 count = 0; 667 curaddr = buf; 668 while (buflen != 0) { 669 sgsize = MIN(buflen, dmat->common.maxsegsz); 670 if (must_bounce(dmat, map, curaddr, sgsize)) { 671 sgsize = MIN(sgsize, 672 PAGE_SIZE - (curaddr & PAGE_MASK)); 673 if (pagesneeded == NULL) 674 return (true); 675 count++; 676 } 677 curaddr += sgsize; 678 buflen -= sgsize; 679 } 680 681 if (pagesneeded != NULL) 682 *pagesneeded = count; 683 return (count != 0); 684 } 685 686 static void 687 _bus_dmamap_count_phys(bus_dma_tag_t dmat, bus_dmamap_t map, vm_paddr_t buf, 688 bus_size_t buflen, int flags) 689 { 690 691 if (map->pagesneeded == 0) { 692 _bus_dmamap_pagesneeded(dmat, map, buf, buflen, 693 &map->pagesneeded); 694 CTR1(KTR_BUSDMA, "pagesneeded= %d\n", map->pagesneeded); 695 } 696 } 697 698 static void 699 _bus_dmamap_count_pages(bus_dma_tag_t dmat, bus_dmamap_t map, pmap_t pmap, 700 void *buf, bus_size_t buflen, int flags) 701 { 702 vm_offset_t vaddr; 703 vm_offset_t vendaddr; 704 bus_addr_t paddr; 705 bus_size_t sg_len; 706 707 if (map->pagesneeded == 0) { 708 CTR4(KTR_BUSDMA, "lowaddr= %d Maxmem= %d, boundary= %d, " 709 "alignment= %d", dmat->common.lowaddr, 710 ptoa((vm_paddr_t)Maxmem), 711 dmat->common.boundary, dmat->common.alignment); 712 CTR2(KTR_BUSDMA, "map= %p, pagesneeded= %d", map, 713 map->pagesneeded); 714 /* 715 * Count the number of bounce pages 716 * needed in order to complete this transfer 717 */ 718 vaddr = (vm_offset_t)buf; 719 vendaddr = (vm_offset_t)buf + buflen; 720 721 while (vaddr < vendaddr) { 722 sg_len = PAGE_SIZE - ((vm_offset_t)vaddr & PAGE_MASK); 723 if (pmap == kernel_pmap) 724 paddr = pmap_kextract(vaddr); 725 else 726 paddr = pmap_extract(pmap, vaddr); 727 if (must_bounce(dmat, map, paddr, 728 min(vendaddr - vaddr, (PAGE_SIZE - ((vm_offset_t)vaddr & 729 PAGE_MASK)))) != 0) { 730 sg_len = roundup2(sg_len, 731 dmat->common.alignment); 732 map->pagesneeded++; 733 } 734 vaddr += sg_len; 735 } 736 CTR1(KTR_BUSDMA, "pagesneeded= %d\n", map->pagesneeded); 737 } 738 } 739 740 static int 741 _bus_dmamap_reserve_pages(bus_dma_tag_t dmat, bus_dmamap_t map, int flags) 742 { 743 744 /* Reserve Necessary Bounce Pages */ 745 mtx_lock(&bounce_lock); 746 if (flags & BUS_DMA_NOWAIT) { 747 if (reserve_bounce_pages(dmat, map, 0) != 0) { 748 mtx_unlock(&bounce_lock); 749 return (ENOMEM); 750 } 751 } else { 752 if (reserve_bounce_pages(dmat, map, 1) != 0) { 753 /* Queue us for resources */ 754 STAILQ_INSERT_TAIL(&bounce_map_waitinglist, map, links); 755 mtx_unlock(&bounce_lock); 756 return (EINPROGRESS); 757 } 758 } 759 mtx_unlock(&bounce_lock); 760 761 return (0); 762 } 763 764 /* 765 * Add a single contiguous physical range to the segment list. 766 */ 767 static bus_size_t 768 _bus_dmamap_addseg(bus_dma_tag_t dmat, bus_dmamap_t map, bus_addr_t curaddr, 769 bus_size_t sgsize, bus_dma_segment_t *segs, int *segp) 770 { 771 bus_addr_t baddr, bmask; 772 int seg; 773 774 /* 775 * Make sure we don't cross any boundaries. 776 */ 777 bmask = ~(dmat->common.boundary - 1); 778 if (dmat->common.boundary > 0) { 779 baddr = (curaddr + dmat->common.boundary) & bmask; 780 if (sgsize > (baddr - curaddr)) 781 sgsize = (baddr - curaddr); 782 } 783 784 /* 785 * Insert chunk into a segment, coalescing with 786 * previous segment if possible. 787 */ 788 seg = *segp; 789 if (seg == -1) { 790 seg = 0; 791 segs[seg].ds_addr = curaddr; 792 segs[seg].ds_len = sgsize; 793 } else { 794 if (curaddr == segs[seg].ds_addr + segs[seg].ds_len && 795 (segs[seg].ds_len + sgsize) <= dmat->common.maxsegsz && 796 (dmat->common.boundary == 0 || 797 (segs[seg].ds_addr & bmask) == (curaddr & bmask))) 798 segs[seg].ds_len += sgsize; 799 else { 800 if (++seg >= dmat->common.nsegments) 801 return (0); 802 segs[seg].ds_addr = curaddr; 803 segs[seg].ds_len = sgsize; 804 } 805 } 806 *segp = seg; 807 return (sgsize); 808 } 809 810 /* 811 * Utility function to load a physical buffer. segp contains 812 * the starting segment on entrace, and the ending segment on exit. 813 */ 814 static int 815 bounce_bus_dmamap_load_phys(bus_dma_tag_t dmat, bus_dmamap_t map, 816 vm_paddr_t buf, bus_size_t buflen, int flags, bus_dma_segment_t *segs, 817 int *segp) 818 { 819 struct sync_list *sl; 820 bus_size_t sgsize; 821 bus_addr_t curaddr, sl_end; 822 int error; 823 824 if (segs == NULL) 825 segs = dmat->segments; 826 827 if (might_bounce(dmat, map, (bus_addr_t)buf, buflen)) { 828 _bus_dmamap_count_phys(dmat, map, buf, buflen, flags); 829 if (map->pagesneeded != 0) { 830 error = _bus_dmamap_reserve_pages(dmat, map, flags); 831 if (error) 832 return (error); 833 } 834 } 835 836 sl = map->slist + map->sync_count - 1; 837 sl_end = 0; 838 839 while (buflen > 0) { 840 curaddr = buf; 841 sgsize = MIN(buflen, dmat->common.maxsegsz); 842 if (map->pagesneeded != 0 && 843 must_bounce(dmat, map, curaddr, sgsize)) { 844 /* 845 * The attempt to split a physically continuous buffer 846 * seems very controversial, it's unclear whether we 847 * can do this in all cases. Also, memory for bounced 848 * buffers is allocated as pages, so we cannot 849 * guarantee multipage alignment. 850 */ 851 KASSERT(dmat->common.alignment <= PAGE_SIZE, 852 ("bounced buffer cannot have alignment bigger " 853 "than PAGE_SIZE: %lu", dmat->common.alignment)); 854 sgsize = MIN(sgsize, PAGE_SIZE - (curaddr & PAGE_MASK)); 855 curaddr = add_bounce_page(dmat, map, 0, curaddr, 856 sgsize); 857 } else if ((map->flags & DMAMAP_COHERENT) == 0) { 858 if (map->sync_count > 0) 859 sl_end = sl->paddr + sl->datacount; 860 861 if (map->sync_count == 0 || curaddr != sl_end) { 862 if (++map->sync_count > dmat->common.nsegments) 863 break; 864 sl++; 865 sl->vaddr = 0; 866 sl->paddr = curaddr; 867 sl->pages = PHYS_TO_VM_PAGE(curaddr); 868 KASSERT(sl->pages != NULL, 869 ("%s: page at PA:0x%08lx is not in " 870 "vm_page_array", __func__, curaddr)); 871 sl->datacount = sgsize; 872 } else 873 sl->datacount += sgsize; 874 } 875 sgsize = _bus_dmamap_addseg(dmat, map, curaddr, sgsize, segs, 876 segp); 877 if (sgsize == 0) 878 break; 879 buf += sgsize; 880 buflen -= sgsize; 881 } 882 883 /* 884 * Did we fit? 885 */ 886 if (buflen != 0) { 887 bus_dmamap_unload(dmat, map); 888 return (EFBIG); /* XXX better return value here? */ 889 } 890 return (0); 891 } 892 893 /* 894 * Utility function to load a linear buffer. segp contains 895 * the starting segment on entrace, and the ending segment on exit. 896 */ 897 static int 898 bounce_bus_dmamap_load_buffer(bus_dma_tag_t dmat, bus_dmamap_t map, void *buf, 899 bus_size_t buflen, pmap_t pmap, int flags, bus_dma_segment_t *segs, 900 int *segp) 901 { 902 struct sync_list *sl; 903 bus_size_t sgsize; 904 bus_addr_t curaddr, sl_pend; 905 vm_offset_t kvaddr, vaddr, sl_vend; 906 int error; 907 908 KASSERT((map->flags & DMAMAP_FROM_DMAMEM) != 0 || 909 dmat->common.alignment <= PAGE_SIZE, 910 ("loading user buffer with alignment bigger than PAGE_SIZE is not " 911 "supported")); 912 913 if (segs == NULL) 914 segs = dmat->segments; 915 916 if (flags & BUS_DMA_LOAD_MBUF) 917 map->flags |= DMAMAP_MBUF; 918 919 if (might_bounce(dmat, map, (bus_addr_t)buf, buflen)) { 920 _bus_dmamap_count_pages(dmat, map, pmap, buf, buflen, flags); 921 if (map->pagesneeded != 0) { 922 error = _bus_dmamap_reserve_pages(dmat, map, flags); 923 if (error) 924 return (error); 925 } 926 } 927 928 /* 929 * XXX Optimally we should parse input buffer for physically 930 * continuous segments first and then pass these segment into 931 * load loop. 932 */ 933 sl = map->slist + map->sync_count - 1; 934 vaddr = (vm_offset_t)buf; 935 sl_pend = 0; 936 sl_vend = 0; 937 938 while (buflen > 0) { 939 /* 940 * Get the physical address for this segment. 941 */ 942 if (__predict_true(pmap == kernel_pmap)) { 943 curaddr = pmap_kextract(vaddr); 944 kvaddr = vaddr; 945 } else { 946 curaddr = pmap_extract(pmap, vaddr); 947 kvaddr = 0; 948 } 949 950 /* 951 * Compute the segment size, and adjust counts. 952 */ 953 sgsize = MIN(buflen, dmat->common.maxsegsz); 954 if ((map->flags & DMAMAP_FROM_DMAMEM) == 0) 955 sgsize = MIN(sgsize, PAGE_SIZE - (curaddr & PAGE_MASK)); 956 957 if (map->pagesneeded != 0 && 958 must_bounce(dmat, map, curaddr, sgsize)) { 959 /* See comment in bounce_bus_dmamap_load_phys */ 960 KASSERT(dmat->common.alignment <= PAGE_SIZE, 961 ("bounced buffer cannot have alignment bigger " 962 "than PAGE_SIZE: %lu", dmat->common.alignment)); 963 curaddr = add_bounce_page(dmat, map, kvaddr, curaddr, 964 sgsize); 965 } else if ((map->flags & DMAMAP_COHERENT) == 0) { 966 if (map->sync_count > 0) { 967 sl_pend = sl->paddr + sl->datacount; 968 sl_vend = sl->vaddr + sl->datacount; 969 } 970 971 if (map->sync_count == 0 || 972 (kvaddr != 0 && kvaddr != sl_vend) || 973 (curaddr != sl_pend)) { 974 if (++map->sync_count > dmat->common.nsegments) 975 break; 976 sl++; 977 sl->vaddr = kvaddr; 978 sl->paddr = curaddr; 979 if (kvaddr != 0) { 980 sl->pages = NULL; 981 } else { 982 sl->pages = PHYS_TO_VM_PAGE(curaddr); 983 KASSERT(sl->pages != NULL, 984 ("%s: page at PA:0x%08lx is not " 985 "in vm_page_array", __func__, 986 curaddr)); 987 } 988 sl->datacount = sgsize; 989 } else 990 sl->datacount += sgsize; 991 } 992 sgsize = _bus_dmamap_addseg(dmat, map, curaddr, sgsize, segs, 993 segp); 994 if (sgsize == 0) 995 break; 996 vaddr += sgsize; 997 buflen -= sgsize; 998 } 999 1000 /* 1001 * Did we fit? 1002 */ 1003 if (buflen != 0) { 1004 bus_dmamap_unload(dmat, map); 1005 return (EFBIG); /* XXX better return value here? */ 1006 } 1007 return (0); 1008 } 1009 1010 static void 1011 bounce_bus_dmamap_waitok(bus_dma_tag_t dmat, bus_dmamap_t map, 1012 struct memdesc *mem, bus_dmamap_callback_t *callback, void *callback_arg) 1013 { 1014 1015 map->mem = *mem; 1016 map->dmat = dmat; 1017 map->callback = callback; 1018 map->callback_arg = callback_arg; 1019 } 1020 1021 static bus_dma_segment_t * 1022 bounce_bus_dmamap_complete(bus_dma_tag_t dmat, bus_dmamap_t map, 1023 bus_dma_segment_t *segs, int nsegs, int error) 1024 { 1025 1026 if (segs == NULL) 1027 segs = dmat->segments; 1028 return (segs); 1029 } 1030 1031 /* 1032 * Release the mapping held by map. 1033 */ 1034 static void 1035 bounce_bus_dmamap_unload(bus_dma_tag_t dmat, bus_dmamap_t map) 1036 { 1037 struct bounce_page *bpage; 1038 1039 while ((bpage = STAILQ_FIRST(&map->bpages)) != NULL) { 1040 STAILQ_REMOVE_HEAD(&map->bpages, links); 1041 free_bounce_page(dmat, bpage); 1042 } 1043 1044 map->sync_count = 0; 1045 map->flags &= ~DMAMAP_MBUF; 1046 } 1047 1048 static void 1049 dma_preread_safe(vm_offset_t va, vm_size_t size) 1050 { 1051 /* 1052 * Write back any partial cachelines immediately before and 1053 * after the DMA region. 1054 */ 1055 if (va & (dcache_line_size - 1)) 1056 cpu_dcache_wb_range(va, 1); 1057 if ((va + size) & (dcache_line_size - 1)) 1058 cpu_dcache_wb_range(va + size, 1); 1059 1060 cpu_dcache_inv_range(va, size); 1061 } 1062 1063 static void 1064 dma_dcache_sync(struct sync_list *sl, bus_dmasync_op_t op) 1065 { 1066 uint32_t len, offset; 1067 vm_page_t m; 1068 vm_paddr_t pa; 1069 vm_offset_t va, tempva; 1070 bus_size_t size; 1071 1072 offset = sl->paddr & PAGE_MASK; 1073 m = sl->pages; 1074 size = sl->datacount; 1075 pa = sl->paddr; 1076 1077 for ( ; size != 0; size -= len, pa += len, offset = 0, ++m) { 1078 tempva = 0; 1079 if (sl->vaddr == 0) { 1080 len = min(PAGE_SIZE - offset, size); 1081 tempva = pmap_quick_enter_page(m); 1082 va = tempva | offset; 1083 KASSERT(pa == (VM_PAGE_TO_PHYS(m) | offset), 1084 ("unexpected vm_page_t phys: 0x%16lx != 0x%16lx", 1085 VM_PAGE_TO_PHYS(m) | offset, pa)); 1086 } else { 1087 len = sl->datacount; 1088 va = sl->vaddr; 1089 } 1090 1091 switch (op) { 1092 case BUS_DMASYNC_PREWRITE: 1093 case BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD: 1094 cpu_dcache_wb_range(va, len); 1095 break; 1096 case BUS_DMASYNC_PREREAD: 1097 /* 1098 * An mbuf may start in the middle of a cacheline. There 1099 * will be no cpu writes to the beginning of that line 1100 * (which contains the mbuf header) while dma is in 1101 * progress. Handle that case by doing a writeback of 1102 * just the first cacheline before invalidating the 1103 * overall buffer. Any mbuf in a chain may have this 1104 * misalignment. Buffers which are not mbufs bounce if 1105 * they are not aligned to a cacheline. 1106 */ 1107 dma_preread_safe(va, len); 1108 break; 1109 case BUS_DMASYNC_POSTREAD: 1110 case BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE: 1111 cpu_dcache_inv_range(va, len); 1112 break; 1113 default: 1114 panic("unsupported combination of sync operations: " 1115 "0x%08x\n", op); 1116 } 1117 1118 if (tempva != 0) 1119 pmap_quick_remove_page(tempva); 1120 } 1121 } 1122 1123 static void 1124 bounce_bus_dmamap_sync(bus_dma_tag_t dmat, bus_dmamap_t map, 1125 bus_dmasync_op_t op) 1126 { 1127 struct bounce_page *bpage; 1128 struct sync_list *sl, *end; 1129 vm_offset_t datavaddr, tempvaddr; 1130 1131 if (op == BUS_DMASYNC_POSTWRITE) 1132 return; 1133 1134 if ((op & BUS_DMASYNC_POSTREAD) != 0) { 1135 /* 1136 * Wait for any DMA operations to complete before the bcopy. 1137 */ 1138 dsb(sy); 1139 } 1140 1141 if ((bpage = STAILQ_FIRST(&map->bpages)) != NULL) { 1142 CTR4(KTR_BUSDMA, "%s: tag %p tag flags 0x%x op 0x%x " 1143 "performing bounce", __func__, dmat, dmat->common.flags, 1144 op); 1145 1146 if ((op & BUS_DMASYNC_PREWRITE) != 0) { 1147 while (bpage != NULL) { 1148 tempvaddr = 0; 1149 datavaddr = bpage->datavaddr; 1150 if (datavaddr == 0) { 1151 tempvaddr = pmap_quick_enter_page( 1152 bpage->datapage); 1153 datavaddr = tempvaddr | bpage->dataoffs; 1154 } 1155 1156 bcopy((void *)datavaddr, 1157 (void *)bpage->vaddr, bpage->datacount); 1158 if (tempvaddr != 0) 1159 pmap_quick_remove_page(tempvaddr); 1160 if ((map->flags & DMAMAP_COHERENT) == 0) 1161 cpu_dcache_wb_range(bpage->vaddr, 1162 bpage->datacount); 1163 bpage = STAILQ_NEXT(bpage, links); 1164 } 1165 dmat->bounce_zone->total_bounced++; 1166 } else if ((op & BUS_DMASYNC_PREREAD) != 0) { 1167 while (bpage != NULL) { 1168 if ((map->flags & DMAMAP_COHERENT) == 0) 1169 cpu_dcache_wbinv_range(bpage->vaddr, 1170 bpage->datacount); 1171 bpage = STAILQ_NEXT(bpage, links); 1172 } 1173 } 1174 1175 if ((op & BUS_DMASYNC_POSTREAD) != 0) { 1176 while (bpage != NULL) { 1177 if ((map->flags & DMAMAP_COHERENT) == 0) 1178 cpu_dcache_inv_range(bpage->vaddr, 1179 bpage->datacount); 1180 tempvaddr = 0; 1181 datavaddr = bpage->datavaddr; 1182 if (datavaddr == 0) { 1183 tempvaddr = pmap_quick_enter_page( 1184 bpage->datapage); 1185 datavaddr = tempvaddr | bpage->dataoffs; 1186 } 1187 1188 bcopy((void *)bpage->vaddr, 1189 (void *)datavaddr, bpage->datacount); 1190 1191 if (tempvaddr != 0) 1192 pmap_quick_remove_page(tempvaddr); 1193 bpage = STAILQ_NEXT(bpage, links); 1194 } 1195 dmat->bounce_zone->total_bounced++; 1196 } 1197 } 1198 1199 /* 1200 * Cache maintenance for normal (non-COHERENT non-bounce) buffers. 1201 */ 1202 if (map->sync_count != 0) { 1203 sl = &map->slist[0]; 1204 end = &map->slist[map->sync_count]; 1205 CTR3(KTR_BUSDMA, "%s: tag %p op 0x%x " 1206 "performing sync", __func__, dmat, op); 1207 1208 for ( ; sl != end; ++sl) 1209 dma_dcache_sync(sl, op); 1210 } 1211 1212 if ((op & (BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE)) != 0) { 1213 /* 1214 * Wait for the bcopy to complete before any DMA operations. 1215 */ 1216 dsb(sy); 1217 } 1218 } 1219 1220 static void 1221 init_bounce_pages(void *dummy __unused) 1222 { 1223 1224 total_bpages = 0; 1225 STAILQ_INIT(&bounce_zone_list); 1226 STAILQ_INIT(&bounce_map_waitinglist); 1227 STAILQ_INIT(&bounce_map_callbacklist); 1228 mtx_init(&bounce_lock, "bounce pages lock", NULL, MTX_DEF); 1229 } 1230 SYSINIT(bpages, SI_SUB_LOCK, SI_ORDER_ANY, init_bounce_pages, NULL); 1231 1232 static struct sysctl_ctx_list * 1233 busdma_sysctl_tree(struct bounce_zone *bz) 1234 { 1235 1236 return (&bz->sysctl_tree); 1237 } 1238 1239 static struct sysctl_oid * 1240 busdma_sysctl_tree_top(struct bounce_zone *bz) 1241 { 1242 1243 return (bz->sysctl_tree_top); 1244 } 1245 1246 static int 1247 alloc_bounce_zone(bus_dma_tag_t dmat) 1248 { 1249 struct bounce_zone *bz; 1250 1251 /* Check to see if we already have a suitable zone */ 1252 STAILQ_FOREACH(bz, &bounce_zone_list, links) { 1253 if ((dmat->common.alignment <= bz->alignment) && 1254 (dmat->common.lowaddr >= bz->lowaddr)) { 1255 dmat->bounce_zone = bz; 1256 return (0); 1257 } 1258 } 1259 1260 if ((bz = (struct bounce_zone *)malloc(sizeof(*bz), M_DEVBUF, 1261 M_NOWAIT | M_ZERO)) == NULL) 1262 return (ENOMEM); 1263 1264 STAILQ_INIT(&bz->bounce_page_list); 1265 bz->free_bpages = 0; 1266 bz->reserved_bpages = 0; 1267 bz->active_bpages = 0; 1268 bz->lowaddr = dmat->common.lowaddr; 1269 bz->alignment = MAX(dmat->common.alignment, PAGE_SIZE); 1270 bz->map_count = 0; 1271 snprintf(bz->zoneid, 8, "zone%d", busdma_zonecount); 1272 busdma_zonecount++; 1273 snprintf(bz->lowaddrid, 18, "%#jx", (uintmax_t)bz->lowaddr); 1274 STAILQ_INSERT_TAIL(&bounce_zone_list, bz, links); 1275 dmat->bounce_zone = bz; 1276 1277 sysctl_ctx_init(&bz->sysctl_tree); 1278 bz->sysctl_tree_top = SYSCTL_ADD_NODE(&bz->sysctl_tree, 1279 SYSCTL_STATIC_CHILDREN(_hw_busdma), OID_AUTO, bz->zoneid, 1280 CTLFLAG_RD | CTLFLAG_MPSAFE, 0, ""); 1281 if (bz->sysctl_tree_top == NULL) { 1282 sysctl_ctx_free(&bz->sysctl_tree); 1283 return (0); /* XXX error code? */ 1284 } 1285 1286 SYSCTL_ADD_INT(busdma_sysctl_tree(bz), 1287 SYSCTL_CHILDREN(busdma_sysctl_tree_top(bz)), OID_AUTO, 1288 "total_bpages", CTLFLAG_RD, &bz->total_bpages, 0, 1289 "Total bounce pages"); 1290 SYSCTL_ADD_INT(busdma_sysctl_tree(bz), 1291 SYSCTL_CHILDREN(busdma_sysctl_tree_top(bz)), OID_AUTO, 1292 "free_bpages", CTLFLAG_RD, &bz->free_bpages, 0, 1293 "Free bounce pages"); 1294 SYSCTL_ADD_INT(busdma_sysctl_tree(bz), 1295 SYSCTL_CHILDREN(busdma_sysctl_tree_top(bz)), OID_AUTO, 1296 "reserved_bpages", CTLFLAG_RD, &bz->reserved_bpages, 0, 1297 "Reserved bounce pages"); 1298 SYSCTL_ADD_INT(busdma_sysctl_tree(bz), 1299 SYSCTL_CHILDREN(busdma_sysctl_tree_top(bz)), OID_AUTO, 1300 "active_bpages", CTLFLAG_RD, &bz->active_bpages, 0, 1301 "Active bounce pages"); 1302 SYSCTL_ADD_INT(busdma_sysctl_tree(bz), 1303 SYSCTL_CHILDREN(busdma_sysctl_tree_top(bz)), OID_AUTO, 1304 "total_bounced", CTLFLAG_RD, &bz->total_bounced, 0, 1305 "Total bounce requests"); 1306 SYSCTL_ADD_INT(busdma_sysctl_tree(bz), 1307 SYSCTL_CHILDREN(busdma_sysctl_tree_top(bz)), OID_AUTO, 1308 "total_deferred", CTLFLAG_RD, &bz->total_deferred, 0, 1309 "Total bounce requests that were deferred"); 1310 SYSCTL_ADD_STRING(busdma_sysctl_tree(bz), 1311 SYSCTL_CHILDREN(busdma_sysctl_tree_top(bz)), OID_AUTO, 1312 "lowaddr", CTLFLAG_RD, bz->lowaddrid, 0, ""); 1313 SYSCTL_ADD_UAUTO(busdma_sysctl_tree(bz), 1314 SYSCTL_CHILDREN(busdma_sysctl_tree_top(bz)), OID_AUTO, 1315 "alignment", CTLFLAG_RD, &bz->alignment, ""); 1316 1317 return (0); 1318 } 1319 1320 static int 1321 alloc_bounce_pages(bus_dma_tag_t dmat, u_int numpages) 1322 { 1323 struct bounce_zone *bz; 1324 int count; 1325 1326 bz = dmat->bounce_zone; 1327 count = 0; 1328 while (numpages > 0) { 1329 struct bounce_page *bpage; 1330 1331 bpage = (struct bounce_page *)malloc(sizeof(*bpage), M_DEVBUF, 1332 M_NOWAIT | M_ZERO); 1333 1334 if (bpage == NULL) 1335 break; 1336 bpage->vaddr = (vm_offset_t)contigmalloc(PAGE_SIZE, M_DEVBUF, 1337 M_NOWAIT, 0ul, bz->lowaddr, PAGE_SIZE, 0); 1338 if (bpage->vaddr == 0) { 1339 free(bpage, M_DEVBUF); 1340 break; 1341 } 1342 bpage->busaddr = pmap_kextract(bpage->vaddr); 1343 mtx_lock(&bounce_lock); 1344 STAILQ_INSERT_TAIL(&bz->bounce_page_list, bpage, links); 1345 total_bpages++; 1346 bz->total_bpages++; 1347 bz->free_bpages++; 1348 mtx_unlock(&bounce_lock); 1349 count++; 1350 numpages--; 1351 } 1352 return (count); 1353 } 1354 1355 static int 1356 reserve_bounce_pages(bus_dma_tag_t dmat, bus_dmamap_t map, int commit) 1357 { 1358 struct bounce_zone *bz; 1359 int pages; 1360 1361 mtx_assert(&bounce_lock, MA_OWNED); 1362 bz = dmat->bounce_zone; 1363 pages = MIN(bz->free_bpages, map->pagesneeded - map->pagesreserved); 1364 if (commit == 0 && map->pagesneeded > (map->pagesreserved + pages)) 1365 return (map->pagesneeded - (map->pagesreserved + pages)); 1366 bz->free_bpages -= pages; 1367 bz->reserved_bpages += pages; 1368 map->pagesreserved += pages; 1369 pages = map->pagesneeded - map->pagesreserved; 1370 1371 return (pages); 1372 } 1373 1374 static bus_addr_t 1375 add_bounce_page(bus_dma_tag_t dmat, bus_dmamap_t map, vm_offset_t vaddr, 1376 bus_addr_t addr, bus_size_t size) 1377 { 1378 struct bounce_zone *bz; 1379 struct bounce_page *bpage; 1380 1381 KASSERT(dmat->bounce_zone != NULL, ("no bounce zone in dma tag")); 1382 1383 bz = dmat->bounce_zone; 1384 if (map->pagesneeded == 0) 1385 panic("add_bounce_page: map doesn't need any pages"); 1386 map->pagesneeded--; 1387 1388 if (map->pagesreserved == 0) 1389 panic("add_bounce_page: map doesn't need any pages"); 1390 map->pagesreserved--; 1391 1392 mtx_lock(&bounce_lock); 1393 bpage = STAILQ_FIRST(&bz->bounce_page_list); 1394 if (bpage == NULL) 1395 panic("add_bounce_page: free page list is empty"); 1396 1397 STAILQ_REMOVE_HEAD(&bz->bounce_page_list, links); 1398 bz->reserved_bpages--; 1399 bz->active_bpages++; 1400 mtx_unlock(&bounce_lock); 1401 1402 if (dmat->common.flags & BUS_DMA_KEEP_PG_OFFSET) { 1403 /* Page offset needs to be preserved. */ 1404 bpage->vaddr |= addr & PAGE_MASK; 1405 bpage->busaddr |= addr & PAGE_MASK; 1406 } 1407 bpage->datavaddr = vaddr; 1408 bpage->datapage = PHYS_TO_VM_PAGE(addr); 1409 bpage->dataoffs = addr & PAGE_MASK; 1410 bpage->datacount = size; 1411 STAILQ_INSERT_TAIL(&(map->bpages), bpage, links); 1412 return (bpage->busaddr); 1413 } 1414 1415 static void 1416 free_bounce_page(bus_dma_tag_t dmat, struct bounce_page *bpage) 1417 { 1418 struct bus_dmamap *map; 1419 struct bounce_zone *bz; 1420 1421 bz = dmat->bounce_zone; 1422 bpage->datavaddr = 0; 1423 bpage->datacount = 0; 1424 if (dmat->common.flags & BUS_DMA_KEEP_PG_OFFSET) { 1425 /* 1426 * Reset the bounce page to start at offset 0. Other uses 1427 * of this bounce page may need to store a full page of 1428 * data and/or assume it starts on a page boundary. 1429 */ 1430 bpage->vaddr &= ~PAGE_MASK; 1431 bpage->busaddr &= ~PAGE_MASK; 1432 } 1433 1434 mtx_lock(&bounce_lock); 1435 STAILQ_INSERT_HEAD(&bz->bounce_page_list, bpage, links); 1436 bz->free_bpages++; 1437 bz->active_bpages--; 1438 if ((map = STAILQ_FIRST(&bounce_map_waitinglist)) != NULL) { 1439 if (reserve_bounce_pages(map->dmat, map, 1) == 0) { 1440 STAILQ_REMOVE_HEAD(&bounce_map_waitinglist, links); 1441 STAILQ_INSERT_TAIL(&bounce_map_callbacklist, 1442 map, links); 1443 busdma_swi_pending = 1; 1444 bz->total_deferred++; 1445 swi_sched(vm_ih, 0); 1446 } 1447 } 1448 mtx_unlock(&bounce_lock); 1449 } 1450 1451 void 1452 busdma_swi(void) 1453 { 1454 bus_dma_tag_t dmat; 1455 struct bus_dmamap *map; 1456 1457 mtx_lock(&bounce_lock); 1458 while ((map = STAILQ_FIRST(&bounce_map_callbacklist)) != NULL) { 1459 STAILQ_REMOVE_HEAD(&bounce_map_callbacklist, links); 1460 mtx_unlock(&bounce_lock); 1461 dmat = map->dmat; 1462 (dmat->common.lockfunc)(dmat->common.lockfuncarg, BUS_DMA_LOCK); 1463 bus_dmamap_load_mem(map->dmat, map, &map->mem, 1464 map->callback, map->callback_arg, BUS_DMA_WAITOK); 1465 (dmat->common.lockfunc)(dmat->common.lockfuncarg, 1466 BUS_DMA_UNLOCK); 1467 mtx_lock(&bounce_lock); 1468 } 1469 mtx_unlock(&bounce_lock); 1470 } 1471 1472 struct bus_dma_impl bus_dma_bounce_impl = { 1473 .tag_create = bounce_bus_dma_tag_create, 1474 .tag_destroy = bounce_bus_dma_tag_destroy, 1475 .id_mapped = bounce_bus_dma_id_mapped, 1476 .map_create = bounce_bus_dmamap_create, 1477 .map_destroy = bounce_bus_dmamap_destroy, 1478 .mem_alloc = bounce_bus_dmamem_alloc, 1479 .mem_free = bounce_bus_dmamem_free, 1480 .load_phys = bounce_bus_dmamap_load_phys, 1481 .load_buffer = bounce_bus_dmamap_load_buffer, 1482 .load_ma = bus_dmamap_load_ma_triv, 1483 .map_waitok = bounce_bus_dmamap_waitok, 1484 .map_complete = bounce_bus_dmamap_complete, 1485 .map_unload = bounce_bus_dmamap_unload, 1486 .map_sync = bounce_bus_dmamap_sync 1487 }; 1488