summaryrefslogtreecommitdiffstats
path: root/sys/contrib/vchiq
diff options
context:
space:
mode:
authorgonzo <gonzo@FreeBSD.org>2015-10-30 01:19:04 +0000
committergonzo <gonzo@FreeBSD.org>2015-10-30 01:19:04 +0000
commitb222411003070166177496fcfaf0912788321404 (patch)
treecb2e0673133fb9bc70b03525b4adfafd8d3d93c2 /sys/contrib/vchiq
parent949e84b266cc7b3ae7f1c83e09223981fe6a0f0b (diff)
downloadFreeBSD-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/vchiq')
-rw-r--r--sys/contrib/vchiq/interface/vchiq_arm/vchiq_2835_arm.c26
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);
OpenPOWER on IntegriCloud