All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH V2] spi: bcm2835: enabling polling mode for transfers shorter than 30us
@ 2015-04-06 17:16 kernel-TqfNSX0MhmxHKSADF0wUEw
       [not found] ` <1428340592-3196-1-git-send-email-kernel-TqfNSX0MhmxHKSADF0wUEw@public.gmane.org>
  0 siblings, 1 reply; 15+ messages in thread
From: kernel-TqfNSX0MhmxHKSADF0wUEw @ 2015-04-06 17:16 UTC (permalink / raw)
  To: Mark Brown, Stephen Warren, Lee Jones,
	linux-spi-u79uwXL29TY76Z2rM5mHXA,
	linux-rpi-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r
  Cc: Martin Sperl

From: Martin Sperl <kernel-TqfNSX0MhmxHKSADF0wUEw@public.gmane.org>

In cases of short transfer times the CPU is spending lots of time
in the interrupt handler and scheduler to reschedule the worker thread.

Measurements show that we have times where it takes 29.32us to between
the last clock change and the time that the worker-thread is running again
returning from wait_for_completion_timeout().

During this time the interrupt-handler is running calling complete()
and then also the scheduler is rescheduling the worker thread.

This time can vary depending on how much of the code is still in
CPU-caches, when there is a burst of spi transfers the subsequent delays
are in the order of 25us, so the value of 30us seems reasonable.

With polling the whole transfer of 4 bytes at 10MHz finishes after 6.16us
(CS down to up) with the real transfer (clock running) taking 3.56us.
So the efficiency has much improved and is also freeing CPU cycles,
reducing interrupts and context switches.

Because of the above 30us seems to be a reasonable limit for polling.

Signed-off-by: Martin Sperl <kernel-TqfNSX0MhmxHKSADF0wUEw@public.gmane.org>
---
 drivers/spi/spi-bcm2835.c |  112 ++++++++++++++++++++++++++++++++++-----------
 1 file changed, 86 insertions(+), 26 deletions(-)

Applies against: spi - for-next

Changelog:
[V1 -> V2]:
  * moved to separate handler functions for polling and interrupt driven
  * added some comments clarifying why we have 9 clocks/byte
  * fixed extra/redundant brackets

Tested with the following setup:
* native CS:
  * mcp2515
  * mmc_spi (patched to make it work on the RPI)
* gpio-CS:
  * mcp2515
  * enc28j60
* gpio-CS with spi-cs-pol:
  * fb_st7735r

diff --git a/drivers/spi/spi-bcm2835.c b/drivers/spi/spi-bcm2835.c
index 08e5406..88b808b 100644
--- a/drivers/spi/spi-bcm2835.c
+++ b/drivers/spi/spi-bcm2835.c
@@ -68,7 +68,8 @@
 #define BCM2835_SPI_CS_CS_10		0x00000002
 #define BCM2835_SPI_CS_CS_01		0x00000001

-#define BCM2835_SPI_TIMEOUT_MS	30000
+#define BCM2835_SPI_POLLING_LIMIT_US	30
+#define BCM2835_SPI_TIMEOUT_MS		30000
 #define BCM2835_SPI_MODE_BITS	(SPI_CPOL | SPI_CPHA | SPI_CS_HIGH \
 				| SPI_NO_CS | SPI_3WIRE)

@@ -156,12 +157,86 @@ static irqreturn_t bcm2835_spi_interrupt(int irq, void *dev_id)
 	return IRQ_HANDLED;
 }

+static int bcm2835_spi_transfer_one_poll(struct spi_master *master,
+					 struct spi_device *spi,
+					 struct spi_transfer *tfr,
+					 u32 cs,
+					 unsigned long xfer_time_us)
+{
+	struct bcm2835_spi *bs = spi_master_get_devdata(master);
+	unsigned long timeout = jiffies +
+		max(4 * xfer_time_us * HZ / 1000000, 2uL);
+
+	/* enable HW block without interrupts */
+	bcm2835_wr(bs, BCM2835_SPI_CS, cs | BCM2835_SPI_CS_TA);
+
+	/* set timeout to 4x the expected time, or 2 jiffies */
+	/* loop until finished the transfer */
+	while (bs->rx_len) {
+		/* read from fifo as much as possible */
+		bcm2835_rd_fifo(bs);
+		/* fill in tx fifo as much as possible */
+		bcm2835_wr_fifo(bs);
+		/* if we still expect some data after the read,
+		 * check for a possible timeout
+		 */
+		if (bs->rx_len && time_after(jiffies, timeout)) {
+			/* Transfer complete - reset SPI HW */
+			bcm2835_spi_reset_hw(master);
+			/* and return timeout */
+			return -ETIMEDOUT;
+		}
+	}
+
+	/* Transfer complete - reset SPI HW */
+	bcm2835_spi_reset_hw(master);
+	/* and return without waiting for completion */
+	return 0;
+}
+
+static int bcm2835_spi_transfer_one_irq(struct spi_master *master,
+					struct spi_device *spi,
+					struct spi_transfer *tfr,
+					u32 cs)
+{
+	struct bcm2835_spi *bs = spi_master_get_devdata(master);
+
+	/* fill in fifo if we have gpio-cs
+	 * note that there have been rare events where the native-CS
+	 * flapped for <1us which may change the behaviour
+	 * with gpio-cs this does not happen, so it is implemented
+	 * only for this case
+	 */
+	if (gpio_is_valid(spi->cs_gpio)) {
+		/* enable HW block, but without interrupts enabled
+		 * this would triggern an immediate interrupt
+		 */
+		bcm2835_wr(bs, BCM2835_SPI_CS,
+			   cs | BCM2835_SPI_CS_TA);
+		/* fill in tx fifo as much as possible */
+		bcm2835_wr_fifo(bs);
+	}
+
+	/*
+	 * Enable the HW block. This will immediately trigger a DONE (TX
+	 * empty) interrupt, upon which we will fill the TX FIFO with the
+	 * first TX bytes. Pre-filling the TX FIFO here to avoid the
+	 * interrupt doesn't work:-(
+	 */
+	cs |= BCM2835_SPI_CS_INTR | BCM2835_SPI_CS_INTD | BCM2835_SPI_CS_TA;
+	bcm2835_wr(bs, BCM2835_SPI_CS, cs);
+
+	/* signal that we need to wait for completion */
+	return 1;
+}
+
 static int bcm2835_spi_transfer_one(struct spi_master *master,
 				    struct spi_device *spi,
 				    struct spi_transfer *tfr)
 {
 	struct bcm2835_spi *bs = spi_master_get_devdata(master);
 	unsigned long spi_hz, clk_hz, cdiv;
+	unsigned long spi_used_hz, xfer_time_us;
 	u32 cs = bcm2835_rd(bs, BCM2835_SPI_CS);

 	/* set clock */
@@ -180,6 +255,7 @@ static int bcm2835_spi_transfer_one(struct spi_master *master,
 	} else {
 		cdiv = 0; /* 0 is the slowest we can go */
 	}
+	spi_used_hz = cdiv ? (clk_hz / cdiv) : (clk_hz / 65536);
 	bcm2835_wr(bs, BCM2835_SPI_CLK, cdiv);

 	/* handle all the modes */
@@ -203,33 +279,17 @@ static int bcm2835_spi_transfer_one(struct spi_master *master,
 	bs->tx_len = tfr->len;
 	bs->rx_len = tfr->len;

-	/* fill in fifo if we have gpio-cs
-	 * note that there have been rare events where the native-CS
-	 * flapped for <1us which may change the behaviour
-	 * with gpio-cs this does not happen, so it is implemented
-	 * only for this case
-	 */
-	if (gpio_is_valid(spi->cs_gpio)) {
-		/* enable HW block, but without interrupts enabled
-		 * this would triggern an immediate interrupt
-		 */
-		bcm2835_wr(bs, BCM2835_SPI_CS,
-			   cs | BCM2835_SPI_CS_TA);
-		/* fill in tx fifo as much as possible */
-		bcm2835_wr_fifo(bs);
-	}
+	/* calculate the estimated time in us the transfer runs */
+	xfer_time_us = tfr->len
+		* 9 /* clocks/byte - SPI-HW waits 1 clock after each byte */
+		* 1000000 / spi_used_hz;

-	/*
-	 * Enable the HW block. This will immediately trigger a DONE (TX
-	 * empty) interrupt, upon which we will fill the TX FIFO with the
-	 * first TX bytes. Pre-filling the TX FIFO here to avoid the
-	 * interrupt doesn't work:-(
-	 */
-	cs |= BCM2835_SPI_CS_INTR | BCM2835_SPI_CS_INTD | BCM2835_SPI_CS_TA;
-	bcm2835_wr(bs, BCM2835_SPI_CS, cs);
+	/* for short requests run polling*/
+	if (xfer_time_us <= BCM2835_SPI_POLLING_LIMIT_US)
+		return bcm2835_spi_transfer_one_poll(master, spi, tfr,
+						     cs, xfer_time_us);

-	/* signal that we need to wait for completion */
-	return 1;
+	return bcm2835_spi_transfer_one_irq(master, spi, tfr, cs);
 }

 static void bcm2835_spi_handle_err(struct spi_master *master,
--
1.7.10.4

--
To unsubscribe from this list: send the line "unsubscribe linux-spi" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply related	[flat|nested] 15+ messages in thread

* Re: [PATCH V2] spi: bcm2835: enabling polling mode for transfers shorter than 30us
       [not found] ` <1428340592-3196-1-git-send-email-kernel-TqfNSX0MhmxHKSADF0wUEw@public.gmane.org>
