]> xenbits.xensource.com Git - people/julieng/freebsd.git/commitdiff
Synchronize with latest upstream VCHI code:
authorgonzo <gonzo@FreeBSD.org>
Sun, 1 Nov 2015 22:17:39 +0000 (22:17 +0000)
committergonzo <gonzo@FreeBSD.org>
Sun, 1 Nov 2015 22:17:39 +0000 (22:17 +0000)
- Add LIB_VERSION ioctl
- Add CLOSE_DELIVERED ioctl
- Bump code version

Upstream version: 3782f2ad42c08f4d32f64138f8be7341afc380f5

21 files changed:
sys/contrib/vchiq/interface/vchi/vchi.h
sys/contrib/vchiq/interface/vchi/vchi_common.h
sys/contrib/vchiq/interface/vchiq_arm/vchiq.h
sys/contrib/vchiq/interface/vchiq_arm/vchiq_2835_arm.c
sys/contrib/vchiq/interface/vchiq_arm/vchiq_arm.c
sys/contrib/vchiq/interface/vchiq_arm/vchiq_arm.h
sys/contrib/vchiq/interface/vchiq_arm/vchiq_cfg.h
sys/contrib/vchiq/interface/vchiq_arm/vchiq_connected.c
sys/contrib/vchiq/interface/vchiq_arm/vchiq_connected.h
sys/contrib/vchiq/interface/vchiq_arm/vchiq_core.c
sys/contrib/vchiq/interface/vchiq_arm/vchiq_core.h
sys/contrib/vchiq/interface/vchiq_arm/vchiq_debugfs.c [new file with mode: 0644]
sys/contrib/vchiq/interface/vchiq_arm/vchiq_debugfs.h [new file with mode: 0644]
sys/contrib/vchiq/interface/vchiq_arm/vchiq_if.h
sys/contrib/vchiq/interface/vchiq_arm/vchiq_ioctl.h
sys/contrib/vchiq/interface/vchiq_arm/vchiq_kern_lib.c
sys/contrib/vchiq/interface/vchiq_arm/vchiq_killable.h [new file with mode: 0644]
sys/contrib/vchiq/interface/vchiq_arm/vchiq_proc.c [deleted file]
sys/contrib/vchiq/interface/vchiq_arm/vchiq_shim.c
sys/contrib/vchiq/interface/vchiq_arm/vchiq_util.c
sys/contrib/vchiq/interface/vchiq_arm/vchiq_util.h

index f1b9d1c2bb5ae2027e47ce800d0aae4cc19c67c9..c80b255107284b075ed2ee33e0c1cb3c4f500c5e 100644 (file)
@@ -220,7 +220,12 @@ extern int32_t vchi_service_use( const VCHI_SERVICE_HANDLE_T handle );
 // 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 9e6c00e82324c423985d28b494ace826f928b639..d535a72970d3f1ee63d2038550db8f4e43589c72 100644 (file)
@@ -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 f87dcbdaaffcd051f14361a96a3e36cb72c98a0c..ad398bae6ee4c3d64fc1a37808398397a9a0fefe 100644 (file)
@@ -38,4 +38,3 @@
 #include "vchiq_util.h"
 
 #endif
-
index 2f8ed436a1d5c7b645a7809d85a9a7d68a82d571..c826999f01ec42f1a5279646cbe8f8f69dcd0961 100644 (file)
@@ -61,6 +61,7 @@ MALLOC_DEFINE(M_VCPAGELIST, "vcpagelist", "VideoCore pagelist memory");
 #include "vchiq_arm.h"
 #include "vchiq_2835.h"
 #include "vchiq_connected.h"
+#include "vchiq_killable.h"
 
 #define MAX_FRAGMENTS (VCHIQ_NUM_CURRENT_BULKS * 2)
 
