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