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