greybus: interface: Get manifest using Control protocol
authorViresh Kumar <viresh.kumar@linaro.org>
Mon, 22 Jun 2015 11:12:27 +0000 (16:42 +0530)
committerGreg Kroah-Hartman <gregkh@google.com>
Wed, 24 Jun 2015 06:16:15 +0000 (23:16 -0700)
Control protocol is ready to be used for fetching manifest. Lets do it.

This changes few things:
- Creates/initializes bundle/connection for control protocol initially
  and skips doing the same later.
- Manifest is parsed at link-up now, instead of hotplug which was the
  case earlier. This is because we need device_id (provided during
  link-up) for registering bundle.
- Manifest is fetched using control protocol.

So the sequence of events is:

Event                 Previously       Now
-----                 ----------       ---
Interface Hotplug     create intf      create intf
                      parse mfst

Interface Link Up     init bundles     create control conn
                                       get mfst size
                                       get mfst
                                       parse mfst
                                       init bundles

Reviewed-by: Alex Elder <elder@linaro.org>
Signed-off-by: Viresh Kumar <viresh.kumar@linaro.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@google.com>
drivers/staging/greybus/ap.c
drivers/staging/greybus/bundle.c
drivers/staging/greybus/interface.c
drivers/staging/greybus/interface.h
drivers/staging/greybus/manifest.c

index 07375cc..113fd87 100644 (file)
@@ -146,10 +146,10 @@ static void svc_management(struct svc_function_unipro_management *management,
                                management->link_up.interface_id);
                        return;
                }
-               ret = gb_bundles_init(intf, management->link_up.device_id);
+               ret = gb_interface_init(intf, management->link_up.device_id);
                if (ret) {
                        dev_err(hd->parent,
-                               "error %d initializing bundles for interface %hhu\n",
+                               "error %d initializing interface %hhu\n",
                                ret, management->link_up.interface_id);
                        return;
                }
@@ -175,8 +175,7 @@ static void svc_hotplug(struct svc_function_hotplug *hotplug,
                        return;
                }
                dev_dbg(hd->parent, "interface id %d added\n", interface_id);
-               gb_interface_add(hd, interface_id, hotplug->data,
-                                payload_length - 0x02);
+               gb_interface_create(hd, interface_id);
                break;
 
        case SVC_HOTUNPLUG_EVENT:
index 8d0e86f..a5172e5 100644 (file)
@@ -230,6 +230,10 @@ int gb_bundle_init(struct gb_bundle *bundle, u8 device_id)
        struct gb_interface *intf = bundle->intf;
        int ret;
 
+       /* Don't reinitialize control cport's bundle */
+       if (intf->control && bundle->id == GB_CONTROL_BUNDLE_ID)
+               return 0;
+
        bundle->device_id = device_id;
 
        ret = svc_set_route_send(bundle, intf->hd);
index 5b1621c..901c4ac 100644 (file)
@@ -66,6 +66,36 @@ struct device_type greybus_interface_type = {
        .release =      gb_interface_release,
 };
 
+/*
+ * Create kernel structures corresponding to a bundle and connection for
+ * managing control CPort. Also initialize the bundle, which will request SVC to
+ * set route and will initialize the control protocol for this connection.
+ */
+static int gb_create_control_connection(struct gb_interface *intf, u8 device_id)
+{
+       struct gb_bundle *bundle;
+       int ret;
+
+       bundle = gb_bundle_create(intf, GB_CONTROL_BUNDLE_ID,
+                                 GREYBUS_CLASS_CONTROL);
+       if (!bundle)
+               return -EINVAL;
+
+       if (!gb_connection_create(bundle, GB_CONTROL_CPORT_ID,
+                                 GREYBUS_PROTOCOL_CONTROL))
+               return -EINVAL;
+
+       ret = gb_bundle_init(bundle, device_id);
+       if (ret) {
+               dev_err(&intf->dev,
+                       "error %d initializing bundles for interface %hu\n",
+                       ret, intf->interface_id);
+               return ret;
+       }
+
+       return 0;
+}
+
 /*
  * A Greybus module represents a user-replicable component on an Ara
  * phone.  An interface is the physical connection on that module.  A
@@ -78,8 +108,8 @@ struct device_type greybus_interface_type = {
  * Returns a pointer to the new interfce or a null pointer if a
  * failure occurs due to memory exhaustion.
  */
