mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-10-02 07:04:24 +00:00
greybus: add bg_hd_connection_find()
Add a function that looks up a connection given the host device pointer an the host cport id. This will be used to determine which connection an incoming message is associated with. Replace the list tracking host device connections with a red-black tree so lookup can scale and be done quickly. Signed-off-by: Alex Elder <elder@linaro.org> Signed-off-by: Greg Kroah-Hartman <greg@kroah.com>
This commit is contained in:
parent
369fb83249
commit
ee9ebe4d0b
4 changed files with 58 additions and 5 deletions
|
@ -13,6 +13,56 @@
|
||||||
|
|
||||||
static DEFINE_SPINLOCK(gb_connections_lock);
|
static DEFINE_SPINLOCK(gb_connections_lock);
|
||||||
|
|
||||||
|
static void _gb_hd_connection_insert(struct greybus_host_device *hd,
|
||||||
|
struct gb_connection *connection)
|
||||||
|
{
|
||||||
|
struct rb_root *root = &hd->connections;
|
||||||
|
struct rb_node *node = &connection->hd_node;
|
||||||
|
struct rb_node **link = &root->rb_node;
|
||||||
|
struct rb_node *above = NULL;
|
||||||
|
u16 cport_id = connection->hd_cport_id;
|
||||||
|
|
||||||
|
while (*link) {
|
||||||
|
struct gb_connection *connection;
|
||||||
|
|
||||||
|
above = *link;
|
||||||
|
connection = rb_entry(above, struct gb_connection, hd_node);
|
||||||
|
if (connection->hd_cport_id > cport_id)
|
||||||
|
link = &above->rb_left;
|
||||||
|
else if (connection->hd_cport_id < cport_id)
|
||||||
|
link = &above->rb_right;
|
||||||
|
}
|
||||||
|
rb_link_node(node, above, link);
|
||||||
|
rb_insert_color(node, root);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void _gb_hd_connection_remove(struct gb_connection *connection)
|
||||||
|
{
|
||||||
|
rb_erase(&connection->hd_node, &connection->hd->connections);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct gb_connection *gb_hd_connection_find(struct greybus_host_device *hd,
|
||||||
|
u16 cport_id)
|
||||||
|
{
|
||||||
|
struct gb_connection *connection = NULL;
|
||||||
|
struct rb_node *node;
|
||||||
|
|
||||||
|
spin_lock_irq(&gb_connections_lock);
|
||||||
|
node = hd->connections.rb_node;
|
||||||
|
while (node) {
|
||||||
|
connection = rb_entry(node, struct gb_connection, hd_node);
|
||||||
|
if (connection->hd_cport_id > cport_id)
|
||||||
|
node = node->rb_left;
|
||||||
|
else if (connection->hd_cport_id < cport_id)
|
||||||
|
node = node->rb_right;
|
||||||
|
else
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
spin_unlock_irq(&gb_connections_lock);
|
||||||
|
|
||||||
|
return connection;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Allocate an available CPort Id for use for the host side of the
|
* Allocate an available CPort Id for use for the host side of the
|
||||||
* given connection. The lowest-available id is returned, so the
|
* given connection. The lowest-available id is returned, so the
|
||||||
|
@ -80,7 +130,7 @@ struct gb_connection *gb_connection_create(struct gb_interface *interface,
|
||||||
connection->protocol = protocol;
|
connection->protocol = protocol;
|
||||||
|
|
||||||
spin_lock_irq(&gb_connections_lock);
|
spin_lock_irq(&gb_connections_lock);
|
||||||
list_add_tail(&connection->hd_links, &hd->connections);
|
_gb_hd_connection_insert(hd, connection);
|
||||||
list_add_tail(&connection->interface_links, &interface->connections);
|
list_add_tail(&connection->interface_links, &interface->connections);
|
||||||
spin_unlock_irq(&gb_connections_lock);
|
spin_unlock_irq(&gb_connections_lock);
|
||||||
|
|
||||||
|
@ -102,8 +152,8 @@ void gb_connection_destroy(struct gb_connection *connection)
|
||||||
WARN_ON(!list_empty(&connection->operations));
|
WARN_ON(!list_empty(&connection->operations));
|
||||||
|
|
||||||
spin_lock_irq(&gb_connections_lock);
|
spin_lock_irq(&gb_connections_lock);
|
||||||
list_del(&connection->hd_links);
|
|
||||||
list_del(&connection->interface_links);
|
list_del(&connection->interface_links);
|
||||||
|
_gb_hd_connection_remove(connection);
|
||||||
spin_unlock_irq(&gb_connections_lock);
|
spin_unlock_irq(&gb_connections_lock);
|
||||||
|
|
||||||
gb_connection_hd_cport_id_free(connection);
|
gb_connection_hd_cport_id_free(connection);
|
||||||
|
|
|
@ -19,7 +19,7 @@ struct gb_connection {
|
||||||
u16 hd_cport_id;
|
u16 hd_cport_id;
|
||||||
u16 interface_cport_id;
|
u16 interface_cport_id;
|
||||||
|
|
||||||
struct list_head hd_links;
|
struct rb_node hd_node;
|
||||||
struct list_head interface_links;
|
struct list_head interface_links;
|
||||||
enum greybus_protocol protocol;
|
enum greybus_protocol protocol;
|
||||||
|
|
||||||
|
@ -33,6 +33,9 @@ struct gb_connection *gb_connection_create(struct gb_interface *interface,
|
||||||
u16 cport_id, enum greybus_protocol protocol);
|
u16 cport_id, enum greybus_protocol protocol);
|
||||||
void gb_connection_destroy(struct gb_connection *connection);
|
void gb_connection_destroy(struct gb_connection *connection);
|
||||||
|
|
||||||
|
struct gb_connection *gb_hd_connection_find(struct greybus_host_device *hd,
|
||||||
|
u16 cport_id);
|
||||||
|
|
||||||
u16 gb_connection_op_id(struct gb_connection *connection);
|
u16 gb_connection_op_id(struct gb_connection *connection);
|
||||||
|
|
||||||
__printf(2, 3)
|
__printf(2, 3)
|
||||||
|
|
|
@ -311,7 +311,7 @@ struct greybus_host_device *greybus_create_hd(struct greybus_host_driver *driver
|
||||||
hd->parent = parent;
|
hd->parent = parent;
|
||||||
hd->driver = driver;
|
hd->driver = driver;
|
||||||
INIT_LIST_HEAD(&hd->modules);
|
INIT_LIST_HEAD(&hd->modules);
|
||||||
INIT_LIST_HEAD(&hd->connections);
|
hd->connections = RB_ROOT;
|
||||||
ida_init(&hd->cport_id_map);
|
ida_init(&hd->cport_id_map);
|
||||||
|
|
||||||
return hd;
|
return hd;
|
||||||
|
|
|
@ -187,7 +187,7 @@ struct greybus_host_device {
|
||||||
const struct greybus_host_driver *driver;
|
const struct greybus_host_driver *driver;
|
||||||
|
|
||||||
struct list_head modules;
|
struct list_head modules;
|
||||||
struct list_head connections;
|
struct rb_root connections;
|
||||||
struct ida cport_id_map;
|
struct ida cport_id_map;
|
||||||
|
|
||||||
/* Private data for the host driver */
|
/* Private data for the host driver */
|
||||||
|
|
Loading…
Reference in a new issue