Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 26e59d80 authored by Mohamad Haj Yahia's avatar Mohamad Haj Yahia Committed by David S. Miller
Browse files

net/mlx5e: Implement mlx5e interface attach/detach callbacks



Needed to support seamless and lightweight PCI/Internal error recovery.
Implement the attach/detach interface callbacks.
In attach callback we only allocate HW resources.
In detach callback we only deallocate HW resources.
All SW/kernel objects initialzing/destroying is kept in add/remove
callbacks.

Signed-off-by: default avatarMohamad Haj Yahia <mohamad@mellanox.com>
Signed-off-by: default avatarSaeed Mahameed <saeedm@mellanox.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 1ab2068a
Loading
Loading
Loading
Loading
+5 −2
Original line number Original line Diff line number Diff line
@@ -844,9 +844,12 @@ void mlx5e_cleanup_nic_tx(struct mlx5e_priv *priv);
int mlx5e_close(struct net_device *netdev);
int mlx5e_close(struct net_device *netdev);
int mlx5e_open(struct net_device *netdev);
int mlx5e_open(struct net_device *netdev);
void mlx5e_update_stats_work(struct work_struct *work);
void mlx5e_update_stats_work(struct work_struct *work);
void *mlx5e_create_netdev(struct mlx5_core_dev *mdev,
struct net_device *mlx5e_create_netdev(struct mlx5_core_dev *mdev,
			  const struct mlx5e_profile *profile, void *ppriv);
				       const struct mlx5e_profile *profile,
				       void *ppriv);
void mlx5e_destroy_netdev(struct mlx5_core_dev *mdev, struct mlx5e_priv *priv);
void mlx5e_destroy_netdev(struct mlx5_core_dev *mdev, struct mlx5e_priv *priv);
int mlx5e_attach_netdev(struct mlx5_core_dev *mdev, struct net_device *netdev);
void mlx5e_detach_netdev(struct mlx5_core_dev *mdev, struct net_device *netdev);
struct rtnl_link_stats64 *
struct rtnl_link_stats64 *
mlx5e_get_stats(struct net_device *dev, struct rtnl_link_stats64 *stats);
mlx5e_get_stats(struct net_device *dev, struct rtnl_link_stats64 *stats);


+143 −57
Original line number Original line Diff line number Diff line
@@ -1883,6 +1883,9 @@ int mlx5e_close(struct net_device *netdev)
	struct mlx5e_priv *priv = netdev_priv(netdev);
	struct mlx5e_priv *priv = netdev_priv(netdev);
	int err;
	int err;


	if (!netif_device_present(netdev))
		return -ENODEV;

	mutex_lock(&priv->state_lock);
	mutex_lock(&priv->state_lock);
	err = mlx5e_close_locked(netdev);
	err = mlx5e_close_locked(netdev);
	mutex_unlock(&priv->state_lock);
	mutex_unlock(&priv->state_lock);
@@ -3401,13 +3404,13 @@ static const struct mlx5e_profile mlx5e_nic_profile = {
	.max_tc		   = MLX5E_MAX_NUM_TC,
	.max_tc		   = MLX5E_MAX_NUM_TC,
};
};


