All of lore.kernel.org
 help / color / mirror / Atom feed
From: Marc Kleine-Budde <mkl@pengutronix.de>
To: linux-can@vger.kernel.org
Cc: kernel@pengutronix.de,
	Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>,
	Thomas Kopp <thomas.kopp@microchip.com>,
	Marc Kleine-Budde <mkl@pengutronix.de>
Subject: [can-next-rfc 08/12] can: mcp251xfd: add RX IRQ coalescing support
Date: Sun, 13 Mar 2022 09:36:36 +0100	[thread overview]
Message-ID: <20220313083640.501791-9-mkl@pengutronix.de> (raw)
In-Reply-To: <20220313083640.501791-1-mkl@pengutronix.de>

This patch adds RX IRQ coalescing support to the driver.

The mcp251xfd chip doesn't support proper hardware based coalescing,
so this patch tries to implemented it in software. The RX-FIFO offers
a "FIFO not empty" interrupt, which is used if no coalescing is
active.

With activated RX IRQ coalescing the "FIFO not empty" interrupt is
disabled in the RX IRQ handler and the "FIFO half full" or "FIFO full
interrupt" (depending on RX max coalesced frames IRQ) is used instead.
To avoid RX CAN frame starvation a hrtimer is setup with RX coalesce
usecs IRQ,on timer expiration the "FIFO not empty" is enabled again.

Support for ethtool configuration is added in the next patch.

Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
---
 .../net/can/spi/mcp251xfd/mcp251xfd-core.c    |   5 +
 .../net/can/spi/mcp251xfd/mcp251xfd-ethtool.c |   3 +
 .../net/can/spi/mcp251xfd/mcp251xfd-ring.c    | 103 ++++++++++++++++--
 drivers/net/can/spi/mcp251xfd/mcp251xfd-rx.c  |  12 +-
 drivers/net/can/spi/mcp251xfd/mcp251xfd.h     |  10 ++
 5 files changed, 123 insertions(+), 10 deletions(-)

diff --git a/drivers/net/can/spi/mcp251xfd/mcp251xfd-core.c b/drivers/net/can/spi/mcp251xfd/mcp251xfd-core.c
index ebb4dc999bac..325024be7b04 100644
--- a/drivers/net/can/spi/mcp251xfd/mcp251xfd-core.c
+++ b/drivers/net/can/spi/mcp251xfd/mcp251xfd-core.c
@@ -1598,6 +1598,7 @@ static int mcp251xfd_open(struct net_device *ndev)
 		goto out_transceiver_disable;
 
 	mcp251xfd_timestamp_init(priv);
+	clear_bit(MCP251XFD_FLAGS_DOWN, priv->flags);
 	can_rx_offload_enable(&priv->offload);
 
 	err = request_threaded_irq(spi->irq, NULL, mcp251xfd_irq,
@@ -1618,6 +1619,7 @@ static int mcp251xfd_open(struct net_device *ndev)
 	free_irq(spi->irq, priv);
  out_can_rx_offload_disable:
 	can_rx_offload_disable(&priv->offload);
+	set_bit(MCP251XFD_FLAGS_DOWN, priv->flags);
 	mcp251xfd_timestamp_stop(priv);
  out_transceiver_disable:
 	mcp251xfd_transceiver_disable(priv);
@@ -1637,6 +1639,8 @@ static int mcp251xfd_stop(struct net_device *ndev)
 	struct mcp251xfd_priv *priv = netdev_priv(ndev);
 
 	netif_stop_queue(ndev);
+	set_bit(MCP251XFD_FLAGS_DOWN, priv->flags);
+	hrtimer_cancel(&priv->rx_irq_timer);
 	mcp251xfd_chip_interrupts_disable(priv);
 	free_irq(ndev->irq, priv);
 	can_rx_offload_disable(&priv->offload);
@@ -2036,6 +2040,7 @@ static int mcp251xfd_probe(struct spi_device *spi)
 		CAN_CTRLMODE_LISTENONLY | CAN_CTRLMODE_BERR_REPORTING |
 		CAN_CTRLMODE_FD | CAN_CTRLMODE_FD_NON_ISO |
 		CAN_CTRLMODE_CC_LEN8_DLC;
+	set_bit(MCP251XFD_FLAGS_DOWN, priv->flags);
 	priv->ndev = ndev;
 	priv->spi = spi;
 	priv->rx_int = rx_int;
diff --git a/drivers/net/can/spi/mcp251xfd/mcp251xfd-ethtool.c b/drivers/net/can/spi/mcp251xfd/mcp251xfd-ethtool.c
index 8825195fa05f..8f14c9c08929 100644
--- a/drivers/net/can/spi/mcp251xfd/mcp251xfd-ethtool.c
+++ b/drivers/net/can/spi/mcp251xfd/mcp251xfd-ethtool.c
@@ -65,4 +65,7 @@ void mcp251xfd_ethtool_init(struct mcp251xfd_priv *priv)
 	can_ram_get_layout(&layout, &mcp251xfd_ram_config, NULL, NULL, false);
 	priv->rx_obj_num = layout.default_rx;
 	priv->tx->obj_num = layout.default_tx;
+
+	priv->rx_obj_num_coalesce_irq = 0;
+	priv->rx_coalesce_usecs_irq = 0;
 }
