1 /*- 2 * Copyright (c) 2015-2019 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 "port_buffer.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 void 52 mlx5e_create_counter_stats(struct sysctl_ctx_list *ctx, 53 struct sysctl_oid_list *parent, const char *buffer, 54 const char **desc, unsigned num, counter_u64_t *arg) 55 { 56 struct sysctl_oid *node; 57 unsigned x; 58 59 sysctl_ctx_init(ctx); 60 61 node = SYSCTL_ADD_NODE(ctx, parent, OID_AUTO, 62 buffer, CTLFLAG_RD, NULL, "Statistics"); 63 if (node == NULL) 64 return; 65 for (x = 0; x != num; x++) { 66 SYSCTL_ADD_COUNTER_U64(ctx, SYSCTL_CHILDREN(node), OID_AUTO, 67 desc[2 * x], CTLFLAG_RD, arg + x, desc[2 * x + 1]); 68 } 69 } 70 71 static void 72 mlx5e_ethtool_sync_tx_completion_fact(struct mlx5e_priv *priv) 73 { 74 /* 75 * Limit the maximum distance between completion events to 76 * half of the currently set TX queue size. 77 * 78 * The maximum number of queue entries a single IP packet can 79 * consume is given by MLX5_SEND_WQE_MAX_WQEBBS. 80 * 81 * The worst case max value is then given as below: 82 */ 83 uint64_t max = priv->params_ethtool.tx_queue_size / 84 (2 * MLX5_SEND_WQE_MAX_WQEBBS); 85 86 /* 87 * Update the maximum completion factor value in case the 88 * tx_queue_size field changed. Ensure we don't overflow 89 * 16-bits. 90 */ 91 if (max < 1) 92 max = 1; 93 else if (max > 65535) 94 max = 65535; 95 priv->params_ethtool.tx_completion_fact_max = max; 96 97 /* 98 * Verify that the current TX completion factor is within the 99 * given limits: 100 */ 101 if (priv->params_ethtool.tx_completion_fact < 1) 102 priv->params_ethtool.tx_completion_fact = 1; 103 else if (priv->params_ethtool.tx_completion_fact > max) 104 priv->params_ethtool.tx_completion_fact = max; 105 } 106 107 static int 108 mlx5e_getmaxrate(struct mlx5e_priv *priv) 109 { 110 struct mlx5_core_dev *mdev = priv->mdev; 111 u8 max_bw_unit[IEEE_8021QAZ_MAX_TCS]; 112 u8 max_bw_value[IEEE_8021QAZ_MAX_TCS]; 113 int err; 114 int i; 115 116 PRIV_LOCK(priv); 117 err = -mlx5_query_port_tc_rate_limit(mdev, max_bw_value, max_bw_unit); 118 if (err) 119 goto done; 120 121 for (i = 0; i <= mlx5_max_tc(mdev); i++) { 122 switch (max_bw_unit[i]) { 123 case MLX5_100_MBPS_UNIT: 124 priv->params_ethtool.max_bw_value[i] = max_bw_value[i] * MLX5E_100MB; 125 break; 126 case MLX5_GBPS_UNIT: 127 priv->params_ethtool.max_bw_value[i] = max_bw_value[i] * MLX5E_1GB; 128 break; 129 case MLX5_BW_NO_LIMIT: 130 priv->params_ethtool.max_bw_value[i] = 0; 131 break; 132 default: 133 priv->params_ethtool.max_bw_value[i] = -1; 134 WARN_ONCE(true, "non-supported BW unit"); 135 break; 136 } 137 } 138 done: 139 PRIV_UNLOCK(priv); 140 return (err); 141 } 142 143 static int 144 mlx5e_get_max_alloc(struct mlx5e_priv *priv) 145 { 146 struct mlx5_core_dev *mdev = priv->mdev; 147 int err; 148 int x; 149 150 PRIV_LOCK(priv); 151 err = -mlx5_query_port_tc_bw_alloc(mdev, priv->params_ethtool.max_bw_share); 152 if (err == 0) { 153 /* set default value */ 154 for (x = 0; x != IEEE_8021QAZ_MAX_TCS; x++) { 155 priv->params_ethtool.max_bw_share[x] = 156 100 / IEEE_8021QAZ_MAX_TCS; 157 } 158 err = -mlx5_set_port_tc_bw_alloc(mdev, 159 priv->params_ethtool.max_bw_share); 160 } 161 PRIV_UNLOCK(priv); 162 163 return (err); 164 } 165 166 static int 167 mlx5e_get_dscp(struct mlx5e_priv *priv) 168 { 169 struct mlx5_core_dev *mdev = priv->mdev; 170 int err; 171 172 if (MLX5_CAP_GEN(mdev, qcam_reg) == 0 || 173 MLX5_CAP_QCAM_REG(mdev, qpts) == 0 || 174 MLX5_CAP_QCAM_REG(mdev, qpdpm) == 0) 175 return (EOPNOTSUPP); 176 177 PRIV_LOCK(priv); 178 err = -mlx5_query_dscp2prio(mdev, priv->params_ethtool.dscp2prio); 179 if (err) 180 goto done; 181 182 err = -mlx5_query_trust_state(mdev, &priv->params_ethtool.trust_state); 183 if (err) 184 goto done; 185 done: 186 PRIV_UNLOCK(priv); 187 return (err); 188 } 189 190 static void 191 mlx5e_tc_get_parameters(struct mlx5e_priv *priv, 192 u64 *new_bw_value, u8 *max_bw_value, u8 *max_bw_unit) 193 { 194 const u64 upper_limit_mbps = 255 * MLX5E_100MB; 195 const u64 upper_limit_gbps = 255 * MLX5E_1GB; 196 u64 temp; 197 int i; 198 199 memset(max_bw_value, 0, IEEE_8021QAZ_MAX_TCS); 200 memset(max_bw_unit, 0, IEEE_8021QAZ_MAX_TCS); 201 202 for (i = 0; i <= mlx5_max_tc(priv->mdev); i++) { 203 temp = (new_bw_value != NULL) ? 204 new_bw_value[i] : priv->params_ethtool.max_bw_value[i]; 205 206 if (!temp) { 207 max_bw_unit[i] = MLX5_BW_NO_LIMIT; 208 } else if (temp > upper_limit_gbps) { 209 max_bw_unit[i] = MLX5_BW_NO_LIMIT; 210 } else if (temp <= upper_limit_mbps) { 211 max_bw_value[i] = howmany(temp, MLX5E_100MB); 212 max_bw_unit[i] = MLX5_100_MBPS_UNIT; 213 } else { 214 max_bw_value[i] = howmany(temp, MLX5E_1GB); 215 max_bw_unit[i] = MLX5_GBPS_UNIT; 216 } 217 } 218 } 219 220 static int 221 mlx5e_tc_maxrate_handler(SYSCTL_HANDLER_ARGS) 222 { 223 struct mlx5e_priv *priv = arg1; 224 struct mlx5_core_dev *mdev = priv->mdev; 225 u8 max_bw_unit[IEEE_8021QAZ_MAX_TCS]; 226 u8 max_bw_value[IEEE_8021QAZ_MAX_TCS]; 227 u64 new_bw_value[IEEE_8021QAZ_MAX_TCS]; 228 u8 max_rates = mlx5_max_tc(mdev) + 1; 229 u8 x; 230 int err; 231 232 PRIV_LOCK(priv); 233 err = SYSCTL_OUT(req, priv->params_ethtool.max_bw_value, 234 sizeof(priv->params_ethtool.max_bw_value[0]) * max_rates); 235 if (err || !req->newptr) 236 goto done; 237 err = SYSCTL_IN(req, new_bw_value, 238 sizeof(new_bw_value[0]) * max_rates); 239 if (err) 240 goto done; 241 242 /* range check input value */ 243 for (x = 0; x != max_rates; x++) { 244 if (new_bw_value[x] % MLX5E_100MB) { 245 err = ERANGE; 246 goto done; 247 } 248 } 249 250 mlx5e_tc_get_parameters(priv, new_bw_value, max_bw_value, max_bw_unit); 251 252 err = -mlx5_modify_port_tc_rate_limit(mdev, max_bw_value, max_bw_unit); 253 if (err) 254 goto done; 255 256 memcpy(priv->params_ethtool.max_bw_value, new_bw_value, 257 sizeof(priv->params_ethtool.max_bw_value)); 258 done: 259 PRIV_UNLOCK(priv); 260 return (err); 261 } 262 263 static int 264 mlx5e_tc_rate_share_handler(SYSCTL_HANDLER_ARGS) 265 { 266 struct mlx5e_priv *priv = arg1; 267 struct mlx5_core_dev *mdev = priv->mdev; 268 u8 max_bw_share[IEEE_8021QAZ_MAX_TCS]; 269 u8 max_rates = mlx5_max_tc(mdev) + 1; 270 int i; 271 int err; 272 int sum; 273 274 PRIV_LOCK(priv); 275 err = SYSCTL_OUT(req, priv->params_ethtool.max_bw_share, max_rates); 276 if (err || !req->newptr) 277 goto done; 278 err = SYSCTL_IN(req, max_bw_share, max_rates); 279 if (err) 280 goto done; 281 282 /* range check input value */ 283 for (sum = i = 0; i != max_rates; i++) { 284 if (max_bw_share[i] < 1 || max_bw_share[i] > 100) { 285 err = ERANGE; 286 goto done; 287 } 288 sum += max_bw_share[i]; 289 } 290 291 /* sum of values should be as close to 100 as possible */ 292 if (sum < (100 - max_rates + 1) || sum > 100) { 293 err = ERANGE; 294 goto done; 295 } 296 297 err = -mlx5_set_port_tc_bw_alloc(mdev, max_bw_share); 298 if (err) 299 goto done; 300 301 memcpy(priv->params_ethtool.max_bw_share, max_bw_share, 302 sizeof(priv->params_ethtool.max_bw_share)); 303 done: 304 PRIV_UNLOCK(priv); 305 return (err); 306 } 307 308 static int 309 mlx5e_get_prio_tc(struct mlx5e_priv *priv) 310 { 311 struct mlx5_core_dev *mdev = priv->mdev; 312 int err = 0; 313 int i; 314 315 PRIV_LOCK(priv); 316 if (!MLX5_CAP_GEN(priv->mdev, ets)) { 317 PRIV_UNLOCK(priv); 318 return (EOPNOTSUPP); 319 } 320 321 for (i = 0; i != MLX5E_MAX_PRIORITY; i++) { 322 err = -mlx5_query_port_prio_tc(mdev, i, priv->params_ethtool.prio_tc + i); 323 if (err) 324 break; 325 } 326 PRIV_UNLOCK(priv); 327 return (err); 328 } 329 330 static int 331 mlx5e_prio_to_tc_handler(SYSCTL_HANDLER_ARGS) 332 { 333 struct mlx5e_priv *priv = arg1; 334 struct mlx5_core_dev *mdev = priv->mdev; 335 uint8_t temp[MLX5E_MAX_PRIORITY]; 336 int err; 337 int i; 338 339 PRIV_LOCK(priv); 340 err = SYSCTL_OUT(req, priv->params_ethtool.prio_tc, MLX5E_MAX_PRIORITY); 341 if (err || !req->newptr) 342 goto done; 343 err = SYSCTL_IN(req, temp, MLX5E_MAX_PRIORITY); 344 if (err) 345 goto done; 346 347 for (i = 0; i != MLX5E_MAX_PRIORITY; i++) { 348 if (temp[i] > mlx5_max_tc(mdev)) { 349 err = ERANGE; 350 goto done; 351 } 352 } 353 354 for (i = 0; i != MLX5E_MAX_PRIORITY; i++) { 355 if (temp[i] == priv->params_ethtool.prio_tc[i]) 356 continue; 357 err = -mlx5_set_port_prio_tc(mdev, i, temp[i]); 358 if (err) 359 goto done; 360 /* update cached value */ 361 priv->params_ethtool.prio_tc[i] = temp[i]; 362 } 363 done: 364 PRIV_UNLOCK(priv); 365 return (err); 366 } 367 368 int 369 mlx5e_fec_update(struct mlx5e_priv *priv) 370 { 371 struct mlx5_core_dev *mdev = priv->mdev; 372 u32 in[MLX5_ST_SZ_DW(pplm_reg)] = {}; 373 const int sz = MLX5_ST_SZ_BYTES(pplm_reg); 374 int err; 375 376 if (!MLX5_CAP_GEN(mdev, pcam_reg)) 377 return (EOPNOTSUPP); 378 379 if (!MLX5_CAP_PCAM_REG(mdev, pplm)) 380 return (EOPNOTSUPP); 381 382 MLX5_SET(pplm_reg, in, local_port, 1); 383 384 err = -mlx5_core_access_reg(mdev, in, sz, in, sz, MLX5_REG_PPLM, 0, 0); 385 if (err) 386 return (err); 387 388 /* get 10x..25x mask */ 389 priv->params_ethtool.fec_mask_10x_25x[0] = 390 MLX5_GET(pplm_reg, in, fec_override_admin_10g_40g); 391 priv->params_ethtool.fec_mask_10x_25x[1] = 392 MLX5_GET(pplm_reg, in, fec_override_admin_25g) & 393 MLX5_GET(pplm_reg, in, fec_override_admin_50g); 394 priv->params_ethtool.fec_mask_10x_25x[2] = 395 MLX5_GET(pplm_reg, in, fec_override_admin_56g); 396 priv->params_ethtool.fec_mask_10x_25x[3] = 397 MLX5_GET(pplm_reg, in, fec_override_admin_100g); 398 399 /* get 10x..25x available bits */ 400 priv->params_ethtool.fec_avail_10x_25x[0] = 401 MLX5_GET(pplm_reg, in, fec_override_cap_10g_40g); 402 priv->params_ethtool.fec_avail_10x_25x[1] = 403 MLX5_GET(pplm_reg, in, fec_override_cap_25g) & 404 MLX5_GET(pplm_reg, in, fec_override_cap_50g); 405 priv->params_ethtool.fec_avail_10x_25x[2] = 406 MLX5_GET(pplm_reg, in, fec_override_cap_56g); 407 priv->params_ethtool.fec_avail_10x_25x[3] = 408 MLX5_GET(pplm_reg, in, fec_override_cap_100g); 409 410 /* get 50x mask */ 411 priv->params_ethtool.fec_mask_50x[0] = 412 MLX5_GET(pplm_reg, in, fec_override_admin_50g_1x); 413 priv->params_ethtool.fec_mask_50x[1] = 414 MLX5_GET(pplm_reg, in, fec_override_admin_100g_2x); 415 priv->params_ethtool.fec_mask_50x[2] = 416 MLX5_GET(pplm_reg, in, fec_override_admin_200g_4x); 417 priv->params_ethtool.fec_mask_50x[3] = 418 MLX5_GET(pplm_reg, in, fec_override_admin_400g_8x); 419 420 /* get 50x available bits */ 421 priv->params_ethtool.fec_avail_50x[0] = 422 MLX5_GET(pplm_reg, in, fec_override_cap_50g_1x); 423 priv->params_ethtool.fec_avail_50x[1] = 424 MLX5_GET(pplm_reg, in, fec_override_cap_100g_2x); 425 priv->params_ethtool.fec_avail_50x[2] = 426 MLX5_GET(pplm_reg, in, fec_override_cap_200g_4x); 427 priv->params_ethtool.fec_avail_50x[3] = 428 MLX5_GET(pplm_reg, in, fec_override_cap_400g_8x); 429 430 /* get current FEC mask */ 431 priv->params_ethtool.fec_mode_active = 432 MLX5_GET(pplm_reg, in, fec_mode_active); 433 434 return (0); 435 } 436 437 static int 438 mlx5e_fec_mask_10x_25x_handler(SYSCTL_HANDLER_ARGS) 439 { 440 struct mlx5e_priv *priv = arg1; 441 struct mlx5_core_dev *mdev = priv->mdev; 442 u32 out[MLX5_ST_SZ_DW(pplm_reg)] = {}; 443 u32 in[MLX5_ST_SZ_DW(pplm_reg)] = {}; 444 const int sz = MLX5_ST_SZ_BYTES(pplm_reg); 445 u8 fec_mask_10x_25x[MLX5E_MAX_FEC_10X_25X]; 446 u8 fec_cap_changed = 0; 447 u8 x; 448 int err; 449 450 PRIV_LOCK(priv); 451 err = SYSCTL_OUT(req, priv->params_ethtool.fec_mask_10x_25x, 452 sizeof(priv->params_ethtool.fec_mask_10x_25x)); 453 if (err || !req->newptr) 454 goto done; 455 456 err = SYSCTL_IN(req, fec_mask_10x_25x, 457 sizeof(fec_mask_10x_25x)); 458 if (err) 459 goto done; 460 461 if (!MLX5_CAP_GEN(mdev, pcam_reg)) { 462 err = EOPNOTSUPP; 463 goto done; 464 } 465 466 if (!MLX5_CAP_PCAM_REG(mdev, pplm)) { 467 err = EOPNOTSUPP; 468 goto done; 469 } 470 471 MLX5_SET(pplm_reg, in, local_port, 1); 472 473 err = -mlx5_core_access_reg(mdev, in, sz, in, sz, MLX5_REG_PPLM, 0, 0); 474 if (err) 475 goto done; 476 477 /* range check input value */ 478 for (x = 0; x != MLX5E_MAX_FEC_10X_25X; x++) { 479 /* check only one bit is set, if any */ 480 if (fec_mask_10x_25x[x] & (fec_mask_10x_25x[x] - 1)) { 481 err = ERANGE; 482 goto done; 483 } 484 /* check a supported bit is set, if any */ 485 if (fec_mask_10x_25x[x] & 486 ~priv->params_ethtool.fec_avail_10x_25x[x]) { 487 err = ERANGE; 488 goto done; 489 } 490 fec_cap_changed |= (fec_mask_10x_25x[x] ^ 491 priv->params_ethtool.fec_mask_10x_25x[x]); 492 } 493 494 /* check for no changes */ 495 if (fec_cap_changed == 0) 496 goto done; 497 498 memset(in, 0, sizeof(in)); 499 500 MLX5_SET(pplm_reg, in, local_port, 1); 501 502 /* set new values */ 503 MLX5_SET(pplm_reg, in, fec_override_admin_10g_40g, fec_mask_10x_25x[0]); 504 MLX5_SET(pplm_reg, in, fec_override_admin_25g, fec_mask_10x_25x[1]); 505 MLX5_SET(pplm_reg, in, fec_override_admin_50g, fec_mask_10x_25x[1]); 506 MLX5_SET(pplm_reg, in, fec_override_admin_56g, fec_mask_10x_25x[2]); 507 MLX5_SET(pplm_reg, in, fec_override_admin_100g, fec_mask_10x_25x[3]); 508 509 /* preserve other values */ 510 MLX5_SET(pplm_reg, in, fec_override_admin_50g_1x, priv->params_ethtool.fec_mask_50x[0]); 511 MLX5_SET(pplm_reg, in, fec_override_admin_100g_2x, priv->params_ethtool.fec_mask_50x[1]); 512 MLX5_SET(pplm_reg, in, fec_override_admin_200g_4x, priv->params_ethtool.fec_mask_50x[2]); 513 MLX5_SET(pplm_reg, in, fec_override_admin_400g_8x, priv->params_ethtool.fec_mask_50x[3]); 514 515 /* send new value to the firmware */ 516 err = -mlx5_core_access_reg(mdev, in, sz, out, sz, MLX5_REG_PPLM, 0, 1); 517 if (err) 518 goto done; 519 520 memcpy(priv->params_ethtool.fec_mask_10x_25x, fec_mask_10x_25x, 521 sizeof(priv->params_ethtool.fec_mask_10x_25x)); 522 523 mlx5_toggle_port_link(priv->mdev); 524 done: 525 PRIV_UNLOCK(priv); 526 return (err); 527 } 528 529 static int 530 mlx5e_fec_avail_10x_25x_handler(SYSCTL_HANDLER_ARGS) 531 { 532 struct mlx5e_priv *priv = arg1; 533 int err; 534 535 PRIV_LOCK(priv); 536 err = SYSCTL_OUT(req, priv->params_ethtool.fec_avail_10x_25x, 537 sizeof(priv->params_ethtool.fec_avail_10x_25x)); 538 PRIV_UNLOCK(priv); 539 return (err); 540 } 541 542 static int 543 mlx5e_fec_mask_50x_handler(SYSCTL_HANDLER_ARGS) 544 { 545 struct mlx5e_priv *priv = arg1; 546 struct mlx5_core_dev *mdev = priv->mdev; 547 u32 out[MLX5_ST_SZ_DW(pplm_reg)] = {}; 548 u32 in[MLX5_ST_SZ_DW(pplm_reg)] = {}; 549 const int sz = MLX5_ST_SZ_BYTES(pplm_reg); 550 u16 fec_mask_50x[MLX5E_MAX_FEC_50X]; 551 u16 fec_cap_changed = 0; 552 u8 x; 553 int err; 554 555 PRIV_LOCK(priv); 556 err = SYSCTL_OUT(req, priv->params_ethtool.fec_mask_50x, 557 sizeof(priv->params_ethtool.fec_mask_50x)); 558 if (err || !req->newptr) 559 goto done; 560 561 err = SYSCTL_IN(req, fec_mask_50x, 562 sizeof(fec_mask_50x)); 563 if (err) 564 goto done; 565 566 if (!MLX5_CAP_GEN(mdev, pcam_reg)) { 567 err = EOPNOTSUPP; 568 goto done; 569 } 570 571 if (!MLX5_CAP_PCAM_REG(mdev, pplm)) { 572 err = EOPNOTSUPP; 573 goto done; 574 } 575 576 MLX5_SET(pplm_reg, in, local_port, 1); 577 578 err = -mlx5_core_access_reg(mdev, in, sz, in, sz, MLX5_REG_PPLM, 0, 0); 579 if (err) 580 goto done; 581 582 /* range check input value */ 583 for (x = 0; x != MLX5E_MAX_FEC_50X; x++) { 584 /* check only one bit is set, if any */ 585 if (fec_mask_50x[x] & (fec_mask_50x[x] - 1)) { 586 err = ERANGE; 587 goto done; 588 } 589 /* check a supported bit is set, if any */ 590 if (fec_mask_50x[x] & 591 ~priv->params_ethtool.fec_avail_50x[x]) { 592 err = ERANGE; 593 goto done; 594 } 595 fec_cap_changed |= (fec_mask_50x[x] ^ 596 priv->params_ethtool.fec_mask_50x[x]); 597 } 598 599 /* check for no changes */ 600 if (fec_cap_changed == 0) 601 goto done; 602 603 memset(in, 0, sizeof(in)); 604 605 MLX5_SET(pplm_reg, in, local_port, 1); 606 607 /* set new values */ 608 MLX5_SET(pplm_reg, in, fec_override_admin_50g_1x, fec_mask_50x[0]); 609 MLX5_SET(pplm_reg, in, fec_override_admin_100g_2x, fec_mask_50x[1]); 610 MLX5_SET(pplm_reg, in, fec_override_admin_200g_4x, fec_mask_50x[2]); 611 MLX5_SET(pplm_reg, in, fec_override_admin_400g_8x, fec_mask_50x[3]); 612 613 /* preserve other values */ 614 MLX5_SET(pplm_reg, in, fec_override_admin_10g_40g, priv->params_ethtool.fec_mask_10x_25x[0]); 615 MLX5_SET(pplm_reg, in, fec_override_admin_25g, priv->params_ethtool.fec_mask_10x_25x[1]); 616 MLX5_SET(pplm_reg, in, fec_override_admin_50g, priv->params_ethtool.fec_mask_10x_25x[1]); 617 MLX5_SET(pplm_reg, in, fec_override_admin_56g, priv->params_ethtool.fec_mask_10x_25x[2]); 618 MLX5_SET(pplm_reg, in, fec_override_admin_100g, priv->params_ethtool.fec_mask_10x_25x[3]); 619 620 /* send new value to the firmware */ 621 err = -mlx5_core_access_reg(mdev, in, sz, out, sz, MLX5_REG_PPLM, 0, 1); 622 if (err) 623 goto done; 624 625 memcpy(priv->params_ethtool.fec_mask_50x, fec_mask_50x, 626 sizeof(priv->params_ethtool.fec_mask_50x)); 627 628 mlx5_toggle_port_link(priv->mdev); 629 done: 630 PRIV_UNLOCK(priv); 631 return (err); 632 } 633 634 static int 635 mlx5e_fec_avail_50x_handler(SYSCTL_HANDLER_ARGS) 636 { 637 struct mlx5e_priv *priv = arg1; 638 int err; 639 640 PRIV_LOCK(priv); 641 err = SYSCTL_OUT(req, priv->params_ethtool.fec_avail_50x, 642 sizeof(priv->params_ethtool.fec_avail_50x)); 643 PRIV_UNLOCK(priv); 644 return (err); 645 } 646 647 static int 648 mlx5e_trust_state_handler(SYSCTL_HANDLER_ARGS) 649 { 650 struct mlx5e_priv *priv = arg1; 651 struct mlx5_core_dev *mdev = priv->mdev; 652 int err; 653 u8 result; 654 655 PRIV_LOCK(priv); 656 result = priv->params_ethtool.trust_state; 657 err = sysctl_handle_8(oidp, &result, 0, req); 658 if (err || !req->newptr || 659 result == priv->params_ethtool.trust_state) 660 goto done; 661 662 switch (result) { 663 case MLX5_QPTS_TRUST_PCP: 664 case MLX5_QPTS_TRUST_DSCP: 665 break; 666 case MLX5_QPTS_TRUST_BOTH: 667 if (!MLX5_CAP_QCAM_FEATURE(mdev, qpts_trust_both)) { 668 err = EOPNOTSUPP; 669 goto done; 670 } 671 break; 672 default: 673 err = ERANGE; 674 goto done; 675 } 676 677 err = -mlx5_set_trust_state(mdev, result); 678 if (err) 679 goto done; 680 681 priv->params_ethtool.trust_state = result; 682 683 /* update inline mode */ 684 mlx5e_refresh_sq_inline(priv); 685 #ifdef RATELIMIT 686 mlx5e_rl_refresh_sq_inline(&priv->rl); 687 #endif 688 done: 689 PRIV_UNLOCK(priv); 690 return (err); 691 } 692 693 static int 694 mlx5e_dscp_prio_handler(SYSCTL_HANDLER_ARGS) 695 { 696 struct mlx5e_priv *priv = arg1; 697 int prio_index = arg2; 698 struct mlx5_core_dev *mdev = priv->mdev; 699 uint8_t dscp2prio[MLX5_MAX_SUPPORTED_DSCP]; 700 uint8_t x; 701 int err; 702 703 PRIV_LOCK(priv); 704 err = SYSCTL_OUT(req, priv->params_ethtool.dscp2prio + prio_index, 705 sizeof(priv->params_ethtool.dscp2prio) / 8); 706 if (err || !req->newptr) 707 goto done; 708 709 memcpy(dscp2prio, priv->params_ethtool.dscp2prio, sizeof(dscp2prio)); 710 err = SYSCTL_IN(req, dscp2prio + prio_index, sizeof(dscp2prio) / 8); 711 if (err) 712 goto done; 713 for (x = 0; x != MLX5_MAX_SUPPORTED_DSCP; x++) { 714 if (dscp2prio[x] > 7) { 715 err = ERANGE; 716 goto done; 717 } 718 } 719 err = -mlx5_set_dscp2prio(mdev, dscp2prio); 720 if (err) 721 goto done; 722 723 /* update local array */ 724 memcpy(priv->params_ethtool.dscp2prio, dscp2prio, 725 sizeof(priv->params_ethtool.dscp2prio)); 726 done: 727 PRIV_UNLOCK(priv); 728 return (err); 729 } 730 731 int 732 mlx5e_update_buf_lossy(struct mlx5e_priv *priv) 733 { 734 struct ieee_pfc pfc; 735 736 PRIV_ASSERT_LOCKED(priv); 737 bzero(&pfc, sizeof(pfc)); 738 pfc.pfc_en = priv->params.rx_priority_flow_control; 739 return (-mlx5e_port_manual_buffer_config(priv, MLX5E_PORT_BUFFER_PFC, 740 priv->params_ethtool.hw_mtu, &pfc, NULL, NULL)); 741 } 742 743 static int 744 mlx5e_buf_size_handler(SYSCTL_HANDLER_ARGS) 745 { 746 struct mlx5e_priv *priv; 747 u32 buf_size[MLX5E_MAX_BUFFER]; 748 struct mlx5e_port_buffer port_buffer; 749 int error, i; 750 751 priv = arg1; 752 PRIV_LOCK(priv); 753 error = -mlx5e_port_query_buffer(priv, &port_buffer); 754 if (error != 0) 755 goto done; 756 for (i = 0; i < nitems(buf_size); i++) 757 buf_size[i] = port_buffer.buffer[i].size; 758 error = SYSCTL_OUT(req, buf_size, sizeof(buf_size)); 759 if (error != 0 || req->newptr == NULL) 760 goto done; 761 error = SYSCTL_IN(req, buf_size, sizeof(buf_size)); 762 if (error != 0) 763 goto done; 764 error = -mlx5e_port_manual_buffer_config(priv, MLX5E_PORT_BUFFER_SIZE, 765 priv->params_ethtool.hw_mtu, NULL, buf_size, NULL); 766 done: 767 PRIV_UNLOCK(priv); 768 return (error); 769 } 770 771 static int 772 mlx5e_buf_prio_handler(SYSCTL_HANDLER_ARGS) 773 { 774 struct mlx5e_priv *priv; 775 struct mlx5_core_dev *mdev; 776 u8 buffer[MLX5E_MAX_BUFFER]; 777 int error; 778 779 priv = arg1; 780 mdev = priv->mdev; 781 PRIV_LOCK(priv); 782 error = -mlx5e_port_query_priority2buffer(mdev, buffer); 783 if (error != 0) 784 goto done; 785 error = SYSCTL_OUT(req, buffer, MLX5E_MAX_BUFFER); 786 if (error != 0 || req->newptr == NULL) 787 goto done; 788 error = SYSCTL_IN(req, buffer, MLX5E_MAX_BUFFER); 789 if (error != 0) 790 goto done; 791 error = -mlx5e_port_manual_buffer_config(priv, 792 MLX5E_PORT_BUFFER_PRIO2BUFFER, 793 priv->params_ethtool.hw_mtu, NULL, NULL, buffer); 794 if (error == 0) 795 error = mlx5e_update_buf_lossy(priv); 796 done: 797 PRIV_UNLOCK(priv); 798 return (error); 799 } 800 801 static int 802 mlx5e_cable_length_handler(SYSCTL_HANDLER_ARGS) 803 { 804 struct mlx5e_priv *priv; 805 u_int cable_len; 806 int error; 807 808 priv = arg1; 809 PRIV_LOCK(priv); 810 cable_len = priv->dcbx.cable_len; 811 error = sysctl_handle_int(oidp, &cable_len, 0, req); 812 if (error == 0 && req->newptr != NULL && 813 cable_len != priv->dcbx.cable_len) { 814 error = -mlx5e_port_manual_buffer_config(priv, 815 MLX5E_PORT_BUFFER_CABLE_LEN, priv->params_ethtool.hw_mtu, 816 NULL, NULL, NULL); 817 if (error == 0) 818 priv->dcbx.cable_len = cable_len; 819 } 820 PRIV_UNLOCK(priv); 821 return (error); 822 } 823 824 #define MLX5_PARAM_OFFSET(n) \ 825 __offsetof(struct mlx5e_priv, params_ethtool.n) 826 827 static int 828 mlx5e_ethtool_handler(SYSCTL_HANDLER_ARGS) 829 { 830 struct mlx5e_priv *priv = arg1; 831 uint64_t value; 832 int mode_modify; 833 int was_opened; 834 int error; 835 836 PRIV_LOCK(priv); 837 value = priv->params_ethtool.arg[arg2]; 838 if (req != NULL) { 839 error = sysctl_handle_64(oidp, &value, 0, req); 840 if (error || req->newptr == NULL || 841 value == priv->params_ethtool.arg[arg2]) 842 goto done; 843 844 /* assign new value */ 845 priv->params_ethtool.arg[arg2] = value; 846 } else { 847 error = 0; 848 } 849 /* check if device is gone */ 850 if (priv->gone) { 851 error = ENXIO; 852 goto done; 853 } 854 was_opened = test_bit(MLX5E_STATE_OPENED, &priv->state); 855 mode_modify = MLX5_CAP_GEN(priv->mdev, cq_period_mode_modify); 856 857 switch (MLX5_PARAM_OFFSET(arg[arg2])) { 858 case MLX5_PARAM_OFFSET(rx_coalesce_usecs): 859 /* import RX coal time */ 860 if (priv->params_ethtool.rx_coalesce_usecs < 1) 861 priv->params_ethtool.rx_coalesce_usecs = 0; 862 else if (priv->params_ethtool.rx_coalesce_usecs > 863 MLX5E_FLD_MAX(cqc, cq_period)) { 864 priv->params_ethtool.rx_coalesce_usecs = 865 MLX5E_FLD_MAX(cqc, cq_period); 866 } 867 priv->params.rx_cq_moderation_usec = 868 priv->params_ethtool.rx_coalesce_usecs; 869 870 /* check to avoid down and up the network interface */ 871 if (was_opened) 872 error = mlx5e_refresh_channel_params(priv); 873 break; 874 875 case MLX5_PARAM_OFFSET(rx_coalesce_pkts): 876 /* import RX coal pkts */ 877 if (priv->params_ethtool.rx_coalesce_pkts < 1) 878 priv->params_ethtool.rx_coalesce_pkts = 0; 879 else if (priv->params_ethtool.rx_coalesce_pkts > 880 MLX5E_FLD_MAX(cqc, cq_max_count)) { 881 priv->params_ethtool.rx_coalesce_pkts = 882 MLX5E_FLD_MAX(cqc, cq_max_count); 883 } 884 priv->params.rx_cq_moderation_pkts = 885 priv->params_ethtool.rx_coalesce_pkts; 886 887 /* check to avoid down and up the network interface */ 888 if (was_opened) 889 error = mlx5e_refresh_channel_params(priv); 890 break; 891 892 case MLX5_PARAM_OFFSET(tx_coalesce_usecs): 893 /* import TX coal time */ 894 if (priv->params_ethtool.tx_coalesce_usecs < 1) 895 priv->params_ethtool.tx_coalesce_usecs = 0; 896 else if (priv->params_ethtool.tx_coalesce_usecs > 897 MLX5E_FLD_MAX(cqc, cq_period)) { 898 priv->params_ethtool.tx_coalesce_usecs = 899 MLX5E_FLD_MAX(cqc, cq_period); 900 } 901 priv->params.tx_cq_moderation_usec = 902 priv->params_ethtool.tx_coalesce_usecs; 903 904 /* check to avoid down and up the network interface */ 905 if (was_opened) 906 error = mlx5e_refresh_channel_params(priv); 907 break; 908 909 case MLX5_PARAM_OFFSET(tx_coalesce_pkts): 910 /* import TX coal pkts */ 911 if (priv->params_ethtool.tx_coalesce_pkts < 1) 912 priv->params_ethtool.tx_coalesce_pkts = 0; 913 else if (priv->params_ethtool.tx_coalesce_pkts > 914 MLX5E_FLD_MAX(cqc, cq_max_count)) { 915 priv->params_ethtool.tx_coalesce_pkts = 916 MLX5E_FLD_MAX(cqc, cq_max_count); 917 } 918 priv->params.tx_cq_moderation_pkts = 919 priv->params_ethtool.tx_coalesce_pkts; 920 921 /* check to avoid down and up the network interface */ 922 if (was_opened) 923 error = mlx5e_refresh_channel_params(priv); 924 break; 925 926 case MLX5_PARAM_OFFSET(tx_queue_size): 927 /* network interface must be down */ 928 if (was_opened) 929 mlx5e_close_locked(priv->ifp); 930 931 /* import TX queue size */ 932 if (priv->params_ethtool.tx_queue_size < 933 (1 << MLX5E_PARAMS_MINIMUM_LOG_SQ_SIZE)) { 934 priv->params_ethtool.tx_queue_size = 935 (1 << MLX5E_PARAMS_MINIMUM_LOG_SQ_SIZE); 936 } else if (priv->params_ethtool.tx_queue_size > 937 priv->params_ethtool.tx_queue_size_max) { 938 priv->params_ethtool.tx_queue_size = 939 priv->params_ethtool.tx_queue_size_max; 940 } 941 /* store actual TX queue size */ 942 priv->params.log_sq_size = 943 order_base_2(priv->params_ethtool.tx_queue_size); 944 priv->params_ethtool.tx_queue_size = 945 1 << priv->params.log_sq_size; 946 947 /* verify TX completion factor */ 948 mlx5e_ethtool_sync_tx_completion_fact(priv); 949 950 /* restart network interface, if any */ 951 if (was_opened) 952 mlx5e_open_locked(priv->ifp); 953 break; 954 955 case MLX5_PARAM_OFFSET(rx_queue_size): 956 /* network interface must be down */ 957 if (was_opened) 958 mlx5e_close_locked(priv->ifp); 959 960 /* import RX queue size */ 961 if (priv->params_ethtool.rx_queue_size < 962 (1 << MLX5E_PARAMS_MINIMUM_LOG_RQ_SIZE)) { 963 priv->params_ethtool.rx_queue_size = 964 (1 << MLX5E_PARAMS_MINIMUM_LOG_RQ_SIZE); 965 } else if (priv->params_ethtool.rx_queue_size > 966 priv->params_ethtool.rx_queue_size_max) { 967 priv->params_ethtool.rx_queue_size = 968 priv->params_ethtool.rx_queue_size_max; 969 } 970 /* store actual RX queue size */ 971 priv->params.log_rq_size = 972 order_base_2(priv->params_ethtool.rx_queue_size); 973 priv->params_ethtool.rx_queue_size = 974 1 << priv->params.log_rq_size; 975 976 /* update least number of RX WQEs */ 977 priv->params.min_rx_wqes = min( 978 priv->params_ethtool.rx_queue_size - 1, 979 MLX5E_PARAMS_DEFAULT_MIN_RX_WQES); 980 981 /* restart network interface, if any */ 982 if (was_opened) 983 mlx5e_open_locked(priv->ifp); 984 break; 985 986 case MLX5_PARAM_OFFSET(channels_rsss): 987 /* network interface must be down */ 988 if (was_opened) 989 mlx5e_close_locked(priv->ifp); 990 991 /* import number of channels */ 992 if (priv->params_ethtool.channels_rsss < 1) 993 priv->params_ethtool.channels_rsss = 1; 994 else if (priv->params_ethtool.channels_rsss > 128) 995 priv->params_ethtool.channels_rsss = 128; 996 997 priv->params.channels_rsss = priv->params_ethtool.channels_rsss; 998 999 /* restart network interface, if any */ 1000 if (was_opened) 1001 mlx5e_open_locked(priv->ifp); 1002 break; 1003 1004 case MLX5_PARAM_OFFSET(channels): 1005 /* network interface must be down */ 1006 if (was_opened) 1007 mlx5e_close_locked(priv->ifp); 1008 1009 /* import number of channels */ 1010 if (priv->params_ethtool.channels < 1) 1011 priv->params_ethtool.channels = 1; 1012 else if (priv->params_ethtool.channels > 1013 (u64) priv->mdev->priv.eq_table.num_comp_vectors) { 1014 priv->params_ethtool.channels = 1015 (u64) priv->mdev->priv.eq_table.num_comp_vectors; 1016 } 1017 priv->params.num_channels = priv->params_ethtool.channels; 1018 1019 /* restart network interface, if any */ 1020 if (was_opened) 1021 mlx5e_open_locked(priv->ifp); 1022 break; 1023 1024 case MLX5_PARAM_OFFSET(rx_coalesce_mode): 1025 /* network interface must be down */ 1026 if (was_opened != 0 && mode_modify == 0) 1027 mlx5e_close_locked(priv->ifp); 1028 1029 /* import RX coalesce mode */ 1030 if (priv->params_ethtool.rx_coalesce_mode > 3) 1031 priv->params_ethtool.rx_coalesce_mode = 3; 1032 priv->params.rx_cq_moderation_mode = 1033 priv->params_ethtool.rx_coalesce_mode; 1034 1035 /* restart network interface, if any */ 1036 if (was_opened != 0) { 1037 if (mode_modify == 0) 1038 mlx5e_open_locked(priv->ifp); 1039 else 1040 error = mlx5e_refresh_channel_params(priv); 1041 } 1042 break; 1043 1044 case MLX5_PARAM_OFFSET(tx_coalesce_mode): 1045 /* network interface must be down */ 1046 if (was_opened != 0 && mode_modify == 0) 1047 mlx5e_close_locked(priv->ifp); 1048 1049 /* import TX coalesce mode */ 1050 if (priv->params_ethtool.tx_coalesce_mode != 0) 1051 priv->params_ethtool.tx_coalesce_mode = 1; 1052 priv->params.tx_cq_moderation_mode = 1053 priv->params_ethtool.tx_coalesce_mode; 1054 1055 /* restart network interface, if any */ 1056 if (was_opened != 0) { 1057 if (mode_modify == 0) 1058 mlx5e_open_locked(priv->ifp); 1059 else 1060 error = mlx5e_refresh_channel_params(priv); 1061 } 1062 break; 1063 1064 case MLX5_PARAM_OFFSET(hw_lro): 1065 /* network interface must be down */ 1066 if (was_opened) 1067 mlx5e_close_locked(priv->ifp); 1068 1069 /* import HW LRO mode */ 1070 if (priv->params_ethtool.hw_lro != 0 && 1071 MLX5_CAP_ETH(priv->mdev, lro_cap)) { 1072 priv->params_ethtool.hw_lro = 1; 1073 /* check if feature should actually be enabled */ 1074 if (priv->ifp->if_capenable & IFCAP_LRO) { 1075 priv->params.hw_lro_en = true; 1076 } else { 1077 priv->params.hw_lro_en = false; 1078 1079 mlx5_en_warn(priv->ifp, "To enable HW LRO " 1080 "please also enable LRO via ifconfig(8).\n"); 1081 } 1082 } else { 1083 /* return an error if HW does not support this feature */ 1084 if (priv->params_ethtool.hw_lro != 0) 1085 error = EINVAL; 1086 priv->params.hw_lro_en = false; 1087 priv->params_ethtool.hw_lro = 0; 1088 } 1089 /* restart network interface, if any */ 1090 if (was_opened) 1091 mlx5e_open_locked(priv->ifp); 1092 break; 1093 1094 case MLX5_PARAM_OFFSET(cqe_zipping): 1095 /* network interface must be down */ 1096 if (was_opened) 1097 mlx5e_close_locked(priv->ifp); 1098 1099 /* import CQE zipping mode */ 1100 if (priv->params_ethtool.cqe_zipping && 1101 MLX5_CAP_GEN(priv->mdev, cqe_compression)) { 1102 priv->params.cqe_zipping_en = true; 1103 priv->params_ethtool.cqe_zipping = 1; 1104 } else { 1105 priv->params.cqe_zipping_en = false; 1106 priv->params_ethtool.cqe_zipping = 0; 1107 } 1108 /* restart network interface, if any */ 1109 if (was_opened) 1110 mlx5e_open_locked(priv->ifp); 1111 break; 1112 1113 case MLX5_PARAM_OFFSET(tx_completion_fact): 1114 /* network interface must be down */ 1115 if (was_opened) 1116 mlx5e_close_locked(priv->ifp); 1117 1118 /* verify parameter */ 1119 mlx5e_ethtool_sync_tx_completion_fact(priv); 1120 1121 /* restart network interface, if any */ 1122 if (was_opened) 1123 mlx5e_open_locked(priv->ifp); 1124 break; 1125 1126 case MLX5_PARAM_OFFSET(modify_tx_dma): 1127 /* check if network interface is opened */ 1128 if (was_opened) { 1129 priv->params_ethtool.modify_tx_dma = 1130 priv->params_ethtool.modify_tx_dma ? 1 : 0; 1131 /* modify tx according to value */ 1132 mlx5e_modify_tx_dma(priv, value != 0); 1133 } else { 1134 /* if closed force enable tx */ 1135 priv->params_ethtool.modify_tx_dma = 0; 1136 } 1137 break; 1138 1139 case MLX5_PARAM_OFFSET(modify_rx_dma): 1140 /* check if network interface is opened */ 1141 if (was_opened) { 1142 priv->params_ethtool.modify_rx_dma = 1143 priv->params_ethtool.modify_rx_dma ? 1 : 0; 1144 /* modify rx according to value */ 1145 mlx5e_modify_rx_dma(priv, value != 0); 1146 } else { 1147 /* if closed force enable rx */ 1148 priv->params_ethtool.modify_rx_dma = 0; 1149 } 1150 break; 1151 1152 case MLX5_PARAM_OFFSET(diag_pci_enable): 1153 priv->params_ethtool.diag_pci_enable = 1154 priv->params_ethtool.diag_pci_enable ? 1 : 0; 1155 1156 error = -mlx5_core_set_diagnostics_full(priv->mdev, 1157 priv->params_ethtool.diag_pci_enable, 1158 priv->params_ethtool.diag_general_enable); 1159 break; 1160 1161 case MLX5_PARAM_OFFSET(diag_general_enable): 1162 priv->params_ethtool.diag_general_enable = 1163 priv->params_ethtool.diag_general_enable ? 1 : 0; 1164 1165 error = -mlx5_core_set_diagnostics_full(priv->mdev, 1166 priv->params_ethtool.diag_pci_enable, 1167 priv->params_ethtool.diag_general_enable); 1168 break; 1169 1170 case MLX5_PARAM_OFFSET(mc_local_lb): 1171 priv->params_ethtool.mc_local_lb = 1172 priv->params_ethtool.mc_local_lb ? 1 : 0; 1173 1174 if (MLX5_CAP_GEN(priv->mdev, disable_local_lb)) { 1175 error = mlx5_nic_vport_modify_local_lb(priv->mdev, 1176 MLX5_LOCAL_MC_LB, priv->params_ethtool.mc_local_lb); 1177 } else { 1178 error = EOPNOTSUPP; 1179 } 1180 break; 1181 1182 case MLX5_PARAM_OFFSET(uc_local_lb): 1183 priv->params_ethtool.uc_local_lb = 1184 priv->params_ethtool.uc_local_lb ? 1 : 0; 1185 1186 if (MLX5_CAP_GEN(priv->mdev, disable_local_lb)) { 1187 error = mlx5_nic_vport_modify_local_lb(priv->mdev, 1188 MLX5_LOCAL_UC_LB, priv->params_ethtool.uc_local_lb); 1189 } else { 1190 error = EOPNOTSUPP; 1191 } 1192 break; 1193 1194 default: 1195 break; 1196 } 1197 done: 1198 PRIV_UNLOCK(priv); 1199 return (error); 1200 } 1201 1202 static const char *mlx5e_params_desc[] = { 1203 MLX5E_PARAMS(MLX5E_STATS_DESC) 1204 }; 1205 1206 static const char *mlx5e_port_stats_debug_desc[] = { 1207 MLX5E_PORT_STATS_DEBUG(MLX5E_STATS_DESC) 1208 }; 1209 1210 static int 1211 mlx5e_ethtool_debug_channel_info(SYSCTL_HANDLER_ARGS) 1212 { 1213 struct mlx5e_priv *priv; 1214 struct sbuf sb; 1215 struct mlx5e_channel *c; 1216 struct mlx5e_sq *sq; 1217 struct mlx5e_rq *rq; 1218 int error, i, tc; 1219 bool opened; 1220 1221 priv = arg1; 1222 error = sysctl_wire_old_buffer(req, 0); 1223 if (error != 0) 1224 return (error); 1225 if (sbuf_new_for_sysctl(&sb, NULL, 1024, req) == NULL) 1226 return (ENOMEM); 1227 sbuf_clear_flags(&sb, SBUF_INCLUDENUL); 1228 1229 PRIV_LOCK(priv); 1230 opened = test_bit(MLX5E_STATE_OPENED, &priv->state); 1231 1232 sbuf_printf(&sb, "pages irq %d\n", 1233 priv->mdev->priv.msix_arr[MLX5_EQ_VEC_PAGES].vector); 1234 sbuf_printf(&sb, "command irq %d\n", 1235 priv->mdev->priv.msix_arr[MLX5_EQ_VEC_CMD].vector); 1236 sbuf_printf(&sb, "async irq %d\n", 1237 priv->mdev->priv.msix_arr[MLX5_EQ_VEC_ASYNC].vector); 1238 1239 for (i = 0; i != priv->params.num_channels; i++) { 1240 int eqn_not_used = -1; 1241 int irqn = MLX5_EQ_VEC_COMP_BASE; 1242 1243 if (mlx5_vector2eqn(priv->mdev, i, &eqn_not_used, &irqn) != 0) 1244 continue; 1245 1246 c = opened ? &priv->channel[i] : NULL; 1247 rq = opened ? &c->rq : NULL; 1248 sbuf_printf(&sb, "channel %d rq %d cq %d irq %d\n", i, 1249 opened ? rq->rqn : -1, 1250 opened ? rq->cq.mcq.cqn : -1, 1251 priv->mdev->priv.msix_arr[irqn].vector); 1252 1253 for (tc = 0; tc != priv->num_tc; tc++) { 1254 sq = opened ? &c->sq[tc] : NULL; 1255 sbuf_printf(&sb, "channel %d tc %d sq %d cq %d irq %d\n", 1256 i, tc, 1257 opened ? sq->sqn : -1, 1258 opened ? sq->cq.mcq.cqn : -1, 1259 priv->mdev->priv.msix_arr[irqn].vector); 1260 } 1261 } 1262 PRIV_UNLOCK(priv); 1263 error = sbuf_finish(&sb); 1264 sbuf_delete(&sb); 1265 return (error); 1266 } 1267 1268 static int 1269 mlx5e_ethtool_debug_stats(SYSCTL_HANDLER_ARGS) 1270 { 1271 struct mlx5e_priv *priv = arg1; 1272 int sys_debug; 1273 int error; 1274 1275 PRIV_LOCK(priv); 1276 if (priv->gone != 0) { 1277 error = ENODEV; 1278 goto done; 1279 } 1280 sys_debug = priv->sysctl_debug; 1281 error = sysctl_handle_int(oidp, &sys_debug, 0, req); 1282 if (error != 0 || !req->newptr) 1283 goto done; 1284 sys_debug = sys_debug ? 1 : 0; 1285 if (sys_debug == priv->sysctl_debug) 1286 goto done; 1287 1288 if ((priv->sysctl_debug = sys_debug)) { 1289 mlx5e_create_stats(&priv->stats.port_stats_debug.ctx, 1290 SYSCTL_CHILDREN(priv->sysctl_ifnet), "debug_stats", 1291 mlx5e_port_stats_debug_desc, MLX5E_PORT_STATS_DEBUG_NUM, 1292 priv->stats.port_stats_debug.arg); 1293 SYSCTL_ADD_PROC(&priv->stats.port_stats_debug.ctx, 1294 SYSCTL_CHILDREN(priv->sysctl_ifnet), OID_AUTO, 1295 "hw_ctx_debug", 1296 CTLFLAG_RD | CTLFLAG_MPSAFE | CTLTYPE_STRING, priv, 0, 1297 mlx5e_ethtool_debug_channel_info, "S", ""); 1298 } else { 1299 sysctl_ctx_free(&priv->stats.port_stats_debug.ctx); 1300 } 1301 done: 1302 PRIV_UNLOCK(priv); 1303 return (error); 1304 } 1305 1306 static void 1307 mlx5e_create_diagnostics(struct mlx5e_priv *priv) 1308 { 1309 struct mlx5_core_diagnostics_entry entry; 1310 struct sysctl_ctx_list *ctx; 1311 struct sysctl_oid *node; 1312 int x; 1313 1314 /* sysctl context we are using */ 1315 ctx = &priv->sysctl_ctx; 1316 1317 /* create root node */ 1318 node = SYSCTL_ADD_NODE(ctx, 1319 SYSCTL_CHILDREN(priv->sysctl_ifnet), OID_AUTO, 1320 "diagnostics", CTLFLAG_RD, NULL, "Diagnostics"); 1321 if (node == NULL) 1322 return; 1323 1324 /* create PCI diagnostics */ 1325 for (x = 0; x != MLX5_CORE_PCI_DIAGNOSTICS_NUM; x++) { 1326 entry = mlx5_core_pci_diagnostics_table[x]; 1327 if (mlx5_core_supports_diagnostics(priv->mdev, entry.counter_id) == 0) 1328 continue; 1329 SYSCTL_ADD_UQUAD(ctx, SYSCTL_CHILDREN(node), OID_AUTO, 1330 entry.desc, CTLFLAG_RD, priv->params_pci.array + x, 1331 "PCI diagnostics counter"); 1332 } 1333 1334 /* create general diagnostics */ 1335 for (x = 0; x != MLX5_CORE_GENERAL_DIAGNOSTICS_NUM; x++) { 1336 entry = mlx5_core_general_diagnostics_table[x]; 1337 if (mlx5_core_supports_diagnostics(priv->mdev, entry.counter_id) == 0) 1338 continue; 1339 SYSCTL_ADD_UQUAD(ctx, SYSCTL_CHILDREN(node), OID_AUTO, 1340 entry.desc, CTLFLAG_RD, priv->params_general.array + x, 1341 "General diagnostics counter"); 1342 } 1343 } 1344 1345 void 1346 mlx5e_create_ethtool(struct mlx5e_priv *priv) 1347 { 1348 struct sysctl_oid *fec_node; 1349 struct sysctl_oid *qos_node; 1350 struct sysctl_oid *node; 1351 const char *pnameunit; 1352 struct mlx5e_port_buffer port_buffer; 1353 unsigned x; 1354 int i; 1355 1356 /* set some defaults */ 1357 priv->params_ethtool.tx_queue_size_max = 1 << MLX5E_PARAMS_MAXIMUM_LOG_SQ_SIZE; 1358 priv->params_ethtool.rx_queue_size_max = 1 << MLX5E_PARAMS_MAXIMUM_LOG_RQ_SIZE; 1359 priv->params_ethtool.tx_queue_size = 1 << priv->params.log_sq_size; 1360 priv->params_ethtool.rx_queue_size = 1 << priv->params.log_rq_size; 1361 priv->params_ethtool.channels = priv->params.num_channels; 1362 priv->params_ethtool.channels_rsss = priv->params.channels_rsss; 1363 priv->params_ethtool.coalesce_pkts_max = MLX5E_FLD_MAX(cqc, cq_max_count); 1364 priv->params_ethtool.coalesce_usecs_max = MLX5E_FLD_MAX(cqc, cq_period); 1365 priv->params_ethtool.rx_coalesce_mode = priv->params.rx_cq_moderation_mode; 1366 priv->params_ethtool.rx_coalesce_usecs = priv->params.rx_cq_moderation_usec; 1367 priv->params_ethtool.rx_coalesce_pkts = priv->params.rx_cq_moderation_pkts; 1368 priv->params_ethtool.tx_coalesce_mode = priv->params.tx_cq_moderation_mode; 1369 priv->params_ethtool.tx_coalesce_usecs = priv->params.tx_cq_moderation_usec; 1370 priv->params_ethtool.tx_coalesce_pkts = priv->params.tx_cq_moderation_pkts; 1371 priv->params_ethtool.hw_lro = priv->params.hw_lro_en; 1372 priv->params_ethtool.cqe_zipping = priv->params.cqe_zipping_en; 1373 mlx5e_ethtool_sync_tx_completion_fact(priv); 1374 1375 /* get default values for local loopback, if any */ 1376 if (MLX5_CAP_GEN(priv->mdev, disable_local_lb)) { 1377 int err; 1378 u8 val; 1379 1380 err = mlx5_nic_vport_query_local_lb(priv->mdev, MLX5_LOCAL_MC_LB, &val); 1381 if (err == 0) 1382 priv->params_ethtool.mc_local_lb = val; 1383 1384 err = mlx5_nic_vport_query_local_lb(priv->mdev, MLX5_LOCAL_UC_LB, &val); 1385 if (err == 0) 1386 priv->params_ethtool.uc_local_lb = val; 1387 } 1388 1389 /* create root node */ 1390 node = SYSCTL_ADD_NODE(&priv->sysctl_ctx, 1391 SYSCTL_CHILDREN(priv->sysctl_ifnet), OID_AUTO, 1392 "conf", CTLFLAG_RW, NULL, "Configuration"); 1393 if (node == NULL) 1394 return; 1395 for (x = 0; x != MLX5E_PARAMS_NUM; x++) { 1396 /* check for read-only parameter */ 1397 if (strstr(mlx5e_params_desc[2 * x], "_max") != NULL || 1398 strstr(mlx5e_params_desc[2 * x], "_mtu") != NULL) { 1399 SYSCTL_ADD_PROC(&priv->sysctl_ctx, SYSCTL_CHILDREN(node), OID_AUTO, 1400 mlx5e_params_desc[2 * x], CTLTYPE_U64 | CTLFLAG_RD | 1401 CTLFLAG_MPSAFE, priv, x, &mlx5e_ethtool_handler, "QU", 1402 mlx5e_params_desc[2 * x + 1]); 1403 } else { 1404 #if (__FreeBSD_version < 1100000) 1405 char path[64]; 1406 #endif 1407 /* 1408 * NOTE: In FreeBSD-11 and newer the 1409 * CTLFLAG_RWTUN flag will take care of 1410 * loading default sysctl value from the 1411 * kernel environment, if any: 1412 */ 1413 SYSCTL_ADD_PROC(&priv->sysctl_ctx, SYSCTL_CHILDREN(node), OID_AUTO, 1414 mlx5e_params_desc[2 * x], CTLTYPE_U64 | CTLFLAG_RWTUN | 1415 CTLFLAG_MPSAFE, priv, x, &mlx5e_ethtool_handler, "QU", 1416 mlx5e_params_desc[2 * x + 1]); 1417 1418 #if (__FreeBSD_version < 1100000) 1419 /* compute path for sysctl */ 1420 snprintf(path, sizeof(path), "dev.mce.%d.conf.%s", 1421 device_get_unit(priv->mdev->pdev->dev.bsddev), 1422 mlx5e_params_desc[2 * x]); 1423 1424 /* try to fetch tunable, if any */ 1425 if (TUNABLE_QUAD_FETCH(path, &priv->params_ethtool.arg[x])) 1426 mlx5e_ethtool_handler(NULL, priv, x, NULL); 1427 #endif 1428 } 1429 } 1430 1431 /* create fec node */ 1432 fec_node = SYSCTL_ADD_NODE(&priv->sysctl_ctx, 1433 SYSCTL_CHILDREN(node), OID_AUTO, 1434 "fec", CTLFLAG_RW, NULL, "Forward Error Correction"); 1435 if (fec_node == NULL) 1436 return; 1437 1438 if (mlx5e_fec_update(priv) == 0) { 1439 SYSCTL_ADD_U32(&priv->sysctl_ctx, SYSCTL_CHILDREN(fec_node), OID_AUTO, 1440 "mode_active", CTLFLAG_RD | CTLFLAG_MPSAFE, 1441 &priv->params_ethtool.fec_mode_active, 0, 1442 "Current FEC mode bit, if any."); 1443 1444 SYSCTL_ADD_PROC(&priv->sysctl_ctx, SYSCTL_CHILDREN(fec_node), OID_AUTO, 1445 "mask_10x_25x", CTLTYPE_U8 | CTLFLAG_RWTUN | CTLFLAG_MPSAFE, 1446 priv, 0, &mlx5e_fec_mask_10x_25x_handler, "CU", 1447 "Set FEC masks for 10G_40G, 25G_50G, 56G, 100G respectivly. " 1448 "0:Auto " 1449 "1:NOFEC " 1450 "2:FIRECODE " 1451 "4:RS"); 1452 1453 SYSCTL_ADD_PROC(&priv->sysctl_ctx, SYSCTL_CHILDREN(fec_node), OID_AUTO, 1454 "avail_10x_25x", CTLTYPE_U8 | CTLFLAG_RD | CTLFLAG_MPSAFE, 1455 priv, 0, &mlx5e_fec_avail_10x_25x_handler, "CU", 1456 "Get available FEC bits for 10G_40G, 25G_50G, 56G, 100G respectivly. " 1457 "0:Auto " 1458 "1:NOFEC " 1459 "2:FIRECODE " 1460 "4:RS"); 1461 1462 SYSCTL_ADD_PROC(&priv->sysctl_ctx, SYSCTL_CHILDREN(fec_node), OID_AUTO, 1463 "mask_50x", CTLTYPE_U16 | CTLFLAG_RWTUN | CTLFLAG_MPSAFE, 1464 priv, 0, &mlx5e_fec_mask_50x_handler, "SU", 1465 "Set FEC masks for 50G 1x, 100G 2x, 200G 4x, 400G 8x respectivly. " 1466 "0:Auto " 1467 "128:RS " 1468 "512:LL RS"); 1469 1470 SYSCTL_ADD_PROC(&priv->sysctl_ctx, SYSCTL_CHILDREN(fec_node), OID_AUTO, 1471 "avail_50x", CTLTYPE_U16 | CTLFLAG_RD | CTLFLAG_MPSAFE, 1472 priv, 0, &mlx5e_fec_avail_50x_handler, "SU", 1473 "Get available FEC bits for 50G 1x, 100G 2x, 200G 4x, 400G 8x respectivly. " 1474 "0:Auto " 1475 "128:RS " 1476 "512:LL RS"); 1477 } 1478 1479 SYSCTL_ADD_PROC(&priv->sysctl_ctx, SYSCTL_CHILDREN(node), OID_AUTO, 1480 "debug_stats", CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, priv, 1481 0, &mlx5e_ethtool_debug_stats, "I", "Extended debug statistics"); 1482 1483 pnameunit = device_get_nameunit(priv->mdev->pdev->dev.bsddev); 1484 1485 SYSCTL_ADD_STRING(&priv->sysctl_ctx, SYSCTL_CHILDREN(node), 1486 OID_AUTO, "device_name", CTLFLAG_RD, 1487 __DECONST(void *, pnameunit), 0, 1488 "PCI device name"); 1489 1490 /* Diagnostics support */ 1491 mlx5e_create_diagnostics(priv); 1492 1493 /* create qos node */ 1494 qos_node = SYSCTL_ADD_NODE(&priv->sysctl_ctx, 1495 SYSCTL_CHILDREN(node), OID_AUTO, 1496 "qos", CTLFLAG_RW, NULL, "Quality Of Service configuration"); 1497 if (qos_node == NULL) 1498 return; 1499 1500 /* Priority rate limit support */ 1501 if (mlx5e_getmaxrate(priv) == 0) { 1502 SYSCTL_ADD_PROC(&priv->sysctl_ctx, SYSCTL_CHILDREN(qos_node), 1503 OID_AUTO, "tc_max_rate", CTLTYPE_U64 | CTLFLAG_RWTUN | CTLFLAG_MPSAFE, 1504 priv, 0, mlx5e_tc_maxrate_handler, "QU", 1505 "Max rate for priority, specified in kilobits, where kilo=1000, " 1506 "max_rate must be divisible by 100000"); 1507 } 1508 1509 /* Bandwidth limiting by ratio */ 1510 if (mlx5e_get_max_alloc(priv) == 0) { 1511 SYSCTL_ADD_PROC(&priv->sysctl_ctx, SYSCTL_CHILDREN(qos_node), 1512 OID_AUTO, "tc_rate_share", CTLTYPE_U8 | CTLFLAG_RWTUN | CTLFLAG_MPSAFE, 1513 priv, 0, mlx5e_tc_rate_share_handler, "QU", 1514 "Specify bandwidth ratio from 1 to 100 " 1515 "for the available traffic classes"); 1516 } 1517 1518 /* Priority to traffic class mapping */ 1519 if (mlx5e_get_prio_tc(priv) == 0) { 1520 SYSCTL_ADD_PROC(&priv->sysctl_ctx, SYSCTL_CHILDREN(qos_node), 1521 OID_AUTO, "prio_0_7_tc", CTLTYPE_U8 | CTLFLAG_RWTUN | CTLFLAG_MPSAFE, 1522 priv, 0, mlx5e_prio_to_tc_handler, "CU", 1523 "Set traffic class 0 to 7 for priority 0 to 7 inclusivly"); 1524 } 1525 1526 /* DSCP support */ 1527 if (mlx5e_get_dscp(priv) == 0) { 1528 for (i = 0; i != MLX5_MAX_SUPPORTED_DSCP; i += 8) { 1529 char name[32]; 1530 snprintf(name, sizeof(name), "dscp_%d_%d_prio", i, i + 7); 1531 SYSCTL_ADD_PROC(&priv->sysctl_ctx, SYSCTL_CHILDREN(qos_node), 1532 OID_AUTO, name, CTLTYPE_U8 | CTLFLAG_RWTUN | CTLFLAG_MPSAFE, 1533 priv, i, mlx5e_dscp_prio_handler, "CU", 1534 "Set DSCP to priority mapping, 0..7"); 1535 } 1536 #define A "Set trust state, 1:PCP 2:DSCP" 1537 #define B " 3:BOTH" 1538 SYSCTL_ADD_PROC(&priv->sysctl_ctx, SYSCTL_CHILDREN(qos_node), 1539 OID_AUTO, "trust_state", CTLTYPE_U8 | CTLFLAG_RWTUN | CTLFLAG_MPSAFE, 1540 priv, 0, mlx5e_trust_state_handler, "CU", 1541 MLX5_CAP_QCAM_FEATURE(priv->mdev, qpts_trust_both) ? 1542 A B : A); 1543 #undef B 1544 #undef A 1545 } 1546 1547 if (mlx5e_port_query_buffer(priv, &port_buffer) == 0) { 1548 SYSCTL_ADD_PROC(&priv->sysctl_ctx, SYSCTL_CHILDREN(qos_node), 1549 OID_AUTO, "buffers_size", 1550 CTLTYPE_U32 | CTLFLAG_RWTUN | CTLFLAG_MPSAFE, 1551 priv, 0, mlx5e_buf_size_handler, "IU", 1552 "Set buffers sizes"); 1553 SYSCTL_ADD_PROC(&priv->sysctl_ctx, SYSCTL_CHILDREN(qos_node), 1554 OID_AUTO, "buffers_prio", 1555 CTLTYPE_U8 | CTLFLAG_RWTUN | CTLFLAG_MPSAFE, 1556 priv, 0, mlx5e_buf_prio_handler, "CU", 1557 "Set prio to buffers mapping"); 1558 SYSCTL_ADD_PROC(&priv->sysctl_ctx, SYSCTL_CHILDREN(qos_node), 1559 OID_AUTO, "cable_length", 1560 CTLTYPE_UINT | CTLFLAG_RWTUN | CTLFLAG_MPSAFE, 1561 priv, 0, mlx5e_cable_length_handler, "IU", 1562 "Set cable length in meters for xoff threshold calculation"); 1563 } 1564 } 1565