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 361171 2020-05-18 09:04:24Z 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
804361171Shselaskystatic int
805361171Shselaskymlx5e_hw_temperature_handler(SYSCTL_HANDLER_ARGS)
806361171Shselasky{
807361171Shselasky	struct mlx5e_priv *priv = arg1;
808361171Shselasky	int err;
809361171Shselasky
810361171Shselasky	PRIV_LOCK(priv);
811361171Shselasky	err = SYSCTL_OUT(req, priv->params_ethtool.hw_val_temp,
812361171Shselasky	    sizeof(priv->params_ethtool.hw_val_temp[0]) *
813361171Shselasky	    priv->params_ethtool.hw_num_temp);
814361171Shselasky	if (err == 0 && req->newptr != NULL)
815361171Shselasky		err = EOPNOTSUPP;
816361171Shselasky	PRIV_UNLOCK(priv);
817361171Shselasky	return (err);
818361171Shselasky}
819361171Shselasky
820361171Shselaskyint
821361171Shselaskymlx5e_hw_temperature_update(struct mlx5e_priv *priv)
822361171Shselasky{
823361171Shselasky	int err;
824361171Shselasky	u32 x;
825361171Shselasky
826361171Shselasky	if (priv->params_ethtool.hw_num_temp == 0) {
827361171Shselasky		u32 out_cap[MLX5_ST_SZ_DW(mtcap)] = {};
828361171Shselasky		const int sz_cap = MLX5_ST_SZ_BYTES(mtcap);
829361171Shselasky		u32 value;
830361171Shselasky
831361171Shselasky		err = -mlx5_core_access_reg(priv->mdev, NULL, 0, out_cap, sz_cap,
832361171Shselasky		    MLX5_ACCESS_REG_SUMMARY_CTRL_ID_MTCAP, 0, 0);
833361171Shselasky		if (err)
834361171Shselasky			goto done;
835361171Shselasky		value = MLX5_GET(mtcap, out_cap, sensor_count);
836361171Shselasky		if (value == 0)
837361171Shselasky			return (0);
838361171Shselasky		if (value > MLX5_MAX_TEMPERATURE)
839361171Shselasky			value = MLX5_MAX_TEMPERATURE;
840361171Shselasky		/* update number of temperature sensors */
841361171Shselasky		priv->params_ethtool.hw_num_temp = value;
842361171Shselasky	}
843361171Shselasky
844361171Shselasky	for (x = 0; x != priv->params_ethtool.hw_num_temp; x++) {
845361171Shselasky		u32 out_sensor[MLX5_ST_SZ_DW(mtmp_reg)] = {};
846361171Shselasky		const int sz_sensor = MLX5_ST_SZ_BYTES(mtmp_reg);
847361171Shselasky
848361171Shselasky		MLX5_SET(mtmp_reg, out_sensor, sensor_index, x);
849361171Shselasky
850361171Shselasky		err = -mlx5_core_access_reg(priv->mdev, out_sensor, sz_sensor,
851361171Shselasky		    out_sensor, sz_sensor,
852361171Shselasky		    MLX5_ACCESS_REG_SUMMARY_CTRL_ID_MTMP, 0, 0);
853361171Shselasky		if (err)
854361171Shselasky			goto done;
855361171Shselasky		/* convert from 0.125 celcius to millicelcius */
856361171Shselasky		priv->params_ethtool.hw_val_temp[x] =
857361171Shselasky		    (s16)MLX5_GET(mtmp_reg, out_sensor, temperature) * 125;
858361171Shselasky	}
859361171Shselaskydone:
860361171Shselasky	return (err);
861361171Shselasky}
862361171Shselasky
863300282Shselasky#define	MLX5_PARAM_OFFSET(n)				\
864300282Shselasky    __offsetof(struct mlx5e_priv, params_ethtool.n)
865300282Shselasky
866290650Shselaskystatic int
867290650Shselaskymlx5e_ethtool_handler(SYSCTL_HANDLER_ARGS)
868290650Shselasky{
869290650Shselasky	struct mlx5e_priv *priv = arg1;
870290650Shselasky	uint64_t value;
871321995Shselasky	int mode_modify;
872290650Shselasky	int was_opened;
873290650Shselasky	int error;
874290650Shselasky
875290650Shselasky	PRIV_LOCK(priv);
876290650Shselasky	value = priv->params_ethtool.arg[arg2];
877292837Shselasky	if (req != NULL) {
878292837Shselasky		error = sysctl_handle_64(oidp, &value, 0, req);
879292837Shselasky		if (error || req->newptr == NULL ||
880292837Shselasky		    value == priv->params_ethtool.arg[arg2])
881292837Shselasky			goto done;
882290650Shselasky
883292837Shselasky		/* assign new value */
884292837Shselasky		priv->params_ethtool.arg[arg2] = value;
885292837Shselasky	} else {
886292837Shselasky		error = 0;
887292837Shselasky	}
888290650Shselasky	/* check if device is gone */
889290650Shselasky	if (priv->gone) {
890290650Shselasky		error = ENXIO;
891290650Shselasky		goto done;
892290650Shselasky	}
893300282Shselasky	was_opened = test_bit(MLX5E_STATE_OPENED, &priv->state);
894321995Shselasky	mode_modify = MLX5_CAP_GEN(priv->mdev, cq_period_mode_modify);
895290650Shselasky
896300282Shselasky	switch (MLX5_PARAM_OFFSET(arg[arg2])) {
897300282Shselasky	case MLX5_PARAM_OFFSET(rx_coalesce_usecs):
898300282Shselasky		/* import RX coal time */
899300282Shselasky		if (priv->params_ethtool.rx_coalesce_usecs < 1)
900300282Shselasky			priv->params_ethtool.rx_coalesce_usecs = 0;
901300282Shselasky		else if (priv->params_ethtool.rx_coalesce_usecs >
902300282Shselasky		    MLX5E_FLD_MAX(cqc, cq_period)) {
903300282Shselasky			priv->params_ethtool.rx_coalesce_usecs =
904300282Shselasky			    MLX5E_FLD_MAX(cqc, cq_period);
905300282Shselasky		}
906300282Shselasky		priv->params.rx_cq_moderation_usec =
907300282Shselasky		    priv->params_ethtool.rx_coalesce_usecs;
908292949Shselasky
909300282Shselasky		/* check to avoid down and up the network interface */
910300282Shselasky		if (was_opened)
911300282Shselasky			error = mlx5e_refresh_channel_params(priv);
912300282Shselasky		break;
913292949Shselasky
914300282Shselasky	case MLX5_PARAM_OFFSET(rx_coalesce_pkts):
915300282Shselasky		/* import RX coal pkts */
916300282Shselasky		if (priv->params_ethtool.rx_coalesce_pkts < 1)
917300282Shselasky			priv->params_ethtool.rx_coalesce_pkts = 0;
918300282Shselasky		else if (priv->params_ethtool.rx_coalesce_pkts >
919300282Shselasky		    MLX5E_FLD_MAX(cqc, cq_max_count)) {
920300282Shselasky			priv->params_ethtool.rx_coalesce_pkts =
921300282Shselasky			    MLX5E_FLD_MAX(cqc, cq_max_count);
922300282Shselasky		}
923300282Shselasky		priv->params.rx_cq_moderation_pkts =
924300282Shselasky		    priv->params_ethtool.rx_coalesce_pkts;
925292949Shselasky
926300282Shselasky		/* check to avoid down and up the network interface */
927300282Shselasky		if (was_opened)
928300282Shselasky			error = mlx5e_refresh_channel_params(priv);
929300282Shselasky		break;
930292949Shselasky
931300282Shselasky	case MLX5_PARAM_OFFSET(tx_coalesce_usecs):
932300282Shselasky		/* import TX coal time */
933300282Shselasky		if (priv->params_ethtool.tx_coalesce_usecs < 1)
934300282Shselasky			priv->params_ethtool.tx_coalesce_usecs = 0;
935300282Shselasky		else if (priv->params_ethtool.tx_coalesce_usecs >
936300282Shselasky		    MLX5E_FLD_MAX(cqc, cq_period)) {
937300282Shselasky			priv->params_ethtool.tx_coalesce_usecs =
938300282Shselasky			    MLX5E_FLD_MAX(cqc, cq_period);
939300282Shselasky		}
940300282Shselasky		priv->params.tx_cq_moderation_usec =
941300282Shselasky		    priv->params_ethtool.tx_coalesce_usecs;
942300282Shselasky
943300282Shselasky		/* check to avoid down and up the network interface */
944300282Shselasky		if (was_opened)
945292949Shselasky			error = mlx5e_refresh_channel_params(priv);
946300282Shselasky		break;
947300282Shselasky
948300282Shselasky	case MLX5_PARAM_OFFSET(tx_coalesce_pkts):
949300282Shselasky		/* import TX coal pkts */
950300282Shselasky		if (priv->params_ethtool.tx_coalesce_pkts < 1)
951300282Shselasky			priv->params_ethtool.tx_coalesce_pkts = 0;
952300282Shselasky		else if (priv->params_ethtool.tx_coalesce_pkts >
953300282Shselasky		    MLX5E_FLD_MAX(cqc, cq_max_count)) {
954300282Shselasky			priv->params_ethtool.tx_coalesce_pkts =
955300282Shselasky			    MLX5E_FLD_MAX(cqc, cq_max_count);
956292949Shselasky		}
957300282Shselasky		priv->params.tx_cq_moderation_pkts =
958300282Shselasky		    priv->params_ethtool.tx_coalesce_pkts;
959300282Shselasky
960300282Shselasky		/* check to avoid down and up the network interface */
961300282Shselasky		if (was_opened)
962300282Shselasky			error = mlx5e_refresh_channel_params(priv);
963300282Shselasky		break;
964300282Shselasky
965300282Shselasky	case MLX5_PARAM_OFFSET(tx_queue_size):
966300282Shselasky		/* network interface must be down */
967300282Shselasky		if (was_opened)
968300282Shselasky			mlx5e_close_locked(priv->ifp);
969300282Shselasky
970300282Shselasky		/* import TX queue size */
971300282Shselasky		if (priv->params_ethtool.tx_queue_size <
972300282Shselasky		    (1 << MLX5E_PARAMS_MINIMUM_LOG_SQ_SIZE)) {
973300282Shselasky			priv->params_ethtool.tx_queue_size =
974300282Shselasky			    (1 << MLX5E_PARAMS_MINIMUM_LOG_SQ_SIZE);
975300282Shselasky		} else if (priv->params_ethtool.tx_queue_size >
976300282Shselasky		    priv->params_ethtool.tx_queue_size_max) {
977300282Shselasky			priv->params_ethtool.tx_queue_size =
978300282Shselasky			    priv->params_ethtool.tx_queue_size_max;
979300282Shselasky		}
980300282Shselasky		/* store actual TX queue size */
981300282Shselasky		priv->params.log_sq_size =
982300282Shselasky		    order_base_2(priv->params_ethtool.tx_queue_size);
983290650Shselasky		priv->params_ethtool.tx_queue_size =
984300282Shselasky		    1 << priv->params.log_sq_size;
985290650Shselasky
986300282Shselasky		/* verify TX completion factor */
987300282Shselasky		mlx5e_ethtool_sync_tx_completion_fact(priv);
988300282Shselasky
989300282Shselasky		/* restart network interface, if any */
990300282Shselasky		if (was_opened)
991300282Shselasky			mlx5e_open_locked(priv->ifp);
992300282Shselasky		break;
993300282Shselasky
994300282Shselasky	case MLX5_PARAM_OFFSET(rx_queue_size):
995300282Shselasky		/* network interface must be down */
996300282Shselasky		if (was_opened)
997300282Shselasky			mlx5e_close_locked(priv->ifp);
998300282Shselasky
999300282Shselasky		/* import RX queue size */
1000300282Shselasky		if (priv->params_ethtool.rx_queue_size <
1001300282Shselasky		    (1 << MLX5E_PARAMS_MINIMUM_LOG_RQ_SIZE)) {
1002300282Shselasky			priv->params_ethtool.rx_queue_size =
1003300282Shselasky			    (1 << MLX5E_PARAMS_MINIMUM_LOG_RQ_SIZE);
1004300282Shselasky		} else if (priv->params_ethtool.rx_queue_size >
1005300282Shselasky		    priv->params_ethtool.rx_queue_size_max) {
1006300282Shselasky			priv->params_ethtool.rx_queue_size =
1007300282Shselasky			    priv->params_ethtool.rx_queue_size_max;
1008300282Shselasky		}
1009300282Shselasky		/* store actual RX queue size */
1010300282Shselasky		priv->params.log_rq_size =
1011300282Shselasky		    order_base_2(priv->params_ethtool.rx_queue_size);
1012290650Shselasky		priv->params_ethtool.rx_queue_size =
1013300282Shselasky		    1 << priv->params.log_rq_size;
1014290650Shselasky
1015300282Shselasky		/* update least number of RX WQEs */
1016300282Shselasky		priv->params.min_rx_wqes = min(
1017300282Shselasky		    priv->params_ethtool.rx_queue_size - 1,
1018300282Shselasky		    MLX5E_PARAMS_DEFAULT_MIN_RX_WQES);
1019290650Shselasky
1020300282Shselasky		/* restart network interface, if any */
1021300282Shselasky		if (was_opened)
1022300282Shselasky			mlx5e_open_locked(priv->ifp);
1023300282Shselasky		break;
1024290650Shselasky
1025338552Shselasky	case MLX5_PARAM_OFFSET(channels_rsss):
1026338552Shselasky		/* network interface must be down */
1027338552Shselasky		if (was_opened)
1028338552Shselasky			mlx5e_close_locked(priv->ifp);
1029338552Shselasky
1030338552Shselasky		/* import number of channels */
1031338552Shselasky		if (priv->params_ethtool.channels_rsss < 1)
1032338552Shselasky			priv->params_ethtool.channels_rsss = 1;
1033338552Shselasky		else if (priv->params_ethtool.channels_rsss > 128)
1034338552Shselasky			priv->params_ethtool.channels_rsss = 128;
1035338552Shselasky
1036338552Shselasky		priv->params.channels_rsss = priv->params_ethtool.channels_rsss;
1037338552Shselasky
1038338552Shselasky		/* restart network interface, if any */
1039338552Shselasky		if (was_opened)
1040338552Shselasky			mlx5e_open_locked(priv->ifp);
1041338552Shselasky		break;
1042338552Shselasky
1043300282Shselasky	case MLX5_PARAM_OFFSET(channels):
1044300282Shselasky		/* network interface must be down */
1045300282Shselasky		if (was_opened)
1046300282Shselasky			mlx5e_close_locked(priv->ifp);
1047290650Shselasky
1048300282Shselasky		/* import number of channels */
1049300282Shselasky		if (priv->params_ethtool.channels < 1)
1050300282Shselasky			priv->params_ethtool.channels = 1;
1051300282Shselasky		else if (priv->params_ethtool.channels >
1052300282Shselasky		    (u64) priv->mdev->priv.eq_table.num_comp_vectors) {
1053300282Shselasky			priv->params_ethtool.channels =
1054300282Shselasky			    (u64) priv->mdev->priv.eq_table.num_comp_vectors;
1055300282Shselasky		}
1056300282Shselasky		priv->params.num_channels = priv->params_ethtool.channels;
1057291932Shselasky
1058300282Shselasky		/* restart network interface, if any */
1059300282Shselasky		if (was_opened)
1060300282Shselasky			mlx5e_open_locked(priv->ifp);
1061300282Shselasky		break;
1062300282Shselasky
1063300282Shselasky	case MLX5_PARAM_OFFSET(rx_coalesce_mode):
1064300282Shselasky		/* network interface must be down */
1065321995Shselasky		if (was_opened != 0 && mode_modify == 0)
1066300282Shselasky			mlx5e_close_locked(priv->ifp);
1067300282Shselasky
1068300282Shselasky		/* import RX coalesce mode */
1069347796Shselasky		if (priv->params_ethtool.rx_coalesce_mode > 3)
1070347796Shselasky			priv->params_ethtool.rx_coalesce_mode = 3;
1071300282Shselasky		priv->params.rx_cq_moderation_mode =
1072300282Shselasky		    priv->params_ethtool.rx_coalesce_mode;
1073300282Shselasky
1074300282Shselasky		/* restart network interface, if any */
1075321995Shselasky		if (was_opened != 0) {
1076321995Shselasky			if (mode_modify == 0)
1077321995Shselasky				mlx5e_open_locked(priv->ifp);
1078321995Shselasky			else
1079321995Shselasky				error = mlx5e_refresh_channel_params(priv);
1080321995Shselasky		}
1081300282Shselasky		break;
1082300282Shselasky
1083300282Shselasky	case MLX5_PARAM_OFFSET(tx_coalesce_mode):
1084300282Shselasky		/* network interface must be down */
1085321995Shselasky		if (was_opened != 0 && mode_modify == 0)
1086300282Shselasky			mlx5e_close_locked(priv->ifp);
1087300282Shselasky
1088300282Shselasky		/* import TX coalesce mode */
1089300282Shselasky		if (priv->params_ethtool.tx_coalesce_mode != 0)
1090300282Shselasky			priv->params_ethtool.tx_coalesce_mode = 1;
1091300282Shselasky		priv->params.tx_cq_moderation_mode =
1092300282Shselasky		    priv->params_ethtool.tx_coalesce_mode;
1093300282Shselasky
1094300282Shselasky		/* restart network interface, if any */
1095321995Shselasky		if (was_opened != 0) {
1096321995Shselasky			if (mode_modify == 0)
1097321995Shselasky				mlx5e_open_locked(priv->ifp);
1098321995Shselasky			else
1099321995Shselasky				error = mlx5e_refresh_channel_params(priv);
1100321995Shselasky		}
1101300282Shselasky		break;
1102300282Shselasky
1103300282Shselasky	case MLX5_PARAM_OFFSET(hw_lro):
1104300282Shselasky		/* network interface must be down */
1105300282Shselasky		if (was_opened)
1106300282Shselasky			mlx5e_close_locked(priv->ifp);
1107300282Shselasky
1108300282Shselasky		/* import HW LRO mode */
1109341983Shselasky		if (priv->params_ethtool.hw_lro != 0 &&
1110341983Shselasky		    MLX5_CAP_ETH(priv->mdev, lro_cap)) {
1111341983Shselasky			priv->params_ethtool.hw_lro = 1;
1112341983Shselasky			/* check if feature should actually be enabled */
1113341983Shselasky			if (priv->ifp->if_capenable & IFCAP_LRO) {
1114341983Shselasky				priv->params.hw_lro_en = true;
1115300282Shselasky			} else {
1116341983Shselasky				priv->params.hw_lro_en = false;
1117300282Shselasky
1118353226Shselasky				mlx5_en_warn(priv->ifp, "To enable HW LRO "
1119341983Shselasky				    "please also enable LRO via ifconfig(8).\n");
1120300282Shselasky			}
1121294319Shselasky		} else {
1122341983Shselasky			/* return an error if HW does not support this feature */
1123341983Shselasky			if (priv->params_ethtool.hw_lro != 0)
1124341983Shselasky				error = EINVAL;
1125341983Shselasky			priv->params.hw_lro_en = false;
1126341983Shselasky			priv->params_ethtool.hw_lro = 0;
1127291068Shselasky		}
1128300282Shselasky		/* restart network interface, if any */
1129300282Shselasky		if (was_opened)
1130300282Shselasky			mlx5e_open_locked(priv->ifp);
1131300282Shselasky		break;
1132290650Shselasky
1133300282Shselasky	case MLX5_PARAM_OFFSET(cqe_zipping):
1134300282Shselasky		/* network interface must be down */
1135300282Shselasky		if (was_opened)
1136300282Shselasky			mlx5e_close_locked(priv->ifp);
1137300282Shselasky
1138300282Shselasky		/* import CQE zipping mode */
1139292838Shselasky		if (priv->params_ethtool.cqe_zipping &&
1140292838Shselasky		    MLX5_CAP_GEN(priv->mdev, cqe_compression)) {
1141292838Shselasky			priv->params.cqe_zipping_en = true;
1142292838Shselasky			priv->params_ethtool.cqe_zipping = 1;
1143292838Shselasky		} else {
1144292838Shselasky			priv->params.cqe_zipping_en = false;
1145292838Shselasky			priv->params_ethtool.cqe_zipping = 0;
1146292838Shselasky		}
1147300282Shselasky		/* restart network interface, if any */
1148300282Shselasky		if (was_opened)
1149300282Shselasky			mlx5e_open_locked(priv->ifp);
1150300282Shselasky		break;
1151300277Shselasky
1152300282Shselasky	case MLX5_PARAM_OFFSET(tx_completion_fact):
1153300282Shselasky		/* network interface must be down */
1154300282Shselasky		if (was_opened)
1155300282Shselasky			mlx5e_close_locked(priv->ifp);
1156300282Shselasky
1157300277Shselasky		/* verify parameter */
1158300277Shselasky		mlx5e_ethtool_sync_tx_completion_fact(priv);
1159300282Shselasky
1160300282Shselasky		/* restart network interface, if any */
1161300282Shselasky		if (was_opened)
1162300282Shselasky			mlx5e_open_locked(priv->ifp);
1163300282Shselasky		break;
1164300282Shselasky
1165331568Shselasky	case MLX5_PARAM_OFFSET(modify_tx_dma):
1166331568Shselasky		/* check if network interface is opened */
1167331568Shselasky		if (was_opened) {
1168331568Shselasky			priv->params_ethtool.modify_tx_dma =
1169331568Shselasky			    priv->params_ethtool.modify_tx_dma ? 1 : 0;
1170331568Shselasky			/* modify tx according to value */
1171331568Shselasky			mlx5e_modify_tx_dma(priv, value != 0);
1172331568Shselasky		} else {
1173331568Shselasky			/* if closed force enable tx */
1174331568Shselasky			priv->params_ethtool.modify_tx_dma = 0;
1175331568Shselasky		}
1176331568Shselasky		break;
1177331568Shselasky
1178331568Shselasky	case MLX5_PARAM_OFFSET(modify_rx_dma):
1179331568Shselasky		/* check if network interface is opened */
1180331568Shselasky		if (was_opened) {
1181331568Shselasky			priv->params_ethtool.modify_rx_dma =
1182331568Shselasky			    priv->params_ethtool.modify_rx_dma ? 1 : 0;
1183331568Shselasky			/* modify rx according to value */
1184331568Shselasky			mlx5e_modify_rx_dma(priv, value != 0);
1185331568Shselasky		} else {
1186331568Shselasky			/* if closed force enable rx */
1187331568Shselasky			priv->params_ethtool.modify_rx_dma = 0;
1188331568Shselasky		}
1189331568Shselasky		break;
1190331568Shselasky
1191322006Shselasky	case MLX5_PARAM_OFFSET(diag_pci_enable):
1192322006Shselasky		priv->params_ethtool.diag_pci_enable =
1193322006Shselasky		    priv->params_ethtool.diag_pci_enable ? 1 : 0;
1194322006Shselasky
1195322006Shselasky		error = -mlx5_core_set_diagnostics_full(priv->mdev,
1196322006Shselasky		    priv->params_ethtool.diag_pci_enable,
1197322006Shselasky		    priv->params_ethtool.diag_general_enable);
1198322006Shselasky		break;
1199322006Shselasky
1200322006Shselasky	case MLX5_PARAM_OFFSET(diag_general_enable):
1201322006Shselasky		priv->params_ethtool.diag_general_enable =
1202322006Shselasky		    priv->params_ethtool.diag_general_enable ? 1 : 0;
1203322006Shselasky
1204322006Shselasky		error = -mlx5_core_set_diagnostics_full(priv->mdev,
1205322006Shselasky		    priv->params_ethtool.diag_pci_enable,
1206322006Shselasky		    priv->params_ethtool.diag_general_enable);
1207322006Shselasky		break;
1208322006Shselasky
1209331569Shselasky	case MLX5_PARAM_OFFSET(mc_local_lb):
1210331569Shselasky		priv->params_ethtool.mc_local_lb =
1211331569Shselasky		    priv->params_ethtool.mc_local_lb ? 1 : 0;
1212331569Shselasky
1213331569Shselasky		if (MLX5_CAP_GEN(priv->mdev, disable_local_lb)) {
1214331569Shselasky			error = mlx5_nic_vport_modify_local_lb(priv->mdev,
1215331569Shselasky			    MLX5_LOCAL_MC_LB, priv->params_ethtool.mc_local_lb);
1216331569Shselasky		} else {
1217331569Shselasky			error = EOPNOTSUPP;
1218331569Shselasky		}
1219331569Shselasky		break;
1220331569Shselasky
1221331569Shselasky	case MLX5_PARAM_OFFSET(uc_local_lb):
1222331569Shselasky		priv->params_ethtool.uc_local_lb =
1223331569Shselasky		    priv->params_ethtool.uc_local_lb ? 1 : 0;
1224331569Shselasky
1225331569Shselasky		if (MLX5_CAP_GEN(priv->mdev, disable_local_lb)) {
1226331569Shselasky			error = mlx5_nic_vport_modify_local_lb(priv->mdev,
1227331569Shselasky			    MLX5_LOCAL_UC_LB, priv->params_ethtool.uc_local_lb);
1228331569Shselasky		} else {
1229331569Shselasky			error = EOPNOTSUPP;
1230331569Shselasky		}
1231331569Shselasky		break;
1232331569Shselasky
1233300282Shselasky	default:
1234300282Shselasky		break;
1235300277Shselasky	}
1236290650Shselaskydone:
1237290650Shselasky	PRIV_UNLOCK(priv);
1238290650Shselasky	return (error);
1239290650Shselasky}
1240290650Shselasky
1241290650Shselaskystatic const char *mlx5e_params_desc[] = {
1242290650Shselasky	MLX5E_PARAMS(MLX5E_STATS_DESC)
1243290650Shselasky};
1244290650Shselasky
1245290650Shselaskystatic const char *mlx5e_port_stats_debug_desc[] = {
1246290650Shselasky	MLX5E_PORT_STATS_DEBUG(MLX5E_STATS_DESC)
1247290650Shselasky};
1248290650Shselasky
1249290650Shselaskystatic int
1250337108Shselaskymlx5e_ethtool_debug_channel_info(SYSCTL_HANDLER_ARGS)
1251337108Shselasky{
1252337108Shselasky	struct mlx5e_priv *priv;
1253337108Shselasky	struct sbuf sb;
1254337108Shselasky	struct mlx5e_channel *c;
1255337108Shselasky	struct mlx5e_sq *sq;
1256337108Shselasky	struct mlx5e_rq *rq;
1257337108Shselasky	int error, i, tc;
1258353202Shselasky	bool opened;
1259337108Shselasky
1260337108Shselasky	priv = arg1;
1261337108Shselasky	error = sysctl_wire_old_buffer(req, 0);
1262337108Shselasky	if (error != 0)
1263337108Shselasky		return (error);
1264353202Shselasky	if (sbuf_new_for_sysctl(&sb, NULL, 1024, req) == NULL)
1265337108Shselasky		return (ENOMEM);
1266337108Shselasky	sbuf_clear_flags(&sb, SBUF_INCLUDENUL);
1267337108Shselasky
1268337108Shselasky	PRIV_LOCK(priv);
1269353202Shselasky	opened = test_bit(MLX5E_STATE_OPENED, &priv->state);
1270353202Shselasky
1271353202Shselasky	sbuf_printf(&sb, "pages irq %d\n",
1272353202Shselasky	    priv->mdev->priv.msix_arr[MLX5_EQ_VEC_PAGES].vector);
1273353202Shselasky	sbuf_printf(&sb, "command irq %d\n",
1274353202Shselasky	    priv->mdev->priv.msix_arr[MLX5_EQ_VEC_CMD].vector);
1275353202Shselasky	sbuf_printf(&sb, "async irq %d\n",
1276353202Shselasky	    priv->mdev->priv.msix_arr[MLX5_EQ_VEC_ASYNC].vector);
1277353202Shselasky
1278353202Shselasky	for (i = 0; i != priv->params.num_channels; i++) {
1279353202Shselasky		int eqn_not_used = -1;
1280353202Shselasky		int irqn = MLX5_EQ_VEC_COMP_BASE;
1281353202Shselasky
1282353202Shselasky		if (mlx5_vector2eqn(priv->mdev, i, &eqn_not_used, &irqn) != 0)
1283353202Shselasky			continue;
1284353202Shselasky
1285353202Shselasky		c = opened ? &priv->channel[i] : NULL;
1286353202Shselasky		rq = opened ? &c->rq : NULL;
1287353202Shselasky		sbuf_printf(&sb, "channel %d rq %d cq %d irq %d\n", i,
1288353202Shselasky		    opened ? rq->rqn : -1,
1289353202Shselasky		    opened ? rq->cq.mcq.cqn : -1,
1290353202Shselasky		    priv->mdev->priv.msix_arr[irqn].vector);
1291353202Shselasky
1292353202Shselasky		for (tc = 0; tc != priv->num_tc; tc++) {
1293353202Shselasky			sq = opened ? &c->sq[tc] : NULL;
1294353202Shselasky			sbuf_printf(&sb, "channel %d tc %d sq %d cq %d irq %d\n",
1295353202Shselasky			    i, tc,
1296353202Shselasky			    opened ? sq->sqn : -1,
1297353202Shselasky			    opened ? sq->cq.mcq.cqn : -1,
1298353202Shselasky			    priv->mdev->priv.msix_arr[irqn].vector);
1299337108Shselasky		}
1300337108Shselasky	}
1301337108Shselasky	PRIV_UNLOCK(priv);
1302337108Shselasky	error = sbuf_finish(&sb);
1303337108Shselasky	sbuf_delete(&sb);
1304337108Shselasky	return (error);
1305337108Shselasky}
1306337108Shselasky
1307337108Shselaskystatic int
1308290650Shselaskymlx5e_ethtool_debug_stats(SYSCTL_HANDLER_ARGS)
1309290650Shselasky{
1310290650Shselasky	struct mlx5e_priv *priv = arg1;
1311341977Shselasky	int sys_debug;
1312341977Shselasky	int error;
1313290650Shselasky
1314341977Shselasky	PRIV_LOCK(priv);
1315347806Shselasky	if (priv->gone != 0) {
1316347806Shselasky		error = ENODEV;
1317347806Shselasky		goto done;
1318347806Shselasky	}
1319290650Shselasky	sys_debug = priv->sysctl_debug;
1320341977Shselasky	error = sysctl_handle_int(oidp, &sys_debug, 0, req);
1321337108Shselasky	if (error != 0 || !req->newptr)
1322341977Shselasky		goto done;
1323341977Shselasky	sys_debug = sys_debug ? 1 : 0;
1324290650Shselasky	if (sys_debug == priv->sysctl_debug)
1325341977Shselasky		goto done;
1326337108Shselasky
1327341977Shselasky	if ((priv->sysctl_debug = sys_debug)) {
1328290650Shselasky		mlx5e_create_stats(&priv->stats.port_stats_debug.ctx,
1329290650Shselasky		    SYSCTL_CHILDREN(priv->sysctl_ifnet), "debug_stats",
1330290650Shselasky		    mlx5e_port_stats_debug_desc, MLX5E_PORT_STATS_DEBUG_NUM,
1331290650Shselasky		    priv->stats.port_stats_debug.arg);
1332341977Shselasky		SYSCTL_ADD_PROC(&priv->stats.port_stats_debug.ctx,
1333337108Shselasky		    SYSCTL_CHILDREN(priv->sysctl_ifnet), OID_AUTO,
1334337108Shselasky		    "hw_ctx_debug",
1335337108Shselasky		    CTLFLAG_RD | CTLFLAG_MPSAFE | CTLTYPE_STRING, priv, 0,
1336337108Shselasky		    mlx5e_ethtool_debug_channel_info, "S", "");
1337337108Shselasky	} else {
1338290650Shselasky		sysctl_ctx_free(&priv->stats.port_stats_debug.ctx);
1339337108Shselasky	}
1340341977Shselaskydone:
1341337108Shselasky	PRIV_UNLOCK(priv);
1342341977Shselasky	return (error);
1343290650Shselasky}
1344290650Shselasky
1345322006Shselaskystatic void
1346322006Shselaskymlx5e_create_diagnostics(struct mlx5e_priv *priv)
1347322006Shselasky{
1348322006Shselasky	struct mlx5_core_diagnostics_entry entry;
1349322006Shselasky	struct sysctl_ctx_list *ctx;
1350322006Shselasky	struct sysctl_oid *node;
1351322006Shselasky	int x;
1352322006Shselasky
1353322006Shselasky	/* sysctl context we are using */
1354322006Shselasky	ctx = &priv->sysctl_ctx;
1355322006Shselasky
1356322006Shselasky	/* create root node */
1357322006Shselasky	node = SYSCTL_ADD_NODE(ctx,
1358322006Shselasky	    SYSCTL_CHILDREN(priv->sysctl_ifnet), OID_AUTO,
1359322006Shselasky	    "diagnostics", CTLFLAG_RD, NULL, "Diagnostics");
1360322006Shselasky	if (node == NULL)
1361322006Shselasky		return;
1362322006Shselasky
1363322006Shselasky	/* create PCI diagnostics */
1364322006Shselasky	for (x = 0; x != MLX5_CORE_PCI_DIAGNOSTICS_NUM; x++) {
1365322006Shselasky		entry = mlx5_core_pci_diagnostics_table[x];
1366322006Shselasky		if (mlx5_core_supports_diagnostics(priv->mdev, entry.counter_id) == 0)
1367322006Shselasky			continue;
1368322006Shselasky		SYSCTL_ADD_UQUAD(ctx, SYSCTL_CHILDREN(node), OID_AUTO,
1369322006Shselasky		    entry.desc, CTLFLAG_RD, priv->params_pci.array + x,
1370322006Shselasky		    "PCI diagnostics counter");
1371322006Shselasky	}
1372322006Shselasky
1373322006Shselasky	/* create general diagnostics */
1374322006Shselasky	for (x = 0; x != MLX5_CORE_GENERAL_DIAGNOSTICS_NUM; x++) {
1375322006Shselasky		entry = mlx5_core_general_diagnostics_table[x];
1376322006Shselasky		if (mlx5_core_supports_diagnostics(priv->mdev, entry.counter_id) == 0)
1377322006Shselasky			continue;
1378322006Shselasky		SYSCTL_ADD_UQUAD(ctx, SYSCTL_CHILDREN(node), OID_AUTO,
1379322006Shselasky		    entry.desc, CTLFLAG_RD, priv->params_general.array + x,
1380322006Shselasky		    "General diagnostics counter");
1381322006Shselasky	}
1382322006Shselasky}
1383322006Shselasky
1384290650Shselaskyvoid
1385290650Shselaskymlx5e_create_ethtool(struct mlx5e_priv *priv)
1386290650Shselasky{
1387353244Shselasky	struct sysctl_oid *fec_node;
1388353244Shselasky	struct sysctl_oid *qos_node;
1389353244Shselasky	struct sysctl_oid *node;
1390290650Shselasky	const char *pnameunit;
1391353238Shselasky	struct mlx5e_port_buffer port_buffer;
1392290650Shselasky	unsigned x;
1393331577Shselasky	int i;
1394290650Shselasky
1395290650Shselasky	/* set some defaults */
1396290650Shselasky	priv->params_ethtool.tx_queue_size_max = 1 << MLX5E_PARAMS_MAXIMUM_LOG_SQ_SIZE;
1397290650Shselasky	priv->params_ethtool.rx_queue_size_max = 1 << MLX5E_PARAMS_MAXIMUM_LOG_RQ_SIZE;
1398290650Shselasky	priv->params_ethtool.tx_queue_size = 1 << priv->params.log_sq_size;
1399290650Shselasky	priv->params_ethtool.rx_queue_size = 1 << priv->params.log_rq_size;
1400290650Shselasky	priv->params_ethtool.channels = priv->params.num_channels;
1401338552Shselasky	priv->params_ethtool.channels_rsss = priv->params.channels_rsss;
1402290650Shselasky	priv->params_ethtool.coalesce_pkts_max = MLX5E_FLD_MAX(cqc, cq_max_count);
1403290650Shselasky	priv->params_ethtool.coalesce_usecs_max = MLX5E_FLD_MAX(cqc, cq_period);
1404290650Shselasky	priv->params_ethtool.rx_coalesce_mode = priv->params.rx_cq_moderation_mode;
1405290650Shselasky	priv->params_ethtool.rx_coalesce_usecs = priv->params.rx_cq_moderation_usec;
1406290650Shselasky	priv->params_ethtool.rx_coalesce_pkts = priv->params.rx_cq_moderation_pkts;
1407291932Shselasky	priv->params_ethtool.tx_coalesce_mode = priv->params.tx_cq_moderation_mode;
1408290650Shselasky	priv->params_ethtool.tx_coalesce_usecs = priv->params.tx_cq_moderation_usec;
1409290650Shselasky	priv->params_ethtool.tx_coalesce_pkts = priv->params.tx_cq_moderation_pkts;
1410290650Shselasky	priv->params_ethtool.hw_lro = priv->params.hw_lro_en;
1411292838Shselasky	priv->params_ethtool.cqe_zipping = priv->params.cqe_zipping_en;
1412300277Shselasky	mlx5e_ethtool_sync_tx_completion_fact(priv);
1413290650Shselasky
1414331569Shselasky	/* get default values for local loopback, if any */
1415331569Shselasky	if (MLX5_CAP_GEN(priv->mdev, disable_local_lb)) {
1416331569Shselasky		int err;
1417331569Shselasky		u8 val;
1418331569Shselasky
1419331569Shselasky		err = mlx5_nic_vport_query_local_lb(priv->mdev, MLX5_LOCAL_MC_LB, &val);
1420331569Shselasky		if (err == 0)
1421331569Shselasky			priv->params_ethtool.mc_local_lb = val;
1422331569Shselasky
1423331569Shselasky		err = mlx5_nic_vport_query_local_lb(priv->mdev, MLX5_LOCAL_UC_LB, &val);
1424331569Shselasky		if (err == 0)
1425331569Shselasky			priv->params_ethtool.uc_local_lb = val;
1426331569Shselasky	}
1427331569Shselasky
1428290650Shselasky	/* create root node */
1429290650Shselasky	node = SYSCTL_ADD_NODE(&priv->sysctl_ctx,
1430290650Shselasky	    SYSCTL_CHILDREN(priv->sysctl_ifnet), OID_AUTO,
1431290650Shselasky	    "conf", CTLFLAG_RW, NULL, "Configuration");
1432290650Shselasky	if (node == NULL)
1433290650Shselasky		return;
1434290650Shselasky	for (x = 0; x != MLX5E_PARAMS_NUM; x++) {
1435290650Shselasky		/* check for read-only parameter */
1436331570Shselasky		if (strstr(mlx5e_params_desc[2 * x], "_max") != NULL ||
1437331570Shselasky		    strstr(mlx5e_params_desc[2 * x], "_mtu") != NULL) {
1438290650Shselasky			SYSCTL_ADD_PROC(&priv->sysctl_ctx, SYSCTL_CHILDREN(node), OID_AUTO,
1439290650Shselasky			    mlx5e_params_desc[2 * x], CTLTYPE_U64 | CTLFLAG_RD |
1440290650Shselasky			    CTLFLAG_MPSAFE, priv, x, &mlx5e_ethtool_handler, "QU",
1441290650Shselasky			    mlx5e_params_desc[2 * x + 1]);
1442290650Shselasky		} else {
1443292837Shselasky#if (__FreeBSD_version < 1100000)
1444292837Shselasky			char path[64];
1445292837Shselasky#endif
1446292837Shselasky			/*
1447292837Shselasky			 * NOTE: In FreeBSD-11 and newer the
1448292837Shselasky			 * CTLFLAG_RWTUN flag will take care of
1449292837Shselasky			 * loading default sysctl value from the
1450292837Shselasky			 * kernel environment, if any:
1451292837Shselasky			 */
1452290650Shselasky			SYSCTL_ADD_PROC(&priv->sysctl_ctx, SYSCTL_CHILDREN(node), OID_AUTO,
1453290650Shselasky			    mlx5e_params_desc[2 * x], CTLTYPE_U64 | CTLFLAG_RWTUN |
1454290650Shselasky			    CTLFLAG_MPSAFE, priv, x, &mlx5e_ethtool_handler, "QU",
1455290650Shselasky			    mlx5e_params_desc[2 * x + 1]);
1456292837Shselasky
1457292837Shselasky#if (__FreeBSD_version < 1100000)
1458292837Shselasky			/* compute path for sysctl */
1459292837Shselasky			snprintf(path, sizeof(path), "dev.mce.%d.conf.%s",
1460292837Shselasky			    device_get_unit(priv->mdev->pdev->dev.bsddev),
1461292837Shselasky			    mlx5e_params_desc[2 * x]);
1462292837Shselasky
1463292837Shselasky			/* try to fetch tunable, if any */
1464292837Shselasky			if (TUNABLE_QUAD_FETCH(path, &priv->params_ethtool.arg[x]))
1465292837Shselasky				mlx5e_ethtool_handler(NULL, priv, x, NULL);
1466292837Shselasky#endif
1467290650Shselasky		}
1468290650Shselasky	}
1469290650Shselasky
1470353244Shselasky	/* create fec node */
1471353244Shselasky	fec_node = SYSCTL_ADD_NODE(&priv->sysctl_ctx,
1472353244Shselasky	    SYSCTL_CHILDREN(node), OID_AUTO,
1473353244Shselasky	    "fec", CTLFLAG_RW, NULL, "Forward Error Correction");
1474353244Shselasky	if (fec_node == NULL)
1475353244Shselasky		return;
1476353244Shselasky
1477353244Shselasky	if (mlx5e_fec_update(priv) == 0) {
1478353244Shselasky		SYSCTL_ADD_U32(&priv->sysctl_ctx, SYSCTL_CHILDREN(fec_node), OID_AUTO,
1479353244Shselasky		    "mode_active", CTLFLAG_RD | CTLFLAG_MPSAFE,
1480353244Shselasky		    &priv->params_ethtool.fec_mode_active, 0,
1481353244Shselasky		    "Current FEC mode bit, if any.");
1482353244Shselasky
1483353244Shselasky		SYSCTL_ADD_PROC(&priv->sysctl_ctx, SYSCTL_CHILDREN(fec_node), OID_AUTO,
1484353244Shselasky		    "mask_10x_25x", CTLTYPE_U8 | CTLFLAG_RWTUN | CTLFLAG_MPSAFE,
1485353244Shselasky		    priv, 0, &mlx5e_fec_mask_10x_25x_handler, "CU",
1486353244Shselasky		    "Set FEC masks for 10G_40G, 25G_50G, 56G, 100G respectivly. "
1487353244Shselasky		    "0:Auto "
1488353244Shselasky		    "1:NOFEC "
1489353244Shselasky		    "2:FIRECODE "
1490353244Shselasky		    "4:RS");
1491353244Shselasky
1492353244Shselasky		SYSCTL_ADD_PROC(&priv->sysctl_ctx, SYSCTL_CHILDREN(fec_node), OID_AUTO,
1493353244Shselasky		    "avail_10x_25x", CTLTYPE_U8 | CTLFLAG_RD | CTLFLAG_MPSAFE,
1494353244Shselasky		    priv, 0, &mlx5e_fec_avail_10x_25x_handler, "CU",
1495353244Shselasky		    "Get available FEC bits for 10G_40G, 25G_50G, 56G, 100G respectivly. "
1496353244Shselasky		    "0:Auto "
1497353244Shselasky		    "1:NOFEC "
1498353244Shselasky		    "2:FIRECODE "
1499353244Shselasky		    "4:RS");
1500353244Shselasky
1501353244Shselasky		SYSCTL_ADD_PROC(&priv->sysctl_ctx, SYSCTL_CHILDREN(fec_node), OID_AUTO,
1502353244Shselasky		    "mask_50x", CTLTYPE_U16 | CTLFLAG_RWTUN | CTLFLAG_MPSAFE,
1503353244Shselasky		    priv, 0, &mlx5e_fec_mask_50x_handler, "SU",
1504353244Shselasky		    "Set FEC masks for 50G 1x, 100G 2x, 200G 4x, 400G 8x respectivly. "
1505353244Shselasky		    "0:Auto "
1506353244Shselasky		    "128:RS "
1507353244Shselasky		    "512:LL RS");
1508353244Shselasky
1509353244Shselasky		SYSCTL_ADD_PROC(&priv->sysctl_ctx, SYSCTL_CHILDREN(fec_node), OID_AUTO,
1510353244Shselasky		    "avail_50x", CTLTYPE_U16 | CTLFLAG_RD | CTLFLAG_MPSAFE,
1511353244Shselasky		    priv, 0, &mlx5e_fec_avail_50x_handler, "SU",
1512353244Shselasky		    "Get available FEC bits for 50G 1x, 100G 2x, 200G 4x, 400G 8x respectivly. "
1513353244Shselasky		    "0:Auto "
1514353244Shselasky		    "128:RS "
1515353244Shselasky		    "512:LL RS");
1516353244Shselasky	}
1517353244Shselasky
1518290650Shselasky	SYSCTL_ADD_PROC(&priv->sysctl_ctx, SYSCTL_CHILDREN(node), OID_AUTO,
1519290650Shselasky	    "debug_stats", CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, priv,
1520290650Shselasky	    0, &mlx5e_ethtool_debug_stats, "I", "Extended debug statistics");
1521290650Shselasky
1522290650Shselasky	pnameunit = device_get_nameunit(priv->mdev->pdev->dev.bsddev);
1523290650Shselasky
1524290650Shselasky	SYSCTL_ADD_STRING(&priv->sysctl_ctx, SYSCTL_CHILDREN(node),
1525290650Shselasky	    OID_AUTO, "device_name", CTLFLAG_RD,
1526290650Shselasky	    __DECONST(void *, pnameunit), 0,
1527290650Shselasky	    "PCI device name");
1528290650Shselasky
1529322006Shselasky	/* Diagnostics support */
1530322006Shselasky	mlx5e_create_diagnostics(priv);
1531331577Shselasky
1532331577Shselasky	/* create qos node */
1533331577Shselasky	qos_node = SYSCTL_ADD_NODE(&priv->sysctl_ctx,
1534331577Shselasky	    SYSCTL_CHILDREN(node), OID_AUTO,
1535331577Shselasky	    "qos", CTLFLAG_RW, NULL, "Quality Of Service configuration");
1536341968Shselasky	if (qos_node == NULL)
1537331577Shselasky		return;
1538331577Shselasky
1539341968Shselasky	/* Priority rate limit support */
1540341968Shselasky	if (mlx5e_getmaxrate(priv) == 0) {
1541341968Shselasky		SYSCTL_ADD_PROC(&priv->sysctl_ctx, SYSCTL_CHILDREN(qos_node),
1542341968Shselasky		    OID_AUTO, "tc_max_rate", CTLTYPE_U64 | CTLFLAG_RWTUN | CTLFLAG_MPSAFE,
1543341968Shselasky		    priv, 0, mlx5e_tc_maxrate_handler, "QU",
1544341968Shselasky		    "Max rate for priority, specified in kilobits, where kilo=1000, "
1545341968Shselasky		    "max_rate must be divisible by 100000");
1546341968Shselasky	}
1547331577Shselasky
1548341968Shselasky	/* Bandwidth limiting by ratio */
1549341968Shselasky	if (mlx5e_get_max_alloc(priv) == 0) {
1550331577Shselasky		SYSCTL_ADD_PROC(&priv->sysctl_ctx, SYSCTL_CHILDREN(qos_node),
1551341968Shselasky		    OID_AUTO, "tc_rate_share", CTLTYPE_U8 | CTLFLAG_RWTUN | CTLFLAG_MPSAFE,
1552341968Shselasky		    priv, 0, mlx5e_tc_rate_share_handler, "QU",
1553341968Shselasky		    "Specify bandwidth ratio from 1 to 100 "
1554341968Shselasky		    "for the available traffic classes");
1555331577Shselasky	}
1556331578Shselasky
1557341968Shselasky	/* Priority to traffic class mapping */
1558341968Shselasky	if (mlx5e_get_prio_tc(priv) == 0) {
1559347810Shselasky		SYSCTL_ADD_PROC(&priv->sysctl_ctx, SYSCTL_CHILDREN(qos_node),
1560347810Shselasky		    OID_AUTO, "prio_0_7_tc", CTLTYPE_U8 | CTLFLAG_RWTUN | CTLFLAG_MPSAFE,
1561347810Shselasky		    priv, 0, mlx5e_prio_to_tc_handler, "CU",
1562347810Shselasky		    "Set traffic class 0 to 7 for priority 0 to 7 inclusivly");
1563331578Shselasky	}
1564337098Shselasky
1565337098Shselasky	/* DSCP support */
1566337098Shselasky	if (mlx5e_get_dscp(priv) == 0) {
1567337098Shselasky		for (i = 0; i != MLX5_MAX_SUPPORTED_DSCP; i += 8) {
1568337098Shselasky			char name[32];
1569337098Shselasky			snprintf(name, sizeof(name), "dscp_%d_%d_prio", i, i + 7);
1570337098Shselasky			SYSCTL_ADD_PROC(&priv->sysctl_ctx, SYSCTL_CHILDREN(qos_node),
1571337098Shselasky				OID_AUTO, name, CTLTYPE_U8 | CTLFLAG_RWTUN | CTLFLAG_MPSAFE,
1572337098Shselasky				priv, i, mlx5e_dscp_prio_handler, "CU",
1573337098Shselasky				"Set DSCP to priority mapping, 0..7");
1574337098Shselasky		}
1575337107Shselasky#define	A	"Set trust state, 1:PCP 2:DSCP"
1576337107Shselasky#define	B	" 3:BOTH"
1577337098Shselasky		SYSCTL_ADD_PROC(&priv->sysctl_ctx, SYSCTL_CHILDREN(qos_node),
1578337098Shselasky		    OID_AUTO, "trust_state", CTLTYPE_U8 | CTLFLAG_RWTUN | CTLFLAG_MPSAFE,
1579337098Shselasky		    priv, 0, mlx5e_trust_state_handler, "CU",
1580347810Shselasky		    MLX5_CAP_QCAM_FEATURE(priv->mdev, qpts_trust_both) ?
1581337107Shselasky		    A B : A);
1582337107Shselasky#undef B
1583337107Shselasky#undef A
1584337098Shselasky	}
1585353238Shselasky
1586353238Shselasky	if (mlx5e_port_query_buffer(priv, &port_buffer) == 0) {
1587353238Shselasky		SYSCTL_ADD_PROC(&priv->sysctl_ctx, SYSCTL_CHILDREN(qos_node),
1588353238Shselasky		    OID_AUTO, "buffers_size",
1589353238Shselasky		    CTLTYPE_U32 | CTLFLAG_RWTUN | CTLFLAG_MPSAFE,
1590353238Shselasky		    priv, 0, mlx5e_buf_size_handler, "IU",
1591353238Shselasky		    "Set buffers sizes");
1592353238Shselasky		SYSCTL_ADD_PROC(&priv->sysctl_ctx, SYSCTL_CHILDREN(qos_node),
1593353238Shselasky		    OID_AUTO, "buffers_prio",
1594353238Shselasky		    CTLTYPE_U8 | CTLFLAG_RWTUN | CTLFLAG_MPSAFE,
1595353238Shselasky		    priv, 0, mlx5e_buf_prio_handler, "CU",
1596353238Shselasky		    "Set prio to buffers mapping");
1597353238Shselasky		SYSCTL_ADD_PROC(&priv->sysctl_ctx, SYSCTL_CHILDREN(qos_node),
1598353238Shselasky		    OID_AUTO, "cable_length",
1599353238Shselasky		    CTLTYPE_UINT | CTLFLAG_RWTUN | CTLFLAG_MPSAFE,
1600353238Shselasky		    priv, 0, mlx5e_cable_length_handler, "IU",
1601353238Shselasky		    "Set cable length in meters for xoff threshold calculation");
1602353238Shselasky	}
1603361171Shselasky
1604361171Shselasky	if (mlx5e_hw_temperature_update(priv) == 0) {
1605361171Shselasky		SYSCTL_ADD_PROC(&priv->sysctl_ctx, SYSCTL_CHILDREN(priv->sysctl_ifnet),
1606361171Shselasky		    OID_AUTO, "hw_temperature",
1607361171Shselasky		    CTLTYPE_S32 | CTLFLAG_RD | CTLFLAG_MPSAFE,
1608361171Shselasky		    priv, 0, mlx5e_hw_temperature_handler, "I",
1609361171Shselasky		    "HW temperature in millicelcius");
1610361171Shselasky	}
1611290650Shselasky}
1612