diff options
| -rw-r--r-- | drivers/net/ethernet/mellanox/mlx5/core/en.h | 2 | ||||
| -rw-r--r-- | drivers/net/ethernet/mellanox/mlx5/core/en_ethtool.c | 35 | ||||
| -rw-r--r-- | drivers/net/ethernet/mellanox/mlx5/core/fw.c | 6 | ||||
| -rw-r--r-- | drivers/net/ethernet/mellanox/mlx5/core/ipoib/ethtool.c | 9 | ||||
| -rw-r--r-- | drivers/net/ethernet/mellanox/mlx5/core/main.c | 20 | ||||
| -rw-r--r-- | drivers/net/ethernet/mellanox/mlx5/core/mlx5_core.h | 3 | ||||
| -rw-r--r-- | drivers/net/ethernet/mellanox/mlxfw/mlxfw.h | 11 | ||||
| -rw-r--r-- | drivers/net/ethernet/mellanox/mlxfw/mlxfw_fsm.c | 57 | ||||
| -rw-r--r-- | drivers/net/ethernet/mellanox/mlxsw/core.c | 15 | ||||
| -rw-r--r-- | drivers/net/ethernet/mellanox/mlxsw/core.h | 3 | ||||
| -rw-r--r-- | drivers/net/ethernet/mellanox/mlxsw/spectrum.c | 75 | ||||
| -rw-r--r-- | drivers/net/netdevsim/dev.c | 44 | ||||
| -rw-r--r-- | drivers/net/netdevsim/netdevsim.h | 1 | ||||
| -rw-r--r-- | include/net/devlink.h | 8 | ||||
| -rw-r--r-- | include/uapi/linux/devlink.h | 5 | ||||
| -rw-r--r-- | net/core/devlink.c | 102 | ||||
| -rwxr-xr-x | tools/testing/selftests/drivers/net/netdevsim/devlink.sh | 53 | 
17 files changed, 358 insertions, 91 deletions
| diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en.h b/drivers/net/ethernet/mellanox/mlx5/core/en.h index 3a183d690e23..4e417dfe4ee5 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en.h +++ b/drivers/net/ethernet/mellanox/mlx5/core/en.h @@ -1074,8 +1074,6 @@ u32 mlx5e_ethtool_get_rxfh_key_size(struct mlx5e_priv *priv);  u32 mlx5e_ethtool_get_rxfh_indir_size(struct mlx5e_priv *priv);  int mlx5e_ethtool_get_ts_info(struct mlx5e_priv *priv,  			      struct ethtool_ts_info *info); -int mlx5e_ethtool_flash_device(struct mlx5e_priv *priv, -			       struct ethtool_flash *flash);  void mlx5e_ethtool_get_pauseparam(struct mlx5e_priv *priv,  				  struct ethtool_pauseparam *pauseparam);  int mlx5e_ethtool_set_pauseparam(struct mlx5e_priv *priv, diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_ethtool.c b/drivers/net/ethernet/mellanox/mlx5/core/en_ethtool.c index dd764e0471f2..ea59097dd4f8 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_ethtool.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_ethtool.c @@ -1867,40 +1867,6 @@ static u32 mlx5e_get_priv_flags(struct net_device *netdev)  	return priv->channels.params.pflags;  } -int mlx5e_ethtool_flash_device(struct mlx5e_priv *priv, -			       struct ethtool_flash *flash) -{ -	struct mlx5_core_dev *mdev = priv->mdev; -	struct net_device *dev = priv->netdev; -	const struct firmware *fw; -	int err; - -	if (flash->region != ETHTOOL_FLASH_ALL_REGIONS) -		return -EOPNOTSUPP; - -	err = request_firmware_direct(&fw, flash->data, &dev->dev); -	if (err) -		return err; - -	dev_hold(dev); -	rtnl_unlock(); - -	err = mlx5_firmware_flash(mdev, fw); -	release_firmware(fw); - -	rtnl_lock(); -	dev_put(dev); -	return err; -} - -static int mlx5e_flash_device(struct net_device *dev, -			      struct ethtool_flash *flash) -{ -	struct mlx5e_priv *priv = netdev_priv(dev); - -	return mlx5e_ethtool_flash_device(priv, flash); -} -  #ifndef CONFIG_MLX5_EN_RXNFC  /* When CONFIG_MLX5_EN_RXNFC=n we only support ETHTOOL_GRXRINGS   * otherwise this function will be defined from en_fs_ethtool.c @@ -1939,7 +1905,6 @@ const struct ethtool_ops mlx5e_ethtool_ops = {  #ifdef CONFIG_MLX5_EN_RXNFC  	.set_rxnfc         = mlx5e_set_rxnfc,  #endif -	.flash_device      = mlx5e_flash_device,  	.get_tunable       = mlx5e_get_tunable,  	.set_tunable       = mlx5e_set_tunable,  	.get_pauseparam    = mlx5e_get_pauseparam, diff --git a/drivers/net/ethernet/mellanox/mlx5/core/fw.c b/drivers/net/ethernet/mellanox/mlx5/core/fw.c index 1ab6f7e3bec6..e8fedb307b2c 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/fw.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/fw.c @@ -552,7 +552,8 @@ static const struct mlxfw_dev_ops mlx5_mlxfw_dev_ops = {  };  int mlx5_firmware_flash(struct mlx5_core_dev *dev, -			const struct firmware *firmware) +			const struct firmware *firmware, +			struct netlink_ext_ack *extack)  {  	struct mlx5_mlxfw_dev mlx5_mlxfw_dev = {  		.mlxfw_dev = { @@ -571,5 +572,6 @@ int mlx5_firmware_flash(struct mlx5_core_dev *dev,  		return -EOPNOTSUPP;  	} -	return mlxfw_firmware_flash(&mlx5_mlxfw_dev.mlxfw_dev, firmware); +	return mlxfw_firmware_flash(&mlx5_mlxfw_dev.mlxfw_dev, +				    firmware, extack);  } diff --git a/drivers/net/ethernet/mellanox/mlx5/core/ipoib/ethtool.c b/drivers/net/ethernet/mellanox/mlx5/core/ipoib/ethtool.c index 90cb50fe17fd..ebd81f6b556e 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/ipoib/ethtool.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/ipoib/ethtool.c @@ -122,14 +122,6 @@ static int mlx5i_get_ts_info(struct net_device *netdev,  	return mlx5e_ethtool_get_ts_info(priv, info);  } -static int mlx5i_flash_device(struct net_device *netdev, -			      struct ethtool_flash *flash) -{ -	struct mlx5e_priv *priv = mlx5i_epriv(netdev); - -	return mlx5e_ethtool_flash_device(priv, flash); -} -  enum mlx5_ptys_width {  	MLX5_PTYS_WIDTH_1X	= 1 << 0,  	MLX5_PTYS_WIDTH_2X	= 1 << 1, @@ -241,7 +233,6 @@ const struct ethtool_ops mlx5i_ethtool_ops = {  	.get_ethtool_stats  = mlx5i_get_ethtool_stats,  	.get_ringparam      = mlx5i_get_ringparam,  	.set_ringparam      = mlx5i_set_ringparam, -	.flash_device       = mlx5i_flash_device,  	.get_channels       = mlx5i_get_channels,  	.set_channels       = mlx5i_set_channels,  	.get_coalesce       = mlx5i_get_coalesce, diff --git a/drivers/net/ethernet/mellanox/mlx5/core/main.c b/drivers/net/ethernet/mellanox/mlx5/core/main.c index b27f9537256c..7ec135eaabc6 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/main.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/main.c @@ -1214,6 +1214,25 @@ out:  	return err;  } +static int mlx5_devlink_flash_update(struct devlink *devlink, +				     const char *file_name, +				     const char *component, +				     struct netlink_ext_ack *extack) +{ +	struct mlx5_core_dev *dev = devlink_priv(devlink); +	const struct firmware *fw; +	int err; + +	if (component) +		return -EOPNOTSUPP; + +	err = request_firmware_direct(&fw, file_name, &dev->pdev->dev); +	if (err) +		return err; + +	return mlx5_firmware_flash(dev, fw, extack); +} +  static const struct devlink_ops mlx5_devlink_ops = {  #ifdef CONFIG_MLX5_ESWITCH  	.eswitch_mode_set = mlx5_devlink_eswitch_mode_set, @@ -1223,6 +1242,7 @@ static const struct devlink_ops mlx5_devlink_ops = {  	.eswitch_encap_mode_set = mlx5_devlink_eswitch_encap_mode_set,  	.eswitch_encap_mode_get = mlx5_devlink_eswitch_encap_mode_get,  #endif +	.flash_update = mlx5_devlink_flash_update,  };  static int mlx5_mdev_init(struct mlx5_core_dev *dev, int profile_idx) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/mlx5_core.h b/drivers/net/ethernet/mellanox/mlx5/core/mlx5_core.h index 22e69d4813e4..d4dd8c1ae55c 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/mlx5_core.h +++ b/drivers/net/ethernet/mellanox/mlx5/core/mlx5_core.h @@ -184,7 +184,8 @@ int mlx5_set_mtppse(struct mlx5_core_dev *mdev, u8 pin, u8 arm, u8 mode);  			    MLX5_CAP_MCAM_FEATURE((mdev), mtpps_fs) &&	\  			    MLX5_CAP_MCAM_FEATURE((mdev), mtpps_enh_out_per_adj)) -int mlx5_firmware_flash(struct mlx5_core_dev *dev, const struct firmware *fw); +int mlx5_firmware_flash(struct mlx5_core_dev *dev, const struct firmware *fw, +			struct netlink_ext_ack *extack);  void mlx5e_init(void);  void mlx5e_cleanup(void); diff --git a/drivers/net/ethernet/mellanox/mlxfw/mlxfw.h b/drivers/net/ethernet/mellanox/mlxfw/mlxfw.h index 14c0c62f8e73..c50e74ab02c4 100644 --- a/drivers/net/ethernet/mellanox/mlxfw/mlxfw.h +++ b/drivers/net/ethernet/mellanox/mlxfw/mlxfw.h @@ -5,6 +5,7 @@  #define _MLXFW_H  #include <linux/firmware.h> +#include <linux/netlink.h>  enum mlxfw_fsm_state {  	MLXFW_FSM_STATE_IDLE, @@ -57,6 +58,10 @@ struct mlxfw_dev_ops {  	void (*fsm_cancel)(struct mlxfw_dev *mlxfw_dev, u32 fwhandle);  	void (*fsm_release)(struct mlxfw_dev *mlxfw_dev, u32 fwhandle); + +	void (*status_notify)(struct mlxfw_dev *mlxfw_dev, +			      const char *msg, const char *comp_name, +			      u32 done_bytes, u32 total_bytes);  };  struct mlxfw_dev { @@ -67,11 +72,13 @@ struct mlxfw_dev {  #if IS_REACHABLE(CONFIG_MLXFW)  int mlxfw_firmware_flash(struct mlxfw_dev *mlxfw_dev, -			 const struct firmware *firmware); +			 const struct firmware *firmware, +			 struct netlink_ext_ack *extack);  #else  static inline  int mlxfw_firmware_flash(struct mlxfw_dev *mlxfw_dev, -			 const struct firmware *firmware) +			 const struct firmware *firmware, +			 struct netlink_ext_ack *extack)  {  	return -EOPNOTSUPP;  } diff --git a/drivers/net/ethernet/mellanox/mlxfw/mlxfw_fsm.c b/drivers/net/ethernet/mellanox/mlxfw/mlxfw_fsm.c index 240c027e5f07..67990406cba2 100644 --- a/drivers/net/ethernet/mellanox/mlxfw/mlxfw_fsm.c +++ b/drivers/net/ethernet/mellanox/mlxfw/mlxfw_fsm.c @@ -39,8 +39,19 @@ static const char * const mlxfw_fsm_state_err_str[] = {  		"unknown error"  }; +static void mlxfw_status_notify(struct mlxfw_dev *mlxfw_dev, +				const char *msg, const char *comp_name, +				u32 done_bytes, u32 total_bytes) +{ +	if (!mlxfw_dev->ops->status_notify) +		return; +	mlxfw_dev->ops->status_notify(mlxfw_dev, msg, comp_name, +				      done_bytes, total_bytes); +} +  static int mlxfw_fsm_state_wait(struct mlxfw_dev *mlxfw_dev, u32 fwhandle, -				enum mlxfw_fsm_state fsm_state) +				enum mlxfw_fsm_state fsm_state, +				struct netlink_ext_ack *extack)  {  	enum mlxfw_fsm_state_err fsm_state_err;  	enum mlxfw_fsm_state curr_fsm_state; @@ -57,11 +68,13 @@ retry:  	if (fsm_state_err != MLXFW_FSM_STATE_ERR_OK) {  		pr_err("Firmware flash failed: %s\n",  		       mlxfw_fsm_state_err_str[fsm_state_err]); +		NL_SET_ERR_MSG_MOD(extack, "Firmware flash failed");  		return -EINVAL;  	}  	if (curr_fsm_state != fsm_state) {  		if (--times == 0) {  			pr_err("Timeout reached on FSM state change"); +			NL_SET_ERR_MSG_MOD(extack, "Timeout reached on FSM state change");  			return -ETIMEDOUT;  		}  		msleep(MLXFW_FSM_STATE_WAIT_CYCLE_MS); @@ -76,16 +89,20 @@ retry:  static int mlxfw_flash_component(struct mlxfw_dev *mlxfw_dev,  				 u32 fwhandle, -				 struct mlxfw_mfa2_component *comp) +				 struct mlxfw_mfa2_component *comp, +				 struct netlink_ext_ack *extack)  {  	u16 comp_max_write_size;  	u8 comp_align_bits;  	u32 comp_max_size; +	char comp_name[8];  	u16 block_size;  	u8 *block_ptr;  	u32 offset;  	int err; +	sprintf(comp_name, "%u", comp->index); +  	err = mlxfw_dev->ops->component_query(mlxfw_dev, comp->index,  					      &comp_max_size, &comp_align_bits,  					      &comp_max_write_size); @@ -96,6 +113,7 @@ static int mlxfw_flash_component(struct mlxfw_dev *mlxfw_dev,  	if (comp->data_size > comp_max_size) {  		pr_err("Component %d is of size %d which is bigger than limit %d\n",  		       comp->index, comp->data_size, comp_max_size); +		NL_SET_ERR_MSG_MOD(extack, "Component is bigger than limit");  		return -EINVAL;  	} @@ -103,6 +121,7 @@ static int mlxfw_flash_component(struct mlxfw_dev *mlxfw_dev,  					       comp_align_bits);  	pr_debug("Component update\n"); +	mlxfw_status_notify(mlxfw_dev, "Updating component", comp_name, 0, 0);  	err = mlxfw_dev->ops->fsm_component_update(mlxfw_dev, fwhandle,  						   comp->index,  						   comp->data_size); @@ -110,11 +129,13 @@ static int mlxfw_flash_component(struct mlxfw_dev *mlxfw_dev,  		return err;  	err = mlxfw_fsm_state_wait(mlxfw_dev, fwhandle, -				   MLXFW_FSM_STATE_DOWNLOAD); +				   MLXFW_FSM_STATE_DOWNLOAD, extack);  	if (err)  		goto err_out;  	pr_debug("Component download\n"); +	mlxfw_status_notify(mlxfw_dev, "Downloading component", +			    comp_name, 0, comp->data_size);  	for (offset = 0;  	     offset < MLXFW_ALIGN_UP(comp->data_size, comp_align_bits);  	     offset += comp_max_write_size) { @@ -126,15 +147,20 @@ static int mlxfw_flash_component(struct mlxfw_dev *mlxfw_dev,  							 offset);  		if (err)  			goto err_out; +		mlxfw_status_notify(mlxfw_dev, "Downloading component", +				    comp_name, offset + block_size, +				    comp->data_size);  	}  	pr_debug("Component verify\n"); +	mlxfw_status_notify(mlxfw_dev, "Verifying component", comp_name, 0, 0);  	err = mlxfw_dev->ops->fsm_component_verify(mlxfw_dev, fwhandle,  						   comp->index);  	if (err)  		goto err_out; -	err = mlxfw_fsm_state_wait(mlxfw_dev, fwhandle, MLXFW_FSM_STATE_LOCKED); +	err = mlxfw_fsm_state_wait(mlxfw_dev, fwhandle, +				   MLXFW_FSM_STATE_LOCKED, extack);  	if (err)  		goto err_out;  	return 0; @@ -145,7 +171,8 @@ err_out:  }  static int mlxfw_flash_components(struct mlxfw_dev *mlxfw_dev, u32 fwhandle, -				  struct mlxfw_mfa2_file *mfa2_file) +				  struct mlxfw_mfa2_file *mfa2_file, +				  struct netlink_ext_ack *extack)  {  	u32 component_count;  	int err; @@ -156,6 +183,7 @@ static int mlxfw_flash_components(struct mlxfw_dev *mlxfw_dev, u32 fwhandle,  					      &component_count);  	if (err) {  		pr_err("Could not find device PSID in MFA2 file\n"); +		NL_SET_ERR_MSG_MOD(extack, "Could not find device PSID in MFA2 file");  		return err;  	} @@ -168,7 +196,7 @@ static int mlxfw_flash_components(struct mlxfw_dev *mlxfw_dev, u32 fwhandle,  			return PTR_ERR(comp);  		pr_info("Flashing component type %d\n", comp->index); -		err = mlxfw_flash_component(mlxfw_dev, fwhandle, comp); +		err = mlxfw_flash_component(mlxfw_dev, fwhandle, comp, extack);  		mlxfw_mfa2_file_component_put(comp);  		if (err)  			return err; @@ -177,7 +205,8 @@ static int mlxfw_flash_components(struct mlxfw_dev *mlxfw_dev, u32 fwhandle,  }  int mlxfw_firmware_flash(struct mlxfw_dev *mlxfw_dev, -			 const struct firmware *firmware) +			 const struct firmware *firmware, +			 struct netlink_ext_ack *extack)  {  	struct mlxfw_mfa2_file *mfa2_file;  	u32 fwhandle; @@ -185,6 +214,7 @@ int mlxfw_firmware_flash(struct mlxfw_dev *mlxfw_dev,  	if (!mlxfw_mfa2_check(firmware)) {  		pr_err("Firmware file is not MFA2\n"); +		NL_SET_ERR_MSG_MOD(extack, "Firmware file is not MFA2");  		return -EINVAL;  	} @@ -193,29 +223,35 @@ int mlxfw_firmware_flash(struct mlxfw_dev *mlxfw_dev,  		return PTR_ERR(mfa2_file);  	pr_info("Initialize firmware flash process\n"); +	mlxfw_status_notify(mlxfw_dev, "Initializing firmware flash process", +			    NULL, 0, 0);  	err = mlxfw_dev->ops->fsm_lock(mlxfw_dev, &fwhandle);  	if (err) {  		pr_err("Could not lock the firmware FSM\n"); +		NL_SET_ERR_MSG_MOD(extack, "Could not lock the firmware FSM");  		goto err_fsm_lock;  	}  	err = mlxfw_fsm_state_wait(mlxfw_dev, fwhandle, -				   MLXFW_FSM_STATE_LOCKED); +				   MLXFW_FSM_STATE_LOCKED, extack);  	if (err)  		goto err_state_wait_idle_to_locked; -	err = mlxfw_flash_components(mlxfw_dev, fwhandle, mfa2_file); +	err = mlxfw_flash_components(mlxfw_dev, fwhandle, mfa2_file, extack);  	if (err)  		goto err_flash_components;  	pr_debug("Activate image\n"); +	mlxfw_status_notify(mlxfw_dev, "Activating image", NULL, 0, 0);  	err = mlxfw_dev->ops->fsm_activate(mlxfw_dev, fwhandle);  	if (err) {  		pr_err("Could not activate the downloaded image\n"); +		NL_SET_ERR_MSG_MOD(extack, "Could not activate the downloaded image");  		goto err_fsm_activate;  	} -	err = mlxfw_fsm_state_wait(mlxfw_dev, fwhandle, MLXFW_FSM_STATE_LOCKED); +	err = mlxfw_fsm_state_wait(mlxfw_dev, fwhandle, +				   MLXFW_FSM_STATE_LOCKED, extack);  	if (err)  		goto err_state_wait_activate_to_locked; @@ -223,6 +259,7 @@ int mlxfw_firmware_flash(struct mlxfw_dev *mlxfw_dev,  	mlxfw_dev->ops->fsm_release(mlxfw_dev, fwhandle);  	pr_info("Firmware flash done.\n"); +	mlxfw_status_notify(mlxfw_dev, "Firmware flash done", NULL, 0, 0);  	mlxfw_mfa2_file_fini(mfa2_file);  	return 0; diff --git a/drivers/net/ethernet/mellanox/mlxsw/core.c b/drivers/net/ethernet/mellanox/mlxsw/core.c index 182762898361..1c4ef8ed1706 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/core.c +++ b/drivers/net/ethernet/mellanox/mlxsw/core.c @@ -1003,6 +1003,20 @@ static int mlxsw_devlink_core_bus_device_reload(struct devlink *devlink,  	return err;  } +static int mlxsw_devlink_flash_update(struct devlink *devlink, +				      const char *file_name, +				      const char *component, +				      struct netlink_ext_ack *extack) +{ +	struct mlxsw_core *mlxsw_core = devlink_priv(devlink); +	struct mlxsw_driver *mlxsw_driver = mlxsw_core->driver; + +	if (!mlxsw_driver->flash_update) +		return -EOPNOTSUPP; +	return mlxsw_driver->flash_update(mlxsw_core, file_name, +					  component, extack); +} +  static const struct devlink_ops mlxsw_devlink_ops = {  	.reload				= mlxsw_devlink_core_bus_device_reload,  	.port_type_set			= mlxsw_devlink_port_type_set, @@ -1019,6 +1033,7 @@ static const struct devlink_ops mlxsw_devlink_ops = {  	.sb_occ_port_pool_get		= mlxsw_devlink_sb_occ_port_pool_get,  	.sb_occ_tc_port_bind_get	= mlxsw_devlink_sb_occ_tc_port_bind_get,  	.info_get			= mlxsw_devlink_info_get, +	.flash_update			= mlxsw_devlink_flash_update,  };  static int diff --git a/drivers/net/ethernet/mellanox/mlxsw/core.h b/drivers/net/ethernet/mellanox/mlxsw/core.h index e3832cb5bdda..a44ad0fb9477 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/core.h +++ b/drivers/net/ethernet/mellanox/mlxsw/core.h @@ -284,6 +284,9 @@ struct mlxsw_driver {  				       unsigned int sb_index, u16 tc_index,  				       enum devlink_sb_pool_type pool_type,  				       u32 *p_cur, u32 *p_max); +	int (*flash_update)(struct mlxsw_core *mlxsw_core, +			    const char *file_name, const char *component, +			    struct netlink_ext_ack *extack);  	void (*txhdr_construct)(struct sk_buff *skb,  				const struct mlxsw_tx_info *tx_info);  	int (*resources_register)(struct mlxsw_core *mlxsw_core); diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum.c index dfe6b44baf63..417e7c9273ef 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum.c @@ -294,6 +294,19 @@ static void mlxsw_sp_fsm_release(struct mlxfw_dev *mlxfw_dev, u32 fwhandle)  	mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(mcc), mcc_pl);  } +static void mlxsw_sp_status_notify(struct mlxfw_dev *mlxfw_dev, +				   const char *msg, const char *comp_name, +				   u32 done_bytes, u32 total_bytes) +{ +	struct mlxsw_sp_mlxfw_dev *mlxsw_sp_mlxfw_dev = +		container_of(mlxfw_dev, struct mlxsw_sp_mlxfw_dev, mlxfw_dev); +	struct mlxsw_sp *mlxsw_sp = mlxsw_sp_mlxfw_dev->mlxsw_sp; + +	devlink_flash_update_status_notify(priv_to_devlink(mlxsw_sp->core), +					   msg, comp_name, +					   done_bytes, total_bytes); +} +  static const struct mlxfw_dev_ops mlxsw_sp_mlxfw_dev_ops = {  	.component_query	= mlxsw_sp_component_query,  	.fsm_lock		= mlxsw_sp_fsm_lock, @@ -303,11 +316,13 @@ static const struct mlxfw_dev_ops mlxsw_sp_mlxfw_dev_ops = {  	.fsm_activate		= mlxsw_sp_fsm_activate,  	.fsm_query_state	= mlxsw_sp_fsm_query_state,  	.fsm_cancel		= mlxsw_sp_fsm_cancel, -	.fsm_release		= mlxsw_sp_fsm_release +	.fsm_release		= mlxsw_sp_fsm_release, +	.status_notify		= mlxsw_sp_status_notify,  };  static int mlxsw_sp_firmware_flash(struct mlxsw_sp *mlxsw_sp, -				   const struct firmware *firmware) +				   const struct firmware *firmware, +				   struct netlink_ext_ack *extack)  {  	struct mlxsw_sp_mlxfw_dev mlxsw_sp_mlxfw_dev = {  		.mlxfw_dev = { @@ -320,7 +335,10 @@ static int mlxsw_sp_firmware_flash(struct mlxsw_sp *mlxsw_sp,  	int err;  	mlxsw_core_fw_flash_start(mlxsw_sp->core); -	err = mlxfw_firmware_flash(&mlxsw_sp_mlxfw_dev.mlxfw_dev, firmware); +	devlink_flash_update_begin_notify(priv_to_devlink(mlxsw_sp->core)); +	err = mlxfw_firmware_flash(&mlxsw_sp_mlxfw_dev.mlxfw_dev, +				   firmware, extack); +	devlink_flash_update_end_notify(priv_to_devlink(mlxsw_sp->core));  	mlxsw_core_fw_flash_end(mlxsw_sp->core);  	return err; @@ -374,7 +392,7 @@ static int mlxsw_sp_fw_rev_validate(struct mlxsw_sp *mlxsw_sp)  		return err;  	} -	err = mlxsw_sp_firmware_flash(mlxsw_sp, firmware); +	err = mlxsw_sp_firmware_flash(mlxsw_sp, firmware, NULL);  	release_firmware(firmware);  	if (err)  		dev_err(mlxsw_sp->bus_info->dev, "Could not upgrade firmware\n"); @@ -388,6 +406,27 @@ static int mlxsw_sp_fw_rev_validate(struct mlxsw_sp *mlxsw_sp)  		return 0;  } +static int mlxsw_sp_flash_update(struct mlxsw_core *mlxsw_core, +				 const char *file_name, const char *component, +				 struct netlink_ext_ack *extack) +{ +	struct mlxsw_sp *mlxsw_sp = mlxsw_core_driver_priv(mlxsw_core); +	const struct firmware *firmware; +	int err; + +	if (component) +		return -EOPNOTSUPP; + +	err = request_firmware_direct(&firmware, file_name, +				      mlxsw_sp->bus_info->dev); +	if (err) +		return err; +	err = mlxsw_sp_firmware_flash(mlxsw_sp, firmware, extack); +	release_firmware(firmware); + +	return err; +} +  int mlxsw_sp_flow_counter_get(struct mlxsw_sp *mlxsw_sp,  			      unsigned int counter_index, u64 *packets,  			      u64 *bytes) @@ -3159,31 +3198,6 @@ mlxsw_sp_port_set_link_ksettings(struct net_device *dev,  	return 0;  } -static int mlxsw_sp_flash_device(struct net_device *dev, -				 struct ethtool_flash *flash) -{ -	struct mlxsw_sp_port *mlxsw_sp_port = netdev_priv(dev); -	struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp; -	const struct firmware *firmware; -	int err; - -	if (flash->region != ETHTOOL_FLASH_ALL_REGIONS) -		return -EOPNOTSUPP; - -	dev_hold(dev); -	rtnl_unlock(); - -	err = request_firmware_direct(&firmware, flash->data, &dev->dev); -	if (err) -		goto out; -	err = mlxsw_sp_firmware_flash(mlxsw_sp, firmware); -	release_firmware(firmware); -out: -	rtnl_lock(); -	dev_put(dev); -	return err; -} -  static int mlxsw_sp_get_module_info(struct net_device *netdev,  				    struct ethtool_modinfo *modinfo)  { @@ -3224,7 +3238,6 @@ static const struct ethtool_ops mlxsw_sp_port_ethtool_ops = {  	.get_sset_count		= mlxsw_sp_port_get_sset_count,  	.get_link_ksettings	= mlxsw_sp_port_get_link_ksettings,  	.set_link_ksettings	= mlxsw_sp_port_set_link_ksettings, -	.flash_device		= mlxsw_sp_flash_device,  	.get_module_info	= mlxsw_sp_get_module_info,  	.get_module_eeprom	= mlxsw_sp_get_module_eeprom,  }; @@ -4889,6 +4902,7 @@ static struct mlxsw_driver mlxsw_sp1_driver = {  	.sb_occ_max_clear		= mlxsw_sp_sb_occ_max_clear,  	.sb_occ_port_pool_get		= mlxsw_sp_sb_occ_port_pool_get,  	.sb_occ_tc_port_bind_get	= mlxsw_sp_sb_occ_tc_port_bind_get, +	.flash_update			= mlxsw_sp_flash_update,  	.txhdr_construct		= mlxsw_sp_txhdr_construct,  	.resources_register		= mlxsw_sp1_resources_register,  	.kvd_sizes_get			= mlxsw_sp_kvd_sizes_get, @@ -4917,6 +4931,7 @@ static struct mlxsw_driver mlxsw_sp2_driver = {  	.sb_occ_max_clear		= mlxsw_sp_sb_occ_max_clear,  	.sb_occ_port_pool_get		= mlxsw_sp_sb_occ_port_pool_get,  	.sb_occ_tc_port_bind_get	= mlxsw_sp_sb_occ_tc_port_bind_get, +	.flash_update			= mlxsw_sp_flash_update,  	.txhdr_construct		= mlxsw_sp_txhdr_construct,  	.resources_register		= mlxsw_sp2_resources_register,  	.params_register		= mlxsw_sp2_params_register, diff --git a/drivers/net/netdevsim/dev.c b/drivers/net/netdevsim/dev.c index b509b941d5ca..c5c417a3c0ce 100644 --- a/drivers/net/netdevsim/dev.c +++ b/drivers/net/netdevsim/dev.c @@ -38,6 +38,8 @@ static int nsim_dev_debugfs_init(struct nsim_dev *nsim_dev)  	nsim_dev->ports_ddir = debugfs_create_dir("ports", nsim_dev->ddir);  	if (IS_ERR_OR_NULL(nsim_dev->ports_ddir))  		return PTR_ERR_OR_ZERO(nsim_dev->ports_ddir) ?: -EINVAL; +	debugfs_create_bool("fw_update_status", 0600, nsim_dev->ddir, +			    &nsim_dev->fw_update_status);  	return 0;  } @@ -220,8 +222,49 @@ static int nsim_dev_reload(struct devlink *devlink,  	return 0;  } +#define NSIM_DEV_FLASH_SIZE 500000 +#define NSIM_DEV_FLASH_CHUNK_SIZE 1000 +#define NSIM_DEV_FLASH_CHUNK_TIME_MS 10 + +static int nsim_dev_flash_update(struct devlink *devlink, const char *file_name, +				 const char *component, +				 struct netlink_ext_ack *extack) +{ +	struct nsim_dev *nsim_dev = devlink_priv(devlink); +	int i; + +	if (nsim_dev->fw_update_status) { +		devlink_flash_update_begin_notify(devlink); +		devlink_flash_update_status_notify(devlink, +						   "Preparing to flash", +						   component, 0, 0); +	} + +	for (i = 0; i < NSIM_DEV_FLASH_SIZE / NSIM_DEV_FLASH_CHUNK_SIZE; i++) { +		if (nsim_dev->fw_update_status) +			devlink_flash_update_status_notify(devlink, "Flashing", +							   component, +							   i * NSIM_DEV_FLASH_CHUNK_SIZE, +							   NSIM_DEV_FLASH_SIZE); +		msleep(NSIM_DEV_FLASH_CHUNK_TIME_MS); +	} + +	if (nsim_dev->fw_update_status) { +		devlink_flash_update_status_notify(devlink, "Flashing", +						   component, +						   NSIM_DEV_FLASH_SIZE, +						   NSIM_DEV_FLASH_SIZE); +		devlink_flash_update_status_notify(devlink, "Flashing done", +						   component, 0, 0); +		devlink_flash_update_end_notify(devlink); +	} + +	return 0; +} +  static const struct devlink_ops nsim_dev_devlink_ops = {  	.reload = nsim_dev_reload, +	.flash_update = nsim_dev_flash_update,  };  static struct nsim_dev * @@ -240,6 +283,7 @@ nsim_dev_create(struct nsim_bus_dev *nsim_bus_dev, unsigned int port_count)  	get_random_bytes(nsim_dev->switch_id.id, nsim_dev->switch_id.id_len);  	INIT_LIST_HEAD(&nsim_dev->port_list);  	mutex_init(&nsim_dev->port_list_lock); +	nsim_dev->fw_update_status = true;  	nsim_dev->fib_data = nsim_fib_create();  	if (IS_ERR(nsim_dev->fib_data)) { diff --git a/drivers/net/netdevsim/netdevsim.h b/drivers/net/netdevsim/netdevsim.h index 3f398797c2bc..79c05af2a7c0 100644 --- a/drivers/net/netdevsim/netdevsim.h +++ b/drivers/net/netdevsim/netdevsim.h @@ -157,6 +157,7 @@ struct nsim_dev {  	struct netdev_phys_item_id switch_id;  	struct list_head port_list;  	struct mutex port_list_lock; /* protects port list */ +	bool fw_update_status;  };  int nsim_dev_init(void); diff --git a/include/net/devlink.h b/include/net/devlink.h index 151eb930d329..8f65356132be 100644 --- a/include/net/devlink.h +++ b/include/net/devlink.h @@ -741,6 +741,14 @@ void  devlink_health_reporter_state_update(struct devlink_health_reporter *reporter,  				     enum devlink_health_reporter_state state); +void devlink_flash_update_begin_notify(struct devlink *devlink); +void devlink_flash_update_end_notify(struct devlink *devlink); +void devlink_flash_update_status_notify(struct devlink *devlink, +					const char *status_msg, +					const char *component, +					unsigned long done, +					unsigned long total); +  #if IS_ENABLED(CONFIG_NET_DEVLINK)  void devlink_compat_running_version(struct net_device *dev, diff --git a/include/uapi/linux/devlink.h b/include/uapi/linux/devlink.h index 5bb4ea67d84f..5287b42c181f 100644 --- a/include/uapi/linux/devlink.h +++ b/include/uapi/linux/devlink.h @@ -104,6 +104,8 @@ enum devlink_command {  	DEVLINK_CMD_HEALTH_REPORTER_DUMP_CLEAR,  	DEVLINK_CMD_FLASH_UPDATE, +	DEVLINK_CMD_FLASH_UPDATE_END,		/* notification only */ +	DEVLINK_CMD_FLASH_UPDATE_STATUS,	/* notification only */  	/* add new commands above here */  	__DEVLINK_CMD_MAX, @@ -331,6 +333,9 @@ enum devlink_attr {  	DEVLINK_ATTR_FLASH_UPDATE_FILE_NAME,	/* string */  	DEVLINK_ATTR_FLASH_UPDATE_COMPONENT,	/* string */ +	DEVLINK_ATTR_FLASH_UPDATE_STATUS_MSG,	/* string */ +	DEVLINK_ATTR_FLASH_UPDATE_STATUS_DONE,	/* u64 */ +	DEVLINK_ATTR_FLASH_UPDATE_STATUS_TOTAL,	/* u64 */  	/* add new attributes above here, update the policy in devlink.c */ diff --git a/net/core/devlink.c b/net/core/devlink.c index 9716a7f382cb..963178d32dda 100644 --- a/net/core/devlink.c +++ b/net/core/devlink.c @@ -2673,6 +2673,108 @@ static int devlink_nl_cmd_reload(struct sk_buff *skb, struct genl_info *info)  	return devlink->ops->reload(devlink, info->extack);  } +static int devlink_nl_flash_update_fill(struct sk_buff *msg, +					struct devlink *devlink, +					enum devlink_command cmd, +					const char *status_msg, +					const char *component, +					unsigned long done, unsigned long total) +{ +	void *hdr; + +	hdr = genlmsg_put(msg, 0, 0, &devlink_nl_family, 0, cmd); +	if (!hdr) +		return -EMSGSIZE; + +	if (devlink_nl_put_handle(msg, devlink)) +		goto nla_put_failure; + +	if (cmd != DEVLINK_CMD_FLASH_UPDATE_STATUS) +		goto out; + +	if (status_msg && +	    nla_put_string(msg, DEVLINK_ATTR_FLASH_UPDATE_STATUS_MSG, +			   status_msg)) +		goto nla_put_failure; +	if (component && +	    nla_put_string(msg, DEVLINK_ATTR_FLASH_UPDATE_COMPONENT, +			   component)) +		goto nla_put_failure; +	if (nla_put_u64_64bit(msg, DEVLINK_ATTR_FLASH_UPDATE_STATUS_DONE, +			      done, DEVLINK_ATTR_PAD)) +		goto nla_put_failure; +	if (nla_put_u64_64bit(msg, DEVLINK_ATTR_FLASH_UPDATE_STATUS_TOTAL, +			      total, DEVLINK_ATTR_PAD)) +		goto nla_put_failure; + +out: +	genlmsg_end(msg, hdr); +	return 0; + +nla_put_failure: +	genlmsg_cancel(msg, hdr); +	return -EMSGSIZE; +} + +static void __devlink_flash_update_notify(struct devlink *devlink, +					  enum devlink_command cmd, +					  const char *status_msg, +					  const char *component, +					  unsigned long done, +					  unsigned long total) +{ +	struct sk_buff *msg; +	int err; + +	WARN_ON(cmd != DEVLINK_CMD_FLASH_UPDATE && +		cmd != DEVLINK_CMD_FLASH_UPDATE_END && +		cmd != DEVLINK_CMD_FLASH_UPDATE_STATUS); + +	msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); +	if (!msg) +		return; + +	err = devlink_nl_flash_update_fill(msg, devlink, cmd, status_msg, +					   component, done, total); +	if (err) +		goto out_free_msg; + +	genlmsg_multicast_netns(&devlink_nl_family, devlink_net(devlink), +				msg, 0, DEVLINK_MCGRP_CONFIG, GFP_KERNEL); +	return; + +out_free_msg: +	nlmsg_free(msg); +} + +void devlink_flash_update_begin_notify(struct devlink *devlink) +{ +	__devlink_flash_update_notify(devlink, +				      DEVLINK_CMD_FLASH_UPDATE, +				      NULL, NULL, 0, 0); +} +EXPORT_SYMBOL_GPL(devlink_flash_update_begin_notify); + +void devlink_flash_update_end_notify(struct devlink *devlink) +{ +	__devlink_flash_update_notify(devlink, +				      DEVLINK_CMD_FLASH_UPDATE_END, +				      NULL, NULL, 0, 0); +} +EXPORT_SYMBOL_GPL(devlink_flash_update_end_notify); + +void devlink_flash_update_status_notify(struct devlink *devlink, +					const char *status_msg, +					const char *component, +					unsigned long done, +					unsigned long total) +{ +	__devlink_flash_update_notify(devlink, +				      DEVLINK_CMD_FLASH_UPDATE_STATUS, +				      status_msg, component, done, total); +} +EXPORT_SYMBOL_GPL(devlink_flash_update_status_notify); +  static int devlink_nl_cmd_flash_update(struct sk_buff *skb,  				       struct genl_info *info)  { diff --git a/tools/testing/selftests/drivers/net/netdevsim/devlink.sh b/tools/testing/selftests/drivers/net/netdevsim/devlink.sh new file mode 100755 index 000000000000..9d8baf5d14b3 --- /dev/null +++ b/tools/testing/selftests/drivers/net/netdevsim/devlink.sh @@ -0,0 +1,53 @@ +#!/bin/bash +# SPDX-License-Identifier: GPL-2.0 + +lib_dir=$(dirname $0)/../../../net/forwarding + +ALL_TESTS="fw_flash_test" +NUM_NETIFS=0 +source $lib_dir/lib.sh + +BUS_ADDR=10 +PORT_COUNT=4 +DEV_NAME=netdevsim$BUS_ADDR +SYSFS_NET_DIR=/sys/bus/netdevsim/devices/$DEV_NAME/net/ +DEBUGFS_DIR=/sys/kernel/debug/netdevsim/$DEV_NAME/ +DL_HANDLE=netdevsim/$DEV_NAME + +fw_flash_test() +{ +	RET=0 + +	devlink dev flash $DL_HANDLE file dummy +	check_err $? "Failed to flash with status updates on" + +	echo "n"> $DEBUGFS_DIR/fw_update_status +	check_err $? "Failed to disable status updates" + +	devlink dev flash $DL_HANDLE file dummy +	check_err $? "Failed to flash with status updates off" + +	log_test "fw flash test" +} + +setup_prepare() +{ +	modprobe netdevsim +	echo "$BUS_ADDR $PORT_COUNT" > /sys/bus/netdevsim/new_device +	while [ ! -d $SYSFS_NET_DIR ] ; do :; done +} + +cleanup() +{ +	pre_cleanup +	echo "$BUS_ADDR" > /sys/bus/netdevsim/del_device +	modprobe -r netdevsim +} + +trap cleanup EXIT + +setup_prepare + +tests_run + +exit $EXIT_STATUS | 
