1 /* Broadcom NetXtreme-C/E network driver. 2 * 3 * Copyright (c) 2017 Broadcom Limited 4 * 5 * This program is free software; you can redistribute it and/or modify 6 * it under the terms of the GNU General Public License as published by 7 * the Free Software Foundation. 8 */ 9 10 #include <linux/pci.h> 11 #include <linux/netdevice.h> 12 #include <net/devlink.h> 13 #include "bnxt_hsi.h" 14 #include "bnxt.h" 15 #include "bnxt_hwrm.h" 16 #include "bnxt_vfr.h" 17 #include "bnxt_devlink.h" 18 #include "bnxt_ethtool.h" 19 20 static int 21 bnxt_dl_flash_update(struct devlink *dl, 22 struct devlink_flash_update_params *params, 23 struct netlink_ext_ack *extack) 24 { 25 struct bnxt *bp = bnxt_get_bp_from_dl(dl); 26 int rc; 27 28 if (!BNXT_PF(bp)) { 29 NL_SET_ERR_MSG_MOD(extack, 30 "flash update not supported from a VF"); 31 return -EPERM; 32 } 33 34 devlink_flash_update_status_notify(dl, "Preparing to flash", NULL, 0, 0); 35 rc = bnxt_flash_package_from_fw_obj(bp->dev, params->fw, 0); 36 if (!rc) 37 devlink_flash_update_status_notify(dl, "Flashing done", NULL, 0, 0); 38 else 39 devlink_flash_update_status_notify(dl, "Flashing failed", NULL, 0, 0); 40 return rc; 41 } 42 43 static int bnxt_fw_reporter_diagnose(struct devlink_health_reporter *reporter, 44 struct devlink_fmsg *fmsg, 45 struct netlink_ext_ack *extack) 46 { 47 struct bnxt *bp = devlink_health_reporter_priv(reporter); 48 u32 val; 49 int rc; 50 51 if (test_bit(BNXT_STATE_IN_FW_RESET, &bp->state)) 52 return 0; 53 54 val = bnxt_fw_health_readl(bp, BNXT_FW_HEALTH_REG); 55 56 if (BNXT_FW_IS_BOOTING(val)) { 57 rc = devlink_fmsg_string_pair_put(fmsg, "Description", 58 "Not yet completed initialization"); 59 if (rc) 60 return rc; 61 } else if (BNXT_FW_IS_ERR(val)) { 62 rc = devlink_fmsg_string_pair_put(fmsg, "Description", 63 "Encountered fatal error and cannot recover"); 64 if (rc) 65 return rc; 66 } 67 68 if (val >> 16) { 69 rc = devlink_fmsg_u32_pair_put(fmsg, "Error code", val >> 16); 70 if (rc) 71 return rc; 72 } 73 74 val = bnxt_fw_health_readl(bp, BNXT_FW_RESET_CNT_REG); 75 rc = devlink_fmsg_u32_pair_put(fmsg, "Reset count", val); 76 if (rc) 77 return rc; 78 79 return 0; 80 } 81 82 static const struct devlink_health_reporter_ops bnxt_dl_fw_reporter_ops = { 83 .name = "fw", 84 .diagnose = bnxt_fw_reporter_diagnose, 85 }; 86 87 static int bnxt_fw_reset_recover(struct devlink_health_reporter *reporter, 88 void *priv_ctx, 89 struct netlink_ext_ack *extack) 90 { 91 struct bnxt *bp = devlink_health_reporter_priv(reporter); 92 93 if (!priv_ctx) 94 return -EOPNOTSUPP; 95 96 bnxt_fw_reset(bp); 97 return -EINPROGRESS; 98 } 99 100 static const 101 struct devlink_health_reporter_ops bnxt_dl_fw_reset_reporter_ops = { 102 .name = "fw_reset", 103 .recover = bnxt_fw_reset_recover, 104 }; 105 106 static int bnxt_fw_fatal_recover(struct devlink_health_reporter *reporter, 107 void *priv_ctx, 108 struct netlink_ext_ack *extack) 109 { 110 struct bnxt *bp = devlink_health_reporter_priv(reporter); 111 struct bnxt_fw_reporter_ctx *fw_reporter_ctx = priv_ctx; 112 unsigned long event; 113 114 if (!priv_ctx) 115 return -EOPNOTSUPP; 116 117 bp->fw_health->fatal = true; 118 event = fw_reporter_ctx->sp_event; 119 if (event == BNXT_FW_RESET_NOTIFY_SP_EVENT) 120 bnxt_fw_reset(bp); 121 else if (event == BNXT_FW_EXCEPTION_SP_EVENT) 122 bnxt_fw_exception(bp); 123 124 return -EINPROGRESS; 125 } 126 127 static const 128 struct devlink_health_reporter_ops bnxt_dl_fw_fatal_reporter_ops = { 129 .name = "fw_fatal", 130 .recover = bnxt_fw_fatal_recover, 131 }; 132 133 void bnxt_dl_fw_reporters_create(struct bnxt *bp) 134 { 135 struct bnxt_fw_health *health = bp->fw_health; 136 137 if (!bp->dl || !health) 138 return; 139 140 if (!(bp->fw_cap & BNXT_FW_CAP_HOT_RESET) || health->fw_reset_reporter) 141 goto err_recovery; 142 143 health->fw_reset_reporter = 144 devlink_health_reporter_create(bp->dl, 145 &bnxt_dl_fw_reset_reporter_ops, 146 0, bp); 147 if (IS_ERR(health->fw_reset_reporter)) { 148 netdev_warn(bp->dev, "Failed to create FW fatal health reporter, rc = %ld\n", 149 PTR_ERR(health->fw_reset_reporter)); 150 health->fw_reset_reporter = NULL; 151 bp->fw_cap &= ~BNXT_FW_CAP_HOT_RESET; 152 } 153 154 err_recovery: 155 if (!(bp->fw_cap & BNXT_FW_CAP_ERROR_RECOVERY)) 156 return; 157 158 if (!health->fw_reporter) { 159 health->fw_reporter = 160 devlink_health_reporter_create(bp->dl, 161 &bnxt_dl_fw_reporter_ops, 162 0, bp); 163 if (IS_ERR(health->fw_reporter)) { 164 netdev_warn(bp->dev, "Failed to create FW health reporter, rc = %ld\n", 165 PTR_ERR(health->fw_reporter)); 166 health->fw_reporter = NULL; 167 bp->fw_cap &= ~BNXT_FW_CAP_ERROR_RECOVERY; 168 return; 169 } 170 } 171 172 if (health->fw_fatal_reporter) 173 return; 174 175 health->fw_fatal_reporter = 176 devlink_health_reporter_create(bp->dl, 177 &bnxt_dl_fw_fatal_reporter_ops, 178 0, bp); 179 if (IS_ERR(health->fw_fatal_reporter)) { 180 netdev_warn(bp->dev, "Failed to create FW fatal health reporter, rc = %ld\n", 181 PTR_ERR(health->fw_fatal_reporter)); 182 health->fw_fatal_reporter = NULL; 183 bp->fw_cap &= ~BNXT_FW_CAP_ERROR_RECOVERY; 184 } 185 } 186 187 void bnxt_dl_fw_reporters_destroy(struct bnxt *bp, bool all) 188 { 189 struct bnxt_fw_health *health = bp->fw_health; 190 191 if (!bp->dl || !health) 192 return; 193 194 if ((all || !(bp->fw_cap & BNXT_FW_CAP_HOT_RESET)) && 195 health->fw_reset_reporter) { 196 devlink_health_reporter_destroy(health->fw_reset_reporter); 197 health->fw_reset_reporter = NULL; 198 } 199 200 if ((bp->fw_cap & BNXT_FW_CAP_ERROR_RECOVERY) && !all) 201 return; 202 203 if (health->fw_reporter) { 204 devlink_health_reporter_destroy(health->fw_reporter); 205 health->fw_reporter = NULL; 206 } 207 208 if (health->fw_fatal_reporter) { 209 devlink_health_reporter_destroy(health->fw_fatal_reporter); 210 health->fw_fatal_reporter = NULL; 211 } 212 } 213 214 void bnxt_devlink_health_report(struct bnxt *bp, unsigned long event) 215 { 216 struct bnxt_fw_health *fw_health = bp->fw_health; 217 struct bnxt_fw_reporter_ctx fw_reporter_ctx; 218 219 fw_reporter_ctx.sp_event = event; 220 switch (event) { 221 case BNXT_FW_RESET_NOTIFY_SP_EVENT: 222 if (test_bit(BNXT_STATE_FW_FATAL_COND, &bp->state)) { 223 if (!fw_health->fw_fatal_reporter) 224 return; 225 226 devlink_health_report(fw_health->fw_fatal_reporter, 227 "FW fatal async event received", 228 &fw_reporter_ctx); 229 return; 230 } 231 if (!fw_health->fw_reset_reporter) 232 return; 233 234 devlink_health_report(fw_health->fw_reset_reporter, 235 "FW non-fatal reset event received", 236 &fw_reporter_ctx); 237 return; 238 239 case BNXT_FW_EXCEPTION_SP_EVENT: 240 if (!fw_health->fw_fatal_reporter) 241 return; 242 243 devlink_health_report(fw_health->fw_fatal_reporter, 244 "FW fatal error reported", 245 &fw_reporter_ctx); 246 return; 247 } 248 } 249 250 void bnxt_dl_health_status_update(struct bnxt *bp, bool healthy) 251 { 252 struct bnxt_fw_health *health = bp->fw_health; 253 u8 state; 254 255 if (healthy) 256 state = DEVLINK_HEALTH_REPORTER_STATE_HEALTHY; 257 else 258 state = DEVLINK_HEALTH_REPORTER_STATE_ERROR; 259 260 if (health->fatal) 261 devlink_health_reporter_state_update(health->fw_fatal_reporter, 262 state); 263 else 264 devlink_health_reporter_state_update(health->fw_reset_reporter, 265 state); 266 267 health->fatal = false; 268 } 269 270 void bnxt_dl_health_recovery_done(struct bnxt *bp) 271 { 272 struct bnxt_fw_health *hlth = bp->fw_health; 273 274 if (hlth->fatal) 275 devlink_health_reporter_recovery_done(hlth->fw_fatal_reporter); 276 else 277 devlink_health_reporter_recovery_done(hlth->fw_reset_reporter); 278 } 279 280 static int bnxt_dl_info_get(struct devlink *dl, struct devlink_info_req *req, 281 struct netlink_ext_ack *extack); 282 283 static const struct devlink_ops bnxt_dl_ops = { 284 #ifdef CONFIG_BNXT_SRIOV 285 .eswitch_mode_set = bnxt_dl_eswitch_mode_set, 286 .eswitch_mode_get = bnxt_dl_eswitch_mode_get, 287 #endif /* CONFIG_BNXT_SRIOV */ 288 .info_get = bnxt_dl_info_get, 289 .flash_update = bnxt_dl_flash_update, 290 }; 291 292 static const struct devlink_ops bnxt_vf_dl_ops; 293 294 enum bnxt_dl_param_id { 295 BNXT_DEVLINK_PARAM_ID_BASE = DEVLINK_PARAM_GENERIC_ID_MAX, 296 BNXT_DEVLINK_PARAM_ID_GRE_VER_CHECK, 297 }; 298 299 static const struct bnxt_dl_nvm_param nvm_params[] = { 300 {DEVLINK_PARAM_GENERIC_ID_ENABLE_SRIOV, NVM_OFF_ENABLE_SRIOV, 301 BNXT_NVM_SHARED_CFG, 1, 1}, 302 {DEVLINK_PARAM_GENERIC_ID_IGNORE_ARI, NVM_OFF_IGNORE_ARI, 303 BNXT_NVM_SHARED_CFG, 1, 1}, 304 {DEVLINK_PARAM_GENERIC_ID_MSIX_VEC_PER_PF_MAX, 305 NVM_OFF_MSIX_VEC_PER_PF_MAX, BNXT_NVM_SHARED_CFG, 10, 4}, 306 {DEVLINK_PARAM_GENERIC_ID_MSIX_VEC_PER_PF_MIN, 307 NVM_OFF_MSIX_VEC_PER_PF_MIN, BNXT_NVM_SHARED_CFG, 7, 4}, 308 {BNXT_DEVLINK_PARAM_ID_GRE_VER_CHECK, NVM_OFF_DIS_GRE_VER_CHECK, 309 BNXT_NVM_SHARED_CFG, 1, 1}, 310 }; 311 312 union bnxt_nvm_data { 313 u8 val8; 314 __le32 val32; 315 }; 316 317 static void bnxt_copy_to_nvm_data(union bnxt_nvm_data *dst, 318 union devlink_param_value *src, 319 int nvm_num_bits, int dl_num_bytes) 320 { 321 u32 val32 = 0; 322 323 if (nvm_num_bits == 1) { 324 dst->val8 = src->vbool; 325 return; 326 } 327 if (dl_num_bytes == 4) 328 val32 = src->vu32; 329 else if (dl_num_bytes == 2) 330 val32 = (u32)src->vu16; 331 else if (dl_num_bytes == 1) 332 val32 = (u32)src->vu8; 333 dst->val32 = cpu_to_le32(val32); 334 } 335 336 static void bnxt_copy_from_nvm_data(union devlink_param_value *dst, 337 union bnxt_nvm_data *src, 338 int nvm_num_bits, int dl_num_bytes) 339 { 340 u32 val32; 341 342 if (nvm_num_bits == 1) { 343 dst->vbool = src->val8; 344 return; 345 } 346 val32 = le32_to_cpu(src->val32); 347 if (dl_num_bytes == 4) 348 dst->vu32 = val32; 349 else if (dl_num_bytes == 2) 350 dst->vu16 = (u16)val32; 351 else if (dl_num_bytes == 1) 352 dst->vu8 = (u8)val32; 353 } 354 355 static int bnxt_hwrm_get_nvm_cfg_ver(struct bnxt *bp, u32 *nvm_cfg_ver) 356 { 357 struct hwrm_nvm_get_variable_input *req; 358 u16 bytes = BNXT_NVM_CFG_VER_BYTES; 359 u16 bits = BNXT_NVM_CFG_VER_BITS; 360 union devlink_param_value ver; 361 union bnxt_nvm_data *data; 362 dma_addr_t data_dma_addr; 363 int rc, i = 2; 364 u16 dim = 1; 365 366 rc = hwrm_req_init(bp, req, HWRM_NVM_GET_VARIABLE); 367 if (rc) 368 return rc; 369 370 data = hwrm_req_dma_slice(bp, req, sizeof(*data), &data_dma_addr); 371 if (!data) { 372 rc = -ENOMEM; 373 goto exit; 374 } 375 376 /* earlier devices present as an array of raw bytes */ 377 if (!BNXT_CHIP_P5(bp)) { 378 dim = 0; 379 i = 0; 380 bits *= 3; /* array of 3 version components */ 381 bytes *= 4; /* copy whole word */ 382 } 383 384 hwrm_req_hold(bp, req); 385 req->dest_data_addr = cpu_to_le64(data_dma_addr); 386 req->data_len = cpu_to_le16(bits); 387 req->option_num = cpu_to_le16(NVM_OFF_NVM_CFG_VER); 388 req->dimensions = cpu_to_le16(dim); 389 390 while (i >= 0) { 391 req->index_0 = cpu_to_le16(i--); 392 rc = hwrm_req_send_silent(bp, req); 393 if (rc) 394 goto exit; 395 bnxt_copy_from_nvm_data(&ver, data, bits, bytes); 396 397 if (BNXT_CHIP_P5(bp)) { 398 *nvm_cfg_ver <<= 8; 399 *nvm_cfg_ver |= ver.vu8; 400 } else { 401 *nvm_cfg_ver = ver.vu32; 402 } 403 } 404 405 exit: 406 hwrm_req_drop(bp, req); 407 return rc; 408 } 409 410 static int bnxt_dl_info_put(struct bnxt *bp, struct devlink_info_req *req, 411 enum bnxt_dl_version_type type, const char *key, 412 char *buf) 413 { 414 if (!strlen(buf)) 415 return 0; 416 417 if ((bp->flags & BNXT_FLAG_CHIP_P5) && 418 (!strcmp(key, DEVLINK_INFO_VERSION_GENERIC_FW_NCSI) || 419 !strcmp(key, DEVLINK_INFO_VERSION_GENERIC_FW_ROCE))) 420 return 0; 421 422 switch (type) { 423 case BNXT_VERSION_FIXED: 424 return devlink_info_version_fixed_put(req, key, buf); 425 case BNXT_VERSION_RUNNING: 426 return devlink_info_version_running_put(req, key, buf); 427 case BNXT_VERSION_STORED: 428 return devlink_info_version_stored_put(req, key, buf); 429 } 430 return 0; 431 } 432 433 #define HWRM_FW_VER_STR_LEN 16 434 435 static int bnxt_dl_info_get(struct devlink *dl, struct devlink_info_req *req, 436 struct netlink_ext_ack *extack) 437 { 438 struct hwrm_nvm_get_dev_info_output nvm_dev_info; 439 struct bnxt *bp = bnxt_get_bp_from_dl(dl); 440 struct hwrm_ver_get_output *ver_resp; 441 char mgmt_ver[FW_VER_STR_LEN]; 442 char roce_ver[FW_VER_STR_LEN]; 443 char ncsi_ver[FW_VER_STR_LEN]; 444 char buf[32]; 445 u32 ver = 0; 446 int rc; 447 448 rc = devlink_info_driver_name_put(req, DRV_MODULE_NAME); 449 if (rc) 450 return rc; 451 452 if (BNXT_PF(bp) && (bp->flags & BNXT_FLAG_DSN_VALID)) { 453 sprintf(buf, "%02X-%02X-%02X-%02X-%02X-%02X-%02X-%02X", 454 bp->dsn[7], bp->dsn[6], bp->dsn[5], bp->dsn[4], 455 bp->dsn[3], bp->dsn[2], bp->dsn[1], bp->dsn[0]); 456 rc = devlink_info_serial_number_put(req, buf); 457 if (rc) 458 return rc; 459 } 460 461 if (strlen(bp->board_serialno)) { 462 rc = devlink_info_board_serial_number_put(req, bp->board_serialno); 463 if (rc) 464 return rc; 465 } 466 467 rc = bnxt_dl_info_put(bp, req, BNXT_VERSION_FIXED, 468 DEVLINK_INFO_VERSION_GENERIC_BOARD_ID, 469 bp->board_partno); 470 if (rc) 471 return rc; 472 473 sprintf(buf, "%X", bp->chip_num); 474 rc = bnxt_dl_info_put(bp, req, BNXT_VERSION_FIXED, 475 DEVLINK_INFO_VERSION_GENERIC_ASIC_ID, buf); 476 if (rc) 477 return rc; 478 479 ver_resp = &bp->ver_resp; 480 sprintf(buf, "%c%d", 'A' + ver_resp->chip_rev, ver_resp->chip_metal); 481 rc = bnxt_dl_info_put(bp, req, BNXT_VERSION_FIXED, 482 DEVLINK_INFO_VERSION_GENERIC_ASIC_REV, buf); 483 if (rc) 484 return rc; 485 486 rc = bnxt_dl_info_put(bp, req, BNXT_VERSION_RUNNING, 487 DEVLINK_INFO_VERSION_GENERIC_FW_PSID, 488 bp->nvm_cfg_ver); 489 if (rc) 490 return rc; 491 492 buf[0] = 0; 493 strncat(buf, ver_resp->active_pkg_name, HWRM_FW_VER_STR_LEN); 494 rc = bnxt_dl_info_put(bp, req, BNXT_VERSION_RUNNING, 495 DEVLINK_INFO_VERSION_GENERIC_FW, buf); 496 if (rc) 497 return rc; 498 499 if (BNXT_PF(bp) && !bnxt_hwrm_get_nvm_cfg_ver(bp, &ver)) { 500 sprintf(buf, "%d.%d.%d", (ver >> 16) & 0xff, (ver >> 8) & 0xff, 501 ver & 0xff); 502 rc = bnxt_dl_info_put(bp, req, BNXT_VERSION_STORED, 503 DEVLINK_INFO_VERSION_GENERIC_FW_PSID, 504 buf); 505 if (rc) 506 return rc; 507 } 508 509 if (ver_resp->flags & VER_GET_RESP_FLAGS_EXT_VER_AVAIL) { 510 snprintf(mgmt_ver, FW_VER_STR_LEN, "%d.%d.%d.%d", 511 ver_resp->hwrm_fw_major, ver_resp->hwrm_fw_minor, 512 ver_resp->hwrm_fw_build, ver_resp->hwrm_fw_patch); 513 514 snprintf(ncsi_ver, FW_VER_STR_LEN, "%d.%d.%d.%d", 515 ver_resp->mgmt_fw_major, ver_resp->mgmt_fw_minor, 516 ver_resp->mgmt_fw_build, ver_resp->mgmt_fw_patch); 517 518 snprintf(roce_ver, FW_VER_STR_LEN, "%d.%d.%d.%d", 519 ver_resp->roce_fw_major, ver_resp->roce_fw_minor, 520 ver_resp->roce_fw_build, ver_resp->roce_fw_patch); 521 } else { 522 snprintf(mgmt_ver, FW_VER_STR_LEN, "%d.%d.%d.%d", 523 ver_resp->hwrm_fw_maj_8b, ver_resp->hwrm_fw_min_8b, 524 ver_resp->hwrm_fw_bld_8b, ver_resp->hwrm_fw_rsvd_8b); 525 526 snprintf(ncsi_ver, FW_VER_STR_LEN, "%d.%d.%d.%d", 527 ver_resp->mgmt_fw_maj_8b, ver_resp->mgmt_fw_min_8b, 528 ver_resp->mgmt_fw_bld_8b, ver_resp->mgmt_fw_rsvd_8b); 529 530 snprintf(roce_ver, FW_VER_STR_LEN, "%d.%d.%d.%d", 531 ver_resp->roce_fw_maj_8b, ver_resp->roce_fw_min_8b, 532 ver_resp->roce_fw_bld_8b, ver_resp->roce_fw_rsvd_8b); 533 } 534 rc = bnxt_dl_info_put(bp, req, BNXT_VERSION_RUNNING, 535 DEVLINK_INFO_VERSION_GENERIC_FW_MGMT, mgmt_ver); 536 if (rc) 537 return rc; 538 539 rc = bnxt_dl_info_put(bp, req, BNXT_VERSION_RUNNING, 540 DEVLINK_INFO_VERSION_GENERIC_FW_MGMT_API, 541 bp->hwrm_ver_supp); 542 if (rc) 543 return rc; 544 545 rc = bnxt_dl_info_put(bp, req, BNXT_VERSION_RUNNING, 546 DEVLINK_INFO_VERSION_GENERIC_FW_NCSI, ncsi_ver); 547 if (rc) 548 return rc; 549 550 rc = bnxt_dl_info_put(bp, req, BNXT_VERSION_RUNNING, 551 DEVLINK_INFO_VERSION_GENERIC_FW_ROCE, roce_ver); 552 if (rc) 553 return rc; 554 555 rc = bnxt_hwrm_nvm_get_dev_info(bp, &nvm_dev_info); 556 if (rc || 557 !(nvm_dev_info.flags & NVM_GET_DEV_INFO_RESP_FLAGS_FW_VER_VALID)) 558 return 0; 559 560 buf[0] = 0; 561 strncat(buf, nvm_dev_info.pkg_name, HWRM_FW_VER_STR_LEN); 562 rc = bnxt_dl_info_put(bp, req, BNXT_VERSION_STORED, 563 DEVLINK_INFO_VERSION_GENERIC_FW, buf); 564 if (rc) 565 return rc; 566 567 snprintf(mgmt_ver, FW_VER_STR_LEN, "%d.%d.%d.%d", 568 nvm_dev_info.hwrm_fw_major, nvm_dev_info.hwrm_fw_minor, 569 nvm_dev_info.hwrm_fw_build, nvm_dev_info.hwrm_fw_patch); 570 rc = bnxt_dl_info_put(bp, req, BNXT_VERSION_STORED, 571 DEVLINK_INFO_VERSION_GENERIC_FW_MGMT, mgmt_ver); 572 if (rc) 573 return rc; 574 575 snprintf(ncsi_ver, FW_VER_STR_LEN, "%d.%d.%d.%d", 576 nvm_dev_info.mgmt_fw_major, nvm_dev_info.mgmt_fw_minor, 577 nvm_dev_info.mgmt_fw_build, nvm_dev_info.mgmt_fw_patch); 578 rc = bnxt_dl_info_put(bp, req, BNXT_VERSION_STORED, 579 DEVLINK_INFO_VERSION_GENERIC_FW_NCSI, ncsi_ver); 580 if (rc) 581 return rc; 582 583 snprintf(roce_ver, FW_VER_STR_LEN, "%d.%d.%d.%d", 584 nvm_dev_info.roce_fw_major, nvm_dev_info.roce_fw_minor, 585 nvm_dev_info.roce_fw_build, nvm_dev_info.roce_fw_patch); 586 return bnxt_dl_info_put(bp, req, BNXT_VERSION_STORED, 587 DEVLINK_INFO_VERSION_GENERIC_FW_ROCE, roce_ver); 588 } 589 590 static int bnxt_hwrm_nvm_req(struct bnxt *bp, u32 param_id, void *msg, 591 union devlink_param_value *val) 592 { 593 struct hwrm_nvm_get_variable_input *req = msg; 594 struct bnxt_dl_nvm_param nvm_param; 595 struct hwrm_err_output *resp; 596 union bnxt_nvm_data *data; 597 dma_addr_t data_dma_addr; 598 int idx = 0, rc, i; 599 600 /* Get/Set NVM CFG parameter is supported only on PFs */ 601 if (BNXT_VF(bp)) { 602 hwrm_req_drop(bp, req); 603 return -EPERM; 604 } 605 606 for (i = 0; i < ARRAY_SIZE(nvm_params); i++) { 607 if (nvm_params[i].id == param_id) { 608 nvm_param = nvm_params[i]; 609 break; 610 } 611 } 612 613 if (i == ARRAY_SIZE(nvm_params)) { 614 hwrm_req_drop(bp, req); 615 return -EOPNOTSUPP; 616 } 617 618 if (nvm_param.dir_type == BNXT_NVM_PORT_CFG) 619 idx = bp->pf.port_id; 620 else if (nvm_param.dir_type == BNXT_NVM_FUNC_CFG) 621 idx = bp->pf.fw_fid - BNXT_FIRST_PF_FID; 622 623 data = hwrm_req_dma_slice(bp, req, sizeof(*data), &data_dma_addr); 624 625 if (!data) { 626 hwrm_req_drop(bp, req); 627 return -ENOMEM; 628 } 629 630 req->dest_data_addr = cpu_to_le64(data_dma_addr); 631 req->data_len = cpu_to_le16(nvm_param.nvm_num_bits); 632 req->option_num = cpu_to_le16(nvm_param.offset); 633 req->index_0 = cpu_to_le16(idx); 634 if (idx) 635 req->dimensions = cpu_to_le16(1); 636 637 resp = hwrm_req_hold(bp, req); 638 if (req->req_type == cpu_to_le16(HWRM_NVM_SET_VARIABLE)) { 639 bnxt_copy_to_nvm_data(data, val, nvm_param.nvm_num_bits, 640 nvm_param.dl_num_bytes); 641 rc = hwrm_req_send(bp, msg); 642 } else { 643 rc = hwrm_req_send_silent(bp, msg); 644 if (!rc) { 645 bnxt_copy_from_nvm_data(val, data, 646 nvm_param.nvm_num_bits, 647 nvm_param.dl_num_bytes); 648 } else { 649 if (resp->cmd_err == 650 NVM_GET_VARIABLE_CMD_ERR_CODE_VAR_NOT_EXIST) 651 rc = -EOPNOTSUPP; 652 } 653 } 654 hwrm_req_drop(bp, req); 655 if (rc == -EACCES) 656 netdev_err(bp->dev, "PF does not have admin privileges to modify NVM config\n"); 657 return rc; 658 } 659 660 static int bnxt_dl_nvm_param_get(struct devlink *dl, u32 id, 661 struct devlink_param_gset_ctx *ctx) 662 { 663 struct bnxt *bp = bnxt_get_bp_from_dl(dl); 664 struct hwrm_nvm_get_variable_input *req; 665 int rc; 666 667 rc = hwrm_req_init(bp, req, HWRM_NVM_GET_VARIABLE); 668 if (rc) 669 return rc; 670 671 rc = bnxt_hwrm_nvm_req(bp, id, req, &ctx->val); 672 if (!rc && id == BNXT_DEVLINK_PARAM_ID_GRE_VER_CHECK) 673 ctx->val.vbool = !ctx->val.vbool; 674 675 return rc; 676 } 677 678 static int bnxt_dl_nvm_param_set(struct devlink *dl, u32 id, 679 struct devlink_param_gset_ctx *ctx) 680 { 681 struct bnxt *bp = bnxt_get_bp_from_dl(dl); 682 struct hwrm_nvm_set_variable_input *req; 683 int rc; 684 685 rc = hwrm_req_init(bp, req, HWRM_NVM_SET_VARIABLE); 686 if (rc) 687 return rc; 688 689 if (id == BNXT_DEVLINK_PARAM_ID_GRE_VER_CHECK) 690 ctx->val.vbool = !ctx->val.vbool; 691 692 return bnxt_hwrm_nvm_req(bp, id, req, &ctx->val); 693 } 694 695 static int bnxt_dl_msix_validate(struct devlink *dl, u32 id, 696 union devlink_param_value val, 697 struct netlink_ext_ack *extack) 698 { 699 int max_val = -1; 700 701 if (id == DEVLINK_PARAM_GENERIC_ID_MSIX_VEC_PER_PF_MAX) 702 max_val = BNXT_MSIX_VEC_MAX; 703 704 if (id == DEVLINK_PARAM_GENERIC_ID_MSIX_VEC_PER_PF_MIN) 705 max_val = BNXT_MSIX_VEC_MIN_MAX; 706 707 if (val.vu32 > max_val) { 708 NL_SET_ERR_MSG_MOD(extack, "MSIX value is exceeding the range"); 709 return -EINVAL; 710 } 711 712 return 0; 713 } 714 715 static const struct devlink_param bnxt_dl_params[] = { 716 DEVLINK_PARAM_GENERIC(ENABLE_SRIOV, 717 BIT(DEVLINK_PARAM_CMODE_PERMANENT), 718 bnxt_dl_nvm_param_get, bnxt_dl_nvm_param_set, 719 NULL), 720 DEVLINK_PARAM_GENERIC(IGNORE_ARI, 721 BIT(DEVLINK_PARAM_CMODE_PERMANENT), 722 bnxt_dl_nvm_param_get, bnxt_dl_nvm_param_set, 723 NULL), 724 DEVLINK_PARAM_GENERIC(MSIX_VEC_PER_PF_MAX, 725 BIT(DEVLINK_PARAM_CMODE_PERMANENT), 726 bnxt_dl_nvm_param_get, bnxt_dl_nvm_param_set, 727 bnxt_dl_msix_validate), 728 DEVLINK_PARAM_GENERIC(MSIX_VEC_PER_PF_MIN, 729 BIT(DEVLINK_PARAM_CMODE_PERMANENT), 730 bnxt_dl_nvm_param_get, bnxt_dl_nvm_param_set, 731 bnxt_dl_msix_validate), 732 DEVLINK_PARAM_DRIVER(BNXT_DEVLINK_PARAM_ID_GRE_VER_CHECK, 733 "gre_ver_check", DEVLINK_PARAM_TYPE_BOOL, 734 BIT(DEVLINK_PARAM_CMODE_PERMANENT), 735 bnxt_dl_nvm_param_get, bnxt_dl_nvm_param_set, 736 NULL), 737 }; 738 739 static const struct devlink_param bnxt_dl_port_params[] = { 740 }; 741 742 static int bnxt_dl_params_register(struct bnxt *bp) 743 { 744 int rc; 745 746 if (bp->hwrm_spec_code < 0x10600) 747 return 0; 748 749 rc = devlink_params_register(bp->dl, bnxt_dl_params, 750 ARRAY_SIZE(bnxt_dl_params)); 751 if (rc) { 752 netdev_warn(bp->dev, "devlink_params_register failed. rc=%d\n", 753 rc); 754 return rc; 755 } 756 rc = devlink_port_params_register(&bp->dl_port, bnxt_dl_port_params, 757 ARRAY_SIZE(bnxt_dl_port_params)); 758 if (rc) { 759 netdev_err(bp->dev, "devlink_port_params_register failed\n"); 760 devlink_params_unregister(bp->dl, bnxt_dl_params, 761 ARRAY_SIZE(bnxt_dl_params)); 762 return rc; 763 } 764 devlink_params_publish(bp->dl); 765 766 return 0; 767 } 768 769 static void bnxt_dl_params_unregister(struct bnxt *bp) 770 { 771 if (bp->hwrm_spec_code < 0x10600) 772 return; 773 774 devlink_params_unregister(bp->dl, bnxt_dl_params, 775 ARRAY_SIZE(bnxt_dl_params)); 776 devlink_port_params_unregister(&bp->dl_port, bnxt_dl_port_params, 777 ARRAY_SIZE(bnxt_dl_port_params)); 778 } 779 780 int bnxt_dl_register(struct bnxt *bp) 781 { 782 const struct devlink_ops *devlink_ops; 783 struct devlink_port_attrs attrs = {}; 784 struct devlink *dl; 785 int rc; 786 787 if (BNXT_PF(bp)) 788 devlink_ops = &bnxt_dl_ops; 789 else 790 devlink_ops = &bnxt_vf_dl_ops; 791 792 dl = devlink_alloc(devlink_ops, sizeof(struct bnxt_dl), &bp->pdev->dev); 793 if (!dl) { 794 netdev_warn(bp->dev, "devlink_alloc failed\n"); 795 return -ENOMEM; 796 } 797 798 bnxt_link_bp_to_dl(bp, dl); 799 800 /* Add switchdev eswitch mode setting, if SRIOV supported */ 801 if (pci_find_ext_capability(bp->pdev, PCI_EXT_CAP_ID_SRIOV) && 802 bp->hwrm_spec_code > 0x10803) 803 bp->eswitch_mode = DEVLINK_ESWITCH_MODE_LEGACY; 804 805 rc = devlink_register(dl); 806 if (rc) { 807 netdev_warn(bp->dev, "devlink_register failed. rc=%d\n", rc); 808 goto err_dl_free; 809 } 810 811 if (!BNXT_PF(bp)) 812 return 0; 813 814 attrs.flavour = DEVLINK_PORT_FLAVOUR_PHYSICAL; 815 attrs.phys.port_number = bp->pf.port_id; 816 memcpy(attrs.switch_id.id, bp->dsn, sizeof(bp->dsn)); 817 attrs.switch_id.id_len = sizeof(bp->dsn); 818 devlink_port_attrs_set(&bp->dl_port, &attrs); 819 rc = devlink_port_register(dl, &bp->dl_port, bp->pf.port_id); 820 if (rc) { 821 netdev_err(bp->dev, "devlink_port_register failed\n"); 822 goto err_dl_unreg; 823 } 824 825 rc = bnxt_dl_params_register(bp); 826 if (rc) 827 goto err_dl_port_unreg; 828 829 return 0; 830 831 err_dl_port_unreg: 832 devlink_port_unregister(&bp->dl_port); 833 err_dl_unreg: 834 devlink_unregister(dl); 835 err_dl_free: 836 bnxt_link_bp_to_dl(bp, NULL); 837 devlink_free(dl); 838 return rc; 839 } 840 841 void bnxt_dl_unregister(struct bnxt *bp) 842 { 843 struct devlink *dl = bp->dl; 844 845 if (!dl) 846 return; 847 848 if (BNXT_PF(bp)) { 849 bnxt_dl_params_unregister(bp); 850 devlink_port_unregister(&bp->dl_port); 851 } 852 devlink_unregister(dl); 853 devlink_free(dl); 854 } 855