]>
Commit | Line | Data |
---|---|---|
f62b8bb8 AV |
1 | /* |
2 | * Copyright (c) 2015, 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" | |
2c81bfd5 | 34 | #include "en/port.h" |
f62b8bb8 | 35 | |
076b0936 ES |
36 | void mlx5e_ethtool_get_drvinfo(struct mlx5e_priv *priv, |
37 | struct ethtool_drvinfo *drvinfo) | |
f62b8bb8 | 38 | { |
f62b8bb8 AV |
39 | struct mlx5_core_dev *mdev = priv->mdev; |
40 | ||
41 | strlcpy(drvinfo->driver, DRIVER_NAME, sizeof(drvinfo->driver)); | |
7913d205 | 42 | strlcpy(drvinfo->version, DRIVER_VERSION, |
f62b8bb8 AV |
43 | sizeof(drvinfo->version)); |
44 | snprintf(drvinfo->fw_version, sizeof(drvinfo->fw_version), | |
84e11edb IK |
45 | "%d.%d.%04d (%.16s)", |
46 | fw_rev_maj(mdev), fw_rev_min(mdev), fw_rev_sub(mdev), | |
47 | mdev->board_id); | |
f62b8bb8 AV |
48 | strlcpy(drvinfo->bus_info, pci_name(mdev->pdev), |
49 | sizeof(drvinfo->bus_info)); | |
50 | } | |
51 | ||
076b0936 ES |
52 | static void mlx5e_get_drvinfo(struct net_device *dev, |
53 | struct ethtool_drvinfo *drvinfo) | |
54 | { | |
55 | struct mlx5e_priv *priv = netdev_priv(dev); | |
56 | ||
57 | mlx5e_ethtool_get_drvinfo(priv, drvinfo); | |
58 | } | |
59 | ||
665bc539 GP |
60 | struct ptys2ethtool_config { |
61 | __ETHTOOL_DECLARE_LINK_MODE_MASK(supported); | |
62 | __ETHTOOL_DECLARE_LINK_MODE_MASK(advertised); | |
f62b8bb8 AV |
63 | }; |
64 | ||
665bc539 GP |
65 | static struct ptys2ethtool_config ptys2ethtool_table[MLX5E_LINK_MODES_NUMBER]; |
66 | ||
2c81bfd5 | 67 | #define MLX5_BUILD_PTYS2ETHTOOL_CONFIG(reg_, ...) \ |
665bc539 GP |
68 | ({ \ |
69 | struct ptys2ethtool_config *cfg; \ | |
70 | const unsigned int modes[] = { __VA_ARGS__ }; \ | |
71 | unsigned int i; \ | |
72 | cfg = &ptys2ethtool_table[reg_]; \ | |
665bc539 GP |
73 | bitmap_zero(cfg->supported, \ |
74 | __ETHTOOL_LINK_MODE_MASK_NBITS); \ | |
75 | bitmap_zero(cfg->advertised, \ | |
76 | __ETHTOOL_LINK_MODE_MASK_NBITS); \ | |
77 | for (i = 0 ; i < ARRAY_SIZE(modes) ; ++i) { \ | |
78 | __set_bit(modes[i], cfg->supported); \ | |
79 | __set_bit(modes[i], cfg->advertised); \ | |
80 | } \ | |
81 | }) | |
82 | ||
83 | void mlx5e_build_ptys2ethtool_map(void) | |
84 | { | |
2c81bfd5 | 85 | MLX5_BUILD_PTYS2ETHTOOL_CONFIG(MLX5E_1000BASE_CX_SGMII, |
665bc539 | 86 | ETHTOOL_LINK_MODE_1000baseKX_Full_BIT); |
2c81bfd5 | 87 | MLX5_BUILD_PTYS2ETHTOOL_CONFIG(MLX5E_1000BASE_KX, |
665bc539 | 88 | ETHTOOL_LINK_MODE_1000baseKX_Full_BIT); |
2c81bfd5 | 89 | MLX5_BUILD_PTYS2ETHTOOL_CONFIG(MLX5E_10GBASE_CX4, |
665bc539 | 90 | ETHTOOL_LINK_MODE_10000baseKX4_Full_BIT); |
2c81bfd5 | 91 | MLX5_BUILD_PTYS2ETHTOOL_CONFIG(MLX5E_10GBASE_KX4, |
665bc539 | 92 | ETHTOOL_LINK_MODE_10000baseKX4_Full_BIT); |
2c81bfd5 | 93 | MLX5_BUILD_PTYS2ETHTOOL_CONFIG(MLX5E_10GBASE_KR, |
665bc539 | 94 | ETHTOOL_LINK_MODE_10000baseKR_Full_BIT); |
2c81bfd5 | 95 | MLX5_BUILD_PTYS2ETHTOOL_CONFIG(MLX5E_20GBASE_KR2, |
665bc539 | 96 | ETHTOOL_LINK_MODE_20000baseKR2_Full_BIT); |
2c81bfd5 | 97 | MLX5_BUILD_PTYS2ETHTOOL_CONFIG(MLX5E_40GBASE_CR4, |
665bc539 | 98 | ETHTOOL_LINK_MODE_40000baseCR4_Full_BIT); |
2c81bfd5 | 99 | MLX5_BUILD_PTYS2ETHTOOL_CONFIG(MLX5E_40GBASE_KR4, |
665bc539 | 100 | ETHTOOL_LINK_MODE_40000baseKR4_Full_BIT); |
2c81bfd5 | 101 | MLX5_BUILD_PTYS2ETHTOOL_CONFIG(MLX5E_56GBASE_R4, |
665bc539 | 102 | ETHTOOL_LINK_MODE_56000baseKR4_Full_BIT); |
2c81bfd5 | 103 | MLX5_BUILD_PTYS2ETHTOOL_CONFIG(MLX5E_10GBASE_CR, |
665bc539 | 104 | ETHTOOL_LINK_MODE_10000baseKR_Full_BIT); |
2c81bfd5 | 105 | MLX5_BUILD_PTYS2ETHTOOL_CONFIG(MLX5E_10GBASE_SR, |
665bc539 | 106 | ETHTOOL_LINK_MODE_10000baseKR_Full_BIT); |
2c81bfd5 | 107 | MLX5_BUILD_PTYS2ETHTOOL_CONFIG(MLX5E_10GBASE_ER, |
665bc539 | 108 | ETHTOOL_LINK_MODE_10000baseKR_Full_BIT); |
2c81bfd5 | 109 | MLX5_BUILD_PTYS2ETHTOOL_CONFIG(MLX5E_40GBASE_SR4, |
665bc539 | 110 | ETHTOOL_LINK_MODE_40000baseSR4_Full_BIT); |
2c81bfd5 | 111 | MLX5_BUILD_PTYS2ETHTOOL_CONFIG(MLX5E_40GBASE_LR4, |
665bc539 | 112 | ETHTOOL_LINK_MODE_40000baseLR4_Full_BIT); |
2c81bfd5 | 113 | MLX5_BUILD_PTYS2ETHTOOL_CONFIG(MLX5E_50GBASE_SR2, |
665bc539 | 114 | ETHTOOL_LINK_MODE_50000baseSR2_Full_BIT); |
2c81bfd5 | 115 | MLX5_BUILD_PTYS2ETHTOOL_CONFIG(MLX5E_100GBASE_CR4, |
665bc539 | 116 | ETHTOOL_LINK_MODE_100000baseCR4_Full_BIT); |
2c81bfd5 | 117 | MLX5_BUILD_PTYS2ETHTOOL_CONFIG(MLX5E_100GBASE_SR4, |
665bc539 | 118 | ETHTOOL_LINK_MODE_100000baseSR4_Full_BIT); |
2c81bfd5 | 119 | MLX5_BUILD_PTYS2ETHTOOL_CONFIG(MLX5E_100GBASE_KR4, |
665bc539 | 120 | ETHTOOL_LINK_MODE_100000baseKR4_Full_BIT); |
2c81bfd5 | 121 | MLX5_BUILD_PTYS2ETHTOOL_CONFIG(MLX5E_100GBASE_LR4, |
665bc539 | 122 | ETHTOOL_LINK_MODE_100000baseLR4_ER4_Full_BIT); |
2c81bfd5 | 123 | MLX5_BUILD_PTYS2ETHTOOL_CONFIG(MLX5E_10GBASE_T, |
665bc539 | 124 | ETHTOOL_LINK_MODE_10000baseT_Full_BIT); |
2c81bfd5 | 125 | MLX5_BUILD_PTYS2ETHTOOL_CONFIG(MLX5E_25GBASE_CR, |
665bc539 | 126 | ETHTOOL_LINK_MODE_25000baseCR_Full_BIT); |
2c81bfd5 | 127 | MLX5_BUILD_PTYS2ETHTOOL_CONFIG(MLX5E_25GBASE_KR, |
665bc539 | 128 | ETHTOOL_LINK_MODE_25000baseKR_Full_BIT); |
2c81bfd5 | 129 | MLX5_BUILD_PTYS2ETHTOOL_CONFIG(MLX5E_25GBASE_SR, |
665bc539 | 130 | ETHTOOL_LINK_MODE_25000baseSR_Full_BIT); |
2c81bfd5 | 131 | MLX5_BUILD_PTYS2ETHTOOL_CONFIG(MLX5E_50GBASE_CR2, |
665bc539 | 132 | ETHTOOL_LINK_MODE_50000baseCR2_Full_BIT); |
2c81bfd5 | 133 | MLX5_BUILD_PTYS2ETHTOOL_CONFIG(MLX5E_50GBASE_KR2, |
665bc539 GP |
134 | ETHTOOL_LINK_MODE_50000baseKR2_Full_BIT); |
135 | } | |
136 | ||
076b0936 | 137 | int mlx5e_ethtool_get_sset_count(struct mlx5e_priv *priv, int sset) |
f62b8bb8 | 138 | { |
c0752f2b KH |
139 | int i, num_stats = 0; |
140 | ||
f62b8bb8 AV |
141 | switch (sset) { |
142 | case ETH_SS_STATS: | |
c0752f2b KH |
143 | for (i = 0; i < mlx5e_num_stats_grps; i++) |
144 | num_stats += mlx5e_stats_grps[i].get_num_stats(priv); | |
1fe85006 | 145 | return num_stats; |
4e59e288 GP |
146 | case ETH_SS_PRIV_FLAGS: |
147 | return ARRAY_SIZE(mlx5e_priv_flags); | |
d605d668 KH |
148 | case ETH_SS_TEST: |
149 | return mlx5e_self_test_num(priv); | |
f62b8bb8 AV |
150 | /* fallthrough */ |
151 | default: | |
152 | return -EOPNOTSUPP; | |
153 | } | |
154 | } | |
155 | ||
076b0936 ES |
156 | static int mlx5e_get_sset_count(struct net_device *dev, int sset) |
157 | { | |
158 | struct mlx5e_priv *priv = netdev_priv(dev); | |
159 | ||
160 | return mlx5e_ethtool_get_sset_count(priv, sset); | |
161 | } | |
162 | ||
c045deef | 163 | static void mlx5e_fill_stats_strings(struct mlx5e_priv *priv, u8 *data) |
9218b44d | 164 | { |
1fe85006 | 165 | int i, idx = 0; |
9218b44d | 166 | |
c0752f2b KH |
167 | for (i = 0; i < mlx5e_num_stats_grps; i++) |
168 | idx = mlx5e_stats_grps[i].fill_strings(priv, data, idx); | |
9218b44d GP |
169 | } |
170 | ||
c045deef | 171 | void mlx5e_ethtool_get_strings(struct mlx5e_priv *priv, u32 stringset, u8 *data) |
f62b8bb8 | 172 | { |
4e59e288 | 173 | int i; |
f62b8bb8 AV |
174 | |
175 | switch (stringset) { | |
176 | case ETH_SS_PRIV_FLAGS: | |
4e59e288 GP |
177 | for (i = 0; i < ARRAY_SIZE(mlx5e_priv_flags); i++) |
178 | strcpy(data + i * ETH_GSTRING_LEN, mlx5e_priv_flags[i]); | |
f62b8bb8 AV |
179 | break; |
180 | ||
181 | case ETH_SS_TEST: | |
d605d668 KH |
182 | for (i = 0; i < mlx5e_self_test_num(priv); i++) |
183 | strcpy(data + i * ETH_GSTRING_LEN, | |
184 | mlx5e_self_tests[i]); | |
f62b8bb8 AV |
185 | break; |
186 | ||
187 | case ETH_SS_STATS: | |
9218b44d | 188 | mlx5e_fill_stats_strings(priv, data); |
f62b8bb8 AV |
189 | break; |
190 | } | |
191 | } | |
192 | ||
c045deef | 193 | static void mlx5e_get_strings(struct net_device *dev, u32 stringset, u8 *data) |
f62b8bb8 AV |
194 | { |
195 | struct mlx5e_priv *priv = netdev_priv(dev); | |
076b0936 ES |
196 | |
197 | mlx5e_ethtool_get_strings(priv, stringset, data); | |
198 | } | |
199 | ||
200 | void mlx5e_ethtool_get_ethtool_stats(struct mlx5e_priv *priv, | |
201 | struct ethtool_stats *stats, u64 *data) | |
202 | { | |
1fe85006 | 203 | int i, idx = 0; |
f62b8bb8 | 204 | |
f62b8bb8 | 205 | mutex_lock(&priv->state_lock); |
19386177 | 206 | mlx5e_update_stats(priv); |
f62b8bb8 AV |
207 | mutex_unlock(&priv->state_lock); |
208 | ||
c0752f2b KH |
209 | for (i = 0; i < mlx5e_num_stats_grps; i++) |
210 | idx = mlx5e_stats_grps[i].fill_stats(priv, data, idx); | |
f62b8bb8 AV |
211 | } |
212 | ||
076b0936 ES |
213 | static void mlx5e_get_ethtool_stats(struct net_device *dev, |
214 | struct ethtool_stats *stats, | |
215 | u64 *data) | |
216 | { | |
217 | struct mlx5e_priv *priv = netdev_priv(dev); | |
218 | ||
219 | mlx5e_ethtool_get_ethtool_stats(priv, stats, data); | |
220 | } | |
221 | ||
076b0936 ES |
222 | void mlx5e_ethtool_get_ringparam(struct mlx5e_priv *priv, |
223 | struct ethtool_ringparam *param) | |
f62b8bb8 | 224 | { |
73281b78 | 225 | param->rx_max_pending = 1 << MLX5E_PARAMS_MAXIMUM_LOG_RQ_SIZE; |
f62b8bb8 | 226 | param->tx_max_pending = 1 << MLX5E_PARAMS_MAXIMUM_LOG_SQ_SIZE; |
73281b78 | 227 | param->rx_pending = 1 << priv->channels.params.log_rq_mtu_frames; |
6a9764ef | 228 | param->tx_pending = 1 << priv->channels.params.log_sq_size; |
f62b8bb8 AV |
229 | } |
230 | ||
076b0936 ES |
231 | static void mlx5e_get_ringparam(struct net_device *dev, |
232 | struct ethtool_ringparam *param) | |
f62b8bb8 AV |
233 | { |
234 | struct mlx5e_priv *priv = netdev_priv(dev); | |
076b0936 ES |
235 | |
236 | mlx5e_ethtool_get_ringparam(priv, param); | |
237 | } | |
238 | ||
239 | int mlx5e_ethtool_set_ringparam(struct mlx5e_priv *priv, | |
240 | struct ethtool_ringparam *param) | |
241 | { | |
546f18ed | 242 | struct mlx5e_channels new_channels = {}; |
f62b8bb8 AV |
243 | u8 log_rq_size; |
244 | u8 log_sq_size; | |
245 | int err = 0; | |
246 | ||
247 | if (param->rx_jumbo_pending) { | |
076b0936 | 248 | netdev_info(priv->netdev, "%s: rx_jumbo_pending not supported\n", |
f62b8bb8 AV |
249 | __func__); |
250 | return -EINVAL; | |
251 | } | |
252 | if (param->rx_mini_pending) { | |
076b0936 | 253 | netdev_info(priv->netdev, "%s: rx_mini_pending not supported\n", |
f62b8bb8 AV |
254 | __func__); |
255 | return -EINVAL; | |
256 | } | |
cc8e9ebf | 257 | |
73281b78 | 258 | if (param->rx_pending < (1 << MLX5E_PARAMS_MINIMUM_LOG_RQ_SIZE)) { |
076b0936 | 259 | netdev_info(priv->netdev, "%s: rx_pending (%d) < min (%d)\n", |
f62b8bb8 | 260 | __func__, param->rx_pending, |
73281b78 | 261 | 1 << MLX5E_PARAMS_MINIMUM_LOG_RQ_SIZE); |
fe4c988b SM |
262 | return -EINVAL; |
263 | } | |
264 | ||
f62b8bb8 | 265 | if (param->tx_pending < (1 << MLX5E_PARAMS_MINIMUM_LOG_SQ_SIZE)) { |
076b0936 | 266 | netdev_info(priv->netdev, "%s: tx_pending (%d) < min (%d)\n", |
f62b8bb8 AV |
267 | __func__, param->tx_pending, |
268 | 1 << MLX5E_PARAMS_MINIMUM_LOG_SQ_SIZE); | |
269 | return -EINVAL; | |
270 | } | |
f62b8bb8 | 271 | |
73281b78 | 272 | log_rq_size = order_base_2(param->rx_pending); |
f62b8bb8 | 273 | log_sq_size = order_base_2(param->tx_pending); |
f62b8bb8 | 274 | |
73281b78 | 275 | if (log_rq_size == priv->channels.params.log_rq_mtu_frames && |
6a9764ef | 276 | log_sq_size == priv->channels.params.log_sq_size) |
f62b8bb8 AV |
277 | return 0; |
278 | ||
279 | mutex_lock(&priv->state_lock); | |
98e81b0a | 280 | |
546f18ed | 281 | new_channels.params = priv->channels.params; |
73281b78 | 282 | new_channels.params.log_rq_mtu_frames = log_rq_size; |
546f18ed | 283 | new_channels.params.log_sq_size = log_sq_size; |
98e81b0a | 284 | |
546f18ed SM |
285 | if (!test_bit(MLX5E_STATE_OPENED, &priv->state)) { |
286 | priv->channels.params = new_channels.params; | |
287 | goto unlock; | |
288 | } | |
98e81b0a | 289 | |
546f18ed SM |
290 | err = mlx5e_open_channels(priv, &new_channels); |
291 | if (err) | |
292 | goto unlock; | |
293 | ||
2e20a151 | 294 | mlx5e_switch_priv_channels(priv, &new_channels, NULL); |
98e81b0a | 295 | |
546f18ed | 296 | unlock: |
f62b8bb8 AV |
297 | mutex_unlock(&priv->state_lock); |
298 | ||
299 | return err; | |
300 | } | |
301 | ||
076b0936 ES |
302 | static int mlx5e_set_ringparam(struct net_device *dev, |
303 | struct ethtool_ringparam *param) | |
f62b8bb8 AV |
304 | { |
305 | struct mlx5e_priv *priv = netdev_priv(dev); | |
f62b8bb8 | 306 | |
076b0936 ES |
307 | return mlx5e_ethtool_set_ringparam(priv, param); |
308 | } | |
309 | ||
310 | void mlx5e_ethtool_get_channels(struct mlx5e_priv *priv, | |
311 | struct ethtool_channels *ch) | |
312 | { | |
b4e029da | 313 | ch->max_combined = priv->profile->max_nch(priv->mdev); |
6a9764ef | 314 | ch->combined_count = priv->channels.params.num_channels; |
f62b8bb8 AV |
315 | } |
316 | ||
076b0936 ES |
317 | static void mlx5e_get_channels(struct net_device *dev, |
318 | struct ethtool_channels *ch) | |
f62b8bb8 AV |
319 | { |
320 | struct mlx5e_priv *priv = netdev_priv(dev); | |
076b0936 ES |
321 | |
322 | mlx5e_ethtool_get_channels(priv, ch); | |
323 | } | |
324 | ||
325 | int mlx5e_ethtool_set_channels(struct mlx5e_priv *priv, | |
326 | struct ethtool_channels *ch) | |
327 | { | |
f62b8bb8 | 328 | unsigned int count = ch->combined_count; |
55c2503d | 329 | struct mlx5e_channels new_channels = {}; |
45bf454a | 330 | bool arfs_enabled; |
f62b8bb8 AV |
331 | int err = 0; |
332 | ||
333 | if (!count) { | |
076b0936 | 334 | netdev_info(priv->netdev, "%s: combined_count=0 not supported\n", |
f62b8bb8 AV |
335 | __func__); |
336 | return -EINVAL; | |
337 | } | |
f62b8bb8 | 338 | |
6a9764ef | 339 | if (priv->channels.params.num_channels == count) |
f62b8bb8 AV |
340 | return 0; |
341 | ||
342 | mutex_lock(&priv->state_lock); | |
98e81b0a | 343 | |
55c2503d SM |
344 | new_channels.params = priv->channels.params; |
345 | new_channels.params.num_channels = count; | |
5a8e1267 | 346 | if (!netif_is_rxfh_configured(priv->netdev)) |
d4b6c488 | 347 | mlx5e_build_default_indir_rqt(new_channels.params.indirection_rqt, |
5a8e1267 | 348 | MLX5E_INDIR_RQT_SIZE, count); |
55c2503d SM |
349 | |
350 | if (!test_bit(MLX5E_STATE_OPENED, &priv->state)) { | |
351 | priv->channels.params = new_channels.params; | |
352 | goto out; | |
353 | } | |
354 | ||
355 | /* Create fresh channels with new parameters */ | |
356 | err = mlx5e_open_channels(priv, &new_channels); | |
357 | if (err) | |
358 | goto out; | |
98e81b0a | 359 | |
076b0936 | 360 | arfs_enabled = priv->netdev->features & NETIF_F_NTUPLE; |
45bf454a MG |
361 | if (arfs_enabled) |
362 | mlx5e_arfs_disable(priv); | |
363 | ||
55c2503d | 364 | /* Switch to new channels, set new parameters and close old ones */ |
2e20a151 | 365 | mlx5e_switch_priv_channels(priv, &new_channels, NULL); |
45bf454a MG |
366 | |
367 | if (arfs_enabled) { | |
368 | err = mlx5e_arfs_enable(priv); | |
369 | if (err) | |
076b0936 | 370 | netdev_err(priv->netdev, "%s: mlx5e_arfs_enable failed: %d\n", |
45bf454a MG |
371 | __func__, err); |
372 | } | |
98e81b0a | 373 | |
45bf454a | 374 | out: |
f62b8bb8 AV |
375 | mutex_unlock(&priv->state_lock); |
376 | ||
377 | return err; | |
378 | } | |
379 | ||
076b0936 ES |
380 | static int mlx5e_set_channels(struct net_device *dev, |
381 | struct ethtool_channels *ch) | |
f62b8bb8 | 382 | { |
076b0936 ES |
383 | struct mlx5e_priv *priv = netdev_priv(dev); |
384 | ||
385 | return mlx5e_ethtool_set_channels(priv, ch); | |
386 | } | |
f62b8bb8 | 387 | |
076b0936 ES |
388 | int mlx5e_ethtool_get_coalesce(struct mlx5e_priv *priv, |
389 | struct ethtool_coalesce *coal) | |
390 | { | |
cbce4f44 TG |
391 | struct net_dim_cq_moder *rx_moder, *tx_moder; |
392 | ||
7524a5d8 | 393 | if (!MLX5_CAP_GEN(priv->mdev, cq_moderation)) |
9eb78923 | 394 | return -EOPNOTSUPP; |
7524a5d8 | 395 | |
cbce4f44 TG |
396 | rx_moder = &priv->channels.params.rx_cq_moderation; |
397 | coal->rx_coalesce_usecs = rx_moder->usec; | |
398 | coal->rx_max_coalesced_frames = rx_moder->pkts; | |
399 | coal->use_adaptive_rx_coalesce = priv->channels.params.rx_dim_enabled; | |
400 | ||
401 | tx_moder = &priv->channels.params.tx_cq_moderation; | |
402 | coal->tx_coalesce_usecs = tx_moder->usec; | |
403 | coal->tx_max_coalesced_frames = tx_moder->pkts; | |
404 | coal->use_adaptive_tx_coalesce = priv->channels.params.tx_dim_enabled; | |
f62b8bb8 AV |
405 | |
406 | return 0; | |
407 | } | |
408 | ||
076b0936 ES |
409 | static int mlx5e_get_coalesce(struct net_device *netdev, |
410 | struct ethtool_coalesce *coal) | |
411 | { | |
412 | struct mlx5e_priv *priv = netdev_priv(netdev); | |
413 | ||
414 | return mlx5e_ethtool_get_coalesce(priv, coal); | |
415 | } | |
416 | ||
b392a207 MS |
417 | #define MLX5E_MAX_COAL_TIME MLX5_MAX_CQ_PERIOD |
418 | #define MLX5E_MAX_COAL_FRAMES MLX5_MAX_CQ_COUNT | |
419 | ||
546f18ed SM |
420 | static void |
421 | mlx5e_set_priv_channels_coalesce(struct mlx5e_priv *priv, struct ethtool_coalesce *coal) | |
f62b8bb8 | 422 | { |
f62b8bb8 | 423 | struct mlx5_core_dev *mdev = priv->mdev; |
f62b8bb8 AV |
424 | int tc; |
425 | int i; | |
426 | ||
ff9c852f SM |
427 | for (i = 0; i < priv->channels.num; ++i) { |
428 | struct mlx5e_channel *c = priv->channels.c[i]; | |
f62b8bb8 AV |
429 | |
430 | for (tc = 0; tc < c->num_tc; tc++) { | |
431 | mlx5_core_modify_cq_moderation(mdev, | |
432 | &c->sq[tc].cq.mcq, | |
433 | coal->tx_coalesce_usecs, | |
434 | coal->tx_max_coalesced_frames); | |
435 | } | |
436 | ||
437 | mlx5_core_modify_cq_moderation(mdev, &c->rq.cq.mcq, | |
438 | coal->rx_coalesce_usecs, | |
439 | coal->rx_max_coalesced_frames); | |
440 | } | |
546f18ed | 441 | } |
f62b8bb8 | 442 | |
076b0936 ES |
443 | int mlx5e_ethtool_set_coalesce(struct mlx5e_priv *priv, |
444 | struct ethtool_coalesce *coal) | |
546f18ed | 445 | { |
cbce4f44 | 446 | struct net_dim_cq_moder *rx_moder, *tx_moder; |
546f18ed SM |
447 | struct mlx5_core_dev *mdev = priv->mdev; |
448 | struct mlx5e_channels new_channels = {}; | |
449 | int err = 0; | |
450 | bool reset; | |
cb3c7fd4 | 451 | |
546f18ed SM |
452 | if (!MLX5_CAP_GEN(mdev, cq_moderation)) |
453 | return -EOPNOTSUPP; | |
454 | ||
b392a207 MS |
455 | if (coal->tx_coalesce_usecs > MLX5E_MAX_COAL_TIME || |
456 | coal->rx_coalesce_usecs > MLX5E_MAX_COAL_TIME) { | |
457 | netdev_info(priv->netdev, "%s: maximum coalesce time supported is %lu usecs\n", | |
458 | __func__, MLX5E_MAX_COAL_TIME); | |
459 | return -ERANGE; | |
460 | } | |
461 | ||
462 | if (coal->tx_max_coalesced_frames > MLX5E_MAX_COAL_FRAMES || | |
463 | coal->rx_max_coalesced_frames > MLX5E_MAX_COAL_FRAMES) { | |
464 | netdev_info(priv->netdev, "%s: maximum coalesced frames supported is %lu\n", | |
465 | __func__, MLX5E_MAX_COAL_FRAMES); | |
466 | return -ERANGE; | |
467 | } | |
468 | ||
546f18ed SM |
469 | mutex_lock(&priv->state_lock); |
470 | new_channels.params = priv->channels.params; | |
471 | ||
cbce4f44 TG |
472 | rx_moder = &new_channels.params.rx_cq_moderation; |
473 | rx_moder->usec = coal->rx_coalesce_usecs; | |
474 | rx_moder->pkts = coal->rx_max_coalesced_frames; | |
475 | new_channels.params.rx_dim_enabled = !!coal->use_adaptive_rx_coalesce; | |
476 | ||
477 | tx_moder = &new_channels.params.tx_cq_moderation; | |
478 | tx_moder->usec = coal->tx_coalesce_usecs; | |
479 | tx_moder->pkts = coal->tx_max_coalesced_frames; | |
480 | new_channels.params.tx_dim_enabled = !!coal->use_adaptive_tx_coalesce; | |
546f18ed SM |
481 | |
482 | if (!test_bit(MLX5E_STATE_OPENED, &priv->state)) { | |
483 | priv->channels.params = new_channels.params; | |
484 | goto out; | |
485 | } | |
486 | /* we are opened */ | |
487 | ||
cbce4f44 TG |
488 | reset = (!!coal->use_adaptive_rx_coalesce != priv->channels.params.rx_dim_enabled) || |
489 | (!!coal->use_adaptive_tx_coalesce != priv->channels.params.tx_dim_enabled); | |
490 | ||
546f18ed SM |
491 | if (!reset) { |
492 | mlx5e_set_priv_channels_coalesce(priv, coal); | |
493 | priv->channels.params = new_channels.params; | |
494 | goto out; | |
495 | } | |
496 | ||
497 | /* open fresh channels with new coal parameters */ | |
498 | err = mlx5e_open_channels(priv, &new_channels); | |
499 | if (err) | |
500 | goto out; | |
501 | ||
2e20a151 | 502 | mlx5e_switch_priv_channels(priv, &new_channels, NULL); |
546f18ed SM |
503 | |
504 | out: | |
2fcb92fb | 505 | mutex_unlock(&priv->state_lock); |
cb3c7fd4 | 506 | return err; |
f62b8bb8 AV |
507 | } |
508 | ||
076b0936 ES |
509 | static int mlx5e_set_coalesce(struct net_device *netdev, |
510 | struct ethtool_coalesce *coal) | |
511 | { | |
512 | struct mlx5e_priv *priv = netdev_priv(netdev); | |
513 | ||
514 | return mlx5e_ethtool_set_coalesce(priv, coal); | |
515 | } | |
516 | ||
665bc539 GP |
517 | static void ptys2ethtool_supported_link(unsigned long *supported_modes, |
518 | u32 eth_proto_cap) | |
f62b8bb8 | 519 | { |
7abc2110 | 520 | unsigned long proto_cap = eth_proto_cap; |
665bc539 | 521 | int proto; |
f62b8bb8 | 522 | |
7abc2110 | 523 | for_each_set_bit(proto, &proto_cap, MLX5E_LINK_MODES_NUMBER) |
665bc539 GP |
524 | bitmap_or(supported_modes, supported_modes, |
525 | ptys2ethtool_table[proto].supported, | |
526 | __ETHTOOL_LINK_MODE_MASK_NBITS); | |
f62b8bb8 AV |
527 | } |
528 | ||
665bc539 GP |
529 | static void ptys2ethtool_adver_link(unsigned long *advertising_modes, |
530 | u32 eth_proto_cap) | |
f62b8bb8 | 531 | { |
7abc2110 | 532 | unsigned long proto_cap = eth_proto_cap; |
665bc539 | 533 | int proto; |
f62b8bb8 | 534 | |
7abc2110 | 535 | for_each_set_bit(proto, &proto_cap, MLX5E_LINK_MODES_NUMBER) |
665bc539 GP |
536 | bitmap_or(advertising_modes, advertising_modes, |
537 | ptys2ethtool_table[proto].advertised, | |
538 | __ETHTOOL_LINK_MODE_MASK_NBITS); | |
f62b8bb8 AV |
539 | } |
540 | ||
46e9d0b6 EBE |
541 | static void ptys2ethtool_supported_advertised_port(struct ethtool_link_ksettings *link_ksettings, |
542 | u32 eth_proto_cap, | |
543 | u8 connector_type) | |
f62b8bb8 | 544 | { |
46e9d0b6 EBE |
545 | if (!connector_type || connector_type >= MLX5E_CONNECTOR_TYPE_NUMBER) { |
546 | if (eth_proto_cap & (MLX5E_PROT_MASK(MLX5E_10GBASE_CR) | |
547 | | MLX5E_PROT_MASK(MLX5E_10GBASE_SR) | |
548 | | MLX5E_PROT_MASK(MLX5E_40GBASE_CR4) | |
549 | | MLX5E_PROT_MASK(MLX5E_40GBASE_SR4) | |
550 | | MLX5E_PROT_MASK(MLX5E_100GBASE_SR4) | |
551 | | MLX5E_PROT_MASK(MLX5E_1000BASE_CX_SGMII))) { | |
552 | ethtool_link_ksettings_add_link_mode(link_ksettings, | |
553 | supported, | |
554 | FIBRE); | |
555 | ethtool_link_ksettings_add_link_mode(link_ksettings, | |
556 | advertising, | |
557 | FIBRE); | |
558 | } | |
559 | ||
560 | if (eth_proto_cap & (MLX5E_PROT_MASK(MLX5E_100GBASE_KR4) | |
561 | | MLX5E_PROT_MASK(MLX5E_40GBASE_KR4) | |
562 | | MLX5E_PROT_MASK(MLX5E_10GBASE_KR) | |
563 | | MLX5E_PROT_MASK(MLX5E_10GBASE_KX4) | |
564 | | MLX5E_PROT_MASK(MLX5E_1000BASE_KX))) { | |
565 | ethtool_link_ksettings_add_link_mode(link_ksettings, | |
566 | supported, | |
567 | Backplane); | |
568 | ethtool_link_ksettings_add_link_mode(link_ksettings, | |
569 | advertising, | |
570 | Backplane); | |
571 | } | |
572 | return; | |
f62b8bb8 AV |
573 | } |
574 | ||
46e9d0b6 EBE |
575 | switch (connector_type) { |
576 | case MLX5E_PORT_TP: | |
577 | ethtool_link_ksettings_add_link_mode(link_ksettings, | |
578 | supported, TP); | |
579 | ethtool_link_ksettings_add_link_mode(link_ksettings, | |
580 | advertising, TP); | |
581 | break; | |
582 | case MLX5E_PORT_AUI: | |
583 | ethtool_link_ksettings_add_link_mode(link_ksettings, | |
584 | supported, AUI); | |
585 | ethtool_link_ksettings_add_link_mode(link_ksettings, | |
586 | advertising, AUI); | |
587 | break; | |
588 | case MLX5E_PORT_BNC: | |
589 | ethtool_link_ksettings_add_link_mode(link_ksettings, | |
590 | supported, BNC); | |
591 | ethtool_link_ksettings_add_link_mode(link_ksettings, | |
592 | advertising, BNC); | |
593 | break; | |
594 | case MLX5E_PORT_MII: | |
595 | ethtool_link_ksettings_add_link_mode(link_ksettings, | |
596 | supported, MII); | |
597 | ethtool_link_ksettings_add_link_mode(link_ksettings, | |
598 | advertising, MII); | |
599 | break; | |
600 | case MLX5E_PORT_FIBRE: | |
601 | ethtool_link_ksettings_add_link_mode(link_ksettings, | |
602 | supported, FIBRE); | |
603 | ethtool_link_ksettings_add_link_mode(link_ksettings, | |
604 | advertising, FIBRE); | |
605 | break; | |
606 | case MLX5E_PORT_DA: | |
607 | ethtool_link_ksettings_add_link_mode(link_ksettings, | |
608 | supported, Backplane); | |
609 | ethtool_link_ksettings_add_link_mode(link_ksettings, | |
610 | advertising, Backplane); | |
611 | break; | |
612 | case MLX5E_PORT_NONE: | |
613 | case MLX5E_PORT_OTHER: | |
614 | default: | |
615 | break; | |
f62b8bb8 | 616 | } |
f62b8bb8 AV |
617 | } |
618 | ||
619 | static void get_speed_duplex(struct net_device *netdev, | |
620 | u32 eth_proto_oper, | |
665bc539 | 621 | struct ethtool_link_ksettings *link_ksettings) |
f62b8bb8 | 622 | { |
f62b8bb8 AV |
623 | u32 speed = SPEED_UNKNOWN; |
624 | u8 duplex = DUPLEX_UNKNOWN; | |
625 | ||
626 | if (!netif_carrier_ok(netdev)) | |
627 | goto out; | |
628 | ||
2c81bfd5 HN |
629 | speed = mlx5e_port_ptys2speed(eth_proto_oper); |
630 | if (!speed) { | |
631 | speed = SPEED_UNKNOWN; | |
632 | goto out; | |
f62b8bb8 | 633 | } |
2c81bfd5 HN |
634 | |
635 | duplex = DUPLEX_FULL; | |
636 | ||
f62b8bb8 | 637 | out: |
665bc539 GP |
638 | link_ksettings->base.speed = speed; |
639 | link_ksettings->base.duplex = duplex; | |
f62b8bb8 AV |
640 | } |
641 | ||
665bc539 GP |
642 | static void get_supported(u32 eth_proto_cap, |
643 | struct ethtool_link_ksettings *link_ksettings) | |
f62b8bb8 | 644 | { |
665bc539 GP |
645 | unsigned long *supported = link_ksettings->link_modes.supported; |
646 | ||
665bc539 GP |
647 | ptys2ethtool_supported_link(supported, eth_proto_cap); |
648 | ethtool_link_ksettings_add_link_mode(link_ksettings, supported, Pause); | |
f62b8bb8 AV |
649 | } |
650 | ||
651 | static void get_advertising(u32 eth_proto_cap, u8 tx_pause, | |
665bc539 GP |
652 | u8 rx_pause, |
653 | struct ethtool_link_ksettings *link_ksettings) | |
f62b8bb8 | 654 | { |
665bc539 GP |
655 | unsigned long *advertising = link_ksettings->link_modes.advertising; |
656 | ||
657 | ptys2ethtool_adver_link(advertising, eth_proto_cap); | |
e3c19503 | 658 | if (rx_pause) |
665bc539 GP |
659 | ethtool_link_ksettings_add_link_mode(link_ksettings, advertising, Pause); |
660 | if (tx_pause ^ rx_pause) | |
661 | ethtool_link_ksettings_add_link_mode(link_ksettings, advertising, Asym_Pause); | |
f62b8bb8 AV |
662 | } |
663 | ||
5b4793f8 EBE |
664 | static int ptys2connector_type[MLX5E_CONNECTOR_TYPE_NUMBER] = { |
665 | [MLX5E_PORT_UNKNOWN] = PORT_OTHER, | |
666 | [MLX5E_PORT_NONE] = PORT_NONE, | |
667 | [MLX5E_PORT_TP] = PORT_TP, | |
668 | [MLX5E_PORT_AUI] = PORT_AUI, | |
669 | [MLX5E_PORT_BNC] = PORT_BNC, | |
670 | [MLX5E_PORT_MII] = PORT_MII, | |
671 | [MLX5E_PORT_FIBRE] = PORT_FIBRE, | |
672 | [MLX5E_PORT_DA] = PORT_DA, | |
673 | [MLX5E_PORT_OTHER] = PORT_OTHER, | |
674 | }; | |
675 | ||
676 | static u8 get_connector_port(u32 eth_proto, u8 connector_type) | |
f62b8bb8 | 677 | { |
5b4793f8 EBE |
678 | if (connector_type && connector_type < MLX5E_CONNECTOR_TYPE_NUMBER) |
679 | return ptys2connector_type[connector_type]; | |
680 | ||
61bf2125 OG |
681 | if (eth_proto & |
682 | (MLX5E_PROT_MASK(MLX5E_10GBASE_SR) | | |
683 | MLX5E_PROT_MASK(MLX5E_40GBASE_SR4) | | |
684 | MLX5E_PROT_MASK(MLX5E_100GBASE_SR4) | | |
685 | MLX5E_PROT_MASK(MLX5E_1000BASE_CX_SGMII))) { | |
686 | return PORT_FIBRE; | |
f62b8bb8 AV |
687 | } |
688 | ||
61bf2125 OG |
689 | if (eth_proto & |
690 | (MLX5E_PROT_MASK(MLX5E_40GBASE_CR4) | | |
691 | MLX5E_PROT_MASK(MLX5E_10GBASE_CR) | | |
692 | MLX5E_PROT_MASK(MLX5E_100GBASE_CR4))) { | |
693 | return PORT_DA; | |
f62b8bb8 AV |
694 | } |
695 | ||
61bf2125 OG |
696 | if (eth_proto & |
697 | (MLX5E_PROT_MASK(MLX5E_10GBASE_KX4) | | |
698 | MLX5E_PROT_MASK(MLX5E_10GBASE_KR) | | |
699 | MLX5E_PROT_MASK(MLX5E_40GBASE_KR4) | | |
700 | MLX5E_PROT_MASK(MLX5E_100GBASE_KR4))) { | |
701 | return PORT_NONE; | |
f62b8bb8 AV |
702 | } |
703 | ||
704 | return PORT_OTHER; | |
705 | } | |
706 | ||
665bc539 GP |
707 | static void get_lp_advertising(u32 eth_proto_lp, |
708 | struct ethtool_link_ksettings *link_ksettings) | |
f62b8bb8 | 709 | { |
665bc539 GP |
710 | unsigned long *lp_advertising = link_ksettings->link_modes.lp_advertising; |
711 | ||
712 | ptys2ethtool_adver_link(lp_advertising, eth_proto_lp); | |
f62b8bb8 AV |
713 | } |
714 | ||
665bc539 GP |
715 | static int mlx5e_get_link_ksettings(struct net_device *netdev, |
716 | struct ethtool_link_ksettings *link_ksettings) | |
f62b8bb8 AV |
717 | { |
718 | struct mlx5e_priv *priv = netdev_priv(netdev); | |
719 | struct mlx5_core_dev *mdev = priv->mdev; | |
c4f287c4 | 720 | u32 out[MLX5_ST_SZ_DW(ptys_reg)] = {0}; |
b383b544 GP |
721 | u32 rx_pause = 0; |
722 | u32 tx_pause = 0; | |
f62b8bb8 AV |
723 | u32 eth_proto_cap; |
724 | u32 eth_proto_admin; | |
725 | u32 eth_proto_lp; | |
726 | u32 eth_proto_oper; | |
52244d96 GP |
727 | u8 an_disable_admin; |
728 | u8 an_status; | |
5b4793f8 | 729 | u8 connector_type; |
f62b8bb8 AV |
730 | int err; |
731 | ||
a05bdefa | 732 | err = mlx5_query_port_ptys(mdev, out, sizeof(out), MLX5_PTYS_EN, 1); |
f62b8bb8 AV |
733 | if (err) { |
734 | netdev_err(netdev, "%s: query port ptys failed: %d\n", | |
735 | __func__, err); | |
736 | goto err_query_ptys; | |
737 | } | |
738 | ||
52244d96 GP |
739 | eth_proto_cap = MLX5_GET(ptys_reg, out, eth_proto_capability); |
740 | eth_proto_admin = MLX5_GET(ptys_reg, out, eth_proto_admin); | |
741 | eth_proto_oper = MLX5_GET(ptys_reg, out, eth_proto_oper); | |
742 | eth_proto_lp = MLX5_GET(ptys_reg, out, eth_proto_lp_advertise); | |
743 | an_disable_admin = MLX5_GET(ptys_reg, out, an_disable_admin); | |
744 | an_status = MLX5_GET(ptys_reg, out, an_status); | |
5b4793f8 | 745 | connector_type = MLX5_GET(ptys_reg, out, connector_type); |
f62b8bb8 | 746 | |
b383b544 GP |
747 | mlx5_query_port_pause(mdev, &rx_pause, &tx_pause); |
748 | ||
665bc539 GP |
749 | ethtool_link_ksettings_zero_link_mode(link_ksettings, supported); |
750 | ethtool_link_ksettings_zero_link_mode(link_ksettings, advertising); | |
f62b8bb8 | 751 | |
665bc539 | 752 | get_supported(eth_proto_cap, link_ksettings); |
b383b544 | 753 | get_advertising(eth_proto_admin, tx_pause, rx_pause, link_ksettings); |
665bc539 | 754 | get_speed_duplex(netdev, eth_proto_oper, link_ksettings); |
f62b8bb8 AV |
755 | |
756 | eth_proto_oper = eth_proto_oper ? eth_proto_oper : eth_proto_cap; | |
757 | ||
5b4793f8 EBE |
758 | link_ksettings->base.port = get_connector_port(eth_proto_oper, |
759 | connector_type); | |
46e9d0b6 EBE |
760 | ptys2ethtool_supported_advertised_port(link_ksettings, eth_proto_admin, |
761 | connector_type); | |
665bc539 | 762 | get_lp_advertising(eth_proto_lp, link_ksettings); |
f62b8bb8 | 763 | |
52244d96 GP |
764 | if (an_status == MLX5_AN_COMPLETE) |
765 | ethtool_link_ksettings_add_link_mode(link_ksettings, | |
766 | lp_advertising, Autoneg); | |
767 | ||
768 | link_ksettings->base.autoneg = an_disable_admin ? AUTONEG_DISABLE : | |
769 | AUTONEG_ENABLE; | |
770 | ethtool_link_ksettings_add_link_mode(link_ksettings, supported, | |
771 | Autoneg); | |
772 | if (!an_disable_admin) | |
773 | ethtool_link_ksettings_add_link_mode(link_ksettings, | |
774 | advertising, Autoneg); | |
775 | ||
f62b8bb8 AV |
776 | err_query_ptys: |
777 | return err; | |
778 | } | |
779 | ||
665bc539 | 780 | static u32 mlx5e_ethtool2ptys_adver_link(const unsigned long *link_modes) |
f62b8bb8 AV |
781 | { |
782 | u32 i, ptys_modes = 0; | |
783 | ||
784 | for (i = 0; i < MLX5E_LINK_MODES_NUMBER; ++i) { | |
665bc539 GP |
785 | if (bitmap_intersects(ptys2ethtool_table[i].advertised, |
786 | link_modes, | |
787 | __ETHTOOL_LINK_MODE_MASK_NBITS)) | |
f62b8bb8 AV |
788 | ptys_modes |= MLX5E_PROT_MASK(i); |
789 | } | |
790 | ||
791 | return ptys_modes; | |
792 | } | |
793 | ||
665bc539 GP |
794 | static int mlx5e_set_link_ksettings(struct net_device *netdev, |
795 | const struct ethtool_link_ksettings *link_ksettings) | |
f62b8bb8 AV |
796 | { |
797 | struct mlx5e_priv *priv = netdev_priv(netdev); | |
798 | struct mlx5_core_dev *mdev = priv->mdev; | |
52244d96 GP |
799 | u32 eth_proto_cap, eth_proto_admin; |
800 | bool an_changes = false; | |
801 | u8 an_disable_admin; | |
802 | u8 an_disable_cap; | |
803 | bool an_disable; | |
f62b8bb8 | 804 | u32 link_modes; |
52244d96 | 805 | u8 an_status; |
f62b8bb8 | 806 | u32 speed; |
f62b8bb8 AV |
807 | int err; |
808 | ||
665bc539 | 809 | speed = link_ksettings->base.speed; |
f62b8bb8 | 810 | |
665bc539 GP |
811 | link_modes = link_ksettings->base.autoneg == AUTONEG_ENABLE ? |
812 | mlx5e_ethtool2ptys_adver_link(link_ksettings->link_modes.advertising) : | |
2c81bfd5 | 813 | mlx5e_port_speed2linkmodes(speed); |
f62b8bb8 AV |
814 | |
815 | err = mlx5_query_port_proto_cap(mdev, ð_proto_cap, MLX5_PTYS_EN); | |
816 | if (err) { | |
817 | netdev_err(netdev, "%s: query port eth proto cap failed: %d\n", | |
818 | __func__, err); | |
819 | goto out; | |
820 | } | |
821 | ||
822 | link_modes = link_modes & eth_proto_cap; | |
823 | if (!link_modes) { | |
824 | netdev_err(netdev, "%s: Not supported link mode(s) requested", | |
825 | __func__); | |
826 | err = -EINVAL; | |
827 | goto out; | |
828 | } | |
829 | ||
830 | err = mlx5_query_port_proto_admin(mdev, ð_proto_admin, MLX5_PTYS_EN); | |
831 | if (err) { | |
832 | netdev_err(netdev, "%s: query port eth proto admin failed: %d\n", | |
833 | __func__, err); | |
834 | goto out; | |
835 | } | |
836 | ||
52244d96 GP |
837 | mlx5_query_port_autoneg(mdev, MLX5_PTYS_EN, &an_status, |
838 | &an_disable_cap, &an_disable_admin); | |
839 | ||
840 | an_disable = link_ksettings->base.autoneg == AUTONEG_DISABLE; | |
841 | an_changes = ((!an_disable && an_disable_admin) || | |
842 | (an_disable && !an_disable_admin)); | |
843 | ||
844 | if (!an_changes && link_modes == eth_proto_admin) | |
f62b8bb8 AV |
845 | goto out; |
846 | ||
52244d96 | 847 | mlx5_set_port_ptys(mdev, an_disable, link_modes, MLX5_PTYS_EN); |
667daeda | 848 | mlx5_toggle_port_link(mdev); |
f62b8bb8 | 849 | |
f62b8bb8 AV |
850 | out: |
851 | return err; | |
852 | } | |
853 | ||
2d75b2bc AS |
854 | static u32 mlx5e_get_rxfh_key_size(struct net_device *netdev) |
855 | { | |
856 | struct mlx5e_priv *priv = netdev_priv(netdev); | |
857 | ||
6a9764ef | 858 | return sizeof(priv->channels.params.toeplitz_hash_key); |
2d75b2bc AS |
859 | } |
860 | ||
861 | static u32 mlx5e_get_rxfh_indir_size(struct net_device *netdev) | |
862 | { | |
863 | return MLX5E_INDIR_RQT_SIZE; | |
864 | } | |
865 | ||
2be6967c SM |
866 | static int mlx5e_get_rxfh(struct net_device *netdev, u32 *indir, u8 *key, |
867 | u8 *hfunc) | |
868 | { | |
869 | struct mlx5e_priv *priv = netdev_priv(netdev); | |
870 | ||
2d75b2bc | 871 | if (indir) |
6a9764ef SM |
872 | memcpy(indir, priv->channels.params.indirection_rqt, |
873 | sizeof(priv->channels.params.indirection_rqt)); | |
2d75b2bc AS |
874 | |
875 | if (key) | |
6a9764ef SM |
876 | memcpy(key, priv->channels.params.toeplitz_hash_key, |
877 | sizeof(priv->channels.params.toeplitz_hash_key)); | |
2d75b2bc | 878 | |
2be6967c | 879 | if (hfunc) |
6a9764ef | 880 | *hfunc = priv->channels.params.rss_hfunc; |
2be6967c SM |
881 | |
882 | return 0; | |
883 | } | |
884 | ||
bdfc028d TT |
885 | static void mlx5e_modify_tirs_hash(struct mlx5e_priv *priv, void *in, int inlen) |
886 | { | |
bdfc028d | 887 | void *tirc = MLX5_ADDR_OF(modify_tir_in, in, ctx); |
a100ff3e GP |
888 | struct mlx5_core_dev *mdev = priv->mdev; |
889 | int ctxlen = MLX5_ST_SZ_BYTES(tirc); | |
890 | int tt; | |
bdfc028d TT |
891 | |
892 | MLX5_SET(modify_tir_in, in, bitmask.hash, 1); | |
bdfc028d | 893 | |
a100ff3e GP |
894 | for (tt = 0; tt < MLX5E_NUM_INDIR_TIRS; tt++) { |
895 | memset(tirc, 0, ctxlen); | |
7b3722fa | 896 | mlx5e_build_indir_tir_ctx_hash(&priv->channels.params, tt, tirc, false); |
a100ff3e GP |
897 | mlx5_core_modify_tir(mdev, priv->indir_tir[tt].tirn, in, inlen); |
898 | } | |
7b3722fa GP |
899 | |
900 | if (!mlx5e_tunnel_inner_ft_supported(priv->mdev)) | |
901 | return; | |
902 | ||
903 | for (tt = 0; tt < MLX5E_NUM_INDIR_TIRS; tt++) { | |
904 | memset(tirc, 0, ctxlen); | |
905 | mlx5e_build_indir_tir_ctx_hash(&priv->channels.params, tt, tirc, true); | |
906 | mlx5_core_modify_tir(mdev, priv->inner_indir_tir[tt].tirn, in, inlen); | |
907 | } | |
bdfc028d TT |
908 | } |
909 | ||
98e81b0a | 910 | static int mlx5e_set_rxfh(struct net_device *dev, const u32 *indir, |
2be6967c SM |
911 | const u8 *key, const u8 hfunc) |
912 | { | |
98e81b0a | 913 | struct mlx5e_priv *priv = netdev_priv(dev); |
bdfc028d | 914 | int inlen = MLX5_ST_SZ_BYTES(modify_tir_in); |
1d3398fa | 915 | bool hash_changed = false; |
bdfc028d | 916 | void *in; |
2be6967c | 917 | |
2d75b2bc AS |
918 | if ((hfunc != ETH_RSS_HASH_NO_CHANGE) && |
919 | (hfunc != ETH_RSS_HASH_XOR) && | |
2be6967c SM |
920 | (hfunc != ETH_RSS_HASH_TOP)) |
921 | return -EINVAL; | |
922 | ||
1b9a07ee | 923 | in = kvzalloc(inlen, GFP_KERNEL); |
bdfc028d TT |
924 | if (!in) |
925 | return -ENOMEM; | |
926 | ||
2be6967c SM |
927 | mutex_lock(&priv->state_lock); |
928 | ||
1d3398fa | 929 | if (hfunc != ETH_RSS_HASH_NO_CHANGE && |
6a9764ef SM |
930 | hfunc != priv->channels.params.rss_hfunc) { |
931 | priv->channels.params.rss_hfunc = hfunc; | |
1d3398fa GP |
932 | hash_changed = true; |
933 | } | |
934 | ||
a5f97fee | 935 | if (indir) { |
6a9764ef SM |
936 | memcpy(priv->channels.params.indirection_rqt, indir, |
937 | sizeof(priv->channels.params.indirection_rqt)); | |
a5f97fee SM |
938 | |
939 | if (test_bit(MLX5E_STATE_OPENED, &priv->state)) { | |
940 | u32 rqtn = priv->indir_rqt.rqtn; | |
941 | struct mlx5e_redirect_rqt_param rrp = { | |
942 | .is_rss = true, | |
e270e966 AM |
943 | { |
944 | .rss = { | |
945 | .hfunc = priv->channels.params.rss_hfunc, | |
946 | .channels = &priv->channels, | |
947 | }, | |
948 | }, | |
a5f97fee SM |
949 | }; |
950 | ||
951 | mlx5e_redirect_rqt(priv, rqtn, MLX5E_INDIR_RQT_SIZE, rrp); | |
952 | } | |
953 | } | |
954 | ||
1d3398fa | 955 | if (key) { |
6a9764ef SM |
956 | memcpy(priv->channels.params.toeplitz_hash_key, key, |
957 | sizeof(priv->channels.params.toeplitz_hash_key)); | |
1d3398fa | 958 | hash_changed = hash_changed || |
6a9764ef | 959 | priv->channels.params.rss_hfunc == ETH_RSS_HASH_TOP; |
1d3398fa | 960 | } |
2d75b2bc | 961 | |
1d3398fa GP |
962 | if (hash_changed) |
963 | mlx5e_modify_tirs_hash(priv, in, inlen); | |
2d75b2bc | 964 | |
2be6967c SM |
965 | mutex_unlock(&priv->state_lock); |
966 | ||
bdfc028d TT |
967 | kvfree(in); |
968 | ||
969 | return 0; | |
2be6967c SM |
970 | } |
971 | ||
2d75b2bc AS |
972 | static int mlx5e_get_rxnfc(struct net_device *netdev, |
973 | struct ethtool_rxnfc *info, u32 *rule_locs) | |
974 | { | |
975 | struct mlx5e_priv *priv = netdev_priv(netdev); | |
976 | int err = 0; | |
977 | ||
978 | switch (info->cmd) { | |
979 | case ETHTOOL_GRXRINGS: | |
6a9764ef | 980 | info->data = priv->channels.params.num_channels; |
2d75b2bc | 981 | break; |
f913a72a MG |
982 | case ETHTOOL_GRXCLSRLCNT: |
983 | info->rule_cnt = priv->fs.ethtool.tot_num_rules; | |
984 | break; | |
985 | case ETHTOOL_GRXCLSRULE: | |
986 | err = mlx5e_ethtool_get_flow(priv, info, info->fs.location); | |
987 | break; | |
988 | case ETHTOOL_GRXCLSRLALL: | |
989 | err = mlx5e_ethtool_get_all_flows(priv, info, rule_locs); | |
990 | break; | |
2d75b2bc AS |
991 | default: |
992 | err = -EOPNOTSUPP; | |
993 | break; | |
994 | } | |
995 | ||
996 | return err; | |
997 | } | |
998 | ||
2afa609f IK |
999 | #define MLX5E_PFC_PREVEN_AUTO_TOUT_MSEC 100 |
1000 | #define MLX5E_PFC_PREVEN_TOUT_MAX_MSEC 8000 | |
1001 | #define MLX5E_PFC_PREVEN_MINOR_PRECENT 85 | |
1002 | #define MLX5E_PFC_PREVEN_TOUT_MIN_MSEC 80 | |
1003 | #define MLX5E_DEVICE_STALL_MINOR_WATERMARK(critical_tout) \ | |
1004 | max_t(u16, MLX5E_PFC_PREVEN_TOUT_MIN_MSEC, \ | |
1005 | (critical_tout * MLX5E_PFC_PREVEN_MINOR_PRECENT) / 100) | |
1006 | ||
1007 | static int mlx5e_get_pfc_prevention_tout(struct net_device *netdev, | |
1008 | u16 *pfc_prevention_tout) | |
1009 | { | |
1010 | struct mlx5e_priv *priv = netdev_priv(netdev); | |
1011 | struct mlx5_core_dev *mdev = priv->mdev; | |
1012 | ||
1013 | if (!MLX5_CAP_PCAM_FEATURE((priv)->mdev, pfcc_mask) || | |
1014 | !MLX5_CAP_DEBUG((priv)->mdev, stall_detect)) | |
1015 | return -EOPNOTSUPP; | |
1016 | ||
1017 | return mlx5_query_port_stall_watermark(mdev, pfc_prevention_tout, NULL); | |
1018 | } | |
1019 | ||
1020 | static int mlx5e_set_pfc_prevention_tout(struct net_device *netdev, | |
1021 | u16 pfc_preven) | |
1022 | { | |
1023 | struct mlx5e_priv *priv = netdev_priv(netdev); | |
1024 | struct mlx5_core_dev *mdev = priv->mdev; | |
1025 | u16 critical_tout; | |
1026 | u16 minor; | |
1027 | ||
1028 | if (!MLX5_CAP_PCAM_FEATURE((priv)->mdev, pfcc_mask) || | |
1029 | !MLX5_CAP_DEBUG((priv)->mdev, stall_detect)) | |
1030 | return -EOPNOTSUPP; | |
1031 | ||
1032 | critical_tout = (pfc_preven == PFC_STORM_PREVENTION_AUTO) ? | |
1033 | MLX5E_PFC_PREVEN_AUTO_TOUT_MSEC : | |
1034 | pfc_preven; | |
1035 | ||
1036 | if (critical_tout != PFC_STORM_PREVENTION_DISABLE && | |
1037 | (critical_tout > MLX5E_PFC_PREVEN_TOUT_MAX_MSEC || | |
1038 | critical_tout < MLX5E_PFC_PREVEN_TOUT_MIN_MSEC)) { | |
1039 | netdev_info(netdev, "%s: pfc prevention tout not in range (%d-%d)\n", | |
1040 | __func__, MLX5E_PFC_PREVEN_TOUT_MIN_MSEC, | |
1041 | MLX5E_PFC_PREVEN_TOUT_MAX_MSEC); | |
1042 | return -EINVAL; | |
1043 | } | |
1044 | ||
1045 | minor = MLX5E_DEVICE_STALL_MINOR_WATERMARK(critical_tout); | |
1046 | return mlx5_set_port_stall_watermark(mdev, critical_tout, | |
1047 | minor); | |
1048 | } | |
1049 | ||
58d52291 AS |
1050 | static int mlx5e_get_tunable(struct net_device *dev, |
1051 | const struct ethtool_tunable *tuna, | |
1052 | void *data) | |
1053 | { | |
c4554fbc | 1054 | int err; |
58d52291 AS |
1055 | |
1056 | switch (tuna->id) { | |
2afa609f IK |
1057 | case ETHTOOL_PFC_PREVENTION_TOUT: |
1058 | err = mlx5e_get_pfc_prevention_tout(dev, data); | |
1059 | break; | |
58d52291 AS |
1060 | default: |
1061 | err = -EINVAL; | |
1062 | break; | |
1063 | } | |
1064 | ||
1065 | return err; | |
1066 | } | |
1067 | ||
1068 | static int mlx5e_set_tunable(struct net_device *dev, | |
1069 | const struct ethtool_tunable *tuna, | |
1070 | const void *data) | |
1071 | { | |
1072 | struct mlx5e_priv *priv = netdev_priv(dev); | |
c4554fbc | 1073 | int err; |
546f18ed SM |
1074 | |
1075 | mutex_lock(&priv->state_lock); | |
58d52291 AS |
1076 | |
1077 | switch (tuna->id) { | |
2afa609f IK |
1078 | case ETHTOOL_PFC_PREVENTION_TOUT: |
1079 | err = mlx5e_set_pfc_prevention_tout(dev, *(u16 *)data); | |
58d52291 AS |
1080 | break; |
1081 | default: | |
1082 | err = -EINVAL; | |
1083 | break; | |
1084 | } | |
1085 | ||
546f18ed | 1086 | mutex_unlock(&priv->state_lock); |
58d52291 AS |
1087 | return err; |
1088 | } | |
1089 | ||
3c2d18ef AS |
1090 | static void mlx5e_get_pauseparam(struct net_device *netdev, |
1091 | struct ethtool_pauseparam *pauseparam) | |
1092 | { | |
1093 | struct mlx5e_priv *priv = netdev_priv(netdev); | |
1094 | struct mlx5_core_dev *mdev = priv->mdev; | |
1095 | int err; | |
1096 | ||
1097 | err = mlx5_query_port_pause(mdev, &pauseparam->rx_pause, | |
1098 | &pauseparam->tx_pause); | |
1099 | if (err) { | |
1100 | netdev_err(netdev, "%s: mlx5_query_port_pause failed:0x%x\n", | |
1101 | __func__, err); | |
1102 | } | |
1103 | } | |
1104 | ||
1105 | static int mlx5e_set_pauseparam(struct net_device *netdev, | |
1106 | struct ethtool_pauseparam *pauseparam) | |
1107 | { | |
1108 | struct mlx5e_priv *priv = netdev_priv(netdev); | |
1109 | struct mlx5_core_dev *mdev = priv->mdev; | |
1110 | int err; | |
1111 | ||
1112 | if (pauseparam->autoneg) | |
1113 | return -EINVAL; | |
1114 | ||
1115 | err = mlx5_set_port_pause(mdev, | |
1116 | pauseparam->rx_pause ? 1 : 0, | |
1117 | pauseparam->tx_pause ? 1 : 0); | |
1118 | if (err) { | |
1119 | netdev_err(netdev, "%s: mlx5_set_port_pause failed:0x%x\n", | |
1120 | __func__, err); | |
1121 | } | |
1122 | ||
1123 | return err; | |
1124 | } | |
1125 | ||
3844b07e FD |
1126 | int mlx5e_ethtool_get_ts_info(struct mlx5e_priv *priv, |
1127 | struct ethtool_ts_info *info) | |
ef9814de | 1128 | { |
7c39afb3 | 1129 | struct mlx5_core_dev *mdev = priv->mdev; |
ef9814de EBE |
1130 | int ret; |
1131 | ||
3844b07e | 1132 | ret = ethtool_op_get_ts_info(priv->netdev, info); |
ef9814de EBE |
1133 | if (ret) |
1134 | return ret; | |
1135 | ||
7c39afb3 FD |
1136 | info->phc_index = mdev->clock.ptp ? |
1137 | ptp_clock_index(mdev->clock.ptp) : -1; | |
ef9814de EBE |
1138 | |
1139 | if (!MLX5_CAP_GEN(priv->mdev, device_frequency_khz)) | |
1140 | return 0; | |
1141 | ||
1142 | info->so_timestamping |= SOF_TIMESTAMPING_TX_HARDWARE | | |
1143 | SOF_TIMESTAMPING_RX_HARDWARE | | |
1144 | SOF_TIMESTAMPING_RAW_HARDWARE; | |
1145 | ||
f0b38117 MD |
1146 | info->tx_types = BIT(HWTSTAMP_TX_OFF) | |
1147 | BIT(HWTSTAMP_TX_ON); | |
ef9814de | 1148 | |
f0b38117 MD |
1149 | info->rx_filters = BIT(HWTSTAMP_FILTER_NONE) | |
1150 | BIT(HWTSTAMP_FILTER_ALL); | |
ef9814de EBE |
1151 | |
1152 | return 0; | |
1153 | } | |
1154 | ||
3844b07e FD |
1155 | static int mlx5e_get_ts_info(struct net_device *dev, |
1156 | struct ethtool_ts_info *info) | |
1157 | { | |
1158 | struct mlx5e_priv *priv = netdev_priv(dev); | |
1159 | ||
1160 | return mlx5e_ethtool_get_ts_info(priv, info); | |
1161 | } | |
1162 | ||
928cfe87 TT |
1163 | static __u32 mlx5e_get_wol_supported(struct mlx5_core_dev *mdev) |
1164 | { | |
1165 | __u32 ret = 0; | |
1166 | ||
1167 | if (MLX5_CAP_GEN(mdev, wol_g)) | |
1168 | ret |= WAKE_MAGIC; | |
1169 | ||
1170 | if (MLX5_CAP_GEN(mdev, wol_s)) | |
1171 | ret |= WAKE_MAGICSECURE; | |
1172 | ||
1173 | if (MLX5_CAP_GEN(mdev, wol_a)) | |
1174 | ret |= WAKE_ARP; | |
1175 | ||
1176 | if (MLX5_CAP_GEN(mdev, wol_b)) | |
1177 | ret |= WAKE_BCAST; | |
1178 | ||
1179 | if (MLX5_CAP_GEN(mdev, wol_m)) | |
1180 | ret |= WAKE_MCAST; | |
1181 | ||
1182 | if (MLX5_CAP_GEN(mdev, wol_u)) | |
1183 | ret |= WAKE_UCAST; | |
1184 | ||
1185 | if (MLX5_CAP_GEN(mdev, wol_p)) | |
1186 | ret |= WAKE_PHY; | |
1187 | ||
1188 | return ret; | |
1189 | } | |
1190 | ||
1191 | static __u32 mlx5e_refomrat_wol_mode_mlx5_to_linux(u8 mode) | |
1192 | { | |
1193 | __u32 ret = 0; | |
1194 | ||
1195 | if (mode & MLX5_WOL_MAGIC) | |
1196 | ret |= WAKE_MAGIC; | |
1197 | ||
1198 | if (mode & MLX5_WOL_SECURED_MAGIC) | |
1199 | ret |= WAKE_MAGICSECURE; | |
1200 | ||
1201 | if (mode & MLX5_WOL_ARP) | |
1202 | ret |= WAKE_ARP; | |
1203 | ||
1204 | if (mode & MLX5_WOL_BROADCAST) | |
1205 | ret |= WAKE_BCAST; | |
1206 | ||
1207 | if (mode & MLX5_WOL_MULTICAST) | |
1208 | ret |= WAKE_MCAST; | |
1209 | ||
1210 | if (mode & MLX5_WOL_UNICAST) | |
1211 | ret |= WAKE_UCAST; | |
1212 | ||
1213 | if (mode & MLX5_WOL_PHY_ACTIVITY) | |
1214 | ret |= WAKE_PHY; | |
1215 | ||
1216 | return ret; | |
1217 | } | |
1218 | ||
1219 | static u8 mlx5e_refomrat_wol_mode_linux_to_mlx5(__u32 mode) | |
1220 | { | |
1221 | u8 ret = 0; | |
1222 | ||
1223 | if (mode & WAKE_MAGIC) | |
1224 | ret |= MLX5_WOL_MAGIC; | |
1225 | ||
1226 | if (mode & WAKE_MAGICSECURE) | |
1227 | ret |= MLX5_WOL_SECURED_MAGIC; | |
1228 | ||
1229 | if (mode & WAKE_ARP) | |
1230 | ret |= MLX5_WOL_ARP; | |
1231 | ||
1232 | if (mode & WAKE_BCAST) | |
1233 | ret |= MLX5_WOL_BROADCAST; | |
1234 | ||
1235 | if (mode & WAKE_MCAST) | |
1236 | ret |= MLX5_WOL_MULTICAST; | |
1237 | ||
1238 | if (mode & WAKE_UCAST) | |
1239 | ret |= MLX5_WOL_UNICAST; | |
1240 | ||
1241 | if (mode & WAKE_PHY) | |
1242 | ret |= MLX5_WOL_PHY_ACTIVITY; | |
1243 | ||
1244 | return ret; | |
1245 | } | |
1246 | ||
1247 | static void mlx5e_get_wol(struct net_device *netdev, | |
1248 | struct ethtool_wolinfo *wol) | |
1249 | { | |
1250 | struct mlx5e_priv *priv = netdev_priv(netdev); | |
1251 | struct mlx5_core_dev *mdev = priv->mdev; | |
1252 | u8 mlx5_wol_mode; | |
1253 | int err; | |
1254 | ||
1255 | memset(wol, 0, sizeof(*wol)); | |
1256 | ||
1257 | wol->supported = mlx5e_get_wol_supported(mdev); | |
1258 | if (!wol->supported) | |
1259 | return; | |
1260 | ||
1261 | err = mlx5_query_port_wol(mdev, &mlx5_wol_mode); | |
1262 | if (err) | |
1263 | return; | |
1264 | ||
1265 | wol->wolopts = mlx5e_refomrat_wol_mode_mlx5_to_linux(mlx5_wol_mode); | |
1266 | } | |
1267 | ||
1268 | static int mlx5e_set_wol(struct net_device *netdev, struct ethtool_wolinfo *wol) | |
1269 | { | |
1270 | struct mlx5e_priv *priv = netdev_priv(netdev); | |
1271 | struct mlx5_core_dev *mdev = priv->mdev; | |
1272 | __u32 wol_supported = mlx5e_get_wol_supported(mdev); | |
1273 | u32 mlx5_wol_mode; | |
1274 | ||
1275 | if (!wol_supported) | |
9eb78923 | 1276 | return -EOPNOTSUPP; |
928cfe87 TT |
1277 | |
1278 | if (wol->wolopts & ~wol_supported) | |
1279 | return -EINVAL; | |
1280 | ||
1281 | mlx5_wol_mode = mlx5e_refomrat_wol_mode_linux_to_mlx5(wol->wolopts); | |
1282 | ||
1283 | return mlx5_set_port_wol(mdev, mlx5_wol_mode); | |
1284 | } | |
1285 | ||
79c48764 GP |
1286 | static u32 mlx5e_get_msglevel(struct net_device *dev) |
1287 | { | |
1288 | return ((struct mlx5e_priv *)netdev_priv(dev))->msglevel; | |
1289 | } | |
1290 | ||
1291 | static void mlx5e_set_msglevel(struct net_device *dev, u32 val) | |
1292 | { | |
1293 | ((struct mlx5e_priv *)netdev_priv(dev))->msglevel = val; | |
1294 | } | |
1295 | ||
da54d24e GP |
1296 | static int mlx5e_set_phys_id(struct net_device *dev, |
1297 | enum ethtool_phys_id_state state) | |
1298 | { | |
1299 | struct mlx5e_priv *priv = netdev_priv(dev); | |
1300 | struct mlx5_core_dev *mdev = priv->mdev; | |
1301 | u16 beacon_duration; | |
1302 | ||
1303 | if (!MLX5_CAP_GEN(mdev, beacon_led)) | |
1304 | return -EOPNOTSUPP; | |
1305 | ||
1306 | switch (state) { | |
1307 | case ETHTOOL_ID_ACTIVE: | |
1308 | beacon_duration = MLX5_BEACON_DURATION_INF; | |
1309 | break; | |
1310 | case ETHTOOL_ID_INACTIVE: | |
1311 | beacon_duration = MLX5_BEACON_DURATION_OFF; | |
1312 | break; | |
1313 | default: | |
1314 | return -EOPNOTSUPP; | |
1315 | } | |
1316 | ||
1317 | return mlx5_set_port_beacon(mdev, beacon_duration); | |
1318 | } | |
1319 | ||
bb64143e GP |
1320 | static int mlx5e_get_module_info(struct net_device *netdev, |
1321 | struct ethtool_modinfo *modinfo) | |
1322 | { | |
1323 | struct mlx5e_priv *priv = netdev_priv(netdev); | |
1324 | struct mlx5_core_dev *dev = priv->mdev; | |
1325 | int size_read = 0; | |
1326 | u8 data[4]; | |
1327 | ||
1328 | size_read = mlx5_query_module_eeprom(dev, 0, 2, data); | |
1329 | if (size_read < 2) | |
1330 | return -EIO; | |
1331 | ||
1332 | /* data[0] = identifier byte */ | |
1333 | switch (data[0]) { | |
1334 | case MLX5_MODULE_ID_QSFP: | |
1335 | modinfo->type = ETH_MODULE_SFF_8436; | |
1336 | modinfo->eeprom_len = ETH_MODULE_SFF_8436_LEN; | |
1337 | break; | |
1338 | case MLX5_MODULE_ID_QSFP_PLUS: | |
1339 | case MLX5_MODULE_ID_QSFP28: | |
1340 | /* data[1] = revision id */ | |
1341 | if (data[0] == MLX5_MODULE_ID_QSFP28 || data[1] >= 0x3) { | |
1342 | modinfo->type = ETH_MODULE_SFF_8636; | |
1343 | modinfo->eeprom_len = ETH_MODULE_SFF_8636_LEN; | |
1344 | } else { | |
1345 | modinfo->type = ETH_MODULE_SFF_8436; | |
1346 | modinfo->eeprom_len = ETH_MODULE_SFF_8436_LEN; | |
1347 | } | |
1348 | break; | |
1349 | case MLX5_MODULE_ID_SFP: | |
1350 | modinfo->type = ETH_MODULE_SFF_8472; | |
1351 | modinfo->eeprom_len = ETH_MODULE_SFF_8472_LEN; | |
1352 | break; | |
1353 | default: | |
1354 | netdev_err(priv->netdev, "%s: cable type not recognized:0x%x\n", | |
1355 | __func__, data[0]); | |
1356 | return -EINVAL; | |
1357 | } | |
1358 | ||
1359 | return 0; | |
1360 | } | |
1361 | ||
1362 | static int mlx5e_get_module_eeprom(struct net_device *netdev, | |
1363 | struct ethtool_eeprom *ee, | |
1364 | u8 *data) | |
1365 | { | |
1366 | struct mlx5e_priv *priv = netdev_priv(netdev); | |
1367 | struct mlx5_core_dev *mdev = priv->mdev; | |
1368 | int offset = ee->offset; | |
1369 | int size_read; | |
1370 | int i = 0; | |
1371 | ||
1372 | if (!ee->len) | |
1373 | return -EINVAL; | |
1374 | ||
1375 | memset(data, 0, ee->len); | |
1376 | ||
1377 | while (i < ee->len) { | |
1378 | size_read = mlx5_query_module_eeprom(mdev, offset, ee->len - i, | |
1379 | data + i); | |
1380 | ||
1381 | if (!size_read) | |
1382 | /* Done reading */ | |
1383 | return 0; | |
1384 | ||
1385 | if (size_read < 0) { | |
1386 | netdev_err(priv->netdev, "%s: mlx5_query_eeprom failed:0x%x\n", | |
1387 | __func__, size_read); | |
1388 | return 0; | |
1389 | } | |
1390 | ||
1391 | i += size_read; | |
1392 | offset += size_read; | |
1393 | } | |
1394 | ||
1395 | return 0; | |
1396 | } | |
1397 | ||
4e59e288 GP |
1398 | typedef int (*mlx5e_pflag_handler)(struct net_device *netdev, bool enable); |
1399 | ||
0088cbbc TG |
1400 | static int set_pflag_cqe_based_moder(struct net_device *netdev, bool enable, |
1401 | bool is_rx_cq) | |
4e59e288 | 1402 | { |
9908aa29 TT |
1403 | struct mlx5e_priv *priv = netdev_priv(netdev); |
1404 | struct mlx5_core_dev *mdev = priv->mdev; | |
be7e87f9 | 1405 | struct mlx5e_channels new_channels = {}; |
0088cbbc TG |
1406 | bool mode_changed; |
1407 | u8 cq_period_mode, current_cq_period_mode; | |
9908aa29 | 1408 | int err = 0; |
9908aa29 | 1409 | |
0088cbbc | 1410 | cq_period_mode = enable ? |
9908aa29 TT |
1411 | MLX5_CQ_PERIOD_MODE_START_FROM_CQE : |
1412 | MLX5_CQ_PERIOD_MODE_START_FROM_EQE; | |
0088cbbc TG |
1413 | current_cq_period_mode = is_rx_cq ? |
1414 | priv->channels.params.rx_cq_moderation.cq_period_mode : | |
1415 | priv->channels.params.tx_cq_moderation.cq_period_mode; | |
1416 | mode_changed = cq_period_mode != current_cq_period_mode; | |
9908aa29 | 1417 | |
0088cbbc | 1418 | if (cq_period_mode == MLX5_CQ_PERIOD_MODE_START_FROM_CQE && |
9908aa29 | 1419 | !MLX5_CAP_GEN(mdev, cq_period_start_from_cqe)) |
9eb78923 | 1420 | return -EOPNOTSUPP; |
9908aa29 | 1421 | |
0088cbbc | 1422 | if (!mode_changed) |
9908aa29 TT |
1423 | return 0; |
1424 | ||
be7e87f9 | 1425 | new_channels.params = priv->channels.params; |
0088cbbc TG |
1426 | if (is_rx_cq) |
1427 | mlx5e_set_rx_cq_mode_params(&new_channels.params, cq_period_mode); | |
1428 | else | |
1429 | mlx5e_set_tx_cq_mode_params(&new_channels.params, cq_period_mode); | |
9908aa29 | 1430 | |
be7e87f9 SM |
1431 | if (!test_bit(MLX5E_STATE_OPENED, &priv->state)) { |
1432 | priv->channels.params = new_channels.params; | |
1433 | return 0; | |
1434 | } | |
1435 | ||
1436 | err = mlx5e_open_channels(priv, &new_channels); | |
1437 | if (err) | |
1438 | return err; | |
9908aa29 | 1439 | |
2e20a151 | 1440 | mlx5e_switch_priv_channels(priv, &new_channels, NULL); |
be7e87f9 SM |
1441 | return 0; |
1442 | } | |
9908aa29 | 1443 | |
0088cbbc TG |
1444 | static int set_pflag_tx_cqe_based_moder(struct net_device *netdev, bool enable) |
1445 | { | |
1446 | return set_pflag_cqe_based_moder(netdev, enable, false); | |
1447 | } | |
1448 | ||
1449 | static int set_pflag_rx_cqe_based_moder(struct net_device *netdev, bool enable) | |
1450 | { | |
1451 | return set_pflag_cqe_based_moder(netdev, enable, true); | |
1452 | } | |
1453 | ||
be7e87f9 SM |
1454 | int mlx5e_modify_rx_cqe_compression_locked(struct mlx5e_priv *priv, bool new_val) |
1455 | { | |
1456 | bool curr_val = MLX5E_GET_PFLAG(&priv->channels.params, MLX5E_PFLAG_RX_CQE_COMPRESS); | |
1457 | struct mlx5e_channels new_channels = {}; | |
1458 | int err = 0; | |
1459 | ||
1460 | if (!MLX5_CAP_GEN(priv->mdev, cqe_compression)) | |
1461 | return new_val ? -EOPNOTSUPP : 0; | |
1462 | ||
1463 | if (curr_val == new_val) | |
1464 | return 0; | |
1465 | ||
1466 | new_channels.params = priv->channels.params; | |
1467 | MLX5E_SET_PFLAG(&new_channels.params, MLX5E_PFLAG_RX_CQE_COMPRESS, new_val); | |
1468 | ||
be7e87f9 SM |
1469 | if (!test_bit(MLX5E_STATE_OPENED, &priv->state)) { |
1470 | priv->channels.params = new_channels.params; | |
1471 | return 0; | |
1472 | } | |
1473 | ||
1474 | err = mlx5e_open_channels(priv, &new_channels); | |
1475 | if (err) | |
1476 | return err; | |
1477 | ||
2e20a151 | 1478 | mlx5e_switch_priv_channels(priv, &new_channels, NULL); |
696a97cf EE |
1479 | mlx5e_dbg(DRV, priv, "MLX5E: RxCqeCmprss was turned %s\n", |
1480 | MLX5E_GET_PFLAG(&priv->channels.params, | |
1481 | MLX5E_PFLAG_RX_CQE_COMPRESS) ? "ON" : "OFF"); | |
1482 | ||
be7e87f9 | 1483 | return 0; |
4e59e288 GP |
1484 | } |
1485 | ||
9bcc8606 SD |
1486 | static int set_pflag_rx_cqe_compress(struct net_device *netdev, |
1487 | bool enable) | |
1488 | { | |
1489 | struct mlx5e_priv *priv = netdev_priv(netdev); | |
1490 | struct mlx5_core_dev *mdev = priv->mdev; | |
9bcc8606 SD |
1491 | |
1492 | if (!MLX5_CAP_GEN(mdev, cqe_compression)) | |
9eb78923 | 1493 | return -EOPNOTSUPP; |
9bcc8606 | 1494 | |
7c39afb3 | 1495 | if (enable && priv->tstamp.rx_filter != HWTSTAMP_FILTER_NONE) { |
9bcc8606 SD |
1496 | netdev_err(netdev, "Can't enable cqe compression while timestamping is enabled.\n"); |
1497 | return -EINVAL; | |
1498 | } | |
1499 | ||
5eb0249b | 1500 | mlx5e_modify_rx_cqe_compression_locked(priv, enable); |
6a9764ef | 1501 | priv->channels.params.rx_cqe_compress_def = enable; |
9bcc8606 | 1502 | |
5eb0249b | 1503 | return 0; |
9bcc8606 SD |
1504 | } |
1505 | ||
2ccb0a79 TT |
1506 | static int set_pflag_rx_striding_rq(struct net_device *netdev, bool enable) |
1507 | { | |
1508 | struct mlx5e_priv *priv = netdev_priv(netdev); | |
1509 | struct mlx5_core_dev *mdev = priv->mdev; | |
1510 | struct mlx5e_channels new_channels = {}; | |
1511 | int err; | |
1512 | ||
1513 | if (enable) { | |
1514 | if (!mlx5e_check_fragmented_striding_rq_cap(mdev)) | |
1515 | return -EOPNOTSUPP; | |
1516 | if (!mlx5e_striding_rq_possible(mdev, &priv->channels.params)) | |
1517 | return -EINVAL; | |
1518 | } | |
1519 | ||
1520 | new_channels.params = priv->channels.params; | |
1521 | ||
1522 | MLX5E_SET_PFLAG(&new_channels.params, MLX5E_PFLAG_RX_STRIDING_RQ, enable); | |
1523 | mlx5e_set_rq_type(mdev, &new_channels.params); | |
1524 | ||
1525 | if (!test_bit(MLX5E_STATE_OPENED, &priv->state)) { | |
1526 | priv->channels.params = new_channels.params; | |
1527 | return 0; | |
1528 | } | |
1529 | ||
1530 | err = mlx5e_open_channels(priv, &new_channels); | |
1531 | if (err) | |
1532 | return err; | |
1533 | ||
1534 | mlx5e_switch_priv_channels(priv, &new_channels, NULL); | |
1535 | return 0; | |
1536 | } | |
1537 | ||
4e59e288 GP |
1538 | static int mlx5e_handle_pflag(struct net_device *netdev, |
1539 | u32 wanted_flags, | |
1540 | enum mlx5e_priv_flag flag, | |
1541 | mlx5e_pflag_handler pflag_handler) | |
1542 | { | |
1543 | struct mlx5e_priv *priv = netdev_priv(netdev); | |
1544 | bool enable = !!(wanted_flags & flag); | |
6a9764ef | 1545 | u32 changes = wanted_flags ^ priv->channels.params.pflags; |
4e59e288 GP |
1546 | int err; |
1547 | ||
1548 | if (!(changes & flag)) | |
1549 | return 0; | |
1550 | ||
1551 | err = pflag_handler(netdev, enable); | |
1552 | if (err) { | |
1553 | netdev_err(netdev, "%s private flag 0x%x failed err %d\n", | |
1554 | enable ? "Enable" : "Disable", flag, err); | |
1555 | return err; | |
1556 | } | |
1557 | ||
6a9764ef | 1558 | MLX5E_SET_PFLAG(&priv->channels.params, flag, enable); |
4e59e288 GP |
1559 | return 0; |
1560 | } | |
1561 | ||
1562 | static int mlx5e_set_priv_flags(struct net_device *netdev, u32 pflags) | |
1563 | { | |
1564 | struct mlx5e_priv *priv = netdev_priv(netdev); | |
1565 | int err; | |
1566 | ||
1567 | mutex_lock(&priv->state_lock); | |
9908aa29 TT |
1568 | err = mlx5e_handle_pflag(netdev, pflags, |
1569 | MLX5E_PFLAG_RX_CQE_BASED_MODER, | |
1570 | set_pflag_rx_cqe_based_moder); | |
9bcc8606 SD |
1571 | if (err) |
1572 | goto out; | |
4e59e288 | 1573 | |
0088cbbc TG |
1574 | err = mlx5e_handle_pflag(netdev, pflags, |
1575 | MLX5E_PFLAG_TX_CQE_BASED_MODER, | |
1576 | set_pflag_tx_cqe_based_moder); | |
1577 | if (err) | |
1578 | goto out; | |
1579 | ||
9bcc8606 SD |
1580 | err = mlx5e_handle_pflag(netdev, pflags, |
1581 | MLX5E_PFLAG_RX_CQE_COMPRESS, | |
1582 | set_pflag_rx_cqe_compress); | |
2ccb0a79 TT |
1583 | if (err) |
1584 | goto out; | |
1585 | ||
1586 | err = mlx5e_handle_pflag(netdev, pflags, | |
1587 | MLX5E_PFLAG_RX_STRIDING_RQ, | |
1588 | set_pflag_rx_striding_rq); | |
9bcc8606 SD |
1589 | |
1590 | out: | |
4e59e288 | 1591 | mutex_unlock(&priv->state_lock); |
9bcc8606 | 1592 | return err; |
4e59e288 GP |
1593 | } |
1594 | ||
1595 | static u32 mlx5e_get_priv_flags(struct net_device *netdev) | |
1596 | { | |
1597 | struct mlx5e_priv *priv = netdev_priv(netdev); | |
1598 | ||
6a9764ef | 1599 | return priv->channels.params.pflags; |
4e59e288 GP |
1600 | } |
1601 | ||
6dc6071c MG |
1602 | static int mlx5e_set_rxnfc(struct net_device *dev, struct ethtool_rxnfc *cmd) |
1603 | { | |
1604 | int err = 0; | |
1605 | struct mlx5e_priv *priv = netdev_priv(dev); | |
1606 | ||
1607 | switch (cmd->cmd) { | |
1608 | case ETHTOOL_SRXCLSRLINS: | |
1609 | err = mlx5e_ethtool_flow_replace(priv, &cmd->fs); | |
1610 | break; | |
1611 | case ETHTOOL_SRXCLSRLDEL: | |
1612 | err = mlx5e_ethtool_flow_remove(priv, cmd->fs.location); | |
1613 | break; | |
1614 | default: | |
1615 | err = -EOPNOTSUPP; | |
1616 | break; | |
1617 | } | |
1618 | ||
1619 | return err; | |
1620 | } | |
1621 | ||
3ffaabec OG |
1622 | int mlx5e_ethtool_flash_device(struct mlx5e_priv *priv, |
1623 | struct ethtool_flash *flash) | |
1624 | { | |
1625 | struct mlx5_core_dev *mdev = priv->mdev; | |
1626 | struct net_device *dev = priv->netdev; | |
1627 | const struct firmware *fw; | |
1628 | int err; | |
1629 | ||
1630 | if (flash->region != ETHTOOL_FLASH_ALL_REGIONS) | |
1631 | return -EOPNOTSUPP; | |
1632 | ||
1633 | err = request_firmware_direct(&fw, flash->data, &dev->dev); | |
1634 | if (err) | |
1635 | return err; | |
1636 | ||
1637 | dev_hold(dev); | |
1638 | rtnl_unlock(); | |
1639 | ||
1640 | err = mlx5_firmware_flash(mdev, fw); | |
1641 | release_firmware(fw); | |
1642 | ||
1643 | rtnl_lock(); | |
1644 | dev_put(dev); | |
1645 | return err; | |
1646 | } | |
1647 | ||
1648 | static int mlx5e_flash_device(struct net_device *dev, | |
1649 | struct ethtool_flash *flash) | |
1650 | { | |
1651 | struct mlx5e_priv *priv = netdev_priv(dev); | |
1652 | ||
1653 | return mlx5e_ethtool_flash_device(priv, flash); | |
1654 | } | |
1655 | ||
f62b8bb8 AV |
1656 | const struct ethtool_ops mlx5e_ethtool_ops = { |
1657 | .get_drvinfo = mlx5e_get_drvinfo, | |
1658 | .get_link = ethtool_op_get_link, | |
1659 | .get_strings = mlx5e_get_strings, | |
1660 | .get_sset_count = mlx5e_get_sset_count, | |
1661 | .get_ethtool_stats = mlx5e_get_ethtool_stats, | |
1662 | .get_ringparam = mlx5e_get_ringparam, | |
1663 | .set_ringparam = mlx5e_set_ringparam, | |
1664 | .get_channels = mlx5e_get_channels, | |
1665 | .set_channels = mlx5e_set_channels, | |
1666 | .get_coalesce = mlx5e_get_coalesce, | |
1667 | .set_coalesce = mlx5e_set_coalesce, | |
665bc539 GP |
1668 | .get_link_ksettings = mlx5e_get_link_ksettings, |
1669 | .set_link_ksettings = mlx5e_set_link_ksettings, | |
2d75b2bc AS |
1670 | .get_rxfh_key_size = mlx5e_get_rxfh_key_size, |
1671 | .get_rxfh_indir_size = mlx5e_get_rxfh_indir_size, | |
2be6967c SM |
1672 | .get_rxfh = mlx5e_get_rxfh, |
1673 | .set_rxfh = mlx5e_set_rxfh, | |
2d75b2bc | 1674 | .get_rxnfc = mlx5e_get_rxnfc, |
6dc6071c | 1675 | .set_rxnfc = mlx5e_set_rxnfc, |
3ffaabec | 1676 | .flash_device = mlx5e_flash_device, |
58d52291 AS |
1677 | .get_tunable = mlx5e_get_tunable, |
1678 | .set_tunable = mlx5e_set_tunable, | |
3c2d18ef AS |
1679 | .get_pauseparam = mlx5e_get_pauseparam, |
1680 | .set_pauseparam = mlx5e_set_pauseparam, | |
ef9814de | 1681 | .get_ts_info = mlx5e_get_ts_info, |
da54d24e | 1682 | .set_phys_id = mlx5e_set_phys_id, |
928cfe87 TT |
1683 | .get_wol = mlx5e_get_wol, |
1684 | .set_wol = mlx5e_set_wol, | |
bb64143e GP |
1685 | .get_module_info = mlx5e_get_module_info, |
1686 | .get_module_eeprom = mlx5e_get_module_eeprom, | |
4e59e288 | 1687 | .get_priv_flags = mlx5e_get_priv_flags, |
d605d668 KH |
1688 | .set_priv_flags = mlx5e_set_priv_flags, |
1689 | .self_test = mlx5e_self_test, | |
79c48764 GP |
1690 | .get_msglevel = mlx5e_get_msglevel, |
1691 | .set_msglevel = mlx5e_set_msglevel, | |
1692 | ||
f62b8bb8 | 1693 | }; |