-static struct gb_interface *gb_interface_create(struct greybus_host_device *hd,
-                                               u8 interface_id)
+struct gb_interface *gb_interface_create(struct greybus_host_device *hd,
+                                        u8 interface_id)
 {
        struct gb_module *module;
        struct gb_interface *intf;
@@ -165,29 +195,60 @@ static void gb_interface_destroy(struct gb_interface *intf)
 /**
  * gb_interface_add
  *
- * Pass in a buffer that _should_ contain a Greybus manifest
- * and register a greybus device structure with the kernel core.
+ * Create connection for control CPort and then request/parse manifest.
+ * Finally initialize all the bundles to set routes via SVC and initialize all
+ * connections.
  */
-void gb_interface_add(struct greybus_host_device *hd, u8 interface_id, u8 *data,
-                     int size)
+int gb_interface_init(struct gb_interface *intf, u8 device_id)
 {
-       struct gb_interface *intf;
+       int ret, size;
+       void *manifest;
+
+       /* Establish control CPort connection */
+       ret = gb_create_control_connection(intf, device_id);
+       if (ret) {
+               dev_err(&intf->dev, "Failed to create control CPort connection (%d)\n", ret);
+               return ret;
+       }
 
-       intf = gb_interface_create(hd, interface_id);
-       if (!intf) {
-               dev_err(hd->parent, "failed to create interface\n");
-               return;
+       /* Get manifest size using control protocol on CPort */
+       size = gb_control_get_manifest_size_operation(intf);
+       if (size <= 0) {
+               dev_err(&intf->dev, "%s: Failed to get manifest size (%d)\n",
+                       __func__, size);
+               if (size)
+                       return size;
+               else
+                       return -EINVAL;
+       }
+
+       manifest = kmalloc(size, GFP_KERNEL);
+       if (!manifest)
+               return -ENOMEM;
+
+       /* Get manifest using control protocol on CPort */
+       ret = gb_control_get_manifest_operation(intf, manifest, size);
+       if (ret) {
+               dev_err(&intf->dev, "%s: Failed to get manifest\n", __func__);
+               goto free_manifest;
        }
 
        /*
-        * Parse the manifest and build up our data structures
-        * representing what's in it.
+        * Parse the manifest and build up our data structures representing
+        * what's in it.
         */
-       if (!gb_manifest_parse(intf, data, size)) {
-               dev_err(hd->parent, "manifest error\n");
-               goto err_parse;
+       if (!gb_manifest_parse(intf, manifest, size)) {
+               dev_err(&intf->dev, "%s: Failed to parse manifest\n", __func__);
+               ret = -EINVAL;
+               goto free_manifest;
        }
 
+       ret = gb_bundles_init(intf, device_id);
+       if (ret)
+               dev_err(&intf->dev,
+                       "Error %d initializing bundles for interface %hu\n",
+                       ret, intf->interface_id);
+
        /*
         * XXX
         * We've successfully parsed the manifest.  Now we need to
@@ -197,10 +258,9 @@ void gb_interface_add(struct greybus_host_device *hd, u8 interface_id, u8 *data,
         * configuring the switch to allow them to communicate).
         */
 
-       return;
-
-err_parse:
-       gb_interface_destroy(intf);
+free_manifest:
+       kfree(manifest);
+       return ret;
 }
 
 void gb_interface_remove(struct greybus_host_device *hd, u8 interface_id)
index 9c566b2..90dbff1 100644 (file)
@@ -48,8 +48,9 @@ static inline void *gb_interface_get_drvdata(struct gb_interface *intf)
 struct gb_interface *gb_interface_find(struct greybus_host_device *hd,
                                       u8 interface_id);
 
-void gb_interface_add(struct greybus_host_device *hd, u8 interface_id, u8 *data,
-                     int size);
+struct gb_interface *gb_interface_create(struct greybus_host_device *hd,
+                                        u8 interface_id);
+int gb_interface_init(struct gb_interface *intf, u8 device_id);
 void gb_interface_remove(struct greybus_host_device *hd, u8 interface_id);
 void gb_interfaces_remove(struct greybus_host_device *hd);
 
index 377c449..bd5753f 100644 (file)
@@ -225,11 +225,17 @@ static u32 gb_manifest_parse_cports(struct gb_bundle *bundle)
                if (cport_id > CPORT_ID_MAX)
                        goto cleanup;
 
+               /* Don't recreate connection for control cport */
+               if (cport_id == GB_CONTROL_CPORT_ID)
+                       goto release_descriptor;
+
                /* Found one.  Set up its function structure */
                protocol_id = desc_cport->protocol_id;
+
                if (!gb_connection_create(bundle, cport_id, protocol_id))
                        goto cleanup;
 
+release_descriptor:
                count++;
 
                /* Release the cport descriptor */
@@ -268,11 +274,19 @@ static u32 gb_manifest_parse_bundles(struct gb_interface *intf)
 
                /* Found one.  Set up its bundle structure*/
                desc_bundle = desc->data;
+
+               /* Don't recreate bundle for control cport */
+               if (desc_bundle->id == GB_CONTROL_BUNDLE_ID) {
+                       bundle = intf->control->connection->bundle;
+                       goto parse_cports;
+               }
+
                bundle = gb_bundle_create(intf, desc_bundle->id,
                                          desc_bundle->class);
                if (!bundle)
                        goto cleanup;
 
+parse_cports:
                /* Now go set up this bundle's functions and cports */
                if (!gb_manifest_parse_cports(bundle))
                        goto cleanup;