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