bnxt_en: add enable_remote_dev_reset devlink parameter

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>
This commit is contained in:
Edwin Peer 2021-10-29 03:47:42 -04:00 committed by David S. Miller
parent 8f6c5e4d14
commit 892a662f04
5 changed files with 111 additions and 4 deletions

View 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;

View 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);

View 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) &&

View 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

View 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;