void *mlx5e_create_netdev(struct mlx5_core_dev *mdev,
struct net_device *mlx5e_create_netdev(struct mlx5_core_dev *mdev,
			  const struct mlx5e_profile *profile, void *ppriv)
				       const struct mlx5e_profile *profile,
				       void *ppriv)
{
{
	int nch = profile->max_nch(mdev);
	struct net_device *netdev;
	struct net_device *netdev;
	struct mlx5e_priv *priv;
	struct mlx5e_priv *priv;
	int nch = profile->max_nch(mdev);
	int err;


	netdev = alloc_etherdev_mqs(sizeof(struct mlx5e_priv),
	netdev = alloc_etherdev_mqs(sizeof(struct mlx5e_priv),
				    nch * profile->max_tc,
				    nch * profile->max_tc,
@@ -3425,12 +3428,31 @@ void *mlx5e_create_netdev(struct mlx5_core_dev *mdev,


	priv->wq = create_singlethread_workqueue("mlx5e");
	priv->wq = create_singlethread_workqueue("mlx5e");
	if (!priv->wq)
	if (!priv->wq)
		goto err_free_netdev;
		goto err_cleanup_nic;

	return netdev;

err_cleanup_nic:
	profile->cleanup(priv);
	free_netdev(netdev);

	return NULL;
}

int mlx5e_attach_netdev(struct mlx5_core_dev *mdev, struct net_device *netdev)
{
	const struct mlx5e_profile *profile;
	struct mlx5e_priv *priv;
	int err;

	priv = netdev_priv(netdev);
	profile = priv->profile;
	clear_bit(MLX5E_STATE_DESTROYING, &priv->state);


	err = mlx5e_create_umr_mkey(priv);
	err = mlx5e_create_umr_mkey(priv);
	if (err) {
	if (err) {
		mlx5_core_err(mdev, "create umr mkey failed, %d\n", err);
		mlx5_core_err(mdev, "create umr mkey failed, %d\n", err);
		goto err_destroy_wq;
		goto out;
	}
	}


	err = profile->init_tx(priv);
	err = profile->init_tx(priv);
@@ -3453,20 +3475,16 @@ void *mlx5e_create_netdev(struct mlx5_core_dev *mdev,


	mlx5e_set_dev_port_mtu(netdev);
	mlx5e_set_dev_port_mtu(netdev);


	err = register_netdev(netdev);
	if (err) {
		mlx5_core_err(mdev, "register_netdev failed, %d\n", err);
		goto err_dealloc_q_counters;
	}

	if (profile->enable)
	if (profile->enable)
		profile->enable(priv);
		profile->enable(priv);


	return priv;
	rtnl_lock();
	if (netif_running(netdev))
		mlx5e_open(netdev);
	netif_device_attach(netdev);
	rtnl_unlock();


err_dealloc_q_counters:
	return 0;
	mlx5e_destroy_q_counter(priv);
	profile->cleanup_rx(priv);


err_close_drop_rq:
err_close_drop_rq:
	mlx5e_close_drop_rq(priv);
	mlx5e_close_drop_rq(priv);
@@ -3477,13 +3495,8 @@ void *mlx5e_create_netdev(struct mlx5_core_dev *mdev,
err_destroy_umr_mkey:
err_destroy_umr_mkey:
	mlx5_core_destroy_mkey(mdev, &priv->umr_mkey);
	mlx5_core_destroy_mkey(mdev, &priv->umr_mkey);


err_destroy_wq:
out:
	destroy_workqueue(priv->wq);
	return err;

err_free_netdev:
	free_netdev(netdev);

	return NULL;
}
}


static void mlx5e_register_vport_rep(struct mlx5_core_dev *mdev)
static void mlx5e_register_vport_rep(struct mlx5_core_dev *mdev)
@@ -3509,16 +3522,80 @@ static void mlx5e_register_vport_rep(struct mlx5_core_dev *mdev)
	}
	}
}
}


void mlx5e_detach_netdev(struct mlx5_core_dev *mdev, struct net_device *netdev)
{
	struct mlx5e_priv *priv = netdev_priv(netdev);
	const struct mlx5e_profile *profile = priv->profile;

	set_bit(MLX5E_STATE_DESTROYING, &priv->state);
	if (profile->disable)
		profile->disable(priv);

	flush_workqueue(priv->wq);

	rtnl_lock();
	if (netif_running(netdev))
		mlx5e_close(netdev);
	netif_device_detach(netdev);
	rtnl_unlock();

	mlx5e_destroy_q_counter(priv);
	profile->cleanup_rx(priv);
	mlx5e_close_drop_rq(priv);
	profile->cleanup_tx(priv);
	mlx5_core_destroy_mkey(priv->mdev, &priv->umr_mkey);
	cancel_delayed_work_sync(&priv->update_stats_work);
}

/* mlx5e_attach and mlx5e_detach scope should be only creating/destroying
 * hardware contexts and to connect it to the current netdev.
 */
static int mlx5e_attach(struct mlx5_core_dev *mdev, void *vpriv)
{
	struct mlx5e_priv *priv = vpriv;
	struct net_device *netdev = priv->netdev;
	int err;

	if (netif_device_present(netdev))
		return 0;

	err = mlx5e_create_mdev_resources(mdev);
	if (err)
		return err;

	err = mlx5e_attach_netdev(mdev, netdev);
	if (err) {
		mlx5e_destroy_mdev_resources(mdev);
		return err;
	}

	return 0;
}

static void mlx5e_detach(struct mlx5_core_dev *mdev, void *vpriv)
{
	struct mlx5e_priv *priv = vpriv;
	struct net_device *netdev = priv->netdev;

	if (!netif_device_present(netdev))
		return;

	mlx5e_detach_netdev(mdev, netdev);
	mlx5e_destroy_mdev_resources(mdev);
}

static void *mlx5e_add(struct mlx5_core_dev *mdev)
static void *mlx5e_add(struct mlx5_core_dev *mdev)
{
{
	struct mlx5_eswitch *esw = mdev->priv.eswitch;
	struct mlx5_eswitch *esw = mdev->priv.eswitch;
	int total_vfs = MLX5_TOTAL_VPORTS(mdev);
	void *ppriv = NULL;
	void *ppriv = NULL;
	void *ret;
	void *priv;

	int vport;
	if (mlx5e_check_required_hca_cap(mdev))
	int err;
		return NULL;
	struct net_device *netdev;


	if (mlx5e_create_mdev_resources(mdev))
	err = mlx5e_check_required_hca_cap(mdev);
	if (err)
		return NULL;
		return NULL;


	mlx5e_register_vport_rep(mdev);
	mlx5e_register_vport_rep(mdev);
@@ -3526,12 +3603,39 @@ static void *mlx5e_add(struct mlx5_core_dev *mdev)
	if (MLX5_CAP_GEN(mdev, vport_group_manager))
	if (MLX5_CAP_GEN(mdev, vport_group_manager))
		ppriv = &esw->offloads.vport_reps[0];
		ppriv = &esw->offloads.vport_reps[0];


	ret = mlx5e_create_netdev(mdev, &mlx5e_nic_profile, ppriv);
	netdev = mlx5e_create_netdev(mdev, &mlx5e_nic_profile, ppriv);
	if (!ret) {
	if (!netdev) {
		mlx5e_destroy_mdev_resources(mdev);
		mlx5_core_err(mdev, "mlx5e_create_netdev failed\n");
		return NULL;
		goto err_unregister_reps;
	}

	priv = netdev_priv(netdev);

	err = mlx5e_attach(mdev, priv);
	if (err) {
		mlx5_core_err(mdev, "mlx5e_attach failed, %d\n", err);
		goto err_destroy_netdev;
	}

	err = register_netdev(netdev);
	if (err) {
		mlx5_core_err(mdev, "register_netdev failed, %d\n", err);
		goto err_detach;
	}
	}
	return ret;

	return priv;

err_detach:
	mlx5e_detach(mdev, priv);

err_destroy_netdev:
	mlx5e_destroy_netdev(mdev, priv);

err_unregister_reps:
	for (vport = 1; vport < total_vfs; vport++)
		mlx5_eswitch_unregister_vport_rep(esw, vport);

	return NULL;
}
}


void mlx5e_destroy_netdev(struct mlx5_core_dev *mdev, struct mlx5e_priv *priv)
void mlx5e_destroy_netdev(struct mlx5_core_dev *mdev, struct mlx5e_priv *priv)
@@ -3539,29 +3643,10 @@ void mlx5e_destroy_netdev(struct mlx5_core_dev *mdev, struct mlx5e_priv *priv)
	const struct mlx5e_profile *profile = priv->profile;
	const struct mlx5e_profile *profile = priv->profile;
	struct net_device *netdev = priv->netdev;
	struct net_device *netdev = priv->netdev;


	set_bit(MLX5E_STATE_DESTROYING, &priv->state);
	if (profile->disable)
		profile->disable(priv);

	flush_workqueue(priv->wq);
	if (test_bit(MLX5_INTERFACE_STATE_SHUTDOWN, &mdev->intf_state)) {
		netif_device_detach(netdev);
		mlx5e_close(netdev);
	} else {
	unregister_netdev(netdev);
	unregister_netdev(netdev);
	}

	mlx5e_destroy_q_counter(priv);
	profile->cleanup_rx(priv);
	mlx5e_close_drop_rq(priv);
	profile->cleanup_tx(priv);
	mlx5_core_destroy_mkey(priv->mdev, &priv->umr_mkey);
	cancel_delayed_work_sync(&priv->update_stats_work);
	destroy_workqueue(priv->wq);
	destroy_workqueue(priv->wq);
	if (profile->cleanup)
	if (profile->cleanup)
		profile->cleanup(priv);
		profile->cleanup(priv);

	if (!test_bit(MLX5_INTERFACE_STATE_SHUTDOWN, &mdev->intf_state))
	free_netdev(netdev);
	free_netdev(netdev);
}
}