index d534a7fa755f71c7f94b10723dbb8d3732ed95cb..556ddf6197781d22809774ae98ebaa48daa915b3 100644 (file)
@@ -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, VCHIQ_REASON_T reason,
        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, VCHIQ_HEADER_T *header,
                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);
 
@@ -375,6 +387,28 @@ user_service_free(void *userdata)
        kfree(user_service);
 }
 
+/****************************************************************************
+*
+*   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 cmd, caddr_t arg, int fflag,
                        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 cmd, caddr_t arg, int fflag,
 #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 cmd, caddr_t arg, int fflag,
 #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 cmd, caddr_t arg, int fflag,
                                        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 cmd, caddr_t arg, int fflag,
 #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 __unused, int fmt __unused,
                                (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 *state, VCHIQ_ARM_STATE_T *arm_state)
 ** 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_state,
                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_state,
        }
 }
 
-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_state,
        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_state)
         * (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_state)
                write_lock_bh(&arm_state->susp_res_lock);
                resume_count++;
        }
+       /* TODO: reinit_completion */
        INIT_COMPLETION(arm_state->resume_blocker);
        arm_state->resume_blocked = 1;
 
index e514a7f6119b6c476ab0de447b20d86ed1fd48a4..c7e9ae72dfbe1f041b680b79ca56e3aca273344b 100644 (file)
@@ -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, VCHIQ_SERVICE_T *service,
 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 */
index 493c86c34957cbcfcdc7406e26d92a26e2a8abd9..d2797db702f9fd2e35beb3dd2d5ac9323ccedfc6 100644 (file)
@@ -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
 
 #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 0bc6c587754f11b5d3c0945e032f14fb7f0c67fd..928e454031da193eaa2f993db23c83e184f3bc0b 100644 (file)
@@ -33,6 +33,7 @@
 
 #include "vchiq_connected.h"
 #include "vchiq_core.h"
+#include "vchiq_killable.h"
 
 #define  MAX_CALLBACKS  10
 
index e4cfdcc8aab203d8edc45006c93b354d5175f07b..863b3e335c1aa4bbe7f8652e0e6c3713ea1aed45 100644 (file)
@@ -48,4 +48,3 @@ void vchiq_add_connected_callback(VCHIQ_CONNECTED_CALLBACK_T callback);
 void vchiq_call_connected_callbacks(void);
 
 #endif /* VCHIQ_CONNECTED_H */
-
index 633fd869b5cc9432d353cda539f9233b7a317fdc..2ded208bae35559a395528ae644f549ce8026456 100644 (file)
@@ -32,6 +32,7 @@
  */
 
 #include "vchiq_core.h"
+#include "vchiq_killable.h"
 
 #define VCHIQ_SLOT_HANDLER_STACK 8192
 
 #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)));
@@ -230,6 +241,31 @@ find_service_for_instance(VCHIQ_INSTANCE_T instance,
        return service;
 }
 
+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, VCHIQ_SERVICE_T *service,
 
        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, VCHIQ_SERVICE_T *service,
                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, VCHIQ_SERVICE_T *service,
                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, VCHIQ_SERVICE_T *service,
                        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, VCHIQ_SERVICE_T *service,
                                        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, VCHIQ_SERVICE_T *service,
                        ? 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, VCHIQ_SERVICE_T *service,
        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_SERVICE_T *service,
                                                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_BULK_QUEUE_T *queue)
                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, VCHIQ_BULK_QUEUE_T *queue)
                                        (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 *service, VCHIQ_BULK_QUEUE_T *queue)
                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_HEADER_T *header)
 
                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_HEADER_T *header)
                                        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_HEADER_T *header)
                                        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, VCHIQ_SLOT_ZERO_T *slot_zero,
                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 *state,
                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_SERVICE_T *service, int client_id)
        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 *service)
        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_SERVICE_T *service, int close_recvd)
                                (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 *state, VCHIQ_INSTANCE_T instance)
        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_T 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_T 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_HANDLE_T handle,
                        }
                        break;
 
