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 11 static 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 21 static u8 22 can_ram_rounddown_pow_of_two(const struct can_ram_config *config, 23 const struct can_ram_obj_config *obj, u8 val) 24 { 25 u8 fifo_num = obj->fifo_num; 26 u8 ret = 0, i; 27 28 val = can_ram_clamp(config, obj, val); 29 30 for (i = 0; i < fifo_num && val; i++) { 31 u8 n; 32 33 n = min_t(u8, rounddown_pow_of_two(val), 34 config->fifo_depth); 35 36 /* skip small FIFOs */ 37 if (n < obj->fifo_depth_min) 38 return ret; 39 40 ret += n; 41 val -= n; 42 } 43 44 return ret; 45 } 46 47 void can_ram_get_layout(struct can_ram_layout *layout, 48 const struct can_ram_config *config, 49 const struct ethtool_ringparam *ring, 50 const bool fd_mode) 51 { 52 u8 num_rx, num_tx; 53 u16 ram_free; 54 55 /* default CAN */ 56 57 num_tx = config->tx.def[fd_mode]; 58 num_tx = can_ram_rounddown_pow_of_two(config, &config->tx, num_tx); 59 60 ram_free = config->size; 61 ram_free -= config->tx.size[fd_mode] * num_tx; 62 63 num_rx = ram_free / config->rx.size[fd_mode]; 64 65 layout->default_rx = can_ram_rounddown_pow_of_two(config, &config->rx, num_rx); 66 layout->default_tx = num_tx; 67 68 /* MAX CAN */ 69 70 ram_free = config->size; 71 ram_free -= config->tx.size[fd_mode] * config->tx.min; 72 num_rx = ram_free / config->rx.size[fd_mode]; 73 74 ram_free = config->size; 75 ram_free -= config->rx.size[fd_mode] * config->rx.min; 76 num_tx = ram_free / config->tx.size[fd_mode]; 77 78 layout->max_rx = can_ram_rounddown_pow_of_two(config, &config->rx, num_rx); 79 layout->max_tx = can_ram_rounddown_pow_of_two(config, &config->tx, num_tx); 80 81 /* cur CAN */ 82 83 if (ring) { 84 num_rx = can_ram_rounddown_pow_of_two(config, &config->rx, ring->rx_pending); 85 86 ram_free = config->size - config->rx.size[fd_mode] * num_rx; 87 num_tx = ram_free / config->tx.size[fd_mode]; 88 num_tx = min_t(u8, ring->tx_pending, num_tx); 89 num_tx = can_ram_rounddown_pow_of_two(config, &config->tx, num_tx); 90 91 layout->cur_rx = num_rx; 92 layout->cur_tx = num_tx; 93 } else { 94 layout->cur_rx = layout->default_rx; 95 layout->cur_tx = layout->default_tx; 96 } 97 } 98