Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 98fdf5a0 authored by Johan Hovold's avatar Johan Hovold Committed by Greg Kroah-Hartman
Browse files

greybus: core: defer connection creation to driver probe



Defer connection creation to bundle driver probe instead of creating
them when initialising the interface and parsing the manifest.

Store copies of the CPorts descriptors in the bundle for the drivers to
use, and update the legacy driver.

This is needed for drivers that need more control over host-device
resource management, for example, when a protocol needs to use a
dedicated host CPort for traffic offloading (e.g. camera data).

This also avoids allocating host CPorts for bundles that are not bound
to a driver or for remote CPorts that a driver does not need.

Reviewed-by: default avatarViresh Kumar <viresh.kumar@linaro.org>
Signed-off-by: default avatarJohan Hovold <johan@hovoldconsulting.com>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@google.com>
parent 6ce4cc27
Loading
Loading
Loading
Loading
+1 −7
Original line number Diff line number Diff line
@@ -81,15 +81,9 @@ static struct gb_bundle *gb_bundle_find(struct gb_interface *intf,
static void gb_bundle_release(struct device *dev)
{
	struct gb_bundle *bundle = to_gb_bundle(dev);
	struct gb_connection *connection;
	struct gb_connection *tmp;

	list_for_each_entry_safe(connection, tmp, &bundle->connections,
								bundle_links) {
		gb_connection_destroy(connection);
	}

	kfree(bundle->state);
	kfree(bundle->cport_desc);
	kfree(bundle);
}

+3 −0
Original line number Diff line number Diff line
@@ -22,6 +22,9 @@ struct gb_bundle {
	u8			class_major;
	u8			class_minor;

	size_t			num_cports;
	struct greybus_descriptor_cport *cport_desc;

	struct list_head	connections;
	u8			*state;

+2 −0
Original line number Diff line number Diff line
@@ -232,6 +232,7 @@ gb_connection_create_dynamic(struct gb_interface *intf,
	return gb_connection_create(intf->hd, -1, intf, bundle, cport_id,
								protocol_id);
}
EXPORT_SYMBOL_GPL(gb_connection_create_dynamic);

static int gb_connection_hd_cport_enable(struct gb_connection *connection)
{
@@ -546,6 +547,7 @@ void gb_connection_destroy(struct gb_connection *connection)

	gb_connection_put(connection);
}
EXPORT_SYMBOL_GPL(gb_connection_destroy);

void gb_connection_latency_tag_enable(struct gb_connection *connection)
{
+9 −6
Original line number Diff line number Diff line
@@ -151,8 +151,14 @@ static int greybus_probe(struct device *dev)
		return -ENODEV;

	retval = driver->probe(bundle, id);
	if (retval)
	if (retval) {
		/*
		 * Catch buggy drivers that fail to destroy their connections.
		 */
		WARN_ON(!list_empty(&bundle->connections));

		return retval;
	}

	return 0;
}
@@ -172,11 +178,8 @@ static int greybus_remove(struct device *dev)

	driver->disconnect(bundle);

	/* Catch buggy drivers that fail to disable their connections. */
	list_for_each_entry(connection, &bundle->connections, bundle_links) {
		if (WARN_ON(connection->state != GB_CONNECTION_STATE_DISABLED))
			gb_connection_disable(connection);
	}
	/* Catch buggy drivers that fail to destroy their connections. */
	WARN_ON(!list_empty(&bundle->connections));

	return 0;
}
+40 −16
Original line number Diff line number Diff line
@@ -14,6 +14,7 @@

struct legacy_data {
	size_t num_cports;
	struct gb_connection **connections;
};


@@ -128,25 +129,44 @@ static void legacy_connection_exit(struct gb_connection *connection)
static int legacy_probe(struct gb_bundle *bundle,
			const struct greybus_bundle_id *id)
{
	struct greybus_descriptor_cport *cport_desc;
	struct legacy_data *data;
	struct gb_connection *connection;
	int ret;
	int i;
	int ret = -ENOMEM;

	dev_dbg(&bundle->dev,
			"%s - bundle class = 0x%02x, num_cports = %zu\n",
			__func__, bundle->class, bundle->num_cports);

	data = kzalloc(sizeof(*data), GFP_KERNEL);
	if (!data)
		return -ENOMEM;

	data->num_cports = 0;
	list_for_each_entry(connection, &bundle->connections, bundle_links)
		data->num_cports++;
	data->num_cports = bundle->num_cports;
	data->connections = kcalloc(data->num_cports,
						sizeof(*data->connections),
						GFP_KERNEL);
	if (!data->connections)
		goto err_free_data;

	dev_dbg(&bundle->dev,
			"%s - bundle class = 0x%02x, num_cports = %zu\n",
			__func__, bundle->class, data->num_cports);
	for (i = 0; i < data->num_cports; ++i) {
		cport_desc = &bundle->cport_desc[i];

		connection = gb_connection_create_dynamic(bundle->intf,
						bundle,
						le16_to_cpu(cport_desc->id),
						cport_desc->protocol_id);
		if (!connection)
			goto err_connections_destroy;

		data->connections[i] = connection;
	}

	greybus_set_drvdata(bundle, data);

	list_for_each_entry(connection, &bundle->connections, bundle_links) {
	for (i = 0; i < data->num_cports; ++i) {
		connection = data->connections[i];
		dev_dbg(&bundle->dev, "enabling connection %s\n",
				connection->name);

@@ -158,10 +178,13 @@ static int legacy_probe(struct gb_bundle *bundle,
	return 0;

err_connections_disable:
	list_for_each_entry_reverse(connection, &bundle->connections,
							bundle_links) {
		legacy_connection_exit(connection);
	}
	for (--i; i >= 0; --i)
		legacy_connection_exit(data->connections[i]);
err_connections_destroy:
	for (i = 0; i < data->num_cports; ++i)
		gb_connection_destroy(data->connections[i]);
	kfree(data->connections);
err_free_data:
	kfree(data);

	return ret;
@@ -170,16 +193,17 @@ static int legacy_probe(struct gb_bundle *bundle,
static void legacy_disconnect(struct gb_bundle *bundle)
{
	struct legacy_data *data = greybus_get_drvdata(bundle);
	struct gb_connection *connection;
	int i;

	dev_dbg(&bundle->dev, "%s - bundle class = 0x%02x\n", __func__,
			bundle->class);

	list_for_each_entry_reverse(connection, &bundle->connections,
							bundle_links) {
		legacy_connection_exit(connection);
	for (i = 0; i < data->num_cports; ++i) {
		legacy_connection_exit(data->connections[i]);
		gb_connection_destroy(data->connections[i]);
	}

	kfree(data->connections);
	kfree(data);
}

Loading