+               case VCHIQ_SERVICE_OPTION_TRACE:
+                       service->trace = value;
+                       status = VCHIQ_SUCCESS;
+                       break;
+
                default:
                        break;
                }
index fb50e85f2d88236c1ce2e3722e6e821cc6d6b181..754c9f66924025ab523e790ef71454ecd4f44ee4 100644 (file)
@@ -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;
@@ -605,6 +607,10 @@ extern VCHIQ_SERVICE_T *
 find_service_for_instance(VCHIQ_INSTANCE_T 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);
diff --git a/sys/contrib/vchiq/interface/vchiq_arm/vchiq_debugfs.c b/sys/contrib/vchiq/interface/vchiq_arm/vchiq_debugfs.c
new file mode 100644 (file)
index 0000000..7e03213
--- /dev/null
@@ -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
+ * 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.
+ */
+
+
+#include <linux/debugfs.h>
+#include "vchiq_core.h"
+#include "vchiq_arm.h"
+#include "vchiq_debugfs.h"
+
+#ifdef CONFIG_DEBUG_FS
+
+/****************************************************************************
+*
+*   log category entries
+*
+***************************************************************************/
+#define DEBUGFS_WRITE_BUF_SIZE 256
+
+#define VCHIQ_LOG_ERROR_STR   "error"
+#define VCHIQ_LOG_WARNING_STR "warning"
+#define VCHIQ_LOG_INFO_STR    "info"
+#define VCHIQ_LOG_TRACE_STR   "trace"
+
+
+/* Top-level debug info */
+struct vchiq_debugfs_info {
+       /* Global 'vchiq' debugfs entry used by all instances */
+       struct dentry *vchiq_cfg_dir;
+
+       /* one entry per client process */
+       struct dentry *clients;
+
+       /* log categories */
+       struct dentry *log_categories;
+};
+
+static struct vchiq_debugfs_info debugfs_info;
+
+/* Log category debugfs entries */
+struct vchiq_debugfs_log_entry {
+       const char *name;
+       int *plevel;
+       struct dentry *dir;
+};
+
+static struct vchiq_debugfs_log_entry vchiq_debugfs_log_entries[] = {
+       { "core", &vchiq_core_log_level },
+       { "msg",  &vchiq_core_msg_log_level },
+       { "sync", &vchiq_sync_log_level },
+       { "susp", &vchiq_susp_log_level },
+       { "arm",  &vchiq_arm_log_level },
+};
+static int n_log_entries =
+       sizeof(vchiq_debugfs_log_entries)/sizeof(vchiq_debugfs_log_entries[0]);
+
+
+static struct dentry *vchiq_clients_top(void);
+static struct dentry *vchiq_debugfs_top(void);
+
+static int debugfs_log_show(struct seq_file *f, void *offset)
+{
+       int *levp = f->private;
+       char *log_value = NULL;
+
+       switch (*levp) {
+       case VCHIQ_LOG_ERROR:
+               log_value = VCHIQ_LOG_ERROR_STR;
+               break;
+       case VCHIQ_LOG_WARNING:
+               log_value = VCHIQ_LOG_WARNING_STR;
+               break;
+       case VCHIQ_LOG_INFO:
+               log_value = VCHIQ_LOG_INFO_STR;
+               break;
+       case VCHIQ_LOG_TRACE:
+               log_value = VCHIQ_LOG_TRACE_STR;
+               break;
+       default:
+               break;
+       }
+
+       seq_printf(f, "%s\n", log_value ? log_value : "(null)");
+
+       return 0;
+}
+
+static int debugfs_log_open(struct inode *inode, struct file *file)
+{
+       return single_open(file, debugfs_log_show, inode->i_private);
+}
+
+static int debugfs_log_write(struct file *file,
+       const char __user *buffer,
+       size_t count, loff_t *ppos)
+{
+       struct seq_file *f = (struct seq_file *)file->private_data;
+       int *levp = f->private;
+       char kbuf[DEBUGFS_WRITE_BUF_SIZE + 1];
+
+       memset(kbuf, 0, DEBUGFS_WRITE_BUF_SIZE + 1);
+       if (count >= DEBUGFS_WRITE_BUF_SIZE)
+               count = DEBUGFS_WRITE_BUF_SIZE;
+
+       if (copy_from_user(kbuf, buffer, count) != 0)
+               return -EFAULT;
+       kbuf[count - 1] = 0;
+
+       if (strncmp("error", kbuf, strlen("error")) == 0)
+               *levp = VCHIQ_LOG_ERROR;
+       else if (strncmp("warning", kbuf, strlen("warning")) == 0)
+               *levp = VCHIQ_LOG_WARNING;
+       else if (strncmp("info", kbuf, strlen("info")) == 0)
+               *levp = VCHIQ_LOG_INFO;
+       else if (strncmp("trace", kbuf, strlen("trace")) == 0)
+               *levp = VCHIQ_LOG_TRACE;
+       else
+               *levp = VCHIQ_LOG_DEFAULT;
+
+       *ppos += count;
+
+       return count;
+}
+
+static const struct file_operations debugfs_log_fops = {
+       .owner          = THIS_MODULE,
+       .open           = debugfs_log_open,
+       .write          = debugfs_log_write,
+       .read           = seq_read,
+       .llseek         = seq_lseek,
+       .release        = single_release,
+};
+
+/* create an entry under <debugfs>/vchiq/log for each log category */
+static int vchiq_debugfs_create_log_entries(struct dentry *top)
+{
+       struct dentry *dir;
+       size_t i;
+       int ret = 0;
+       dir = debugfs_create_dir("log", vchiq_debugfs_top());
+       if (!dir)
+               return -ENOMEM;
+       debugfs_info.log_categories = dir;
+
+       for (i = 0; i < n_log_entries; i++) {
+               void *levp = (void *)vchiq_debugfs_log_entries[i].plevel;
+               dir = debugfs_create_file(vchiq_debugfs_log_entries[i].name,
+                                         0644,
+                                         debugfs_info.log_categories,
+                                         levp,
+                                         &debugfs_log_fops);
+               if (!dir) {
+                       ret = -ENOMEM;
+                       break;
+               }
+
+               vchiq_debugfs_log_entries[i].dir = dir;
+       }
+       return ret;
+}
+
+static int debugfs_usecount_show(struct seq_file *f, void *offset)
+{
+       VCHIQ_INSTANCE_T instance = f->private;
+       int use_count;
+
+       use_count = vchiq_instance_get_use_count(instance);
+       seq_printf(f, "%d\n", use_count);
+
+       return 0;
+}
+
+static int debugfs_usecount_open(struct inode *inode, struct file *file)
+{
+       return single_open(file, debugfs_usecount_show, inode->i_private);
+}
+
+static const struct file_operations debugfs_usecount_fops = {
+       .owner          = THIS_MODULE,
+       .open           = debugfs_usecount_open,
+       .read           = seq_read,
+       .llseek         = seq_lseek,
+       .release        = single_release,
+};
+
+static int debugfs_trace_show(struct seq_file *f, void *offset)
+{
+       VCHIQ_INSTANCE_T instance = f->private;
+       int trace;
+
+       trace = vchiq_instance_get_trace(instance);
+       seq_printf(f, "%s\n", trace ? "Y" : "N");
+
+       return 0;
+}
+
+static int debugfs_trace_open(struct inode *inode, struct file *file)
+{
+       return single_open(file, debugfs_trace_show, inode->i_private);
+}
+
+static int debugfs_trace_write(struct file *file,
+       const char __user *buffer,
+       size_t count, loff_t *ppos)
+{
+       struct seq_file *f = (struct seq_file *)file->private_data;
+       VCHIQ_INSTANCE_T instance = f->private;
+       char firstchar;
+
+       if (copy_from_user(&firstchar, buffer, 1) != 0)
+               return -EFAULT;
+
+       switch (firstchar) {
+       case 'Y':
+       case 'y':
+       case '1':
+               vchiq_instance_set_trace(instance, 1);
+               break;
+       case 'N':
+       case 'n':
+       case '0':
+               vchiq_instance_set_trace(instance, 0);
+               break;
+       default:
+               break;
+       }
+
+       *ppos += count;
+
+       return count;
+}
+
+static const struct file_operations debugfs_trace_fops = {
+       .owner          = THIS_MODULE,
+       .open           = debugfs_trace_open,
+       .write          = debugfs_trace_write,
+       .read           = seq_read,
+       .llseek         = seq_lseek,
+       .release        = single_release,
+};
+
+/* add an instance (process) to the debugfs entries */
+int vchiq_debugfs_add_instance(VCHIQ_INSTANCE_T instance)
+{
+       char pidstr[16];
+       struct dentry *top, *use_count, *trace;
+       struct dentry *clients = vchiq_clients_top();
+
+       snprintf(pidstr, sizeof(pidstr), "%d",
+                vchiq_instance_get_pid(instance));
+
+       top = debugfs_create_dir(pidstr, clients);
+       if (!top)
+               goto fail_top;
+
+       use_count = debugfs_create_file("use_count",
+                                       0444, top,
+                                       instance,
+                                       &debugfs_usecount_fops);
+       if (!use_count)
+               goto fail_use_count;
+
+       trace = debugfs_create_file("trace",
+                                   0644, top,
+                                   instance,
+                                   &debugfs_trace_fops);
+       if (!trace)
+               goto fail_trace;
+
+       vchiq_instance_get_debugfs_node(instance)->dentry = top;
+
+       return 0;
+
+fail_trace:
+       debugfs_remove(use_count);
+fail_use_count:
+       debugfs_remove(top);
+fail_top:
+       return -ENOMEM;
+}
+
+void vchiq_debugfs_remove_instance(VCHIQ_INSTANCE_T instance)
+{
+       VCHIQ_DEBUGFS_NODE_T *node = vchiq_instance_get_debugfs_node(instance);
+       debugfs_remove_recursive(node->dentry);
+}
+
+
+int vchiq_debugfs_init(void)
+{
+       BUG_ON(debugfs_info.vchiq_cfg_dir != NULL);
+
+       debugfs_info.vchiq_cfg_dir = debugfs_create_dir("vchiq", NULL);
+       if (debugfs_info.vchiq_cfg_dir == NULL)
+               goto fail;
+
+       debugfs_info.clients = debugfs_create_dir("clients",
+                               vchiq_debugfs_top());
+       if (!debugfs_info.clients)
+               goto fail;
+
+       if (vchiq_debugfs_create_log_entries(vchiq_debugfs_top()) != 0)
+               goto fail;
+
+       return 0;
+
+fail:
+       vchiq_debugfs_deinit();
+       vchiq_log_error(vchiq_arm_log_level,
+               "%s: failed to create debugfs directory",
+               __func__);
+
+       return -ENOMEM;
+}
+
+/* remove all the debugfs entries */
+void vchiq_debugfs_deinit(void)
+{
+       debugfs_remove_recursive(vchiq_debugfs_top());
+}
+
+static struct dentry *vchiq_clients_top(void)
+{
+       return debugfs_info.clients;
+}
+
+static struct dentry *vchiq_debugfs_top(void)
+{
+       BUG_ON(debugfs_info.vchiq_cfg_dir == NULL);
+       return debugfs_info.vchiq_cfg_dir;
+}
+
+#else /* CONFIG_DEBUG_FS */
+
+int vchiq_debugfs_init(void)
+{
+       return 0;
+}
+
+void vchiq_debugfs_deinit(void)
+{
+}
+
+int vchiq_debugfs_add_instance(VCHIQ_INSTANCE_T instance)
+{
+       return 0;
+}
+
+void vchiq_debugfs_remove_instance(VCHIQ_INSTANCE_T instance)
+{
+}
+
+#endif /* CONFIG_DEBUG_FS */
diff --git a/sys/contrib/vchiq/interface/vchiq_arm/vchiq_debugfs.h b/sys/contrib/vchiq/interface/vchiq_arm/vchiq_debugfs.h
new file mode 100644 (file)
index 0000000..4d6a378
--- /dev/null
@@ -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 */
index 6a95a67a833a82d2cf3723b794655b97d5a566f8..a5fb12863c73f3ab823a7bac5d5f4f3a5e69f58e 100644 (file)
@@ -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 13103c5c36324ba8df4898caa464c169c91ca909..617479eff136fa48daff91d5551bf35663c4f6cf 100644 (file)
@@ -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 6edbb67d8e0a118668fd05a0491610486e4ccc51..1f849a09d854c27ee8edb5fe9f394f260e851c09 100644 (file)
@@ -35,6 +35,7 @@
 
 #include "vchiq_core.h"
 #include "vchiq_arm.h"
