123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192 |
- From 96d2e8f913ef4e62b93a2fd42412655643d24ad1 Mon Sep 17 00:00:00 2001
- From: Phil Elwell <phil@raspberrypi.org>
- Date: Mon, 20 Jun 2016 13:51:44 +0100
- Subject: [PATCH] vchiq_arm: Avoid use of mutex in add_completion
- Claiming the completion_mutex within add_completion did prevent some
- messages appearing twice, but provokes a deadlock caused by vcsm using
- vchiq within a page fault handler.
- Revert the use of completion_mutex, and instead fix the original
- problem using more memory barriers.
- Signed-off-by: Phil Elwell <phil@raspberrypi.org>
- ---
- .../vc04_services/interface/vchiq_arm/vchiq_arm.c | 55 +++++++++++-----------
- .../vc04_services/interface/vchiq_arm/vchiq_core.c | 14 ++++--
- 2 files changed, 37 insertions(+), 32 deletions(-)
- --- a/drivers/misc/vc04_services/interface/vchiq_arm/vchiq_arm.c
- +++ b/drivers/misc/vc04_services/interface/vchiq_arm/vchiq_arm.c
- @@ -64,10 +64,10 @@
- #define VCHIQ_MINOR 0
-
- /* Some per-instance constants */
- -#define MAX_COMPLETIONS 16
- +#define MAX_COMPLETIONS 128
- #define MAX_SERVICES 64
- #define MAX_ELEMENTS 8
- -#define MSG_QUEUE_SIZE 64
- +#define MSG_QUEUE_SIZE 128
-
- #define KEEPALIVE_VER 1
- #define KEEPALIVE_VER_MIN KEEPALIVE_VER
- @@ -208,28 +208,24 @@ add_completion(VCHIQ_INSTANCE_T instance
- void *bulk_userdata)
- {
- VCHIQ_COMPLETION_DATA_T *completion;
- + int insert;
- DEBUG_INITIALISE(g_state.local)
-
- - mutex_lock(&instance->completion_mutex);
- -
- - while (instance->completion_insert ==
- - (instance->completion_remove + MAX_COMPLETIONS)) {
- + insert = instance->completion_insert;
- + while ((insert - instance->completion_remove) >= MAX_COMPLETIONS) {
- /* Out of space - wait for the client */
- DEBUG_TRACE(SERVICE_CALLBACK_LINE);
- vchiq_log_trace(vchiq_arm_log_level,
- "add_completion - completion queue full");
- DEBUG_COUNT(COMPLETION_QUEUE_FULL_COUNT);
-
- - mutex_unlock(&instance->completion_mutex);
- if (down_interruptible(&instance->remove_event) != 0) {
- vchiq_log_info(vchiq_arm_log_level,
- "service_callback interrupted");
- return VCHIQ_RETRY;
- }
-
- - mutex_lock(&instance->completion_mutex);
- if (instance->closing) {
- - mutex_unlock(&instance->completion_mutex);
- vchiq_log_info(vchiq_arm_log_level,
- "service_callback closing");
- return VCHIQ_SUCCESS;
- @@ -237,9 +233,7 @@ add_completion(VCHIQ_INSTANCE_T instance
- DEBUG_TRACE(SERVICE_CALLBACK_LINE);
- }
-
- - completion =
- - &instance->completions[instance->completion_insert &
- - (MAX_COMPLETIONS - 1)];
- + completion = &instance->completions[insert & (MAX_COMPLETIONS - 1)];
-
- completion->header = header;
- completion->reason = reason;
- @@ -260,12 +254,9 @@ add_completion(VCHIQ_INSTANCE_T instance
- wmb();
-
- if (reason == VCHIQ_MESSAGE_AVAILABLE)
- - user_service->message_available_pos =
- - instance->completion_insert;
- -
- - instance->completion_insert++;
- + user_service->message_available_pos = insert;
-
- - mutex_unlock(&instance->completion_mutex);
- + instance->completion_insert = ++insert;
-
- up(&instance->insert_event);
-
- @@ -795,6 +786,7 @@ vchiq_ioctl(struct file *file, unsigned
- instance->completion_insert)
- && !instance->closing) {
- int rc;
- +
- DEBUG_TRACE(AWAIT_COMPLETION_LINE);
- mutex_unlock(&instance->completion_mutex);
- rc = down_interruptible(&instance->insert_event);
- @@ -809,24 +801,29 @@ vchiq_ioctl(struct file *file, unsigned
- }
- DEBUG_TRACE(AWAIT_COMPLETION_LINE);
-
- - /* A read memory barrier is needed to stop prefetch of a stale
- - ** completion record
- - */
- - rmb();
- -
- if (ret == 0) {
- int msgbufcount = args.msgbufcount;
- + int remove;
- +
- + remove = instance->completion_remove;
- +
- for (ret = 0; ret < args.count; ret++) {
- VCHIQ_COMPLETION_DATA_T *completion;
- VCHIQ_SERVICE_T *service;
- USER_SERVICE_T *user_service;
- VCHIQ_HEADER_T *header;
- - if (instance->completion_remove ==
- - instance->completion_insert)
- +
- + if (remove == instance->completion_insert)
- break;
- +
- completion = &instance->completions[
- - instance->completion_remove &
- - (MAX_COMPLETIONS - 1)];
- + remove & (MAX_COMPLETIONS - 1)];
- +
- +
- + /* A read memory barrier is needed to prevent
- + ** the prefetch of a stale completion record
- + */
- + rmb();
-
- service = completion->service_userdata;
- user_service = service->base.userdata;
- @@ -903,7 +900,11 @@ vchiq_ioctl(struct file *file, unsigned
- break;
- }
-
- - instance->completion_remove++;
- + /* Ensure that the above copy has completed
- + ** before advancing the remove pointer. */
- + mb();
- +
- + instance->completion_remove = ++remove;
- }
-
- if (msgbufcount != args.msgbufcount) {
- --- a/drivers/misc/vc04_services/interface/vchiq_arm/vchiq_core.c
- +++ b/drivers/misc/vc04_services/interface/vchiq_arm/vchiq_core.c
- @@ -610,15 +610,15 @@ process_free_queue(VCHIQ_STATE_T *state)
- BITSET_T service_found[BITSET_SIZE(VCHIQ_MAX_SERVICES)];
- int slot_queue_available;
-
- - /* Use a read memory barrier to ensure that any state that may have
- - ** been modified by another thread is not masked by stale prefetched
- - ** values. */
- - rmb();
- -
- /* Find slots which have been freed by the other side, and return them
- ** to the available queue. */
- slot_queue_available = state->slot_queue_available;
-
- + /* Use a memory barrier to ensure that any state that may have been
- + ** modified by another thread is not masked by stale prefetched
- + ** values. */
- + mb();
- +
- while (slot_queue_available != local->slot_queue_recycle) {
- unsigned int pos;
- int slot_index = local->slot_queue[slot_queue_available++ &
- @@ -626,6 +626,8 @@ process_free_queue(VCHIQ_STATE_T *state)
- char *data = (char *)SLOT_DATA_FROM_INDEX(state, slot_index);
- int data_found = 0;
-
- + rmb();
- +
- vchiq_log_trace(vchiq_core_log_level, "%d: pfq %d=%x %x %x",
- state->id, slot_index, (unsigned int)data,
- local->slot_queue_recycle, slot_queue_available);
- @@ -741,6 +743,8 @@ process_free_queue(VCHIQ_STATE_T *state)
- up(&state->data_quota_event);
- }
-
- + mb();
- +
- state->slot_queue_available = slot_queue_available;
- up(&state->slot_available_event);
- }
|