summaryrefslogtreecommitdiff
path: root/target/linux/brcm2708/patches-4.9/950-0099-vchiq_arm-Avoid-use-of-mutex-in-add_completion.patch
diff options
context:
space:
mode:
Diffstat (limited to 'target/linux/brcm2708/patches-4.9/950-0099-vchiq_arm-Avoid-use-of-mutex-in-add_completion.patch')
-rw-r--r--target/linux/brcm2708/patches-4.9/950-0099-vchiq_arm-Avoid-use-of-mutex-in-add_completion.patch192
1 files changed, 192 insertions, 0 deletions
diff --git a/target/linux/brcm2708/patches-4.9/950-0099-vchiq_arm-Avoid-use-of-mutex-in-add_completion.patch b/target/linux/brcm2708/patches-4.9/950-0099-vchiq_arm-Avoid-use-of-mutex-in-add_completion.patch
new file mode 100644
index 0000000..c8cc5b7
--- /dev/null
+++ b/target/linux/brcm2708/patches-4.9/950-0099-vchiq_arm-Avoid-use-of-mutex-in-add_completion.patch
@@ -0,0 +1,192 @@
+From 965475a1620ba1c4f19d6585925a40e3c749d7d1 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/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c
++++ b/drivers/staging/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/staging/vc04_services/interface/vchiq_arm/vchiq_core.c
++++ b/drivers/staging/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);
+ }