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 37 static 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 47 static 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 54 static 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 61 static 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 70 static 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 80 static 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 90 static int mlx5i_set_channels(struct net_device *dev, 91 struct ethtool_channels *ch) 92 { 93 struct mlx5e_priv *priv = mlx5i_epriv(dev); 94 95 return mlx5e_ethtool_set_channels(priv, ch); 96 } 97 98 static void mlx5i_get_channels(struct net_device *dev, 99 struct ethtool_channels *ch) 100 { 101 struct mlx5e_priv *priv = mlx5i_epriv(dev); 102 103 mlx5e_ethtool_get_channels(priv, ch); 104 } 105 106 static int mlx5i_set_coalesce(struct net_device *netdev, 107 struct ethtool_coalesce *coal, 108 struct kernel_ethtool_coalesce *kernel_coal, 109 struct netlink_ext_ack *extack) 110 { 111 struct mlx5e_priv *priv = mlx5i_epriv(netdev); 112 113 return mlx5e_ethtool_set_coalesce(priv, coal, kernel_coal, extack); 114 } 115 116 static int mlx5i_get_coalesce(struct net_device *netdev, 117 struct ethtool_coalesce *coal, 118 struct kernel_ethtool_coalesce *kernel_coal, 119 struct netlink_ext_ack *extack) 120 { 121 struct mlx5e_priv *priv = mlx5i_epriv(netdev); 122 123 return mlx5e_ethtool_get_coalesce(priv, coal, kernel_coal); 124 } 125 126 static int mlx5i_get_ts_info(struct net_device *netdev, 127 struct ethtool_ts_info *info) 128 { 129 struct mlx5e_priv *priv = mlx5i_epriv(netdev); 130 131 return mlx5e_ethtool_get_ts_info(priv, info); 132 } 133 134 static int mlx5i_flash_device(struct net_device *netdev, 135 struct ethtool_flash *flash) 136 { 137 struct mlx5e_priv *priv = mlx5i_epriv(netdev); 138 139 return mlx5e_ethtool_flash_device(priv, flash); 140 } 141 142 static inline int mlx5_ptys_width_enum_to_int(enum mlx5_ptys_width width) 143 { 144 switch (width) { 145 case MLX5_PTYS_WIDTH_1X: return 1; 146 case MLX5_PTYS_WIDTH_2X: return 2; 147 case MLX5_PTYS_WIDTH_4X: return 4; 148 case MLX5_PTYS_WIDTH_8X: return 8; 149 case MLX5_PTYS_WIDTH_12X: return 12; 150 default: return -1; 151 } 152 } 153 154 enum mlx5_ptys_rate { 155 MLX5_PTYS_RATE_SDR = 1 << 0, 156 MLX5_PTYS_RATE_DDR = 1 << 1, 157 MLX5_PTYS_RATE_QDR = 1 << 2, 158 MLX5_PTYS_RATE_FDR10 = 1 << 3, 159 MLX5_PTYS_RATE_FDR = 1 << 4, 160 MLX5_PTYS_RATE_EDR = 1 << 5, 161 MLX5_PTYS_RATE_HDR = 1 << 6, 162 MLX5_PTYS_RATE_NDR = 1 << 7, 163 }; 164 165 static inline int mlx5_ptys_rate_enum_to_int(enum mlx5_ptys_rate rate) 166 { 167 switch (rate) { 168 case MLX5_PTYS_RATE_SDR: return 2500; 169 case MLX5_PTYS_RATE_DDR: return 5000; 170 case MLX5_PTYS_RATE_QDR: 171 case MLX5_PTYS_RATE_FDR10: return 10000; 172 case MLX5_PTYS_RATE_FDR: return 14000; 173 case MLX5_PTYS_RATE_EDR: return 25000; 174 case MLX5_PTYS_RATE_HDR: return 50000; 175 case MLX5_PTYS_RATE_NDR: return 100000; 176 default: return -1; 177 } 178 } 179 180 static int mlx5i_get_speed_settings(u16 ib_link_width_oper, u16 ib_proto_oper) 181 { 182 int rate, width; 183 184 rate = mlx5_ptys_rate_enum_to_int(ib_proto_oper); 185 if (rate < 0) 186 return -EINVAL; 187 width = mlx5_ptys_width_enum_to_int(ib_link_width_oper); 188 if (width < 0) 189 return -EINVAL; 190 191 return rate * width; 192 } 193 194 static int mlx5i_get_link_ksettings(struct net_device *netdev, 195 struct ethtool_link_ksettings *link_ksettings) 196 { 197 struct mlx5e_priv *priv = mlx5i_epriv(netdev); 198 struct mlx5_core_dev *mdev = priv->mdev; 199 u16 ib_link_width_oper; 200 u16 ib_proto_oper; 201 int speed, ret; 202 203 ret = mlx5_query_ib_port_oper(mdev, &ib_link_width_oper, &ib_proto_oper, 204 1); 205 if (ret) 206 return ret; 207 208 ethtool_link_ksettings_zero_link_mode(link_ksettings, supported); 209 ethtool_link_ksettings_zero_link_mode(link_ksettings, advertising); 210 211 speed = mlx5i_get_speed_settings(ib_link_width_oper, ib_proto_oper); 212 if (speed < 0) 213 return -EINVAL; 214 215 link_ksettings->base.duplex = DUPLEX_FULL; 216 link_ksettings->base.port = PORT_OTHER; 217 218 link_ksettings->base.autoneg = AUTONEG_DISABLE; 219 220 link_ksettings->base.speed = speed; 221 222 return 0; 223 } 224 225 static u32 mlx5i_flow_type_mask(u32 flow_type) 226 { 227 return flow_type & ~(FLOW_EXT | FLOW_MAC_EXT | FLOW_RSS); 228 } 229 230 static int mlx5i_set_rxnfc(struct net_device *dev, struct ethtool_rxnfc *cmd) 231 { 232 struct mlx5e_priv *priv = mlx5i_epriv(dev); 233 struct ethtool_rx_flow_spec *fs = &cmd->fs; 234 235 if (mlx5i_flow_type_mask(fs->flow_type) == ETHER_FLOW) 236 return -EINVAL; 237 238 return mlx5e_ethtool_set_rxnfc(priv, cmd); 239 } 240 241 static int mlx5i_get_rxnfc(struct net_device *dev, struct ethtool_rxnfc *info, 242 u32 *rule_locs) 243 { 244 struct mlx5e_priv *priv = mlx5i_epriv(dev); 245 246 /* ETHTOOL_GRXRINGS is needed by ethtool -x which is not part 247 * of rxnfc. We keep this logic out of mlx5e_ethtool_get_rxnfc, 248 * to avoid breaking "ethtool -x" when mlx5e_ethtool_get_rxnfc 249 * is compiled out via CONFIG_MLX5_EN_RXNFC=n. 250 */ 251 if (info->cmd == ETHTOOL_GRXRINGS) { 252 info->data = priv->channels.params.num_channels; 253 return 0; 254 } 255 256 return mlx5e_ethtool_get_rxnfc(priv, info, rule_locs); 257 } 258 259 const struct ethtool_ops mlx5i_ethtool_ops = { 260 .supported_coalesce_params = ETHTOOL_COALESCE_USECS | 261 ETHTOOL_COALESCE_MAX_FRAMES | 262 ETHTOOL_COALESCE_USE_ADAPTIVE, 263 .get_drvinfo = mlx5i_get_drvinfo, 264 .get_strings = mlx5i_get_strings, 265 .get_sset_count = mlx5i_get_sset_count, 266 .get_ethtool_stats = mlx5i_get_ethtool_stats, 267 .get_ringparam = mlx5i_get_ringparam, 268 .set_ringparam = mlx5i_set_ringparam, 269 .flash_device = mlx5i_flash_device, 270 .get_channels = mlx5i_get_channels, 271 .set_channels = mlx5i_set_channels, 272 .get_coalesce = mlx5i_get_coalesce, 273 .set_coalesce = mlx5i_set_coalesce, 274 .get_ts_info = mlx5i_get_ts_info, 275 .get_rxnfc = mlx5i_get_rxnfc, 276 .set_rxnfc = mlx5i_set_rxnfc, 277 .get_link_ksettings = mlx5i_get_link_ksettings, 278 .get_link = ethtool_op_get_link, 279 }; 280 281 const struct ethtool_ops mlx5i_pkey_ethtool_ops = { 282 .get_drvinfo = mlx5i_get_drvinfo, 283 .get_link = ethtool_op_get_link, 284 .get_ts_info = mlx5i_get_ts_info, 285 }; 286