Commit 36f241ff authored by Bryan O'Donoghue's avatar Bryan O'Donoghue Committed by Greg Kroah-Hartman

greybus: loopback: Wait for all async operations to complete on exit

On gb_loopback_connection_exit() we should ensure every issued asynchronous
operation completes before exiting connection_exit(). This patch introduces
a waitqueue with a counter which represents the number of incomplete
asynchronous operations. When the counter reaches zero connection_exit()
will complete. At the point which we wait for outstanding operations to
complete the connection-specific loopback thread will have ceased to issue
new operations. Tested with both synchronous and asynchronous operations.
Reviewed-by: default avatarJohan Hovold <johan@hovoldconsulting.com>
Suggested-by: default avatarJohan Hovold <johan@hovoldconsulting.com>
Signed-off-by: default avatarBryan O'Donoghue <bryan.odonoghue@linaro.org>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@google.com>
parent c7aae4e6
...@@ -21,6 +21,7 @@ ...@@ -21,6 +21,7 @@
#include <linux/list_sort.h> #include <linux/list_sort.h>
#include <linux/spinlock.h> #include <linux/spinlock.h>
#include <linux/workqueue.h> #include <linux/workqueue.h>
#include <linux/atomic.h>
#include <asm/div64.h> #include <asm/div64.h>
...@@ -73,6 +74,8 @@ struct gb_loopback { ...@@ -73,6 +74,8 @@ struct gb_loopback {
struct list_head entry; struct list_head entry;
struct device *dev; struct device *dev;
wait_queue_head_t wq; wait_queue_head_t wq;
wait_queue_head_t wq_completion;
atomic_t outstanding_operations;
/* Per connection stats */ /* Per connection stats */
struct gb_loopback_stats latency; struct gb_loopback_stats latency;
...@@ -433,6 +436,8 @@ static void __gb_loopback_async_operation_destroy(struct kref *kref) ...@@ -433,6 +436,8 @@ static void __gb_loopback_async_operation_destroy(struct kref *kref)
list_del(&op_async->entry); list_del(&op_async->entry);
if (op_async->operation) if (op_async->operation)
gb_operation_put(op_async->operation); gb_operation_put(op_async->operation);
atomic_dec(&op_async->gb->outstanding_operations);
wake_up(&op_async->gb->wq_completion);
kfree(op_async); kfree(op_async);
} }
...@@ -472,6 +477,12 @@ static struct gb_loopback_async_operation * ...@@ -472,6 +477,12 @@ static struct gb_loopback_async_operation *
return found ? op_async : NULL; return found ? op_async : NULL;
} }
static void gb_loopback_async_wait_all(struct gb_loopback *gb)
{
wait_event(gb->wq_completion,
!atomic_read(&gb->outstanding_operations));
}
static void gb_loopback_async_operation_callback(struct gb_operation *operation) static void gb_loopback_async_operation_callback(struct gb_operation *operation)
{ {
struct gb_loopback_async_operation *op_async; struct gb_loopback_async_operation *op_async;
...@@ -597,6 +608,7 @@ static int gb_loopback_async_operation(struct gb_loopback *gb, int type, ...@@ -597,6 +608,7 @@ static int gb_loopback_async_operation(struct gb_loopback *gb, int type,
do_gettimeofday(&op_async->ts); do_gettimeofday(&op_async->ts);
op_async->pending = true; op_async->pending = true;
atomic_inc(&gb->outstanding_operations);
ret = gb_operation_request_send(operation, ret = gb_operation_request_send(operation,
gb_loopback_async_operation_callback, gb_loopback_async_operation_callback,
GFP_KERNEL); GFP_KERNEL);
...@@ -1063,6 +1075,8 @@ static int gb_loopback_connection_init(struct gb_connection *connection) ...@@ -1063,6 +1075,8 @@ static int gb_loopback_connection_init(struct gb_connection *connection)
return -ENOMEM; return -ENOMEM;
init_waitqueue_head(&gb->wq); init_waitqueue_head(&gb->wq);
init_waitqueue_head(&gb->wq_completion);
atomic_set(&gb->outstanding_operations, 0);
gb_loopback_reset_stats(gb); gb_loopback_reset_stats(gb);
/* Reported values to user-space for min/max timeouts */ /* Reported values to user-space for min/max timeouts */
...@@ -1162,6 +1176,7 @@ static void gb_loopback_connection_exit(struct gb_connection *connection) ...@@ -1162,6 +1176,7 @@ static void gb_loopback_connection_exit(struct gb_connection *connection)
kfifo_free(&gb->kfifo_ts); kfifo_free(&gb->kfifo_ts);
gb_connection_latency_tag_disable(connection); gb_connection_latency_tag_disable(connection);
debugfs_remove(gb->file); debugfs_remove(gb->file);
gb_loopback_async_wait_all(gb);
spin_lock_irqsave(&gb_dev.lock, flags); spin_lock_irqsave(&gb_dev.lock, flags);
gb_dev.count--; gb_dev.count--;
......
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