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>
This commit is contained in:
Viresh Kumar 2015-06-22 16:42:27 +05:30 committed by Greg Kroah-Hartman
parent cdee4f7505
commit 6c68da264b
5 changed files with 104 additions and 26 deletions

View 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:

View 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);

View 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;
intf = gb_interface_create(hd, interface_id);
if (!intf) {
dev_err(hd->parent, "failed to create interface\n");
return;
/* 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;
}
/* 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)

View 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);

View 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;