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, 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 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, 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 } 154