summaryrefslogtreecommitdiffstats
path: root/drivers/staging/greybus/connection.c
diff options
context:
space:
mode:
authorAlex Elder2015-06-10 00:42:58 +0200
committerGreg Kroah-Hartman2015-06-10 19:38:23 +0200
commitf5c2be9e9bd934973d3e51b933bf7c03f85d2010 (patch)
tree35c0091405999b6a696aab54ef463bc003c2f997 /drivers/staging/greybus/connection.c
parentgreybus: bundle: check for duplicate bundle ids (diff)
downloadkernel-qcow2-linux-f5c2be9e9bd934973d3e51b933bf7c03f85d2010.tar.gz
kernel-qcow2-linux-f5c2be9e9bd934973d3e51b933bf7c03f85d2010.tar.xz
kernel-qcow2-linux-f5c2be9e9bd934973d3e51b933bf7c03f85d2010.zip
greybus: connection: check for duplicate cport ids
Check at connection creation time for an attempt to create a connection with an interface CPort ID that's the same as one that's already been created. Define a new helper function to look for such a duplicate. The check for a duplicate is only performed at initialization time, and CPorts are initialized serially for each bundle, so there's no need to acquire the list lock for this search. Signed-off-by: Alex Elder <elder@linaro.org> Signed-off-by: Greg Kroah-Hartman <gregkh@google.com>
Diffstat (limited to 'drivers/staging/greybus/connection.c')
-rw-r--r--drivers/staging/greybus/connection.c32
1 files changed, 26 insertions, 6 deletions
diff --git a/drivers/staging/greybus/connection.c b/drivers/staging/greybus/connection.c
index 8f528c1640e1..ab6c60ec874c 100644
--- a/drivers/staging/greybus/connection.c
+++ b/drivers/staging/greybus/connection.c
@@ -11,10 +11,22 @@
static DEFINE_SPINLOCK(gb_connections_lock);
+/* This is only used at initialization time; no locking is required. */
+static struct gb_connection *
+gb_connection_intf_find(struct greybus_host_device *hd, u16 cport_id)
+{
+ struct gb_connection *connection;
+
+ list_for_each_entry(connection, &hd->connections, hd_links)
+ if (connection->intf_cport_id == cport_id)
+ return connection;
+ return NULL;
+}
+
static struct gb_connection *
gb_connection_hd_find(struct greybus_host_device *hd, u16 cport_id)
{
- struct gb_connection *connection = NULL;
+ struct gb_connection *connection;
unsigned long flags;
spin_lock_irqsave(&gb_connections_lock, flags);
@@ -22,7 +34,7 @@ gb_connection_hd_find(struct greybus_host_device *hd, u16 cport_id)
if (connection->hd_cport_id == cport_id)
goto found;
connection = NULL;
- found:
+found:
spin_unlock_irqrestore(&gb_connections_lock, flags);
return connection;
@@ -159,21 +171,29 @@ struct gb_connection *gb_connection_create(struct gb_bundle *bundle,
u16 cport_id, u8 protocol_id)
{
struct gb_connection *connection;
- struct greybus_host_device *hd;
+ struct greybus_host_device *hd = bundle->intf->hd;
int retval;
u8 major = 0;
u8 minor = 1;
+ /*
+ * If a manifest tries to reuse a cport, reject it. We
+ * initialize connections serially so we don't need to worry
+ * about holding the connection lock.
+ */
+ if (gb_connection_intf_find(hd, cport_id)) {
+ pr_err("duplicate interface cport id 0x%04hx\n", cport_id);
+ return NULL;
+ }
+
connection = kzalloc(sizeof(*connection), GFP_KERNEL);
if (!connection)
return NULL;
+ connection->hd = hd;
connection->protocol_id = protocol_id;
connection->major = major;
connection->minor = minor;
-
- hd = bundle->intf->hd;
- connection->hd = hd;
if (!gb_connection_hd_cport_id_alloc(connection)) {
gb_protocol_put(connection->protocol);
kfree(connection);