can: mcp251xfd: add TX IRQ coalescing support
authorMarc Kleine-Budde <mkl@pengutronix.de>
Mon, 15 Nov 2021 11:21:11 +0000 (12:21 +0100)
committerMarc Kleine-Budde <mkl@pengutronix.de>
Sun, 13 Mar 2022 08:45:36 +0000 (09:45 +0100)
This patch adds TX IRQ coalescing support to the driver.

The implemented algorithm is similar to the RX IRQ coalescing support
added in the previous patch.

Link: https://lore.kernel.org/20220313083640.501791-11-mkl@pengutronix.de
Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
drivers/net/can/spi/mcp251xfd/mcp251xfd-ring.c
drivers/net/can/spi/mcp251xfd/mcp251xfd-tef.c
drivers/net/can/spi/mcp251xfd/mcp251xfd.h

index f12a7aa8af1423620275d7fe2aae3b917bd971cd..3037ad3dd46be173c0897a35cd34da751e1f1ac1 100644 (file)
@@ -71,6 +71,17 @@ mcp251xfd_ring_init_tef(struct mcp251xfd_priv *priv, u16 *base)
        /* TEF- and TX-FIFO have same number of objects */
        *base = mcp251xfd_get_tef_obj_addr(priv->tx->obj_num);
 
+       /* FIFO IRQ enable */
+       addr = MCP251XFD_REG_TEFCON;
+       val = MCP251XFD_REG_TEFCON_TEFOVIE | MCP251XFD_REG_TEFCON_TEFNEIE;
+
+       len = mcp251xfd_cmd_prepare_write_reg(priv, &tef_ring->irq_enable_buf,
+                                             addr, val, val);
+       tef_ring->irq_enable_xfer.tx_buf = &tef_ring->irq_enable_buf;
+       tef_ring->irq_enable_xfer.len = len;
+       spi_message_init_with_transfers(&tef_ring->irq_enable_msg,
+                                       &tef_ring->irq_enable_xfer, 1);
+
        /* FIFO increment TEF tail pointer */
        addr = MCP251XFD_REG_TEFCON;
        val = MCP251XFD_REG_TEFCON_UINC;
@@ -94,6 +105,18 @@ mcp251xfd_ring_init_tef(struct mcp251xfd_priv *priv, u16 *base)
         * message.
         */
        xfer->cs_change = 0;
+
+       if (priv->tx_coalesce_usecs_irq || priv->tx_obj_num_coalesce_irq) {
+               val = MCP251XFD_REG_TEFCON_UINC |
+                       MCP251XFD_REG_TEFCON_TEFOVIE |
+                       MCP251XFD_REG_TEFCON_TEFHIE;
+
+               len = mcp251xfd_cmd_prepare_write_reg(priv,
+                                                     &tef_ring->uinc_irq_disable_buf,
+                                                     addr, val, val);
+               xfer->tx_buf = &tef_ring->uinc_irq_disable_buf;
+               xfer->len = len;
+       }
 }
 
 static void
@@ -282,11 +305,29 @@ int mcp251xfd_ring_init(struct mcp251xfd_priv *priv)
         */
        priv->regs_status.rxif = BIT(priv->rx[0]->fifo_nr);
 
