From 90808738fd242ef2533e86f2f481bebe8a7aa11b Mon Sep 17 00:00:00 2001
From: Mark Brown <broonie@linaro.org>
Date: Wed, 13 Nov 2013 23:44:15 +0000
Subject: spi: Factor validation and initialisation of messages outside lock

Currently we do a bunch of per-message validation and initialisation in
__spi_async() which is called with the bus lock held. Since none of this
validation depends on the current bus status there's no need to hold the
lock to do it so split it out into a separate __spi_validate() function
which is called prior to taking the bus lock.

This could be slightly neater but keep things simple for now to show the
code motion clearly.

Based on observations from Martin Sperl.

Signed-off-by: Mark Brown <broonie@linaro.org>
---
 drivers/spi/spi.c | 26 +++++++++++++++++++++-----
 1 file changed, 21 insertions(+), 5 deletions(-)

(limited to 'drivers/spi/spi.c')

diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c
index 18cc625d887f..857ee8c407b1 100644
--- a/drivers/spi/spi.c
+++ b/drivers/spi/spi.c
@@ -1596,15 +1596,11 @@ int spi_setup(struct spi_device *spi)
 }
 EXPORT_SYMBOL_GPL(spi_setup);
 
-static int __spi_async(struct spi_device *spi, struct spi_message *message)
+static int __spi_validate(struct spi_device *spi, struct spi_message *message)
 {
 	struct spi_master *master = spi->master;
 	struct spi_transfer *xfer;
 
-	message->spi = spi;
-
-	trace_spi_message_submit(message);
-
 	if (list_empty(&message->transfers))
 		return -EINVAL;
 	if (!message->complete)
@@ -1705,6 +1701,18 @@ static int __spi_async(struct spi_device *spi, struct spi_message *message)
 	}
 
 	message->status = -EINPROGRESS;
+
+	return 0;
+}
+
+static int __spi_async(struct spi_device *spi, struct spi_message *message)
+{
+	struct spi_master *master = spi->master;
+
+	message->spi = spi;
+
+	trace_spi_message_submit(message);
+
 	return master->transfer(spi, message);
 }
 
@@ -1743,6 +1751,10 @@ int spi_async(struct spi_device *spi, struct spi_message *message)
 	int ret;
 	unsigned long flags;
 
+	ret = __spi_validate(spi, message);
+	if (ret != 0)
+		return ret;
+
 	spin_lock_irqsave(&master->bus_lock_spinlock, flags);
 
 	if (master->bus_lock_flag)
@@ -1791,6 +1803,10 @@ int spi_async_locked(struct spi_device *spi, struct spi_message *message)
 	int ret;
 	unsigned long flags;
 
+	ret = __spi_validate(spi, message);
+	if (ret != 0)
+		return ret;
+
 	spin_lock_irqsave(&master->bus_lock_spinlock, flags);
 
 	ret = __spi_async(spi, message);
-- 
cgit v1.2.3


From 368ca4e0c75612c0a4d6bbcef7efb944604340c2 Mon Sep 17 00:00:00 2001
From: Trent Piepho <tpiepho@gmail.com>
Date: Thu, 26 Dec 2013 21:51:06 -0800
Subject: spi: Eliminate 3WIRE spi_transfer check

Checking for SPI_3WIRE isn't needed.  spi_setup() already prevents 3WIRE
mode from being combined with DUAL or QUAD mode support.  So there is no
need to differentiate between a single bit device with SPI_3WIRE set and
one with without.  It doesn't change the allowed bit widths.

Signed-off-by: Trent Piepho <tpiepho@gmail.com>
Signed-off-by: Mark Brown <broonie@linaro.org>
---
 drivers/spi/spi.c | 6 ------
 1 file changed, 6 deletions(-)

(limited to 'drivers/spi/spi.c')

diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c
index 857ee8c407b1..2cd9fdc9c7f9 100644
--- a/drivers/spi/spi.c
+++ b/drivers/spi/spi.c
@@ -1678,9 +1678,6 @@ static int __spi_validate(struct spi_device *spi, struct spi_message *message)
 			if ((xfer->tx_nbits == SPI_NBITS_QUAD) &&
 				!(spi->mode & SPI_TX_QUAD))
 				return -EINVAL;
