|
|
|
@ -44,6 +44,7 @@
|
|
|
|
|
#include "en_tc.h"
|
|
|
|
|
#include "en/rep/tc.h"
|
|
|
|
|
#include "en/rep/neigh.h"
|
|
|
|
|
#include "en/devlink.h"
|
|
|
|
|
#include "fs_core.h"
|
|
|
|
|
#include "lib/mlx5.h"
|
|
|
|
|
#define CREATE_TRACE_POINTS
|
|
|
|
@ -588,26 +589,15 @@ static void mlx5e_build_rep_params(struct net_device *netdev)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void mlx5e_build_rep_netdev(struct net_device *netdev,
|
|
|
|
|
struct mlx5_core_dev *mdev,
|
|
|
|
|
struct mlx5_eswitch_rep *rep)
|
|
|
|
|
struct mlx5_core_dev *mdev)
|
|
|
|
|
{
|
|
|
|
|
SET_NETDEV_DEV(netdev, mdev->device);
|
|
|
|
|
if (rep->vport == MLX5_VPORT_UPLINK) {
|
|
|
|
|
netdev->netdev_ops = &mlx5e_netdev_ops;
|
|
|
|
|
/* we want a persistent mac for the uplink rep */
|
|
|
|
|
mlx5_query_mac_address(mdev, netdev->dev_addr);
|
|
|
|
|
netdev->ethtool_ops = &mlx5e_ethtool_ops;
|
|
|
|
|
mlx5e_dcbnl_build_rep_netdev(netdev);
|
|
|
|
|
} else {
|
|
|
|
|
netdev->netdev_ops = &mlx5e_netdev_ops_rep;
|
|
|
|
|
eth_hw_addr_random(netdev);
|
|
|
|
|
netdev->ethtool_ops = &mlx5e_rep_ethtool_ops;
|
|
|
|
|
}
|
|
|
|
|
netdev->netdev_ops = &mlx5e_netdev_ops_rep;
|
|
|
|
|
eth_hw_addr_random(netdev);
|
|
|
|
|
netdev->ethtool_ops = &mlx5e_rep_ethtool_ops;
|
|
|
|
|
|
|
|
|
|
netdev->watchdog_timeo = 15 * HZ;
|
|
|
|
|
|
|
|
|
|
netdev->features |= NETIF_F_NETNS_LOCAL;
|
|
|
|
|
|
|
|
|
|
#if IS_ENABLED(CONFIG_MLX5_CLS_ACT)
|
|
|
|
|
netdev->hw_features |= NETIF_F_HW_TC;
|
|
|
|
|
#endif
|
|
|
|
@ -619,12 +609,9 @@ static void mlx5e_build_rep_netdev(struct net_device *netdev,
|
|
|
|
|
netdev->hw_features |= NETIF_F_TSO6;
|
|
|
|
|
netdev->hw_features |= NETIF_F_RXCSUM;
|
|
|
|
|
|
|
|
|
|
if (rep->vport == MLX5_VPORT_UPLINK)
|
|
|
|
|
netdev->hw_features |= NETIF_F_HW_VLAN_CTAG_RX;
|
|
|
|
|
else
|
|
|
|
|
netdev->features |= NETIF_F_VLAN_CHALLENGED;
|
|
|
|
|
|
|
|
|
|
netdev->features |= netdev->hw_features;
|
|
|
|
|
netdev->features |= NETIF_F_VLAN_CHALLENGED;
|
|
|
|
|
netdev->features |= NETIF_F_NETNS_LOCAL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int mlx5e_init_rep(struct mlx5_core_dev *mdev,
|
|
|
|
@ -990,6 +977,14 @@ static void mlx5e_uplink_rep_enable(struct mlx5e_priv *priv)
|
|
|
|
|
mlx5e_dcbnl_initialize(priv);
|
|
|
|
|
mlx5e_dcbnl_init_app(priv);
|
|
|
|
|
mlx5e_rep_neigh_init(rpriv);
|
|
|
|
|
|
|
|
|
|
netdev->wanted_features |= NETIF_F_HW_TC;
|
|
|
|
|
|
|
|
|
|
rtnl_lock();
|
|
|
|
|
if (netif_running(netdev))
|
|
|
|
|
mlx5e_open(netdev);
|
|
|
|
|
netif_device_attach(netdev);
|
|
|
|
|
rtnl_unlock();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void mlx5e_uplink_rep_disable(struct mlx5e_priv *priv)
|
|
|
|
@ -997,6 +992,12 @@ static void mlx5e_uplink_rep_disable(struct mlx5e_priv *priv)
|
|
|
|
|
struct mlx5e_rep_priv *rpriv = priv->ppriv;
|
|
|
|
|
struct mlx5_core_dev *mdev = priv->mdev;
|
|
|
|
|
|
|
|
|
|
rtnl_lock();
|
|
|
|
|
if (netif_running(priv->netdev))
|
|
|
|
|
mlx5e_close(priv->netdev);
|
|
|
|
|
netif_device_detach(priv->netdev);
|
|
|
|
|
rtnl_unlock();
|
|
|
|
|
|
|
|
|
|
mlx5e_rep_neigh_cleanup(rpriv);
|
|
|
|
|
mlx5e_dcbnl_delete_app(priv);
|
|
|
|
|
mlx5_notifier_unregister(mdev, &priv->events_nb);
|
|
|
|
@ -1081,26 +1082,56 @@ static const struct mlx5e_profile mlx5e_uplink_rep_profile = {
|
|
|
|
|
|
|
|
|
|
/* e-Switch vport representors */
|
|
|
|
|
static int
|
|
|
|
|
mlx5e_vport_rep_load(struct mlx5_core_dev *dev, struct mlx5_eswitch_rep *rep)
|
|
|
|
|
mlx5e_vport_uplink_rep_load(struct mlx5_core_dev *dev, struct mlx5_eswitch_rep *rep)
|
|
|
|
|
{
|
|
|
|
|
struct mlx5e_priv *priv = netdev_priv(mlx5_uplink_netdev_get(dev));
|
|
|
|
|
struct mlx5e_rep_priv *rpriv = mlx5e_rep_to_rep_priv(rep);
|
|
|
|
|
struct devlink_port *dl_port;
|
|
|
|
|
int err;
|
|
|
|
|
|
|
|
|
|
rpriv->netdev = priv->netdev;
|
|
|
|
|
|
|
|
|
|
err = mlx5e_netdev_change_profile(priv, &mlx5e_uplink_rep_profile,
|
|
|
|
|
rpriv);
|
|
|
|
|
if (err)
|
|
|
|
|
return err;
|
|
|
|
|
|
|
|
|
|
dl_port = mlx5_esw_offloads_devlink_port(dev->priv.eswitch, rpriv->rep->vport);
|
|
|
|
|
if (dl_port)
|
|
|
|
|
devlink_port_type_eth_set(dl_port, rpriv->netdev);
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
mlx5e_vport_uplink_rep_unload(struct mlx5e_rep_priv *rpriv)
|
|
|
|
|
{
|
|
|
|
|
struct net_device *netdev = rpriv->netdev;
|
|
|
|
|
struct devlink_port *dl_port;
|
|
|
|
|
struct mlx5_core_dev *dev;
|
|
|
|
|
struct mlx5e_priv *priv;
|
|
|
|
|
|
|
|
|
|
priv = netdev_priv(netdev);
|
|
|
|
|
dev = priv->mdev;
|
|
|
|
|
|
|
|
|
|
dl_port = mlx5_esw_offloads_devlink_port(dev->priv.eswitch, rpriv->rep->vport);
|
|
|
|
|
if (dl_port)
|
|
|
|
|
devlink_port_type_clear(dl_port);
|
|
|
|
|
mlx5e_netdev_attach_nic_profile(priv);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int
|
|
|
|
|
mlx5e_vport_vf_rep_load(struct mlx5_core_dev *dev, struct mlx5_eswitch_rep *rep)
|
|
|
|
|
{
|
|
|
|
|
struct mlx5e_rep_priv *rpriv = mlx5e_rep_to_rep_priv(rep);
|
|
|
|
|
const struct mlx5e_profile *profile;
|
|
|
|
|
struct mlx5e_rep_priv *rpriv;
|
|
|
|
|
struct devlink_port *dl_port;
|
|
|
|
|
struct net_device *netdev;
|
|
|
|
|
struct mlx5e_priv *priv;
|
|
|
|
|
unsigned int txqs, rxqs;
|
|
|
|
|
int nch, err;
|
|
|
|
|
|
|
|
|
|
rpriv = kzalloc(sizeof(*rpriv), GFP_KERNEL);
|
|
|
|
|
if (!rpriv)
|
|
|
|
|
return -ENOMEM;
|
|
|
|
|
|
|
|
|
|
/* rpriv->rep to be looked up when profile->init() is called */
|
|
|
|
|
rpriv->rep = rep;
|
|
|
|
|
|
|
|
|
|
profile = (rep->vport == MLX5_VPORT_UPLINK) ?
|
|
|
|
|
&mlx5e_uplink_rep_profile : &mlx5e_rep_profile;
|
|
|
|
|
|
|
|
|
|
profile = &mlx5e_rep_profile;
|
|
|
|
|
nch = mlx5e_get_max_num_channels(dev);
|
|
|
|
|
txqs = nch * profile->max_tc;
|
|
|
|
|
rxqs = nch * profile->rq_groups;
|
|
|
|
@ -1109,21 +1140,11 @@ mlx5e_vport_rep_load(struct mlx5_core_dev *dev, struct mlx5_eswitch_rep *rep)
|
|
|
|
|
mlx5_core_warn(dev,
|
|
|
|
|
"Failed to create representor netdev for vport %d\n",
|
|
|
|
|
rep->vport);
|
|
|
|
|
kfree(rpriv);
|
|
|
|
|
return -EINVAL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
mlx5e_build_rep_netdev(netdev, dev, rep);
|
|
|
|
|
|
|
|
|
|
mlx5e_build_rep_netdev(netdev, dev);
|
|
|
|
|
rpriv->netdev = netdev;
|
|
|
|
|
rep->rep_data[REP_ETH].priv = rpriv;
|
|
|
|
|
INIT_LIST_HEAD(&rpriv->vport_sqs_list);
|
|
|
|
|
|
|
|
|
|
if (rep->vport == MLX5_VPORT_UPLINK) {
|
|
|
|
|
err = mlx5e_create_mdev_resources(dev);
|
|
|
|
|
if (err)
|
|
|
|
|
goto err_destroy_netdev;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
priv = netdev_priv(netdev);
|
|
|
|
|
priv->profile = profile;
|
|
|
|
@ -1131,7 +1152,7 @@ mlx5e_vport_rep_load(struct mlx5_core_dev *dev, struct mlx5_eswitch_rep *rep)
|
|
|
|
|
err = profile->init(dev, netdev);
|
|
|
|
|
if (err) {
|
|
|
|
|
netdev_warn(netdev, "rep profile init failed, %d\n", err);
|
|
|
|
|
goto err_destroy_mdev_resources;
|
|
|
|
|
goto err_destroy_netdev;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
err = mlx5e_attach_netdev(netdev_priv(netdev));
|
|
|
|
@ -1161,13 +1182,34 @@ err_detach_netdev:
|
|
|
|
|
err_cleanup_profile:
|
|
|
|
|
priv->profile->cleanup(priv);
|
|
|
|
|
|
|
|
|
|
err_destroy_mdev_resources:
|
|
|
|
|
if (rep->vport == MLX5_VPORT_UPLINK)
|
|
|
|
|
mlx5e_destroy_mdev_resources(dev);
|
|
|
|
|
|
|
|
|
|
err_destroy_netdev:
|
|
|
|
|
mlx5e_destroy_netdev(netdev_priv(netdev));
|
|
|
|
|
kfree(rpriv);
|
|
|
|
|
return err;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int
|
|
|
|
|
mlx5e_vport_rep_load(struct mlx5_core_dev *dev, struct mlx5_eswitch_rep *rep)
|
|
|
|
|
{
|
|
|
|
|
struct mlx5e_rep_priv *rpriv;
|
|
|
|
|
int err;
|
|
|
|
|
|
|
|
|
|
rpriv = kzalloc(sizeof(*rpriv), GFP_KERNEL);
|
|
|
|
|
if (!rpriv)
|
|
|
|
|
return -ENOMEM;
|
|
|
|
|
|
|
|
|
|
/* rpriv->rep to be looked up when profile->init() is called */
|
|
|
|
|
rpriv->rep = rep;
|
|
|
|
|
rep->rep_data[REP_ETH].priv = rpriv;
|
|
|
|
|
INIT_LIST_HEAD(&rpriv->vport_sqs_list);
|
|
|
|
|
|
|
|
|
|
if (rep->vport == MLX5_VPORT_UPLINK)
|
|
|
|
|
err = mlx5e_vport_uplink_rep_load(dev, rep);
|
|
|
|
|
else
|
|
|
|
|
err = mlx5e_vport_vf_rep_load(dev, rep);
|
|
|
|
|
|
|
|
|
|
if (err)
|
|
|
|
|
kfree(rpriv);
|
|
|
|
|
|
|
|
|
|
return err;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -1181,15 +1223,19 @@ mlx5e_vport_rep_unload(struct mlx5_eswitch_rep *rep)
|
|
|
|
|
struct devlink_port *dl_port;
|
|
|
|
|
void *ppriv = priv->ppriv;
|
|
|
|
|
|
|
|
|
|
if (rep->vport == MLX5_VPORT_UPLINK) {
|
|
|
|
|
mlx5e_vport_uplink_rep_unload(rpriv);
|
|
|
|
|
goto free_ppriv;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
dl_port = mlx5_esw_offloads_devlink_port(dev->priv.eswitch, rpriv->rep->vport);
|
|
|
|
|
if (dl_port)
|
|
|
|
|
devlink_port_type_clear(dl_port);
|
|
|
|
|
unregister_netdev(netdev);
|
|
|
|
|
mlx5e_detach_netdev(priv);
|
|
|
|
|
priv->profile->cleanup(priv);
|
|
|
|
|
if (rep->vport == MLX5_VPORT_UPLINK)
|
|
|
|
|
mlx5e_destroy_mdev_resources(priv->mdev);
|
|
|
|
|
mlx5e_destroy_netdev(priv);
|
|
|
|
|
free_ppriv:
|
|
|
|
|
kfree(ppriv); /* mlx5e_rep_priv */
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|