Linux Audio

Check our new training course

Loading...
  1// SPDX-License-Identifier: GPL-2.0
  2//
  3// mcp251xfd - Microchip MCP251xFD Family CAN controller driver
  4//
  5// Copyright (c) 2021, 2022 Pengutronix,
  6//               Marc Kleine-Budde <kernel@pengutronix.de>
  7//
  8
  9#include "mcp251xfd-ram.h"
 10
 11static inline u8 can_ram_clamp(const struct can_ram_config *config,
 12			       const struct can_ram_obj_config *obj,
 13			       u8 val)
 14{
 15	u8 max;
 16
 17	max = min_t(u8, obj->max, obj->fifo_num * config->fifo_depth);
 18	return clamp(val, obj->min, max);
 19}
 20
 21static u8
 22can_ram_rounddown_pow_of_two(const struct can_ram_config *config,
 23			     const struct can_ram_obj_config *obj,
 24			     const u8 coalesce, u8 val)
 25{
 26	u8 fifo_num = obj->fifo_num;
 27	u8 ret = 0, i;
 28
 29	val = can_ram_clamp(config, obj, val);
 30
 31	if (coalesce) {
 32		/* Use 1st FIFO for coalescing, if requested.
 33		 *
 34		 * Either use complete FIFO (and FIFO Full IRQ) for
 35		 * coalescing or only half of FIFO (FIFO Half Full
 36		 * IRQ) and use remaining half for normal objects.
 37		 */
 38		ret = min_t(u8, coalesce * 2, config->fifo_depth);
 39		val -= ret;
 40		fifo_num--;
 41	}
 42
 43	for (i = 0; i < fifo_num && val; i++) {
 44		u8 n;
 45
 46		n = min_t(u8, rounddown_pow_of_two(val),
 47			  config->fifo_depth);
 48
 49		/* skip small FIFOs */
 50		if (n < obj->fifo_depth_min)
 51			return ret;
 52
 53		ret += n;
 54		val -= n;
 55	}
 56
 57	return ret;
 58}
 59
 60void can_ram_get_layout(struct can_ram_layout *layout,
 61			const struct can_ram_config *config,
 62			const struct ethtool_ringparam *ring,
 63			const struct ethtool_coalesce *ec,
 64			const bool fd_mode)
 65{
 66	u8 num_rx, num_tx;
 67	u16 ram_free;
 68
 69	/* default CAN */
 70
 71	num_tx = config->tx.def[fd_mode];
 72	num_tx = can_ram_rounddown_pow_of_two(config, &config->tx, 0, num_tx);
 73
 74	ram_free = config->size;
 75	ram_free -= config->tx.size[fd_mode] * num_tx;
 76
 77	num_rx = ram_free / config->rx.size[fd_mode];
 78
 79	layout->default_rx = can_ram_rounddown_pow_of_two(config, &config->rx, 0, num_rx);
 80	layout->default_tx = num_tx;
 81
 82	/* MAX CAN */
 83
 84	ram_free = config->size;
 85	ram_free -= config->tx.size[fd_mode] * config->tx.min;
 86	num_rx = ram_free / config->rx.size[fd_mode];
 87
 88	ram_free = config->size;
 89	ram_free -= config->rx.size[fd_mode] * config->rx.min;
 90	num_tx = ram_free / config->tx.size[fd_mode];
 91
 92	layout->max_rx = can_ram_rounddown_pow_of_two(config, &config->rx, 0, num_rx);
 93	layout->max_tx = can_ram_rounddown_pow_of_two(config, &config->tx, 0, num_tx);
 94
 95	/* cur CAN */
 96
 97	if (ring) {
 98		u8 num_rx_coalesce = 0, num_tx_coalesce = 0;
 99
100		num_rx = can_ram_rounddown_pow_of_two(config, &config->rx, 0, ring->rx_pending);
101
102		/* The ethtool doc says:
103		 * To disable coalescing, set usecs = 0 and max_frames = 1.
104		 */
105		if (ec && !(ec->rx_coalesce_usecs_irq == 0 &&
106			    ec->rx_max_coalesced_frames_irq == 1)) {
107			u8 max;
108
109			/* use only max half of available objects for coalescing */
110			max = min_t(u8, num_rx / 2, config->fifo_depth);
111			num_rx_coalesce = clamp(ec->rx_max_coalesced_frames_irq,
112						(u32)config->rx.fifo_depth_coalesce_min,
113						(u32)max);
114			num_rx_coalesce = rounddown_pow_of_two(num_rx_coalesce);
115
116			num_rx = can_ram_rounddown_pow_of_two(config, &config->rx,
117							      num_rx_coalesce, num_rx);
118		}
119
120		ram_free = config->size - config->rx.size[fd_mode] * num_rx;
121		num_tx = ram_free / config->tx.size[fd_mode];
122		num_tx = min_t(u8, ring->tx_pending, num_tx);
123		num_tx = can_ram_rounddown_pow_of_two(config, &config->tx, 0, num_tx);
124
125		/* The ethtool doc says:
126		 * To disable coalescing, set usecs = 0 and max_frames = 1.
127		 */
128		if (ec && !(ec->tx_coalesce_usecs_irq == 0 &&
129			    ec->tx_max_coalesced_frames_irq == 1)) {
130			u8 max;
131
132			/* use only max half of available objects for coalescing */
133			max = min_t(u8, num_tx / 2, config->fifo_depth);
134			num_tx_coalesce = clamp(ec->tx_max_coalesced_frames_irq,
135						(u32)config->tx.fifo_depth_coalesce_min,
136						(u32)max);
137			num_tx_coalesce = rounddown_pow_of_two(num_tx_coalesce);
138
139			num_tx = can_ram_rounddown_pow_of_two(config, &config->tx,
140							      num_tx_coalesce, num_tx);
141		}
142
143		layout->cur_rx = num_rx;
144		layout->cur_tx = num_tx;
145		layout->rx_coalesce = num_rx_coalesce;
146		layout->tx_coalesce = num_tx_coalesce;
147	} else {
148		layout->cur_rx = layout->default_rx;
149		layout->cur_tx = layout->default_tx;
150		layout->rx_coalesce = 0;
151		layout->tx_coalesce = 0;
152	}
153}