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:
parent
cdee4f7505
commit
6c68da264b
@ -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:
|
||||
|
@ -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);
|
||||
|
@ -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)
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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;
|
||||
|
Loading…
x
Reference in New Issue
Block a user