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: Alex Elder <elder@linaro.org> Signed-off-by: Greg Kroah-Hartman <greg@kroah.com>
This commit is contained in:
parent
df469a9423
commit
fb69cb506c
|
@ -45,6 +45,36 @@ struct device_type greybus_bundle_type = {
|
||||||
/* XXX This could be per-host device or per-module */
|
/* XXX This could be per-host device or per-module */
|
||||||
static DEFINE_SPINLOCK(gb_bundles_lock);
|
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
|
* Create a gb_bundle structure to represent a discovered
|
||||||
* bundle. Returns a pointer to the new bundle or a null
|
* bundle. Returns a pointer to the new bundle or a null
|
||||||
|
|
|
@ -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);
|
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);
|
struct gb_bundle *gb_bundle_find(struct gb_interface *intf, u8 bundle_id);
|
||||||
|
void gb_bundle_bind_protocols(void);
|
||||||
|
|
||||||
#endif /* __BUNDLE_H */
|
#endif /* __BUNDLE_H */
|
||||||
|
|
|
@ -124,6 +124,32 @@ struct device_type greybus_connection_type = {
|
||||||
.release = gb_connection_release,
|
.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
|
* Set up a Greybus connection, representing the bidirectional link
|
||||||
* between a CPort on a (local) Greybus host device and a CPort on
|
* 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)
|
if (!connection)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
/* XXX Will have to establish connections to get version */
|
connection->protocol_id = protocol_id;
|
||||||
connection->protocol = gb_protocol_get(protocol_id, major, minor);
|
connection->major = major;
|
||||||
if (!connection->protocol) {
|
connection->minor = minor;
|
||||||
pr_err("protocol 0x%02hhx not found\n", protocol_id);
|
|
||||||
kfree(connection);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
hd = bundle->intf->hd;
|
hd = bundle->intf->hd;
|
||||||
connection->hd = hd;
|
connection->hd = hd;
|
||||||
|
@ -187,6 +209,12 @@ struct gb_connection *gb_connection_create(struct gb_bundle *bundle,
|
||||||
return NULL;
|
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);
|
spin_lock_irq(&gb_connections_lock);
|
||||||
list_add_tail(&connection->hd_links, &hd->connections);
|
list_add_tail(&connection->hd_links, &hd->connections);
|
||||||
list_add_tail(&connection->bundle_links, &bundle->connections);
|
list_add_tail(&connection->bundle_links, &bundle->connections);
|
||||||
|
@ -250,8 +278,8 @@ int gb_connection_init(struct gb_connection *connection)
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
if (!connection->protocol) {
|
if (!connection->protocol) {
|
||||||
gb_connection_err(connection, "uninitialized connection");
|
dev_warn(&connection->dev, "init without protocol.\n");
|
||||||
return -EIO;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Need to enable the connection to initialize it */
|
/* 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)
|
void gb_connection_exit(struct gb_connection *connection)
|
||||||
{
|
{
|
||||||
if (!connection->protocol) {
|
if (!connection->protocol) {
|
||||||
gb_connection_err(connection, "uninitialized connection");
|
dev_warn(&connection->dev, "exit without protocol.\n");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
connection->state = GB_CONNECTION_STATE_DESTROYING;
|
connection->state = GB_CONNECTION_STATE_DESTROYING;
|
||||||
|
|
|
@ -33,6 +33,9 @@ struct gb_connection {
|
||||||
struct list_head bundle_links;
|
struct list_head bundle_links;
|
||||||
|
|
||||||
struct gb_protocol *protocol;
|
struct gb_protocol *protocol;
|
||||||
|
u8 protocol_id;
|
||||||
|
u8 major;
|
||||||
|
u8 minor;
|
||||||
|
|
||||||
enum gb_connection_state state;
|
enum gb_connection_state state;
|
||||||
|
|
||||||
|
@ -58,4 +61,6 @@ void greybus_data_rcvd(struct greybus_host_device *hd, u16 cport_id,
|
||||||
__printf(2, 3)
|
__printf(2, 3)
|
||||||
void gb_connection_err(struct gb_connection *connection, const char *fmt, ...);
|
void gb_connection_err(struct gb_connection *connection, const char *fmt, ...);
|
||||||
|
|
||||||
|
void gb_connection_bind_protocol(struct gb_connection *connection);
|
||||||
|
|
||||||
#endif /* __CONNECTION_H */
|
#endif /* __CONNECTION_H */
|
||||||
|
|
|
@ -206,6 +206,9 @@ static void gb_operation_request_handle(struct gb_operation *operation)
|
||||||
{
|
{
|
||||||
struct gb_protocol *protocol = operation->connection->protocol;
|
struct gb_protocol *protocol = operation->connection->protocol;
|
||||||
|
|
||||||
|
if (!protocol)
|
||||||
|
return;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If the protocol has no incoming request handler, report
|
* If the protocol has no incoming request handler, report
|
||||||
* an error and mark the request bad.
|
* an error and mark the request bad.
|
||||||
|
|
|
@ -84,6 +84,12 @@ int gb_protocol_register(struct gb_protocol *protocol)
|
||||||
list_add_tail(&protocol->links, &existing->links);
|
list_add_tail(&protocol->links, &existing->links);
|
||||||
spin_unlock_irq(&gb_protocols_lock);
|
spin_unlock_irq(&gb_protocols_lock);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Go try to bind any unbound connections, as we have a
|
||||||
|
* new protocol in the system
|
||||||
|
*/
|
||||||
|
gb_bundle_bind_protocols();
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(gb_protocol_register);
|
EXPORT_SYMBOL_GPL(gb_protocol_register);
|
||||||
|
|
Loading…
Reference in a new issue