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