bnxt_en: add enable_remote_dev_reset devlink parameter
authorEdwin Peer <edwin.peer@broadcom.com>
Fri, 29 Oct 2021 07:47:42 +0000 (03:47 -0400)
committerDavid S. Miller <davem@davemloft.net>
Fri, 29 Oct 2021 11:13:05 +0000 (12:13 +0100)
The reported parameter value should not take into account the state
of remote drivers. Firmware will reject remote resets as appropriate,
thus it is not strictly necessary to check HOT_RESET_ALLOWED before
attempting to initiate a reset. But we add the check so that we can
provide more intuitive messages when reset is not permitted.

This firmware setting needs to be restored from all functions after
a firmware reset.

Signed-off-by: Edwin Peer <edwin.peer@broadcom.com>
Signed-off-by: Michael Chan <michael.chan@broadcom.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
drivers/net/ethernet/broadcom/bnxt/bnxt.c
drivers/net/ethernet/broadcom/bnxt/bnxt.h
drivers/net/ethernet/broadcom/bnxt/bnxt_devlink.c
drivers/net/ethernet/broadcom/bnxt/bnxt_devlink.h
drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c

index cd5932c75997e8f829bd07e375046e7b16d9e1ec..80fff3d8b31f50db122b94a023950242f96b8066 100644 (file)
@@ -7476,6 +7476,8 @@ static int __bnxt_hwrm_func_qcaps(struct bnxt *bp)
                bp->fw_cap |= BNXT_FW_CAP_EXT_HW_STATS_SUPPORTED;
        if (BNXT_PF(bp) && (flags_ext & FUNC_QCAPS_RESP_FLAGS_EXT_PTP_PPS_SUPPORTED))
                bp->fw_cap |= BNXT_FW_CAP_PTP_PPS;
+       if (BNXT_PF(bp) && (flags_ext & FUNC_QCAPS_RESP_FLAGS_EXT_HOT_RESET_IF_SUPPORT))
+               bp->fw_cap |= BNXT_FW_CAP_HOT_RESET_IF;
 
        bp->tx_push_thresh = 0;
        if ((flags & FUNC_QCAPS_RESP_FLAGS_PUSH_MODE_SUPPORTED) &&
@@ -12010,6 +12012,27 @@ static void bnxt_fw_reset_writel(struct bnxt *bp, int reg_idx)
        }
 }
 