-			if ((spi->mode & SPI_3WIRE) &&
-				(xfer->tx_nbits != SPI_NBITS_SINGLE))
-				return -EINVAL;
 		}
 		/* check transfer rx_nbits */
 		if (xfer->rx_buf) {
@@ -1694,9 +1691,6 @@ static int __spi_validate(struct spi_device *spi, struct spi_message *message)
 			if ((xfer->rx_nbits == SPI_NBITS_QUAD) &&
 				!(spi->mode & SPI_RX_QUAD))
 				return -EINVAL;
-			if ((spi->mode & SPI_3WIRE) &&
-				(xfer->rx_nbits != SPI_NBITS_SINGLE))
-				return -EINVAL;
 		}
 	}
 
-- 
cgit v1.2.3


From 1cfd97f93e36b3f8b5d2a26147aaccae0c847a9c Mon Sep 17 00:00:00 2001
From: Axel Lin <axel.lin@ingics.com>
Date: Thu, 2 Jan 2014 15:16:40 +0800
Subject: spi: core: Use list_first_entry_or_null() instead of open-coded

Use list_first_entry_or_null() to save a few lines.

Signed-off-by: Axel Lin <axel.lin@ingics.com>
Signed-off-by: Mark Brown <broonie@linaro.org>
---
 drivers/spi/spi.c | 7 ++-----
 1 file changed, 2 insertions(+), 5 deletions(-)

(limited to 'drivers/spi/spi.c')

diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c
index 2cd9fdc9c7f9..401cd66770f9 100644
--- a/drivers/spi/spi.c
+++ b/drivers/spi/spi.c
@@ -791,11 +791,8 @@ struct spi_message *spi_get_next_queued_message(struct spi_master *master)
 
 	/* get a pointer to the next message, if any */
 	spin_lock_irqsave(&master->queue_lock, flags);
-	if (list_empty(&master->queue))
-		next = NULL;
-	else
-		next = list_entry(master->queue.next,
-				  struct spi_message, queue);
+	next = list_first_entry_or_null(&master->queue, struct spi_message,
+					queue);
 	spin_unlock_irqrestore(&master->queue_lock, flags);
 
 	return next;
-- 
cgit v1.2.3


From e120cc0dcf2880a4c5c0a6cb27b655600a1cfa1d Mon Sep 17 00:00:00 2001
From: Daniel Santos <daniel.santos@pobox.com>
Date: Sun, 5 Jan 2014 17:39:26 -0600
Subject: spidev: fix hang when transfer_one_message fails

This corrects a problem in spi_pump_messages() that leads to an spi
message hanging forever when a call to transfer_one_message() fails.
This failure occurs in my MCP2210 driver when the cs_change bit is set
on the last transfer in a message, an operation which the hardware does
not support.

Rationale
Since the transfer_one_message() returns an int, we must presume that it
may fail.  If transfer_one_message() should never fail, it should return
void.  Thus, calls to transfer_one_message() should properly manage a
failure.

Fixes: ffbbdd21329f3 (spi: create a message queueing infrastructure)
Signed-off-by: Daniel Santos <daniel.santos@pobox.com>
Signed-off-by: Mark Brown <broonie@linaro.org>
Cc: stable@vger.kernel.org
---
 drivers/spi/spi.c | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

(limited to 'drivers/spi/spi.c')

diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c
index 18cc625d887f..0e215237383b 100644
--- a/drivers/spi/spi.c
+++ b/drivers/spi/spi.c
@@ -735,7 +735,9 @@ static void spi_pump_messages(struct kthread_work *work)
 	ret = master->transfer_one_message(master, master->cur_msg);
 	if (ret) {
 		dev_err(&master->dev,
-			"failed to transfer one message from queue\n");
+			"failed to transfer one message from queue: %d\n", ret);
+		master->cur_msg->status = ret;
+		spi_finalize_current_message(master);
 		return;
 	}
 }
-- 
cgit v1.2.3


