]> git.karo-electronics.de Git - karo-tx-linux.git/blobdiff - drivers/staging/greybus/manifest.c
greybus: interface: drop the control bundle
[karo-tx-linux.git] / drivers / staging / greybus / manifest.c
index 9014611c6a7a947941a52226fdda6324bea8f795..ea5ff8682e6951cdd8e15ce88d1f46299a97b460 100644 (file)
@@ -1,22 +1,40 @@
 /*
- * Greybus module manifest parsing
+ * Greybus manifest parsing
  *
- * Copyright 2014 Google Inc.
+ * Copyright 2014-2015 Google Inc.
+ * Copyright 2014-2015 Linaro Ltd.
  *
  * Released under the GPLv2 only.
  */
 
 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
 
-#include <linux/err.h>
-
 #include "greybus.h"
 
+static const char *get_descriptor_type_string(u8 type)
+{
+       switch(type) {
+       case GREYBUS_TYPE_INVALID:
+               return "invalid";
+       case GREYBUS_TYPE_STRING:
+               return "string";
+       case GREYBUS_TYPE_INTERFACE:
+               return "interface";
+       case GREYBUS_TYPE_CPORT:
+               return "cport";
+       case GREYBUS_TYPE_BUNDLE:
+               return "bundle";
+       default:
+               WARN_ON(1);
+               return "unknown";
+       }
+}
+
 /*
  * We scan the manifest once to identify where all the descriptors
  * are.  The result is a list of these manifest_desc structures.  We
  * then pick through them for what we're looking for (starting with
- * the module descriptor).  As each is processed we remove it from
+ * the interface descriptor).  As each is processed we remove it from
  * the list.  When we're done the list should (probably) be empty.
  */
 struct manifest_desc {
@@ -27,80 +45,98 @@ struct manifest_desc {
        enum greybus_descriptor_type    type;
 };
 
-static LIST_HEAD(manifest_descs);
-
 static void release_manifest_descriptor(struct manifest_desc *descriptor)
 {
        list_del(&descriptor->links);
        kfree(descriptor);
 }
 
-static void release_manifest_descriptors(void)
+static void release_manifest_descriptors(struct gb_interface *intf)
 {
        struct manifest_desc *descriptor;
        struct manifest_desc *next;
 
-       list_for_each_entry_safe(descriptor, next, &manifest_descs, links)
+       list_for_each_entry_safe(descriptor, next, &intf->manifest_descs, links)
                release_manifest_descriptor(descriptor);
 }
 
+static void release_cport_descriptors(struct list_head *head, u8 bundle_id)
+{
+       struct manifest_desc *desc, *tmp;
+       struct greybus_descriptor_cport *desc_cport;
+
+       list_for_each_entry_safe(desc, tmp, head, links) {
+               desc_cport = desc->data;
+
+               if (desc->type != GREYBUS_TYPE_CPORT)
+                       continue;
+
+               if (desc_cport->bundle == bundle_id)
+                       release_manifest_descriptor(desc);
+       }
+}
+
+static struct manifest_desc *get_next_bundle_desc(struct gb_interface *intf)
+{
+       struct manifest_desc *descriptor;
+       struct manifest_desc *next;
+
+       list_for_each_entry_safe(descriptor, next, &intf->manifest_descs, links)
+               if (descriptor->type == GREYBUS_TYPE_BUNDLE)
+                       return descriptor;
+
+       return NULL;
+}
+
 /*
  * Validate the given descriptor.  Its reported size must fit within
- * the number of bytes reamining, and it must have a recognized
+ * the number of bytes remaining, and it must have a recognized
  * type.  Check that the reported size is at least as big as what
  * we expect to see.  (It could be bigger, perhaps for a new version
  * of the format.)
  *
- * Returns the number of bytes consumed by the descriptor, or a
- * negative errno.
+ * Returns the (non-zero) number of bytes consumed by the descriptor,
+ * or a negative errno.
  */
-static int identify_descriptor(struct greybus_descriptor *desc, size_t size)
+static int identify_descriptor(struct gb_interface *intf,
+                              struct greybus_descriptor *desc, size_t size)
 {
        struct greybus_descriptor_header *desc_header = &desc->header;
        struct manifest_desc *descriptor;
-       int desc_size;
+       size_t desc_size;
        size_t expected_size;
 
        if (size < sizeof(*desc_header)) {
-               pr_err("manifest too small\n");
+               pr_err("manifest too small (%zu < %zu)\n",
+                               size, sizeof(*desc_header));
                return -EINVAL;         /* Must at least have header */
        }
 
-       desc_size = (int)le16_to_cpu(desc_header->size);
-       if ((size_t)desc_size > size) {
-               pr_err("descriptor too big\n");
+       desc_size = le16_to_cpu(desc_header->size);
+       if (desc_size > size) {
+               pr_err("descriptor too big (%zu > %zu)\n", desc_size, size);
                return -EINVAL;
        }
 
+       /* Descriptor needs to at least have a header */
+       expected_size = sizeof(*desc_header);
+
        switch (desc_header->type) {
-       case GREYBUS_TYPE_MODULE:
-               if (desc_size < sizeof(struct greybus_descriptor_module)) {
-                       pr_err("module descriptor too small (%u)\n",
-                               desc_size);
-                       return -EINVAL;
-               }
-               break;
        case GREYBUS_TYPE_STRING:
-               expected_size = sizeof(struct greybus_descriptor_header);
                expected_size += sizeof(struct greybus_descriptor_string);
-               expected_size += (size_t)desc->string.length;
-               if (desc_size < expected_size) {
-                       pr_err("string descriptor too small (%u)\n",
-                               desc_size);
-                       return -EINVAL;
-               }
+               expected_size += desc->string.length;
+
+               /* String descriptors are padded to 4 byte boundaries */
+               expected_size = ALIGN(expected_size, 4);
                break;
        case GREYBUS_TYPE_INTERFACE:
+               expected_size += sizeof(struct greybus_descriptor_interface);
                break;
-       case GREYBUS_TYPE_CPORT:
-               if (desc_size < sizeof(struct greybus_descriptor_cport)) {
-                       pr_err("cport descriptor too small (%u)\n",
-                               desc_size);
-                       return -EINVAL;
-               }
+       case GREYBUS_TYPE_BUNDLE:
+               expected_size += sizeof(struct greybus_descriptor_bundle);
                break;
-       case GREYBUS_TYPE_CLASS:
-               pr_warn("class descriptor found (ignoring)\n");
+       case GREYBUS_TYPE_CPORT:
+               expected_size += sizeof(struct greybus_descriptor_cport);
                break;
        case GREYBUS_TYPE_INVALID:
        default:
@@ -108,14 +144,30 @@ static int identify_descriptor(struct greybus_descriptor *desc, size_t size)
                return -EINVAL;
        }
 
+       if (desc_size < expected_size) {
+               pr_err("%s descriptor too small (%zu < %zu)\n",
+                      get_descriptor_type_string(desc_header->type),
+                      desc_size, expected_size);
+               return -EINVAL;
+       }
+
+       /* Descriptor bigger than what we expect */
+       if (desc_size > expected_size) {
+               pr_warn("%s descriptor size mismatch (want %zu got %zu)\n",
+                       get_descriptor_type_string(desc_header->type),
+                       expected_size, desc_size);
+       }
+
        descriptor = kzalloc(sizeof(*descriptor), GFP_KERNEL);
        if (!descriptor)
                return -ENOMEM;
 
        descriptor->size = desc_size;
-       descriptor->data = (u8 *)desc + sizeof(*desc_header);
+       descriptor->data = (char *)desc + sizeof(*desc_header);
        descriptor->type = desc_header->type;
-       list_add_tail(&descriptor->links, &manifest_descs);
+       list_add_tail(&descriptor->links, &intf->manifest_descs);
+
+       /* desc_size is positive and is known to fit in a signed int */
 
        return desc_size;
 }
@@ -131,7 +183,7 @@ static int identify_descriptor(struct greybus_descriptor *desc, size_t size)
  * Otherwise returns a pointer to a newly-allocated copy of the
  * descriptor string, or an error-coded pointer on failure.
  */
-static char *gb_string_get(u8 string_id)
+static char *gb_string_get(struct gb_interface *intf, u8 string_id)
 {
        struct greybus_descriptor_string *desc_string;
        struct manifest_desc *descriptor;
@@ -142,8 +194,7 @@ static char *gb_string_get(u8 string_id)
        if (!string_id)
                return NULL;
 
-       list_for_each_entry(descriptor, &manifest_descs, links) {
-
+       list_for_each_entry(descriptor, &intf->manifest_descs, links) {
                if (descriptor->type != GREYBUS_TYPE_STRING)
                        continue;
 
@@ -157,7 +208,7 @@ static char *gb_string_get(u8 string_id)
                return ERR_PTR(-ENOENT);
 
        /* Allocate an extra byte so we can guarantee it's NUL-terminated */
-       string = kmemdup(&desc_string->string, (size_t)desc_string->length + 1,
+       string = kmemdup(&desc_string->string, desc_string->length + 1,
                                GFP_KERNEL);
        if (!string)
                return ERR_PTR(-ENOMEM);
@@ -170,134 +221,178 @@ static char *gb_string_get(u8 string_id)
 }
 
 /*
- * Find cport descriptors in the manifest and set up data structures
- * for the functions that use them.  Returns the number of interfaces
- * set up for the given module, or 0 if there is an error.
+ * Find cport descriptors in the manifest associated with the given
+ * bundle, and set up data structures for the functions that use
+ * them.  Returns the number of cports set up for the bundle, or 0
+ * if there is an error.
  */
-static u32 gb_manifest_parse_cports(struct gb_interface *interface)
+static u32 gb_manifest_parse_cports(struct gb_bundle *bundle)
 {
+       struct gb_interface *intf = bundle->intf;
+       struct manifest_desc *desc;
+       struct manifest_desc *next;
+       u8 bundle_id = bundle->id;
+       u8 protocol_id;
+       u16 cport_id;
        u32 count = 0;
 
-       while (true) {
-               struct manifest_desc *descriptor;
+       /* 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;
-               u8 protocol_id;
-               u16 cport_id;
-               bool found = false;
-
-               /* Find a cport descriptor */
-               list_for_each_entry(descriptor, &manifest_descs, links) {
-                       if (descriptor->type == GREYBUS_TYPE_CPORT) {
-                               desc_cport = descriptor->data;
-                               if (desc_cport->interface == interface->id) {
-                                       found = true;
-                                       break;
-                               }
-                       }
-               }
-               if (!found)
-                       break;
+
+               if (desc->type != GREYBUS_TYPE_CPORT)
+                       continue;
+
+               desc_cport = desc->data;
+               if (desc_cport->bundle != bundle_id)
+                       continue;
+
+               cport_id = le16_to_cpu(desc_cport->id);
+               if (cport_id > CPORT_ID_MAX)
+                       goto exit;
 
                /* Found one.  Set up its function structure */
                protocol_id = desc_cport->protocol_id;
-               cport_id = le16_to_cpu(desc_cport->id);
-               if (!gb_connection_create(interface, cport_id, protocol_id))
-                       return 0;       /* Error */
+
+               if (!gb_connection_create_dynamic(intf, bundle, cport_id,
+                                                               protocol_id))
+                       goto exit;
 
                count++;
+
                /* Release the cport descriptor */
-               release_manifest_descriptor(descriptor);
+               release_manifest_descriptor(desc);
        }
 
        return count;
+exit:
+
+       /*
+        * Free all cports for this bundle to avoid 'excess descriptors'
+        * warnings.
+        */
+       release_cport_descriptors(&intf->manifest_descs, bundle_id);
+
+       return 0;       /* Error; count should also be 0 */
 }
 
 /*
- * Find interface descriptors in the manifest and set up their data
- * structures.  Returns the number of interfaces set up for the
- * given module.
+ * Find bundle descriptors in the manifest and set up their data
+ * structures.  Returns the number of bundles set up for the
+ * given interface.
  */
-static u32 gb_manifest_parse_interfaces(struct gb_module *gmod)
+static u32 gb_manifest_parse_bundles(struct gb_interface *intf)
 {
+       struct manifest_desc *desc;
+       struct gb_bundle *bundle;
+       struct gb_bundle *bundle_next;
        u32 count = 0;
-
-       while (true) {
-               struct manifest_desc *descriptor;
-               struct greybus_descriptor_interface *desc_interface;
-               struct gb_interface *interface;
-               bool found = false;
-
-               /* Find an interface descriptor */
-               list_for_each_entry(descriptor, &manifest_descs, links) {
-                       if (descriptor->type == GREYBUS_TYPE_INTERFACE) {
-                               found = true;
-                               break;
-                       }
+       u8 bundle_id;
+       u8 class;
+
+       while ((desc = get_next_bundle_desc(intf))) {
+               struct greybus_descriptor_bundle *desc_bundle;
+
+               /* Found one.  Set up its bundle structure*/
+               desc_bundle = desc->data;
+               bundle_id = desc_bundle->id;
+               class = desc_bundle->class;
+
+               /* Done with this bundle descriptor */
+               release_manifest_descriptor(desc);
+
+               /* Ignore any legacy control bundles */
+               if (bundle_id == GB_CONTROL_BUNDLE_ID) {
+                       dev_dbg(&intf->dev, "%s - ignoring control bundle\n",
+                                       __func__);
+                       release_cport_descriptors(&intf->manifest_descs,
+                                                               bundle_id);
+                       continue;
                }
-               if (!found)
-                       break;
 
-               /* Found one.  Set up its interface structure*/
-               desc_interface = descriptor->data;
-               interface = gb_interface_create(gmod, desc_interface->id);
-               if (!interface)
-                       return 0;       /* Error */
+               /* Nothing else should have its class set to control class */
+               if (class == GREYBUS_CLASS_CONTROL) {
+                       dev_err(&intf->dev,
+                               "bundle 0x%02x cannot use control class\n",
+                               bundle_id);
+                       goto cleanup;
+               }
 
-               /* Now go set up this interface's functions and cports */
-               if (!gb_manifest_parse_cports(interface))
-                       return 0;       /* Error parsing cports */
+               bundle = gb_bundle_create(intf, bundle_id, class);
+               if (!bundle)
+                       goto cleanup;
+
+               /*
+                * Now go set up this bundle's functions and cports.
+                *
+                * A 'bundle' represents a device in greybus. It may require
+                * multiple cports for its functioning. If we fail to setup any
+                * cport of a bundle, we better reject the complete bundle as
+                * the device may not be able to function properly then.
+                *
+                * But, failing to setup a cport of bundle X doesn't mean that
+                * the device corresponding to bundle Y will not work properly.
+                * Bundles should be treated as separate independent devices.
+                *
+                * While parsing manifest for an interface, treat bundles as
+                * separate entities and don't reject entire interface and its
+                * bundles on failing to initialize a cport. But make sure the
+                * bundle which needs the cport, gets destroyed properly.
+                */
+               if (!gb_manifest_parse_cports(bundle)) {
+                       gb_bundle_destroy(bundle);
+                       continue;
+               }
 
                count++;
-
-               /* Done with this interface descriptor */
-               release_manifest_descriptor(descriptor);
        }
 
        return count;
+cleanup:
+       /* An error occurred; undo any changes we've made */
+       list_for_each_entry_safe(bundle, bundle_next, &intf->bundles, links) {
+               gb_bundle_destroy(bundle);
+               count--;
+       }
+       return 0;       /* Error; count should also be 0 */
 }
 
-static bool gb_manifest_parse_module(struct gb_module *gmod,
-                                       struct manifest_desc *module_desc)
+static bool gb_manifest_parse_interface(struct gb_interface *intf,
+                                       struct manifest_desc *interface_desc)
 {
-       struct greybus_descriptor_module *desc_module = module_desc->data;
+       struct greybus_descriptor_interface *desc_intf = interface_desc->data;
 
        /* Handle the strings first--they can fail */
-       gmod->vendor_string = gb_string_get(desc_module->vendor_stringid);
-       if (IS_ERR(gmod->vendor_string))
+       intf->vendor_string = gb_string_get(intf, desc_intf->vendor_stringid);
+       if (IS_ERR(intf->vendor_string))
                return false;
 
-       gmod->product_string = gb_string_get(desc_module->product_stringid);
-       if (IS_ERR(gmod->product_string)) {
+       intf->product_string = gb_string_get(intf, desc_intf->product_stringid);
+       if (IS_ERR(intf->product_string))
                goto out_free_vendor_string;
-       }
-
-       gmod->vendor = le16_to_cpu(desc_module->vendor);
-       gmod->product = le16_to_cpu(desc_module->product);
-       gmod->version = le16_to_cpu(desc_module->version);
-       gmod->unique_id = le64_to_cpu(desc_module->unique_id);
 
-       /* Release the module descriptor, now that we're done with it */
-       release_manifest_descriptor(module_desc);
+       /* Release the interface descriptor, now that we're done with it */
+       release_manifest_descriptor(interface_desc);
 
-       /* A module must have at least one interface descriptor */
-       if (!gb_manifest_parse_interfaces(gmod)) {
-               pr_err("manifest interface descriptors not valid\n");
+       /* An interface must have at least one bundle descriptor */
+       if (!gb_manifest_parse_bundles(intf)) {
+               dev_err(&intf->dev, "manifest bundle descriptors not valid\n");
                goto out_err;
        }
 
        return true;
 out_err:
-       kfree(gmod->product_string);
-       gmod->product_string = NULL;
+       kfree(intf->product_string);
+       intf->product_string = NULL;
 out_free_vendor_string:
-       kfree(gmod->vendor_string);
-       gmod->vendor_string = NULL;
+       kfree(intf->vendor_string);
+       intf->vendor_string = NULL;
 
        return false;
 }
 
 /*
- * Parse a buffer containing a module manifest.
+ * Parse a buffer containing an interface manifest.
  *
  * If we find anything wrong with the content/format of the buffer
  * we reject it.
@@ -309,34 +404,34 @@ out_free_vendor_string:
  * the descriptors it contains, keeping track for each its type
  * and the location size of its data in the buffer.
  *
- * Next we scan the descriptors, looking for a module descriptor;
+ * Next we scan the descriptors, looking for an interface descriptor;
  * there must be exactly one of those.  When found, we record the
  * information it contains, and then remove that descriptor (and any
  * string descriptors it refers to) from further consideration.
  *
- * After that we look for the module's interfaces--there must be at
+ * After that we look for the interface's bundles--there must be at
  * least one of those.
  *
  * Returns true if parsing was successful, false otherwise.
  */
-bool gb_manifest_parse(struct gb_module *gmod, void *data, size_t size)
+bool gb_manifest_parse(struct gb_interface *intf, void *data, size_t size)
 {
        struct greybus_manifest *manifest;
        struct greybus_manifest_header *header;
        struct greybus_descriptor *desc;
        struct manifest_desc *descriptor;
-       struct manifest_desc *module_desc = NULL;
+       struct manifest_desc *interface_desc = NULL;
        u16 manifest_size;
        u32 found = 0;
        bool result;
 
        /* Manifest descriptor list should be empty here */
-       if (WARN_ON(!list_empty(&manifest_descs)))
+       if (WARN_ON(!list_empty(&intf->manifest_descs)))
                return false;
 
        /* we have to have at _least_ the manifest header */
-       if (size <= sizeof(manifest->header)) {
-               pr_err("short manifest (%zu)\n", size);
+       if (size < sizeof(*header)) {
+               pr_err("short manifest (%zu < %zu)\n", size, sizeof(*header));
                return false;
        }
 
@@ -345,7 +440,7 @@ bool gb_manifest_parse(struct gb_module *gmod, void *data, size_t size)
        header = &manifest->header;
        manifest_size = le16_to_cpu(header->size);
        if (manifest_size != size) {
-               pr_err("manifest size mismatch %zu != %hu\n",
+               pr_err("manifest size mismatch (%zu != %hu)\n",
                        size, manifest_size);
                return false;
        }
@@ -353,21 +448,19 @@ bool gb_manifest_parse(struct gb_module *gmod, void *data, size_t size)
        /* Validate major/minor number */
        if (header->version_major > GREYBUS_VERSION_MAJOR) {
                pr_err("manifest version too new (%hhu.%hhu > %hhu.%hhu)\n",
-                       header->version_major, header->version_minor,
-                       GREYBUS_VERSION_MAJOR, GREYBUS_VERSION_MINOR);
+                      header->version_major, header->version_minor,
+                      GREYBUS_VERSION_MAJOR, GREYBUS_VERSION_MINOR);
                return false;
        }
 
        /* OK, find all the descriptors */
-       desc = (struct greybus_descriptor *)(header + 1);
+       desc = manifest->descriptors;
        size -= sizeof(*header);
        while (size) {
                int desc_size;
 
-               desc_size = identify_descriptor(desc, size);
-               if (desc_size <= 0) {
-                       if (!desc_size)
-                               pr_err("zero-sized manifest descriptor\n");
+               desc_size = identify_descriptor(intf, desc, size);
+               if (desc_size < 0) {
                        result = false;
                        goto out;
                }
@@ -375,30 +468,30 @@ bool gb_manifest_parse(struct gb_module *gmod, void *data, size_t size)
                size -= desc_size;
        }
 
-       /* There must be a single module descriptor */
-       list_for_each_entry(descriptor, &manifest_descs, links) {
-               if (descriptor->type == GREYBUS_TYPE_MODULE)
+       /* There must be a single interface descriptor */
+       list_for_each_entry(descriptor, &intf->manifest_descs, links) {
+               if (descriptor->type == GREYBUS_TYPE_INTERFACE)
                        if (!found++)
-                               module_desc = descriptor;
+                               interface_desc = descriptor;
        }
        if (found != 1) {
-               pr_err("manifest must have 1 module descriptor (%u found)\n",
+               pr_err("manifest must have 1 interface descriptor (%u found)\n",
                        found);
                result = false;
                goto out;
        }
 
-       /* Parse the module manifest, starting with the module descriptor */
-       result = gb_manifest_parse_module(gmod, module_desc);
+       /* Parse the manifest, starting with the interface descriptor */
+       result = gb_manifest_parse_interface(intf, interface_desc);
 
        /*
         * We really should have no remaining descriptors, but we
         * don't know what newer format manifests might leave.
         */
-       if (result && !list_empty(&manifest_descs))
-               pr_info("excess descriptors in module manifest\n");
+       if (result && !list_empty(&intf->manifest_descs))
+               pr_info("excess descriptors in interface manifest\n");
 out:
-       release_manifest_descriptors();
+       release_manifest_descriptors(intf);
 
        return result;
 }