Commit 9263c2e9 authored by Marc Kleine-Budde's avatar Marc Kleine-Budde
Browse files

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: default avatarMarc Kleine-Budde <mkl@pengutronix.de>
parent c9e6b80d
Loading
Loading
Loading
Loading
+35 −2
Original line number Diff line number Diff line
@@ -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;
}
+44 −15
Original line number Diff line number Diff line
@@ -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) {
+9 −0
Original line number Diff line number Diff line
@@ -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);