]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/blame - releases/4.9.149/spi-bcm2835-fix-race-on-dma-termination.patch
Linux 5.1.6
[thirdparty/kernel/stable-queue.git] / releases / 4.9.149 / spi-bcm2835-fix-race-on-dma-termination.patch
CommitLineData
433ee529
GKH
1From e82b0b3828451c1cd331d9f304c6078fcd43b62e Mon Sep 17 00:00:00 2001
2From: Lukas Wunner <lukas@wunner.de>
3Date: Thu, 8 Nov 2018 08:06:10 +0100
4Subject: spi: bcm2835: Fix race on DMA termination
5MIME-Version: 1.0
6Content-Type: text/plain; charset=UTF-8
7Content-Transfer-Encoding: 8bit
8
9From: Lukas Wunner <lukas@wunner.de>
10
11commit e82b0b3828451c1cd331d9f304c6078fcd43b62e upstream.
12
13If a DMA transfer finishes orderly right when spi_transfer_one_message()
14determines that it has timed out, the callbacks bcm2835_spi_dma_done()
15and bcm2835_spi_handle_err() race to call dmaengine_terminate_all(),
16potentially leading to double termination.
17
18Prevent by atomically changing the dma_pending flag before calling
19dmaengine_terminate_all().
20
21Signed-off-by: Lukas Wunner <lukas@wunner.de>
22Fixes: 3ecd37edaa2a ("spi: bcm2835: enable dma modes for transfers meeting certain conditions")
23Cc: stable@vger.kernel.org # v4.2+
24Cc: Mathias Duckeck <m.duckeck@kunbus.de>
25Cc: Frank Pavlic <f.pavlic@kunbus.de>
26Cc: Martin Sperl <kernel@martin.sperl.org>
27Cc: Noralf Trønnes <noralf@tronnes.org>
28Signed-off-by: Mark Brown <broonie@kernel.org>
29Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
30
31---
32 drivers/spi/spi-bcm2835.c | 10 ++++------
33 1 file changed, 4 insertions(+), 6 deletions(-)
34
35--- a/drivers/spi/spi-bcm2835.c
36+++ b/drivers/spi/spi-bcm2835.c
37@@ -233,10 +233,9 @@ static void bcm2835_spi_dma_done(void *d
38 * is called the tx-dma must have finished - can't get to this
39 * situation otherwise...
40 */
41- dmaengine_terminate_all(master->dma_tx);
42-
43- /* mark as no longer pending */
44- bs->dma_pending = 0;
45+ if (cmpxchg(&bs->dma_pending, true, false)) {
46+ dmaengine_terminate_all(master->dma_tx);
47+ }
48
49 /* and mark as completed */;
50 complete(&master->xfer_completion);
51@@ -617,10 +616,9 @@ static void bcm2835_spi_handle_err(struc
52 struct bcm2835_spi *bs = spi_master_get_devdata(master);
53
54 /* if an error occurred and we have an active dma, then terminate */
55- if (bs->dma_pending) {
56+ if (cmpxchg(&bs->dma_pending, true, false)) {
57 dmaengine_terminate_all(master->dma_tx);
58 dmaengine_terminate_all(master->dma_rx);
59- bs->dma_pending = 0;
60 }
61 /* and reset */
62 bcm2835_spi_reset_hw(master);