-       netdev_dbg(priv->ndev,
-                  "FIFO setup: TEF:         0x%03x: %2d*%zu bytes = %4zu bytes\n",
-                  mcp251xfd_get_tef_obj_addr(0),
-                  priv->tx->obj_num, sizeof(struct mcp251xfd_hw_tef_obj),
-                  priv->tx->obj_num * sizeof(struct mcp251xfd_hw_tef_obj));
+       if (priv->tx_obj_num_coalesce_irq) {
+               netdev_dbg(priv->ndev,
+                          "FIFO setup: TEF:         0x%03x: %2d*%zu bytes = %4zu bytes (coalesce)\n",
+                          mcp251xfd_get_tef_obj_addr(0),
+                          priv->tx_obj_num_coalesce_irq,
+                          sizeof(struct mcp251xfd_hw_tef_obj),
+                          priv->tx_obj_num_coalesce_irq *
+                          sizeof(struct mcp251xfd_hw_tef_obj));
+
+               netdev_dbg(priv->ndev,
+                          "                         0x%03x: %2d*%zu bytes = %4zu bytes\n",
+                          mcp251xfd_get_tef_obj_addr(priv->tx_obj_num_coalesce_irq),
+                          priv->tx->obj_num - priv->tx_obj_num_coalesce_irq,
+                          sizeof(struct mcp251xfd_hw_tef_obj),
+                          (priv->tx->obj_num - priv->tx_obj_num_coalesce_irq) *
+                          sizeof(struct mcp251xfd_hw_tef_obj));
+       } else {
+               netdev_dbg(priv->ndev,
+                          "FIFO setup: TEF:         0x%03x: %2d*%zu bytes = %4zu bytes\n",
+                          mcp251xfd_get_tef_obj_addr(0),
+                          priv->tx->obj_num, sizeof(struct mcp251xfd_hw_tef_obj),
+                          priv->tx->obj_num * sizeof(struct mcp251xfd_hw_tef_obj));
+       }
 
        mcp251xfd_for_each_rx_ring(priv, rx_ring, i) {
                if (rx_ring->nr == 0 && priv->rx_obj_num_coalesce_irq) {
@@ -364,6 +405,20 @@ static enum hrtimer_restart mcp251xfd_rx_irq_timer(struct hrtimer *t)
        return HRTIMER_NORESTART;
 }
 
+static enum hrtimer_restart mcp251xfd_tx_irq_timer(struct hrtimer *t)
+{
+       struct mcp251xfd_priv *priv = container_of(t, struct mcp251xfd_priv,
+                                                  tx_irq_timer);
+       struct mcp251xfd_tef_ring *ring = priv->tef;
+
+       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),
@@ -449,5 +504,8 @@ int mcp251xfd_ring_alloc(struct mcp251xfd_priv *priv)
        hrtimer_init(&priv->rx_irq_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
        priv->rx_irq_timer.function = mcp251xfd_rx_irq_timer;
 
+       hrtimer_init(&priv->tx_irq_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
+       priv->tx_irq_timer.function = mcp251xfd_tx_irq_timer;
+
        return 0;
 }
index 406166005b99fe33992027a13554688b35cfa289..237617b0c125f49b66fc19ee413d135715a8ebf2 100644 (file)
@@ -256,5 +256,11 @@ int mcp251xfd_handle_tefif(struct mcp251xfd_priv *priv)
                netif_wake_queue(priv->ndev);
        }
 
+       if (priv->tx_coalesce_usecs_irq)
+               hrtimer_start(&priv->tx_irq_timer,
+                             ns_to_ktime(priv->tx_coalesce_usecs_irq *
+                                         NSEC_PER_USEC),
+                             HRTIMER_MODE_REL);
+
        return 0;
 }
index 8d912bacd2f153253d1e9b28dc45f153cf975ed6..ee2c93ddc5ede7d1738568c1374cb9e965c7655f 100644 (file)
@@ -518,7 +518,12 @@ struct mcp251xfd_tef_ring {
        /* u8 obj_num equals tx_ring->obj_num */
        /* u8 obj_size equals sizeof(struct mcp251xfd_hw_tef_obj) */
 
+       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_TX_OBJ_NUM_MAX];
 };
 
@@ -625,9 +630,12 @@ struct mcp251xfd_priv {
        u8 rx_ring_num;
        u8 rx_obj_num;
        u8 rx_obj_num_coalesce_irq;
+       u8 tx_obj_num_coalesce_irq;
 
        u32 rx_coalesce_usecs_irq;
+       u32 tx_coalesce_usecs_irq;
        struct hrtimer rx_irq_timer;
+       struct hrtimer tx_irq_timer;
 
        struct mcp251xfd_ecc ecc;
        struct mcp251xfd_regs_status regs_status;