diff options
Diffstat (limited to 'drivers/net/ethernet/intel/ice/ice_devlink.c')
| -rw-r--r-- | drivers/net/ethernet/intel/ice/ice_devlink.c | 99 | 
1 files changed, 99 insertions, 0 deletions
diff --git a/drivers/net/ethernet/intel/ice/ice_devlink.c b/drivers/net/ethernet/intel/ice/ice_devlink.c index 7e463b53ea98..5aa18219920b 100644 --- a/drivers/net/ethernet/intel/ice/ice_devlink.c +++ b/drivers/net/ethernet/intel/ice/ice_devlink.c @@ -370,8 +370,106 @@ out_free_ctx:  	return err;  } +/** + * ice_devlink_reload_empr_start - Start EMP reset to activate new firmware + * @devlink: pointer to the devlink instance to reload + * @netns_change: if true, the network namespace is changing + * @action: the action to perform. Must be DEVLINK_RELOAD_ACTION_FW_ACTIVATE + * @limit: limits on what reload should do, such as not resetting + * @extack: netlink extended ACK structure + * + * Allow user to activate new Embedded Management Processor firmware by + * issuing device specific EMP reset. Called in response to + * a DEVLINK_CMD_RELOAD with the DEVLINK_RELOAD_ACTION_FW_ACTIVATE. + * + * Note that teardown and rebuild of the driver state happens automatically as + * part of an interrupt and watchdog task. This is because all physical + * functions on the device must be able to reset when an EMP reset occurs from + * any source. + */ +static int +ice_devlink_reload_empr_start(struct devlink *devlink, bool netns_change, +			      enum devlink_reload_action action, +			      enum devlink_reload_limit limit, +			      struct netlink_ext_ack *extack) +{ +	struct ice_pf *pf = devlink_priv(devlink); +	struct device *dev = ice_pf_to_dev(pf); +	struct ice_hw *hw = &pf->hw; +	u8 pending; +	int err; + +	err = ice_get_pending_updates(pf, &pending, extack); +	if (err) +		return err; + +	/* pending is a bitmask of which flash banks have a pending update, +	 * including the main NVM bank, the Option ROM bank, and the netlist +	 * bank. If any of these bits are set, then there is a pending update +	 * waiting to be activated. +	 */ +	if (!pending) { +		NL_SET_ERR_MSG_MOD(extack, "No pending firmware update"); +		return -ECANCELED; +	} + +	if (pf->fw_emp_reset_disabled) { +		NL_SET_ERR_MSG_MOD(extack, "EMP reset is not available. To activate firmware, a reboot or power cycle is needed"); +		return -ECANCELED; +	} + +	dev_dbg(dev, "Issuing device EMP reset to activate firmware\n"); + +	err = ice_aq_nvm_update_empr(hw); +	if (err) { +		dev_err(dev, "Failed to trigger EMP device reset to reload firmware, err %d aq_err %s\n", +			err, ice_aq_str(hw->adminq.sq_last_status)); +		NL_SET_ERR_MSG_MOD(extack, "Failed to trigger EMP device reset to reload firmware"); +		return err; +	} + +	return 0; +} + +/** + * ice_devlink_reload_empr_finish - Wait for EMP reset to finish + * @devlink: pointer to the devlink instance reloading + * @action: the action requested + * @limit: limits imposed by userspace, such as not resetting + * @actions_performed: on return, indicate what actions actually performed + * @extack: netlink extended ACK structure + * + * Wait for driver to finish rebuilding after EMP reset is completed. This + * includes time to wait for both the actual device reset as well as the time + * for the driver's rebuild to complete. + */ +static int +ice_devlink_reload_empr_finish(struct devlink *devlink, +			       enum devlink_reload_action action, +			       enum devlink_reload_limit limit, +			       u32 *actions_performed, +			       struct netlink_ext_ack *extack) +{ +	struct ice_pf *pf = devlink_priv(devlink); +	int err; + +	*actions_performed = BIT(DEVLINK_RELOAD_ACTION_FW_ACTIVATE); + +	err = ice_wait_for_reset(pf, 60 * HZ); +	if (err) { +		NL_SET_ERR_MSG_MOD(extack, "Device still resetting after 1 minute"); +		return err; +	} + +	return 0; +} +  static const struct devlink_ops ice_devlink_ops = {  	.supported_flash_update_params = DEVLINK_SUPPORT_FLASH_UPDATE_OVERWRITE_MASK, +	.reload_actions = BIT(DEVLINK_RELOAD_ACTION_FW_ACTIVATE), +	/* The ice driver currently does not support driver reinit */ +	.reload_down = ice_devlink_reload_empr_start, +	.reload_up = ice_devlink_reload_empr_finish,  	.eswitch_mode_get = ice_eswitch_mode_get,  	.eswitch_mode_set = ice_eswitch_mode_set,  	.info_get = ice_devlink_info_get, @@ -532,6 +630,7 @@ void ice_devlink_register(struct ice_pf *pf)  {  	struct devlink *devlink = priv_to_devlink(pf); +	devlink_set_features(devlink, DEVLINK_F_RELOAD);  	devlink_register(devlink);  }  | 
