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