Commit ca3df03b authored by Phil Elwell's avatar Phil Elwell Committed by Greg Kroah-Hartman

staging: vc04_services: Fix messages appearing twice

An issue was observed when flushing openmax components
which generate a large number of messages returning
buffers to host.

We occasionally found a duplicate message from 16
messages prior, resulting in a buffer returned twice.

So fix the issue by adding more memory barriers.
Signed-off-by: default avatarPhil Elwell <phil@raspberrypi.org>
Signed-off-by: default avatarStefan Wahren <stefan.wahren@i2se.com>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent 5069c86a
...@@ -208,10 +208,11 @@ add_completion(VCHIQ_INSTANCE_T instance, VCHIQ_REASON_T reason, ...@@ -208,10 +208,11 @@ add_completion(VCHIQ_INSTANCE_T instance, VCHIQ_REASON_T reason,
void *bulk_userdata) void *bulk_userdata)
{ {
VCHIQ_COMPLETION_DATA_T *completion; VCHIQ_COMPLETION_DATA_T *completion;
int insert;
DEBUG_INITIALISE(g_state.local) DEBUG_INITIALISE(g_state.local)
while (instance->completion_insert == insert = instance->completion_insert;
(instance->completion_remove + MAX_COMPLETIONS)) { while ((insert - instance->completion_remove) >= MAX_COMPLETIONS) {
/* Out of space - wait for the client */ /* Out of space - wait for the client */
DEBUG_TRACE(SERVICE_CALLBACK_LINE); DEBUG_TRACE(SERVICE_CALLBACK_LINE);
vchiq_log_trace(vchiq_arm_log_level, vchiq_log_trace(vchiq_arm_log_level,
...@@ -229,9 +230,7 @@ add_completion(VCHIQ_INSTANCE_T instance, VCHIQ_REASON_T reason, ...@@ -229,9 +230,7 @@ add_completion(VCHIQ_INSTANCE_T instance, VCHIQ_REASON_T reason,
DEBUG_TRACE(SERVICE_CALLBACK_LINE); DEBUG_TRACE(SERVICE_CALLBACK_LINE);
} }
completion = completion = &instance->completions[insert & (MAX_COMPLETIONS - 1)];
&instance->completions[instance->completion_insert &
(MAX_COMPLETIONS - 1)];
completion->header = header; completion->header = header;
completion->reason = reason; completion->reason = reason;
...@@ -252,9 +251,10 @@ add_completion(VCHIQ_INSTANCE_T instance, VCHIQ_REASON_T reason, ...@@ -252,9 +251,10 @@ add_completion(VCHIQ_INSTANCE_T instance, VCHIQ_REASON_T reason,
wmb(); wmb();
if (reason == VCHIQ_MESSAGE_AVAILABLE) if (reason == VCHIQ_MESSAGE_AVAILABLE)
user_service->message_available_pos = user_service->message_available_pos = insert;
instance->completion_insert;
instance->completion_insert++; insert++;
instance->completion_insert = insert;
up(&instance->insert_event); up(&instance->insert_event);
...@@ -895,24 +895,27 @@ vchiq_ioctl(struct file *file, unsigned int cmd, unsigned long arg) ...@@ -895,24 +895,27 @@ vchiq_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
} }
DEBUG_TRACE(AWAIT_COMPLETION_LINE); DEBUG_TRACE(AWAIT_COMPLETION_LINE);
/* A read memory barrier is needed to stop prefetch of a stale
** completion record
*/
rmb();
if (ret == 0) { if (ret == 0) {
int msgbufcount = args.msgbufcount; int msgbufcount = args.msgbufcount;
int remove = instance->completion_remove;
for (ret = 0; ret < args.count; ret++) { for (ret = 0; ret < args.count; ret++) {
VCHIQ_COMPLETION_DATA_T *completion; VCHIQ_COMPLETION_DATA_T *completion;
VCHIQ_SERVICE_T *service; VCHIQ_SERVICE_T *service;
USER_SERVICE_T *user_service; USER_SERVICE_T *user_service;
VCHIQ_HEADER_T *header; VCHIQ_HEADER_T *header;
if (instance->completion_remove ==
instance->completion_insert) if (remove == instance->completion_insert)
break; break;
completion = &instance->completions[ completion = &instance->completions[
instance->completion_remove & remove & (MAX_COMPLETIONS - 1)];
(MAX_COMPLETIONS - 1)];
/*
* A read memory barrier is needed to stop
* prefetch of a stale completion record
*/
rmb();
service = completion->service_userdata; service = completion->service_userdata;
user_service = service->base.userdata; user_service = service->base.userdata;
...@@ -987,7 +990,13 @@ vchiq_ioctl(struct file *file, unsigned int cmd, unsigned long arg) ...@@ -987,7 +990,13 @@ vchiq_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
break; break;
} }
instance->completion_remove++; /*
* Ensure that the above copy has completed
* before advancing the remove pointer.
*/
mb();
remove++;
instance->completion_remove = remove;
} }
if (msgbufcount != args.msgbufcount) { if (msgbufcount != args.msgbufcount) {
......
...@@ -607,15 +607,17 @@ process_free_queue(VCHIQ_STATE_T *state) ...@@ -607,15 +607,17 @@ process_free_queue(VCHIQ_STATE_T *state)
BITSET_T service_found[BITSET_SIZE(VCHIQ_MAX_SERVICES)]; BITSET_T service_found[BITSET_SIZE(VCHIQ_MAX_SERVICES)];
int slot_queue_available; 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 /* Find slots which have been freed by the other side, and return them
** to the available queue. */ ** to the available queue. */
slot_queue_available = state->slot_queue_available; 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) { while (slot_queue_available != local->slot_queue_recycle) {
unsigned int pos; unsigned int pos;
int slot_index = local->slot_queue[slot_queue_available++ & int slot_index = local->slot_queue[slot_queue_available++ &
...@@ -623,6 +625,12 @@ process_free_queue(VCHIQ_STATE_T *state) ...@@ -623,6 +625,12 @@ process_free_queue(VCHIQ_STATE_T *state)
char *data = (char *)SLOT_DATA_FROM_INDEX(state, slot_index); char *data = (char *)SLOT_DATA_FROM_INDEX(state, slot_index);
int data_found = 0; int data_found = 0;
/*
* Beware of the address dependency - data is calculated
* using an index written by the other side.
*/
rmb();
vchiq_log_trace(vchiq_core_log_level, "%d: pfq %d=%pK %x %x", vchiq_log_trace(vchiq_core_log_level, "%d: pfq %d=%pK %x %x",
state->id, slot_index, data, state->id, slot_index, data,
local->slot_queue_recycle, slot_queue_available); local->slot_queue_recycle, slot_queue_available);
...@@ -721,6 +729,12 @@ process_free_queue(VCHIQ_STATE_T *state) ...@@ -721,6 +729,12 @@ process_free_queue(VCHIQ_STATE_T *state)
up(&state->data_quota_event); up(&state->data_quota_event);
} }
/*
* Don't allow the slot to be reused until we are no
* longer interested in it.
*/
mb();
state->slot_queue_available = slot_queue_available; state->slot_queue_available = slot_queue_available;
up(&state->slot_available_event); up(&state->slot_available_event);
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment