mlx5_en_ethtool.c revision 341977
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 341977 2018-12-12 13:05:45Z 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			if ((priv->ifp->if_capenable & IFCAP_LRO) &&
674			    MLX5_CAP_ETH(priv->mdev, lro_cap)) {
675				priv->params.hw_lro_en = 1;
676				priv->params_ethtool.hw_lro = 1;
677			} else {
678				priv->params.hw_lro_en = 0;
679				priv->params_ethtool.hw_lro = 0;
680				error = EINVAL;
681
682				if_printf(priv->ifp, "Can't enable HW LRO: "
683				    "The HW or SW LRO feature is disabled\n");
684			}
685		} else {
686			priv->params.hw_lro_en = 0;
687		}
688		/* restart network interface, if any */
689		if (was_opened)
690			mlx5e_open_locked(priv->ifp);
691		break;
692
693	case MLX5_PARAM_OFFSET(cqe_zipping):
694		/* network interface must be down */
695		if (was_opened)
696			mlx5e_close_locked(priv->ifp);
697
698		/* import CQE zipping mode */
699		if (priv->params_ethtool.cqe_zipping &&
700		    MLX5_CAP_GEN(priv->mdev, cqe_compression)) {
701			priv->params.cqe_zipping_en = true;
702			priv->params_ethtool.cqe_zipping = 1;
703		} else {
704			priv->params.cqe_zipping_en = false;
705			priv->params_ethtool.cqe_zipping = 0;
706		}
707		/* restart network interface, if any */
708		if (was_opened)
709			mlx5e_open_locked(priv->ifp);
710		break;
711
712	case MLX5_PARAM_OFFSET(tx_completion_fact):
713		/* network interface must be down */
714		if (was_opened)
715			mlx5e_close_locked(priv->ifp);
716
717		/* verify parameter */
718		mlx5e_ethtool_sync_tx_completion_fact(priv);
719
720		/* restart network interface, if any */
721		if (was_opened)
722			mlx5e_open_locked(priv->ifp);
723		break;
724
725	case MLX5_PARAM_OFFSET(modify_tx_dma):
726		/* check if network interface is opened */
727		if (was_opened) {
728			priv->params_ethtool.modify_tx_dma =
729			    priv->params_ethtool.modify_tx_dma ? 1 : 0;
730			/* modify tx according to value */
731			mlx5e_modify_tx_dma(priv, value != 0);
732		} else {
733			/* if closed force enable tx */
734			priv->params_ethtool.modify_tx_dma = 0;
735		}
736		break;
737
738	case MLX5_PARAM_OFFSET(modify_rx_dma):
739		/* check if network interface is opened */
740		if (was_opened) {
741			priv->params_ethtool.modify_rx_dma =
742			    priv->params_ethtool.modify_rx_dma ? 1 : 0;
743			/* modify rx according to value */
744			mlx5e_modify_rx_dma(priv, value != 0);
745		} else {
746			/* if closed force enable rx */
747			priv->params_ethtool.modify_rx_dma = 0;
748		}
749		break;
750
751	case MLX5_PARAM_OFFSET(diag_pci_enable):
752		priv->params_ethtool.diag_pci_enable =
753		    priv->params_ethtool.diag_pci_enable ? 1 : 0;
754
755		error = -mlx5_core_set_diagnostics_full(priv->mdev,
756		    priv->params_ethtool.diag_pci_enable,
757		    priv->params_ethtool.diag_general_enable);
758		break;
759
760	case MLX5_PARAM_OFFSET(diag_general_enable):
761		priv->params_ethtool.diag_general_enable =
762		    priv->params_ethtool.diag_general_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(mc_local_lb):
770		priv->params_ethtool.mc_local_lb =
771		    priv->params_ethtool.mc_local_lb ? 1 : 0;
772
773		if (MLX5_CAP_GEN(priv->mdev, disable_local_lb)) {
774			error = mlx5_nic_vport_modify_local_lb(priv->mdev,
775			    MLX5_LOCAL_MC_LB, priv->params_ethtool.mc_local_lb);
776		} else {
777			error = EOPNOTSUPP;
778		}
779		break;
780
781	case MLX5_PARAM_OFFSET(uc_local_lb):
782		priv->params_ethtool.uc_local_lb =
783		    priv->params_ethtool.uc_local_lb ? 1 : 0;
784
785		if (MLX5_CAP_GEN(priv->mdev, disable_local_lb)) {
786			error = mlx5_nic_vport_modify_local_lb(priv->mdev,
787			    MLX5_LOCAL_UC_LB, priv->params_ethtool.uc_local_lb);
788		} else {
789			error = EOPNOTSUPP;
790		}
791		break;
792
793	default:
794		break;
795	}
796done:
797	PRIV_UNLOCK(priv);
798	return (error);
799}
800
801/*
802 * Read the first three bytes of the eeprom in order to get the needed info
803 * for the whole reading.
804 * Byte 0 - Identifier byte
805 * Byte 1 - Revision byte
806 * Byte 2 - Status byte
807 */
808static int
809mlx5e_get_eeprom_info(struct mlx5e_priv *priv, struct mlx5e_eeprom *eeprom)
810{
811	struct mlx5_core_dev *dev = priv->mdev;
812	u32 data = 0;
813	int size_read = 0;
814	int ret;
815
816	ret = mlx5_query_module_num(dev, &eeprom->module_num);
817	if (ret) {
818		if_printf(priv->ifp, "%s:%d: Failed query module error=%d\n",
819		    __func__, __LINE__, ret);
820		return (ret);
821	}
822
823	/* Read the first three bytes to get Identifier, Revision and Status */
824	ret = mlx5_query_eeprom(dev, eeprom->i2c_addr, eeprom->page_num,
825	    eeprom->device_addr, MLX5E_EEPROM_INFO_BYTES, eeprom->module_num, &data,
826	    &size_read);
827	if (ret) {
828		if_printf(priv->ifp, "%s:%d: Failed query eeprom module error=0x%x\n",
829		    __func__, __LINE__, ret);
830		return (ret);
831	}
832
833	switch (data & MLX5_EEPROM_IDENTIFIER_BYTE_MASK) {
834	case SFF_8024_ID_QSFP:
835		eeprom->type = MLX5E_ETH_MODULE_SFF_8436;
836		eeprom->len = MLX5E_ETH_MODULE_SFF_8436_LEN;
837		break;
838	case SFF_8024_ID_QSFPPLUS:
839	case SFF_8024_ID_QSFP28:
840		if ((data & MLX5_EEPROM_IDENTIFIER_BYTE_MASK) == SFF_8024_ID_QSFP28 ||
841		    ((data & MLX5_EEPROM_REVISION_ID_BYTE_MASK) >> 8) >= 0x3) {
842			eeprom->type = MLX5E_ETH_MODULE_SFF_8636;
843			eeprom->len = MLX5E_ETH_MODULE_SFF_8636_LEN;
844		} else {
845			eeprom->type = MLX5E_ETH_MODULE_SFF_8436;
846			eeprom->len = MLX5E_ETH_MODULE_SFF_8436_LEN;
847		}
848		if ((data & MLX5_EEPROM_PAGE_3_VALID_BIT_MASK) == 0)
849			eeprom->page_valid = 1;
850		break;
851	case SFF_8024_ID_SFP:
852		eeprom->type = MLX5E_ETH_MODULE_SFF_8472;
853		eeprom->len = MLX5E_ETH_MODULE_SFF_8472_LEN;
854		break;
855	default:
856		if_printf(priv->ifp, "%s:%d: Not recognized cable type = 0x%x(%s)\n",
857		    __func__, __LINE__, data & MLX5_EEPROM_IDENTIFIER_BYTE_MASK,
858		    sff_8024_id[data & MLX5_EEPROM_IDENTIFIER_BYTE_MASK]);
859		return (EINVAL);
860	}
861	return (0);
862}
863
864/* Read both low and high pages of the eeprom */
865static int
866mlx5e_get_eeprom(struct mlx5e_priv *priv, struct mlx5e_eeprom *ee)
867{
868	struct mlx5_core_dev *dev = priv->mdev;
869	int size_read = 0;
870	int ret;
871
872	if (ee->len == 0)
873		return (EINVAL);
874
875	/* Read low page of the eeprom */
876	while (ee->device_addr < ee->len) {
877		ret = mlx5_query_eeprom(dev, ee->i2c_addr, ee->page_num, ee->device_addr,
878		    ee->len - ee->device_addr, ee->module_num,
879		    ee->data + (ee->device_addr / 4), &size_read);
880		if (ret) {
881			if_printf(priv->ifp, "%s:%d: Failed reading eeprom, "
882			    "error = 0x%02x\n", __func__, __LINE__, ret);
883			return (ret);
884		}
885		ee->device_addr += size_read;
886	}
887
888	/* Read high page of the eeprom */
889	if (ee->page_valid) {
890		ee->device_addr = MLX5E_EEPROM_HIGH_PAGE_OFFSET;
891		ee->page_num = MLX5E_EEPROM_HIGH_PAGE;
892		size_read = 0;
893		while (ee->device_addr < MLX5E_EEPROM_PAGE_LENGTH) {
894			ret = mlx5_query_eeprom(dev, ee->i2c_addr, ee->page_num,
895			    ee->device_addr, MLX5E_EEPROM_PAGE_LENGTH - ee->device_addr,
896			    ee->module_num, ee->data + (ee->len / 4) +
897			    ((ee->device_addr - MLX5E_EEPROM_HIGH_PAGE_OFFSET) / 4),
898			    &size_read);
899			if (ret) {
900				if_printf(priv->ifp, "%s:%d: Failed reading eeprom, "
901				    "error = 0x%02x\n", __func__, __LINE__, ret);
902				return (ret);
903			}
904			ee->device_addr += size_read;
905		}
906	}
907	return (0);
908}
909
910static void
911mlx5e_print_eeprom(struct mlx5e_eeprom *eeprom)
912{
913	int row;
914	int index_in_row;
915	int byte_to_write = 0;
916	int line_length = 16;
917
918	printf("\nOffset\t\tValues\n");
919	printf("------\t\t------");
920	while (byte_to_write < eeprom->len) {
921		printf("\n0x%04X\t\t", byte_to_write);
922		for (index_in_row = 0; index_in_row < line_length; index_in_row++) {
923			printf("%02X ", ((u8 *)eeprom->data)[byte_to_write]);
924			byte_to_write++;
925		}
926	}
927
928	if (eeprom->page_valid) {
929		row = MLX5E_EEPROM_HIGH_PAGE_OFFSET;
930		printf("\n\nUpper Page 0x03\n");
931		printf("\nOffset\t\tValues\n");
932		printf("------\t\t------");
933		while (row < MLX5E_EEPROM_PAGE_LENGTH) {
934			printf("\n0x%04X\t\t", row);
935			for (index_in_row = 0; index_in_row < line_length; index_in_row++) {
936				printf("%02X ", ((u8 *)eeprom->data)[byte_to_write]);
937				byte_to_write++;
938				row++;
939			}
940		}
941	}
942}
943
944/*
945 * Read cable EEPROM module information by first inspecting the first
946 * three bytes to get the initial information for a whole reading.
947 * Information will be printed to dmesg.
948 */
949static int
950mlx5e_read_eeprom(SYSCTL_HANDLER_ARGS)
951{
952	struct mlx5e_priv *priv = arg1;
953	struct mlx5e_eeprom eeprom;
954	int error;
955	int result = 0;
956
957	PRIV_LOCK(priv);
958	error = sysctl_handle_int(oidp, &result, 0, req);
959	if (error || !req->newptr)
960		goto done;
961
962	/* Check if device is gone */
963	if (priv->gone) {
964		error = ENXIO;
965		goto done;
966	}
967
968	if (result == 1) {
969		eeprom.i2c_addr = MLX5E_I2C_ADDR_LOW;
970		eeprom.device_addr = 0;
971		eeprom.page_num = MLX5E_EEPROM_LOW_PAGE;
972		eeprom.page_valid = 0;
973
974		/* Read three first bytes to get important info */
975		error = mlx5e_get_eeprom_info(priv, &eeprom);
976		if (error) {
977			if_printf(priv->ifp, "%s:%d: Failed reading eeprom's "
978			    "initial information\n", __func__, __LINE__);
979			error = 0;
980			goto done;
981		}
982		/*
983		 * Allocate needed length buffer and additional space for
984		 * page 0x03
985		 */
986		eeprom.data = malloc(eeprom.len + MLX5E_EEPROM_PAGE_LENGTH,
987		    M_MLX5EN, M_WAITOK | M_ZERO);
988
989		/* Read the whole eeprom information */
990		error = mlx5e_get_eeprom(priv, &eeprom);
991		if (error) {
992			if_printf(priv->ifp, "%s:%d: Failed reading eeprom\n",
993			    __func__, __LINE__);
994			error = 0;
995			/*
996			 * Continue printing partial information in case of
997			 * an error
998			 */
999		}
1000		mlx5e_print_eeprom(&eeprom);
1001		free(eeprom.data, M_MLX5EN);
1002	}
1003done:
1004	PRIV_UNLOCK(priv);
1005	return (error);
1006}
1007
1008static const char *mlx5e_params_desc[] = {
1009	MLX5E_PARAMS(MLX5E_STATS_DESC)
1010};
1011
1012static const char *mlx5e_port_stats_debug_desc[] = {
1013	MLX5E_PORT_STATS_DEBUG(MLX5E_STATS_DESC)
1014};
1015
1016static int
1017mlx5e_ethtool_debug_channel_info(SYSCTL_HANDLER_ARGS)
1018{
1019	struct mlx5e_priv *priv;
1020	struct sbuf sb;
1021	struct mlx5e_channel *c;
1022	struct mlx5e_sq *sq;
1023	struct mlx5e_rq *rq;
1024	int error, i, tc;
1025
1026	priv = arg1;
1027	error = sysctl_wire_old_buffer(req, 0);
1028	if (error != 0)
1029		return (error);
1030	if (sbuf_new_for_sysctl(&sb, NULL, 128, req) == NULL)
1031		return (ENOMEM);
1032	sbuf_clear_flags(&sb, SBUF_INCLUDENUL);
1033
1034	PRIV_LOCK(priv);
1035	if (test_bit(MLX5E_STATE_OPENED, &priv->state) == 0)
1036		goto out;
1037	for (i = 0; i < priv->params.num_channels; i++) {
1038		c = priv->channel[i];
1039		rq = &c->rq;
1040		sbuf_printf(&sb, "channel %d rq %d cq %d\n",
1041		    c->ix, rq->rqn, rq->cq.mcq.cqn);
1042		for (tc = 0; tc < c->num_tc; tc++) {
1043			sq = &c->sq[tc];
1044			sbuf_printf(&sb, "channel %d tc %d sq %d cq %d\n",
1045			    c->ix, tc, sq->sqn, sq->cq.mcq.cqn);
1046		}
1047	}
1048out:
1049	PRIV_UNLOCK(priv);
1050	error = sbuf_finish(&sb);
1051	sbuf_delete(&sb);
1052	return (error);
1053}
1054
1055static int
1056mlx5e_ethtool_debug_stats(SYSCTL_HANDLER_ARGS)
1057{
1058	struct mlx5e_priv *priv = arg1;
1059	int sys_debug;
1060	int error;
1061
1062	PRIV_LOCK(priv);
1063	sys_debug = priv->sysctl_debug;
1064	error = sysctl_handle_int(oidp, &sys_debug, 0, req);
1065	if (error != 0 || !req->newptr)
1066		goto done;
1067	sys_debug = sys_debug ? 1 : 0;
1068	if (sys_debug == priv->sysctl_debug)
1069		goto done;
1070
1071	if ((priv->sysctl_debug = sys_debug)) {
1072		mlx5e_create_stats(&priv->stats.port_stats_debug.ctx,
1073		    SYSCTL_CHILDREN(priv->sysctl_ifnet), "debug_stats",
1074		    mlx5e_port_stats_debug_desc, MLX5E_PORT_STATS_DEBUG_NUM,
1075		    priv->stats.port_stats_debug.arg);
1076		SYSCTL_ADD_PROC(&priv->stats.port_stats_debug.ctx,
1077		    SYSCTL_CHILDREN(priv->sysctl_ifnet), OID_AUTO,
1078		    "hw_ctx_debug",
1079		    CTLFLAG_RD | CTLFLAG_MPSAFE | CTLTYPE_STRING, priv, 0,
1080		    mlx5e_ethtool_debug_channel_info, "S", "");
1081	} else {
1082		sysctl_ctx_free(&priv->stats.port_stats_debug.ctx);
1083	}
1084done:
1085	PRIV_UNLOCK(priv);
1086	return (error);
1087}
1088
1089static void
1090mlx5e_create_diagnostics(struct mlx5e_priv *priv)
1091{
1092	struct mlx5_core_diagnostics_entry entry;
1093	struct sysctl_ctx_list *ctx;
1094	struct sysctl_oid *node;
1095	int x;
1096
1097	/* sysctl context we are using */
1098	ctx = &priv->sysctl_ctx;
1099
1100	/* create root node */
1101	node = SYSCTL_ADD_NODE(ctx,
1102	    SYSCTL_CHILDREN(priv->sysctl_ifnet), OID_AUTO,
1103	    "diagnostics", CTLFLAG_RD, NULL, "Diagnostics");
1104	if (node == NULL)
1105		return;
1106
1107	/* create PCI diagnostics */
1108	for (x = 0; x != MLX5_CORE_PCI_DIAGNOSTICS_NUM; x++) {
1109		entry = mlx5_core_pci_diagnostics_table[x];
1110		if (mlx5_core_supports_diagnostics(priv->mdev, entry.counter_id) == 0)
1111			continue;
1112		SYSCTL_ADD_UQUAD(ctx, SYSCTL_CHILDREN(node), OID_AUTO,
1113		    entry.desc, CTLFLAG_RD, priv->params_pci.array + x,
1114		    "PCI diagnostics counter");
1115	}
1116
1117	/* create general diagnostics */
1118	for (x = 0; x != MLX5_CORE_GENERAL_DIAGNOSTICS_NUM; x++) {
1119		entry = mlx5_core_general_diagnostics_table[x];
1120		if (mlx5_core_supports_diagnostics(priv->mdev, entry.counter_id) == 0)
1121			continue;
1122		SYSCTL_ADD_UQUAD(ctx, SYSCTL_CHILDREN(node), OID_AUTO,
1123		    entry.desc, CTLFLAG_RD, priv->params_general.array + x,
1124		    "General diagnostics counter");
1125	}
1126}
1127
1128void
1129mlx5e_create_ethtool(struct mlx5e_priv *priv)
1130{
1131	struct mlx5_core_dev *mdev = priv->mdev;
1132	struct sysctl_oid *node, *qos_node;
1133	const char *pnameunit;
1134	unsigned x;
1135	int i;
1136
1137	/* set some defaults */
1138	priv->params_ethtool.tx_queue_size_max = 1 << MLX5E_PARAMS_MAXIMUM_LOG_SQ_SIZE;
1139	priv->params_ethtool.rx_queue_size_max = 1 << MLX5E_PARAMS_MAXIMUM_LOG_RQ_SIZE;
1140	priv->params_ethtool.tx_queue_size = 1 << priv->params.log_sq_size;
1141	priv->params_ethtool.rx_queue_size = 1 << priv->params.log_rq_size;
1142	priv->params_ethtool.channels = priv->params.num_channels;
1143	priv->params_ethtool.channels_rsss = priv->params.channels_rsss;
1144	priv->params_ethtool.coalesce_pkts_max = MLX5E_FLD_MAX(cqc, cq_max_count);
1145	priv->params_ethtool.coalesce_usecs_max = MLX5E_FLD_MAX(cqc, cq_period);
1146	priv->params_ethtool.rx_coalesce_mode = priv->params.rx_cq_moderation_mode;
1147	priv->params_ethtool.rx_coalesce_usecs = priv->params.rx_cq_moderation_usec;
1148	priv->params_ethtool.rx_coalesce_pkts = priv->params.rx_cq_moderation_pkts;
1149	priv->params_ethtool.tx_coalesce_mode = priv->params.tx_cq_moderation_mode;
1150	priv->params_ethtool.tx_coalesce_usecs = priv->params.tx_cq_moderation_usec;
1151	priv->params_ethtool.tx_coalesce_pkts = priv->params.tx_cq_moderation_pkts;
1152	priv->params_ethtool.hw_lro = priv->params.hw_lro_en;
1153	priv->params_ethtool.cqe_zipping = priv->params.cqe_zipping_en;
1154	mlx5e_ethtool_sync_tx_completion_fact(priv);
1155
1156	/* get default values for local loopback, if any */
1157	if (MLX5_CAP_GEN(priv->mdev, disable_local_lb)) {
1158		int err;
1159		u8 val;
1160
1161		err = mlx5_nic_vport_query_local_lb(priv->mdev, MLX5_LOCAL_MC_LB, &val);
1162		if (err == 0)
1163			priv->params_ethtool.mc_local_lb = val;
1164
1165		err = mlx5_nic_vport_query_local_lb(priv->mdev, MLX5_LOCAL_UC_LB, &val);
1166		if (err == 0)
1167			priv->params_ethtool.uc_local_lb = val;
1168	}
1169
1170	/* create root node */
1171	node = SYSCTL_ADD_NODE(&priv->sysctl_ctx,
1172	    SYSCTL_CHILDREN(priv->sysctl_ifnet), OID_AUTO,
1173	    "conf", CTLFLAG_RW, NULL, "Configuration");
1174	if (node == NULL)
1175		return;
1176	for (x = 0; x != MLX5E_PARAMS_NUM; x++) {
1177		/* check for read-only parameter */
1178		if (strstr(mlx5e_params_desc[2 * x], "_max") != NULL ||
1179		    strstr(mlx5e_params_desc[2 * x], "_mtu") != NULL) {
1180			SYSCTL_ADD_PROC(&priv->sysctl_ctx, SYSCTL_CHILDREN(node), OID_AUTO,
1181			    mlx5e_params_desc[2 * x], CTLTYPE_U64 | CTLFLAG_RD |
1182			    CTLFLAG_MPSAFE, priv, x, &mlx5e_ethtool_handler, "QU",
1183			    mlx5e_params_desc[2 * x + 1]);
1184		} else {
1185#if (__FreeBSD_version < 1100000)
1186			char path[64];
1187#endif
1188			/*
1189			 * NOTE: In FreeBSD-11 and newer the
1190			 * CTLFLAG_RWTUN flag will take care of
1191			 * loading default sysctl value from the
1192			 * kernel environment, if any:
1193			 */
1194			SYSCTL_ADD_PROC(&priv->sysctl_ctx, SYSCTL_CHILDREN(node), OID_AUTO,
1195			    mlx5e_params_desc[2 * x], CTLTYPE_U64 | CTLFLAG_RWTUN |
1196			    CTLFLAG_MPSAFE, priv, x, &mlx5e_ethtool_handler, "QU",
1197			    mlx5e_params_desc[2 * x + 1]);
1198
1199#if (__FreeBSD_version < 1100000)
1200			/* compute path for sysctl */
1201			snprintf(path, sizeof(path), "dev.mce.%d.conf.%s",
1202			    device_get_unit(priv->mdev->pdev->dev.bsddev),
1203			    mlx5e_params_desc[2 * x]);
1204
1205			/* try to fetch tunable, if any */
1206			if (TUNABLE_QUAD_FETCH(path, &priv->params_ethtool.arg[x]))
1207				mlx5e_ethtool_handler(NULL, priv, x, NULL);
1208#endif
1209		}
1210	}
1211
1212	SYSCTL_ADD_PROC(&priv->sysctl_ctx, SYSCTL_CHILDREN(node), OID_AUTO,
1213	    "debug_stats", CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, priv,
1214	    0, &mlx5e_ethtool_debug_stats, "I", "Extended debug statistics");
1215
1216	pnameunit = device_get_nameunit(priv->mdev->pdev->dev.bsddev);
1217
1218	SYSCTL_ADD_STRING(&priv->sysctl_ctx, SYSCTL_CHILDREN(node),
1219	    OID_AUTO, "device_name", CTLFLAG_RD,
1220	    __DECONST(void *, pnameunit), 0,
1221	    "PCI device name");
1222
1223	/* EEPROM support */
1224	SYSCTL_ADD_PROC(&priv->sysctl_ctx, SYSCTL_CHILDREN(node), OID_AUTO, "eeprom_info",
1225	    CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, priv, 0,
1226	    mlx5e_read_eeprom, "I", "EEPROM information");
1227
1228	/* Diagnostics support */
1229	mlx5e_create_diagnostics(priv);
1230
1231	/* create qos node */
1232	qos_node = SYSCTL_ADD_NODE(&priv->sysctl_ctx,
1233	    SYSCTL_CHILDREN(node), OID_AUTO,
1234	    "qos", CTLFLAG_RW, NULL, "Quality Of Service configuration");
1235	if (qos_node == NULL)
1236		return;
1237
1238	/* Priority rate limit support */
1239	if (mlx5e_getmaxrate(priv) == 0) {
1240		SYSCTL_ADD_PROC(&priv->sysctl_ctx, SYSCTL_CHILDREN(qos_node),
1241		    OID_AUTO, "tc_max_rate", CTLTYPE_U64 | CTLFLAG_RWTUN | CTLFLAG_MPSAFE,
1242		    priv, 0, mlx5e_tc_maxrate_handler, "QU",
1243		    "Max rate for priority, specified in kilobits, where kilo=1000, "
1244		    "max_rate must be divisible by 100000");
1245	}
1246
1247	/* Bandwidth limiting by ratio */
1248	if (mlx5e_get_max_alloc(priv) == 0) {
1249		SYSCTL_ADD_PROC(&priv->sysctl_ctx, SYSCTL_CHILDREN(qos_node),
1250		    OID_AUTO, "tc_rate_share", CTLTYPE_U8 | CTLFLAG_RWTUN | CTLFLAG_MPSAFE,
1251		    priv, 0, mlx5e_tc_rate_share_handler, "QU",
1252		    "Specify bandwidth ratio from 1 to 100 "
1253		    "for the available traffic classes");
1254	}
1255
1256	/* Priority to traffic class mapping */
1257	if (mlx5e_get_prio_tc(priv) == 0) {
1258		for (i = 0; i <= mlx5_max_tc(mdev); i++) {
1259			char name[32];
1260			snprintf(name, sizeof(name), "prio_%d_to_tc", i);
1261			SYSCTL_ADD_PROC(&priv->sysctl_ctx, SYSCTL_CHILDREN(qos_node),
1262				OID_AUTO, name, CTLTYPE_U8 | CTLFLAG_RWTUN | CTLFLAG_MPSAFE,
1263				priv, i, mlx5e_prio_to_tc_handler, "CU",
1264				"Set priority to traffic class");
1265		}
1266	}
1267
1268	/* DSCP support */
1269	if (mlx5e_get_dscp(priv) == 0) {
1270		for (i = 0; i != MLX5_MAX_SUPPORTED_DSCP; i += 8) {
1271			char name[32];
1272			snprintf(name, sizeof(name), "dscp_%d_%d_prio", i, i + 7);
1273			SYSCTL_ADD_PROC(&priv->sysctl_ctx, SYSCTL_CHILDREN(qos_node),
1274				OID_AUTO, name, CTLTYPE_U8 | CTLFLAG_RWTUN | CTLFLAG_MPSAFE,
1275				priv, i, mlx5e_dscp_prio_handler, "CU",
1276				"Set DSCP to priority mapping, 0..7");
1277		}
1278#define	A	"Set trust state, 1:PCP 2:DSCP"
1279#define	B	" 3:BOTH"
1280		SYSCTL_ADD_PROC(&priv->sysctl_ctx, SYSCTL_CHILDREN(qos_node),
1281		    OID_AUTO, "trust_state", CTLTYPE_U8 | CTLFLAG_RWTUN | CTLFLAG_MPSAFE,
1282		    priv, 0, mlx5e_trust_state_handler, "CU",
1283		    MLX5_CAP_QCAM_FEATURE(mdev, qpts_trust_both) ?
1284		    A B : A);
1285#undef B
1286#undef A
1287	}
1288}
1289