aboutsummaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
authorGravatar Viresh Kumar <viresh.kumar@linaro.org> 2015-06-22 16:42:27 +0530
committerGravatar Greg Kroah-Hartman <gregkh@google.com> 2015-06-23 23:16:15 -0700
commit6c68da264b080f749e8848b0227e6bb7d7c72f21 (patch)
tree9092b29b987a070bf14d925dfd3e10d1bc3821bb /drivers
parentgreybus: Add control protocol support (diff)
downloadlinux-6c68da264b080f749e8848b0227e6bb7d7c72f21.tar.gz
linux-6c68da264b080f749e8848b0227e6bb7d7c72f21.tar.bz2
linux-6c68da264b080f749e8848b0227e6bb7d7c72f21.zip
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 <elder@linaro.org> Signed-off-by: Viresh Kumar <viresh.kumar@linaro.org> Signed-off-by: Greg Kroah-Hartman <gregkh@google.com>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/staging/greybus/ap.c7
-rw-r--r--drivers/staging/greybus/bundle.c4
-rw-r--r--drivers/staging/greybus/interface.c100
-rw-r--r--drivers/staging/greybus/interface.h5
-rw-r--r--drivers/staging/greybus/manifest.c14
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;