@ 2015-04-10 18:51   ` Mark Brown
       [not found]     ` <20150410185132.GU6023-GFdadSzt00ze9xe1eoZjHA@public.gmane.org>
  0 siblings, 1 reply; 15+ messages in thread
From: Mark Brown @ 2015-04-10 18:51 UTC (permalink / raw)
  To: kernel-TqfNSX0MhmxHKSADF0wUEw
  Cc: Stephen Warren, Lee Jones, linux-spi-u79uwXL29TY76Z2rM5mHXA,
	linux-rpi-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r

[-- Attachment #1: Type: text/plain, Size: 336 bytes --]

On Mon, Apr 06, 2015 at 05:16:30PM +0000, kernel-TqfNSX0MhmxHKSADF0wUEw@public.gmane.org wrote:
> From: Martin Sperl <kernel-TqfNSX0MhmxHKSADF0wUEw@public.gmane.org>
> 
> In cases of short transfer times the CPU is spending lots of time
> in the interrupt handler and scheduler to reschedule the worker thread.

Applied, thanks.

[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 473 bytes --]

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH V2] spi: bcm2835: enabling polling mode for transfers shorter than 30us
       [not found]     ` <20150410185132.GU6023-GFdadSzt00ze9xe1eoZjHA@public.gmane.org>
@ 2015-04-14 14:29       ` Martin Sperl
       [not found]         ` <F35B7C71-1917-40AE-BA42-CB3E63B877EF-TqfNSX0MhmxHKSADF0wUEw@public.gmane.org>
  0 siblings, 1 reply; 15+ messages in thread
From: Martin Sperl @ 2015-04-14 14:29 UTC (permalink / raw)
  To: Mark Brown
  Cc: Stephen Warren, Lee Jones, linux-spi-u79uwXL29TY76Z2rM5mHXA,
	linux-rpi-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r


> On 10.04.2015, at 20:51, Mark Brown <broonie-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org> wrote:
> 
> On Mon, Apr 06, 2015 at 05:16:30PM +0000, kernel-TqfNSX0MhmxHKSADF0wUEw@public.gmane.org wrote:
>> From: Martin Sperl <kernel-TqfNSX0MhmxHKSADF0wUEw@public.gmane.org>
>> 
>> In cases of short transfer times the CPU is spending lots of time
>> in the interrupt handler and scheduler to reschedule the worker thread.
> 
> Applied, thanks.

I have been running a heavy CAN-based spi load with the following parameters:
* about 3000 can messages/second received by 2 mcp2515 can controller
  (so a total of 6000 can-messages passing thru the system)
* each can message producing 3 SPI transfers with all of them running <30us
  which means that all of them run in polling mode of the spi-bcm2835.
* 10% user CPU
* 76% system CPU
* most time spent inside the interrupt handler for the mcp2515 which
  triggers spi_sync commands, so these mostly run locally
  see also the information from the kernel threads via ps:
root     26986  4.3  0.0      0     0 ?        S    12:54   0:23 [spi32762]
root     27091 37.0  0.0      0     0 ?        S    12:54   3:20 [irq/104-mcp251x]
root     27096 27.0  0.0      0     0 ?        S    12:54   2:26 [irq/105-mcp251x]
  so most of the time is spent in the threaded irq handlers of the mcp251x
* 17000 interrupts/s - 8000+ interrupts for USB + 
     1 interrupt per can-message per mcp2515 so about 6000)
  here the content of /proc/interrupts:
           CPU0
 27:     722456  ARMCTRL-level  35  timer
 33:   90007770  ARMCTRL-level  41  20980000.usb, dwc2_hsotg:usb1
 73:   18381921  ARMCTRL-level  81  20200000.gpio:bank0
 74:          0  ARMCTRL-level  82  20200000.gpio:bank1
 77:          0  ARMCTRL-level  85  20205000.i2c, 20804000.i2c
 78:          0  ARMCTRL-level  86  20204000.spi
 81:        791  ARMCTRL-level  89  uart-pl011
 86:      56425  ARMCTRL-level  94  mmc0
104:   17086956  pinctrl-bcm2835  16  mcp251x
105:   18300261  pinctrl-bcm2835  17  mcp251x
Err:          0
* 10000 to 13000 context switches/s

With nothing else happening on the system everything works fine and I
can receive 100M can messages without issues on both controllers (about 9 hours)

But if I start a compile of the kernel (or even just linking the kernel
modules) I get a stalled can driver and messages like this:

[ 7529.270495] mcp251x spi32763.0: SPI transfer failed: -110
[ 7529.270541] spi_master spi32763: failed to transfer one message from queue
[ 7529.270563] mcp251x spi32763.0: spi transfer failed: ret = -110

The last one is from the mcp251x driver, which subsequently does not
handle interrupts any longer.

I have some captures of the bus, interrupt lines,... and the issue is
related to the fact that the kernel-thread gets interrupted while the
driver is polling SPI-HW for the HW to terminate the traffic.
I got some examples where it takes 78ms where the worker thread
not running.

This is obviously way longer than the timeout limit of the max of:
  * 2 jiffies
  * 4x expected transfer time on the bus
which means we return -ETIMEDOUT.

For reference here a screenshot of the capture with the gap:
https://cloud.githubusercontent.com/assets/2638784/7137494/622dafb0-e2ba-11e4-8e25-840d702e04df.png

It shows that the cs is asserted, and then before anything can get written
to the fifo the thread gets rescheduled (or an interrupt triggers) and only
when it continues the fifo is filled and then the timeout check happens.

Obviously it depends heavily on in which code passage the process is
interrupted. Putting the spi-worker-thread in RT mode does not help,
as most of the transfers are now running inside the callers thread
due to spi_sync now calling __spi_pump_message directly if the queue
is empty and that way avoiding the scheduling overhead and latencies.

Here for completeness also the statistics on context switches for the
3 threads (spi worker and irq-mcp251x) listed above:
grep ctxt /proc/26986/status /proc/27091/status /proc/27096/status
/proc/26986/status:voluntary_ctxt_switches:	11503960
/proc/26986/status:nonvoluntary_ctxt_switches:	123465
/proc/27091/status:voluntary_ctxt_switches:	12117492
/proc/27091/status:nonvoluntary_ctxt_switches:	292
/proc/27096/status:voluntary_ctxt_switches:	11934367
/proc/27096/status:nonvoluntary_ctxt_switches:	247

So we have a probability of 0.002% that the mcp251x-irq threads
gets interrupted.
The spi-worker thread has a 1% chance of getting interrupted while
running its work.

Those values are for a system that is idle - no compile or anything
except for some minimal monitoring.

Approaches I can think of to solve the issue:
* accept this fact as a reality - drivers should be able to handle
  such situations in a well-behaved manner
* remove polling mode completely from the spi-bcm2835 driver
* remove the timeout code when polling
* make the timeout a warning
* set the timeout to something much longer say 200ms
* stop the system from interrupting (either scheduler or interrupt
  handler) for the next 30us or the calculated timeout-period.
  Maybe by holding a spinlock (or similar) / disabling interrupts /
  ...?
* others

So the question is: which approach should get implemented?

Thanks,
	Martin

P.s: Obviously the mcp251x driver should also handle this gracefully,
but that is a different story.

--
To unsubscribe from this list: send the line "unsubscribe linux-spi" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH V2] spi: bcm2835: enabling polling mode for transfers shorter than 30us
       [not found]         ` <F35B7C71-1917-40AE-BA42-CB3E63B877EF-TqfNSX0MhmxHKSADF0wUEw@public.gmane.org>
