diff options
author | gonzo <gonzo@FreeBSD.org> | 2015-10-30 01:19:04 +0000 |
---|---|---|
committer | gonzo <gonzo@FreeBSD.org> | 2015-10-30 01:19:04 +0000 |
commit | b222411003070166177496fcfaf0912788321404 (patch) | |
tree | cb2e0673133fb9bc70b03525b4adfafd8d3d93c2 /sys/contrib | |
parent | 949e84b266cc7b3ae7f1c83e09223981fe6a0f0b (diff) | |
download | FreeBSD-src-b222411003070166177496fcfaf0912788321404.zip FreeBSD-src-b222411003070166177496fcfaf0912788321404.tar.gz |
Fix BULK read transfer if destination buffer is not cache line-aligned.
We can't use copyout because destination memory is userland address
in another process but we have reference to respective page so map
the page into kernel address space and copy fragments there
Diffstat (limited to 'sys/contrib')
-rw-r--r-- | sys/contrib/vchiq/interface/vchiq_arm/vchiq_2835_arm.c | 26 |
1 files changed, 23 insertions, 3 deletions
diff --git a/sys/contrib/vchiq/interface/vchiq_arm/vchiq_2835_arm.c b/sys/contrib/vchiq/interface/vchiq_arm/vchiq_2835_arm.c index 2aa2ecc..2f8ed43 100644 --- a/sys/contrib/vchiq/interface/vchiq_arm/vchiq_2835_arm.c +++ b/sys/contrib/vchiq/interface/vchiq_arm/vchiq_2835_arm.c @@ -109,6 +109,22 @@ vchiq_dmamap_cb(void *arg, bus_dma_segment_t *segs, int nseg, int err) *addr = PHYS_TO_VCBUS(segs[0].ds_addr); } +static int +copyout_page(vm_page_t p, size_t offset, void *kaddr, size_t size) +{ + uint8_t *dst; + + dst = pmap_mapdev(VM_PAGE_TO_PHYS(p), PAGE_SIZE); + if (!dst) + return ENOMEM; + + memcpy(dst + offset, kaddr, size); + + pmap_unmapdev((vm_offset_t)dst, PAGE_SIZE); + + return 0; +} + int __init vchiq_platform_init(VCHIQ_STATE_T *state) { @@ -560,15 +576,19 @@ free_pagelist(BULKINFO_T *bi, int actual) if (head_bytes > actual) head_bytes = actual; - memcpy((char *)bi->buf, + copyout_page(pages[0], + pagelist->offset, fragments->headbuf, head_bytes); } if ((actual >= 0) && (head_bytes < actual) && (tail_bytes != 0)) { - memcpy((char *)bi->buf + actual - tail_bytes, - fragments->tailbuf, tail_bytes); + + copyout_page(pages[num_pages-1], + (((vm_offset_t)bi->buf + actual) % PAGE_SIZE) - tail_bytes, + fragments->tailbuf, + tail_bytes); } down(&g_free_fragments_mutex); |