Merge branch 'mlx5e-profile-change-fix'

Saeed Mahameed says:

====================
mlx5e profile change fix

This series fixes a crash in mlx5e due to profile change error flow.
====================

Link: https://patch.msgid.link/20260108212657.25090-1-saeed@kernel.org
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
Jakub Kicinski 2026-01-10 15:21:12 -08:00
commit 16ce6e6fa9
3 changed files with 71 additions and 43 deletions

View File

@ -962,7 +962,7 @@ struct mlx5e_priv {
};
struct mlx5e_dev {
struct mlx5e_priv *priv;
struct net_device *netdev;
struct devlink_port dl_port;
};
@ -1242,10 +1242,13 @@ struct net_device *
mlx5e_create_netdev(struct mlx5_core_dev *mdev, const struct mlx5e_profile *profile);
int mlx5e_attach_netdev(struct mlx5e_priv *priv);
void mlx5e_detach_netdev(struct mlx5e_priv *priv);
void mlx5e_destroy_netdev(struct mlx5e_priv *priv);
int mlx5e_netdev_change_profile(struct mlx5e_priv *priv,
const struct mlx5e_profile *new_profile, void *new_ppriv);
void mlx5e_netdev_attach_nic_profile(struct mlx5e_priv *priv);
void mlx5e_destroy_netdev(struct net_device *netdev);
int mlx5e_netdev_change_profile(struct net_device *netdev,
struct mlx5_core_dev *mdev,
const struct mlx5e_profile *new_profile,
void *new_ppriv);
void mlx5e_netdev_attach_nic_profile(struct net_device *netdev,
struct mlx5_core_dev *mdev);
void mlx5e_set_netdev_mtu_boundaries(struct mlx5e_priv *priv);
void mlx5e_build_nic_params(struct mlx5e_priv *priv, struct mlx5e_xsk *xsk, u16 mtu);

View File