From a89e2d2754246645959f1a2f91e37e9b367bfd36 Mon Sep 17 00:00:00 2001
From: Axel Lin <axel.lin@ingics.com>
Date: Thu, 9 Jan 2014 16:03:58 +0800
Subject: spi: core: Use list_first_entry to extract head of queue

For slightly better readability.

Signed-off-by: Axel Lin <axel.lin@ingics.com>
Signed-off-by: Mark Brown <broonie@linaro.org>
---
 drivers/spi/spi.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

(limited to 'drivers/spi/spi.c')

diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c
index 401cd66770f9..36bfa7f820a6 100644
--- a/drivers/spi/spi.c
+++ b/drivers/spi/spi.c
@@ -685,7 +685,7 @@ static void spi_pump_messages(struct kthread_work *work)
 	}
 	/* Extract head of queue */
 	master->cur_msg =
-	    list_entry(master->queue.next, struct spi_message, queue);
+		list_first_entry(&master->queue, struct spi_message, queue);
 
 	list_del_init(&master->cur_msg->queue);
 	if (master->busy)
-- 
cgit v1.2.3


From b6fb8d3a1f156c50a35f88b9b55f404034493938 Mon Sep 17 00:00:00 2001
From: Mika Westerberg <mika.westerberg@linux.intel.com>
Date: Thu, 9 Jan 2014 15:23:55 +0200
Subject: spi: Check conflicting CS based on spi->chip_select instead of device
 name

Commit e13ac47bec20 (spi: Use stable dev_name for ACPI enumerated SPI
slaves) changed the SPI device naming to be based on ACPI device name
instead of carrying bus number and chip select for devices enumerated
from ACPI namespace.

In case of a buggy BIOS that lists multiple SPI devices sharing the same
chip select (even though they should use different) the current code fails
to detect that and allows the devices to be added to the bus.

Fix this by walking through the bus and comparing spi->chip_select instead
of device name. This should work regardless what the device name will be in
future.

Signed-off-by: Mika Westerberg <mika.westerberg@linux.intel.com>
Acked-by: Jarkko Nikula <jarkko.nikula@linux.intel.com>
Signed-off-by: Mark Brown <broonie@linaro.org>
---
 drivers/spi/spi.c | 18 +++++++++++++-----
 1 file changed, 13 insertions(+), 5 deletions(-)

(limited to 'drivers/spi/spi.c')

diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c
index 0e215237383b..51e00c6436aa 100644
--- a/drivers/spi/spi.c
+++ b/drivers/spi/spi.c
@@ -370,6 +370,17 @@ static void spi_dev_set_name(struct spi_device *spi)
 		     spi->chip_select);
 }
 
+static int spi_dev_check(struct device *dev, void *data)
+{
+	struct spi_device *spi = to_spi_device(dev);
+	struct spi_device *new_spi = data;
+
+	if (spi->master == new_spi->master &&
+	    spi->chip_select == new_spi->chip_select)
+		return -EBUSY;
+	return 0;
+}
+
 /**
  * spi_add_device - Add spi_device allocated with spi_alloc_device
  * @spi: spi_device to register
@@ -384,7 +395,6 @@ int spi_add_device(struct spi_device *spi)
 	static DEFINE_MUTEX(spi_add_lock);
 	struct spi_master *master = spi->master;
 	struct device *dev = master->dev.parent;
-	struct device *d;
 	int status;
 
 	/* Chipselects are numbered 0..max; validate. */
@@ -404,12 +414,10 @@ int spi_add_device(struct spi_device *spi)
 	 */
 	mutex_lock(&spi_add_lock);
 
