busdma_machdep.c revision 227309
1/*- 2 * Copyright (c) 1997, 1998 Justin T. Gibbs. 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions, and the following disclaimer, 10 * without modification, immediately at the beginning of the file. 11 * 2. The name of the author may not be used to endorse or promote products 12 * derived from this software without specific prior written permission. 13 * 14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR 18 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24 * SUCH DAMAGE. 25 */ 26 27/* 28 * From amd64/busdma_machdep.c, r204214 29 */ 30 31#include <sys/cdefs.h> 32__FBSDID("$FreeBSD: head/sys/powerpc/powerpc/busdma_machdep.c 227309 2011-11-07 15:43:11Z ed $"); 33 34#include <sys/param.h> 35#include <sys/systm.h> 36#include <sys/malloc.h> 37#include <sys/bus.h> 38#include <sys/interrupt.h> 39#include <sys/kernel.h> 40#include <sys/ktr.h> 41#include <sys/lock.h> 42#include <sys/proc.h> 43#include <sys/mutex.h> 44#include <sys/mbuf.h> 45#include <sys/uio.h> 46#include <sys/sysctl.h> 47 48#include <vm/vm.h> 49#include <vm/vm_page.h> 50#include <vm/vm_map.h> 51 52#include <machine/atomic.h> 53#include <machine/bus.h> 54#include <machine/md_var.h> 55 56#include "iommu_if.h" 57 58#define MAX_BPAGES MIN(8192, physmem/40) 59 60struct bounce_zone; 61 62struct bus_dma_tag { 63 bus_dma_tag_t parent; 64 bus_size_t alignment; 65 bus_size_t boundary; 66 bus_addr_t lowaddr; 67 bus_addr_t highaddr; 68 bus_dma_filter_t *filter; 69 void *filterarg; 70 bus_size_t maxsize; 71 u_int nsegments; 72 bus_size_t maxsegsz; 73 int flags; 74 int ref_count; 75 int map_count; 76 bus_dma_lock_t *lockfunc; 77 void *lockfuncarg; 78 struct bounce_zone *bounce_zone; 79 device_t iommu; 80 void *iommu_cookie; 81}; 82 83struct 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 bus_size_t datacount; /* client data count */ 88 STAILQ_ENTRY(bounce_page) links; 89}; 90 91int busdma_swi_pending; 92 93struct 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 111static struct mtx bounce_lock; 112static int total_bpages; 113static int busdma_zonecount; 114static STAILQ_HEAD(, bounce_zone) bounce_zone_list; 115 116static SYSCTL_NODE(_hw, OID_AUTO, busdma, CTLFLAG_RD, 0, "Busdma parameters"); 117SYSCTL_INT(_hw_busdma, OID_AUTO, total_bpages, CTLFLAG_RD, &total_bpages, 0, 118 "Total bounce pages"); 119 120struct bus_dmamap { 121 struct bp_list bpages; 122 int pagesneeded; 123 int pagesreserved; 124 bus_dma_tag_t dmat; 125 void *buf; /* unmapped buffer pointer */ 126 bus_size_t buflen; /* unmapped buffer length */ 127 bus_dma_segment_t *segments; 128 int nsegs; 129 bus_dmamap_callback_t *callback; 130 void *callback_arg; 131 STAILQ_ENTRY(bus_dmamap) links; 132}; 133 134static STAILQ_HEAD(, bus_dmamap) bounce_map_waitinglist; 135static STAILQ_HEAD(, bus_dmamap) bounce_map_callbacklist; 136 137static void init_bounce_pages(void *dummy); 138static int alloc_bounce_zone(bus_dma_tag_t dmat); 139static int alloc_bounce_pages(bus_dma_tag_t dmat, u_int numpages); 140static int reserve_bounce_pages(bus_dma_tag_t dmat, bus_dmamap_t map, 141 int commit); 142static bus_addr_t add_bounce_page(bus_dma_tag_t dmat, bus_dmamap_t map, 143 vm_offset_t vaddr, bus_size_t size); 144static void free_bounce_page(bus_dma_tag_t dmat, struct bounce_page *bpage); 145static __inline int run_filter(bus_dma_tag_t dmat, bus_addr_t paddr); 146 147/* 148 * Return true if a match is made. 149 * 150 * To find a match walk the chain of bus_dma_tag_t's looking for 'paddr'. 151 * 152 * If paddr is within the bounds of the dma tag then call the filter callback 153 * to check for a match, if there is no filter callback then assume a match. 154 */ 155static __inline int 156run_filter(bus_dma_tag_t dmat, bus_addr_t paddr) 157{ 158 int retval; 159 160 retval = 0; 161 162 do { 163 if (dmat->filter == NULL && dmat->iommu == NULL && 164 paddr > dmat->lowaddr && paddr <= dmat->highaddr) 165 retval = 1; 166 if (dmat->filter == NULL && 167 (paddr & (dmat->alignment - 1)) != 0) 168 retval = 1; 169 if (dmat->filter != NULL && 170 (*dmat->filter)(dmat->filterarg, paddr) != 0) 171 retval = 1; 172 173 dmat = dmat->parent; 174 } while (retval == 0 && dmat != NULL); 175 return (retval); 176} 177 178/* 179 * Convenience function for manipulating driver locks from busdma (during 180 * busdma_swi, for example). Drivers that don't provide their own locks 181 * should specify &Giant to dmat->lockfuncarg. Drivers that use their own 182 * non-mutex locking scheme don't have to use this at all. 183 */ 184void 185busdma_lock_mutex(void *arg, bus_dma_lock_op_t op) 186{ 187 struct mtx *dmtx; 188 189 dmtx = (struct mtx *)arg; 190 switch (op) { 191 case BUS_DMA_LOCK: 192 mtx_lock(dmtx); 193 break; 194 case BUS_DMA_UNLOCK: 195 mtx_unlock(dmtx); 196 break; 197 default: 198 panic("Unknown operation 0x%x for busdma_lock_mutex!", op); 199 } 200} 201 202/* 203 * dflt_lock should never get called. It gets put into the dma tag when 204 * lockfunc == NULL, which is only valid if the maps that are associated 205 * with the tag are meant to never be defered. 206 * XXX Should have a way to identify which driver is responsible here. 207 */ 208static void 209dflt_lock(void *arg, bus_dma_lock_op_t op) 210{ 211 panic("driver error: busdma dflt_lock called"); 212} 213 214#define BUS_DMA_COULD_BOUNCE BUS_DMA_BUS3 215#define BUS_DMA_MIN_ALLOC_COMP BUS_DMA_BUS4 216/* 217 * Allocate a device specific dma_tag. 218 */ 219int 220bus_dma_tag_create(bus_dma_tag_t parent, bus_size_t alignment, 221 bus_size_t boundary, bus_addr_t lowaddr, 222 bus_addr_t highaddr, bus_dma_filter_t *filter, 223 void *filterarg, bus_size_t maxsize, int nsegments, 224 bus_size_t maxsegsz, int flags, bus_dma_lock_t *lockfunc, 225 void *lockfuncarg, bus_dma_tag_t *dmat) 226{ 227 bus_dma_tag_t newtag; 228 int error = 0; 229 230 /* Basic sanity checking */ 231 if (boundary != 0 && boundary < maxsegsz) 232 maxsegsz = boundary; 233 234 if (maxsegsz == 0) { 235 return (EINVAL); 236 } 237 238 /* Return a NULL tag on failure */ 239 *dmat = NULL; 240 241 newtag = (bus_dma_tag_t)malloc(sizeof(*newtag), M_DEVBUF, 242 M_ZERO | M_NOWAIT); 243 if (newtag == NULL) { 244 CTR4(KTR_BUSDMA, "%s returned tag %p tag flags 0x%x error %d", 245 __func__, newtag, 0, error); 246 return (ENOMEM); 247 } 248 249 newtag->parent = parent; 250 newtag->alignment = alignment; 251 newtag->boundary = boundary; 252 newtag->lowaddr = trunc_page((vm_paddr_t)lowaddr) + (PAGE_SIZE - 1); 253 newtag->highaddr = trunc_page((vm_paddr_t)highaddr) + (PAGE_SIZE - 1); 254 newtag->filter = filter; 255 newtag->filterarg = filterarg; 256 newtag->maxsize = maxsize; 257 newtag->nsegments = nsegments; 258 newtag->maxsegsz = maxsegsz; 259 newtag->flags = flags; 260 newtag->ref_count = 1; /* Count ourself */ 261 newtag->map_count = 0; 262 if (lockfunc != NULL) { 263 newtag->lockfunc = lockfunc; 264 newtag->lockfuncarg = lockfuncarg; 265 } else { 266 newtag->lockfunc = dflt_lock; 267 newtag->lockfuncarg = NULL; 268 } 269 270 /* Take into account any restrictions imposed by our parent tag */ 271 if (parent != NULL) { 272 newtag->lowaddr = MIN(parent->lowaddr, newtag->lowaddr); 273 newtag->highaddr = MAX(parent->highaddr, newtag->highaddr); 274 if (newtag->boundary == 0) 275 newtag->boundary = parent->boundary; 276 else if (parent->boundary != 0) 277 newtag->boundary = MIN(parent->boundary, 278 newtag->boundary); 279 if (newtag->filter == NULL) { 280 /* 281 * Short circuit looking at our parent directly 282 * since we have encapsulated all of its information 283 */ 284 newtag->filter = parent->filter; 285 newtag->filterarg = parent->filterarg; 286 newtag->parent = parent->parent; 287 } 288 if (newtag->parent != NULL) 289 atomic_add_int(&parent->ref_count, 1); 290 newtag->iommu = parent->iommu; 291 newtag->iommu_cookie = parent->iommu_cookie; 292 } 293 294 if (newtag->lowaddr < ptoa((vm_paddr_t)Maxmem) && newtag->iommu == NULL) 295 newtag->flags |= BUS_DMA_COULD_BOUNCE; 296 297 if (newtag->alignment > 1) 298 newtag->flags |= BUS_DMA_COULD_BOUNCE; 299 300 if (((newtag->flags & BUS_DMA_COULD_BOUNCE) != 0) && 301 (flags & BUS_DMA_ALLOCNOW) != 0) { 302 struct bounce_zone *bz; 303 304 /* Must bounce */ 305 306 if ((error = alloc_bounce_zone(newtag)) != 0) { 307 free(newtag, M_DEVBUF); 308 return (error); 309 } 310 bz = newtag->bounce_zone; 311 312 if (ptoa(bz->total_bpages) < maxsize) { 313 int pages; 314 315 pages = atop(maxsize) - bz->total_bpages; 316 317 /* Add pages to our bounce pool */ 318 if (alloc_bounce_pages(newtag, pages) < pages) 319 error = ENOMEM; 320 } 321 /* Performed initial allocation */ 322 newtag->flags |= BUS_DMA_MIN_ALLOC_COMP; 323 } 324 325 if (error != 0) { 326 free(newtag, M_DEVBUF); 327 } else { 328 *dmat = newtag; 329 } 330 CTR4(KTR_BUSDMA, "%s returned tag %p tag flags 0x%x error %d", 331 __func__, newtag, (newtag != NULL ? newtag->flags : 0), error); 332 return (error); 333} 334 335int 336bus_dma_tag_destroy(bus_dma_tag_t dmat) 337{ 338 bus_dma_tag_t dmat_copy; 339 int error; 340 341 error = 0; 342 dmat_copy = dmat; 343 344 if (dmat != NULL) { 345 346 if (dmat->map_count != 0) { 347 error = EBUSY; 348 goto out; 349 } 350 351 while (dmat != NULL) { 352 bus_dma_tag_t parent; 353 354 parent = dmat->parent; 355 atomic_subtract_int(&dmat->ref_count, 1); 356 if (dmat->ref_count == 0) { 357 free(dmat, M_DEVBUF); 358 /* 359 * Last reference count, so 360 * release our reference 361 * count on our parent. 362 */ 363 dmat = parent; 364 } else 365 dmat = NULL; 366 } 367 } 368out: 369 CTR3(KTR_BUSDMA, "%s tag %p error %d", __func__, dmat_copy, error); 370 return (error); 371} 372 373/* 374 * Allocate a handle for mapping from kva/uva/physical 375 * address space into bus device space. 376 */ 377int 378bus_dmamap_create(bus_dma_tag_t dmat, int flags, bus_dmamap_t *mapp) 379{ 380 int error; 381 382 error = 0; 383 384 *mapp = (bus_dmamap_t)malloc(sizeof(**mapp), M_DEVBUF, 385 M_NOWAIT | M_ZERO); 386 if (*mapp == NULL) { 387 CTR3(KTR_BUSDMA, "%s: tag %p error %d", 388 __func__, dmat, ENOMEM); 389 return (ENOMEM); 390 } 391 392 393 /* 394 * Bouncing might be required if the driver asks for an active 395 * exclusion region, a data alignment that is stricter than 1, and/or 396 * an active address boundary. 397 */ 398 if (dmat->flags & BUS_DMA_COULD_BOUNCE) { 399 400 /* Must bounce */ 401 struct bounce_zone *bz; 402 int maxpages; 403 404 if (dmat->bounce_zone == NULL) { 405 if ((error = alloc_bounce_zone(dmat)) != 0) 406 return (error); 407 } 408 bz = dmat->bounce_zone; 409 410 /* Initialize the new map */ 411 STAILQ_INIT(&((*mapp)->bpages)); 412 413 /* 414 * Attempt to add pages to our pool on a per-instance 415 * basis up to a sane limit. 416 */ 417 if (dmat->alignment > 1) 418 maxpages = MAX_BPAGES; 419 else 420 maxpages = MIN(MAX_BPAGES, Maxmem -atop(dmat->lowaddr)); 421 if ((dmat->flags & BUS_DMA_MIN_ALLOC_COMP) == 0 422 || (bz->map_count > 0 && bz->total_bpages < maxpages)) { 423 int pages; 424 425 pages = MAX(atop(dmat->maxsize), 1); 426 pages = MIN(maxpages - bz->total_bpages, pages); 427 pages = MAX(pages, 1); 428 if (alloc_bounce_pages(dmat, pages) < pages) 429 error = ENOMEM; 430 431 if ((dmat->flags & BUS_DMA_MIN_ALLOC_COMP) == 0) { 432 if (error == 0) 433 dmat->flags |= BUS_DMA_MIN_ALLOC_COMP; 434 } else { 435 error = 0; 436 } 437 } 438 bz->map_count++; 439 } 440 441 (*mapp)->nsegs = 0; 442 (*mapp)->segments = (bus_dma_segment_t *)malloc( 443 sizeof(bus_dma_segment_t) * dmat->nsegments, M_DEVBUF, 444 M_NOWAIT); 445 if ((*mapp)->segments == NULL) { 446 CTR3(KTR_BUSDMA, "%s: tag %p error %d", 447 __func__, dmat, ENOMEM); 448 return (ENOMEM); 449 } 450 451 if (error == 0) 452 dmat->map_count++; 453 CTR4(KTR_BUSDMA, "%s: tag %p tag flags 0x%x error %d", 454 __func__, dmat, dmat->flags, error); 455 return (error); 456} 457 458/* 459 * Destroy a handle for mapping from kva/uva/physical 460 * address space into bus device space. 461 */ 462int 463bus_dmamap_destroy(bus_dma_tag_t dmat, bus_dmamap_t map) 464{ 465 if (dmat->flags & BUS_DMA_COULD_BOUNCE) { 466 if (STAILQ_FIRST(&map->bpages) != NULL) { 467 CTR3(KTR_BUSDMA, "%s: tag %p error %d", 468 __func__, dmat, EBUSY); 469 return (EBUSY); 470 } 471 if (dmat->bounce_zone) 472 dmat->bounce_zone->map_count--; 473 } 474 free(map->segments, M_DEVBUF); 475 free(map, M_DEVBUF); 476 dmat->map_count--; 477 CTR2(KTR_BUSDMA, "%s: tag %p error 0", __func__, dmat); 478 return (0); 479} 480 481 482/* 483 * Allocate a piece of memory that can be efficiently mapped into 484 * bus device space based on the constraints lited in the dma tag. 485 * A dmamap to for use with dmamap_load is also allocated. 486 */ 487int 488bus_dmamem_alloc(bus_dma_tag_t dmat, void** vaddr, int flags, 489 bus_dmamap_t *mapp) 490{ 491 int mflags; 492 493 if (flags & BUS_DMA_NOWAIT) 494 mflags = M_NOWAIT; 495 else 496 mflags = M_WAITOK; 497 498 bus_dmamap_create(dmat, flags, mapp); 499 500 if (flags & BUS_DMA_ZERO) 501 mflags |= M_ZERO; 502 503 /* 504 * XXX: 505 * (dmat->alignment < dmat->maxsize) is just a quick hack; the exact 506 * alignment guarantees of malloc need to be nailed down, and the 507 * code below should be rewritten to take that into account. 508 * 509 * In the meantime, we'll warn the user if malloc gets it wrong. 510 */ 511 if ((dmat->maxsize <= PAGE_SIZE) && 512 (dmat->alignment < dmat->maxsize) && 513 dmat->lowaddr >= ptoa((vm_paddr_t)Maxmem)) { 514 *vaddr = malloc(dmat->maxsize, M_DEVBUF, mflags); 515 } else { 516 /* 517 * XXX Use Contigmalloc until it is merged into this facility 518 * and handles multi-seg allocations. Nobody is doing 519 * multi-seg allocations yet though. 520 * XXX Certain AGP hardware does. 521 */ 522 *vaddr = contigmalloc(dmat->maxsize, M_DEVBUF, mflags, 523 0ul, dmat->lowaddr, dmat->alignment? dmat->alignment : 1ul, 524 dmat->boundary); 525 } 526 if (*vaddr == NULL) { 527 CTR4(KTR_BUSDMA, "%s: tag %p tag flags 0x%x error %d", 528 __func__, dmat, dmat->flags, ENOMEM); 529 return (ENOMEM); 530 } else if (vtophys(*vaddr) & (dmat->alignment - 1)) { 531 printf("bus_dmamem_alloc failed to align memory properly.\n"); 532 } 533#ifdef NOTYET 534 if (flags & BUS_DMA_NOCACHE) 535 pmap_change_attr((vm_offset_t)*vaddr, dmat->maxsize, 536 VM_MEMATTR_UNCACHEABLE); 537#endif 538 CTR4(KTR_BUSDMA, "%s: tag %p tag flags 0x%x error %d", 539 __func__, dmat, dmat->flags, 0); 540 return (0); 541} 542 543/* 544 * Free a piece of memory and it's allociated dmamap, that was allocated 545 * via bus_dmamem_alloc. Make the same choice for free/contigfree. 546 */ 547void 548bus_dmamem_free(bus_dma_tag_t dmat, void *vaddr, bus_dmamap_t map) 549{ 550 bus_dmamap_destroy(dmat, map); 551 552#ifdef NOTYET 553 pmap_change_attr((vm_offset_t)vaddr, dmat->maxsize, VM_MEMATTR_DEFAULT); 554#endif 555 if ((dmat->maxsize <= PAGE_SIZE) && 556 (dmat->alignment < dmat->maxsize) && 557 dmat->lowaddr >= ptoa((vm_paddr_t)Maxmem)) 558 free(vaddr, M_DEVBUF); 559 else { 560 contigfree(vaddr, dmat->maxsize, M_DEVBUF); 561 } 562 CTR3(KTR_BUSDMA, "%s: tag %p flags 0x%x", __func__, dmat, dmat->flags); 563} 564 565/* 566 * Utility function to load a linear buffer. lastaddrp holds state 567 * between invocations (for multiple-buffer loads). segp contains 568 * the starting segment on entrance, and the ending segment on exit. 569 * first indicates if this is the first invocation of this function. 570 */ 571static __inline int 572_bus_dmamap_load_buffer(bus_dma_tag_t dmat, 573 bus_dmamap_t map, 574 void *buf, bus_size_t buflen, 575 pmap_t pmap, 576 int flags, 577 bus_addr_t *lastaddrp, 578 bus_dma_segment_t *segs, 579 int *segp, 580 int first) 581{ 582 bus_size_t sgsize; 583 bus_addr_t curaddr, lastaddr, baddr, bmask; 584 vm_offset_t vaddr; 585 bus_addr_t paddr; 586 int seg; 587 588 if (map->pagesneeded == 0 && ((dmat->flags & BUS_DMA_COULD_BOUNCE) != 0)) { 589 vm_offset_t vendaddr; 590 591 CTR4(KTR_BUSDMA, "lowaddr= %d Maxmem= %d, boundary= %d, " 592 "alignment= %d", dmat->lowaddr, ptoa((vm_paddr_t)Maxmem), 593 dmat->boundary, dmat->alignment); 594 CTR2(KTR_BUSDMA, "map= %p, pagesneeded= %d", map, map->pagesneeded); 595 /* 596 * Count the number of bounce pages 597 * needed in order to complete this transfer 598 */ 599 vaddr = (vm_offset_t)buf; 600 vendaddr = (vm_offset_t)buf + buflen; 601 602 while (vaddr < vendaddr) { 603 bus_size_t sg_len; 604 605 sg_len = PAGE_SIZE - ((vm_offset_t)vaddr & PAGE_MASK); 606 if (pmap) 607 paddr = pmap_extract(pmap, vaddr); 608 else 609 paddr = pmap_kextract(vaddr); 610 if (run_filter(dmat, paddr) != 0) { 611 sg_len = roundup2(sg_len, dmat->alignment); 612 map->pagesneeded++; 613 } 614 vaddr += sg_len; 615 } 616 CTR1(KTR_BUSDMA, "pagesneeded= %d\n", map->pagesneeded); 617 } 618 619 /* Reserve Necessary Bounce Pages */ 620 if (map->pagesneeded != 0) { 621 mtx_lock(&bounce_lock); 622 if (flags & BUS_DMA_NOWAIT) { 623 if (reserve_bounce_pages(dmat, map, 0) != 0) { 624 mtx_unlock(&bounce_lock); 625 return (ENOMEM); 626 } 627 } else { 628 if (reserve_bounce_pages(dmat, map, 1) != 0) { 629 /* Queue us for resources */ 630 map->dmat = dmat; 631 map->buf = buf; 632 map->buflen = buflen; 633 STAILQ_INSERT_TAIL(&bounce_map_waitinglist, 634 map, links); 635 mtx_unlock(&bounce_lock); 636 return (EINPROGRESS); 637 } 638 } 639 mtx_unlock(&bounce_lock); 640 } 641 642 vaddr = (vm_offset_t)buf; 643 lastaddr = *lastaddrp; 644 bmask = ~(dmat->boundary - 1); 645 646 for (seg = *segp; buflen > 0 ; ) { 647 bus_size_t max_sgsize; 648 649 /* 650 * Get the physical address for this segment. 651 */ 652 if (pmap) 653 curaddr = pmap_extract(pmap, vaddr); 654 else 655 curaddr = pmap_kextract(vaddr); 656 657 /* 658 * Compute the segment size, and adjust counts. 659 */ 660 max_sgsize = MIN(buflen, dmat->maxsegsz); 661 sgsize = PAGE_SIZE - ((vm_offset_t)curaddr & PAGE_MASK); 662 if (map->pagesneeded != 0 && run_filter(dmat, curaddr)) { 663 sgsize = roundup2(sgsize, dmat->alignment); 664 sgsize = MIN(sgsize, max_sgsize); 665 curaddr = add_bounce_page(dmat, map, vaddr, sgsize); 666 } else { 667 sgsize = MIN(sgsize, max_sgsize); 668 } 669 670 /* 671 * Make sure we don't cross any boundaries. 672 */ 673 if (dmat->boundary > 0) { 674 baddr = (curaddr + dmat->boundary) & bmask; 675 if (sgsize > (baddr - curaddr)) 676 sgsize = (baddr - curaddr); 677 } 678 679 /* 680 * Insert chunk into a segment, coalescing with 681 * previous segment if possible. 682 */ 683 if (first) { 684 segs[seg].ds_addr = curaddr; 685 segs[seg].ds_len = sgsize; 686 first = 0; 687 } else { 688 if (curaddr == lastaddr && 689 (segs[seg].ds_len + sgsize) <= dmat->maxsegsz && 690 (dmat->boundary == 0 || 691 (segs[seg].ds_addr & bmask) == (curaddr & bmask))) 692 segs[seg].ds_len += sgsize; 693 else { 694 if (++seg >= dmat->nsegments) 695 break; 696 segs[seg].ds_addr = curaddr; 697 segs[seg].ds_len = sgsize; 698 } 699 } 700 701 lastaddr = curaddr + sgsize; 702 vaddr += sgsize; 703 buflen -= sgsize; 704 } 705 706 *segp = seg; 707 *lastaddrp = lastaddr; 708 709 /* 710 * Did we fit? 711 */ 712 return (buflen != 0 ? EFBIG : 0); /* XXX better return value here? */ 713} 714 715/* 716 * Map the buffer buf into bus space using the dmamap map. 717 */ 718int 719bus_dmamap_load(bus_dma_tag_t dmat, bus_dmamap_t map, void *buf, 720 bus_size_t buflen, bus_dmamap_callback_t *callback, 721 void *callback_arg, int flags) 722{ 723 bus_addr_t lastaddr = 0; 724 int error; 725 726 if (dmat->flags & BUS_DMA_COULD_BOUNCE) { 727 flags |= BUS_DMA_WAITOK; 728 map->callback = callback; 729 map->callback_arg = callback_arg; 730 } 731 732 map->nsegs = 0; 733 error = _bus_dmamap_load_buffer(dmat, map, buf, buflen, NULL, flags, 734 &lastaddr, map->segments, &map->nsegs, 1); 735 map->nsegs++; 736 737 CTR5(KTR_BUSDMA, "%s: tag %p tag flags 0x%x error %d nsegs %d", 738 __func__, dmat, dmat->flags, error, map->nsegs); 739 740 if (error == EINPROGRESS) { 741 return (error); 742 } 743 744 if (dmat->iommu != NULL) 745 IOMMU_MAP(dmat->iommu, map->segments, &map->nsegs, dmat->lowaddr, 746 dmat->highaddr, dmat->alignment, dmat->boundary, 747 dmat->iommu_cookie); 748 749 if (error) 750 (*callback)(callback_arg, map->segments, 0, error); 751 else 752 (*callback)(callback_arg, map->segments, map->nsegs, 0); 753 754 /* 755 * Return ENOMEM to the caller so that it can pass it up the stack. 756 * This error only happens when NOWAIT is set, so deferal is disabled. 757 */ 758 if (error == ENOMEM) 759 return (error); 760 761 return (0); 762} 763 764 765/* 766 * Like _bus_dmamap_load(), but for mbufs. 767 */ 768int 769bus_dmamap_load_mbuf(bus_dma_tag_t dmat, bus_dmamap_t map, 770 struct mbuf *m0, 771 bus_dmamap_callback2_t *callback, void *callback_arg, 772 int flags) 773{ 774 int error; 775 776 M_ASSERTPKTHDR(m0); 777 778 flags |= BUS_DMA_NOWAIT; 779 map->nsegs = 0; 780 error = 0; 781 if (m0->m_pkthdr.len <= dmat->maxsize) { 782 int first = 1; 783 bus_addr_t lastaddr = 0; 784 struct mbuf *m; 785 786 for (m = m0; m != NULL && error == 0; m = m->m_next) { 787 if (m->m_len > 0) { 788 error = _bus_dmamap_load_buffer(dmat, map, 789 m->m_data, m->m_len, 790 NULL, flags, &lastaddr, 791 map->segments, &map->nsegs, first); 792 first = 0; 793 } 794 } 795 } else { 796 error = EINVAL; 797 } 798 799 map->nsegs++; 800 if (dmat->iommu != NULL) 801 IOMMU_MAP(dmat->iommu, map->segments, &map->nsegs, dmat->lowaddr, 802 dmat->highaddr, dmat->alignment, dmat->boundary, 803 dmat->iommu_cookie); 804 805 if (error) { 806 /* force "no valid mappings" in callback */ 807 (*callback)(callback_arg, map->segments, 0, 0, error); 808 } else { 809 (*callback)(callback_arg, map->segments, 810 map->nsegs, m0->m_pkthdr.len, error); 811 } 812 CTR5(KTR_BUSDMA, "%s: tag %p tag flags 0x%x error %d nsegs %d", 813 __func__, dmat, dmat->flags, error, map->nsegs); 814 return (error); 815} 816 817int 818bus_dmamap_load_mbuf_sg(bus_dma_tag_t dmat, bus_dmamap_t map, 819 struct mbuf *m0, bus_dma_segment_t *segs, int *nsegs, 820 int flags) 821{ 822 int error; 823 824 M_ASSERTPKTHDR(m0); 825 826 flags |= BUS_DMA_NOWAIT; 827 *nsegs = 0; 828 error = 0; 829 if (m0->m_pkthdr.len <= dmat->maxsize) { 830 int first = 1; 831 bus_addr_t lastaddr = 0; 832 struct mbuf *m; 833 834 for (m = m0; m != NULL && error == 0; m = m->m_next) { 835 if (m->m_len > 0) { 836 error = _bus_dmamap_load_buffer(dmat, map, 837 m->m_data, m->m_len, 838 NULL, flags, &lastaddr, 839 segs, nsegs, first); 840 first = 0; 841 } 842 } 843 } else { 844 error = EINVAL; 845 } 846 847 /* XXX FIXME: Having to increment nsegs is really annoying */ 848 ++*nsegs; 849 850 if (dmat->iommu != NULL) 851 IOMMU_MAP(dmat->iommu, segs, nsegs, dmat->lowaddr, 852 dmat->highaddr, dmat->alignment, dmat->boundary, 853 dmat->iommu_cookie); 854 855 map->nsegs = *nsegs; 856 memcpy(map->segments, segs, map->nsegs*sizeof(segs[0])); 857 858 CTR5(KTR_BUSDMA, "%s: tag %p tag flags 0x%x error %d nsegs %d", 859 __func__, dmat, dmat->flags, error, *nsegs); 860 return (error); 861} 862 863/* 864 * Like _bus_dmamap_load(), but for uios. 865 */ 866int 867bus_dmamap_load_uio(bus_dma_tag_t dmat, bus_dmamap_t map, 868 struct uio *uio, 869 bus_dmamap_callback2_t *callback, void *callback_arg, 870 int flags) 871{ 872 bus_addr_t lastaddr = 0; 873 int error, first, i; 874 bus_size_t resid; 875 struct iovec *iov; 876 pmap_t pmap; 877 878 flags |= BUS_DMA_NOWAIT; 879 resid = uio->uio_resid; 880 iov = uio->uio_iov; 881 882 if (uio->uio_segflg == UIO_USERSPACE) { 883 KASSERT(uio->uio_td != NULL, 884 ("bus_dmamap_load_uio: USERSPACE but no proc")); 885 pmap = vmspace_pmap(uio->uio_td->td_proc->p_vmspace); 886 } else 887 pmap = NULL; 888 889 map->nsegs = 0; 890 error = 0; 891 first = 1; 892 for (i = 0; i < uio->uio_iovcnt && resid != 0 && !error; i++) { 893 /* 894 * Now at the first iovec to load. Load each iovec 895 * until we have exhausted the residual count. 896 */ 897 bus_size_t minlen = 898 resid < iov[i].iov_len ? resid : iov[i].iov_len; 899 caddr_t addr = (caddr_t) iov[i].iov_base; 900 901 if (minlen > 0) { 902 error = _bus_dmamap_load_buffer(dmat, map, 903 addr, minlen, pmap, flags, &lastaddr, 904 map->segments, &map->nsegs, first); 905 first = 0; 906 907 resid -= minlen; 908 } 909 } 910 911 map->nsegs++; 912 if (dmat->iommu != NULL) 913 IOMMU_MAP(dmat->iommu, map->segments, &map->nsegs, dmat->lowaddr, 914 dmat->highaddr, dmat->alignment, dmat->boundary, 915 dmat->iommu_cookie); 916 917 if (error) { 918 /* force "no valid mappings" in callback */ 919 (*callback)(callback_arg, map->segments, 0, 0, error); 920 } else { 921 (*callback)(callback_arg, map->segments, 922 map->nsegs, uio->uio_resid, error); 923 } 924 CTR5(KTR_BUSDMA, "%s: tag %p tag flags 0x%x error %d nsegs %d", 925 __func__, dmat, dmat->flags, error, map->nsegs); 926 return (error); 927} 928 929/* 930 * Release the mapping held by map. 931 */ 932void 933_bus_dmamap_unload(bus_dma_tag_t dmat, bus_dmamap_t map) 934{ 935 struct bounce_page *bpage; 936 937 if (dmat->iommu) { 938 IOMMU_UNMAP(dmat->iommu, map->segments, map->nsegs, dmat->iommu_cookie); 939 map->nsegs = 0; 940 } 941 942 while ((bpage = STAILQ_FIRST(&map->bpages)) != NULL) { 943 STAILQ_REMOVE_HEAD(&map->bpages, links); 944 free_bounce_page(dmat, bpage); 945 } 946} 947 948void 949_bus_dmamap_sync(bus_dma_tag_t dmat, bus_dmamap_t map, bus_dmasync_op_t op) 950{ 951 struct bounce_page *bpage; 952 953 if ((bpage = STAILQ_FIRST(&map->bpages)) != NULL) { 954 /* 955 * Handle data bouncing. We might also 956 * want to add support for invalidating 957 * the caches on broken hardware 958 */ 959 CTR4(KTR_BUSDMA, "%s: tag %p tag flags 0x%x op 0x%x " 960 "performing bounce", __func__, op, dmat, dmat->flags); 961 962 if (op & BUS_DMASYNC_PREWRITE) { 963 while (bpage != NULL) { 964 bcopy((void *)bpage->datavaddr, 965 (void *)bpage->vaddr, 966 bpage->datacount); 967 bpage = STAILQ_NEXT(bpage, links); 968 } 969 dmat->bounce_zone->total_bounced++; 970 } 971 972 if (op & BUS_DMASYNC_POSTREAD) { 973 while (bpage != NULL) { 974 bcopy((void *)bpage->vaddr, 975 (void *)bpage->datavaddr, 976 bpage->datacount); 977 bpage = STAILQ_NEXT(bpage, links); 978 } 979 dmat->bounce_zone->total_bounced++; 980 } 981 } 982} 983 984static void 985init_bounce_pages(void *dummy __unused) 986{ 987 988 total_bpages = 0; 989 STAILQ_INIT(&bounce_zone_list); 990 STAILQ_INIT(&bounce_map_waitinglist); 991 STAILQ_INIT(&bounce_map_callbacklist); 992 mtx_init(&bounce_lock, "bounce pages lock", NULL, MTX_DEF); 993} 994SYSINIT(bpages, SI_SUB_LOCK, SI_ORDER_ANY, init_bounce_pages, NULL); 995 996static struct sysctl_ctx_list * 997busdma_sysctl_tree(struct bounce_zone *bz) 998{ 999 return (&bz->sysctl_tree); 1000} 1001 1002static struct sysctl_oid * 1003busdma_sysctl_tree_top(struct bounce_zone *bz) 1004{ 1005 return (bz->sysctl_tree_top); 1006} 1007 1008static int 1009alloc_bounce_zone(bus_dma_tag_t dmat) 1010{ 1011 struct bounce_zone *bz; 1012 1013 /* Check to see if we already have a suitable zone */ 1014 STAILQ_FOREACH(bz, &bounce_zone_list, links) { 1015 if ((dmat->alignment <= bz->alignment) 1016 && (dmat->lowaddr >= bz->lowaddr)) { 1017 dmat->bounce_zone = bz; 1018 return (0); 1019 } 1020 } 1021 1022 if ((bz = (struct bounce_zone *)malloc(sizeof(*bz), M_DEVBUF, 1023 M_NOWAIT | M_ZERO)) == NULL) 1024 return (ENOMEM); 1025 1026 STAILQ_INIT(&bz->bounce_page_list); 1027 bz->free_bpages = 0; 1028 bz->reserved_bpages = 0; 1029 bz->active_bpages = 0; 1030 bz->lowaddr = dmat->lowaddr; 1031 bz->alignment = MAX(dmat->alignment, PAGE_SIZE); 1032 bz->map_count = 0; 1033 snprintf(bz->zoneid, 8, "zone%d", busdma_zonecount); 1034 busdma_zonecount++; 1035 snprintf(bz->lowaddrid, 18, "%#jx", (uintmax_t)bz->lowaddr); 1036 STAILQ_INSERT_TAIL(&bounce_zone_list, bz, links); 1037 dmat->bounce_zone = bz; 1038 1039 sysctl_ctx_init(&bz->sysctl_tree); 1040 bz->sysctl_tree_top = SYSCTL_ADD_NODE(&bz->sysctl_tree, 1041 SYSCTL_STATIC_CHILDREN(_hw_busdma), OID_AUTO, bz->zoneid, 1042 CTLFLAG_RD, 0, ""); 1043 if (bz->sysctl_tree_top == NULL) { 1044 sysctl_ctx_free(&bz->sysctl_tree); 1045 return (0); /* XXX error code? */ 1046 } 1047 1048 SYSCTL_ADD_INT(busdma_sysctl_tree(bz), 1049 SYSCTL_CHILDREN(busdma_sysctl_tree_top(bz)), OID_AUTO, 1050 "total_bpages", CTLFLAG_RD, &bz->total_bpages, 0, 1051 "Total bounce pages"); 1052 SYSCTL_ADD_INT(busdma_sysctl_tree(bz), 1053 SYSCTL_CHILDREN(busdma_sysctl_tree_top(bz)), OID_AUTO, 1054 "free_bpages", CTLFLAG_RD, &bz->free_bpages, 0, 1055 "Free bounce pages"); 1056 SYSCTL_ADD_INT(busdma_sysctl_tree(bz), 1057 SYSCTL_CHILDREN(busdma_sysctl_tree_top(bz)), OID_AUTO, 1058 "reserved_bpages", CTLFLAG_RD, &bz->reserved_bpages, 0, 1059 "Reserved bounce pages"); 1060 SYSCTL_ADD_INT(busdma_sysctl_tree(bz), 1061 SYSCTL_CHILDREN(busdma_sysctl_tree_top(bz)), OID_AUTO, 1062 "active_bpages", CTLFLAG_RD, &bz->active_bpages, 0, 1063 "Active bounce pages"); 1064 SYSCTL_ADD_INT(busdma_sysctl_tree(bz), 1065 SYSCTL_CHILDREN(busdma_sysctl_tree_top(bz)), OID_AUTO, 1066 "total_bounced", CTLFLAG_RD, &bz->total_bounced, 0, 1067 "Total bounce requests"); 1068 SYSCTL_ADD_INT(busdma_sysctl_tree(bz), 1069 SYSCTL_CHILDREN(busdma_sysctl_tree_top(bz)), OID_AUTO, 1070 "total_deferred", CTLFLAG_RD, &bz->total_deferred, 0, 1071 "Total bounce requests that were deferred"); 1072 SYSCTL_ADD_STRING(busdma_sysctl_tree(bz), 1073 SYSCTL_CHILDREN(busdma_sysctl_tree_top(bz)), OID_AUTO, 1074 "lowaddr", CTLFLAG_RD, bz->lowaddrid, 0, ""); 1075 SYSCTL_ADD_INT(busdma_sysctl_tree(bz), 1076 SYSCTL_CHILDREN(busdma_sysctl_tree_top(bz)), OID_AUTO, 1077 "alignment", CTLFLAG_RD, &bz->alignment, 0, ""); 1078 1079 return (0); 1080} 1081 1082static int 1083alloc_bounce_pages(bus_dma_tag_t dmat, u_int numpages) 1084{ 1085 struct bounce_zone *bz; 1086 int count; 1087 1088 bz = dmat->bounce_zone; 1089 count = 0; 1090 while (numpages > 0) { 1091 struct bounce_page *bpage; 1092 1093 bpage = (struct bounce_page *)malloc(sizeof(*bpage), M_DEVBUF, 1094 M_NOWAIT | M_ZERO); 1095 1096 if (bpage == NULL) 1097 break; 1098 bpage->vaddr = (vm_offset_t)contigmalloc(PAGE_SIZE, M_DEVBUF, 1099 M_NOWAIT, 0ul, 1100 bz->lowaddr, 1101 PAGE_SIZE, 1102 0); 1103 if (bpage->vaddr == 0) { 1104 free(bpage, M_DEVBUF); 1105 break; 1106 } 1107 bpage->busaddr = pmap_kextract(bpage->vaddr); 1108 mtx_lock(&bounce_lock); 1109 STAILQ_INSERT_TAIL(&bz->bounce_page_list, bpage, links); 1110 total_bpages++; 1111 bz->total_bpages++; 1112 bz->free_bpages++; 1113 mtx_unlock(&bounce_lock); 1114 count++; 1115 numpages--; 1116 } 1117 return (count); 1118} 1119 1120static int 1121reserve_bounce_pages(bus_dma_tag_t dmat, bus_dmamap_t map, int commit) 1122{ 1123 struct bounce_zone *bz; 1124 int pages; 1125 1126 mtx_assert(&bounce_lock, MA_OWNED); 1127 bz = dmat->bounce_zone; 1128 pages = MIN(bz->free_bpages, map->pagesneeded - map->pagesreserved); 1129 if (commit == 0 && map->pagesneeded > (map->pagesreserved + pages)) 1130 return (map->pagesneeded - (map->pagesreserved + pages)); 1131 bz->free_bpages -= pages; 1132 bz->reserved_bpages += pages; 1133 map->pagesreserved += pages; 1134 pages = map->pagesneeded - map->pagesreserved; 1135 1136 return (pages); 1137} 1138 1139static bus_addr_t 1140add_bounce_page(bus_dma_tag_t dmat, bus_dmamap_t map, vm_offset_t vaddr, 1141 bus_size_t size) 1142{ 1143 struct bounce_zone *bz; 1144 struct bounce_page *bpage; 1145 1146 KASSERT(dmat->bounce_zone != NULL, ("no bounce zone in dma tag")); 1147 1148 bz = dmat->bounce_zone; 1149 if (map->pagesneeded == 0) 1150 panic("add_bounce_page: map doesn't need any pages"); 1151 map->pagesneeded--; 1152 1153 if (map->pagesreserved == 0) 1154 panic("add_bounce_page: map doesn't need any pages"); 1155 map->pagesreserved--; 1156 1157 mtx_lock(&bounce_lock); 1158 bpage = STAILQ_FIRST(&bz->bounce_page_list); 1159 if (bpage == NULL) 1160 panic("add_bounce_page: free page list is empty"); 1161 1162 STAILQ_REMOVE_HEAD(&bz->bounce_page_list, links); 1163 bz->reserved_bpages--; 1164 bz->active_bpages++; 1165 mtx_unlock(&bounce_lock); 1166 1167 if (dmat->flags & BUS_DMA_KEEP_PG_OFFSET) { 1168 /* Page offset needs to be preserved. */ 1169 bpage->vaddr |= vaddr & PAGE_MASK; 1170 bpage->busaddr |= vaddr & PAGE_MASK; 1171 } 1172 bpage->datavaddr = vaddr; 1173 bpage->datacount = size; 1174 STAILQ_INSERT_TAIL(&(map->bpages), bpage, links); 1175 return (bpage->busaddr); 1176} 1177 1178static void 1179free_bounce_page(bus_dma_tag_t dmat, struct bounce_page *bpage) 1180{ 1181 struct bus_dmamap *map; 1182 struct bounce_zone *bz; 1183 1184 bz = dmat->bounce_zone; 1185 bpage->datavaddr = 0; 1186 bpage->datacount = 0; 1187 if (dmat->flags & BUS_DMA_KEEP_PG_OFFSET) { 1188 /* 1189 * Reset the bounce page to start at offset 0. Other uses 1190 * of this bounce page may need to store a full page of 1191 * data and/or assume it starts on a page boundary. 1192 */ 1193 bpage->vaddr &= ~PAGE_MASK; 1194 bpage->busaddr &= ~PAGE_MASK; 1195 } 1196 1197 mtx_lock(&bounce_lock); 1198 STAILQ_INSERT_HEAD(&bz->bounce_page_list, bpage, links); 1199 bz->free_bpages++; 1200 bz->active_bpages--; 1201 if ((map = STAILQ_FIRST(&bounce_map_waitinglist)) != NULL) { 1202 if (reserve_bounce_pages(map->dmat, map, 1) == 0) { 1203 STAILQ_REMOVE_HEAD(&bounce_map_waitinglist, links); 1204 STAILQ_INSERT_TAIL(&bounce_map_callbacklist, 1205 map, links); 1206 busdma_swi_pending = 1; 1207 bz->total_deferred++; 1208 swi_sched(vm_ih, 0); 1209 } 1210 } 1211 mtx_unlock(&bounce_lock); 1212} 1213 1214void 1215busdma_swi(void) 1216{ 1217 bus_dma_tag_t dmat; 1218 struct bus_dmamap *map; 1219 1220 mtx_lock(&bounce_lock); 1221 while ((map = STAILQ_FIRST(&bounce_map_callbacklist)) != NULL) { 1222 STAILQ_REMOVE_HEAD(&bounce_map_callbacklist, links); 1223 mtx_unlock(&bounce_lock); 1224 dmat = map->dmat; 1225 (dmat->lockfunc)(dmat->lockfuncarg, BUS_DMA_LOCK); 1226 bus_dmamap_load(map->dmat, map, map->buf, map->buflen, 1227 map->callback, map->callback_arg, /*flags*/0); 1228 (dmat->lockfunc)(dmat->lockfuncarg, BUS_DMA_UNLOCK); 1229 mtx_lock(&bounce_lock); 1230 } 1231 mtx_unlock(&bounce_lock); 1232} 1233 1234int 1235bus_dma_tag_set_iommu(bus_dma_tag_t tag, struct device *iommu, void *cookie) 1236{ 1237 tag->iommu = iommu; 1238 tag->iommu_cookie = cookie; 1239 1240 return (0); 1241} 1242 1243