aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--drivers/staging/greybus/bundle.c8
-rw-r--r--drivers/staging/greybus/bundle.h3
-rw-r--r--drivers/staging/greybus/connection.c2
-rw-r--r--drivers/staging/greybus/core.c15
-rw-r--r--drivers/staging/greybus/legacy.c56
-rw-r--r--drivers/staging/greybus/manifest.c35
6 files changed, 77 insertions, 42 deletions
diff --git a/drivers/staging/greybus/bundle.c b/drivers/staging/greybus/bundle.c
index ec52bdecb5c1..1714482bd34d 100644
--- a/drivers/staging/greybus/bundle.c
+++ b/drivers/staging/greybus/bundle.c
@@ -81,15 +81,9 @@ static struct gb_bundle *gb_bundle_find(struct gb_interface *intf,
static void gb_bundle_release(struct device *dev)
{
struct gb_bundle *bundle = to_gb_bundle(dev);
- struct gb_connection *connection;
- struct gb_connection *tmp;
-
- list_for_each_entry_safe(connection, tmp, &bundle->connections,
- bundle_links) {
- gb_connection_destroy(connection);
- }
kfree(bundle->state);
+ kfree(bundle->cport_desc);
kfree(bundle);
}
diff --git a/drivers/staging/greybus/bundle.h b/drivers/staging/greybus/bundle.h
index 837682d91e5b..48fb3fd76817 100644
--- a/drivers/staging/greybus/bundle.h
+++ b/drivers/staging/greybus/bundle.h
@@ -22,6 +22,9 @@ struct gb_bundle {
u8 class_major;
u8 class_minor;
+ size_t num_cports;
+ struct greybus_descriptor_cport *cport_desc;
+
struct list_head connections;
u8 *state;
diff --git a/drivers/staging/greybus/connection.c b/drivers/staging/greybus/connection.c
index 88c8a3fab2c6..c92af6e1a11f 100644
--- a/drivers/staging/greybus/connection.c
+++ b/drivers/staging/greybus/connection.c
@@ -232,6 +232,7 @@ gb_connection_create_dynamic(struct gb_interface *intf,
return gb_connection_create(intf->hd, -1, intf, bundle, cport_id,
protocol_id);
}
+EXPORT_SYMBOL_GPL(gb_connection_create_dynamic);
static int gb_connection_hd_cport_enable(struct gb_connection *connection)
{
@@ -546,6 +547,7 @@ void gb_connection_destroy(struct gb_connection *connection)
gb_connection_put(connection);
}
+EXPORT_SYMBOL_GPL(gb_connection_destroy);
void gb_connection_latency_tag_enable(struct gb_connection *connection)
{
diff --git a/drivers/staging/greybus/core.c b/drivers/staging/greybus/core.c
index 1bb685bae7d2..b9303c0cd5e4 100644
--- a/drivers/staging/greybus/core.c
+++ b/drivers/staging/greybus/core.c
@@ -151,8 +151,14 @@ static int greybus_probe(struct device *dev)
return -ENODEV;
retval = driver->probe(bundle, id);
- if (retval)
+ if (retval) {
+ /*
+ * Catch buggy drivers that fail to destroy their connections.
+ */
+ WARN_ON(!list_empty(&bundle->connections));
+
return retval;
+ }
return 0;
}
@@ -172,11 +178,8 @@ static int greybus_remove(struct device *dev)
driver->disconnect(bundle);
- /* Catch buggy drivers that fail to disable their connections. */
- list_for_each_entry(connection, &bundle->connections, bundle_links) {
- if (WARN_ON(connection->state != GB_CONNECTION_STATE_DISABLED))
- gb_connection_disable(connection);
- }
+ /* Catch buggy drivers that fail to destroy their connections. */
+ WARN_ON(!list_empty(&bundle->connections));
return 0;
}
diff --git a/drivers/staging/greybus/legacy.c b/drivers/staging/greybus/legacy.c
index 1e878beea8a5..0f3dc8689fb4 100644
--- a/drivers/staging/greybus/legacy.c
+++ b/drivers/staging/greybus/legacy.c
@@ -14,6 +14,7 @@
struct legacy_data {
size_t num_cports;
+ struct gb_connection **connections;
};
@@ -128,25 +129,44 @@ static void legacy_connection_exit(struct gb_connection *connection)
static int legacy_probe(struct gb_bundle *bundle,
const struct greybus_bundle_id *id)
{
+ struct greybus_descriptor_cport *cport_desc;
struct legacy_data *data;
struct gb_connection *connection;
- int ret;
+ int i;
+ int ret = -ENOMEM;
+
+ dev_dbg(&bundle->dev,
+ "%s - bundle class = 0x%02x, num_cports = %zu\n",
+ __func__, bundle->class, bundle->num_cports);
data = kzalloc(sizeof(*data), GFP_KERNEL);
if (!data)
return -ENOMEM;
- data->num_cports = 0;
- list_for_each_entry(connection, &bundle->connections, bundle_links)
- data->num_cports++;
+ data->num_cports = bundle->num_cports;
+ data->connections = kcalloc(data->num_cports,
+ sizeof(*data->connections),
+ GFP_KERNEL);
+ if (!data->connections)
+ goto err_free_data;
- dev_dbg(&bundle->dev,
- "%s - bundle class = 0x%02x, num_cports = %zu\n",
- __func__, bundle->class, data->num_cports);
+ for (i = 0; i < data->num_cports; ++i) {
+ cport_desc = &bundle->cport_desc[i];
+
+ connection = gb_connection_create_dynamic(bundle->intf,
+ bundle,
+ le16_to_cpu(cport_desc->id),
+ cport_desc->protocol_id);
+ if (!connection)
+ goto err_connections_destroy;
+
+ data->connections[i] = connection;
+ }
greybus_set_drvdata(bundle, data);
- list_for_each_entry(connection, &bundle->connections, bundle_links) {
+ for (i = 0; i < data->num_cports; ++i) {
+ connection = data->connections[i];
dev_dbg(&bundle->dev, "enabling connection %s\n",
connection->name);
@@ -158,10 +178,13 @@ static int legacy_probe(struct gb_bundle *bundle,
return 0;
err_connections_disable:
- list_for_each_entry_reverse(connection, &bundle->connections,
- bundle_links) {
- legacy_connection_exit(connection);
- }
+ for (--i; i >= 0; --i)
+ legacy_connection_exit(data->connections[i]);
+err_connections_destroy:
+ for (i = 0; i < data->num_cports; ++i)
+ gb_connection_destroy(data->connections[i]);
+ kfree(data->connections);
+err_free_data:
kfree(data);
return ret;
@@ -170,16 +193,17 @@ err_connections_disable:
static void legacy_disconnect(struct gb_bundle *bundle)
{
struct legacy_data *data = greybus_get_drvdata(bundle);
- struct gb_connection *connection;
+ int i;
dev_dbg(&bundle->dev, "%s - bundle class = 0x%02x\n", __func__,
bundle->class);
- list_for_each_entry_reverse(connection, &bundle->connections,
- bundle_links) {
- legacy_connection_exit(connection);
+ for (i = 0; i < data->num_cports; ++i) {
+ legacy_connection_exit(data->connections[i]);
+ gb_connection_destroy(data->connections[i]);
}
+ kfree(data->connections);
kfree(data);
}
diff --git a/drivers/staging/greybus/manifest.c b/drivers/staging/greybus/manifest.c
index 357f9c64821b..64c60c2dfaf5 100644
--- a/drivers/staging/greybus/manifest.c
+++ b/drivers/staging/greybus/manifest.c
@@ -228,19 +228,18 @@ static char *gb_string_get(struct gb_interface *intf, u8 string_id)
*/
static u32 gb_manifest_parse_cports(struct gb_bundle *bundle)
{
- struct gb_connection *connection;
struct gb_interface *intf = bundle->intf;
+ struct greybus_descriptor_cport *desc_cport;
struct manifest_desc *desc;
struct manifest_desc *next;
+ LIST_HEAD(list);
u8 bundle_id = bundle->id;
- u8 protocol_id;
u16 cport_id;
u32 count = 0;
+ int i;
/* Set up all cport descriptors associated with this bundle */
list_for_each_entry_safe(desc, next, &intf->manifest_descs, links) {
- struct greybus_descriptor_cport *desc_cport;
-
if (desc->type != GREYBUS_TYPE_CPORT)
continue;
@@ -252,16 +251,26 @@ static u32 gb_manifest_parse_cports(struct gb_bundle *bundle)
if (cport_id > CPORT_ID_MAX)
goto exit;
- /* Found one. Set up its function structure */
- protocol_id = desc_cport->protocol_id;
+ /* Found one, move it to our temporary list. */
+ list_move(&desc->links, &list);
+ count++;
+ }
- connection = gb_connection_create_dynamic(intf, bundle,
- cport_id,
- protocol_id);
- if (!connection)
- goto exit;
+ if (!count)
+ return 0;
- count++;
+ bundle->cport_desc = kcalloc(count, sizeof(*bundle->cport_desc),
+ GFP_KERNEL);
+ if (!bundle->cport_desc)
+ goto exit;
+
+ bundle->num_cports = count;
+
+ i = 0;
+ list_for_each_entry_safe(desc, next, &list, links) {
+ desc_cport = desc->data;
+ memcpy(&bundle->cport_desc[i++], desc_cport,
+ sizeof(*desc_cport));
/* Release the cport descriptor */
release_manifest_descriptor(desc);
@@ -269,7 +278,7 @@ static u32 gb_manifest_parse_cports(struct gb_bundle *bundle)
return count;
exit:
-
+ release_cport_descriptors(&list, bundle_id);
/*
* Free all cports for this bundle to avoid 'excess descriptors'
* warnings.