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

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
...@@ -844,9 +844,12 @@ void mlx5e_cleanup_nic_tx(struct mlx5e_priv *priv); ...@@ -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);
......
...@@ -1883,6 +1883,9 @@ int mlx5e_close(struct net_device *netdev) ...@@ -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 = { ...@@ -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, ...@@ -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, ...@@ -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, ...@@ -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) ...@@ -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) ...@@ -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,30 +3643,11 @@ void mlx5e_destroy_netdev(struct mlx5_core_dev *mdev, struct mlx5e_priv *priv) ...@@ -3539,30 +3643,11 @@ 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); unregister_netdev(netdev);
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);
}
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);
free_netdev(netdev);
if (!test_bit(MLX5_INTERFACE_STATE_SHUTDOWN, &mdev->intf_state))
free_netdev(netdev);
} }
static void mlx5e_remove(struct mlx5_core_dev *mdev, void *vpriv) static void mlx5e_remove(struct mlx5_core_dev *mdev, void *vpriv)
...@@ -3572,12 +3657,11 @@ static void mlx5e_remove(struct mlx5_core_dev *mdev, void *vpriv) ...@@ -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) ...@@ -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,
......
...@@ -413,19 +413,50 @@ static struct mlx5e_profile mlx5e_rep_profile = { ...@@ -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",
rep->vport); 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);
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);
} }
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment