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