Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 //
0003 // mcp251xfd - Microchip MCP251xFD Family CAN controller driver
0004 //
0005 // Copyright (c) 2021, 2022 Pengutronix,
0006 //               Marc Kleine-Budde <kernel@pengutronix.de>
0007 //
0008 
0009 #include "mcp251xfd-ram.h"
0010 
0011 static inline u8 can_ram_clamp(const struct can_ram_config *config,
0012                    const struct can_ram_obj_config *obj,
0013                    u8 val)
0014 {
0015     u8 max;
0016 
0017     max = min_t(u8, obj->max, obj->fifo_num * config->fifo_depth);
0018     return clamp(val, obj->min, max);
0019 }
0020 
0021 static u8
0022 can_ram_rounddown_pow_of_two(const struct can_ram_config *config,
0023                  const struct can_ram_obj_config *obj,
0024                  const u8 coalesce, u8 val)
0025 {
0026     u8 fifo_num = obj->fifo_num;
0027     u8 ret = 0, i;
0028 
0029     val = can_ram_clamp(config, obj, val);
0030 
0031     if (coalesce) {
0032         /* Use 1st FIFO for coalescing, if requested.
0033          *
0034          * Either use complete FIFO (and FIFO Full IRQ) for
0035          * coalescing or only half of FIFO (FIFO Half Full
0036          * IRQ) and use remaining half for normal objects.
0037          */
0038         ret = min_t(u8, coalesce * 2, config->fifo_depth);
0039         val -= ret;
0040         fifo_num--;
0041     }
0042 
0043     for (i = 0; i < fifo_num && val; i++) {
0044         u8 n;
0045 
0046         n = min_t(u8, rounddown_pow_of_two(val),
0047               config->fifo_depth);
0048 
0049         /* skip small FIFOs */
0050         if (n < obj->fifo_depth_min)
0051             return ret;
0052 
0053         ret += n;
0054         val -= n;
0055     }
0056 
0057     return ret;
0058 }
0059 
0060 void can_ram_get_layout(struct can_ram_layout *layout,
0061             const struct can_ram_config *config,
0062             const struct ethtool_ringparam *ring,
0063             const struct ethtool_coalesce *ec,
0064             const bool fd_mode)
0065 {
0066     u8 num_rx, num_tx;
0067     u16 ram_free;
0068 
0069     /* default CAN */
0070 
0071     num_tx = config->tx.def[fd_mode];
0072     num_tx = can_ram_rounddown_pow_of_two(config, &config->tx, 0, num_tx);
0073 
0074     ram_free = config->size;
0075     ram_free -= config->tx.size[fd_mode] * num_tx;
0076 
0077     num_rx = ram_free / config->rx.size[fd_mode];
0078 
0079     layout->default_rx = can_ram_rounddown_pow_of_two(config, &config->rx, 0, num_rx);
0080     layout->default_tx = num_tx;
0081 
0082     /* MAX CAN */
0083 
0084     ram_free = config->size;
0085     ram_free -= config->tx.size[fd_mode] * config->tx.min;
0086     num_rx = ram_free / config->rx.size[fd_mode];
0087 
0088     ram_free = config->size;
0089     ram_free -= config->rx.size[fd_mode] * config->rx.min;
0090     num_tx = ram_free / config->tx.size[fd_mode];
0091 
0092     layout->max_rx = can_ram_rounddown_pow_of_two(config, &config->rx, 0, num_rx);
0093     layout->max_tx = can_ram_rounddown_pow_of_two(config, &config->tx, 0, num_tx);
0094 
0095     /* cur CAN */
0096 
0097     if (ring) {
0098         u8 num_rx_coalesce = 0, num_tx_coalesce = 0;
0099 
0100         num_rx = can_ram_rounddown_pow_of_two(config, &config->rx, 0, ring->rx_pending);
0101 
0102         /* The ethtool doc says:
0103          * To disable coalescing, set usecs = 0 and max_frames = 1.
0104          */
0105         if (ec && !(ec->rx_coalesce_usecs_irq == 0 &&
0106                 ec->rx_max_coalesced_frames_irq == 1)) {
0107             u8 max;
0108 
0109             /* use only max half of available objects for coalescing */
0110             max = min_t(u8, num_rx / 2, config->fifo_depth);
0111             num_rx_coalesce = clamp(ec->rx_max_coalesced_frames_irq,
0112                         (u32)config->rx.fifo_depth_coalesce_min,
0113                         (u32)max);
0114             num_rx_coalesce = rounddown_pow_of_two(num_rx_coalesce);
0115 
0116             num_rx = can_ram_rounddown_pow_of_two(config, &config->rx,
0117                                   num_rx_coalesce, num_rx);
0118         }
0119 
0120         ram_free = config->size - config->rx.size[fd_mode] * num_rx;
0121         num_tx = ram_free / config->tx.size[fd_mode];
0122         num_tx = min_t(u8, ring->tx_pending, num_tx);
0123         num_tx = can_ram_rounddown_pow_of_two(config, &config->tx, 0, num_tx);
0124 
0125         /* The ethtool doc says:
0126          * To disable coalescing, set usecs = 0 and max_frames = 1.
0127          */
0128         if (ec && !(ec->tx_coalesce_usecs_irq == 0 &&
0129                 ec->tx_max_coalesced_frames_irq == 1)) {
0130             u8 max;
0131 
0132             /* use only max half of available objects for coalescing */
0133             max = min_t(u8, num_tx / 2, config->fifo_depth);
0134             num_tx_coalesce = clamp(ec->tx_max_coalesced_frames_irq,
0135                         (u32)config->tx.fifo_depth_coalesce_min,
0136                         (u32)max);
0137             num_tx_coalesce = rounddown_pow_of_two(num_tx_coalesce);
0138 
0139             num_tx = can_ram_rounddown_pow_of_two(config, &config->tx,
0140                                   num_tx_coalesce, num_tx);
0141         }
0142 
0143         layout->cur_rx = num_rx;
0144         layout->cur_tx = num_tx;
0145         layout->rx_coalesce = num_rx_coalesce;
0146         layout->tx_coalesce = num_tx_coalesce;
0147     } else {
0148         layout->cur_rx = layout->default_rx;
0149         layout->cur_tx = layout->default_tx;
0150         layout->rx_coalesce = 0;
0151         layout->tx_coalesce = 0;
0152     }
0153 }