1 // SPDX-License-Identifier: GPL-2.0
3 // mcp251xfd - Microchip MCP251xFD Family CAN controller driver
5 // Copyright (c) 2021, 2022 Pengutronix,
9 #include "mcp251xfd-ram.h"
11 static inline u8 can_ram_clamp(const struct can_ram_config *config,
12 const struct can_ram_obj_config *obj,
17 max = min_t(u8, obj->max, obj->fifo_num * config->fifo_depth);
18 return clamp(val, obj->min, max);
22 can_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)
26 u8 fifo_num = obj->fifo_num;
29 val = can_ram_clamp(config, obj, val);
32 /* Use 1st FIFO for coalescing, if requested.
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.
38 ret = min_t(u8, coalesce * 2, config->fifo_depth);
43 for (i = 0; i < fifo_num && val; i++) {
46 n = min_t(u8, rounddown_pow_of_two(val),
49 /* skip small FIFOs */
50 if (n < obj->fifo_depth_min)
60 void 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,
71 num_tx = config->tx.def[fd_mode];
72 num_tx = can_ram_rounddown_pow_of_two(config, &config->tx, 0, num_tx);
74 ram_free = config->size;
75 ram_free -= config->tx.size[fd_mode] * num_tx;
77 num_rx = ram_free / config->rx.size[fd_mode];
79 layout->default_rx = can_ram_rounddown_pow_of_two(config, &config->rx, 0, num_rx);
80 layout->default_tx = num_tx;
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];
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];
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);
98 u8 num_rx_coalesce = 0, num_tx_coalesce = 0;
100 num_rx = can_ram_rounddown_pow_of_two(config, &config->rx, 0, ring->rx_pending);
102 /* The ethtool doc says:
103 * To disable coalescing, set usecs = 0 and max_frames = 1.
105 if (ec && !(ec->rx_coalesce_usecs_irq == 0 &&
106 ec->rx_max_coalesced_frames_irq == 1)) {
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,
114 num_rx_coalesce = rounddown_pow_of_two(num_rx_coalesce);
116 num_rx = can_ram_rounddown_pow_of_two(config, &config->rx,
117 num_rx_coalesce, num_rx);
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);
125 /* The ethtool doc says:
126 * To disable coalescing, set usecs = 0 and max_frames = 1.
128 if (ec && !(ec->tx_coalesce_usecs_irq == 0 &&
129 ec->tx_max_coalesced_frames_irq == 1)) {
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,
137 num_tx_coalesce = rounddown_pow_of_two(num_tx_coalesce);
139 num_tx = can_ram_rounddown_pow_of_two(config, &config->tx,
140 num_tx_coalesce, num_tx);
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;
148 layout->cur_rx = layout->default_rx;
149 layout->cur_tx = layout->default_tx;
150 layout->rx_coalesce = 0;
151 layout->tx_coalesce = 0;