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