From: Viresh Kumar <viresh.kumar@linaro.org>
Date: Sun, 7 Jun 2015 03:43:15 +0000 (+0530)
Subject: greybus: Generate greybus wide unique ids for endo devices
X-Git-Url: http://git.maquefel.me/?a=commitdiff_plain;h=4a0418700871936cddec3a2b3c5a029ec0b2d6a3;p=linux.git

greybus: Generate greybus wide unique ids for endo devices

Currently we name the endo device as "endo". And it shows up with the
same name in sysfs directory: /sys/bus/greybus/devices/.

But each device in kernel should be represented by a unique id in
kernel, and "endo" isn't unique.

Lets generate unique ids for endo devices. The ida mechanism for
allocating ids may be overkill but it works.

Reviewed-by: Alex Elder <elder@linaro.org>
Signed-off-by: Viresh Kumar <viresh.kumar@linaro.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@google.com>
---

diff --git a/drivers/staging/greybus/core.c b/drivers/staging/greybus/core.c
index 0a24822ac4ab3..9bbbf374c8c71 100644
--- a/drivers/staging/greybus/core.c
+++ b/drivers/staging/greybus/core.c
@@ -18,6 +18,8 @@
 
 #include "greybus.h"
 
+extern struct ida greybus_endo_id_map;
+
 /* Allow greybus to be disabled at boot if needed */
 static bool nogreybus;
 #ifdef MODULE
@@ -263,6 +265,8 @@ static int __init gb_init(void)
 		goto error_bus;
 	}
 
+	ida_init(&greybus_endo_id_map);
+
 	retval = gb_ap_init();
 	if (retval) {
 		pr_err("gb_ap_init failed\n");
diff --git a/drivers/staging/greybus/endo.c b/drivers/staging/greybus/endo.c
index 4f9ae4b2a8e3d..b89b14f59fb23 100644
--- a/drivers/staging/greybus/endo.c
+++ b/drivers/staging/greybus/endo.c
@@ -43,6 +43,8 @@
 #define max_endo_interface_id(endo_layout) \
 		(4 + ((endo_layout)->max_ribs + 1) * 2)
 
+struct ida greybus_endo_id_map;
+
 /* endo sysfs attributes */
 static ssize_t serial_number_show(struct device *dev,
 				struct device_attribute *attr, char *buf)
@@ -432,18 +434,51 @@ static int create_modules(struct gb_endo *endo)
 	return 0;
 }
 
+/*
+ * Allocate an available Id to uniquely identify the endo device. The lowest
+ * available id is returned, so the first call is guaranteed to allocate endo Id
+ * 0.
+ *
+ * Assigns the endo's id and returns 0 if successful.
+ * Returns error otherwise.
+ */
+static int gb_endo_id_alloc(struct gb_endo *endo)
+{
+	int id;
+
+	id = ida_simple_get(&greybus_endo_id_map, 0, 0, GFP_ATOMIC);
+	if (id < 0)
+		return id;
+
+	endo->dev_id = (u16)id;
+
+	return 0;
+}
+
+/*
+ * Free a previously-allocated Endo Id.
+ */
+static void gb_endo_id_free(struct gb_endo *endo)
+{
+	ida_simple_remove(&greybus_endo_id_map, endo->dev_id);
+}
+
 static int gb_endo_register(struct greybus_host_device *hd,
 			    struct gb_endo *endo)
 {
 	int retval;
 
+	retval = gb_endo_id_alloc(endo);
+	if (retval)
+		return retval;
+
 	endo->dev.parent = hd->parent;
-	endo->dev.init_name = "endo";
 	endo->dev.bus = &greybus_bus_type;
 	endo->dev.type = &greybus_endo_type;
 	endo->dev.groups = endo_groups;
 	endo->dev.dma_mask = hd->parent->dma_mask;
 	device_initialize(&endo->dev);
+	dev_set_name(&endo->dev, "endo%hu", endo->dev_id);
 
 	// FIXME
 	// Get the version and serial number from the SVC, right now we are
@@ -456,6 +491,7 @@ static int gb_endo_register(struct greybus_host_device *hd,
 		dev_err(hd->parent, "failed to add endo device of id 0x%04x\n",
 			endo->id);
 		put_device(&endo->dev);
+		gb_endo_id_free(endo);
 	}
 
 	return retval;
@@ -511,6 +547,7 @@ void gb_endo_remove(struct gb_endo *endo)
 	/* remove all modules for this endo */
 	gb_module_remove_all(endo);
 
+	gb_endo_id_free(endo);
 	device_unregister(&endo->dev);
 }
 
diff --git a/drivers/staging/greybus/endo.h b/drivers/staging/greybus/endo.h
index e211fb7d53bc2..2547b63e59bb1 100644
--- a/drivers/staging/greybus/endo.h
+++ b/drivers/staging/greybus/endo.h
@@ -40,6 +40,7 @@ struct gb_endo {
 	struct device dev;
 	struct endo_layout layout;
 	struct gb_svc_info svc_info;
+	u16 dev_id;
 	u16 id;
 	u8 ap_intf_id;
 };