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 | }, | |
6e4c2189 RS |
141 | [MLX5E_1000BASE_T] = { |
142 | .supported = SUPPORTED_1000baseT_Full, | |
143 | .advertised = ADVERTISED_1000baseT_Full, | |
144 | .speed = 1000, | |
f62b8bb8 AV |
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 | ||
cf678570 GP |
168 | static unsigned long mlx5e_query_pfc_combined(struct mlx5e_priv *priv) |
169 | { | |
170 | struct mlx5_core_dev *mdev = priv->mdev; | |
171 | u8 pfc_en_tx; | |
172 | u8 pfc_en_rx; | |
173 | int err; | |
174 | ||
175 | err = mlx5_query_port_pfc(mdev, &pfc_en_tx, &pfc_en_rx); | |
176 | ||
177 | return err ? 0 : pfc_en_tx | pfc_en_rx; | |
178 | } | |
179 | ||
593cf338 | 180 | #define MLX5E_NUM_Q_CNTRS(priv) (NUM_Q_COUNTERS * (!!priv->q_counter)) |
9218b44d GP |
181 | #define MLX5E_NUM_RQ_STATS(priv) \ |
182 | (NUM_RQ_STATS * priv->params.num_channels * \ | |
183 | test_bit(MLX5E_STATE_OPENED, &priv->state)) | |
184 | #define MLX5E_NUM_SQ_STATS(priv) \ | |
185 | (NUM_SQ_STATS * priv->params.num_channels * priv->params.num_tc * \ | |
186 | test_bit(MLX5E_STATE_OPENED, &priv->state)) | |
ed80ec4c GP |
187 | #define MLX5E_NUM_PFC_COUNTERS(priv) \ |
188 | (hweight8(mlx5e_query_pfc_combined(priv)) * \ | |
189 | NUM_PPORT_PER_PRIO_PFC_COUNTERS) | |
593cf338 | 190 | |
f62b8bb8 AV |
191 | static int mlx5e_get_sset_count(struct net_device *dev, int sset) |
192 | { | |
193 | struct mlx5e_priv *priv = netdev_priv(dev); | |
194 | ||
195 | switch (sset) { | |
196 | case ETH_SS_STATS: | |
9218b44d | 197 | return NUM_SW_COUNTERS + |
593cf338 | 198 | MLX5E_NUM_Q_CNTRS(priv) + |
9218b44d GP |
199 | NUM_VPORT_COUNTERS + NUM_PPORT_COUNTERS + |
200 | MLX5E_NUM_RQ_STATS(priv) + | |
cf678570 GP |
201 | MLX5E_NUM_SQ_STATS(priv) + |
202 | MLX5E_NUM_PFC_COUNTERS(priv); | |
f62b8bb8 AV |
203 | /* fallthrough */ |
204 | default: | |
205 | return -EOPNOTSUPP; | |
206 | } | |
207 | } | |
208 | ||
9218b44d GP |
209 | static void mlx5e_fill_stats_strings(struct mlx5e_priv *priv, uint8_t *data) |
210 | { | |
cf678570 GP |
211 | int i, j, tc, prio, idx = 0; |
212 | unsigned long pfc_combined; | |
9218b44d GP |
213 | |
214 | /* SW counters */ | |
215 | for (i = 0; i < NUM_SW_COUNTERS; i++) | |
bfe6d8d1 | 216 | strcpy(data + (idx++) * ETH_GSTRING_LEN, sw_stats_desc[i].format); |
9218b44d GP |
217 | |
218 | /* Q counters */ | |
219 | for (i = 0; i < MLX5E_NUM_Q_CNTRS(priv); i++) | |
bfe6d8d1 | 220 | strcpy(data + (idx++) * ETH_GSTRING_LEN, q_stats_desc[i].format); |
9218b44d GP |
221 | |
222 | /* VPORT counters */ | |
223 | for (i = 0; i < NUM_VPORT_COUNTERS; i++) | |
224 | strcpy(data + (idx++) * ETH_GSTRING_LEN, | |
bfe6d8d1 | 225 | vport_stats_desc[i].format); |
9218b44d GP |
226 | |
227 | /* PPORT counters */ | |
228 | for (i = 0; i < NUM_PPORT_802_3_COUNTERS; i++) | |
229 | strcpy(data + (idx++) * ETH_GSTRING_LEN, | |
bfe6d8d1 | 230 | pport_802_3_stats_desc[i].format); |
9218b44d GP |
231 | |
232 | for (i = 0; i < NUM_PPORT_2863_COUNTERS; i++) | |
233 | strcpy(data + (idx++) * ETH_GSTRING_LEN, | |
bfe6d8d1 | 234 | pport_2863_stats_desc[i].format); |
9218b44d GP |
235 | |
236 | for (i = 0; i < NUM_PPORT_2819_COUNTERS; i++) | |
237 | strcpy(data + (idx++) * ETH_GSTRING_LEN, | |
bfe6d8d1 | 238 | pport_2819_stats_desc[i].format); |
9218b44d | 239 | |
cf678570 GP |
240 | for (prio = 0; prio < NUM_PPORT_PRIO; prio++) { |
241 | for (i = 0; i < NUM_PPORT_PER_PRIO_TRAFFIC_COUNTERS; i++) | |
bfe6d8d1 GP |
242 | sprintf(data + (idx++) * ETH_GSTRING_LEN, |
243 | pport_per_prio_traffic_stats_desc[i].format, prio); | |
cf678570 GP |
244 | } |
245 | ||
246 | pfc_combined = mlx5e_query_pfc_combined(priv); | |
247 | for_each_set_bit(prio, &pfc_combined, NUM_PPORT_PRIO) { | |
248 | for (i = 0; i < NUM_PPORT_PER_PRIO_PFC_COUNTERS; i++) { | |
bfe6d8d1 GP |
249 | sprintf(data + (idx++) * ETH_GSTRING_LEN, |
250 | pport_per_prio_pfc_stats_desc[i].format, prio); | |
cf678570 GP |
251 | } |
252 | } | |
253 | ||
9218b44d GP |
254 | if (!test_bit(MLX5E_STATE_OPENED, &priv->state)) |
255 | return; | |
256 | ||
257 | /* per channel counters */ | |
258 | for (i = 0; i < priv->params.num_channels; i++) | |
259 | for (j = 0; j < NUM_RQ_STATS; j++) | |
bfe6d8d1 GP |
260 | sprintf(data + (idx++) * ETH_GSTRING_LEN, |
261 | rq_stats_desc[j].format, i); | |
9218b44d GP |
262 | |
263 | for (tc = 0; tc < priv->params.num_tc; tc++) | |
264 | for (i = 0; i < priv->params.num_channels; i++) | |
265 | for (j = 0; j < NUM_SQ_STATS; j++) | |
266 | sprintf(data + (idx++) * ETH_GSTRING_LEN, | |
bfe6d8d1 GP |
267 | sq_stats_desc[j].format, |
268 | priv->channeltc_to_txq_map[i][tc]); | |
9218b44d GP |
269 | } |
270 | ||
f62b8bb8 AV |
271 | static void mlx5e_get_strings(struct net_device *dev, |
272 | uint32_t stringset, uint8_t *data) | |
273 | { | |
f62b8bb8 AV |
274 | struct mlx5e_priv *priv = netdev_priv(dev); |
275 | ||
276 | switch (stringset) { | |
277 | case ETH_SS_PRIV_FLAGS: | |
278 | break; | |
279 | ||
280 | case ETH_SS_TEST: | |
281 | break; | |
282 | ||
283 | case ETH_SS_STATS: | |
9218b44d | 284 | mlx5e_fill_stats_strings(priv, data); |
f62b8bb8 AV |
285 | break; |
286 | } | |
287 | } | |
288 | ||
289 | static void mlx5e_get_ethtool_stats(struct net_device *dev, | |
290 | struct ethtool_stats *stats, u64 *data) | |
291 | { | |
292 | struct mlx5e_priv *priv = netdev_priv(dev); | |
cf678570 GP |
293 | int i, j, tc, prio, idx = 0; |
294 | unsigned long pfc_combined; | |
f62b8bb8 AV |
295 | |
296 | if (!data) | |
297 | return; | |
298 | ||
299 | mutex_lock(&priv->state_lock); | |
300 | if (test_bit(MLX5E_STATE_OPENED, &priv->state)) | |
301 | mlx5e_update_stats(priv); | |
302 | mutex_unlock(&priv->state_lock); | |
303 | ||
9218b44d GP |
304 | for (i = 0; i < NUM_SW_COUNTERS; i++) |
305 | data[idx++] = MLX5E_READ_CTR64_CPU(&priv->stats.sw, | |
306 | sw_stats_desc, i); | |
f62b8bb8 | 307 | |
593cf338 | 308 | for (i = 0; i < MLX5E_NUM_Q_CNTRS(priv); i++) |
9218b44d GP |
309 | data[idx++] = MLX5E_READ_CTR32_CPU(&priv->stats.qcnt, |
310 | q_stats_desc, i); | |
311 | ||
312 | for (i = 0; i < NUM_VPORT_COUNTERS; i++) | |
313 | data[idx++] = MLX5E_READ_CTR64_BE(priv->stats.vport.query_vport_out, | |
314 | vport_stats_desc, i); | |
593cf338 | 315 | |
9218b44d GP |
316 | for (i = 0; i < NUM_PPORT_802_3_COUNTERS; i++) |
317 | data[idx++] = MLX5E_READ_CTR64_BE(&priv->stats.pport.IEEE_802_3_counters, | |
318 | pport_802_3_stats_desc, i); | |
319 | ||
320 | for (i = 0; i < NUM_PPORT_2863_COUNTERS; i++) | |
321 | data[idx++] = MLX5E_READ_CTR64_BE(&priv->stats.pport.RFC_2863_counters, | |
322 | pport_2863_stats_desc, i); | |
323 | ||
324 | for (i = 0; i < NUM_PPORT_2819_COUNTERS; i++) | |
325 | data[idx++] = MLX5E_READ_CTR64_BE(&priv->stats.pport.RFC_2819_counters, | |
326 | pport_2819_stats_desc, i); | |
327 | ||
cf678570 GP |
328 | for (prio = 0; prio < NUM_PPORT_PRIO; prio++) { |
329 | for (i = 0; i < NUM_PPORT_PER_PRIO_TRAFFIC_COUNTERS; i++) | |
330 | data[idx++] = MLX5E_READ_CTR64_BE(&priv->stats.pport.per_prio_counters[prio], | |
331 | pport_per_prio_traffic_stats_desc, i); | |
332 | } | |
333 | ||
334 | pfc_combined = mlx5e_query_pfc_combined(priv); | |
335 | for_each_set_bit(prio, &pfc_combined, NUM_PPORT_PRIO) { | |
336 | for (i = 0; i < NUM_PPORT_PER_PRIO_PFC_COUNTERS; i++) { | |
337 | data[idx++] = MLX5E_READ_CTR64_BE(&priv->stats.pport.per_prio_counters[prio], | |
338 | pport_per_prio_pfc_stats_desc, i); | |
339 | } | |
340 | } | |
341 | ||
9218b44d GP |
342 | if (!test_bit(MLX5E_STATE_OPENED, &priv->state)) |
343 | return; | |
efea389d | 344 | |
f62b8bb8 AV |
345 | /* per channel counters */ |
346 | for (i = 0; i < priv->params.num_channels; i++) | |
347 | for (j = 0; j < NUM_RQ_STATS; j++) | |
9218b44d GP |
348 | data[idx++] = |
349 | MLX5E_READ_CTR64_CPU(&priv->channel[i]->rq.stats, | |
350 | rq_stats_desc, j); | |
f62b8bb8 | 351 | |
3b619524 TT |
352 | for (tc = 0; tc < priv->params.num_tc; tc++) |
353 | for (i = 0; i < priv->params.num_channels; i++) | |
f62b8bb8 | 354 | for (j = 0; j < NUM_SQ_STATS; j++) |
9218b44d GP |
355 | data[idx++] = MLX5E_READ_CTR64_CPU(&priv->channel[i]->sq[tc].stats, |
356 | sq_stats_desc, j); | |
f62b8bb8 AV |
357 | } |
358 | ||
359 | static void mlx5e_get_ringparam(struct net_device *dev, | |
360 | struct ethtool_ringparam *param) | |
361 | { | |
362 | struct mlx5e_priv *priv = netdev_priv(dev); | |
461017cb | 363 | int rq_wq_type = priv->params.rq_wq_type; |
f62b8bb8 | 364 | |
461017cb | 365 | param->rx_max_pending = 1 << mlx5_max_log_rq_size(rq_wq_type); |
f62b8bb8 AV |
366 | param->tx_max_pending = 1 << MLX5E_PARAMS_MAXIMUM_LOG_SQ_SIZE; |
367 | param->rx_pending = 1 << priv->params.log_rq_size; | |
368 | param->tx_pending = 1 << priv->params.log_sq_size; | |
369 | } | |
370 | ||
371 | static int mlx5e_set_ringparam(struct net_device *dev, | |
372 | struct ethtool_ringparam *param) | |
373 | { | |
374 | struct mlx5e_priv *priv = netdev_priv(dev); | |
98e81b0a | 375 | bool was_opened; |
461017cb | 376 | int rq_wq_type = priv->params.rq_wq_type; |
f62b8bb8 AV |
377 | u16 min_rx_wqes; |
378 | u8 log_rq_size; | |
379 | u8 log_sq_size; | |
380 | int err = 0; | |
381 | ||
382 | if (param->rx_jumbo_pending) { | |
383 | netdev_info(dev, "%s: rx_jumbo_pending not supported\n", | |
384 | __func__); | |
385 | return -EINVAL; | |
386 | } | |
387 | if (param->rx_mini_pending) { | |
388 | netdev_info(dev, "%s: rx_mini_pending not supported\n", | |
389 | __func__); | |
390 | return -EINVAL; | |
391 | } | |
461017cb | 392 | if (param->rx_pending < (1 << mlx5_min_log_rq_size(rq_wq_type))) { |
f62b8bb8 AV |
393 | netdev_info(dev, "%s: rx_pending (%d) < min (%d)\n", |
394 | __func__, param->rx_pending, | |
461017cb | 395 | 1 << mlx5_min_log_rq_size(rq_wq_type)); |
f62b8bb8 AV |
396 | return -EINVAL; |
397 | } | |
461017cb | 398 | if (param->rx_pending > (1 << mlx5_max_log_rq_size(rq_wq_type))) { |
f62b8bb8 AV |
399 | netdev_info(dev, "%s: rx_pending (%d) > max (%d)\n", |
400 | __func__, param->rx_pending, | |
461017cb | 401 | 1 << mlx5_max_log_rq_size(rq_wq_type)); |
f62b8bb8 AV |
402 | return -EINVAL; |
403 | } | |
404 | if (param->tx_pending < (1 << MLX5E_PARAMS_MINIMUM_LOG_SQ_SIZE)) { | |
405 | netdev_info(dev, "%s: tx_pending (%d) < min (%d)\n", | |
406 | __func__, param->tx_pending, | |
407 | 1 << MLX5E_PARAMS_MINIMUM_LOG_SQ_SIZE); | |
408 | return -EINVAL; | |
409 | } | |
410 | if (param->tx_pending > (1 << MLX5E_PARAMS_MAXIMUM_LOG_SQ_SIZE)) { | |
411 | netdev_info(dev, "%s: tx_pending (%d) > max (%d)\n", | |
412 | __func__, param->tx_pending, | |
413 | 1 << MLX5E_PARAMS_MAXIMUM_LOG_SQ_SIZE); | |
414 | return -EINVAL; | |
415 | } | |
416 | ||
417 | log_rq_size = order_base_2(param->rx_pending); | |
418 | log_sq_size = order_base_2(param->tx_pending); | |
461017cb | 419 | min_rx_wqes = mlx5_min_rx_wqes(rq_wq_type, param->rx_pending); |
f62b8bb8 AV |
420 | |
421 | if (log_rq_size == priv->params.log_rq_size && | |
422 | log_sq_size == priv->params.log_sq_size && | |
423 | min_rx_wqes == priv->params.min_rx_wqes) | |
424 | return 0; | |
425 | ||
426 | mutex_lock(&priv->state_lock); | |
98e81b0a AS |
427 | |
428 | was_opened = test_bit(MLX5E_STATE_OPENED, &priv->state); | |
429 | if (was_opened) | |
430 | mlx5e_close_locked(dev); | |
431 | ||
432 | priv->params.log_rq_size = log_rq_size; | |
433 | priv->params.log_sq_size = log_sq_size; | |
434 | priv->params.min_rx_wqes = min_rx_wqes; | |
435 | ||
436 | if (was_opened) | |
437 | err = mlx5e_open_locked(dev); | |
438 | ||
f62b8bb8 AV |
439 | mutex_unlock(&priv->state_lock); |
440 | ||
441 | return err; | |
442 | } | |
443 | ||
444 | static void mlx5e_get_channels(struct net_device *dev, | |
445 | struct ethtool_channels *ch) | |
446 | { | |
447 | struct mlx5e_priv *priv = netdev_priv(dev); | |
f62b8bb8 | 448 | |
3435ab59 | 449 | ch->max_combined = mlx5e_get_max_num_channels(priv->mdev); |
f62b8bb8 AV |
450 | ch->combined_count = priv->params.num_channels; |
451 | } | |
452 | ||
453 | static int mlx5e_set_channels(struct net_device *dev, | |
454 | struct ethtool_channels *ch) | |
455 | { | |
456 | struct mlx5e_priv *priv = netdev_priv(dev); | |
3435ab59 | 457 | int ncv = mlx5e_get_max_num_channels(priv->mdev); |
f62b8bb8 | 458 | unsigned int count = ch->combined_count; |
45bf454a | 459 | bool arfs_enabled; |
98e81b0a | 460 | bool was_opened; |
f62b8bb8 AV |
461 | int err = 0; |
462 | ||
463 | if (!count) { | |
464 | netdev_info(dev, "%s: combined_count=0 not supported\n", | |
465 | __func__); | |
466 | return -EINVAL; | |
467 | } | |
468 | if (ch->rx_count || ch->tx_count) { | |
469 | netdev_info(dev, "%s: separate rx/tx count not supported\n", | |
470 | __func__); | |
471 | return -EINVAL; | |
472 | } | |
473 | if (count > ncv) { | |
474 | netdev_info(dev, "%s: count (%d) > max (%d)\n", | |
475 | __func__, count, ncv); | |
476 | return -EINVAL; | |
477 | } | |
478 | ||
479 | if (priv->params.num_channels == count) | |
480 | return 0; | |
481 | ||
482 | mutex_lock(&priv->state_lock); | |
98e81b0a AS |
483 | |
484 | was_opened = test_bit(MLX5E_STATE_OPENED, &priv->state); | |
485 | if (was_opened) | |
486 | mlx5e_close_locked(dev); | |
487 | ||
45bf454a MG |
488 | arfs_enabled = dev->features & NETIF_F_NTUPLE; |
489 | if (arfs_enabled) | |
490 | mlx5e_arfs_disable(priv); | |
491 | ||
98e81b0a | 492 | priv->params.num_channels = count; |
d8c9660d | 493 | mlx5e_build_default_indir_rqt(priv->mdev, priv->params.indirection_rqt, |
85082dba | 494 | MLX5E_INDIR_RQT_SIZE, count); |
98e81b0a AS |
495 | |
496 | if (was_opened) | |
497 | err = mlx5e_open_locked(dev); | |
45bf454a MG |
498 | if (err) |
499 | goto out; | |
500 | ||
501 | if (arfs_enabled) { | |
502 | err = mlx5e_arfs_enable(priv); | |
503 | if (err) | |
504 | netdev_err(dev, "%s: mlx5e_arfs_enable failed: %d\n", | |
505 | __func__, err); | |
506 | } | |
98e81b0a | 507 | |
45bf454a | 508 | out: |
f62b8bb8 AV |
509 | mutex_unlock(&priv->state_lock); |
510 | ||
511 | return err; | |
512 | } | |
513 | ||
514 | static int mlx5e_get_coalesce(struct net_device *netdev, | |
515 | struct ethtool_coalesce *coal) | |
516 | { | |
517 | struct mlx5e_priv *priv = netdev_priv(netdev); | |
518 | ||
7524a5d8 GP |
519 | if (!MLX5_CAP_GEN(priv->mdev, cq_moderation)) |
520 | return -ENOTSUPP; | |
521 | ||
f62b8bb8 AV |
522 | coal->rx_coalesce_usecs = priv->params.rx_cq_moderation_usec; |
523 | coal->rx_max_coalesced_frames = priv->params.rx_cq_moderation_pkts; | |
524 | coal->tx_coalesce_usecs = priv->params.tx_cq_moderation_usec; | |
525 | coal->tx_max_coalesced_frames = priv->params.tx_cq_moderation_pkts; | |
526 | ||
527 | return 0; | |
528 | } | |
529 | ||
530 | static int mlx5e_set_coalesce(struct net_device *netdev, | |
531 | struct ethtool_coalesce *coal) | |
532 | { | |
533 | struct mlx5e_priv *priv = netdev_priv(netdev); | |
534 | struct mlx5_core_dev *mdev = priv->mdev; | |
535 | struct mlx5e_channel *c; | |
536 | int tc; | |
537 | int i; | |
538 | ||
7524a5d8 GP |
539 | if (!MLX5_CAP_GEN(mdev, cq_moderation)) |
540 | return -ENOTSUPP; | |
541 | ||
2fcb92fb | 542 | mutex_lock(&priv->state_lock); |
f62b8bb8 AV |
543 | priv->params.tx_cq_moderation_usec = coal->tx_coalesce_usecs; |
544 | priv->params.tx_cq_moderation_pkts = coal->tx_max_coalesced_frames; | |
545 | priv->params.rx_cq_moderation_usec = coal->rx_coalesce_usecs; | |
546 | priv->params.rx_cq_moderation_pkts = coal->rx_max_coalesced_frames; | |
547 | ||
2fcb92fb GP |
548 | if (!test_bit(MLX5E_STATE_OPENED, &priv->state)) |
549 | goto out; | |
550 | ||
f62b8bb8 AV |
551 | for (i = 0; i < priv->params.num_channels; ++i) { |
552 | c = priv->channel[i]; | |
553 | ||
554 | for (tc = 0; tc < c->num_tc; tc++) { | |
555 | mlx5_core_modify_cq_moderation(mdev, | |
556 | &c->sq[tc].cq.mcq, | |
557 | coal->tx_coalesce_usecs, | |
558 | coal->tx_max_coalesced_frames); | |
559 | } | |
560 | ||
561 | mlx5_core_modify_cq_moderation(mdev, &c->rq.cq.mcq, | |
562 | coal->rx_coalesce_usecs, | |
563 | coal->rx_max_coalesced_frames); | |
564 | } | |
565 | ||
2fcb92fb GP |
566 | out: |
567 | mutex_unlock(&priv->state_lock); | |
f62b8bb8 AV |
568 | return 0; |
569 | } | |
570 | ||
571 | static u32 ptys2ethtool_supported_link(u32 eth_proto_cap) | |
572 | { | |
573 | int i; | |
574 | u32 supported_modes = 0; | |
575 | ||
576 | for (i = 0; i < MLX5E_LINK_MODES_NUMBER; ++i) { | |
577 | if (eth_proto_cap & MLX5E_PROT_MASK(i)) | |
578 | supported_modes |= ptys2ethtool_table[i].supported; | |
579 | } | |
580 | return supported_modes; | |
581 | } | |
582 | ||
583 | static u32 ptys2ethtool_adver_link(u32 eth_proto_cap) | |
584 | { | |
585 | int i; | |
586 | u32 advertising_modes = 0; | |
587 | ||
588 | for (i = 0; i < MLX5E_LINK_MODES_NUMBER; ++i) { | |
589 | if (eth_proto_cap & MLX5E_PROT_MASK(i)) | |
590 | advertising_modes |= ptys2ethtool_table[i].advertised; | |
591 | } | |
592 | return advertising_modes; | |
593 | } | |
594 | ||
595 | static u32 ptys2ethtool_supported_port(u32 eth_proto_cap) | |
596 | { | |
597 | if (eth_proto_cap & (MLX5E_PROT_MASK(MLX5E_10GBASE_CR) | |
598 | | MLX5E_PROT_MASK(MLX5E_10GBASE_SR) | |
599 | | MLX5E_PROT_MASK(MLX5E_40GBASE_CR4) | |
600 | | MLX5E_PROT_MASK(MLX5E_40GBASE_SR4) | |
601 | | MLX5E_PROT_MASK(MLX5E_100GBASE_SR4) | |
602 | | MLX5E_PROT_MASK(MLX5E_1000BASE_CX_SGMII))) { | |
603 | return SUPPORTED_FIBRE; | |
604 | } | |
605 | ||
606 | if (eth_proto_cap & (MLX5E_PROT_MASK(MLX5E_100GBASE_KR4) | |
607 | | MLX5E_PROT_MASK(MLX5E_40GBASE_KR4) | |
608 | | MLX5E_PROT_MASK(MLX5E_10GBASE_KR) | |
609 | | MLX5E_PROT_MASK(MLX5E_10GBASE_KX4) | |
610 | | MLX5E_PROT_MASK(MLX5E_1000BASE_KX))) { | |
611 | return SUPPORTED_Backplane; | |
612 | } | |
613 | return 0; | |
614 | } | |
615 | ||
b797a684 SM |
616 | int mlx5e_get_max_linkspeed(struct mlx5_core_dev *mdev, u32 *speed) |
617 | { | |
618 | u32 max_speed = 0; | |
619 | u32 proto_cap; | |
620 | int err; | |
621 | int i; | |
622 | ||
623 | err = mlx5_query_port_proto_cap(mdev, &proto_cap, MLX5_PTYS_EN); | |
624 | if (err) | |
625 | return err; | |
626 | ||
627 | for (i = 0; i < MLX5E_LINK_MODES_NUMBER; ++i) | |
628 | if (proto_cap & MLX5E_PROT_MASK(i)) | |
629 | max_speed = max(max_speed, ptys2ethtool_table[i].speed); | |
630 | ||
631 | *speed = max_speed; | |
632 | return 0; | |
633 | } | |
634 | ||
f62b8bb8 AV |
635 | static void get_speed_duplex(struct net_device *netdev, |
636 | u32 eth_proto_oper, | |
637 | struct ethtool_cmd *cmd) | |
638 | { | |
639 | int i; | |
640 | u32 speed = SPEED_UNKNOWN; | |
641 | u8 duplex = DUPLEX_UNKNOWN; | |
642 | ||
643 | if (!netif_carrier_ok(netdev)) | |
644 | goto out; | |
645 | ||
646 | for (i = 0; i < MLX5E_LINK_MODES_NUMBER; ++i) { | |
647 | if (eth_proto_oper & MLX5E_PROT_MASK(i)) { | |
648 | speed = ptys2ethtool_table[i].speed; | |
649 | duplex = DUPLEX_FULL; | |
650 | break; | |
651 | } | |
652 | } | |
653 | out: | |
654 | ethtool_cmd_speed_set(cmd, speed); | |
655 | cmd->duplex = duplex; | |
656 | } | |
657 | ||
658 | static void get_supported(u32 eth_proto_cap, u32 *supported) | |
659 | { | |
660 | *supported |= ptys2ethtool_supported_port(eth_proto_cap); | |
661 | *supported |= ptys2ethtool_supported_link(eth_proto_cap); | |
662 | *supported |= SUPPORTED_Pause | SUPPORTED_Asym_Pause; | |
663 | } | |
664 | ||
665 | static void get_advertising(u32 eth_proto_cap, u8 tx_pause, | |
666 | u8 rx_pause, u32 *advertising) | |
667 | { | |
668 | *advertising |= ptys2ethtool_adver_link(eth_proto_cap); | |
669 | *advertising |= tx_pause ? ADVERTISED_Pause : 0; | |
670 | *advertising |= (tx_pause ^ rx_pause) ? ADVERTISED_Asym_Pause : 0; | |
671 | } | |
672 | ||
673 | static u8 get_connector_port(u32 eth_proto) | |
674 | { | |
675 | if (eth_proto & (MLX5E_PROT_MASK(MLX5E_10GBASE_SR) | |
676 | | MLX5E_PROT_MASK(MLX5E_40GBASE_SR4) | |
677 | | MLX5E_PROT_MASK(MLX5E_100GBASE_SR4) | |
678 | | MLX5E_PROT_MASK(MLX5E_1000BASE_CX_SGMII))) { | |
679 | return PORT_FIBRE; | |
680 | } | |
681 | ||
682 | if (eth_proto & (MLX5E_PROT_MASK(MLX5E_40GBASE_CR4) | |
683 | | MLX5E_PROT_MASK(MLX5E_10GBASE_CR) | |
684 | | MLX5E_PROT_MASK(MLX5E_100GBASE_CR4))) { | |
685 | return PORT_DA; | |
686 | } | |
687 | ||
688 | if (eth_proto & (MLX5E_PROT_MASK(MLX5E_10GBASE_KX4) | |
689 | | MLX5E_PROT_MASK(MLX5E_10GBASE_KR) | |
690 | | MLX5E_PROT_MASK(MLX5E_40GBASE_KR4) | |
691 | | MLX5E_PROT_MASK(MLX5E_100GBASE_KR4))) { | |
692 | return PORT_NONE; | |
693 | } | |
694 | ||
695 | return PORT_OTHER; | |
696 | } | |
697 | ||
698 | static void get_lp_advertising(u32 eth_proto_lp, u32 *lp_advertising) | |
699 | { | |
700 | *lp_advertising = ptys2ethtool_adver_link(eth_proto_lp); | |
701 | } | |
702 | ||
703 | static int mlx5e_get_settings(struct net_device *netdev, | |
704 | struct ethtool_cmd *cmd) | |
705 | { | |
706 | struct mlx5e_priv *priv = netdev_priv(netdev); | |
707 | struct mlx5_core_dev *mdev = priv->mdev; | |
708 | u32 out[MLX5_ST_SZ_DW(ptys_reg)]; | |
709 | u32 eth_proto_cap; | |
710 | u32 eth_proto_admin; | |
711 | u32 eth_proto_lp; | |
712 | u32 eth_proto_oper; | |
713 | int err; | |
714 | ||
a05bdefa | 715 | err = mlx5_query_port_ptys(mdev, out, sizeof(out), MLX5_PTYS_EN, 1); |
f62b8bb8 AV |
716 | |
717 | if (err) { | |
718 | netdev_err(netdev, "%s: query port ptys failed: %d\n", | |
719 | __func__, err); | |
720 | goto err_query_ptys; | |
721 | } | |
722 | ||
723 | eth_proto_cap = MLX5_GET(ptys_reg, out, eth_proto_capability); | |
724 | eth_proto_admin = MLX5_GET(ptys_reg, out, eth_proto_admin); | |
725 | eth_proto_oper = MLX5_GET(ptys_reg, out, eth_proto_oper); | |
726 | eth_proto_lp = MLX5_GET(ptys_reg, out, eth_proto_lp_advertise); | |
727 | ||
728 | cmd->supported = 0; | |
729 | cmd->advertising = 0; | |
730 | ||
731 | get_supported(eth_proto_cap, &cmd->supported); | |
732 | get_advertising(eth_proto_admin, 0, 0, &cmd->advertising); | |
733 | get_speed_duplex(netdev, eth_proto_oper, cmd); | |
734 | ||
735 | eth_proto_oper = eth_proto_oper ? eth_proto_oper : eth_proto_cap; | |
736 | ||
737 | cmd->port = get_connector_port(eth_proto_oper); | |
738 | get_lp_advertising(eth_proto_lp, &cmd->lp_advertising); | |
739 | ||
740 | cmd->transceiver = XCVR_INTERNAL; | |
741 | ||
742 | err_query_ptys: | |
743 | return err; | |
744 | } | |
745 | ||
746 | static u32 mlx5e_ethtool2ptys_adver_link(u32 link_modes) | |
747 | { | |
748 | u32 i, ptys_modes = 0; | |
749 | ||
750 | for (i = 0; i < MLX5E_LINK_MODES_NUMBER; ++i) { | |
751 | if (ptys2ethtool_table[i].advertised & link_modes) | |
752 | ptys_modes |= MLX5E_PROT_MASK(i); | |
753 | } | |
754 | ||
755 | return ptys_modes; | |
756 | } | |
757 | ||
758 | static u32 mlx5e_ethtool2ptys_speed_link(u32 speed) | |
759 | { | |
760 | u32 i, speed_links = 0; | |
761 | ||
762 | for (i = 0; i < MLX5E_LINK_MODES_NUMBER; ++i) { | |
763 | if (ptys2ethtool_table[i].speed == speed) | |
764 | speed_links |= MLX5E_PROT_MASK(i); | |
765 | } | |
766 | ||
767 | return speed_links; | |
768 | } | |
769 | ||
770 | static int mlx5e_set_settings(struct net_device *netdev, | |
771 | struct ethtool_cmd *cmd) | |
772 | { | |
773 | struct mlx5e_priv *priv = netdev_priv(netdev); | |
774 | struct mlx5_core_dev *mdev = priv->mdev; | |
775 | u32 link_modes; | |
776 | u32 speed; | |
777 | u32 eth_proto_cap, eth_proto_admin; | |
6fa1bcab | 778 | enum mlx5_port_status ps; |
f62b8bb8 AV |
779 | int err; |
780 | ||
781 | speed = ethtool_cmd_speed(cmd); | |
782 | ||
783 | link_modes = cmd->autoneg == AUTONEG_ENABLE ? | |
784 | mlx5e_ethtool2ptys_adver_link(cmd->advertising) : | |
785 | mlx5e_ethtool2ptys_speed_link(speed); | |
786 | ||
787 | err = mlx5_query_port_proto_cap(mdev, ð_proto_cap, MLX5_PTYS_EN); | |
788 | if (err) { | |
789 | netdev_err(netdev, "%s: query port eth proto cap failed: %d\n", | |
790 | __func__, err); | |
791 | goto out; | |
792 | } | |
793 | ||
794 | link_modes = link_modes & eth_proto_cap; | |
795 | if (!link_modes) { | |
796 | netdev_err(netdev, "%s: Not supported link mode(s) requested", | |
797 | __func__); | |
798 | err = -EINVAL; | |
799 | goto out; | |
800 | } | |
801 | ||
802 | err = mlx5_query_port_proto_admin(mdev, ð_proto_admin, MLX5_PTYS_EN); | |
803 | if (err) { | |
804 | netdev_err(netdev, "%s: query port eth proto admin failed: %d\n", | |
805 | __func__, err); | |
806 | goto out; | |
807 | } | |
808 | ||
809 | if (link_modes == eth_proto_admin) | |
810 | goto out; | |
811 | ||
6fa1bcab AS |
812 | mlx5_query_port_admin_status(mdev, &ps); |
813 | if (ps == MLX5_PORT_UP) | |
814 | mlx5_set_port_admin_status(mdev, MLX5_PORT_DOWN); | |
815 | mlx5_set_port_proto(mdev, link_modes, MLX5_PTYS_EN); | |
816 | if (ps == MLX5_PORT_UP) | |
817 | mlx5_set_port_admin_status(mdev, MLX5_PORT_UP); | |
f62b8bb8 | 818 | |
f62b8bb8 AV |
819 | out: |
820 | return err; | |
821 | } | |
822 | ||
2d75b2bc AS |
823 | static u32 mlx5e_get_rxfh_key_size(struct net_device *netdev) |
824 | { | |
825 | struct mlx5e_priv *priv = netdev_priv(netdev); | |
826 | ||
827 | return sizeof(priv->params.toeplitz_hash_key); | |
828 | } | |
829 | ||
830 | static u32 mlx5e_get_rxfh_indir_size(struct net_device *netdev) | |
831 | { | |
832 | return MLX5E_INDIR_RQT_SIZE; | |
833 | } | |
834 | ||
2be6967c SM |
835 | static int mlx5e_get_rxfh(struct net_device *netdev, u32 *indir, u8 *key, |
836 | u8 *hfunc) | |
837 | { | |
838 | struct mlx5e_priv *priv = netdev_priv(netdev); | |
839 | ||
2d75b2bc AS |
840 | if (indir) |
841 | memcpy(indir, priv->params.indirection_rqt, | |
842 | sizeof(priv->params.indirection_rqt)); | |
843 | ||
844 | if (key) | |
845 | memcpy(key, priv->params.toeplitz_hash_key, | |
846 | sizeof(priv->params.toeplitz_hash_key)); | |
847 | ||
2be6967c SM |
848 | if (hfunc) |
849 | *hfunc = priv->params.rss_hfunc; | |
850 | ||
851 | return 0; | |
852 | } | |
853 | ||
bdfc028d TT |
854 | static void mlx5e_modify_tirs_hash(struct mlx5e_priv *priv, void *in, int inlen) |
855 | { | |
856 | struct mlx5_core_dev *mdev = priv->mdev; | |
857 | void *tirc = MLX5_ADDR_OF(modify_tir_in, in, ctx); | |
858 | int i; | |
859 | ||
860 | MLX5_SET(modify_tir_in, in, bitmask.hash, 1); | |
861 | mlx5e_build_tir_ctx_hash(tirc, priv); | |
862 | ||
1da36696 TT |
863 | for (i = 0; i < MLX5E_NUM_INDIR_TIRS; i++) |
864 | mlx5_core_modify_tir(mdev, priv->indir_tirn[i], in, inlen); | |
bdfc028d TT |
865 | } |
866 | ||
98e81b0a | 867 | static int mlx5e_set_rxfh(struct net_device *dev, const u32 *indir, |
2be6967c SM |
868 | const u8 *key, const u8 hfunc) |
869 | { | |
98e81b0a | 870 | struct mlx5e_priv *priv = netdev_priv(dev); |
bdfc028d TT |
871 | int inlen = MLX5_ST_SZ_BYTES(modify_tir_in); |
872 | void *in; | |
2be6967c | 873 | |
2d75b2bc AS |
874 | if ((hfunc != ETH_RSS_HASH_NO_CHANGE) && |
875 | (hfunc != ETH_RSS_HASH_XOR) && | |
2be6967c SM |
876 | (hfunc != ETH_RSS_HASH_TOP)) |
877 | return -EINVAL; | |
878 | ||
bdfc028d TT |
879 | in = mlx5_vzalloc(inlen); |
880 | if (!in) | |
881 | return -ENOMEM; | |
882 | ||
2be6967c SM |
883 | mutex_lock(&priv->state_lock); |
884 | ||
2d75b2bc | 885 | if (indir) { |
1da36696 TT |
886 | u32 rqtn = priv->indir_rqtn; |
887 | ||
2d75b2bc AS |
888 | memcpy(priv->params.indirection_rqt, indir, |
889 | sizeof(priv->params.indirection_rqt)); | |
1da36696 | 890 | mlx5e_redirect_rqt(priv, rqtn, MLX5E_INDIR_RQT_SIZE, 0); |
2be6967c SM |
891 | } |
892 | ||
2d75b2bc AS |
893 | if (key) |
894 | memcpy(priv->params.toeplitz_hash_key, key, | |
895 | sizeof(priv->params.toeplitz_hash_key)); | |
896 | ||
897 | if (hfunc != ETH_RSS_HASH_NO_CHANGE) | |
898 | priv->params.rss_hfunc = hfunc; | |
899 | ||
bdfc028d | 900 | mlx5e_modify_tirs_hash(priv, in, inlen); |
2d75b2bc | 901 | |
2be6967c SM |
902 | mutex_unlock(&priv->state_lock); |
903 | ||
bdfc028d TT |
904 | kvfree(in); |
905 | ||
906 | return 0; | |
2be6967c SM |
907 | } |
908 | ||
2d75b2bc AS |
909 | static int mlx5e_get_rxnfc(struct net_device *netdev, |
910 | struct ethtool_rxnfc *info, u32 *rule_locs) | |
911 | { | |
912 | struct mlx5e_priv *priv = netdev_priv(netdev); | |
913 | int err = 0; | |
914 | ||
915 | switch (info->cmd) { | |
916 | case ETHTOOL_GRXRINGS: | |
917 | info->data = priv->params.num_channels; | |
918 | break; | |
919 | default: | |
920 | err = -EOPNOTSUPP; | |
921 | break; | |
922 | } | |
923 | ||
924 | return err; | |
925 | } | |
926 | ||
58d52291 AS |
927 | static int mlx5e_get_tunable(struct net_device *dev, |
928 | const struct ethtool_tunable *tuna, | |
929 | void *data) | |
930 | { | |
931 | const struct mlx5e_priv *priv = netdev_priv(dev); | |
932 | int err = 0; | |
933 | ||
934 | switch (tuna->id) { | |
935 | case ETHTOOL_TX_COPYBREAK: | |
936 | *(u32 *)data = priv->params.tx_max_inline; | |
937 | break; | |
938 | default: | |
939 | err = -EINVAL; | |
940 | break; | |
941 | } | |
942 | ||
943 | return err; | |
944 | } | |
945 | ||
946 | static int mlx5e_set_tunable(struct net_device *dev, | |
947 | const struct ethtool_tunable *tuna, | |
948 | const void *data) | |
949 | { | |
950 | struct mlx5e_priv *priv = netdev_priv(dev); | |
951 | struct mlx5_core_dev *mdev = priv->mdev; | |
98e81b0a | 952 | bool was_opened; |
58d52291 AS |
953 | u32 val; |
954 | int err = 0; | |
955 | ||
956 | switch (tuna->id) { | |
957 | case ETHTOOL_TX_COPYBREAK: | |
958 | val = *(u32 *)data; | |
959 | if (val > mlx5e_get_max_inline_cap(mdev)) { | |
960 | err = -EINVAL; | |
961 | break; | |
962 | } | |
963 | ||
964 | mutex_lock(&priv->state_lock); | |
98e81b0a AS |
965 | |
966 | was_opened = test_bit(MLX5E_STATE_OPENED, &priv->state); | |
967 | if (was_opened) | |
968 | mlx5e_close_locked(dev); | |
969 | ||
970 | priv->params.tx_max_inline = val; | |
971 | ||
972 | if (was_opened) | |
973 | err = mlx5e_open_locked(dev); | |
974 | ||
58d52291 AS |
975 | mutex_unlock(&priv->state_lock); |
976 | break; | |
977 | default: | |
978 | err = -EINVAL; | |
979 | break; | |
980 | } | |
981 | ||
982 | return err; | |
983 | } | |
984 | ||
3c2d18ef AS |
985 | static void mlx5e_get_pauseparam(struct net_device *netdev, |
986 | struct ethtool_pauseparam *pauseparam) | |
987 | { | |
988 | struct mlx5e_priv *priv = netdev_priv(netdev); | |
989 | struct mlx5_core_dev *mdev = priv->mdev; | |
990 | int err; | |
991 | ||
992 | err = mlx5_query_port_pause(mdev, &pauseparam->rx_pause, | |
993 | &pauseparam->tx_pause); | |
994 | if (err) { | |
995 | netdev_err(netdev, "%s: mlx5_query_port_pause failed:0x%x\n", | |
996 | __func__, err); | |
997 | } | |
998 | } | |
999 | ||
1000 | static int mlx5e_set_pauseparam(struct net_device *netdev, | |
1001 | struct ethtool_pauseparam *pauseparam) | |
1002 | { | |
1003 | struct mlx5e_priv *priv = netdev_priv(netdev); | |
1004 | struct mlx5_core_dev *mdev = priv->mdev; | |
1005 | int err; | |
1006 | ||
1007 | if (pauseparam->autoneg) | |
1008 | return -EINVAL; | |
1009 | ||
1010 | err = mlx5_set_port_pause(mdev, | |
1011 | pauseparam->rx_pause ? 1 : 0, | |
1012 | pauseparam->tx_pause ? 1 : 0); | |
1013 | if (err) { | |
1014 | netdev_err(netdev, "%s: mlx5_set_port_pause failed:0x%x\n", | |
1015 | __func__, err); | |
1016 | } | |
1017 | ||
1018 | return err; | |
1019 | } | |
1020 | ||
ef9814de EBE |
1021 | static int mlx5e_get_ts_info(struct net_device *dev, |
1022 | struct ethtool_ts_info *info) | |
1023 | { | |
1024 | struct mlx5e_priv *priv = netdev_priv(dev); | |
1025 | int ret; | |
1026 | ||
1027 | ret = ethtool_op_get_ts_info(dev, info); | |
1028 | if (ret) | |
1029 | return ret; | |
1030 | ||
3d8c38af EBE |
1031 | info->phc_index = priv->tstamp.ptp ? |
1032 | ptp_clock_index(priv->tstamp.ptp) : -1; | |
ef9814de EBE |
1033 | |
1034 | if (!MLX5_CAP_GEN(priv->mdev, device_frequency_khz)) | |
1035 | return 0; | |
1036 | ||
1037 | info->so_timestamping |= SOF_TIMESTAMPING_TX_HARDWARE | | |
1038 | SOF_TIMESTAMPING_RX_HARDWARE | | |
1039 | SOF_TIMESTAMPING_RAW_HARDWARE; | |
1040 | ||
1041 | info->tx_types = (BIT(1) << HWTSTAMP_TX_OFF) | | |
1042 | (BIT(1) << HWTSTAMP_TX_ON); | |
1043 | ||
1044 | info->rx_filters = (BIT(1) << HWTSTAMP_FILTER_NONE) | | |
1045 | (BIT(1) << HWTSTAMP_FILTER_ALL); | |
1046 | ||
1047 | return 0; | |
1048 | } | |
1049 | ||
928cfe87 TT |
1050 | static __u32 mlx5e_get_wol_supported(struct mlx5_core_dev *mdev) |
1051 | { | |
1052 | __u32 ret = 0; | |
1053 | ||
1054 | if (MLX5_CAP_GEN(mdev, wol_g)) | |
1055 | ret |= WAKE_MAGIC; | |
1056 | ||
1057 | if (MLX5_CAP_GEN(mdev, wol_s)) | |
1058 | ret |= WAKE_MAGICSECURE; | |
1059 | ||
1060 | if (MLX5_CAP_GEN(mdev, wol_a)) | |
1061 | ret |= WAKE_ARP; | |
1062 | ||
1063 | if (MLX5_CAP_GEN(mdev, wol_b)) | |
1064 | ret |= WAKE_BCAST; | |
1065 | ||
1066 | if (MLX5_CAP_GEN(mdev, wol_m)) | |
1067 | ret |= WAKE_MCAST; | |
1068 | ||
1069 | if (MLX5_CAP_GEN(mdev, wol_u)) | |
1070 | ret |= WAKE_UCAST; | |
1071 | ||
1072 | if (MLX5_CAP_GEN(mdev, wol_p)) | |
1073 | ret |= WAKE_PHY; | |
1074 | ||
1075 | return ret; | |
1076 | } | |
1077 | ||
1078 | static __u32 mlx5e_refomrat_wol_mode_mlx5_to_linux(u8 mode) | |
1079 | { | |
1080 | __u32 ret = 0; | |
1081 | ||
1082 | if (mode & MLX5_WOL_MAGIC) | |
1083 | ret |= WAKE_MAGIC; | |
1084 | ||
1085 | if (mode & MLX5_WOL_SECURED_MAGIC) | |
1086 | ret |= WAKE_MAGICSECURE; | |
1087 | ||
1088 | if (mode & MLX5_WOL_ARP) | |
1089 | ret |= WAKE_ARP; | |
1090 | ||
1091 | if (mode & MLX5_WOL_BROADCAST) | |
1092 | ret |= WAKE_BCAST; | |
1093 | ||
1094 | if (mode & MLX5_WOL_MULTICAST) | |
1095 | ret |= WAKE_MCAST; | |
1096 | ||
1097 | if (mode & MLX5_WOL_UNICAST) | |
1098 | ret |= WAKE_UCAST; | |
1099 | ||
1100 | if (mode & MLX5_WOL_PHY_ACTIVITY) | |
1101 | ret |= WAKE_PHY; | |
1102 | ||
1103 | return ret; | |
1104 | } | |
1105 | ||
1106 | static u8 mlx5e_refomrat_wol_mode_linux_to_mlx5(__u32 mode) | |
1107 | { | |
1108 | u8 ret = 0; | |
1109 | ||
1110 | if (mode & WAKE_MAGIC) | |
1111 | ret |= MLX5_WOL_MAGIC; | |
1112 | ||
1113 | if (mode & WAKE_MAGICSECURE) | |
1114 | ret |= MLX5_WOL_SECURED_MAGIC; | |
1115 | ||
1116 | if (mode & WAKE_ARP) | |
1117 | ret |= MLX5_WOL_ARP; | |
1118 | ||
1119 | if (mode & WAKE_BCAST) | |
1120 | ret |= MLX5_WOL_BROADCAST; | |
1121 | ||
1122 | if (mode & WAKE_MCAST) | |
1123 | ret |= MLX5_WOL_MULTICAST; | |
1124 | ||
1125 | if (mode & WAKE_UCAST) | |
1126 | ret |= MLX5_WOL_UNICAST; | |
1127 | ||
1128 | if (mode & WAKE_PHY) | |
1129 | ret |= MLX5_WOL_PHY_ACTIVITY; | |
1130 | ||
1131 | return ret; | |
1132 | } | |
1133 | ||
1134 | static void mlx5e_get_wol(struct net_device *netdev, | |
1135 | struct ethtool_wolinfo *wol) | |
1136 | { | |
1137 | struct mlx5e_priv *priv = netdev_priv(netdev); | |
1138 | struct mlx5_core_dev *mdev = priv->mdev; | |
1139 | u8 mlx5_wol_mode; | |
1140 | int err; | |
1141 | ||
1142 | memset(wol, 0, sizeof(*wol)); | |
1143 | ||
1144 | wol->supported = mlx5e_get_wol_supported(mdev); | |
1145 | if (!wol->supported) | |
1146 | return; | |
1147 | ||
1148 | err = mlx5_query_port_wol(mdev, &mlx5_wol_mode); | |
1149 | if (err) | |
1150 | return; | |
1151 | ||
1152 | wol->wolopts = mlx5e_refomrat_wol_mode_mlx5_to_linux(mlx5_wol_mode); | |
1153 | } | |
1154 | ||
1155 | static int mlx5e_set_wol(struct net_device *netdev, struct ethtool_wolinfo *wol) | |
1156 | { | |
1157 | struct mlx5e_priv *priv = netdev_priv(netdev); | |
1158 | struct mlx5_core_dev *mdev = priv->mdev; | |
1159 | __u32 wol_supported = mlx5e_get_wol_supported(mdev); | |
1160 | u32 mlx5_wol_mode; | |
1161 | ||
1162 | if (!wol_supported) | |
1163 | return -ENOTSUPP; | |
1164 | ||
1165 | if (wol->wolopts & ~wol_supported) | |
1166 | return -EINVAL; | |
1167 | ||
1168 | mlx5_wol_mode = mlx5e_refomrat_wol_mode_linux_to_mlx5(wol->wolopts); | |
1169 | ||
1170 | return mlx5_set_port_wol(mdev, mlx5_wol_mode); | |
1171 | } | |
1172 | ||
da54d24e GP |
1173 | static int mlx5e_set_phys_id(struct net_device *dev, |
1174 | enum ethtool_phys_id_state state) | |
1175 | { | |
1176 | struct mlx5e_priv *priv = netdev_priv(dev); | |
1177 | struct mlx5_core_dev *mdev = priv->mdev; | |
1178 | u16 beacon_duration; | |
1179 | ||
1180 | if (!MLX5_CAP_GEN(mdev, beacon_led)) | |
1181 | return -EOPNOTSUPP; | |
1182 | ||
1183 | switch (state) { | |
1184 | case ETHTOOL_ID_ACTIVE: | |
1185 | beacon_duration = MLX5_BEACON_DURATION_INF; | |
1186 | break; | |
1187 | case ETHTOOL_ID_INACTIVE: | |
1188 | beacon_duration = MLX5_BEACON_DURATION_OFF; | |
1189 | break; | |
1190 | default: | |
1191 | return -EOPNOTSUPP; | |
1192 | } | |
1193 | ||
1194 | return mlx5_set_port_beacon(mdev, beacon_duration); | |
1195 | } | |
1196 | ||
bb64143e GP |
1197 | static int mlx5e_get_module_info(struct net_device *netdev, |
1198 | struct ethtool_modinfo *modinfo) | |
1199 | { | |
1200 | struct mlx5e_priv *priv = netdev_priv(netdev); | |
1201 | struct mlx5_core_dev *dev = priv->mdev; | |
1202 | int size_read = 0; | |
1203 | u8 data[4]; | |
1204 | ||
1205 | size_read = mlx5_query_module_eeprom(dev, 0, 2, data); | |
1206 | if (size_read < 2) | |
1207 | return -EIO; | |
1208 | ||
1209 | /* data[0] = identifier byte */ | |
1210 | switch (data[0]) { | |
1211 | case MLX5_MODULE_ID_QSFP: | |
1212 | modinfo->type = ETH_MODULE_SFF_8436; | |
1213 | modinfo->eeprom_len = ETH_MODULE_SFF_8436_LEN; | |
1214 | break; | |
1215 | case MLX5_MODULE_ID_QSFP_PLUS: | |
1216 | case MLX5_MODULE_ID_QSFP28: | |
1217 | /* data[1] = revision id */ | |
1218 | if (data[0] == MLX5_MODULE_ID_QSFP28 || data[1] >= 0x3) { | |
1219 | modinfo->type = ETH_MODULE_SFF_8636; | |
1220 | modinfo->eeprom_len = ETH_MODULE_SFF_8636_LEN; | |
1221 | } else { | |
1222 | modinfo->type = ETH_MODULE_SFF_8436; | |
1223 | modinfo->eeprom_len = ETH_MODULE_SFF_8436_LEN; | |
1224 | } | |
1225 | break; | |
1226 | case MLX5_MODULE_ID_SFP: | |
1227 | modinfo->type = ETH_MODULE_SFF_8472; | |
1228 | modinfo->eeprom_len = ETH_MODULE_SFF_8472_LEN; | |
1229 | break; | |
1230 | default: | |
1231 | netdev_err(priv->netdev, "%s: cable type not recognized:0x%x\n", | |
1232 | __func__, data[0]); | |
1233 | return -EINVAL; | |
1234 | } | |
1235 | ||
1236 | return 0; | |
1237 | } | |
1238 | ||
1239 | static int mlx5e_get_module_eeprom(struct net_device *netdev, | |
1240 | struct ethtool_eeprom *ee, | |
1241 | u8 *data) | |
1242 | { | |
1243 | struct mlx5e_priv *priv = netdev_priv(netdev); | |
1244 | struct mlx5_core_dev *mdev = priv->mdev; | |
1245 | int offset = ee->offset; | |
1246 | int size_read; | |
1247 | int i = 0; | |
1248 | ||
1249 | if (!ee->len) | |
1250 | return -EINVAL; | |
1251 | ||
1252 | memset(data, 0, ee->len); | |
1253 | ||
1254 | while (i < ee->len) { | |
1255 | size_read = mlx5_query_module_eeprom(mdev, offset, ee->len - i, | |
1256 | data + i); | |
1257 | ||
1258 | if (!size_read) | |
1259 | /* Done reading */ | |
1260 | return 0; | |
1261 | ||
1262 | if (size_read < 0) { | |
1263 | netdev_err(priv->netdev, "%s: mlx5_query_eeprom failed:0x%x\n", | |
1264 | __func__, size_read); | |
1265 | return 0; | |
1266 | } | |
1267 | ||
1268 | i += size_read; | |
1269 | offset += size_read; | |
1270 | } | |
1271 | ||
1272 | return 0; | |
1273 | } | |
1274 | ||
f62b8bb8 AV |
1275 | const struct ethtool_ops mlx5e_ethtool_ops = { |
1276 | .get_drvinfo = mlx5e_get_drvinfo, | |
1277 | .get_link = ethtool_op_get_link, | |
1278 | .get_strings = mlx5e_get_strings, | |
1279 | .get_sset_count = mlx5e_get_sset_count, | |
1280 | .get_ethtool_stats = mlx5e_get_ethtool_stats, | |
1281 | .get_ringparam = mlx5e_get_ringparam, | |
1282 | .set_ringparam = mlx5e_set_ringparam, | |
1283 | .get_channels = mlx5e_get_channels, | |
1284 | .set_channels = mlx5e_set_channels, | |
1285 | .get_coalesce = mlx5e_get_coalesce, | |
1286 | .set_coalesce = mlx5e_set_coalesce, | |
1287 | .get_settings = mlx5e_get_settings, | |
1288 | .set_settings = mlx5e_set_settings, | |
2d75b2bc AS |
1289 | .get_rxfh_key_size = mlx5e_get_rxfh_key_size, |
1290 | .get_rxfh_indir_size = mlx5e_get_rxfh_indir_size, | |
2be6967c SM |
1291 | .get_rxfh = mlx5e_get_rxfh, |
1292 | .set_rxfh = mlx5e_set_rxfh, | |
2d75b2bc | 1293 | .get_rxnfc = mlx5e_get_rxnfc, |
58d52291 AS |
1294 | .get_tunable = mlx5e_get_tunable, |
1295 | .set_tunable = mlx5e_set_tunable, | |
3c2d18ef AS |
1296 | .get_pauseparam = mlx5e_get_pauseparam, |
1297 | .set_pauseparam = mlx5e_set_pauseparam, | |
ef9814de | 1298 | .get_ts_info = mlx5e_get_ts_info, |
da54d24e | 1299 | .set_phys_id = mlx5e_set_phys_id, |
928cfe87 TT |
1300 | .get_wol = mlx5e_get_wol, |
1301 | .set_wol = mlx5e_set_wol, | |
bb64143e GP |
1302 | .get_module_info = mlx5e_get_module_info, |
1303 | .get_module_eeprom = mlx5e_get_module_eeprom, | |
f62b8bb8 | 1304 | }; |