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