OSDN Git Service

can: mcp251xfd: ram: add helper function for runtime ring size calculation
authorMarc Kleine-Budde <mkl@pengutronix.de>
Fri, 22 Oct 2021 17:11:57 +0000 (19:11 +0200)
committerMarc Kleine-Budde <mkl@pengutronix.de>
Sun, 13 Mar 2022 08:45:35 +0000 (09:45 +0100)
This patch adds a helper function to calculate the ring configuration
of the controller based on various constraints, like available RAM,
size of RX and TX objects, CAN-mode, number of FIFOs and FIFO depth.

Link: https://lore.kernel.org/20220313083640.501791-3-mkl@pengutronix.de
Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
drivers/net/can/spi/mcp251xfd/Makefile
drivers/net/can/spi/mcp251xfd/mcp251xfd-ram.c [new file with mode: 0644]
drivers/net/can/spi/mcp251xfd/mcp251xfd-ram.h [new file with mode: 0644]

index a83d685..10c4f88 100644 (file)
@@ -6,6 +6,7 @@ mcp251xfd-objs :=
 mcp251xfd-objs += mcp251xfd-chip-fifo.o
 mcp251xfd-objs += mcp251xfd-core.o
 mcp251xfd-objs += mcp251xfd-crc16.o
+mcp251xfd-objs += mcp251xfd-ram.o
 mcp251xfd-objs += mcp251xfd-regmap.o
 mcp251xfd-objs += mcp251xfd-ring.o
 mcp251xfd-objs += mcp251xfd-rx.o
diff --git a/drivers/net/can/spi/mcp251xfd/mcp251xfd-ram.c b/drivers/net/can/spi/mcp251xfd/mcp251xfd-ram.c
new file mode 100644 (file)
index 0000000..6e7293e
--- /dev/null
@@ -0,0 +1,97 @@
+// SPDX-License-Identifier: GPL-2.0
+//
+// mcp251xfd - Microchip MCP251xFD Family CAN controller driver
+//
+// Copyright (c) 2021, 2022 Pengutronix,
+//               Marc Kleine-Budde <kernel@pengutronix.de>
+//
+
+#include "mcp251xfd-ram.h"
+
+static inline u8 can_ram_clamp(const struct can_ram_config *config,
+                              const struct can_ram_obj_config *obj,
+                              u8 val)
+{
+       u8 max;
+
+       max = min_t(u8, obj->max, obj->fifo_num * config->fifo_depth);
+       return clamp(val, obj->min, max);
+}
+
+static u8
+can_ram_rounddown_pow_of_two(const struct can_ram_config *config,
+                            const struct can_ram_obj_config *obj, u8 val)
+{
+       u8 fifo_num = obj->fifo_num;
+       u8 ret = 0, i;
+
+       val = can_ram_clamp(config, obj, val);
+
+       for (i = 0; i < fifo_num && val; i++) {
+               u8 n;
+
+               n = min_t(u8, rounddown_pow_of_two(val),
+                         config->fifo_depth);
+
+               /* skip small FIFOs */
+               if (n < obj->fifo_depth_min)
+                       return ret;
+
+               ret += n;
+               val -= n;
+       }
+
+       return ret;
+}
+
+void can_ram_get_layout(struct can_ram_layout *layout,
+                       const struct can_ram_config *config,
+                       const struct ethtool_ringparam *ring,
+                       const bool fd_mode)
+{
+       u8 num_rx, num_tx;
+       u16 ram_free;
+
+       /* default CAN */
+
+       num_tx = config->tx.def[fd_mode];
+       num_tx = can_ram_rounddown_pow_of_two(config, &config->tx, 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_tx = num_tx;
+
+       /* MAX CAN */
+
+       ram_free = config->size;
+       ram_free -= config->tx.size[fd_mode] * config->tx.min;
+       num_rx = ram_free / config->rx.size[fd_mode];
+
+       ram_free = config->size;
+       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);
+
+       /* cur CAN */
+
+       if (ring) {
+               num_rx = can_ram_rounddown_pow_of_two(config, &config->rx, ring->rx_pending);
+
+               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);
+
+               layout->cur_rx = num_rx;
+               layout->cur_tx = num_tx;
+       } else {
+               layout->cur_rx = layout->default_rx;
+               layout->cur_tx = layout->default_tx;
+       }
+}
diff --git a/drivers/net/can/spi/mcp251xfd/mcp251xfd-ram.h b/drivers/net/can/spi/mcp251xfd/mcp251xfd-ram.h
new file mode 100644 (file)
index 0000000..c998a03
--- /dev/null
@@ -0,0 +1,57 @@
+/* SPDX-License-Identifier: GPL-2.0
+ *
+ * mcp251xfd - Microchip MCP251xFD Family CAN controller driver
+ *
+ * Copyright (c) 2021, 2022 Pengutronix,
+ *               Marc Kleine-Budde <kernel@pengutronix.de>
+ */
+
+#ifndef _MCP251XFD_RAM_H
+#define _MCP251XFD_RAM_H
+
+#include <linux/ethtool.h>
+
+#define CAN_RAM_NUM_MAX (-1)
+
+enum can_ram_mode {
+       CAN_RAM_MODE_CAN,
+       CAN_RAM_MODE_CANFD,
+       __CAN_RAM_MODE_MAX
+};
+
+struct can_ram_obj_config {
+       u8 size[__CAN_RAM_MODE_MAX];
+
+       u8 def[__CAN_RAM_MODE_MAX];
+       u8 min;
+       u8 max;
+
+       u8 fifo_num;
+       u8 fifo_depth_min;
+};
+
+struct can_ram_config {
+       const struct can_ram_obj_config rx;
+       const struct can_ram_obj_config tx;
+
+       u16 size;
+       u8 fifo_depth;
+};
+
+struct can_ram_layout {
+       u8 default_rx;
+       u8 default_tx;
+
+       u8 max_rx;
+       u8 max_tx;
+
+       u8 cur_rx;
+       u8 cur_tx;
+};
+
+void can_ram_get_layout(struct can_ram_layout *layout,
+                       const struct can_ram_config *config,
+                       const struct ethtool_ringparam *ring,
+                       const bool fd_mode);
+
+#endif