]>
Commit | Line | Data |
---|---|---|
326a9cc7 GKH |
1 | From 56c1723426d3cfd4723bfbfce531d7b38bae6266 Mon Sep 17 00:00:00 2001 |
2 | From: Lukas Wunner <lukas@wunner.de> | |
3 | Date: Thu, 8 Nov 2018 08:06:10 +0100 | |
4 | Subject: spi: bcm2835: Avoid finishing transfer prematurely in IRQ mode | |
5 | MIME-Version: 1.0 | |
6 | Content-Type: text/plain; charset=UTF-8 | |
7 | Content-Transfer-Encoding: 8bit | |
8 | ||
9 | From: Lukas Wunner <lukas@wunner.de> | |
10 | ||
11 | commit 56c1723426d3cfd4723bfbfce531d7b38bae6266 upstream. | |
12 | ||
13 | The IRQ handler bcm2835_spi_interrupt() first reads as much as possible | |
14 | from the RX FIFO, then writes as much as possible to the TX FIFO. | |
15 | Afterwards it decides whether the transfer is finished by checking if | |
16 | the TX FIFO is empty. | |
17 | ||
18 | If very few bytes were written to the TX FIFO, they may already have | |
19 | been transmitted by the time the FIFO's emptiness is checked. As a | |
20 | result, the transfer will be declared finished and the chip will be | |
21 | reset without reading the corresponding received bytes from the RX FIFO. | |
22 | ||
23 | The odds of this happening increase with a high clock frequency (such | |
24 | that the TX FIFO drains quickly) and either passing "threadirqs" on the | |
25 | command line or enabling CONFIG_PREEMPT_RT_BASE (such that the IRQ | |
26 | handler may be preempted between filling the TX FIFO and checking its | |
27 | emptiness). | |
28 | ||
29 | Fix by instead checking whether rx_len has reached zero, which means | |
30 | that the transfer has been received in full. This is also more | |
31 | efficient as it avoids one bus read access per interrupt. Note that | |
32 | bcm2835_spi_transfer_one_poll() likewise uses rx_len to determine | |
33 | whether the transfer has finished. | |
34 | ||
35 | Signed-off-by: Lukas Wunner <lukas@wunner.de> | |
36 | Fixes: e34ff011c70e ("spi: bcm2835: move to the transfer_one driver model") | |
37 | Cc: stable@vger.kernel.org # v4.1+ | |
38 | Cc: Mathias Duckeck <m.duckeck@kunbus.de> | |
39 | Cc: Frank Pavlic <f.pavlic@kunbus.de> | |
40 | Cc: Martin Sperl <kernel@martin.sperl.org> | |
41 | Cc: Noralf Trønnes <noralf@tronnes.org> | |
42 | Signed-off-by: Mark Brown <broonie@kernel.org> | |
43 | Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> | |
44 | ||
45 | --- | |
46 | drivers/spi/spi-bcm2835.c | 3 +-- | |
47 | 1 file changed, 1 insertion(+), 2 deletions(-) | |
48 | ||
49 | --- a/drivers/spi/spi-bcm2835.c | |
50 | +++ b/drivers/spi/spi-bcm2835.c | |
51 | @@ -155,8 +155,7 @@ static irqreturn_t bcm2835_spi_interrupt | |
52 | /* Write as many bytes as possible to FIFO */ | |
53 | bcm2835_wr_fifo(bs); | |
54 | ||
55 | - /* based on flags decide if we can finish the transfer */ | |
56 | - if (bcm2835_rd(bs, BCM2835_SPI_CS) & BCM2835_SPI_CS_DONE) { | |
57 | + if (!bs->rx_len) { | |
58 | /* Transfer complete - reset SPI HW */ | |
59 | bcm2835_spi_reset_hw(master); | |
60 | /* wake up the framework */ |