diff --git a/drivers/net/can/spi/mcp251xfd/mcp251xfd-ring.c b/drivers/net/can/spi/mcp251xfd/mcp251xfd-ring.c
index 2ff4d4e803b0..6dbbc5b8a069 100644
--- a/drivers/net/can/spi/mcp251xfd/mcp251xfd-ring.c
+++ b/drivers/net/can/spi/mcp251xfd/mcp251xfd-ring.c
@@ -182,8 +182,18 @@ mcp251xfd_ring_init_rx(struct mcp251xfd_priv *priv, u16 *base, u8 *fifo_nr)
 		*base = mcp251xfd_get_rx_obj_addr(rx_ring, rx_ring->obj_num);
 		*fifo_nr += 1;
 
-		/* FIFO increment RX tail pointer */
+		/* FIFO IRQ enable */
 		addr = MCP251XFD_REG_FIFOCON(rx_ring->fifo_nr);
+		val = MCP251XFD_REG_FIFOCON_RXOVIE |
+			MCP251XFD_REG_FIFOCON_TFNRFNIE;
+		len = mcp251xfd_cmd_prepare_write_reg(priv, &rx_ring->irq_enable_buf,
+						      addr, val, val);
+		rx_ring->irq_enable_xfer.tx_buf = &rx_ring->irq_enable_buf;
+		rx_ring->irq_enable_xfer.len = len;
+		spi_message_init_with_transfers(&rx_ring->irq_enable_msg,
+						&rx_ring->irq_enable_xfer, 1);
+
+		/* FIFO increment RX tail pointer */
 		val = MCP251XFD_REG_FIFOCON_UINC;
 		len = mcp251xfd_cmd_prepare_write_reg(priv, &rx_ring->uinc_buf,
 						      addr, val, val);
@@ -205,6 +215,39 @@ mcp251xfd_ring_init_rx(struct mcp251xfd_priv *priv, u16 *base, u8 *fifo_nr)
 		 * the chip select at the end of the message.
 		 */
 		xfer->cs_change = 0;
