mlx5_en_ethtool.c revision 353244
1290650Shselasky/*-
2353202Shselasky * Copyright (c) 2015-2019 Mellanox Technologies. All rights reserved.
3290650Shselasky *
4290650Shselasky * Redistribution and use in source and binary forms, with or without
5290650Shselasky * modification, are permitted provided that the following conditions
6290650Shselasky * are met:
7290650Shselasky * 1. Redistributions of source code must retain the above copyright
8290650Shselasky *    notice, this list of conditions and the following disclaimer.
9290650Shselasky * 2. Redistributions in binary form must reproduce the above copyright
10290650Shselasky *    notice, this list of conditions and the following disclaimer in the
11290650Shselasky *    documentation and/or other materials provided with the distribution.
12290650Shselasky *
13290650Shselasky * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS `AS IS' AND
14290650Shselasky * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15290650Shselasky * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
16290650Shselasky * ARE DISCLAIMED.  IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
17290650Shselasky * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
18290650Shselasky * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
19290650Shselasky * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
20290650Shselasky * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
21290650Shselasky * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
22290650Shselasky * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
23290650Shselasky * SUCH DAMAGE.
24290650Shselasky *
25290650Shselasky * $FreeBSD: stable/11/sys/dev/mlx5/mlx5_en/mlx5_en_ethtool.c 353244 2019-10-07 09:52:10Z hselasky $
26290650Shselasky */
27290650Shselasky
28290650Shselasky#include "en.h"
29353238Shselasky#include "port_buffer.h"
30290650Shselasky
31290650Shselaskyvoid
32290650Shselaskymlx5e_create_stats(struct sysctl_ctx_list *ctx,
33290650Shselasky    struct sysctl_oid_list *parent, const char *buffer,
34290650Shselasky    const char **desc, unsigned num, u64 * arg)
35290650Shselasky{
36290650Shselasky	struct sysctl_oid *node;
37290650Shselasky	unsigned x;
38290650Shselasky
39290650Shselasky	sysctl_ctx_init(ctx);
40290650Shselasky
41290650Shselasky	node = SYSCTL_ADD_NODE(ctx, parent, OID_AUTO,
42290650Shselasky	    buffer, CTLFLAG_RD, NULL, "Statistics");
43290650Shselasky	if (node == NULL)
44290650Shselasky		return;
45290650Shselasky	for (x = 0; x != num; x++) {
46290650Shselasky		SYSCTL_ADD_UQUAD(ctx, SYSCTL_CHILDREN(node), OID_AUTO,
47290650Shselasky		    desc[2 * x], CTLFLAG_RD, arg + x, desc[2 * x + 1]);
48290650Shselasky	}
49290650Shselasky}
50290650Shselasky
51300277Shselaskystatic void
52300277Shselaskymlx5e_ethtool_sync_tx_completion_fact(struct mlx5e_priv *priv)
53300277Shselasky{
54300277Shselasky	/*
55300277Shselasky	 * Limit the maximum distance between completion events to
56300277Shselasky	 * half of the currently set TX queue size.
57300277Shselasky	 *
58300277Shselasky	 * The maximum number of queue entries a single IP packet can
59300277Shselasky	 * consume is given by MLX5_SEND_WQE_MAX_WQEBBS.
60300277Shselasky	 *
61300277Shselasky	 * The worst case max value is then given as below:
62300277Shselasky	 */
63300277Shselasky	uint64_t max = priv->params_ethtool.tx_queue_size /
64300277Shselasky	    (2 * MLX5_SEND_WQE_MAX_WQEBBS);
65300277Shselasky
66300277Shselasky	/*
67300277Shselasky	 * Update the maximum completion factor value in case the
68300277Shselasky	 * tx_queue_size field changed. Ensure we don't overflow
69300277Shselasky	 * 16-bits.
70300277Shselasky	 */
71300277Shselasky	if (max < 1)
72300277Shselasky		max = 1;
73300277Shselasky	else if (max > 65535)
74300277Shselasky		max = 65535;
75300277Shselasky	priv->params_ethtool.tx_completion_fact_max = max;
76300277Shselasky
77300277Shselasky	/*
78300277Shselasky	 * Verify that the current TX completion factor is within the
79300277Shselasky	 * given limits:
80300277Shselasky	 */
81300277Shselasky	if (priv->params_ethtool.tx_completion_fact < 1)
82300277Shselasky		priv->params_ethtool.tx_completion_fact = 1;
83300277Shselasky	else if (priv->params_ethtool.tx_completion_fact > max)
84300277Shselasky		priv->params_ethtool.tx_completion_fact = max;
85300277Shselasky}
86300277Shselasky
87331577Shselaskystatic int
88331577Shselaskymlx5e_getmaxrate(struct mlx5e_priv *priv)
89331577Shselasky{
90331577Shselasky	struct mlx5_core_dev *mdev = priv->mdev;
91331577Shselasky	u8 max_bw_unit[IEEE_8021QAZ_MAX_TCS];
92331577Shselasky	u8 max_bw_value[IEEE_8021QAZ_MAX_TCS];
93331577Shselasky	int err;
94331577Shselasky	int i;
95331577Shselasky
96331577Shselasky	PRIV_LOCK(priv);
97331577Shselasky	err = -mlx5_query_port_tc_rate_limit(mdev, max_bw_value, max_bw_unit);
98331577Shselasky	if (err)
99331577Shselasky		goto done;
100331577Shselasky
101331577Shselasky	for (i = 0; i <= mlx5_max_tc(mdev); i++) {
102331577Shselasky		switch (max_bw_unit[i]) {
103331577Shselasky		case MLX5_100_MBPS_UNIT:
104331577Shselasky			priv->params_ethtool.max_bw_value[i] = max_bw_value[i] * MLX5E_100MB;
105331577Shselasky			break;
106331577Shselasky		case MLX5_GBPS_UNIT:
107331577Shselasky			priv->params_ethtool.max_bw_value[i] = max_bw_value[i] * MLX5E_1GB;
108331577Shselasky			break;
109331577Shselasky		case MLX5_BW_NO_LIMIT:
110331577Shselasky			priv->params_ethtool.max_bw_value[i] = 0;
111331577Shselasky			break;
112331577Shselasky		default:
113331577Shselasky			priv->params_ethtool.max_bw_value[i] = -1;
114331577Shselasky			WARN_ONCE(true, "non-supported BW unit");
115331577Shselasky			break;
116331577Shselasky		}
117331577Shselasky	}
118331577Shselaskydone:
119331577Shselasky	PRIV_UNLOCK(priv);
120331577Shselasky	return (err);
121331577Shselasky}
122331577Shselasky
123331577Shselaskystatic int
124341968Shselaskymlx5e_get_max_alloc(struct mlx5e_priv *priv)
125341968Shselasky{
126341968Shselasky	struct mlx5_core_dev *mdev = priv->mdev;
127341968Shselasky	int err;
128341968Shselasky	int x;
129341968Shselasky
130341968Shselasky	PRIV_LOCK(priv);
131341968Shselasky	err = -mlx5_query_port_tc_bw_alloc(mdev, priv->params_ethtool.max_bw_share);
132341968Shselasky	if (err == 0) {
133341968Shselasky		/* set default value */
134341968Shselasky		for (x = 0; x != IEEE_8021QAZ_MAX_TCS; x++) {
135341968Shselasky			priv->params_ethtool.max_bw_share[x] =
136341968Shselasky			    100 / IEEE_8021QAZ_MAX_TCS;
137341968Shselasky		}
138341968Shselasky		err = -mlx5_set_port_tc_bw_alloc(mdev,
139341968Shselasky		    priv->params_ethtool.max_bw_share);
140341968Shselasky	}
141341968Shselasky	PRIV_UNLOCK(priv);
142341968Shselasky
143341968Shselasky	return (err);
144341968Shselasky}
145341968Shselasky
146341968Shselaskystatic int
147337098Shselaskymlx5e_get_dscp(struct mlx5e_priv *priv)
148337098Shselasky{
149337098Shselasky	struct mlx5_core_dev *mdev = priv->mdev;
150337098Shselasky	int err;
151337098Shselasky
152337098Shselasky	if (MLX5_CAP_GEN(mdev, qcam_reg) == 0 ||
153337098Shselasky	    MLX5_CAP_QCAM_REG(mdev, qpts) == 0 ||
154337098Shselasky	    MLX5_CAP_QCAM_REG(mdev, qpdpm) == 0)
155337098Shselasky		return (EOPNOTSUPP);
156337098Shselasky
157337098Shselasky	PRIV_LOCK(priv);
158337098Shselasky	err = -mlx5_query_dscp2prio(mdev, priv->params_ethtool.dscp2prio);
159337098Shselasky	if (err)
160337098Shselasky		goto done;
161337098Shselasky
162337098Shselasky	err = -mlx5_query_trust_state(mdev, &priv->params_ethtool.trust_state);
163337098Shselasky	if (err)
164337098Shselasky		goto done;
165337098Shselaskydone:
166337098Shselasky	PRIV_UNLOCK(priv);
167337098Shselasky	return (err);
168337098Shselasky}
169337098Shselasky
170341968Shselaskystatic void
171341968Shselaskymlx5e_tc_get_parameters(struct mlx5e_priv *priv,
172341968Shselasky    u64 *new_bw_value, u8 *max_bw_value, u8 *max_bw_unit)
173341968Shselasky{
174341968Shselasky	const u64 upper_limit_mbps = 255 * MLX5E_100MB;
175341968Shselasky	const u64 upper_limit_gbps = 255 * MLX5E_1GB;
176341968Shselasky	u64 temp;
177341968Shselasky	int i;
178341968Shselasky
179341968Shselasky	memset(max_bw_value, 0, IEEE_8021QAZ_MAX_TCS);
180341968Shselasky	memset(max_bw_unit, 0, IEEE_8021QAZ_MAX_TCS);
181341968Shselasky
182341968Shselasky	for (i = 0; i <= mlx5_max_tc(priv->mdev); i++) {
183341968Shselasky		temp = (new_bw_value != NULL) ?
184341968Shselasky		    new_bw_value[i] : priv->params_ethtool.max_bw_value[i];
185341968Shselasky
186341968Shselasky		if (!temp) {
187341968Shselasky			max_bw_unit[i] = MLX5_BW_NO_LIMIT;
188341968Shselasky		} else if (temp > upper_limit_gbps) {
189341968Shselasky			max_bw_unit[i] = MLX5_BW_NO_LIMIT;
190341968Shselasky		} else if (temp <= upper_limit_mbps) {
191341968Shselasky			max_bw_value[i] = howmany(temp, MLX5E_100MB);
192341968Shselasky			max_bw_unit[i]  = MLX5_100_MBPS_UNIT;
193341968Shselasky		} else {
194341968Shselasky			max_bw_value[i] = howmany(temp, MLX5E_1GB);
195341968Shselasky			max_bw_unit[i]  = MLX5_GBPS_UNIT;
196341968Shselasky		}
197341968Shselasky	}
198341968Shselasky}
199341968Shselasky
200337098Shselaskystatic int
201331577Shselaskymlx5e_tc_maxrate_handler(SYSCTL_HANDLER_ARGS)
202331577Shselasky{
203331577Shselasky	struct mlx5e_priv *priv = arg1;
204331577Shselasky	struct mlx5_core_dev *mdev = priv->mdev;
205331577Shselasky	u8 max_bw_unit[IEEE_8021QAZ_MAX_TCS];
206331577Shselasky	u8 max_bw_value[IEEE_8021QAZ_MAX_TCS];
207341968Shselasky	u64 new_bw_value[IEEE_8021QAZ_MAX_TCS];
208341968Shselasky	u8 max_rates = mlx5_max_tc(mdev) + 1;
209341968Shselasky	u8 x;
210341968Shselasky	int err;
211331577Shselasky
212331577Shselasky	PRIV_LOCK(priv);
213341968Shselasky	err = SYSCTL_OUT(req, priv->params_ethtool.max_bw_value,
214341968Shselasky	    sizeof(priv->params_ethtool.max_bw_value[0]) * max_rates);
215341968Shselasky	if (err || !req->newptr)
216331577Shselasky		goto done;
217341968Shselasky	err = SYSCTL_IN(req, new_bw_value,
218341968Shselasky	    sizeof(new_bw_value[0]) * max_rates);
219341968Shselasky	if (err)
220341968Shselasky		goto done;
221331577Shselasky
222341968Shselasky	/* range check input value */
223341968Shselasky	for (x = 0; x != max_rates; x++) {
224341968Shselasky		if (new_bw_value[x] % MLX5E_100MB) {
225341968Shselasky			err = ERANGE;
226341968Shselasky			goto done;
227341968Shselasky		}
228331577Shselasky	}
229331577Shselasky
230341968Shselasky	mlx5e_tc_get_parameters(priv, new_bw_value, max_bw_value, max_bw_unit);
231331577Shselasky
232341968Shselasky	err = -mlx5_modify_port_tc_rate_limit(mdev, max_bw_value, max_bw_unit);
233341968Shselasky	if (err)
234341968Shselasky		goto done;
235331577Shselasky
236341968Shselasky	memcpy(priv->params_ethtool.max_bw_value, new_bw_value,
237341968Shselasky	    sizeof(priv->params_ethtool.max_bw_value));
238341968Shselaskydone:
239341968Shselasky	PRIV_UNLOCK(priv);
240341968Shselasky	return (err);
241341968Shselasky}
242341968Shselasky
243341968Shselaskystatic int
244341968Shselaskymlx5e_tc_rate_share_handler(SYSCTL_HANDLER_ARGS)
245341968Shselasky{
246341968Shselasky	struct mlx5e_priv *priv = arg1;
247341968Shselasky	struct mlx5_core_dev *mdev = priv->mdev;
248341968Shselasky	u8 max_bw_share[IEEE_8021QAZ_MAX_TCS];
249341968Shselasky	u8 max_rates = mlx5_max_tc(mdev) + 1;
250341968Shselasky	int i;
251341968Shselasky	int err;
252341968Shselasky	int sum;
253341968Shselasky
254341968Shselasky	PRIV_LOCK(priv);
255341968Shselasky	err = SYSCTL_OUT(req, priv->params_ethtool.max_bw_share, max_rates);
256341968Shselasky	if (err || !req->newptr)
257341968Shselasky		goto done;
258341968Shselasky	err = SYSCTL_IN(req, max_bw_share, max_rates);
259341968Shselasky	if (err)
260341968Shselasky		goto done;
261341968Shselasky
262341968Shselasky	/* range check input value */
263341968Shselasky	for (sum = i = 0; i != max_rates; i++) {
264341968Shselasky		if (max_bw_share[i] < 1 || max_bw_share[i] > 100) {
265341968Shselasky			err = ERANGE;
266341968Shselasky			goto done;
267331577Shselasky		}
268341968Shselasky		sum += max_bw_share[i];
269331577Shselasky	}
270331577Shselasky
271341968Shselasky	/* sum of values should be as close to 100 as possible */
272341968Shselasky	if (sum < (100 - max_rates + 1) || sum > 100) {
273341968Shselasky		err = ERANGE;
274341968Shselasky		goto done;
275341968Shselasky	}
276341968Shselasky
277341968Shselasky	err = -mlx5_set_port_tc_bw_alloc(mdev, max_bw_share);
278331577Shselasky	if (err)
279331577Shselasky		goto done;
280331577Shselasky
281341968Shselasky	memcpy(priv->params_ethtool.max_bw_share, max_bw_share,
282341968Shselasky	    sizeof(priv->params_ethtool.max_bw_share));
283331577Shselaskydone:
284331577Shselasky	PRIV_UNLOCK(priv);
285331577Shselasky	return (err);
286331577Shselasky}
287331577Shselasky
288331578Shselaskystatic int
289331578Shselaskymlx5e_get_prio_tc(struct mlx5e_priv *priv)
290331578Shselasky{
291331578Shselasky	struct mlx5_core_dev *mdev = priv->mdev;
292331578Shselasky	int err = 0;
293331578Shselasky	int i;
294331578Shselasky
295331578Shselasky	PRIV_LOCK(priv);
296331578Shselasky	if (!MLX5_CAP_GEN(priv->mdev, ets)) {
297331578Shselasky		PRIV_UNLOCK(priv);
298331578Shselasky		return (EOPNOTSUPP);
299331578Shselasky	}
300331578Shselasky
301347810Shselasky	for (i = 0; i != MLX5E_MAX_PRIORITY; i++) {
302347810Shselasky		err = -mlx5_query_port_prio_tc(mdev, i, priv->params_ethtool.prio_tc + i);
303331578Shselasky		if (err)
304331578Shselasky			break;
305331578Shselasky	}
306331578Shselasky	PRIV_UNLOCK(priv);
307331578Shselasky	return (err);
308331578Shselasky}
309331578Shselasky
310331578Shselaskystatic int
311331578Shselaskymlx5e_prio_to_tc_handler(SYSCTL_HANDLER_ARGS)
312331578Shselasky{
313331578Shselasky	struct mlx5e_priv *priv = arg1;
314331578Shselasky	struct mlx5_core_dev *mdev = priv->mdev;
315347810Shselasky	uint8_t temp[MLX5E_MAX_PRIORITY];
316331578Shselasky	int err;
317347810Shselasky	int i;
318331578Shselasky
319331578Shselasky	PRIV_LOCK(priv);
320347810Shselasky	err = SYSCTL_OUT(req, priv->params_ethtool.prio_tc, MLX5E_MAX_PRIORITY);
321347810Shselasky	if (err || !req->newptr)
322331578Shselasky		goto done;
323347810Shselasky	err = SYSCTL_IN(req, temp, MLX5E_MAX_PRIORITY);
324331578Shselasky	if (err)
325331578Shselasky		goto done;
326331578Shselasky
327347810Shselasky	for (i = 0; i != MLX5E_MAX_PRIORITY; i++) {
328347810Shselasky		if (temp[i] > mlx5_max_tc(mdev)) {
329347810Shselasky			err = ERANGE;
330347810Shselasky			goto done;
331347810Shselasky		}
332347810Shselasky	}
333331578Shselasky
334347810Shselasky	for (i = 0; i != MLX5E_MAX_PRIORITY; i++) {
335347810Shselasky		if (temp[i] == priv->params_ethtool.prio_tc[i])
336347810Shselasky			continue;
337347810Shselasky		err = -mlx5_set_port_prio_tc(mdev, i, temp[i]);
338347810Shselasky		if (err)
339347810Shselasky			goto done;
340347810Shselasky		/* update cached value */
341347810Shselasky		priv->params_ethtool.prio_tc[i] = temp[i];
342347810Shselasky	}
343331578Shselaskydone:
344331578Shselasky	PRIV_UNLOCK(priv);
345331578Shselasky	return (err);
346331578Shselasky}
347331578Shselasky
348353244Shselaskyint
349353244Shselaskymlx5e_fec_update(struct mlx5e_priv *priv)
350353244Shselasky{
351353244Shselasky	struct mlx5_core_dev *mdev = priv->mdev;
352353244Shselasky	u32 in[MLX5_ST_SZ_DW(pplm_reg)] = {};
353353244Shselasky	const int sz = MLX5_ST_SZ_BYTES(pplm_reg);
354353244Shselasky	int err;
355353244Shselasky
356353244Shselasky	if (!MLX5_CAP_GEN(mdev, pcam_reg))
357353244Shselasky		return (EOPNOTSUPP);
358353244Shselasky
359353244Shselasky	if (!MLX5_CAP_PCAM_REG(mdev, pplm))
360353244Shselasky		return (EOPNOTSUPP);
361353244Shselasky
362353244Shselasky	MLX5_SET(pplm_reg, in, local_port, 1);
363353244Shselasky
364353244Shselasky	err = -mlx5_core_access_reg(mdev, in, sz, in, sz, MLX5_REG_PPLM, 0, 0);
365353244Shselasky	if (err)
366353244Shselasky		return (err);
367353244Shselasky
368353244Shselasky	/* get 10x..25x mask */
369353244Shselasky	priv->params_ethtool.fec_mask_10x_25x[0] =
370353244Shselasky	    MLX5_GET(pplm_reg, in, fec_override_admin_10g_40g);
371353244Shselasky	priv->params_ethtool.fec_mask_10x_25x[1] =
372353244Shselasky	    MLX5_GET(pplm_reg, in, fec_override_admin_25g) &
373353244Shselasky	    MLX5_GET(pplm_reg, in, fec_override_admin_50g);
374353244Shselasky	priv->params_ethtool.fec_mask_10x_25x[2] =
375353244Shselasky	    MLX5_GET(pplm_reg, in, fec_override_admin_56g);
376353244Shselasky	priv->params_ethtool.fec_mask_10x_25x[3] =
377353244Shselasky	    MLX5_GET(pplm_reg, in, fec_override_admin_100g);
378353244Shselasky
379353244Shselasky	/* get 10x..25x available bits */
380353244Shselasky	priv->params_ethtool.fec_avail_10x_25x[0] =
381353244Shselasky	    MLX5_GET(pplm_reg, in, fec_override_cap_10g_40g);
382353244Shselasky	priv->params_ethtool.fec_avail_10x_25x[1] =
383353244Shselasky	    MLX5_GET(pplm_reg, in, fec_override_cap_25g) &
384353244Shselasky	    MLX5_GET(pplm_reg, in, fec_override_cap_50g);
385353244Shselasky	priv->params_ethtool.fec_avail_10x_25x[2] =
386353244Shselasky	    MLX5_GET(pplm_reg, in, fec_override_cap_56g);
387353244Shselasky	priv->params_ethtool.fec_avail_10x_25x[3] =
388353244Shselasky	    MLX5_GET(pplm_reg, in, fec_override_cap_100g);
389353244Shselasky
390353244Shselasky	/* get 50x mask */
391353244Shselasky	priv->params_ethtool.fec_mask_50x[0] =
392353244Shselasky	    MLX5_GET(pplm_reg, in, fec_override_admin_50g_1x);
393353244Shselasky	priv->params_ethtool.fec_mask_50x[1] =
394353244Shselasky	    MLX5_GET(pplm_reg, in, fec_override_admin_100g_2x);
395353244Shselasky	priv->params_ethtool.fec_mask_50x[2] =
396353244Shselasky	    MLX5_GET(pplm_reg, in, fec_override_admin_200g_4x);
397353244Shselasky	priv->params_ethtool.fec_mask_50x[3] =
398353244Shselasky	    MLX5_GET(pplm_reg, in, fec_override_admin_400g_8x);
399353244Shselasky
400353244Shselasky	/* get 50x available bits */
401353244Shselasky	priv->params_ethtool.fec_avail_50x[0] =
402353244Shselasky	    MLX5_GET(pplm_reg, in, fec_override_cap_50g_1x);
403353244Shselasky	priv->params_ethtool.fec_avail_50x[1] =
404353244Shselasky	    MLX5_GET(pplm_reg, in, fec_override_cap_100g_2x);
405353244Shselasky	priv->params_ethtool.fec_avail_50x[2] =
406353244Shselasky	    MLX5_GET(pplm_reg, in, fec_override_cap_200g_4x);
407353244Shselasky	priv->params_ethtool.fec_avail_50x[3] =
408353244Shselasky	    MLX5_GET(pplm_reg, in, fec_override_cap_400g_8x);
409353244Shselasky
410353244Shselasky	/* get current FEC mask */
411353244Shselasky	priv->params_ethtool.fec_mode_active =
412353244Shselasky	    MLX5_GET(pplm_reg, in, fec_mode_active);
413353244Shselasky
414353244Shselasky	return (0);
415353244Shselasky}
416353244Shselasky
417337098Shselaskystatic int
418353244Shselaskymlx5e_fec_mask_10x_25x_handler(SYSCTL_HANDLER_ARGS)
419353244Shselasky{
420353244Shselasky	struct mlx5e_priv *priv = arg1;
421353244Shselasky	struct mlx5_core_dev *mdev = priv->mdev;
422353244Shselasky	u32 out[MLX5_ST_SZ_DW(pplm_reg)] = {};
423353244Shselasky	u32 in[MLX5_ST_SZ_DW(pplm_reg)] = {};
424353244Shselasky	const int sz = MLX5_ST_SZ_BYTES(pplm_reg);
425353244Shselasky	u8 fec_mask_10x_25x[MLX5E_MAX_FEC_10X_25X];
426353244Shselasky	u8 fec_cap_changed = 0;
427353244Shselasky	u8 x;
428353244Shselasky	int err;
429353244Shselasky
430353244Shselasky	PRIV_LOCK(priv);
431353244Shselasky	err = SYSCTL_OUT(req, priv->params_ethtool.fec_mask_10x_25x,
432353244Shselasky	    sizeof(priv->params_ethtool.fec_mask_10x_25x));
433353244Shselasky	if (err || !req->newptr)
434353244Shselasky		goto done;
435353244Shselasky
436353244Shselasky	err = SYSCTL_IN(req, fec_mask_10x_25x,
437353244Shselasky	    sizeof(fec_mask_10x_25x));
438353244Shselasky	if (err)
439353244Shselasky		goto done;
440353244Shselasky
441353244Shselasky	if (!MLX5_CAP_GEN(mdev, pcam_reg)) {
442353244Shselasky		err = EOPNOTSUPP;
443353244Shselasky		goto done;
444353244Shselasky	}
445353244Shselasky
446353244Shselasky	if (!MLX5_CAP_PCAM_REG(mdev, pplm)) {
447353244Shselasky		err = EOPNOTSUPP;
448353244Shselasky		goto done;
449353244Shselasky	}
450353244Shselasky
451353244Shselasky	MLX5_SET(pplm_reg, in, local_port, 1);
452353244Shselasky
453353244Shselasky	err = -mlx5_core_access_reg(mdev, in, sz, in, sz, MLX5_REG_PPLM, 0, 0);
454353244Shselasky	if (err)
455353244Shselasky		goto done;
456353244Shselasky
457353244Shselasky	/* range check input value */
458353244Shselasky	for (x = 0; x != MLX5E_MAX_FEC_10X_25X; x++) {
459353244Shselasky		/* check only one bit is set, if any */
460353244Shselasky		if (fec_mask_10x_25x[x] & (fec_mask_10x_25x[x] - 1)) {
461353244Shselasky			err = ERANGE;
462353244Shselasky			goto done;
463353244Shselasky		}
464353244Shselasky		/* check a supported bit is set, if any */
465353244Shselasky		if (fec_mask_10x_25x[x] &
466353244Shselasky		    ~priv->params_ethtool.fec_avail_10x_25x[x]) {
467353244Shselasky			err = ERANGE;
468353244Shselasky			goto done;
469353244Shselasky		}
470353244Shselasky		fec_cap_changed |= (fec_mask_10x_25x[x] ^
471353244Shselasky		    priv->params_ethtool.fec_mask_10x_25x[x]);
472353244Shselasky	}
473353244Shselasky
474353244Shselasky	/* check for no changes */
475353244Shselasky	if (fec_cap_changed == 0)
476353244Shselasky		goto done;
477353244Shselasky
478353244Shselasky	memset(in, 0, sizeof(in));
479353244Shselasky
480353244Shselasky	MLX5_SET(pplm_reg, in, local_port, 1);
481353244Shselasky
482353244Shselasky	/* set new values */
483353244Shselasky	MLX5_SET(pplm_reg, in, fec_override_admin_10g_40g, fec_mask_10x_25x[0]);
484353244Shselasky	MLX5_SET(pplm_reg, in, fec_override_admin_25g, fec_mask_10x_25x[1]);
485353244Shselasky	MLX5_SET(pplm_reg, in, fec_override_admin_50g, fec_mask_10x_25x[1]);
486353244Shselasky	MLX5_SET(pplm_reg, in, fec_override_admin_56g, fec_mask_10x_25x[2]);
487353244Shselasky	MLX5_SET(pplm_reg, in, fec_override_admin_100g, fec_mask_10x_25x[3]);
488353244Shselasky
489353244Shselasky	/* preserve other values */
490353244Shselasky	MLX5_SET(pplm_reg, in, fec_override_admin_50g_1x, priv->params_ethtool.fec_mask_50x[0]);
491353244Shselasky	MLX5_SET(pplm_reg, in, fec_override_admin_100g_2x, priv->params_ethtool.fec_mask_50x[1]);
492353244Shselasky	MLX5_SET(pplm_reg, in, fec_override_admin_200g_4x, priv->params_ethtool.fec_mask_50x[2]);
493353244Shselasky	MLX5_SET(pplm_reg, in, fec_override_admin_400g_8x, priv->params_ethtool.fec_mask_50x[3]);
494353244Shselasky
495353244Shselasky	/* send new value to the firmware */
496353244Shselasky	err = -mlx5_core_access_reg(mdev, in, sz, out, sz, MLX5_REG_PPLM, 0, 1);
497353244Shselasky	if (err)
498353244Shselasky		goto done;
499353244Shselasky
500353244Shselasky	memcpy(priv->params_ethtool.fec_mask_10x_25x, fec_mask_10x_25x,
501353244Shselasky	    sizeof(priv->params_ethtool.fec_mask_10x_25x));
502353244Shselasky
503353244Shselasky	mlx5_toggle_port_link(priv->mdev);
504353244Shselaskydone:
505353244Shselasky	PRIV_UNLOCK(priv);
506353244Shselasky	return (err);
507353244Shselasky}
508353244Shselasky
509353244Shselaskystatic int
510353244Shselaskymlx5e_fec_avail_10x_25x_handler(SYSCTL_HANDLER_ARGS)
511353244Shselasky{
512353244Shselasky	struct mlx5e_priv *priv = arg1;
513353244Shselasky	int err;
514353244Shselasky
515353244Shselasky	PRIV_LOCK(priv);
516353244Shselasky	err = SYSCTL_OUT(req, priv->params_ethtool.fec_avail_10x_25x,
517353244Shselasky	    sizeof(priv->params_ethtool.fec_avail_10x_25x));
518353244Shselasky	PRIV_UNLOCK(priv);
519353244Shselasky	return (err);
520353244Shselasky}
521353244Shselasky
522353244Shselaskystatic int
523353244Shselaskymlx5e_fec_mask_50x_handler(SYSCTL_HANDLER_ARGS)
524353244Shselasky{
525353244Shselasky	struct mlx5e_priv *priv = arg1;
526353244Shselasky	struct mlx5_core_dev *mdev = priv->mdev;
527353244Shselasky	u32 out[MLX5_ST_SZ_DW(pplm_reg)] = {};
528353244Shselasky	u32 in[MLX5_ST_SZ_DW(pplm_reg)] = {};
529353244Shselasky	const int sz = MLX5_ST_SZ_BYTES(pplm_reg);
530353244Shselasky	u16 fec_mask_50x[MLX5E_MAX_FEC_50X];
531353244Shselasky	u16 fec_cap_changed = 0;
532353244Shselasky	u8 x;
533353244Shselasky	int err;
534353244Shselasky
535353244Shselasky	PRIV_LOCK(priv);
536353244Shselasky	err = SYSCTL_OUT(req, priv->params_ethtool.fec_mask_50x,
537353244Shselasky	    sizeof(priv->params_ethtool.fec_mask_50x));
538353244Shselasky	if (err || !req->newptr)
539353244Shselasky		goto done;
540353244Shselasky
541353244Shselasky	err = SYSCTL_IN(req, fec_mask_50x,
542353244Shselasky	    sizeof(fec_mask_50x));
543353244Shselasky	if (err)
544353244Shselasky		goto done;
545353244Shselasky
546353244Shselasky	if (!MLX5_CAP_GEN(mdev, pcam_reg)) {
547353244Shselasky		err = EOPNOTSUPP;
548353244Shselasky		goto done;
549353244Shselasky	}
550353244Shselasky
551353244Shselasky	if (!MLX5_CAP_PCAM_REG(mdev, pplm)) {
552353244Shselasky		err = EOPNOTSUPP;
553353244Shselasky		goto done;
554353244Shselasky	}
555353244Shselasky
556353244Shselasky	MLX5_SET(pplm_reg, in, local_port, 1);
557353244Shselasky
558353244Shselasky	err = -mlx5_core_access_reg(mdev, in, sz, in, sz, MLX5_REG_PPLM, 0, 0);
559353244Shselasky	if (err)
560353244Shselasky		goto done;
561353244Shselasky
562353244Shselasky	/* range check input value */
563353244Shselasky	for (x = 0; x != MLX5E_MAX_FEC_50X; x++) {
564353244Shselasky		/* check only one bit is set, if any */
565353244Shselasky		if (fec_mask_50x[x] & (fec_mask_50x[x] - 1)) {
566353244Shselasky			err = ERANGE;
567353244Shselasky			goto done;
568353244Shselasky		}
569353244Shselasky		/* check a supported bit is set, if any */
570353244Shselasky		if (fec_mask_50x[x] &
571353244Shselasky		    ~priv->params_ethtool.fec_avail_50x[x]) {
572353244Shselasky			err = ERANGE;
573353244Shselasky			goto done;
574353244Shselasky		}
575353244Shselasky		fec_cap_changed |= (fec_mask_50x[x] ^
576353244Shselasky		    priv->params_ethtool.fec_mask_50x[x]);
577353244Shselasky	}
578353244Shselasky
579353244Shselasky	/* check for no changes */
580353244Shselasky	if (fec_cap_changed == 0)
581353244Shselasky		goto done;
582353244Shselasky
583353244Shselasky	memset(in, 0, sizeof(in));
584353244Shselasky
585353244Shselasky	MLX5_SET(pplm_reg, in, local_port, 1);
586353244Shselasky
587353244Shselasky	/* set new values */
588353244Shselasky	MLX5_SET(pplm_reg, in, fec_override_admin_50g_1x, fec_mask_50x[0]);
589353244Shselasky	MLX5_SET(pplm_reg, in, fec_override_admin_100g_2x, fec_mask_50x[1]);
590353244Shselasky	MLX5_SET(pplm_reg, in, fec_override_admin_200g_4x, fec_mask_50x[2]);
591353244Shselasky	MLX5_SET(pplm_reg, in, fec_override_admin_400g_8x, fec_mask_50x[3]);
592353244Shselasky
593353244Shselasky	/* preserve other values */
594353244Shselasky	MLX5_SET(pplm_reg, in, fec_override_admin_10g_40g, priv->params_ethtool.fec_mask_10x_25x[0]);
595353244Shselasky	MLX5_SET(pplm_reg, in, fec_override_admin_25g, priv->params_ethtool.fec_mask_10x_25x[1]);
596353244Shselasky	MLX5_SET(pplm_reg, in, fec_override_admin_50g, priv->params_ethtool.fec_mask_10x_25x[1]);
597353244Shselasky	MLX5_SET(pplm_reg, in, fec_override_admin_56g, priv->params_ethtool.fec_mask_10x_25x[2]);
598353244Shselasky	MLX5_SET(pplm_reg, in, fec_override_admin_100g, priv->params_ethtool.fec_mask_10x_25x[3]);
599353244Shselasky
600353244Shselasky	/* send new value to the firmware */
601353244Shselasky	err = -mlx5_core_access_reg(mdev, in, sz, out, sz, MLX5_REG_PPLM, 0, 1);
602353244Shselasky	if (err)
603353244Shselasky		goto done;
604353244Shselasky
605353244Shselasky	memcpy(priv->params_ethtool.fec_mask_50x, fec_mask_50x,
606353244Shselasky	    sizeof(priv->params_ethtool.fec_mask_50x));
607353244Shselasky
608353244Shselasky	mlx5_toggle_port_link(priv->mdev);
609353244Shselaskydone:
610353244Shselasky	PRIV_UNLOCK(priv);
611353244Shselasky	return (err);
612353244Shselasky}
613353244Shselasky
614353244Shselaskystatic int
615353244Shselaskymlx5e_fec_avail_50x_handler(SYSCTL_HANDLER_ARGS)
616353244Shselasky{
617353244Shselasky	struct mlx5e_priv *priv = arg1;
618353244Shselasky	int err;
619353244Shselasky
620353244Shselasky	PRIV_LOCK(priv);
621353244Shselasky	err = SYSCTL_OUT(req, priv->params_ethtool.fec_avail_50x,
622353244Shselasky	    sizeof(priv->params_ethtool.fec_avail_50x));
623353244Shselasky	PRIV_UNLOCK(priv);
624353244Shselasky	return (err);
625353244Shselasky}
626353244Shselasky
627353244Shselaskystatic int
628337098Shselaskymlx5e_trust_state_handler(SYSCTL_HANDLER_ARGS)
629337098Shselasky{
630337098Shselasky	struct mlx5e_priv *priv = arg1;
631337098Shselasky	struct mlx5_core_dev *mdev = priv->mdev;
632337098Shselasky	int err;
633337098Shselasky	u8 result;
634337098Shselasky
635337098Shselasky	PRIV_LOCK(priv);
636337098Shselasky	result = priv->params_ethtool.trust_state;
637337098Shselasky	err = sysctl_handle_8(oidp, &result, 0, req);
638337098Shselasky	if (err || !req->newptr ||
639337098Shselasky	    result == priv->params_ethtool.trust_state)
640337098Shselasky		goto done;
641337098Shselasky
642337098Shselasky	switch (result) {
643337098Shselasky	case MLX5_QPTS_TRUST_PCP:
644337098Shselasky	case MLX5_QPTS_TRUST_DSCP:
645337098Shselasky		break;
646337098Shselasky	case MLX5_QPTS_TRUST_BOTH:
647337098Shselasky		if (!MLX5_CAP_QCAM_FEATURE(mdev, qpts_trust_both)) {
648337098Shselasky			err = EOPNOTSUPP;
649337098Shselasky			goto done;
650337098Shselasky		}
651337098Shselasky		break;
652337098Shselasky	default:
653337098Shselasky		err = ERANGE;
654337098Shselasky		goto done;
655337098Shselasky	}
656337098Shselasky
657337098Shselasky	err = -mlx5_set_trust_state(mdev, result);
658337098Shselasky	if (err)
659337098Shselasky		goto done;
660337098Shselasky
661337098Shselasky	priv->params_ethtool.trust_state = result;
662341972Shselasky
663341972Shselasky	/* update inline mode */
664341972Shselasky	mlx5e_refresh_sq_inline(priv);
665341972Shselasky#ifdef RATELIMIT
666341972Shselasky	mlx5e_rl_refresh_sq_inline(&priv->rl);
667341972Shselasky#endif
668337098Shselaskydone:
669337098Shselasky	PRIV_UNLOCK(priv);
670337098Shselasky	return (err);
671337098Shselasky}
672337098Shselasky
673337098Shselaskystatic int
674337098Shselaskymlx5e_dscp_prio_handler(SYSCTL_HANDLER_ARGS)
675337098Shselasky{
676337098Shselasky	struct mlx5e_priv *priv = arg1;
677337098Shselasky	int prio_index = arg2;
678337098Shselasky	struct mlx5_core_dev *mdev = priv->mdev;
679337098Shselasky	uint8_t dscp2prio[MLX5_MAX_SUPPORTED_DSCP];
680337098Shselasky	uint8_t x;
681337098Shselasky	int err;
682337098Shselasky
683337098Shselasky	PRIV_LOCK(priv);
684337098Shselasky	err = SYSCTL_OUT(req, priv->params_ethtool.dscp2prio + prio_index,
685337098Shselasky	    sizeof(priv->params_ethtool.dscp2prio) / 8);
686337098Shselasky	if (err || !req->newptr)
687337098Shselasky		goto done;
688337098Shselasky
689337098Shselasky	memcpy(dscp2prio, priv->params_ethtool.dscp2prio, sizeof(dscp2prio));
690337098Shselasky	err = SYSCTL_IN(req, dscp2prio + prio_index, sizeof(dscp2prio) / 8);
691337098Shselasky	if (err)
692337098Shselasky		goto done;
693337098Shselasky	for (x = 0; x != MLX5_MAX_SUPPORTED_DSCP; x++) {
694337098Shselasky		if (dscp2prio[x] > 7) {
695337098Shselasky			err = ERANGE;
696337098Shselasky			goto done;
697337098Shselasky		}
698337098Shselasky	}
699337098Shselasky	err = -mlx5_set_dscp2prio(mdev, dscp2prio);
700337098Shselasky	if (err)
701337098Shselasky		goto done;
702337098Shselasky
703337098Shselasky	/* update local array */
704337098Shselasky	memcpy(priv->params_ethtool.dscp2prio, dscp2prio,
705337098Shselasky	    sizeof(priv->params_ethtool.dscp2prio));
706337098Shselaskydone:
707337098Shselasky	PRIV_UNLOCK(priv);
708337098Shselasky	return (err);
709337098Shselasky}
710337098Shselasky
711353238Shselaskyint
712353238Shselaskymlx5e_update_buf_lossy(struct mlx5e_priv *priv)
713353238Shselasky{
714353238Shselasky	struct ieee_pfc pfc;
715353238Shselasky
716353238Shselasky	PRIV_ASSERT_LOCKED(priv);
717353238Shselasky	bzero(&pfc, sizeof(pfc));
718353238Shselasky	pfc.pfc_en = priv->params.rx_priority_flow_control;
719353238Shselasky	return (-mlx5e_port_manual_buffer_config(priv, MLX5E_PORT_BUFFER_PFC,
720353238Shselasky	    priv->params_ethtool.hw_mtu, &pfc, NULL, NULL));
721353238Shselasky}
722353238Shselasky
723353238Shselaskystatic int
724353238Shselaskymlx5e_buf_size_handler(SYSCTL_HANDLER_ARGS)
725353238Shselasky{
726353238Shselasky	struct mlx5e_priv *priv;
727353238Shselasky	u32 buf_size[MLX5E_MAX_BUFFER];
728353238Shselasky	struct mlx5e_port_buffer port_buffer;
729353238Shselasky	int error, i;
730353238Shselasky
731353238Shselasky	priv = arg1;
732353238Shselasky	PRIV_LOCK(priv);
733353238Shselasky	error = -mlx5e_port_query_buffer(priv, &port_buffer);
734353238Shselasky	if (error != 0)
735353238Shselasky		goto done;
736353238Shselasky	for (i = 0; i < nitems(buf_size); i++)
737353238Shselasky		buf_size[i] = port_buffer.buffer[i].size;
738353238Shselasky	error = SYSCTL_OUT(req, buf_size, sizeof(buf_size));
739353238Shselasky	if (error != 0 || req->newptr == NULL)
740353238Shselasky		goto done;
741353238Shselasky	error = SYSCTL_IN(req, buf_size, sizeof(buf_size));
742353238Shselasky	if (error != 0)
743353238Shselasky		goto done;
744353238Shselasky	error = -mlx5e_port_manual_buffer_config(priv, MLX5E_PORT_BUFFER_SIZE,
745353238Shselasky	    priv->params_ethtool.hw_mtu, NULL, buf_size, NULL);
746353238Shselaskydone:
747353238Shselasky	PRIV_UNLOCK(priv);
748353238Shselasky	return (error);
749353238Shselasky}
750353238Shselasky
751353238Shselaskystatic int
752353238Shselaskymlx5e_buf_prio_handler(SYSCTL_HANDLER_ARGS)
753353238Shselasky{
754353238Shselasky	struct mlx5e_priv *priv;
755353238Shselasky	struct mlx5_core_dev *mdev;
756353238Shselasky	u8 buffer[MLX5E_MAX_BUFFER];
757353238Shselasky	int error;
758353238Shselasky
759353238Shselasky	priv = arg1;
760353238Shselasky	mdev = priv->mdev;
761353238Shselasky	PRIV_LOCK(priv);
762353238Shselasky	error = -mlx5e_port_query_priority2buffer(mdev, buffer);
763353238Shselasky	if (error != 0)
764353238Shselasky		goto done;
765353238Shselasky	error = SYSCTL_OUT(req, buffer, MLX5E_MAX_BUFFER);
766353238Shselasky	if (error != 0 || req->newptr == NULL)
767353238Shselasky		goto done;
768353238Shselasky	error = SYSCTL_IN(req, buffer, MLX5E_MAX_BUFFER);
769353238Shselasky	if (error != 0)
770353238Shselasky		goto done;
771353238Shselasky	error = -mlx5e_port_manual_buffer_config(priv,
772353238Shselasky	    MLX5E_PORT_BUFFER_PRIO2BUFFER,
773353238Shselasky	    priv->params_ethtool.hw_mtu, NULL, NULL, buffer);
774353238Shselasky	if (error == 0)
775353238Shselasky		error = mlx5e_update_buf_lossy(priv);
776353238Shselaskydone:
777353238Shselasky	PRIV_UNLOCK(priv);
778353238Shselasky	return (error);
779353238Shselasky}
780353238Shselasky
781353238Shselaskystatic int
782353238Shselaskymlx5e_cable_length_handler(SYSCTL_HANDLER_ARGS)
783353238Shselasky{
784353238Shselasky	struct mlx5e_priv *priv;
785353238Shselasky	u_int cable_len;
786353238Shselasky	int error;
787353238Shselasky
788353238Shselasky	priv = arg1;
789353238Shselasky	PRIV_LOCK(priv);
790353238Shselasky	cable_len = priv->dcbx.cable_len;
791353238Shselasky	error = sysctl_handle_int(oidp, &cable_len, 0, req);
792353238Shselasky	if (error == 0 && req->newptr != NULL &&
793353238Shselasky	    cable_len != priv->dcbx.cable_len) {
794353238Shselasky		error = -mlx5e_port_manual_buffer_config(priv,
795353238Shselasky		    MLX5E_PORT_BUFFER_CABLE_LEN, priv->params_ethtool.hw_mtu,
796353238Shselasky		    NULL, NULL, NULL);
797353238Shselasky		if (error == 0)
798353238Shselasky			priv->dcbx.cable_len = cable_len;
799353238Shselasky	}
800353238Shselasky	PRIV_UNLOCK(priv);
801353238Shselasky	return (error);
802353238Shselasky}
803353238Shselasky
804300282Shselasky#define	MLX5_PARAM_OFFSET(n)				\
805300282Shselasky    __offsetof(struct mlx5e_priv, params_ethtool.n)
806300282Shselasky
807290650Shselaskystatic int
808290650Shselaskymlx5e_ethtool_handler(SYSCTL_HANDLER_ARGS)
809290650Shselasky{
810290650Shselasky	struct mlx5e_priv *priv = arg1;
811290650Shselasky	uint64_t value;
812321995Shselasky	int mode_modify;
813290650Shselasky	int was_opened;
814290650Shselasky	int error;
815290650Shselasky
816290650Shselasky	PRIV_LOCK(priv);
817290650Shselasky	value = priv->params_ethtool.arg[arg2];
818292837Shselasky	if (req != NULL) {
819292837Shselasky		error = sysctl_handle_64(oidp, &value, 0, req);
820292837Shselasky		if (error || req->newptr == NULL ||
821292837Shselasky		    value == priv->params_ethtool.arg[arg2])
822292837Shselasky			goto done;
823290650Shselasky
824292837Shselasky		/* assign new value */
825292837Shselasky		priv->params_ethtool.arg[arg2] = value;
826292837Shselasky	} else {
827292837Shselasky		error = 0;
828292837Shselasky	}
829290650Shselasky	/* check if device is gone */
830290650Shselasky	if (priv->gone) {
831290650Shselasky		error = ENXIO;
832290650Shselasky		goto done;
833290650Shselasky	}
834300282Shselasky	was_opened = test_bit(MLX5E_STATE_OPENED, &priv->state);
835321995Shselasky	mode_modify = MLX5_CAP_GEN(priv->mdev, cq_period_mode_modify);
836290650Shselasky
837300282Shselasky	switch (MLX5_PARAM_OFFSET(arg[arg2])) {
838300282Shselasky	case MLX5_PARAM_OFFSET(rx_coalesce_usecs):
839300282Shselasky		/* import RX coal time */
840300282Shselasky		if (priv->params_ethtool.rx_coalesce_usecs < 1)
841300282Shselasky			priv->params_ethtool.rx_coalesce_usecs = 0;
842300282Shselasky		else if (priv->params_ethtool.rx_coalesce_usecs >
843300282Shselasky		    MLX5E_FLD_MAX(cqc, cq_period)) {
844300282Shselasky			priv->params_ethtool.rx_coalesce_usecs =
845300282Shselasky			    MLX5E_FLD_MAX(cqc, cq_period);
846300282Shselasky		}
847300282Shselasky		priv->params.rx_cq_moderation_usec =
848300282Shselasky		    priv->params_ethtool.rx_coalesce_usecs;
849292949Shselasky
850300282Shselasky		/* check to avoid down and up the network interface */
851300282Shselasky		if (was_opened)
852300282Shselasky			error = mlx5e_refresh_channel_params(priv);
853300282Shselasky		break;
854292949Shselasky
855300282Shselasky	case MLX5_PARAM_OFFSET(rx_coalesce_pkts):
856300282Shselasky		/* import RX coal pkts */
857300282Shselasky		if (priv->params_ethtool.rx_coalesce_pkts < 1)
858300282Shselasky			priv->params_ethtool.rx_coalesce_pkts = 0;
859300282Shselasky		else if (priv->params_ethtool.rx_coalesce_pkts >
860300282Shselasky		    MLX5E_FLD_MAX(cqc, cq_max_count)) {
861300282Shselasky			priv->params_ethtool.rx_coalesce_pkts =
862300282Shselasky			    MLX5E_FLD_MAX(cqc, cq_max_count);
863300282Shselasky		}
864300282Shselasky		priv->params.rx_cq_moderation_pkts =
865300282Shselasky		    priv->params_ethtool.rx_coalesce_pkts;
866292949Shselasky
867300282Shselasky		/* check to avoid down and up the network interface */
868300282Shselasky		if (was_opened)
869300282Shselasky			error = mlx5e_refresh_channel_params(priv);
870300282Shselasky		break;
871292949Shselasky
872300282Shselasky	case MLX5_PARAM_OFFSET(tx_coalesce_usecs):
873300282Shselasky		/* import TX coal time */
874300282Shselasky		if (priv->params_ethtool.tx_coalesce_usecs < 1)
875300282Shselasky			priv->params_ethtool.tx_coalesce_usecs = 0;
876300282Shselasky		else if (priv->params_ethtool.tx_coalesce_usecs >
877300282Shselasky		    MLX5E_FLD_MAX(cqc, cq_period)) {
878300282Shselasky			priv->params_ethtool.tx_coalesce_usecs =
879300282Shselasky			    MLX5E_FLD_MAX(cqc, cq_period);
880300282Shselasky		}
881300282Shselasky		priv->params.tx_cq_moderation_usec =
882300282Shselasky		    priv->params_ethtool.tx_coalesce_usecs;
883300282Shselasky
884300282Shselasky		/* check to avoid down and up the network interface */
885300282Shselasky		if (was_opened)
886292949Shselasky			error = mlx5e_refresh_channel_params(priv);
887300282Shselasky		break;
888300282Shselasky
889300282Shselasky	case MLX5_PARAM_OFFSET(tx_coalesce_pkts):
890300282Shselasky		/* import TX coal pkts */
891300282Shselasky		if (priv->params_ethtool.tx_coalesce_pkts < 1)
892300282Shselasky			priv->params_ethtool.tx_coalesce_pkts = 0;
893300282Shselasky		else if (priv->params_ethtool.tx_coalesce_pkts >
894300282Shselasky		    MLX5E_FLD_MAX(cqc, cq_max_count)) {
895300282Shselasky			priv->params_ethtool.tx_coalesce_pkts =
896300282Shselasky			    MLX5E_FLD_MAX(cqc, cq_max_count);
897292949Shselasky		}
898300282Shselasky		priv->params.tx_cq_moderation_pkts =
899300282Shselasky		    priv->params_ethtool.tx_coalesce_pkts;
900300282Shselasky
901300282Shselasky		/* check to avoid down and up the network interface */
902300282Shselasky		if (was_opened)
903300282Shselasky			error = mlx5e_refresh_channel_params(priv);
904300282Shselasky		break;
905300282Shselasky
906300282Shselasky	case MLX5_PARAM_OFFSET(tx_queue_size):
907300282Shselasky		/* network interface must be down */
908300282Shselasky		if (was_opened)
909300282Shselasky			mlx5e_close_locked(priv->ifp);
910300282Shselasky
911300282Shselasky		/* import TX queue size */
912300282Shselasky		if (priv->params_ethtool.tx_queue_size <
913300282Shselasky		    (1 << MLX5E_PARAMS_MINIMUM_LOG_SQ_SIZE)) {
914300282Shselasky			priv->params_ethtool.tx_queue_size =
915300282Shselasky			    (1 << MLX5E_PARAMS_MINIMUM_LOG_SQ_SIZE);
916300282Shselasky		} else if (priv->params_ethtool.tx_queue_size >
917300282Shselasky		    priv->params_ethtool.tx_queue_size_max) {
918300282Shselasky			priv->params_ethtool.tx_queue_size =
919300282Shselasky			    priv->params_ethtool.tx_queue_size_max;
920300282Shselasky		}
921300282Shselasky		/* store actual TX queue size */
922300282Shselasky		priv->params.log_sq_size =
923300282Shselasky		    order_base_2(priv->params_ethtool.tx_queue_size);
924290650Shselasky		priv->params_ethtool.tx_queue_size =
925300282Shselasky		    1 << priv->params.log_sq_size;
926290650Shselasky
927300282Shselasky		/* verify TX completion factor */
928300282Shselasky		mlx5e_ethtool_sync_tx_completion_fact(priv);
929300282Shselasky
930300282Shselasky		/* restart network interface, if any */
931300282Shselasky		if (was_opened)
932300282Shselasky			mlx5e_open_locked(priv->ifp);
933300282Shselasky		break;
934300282Shselasky
935300282Shselasky	case MLX5_PARAM_OFFSET(rx_queue_size):
936300282Shselasky		/* network interface must be down */
937300282Shselasky		if (was_opened)
938300282Shselasky			mlx5e_close_locked(priv->ifp);
939300282Shselasky
940300282Shselasky		/* import RX queue size */
941300282Shselasky		if (priv->params_ethtool.rx_queue_size <
942300282Shselasky		    (1 << MLX5E_PARAMS_MINIMUM_LOG_RQ_SIZE)) {
943300282Shselasky			priv->params_ethtool.rx_queue_size =
944300282Shselasky			    (1 << MLX5E_PARAMS_MINIMUM_LOG_RQ_SIZE);
945300282Shselasky		} else if (priv->params_ethtool.rx_queue_size >
946300282Shselasky		    priv->params_ethtool.rx_queue_size_max) {
947300282Shselasky			priv->params_ethtool.rx_queue_size =
948300282Shselasky			    priv->params_ethtool.rx_queue_size_max;
949300282Shselasky		}
950300282Shselasky		/* store actual RX queue size */
951300282Shselasky		priv->params.log_rq_size =
952300282Shselasky		    order_base_2(priv->params_ethtool.rx_queue_size);
953290650Shselasky		priv->params_ethtool.rx_queue_size =
954300282Shselasky		    1 << priv->params.log_rq_size;
955290650Shselasky
956300282Shselasky		/* update least number of RX WQEs */
957300282Shselasky		priv->params.min_rx_wqes = min(
958300282Shselasky		    priv->params_ethtool.rx_queue_size - 1,
959300282Shselasky		    MLX5E_PARAMS_DEFAULT_MIN_RX_WQES);
960290650Shselasky
961300282Shselasky		/* restart network interface, if any */
962300282Shselasky		if (was_opened)
963300282Shselasky			mlx5e_open_locked(priv->ifp);
964300282Shselasky		break;
965290650Shselasky
966338552Shselasky	case MLX5_PARAM_OFFSET(channels_rsss):
967338552Shselasky		/* network interface must be down */
968338552Shselasky		if (was_opened)
969338552Shselasky			mlx5e_close_locked(priv->ifp);
970338552Shselasky
971338552Shselasky		/* import number of channels */
972338552Shselasky		if (priv->params_ethtool.channels_rsss < 1)
973338552Shselasky			priv->params_ethtool.channels_rsss = 1;
974338552Shselasky		else if (priv->params_ethtool.channels_rsss > 128)
975338552Shselasky			priv->params_ethtool.channels_rsss = 128;
976338552Shselasky
977338552Shselasky		priv->params.channels_rsss = priv->params_ethtool.channels_rsss;
978338552Shselasky
979338552Shselasky		/* restart network interface, if any */
980338552Shselasky		if (was_opened)
981338552Shselasky			mlx5e_open_locked(priv->ifp);
982338552Shselasky		break;
983338552Shselasky
984300282Shselasky	case MLX5_PARAM_OFFSET(channels):
985300282Shselasky		/* network interface must be down */
986300282Shselasky		if (was_opened)
987300282Shselasky			mlx5e_close_locked(priv->ifp);
988290650Shselasky
989300282Shselasky		/* import number of channels */
990300282Shselasky		if (priv->params_ethtool.channels < 1)
991300282Shselasky			priv->params_ethtool.channels = 1;
992300282Shselasky		else if (priv->params_ethtool.channels >
993300282Shselasky		    (u64) priv->mdev->priv.eq_table.num_comp_vectors) {
994300282Shselasky			priv->params_ethtool.channels =
995300282Shselasky			    (u64) priv->mdev->priv.eq_table.num_comp_vectors;
996300282Shselasky		}
997300282Shselasky		priv->params.num_channels = priv->params_ethtool.channels;
998291932Shselasky
999300282Shselasky		/* restart network interface, if any */
1000300282Shselasky		if (was_opened)
1001300282Shselasky			mlx5e_open_locked(priv->ifp);
1002300282Shselasky		break;
1003300282Shselasky
1004300282Shselasky	case MLX5_PARAM_OFFSET(rx_coalesce_mode):
1005300282Shselasky		/* network interface must be down */
1006321995Shselasky		if (was_opened != 0 && mode_modify == 0)
1007300282Shselasky			mlx5e_close_locked(priv->ifp);
1008300282Shselasky
1009300282Shselasky		/* import RX coalesce mode */
1010347796Shselasky		if (priv->params_ethtool.rx_coalesce_mode > 3)
1011347796Shselasky			priv->params_ethtool.rx_coalesce_mode = 3;
1012300282Shselasky		priv->params.rx_cq_moderation_mode =
1013300282Shselasky		    priv->params_ethtool.rx_coalesce_mode;
1014300282Shselasky
1015300282Shselasky		/* restart network interface, if any */
1016321995Shselasky		if (was_opened != 0) {
1017321995Shselasky			if (mode_modify == 0)
1018321995Shselasky				mlx5e_open_locked(priv->ifp);
1019321995Shselasky			else
1020321995Shselasky				error = mlx5e_refresh_channel_params(priv);
1021321995Shselasky		}
1022300282Shselasky		break;
1023300282Shselasky
1024300282Shselasky	case MLX5_PARAM_OFFSET(tx_coalesce_mode):
1025300282Shselasky		/* network interface must be down */
1026321995Shselasky		if (was_opened != 0 && mode_modify == 0)
1027300282Shselasky			mlx5e_close_locked(priv->ifp);
1028300282Shselasky
1029300282Shselasky		/* import TX coalesce mode */
1030300282Shselasky		if (priv->params_ethtool.tx_coalesce_mode != 0)
1031300282Shselasky			priv->params_ethtool.tx_coalesce_mode = 1;
1032300282Shselasky		priv->params.tx_cq_moderation_mode =
1033300282Shselasky		    priv->params_ethtool.tx_coalesce_mode;
1034300282Shselasky
1035300282Shselasky		/* restart network interface, if any */
1036321995Shselasky		if (was_opened != 0) {
1037321995Shselasky			if (mode_modify == 0)
1038321995Shselasky				mlx5e_open_locked(priv->ifp);
1039321995Shselasky			else
1040321995Shselasky				error = mlx5e_refresh_channel_params(priv);
1041321995Shselasky		}
1042300282Shselasky		break;
1043300282Shselasky
1044300282Shselasky	case MLX5_PARAM_OFFSET(hw_lro):
1045300282Shselasky		/* network interface must be down */
1046300282Shselasky		if (was_opened)
1047300282Shselasky			mlx5e_close_locked(priv->ifp);
1048300282Shselasky
1049300282Shselasky		/* import HW LRO mode */
1050341983Shselasky		if (priv->params_ethtool.hw_lro != 0 &&
1051341983Shselasky		    MLX5_CAP_ETH(priv->mdev, lro_cap)) {
1052341983Shselasky			priv->params_ethtool.hw_lro = 1;
1053341983Shselasky			/* check if feature should actually be enabled */
1054341983Shselasky			if (priv->ifp->if_capenable & IFCAP_LRO) {
1055341983Shselasky				priv->params.hw_lro_en = true;
1056300282Shselasky			} else {
1057341983Shselasky				priv->params.hw_lro_en = false;
1058300282Shselasky
1059353226Shselasky				mlx5_en_warn(priv->ifp, "To enable HW LRO "
1060341983Shselasky				    "please also enable LRO via ifconfig(8).\n");
1061300282Shselasky			}
1062294319Shselasky		} else {
1063341983Shselasky			/* return an error if HW does not support this feature */
1064341983Shselasky			if (priv->params_ethtool.hw_lro != 0)
1065341983Shselasky				error = EINVAL;
1066341983Shselasky			priv->params.hw_lro_en = false;
1067341983Shselasky			priv->params_ethtool.hw_lro = 0;
1068291068Shselasky		}
1069300282Shselasky		/* restart network interface, if any */
1070300282Shselasky		if (was_opened)
1071300282Shselasky			mlx5e_open_locked(priv->ifp);
1072300282Shselasky		break;
1073290650Shselasky
1074300282Shselasky	case MLX5_PARAM_OFFSET(cqe_zipping):
1075300282Shselasky		/* network interface must be down */
1076300282Shselasky		if (was_opened)
1077300282Shselasky			mlx5e_close_locked(priv->ifp);
1078300282Shselasky
1079300282Shselasky		/* import CQE zipping mode */
1080292838Shselasky		if (priv->params_ethtool.cqe_zipping &&
1081292838Shselasky		    MLX5_CAP_GEN(priv->mdev, cqe_compression)) {
1082292838Shselasky			priv->params.cqe_zipping_en = true;
1083292838Shselasky			priv->params_ethtool.cqe_zipping = 1;
1084292838Shselasky		} else {
1085292838Shselasky			priv->params.cqe_zipping_en = false;
1086292838Shselasky			priv->params_ethtool.cqe_zipping = 0;
1087292838Shselasky		}
1088300282Shselasky		/* restart network interface, if any */
1089300282Shselasky		if (was_opened)
1090300282Shselasky			mlx5e_open_locked(priv->ifp);
1091300282Shselasky		break;
1092300277Shselasky
1093300282Shselasky	case MLX5_PARAM_OFFSET(tx_completion_fact):
1094300282Shselasky		/* network interface must be down */
1095300282Shselasky		if (was_opened)
1096300282Shselasky			mlx5e_close_locked(priv->ifp);
1097300282Shselasky
1098300277Shselasky		/* verify parameter */
1099300277Shselasky		mlx5e_ethtool_sync_tx_completion_fact(priv);
1100300282Shselasky
1101300282Shselasky		/* restart network interface, if any */
1102300282Shselasky		if (was_opened)
1103300282Shselasky			mlx5e_open_locked(priv->ifp);
1104300282Shselasky		break;
1105300282Shselasky
1106331568Shselasky	case MLX5_PARAM_OFFSET(modify_tx_dma):
1107331568Shselasky		/* check if network interface is opened */
1108331568Shselasky		if (was_opened) {
1109331568Shselasky			priv->params_ethtool.modify_tx_dma =
1110331568Shselasky			    priv->params_ethtool.modify_tx_dma ? 1 : 0;
1111331568Shselasky			/* modify tx according to value */
1112331568Shselasky			mlx5e_modify_tx_dma(priv, value != 0);
1113331568Shselasky		} else {
1114331568Shselasky			/* if closed force enable tx */
1115331568Shselasky			priv->params_ethtool.modify_tx_dma = 0;
1116331568Shselasky		}
1117331568Shselasky		break;
1118331568Shselasky
1119331568Shselasky	case MLX5_PARAM_OFFSET(modify_rx_dma):
1120331568Shselasky		/* check if network interface is opened */
1121331568Shselasky		if (was_opened) {
1122331568Shselasky			priv->params_ethtool.modify_rx_dma =
1123331568Shselasky			    priv->params_ethtool.modify_rx_dma ? 1 : 0;
1124331568Shselasky			/* modify rx according to value */
1125331568Shselasky			mlx5e_modify_rx_dma(priv, value != 0);
1126331568Shselasky		} else {
1127331568Shselasky			/* if closed force enable rx */
1128331568Shselasky			priv->params_ethtool.modify_rx_dma = 0;
1129331568Shselasky		}
1130331568Shselasky		break;
1131331568Shselasky
1132322006Shselasky	case MLX5_PARAM_OFFSET(diag_pci_enable):
1133322006Shselasky		priv->params_ethtool.diag_pci_enable =
1134322006Shselasky		    priv->params_ethtool.diag_pci_enable ? 1 : 0;
1135322006Shselasky
1136322006Shselasky		error = -mlx5_core_set_diagnostics_full(priv->mdev,
1137322006Shselasky		    priv->params_ethtool.diag_pci_enable,
1138322006Shselasky		    priv->params_ethtool.diag_general_enable);
1139322006Shselasky		break;
1140322006Shselasky
1141322006Shselasky	case MLX5_PARAM_OFFSET(diag_general_enable):
1142322006Shselasky		priv->params_ethtool.diag_general_enable =
1143322006Shselasky		    priv->params_ethtool.diag_general_enable ? 1 : 0;
1144322006Shselasky
1145322006Shselasky		error = -mlx5_core_set_diagnostics_full(priv->mdev,
1146322006Shselasky		    priv->params_ethtool.diag_pci_enable,
1147322006Shselasky		    priv->params_ethtool.diag_general_enable);
1148322006Shselasky		break;
1149322006Shselasky
1150331569Shselasky	case MLX5_PARAM_OFFSET(mc_local_lb):
1151331569Shselasky		priv->params_ethtool.mc_local_lb =
1152331569Shselasky		    priv->params_ethtool.mc_local_lb ? 1 : 0;
1153331569Shselasky
1154331569Shselasky		if (MLX5_CAP_GEN(priv->mdev, disable_local_lb)) {
1155331569Shselasky			error = mlx5_nic_vport_modify_local_lb(priv->mdev,
1156331569Shselasky			    MLX5_LOCAL_MC_LB, priv->params_ethtool.mc_local_lb);
1157331569Shselasky		} else {
1158331569Shselasky			error = EOPNOTSUPP;
1159331569Shselasky		}
1160331569Shselasky		break;
1161331569Shselasky
1162331569Shselasky	case MLX5_PARAM_OFFSET(uc_local_lb):
1163331569Shselasky		priv->params_ethtool.uc_local_lb =
1164331569Shselasky		    priv->params_ethtool.uc_local_lb ? 1 : 0;
1165331569Shselasky
1166331569Shselasky		if (MLX5_CAP_GEN(priv->mdev, disable_local_lb)) {
1167331569Shselasky			error = mlx5_nic_vport_modify_local_lb(priv->mdev,
1168331569Shselasky			    MLX5_LOCAL_UC_LB, priv->params_ethtool.uc_local_lb);
1169331569Shselasky		} else {
1170331569Shselasky			error = EOPNOTSUPP;
1171331569Shselasky		}
1172331569Shselasky		break;
1173331569Shselasky
1174300282Shselasky	default:
1175300282Shselasky		break;
1176300277Shselasky	}
1177290650Shselaskydone:
1178290650Shselasky	PRIV_UNLOCK(priv);
1179290650Shselasky	return (error);
1180290650Shselasky}
1181290650Shselasky
1182290650Shselaskystatic const char *mlx5e_params_desc[] = {
1183290650Shselasky	MLX5E_PARAMS(MLX5E_STATS_DESC)
1184290650Shselasky};
1185290650Shselasky
1186290650Shselaskystatic const char *mlx5e_port_stats_debug_desc[] = {
1187290650Shselasky	MLX5E_PORT_STATS_DEBUG(MLX5E_STATS_DESC)
1188290650Shselasky};
1189290650Shselasky
1190290650Shselaskystatic int
1191337108Shselaskymlx5e_ethtool_debug_channel_info(SYSCTL_HANDLER_ARGS)
1192337108Shselasky{
1193337108Shselasky	struct mlx5e_priv *priv;
1194337108Shselasky	struct sbuf sb;
1195337108Shselasky	struct mlx5e_channel *c;
1196337108Shselasky	struct mlx5e_sq *sq;
1197337108Shselasky	struct mlx5e_rq *rq;
1198337108Shselasky	int error, i, tc;
1199353202Shselasky	bool opened;
1200337108Shselasky
1201337108Shselasky	priv = arg1;
1202337108Shselasky	error = sysctl_wire_old_buffer(req, 0);
1203337108Shselasky	if (error != 0)
1204337108Shselasky		return (error);
1205353202Shselasky	if (sbuf_new_for_sysctl(&sb, NULL, 1024, req) == NULL)
1206337108Shselasky		return (ENOMEM);
1207337108Shselasky	sbuf_clear_flags(&sb, SBUF_INCLUDENUL);
1208337108Shselasky
1209337108Shselasky	PRIV_LOCK(priv);
1210353202Shselasky	opened = test_bit(MLX5E_STATE_OPENED, &priv->state);
1211353202Shselasky
1212353202Shselasky	sbuf_printf(&sb, "pages irq %d\n",
1213353202Shselasky	    priv->mdev->priv.msix_arr[MLX5_EQ_VEC_PAGES].vector);
1214353202Shselasky	sbuf_printf(&sb, "command irq %d\n",
1215353202Shselasky	    priv->mdev->priv.msix_arr[MLX5_EQ_VEC_CMD].vector);
1216353202Shselasky	sbuf_printf(&sb, "async irq %d\n",
1217353202Shselasky	    priv->mdev->priv.msix_arr[MLX5_EQ_VEC_ASYNC].vector);
1218353202Shselasky
1219353202Shselasky	for (i = 0; i != priv->params.num_channels; i++) {
1220353202Shselasky		int eqn_not_used = -1;
1221353202Shselasky		int irqn = MLX5_EQ_VEC_COMP_BASE;
1222353202Shselasky
1223353202Shselasky		if (mlx5_vector2eqn(priv->mdev, i, &eqn_not_used, &irqn) != 0)
1224353202Shselasky			continue;
1225353202Shselasky
1226353202Shselasky		c = opened ? &priv->channel[i] : NULL;
1227353202Shselasky		rq = opened ? &c->rq : NULL;
1228353202Shselasky		sbuf_printf(&sb, "channel %d rq %d cq %d irq %d\n", i,
1229353202Shselasky		    opened ? rq->rqn : -1,
1230353202Shselasky		    opened ? rq->cq.mcq.cqn : -1,
1231353202Shselasky		    priv->mdev->priv.msix_arr[irqn].vector);
1232353202Shselasky
1233353202Shselasky		for (tc = 0; tc != priv->num_tc; tc++) {
1234353202Shselasky			sq = opened ? &c->sq[tc] : NULL;
1235353202Shselasky			sbuf_printf(&sb, "channel %d tc %d sq %d cq %d irq %d\n",
1236353202Shselasky			    i, tc,
1237353202Shselasky			    opened ? sq->sqn : -1,
1238353202Shselasky			    opened ? sq->cq.mcq.cqn : -1,
1239353202Shselasky			    priv->mdev->priv.msix_arr[irqn].vector);
1240337108Shselasky		}
1241337108Shselasky	}
1242337108Shselasky	PRIV_UNLOCK(priv);
1243337108Shselasky	error = sbuf_finish(&sb);
1244337108Shselasky	sbuf_delete(&sb);
1245337108Shselasky	return (error);
1246337108Shselasky}
1247337108Shselasky
1248337108Shselaskystatic int
1249290650Shselaskymlx5e_ethtool_debug_stats(SYSCTL_HANDLER_ARGS)
1250290650Shselasky{
1251290650Shselasky	struct mlx5e_priv *priv = arg1;
1252341977Shselasky	int sys_debug;
1253341977Shselasky	int error;
1254290650Shselasky
1255341977Shselasky	PRIV_LOCK(priv);
1256347806Shselasky	if (priv->gone != 0) {
1257347806Shselasky		error = ENODEV;
1258347806Shselasky		goto done;
1259347806Shselasky	}
1260290650Shselasky	sys_debug = priv->sysctl_debug;
1261341977Shselasky	error = sysctl_handle_int(oidp, &sys_debug, 0, req);
1262337108Shselasky	if (error != 0 || !req->newptr)
1263341977Shselasky		goto done;
1264341977Shselasky	sys_debug = sys_debug ? 1 : 0;
1265290650Shselasky	if (sys_debug == priv->sysctl_debug)
1266341977Shselasky		goto done;
1267337108Shselasky
1268341977Shselasky	if ((priv->sysctl_debug = sys_debug)) {
1269290650Shselasky		mlx5e_create_stats(&priv->stats.port_stats_debug.ctx,
1270290650Shselasky		    SYSCTL_CHILDREN(priv->sysctl_ifnet), "debug_stats",
1271290650Shselasky		    mlx5e_port_stats_debug_desc, MLX5E_PORT_STATS_DEBUG_NUM,
1272290650Shselasky		    priv->stats.port_stats_debug.arg);
1273341977Shselasky		SYSCTL_ADD_PROC(&priv->stats.port_stats_debug.ctx,
1274337108Shselasky		    SYSCTL_CHILDREN(priv->sysctl_ifnet), OID_AUTO,
1275337108Shselasky		    "hw_ctx_debug",
1276337108Shselasky		    CTLFLAG_RD | CTLFLAG_MPSAFE | CTLTYPE_STRING, priv, 0,
1277337108Shselasky		    mlx5e_ethtool_debug_channel_info, "S", "");
1278337108Shselasky	} else {
1279290650Shselasky		sysctl_ctx_free(&priv->stats.port_stats_debug.ctx);
1280337108Shselasky	}
1281341977Shselaskydone:
1282337108Shselasky	PRIV_UNLOCK(priv);
1283341977Shselasky	return (error);
1284290650Shselasky}
1285290650Shselasky
1286322006Shselaskystatic void
1287322006Shselaskymlx5e_create_diagnostics(struct mlx5e_priv *priv)
1288322006Shselasky{
1289322006Shselasky	struct mlx5_core_diagnostics_entry entry;
1290322006Shselasky	struct sysctl_ctx_list *ctx;
1291322006Shselasky	struct sysctl_oid *node;
1292322006Shselasky	int x;
1293322006Shselasky
1294322006Shselasky	/* sysctl context we are using */
1295322006Shselasky	ctx = &priv->sysctl_ctx;
1296322006Shselasky
1297322006Shselasky	/* create root node */
1298322006Shselasky	node = SYSCTL_ADD_NODE(ctx,
1299322006Shselasky	    SYSCTL_CHILDREN(priv->sysctl_ifnet), OID_AUTO,
1300322006Shselasky	    "diagnostics", CTLFLAG_RD, NULL, "Diagnostics");
1301322006Shselasky	if (node == NULL)
1302322006Shselasky		return;
1303322006Shselasky
1304322006Shselasky	/* create PCI diagnostics */
1305322006Shselasky	for (x = 0; x != MLX5_CORE_PCI_DIAGNOSTICS_NUM; x++) {
1306322006Shselasky		entry = mlx5_core_pci_diagnostics_table[x];
1307322006Shselasky		if (mlx5_core_supports_diagnostics(priv->mdev, entry.counter_id) == 0)
1308322006Shselasky			continue;
1309322006Shselasky		SYSCTL_ADD_UQUAD(ctx, SYSCTL_CHILDREN(node), OID_AUTO,
1310322006Shselasky		    entry.desc, CTLFLAG_RD, priv->params_pci.array + x,
1311322006Shselasky		    "PCI diagnostics counter");
1312322006Shselasky	}
1313322006Shselasky
1314322006Shselasky	/* create general diagnostics */
1315322006Shselasky	for (x = 0; x != MLX5_CORE_GENERAL_DIAGNOSTICS_NUM; x++) {
1316322006Shselasky		entry = mlx5_core_general_diagnostics_table[x];
1317322006Shselasky		if (mlx5_core_supports_diagnostics(priv->mdev, entry.counter_id) == 0)
1318322006Shselasky			continue;
1319322006Shselasky		SYSCTL_ADD_UQUAD(ctx, SYSCTL_CHILDREN(node), OID_AUTO,
1320322006Shselasky		    entry.desc, CTLFLAG_RD, priv->params_general.array + x,
1321322006Shselasky		    "General diagnostics counter");
1322322006Shselasky	}
1323322006Shselasky}
1324322006Shselasky
1325290650Shselaskyvoid
1326290650Shselaskymlx5e_create_ethtool(struct mlx5e_priv *priv)
1327290650Shselasky{
1328353244Shselasky	struct sysctl_oid *fec_node;
1329353244Shselasky	struct sysctl_oid *qos_node;
1330353244Shselasky	struct sysctl_oid *node;
1331290650Shselasky	const char *pnameunit;
1332353238Shselasky	struct mlx5e_port_buffer port_buffer;
1333290650Shselasky	unsigned x;
1334331577Shselasky	int i;
1335290650Shselasky
1336290650Shselasky	/* set some defaults */
1337290650Shselasky	priv->params_ethtool.tx_queue_size_max = 1 << MLX5E_PARAMS_MAXIMUM_LOG_SQ_SIZE;
1338290650Shselasky	priv->params_ethtool.rx_queue_size_max = 1 << MLX5E_PARAMS_MAXIMUM_LOG_RQ_SIZE;
1339290650Shselasky	priv->params_ethtool.tx_queue_size = 1 << priv->params.log_sq_size;
1340290650Shselasky	priv->params_ethtool.rx_queue_size = 1 << priv->params.log_rq_size;
1341290650Shselasky	priv->params_ethtool.channels = priv->params.num_channels;
1342338552Shselasky	priv->params_ethtool.channels_rsss = priv->params.channels_rsss;
1343290650Shselasky	priv->params_ethtool.coalesce_pkts_max = MLX5E_FLD_MAX(cqc, cq_max_count);
1344290650Shselasky	priv->params_ethtool.coalesce_usecs_max = MLX5E_FLD_MAX(cqc, cq_period);
1345290650Shselasky	priv->params_ethtool.rx_coalesce_mode = priv->params.rx_cq_moderation_mode;
1346290650Shselasky	priv->params_ethtool.rx_coalesce_usecs = priv->params.rx_cq_moderation_usec;
1347290650Shselasky	priv->params_ethtool.rx_coalesce_pkts = priv->params.rx_cq_moderation_pkts;
1348291932Shselasky	priv->params_ethtool.tx_coalesce_mode = priv->params.tx_cq_moderation_mode;
1349290650Shselasky	priv->params_ethtool.tx_coalesce_usecs = priv->params.tx_cq_moderation_usec;
1350290650Shselasky	priv->params_ethtool.tx_coalesce_pkts = priv->params.tx_cq_moderation_pkts;
1351290650Shselasky	priv->params_ethtool.hw_lro = priv->params.hw_lro_en;
1352292838Shselasky	priv->params_ethtool.cqe_zipping = priv->params.cqe_zipping_en;
1353300277Shselasky	mlx5e_ethtool_sync_tx_completion_fact(priv);
1354290650Shselasky
1355331569Shselasky	/* get default values for local loopback, if any */
1356331569Shselasky	if (MLX5_CAP_GEN(priv->mdev, disable_local_lb)) {
1357331569Shselasky		int err;
1358331569Shselasky		u8 val;
1359331569Shselasky
1360331569Shselasky		err = mlx5_nic_vport_query_local_lb(priv->mdev, MLX5_LOCAL_MC_LB, &val);
1361331569Shselasky		if (err == 0)
1362331569Shselasky			priv->params_ethtool.mc_local_lb = val;
1363331569Shselasky
1364331569Shselasky		err = mlx5_nic_vport_query_local_lb(priv->mdev, MLX5_LOCAL_UC_LB, &val);
1365331569Shselasky		if (err == 0)
1366331569Shselasky			priv->params_ethtool.uc_local_lb = val;
1367331569Shselasky	}
1368331569Shselasky
1369290650Shselasky	/* create root node */
1370290650Shselasky	node = SYSCTL_ADD_NODE(&priv->sysctl_ctx,
1371290650Shselasky	    SYSCTL_CHILDREN(priv->sysctl_ifnet), OID_AUTO,
1372290650Shselasky	    "conf", CTLFLAG_RW, NULL, "Configuration");
1373290650Shselasky	if (node == NULL)
1374290650Shselasky		return;
1375290650Shselasky	for (x = 0; x != MLX5E_PARAMS_NUM; x++) {
1376290650Shselasky		/* check for read-only parameter */
1377331570Shselasky		if (strstr(mlx5e_params_desc[2 * x], "_max") != NULL ||
1378331570Shselasky		    strstr(mlx5e_params_desc[2 * x], "_mtu") != NULL) {
1379290650Shselasky			SYSCTL_ADD_PROC(&priv->sysctl_ctx, SYSCTL_CHILDREN(node), OID_AUTO,
1380290650Shselasky			    mlx5e_params_desc[2 * x], CTLTYPE_U64 | CTLFLAG_RD |
1381290650Shselasky			    CTLFLAG_MPSAFE, priv, x, &mlx5e_ethtool_handler, "QU",
1382290650Shselasky			    mlx5e_params_desc[2 * x + 1]);
1383290650Shselasky		} else {
1384292837Shselasky#if (__FreeBSD_version < 1100000)
1385292837Shselasky			char path[64];
1386292837Shselasky#endif
1387292837Shselasky			/*
1388292837Shselasky			 * NOTE: In FreeBSD-11 and newer the
1389292837Shselasky			 * CTLFLAG_RWTUN flag will take care of
1390292837Shselasky			 * loading default sysctl value from the
1391292837Shselasky			 * kernel environment, if any:
1392292837Shselasky			 */
1393290650Shselasky			SYSCTL_ADD_PROC(&priv->sysctl_ctx, SYSCTL_CHILDREN(node), OID_AUTO,
1394290650Shselasky			    mlx5e_params_desc[2 * x], CTLTYPE_U64 | CTLFLAG_RWTUN |
1395290650Shselasky			    CTLFLAG_MPSAFE, priv, x, &mlx5e_ethtool_handler, "QU",
1396290650Shselasky			    mlx5e_params_desc[2 * x + 1]);
1397292837Shselasky
1398292837Shselasky#if (__FreeBSD_version < 1100000)
1399292837Shselasky			/* compute path for sysctl */
1400292837Shselasky			snprintf(path, sizeof(path), "dev.mce.%d.conf.%s",
1401292837Shselasky			    device_get_unit(priv->mdev->pdev->dev.bsddev),
1402292837Shselasky			    mlx5e_params_desc[2 * x]);
1403292837Shselasky
1404292837Shselasky			/* try to fetch tunable, if any */
1405292837Shselasky			if (TUNABLE_QUAD_FETCH(path, &priv->params_ethtool.arg[x]))
1406292837Shselasky				mlx5e_ethtool_handler(NULL, priv, x, NULL);
1407292837Shselasky#endif
1408290650Shselasky		}
1409290650Shselasky	}
1410290650Shselasky
1411353244Shselasky	/* create fec node */
1412353244Shselasky	fec_node = SYSCTL_ADD_NODE(&priv->sysctl_ctx,
1413353244Shselasky	    SYSCTL_CHILDREN(node), OID_AUTO,
1414353244Shselasky	    "fec", CTLFLAG_RW, NULL, "Forward Error Correction");
1415353244Shselasky	if (fec_node == NULL)
1416353244Shselasky		return;
1417353244Shselasky
1418353244Shselasky	if (mlx5e_fec_update(priv) == 0) {
1419353244Shselasky		SYSCTL_ADD_U32(&priv->sysctl_ctx, SYSCTL_CHILDREN(fec_node), OID_AUTO,
1420353244Shselasky		    "mode_active", CTLFLAG_RD | CTLFLAG_MPSAFE,
1421353244Shselasky		    &priv->params_ethtool.fec_mode_active, 0,
1422353244Shselasky		    "Current FEC mode bit, if any.");
1423353244Shselasky
1424353244Shselasky		SYSCTL_ADD_PROC(&priv->sysctl_ctx, SYSCTL_CHILDREN(fec_node), OID_AUTO,
1425353244Shselasky		    "mask_10x_25x", CTLTYPE_U8 | CTLFLAG_RWTUN | CTLFLAG_MPSAFE,
1426353244Shselasky		    priv, 0, &mlx5e_fec_mask_10x_25x_handler, "CU",
1427353244Shselasky		    "Set FEC masks for 10G_40G, 25G_50G, 56G, 100G respectivly. "
1428353244Shselasky		    "0:Auto "
1429353244Shselasky		    "1:NOFEC "
1430353244Shselasky		    "2:FIRECODE "
1431353244Shselasky		    "4:RS");
1432353244Shselasky
1433353244Shselasky		SYSCTL_ADD_PROC(&priv->sysctl_ctx, SYSCTL_CHILDREN(fec_node), OID_AUTO,
1434353244Shselasky		    "avail_10x_25x", CTLTYPE_U8 | CTLFLAG_RD | CTLFLAG_MPSAFE,
1435353244Shselasky		    priv, 0, &mlx5e_fec_avail_10x_25x_handler, "CU",
1436353244Shselasky		    "Get available FEC bits for 10G_40G, 25G_50G, 56G, 100G respectivly. "
1437353244Shselasky		    "0:Auto "
1438353244Shselasky		    "1:NOFEC "
1439353244Shselasky		    "2:FIRECODE "
1440353244Shselasky		    "4:RS");
1441353244Shselasky
1442353244Shselasky		SYSCTL_ADD_PROC(&priv->sysctl_ctx, SYSCTL_CHILDREN(fec_node), OID_AUTO,
1443353244Shselasky		    "mask_50x", CTLTYPE_U16 | CTLFLAG_RWTUN | CTLFLAG_MPSAFE,
1444353244Shselasky		    priv, 0, &mlx5e_fec_mask_50x_handler, "SU",
1445353244Shselasky		    "Set FEC masks for 50G 1x, 100G 2x, 200G 4x, 400G 8x respectivly. "
1446353244Shselasky		    "0:Auto "
1447353244Shselasky		    "128:RS "
1448353244Shselasky		    "512:LL RS");
1449353244Shselasky
1450353244Shselasky		SYSCTL_ADD_PROC(&priv->sysctl_ctx, SYSCTL_CHILDREN(fec_node), OID_AUTO,
1451353244Shselasky		    "avail_50x", CTLTYPE_U16 | CTLFLAG_RD | CTLFLAG_MPSAFE,
1452353244Shselasky		    priv, 0, &mlx5e_fec_avail_50x_handler, "SU",
1453353244Shselasky		    "Get available FEC bits for 50G 1x, 100G 2x, 200G 4x, 400G 8x respectivly. "
1454353244Shselasky		    "0:Auto "
1455353244Shselasky		    "128:RS "
1456353244Shselasky		    "512:LL RS");
1457353244Shselasky	}
1458353244Shselasky
1459290650Shselasky	SYSCTL_ADD_PROC(&priv->sysctl_ctx, SYSCTL_CHILDREN(node), OID_AUTO,
1460290650Shselasky	    "debug_stats", CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, priv,
1461290650Shselasky	    0, &mlx5e_ethtool_debug_stats, "I", "Extended debug statistics");
1462290650Shselasky
1463290650Shselasky	pnameunit = device_get_nameunit(priv->mdev->pdev->dev.bsddev);
1464290650Shselasky
1465290650Shselasky	SYSCTL_ADD_STRING(&priv->sysctl_ctx, SYSCTL_CHILDREN(node),
1466290650Shselasky	    OID_AUTO, "device_name", CTLFLAG_RD,
1467290650Shselasky	    __DECONST(void *, pnameunit), 0,
1468290650Shselasky	    "PCI device name");
1469290650Shselasky
1470322006Shselasky	/* Diagnostics support */
1471322006Shselasky	mlx5e_create_diagnostics(priv);
1472331577Shselasky
1473331577Shselasky	/* create qos node */
1474331577Shselasky	qos_node = SYSCTL_ADD_NODE(&priv->sysctl_ctx,
1475331577Shselasky	    SYSCTL_CHILDREN(node), OID_AUTO,
1476331577Shselasky	    "qos", CTLFLAG_RW, NULL, "Quality Of Service configuration");
1477341968Shselasky	if (qos_node == NULL)
1478331577Shselasky		return;
1479331577Shselasky
1480341968Shselasky	/* Priority rate limit support */
1481341968Shselasky	if (mlx5e_getmaxrate(priv) == 0) {
1482341968Shselasky		SYSCTL_ADD_PROC(&priv->sysctl_ctx, SYSCTL_CHILDREN(qos_node),
1483341968Shselasky		    OID_AUTO, "tc_max_rate", CTLTYPE_U64 | CTLFLAG_RWTUN | CTLFLAG_MPSAFE,
1484341968Shselasky		    priv, 0, mlx5e_tc_maxrate_handler, "QU",
1485341968Shselasky		    "Max rate for priority, specified in kilobits, where kilo=1000, "
1486341968Shselasky		    "max_rate must be divisible by 100000");
1487341968Shselasky	}
1488331577Shselasky
1489341968Shselasky	/* Bandwidth limiting by ratio */
1490341968Shselasky	if (mlx5e_get_max_alloc(priv) == 0) {
1491331577Shselasky		SYSCTL_ADD_PROC(&priv->sysctl_ctx, SYSCTL_CHILDREN(qos_node),
1492341968Shselasky		    OID_AUTO, "tc_rate_share", CTLTYPE_U8 | CTLFLAG_RWTUN | CTLFLAG_MPSAFE,
1493341968Shselasky		    priv, 0, mlx5e_tc_rate_share_handler, "QU",
1494341968Shselasky		    "Specify bandwidth ratio from 1 to 100 "
1495341968Shselasky		    "for the available traffic classes");
1496331577Shselasky	}
1497331578Shselasky
1498341968Shselasky	/* Priority to traffic class mapping */
1499341968Shselasky	if (mlx5e_get_prio_tc(priv) == 0) {
1500347810Shselasky		SYSCTL_ADD_PROC(&priv->sysctl_ctx, SYSCTL_CHILDREN(qos_node),
1501347810Shselasky		    OID_AUTO, "prio_0_7_tc", CTLTYPE_U8 | CTLFLAG_RWTUN | CTLFLAG_MPSAFE,
1502347810Shselasky		    priv, 0, mlx5e_prio_to_tc_handler, "CU",
1503347810Shselasky		    "Set traffic class 0 to 7 for priority 0 to 7 inclusivly");
1504331578Shselasky	}
1505337098Shselasky
1506337098Shselasky	/* DSCP support */
1507337098Shselasky	if (mlx5e_get_dscp(priv) == 0) {
1508337098Shselasky		for (i = 0; i != MLX5_MAX_SUPPORTED_DSCP; i += 8) {
1509337098Shselasky			char name[32];
1510337098Shselasky			snprintf(name, sizeof(name), "dscp_%d_%d_prio", i, i + 7);
1511337098Shselasky			SYSCTL_ADD_PROC(&priv->sysctl_ctx, SYSCTL_CHILDREN(qos_node),
1512337098Shselasky				OID_AUTO, name, CTLTYPE_U8 | CTLFLAG_RWTUN | CTLFLAG_MPSAFE,
1513337098Shselasky				priv, i, mlx5e_dscp_prio_handler, "CU",
1514337098Shselasky				"Set DSCP to priority mapping, 0..7");
1515337098Shselasky		}
1516337107Shselasky#define	A	"Set trust state, 1:PCP 2:DSCP"
1517337107Shselasky#define	B	" 3:BOTH"
1518337098Shselasky		SYSCTL_ADD_PROC(&priv->sysctl_ctx, SYSCTL_CHILDREN(qos_node),
1519337098Shselasky		    OID_AUTO, "trust_state", CTLTYPE_U8 | CTLFLAG_RWTUN | CTLFLAG_MPSAFE,
1520337098Shselasky		    priv, 0, mlx5e_trust_state_handler, "CU",
1521347810Shselasky		    MLX5_CAP_QCAM_FEATURE(priv->mdev, qpts_trust_both) ?
1522337107Shselasky		    A B : A);
1523337107Shselasky#undef B
1524337107Shselasky#undef A
1525337098Shselasky	}
1526353238Shselasky
1527353238Shselasky	if (mlx5e_port_query_buffer(priv, &port_buffer) == 0) {
1528353238Shselasky		SYSCTL_ADD_PROC(&priv->sysctl_ctx, SYSCTL_CHILDREN(qos_node),
1529353238Shselasky		    OID_AUTO, "buffers_size",
1530353238Shselasky		    CTLTYPE_U32 | CTLFLAG_RWTUN | CTLFLAG_MPSAFE,
1531353238Shselasky		    priv, 0, mlx5e_buf_size_handler, "IU",
1532353238Shselasky		    "Set buffers sizes");
1533353238Shselasky		SYSCTL_ADD_PROC(&priv->sysctl_ctx, SYSCTL_CHILDREN(qos_node),
1534353238Shselasky		    OID_AUTO, "buffers_prio",
1535353238Shselasky		    CTLTYPE_U8 | CTLFLAG_RWTUN | CTLFLAG_MPSAFE,
1536353238Shselasky		    priv, 0, mlx5e_buf_prio_handler, "CU",
1537353238Shselasky		    "Set prio to buffers mapping");
1538353238Shselasky		SYSCTL_ADD_PROC(&priv->sysctl_ctx, SYSCTL_CHILDREN(qos_node),
1539353238Shselasky		    OID_AUTO, "cable_length",
1540353238Shselasky		    CTLTYPE_UINT | CTLFLAG_RWTUN | CTLFLAG_MPSAFE,
1541353238Shselasky		    priv, 0, mlx5e_cable_length_handler, "IU",
1542353238Shselasky		    "Set cable length in meters for xoff threshold calculation");
1543353238Shselasky	}
1544290650Shselasky}
1545