aboutsummaryrefslogtreecommitdiffstats
path: root/target/linux/brcm2708/patches-4.1/0155-spi-bcm2835-fallback-to-interrupt-for-polling-timeou.patch
diff options
context:
space:
mode:
authorJames <>2015-11-04 11:49:21 +0000
committerJames <>2015-11-04 11:49:21 +0000
commit716ca530e1c4515d8683c9d5be3d56b301758b66 (patch)
tree700eb5bcc1a462a5f21dcec15ce7c97ecfefa772 /target/linux/brcm2708/patches-4.1/0155-spi-bcm2835-fallback-to-interrupt-for-polling-timeou.patch
downloadtrunk-47381-716ca530e1c4515d8683c9d5be3d56b301758b66.tar.gz
trunk-47381-716ca530e1c4515d8683c9d5be3d56b301758b66.tar.bz2
trunk-47381-716ca530e1c4515d8683c9d5be3d56b301758b66.zip
trunk-47381HEADmaster
Diffstat (limited to 'target/linux/brcm2708/patches-4.1/0155-spi-bcm2835-fallback-to-interrupt-for-polling-timeou.patch')
-rw-r--r--target/linux/brcm2708/patches-4.1/0155-spi-bcm2835-fallback-to-interrupt-for-polling-timeou.patch136
1 files changed, 136 insertions, 0 deletions
diff --git a/target/linux/brcm2708/patches-4.1/0155-spi-bcm2835-fallback-to-interrupt-for-polling-timeou.patch b/target/linux/brcm2708/patches-4.1/0155-spi-bcm2835-fallback-to-interrupt-for-polling-timeou.patch
new file mode 100644
index 0000000..766923e
--- /dev/null
+++ b/target/linux/brcm2708/patches-4.1/0155-spi-bcm2835-fallback-to-interrupt-for-polling-timeou.patch
@@ -0,0 +1,136 @@
+From 0e646de6b27ee8b6631e5cebf8beffeccad8de63 Mon Sep 17 00:00:00 2001
+From: Martin Sperl <kernel@martin.sperl.org>
+Date: Wed, 22 Apr 2015 07:33:03 +0000
+Subject: [PATCH 155/203] spi: bcm2835: fallback to interrupt for polling
+ timeouts exceeding 2 jiffies
+
+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@martin.sperl.org>
+Signed-off-by: Mark Brown <broonie@kernel.org>
+(cherry picked from commit a750b124cfd27bae1a12df22318db5a2083dfb12)
+---
+ drivers/spi/spi-bcm2835.c | 87 +++++++++++++++++++++++++++--------------------
+ 1 file changed, 50 insertions(+), 37 deletions(-)
+
+--- 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
+ 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(
+ 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)