@ 2015-04-15 18:58           ` Mark Brown
       [not found]             ` <20150415185824.GU6023-GFdadSzt00ze9xe1eoZjHA@public.gmane.org>
  0 siblings, 1 reply; 15+ messages in thread
From: Mark Brown @ 2015-04-15 18:58 UTC (permalink / raw)
  To: Martin Sperl
  Cc: Stephen Warren, Lee Jones, linux-spi-u79uwXL29TY76Z2rM5mHXA,
	linux-rpi-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r

[-- Attachment #1: Type: text/plain, Size: 866 bytes --]

On Tue, Apr 14, 2015 at 04:29:49PM +0200, Martin Sperl wrote:

> Approaches I can think of to solve the issue:
> * accept this fact as a reality - drivers should be able to handle
>   such situations in a well-behaved manner
> * remove polling mode completely from the spi-bcm2835 driver
> * remove the timeout code when polling
> * make the timeout a warning
> * set the timeout to something much longer say 200ms
> * stop the system from interrupting (either scheduler or interrupt
>   handler) for the next 30us or the calculated timeout-period.
>   Maybe by holding a spinlock (or similar) / disabling interrupts /
>   ...?
> * others

> So the question is: which approach should get implemented?

Running without a timeout doesn't feel safe - the standard thing here is
to busy wait for a short period then fall back to something that sleeps
if that times out.

[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 473 bytes --]

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH V2] spi: bcm2835: enabling polling mode for transfers shorter than 30us
       [not found]             ` <20150415185824.GU6023-GFdadSzt00ze9xe1eoZjHA@public.gmane.org>
@ 2015-04-15 19:33               ` Martin Sperl
       [not found]                 ` <262B0C8C-7728-458E-8748-06F79251BE0C-TqfNSX0MhmxHKSADF0wUEw@public.gmane.org>
  0 siblings, 1 reply; 15+ messages in thread
From: Martin Sperl @ 2015-04-15 19:33 UTC (permalink / raw)
  To: Mark Brown
  Cc: Stephen Warren, Lee Jones, linux-spi-u79uwXL29TY76Z2rM5mHXA,
	linux-rpi-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r


> On 15.04.2015, at 20:58, Mark Brown <broonie-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org> wrote:
> Running without a timeout doesn't feel safe - the standard thing here is
> to busy wait for a short period then fall back to something that sleeps
> if that times out.

That is what is implemented now, but unfortunately the issue is that the 
implementation as of now is depending on jiffies, which I found out to be
in the order of 10ms and on top requires a timer interrupt which would
interrupt polling in the first place. But it is still sensitive enough
to trigger on some rescheduling of the polling thread.

One possibility could be increasing the timeout to something longer like
one second or a fraction of one second.

Something along those lines:
-	unsigned long timeout = jiffies +
-		max(4 * xfer_time_us * HZ / 1000000, 2uL);
+	/* one second timeout - this should also allow for graceful
+	 * timeouts even when experiencing rescheduling of the thread
+	 */
+	unsigned long timeout = jiffies + HZ;

Would this be sufficient and acceptable?

Alternatively we would need some way to measure the time in uSeconds
quite accurately and then code some "rescheduling" detection into the
polling loop to modify the end-time if the thread got rescheduled or
otherwise interrupted for longer periods. Things would get complicated
here...

What kind of interface could we use for this timeout behavior?

The question here is - is the "simple" 1 second timeout approach
sufficient or would we need something more complex?

The patch removing the timeout worked for about 1.47B SPI messages
using the polling code-path now without issues.
--
To unsubscribe from this list: send the line "unsubscribe linux-spi" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH V2] spi: bcm2835: enabling polling mode for transfers shorter than 30us
       [not found]                 ` <262B0C8C-7728-458E-8748-06F79251BE0C-TqfNSX0MhmxHKSADF0wUEw@public.gmane.org>
