# devlink dev eswitch set pci/0000:05:00.0 mode switchdev
# echo 2 > /sys/class/net/enp5s0f0/device/sriov_numvfs
# ip l show
297: enp5s0f0: <BROADCAST,MULTICAST> mtu 1500 qdisc noop portid 6805ca2e7268 state DOWN mode DEFAULT group default qlen 1000
link/ether 68:05:ca:2e:72:68 brd ff:ff:ff:ff:ff:ff
vf 0 MAC 00:00:00:00:00:00, spoof checking on, link-state auto, trust off
vf 1 MAC 00:00:00:00:00:00, spoof checking on, link-state auto, trust off
299: enp5s0f0-vf0: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000
link/ether 00:00:00:00:00:00 brd ff:ff:ff:ff:ff:ff
300: enp5s0f0-vf1: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000
link/ether 00:00:00:00:00:00 brd ff:ff:ff:ff:ff:ff
static int i40e_devlink_eswitch_mode_set(struct devlink *devlink, u16 mode)
{
struct i40e_pf *pf = devlink_priv(devlink);
int err = 0;
struct i40e_vf *vf;
int i, j, err = 0;
if (mode == pf->eswitch_mode)
goto done;
switch (mode) {
case DEVLINK_ESWITCH_MODE_LEGACY:
for (i = 0; i < pf->num_alloc_vfs; i++) {
vf = &(pf->vf[i]);
i40e_free_vfpr_netdev(vf);
}
pf->eswitch_mode = mode;
break;
case DEVLINK_ESWITCH_MODE_SWITCHDEV:
for (i = 0; i < pf->num_alloc_vfs; i++) {
vf = &(pf->vf[i]);
err = i40e_alloc_vfpr_netdev(vf, i);
if (err) {
for (j = 0; j < i; j++) {
vf = &(pf->vf[j]);
i40e_free_vfpr_netdev(vf);
}
goto done;
}
}
pf->eswitch_mode = mode;
break;
}
int i40e_alloc_vfpr_netdev(struct i40e_vf *vf, u16 vf_num)
{
struct net_device *vfpr_netdev;
char netdev_name[IFNAMSIZ];
struct i40e_vfpr_netdev_priv *priv;
struct i40e_pf *pf = vf->pf;
struct i40e_vsi *vsi = pf->vsi[pf->lan_vsi];
int err;
snprintf(netdev_name, IFNAMSIZ, "%s-vf%d", vsi->netdev->name, vf_num);
vfpr_netdev = alloc_netdev(sizeof(struct i40e_vfpr_netdev_priv),
netdev_name, NET_NAME_UNKNOWN, ether_setup);
if (!vfpr_netdev) {
dev_err(&pf->pdev->dev, "alloc_netdev failed for vf:%d\n",
vf_num);
return -ENOMEM;
}
pf->vf[vf_num].vfpr_netdev = vfpr_netdev;
priv = netdev_priv(vfpr_netdev);
priv->vf = &(pf->vf[vf_num]);
vfpr_netdev->netdev_ops = &i40e_vfpr_netdev_ops;
netif_carrier_off(vfpr_netdev);
netif_tx_disable(vfpr_netdev);
err = register_netdev(vfpr_netdev);
if (err) {
dev_err(&pf->pdev->dev, "register_netdev failed for vf: %s\n",
vf->vfpr_netdev->name);
free_netdev(vfpr_netdev);
return err;
}
dev_info(&pf->pdev->dev, "VF Port representor(%s) created for VF %d\n",
vf->vfpr_netdev->name, vf_num);
/* Delete broadcast filter for VF */
i40e_update_vf_broadcast_filter(vf, false);
return 0;
}
struct mlx5_eswitch_rep_ops {
int (*load)(struct mlx5_core_dev *dev, struct mlx5_eswitch_rep *rep);
void (*unload)(struct mlx5_eswitch_rep *rep);
void *(*get_proto_dev)(struct mlx5_eswitch_rep *rep);
};
struct mlx5_eswitch_rep_data {
void *priv;
atomic_t state;
};
struct mlx5_eswitch_rep {
struct mlx5_eswitch_rep_data rep_data[NUM_REP_TYPES];
u16 vport;
u16 vlan;
/* Only IB rep is using vport_index */
u16 vport_index;
u32 vlan_refcount;
};
static void *mlx5e_vport_rep_get_proto_dev(struct mlx5_eswitch_rep *rep)
{
struct mlx5e_rep_priv *rpriv;
rpriv = mlx5e_rep_to_rep_priv(rep);
return rpriv->netdev;
}
static inline
struct mlx5e_rep_priv *mlx5e_rep_to_rep_priv(struct mlx5_eswitch_rep *rep)
{
return rep->rep_data[REP_ETH].priv;
}
/* e-Switch vport representors */
static int
mlx5e_vport_rep_load(struct mlx5_core_dev *dev, struct mlx5_eswitch_rep *rep)
{
const struct mlx5e_profile *profile;
struct mlx5e_rep_priv *rpriv;
struct net_device *netdev;
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;
nch = mlx5e_get_max_num_channels(dev);
profile = (rep->vport == MLX5_VPORT_UPLINK) ?
&mlx5e_uplink_rep_profile : &mlx5e_rep_profile;
netdev = mlx5e_create_netdev(dev, profile, nch, rpriv);
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;
}
err = mlx5e_attach_netdev(netdev_priv(netdev));
err = mlx5e_rep_neigh_init(rpriv);
err = register_devlink_port(dev, rpriv);
err = register_netdev(netdev);
}