diff --git a/drivers/staging/greybus/connection.c b/drivers/staging/greybus/connection.c index 53086126f961..449ae34bf531 100644 --- a/drivers/staging/greybus/connection.c +++ b/drivers/staging/greybus/connection.c @@ -13,6 +13,56 @@ 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 * 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; 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); spin_unlock_irq(&gb_connections_lock); @@ -102,8 +152,8 @@ void gb_connection_destroy(struct gb_connection *connection) WARN_ON(!list_empty(&connection->operations)); spin_lock_irq(&gb_connections_lock); - list_del(&connection->hd_links); list_del(&connection->interface_links); + _gb_hd_connection_remove(connection); spin_unlock_irq(&gb_connections_lock); gb_connection_hd_cport_id_free(connection); diff --git a/drivers/staging/greybus/connection.h b/drivers/staging/greybus/connection.h index 61e94357db3a..89d58e5707bc 100644 --- a/drivers/staging/greybus/connection.h +++ b/drivers/staging/greybus/connection.h @@ -19,7 +19,7 @@ struct gb_connection { u16 hd_cport_id; u16 interface_cport_id; - struct list_head hd_links; + struct rb_node hd_node; struct list_head interface_links; 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); 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); __printf(2, 3) diff --git a/drivers/staging/greybus/core.c b/drivers/staging/greybus/core.c index 41fb7caf0d8b..51d7e59362d5 100644 --- a/drivers/staging/greybus/core.c +++ b/drivers/staging/greybus/core.c @@ -311,7 +311,7 @@ struct greybus_host_device *greybus_create_hd(struct greybus_host_driver *driver hd->parent = parent; hd->driver = driver; INIT_LIST_HEAD(&hd->modules); - INIT_LIST_HEAD(&hd->connections); + hd->connections = RB_ROOT; ida_init(&hd->cport_id_map); return hd; diff --git a/drivers/staging/greybus/greybus.h b/drivers/staging/greybus/greybus.h index f4ca18aba2a6..ae7d32244c53 100644 --- a/drivers/staging/greybus/greybus.h +++ b/drivers/staging/greybus/greybus.h @@ -187,7 +187,7 @@ struct greybus_host_device { const struct greybus_host_driver *driver; struct list_head modules; - struct list_head connections; + struct rb_root connections; struct ida cport_id_map; /* Private data for the host driver */