]> CyberLeo.Net >> Repos - FreeBSD/stable/10.git/blob - sys/dev/mlx5/mlx5_en/mlx5_en_ethtool.c
MFC r292838:
[FreeBSD/stable/10.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 int
52 mlx5e_ethtool_handler(SYSCTL_HANDLER_ARGS)
53 {
54         struct mlx5e_priv *priv = arg1;
55         uint64_t value;
56         int was_opened;
57         int error;
58
59         PRIV_LOCK(priv);
60         value = priv->params_ethtool.arg[arg2];
61         if (req != NULL) {
62                 error = sysctl_handle_64(oidp, &value, 0, req);
63                 if (error || req->newptr == NULL ||
64                     value == priv->params_ethtool.arg[arg2])
65                         goto done;
66
67                 /* assign new value */
68                 priv->params_ethtool.arg[arg2] = value;
69         } else {
70                 error = 0;
71         }
72
73         /* check if device is gone */
74         if (priv->gone) {
75                 error = ENXIO;
76                 goto done;
77         }
78
79         if (&priv->params_ethtool.arg[arg2] == &priv->params_ethtool.rx_pauseframe_control ||
80             &priv->params_ethtool.arg[arg2] == &priv->params_ethtool.tx_pauseframe_control) {
81                 /* range check parameters */
82                 priv->params_ethtool.rx_pauseframe_control =
83                     priv->params_ethtool.rx_pauseframe_control ? 1 : 0;
84                 priv->params_ethtool.tx_pauseframe_control =
85                     priv->params_ethtool.tx_pauseframe_control ? 1 : 0;
86
87                 /* update firmware */
88                 error = -mlx5_set_port_pause(priv->mdev, 1,
89                     priv->params_ethtool.rx_pauseframe_control,
90                     priv->params_ethtool.tx_pauseframe_control);
91                 goto done;
92         }
93
94         was_opened = test_bit(MLX5E_STATE_OPENED, &priv->state);
95         if (was_opened)
96                 mlx5e_close_locked(priv->ifp);
97
98         /* import TX queue size */
99         if (priv->params_ethtool.tx_queue_size <
100             (1 << MLX5E_PARAMS_MINIMUM_LOG_SQ_SIZE)) {
101                 priv->params_ethtool.tx_queue_size =
102                     (1 << MLX5E_PARAMS_MINIMUM_LOG_SQ_SIZE);
103         } else if (priv->params_ethtool.tx_queue_size >
104             priv->params_ethtool.tx_queue_size_max) {
105                 priv->params_ethtool.tx_queue_size =
106                     priv->params_ethtool.tx_queue_size_max;
107         }
108         priv->params.log_sq_size =
109             order_base_2(priv->params_ethtool.tx_queue_size);
110
111         /* import RX queue size */
112         if (priv->params_ethtool.rx_queue_size <
113             (1 << MLX5E_PARAMS_MINIMUM_LOG_RQ_SIZE)) {
114                 priv->params_ethtool.rx_queue_size =
115                     (1 << MLX5E_PARAMS_MINIMUM_LOG_RQ_SIZE);
116         } else if (priv->params_ethtool.rx_queue_size >
117             priv->params_ethtool.rx_queue_size_max) {
118                 priv->params_ethtool.rx_queue_size =
119                     priv->params_ethtool.rx_queue_size_max;
120         }
121         priv->params.log_rq_size =
122             order_base_2(priv->params_ethtool.rx_queue_size);
123
124         priv->params.min_rx_wqes = min_t (u16,
125                   priv->params_ethtool.rx_queue_size - 1,
126                   MLX5E_PARAMS_DEFAULT_MIN_RX_WQES);
127
128         /* import number of channels */
129         if (priv->params_ethtool.channels < 1)
130                 priv->params_ethtool.channels = 1;
131         else if (priv->params_ethtool.channels >
132             (u64) priv->mdev->priv.eq_table.num_comp_vectors) {
133                 priv->params_ethtool.channels =
134                     (u64) priv->mdev->priv.eq_table.num_comp_vectors;
135         }
136         priv->params.num_channels = priv->params_ethtool.channels;
137
138         /* import RX mode */
139         if (priv->params_ethtool.rx_coalesce_mode != 0)
140                 priv->params_ethtool.rx_coalesce_mode = 1;
141         priv->params.rx_cq_moderation_mode = priv->params_ethtool.rx_coalesce_mode;
142
143         /* import TX mode */
144         if (priv->params_ethtool.tx_coalesce_mode != 0)
145                 priv->params_ethtool.tx_coalesce_mode = 1;
146         priv->params.tx_cq_moderation_mode = priv->params_ethtool.tx_coalesce_mode;
147
148         /* import RX coal time */
149         if (priv->params_ethtool.rx_coalesce_usecs < 1)
150                 priv->params_ethtool.rx_coalesce_usecs = 0;
151         else if (priv->params_ethtool.rx_coalesce_usecs >
152             MLX5E_FLD_MAX(cqc, cq_period)) {
153                 priv->params_ethtool.rx_coalesce_usecs =
154                     MLX5E_FLD_MAX(cqc, cq_period);
155         }
156         priv->params.rx_cq_moderation_usec = priv->params_ethtool.rx_coalesce_usecs;
157
158         /* import RX coal pkts */
159         if (priv->params_ethtool.rx_coalesce_pkts < 1)
160                 priv->params_ethtool.rx_coalesce_pkts = 0;
161         else if (priv->params_ethtool.rx_coalesce_pkts >
162             MLX5E_FLD_MAX(cqc, cq_max_count)) {
163                 priv->params_ethtool.rx_coalesce_pkts =
164                     MLX5E_FLD_MAX(cqc, cq_max_count);
165         }
166         priv->params.rx_cq_moderation_pkts = priv->params_ethtool.rx_coalesce_pkts;
167
168         /* import TX coal time */
169         if (priv->params_ethtool.tx_coalesce_usecs < 1)
170                 priv->params_ethtool.tx_coalesce_usecs = 0;
171         else if (priv->params_ethtool.tx_coalesce_usecs >
172             MLX5E_FLD_MAX(cqc, cq_period)) {
173                 priv->params_ethtool.tx_coalesce_usecs =
174                     MLX5E_FLD_MAX(cqc, cq_period);
175         }
176         priv->params.tx_cq_moderation_usec = priv->params_ethtool.tx_coalesce_usecs;
177
178         /* import TX coal pkts */
179         if (priv->params_ethtool.tx_coalesce_pkts < 1)
180                 priv->params_ethtool.tx_coalesce_pkts = 0;
181         else if (priv->params_ethtool.tx_coalesce_pkts >
182             MLX5E_FLD_MAX(cqc, cq_max_count)) {
183                 priv->params_ethtool.tx_coalesce_pkts = MLX5E_FLD_MAX(cqc, cq_max_count);
184         }
185         priv->params.tx_cq_moderation_pkts = priv->params_ethtool.tx_coalesce_pkts;
186
187         /* we always agree to turn off HW LRO - but not always to turn on */
188         if (priv->params_ethtool.hw_lro) {
189                 if (priv->params_ethtool.hw_lro != 1) {
190                         priv->params_ethtool.hw_lro = priv->params.hw_lro_en;
191                         error = EINVAL;
192                         goto done;
193                 }
194                 if (priv->ifp->if_capenable & IFCAP_LRO)
195                         priv->params.hw_lro_en = !!MLX5_CAP_ETH(priv->mdev, lro_cap);
196                 else {
197                         /* set the correct (0) value to params_ethtool.hw_lro, issue a warning and return error */
198                         priv->params_ethtool.hw_lro = 0;
199                         error = EINVAL;
200                         if_printf(priv->ifp, "Can't set HW_LRO to a device with LRO turned off");
201                         goto done;
202                 }
203         } else {
204                 priv->params.hw_lro_en = false;
205         }
206
207         if (&priv->params_ethtool.arg[arg2] ==
208             &priv->params_ethtool.cqe_zipping) {
209                 if (priv->params_ethtool.cqe_zipping &&
210                     MLX5_CAP_GEN(priv->mdev, cqe_compression)) {
211                         priv->params.cqe_zipping_en = true;
212                         priv->params_ethtool.cqe_zipping = 1;
213                 } else {
214                         priv->params.cqe_zipping_en = false;
215                         priv->params_ethtool.cqe_zipping = 0;
216                 }
217         }
218
219         if (was_opened)
220                 mlx5e_open_locked(priv->ifp);
221 done:
222         PRIV_UNLOCK(priv);
223         return (error);
224 }
225
226 /*
227  * Read the first three bytes of the eeprom in order to get the needed info
228  * for the whole reading.
229  * Byte 0 - Identifier byte
230  * Byte 1 - Revision byte
231  * Byte 2 - Status byte
232  */
233 static int
234 mlx5e_get_eeprom_info(struct mlx5e_priv *priv, struct mlx5e_eeprom *eeprom)
235 {
236         struct mlx5_core_dev *dev = priv->mdev;
237         u32 data = 0;
238         int size_read = 0;
239         int ret;
240
241         ret = mlx5_query_module_num(dev, &eeprom->module_num);
242         if (ret) {
243                 if_printf(priv->ifp, "%s:%d: Failed query module error=%d\n",
244                     __func__, __LINE__, ret);
245                 return (ret);
246         }
247
248         /* Read the first three bytes to get Identifier, Revision and Status */
249         ret = mlx5_query_eeprom(dev, eeprom->i2c_addr, eeprom->page_num,
250             eeprom->device_addr, MLX5E_EEPROM_INFO_BYTES, eeprom->module_num, &data,
251             &size_read);
252         if (ret) {
253                 if_printf(priv->ifp, "%s:%d: Failed query eeprom module error=0x%x\n",
254                     __func__, __LINE__, ret);
255                 return (ret);
256         }
257
258         switch (data & MLX5_EEPROM_IDENTIFIER_BYTE_MASK) {
259         case SFF_8024_ID_QSFP:
260                 eeprom->type = MLX5E_ETH_MODULE_SFF_8436;
261                 eeprom->len = MLX5E_ETH_MODULE_SFF_8436_LEN;
262                 break;
263         case SFF_8024_ID_QSFPPLUS:
264         case SFF_8024_ID_QSFP28:
265                 if ((data & MLX5_EEPROM_IDENTIFIER_BYTE_MASK) == SFF_8024_ID_QSFP28 ||
266                     ((data & MLX5_EEPROM_REVISION_ID_BYTE_MASK) >> 8) >= 0x3) {
267                         eeprom->type = MLX5E_ETH_MODULE_SFF_8636;
268                         eeprom->len = MLX5E_ETH_MODULE_SFF_8636_LEN;
269                 } else {
270                         eeprom->type = MLX5E_ETH_MODULE_SFF_8436;
271                         eeprom->len = MLX5E_ETH_MODULE_SFF_8436_LEN;
272                 }
273                 if ((data & MLX5_EEPROM_PAGE_3_VALID_BIT_MASK) == 0)
274                         eeprom->page_valid = 1;
275                 break;
276         case SFF_8024_ID_SFP:
277                 eeprom->type = MLX5E_ETH_MODULE_SFF_8472;
278                 eeprom->len = MLX5E_ETH_MODULE_SFF_8472_LEN;
279                 break;
280         default:
281                 if_printf(priv->ifp, "%s:%d: Not recognized cable type = 0x%x(%s)\n",
282                     __func__, __LINE__, data & MLX5_EEPROM_IDENTIFIER_BYTE_MASK,
283                     sff_8024_id[data & MLX5_EEPROM_IDENTIFIER_BYTE_MASK]);
284                 return (EINVAL);
285         }
286         return (0);
287 }
288
289 /* Read both low and high pages of the eeprom */
290 static int
291 mlx5e_get_eeprom(struct mlx5e_priv *priv, struct mlx5e_eeprom *ee)
292 {
293         struct mlx5_core_dev *dev = priv->mdev;
294         int size_read = 0;
295         int ret;
296
297         if (ee->len == 0)
298                 return (EINVAL);
299
300         /* Read low page of the eeprom */
301         while (ee->device_addr < ee->len) {
302                 ret = mlx5_query_eeprom(dev, ee->i2c_addr, ee->page_num, ee->device_addr,
303                     ee->len - ee->device_addr, ee->module_num,
304                     ee->data + (ee->device_addr / 4), &size_read);
305                 if (ret) {
306                         if_printf(priv->ifp, "%s:%d: Failed reading eeprom, "
307                             "error = 0x%02x\n", __func__, __LINE__, ret);
308                         return (ret);
309                 }
310                 ee->device_addr += size_read;
311         }
312
313         /* Read high page of the eeprom */
314         if (ee->page_valid) {
315                 ee->device_addr = MLX5E_EEPROM_HIGH_PAGE_OFFSET;
316                 ee->page_num = MLX5E_EEPROM_HIGH_PAGE;
317                 size_read = 0;
318                 while (ee->device_addr < MLX5E_EEPROM_PAGE_LENGTH) {
319                         ret = mlx5_query_eeprom(dev, ee->i2c_addr, ee->page_num,
320                             ee->device_addr, MLX5E_EEPROM_PAGE_LENGTH - ee->device_addr,
321                             ee->module_num, ee->data + (ee->len / 4) +
322                             ((ee->device_addr - MLX5E_EEPROM_HIGH_PAGE_OFFSET) / 4),
323                             &size_read);
324                         if (ret) {
325                                 if_printf(priv->ifp, "%s:%d: Failed reading eeprom, "
326                                     "error = 0x%02x\n", __func__, __LINE__, ret);
327                                 return (ret);
328                         }
329                         ee->device_addr += size_read;
330                 }
331         }
332         return (0);
333 }
334
335 static void
336 mlx5e_print_eeprom(struct mlx5e_eeprom *eeprom)
337 {
338         int row;
339         int index_in_row;
340         int byte_to_write = 0;
341         int line_length = 16;
342
343         printf("\nOffset\t\tValues\n");
344         printf("------\t\t------");
345         while (byte_to_write < eeprom->len) {
346                 printf("\n0x%04X\t\t", byte_to_write);
347                 for (index_in_row = 0; index_in_row < line_length; index_in_row++) {
348                         printf("%02X ", ((u8 *)eeprom->data)[byte_to_write]);
349                         byte_to_write++;
350                 }
351         }
352
353         if (eeprom->page_valid) {
354                 row = MLX5E_EEPROM_HIGH_PAGE_OFFSET;
355                 printf("\n\nUpper Page 0x03\n");
356                 printf("\nOffset\t\tValues\n");
357                 printf("------\t\t------");
358                 while (row < MLX5E_EEPROM_PAGE_LENGTH) {
359                         printf("\n0x%04X\t\t", row);
360                         for (index_in_row = 0; index_in_row < line_length; index_in_row++) {
361                                 printf("%02X ", ((u8 *)eeprom->data)[byte_to_write]);
362                                 byte_to_write++;
363                                 row++;
364                         }
365                 }
366         }
367 }
368
369 /*
370  * Read cable EEPROM module information by first inspecting the first
371  * three bytes to get the initial information for a whole reading.
372  * Information will be printed to dmesg.
373  */
374 static int
375 mlx5e_read_eeprom(SYSCTL_HANDLER_ARGS)
376 {
377         struct mlx5e_priv *priv = arg1;
378         struct mlx5e_eeprom eeprom;
379         int error;
380         int result = 0;
381
382         PRIV_LOCK(priv);
383         error = sysctl_handle_int(oidp, &result, 0, req);
384         if (error || !req->newptr)
385                 goto done;
386
387         /* Check if device is gone */
388         if (priv->gone) {
389                 error = ENXIO;
390                 goto done;
391         }
392
393         if (result == 1) {
394                 eeprom.i2c_addr = MLX5E_I2C_ADDR_LOW;
395                 eeprom.device_addr = 0;
396                 eeprom.page_num = MLX5E_EEPROM_LOW_PAGE;
397                 eeprom.page_valid = 0;
398
399                 /* Read three first bytes to get important info */
400                 error = mlx5e_get_eeprom_info(priv, &eeprom);
401                 if (error) {
402                         if_printf(priv->ifp, "%s:%d: Failed reading eeprom's "
403                             "initial information\n", __func__, __LINE__);
404                         error = 0;
405                         goto done;
406                 }
407                 /*
408                  * Allocate needed length buffer and additional space for
409                  * page 0x03
410                  */
411                 eeprom.data = malloc(eeprom.len + MLX5E_EEPROM_PAGE_LENGTH,
412                     M_MLX5EN, M_WAITOK | M_ZERO);
413
414                 /* Read the whole eeprom information */
415                 error = mlx5e_get_eeprom(priv, &eeprom);
416                 if (error) {
417                         if_printf(priv->ifp, "%s:%d: Failed reading eeprom\n",
418                             __func__, __LINE__);
419                         error = 0;
420                         /*
421                          * Continue printing partial information in case of
422                          * an error
423                          */
424                 }
425                 mlx5e_print_eeprom(&eeprom);
426                 free(eeprom.data, M_MLX5EN);
427         }
428 done:
429         PRIV_UNLOCK(priv);
430         return (error);
431 }
432
433 static const char *mlx5e_params_desc[] = {
434         MLX5E_PARAMS(MLX5E_STATS_DESC)
435 };
436
437 static const char *mlx5e_port_stats_debug_desc[] = {
438         MLX5E_PORT_STATS_DEBUG(MLX5E_STATS_DESC)
439 };
440
441 static int
442 mlx5e_ethtool_debug_stats(SYSCTL_HANDLER_ARGS)
443 {
444         struct mlx5e_priv *priv = arg1;
445         int error;
446         int sys_debug;
447
448         sys_debug = priv->sysctl_debug;
449         error = sysctl_handle_int(oidp, &priv->sysctl_debug, 0, req);
450         if (error || !req->newptr)
451                 return (error);
452         priv->sysctl_debug = !!priv->sysctl_debug;
453         if (sys_debug == priv->sysctl_debug)
454                 return (error);
455         if (priv->sysctl_debug)
456                 mlx5e_create_stats(&priv->stats.port_stats_debug.ctx,
457                     SYSCTL_CHILDREN(priv->sysctl_ifnet), "debug_stats",
458                     mlx5e_port_stats_debug_desc, MLX5E_PORT_STATS_DEBUG_NUM,
459                     priv->stats.port_stats_debug.arg);
460         else
461                 sysctl_ctx_free(&priv->stats.port_stats_debug.ctx);
462         return (error);
463 }
464
465 void
466 mlx5e_create_ethtool(struct mlx5e_priv *priv)
467 {
468         struct sysctl_oid *node;
469         const char *pnameunit;
470         unsigned x;
471
472         /* set some defaults */
473         priv->params_ethtool.tx_queue_size_max = 1 << MLX5E_PARAMS_MAXIMUM_LOG_SQ_SIZE;
474         priv->params_ethtool.rx_queue_size_max = 1 << MLX5E_PARAMS_MAXIMUM_LOG_RQ_SIZE;
475         priv->params_ethtool.tx_queue_size = 1 << priv->params.log_sq_size;
476         priv->params_ethtool.rx_queue_size = 1 << priv->params.log_rq_size;
477         priv->params_ethtool.channels = priv->params.num_channels;
478         priv->params_ethtool.coalesce_pkts_max = MLX5E_FLD_MAX(cqc, cq_max_count);
479         priv->params_ethtool.coalesce_usecs_max = MLX5E_FLD_MAX(cqc, cq_period);
480         priv->params_ethtool.rx_coalesce_mode = priv->params.rx_cq_moderation_mode;
481         priv->params_ethtool.rx_coalesce_usecs = priv->params.rx_cq_moderation_usec;
482         priv->params_ethtool.rx_coalesce_pkts = priv->params.rx_cq_moderation_pkts;
483         priv->params_ethtool.tx_coalesce_mode = priv->params.tx_cq_moderation_mode;
484         priv->params_ethtool.tx_coalesce_usecs = priv->params.tx_cq_moderation_usec;
485         priv->params_ethtool.tx_coalesce_pkts = priv->params.tx_cq_moderation_pkts;
486         priv->params_ethtool.hw_lro = priv->params.hw_lro_en;
487         priv->params_ethtool.cqe_zipping = priv->params.cqe_zipping_en;
488
489         /* create root node */
490         node = SYSCTL_ADD_NODE(&priv->sysctl_ctx,
491             SYSCTL_CHILDREN(priv->sysctl_ifnet), OID_AUTO,
492             "conf", CTLFLAG_RW, NULL, "Configuration");
493         if (node == NULL)
494                 return;
495         for (x = 0; x != MLX5E_PARAMS_NUM; x++) {
496                 /* check for read-only parameter */
497                 if (strstr(mlx5e_params_desc[2 * x], "_max") != NULL) {
498                         SYSCTL_ADD_PROC(&priv->sysctl_ctx, SYSCTL_CHILDREN(node), OID_AUTO,
499                             mlx5e_params_desc[2 * x], CTLTYPE_U64 | CTLFLAG_RD |
500                             CTLFLAG_MPSAFE, priv, x, &mlx5e_ethtool_handler, "QU",
501                             mlx5e_params_desc[2 * x + 1]);
502                 } else {
503 #if (__FreeBSD_version < 1100000)
504                         char path[64];
505 #endif
506                         /*
507                          * NOTE: In FreeBSD-11 and newer the
508                          * CTLFLAG_RWTUN flag will take care of
509                          * loading default sysctl value from the
510                          * kernel environment, if any:
511                          */
512                         SYSCTL_ADD_PROC(&priv->sysctl_ctx, SYSCTL_CHILDREN(node), OID_AUTO,
513                             mlx5e_params_desc[2 * x], CTLTYPE_U64 | CTLFLAG_RWTUN |
514                             CTLFLAG_MPSAFE, priv, x, &mlx5e_ethtool_handler, "QU",
515                             mlx5e_params_desc[2 * x + 1]);
516
517 #if (__FreeBSD_version < 1100000)
518                         /* compute path for sysctl */
519                         snprintf(path, sizeof(path), "dev.mce.%d.conf.%s",
520                             device_get_unit(priv->mdev->pdev->dev.bsddev),
521                             mlx5e_params_desc[2 * x]);
522
523                         /* try to fetch tunable, if any */
524                         if (TUNABLE_QUAD_FETCH(path, &priv->params_ethtool.arg[x]))
525                                 mlx5e_ethtool_handler(NULL, priv, x, NULL);
526 #endif
527                 }
528         }
529
530         SYSCTL_ADD_PROC(&priv->sysctl_ctx, SYSCTL_CHILDREN(node), OID_AUTO,
531             "debug_stats", CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, priv,
532             0, &mlx5e_ethtool_debug_stats, "I", "Extended debug statistics");
533
534         pnameunit = device_get_nameunit(priv->mdev->pdev->dev.bsddev);
535
536         SYSCTL_ADD_STRING(&priv->sysctl_ctx, SYSCTL_CHILDREN(node),
537             OID_AUTO, "device_name", CTLFLAG_RD,
538             __DECONST(void *, pnameunit), 0,
539             "PCI device name");
540
541         /* EEPROM support */
542         SYSCTL_ADD_PROC(&priv->sysctl_ctx, SYSCTL_CHILDREN(node), OID_AUTO, "eeprom_info",
543             CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, priv, 0,
544             mlx5e_read_eeprom, "I", "EEPROM information");
545 }