lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <20200529035915.20790-5-Sergey.Semin@baikalelectronics.ru>
Date:   Fri, 29 May 2020 06:59:02 +0300
From:   Serge Semin <Sergey.Semin@...kalelectronics.ru>
To:     Mark Brown <broonie@...nel.org>, Vinod Koul <vkoul@...nel.org>,
        Feng Tang <feng.tang@...el.com>,
        Linus Walleij <linus.walleij@...ricsson.com>,
        Alan Cox <alan@...ux.intel.com>,
        Grant Likely <grant.likely@...retlab.ca>
CC:     Serge Semin <Sergey.Semin@...kalelectronics.ru>,
        Serge Semin <fancer.lancer@...il.com>,
        Georgy Vlasov <Georgy.Vlasov@...kalelectronics.ru>,
        Ramil Zaripov <Ramil.Zaripov@...kalelectronics.ru>,
        Alexey Malahov <Alexey.Malahov@...kalelectronics.ru>,
        Thomas Bogendoerfer <tsbogend@...ha.franken.de>,
        Arnd Bergmann <arnd@...db.de>,
        Andy Shevchenko <andriy.shevchenko@...ux.intel.com>,
        Rob Herring <robh+dt@...nel.org>, <linux-mips@...r.kernel.org>,
        <devicetree@...r.kernel.org>, <linux-spi@...r.kernel.org>,
        <linux-kernel@...r.kernel.org>
Subject: [PATCH v5 04/16] spi: dw: Add SPI Tx-done wait method to DMA-based transfer

Since DMA transfers are performed asynchronously with actual SPI bus
transfers, then even if DMA transactions are finished it doesn't mean
all data is actually pushed to the SPI bus. Some data might still be
in the controller FIFO. This is specifically true for Tx-only transfers.
In this case if the next SPI transfer is recharged while a tail of the
previous one is still in FIFO, we'll loose that tail data. In order to
fix that problem let's add the wait procedure of the Tx SPI transfer
completion after the DMA transactions are finished.

Fixes: 7063c0d942a1 ("spi/dw_spi: add DMA support")
Co-developed-by: Georgy Vlasov <Georgy.Vlasov@...kalelectronics.ru>
Signed-off-by: Georgy Vlasov <Georgy.Vlasov@...kalelectronics.ru>
Signed-off-by: Serge Semin <Sergey.Semin@...kalelectronics.ru>
Cc: Ramil Zaripov <Ramil.Zaripov@...kalelectronics.ru>
Cc: Alexey Malahov <Alexey.Malahov@...kalelectronics.ru>
Cc: Thomas Bogendoerfer <tsbogend@...ha.franken.de>
Cc: Arnd Bergmann <arnd@...db.de>
Cc: Andy Shevchenko <andriy.shevchenko@...ux.intel.com>
Cc: Feng Tang <feng.tang@...el.com>
Cc: Rob Herring <robh+dt@...nel.org>
Cc: linux-mips@...r.kernel.org
Cc: devicetree@...r.kernel.org

---

Changelog v2:
- Use conditional statement instead of the ternary operator in the ref
  clock getter.
- Move the patch to the head of the series so one could be picked up to
  the stable kernels as a fix.

Changelog v3:
- Use spi_delay_exec() method to wait for the current operation completion.

Changelog v4:
- Get back ndelay() method to wait for an SPI transfer completion.
  spi_delay_exec() isn't suitable for the atomic context.

Changelog v5:
- Add more detailed description of the problems the patch fixes.
- Wait for the SPI Tx transfer finish in the mid_spi_dma_transfer() method
  executed in the task context.
- Use spi_delay_exec() to wait for the SPI Tx completion, since now the
  driver does in the kernel thread context.
- Use SPI_DELAY_UNIT_SCK spi_delay unit, since SPI xfer's are now have the
  effective_speed_hz initialized.
---
 drivers/spi/spi-dw-mid.c | 34 ++++++++++++++++++++++++++++++++++
 1 file changed, 34 insertions(+)

diff --git a/drivers/spi/spi-dw-mid.c b/drivers/spi/spi-dw-mid.c
index 355b641c4483..846e3db91329 100644
--- a/drivers/spi/spi-dw-mid.c
+++ b/drivers/spi/spi-dw-mid.c
@@ -19,6 +19,7 @@
 #include <linux/pci.h>
 #include <linux/platform_data/dma-dw.h>
 
+#define WAIT_RETRIES	5
 #define RX_BUSY		0
 #define TX_BUSY		1
 
@@ -171,6 +172,33 @@ static int dw_spi_dma_wait(struct dw_spi *dws, struct spi_transfer *xfer)
 	return 0;
 }
 
+static inline bool dw_spi_dma_tx_busy(struct dw_spi *dws)
+{
+	return !(dw_readl(dws, DW_SPI_SR) & SR_TF_EMPT);
+}
+
+static int dw_spi_dma_wait_tx_done(struct dw_spi *dws,
+				   struct spi_transfer *xfer)
+{
+	int retry = WAIT_RETRIES;
+	struct spi_delay delay;
+	u32 nents;
+
+	nents = dw_readl(dws, DW_SPI_TXFLR);
+	delay.unit = SPI_DELAY_UNIT_SCK;
+	delay.value = nents * dws->n_bytes * BITS_PER_BYTE;
+
+	while (dw_spi_dma_tx_busy(dws) && retry--)
+		spi_delay_exec(&delay, xfer);
+
+	if (retry < 0) {
+		dev_err(&dws->master->dev, "Tx hanged up\n");
+		return -EIO;
+	}
+
+	return 0;
+}
+
 /*
  * dws->dma_chan_busy is set before the dma transfer starts, callback for tx
  * channel will clear a corresponding bit.
@@ -324,6 +352,12 @@ static int mid_spi_dma_transfer(struct dw_spi *dws, struct spi_transfer *xfer)
 	if (ret)
 		return ret;
 
+	if (txdesc && dws->master->cur_msg->status == -EINPROGRESS) {
+		ret = dw_spi_dma_wait_tx_done(dws, xfer);
+		if (ret)
+			return ret;
+	}
+
 	return 0;
 }
 
-- 
2.26.2

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