@ 2015-04-18 10:42                   ` Mark Brown
       [not found]                     ` <20150418104202.GA26185-GFdadSzt00ze9xe1eoZjHA@public.gmane.org>
  0 siblings, 1 reply; 15+ messages in thread
From: Mark Brown @ 2015-04-18 10:42 UTC (permalink / raw)
  To: Martin Sperl
  Cc: Stephen Warren, Lee Jones, linux-spi-u79uwXL29TY76Z2rM5mHXA,
	linux-rpi-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r

[-- Attachment #1: Type: text/plain, Size: 1764 bytes --]

On Wed, Apr 15, 2015 at 09:33:48PM +0200, Martin Sperl wrote:
> > On 15.04.2015, at 20:58, Mark Brown <broonie-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org> wrote:

> > Running without a timeout doesn't feel safe - the standard thing here is
> > to busy wait for a short period then fall back to something that sleeps
> > if that times out.

> That is what is implemented now, but unfortunately the issue is that the 
> implementation as of now is depending on jiffies, which I found out to be
> in the order of 10ms and on top requires a timer interrupt which would
> interrupt polling in the first place. But it is still sensitive enough
> to trigger on some rescheduling of the polling thread.

Then that's not what is implemented...  I'd expect something like a busy
wait loop done by something like dead reckoning the number of iterations
followed by msleep() if we go beyond the busy loop period.

> One possibility could be increasing the timeout to something longer like
> one second or a fraction of one second.

> Something along those lines:
> -	unsigned long timeout = jiffies +
> -		max(4 * xfer_time_us * HZ / 1000000, 2uL);
> +	/* one second timeout - this should also allow for graceful
> +	 * timeouts even when experiencing rescheduling of the thread
> +	 */
> +	unsigned long timeout = jiffies + HZ;

> Would this be sufficient and acceptable?

No, we need to not busy wait for that long.

> The patch removing the timeout worked for about 1.47B SPI messages
> using the polling code-path now without issues.

Sure, if everythinng is working fine then there's never any need to time
out - the question is what happens when things go wrong.  A hard lockup
probably isn't the answer people were looking for there.

[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 473 bytes --]

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH V2] spi: bcm2835: enabling polling mode for transfers shorter than 30us
       [not found]                     ` <20150418104202.GA26185-GFdadSzt00ze9xe1eoZjHA@public.gmane.org>
@ 2015-04-18 11:12                       ` Martin Sperl
       [not found]                         ` <54169601-55F7-464C-8A0E-ABF833C0F3BA-TqfNSX0MhmxHKSADF0wUEw@public.gmane.org>
  0 siblings, 1 reply; 15+ messages in thread
From: Martin Sperl @ 2015-04-18 11:12 UTC (permalink / raw)
  To: Mark Brown
  Cc: Stephen Warren, Lee Jones, linux-spi-u79uwXL29TY76Z2rM5mHXA,
	linux-rpi-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r


> On 18.04.2015, at 12:42, Mark Brown <broonie-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org> wrote:
> Sure, if everythinng is working fine then there's never any need to time
> out - the question is what happens when things go wrong.  A hard lockup
> probably isn't the answer people were looking for there.

Well that is why I have implemented the 1s timeout patch,
which you have already merged (145367baa492246). 

Such a timeout would typically also trigger a messages to
dmesg, so it becomes apparent that such a situation happened.

The only issues that could really trigger a timeout would be:
* heavy load on the system, where it takes >1s to reschedule
  the polling thread - but if you get to such a situation then
  all bets are off anyway.
* a hick-up in hardware 

As said: I have tried one type of load where I had something like
3000M SPI messages all running with polling  (about 18000 per second)
without any issues or timeouts while compiling the linux kernel.
And except for rescheduling the polling thread and the corresponding
delays there were no issues with the 1s timeout - it never triggered!

If you think that timeout of 1 second is too long, then we can change
it to something more acceptable, but it should be in the order of
100ms or more to avoid those “false” positives due to high cpu load
that the original code showed.

--
To unsubscribe from this list: send the line "unsubscribe linux-spi" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH V2] spi: bcm2835: enabling polling mode for transfers shorter than 30us
       [not found]                         ` <54169601-55F7-464C-8A0E-ABF833C0F3BA-TqfNSX0MhmxHKSADF0wUEw@public.gmane.org>
@ 2015-04-18 11:53                           ` Mark Brown
       [not found]                             ` <20150418115343.GI26185-GFdadSzt00ze9xe1eoZjHA@public.gmane.org>
  0 siblings, 1 reply; 15+ messages in thread
From: Mark Brown @ 2015-04-18 11:53 UTC (permalink / raw)
  To: Martin Sperl
  Cc: Stephen Warren, Lee Jones, linux-spi-u79uwXL29TY76Z2rM5mHXA,
	linux-rpi-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r

