Module Name: src
Committed By: skrll
Date: Thu Jan 12 05:41:25 UTC 2017
Modified Files:
src/sys/external/bsd/vchiq/dist/interface/vchi: vchi.h vchi_common.h
src/sys/external/bsd/vchiq/dist/interface/vchiq_arm: vchiq.h
vchiq_2835_arm.c vchiq_arm.c vchiq_arm.h vchiq_cfg.h
vchiq_connected.h vchiq_core.c vchiq_core.h vchiq_genversion
vchiq_if.h vchiq_ioctl.h vchiq_shim.c vchiq_util.c vchiq_util.h
Added Files:
src/sys/external/bsd/vchiq/dist/interface/vchiq_arm: vchiq_debugfs.h
Removed Files:
src/sys/external/bsd/vchiq/dist/interface/vchiq_arm: vchiq_proc.c
Log Message:
Sync with latest github/raspberrypi/linux sources
XXX should provide a vchiq2netbsd and cvs import
To generate a diff of this commit:
cvs rdiff -u -r1.1 -r1.2 \
src/sys/external/bsd/vchiq/dist/interface/vchi/vchi.h \
src/sys/external/bsd/vchiq/dist/interface/vchi/vchi_common.h
cvs rdiff -u -r1.1 -r1.2 \
src/sys/external/bsd/vchiq/dist/interface/vchiq_arm/vchiq.h \
src/sys/external/bsd/vchiq/dist/interface/vchiq_arm/vchiq_arm.h \
src/sys/external/bsd/vchiq/dist/interface/vchiq_arm/vchiq_cfg.h \
src/sys/external/bsd/vchiq/dist/interface/vchiq_arm/vchiq_connected.h \
src/sys/external/bsd/vchiq/dist/interface/vchiq_arm/vchiq_genversion
cvs rdiff -u -r1.17 -r1.18 \
src/sys/external/bsd/vchiq/dist/interface/vchiq_arm/vchiq_2835_arm.c \
src/sys/external/bsd/vchiq/dist/interface/vchiq_arm/vchiq_arm.c
cvs rdiff -u -r1.10 -r1.11 \
src/sys/external/bsd/vchiq/dist/interface/vchiq_arm/vchiq_core.c
cvs rdiff -u -r1.3 -r1.4 \
src/sys/external/bsd/vchiq/dist/interface/vchiq_arm/vchiq_core.h
cvs rdiff -u -r0 -r1.1 \
src/sys/external/bsd/vchiq/dist/interface/vchiq_arm/vchiq_debugfs.h
cvs rdiff -u -r1.2 -r1.3 \
src/sys/external/bsd/vchiq/dist/interface/vchiq_arm/vchiq_if.h \
src/sys/external/bsd/vchiq/dist/interface/vchiq_arm/vchiq_ioctl.h \
src/sys/external/bsd/vchiq/dist/interface/vchiq_arm/vchiq_util.c \
src/sys/external/bsd/vchiq/dist/interface/vchiq_arm/vchiq_util.h
cvs rdiff -u -r1.2 -r0 \
src/sys/external/bsd/vchiq/dist/interface/vchiq_arm/vchiq_proc.c
cvs rdiff -u -r1.5 -r1.6 \
src/sys/external/bsd/vchiq/dist/interface/vchiq_arm/vchiq_shim.c
Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.
Modified files:
Index: src/sys/external/bsd/vchiq/dist/interface/vchi/vchi.h
diff -u src/sys/external/bsd/vchiq/dist/interface/vchi/vchi.h:1.1 src/sys/external/bsd/vchiq/dist/interface/vchi/vchi.h:1.2
--- src/sys/external/bsd/vchiq/dist/interface/vchi/vchi.h:1.1 Fri Mar 8 12:32:30 2013
+++ src/sys/external/bsd/vchiq/dist/interface/vchi/vchi.h Thu Jan 12 05:41:25 2017
@@ -220,7 +220,12 @@ extern int32_t vchi_service_use( const V
// Routine to decrement ref count on a named service
extern int32_t vchi_service_release( const VCHI_SERVICE_HANDLE_T handle );
-// Routine to send a message accross a service
+// Routine to set a control option for a named service
+extern int32_t vchi_service_set_option( const VCHI_SERVICE_HANDLE_T handle,
+ VCHI_SERVICE_OPTION_T option,
+ int value);
+
+// Routine to send a message across a service
extern int32_t vchi_msg_queue( VCHI_SERVICE_HANDLE_T handle,
const void *data,
uint32_t data_size,
Index: src/sys/external/bsd/vchiq/dist/interface/vchi/vchi_common.h
diff -u src/sys/external/bsd/vchiq/dist/interface/vchi/vchi_common.h:1.1 src/sys/external/bsd/vchiq/dist/interface/vchi/vchi_common.h:1.2
--- src/sys/external/bsd/vchiq/dist/interface/vchi/vchi_common.h:1.1 Fri Mar 8 12:32:30 2013
+++ src/sys/external/bsd/vchiq/dist/interface/vchi/vchi_common.h Thu Jan 12 05:41:25 2017
@@ -110,7 +110,19 @@ typedef enum
VCHI_CALLBACK_REASON_MAX
} VCHI_CALLBACK_REASON_T;
-//Calback used by all services / bulk transfers
+// service control options
+typedef enum
+{
+ VCHI_SERVICE_OPTION_MIN,
+
+ VCHI_SERVICE_OPTION_TRACE,
+ VCHI_SERVICE_OPTION_SYNCHRONOUS,
+
+ VCHI_SERVICE_OPTION_MAX
+} VCHI_SERVICE_OPTION_T;
+
+
+//Callback used by all services / bulk transfers
typedef void (*VCHI_CALLBACK_T)( void *callback_param, //my service local param
VCHI_CALLBACK_REASON_T reason,
void *handle ); //for transmitting msg's only
Index: src/sys/external/bsd/vchiq/dist/interface/vchiq_arm/vchiq.h
diff -u src/sys/external/bsd/vchiq/dist/interface/vchiq_arm/vchiq.h:1.1 src/sys/external/bsd/vchiq/dist/interface/vchiq_arm/vchiq.h:1.2
--- src/sys/external/bsd/vchiq/dist/interface/vchiq_arm/vchiq.h:1.1 Fri Mar 8 12:32:30 2013
+++ src/sys/external/bsd/vchiq/dist/interface/vchiq_arm/vchiq.h Thu Jan 12 05:41:25 2017
@@ -38,4 +38,3 @@
#include "vchiq_util.h"
#endif
-
Index: src/sys/external/bsd/vchiq/dist/interface/vchiq_arm/vchiq_arm.h
diff -u src/sys/external/bsd/vchiq/dist/interface/vchiq_arm/vchiq_arm.h:1.1 src/sys/external/bsd/vchiq/dist/interface/vchiq_arm/vchiq_arm.h:1.2
--- src/sys/external/bsd/vchiq/dist/interface/vchiq_arm/vchiq_arm.h:1.1 Fri Mar 8 12:32:31 2013
+++ src/sys/external/bsd/vchiq/dist/interface/vchiq_arm/vchiq_arm.h Thu Jan 12 05:41:25 2017
@@ -1,4 +1,5 @@
/**
+ * Copyright (c) 2014 Raspberry Pi (Trading) Ltd. All rights reserved.
* Copyright (c) 2010-2012 Broadcom. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -35,6 +36,7 @@
#define VCHIQ_ARM_H
#include "vchiq_core.h"
+#include "vchiq_debugfs.h"
enum vc_suspend_status {
@@ -152,6 +154,14 @@ vchiq_check_resume(VCHIQ_STATE_T *state)
extern void
vchiq_check_suspend(VCHIQ_STATE_T *state);
+ VCHIQ_STATUS_T
+vchiq_use_service(VCHIQ_SERVICE_HANDLE_T handle);
+
+extern VCHIQ_STATUS_T
+vchiq_release_service(VCHIQ_SERVICE_HANDLE_T handle);
+
+extern VCHIQ_STATUS_T
+vchiq_check_service(VCHIQ_SERVICE_T *service);
extern VCHIQ_STATUS_T
vchiq_platform_suspend(VCHIQ_STATE_T *state);
@@ -180,21 +190,31 @@ vchiq_use_internal(VCHIQ_STATE_T *state,
extern VCHIQ_STATUS_T
vchiq_release_internal(VCHIQ_STATE_T *state, VCHIQ_SERVICE_T *service);
-void
+// extern VCHIQ_DEBUGFS_NODE_T *
+// vchiq_instance_get_debugfs_node(VCHIQ_INSTANCE_T instance);
+
+extern int
+vchiq_instance_get_use_count(VCHIQ_INSTANCE_T instance);
+
+extern int
+vchiq_instance_get_pid(VCHIQ_INSTANCE_T instance);
+
+extern int
+vchiq_instance_get_trace(VCHIQ_INSTANCE_T instance);
+
+extern void
+vchiq_instance_set_trace(VCHIQ_INSTANCE_T instance, int trace);
+
+extern void
set_suspend_state(VCHIQ_ARM_STATE_T *arm_state,
enum vc_suspend_status new_state);
-void
+extern void
set_resume_state(VCHIQ_ARM_STATE_T *arm_state,
enum vc_resume_status new_state);
-void
+extern void
start_suspend_timer(VCHIQ_ARM_STATE_T *arm_state);
-extern int vchiq_proc_init(void);
-extern void vchiq_proc_deinit(void);
-extern struct proc_dir_entry *vchiq_proc_top(void);
-extern struct proc_dir_entry *vchiq_clients_top(void);
-
#endif /* VCHIQ_ARM_H */
Index: src/sys/external/bsd/vchiq/dist/interface/vchiq_arm/vchiq_cfg.h
diff -u src/sys/external/bsd/vchiq/dist/interface/vchiq_arm/vchiq_cfg.h:1.1 src/sys/external/bsd/vchiq/dist/interface/vchiq_arm/vchiq_cfg.h:1.2
--- src/sys/external/bsd/vchiq/dist/interface/vchiq_arm/vchiq_cfg.h:1.1 Fri Mar 8 12:32:31 2013
+++ src/sys/external/bsd/vchiq/dist/interface/vchiq_arm/vchiq_cfg.h Thu Jan 12 05:41:25 2017
@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2010-2012 Broadcom. All rights reserved.
+ * Copyright (c) 2010-2014 Broadcom. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -36,11 +36,20 @@
#define VCHIQ_MAGIC VCHIQ_MAKE_FOURCC('V', 'C', 'H', 'I')
/* The version of VCHIQ - change with any non-trivial change */
-#define VCHIQ_VERSION 6
+#define VCHIQ_VERSION 8
/* The minimum compatible version - update to match VCHIQ_VERSION with any
** incompatible change */
#define VCHIQ_VERSION_MIN 3
+/* The version that introduced the VCHIQ_IOC_LIB_VERSION ioctl */
+#define VCHIQ_VERSION_LIB_VERSION 7
+
+/* The version that introduced the VCHIQ_IOC_CLOSE_DELIVERED ioctl */
+#define VCHIQ_VERSION_CLOSE_DELIVERED 7
+
+/* The version that made it safe to use SYNCHRONOUS mode */
+#define VCHIQ_VERSION_SYNCHRONOUS_MODE 8
+
#define VCHIQ_MAX_STATES 1
#define VCHIQ_MAX_SERVICES 4096
#define VCHIQ_MAX_SLOTS 128
Index: src/sys/external/bsd/vchiq/dist/interface/vchiq_arm/vchiq_connected.h
diff -u src/sys/external/bsd/vchiq/dist/interface/vchiq_arm/vchiq_connected.h:1.1 src/sys/external/bsd/vchiq/dist/interface/vchiq_arm/vchiq_connected.h:1.2
--- src/sys/external/bsd/vchiq/dist/interface/vchiq_arm/vchiq_connected.h:1.1 Fri Mar 8 12:32:31 2013
+++ src/sys/external/bsd/vchiq/dist/interface/vchiq_arm/vchiq_connected.h Thu Jan 12 05:41:25 2017
@@ -48,4 +48,3 @@ void vchiq_add_connected_callback(VCHIQ_
void vchiq_call_connected_callbacks(void);
#endif /* VCHIQ_CONNECTED_H */
-
Index: src/sys/external/bsd/vchiq/dist/interface/vchiq_arm/vchiq_genversion
diff -u src/sys/external/bsd/vchiq/dist/interface/vchiq_arm/vchiq_genversion:1.1 src/sys/external/bsd/vchiq/dist/interface/vchiq_arm/vchiq_genversion:1.2
--- src/sys/external/bsd/vchiq/dist/interface/vchiq_arm/vchiq_genversion:1.1 Fri Mar 8 12:32:31 2013
+++ src/sys/external/bsd/vchiq/dist/interface/vchiq_arm/vchiq_genversion Thu Jan 12 05:41:25 2017
@@ -41,11 +41,11 @@ if ( -d "$root/.git" ) {
$tainted =~ s/[ \r\n]*$//; # chomp may not be enough (cygwin).
$tainted =~ s/^[ \r\n]*//; # chomp may not be enough (cygwin).
if (length $tainted) {
- $version = join ' ', $version, "(tainted)";
- }
- else {
- $version = join ' ', $version, "(clean)";
- }
+ $version = join ' ', $version, "(tainted)";
+ }
+ else {
+ $version = join ' ', $version, "(clean)";
+ }
}
}
}
@@ -85,5 +85,3 @@ const char *vchiq_get_build_time( void )
return vchiq_build_time;
}
EOF
-
-
Index: src/sys/external/bsd/vchiq/dist/interface/vchiq_arm/vchiq_2835_arm.c
diff -u src/sys/external/bsd/vchiq/dist/interface/vchiq_arm/vchiq_2835_arm.c:1.17 src/sys/external/bsd/vchiq/dist/interface/vchiq_arm/vchiq_2835_arm.c:1.18
--- src/sys/external/bsd/vchiq/dist/interface/vchiq_arm/vchiq_2835_arm.c:1.17 Thu May 1 03:07:50 2014
+++ src/sys/external/bsd/vchiq/dist/interface/vchiq_arm/vchiq_2835_arm.c Thu Jan 12 05:41:25 2017
@@ -63,16 +63,17 @@ typedef struct vchiq_2835_state_struct {
VCHIQ_ARM_STATE_T arm_state;
} VCHIQ_2835_ARM_STATE_T;
-static char *g_slot_mem;
-static int g_slot_mem_size;
-paddr_t g_slot_phys, g_slot_phys_cpu;
/* BSD DMA */
static bus_dmamap_t dma_map;
-static FRAGMENTS_T *g_fragments_base;
-static FRAGMENTS_T *g_free_fragments;
+
+static unsigned int g_cache_line_size = CACHE_LINE_SIZE;
+static unsigned int g_fragments_size;
+static char *g_fragments_base;
+static char *g_free_fragments;
+
struct semaphore g_free_fragments_sema;
+static struct semaphore g_free_fragments_mutex;
-static DEFINE_SEMAPHORE(g_free_fragments_mutex);
int __init
vchiq_platform_init(VCHIQ_STATE_T *state)
@@ -80,19 +81,25 @@ vchiq_platform_init(VCHIQ_STATE_T *state
VCHIQ_SLOT_ZERO_T *vchiq_slot_zero;
bus_dma_segment_t dma_segs[1];
int dma_nsegs;
- int frag_mem_size;
+ void *slot_mem;
+ bus_addr_t slot_phys;
+ int slot_mem_size, frag_mem_size;
int err;
int i;
_sema_init(&g_free_fragments_mutex, 1);
+ g_cache_line_size = 32;
+
+ g_fragments_size = 2 * g_cache_line_size;
+
/* Allocate space for the channels in coherent memory */
- g_slot_mem_size = PAGE_ALIGN(TOTAL_SLOTS * VCHIQ_SLOT_SIZE);
- frag_mem_size = PAGE_ALIGN(sizeof(FRAGMENTS_T) * MAX_FRAGMENTS);
+ slot_mem_size = PAGE_ALIGN(TOTAL_SLOTS * VCHIQ_SLOT_SIZE);
+ frag_mem_size = PAGE_ALIGN(g_fragments_size * MAX_FRAGMENTS);
dma_nsegs = __arraycount(dma_segs);
err = bus_dmamem_alloc(&bcm2835_bus_dma_tag,
- g_slot_mem_size + frag_mem_size, PAGE_SIZE, 0,
+ slot_mem_size + frag_mem_size, PAGE_SIZE, 0,
dma_segs, dma_nsegs, &dma_nsegs, BUS_DMA_WAITOK);
if (err) {
vchiq_log_error(vchiq_core_log_level, "Unable to allocate channel memory");
@@ -101,8 +108,8 @@ vchiq_platform_init(VCHIQ_STATE_T *state
}
err = bus_dmamem_map(&bcm2835_bus_dma_tag,
- dma_segs, dma_nsegs, g_slot_mem_size + frag_mem_size,
- (void **)&g_slot_mem, BUS_DMA_COHERENT | BUS_DMA_WAITOK);
+ dma_segs, dma_nsegs, slot_mem_size + frag_mem_size,
+ (void **)&slot_mem, BUS_DMA_COHERENT | BUS_DMA_WAITOK);
if (err) {
vchiq_log_error(vchiq_core_log_level, "Unable to map channel memory");
err = -ENOMEM;
@@ -110,8 +117,8 @@ vchiq_platform_init(VCHIQ_STATE_T *state
}
err = bus_dmamap_create(&bcm2835_bus_dma_tag,
- g_slot_mem_size + frag_mem_size, 1, /* maxsize, nsegments */
- g_slot_mem_size + frag_mem_size, 0, /* maxsegsize, boundary */
+ slot_mem_size + frag_mem_size, 1, /* maxsize, nsegments */
+ slot_mem_size + frag_mem_size, 0, /* maxsegsize, boundary */
BUS_DMA_WAITOK,
&dma_map);
if (err) {
@@ -120,40 +127,41 @@ vchiq_platform_init(VCHIQ_STATE_T *state
goto failed_alloc;
}
- err = bus_dmamap_load(&bcm2835_bus_dma_tag, dma_map, g_slot_mem,
- g_slot_mem_size + frag_mem_size, NULL, BUS_DMA_WAITOK);
+ err = bus_dmamap_load(&bcm2835_bus_dma_tag, dma_map, slot_mem,
+ slot_mem_size + frag_mem_size, NULL, BUS_DMA_WAITOK);
if (err) {
vchiq_log_error(vchiq_core_log_level, "cannot load DMA map (%d)", err);
err = -ENOMEM;
goto failed_load;
}
- g_slot_phys = dma_map->dm_segs[0].ds_addr;
+ slot_phys = dma_map->dm_segs[0].ds_addr;
vchiq_log_info(vchiq_arm_log_level,
- "%s: g_slot_phys = %x\n", __func__, (unsigned int)g_slot_phys);
+ "%s: slot_phys = %lx\n", __func__, slot_phys);
- WARN_ON(((int)g_slot_mem & (PAGE_SIZE - 1)) != 0);
+ WARN_ON(((int)slot_mem & (PAGE_SIZE - 1)) != 0);
- vchiq_slot_zero = vchiq_init_slots(g_slot_mem, g_slot_mem_size);
+ vchiq_slot_zero = vchiq_init_slots(slot_mem, slot_mem_size);
if (!vchiq_slot_zero) {
err = -EINVAL;
goto failed_init_slots;
}
vchiq_slot_zero->platform_data[VCHIQ_PLATFORM_FRAGMENTS_OFFSET_IDX] =
- (int)g_slot_phys + g_slot_mem_size;
+ (int)slot_phys + slot_mem_size;
vchiq_slot_zero->platform_data[VCHIQ_PLATFORM_FRAGMENTS_COUNT_IDX] =
MAX_FRAGMENTS;
- g_fragments_base = (FRAGMENTS_T *)(g_slot_mem + g_slot_mem_size);
- g_slot_mem_size += frag_mem_size;
+ g_fragments_base = (char *)slot_mem + slot_mem_size;
+ slot_mem_size += frag_mem_size;
g_free_fragments = g_fragments_base;
for (i = 0; i < (MAX_FRAGMENTS - 1); i++) {
- *(FRAGMENTS_T **)&g_fragments_base[i] =
- &g_fragments_base[i + 1];
+ *(char **)&g_fragments_base[i*g_fragments_size] =
+ &g_fragments_base[(i + 1)*g_fragments_size];
}
- *(FRAGMENTS_T **)&g_fragments_base[i] = NULL;
+ *(char **)&g_fragments_base[i * g_fragments_size] = NULL;
+
_sema_init(&g_free_fragments_sema, MAX_FRAGMENTS);
if (vchiq_init_state(state, vchiq_slot_zero, 0/*slave*/) !=
@@ -162,17 +170,20 @@ vchiq_platform_init(VCHIQ_STATE_T *state
goto failed_vchiq_init;
}
- bus_dmamap_sync(&bcm2835_bus_dma_tag, dma_map, 0, g_slot_mem_size,
- BUS_DMASYNC_PREWRITE);
- bcm_mbox_write(BCM2835_MBOX_CHAN_VCHIQ, (unsigned int)g_slot_phys);
- bus_dmamap_sync(&bcm2835_bus_dma_tag, dma_map, 0, g_slot_mem_size,
- BUS_DMASYNC_POSTWRITE);
+ /* Send the base address of the slots to VideoCore */
+ dsb(); /* Ensure all writes have completed */
+
+ bus_dmamap_sync(&bcm2835_bus_dma_tag, dma_map, 0, slot_mem_size,
+ BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
+ bcm_mbox_write(BCM2835_MBOX_CHAN_VCHIQ, (unsigned int)slot_phys);
+ bus_dmamap_sync(&bcm2835_bus_dma_tag, dma_map, 0, slot_mem_size,
+ BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
vchiq_log_info(vchiq_arm_log_level,
"vchiq_init - done (slots %x, phys %x)",
- (unsigned int)vchiq_slot_zero, (unsigned int)g_slot_phys);
+ (unsigned int)vchiq_slot_zero, (unsigned int)slot_phys);
- vchiq_call_connected_callbacks();
+ vchiq_call_connected_callbacks();
return 0;
@@ -261,13 +272,15 @@ vchiq_prepare_bulk_data(VCHIQ_BULK_T *bu
int ret;
vchiq_log_info(vchiq_arm_log_level,
- "%s: buf %p size %08x dir %s\n", __func__, buf, size,
+ "%s: buf %p size %08x dir %s", __func__, buf, size,
dir == VCHIQ_BULK_RECEIVE ? "read" : "write");
vaddr_t va = (vaddr_t)buf;
const size_t maxsegs = atop(round_page(va + size) - trunc_page(va));
- int uvmflags = (dir == VCHIQ_BULK_RECEIVE ? VM_PROT_READ : VM_PROT_WRITE);
- int dmaflags = (dir == VCHIQ_BULK_RECEIVE ? BUS_DMA_READ : BUS_DMA_WRITE);
+ const int uvmflags = (dir == VCHIQ_BULK_RECEIVE ?
+ VM_PROT_READ : VM_PROT_WRITE);
+ const int dmaflags = (dir == VCHIQ_BULK_RECEIVE ?
+ BUS_DMA_READ : BUS_DMA_WRITE);
WARN_ON(memhandle != VCHI_MEM_HANDLE_INVALID);
@@ -294,6 +307,7 @@ vchiq_prepare_bulk_data(VCHIQ_BULK_T *bu
goto fail2;
pagelist = bi->pagelist;
+
ret = bus_dmamap_create(&bcm2835_bus_dma_tag, bi->pagelist_size,
nsegs, bi->pagelist_size, 0, BUS_DMA_WAITOK, &bi->pagelist_map);
if (ret != 0)
@@ -305,12 +319,6 @@ vchiq_prepare_bulk_data(VCHIQ_BULK_T *bu
goto fail4;
/*
- * We've now got the bus_addr_t for the pagelist we want the transfer
- * to use.
- */
- bulk->data = (void *)bi->pagelist_map->dm_segs[0].ds_addr;
-
- /*
* Need to wire the buffer pages in.
*/
if (IS_USER_ADDRESS(buf)) {
@@ -334,6 +342,11 @@ vchiq_prepare_bulk_data(VCHIQ_BULK_T *bu
goto fail7;
bulk->handle = memhandle;
+ /*
+ * We've now got the bus_addr_t for the pagelist we want the transfer
+ * to use.
+ */
+ bulk->data = (void *)bi->pagelist_map->dm_segs[0].ds_addr;
pagelist->type = (dir == VCHIQ_BULK_RECEIVE) ?
PAGELIST_READ : PAGELIST_WRITE;
@@ -355,9 +368,9 @@ vchiq_prepare_bulk_data(VCHIQ_BULK_T *bu
/* Partial cache lines (fragments) require special measures */
if ((pagelist->type == PAGELIST_READ) &&
- ((pagelist->offset & (arm_dcache_align - 1)) ||
- ((pagelist->offset + pagelist->length) & (arm_dcache_align - 1)))) {
- FRAGMENTS_T *fragments;
+ ((pagelist->offset & (g_cache_line_size - 1)) ||
+ ((pagelist->offset + pagelist->length) & (g_cache_line_size - 1)))) {
+ char *fragments;
if (down_interruptible(&g_free_fragments_sema) != 0) {
goto fail7;
@@ -366,14 +379,14 @@ vchiq_prepare_bulk_data(VCHIQ_BULK_T *bu
WARN_ON(g_free_fragments == NULL);
down(&g_free_fragments_mutex);
- fragments = (FRAGMENTS_T *) g_free_fragments;
+ fragments = g_free_fragments;
WARN_ON(fragments == NULL);
- g_free_fragments = *(FRAGMENTS_T **) g_free_fragments;
+ g_free_fragments = *(char **) g_free_fragments;
up(&g_free_fragments_mutex);
pagelist->type = PAGELIST_READ_WITH_FRAGMENTS +
- (fragments - g_fragments_base);
+ (fragments - g_fragments_base) / g_fragments_size;
bus_dmamap_sync(&bcm2835_bus_dma_tag, dma_map,
- (char *)fragments - g_slot_mem, sizeof(*fragments),
+ (char *)fragments - g_fragments_base, sizeof(*fragments),
BUS_DMASYNC_PREREAD);
}
@@ -423,9 +436,13 @@ void
vchiq_complete_bulk(VCHIQ_BULK_T *bulk)
{
if (bulk && bulk->remote_data && bulk->actual) {
+ int actual = bulk->actual;
BULKINFO_T *bi = bulk->remote_data;
PAGELIST_T *pagelist = bi->pagelist;
+ vchiq_log_trace(vchiq_arm_log_level,
+ "free_pagelist - %x, %d", (unsigned int)pagelist, actual);
+
bus_dmamap_sync(&bcm2835_bus_dma_tag, bi->pagelist_map, 0,
bi->pagelist_size, BUS_DMASYNC_POSTWRITE);
@@ -435,31 +452,29 @@ vchiq_complete_bulk(VCHIQ_BULK_T *bulk)
/* Deal with any partial cache lines (fragments) */
if (pagelist->type >= PAGELIST_READ_WITH_FRAGMENTS) {
- FRAGMENTS_T *fragments = g_fragments_base +
- (pagelist->type - PAGELIST_READ_WITH_FRAGMENTS);
+ char *fragments = g_fragments_base +
+ (pagelist->type - PAGELIST_READ_WITH_FRAGMENTS) *
+ g_fragments_size;
int head_bytes, tail_bytes;
- int actual = bulk->actual;
bus_dmamap_sync(&bcm2835_bus_dma_tag, dma_map,
- (char *)fragments - g_slot_mem, sizeof(*fragments),
+ (char *)fragments - g_fragments_base, g_fragments_size,
BUS_DMASYNC_POSTREAD);
- head_bytes = (arm_dcache_align - pagelist->offset) &
- (arm_dcache_align - 1);
+ head_bytes = (g_cache_line_size - pagelist->offset) &
+ (g_cache_line_size - 1);
tail_bytes = (pagelist->offset + actual) &
- (arm_dcache_align - 1);
+ (g_cache_line_size - 1);
if ((actual >= 0) && (head_bytes != 0)) {
if (head_bytes > actual)
head_bytes = actual;
if (IS_USER_ADDRESS(bi->buf)) {
- copyout_proc(bi->proc,
- fragments->headbuf, bi->buf,
- head_bytes);
+ copyout_proc(bi->proc, fragments,
+ bi->buf, head_bytes);
} else {
- kcopy(fragments->headbuf, bi->buf,
- head_bytes);
+ kcopy(fragments, bi->buf, head_bytes);
}
}
if ((actual >= 0) && (head_bytes < actual) &&
@@ -469,15 +484,16 @@ vchiq_complete_bulk(VCHIQ_BULK_T *bulk)
if (IS_USER_ADDRESS(bi->buf)) {
copyout_proc(bi->proc,
- fragments->tailbuf, t, tail_bytes);
+ fragments + g_cache_line_size, t,
+ tail_bytes);
} else {
- kcopy(fragments->tailbuf, t,
+ kcopy(fragments + g_cache_line_size, t,
tail_bytes);
}
}
down(&g_free_fragments_mutex);
- *(FRAGMENTS_T **) fragments = g_free_fragments;
+ *(char **)fragments = g_free_fragments;
g_free_fragments = fragments;
up(&g_free_fragments_mutex);
up(&g_free_fragments_sema);
Index: src/sys/external/bsd/vchiq/dist/interface/vchiq_arm/vchiq_arm.c
diff -u src/sys/external/bsd/vchiq/dist/interface/vchiq_arm/vchiq_arm.c:1.17 src/sys/external/bsd/vchiq/dist/interface/vchiq_arm/vchiq_arm.c:1.18
--- src/sys/external/bsd/vchiq/dist/interface/vchiq_arm/vchiq_arm.c:1.17 Sun Jan 8 05:20:51 2017
+++ src/sys/external/bsd/vchiq/dist/interface/vchiq_arm/vchiq_arm.c Thu Jan 12 05:41:25 2017
@@ -1,4 +1,5 @@
/**
+ * Copyright (c) 2014 Raspberry Pi (Trading) Ltd. All rights reserved.
* Copyright (c) 2010-2012 Broadcom. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -41,6 +42,7 @@
#include "vchiq_core.h"
#include "vchiq_ioctl.h"
#include "vchiq_arm.h"
+#include "vchiq_debugfs.h"
#define DEVICE_NAME "vchiq"
@@ -51,10 +53,10 @@
#define VCHIQ_MINOR 0
/* Some per-instance constants */
-#define MAX_COMPLETIONS 16
+#define MAX_COMPLETIONS 128
#define MAX_SERVICES 64
#define MAX_ELEMENTS 8
-#define MSG_QUEUE_SIZE 64
+#define MSG_QUEUE_SIZE 128
#define KEEPALIVE_VER 1
#define KEEPALIVE_VER_MIN KEEPALIVE_VER
@@ -98,23 +100,21 @@ static const char *const resume_state_na
static void suspend_timer_callback(unsigned long context);
-#ifdef notyet
-static int vchiq_proc_add_instance(VCHIQ_INSTANCE_T instance);
-static void vchiq_proc_remove_instance(VCHIQ_INSTANCE_T instance);
-#endif
typedef struct user_service_struct {
VCHIQ_SERVICE_T *service;
void *userdata;
VCHIQ_INSTANCE_T instance;
- int is_vchi;
- int dequeue_pending;
+ char is_vchi;
+ char dequeue_pending;
+ char close_pending;
int message_available_pos;
int msg_insert;
int msg_remove;
struct semaphore insert_event;
struct semaphore remove_event;
+ struct semaphore close_event;
VCHIQ_HEADER_T * msg_queue[MSG_QUEUE_SIZE];
} USER_SERVICE_T;
@@ -137,11 +137,13 @@ struct vchiq_instance_struct {
int closing;
int pid;
int mark;
+ int use_close_delivered;
+ int trace;
struct list_head bulk_waiter_list;
struct mutex bulk_waiter_list_mutex;
- struct proc_dir_entry *proc_entry;
+ VCHIQ_DEBUGFS_NODE_T debugfs_node;
};
typedef struct dump_context_struct {
@@ -170,7 +172,9 @@ static const char *const ioctl_names[] =
"USE_SERVICE",
"RELEASE_SERVICE",
"SET_SERVICE_OPTION",
- "DUMP_PHYS_MEM"
+ "DUMP_PHYS_MEM",
+ "LIB_VERSION",
+ "CLOSE_DELIVERED"
};
vchiq_static_assert((sizeof(ioctl_names)/sizeof(ioctl_names[0])) ==
@@ -227,30 +231,32 @@ add_completion(VCHIQ_INSTANCE_T instance
void *bulk_userdata)
{
VCHIQ_COMPLETION_DATA_T *completion;
+ int insert;
DEBUG_INITIALISE(g_state.local)
- while (instance->completion_insert ==
- (instance->completion_remove + MAX_COMPLETIONS)) {
+ insert = instance->completion_insert;
+ while ((insert - instance->completion_remove) >= MAX_COMPLETIONS) {
/* Out of space - wait for the client */
DEBUG_TRACE(SERVICE_CALLBACK_LINE);
vchiq_log_trace(vchiq_arm_log_level,
"add_completion - completion queue full");
DEBUG_COUNT(COMPLETION_QUEUE_FULL_COUNT);
+
if (down_interruptible(&instance->remove_event) != 0) {
vchiq_log_info(vchiq_arm_log_level,
"service_callback interrupted");
return VCHIQ_RETRY;
- } else if (instance->closing) {
+ }
+
+ if (instance->closing) {
vchiq_log_info(vchiq_arm_log_level,
"service_callback closing");
- return VCHIQ_ERROR;
+ return VCHIQ_SUCCESS;
}
DEBUG_TRACE(SERVICE_CALLBACK_LINE);
}
- completion =
- &instance->completions[instance->completion_insert &
- (MAX_COMPLETIONS - 1)];
+ completion = &instance->completions[insert & (MAX_COMPLETIONS - 1)];
completion->header = header;
completion->reason = reason;
@@ -258,19 +264,22 @@ add_completion(VCHIQ_INSTANCE_T instance
completion->service_userdata = user_service->service;
completion->bulk_userdata = bulk_userdata;
- if (reason == VCHIQ_SERVICE_CLOSED)
+ if (reason == VCHIQ_SERVICE_CLOSED) {
/* Take an extra reference, to be held until
this CLOSED notification is delivered. */
lock_service(user_service->service);
+ if (instance->use_close_delivered)
+ user_service->close_pending = 1;
+ }
/* A write barrier is needed here to ensure that the entire completion
record is written out before the insert point. */
wmb();
if (reason == VCHIQ_MESSAGE_AVAILABLE)
- user_service->message_available_pos =
- instance->completion_insert;
- instance->completion_insert++;
+ user_service->message_available_pos = insert;
+
+ instance->completion_insert = ++insert;
up(&instance->insert_event);
@@ -295,6 +304,7 @@ service_callback(VCHIQ_REASON_T reason,
USER_SERVICE_T *user_service;
VCHIQ_SERVICE_T *service;
VCHIQ_INSTANCE_T instance;
+ int skip_completion = 0;
DEBUG_INITIALISE(g_state.local)
DEBUG_TRACE(SERVICE_CALLBACK_LINE);
@@ -308,10 +318,10 @@ service_callback(VCHIQ_REASON_T reason,
return VCHIQ_SUCCESS;
vchiq_log_trace(vchiq_arm_log_level,
- "service_callback - service %lx(%d), handle %x, reason %d, header %lx, "
+ "service_callback - service %lx(%d,%p), reason %d, header %lx, "
"instance %lx, bulk_userdata %lx",
(unsigned long)user_service,
- service->localport, service->handle,
+ service->localport, user_service->userdata,
reason, (unsigned long)header,
(unsigned long)instance, (unsigned long)bulk_userdata);
@@ -361,9 +371,6 @@ service_callback(VCHIQ_REASON_T reason,
user_service->msg_queue[user_service->msg_insert &
(MSG_QUEUE_SIZE - 1)] = header;
user_service->msg_insert++;
- spin_unlock(&msg_queue_spinlock);
-
- up(&user_service->insert_event);
/* If there is a thread waiting in DEQUEUE_MESSAGE, or if
** there is a MESSAGE_AVAILABLE in the completion queue then
@@ -372,13 +379,22 @@ service_callback(VCHIQ_REASON_T reason,
if (((user_service->message_available_pos -
instance->completion_remove) >= 0) ||
user_service->dequeue_pending) {
- DEBUG_TRACE(SERVICE_CALLBACK_LINE);
user_service->dequeue_pending = 0;
- return VCHIQ_SUCCESS;
+ skip_completion = 1;
}
+ spin_unlock(&msg_queue_spinlock);
+
+ up(&user_service->insert_event);
+
header = NULL;
}
+
+ if (skip_completion) {
+ DEBUG_TRACE(SERVICE_CALLBACK_LINE);
+ return VCHIQ_SUCCESS;
+ }
+
DEBUG_TRACE(SERVICE_CALLBACK_LINE);
return add_completion(instance, reason, header, user_service,
@@ -394,7 +410,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);
@@ -403,6 +419,28 @@ user_service_free(void *userdata)
/****************************************************************************
*
+* close_delivered
+*
+***************************************************************************/
+static void close_delivered(USER_SERVICE_T *user_service)
+{
+ vchiq_log_info(vchiq_arm_log_level,
+ "close_delivered(handle=%x)",
+ user_service->service->handle);
+
+ if (user_service->close_pending) {
+ /* Allow the underlying service to be culled */
+ unlock_service(user_service->service);
+
+ /* Wake the user-thread blocked in close_ or remove_service */
+ up(&user_service->close_event);
+
+ user_service->close_pending = 0;
+ }
+}
+
+/****************************************************************************
+*
* vchiq_ioctl
*
***************************************************************************/
@@ -410,15 +448,13 @@ user_service_free(void *userdata)
static int
vchiq_ioctl(struct file *fp, u_long cmd, void *arg)
{
- VCHIQ_INSTANCE_T instance;
+ VCHIQ_INSTANCE_T instance = fp->f_data;
VCHIQ_STATUS_T status = VCHIQ_SUCCESS;
VCHIQ_SERVICE_T *service = NULL;
int ret = 0;
int i, rc;
DEBUG_INITIALISE(g_state.local)
- instance = fp->f_data;
-
/* XXXBSD: HACK! */
#define _IOC_NR(x) ((x) & 0xff)
#define _IOC_TYPE(x) IOCGROUP(x)
@@ -480,17 +516,19 @@ vchiq_ioctl(struct file *fp, u_long cmd,
case VCHIQ_IOC_CREATE_SERVICE: {
VCHIQ_CREATE_SERVICE_T *pargs = arg;
+ VCHIQ_CREATE_SERVICE_T args = *pargs;
USER_SERVICE_T *user_service = NULL;
void *userdata;
int srvstate;
+ /* XXXNH kmalloc */
user_service = kzalloc(sizeof(USER_SERVICE_T), GFP_KERNEL);
if (!user_service) {
ret = -ENOMEM;
break;
}
- if (pargs->is_open) {
+ if (args.is_open) {
if (!instance->connected) {
ret = -ENOTCONN;
kfree(user_service);
@@ -504,9 +542,11 @@ vchiq_ioctl(struct file *fp, u_long cmd,
VCHIQ_SRVSTATE_HIDDEN;
}
- userdata = pargs->params.userdata;
+ userdata = args.params.userdata;
pargs->params.callback = service_callback;
pargs->params.userdata = user_service;
+ args.params.callback = service_callback;
+ args.params.userdata = user_service;
service = vchiq_add_service_internal(
instance->state,
&pargs->params, srvstate,
@@ -516,16 +556,18 @@ vchiq_ioctl(struct file *fp, u_long cmd,
user_service->service = service;
user_service->userdata = userdata;
user_service->instance = instance;
- user_service->is_vchi = pargs->is_vchi;
+ user_service->is_vchi = (args.is_vchi != 0);
user_service->dequeue_pending = 0;
+ user_service->close_pending = 0;
user_service->message_available_pos =
instance->completion_remove - 1;
user_service->msg_insert = 0;
user_service->msg_remove = 0;
_sema_init(&user_service->insert_event, 0);
_sema_init(&user_service->remove_event, 0);
+ _sema_init(&user_service->close_event, 0);
- if (pargs->is_open) {
+ if (args.is_open) {
status = vchiq_open_service_internal
(service, instance->pid);
if (status != VCHIQ_SUCCESS) {
@@ -557,8 +599,24 @@ vchiq_ioctl(struct file *fp, u_long cmd,
#endif
service = find_service_for_instance(instance, handle);
- if (service != NULL)
- status = vchiq_close_service(service->handle);
+ if (service != NULL) {
+ USER_SERVICE_T *user_service =
+ (USER_SERVICE_T *)service->base.userdata;
+ /* close_pending is false on first entry, and when the
+ wait in vchiq_close_service has been interrupted. */
+ if (!user_service->close_pending) {
+ status = vchiq_close_service(service->handle);
+ if (status != VCHIQ_SUCCESS)
+ break;
+ }
+
+ /* close_pending is true once the underlying service
+ has been closed until the client library calls the
+ CLOSE_DELIVERED ioctl, signalling close_event. */
+ if (user_service->close_pending &&
+ down_interruptible(&user_service->close_event))
+ status = VCHIQ_RETRY;
+ }
else
ret = -EINVAL;
} break;
@@ -571,8 +629,24 @@ vchiq_ioctl(struct file *fp, u_long cmd,
#endif
service = find_service_for_instance(instance, handle);
- if (service != NULL)
- status = vchiq_remove_service(service->handle);
+ if (service != NULL) {
+ USER_SERVICE_T *user_service =
+ (USER_SERVICE_T *)service->base.userdata;
+ /* close_pending is false on first entry, and when the
+ wait in vchiq_close_service has been interrupted. */
+ if (!user_service->close_pending) {
+ status = vchiq_remove_service(service->handle);
+ if (status != VCHIQ_SUCCESS)
+ break;
+ }
+
+ /* close_pending is true once the underlying service
+ has been closed until the client library calls the
+ CLOSE_DELIVERED ioctl, signalling close_event. */
+ if (user_service->close_pending &&
+ down_interruptible(&user_service->close_event))
+ status = VCHIQ_RETRY;
+ }
else
ret = -EINVAL;
} break;
@@ -611,21 +685,22 @@ vchiq_ioctl(struct file *fp, u_long cmd,
case VCHIQ_IOC_QUEUE_MESSAGE: {
VCHIQ_QUEUE_MESSAGE_T *pargs = arg;
+ VCHIQ_QUEUE_MESSAGE_T args = *pargs;
#ifdef VCHIQ_IOCTL_DEBUG
- printf("%s: [QUEUE MESSAGE] handle = %08x\n", __func__, pargs->handle);
+ printf("%s: [QUEUE MESSAGE] handle = %08x\n", __func__, args.handle);
#endif
- service = find_service_for_instance(instance, pargs->handle);
+ service = find_service_for_instance(instance, args.handle);
- if ((service != NULL) && (pargs->count <= MAX_ELEMENTS)) {
+ if ((service != NULL) && (args.count <= MAX_ELEMENTS)) {
/* Copy elements into kernel space */
VCHIQ_ELEMENT_T elements[MAX_ELEMENTS];
- if (copy_from_user(elements, pargs->elements,
- pargs->count * sizeof(VCHIQ_ELEMENT_T)) == 0)
+ if (copy_from_user(elements, args.elements,
+ args.count * sizeof(VCHIQ_ELEMENT_T)) == 0)
status = vchiq_queue_message
- (pargs->handle,
- elements, pargs->count);
+ (args.handle,
+ elements, args.count);
else
ret = -EFAULT;
} else {
@@ -636,26 +711,27 @@ vchiq_ioctl(struct file *fp, u_long cmd,
case VCHIQ_IOC_QUEUE_BULK_TRANSMIT:
case VCHIQ_IOC_QUEUE_BULK_RECEIVE: {
VCHIQ_QUEUE_BULK_TRANSFER_T *pargs = arg;
+ VCHIQ_QUEUE_BULK_TRANSFER_T args = *pargs;
struct bulk_waiter_node *waiter = NULL;
VCHIQ_BULK_DIR_T dir =
(cmd == VCHIQ_IOC_QUEUE_BULK_TRANSMIT) ?
VCHIQ_BULK_TRANSMIT : VCHIQ_BULK_RECEIVE;
- service = find_service_for_instance(instance, pargs->handle);
+ service = find_service_for_instance(instance, args.handle);
if (!service) {
ret = -EINVAL;
break;
}
- if (pargs->mode == VCHIQ_BULK_MODE_BLOCKING) {
+ if (args.mode == VCHIQ_BULK_MODE_BLOCKING) {
waiter = kzalloc(sizeof(struct bulk_waiter_node),
GFP_KERNEL);
if (!waiter) {
ret = -ENOMEM;
break;
}
- pargs->userdata = &waiter->bulk_waiter;
- } else if (pargs->mode == VCHIQ_BULK_MODE_WAITING) {
+ args.userdata = &waiter->bulk_waiter;
+ } else if (args.mode == VCHIQ_BULK_MODE_WAITING) {
struct list_head *pos;
lmutex_lock(&instance->bulk_waiter_list_mutex);
list_for_each(pos, &instance->bulk_waiter_list) {
@@ -680,13 +756,13 @@ vchiq_ioctl(struct file *fp, u_long cmd,
vchiq_log_info(vchiq_arm_log_level,
"found bulk_waiter %x for pid %d",
(unsigned int)waiter, current->l_proc->p_pid);
- pargs->userdata = &waiter->bulk_waiter;
+ args.userdata = &waiter->bulk_waiter;
}
status = vchiq_bulk_transfer
- (pargs->handle,
+ (args.handle,
VCHI_MEM_HANDLE_INVALID,
- pargs->data, pargs->size,
- pargs->userdata, pargs->mode,
+ args.data, args.size,
+ args.userdata, args.mode,
dir);
if (!waiter)
break;
@@ -718,6 +794,7 @@ vchiq_ioctl(struct file *fp, u_long cmd,
case VCHIQ_IOC_AWAIT_COMPLETION: {
VCHIQ_AWAIT_COMPLETION_T *pargs = arg;
+ VCHIQ_AWAIT_COMPLETION_T args = *pargs;
int count = 0;
DEBUG_TRACE(AWAIT_COMPLETION_LINE);
@@ -746,25 +823,29 @@ vchiq_ioctl(struct file *fp, u_long cmd,
}
DEBUG_TRACE(AWAIT_COMPLETION_LINE);
- /* A read memory barrier is needed to stop prefetch of a stale
- ** completion record
- */
- rmb();
-
if (ret == 0) {
- int msgbufcount = pargs->msgbufcount;
+ int msgbufcount = args.msgbufcount;
+ int remove;
+
+ remove = instance->completion_remove;
- for (; count < pargs->count; count++) {
+ for (count = 0; count < args.count; count++) {
VCHIQ_COMPLETION_DATA_T *completion;
VCHIQ_SERVICE_T *service1;
USER_SERVICE_T *user_service;
VCHIQ_HEADER_T *header;
- if (instance->completion_remove ==
- instance->completion_insert)
+
+ if (remove == instance->completion_insert)
break;
+
completion = &instance->completions[
- instance->completion_remove &
- (MAX_COMPLETIONS - 1)];
+ remove & (MAX_COMPLETIONS - 1)];
+
+ /* A read memory barrier is needed to prevent
+ ** the prefetch of a stale completion record
+ */
+ rmb();
+
service1 = completion->service_userdata;
user_service = service1->base.userdata;
@@ -779,13 +860,13 @@ vchiq_ioctl(struct file *fp, u_long cmd,
msglen = header->size +
sizeof(VCHIQ_HEADER_T);
/* This must be a VCHIQ-style service */
- if (pargs->msgbufsize < msglen) {
+ if (args.msgbufsize < msglen) {
vchiq_log_error(
vchiq_arm_log_level,
"header %x: msgbufsize"
" %x < msglen %x",
(unsigned int)header,
- pargs->msgbufsize,
+ args.msgbufsize,
msglen);
WARN(1, "invalid message "
"size\n");
@@ -801,7 +882,7 @@ vchiq_ioctl(struct file *fp, u_long cmd,
msgbufcount--;
if (copy_from_user(&msgbuf,
(const void __user *)
- &pargs->msgbufs[msgbufcount],
+ &args.msgbufs[msgbufcount],
sizeof(msgbuf)) != 0) {
if (count == 0)
ret = -EFAULT;
@@ -826,12 +907,13 @@ vchiq_ioctl(struct file *fp, u_long cmd,
completion->header = msgbuf;
}
- if (completion->reason ==
- VCHIQ_SERVICE_CLOSED)
+ if ((completion->reason ==
+ VCHIQ_SERVICE_CLOSED) &&
+ !instance->use_close_delivered)
unlock_service(service1);
if (copy_to_user((void __user *)(
- (size_t)pargs->buf +
+ (size_t)args.buf +
count * sizeof(VCHIQ_COMPLETION_DATA_T)),
completion,
sizeof(VCHIQ_COMPLETION_DATA_T)) != 0) {
@@ -840,26 +922,31 @@ vchiq_ioctl(struct file *fp, u_long cmd,
break;
}
- instance->completion_remove++;
+ /* Ensure that the above copy has completed
+ ** before advancing the remove pointer. */
+ mb();
+
+ instance->completion_remove = ++remove;
}
pargs->msgbufcount = msgbufcount;
pargs->count = count;
}
-
if (count != 0)
up(&instance->remove_event);
+
lmutex_unlock(&instance->completion_mutex);
DEBUG_TRACE(AWAIT_COMPLETION_LINE);
} break;
case VCHIQ_IOC_DEQUEUE_MESSAGE: {
VCHIQ_DEQUEUE_MESSAGE_T *pargs = arg;
+ VCHIQ_DEQUEUE_MESSAGE_T args = *pargs;
USER_SERVICE_T *user_service;
VCHIQ_HEADER_T *header;
DEBUG_TRACE(DEQUEUE_MESSAGE_LINE);
- service = find_service_for_instance(instance, pargs->handle);
+ service = find_service_for_instance(instance, args.handle);
if (!service) {
ret = -EINVAL;
break;
@@ -872,7 +959,7 @@ vchiq_ioctl(struct file *fp, u_long cmd,
spin_lock(&msg_queue_spinlock);
if (user_service->msg_remove == user_service->msg_insert) {
- if (!pargs->blocking) {
+ if (!args.blocking) {
spin_unlock(&msg_queue_spinlock);
DEBUG_TRACE(DEQUEUE_MESSAGE_LINE);
ret = -EWOULDBLOCK;
@@ -908,10 +995,10 @@ vchiq_ioctl(struct file *fp, u_long cmd,
up(&user_service->remove_event);
if (header == NULL)
ret = -ENOTCONN;
- else if (header->size <= pargs->bufsize) {
+ else if (header->size <= args.bufsize) {
/* Copy to user space if msgbuf is not NULL */
- if ((pargs->buf == NULL) ||
- (copy_to_user((void __user *)pargs->buf,
+ if ((args.buf == NULL) ||
+ (copy_to_user((void __user *)args.buf,
header->data,
header->size) == 0)) {
pargs->bufsize = header->size;
@@ -923,7 +1010,7 @@ vchiq_ioctl(struct file *fp, u_long cmd,
} else {
vchiq_log_error(vchiq_arm_log_level,
"header %x: bufsize %x < size %x",
- (unsigned int)header, pargs->bufsize,
+ (unsigned int)header, args.bufsize,
header->size);
WARN(1, "invalid size\n");
ret = -EMSGSIZE;
@@ -932,23 +1019,24 @@ vchiq_ioctl(struct file *fp, u_long cmd,
} break;
case VCHIQ_IOC_GET_CLIENT_ID: {
- VCHIQ_SERVICE_HANDLE_T handle = (VCHIQ_SERVICE_HANDLE_T)arg;
+ VCHIQ_SERVICE_HANDLE_T handle = *(VCHIQ_SERVICE_HANDLE_T *)arg;
ret = vchiq_get_client_id(handle);
} break;
case VCHIQ_IOC_GET_CONFIG: {
VCHIQ_GET_CONFIG_T *pargs = arg;
+ VCHIQ_GET_CONFIG_T args = *pargs;
VCHIQ_CONFIG_T config;
- if (pargs->config_size > sizeof(config)) {
+ if (args.config_size > sizeof(config)) {
ret = -EINVAL;
break;
}
- status = vchiq_get_config(instance, pargs->config_size, &config);
+ status = vchiq_get_config(instance, args.config_size, &config);
if (status == VCHIQ_SUCCESS) {
- if (copy_to_user((void __user *)pargs->pconfig,
- &config, pargs->config_size) != 0) {
+ if (copy_to_user((void __user *)args.pconfig,
+ &config, args.config_size) != 0) {
ret = -EFAULT;
break;
}
@@ -957,15 +1045,16 @@ vchiq_ioctl(struct file *fp, u_long cmd,
case VCHIQ_IOC_SET_SERVICE_OPTION: {
VCHIQ_SET_SERVICE_OPTION_T *pargs = arg;
+ VCHIQ_SET_SERVICE_OPTION_T args = *pargs;
- service = find_service_for_instance(instance, pargs->handle);
+ service = find_service_for_instance(instance, args.handle);
if (!service) {
ret = -EINVAL;
break;
}
status = vchiq_set_service_option(
- pargs->handle, pargs->option, pargs->value);
+ args.handle, args.option, args.value);
} break;
case VCHIQ_IOC_DUMP_PHYS_MEM: {
@@ -979,6 +1068,28 @@ vchiq_ioctl(struct file *fp, u_long cmd,
#endif
} break;
+ case VCHIQ_IOC_LIB_VERSION: {
+ unsigned int lib_version = (unsigned int)arg;
+
+ if (lib_version < VCHIQ_VERSION_MIN)
+ ret = -EINVAL;
+ else if (lib_version >= VCHIQ_VERSION_CLOSE_DELIVERED)
+ instance->use_close_delivered = 1;
+ } break;
+
+ case VCHIQ_IOC_CLOSE_DELIVERED: {
+ VCHIQ_SERVICE_HANDLE_T handle = *(VCHIQ_SERVICE_HANDLE_T *)arg;
+
+ service = find_closed_service_for_instance(instance, handle);
+ if (service != NULL) {
+ USER_SERVICE_T *user_service =
+ (USER_SERVICE_T *)service->base.userdata;
+ close_delivered(user_service);
+ }
+ else
+ ret = -EINVAL;
+ } break;
+
default:
ret = -ENOTTY;
break;
@@ -1019,15 +1130,6 @@ vchiq_ioctl(struct file *fp, u_long cmd,
return ret;
}
-#if notyet
-static void
-instance_dtr(void *data)
-{
-
- free(data, M_VCHIQ);
-}
-#endif
-
/****************************************************************************
*
* vchiq_open
@@ -1067,7 +1169,7 @@ vchiq_open(dev_t dev, int flags, int mod
instance->pid = current->l_proc->p_pid;
#ifdef notyet
- ret = vchiq_proc_add_instance(instance);
+ ret = vchiq_debugfs_add_instance(instance);
if (ret != 0) {
kfree(instance);
return ret;
@@ -1101,13 +1203,11 @@ vchiq_close(struct file *fp)
{
int ret = 0;
if (1) {
- VCHIQ_INSTANCE_T instance;
+ VCHIQ_INSTANCE_T instance = fp->f_data;
VCHIQ_STATE_T *state = vchiq_get_state();
VCHIQ_SERVICE_T *service;
int i;
- instance = fp->f_data;
-
vchiq_log_info(vchiq_arm_log_level,
"vchiq_release: instance=%lx",
(unsigned long)instance);
@@ -1187,7 +1287,15 @@ vchiq_close(struct file *fp)
(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++;
}
@@ -1458,7 +1566,7 @@ vchiq_read(struct file *file, off_t *ppo
result = uiomove(buf, context.actual, uio);
kmem_free(buf, PAGE_SIZE);
-
+
return result;
}
@@ -1591,6 +1699,8 @@ exit:
return 0;
}
+
+
VCHIQ_STATUS_T
vchiq_arm_init_state(VCHIQ_STATE_T *state, VCHIQ_ARM_STATE_T *arm_state)
{
@@ -1710,7 +1820,7 @@ set_suspend_state(VCHIQ_ARM_STATE_T *arm
complete_all(&arm_state->vc_resume_complete);
break;
case VC_SUSPEND_IDLE:
- INIT_COMPLETION(arm_state->vc_suspend_complete);
+ reinit_completion(&arm_state->vc_suspend_complete);
break;
case VC_SUSPEND_REQUESTED:
break;
@@ -1738,7 +1848,7 @@ set_resume_state(VCHIQ_ARM_STATE_T *arm_
case VC_RESUME_FAILED:
break;
case VC_RESUME_IDLE:
- INIT_COMPLETION(arm_state->vc_resume_complete);
+ reinit_completion(&arm_state->vc_resume_complete);
break;
case VC_RESUME_REQUESTED:
break;
@@ -1800,7 +1910,7 @@ block_resume(VCHIQ_ARM_STATE_T *arm_stat
* (which only happens when blocked_count hits 0) then those threads
* will have to wait until next time around */
if (arm_state->blocked_count) {
- INIT_COMPLETION(arm_state->blocked_blocker);
+ reinit_completion(&arm_state->blocked_blocker);
write_unlock_bh(&arm_state->susp_res_lock);
vchiq_log_info(vchiq_susp_log_level, "%s wait for previously "
"blocked clients", __func__);
@@ -1845,7 +1955,7 @@ block_resume(VCHIQ_ARM_STATE_T *arm_stat
write_lock_bh(&arm_state->susp_res_lock);
resume_count++;
}
- INIT_COMPLETION(arm_state->resume_blocker);
+ reinit_completion(&arm_state->resume_blocker);
arm_state->resume_blocked = 1;
out:
@@ -2456,6 +2566,54 @@ vchiq_release_service_internal(VCHIQ_SER
return vchiq_release_internal(service->state, service);
}
+#ifdef notyet
+VCHIQ_DEBUGFS_NODE_T *
+vchiq_instance_get_debugfs_node(VCHIQ_INSTANCE_T instance)
+{
+ return &instance->debugfs_node;
+}
+
+int
+vchiq_instance_get_use_count(VCHIQ_INSTANCE_T instance)
+{
+ VCHIQ_SERVICE_T *service;
+ int use_count = 0, i;
+ i = 0;
+ while ((service = next_service_by_instance(instance->state,
+ instance, &i)) != NULL) {
+ use_count += service->service_use_count;
+ unlock_service(service);
+ }
+ return use_count;
+}
+
+int
+vchiq_instance_get_pid(VCHIQ_INSTANCE_T instance)
+{
+ return instance->pid;
+}
+
+int
+vchiq_instance_get_trace(VCHIQ_INSTANCE_T instance)
+{
+ return instance->trace;
+}
+
+void
+vchiq_instance_set_trace(VCHIQ_INSTANCE_T instance, int trace)
+{
+ VCHIQ_SERVICE_T *service;
+ int i;
+ i = 0;
+ while ((service = next_service_by_instance(instance->state,
+ instance, &i)) != NULL) {
+ service->trace = trace;
+ unlock_service(service);
+ }
+ instance->trace = (trace != 0);
+}
+#endif
+
static void suspend_timer_callback(unsigned long context)
{
VCHIQ_STATE_T *state = (VCHIQ_STATE_T *)context;
@@ -2658,6 +2816,7 @@ void vchiq_platform_conn_state_changed(V
}
}
+
/****************************************************************************
*
* vchiq_init - called when the module is loaded.
@@ -2694,73 +2853,6 @@ failed_platform_init:
return err;
}
-#ifdef notyet
-static int vchiq_instance_get_use_count(VCHIQ_INSTANCE_T instance)
-{
- VCHIQ_SERVICE_T *service;
- int use_count = 0, i;
- i = 0;
- while ((service = next_service_by_instance(instance->state,
- instance, &i)) != NULL) {
- use_count += service->service_use_count;
- unlock_service(service);
- }
- return use_count;
-}
-
-/* read the per-process use-count */
-static int proc_read_use_count(char *page, char **start,
- off_t off, int count,
- int *eof, void *data)
-{
- VCHIQ_INSTANCE_T instance = data;
- int len, use_count;
-
- use_count = vchiq_instance_get_use_count(instance);
- len = snprintf(page+off, count, "%d\n", use_count);
-
- return len;
-}
-
-/* add an instance (process) to the proc entries */
-static int vchiq_proc_add_instance(VCHIQ_INSTANCE_T instance)
-{
- char pidstr[32];
- struct proc_dir_entry *top, *use_count;
- struct proc_dir_entry *clients = vchiq_clients_top();
- int pid = instance->pid;
-
- snprintf(pidstr, sizeof(pidstr), "%d", pid);
- top = proc_mkdir(pidstr, clients);
- if (!top)
- goto fail_top;
-
- use_count = create_proc_read_entry("use_count",
- 0444, top,
- proc_read_use_count,
- instance);
- if (!use_count)
- goto fail_use_count;
-
- instance->proc_entry = top;
-
- return 0;
-
-fail_use_count:
- remove_proc_entry(top->name, clients);
-fail_top:
- return -ENOMEM;
-}
-
-static void vchiq_proc_remove_instance(VCHIQ_INSTANCE_T instance)
-{
- struct proc_dir_entry *clients = vchiq_clients_top();
- remove_proc_entry("use_count", instance->proc_entry);
- remove_proc_entry(instance->proc_entry->name, clients);
-}
-
-#endif
-
/****************************************************************************
*
* vchiq_exit - called when the module is unloaded.
Index: src/sys/external/bsd/vchiq/dist/interface/vchiq_arm/vchiq_core.c
diff -u src/sys/external/bsd/vchiq/dist/interface/vchiq_arm/vchiq_core.c:1.10 src/sys/external/bsd/vchiq/dist/interface/vchiq_arm/vchiq_core.c:1.11
--- src/sys/external/bsd/vchiq/dist/interface/vchiq_arm/vchiq_core.c:1.10 Sat Dec 20 19:49:27 2014
+++ src/sys/external/bsd/vchiq/dist/interface/vchiq_arm/vchiq_core.c Thu Jan 12 05:41:25 2017
@@ -47,9 +47,12 @@
#define SLOT_QUEUE_INDEX_FROM_POS(pos) \
((int)((unsigned int)(pos) / VCHIQ_SLOT_SIZE))
-
#define BULK_INDEX(x) (x & (VCHIQ_NUM_SERVICE_BULKS - 1))
+#define SRVTRACE_LEVEL(srv) \
+ (((srv) && (srv)->trace) ? VCHIQ_LOG_TRACE : vchiq_core_msg_log_level)
+#define SRVTRACE_ENABLED(srv, lev) \
+ (((srv) && (srv)->trace) || (vchiq_core_msg_log_level >= (lev)))
struct vchiq_open_payload {
int fourcc;
@@ -62,6 +65,13 @@ struct vchiq_openack_payload {
short version;
};
+enum
+{
+ QMFLAGS_IS_BLOCKING = (1 << 0),
+ QMFLAGS_NO_MUTEX_LOCK = (1 << 1),
+ QMFLAGS_NO_MUTEX_UNLOCK = (1 << 2)
+};
+
/* we require this for consistency between endpoints */
vchiq_static_assert(sizeof(VCHIQ_HEADER_T) == 8);
vchiq_static_assert(IS_POW2(sizeof(VCHIQ_HEADER_T)));
@@ -231,6 +241,31 @@ find_service_for_instance(VCHIQ_INSTANCE
}
VCHIQ_SERVICE_T *
+find_closed_service_for_instance(VCHIQ_INSTANCE_T instance,
+ VCHIQ_SERVICE_HANDLE_T handle) {
+ VCHIQ_SERVICE_T *service;
+
+ spin_lock(&service_spinlock);
+ service = handle_to_service(handle);
+ if (service &&
+ ((service->srvstate == VCHIQ_SRVSTATE_FREE) ||
+ (service->srvstate == VCHIQ_SRVSTATE_CLOSED)) &&
+ (service->handle == handle) &&
+ (service->instance == instance)) {
+ BUG_ON(service->ref_count == 0);
+ service->ref_count++;
+ } else
+ service = NULL;
+ spin_unlock(&service_spinlock);
+
+ if (!service)
+ vchiq_log_info(vchiq_core_log_level,
+ "Invalid service handle 0x%x", handle);
+
+ return service;
+}
+
+VCHIQ_SERVICE_T *
next_service_by_instance(VCHIQ_STATE_T *state, VCHIQ_INSTANCE_T instance,
int *pidx)
{
@@ -586,15 +621,15 @@ process_free_queue(VCHIQ_STATE_T *state)
BITSET_T service_found[BITSET_SIZE(VCHIQ_MAX_SERVICES)];
int slot_queue_available;
- /* Use a read memory barrier to ensure that any state that may have
- ** been modified by another thread is not masked by stale prefetched
- ** values. */
- rmb();
-
/* Find slots which have been freed by the other side, and return them
** to the available queue. */
slot_queue_available = state->slot_queue_available;
+ /* Use a memory barrier to ensure that any state that may have been
+ ** modified by another thread is not masked by stale prefetched
+ ** values. */
+ mb();
+
while (slot_queue_available != local->slot_queue_recycle) {
unsigned int pos;
int slot_index = local->slot_queue[slot_queue_available++ &
@@ -602,6 +637,8 @@ process_free_queue(VCHIQ_STATE_T *state)
char *data = (char *)SLOT_DATA_FROM_INDEX(state, slot_index);
int data_found = 0;
+ rmb();
+
vchiq_log_trace(vchiq_core_log_level, "%d: pfq %d=%x %x %x",
state->id, slot_index, (unsigned int)data,
local->slot_queue_recycle, slot_queue_available);
@@ -717,6 +754,8 @@ process_free_queue(VCHIQ_STATE_T *state)
up(&state->data_quota_event);
}
+ mb();
+
state->slot_queue_available = slot_queue_available;
up(&state->slot_available_event);
}
@@ -726,7 +765,7 @@ process_free_queue(VCHIQ_STATE_T *state)
static VCHIQ_STATUS_T
queue_message(VCHIQ_STATE_T *state, VCHIQ_SERVICE_T *service,
int msgid, const VCHIQ_ELEMENT_T *elements,
- int count, int size, int is_blocking)
+ int count, int size, int flags)
{
VCHIQ_SHARED_STATE_T *local;
VCHIQ_SERVICE_QUOTA_T *service_quota = NULL;
@@ -741,7 +780,7 @@ queue_message(VCHIQ_STATE_T *state, VCHI
WARN_ON(!(stride <= VCHIQ_SLOT_SIZE));
- if ((type != VCHIQ_MSG_RESUME) &&
+ if (!(flags & QMFLAGS_NO_MUTEX_LOCK) &&
(lmutex_lock_interruptible(&state->slot_mutex) != 0))
return VCHIQ_RETRY;
@@ -749,6 +788,8 @@ queue_message(VCHIQ_STATE_T *state, VCHI
int tx_end_index;
BUG_ON(!service);
+ BUG_ON((flags & (QMFLAGS_NO_MUTEX_LOCK |
+ QMFLAGS_NO_MUTEX_UNLOCK)) != 0);
if (service->closing) {
/* The service has been closed */
@@ -824,12 +865,15 @@ queue_message(VCHIQ_STATE_T *state, VCHI
spin_unlock("a_spinlock);
}
- header = reserve_space(state, stride, is_blocking);
+ header = reserve_space(state, stride, flags & QMFLAGS_IS_BLOCKING);
if (!header) {
if (service)
VCHIQ_SERVICE_STATS_INC(service, slot_stalls);
- lmutex_unlock(&state->slot_mutex);
+ /* In the event of a failure, return the mutex to the
+ state it was in */
+ if (!(flags & QMFLAGS_NO_MUTEX_LOCK))
+ lmutex_unlock(&state->slot_mutex);
return VCHIQ_RETRY;
}
@@ -847,6 +891,8 @@ queue_message(VCHIQ_STATE_T *state, VCHI
VCHIQ_MSG_DSTPORT(msgid));
BUG_ON(!service);
+ BUG_ON((flags & (QMFLAGS_NO_MUTEX_LOCK |
+ QMFLAGS_NO_MUTEX_UNLOCK)) != 0);
for (i = 0, pos = 0; i < (unsigned int)count;
pos += elements[i++].size)
@@ -860,16 +906,14 @@ queue_message(VCHIQ_STATE_T *state, VCHI
error_count);
return VCHIQ_ERROR;
}
- if (i == 0) {
- if (vchiq_core_msg_log_level >=
- VCHIQ_LOG_INFO)
- vchiq_log_dump_mem("Sent", 0,
- header->data + pos,
- min(64,
- elements[0].size));
- }
}
+ if (SRVTRACE_ENABLED(service,
+ VCHIQ_LOG_INFO))
+ vchiq_log_dump_mem("Sent", 0,
+ header->data,
+ min(16, pos));
+
spin_lock("a_spinlock);
service_quota->message_use_count++;
@@ -928,7 +972,7 @@ queue_message(VCHIQ_STATE_T *state, VCHI
? service->base.fourcc
: VCHIQ_MAKE_FOURCC('?', '?', '?', '?');
- vchiq_log_info(vchiq_core_msg_log_level,
+ vchiq_log_info(SRVTRACE_LEVEL(service),
"Sent Msg %s(%u) to %c%c%c%c s:%u d:%d len:%d",
msg_type_str(VCHIQ_MSG_TYPE(msgid)),
VCHIQ_MSG_TYPE(msgid),
@@ -948,7 +992,7 @@ queue_message(VCHIQ_STATE_T *state, VCHI
if (service && (type == VCHIQ_MSG_CLOSE))
vchiq_set_service_state(service, VCHIQ_SRVSTATE_CLOSESENT);
- if (VCHIQ_MSG_TYPE(msgid) != VCHIQ_MSG_PAUSE)
+ if (!(flags & QMFLAGS_NO_MUTEX_UNLOCK))
lmutex_unlock(&state->slot_mutex);
remote_event_signal(&state->remote->trigger);
@@ -1008,16 +1052,13 @@ queue_message_sync(VCHIQ_STATE_T *state,
error_count);
return VCHIQ_ERROR;
}
- if (i == 0) {
- if (vchiq_sync_log_level >=
- VCHIQ_LOG_TRACE)
- vchiq_log_dump_mem("Sent Sync",
- 0, header->data + pos,
- min(64,
- elements[0].size));
- }
}
+ if (vchiq_sync_log_level >= VCHIQ_LOG_TRACE)
+ vchiq_log_dump_mem("Sent Sync",
+ 0, header->data,
+ min(16, pos));
+
VCHIQ_SERVICE_STATS_INC(service, ctrl_tx_count);
VCHIQ_SERVICE_STATS_ADD(service, ctrl_tx_bytes, size);
} else {
@@ -1320,11 +1361,11 @@ resolve_bulks(VCHIQ_SERVICE_T *service,
vchiq_transfer_bulk(bulk);
lmutex_unlock(&state->bulk_transfer_mutex);
- if (vchiq_core_msg_log_level >= VCHIQ_LOG_INFO) {
+ if (SRVTRACE_ENABLED(service, VCHIQ_LOG_INFO)) {
const char *header = (queue == &service->bulk_tx) ?
"Send Bulk to" : "Recv Bulk from";
if (bulk->actual != VCHIQ_BULK_ACTUAL_ABORTED)
- vchiq_log_info(vchiq_core_msg_log_level,
+ vchiq_log_info(SRVTRACE_LEVEL(service),
"%s %c%c%c%c d:%d len:%d %x<->%x",
header,
VCHIQ_FOURCC_AS_4CHARS(
@@ -1334,7 +1375,7 @@ resolve_bulks(VCHIQ_SERVICE_T *service,
(unsigned int)bulk->data,
(unsigned int)bulk->remote_data);
else
- vchiq_log_info(vchiq_core_msg_log_level,
+ vchiq_log_info(SRVTRACE_LEVEL(service),
"%s %c%c%c%c d:%d ABORTED - tx len:%d,"
" rx len:%d %x<->%x",
header,
@@ -1381,7 +1422,7 @@ abort_outstanding_bulks(VCHIQ_SERVICE_T
if (queue->process != queue->local_insert) {
vchiq_complete_bulk(bulk);
- vchiq_log_info(vchiq_core_msg_log_level,
+ vchiq_log_info(SRVTRACE_LEVEL(service),
"%s %c%c%c%c d:%d ABORTED - tx len:%d, "
"rx len:%d",
is_tx ? "Send Bulk to" : "Recv Bulk from",
@@ -1516,8 +1557,14 @@ parse_open(VCHIQ_STATE_T *state, VCHIQ_H
sizeof(ack_payload)
};
+ if (state->version_common <
+ VCHIQ_VERSION_SYNCHRONOUS_MODE)
+ service->sync = 0;
+
/* Acknowledge the OPEN */
- if (service->sync) {
+ if (service->sync &&
+ (state->version_common >=
+ VCHIQ_VERSION_SYNCHRONOUS_MODE)) {
if (queue_message_sync(state, NULL,
VCHIQ_MAKE_MSG(
VCHIQ_MSG_OPENACK,
@@ -1631,9 +1678,11 @@ parse_rx_slots(VCHIQ_STATE_T *state)
case VCHIQ_MSG_BULK_RX_DONE:
case VCHIQ_MSG_BULK_TX_DONE:
service = find_service_by_port(state, localport);
- if ((!service || service->remoteport != remoteport) &&
- (localport == 0) &&
- (type == VCHIQ_MSG_CLOSE)) {
+ if ((!service ||
+ ((service->remoteport != remoteport) &&
+ (service->remoteport != VCHIQ_PORT_FREE))) &&
+ (localport == 0) &&
+ (type == VCHIQ_MSG_CLOSE)) {
/* This could be a CLOSE from a client which
hadn't yet received the OPENACK - look for
the connected service */
@@ -1665,13 +1714,13 @@ parse_rx_slots(VCHIQ_STATE_T *state)
break;
}
- if (vchiq_core_msg_log_level >= VCHIQ_LOG_INFO) {
+ if (SRVTRACE_ENABLED(service, VCHIQ_LOG_INFO)) {
int svc_fourcc;
svc_fourcc = service
? service->base.fourcc
: VCHIQ_MAKE_FOURCC('?', '?', '?', '?');
- vchiq_log_info(vchiq_core_msg_log_level,
+ vchiq_log_info(SRVTRACE_LEVEL(service),
"Rcvd Msg %s(%u) from %c%c%c%c s:%d d:%d "
"len:%d",
msg_type_str(type), type,
@@ -1679,7 +1728,7 @@ parse_rx_slots(VCHIQ_STATE_T *state)
remoteport, localport, size);
if (size > 0)
vchiq_log_dump_mem("Rcvd", 0, header->data,
- min(64, size));
+ min(16, size));
}
if (((unsigned int)header & VCHIQ_SLOT_MASK) + calc_stride(size)
@@ -1741,7 +1790,7 @@ parse_rx_slots(VCHIQ_STATE_T *state)
service->remoteport);
break;
case VCHIQ_MSG_DATA:
- vchiq_log_trace(vchiq_core_log_level,
+ vchiq_log_info(vchiq_core_log_level,
"%d: prs DATA@%x,%x (%d->%d)",
state->id, (unsigned int)header, size,
remoteport, localport);
@@ -1769,6 +1818,8 @@ parse_rx_slots(VCHIQ_STATE_T *state)
vchiq_log_info(vchiq_core_log_level,
"%d: prs CONNECT@%x",
state->id, (unsigned int)header);
+ state->version_common = ((VCHIQ_SLOT_ZERO_T *)
+ state->slot_data)->version;
up(&state->connect);
break;
case VCHIQ_MSG_BULK_RX:
@@ -1922,7 +1973,8 @@ parse_rx_slots(VCHIQ_STATE_T *state)
/* Send a PAUSE in response */
if (queue_message(state, NULL,
VCHIQ_MAKE_MSG(VCHIQ_MSG_PAUSE, 0, 0),
- NULL, 0, 0, 0) == VCHIQ_RETRY)
+ NULL, 0, 0, QMFLAGS_NO_MUTEX_UNLOCK)
+ == VCHIQ_RETRY)
goto bail_not_ready;
if (state->is_master)
pause_bulks(state);
@@ -1985,8 +2037,8 @@ bail_not_ready:
}
/* Called by the slot handler thread */
-int slot_handler_func(void *v);
-int
+static int slot_handler_func(void *v);
+static int
slot_handler_func(void *v)
{
VCHIQ_STATE_T *state = (VCHIQ_STATE_T *) v;
@@ -2021,7 +2073,9 @@ slot_handler_func(void *v)
pause_bulks(state);
if (queue_message(state, NULL,
VCHIQ_MAKE_MSG(VCHIQ_MSG_PAUSE, 0, 0),
- NULL, 0, 0, 0) != VCHIQ_RETRY) {
+ NULL, 0, 0,
+ QMFLAGS_NO_MUTEX_UNLOCK)
+ != VCHIQ_RETRY) {
vchiq_set_conn_state(state,
VCHIQ_CONNSTATE_PAUSE_SENT);
} else {
@@ -2039,7 +2093,8 @@ slot_handler_func(void *v)
case VCHIQ_CONNSTATE_RESUMING:
if (queue_message(state, NULL,
VCHIQ_MAKE_MSG(VCHIQ_MSG_RESUME, 0, 0),
- NULL, 0, 0, 0) != VCHIQ_RETRY) {
+ NULL, 0, 0, QMFLAGS_NO_MUTEX_LOCK)
+ != VCHIQ_RETRY) {
if (state->is_master)
resume_bulks(state);
vchiq_set_conn_state(state,
@@ -2075,8 +2130,8 @@ slot_handler_func(void *v)
/* Called by the recycle thread */
-int recycle_func(void *v);
-int
+static int recycle_func(void *v);
+static int
recycle_func(void *v)
{
VCHIQ_STATE_T *state = (VCHIQ_STATE_T *) v;
@@ -2092,8 +2147,8 @@ recycle_func(void *v)
/* Called by the sync thread */
-int sync_func(void *v);
-int
+static int sync_func(void *v);
+static int
sync_func(void *v)
{
VCHIQ_STATE_T *state = (VCHIQ_STATE_T *) v;
@@ -2143,7 +2198,7 @@ sync_func(void *v)
remoteport, localport, size);
if (size > 0)
vchiq_log_dump_mem("Rcvd", 0, header->data,
- min(64, size));
+ min(16, size));
}
switch (type) {
@@ -2162,6 +2217,7 @@ sync_func(void *v)
service->remoteport = remoteport;
vchiq_set_service_state(service,
VCHIQ_SRVSTATE_OPENSYNC);
+ service->sync = 1;
up(&service->remove_event);
}
release_message_sync(state, header);
@@ -2270,6 +2326,10 @@ vchiq_init_state(VCHIQ_STATE_T *state, V
static int id;
int i;
+ vchiq_log_warning(vchiq_core_log_level,
+ "%s: slot_zero = 0x%08lx, is_master = %d",
+ __func__, (unsigned long)slot_zero, is_master);
+
/* Check the input configuration */
if (slot_zero->magic != VCHIQ_MAGIC) {
@@ -2341,6 +2401,9 @@ vchiq_init_state(VCHIQ_STATE_T *state, V
return VCHIQ_ERROR;
}
+ if (VCHIQ_VERSION < slot_zero->version)
+ slot_zero->version = VCHIQ_VERSION;
+
if (is_master) {
local = &slot_zero->master;
remote = &slot_zero->slave;
@@ -2380,6 +2443,10 @@ vchiq_init_state(VCHIQ_STATE_T *state, V
_sema_init(&state->connect, 0);
lmutex_init(&state->mutex);
+ _sema_init(&state->trigger_event, 0);
+ _sema_init(&state->recycle_event, 0);
+ _sema_init(&state->sync_trigger_event, 0);
+ _sema_init(&state->sync_release_event, 0);
lmutex_init(&state->slot_mutex);
lmutex_init(&state->recycle_mutex);
@@ -2513,6 +2580,7 @@ vchiq_add_service_internal(VCHIQ_STATE_T
service->auto_close = 1;
service->sync = 0;
service->closing = 0;
+ service->trace = 0;
atomic_set(&service->poll_flags, 0);
service->version = params->version;
service->version_min = params->version_min;
@@ -2643,8 +2711,9 @@ vchiq_open_service_internal(VCHIQ_SERVIC
vchiq_use_service_internal(service);
status = queue_message(service->state, NULL,
VCHIQ_MAKE_MSG(VCHIQ_MSG_OPEN, service->localport, 0),
- &body, 1, sizeof(payload), 1);
+ &body, 1, sizeof(payload), QMFLAGS_IS_BLOCKING);
if (status == VCHIQ_SUCCESS) {
+ /* Wait for the ACK/NAK */
if (down_interruptible(&service->remove_event) != 0) {
status = VCHIQ_RETRY;
vchiq_release_service_internal(service);
@@ -2671,7 +2740,18 @@ release_service_messages(VCHIQ_SERVICE_T
int slot_last = state->remote->slot_last;
int i;
- /* Release any claimed messages */
+ /* Release any claimed messages aimed at this service */
+
+ if (service->sync) {
+ VCHIQ_HEADER_T *header =
+ (VCHIQ_HEADER_T *)SLOT_DATA_FROM_INDEX(state,
+ state->remote->slot_sync);
+ if (VCHIQ_MSG_DSTPORT(header->msgid) == service->localport)
+ release_message_sync(state, header);
+
+ return;
+ }
+
for (i = state->remote->slot_first; i <= slot_last; i++) {
VCHIQ_SLOT_INFO_T *slot_info =
SLOT_INFO_FROM_INDEX(state, i);
@@ -2869,17 +2949,31 @@ vchiq_close_service_internal(VCHIQ_SERVI
(VCHIQ_MSG_CLOSE,
service->localport,
VCHIQ_MSG_DSTPORT(service->remoteport)),
- NULL, 0, 0, 0);
+ NULL, 0, 0, QMFLAGS_NO_MUTEX_UNLOCK);
if (status == VCHIQ_SUCCESS) {
- if (!close_recvd)
+ if (!close_recvd) {
+ /* Change the state while the mutex is
+ still held */
+ vchiq_set_service_state(service,
+ VCHIQ_SRVSTATE_CLOSESENT);
+ lmutex_unlock(&state->slot_mutex);
+ if (service->sync)
+ lmutex_unlock(&state->sync_mutex);
break;
+ }
} else if (service->srvstate == VCHIQ_SRVSTATE_OPENSYNC) {
lmutex_unlock(&state->sync_mutex);
break;
} else
break;
+ /* Change the state while the mutex is still held */
+ vchiq_set_service_state(service, VCHIQ_SRVSTATE_CLOSERECVD);
+ lmutex_unlock(&state->slot_mutex);
+ if (service->sync)
+ lmutex_unlock(&state->sync_mutex);
+
status = close_service_complete(service,
VCHIQ_SRVSTATE_CLOSERECVD);
break;
@@ -2986,7 +3080,7 @@ vchiq_connect_internal(VCHIQ_STATE_T *st
if (state->conn_state == VCHIQ_CONNSTATE_DISCONNECTED) {
if (queue_message(state, NULL,
VCHIQ_MAKE_MSG(VCHIQ_MSG_CONNECT, 0, 0), NULL, 0,
- 0, 1) == VCHIQ_RETRY)
+ 0, QMFLAGS_IS_BLOCKING) == VCHIQ_RETRY)
return VCHIQ_RETRY;
vchiq_set_conn_state(state, VCHIQ_CONNSTATE_CONNECTING);
@@ -3272,6 +3366,16 @@ vchiq_bulk_transfer(VCHIQ_SERVICE_HANDLE
service->localport, service->remoteport, dir_char,
size, (unsigned int)bulk->data, (unsigned int)userdata);
+ /* The slot mutex must be held when the service is being closed, so
+ claim it here to ensure that isn't happening */
+ if (lmutex_lock_interruptible(&state->slot_mutex) != 0) {
+ status = VCHIQ_RETRY;
+ goto cancel_bulk_error_exit;
+ }
+
+ if (service->srvstate != VCHIQ_SRVSTATE_OPEN)
+ goto unlock_both_error_exit;
+
if (state->is_master) {
queue->local_insert++;
if (resolve_bulks(service, queue))
@@ -3285,14 +3389,17 @@ vchiq_bulk_transfer(VCHIQ_SERVICE_HANDLE
status = queue_message(state, NULL,
VCHIQ_MAKE_MSG(dir_msgtype,
service->localport, service->remoteport),
- &element, 1, sizeof(payload), 1);
+ &element, 1, sizeof(payload),
+ QMFLAGS_IS_BLOCKING |
+ QMFLAGS_NO_MUTEX_LOCK |
+ QMFLAGS_NO_MUTEX_UNLOCK);
if (status != VCHIQ_SUCCESS) {
- vchiq_complete_bulk(bulk);
- goto unlock_error_exit;
+ goto unlock_both_error_exit;
}
queue->local_insert++;
}
+ lmutex_unlock(&state->slot_mutex);
lmutex_unlock(&service->bulk_mutex);
vchiq_log_trace(vchiq_core_log_level,
@@ -3316,6 +3423,10 @@ waiting:
return status;
+unlock_both_error_exit:
+ lmutex_unlock(&state->slot_mutex);
+cancel_bulk_error_exit:
+ vchiq_complete_bulk(bulk);
unlock_error_exit:
lmutex_unlock(&service->bulk_mutex);
@@ -3526,6 +3637,11 @@ vchiq_set_service_option(VCHIQ_SERVICE_H
}
break;
+ case VCHIQ_SERVICE_OPTION_TRACE:
+ service->trace = value;
+ status = VCHIQ_SUCCESS;
+ break;
+
default:
break;
}
Index: src/sys/external/bsd/vchiq/dist/interface/vchiq_arm/vchiq_core.h
diff -u src/sys/external/bsd/vchiq/dist/interface/vchiq_arm/vchiq_core.h:1.3 src/sys/external/bsd/vchiq/dist/interface/vchiq_arm/vchiq_core.h:1.4
--- src/sys/external/bsd/vchiq/dist/interface/vchiq_arm/vchiq_core.h:1.3 Thu Mar 27 23:03:07 2014
+++ src/sys/external/bsd/vchiq/dist/interface/vchiq_arm/vchiq_core.h Thu Jan 12 05:41:25 2017
@@ -55,22 +55,22 @@
#ifndef vchiq_log_error
#define vchiq_log_error(cat, fmt, ...) \
do { if (cat >= VCHIQ_LOG_ERROR) \
- printf(VCHIQ_LOG_PREFIX fmt "\n", ##__VA_ARGS__); } while (0)
+ printf_tolog(VCHIQ_LOG_PREFIX fmt "\n", ##__VA_ARGS__); } while (0)
#endif
#ifndef vchiq_log_warning
#define vchiq_log_warning(cat, fmt, ...) \
do { if (cat >= VCHIQ_LOG_WARNING) \
- printf(VCHIQ_LOG_PREFIX fmt "\n", ##__VA_ARGS__); } while (0)
+ printf_tolog(VCHIQ_LOG_PREFIX fmt "\n", ##__VA_ARGS__); } while (0)
#endif
#ifndef vchiq_log_info
#define vchiq_log_info(cat, fmt, ...) \
do { if (cat >= VCHIQ_LOG_INFO) \
- printf(VCHIQ_LOG_PREFIX fmt "\n", ##__VA_ARGS__); } while (0)
+ printf_tolog(VCHIQ_LOG_PREFIX fmt "\n", ##__VA_ARGS__); } while (0)
#endif
#ifndef vchiq_log_trace
#define vchiq_log_trace(cat, fmt, ...) \
do { if (cat >= VCHIQ_LOG_TRACE) \
- printf(VCHIQ_LOG_PREFIX fmt "\n", ##__VA_ARGS__); } while (0)
+ printf_tolog(VCHIQ_LOG_PREFIX fmt "\n", ##__VA_ARGS__); } while (0)
#endif
#define vchiq_loud_error(...) \
@@ -295,6 +295,7 @@ typedef struct vchiq_service_struct {
char auto_close;
char sync;
char closing;
+ char trace;
atomic_t poll_flags;
short version;
short version_min;
@@ -402,6 +403,7 @@ struct vchiq_state_struct {
int initialised;
VCHIQ_CONNSTATE_T conn_state;
int is_master;
+ short version_common;
VCHIQ_SHARED_STATE_T *local;
VCHIQ_SHARED_STATE_T *remote;
@@ -606,6 +608,10 @@ find_service_for_instance(VCHIQ_INSTANCE
VCHIQ_SERVICE_HANDLE_T handle);
extern VCHIQ_SERVICE_T *
+find_closed_service_for_instance(VCHIQ_INSTANCE_T instance,
+ VCHIQ_SERVICE_HANDLE_T handle);
+
+extern VCHIQ_SERVICE_T *
next_service_by_instance(VCHIQ_STATE_T *state, VCHIQ_INSTANCE_T instance,
int *pidx);
Index: src/sys/external/bsd/vchiq/dist/interface/vchiq_arm/vchiq_if.h
diff -u src/sys/external/bsd/vchiq/dist/interface/vchiq_arm/vchiq_if.h:1.2 src/sys/external/bsd/vchiq/dist/interface/vchiq_arm/vchiq_if.h:1.3
--- src/sys/external/bsd/vchiq/dist/interface/vchiq_arm/vchiq_if.h:1.2 Thu Mar 27 23:03:07 2014
+++ src/sys/external/bsd/vchiq/dist/interface/vchiq_arm/vchiq_if.h Thu Jan 12 05:41:25 2017
@@ -74,7 +74,8 @@ typedef enum {
VCHIQ_SERVICE_OPTION_AUTOCLOSE,
VCHIQ_SERVICE_OPTION_SLOT_QUOTA,
VCHIQ_SERVICE_OPTION_MESSAGE_QUOTA,
- VCHIQ_SERVICE_OPTION_SYNCHRONOUS
+ VCHIQ_SERVICE_OPTION_SYNCHRONOUS,
+ VCHIQ_SERVICE_OPTION_TRACE
} VCHIQ_SERVICE_OPTION_T;
typedef struct vchiq_header_struct {
Index: src/sys/external/bsd/vchiq/dist/interface/vchiq_arm/vchiq_ioctl.h
diff -u src/sys/external/bsd/vchiq/dist/interface/vchiq_arm/vchiq_ioctl.h:1.2 src/sys/external/bsd/vchiq/dist/interface/vchiq_arm/vchiq_ioctl.h:1.3
--- src/sys/external/bsd/vchiq/dist/interface/vchiq_arm/vchiq_ioctl.h:1.2 Thu Mar 27 23:03:07 2014
+++ src/sys/external/bsd/vchiq/dist/interface/vchiq_arm/vchiq_ioctl.h Thu Jan 12 05:41:25 2017
@@ -123,6 +123,8 @@ typedef struct {
_IOW(VCHIQ_IOC_MAGIC, 14, VCHIQ_SET_SERVICE_OPTION_T)
#define VCHIQ_IOC_DUMP_PHYS_MEM \
_IOW(VCHIQ_IOC_MAGIC, 15, VCHIQ_DUMP_MEM_T)
-#define VCHIQ_IOC_MAX 15
+#define VCHIQ_IOC_LIB_VERSION _IO(VCHIQ_IOC_MAGIC, 16)
+#define VCHIQ_IOC_CLOSE_DELIVERED _IO(VCHIQ_IOC_MAGIC, 17)
+#define VCHIQ_IOC_MAX 17
#endif
Index: src/sys/external/bsd/vchiq/dist/interface/vchiq_arm/vchiq_util.c
diff -u src/sys/external/bsd/vchiq/dist/interface/vchiq_arm/vchiq_util.c:1.2 src/sys/external/bsd/vchiq/dist/interface/vchiq_arm/vchiq_util.c:1.3
--- src/sys/external/bsd/vchiq/dist/interface/vchiq_arm/vchiq_util.c:1.2 Thu Mar 27 23:03:07 2014
+++ src/sys/external/bsd/vchiq/dist/interface/vchiq_arm/vchiq_util.c Thu Jan 12 05:41:25 2017
@@ -45,6 +45,7 @@ int vchiu_queue_init(VCHIU_QUEUE_T *queu
queue->size = size;
queue->read = 0;
queue->write = 0;
+ queue->initialized = 1;
_sema_init(&queue->pop, 0);
_sema_init(&queue->push, 0);
@@ -75,6 +76,9 @@ int vchiu_queue_is_full(VCHIU_QUEUE_T *q
void vchiu_queue_push(VCHIU_QUEUE_T *queue, VCHIQ_HEADER_T *header)
{
+ if (!queue->initialized)
+ return;
+
while (queue->write == queue->read + queue->size) {
if (down_interruptible(&queue->pop) != 0) {
flush_signals(current);
Index: src/sys/external/bsd/vchiq/dist/interface/vchiq_arm/vchiq_util.h
diff -u src/sys/external/bsd/vchiq/dist/interface/vchiq_arm/vchiq_util.h:1.2 src/sys/external/bsd/vchiq/dist/interface/vchiq_arm/vchiq_util.h:1.3
--- src/sys/external/bsd/vchiq/dist/interface/vchiq_arm/vchiq_util.h:1.2 Thu Sep 19 14:43:39 2013
+++ src/sys/external/bsd/vchiq/dist/interface/vchiq_arm/vchiq_util.h Thu Jan 12 05:41:25 2017
@@ -44,6 +44,7 @@ typedef struct {
int size;
int read;
int write;
+ int initialized;
struct semaphore pop;
struct semaphore push;
@@ -63,4 +64,3 @@ extern VCHIQ_HEADER_T *vchiu_queue_peek(
extern VCHIQ_HEADER_T *vchiu_queue_pop(VCHIU_QUEUE_T *queue);
#endif
-
Index: src/sys/external/bsd/vchiq/dist/interface/vchiq_arm/vchiq_shim.c
diff -u src/sys/external/bsd/vchiq/dist/interface/vchiq_arm/vchiq_shim.c:1.5 src/sys/external/bsd/vchiq/dist/interface/vchiq_arm/vchiq_shim.c:1.6
--- src/sys/external/bsd/vchiq/dist/interface/vchiq_arm/vchiq_shim.c:1.5 Tue Sep 2 21:38:28 2014
+++ src/sys/external/bsd/vchiq/dist/interface/vchiq_arm/vchiq_shim.c Thu Jan 12 05:41:25 2017
@@ -403,6 +403,7 @@ int32_t vchi_held_msg_release(VCHI_HELD_
return 0;
}
+EXPORT_SYMBOL(vchi_held_msg_release);
/***********************************************************
* Name: vchi_msg_hold
@@ -448,13 +449,12 @@ int32_t vchi_msg_hold(VCHI_SERVICE_HANDL
return 0;
}
+EXPORT_SYMBOL(vchi_msg_hold);
/***********************************************************
* Name: vchi_initialise
*
* Arguments: VCHI_INSTANCE_T *instance_handle
- * VCHI_CONNECTION_T **connections
- * const uint32_t num_connections
*
* Description: Initialises the hardware but does not transmit anything
* When run as a Host App this will be called twice hence the need
@@ -725,6 +725,36 @@ int32_t vchi_service_destroy(const VCHI_
}
EXPORT_SYMBOL(vchi_service_destroy);
+int32_t vchi_service_set_option(const VCHI_SERVICE_HANDLE_T handle,
+ VCHI_SERVICE_OPTION_T option,
+ int value)
+{
+ int32_t ret = -1;
+ SHIM_SERVICE_T *service = (SHIM_SERVICE_T *)handle;
+ VCHIQ_SERVICE_OPTION_T vchiq_option;
+ switch (option) {
+ case VCHI_SERVICE_OPTION_TRACE:
+ vchiq_option = VCHIQ_SERVICE_OPTION_TRACE;
+ break;
+ case VCHI_SERVICE_OPTION_SYNCHRONOUS:
+ vchiq_option = VCHIQ_SERVICE_OPTION_SYNCHRONOUS;
+ break;
+ default:
+ service = NULL;
+ break;
+ }
+ if (service) {
+ VCHIQ_STATUS_T status =
+ vchiq_set_service_option(service->handle,
+ vchiq_option,
+ value);
+
+ ret = vchiq_status_to_vchi(status);
+ }
+ return ret;
+}
+EXPORT_SYMBOL(vchi_service_set_option);
+
int32_t vchi_get_peer_version( const VCHI_SERVICE_HANDLE_T handle, short *peer_version )
{
int32_t ret = -1;
Added files:
Index: src/sys/external/bsd/vchiq/dist/interface/vchiq_arm/vchiq_debugfs.h
diff -u /dev/null src/sys/external/bsd/vchiq/dist/interface/vchiq_arm/vchiq_debugfs.h:1.1
--- /dev/null Thu Jan 12 05:41:26 2017
+++ src/sys/external/bsd/vchiq/dist/interface/vchiq_arm/vchiq_debugfs.h Thu Jan 12 05:41:25 2017
@@ -0,0 +1,52 @@
+/**
+ * Copyright (c) 2014 Raspberry Pi (Trading) Ltd. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions, and the following disclaimer,
+ * without modification.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The names of the above-listed copyright holders may not be used
+ * to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * ALTERNATIVELY, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2, as published by the Free
+ * Software Foundation.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef VCHIQ_DEBUGFS_H
+#define VCHIQ_DEBUGFS_H
+
+#include "vchiq_core.h"
+
+typedef struct vchiq_debugfs_node_struct
+{
+ struct dentry *dentry;
+} VCHIQ_DEBUGFS_NODE_T;
+
+int vchiq_debugfs_init(void);
+
+void vchiq_debugfs_deinit(void);
+
+int vchiq_debugfs_add_instance(VCHIQ_INSTANCE_T instance);
+
+void vchiq_debugfs_remove_instance(VCHIQ_INSTANCE_T instance);
+
+#endif /* VCHIQ_DEBUGFS_H */