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