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