linux-spi.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: sunil.m@techveda.org
To: broonie@kernel.org
Cc: linux-spi@vger.kernel.org, linux-kernel@vger.kernel.org,
	karthik@techveda.org, Suniel Mahesh <sunil.m@techveda.org>
Subject: [PATCH] drivers: spi: Pick spi bus number from Linux idr or spi alias
Date: Thu,  3 Aug 2017 10:05:57 +0530	[thread overview]
Message-ID: <1501734957-20725-1-git-send-email-sunil.m@techveda.org> (raw)

From: Suniel Mahesh <sunil.m@techveda.org>

Modify existing code, for automatically picking the spi bus number based
on Linux idr scheme as mentioned in FIXME.
This patch does the following:
(a) Remove the now unnecessary code which was allocating bus numbers using
ATOMIC_INIT and atomic_dec_return macro's.
(b) If we have an alias, pick the bus number from alias ID
(c) Convert to linux idr interface

Signed-off-by: Suniel Mahesh <sunil.m@techveda.org>
Signed-off-by: Karthik Tummala <karthik@techveda.org>
Tested-by: Karthik Tummala <karthik@techveda.org>
---
Note:
- Patch was compile tested and built(ARCH=arm) on next-20170802.
- Patch was hardware tested on AM335x (McSPI controller) with
  memory chips as slaves.
- Added spi aliases in aliases node, device tree and tested.
- No build/run-time issues reported.
---
 drivers/spi/spi.c | 71 +++++++++++++++++++++++++++++++++++++++++++------------
 1 file changed, 56 insertions(+), 15 deletions(-)

diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c
index ec69293..17bec04d 100644
--- a/drivers/spi/spi.c
+++ b/drivers/spi/spi.c
@@ -40,9 +40,13 @@
 #include <linux/ioport.h>
 #include <linux/acpi.h>
 #include <linux/highmem.h>
+#include <linux/idr.h>
 
 #define CREATE_TRACE_POINTS
 #include <trace/events/spi.h>
