From 6c68da264b080f749e8848b0227e6bb7d7c72f21 Mon Sep 17 00:00:00 2001 From: Viresh Kumar Date: Mon, 22 Jun 2015 16:42:27 +0530 Subject: [PATCH] greybus: interface: Get manifest using Control protocol 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 Signed-off-by: Viresh Kumar Signed-off-by: Greg Kroah-Hartman --- drivers/staging/greybus/ap.c | 7 ++- drivers/staging/greybus/bundle.c | 4 ++ drivers/staging/greybus/interface.c | 100 ++++++++++++++++++++++++++++-------- drivers/staging/greybus/interface.h | 5 +- drivers/staging/greybus/manifest.c | 14 +++++ 5 files changed, 104 insertions(+), 26 deletions(-) diff --git a/drivers/staging/greybus/ap.c b/drivers/staging/greybus/ap.c index 07375cc96bfb..113fd878c634 100644 --- a/drivers/staging/greybus/ap.c +++ b/drivers/staging/greybus/ap.c @@ -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: diff --git a/drivers/staging/greybus/bundle.c b/drivers/staging/greybus/bundle.c index 8d0e86fc2cfc..a5172e5f64b2 100644 --- a/drivers/staging/greybus/bundle.c +++ b/drivers/staging/greybus/bundle.c @@ -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); diff --git a/drivers/staging/greybus/interface.c b/drivers/staging/greybus/interface.c index 5b1621ccf724..901c4acc2421 100644 --- a/drivers/staging/greybus/interface.c +++ b/drivers/staging/greybus/interface.c @@ -67,6 +67,36 @@ struct device_type greybus_interface_type = { }; /* + * 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 * module may have more than one interface. @@ -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) diff --git a/drivers/staging/greybus/interface.h b/drivers/staging/greybus/interface.h index 9c566b237aba..90dbff13e977 100644 --- a/drivers/staging/greybus/interface.h +++ b/drivers/staging/greybus/interface.h @@ -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); diff --git a/drivers/staging/greybus/manifest.c b/drivers/staging/greybus/manifest.c index 377c449d5785..bd5753f8c384 100644 --- a/drivers/staging/greybus/manifest.c +++ b/drivers/staging/greybus/manifest.c @@ -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; -- 2.11.0