163 lines · c
1// SPDX-License-Identifier: GPL-2.02//3// mcp251xfd - Microchip MCP251xFD Family CAN controller driver4//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 u822can_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) for35 * coalescing or only half of FIFO (FIFO Half Full36 * 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 /* If the ring parameters have been configured in101 * CAN-CC mode, but and we are in CAN-FD mode now,102 * they might be to big. Use the default CAN-FD values103 * in this case.104 */105 num_rx = ring->rx_pending;106 if (num_rx > layout->max_rx)107 num_rx = layout->default_rx;108 109 num_rx = can_ram_rounddown_pow_of_two(config, &config->rx, 0, num_rx);110 111 /* The ethtool doc says:112 * To disable coalescing, set usecs = 0 and max_frames = 1.113 */114 if (ec && !(ec->rx_coalesce_usecs_irq == 0 &&115 ec->rx_max_coalesced_frames_irq == 1)) {116 u8 max;117 118 /* use only max half of available objects for coalescing */119 max = min_t(u8, num_rx / 2, config->fifo_depth);120 num_rx_coalesce = clamp(ec->rx_max_coalesced_frames_irq,121 (u32)config->rx.fifo_depth_coalesce_min,122 (u32)max);123 num_rx_coalesce = rounddown_pow_of_two(num_rx_coalesce);124 125 num_rx = can_ram_rounddown_pow_of_two(config, &config->rx,126 num_rx_coalesce, num_rx);127 }128 129 ram_free = config->size - config->rx.size[fd_mode] * num_rx;130 num_tx = ram_free / config->tx.size[fd_mode];131 num_tx = min_t(u8, ring->tx_pending, num_tx);132 num_tx = can_ram_rounddown_pow_of_two(config, &config->tx, 0, num_tx);133 134 /* The ethtool doc says:135 * To disable coalescing, set usecs = 0 and max_frames = 1.136 */137 if (ec && !(ec->tx_coalesce_usecs_irq == 0 &&138 ec->tx_max_coalesced_frames_irq == 1)) {139 u8 max;140 141 /* use only max half of available objects for coalescing */142 max = min_t(u8, num_tx / 2, config->fifo_depth);143 num_tx_coalesce = clamp(ec->tx_max_coalesced_frames_irq,144 (u32)config->tx.fifo_depth_coalesce_min,145 (u32)max);146 num_tx_coalesce = rounddown_pow_of_two(num_tx_coalesce);147 148 num_tx = can_ram_rounddown_pow_of_two(config, &config->tx,149 num_tx_coalesce, num_tx);150 }151 152 layout->cur_rx = num_rx;153 layout->cur_tx = num_tx;154 layout->rx_coalesce = num_rx_coalesce;155 layout->tx_coalesce = num_tx_coalesce;156 } else {157 layout->cur_rx = layout->default_rx;158 layout->cur_tx = layout->default_tx;159 layout->rx_coalesce = 0;160 layout->tx_coalesce = 0;161 }162}163