[-- Attachment #1: Type: text/plain, Size: 622 bytes --]

On Sat, Apr 18, 2015 at 01:12:02PM +0200, Martin Sperl wrote:

> Well that is why I have implemented the 1s timeout patch,
> which you have already merged (145367baa492246). 

> If you think that timeout of 1 second is too long, then we can change
> it to something more acceptable, but it should be in the order of
> 100ms or more to avoid those “false” positives due to high cpu load
> that the original code showed.

As I've said several times now 1s seems far too long for a busy wait,
the driver should fall back to something that sleeps after an initial
busy wait (once it's clear we're over time).

[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 473 bytes --]

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH V2] spi: bcm2835: enabling polling mode for transfers shorter than 30us
       [not found]                             ` <20150418115343.GI26185-GFdadSzt00ze9xe1eoZjHA@public.gmane.org>
@ 2015-04-18 12:13                               ` Martin Sperl
       [not found]                                 ` <EB2DE44C-29CA-422D-A89C-4173E02A2CEF-TqfNSX0MhmxHKSADF0wUEw@public.gmane.org>
  0 siblings, 1 reply; 15+ messages in thread
From: Martin Sperl @ 2015-04-18 12:13 UTC (permalink / raw)
  To: Mark Brown
  Cc: Stephen Warren, Lee Jones, linux-spi-u79uwXL29TY76Z2rM5mHXA,
	linux-rpi-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r


> On 18.04.2015, at 13:53, Mark Brown <broonie-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org> wrote:
> 
> As I've said several times now 1s seems far too long for a busy wait,
> the driver should fall back to something that sleeps after an initial
> busy wait (once it's clear we're over time).
Then I have misread what you wrote - I understood you wanted to avoid
having no timeout at all.

So you want something like:
* wait for 4 jiffies (which is 40ms typically)
* if we exceed that, then enable interrupts for the rest of the transfer
and let the 30s timeout handle everything else

Martin
--
To unsubscribe from this list: send the line "unsubscribe linux-spi" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH V2] spi: bcm2835: enabling polling mode for transfers shorter than 30us
       [not found]                                 ` <EB2DE44C-29CA-422D-A89C-4173E02A2CEF-TqfNSX0MhmxHKSADF0wUEw@public.gmane.org>
@ 2015-04-18 12:27                                   ` Mark Brown
       [not found]                                     ` <20150418122748.GO26185-GFdadSzt00ze9xe1eoZjHA@public.gmane.org>
  0 siblings, 1 reply; 15+ messages in thread
From: Mark Brown @ 2015-04-18 12:27 UTC (permalink / raw)
  To: Martin Sperl
  Cc: Stephen Warren, Lee Jones, linux-spi-u79uwXL29TY76Z2rM5mHXA,
	linux-rpi-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r

[-- Attachment #1: Type: text/plain, Size: 933 bytes --]

On Sat, Apr 18, 2015 at 02:13:56PM +0200, Martin Sperl wrote:
> > On 18.04.2015, at 13:53, Mark Brown <broonie-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org> wrote:

> > As I've said several times now 1s seems far too long for a busy wait,
> > the driver should fall back to something that sleeps after an initial
> > busy wait (once it's clear we're over time).

> Then I have misread what you wrote - I understood you wanted to avoid
> having no timeout at all.

No, that's correct - we shouldn't be busy waiting for ever so we need
something that will terminate.

> So you want something like:
> * wait for 4 jiffies (which is 40ms typically)
> * if we exceed that, then enable interrupts for the rest of the transfer
> and let the 30s timeout handle everything else

That's probably fine, though the 40ms is a bit on the long side.  The
30s timeout could use pulling in too, that's going to fail very badly if
anything does go wronng.

[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 473 bytes --]

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH V2] spi: bcm2835: enabling polling mode for transfers shorter than 30us
       [not found]                                     ` <20150418122748.GO26185-GFdadSzt00ze9xe1eoZjHA@public.gmane.org>
@ 2015-04-18 13:31                                       ` Martin Sperl
       [not found]                                         ` <2DB27253-8254-4098-ADE3-9AA22D52BE9D-TqfNSX0MhmxHKSADF0wUEw@public.gmane.org>
  0 siblings, 1 reply; 15+ messages in thread
From: Martin Sperl @ 2015-04-18 13:31 UTC (permalink / raw)
  To: Mark Brown
  Cc: Stephen Warren, Lee Jones, linux-spi-u79uwXL29TY76Z2rM5mHXA,
	linux-rpi-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r


> On 18.04.2015, at 14:27, Mark Brown <broonie-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org> wrote:
> That's probably fine, though the 40ms is a bit on the long side.  The
> 30s timeout could use pulling in too, that's going to fail very badly if
> anything does go wronng.

Anything below 2 jiffies will give enough false positives during a kernel
recompile - the original code has had 2 jiffies as the effective minimum,
because the calculated delivery-time of max 30us is still orders of magnitudes
smaller than a single jiffy, but a reschedule can happen, which would be the
main reason why we have had triggered timeouts before.

SO IMO anything shorter than 2-3 jifies would need to use a new framework to
get access to high-resolution timers - and I do not know how to do that.

We can implement it as 3 jiffies or 30ms if that seems more acceptable.

Would look something like this:
diff --git a/drivers/spi/spi-bcm2835.c b/drivers/spi/spi-bcm2835.c
index 37875cf..1bbfccd 100644
--- a/drivers/spi/spi-bcm2835.c
+++ b/drivers/spi/spi-bcm2835.c
@@ -68,8 +68,7 @@
 #define BCM2835_SPI_CS_CS_10		0x00000002
 #define BCM2835_SPI_CS_CS_01		0x00000001
 
-#define BCM2835_SPI_POLLING_LIMIT_US	30
-#define BCM2835_SPI_TIMEOUT_MS		30000
+#define BCM2835_SPI_POLLING_LIMIT_MS	30
 #define BCM2835_SPI_MODE_BITS	(SPI_CPOL | SPI_CPHA | SPI_CS_HIGH \
 				| SPI_NO_CS | SPI_3WIRE)
 
@@ -164,8 +163,9 @@ static int bcm2835_spi_transfer_one_poll(struct spi_master *master,
 					 unsigned long xfer_time_us)
 {
 	struct bcm2835_spi *bs = spi_master_get_devdata(master);
-	/* set timeout to 1 second of maximum polling */
-	unsigned long timeout = jiffies + HZ;
+	/* set timeout and then fall back to interrupts */
+	unsigned long timeout = jiffies +
+		HZ * BCM2835_SPI_POLLING_LIMIT_MS / 1000;
 
 	/* enable HW block without interrupts */
 	bcm2835_wr(bs, BCM2835_SPI_CS, cs | BCM2835_SPI_CS_TA);
@@ -177,13 +177,12 @@ static int bcm2835_spi_transfer_one_poll(struct spi_master *master,
 		/* fill in tx fifo as much as possible */
 		bcm2835_wr_fifo(bs);
 		/* if we still expect some data after the read,
-		 * check for a possible timeout
+		 * check for a possible timeout and if we reach that
+		 * then fallback to interrupt mode...
 		 */
 		if (bs->rx_len && time_after(jiffies, timeout)) {
-			/* Transfer complete - reset SPI HW */
-			bcm2835_spi_reset_hw(master);
-			/* and return timeout */
-			return -ETIMEDOUT;
+			return bcm2835_spi_transfer_one_irq(master, spi,
+							    tfr,cs);
 		}
 	}
 

I will need to test it and then I will submit it as a patch against
the 1s timeout patch (so what is already in for-next).

Martin--
To unsubscribe from this list: send the line "unsubscribe linux-spi" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply related	[flat|nested] 15+ messages in thread

* Re: [PATCH V2] spi: bcm2835: enabling polling mode for transfers shorter than 30us
       [not found]                                         ` <2DB27253-8254-4098-ADE3-9AA22D52BE9D-TqfNSX0MhmxHKSADF0wUEw@public.gmane.org>
