can: mcp251xfd: ring: add support for runtime configurable RX/TX ring parameters

This patch adds runtime configurable RX and TX ring parameters via
ethtool to the driver.

Link: https://lore.kernel.org/20220313083640.501791-8-mkl@pengutronix.de
Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
This commit is contained in:
Marc Kleine-Budde 2021-10-25 11:34:32 +02:00
parent c9e6b80dfd
commit 9263c2e92b
3 changed files with 92 additions and 21 deletions

View File

@ -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;
}

View File

@ -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;
tx_obj_size = sizeof(struct mcp251xfd_hw_tx_obj_canfd);
rx_obj_size = sizeof(struct mcp251xfd_hw_rx_obj_canfd);
} 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);
/* 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;
}
priv->rx_obj_num = 0;
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_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);
}
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) {

View File

@ -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);