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 <linux/ethtool.h>
0010 
0011 #include "mcp251xfd.h"
0012 #include "mcp251xfd-ram.h"
0013 
0014 static void
0015 mcp251xfd_ring_get_ringparam(struct net_device *ndev,
0016                  struct ethtool_ringparam *ring,
0017                  struct kernel_ethtool_ringparam *kernel_ring,
0018                  struct netlink_ext_ack *extack)
0019 {
0020     const struct mcp251xfd_priv *priv = netdev_priv(ndev);
0021     const bool fd_mode = mcp251xfd_is_fd_mode(priv);
0022     struct can_ram_layout layout;
0023 
0024     can_ram_get_layout(&layout, &mcp251xfd_ram_config, NULL, NULL, fd_mode);
0025     ring->rx_max_pending = layout.max_rx;
0026     ring->tx_max_pending = layout.max_tx;
0027 
0028     ring->rx_pending = priv->rx_obj_num;
0029     ring->tx_pending = priv->tx->obj_num;
0030 }
0031 
0032 static int
0033 mcp251xfd_ring_set_ringparam(struct net_device *ndev,
0034                  struct ethtool_ringparam *ring,
0035                  struct kernel_ethtool_ringparam *kernel_ring,
0036                  struct netlink_ext_ack *extack)
0037 {
0038     struct mcp251xfd_priv *priv = netdev_priv(ndev);
0039     const bool fd_mode = mcp251xfd_is_fd_mode(priv);
0040     struct can_ram_layout layout;
0041 
0042     can_ram_get_layout(&layout, &mcp251xfd_ram_config, ring, NULL, fd_mode);
0043     if ((layout.cur_rx != priv->rx_obj_num ||
0044          layout.cur_tx != priv->tx->obj_num) &&
0045         netif_running(ndev))
0046         return -EBUSY;
0047 
0048     priv->rx_obj_num = layout.cur_rx;
0049     priv->rx_obj_num_coalesce_irq = layout.rx_coalesce;
0050     priv->tx->obj_num = layout.cur_tx;
0051 
0052     return 0;
0053 }
0054 
0055 static int mcp251xfd_ring_get_coalesce(struct net_device *ndev,
0056                        struct ethtool_coalesce *ec,
0057                        struct kernel_ethtool_coalesce *kec,
0058                        struct netlink_ext_ack *ext_ack)
0059 {
0060     struct mcp251xfd_priv *priv = netdev_priv(ndev);
0061     u32 rx_max_frames, tx_max_frames;
0062 
0063     /* The ethtool doc says:
0064      * To disable coalescing, set usecs = 0 and max_frames = 1.
0065      */
0066     if (priv->rx_obj_num_coalesce_irq == 0)
0067         rx_max_frames = 1;
0068     else
0069         rx_max_frames = priv->rx_obj_num_coalesce_irq;
0070 
0071     ec->rx_max_coalesced_frames_irq = rx_max_frames;
0072     ec->rx_coalesce_usecs_irq = priv->rx_coalesce_usecs_irq;
0073 
0074     if (priv->tx_obj_num_coalesce_irq == 0)
0075         tx_max_frames = 1;
0076     else
0077         tx_max_frames = priv->tx_obj_num_coalesce_irq;
0078 
0079     ec->tx_max_coalesced_frames_irq = tx_max_frames;
0080     ec->tx_coalesce_usecs_irq = priv->tx_coalesce_usecs_irq;
0081 
0082     return 0;
0083 }
0084 
0085 static int mcp251xfd_ring_set_coalesce(struct net_device *ndev,
0086                        struct ethtool_coalesce *ec,
0087                        struct kernel_ethtool_coalesce *kec,
0088                        struct netlink_ext_ack *ext_ack)
0089 {
0090     struct mcp251xfd_priv *priv = netdev_priv(ndev);
0091     const bool fd_mode = mcp251xfd_is_fd_mode(priv);
0092     const struct ethtool_ringparam ring = {
0093         .rx_pending = priv->rx_obj_num,
0094         .tx_pending = priv->tx->obj_num,
0095     };
0096     struct can_ram_layout layout;
0097 
0098     can_ram_get_layout(&layout, &mcp251xfd_ram_config, &ring, ec, fd_mode);
0099 
0100     if ((layout.rx_coalesce != priv->rx_obj_num_coalesce_irq ||
0101          ec->rx_coalesce_usecs_irq != priv->rx_coalesce_usecs_irq ||
0102          layout.tx_coalesce != priv->tx_obj_num_coalesce_irq ||
0103          ec->tx_coalesce_usecs_irq != priv->tx_coalesce_usecs_irq) &&
0104         netif_running(ndev))
0105         return -EBUSY;
0106 
0107     priv->rx_obj_num = layout.cur_rx;
0108     priv->rx_obj_num_coalesce_irq = layout.rx_coalesce;
0109     priv->rx_coalesce_usecs_irq = ec->rx_coalesce_usecs_irq;
0110 
0111     priv->tx->obj_num = layout.cur_tx;
0112     priv->tx_obj_num_coalesce_irq = layout.tx_coalesce;
0113     priv->tx_coalesce_usecs_irq = ec->tx_coalesce_usecs_irq;
0114 
0115     return 0;
0116 }
0117 
0118 static const struct ethtool_ops mcp251xfd_ethtool_ops = {
0119     .supported_coalesce_params = ETHTOOL_COALESCE_RX_USECS_IRQ |
0120         ETHTOOL_COALESCE_RX_MAX_FRAMES_IRQ |
0121         ETHTOOL_COALESCE_TX_USECS_IRQ |
0122         ETHTOOL_COALESCE_TX_MAX_FRAMES_IRQ,
0123     .get_ringparam = mcp251xfd_ring_get_ringparam,
0124     .set_ringparam = mcp251xfd_ring_set_ringparam,
0125     .get_coalesce = mcp251xfd_ring_get_coalesce,
0126     .set_coalesce = mcp251xfd_ring_set_coalesce,
0127     .get_ts_info = can_ethtool_op_get_ts_info_hwts,
0128 };
0129 
0130 void mcp251xfd_ethtool_init(struct mcp251xfd_priv *priv)
0131 {
0132     struct can_ram_layout layout;
0133 
0134     priv->ndev->ethtool_ops = &mcp251xfd_ethtool_ops;
0135 
0136     can_ram_get_layout(&layout, &mcp251xfd_ram_config, NULL, NULL, false);
0137     priv->rx_obj_num = layout.default_rx;
0138     priv->tx->obj_num = layout.default_tx;
0139 
0140     priv->rx_obj_num_coalesce_irq = 0;
0141     priv->tx_obj_num_coalesce_irq = 0;
0142     priv->rx_coalesce_usecs_irq = 0;
0143     priv->tx_coalesce_usecs_irq = 0;
0144 }