FILE
ethtool.c
File preview with syntax highlighting.
linux-6.19.14/drivers/net/ethernet/mellanox/mlx5/core/ipoib/ethtool.c
1/* 2 * Copyright (c) 2017, Mellanox Technologies. All rights reserved. 3 * 4 * This software is available to you under a choice of one of two 5 * licenses. You may choose to be licensed under the terms of the GNU 6 * General Public License (GPL) Version 2, available from the file 7 * COPYING in the main directory of this source tree, or the 8 * OpenIB.org BSD license below: 9 * 10 * Redistribution and use in source and binary forms, with or 11 * without modification, are permitted provided that the following 12 * conditions are met: 13 * 14 * - Redistributions of source code must retain the above 15 * copyright notice, this list of conditions and the following 16 * disclaimer. 17 * 18 * - Redistributions in binary form must reproduce the above 19 * copyright notice, this list of conditions and the following 20 * disclaimer in the documentation and/or other materials 21 * provided with the distribution. 22 * 23 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 24 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 25 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 26 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 27 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 28 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 29 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 30 * SOFTWARE. 31 */ 32 33#include "en.h" 34#include "ipoib.h" 35#include "en/fs_ethtool.h" 36 37static void mlx5i_get_drvinfo(struct net_device *dev, 38 struct ethtool_drvinfo *drvinfo) 39{ 40 struct mlx5e_priv *priv = mlx5i_epriv(dev); 41 42 mlx5e_ethtool_get_drvinfo(priv, drvinfo); 43 strscpy(drvinfo->driver, KBUILD_MODNAME "[ib_ipoib]", 44 sizeof(drvinfo->driver)); 45} 46 47static void mlx5i_get_strings(struct net_device *dev, u32 stringset, u8 *data) 48{ 49 struct mlx5e_priv *priv = mlx5i_epriv(dev); 50 51 mlx5e_ethtool_get_strings(priv, stringset, data); 52} 53 54static int mlx5i_get_sset_count(struct net_device *dev, int sset) 55{ 56 struct mlx5e_priv *priv = mlx5i_epriv(dev); 57 58 return mlx5e_ethtool_get_sset_count(priv, sset); 59} 60 61static void mlx5i_get_ethtool_stats(struct net_device *dev, 62 struct ethtool_stats *stats, 63 u64 *data) 64{ 65 struct mlx5e_priv *priv = mlx5i_epriv(dev); 66 67 mlx5e_ethtool_get_ethtool_stats(priv, stats, data); 68} 69 70static int mlx5i_set_ringparam(struct net_device *dev, 71 struct ethtool_ringparam *param, 72 struct kernel_ethtool_ringparam *kernel_param, 73 struct netlink_ext_ack *extack) 74{ 75 struct mlx5e_priv *priv = mlx5i_epriv(dev); 76 77 return mlx5e_ethtool_set_ringparam(priv, param, extack); 78} 79 80static void mlx5i_get_ringparam(struct net_device *dev, 81 struct ethtool_ringparam *param, 82 struct kernel_ethtool_ringparam *kernel_param, 83 struct netlink_ext_ack *extack) 84{ 85 struct mlx5e_priv *priv = mlx5i_epriv(dev); 86 87 mlx5e_ethtool_get_ringparam(priv, param, kernel_param); 88} 89 90static int mlx5i_set_channels(struct net_device *dev, 91 struct ethtool_channels *ch) 92{ 93 struct mlx5i_priv *ipriv = netdev_priv(dev); 94 struct mlx5e_priv *epriv = mlx5i_epriv(dev); 95 96 /* rtnl lock protects from race between this ethtool op and sub 97 * interface ndo_init/uninit. 98 */ 99 ASSERT_RTNL(); 100 if (ipriv->num_sub_interfaces > 0) { 101 mlx5_core_warn(epriv->mdev, 102 "can't change number of channels for interfaces with sub interfaces (%u)\n", 103 ipriv->num_sub_interfaces); 104 return -EINVAL; 105 } 106 107 return mlx5e_ethtool_set_channels(epriv, ch); 108} 109 110static void mlx5i_get_channels(struct net_device *dev, 111 struct ethtool_channels *ch) 112{ 113 struct mlx5e_priv *priv = mlx5i_epriv(dev); 114 115 mlx5e_ethtool_get_channels(priv, ch); 116} 117 118static int mlx5i_set_coalesce(struct net_device *netdev, 119 struct ethtool_coalesce *coal, 120 struct kernel_ethtool_coalesce *kernel_coal, 121 struct netlink_ext_ack *extack) 122{ 123 struct mlx5e_priv *priv = mlx5i_epriv(netdev); 124 125 return mlx5e_ethtool_set_coalesce(priv, coal, kernel_coal, extack); 126} 127 128static int mlx5i_get_coalesce(struct net_device *netdev, 129 struct ethtool_coalesce *coal, 130 struct kernel_ethtool_coalesce *kernel_coal, 131 struct netlink_ext_ack *extack) 132{ 133 struct mlx5e_priv *priv = mlx5i_epriv(netdev); 134 135 return mlx5e_ethtool_get_coalesce(priv, coal, kernel_coal, extack); 136} 137 138static int mlx5i_get_ts_info(struct net_device *netdev, 139 struct kernel_ethtool_ts_info *info) 140{ 141 struct mlx5e_priv *priv = mlx5i_epriv(netdev); 142 143 return mlx5e_ethtool_get_ts_info(priv, info); 144} 145 146static int mlx5i_flash_device(struct net_device *netdev, 147 struct ethtool_flash *flash) 148{ 149 struct mlx5e_priv *priv = mlx5i_epriv(netdev); 150 151 return mlx5e_ethtool_flash_device(priv, flash); 152} 153 154static inline int mlx5_ptys_width_enum_to_int(enum mlx5_ptys_width width) 155{ 156 switch (width) { 157 case MLX5_PTYS_WIDTH_1X: return 1; 158 case MLX5_PTYS_WIDTH_2X: return 2; 159 case MLX5_PTYS_WIDTH_4X: return 4; 160 case MLX5_PTYS_WIDTH_8X: return 8; 161 case MLX5_PTYS_WIDTH_12X: return 12; 162 default: return -1; 163 } 164} 165 166enum mlx5_ptys_rate { 167 MLX5_PTYS_RATE_SDR = 1 << 0, 168 MLX5_PTYS_RATE_DDR = 1 << 1, 169 MLX5_PTYS_RATE_QDR = 1 << 2, 170 MLX5_PTYS_RATE_FDR10 = 1 << 3, 171 MLX5_PTYS_RATE_FDR = 1 << 4, 172 MLX5_PTYS_RATE_EDR = 1 << 5, 173 MLX5_PTYS_RATE_HDR = 1 << 6, 174 MLX5_PTYS_RATE_NDR = 1 << 7, 175 MLX5_PTYS_RATE_XDR = 1 << 8, 176}; 177 178static inline int mlx5_ptys_rate_enum_to_int(enum mlx5_ptys_rate rate) 179{ 180 switch (rate) { 181 case MLX5_PTYS_RATE_SDR: return 2500; 182 case MLX5_PTYS_RATE_DDR: return 5000; 183 case MLX5_PTYS_RATE_QDR: 184 case MLX5_PTYS_RATE_FDR10: return 10000; 185 case MLX5_PTYS_RATE_FDR: return 14000; 186 case MLX5_PTYS_RATE_EDR: return 25000; 187 case MLX5_PTYS_RATE_HDR: return 50000; 188 case MLX5_PTYS_RATE_NDR: return 100000; 189 case MLX5_PTYS_RATE_XDR: return 200000; 190 default: return -1; 191 } 192} 193 194static u32 mlx5i_get_speed_settings(u16 ib_link_width_oper, u16 ib_proto_oper) 195{ 196 int rate, width; 197 198 rate = mlx5_ptys_rate_enum_to_int(ib_proto_oper); 199 if (rate < 0) 200 return SPEED_UNKNOWN; 201 width = mlx5_ptys_width_enum_to_int(ib_link_width_oper); 202 if (width < 0) 203 return SPEED_UNKNOWN; 204 205 return rate * width; 206} 207 208static int mlx5i_get_link_ksettings(struct net_device *netdev, 209 struct ethtool_link_ksettings *link_ksettings) 210{ 211 struct mlx5e_priv *priv = mlx5i_epriv(netdev); 212 struct mlx5_core_dev *mdev = priv->mdev; 213 u16 ib_link_width_oper; 214 u16 ib_proto_oper; 215 int speed, ret; 216 217 ret = mlx5_query_ib_port_oper(mdev, &ib_link_width_oper, &ib_proto_oper, 218 1, 0); 219 if (ret) 220 return ret; 221 222 ethtool_link_ksettings_zero_link_mode(link_ksettings, supported); 223 ethtool_link_ksettings_zero_link_mode(link_ksettings, advertising); 224 225 speed = mlx5i_get_speed_settings(ib_link_width_oper, ib_proto_oper); 226 link_ksettings->base.speed = speed; 227 link_ksettings->base.duplex = speed == SPEED_UNKNOWN ? DUPLEX_UNKNOWN : DUPLEX_FULL; 228 229 link_ksettings->base.port = PORT_OTHER; 230 231 link_ksettings->base.autoneg = AUTONEG_DISABLE; 232 233 return 0; 234} 235 236static u32 mlx5i_flow_type_mask(u32 flow_type) 237{ 238 return flow_type & ~(FLOW_EXT | FLOW_MAC_EXT | FLOW_RSS); 239} 240 241static int mlx5i_set_rxfh_fields(struct net_device *dev, 242 const struct ethtool_rxfh_fields *cmd, 243 struct netlink_ext_ack *extack) 244{ 245 struct mlx5e_priv *priv = mlx5i_epriv(dev); 246 247 return mlx5e_ethtool_set_rxfh_fields(priv, cmd, extack); 248} 249 250static int mlx5i_get_rxfh_fields(struct net_device *dev, 251 struct ethtool_rxfh_fields *info) 252{ 253 struct mlx5e_priv *priv = mlx5i_epriv(dev); 254 255 return mlx5e_ethtool_get_rxfh_fields(priv, info); 256} 257 258static int mlx5i_set_rxnfc(struct net_device *dev, struct ethtool_rxnfc *cmd) 259{ 260 struct mlx5e_priv *priv = mlx5i_epriv(dev); 261 struct ethtool_rx_flow_spec *fs = &cmd->fs; 262 263 if (mlx5i_flow_type_mask(fs->flow_type) == ETHER_FLOW) 264 return -EINVAL; 265 266 return mlx5e_ethtool_set_rxnfc(priv, cmd); 267} 268 269static u32 mlx5i_get_rx_ring_count(struct net_device *dev) 270{ 271 struct mlx5e_priv *priv = mlx5i_epriv(dev); 272 273 return priv->channels.params.num_channels; 274} 275 276static int mlx5i_get_rxnfc(struct net_device *dev, struct ethtool_rxnfc *info, 277 u32 *rule_locs) 278{ 279 struct mlx5e_priv *priv = mlx5i_epriv(dev); 280 281 return mlx5e_ethtool_get_rxnfc(priv, info, rule_locs); 282} 283 284const struct ethtool_ops mlx5i_ethtool_ops = { 285 .supported_coalesce_params = ETHTOOL_COALESCE_USECS | 286 ETHTOOL_COALESCE_MAX_FRAMES | 287 ETHTOOL_COALESCE_USE_ADAPTIVE, 288 .get_drvinfo = mlx5i_get_drvinfo, 289 .get_strings = mlx5i_get_strings, 290 .get_sset_count = mlx5i_get_sset_count, 291 .get_ethtool_stats = mlx5i_get_ethtool_stats, 292 .get_ringparam = mlx5i_get_ringparam, 293 .set_ringparam = mlx5i_set_ringparam, 294 .flash_device = mlx5i_flash_device, 295 .get_channels = mlx5i_get_channels, 296 .set_channels = mlx5i_set_channels, 297 .get_coalesce = mlx5i_get_coalesce, 298 .set_coalesce = mlx5i_set_coalesce, 299 .get_ts_info = mlx5i_get_ts_info, 300 .get_rxfh_fields = mlx5i_get_rxfh_fields, 301 .set_rxfh_fields = mlx5i_set_rxfh_fields, 302 .get_rxnfc = mlx5i_get_rxnfc, 303 .set_rxnfc = mlx5i_set_rxnfc, 304 .get_rx_ring_count = mlx5i_get_rx_ring_count, 305 .get_link_ksettings = mlx5i_get_link_ksettings, 306 .get_link = ethtool_op_get_link, 307}; 308 309const struct ethtool_ops mlx5i_pkey_ethtool_ops = { 310 .get_drvinfo = mlx5i_get_drvinfo, 311 .get_link = ethtool_op_get_link, 312 .get_ts_info = mlx5i_get_ts_info, 313};
~/
Read-only file preview.