+#include "vchiq_killable.h"
 
 /* ---- Public Variables ------------------------------------------------- */
 
diff --git a/sys/contrib/vchiq/interface/vchiq_arm/vchiq_killable.h b/sys/contrib/vchiq/interface/vchiq_arm/vchiq_killable.h
new file mode 100644 (file)
index 0000000..9385dbb
--- /dev/null
@@ -0,0 +1,72 @@
+/**
+ * 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
+ * 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_KILLABLE_H
+#define VCHIQ_KILLABLE_H
+
+#ifdef notyet
+#include <linux/mutex.h>
+#include <linux/semaphore.h>
+
+#define SHUTDOWN_SIGS   (sigmask(SIGKILL) | sigmask(SIGINT) | sigmask(SIGQUIT) | sigmask(SIGTRAP) | sigmask(SIGSTOP) | sigmask(SIGCONT))
+
+static inline int __must_check down_interruptible_killable(struct semaphore *sem)
+{
+       /* Allow interception of killable signals only. We don't want to be interrupted by harmless signals like SIGALRM */
+       int ret;
+       sigset_t blocked, oldset;
+       siginitsetinv(&blocked, SHUTDOWN_SIGS);
+       sigprocmask(SIG_SETMASK, &blocked, &oldset);
+       ret = down_interruptible(sem);
+       sigprocmask(SIG_SETMASK, &oldset, NULL);
+       return ret;
+}
+#define down_interruptible down_interruptible_killable
+
+
+static inline int __must_check mutex_lock_interruptible_killable(struct mutex *lock)
+{
+       /* Allow interception of killable signals only. We don't want to be interrupted by harmless signals like SIGALRM */
+       int ret;
+       sigset_t blocked, oldset;
+       siginitsetinv(&blocked, SHUTDOWN_SIGS);
+       sigprocmask(SIG_SETMASK, &blocked, &oldset);
+       ret = mutex_lock_interruptible(lock);
+       sigprocmask(SIG_SETMASK, &oldset, NULL);
+       return ret;
+}
+#define mutex_lock_interruptible mutex_lock_interruptible_killable
+
+#endif
+
+#endif
diff --git a/sys/contrib/vchiq/interface/vchiq_arm/vchiq_proc.c b/sys/contrib/vchiq/interface/vchiq_arm/vchiq_proc.c
deleted file mode 100644 (file)
index 863c285..0000000
+++ /dev/null
@@ -1,240 +0,0 @@
-/**
- * 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
- * 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.
- */
-
-
-#include <linux/proc_fs.h>
-#include "vchiq_core.h"
-#include "vchiq_arm.h"
-
-struct vchiq_proc_info {
-       /* Global 'vc' proc entry used by all instances */
-       struct proc_dir_entry *vc_cfg_dir;
-
-       /* one entry per client process */
-       struct proc_dir_entry *clients;
-
-       /* log categories */
-       struct proc_dir_entry *log_categories;
-};
-
-static struct vchiq_proc_info proc_info;
-
-struct proc_dir_entry *vchiq_proc_top(void)
-{
-       BUG_ON(proc_info.vc_cfg_dir == NULL);
-       return proc_info.vc_cfg_dir;
-}
-
-/****************************************************************************
-*
-*   log category entries
-*
-***************************************************************************/
-#define PROC_WRITE_BUF_SIZE 256
-
-#define VCHIQ_LOG_ERROR_STR   "error"
-#define VCHIQ_LOG_WARNING_STR "warning"
-#define VCHIQ_LOG_INFO_STR    "info"
-#define VCHIQ_LOG_TRACE_STR   "trace"
-
-static int log_cfg_read(char *buffer,
-       char **start,
-       off_t off,
-       int count,
-       int *eof,
-       void *data)
-{
-       int len = 0;
-       char *log_value = NULL;
-
-       switch (*((int *)data)) {
-       case VCHIQ_LOG_ERROR:
-               log_value = VCHIQ_LOG_ERROR_STR;
-               break;
-       case VCHIQ_LOG_WARNING:
-               log_value = VCHIQ_LOG_WARNING_STR;
-               break;
-       case VCHIQ_LOG_INFO:
-               log_value = VCHIQ_LOG_INFO_STR;
-               break;
-       case VCHIQ_LOG_TRACE:
-               log_value = VCHIQ_LOG_TRACE_STR;
-               break;
-       default:
-               break;
-       }
-
-       len += snprintf(buffer + len, count - len,
-               "%s\n",
-               log_value ? log_value : "(null)");
-
-       return len;
-}
-
-
-static int log_cfg_write(struct file *file,
-       const char __user *buffer,
-       unsigned long count,
-       void *data)
-{
-       int *log_module = data;
-       char kbuf[PROC_WRITE_BUF_SIZE + 1];
-
-       (void)file;
-
-       memset(kbuf, 0, PROC_WRITE_BUF_SIZE + 1);
-       if (count >= PROC_WRITE_BUF_SIZE)
-               count = PROC_WRITE_BUF_SIZE;
-
-       if (copy_from_user(kbuf,
-               buffer,
-               count) != 0)
-               return -EFAULT;
-       kbuf[count - 1] = 0;
-
-       if (strncmp("error", kbuf, strlen("error")) == 0)
-               *log_module = VCHIQ_LOG_ERROR;
-       else if (strncmp("warning", kbuf, strlen("warning")) == 0)
-               *log_module = VCHIQ_LOG_WARNING;
-       else if (strncmp("info", kbuf, strlen("info")) == 0)
-               *log_module = VCHIQ_LOG_INFO;
-       else if (strncmp("trace", kbuf, strlen("trace")) == 0)
-               *log_module = VCHIQ_LOG_TRACE;
-       else
-               *log_module = VCHIQ_LOG_DEFAULT;
-
-       return count;
-}
-
-/* Log category proc entries */
-struct vchiq_proc_log_entry {
-       const char *name;
-       int *plevel;
-       struct proc_dir_entry *dir;
-};
-
-static struct vchiq_proc_log_entry vchiq_proc_log_entries[] = {
-       { "core", &vchiq_core_log_level },
-       { "msg",  &vchiq_core_msg_log_level },
-       { "sync", &vchiq_sync_log_level },
-       { "susp", &vchiq_susp_log_level },
-       { "arm",  &vchiq_arm_log_level },
-};
-static int n_log_entries =
-       sizeof(vchiq_proc_log_entries)/sizeof(vchiq_proc_log_entries[0]);
-
-/* create an entry under /proc/vc/log for each log category */
-static int vchiq_proc_create_log_entries(struct proc_dir_entry *top)
-{
-       struct proc_dir_entry *dir;
-       size_t i;
-       int ret = 0;
-
-       dir = proc_mkdir("log", proc_info.vc_cfg_dir);
-       if (!dir)
-               return -ENOMEM;
-       proc_info.log_categories = dir;
-
-       for (i = 0; i < n_log_entries; i++) {
-               dir = create_proc_entry(vchiq_proc_log_entries[i].name,
-                                       0644,
-                                       proc_info.log_categories);
-               if (!dir) {
-                       ret = -ENOMEM;
-                       break;
-               }
-
-               dir->read_proc = &log_cfg_read;
-               dir->write_proc = &log_cfg_write;
-               dir->data = (void *)vchiq_proc_log_entries[i].plevel;
-
-               vchiq_proc_log_entries[i].dir = dir;
-       }
-       return ret;
-}
-
-
-int vchiq_proc_init(void)
-{
-       BUG_ON(proc_info.vc_cfg_dir != NULL);
-
-       proc_info.vc_cfg_dir = proc_mkdir("vc", NULL);
-       if (proc_info.vc_cfg_dir == NULL)
-               goto fail;
-
-       proc_info.clients = proc_mkdir("clients",
-                               proc_info.vc_cfg_dir);
-       if (!proc_info.clients)
-               goto fail;
-
-       if (vchiq_proc_create_log_entries(proc_info.vc_cfg_dir) != 0)
-               goto fail;
-
-       return 0;
-
-fail:
-       vchiq_proc_deinit();
-       vchiq_log_error(vchiq_arm_log_level,
-               "%s: failed to create proc directory",
-               __func__);
-
-       return -ENOMEM;
-}
-
-/* remove all the proc entries */
-void vchiq_proc_deinit(void)
-{
-       /* log category entries */
-       if (proc_info.log_categories) {
-               size_t i;
-               for (i = 0; i < n_log_entries; i++)
-                       if (vchiq_proc_log_entries[i].dir)
-                               remove_proc_entry(
-                                       vchiq_proc_log_entries[i].name,
-                                       proc_info.log_categories);
-
-               remove_proc_entry(proc_info.log_categories->name,
-                                 proc_info.vc_cfg_dir);
-       }
-       if (proc_info.clients)
-               remove_proc_entry(proc_info.clients->name,
-                                 proc_info.vc_cfg_dir);
-       if (proc_info.vc_cfg_dir)
-               remove_proc_entry(proc_info.vc_cfg_dir->name, NULL);
-}
-
-struct proc_dir_entry *vchiq_clients_top(void)
-{
-       return proc_info.clients;
-}
-
index 94ad46ea833f53b804acc6f9c161db45c811d0fc..cc8ef2e071f857d426e06b675a6538b832cb28f9 100644 (file)
@@ -403,6 +403,7 @@ int32_t vchi_held_msg_release(VCHI_HELD_MSG_T *message)
 
        return 0;
 }
+EXPORT_SYMBOL(vchi_held_msg_release);
 
 /***********************************************************
  * Name: vchi_msg_hold
@@ -448,13 +449,12 @@ int32_t vchi_msg_hold(VCHI_SERVICE_HANDLE_T handle,
 
        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_SERVICE_HANDLE_T handle)
 }
 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;
index d972d3b791f410c6b114f53cf2e46fb77241ef57..67270b3157275cd8e2d409f33c5677a4d06fa974 100644 (file)
@@ -45,6 +45,7 @@ int vchiu_queue_init(VCHIU_QUEUE_T *queue, int size)
        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 *queue)
 
 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 ce49037f96005009f49f819842f946835e4c28cd..b63f1aa2b263afafa8d2d6f171f888083bdd57a1 100644 (file)
@@ -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(VCHIU_QUEUE_T *queue);
 extern VCHIQ_HEADER_T *vchiu_queue_pop(VCHIU_QUEUE_T *queue);
 
 #endif
-