xref: /freebsd/sys/dev/mlx5/mlx5_en/mlx5_en_ethtool.c (revision 048ddb58bc5eeedba578dace633efbf1c6c2864a)
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 static int
350 mlx5e_trust_state_handler(SYSCTL_HANDLER_ARGS)
351 {
352 	struct mlx5e_priv *priv = arg1;
353 	struct mlx5_core_dev *mdev = priv->mdev;
354 	int err;
355 	u8 result;
356 
357 	PRIV_LOCK(priv);
358 	result = priv->params_ethtool.trust_state;
359 	err = sysctl_handle_8(oidp, &result, 0, req);
360 	if (err || !req->newptr ||
361 	    result == priv->params_ethtool.trust_state)
362 		goto done;
363 
364 	switch (result) {
365 	case MLX5_QPTS_TRUST_PCP:
366 	case MLX5_QPTS_TRUST_DSCP:
367 		break;
368 	case MLX5_QPTS_TRUST_BOTH:
369 		if (!MLX5_CAP_QCAM_FEATURE(mdev, qpts_trust_both)) {
370 			err = EOPNOTSUPP;
371 			goto done;
372 		}
373 		break;
374 	default:
375 		err = ERANGE;
376 		goto done;
377 	}
378 
379 	err = -mlx5_set_trust_state(mdev, result);
380 	if (err)
381 		goto done;
382 
383 	priv->params_ethtool.trust_state = result;
384 
385 	/* update inline mode */
386 	mlx5e_refresh_sq_inline(priv);
387 #ifdef RATELIMIT
388 	mlx5e_rl_refresh_sq_inline(&priv->rl);
389 #endif
390 done:
391 	PRIV_UNLOCK(priv);
392 	return (err);
393 }
394 
395 static int
396 mlx5e_dscp_prio_handler(SYSCTL_HANDLER_ARGS)
397 {
398 	struct mlx5e_priv *priv = arg1;
399 	int prio_index = arg2;
400 	struct mlx5_core_dev *mdev = priv->mdev;
401 	uint8_t dscp2prio[MLX5_MAX_SUPPORTED_DSCP];
402 	uint8_t x;
403 	int err;
404 
405 	PRIV_LOCK(priv);
406 	err = SYSCTL_OUT(req, priv->params_ethtool.dscp2prio + prio_index,
407 	    sizeof(priv->params_ethtool.dscp2prio) / 8);
408 	if (err || !req->newptr)
409 		goto done;
410 
411 	memcpy(dscp2prio, priv->params_ethtool.dscp2prio, sizeof(dscp2prio));
412 	err = SYSCTL_IN(req, dscp2prio + prio_index, sizeof(dscp2prio) / 8);
413 	if (err)
414 		goto done;
415 	for (x = 0; x != MLX5_MAX_SUPPORTED_DSCP; x++) {
416 		if (dscp2prio[x] > 7) {
417 			err = ERANGE;
418 			goto done;
419 		}
420 	}
421 	err = -mlx5_set_dscp2prio(mdev, dscp2prio);
422 	if (err)
423 		goto done;
424 
425 	/* update local array */
426 	memcpy(priv->params_ethtool.dscp2prio, dscp2prio,
427 	    sizeof(priv->params_ethtool.dscp2prio));
428 done:
429 	PRIV_UNLOCK(priv);
430 	return (err);
431 }
432 
433 int
434 mlx5e_update_buf_lossy(struct mlx5e_priv *priv)
435 {
436 	struct ieee_pfc pfc;
437 
438 	PRIV_ASSERT_LOCKED(priv);
439 	bzero(&pfc, sizeof(pfc));
440 	pfc.pfc_en = priv->params.rx_priority_flow_control;
441 	return (-mlx5e_port_manual_buffer_config(priv, MLX5E_PORT_BUFFER_PFC,
442 	    priv->params_ethtool.hw_mtu, &pfc, NULL, NULL));
443 }
444 
445 static int
446 mlx5e_buf_size_handler(SYSCTL_HANDLER_ARGS)
447 {
448 	struct mlx5e_priv *priv;
449 	u32 buf_size[MLX5E_MAX_BUFFER];
450 	struct mlx5e_port_buffer port_buffer;
451 	int error, i;
452 
453 	priv = arg1;
454 	PRIV_LOCK(priv);
455 	error = -mlx5e_port_query_buffer(priv, &port_buffer);
456 	if (error != 0)
457 		goto done;
458 	for (i = 0; i < nitems(buf_size); i++)
459 		buf_size[i] = port_buffer.buffer[i].size;
460 	error = SYSCTL_OUT(req, buf_size, sizeof(buf_size));
461 	if (error != 0 || req->newptr == NULL)
462 		goto done;
463 	error = SYSCTL_IN(req, buf_size, sizeof(buf_size));
464 	if (error != 0)
465 		goto done;
466 	error = -mlx5e_port_manual_buffer_config(priv, MLX5E_PORT_BUFFER_SIZE,
467 	    priv->params_ethtool.hw_mtu, NULL, buf_size, NULL);
468 done:
469 	PRIV_UNLOCK(priv);
470 	return (error);
471 }
472 
473 static int
474 mlx5e_buf_prio_handler(SYSCTL_HANDLER_ARGS)
475 {
476 	struct mlx5e_priv *priv;
477 	struct mlx5_core_dev *mdev;
478 	u8 buffer[MLX5E_MAX_BUFFER];
479 	int error;
480 
481 	priv = arg1;
482 	mdev = priv->mdev;
483 	PRIV_LOCK(priv);
484 	error = -mlx5e_port_query_priority2buffer(mdev, buffer);
485 	if (error != 0)
486 		goto done;
487 	error = SYSCTL_OUT(req, buffer, MLX5E_MAX_BUFFER);
488 	if (error != 0 || req->newptr == NULL)
489 		goto done;
490 	error = SYSCTL_IN(req, buffer, MLX5E_MAX_BUFFER);
491 	if (error != 0)
492 		goto done;
493 	error = -mlx5e_port_manual_buffer_config(priv,
494 	    MLX5E_PORT_BUFFER_PRIO2BUFFER,
495 	    priv->params_ethtool.hw_mtu, NULL, NULL, buffer);
496 	if (error == 0)
497 		error = mlx5e_update_buf_lossy(priv);
498 done:
499 	PRIV_UNLOCK(priv);
500 	return (error);
501 }
502 
503 static int
504 mlx5e_cable_length_handler(SYSCTL_HANDLER_ARGS)
505 {
506 	struct mlx5e_priv *priv;
507 	u_int cable_len;
508 	int error;
509 
510 	priv = arg1;
511 	PRIV_LOCK(priv);
512 	cable_len = priv->dcbx.cable_len;
513 	error = sysctl_handle_int(oidp, &cable_len, 0, req);
514 	if (error == 0 && req->newptr != NULL &&
515 	    cable_len != priv->dcbx.cable_len) {
516 		error = -mlx5e_port_manual_buffer_config(priv,
517 		    MLX5E_PORT_BUFFER_CABLE_LEN, priv->params_ethtool.hw_mtu,
518 		    NULL, NULL, NULL);
519 		if (error == 0)
520 			priv->dcbx.cable_len = cable_len;
521 	}
522 	PRIV_UNLOCK(priv);
523 	return (error);
524 }
525 
526 #define	MLX5_PARAM_OFFSET(n)				\
527     __offsetof(struct mlx5e_priv, params_ethtool.n)
528 
529 static int
530 mlx5e_ethtool_handler(SYSCTL_HANDLER_ARGS)
531 {
532 	struct mlx5e_priv *priv = arg1;
533 	uint64_t value;
534 	int mode_modify;
535 	int was_opened;
536 	int error;
537 
538 	PRIV_LOCK(priv);
539 	value = priv->params_ethtool.arg[arg2];
540 	if (req != NULL) {
541 		error = sysctl_handle_64(oidp, &value, 0, req);
542 		if (error || req->newptr == NULL ||
543 		    value == priv->params_ethtool.arg[arg2])
544 			goto done;
545 
546 		/* assign new value */
547 		priv->params_ethtool.arg[arg2] = value;
548 	} else {
549 		error = 0;
550 	}
551 	/* check if device is gone */
552 	if (priv->gone) {
553 		error = ENXIO;
554 		goto done;
555 	}
556 	was_opened = test_bit(MLX5E_STATE_OPENED, &priv->state);
557 	mode_modify = MLX5_CAP_GEN(priv->mdev, cq_period_mode_modify);
558 
559 	switch (MLX5_PARAM_OFFSET(arg[arg2])) {
560 	case MLX5_PARAM_OFFSET(rx_coalesce_usecs):
561 		/* import RX coal time */
562 		if (priv->params_ethtool.rx_coalesce_usecs < 1)
563 			priv->params_ethtool.rx_coalesce_usecs = 0;
564 		else if (priv->params_ethtool.rx_coalesce_usecs >
565 		    MLX5E_FLD_MAX(cqc, cq_period)) {
566 			priv->params_ethtool.rx_coalesce_usecs =
567 			    MLX5E_FLD_MAX(cqc, cq_period);
568 		}
569 		priv->params.rx_cq_moderation_usec =
570 		    priv->params_ethtool.rx_coalesce_usecs;
571 
572 		/* check to avoid down and up the network interface */
573 		if (was_opened)
574 			error = mlx5e_refresh_channel_params(priv);
575 		break;
576 
577 	case MLX5_PARAM_OFFSET(rx_coalesce_pkts):
578 		/* import RX coal pkts */
579 		if (priv->params_ethtool.rx_coalesce_pkts < 1)
580 			priv->params_ethtool.rx_coalesce_pkts = 0;
581 		else if (priv->params_ethtool.rx_coalesce_pkts >
582 		    MLX5E_FLD_MAX(cqc, cq_max_count)) {
583 			priv->params_ethtool.rx_coalesce_pkts =
584 			    MLX5E_FLD_MAX(cqc, cq_max_count);
585 		}
586 		priv->params.rx_cq_moderation_pkts =
587 		    priv->params_ethtool.rx_coalesce_pkts;
588 
589 		/* check to avoid down and up the network interface */
590 		if (was_opened)
591 			error = mlx5e_refresh_channel_params(priv);
592 		break;
593 
594 	case MLX5_PARAM_OFFSET(tx_coalesce_usecs):
595 		/* import TX coal time */
596 		if (priv->params_ethtool.tx_coalesce_usecs < 1)
597 			priv->params_ethtool.tx_coalesce_usecs = 0;
598 		else if (priv->params_ethtool.tx_coalesce_usecs >
599 		    MLX5E_FLD_MAX(cqc, cq_period)) {
600 			priv->params_ethtool.tx_coalesce_usecs =
601 			    MLX5E_FLD_MAX(cqc, cq_period);
602 		}
603 		priv->params.tx_cq_moderation_usec =
604 		    priv->params_ethtool.tx_coalesce_usecs;
605 
606 		/* check to avoid down and up the network interface */
607 		if (was_opened)
608 			error = mlx5e_refresh_channel_params(priv);
609 		break;
610 
611 	case MLX5_PARAM_OFFSET(tx_coalesce_pkts):
612 		/* import TX coal pkts */
613 		if (priv->params_ethtool.tx_coalesce_pkts < 1)
614 			priv->params_ethtool.tx_coalesce_pkts = 0;
615 		else if (priv->params_ethtool.tx_coalesce_pkts >
616 		    MLX5E_FLD_MAX(cqc, cq_max_count)) {
617 			priv->params_ethtool.tx_coalesce_pkts =
618 			    MLX5E_FLD_MAX(cqc, cq_max_count);
619 		}
620 		priv->params.tx_cq_moderation_pkts =
621 		    priv->params_ethtool.tx_coalesce_pkts;
622 
623 		/* check to avoid down and up the network interface */
624 		if (was_opened)
625 			error = mlx5e_refresh_channel_params(priv);
626 		break;
627 
628 	case MLX5_PARAM_OFFSET(tx_queue_size):
629 		/* network interface must be down */
630 		if (was_opened)
631 			mlx5e_close_locked(priv->ifp);
632 
633 		/* import TX queue size */
634 		if (priv->params_ethtool.tx_queue_size <
635 		    (1 << MLX5E_PARAMS_MINIMUM_LOG_SQ_SIZE)) {
636 			priv->params_ethtool.tx_queue_size =
637 			    (1 << MLX5E_PARAMS_MINIMUM_LOG_SQ_SIZE);
638 		} else if (priv->params_ethtool.tx_queue_size >
639 		    priv->params_ethtool.tx_queue_size_max) {
640 			priv->params_ethtool.tx_queue_size =
641 			    priv->params_ethtool.tx_queue_size_max;
642 		}
643 		/* store actual TX queue size */
644 		priv->params.log_sq_size =
645 		    order_base_2(priv->params_ethtool.tx_queue_size);
646 		priv->params_ethtool.tx_queue_size =
647 		    1 << priv->params.log_sq_size;
648 
649 		/* verify TX completion factor */
650 		mlx5e_ethtool_sync_tx_completion_fact(priv);
651 
652 		/* restart network interface, if any */
653 		if (was_opened)
654 			mlx5e_open_locked(priv->ifp);
655 		break;
656 
657 	case MLX5_PARAM_OFFSET(rx_queue_size):
658 		/* network interface must be down */
659 		if (was_opened)
660 			mlx5e_close_locked(priv->ifp);
661 
662 		/* import RX queue size */
663 		if (priv->params_ethtool.rx_queue_size <
664 		    (1 << MLX5E_PARAMS_MINIMUM_LOG_RQ_SIZE)) {
665 			priv->params_ethtool.rx_queue_size =
666 			    (1 << MLX5E_PARAMS_MINIMUM_LOG_RQ_SIZE);
667 		} else if (priv->params_ethtool.rx_queue_size >
668 		    priv->params_ethtool.rx_queue_size_max) {
669 			priv->params_ethtool.rx_queue_size =
670 			    priv->params_ethtool.rx_queue_size_max;
671 		}
672 		/* store actual RX queue size */
673 		priv->params.log_rq_size =
674 		    order_base_2(priv->params_ethtool.rx_queue_size);
675 		priv->params_ethtool.rx_queue_size =
676 		    1 << priv->params.log_rq_size;
677 
678 		/* update least number of RX WQEs */
679 		priv->params.min_rx_wqes = min(
680 		    priv->params_ethtool.rx_queue_size - 1,
681 		    MLX5E_PARAMS_DEFAULT_MIN_RX_WQES);
682 
683 		/* restart network interface, if any */
684 		if (was_opened)
685 			mlx5e_open_locked(priv->ifp);
686 		break;
687 
688 	case MLX5_PARAM_OFFSET(channels_rsss):
689 		/* network interface must be down */
690 		if (was_opened)
691 			mlx5e_close_locked(priv->ifp);
692 
693 		/* import number of channels */
694 		if (priv->params_ethtool.channels_rsss < 1)
695 			priv->params_ethtool.channels_rsss = 1;
696 		else if (priv->params_ethtool.channels_rsss > 128)
697 			priv->params_ethtool.channels_rsss = 128;
698 
699 		priv->params.channels_rsss = priv->params_ethtool.channels_rsss;
700 
701 		/* restart network interface, if any */
702 		if (was_opened)
703 			mlx5e_open_locked(priv->ifp);
704 		break;
705 
706 	case MLX5_PARAM_OFFSET(channels):
707 		/* network interface must be down */
708 		if (was_opened)
709 			mlx5e_close_locked(priv->ifp);
710 
711 		/* import number of channels */
712 		if (priv->params_ethtool.channels < 1)
713 			priv->params_ethtool.channels = 1;
714 		else if (priv->params_ethtool.channels >
715 		    (u64) priv->mdev->priv.eq_table.num_comp_vectors) {
716 			priv->params_ethtool.channels =
717 			    (u64) priv->mdev->priv.eq_table.num_comp_vectors;
718 		}
719 		priv->params.num_channels = priv->params_ethtool.channels;
720 
721 		/* restart network interface, if any */
722 		if (was_opened)
723 			mlx5e_open_locked(priv->ifp);
724 		break;
725 
726 	case MLX5_PARAM_OFFSET(rx_coalesce_mode):
727 		/* network interface must be down */
728 		if (was_opened != 0 && mode_modify == 0)
729 			mlx5e_close_locked(priv->ifp);
730 
731 		/* import RX coalesce mode */
732 		if (priv->params_ethtool.rx_coalesce_mode > 3)
733 			priv->params_ethtool.rx_coalesce_mode = 3;
734 		priv->params.rx_cq_moderation_mode =
735 		    priv->params_ethtool.rx_coalesce_mode;
736 
737 		/* restart network interface, if any */
738 		if (was_opened != 0) {
739 			if (mode_modify == 0)
740 				mlx5e_open_locked(priv->ifp);
741 			else
742 				error = mlx5e_refresh_channel_params(priv);
743 		}
744 		break;
745 
746 	case MLX5_PARAM_OFFSET(tx_coalesce_mode):
747 		/* network interface must be down */
748 		if (was_opened != 0 && mode_modify == 0)
749 			mlx5e_close_locked(priv->ifp);
750 
751 		/* import TX coalesce mode */
752 		if (priv->params_ethtool.tx_coalesce_mode != 0)
753 			priv->params_ethtool.tx_coalesce_mode = 1;
754 		priv->params.tx_cq_moderation_mode =
755 		    priv->params_ethtool.tx_coalesce_mode;
756 
757 		/* restart network interface, if any */
758 		if (was_opened != 0) {
759 			if (mode_modify == 0)
760 				mlx5e_open_locked(priv->ifp);
761 			else
762 				error = mlx5e_refresh_channel_params(priv);
763 		}
764 		break;
765 
766 	case MLX5_PARAM_OFFSET(hw_lro):
767 		/* network interface must be down */
768 		if (was_opened)
769 			mlx5e_close_locked(priv->ifp);
770 
771 		/* import HW LRO mode */
772 		if (priv->params_ethtool.hw_lro != 0 &&
773 		    MLX5_CAP_ETH(priv->mdev, lro_cap)) {
774 			priv->params_ethtool.hw_lro = 1;
775 			/* check if feature should actually be enabled */
776 			if (priv->ifp->if_capenable & IFCAP_LRO) {
777 				priv->params.hw_lro_en = true;
778 			} else {
779 				priv->params.hw_lro_en = false;
780 
781 				mlx5_en_warn(priv->ifp, "To enable HW LRO "
782 				    "please also enable LRO via ifconfig(8).\n");
783 			}
784 		} else {
785 			/* return an error if HW does not support this feature */
786 			if (priv->params_ethtool.hw_lro != 0)
787 				error = EINVAL;
788 			priv->params.hw_lro_en = false;
789 			priv->params_ethtool.hw_lro = 0;
790 		}
791 		/* restart network interface, if any */
792 		if (was_opened)
793 			mlx5e_open_locked(priv->ifp);
794 		break;
795 
796 	case MLX5_PARAM_OFFSET(cqe_zipping):
797 		/* network interface must be down */
798 		if (was_opened)
799 			mlx5e_close_locked(priv->ifp);
800 
801 		/* import CQE zipping mode */
802 		if (priv->params_ethtool.cqe_zipping &&
803 		    MLX5_CAP_GEN(priv->mdev, cqe_compression)) {
804 			priv->params.cqe_zipping_en = true;
805 			priv->params_ethtool.cqe_zipping = 1;
806 		} else {
807 			priv->params.cqe_zipping_en = false;
808 			priv->params_ethtool.cqe_zipping = 0;
809 		}
810 		/* restart network interface, if any */
811 		if (was_opened)
812 			mlx5e_open_locked(priv->ifp);
813 		break;
814 
815 	case MLX5_PARAM_OFFSET(tx_completion_fact):
816 		/* network interface must be down */
817 		if (was_opened)
818 			mlx5e_close_locked(priv->ifp);
819 
820 		/* verify parameter */
821 		mlx5e_ethtool_sync_tx_completion_fact(priv);
822 
823 		/* restart network interface, if any */
824 		if (was_opened)
825 			mlx5e_open_locked(priv->ifp);
826 		break;
827 
828 	case MLX5_PARAM_OFFSET(modify_tx_dma):
829 		/* check if network interface is opened */
830 		if (was_opened) {
831 			priv->params_ethtool.modify_tx_dma =
832 			    priv->params_ethtool.modify_tx_dma ? 1 : 0;
833 			/* modify tx according to value */
834 			mlx5e_modify_tx_dma(priv, value != 0);
835 		} else {
836 			/* if closed force enable tx */
837 			priv->params_ethtool.modify_tx_dma = 0;
838 		}
839 		break;
840 
841 	case MLX5_PARAM_OFFSET(modify_rx_dma):
842 		/* check if network interface is opened */
843 		if (was_opened) {
844 			priv->params_ethtool.modify_rx_dma =
845 			    priv->params_ethtool.modify_rx_dma ? 1 : 0;
846 			/* modify rx according to value */
847 			mlx5e_modify_rx_dma(priv, value != 0);
848 		} else {
849 			/* if closed force enable rx */
850 			priv->params_ethtool.modify_rx_dma = 0;
851 		}
852 		break;
853 
854 	case MLX5_PARAM_OFFSET(diag_pci_enable):
855 		priv->params_ethtool.diag_pci_enable =
856 		    priv->params_ethtool.diag_pci_enable ? 1 : 0;
857 
858 		error = -mlx5_core_set_diagnostics_full(priv->mdev,
859 		    priv->params_ethtool.diag_pci_enable,
860 		    priv->params_ethtool.diag_general_enable);
861 		break;
862 
863 	case MLX5_PARAM_OFFSET(diag_general_enable):
864 		priv->params_ethtool.diag_general_enable =
865 		    priv->params_ethtool.diag_general_enable ? 1 : 0;
866 
867 		error = -mlx5_core_set_diagnostics_full(priv->mdev,
868 		    priv->params_ethtool.diag_pci_enable,
869 		    priv->params_ethtool.diag_general_enable);
870 		break;
871 
872 	case MLX5_PARAM_OFFSET(mc_local_lb):
873 		priv->params_ethtool.mc_local_lb =
874 		    priv->params_ethtool.mc_local_lb ? 1 : 0;
875 
876 		if (MLX5_CAP_GEN(priv->mdev, disable_local_lb)) {
877 			error = mlx5_nic_vport_modify_local_lb(priv->mdev,
878 			    MLX5_LOCAL_MC_LB, priv->params_ethtool.mc_local_lb);
879 		} else {
880 			error = EOPNOTSUPP;
881 		}
882 		break;
883 
884 	case MLX5_PARAM_OFFSET(uc_local_lb):
885 		priv->params_ethtool.uc_local_lb =
886 		    priv->params_ethtool.uc_local_lb ? 1 : 0;
887 
888 		if (MLX5_CAP_GEN(priv->mdev, disable_local_lb)) {
889 			error = mlx5_nic_vport_modify_local_lb(priv->mdev,
890 			    MLX5_LOCAL_UC_LB, priv->params_ethtool.uc_local_lb);
891 		} else {
892 			error = EOPNOTSUPP;
893 		}
894 		break;
895 
896 	default:
897 		break;
898 	}
899 done:
900 	PRIV_UNLOCK(priv);
901 	return (error);
902 }
903 
904 static const char *mlx5e_params_desc[] = {
905 	MLX5E_PARAMS(MLX5E_STATS_DESC)
906 };
907 
908 static const char *mlx5e_port_stats_debug_desc[] = {
909 	MLX5E_PORT_STATS_DEBUG(MLX5E_STATS_DESC)
910 };
911 
912 static int
913 mlx5e_ethtool_debug_channel_info(SYSCTL_HANDLER_ARGS)
914 {
915 	struct mlx5e_priv *priv;
916 	struct sbuf sb;
917 	struct mlx5e_channel *c;
918 	struct mlx5e_sq *sq;
919 	struct mlx5e_rq *rq;
920 	int error, i, tc;
921 	bool opened;
922 
923 	priv = arg1;
924 	error = sysctl_wire_old_buffer(req, 0);
925 	if (error != 0)
926 		return (error);
927 	if (sbuf_new_for_sysctl(&sb, NULL, 1024, req) == NULL)
928 		return (ENOMEM);
929 	sbuf_clear_flags(&sb, SBUF_INCLUDENUL);
930 
931 	PRIV_LOCK(priv);
932 	opened = test_bit(MLX5E_STATE_OPENED, &priv->state);
933 
934 	sbuf_printf(&sb, "pages irq %d\n",
935 	    priv->mdev->priv.msix_arr[MLX5_EQ_VEC_PAGES].vector);
936 	sbuf_printf(&sb, "command irq %d\n",
937 	    priv->mdev->priv.msix_arr[MLX5_EQ_VEC_CMD].vector);
938 	sbuf_printf(&sb, "async irq %d\n",
939 	    priv->mdev->priv.msix_arr[MLX5_EQ_VEC_ASYNC].vector);
940 
941 	for (i = 0; i != priv->params.num_channels; i++) {
942 		int eqn_not_used = -1;
943 		int irqn = MLX5_EQ_VEC_COMP_BASE;
944 
945 		if (mlx5_vector2eqn(priv->mdev, i, &eqn_not_used, &irqn) != 0)
946 			continue;
947 
948 		c = opened ? &priv->channel[i] : NULL;
949 		rq = opened ? &c->rq : NULL;
950 		sbuf_printf(&sb, "channel %d rq %d cq %d irq %d\n", i,
951 		    opened ? rq->rqn : -1,
952 		    opened ? rq->cq.mcq.cqn : -1,
953 		    priv->mdev->priv.msix_arr[irqn].vector);
954 
955 		for (tc = 0; tc != priv->num_tc; tc++) {
956 			sq = opened ? &c->sq[tc] : NULL;
957 			sbuf_printf(&sb, "channel %d tc %d sq %d cq %d irq %d\n",
958 			    i, tc,
959 			    opened ? sq->sqn : -1,
960 			    opened ? sq->cq.mcq.cqn : -1,
961 			    priv->mdev->priv.msix_arr[irqn].vector);
962 		}
963 	}
964 	PRIV_UNLOCK(priv);
965 	error = sbuf_finish(&sb);
966 	sbuf_delete(&sb);
967 	return (error);
968 }
969 
970 static int
971 mlx5e_ethtool_debug_stats(SYSCTL_HANDLER_ARGS)
972 {
973 	struct mlx5e_priv *priv = arg1;
974 	int sys_debug;
975 	int error;
976 
977 	PRIV_LOCK(priv);
978 	if (priv->gone != 0) {
979 		error = ENODEV;
980 		goto done;
981 	}
982 	sys_debug = priv->sysctl_debug;
983 	error = sysctl_handle_int(oidp, &sys_debug, 0, req);
984 	if (error != 0 || !req->newptr)
985 		goto done;
986 	sys_debug = sys_debug ? 1 : 0;
987 	if (sys_debug == priv->sysctl_debug)
988 		goto done;
989 
990 	if ((priv->sysctl_debug = sys_debug)) {
991 		mlx5e_create_stats(&priv->stats.port_stats_debug.ctx,
992 		    SYSCTL_CHILDREN(priv->sysctl_ifnet), "debug_stats",
993 		    mlx5e_port_stats_debug_desc, MLX5E_PORT_STATS_DEBUG_NUM,
994 		    priv->stats.port_stats_debug.arg);
995 		SYSCTL_ADD_PROC(&priv->stats.port_stats_debug.ctx,
996 		    SYSCTL_CHILDREN(priv->sysctl_ifnet), OID_AUTO,
997 		    "hw_ctx_debug",
998 		    CTLFLAG_RD | CTLFLAG_MPSAFE | CTLTYPE_STRING, priv, 0,
999 		    mlx5e_ethtool_debug_channel_info, "S", "");
1000 	} else {
1001 		sysctl_ctx_free(&priv->stats.port_stats_debug.ctx);
1002 	}
1003 done:
1004 	PRIV_UNLOCK(priv);
1005 	return (error);
1006 }
1007 
1008 static void
1009 mlx5e_create_diagnostics(struct mlx5e_priv *priv)
1010 {
1011 	struct mlx5_core_diagnostics_entry entry;
1012 	struct sysctl_ctx_list *ctx;
1013 	struct sysctl_oid *node;
1014 	int x;
1015 
1016 	/* sysctl context we are using */
1017 	ctx = &priv->sysctl_ctx;
1018 
1019 	/* create root node */
1020 	node = SYSCTL_ADD_NODE(ctx,
1021 	    SYSCTL_CHILDREN(priv->sysctl_ifnet), OID_AUTO,
1022 	    "diagnostics", CTLFLAG_RD, NULL, "Diagnostics");
1023 	if (node == NULL)
1024 		return;
1025 
1026 	/* create PCI diagnostics */
1027 	for (x = 0; x != MLX5_CORE_PCI_DIAGNOSTICS_NUM; x++) {
1028 		entry = mlx5_core_pci_diagnostics_table[x];
1029 		if (mlx5_core_supports_diagnostics(priv->mdev, entry.counter_id) == 0)
1030 			continue;
1031 		SYSCTL_ADD_UQUAD(ctx, SYSCTL_CHILDREN(node), OID_AUTO,
1032 		    entry.desc, CTLFLAG_RD, priv->params_pci.array + x,
1033 		    "PCI diagnostics counter");
1034 	}
1035 
1036 	/* create general diagnostics */
1037 	for (x = 0; x != MLX5_CORE_GENERAL_DIAGNOSTICS_NUM; x++) {
1038 		entry = mlx5_core_general_diagnostics_table[x];
1039 		if (mlx5_core_supports_diagnostics(priv->mdev, entry.counter_id) == 0)
1040 			continue;
1041 		SYSCTL_ADD_UQUAD(ctx, SYSCTL_CHILDREN(node), OID_AUTO,
1042 		    entry.desc, CTLFLAG_RD, priv->params_general.array + x,
1043 		    "General diagnostics counter");
1044 	}
1045 }
1046 
1047 void
1048 mlx5e_create_ethtool(struct mlx5e_priv *priv)
1049 {
1050 	struct sysctl_oid *node, *qos_node;
1051 	const char *pnameunit;
1052 	struct mlx5e_port_buffer port_buffer;
1053 	unsigned x;
1054 	int i;
1055 
1056 	/* set some defaults */
1057 	priv->params_ethtool.tx_queue_size_max = 1 << MLX5E_PARAMS_MAXIMUM_LOG_SQ_SIZE;
1058 	priv->params_ethtool.rx_queue_size_max = 1 << MLX5E_PARAMS_MAXIMUM_LOG_RQ_SIZE;
1059 	priv->params_ethtool.tx_queue_size = 1 << priv->params.log_sq_size;
1060 	priv->params_ethtool.rx_queue_size = 1 << priv->params.log_rq_size;
1061 	priv->params_ethtool.channels = priv->params.num_channels;
1062 	priv->params_ethtool.channels_rsss = priv->params.channels_rsss;
1063 	priv->params_ethtool.coalesce_pkts_max = MLX5E_FLD_MAX(cqc, cq_max_count);
1064 	priv->params_ethtool.coalesce_usecs_max = MLX5E_FLD_MAX(cqc, cq_period);
1065 	priv->params_ethtool.rx_coalesce_mode = priv->params.rx_cq_moderation_mode;
1066 	priv->params_ethtool.rx_coalesce_usecs = priv->params.rx_cq_moderation_usec;
1067 	priv->params_ethtool.rx_coalesce_pkts = priv->params.rx_cq_moderation_pkts;
1068 	priv->params_ethtool.tx_coalesce_mode = priv->params.tx_cq_moderation_mode;
1069 	priv->params_ethtool.tx_coalesce_usecs = priv->params.tx_cq_moderation_usec;
1070 	priv->params_ethtool.tx_coalesce_pkts = priv->params.tx_cq_moderation_pkts;
1071 	priv->params_ethtool.hw_lro = priv->params.hw_lro_en;
1072 	priv->params_ethtool.cqe_zipping = priv->params.cqe_zipping_en;
1073 	mlx5e_ethtool_sync_tx_completion_fact(priv);
1074 
1075 	/* get default values for local loopback, if any */
1076 	if (MLX5_CAP_GEN(priv->mdev, disable_local_lb)) {
1077 		int err;
1078 		u8 val;
1079 
1080 		err = mlx5_nic_vport_query_local_lb(priv->mdev, MLX5_LOCAL_MC_LB, &val);
1081 		if (err == 0)
1082 			priv->params_ethtool.mc_local_lb = val;
1083 
1084 		err = mlx5_nic_vport_query_local_lb(priv->mdev, MLX5_LOCAL_UC_LB, &val);
1085 		if (err == 0)
1086 			priv->params_ethtool.uc_local_lb = val;
1087 	}
1088 
1089 	/* create root node */
1090 	node = SYSCTL_ADD_NODE(&priv->sysctl_ctx,
1091 	    SYSCTL_CHILDREN(priv->sysctl_ifnet), OID_AUTO,
1092 	    "conf", CTLFLAG_RW, NULL, "Configuration");
1093 	if (node == NULL)
1094 		return;
1095 	for (x = 0; x != MLX5E_PARAMS_NUM; x++) {
1096 		/* check for read-only parameter */
1097 		if (strstr(mlx5e_params_desc[2 * x], "_max") != NULL ||
1098 		    strstr(mlx5e_params_desc[2 * x], "_mtu") != NULL) {
1099 			SYSCTL_ADD_PROC(&priv->sysctl_ctx, SYSCTL_CHILDREN(node), OID_AUTO,
1100 			    mlx5e_params_desc[2 * x], CTLTYPE_U64 | CTLFLAG_RD |
1101 			    CTLFLAG_MPSAFE, priv, x, &mlx5e_ethtool_handler, "QU",
1102 			    mlx5e_params_desc[2 * x + 1]);
1103 		} else {
1104 #if (__FreeBSD_version < 1100000)
1105 			char path[64];
1106 #endif
1107 			/*
1108 			 * NOTE: In FreeBSD-11 and newer the
1109 			 * CTLFLAG_RWTUN flag will take care of
1110 			 * loading default sysctl value from the
1111 			 * kernel environment, if any:
1112 			 */
1113 			SYSCTL_ADD_PROC(&priv->sysctl_ctx, SYSCTL_CHILDREN(node), OID_AUTO,
1114 			    mlx5e_params_desc[2 * x], CTLTYPE_U64 | CTLFLAG_RWTUN |
1115 			    CTLFLAG_MPSAFE, priv, x, &mlx5e_ethtool_handler, "QU",
1116 			    mlx5e_params_desc[2 * x + 1]);
1117 
1118 #if (__FreeBSD_version < 1100000)
1119 			/* compute path for sysctl */
1120 			snprintf(path, sizeof(path), "dev.mce.%d.conf.%s",
1121 			    device_get_unit(priv->mdev->pdev->dev.bsddev),
1122 			    mlx5e_params_desc[2 * x]);
1123 
1124 			/* try to fetch tunable, if any */
1125 			if (TUNABLE_QUAD_FETCH(path, &priv->params_ethtool.arg[x]))
1126 				mlx5e_ethtool_handler(NULL, priv, x, NULL);
1127 #endif
1128 		}
1129 	}
1130 
1131 	SYSCTL_ADD_PROC(&priv->sysctl_ctx, SYSCTL_CHILDREN(node), OID_AUTO,
1132 	    "debug_stats", CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, priv,
1133 	    0, &mlx5e_ethtool_debug_stats, "I", "Extended debug statistics");
1134 
1135 	pnameunit = device_get_nameunit(priv->mdev->pdev->dev.bsddev);
1136 
1137 	SYSCTL_ADD_STRING(&priv->sysctl_ctx, SYSCTL_CHILDREN(node),
1138 	    OID_AUTO, "device_name", CTLFLAG_RD,
1139 	    __DECONST(void *, pnameunit), 0,
1140 	    "PCI device name");
1141 
1142 	/* Diagnostics support */
1143 	mlx5e_create_diagnostics(priv);
1144 
1145 	/* create qos node */
1146 	qos_node = SYSCTL_ADD_NODE(&priv->sysctl_ctx,
1147 	    SYSCTL_CHILDREN(node), OID_AUTO,
1148 	    "qos", CTLFLAG_RW, NULL, "Quality Of Service configuration");
1149 	if (qos_node == NULL)
1150 		return;
1151 
1152 	/* Priority rate limit support */
1153 	if (mlx5e_getmaxrate(priv) == 0) {
1154 		SYSCTL_ADD_PROC(&priv->sysctl_ctx, SYSCTL_CHILDREN(qos_node),
1155 		    OID_AUTO, "tc_max_rate", CTLTYPE_U64 | CTLFLAG_RWTUN | CTLFLAG_MPSAFE,
1156 		    priv, 0, mlx5e_tc_maxrate_handler, "QU",
1157 		    "Max rate for priority, specified in kilobits, where kilo=1000, "
1158 		    "max_rate must be divisible by 100000");
1159 	}
1160 
1161 	/* Bandwidth limiting by ratio */
1162 	if (mlx5e_get_max_alloc(priv) == 0) {
1163 		SYSCTL_ADD_PROC(&priv->sysctl_ctx, SYSCTL_CHILDREN(qos_node),
1164 		    OID_AUTO, "tc_rate_share", CTLTYPE_U8 | CTLFLAG_RWTUN | CTLFLAG_MPSAFE,
1165 		    priv, 0, mlx5e_tc_rate_share_handler, "QU",
1166 		    "Specify bandwidth ratio from 1 to 100 "
1167 		    "for the available traffic classes");
1168 	}
1169 
1170 	/* Priority to traffic class mapping */
1171 	if (mlx5e_get_prio_tc(priv) == 0) {
1172 		SYSCTL_ADD_PROC(&priv->sysctl_ctx, SYSCTL_CHILDREN(qos_node),
1173 		    OID_AUTO, "prio_0_7_tc", CTLTYPE_U8 | CTLFLAG_RWTUN | CTLFLAG_MPSAFE,
1174 		    priv, 0, mlx5e_prio_to_tc_handler, "CU",
1175 		    "Set traffic class 0 to 7 for priority 0 to 7 inclusivly");
1176 	}
1177 
1178 	/* DSCP support */
1179 	if (mlx5e_get_dscp(priv) == 0) {
1180 		for (i = 0; i != MLX5_MAX_SUPPORTED_DSCP; i += 8) {
1181 			char name[32];
1182 			snprintf(name, sizeof(name), "dscp_%d_%d_prio", i, i + 7);
1183 			SYSCTL_ADD_PROC(&priv->sysctl_ctx, SYSCTL_CHILDREN(qos_node),
1184 				OID_AUTO, name, CTLTYPE_U8 | CTLFLAG_RWTUN | CTLFLAG_MPSAFE,
1185 				priv, i, mlx5e_dscp_prio_handler, "CU",
1186 				"Set DSCP to priority mapping, 0..7");
1187 		}
1188 #define	A	"Set trust state, 1:PCP 2:DSCP"
1189 #define	B	" 3:BOTH"
1190 		SYSCTL_ADD_PROC(&priv->sysctl_ctx, SYSCTL_CHILDREN(qos_node),
1191 		    OID_AUTO, "trust_state", CTLTYPE_U8 | CTLFLAG_RWTUN | CTLFLAG_MPSAFE,
1192 		    priv, 0, mlx5e_trust_state_handler, "CU",
1193 		    MLX5_CAP_QCAM_FEATURE(priv->mdev, qpts_trust_both) ?
1194 		    A B : A);
1195 #undef B
1196 #undef A
1197 	}
1198 
1199 	if (mlx5e_port_query_buffer(priv, &port_buffer) == 0) {
1200 		SYSCTL_ADD_PROC(&priv->sysctl_ctx, SYSCTL_CHILDREN(qos_node),
1201 		    OID_AUTO, "buffers_size",
1202 		    CTLTYPE_U32 | CTLFLAG_RWTUN | CTLFLAG_MPSAFE,
1203 		    priv, 0, mlx5e_buf_size_handler, "IU",
1204 		    "Set buffers sizes");
1205 		SYSCTL_ADD_PROC(&priv->sysctl_ctx, SYSCTL_CHILDREN(qos_node),
1206 		    OID_AUTO, "buffers_prio",
1207 		    CTLTYPE_U8 | CTLFLAG_RWTUN | CTLFLAG_MPSAFE,
1208 		    priv, 0, mlx5e_buf_prio_handler, "CU",
1209 		    "Set prio to buffers mapping");
1210 		SYSCTL_ADD_PROC(&priv->sysctl_ctx, SYSCTL_CHILDREN(qos_node),
1211 		    OID_AUTO, "cable_length",
1212 		    CTLTYPE_UINT | CTLFLAG_RWTUN | CTLFLAG_MPSAFE,
1213 		    priv, 0, mlx5e_cable_length_handler, "IU",
1214 		    "Set cable length in meters for xoff threshold calculation");
1215 	}
1216 }
1217