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" | |
34 | ||
35 | static void mlx5e_get_drvinfo(struct net_device *dev, | |
36 | struct ethtool_drvinfo *drvinfo) | |
37 | { | |
38 | struct mlx5e_priv *priv = netdev_priv(dev); | |
39 | struct mlx5_core_dev *mdev = priv->mdev; | |
40 | ||
41 | strlcpy(drvinfo->driver, DRIVER_NAME, sizeof(drvinfo->driver)); | |
42 | strlcpy(drvinfo->version, DRIVER_VERSION " (" DRIVER_RELDATE ")", | |
43 | sizeof(drvinfo->version)); | |
44 | snprintf(drvinfo->fw_version, sizeof(drvinfo->fw_version), | |
45 | "%d.%d.%d", | |
46 | fw_rev_maj(mdev), fw_rev_min(mdev), fw_rev_sub(mdev)); | |
47 | strlcpy(drvinfo->bus_info, pci_name(mdev->pdev), | |
48 | sizeof(drvinfo->bus_info)); | |
49 | } | |
50 | ||
51 | static const struct { | |
52 | u32 supported; | |
53 | u32 advertised; | |
54 | u32 speed; | |
55 | } ptys2ethtool_table[MLX5E_LINK_MODES_NUMBER] = { | |
56 | [MLX5E_1000BASE_CX_SGMII] = { | |
57 | .supported = SUPPORTED_1000baseKX_Full, | |
58 | .advertised = ADVERTISED_1000baseKX_Full, | |
59 | .speed = 1000, | |
60 | }, | |
61 | [MLX5E_1000BASE_KX] = { | |
62 | .supported = SUPPORTED_1000baseKX_Full, | |
63 | .advertised = ADVERTISED_1000baseKX_Full, | |
64 | .speed = 1000, | |
65 | }, | |
66 | [MLX5E_10GBASE_CX4] = { | |
67 | .supported = SUPPORTED_10000baseKX4_Full, | |
68 | .advertised = ADVERTISED_10000baseKX4_Full, | |
69 | .speed = 10000, | |
70 | }, | |
71 | [MLX5E_10GBASE_KX4] = { | |
72 | .supported = SUPPORTED_10000baseKX4_Full, | |
73 | .advertised = ADVERTISED_10000baseKX4_Full, | |
74 | .speed = 10000, | |
75 | }, | |
76 | [MLX5E_10GBASE_KR] = { | |
77 | .supported = SUPPORTED_10000baseKR_Full, | |
78 | .advertised = ADVERTISED_10000baseKR_Full, | |
79 | .speed = 10000, | |
80 | }, | |
81 | [MLX5E_20GBASE_KR2] = { | |
82 | .supported = SUPPORTED_20000baseKR2_Full, | |
83 | .advertised = ADVERTISED_20000baseKR2_Full, | |
84 | .speed = 20000, | |
85 | }, | |
86 | [MLX5E_40GBASE_CR4] = { | |
87 | .supported = SUPPORTED_40000baseCR4_Full, | |
88 | .advertised = ADVERTISED_40000baseCR4_Full, | |
89 | .speed = 40000, | |
90 | }, | |
91 | [MLX5E_40GBASE_KR4] = { | |
92 | .supported = SUPPORTED_40000baseKR4_Full, | |
93 | .advertised = ADVERTISED_40000baseKR4_Full, | |
94 | .speed = 40000, | |
95 | }, | |
96 | [MLX5E_56GBASE_R4] = { | |
97 | .supported = SUPPORTED_56000baseKR4_Full, | |
98 | .advertised = ADVERTISED_56000baseKR4_Full, | |
99 | .speed = 56000, | |
100 | }, | |
101 | [MLX5E_10GBASE_CR] = { | |
102 | .supported = SUPPORTED_10000baseKR_Full, | |
103 | .advertised = ADVERTISED_10000baseKR_Full, | |
104 | .speed = 10000, | |
105 | }, | |
106 | [MLX5E_10GBASE_SR] = { | |
107 | .supported = SUPPORTED_10000baseKR_Full, | |
108 | .advertised = ADVERTISED_10000baseKR_Full, | |
109 | .speed = 10000, | |
110 | }, | |
111 | [MLX5E_10GBASE_ER] = { | |
112 | .supported = SUPPORTED_10000baseKR_Full, | |
113 | .advertised = ADVERTISED_10000baseKR_Full, | |
114 | .speed = 10000, | |
115 | }, | |
116 | [MLX5E_40GBASE_SR4] = { | |
117 | .supported = SUPPORTED_40000baseSR4_Full, | |
118 | .advertised = ADVERTISED_40000baseSR4_Full, | |
119 | .speed = 40000, | |
120 | }, | |
121 | [MLX5E_40GBASE_LR4] = { | |
122 | .supported = SUPPORTED_40000baseLR4_Full, | |
123 | .advertised = ADVERTISED_40000baseLR4_Full, | |
124 | .speed = 40000, | |
125 | }, | |
126 | [MLX5E_100GBASE_CR4] = { | |
127 | .speed = 100000, | |
128 | }, | |
129 | [MLX5E_100GBASE_SR4] = { | |
130 | .speed = 100000, | |
131 | }, | |
132 | [MLX5E_100GBASE_KR4] = { | |
133 | .speed = 100000, | |
134 | }, | |
135 | [MLX5E_100GBASE_LR4] = { | |
136 | .speed = 100000, | |
137 | }, | |
138 | [MLX5E_100BASE_TX] = { | |
139 | .speed = 100, | |
140 | }, | |
141 | [MLX5E_100BASE_T] = { | |
142 | .supported = SUPPORTED_100baseT_Full, | |
143 | .advertised = ADVERTISED_100baseT_Full, | |
144 | .speed = 100, | |
145 | }, | |
146 | [MLX5E_10GBASE_T] = { | |
147 | .supported = SUPPORTED_10000baseT_Full, | |
148 | .advertised = ADVERTISED_10000baseT_Full, | |
149 | .speed = 1000, | |
150 | }, | |
151 | [MLX5E_25GBASE_CR] = { | |
152 | .speed = 25000, | |
153 | }, | |
154 | [MLX5E_25GBASE_KR] = { | |
155 | .speed = 25000, | |
156 | }, | |
157 | [MLX5E_25GBASE_SR] = { | |
158 | .speed = 25000, | |
159 | }, | |
160 | [MLX5E_50GBASE_CR2] = { | |
161 | .speed = 50000, | |
162 | }, | |
163 | [MLX5E_50GBASE_KR2] = { | |
164 | .speed = 50000, | |
165 | }, | |
166 | }; | |
167 | ||
168 | static int mlx5e_get_sset_count(struct net_device *dev, int sset) | |
169 | { | |
170 | struct mlx5e_priv *priv = netdev_priv(dev); | |
171 | ||
172 | switch (sset) { | |
173 | case ETH_SS_STATS: | |
174 | return NUM_VPORT_COUNTERS + | |
175 | priv->params.num_channels * NUM_RQ_STATS + | |
176 | priv->params.num_channels * priv->num_tc * | |
177 | NUM_SQ_STATS; | |
178 | /* fallthrough */ | |
179 | default: | |
180 | return -EOPNOTSUPP; | |
181 | } | |
182 | } | |
183 | ||
184 | static void mlx5e_get_strings(struct net_device *dev, | |
185 | uint32_t stringset, uint8_t *data) | |
186 | { | |
187 | int i, j, tc, idx = 0; | |
188 | struct mlx5e_priv *priv = netdev_priv(dev); | |
189 | ||
190 | switch (stringset) { | |
191 | case ETH_SS_PRIV_FLAGS: | |
192 | break; | |
193 | ||
194 | case ETH_SS_TEST: | |
195 | break; | |
196 | ||
197 | case ETH_SS_STATS: | |
198 | /* VPORT counters */ | |
199 | for (i = 0; i < NUM_VPORT_COUNTERS; i++) | |
200 | strcpy(data + (idx++) * ETH_GSTRING_LEN, | |
201 | vport_strings[i]); | |
202 | ||
203 | /* per channel counters */ | |
204 | for (i = 0; i < priv->params.num_channels; i++) | |
205 | for (j = 0; j < NUM_RQ_STATS; j++) | |
206 | sprintf(data + (idx++) * ETH_GSTRING_LEN, | |
207 | "rx%d_%s", i, rq_stats_strings[j]); | |
208 | ||
209 | for (i = 0; i < priv->params.num_channels; i++) | |
210 | for (tc = 0; tc < priv->num_tc; tc++) | |
211 | for (j = 0; j < NUM_SQ_STATS; j++) | |
212 | sprintf(data + | |
213 | (idx++) * ETH_GSTRING_LEN, | |
214 | "tx%d_%d_%s", i, tc, | |
215 | sq_stats_strings[j]); | |
216 | break; | |
217 | } | |
218 | } | |
219 | ||
220 | static void mlx5e_get_ethtool_stats(struct net_device *dev, | |
221 | struct ethtool_stats *stats, u64 *data) | |
222 | { | |
223 | struct mlx5e_priv *priv = netdev_priv(dev); | |
224 | int i, j, tc, idx = 0; | |
225 | ||
226 | if (!data) | |
227 | return; | |
228 | ||
229 | mutex_lock(&priv->state_lock); | |
230 | if (test_bit(MLX5E_STATE_OPENED, &priv->state)) | |
231 | mlx5e_update_stats(priv); | |
232 | mutex_unlock(&priv->state_lock); | |
233 | ||
234 | for (i = 0; i < NUM_VPORT_COUNTERS; i++) | |
235 | data[idx++] = ((u64 *)&priv->stats.vport)[i]; | |
236 | ||
237 | /* per channel counters */ | |
238 | for (i = 0; i < priv->params.num_channels; i++) | |
239 | for (j = 0; j < NUM_RQ_STATS; j++) | |
240 | data[idx++] = !test_bit(MLX5E_STATE_OPENED, | |
241 | &priv->state) ? 0 : | |
242 | ((u64 *)&priv->channel[i]->rq.stats)[j]; | |
243 | ||
244 | for (i = 0; i < priv->params.num_channels; i++) | |
245 | for (tc = 0; tc < priv->num_tc; tc++) | |
246 | for (j = 0; j < NUM_SQ_STATS; j++) | |
247 | data[idx++] = !test_bit(MLX5E_STATE_OPENED, | |
248 | &priv->state) ? 0 : | |
249 | ((u64 *)&priv->channel[i]->sq[tc].stats)[j]; | |
250 | } | |
251 | ||
252 | static void mlx5e_get_ringparam(struct net_device *dev, | |
253 | struct ethtool_ringparam *param) | |
254 | { | |
255 | struct mlx5e_priv *priv = netdev_priv(dev); | |
256 | ||
257 | param->rx_max_pending = 1 << MLX5E_PARAMS_MAXIMUM_LOG_RQ_SIZE; | |
258 | param->tx_max_pending = 1 << MLX5E_PARAMS_MAXIMUM_LOG_SQ_SIZE; | |
259 | param->rx_pending = 1 << priv->params.log_rq_size; | |
260 | param->tx_pending = 1 << priv->params.log_sq_size; | |
261 | } | |
262 | ||
263 | static int mlx5e_set_ringparam(struct net_device *dev, | |
264 | struct ethtool_ringparam *param) | |
265 | { | |
266 | struct mlx5e_priv *priv = netdev_priv(dev); | |
267 | struct mlx5e_params new_params; | |
268 | u16 min_rx_wqes; | |
269 | u8 log_rq_size; | |
270 | u8 log_sq_size; | |
271 | int err = 0; | |
272 | ||
273 | if (param->rx_jumbo_pending) { | |
274 | netdev_info(dev, "%s: rx_jumbo_pending not supported\n", | |
275 | __func__); | |
276 | return -EINVAL; | |
277 | } | |
278 | if (param->rx_mini_pending) { | |
279 | netdev_info(dev, "%s: rx_mini_pending not supported\n", | |
280 | __func__); | |
281 | return -EINVAL; | |
282 | } | |
283 | if (param->rx_pending < (1 << MLX5E_PARAMS_MINIMUM_LOG_RQ_SIZE)) { | |
284 | netdev_info(dev, "%s: rx_pending (%d) < min (%d)\n", | |
285 | __func__, param->rx_pending, | |
286 | 1 << MLX5E_PARAMS_MINIMUM_LOG_RQ_SIZE); | |
287 | return -EINVAL; | |
288 | } | |
289 | if (param->rx_pending > (1 << MLX5E_PARAMS_MAXIMUM_LOG_RQ_SIZE)) { | |
290 | netdev_info(dev, "%s: rx_pending (%d) > max (%d)\n", | |
291 | __func__, param->rx_pending, | |
292 | 1 << MLX5E_PARAMS_MAXIMUM_LOG_RQ_SIZE); | |
293 | return -EINVAL; | |
294 | } | |
295 | if (param->tx_pending < (1 << MLX5E_PARAMS_MINIMUM_LOG_SQ_SIZE)) { | |
296 | netdev_info(dev, "%s: tx_pending (%d) < min (%d)\n", | |
297 | __func__, param->tx_pending, | |
298 | 1 << MLX5E_PARAMS_MINIMUM_LOG_SQ_SIZE); | |
299 | return -EINVAL; | |
300 | } | |
301 | if (param->tx_pending > (1 << MLX5E_PARAMS_MAXIMUM_LOG_SQ_SIZE)) { | |
302 | netdev_info(dev, "%s: tx_pending (%d) > max (%d)\n", | |
303 | __func__, param->tx_pending, | |
304 | 1 << MLX5E_PARAMS_MAXIMUM_LOG_SQ_SIZE); | |
305 | return -EINVAL; | |
306 | } | |
307 | ||
308 | log_rq_size = order_base_2(param->rx_pending); | |
309 | log_sq_size = order_base_2(param->tx_pending); | |
310 | min_rx_wqes = min_t(u16, param->rx_pending - 1, | |
311 | MLX5E_PARAMS_DEFAULT_MIN_RX_WQES); | |
312 | ||
313 | if (log_rq_size == priv->params.log_rq_size && | |
314 | log_sq_size == priv->params.log_sq_size && | |
315 | min_rx_wqes == priv->params.min_rx_wqes) | |
316 | return 0; | |
317 | ||
318 | mutex_lock(&priv->state_lock); | |
319 | new_params = priv->params; | |
320 | new_params.log_rq_size = log_rq_size; | |
321 | new_params.log_sq_size = log_sq_size; | |
322 | new_params.min_rx_wqes = min_rx_wqes; | |
323 | err = mlx5e_update_priv_params(priv, &new_params); | |
324 | mutex_unlock(&priv->state_lock); | |
325 | ||
326 | return err; | |
327 | } | |
328 | ||
329 | static void mlx5e_get_channels(struct net_device *dev, | |
330 | struct ethtool_channels *ch) | |
331 | { | |
332 | struct mlx5e_priv *priv = netdev_priv(dev); | |
333 | int ncv = priv->mdev->priv.eq_table.num_comp_vectors; | |
334 | ||
335 | ch->max_combined = ncv; | |
336 | ch->combined_count = priv->params.num_channels; | |
337 | } | |
338 | ||
339 | static int mlx5e_set_channels(struct net_device *dev, | |
340 | struct ethtool_channels *ch) | |
341 | { | |
342 | struct mlx5e_priv *priv = netdev_priv(dev); | |
343 | int ncv = priv->mdev->priv.eq_table.num_comp_vectors; | |
344 | unsigned int count = ch->combined_count; | |
345 | struct mlx5e_params new_params; | |
346 | int err = 0; | |
347 | ||
348 | if (!count) { | |
349 | netdev_info(dev, "%s: combined_count=0 not supported\n", | |
350 | __func__); | |
351 | return -EINVAL; | |
352 | } | |
353 | if (ch->rx_count || ch->tx_count) { | |
354 | netdev_info(dev, "%s: separate rx/tx count not supported\n", | |
355 | __func__); | |
356 | return -EINVAL; | |
357 | } | |
358 | if (count > ncv) { | |
359 | netdev_info(dev, "%s: count (%d) > max (%d)\n", | |
360 | __func__, count, ncv); | |
361 | return -EINVAL; | |
362 | } | |
363 | ||
364 | if (priv->params.num_channels == count) | |
365 | return 0; | |
366 | ||
367 | mutex_lock(&priv->state_lock); | |
368 | new_params = priv->params; | |
369 | new_params.num_channels = count; | |
370 | err = mlx5e_update_priv_params(priv, &new_params); | |
371 | mutex_unlock(&priv->state_lock); | |
372 | ||
373 | return err; | |
374 | } | |
375 | ||
376 | static int mlx5e_get_coalesce(struct net_device *netdev, | |
377 | struct ethtool_coalesce *coal) | |
378 | { | |
379 | struct mlx5e_priv *priv = netdev_priv(netdev); | |
380 | ||
381 | coal->rx_coalesce_usecs = priv->params.rx_cq_moderation_usec; | |
382 | coal->rx_max_coalesced_frames = priv->params.rx_cq_moderation_pkts; | |
383 | coal->tx_coalesce_usecs = priv->params.tx_cq_moderation_usec; | |
384 | coal->tx_max_coalesced_frames = priv->params.tx_cq_moderation_pkts; | |
385 | ||
386 | return 0; | |
387 | } | |
388 | ||
389 | static int mlx5e_set_coalesce(struct net_device *netdev, | |
390 | struct ethtool_coalesce *coal) | |
391 | { | |
392 | struct mlx5e_priv *priv = netdev_priv(netdev); | |
393 | struct mlx5_core_dev *mdev = priv->mdev; | |
394 | struct mlx5e_channel *c; | |
395 | int tc; | |
396 | int i; | |
397 | ||
398 | priv->params.tx_cq_moderation_usec = coal->tx_coalesce_usecs; | |
399 | priv->params.tx_cq_moderation_pkts = coal->tx_max_coalesced_frames; | |
400 | priv->params.rx_cq_moderation_usec = coal->rx_coalesce_usecs; | |
401 | priv->params.rx_cq_moderation_pkts = coal->rx_max_coalesced_frames; | |
402 | ||
403 | for (i = 0; i < priv->params.num_channels; ++i) { | |
404 | c = priv->channel[i]; | |
405 | ||
406 | for (tc = 0; tc < c->num_tc; tc++) { | |
407 | mlx5_core_modify_cq_moderation(mdev, | |
408 | &c->sq[tc].cq.mcq, | |
409 | coal->tx_coalesce_usecs, | |
410 | coal->tx_max_coalesced_frames); | |
411 | } | |
412 | ||
413 | mlx5_core_modify_cq_moderation(mdev, &c->rq.cq.mcq, | |
414 | coal->rx_coalesce_usecs, | |
415 | coal->rx_max_coalesced_frames); | |
416 | } | |
417 | ||
418 | return 0; | |
419 | } | |
420 | ||
421 | static u32 ptys2ethtool_supported_link(u32 eth_proto_cap) | |
422 | { | |
423 | int i; | |
424 | u32 supported_modes = 0; | |
425 | ||
426 | for (i = 0; i < MLX5E_LINK_MODES_NUMBER; ++i) { | |
427 | if (eth_proto_cap & MLX5E_PROT_MASK(i)) | |
428 | supported_modes |= ptys2ethtool_table[i].supported; | |
429 | } | |
430 | return supported_modes; | |
431 | } | |
432 | ||
433 | static u32 ptys2ethtool_adver_link(u32 eth_proto_cap) | |
434 | { | |
435 | int i; | |
436 | u32 advertising_modes = 0; | |
437 | ||
438 | for (i = 0; i < MLX5E_LINK_MODES_NUMBER; ++i) { | |
439 | if (eth_proto_cap & MLX5E_PROT_MASK(i)) | |
440 | advertising_modes |= ptys2ethtool_table[i].advertised; | |
441 | } | |
442 | return advertising_modes; | |
443 | } | |
444 | ||
445 | static u32 ptys2ethtool_supported_port(u32 eth_proto_cap) | |
446 | { | |
447 | if (eth_proto_cap & (MLX5E_PROT_MASK(MLX5E_10GBASE_CR) | |
448 | | MLX5E_PROT_MASK(MLX5E_10GBASE_SR) | |
449 | | MLX5E_PROT_MASK(MLX5E_40GBASE_CR4) | |
450 | | MLX5E_PROT_MASK(MLX5E_40GBASE_SR4) | |
451 | | MLX5E_PROT_MASK(MLX5E_100GBASE_SR4) | |
452 | | MLX5E_PROT_MASK(MLX5E_1000BASE_CX_SGMII))) { | |
453 | return SUPPORTED_FIBRE; | |
454 | } | |
455 | ||
456 | if (eth_proto_cap & (MLX5E_PROT_MASK(MLX5E_100GBASE_KR4) | |
457 | | MLX5E_PROT_MASK(MLX5E_40GBASE_KR4) | |
458 | | MLX5E_PROT_MASK(MLX5E_10GBASE_KR) | |
459 | | MLX5E_PROT_MASK(MLX5E_10GBASE_KX4) | |
460 | | MLX5E_PROT_MASK(MLX5E_1000BASE_KX))) { | |
461 | return SUPPORTED_Backplane; | |
462 | } | |
463 | return 0; | |
464 | } | |
465 | ||
466 | static void get_speed_duplex(struct net_device *netdev, | |
467 | u32 eth_proto_oper, | |
468 | struct ethtool_cmd *cmd) | |
469 | { | |
470 | int i; | |
471 | u32 speed = SPEED_UNKNOWN; | |
472 | u8 duplex = DUPLEX_UNKNOWN; | |
473 | ||
474 | if (!netif_carrier_ok(netdev)) | |
475 | goto out; | |
476 | ||
477 | for (i = 0; i < MLX5E_LINK_MODES_NUMBER; ++i) { | |
478 | if (eth_proto_oper & MLX5E_PROT_MASK(i)) { | |
479 | speed = ptys2ethtool_table[i].speed; | |
480 | duplex = DUPLEX_FULL; | |
481 | break; | |
482 | } | |
483 | } | |
484 | out: | |
485 | ethtool_cmd_speed_set(cmd, speed); | |
486 | cmd->duplex = duplex; | |
487 | } | |
488 | ||
489 | static void get_supported(u32 eth_proto_cap, u32 *supported) | |
490 | { | |
491 | *supported |= ptys2ethtool_supported_port(eth_proto_cap); | |
492 | *supported |= ptys2ethtool_supported_link(eth_proto_cap); | |
493 | *supported |= SUPPORTED_Pause | SUPPORTED_Asym_Pause; | |
494 | } | |
495 | ||
496 | static void get_advertising(u32 eth_proto_cap, u8 tx_pause, | |
497 | u8 rx_pause, u32 *advertising) | |
498 | { | |
499 | *advertising |= ptys2ethtool_adver_link(eth_proto_cap); | |
500 | *advertising |= tx_pause ? ADVERTISED_Pause : 0; | |
501 | *advertising |= (tx_pause ^ rx_pause) ? ADVERTISED_Asym_Pause : 0; | |
502 | } | |
503 | ||
504 | static u8 get_connector_port(u32 eth_proto) | |
505 | { | |
506 | if (eth_proto & (MLX5E_PROT_MASK(MLX5E_10GBASE_SR) | |
507 | | MLX5E_PROT_MASK(MLX5E_40GBASE_SR4) | |
508 | | MLX5E_PROT_MASK(MLX5E_100GBASE_SR4) | |
509 | | MLX5E_PROT_MASK(MLX5E_1000BASE_CX_SGMII))) { | |
510 | return PORT_FIBRE; | |
511 | } | |
512 | ||
513 | if (eth_proto & (MLX5E_PROT_MASK(MLX5E_40GBASE_CR4) | |
514 | | MLX5E_PROT_MASK(MLX5E_10GBASE_CR) | |
515 | | MLX5E_PROT_MASK(MLX5E_100GBASE_CR4))) { | |
516 | return PORT_DA; | |
517 | } | |
518 | ||
519 | if (eth_proto & (MLX5E_PROT_MASK(MLX5E_10GBASE_KX4) | |
520 | | MLX5E_PROT_MASK(MLX5E_10GBASE_KR) | |
521 | | MLX5E_PROT_MASK(MLX5E_40GBASE_KR4) | |
522 | | MLX5E_PROT_MASK(MLX5E_100GBASE_KR4))) { | |
523 | return PORT_NONE; | |
524 | } | |
525 | ||
526 | return PORT_OTHER; | |
527 | } | |
528 | ||
529 | static void get_lp_advertising(u32 eth_proto_lp, u32 *lp_advertising) | |
530 | { | |
531 | *lp_advertising = ptys2ethtool_adver_link(eth_proto_lp); | |
532 | } | |
533 | ||
534 | static int mlx5e_get_settings(struct net_device *netdev, | |
535 | struct ethtool_cmd *cmd) | |
536 | { | |
537 | struct mlx5e_priv *priv = netdev_priv(netdev); | |
538 | struct mlx5_core_dev *mdev = priv->mdev; | |
539 | u32 out[MLX5_ST_SZ_DW(ptys_reg)]; | |
540 | u32 eth_proto_cap; | |
541 | u32 eth_proto_admin; | |
542 | u32 eth_proto_lp; | |
543 | u32 eth_proto_oper; | |
544 | int err; | |
545 | ||
a05bdefa | 546 | err = mlx5_query_port_ptys(mdev, out, sizeof(out), MLX5_PTYS_EN, 1); |
f62b8bb8 AV |
547 | |
548 | if (err) { | |
549 | netdev_err(netdev, "%s: query port ptys failed: %d\n", | |
550 | __func__, err); | |
551 | goto err_query_ptys; | |
552 | } | |
553 | ||
554 | eth_proto_cap = MLX5_GET(ptys_reg, out, eth_proto_capability); | |
555 | eth_proto_admin = MLX5_GET(ptys_reg, out, eth_proto_admin); | |
556 | eth_proto_oper = MLX5_GET(ptys_reg, out, eth_proto_oper); | |
557 | eth_proto_lp = MLX5_GET(ptys_reg, out, eth_proto_lp_advertise); | |
558 | ||
559 | cmd->supported = 0; | |
560 | cmd->advertising = 0; | |
561 | ||
562 | get_supported(eth_proto_cap, &cmd->supported); | |
563 | get_advertising(eth_proto_admin, 0, 0, &cmd->advertising); | |
564 | get_speed_duplex(netdev, eth_proto_oper, cmd); | |
565 | ||
566 | eth_proto_oper = eth_proto_oper ? eth_proto_oper : eth_proto_cap; | |
567 | ||
568 | cmd->port = get_connector_port(eth_proto_oper); | |
569 | get_lp_advertising(eth_proto_lp, &cmd->lp_advertising); | |
570 | ||
571 | cmd->transceiver = XCVR_INTERNAL; | |
572 | ||
573 | err_query_ptys: | |
574 | return err; | |
575 | } | |
576 | ||
577 | static u32 mlx5e_ethtool2ptys_adver_link(u32 link_modes) | |
578 | { | |
579 | u32 i, ptys_modes = 0; | |
580 | ||
581 | for (i = 0; i < MLX5E_LINK_MODES_NUMBER; ++i) { | |
582 | if (ptys2ethtool_table[i].advertised & link_modes) | |
583 | ptys_modes |= MLX5E_PROT_MASK(i); | |
584 | } | |
585 | ||
586 | return ptys_modes; | |
587 | } | |
588 | ||
589 | static u32 mlx5e_ethtool2ptys_speed_link(u32 speed) | |
590 | { | |
591 | u32 i, speed_links = 0; | |
592 | ||
593 | for (i = 0; i < MLX5E_LINK_MODES_NUMBER; ++i) { | |
594 | if (ptys2ethtool_table[i].speed == speed) | |
595 | speed_links |= MLX5E_PROT_MASK(i); | |
596 | } | |
597 | ||
598 | return speed_links; | |
599 | } | |
600 | ||
601 | static int mlx5e_set_settings(struct net_device *netdev, | |
602 | struct ethtool_cmd *cmd) | |
603 | { | |
604 | struct mlx5e_priv *priv = netdev_priv(netdev); | |
605 | struct mlx5_core_dev *mdev = priv->mdev; | |
606 | u32 link_modes; | |
607 | u32 speed; | |
608 | u32 eth_proto_cap, eth_proto_admin; | |
609 | u8 port_status; | |
610 | int err; | |
611 | ||
612 | speed = ethtool_cmd_speed(cmd); | |
613 | ||
614 | link_modes = cmd->autoneg == AUTONEG_ENABLE ? | |
615 | mlx5e_ethtool2ptys_adver_link(cmd->advertising) : | |
616 | mlx5e_ethtool2ptys_speed_link(speed); | |
617 | ||
618 | err = mlx5_query_port_proto_cap(mdev, ð_proto_cap, MLX5_PTYS_EN); | |
619 | if (err) { | |
620 | netdev_err(netdev, "%s: query port eth proto cap failed: %d\n", | |
621 | __func__, err); | |
622 | goto out; | |
623 | } | |
624 | ||
625 | link_modes = link_modes & eth_proto_cap; | |
626 | if (!link_modes) { | |
627 | netdev_err(netdev, "%s: Not supported link mode(s) requested", | |
628 | __func__); | |
629 | err = -EINVAL; | |
630 | goto out; | |
631 | } | |
632 | ||
633 | err = mlx5_query_port_proto_admin(mdev, ð_proto_admin, MLX5_PTYS_EN); | |
634 | if (err) { | |
635 | netdev_err(netdev, "%s: query port eth proto admin failed: %d\n", | |
636 | __func__, err); | |
637 | goto out; | |
638 | } | |
639 | ||
640 | if (link_modes == eth_proto_admin) | |
641 | goto out; | |
642 | ||
643 | err = mlx5_set_port_proto(mdev, link_modes, MLX5_PTYS_EN); | |
644 | if (err) { | |
645 | netdev_err(netdev, "%s: set port eth proto admin failed: %d\n", | |
646 | __func__, err); | |
647 | goto out; | |
648 | } | |
649 | ||
650 | err = mlx5_query_port_status(mdev, &port_status); | |
651 | if (err) | |
652 | goto out; | |
653 | ||
654 | if (port_status == MLX5_PORT_DOWN) | |
655 | return 0; | |
656 | ||
657 | err = mlx5_set_port_status(mdev, MLX5_PORT_DOWN); | |
658 | if (err) | |
659 | goto out; | |
660 | err = mlx5_set_port_status(mdev, MLX5_PORT_UP); | |
661 | out: | |
662 | return err; | |
663 | } | |
664 | ||
2be6967c SM |
665 | static int mlx5e_get_rxfh(struct net_device *netdev, u32 *indir, u8 *key, |
666 | u8 *hfunc) | |
667 | { | |
668 | struct mlx5e_priv *priv = netdev_priv(netdev); | |
669 | ||
670 | if (hfunc) | |
671 | *hfunc = priv->params.rss_hfunc; | |
672 | ||
673 | return 0; | |
674 | } | |
675 | ||
676 | static int mlx5e_set_rxfh(struct net_device *netdev, const u32 *indir, | |
677 | const u8 *key, const u8 hfunc) | |
678 | { | |
679 | struct mlx5e_priv *priv = netdev_priv(netdev); | |
680 | int err = 0; | |
681 | ||
682 | if (hfunc == ETH_RSS_HASH_NO_CHANGE) | |
683 | return 0; | |
684 | ||
685 | if ((hfunc != ETH_RSS_HASH_XOR) && | |
686 | (hfunc != ETH_RSS_HASH_TOP)) | |
687 | return -EINVAL; | |
688 | ||
689 | mutex_lock(&priv->state_lock); | |
690 | ||
691 | priv->params.rss_hfunc = hfunc; | |
692 | if (test_bit(MLX5E_STATE_OPENED, &priv->state)) { | |
693 | mlx5e_close_locked(priv->netdev); | |
694 | err = mlx5e_open_locked(priv->netdev); | |
695 | } | |
696 | ||
697 | mutex_unlock(&priv->state_lock); | |
698 | ||
699 | return err; | |
700 | } | |
701 | ||
f62b8bb8 AV |
702 | const struct ethtool_ops mlx5e_ethtool_ops = { |
703 | .get_drvinfo = mlx5e_get_drvinfo, | |
704 | .get_link = ethtool_op_get_link, | |
705 | .get_strings = mlx5e_get_strings, | |
706 | .get_sset_count = mlx5e_get_sset_count, | |
707 | .get_ethtool_stats = mlx5e_get_ethtool_stats, | |
708 | .get_ringparam = mlx5e_get_ringparam, | |
709 | .set_ringparam = mlx5e_set_ringparam, | |
710 | .get_channels = mlx5e_get_channels, | |
711 | .set_channels = mlx5e_set_channels, | |
712 | .get_coalesce = mlx5e_get_coalesce, | |
713 | .set_coalesce = mlx5e_set_coalesce, | |
714 | .get_settings = mlx5e_get_settings, | |
715 | .set_settings = mlx5e_set_settings, | |
2be6967c SM |
716 | .get_rxfh = mlx5e_get_rxfh, |
717 | .set_rxfh = mlx5e_set_rxfh, | |
f62b8bb8 | 718 | }; |