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