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