diff options
Diffstat (limited to 'drivers/net/ethernet/broadcom/bnxt/bnxt_devlink.c')
| -rw-r--r-- | drivers/net/ethernet/broadcom/bnxt/bnxt_devlink.c | 155 | 
1 files changed, 121 insertions, 34 deletions
diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt_devlink.c b/drivers/net/ethernet/broadcom/bnxt/bnxt_devlink.c index 4da31b1b84f9..8a6f788f6294 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt_devlink.c +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt_devlink.c @@ -20,6 +20,7 @@  #include "bnxt_ulp.h"  #include "bnxt_ptp.h"  #include "bnxt_coredump.h" +#include "bnxt_nvm_defs.h"  static void __bnxt_fw_recover(struct bnxt *bp)  { @@ -45,7 +46,7 @@ bnxt_dl_flash_update(struct devlink *dl,  	}  	devlink_flash_update_status_notify(dl, "Preparing to flash", NULL, 0, 0); -	rc = bnxt_flash_package_from_fw_obj(bp->dev, params->fw, 0); +	rc = bnxt_flash_package_from_fw_obj(bp->dev, params->fw, 0, extack);  	if (!rc)  		devlink_flash_update_status_notify(dl, "Flashing done", NULL, 0, 0);  	else @@ -241,37 +242,37 @@ static const struct devlink_health_reporter_ops bnxt_dl_fw_reporter_ops = {  	.recover = bnxt_fw_recover,  }; -void bnxt_dl_fw_reporters_create(struct bnxt *bp) +static struct devlink_health_reporter * +__bnxt_dl_reporter_create(struct bnxt *bp, +			  const struct devlink_health_reporter_ops *ops)  { -	struct bnxt_fw_health *health = bp->fw_health; - -	if (!health || health->fw_reporter) -		return; +	struct devlink_health_reporter *reporter; -	health->fw_reporter = -		devlink_health_reporter_create(bp->dl, &bnxt_dl_fw_reporter_ops, -					       0, bp); -	if (IS_ERR(health->fw_reporter)) { -		netdev_warn(bp->dev, "Failed to create FW health reporter, rc = %ld\n", -			    PTR_ERR(health->fw_reporter)); -		health->fw_reporter = NULL; -		bp->fw_cap &= ~BNXT_FW_CAP_ERROR_RECOVERY; +	reporter = devlink_health_reporter_create(bp->dl, ops, 0, bp); +	if (IS_ERR(reporter)) { +		netdev_warn(bp->dev, "Failed to create %s health reporter, rc = %ld\n", +			    ops->name, PTR_ERR(reporter)); +		return NULL;  	} + +	return reporter;  } -void bnxt_dl_fw_reporters_destroy(struct bnxt *bp, bool all) +void bnxt_dl_fw_reporters_create(struct bnxt *bp)  { -	struct bnxt_fw_health *health = bp->fw_health; +	struct bnxt_fw_health *fw_health = bp->fw_health; -	if (!health) -		return; +	if (fw_health && !fw_health->fw_reporter) +		fw_health->fw_reporter = __bnxt_dl_reporter_create(bp, &bnxt_dl_fw_reporter_ops); +} -	if ((bp->fw_cap & BNXT_FW_CAP_ERROR_RECOVERY) && !all) -		return; +void bnxt_dl_fw_reporters_destroy(struct bnxt *bp) +{ +	struct bnxt_fw_health *fw_health = bp->fw_health; -	if (health->fw_reporter) { -		devlink_health_reporter_destroy(health->fw_reporter); -		health->fw_reporter = NULL; +	if (fw_health && fw_health->fw_reporter) { +		devlink_health_reporter_destroy(fw_health->fw_reporter); +		fw_health->fw_reporter = NULL;  	}  } @@ -367,6 +368,16 @@ bnxt_dl_livepatch_report_err(struct bnxt *bp, struct netlink_ext_ack *extack,  	}  } +/* Live patch status in NVM */ +#define BNXT_LIVEPATCH_NOT_INSTALLED	0 +#define BNXT_LIVEPATCH_INSTALLED	FW_LIVEPATCH_QUERY_RESP_STATUS_FLAGS_INSTALL +#define BNXT_LIVEPATCH_REMOVED		FW_LIVEPATCH_QUERY_RESP_STATUS_FLAGS_ACTIVE +#define BNXT_LIVEPATCH_MASK		(FW_LIVEPATCH_QUERY_RESP_STATUS_FLAGS_INSTALL | \ +					 FW_LIVEPATCH_QUERY_RESP_STATUS_FLAGS_ACTIVE) +#define BNXT_LIVEPATCH_ACTIVATED	BNXT_LIVEPATCH_MASK + +#define BNXT_LIVEPATCH_STATE(flags)	((flags) & BNXT_LIVEPATCH_MASK) +  static int  bnxt_dl_livepatch_activate(struct bnxt *bp, struct netlink_ext_ack *extack)  { @@ -374,8 +385,9 @@ bnxt_dl_livepatch_activate(struct bnxt *bp, struct netlink_ext_ack *extack)  	struct hwrm_fw_livepatch_query_input *query_req;  	struct hwrm_fw_livepatch_output *patch_resp;  	struct hwrm_fw_livepatch_input *patch_req; +	u16 flags, live_patch_state; +	bool activated = false;  	u32 installed = 0; -	u16 flags;  	u8 target;  	int rc; @@ -394,7 +406,6 @@ bnxt_dl_livepatch_activate(struct bnxt *bp, struct netlink_ext_ack *extack)  		hwrm_req_drop(bp, query_req);  		return rc;  	} -	patch_req->opcode = FW_LIVEPATCH_REQ_OPCODE_ACTIVATE;  	patch_req->loadtype = FW_LIVEPATCH_REQ_LOADTYPE_NVM_INSTALL;  	patch_resp = hwrm_req_hold(bp, patch_req); @@ -407,12 +418,20 @@ bnxt_dl_livepatch_activate(struct bnxt *bp, struct netlink_ext_ack *extack)  		}  		flags = le16_to_cpu(query_resp->status_flags); -		if (~flags & FW_LIVEPATCH_QUERY_RESP_STATUS_FLAGS_INSTALL) +		live_patch_state = BNXT_LIVEPATCH_STATE(flags); + +		if (live_patch_state == BNXT_LIVEPATCH_NOT_INSTALLED)  			continue; -		if ((flags & FW_LIVEPATCH_QUERY_RESP_STATUS_FLAGS_ACTIVE) && -		    !strncmp(query_resp->active_ver, query_resp->install_ver, -			     sizeof(query_resp->active_ver))) + +		if (live_patch_state == BNXT_LIVEPATCH_ACTIVATED) { +			activated = true;  			continue; +		} + +		if (live_patch_state == BNXT_LIVEPATCH_INSTALLED) +			patch_req->opcode = FW_LIVEPATCH_REQ_OPCODE_ACTIVATE; +		else if (live_patch_state == BNXT_LIVEPATCH_REMOVED) +			patch_req->opcode = FW_LIVEPATCH_REQ_OPCODE_DEACTIVATE;  		patch_req->fw_target = target;  		rc = hwrm_req_send(bp, patch_req); @@ -424,8 +443,13 @@ bnxt_dl_livepatch_activate(struct bnxt *bp, struct netlink_ext_ack *extack)  	}  	if (!rc && !installed) { -		NL_SET_ERR_MSG_MOD(extack, "No live patches found"); -		rc = -ENOENT; +		if (activated) { +			NL_SET_ERR_MSG_MOD(extack, "Live patch already activated"); +			rc = -EEXIST; +		} else { +			NL_SET_ERR_MSG_MOD(extack, "No live patches found"); +			rc = -ENOENT; +		}  	}  	hwrm_req_drop(bp, query_req);  	hwrm_req_drop(bp, patch_req); @@ -587,6 +611,64 @@ static int bnxt_dl_reload_up(struct devlink *dl, enum devlink_reload_action acti  	return rc;  } +static bool bnxt_nvm_test(struct bnxt *bp, struct netlink_ext_ack *extack) +{ +	bool rc = false; +	u32 datalen; +	u16 index; +	u8 *buf; + +	if (bnxt_find_nvram_item(bp->dev, BNX_DIR_TYPE_VPD, +				 BNX_DIR_ORDINAL_FIRST, BNX_DIR_EXT_NONE, +				 &index, NULL, &datalen) || !datalen) { +		NL_SET_ERR_MSG_MOD(extack, "nvm test vpd entry error"); +		return false; +	} + +	buf = kzalloc(datalen, GFP_KERNEL); +	if (!buf) { +		NL_SET_ERR_MSG_MOD(extack, "insufficient memory for nvm test"); +		return false; +	} + +	if (bnxt_get_nvram_item(bp->dev, index, 0, datalen, buf)) { +		NL_SET_ERR_MSG_MOD(extack, "nvm test vpd read error"); +		goto done; +	} + +	if (bnxt_flash_nvram(bp->dev, BNX_DIR_TYPE_VPD, BNX_DIR_ORDINAL_FIRST, +			     BNX_DIR_EXT_NONE, 0, 0, buf, datalen)) { +		NL_SET_ERR_MSG_MOD(extack, "nvm test vpd write error"); +		goto done; +	} + +	rc = true; + +done: +	kfree(buf); +	return rc; +} + +static bool bnxt_dl_selftest_check(struct devlink *dl, unsigned int id, +				   struct netlink_ext_ack *extack) +{ +	return id == DEVLINK_ATTR_SELFTEST_ID_FLASH; +} + +static enum devlink_selftest_status bnxt_dl_selftest_run(struct devlink *dl, +							 unsigned int id, +							 struct netlink_ext_ack *extack) +{ +	struct bnxt *bp = bnxt_get_bp_from_dl(dl); + +	if (id == DEVLINK_ATTR_SELFTEST_ID_FLASH) +		return bnxt_nvm_test(bp, extack) ? +				DEVLINK_SELFTEST_STATUS_PASS : +				DEVLINK_SELFTEST_STATUS_FAIL; + +	return DEVLINK_SELFTEST_STATUS_SKIP; +} +  static const struct devlink_ops bnxt_dl_ops = {  #ifdef CONFIG_BNXT_SRIOV  	.eswitch_mode_set = bnxt_dl_eswitch_mode_set, @@ -599,6 +681,8 @@ static const struct devlink_ops bnxt_dl_ops = {  	.reload_limits	  = BIT(DEVLINK_RELOAD_LIMIT_NO_RESET),  	.reload_down	  = bnxt_dl_reload_down,  	.reload_up	  = bnxt_dl_reload_up, +	.selftest_check	  = bnxt_dl_selftest_check, +	.selftest_run	  = bnxt_dl_selftest_run,  };  static const struct devlink_ops bnxt_vf_dl_ops; @@ -956,9 +1040,11 @@ static int bnxt_dl_info_get(struct devlink *dl, struct devlink_info_req *req,  	if (rc)  		return rc; -	rc = bnxt_dl_livepatch_info_put(bp, req, BNXT_FW_SRT_PATCH); -	if (rc) -		return rc; +	if (BNXT_CHIP_P5(bp)) { +		rc = bnxt_dl_livepatch_info_put(bp, req, BNXT_FW_SRT_PATCH); +		if (rc) +			return rc; +	}  	return bnxt_dl_livepatch_info_put(bp, req, BNXT_FW_CRT_PATCH);  } @@ -1221,6 +1307,7 @@ int bnxt_dl_register(struct bnxt *bp)  	if (rc)  		goto err_dl_port_unreg; +	devlink_set_features(dl, DEVLINK_F_RELOAD);  out:  	devlink_register(dl);  	return 0;  | 
