#include <linux/highmem.h>
#include <linux/pagemap.h>
#include <linux/bug.h>
-#include <linux/semaphore.h>
+#include <linux/completion.h>
#include <linux/list.h>
#include <linux/of.h>
#include <linux/platform_device.h>
int message_available_pos;
int msg_insert;
int msg_remove;
- struct semaphore insert_event;
- struct semaphore remove_event;
- struct semaphore close_event;
+ struct completion insert_event;
+ struct completion remove_event;
+ struct completion close_event;
VCHIQ_HEADER_T * msg_queue[MSG_QUEUE_SIZE];
} USER_SERVICE_T;
VCHIQ_COMPLETION_DATA_T completions[MAX_COMPLETIONS];
int completion_insert;
int completion_remove;
- struct semaphore insert_event;
- struct semaphore remove_event;
+ struct completion insert_event;
+ struct completion remove_event;
struct mutex completion_mutex;
int connected;
vchiq_log_trace(vchiq_arm_log_level,
"%s - completion queue full", __func__);
DEBUG_COUNT(COMPLETION_QUEUE_FULL_COUNT);
- if (down_interruptible(&instance->remove_event) != 0) {
+ if (wait_for_completion_interruptible(
+ &instance->remove_event)) {
vchiq_log_info(vchiq_arm_log_level,
"service_callback interrupted");
return VCHIQ_RETRY;
insert++;
instance->completion_insert = insert;
- up(&instance->insert_event);
+ complete(&instance->insert_event);
return VCHIQ_SUCCESS;
}
}
DEBUG_TRACE(SERVICE_CALLBACK_LINE);
- if (down_interruptible(&user_service->remove_event)
+ if (wait_for_completion_interruptible(
+ &user_service->remove_event)
!= 0) {
vchiq_log_info(vchiq_arm_log_level,
"%s interrupted", __func__);
}
spin_unlock(&msg_queue_spinlock);
- up(&user_service->insert_event);
+ complete(&user_service->insert_event);
header = NULL;
}
unlock_service(user_service->service);
/* Wake the user-thread blocked in close_ or remove_service */
- up(&user_service->close_event);
+ complete(&user_service->close_event);
user_service->close_pending = 0;
}
if (status == VCHIQ_SUCCESS) {
/* Wake the completion thread and ask it to exit */
instance->closing = 1;
- up(&instance->insert_event);
+ complete(&instance->insert_event);
}
break;
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);
+ init_completion(&user_service->insert_event);
+ init_completion(&user_service->remove_event);
+ init_completion(&user_service->close_event);
if (args.is_open) {
status = vchiq_open_service_internal
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))
+ wait_for_completion_interruptible(
+ &user_service->close_event))
status = VCHIQ_RETRY;
break;
}
DEBUG_TRACE(AWAIT_COMPLETION_LINE);
mutex_unlock(&instance->completion_mutex);
- rc = down_interruptible(&instance->insert_event);
+ rc = wait_for_completion_interruptible(
+ &instance->insert_event);
mutex_lock(&instance->completion_mutex);
if (rc != 0) {
DEBUG_TRACE(AWAIT_COMPLETION_LINE);
}
if (ret != 0)
- up(&instance->remove_event);
+ complete(&instance->remove_event);
mutex_unlock(&instance->completion_mutex);
DEBUG_TRACE(AWAIT_COMPLETION_LINE);
} break;
do {
spin_unlock(&msg_queue_spinlock);
DEBUG_TRACE(DEQUEUE_MESSAGE_LINE);
- if (down_interruptible(
- &user_service->insert_event) != 0) {
+ if (wait_for_completion_interruptible(
+ &user_service->insert_event)) {
vchiq_log_info(vchiq_arm_log_level,
"DEQUEUE_MESSAGE interrupted");
ret = -EINTR;
user_service->msg_remove++;
spin_unlock(&msg_queue_spinlock);
- up(&user_service->remove_event);
+ complete(&user_service->remove_event);
if (header == NULL)
ret = -ENOTCONN;
else if (header->size <= args.bufsize) {
vchiq_debugfs_add_instance(instance);
- sema_init(&instance->insert_event, 0);
- sema_init(&instance->remove_event, 0);
+ init_completion(&instance->insert_event);
+ init_completion(&instance->remove_event);
mutex_init(&instance->completion_mutex);
mutex_init(&instance->bulk_waiter_list_mutex);
INIT_LIST_HEAD(&instance->bulk_waiter_list);
/* Wake the completion thread and ask it to exit */
instance->closing = 1;
- up(&instance->insert_event);
+ complete(&instance->insert_event);
mutex_unlock(&instance->completion_mutex);
/* Wake the slot handler if the completion queue is full. */
- up(&instance->remove_event);
+ complete(&instance->remove_event);
/* Mark all services for termination... */
i = 0;
USER_SERVICE_T *user_service = service->base.userdata;
/* Wake the slot handler if the msg queue is full. */
- up(&user_service->remove_event);
+ complete(&user_service->remove_event);
vchiq_terminate_service_internal(service);
unlock_service(service);
!= NULL) {
USER_SERVICE_T *user_service = service->base.userdata;
- down(&service->remove_event);
+ wait_for_completion(&service->remove_event);
BUG_ON(service->srvstate != VCHIQ_SRVSTATE_FREE);
/* Wake any blocked user-thread */
if (instance->use_close_delivered)
- up(&user_service->close_event);
+ complete(&user_service->close_event);
unlock_service(service);
}
instance->completion_remove++;
/* Unblock any sending thread. */
service_quota = &state->service_quotas[service->localport];
- up(&service_quota->quota_event);
+ complete(&service_quota->quota_event);
}
static void
event->armed = 1;
dsb(sy);
if (!event->fired) {
- if (down_interruptible(
- (struct semaphore *)
- ((char *)state + event->event)) != 0) {
+ if (wait_for_completion_interruptible(
+ (struct completion *)
+ ((char *)state + event->event))) {
event->armed = 0;
return 0;
}
remote_event_signal_local(VCHIQ_STATE_T *state, REMOTE_EVENT_T *event)
{
event->armed = 0;
- up((struct semaphore *)((char *)state + event->event));
+ complete((struct completion *)((char *)state + event->event));
}
static inline void
/* If there is no free slot... */
- if (down_trylock(&state->slot_available_event) != 0) {
+ if (!try_wait_for_completion(&state->slot_available_event)) {
/* ...wait for one. */
VCHIQ_STATS_INC(state, slot_stalls);
remote_event_signal(&state->remote->trigger);
if (!is_blocking ||
- (down_interruptible(
- &state->slot_available_event) != 0))
+ (wait_for_completion_interruptible(
+ &state->slot_available_event)))
return NULL; /* No space available */
}
if (tx_pos == (state->slot_queue_available * VCHIQ_SLOT_SIZE)) {
- up(&state->slot_available_event);
+ complete(&state->slot_available_event);
pr_warn("%s: invalid tx_pos: %d\n", __func__, tx_pos);
return NULL;
}
/* Signal the service that it
** has dropped below its quota
*/
- up(&service_quota->quota_event);
+ complete(&service_quota->quota_event);
else if (count == 0) {
vchiq_log_error(vchiq_core_log_level,
"service %d message_use_count=%d (header %pK, msgid %x, header->msgid %x, header->size %x)",
/* Signal the service in case
** it has dropped below its
** quota */
- up(&service_quota->quota_event);
+ complete(&service_quota->quota_event);
vchiq_log_trace(
vchiq_core_log_level,
"%d: pfq:%d %x@%pK - slot_use->%d",
count - 1;
spin_unlock("a_spinlock);
if (count == state->data_quota)
- up(&state->data_quota_event);
+ complete(&state->data_quota_event);
}
/*
mb();
state->slot_queue_available = slot_queue_available;
- up(&state->slot_available_event);
+ complete(&state->slot_available_event);
}
}
spin_unlock("a_spinlock);
mutex_unlock(&state->slot_mutex);
- if (down_interruptible(&state->data_quota_event)
- != 0)
+ if (wait_for_completion_interruptible(
+ &state->data_quota_event))
return VCHIQ_RETRY;
mutex_lock(&state->slot_mutex);
if ((tx_end_index == state->previous_data_index) ||
(state->data_use_count < state->data_quota)) {
/* Pass the signal on to other waiters */
- up(&state->data_quota_event);
+ complete(&state->data_quota_event);
break;
}
}
service_quota->slot_use_count);
VCHIQ_SERVICE_STATS_INC(service, quota_stalls);
mutex_unlock(&state->slot_mutex);
- if (down_interruptible(&service_quota->quota_event)
- != 0)
+ if (wait_for_completion_interruptible(
+ &service_quota->quota_event))
return VCHIQ_RETRY;
if (service->closing)
return VCHIQ_ERROR;
waiter = bulk->userdata;
if (waiter) {
waiter->actual = bulk->actual;
- up(&waiter->event);
+ complete(&waiter->event);
}
spin_unlock(&bulk_waiter_spinlock);
} else if (bulk->mode ==
}
queue->remove++;
- up(&service->bulk_remove_event);
+ complete(&service->bulk_remove_event);
}
if (!retry_poll)
status = VCHIQ_SUCCESS;
service->remoteport = remoteport;
vchiq_set_service_state(service,
VCHIQ_SRVSTATE_OPEN);
- up(&service->remove_event);
+ complete(&service->remove_event);
} else
vchiq_log_error(vchiq_core_log_level,
"OPENACK received in state %s",
"%d: prs CONNECT@%pK", state->id, header);
state->version_common = ((VCHIQ_SLOT_ZERO_T *)
state->slot_data)->version;
- up(&state->connect);
+ complete(&state->connect);
break;
case VCHIQ_MSG_BULK_RX:
case VCHIQ_MSG_BULK_TX:
vchiq_set_service_state(service,
VCHIQ_SRVSTATE_OPENSYNC);
service->sync = 1;
- up(&service->remove_event);
+ complete(&service->remove_event);
}
release_message_sync(state, header);
break;
initialize events and mutexes
*/
- sema_init(&state->connect, 0);
+ init_completion(&state->connect);
mutex_init(&state->mutex);
- sema_init(&state->trigger_event, 0);
- sema_init(&state->recycle_event, 0);
- sema_init(&state->sync_trigger_event, 0);
- sema_init(&state->sync_release_event, 0);
+ init_completion(&state->trigger_event);
+ init_completion(&state->recycle_event);
+ init_completion(&state->sync_trigger_event);
+ init_completion(&state->sync_release_event);
mutex_init(&state->slot_mutex);
mutex_init(&state->recycle_mutex);
mutex_init(&state->sync_mutex);
mutex_init(&state->bulk_transfer_mutex);
- sema_init(&state->slot_available_event, 0);
- sema_init(&state->slot_remove_event, 0);
- sema_init(&state->data_quota_event, 0);
+ init_completion(&state->slot_available_event);
+ init_completion(&state->slot_remove_event);
+ init_completion(&state->data_quota_event);
state->slot_queue_available = 0;
for (i = 0; i < VCHIQ_MAX_SERVICES; i++) {
VCHIQ_SERVICE_QUOTA_T *service_quota =
&state->service_quotas[i];
- sema_init(&service_quota->quota_event, 0);
+ init_completion(&service_quota->quota_event);
}
for (i = local->slot_first; i <= local->slot_last; i++) {
local->slot_queue[state->slot_queue_available++] = i;
- up(&state->slot_available_event);
+ complete(&state->slot_available_event);
}
state->default_slot_quota = state->slot_queue_available/2;
service->service_use_count = 0;
init_bulk_queue(&service->bulk_tx);
init_bulk_queue(&service->bulk_rx);
- sema_init(&service->remove_event, 0);
- sema_init(&service->bulk_remove_event, 0);
+ init_completion(&service->remove_event);
+ init_completion(&service->bulk_remove_event);
mutex_init(&service->bulk_mutex);
memset(&service->stats, 0, sizeof(service->stats));
QMFLAGS_IS_BLOCKING);
if (status == VCHIQ_SUCCESS) {
/* Wait for the ACK/NAK */
- if (down_interruptible(&service->remove_event) != 0) {
+ if (wait_for_completion_interruptible(&service->remove_event)) {
status = VCHIQ_RETRY;
vchiq_release_service_internal(service);
} else if ((service->srvstate != VCHIQ_SRVSTATE_OPEN) &&
if (is_server)
service->closing = 0;
- up(&service->remove_event);
+ complete(&service->remove_event);
}
} else
vchiq_set_service_state(service, failstate);
vchiq_set_service_state(service,
VCHIQ_SRVSTATE_LISTENING);
}
- up(&service->remove_event);
+ complete(&service->remove_event);
} else
vchiq_free_service_internal(service);
break;
/* The open was rejected - tell the user */
vchiq_set_service_state(service,
VCHIQ_SRVSTATE_CLOSEWAIT);
- up(&service->remove_event);
+ complete(&service->remove_event);
} else {
/* Shutdown mid-open - let the other side know */
status = queue_message(state, service,
vchiq_set_service_state(service, VCHIQ_SRVSTATE_FREE);
- up(&service->remove_event);
+ complete(&service->remove_event);
/* Release the initial lock */
unlock_service(service);
}
if (state->conn_state == VCHIQ_CONNSTATE_CONNECTING) {
- if (down_interruptible(&state->connect) != 0)
+ if (wait_for_completion_interruptible(&state->connect))
return VCHIQ_RETRY;
vchiq_set_conn_state(state, VCHIQ_CONNSTATE_CONNECTED);
- up(&state->connect);
+ complete(&state->connect);
}
return VCHIQ_SUCCESS;
}
while (1) {
- if (down_interruptible(&service->remove_event) != 0) {
+ if (wait_for_completion_interruptible(&service->remove_event)) {
status = VCHIQ_RETRY;
break;
}
request_poll(service->state, service, VCHIQ_POLL_REMOVE);
}
while (1) {
- if (down_interruptible(&service->remove_event) != 0) {
+ if (wait_for_completion_interruptible(&service->remove_event)) {
status = VCHIQ_RETRY;
break;
}
break;
case VCHIQ_BULK_MODE_BLOCKING:
bulk_waiter = (struct bulk_waiter *)userdata;
- sema_init(&bulk_waiter->event, 0);
+ init_completion(&bulk_waiter->event);
bulk_waiter->actual = 0;
bulk_waiter->bulk = NULL;
break;
VCHIQ_SERVICE_STATS_INC(service, bulk_stalls);
do {
mutex_unlock(&service->bulk_mutex);
- if (down_interruptible(&service->bulk_remove_event)
- != 0) {
+ if (wait_for_completion_interruptible(
+ &service->bulk_remove_event)) {
status = VCHIQ_RETRY;
goto error_exit;
}
if (bulk_waiter) {
bulk_waiter->bulk = bulk;
- if (down_interruptible(&bulk_waiter->event) != 0)
+ if (wait_for_completion_interruptible(&bulk_waiter->event))
status = VCHIQ_RETRY;
else if (bulk_waiter->actual == VCHIQ_BULK_ACTUAL_ABORTED)
status = VCHIQ_ERROR;
service_quota->message_use_count)) {
/* Signal the service that it may have
** dropped below its quota */
- up(&service_quota->quota_event);
+ complete(&service_quota->quota_event);
}
status = VCHIQ_SUCCESS;
}
service_quota->slot_use_count))
/* Signal the service that it may have
** dropped below its quota */
- up(&service_quota->quota_event);
+ complete(&service_quota->quota_event);
status = VCHIQ_SUCCESS;
}
} break;
#define VCHIQ_CORE_H
#include <linux/mutex.h>
-#include <linux/semaphore.h>
+#include <linux/completion.h>
#include <linux/kthread.h>
#include "vchiq_cfg.h"
VCHIQ_BULK_QUEUE_T bulk_tx;
VCHIQ_BULK_QUEUE_T bulk_rx;
- struct semaphore remove_event;
- struct semaphore bulk_remove_event;
+ struct completion remove_event;
+ struct completion bulk_remove_event;
struct mutex bulk_mutex;
struct service_stats_struct {
unsigned short slot_use_count;
unsigned short message_quota;
unsigned short message_use_count;
- struct semaphore quota_event;
+ struct completion quota_event;
int previous_tx_index;
} VCHIQ_SERVICE_QUOTA_T;
unsigned short default_message_quota;
/* Event indicating connect message received */
- struct semaphore connect;
+ struct completion connect;
/* Mutex protecting services */
struct mutex mutex;
struct task_struct *sync_thread;
/* Local implementation of the trigger remote event */
- struct semaphore trigger_event;
+ struct completion trigger_event;
/* Local implementation of the recycle remote event */
- struct semaphore recycle_event;
+ struct completion recycle_event;
/* Local implementation of the sync trigger remote event */
- struct semaphore sync_trigger_event;
+ struct completion sync_trigger_event;
/* Local implementation of the sync release remote event */
- struct semaphore sync_release_event;
+ struct completion sync_release_event;
char *tx_data;
char *rx_data;
int unused_service;
/* Signalled when a free slot becomes available. */
- struct semaphore slot_available_event;
+ struct completion slot_available_event;
- struct semaphore slot_remove_event;
+ struct completion slot_remove_event;
/* Signalled when a free data slot becomes available. */
- struct semaphore data_quota_event;
+ struct completion data_quota_event;
struct state_stats_struct {
int slot_stalls;
struct bulk_waiter {
VCHIQ_BULK_T *bulk;
- struct semaphore event;
+ struct completion event;
int actual;
};