Skip to content

Commit

Permalink
Merge branch 'net-expose-flash-update-status-to-user'
Browse files Browse the repository at this point in the history
Jiri Pirko says:

====================
expose flash update status to user

When user is flashing device using devlink, he currenly does not see any
information about what is going on, percentages, etc.
Drivers, for example mlxsw and mlx5, have notion about the progress
and what is happening. This patchset exposes this progress
information to userspace.

Example output for existing flash command:
$ devlink dev flash pci/0000:01:00.0 file firmware.bin
Preparing to flash
Flashing 100%
Flashing done

See this console recording which shows flashing FW on a Mellanox
Spectrum device:
https://asciinema.org/a/247926

Please see individual patches for changelog.
v2->v3 only adds tags and the last selftest patch
====================

Signed-off-by: David S. Miller <davem@davemloft.net>
  • Loading branch information
David S. Miller committed Jun 4, 2019
2 parents 712246b + fc4c93f commit ae95f9c
Show file tree
Hide file tree
Showing 17 changed files with 358 additions and 91 deletions.
2 changes: 0 additions & 2 deletions drivers/net/ethernet/mellanox/mlx5/core/en.h
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
35 changes: 0 additions & 35 deletions drivers/net/ethernet/mellanox/mlx5/core/en_ethtool.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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,
Expand Down
6 changes: 4 additions & 2 deletions drivers/net/ethernet/mellanox/mlx5/core/fw.c
Original file line number Diff line number Diff line change
Expand Up @@ -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 = {
Expand All @@ -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);
}
9 changes: 0 additions & 9 deletions drivers/net/ethernet/mellanox/mlx5/core/ipoib/ethtool.c
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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,
Expand Down
20 changes: 20 additions & 0 deletions drivers/net/ethernet/mellanox/mlx5/core/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -1214,6 +1214,25 @@ static int mlx5_unload_one(struct mlx5_core_dev *dev, bool cleanup)
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,
Expand All @@ -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)
Expand Down
3 changes: 2 additions & 1 deletion drivers/net/ethernet/mellanox/mlx5/core/mlx5_core.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
11 changes: 9 additions & 2 deletions drivers/net/ethernet/mellanox/mlxfw/mlxfw.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
#define _MLXFW_H

#include <linux/firmware.h>
#include <linux/netlink.h>

enum mlxfw_fsm_state {
MLXFW_FSM_STATE_IDLE,
Expand Down Expand Up @@ -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 {
Expand All @@ -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;
}
Expand Down
57 changes: 47 additions & 10 deletions drivers/net/ethernet/mellanox/mlxfw/mlxfw_fsm.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -57,11 +68,13 @@ static int mlxfw_fsm_state_wait(struct mlxfw_dev *mlxfw_dev, u32 fwhandle,
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);
Expand All @@ -76,16 +89,20 @@ static int mlxfw_fsm_state_wait(struct mlxfw_dev *mlxfw_dev, u32 fwhandle,

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);
Expand All @@ -96,25 +113,29 @@ 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;
}

comp_max_write_size = MLXFW_ALIGN_DOWN(comp_max_write_size,
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);
if (err)
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) {
Expand All @@ -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;
Expand All @@ -145,7 +171,8 @@ static int mlxfw_flash_component(struct mlxfw_dev *mlxfw_dev,
}

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;
Expand All @@ -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;
}

Expand All @@ -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;
Expand All @@ -177,14 +205,16 @@ 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;
int err;

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

Expand All @@ -193,36 +223,43 @@ 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;

pr_debug("Handle release\n");
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;

Expand Down
Loading

0 comments on commit ae95f9c

Please sign in to comment.