Changeset View
Changeset View
Standalone View
Standalone View
sys/x86/x86/busdma_bounce.c
Show First 20 Lines • Show All 460 Lines • ▼ Show 20 Lines | |||||
} | } | ||||
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) | ||||
{ | { | ||||
bus_addr_t curaddr; | bus_addr_t curaddr; | ||||
bus_size_t sgsize; | bus_size_t sgsize; | ||||
bus_size_t len; | |||||
bool bounce; | |||||
if ((map != &nobounce_dmamap && map->pagesneeded == 0)) { | if ((map != &nobounce_dmamap && map->pagesneeded == 0)) { | ||||
/* | /* | ||||
* 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 | ||||
*/ | */ | ||||
bounce = FALSE; | |||||
again: | |||||
curaddr = buf; | curaddr = buf; | ||||
while (buflen != 0) { | len = buflen; | ||||
sgsize = MIN(buflen, dmat->common.maxsegsz); | while (len != 0) { | ||||
if (bus_dma_run_filter(&dmat->common, curaddr)) { | sgsize = MIN(len, dmat->common.maxsegsz); | ||||
if (bounce || | |||||
bus_dma_run_filter(&dmat->common, curaddr)) { | |||||
if (!bounce) { | |||||
bounce = TRUE; | |||||
goto again; | |||||
} | |||||
sgsize = MIN(PAGE_SIZE, sgsize); | sgsize = MIN(PAGE_SIZE, sgsize); | ||||
map->pagesneeded++; | map->pagesneeded++; | ||||
} | } | ||||
curaddr += sgsize; | curaddr += sgsize; | ||||
buflen -= sgsize; | len -= sgsize; | ||||
} | } | ||||
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; | ||||
bool bounce; | |||||
if ((map != &nobounce_dmamap && map->pagesneeded == 0)) { | if ((map != &nobounce_dmamap && 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); | ||||
CTR3(KTR_BUSDMA, "map= %p, nobouncemap= %p, pagesneeded= %d", | CTR3(KTR_BUSDMA, "map= %p, nobouncemap= %p, pagesneeded= %d", | ||||
map, &nobounce_dmamap, map->pagesneeded); | map, &nobounce_dmamap, 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 | ||||
*/ | */ | ||||
bounce = FALSE; | |||||
again: | |||||
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 (bounce || | ||||
bus_dma_run_filter(&dmat->common, paddr) != 0) { | |||||
if (!bounce) { | |||||
bounce = TRUE; | |||||
goto again; | |||||
} | |||||
sg_len = PAGE_SIZE; | sg_len = PAGE_SIZE; | ||||
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); | ||||
} | } | ||||
} | } | ||||
static void | static void | ||||
_bus_dmamap_count_ma(bus_dma_tag_t dmat, bus_dmamap_t map, struct vm_page **ma, | _bus_dmamap_count_ma(bus_dma_tag_t dmat, bus_dmamap_t map, struct vm_page **ma, | ||||
int ma_offs, bus_size_t buflen, int flags) | int ma_offs, bus_size_t buflen, int flags) | ||||
{ | { | ||||
bus_size_t sg_len, max_sgsize; | bus_size_t sg_len, max_sgsize, len; | ||||
int page_index; | int page_index; | ||||
vm_paddr_t paddr; | vm_paddr_t paddr; | ||||
bool bounce; | |||||
if ((map != &nobounce_dmamap && map->pagesneeded == 0)) { | if ((map != &nobounce_dmamap && 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); | ||||
CTR3(KTR_BUSDMA, "map= %p, nobouncemap= %p, pagesneeded= %d", | CTR3(KTR_BUSDMA, "map= %p, nobouncemap= %p, pagesneeded= %d", | ||||
map, &nobounce_dmamap, map->pagesneeded); | map, &nobounce_dmamap, 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 | ||||
*/ | */ | ||||
bounce = FALSE; | |||||
again: | |||||
len = buflen; | |||||
page_index = 0; | page_index = 0; | ||||
while (buflen > 0) { | while (len > 0) { | ||||
paddr = VM_PAGE_TO_PHYS(ma[page_index]) + ma_offs; | paddr = VM_PAGE_TO_PHYS(ma[page_index]) + ma_offs; | ||||
sg_len = PAGE_SIZE - ma_offs; | sg_len = PAGE_SIZE - ma_offs; | ||||
max_sgsize = MIN(buflen, dmat->common.maxsegsz); | max_sgsize = MIN(len, dmat->common.maxsegsz); | ||||
sg_len = MIN(sg_len, max_sgsize); | sg_len = MIN(sg_len, max_sgsize); | ||||
if (bus_dma_run_filter(&dmat->common, paddr) != 0) { | if (bounce || | ||||
bus_dma_run_filter(&dmat->common, paddr) != 0) { | |||||
if (!bounce) { | |||||
bounce = TRUE; | |||||
goto again; | |||||
} | |||||
sg_len = MIN(PAGE_SIZE, max_sgsize); | sg_len = MIN(PAGE_SIZE, max_sgsize); | ||||
KASSERT((sg_len & (dmat->common.alignment - 1)) | KASSERT((sg_len & (dmat->common.alignment - 1)) | ||||
== 0, ("Segment size is not aligned")); | == 0, ("Segment size is not aligned")); | ||||
map->pagesneeded++; | map->pagesneeded++; | ||||
} | } | ||||
if (((ma_offs + sg_len) & ~PAGE_MASK) != 0) | if (((ma_offs + sg_len) & ~PAGE_MASK) != 0) | ||||
page_index++; | page_index++; | ||||
ma_offs = (ma_offs + sg_len) & PAGE_MASK; | ma_offs = (ma_offs + sg_len) & PAGE_MASK; | ||||
KASSERT(buflen >= sg_len, | KASSERT(len >= sg_len, | ||||
("Segment length overruns original buffer")); | ("Segment length overruns original buffer")); | ||||
buflen -= sg_len; | len -= sg_len; | ||||
} | } | ||||
CTR1(KTR_BUSDMA, "pagesneeded= %d\n", map->pagesneeded); | CTR1(KTR_BUSDMA, "pagesneeded= %d\n", map->pagesneeded); | ||||
} | } | ||||
} | } | ||||
static int | static int | ||||
_bus_dmamap_reserve_pages(bus_dma_tag_t dmat, bus_dmamap_t map, int flags) | _bus_dmamap_reserve_pages(bus_dma_tag_t dmat, bus_dmamap_t map, int flags) | ||||
{ | { | ||||
▲ Show 20 Lines • Show All 91 Lines • ▼ Show 20 Lines | if (map->pagesneeded != 0) { | ||||
return (error); | return (error); | ||||
} | } | ||||
} | } | ||||
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 & BUS_DMA_COULD_BOUNCE) != 0) && | if (((dmat->bounce_flags & BUS_DMA_COULD_BOUNCE) != 0) && | ||||
map->pagesneeded != 0 && | map->pagesneeded != 0) { | ||||
bus_dma_run_filter(&dmat->common, curaddr)) { | |||||
nextaddr = 0; | nextaddr = 0; | ||||
sgsize = MIN(PAGE_SIZE, sgsize); | sgsize = MIN(PAGE_SIZE, sgsize); | ||||
if ((curaddr & PAGE_MASK) + sgsize > PAGE_SIZE) | if ((curaddr & PAGE_MASK) + sgsize > PAGE_SIZE) | ||||
nextaddr = roundup2(curaddr, PAGE_SIZE); | nextaddr = roundup2(curaddr, PAGE_SIZE); | ||||
curaddr = add_bounce_page(dmat, map, 0, curaddr, | curaddr = add_bounce_page(dmat, map, 0, curaddr, | ||||
nextaddr, sgsize); | nextaddr, sgsize); | ||||
} | } | ||||
sgsize = _bus_dmamap_addseg(dmat, map, curaddr, sgsize, segs, | sgsize = _bus_dmamap_addseg(dmat, map, curaddr, sgsize, segs, | ||||
▲ Show 20 Lines • Show All 53 Lines • ▼ Show 20 Lines | while (buflen > 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 & BUS_DMA_COULD_BOUNCE) != 0) && | if (((dmat->bounce_flags & BUS_DMA_COULD_BOUNCE) != 0) && | ||||
map->pagesneeded != 0 && | map->pagesneeded != 0) { | ||||
bus_dma_run_filter(&dmat->common, curaddr)) { | |||||
sgsize = MIN(PAGE_SIZE, max_sgsize); | sgsize = MIN(PAGE_SIZE, max_sgsize); | ||||
curaddr = add_bounce_page(dmat, map, kvaddr, curaddr, 0, | curaddr = add_bounce_page(dmat, map, kvaddr, curaddr, 0, | ||||
sgsize); | sgsize); | ||||
} else { | } else { | ||||
sgsize = MIN(sgsize, max_sgsize); | sgsize = MIN(sgsize, max_sgsize); | ||||
} | } | ||||
sgsize = _bus_dmamap_addseg(dmat, map, curaddr, sgsize, segs, | sgsize = _bus_dmamap_addseg(dmat, map, curaddr, sgsize, segs, | ||||
segp); | segp); | ||||
Show All 37 Lines | bounce_bus_dmamap_load_ma(bus_dma_tag_t dmat, bus_dmamap_t map, | ||||
while (buflen > 0) { | while (buflen > 0) { | ||||
/* | /* | ||||
* Compute the segment size, and adjust counts. | * Compute the segment size, and adjust counts. | ||||
*/ | */ | ||||
paddr = VM_PAGE_TO_PHYS(ma[page_index]) + ma_offs; | paddr = VM_PAGE_TO_PHYS(ma[page_index]) + ma_offs; | ||||
max_sgsize = MIN(buflen, dmat->common.maxsegsz); | max_sgsize = MIN(buflen, dmat->common.maxsegsz); | ||||
sgsize = PAGE_SIZE - ma_offs; | sgsize = PAGE_SIZE - ma_offs; | ||||
if (((dmat->bounce_flags & BUS_DMA_COULD_BOUNCE) != 0) && | if (((dmat->bounce_flags & BUS_DMA_COULD_BOUNCE) != 0) && | ||||
map->pagesneeded != 0 && | map->pagesneeded != 0) { | ||||
bus_dma_run_filter(&dmat->common, paddr)) { | |||||
sgsize = MIN(PAGE_SIZE, max_sgsize); | sgsize = MIN(PAGE_SIZE, max_sgsize); | ||||
/* | /* | ||||
* Check if two pages of the user provided buffer | * Check if two pages of the user provided buffer | ||||
* are used. | * are used. | ||||
*/ | */ | ||||
if ((ma_offs + sgsize) > PAGE_SIZE) | if ((ma_offs + sgsize) > PAGE_SIZE) | ||||
next_paddr = | next_paddr = | ||||
VM_PAGE_TO_PHYS(ma[page_index + 1]); | VM_PAGE_TO_PHYS(ma[page_index + 1]); | ||||
▲ Show 20 Lines • Show All 426 Lines • Show Last 20 Lines |