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); 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); 136} 137 138static int mlx5i_get_ts_info(struct net_device *netdev, 139 struct 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); 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_rxnfc(struct net_device *dev, struct ethtool_rxnfc *cmd) 242{ 243 struct mlx5e_priv *priv = mlx5i_epriv(dev); 244 struct ethtool_rx_flow_spec *fs = &cmd->fs; 245 246 if (mlx5i_flow_type_mask(fs->flow_type) == ETHER_FLOW) 247 return -EINVAL; 248 249 return mlx5e_ethtool_set_rxnfc(priv, cmd); 250} 251 252static int mlx5i_get_rxnfc(struct net_device *dev, struct ethtool_rxnfc *info, 253 u32 *rule_locs) 254{ 255 struct mlx5e_priv *priv = mlx5i_epriv(dev); 256 257 /* ETHTOOL_GRXRINGS is needed by ethtool -x which is not part 258 * of rxnfc. We keep this logic out of mlx5e_ethtool_get_rxnfc, 259 * to avoid breaking "ethtool -x" when mlx5e_ethtool_get_rxnfc 260 * is compiled out via CONFIG_MLX5_EN_RXNFC=n. 261 */ 262 if (info->cmd == ETHTOOL_GRXRINGS) { 263 info->data = priv->channels.params.num_channels; 264 return 0; 265 } 266 267 return mlx5e_ethtool_get_rxnfc(priv, info, rule_locs); 268} 269 270const struct ethtool_ops mlx5i_ethtool_ops = { 271 .supported_coalesce_params = ETHTOOL_COALESCE_USECS | 272 ETHTOOL_COALESCE_MAX_FRAMES | 273 ETHTOOL_COALESCE_USE_ADAPTIVE, 274 .get_drvinfo = mlx5i_get_drvinfo, 275 .get_strings = mlx5i_get_strings, 276 .get_sset_count = mlx5i_get_sset_count, 277 .get_ethtool_stats = mlx5i_get_ethtool_stats, 278 .get_ringparam = mlx5i_get_ringparam, 279 .set_ringparam = mlx5i_set_ringparam, 280 .flash_device = mlx5i_flash_device, 281 .get_channels = mlx5i_get_channels, 282 .set_channels = mlx5i_set_channels, 283 .get_coalesce = mlx5i_get_coalesce, 284 .set_coalesce = mlx5i_set_coalesce, 285 .get_ts_info = mlx5i_get_ts_info, 286 .get_rxnfc = mlx5i_get_rxnfc, 287 .set_rxnfc = mlx5i_set_rxnfc, 288 .get_link_ksettings = mlx5i_get_link_ksettings, 289 .get_link = ethtool_op_get_link, 290}; 291 292const struct ethtool_ops mlx5i_pkey_ethtool_ops = { 293 .get_drvinfo = mlx5i_get_drvinfo, 294 .get_link = ethtool_op_get_link, 295 .get_ts_info = mlx5i_get_ts_info, 296}; 297