2 * Copyright (c) 2015 Mellanox Technologies. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
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.
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
29 #include <net/sff8472.h>
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)
36 struct sysctl_oid *node;
41 node = SYSCTL_ADD_NODE(ctx, parent, OID_AUTO,
42 buffer, CTLFLAG_RD, NULL, "Statistics");
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]);
52 mlx5e_ethtool_handler(SYSCTL_HANDLER_ARGS)
54 struct mlx5e_priv *priv = arg1;
60 value = priv->params_ethtool.arg[arg2];
62 error = sysctl_handle_64(oidp, &value, 0, req);
63 if (error || req->newptr == NULL ||
64 value == priv->params_ethtool.arg[arg2])
67 /* assign new value */
68 priv->params_ethtool.arg[arg2] = value;
73 /* check if device is gone */
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;
88 error = -mlx5_set_port_pause(priv->mdev, 1,
89 priv->params_ethtool.rx_pauseframe_control,
90 priv->params_ethtool.tx_pauseframe_control);
94 was_opened = test_bit(MLX5E_STATE_OPENED, &priv->state);
96 mlx5e_close_locked(priv->ifp);
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;
108 priv->params.log_sq_size =
109 order_base_2(priv->params_ethtool.tx_queue_size);
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;
121 priv->params.log_rq_size =
122 order_base_2(priv->params_ethtool.rx_queue_size);
124 priv->params.min_rx_wqes = min_t (u16,
125 priv->params_ethtool.rx_queue_size - 1,
126 MLX5E_PARAMS_DEFAULT_MIN_RX_WQES);
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;
136 priv->params.num_channels = priv->params_ethtool.channels;
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;
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;
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);
156 priv->params.rx_cq_moderation_usec = priv->params_ethtool.rx_coalesce_usecs;
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);
166 priv->params.rx_cq_moderation_pkts = priv->params_ethtool.rx_coalesce_pkts;
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);
176 priv->params.tx_cq_moderation_usec = priv->params_ethtool.tx_coalesce_usecs;
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);
185 priv->params.tx_cq_moderation_pkts = priv->params_ethtool.tx_coalesce_pkts;
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;
194 if (priv->ifp->if_capenable & IFCAP_LRO)
195 priv->params.hw_lro_en = !!MLX5_CAP_ETH(priv->mdev, lro_cap);
197 /* set the correct (0) value to params_ethtool.hw_lro, issue a warning and return error */
198 priv->params_ethtool.hw_lro = 0;
200 if_printf(priv->ifp, "Can't set HW_LRO to a device with LRO turned off");
204 priv->params.hw_lro_en = false;
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;
214 priv->params.cqe_zipping_en = false;
215 priv->params_ethtool.cqe_zipping = 0;
220 mlx5e_open_locked(priv->ifp);
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
234 mlx5e_get_eeprom_info(struct mlx5e_priv *priv, struct mlx5e_eeprom *eeprom)
236 struct mlx5_core_dev *dev = priv->mdev;
241 ret = mlx5_query_module_num(dev, &eeprom->module_num);
243 if_printf(priv->ifp, "%s:%d: Failed query module error=%d\n",
244 __func__, __LINE__, ret);
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,
253 if_printf(priv->ifp, "%s:%d: Failed query eeprom module error=0x%x\n",
254 __func__, __LINE__, ret);
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;
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;
270 eeprom->type = MLX5E_ETH_MODULE_SFF_8436;
271 eeprom->len = MLX5E_ETH_MODULE_SFF_8436_LEN;
273 if ((data & MLX5_EEPROM_PAGE_3_VALID_BIT_MASK) == 0)
274 eeprom->page_valid = 1;
276 case SFF_8024_ID_SFP:
277 eeprom->type = MLX5E_ETH_MODULE_SFF_8472;
278 eeprom->len = MLX5E_ETH_MODULE_SFF_8472_LEN;
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]);
289 /* Read both low and high pages of the eeprom */
291 mlx5e_get_eeprom(struct mlx5e_priv *priv, struct mlx5e_eeprom *ee)
293 struct mlx5_core_dev *dev = priv->mdev;
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);
306 if_printf(priv->ifp, "%s:%d: Failed reading eeprom, "
307 "error = 0x%02x\n", __func__, __LINE__, ret);
310 ee->device_addr += size_read;
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;
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),
325 if_printf(priv->ifp, "%s:%d: Failed reading eeprom, "
326 "error = 0x%02x\n", __func__, __LINE__, ret);
329 ee->device_addr += size_read;
336 mlx5e_print_eeprom(struct mlx5e_eeprom *eeprom)
340 int byte_to_write = 0;
341 int line_length = 16;
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]);
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]);
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.
375 mlx5e_read_eeprom(SYSCTL_HANDLER_ARGS)
377 struct mlx5e_priv *priv = arg1;
378 struct mlx5e_eeprom eeprom;
383 error = sysctl_handle_int(oidp, &result, 0, req);
384 if (error || !req->newptr)
387 /* Check if device is gone */
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;
399 /* Read three first bytes to get important info */
400 error = mlx5e_get_eeprom_info(priv, &eeprom);
402 if_printf(priv->ifp, "%s:%d: Failed reading eeprom's "
403 "initial information\n", __func__, __LINE__);
408 * Allocate needed length buffer and additional space for
411 eeprom.data = malloc(eeprom.len + MLX5E_EEPROM_PAGE_LENGTH,
412 M_MLX5EN, M_WAITOK | M_ZERO);
414 /* Read the whole eeprom information */
415 error = mlx5e_get_eeprom(priv, &eeprom);
417 if_printf(priv->ifp, "%s:%d: Failed reading eeprom\n",
421 * Continue printing partial information in case of
425 mlx5e_print_eeprom(&eeprom);
426 free(eeprom.data, M_MLX5EN);
433 static const char *mlx5e_params_desc[] = {
434 MLX5E_PARAMS(MLX5E_STATS_DESC)
437 static const char *mlx5e_port_stats_debug_desc[] = {
438 MLX5E_PORT_STATS_DEBUG(MLX5E_STATS_DESC)
442 mlx5e_ethtool_debug_stats(SYSCTL_HANDLER_ARGS)
444 struct mlx5e_priv *priv = arg1;
448 sys_debug = priv->sysctl_debug;
449 error = sysctl_handle_int(oidp, &priv->sysctl_debug, 0, req);
450 if (error || !req->newptr)
452 priv->sysctl_debug = !!priv->sysctl_debug;
453 if (sys_debug == priv->sysctl_debug)
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);
461 sysctl_ctx_free(&priv->stats.port_stats_debug.ctx);
466 mlx5e_create_ethtool(struct mlx5e_priv *priv)
468 struct sysctl_oid *node;
469 const char *pnameunit;
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;
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");
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]);
503 #if (__FreeBSD_version < 1100000)
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:
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]);
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]);
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);
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");
534 pnameunit = device_get_nameunit(priv->mdev->pdev->dev.bsddev);
536 SYSCTL_ADD_STRING(&priv->sysctl_ctx, SYSCTL_CHILDREN(node),
537 OID_AUTO, "device_name", CTLFLAG_RD,
538 __DECONST(void *, pnameunit), 0,
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");