Skip site navigation (1)Skip section navigation (2)
Date:      Sun, 1 Nov 2015 22:17:39 +0000 (UTC)
From:      Oleksandr Tymoshenko <gonzo@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r290245 - in head/sys/contrib/vchiq/interface: vchi vchiq_arm
Message-ID:  <201511012217.tA1MHdMJ047219@repo.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: gonzo
Date: Sun Nov  1 22:17:39 2015
New Revision: 290245
URL: https://svnweb.freebsd.org/changeset/base/290245

Log:
  Synchronize with latest upstream VCHI code:
  
  - Add LIB_VERSION ioctl
  - Add CLOSE_DELIVERED ioctl
  - Bump code version
  
  Upstream version: 3782f2ad42c08f4d32f64138f8be7341afc380f5

Added:
  head/sys/contrib/vchiq/interface/vchiq_arm/vchiq_debugfs.c   (contents, props changed)
  head/sys/contrib/vchiq/interface/vchiq_arm/vchiq_debugfs.h   (contents, props changed)
  head/sys/contrib/vchiq/interface/vchiq_arm/vchiq_killable.h   (contents, props changed)
Deleted:
  head/sys/contrib/vchiq/interface/vchiq_arm/vchiq_proc.c
Modified:
  head/sys/contrib/vchiq/interface/vchi/vchi.h
  head/sys/contrib/vchiq/interface/vchi/vchi_common.h
  head/sys/contrib/vchiq/interface/vchiq_arm/vchiq.h
  head/sys/contrib/vchiq/interface/vchiq_arm/vchiq_2835_arm.c
  head/sys/contrib/vchiq/interface/vchiq_arm/vchiq_arm.c
  head/sys/contrib/vchiq/interface/vchiq_arm/vchiq_arm.h
  head/sys/contrib/vchiq/interface/vchiq_arm/vchiq_cfg.h
  head/sys/contrib/vchiq/interface/vchiq_arm/vchiq_connected.c
  head/sys/contrib/vchiq/interface/vchiq_arm/vchiq_connected.h
  head/sys/contrib/vchiq/interface/vchiq_arm/vchiq_core.c
  head/sys/contrib/vchiq/interface/vchiq_arm/vchiq_core.h
  head/sys/contrib/vchiq/interface/vchiq_arm/vchiq_if.h
  head/sys/contrib/vchiq/interface/vchiq_arm/vchiq_ioctl.h
  head/sys/contrib/vchiq/interface/vchiq_arm/vchiq_kern_lib.c
  head/sys/contrib/vchiq/interface/vchiq_arm/vchiq_shim.c
  head/sys/contrib/vchiq/interface/vchiq_arm/vchiq_util.c
  head/sys/contrib/vchiq/interface/vchiq_arm/vchiq_util.h

Modified: head/sys/contrib/vchiq/interface/vchi/vchi.h
==============================================================================
--- head/sys/contrib/vchiq/interface/vchi/vchi.h	Sun Nov  1 22:07:40 2015	(r290244)
+++ head/sys/contrib/vchiq/interface/vchi/vchi.h	Sun Nov  1 22:17:39 2015	(r290245)
@@ -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,

Modified: head/sys/contrib/vchiq/interface/vchi/vchi_common.h
==============================================================================
--- head/sys/contrib/vchiq/interface/vchi/vchi_common.h	Sun Nov  1 22:07:40 2015	(r290244)
+++ head/sys/contrib/vchiq/interface/vchi/vchi_common.h	Sun Nov  1 22:17:39 2015	(r290245)
@@ -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

Modified: head/sys/contrib/vchiq/interface/vchiq_arm/vchiq.h
==============================================================================
--- head/sys/contrib/vchiq/interface/vchiq_arm/vchiq.h	Sun Nov  1 22:07:40 2015	(r290244)
+++ head/sys/contrib/vchiq/interface/vchiq_arm/vchiq.h	Sun Nov  1 22:17:39 2015	(r290245)
@@ -38,4 +38,3 @@
 #include "vchiq_util.h"
 
 #endif
