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 36 static void mlx5i_get_drvinfo(struct net_device *dev, 37 struct ethtool_drvinfo *drvinfo) 38 { 39 struct mlx5e_priv *priv = mlx5i_epriv(dev); 40 41 mlx5e_ethtool_get_drvinfo(priv, drvinfo); 42 strlcpy(drvinfo->driver, DRIVER_NAME "[ib_ipoib]", 43 sizeof(drvinfo->driver)); 44 } 45 46 static void mlx5i_get_strings(struct net_device *dev, u32 stringset, u8 *data) 47 { 48 struct mlx5e_priv *priv = mlx5i_epriv(dev); 49 50 mlx5e_ethtool_get_strings(priv, stringset, data); 51 } 52 53 static int mlx5i_get_sset_count(struct net_device *dev, int sset) 54 { 55 struct mlx5e_priv *priv = mlx5i_epriv(dev); 56 57 return mlx5e_ethtool_get_sset_count(priv, sset); 58 } 59 60 static void mlx5i_get_ethtool_stats(struct net_device *dev, 61 struct ethtool_stats *stats, 62 u64 *data) 63 { 64 struct mlx5e_priv *priv = mlx5i_epriv(dev); 65 66 mlx5e_ethtool_get_ethtool_stats(priv, stats, data); 67 } 68 69 static int mlx5i_set_ringparam(struct net_device *dev, 70 struct ethtool_ringparam *param) 71 { 72 struct mlx5e_priv *priv = mlx5i_epriv(dev); 73 74 return mlx5e_ethtool_set_ringparam(priv, param); 75 } 76 77 static void mlx5i_get_ringparam(struct net_device *dev, 78 struct ethtool_ringparam *param) 79 { 80 struct mlx5e_priv *priv = mlx5i_epriv(dev); 81 82 mlx5e_ethtool_get_ringparam(priv, param); 83 } 84 85 static int mlx5i_set_channels(struct net_device *dev, 86 struct ethtool_channels *ch) 87 { 88 struct mlx5e_priv *priv = mlx5i_epriv(dev); 89 90 return mlx5e_ethtool_set_channels(priv, ch); 91 } 92 93 static void mlx5i_get_channels(struct net_device *dev, 94 struct ethtool_channels *ch) 95 { 96 struct mlx5e_priv *priv = mlx5i_epriv(dev); 97 98 mlx5e_ethtool_get_channels(priv, ch); 99 } 100 101 static int mlx5i_set_coalesce(struct net_device *netdev, 102 struct ethtool_coalesce *coal) 103 { 104 struct mlx5e_priv *priv = mlx5i_epriv(netdev); 105 106 return mlx5e_ethtool_set_coalesce(priv, coal); 107 } 108 109 static int mlx5i_get_coalesce(struct net_device *netdev, 110 struct ethtool_coalesce *coal) 111 { 112 struct mlx5e_priv *priv = mlx5i_epriv(netdev); 113 114 return mlx5e_ethtool_get_coalesce(priv, coal); 115 } 116 117 static int mlx5i_get_ts_info(struct net_device *netdev, 118 struct ethtool_ts_info *info) 119 { 120 struct mlx5e_priv *priv = mlx5i_epriv(netdev); 121 122 return mlx5e_ethtool_get_ts_info(priv, info); 123 } 124 125 enum mlx5_ptys_width { 126 MLX5_PTYS_WIDTH_1X = 1 << 0, 127 MLX5_PTYS_WIDTH_2X = 1 << 1, 128 MLX5_PTYS_WIDTH_4X = 1 << 2, 129 MLX5_PTYS_WIDTH_8X = 1 << 3, 130 MLX5_PTYS_WIDTH_12X = 1 << 4, 131 }; 132 133 static inline int mlx5_ptys_width_enum_to_int(enum mlx5_ptys_width width) 134 { 135 switch (width) { 136 case MLX5_PTYS_WIDTH_1X: return 1; 137 case MLX5_PTYS_WIDTH_2X: return 2; 138 case MLX5_PTYS_WIDTH_4X: return 4; 139 case MLX5_PTYS_WIDTH_8X: return 8; 140 case MLX5_PTYS_WIDTH_12X: return 12; 141 default: return -1; 142 } 143 } 144 145 enum mlx5_ptys_rate { 146 MLX5_PTYS_RATE_SDR = 1 << 0, 147 MLX5_PTYS_RATE_DDR = 1 << 1, 148 MLX5_PTYS_RATE_QDR = 1 << 2, 149 MLX5_PTYS_RATE_FDR10 = 1 << 3, 150 MLX5_PTYS_RATE_FDR = 1 << 4, 151 MLX5_PTYS_RATE_EDR = 1 << 5, 152 MLX5_PTYS_RATE_HDR = 1 << 6, 153 }; 154 155 static inline int mlx5_ptys_rate_enum_to_int(enum mlx5_ptys_rate rate) 156 { 157 switch (rate) { 158 case MLX5_PTYS_RATE_SDR: return 2500; 159 case MLX5_PTYS_RATE_DDR: return 5000; 160 case MLX5_PTYS_RATE_QDR: 161 case MLX5_PTYS_RATE_FDR10: return 10000; 162 case MLX5_PTYS_RATE_FDR: return 14000; 163 case MLX5_PTYS_RATE_EDR: return 25000; 164 case MLX5_PTYS_RATE_HDR: return 50000; 165 default: return -1; 166 } 167 } 168 169 static int mlx5i_get_port_settings(struct net_device *netdev, 170 u16 *ib_link_width_oper, u16 *ib_proto_oper) 171 { 172 struct mlx5e_priv *priv = mlx5i_epriv(netdev); 173 struct mlx5_core_dev *mdev = priv->mdev; 174 u32 out[MLX5_ST_SZ_DW(ptys_reg)] = {0}; 175 int ret; 176 177 ret = mlx5_query_port_ptys(mdev, out, sizeof(out), MLX5_PTYS_IB, 1); 178 if (ret) 179 return ret; 180 181 *ib_link_width_oper = MLX5_GET(ptys_reg, out, ib_link_width_oper); 182 *ib_proto_oper = MLX5_GET(ptys_reg, out, ib_proto_oper); 183 184 return 0; 185 } 186 187 static int mlx5i_get_speed_settings(u16 ib_link_width_oper, u16 ib_proto_oper) 188 { 189 int rate, width; 190 191 rate = mlx5_ptys_rate_enum_to_int(ib_proto_oper); 192 if (rate < 0) 193 return -EINVAL; 194 width = mlx5_ptys_width_enum_to_int(ib_link_width_oper); 195 if (width < 0) 196 return -EINVAL; 197 198 return rate * width; 199 } 200 201 static int mlx5i_get_link_ksettings(struct net_device *netdev, 202 struct ethtool_link_ksettings *link_ksettings) 203 { 204 u16 ib_link_width_oper; 205 u16 ib_proto_oper; 206 int speed, ret; 207 208 ret = mlx5i_get_port_settings(netdev, &ib_link_width_oper, &ib_proto_oper); 209 if (ret) 210 return ret; 211 212 ethtool_link_ksettings_zero_link_mode(link_ksettings, supported); 213 ethtool_link_ksettings_zero_link_mode(link_ksettings, advertising); 214 215 speed = mlx5i_get_speed_settings(ib_link_width_oper, ib_proto_oper); 216 if (speed < 0) 217 return -EINVAL; 218 219 link_ksettings->base.duplex = DUPLEX_FULL; 220 link_ksettings->base.port = PORT_OTHER; 221 222 link_ksettings->base.autoneg = AUTONEG_DISABLE; 223 224 link_ksettings->base.speed = speed; 225 226 return 0; 227 } 228 229 const struct ethtool_ops mlx5i_ethtool_ops = { 230 .get_drvinfo = mlx5i_get_drvinfo, 231 .get_strings = mlx5i_get_strings, 232 .get_sset_count = mlx5i_get_sset_count, 233 .get_ethtool_stats = mlx5i_get_ethtool_stats, 234 .get_ringparam = mlx5i_get_ringparam, 235 .set_ringparam = mlx5i_set_ringparam, 236 .get_channels = mlx5i_get_channels, 237 .set_channels = mlx5i_set_channels, 238 .get_coalesce = mlx5i_get_coalesce, 239 .set_coalesce = mlx5i_set_coalesce, 240 .get_ts_info = mlx5i_get_ts_info, 241 .get_link_ksettings = mlx5i_get_link_ksettings, 242 .get_link = ethtool_op_get_link, 243 }; 244 245 const struct ethtool_ops mlx5i_pkey_ethtool_ops = { 246 .get_drvinfo = mlx5i_get_drvinfo, 247 .get_link = ethtool_op_get_link, 248 .get_ts_info = mlx5i_get_ts_info, 249 }; 250