@ 2015-04-18 17:07                                           ` Mark Brown
       [not found]                                             ` <20150418170756.GX26185-GFdadSzt00ze9xe1eoZjHA@public.gmane.org>
  0 siblings, 1 reply; 15+ messages in thread
From: Mark Brown @ 2015-04-18 17:07 UTC (permalink / raw)
  To: Martin Sperl
  Cc: Stephen Warren, Lee Jones, linux-spi-u79uwXL29TY76Z2rM5mHXA,
	linux-rpi-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r

[-- Attachment #1: Type: text/plain, Size: 1377 bytes --]

On Sat, Apr 18, 2015 at 03:31:13PM +0200, Martin Sperl wrote:

> > On 18.04.2015, at 14:27, Mark Brown <broonie-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org> wrote:
> > That's probably fine, though the 40ms is a bit on the long side.  The
> > 30s timeout could use pulling in too, that's going to fail very badly if
> > anything does go wronng.

> Anything below 2 jiffies will give enough false positives during a kernel
> recompile - the original code has had 2 jiffies as the effective minimum,
> because the calculated delivery-time of max 30us is still orders of magnitudes
> smaller than a single jiffy, but a reschedule can happen, which would be the
> main reason why we have had triggered timeouts before.

Sure, but with the fallback to a much longer sleeping delay that'd be
covered transparently anyway - it doesn't matter if we don't always
manage to busy wait under load, what's more important is that we don't
fail the operation as a whole.

Actually if it's just scheduling that's a concern then one final check
after the time expires should do the trick shouldn't it?

> SO IMO anything shorter than 2-3 jifies would need to use a new framework to
> get access to high-resolution timers - and I do not know how to do that.

hrtimer_ is the high resolution timer stuff, though I don't think it's
really what you're looking for, it's more about async callbacks IIRC.

[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 473 bytes --]

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH V2] spi: bcm2835: enabling polling mode for transfers shorter than 30us
       [not found]                                             ` <20150418170756.GX26185-GFdadSzt00ze9xe1eoZjHA@public.gmane.org>
@ 2015-04-19  9:44                                               ` Martin Sperl
       [not found]                                                 ` <E9247B42-11B6-4032-A6C1-1FCEA3EDA2A6-TqfNSX0MhmxHKSADF0wUEw@public.gmane.org>
  0 siblings, 1 reply; 15+ messages in thread
From: Martin Sperl @ 2015-04-19  9:44 UTC (permalink / raw)
  To: Mark Brown
  Cc: Stephen Warren, Lee Jones, linux-spi-u79uwXL29TY76Z2rM5mHXA,
	linux-rpi-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r


> On 18.04.2015, at 19:07, Mark Brown <broonie-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org> wrote:
> 
> Sure, but with the fallback to a much longer sleeping delay that'd be
> covered transparently anyway - it doesn't matter if we don't always
> manage to busy wait under load, what's more important is that we don't
> fail the operation as a whole.
> 
> Actually if it's just scheduling that's a concern then one final check
> after the time expires should do the trick shouldn't it?

Well - I have tried now lots of things now and I have also started some
diagnostics on timeouts as well as trying to detect reschedules and then
report on the jiffies that have passed between start of loop and the check
and I get values like this:

[ 5867.943426] mcp251x spi32759.2: detected reschedule: 7 jiffies
[ 5868.628859] mcp251x spi32759.2: detected reschedule: 8 jiffies
[ 5869.867311] mcp251x spi32759.2: detected reschedule: 8 jiffies
[ 5870.139622] mcp251x spi32759.0: detected reschedule: 8 jiffies
[ 5870.272004] mcp251x spi32759.2: detected reschedule: 8 jiffies
[ 5871.352704] mcp251x spi32759.0: detected reschedule: 5 jiffies
[ 5871.469095] mcp251x spi32759.0: detected reschedule: 8 jiffies
[ 5908.783971] mcp251x spi32759.2: detected reschedule: 75 jiffies
[ 5955.831822] mcp251x spi32759.0: detected reschedule: 75 jiffies
[ 5977.380447] mcp251x spi32759.2: detected reschedule: 82 jiffies
[ 5977.602457] mcp251x spi32759.0: detected reschedule: 15 jiffies
[ 5980.093570] mcp251x spi32759.2: detected reschedule: 2 jiffies
[ 6006.559147] mcp251x spi32759.2: detected reschedule: 5 jiffies
[ 6009.030543] mcp251x spi32759.0: detected reschedule: 8 jiffies
[ 6016.872027] mcp251x spi32759.0: detected reschedule: 27 jiffies
[ 6018.808468] mcp251x spi32759.2: detected reschedule: 82 jiffies
[ 6021.586796] mcp251x spi32759.2: detected reschedule: 81 jiffies
[ 6024.411264] mcp251x spi32759.2: detected reschedule: 77 jiffies
[ 6033.868509] mcp251x spi32759.2: detected reschedule: 55 jiffies
[ 6035.914697] mcp251x spi32759.0: detected reschedule: 81 jiffies
[ 6051.216355] mcp251x spi32759.2: detected reschedule: 82 jiffies
[ 6051.801190] mcp251x spi32759.0: detected reschedule: 55 jiffies
[ 6052.075748] mcp251x spi32759.0: detected reschedule: 27 jiffies
[ 6054.004605] mcp251x spi32759.0: detected reschedule: 81 jiffies
[ 6068.815078] mcp251x spi32759.2: detected reschedule: 27 jiffies
[ 6072.394473] mcp251x spi32759.2: detected reschedule: 81 jiffies
[ 6081.257468] mcp251x spi32759.2: detected reschedule: 81 jiffies
[ 6085.751653] mcp251x spi32759.2: detected reschedule: 82 jiffies
[ 6111.253374] mcp251x spi32759.2: detected reschedule: 82 jiffies
[ 6119.573181] mcp251x spi32759.2: detected reschedule: 74 jiffies
[ 6131.105261] mcp251x spi32759.0: detected reschedule: 4 jiffies
[ 6131.960492] mcp251x spi32759.2: detected reschedule: 82 jiffies
[ 6132.808198] mcp251x spi32759.2: detected reschedule: 82 jiffies
[ 6132.958858] mcp251x spi32759.2: detected reschedule: 8 jiffies
[ 6137.992678] mcp251x spi32759.2: detected reschedule: 48 jiffies
[ 6144.553370] mcp251x spi32759.2: detected reschedule: 34 jiffies
[ 6146.819876] mcp251x spi32759.0: detected reschedule: 82 jiffies
[ 6146.969923] mcp251x spi32759.2: detected reschedule: 8 jiffies
[ 6152.984406] mcp251x spi32759.2: detected reschedule: 82 jiffies
[ 6170.475425] mcp251x spi32759.0: detected reschedule: 74 jiffies
[ 6174.954398] mcp251x spi32759.2: detected reschedule: 82 jiffies

That happens when running torture CAN message receive test and
concurrently taring the “*.o” files of the kernel - which produces
lots of IO...
But sometimes it also happens during other “minimal” activities - 
but that is a much rarer event.

This is really the worsted case, as even those typical 8000 irq/s
on an idle RPI sometimes drop down to 200 irqs/s (plus high block out
counts) - and then the system is no very responsive to put it mildly...

So the only solution seem to be: if a timeout of > 2 jiffies occurs
fall back to interrupts.

This way we are catering for the worsted case and at least our code
should not make some drivers fail due to missing error-handling 
in the driver when the system is overloaded and produces this kind
of delays.

In the hope that this is an acceptable approach I will post a patch
as soon as I have confirmed it to be working with  a much longer
torture-test that does not show any hiccups on the driver-side.

--
To unsubscribe from this list: send the line "unsubscribe linux-spi" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 15+ messages in thread

* [PATCH] spi: bcm2835: fallback to interrupt for polling timeouts exceeding 2 jiffies
       [not found]                                                 ` <E9247B42-11B6-4032-A6C1-1FCEA3EDA2A6-TqfNSX0MhmxHKSADF0wUEw@public.gmane.org>
