Changeset View
Changeset View
Standalone View
Standalone View
head/sys/arm64/arm64/busdma_bounce.c
Show First 20 Lines • Show All 156 Lines • ▼ Show 20 Lines | static bool _bus_dmamap_pagesneeded(bus_dma_tag_t dmat, vm_paddr_t buf, | ||||
bus_size_t buflen, int *pagesneeded); | bus_size_t buflen, int *pagesneeded); | ||||
static void _bus_dmamap_count_pages(bus_dma_tag_t dmat, bus_dmamap_t map, | static void _bus_dmamap_count_pages(bus_dma_tag_t dmat, bus_dmamap_t map, | ||||
pmap_t pmap, void *buf, bus_size_t buflen, int flags); | pmap_t pmap, void *buf, bus_size_t buflen, int flags); | ||||
static void _bus_dmamap_count_phys(bus_dma_tag_t dmat, bus_dmamap_t map, | static void _bus_dmamap_count_phys(bus_dma_tag_t dmat, bus_dmamap_t map, | ||||
vm_paddr_t buf, bus_size_t buflen, int flags); | vm_paddr_t buf, bus_size_t buflen, int flags); | ||||
static int _bus_dmamap_reserve_pages(bus_dma_tag_t dmat, bus_dmamap_t map, | static int _bus_dmamap_reserve_pages(bus_dma_tag_t dmat, bus_dmamap_t map, | ||||
int flags); | int flags); | ||||
static bool | |||||
might_bounce(bus_dma_tag_t dmat) | |||||
{ | |||||
if ((dmat->bounce_flags & BF_COULD_BOUNCE) != 0) | |||||
return (true); | |||||
return (false); | |||||
} | |||||
static bool | |||||
must_bounce(bus_dma_tag_t dmat, bus_addr_t paddr) | |||||
{ | |||||
if ((dmat->bounce_flags & BF_COULD_BOUNCE) != 0 && | |||||
bus_dma_run_filter(&dmat->common, paddr)) | |||||
return (true); | |||||
return (false); | |||||
} | |||||
/* | /* | ||||
* Allocate a device specific dma_tag. | * Allocate a device specific dma_tag. | ||||
*/ | */ | ||||
static int | static int | ||||
bounce_bus_dma_tag_create(bus_dma_tag_t parent, bus_size_t alignment, | bounce_bus_dma_tag_create(bus_dma_tag_t parent, bus_size_t alignment, | ||||
bus_addr_t boundary, bus_addr_t lowaddr, bus_addr_t highaddr, | bus_addr_t boundary, bus_addr_t lowaddr, bus_addr_t highaddr, | ||||
bus_dma_filter_t *filter, void *filterarg, bus_size_t maxsize, | bus_dma_filter_t *filter, void *filterarg, bus_size_t maxsize, | ||||
int nsegments, bus_size_t maxsegsz, int flags, bus_dma_lock_t *lockfunc, | int nsegments, bus_size_t maxsegsz, int flags, bus_dma_lock_t *lockfunc, | ||||
▲ Show 20 Lines • Show All 100 Lines • ▼ Show 20 Lines | out: | ||||
CTR3(KTR_BUSDMA, "%s tag %p error %d", __func__, dmat_copy, error); | CTR3(KTR_BUSDMA, "%s tag %p error %d", __func__, dmat_copy, error); | ||||
return (error); | return (error); | ||||
} | } | ||||
static bool | static bool | ||||
bounce_bus_dma_id_mapped(bus_dma_tag_t dmat, vm_paddr_t buf, bus_size_t buflen) | bounce_bus_dma_id_mapped(bus_dma_tag_t dmat, vm_paddr_t buf, bus_size_t buflen) | ||||
{ | { | ||||
if ((dmat->bounce_flags & BF_COULD_BOUNCE) == 0) | if (!might_bounce(dmat)) | ||||
return (true); | return (true); | ||||
return (!_bus_dmamap_pagesneeded(dmat, buf, buflen, NULL)); | return (!_bus_dmamap_pagesneeded(dmat, buf, buflen, NULL)); | ||||
} | } | ||||
static bus_dmamap_t | static bus_dmamap_t | ||||
alloc_dmamap(bus_dma_tag_t dmat, int flags) | alloc_dmamap(bus_dma_tag_t dmat, int flags) | ||||
{ | { | ||||
u_long mapsize; | u_long mapsize; | ||||
▲ Show 20 Lines • Show All 271 Lines • ▼ Show 20 Lines | _bus_dmamap_pagesneeded(bus_dma_tag_t dmat, vm_paddr_t buf, bus_size_t buflen, | ||||
/* | /* | ||||
* Count the number of bounce pages needed in order to | * Count the number of bounce pages needed in order to | ||||
* complete this transfer | * complete this transfer | ||||
*/ | */ | ||||
count = 0; | count = 0; | ||||
curaddr = buf; | curaddr = buf; | ||||
while (buflen != 0) { | while (buflen != 0) { | ||||
sgsize = MIN(buflen, dmat->common.maxsegsz); | sgsize = MIN(buflen, dmat->common.maxsegsz); | ||||
if (bus_dma_run_filter(&dmat->common, curaddr)) { | if (must_bounce(dmat, curaddr)) { | ||||
sgsize = MIN(sgsize, | sgsize = MIN(sgsize, | ||||
PAGE_SIZE - (curaddr & PAGE_MASK)); | PAGE_SIZE - (curaddr & PAGE_MASK)); | ||||
if (pagesneeded == NULL) | if (pagesneeded == NULL) | ||||
return (true); | return (true); | ||||
count++; | count++; | ||||
} | } | ||||
curaddr += sgsize; | curaddr += sgsize; | ||||
buflen -= sgsize; | buflen -= sgsize; | ||||
} | } | ||||
if (pagesneeded != NULL) | if (pagesneeded != NULL) | ||||
*pagesneeded = count; | *pagesneeded = count; | ||||
return (count != 0); | return (count != 0); | ||||
} | } | ||||
static void | static void | ||||
_bus_dmamap_count_phys(bus_dma_tag_t dmat, bus_dmamap_t map, vm_paddr_t buf, | _bus_dmamap_count_phys(bus_dma_tag_t dmat, bus_dmamap_t map, vm_paddr_t buf, | ||||
bus_size_t buflen, int flags) | bus_size_t buflen, int flags) | ||||
{ | { | ||||
if ((map->flags & DMAMAP_COULD_BOUNCE) != 0 && map->pagesneeded == 0) { | if (map->pagesneeded == 0) { | ||||
_bus_dmamap_pagesneeded(dmat, buf, buflen, &map->pagesneeded); | _bus_dmamap_pagesneeded(dmat, buf, buflen, &map->pagesneeded); | ||||
CTR1(KTR_BUSDMA, "pagesneeded= %d\n", map->pagesneeded); | CTR1(KTR_BUSDMA, "pagesneeded= %d\n", map->pagesneeded); | ||||
} | } | ||||
} | } | ||||
static void | static void | ||||
_bus_dmamap_count_pages(bus_dma_tag_t dmat, bus_dmamap_t map, pmap_t pmap, | _bus_dmamap_count_pages(bus_dma_tag_t dmat, bus_dmamap_t map, pmap_t pmap, | ||||
void *buf, bus_size_t buflen, int flags) | void *buf, bus_size_t buflen, int flags) | ||||
{ | { | ||||
vm_offset_t vaddr; | vm_offset_t vaddr; | ||||
vm_offset_t vendaddr; | vm_offset_t vendaddr; | ||||
bus_addr_t paddr; | bus_addr_t paddr; | ||||
bus_size_t sg_len; | bus_size_t sg_len; | ||||
if ((map->flags & DMAMAP_COULD_BOUNCE) != 0 && map->pagesneeded == 0) { | if (map->pagesneeded == 0) { | ||||
CTR4(KTR_BUSDMA, "lowaddr= %d Maxmem= %d, boundary= %d, " | CTR4(KTR_BUSDMA, "lowaddr= %d Maxmem= %d, boundary= %d, " | ||||
"alignment= %d", dmat->common.lowaddr, | "alignment= %d", dmat->common.lowaddr, | ||||
ptoa((vm_paddr_t)Maxmem), | ptoa((vm_paddr_t)Maxmem), | ||||
dmat->common.boundary, dmat->common.alignment); | dmat->common.boundary, dmat->common.alignment); | ||||
CTR2(KTR_BUSDMA, "map= %p, pagesneeded= %d", map, | CTR2(KTR_BUSDMA, "map= %p, pagesneeded= %d", map, | ||||
map->pagesneeded); | map->pagesneeded); | ||||
/* | /* | ||||
* Count the number of bounce pages | * Count the number of bounce pages | ||||
* needed in order to complete this transfer | * needed in order to complete this transfer | ||||
*/ | */ | ||||
vaddr = (vm_offset_t)buf; | vaddr = (vm_offset_t)buf; | ||||
vendaddr = (vm_offset_t)buf + buflen; | vendaddr = (vm_offset_t)buf + buflen; | ||||
while (vaddr < vendaddr) { | while (vaddr < vendaddr) { | ||||
sg_len = PAGE_SIZE - ((vm_offset_t)vaddr & PAGE_MASK); | sg_len = PAGE_SIZE - ((vm_offset_t)vaddr & PAGE_MASK); | ||||
if (pmap == kernel_pmap) | if (pmap == kernel_pmap) | ||||
paddr = pmap_kextract(vaddr); | paddr = pmap_kextract(vaddr); | ||||
else | else | ||||
paddr = pmap_extract(pmap, vaddr); | paddr = pmap_extract(pmap, vaddr); | ||||
if (bus_dma_run_filter(&dmat->common, paddr) != 0) { | if (must_bounce(dmat, paddr)) { | ||||
sg_len = roundup2(sg_len, | sg_len = roundup2(sg_len, | ||||
dmat->common.alignment); | dmat->common.alignment); | ||||
map->pagesneeded++; | map->pagesneeded++; | ||||
} | } | ||||
vaddr += sg_len; | vaddr += sg_len; | ||||
} | } | ||||
CTR1(KTR_BUSDMA, "pagesneeded= %d\n", map->pagesneeded); | CTR1(KTR_BUSDMA, "pagesneeded= %d\n", map->pagesneeded); | ||||
} | } | ||||
▲ Show 20 Lines • Show All 81 Lines • ▼ Show 20 Lines | bounce_bus_dmamap_load_phys(bus_dma_tag_t dmat, bus_dmamap_t map, | ||||
struct sync_list *sl; | struct sync_list *sl; | ||||
bus_size_t sgsize; | bus_size_t sgsize; | ||||
bus_addr_t curaddr, sl_end; | bus_addr_t curaddr, sl_end; | ||||
int error; | int error; | ||||
if (segs == NULL) | if (segs == NULL) | ||||
segs = dmat->segments; | segs = dmat->segments; | ||||
if ((dmat->bounce_flags & BF_COULD_BOUNCE) != 0) { | if (might_bounce(dmat)) { | ||||
_bus_dmamap_count_phys(dmat, map, buf, buflen, flags); | _bus_dmamap_count_phys(dmat, map, buf, buflen, flags); | ||||
if (map->pagesneeded != 0) { | if (map->pagesneeded != 0) { | ||||
error = _bus_dmamap_reserve_pages(dmat, map, flags); | error = _bus_dmamap_reserve_pages(dmat, map, flags); | ||||
if (error) | if (error) | ||||
return (error); | return (error); | ||||
} | } | ||||
} | } | ||||
sl = map->slist + map->sync_count - 1; | sl = map->slist + map->sync_count - 1; | ||||
sl_end = 0; | sl_end = 0; | ||||
while (buflen > 0) { | while (buflen > 0) { | ||||
curaddr = buf; | curaddr = buf; | ||||
sgsize = MIN(buflen, dmat->common.maxsegsz); | sgsize = MIN(buflen, dmat->common.maxsegsz); | ||||
if (((dmat->bounce_flags & BF_COULD_BOUNCE) != 0) && | if (map->pagesneeded != 0 && must_bounce(dmat, curaddr)) { | ||||
map->pagesneeded != 0 && | |||||
bus_dma_run_filter(&dmat->common, curaddr)) { | |||||
sgsize = MIN(sgsize, PAGE_SIZE - (curaddr & PAGE_MASK)); | sgsize = MIN(sgsize, PAGE_SIZE - (curaddr & PAGE_MASK)); | ||||
curaddr = add_bounce_page(dmat, map, 0, curaddr, | curaddr = add_bounce_page(dmat, map, 0, curaddr, | ||||
sgsize); | sgsize); | ||||
} else if ((dmat->bounce_flags & BF_COHERENT) == 0) { | } else if ((dmat->bounce_flags & BF_COHERENT) == 0) { | ||||
if (map->sync_count > 0) | if (map->sync_count > 0) | ||||
sl_end = sl->paddr + sl->datacount; | sl_end = sl->paddr + sl->datacount; | ||||
if (map->sync_count == 0 || curaddr != sl_end) { | if (map->sync_count == 0 || curaddr != sl_end) { | ||||
Show All 37 Lines | bounce_bus_dmamap_load_buffer(bus_dma_tag_t dmat, bus_dmamap_t map, void *buf, | ||||
bus_size_t sgsize, max_sgsize; | bus_size_t sgsize, max_sgsize; | ||||
bus_addr_t curaddr, sl_pend; | bus_addr_t curaddr, sl_pend; | ||||
vm_offset_t kvaddr, vaddr, sl_vend; | vm_offset_t kvaddr, vaddr, sl_vend; | ||||
int error; | int error; | ||||
if (segs == NULL) | if (segs == NULL) | ||||
segs = dmat->segments; | segs = dmat->segments; | ||||
if ((dmat->bounce_flags & BF_COULD_BOUNCE) != 0) { | if (might_bounce(dmat)) { | ||||
_bus_dmamap_count_pages(dmat, map, pmap, buf, buflen, flags); | _bus_dmamap_count_pages(dmat, map, pmap, buf, buflen, flags); | ||||
if (map->pagesneeded != 0) { | if (map->pagesneeded != 0) { | ||||
error = _bus_dmamap_reserve_pages(dmat, map, flags); | error = _bus_dmamap_reserve_pages(dmat, map, flags); | ||||
if (error) | if (error) | ||||
return (error); | return (error); | ||||
} | } | ||||
} | } | ||||
Show All 14 Lines | if (pmap == kernel_pmap) { | ||||
kvaddr = 0; | kvaddr = 0; | ||||
} | } | ||||
/* | /* | ||||
* Compute the segment size, and adjust counts. | * Compute the segment size, and adjust counts. | ||||
*/ | */ | ||||
max_sgsize = MIN(buflen, dmat->common.maxsegsz); | max_sgsize = MIN(buflen, dmat->common.maxsegsz); | ||||
sgsize = PAGE_SIZE - (curaddr & PAGE_MASK); | sgsize = PAGE_SIZE - (curaddr & PAGE_MASK); | ||||
if (((dmat->bounce_flags & BF_COULD_BOUNCE) != 0) && | if (map->pagesneeded != 0 && must_bounce(dmat, curaddr)) { | ||||
map->pagesneeded != 0 && | |||||
bus_dma_run_filter(&dmat->common, curaddr)) { | |||||
sgsize = roundup2(sgsize, dmat->common.alignment); | sgsize = roundup2(sgsize, dmat->common.alignment); | ||||
sgsize = MIN(sgsize, max_sgsize); | sgsize = MIN(sgsize, max_sgsize); | ||||
curaddr = add_bounce_page(dmat, map, kvaddr, curaddr, | curaddr = add_bounce_page(dmat, map, kvaddr, curaddr, | ||||
sgsize); | sgsize); | ||||
} else if ((dmat->bounce_flags & BF_COHERENT) == 0) { | } else if ((dmat->bounce_flags & BF_COHERENT) == 0) { | ||||
sgsize = MIN(sgsize, max_sgsize); | sgsize = MIN(sgsize, max_sgsize); | ||||
if (map->sync_count > 0) { | if (map->sync_count > 0) { | ||||
sl_pend = sl->paddr + sl->datacount; | sl_pend = sl->paddr + sl->datacount; | ||||
▲ Show 20 Lines • Show All 522 Lines • Show Last 20 Lines |