Commit 2e238d71 authored by Bryan O'Donoghue's avatar Bryan O'Donoghue Committed by Greg Kroah-Hartman

greybus: loopback: Convert cross-thread mutex to spinlock while relaxing connect locks

This patch converts the cross-thread mutex used to synchronize threads with
respect to each other to a spinlock. This is done to enable taking of locks
in the following patches while in atomic context. A small re-order of
locking in connection setup/tear-down is done to minimize the amount of
time spent in spinlock_irqsave().
Signed-off-by: default avatarBryan O'Donoghue <bryan.odonoghue@linaro.org>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@google.com>
parent b933fa4a
...@@ -19,6 +19,7 @@ ...@@ -19,6 +19,7 @@
#include <linux/kfifo.h> #include <linux/kfifo.h>
#include <linux/debugfs.h> #include <linux/debugfs.h>
#include <linux/list_sort.h> #include <linux/list_sort.h>
#include <linux/spinlock.h>
#include <asm/div64.h> #include <asm/div64.h>
...@@ -39,7 +40,8 @@ struct gb_loopback_device { ...@@ -39,7 +40,8 @@ struct gb_loopback_device {
u32 count; u32 count;
size_t size_max; size_t size_max;
struct mutex mutex; /* We need to take a lock in atomic context */
spinlock_t lock;
struct list_head list; struct list_head list;
}; };
...@@ -731,6 +733,7 @@ static int gb_loopback_connection_init(struct gb_connection *connection) ...@@ -731,6 +733,7 @@ static int gb_loopback_connection_init(struct gb_connection *connection)
struct gb_loopback *gb; struct gb_loopback *gb;
int retval; int retval;
char name[DEBUGFS_NAMELEN]; char name[DEBUGFS_NAMELEN];
unsigned long flags;
gb = kzalloc(sizeof(*gb), GFP_KERNEL); gb = kzalloc(sizeof(*gb), GFP_KERNEL);
if (!gb) if (!gb)
...@@ -739,14 +742,13 @@ static int gb_loopback_connection_init(struct gb_connection *connection) ...@@ -739,14 +742,13 @@ static int gb_loopback_connection_init(struct gb_connection *connection)
init_waitqueue_head(&gb->wq); init_waitqueue_head(&gb->wq);
gb_loopback_reset_stats(gb); gb_loopback_reset_stats(gb);
mutex_lock(&gb_dev.mutex);
if (!gb_dev.count) { if (!gb_dev.count) {
/* Calculate maximum payload */ /* Calculate maximum payload */
gb_dev.size_max = gb_operation_get_payload_size_max(connection); gb_dev.size_max = gb_operation_get_payload_size_max(connection);
if (gb_dev.size_max <= if (gb_dev.size_max <=
sizeof(struct gb_loopback_transfer_request)) { sizeof(struct gb_loopback_transfer_request)) {
retval = -EINVAL; retval = -EINVAL;
goto out_sysfs; goto out_kzalloc;
} }
gb_dev.size_max -= sizeof(struct gb_loopback_transfer_request); gb_dev.size_max -= sizeof(struct gb_loopback_transfer_request);
} }
...@@ -783,10 +785,12 @@ static int gb_loopback_connection_init(struct gb_connection *connection) ...@@ -783,10 +785,12 @@ static int gb_loopback_connection_init(struct gb_connection *connection)
goto out_kfifo1; goto out_kfifo1;
} }
spin_lock_irqsave(&gb_dev.lock, flags);
gb_loopback_insert_id(gb); gb_loopback_insert_id(gb);
gb_connection_latency_tag_enable(connection);
gb_dev.count++; gb_dev.count++;
mutex_unlock(&gb_dev.mutex); spin_unlock_irqrestore(&gb_dev.lock, flags);
gb_connection_latency_tag_enable(connection);
return 0; return 0;
out_kfifo1: out_kfifo1:
...@@ -798,7 +802,7 @@ static int gb_loopback_connection_init(struct gb_connection *connection) ...@@ -798,7 +802,7 @@ static int gb_loopback_connection_init(struct gb_connection *connection)
out_sysfs: out_sysfs:
debugfs_remove(gb->file); debugfs_remove(gb->file);
connection->bundle->private = NULL; connection->bundle->private = NULL;
mutex_unlock(&gb_dev.mutex); out_kzalloc:
kfree(gb); kfree(gb);
return retval; return retval;
...@@ -807,22 +811,24 @@ static int gb_loopback_connection_init(struct gb_connection *connection) ...@@ -807,22 +811,24 @@ static int gb_loopback_connection_init(struct gb_connection *connection)
static void gb_loopback_connection_exit(struct gb_connection *connection) static void gb_loopback_connection_exit(struct gb_connection *connection)
{ {
struct gb_loopback *gb = connection->bundle->private; struct gb_loopback *gb = connection->bundle->private;
unsigned long flags;
if (!IS_ERR_OR_NULL(gb->task)) if (!IS_ERR_OR_NULL(gb->task))
kthread_stop(gb->task); kthread_stop(gb->task);
mutex_lock(&gb_dev.mutex);
connection->bundle->private = NULL; connection->bundle->private = NULL;
kfifo_free(&gb->kfifo_lat); kfifo_free(&gb->kfifo_lat);
kfifo_free(&gb->kfifo_ts); kfifo_free(&gb->kfifo_ts);
gb_connection_latency_tag_disable(connection); gb_connection_latency_tag_disable(connection);
gb_dev.count--;
sysfs_remove_groups(&connection->bundle->dev.kobj, sysfs_remove_groups(&connection->bundle->dev.kobj,
loopback_groups); loopback_groups);
debugfs_remove(gb->file); debugfs_remove(gb->file);
spin_lock_irqsave(&gb_dev.lock, flags);
gb_dev.count--;
list_del(&gb->entry); list_del(&gb->entry);
mutex_unlock(&gb_dev.mutex); spin_unlock_irqrestore(&gb_dev.lock, flags);
kfree(gb); kfree(gb);
} }
...@@ -841,7 +847,7 @@ static int loopback_init(void) ...@@ -841,7 +847,7 @@ static int loopback_init(void)
int retval; int retval;
INIT_LIST_HEAD(&gb_dev.list); INIT_LIST_HEAD(&gb_dev.list);
mutex_init(&gb_dev.mutex); spin_lock_init(&gb_dev.lock);
gb_dev.root = debugfs_create_dir("gb_loopback", NULL); gb_dev.root = debugfs_create_dir("gb_loopback", NULL);
retval = gb_protocol_register(&loopback_protocol); retval = gb_protocol_register(&loopback_protocol);
......
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