From 177404bd20fdabd77d04ad818d56ab34150fff4c Mon Sep 17 00:00:00 2001 From: Alex Elder Date: Fri, 3 Oct 2014 14:14:24 -0500 Subject: [PATCH] greybus: use ida for cport id allocation The ida mechanism for allocating ids may be overkill but it works. Don't preallocate the id 0 for control. That should be done when initializing connections based on the manifest anyway. Signed-off-by: Alex Elder Signed-off-by: Greg Kroah-Hartman --- drivers/staging/greybus/connection.c | 40 ++++++++++++++++++-- drivers/staging/greybus/core.c | 71 +----------------------------------- drivers/staging/greybus/greybus.h | 6 +-- 3 files changed, 40 insertions(+), 77 deletions(-) diff --git a/drivers/staging/greybus/connection.c b/drivers/staging/greybus/connection.c index 806eb8c..c50472d 100644 --- a/drivers/staging/greybus/connection.c +++ b/drivers/staging/greybus/connection.c @@ -14,6 +14,39 @@ static DEFINE_SPINLOCK(gb_connections_lock); /* + * Allocate an available CPort Id for use for the host side of the + * given connection. The lowest-available id is returned, so the + * first call is guaranteed to allocate CPort Id 0. + * + * Assigns the connection's hd_cport_id and returns true if successful. + * Returns false otherwise. + */ +static bool hd_connection_hd_cport_id_alloc(struct gb_connection *connection) +{ + struct ida *ida = &connection->hd->cport_id_map; + int id; + + id = ida_simple_get(ida, 0, HOST_DEV_CPORT_ID_MAX, GFP_KERNEL); + if (id < 0) + return false; + + connection->hd_cport_id = (u16)id; + + return true; +} + +/* + * Free a previously-allocated CPort Id on the given host device. + */ +static void hd_connection_hd_cport_id_free(struct gb_connection *connection) +{ + struct ida *ida = &connection->hd->cport_id_map; + + ida_simple_remove(ida, connection->hd_cport_id); + connection->hd_cport_id = CPORT_ID_BAD; +} + +/* * Set up a Greybus connection, representing the bidirectional link * between a CPort on a (local) Greybus host device and a CPort on * another Greybus module. @@ -35,8 +68,9 @@ struct gb_connection *gb_connection_create(struct gb_interface *interface, return NULL; hd = interface->gmod->hd; - connection->hd_cport_id = greybus_hd_cport_id_alloc(hd); - if (connection->hd_cport_id == CPORT_ID_BAD) { + connection->hd = hd; /* XXX refcount? */ + if (!hd_connection_hd_cport_id_alloc(connection)) { + /* kref_put(connection->hd); */ kfree(connection); return NULL; } @@ -72,7 +106,7 @@ void gb_connection_destroy(struct gb_connection *connection) list_del(&connection->interface_links); spin_unlock_irq(&gb_connections_lock); - greybus_hd_cport_id_free(connection->hd, connection->hd_cport_id); + hd_connection_hd_cport_id_free(connection); /* kref_put(connection->interface); */ /* kref_put(connection->hd); */ kfree(connection); diff --git a/drivers/staging/greybus/core.c b/drivers/staging/greybus/core.c index 16100e7..40c8996 100644 --- a/drivers/staging/greybus/core.c +++ b/drivers/staging/greybus/core.c @@ -282,69 +282,6 @@ void greybus_remove_device(struct gb_module *gmod) static DEFINE_MUTEX(hd_mutex); -/* - * Allocate an available CPort Id for use on the given host device. - * Returns the CPort Id, or CPORT_ID_BAD of none remain. - * - * The lowest-available id is returned, so the first call is - * guaranteed to allocate CPort Id 0. - */ -u16 greybus_hd_cport_id_alloc(struct greybus_host_device *hd) -{ - unsigned long cport_id; - - /* If none left, return BAD */ - if (hd->cport_id_count == HOST_DEV_CPORT_ID_MAX) - return CPORT_ID_BAD; - - spin_lock_irq(&cport_id_map_lock); - cport_id = find_next_zero_bit(hd->cport_id_map, HOST_DEV_CPORT_ID_MAX, - hd->cport_id_next_free); - if (cport_id < HOST_DEV_CPORT_ID_MAX) { - hd->cport_id_next_free = cport_id + 1; /* Success */ - hd->cport_id_count++; - } else { - /* Lost a race for the last one */ - if (hd->cport_id_count != HOST_DEV_CPORT_ID_MAX) { - pr_err("bad cport_id_count in alloc"); - hd->cport_id_count = HOST_DEV_CPORT_ID_MAX; - } - cport_id = CPORT_ID_BAD; - } - spin_unlock_irq(&cport_id_map_lock); - - return cport_id; -} - -/* - * Free a previously-allocated CPort Id on the given host device. - */ -void greybus_hd_cport_id_free(struct greybus_host_device *hd, u16 cport_id) -{ - if (cport_id >= HOST_DEV_CPORT_ID_MAX) { - pr_err("bad cport_id %hu\n", cport_id); - return; - } - if (!hd->cport_id_count) { - pr_err("too many cport_id frees\n"); - return; - } - - spin_lock_irq(&cport_id_map_lock); - if (test_and_clear_bit(cport_id, hd->cport_id_map)) { - if (hd->cport_id_count) { - hd->cport_id_count--; - if (cport_id < hd->cport_id_next_free) - hd->cport_id_next_free = cport_id; - } else { - pr_err("bad cport_id_count in free"); - } - } else { - pr_err("duplicate cport_id %hu free\n", cport_id); - } - spin_unlock_irq(&cport_id_map_lock); -} - static void free_hd(struct kref *kref) { struct greybus_host_device *hd; @@ -368,13 +305,7 @@ struct greybus_host_device *greybus_create_hd(struct greybus_host_driver *driver hd->driver = driver; INIT_LIST_HEAD(&hd->modules); INIT_LIST_HEAD(&hd->connections); - - /* Pre-allocate CPort 0 for control stuff. XXX */ - if (greybus_hd_cport_id_alloc(hd) != 0) { - pr_err("couldn't allocate cport 0\n"); - kfree(hd); - return NULL; - } + ida_init(&hd->cport_id_map); return hd; } diff --git a/drivers/staging/greybus/greybus.h b/drivers/staging/greybus/greybus.h index 460ace5..4404d93 100644 --- a/drivers/staging/greybus/greybus.h +++ b/drivers/staging/greybus/greybus.h @@ -17,6 +17,7 @@ #include #include #include +#include #include "kernel_ver.h" #include "greybus_id.h" @@ -194,7 +195,7 @@ struct greybus_host_device { struct list_head modules; struct list_head connections; - DECLARE_BITMAP(cport_id_map, HOST_DEV_CPORT_ID_MAX); + struct ida cport_id_map; u16 cport_id_count; /* How many have been allocated */ u16 cport_id_next_free; /* Where to start checking anyway */ @@ -202,9 +203,6 @@ struct greybus_host_device { unsigned long hd_priv[0] __attribute__ ((aligned(sizeof(s64)))); }; -u16 greybus_hd_cport_id_alloc(struct greybus_host_device *hd); -void greybus_hd_cport_id_free(struct greybus_host_device *hd, u16 cport_id); - struct greybus_host_device *greybus_create_hd(struct greybus_host_driver *host_driver, struct device *parent); void greybus_remove_hd(struct greybus_host_device *hd); -- 2.7.4