@ 2015-04-22  7:33                                                   ` kernel-TqfNSX0MhmxHKSADF0wUEw
       [not found]                                                     ` <1429687984-7350-1-git-send-email-kernel-TqfNSX0MhmxHKSADF0wUEw@public.gmane.org>
  0 siblings, 1 reply; 15+ messages in thread
From: kernel-TqfNSX0MhmxHKSADF0wUEw @ 2015-04-22  7:33 UTC (permalink / raw)
  To: Mark Brown, Stephen Warren, Lee Jones,
	linux-spi-u79uwXL29TY76Z2rM5mHXA,
	linux-rpi-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r
  Cc: Martin Sperl

From: Martin Sperl <kernel-TqfNSX0MhmxHKSADF0wUEw@public.gmane.org>

The polling mode of the driver is designed for transfers that run
less than 30us - it will only execute under those circumstances.
So it should run comfortably without getting interrupted by the
scheduler.

But there are situations where the raspberry pi is so overloaded
that it can take up to 80 jiffies until the polling thread gets
rescheduled - this has been observed especially under heavy
IO situations.

In such a situation we now fall back to the interrupt handler and
log the situation at debug level.

Signed-off-by: Martin Sperl <kernel-TqfNSX0MhmxHKSADF0wUEw@public.gmane.org>
---
 drivers/spi/spi-bcm2835.c |   87 ++++++++++++++++++++++++++-------------------
 1 file changed, 50 insertions(+), 37 deletions(-)

Applies against for-next

diff --git a/drivers/spi/spi-bcm2835.c b/drivers/spi/spi-bcm2835.c
index 37875cf..830d99c 100644
--- a/drivers/spi/spi-bcm2835.c
+++ b/drivers/spi/spi-bcm2835.c
@@ -69,7 +69,7 @@
 #define BCM2835_SPI_CS_CS_01		0x00000001
 
 #define BCM2835_SPI_POLLING_LIMIT_US	30
-#define BCM2835_SPI_TIMEOUT_MS		30000
+#define BCM2835_SPI_POLLING_JIFFIES	2
 #define BCM2835_SPI_MODE_BITS	(SPI_CPOL | SPI_CPHA | SPI_CS_HIGH \
 				| SPI_NO_CS | SPI_3WIRE)
 
@@ -157,42 +157,6 @@ static irqreturn_t bcm2835_spi_interrupt(int irq, void *dev_id)
 	return IRQ_HANDLED;
 }
 
