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 /* If the ring parameters have been configured in 101 * CAN-CC mode, but and we are in CAN-FD mode now, 102 * they might be to big. Use the default CAN-FD values 103 * 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