Deleted Added
full compact
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 ---