Skip to content

Commit a750b12

Browse files
msperlbroonie
authored andcommitted
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>
1 parent 76ee023 commit a750b12

File tree

1 file changed

+50
-37
lines changed

1 file changed

+50
-37
lines changed

drivers/spi/spi-bcm2835.c

+50-37
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@
6969
#define BCM2835_SPI_CS_CS_01 0x00000001
7070

7171
#define BCM2835_SPI_POLLING_LIMIT_US 30
72-
#define BCM2835_SPI_TIMEOUT_MS 30000
72+
#define BCM2835_SPI_POLLING_JIFFIES 2
7373
#define BCM2835_SPI_MODE_BITS (SPI_CPOL | SPI_CPHA | SPI_CS_HIGH \
7474
| SPI_NO_CS | SPI_3WIRE)
7575

@@ -157,42 +157,6 @@ static irqreturn_t bcm2835_spi_interrupt(int irq, void *dev_id)
157157
return IRQ_HANDLED;
158158
}
159159

160-
static int bcm2835_spi_transfer_one_poll(struct spi_master *master,
161-
struct spi_device *spi,
162-
struct spi_transfer *tfr,
163-
u32 cs,
164-
unsigned long xfer_time_us)
165-
{
166-
struct bcm2835_spi *bs = spi_master_get_devdata(master);
167-
/* set timeout to 1 second of maximum polling */
168-
unsigned long timeout = jiffies + HZ;
169-
170-
/* enable HW block without interrupts */
171-
bcm2835_wr(bs, BCM2835_SPI_CS, cs | BCM2835_SPI_CS_TA);
172-
173-
/* loop until finished the transfer */
174-
while (bs->rx_len) {
175-
/* read from fifo as much as possible */
176-
bcm2835_rd_fifo(bs);
177-
/* fill in tx fifo as much as possible */
178-
bcm2835_wr_fifo(bs);
179-
/* if we still expect some data after the read,
180-
* check for a possible timeout
181-
*/
182-
if (bs->rx_len && time_after(jiffies, timeout)) {
183-
/* Transfer complete - reset SPI HW */
184-
bcm2835_spi_reset_hw(master);
185-
/* and return timeout */
186-
return -ETIMEDOUT;
187-
}
188-
}
189-
190-
/* Transfer complete - reset SPI HW */
191-
bcm2835_spi_reset_hw(master);
192-
/* and return without waiting for completion */
193-
return 0;
194-
}
195-
196160
static int bcm2835_spi_transfer_one_irq(struct spi_master *master,
197161
struct spi_device *spi,
198162
struct spi_transfer *tfr,
@@ -229,6 +193,55 @@ static int bcm2835_spi_transfer_one_irq(struct spi_master *master,
229193
return 1;
230194
}
231195

196+
static int bcm2835_spi_transfer_one_poll(struct spi_master *master,
197+
struct spi_device *spi,
198+
struct spi_transfer *tfr,
199+
u32 cs,
200+
unsigned long xfer_time_us)
201+
{
202+
struct bcm2835_spi *bs = spi_master_get_devdata(master);
203+
unsigned long timeout;
204+
205+
/* enable HW block without interrupts */
206+
bcm2835_wr(bs, BCM2835_SPI_CS, cs | BCM2835_SPI_CS_TA);
207+
208+
/* fill in the fifo before timeout calculations
209+
* if we are interrupted here, then the data is
210+
* getting transferred by the HW while we are interrupted
211+
*/
212+
bcm2835_wr_fifo(bs);
213+
214+
/* set the timeout */
215+
timeout = jiffies + BCM2835_SPI_POLLING_JIFFIES;
216+
217+
/* loop until finished the transfer */
218+
while (bs->rx_len) {
219+
/* fill in tx fifo with remaining data */
220+
bcm2835_wr_fifo(bs);
221+
222+
/* read from fifo as much as possible */
223+
bcm2835_rd_fifo(bs);
224+
225+
/* if there is still data pending to read
226+
* then check the timeout
227+
*/
228+
if (bs->rx_len && time_after(jiffies, timeout)) {
229+
dev_dbg_ratelimited(&spi->dev,
230+
"timeout period reached: jiffies: %lu remaining tx/rx: %d/%d - falling back to interrupt mode\n",
231+
jiffies - timeout,
232+
bs->tx_len, bs->rx_len);
233+
/* fall back to interrupt mode */
234+
return bcm2835_spi_transfer_one_irq(master, spi,
235+
tfr, cs);
236+
}
237+
}
238+
239+
/* Transfer complete - reset SPI HW */
240+
bcm2835_spi_reset_hw(master);
241+
/* and return without waiting for completion */
242+
return 0;
243+
}
244+
232245
static int bcm2835_spi_transfer_one(struct spi_master *master,
233246
struct spi_device *spi,
234247
struct spi_transfer *tfr)

0 commit comments

Comments
 (0)