@ -6325,6 +6325,7 @@ int mlx5e_priv_init(struct mlx5e_priv *priv,
void mlx5e_priv_cleanup(struct mlx5e_priv *priv)
{
bool destroying = test_bit(MLX5E_STATE_DESTROYING, &priv->state);
int i;
/* bail if change profile failed and also rollback failed */
@ -6352,6 +6353,8 @@ void mlx5e_priv_cleanup(struct mlx5e_priv *priv)
}
memset(priv, 0, sizeof(*priv));
if (destroying) /* restore destroying bit, to allow unload */
set_bit(MLX5E_STATE_DESTROYING, &priv->state);
}
static unsigned int mlx5e_get_max_num_txqs(struct mlx5_core_dev *mdev,
@ -6584,19 +6587,28 @@ mlx5e_netdev_attach_profile(struct net_device *netdev, struct mlx5_core_dev *mde
return err;
}
int mlx5e_netdev_change_profile(struct mlx5e_priv *priv,
const struct mlx5e_profile *new_profile, void *new_ppriv)
int mlx5e_netdev_change_profile(struct net_device *netdev,
struct mlx5_core_dev *mdev,
const struct mlx5e_profile *new_profile,
void *new_ppriv)
{
const struct mlx5e_profile *orig_profile = priv->profile;
struct net_device *netdev = priv->netdev;
struct mlx5_core_dev *mdev = priv->mdev;
void *orig_ppriv = priv->ppriv;
struct mlx5e_priv *priv = netdev_priv(netdev);
const struct mlx5e_profile *orig_profile;
int err, rollback_err;
void *orig_ppriv;
/* cleanup old profile */
mlx5e_detach_netdev(priv);
priv->profile->cleanup(priv);
mlx5e_priv_cleanup(priv);
orig_profile = priv->profile;
orig_ppriv = priv->ppriv;
/* NULL could happen if previous change_profile failed to rollback */
if (priv->profile) {
WARN_ON_ONCE(priv->mdev != mdev);
/* cleanup old profile */
mlx5e_detach_netdev(priv);
priv->profile->cleanup(priv);
mlx5e_priv_cleanup(priv);
}
/* priv members are not valid from this point ... */
if (mdev->state == MLX5_DEVICE_STATE_INTERNAL_ERROR) {
mlx5e_netdev_init_profile(netdev, mdev, new_profile, new_ppriv);
@ -6613,23 +6625,33 @@ int mlx5e_netdev_change_profile(struct mlx5e_priv *priv,
return 0;
rollback:
if (!orig_profile) {
netdev_warn(netdev, "no original profile to rollback to\n");
priv->profile = NULL;
return err;
}
rollback_err = mlx5e_netdev_attach_profile(netdev, mdev, orig_profile, orig_ppriv);
if (rollback_err)
netdev_err(netdev, "%s: failed to rollback to orig profile, %d\n",
__func__, rollback_err);
if (rollback_err) {
netdev_err(netdev, "failed to rollback to orig profile, %d\n",
rollback_err);
priv->profile = NULL;
}
return err;
}
void mlx5e_netdev_attach_nic_profile(struct mlx5e_priv *priv)
void mlx5e_netdev_attach_nic_profile(struct net_device *netdev,
struct mlx5_core_dev *mdev)
{
mlx5e_netdev_change_profile(priv, &mlx5e_nic_profile, NULL);
mlx5e_netdev_change_profile(netdev, mdev, &mlx5e_nic_profile, NULL);
}
void mlx5e_destroy_netdev(struct mlx5e_priv *priv)
void mlx5e_destroy_netdev(struct net_device *netdev)
{
struct net_device *netdev = priv->netdev;
struct mlx5e_priv *priv = netdev_priv(netdev);
mlx5e_priv_cleanup(priv);
if (priv->profile)
mlx5e_priv_cleanup(priv);
free_netdev(netdev);
}
@ -6637,8 +6659,8 @@ static int _mlx5e_resume(struct auxiliary_device *adev)
{
struct mlx5_adev *edev = container_of(adev, struct mlx5_adev, adev);
struct mlx5e_dev *mlx5e_dev = auxiliary_get_drvdata(adev);
struct mlx5e_priv *priv = mlx5e_dev->priv;
struct net_device *netdev = priv->netdev;
struct mlx5e_priv *priv = netdev_priv(mlx5e_dev->netdev);
struct net_device *netdev = mlx5e_dev->netdev;
struct mlx5_core_dev *mdev = edev->mdev;
struct mlx5_core_dev *pos, *to;
int err, i;
@ -6684,10 +6706,11 @@ static int mlx5e_resume(struct auxiliary_device *adev)
static int _mlx5e_suspend(struct auxiliary_device *adev, bool pre_netdev_reg)
{
struct mlx5_adev *edev = container_of(adev, struct mlx5_adev, adev);
struct mlx5e_dev *mlx5e_dev = auxiliary_get_drvdata(adev);
struct mlx5e_priv *priv = mlx5e_dev->priv;
struct net_device *netdev = priv->netdev;
struct mlx5_core_dev *mdev = priv->mdev;
struct mlx5e_priv *priv = netdev_priv(mlx5e_dev->netdev);
struct net_device *netdev = mlx5e_dev->netdev;
struct mlx5_core_dev *mdev = edev->mdev;
struct mlx5_core_dev *pos;
int i;
@ -6748,11 +6771,11 @@ static int _mlx5e_probe(struct auxiliary_device *adev)
goto err_devlink_port_unregister;
}
SET_NETDEV_DEVLINK_PORT(netdev, &mlx5e_dev->dl_port);
mlx5e_dev->netdev = netdev;
mlx5e_build_nic_netdev(netdev);
priv = netdev_priv(netdev);
mlx5e_dev->priv = priv;
priv->profile = profile;
priv->ppriv = NULL;
@ -6785,7 +6808,7 @@ static int _mlx5e_probe(struct auxiliary_device *adev)
err_profile_cleanup:
profile->cleanup(priv);
err_destroy_netdev:
mlx5e_destroy_netdev(priv);
mlx5e_destroy_netdev(netdev);
err_devlink_port_unregister:
mlx5e_devlink_port_unregister(mlx5e_dev);
err_devlink_unregister:
@ -6815,17 +6838,20 @@ static void _mlx5e_remove(struct auxiliary_device *adev)
{
struct mlx5_adev *edev = container_of(adev, struct mlx5_adev, adev);
struct mlx5e_dev *mlx5e_dev = auxiliary_get_drvdata(adev);
struct mlx5e_priv *priv = mlx5e_dev->priv;
struct net_device *netdev = mlx5e_dev->netdev;
struct mlx5e_priv *priv = netdev_priv(netdev);
struct mlx5_core_dev *mdev = edev->mdev;
mlx5_core_uplink_netdev_set(mdev, NULL);
mlx5e_dcbnl_delete_app(priv);
if (priv->profile)
mlx5e_dcbnl_delete_app(priv);
/* When unload driver, the netdev is in registered state
* if it's from legacy mode. If from switchdev mode, it
* is already unregistered before changing to NIC profile.
*/
if (priv->netdev->reg_state == NETREG_REGISTERED) {
unregister_netdev(priv->netdev);
if (netdev->reg_state == NETREG_REGISTERED) {
unregister_netdev(netdev);
_mlx5e_suspend(adev, false);
} else {
struct mlx5_core_dev *pos;
@ -6840,7 +6866,7 @@ static void _mlx5e_remove(struct auxiliary_device *adev)
/* Avoid cleanup if profile rollback failed. */
if (priv->profile)
priv->profile->cleanup(priv);
mlx5e_destroy_netdev(priv);
mlx5e_destroy_netdev(netdev);
mlx5e_devlink_port_unregister(mlx5e_dev);
mlx5e_destroy_devlink(mlx5e_dev);
}

View File

@ -1508,17 +1508,16 @@ mlx5e_vport_uplink_rep_load(struct mlx5_core_dev *dev, struct mlx5_eswitch_rep *
{
struct mlx5e_rep_priv *rpriv = mlx5e_rep_to_rep_priv(rep);
struct net_device *netdev;
struct mlx5e_priv *priv;
int err;
netdev = mlx5_uplink_netdev_get(dev);
if (!netdev)
return 0;
priv = netdev_priv(netdev);
rpriv->netdev = priv->netdev;
err = mlx5e_netdev_change_profile(priv, &mlx5e_uplink_rep_profile,
rpriv);
/* must not use netdev_priv(netdev), it might not be initialized yet */
rpriv->netdev = netdev;
err = mlx5e_netdev_change_profile(netdev, dev,
&mlx5e_uplink_rep_profile, rpriv);
mlx5_uplink_netdev_put(dev, netdev);
return err;
}
@ -1546,7 +1545,7 @@ mlx5e_vport_uplink_rep_unload(struct mlx5e_rep_priv *rpriv)
if (!(priv->mdev->priv.flags & MLX5_PRIV_FLAGS_SWITCH_LEGACY))
unregister_netdev(netdev);
mlx5e_netdev_attach_nic_profile(priv);
mlx5e_netdev_attach_nic_profile(netdev, priv->mdev);
}
static int
@ -1612,7 +1611,7 @@ mlx5e_vport_vf_rep_load(struct mlx5_core_dev *dev, struct mlx5_eswitch_rep *rep)
priv->profile->cleanup(priv);
err_destroy_netdev:
mlx5e_destroy_netdev(netdev_priv(netdev));
mlx5e_destroy_netdev(netdev);
return err;
}
@ -1667,7 +1666,7 @@ mlx5e_vport_rep_unload(struct mlx5_eswitch_rep *rep)
mlx5e_rep_vnic_reporter_destroy(priv);
mlx5e_detach_netdev(priv);
priv->profile->cleanup(priv);
mlx5e_destroy_netdev(priv);
mlx5e_destroy_netdev(netdev);
free_ppriv:
kvfree(ppriv); /* mlx5e_rep_priv */
}