-

Modified: head/sys/contrib/vchiq/interface/vchiq_arm/vchiq_2835_arm.c
==============================================================================
--- head/sys/contrib/vchiq/interface/vchiq_arm/vchiq_2835_arm.c	Sun Nov  1 22:07:40 2015	(r290244)
+++ head/sys/contrib/vchiq/interface/vchiq_arm/vchiq_2835_arm.c	Sun Nov  1 22:17:39 2015	(r290245)
@@ -61,6 +61,7 @@ MALLOC_DEFINE(M_VCPAGELIST, "vcpagelist"
 #include "vchiq_arm.h"
 #include "vchiq_2835.h"
 #include "vchiq_connected.h"
+#include "vchiq_killable.h"
 
 #define MAX_FRAGMENTS (VCHIQ_NUM_CURRENT_BULKS * 2)
 

Modified: head/sys/contrib/vchiq/interface/vchiq_arm/vchiq_arm.c
==============================================================================
--- head/sys/contrib/vchiq/interface/vchiq_arm/vchiq_arm.c	Sun Nov  1 22:07:40 2015	(r290244)
+++ head/sys/contrib/vchiq/interface/vchiq_arm/vchiq_arm.c	Sun Nov  1 22:17:39 2015	(r290245)
@@ -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
@@ -102,13 +103,15 @@ 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;
 
@@ -131,11 +134,15 @@ 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;
+#ifdef notyet
+	VCHIQ_DEBUGFS_NODE_T proc_entry;
+#endif
 };
 
 typedef struct dump_context_struct {
@@ -165,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])) ==
@@ -232,10 +241,13 @@ 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. */
@@ -282,10 +294,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);
 
@@ -377,6 +389,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
 *
 ***************************************************************************/
