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 if (strlen(bp->board_serialno)) { 415 rc = devlink_info_board_serial_number_put(req, bp->board_serialno); 416 if (rc) 417 return rc; 418 } 419 420 sprintf(buf, "%X", bp->chip_num); 421 rc = devlink_info_version_fixed_put(req, 422 DEVLINK_INFO_VERSION_GENERIC_ASIC_ID, buf); 423 if (rc) 424 return rc; 425 426 ver_resp = &bp->ver_resp; 427 sprintf(buf, "%X", ver_resp->chip_rev); 428 rc = devlink_info_version_fixed_put(req, 429 DEVLINK_INFO_VERSION_GENERIC_ASIC_REV, buf); 430 if (rc) 431 return rc; 432 433 if (BNXT_PF(bp)) { 434 sprintf(buf, "%02X-%02X-%02X-%02X-%02X-%02X-%02X-%02X", 435 bp->dsn[7], bp->dsn[6], bp->dsn[5], bp->dsn[4], 436 bp->dsn[3], bp->dsn[2], bp->dsn[1], bp->dsn[0]); 437 rc = devlink_info_serial_number_put(req, buf); 438 if (rc) 439 return rc; 440 } 441 442 if (strlen(ver_resp->active_pkg_name)) { 443 rc = 444 devlink_info_version_running_put(req, 445 DEVLINK_INFO_VERSION_GENERIC_FW, 446 ver_resp->active_pkg_name); 447 if (rc) 448 return rc; 449 } 450 451 if (BNXT_PF(bp) && !bnxt_hwrm_get_nvm_cfg_ver(bp, &nvm_cfg_ver)) { 452 u32 ver = nvm_cfg_ver.vu32; 453 454 sprintf(buf, "%X.%X.%X", (ver >> 16) & 0xF, (ver >> 8) & 0xF, 455 ver & 0xF); 456 rc = devlink_info_version_running_put(req, 457 DEVLINK_INFO_VERSION_GENERIC_FW_PSID, buf); 458 if (rc) 459 return rc; 460 } 461 462 if (ver_resp->flags & VER_GET_RESP_FLAGS_EXT_VER_AVAIL) { 463 snprintf(fw_ver, FW_VER_STR_LEN, "%d.%d.%d.%d", 464 ver_resp->hwrm_fw_major, ver_resp->hwrm_fw_minor, 465 ver_resp->hwrm_fw_build, ver_resp->hwrm_fw_patch); 466 467 snprintf(mgmt_ver, FW_VER_STR_LEN, "%d.%d.%d.%d", 468 ver_resp->mgmt_fw_major, ver_resp->mgmt_fw_minor, 469 ver_resp->mgmt_fw_build, ver_resp->mgmt_fw_patch); 470 471 snprintf(roce_ver, FW_VER_STR_LEN, "%d.%d.%d.%d", 472 ver_resp->roce_fw_major, ver_resp->roce_fw_minor, 473 ver_resp->roce_fw_build, ver_resp->roce_fw_patch); 474 } else { 475 snprintf(fw_ver, FW_VER_STR_LEN, "%d.%d.%d.%d", 476 ver_resp->hwrm_fw_maj_8b, ver_resp->hwrm_fw_min_8b, 477 ver_resp->hwrm_fw_bld_8b, ver_resp->hwrm_fw_rsvd_8b); 478 479 snprintf(mgmt_ver, FW_VER_STR_LEN, "%d.%d.%d.%d", 480 ver_resp->mgmt_fw_maj_8b, ver_resp->mgmt_fw_min_8b, 481 ver_resp->mgmt_fw_bld_8b, ver_resp->mgmt_fw_rsvd_8b); 482 483 snprintf(roce_ver, FW_VER_STR_LEN, "%d.%d.%d.%d", 484 ver_resp->roce_fw_maj_8b, ver_resp->roce_fw_min_8b, 485 ver_resp->roce_fw_bld_8b, ver_resp->roce_fw_rsvd_8b); 486 } 487 rc = devlink_info_version_running_put(req, 488 DEVLINK_INFO_VERSION_GENERIC_FW_MGMT, fw_ver); 489 if (rc) 490 return rc; 491 492 rc = devlink_info_version_running_put(req, 493 DEVLINK_INFO_VERSION_GENERIC_FW_MGMT_API, 494 bp->hwrm_ver_supp); 495 if (rc) 496 return rc; 497 498 if (!(bp->flags & BNXT_FLAG_CHIP_P5)) { 499 rc = devlink_info_version_running_put(req, 500 DEVLINK_INFO_VERSION_GENERIC_FW_NCSI, mgmt_ver); 501 if (rc) 502 return rc; 503 504 rc = devlink_info_version_running_put(req, 505 DEVLINK_INFO_VERSION_GENERIC_FW_ROCE, roce_ver); 506 if (rc) 507 return rc; 508 } 509 return 0; 510 } 511 512 static int bnxt_hwrm_nvm_req(struct bnxt *bp, u32 param_id, void *msg, 513 int msg_len, union devlink_param_value *val) 514 { 515 struct hwrm_nvm_get_variable_input *req = msg; 516 struct bnxt_dl_nvm_param nvm_param; 517 union bnxt_nvm_data *data; 518 dma_addr_t data_dma_addr; 519 int idx = 0, rc, i; 520 521 /* Get/Set NVM CFG parameter is supported only on PFs */ 522 if (BNXT_VF(bp)) 523 return -EPERM; 524 525 for (i = 0; i < ARRAY_SIZE(nvm_params); i++) { 526 if (nvm_params[i].id == param_id) { 527 nvm_param = nvm_params[i]; 528 break; 529 } 530 } 531 532 if (i == ARRAY_SIZE(nvm_params)) 533 return -EOPNOTSUPP; 534 535 if (nvm_param.dir_type == BNXT_NVM_PORT_CFG) 536 idx = bp->pf.port_id; 537 else if (nvm_param.dir_type == BNXT_NVM_FUNC_CFG) 538 idx = bp->pf.fw_fid - BNXT_FIRST_PF_FID; 539 540 data = dma_alloc_coherent(&bp->pdev->dev, sizeof(*data), 541 &data_dma_addr, GFP_KERNEL); 542 if (!data) 543 return -ENOMEM; 544 545 req->dest_data_addr = cpu_to_le64(data_dma_addr); 546 req->data_len = cpu_to_le16(nvm_param.nvm_num_bits); 547 req->option_num = cpu_to_le16(nvm_param.offset); 548 req->index_0 = cpu_to_le16(idx); 549 if (idx) 550 req->dimensions = cpu_to_le16(1); 551 552 if (req->req_type == cpu_to_le16(HWRM_NVM_SET_VARIABLE)) { 553 bnxt_copy_to_nvm_data(data, val, nvm_param.nvm_num_bits, 554 nvm_param.dl_num_bytes); 555 rc = hwrm_send_message(bp, msg, msg_len, HWRM_CMD_TIMEOUT); 556 } else { 557 rc = hwrm_send_message_silent(bp, msg, msg_len, 558 HWRM_CMD_TIMEOUT); 559 if (!rc) { 560 bnxt_copy_from_nvm_data(val, data, 561 nvm_param.nvm_num_bits, 562 nvm_param.dl_num_bytes); 563 } else { 564 struct hwrm_err_output *resp = bp->hwrm_cmd_resp_addr; 565 566 if (resp->cmd_err == 567 NVM_GET_VARIABLE_CMD_ERR_CODE_VAR_NOT_EXIST) 568 rc = -EOPNOTSUPP; 569 } 570 } 571 dma_free_coherent(&bp->pdev->dev, sizeof(*data), data, data_dma_addr); 572 if (rc == -EACCES) 573 netdev_err(bp->dev, "PF does not have admin privileges to modify NVM config\n"); 574 return rc; 575 } 576 577 static int bnxt_dl_nvm_param_get(struct devlink *dl, u32 id, 578 struct devlink_param_gset_ctx *ctx) 579 { 580 struct hwrm_nvm_get_variable_input req = {0}; 581 struct bnxt *bp = bnxt_get_bp_from_dl(dl); 582 int rc; 583 584 bnxt_hwrm_cmd_hdr_init(bp, &req, HWRM_NVM_GET_VARIABLE, -1, -1); 585 rc = bnxt_hwrm_nvm_req(bp, id, &req, sizeof(req), &ctx->val); 586 if (!rc) 587 if (id == BNXT_DEVLINK_PARAM_ID_GRE_VER_CHECK) 588 ctx->val.vbool = !ctx->val.vbool; 589 590 return rc; 591 } 592 593 static int bnxt_dl_nvm_param_set(struct devlink *dl, u32 id, 594 struct devlink_param_gset_ctx *ctx) 595 { 596 struct hwrm_nvm_set_variable_input req = {0}; 597 struct bnxt *bp = bnxt_get_bp_from_dl(dl); 598 599 bnxt_hwrm_cmd_hdr_init(bp, &req, HWRM_NVM_SET_VARIABLE, -1, -1); 600 601 if (id == BNXT_DEVLINK_PARAM_ID_GRE_VER_CHECK) 602 ctx->val.vbool = !ctx->val.vbool; 603 604 return bnxt_hwrm_nvm_req(bp, id, &req, sizeof(req), &ctx->val); 605 } 606 607 static int bnxt_dl_msix_validate(struct devlink *dl, u32 id, 608 union devlink_param_value val, 609 struct netlink_ext_ack *extack) 610 { 611 int max_val = -1; 612 613 if (id == DEVLINK_PARAM_GENERIC_ID_MSIX_VEC_PER_PF_MAX) 614 max_val = BNXT_MSIX_VEC_MAX; 615 616 if (id == DEVLINK_PARAM_GENERIC_ID_MSIX_VEC_PER_PF_MIN) 617 max_val = BNXT_MSIX_VEC_MIN_MAX; 618 619 if (val.vu32 > max_val) { 620 NL_SET_ERR_MSG_MOD(extack, "MSIX value is exceeding the range"); 621 return -EINVAL; 622 } 623 624 return 0; 625 } 626 627 static const struct devlink_param bnxt_dl_params[] = { 628 DEVLINK_PARAM_GENERIC(ENABLE_SRIOV, 629 BIT(DEVLINK_PARAM_CMODE_PERMANENT), 630 bnxt_dl_nvm_param_get, bnxt_dl_nvm_param_set, 631 NULL), 632 DEVLINK_PARAM_GENERIC(IGNORE_ARI, 633 BIT(DEVLINK_PARAM_CMODE_PERMANENT), 634 bnxt_dl_nvm_param_get, bnxt_dl_nvm_param_set, 635 NULL), 636 DEVLINK_PARAM_GENERIC(MSIX_VEC_PER_PF_MAX, 637 BIT(DEVLINK_PARAM_CMODE_PERMANENT), 638 bnxt_dl_nvm_param_get, bnxt_dl_nvm_param_set, 639 bnxt_dl_msix_validate), 640 DEVLINK_PARAM_GENERIC(MSIX_VEC_PER_PF_MIN, 641 BIT(DEVLINK_PARAM_CMODE_PERMANENT), 642 bnxt_dl_nvm_param_get, bnxt_dl_nvm_param_set, 643 bnxt_dl_msix_validate), 644 DEVLINK_PARAM_DRIVER(BNXT_DEVLINK_PARAM_ID_GRE_VER_CHECK, 645 "gre_ver_check", DEVLINK_PARAM_TYPE_BOOL, 646 BIT(DEVLINK_PARAM_CMODE_PERMANENT), 647 bnxt_dl_nvm_param_get, bnxt_dl_nvm_param_set, 648 NULL), 649 }; 650 651 static const struct devlink_param bnxt_dl_port_params[] = { 652 }; 653 654 static int bnxt_dl_params_register(struct bnxt *bp) 655 { 656 int rc; 657 658 if (bp->hwrm_spec_code < 0x10600) 659 return 0; 660 661 rc = devlink_params_register(bp->dl, bnxt_dl_params, 662 ARRAY_SIZE(bnxt_dl_params)); 663 if (rc) { 664 netdev_warn(bp->dev, "devlink_params_register failed. rc=%d\n", 665 rc); 666 return rc; 667 } 668 rc = devlink_port_params_register(&bp->dl_port, bnxt_dl_port_params, 669 ARRAY_SIZE(bnxt_dl_port_params)); 670 if (rc) { 671 netdev_err(bp->dev, "devlink_port_params_register failed\n"); 672 devlink_params_unregister(bp->dl, bnxt_dl_params, 673 ARRAY_SIZE(bnxt_dl_params)); 674 return rc; 675 } 676 devlink_params_publish(bp->dl); 677 678 return 0; 679 } 680 681 static void bnxt_dl_params_unregister(struct bnxt *bp) 682 { 683 if (bp->hwrm_spec_code < 0x10600) 684 return; 685 686 devlink_params_unregister(bp->dl, bnxt_dl_params, 687 ARRAY_SIZE(bnxt_dl_params)); 688 devlink_port_params_unregister(&bp->dl_port, bnxt_dl_port_params, 689 ARRAY_SIZE(bnxt_dl_port_params)); 690 } 691 692 int bnxt_dl_register(struct bnxt *bp) 693 { 694 struct devlink_port_attrs attrs = {}; 695 struct devlink *dl; 696 int rc; 697 698 if (BNXT_PF(bp)) 699 dl = devlink_alloc(&bnxt_dl_ops, sizeof(struct bnxt_dl)); 700 else 701 dl = devlink_alloc(&bnxt_vf_dl_ops, sizeof(struct bnxt_dl)); 702 if (!dl) { 703 netdev_warn(bp->dev, "devlink_alloc failed\n"); 704 return -ENOMEM; 705 } 706 707 bnxt_link_bp_to_dl(bp, dl); 708 709 /* Add switchdev eswitch mode setting, if SRIOV supported */ 710 if (pci_find_ext_capability(bp->pdev, PCI_EXT_CAP_ID_SRIOV) && 711 bp->hwrm_spec_code > 0x10803) 712 bp->eswitch_mode = DEVLINK_ESWITCH_MODE_LEGACY; 713 714 rc = devlink_register(dl, &bp->pdev->dev); 715 if (rc) { 716 netdev_warn(bp->dev, "devlink_register failed. rc=%d\n", rc); 717 goto err_dl_free; 718 } 719 720 if (!BNXT_PF(bp)) 721 return 0; 722 723 attrs.flavour = DEVLINK_PORT_FLAVOUR_PHYSICAL; 724 attrs.phys.port_number = bp->pf.port_id; 725 memcpy(attrs.switch_id.id, bp->dsn, sizeof(bp->dsn)); 726 attrs.switch_id.id_len = sizeof(bp->dsn); 727 devlink_port_attrs_set(&bp->dl_port, &attrs); 728 rc = devlink_port_register(dl, &bp->dl_port, bp->pf.port_id); 729 if (rc) { 730 netdev_err(bp->dev, "devlink_port_register failed\n"); 731 goto err_dl_unreg; 732 } 733 734 rc = bnxt_dl_params_register(bp); 735 if (rc) 736 goto err_dl_port_unreg; 737 738 return 0; 739 740 err_dl_port_unreg: 741 devlink_port_unregister(&bp->dl_port); 742 err_dl_unreg: 743 devlink_unregister(dl); 744 err_dl_free: 745 bnxt_link_bp_to_dl(bp, NULL); 746 devlink_free(dl); 747 return rc; 748 } 749 750 void bnxt_dl_unregister(struct bnxt *bp) 751 { 752 struct devlink *dl = bp->dl; 753 754 if (!dl) 755 return; 756 757 if (BNXT_PF(bp)) { 758 bnxt_dl_params_unregister(bp); 759 devlink_port_unregister(&bp->dl_port); 760 } 761 devlink_unregister(dl); 762 devlink_free(dl); 763 } 764