+#define SPI_DYN_FIRST_BUS_NUM 0
+
+static DEFINE_IDR(spi_master_idr);
 
 static void spidev_release(struct device *dev)
 {
@@ -420,6 +424,7 @@ struct boardinfo {
 /*
  * Used to protect add/del opertion for board_info list and
  * spi_controller list, and their matching process
+ * also used to protect object of type struct idr 
  */
 static DEFINE_MUTEX(board_lock);
 
@@ -2046,11 +2051,10 @@ static int of_spi_register_master(struct spi_controller *ctlr)
  */
 int spi_register_controller(struct spi_controller *ctlr)
 {
-	static atomic_t		dyn_bus_id = ATOMIC_INIT((1<<15) - 1);
 	struct device		*dev = ctlr->dev.parent;
 	struct boardinfo	*bi;
 	int			status = -ENODEV;
-	int			dynamic = 0;
+	int			id;
 
 	if (!dev)
 		return -ENODEV;
@@ -2066,17 +2070,29 @@ int spi_register_controller(struct spi_controller *ctlr)
 	 */
 	if (ctlr->num_chipselect == 0)
 		return -EINVAL;
-
-	if ((ctlr->bus_num < 0) && ctlr->dev.of_node)
-		ctlr->bus_num = of_alias_get_id(ctlr->dev.of_node, "spi");
-
-	/* convention:  dynamically assigned bus IDs count down from the max */
+	
+	/* allocate dynamic bus number using Linux idr */
+	if ((ctlr->bus_num < 0) && ctlr->dev.of_node) {
+		id = of_alias_get_id(ctlr->dev.of_node, "spi");
+		if (id >= 0) {
+			ctlr->bus_num = id;
+			mutex_lock(&board_lock);
+			id = idr_alloc(&spi_master_idr, ctlr, ctlr->bus_num,
+				       ctlr->bus_num + 1, GFP_KERNEL);
+			mutex_unlock(&board_lock);
+			if (WARN(id < 0, "couldn't get idr"))
+				return id == -ENOSPC ? -EBUSY : id;
+		}
+	}
 	if (ctlr->bus_num < 0) {
-		/* FIXME switch to an IDR based scheme, something like
-		 * I2C now uses, so we can't run out of "dynamic" IDs
-		 */
-		ctlr->bus_num = atomic_dec_return(&dyn_bus_id);
-		dynamic = 1;
+			mutex_lock(&board_lock);
+			id = idr_alloc(&spi_master_idr, ctlr,
+				       SPI_DYN_FIRST_BUS_NUM, 0, GFP_KERNEL);
+                        mutex_unlock(&board_lock);
+			if (WARN(id < 0, "couldn't get idr"))
+				return id;
+
+			ctlr->bus_num = id;
 	}
 
 	INIT_LIST_HEAD(&ctlr->queue);
@@ -2094,11 +2110,16 @@ int spi_register_controller(struct spi_controller *ctlr)
 	 */
 	dev_set_name(&ctlr->dev, "spi%u", ctlr->bus_num);
 	status = device_add(&ctlr->dev);
-	if (status < 0)
+	if (status < 0) {
+		/* free bus id */
+		mutex_lock(&board_lock);
+		idr_remove(&spi_master_idr, ctlr->bus_num);
+		mutex_unlock(&board_lock);
 		goto done;
-	dev_dbg(dev, "registered %s %s%s\n",
+	}
+	dev_dbg(dev, "registered %s %s\n",
 			spi_controller_is_slave(ctlr) ? "slave" : "master",
-			dev_name(&ctlr->dev), dynamic ? " (dynamic)" : "");
+			dev_name(&ctlr->dev));
 
 	/* If we're using a queued driver, start the queue */
 	if (ctlr->transfer)
@@ -2107,6 +2128,10 @@ int spi_register_controller(struct spi_controller *ctlr)
 		status = spi_controller_initialize_queue(ctlr);
 		if (status) {
 			device_del(&ctlr->dev);
+			/* free bus id */
+			mutex_lock(&board_lock);
+			idr_remove(&spi_master_idr, ctlr->bus_num);
+			mutex_unlock(&board_lock);
 			goto done;
 		}
 	}
@@ -2185,8 +2210,20 @@ static int __unregister(struct device *dev, void *null)
  */
 void spi_unregister_controller(struct spi_controller *ctlr)
 {
+	struct spi_controller *found;
 	int dummy;
 
+	/* First make sure that this controller was ever added */
+	mutex_lock(&board_lock);
+	found = idr_find(&spi_master_idr, ctlr->bus_num);
+	mutex_unlock(&board_lock);
+        if (found != ctlr) {
+                dev_dbg(&ctlr->dev, 
+			"attempting to delete unregistered controller [%s]\n",
+			dev_name(&ctlr->dev));
+                return;
+        }
+
 	if (ctlr->queued) {
 		if (spi_destroy_queue(ctlr))
 			dev_err(&ctlr->dev, "queue remove failed\n");
@@ -2198,6 +2235,10 @@ void spi_unregister_controller(struct spi_controller *ctlr)
 
 	dummy = device_for_each_child(&ctlr->dev, NULL, __unregister);
 	device_unregister(&ctlr->dev);
+	/* free bus id */
+	mutex_lock(&board_lock);
+	idr_remove(&spi_master_idr, ctlr->bus_num);
+	mutex_unlock(&board_lock);
 }
 EXPORT_SYMBOL_GPL(spi_unregister_controller);
 
-- 
1.9.1

                 reply	other threads:[~2017-08-03  4:35 UTC|newest]

Thread overview: [no followups] expand[flat|nested]  mbox.gz  Atom feed

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1501734957-20725-1-git-send-email-sunil.m@techveda.org \
    --to=sunil.m@techveda.org \
    --cc=broonie@kernel.org \
    --cc=karthik@techveda.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-spi@vger.kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).