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