]> asedeno.scripts.mit.edu Git - linux.git/commitdiff
greybus: core: defer connection creation to driver probe
authorJohan Hovold <johan@hovoldconsulting.com>
Thu, 21 Jan 2016 16:34:09 +0000 (17:34 +0100)
committerGreg Kroah-Hartman <gregkh@google.com>
Fri, 22 Jan 2016 06:45:09 +0000 (22:45 -0800)
Defer connection creation to bundle driver probe instead of creating
them when initialising the interface and parsing the manifest.

Store copies of the CPorts descriptors in the bundle for the drivers to
use, and update the legacy driver.

This is needed for drivers that need more control over host-device
resource management, for example, when a protocol needs to use a
dedicated host CPort for traffic offloading (e.g. camera data).

This also avoids allocating host CPorts for bundles that are not bound
to a driver or for remote CPorts that a driver does not need.

Reviewed-by: Viresh Kumar <viresh.kumar@linaro.org>
Signed-off-by: Johan Hovold <johan@hovoldconsulting.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@google.com>
drivers/staging/greybus/bundle.c
drivers/staging/greybus/bundle.h
drivers/staging/greybus/connection.c
drivers/staging/greybus/core.c
drivers/staging/greybus/legacy.c
drivers/staging/greybus/manifest.c

index ec52bdecb5c1d3e146e31de6c1547cddc0598e7b..1714482bd34dfb575ec9e033fe43af5563a14abc 100644 (file)
@@ -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);
 }
 
index 837682d91e5b16cd0c57f1e1a3f5af8add821b11..48fb3fd768173d2d33439b9f672dd3f624859859 100644 (file)
@@ -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;
 
index 88c8a3fab2c641a36b6dac7e38bb288a0284afcd..c92af6e1a11f86c1209aa5629a28a15bb713697c 100644 (file)
@@ -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)
 {
index 1bb685bae7d267b29b8cebf9c10e9151b44c3e57..b9303c0cd5e4fc0f4fa031eed15ce02d56ce3cd4 100644 (file)
@@ -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;
 }
index 1e878beea8a514b7b8912afc2c99a5301e85efce..0f3dc8689fb4410f9ad2094a93cd705f0ff145b1 100644 (file)
@@ -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 @@ static int legacy_probe(struct gb_bundle *bundle,
 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);
 }
 
index 357f9c64821b44876c5cf1d96820415ec72191c6..64c60c2dfaf5864ecb74c7c5883e35a6fefe6fe6 100644 (file)
@@ -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.