@@ -3572,12 +3657,11 @@ static void mlx5e_remove(struct mlx5_core_dev *mdev, void *vpriv)
	struct mlx5e_priv *priv = vpriv;
	struct mlx5e_priv *priv = vpriv;
	int vport;
	int vport;


	mlx5e_destroy_netdev(mdev, priv);

	for (vport = 1; vport < total_vfs; vport++)
	for (vport = 1; vport < total_vfs; vport++)
		mlx5_eswitch_unregister_vport_rep(esw, vport);
		mlx5_eswitch_unregister_vport_rep(esw, vport);


	mlx5e_destroy_mdev_resources(mdev);
	mlx5e_detach(mdev, vpriv);
	mlx5e_destroy_netdev(mdev, priv);
}
}


static void *mlx5e_get_netdev(void *vpriv)
static void *mlx5e_get_netdev(void *vpriv)
@@ -3590,6 +3674,8 @@ static void *mlx5e_get_netdev(void *vpriv)
static struct mlx5_interface mlx5e_interface = {
static struct mlx5_interface mlx5e_interface = {
	.add       = mlx5e_add,
	.add       = mlx5e_add,
	.remove    = mlx5e_remove,
	.remove    = mlx5e_remove,
	.attach    = mlx5e_attach,
	.detach    = mlx5e_detach,
	.event     = mlx5e_async_event,
	.event     = mlx5e_async_event,
	.protocol  = MLX5_INTERFACE_PROTOCOL_ETH,
	.protocol  = MLX5_INTERFACE_PROTOCOL_ETH,
	.get_dev   = mlx5e_get_netdev,
	.get_dev   = mlx5e_get_netdev,
+35 −4
Original line number Original line Diff line number Diff line
@@ -413,19 +413,50 @@ static struct mlx5e_profile mlx5e_rep_profile = {
int mlx5e_vport_rep_load(struct mlx5_eswitch *esw,
int mlx5e_vport_rep_load(struct mlx5_eswitch *esw,
			 struct mlx5_eswitch_rep *rep)
			 struct mlx5_eswitch_rep *rep)
{
{
	rep->priv_data = mlx5e_create_netdev(esw->dev, &mlx5e_rep_profile, rep);
	struct net_device *netdev;
	if (!rep->priv_data) {
	int err;
		mlx5_core_warn(esw->dev, "Failed to create representor for vport %d\n",

	netdev = mlx5e_create_netdev(esw->dev, &mlx5e_rep_profile, rep);
	if (!netdev) {
		pr_warn("Failed to create representor netdev for vport %d\n",
			rep->vport);
			rep->vport);
		return -EINVAL;
		return -EINVAL;
	}
	}

	rep->priv_data = netdev_priv(netdev);

	err = mlx5e_attach_netdev(esw->dev, netdev);
	if (err) {
		pr_warn("Failed to attach representor netdev for vport %d\n",
			rep->vport);
		goto err_destroy_netdev;
	}

	err = register_netdev(netdev);
	if (err) {
		pr_warn("Failed to register representor netdev for vport %d\n",
			rep->vport);
		goto err_detach_netdev;
	}

	return 0;
	return 0;

err_detach_netdev:
	mlx5e_detach_netdev(esw->dev, netdev);

err_destroy_netdev:
	mlx5e_destroy_netdev(esw->dev, rep->priv_data);

	return err;

}
}


void mlx5e_vport_rep_unload(struct mlx5_eswitch *esw,
void mlx5e_vport_rep_unload(struct mlx5_eswitch *esw,
			    struct mlx5_eswitch_rep *rep)
			    struct mlx5_eswitch_rep *rep)
{
{
	struct mlx5e_priv *priv = rep->priv_data;
	struct mlx5e_priv *priv = rep->priv_data;
	struct net_device *netdev = priv->netdev;


	mlx5e_detach_netdev(esw->dev, netdev);
	mlx5e_destroy_netdev(esw->dev, priv);
	mlx5e_destroy_netdev(esw->dev, priv);
}
}