mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
From: Serge Semin <Sergey.Semin@baikalelectronics.ru>
To: Mark Brown <broonie@kernel.org>
Cc: Serge Semin <Sergey.Semin@baikalelectronics.ru>,
	Serge Semin <fancer.lancer@gmail.com>,
	Georgy Vlasov <Georgy.Vlasov@baikalelectronics.ru>,
	Ramil Zaripov <Ramil.Zaripov@baikalelectronics.ru>,
	Alexey Malahov <Alexey.Malahov@baikalelectronics.ru>,
	Thomas Bogendoerfer <tsbogend@alpha.franken.de>,
	Arnd Bergmann <arnd@arndb.de>, Feng Tang <feng.tang@intel.com>,
	Andy Shevchenko <andriy.shevchenko@linux.intel.com>,
	Rob Herring <robh+dt@kernel.org>, <linux-mips@vger.kernel.org>,
	<devicetree@vger.kernel.org>, <linux-spi@vger.kernel.org>,
	<linux-kernel@vger.kernel.org>
Subject: [PATCH v5 03/16] spi: dw: Locally wait for the DMA transactions completion
Date: Fri, 29 May 2020 06:59:01 +0300	[thread overview]
Message-ID: <20200529035915.20790-4-Sergey.Semin@baikalelectronics.ru> (raw)
In-Reply-To: <20200529035915.20790-1-Sergey.Semin@baikalelectronics.ru>

Even if DMA transactions are finished it doesn't mean that the SPI
transfers are also completed. It's specifically concerns the Tx-only
SPI transfers, since there might be data left in the SPI Tx FIFO after
the DMA engine notifies that the Tx DMA procedure is done. In order to
completely fix the problem first the driver has to wait for the DMA
transaction completion, then for the corresponding SPI operations to be
finished. In this commit we implement the former part of the solution.

Note we can't just move the SPI operations wait procedure to the DMA
completion callbacks, since these callbacks might be executed in the
tasklet context (and they will be in case of the DW DMA). In case of
slow SPI bus it can cause significant system performance drop.

Signed-off-by: Serge Semin <Sergey.Semin@baikalelectronics.ru>
Cc: Georgy Vlasov <Georgy.Vlasov@baikalelectronics.ru>
Cc: Ramil Zaripov <Ramil.Zaripov@baikalelectronics.ru>
Cc: Alexey Malahov <Alexey.Malahov@baikalelectronics.ru>
Cc: Thomas Bogendoerfer <tsbogend@alpha.franken.de>
Cc: Arnd Bergmann <arnd@arndb.de>
Cc: Feng Tang <feng.tang@intel.com>
Cc: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
Cc: Rob Herring <robh+dt@kernel.org>
Cc: linux-mips@vger.kernel.org
Cc: devicetree@vger.kernel.org
---
 drivers/spi/spi-dw-mid.c | 44 ++++++++++++++++++++++++++++++++++++----
 drivers/spi/spi-dw.h     |  2 ++
 2 files changed, 42 insertions(+), 4 deletions(-)

diff --git a/drivers/spi/spi-dw-mid.c b/drivers/spi/spi-dw-mid.c
index 7ff1acaa55f8..355b641c4483 100644
--- a/drivers/spi/spi-dw-mid.c
+++ b/drivers/spi/spi-dw-mid.c
@@ -11,9 +11,11 @@
 #include "spi-dw.h"
 
 #ifdef CONFIG_SPI_DW_MID_DMA
+#include <linux/completion.h>
 #include <linux/dma-mapping.h>
 #include <linux/dmaengine.h>
 #include <linux/irqreturn.h>
+#include <linux/jiffies.h>
 #include <linux/pci.h>
 #include <linux/platform_data/dma-dw.h>
 
@@ -66,6 +68,8 @@ static int mid_spi_dma_init_mfld(struct device *dev, struct dw_spi *dws)
 	dws->master->dma_rx = dws->rxchan;
 	dws->master->dma_tx = dws->txchan;
 
+	init_completion(&dws->dma_completion);
+
 	return 0;
 
 free_rxchan:
@@ -91,6 +95,8 @@ static int mid_spi_dma_init_generic(struct device *dev, struct dw_spi *dws)
 	dws->master->dma_rx = dws->rxchan;
 	dws->master->dma_tx = dws->txchan;
 
