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