123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153 |
- // SPDX-License-Identifier: GPL-2.0
- //
- // mcp251xfd - Microchip MCP251xFD Family CAN controller driver
- //
- // Copyright (c) 2021, 2022 Pengutronix,
- // Marc Kleine-Budde <[email protected]>
- //
- #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,
- const u8 coalesce, u8 val)
- {
- u8 fifo_num = obj->fifo_num;
- u8 ret = 0, i;
- val = can_ram_clamp(config, obj, val);
- if (coalesce) {
- /* Use 1st FIFO for coalescing, if requested.
- *
- * Either use complete FIFO (and FIFO Full IRQ) for
- * coalescing or only half of FIFO (FIFO Half Full
- * IRQ) and use remaining half for normal objects.
- */
- ret = min_t(u8, coalesce * 2, config->fifo_depth);
- val -= ret;
- fifo_num--;
- }
- 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 struct ethtool_coalesce *ec,
- 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, 0, 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, 0, 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, 0, num_rx);
- layout->max_tx = can_ram_rounddown_pow_of_two(config, &config->tx, 0, num_tx);
- /* cur CAN */
- if (ring) {
- u8 num_rx_coalesce = 0, num_tx_coalesce = 0;
- num_rx = can_ram_rounddown_pow_of_two(config, &config->rx, 0, ring->rx_pending);
- /* The ethtool doc says:
- * To disable coalescing, set usecs = 0 and max_frames = 1.
- */
- if (ec && !(ec->rx_coalesce_usecs_irq == 0 &&
- ec->rx_max_coalesced_frames_irq == 1)) {
- u8 max;
- /* use only max half of available objects for coalescing */
- max = min_t(u8, num_rx / 2, config->fifo_depth);
- num_rx_coalesce = clamp(ec->rx_max_coalesced_frames_irq,
- (u32)config->rx.fifo_depth_coalesce_min,
- (u32)max);
- num_rx_coalesce = rounddown_pow_of_two(num_rx_coalesce);
- num_rx = can_ram_rounddown_pow_of_two(config, &config->rx,
- num_rx_coalesce, num_rx);
- }
- 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, 0, num_tx);
- /* The ethtool doc says:
- * To disable coalescing, set usecs = 0 and max_frames = 1.
- */
- if (ec && !(ec->tx_coalesce_usecs_irq == 0 &&
- ec->tx_max_coalesced_frames_irq == 1)) {
- u8 max;
- /* use only max half of available objects for coalescing */
- max = min_t(u8, num_tx / 2, config->fifo_depth);
- num_tx_coalesce = clamp(ec->tx_max_coalesced_frames_irq,
- (u32)config->tx.fifo_depth_coalesce_min,
- (u32)max);
- num_tx_coalesce = rounddown_pow_of_two(num_tx_coalesce);
- num_tx = can_ram_rounddown_pow_of_two(config, &config->tx,
- num_tx_coalesce, num_tx);
- }
- layout->cur_rx = num_rx;
- layout->cur_tx = num_tx;
- layout->rx_coalesce = num_rx_coalesce;
- layout->tx_coalesce = num_tx_coalesce;
- } else {
- layout->cur_rx = layout->default_rx;
- layout->cur_tx = layout->default_tx;
- layout->rx_coalesce = 0;
- layout->tx_coalesce = 0;
- }
- }
|