-	d = bus_find_device_by_name(&spi_bus_type, NULL, dev_name(&spi->dev));
-	if (d != NULL) {
+	status = bus_for_each_dev(&spi_bus_type, NULL, spi, spi_dev_check);
+	if (status) {
 		dev_err(dev, "chipselect %d already in use\n",
 				spi->chip_select);
-		put_device(d);
-		status = -EBUSY;
 		goto done;
 	}
 
-- 
cgit v1.2.3


From 1afd9989a6a2561183be82e420d4d2f3889b7ee7 Mon Sep 17 00:00:00 2001
From: Geert Uytterhoeven <geert+renesas@linux-m68k.org>
Date: Sun, 12 Jan 2014 14:00:29 +0100
Subject: spi: core: Improve tx/rx_nbits check comments

  - Rephrase the comments about tx/rx_nbits validity checks,
  - Remove the stale comment about SPI_3WIRE (the code it refers to was
    removed in commit 368ca4e0c75612c0a4d6bbcef7efb944604340c2 ("spi:
    Eliminate 3WIRE spi_transfer check")).

Signed-off-by: Geert Uytterhoeven <geert+renesas@linux-m68k.org>
Signed-off-by: Mark Brown <broonie@linaro.org>
---
 drivers/spi/spi.c | 5 ++---
 1 file changed, 2 insertions(+), 3 deletions(-)

(limited to 'drivers/spi/spi.c')

diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c
index 36bfa7f820a6..9f26797e4319 100644
--- a/drivers/spi/spi.c
+++ b/drivers/spi/spi.c
@@ -1660,9 +1660,8 @@ static int __spi_validate(struct spi_device *spi, struct spi_message *message)
 		if (xfer->rx_buf && !xfer->rx_nbits)
 			xfer->rx_nbits = SPI_NBITS_SINGLE;
 		/* check transfer tx/rx_nbits:
-		 * 1. keep the value is not out of single, dual and quad
-		 * 2. keep tx/rx_nbits is contained by mode in spi_device
-		 * 3. if SPI_3WIRE, tx/rx_nbits should be in single
+		 * 1. check the value matches one of single, dual and quad
+		 * 2. check tx/rx_nbits match the mode in spi_device
 		 */
 		if (xfer->tx_buf) {
 			if (xfer->tx_nbits != SPI_NBITS_SINGLE &&
-- 
cgit v1.2.3


From 9e8f4882cc49205a688b616c1b6c17bade10587f Mon Sep 17 00:00:00 2001
From: Geert Uytterhoeven <geert+renesas@linux-m68k.org>
Date: Tue, 21 Jan 2014 16:10:05 +0100
Subject: spi: Spelling s/finised/finished/

Signed-off-by: Geert Uytterhoeven <geert+renesas@linux-m68k.org>
Signed-off-by: Mark Brown <broonie@linaro.org>
---
 drivers/spi/spi.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

(limited to 'drivers/spi/spi.c')

diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c
index 51e00c6436aa..56b41099b40c 100644
--- a/drivers/spi/spi.c
+++ b/drivers/spi/spi.c
@@ -640,7 +640,7 @@ out:
  *
  * Called by SPI drivers using the core transfer_one_message()
  * implementation to notify it that the current interrupt driven
- * transfer has finised and the next one may be scheduled.
+ * transfer has finished and the next one may be scheduled.
  */
 void spi_finalize_current_transfer(struct spi_master *master)
 {
-- 
cgit v1.2.3


From 13a4279880229240af38486611c94587492b24d3 Mon Sep 17 00:00:00 2001
From: Axel Lin <axel.lin@ingics.com>
Date: Sat, 18 Jan 2014 22:05:22 +0800
Subject: spi: core: Fix transfer failure when master->transfer_one returns
 positive value

master->transfer_one returns positive value is not a error.
So set ret to 0 when master->transfer_one returns positive value.
Otherwise, I hit "spi_master spi0: failed to transfer one message from queue"
error when my transfer_one callback returns 1.

Signed-off-by: Axel Lin <axel.lin@ingics.com>
Signed-off-by: Mark Brown <broonie@linaro.org>
---
 drivers/spi/spi.c | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

(limited to 'drivers/spi/spi.c')

diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c
index 56b41099b40c..8ed1aee13c6f 100644
--- a/drivers/spi/spi.c
+++ b/drivers/spi/spi.c
@@ -599,8 +599,10 @@ static int spi_transfer_one_message(struct spi_master *master,
 			goto out;
 		}
 
-		if (ret > 0)
+		if (ret > 0) {
+			ret = 0;
 			wait_for_completion(&master->xfer_completion);
+		}
 
 		trace_spi_transfer_stop(msg, xfer);
 
-- 
cgit v1.2.3