aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/staging/greybus/loopback.c
diff options
context:
space:
mode:
authorBryan O'Donoghue <bryan.odonoghue@linaro.org>2015-12-07 01:59:05 +0000
committerGreg Kroah-Hartman <gregkh@google.com>2015-12-07 14:32:20 -0500
commit2e238d71edadf03bed470cf58514ee10795a806b (patch)
tree190e42f6dc8e80a8d062902c0f74be3b99ac7f70 /drivers/staging/greybus/loopback.c
parentgreybus: Prefix hexadecimal values with 0x while printing them (diff)
downloadlinux-dev-2e238d71edadf03bed470cf58514ee10795a806b.tar.xz
linux-dev-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/staging/greybus/loopback.c')
-rw-r--r--drivers/staging/greybus/loopback.c28
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);