+bool bnxt_hwrm_reset_permitted(struct bnxt *bp)
+{
+       struct hwrm_func_qcfg_output *resp;
+       struct hwrm_func_qcfg_input *req;
+       bool result = true; /* firmware will enforce if unknown */
+
+       if (~bp->fw_cap & BNXT_FW_CAP_HOT_RESET_IF)
+               return result;
+
+       if (hwrm_req_init(bp, req, HWRM_FUNC_QCFG))
+               return result;
+
+       req->fid = cpu_to_le16(0xffff);
+       resp = hwrm_req_hold(bp, req);
+       if (!hwrm_req_send(bp, req))
+               result = !!(le16_to_cpu(resp->flags) &
+                           FUNC_QCFG_RESP_FLAGS_HOT_RESET_ALLOWED);
+       hwrm_req_drop(bp, req);
+       return result;
+}
+
 static void bnxt_reset_all(struct bnxt *bp)
 {
        struct bnxt_fw_health *fw_health = bp->fw_health;
index 38c23b4106a14852d539697cfca9ce760ea19996..e56f2a27c67a5ec3924a2131f7d0fc23daca38eb 100644 (file)
@@ -1935,6 +1935,7 @@ struct bnxt {
        #define BNXT_FW_CAP_VLAN_TX_INSERT              0x02000000
        #define BNXT_FW_CAP_EXT_HW_STATS_SUPPORTED      0x04000000
        #define BNXT_FW_CAP_PTP_PPS                     0x10000000
+       #define BNXT_FW_CAP_HOT_RESET_IF                0x20000000
        #define BNXT_FW_CAP_RING_MONITOR                0x40000000
 
 #define BNXT_NEW_RM(bp)                ((bp)->fw_cap & BNXT_FW_CAP_NEW_RM)
@@ -2274,6 +2275,7 @@ void bnxt_fw_reset(struct bnxt *bp);
 int bnxt_check_rings(struct bnxt *bp, int tx, int rx, bool sh, int tcs,
                     int tx_xdp);
 int bnxt_fw_init_one(struct bnxt *bp);
+bool bnxt_hwrm_reset_permitted(struct bnxt *bp);
 int bnxt_setup_mq_tc(struct net_device *dev, u8 tc);
 int bnxt_get_max_rings(struct bnxt *, int *, int *, bool);
 int bnxt_restore_pf_fw_resources(struct bnxt *bp);
index 9922c1428129d4695852d9aea633f49b2cf9ebaf..8673f3c4b5810ee083b6040a7455e41236f30afd 100644 (file)
@@ -42,6 +42,26 @@ bnxt_dl_flash_update(struct devlink *dl,
        return rc;
 }
 
+static int bnxt_hwrm_remote_dev_reset_set(struct bnxt *bp, bool remote_reset)
+{
+       struct hwrm_func_cfg_input *req;
+       int rc;
+
+       if (~bp->fw_cap & BNXT_FW_CAP_HOT_RESET_IF)
+               return -EOPNOTSUPP;
+
+       rc = hwrm_req_init(bp, req, HWRM_FUNC_CFG);
+       if (rc)
+               return rc;
+
+       req->fid = cpu_to_le16(0xffff);
+       req->enables = cpu_to_le32(FUNC_CFG_REQ_ENABLES_HOT_RESET_IF_SUPPORT);
+       if (remote_reset)
+               req->flags = cpu_to_le32(FUNC_CFG_REQ_FLAGS_HOT_RESET_IF_EN_DIS);
+
+       return hwrm_req_send(bp, req);
+}
+
 static int bnxt_fw_reporter_diagnose(struct devlink_health_reporter *reporter,
                                     struct devlink_fmsg *fmsg,
                                     struct netlink_ext_ack *extack)
@@ -272,11 +292,13 @@ void bnxt_dl_health_status_update(struct bnxt *bp, bool healthy)
 void bnxt_dl_health_recovery_done(struct bnxt *bp)
 {
        struct bnxt_fw_health *hlth = bp->fw_health;
+       struct bnxt_dl *dl = devlink_priv(bp->dl);
 
        if (hlth->fatal)
                devlink_health_reporter_recovery_done(hlth->fw_fatal_reporter);
        else
                devlink_health_reporter_recovery_done(hlth->fw_reset_reporter);
+       bnxt_hwrm_remote_dev_reset_set(bp, dl->remote_reset);
 }
 
 static int bnxt_dl_info_get(struct devlink *dl, struct devlink_info_req *req,
@@ -332,6 +354,11 @@ static int bnxt_dl_reload_down(struct devlink *dl, bool netns_change,
                        NL_SET_ERR_MSG_MOD(extack, "Device not capable, requires reboot");
                        return -EOPNOTSUPP;
                }
+               if (!bnxt_hwrm_reset_permitted(bp)) {
+                       NL_SET_ERR_MSG_MOD(extack,
+                                          "Reset denied by firmware, it may be inhibited by remote driver");
+                       return -EPERM;
+               }
                rtnl_lock();
                if (bp->dev->reg_state == NETREG_UNREGISTERED) {
                        rtnl_unlock();
@@ -863,6 +890,32 @@ static int bnxt_dl_msix_validate(struct devlink *dl, u32 id,
        return 0;
 }
 
+static int bnxt_remote_dev_reset_get(struct devlink *dl, u32 id,
+                                    struct devlink_param_gset_ctx *ctx)
+{
+       struct bnxt *bp = bnxt_get_bp_from_dl(dl);
+
+       if (~bp->fw_cap & BNXT_FW_CAP_HOT_RESET_IF)
+               return -EOPNOTSUPP;
+
+       ctx->val.vbool = bnxt_dl_get_remote_reset(dl);
+       return 0;
+}
+
+static int bnxt_remote_dev_reset_set(struct devlink *dl, u32 id,
+                                    struct devlink_param_gset_ctx *ctx)
+{
+       struct bnxt *bp = bnxt_get_bp_from_dl(dl);
+       int rc;
+
+       rc = bnxt_hwrm_remote_dev_reset_set(bp, ctx->val.vbool);
+       if (rc)
+               return rc;
+
+       bnxt_dl_set_remote_reset(dl, ctx->val.vbool);
+       return rc;
+}
+
 static const struct devlink_param bnxt_dl_params[] = {
        DEVLINK_PARAM_GENERIC(ENABLE_SRIOV,
                              BIT(DEVLINK_PARAM_CMODE_PERMANENT),
@@ -885,17 +938,25 @@ static const struct devlink_param bnxt_dl_params[] = {
                             BIT(DEVLINK_PARAM_CMODE_PERMANENT),
                             bnxt_dl_nvm_param_get, bnxt_dl_nvm_param_set,
                             NULL),
+       /* keep REMOTE_DEV_RESET last, it is excluded based on caps */
+       DEVLINK_PARAM_GENERIC(ENABLE_REMOTE_DEV_RESET,
+                             BIT(DEVLINK_PARAM_CMODE_RUNTIME),
+                             bnxt_remote_dev_reset_get,
+                             bnxt_remote_dev_reset_set, NULL),
 };
 
 static int bnxt_dl_params_register(struct bnxt *bp)
 {
+       int num_params = ARRAY_SIZE(bnxt_dl_params);
        int rc;
 
        if (bp->hwrm_spec_code < 0x10600)
                return 0;
 
-       rc = devlink_params_register(bp->dl, bnxt_dl_params,
-                                    ARRAY_SIZE(bnxt_dl_params));
+       if (~bp->fw_cap & BNXT_FW_CAP_HOT_RESET_IF)
+               num_params--;
+
+       rc = devlink_params_register(bp->dl, bnxt_dl_params, num_params);
        if (rc)
                netdev_warn(bp->dev, "devlink_params_register failed. rc=%d\n",
                            rc);
@@ -904,11 +965,15 @@ static int bnxt_dl_params_register(struct bnxt *bp)
 
 static void bnxt_dl_params_unregister(struct bnxt *bp)
 {
+       int num_params = ARRAY_SIZE(bnxt_dl_params);
+
        if (bp->hwrm_spec_code < 0x10600)
                return;
 
-       devlink_params_unregister(bp->dl, bnxt_dl_params,
-                                 ARRAY_SIZE(bnxt_dl_params));
+       if (~bp->fw_cap & BNXT_FW_CAP_HOT_RESET_IF)
+               num_params--;
+
+       devlink_params_unregister(bp->dl, bnxt_dl_params, num_params);
 }
 
 int bnxt_dl_register(struct bnxt *bp)
@@ -933,6 +998,7 @@ int bnxt_dl_register(struct bnxt *bp)
        bp->dl = dl;
        bp_dl = devlink_priv(dl);
        bp_dl->bp = bp;
+       bnxt_dl_set_remote_reset(dl, true);
 
        /* Add switchdev eswitch mode setting, if SRIOV supported */
        if (pci_find_ext_capability(bp->pdev, PCI_EXT_CAP_ID_SRIOV) &&
index a189cfe1e44172c6a382d1137a26a4a81c09de2f..456e18c4badf3cbd8a04af3501283ea4ca092c64 100644 (file)
@@ -13,6 +13,7 @@
 /* Struct to hold housekeeping info needed by devlink interface */
 struct bnxt_dl {
        struct bnxt *bp;        /* back ptr to the controlling dev */
+       bool remote_reset;
 };
 
 static inline struct bnxt *bnxt_get_bp_from_dl(struct devlink *dl)
@@ -27,6 +28,16 @@ static inline void bnxt_dl_remote_reload(struct bnxt *bp)
                                                BIT(DEVLINK_RELOAD_ACTION_FW_ACTIVATE));
 }
 
+static inline bool bnxt_dl_get_remote_reset(struct devlink *dl)
+{
+       return ((struct bnxt_dl *)devlink_priv(dl))->remote_reset;
+}
+
+static inline void bnxt_dl_set_remote_reset(struct devlink *dl, bool value)
+{
+       ((struct bnxt_dl *)devlink_priv(dl))->remote_reset = value;
+}
+
 #define NVM_OFF_MSIX_VEC_PER_PF_MAX    108
 #define NVM_OFF_MSIX_VEC_PER_PF_MIN    114
 #define NVM_OFF_IGNORE_ARI             164
index ac8df5c6906f99a971fbc57fbf25c269b85b50fd..15c5180249652709656194aa9515e75b24ffb4e0 100644 (file)
@@ -2187,6 +2187,11 @@ int bnxt_hwrm_firmware_reset(struct net_device *dev, u8 proc_type,
        struct hwrm_fw_reset_input *req;
        int rc;
 
+       if (!bnxt_hwrm_reset_permitted(bp)) {
+               netdev_warn(bp->dev, "Reset denied by firmware, it may be inhibited by remote driver");
+               return -EPERM;
+       }
+
        rc = hwrm_req_init(bp, req, HWRM_FW_RESET);
        if (rc)
                return rc;