All of lore.kernel.org
 help / color / mirror / Atom feed
From: Marc Kleine-Budde <mkl@pengutronix.de>
To: linux-spi@vger.kernel.org, Fabio Estevam <festevam@gmail.com>,
	Marek Vasut <marex@denx.de>
Cc: kernel@pengutronix.de, linux-imx@nxp.com,
	Mark Brown <broonie@kernel.org>,
	linux-arm-kernel@lists.infradead.org,
	Baruch Siach <baruch@tkos.co.il>,
	Marc Kleine-Budde <mkl@pengutronix.de>,
	David Jander <david@protonic.nl>
Subject: [PATCH v1 8/9] spi: spi-imx: add PIO polling support
Date: Mon,  2 May 2022 19:54:56 +0200	[thread overview]
Message-ID: <20220502175457.1977983-9-mkl@pengutronix.de> (raw)
In-Reply-To: <20220502175457.1977983-1-mkl@pengutronix.de>

The driver supports several modes, one of them is PIO/IRQ
"spi_imx_pio_transfer()". The data is exchanged with the IP core using
PIO, an IRQ is setup to signal empty/full FIFOs and the end of the
transfer. The IRQ and scheduling overhead for short transfers is
significant. Using polling instead of IRQs can be beneficial to reduce
the overall CPU load, especially on small transfer workloads.

On an imx6 single core, a given RX workload of the mcp251xfd driver
results in 40% CPU load. Using polling mode reduces the CPU load to
30%.

This patch adds PIO polling support to the driver. For transfers with
a duration of less than 30 µs the polling mode instead of IRQ based
PIO mode is used. 30 µs seems to be a good compromise, which is used
the by the SPI drivers for the raspberry Pi (spi-bcm2835,
spi-bcm2835), too.

Co-developed-by: David Jander <david@protonic.nl>
Signed-off-by: David Jander <david@protonic.nl>
Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
---
 drivers/spi/spi-imx.c | 66 +++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 66 insertions(+)

diff --git a/drivers/spi/spi-imx.c b/drivers/spi/spi-imx.c
index 894801ed182b..fe2305e6e38e 100644
--- a/drivers/spi/spi-imx.c
+++ b/drivers/spi/spi-imx.c
@@ -31,6 +31,12 @@ static bool use_dma = true;
 module_param(use_dma, bool, 0644);
 MODULE_PARM_DESC(use_dma, "Enable usage of DMA when available (default)");
 
+/* define polling limits */
+static unsigned int polling_limit_us = 30;
+module_param(polling_limit_us, uint, 0664);
+MODULE_PARM_DESC(polling_limit_us,
+		 "time in us to run a transfer in polling mode\n");
+
 #define MXC_RPM_TIMEOUT		2000 /* 2000ms */
 
 #define MXC_CSPIRXDATA		0x00
@@ -1488,6 +1494,54 @@ static int spi_imx_pio_transfer(struct spi_device *spi,
 	return 0;
 }
 