@@ -496,14 +530,16 @@ vchiq_ioctl(struct cdev *cdev, u_long cm
 			user_service->service = service;
 			user_service->userdata = userdata;
 			user_service->instance = instance;
-			user_service->is_vchi = args.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 (args.is_open) {
 				status = vchiq_open_service_internal
@@ -543,8 +579,24 @@ vchiq_ioctl(struct cdev *cdev, u_long cm
 #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;
@@ -559,8 +611,24 @@ vchiq_ioctl(struct cdev *cdev, u_long cm
 #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;
@@ -824,8 +892,9 @@ vchiq_ioctl(struct cdev *cdev, u_long cm
 					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 *)(
@@ -1007,6 +1076,29 @@ vchiq_ioctl(struct cdev *cdev, u_long cm
 #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;
+		memcpy(&handle, (const void*)arg, sizeof(handle));
+
+		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;
@@ -1209,7 +1301,15 @@ vchiq_close(struct cdev *dev, int flags 
 				(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++;
 		}
 
@@ -1704,7 +1804,7 @@ vchiq_arm_init_state(VCHIQ_STATE_T *stat
 ** VC_RESUME_FAILED - Currently unused - no mechanism to fail resume exists.
 */
 
-inline void
+void
 set_suspend_state(VCHIQ_ARM_STATE_T *arm_state,
 	enum vc_suspend_status new_state)
 {
@@ -1725,6 +1825,7 @@ set_suspend_state(VCHIQ_ARM_STATE_T *arm
 		complete_all(&arm_state->vc_resume_complete);
 		break;
 	case VC_SUSPEND_IDLE:
+		/* TODO: reinit_completion */
 		INIT_COMPLETION(arm_state->vc_suspend_complete);
 		break;
 	case VC_SUSPEND_REQUESTED:
@@ -1741,7 +1842,7 @@ set_suspend_state(VCHIQ_ARM_STATE_T *arm
 	}
 }
 
-inline void
+void
 set_resume_state(VCHIQ_ARM_STATE_T *arm_state,
 	enum vc_resume_status new_state)
 {
@@ -1753,6 +1854,7 @@ set_resume_state(VCHIQ_ARM_STATE_T *arm_
 	case VC_RESUME_FAILED:
 		break;
 	case VC_RESUME_IDLE:
+		/* TODO: reinit_completion */
 		INIT_COMPLETION(arm_state->vc_resume_complete);
 		break;
 	case VC_RESUME_REQUESTED:
@@ -1815,6 +1917,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) {
+		/* TODO: reinit_completion */
 		INIT_COMPLETION(arm_state->blocked_blocker);
 		write_unlock_bh(&arm_state->susp_res_lock);
 		vchiq_log_info(vchiq_susp_log_level, "%s wait for previously "
@@ -1860,6 +1963,7 @@ block_resume(VCHIQ_ARM_STATE_T *arm_stat
 		write_lock_bh(&arm_state->susp_res_lock);
 		resume_count++;
 	}
+	/* TODO: reinit_completion */
 	INIT_COMPLETION(arm_state->resume_blocker);
 	arm_state->resume_blocked = 1;
 

Modified: head/sys/contrib/vchiq/interface/vchiq_arm/vchiq_arm.h
==============================================================================
--- head/sys/contrib/vchiq/interface/vchiq_arm/vchiq_arm.h	Sun Nov  1 22:07:40 2015	(r290244)
+++ head/sys/contrib/vchiq/interface/vchiq_arm/vchiq_arm.h	Sun Nov  1 22:17:39 2015	(r290245)
@@ -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
@@ -153,6 +154,9 @@ 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_platform_suspend(VCHIQ_STATE_T *state);
 
@@ -180,21 +184,32 @@ vchiq_use_internal(VCHIQ_STATE_T *state,
 extern VCHIQ_STATUS_T
 vchiq_release_internal(VCHIQ_STATE_T *state, VCHIQ_SERVICE_T *service);
 
-void
+#ifdef notyet
+extern VCHIQ_DEBUGFS_NODE_T *
+vchiq_instance_get_debugfs_node(VCHIQ_INSTANCE_T instance);
+#endif
+
+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 */

Modified: head/sys/contrib/vchiq/interface/vchiq_arm/vchiq_cfg.h
==============================================================================
--- head/sys/contrib/vchiq/interface/vchiq_arm/vchiq_cfg.h	Sun Nov  1 22:07:40 2015	(r290244)
+++ head/sys/contrib/vchiq/interface/vchiq_arm/vchiq_cfg.h	Sun Nov  1 22:17:39 2015	(r290245)
@@ -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

Modified: head/sys/contrib/vchiq/interface/vchiq_arm/vchiq_connected.c
==============================================================================
--- head/sys/contrib/vchiq/interface/vchiq_arm/vchiq_connected.c	Sun Nov  1 22:07:40 2015	(r290244)
+++ head/sys/contrib/vchiq/interface/vchiq_arm/vchiq_connected.c	Sun Nov  1 22:17:39 2015	(r290245)
@@ -33,6 +33,7 @@
 
 #include "vchiq_connected.h"
 #include "vchiq_core.h"
+#include "vchiq_killable.h"
 
 #define  MAX_CALLBACKS  10
 

Modified: head/sys/contrib/vchiq/interface/vchiq_arm/vchiq_connected.h
==============================================================================
--- head/sys/contrib/vchiq/interface/vchiq_arm/vchiq_connected.h	Sun Nov  1 22:07:40 2015	(r290244)
+++ head/sys/contrib/vchiq/interface/vchiq_arm/vchiq_connected.h	Sun Nov  1 22:17:39 2015	(r290245)
@@ -48,4 +48,3 @@ void vchiq_add_connected_callback(VCHIQ_
 void vchiq_call_connected_callbacks(void);
 
 #endif /* VCHIQ_CONNECTED_H */
-

Modified: head/sys/contrib/vchiq/interface/vchiq_arm/vchiq_core.c
==============================================================================
--- head/sys/contrib/vchiq/interface/vchiq_arm/vchiq_core.c	Sun Nov  1 22:07:40 2015	(r290244)
+++ head/sys/contrib/vchiq/interface/vchiq_arm/vchiq_core.c	Sun Nov  1 22:17:39 2015	(r290245)
@@ -32,6 +32,7 @@
  */
 
 #include "vchiq_core.h"
+#include "vchiq_killable.h"
 
 #define VCHIQ_SLOT_HANDLER_STACK 8192
 
@@ -47,9 +48,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 +66,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 +242,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)
 {
@@ -726,7 +762,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 +777,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 +785,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 +862,16 @@ queue_message(VCHIQ_STATE_T *state, VCHI
 		spin_unlock(&quota_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 +889,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)
@@ -861,11 +905,11 @@ queue_message(VCHIQ_STATE_T *state, VCHI
 					return VCHIQ_ERROR;
 				}
 				if (i == 0) {
-					if (vchiq_core_msg_log_level >=
-						VCHIQ_LOG_INFO)
+					if (SRVTRACE_ENABLED(service,
+							VCHIQ_LOG_INFO))
 						vchiq_log_dump_mem("Sent", 0,
 							header->data + pos,
-							min(64,
+							min(64u,
 							elements[0].size));
 				}
 			}
@@ -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);
@@ -1013,7 +1057,7 @@ queue_message_sync(VCHIQ_STATE_T *state,
 						VCHIQ_LOG_TRACE)
 						vchiq_log_dump_mem("Sent Sync",
 							0, header->data + pos,
-							min(64,
+							min(64u,
 							elements[0].size));
 				}
 			}
@@ -1320,11 +1364,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 +1378,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 +1425,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",
@@ -1488,10 +1532,10 @@ parse_open(VCHIQ_STATE_T *state, VCHIQ_H
 
 		if (service) {
 			/* A matching service exists */
-			short v = payload->version;
+			short version = payload->version;
 			short version_min = payload->version_min;
 			if ((service->version < version_min) ||
-				(v < service->version_min)) {
+				(version < service->version_min)) {
 				/* Version mismatch */
 				vchiq_loud_error_header();
 				vchiq_loud_error("%d: service %d (%c%c%c%c) "
@@ -1500,12 +1544,13 @@ parse_open(VCHIQ_STATE_T *state, VCHIQ_H
 					state->id, service->localport,
 					VCHIQ_FOURCC_AS_4CHARS(fourcc),
 					service->version, service->version_min,
-					v, version_min);
+					version, version_min);
 				vchiq_loud_error_footer();
 				unlock_service(service);
+				service = NULL;
 				goto fail_open;
 			}
-			service->peer_version = v;
+			service->peer_version = version;
 
 			if (service->srvstate == VCHIQ_SRVSTATE_LISTENING) {
 				struct vchiq_openack_payload ack_payload = {
@@ -1516,8 +1561,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 +1682,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 +1718,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,
@@ -1741,7 +1794,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 +1822,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 +1977,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);
@@ -2021,7 +2077,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 +2097,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,
@@ -2162,6 +2221,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);
@@ -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;
@@ -2517,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;
@@ -2647,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);
@@ -2675,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);
@@ -2873,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;
@@ -2990,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);
@@ -3276,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))
@@ -3289,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,
@@ -3320,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);
 
@@ -3530,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;
 		}

Modified: head/sys/contrib/vchiq/interface/vchiq_arm/vchiq_core.h
==============================================================================
--- head/sys/contrib/vchiq/interface/vchiq_arm/vchiq_core.h	Sun Nov  1 22:07:40 2015	(r290244)
+++ head/sys/contrib/vchiq/interface/vchiq_arm/vchiq_core.h	Sun Nov  1 22:17:39 2015	(r290245)
@@ -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);
 

Added: head/sys/contrib/vchiq/interface/vchiq_arm/vchiq_debugfs.c
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ head/sys/contrib/vchiq/interface/vchiq_arm/vchiq_debugfs.c	Sun Nov  1 22:17:39 2015	(r290245)
@@ -0,0 +1,383 @@
+/**
+ * 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
+ * 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

*** DIFF OUTPUT TRUNCATED AT 1000 LINES ***



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201511012217.tA1MHdMJ047219>