+
+		/* Use 1st RX-FIFO for IRQ coalescing. If enabled
+		 * (rx_coalesce_usecs_irq or rx_max_coalesce_frames_irq
+		 * is activated), use the last transfer to disable:
+		 *
+		 * - TFNRFNIE (Receive FIFO Not Empty Interrupt)
+		 *
+		 * and enable:
+		 *
+		 * - TFHRFHIE (Receive FIFO Half Full Interrupt)
+		 *   - or -
+		 * - TFERFFIE (Receive FIFO Full Interrupt)
+		 *
+		 * depending on rx_max_coalesce_frames_irq.
+		 *
+		 * The RXOVIE (Overflow Interrupt) is always enabled.
+		 */
+		if (rx_ring->nr == 0 && (priv->rx_coalesce_usecs_irq ||
+					 priv->rx_obj_num_coalesce_irq)) {
+			val = MCP251XFD_REG_FIFOCON_UINC |
+				MCP251XFD_REG_FIFOCON_RXOVIE;
+
+			if (priv->rx_obj_num_coalesce_irq == rx_ring->obj_num)
+				val |= MCP251XFD_REG_FIFOCON_TFERFFIE;
+			else if (priv->rx_obj_num_coalesce_irq)
+				val |= MCP251XFD_REG_FIFOCON_TFHRFHIE;
+
+			len = mcp251xfd_cmd_prepare_write_reg(priv,
+							      &rx_ring->uinc_irq_disable_buf,
+							      addr, val, val);
+			xfer->tx_buf = &rx_ring->uinc_irq_disable_buf;
+			xfer->len = len;
+		}
 	}
 }
 
@@ -246,12 +289,33 @@ int mcp251xfd_ring_init(struct mcp251xfd_priv *priv)
 		   priv->tx->obj_num * sizeof(struct mcp251xfd_hw_tef_obj));
 
 	mcp251xfd_for_each_rx_ring(priv, rx_ring, i) {
-		netdev_dbg(priv->ndev,
-			   "FIFO setup: RX-%u: FIFO %u/0x%03x: %2u*%u bytes = %4u bytes\n",
-			   rx_ring->nr, rx_ring->fifo_nr,
-			   mcp251xfd_get_rx_obj_addr(rx_ring, 0),
-			   rx_ring->obj_num, rx_ring->obj_size,
-			   rx_ring->obj_num * rx_ring->obj_size);
+		if (rx_ring->nr == 0 && priv->rx_obj_num_coalesce_irq) {
+			netdev_dbg(priv->ndev,
+				   "FIFO setup: RX-%u: FIFO %u/0x%03x: %2u*%u bytes = %4u bytes (coalesce)\n",
+				   rx_ring->nr, rx_ring->fifo_nr,
+				   mcp251xfd_get_rx_obj_addr(rx_ring, 0),
+				   priv->rx_obj_num_coalesce_irq, rx_ring->obj_size,
+				   priv->rx_obj_num_coalesce_irq * rx_ring->obj_size);
+
+			if (priv->rx_obj_num_coalesce_irq == MCP251XFD_FIFO_DEPTH)
+				continue;
+
+			netdev_dbg(priv->ndev,
+				   "                         0x%03x: %2u*%u bytes = %4u bytes\n",
+				   mcp251xfd_get_rx_obj_addr(rx_ring,
+							     priv->rx_obj_num_coalesce_irq),
+				   rx_ring->obj_num - priv->rx_obj_num_coalesce_irq,
+				   rx_ring->obj_size,
+				   (rx_ring->obj_num - priv->rx_obj_num_coalesce_irq) *
+				   rx_ring->obj_size);
+		} else {
+			netdev_dbg(priv->ndev,
+				   "FIFO setup: RX-%u: FIFO %u/0x%03x: %2u*%u bytes = %4u bytes\n",
+				   rx_ring->nr, rx_ring->fifo_nr,
+				   mcp251xfd_get_rx_obj_addr(rx_ring, 0),
+				   rx_ring->obj_num, rx_ring->obj_size,
+				   rx_ring->obj_num * rx_ring->obj_size);
+		}
 	}
 
 	netdev_dbg(priv->ndev,
@@ -286,6 +350,20 @@ void mcp251xfd_ring_free(struct mcp251xfd_priv *priv)
 	}
 }
 