+static int spi_imx_poll_transfer(struct spi_device *spi,
+				 struct spi_transfer *transfer)
+{
+	struct spi_imx_data *spi_imx = spi_controller_get_devdata(spi->controller);
+	unsigned long timeout;
+
+	spi_imx->tx_buf = transfer->tx_buf;
+	spi_imx->rx_buf = transfer->rx_buf;
+	spi_imx->count = transfer->len;
+	spi_imx->txfifo = 0;
+	spi_imx->remainder = 0;
+
+	/* fill in the fifo before timeout calculations if we are
+	 * interrupted here, then the data is getting transferred by
+	 * the HW while we are interrupted
+	 */
+	spi_imx_push(spi_imx);
+
+	timeout = spi_imx_calculate_timeout(spi_imx, transfer->len) + jiffies;
+	while (spi_imx->txfifo) {
+		/* RX */
+		while (spi_imx->txfifo &&
+		       spi_imx->devtype_data->rx_available(spi_imx)) {
+			spi_imx->rx(spi_imx);
+			spi_imx->txfifo--;
+		}
+
+		/* TX */
+		if (spi_imx->count) {
+			spi_imx_push(spi_imx);
+			continue;
+		}
+
+		if (spi_imx->txfifo &&
+		    time_after(jiffies, timeout)) {
+
+			dev_err_ratelimited(&spi->dev,
+					    "timeout period reached: jiffies: %lu- falling back to interrupt mode\n",
+					    jiffies - timeout);
+
+			/* fall back to interrupt mode */
+			return spi_imx_pio_transfer(spi, transfer);
+		}
+	}
+
+	return 0;
+}
+
 static int spi_imx_pio_transfer_slave(struct spi_device *spi,
 				      struct spi_transfer *transfer)
 {
@@ -1537,6 +1591,7 @@ static int spi_imx_transfer_one(struct spi_controller *controller,
 				struct spi_transfer *transfer)
 {
 	struct spi_imx_data *spi_imx = spi_controller_get_devdata(spi->controller);
+	unsigned long hz_per_byte, byte_limit;
 
 	spi_imx_setupxfer(spi, transfer);
 	transfer->effective_speed_hz = spi_imx->spi_bus_clk;
@@ -1548,6 +1603,17 @@ static int spi_imx_transfer_one(struct spi_controller *controller,
 	if (spi_imx->slave_mode)
 		return spi_imx_pio_transfer_slave(spi, transfer);
 
+	/*
+	 * Calculate the estimated time in us the transfer runs. Find
+	 * the number of Hz per byte per polling limit.
+	 */
+	hz_per_byte = polling_limit_us ? ((8 + 4) * USEC_PER_SEC) / polling_limit_us : 0;
+	byte_limit = hz_per_byte ? transfer->effective_speed_hz / hz_per_byte : 1;
+
+	/* run in polling mode for short transfers */
+	if (transfer->len < byte_limit)
+		return spi_imx_poll_transfer(spi, transfer);
+
 	if (spi_imx->usedma)
 		return spi_imx_dma_transfer(spi_imx, transfer);
 
-- 
2.35.1



WARNING: multiple messages have this Message-ID
From: Marc Kleine-Budde <mkl@pengutronix.de>
To: linux-spi@vger.kernel.org, Fabio Estevam <festevam@gmail.com>,
	Marek Vasut <marex@denx.de>
Cc: kernel@pengutronix.de, linux-imx@nxp.com,
	Mark Brown <broonie@kernel.org>,
	linux-arm-kernel@lists.infradead.org,
	Baruch Siach <baruch@tkos.co.il>,
	Marc Kleine-Budde <mkl@pengutronix.de>,
	David Jander <david@protonic.nl>
Subject: [PATCH v1 8/9] spi: spi-imx: add PIO polling support
Date: Mon,  2 May 2022 19:54:56 +0200	[thread overview]
Message-ID: <20220502175457.1977983-9-mkl@pengutronix.de> (raw)
In-Reply-To: <20220502175457.1977983-1-mkl@pengutronix.de>

The driver supports several modes, one of them is PIO/IRQ
"spi_imx_pio_transfer()". The data is exchanged with the IP core using
PIO, an IRQ is setup to signal empty/full FIFOs and the end of the
transfer. The IRQ and scheduling overhead for short transfers is
significant. Using polling instead of IRQs can be beneficial to reduce
the overall CPU load, especially on small transfer workloads.

On an imx6 single core, a given RX workload of the mcp251xfd driver
results in 40% CPU load. Using polling mode reduces the CPU load to
30%.

This patch adds PIO polling support to the driver. For transfers with
a duration of less than 30 µs the polling mode instead of IRQ based
PIO mode is used. 30 µs seems to be a good compromise, which is used
the by the SPI drivers for the raspberry Pi (spi-bcm2835,
spi-bcm2835), too.

Co-developed-by: David Jander <david@protonic.nl>
Signed-off-by: David Jander <david@protonic.nl>
Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
---
 drivers/spi/spi-imx.c | 66 +++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 66 insertions(+)

diff --git a/drivers/spi/spi-imx.c b/drivers/spi/spi-imx.c
index 894801ed182b..fe2305e6e38e 100644
--- a/drivers/spi/spi-imx.c
+++ b/drivers/spi/spi-imx.c
@@ -31,6 +31,12 @@ static bool use_dma = true;
 module_param(use_dma, bool, 0644);
 MODULE_PARM_DESC(use_dma, "Enable usage of DMA when available (default)");
 
+/* define polling limits */
+static unsigned int polling_limit_us = 30;
+module_param(polling_limit_us, uint, 0664);
+MODULE_PARM_DESC(polling_limit_us,
+		 "time in us to run a transfer in polling mode\n");
+
 #define MXC_RPM_TIMEOUT		2000 /* 2000ms */
 
 #define MXC_CSPIRXDATA		0x00
@@ -1488,6 +1494,54 @@ static int spi_imx_pio_transfer(struct spi_device *spi,
 	return 0;
 }
 
+static int spi_imx_poll_transfer(struct spi_device *spi,
+				 struct spi_transfer *transfer)
+{
+	struct spi_imx_data *spi_imx = spi_controller_get_devdata(spi->controller);
+	unsigned long timeout;
+
+	spi_imx->tx_buf = transfer->tx_buf;
+	spi_imx->rx_buf = transfer->rx_buf;
+	spi_imx->count = transfer->len;
+	spi_imx->txfifo = 0;
+	spi_imx->remainder = 0;
+
+	/* fill in the fifo before timeout calculations if we are
+	 * interrupted here, then the data is getting transferred by
+	 * the HW while we are interrupted
+	 */
+	spi_imx_push(spi_imx);
+
+	timeout = spi_imx_calculate_timeout(spi_imx, transfer->len) + jiffies;
+	while (spi_imx->txfifo) {
+		/* RX */
+		while (spi_imx->txfifo &&
+		       spi_imx->devtype_data->rx_available(spi_imx)) {
+			spi_imx->rx(spi_imx);
+			spi_imx->txfifo--;
+		}
+
+		/* TX */
+		if (spi_imx->count) {
+			spi_imx_push(spi_imx);
+			continue;
+		}
+
+		if (spi_imx->txfifo &&
+		    time_after(jiffies, timeout)) {
+
+			dev_err_ratelimited(&spi->dev,
+					    "timeout period reached: jiffies: %lu- falling back to interrupt mode\n",
+					    jiffies - timeout);
+
+			/* fall back to interrupt mode */
+			return spi_imx_pio_transfer(spi, transfer);
+		}
+	}
+
+	return 0;
+}
+
 static int spi_imx_pio_transfer_slave(struct spi_device *spi,
 				      struct spi_transfer *transfer)
 {
@@ -1537,6 +1591,7 @@ static int spi_imx_transfer_one(struct spi_controller *controller,
 				struct spi_transfer *transfer)
 {
 	struct spi_imx_data *spi_imx = spi_controller_get_devdata(spi->controller);
+	unsigned long hz_per_byte, byte_limit;
 
 	spi_imx_setupxfer(spi, transfer);
 	transfer->effective_speed_hz = spi_imx->spi_bus_clk;
@@ -1548,6 +1603,17 @@ static int spi_imx_transfer_one(struct spi_controller *controller,
 	if (spi_imx->slave_mode)
 		return spi_imx_pio_transfer_slave(spi, transfer);
 
+	/*
+	 * Calculate the estimated time in us the transfer runs. Find
+	 * the number of Hz per byte per polling limit.
+	 */
+	hz_per_byte = polling_limit_us ? ((8 + 4) * USEC_PER_SEC) / polling_limit_us : 0;
+	byte_limit = hz_per_byte ? transfer->effective_speed_hz / hz_per_byte : 1;
+
+	/* run in polling mode for short transfers */
+	if (transfer->len < byte_limit)
+		return spi_imx_poll_transfer(spi, transfer);
+
 	if (spi_imx->usedma)
 		return spi_imx_dma_transfer(spi_imx, transfer);
 
-- 
2.35.1



_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

  parent reply	other threads:[~2022-05-02 18:02 UTC|newest]

Thread overview: 22+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2022-05-02 17:54 [PATCH v1 0/9] spi: spi-imx: cleanups and performance improvements Marc Kleine-Budde
2022-05-02 17:54 ` Marc Kleine-Budde
2022-05-02 17:54 ` [PATCH v1 1/9] spi: spi-imx: fix sparse warning: add identifier name to function definition Marc Kleine-Budde
2022-05-02 17:54   ` Marc Kleine-Budde
2022-05-02 17:54 ` [PATCH v1 2/9] spi: spi-imx: avoid unnecessary line continuations Marc Kleine-Budde
2022-05-02 17:54   ` Marc Kleine-Budde
2022-05-02 17:54 ` [PATCH v1 3/9] spi: spi-imx: mx51_ecspi_intctrl(): prefer 'unsigned int' to bare use of 'unsigned' Marc Kleine-Budde
2022-05-02 17:54   ` Marc Kleine-Budde
2022-05-02 17:54 ` [PATCH v1 4/9] spi: spi-imx: spi_imx_buf_rx_swap_u32(): fix sparse warning: use swab32s() instead of cpu_to_be32() Marc Kleine-Budde
2022-05-02 17:54   ` Marc Kleine-Budde
2022-05-02 17:54 ` [PATCH v1 5/9] spi: spi-imx: spi_imx_buf_rx_swap_u32(): replace open coded swahw32s() Marc Kleine-Budde
2022-05-02 17:54   ` Marc Kleine-Budde
2022-05-02 17:54 ` [PATCH v1 6/9] spi: spi-imx: complete conversion from master -> controller Marc Kleine-Budde
2022-05-02 17:54   ` Marc Kleine-Budde
2022-05-02 17:54 ` [PATCH v1 7/9] spi: spi-imx: replace struct spi_imx_data::bitbang by pointer to struct spi_controller Marc Kleine-Budde
2022-05-02 17:54   ` Marc Kleine-Budde
2022-05-02 17:54 ` Marc Kleine-Budde [this message]
2022-05-02 17:54   ` [PATCH v1 8/9] spi: spi-imx: add PIO polling support Marc Kleine-Budde
2022-05-02 17:54 ` [PATCH v1 9/9] spi: spi-imx: mx51_ecspi_prepare_message(): skip writing MX51_ECSPI_CONFIG register if unchanged Marc Kleine-Budde
2022-05-02 17:54   ` Marc Kleine-Budde
2022-05-09 21:13 ` [PATCH v1 0/9] spi: spi-imx: cleanups and performance improvements Mark Brown
2022-05-09 21:13   ` Mark Brown

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=20220502175457.1977983-9-mkl@pengutronix.de \
    --to=mkl@pengutronix.de \
    --cc=baruch@tkos.co.il \
    --cc=broonie@kernel.org \
    --cc=david@protonic.nl \
    --cc=festevam@gmail.com \
    --cc=kernel@pengutronix.de \
    --cc=linux-arm-kernel@lists.infradead.org \
    --cc=linux-imx@nxp.com \
    --cc=linux-spi@vger.kernel.org \
    --cc=marex@denx.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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.