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