diff --git a/sys/dev/buslogic/bt_isa.c b/sys/dev/buslogic/bt_isa.c index ce121c3..3ce1f7b 100644 --- a/sys/dev/buslogic/bt_isa.c +++ b/sys/dev/buslogic/bt_isa.c @@ -312,7 +312,7 @@ bt_isa_attach(device_t dev) #define BIOS_MAP_SIZE (16 * 1024) static int -btvlbouncefilter(void *arg, bus_addr_t addr) +btvlbouncefilter(void *arg, bus_addr_t addr, int flags) { struct bt_softc *bt; diff --git a/sys/sys/bus_dma.h b/sys/sys/bus_dma.h index 4ea5b08..756570e 100644 --- a/sys/sys/bus_dma.h +++ b/sys/sys/bus_dma.h @@ -133,9 +133,13 @@ typedef struct bus_dma_segment { /* * A function that returns 1 if the address cannot be accessed by - * a device and 0 if it can be. + * a device and 0 if it can be. The last parameter is a flag containing + * additional info about the segment. + * */ -typedef int bus_dma_filter_t(void *, bus_addr_t); +#define BUS_DMAFILTER_FIRST_SEG (1 << 0) +#define BUS_DMAFILTER_LAST_SEG (1 << 1) +typedef int bus_dma_filter_t(void *, bus_addr_t, int); /* * Generic helper function for manipulating mutexes. diff --git a/sys/x86/include/busdma_impl.h b/sys/x86/include/busdma_impl.h index b851e7a..c81cddd 100644 --- a/sys/x86/include/busdma_impl.h +++ b/sys/x86/include/busdma_impl.h @@ -83,7 +83,8 @@ struct bus_dma_impl { }; void bus_dma_dflt_lock(void *arg, bus_dma_lock_op_t op); -int bus_dma_run_filter(struct bus_dma_tag_common *dmat, bus_addr_t paddr); +int bus_dma_run_filter(struct bus_dma_tag_common *dmat, bus_addr_t paddr, + int flags); int common_bus_dma_tag_create(struct bus_dma_tag_common *parent, bus_size_t alignment, bus_addr_t boundary, bus_addr_t lowaddr, bus_addr_t highaddr, diff --git a/sys/x86/x86/busdma_bounce.c b/sys/x86/x86/busdma_bounce.c index 1438053..c4032ec 100644 --- a/sys/x86/x86/busdma_bounce.c +++ b/sys/x86/x86/busdma_bounce.c @@ -470,6 +470,7 @@ _bus_dmamap_count_phys(bus_dma_tag_t dmat, bus_dmamap_t map, vm_paddr_t buf, { bus_addr_t curaddr; bus_size_t sgsize; + int fflags; if ((map != &nobounce_dmamap && map->pagesneeded == 0)) { /* @@ -479,7 +480,14 @@ _bus_dmamap_count_phys(bus_dma_tag_t dmat, bus_dmamap_t map, vm_paddr_t buf, curaddr = buf; while (buflen != 0) { sgsize = MIN(buflen, dmat->common.maxsegsz); - if (bus_dma_run_filter(&dmat->common, curaddr)) { + if (curaddr == buf) + fflags = BUS_DMAFILTER_FIRST_SEG; + else if (buflen - sgsize == 0) + fflags = BUS_DMAFILTER_LAST_SEG; + else + fflags = 0; + if (bus_dma_run_filter(&dmat->common, curaddr, + fflags)) { sgsize = MIN(sgsize, PAGE_SIZE); map->pagesneeded++; } @@ -498,6 +506,7 @@ _bus_dmamap_count_pages(bus_dma_tag_t dmat, bus_dmamap_t map, pmap_t pmap, vm_offset_t vendaddr; bus_addr_t paddr; bus_size_t sg_len; + int fflags; if ((map != &nobounce_dmamap && map->pagesneeded == 0)) { CTR4(KTR_BUSDMA, "lowaddr= %d Maxmem= %d, boundary= %d, " @@ -515,11 +524,18 @@ _bus_dmamap_count_pages(bus_dma_tag_t dmat, bus_dmamap_t map, pmap_t pmap, while (vaddr < vendaddr) { sg_len = PAGE_SIZE - ((vm_offset_t)vaddr & PAGE_MASK); + if (vaddr == (vm_offset_t)buf) + fflags = BUS_DMAFILTER_FIRST_SEG; + else if ((vaddr + sg_len) >= vendaddr) + fflags = BUS_DMAFILTER_LAST_SEG; + else + fflags = 0; if (pmap == kernel_pmap) paddr = pmap_kextract(vaddr); else paddr = pmap_extract(pmap, vaddr); - if (bus_dma_run_filter(&dmat->common, paddr) != 0) { + if (bus_dma_run_filter(&dmat->common, paddr, fflags) + != 0) { sg_len = roundup2(sg_len, dmat->common.alignment); map->pagesneeded++; @@ -611,7 +627,7 @@ bounce_bus_dmamap_load_phys(bus_dma_tag_t dmat, bus_dmamap_t map, { bus_size_t sgsize; bus_addr_t curaddr; - int error; + int error, fflags, seg; if (map == NULL) map = &nobounce_dmamap; @@ -628,12 +644,19 @@ bounce_bus_dmamap_load_phys(bus_dma_tag_t dmat, bus_dmamap_t map, } } + seg = 0; while (buflen > 0) { curaddr = buf; sgsize = MIN(buflen, dmat->common.maxsegsz); + if (seg == 0) + fflags = BUS_DMAFILTER_FIRST_SEG; + else if (buflen - sgsize == 0) + fflags = BUS_DMAFILTER_LAST_SEG; + else + fflags = 0; if (((dmat->bounce_flags & BUS_DMA_COULD_BOUNCE) != 0) && map->pagesneeded != 0 && - bus_dma_run_filter(&dmat->common, curaddr)) { + bus_dma_run_filter(&dmat->common, curaddr, fflags)) { sgsize = MIN(sgsize, PAGE_SIZE); curaddr = add_bounce_page(dmat, map, 0, curaddr, sgsize); @@ -644,6 +667,7 @@ bounce_bus_dmamap_load_phys(bus_dma_tag_t dmat, bus_dmamap_t map, break; buf += sgsize; buflen -= sgsize; + seg++; } /* @@ -664,7 +688,7 @@ bounce_bus_dmamap_load_buffer(bus_dma_tag_t dmat, bus_dmamap_t map, void *buf, bus_size_t sgsize, max_sgsize; bus_addr_t curaddr; vm_offset_t vaddr; - int error; + int error, fflags; if (map == NULL) map = &nobounce_dmamap; @@ -696,9 +720,15 @@ bounce_bus_dmamap_load_buffer(bus_dma_tag_t dmat, bus_dmamap_t map, void *buf, */ max_sgsize = MIN(buflen, dmat->common.maxsegsz); sgsize = PAGE_SIZE - ((vm_offset_t)curaddr & PAGE_MASK); + if (vaddr == (vm_offset_t)buf) + fflags = BUS_DMAFILTER_FIRST_SEG; + else if (buflen - MIN(sgsize, max_sgsize) == 0) + fflags = BUS_DMAFILTER_LAST_SEG; + else + fflags = 0; if (((dmat->bounce_flags & BUS_DMA_COULD_BOUNCE) != 0) && map->pagesneeded != 0 && - bus_dma_run_filter(&dmat->common, curaddr)) { + bus_dma_run_filter(&dmat->common, curaddr, fflags)) { sgsize = roundup2(sgsize, dmat->common.alignment); sgsize = MIN(sgsize, max_sgsize); curaddr = add_bounce_page(dmat, map, vaddr, curaddr, diff --git a/sys/x86/x86/busdma_machdep.c b/sys/x86/x86/busdma_machdep.c index c96b26d..6dbd966 100644 --- a/sys/x86/x86/busdma_machdep.c +++ b/sys/x86/x86/busdma_machdep.c @@ -93,7 +93,7 @@ bus_dma_dflt_lock(void *arg, bus_dma_lock_op_t op) * to check for a match, if there is no filter callback then assume a match. */ int -bus_dma_run_filter(struct bus_dma_tag_common *tc, bus_addr_t paddr) +bus_dma_run_filter(struct bus_dma_tag_common *tc, bus_addr_t paddr, int flags) { int retval; @@ -102,7 +102,7 @@ bus_dma_run_filter(struct bus_dma_tag_common *tc, bus_addr_t paddr) if (((paddr > tc->lowaddr && paddr <= tc->highaddr) || ((paddr & (tc->alignment - 1)) != 0)) && (tc->filter == NULL || - (*tc->filter)(tc->filterarg, paddr) != 0)) + (*tc->filter)(tc->filterarg, paddr, flags) != 0)) retval = 1; tc = tc->parent;