diff options
author | James <> | 2015-11-04 11:49:21 +0000 |
---|---|---|
committer | James <> | 2015-11-04 11:49:21 +0000 |
commit | 716ca530e1c4515d8683c9d5be3d56b301758b66 (patch) | |
tree | 700eb5bcc1a462a5f21dcec15ce7c97ecfefa772 /target/linux/brcm2708/patches-4.1/0155-spi-bcm2835-fallback-to-interrupt-for-polling-timeou.patch | |
download | trunk-47381-716ca530e1c4515d8683c9d5be3d56b301758b66.tar.gz trunk-47381-716ca530e1c4515d8683c9d5be3d56b301758b66.tar.bz2 trunk-47381-716ca530e1c4515d8683c9d5be3d56b301758b66.zip |
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.patch | 136 |
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) |