+	init_completion(&dws->dma_completion);
+
 	return 0;
 }
 
@@ -121,7 +127,7 @@ static irqreturn_t dma_transfer(struct dw_spi *dws)
 
 	dev_err(&dws->master->dev, "%s: FIFO overrun/underrun\n", __func__);
 	dws->master->cur_msg->status = -EIO;
-	spi_finalize_current_transfer(dws->master);
+	complete(&dws->dma_completion);
 	return IRQ_HANDLED;
 }
 
@@ -142,6 +148,29 @@ static enum dma_slave_buswidth convert_dma_width(u8 n_bytes) {
 	return DMA_SLAVE_BUSWIDTH_UNDEFINED;
 }
 
+static int dw_spi_dma_wait(struct dw_spi *dws, struct spi_transfer *xfer)
+{
+	unsigned long long ms;
+
+	ms = xfer->len * MSEC_PER_SEC * BITS_PER_BYTE;
+	do_div(ms, xfer->effective_speed_hz);
+	ms += ms + 200;
+
+	if (ms > UINT_MAX)
+		ms = UINT_MAX;
+
+	ms = wait_for_completion_timeout(&dws->dma_completion,
+					 msecs_to_jiffies(ms));
+
+	if (ms == 0) {
+		dev_err(&dws->master->cur_msg->spi->dev,
+			"DMA transaction timed out\n");
+		return -ETIMEDOUT;
+	}
+
+	return 0;
+}
+
 /*
  * dws->dma_chan_busy is set before the dma transfer starts, callback for tx
  * channel will clear a corresponding bit.
@@ -155,7 +184,7 @@ static void dw_spi_dma_tx_done(void *arg)
 		return;
 
 	dw_writel(dws, DW_SPI_DMACR, 0);
-	spi_finalize_current_transfer(dws->master);
+	complete(&dws->dma_completion);
 }
 
 static struct dma_async_tx_descriptor *dw_spi_dma_prepare_tx(struct dw_spi *dws,
@@ -204,7 +233,7 @@ static void dw_spi_dma_rx_done(void *arg)
 		return;
 
 	dw_writel(dws, DW_SPI_DMACR, 0);
-	spi_finalize_current_transfer(dws->master);
+	complete(&dws->dma_completion);
 }
 
 static struct dma_async_tx_descriptor *dw_spi_dma_prepare_rx(struct dw_spi *dws,
@@ -260,6 +289,8 @@ static int mid_spi_dma_setup(struct dw_spi *dws, struct spi_transfer *xfer)
 	/* Set the interrupt mask */
 	spi_umask_intr(dws, imr);
 
+	reinit_completion(&dws->dma_completion);
+
 	dws->transfer_handler = dma_transfer;
 
 	return 0;
@@ -268,6 +299,7 @@ static int mid_spi_dma_setup(struct dw_spi *dws, struct spi_transfer *xfer)
 static int mid_spi_dma_transfer(struct dw_spi *dws, struct spi_transfer *xfer)
 {
 	struct dma_async_tx_descriptor *txdesc, *rxdesc;
+	int ret;
 
 	/* Prepare the TX dma transfer */
 	txdesc = dw_spi_dma_prepare_tx(dws, xfer);
@@ -288,7 +320,11 @@ static int mid_spi_dma_transfer(struct dw_spi *dws, struct spi_transfer *xfer)
 		dma_async_issue_pending(dws->txchan);
 	}
 
-	return 1;
+	ret = dw_spi_dma_wait(dws, xfer);
+	if (ret)
+		return ret;
+
+	return 0;
 }
 
 static void mid_spi_dma_stop(struct dw_spi *dws)
diff --git a/drivers/spi/spi-dw.h b/drivers/spi/spi-dw.h
index 79782e93eb12..9585d0c83a6d 100644
--- a/drivers/spi/spi-dw.h
+++ b/drivers/spi/spi-dw.h
@@ -2,6 +2,7 @@
 #ifndef DW_SPI_HEADER_H
 #define DW_SPI_HEADER_H
 
+#include <linux/completion.h>
 #include <linux/irqreturn.h>
 #include <linux/io.h>
 #include <linux/scatterlist.h>
