0001
0002
0003
0004
0005
0006
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
0064
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 }