mlx5_en_ethtool.c revision 337108
1/*-
2 * Copyright (c) 2015 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: stable/11/sys/dev/mlx5/mlx5_en/mlx5_en_ethtool.c 337108 2018-08-02 08:47:24Z hselasky $
26 */
27
28#include "en.h"
29#include <net/sff8472.h>
30
31void
32mlx5e_create_stats(struct sysctl_ctx_list *ctx,
33    struct sysctl_oid_list *parent, const char *buffer,
34    const char **desc, unsigned num, u64 * arg)
35{
36	struct sysctl_oid *node;
37	unsigned x;
38
39	sysctl_ctx_init(ctx);
40
41	node = SYSCTL_ADD_NODE(ctx, parent, OID_AUTO,
42	    buffer, CTLFLAG_RD, NULL, "Statistics");
43	if (node == NULL)
44		return;
45	for (x = 0; x != num; x++) {
46		SYSCTL_ADD_UQUAD(ctx, SYSCTL_CHILDREN(node), OID_AUTO,
47		    desc[2 * x], CTLFLAG_RD, arg + x, desc[2 * x + 1]);
48	}
49}
50
51static void
52mlx5e_ethtool_sync_tx_completion_fact(struct mlx5e_priv *priv)
53{
54	/*
55	 * Limit the maximum distance between completion events to
56	 * half of the currently set TX queue size.
57	 *
58	 * The maximum number of queue entries a single IP packet can
59	 * consume is given by MLX5_SEND_WQE_MAX_WQEBBS.
60	 *
61	 * The worst case max value is then given as below:
62	 */
63	uint64_t max = priv->params_ethtool.tx_queue_size /
64	    (2 * MLX5_SEND_WQE_MAX_WQEBBS);
65
66	/*
67	 * Update the maximum completion factor value in case the
68	 * tx_queue_size field changed. Ensure we don't overflow
69	 * 16-bits.
70	 */
71	if (max < 1)
72		max = 1;
73	else if (max > 65535)
74		max = 65535;
75	priv->params_ethtool.tx_completion_fact_max = max;
76
77	/*
78	 * Verify that the current TX completion factor is within the
79	 * given limits:
80	 */
81	if (priv->params_ethtool.tx_completion_fact < 1)
82		priv->params_ethtool.tx_completion_fact = 1;
83	else if (priv->params_ethtool.tx_completion_fact > max)
84		priv->params_ethtool.tx_completion_fact = max;
85}
86
87static int
88mlx5e_getmaxrate(struct mlx5e_priv *priv)
89{
90	struct mlx5_core_dev *mdev = priv->mdev;
91	u8 max_bw_unit[IEEE_8021QAZ_MAX_TCS];
92	u8 max_bw_value[IEEE_8021QAZ_MAX_TCS];
93	int err;
94	int i;
95
96	PRIV_LOCK(priv);
97	err = -mlx5_query_port_tc_rate_limit(mdev, max_bw_value, max_bw_unit);
98	if (err)
99		goto done;
100
101	for (i = 0; i <= mlx5_max_tc(mdev); i++) {
102		switch (max_bw_unit[i]) {
103		case MLX5_100_MBPS_UNIT:
104			priv->params_ethtool.max_bw_value[i] = max_bw_value[i] * MLX5E_100MB;
105			break;
106		case MLX5_GBPS_UNIT:
107			priv->params_ethtool.max_bw_value[i] = max_bw_value[i] * MLX5E_1GB;
108			break;
109		case MLX5_BW_NO_LIMIT:
110			priv->params_ethtool.max_bw_value[i] = 0;
111			break;
112		default:
113			priv->params_ethtool.max_bw_value[i] = -1;
114			WARN_ONCE(true, "non-supported BW unit");
115			break;
116		}
117	}
118done:
119	PRIV_UNLOCK(priv);
120	return (err);
121}
122
123static int
124mlx5e_get_dscp(struct mlx5e_priv *priv)
125{
126	struct mlx5_core_dev *mdev = priv->mdev;
127	int err;
128
129	if (MLX5_CAP_GEN(mdev, qcam_reg) == 0 ||
130	    MLX5_CAP_QCAM_REG(mdev, qpts) == 0 ||
131	    MLX5_CAP_QCAM_REG(mdev, qpdpm) == 0)
132		return (EOPNOTSUPP);
133
134	PRIV_LOCK(priv);
135	err = -mlx5_query_dscp2prio(mdev, priv->params_ethtool.dscp2prio);
136	if (err)
137		goto done;
138
139	err = -mlx5_query_trust_state(mdev, &priv->params_ethtool.trust_state);
140	if (err)
141		goto done;
142done:
143	PRIV_UNLOCK(priv);
144	return (err);
145}
146
147static int
148mlx5e_tc_maxrate_handler(SYSCTL_HANDLER_ARGS)
149{
150	struct mlx5e_priv *priv = arg1;
151	int prio_index = arg2;
152	struct mlx5_core_dev *mdev = priv->mdev;
153	u8 max_bw_unit[IEEE_8021QAZ_MAX_TCS];
154	u8 max_bw_value[IEEE_8021QAZ_MAX_TCS];
155	int i, err;
156	u64 bw_val;
157	u64 result = priv->params_ethtool.max_bw_value[prio_index];
158	const u64 upper_limit_mbps = 255 * MLX5E_100MB;
159	const u64 upper_limit_gbps = 255 * MLX5E_1GB;
160
161	PRIV_LOCK(priv);
162	err = sysctl_handle_64(oidp, &result, 0, req);
163	if (err || !req->newptr ||
164	    result == priv->params_ethtool.max_bw_value[prio_index])
165		goto done;
166
167	if (result % MLX5E_100MB) {
168		err = ERANGE;
169		goto done;
170	}
171
172	memset(max_bw_value, 0, sizeof(max_bw_value));
173	memset(max_bw_unit, 0, sizeof(max_bw_unit));
174
175	for (i = 0; i <= mlx5_max_tc(mdev); i++) {
176		bw_val = (i == prio_index) ? result : priv->params_ethtool.max_bw_value[i];
177
178		if (!bw_val) {
179			max_bw_unit[i] = MLX5_BW_NO_LIMIT;
180		} else if (bw_val > upper_limit_gbps) {
181			result = 0;
182			max_bw_unit[i] = MLX5_BW_NO_LIMIT;
183		} else if (bw_val <= upper_limit_mbps) {
184			max_bw_value[i] = howmany(bw_val, MLX5E_100MB);
185			max_bw_unit[i]  = MLX5_100_MBPS_UNIT;
186		} else {
187			max_bw_value[i] = howmany(bw_val, MLX5E_1GB);
188			max_bw_unit[i]  = MLX5_GBPS_UNIT;
189		}
190	}
191
192	err = -mlx5_modify_port_tc_rate_limit(mdev, max_bw_value, max_bw_unit);
193	if (err)
194		goto done;
195
196	priv->params_ethtool.max_bw_value[prio_index] = result;
197done:
198	PRIV_UNLOCK(priv);
199	return (err);
200}
201
202static int
203mlx5e_get_prio_tc(struct mlx5e_priv *priv)
204{
205	struct mlx5_core_dev *mdev = priv->mdev;
206	int err = 0;
207	int i;
208
209	PRIV_LOCK(priv);
210	if (!MLX5_CAP_GEN(priv->mdev, ets)) {
211		PRIV_UNLOCK(priv);
212		return (EOPNOTSUPP);
213	}
214
215	for (i = 0; i <= mlx5_max_tc(priv->mdev); i++) {
216		err = -mlx5_query_port_prio_tc(mdev, i, &(priv->params_ethtool.prio_tc[i]));
217		if (err)
218			break;
219	}
220
221	PRIV_UNLOCK(priv);
222	return (err);
223}
224
225static int
226mlx5e_prio_to_tc_handler(SYSCTL_HANDLER_ARGS)
227{
228	struct mlx5e_priv *priv = arg1;
229	int prio_index = arg2;
230	struct mlx5_core_dev *mdev = priv->mdev;
231	int err;
232	uint8_t result = priv->params_ethtool.prio_tc[prio_index];
233
234	PRIV_LOCK(priv);
235	err = sysctl_handle_8(oidp, &result, 0, req);
236	if (err || !req->newptr ||
237	    result == priv->params_ethtool.prio_tc[prio_index])
238		goto done;
239
240	if (result > mlx5_max_tc(mdev)) {
241		err = ERANGE;
242		goto done;
243	}
244
245	err = -mlx5_set_port_prio_tc(mdev, prio_index, result);
246	if (err)
247		goto done;
248
249	priv->params_ethtool.prio_tc[prio_index] = result;
250
251done:
252	PRIV_UNLOCK(priv);
253	return (err);
254}
255
256static int
257mlx5e_trust_state_handler(SYSCTL_HANDLER_ARGS)
258{
259	struct mlx5e_priv *priv = arg1;
260	struct mlx5_core_dev *mdev = priv->mdev;
261	int err;
262	u8 result;
263
264	PRIV_LOCK(priv);
265	result = priv->params_ethtool.trust_state;
266	err = sysctl_handle_8(oidp, &result, 0, req);
267	if (err || !req->newptr ||
268	    result == priv->params_ethtool.trust_state)
269		goto done;
270
271	switch (result) {
272	case MLX5_QPTS_TRUST_PCP:
273	case MLX5_QPTS_TRUST_DSCP:
274		break;
275	case MLX5_QPTS_TRUST_BOTH:
276		if (!MLX5_CAP_QCAM_FEATURE(mdev, qpts_trust_both)) {
277			err = EOPNOTSUPP;
278			goto done;
279		}
280		break;
281	default:
282		err = ERANGE;
283		goto done;
284	}
285
286	err = -mlx5_set_trust_state(mdev, result);
287	if (err)
288		goto done;
289
290	priv->params_ethtool.trust_state = result;
291done:
292	PRIV_UNLOCK(priv);
293	return (err);
294}
295
296static int
297mlx5e_dscp_prio_handler(SYSCTL_HANDLER_ARGS)
298{
299	struct mlx5e_priv *priv = arg1;
300	int prio_index = arg2;
301	struct mlx5_core_dev *mdev = priv->mdev;
302	uint8_t dscp2prio[MLX5_MAX_SUPPORTED_DSCP];
303	uint8_t x;
304	int err;
305
306	PRIV_LOCK(priv);
307	err = SYSCTL_OUT(req, priv->params_ethtool.dscp2prio + prio_index,
308	    sizeof(priv->params_ethtool.dscp2prio) / 8);
309	if (err || !req->newptr)
310		goto done;
311
312	memcpy(dscp2prio, priv->params_ethtool.dscp2prio, sizeof(dscp2prio));
313	err = SYSCTL_IN(req, dscp2prio + prio_index, sizeof(dscp2prio) / 8);
314	if (err)
315		goto done;
316	for (x = 0; x != MLX5_MAX_SUPPORTED_DSCP; x++) {
317		if (dscp2prio[x] > 7) {
318			err = ERANGE;
319			goto done;
320		}
321	}
322	err = -mlx5_set_dscp2prio(mdev, dscp2prio);
323	if (err)
324		goto done;
325
326	/* update local array */
327	memcpy(priv->params_ethtool.dscp2prio, dscp2prio,
328	    sizeof(priv->params_ethtool.dscp2prio));
329done:
330	PRIV_UNLOCK(priv);
331	return (err);
332}
333
334#define	MLX5_PARAM_OFFSET(n)				\
335    __offsetof(struct mlx5e_priv, params_ethtool.n)
336
337static int
338mlx5e_ethtool_handler(SYSCTL_HANDLER_ARGS)
339{
340	struct mlx5e_priv *priv = arg1;
341	uint64_t value;
342	int mode_modify;
343	int was_opened;
344	int error;
345
346	PRIV_LOCK(priv);
347	value = priv->params_ethtool.arg[arg2];
348	if (req != NULL) {
349		error = sysctl_handle_64(oidp, &value, 0, req);
350		if (error || req->newptr == NULL ||
351		    value == priv->params_ethtool.arg[arg2])
352			goto done;
353
354		/* assign new value */
355		priv->params_ethtool.arg[arg2] = value;
356	} else {
357		error = 0;
358	}
359	/* check if device is gone */
360	if (priv->gone) {
361		error = ENXIO;
362		goto done;
363	}
364	was_opened = test_bit(MLX5E_STATE_OPENED, &priv->state);
365	mode_modify = MLX5_CAP_GEN(priv->mdev, cq_period_mode_modify);
366
367	switch (MLX5_PARAM_OFFSET(arg[arg2])) {
368	case MLX5_PARAM_OFFSET(rx_coalesce_usecs):
369		/* import RX coal time */
370		if (priv->params_ethtool.rx_coalesce_usecs < 1)
371			priv->params_ethtool.rx_coalesce_usecs = 0;
372		else if (priv->params_ethtool.rx_coalesce_usecs >
373		    MLX5E_FLD_MAX(cqc, cq_period)) {
374			priv->params_ethtool.rx_coalesce_usecs =
375			    MLX5E_FLD_MAX(cqc, cq_period);
376		}
377		priv->params.rx_cq_moderation_usec =
378		    priv->params_ethtool.rx_coalesce_usecs;
379
380		/* check to avoid down and up the network interface */
381		if (was_opened)
382			error = mlx5e_refresh_channel_params(priv);
383		break;
384
385	case MLX5_PARAM_OFFSET(rx_coalesce_pkts):
386		/* import RX coal pkts */
387		if (priv->params_ethtool.rx_coalesce_pkts < 1)
388			priv->params_ethtool.rx_coalesce_pkts = 0;
389		else if (priv->params_ethtool.rx_coalesce_pkts >
390		    MLX5E_FLD_MAX(cqc, cq_max_count)) {
391			priv->params_ethtool.rx_coalesce_pkts =
392			    MLX5E_FLD_MAX(cqc, cq_max_count);
393		}
394		priv->params.rx_cq_moderation_pkts =
395		    priv->params_ethtool.rx_coalesce_pkts;
396
397		/* check to avoid down and up the network interface */
398		if (was_opened)
399			error = mlx5e_refresh_channel_params(priv);
400		break;
401
402	case MLX5_PARAM_OFFSET(tx_coalesce_usecs):
403		/* import TX coal time */
404		if (priv->params_ethtool.tx_coalesce_usecs < 1)
405			priv->params_ethtool.tx_coalesce_usecs = 0;
406		else if (priv->params_ethtool.tx_coalesce_usecs >
407		    MLX5E_FLD_MAX(cqc, cq_period)) {
408			priv->params_ethtool.tx_coalesce_usecs =
409			    MLX5E_FLD_MAX(cqc, cq_period);
410		}
411		priv->params.tx_cq_moderation_usec =
412		    priv->params_ethtool.tx_coalesce_usecs;
413
414		/* check to avoid down and up the network interface */
415		if (was_opened)
416			error = mlx5e_refresh_channel_params(priv);
417		break;
418
419	case MLX5_PARAM_OFFSET(tx_coalesce_pkts):
420		/* import TX coal pkts */
421		if (priv->params_ethtool.tx_coalesce_pkts < 1)
422			priv->params_ethtool.tx_coalesce_pkts = 0;
423		else if (priv->params_ethtool.tx_coalesce_pkts >
424		    MLX5E_FLD_MAX(cqc, cq_max_count)) {
425			priv->params_ethtool.tx_coalesce_pkts =
426			    MLX5E_FLD_MAX(cqc, cq_max_count);
427		}
428		priv->params.tx_cq_moderation_pkts =
429		    priv->params_ethtool.tx_coalesce_pkts;
430
431		/* check to avoid down and up the network interface */
432		if (was_opened)
433			error = mlx5e_refresh_channel_params(priv);
434		break;
435
436	case MLX5_PARAM_OFFSET(tx_queue_size):
437		/* network interface must be down */
438		if (was_opened)
439			mlx5e_close_locked(priv->ifp);
440
441		/* import TX queue size */
442		if (priv->params_ethtool.tx_queue_size <
443		    (1 << MLX5E_PARAMS_MINIMUM_LOG_SQ_SIZE)) {
444			priv->params_ethtool.tx_queue_size =
445			    (1 << MLX5E_PARAMS_MINIMUM_LOG_SQ_SIZE);
446		} else if (priv->params_ethtool.tx_queue_size >
447		    priv->params_ethtool.tx_queue_size_max) {
448			priv->params_ethtool.tx_queue_size =
449			    priv->params_ethtool.tx_queue_size_max;
450		}
451		/* store actual TX queue size */
452		priv->params.log_sq_size =
453		    order_base_2(priv->params_ethtool.tx_queue_size);
454		priv->params_ethtool.tx_queue_size =
455		    1 << priv->params.log_sq_size;
456
457		/* verify TX completion factor */
458		mlx5e_ethtool_sync_tx_completion_fact(priv);
459
460		/* restart network interface, if any */
461		if (was_opened)
462			mlx5e_open_locked(priv->ifp);
463		break;
464
465	case MLX5_PARAM_OFFSET(rx_queue_size):
466		/* network interface must be down */
467		if (was_opened)
468			mlx5e_close_locked(priv->ifp);
469
470		/* import RX queue size */
471		if (priv->params_ethtool.rx_queue_size <
472		    (1 << MLX5E_PARAMS_MINIMUM_LOG_RQ_SIZE)) {
473			priv->params_ethtool.rx_queue_size =
474			    (1 << MLX5E_PARAMS_MINIMUM_LOG_RQ_SIZE);
475		} else if (priv->params_ethtool.rx_queue_size >
476		    priv->params_ethtool.rx_queue_size_max) {
477			priv->params_ethtool.rx_queue_size =
478			    priv->params_ethtool.rx_queue_size_max;
479		}
480		/* store actual RX queue size */
481		priv->params.log_rq_size =
482		    order_base_2(priv->params_ethtool.rx_queue_size);
483		priv->params_ethtool.rx_queue_size =
484		    1 << priv->params.log_rq_size;
485
486		/* update least number of RX WQEs */
487		priv->params.min_rx_wqes = min(
488		    priv->params_ethtool.rx_queue_size - 1,
489		    MLX5E_PARAMS_DEFAULT_MIN_RX_WQES);
490
491		/* restart network interface, if any */
492		if (was_opened)
493			mlx5e_open_locked(priv->ifp);
494		break;
495
496	case MLX5_PARAM_OFFSET(channels):
497		/* network interface must be down */
498		if (was_opened)
499			mlx5e_close_locked(priv->ifp);
500
501		/* import number of channels */
502		if (priv->params_ethtool.channels < 1)
503			priv->params_ethtool.channels = 1;
504		else if (priv->params_ethtool.channels >
505		    (u64) priv->mdev->priv.eq_table.num_comp_vectors) {
506			priv->params_ethtool.channels =
507			    (u64) priv->mdev->priv.eq_table.num_comp_vectors;
508		}
509		priv->params.num_channels = priv->params_ethtool.channels;
510
511		/* restart network interface, if any */
512		if (was_opened)
513			mlx5e_open_locked(priv->ifp);
514		break;
515
516	case MLX5_PARAM_OFFSET(rx_coalesce_mode):
517		/* network interface must be down */
518		if (was_opened != 0 && mode_modify == 0)
519			mlx5e_close_locked(priv->ifp);
520
521		/* import RX coalesce mode */
522		if (priv->params_ethtool.rx_coalesce_mode != 0)
523			priv->params_ethtool.rx_coalesce_mode = 1;
524		priv->params.rx_cq_moderation_mode =
525		    priv->params_ethtool.rx_coalesce_mode;
526
527		/* restart network interface, if any */
528		if (was_opened != 0) {
529			if (mode_modify == 0)
530				mlx5e_open_locked(priv->ifp);
531			else
532				error = mlx5e_refresh_channel_params(priv);
533		}
534		break;
535
536	case MLX5_PARAM_OFFSET(tx_coalesce_mode):
537		/* network interface must be down */
538		if (was_opened != 0 && mode_modify == 0)
539			mlx5e_close_locked(priv->ifp);
540
541		/* import TX coalesce mode */
542		if (priv->params_ethtool.tx_coalesce_mode != 0)
543			priv->params_ethtool.tx_coalesce_mode = 1;
544		priv->params.tx_cq_moderation_mode =
545		    priv->params_ethtool.tx_coalesce_mode;
546
547		/* restart network interface, if any */
548		if (was_opened != 0) {
549			if (mode_modify == 0)
550				mlx5e_open_locked(priv->ifp);
551			else
552				error = mlx5e_refresh_channel_params(priv);
553		}
554		break;
555
556	case MLX5_PARAM_OFFSET(hw_lro):
557		/* network interface must be down */
558		if (was_opened)
559			mlx5e_close_locked(priv->ifp);
560
561		/* import HW LRO mode */
562		if (priv->params_ethtool.hw_lro != 0) {
563			if ((priv->ifp->if_capenable & IFCAP_LRO) &&
564			    MLX5_CAP_ETH(priv->mdev, lro_cap)) {
565				priv->params.hw_lro_en = 1;
566				priv->params_ethtool.hw_lro = 1;
567			} else {
568				priv->params.hw_lro_en = 0;
569				priv->params_ethtool.hw_lro = 0;
570				error = EINVAL;
571
572				if_printf(priv->ifp, "Can't enable HW LRO: "
573				    "The HW or SW LRO feature is disabled\n");
574			}
575		} else {
576			priv->params.hw_lro_en = 0;
577		}
578		/* restart network interface, if any */
579		if (was_opened)
580			mlx5e_open_locked(priv->ifp);
581		break;
582
583	case MLX5_PARAM_OFFSET(cqe_zipping):
584		/* network interface must be down */
585		if (was_opened)
586			mlx5e_close_locked(priv->ifp);
587
588		/* import CQE zipping mode */
589		if (priv->params_ethtool.cqe_zipping &&
590		    MLX5_CAP_GEN(priv->mdev, cqe_compression)) {
591			priv->params.cqe_zipping_en = true;
592			priv->params_ethtool.cqe_zipping = 1;
593		} else {
594			priv->params.cqe_zipping_en = false;
595			priv->params_ethtool.cqe_zipping = 0;
596		}
597		/* restart network interface, if any */
598		if (was_opened)
599			mlx5e_open_locked(priv->ifp);
600		break;
601
602	case MLX5_PARAM_OFFSET(tx_bufring_disable):
603		/* rangecheck input value */
604		priv->params_ethtool.tx_bufring_disable =
605		    priv->params_ethtool.tx_bufring_disable ? 1 : 0;
606
607		/* reconfigure the sendqueues, if any */
608		if (was_opened) {
609			mlx5e_close_locked(priv->ifp);
610			mlx5e_open_locked(priv->ifp);
611		}
612		break;
613
614	case MLX5_PARAM_OFFSET(tx_completion_fact):
615		/* network interface must be down */
616		if (was_opened)
617			mlx5e_close_locked(priv->ifp);
618
619		/* verify parameter */
620		mlx5e_ethtool_sync_tx_completion_fact(priv);
621
622		/* restart network interface, if any */
623		if (was_opened)
624			mlx5e_open_locked(priv->ifp);
625		break;
626
627	case MLX5_PARAM_OFFSET(modify_tx_dma):
628		/* check if network interface is opened */
629		if (was_opened) {
630			priv->params_ethtool.modify_tx_dma =
631			    priv->params_ethtool.modify_tx_dma ? 1 : 0;
632			/* modify tx according to value */
633			mlx5e_modify_tx_dma(priv, value != 0);
634		} else {
635			/* if closed force enable tx */
636			priv->params_ethtool.modify_tx_dma = 0;
637		}
638		break;
639
640	case MLX5_PARAM_OFFSET(modify_rx_dma):
641		/* check if network interface is opened */
642		if (was_opened) {
643			priv->params_ethtool.modify_rx_dma =
644			    priv->params_ethtool.modify_rx_dma ? 1 : 0;
645			/* modify rx according to value */
646			mlx5e_modify_rx_dma(priv, value != 0);
647		} else {
648			/* if closed force enable rx */
649			priv->params_ethtool.modify_rx_dma = 0;
650		}
651		break;
652
653	case MLX5_PARAM_OFFSET(diag_pci_enable):
654		priv->params_ethtool.diag_pci_enable =
655		    priv->params_ethtool.diag_pci_enable ? 1 : 0;
656
657		error = -mlx5_core_set_diagnostics_full(priv->mdev,
658		    priv->params_ethtool.diag_pci_enable,
659		    priv->params_ethtool.diag_general_enable);
660		break;
661
662	case MLX5_PARAM_OFFSET(diag_general_enable):
663		priv->params_ethtool.diag_general_enable =
664		    priv->params_ethtool.diag_general_enable ? 1 : 0;
665
666		error = -mlx5_core_set_diagnostics_full(priv->mdev,
667		    priv->params_ethtool.diag_pci_enable,
668		    priv->params_ethtool.diag_general_enable);
669		break;
670
671	case MLX5_PARAM_OFFSET(mc_local_lb):
672		priv->params_ethtool.mc_local_lb =
673		    priv->params_ethtool.mc_local_lb ? 1 : 0;
674
675		if (MLX5_CAP_GEN(priv->mdev, disable_local_lb)) {
676			error = mlx5_nic_vport_modify_local_lb(priv->mdev,
677			    MLX5_LOCAL_MC_LB, priv->params_ethtool.mc_local_lb);
678		} else {
679			error = EOPNOTSUPP;
680		}
681		break;
682
683	case MLX5_PARAM_OFFSET(uc_local_lb):
684		priv->params_ethtool.uc_local_lb =
685		    priv->params_ethtool.uc_local_lb ? 1 : 0;
686
687		if (MLX5_CAP_GEN(priv->mdev, disable_local_lb)) {
688			error = mlx5_nic_vport_modify_local_lb(priv->mdev,
689			    MLX5_LOCAL_UC_LB, priv->params_ethtool.uc_local_lb);
690		} else {
691			error = EOPNOTSUPP;
692		}
693		break;
694
695	default:
696		break;
697	}
698done:
699	PRIV_UNLOCK(priv);
700	return (error);
701}
702
703/*
704 * Read the first three bytes of the eeprom in order to get the needed info
705 * for the whole reading.
706 * Byte 0 - Identifier byte
707 * Byte 1 - Revision byte
708 * Byte 2 - Status byte
709 */
710static int
711mlx5e_get_eeprom_info(struct mlx5e_priv *priv, struct mlx5e_eeprom *eeprom)
712{
713	struct mlx5_core_dev *dev = priv->mdev;
714	u32 data = 0;
715	int size_read = 0;
716	int ret;
717
718	ret = mlx5_query_module_num(dev, &eeprom->module_num);
719	if (ret) {
720		if_printf(priv->ifp, "%s:%d: Failed query module error=%d\n",
721		    __func__, __LINE__, ret);
722		return (ret);
723	}
724
725	/* Read the first three bytes to get Identifier, Revision and Status */
726	ret = mlx5_query_eeprom(dev, eeprom->i2c_addr, eeprom->page_num,
727	    eeprom->device_addr, MLX5E_EEPROM_INFO_BYTES, eeprom->module_num, &data,
728	    &size_read);
729	if (ret) {
730		if_printf(priv->ifp, "%s:%d: Failed query eeprom module error=0x%x\n",
731		    __func__, __LINE__, ret);
732		return (ret);
733	}
734
735	switch (data & MLX5_EEPROM_IDENTIFIER_BYTE_MASK) {
736	case SFF_8024_ID_QSFP:
737		eeprom->type = MLX5E_ETH_MODULE_SFF_8436;
738		eeprom->len = MLX5E_ETH_MODULE_SFF_8436_LEN;
739		break;
740	case SFF_8024_ID_QSFPPLUS:
741	case SFF_8024_ID_QSFP28:
742		if ((data & MLX5_EEPROM_IDENTIFIER_BYTE_MASK) == SFF_8024_ID_QSFP28 ||
743		    ((data & MLX5_EEPROM_REVISION_ID_BYTE_MASK) >> 8) >= 0x3) {
744			eeprom->type = MLX5E_ETH_MODULE_SFF_8636;
745			eeprom->len = MLX5E_ETH_MODULE_SFF_8636_LEN;
746		} else {
747			eeprom->type = MLX5E_ETH_MODULE_SFF_8436;
748			eeprom->len = MLX5E_ETH_MODULE_SFF_8436_LEN;
749		}
750		if ((data & MLX5_EEPROM_PAGE_3_VALID_BIT_MASK) == 0)
751			eeprom->page_valid = 1;
752		break;
753	case SFF_8024_ID_SFP:
754		eeprom->type = MLX5E_ETH_MODULE_SFF_8472;
755		eeprom->len = MLX5E_ETH_MODULE_SFF_8472_LEN;
756		break;
757	default:
758		if_printf(priv->ifp, "%s:%d: Not recognized cable type = 0x%x(%s)\n",
759		    __func__, __LINE__, data & MLX5_EEPROM_IDENTIFIER_BYTE_MASK,
760		    sff_8024_id[data & MLX5_EEPROM_IDENTIFIER_BYTE_MASK]);
761		return (EINVAL);
762	}
763	return (0);
764}
765
766/* Read both low and high pages of the eeprom */
767static int
768mlx5e_get_eeprom(struct mlx5e_priv *priv, struct mlx5e_eeprom *ee)
769{
770	struct mlx5_core_dev *dev = priv->mdev;
771	int size_read = 0;
772	int ret;
773
774	if (ee->len == 0)
775		return (EINVAL);
776
777	/* Read low page of the eeprom */
778	while (ee->device_addr < ee->len) {
779		ret = mlx5_query_eeprom(dev, ee->i2c_addr, ee->page_num, ee->device_addr,
780		    ee->len - ee->device_addr, ee->module_num,
781		    ee->data + (ee->device_addr / 4), &size_read);
782		if (ret) {
783			if_printf(priv->ifp, "%s:%d: Failed reading eeprom, "
784			    "error = 0x%02x\n", __func__, __LINE__, ret);
785			return (ret);
786		}
787		ee->device_addr += size_read;
788	}
789
790	/* Read high page of the eeprom */
791	if (ee->page_valid) {
792		ee->device_addr = MLX5E_EEPROM_HIGH_PAGE_OFFSET;
793		ee->page_num = MLX5E_EEPROM_HIGH_PAGE;
794		size_read = 0;
795		while (ee->device_addr < MLX5E_EEPROM_PAGE_LENGTH) {
796			ret = mlx5_query_eeprom(dev, ee->i2c_addr, ee->page_num,
797			    ee->device_addr, MLX5E_EEPROM_PAGE_LENGTH - ee->device_addr,
798			    ee->module_num, ee->data + (ee->len / 4) +
799			    ((ee->device_addr - MLX5E_EEPROM_HIGH_PAGE_OFFSET) / 4),
800			    &size_read);
801			if (ret) {
802				if_printf(priv->ifp, "%s:%d: Failed reading eeprom, "
803				    "error = 0x%02x\n", __func__, __LINE__, ret);
804				return (ret);
805			}
806			ee->device_addr += size_read;
807		}
808	}
809	return (0);
810}
811
812static void
813mlx5e_print_eeprom(struct mlx5e_eeprom *eeprom)
814{
815	int row;
816	int index_in_row;
817	int byte_to_write = 0;
818	int line_length = 16;
819
820	printf("\nOffset\t\tValues\n");
821	printf("------\t\t------");
822	while (byte_to_write < eeprom->len) {
823		printf("\n0x%04X\t\t", byte_to_write);
824		for (index_in_row = 0; index_in_row < line_length; index_in_row++) {
825			printf("%02X ", ((u8 *)eeprom->data)[byte_to_write]);
826			byte_to_write++;
827		}
828	}
829
830	if (eeprom->page_valid) {
831		row = MLX5E_EEPROM_HIGH_PAGE_OFFSET;
832		printf("\n\nUpper Page 0x03\n");
833		printf("\nOffset\t\tValues\n");
834		printf("------\t\t------");
835		while (row < MLX5E_EEPROM_PAGE_LENGTH) {
836			printf("\n0x%04X\t\t", row);
837			for (index_in_row = 0; index_in_row < line_length; index_in_row++) {
838				printf("%02X ", ((u8 *)eeprom->data)[byte_to_write]);
839				byte_to_write++;
840				row++;
841			}
842		}
843	}
844}
845
846/*
847 * Read cable EEPROM module information by first inspecting the first
848 * three bytes to get the initial information for a whole reading.
849 * Information will be printed to dmesg.
850 */
851static int
852mlx5e_read_eeprom(SYSCTL_HANDLER_ARGS)
853{
854	struct mlx5e_priv *priv = arg1;
855	struct mlx5e_eeprom eeprom;
856	int error;
857	int result = 0;
858
859	PRIV_LOCK(priv);
860	error = sysctl_handle_int(oidp, &result, 0, req);
861	if (error || !req->newptr)
862		goto done;
863
864	/* Check if device is gone */
865	if (priv->gone) {
866		error = ENXIO;
867		goto done;
868	}
869
870	if (result == 1) {
871		eeprom.i2c_addr = MLX5E_I2C_ADDR_LOW;
872		eeprom.device_addr = 0;
873		eeprom.page_num = MLX5E_EEPROM_LOW_PAGE;
874		eeprom.page_valid = 0;
875
876		/* Read three first bytes to get important info */
877		error = mlx5e_get_eeprom_info(priv, &eeprom);
878		if (error) {
879			if_printf(priv->ifp, "%s:%d: Failed reading eeprom's "
880			    "initial information\n", __func__, __LINE__);
881			error = 0;
882			goto done;
883		}
884		/*
885		 * Allocate needed length buffer and additional space for
886		 * page 0x03
887		 */
888		eeprom.data = malloc(eeprom.len + MLX5E_EEPROM_PAGE_LENGTH,
889		    M_MLX5EN, M_WAITOK | M_ZERO);
890
891		/* Read the whole eeprom information */
892		error = mlx5e_get_eeprom(priv, &eeprom);
893		if (error) {
894			if_printf(priv->ifp, "%s:%d: Failed reading eeprom\n",
895			    __func__, __LINE__);
896			error = 0;
897			/*
898			 * Continue printing partial information in case of
899			 * an error
900			 */
901		}
902		mlx5e_print_eeprom(&eeprom);
903		free(eeprom.data, M_MLX5EN);
904	}
905done:
906	PRIV_UNLOCK(priv);
907	return (error);
908}
909
910static const char *mlx5e_params_desc[] = {
911	MLX5E_PARAMS(MLX5E_STATS_DESC)
912};
913
914static const char *mlx5e_port_stats_debug_desc[] = {
915	MLX5E_PORT_STATS_DEBUG(MLX5E_STATS_DESC)
916};
917
918static int
919mlx5e_ethtool_debug_channel_info(SYSCTL_HANDLER_ARGS)
920{
921	struct mlx5e_priv *priv;
922	struct sbuf sb;
923	struct mlx5e_channel *c;
924	struct mlx5e_sq *sq;
925	struct mlx5e_rq *rq;
926	int error, i, tc;
927
928	priv = arg1;
929	error = sysctl_wire_old_buffer(req, 0);
930	if (error != 0)
931		return (error);
932	if (sbuf_new_for_sysctl(&sb, NULL, 128, req) == NULL)
933		return (ENOMEM);
934	sbuf_clear_flags(&sb, SBUF_INCLUDENUL);
935
936	PRIV_LOCK(priv);
937	if (test_bit(MLX5E_STATE_OPENED, &priv->state) == 0)
938		goto out;
939	for (i = 0; i < priv->params.num_channels; i++) {
940		c = priv->channel[i];
941		rq = &c->rq;
942		sbuf_printf(&sb, "channel %d rq %d cq %d\n",
943		    c->ix, rq->rqn, rq->cq.mcq.cqn);
944		for (tc = 0; tc < c->num_tc; tc++) {
945			sq = &c->sq[tc];
946			sbuf_printf(&sb, "channel %d tc %d sq %d cq %d\n",
947			    c->ix, tc, sq->sqn, sq->cq.mcq.cqn);
948		}
949	}
950out:
951	PRIV_UNLOCK(priv);
952	error = sbuf_finish(&sb);
953	sbuf_delete(&sb);
954	return (error);
955}
956
957static int
958mlx5e_ethtool_debug_stats(SYSCTL_HANDLER_ARGS)
959{
960	struct mlx5e_priv *priv = arg1;
961	int error, sys_debug;
962
963	sys_debug = priv->sysctl_debug;
964	error = sysctl_handle_int(oidp, &priv->sysctl_debug, 0, req);
965	if (error != 0 || !req->newptr)
966		return (error);
967	priv->sysctl_debug = priv->sysctl_debug != 0;
968	if (sys_debug == priv->sysctl_debug)
969		return (0);
970
971	PRIV_LOCK(priv);
972	if (priv->sysctl_debug) {
973		mlx5e_create_stats(&priv->stats.port_stats_debug.ctx,
974		    SYSCTL_CHILDREN(priv->sysctl_ifnet), "debug_stats",
975		    mlx5e_port_stats_debug_desc, MLX5E_PORT_STATS_DEBUG_NUM,
976		    priv->stats.port_stats_debug.arg);
977		SYSCTL_ADD_PROC(&priv->sysctl_ctx_channel_debug,
978		    SYSCTL_CHILDREN(priv->sysctl_ifnet), OID_AUTO,
979		    "hw_ctx_debug",
980		    CTLFLAG_RD | CTLFLAG_MPSAFE | CTLTYPE_STRING, priv, 0,
981		    mlx5e_ethtool_debug_channel_info, "S", "");
982	} else {
983		sysctl_ctx_free(&priv->stats.port_stats_debug.ctx);
984		sysctl_ctx_free(&priv->sysctl_ctx_channel_debug);
985	}
986	PRIV_UNLOCK(priv);
987	return (0);
988}
989
990static void
991mlx5e_create_diagnostics(struct mlx5e_priv *priv)
992{
993	struct mlx5_core_diagnostics_entry entry;
994	struct sysctl_ctx_list *ctx;
995	struct sysctl_oid *node;
996	int x;
997
998	/* sysctl context we are using */
999	ctx = &priv->sysctl_ctx;
1000
1001	/* create root node */
1002	node = SYSCTL_ADD_NODE(ctx,
1003	    SYSCTL_CHILDREN(priv->sysctl_ifnet), OID_AUTO,
1004	    "diagnostics", CTLFLAG_RD, NULL, "Diagnostics");
1005	if (node == NULL)
1006		return;
1007
1008	/* create PCI diagnostics */
1009	for (x = 0; x != MLX5_CORE_PCI_DIAGNOSTICS_NUM; x++) {
1010		entry = mlx5_core_pci_diagnostics_table[x];
1011		if (mlx5_core_supports_diagnostics(priv->mdev, entry.counter_id) == 0)
1012			continue;
1013		SYSCTL_ADD_UQUAD(ctx, SYSCTL_CHILDREN(node), OID_AUTO,
1014		    entry.desc, CTLFLAG_RD, priv->params_pci.array + x,
1015		    "PCI diagnostics counter");
1016	}
1017
1018	/* create general diagnostics */
1019	for (x = 0; x != MLX5_CORE_GENERAL_DIAGNOSTICS_NUM; x++) {
1020		entry = mlx5_core_general_diagnostics_table[x];
1021		if (mlx5_core_supports_diagnostics(priv->mdev, entry.counter_id) == 0)
1022			continue;
1023		SYSCTL_ADD_UQUAD(ctx, SYSCTL_CHILDREN(node), OID_AUTO,
1024		    entry.desc, CTLFLAG_RD, priv->params_general.array + x,
1025		    "General diagnostics counter");
1026	}
1027}
1028
1029void
1030mlx5e_create_ethtool(struct mlx5e_priv *priv)
1031{
1032	struct mlx5_core_dev *mdev = priv->mdev;
1033	struct sysctl_oid *node, *qos_node;
1034	const char *pnameunit;
1035	unsigned x;
1036	int i;
1037
1038	/* set some defaults */
1039	priv->params_ethtool.tx_queue_size_max = 1 << MLX5E_PARAMS_MAXIMUM_LOG_SQ_SIZE;
1040	priv->params_ethtool.rx_queue_size_max = 1 << MLX5E_PARAMS_MAXIMUM_LOG_RQ_SIZE;
1041	priv->params_ethtool.tx_queue_size = 1 << priv->params.log_sq_size;
1042	priv->params_ethtool.rx_queue_size = 1 << priv->params.log_rq_size;
1043	priv->params_ethtool.channels = priv->params.num_channels;
1044	priv->params_ethtool.coalesce_pkts_max = MLX5E_FLD_MAX(cqc, cq_max_count);
1045	priv->params_ethtool.coalesce_usecs_max = MLX5E_FLD_MAX(cqc, cq_period);
1046	priv->params_ethtool.rx_coalesce_mode = priv->params.rx_cq_moderation_mode;
1047	priv->params_ethtool.rx_coalesce_usecs = priv->params.rx_cq_moderation_usec;
1048	priv->params_ethtool.rx_coalesce_pkts = priv->params.rx_cq_moderation_pkts;
1049	priv->params_ethtool.tx_coalesce_mode = priv->params.tx_cq_moderation_mode;
1050	priv->params_ethtool.tx_coalesce_usecs = priv->params.tx_cq_moderation_usec;
1051	priv->params_ethtool.tx_coalesce_pkts = priv->params.tx_cq_moderation_pkts;
1052	priv->params_ethtool.hw_lro = priv->params.hw_lro_en;
1053	priv->params_ethtool.cqe_zipping = priv->params.cqe_zipping_en;
1054	mlx5e_ethtool_sync_tx_completion_fact(priv);
1055
1056	/* get default values for local loopback, if any */
1057	if (MLX5_CAP_GEN(priv->mdev, disable_local_lb)) {
1058		int err;
1059		u8 val;
1060
1061		err = mlx5_nic_vport_query_local_lb(priv->mdev, MLX5_LOCAL_MC_LB, &val);
1062		if (err == 0)
1063			priv->params_ethtool.mc_local_lb = val;
1064
1065		err = mlx5_nic_vport_query_local_lb(priv->mdev, MLX5_LOCAL_UC_LB, &val);
1066		if (err == 0)
1067			priv->params_ethtool.uc_local_lb = val;
1068	}
1069
1070	/* create root node */
1071	node = SYSCTL_ADD_NODE(&priv->sysctl_ctx,
1072	    SYSCTL_CHILDREN(priv->sysctl_ifnet), OID_AUTO,
1073	    "conf", CTLFLAG_RW, NULL, "Configuration");
1074	if (node == NULL)
1075		return;
1076	for (x = 0; x != MLX5E_PARAMS_NUM; x++) {
1077		/* check for read-only parameter */
1078		if (strstr(mlx5e_params_desc[2 * x], "_max") != NULL ||
1079		    strstr(mlx5e_params_desc[2 * x], "_mtu") != NULL) {
1080			SYSCTL_ADD_PROC(&priv->sysctl_ctx, SYSCTL_CHILDREN(node), OID_AUTO,
1081			    mlx5e_params_desc[2 * x], CTLTYPE_U64 | CTLFLAG_RD |
1082			    CTLFLAG_MPSAFE, priv, x, &mlx5e_ethtool_handler, "QU",
1083			    mlx5e_params_desc[2 * x + 1]);
1084		} else {
1085#if (__FreeBSD_version < 1100000)
1086			char path[64];
1087#endif
1088			/*
1089			 * NOTE: In FreeBSD-11 and newer the
1090			 * CTLFLAG_RWTUN flag will take care of
1091			 * loading default sysctl value from the
1092			 * kernel environment, if any:
1093			 */
1094			SYSCTL_ADD_PROC(&priv->sysctl_ctx, SYSCTL_CHILDREN(node), OID_AUTO,
1095			    mlx5e_params_desc[2 * x], CTLTYPE_U64 | CTLFLAG_RWTUN |
1096			    CTLFLAG_MPSAFE, priv, x, &mlx5e_ethtool_handler, "QU",
1097			    mlx5e_params_desc[2 * x + 1]);
1098
1099#if (__FreeBSD_version < 1100000)
1100			/* compute path for sysctl */
1101			snprintf(path, sizeof(path), "dev.mce.%d.conf.%s",
1102			    device_get_unit(priv->mdev->pdev->dev.bsddev),
1103			    mlx5e_params_desc[2 * x]);
1104
1105			/* try to fetch tunable, if any */
1106			if (TUNABLE_QUAD_FETCH(path, &priv->params_ethtool.arg[x]))
1107				mlx5e_ethtool_handler(NULL, priv, x, NULL);
1108#endif
1109		}
1110	}
1111
1112	SYSCTL_ADD_PROC(&priv->sysctl_ctx, SYSCTL_CHILDREN(node), OID_AUTO,
1113	    "debug_stats", CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, priv,
1114	    0, &mlx5e_ethtool_debug_stats, "I", "Extended debug statistics");
1115
1116	pnameunit = device_get_nameunit(priv->mdev->pdev->dev.bsddev);
1117
1118	SYSCTL_ADD_STRING(&priv->sysctl_ctx, SYSCTL_CHILDREN(node),
1119	    OID_AUTO, "device_name", CTLFLAG_RD,
1120	    __DECONST(void *, pnameunit), 0,
1121	    "PCI device name");
1122
1123	/* EEPROM support */
1124	SYSCTL_ADD_PROC(&priv->sysctl_ctx, SYSCTL_CHILDREN(node), OID_AUTO, "eeprom_info",
1125	    CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, priv, 0,
1126	    mlx5e_read_eeprom, "I", "EEPROM information");
1127
1128	/* Diagnostics support */
1129	mlx5e_create_diagnostics(priv);
1130
1131	/* create qos node */
1132	qos_node = SYSCTL_ADD_NODE(&priv->sysctl_ctx,
1133	    SYSCTL_CHILDREN(node), OID_AUTO,
1134	    "qos", CTLFLAG_RW, NULL, "Quality Of Service configuration");
1135	if (node == NULL)
1136		return;
1137
1138	/* Prioriry rate limit support */
1139	if (mlx5e_getmaxrate(priv))
1140		return;
1141
1142	for (i = 0; i <= mlx5_max_tc(mdev); i++) {
1143		char name[32];
1144		snprintf(name, sizeof(name), "tc_%d_max_rate", i);
1145		SYSCTL_ADD_PROC(&priv->sysctl_ctx, SYSCTL_CHILDREN(qos_node),
1146				OID_AUTO, name, CTLTYPE_U64 | CTLFLAG_RW | CTLFLAG_MPSAFE,
1147				priv, i, mlx5e_tc_maxrate_handler, "QU",
1148				"Max rate for priority, specified in kilobits, where kilo=1000, \
1149				max_rate must be divisible by 100000");
1150	}
1151
1152	if (mlx5e_get_prio_tc(priv))
1153		return;
1154
1155	for (i = 0; i <= mlx5_max_tc(mdev); i++) {
1156		char name[32];
1157		snprintf(name, sizeof(name), "prio_%d_to_tc", i);
1158		SYSCTL_ADD_PROC(&priv->sysctl_ctx, SYSCTL_CHILDREN(qos_node),
1159				OID_AUTO, name, CTLTYPE_U8 | CTLFLAG_RW | CTLFLAG_MPSAFE,
1160				priv, i, mlx5e_prio_to_tc_handler, "CU",
1161				"Set priority to traffic class");
1162	}
1163
1164	/* DSCP support */
1165	if (mlx5e_get_dscp(priv) == 0) {
1166		for (i = 0; i != MLX5_MAX_SUPPORTED_DSCP; i += 8) {
1167			char name[32];
1168			snprintf(name, sizeof(name), "dscp_%d_%d_prio", i, i + 7);
1169			SYSCTL_ADD_PROC(&priv->sysctl_ctx, SYSCTL_CHILDREN(qos_node),
1170				OID_AUTO, name, CTLTYPE_U8 | CTLFLAG_RWTUN | CTLFLAG_MPSAFE,
1171				priv, i, mlx5e_dscp_prio_handler, "CU",
1172				"Set DSCP to priority mapping, 0..7");
1173		}
1174#define	A	"Set trust state, 1:PCP 2:DSCP"
1175#define	B	" 3:BOTH"
1176		SYSCTL_ADD_PROC(&priv->sysctl_ctx, SYSCTL_CHILDREN(qos_node),
1177		    OID_AUTO, "trust_state", CTLTYPE_U8 | CTLFLAG_RWTUN | CTLFLAG_MPSAFE,
1178		    priv, 0, mlx5e_trust_state_handler, "CU",
1179		    MLX5_CAP_QCAM_FEATURE(mdev, qpts_trust_both) ?
1180		    A B : A);
1181#undef B
1182#undef A
1183	}
1184}
1185