-static int bcm2835_spi_transfer_one_poll(struct spi_master *master,
-					 struct spi_device *spi,
-					 struct spi_transfer *tfr,
-					 u32 cs,
-					 unsigned long xfer_time_us)
-{
-	struct bcm2835_spi *bs = spi_master_get_devdata(master);
-	/* set timeout to 1 second of maximum polling */
-	unsigned long timeout = jiffies + HZ;
-
-	/* enable HW block without interrupts */
-	bcm2835_wr(bs, BCM2835_SPI_CS, cs | BCM2835_SPI_CS_TA);
-
-	/* loop until finished the transfer */
-	while (bs->rx_len) {
-		/* read from fifo as much as possible */
-		bcm2835_rd_fifo(bs);
-		/* fill in tx fifo as much as possible */
-		bcm2835_wr_fifo(bs);
-		/* if we still expect some data after the read,
-		 * check for a possible timeout
-		 */
-		if (bs->rx_len && time_after(jiffies, timeout)) {
-			/* Transfer complete - reset SPI HW */
-			bcm2835_spi_reset_hw(master);
-			/* and return timeout */
-			return -ETIMEDOUT;
-		}
-	}
-
-	/* Transfer complete - reset SPI HW */
-	bcm2835_spi_reset_hw(master);
-	/* and return without waiting for completion */
-	return 0;
-}
-
 static int bcm2835_spi_transfer_one_irq(struct spi_master *master,
 					struct spi_device *spi,
 					struct spi_transfer *tfr,
@@ -229,6 +193,55 @@ static int bcm2835_spi_transfer_one_irq(struct spi_master *master,
 	return 1;
 }
 
+static int bcm2835_spi_transfer_one_poll(struct spi_master *master,
+					 struct spi_device *spi,
+					 struct spi_transfer *tfr,
+					 u32 cs,
+					 unsigned long xfer_time_us)
+{
+	struct bcm2835_spi *bs = spi_master_get_devdata(master);
+	unsigned long timeout;
+
+	/* enable HW block without interrupts */
+	bcm2835_wr(bs, BCM2835_SPI_CS, cs | BCM2835_SPI_CS_TA);
+
+	/* fill in the fifo before timeout calculations
+	 * if we are interrupted here, then the data is
+	 * getting transferred by the HW while we are interrupted
+	 */
+	bcm2835_wr_fifo(bs);
+
+	/* set the timeout */
+	timeout = jiffies + BCM2835_SPI_POLLING_JIFFIES;
+
+	/* loop until finished the transfer */
+	while (bs->rx_len) {
+		/* fill in tx fifo with remaining data */
+		bcm2835_wr_fifo(bs);
+
+		/* read from fifo as much as possible */
+		bcm2835_rd_fifo(bs);
+
+		/* if there is still data pending to read
+		 * then check the timeout
+		 */
+		if (bs->rx_len && time_after(jiffies, timeout)) {
+			dev_dbg_ratelimited(&spi->dev,
+					    "timeout period reached: jiffies: %lu remaining tx/rx: %d/%d - falling back to interrupt mode\n",
+					    jiffies - timeout,
+					    bs->tx_len, bs->rx_len);
+			/* fall back to interrupt mode */
+			return bcm2835_spi_transfer_one_irq(master, spi,
+							    tfr, cs);
+		}
+	}
+
+	/* Transfer complete - reset SPI HW */
+	bcm2835_spi_reset_hw(master);
+	/* and return without waiting for completion */
+	return 0;
+}
+
 static int bcm2835_spi_transfer_one(struct spi_master *master,
 				    struct spi_device *spi,
 				    struct spi_transfer *tfr)
-- 
1.7.10.4

--
To unsubscribe from this list: send the line "unsubscribe linux-spi" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply related	[flat|nested] 15+ messages in thread

* Re: [PATCH] spi: bcm2835: fallback to interrupt for polling timeouts exceeding 2 jiffies
       [not found]                                                     ` <1429687984-7350-1-git-send-email-kernel-TqfNSX0MhmxHKSADF0wUEw@public.gmane.org>
@ 2015-04-22 19:50                                                       ` Mark Brown
  0 siblings, 0 replies; 15+ messages in thread
From: Mark Brown @ 2015-04-22 19:50 UTC (permalink / raw)
  To: kernel-TqfNSX0MhmxHKSADF0wUEw
  Cc: Stephen Warren, Lee Jones, linux-spi-u79uwXL29TY76Z2rM5mHXA,
	linux-rpi-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r

[-- Attachment #1: Type: text/plain, Size: 410 bytes --]

On Wed, Apr 22, 2015 at 07:33:03AM +0000, kernel-TqfNSX0MhmxHKSADF0wUEw@public.gmane.org wrote:
> From: Martin Sperl <kernel-TqfNSX0MhmxHKSADF0wUEw@public.gmane.org>
> 
> The polling mode of the driver is designed for transfers that run
> less than 30us - it will only execute under those circumstances.
> So it should run comfortably without getting interrupted by the
> scheduler.

Applied, thanks.

[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 473 bytes --]

^ permalink raw reply	[flat|nested] 15+ messages in thread

end of thread, other threads:[~2015-04-22 19:50 UTC | newest]

Thread overview: 15+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2015-04-06 17:16 [PATCH V2] spi: bcm2835: enabling polling mode for transfers shorter than 30us kernel-TqfNSX0MhmxHKSADF0wUEw
     [not found] ` <1428340592-3196-1-git-send-email-kernel-TqfNSX0MhmxHKSADF0wUEw@public.gmane.org>
2015-04-10 18:51   ` Mark Brown
     [not found]     ` <20150410185132.GU6023-GFdadSzt00ze9xe1eoZjHA@public.gmane.org>
2015-04-14 14:29       ` Martin Sperl
     [not found]         ` <F35B7C71-1917-40AE-BA42-CB3E63B877EF-TqfNSX0MhmxHKSADF0wUEw@public.gmane.org>
2015-04-15 18:58           ` Mark Brown
     [not found]             ` <20150415185824.GU6023-GFdadSzt00ze9xe1eoZjHA@public.gmane.org>
2015-04-15 19:33               ` Martin Sperl
     [not found]                 ` <262B0C8C-7728-458E-8748-06F79251BE0C-TqfNSX0MhmxHKSADF0wUEw@public.gmane.org>
2015-04-18 10:42                   ` Mark Brown
     [not found]                     ` <20150418104202.GA26185-GFdadSzt00ze9xe1eoZjHA@public.gmane.org>
2015-04-18 11:12                       ` Martin Sperl
     [not found]                         ` <54169601-55F7-464C-8A0E-ABF833C0F3BA-TqfNSX0MhmxHKSADF0wUEw@public.gmane.org>
2015-04-18 11:53                           ` Mark Brown
     [not found]                             ` <20150418115343.GI26185-GFdadSzt00ze9xe1eoZjHA@public.gmane.org>
2015-04-18 12:13                               ` Martin Sperl
     [not found]                                 ` <EB2DE44C-29CA-422D-A89C-4173E02A2CEF-TqfNSX0MhmxHKSADF0wUEw@public.gmane.org>
2015-04-18 12:27                                   ` Mark Brown
     [not found]                                     ` <20150418122748.GO26185-GFdadSzt00ze9xe1eoZjHA@public.gmane.org>
2015-04-18 13:31                                       ` Martin Sperl
     [not found]                                         ` <2DB27253-8254-4098-ADE3-9AA22D52BE9D-TqfNSX0MhmxHKSADF0wUEw@public.gmane.org>
2015-04-18 17:07                                           ` Mark Brown
     [not found]                                             ` <20150418170756.GX26185-GFdadSzt00ze9xe1eoZjHA@public.gmane.org>
2015-04-19  9:44                                               ` Martin Sperl
     [not found]                                                 ` <E9247B42-11B6-4032-A6C1-1FCEA3EDA2A6-TqfNSX0MhmxHKSADF0wUEw@public.gmane.org>
2015-04-22  7:33                                                   ` [PATCH] spi: bcm2835: fallback to interrupt for polling timeouts exceeding 2 jiffies kernel-TqfNSX0MhmxHKSADF0wUEw
     [not found]                                                     ` <1429687984-7350-1-git-send-email-kernel-TqfNSX0MhmxHKSADF0wUEw@public.gmane.org>
2015-04-22 19:50                                                       ` Mark Brown

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.