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