This patch adds runtime configurable RX and TX ring parameters via ethtool to the driver. Link: https://lore.kernel.org/20220313083640.501791-8-mkl@xxxxxxxxxxxxxx Signed-off-by: Marc Kleine-Budde <mkl@xxxxxxxxxxxxxx> --- .../net/can/spi/mcp251xfd/mcp251xfd-ethtool.c | 37 +++++++++++- .../net/can/spi/mcp251xfd/mcp251xfd-ring.c | 59 ++++++++++++++----- drivers/net/can/spi/mcp251xfd/mcp251xfd.h | 9 +++ 3 files changed, 88 insertions(+), 17 deletions(-) diff --git a/drivers/net/can/spi/mcp251xfd/mcp251xfd-ethtool.c b/drivers/net/can/spi/mcp251xfd/mcp251xfd-ethtool.c index 4131185eaf5a..8825195fa05f 100644 --- a/drivers/net/can/spi/mcp251xfd/mcp251xfd-ethtool.c +++ b/drivers/net/can/spi/mcp251xfd/mcp251xfd-ethtool.c @@ -9,6 +9,7 @@ #include <linux/ethtool.h> #include "mcp251xfd.h" +#include "mcp251xfd-ram.h" static void mcp251xfd_ring_get_ringparam(struct net_device *ndev, @@ -17,19 +18,51 @@ mcp251xfd_ring_get_ringparam(struct net_device *ndev, struct netlink_ext_ack *extack) { const struct mcp251xfd_priv *priv = netdev_priv(ndev); + const bool fd_mode = mcp251xfd_is_fd_mode(priv); + struct can_ram_layout layout; - ring->rx_max_pending = MCP251XFD_RX_OBJ_NUM_MAX; - ring->tx_max_pending = MCP251XFD_TX_OBJ_NUM_MAX; + can_ram_get_layout(&layout, &mcp251xfd_ram_config, NULL, NULL, fd_mode); + ring->rx_max_pending = layout.max_rx; + ring->tx_max_pending = layout.max_tx; ring->rx_pending = priv->rx_obj_num; ring->tx_pending = priv->tx->obj_num; } +static int +mcp251xfd_ring_set_ringparam(struct net_device *ndev, + struct ethtool_ringparam *ring, + struct kernel_ethtool_ringparam *kernel_ring, + struct netlink_ext_ack *extack) +{ + struct mcp251xfd_priv *priv = netdev_priv(ndev); + const bool fd_mode = mcp251xfd_is_fd_mode(priv); + struct can_ram_layout layout; + + can_ram_get_layout(&layout, &mcp251xfd_ram_config, ring, NULL, fd_mode); + if ((layout.cur_rx != priv->rx_obj_num || + layout.cur_tx != priv->tx->obj_num) && + netif_running(ndev)) + return -EBUSY; + + priv->rx_obj_num = layout.cur_rx; + priv->tx->obj_num = layout.cur_tx; + + return 0; +} + static const struct ethtool_ops mcp251xfd_ethtool_ops = { .get_ringparam = mcp251xfd_ring_get_ringparam, + .set_ringparam = mcp251xfd_ring_set_ringparam, }; void mcp251xfd_ethtool_init(struct mcp251xfd_priv *priv) { + struct can_ram_layout layout; + priv->ndev->ethtool_ops = &mcp251xfd_ethtool_ops; + + 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; } diff --git a/drivers/net/can/spi/mcp251xfd/mcp251xfd-ring.c b/drivers/net/can/spi/mcp251xfd/mcp251xfd-ring.c index bb0e342c2d15..2ff4d4e803b0 100644 --- a/drivers/net/can/spi/mcp251xfd/mcp251xfd-ring.c +++ b/drivers/net/can/spi/mcp251xfd/mcp251xfd-ring.c @@ -15,6 +15,7 @@ #include <asm/unaligned.h> #include "mcp251xfd.h" +#include "mcp251xfd-ram.h" static inline u8 mcp251xfd_cmd_prepare_write_reg(const struct mcp251xfd_priv *priv, @@ -285,33 +286,63 @@ void mcp251xfd_ring_free(struct mcp251xfd_priv *priv) } } +const struct can_ram_config mcp251xfd_ram_config = { + .rx = { + .size[CAN_RAM_MODE_CAN] = sizeof(struct mcp251xfd_hw_rx_obj_can), + .size[CAN_RAM_MODE_CANFD] = sizeof(struct mcp251xfd_hw_rx_obj_canfd), + .min = MCP251XFD_RX_OBJ_NUM_MIN, + .max = MCP251XFD_RX_OBJ_NUM_MAX, + .def[CAN_RAM_MODE_CAN] = CAN_RAM_NUM_MAX, + .def[CAN_RAM_MODE_CANFD] = CAN_RAM_NUM_MAX, + .fifo_num = MCP251XFD_FIFO_RX_NUM, + .fifo_depth_min = MCP251XFD_RX_FIFO_DEPTH_MIN, + }, + .tx = { + .size[CAN_RAM_MODE_CAN] = sizeof(struct mcp251xfd_hw_tef_obj) + + sizeof(struct mcp251xfd_hw_tx_obj_can), + .size[CAN_RAM_MODE_CANFD] = sizeof(struct mcp251xfd_hw_tef_obj) + + sizeof(struct mcp251xfd_hw_tx_obj_canfd), + .min = MCP251XFD_TX_OBJ_NUM_MIN, + .max = MCP251XFD_TX_OBJ_NUM_MAX, + .def[CAN_RAM_MODE_CAN] = MCP251XFD_TX_OBJ_NUM_CAN_DEFAULT, + .def[CAN_RAM_MODE_CANFD] = MCP251XFD_TX_OBJ_NUM_CANFD_DEFAULT, + .fifo_num = MCP251XFD_FIFO_TX_NUM, + .fifo_depth_min = MCP251XFD_TX_FIFO_DEPTH_MIN, + }, + .size = MCP251XFD_RAM_SIZE, + .fifo_depth = MCP251XFD_FIFO_DEPTH, +}; + int mcp251xfd_ring_alloc(struct mcp251xfd_priv *priv) { - struct mcp251xfd_tx_ring *tx_ring; + const bool fd_mode = mcp251xfd_is_fd_mode(priv); + struct mcp251xfd_tx_ring *tx_ring = priv->tx; struct mcp251xfd_rx_ring *rx_ring; - u8 tef_obj_size, tx_obj_size, rx_obj_size; - u8 tx_obj_num; + u8 tx_obj_size, rx_obj_size; u8 rem, i; - tef_obj_size = sizeof(struct mcp251xfd_hw_tef_obj); - if (mcp251xfd_is_fd_mode(priv)) { - tx_obj_num = MCP251XFD_TX_OBJ_NUM_CANFD_DEFAULT; + /* switching from CAN-2.0 to CAN-FD mode or vice versa */ + if (fd_mode != test_bit(MCP251XFD_FLAGS_FD_MODE, priv->flags)) { + struct can_ram_layout layout; + + can_ram_get_layout(&layout, &mcp251xfd_ram_config, NULL, NULL, fd_mode); + priv->rx_obj_num = layout.default_rx; + tx_ring->obj_num = layout.default_tx; + } + + if (fd_mode) { tx_obj_size = sizeof(struct mcp251xfd_hw_tx_obj_canfd); rx_obj_size = sizeof(struct mcp251xfd_hw_rx_obj_canfd); + set_bit(MCP251XFD_FLAGS_FD_MODE, priv->flags); } else { - tx_obj_num = MCP251XFD_TX_OBJ_NUM_CAN_DEFAULT; tx_obj_size = sizeof(struct mcp251xfd_hw_tx_obj_can); rx_obj_size = sizeof(struct mcp251xfd_hw_rx_obj_can); + clear_bit(MCP251XFD_FLAGS_FD_MODE, priv->flags); } - priv->rx_obj_num = 0; - - tx_ring = priv->tx; - tx_ring->obj_num = tx_obj_num; tx_ring->obj_size = tx_obj_size; - rem = (MCP251XFD_RAM_SIZE - tx_obj_num * - (tef_obj_size + tx_obj_size)) / rx_obj_size; + rem = priv->rx_obj_num; for (i = 0; i < ARRAY_SIZE(priv->rx) && rem; i++) { u8 rx_obj_num; @@ -319,8 +350,6 @@ int mcp251xfd_ring_alloc(struct mcp251xfd_priv *priv) MCP251XFD_FIFO_DEPTH); rem -= rx_obj_num; - priv->rx_obj_num += rx_obj_num; - rx_ring = kzalloc(sizeof(*rx_ring) + rx_obj_size * rx_obj_num, GFP_KERNEL); if (!rx_ring) { diff --git a/drivers/net/can/spi/mcp251xfd/mcp251xfd.h b/drivers/net/can/spi/mcp251xfd/mcp251xfd.h index b1cc8d19438e..c61df2036fdf 100644 --- a/drivers/net/can/spi/mcp251xfd/mcp251xfd.h +++ b/drivers/net/can/spi/mcp251xfd/mcp251xfd.h @@ -582,6 +582,12 @@ struct mcp251xfd_devtype_data { u32 quirks; }; +enum mcp251xfd_flags { + MCP251XFD_FLAGS_FD_MODE, + + __MCP251XFD_FLAGS_SIZE__ +}; + struct mcp251xfd_priv { struct can_priv can; struct can_rx_offload offload; @@ -607,6 +613,8 @@ struct mcp251xfd_priv { struct mcp251xfd_rx_ring *rx[MCP251XFD_FIFO_RX_NUM]; struct mcp251xfd_tx_ring tx[MCP251XFD_FIFO_TX_NUM]; + DECLARE_BITMAP(flags, __MCP251XFD_FLAGS_SIZE__); + u8 rx_ring_num; u8 rx_obj_num; @@ -892,6 +900,7 @@ u16 mcp251xfd_crc16_compute2(const void *cmd, size_t cmd_size, u16 mcp251xfd_crc16_compute(const void *data, size_t data_size); void mcp251xfd_ethtool_init(struct mcp251xfd_priv *priv); int mcp251xfd_regmap_init(struct mcp251xfd_priv *priv); +extern const struct can_ram_config mcp251xfd_ram_config; int mcp251xfd_ring_init(struct mcp251xfd_priv *priv); void mcp251xfd_ring_free(struct mcp251xfd_priv *priv); int mcp251xfd_ring_alloc(struct mcp251xfd_priv *priv); -- 2.35.1