+static enum hrtimer_restart mcp251xfd_rx_irq_timer(struct hrtimer *t)
+{
+	struct mcp251xfd_priv *priv = container_of(t, struct mcp251xfd_priv,
+						   rx_irq_timer);
+	struct mcp251xfd_rx_ring *ring = priv->rx[0];
+
+	if (test_bit(MCP251XFD_FLAGS_DOWN, priv->flags))
+		return HRTIMER_NORESTART;
+
+	spi_async(priv->spi, &ring->irq_enable_msg);
+
+	return HRTIMER_NORESTART;
+}
+
 const struct can_ram_config mcp251xfd_ram_config = {
 	.rx = {
 		.size[CAN_RAM_MODE_CAN] = sizeof(struct mcp251xfd_hw_rx_obj_can),
@@ -346,8 +424,12 @@ int mcp251xfd_ring_alloc(struct mcp251xfd_priv *priv)
 	for (i = 0; i < ARRAY_SIZE(priv->rx) && rem; i++) {
 		u8 rx_obj_num;
 
-		rx_obj_num = min_t(u8, rounddown_pow_of_two(rem),
-				   MCP251XFD_FIFO_DEPTH);
+		if (i == 0 && priv->rx_obj_num_coalesce_irq)
+			rx_obj_num = min_t(u8, priv->rx_obj_num_coalesce_irq * 2,
+					   MCP251XFD_FIFO_DEPTH);
+		else
+			rx_obj_num = min_t(u8, rounddown_pow_of_two(rem),
+					   MCP251XFD_FIFO_DEPTH);
 		rem -= rx_obj_num;
 
 		rx_ring = kzalloc(sizeof(*rx_ring) + rx_obj_size * rx_obj_num,
@@ -363,5 +445,8 @@ int mcp251xfd_ring_alloc(struct mcp251xfd_priv *priv)
 	}
 	priv->rx_ring_num = i;
 
+	hrtimer_init(&priv->rx_irq_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
+	priv->rx_irq_timer.function = mcp251xfd_rx_irq_timer;
+
 	return 0;
 }
diff --git a/drivers/net/can/spi/mcp251xfd/mcp251xfd-rx.c b/drivers/net/can/spi/mcp251xfd/mcp251xfd-rx.c
index e6d39876065a..d09f7fbf2ba7 100644
--- a/drivers/net/can/spi/mcp251xfd/mcp251xfd-rx.c
+++ b/drivers/net/can/spi/mcp251xfd/mcp251xfd-rx.c
@@ -254,7 +254,11 @@ int mcp251xfd_handle_rxif(struct mcp251xfd_priv *priv)
 	int err, n;
 
 	mcp251xfd_for_each_rx_ring(priv, ring, n) {
-		if (!(priv->regs_status.rxif & BIT(ring->fifo_nr)))
+		/* - if RX IRQ coalescing is active always handle ring 0
+		 * - only handle rings if RX IRQ is active
+		 */
+		if ((ring->nr > 0 || !priv->rx_obj_num_coalesce_irq) &&
+		    !(priv->regs_status.rxif & BIT(ring->fifo_nr)))
 			continue;
 
 		err = mcp251xfd_handle_rxif_ring(priv, ring);
@@ -262,5 +266,11 @@ int mcp251xfd_handle_rxif(struct mcp251xfd_priv *priv)
 			return err;
 	}
 
+	if (priv->rx_coalesce_usecs_irq)
+		hrtimer_start(&priv->rx_irq_timer,
+			      ns_to_ktime(priv->rx_coalesce_usecs_irq *
+					  NSEC_PER_USEC),
+			      HRTIMER_MODE_REL);
+
 	return 0;
 }
diff --git a/drivers/net/can/spi/mcp251xfd/mcp251xfd.h b/drivers/net/can/spi/mcp251xfd/mcp251xfd.h
index c61df2036fdf..ef4728039998 100644
--- a/drivers/net/can/spi/mcp251xfd/mcp251xfd.h
+++ b/drivers/net/can/spi/mcp251xfd/mcp251xfd.h
@@ -545,7 +545,12 @@ struct mcp251xfd_rx_ring {
 	u8 obj_num;
 	u8 obj_size;
 
+	union mcp251xfd_write_reg_buf irq_enable_buf;
+	struct spi_transfer irq_enable_xfer;
+	struct spi_message irq_enable_msg;
+
 	union mcp251xfd_write_reg_buf uinc_buf;
+	union mcp251xfd_write_reg_buf uinc_irq_disable_buf;
 	struct spi_transfer uinc_xfer[MCP251XFD_FIFO_DEPTH];
 	struct mcp251xfd_hw_rx_obj_canfd obj[];
 };
@@ -583,6 +588,7 @@ struct mcp251xfd_devtype_data {
 };
 
 enum mcp251xfd_flags {
+	MCP251XFD_FLAGS_DOWN,
 	MCP251XFD_FLAGS_FD_MODE,
 
 	__MCP251XFD_FLAGS_SIZE__
@@ -617,6 +623,10 @@ struct mcp251xfd_priv {
 
 	u8 rx_ring_num;
 	u8 rx_obj_num;
+	u8 rx_obj_num_coalesce_irq;
+
+	u32 rx_coalesce_usecs_irq;
+	struct hrtimer rx_irq_timer;
 
 	struct mcp251xfd_ecc ecc;
 	struct mcp251xfd_regs_status regs_status;
-- 
2.35.1



  parent reply	other threads:[~2022-03-13  8:37 UTC|newest]

Thread overview: 20+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2022-03-13  8:36 can-next 2022-03-13: mcp251xfd: add Marc Kleine-Budde
2022-03-13  8:36 ` [can-next-rfc 01/12] can: mcp251xfd: mcp251xfd_ring_init(): use %d to print free RAM Marc Kleine-Budde
2022-03-13  8:36 ` [can-next-rfc 02/12] can: mcp251xfd: ram: add helper function for runtime ring size calculation Marc Kleine-Budde
2022-03-13  8:36 ` [can-next-rfc 03/12] can: mcp251xfd: ram: coalescing support Marc Kleine-Budde
2022-03-13  8:36 ` [can-next-rfc 04/12] can: mcp251xfd: ethtool: add support Marc Kleine-Budde
2022-03-13  8:36 ` [can-next-rfc 05/12] can: mcp251xfd: ring: prepare support for runtime configurable RX/TX ring parameters Marc Kleine-Budde
2022-03-13  8:36 ` [can-next-rfc 06/12] can: mcp251xfd: update macros describing ring, FIFO and RAM layout Marc Kleine-Budde
2022-03-13  8:36 ` [can-next-rfc 07/12] can: mcp251xfd: ring: add support for runtime configurable RX/TX ring parameters Marc Kleine-Budde
2022-03-13  8:36 ` Marc Kleine-Budde [this message]
2022-03-13  8:36 ` [can-next-rfc 09/12] can: mcp251xfd: add RX IRQ coalescing ethtool support Marc Kleine-Budde
2022-03-13  8:36 ` [can-next-rfc 10/12] can: mcp251xfd: add TX IRQ coalesce support Marc Kleine-Budde
2022-03-13  8:36 ` [can-next-rfc 11/12] can: mcp251xfd: add TX IRQ coalesce ethtool support Marc Kleine-Budde
2022-03-13  8:36 ` [can-next-rfc 12/12] can: mcp251xfd: ring: increase number of RX-FIFOs to 3 and increase max TX-FIFO depth to 16 Marc Kleine-Budde
2022-03-23 13:28 ` can-next 2022-03-13: mcp251xfd: add Thomas.Kopp
2022-03-23 14:03   ` Marc Kleine-Budde
2022-03-23 15:00     ` Thomas.Kopp
2022-03-23 19:28       ` Marc Kleine-Budde
2022-03-24 12:28         ` Thomas.Kopp
2022-03-24 13:45           ` can-next 2022-03-13: mcp251xfd: add coalescing support Marc Kleine-Budde
2022-03-29  9:08 ` can-next 2022-03-13: mcp251xfd: add Thomas.Kopp

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=20220313083640.501791-9-mkl@pengutronix.de \
    --to=mkl@pengutronix.de \
    --cc=kernel@pengutronix.de \
    --cc=linux-can@vger.kernel.org \
    --cc=manivannan.sadhasivam@linaro.org \
    --cc=thomas.kopp@microchip.com \
    /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.