Synchronize with latest upstream VCHI code:
- Add LIB_VERSION ioctl - Add CLOSE_DELIVERED ioctl - Bump code version Upstream version: 3782f2ad42c08f4d32f64138f8be7341afc380f5
This commit is contained in:
parent
046bfe5240
commit
a0b8746173
@ -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,
|
||||
|
@ -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
|
||||
|
@ -38,4 +38,3 @@
|
||||
#include "vchiq_util.h"
|
||||
|
||||
#endif
|
||||
|
||||
|
@ -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)
|
||||
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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 */
|
||||
|
@ -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
|
||||
|
@ -33,6 +33,7 @@
|
||||
|
||||
#include "vchiq_connected.h"
|
||||
#include "vchiq_core.h"
|
||||
#include "vchiq_killable.h"
|
||||
|
||||
#define MAX_CALLBACKS 10
|
||||
|
||||
|
@ -48,4 +48,3 @@ void vchiq_add_connected_callback(VCHIQ_CONNECTED_CALLBACK_T callback);
|
||||
void vchiq_call_connected_callbacks(void);
|
||||
|
||||
#endif /* VCHIQ_CONNECTED_H */
|
||||
|
||||
|
@ -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)));
|
||||
@ -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("a_spinlock);
|
||||
}
|
||||
|
||||
header = reserve_space(state, stride, is_blocking);
|
||||
header = reserve_space(state, stride, flags & QMFLAGS_IS_BLOCKING);
|
||||
|
||||
if (!header) {
|
||||
if (service)
|
||||
VCHIQ_SERVICE_STATS_INC(service, slot_stalls);
|
||||
lmutex_unlock(&state->slot_mutex);
|
||||
/* In the event of a failure, return the mutex to the
|
||||
state it was in */
|
||||
if (!(flags & QMFLAGS_NO_MUTEX_LOCK))
|
||||
lmutex_unlock(&state->slot_mutex);
|
||||
|
||||
return VCHIQ_RETRY;
|
||||
}
|
||||
|
||||
@ -847,6 +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;
|
||||
}
|
||||
|
@ -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);
|
||||
|
383
sys/contrib/vchiq/interface/vchiq_arm/vchiq_debugfs.c
Normal file
383
sys/contrib/vchiq/interface/vchiq_arm/vchiq_debugfs.c
Normal file
@ -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 */
|
52
sys/contrib/vchiq/interface/vchiq_arm/vchiq_debugfs.h
Normal file
52
sys/contrib/vchiq/interface/vchiq_arm/vchiq_debugfs.h
Normal file
@ -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 */
|
@ -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 {
|
||||
|
@ -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
|
||||
|
@ -35,6 +35,7 @@
|
||||
|
||||
#include "vchiq_core.h"
|
||||
#include "vchiq_arm.h"
|
||||
#include "vchiq_killable.h"
|
||||
|
||||
/* ---- Public Variables ------------------------------------------------- */
|
||||
|
||||
|
72
sys/contrib/vchiq/interface/vchiq_arm/vchiq_killable.h
Normal file
72
sys/contrib/vchiq/interface/vchiq_arm/vchiq_killable.h
Normal file
@ -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
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user