busdma_bounce.c (159130) | busdma_bounce.c (162211) |
---|---|
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 --- 11 unchanged lines hidden (view full) --- 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#include <sys/cdefs.h> | 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 --- 11 unchanged lines hidden (view full) --- 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#include <sys/cdefs.h> |
28__FBSDID("$FreeBSD: head/sys/i386/i386/busdma_machdep.c 159130 2006-06-01 04:49:29Z silby $"); | 28__FBSDID("$FreeBSD: head/sys/i386/i386/busdma_machdep.c 162211 2006-09-11 06:48:53Z scottl $"); |
29 30#include <sys/param.h> 31#include <sys/kdb.h> 32#include <ddb/ddb.h> 33#include <ddb/db_output.h> 34#include <sys/systm.h> 35#include <sys/malloc.h> 36#include <sys/bus.h> --- 11 unchanged lines hidden (view full) --- 48#include <vm/vm_page.h> 49#include <vm/vm_map.h> 50 51#include <machine/atomic.h> 52#include <machine/bus.h> 53#include <machine/md_var.h> 54 55#define MAX_BPAGES 512 | 29 30#include <sys/param.h> 31#include <sys/kdb.h> 32#include <ddb/ddb.h> 33#include <ddb/db_output.h> 34#include <sys/systm.h> 35#include <sys/malloc.h> 36#include <sys/bus.h> --- 11 unchanged lines hidden (view full) --- 48#include <vm/vm_page.h> 49#include <vm/vm_map.h> 50 51#include <machine/atomic.h> 52#include <machine/bus.h> 53#include <machine/md_var.h> 54 55#define MAX_BPAGES 512 |
56#define BUS_DMA_USE_FILTER BUS_DMA_BUS2 57#define BUS_DMA_COULD_BOUNCE BUS_DMA_BUS3 58#define BUS_DMA_MIN_ALLOC_COMP BUS_DMA_BUS4 |
|
56 57struct bounce_zone; 58 59struct bus_dma_tag { 60 bus_dma_tag_t parent; 61 bus_size_t alignment; 62 bus_size_t boundary; 63 bus_addr_t lowaddr; --- 68 unchanged lines hidden (view full) --- 132static void init_bounce_pages(void *dummy); 133static int alloc_bounce_zone(bus_dma_tag_t dmat); 134static int alloc_bounce_pages(bus_dma_tag_t dmat, u_int numpages); 135static int reserve_bounce_pages(bus_dma_tag_t dmat, bus_dmamap_t map, 136 int commit); 137static bus_addr_t add_bounce_page(bus_dma_tag_t dmat, bus_dmamap_t map, 138 vm_offset_t vaddr, bus_size_t size); 139static void free_bounce_page(bus_dma_tag_t dmat, struct bounce_page *bpage); | 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; --- 68 unchanged lines hidden (view full) --- 135static void init_bounce_pages(void *dummy); 136static int alloc_bounce_zone(bus_dma_tag_t dmat); 137static int alloc_bounce_pages(bus_dma_tag_t dmat, u_int numpages); 138static int reserve_bounce_pages(bus_dma_tag_t dmat, bus_dmamap_t map, 139 int commit); 140static bus_addr_t add_bounce_page(bus_dma_tag_t dmat, bus_dmamap_t map, 141 vm_offset_t vaddr, bus_size_t size); 142static void free_bounce_page(bus_dma_tag_t dmat, struct bounce_page *bpage); |
140static __inline int run_filter(bus_dma_tag_t dmat, bus_addr_t paddr); | 143static int run_filter(bus_dma_tag_t dmat, bus_addr_t paddr); |
141 142/* 143 * Return true if a match is made. 144 * 145 * To find a match walk the chain of bus_dma_tag_t's looking for 'paddr'. 146 * 147 * If paddr is within the bounds of the dma tag then call the filter callback 148 * to check for a match, if there is no filter callback then assume a match. 149 */ | 144 145/* 146 * Return true if a match is made. 147 * 148 * To find a match walk the chain of bus_dma_tag_t's looking for 'paddr'. 149 * 150 * If paddr is within the bounds of the dma tag then call the filter callback 151 * to check for a match, if there is no filter callback then assume a match. 152 */ |
150static __inline int | 153static int |
151run_filter(bus_dma_tag_t dmat, bus_addr_t paddr) 152{ 153 int retval; 154 155 retval = 0; 156 157 do { 158 if (((paddr > dmat->lowaddr && paddr <= dmat->highaddr) --- 38 unchanged lines hidden (view full) --- 197 * XXX Should have a way to identify which driver is responsible here. 198 */ 199static void 200dflt_lock(void *arg, bus_dma_lock_op_t op) 201{ 202 panic("driver error: busdma dflt_lock called"); 203} 204 | 154run_filter(bus_dma_tag_t dmat, bus_addr_t paddr) 155{ 156 int retval; 157 158 retval = 0; 159 160 do { 161 if (((paddr > dmat->lowaddr && paddr <= dmat->highaddr) --- 38 unchanged lines hidden (view full) --- 200 * XXX Should have a way to identify which driver is responsible here. 201 */ 202static void 203dflt_lock(void *arg, bus_dma_lock_op_t op) 204{ 205 panic("driver error: busdma dflt_lock called"); 206} 207 |
205#define BUS_DMA_COULD_BOUNCE BUS_DMA_BUS3 206#define BUS_DMA_MIN_ALLOC_COMP BUS_DMA_BUS4 | |
207/* 208 * Allocate a device specific dma_tag. 209 */ 210int 211bus_dma_tag_create(bus_dma_tag_t parent, bus_size_t alignment, 212 bus_size_t boundary, bus_addr_t lowaddr, 213 bus_addr_t highaddr, bus_dma_filter_t *filter, 214 void *filterarg, bus_size_t maxsize, int nsegments, --- 45 unchanged lines hidden (view full) --- 260 if (parent != NULL) { 261 newtag->lowaddr = MIN(parent->lowaddr, newtag->lowaddr); 262 newtag->highaddr = MAX(parent->highaddr, newtag->highaddr); 263 if (newtag->boundary == 0) 264 newtag->boundary = parent->boundary; 265 else if (parent->boundary != 0) 266 newtag->boundary = MIN(parent->boundary, 267 newtag->boundary); | 208/* 209 * Allocate a device specific dma_tag. 210 */ 211int 212bus_dma_tag_create(bus_dma_tag_t parent, bus_size_t alignment, 213 bus_size_t boundary, bus_addr_t lowaddr, 214 bus_addr_t highaddr, bus_dma_filter_t *filter, 215 void *filterarg, bus_size_t maxsize, int nsegments, --- 45 unchanged lines hidden (view full) --- 261 if (parent != NULL) { 262 newtag->lowaddr = MIN(parent->lowaddr, newtag->lowaddr); 263 newtag->highaddr = MAX(parent->highaddr, newtag->highaddr); 264 if (newtag->boundary == 0) 265 newtag->boundary = parent->boundary; 266 else if (parent->boundary != 0) 267 newtag->boundary = MIN(parent->boundary, 268 newtag->boundary); |
269 if ((newtag->filter != NULL) || 270 ((parent->flags & BUS_DMA_USE_FILTER) != 0)) 271 newtag->flags |= BUS_DMA_USE_FILTER; |
|
268 if (newtag->filter == NULL) { 269 /* 270 * Short circuit looking at our parent directly 271 * since we have encapsulated all of its information 272 */ 273 newtag->filter = parent->filter; 274 newtag->filterarg = parent->filterarg; 275 newtag->parent = parent->parent; --- 272 unchanged lines hidden (view full) --- 548 dmat->lowaddr >= ptoa((vm_paddr_t)Maxmem)) 549 free(vaddr, M_DEVBUF); 550 else { 551 contigfree(vaddr, dmat->maxsize, M_DEVBUF); 552 } 553 CTR3(KTR_BUSDMA, "%s: tag %p flags 0x%x", __func__, dmat, dmat->flags); 554} 555 | 272 if (newtag->filter == NULL) { 273 /* 274 * Short circuit looking at our parent directly 275 * since we have encapsulated all of its information 276 */ 277 newtag->filter = parent->filter; 278 newtag->filterarg = parent->filterarg; 279 newtag->parent = parent->parent; --- 272 unchanged lines hidden (view full) --- 552 dmat->lowaddr >= ptoa((vm_paddr_t)Maxmem)) 553 free(vaddr, M_DEVBUF); 554 else { 555 contigfree(vaddr, dmat->maxsize, M_DEVBUF); 556 } 557 CTR3(KTR_BUSDMA, "%s: tag %p flags 0x%x", __func__, dmat, dmat->flags); 558} 559 |
556/* 557 * Utility function to load a linear buffer. lastaddrp holds state 558 * between invocations (for multiple-buffer loads). segp contains 559 * the starting segment on entrace, and the ending segment on exit. 560 * first indicates if this is the first invocation of this function. 561 */ 562static __inline int 563_bus_dmamap_load_buffer(bus_dma_tag_t dmat, 564 bus_dmamap_t map, 565 void *buf, bus_size_t buflen, 566 pmap_t pmap, 567 int flags, 568 bus_addr_t *lastaddrp, 569 bus_dma_segment_t *segs, 570 int *segp, 571 int first) | 560static int 561_bus_dmamap_count_pages(bus_dma_tag_t dmat, bus_dmamap_t map, void *buf, 562 bus_size_t buflen, int flags, int *nb) |
572{ | 563{ |
573 bus_size_t sgsize; 574 bus_addr_t curaddr, lastaddr, baddr, bmask; | |
575 vm_offset_t vaddr; | 564 vm_offset_t vaddr; |
565 vm_offset_t vendaddr; |
|
576 bus_addr_t paddr; | 566 bus_addr_t paddr; |
577 int needbounce = 0; 578 int seg; | 567 int needbounce = *nb; |
579 | 568 |
580 if (map == NULL) 581 map = &nobounce_dmamap; 582 583 if ((map != &nobounce_dmamap && map->pagesneeded == 0) 584 && ((dmat->flags & BUS_DMA_COULD_BOUNCE) != 0)) { 585 vm_offset_t vendaddr; 586 | 569 if ((map != &nobounce_dmamap && map->pagesneeded == 0)) { |
587 CTR4(KTR_BUSDMA, "lowaddr= %d Maxmem= %d, boundary= %d, " 588 "alignment= %d", dmat->lowaddr, ptoa((vm_paddr_t)Maxmem), 589 dmat->boundary, dmat->alignment); 590 CTR3(KTR_BUSDMA, "map= %p, nobouncemap= %p, pagesneeded= %d", 591 map, &nobounce_dmamap, map->pagesneeded); 592 /* 593 * Count the number of bounce pages 594 * needed in order to complete this transfer 595 */ 596 vaddr = trunc_page((vm_offset_t)buf); 597 vendaddr = (vm_offset_t)buf + buflen; 598 599 while (vaddr < vendaddr) { 600 paddr = pmap_kextract(vaddr); | 570 CTR4(KTR_BUSDMA, "lowaddr= %d Maxmem= %d, boundary= %d, " 571 "alignment= %d", dmat->lowaddr, ptoa((vm_paddr_t)Maxmem), 572 dmat->boundary, dmat->alignment); 573 CTR3(KTR_BUSDMA, "map= %p, nobouncemap= %p, pagesneeded= %d", 574 map, &nobounce_dmamap, map->pagesneeded); 575 /* 576 * Count the number of bounce pages 577 * needed in order to complete this transfer 578 */ 579 vaddr = trunc_page((vm_offset_t)buf); 580 vendaddr = (vm_offset_t)buf + buflen; 581 582 while (vaddr < vendaddr) { 583 paddr = pmap_kextract(vaddr); |
601 if (run_filter(dmat, paddr) != 0) { | 584 if (((dmat->flags & BUS_DMA_USE_FILTER) != 0) && 585 run_filter(dmat, paddr) != 0) { |
602 needbounce = 1; 603 map->pagesneeded++; 604 } 605 vaddr += PAGE_SIZE; 606 } 607 CTR1(KTR_BUSDMA, "pagesneeded= %d\n", map->pagesneeded); 608 } 609 --- 15 unchanged lines hidden (view full) --- 625 map, links); 626 mtx_unlock(&bounce_lock); 627 return (EINPROGRESS); 628 } 629 } 630 mtx_unlock(&bounce_lock); 631 } 632 | 586 needbounce = 1; 587 map->pagesneeded++; 588 } 589 vaddr += PAGE_SIZE; 590 } 591 CTR1(KTR_BUSDMA, "pagesneeded= %d\n", map->pagesneeded); 592 } 593 --- 15 unchanged lines hidden (view full) --- 609 map, links); 610 mtx_unlock(&bounce_lock); 611 return (EINPROGRESS); 612 } 613 } 614 mtx_unlock(&bounce_lock); 615 } 616 |
617 *nb = needbounce; 618 return (0); 619} 620 621/* 622 * Utility function to load a linear buffer. lastaddrp holds state 623 * between invocations (for multiple-buffer loads). segp contains 624 * the starting segment on entrace, and the ending segment on exit. 625 * first indicates if this is the first invocation of this function. 626 */ 627static __inline int 628_bus_dmamap_load_buffer(bus_dma_tag_t dmat, 629 bus_dmamap_t map, 630 void *buf, bus_size_t buflen, 631 pmap_t pmap, 632 int flags, 633 bus_addr_t *lastaddrp, 634 bus_dma_segment_t *segs, 635 int *segp, 636 int first) 637{ 638 bus_size_t sgsize; 639 bus_addr_t curaddr, lastaddr, baddr, bmask; 640 vm_offset_t vaddr; 641 int needbounce = 0; 642 int seg, error; 643 644 if (map == NULL) 645 map = &nobounce_dmamap; 646 647 if ((dmat->flags & BUS_DMA_COULD_BOUNCE) != 0) { 648 error = _bus_dmamap_count_pages(dmat, map, buf, buflen, flags, 649 &needbounce); 650 if (error) 651 return (error); 652 } 653 |
|
633 vaddr = (vm_offset_t)buf; 634 lastaddr = *lastaddrp; 635 bmask = ~(dmat->boundary - 1); 636 637 for (seg = *segp; buflen > 0 ; ) { 638 /* 639 * Get the physical address for this segment. 640 */ --- 13 unchanged lines hidden (view full) --- 654 * Make sure we don't cross any boundaries. 655 */ 656 if (dmat->boundary > 0) { 657 baddr = (curaddr + dmat->boundary) & bmask; 658 if (sgsize > (baddr - curaddr)) 659 sgsize = (baddr - curaddr); 660 } 661 | 654 vaddr = (vm_offset_t)buf; 655 lastaddr = *lastaddrp; 656 bmask = ~(dmat->boundary - 1); 657 658 for (seg = *segp; buflen > 0 ; ) { 659 /* 660 * Get the physical address for this segment. 661 */ --- 13 unchanged lines hidden (view full) --- 675 * Make sure we don't cross any boundaries. 676 */ 677 if (dmat->boundary > 0) { 678 baddr = (curaddr + dmat->boundary) & bmask; 679 if (sgsize > (baddr - curaddr)) 680 sgsize = (baddr - curaddr); 681 } 682 |
662 if (map->pagesneeded != 0 && run_filter(dmat, curaddr)) | 683 if (((dmat->flags & BUS_DMA_USE_FILTER) != 0) && 684 map->pagesneeded != 0 && run_filter(dmat, curaddr)) |
663 curaddr = add_bounce_page(dmat, map, vaddr, sgsize); 664 665 /* 666 * Insert chunk into a segment, coalescing with 667 * previous segment if possible. 668 */ 669 if (first) { 670 segs[seg].ds_addr = curaddr; --- 506 unchanged lines hidden --- | 685 curaddr = add_bounce_page(dmat, map, vaddr, sgsize); 686 687 /* 688 * Insert chunk into a segment, coalescing with 689 * previous segment if possible. 690 */ 691 if (first) { 692 segs[seg].ds_addr = curaddr; --- 506 unchanged lines hidden --- |