aboutsummaryrefslogtreecommitdiff
path: root/sys/contrib/vchiq
diff options
context:
space:
mode:
Diffstat (limited to 'sys/contrib/vchiq')
-rw-r--r--sys/contrib/vchiq/interface/compat/vchi_bsd.c12
-rw-r--r--sys/contrib/vchiq/interface/vchiq_arm/vchiq_2835_arm.c145
-rw-r--r--sys/contrib/vchiq/interface/vchiq_arm/vchiq_arm.c482
-rw-r--r--sys/contrib/vchiq/interface/vchiq_arm/vchiq_core.c91
-rw-r--r--sys/contrib/vchiq/interface/vchiq_arm/vchiq_core.h11
-rw-r--r--sys/contrib/vchiq/interface/vchiq_arm/vchiq_ioctl.h121
-rw-r--r--sys/contrib/vchiq/interface/vchiq_arm/vchiq_kmod.c76
-rw-r--r--sys/contrib/vchiq/interface/vchiq_arm/vchiq_pagelist.h8
-rw-r--r--sys/contrib/vchiq/interface/vchiq_arm/vchiq_shim.c4
9 files changed, 744 insertions, 206 deletions
diff --git a/sys/contrib/vchiq/interface/compat/vchi_bsd.c b/sys/contrib/vchiq/interface/compat/vchi_bsd.c
index 8f47b3dc02d6..08f2f66dfc54 100644
--- a/sys/contrib/vchiq/interface/compat/vchi_bsd.c
+++ b/sys/contrib/vchiq/interface/compat/vchi_bsd.c
@@ -340,7 +340,6 @@ down_interruptible(struct semaphore *s)
int ret ;
ret = 0;
-
mtx_lock(&s->mtx);
while (s->value == 0) {
@@ -348,13 +347,11 @@ down_interruptible(struct semaphore *s)
ret = cv_wait_sig(&s->cv, &s->mtx);
s->waiters--;
- if (ret == EINTR) {
+ /* XXXMDC As per its semaphore.c, linux can only return EINTR */
+ if (ret) {
mtx_unlock(&s->mtx);
- return (-EINTR);
+ return -EINTR;
}
-
- if (ret == ERESTART)
- continue;
}
s->value--;
@@ -441,8 +438,7 @@ flush_signals(VCHIQ_THREAD_T thr)
int
fatal_signal_pending(VCHIQ_THREAD_T thr)
{
- printf("Implement ME: %s\n", __func__);
- return (0);
+ return (curproc_sigkilled());
}
/*
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 185e81e71bdc..7e105a6b3b77 100644
--- a/sys/contrib/vchiq/interface/vchiq_arm/vchiq_2835_arm.c
+++ b/sys/contrib/vchiq/interface/vchiq_arm/vchiq_2835_arm.c
@@ -65,9 +65,24 @@ MALLOC_DEFINE(M_VCPAGELIST, "vcpagelist", "VideoCore pagelist memory");
#define MAX_FRAGMENTS (VCHIQ_NUM_CURRENT_BULKS * 2)
+/*
+ * XXXMDC
+ * Do this less ad-hoc-y -- e.g.
+ * https://github.com/raspberrypi/linux/commit/c683db8860a80562a2bb5b451d77b3e471d24f36
+ */
+#if defined(__aarch64__)
+int g_cache_line_size = 64;
+#else
int g_cache_line_size = 32;
+#endif
static int g_fragment_size;
+unsigned int g_long_bulk_space = 0;
+#define VM_PAGE_TO_VC_BULK_PAGE(x) (\
+ g_long_bulk_space ? VM_PAGE_TO_PHYS(x)\
+ : PHYS_TO_VCBUS(VM_PAGE_TO_PHYS(x))\
+)
+
typedef struct vchiq_2835_state_struct {
int inited;
VCHIQ_ARM_STATE_T arm_state;
@@ -113,6 +128,54 @@ vchiq_dmamap_cb(void *arg, bus_dma_segment_t *segs, int nseg, int err)
*addr = PHYS_TO_VCBUS(segs[0].ds_addr);
}
+#if defined(__aarch64__) /* See comment in free_pagelist */
+static int
+invalidate_cachelines_in_range_of_ppage(
+ vm_page_t p,
+ size_t offset,
+ size_t count
+)
+{
+ if(offset + count > PAGE_SIZE){ return EINVAL; }
+ uint8_t *dst = (uint8_t*)pmap_quick_enter_page(p);
+ if (!dst){
+ return ENOMEM;
+ }
+ cpu_dcache_inv_range((void *)((vm_offset_t)dst + offset), count);
+ pmap_quick_remove_page((vm_offset_t)dst);
+ return 0;
+}
+
+/* XXXMDC bulk instead of loading and invalidating single pages? */
+static void
+invalidate_cachelines_in_range_of_ppage_seq(vm_page_t *p, size_t start,
+ size_t count)
+{
+ if (start >= PAGE_SIZE)
+ goto invalid_input;
+
+#define _NEXT_AT(x,_m) (((x)+((_m)-1)) & ~((_m)-1)) /* for power of two m */
+ size_t offset = _NEXT_AT(start,g_cache_line_size);
+#undef _NEXT_AT
+ count = (offset < start + count) ? count - (offset - start) : 0;
+ offset = offset & (PAGE_SIZE - 1);
+ for (size_t done = 0; count > done;
+ p++, done += PAGE_SIZE - offset, offset = 0) {
+ size_t in_page = PAGE_SIZE - offset;
+ size_t todo = (count-done > in_page) ? in_page : count-done;
+ int e = invalidate_cachelines_in_range_of_ppage(*p, offset, todo);
+ if (e != 0)
+ goto problem_in_loop;
+ }
+ return;
+
+problem_in_loop:
+invalid_input:
+ WARN_ON(1);
+ return;
+}
+#endif
+
static int
copyout_page(vm_page_t p, size_t offset, void *kaddr, size_t size)
{
@@ -171,7 +234,7 @@ vchiq_platform_init(VCHIQ_STATE_T *state)
goto failed_load;
}
- WARN_ON(((int)g_slot_mem & (PAGE_SIZE - 1)) != 0);
+ WARN_ON(((size_t)g_slot_mem & (PAGE_SIZE - 1)) != 0);
vchiq_slot_zero = vchiq_init_slots(g_slot_mem, g_slot_mem_size);
if (!vchiq_slot_zero) {
@@ -391,13 +454,14 @@ pagelist_page_free(vm_page_t pp)
** from increased speed as a result.
*/
+
static int
create_pagelist(char __user *buf, size_t count, unsigned short type,
struct proc *p, BULKINFO_T *bi)
{
PAGELIST_T *pagelist;
vm_page_t* pages;
- unsigned long *addrs;
+ uint32_t *addrs;
unsigned int num_pages, i;
vm_offset_t offset;
int pagelist_size;
@@ -434,7 +498,7 @@ create_pagelist(char __user *buf, size_t count, unsigned short type,
err = bus_dmamem_alloc(bi->pagelist_dma_tag, (void **)&pagelist,
BUS_DMA_COHERENT | BUS_DMA_WAITOK, &bi->pagelist_dma_map);
- if (err) {
+ if (err || !pagelist) {
vchiq_log_error(vchiq_core_log_level, "Unable to allocate pagelist memory");
err = -ENOMEM;
goto failed_alloc;
@@ -447,6 +511,7 @@ create_pagelist(char __user *buf, size_t count, unsigned short type,
if (err) {
vchiq_log_error(vchiq_core_log_level, "cannot load DMA map for pagelist memory");
err = -ENOMEM;
+ bi->pagelist = pagelist;
goto failed_load;
}
@@ -463,8 +528,9 @@ create_pagelist(char __user *buf, size_t count, unsigned short type,
if (actual_pages != num_pages) {
if (actual_pages > 0)
vm_page_unhold_pages(pages, actual_pages);
- free(pagelist, M_VCPAGELIST);
- return (-ENOMEM);
+ err = -ENOMEM;
+ bi->pagelist = pagelist;
+ goto failed_hold;
}
pagelist->length = count;
@@ -473,27 +539,28 @@ create_pagelist(char __user *buf, size_t count, unsigned short type,
/* Group the pages into runs of contiguous pages */
- base_addr = (void *)PHYS_TO_VCBUS(VM_PAGE_TO_PHYS(pages[0]));
+ size_t run_ceil = g_long_bulk_space ? 0x100 : PAGE_SIZE;
+ unsigned int pg_addr_rshift = g_long_bulk_space ? 4 : 0;
+ base_addr = (void *) VM_PAGE_TO_VC_BULK_PAGE(pages[0]);
next_addr = base_addr + PAGE_SIZE;
addridx = 0;
run = 0;
-
+#define _PG_BLOCK(base,run) \
+ ((((size_t) (base)) >> pg_addr_rshift) & ~(run_ceil-1)) + (run)
for (i = 1; i < num_pages; i++) {
- addr = (void *)PHYS_TO_VCBUS(VM_PAGE_TO_PHYS(pages[i]));
- if ((addr == next_addr) && (run < (PAGE_SIZE - 1))) {
+ addr = (void *)VM_PAGE_TO_VC_BULK_PAGE(pages[i]);
+ if ((addr == next_addr) && (run < run_ceil - 1)) {
next_addr += PAGE_SIZE;
run++;
} else {
- addrs[addridx] = (unsigned long)base_addr + run;
- addridx++;
+ addrs[addridx++] = (uint32_t) _PG_BLOCK(base_addr,run);
base_addr = addr;
next_addr = addr + PAGE_SIZE;
run = 0;
}
}
-
- addrs[addridx] = (unsigned long)base_addr + run;
- addridx++;
+ addrs[addridx++] = _PG_BLOCK(base_addr, run);
+#undef _PG_BLOCK
/* Partial cache lines (fragments) require special measures */
if ((type == PAGELIST_READ) &&
@@ -514,20 +581,35 @@ create_pagelist(char __user *buf, size_t count, unsigned short type,
WARN_ON(fragments == NULL);
g_free_fragments = *(char **) g_free_fragments;
up(&g_free_fragments_mutex);
- pagelist->type =
- PAGELIST_READ_WITH_FRAGMENTS +
- (fragments - g_fragments_base)/g_fragment_size;
+ pagelist->type = PAGELIST_READ_WITH_FRAGMENTS
+ + (fragments - g_fragments_base)/g_fragment_size;
+#if defined(__aarch64__)
+ bus_dmamap_sync(bcm_slots_dma_tag, bcm_slots_dma_map,
+ BUS_DMASYNC_PREREAD);
+#endif
}
+#if defined(__aarch64__)
+ if(type == PAGELIST_READ) {
+ cpu_dcache_wbinv_range(buf, count);
+ } else {
+ cpu_dcache_wb_range(buf, count);
+ }
+ dsb(sy);
+#else
pa = pmap_extract(PCPU_GET(curpmap), (vm_offset_t)buf);
dcache_wbinv_poc((vm_offset_t)buf, pa, count);
+#endif
- bus_dmamap_sync(bi->pagelist_dma_tag, bi->pagelist_dma_map, BUS_DMASYNC_PREWRITE);
+ bus_dmamap_sync(bi->pagelist_dma_tag, bi->pagelist_dma_map,
+ BUS_DMASYNC_PREWRITE);
bi->pagelist = pagelist;
return 0;
+failed_hold:
+ bus_dmamap_unload(bi->pagelist_dma_tag,bi->pagelist_dma_map);
failed_load:
bus_dmamem_free(bi->pagelist_dma_tag, bi->pagelist, bi->pagelist_dma_map);
failed_alloc:
@@ -556,6 +638,24 @@ free_pagelist(BULKINFO_T *bi, int actual)
pages = (vm_page_t*)(pagelist->addrs + num_pages);
+#if defined(__aarch64__)
+ /*
+ * On arm64, even if the user keeps their end of the bargain
+ * -- do NOT touch the buffers sent to VC -- but reads around the
+ * pagelist after the invalidation above, the arm might preemptively
+ * load (and validate) cache lines for areas inside the page list,
+ * so we must invalidate them again.
+ *
+ * The functional test does it and without this it doesn't pass.
+ *
+ * XXXMDC might it be enough to invalidate a couple of pages at
+ * the ends of the page list?
+ */
+ if(pagelist->type >= PAGELIST_READ && actual > 0)
+ invalidate_cachelines_in_range_of_ppage_seq(pages,
+ pagelist->offset, actual);
+#endif
+
/* Deal with any partial cache lines (fragments) */
if (pagelist->type >= PAGELIST_READ_WITH_FRAGMENTS) {
char *fragments = g_fragments_base +
@@ -592,13 +692,18 @@ free_pagelist(BULKINFO_T *bi, int actual)
up(&g_free_fragments_sema);
}
- for (i = 0; i < num_pages; i++) {
- if (pagelist->type != PAGELIST_WRITE) {
+ if (pagelist->type != PAGELIST_WRITE) {
+ for (i = 0; i < num_pages; i++) {
vm_page_dirty(pages[i]);
pagelist_page_free(pages[i]);
}
}
+#if defined(__aarch64__)
+ /* XXXMDC necessary? */
+ dsb(sy);
+#endif
+
bus_dmamap_unload(bi->pagelist_dma_tag, bi->pagelist_dma_map);
bus_dmamem_free(bi->pagelist_dma_tag, bi->pagelist, bi->pagelist_dma_map);
bus_dma_tag_destroy(bi->pagelist_dma_tag);
diff --git a/sys/contrib/vchiq/interface/vchiq_arm/vchiq_arm.c b/sys/contrib/vchiq/interface/vchiq_arm/vchiq_arm.c
index e25c4d738922..d780f3807cee 100644
--- a/sys/contrib/vchiq/interface/vchiq_arm/vchiq_arm.c
+++ b/sys/contrib/vchiq/interface/vchiq_arm/vchiq_arm.c
@@ -386,7 +386,7 @@ static void
user_service_free(void *userdata)
{
USER_SERVICE_T *user_service = userdata;
-
+
_sema_destroy(&user_service->insert_event);
_sema_destroy(&user_service->remove_event);
@@ -410,7 +410,7 @@ static void close_delivered(USER_SERVICE_T *user_service)
/* Wake the user-thread blocked in close_ or remove_service */
up(&user_service->close_event);
-
+
user_service->close_pending = 0;
}
}
@@ -448,6 +448,22 @@ vchiq_ioctl(struct cdev *cdev, u_long cmd, caddr_t arg, int fflag,
(_IOC_NR(cmd) <= VCHIQ_IOC_MAX)) ?
ioctl_names[_IOC_NR(cmd)] : "<invalid>", arg);
+#ifdef COMPAT_FREEBSD32
+/* A fork in the road to freebsd32 compatibilty */
+#define _CF32_FORK(compat_c, native_c) { \
+ int _____dont_call_your_vars_this = 0; \
+ switch (cmd) { \
+ _CF32_CASE {_____dont_call_your_vars_this = 1;} \
+ break; \
+ } \
+ if (_____dont_call_your_vars_this) \
+ { compat_c } \
+ else \
+ { native_c } \
+ }
+#else
+#define _CF32_FORK(compat_c, native_c) { native_c }
+#endif
switch (cmd) {
case VCHIQ_IOC_SHUTDOWN:
if (!instance->connected)
@@ -496,13 +512,33 @@ vchiq_ioctl(struct cdev *cdev, u_long cmd, caddr_t arg, int fflag,
"vchiq: could not connect: %d", status);
break;
+#ifdef COMPAT_FREEBSD32
+#define _CF32_CASE \
+ case VCHIQ_IOC_CREATE_SERVICE32:
+ _CF32_CASE
+#endif
case VCHIQ_IOC_CREATE_SERVICE: {
VCHIQ_CREATE_SERVICE_T args;
USER_SERVICE_T *user_service = NULL;
void *userdata;
int srvstate;
+_CF32_FORK(
+ VCHIQ_CREATE_SERVICE32_T args32;
+ memcpy(&args32, (const void*)arg, sizeof(args32));
+ args.params.fourcc = args32.params.fourcc;
+ /* XXXMDC not actually used? overwritten straight away */
+ args.params.callback =
+ (VCHIQ_CALLBACK_T)(uintptr_t) args32.params.callback;
+ args.params.userdata = (void*)(uintptr_t)args32.params.userdata;
+ args.params.version = args32.params.version;
+ args.params.version_min = args32.params.version_min;
+ args.is_open = args32.is_open;
+ args.is_vchi = args32.is_vchi;
+ args.handle = args32.handle;
+,
memcpy(&args, (const void*)arg, sizeof(args));
+)
user_service = kmalloc(sizeof(USER_SERVICE_T), GFP_KERNEL);
if (!user_service) {
@@ -558,15 +594,22 @@ vchiq_ioctl(struct cdev *cdev, u_long cmd, caddr_t arg, int fflag,
break;
}
}
-
#ifdef VCHIQ_IOCTL_DEBUG
printf("%s: [CREATE SERVICE] handle = %08x\n", __func__, service->handle);
#endif
+_CF32_FORK(
+ memcpy((void *)
+ &(((VCHIQ_CREATE_SERVICE32_T*)
+ arg)->handle),
+ (const void *)&service->handle,
+ sizeof(service->handle));
+,
memcpy((void *)
&(((VCHIQ_CREATE_SERVICE_T*)
arg)->handle),
(const void *)&service->handle,
sizeof(service->handle));
+);
service = NULL;
} else {
@@ -574,6 +617,7 @@ vchiq_ioctl(struct cdev *cdev, u_long cmd, caddr_t arg, int fflag,
kfree(user_service);
}
} break;
+#undef _CF32_CASE
case VCHIQ_IOC_CLOSE_SERVICE: {
VCHIQ_SERVICE_HANDLE_T handle;
@@ -673,9 +717,22 @@ vchiq_ioctl(struct cdev *cdev, u_long cmd, caddr_t arg, int fflag,
ret = -EINVAL;
} break;
+#ifdef COMPAT_FREEBSD32
+#define _CF32_CASE \
+ case VCHIQ_IOC_QUEUE_MESSAGE32:
+ _CF32_CASE
+#endif
case VCHIQ_IOC_QUEUE_MESSAGE: {
VCHIQ_QUEUE_MESSAGE_T args;
+_CF32_FORK(
+ VCHIQ_QUEUE_MESSAGE32_T args32;
+ memcpy(&args32, (const void*)arg, sizeof(args32));
+ args.handle = args32.handle;
+ args.count = args32.count;
+ args.elements = (VCHIQ_ELEMENT_T *)(uintptr_t)args32.elements;
+,
memcpy(&args, (const void*)arg, sizeof(args));
+)
#ifdef VCHIQ_IOCTL_DEBUG
printf("%s: [QUEUE MESSAGE] handle = %08x\n", __func__, args.handle);
@@ -686,8 +743,22 @@ vchiq_ioctl(struct cdev *cdev, u_long cmd, caddr_t arg, int fflag,
if ((service != NULL) && (args.count <= MAX_ELEMENTS)) {
/* Copy elements into kernel space */
VCHIQ_ELEMENT_T elements[MAX_ELEMENTS];
- if (copy_from_user(elements, args.elements,
- args.count * sizeof(VCHIQ_ELEMENT_T)) == 0)
+ long cp_ret;
+_CF32_FORK(
+ VCHIQ_ELEMENT32_T elements32[MAX_ELEMENTS];
+ cp_ret = copy_from_user(elements32, args.elements,
+ args.count * sizeof(VCHIQ_ELEMENT32_T));
+ for(int i=0;cp_ret == 0 && i < args.count;++i){
+ elements[i].data =
+ (void *)(uintptr_t)elements32[i].data;
+ elements[i].size = elements32[i].size;
+ }
+
+,
+ cp_ret = copy_from_user(elements, args.elements,
+ args.count * sizeof(VCHIQ_ELEMENT_T));
+)
+ if (cp_ret == 0)
status = vchiq_queue_message
(args.handle,
elements, args.count);
@@ -697,16 +768,38 @@ vchiq_ioctl(struct cdev *cdev, u_long cmd, caddr_t arg, int fflag,
ret = -EINVAL;
}
} break;
+#undef _CF32_CASE
+#ifdef COMPAT_FREEBSD32
+#define _CF32_CASE \
+ case VCHIQ_IOC_QUEUE_BULK_TRANSMIT32: \
+ case VCHIQ_IOC_QUEUE_BULK_RECEIVE32:
+ _CF32_CASE
+#endif
case VCHIQ_IOC_QUEUE_BULK_TRANSMIT:
case VCHIQ_IOC_QUEUE_BULK_RECEIVE: {
VCHIQ_QUEUE_BULK_TRANSFER_T args;
+
struct bulk_waiter_node *waiter = NULL;
VCHIQ_BULK_DIR_T dir =
- (cmd == VCHIQ_IOC_QUEUE_BULK_TRANSMIT) ?
- VCHIQ_BULK_TRANSMIT : VCHIQ_BULK_RECEIVE;
-
+ (cmd == VCHIQ_IOC_QUEUE_BULK_TRANSMIT) ||
+ (cmd == VCHIQ_IOC_QUEUE_BULK_TRANSMIT32)?
+ VCHIQ_BULK_TRANSMIT : VCHIQ_BULK_RECEIVE;
+
+_CF32_FORK(
+ VCHIQ_QUEUE_BULK_TRANSFER32_T args32;
+ memcpy(&args32, (const void*)arg, sizeof(args32));
+ /* XXXMDC parens needed (macro parsing?) */
+ args = ((VCHIQ_QUEUE_BULK_TRANSFER_T) {
+ .handle = args32.handle,
+ .data = (void *)(uintptr_t) args32.data,
+ .size = args32.size,
+ .userdata = (void *)(uintptr_t) args32.userdata,
+ .mode = args32.mode,
+ });
+,
memcpy(&args, (const void*)arg, sizeof(args));
+)
service = find_service_for_instance(instance, args.handle);
if (!service) {
@@ -734,7 +827,6 @@ vchiq_ioctl(struct cdev *cdev, u_long cmd, caddr_t arg, int fflag,
list_del(pos);
break;
}
-
}
lmutex_unlock(&instance->bulk_waiter_list_mutex);
if (!waiter) {
@@ -749,6 +841,7 @@ vchiq_ioctl(struct cdev *cdev, u_long cmd, caddr_t arg, int fflag,
(size_t)waiter, current->p_pid);
args.userdata = &waiter->bulk_waiter;
}
+
status = vchiq_bulk_transfer
(args.handle,
VCHI_MEM_HANDLE_INVALID,
@@ -779,14 +872,28 @@ vchiq_ioctl(struct cdev *cdev, u_long cmd, caddr_t arg, int fflag,
"saved bulk_waiter %zx for pid %d",
(size_t)waiter, current->p_pid);
+_CF32_FORK(
+ memcpy((void *)
+ &(((VCHIQ_QUEUE_BULK_TRANSFER32_T *)
+ arg)->mode),
+ (const void *)&mode_waiting,
+ sizeof(mode_waiting));
+,
memcpy((void *)
&(((VCHIQ_QUEUE_BULK_TRANSFER_T *)
arg)->mode),
(const void *)&mode_waiting,
sizeof(mode_waiting));
+)
}
} break;
+#undef _CF32_CASE
+#ifdef COMPAT_FREEBSD32
+#define _CF32_CASE \
+ case VCHIQ_IOC_AWAIT_COMPLETION32:
+ _CF32_CASE
+#endif
case VCHIQ_IOC_AWAIT_COMPLETION: {
VCHIQ_AWAIT_COMPLETION_T args;
int count = 0;
@@ -797,7 +904,17 @@ vchiq_ioctl(struct cdev *cdev, u_long cmd, caddr_t arg, int fflag,
break;
}
+_CF32_FORK(
+ VCHIQ_AWAIT_COMPLETION32_T args32;
+ memcpy(&args32, (const void*)arg, sizeof(args32));
+ args.count = args32.count;
+ args.buf = (VCHIQ_COMPLETION_DATA_T *)(uintptr_t)args32.buf;
+ args.msgbufsize = args32.msgbufsize;
+ args.msgbufcount = args32.msgbufcount;
+ args.msgbufs = (void **)(uintptr_t)args32.msgbufs;
+,
memcpy(&args, (const void*)arg, sizeof(args));
+)
lmutex_lock(&instance->completion_mutex);
@@ -877,6 +994,20 @@ vchiq_ioctl(struct cdev *cdev, u_long cmd, caddr_t arg, int fflag,
break;
/* Get the pointer from user space */
msgbufcount--;
+_CF32_FORK(
+ uint32_t *msgbufs32 =
+ (uint32_t *) args.msgbufs;
+ uint32_t msgbuf32 = 0;
+ if (copy_from_user(&msgbuf32,
+ (const uint32_t __user *)
+ &msgbufs32[msgbufcount],
+ sizeof(msgbuf32)) != 0) {
+ if (count == 0)
+ ret = -EFAULT;
+ break;
+ }
+ msgbuf = (void __user *)(uintptr_t)msgbuf32;
+,
if (copy_from_user(&msgbuf,
(const void __user *)
&args.msgbufs[msgbufcount],
@@ -885,6 +1016,7 @@ vchiq_ioctl(struct cdev *cdev, u_long cmd, caddr_t arg, int fflag,
ret = -EFAULT;
break;
}
+)
/* Copy the message to user space */
if (copy_to_user(msgbuf, header,
@@ -908,7 +1040,30 @@ vchiq_ioctl(struct cdev *cdev, u_long cmd, caddr_t arg, int fflag,
VCHIQ_SERVICE_CLOSED) &&
!instance->use_close_delivered)
unlock_service(service1);
-
+_CF32_FORK(
+ VCHIQ_COMPLETION_DATA32_T comp32 = {0};
+ comp32.reason =
+ (uint32_t)(size_t) completion->reason;
+ comp32.service_userdata =
+ (uint32_t)(size_t)
+ completion->service_userdata;
+ comp32.bulk_userdata =
+ (uint32_t)(size_t)
+ completion->bulk_userdata;
+ comp32.header =
+ (uint32_t)(size_t)completion->header;
+
+ VCHIQ_COMPLETION_DATA32_T __user *buf_loc;
+ buf_loc = (VCHIQ_COMPLETION_DATA32_T __user *)
+ args.buf;
+ buf_loc += count;
+ if (copy_to_user(
+ buf_loc, &comp32, sizeof(comp32)
+ ) != 0) {
+ if (ret == 0)
+ ret = -EFAULT;
+ }
+,
if (copy_to_user((void __user *)(
(size_t)args.buf +
count * sizeof(VCHIQ_COMPLETION_DATA_T)),
@@ -918,6 +1073,7 @@ vchiq_ioctl(struct cdev *cdev, u_long cmd, caddr_t arg, int fflag,
ret = -EFAULT;
break;
}
+)
/* Ensure that the above copy has completed
** before advancing the remove pointer. */
@@ -927,18 +1083,33 @@ vchiq_ioctl(struct cdev *cdev, u_long cmd, caddr_t arg, int fflag,
}
if (msgbufcount != args.msgbufcount) {
+_CF32_FORK(
+ memcpy(
+ (void __user *)
+ &((VCHIQ_AWAIT_COMPLETION32_T *)arg)->
+ msgbufcount,
+ &msgbufcount,
+ sizeof(msgbufcount));
+,
memcpy((void __user *)
&((VCHIQ_AWAIT_COMPLETION_T *)arg)->
msgbufcount,
&msgbufcount,
sizeof(msgbufcount));
+)
}
if (count != args.count)
{
+_CF32_FORK(
+ memcpy((void __user *)
+ &((VCHIQ_AWAIT_COMPLETION32_T *)arg)->count,
+ &count, sizeof(count));
+,
memcpy((void __user *)
&((VCHIQ_AWAIT_COMPLETION_T *)arg)->count,
&count, sizeof(count));
+)
}
}
@@ -947,9 +1118,9 @@ vchiq_ioctl(struct cdev *cdev, u_long cmd, caddr_t arg, int fflag,
if ((ret == 0) && instance->closing)
ret = -ENOTCONN;
- /*
+ /*
* XXXBSD: ioctl return codes are not negative as in linux, so
- * we can not indicate success with positive number of passed
+ * we can not indicate success with positive number of passed
* messages
*/
if (ret > 0)
@@ -958,14 +1129,29 @@ vchiq_ioctl(struct cdev *cdev, u_long cmd, caddr_t arg, int fflag,
lmutex_unlock(&instance->completion_mutex);
DEBUG_TRACE(AWAIT_COMPLETION_LINE);
} break;
+#undef _CF32_CASE
+#ifdef COMPAT_FREEBSD32
+#define _CF32_CASE \
+ case VCHIQ_IOC_DEQUEUE_MESSAGE32:
+ _CF32_CASE
+#endif
case VCHIQ_IOC_DEQUEUE_MESSAGE: {
VCHIQ_DEQUEUE_MESSAGE_T args;
USER_SERVICE_T *user_service;
VCHIQ_HEADER_T *header;
DEBUG_TRACE(DEQUEUE_MESSAGE_LINE);
+_CF32_FORK(
+ VCHIQ_DEQUEUE_MESSAGE32_T args32;
+ memcpy(&args32, (const void*)arg, sizeof(args32));
+ args.handle = args32.handle;
+ args.blocking = args32.blocking;
+ args.bufsize = args32.bufsize;
+ args.buf = (void *)(uintptr_t)args32.buf;
+,
memcpy(&args, (const void*)arg, sizeof(args));
+)
service = find_service_for_instance(instance, args.handle);
if (!service) {
ret = -EINVAL;
@@ -1022,8 +1208,19 @@ vchiq_ioctl(struct cdev *cdev, u_long cmd, caddr_t arg, int fflag,
header->data,
header->size) == 0)) {
args.bufsize = header->size;
+_CF32_FORK(
+ VCHIQ_DEQUEUE_MESSAGE32_T args32;
+ args32.handle = args.handle;
+ args32.blocking = args.blocking;
+ args32.bufsize = args.bufsize;
+ args32.buf = (uintptr_t)(void *)args.buf;
+
+ memcpy((void *)arg, &args32,
+ sizeof(args32));
+,
memcpy((void *)arg, &args,
sizeof(args));
+)
vchiq_release_message(
service->handle,
header);
@@ -1039,6 +1236,7 @@ vchiq_ioctl(struct cdev *cdev, u_long cmd, caddr_t arg, int fflag,
}
DEBUG_TRACE(DEQUEUE_MESSAGE_LINE);
} break;
+#undef _CF32_CASE
case VCHIQ_IOC_GET_CLIENT_ID: {
VCHIQ_SERVICE_HANDLE_T handle;
@@ -1048,11 +1246,24 @@ vchiq_ioctl(struct cdev *cdev, u_long cmd, caddr_t arg, int fflag,
ret = vchiq_get_client_id(handle);
} break;
+#ifdef COMPAT_FREEBSD32
+#define _CF32_CASE \
+ case VCHIQ_IOC_GET_CONFIG32:
+ _CF32_CASE
+#endif
case VCHIQ_IOC_GET_CONFIG: {
VCHIQ_GET_CONFIG_T args;
VCHIQ_CONFIG_T config;
-
+_CF32_FORK(
+ VCHIQ_GET_CONFIG32_T args32;
+
+ memcpy(&args32, (const void*)arg, sizeof(args32));
+ args.config_size = args32.config_size;
+ args.pconfig = (VCHIQ_CONFIG_T *)
+ (uintptr_t)args32.pconfig;
+,
memcpy(&args, (const void*)arg, sizeof(args));
+)
if (args.config_size > sizeof(config)) {
ret = -EINVAL;
break;
@@ -1066,6 +1277,7 @@ vchiq_ioctl(struct cdev *cdev, u_long cmd, caddr_t arg, int fflag,
}
}
} break;
+#undef _CF32_CASE
case VCHIQ_IOC_SET_SERVICE_OPTION: {
VCHIQ_SET_SERVICE_OPTION_T args;
@@ -1082,18 +1294,31 @@ vchiq_ioctl(struct cdev *cdev, u_long cmd, caddr_t arg, int fflag,
args.handle, args.option, args.value);
} break;
+#ifdef COMPAT_FREEBSD32
+#define _CF32_CASE \
+ case VCHIQ_IOC_DUMP_PHYS_MEM32:
+ _CF32_CASE
+#endif
case VCHIQ_IOC_DUMP_PHYS_MEM: {
VCHIQ_DUMP_MEM_T args;
+_CF32_FORK(
+ VCHIQ_DUMP_MEM32_T args32;
+ memcpy(&args32, (const void*)arg, sizeof(args32));
+ args.virt_addr = (void *)(uintptr_t)args32.virt_addr;
+ args.num_bytes = (size_t)args32.num_bytes;
+,
memcpy(&args, (const void*)arg, sizeof(args));
+)
printf("IMPLEMENT ME: %s:%d\n", __FILE__, __LINE__);
#if 0
dump_phys_mem(args.virt_addr, args.num_bytes);
#endif
} break;
+#undef _CF32_CASE
case VCHIQ_IOC_LIB_VERSION: {
- unsigned int lib_version = (unsigned int)arg;
+ size_t lib_version = (size_t)arg;
if (lib_version < VCHIQ_VERSION_MIN)
ret = -EINVAL;
@@ -1119,6 +1344,7 @@ vchiq_ioctl(struct cdev *cdev, u_long cmd, caddr_t arg, int fflag,
ret = -ENOTTY;
break;
}
+#undef _CF32_FORK
if (service)
unlock_service(service);
@@ -1155,18 +1381,14 @@ vchiq_ioctl(struct cdev *cdev, u_long cmd, caddr_t arg, int fflag,
return ret;
}
-static void
-instance_dtr(void *data)
-{
- kfree(data);
-}
/****************************************************************************
*
* vchiq_open
*
***************************************************************************/
+static void instance_dtr(void *data);
static int
vchiq_open(struct cdev *dev, int flags, int fmt __unused, struct thread *td)
@@ -1206,7 +1428,7 @@ vchiq_open(struct cdev *dev, int flags, int fmt __unused, struct thread *td)
INIT_LIST_HEAD(&instance->bulk_waiter_list);
devfs_set_cdevpriv(instance, instance_dtr);
- }
+ }
else {
vchiq_log_error(vchiq_arm_log_level,
"Unknown minor device");
@@ -1222,143 +1444,151 @@ vchiq_open(struct cdev *dev, int flags, int fmt __unused, struct thread *td)
*
***************************************************************************/
+
static int
-vchiq_close(struct cdev *dev, int flags __unused, int fmt __unused,
- struct thread *td)
+_vchiq_close_instance(VCHIQ_INSTANCE_T instance)
{
int ret = 0;
- if (1) {
- VCHIQ_INSTANCE_T instance;
- VCHIQ_STATE_T *state = vchiq_get_state();
- VCHIQ_SERVICE_T *service;
- int i;
-
- if ((ret = devfs_get_cdevpriv((void**)&instance))) {
- printf("devfs_get_cdevpriv failed: error %d\n", ret);
- return (ret);
- }
-
- vchiq_log_info(vchiq_arm_log_level,
- "vchiq_release: instance=%lx",
- (unsigned long)instance);
-
- if (!state) {
- ret = -EPERM;
- goto out;
- }
+ VCHIQ_STATE_T *state = vchiq_get_state();
+ VCHIQ_SERVICE_T *service;
+ int i;
- /* Ensure videocore is awake to allow termination. */
- vchiq_use_internal(instance->state, NULL,
- USE_TYPE_VCHIQ);
+ vchiq_log_info(vchiq_arm_log_level,
+ "vchiq_release: instance=%lx",
+ (unsigned long)instance);
- lmutex_lock(&instance->completion_mutex);
+ if (!state) {
+ ret = -EPERM;
+ goto out;
+ }
- /* Wake the completion thread and ask it to exit */
- instance->closing = 1;
- up(&instance->insert_event);
+ /* Ensure videocore is awake to allow termination. */
+ vchiq_use_internal(instance->state, NULL,
+ USE_TYPE_VCHIQ);
- lmutex_unlock(&instance->completion_mutex);
+ lmutex_lock(&instance->completion_mutex);
- /* Wake the slot handler if the completion queue is full. */
- up(&instance->remove_event);
+ /* Wake the completion thread and ask it to exit */
+ instance->closing = 1;
+ up(&instance->insert_event);
- /* Mark all services for termination... */
- i = 0;
- while ((service = next_service_by_instance(state, instance,
- &i)) != NULL) {
- USER_SERVICE_T *user_service = service->base.userdata;
+ lmutex_unlock(&instance->completion_mutex);
- /* Wake the slot handler if the msg queue is full. */
- up(&user_service->remove_event);
+ /* Wake the slot handler if the completion queue is full. */
+ up(&instance->remove_event);
- vchiq_terminate_service_internal(service);
- unlock_service(service);
- }
+ /* Mark all services for termination... */
+ i = 0;
+ while ((service = next_service_by_instance(state, instance,
+ &i)) != NULL) {
+ USER_SERVICE_T *user_service = service->base.userdata;
- /* ...and wait for them to die */
- i = 0;
- while ((service = next_service_by_instance(state, instance, &i))
- != NULL) {
- USER_SERVICE_T *user_service = service->base.userdata;
+ /* Wake the slot handler if the msg queue is full. */
+ up(&user_service->remove_event);
- down(&service->remove_event);
+ vchiq_terminate_service_internal(service);
+ unlock_service(service);
+ }
- BUG_ON(service->srvstate != VCHIQ_SRVSTATE_FREE);
+ /* ...and wait for them to die */
+ i = 0;
+ while ((service = next_service_by_instance(state, instance, &i))
+ != NULL) {
+ USER_SERVICE_T *user_service = service->base.userdata;
- spin_lock(&msg_queue_spinlock);
+ down(&service->remove_event);
- while (user_service->msg_remove !=
- user_service->msg_insert) {
- VCHIQ_HEADER_T *header = user_service->
- msg_queue[user_service->msg_remove &
- (MSG_QUEUE_SIZE - 1)];
- user_service->msg_remove++;
- spin_unlock(&msg_queue_spinlock);
+ BUG_ON(service->srvstate != VCHIQ_SRVSTATE_FREE);
- if (header)
- vchiq_release_message(
- service->handle,
- header);
- spin_lock(&msg_queue_spinlock);
- }
+ spin_lock(&msg_queue_spinlock);
+ while (user_service->msg_remove !=
+ user_service->msg_insert) {
+ VCHIQ_HEADER_T *header = user_service->
+ msg_queue[user_service->msg_remove &
+ (MSG_QUEUE_SIZE - 1)];
+ user_service->msg_remove++;
spin_unlock(&msg_queue_spinlock);
- unlock_service(service);
+ if (header)
+ vchiq_release_message(
+ service->handle,
+ header);
+ spin_lock(&msg_queue_spinlock);
}
- /* Release any closed services */
- while (instance->completion_remove !=
- instance->completion_insert) {
- VCHIQ_COMPLETION_DATA_T *completion;
- VCHIQ_SERVICE_T *service1;
- completion = &instance->completions[
- instance->completion_remove &
- (MAX_COMPLETIONS - 1)];
- service1 = completion->service_userdata;
- if (completion->reason == VCHIQ_SERVICE_CLOSED)
- {
- USER_SERVICE_T *user_service =
- service->base.userdata;
-
- /* Wake any blocked user-thread */
- if (instance->use_close_delivered)
- up(&user_service->close_event);
- unlock_service(service1);
- }
- instance->completion_remove++;
- }
+ spin_unlock(&msg_queue_spinlock);
- /* Release the PEER service count. */
- vchiq_release_internal(instance->state, NULL);
+ unlock_service(service);
+ }
+ /* Release any closed services */
+ while (instance->completion_remove !=
+ instance->completion_insert) {
+ VCHIQ_COMPLETION_DATA_T *completion;
+ VCHIQ_SERVICE_T *service;
+ completion = &instance->completions[
+ instance->completion_remove &
+ (MAX_COMPLETIONS - 1)];
+ service = completion->service_userdata;
+ if (completion->reason == VCHIQ_SERVICE_CLOSED)
{
- struct list_head *pos, *next;
- list_for_each_safe(pos, next,
- &instance->bulk_waiter_list) {
- struct bulk_waiter_node *waiter;
- waiter = list_entry(pos,
- struct bulk_waiter_node,
- list);
- list_del(pos);
- vchiq_log_info(vchiq_arm_log_level,
- "bulk_waiter - cleaned up %x "
- "for pid %d",
- (unsigned int)waiter, waiter->pid);
- _sema_destroy(&waiter->bulk_waiter.event);
- kfree(waiter);
- }
- }
+ USER_SERVICE_T *user_service =
+ service->base.userdata;
+ /* Wake any blocked user-thread */
+ if (instance->use_close_delivered)
+ up(&user_service->close_event);
+
+ unlock_service(service);
+ }
+ instance->completion_remove++;
}
- else {
- vchiq_log_error(vchiq_arm_log_level,
- "Unknown minor device");
- ret = -ENXIO;
+
+ /* Release the PEER service count. */
+ vchiq_release_internal(instance->state, NULL);
+
+ {
+ struct list_head *pos, *next;
+ list_for_each_safe(pos, next,
+ &instance->bulk_waiter_list) {
+ struct bulk_waiter_node *waiter;
+ waiter = list_entry(pos,
+ struct bulk_waiter_node,
+ list);
+ list_del(pos);
+ vchiq_log_info(vchiq_arm_log_level,
+ "bulk_waiter - cleaned up %zx "
+ "for pid %d",
+ (size_t)waiter, waiter->pid);
+ _sema_destroy(&waiter->bulk_waiter.event);
+ kfree(waiter);
+ }
}
out:
return ret;
+
+}
+
+static void
+instance_dtr(void *data)
+{
+ VCHIQ_INSTANCE_T instance = data;
+ _vchiq_close_instance(instance);
+ kfree(data);
+}
+
+static int
+vchiq_close(struct cdev *dev, int flags __unused, int fmt __unused,
+ struct thread *td)
+{
+
+ /* XXXMDC it's privdata that tracks opens */
+ /* XXXMDC only get closes when there are no more open fds on a vnode */
+
+ return(0);
+
}
/****************************************************************************
diff --git a/sys/contrib/vchiq/interface/vchiq_arm/vchiq_core.c b/sys/contrib/vchiq/interface/vchiq_arm/vchiq_core.c
index e7459a5553e4..923cf56f10ee 100644
--- a/sys/contrib/vchiq/interface/vchiq_arm/vchiq_core.c
+++ b/sys/contrib/vchiq/interface/vchiq_arm/vchiq_core.c
@@ -417,13 +417,15 @@ vchiq_set_conn_state(VCHIQ_STATE_T *state, VCHIQ_CONNSTATE_T newstate)
vchiq_platform_conn_state_changed(state, oldstate, newstate);
}
+#define ACTUAL_EVENT_SEM_ADDR(ref,offset)\
+ ((struct semaphore *)(((size_t) ref) + ((size_t) offset)))
static inline void
-remote_event_create(REMOTE_EVENT_T *event)
+remote_event_create(VCHIQ_STATE_T *ref, REMOTE_EVENT_T *event)
{
event->armed = 0;
/* Don't clear the 'fired' flag because it may already have been set
** by the other side. */
- _sema_init(event->event, 0);
+ _sema_init(ACTUAL_EVENT_SEM_ADDR(ref,event->event), 0);
}
__unused static inline void
@@ -433,13 +435,18 @@ remote_event_destroy(REMOTE_EVENT_T *event)
}
static inline int
-remote_event_wait(REMOTE_EVENT_T *event)
+remote_event_wait(VCHIQ_STATE_T *ref, REMOTE_EVENT_T *event)
{
if (!event->fired) {
event->armed = 1;
+#if defined(__aarch64__)
+ dsb(sy);
+#else
dsb();
+#endif
+
if (!event->fired) {
- if (down_interruptible(event->event) != 0) {
+ if (down_interruptible(ACTUAL_EVENT_SEM_ADDR(ref,event->event)) != 0) {
event->armed = 0;
return 0;
}
@@ -453,26 +460,32 @@ remote_event_wait(REMOTE_EVENT_T *event)
}
static inline void
-remote_event_signal_local(REMOTE_EVENT_T *event)
+remote_event_signal_local(VCHIQ_STATE_T *ref, REMOTE_EVENT_T *event)
{
+/*
+ * Mirror
+ * https://github.com/raspberrypi/linux/commit/a50c4c9a65779ca835746b5fd79d3d5278afbdbe
+ * for extra safety
+ */
+ event->fired = 1;
event->armed = 0;
- up(event->event);
+ up(ACTUAL_EVENT_SEM_ADDR(ref,event->event));
}
static inline void
-remote_event_poll(REMOTE_EVENT_T *event)
+remote_event_poll(VCHIQ_STATE_T *ref, REMOTE_EVENT_T *event)
{
if (event->fired && event->armed)
- remote_event_signal_local(event);
+ remote_event_signal_local(ref,event);
}
void
remote_event_pollall(VCHIQ_STATE_T *state)
{
- remote_event_poll(&state->local->sync_trigger);
- remote_event_poll(&state->local->sync_release);
- remote_event_poll(&state->local->trigger);
- remote_event_poll(&state->local->recycle);
+ remote_event_poll(state , &state->local->sync_trigger);
+ remote_event_poll(state , &state->local->sync_release);
+ remote_event_poll(state , &state->local->trigger);
+ remote_event_poll(state , &state->local->recycle);
}
/* Round up message sizes so that any space at the end of a slot is always big
@@ -553,7 +566,7 @@ request_poll(VCHIQ_STATE_T *state, VCHIQ_SERVICE_T *service, int poll_type)
wmb();
/* ... and ensure the slot handler runs. */
- remote_event_signal_local(&state->local->trigger);
+ remote_event_signal_local(state, &state->local->trigger);
}
/* Called from queue_message, by the slot handler and application threads,
@@ -1016,7 +1029,7 @@ queue_message_sync(VCHIQ_STATE_T *state, VCHIQ_SERVICE_T *service,
(lmutex_lock_interruptible(&state->sync_mutex) != 0))
return VCHIQ_RETRY;
- remote_event_wait(&local->sync_release);
+ remote_event_wait(state, &local->sync_release);
rmb();
@@ -1097,9 +1110,6 @@ queue_message_sync(VCHIQ_STATE_T *state, VCHIQ_SERVICE_T *service,
size);
}
- /* Make sure the new header is visible to the peer. */
- wmb();
-
remote_event_signal(&state->remote->sync_trigger);
if (VCHIQ_MSG_TYPE(msgid) != VCHIQ_MSG_PAUSE)
@@ -1824,8 +1834,17 @@ parse_rx_slots(VCHIQ_STATE_T *state)
state->slot_data)->version;
up(&state->connect);
break;
+/*
+ * XXXMDC Apparently nothing uses this
+ * https://github.com/raspberrypi/linux/commit/14f4d72fb799a9b3170a45ab80d4a3ddad541960
+ * but taking out the master bits is a whole new job
+ */
case VCHIQ_MSG_BULK_RX:
- case VCHIQ_MSG_BULK_TX: {
+ case VCHIQ_MSG_BULK_TX:
+ WARN_ON(1);
+ break;
+#if 0
+ {
VCHIQ_BULK_QUEUE_T *queue;
WARN_ON(!state->is_master);
queue = (type == VCHIQ_MSG_BULK_RX) ?
@@ -1887,9 +1906,11 @@ parse_rx_slots(VCHIQ_STATE_T *state)
lmutex_unlock(&service->bulk_mutex);
if (resolved)
notify_bulks(service, queue,
- 1/*retry_poll*/);
+ 1//retry_poll
+ );
}
- } break;
+ }
+#endif
case VCHIQ_MSG_BULK_RX_DONE:
case VCHIQ_MSG_BULK_TX_DONE:
WARN_ON(state->is_master);
@@ -2050,7 +2071,7 @@ slot_handler_func(void *v)
while (1) {
DEBUG_COUNT(SLOT_HANDLER_COUNT);
DEBUG_TRACE(SLOT_HANDLER_LINE);
- remote_event_wait(&local->trigger);
+ remote_event_wait(state, &local->trigger);
rmb();
@@ -2140,8 +2161,7 @@ recycle_func(void *v)
VCHIQ_SHARED_STATE_T *local = state->local;
while (1) {
- remote_event_wait(&local->recycle);
-
+ remote_event_wait(state, &local->recycle);
process_free_queue(state);
}
return 0;
@@ -2164,7 +2184,7 @@ sync_func(void *v)
int type;
unsigned int localport, remoteport;
- remote_event_wait(&local->sync_trigger);
+ remote_event_wait(state, &local->sync_trigger);
rmb();
@@ -2281,7 +2301,7 @@ get_conn_state_name(VCHIQ_CONNSTATE_T conn_state)
VCHIQ_SLOT_ZERO_T *
vchiq_init_slots(void *mem_base, int mem_size)
{
- int mem_align = (VCHIQ_SLOT_SIZE - (int)mem_base) & VCHIQ_SLOT_MASK;
+ int mem_align = (int)((VCHIQ_SLOT_SIZE - (long)mem_base) & VCHIQ_SLOT_MASK);
VCHIQ_SLOT_ZERO_T *slot_zero =
(VCHIQ_SLOT_ZERO_T *)((char *)mem_base + mem_align);
int num_slots = (mem_size - mem_align)/VCHIQ_SLOT_SIZE;
@@ -2477,24 +2497,24 @@ vchiq_init_state(VCHIQ_STATE_T *state, VCHIQ_SLOT_ZERO_T *slot_zero,
state->data_use_count = 0;
state->data_quota = state->slot_queue_available - 1;
- local->trigger.event = &state->trigger_event;
- remote_event_create(&local->trigger);
+ local->trigger.event = offsetof(VCHIQ_STATE_T, trigger_event);
+ remote_event_create(state, &local->trigger);
local->tx_pos = 0;
- local->recycle.event = &state->recycle_event;
- remote_event_create(&local->recycle);
+ local->recycle.event = offsetof(VCHIQ_STATE_T, recycle_event);
+ remote_event_create(state, &local->recycle);
local->slot_queue_recycle = state->slot_queue_available;
- local->sync_trigger.event = &state->sync_trigger_event;
- remote_event_create(&local->sync_trigger);
+ local->sync_trigger.event = offsetof(VCHIQ_STATE_T, sync_trigger_event);
+ remote_event_create(state, &local->sync_trigger);
- local->sync_release.event = &state->sync_release_event;
- remote_event_create(&local->sync_release);
+ local->sync_release.event = offsetof(VCHIQ_STATE_T, sync_release_event);
+ remote_event_create(state, &local->sync_release);
/* At start-of-day, the slot is empty and available */
((VCHIQ_HEADER_T *)SLOT_DATA_FROM_INDEX(state, local->slot_sync))->msgid
= VCHIQ_MSGID_PADDING;
- remote_event_signal_local(&local->sync_release);
+ remote_event_signal_local(state, &local->sync_release);
local->debug[DEBUG_ENTRIES] = DEBUG_MAX;
@@ -3381,7 +3401,7 @@ vchiq_bulk_transfer(VCHIQ_SERVICE_HANDLE_T handle,
(dir == VCHIQ_BULK_TRANSMIT) ?
VCHIQ_POLL_TXNOTIFY : VCHIQ_POLL_RXNOTIFY);
} else {
- int payload[2] = { (int)bulk->data, bulk->size };
+ uint32_t payload[2] = { (uint32_t)(uintptr_t)bulk->data, bulk->size };
VCHIQ_ELEMENT_T element = { payload, sizeof(payload) };
status = queue_message(state, NULL,
@@ -3525,7 +3545,6 @@ static void
release_message_sync(VCHIQ_STATE_T *state, VCHIQ_HEADER_T *header)
{
header->msgid = VCHIQ_MSGID_PADDING;
- wmb();
remote_event_signal(&state->remote->sync_release);
}
diff --git a/sys/contrib/vchiq/interface/vchiq_arm/vchiq_core.h b/sys/contrib/vchiq/interface/vchiq_arm/vchiq_core.h
index 38ede407f4f4..4e3f41203bc4 100644
--- a/sys/contrib/vchiq/interface/vchiq_arm/vchiq_core.h
+++ b/sys/contrib/vchiq/interface/vchiq_arm/vchiq_core.h
@@ -184,12 +184,21 @@ enum {
#if VCHIQ_ENABLE_DEBUG
#define DEBUG_INITIALISE(local) int *debug_ptr = (local)->debug;
+#if defined(__aarch64__)
+#define DEBUG_TRACE(d) \
+ do { debug_ptr[DEBUG_ ## d] = __LINE__; dsb(sy); } while (0)
+#define DEBUG_VALUE(d, v) \
+ do { debug_ptr[DEBUG_ ## d] = (v); dsb(sy); } while (0)
+#define DEBUG_COUNT(d) \
+ do { debug_ptr[DEBUG_ ## d]++; dsb(sy); } while (0)
+#else
#define DEBUG_TRACE(d) \
do { debug_ptr[DEBUG_ ## d] = __LINE__; dsb(); } while (0)
#define DEBUG_VALUE(d, v) \
do { debug_ptr[DEBUG_ ## d] = (v); dsb(); } while (0)
#define DEBUG_COUNT(d) \
do { debug_ptr[DEBUG_ ## d]++; dsb(); } while (0)
+#endif
#else /* VCHIQ_ENABLE_DEBUG */
@@ -265,7 +274,7 @@ typedef struct vchiq_bulk_queue_struct {
typedef struct remote_event_struct {
int armed;
int fired;
- struct semaphore *event;
+ uint32_t event;
} REMOTE_EVENT_T;
typedef struct opaque_platform_state_t *VCHIQ_PLATFORM_STATE_T;
diff --git a/sys/contrib/vchiq/interface/vchiq_arm/vchiq_ioctl.h b/sys/contrib/vchiq/interface/vchiq_arm/vchiq_ioctl.h
index 617479eff136..90348ca4b0d0 100644
--- a/sys/contrib/vchiq/interface/vchiq_arm/vchiq_ioctl.h
+++ b/sys/contrib/vchiq/interface/vchiq_arm/vchiq_ioctl.h
@@ -127,4 +127,125 @@ typedef struct {
#define VCHIQ_IOC_CLOSE_DELIVERED _IO(VCHIQ_IOC_MAGIC, 17)
#define VCHIQ_IOC_MAX 17
+
+/*
+ * COMPAT_FREEBSD32
+ */
+
+typedef struct {
+ unsigned int config_size;
+ /*VCHIQ_CONFIG_T * */ uint32_t pconfig;
+} VCHIQ_GET_CONFIG32_T;
+
+typedef struct {
+ unsigned int handle;
+ /*void * */ uint32_t data;
+ unsigned int size;
+ /*void * */ uint32_t userdata;
+ VCHIQ_BULK_MODE_T mode;
+} VCHIQ_QUEUE_BULK_TRANSFER32_T;
+
+typedef struct {
+ unsigned int handle;
+ unsigned int count;
+ const /*VCHIQ_ELEMENT_T * */ uint32_t elements;
+} VCHIQ_QUEUE_MESSAGE32_T;
+
+typedef struct {
+ unsigned int handle;
+ int blocking;
+ unsigned int bufsize;
+ /*void * */ uint32_t buf;
+} VCHIQ_DEQUEUE_MESSAGE32_T;
+
+typedef struct {
+ /*void * */ uint32_t virt_addr;
+ /*size_t*/ uint32_t num_bytes;
+} VCHIQ_DUMP_MEM32_T;
+
+typedef struct {
+ VCHIQ_REASON_T reason;
+ /* VCHIQ_HEADER_T * */ uint32_t header;
+ /* void * */ uint32_t service_userdata;
+ /* void * */ uint32_t bulk_userdata;
+} VCHIQ_COMPLETION_DATA32_T;
+
+typedef struct {
+ unsigned int count;
+ /* VCHIQ_COMPLETION_DATA32_T * */ uint32_t buf;
+ unsigned int msgbufsize;
+ unsigned int msgbufcount; /* IN/OUT */
+ /* void ** */ uint32_t msgbufs;
+} VCHIQ_AWAIT_COMPLETION32_T;
+
+typedef struct vchiq_service_params32_struct {
+ int fourcc;
+ /* VCHIQ_CALLBACK_T */ uint32_t callback;
+ /*void * */ uint32_t userdata;
+ short version; /* Increment for non-trivial changes */
+ short version_min; /* Update for incompatible changes */
+} VCHIQ_SERVICE_PARAMS32_T;
+
+typedef struct {
+ VCHIQ_SERVICE_PARAMS32_T params;
+ int is_open;
+ int is_vchi;
+ unsigned int handle; /* OUT */
+} VCHIQ_CREATE_SERVICE32_T;
+
+typedef struct {
+ const /*void */ uint32_t data;
+ unsigned int size;
+} VCHIQ_ELEMENT32_T;
+
+
+#define VCHIQ_IOC_GET_CONFIG32 \
+ _IOC_NEWTYPE( \
+ VCHIQ_IOC_GET_CONFIG, \
+ VCHIQ_GET_CONFIG32_T \
+ )
+
+#define VCHIQ_IOC_QUEUE_BULK_TRANSMIT32 \
+ _IOC_NEWTYPE( \
+ VCHIQ_IOC_QUEUE_BULK_TRANSMIT, \
+ VCHIQ_QUEUE_BULK_TRANSFER32_T \
+ )
+
+#define VCHIQ_IOC_QUEUE_BULK_RECEIVE32 \
+ _IOC_NEWTYPE( \
+ VCHIQ_IOC_QUEUE_BULK_RECEIVE, \
+ VCHIQ_QUEUE_BULK_TRANSFER32_T \
+ )
+
+#define VCHIQ_IOC_QUEUE_MESSAGE32 \
+ _IOC_NEWTYPE( \
+ VCHIQ_IOC_QUEUE_MESSAGE, \
+ VCHIQ_QUEUE_MESSAGE32_T \
+ )
+
+#define VCHIQ_IOC_DEQUEUE_MESSAGE32 \
+ _IOC_NEWTYPE( \
+ VCHIQ_IOC_DEQUEUE_MESSAGE, \
+ VCHIQ_DEQUEUE_MESSAGE32_T \
+ )
+
+#define VCHIQ_IOC_DUMP_PHYS_MEM32 \
+ _IOC_NEWTYPE( \
+ VCHIQ_IOC_DUMP_PHYS_MEM, \
+ VCHIQ_DUMP_MEM32_T \
+ )
+
+#define VCHIQ_IOC_AWAIT_COMPLETION32 \
+ _IOC_NEWTYPE( \
+ VCHIQ_IOC_AWAIT_COMPLETION, \
+ VCHIQ_AWAIT_COMPLETION32_T \
+ )
+
+#define VCHIQ_IOC_CREATE_SERVICE32 \
+ _IOC_NEWTYPE( \
+ VCHIQ_IOC_CREATE_SERVICE, \
+ VCHIQ_CREATE_SERVICE32_T \
+ )
+
+
#endif
diff --git a/sys/contrib/vchiq/interface/vchiq_arm/vchiq_kmod.c b/sys/contrib/vchiq/interface/vchiq_arm/vchiq_kmod.c
index 190b6d16781e..9fcc0e7c2051 100644
--- a/sys/contrib/vchiq/interface/vchiq_arm/vchiq_kmod.c
+++ b/sys/contrib/vchiq/interface/vchiq_arm/vchiq_kmod.c
@@ -47,7 +47,11 @@ __FBSDID("$FreeBSD$");
#include <dev/ofw/ofw_bus_subr.h>
#include <machine/bus.h>
+/* XXXMDC Is this necessary at all? */
+#if defined(__aarch64__)
+#else
#include <machine/fdt.h>
+#endif
#include "vchiq_arm.h"
#include "vchiq_2835.h"
@@ -78,13 +82,31 @@ struct bcm_vchiq_softc {
static struct bcm_vchiq_softc *bcm_vchiq_sc = NULL;
-#define BSD_DTB 1
-#define UPSTREAM_DTB 2
+
+#define CONFIG_INVALID 0
+#define CONFIG_VALID 1 << 0
+#define BSD_REG_ADDRS 1 << 1
+#define LONG_BULK_SPACE 1 << 2
+
+/*
+ * Also controls the use of the standard VC address offset for bulk data DMA
+ * (normal bulks use that offset; bulks for long address spaces use physical
+ * page addresses)
+ */
+extern unsigned int g_long_bulk_space;
+
+
+/*
+ * XXXMDC
+ * The man page for ofw_bus_is_compatible describes ``features''
+ * as ``can be used''. Here we use understand them as ``must be used''
+ */
+
static struct ofw_compat_data compat_data[] = {
- {"broadcom,bcm2835-vchiq", BSD_DTB},
- {"brcm,bcm2835-vchiq", UPSTREAM_DTB},
- {"brcm,bcm2711-vchiq", UPSTREAM_DTB},
- {NULL, 0}
+ {"broadcom,bcm2835-vchiq", BSD_REG_ADDRS | CONFIG_VALID},
+ {"brcm,bcm2835-vchiq", CONFIG_VALID},
+ {"brcm,bcm2711-vchiq", LONG_BULK_SPACE | CONFIG_VALID},
+ {NULL, CONFIG_INVALID}
};
#define vchiq_read_4(reg) \
@@ -119,13 +141,23 @@ bcm_vchiq_intr(void *arg)
void
remote_event_signal(REMOTE_EVENT_T *event)
{
- event->fired = 1;
+ wmb();
+
+ event->fired = 1;
/* The test on the next line also ensures the write on the previous line
has completed */
+ /* UPDATE: not on arm64, it would seem... */
+#if defined(__aarch64__)
+ dsb(sy);
+#endif
if (event->armed) {
/* trigger vc interrupt */
+#if defined(__aarch64__)
+ dsb(sy);
+#else
dsb();
+#endif
vchiq_write_4(0x48, 0);
}
}
@@ -134,13 +166,17 @@ static int
bcm_vchiq_probe(device_t dev)
{
- if (ofw_bus_search_compatible(dev, compat_data)->ocd_data == 0)
+ if ((ofw_bus_search_compatible(dev, compat_data)->ocd_data & CONFIG_VALID) == 0)
return (ENXIO);
device_set_desc(dev, "BCM2835 VCHIQ");
return (BUS_PROBE_DEFAULT);
}
+/* debug_sysctl */
+extern int vchiq_core_log_level;
+extern int vchiq_arm_log_level;
+
static int
bcm_vchiq_attach(device_t dev)
{
@@ -168,14 +204,36 @@ bcm_vchiq_attach(device_t dev)
return (ENXIO);
}
- if (ofw_bus_search_compatible(dev, compat_data)->ocd_data == UPSTREAM_DTB)
+ uintptr_t dev_compat_d = ofw_bus_search_compatible(dev, compat_data)->ocd_data;
+ /* XXXMDC: shouldn't happen (checked for in probe)--but, for symmetry */
+ if ((dev_compat_d & CONFIG_VALID) == 0){
+ device_printf(dev, "attempting to attach using invalid config.\n");
+ bus_release_resource(dev, SYS_RES_IRQ, rid, sc->irq_res);
+ return (EINVAL);
+ }
+ if ((dev_compat_d & BSD_REG_ADDRS) == 0)
sc->regs_offset = -0x40;
+ if(dev_compat_d & LONG_BULK_SPACE)
+ g_long_bulk_space = 1;
node = ofw_bus_get_node(dev);
if ((OF_getencprop(node, "cache-line-size", &cell, sizeof(cell))) > 0)
g_cache_line_size = cell;
vchiq_core_initialize();
+
+ /* debug_sysctl */
+ struct sysctl_ctx_list *ctx_l = device_get_sysctl_ctx(dev);
+ struct sysctl_oid *tree_node = device_get_sysctl_tree(dev);
+ struct sysctl_oid_list *tree = SYSCTL_CHILDREN(tree_node);
+ SYSCTL_ADD_INT(
+ ctx_l, tree, OID_AUTO, "log", CTLFLAG_RW,
+ &vchiq_core_log_level, vchiq_core_log_level, "log level"
+ );
+ SYSCTL_ADD_INT(
+ ctx_l, tree, OID_AUTO, "arm_log", CTLFLAG_RW,
+ &vchiq_arm_log_level, vchiq_arm_log_level, "arm log level"
+ );
/* Setup and enable the timer */
if (bus_setup_intr(dev, sc->irq_res, INTR_TYPE_MISC | INTR_MPSAFE,
diff --git a/sys/contrib/vchiq/interface/vchiq_arm/vchiq_pagelist.h b/sys/contrib/vchiq/interface/vchiq_arm/vchiq_pagelist.h
index 72c362464cc2..d1cb9f1e1658 100644
--- a/sys/contrib/vchiq/interface/vchiq_arm/vchiq_pagelist.h
+++ b/sys/contrib/vchiq/interface/vchiq_arm/vchiq_pagelist.h
@@ -42,10 +42,10 @@
#define PAGELIST_READ_WITH_FRAGMENTS 2
typedef struct pagelist_struct {
- unsigned long length;
- unsigned short type;
- unsigned short offset;
- unsigned long addrs[1]; /* N.B. 12 LSBs hold the number of following
+ uint32_t length;
+ uint16_t type;
+ uint16_t offset;
+ uint32_t addrs[1]; /* N.B. 12 LSBs hold the number of following
pages at consecutive addresses. */
} PAGELIST_T;
diff --git a/sys/contrib/vchiq/interface/vchiq_arm/vchiq_shim.c b/sys/contrib/vchiq/interface/vchiq_arm/vchiq_shim.c
index cc8ef2e071f8..f33c545cea45 100644
--- a/sys/contrib/vchiq/interface/vchiq_arm/vchiq_shim.c
+++ b/sys/contrib/vchiq/interface/vchiq_arm/vchiq_shim.c
@@ -398,7 +398,7 @@ EXPORT_SYMBOL(vchi_msg_queuev);
***********************************************************/
int32_t vchi_held_msg_release(VCHI_HELD_MSG_T *message)
{
- vchiq_release_message((VCHIQ_SERVICE_HANDLE_T)message->service,
+ vchiq_release_message((VCHIQ_SERVICE_HANDLE_T)(size_t)message->service,
(VCHIQ_HEADER_T *)message->message);
return 0;
@@ -444,7 +444,7 @@ int32_t vchi_msg_hold(VCHI_SERVICE_HANDLE_T handle,
*msg_size = header->size;
message_handle->service =
- (struct opaque_vchi_service_t *)service->handle;
+ (struct opaque_vchi_service_t *)(unsigned long)service->handle;
message_handle->message = header;
return 0;