]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/dev/mlx5/mlx5_en/mlx5_en_ethtool.c
Merge upstream patch to unbreak tunnel forwarding.
[FreeBSD/FreeBSD.git] / sys / dev / mlx5 / mlx5_en / mlx5_en_ethtool.c
1 /*-
2  * Copyright (c) 2015 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 <net/sff8472.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, 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 static void
52 mlx5e_ethtool_sync_tx_completion_fact(struct mlx5e_priv *priv)
53 {
54         /*
55          * Limit the maximum distance between completion events to
56          * half of the currently set TX queue size.
57          *
58          * The maximum number of queue entries a single IP packet can
59          * consume is given by MLX5_SEND_WQE_MAX_WQEBBS.
60          *
61          * The worst case max value is then given as below:
62          */
63         uint64_t max = priv->params_ethtool.tx_queue_size /
64             (2 * MLX5_SEND_WQE_MAX_WQEBBS);
65
66         /*
67          * Update the maximum completion factor value in case the
68          * tx_queue_size field changed. Ensure we don't overflow
69          * 16-bits.
70          */
71         if (max < 1)
72                 max = 1;
73         else if (max > 65535)
74                 max = 65535;
75         priv->params_ethtool.tx_completion_fact_max = max;
76
77         /*
78          * Verify that the current TX completion factor is within the
79          * given limits:
80          */
81         if (priv->params_ethtool.tx_completion_fact < 1)
82                 priv->params_ethtool.tx_completion_fact = 1;
83         else if (priv->params_ethtool.tx_completion_fact > max)
84                 priv->params_ethtool.tx_completion_fact = max;
85 }
86
87 static int
88 mlx5e_getmaxrate(struct mlx5e_priv *priv)
89 {
90         struct mlx5_core_dev *mdev = priv->mdev;
91         u8 max_bw_unit[IEEE_8021QAZ_MAX_TCS];
92         u8 max_bw_value[IEEE_8021QAZ_MAX_TCS];
93         int err;
94         int i;
95
96         PRIV_LOCK(priv);
97         err = -mlx5_query_port_tc_rate_limit(mdev, max_bw_value, max_bw_unit);
98         if (err)
99                 goto done;
100
101         for (i = 0; i <= mlx5_max_tc(mdev); i++) {
102                 switch (max_bw_unit[i]) {
103                 case MLX5_100_MBPS_UNIT:
104                         priv->params_ethtool.max_bw_value[i] = max_bw_value[i] * MLX5E_100MB;
105                         break;
106                 case MLX5_GBPS_UNIT:
107                         priv->params_ethtool.max_bw_value[i] = max_bw_value[i] * MLX5E_1GB;
108                         break;
109                 case MLX5_BW_NO_LIMIT:
110                         priv->params_ethtool.max_bw_value[i] = 0;
111                         break;
112                 default:
113                         priv->params_ethtool.max_bw_value[i] = -1;
114                         WARN_ONCE(true, "non-supported BW unit");
115                         break;
116                 }
117         }
118 done:
119         PRIV_UNLOCK(priv);
120         return (err);
121 }
122
123 static int
124 mlx5e_tc_maxrate_handler(SYSCTL_HANDLER_ARGS)
125 {
126         struct mlx5e_priv *priv = arg1;
127         int prio_index = arg2;
128         struct mlx5_core_dev *mdev = priv->mdev;
129         u8 max_bw_unit[IEEE_8021QAZ_MAX_TCS];
130         u8 max_bw_value[IEEE_8021QAZ_MAX_TCS];
131         int i, err;
132         u64 bw_val;
133         u64 result = priv->params_ethtool.max_bw_value[prio_index];
134         const u64 upper_limit_mbps = 255 * MLX5E_100MB;
135         const u64 upper_limit_gbps = 255 * MLX5E_1GB;
136
137         PRIV_LOCK(priv);
138         err = sysctl_handle_64(oidp, &result, 0, req);
139         if (err || !req->newptr ||
140             result == priv->params_ethtool.max_bw_value[prio_index])
141                 goto done;
142
143         if (result % MLX5E_100MB) {
144                 err = ERANGE;
145                 goto done;
146         }
147
148         memset(max_bw_value, 0, sizeof(max_bw_value));
149         memset(max_bw_unit, 0, sizeof(max_bw_unit));
150
151         for (i = 0; i <= mlx5_max_tc(mdev); i++) {
152                 bw_val = (i == prio_index) ? result : priv->params_ethtool.max_bw_value[i];
153
154                 if (!bw_val) {
155                         max_bw_unit[i] = MLX5_BW_NO_LIMIT;
156                 } else if (bw_val > upper_limit_gbps) {
157                         result = 0;
158                         max_bw_unit[i] = MLX5_BW_NO_LIMIT;
159                 } else if (bw_val <= upper_limit_mbps) {
160                         max_bw_value[i] = howmany(bw_val, MLX5E_100MB);
161                         max_bw_unit[i]  = MLX5_100_MBPS_UNIT;
162                 } else {
163                         max_bw_value[i] = howmany(bw_val, MLX5E_1GB);
164                         max_bw_unit[i]  = MLX5_GBPS_UNIT;
165                 }
166         }
167
168         err = -mlx5_modify_port_tc_rate_limit(mdev, max_bw_value, max_bw_unit);
169         if (err)
170                 goto done;
171
172         priv->params_ethtool.max_bw_value[prio_index] = result;
173 done:
174         PRIV_UNLOCK(priv);
175         return (err);
176 }
177
178 static int
179 mlx5e_get_prio_tc(struct mlx5e_priv *priv)
180 {
181         struct mlx5_core_dev *mdev = priv->mdev;
182         int err = 0;
183         int i;
184
185         PRIV_LOCK(priv);
186         if (!MLX5_CAP_GEN(priv->mdev, ets)) {
187                 PRIV_UNLOCK(priv);
188                 return (EOPNOTSUPP);
189         }
190
191         for (i = 0; i <= mlx5_max_tc(priv->mdev); i++) {
192                 err = -mlx5_query_port_prio_tc(mdev, i, &(priv->params_ethtool.prio_tc[i]));
193                 if (err)
194                         break;
195         }
196
197         PRIV_UNLOCK(priv);
198         return (err);
199 }
200
201 static int
202 mlx5e_prio_to_tc_handler(SYSCTL_HANDLER_ARGS)
203 {
204         struct mlx5e_priv *priv = arg1;
205         int prio_index = arg2;
206         struct mlx5_core_dev *mdev = priv->mdev;
207         int err;
208         uint8_t result = priv->params_ethtool.prio_tc[prio_index];
209
210         PRIV_LOCK(priv);
211         err = sysctl_handle_8(oidp, &result, 0, req);
212         if (err || !req->newptr ||
213             result == priv->params_ethtool.prio_tc[prio_index])
214                 goto done;
215
216         if (result > mlx5_max_tc(mdev)) {
217                 err = ERANGE;
218                 goto done;
219         }
220
221         err = -mlx5_set_port_prio_tc(mdev, prio_index, result);
222         if (err)
223                 goto done;
224
225         priv->params_ethtool.prio_tc[prio_index] = result;
226
227 done:
228         PRIV_UNLOCK(priv);
229         return (err);
230 }
231
232 #define MLX5_PARAM_OFFSET(n)                            \
233     __offsetof(struct mlx5e_priv, params_ethtool.n)
234
235 static int
236 mlx5e_ethtool_handler(SYSCTL_HANDLER_ARGS)
237 {
238         struct mlx5e_priv *priv = arg1;
239         uint64_t value;
240         int mode_modify;
241         int was_opened;
242         int error;
243
244         PRIV_LOCK(priv);
245         value = priv->params_ethtool.arg[arg2];
246         if (req != NULL) {
247                 error = sysctl_handle_64(oidp, &value, 0, req);
248                 if (error || req->newptr == NULL ||
249                     value == priv->params_ethtool.arg[arg2])
250                         goto done;
251
252                 /* assign new value */
253                 priv->params_ethtool.arg[arg2] = value;
254         } else {
255                 error = 0;
256         }
257         /* check if device is gone */
258         if (priv->gone) {
259                 error = ENXIO;
260                 goto done;
261         }
262         was_opened = test_bit(MLX5E_STATE_OPENED, &priv->state);
263         mode_modify = MLX5_CAP_GEN(priv->mdev, cq_period_mode_modify);
264
265         switch (MLX5_PARAM_OFFSET(arg[arg2])) {
266         case MLX5_PARAM_OFFSET(rx_coalesce_usecs):
267                 /* import RX coal time */
268                 if (priv->params_ethtool.rx_coalesce_usecs < 1)
269                         priv->params_ethtool.rx_coalesce_usecs = 0;
270                 else if (priv->params_ethtool.rx_coalesce_usecs >
271                     MLX5E_FLD_MAX(cqc, cq_period)) {
272                         priv->params_ethtool.rx_coalesce_usecs =
273                             MLX5E_FLD_MAX(cqc, cq_period);
274                 }
275                 priv->params.rx_cq_moderation_usec =
276                     priv->params_ethtool.rx_coalesce_usecs;
277
278                 /* check to avoid down and up the network interface */
279                 if (was_opened)
280                         error = mlx5e_refresh_channel_params(priv);
281                 break;
282
283         case MLX5_PARAM_OFFSET(rx_coalesce_pkts):
284                 /* import RX coal pkts */
285                 if (priv->params_ethtool.rx_coalesce_pkts < 1)
286                         priv->params_ethtool.rx_coalesce_pkts = 0;
287                 else if (priv->params_ethtool.rx_coalesce_pkts >
288                     MLX5E_FLD_MAX(cqc, cq_max_count)) {
289                         priv->params_ethtool.rx_coalesce_pkts =
290                             MLX5E_FLD_MAX(cqc, cq_max_count);
291                 }
292                 priv->params.rx_cq_moderation_pkts =
293                     priv->params_ethtool.rx_coalesce_pkts;
294
295                 /* check to avoid down and up the network interface */
296                 if (was_opened)
297                         error = mlx5e_refresh_channel_params(priv);
298                 break;
299
300         case MLX5_PARAM_OFFSET(tx_coalesce_usecs):
301                 /* import TX coal time */
302                 if (priv->params_ethtool.tx_coalesce_usecs < 1)
303                         priv->params_ethtool.tx_coalesce_usecs = 0;
304                 else if (priv->params_ethtool.tx_coalesce_usecs >
305                     MLX5E_FLD_MAX(cqc, cq_period)) {
306                         priv->params_ethtool.tx_coalesce_usecs =
307                             MLX5E_FLD_MAX(cqc, cq_period);
308                 }
309                 priv->params.tx_cq_moderation_usec =
310                     priv->params_ethtool.tx_coalesce_usecs;
311
312                 /* check to avoid down and up the network interface */
313                 if (was_opened)
314                         error = mlx5e_refresh_channel_params(priv);
315                 break;
316
317         case MLX5_PARAM_OFFSET(tx_coalesce_pkts):
318                 /* import TX coal pkts */
319                 if (priv->params_ethtool.tx_coalesce_pkts < 1)
320                         priv->params_ethtool.tx_coalesce_pkts = 0;
321                 else if (priv->params_ethtool.tx_coalesce_pkts >
322                     MLX5E_FLD_MAX(cqc, cq_max_count)) {
323                         priv->params_ethtool.tx_coalesce_pkts =
324                             MLX5E_FLD_MAX(cqc, cq_max_count);
325                 }
326                 priv->params.tx_cq_moderation_pkts =
327                     priv->params_ethtool.tx_coalesce_pkts;
328
329                 /* check to avoid down and up the network interface */
330                 if (was_opened)
331                         error = mlx5e_refresh_channel_params(priv);
332                 break;
333
334         case MLX5_PARAM_OFFSET(tx_queue_size):
335                 /* network interface must be down */
336                 if (was_opened)
337                         mlx5e_close_locked(priv->ifp);
338
339                 /* import TX queue size */
340                 if (priv->params_ethtool.tx_queue_size <
341                     (1 << MLX5E_PARAMS_MINIMUM_LOG_SQ_SIZE)) {
342                         priv->params_ethtool.tx_queue_size =
343                             (1 << MLX5E_PARAMS_MINIMUM_LOG_SQ_SIZE);
344                 } else if (priv->params_ethtool.tx_queue_size >
345                     priv->params_ethtool.tx_queue_size_max) {
346                         priv->params_ethtool.tx_queue_size =
347                             priv->params_ethtool.tx_queue_size_max;
348                 }
349                 /* store actual TX queue size */
350                 priv->params.log_sq_size =
351                     order_base_2(priv->params_ethtool.tx_queue_size);
352                 priv->params_ethtool.tx_queue_size =
353                     1 << priv->params.log_sq_size;
354
355                 /* verify TX completion factor */
356                 mlx5e_ethtool_sync_tx_completion_fact(priv);
357
358                 /* restart network interface, if any */
359                 if (was_opened)
360                         mlx5e_open_locked(priv->ifp);
361                 break;
362
363         case MLX5_PARAM_OFFSET(rx_queue_size):
364                 /* network interface must be down */
365                 if (was_opened)
366                         mlx5e_close_locked(priv->ifp);
367
368                 /* import RX queue size */
369                 if (priv->params_ethtool.rx_queue_size <
370                     (1 << MLX5E_PARAMS_MINIMUM_LOG_RQ_SIZE)) {
371                         priv->params_ethtool.rx_queue_size =
372                             (1 << MLX5E_PARAMS_MINIMUM_LOG_RQ_SIZE);
373                 } else if (priv->params_ethtool.rx_queue_size >
374                     priv->params_ethtool.rx_queue_size_max) {
375                         priv->params_ethtool.rx_queue_size =
376                             priv->params_ethtool.rx_queue_size_max;
377                 }
378                 /* store actual RX queue size */
379                 priv->params.log_rq_size =
380                     order_base_2(priv->params_ethtool.rx_queue_size);
381                 priv->params_ethtool.rx_queue_size =
382                     1 << priv->params.log_rq_size;
383
384                 /* update least number of RX WQEs */
385                 priv->params.min_rx_wqes = min(
386                     priv->params_ethtool.rx_queue_size - 1,
387                     MLX5E_PARAMS_DEFAULT_MIN_RX_WQES);
388
389                 /* restart network interface, if any */
390                 if (was_opened)
391                         mlx5e_open_locked(priv->ifp);
392                 break;
393
394         case MLX5_PARAM_OFFSET(channels):
395                 /* network interface must be down */
396                 if (was_opened)
397                         mlx5e_close_locked(priv->ifp);
398
399                 /* import number of channels */
400                 if (priv->params_ethtool.channels < 1)
401                         priv->params_ethtool.channels = 1;
402                 else if (priv->params_ethtool.channels >
403                     (u64) priv->mdev->priv.eq_table.num_comp_vectors) {
404                         priv->params_ethtool.channels =
405                             (u64) priv->mdev->priv.eq_table.num_comp_vectors;
406                 }
407                 priv->params.num_channels = priv->params_ethtool.channels;
408
409                 /* restart network interface, if any */
410                 if (was_opened)
411                         mlx5e_open_locked(priv->ifp);
412                 break;
413
414         case MLX5_PARAM_OFFSET(rx_coalesce_mode):
415                 /* network interface must be down */
416                 if (was_opened != 0 && mode_modify == 0)
417                         mlx5e_close_locked(priv->ifp);
418
419                 /* import RX coalesce mode */
420                 if (priv->params_ethtool.rx_coalesce_mode != 0)
421                         priv->params_ethtool.rx_coalesce_mode = 1;
422                 priv->params.rx_cq_moderation_mode =
423                     priv->params_ethtool.rx_coalesce_mode;
424
425                 /* restart network interface, if any */
426                 if (was_opened != 0) {
427                         if (mode_modify == 0)
428                                 mlx5e_open_locked(priv->ifp);
429                         else
430                                 error = mlx5e_refresh_channel_params(priv);
431                 }
432                 break;
433
434         case MLX5_PARAM_OFFSET(tx_coalesce_mode):
435                 /* network interface must be down */
436                 if (was_opened != 0 && mode_modify == 0)
437                         mlx5e_close_locked(priv->ifp);
438
439                 /* import TX coalesce mode */
440                 if (priv->params_ethtool.tx_coalesce_mode != 0)
441                         priv->params_ethtool.tx_coalesce_mode = 1;
442                 priv->params.tx_cq_moderation_mode =
443                     priv->params_ethtool.tx_coalesce_mode;
444
445                 /* restart network interface, if any */
446                 if (was_opened != 0) {
447                         if (mode_modify == 0)
448                                 mlx5e_open_locked(priv->ifp);
449                         else
450                                 error = mlx5e_refresh_channel_params(priv);
451                 }
452                 break;
453
454         case MLX5_PARAM_OFFSET(hw_lro):
455                 /* network interface must be down */
456                 if (was_opened)
457                         mlx5e_close_locked(priv->ifp);
458
459                 /* import HW LRO mode */
460                 if (priv->params_ethtool.hw_lro != 0) {
461                         if ((priv->ifp->if_capenable & IFCAP_LRO) &&
462                             MLX5_CAP_ETH(priv->mdev, lro_cap)) {
463                                 priv->params.hw_lro_en = 1;
464                                 priv->params_ethtool.hw_lro = 1;
465                         } else {
466                                 priv->params.hw_lro_en = 0;
467                                 priv->params_ethtool.hw_lro = 0;
468                                 error = EINVAL;
469
470                                 if_printf(priv->ifp, "Can't enable HW LRO: "
471                                     "The HW or SW LRO feature is disabled\n");
472                         }
473                 } else {
474                         priv->params.hw_lro_en = 0;
475                 }
476                 /* restart network interface, if any */
477                 if (was_opened)
478                         mlx5e_open_locked(priv->ifp);
479                 break;
480
481         case MLX5_PARAM_OFFSET(cqe_zipping):
482                 /* network interface must be down */
483                 if (was_opened)
484                         mlx5e_close_locked(priv->ifp);
485
486                 /* import CQE zipping mode */
487                 if (priv->params_ethtool.cqe_zipping &&
488                     MLX5_CAP_GEN(priv->mdev, cqe_compression)) {
489                         priv->params.cqe_zipping_en = true;
490                         priv->params_ethtool.cqe_zipping = 1;
491                 } else {
492                         priv->params.cqe_zipping_en = false;
493                         priv->params_ethtool.cqe_zipping = 0;
494                 }
495                 /* restart network interface, if any */
496                 if (was_opened)
497                         mlx5e_open_locked(priv->ifp);
498                 break;
499
500         case MLX5_PARAM_OFFSET(tx_bufring_disable):
501                 /* rangecheck input value */
502                 priv->params_ethtool.tx_bufring_disable =
503                     priv->params_ethtool.tx_bufring_disable ? 1 : 0;
504
505                 /* reconfigure the sendqueues, if any */
506                 if (was_opened) {
507                         mlx5e_close_locked(priv->ifp);
508                         mlx5e_open_locked(priv->ifp);
509                 }
510                 break;
511
512         case MLX5_PARAM_OFFSET(tx_completion_fact):
513                 /* network interface must be down */
514                 if (was_opened)
515                         mlx5e_close_locked(priv->ifp);
516
517                 /* verify parameter */
518                 mlx5e_ethtool_sync_tx_completion_fact(priv);
519
520                 /* restart network interface, if any */
521                 if (was_opened)
522                         mlx5e_open_locked(priv->ifp);
523                 break;
524
525         case MLX5_PARAM_OFFSET(modify_tx_dma):
526                 /* check if network interface is opened */
527                 if (was_opened) {
528                         priv->params_ethtool.modify_tx_dma =
529                             priv->params_ethtool.modify_tx_dma ? 1 : 0;
530                         /* modify tx according to value */
531                         mlx5e_modify_tx_dma(priv, value != 0);
532                 } else {
533                         /* if closed force enable tx */
534                         priv->params_ethtool.modify_tx_dma = 0;
535                 }
536                 break;
537
538         case MLX5_PARAM_OFFSET(modify_rx_dma):
539                 /* check if network interface is opened */
540                 if (was_opened) {
541                         priv->params_ethtool.modify_rx_dma =
542                             priv->params_ethtool.modify_rx_dma ? 1 : 0;
543                         /* modify rx according to value */
544                         mlx5e_modify_rx_dma(priv, value != 0);
545                 } else {
546                         /* if closed force enable rx */
547                         priv->params_ethtool.modify_rx_dma = 0;
548                 }
549                 break;
550
551         case MLX5_PARAM_OFFSET(diag_pci_enable):
552                 priv->params_ethtool.diag_pci_enable =
553                     priv->params_ethtool.diag_pci_enable ? 1 : 0;
554
555                 error = -mlx5_core_set_diagnostics_full(priv->mdev,
556                     priv->params_ethtool.diag_pci_enable,
557                     priv->params_ethtool.diag_general_enable);
558                 break;
559
560         case MLX5_PARAM_OFFSET(diag_general_enable):
561                 priv->params_ethtool.diag_general_enable =
562                     priv->params_ethtool.diag_general_enable ? 1 : 0;
563
564                 error = -mlx5_core_set_diagnostics_full(priv->mdev,
565                     priv->params_ethtool.diag_pci_enable,
566                     priv->params_ethtool.diag_general_enable);
567                 break;
568
569         case MLX5_PARAM_OFFSET(mc_local_lb):
570                 priv->params_ethtool.mc_local_lb =
571                     priv->params_ethtool.mc_local_lb ? 1 : 0;
572
573                 if (MLX5_CAP_GEN(priv->mdev, disable_local_lb)) {
574                         error = mlx5_nic_vport_modify_local_lb(priv->mdev,
575                             MLX5_LOCAL_MC_LB, priv->params_ethtool.mc_local_lb);
576                 } else {
577                         error = EOPNOTSUPP;
578                 }
579                 break;
580
581         case MLX5_PARAM_OFFSET(uc_local_lb):
582                 priv->params_ethtool.uc_local_lb =
583                     priv->params_ethtool.uc_local_lb ? 1 : 0;
584
585                 if (MLX5_CAP_GEN(priv->mdev, disable_local_lb)) {
586                         error = mlx5_nic_vport_modify_local_lb(priv->mdev,
587                             MLX5_LOCAL_UC_LB, priv->params_ethtool.uc_local_lb);
588                 } else {
589                         error = EOPNOTSUPP;
590                 }
591                 break;
592
593         default:
594                 break;
595         }
596 done:
597         PRIV_UNLOCK(priv);
598         return (error);
599 }
600
601 /*
602  * Read the first three bytes of the eeprom in order to get the needed info
603  * for the whole reading.
604  * Byte 0 - Identifier byte
605  * Byte 1 - Revision byte
606  * Byte 2 - Status byte
607  */
608 static int
609 mlx5e_get_eeprom_info(struct mlx5e_priv *priv, struct mlx5e_eeprom *eeprom)
610 {
611         struct mlx5_core_dev *dev = priv->mdev;
612         u32 data = 0;
613         int size_read = 0;
614         int ret;
615
616         ret = mlx5_query_module_num(dev, &eeprom->module_num);
617         if (ret) {
618                 if_printf(priv->ifp, "%s:%d: Failed query module error=%d\n",
619                     __func__, __LINE__, ret);
620                 return (ret);
621         }
622
623         /* Read the first three bytes to get Identifier, Revision and Status */
624         ret = mlx5_query_eeprom(dev, eeprom->i2c_addr, eeprom->page_num,
625             eeprom->device_addr, MLX5E_EEPROM_INFO_BYTES, eeprom->module_num, &data,
626             &size_read);
627         if (ret) {
628                 if_printf(priv->ifp, "%s:%d: Failed query eeprom module error=0x%x\n",
629                     __func__, __LINE__, ret);
630                 return (ret);
631         }
632
633         switch (data & MLX5_EEPROM_IDENTIFIER_BYTE_MASK) {
634         case SFF_8024_ID_QSFP:
635                 eeprom->type = MLX5E_ETH_MODULE_SFF_8436;
636                 eeprom->len = MLX5E_ETH_MODULE_SFF_8436_LEN;
637                 break;
638         case SFF_8024_ID_QSFPPLUS:
639         case SFF_8024_ID_QSFP28:
640                 if ((data & MLX5_EEPROM_IDENTIFIER_BYTE_MASK) == SFF_8024_ID_QSFP28 ||
641                     ((data & MLX5_EEPROM_REVISION_ID_BYTE_MASK) >> 8) >= 0x3) {
642                         eeprom->type = MLX5E_ETH_MODULE_SFF_8636;
643                         eeprom->len = MLX5E_ETH_MODULE_SFF_8636_LEN;
644                 } else {
645                         eeprom->type = MLX5E_ETH_MODULE_SFF_8436;
646                         eeprom->len = MLX5E_ETH_MODULE_SFF_8436_LEN;
647                 }
648                 if ((data & MLX5_EEPROM_PAGE_3_VALID_BIT_MASK) == 0)
649                         eeprom->page_valid = 1;
650                 break;
651         case SFF_8024_ID_SFP:
652                 eeprom->type = MLX5E_ETH_MODULE_SFF_8472;
653                 eeprom->len = MLX5E_ETH_MODULE_SFF_8472_LEN;
654                 break;
655         default:
656                 if_printf(priv->ifp, "%s:%d: Not recognized cable type = 0x%x(%s)\n",
657                     __func__, __LINE__, data & MLX5_EEPROM_IDENTIFIER_BYTE_MASK,
658                     sff_8024_id[data & MLX5_EEPROM_IDENTIFIER_BYTE_MASK]);
659                 return (EINVAL);
660         }
661         return (0);
662 }
663
664 /* Read both low and high pages of the eeprom */
665 static int
666 mlx5e_get_eeprom(struct mlx5e_priv *priv, struct mlx5e_eeprom *ee)
667 {
668         struct mlx5_core_dev *dev = priv->mdev;
669         int size_read = 0;
670         int ret;
671
672         if (ee->len == 0)
673                 return (EINVAL);
674
675         /* Read low page of the eeprom */
676         while (ee->device_addr < ee->len) {
677                 ret = mlx5_query_eeprom(dev, ee->i2c_addr, ee->page_num, ee->device_addr,
678                     ee->len - ee->device_addr, ee->module_num,
679                     ee->data + (ee->device_addr / 4), &size_read);
680                 if (ret) {
681                         if_printf(priv->ifp, "%s:%d: Failed reading eeprom, "
682                             "error = 0x%02x\n", __func__, __LINE__, ret);
683                         return (ret);
684                 }
685                 ee->device_addr += size_read;
686         }
687
688         /* Read high page of the eeprom */
689         if (ee->page_valid) {
690                 ee->device_addr = MLX5E_EEPROM_HIGH_PAGE_OFFSET;
691                 ee->page_num = MLX5E_EEPROM_HIGH_PAGE;
692                 size_read = 0;
693                 while (ee->device_addr < MLX5E_EEPROM_PAGE_LENGTH) {
694                         ret = mlx5_query_eeprom(dev, ee->i2c_addr, ee->page_num,
695                             ee->device_addr, MLX5E_EEPROM_PAGE_LENGTH - ee->device_addr,
696                             ee->module_num, ee->data + (ee->len / 4) +
697                             ((ee->device_addr - MLX5E_EEPROM_HIGH_PAGE_OFFSET) / 4),
698                             &size_read);
699                         if (ret) {
700                                 if_printf(priv->ifp, "%s:%d: Failed reading eeprom, "
701                                     "error = 0x%02x\n", __func__, __LINE__, ret);
702                                 return (ret);
703                         }
704                         ee->device_addr += size_read;
705                 }
706         }
707         return (0);
708 }
709
710 static void
711 mlx5e_print_eeprom(struct mlx5e_eeprom *eeprom)
712 {
713         int row;
714         int index_in_row;
715         int byte_to_write = 0;
716         int line_length = 16;
717
718         printf("\nOffset\t\tValues\n");
719         printf("------\t\t------");
720         while (byte_to_write < eeprom->len) {
721                 printf("\n0x%04X\t\t", byte_to_write);
722                 for (index_in_row = 0; index_in_row < line_length; index_in_row++) {
723                         printf("%02X ", ((u8 *)eeprom->data)[byte_to_write]);
724                         byte_to_write++;
725                 }
726         }
727
728         if (eeprom->page_valid) {
729                 row = MLX5E_EEPROM_HIGH_PAGE_OFFSET;
730                 printf("\n\nUpper Page 0x03\n");
731                 printf("\nOffset\t\tValues\n");
732                 printf("------\t\t------");
733                 while (row < MLX5E_EEPROM_PAGE_LENGTH) {
734                         printf("\n0x%04X\t\t", row);
735                         for (index_in_row = 0; index_in_row < line_length; index_in_row++) {
736                                 printf("%02X ", ((u8 *)eeprom->data)[byte_to_write]);
737                                 byte_to_write++;
738                                 row++;
739                         }
740                 }
741         }
742 }
743
744 /*
745  * Read cable EEPROM module information by first inspecting the first
746  * three bytes to get the initial information for a whole reading.
747  * Information will be printed to dmesg.
748  */
749 static int
750 mlx5e_read_eeprom(SYSCTL_HANDLER_ARGS)
751 {
752         struct mlx5e_priv *priv = arg1;
753         struct mlx5e_eeprom eeprom;
754         int error;
755         int result = 0;
756
757         PRIV_LOCK(priv);
758         error = sysctl_handle_int(oidp, &result, 0, req);
759         if (error || !req->newptr)
760                 goto done;
761
762         /* Check if device is gone */
763         if (priv->gone) {
764                 error = ENXIO;
765                 goto done;
766         }
767
768         if (result == 1) {
769                 eeprom.i2c_addr = MLX5E_I2C_ADDR_LOW;
770                 eeprom.device_addr = 0;
771                 eeprom.page_num = MLX5E_EEPROM_LOW_PAGE;
772                 eeprom.page_valid = 0;
773
774                 /* Read three first bytes to get important info */
775                 error = mlx5e_get_eeprom_info(priv, &eeprom);
776                 if (error) {
777                         if_printf(priv->ifp, "%s:%d: Failed reading eeprom's "
778                             "initial information\n", __func__, __LINE__);
779                         error = 0;
780                         goto done;
781                 }
782                 /*
783                  * Allocate needed length buffer and additional space for
784                  * page 0x03
785                  */
786                 eeprom.data = malloc(eeprom.len + MLX5E_EEPROM_PAGE_LENGTH,
787                     M_MLX5EN, M_WAITOK | M_ZERO);
788
789                 /* Read the whole eeprom information */
790                 error = mlx5e_get_eeprom(priv, &eeprom);
791                 if (error) {
792                         if_printf(priv->ifp, "%s:%d: Failed reading eeprom\n",
793                             __func__, __LINE__);
794                         error = 0;
795                         /*
796                          * Continue printing partial information in case of
797                          * an error
798                          */
799                 }
800                 mlx5e_print_eeprom(&eeprom);
801                 free(eeprom.data, M_MLX5EN);
802         }
803 done:
804         PRIV_UNLOCK(priv);
805         return (error);
806 }
807
808 static const char *mlx5e_params_desc[] = {
809         MLX5E_PARAMS(MLX5E_STATS_DESC)
810 };
811
812 static const char *mlx5e_port_stats_debug_desc[] = {
813         MLX5E_PORT_STATS_DEBUG(MLX5E_STATS_DESC)
814 };
815
816 static int
817 mlx5e_ethtool_debug_stats(SYSCTL_HANDLER_ARGS)
818 {
819         struct mlx5e_priv *priv = arg1;
820         int error;
821         int sys_debug;
822
823         sys_debug = priv->sysctl_debug;
824         error = sysctl_handle_int(oidp, &priv->sysctl_debug, 0, req);
825         if (error || !req->newptr)
826                 return (error);
827         priv->sysctl_debug = !!priv->sysctl_debug;
828         if (sys_debug == priv->sysctl_debug)
829                 return (error);
830         if (priv->sysctl_debug)
831                 mlx5e_create_stats(&priv->stats.port_stats_debug.ctx,
832                     SYSCTL_CHILDREN(priv->sysctl_ifnet), "debug_stats",
833                     mlx5e_port_stats_debug_desc, MLX5E_PORT_STATS_DEBUG_NUM,
834                     priv->stats.port_stats_debug.arg);
835         else
836                 sysctl_ctx_free(&priv->stats.port_stats_debug.ctx);
837         return (error);
838 }
839
840 static void
841 mlx5e_create_diagnostics(struct mlx5e_priv *priv)
842 {
843         struct mlx5_core_diagnostics_entry entry;
844         struct sysctl_ctx_list *ctx;
845         struct sysctl_oid *node;
846         int x;
847
848         /* sysctl context we are using */
849         ctx = &priv->sysctl_ctx;
850
851         /* create root node */
852         node = SYSCTL_ADD_NODE(ctx,
853             SYSCTL_CHILDREN(priv->sysctl_ifnet), OID_AUTO,
854             "diagnostics", CTLFLAG_RD, NULL, "Diagnostics");
855         if (node == NULL)
856                 return;
857
858         /* create PCI diagnostics */
859         for (x = 0; x != MLX5_CORE_PCI_DIAGNOSTICS_NUM; x++) {
860                 entry = mlx5_core_pci_diagnostics_table[x];
861                 if (mlx5_core_supports_diagnostics(priv->mdev, entry.counter_id) == 0)
862                         continue;
863                 SYSCTL_ADD_UQUAD(ctx, SYSCTL_CHILDREN(node), OID_AUTO,
864                     entry.desc, CTLFLAG_RD, priv->params_pci.array + x,
865                     "PCI diagnostics counter");
866         }
867
868         /* create general diagnostics */
869         for (x = 0; x != MLX5_CORE_GENERAL_DIAGNOSTICS_NUM; x++) {
870                 entry = mlx5_core_general_diagnostics_table[x];
871                 if (mlx5_core_supports_diagnostics(priv->mdev, entry.counter_id) == 0)
872                         continue;
873                 SYSCTL_ADD_UQUAD(ctx, SYSCTL_CHILDREN(node), OID_AUTO,
874                     entry.desc, CTLFLAG_RD, priv->params_general.array + x,
875                     "General diagnostics counter");
876         }
877 }
878
879 void
880 mlx5e_create_ethtool(struct mlx5e_priv *priv)
881 {
882         struct mlx5_core_dev *mdev = priv->mdev;
883         struct sysctl_oid *node, *qos_node;
884         const char *pnameunit;
885         unsigned x;
886         int i;
887
888         /* set some defaults */
889         priv->params_ethtool.tx_queue_size_max = 1 << MLX5E_PARAMS_MAXIMUM_LOG_SQ_SIZE;
890         priv->params_ethtool.rx_queue_size_max = 1 << MLX5E_PARAMS_MAXIMUM_LOG_RQ_SIZE;
891         priv->params_ethtool.tx_queue_size = 1 << priv->params.log_sq_size;
892         priv->params_ethtool.rx_queue_size = 1 << priv->params.log_rq_size;
893         priv->params_ethtool.channels = priv->params.num_channels;
894         priv->params_ethtool.coalesce_pkts_max = MLX5E_FLD_MAX(cqc, cq_max_count);
895         priv->params_ethtool.coalesce_usecs_max = MLX5E_FLD_MAX(cqc, cq_period);
896         priv->params_ethtool.rx_coalesce_mode = priv->params.rx_cq_moderation_mode;
897         priv->params_ethtool.rx_coalesce_usecs = priv->params.rx_cq_moderation_usec;
898         priv->params_ethtool.rx_coalesce_pkts = priv->params.rx_cq_moderation_pkts;
899         priv->params_ethtool.tx_coalesce_mode = priv->params.tx_cq_moderation_mode;
900         priv->params_ethtool.tx_coalesce_usecs = priv->params.tx_cq_moderation_usec;
901         priv->params_ethtool.tx_coalesce_pkts = priv->params.tx_cq_moderation_pkts;
902         priv->params_ethtool.hw_lro = priv->params.hw_lro_en;
903         priv->params_ethtool.cqe_zipping = priv->params.cqe_zipping_en;
904         mlx5e_ethtool_sync_tx_completion_fact(priv);
905
906         /* get default values for local loopback, if any */
907         if (MLX5_CAP_GEN(priv->mdev, disable_local_lb)) {
908                 int err;
909                 u8 val;
910
911                 err = mlx5_nic_vport_query_local_lb(priv->mdev, MLX5_LOCAL_MC_LB, &val);
912                 if (err == 0)
913                         priv->params_ethtool.mc_local_lb = val;
914
915                 err = mlx5_nic_vport_query_local_lb(priv->mdev, MLX5_LOCAL_UC_LB, &val);
916                 if (err == 0)
917                         priv->params_ethtool.uc_local_lb = val;
918         }
919
920         /* create root node */
921         node = SYSCTL_ADD_NODE(&priv->sysctl_ctx,
922             SYSCTL_CHILDREN(priv->sysctl_ifnet), OID_AUTO,
923             "conf", CTLFLAG_RW, NULL, "Configuration");
924         if (node == NULL)
925                 return;
926         for (x = 0; x != MLX5E_PARAMS_NUM; x++) {
927                 /* check for read-only parameter */
928                 if (strstr(mlx5e_params_desc[2 * x], "_max") != NULL ||
929                     strstr(mlx5e_params_desc[2 * x], "_mtu") != NULL) {
930                         SYSCTL_ADD_PROC(&priv->sysctl_ctx, SYSCTL_CHILDREN(node), OID_AUTO,
931                             mlx5e_params_desc[2 * x], CTLTYPE_U64 | CTLFLAG_RD |
932                             CTLFLAG_MPSAFE, priv, x, &mlx5e_ethtool_handler, "QU",
933                             mlx5e_params_desc[2 * x + 1]);
934                 } else {
935 #if (__FreeBSD_version < 1100000)
936                         char path[64];
937 #endif
938                         /*
939                          * NOTE: In FreeBSD-11 and newer the
940                          * CTLFLAG_RWTUN flag will take care of
941                          * loading default sysctl value from the
942                          * kernel environment, if any:
943                          */
944                         SYSCTL_ADD_PROC(&priv->sysctl_ctx, SYSCTL_CHILDREN(node), OID_AUTO,
945                             mlx5e_params_desc[2 * x], CTLTYPE_U64 | CTLFLAG_RWTUN |
946                             CTLFLAG_MPSAFE, priv, x, &mlx5e_ethtool_handler, "QU",
947                             mlx5e_params_desc[2 * x + 1]);
948
949 #if (__FreeBSD_version < 1100000)
950                         /* compute path for sysctl */
951                         snprintf(path, sizeof(path), "dev.mce.%d.conf.%s",
952                             device_get_unit(priv->mdev->pdev->dev.bsddev),
953                             mlx5e_params_desc[2 * x]);
954
955                         /* try to fetch tunable, if any */
956                         if (TUNABLE_QUAD_FETCH(path, &priv->params_ethtool.arg[x]))
957                                 mlx5e_ethtool_handler(NULL, priv, x, NULL);
958 #endif
959                 }
960         }
961
962         SYSCTL_ADD_PROC(&priv->sysctl_ctx, SYSCTL_CHILDREN(node), OID_AUTO,
963             "debug_stats", CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, priv,
964             0, &mlx5e_ethtool_debug_stats, "I", "Extended debug statistics");
965
966         pnameunit = device_get_nameunit(priv->mdev->pdev->dev.bsddev);
967
968         SYSCTL_ADD_STRING(&priv->sysctl_ctx, SYSCTL_CHILDREN(node),
969             OID_AUTO, "device_name", CTLFLAG_RD,
970             __DECONST(void *, pnameunit), 0,
971             "PCI device name");
972
973         /* EEPROM support */
974         SYSCTL_ADD_PROC(&priv->sysctl_ctx, SYSCTL_CHILDREN(node), OID_AUTO, "eeprom_info",
975             CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, priv, 0,
976             mlx5e_read_eeprom, "I", "EEPROM information");
977
978         /* Diagnostics support */
979         mlx5e_create_diagnostics(priv);
980
981         /* create qos node */
982         qos_node = SYSCTL_ADD_NODE(&priv->sysctl_ctx,
983             SYSCTL_CHILDREN(node), OID_AUTO,
984             "qos", CTLFLAG_RW, NULL, "Quality Of Service configuration");
985         if (node == NULL)
986                 return;
987
988         /* Prioriry rate limit support */
989         if (mlx5e_getmaxrate(priv))
990                 return;
991
992         for (i = 0; i <= mlx5_max_tc(mdev); i++) {
993                 char name[32];
994                 snprintf(name, sizeof(name), "tc_%d_max_rate", i);
995                 SYSCTL_ADD_PROC(&priv->sysctl_ctx, SYSCTL_CHILDREN(qos_node),
996                                 OID_AUTO, name, CTLTYPE_U64 | CTLFLAG_RW | CTLFLAG_MPSAFE,
997                                 priv, i, mlx5e_tc_maxrate_handler, "QU",
998                                 "Max rate for priority, specified in kilobits, where kilo=1000, \
999                                 max_rate must be divisible by 100000");
1000         }
1001
1002         if (mlx5e_get_prio_tc(priv))
1003                 return;
1004
1005         for (i = 0; i <= mlx5_max_tc(mdev); i++) {
1006                 char name[32];
1007                 snprintf(name, sizeof(name), "prio_%d_to_tc", i);
1008                 SYSCTL_ADD_PROC(&priv->sysctl_ctx, SYSCTL_CHILDREN(qos_node),
1009                                 OID_AUTO, name, CTLTYPE_U8 | CTLFLAG_RW | CTLFLAG_MPSAFE,
1010                                 priv, i, mlx5e_prio_to_tc_handler, "CU",
1011                                 "Set priority to traffic class");
1012         }
1013 }