root/drivers/net/ethernet/broadcom/bnxt/bnxt_devlink.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. bnxt_fw_reporter_diagnose
  2. bnxt_fw_reset_recover
  3. bnxt_fw_fatal_recover
  4. bnxt_dl_fw_reporters_create
  5. bnxt_dl_fw_reporters_destroy
  6. bnxt_devlink_health_report
  7. bnxt_copy_to_nvm_data
  8. bnxt_copy_from_nvm_data
  9. bnxt_hwrm_nvm_req
  10. bnxt_dl_nvm_param_get
  11. bnxt_dl_nvm_param_set
  12. bnxt_dl_msix_validate
  13. bnxt_dl_register
  14. bnxt_dl_unregister

   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 
  18 static int bnxt_fw_reporter_diagnose(struct devlink_health_reporter *reporter,
  19                                      struct devlink_fmsg *fmsg)
  20 {
  21         struct bnxt *bp = devlink_health_reporter_priv(reporter);
  22         u32 val, health_status;
  23         int rc;
  24 
  25         if (test_bit(BNXT_STATE_IN_FW_RESET, &bp->state))
  26                 return 0;
  27 
  28         val = bnxt_fw_health_readl(bp, BNXT_FW_HEALTH_REG);
  29         health_status = val & 0xffff;
  30 
  31         if (health_status < BNXT_FW_STATUS_HEALTHY) {
  32                 rc = devlink_fmsg_string_pair_put(fmsg, "Description",
  33                                                   "Not yet completed initialization");
  34                 if (rc)
  35                         return rc;
  36         } else if (health_status > BNXT_FW_STATUS_HEALTHY) {
  37                 rc = devlink_fmsg_string_pair_put(fmsg, "Description",
  38                                                   "Encountered fatal error and cannot recover");
  39                 if (rc)
  40                         return rc;
  41         }
  42 
  43         if (val >> 16) {
  44                 rc = devlink_fmsg_u32_pair_put(fmsg, "Error code", val >> 16);
  45                 if (rc)
  46                         return rc;
  47         }
  48 
  49         val = bnxt_fw_health_readl(bp, BNXT_FW_RESET_CNT_REG);
  50         rc = devlink_fmsg_u32_pair_put(fmsg, "Reset count", val);
  51         if (rc)
  52                 return rc;
  53 
  54         return 0;
  55 }
  56 
  57 static const struct devlink_health_reporter_ops bnxt_dl_fw_reporter_ops = {
  58         .name = "fw",
  59         .diagnose = bnxt_fw_reporter_diagnose,
  60 };
  61 
  62 static int bnxt_fw_reset_recover(struct devlink_health_reporter *reporter,
  63                                  void *priv_ctx)
  64 {
  65         struct bnxt *bp = devlink_health_reporter_priv(reporter);
  66 
  67         if (!priv_ctx)
  68                 return -EOPNOTSUPP;
  69 
  70         bnxt_fw_reset(bp);
  71         return 0;
  72 }
  73 
  74 static const
  75 struct devlink_health_reporter_ops bnxt_dl_fw_reset_reporter_ops = {
  76         .name = "fw_reset",
  77         .recover = bnxt_fw_reset_recover,
  78 };
  79 
  80 static int bnxt_fw_fatal_recover(struct devlink_health_reporter *reporter,
  81                                  void *priv_ctx)
  82 {
  83         struct bnxt *bp = devlink_health_reporter_priv(reporter);
  84         struct bnxt_fw_reporter_ctx *fw_reporter_ctx = priv_ctx;
  85         unsigned long event;
  86 
  87         if (!priv_ctx)
  88                 return -EOPNOTSUPP;
  89 
  90         event = fw_reporter_ctx->sp_event;
  91         if (event == BNXT_FW_RESET_NOTIFY_SP_EVENT)
  92                 bnxt_fw_reset(bp);
  93         else if (event == BNXT_FW_EXCEPTION_SP_EVENT)
  94                 bnxt_fw_exception(bp);
  95 
  96         return 0;
  97 }
  98 
  99 static const
 100 struct devlink_health_reporter_ops bnxt_dl_fw_fatal_reporter_ops = {
 101         .name = "fw_fatal",
 102         .recover = bnxt_fw_fatal_recover,
 103 };
 104 
 105 void bnxt_dl_fw_reporters_create(struct bnxt *bp)
 106 {
 107         struct bnxt_fw_health *health = bp->fw_health;
 108 
 109         if (!bp->dl || !health)
 110                 return;
 111 
 112         if (!(bp->fw_cap & BNXT_FW_CAP_HOT_RESET) || health->fw_reset_reporter)
 113                 goto err_recovery;
 114 
 115         health->fw_reset_reporter =
 116                 devlink_health_reporter_create(bp->dl,
 117                                                &bnxt_dl_fw_reset_reporter_ops,
 118                                                0, true, bp);
 119         if (IS_ERR(health->fw_reset_reporter)) {
 120                 netdev_warn(bp->dev, "Failed to create FW fatal health reporter, rc = %ld\n",
 121                             PTR_ERR(health->fw_reset_reporter));
 122                 health->fw_reset_reporter = NULL;
 123                 bp->fw_cap &= ~BNXT_FW_CAP_HOT_RESET;
 124         }
 125 
 126 err_recovery:
 127         if (!(bp->fw_cap & BNXT_FW_CAP_ERROR_RECOVERY))
 128                 return;
 129 
 130         if (!health->fw_reporter) {
 131                 health->fw_reporter =
 132                         devlink_health_reporter_create(bp->dl,
 133                                                        &bnxt_dl_fw_reporter_ops,
 134                                                        0, false, bp);
 135                 if (IS_ERR(health->fw_reporter)) {
 136                         netdev_warn(bp->dev, "Failed to create FW health reporter, rc = %ld\n",
 137                                     PTR_ERR(health->fw_reporter));
 138                         health->fw_reporter = NULL;
 139                         bp->fw_cap &= ~BNXT_FW_CAP_ERROR_RECOVERY;
 140                         return;
 141                 }
 142         }
 143 
 144         if (health->fw_fatal_reporter)
 145                 return;
 146 
 147         health->fw_fatal_reporter =
 148                 devlink_health_reporter_create(bp->dl,
 149                                                &bnxt_dl_fw_fatal_reporter_ops,
 150                                                0, true, bp);
 151         if (IS_ERR(health->fw_fatal_reporter)) {
 152                 netdev_warn(bp->dev, "Failed to create FW fatal health reporter, rc = %ld\n",
 153                             PTR_ERR(health->fw_fatal_reporter));
 154                 health->fw_fatal_reporter = NULL;
 155                 bp->fw_cap &= ~BNXT_FW_CAP_ERROR_RECOVERY;
 156         }
 157 }
 158 
 159 void bnxt_dl_fw_reporters_destroy(struct bnxt *bp, bool all)
 160 {
 161         struct bnxt_fw_health *health = bp->fw_health;
 162 
 163         if (!bp->dl || !health)
 164                 return;
 165 
 166         if ((all || !(bp->fw_cap & BNXT_FW_CAP_HOT_RESET)) &&
 167             health->fw_reset_reporter) {
 168                 devlink_health_reporter_destroy(health->fw_reset_reporter);
 169                 health->fw_reset_reporter = NULL;
 170         }
 171 
 172         if ((bp->fw_cap & BNXT_FW_CAP_ERROR_RECOVERY) && !all)
 173                 return;
 174 
 175         if (health->fw_reporter) {
 176                 devlink_health_reporter_destroy(health->fw_reporter);
 177                 health->fw_reporter = NULL;
 178         }
 179 
 180         if (health->fw_fatal_reporter) {
 181                 devlink_health_reporter_destroy(health->fw_fatal_reporter);
 182                 health->fw_fatal_reporter = NULL;
 183         }
 184 }
 185 
 186 void bnxt_devlink_health_report(struct bnxt *bp, unsigned long event)
 187 {
 188         struct bnxt_fw_health *fw_health = bp->fw_health;
 189         struct bnxt_fw_reporter_ctx fw_reporter_ctx;
 190 
 191         fw_reporter_ctx.sp_event = event;
 192         switch (event) {
 193         case BNXT_FW_RESET_NOTIFY_SP_EVENT:
 194                 if (test_bit(BNXT_STATE_FW_FATAL_COND, &bp->state)) {
 195                         if (!fw_health->fw_fatal_reporter)
 196                                 return;
 197 
 198                         devlink_health_report(fw_health->fw_fatal_reporter,
 199                                               "FW fatal async event received",
 200                                               &fw_reporter_ctx);
 201                         return;
 202                 }
 203                 if (!fw_health->fw_reset_reporter)
 204                         return;
 205 
 206                 devlink_health_report(fw_health->fw_reset_reporter,
 207                                       "FW non-fatal reset event received",
 208                                       &fw_reporter_ctx);
 209                 return;
 210 
 211         case BNXT_FW_EXCEPTION_SP_EVENT:
 212                 if (!fw_health->fw_fatal_reporter)
 213                         return;
 214 
 215                 devlink_health_report(fw_health->fw_fatal_reporter,
 216                                       "FW fatal error reported",
 217                                       &fw_reporter_ctx);
 218                 return;
 219         }
 220 }
 221 
 222 static const struct devlink_ops bnxt_dl_ops = {
 223 #ifdef CONFIG_BNXT_SRIOV
 224         .eswitch_mode_set = bnxt_dl_eswitch_mode_set,
 225         .eswitch_mode_get = bnxt_dl_eswitch_mode_get,
 226 #endif /* CONFIG_BNXT_SRIOV */
 227 };
 228 
 229 static const struct devlink_ops bnxt_vf_dl_ops;
 230 
 231 enum bnxt_dl_param_id {
 232         BNXT_DEVLINK_PARAM_ID_BASE = DEVLINK_PARAM_GENERIC_ID_MAX,
 233         BNXT_DEVLINK_PARAM_ID_GRE_VER_CHECK,
 234 };
 235 
 236 static const struct bnxt_dl_nvm_param nvm_params[] = {
 237         {DEVLINK_PARAM_GENERIC_ID_ENABLE_SRIOV, NVM_OFF_ENABLE_SRIOV,
 238          BNXT_NVM_SHARED_CFG, 1, 1},
 239         {DEVLINK_PARAM_GENERIC_ID_IGNORE_ARI, NVM_OFF_IGNORE_ARI,
 240          BNXT_NVM_SHARED_CFG, 1, 1},
 241         {DEVLINK_PARAM_GENERIC_ID_MSIX_VEC_PER_PF_MAX,
 242          NVM_OFF_MSIX_VEC_PER_PF_MAX, BNXT_NVM_SHARED_CFG, 10, 4},
 243         {DEVLINK_PARAM_GENERIC_ID_MSIX_VEC_PER_PF_MIN,
 244          NVM_OFF_MSIX_VEC_PER_PF_MIN, BNXT_NVM_SHARED_CFG, 7, 4},
 245         {BNXT_DEVLINK_PARAM_ID_GRE_VER_CHECK, NVM_OFF_DIS_GRE_VER_CHECK,
 246          BNXT_NVM_SHARED_CFG, 1, 1},
 247 };
 248 
 249 union bnxt_nvm_data {
 250         u8      val8;
 251         __le32  val32;
 252 };
 253 
 254 static void bnxt_copy_to_nvm_data(union bnxt_nvm_data *dst,
 255                                   union devlink_param_value *src,
 256                                   int nvm_num_bits, int dl_num_bytes)
 257 {
 258         u32 val32 = 0;
 259 
 260         if (nvm_num_bits == 1) {
 261                 dst->val8 = src->vbool;
 262                 return;
 263         }
 264         if (dl_num_bytes == 4)
 265                 val32 = src->vu32;
 266         else if (dl_num_bytes == 2)
 267                 val32 = (u32)src->vu16;
 268         else if (dl_num_bytes == 1)
 269                 val32 = (u32)src->vu8;
 270         dst->val32 = cpu_to_le32(val32);
 271 }
 272 
 273 static void bnxt_copy_from_nvm_data(union devlink_param_value *dst,
 274                                     union bnxt_nvm_data *src,
 275                                     int nvm_num_bits, int dl_num_bytes)
 276 {
 277         u32 val32;
 278 
 279         if (nvm_num_bits == 1) {
 280                 dst->vbool = src->val8;
 281                 return;
 282         }
 283         val32 = le32_to_cpu(src->val32);
 284         if (dl_num_bytes == 4)
 285                 dst->vu32 = val32;
 286         else if (dl_num_bytes == 2)
 287                 dst->vu16 = (u16)val32;
 288         else if (dl_num_bytes == 1)
 289                 dst->vu8 = (u8)val32;
 290 }
 291 
 292 static int bnxt_hwrm_nvm_req(struct bnxt *bp, u32 param_id, void *msg,
 293                              int msg_len, union devlink_param_value *val)
 294 {
 295         struct hwrm_nvm_get_variable_input *req = msg;
 296         struct bnxt_dl_nvm_param nvm_param;
 297         union bnxt_nvm_data *data;
 298         dma_addr_t data_dma_addr;
 299         int idx = 0, rc, i;
 300 
 301         /* Get/Set NVM CFG parameter is supported only on PFs */
 302         if (BNXT_VF(bp))
 303                 return -EPERM;
 304 
 305         for (i = 0; i < ARRAY_SIZE(nvm_params); i++) {
 306                 if (nvm_params[i].id == param_id) {
 307                         nvm_param = nvm_params[i];
 308                         break;
 309                 }
 310         }
 311 
 312         if (i == ARRAY_SIZE(nvm_params))
 313                 return -EOPNOTSUPP;
 314 
 315         if (nvm_param.dir_type == BNXT_NVM_PORT_CFG)
 316                 idx = bp->pf.port_id;
 317         else if (nvm_param.dir_type == BNXT_NVM_FUNC_CFG)
 318                 idx = bp->pf.fw_fid - BNXT_FIRST_PF_FID;
 319 
 320         data = dma_alloc_coherent(&bp->pdev->dev, sizeof(*data),
 321                                   &data_dma_addr, GFP_KERNEL);
 322         if (!data)
 323                 return -ENOMEM;
 324 
 325         req->dest_data_addr = cpu_to_le64(data_dma_addr);
 326         req->data_len = cpu_to_le16(nvm_param.nvm_num_bits);
 327         req->option_num = cpu_to_le16(nvm_param.offset);
 328         req->index_0 = cpu_to_le16(idx);
 329         if (idx)
 330                 req->dimensions = cpu_to_le16(1);
 331 
 332         if (req->req_type == cpu_to_le16(HWRM_NVM_SET_VARIABLE)) {
 333                 bnxt_copy_to_nvm_data(data, val, nvm_param.nvm_num_bits,
 334                                       nvm_param.dl_num_bytes);
 335                 rc = hwrm_send_message(bp, msg, msg_len, HWRM_CMD_TIMEOUT);
 336         } else {
 337                 rc = hwrm_send_message_silent(bp, msg, msg_len,
 338                                               HWRM_CMD_TIMEOUT);
 339                 if (!rc) {
 340                         bnxt_copy_from_nvm_data(val, data,
 341                                                 nvm_param.nvm_num_bits,
 342                                                 nvm_param.dl_num_bytes);
 343                 } else {
 344                         struct hwrm_err_output *resp = bp->hwrm_cmd_resp_addr;
 345 
 346                         if (resp->cmd_err ==
 347                                 NVM_GET_VARIABLE_CMD_ERR_CODE_VAR_NOT_EXIST)
 348                                 rc = -EOPNOTSUPP;
 349                 }
 350         }
 351         dma_free_coherent(&bp->pdev->dev, sizeof(*data), data, data_dma_addr);
 352         if (rc == -EACCES)
 353                 netdev_err(bp->dev, "PF does not have admin privileges to modify NVM config\n");
 354         return rc;
 355 }
 356 
 357 static int bnxt_dl_nvm_param_get(struct devlink *dl, u32 id,
 358                                  struct devlink_param_gset_ctx *ctx)
 359 {
 360         struct hwrm_nvm_get_variable_input req = {0};
 361         struct bnxt *bp = bnxt_get_bp_from_dl(dl);
 362         int rc;
 363 
 364         bnxt_hwrm_cmd_hdr_init(bp, &req, HWRM_NVM_GET_VARIABLE, -1, -1);
 365         rc = bnxt_hwrm_nvm_req(bp, id, &req, sizeof(req), &ctx->val);
 366         if (!rc)
 367                 if (id == BNXT_DEVLINK_PARAM_ID_GRE_VER_CHECK)
 368                         ctx->val.vbool = !ctx->val.vbool;
 369 
 370         return rc;
 371 }
 372 
 373 static int bnxt_dl_nvm_param_set(struct devlink *dl, u32 id,
 374                                  struct devlink_param_gset_ctx *ctx)
 375 {
 376         struct hwrm_nvm_set_variable_input req = {0};
 377         struct bnxt *bp = bnxt_get_bp_from_dl(dl);
 378 
 379         bnxt_hwrm_cmd_hdr_init(bp, &req, HWRM_NVM_SET_VARIABLE, -1, -1);
 380 
 381         if (id == BNXT_DEVLINK_PARAM_ID_GRE_VER_CHECK)
 382                 ctx->val.vbool = !ctx->val.vbool;
 383 
 384         return bnxt_hwrm_nvm_req(bp, id, &req, sizeof(req), &ctx->val);
 385 }
 386 
 387 static int bnxt_dl_msix_validate(struct devlink *dl, u32 id,
 388                                  union devlink_param_value val,
 389                                  struct netlink_ext_ack *extack)
 390 {
 391         int max_val = -1;
 392 
 393         if (id == DEVLINK_PARAM_GENERIC_ID_MSIX_VEC_PER_PF_MAX)
 394                 max_val = BNXT_MSIX_VEC_MAX;
 395 
 396         if (id == DEVLINK_PARAM_GENERIC_ID_MSIX_VEC_PER_PF_MIN)
 397                 max_val = BNXT_MSIX_VEC_MIN_MAX;
 398 
 399         if (val.vu32 > max_val) {
 400                 NL_SET_ERR_MSG_MOD(extack, "MSIX value is exceeding the range");
 401                 return -EINVAL;
 402         }
 403 
 404         return 0;
 405 }
 406 
 407 static const struct devlink_param bnxt_dl_params[] = {
 408         DEVLINK_PARAM_GENERIC(ENABLE_SRIOV,
 409                               BIT(DEVLINK_PARAM_CMODE_PERMANENT),
 410                               bnxt_dl_nvm_param_get, bnxt_dl_nvm_param_set,
 411                               NULL),
 412         DEVLINK_PARAM_GENERIC(IGNORE_ARI,
 413                               BIT(DEVLINK_PARAM_CMODE_PERMANENT),
 414                               bnxt_dl_nvm_param_get, bnxt_dl_nvm_param_set,
 415                               NULL),
 416         DEVLINK_PARAM_GENERIC(MSIX_VEC_PER_PF_MAX,
 417                               BIT(DEVLINK_PARAM_CMODE_PERMANENT),
 418                               bnxt_dl_nvm_param_get, bnxt_dl_nvm_param_set,
 419                               bnxt_dl_msix_validate),
 420         DEVLINK_PARAM_GENERIC(MSIX_VEC_PER_PF_MIN,
 421                               BIT(DEVLINK_PARAM_CMODE_PERMANENT),
 422                               bnxt_dl_nvm_param_get, bnxt_dl_nvm_param_set,
 423                               bnxt_dl_msix_validate),
 424         DEVLINK_PARAM_DRIVER(BNXT_DEVLINK_PARAM_ID_GRE_VER_CHECK,
 425                              "gre_ver_check", DEVLINK_PARAM_TYPE_BOOL,
 426                              BIT(DEVLINK_PARAM_CMODE_PERMANENT),
 427                              bnxt_dl_nvm_param_get, bnxt_dl_nvm_param_set,
 428                              NULL),
 429 };
 430 
 431 static const struct devlink_param bnxt_dl_port_params[] = {
 432 };
 433 
 434 int bnxt_dl_register(struct bnxt *bp)
 435 {
 436         struct devlink *dl;
 437         int rc;
 438 
 439         if (bp->hwrm_spec_code < 0x10600) {
 440                 netdev_warn(bp->dev, "Firmware does not support NVM params");
 441                 return -ENOTSUPP;
 442         }
 443 
 444         if (BNXT_PF(bp))
 445                 dl = devlink_alloc(&bnxt_dl_ops, sizeof(struct bnxt_dl));
 446         else
 447                 dl = devlink_alloc(&bnxt_vf_dl_ops, sizeof(struct bnxt_dl));
 448         if (!dl) {
 449                 netdev_warn(bp->dev, "devlink_alloc failed");
 450                 return -ENOMEM;
 451         }
 452 
 453         bnxt_link_bp_to_dl(bp, dl);
 454 
 455         /* Add switchdev eswitch mode setting, if SRIOV supported */
 456         if (pci_find_ext_capability(bp->pdev, PCI_EXT_CAP_ID_SRIOV) &&
 457             bp->hwrm_spec_code > 0x10803)
 458                 bp->eswitch_mode = DEVLINK_ESWITCH_MODE_LEGACY;
 459 
 460         rc = devlink_register(dl, &bp->pdev->dev);
 461         if (rc) {
 462                 netdev_warn(bp->dev, "devlink_register failed. rc=%d", rc);
 463                 goto err_dl_free;
 464         }
 465 
 466         if (!BNXT_PF(bp))
 467                 return 0;
 468 
 469         rc = devlink_params_register(dl, bnxt_dl_params,
 470                                      ARRAY_SIZE(bnxt_dl_params));
 471         if (rc) {
 472                 netdev_warn(bp->dev, "devlink_params_register failed. rc=%d",
 473                             rc);
 474                 goto err_dl_unreg;
 475         }
 476 
 477         devlink_port_attrs_set(&bp->dl_port, DEVLINK_PORT_FLAVOUR_PHYSICAL,
 478                                bp->pf.port_id, false, 0,
 479                                bp->switch_id, sizeof(bp->switch_id));
 480         rc = devlink_port_register(dl, &bp->dl_port, bp->pf.port_id);
 481         if (rc) {
 482                 netdev_err(bp->dev, "devlink_port_register failed");
 483                 goto err_dl_param_unreg;
 484         }
 485 
 486         rc = devlink_port_params_register(&bp->dl_port, bnxt_dl_port_params,
 487                                           ARRAY_SIZE(bnxt_dl_port_params));
 488         if (rc) {
 489                 netdev_err(bp->dev, "devlink_port_params_register failed");
 490                 goto err_dl_port_unreg;
 491         }
 492 
 493         devlink_params_publish(dl);
 494 
 495         return 0;
 496 
 497 err_dl_port_unreg:
 498         devlink_port_unregister(&bp->dl_port);
 499 err_dl_param_unreg:
 500         devlink_params_unregister(dl, bnxt_dl_params,
 501                                   ARRAY_SIZE(bnxt_dl_params));
 502 err_dl_unreg:
 503         devlink_unregister(dl);
 504 err_dl_free:
 505         bnxt_link_bp_to_dl(bp, NULL);
 506         devlink_free(dl);
 507         return rc;
 508 }
 509 
 510 void bnxt_dl_unregister(struct bnxt *bp)
 511 {
 512         struct devlink *dl = bp->dl;
 513 
 514         if (!dl)
 515                 return;
 516 
 517         if (BNXT_PF(bp)) {
 518                 devlink_port_params_unregister(&bp->dl_port,
 519                                                bnxt_dl_port_params,
 520                                                ARRAY_SIZE(bnxt_dl_port_params));
 521                 devlink_port_unregister(&bp->dl_port);
 522                 devlink_params_unregister(dl, bnxt_dl_params,
 523                                           ARRAY_SIZE(bnxt_dl_params));
 524         }
 525         devlink_unregister(dl);
 526         devlink_free(dl);
 527 }

/* [<][>][^][v][top][bottom][index][help] */