Commit fb69cb50 authored by Greg Kroah-Hartman's avatar Greg Kroah-Hartman
Browse files

greybus: protocol: split binding of prototcols to connections out of init



When adding a new protocol to the system, walk all bundles and try to
hook up any connections that do not have a protocol already.  This sets
the stage to allow for protocols to be loaded at any time, not just
before the device is seen in the system.

Reviewed-by: default avatarAlex Elder <elder@linaro.org>
Signed-off-by: default avatarGreg Kroah-Hartman <greg@kroah.com>
parent df469a94
Loading
Loading
Loading
Loading
+30 −0
Original line number Diff line number Diff line
@@ -45,6 +45,36 @@ struct device_type greybus_bundle_type = {
/* XXX This could be per-host device or per-module */
static DEFINE_SPINLOCK(gb_bundles_lock);

static int __bundle_bind_protocols(struct device *dev, void *data)
{
	struct gb_bundle *bundle;
	struct gb_connection *connection;

	if (!is_gb_bundle(dev))
		return 0;

	bundle = to_gb_bundle(dev);

	list_for_each_entry(connection, &bundle->connections, bundle_links) {
		gb_connection_bind_protocol(connection);
	}

	return 0;
}

/*
 * Walk all bundles in the system, and see if any connections are not bound to a
 * specific prototcol.  If they are not, then try to find one for it and bind it
 * to it.
 *
 * This is called after registering a new protocol.
 */
void gb_bundle_bind_protocols(void)
{
	bus_for_each_dev(&greybus_bus_type, NULL, NULL,
			 __bundle_bind_protocols);
}

/*
 * Create a gb_bundle structure to represent a discovered
 * bundle.  Returns a pointer to the new bundle or a null
+1 −0
Original line number Diff line number Diff line
@@ -30,5 +30,6 @@ void gb_bundle_destroy(struct gb_interface *intf);
int gb_bundle_init(struct gb_interface *intf, u8 module_id, u8 device_id);

struct gb_bundle *gb_bundle_find(struct gb_interface *intf, u8 bundle_id);
void gb_bundle_bind_protocols(void);

#endif /* __BUNDLE_H */
+38 −10
Original line number Diff line number Diff line
@@ -124,6 +124,32 @@ struct device_type greybus_connection_type = {
	.release =	gb_connection_release,
};


void gb_connection_bind_protocol(struct gb_connection *connection)
{
	struct gb_bundle *bundle;
	struct gb_protocol *protocol;

	/* If we already have a protocol bound here, just return */
	if (connection->protocol)
		return;

	protocol = gb_protocol_get(connection->protocol_id,
				   connection->major,
				   connection->minor);
	if (!protocol)
		return;
	connection->protocol = protocol;

	/*
	 * If we have a valid device_id for the bundle, then we have an active
	 * device, so bring up the connection at the same time.
	 * */
	bundle = connection->bundle;
	if (bundle->device_id != 0xff)
		gb_connection_init(connection);
}

/*
 * Set up a Greybus connection, representing the bidirectional link
 * between a CPort on a (local) Greybus host device and a CPort on
@@ -148,13 +174,9 @@ struct gb_connection *gb_connection_create(struct gb_bundle *bundle,
	if (!connection)
		return NULL;

	/* XXX Will have to establish connections to get version */
	connection->protocol = gb_protocol_get(protocol_id, major, minor);
	if (!connection->protocol) {
		pr_err("protocol 0x%02hhx not found\n", protocol_id);
		kfree(connection);
		return NULL;
	}
	connection->protocol_id = protocol_id;
	connection->major = major;
	connection->minor = minor;

	hd = bundle->intf->hd;
	connection->hd = hd;
@@ -187,6 +209,12 @@ struct gb_connection *gb_connection_create(struct gb_bundle *bundle,
		return NULL;
	}

	/* XXX Will have to establish connections to get version */
	gb_connection_bind_protocol(connection);
	if (!connection->protocol)
		dev_warn(&bundle->dev,
			 "protocol 0x%02hhx handler not found\n", protocol_id);

	spin_lock_irq(&gb_connections_lock);
	list_add_tail(&connection->hd_links, &hd->connections);
	list_add_tail(&connection->bundle_links, &bundle->connections);
@@ -250,8 +278,8 @@ int gb_connection_init(struct gb_connection *connection)
	int ret;

	if (!connection->protocol) {
		gb_connection_err(connection, "uninitialized connection");
		return -EIO;
		dev_warn(&connection->dev, "init without protocol.\n");
		return 0;
	}

	/* Need to enable the connection to initialize it */
@@ -266,7 +294,7 @@ int gb_connection_init(struct gb_connection *connection)
void gb_connection_exit(struct gb_connection *connection)
{
	if (!connection->protocol) {
		gb_connection_err(connection, "uninitialized connection");
		dev_warn(&connection->dev, "exit without protocol.\n");
		return;
	}
	connection->state = GB_CONNECTION_STATE_DESTROYING;
+5 −0
Original line number Diff line number Diff line
@@ -33,6 +33,9 @@ struct gb_connection {
	struct list_head		bundle_links;

	struct gb_protocol		*protocol;
	u8				protocol_id;
	u8				major;
	u8				minor;

	enum gb_connection_state	state;

@@ -58,4 +61,6 @@ void greybus_data_rcvd(struct greybus_host_device *hd, u16 cport_id,
__printf(2, 3)
void gb_connection_err(struct gb_connection *connection, const char *fmt, ...);

void gb_connection_bind_protocol(struct gb_connection *connection);

#endif /* __CONNECTION_H */
+3 −0
Original line number Diff line number Diff line
@@ -206,6 +206,9 @@ static void gb_operation_request_handle(struct gb_operation *operation)
{
	struct gb_protocol *protocol = operation->connection->protocol;

	if (!protocol)
		return;

	/*
	 * If the protocol has no incoming request handler, report
	 * an error and mark the request bad.
Loading