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