diff options
author | Bryan O'Donoghue | 2015-12-07 02:59:05 +0100 |
---|---|---|
committer | Greg Kroah-Hartman | 2015-12-07 20:32:20 +0100 |
commit | 2e238d71edadf03bed470cf58514ee10795a806b (patch) | |
tree | 190e42f6dc8e80a8d062902c0f74be3b99ac7f70 /drivers | |
parent | greybus: Prefix hexadecimal values with 0x while printing them (diff) | |
download | kernel-qcow2-linux-2e238d71edadf03bed470cf58514ee10795a806b.tar.gz kernel-qcow2-linux-2e238d71edadf03bed470cf58514ee10795a806b.tar.xz kernel-qcow2-linux-2e238d71edadf03bed470cf58514ee10795a806b.zip |
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: Bryan O'Donoghue <bryan.odonoghue@linaro.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@google.com>
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/staging/greybus/loopback.c | 28 |
1 files changed, 17 insertions, 11 deletions
diff --git a/drivers/staging/greybus/loopback.c b/drivers/staging/greybus/loopback.c index 689ebfdb456e..b65e3e591105 100644 --- a/drivers/staging/greybus/loopback.c +++ b/drivers/staging/greybus/loopback.c @@ -19,6 +19,7 @@ #include <linux/kfifo.h> #include <linux/debugfs.h> #include <linux/list_sort.h> +#include <linux/spinlock.h> #include <asm/div64.h> @@ -39,7 +40,8 @@ struct gb_loopback_device { u32 count; size_t size_max; - struct mutex mutex; + /* We need to take a lock in atomic context */ + spinlock_t lock; struct list_head list; }; @@ -731,6 +733,7 @@ static int gb_loopback_connection_init(struct gb_connection *connection) struct gb_loopback *gb; int retval; char name[DEBUGFS_NAMELEN]; + unsigned long flags; gb = kzalloc(sizeof(*gb), GFP_KERNEL); if (!gb) @@ -739,14 +742,13 @@ static int gb_loopback_connection_init(struct gb_connection *connection) init_waitqueue_head(&gb->wq); gb_loopback_reset_stats(gb); - mutex_lock(&gb_dev.mutex); if (!gb_dev.count) { /* Calculate maximum payload */ gb_dev.size_max = gb_operation_get_payload_size_max(connection); if (gb_dev.size_max <= sizeof(struct gb_loopback_transfer_request)) { retval = -EINVAL; - goto out_sysfs; + goto out_kzalloc; } gb_dev.size_max -= sizeof(struct gb_loopback_transfer_request); } @@ -783,10 +785,12 @@ static int gb_loopback_connection_init(struct gb_connection *connection) goto out_kfifo1; } + spin_lock_irqsave(&gb_dev.lock, flags); gb_loopback_insert_id(gb); - gb_connection_latency_tag_enable(connection); gb_dev.count++; - mutex_unlock(&gb_dev.mutex); + spin_unlock_irqrestore(&gb_dev.lock, flags); + + gb_connection_latency_tag_enable(connection); return 0; out_kfifo1: @@ -798,7 +802,7 @@ out_sysfs_conn: out_sysfs: debugfs_remove(gb->file); connection->bundle->private = NULL; - mutex_unlock(&gb_dev.mutex); +out_kzalloc: kfree(gb); return retval; @@ -807,22 +811,24 @@ out_sysfs: static void gb_loopback_connection_exit(struct gb_connection *connection) { struct gb_loopback *gb = connection->bundle->private; + unsigned long flags; if (!IS_ERR_OR_NULL(gb->task)) kthread_stop(gb->task); - mutex_lock(&gb_dev.mutex); - connection->bundle->private = NULL; kfifo_free(&gb->kfifo_lat); kfifo_free(&gb->kfifo_ts); gb_connection_latency_tag_disable(connection); - gb_dev.count--; sysfs_remove_groups(&connection->bundle->dev.kobj, loopback_groups); debugfs_remove(gb->file); + + spin_lock_irqsave(&gb_dev.lock, flags); + gb_dev.count--; list_del(&gb->entry); - mutex_unlock(&gb_dev.mutex); + spin_unlock_irqrestore(&gb_dev.lock, flags); + kfree(gb); } @@ -841,7 +847,7 @@ static int loopback_init(void) int retval; 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); retval = gb_protocol_register(&loopback_protocol); |