xref: /freebsd/sys/dev/mlx5/mlx5_en/mlx5_en_ethtool.c (revision 44d780e32b9d798a93b758fe0957d770e3190988)
1 /*-
2  * Copyright (c) 2015-2019 Mellanox Technologies. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS `AS IS' AND
14  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
16  * ARE DISCLAIMED.  IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
17  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
18  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
19  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
20  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
21  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
22  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
23  * SUCH DAMAGE.
24  *
25  * $FreeBSD$
26  */
27 
28 #include "en.h"
29 #include "port_buffer.h"
30 
31 void
32 mlx5e_create_stats(struct sysctl_ctx_list *ctx,
33     struct sysctl_oid_list *parent, const char *buffer,
34     const char **desc, unsigned num, u64 * arg)
35 {
36 	struct sysctl_oid *node;
37 	unsigned x;
38 
39 	sysctl_ctx_init(ctx);
40 
41 	node = SYSCTL_ADD_NODE(ctx, parent, OID_AUTO,
42 	    buffer, CTLFLAG_RD, NULL, "Statistics");
43 	if (node == NULL)
44 		return;
45 	for (x = 0; x != num; x++) {
46 		SYSCTL_ADD_UQUAD(ctx, SYSCTL_CHILDREN(node), OID_AUTO,
47 		    desc[2 * x], CTLFLAG_RD, arg + x, desc[2 * x + 1]);
48 	}
49 }
50 
51 void
52 mlx5e_create_counter_stats(struct sysctl_ctx_list *ctx,
53     struct sysctl_oid_list *parent, const char *buffer,
54     const char **desc, unsigned num, counter_u64_t *arg)
55 {
56 	struct sysctl_oid *node;
57 	unsigned x;
58 
59 	sysctl_ctx_init(ctx);
60 
61 	node = SYSCTL_ADD_NODE(ctx, parent, OID_AUTO,
62 	    buffer, CTLFLAG_RD, NULL, "Statistics");
63 	if (node == NULL)
64 		return;
65 	for (x = 0; x != num; x++) {
66 		SYSCTL_ADD_COUNTER_U64(ctx, SYSCTL_CHILDREN(node), OID_AUTO,
67 		    desc[2 * x], CTLFLAG_RD, arg + x, desc[2 * x + 1]);
68 	}
69 }
70 
71 static void
72 mlx5e_ethtool_sync_tx_completion_fact(struct mlx5e_priv *priv)
73 {
74 	/*
75 	 * Limit the maximum distance between completion events to
76 	 * half of the currently set TX queue size.
77 	 *
78 	 * The maximum number of queue entries a single IP packet can
79 	 * consume is given by MLX5_SEND_WQE_MAX_WQEBBS.
80 	 *
81 	 * The worst case max value is then given as below:
82 	 */
83 	uint64_t max = priv->params_ethtool.tx_queue_size /
84 	    (2 * MLX5_SEND_WQE_MAX_WQEBBS);
85 
86 	/*
87 	 * Update the maximum completion factor value in case the
88 	 * tx_queue_size field changed. Ensure we don't overflow
89 	 * 16-bits.
90 	 */
91 	if (max < 1)
92 		max = 1;
93 	else if (max > 65535)
94 		max = 65535;
95 	priv->params_ethtool.tx_completion_fact_max = max;
96 
97 	/*
98 	 * Verify that the current TX completion factor is within the
99 	 * given limits:
100 	 */
101 	if (priv->params_ethtool.tx_completion_fact < 1)
102 		priv->params_ethtool.tx_completion_fact = 1;
103 	else if (priv->params_ethtool.tx_completion_fact > max)
104 		priv->params_ethtool.tx_completion_fact = max;
105 }
106 
107 static int
108 mlx5e_getmaxrate(struct mlx5e_priv *priv)
109 {
110 	struct mlx5_core_dev *mdev = priv->mdev;
111 	u8 max_bw_unit[IEEE_8021QAZ_MAX_TCS];
112 	u8 max_bw_value[IEEE_8021QAZ_MAX_TCS];
113 	int err;
114 	int i;
115 
116 	PRIV_LOCK(priv);
117 	err = -mlx5_query_port_tc_rate_limit(mdev, max_bw_value, max_bw_unit);
118 	if (err)
119 		goto done;
120 
121 	for (i = 0; i <= mlx5_max_tc(mdev); i++) {
122 		switch (max_bw_unit[i]) {
123 		case MLX5_100_MBPS_UNIT:
124 			priv->params_ethtool.max_bw_value[i] = max_bw_value[i] * MLX5E_100MB;
125 			break;
126 		case MLX5_GBPS_UNIT:
127 			priv->params_ethtool.max_bw_value[i] = max_bw_value[i] * MLX5E_1GB;
128 			break;
129 		case MLX5_BW_NO_LIMIT:
130 			priv->params_ethtool.max_bw_value[i] = 0;
131 			break;
132 		default:
133 			priv->params_ethtool.max_bw_value[i] = -1;
134 			WARN_ONCE(true, "non-supported BW unit");
135 			break;
136 		}
137 	}
138 done:
139 	PRIV_UNLOCK(priv);
140 	return (err);
141 }
142 
143 static int
144 mlx5e_get_max_alloc(struct mlx5e_priv *priv)
145 {
146 	struct mlx5_core_dev *mdev = priv->mdev;
147 	int err;
148 	int x;
149 
150 	PRIV_LOCK(priv);
151 	err = -mlx5_query_port_tc_bw_alloc(mdev, priv->params_ethtool.max_bw_share);
152 	if (err == 0) {
153 		/* set default value */
154 		for (x = 0; x != IEEE_8021QAZ_MAX_TCS; x++) {
155 			priv->params_ethtool.max_bw_share[x] =
156 			    100 / IEEE_8021QAZ_MAX_TCS;
157 		}
158 		err = -mlx5_set_port_tc_bw_alloc(mdev,
159 		    priv->params_ethtool.max_bw_share);
160 	}
161 	PRIV_UNLOCK(priv);
162 
163 	return (err);
164 }
165 
166 static int
167 mlx5e_get_dscp(struct mlx5e_priv *priv)
168 {
169 	struct mlx5_core_dev *mdev = priv->mdev;
170 	int err;
171 
172 	if (MLX5_CAP_GEN(mdev, qcam_reg) == 0 ||
173 	    MLX5_CAP_QCAM_REG(mdev, qpts) == 0 ||
174 	    MLX5_CAP_QCAM_REG(mdev, qpdpm) == 0)
175 		return (EOPNOTSUPP);
176 
177 	PRIV_LOCK(priv);
178 	err = -mlx5_query_dscp2prio(mdev, priv->params_ethtool.dscp2prio);
179 	if (err)
180 		goto done;
181 
182 	err = -mlx5_query_trust_state(mdev, &priv->params_ethtool.trust_state);
183 	if (err)
184 		goto done;
185 done:
186 	PRIV_UNLOCK(priv);
187 	return (err);
188 }
189 
190 static void
191 mlx5e_tc_get_parameters(struct mlx5e_priv *priv,
192     u64 *new_bw_value, u8 *max_bw_value, u8 *max_bw_unit)
193 {
194 	const u64 upper_limit_mbps = 255 * MLX5E_100MB;
195 	const u64 upper_limit_gbps = 255 * MLX5E_1GB;
196 	u64 temp;
197 	int i;
198 
199 	memset(max_bw_value, 0, IEEE_8021QAZ_MAX_TCS);
200 	memset(max_bw_unit, 0, IEEE_8021QAZ_MAX_TCS);
201 
202 	for (i = 0; i <= mlx5_max_tc(priv->mdev); i++) {
203 		temp = (new_bw_value != NULL) ?
204 		    new_bw_value[i] : priv->params_ethtool.max_bw_value[i];
205 
206 		if (!temp) {
207 			max_bw_unit[i] = MLX5_BW_NO_LIMIT;
208 		} else if (temp > upper_limit_gbps) {
209 			max_bw_unit[i] = MLX5_BW_NO_LIMIT;
210 		} else if (temp <= upper_limit_mbps) {
211 			max_bw_value[i] = howmany(temp, MLX5E_100MB);
212 			max_bw_unit[i]  = MLX5_100_MBPS_UNIT;
213 		} else {
214 			max_bw_value[i] = howmany(temp, MLX5E_1GB);
215 			max_bw_unit[i]  = MLX5_GBPS_UNIT;
216 		}
217 	}
218 }
219 
220 static int
221 mlx5e_tc_maxrate_handler(SYSCTL_HANDLER_ARGS)
222 {
223 	struct mlx5e_priv *priv = arg1;
224 	struct mlx5_core_dev *mdev = priv->mdev;
225 	u8 max_bw_unit[IEEE_8021QAZ_MAX_TCS];
226 	u8 max_bw_value[IEEE_8021QAZ_MAX_TCS];
227 	u64 new_bw_value[IEEE_8021QAZ_MAX_TCS];
228 	u8 max_rates = mlx5_max_tc(mdev) + 1;
229 	u8 x;
230 	int err;
231 
232 	PRIV_LOCK(priv);
233 	err = SYSCTL_OUT(req, priv->params_ethtool.max_bw_value,
234 	    sizeof(priv->params_ethtool.max_bw_value[0]) * max_rates);
235 	if (err || !req->newptr)
236 		goto done;
237 	err = SYSCTL_IN(req, new_bw_value,
238 	    sizeof(new_bw_value[0]) * max_rates);
239 	if (err)
240 		goto done;
241 
242 	/* range check input value */
243 	for (x = 0; x != max_rates; x++) {
244 		if (new_bw_value[x] % MLX5E_100MB) {
245 			err = ERANGE;
246 			goto done;
247 		}
248 	}
249 
250 	mlx5e_tc_get_parameters(priv, new_bw_value, max_bw_value, max_bw_unit);
251 
252 	err = -mlx5_modify_port_tc_rate_limit(mdev, max_bw_value, max_bw_unit);
253 	if (err)
254 		goto done;
255 
256 	memcpy(priv->params_ethtool.max_bw_value, new_bw_value,
257 	    sizeof(priv->params_ethtool.max_bw_value));
258 done:
259 	PRIV_UNLOCK(priv);
260 	return (err);
261 }
262 
263 static int
264 mlx5e_tc_rate_share_handler(SYSCTL_HANDLER_ARGS)
265 {
266 	struct mlx5e_priv *priv = arg1;
267 	struct mlx5_core_dev *mdev = priv->mdev;
268 	u8 max_bw_share[IEEE_8021QAZ_MAX_TCS];
269 	u8 max_rates = mlx5_max_tc(mdev) + 1;
270 	int i;
271 	int err;
272 	int sum;
273 
274 	PRIV_LOCK(priv);
275 	err = SYSCTL_OUT(req, priv->params_ethtool.max_bw_share, max_rates);
276 	if (err || !req->newptr)
277 		goto done;
278 	err = SYSCTL_IN(req, max_bw_share, max_rates);
279 	if (err)
280 		goto done;
281 
282 	/* range check input value */
283 	for (sum = i = 0; i != max_rates; i++) {
284 		if (max_bw_share[i] < 1 || max_bw_share[i] > 100) {
285 			err = ERANGE;
286 			goto done;
287 		}
288 		sum += max_bw_share[i];
289 	}
290 
291 	/* sum of values should be as close to 100 as possible */
292 	if (sum < (100 - max_rates + 1) || sum > 100) {
293 		err = ERANGE;
294 		goto done;
295 	}
296 
297 	err = -mlx5_set_port_tc_bw_alloc(mdev, max_bw_share);
298 	if (err)
299 		goto done;
300 
301 	memcpy(priv->params_ethtool.max_bw_share, max_bw_share,
302 	    sizeof(priv->params_ethtool.max_bw_share));
303 done:
304 	PRIV_UNLOCK(priv);
305 	return (err);
306 }
307 
308 static int
309 mlx5e_get_prio_tc(struct mlx5e_priv *priv)
310 {
311 	struct mlx5_core_dev *mdev = priv->mdev;
312 	int err = 0;
313 	int i;
314 
315 	PRIV_LOCK(priv);
316 	if (!MLX5_CAP_GEN(priv->mdev, ets)) {
317 		PRIV_UNLOCK(priv);
318 		return (EOPNOTSUPP);
319 	}
320 
321 	for (i = 0; i != MLX5E_MAX_PRIORITY; i++) {
322 		err = -mlx5_query_port_prio_tc(mdev, i, priv->params_ethtool.prio_tc + i);
323 		if (err)
324 			break;
325 	}
326 	PRIV_UNLOCK(priv);
327 	return (err);
328 }
329 
330 static int
331 mlx5e_prio_to_tc_handler(SYSCTL_HANDLER_ARGS)
332 {
333 	struct mlx5e_priv *priv = arg1;
334 	struct mlx5_core_dev *mdev = priv->mdev;
335 	uint8_t temp[MLX5E_MAX_PRIORITY];
336 	int err;
337 	int i;
338 
339 	PRIV_LOCK(priv);
340 	err = SYSCTL_OUT(req, priv->params_ethtool.prio_tc, MLX5E_MAX_PRIORITY);
341 	if (err || !req->newptr)
342 		goto done;
343 	err = SYSCTL_IN(req, temp, MLX5E_MAX_PRIORITY);
344 	if (err)
345 		goto done;
346 
347 	for (i = 0; i != MLX5E_MAX_PRIORITY; i++) {
348 		if (temp[i] > mlx5_max_tc(mdev)) {
349 			err = ERANGE;
350 			goto done;
351 		}
352 	}
353 
354 	for (i = 0; i != MLX5E_MAX_PRIORITY; i++) {
355 		if (temp[i] == priv->params_ethtool.prio_tc[i])
356 			continue;
357 		err = -mlx5_set_port_prio_tc(mdev, i, temp[i]);
358 		if (err)
359 			goto done;
360 		/* update cached value */
361 		priv->params_ethtool.prio_tc[i] = temp[i];
362 	}
363 done:
364 	PRIV_UNLOCK(priv);
365 	return (err);
366 }
367 
368 int
369 mlx5e_fec_update(struct mlx5e_priv *priv)
370 {
371 	struct mlx5_core_dev *mdev = priv->mdev;
372 	u32 in[MLX5_ST_SZ_DW(pplm_reg)] = {};
373 	const int sz = MLX5_ST_SZ_BYTES(pplm_reg);
374 	int err;
375 
376 	if (!MLX5_CAP_GEN(mdev, pcam_reg))
377 		return (EOPNOTSUPP);
378 
379 	if (!MLX5_CAP_PCAM_REG(mdev, pplm))
380 		return (EOPNOTSUPP);
381 
382 	MLX5_SET(pplm_reg, in, local_port, 1);
383 
384 	err = -mlx5_core_access_reg(mdev, in, sz, in, sz, MLX5_REG_PPLM, 0, 0);
385 	if (err)
386 		return (err);
387 
388 	/* get 10x..25x mask */
389 	priv->params_ethtool.fec_mask_10x_25x[0] =
390 	    MLX5_GET(pplm_reg, in, fec_override_admin_10g_40g);
391 	priv->params_ethtool.fec_mask_10x_25x[1] =
392 	    MLX5_GET(pplm_reg, in, fec_override_admin_25g) &
393 	    MLX5_GET(pplm_reg, in, fec_override_admin_50g);
394 	priv->params_ethtool.fec_mask_10x_25x[2] =
395 	    MLX5_GET(pplm_reg, in, fec_override_admin_56g);
396 	priv->params_ethtool.fec_mask_10x_25x[3] =
397 	    MLX5_GET(pplm_reg, in, fec_override_admin_100g);
398 
399 	/* get 10x..25x available bits */
400 	priv->params_ethtool.fec_avail_10x_25x[0] =
401 	    MLX5_GET(pplm_reg, in, fec_override_cap_10g_40g);
402 	priv->params_ethtool.fec_avail_10x_25x[1] =
403 	    MLX5_GET(pplm_reg, in, fec_override_cap_25g) &
404 	    MLX5_GET(pplm_reg, in, fec_override_cap_50g);
405 	priv->params_ethtool.fec_avail_10x_25x[2] =
406 	    MLX5_GET(pplm_reg, in, fec_override_cap_56g);
407 	priv->params_ethtool.fec_avail_10x_25x[3] =
408 	    MLX5_GET(pplm_reg, in, fec_override_cap_100g);
409 
410 	/* get 50x mask */
411 	priv->params_ethtool.fec_mask_50x[0] =
412 	    MLX5_GET(pplm_reg, in, fec_override_admin_50g_1x);
413 	priv->params_ethtool.fec_mask_50x[1] =
414 	    MLX5_GET(pplm_reg, in, fec_override_admin_100g_2x);
415 	priv->params_ethtool.fec_mask_50x[2] =
416 	    MLX5_GET(pplm_reg, in, fec_override_admin_200g_4x);
417 	priv->params_ethtool.fec_mask_50x[3] =
418 	    MLX5_GET(pplm_reg, in, fec_override_admin_400g_8x);
419 
420 	/* get 50x available bits */
421 	priv->params_ethtool.fec_avail_50x[0] =
422 	    MLX5_GET(pplm_reg, in, fec_override_cap_50g_1x);
423 	priv->params_ethtool.fec_avail_50x[1] =
424 	    MLX5_GET(pplm_reg, in, fec_override_cap_100g_2x);
425 	priv->params_ethtool.fec_avail_50x[2] =
426 	    MLX5_GET(pplm_reg, in, fec_override_cap_200g_4x);
427 	priv->params_ethtool.fec_avail_50x[3] =
428 	    MLX5_GET(pplm_reg, in, fec_override_cap_400g_8x);
429 
430 	/* get current FEC mask */
431 	priv->params_ethtool.fec_mode_active =
432 	    MLX5_GET(pplm_reg, in, fec_mode_active);
433 
434 	return (0);
435 }
436 
437 static int
438 mlx5e_fec_mask_10x_25x_handler(SYSCTL_HANDLER_ARGS)
439 {
440 	struct mlx5e_priv *priv = arg1;
441 	struct mlx5_core_dev *mdev = priv->mdev;
442 	u32 out[MLX5_ST_SZ_DW(pplm_reg)] = {};
443 	u32 in[MLX5_ST_SZ_DW(pplm_reg)] = {};
444 	const int sz = MLX5_ST_SZ_BYTES(pplm_reg);
445 	u8 fec_mask_10x_25x[MLX5E_MAX_FEC_10X_25X];
446 	u8 fec_cap_changed = 0;
447 	u8 x;
448 	int err;
449 
450 	PRIV_LOCK(priv);
451 	err = SYSCTL_OUT(req, priv->params_ethtool.fec_mask_10x_25x,
452 	    sizeof(priv->params_ethtool.fec_mask_10x_25x));
453 	if (err || !req->newptr)
454 		goto done;
455 
456 	err = SYSCTL_IN(req, fec_mask_10x_25x,
457 	    sizeof(fec_mask_10x_25x));
458 	if (err)
459 		goto done;
460 
461 	if (!MLX5_CAP_GEN(mdev, pcam_reg)) {
462 		err = EOPNOTSUPP;
463 		goto done;
464 	}
465 
466 	if (!MLX5_CAP_PCAM_REG(mdev, pplm)) {
467 		err = EOPNOTSUPP;
468 		goto done;
469 	}
470 
471 	MLX5_SET(pplm_reg, in, local_port, 1);
472 
473 	err = -mlx5_core_access_reg(mdev, in, sz, in, sz, MLX5_REG_PPLM, 0, 0);
474 	if (err)
475 		goto done;
476 
477 	/* range check input value */
478 	for (x = 0; x != MLX5E_MAX_FEC_10X_25X; x++) {
479 		/* check only one bit is set, if any */
480 		if (fec_mask_10x_25x[x] & (fec_mask_10x_25x[x] - 1)) {
481 			err = ERANGE;
482 			goto done;
483 		}
484 		/* check a supported bit is set, if any */
485 		if (fec_mask_10x_25x[x] &
486 		    ~priv->params_ethtool.fec_avail_10x_25x[x]) {
487 			err = ERANGE;
488 			goto done;
489 		}
490 		fec_cap_changed |= (fec_mask_10x_25x[x] ^
491 		    priv->params_ethtool.fec_mask_10x_25x[x]);
492 	}
493 
494 	/* check for no changes */
495 	if (fec_cap_changed == 0)
496 		goto done;
497 
498 	memset(in, 0, sizeof(in));
499 
500 	MLX5_SET(pplm_reg, in, local_port, 1);
501 
502 	/* set new values */
503 	MLX5_SET(pplm_reg, in, fec_override_admin_10g_40g, fec_mask_10x_25x[0]);
504 	MLX5_SET(pplm_reg, in, fec_override_admin_25g, fec_mask_10x_25x[1]);
505 	MLX5_SET(pplm_reg, in, fec_override_admin_50g, fec_mask_10x_25x[1]);
506 	MLX5_SET(pplm_reg, in, fec_override_admin_56g, fec_mask_10x_25x[2]);
507 	MLX5_SET(pplm_reg, in, fec_override_admin_100g, fec_mask_10x_25x[3]);
508 
509 	/* preserve other values */
510 	MLX5_SET(pplm_reg, in, fec_override_admin_50g_1x, priv->params_ethtool.fec_mask_50x[0]);
511 	MLX5_SET(pplm_reg, in, fec_override_admin_100g_2x, priv->params_ethtool.fec_mask_50x[1]);
512 	MLX5_SET(pplm_reg, in, fec_override_admin_200g_4x, priv->params_ethtool.fec_mask_50x[2]);
513 	MLX5_SET(pplm_reg, in, fec_override_admin_400g_8x, priv->params_ethtool.fec_mask_50x[3]);
514 
515 	/* send new value to the firmware */
516 	err = -mlx5_core_access_reg(mdev, in, sz, out, sz, MLX5_REG_PPLM, 0, 1);
517 	if (err)
518 		goto done;
519 
520 	memcpy(priv->params_ethtool.fec_mask_10x_25x, fec_mask_10x_25x,
521 	    sizeof(priv->params_ethtool.fec_mask_10x_25x));
522 
523 	mlx5_toggle_port_link(priv->mdev);
524 done:
525 	PRIV_UNLOCK(priv);
526 	return (err);
527 }
528 
529 static int
530 mlx5e_fec_avail_10x_25x_handler(SYSCTL_HANDLER_ARGS)
531 {
532 	struct mlx5e_priv *priv = arg1;
533 	int err;
534 
535 	PRIV_LOCK(priv);
536 	err = SYSCTL_OUT(req, priv->params_ethtool.fec_avail_10x_25x,
537 	    sizeof(priv->params_ethtool.fec_avail_10x_25x));
538 	PRIV_UNLOCK(priv);
539 	return (err);
540 }
541 
542 static int
543 mlx5e_fec_mask_50x_handler(SYSCTL_HANDLER_ARGS)
544 {
545 	struct mlx5e_priv *priv = arg1;
546 	struct mlx5_core_dev *mdev = priv->mdev;
547 	u32 out[MLX5_ST_SZ_DW(pplm_reg)] = {};
548 	u32 in[MLX5_ST_SZ_DW(pplm_reg)] = {};
549 	const int sz = MLX5_ST_SZ_BYTES(pplm_reg);
550 	u16 fec_mask_50x[MLX5E_MAX_FEC_50X];
551 	u16 fec_cap_changed = 0;
552 	u8 x;
553 	int err;
554 
555 	PRIV_LOCK(priv);
556 	err = SYSCTL_OUT(req, priv->params_ethtool.fec_mask_50x,
557 	    sizeof(priv->params_ethtool.fec_mask_50x));
558 	if (err || !req->newptr)
559 		goto done;
560 
561 	err = SYSCTL_IN(req, fec_mask_50x,
562 	    sizeof(fec_mask_50x));
563 	if (err)
564 		goto done;
565 
566 	if (!MLX5_CAP_GEN(mdev, pcam_reg)) {
567 		err = EOPNOTSUPP;
568 		goto done;
569 	}
570 
571 	if (!MLX5_CAP_PCAM_REG(mdev, pplm)) {
572 		err = EOPNOTSUPP;
573 		goto done;
574 	}
575 
576 	MLX5_SET(pplm_reg, in, local_port, 1);
577 
578 	err = -mlx5_core_access_reg(mdev, in, sz, in, sz, MLX5_REG_PPLM, 0, 0);
579 	if (err)
580 		goto done;
581 
582 	/* range check input value */
583 	for (x = 0; x != MLX5E_MAX_FEC_50X; x++) {
584 		/* check only one bit is set, if any */
585 		if (fec_mask_50x[x] & (fec_mask_50x[x] - 1)) {
586 			err = ERANGE;
587 			goto done;
588 		}
589 		/* check a supported bit is set, if any */
590 		if (fec_mask_50x[x] &
591 		    ~priv->params_ethtool.fec_avail_50x[x]) {
592 			err = ERANGE;
593 			goto done;
594 		}
595 		fec_cap_changed |= (fec_mask_50x[x] ^
596 		    priv->params_ethtool.fec_mask_50x[x]);
597 	}
598 
599 	/* check for no changes */
600 	if (fec_cap_changed == 0)
601 		goto done;
602 
603 	memset(in, 0, sizeof(in));
604 
605 	MLX5_SET(pplm_reg, in, local_port, 1);
606 
607 	/* set new values */
608 	MLX5_SET(pplm_reg, in, fec_override_admin_50g_1x, fec_mask_50x[0]);
609 	MLX5_SET(pplm_reg, in, fec_override_admin_100g_2x, fec_mask_50x[1]);
610 	MLX5_SET(pplm_reg, in, fec_override_admin_200g_4x, fec_mask_50x[2]);
611 	MLX5_SET(pplm_reg, in, fec_override_admin_400g_8x, fec_mask_50x[3]);
612 
613 	/* preserve other values */
614 	MLX5_SET(pplm_reg, in, fec_override_admin_10g_40g, priv->params_ethtool.fec_mask_10x_25x[0]);
615 	MLX5_SET(pplm_reg, in, fec_override_admin_25g, priv->params_ethtool.fec_mask_10x_25x[1]);
616 	MLX5_SET(pplm_reg, in, fec_override_admin_50g, priv->params_ethtool.fec_mask_10x_25x[1]);
617 	MLX5_SET(pplm_reg, in, fec_override_admin_56g, priv->params_ethtool.fec_mask_10x_25x[2]);
618 	MLX5_SET(pplm_reg, in, fec_override_admin_100g, priv->params_ethtool.fec_mask_10x_25x[3]);
619 
620 	/* send new value to the firmware */
621 	err = -mlx5_core_access_reg(mdev, in, sz, out, sz, MLX5_REG_PPLM, 0, 1);
622 	if (err)
623 		goto done;
624 
625 	memcpy(priv->params_ethtool.fec_mask_50x, fec_mask_50x,
626 	    sizeof(priv->params_ethtool.fec_mask_50x));
627 
628 	mlx5_toggle_port_link(priv->mdev);
629 done:
630 	PRIV_UNLOCK(priv);
631 	return (err);
632 }
633 
634 static int
635 mlx5e_fec_avail_50x_handler(SYSCTL_HANDLER_ARGS)
636 {
637 	struct mlx5e_priv *priv = arg1;
638 	int err;
639 
640 	PRIV_LOCK(priv);
641 	err = SYSCTL_OUT(req, priv->params_ethtool.fec_avail_50x,
642 	    sizeof(priv->params_ethtool.fec_avail_50x));
643 	PRIV_UNLOCK(priv);
644 	return (err);
645 }
646 
647 static int
648 mlx5e_trust_state_handler(SYSCTL_HANDLER_ARGS)
649 {
650 	struct mlx5e_priv *priv = arg1;
651 	struct mlx5_core_dev *mdev = priv->mdev;
652 	int err;
653 	u8 result;
654 
655 	PRIV_LOCK(priv);
656 	result = priv->params_ethtool.trust_state;
657 	err = sysctl_handle_8(oidp, &result, 0, req);
658 	if (err || !req->newptr ||
659 	    result == priv->params_ethtool.trust_state)
660 		goto done;
661 
662 	switch (result) {
663 	case MLX5_QPTS_TRUST_PCP:
664 	case MLX5_QPTS_TRUST_DSCP:
665 		break;
666 	case MLX5_QPTS_TRUST_BOTH:
667 		if (!MLX5_CAP_QCAM_FEATURE(mdev, qpts_trust_both)) {
668 			err = EOPNOTSUPP;
669 			goto done;
670 		}
671 		break;
672 	default:
673 		err = ERANGE;
674 		goto done;
675 	}
676 
677 	err = -mlx5_set_trust_state(mdev, result);
678 	if (err)
679 		goto done;
680 
681 	priv->params_ethtool.trust_state = result;
682 
683 	/* update inline mode */
684 	mlx5e_refresh_sq_inline(priv);
685 #ifdef RATELIMIT
686 	mlx5e_rl_refresh_sq_inline(&priv->rl);
687 #endif
688 done:
689 	PRIV_UNLOCK(priv);
690 	return (err);
691 }
692 
693 static int
694 mlx5e_dscp_prio_handler(SYSCTL_HANDLER_ARGS)
695 {
696 	struct mlx5e_priv *priv = arg1;
697 	int prio_index = arg2;
698 	struct mlx5_core_dev *mdev = priv->mdev;
699 	uint8_t dscp2prio[MLX5_MAX_SUPPORTED_DSCP];
700 	uint8_t x;
701 	int err;
702 
703 	PRIV_LOCK(priv);
704 	err = SYSCTL_OUT(req, priv->params_ethtool.dscp2prio + prio_index,
705 	    sizeof(priv->params_ethtool.dscp2prio) / 8);
706 	if (err || !req->newptr)
707 		goto done;
708 
709 	memcpy(dscp2prio, priv->params_ethtool.dscp2prio, sizeof(dscp2prio));
710 	err = SYSCTL_IN(req, dscp2prio + prio_index, sizeof(dscp2prio) / 8);
711 	if (err)
712 		goto done;
713 	for (x = 0; x != MLX5_MAX_SUPPORTED_DSCP; x++) {
714 		if (dscp2prio[x] > 7) {
715 			err = ERANGE;
716 			goto done;
717 		}
718 	}
719 	err = -mlx5_set_dscp2prio(mdev, dscp2prio);
720 	if (err)
721 		goto done;
722 
723 	/* update local array */
724 	memcpy(priv->params_ethtool.dscp2prio, dscp2prio,
725 	    sizeof(priv->params_ethtool.dscp2prio));
726 done:
727 	PRIV_UNLOCK(priv);
728 	return (err);
729 }
730 
731 int
732 mlx5e_update_buf_lossy(struct mlx5e_priv *priv)
733 {
734 	struct ieee_pfc pfc;
735 
736 	PRIV_ASSERT_LOCKED(priv);
737 	bzero(&pfc, sizeof(pfc));
738 	pfc.pfc_en = priv->params.rx_priority_flow_control;
739 	return (-mlx5e_port_manual_buffer_config(priv, MLX5E_PORT_BUFFER_PFC,
740 	    priv->params_ethtool.hw_mtu, &pfc, NULL, NULL));
741 }
742 
743 static int
744 mlx5e_buf_size_handler(SYSCTL_HANDLER_ARGS)
745 {
746 	struct mlx5e_priv *priv;
747 	u32 buf_size[MLX5E_MAX_BUFFER];
748 	struct mlx5e_port_buffer port_buffer;
749 	int error, i;
750 
751 	priv = arg1;
752 	PRIV_LOCK(priv);
753 	error = -mlx5e_port_query_buffer(priv, &port_buffer);
754 	if (error != 0)
755 		goto done;
756 	for (i = 0; i < nitems(buf_size); i++)
757 		buf_size[i] = port_buffer.buffer[i].size;
758 	error = SYSCTL_OUT(req, buf_size, sizeof(buf_size));
759 	if (error != 0 || req->newptr == NULL)
760 		goto done;
761 	error = SYSCTL_IN(req, buf_size, sizeof(buf_size));
762 	if (error != 0)
763 		goto done;
764 	error = -mlx5e_port_manual_buffer_config(priv, MLX5E_PORT_BUFFER_SIZE,
765 	    priv->params_ethtool.hw_mtu, NULL, buf_size, NULL);
766 done:
767 	PRIV_UNLOCK(priv);
768 	return (error);
769 }
770 
771 static int
772 mlx5e_buf_prio_handler(SYSCTL_HANDLER_ARGS)
773 {
774 	struct mlx5e_priv *priv;
775 	struct mlx5_core_dev *mdev;
776 	u8 buffer[MLX5E_MAX_BUFFER];
777 	int error;
778 
779 	priv = arg1;
780 	mdev = priv->mdev;
781 	PRIV_LOCK(priv);
782 	error = -mlx5e_port_query_priority2buffer(mdev, buffer);
783 	if (error != 0)
784 		goto done;
785 	error = SYSCTL_OUT(req, buffer, MLX5E_MAX_BUFFER);
786 	if (error != 0 || req->newptr == NULL)
787 		goto done;
788 	error = SYSCTL_IN(req, buffer, MLX5E_MAX_BUFFER);
789 	if (error != 0)
790 		goto done;
791 	error = -mlx5e_port_manual_buffer_config(priv,
792 	    MLX5E_PORT_BUFFER_PRIO2BUFFER,
793 	    priv->params_ethtool.hw_mtu, NULL, NULL, buffer);
794 	if (error == 0)
795 		error = mlx5e_update_buf_lossy(priv);
796 done:
797 	PRIV_UNLOCK(priv);
798 	return (error);
799 }
800 
801 static int
802 mlx5e_cable_length_handler(SYSCTL_HANDLER_ARGS)
803 {
804 	struct mlx5e_priv *priv;
805 	u_int cable_len;
806 	int error;
807 
808 	priv = arg1;
809 	PRIV_LOCK(priv);
810 	cable_len = priv->dcbx.cable_len;
811 	error = sysctl_handle_int(oidp, &cable_len, 0, req);
812 	if (error == 0 && req->newptr != NULL &&
813 	    cable_len != priv->dcbx.cable_len) {
814 		error = -mlx5e_port_manual_buffer_config(priv,
815 		    MLX5E_PORT_BUFFER_CABLE_LEN, priv->params_ethtool.hw_mtu,
816 		    NULL, NULL, NULL);
817 		if (error == 0)
818 			priv->dcbx.cable_len = cable_len;
819 	}
820 	PRIV_UNLOCK(priv);
821 	return (error);
822 }
823 
824 #define	MLX5_PARAM_OFFSET(n)				\
825     __offsetof(struct mlx5e_priv, params_ethtool.n)
826 
827 static int
828 mlx5e_ethtool_handler(SYSCTL_HANDLER_ARGS)
829 {
830 	struct mlx5e_priv *priv = arg1;
831 	uint64_t value;
832 	int mode_modify;
833 	int was_opened;
834 	int error;
835 
836 	PRIV_LOCK(priv);
837 	value = priv->params_ethtool.arg[arg2];
838 	if (req != NULL) {
839 		error = sysctl_handle_64(oidp, &value, 0, req);
840 		if (error || req->newptr == NULL ||
841 		    value == priv->params_ethtool.arg[arg2])
842 			goto done;
843 
844 		/* assign new value */
845 		priv->params_ethtool.arg[arg2] = value;
846 	} else {
847 		error = 0;
848 	}
849 	/* check if device is gone */
850 	if (priv->gone) {
851 		error = ENXIO;
852 		goto done;
853 	}
854 	was_opened = test_bit(MLX5E_STATE_OPENED, &priv->state);
855 	mode_modify = MLX5_CAP_GEN(priv->mdev, cq_period_mode_modify);
856 
857 	switch (MLX5_PARAM_OFFSET(arg[arg2])) {
858 	case MLX5_PARAM_OFFSET(rx_coalesce_usecs):
859 		/* import RX coal time */
860 		if (priv->params_ethtool.rx_coalesce_usecs < 1)
861 			priv->params_ethtool.rx_coalesce_usecs = 0;
862 		else if (priv->params_ethtool.rx_coalesce_usecs >
863 		    MLX5E_FLD_MAX(cqc, cq_period)) {
864 			priv->params_ethtool.rx_coalesce_usecs =
865 			    MLX5E_FLD_MAX(cqc, cq_period);
866 		}
867 		priv->params.rx_cq_moderation_usec =
868 		    priv->params_ethtool.rx_coalesce_usecs;
869 
870 		/* check to avoid down and up the network interface */
871 		if (was_opened)
872 			error = mlx5e_refresh_channel_params(priv);
873 		break;
874 
875 	case MLX5_PARAM_OFFSET(rx_coalesce_pkts):
876 		/* import RX coal pkts */
877 		if (priv->params_ethtool.rx_coalesce_pkts < 1)
878 			priv->params_ethtool.rx_coalesce_pkts = 0;
879 		else if (priv->params_ethtool.rx_coalesce_pkts >
880 		    MLX5E_FLD_MAX(cqc, cq_max_count)) {
881 			priv->params_ethtool.rx_coalesce_pkts =
882 			    MLX5E_FLD_MAX(cqc, cq_max_count);
883 		}
884 		priv->params.rx_cq_moderation_pkts =
885 		    priv->params_ethtool.rx_coalesce_pkts;
886 
887 		/* check to avoid down and up the network interface */
888 		if (was_opened)
889 			error = mlx5e_refresh_channel_params(priv);
890 		break;
891 
892 	case MLX5_PARAM_OFFSET(tx_coalesce_usecs):
893 		/* import TX coal time */
894 		if (priv->params_ethtool.tx_coalesce_usecs < 1)
895 			priv->params_ethtool.tx_coalesce_usecs = 0;
896 		else if (priv->params_ethtool.tx_coalesce_usecs >
897 		    MLX5E_FLD_MAX(cqc, cq_period)) {
898 			priv->params_ethtool.tx_coalesce_usecs =
899 			    MLX5E_FLD_MAX(cqc, cq_period);
900 		}
901 		priv->params.tx_cq_moderation_usec =
902 		    priv->params_ethtool.tx_coalesce_usecs;
903 
904 		/* check to avoid down and up the network interface */
905 		if (was_opened)
906 			error = mlx5e_refresh_channel_params(priv);
907 		break;
908 
909 	case MLX5_PARAM_OFFSET(tx_coalesce_pkts):
910 		/* import TX coal pkts */
911 		if (priv->params_ethtool.tx_coalesce_pkts < 1)
912 			priv->params_ethtool.tx_coalesce_pkts = 0;
913 		else if (priv->params_ethtool.tx_coalesce_pkts >
914 		    MLX5E_FLD_MAX(cqc, cq_max_count)) {
915 			priv->params_ethtool.tx_coalesce_pkts =
916 			    MLX5E_FLD_MAX(cqc, cq_max_count);
917 		}
918 		priv->params.tx_cq_moderation_pkts =
919 		    priv->params_ethtool.tx_coalesce_pkts;
920 
921 		/* check to avoid down and up the network interface */
922 		if (was_opened)
923 			error = mlx5e_refresh_channel_params(priv);
924 		break;
925 
926 	case MLX5_PARAM_OFFSET(tx_queue_size):
927 		/* network interface must be down */
928 		if (was_opened)
929 			mlx5e_close_locked(priv->ifp);
930 
931 		/* import TX queue size */
932 		if (priv->params_ethtool.tx_queue_size <
933 		    (1 << MLX5E_PARAMS_MINIMUM_LOG_SQ_SIZE)) {
934 			priv->params_ethtool.tx_queue_size =
935 			    (1 << MLX5E_PARAMS_MINIMUM_LOG_SQ_SIZE);
936 		} else if (priv->params_ethtool.tx_queue_size >
937 		    priv->params_ethtool.tx_queue_size_max) {
938 			priv->params_ethtool.tx_queue_size =
939 			    priv->params_ethtool.tx_queue_size_max;
940 		}
941 		/* store actual TX queue size */
942 		priv->params.log_sq_size =
943 		    order_base_2(priv->params_ethtool.tx_queue_size);
944 		priv->params_ethtool.tx_queue_size =
945 		    1 << priv->params.log_sq_size;
946 
947 		/* verify TX completion factor */
948 		mlx5e_ethtool_sync_tx_completion_fact(priv);
949 
950 		/* restart network interface, if any */
951 		if (was_opened)
952 			mlx5e_open_locked(priv->ifp);
953 		break;
954 
955 	case MLX5_PARAM_OFFSET(rx_queue_size):
956 		/* network interface must be down */
957 		if (was_opened)
958 			mlx5e_close_locked(priv->ifp);
959 
960 		/* import RX queue size */
961 		if (priv->params_ethtool.rx_queue_size <
962 		    (1 << MLX5E_PARAMS_MINIMUM_LOG_RQ_SIZE)) {
963 			priv->params_ethtool.rx_queue_size =
964 			    (1 << MLX5E_PARAMS_MINIMUM_LOG_RQ_SIZE);
965 		} else if (priv->params_ethtool.rx_queue_size >
966 		    priv->params_ethtool.rx_queue_size_max) {
967 			priv->params_ethtool.rx_queue_size =
968 			    priv->params_ethtool.rx_queue_size_max;
969 		}
970 		/* store actual RX queue size */
971 		priv->params.log_rq_size =
972 		    order_base_2(priv->params_ethtool.rx_queue_size);
973 		priv->params_ethtool.rx_queue_size =
974 		    1 << priv->params.log_rq_size;
975 
976 		/* update least number of RX WQEs */
977 		priv->params.min_rx_wqes = min(
978 		    priv->params_ethtool.rx_queue_size - 1,
979 		    MLX5E_PARAMS_DEFAULT_MIN_RX_WQES);
980 
981 		/* restart network interface, if any */
982 		if (was_opened)
983 			mlx5e_open_locked(priv->ifp);
984 		break;
985 
986 	case MLX5_PARAM_OFFSET(channels_rsss):
987 		/* network interface must be down */
988 		if (was_opened)
989 			mlx5e_close_locked(priv->ifp);
990 
991 		/* import number of channels */
992 		if (priv->params_ethtool.channels_rsss < 1)
993 			priv->params_ethtool.channels_rsss = 1;
994 		else if (priv->params_ethtool.channels_rsss > 128)
995 			priv->params_ethtool.channels_rsss = 128;
996 
997 		priv->params.channels_rsss = priv->params_ethtool.channels_rsss;
998 
999 		/* restart network interface, if any */
1000 		if (was_opened)
1001 			mlx5e_open_locked(priv->ifp);
1002 		break;
1003 
1004 	case MLX5_PARAM_OFFSET(channels):
1005 		/* network interface must be down */
1006 		if (was_opened)
1007 			mlx5e_close_locked(priv->ifp);
1008 
1009 		/* import number of channels */
1010 		if (priv->params_ethtool.channels < 1)
1011 			priv->params_ethtool.channels = 1;
1012 		else if (priv->params_ethtool.channels >
1013 		    (u64) priv->mdev->priv.eq_table.num_comp_vectors) {
1014 			priv->params_ethtool.channels =
1015 			    (u64) priv->mdev->priv.eq_table.num_comp_vectors;
1016 		}
1017 		priv->params.num_channels = priv->params_ethtool.channels;
1018 
1019 		/* restart network interface, if any */
1020 		if (was_opened)
1021 			mlx5e_open_locked(priv->ifp);
1022 		break;
1023 
1024 	case MLX5_PARAM_OFFSET(rx_coalesce_mode):
1025 		/* network interface must be down */
1026 		if (was_opened != 0 && mode_modify == 0)
1027 			mlx5e_close_locked(priv->ifp);
1028 
1029 		/* import RX coalesce mode */
1030 		if (priv->params_ethtool.rx_coalesce_mode > 3)
1031 			priv->params_ethtool.rx_coalesce_mode = 3;
1032 		priv->params.rx_cq_moderation_mode =
1033 		    priv->params_ethtool.rx_coalesce_mode;
1034 
1035 		/* restart network interface, if any */
1036 		if (was_opened != 0) {
1037 			if (mode_modify == 0)
1038 				mlx5e_open_locked(priv->ifp);
1039 			else
1040 				error = mlx5e_refresh_channel_params(priv);
1041 		}
1042 		break;
1043 
1044 	case MLX5_PARAM_OFFSET(tx_coalesce_mode):
1045 		/* network interface must be down */
1046 		if (was_opened != 0 && mode_modify == 0)
1047 			mlx5e_close_locked(priv->ifp);
1048 
1049 		/* import TX coalesce mode */
1050 		if (priv->params_ethtool.tx_coalesce_mode != 0)
1051 			priv->params_ethtool.tx_coalesce_mode = 1;
1052 		priv->params.tx_cq_moderation_mode =
1053 		    priv->params_ethtool.tx_coalesce_mode;
1054 
1055 		/* restart network interface, if any */
1056 		if (was_opened != 0) {
1057 			if (mode_modify == 0)
1058 				mlx5e_open_locked(priv->ifp);
1059 			else
1060 				error = mlx5e_refresh_channel_params(priv);
1061 		}
1062 		break;
1063 
1064 	case MLX5_PARAM_OFFSET(hw_lro):
1065 		/* network interface must be down */
1066 		if (was_opened)
1067 			mlx5e_close_locked(priv->ifp);
1068 
1069 		/* import HW LRO mode */
1070 		if (priv->params_ethtool.hw_lro != 0 &&
1071 		    MLX5_CAP_ETH(priv->mdev, lro_cap)) {
1072 			priv->params_ethtool.hw_lro = 1;
1073 			/* check if feature should actually be enabled */
1074 			if (priv->ifp->if_capenable & IFCAP_LRO) {
1075 				priv->params.hw_lro_en = true;
1076 			} else {
1077 				priv->params.hw_lro_en = false;
1078 
1079 				mlx5_en_warn(priv->ifp, "To enable HW LRO "
1080 				    "please also enable LRO via ifconfig(8).\n");
1081 			}
1082 		} else {
1083 			/* return an error if HW does not support this feature */
1084 			if (priv->params_ethtool.hw_lro != 0)
1085 				error = EINVAL;
1086 			priv->params.hw_lro_en = false;
1087 			priv->params_ethtool.hw_lro = 0;
1088 		}
1089 		/* restart network interface, if any */
1090 		if (was_opened)
1091 			mlx5e_open_locked(priv->ifp);
1092 		break;
1093 
1094 	case MLX5_PARAM_OFFSET(cqe_zipping):
1095 		/* network interface must be down */
1096 		if (was_opened)
1097 			mlx5e_close_locked(priv->ifp);
1098 
1099 		/* import CQE zipping mode */
1100 		if (priv->params_ethtool.cqe_zipping &&
1101 		    MLX5_CAP_GEN(priv->mdev, cqe_compression)) {
1102 			priv->params.cqe_zipping_en = true;
1103 			priv->params_ethtool.cqe_zipping = 1;
1104 		} else {
1105 			priv->params.cqe_zipping_en = false;
1106 			priv->params_ethtool.cqe_zipping = 0;
1107 		}
1108 		/* restart network interface, if any */
1109 		if (was_opened)
1110 			mlx5e_open_locked(priv->ifp);
1111 		break;
1112 
1113 	case MLX5_PARAM_OFFSET(tx_completion_fact):
1114 		/* network interface must be down */
1115 		if (was_opened)
1116 			mlx5e_close_locked(priv->ifp);
1117 
1118 		/* verify parameter */
1119 		mlx5e_ethtool_sync_tx_completion_fact(priv);
1120 
1121 		/* restart network interface, if any */
1122 		if (was_opened)
1123 			mlx5e_open_locked(priv->ifp);
1124 		break;
1125 
1126 	case MLX5_PARAM_OFFSET(modify_tx_dma):
1127 		/* check if network interface is opened */
1128 		if (was_opened) {
1129 			priv->params_ethtool.modify_tx_dma =
1130 			    priv->params_ethtool.modify_tx_dma ? 1 : 0;
1131 			/* modify tx according to value */
1132 			mlx5e_modify_tx_dma(priv, value != 0);
1133 		} else {
1134 			/* if closed force enable tx */
1135 			priv->params_ethtool.modify_tx_dma = 0;
1136 		}
1137 		break;
1138 
1139 	case MLX5_PARAM_OFFSET(modify_rx_dma):
1140 		/* check if network interface is opened */
1141 		if (was_opened) {
1142 			priv->params_ethtool.modify_rx_dma =
1143 			    priv->params_ethtool.modify_rx_dma ? 1 : 0;
1144 			/* modify rx according to value */
1145 			mlx5e_modify_rx_dma(priv, value != 0);
1146 		} else {
1147 			/* if closed force enable rx */
1148 			priv->params_ethtool.modify_rx_dma = 0;
1149 		}
1150 		break;
1151 
1152 	case MLX5_PARAM_OFFSET(diag_pci_enable):
1153 		priv->params_ethtool.diag_pci_enable =
1154 		    priv->params_ethtool.diag_pci_enable ? 1 : 0;
1155 
1156 		error = -mlx5_core_set_diagnostics_full(priv->mdev,
1157 		    priv->params_ethtool.diag_pci_enable,
1158 		    priv->params_ethtool.diag_general_enable);
1159 		break;
1160 
1161 	case MLX5_PARAM_OFFSET(diag_general_enable):
1162 		priv->params_ethtool.diag_general_enable =
1163 		    priv->params_ethtool.diag_general_enable ? 1 : 0;
1164 
1165 		error = -mlx5_core_set_diagnostics_full(priv->mdev,
1166 		    priv->params_ethtool.diag_pci_enable,
1167 		    priv->params_ethtool.diag_general_enable);
1168 		break;
1169 
1170 	case MLX5_PARAM_OFFSET(mc_local_lb):
1171 		priv->params_ethtool.mc_local_lb =
1172 		    priv->params_ethtool.mc_local_lb ? 1 : 0;
1173 
1174 		if (MLX5_CAP_GEN(priv->mdev, disable_local_lb)) {
1175 			error = mlx5_nic_vport_modify_local_lb(priv->mdev,
1176 			    MLX5_LOCAL_MC_LB, priv->params_ethtool.mc_local_lb);
1177 		} else {
1178 			error = EOPNOTSUPP;
1179 		}
1180 		break;
1181 
1182 	case MLX5_PARAM_OFFSET(uc_local_lb):
1183 		priv->params_ethtool.uc_local_lb =
1184 		    priv->params_ethtool.uc_local_lb ? 1 : 0;
1185 
1186 		if (MLX5_CAP_GEN(priv->mdev, disable_local_lb)) {
1187 			error = mlx5_nic_vport_modify_local_lb(priv->mdev,
1188 			    MLX5_LOCAL_UC_LB, priv->params_ethtool.uc_local_lb);
1189 		} else {
1190 			error = EOPNOTSUPP;
1191 		}
1192 		break;
1193 
1194 	default:
1195 		break;
1196 	}
1197 done:
1198 	PRIV_UNLOCK(priv);
1199 	return (error);
1200 }
1201 
1202 static const char *mlx5e_params_desc[] = {
1203 	MLX5E_PARAMS(MLX5E_STATS_DESC)
1204 };
1205 
1206 static const char *mlx5e_port_stats_debug_desc[] = {
1207 	MLX5E_PORT_STATS_DEBUG(MLX5E_STATS_DESC)
1208 };
1209 
1210 static int
1211 mlx5e_ethtool_debug_channel_info(SYSCTL_HANDLER_ARGS)
1212 {
1213 	struct mlx5e_priv *priv;
1214 	struct sbuf sb;
1215 	struct mlx5e_channel *c;
1216 	struct mlx5e_sq *sq;
1217 	struct mlx5e_rq *rq;
1218 	int error, i, tc;
1219 	bool opened;
1220 
1221 	priv = arg1;
1222 	error = sysctl_wire_old_buffer(req, 0);
1223 	if (error != 0)
1224 		return (error);
1225 	if (sbuf_new_for_sysctl(&sb, NULL, 1024, req) == NULL)
1226 		return (ENOMEM);
1227 	sbuf_clear_flags(&sb, SBUF_INCLUDENUL);
1228 
1229 	PRIV_LOCK(priv);
1230 	opened = test_bit(MLX5E_STATE_OPENED, &priv->state);
1231 
1232 	sbuf_printf(&sb, "pages irq %d\n",
1233 	    priv->mdev->priv.msix_arr[MLX5_EQ_VEC_PAGES].vector);
1234 	sbuf_printf(&sb, "command irq %d\n",
1235 	    priv->mdev->priv.msix_arr[MLX5_EQ_VEC_CMD].vector);
1236 	sbuf_printf(&sb, "async irq %d\n",
1237 	    priv->mdev->priv.msix_arr[MLX5_EQ_VEC_ASYNC].vector);
1238 
1239 	for (i = 0; i != priv->params.num_channels; i++) {
1240 		int eqn_not_used = -1;
1241 		int irqn = MLX5_EQ_VEC_COMP_BASE;
1242 
1243 		if (mlx5_vector2eqn(priv->mdev, i, &eqn_not_used, &irqn) != 0)
1244 			continue;
1245 
1246 		c = opened ? &priv->channel[i] : NULL;
1247 		rq = opened ? &c->rq : NULL;
1248 		sbuf_printf(&sb, "channel %d rq %d cq %d irq %d\n", i,
1249 		    opened ? rq->rqn : -1,
1250 		    opened ? rq->cq.mcq.cqn : -1,
1251 		    priv->mdev->priv.msix_arr[irqn].vector);
1252 
1253 		for (tc = 0; tc != priv->num_tc; tc++) {
1254 			sq = opened ? &c->sq[tc] : NULL;
1255 			sbuf_printf(&sb, "channel %d tc %d sq %d cq %d irq %d\n",
1256 			    i, tc,
1257 			    opened ? sq->sqn : -1,
1258 			    opened ? sq->cq.mcq.cqn : -1,
1259 			    priv->mdev->priv.msix_arr[irqn].vector);
1260 		}
1261 	}
1262 	PRIV_UNLOCK(priv);
1263 	error = sbuf_finish(&sb);
1264 	sbuf_delete(&sb);
1265 	return (error);
1266 }
1267 
1268 static int
1269 mlx5e_ethtool_debug_stats(SYSCTL_HANDLER_ARGS)
1270 {
1271 	struct mlx5e_priv *priv = arg1;
1272 	int sys_debug;
1273 	int error;
1274 
1275 	PRIV_LOCK(priv);
1276 	if (priv->gone != 0) {
1277 		error = ENODEV;
1278 		goto done;
1279 	}
1280 	sys_debug = priv->sysctl_debug;
1281 	error = sysctl_handle_int(oidp, &sys_debug, 0, req);
1282 	if (error != 0 || !req->newptr)
1283 		goto done;
1284 	sys_debug = sys_debug ? 1 : 0;
1285 	if (sys_debug == priv->sysctl_debug)
1286 		goto done;
1287 
1288 	if ((priv->sysctl_debug = sys_debug)) {
1289 		mlx5e_create_stats(&priv->stats.port_stats_debug.ctx,
1290 		    SYSCTL_CHILDREN(priv->sysctl_ifnet), "debug_stats",
1291 		    mlx5e_port_stats_debug_desc, MLX5E_PORT_STATS_DEBUG_NUM,
1292 		    priv->stats.port_stats_debug.arg);
1293 		SYSCTL_ADD_PROC(&priv->stats.port_stats_debug.ctx,
1294 		    SYSCTL_CHILDREN(priv->sysctl_ifnet), OID_AUTO,
1295 		    "hw_ctx_debug",
1296 		    CTLFLAG_RD | CTLFLAG_MPSAFE | CTLTYPE_STRING, priv, 0,
1297 		    mlx5e_ethtool_debug_channel_info, "S", "");
1298 	} else {
1299 		sysctl_ctx_free(&priv->stats.port_stats_debug.ctx);
1300 	}
1301 done:
1302 	PRIV_UNLOCK(priv);
1303 	return (error);
1304 }
1305 
1306 static void
1307 mlx5e_create_diagnostics(struct mlx5e_priv *priv)
1308 {
1309 	struct mlx5_core_diagnostics_entry entry;
1310 	struct sysctl_ctx_list *ctx;
1311 	struct sysctl_oid *node;
1312 	int x;
1313 
1314 	/* sysctl context we are using */
1315 	ctx = &priv->sysctl_ctx;
1316 
1317 	/* create root node */
1318 	node = SYSCTL_ADD_NODE(ctx,
1319 	    SYSCTL_CHILDREN(priv->sysctl_ifnet), OID_AUTO,
1320 	    "diagnostics", CTLFLAG_RD, NULL, "Diagnostics");
1321 	if (node == NULL)
1322 		return;
1323 
1324 	/* create PCI diagnostics */
1325 	for (x = 0; x != MLX5_CORE_PCI_DIAGNOSTICS_NUM; x++) {
1326 		entry = mlx5_core_pci_diagnostics_table[x];
1327 		if (mlx5_core_supports_diagnostics(priv->mdev, entry.counter_id) == 0)
1328 			continue;
1329 		SYSCTL_ADD_UQUAD(ctx, SYSCTL_CHILDREN(node), OID_AUTO,
1330 		    entry.desc, CTLFLAG_RD, priv->params_pci.array + x,
1331 		    "PCI diagnostics counter");
1332 	}
1333 
1334 	/* create general diagnostics */
1335 	for (x = 0; x != MLX5_CORE_GENERAL_DIAGNOSTICS_NUM; x++) {
1336 		entry = mlx5_core_general_diagnostics_table[x];
1337 		if (mlx5_core_supports_diagnostics(priv->mdev, entry.counter_id) == 0)
1338 			continue;
1339 		SYSCTL_ADD_UQUAD(ctx, SYSCTL_CHILDREN(node), OID_AUTO,
1340 		    entry.desc, CTLFLAG_RD, priv->params_general.array + x,
1341 		    "General diagnostics counter");
1342 	}
1343 }
1344 
1345 void
1346 mlx5e_create_ethtool(struct mlx5e_priv *priv)
1347 {
1348 	struct sysctl_oid *fec_node;
1349 	struct sysctl_oid *qos_node;
1350 	struct sysctl_oid *node;
1351 	const char *pnameunit;
1352 	struct mlx5e_port_buffer port_buffer;
1353 	unsigned x;
1354 	int i;
1355 
1356 	/* set some defaults */
1357 	priv->params_ethtool.tx_queue_size_max = 1 << MLX5E_PARAMS_MAXIMUM_LOG_SQ_SIZE;
1358 	priv->params_ethtool.rx_queue_size_max = 1 << MLX5E_PARAMS_MAXIMUM_LOG_RQ_SIZE;
1359 	priv->params_ethtool.tx_queue_size = 1 << priv->params.log_sq_size;
1360 	priv->params_ethtool.rx_queue_size = 1 << priv->params.log_rq_size;
1361 	priv->params_ethtool.channels = priv->params.num_channels;
1362 	priv->params_ethtool.channels_rsss = priv->params.channels_rsss;
1363 	priv->params_ethtool.coalesce_pkts_max = MLX5E_FLD_MAX(cqc, cq_max_count);
1364 	priv->params_ethtool.coalesce_usecs_max = MLX5E_FLD_MAX(cqc, cq_period);
1365 	priv->params_ethtool.rx_coalesce_mode = priv->params.rx_cq_moderation_mode;
1366 	priv->params_ethtool.rx_coalesce_usecs = priv->params.rx_cq_moderation_usec;
1367 	priv->params_ethtool.rx_coalesce_pkts = priv->params.rx_cq_moderation_pkts;
1368 	priv->params_ethtool.tx_coalesce_mode = priv->params.tx_cq_moderation_mode;
1369 	priv->params_ethtool.tx_coalesce_usecs = priv->params.tx_cq_moderation_usec;
1370 	priv->params_ethtool.tx_coalesce_pkts = priv->params.tx_cq_moderation_pkts;
1371 	priv->params_ethtool.hw_lro = priv->params.hw_lro_en;
1372 	priv->params_ethtool.cqe_zipping = priv->params.cqe_zipping_en;
1373 	mlx5e_ethtool_sync_tx_completion_fact(priv);
1374 
1375 	/* get default values for local loopback, if any */
1376 	if (MLX5_CAP_GEN(priv->mdev, disable_local_lb)) {
1377 		int err;
1378 		u8 val;
1379 
1380 		err = mlx5_nic_vport_query_local_lb(priv->mdev, MLX5_LOCAL_MC_LB, &val);
1381 		if (err == 0)
1382 			priv->params_ethtool.mc_local_lb = val;
1383 
1384 		err = mlx5_nic_vport_query_local_lb(priv->mdev, MLX5_LOCAL_UC_LB, &val);
1385 		if (err == 0)
1386 			priv->params_ethtool.uc_local_lb = val;
1387 	}
1388 
1389 	/* create root node */
1390 	node = SYSCTL_ADD_NODE(&priv->sysctl_ctx,
1391 	    SYSCTL_CHILDREN(priv->sysctl_ifnet), OID_AUTO,
1392 	    "conf", CTLFLAG_RW, NULL, "Configuration");
1393 	if (node == NULL)
1394 		return;
1395 	for (x = 0; x != MLX5E_PARAMS_NUM; x++) {
1396 		/* check for read-only parameter */
1397 		if (strstr(mlx5e_params_desc[2 * x], "_max") != NULL ||
1398 		    strstr(mlx5e_params_desc[2 * x], "_mtu") != NULL) {
1399 			SYSCTL_ADD_PROC(&priv->sysctl_ctx, SYSCTL_CHILDREN(node), OID_AUTO,
1400 			    mlx5e_params_desc[2 * x], CTLTYPE_U64 | CTLFLAG_RD |
1401 			    CTLFLAG_MPSAFE, priv, x, &mlx5e_ethtool_handler, "QU",
1402 			    mlx5e_params_desc[2 * x + 1]);
1403 		} else {
1404 #if (__FreeBSD_version < 1100000)
1405 			char path[64];
1406 #endif
1407 			/*
1408 			 * NOTE: In FreeBSD-11 and newer the
1409 			 * CTLFLAG_RWTUN flag will take care of
1410 			 * loading default sysctl value from the
1411 			 * kernel environment, if any:
1412 			 */
1413 			SYSCTL_ADD_PROC(&priv->sysctl_ctx, SYSCTL_CHILDREN(node), OID_AUTO,
1414 			    mlx5e_params_desc[2 * x], CTLTYPE_U64 | CTLFLAG_RWTUN |
1415 			    CTLFLAG_MPSAFE, priv, x, &mlx5e_ethtool_handler, "QU",
1416 			    mlx5e_params_desc[2 * x + 1]);
1417 
1418 #if (__FreeBSD_version < 1100000)
1419 			/* compute path for sysctl */
1420 			snprintf(path, sizeof(path), "dev.mce.%d.conf.%s",
1421 			    device_get_unit(priv->mdev->pdev->dev.bsddev),
1422 			    mlx5e_params_desc[2 * x]);
1423 
1424 			/* try to fetch tunable, if any */
1425 			if (TUNABLE_QUAD_FETCH(path, &priv->params_ethtool.arg[x]))
1426 				mlx5e_ethtool_handler(NULL, priv, x, NULL);
1427 #endif
1428 		}
1429 	}
1430 
1431 	/* create fec node */
1432 	fec_node = SYSCTL_ADD_NODE(&priv->sysctl_ctx,
1433 	    SYSCTL_CHILDREN(node), OID_AUTO,
1434 	    "fec", CTLFLAG_RW, NULL, "Forward Error Correction");
1435 	if (fec_node == NULL)
1436 		return;
1437 
1438 	if (mlx5e_fec_update(priv) == 0) {
1439 		SYSCTL_ADD_U32(&priv->sysctl_ctx, SYSCTL_CHILDREN(fec_node), OID_AUTO,
1440 		    "mode_active", CTLFLAG_RD | CTLFLAG_MPSAFE,
1441 		    &priv->params_ethtool.fec_mode_active, 0,
1442 		    "Current FEC mode bit, if any.");
1443 
1444 		SYSCTL_ADD_PROC(&priv->sysctl_ctx, SYSCTL_CHILDREN(fec_node), OID_AUTO,
1445 		    "mask_10x_25x", CTLTYPE_U8 | CTLFLAG_RWTUN | CTLFLAG_MPSAFE,
1446 		    priv, 0, &mlx5e_fec_mask_10x_25x_handler, "CU",
1447 		    "Set FEC masks for 10G_40G, 25G_50G, 56G, 100G respectivly. "
1448 		    "0:Auto "
1449 		    "1:NOFEC "
1450 		    "2:FIRECODE "
1451 		    "4:RS");
1452 
1453 		SYSCTL_ADD_PROC(&priv->sysctl_ctx, SYSCTL_CHILDREN(fec_node), OID_AUTO,
1454 		    "avail_10x_25x", CTLTYPE_U8 | CTLFLAG_RD | CTLFLAG_MPSAFE,
1455 		    priv, 0, &mlx5e_fec_avail_10x_25x_handler, "CU",
1456 		    "Get available FEC bits for 10G_40G, 25G_50G, 56G, 100G respectivly. "
1457 		    "0:Auto "
1458 		    "1:NOFEC "
1459 		    "2:FIRECODE "
1460 		    "4:RS");
1461 
1462 		SYSCTL_ADD_PROC(&priv->sysctl_ctx, SYSCTL_CHILDREN(fec_node), OID_AUTO,
1463 		    "mask_50x", CTLTYPE_U16 | CTLFLAG_RWTUN | CTLFLAG_MPSAFE,
1464 		    priv, 0, &mlx5e_fec_mask_50x_handler, "SU",
1465 		    "Set FEC masks for 50G 1x, 100G 2x, 200G 4x, 400G 8x respectivly. "
1466 		    "0:Auto "
1467 		    "128:RS "
1468 		    "512:LL RS");
1469 
1470 		SYSCTL_ADD_PROC(&priv->sysctl_ctx, SYSCTL_CHILDREN(fec_node), OID_AUTO,
1471 		    "avail_50x", CTLTYPE_U16 | CTLFLAG_RD | CTLFLAG_MPSAFE,
1472 		    priv, 0, &mlx5e_fec_avail_50x_handler, "SU",
1473 		    "Get available FEC bits for 50G 1x, 100G 2x, 200G 4x, 400G 8x respectivly. "
1474 		    "0:Auto "
1475 		    "128:RS "
1476 		    "512:LL RS");
1477 	}
1478 
1479 	SYSCTL_ADD_PROC(&priv->sysctl_ctx, SYSCTL_CHILDREN(node), OID_AUTO,
1480 	    "debug_stats", CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, priv,
1481 	    0, &mlx5e_ethtool_debug_stats, "I", "Extended debug statistics");
1482 
1483 	pnameunit = device_get_nameunit(priv->mdev->pdev->dev.bsddev);
1484 
1485 	SYSCTL_ADD_STRING(&priv->sysctl_ctx, SYSCTL_CHILDREN(node),
1486 	    OID_AUTO, "device_name", CTLFLAG_RD,
1487 	    __DECONST(void *, pnameunit), 0,
1488 	    "PCI device name");
1489 
1490 	/* Diagnostics support */
1491 	mlx5e_create_diagnostics(priv);
1492 
1493 	/* create qos node */
1494 	qos_node = SYSCTL_ADD_NODE(&priv->sysctl_ctx,
1495 	    SYSCTL_CHILDREN(node), OID_AUTO,
1496 	    "qos", CTLFLAG_RW, NULL, "Quality Of Service configuration");
1497 	if (qos_node == NULL)
1498 		return;
1499 
1500 	/* Priority rate limit support */
1501 	if (mlx5e_getmaxrate(priv) == 0) {
1502 		SYSCTL_ADD_PROC(&priv->sysctl_ctx, SYSCTL_CHILDREN(qos_node),
1503 		    OID_AUTO, "tc_max_rate", CTLTYPE_U64 | CTLFLAG_RWTUN | CTLFLAG_MPSAFE,
1504 		    priv, 0, mlx5e_tc_maxrate_handler, "QU",
1505 		    "Max rate for priority, specified in kilobits, where kilo=1000, "
1506 		    "max_rate must be divisible by 100000");
1507 	}
1508 
1509 	/* Bandwidth limiting by ratio */
1510 	if (mlx5e_get_max_alloc(priv) == 0) {
1511 		SYSCTL_ADD_PROC(&priv->sysctl_ctx, SYSCTL_CHILDREN(qos_node),
1512 		    OID_AUTO, "tc_rate_share", CTLTYPE_U8 | CTLFLAG_RWTUN | CTLFLAG_MPSAFE,
1513 		    priv, 0, mlx5e_tc_rate_share_handler, "QU",
1514 		    "Specify bandwidth ratio from 1 to 100 "
1515 		    "for the available traffic classes");
1516 	}
1517 
1518 	/* Priority to traffic class mapping */
1519 	if (mlx5e_get_prio_tc(priv) == 0) {
1520 		SYSCTL_ADD_PROC(&priv->sysctl_ctx, SYSCTL_CHILDREN(qos_node),
1521 		    OID_AUTO, "prio_0_7_tc", CTLTYPE_U8 | CTLFLAG_RWTUN | CTLFLAG_MPSAFE,
1522 		    priv, 0, mlx5e_prio_to_tc_handler, "CU",
1523 		    "Set traffic class 0 to 7 for priority 0 to 7 inclusivly");
1524 	}
1525 
1526 	/* DSCP support */
1527 	if (mlx5e_get_dscp(priv) == 0) {
1528 		for (i = 0; i != MLX5_MAX_SUPPORTED_DSCP; i += 8) {
1529 			char name[32];
1530 			snprintf(name, sizeof(name), "dscp_%d_%d_prio", i, i + 7);
1531 			SYSCTL_ADD_PROC(&priv->sysctl_ctx, SYSCTL_CHILDREN(qos_node),
1532 				OID_AUTO, name, CTLTYPE_U8 | CTLFLAG_RWTUN | CTLFLAG_MPSAFE,
1533 				priv, i, mlx5e_dscp_prio_handler, "CU",
1534 				"Set DSCP to priority mapping, 0..7");
1535 		}
1536 #define	A	"Set trust state, 1:PCP 2:DSCP"
1537 #define	B	" 3:BOTH"
1538 		SYSCTL_ADD_PROC(&priv->sysctl_ctx, SYSCTL_CHILDREN(qos_node),
1539 		    OID_AUTO, "trust_state", CTLTYPE_U8 | CTLFLAG_RWTUN | CTLFLAG_MPSAFE,
1540 		    priv, 0, mlx5e_trust_state_handler, "CU",
1541 		    MLX5_CAP_QCAM_FEATURE(priv->mdev, qpts_trust_both) ?
1542 		    A B : A);
1543 #undef B
1544 #undef A
1545 	}
1546 
1547 	if (mlx5e_port_query_buffer(priv, &port_buffer) == 0) {
1548 		SYSCTL_ADD_PROC(&priv->sysctl_ctx, SYSCTL_CHILDREN(qos_node),
1549 		    OID_AUTO, "buffers_size",
1550 		    CTLTYPE_U32 | CTLFLAG_RWTUN | CTLFLAG_MPSAFE,
1551 		    priv, 0, mlx5e_buf_size_handler, "IU",
1552 		    "Set buffers sizes");
1553 		SYSCTL_ADD_PROC(&priv->sysctl_ctx, SYSCTL_CHILDREN(qos_node),
1554 		    OID_AUTO, "buffers_prio",
1555 		    CTLTYPE_U8 | CTLFLAG_RWTUN | CTLFLAG_MPSAFE,
1556 		    priv, 0, mlx5e_buf_prio_handler, "CU",
1557 		    "Set prio to buffers mapping");
1558 		SYSCTL_ADD_PROC(&priv->sysctl_ctx, SYSCTL_CHILDREN(qos_node),
1559 		    OID_AUTO, "cable_length",
1560 		    CTLTYPE_UINT | CTLFLAG_RWTUN | CTLFLAG_MPSAFE,
1561 		    priv, 0, mlx5e_cable_length_handler, "IU",
1562 		    "Set cable length in meters for xoff threshold calculation");
1563 	}
1564 }
1565