net/mlx4_core: Add HW enforcement to VF link state
When the firmware supports the UPDATE_QP command, if the VF link is disabled,
block all QPs opened by the VF, by programming the UPDATE_QP command to drop
all RX & TX traffic to/from these QPs. Operates only in VST mode.
Signed-off-by: Rony Efraim <ronye@mellanox.com>
Signed-off-by: Or Gerlitz <ogerlitz@mellanox.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
diff --git a/drivers/net/ethernet/mellanox/mlx4/cmd.c b/drivers/net/ethernet/mellanox/mlx4/cmd.c
index 7b92789..707a7d0 100644
--- a/drivers/net/ethernet/mellanox/mlx4/cmd.c
+++ b/drivers/net/ethernet/mellanox/mlx4/cmd.c
@@ -1521,6 +1521,10 @@
return ret;
}
+static int calculate_transition(u16 oper_vlan, u16 admin_vlan)
+{
+ return (2 * (oper_vlan == MLX4_VGT) + (admin_vlan == MLX4_VGT));
+}
int mlx4_master_immediate_activate_vlan_qos(struct mlx4_priv *priv,
int slave, int port)
@@ -1528,16 +1532,37 @@
struct mlx4_vport_oper_state *vp_oper;
struct mlx4_vport_state *vp_admin;
struct mlx4_vf_immed_vlan_work *work;
+ struct mlx4_dev *dev = &(priv->dev);
int err;
int admin_vlan_ix = NO_INDX;
+ enum mlx4_vlan_transition vlan_trans;
vp_oper = &priv->mfunc.master.vf_oper[slave].vport[port];
vp_admin = &priv->mfunc.master.vf_admin[slave].vport[port];
if (vp_oper->state.default_vlan == vp_admin->default_vlan &&
- vp_oper->state.default_qos == vp_admin->default_qos)
+ vp_oper->state.default_qos == vp_admin->default_qos &&
+ vp_oper->state.link_state == vp_admin->link_state)
return 0;
+ vlan_trans = calculate_transition(vp_oper->state.default_vlan,
+ vp_admin->default_vlan);
+
+ if (!(priv->mfunc.master.slave_state[slave].active &&
+ dev->caps.flags2 & MLX4_DEV_CAP_FLAG2_UPDATE_QP &&
+ vlan_trans == MLX4_VLAN_TRANSITION_VST_VST)) {
+ /* even if the UPDATE_QP command isn't supported, we still want
+ * to set this VF link according to the admin directive
+ */
+ vp_oper->state.link_state = vp_admin->link_state;
+ return -1;
+ }
+
+ mlx4_dbg(dev, "updating immediately admin params slave %d port %d\n",
+ slave, port);
+ mlx4_dbg(dev, "vlan %d QoS %d link down %d\n", vp_admin->default_vlan,
+ vp_admin->default_qos, vp_admin->link_state);
+
work = kzalloc(sizeof(*work), GFP_KERNEL);
if (!work)
return -ENOMEM;
@@ -1572,6 +1597,10 @@
vp_oper->state.default_vlan = vp_admin->default_vlan;
vp_oper->state.default_qos = vp_admin->default_qos;
+ vp_oper->state.link_state = vp_admin->link_state;
+
+ if (vp_admin->link_state == IFLA_VF_LINK_STATE_DISABLE)
+ work->flags |= MLX4_VF_IMMED_VLAN_FLAG_LINK_DISABLE;
/* iterate over QPs owned by this slave, using UPDATE_QP */
work->port = port;
@@ -2201,10 +2230,6 @@
}
EXPORT_SYMBOL_GPL(mlx4_set_vf_mac);
-static int calculate_transition(u16 oper_vlan, u16 admin_vlan)
-{
- return (2 * (oper_vlan == MLX4_VGT) + (admin_vlan == MLX4_VGT));
-}
int mlx4_set_vf_vlan(struct mlx4_dev *dev, int port, int vf, u16 vlan, u8 qos)
{
@@ -2212,7 +2237,6 @@
struct mlx4_vport_oper_state *vf_oper;
struct mlx4_vport_state *vf_admin;
int slave;
- enum mlx4_vlan_transition vlan_trans;
if ((!mlx4_is_master(dev)) ||
!(dev->caps.flags2 & MLX4_DEV_CAP_FLAG2_VLAN_CONTROL))
@@ -2234,16 +2258,10 @@
vf_admin->default_vlan = vlan;
vf_admin->default_qos = qos;
- vlan_trans = calculate_transition(vf_oper->state.default_vlan,
- vf_admin->default_vlan);
-
- if (priv->mfunc.master.slave_state[slave].active &&
- dev->caps.flags2 & MLX4_DEV_CAP_FLAG2_UPDATE_QP &&
- vlan_trans == MLX4_VLAN_TRANSITION_VST_VST) {
- mlx4_info(dev, "updating vf %d port %d config params immediately\n",
+ if (mlx4_master_immediate_activate_vlan_qos(priv, slave, port))
+ mlx4_info(dev,
+ "updating vf %d port %d config will take effect on next VF restart\n",
vf, port);
- mlx4_master_immediate_activate_vlan_qos(priv, slave, port);
- }
return 0;
}
EXPORT_SYMBOL_GPL(mlx4_set_vf_vlan);
@@ -2307,7 +2325,6 @@
{
struct mlx4_priv *priv = mlx4_priv(dev);
struct mlx4_vport_state *s_info;
- struct mlx4_vport_oper_state *vp_oper;
int slave;
u8 link_stat_event;
@@ -2337,14 +2354,16 @@
link_state, slave, port);
return -EINVAL;
};
- /* update the admin & oper state on the link state */
s_info = &priv->mfunc.master.vf_admin[slave].vport[port];
- vp_oper = &priv->mfunc.master.vf_oper[slave].vport[port];
s_info->link_state = link_state;
- vp_oper->state.link_state = link_state;
/* send event */
mlx4_gen_port_state_change_eqe(dev, slave, port, link_stat_event);
+
+ if (mlx4_master_immediate_activate_vlan_qos(priv, slave, port))
+ mlx4_dbg(dev,
+ "updating vf %d port %d no link state HW enforcment\n",
+ vf, port);
return 0;
}
EXPORT_SYMBOL_GPL(mlx4_set_vf_link_state);