Commit 16ce6e6f authored by Jakub Kicinski's avatar Jakub Kicinski
Browse files

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: default avatarJakub Kicinski <kuba@kernel.org>
parents 79db3669 5629f885
Loading
Loading
Loading
Loading
+8 −5
Original line number Diff line number Diff line
@@ -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);

+56 −30
Original line number Diff line number Diff line
@@ -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;

	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,22 +6625,32 @@ 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);

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

	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);
}
+7 −8
Original line number Diff line number Diff line
@@ -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 */
}