can: mcp251xfd: ram: coalescing support
authorMarc Kleine-Budde <mkl@pengutronix.de>
Tue, 16 Feb 2021 10:46:16 +0000 (11:46 +0100)
committerMarc Kleine-Budde <mkl@pengutronix.de>
Sun, 13 Mar 2022 08:45:35 +0000 (09:45 +0100)
This patch adds support for coalescing to the RAM layout calculation.

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

index 6e7293e50d2c05d999a2c41d823381bb2d7d11db..9e8e82cdba461242856293ffb936a0987e481e60 100644 (file)
@@ -20,13 +20,26 @@ static inline u8 can_ram_clamp(const struct can_ram_config *config,
 
 static u8
 can_ram_rounddown_pow_of_two(const struct can_ram_config *config,
-                            const struct can_ram_obj_config *obj, u8 val)
+                            const struct can_ram_obj_config *obj,
+                            const u8 coalesce, u8 val)
 {
        u8 fifo_num = obj->fifo_num;
        u8 ret = 0, i;
 
        val = can_ram_clamp(config, obj, val);
 
+       if (coalesce) {
+               /* Use 1st FIFO for coalescing, if requested.
+                *
+                * Either use complete FIFO (and FIFO Full IRQ) for
+                * coalescing or only half of FIFO (FIFO Half Full
+                * IRQ) and use remaining half for normal objects.
+                */
+               ret = min_t(u8, coalesce * 2, config->fifo_depth);
+               val -= ret;
+               fifo_num--;
+       }
+
        for (i = 0; i < fifo_num && val; i++) {
                u8 n;
 
@@ -47,6 +60,7 @@ can_ram_rounddown_pow_of_two(const struct can_ram_config *config,
 void can_ram_get_layout(struct can_ram_layout *layout,
                        const struct can_ram_config *config,
                        const struct ethtool_ringparam *ring,
+                       const struct ethtool_coalesce *ec,
                        const bool fd_mode)
 {
        u8 num_rx, num_tx;
@@ -55,14 +69,14 @@ void can_ram_get_layout(struct can_ram_layout *layout,
        /* default CAN */
 
        num_tx = config->tx.def[fd_mode];
-       num_tx = can_ram_rounddown_pow_of_two(config, &config->tx, num_tx);
+       num_tx = can_ram_rounddown_pow_of_two(config, &config->tx, 0, num_tx);
 
        ram_free = config->size;
        ram_free -= config->tx.size[fd_mode] * num_tx;
 
        num_rx = ram_free / config->rx.size[fd_mode];
 
-       layout->default_rx = can_ram_rounddown_pow_of_two(config, &config->rx, num_rx);
+       layout->default_rx = can_ram_rounddown_pow_of_two(config, &config->rx, 0, num_rx);
        layout->default_tx = num_tx;
 
        /* MAX CAN */
@@ -75,23 +89,65 @@ void can_ram_get_layout(struct can_ram_layout *layout,
        ram_free -= config->rx.size[fd_mode] * config->rx.min;
        num_tx = ram_free / config->tx.size[fd_mode];
 
-       layout->max_rx = can_ram_rounddown_pow_of_two(config, &config->rx, num_rx);
-       layout->max_tx = can_ram_rounddown_pow_of_two(config, &config->tx, num_tx);
+       layout->max_rx = can_ram_rounddown_pow_of_two(config, &config->rx, 0, num_rx);
+       layout->max_tx = can_ram_rounddown_pow_of_two(config, &config->tx, 0, num_tx);
 
        /* cur CAN */
 
        if (ring) {
-               num_rx = can_ram_rounddown_pow_of_two(config, &config->rx, ring->rx_pending);
+               u8 num_rx_coalesce = 0, num_tx_coalesce = 0;
+
+               num_rx = can_ram_rounddown_pow_of_two(config, &config->rx, 0, ring->rx_pending);
+
+               /* The ethtool doc says:
+                * To disable coalescing, set usecs = 0 and max_frames = 1.
+                */
+               if (ec && !(ec->rx_coalesce_usecs_irq == 0 &&
+                           ec->rx_max_coalesced_frames_irq == 1)) {
+                       u8 max;
+
+                       /* use only max half of available objects for coalescing */
+                       max = min_t(u8, num_rx / 2, config->fifo_depth);
+                       num_rx_coalesce = clamp(ec->rx_max_coalesced_frames_irq,
+                                               (u32)config->rx.fifo_depth_coalesce_min,
+                                               (u32)max);
+                       num_rx_coalesce = rounddown_pow_of_two(num_rx_coalesce);
+
+                       num_rx = can_ram_rounddown_pow_of_two(config, &config->rx,
+                                                             num_rx_coalesce, num_rx);
+               }
 
                ram_free = config->size - config->rx.size[fd_mode] * num_rx;
                num_tx = ram_free / config->tx.size[fd_mode];
                num_tx = min_t(u8, ring->tx_pending, num_tx);
-               num_tx = can_ram_rounddown_pow_of_two(config, &config->tx, num_tx);
+               num_tx = can_ram_rounddown_pow_of_two(config, &config->tx, 0, num_tx);
+
+               /* The ethtool doc says:
+                * To disable coalescing, set usecs = 0 and max_frames = 1.
+                */
+               if (ec && !(ec->tx_coalesce_usecs_irq == 0 &&
+                           ec->tx_max_coalesced_frames_irq == 1)) {
+                       u8 max;
+
+                       /* use only max half of available objects for coalescing */
+                       max = min_t(u8, num_tx / 2, config->fifo_depth);
+                       num_tx_coalesce = clamp(ec->tx_max_coalesced_frames_irq,
+                                               (u32)config->tx.fifo_depth_coalesce_min,
+                                               (u32)max);
+                       num_tx_coalesce = rounddown_pow_of_two(num_tx_coalesce);
+
+                       num_tx = can_ram_rounddown_pow_of_two(config, &config->tx,
+                                                             num_tx_coalesce, num_tx);
+               }
 
                layout->cur_rx = num_rx;
                layout->cur_tx = num_tx;
+               layout->rx_coalesce = num_rx_coalesce;
+               layout->tx_coalesce = num_tx_coalesce;
        } else {
                layout->cur_rx = layout->default_rx;
                layout->cur_tx = layout->default_tx;
+               layout->rx_coalesce = 0;
+               layout->tx_coalesce = 0;
        }
 }
index c998a033c9cb0673dda7100136ac022dd41433fd..7558c1510cbf29619498f8e74a61210f30a539c6 100644 (file)
@@ -28,6 +28,7 @@ struct can_ram_obj_config {
 
        u8 fifo_num;
        u8 fifo_depth_min;
+       u8 fifo_depth_coalesce_min;
 };
 
 struct can_ram_config {
@@ -47,11 +48,15 @@ struct can_ram_layout {
 
        u8 cur_rx;
        u8 cur_tx;
+
+       u8 rx_coalesce;
+       u8 tx_coalesce;
 };
 
 void can_ram_get_layout(struct can_ram_layout *layout,
                        const struct can_ram_config *config,
                        const struct ethtool_ringparam *ring,
+                       const struct ethtool_coalesce *ec,
                        const bool fd_mode);
 
 #endif