@@ -145,6 +146,7 @@ struct dw_spi {
 	unsigned long		dma_chan_busy;
 	dma_addr_t		dma_addr; /* phy address of the Data register */
 	const struct dw_spi_dma_ops *dma_ops;
+	struct completion	dma_completion;
 
 #ifdef CONFIG_DEBUG_FS
 	struct dentry *debugfs;
-- 
2.26.2


  parent reply	other threads:[~2020-05-29  3:59 UTC|newest]

Thread overview: 26+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2020-05-29  3:58 [PATCH v5 00/16] spi: dw: Add generic DW DMA controller support Serge Semin
2020-05-29  3:58 ` [PATCH v5 01/16] spi: dw: Set xfer effective_speed_hz Serge Semin
2020-05-29  8:49   ` Sergei Shtylyov
2020-05-29  9:49     ` Serge Semin
2020-05-29  3:59 ` [PATCH v5 02/16] spi: dw: Return any value retrieved from the dma_transfer callback Serge Semin
2020-05-29  3:59 ` Serge Semin [this message]
2020-05-29  7:55   ` [PATCH v5 03/16] spi: dw: Locally wait for the DMA transactions completion Andy Shevchenko
2020-05-29  8:12     ` Serge Semin
2020-05-29  9:26       ` Andy Shevchenko
2020-05-29  9:56         ` Serge Semin
2020-05-29  3:59 ` [PATCH v5 04/16] spi: dw: Add SPI Tx-done wait method to DMA-based transfer Serge Semin
2020-05-29  3:59 ` [PATCH v5 05/16] spi: dw: Add SPI Rx-done " Serge Semin
2020-05-29  9:46   ` Andy Shevchenko
2020-05-29 10:13     ` Serge Semin
2020-05-29 10:20       ` Andy Shevchenko
2020-05-29  3:59 ` [PATCH v5 06/16] spi: dw: Parameterize the DMA Rx/Tx burst length Serge Semin
2020-05-29  3:59 ` [PATCH v5 07/16] spi: dw: Use DMA max burst to set the request thresholds Serge Semin
2020-05-29  3:59 ` [PATCH v5 08/16] spi: dw: Fix Rx-only DMA transfers Serge Semin
2020-05-29  3:59 ` [PATCH v5 09/16] spi: dw: Add core suffix to the DW APB SSI core source file Serge Semin
2020-05-29  3:59 ` [PATCH v5 10/16] spi: dw: Move Non-DMA code to the DW PCIe-SPI driver Serge Semin
2020-05-29  3:59 ` [PATCH v5 11/16] spi: dw: Remove DW DMA code dependency from DW_DMAC_PCI Serge Semin
2020-05-29  3:59 ` [PATCH v5 12/16] spi: dw: Add DW SPI DMA/PCI/MMIO dependency on the DW SPI core Serge Semin
2020-05-29  3:59 ` [PATCH v5 13/16] spi: dw: Cleanup generic DW DMA code namings Serge Semin
2020-05-29  3:59 ` [PATCH v5 14/16] spi: dw: Add DMA support to the DW SPI MMIO driver Serge Semin
2020-05-29  3:59 ` [PATCH v5 15/16] spi: dw: Use regset32 DebugFS method to create regdump file Serge Semin
2020-05-29  3:59 ` [PATCH v5 16/16] dt-bindings: spi: Convert DW SPI binding to DT schema Serge Semin

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20200529035915.20790-4-Sergey.Semin@baikalelectronics.ru \
    --to=sergey.semin@baikalelectronics.ru \
    --cc=Alexey.Malahov@baikalelectronics.ru \
    --cc=Georgy.Vlasov@baikalelectronics.ru \
    --cc=Ramil.Zaripov@baikalelectronics.ru \
    --cc=andriy.shevchenko@linux.intel.com \
    --cc=arnd@arndb.de \
    --cc=broonie@kernel.org \
    --cc=devicetree@vger.kernel.org \
    --cc=fancer.lancer@gmail.com \
    --cc=feng.tang@intel.com \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-mips@vger.kernel.org \
    --cc=linux-spi@vger.kernel.org \
    --cc=robh+dt@kernel.org \
    --cc=tsbogend@alpha.franken.de \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox

all inboxes | Powered by JetHome®