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

can: mcp251xfd: ram: add helper function for runtime ring size calculation

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: default avatarMarc Kleine-Budde <mkl@pengutronix.de>
parent c47675b1
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -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
+97 −0
Original line number Diff line number Diff line
// 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;
	}
}
+57 −0
Original line number Diff line number Diff line
/* 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