arm64 busdma: Fix loading of small bounced buffers.

- Don't oversize the buffer fragment. PAGE_SIZE - (curaddr & PAGE_MASK)
   may be greater than the total length of the buffer.
 - Don't use roundup2(len, alignment) to calculate the buffer fragment
   size. The length of current bounced fragment is not subject to alignment
   restriction, and next fragment should start at the page boundary.

Tested by:	bz, s199p.wa1k9r@gmail.com
This commit is contained in:
Michal Meloun 2021-01-13 13:50:54 +01:00
parent 24f44a445c
commit f635cef2a4

View File

@ -845,9 +845,7 @@ bounce_bus_dmamap_load_phys(bus_dma_tag_t dmat, bus_dmamap_t map,
KASSERT(dmat->common.alignment <= PAGE_SIZE, KASSERT(dmat->common.alignment <= PAGE_SIZE,
("bounced buffer cannot have alignment bigger " ("bounced buffer cannot have alignment bigger "
"than PAGE_SIZE: %lu", dmat->common.alignment)); "than PAGE_SIZE: %lu", dmat->common.alignment));
sgsize = PAGE_SIZE - (curaddr & PAGE_MASK); sgsize = MIN(sgsize, PAGE_SIZE - (curaddr & PAGE_MASK));
sgsize = roundup2(sgsize, dmat->common.alignment);
sgsize = MIN(sgsize, dmat->common.maxsegsz);
curaddr = add_bounce_page(dmat, map, 0, curaddr, curaddr = add_bounce_page(dmat, map, 0, curaddr,
sgsize); sgsize);
} else if ((map->flags & DMAMAP_COHERENT) == 0) { } else if ((map->flags & DMAMAP_COHERENT) == 0) {
@ -879,7 +877,11 @@ bounce_bus_dmamap_load_phys(bus_dma_tag_t dmat, bus_dmamap_t map,
/* /*
* Did we fit? * Did we fit?
*/ */
return (buflen != 0 ? EFBIG : 0); /* XXX better return value here? */ if (buflen != 0) {
bus_dmamap_unload(dmat, map);
return (EFBIG); /* XXX better return value here? */
}
return (0);
} }
/* /*
@ -892,7 +894,7 @@ bounce_bus_dmamap_load_buffer(bus_dma_tag_t dmat, bus_dmamap_t map, void *buf,
int *segp) int *segp)
{ {
struct sync_list *sl; struct sync_list *sl;
bus_size_t sgsize, max_sgsize; bus_size_t 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;
@ -931,7 +933,7 @@ bounce_bus_dmamap_load_buffer(bus_dma_tag_t dmat, bus_dmamap_t map, void *buf,
/* /*
* Get the physical address for this segment. * Get the physical address for this segment.
*/ */
if (pmap == kernel_pmap) { if (__predict_true(pmap == kernel_pmap)) {
curaddr = pmap_kextract(vaddr); curaddr = pmap_kextract(vaddr);
kvaddr = vaddr; kvaddr = vaddr;
} else { } else {
@ -942,13 +944,9 @@ bounce_bus_dmamap_load_buffer(bus_dma_tag_t dmat, bus_dmamap_t map, void *buf,
/* /*
* Compute the segment size, and adjust counts. * Compute the segment size, and adjust counts.
*/ */
max_sgsize = MIN(buflen, dmat->common.maxsegsz); sgsize = MIN(buflen, dmat->common.maxsegsz);
if ((map->flags & DMAMAP_FROM_DMAMEM) != 0) { if ((map->flags & DMAMAP_FROM_DMAMEM) == 0)
sgsize = max_sgsize; sgsize = MIN(sgsize, PAGE_SIZE - (curaddr & PAGE_MASK));
} else {
sgsize = PAGE_SIZE - (curaddr & PAGE_MASK);
sgsize = MIN(sgsize, max_sgsize);
}
if (map->pagesneeded != 0 && if (map->pagesneeded != 0 &&
must_bounce(dmat, map, curaddr, sgsize)) { must_bounce(dmat, map, curaddr, sgsize)) {
@ -956,9 +954,6 @@ bounce_bus_dmamap_load_buffer(bus_dma_tag_t dmat, bus_dmamap_t map, void *buf,
KASSERT(dmat->common.alignment <= PAGE_SIZE, KASSERT(dmat->common.alignment <= PAGE_SIZE,
("bounced buffer cannot have alignment bigger " ("bounced buffer cannot have alignment bigger "
"than PAGE_SIZE: %lu", dmat->common.alignment)); "than PAGE_SIZE: %lu", dmat->common.alignment));
sgsize = PAGE_SIZE - (curaddr & PAGE_MASK);
sgsize = roundup2(sgsize, dmat->common.alignment);
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 ((map->flags & DMAMAP_COHERENT) == 0) { } else if ((map->flags & DMAMAP_COHERENT) == 0) {
@ -999,7 +994,11 @@ bounce_bus_dmamap_load_buffer(bus_dma_tag_t dmat, bus_dmamap_t map, void *buf,
/* /*
* Did we fit? * Did we fit?
*/ */
return (buflen != 0 ? EFBIG : 0); /* XXX better return value here? */ if (buflen != 0) {
bus_dmamap_unload(dmat, map);
return (EFBIG); /* XXX better return value here? */
}
return (0);
} }
static void static void