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

Commit 0a6eac24 authored by Rony Efraim's avatar Rony Efraim Committed by David S. Miller
Browse files

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: default avatarRony Efraim <ronye@mellanox.com>
Signed-off-by: default avatarOr Gerlitz <ogerlitz@mellanox.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent b01978ca
Loading
Loading
Loading
Loading
+38 −19
Original line number Diff line number Diff line
@@ -1521,6 +1521,10 @@ static int mlx4_master_process_vhcr(struct mlx4_dev *dev, int slave,
	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 @@ int mlx4_master_immediate_activate_vlan_qos(struct mlx4_priv *priv,
	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 @@ int mlx4_master_immediate_activate_vlan_qos(struct mlx4_priv *priv,

	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 @@ int mlx4_set_vf_mac(struct mlx4_dev *dev, int port, int vf, u64 mac)
}
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 @@ int mlx4_set_vf_vlan(struct mlx4_dev *dev, int port, int vf, u16 vlan, u8 qos)
	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 @@ int mlx4_set_vf_vlan(struct mlx4_dev *dev, int port, int vf, u16 vlan, u8 qos)
		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 @@ int mlx4_set_vf_link_state(struct mlx4_dev *dev, int port, int vf, int link_stat
{
	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 @@ int mlx4_set_vf_link_state(struct mlx4_dev *dev, int port, int vf, int link_stat
			  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);
+1 −0
Original line number Diff line number Diff line
@@ -574,6 +574,7 @@ struct mlx4_cmd {
enum {
	MLX4_VF_IMMED_VLAN_FLAG_VLAN = 1 << 0,
	MLX4_VF_IMMED_VLAN_FLAG_QOS = 1 << 1,
	MLX4_VF_IMMED_VLAN_FLAG_LINK_DISABLE = 1 << 2,
};
struct mlx4_vf_immed_vlan_work {
	struct work_struct	work;
+19 −3
Original line number Diff line number Diff line
@@ -384,7 +384,17 @@ static int update_vport_qp_param(struct mlx4_dev *dev,

		/* force strip vlan by clear vsd */
		qpc->param3 &= ~cpu_to_be32(MLX4_STRIP_VLAN);
		if (0 != vp_oper->state.default_vlan) {

		if (vp_oper->state.link_state == IFLA_VF_LINK_STATE_DISABLE &&
		    dev->caps.flags2 & MLX4_DEV_CAP_FLAG2_UPDATE_QP) {
			qpc->pri_path.vlan_control =
				MLX4_VLAN_CTRL_ETH_TX_BLOCK_TAGGED |
				MLX4_VLAN_CTRL_ETH_TX_BLOCK_PRIO_TAGGED |
				MLX4_VLAN_CTRL_ETH_TX_BLOCK_UNTAGGED |
				MLX4_VLAN_CTRL_ETH_RX_BLOCK_PRIO_TAGGED |
				MLX4_VLAN_CTRL_ETH_RX_BLOCK_UNTAGGED |
				MLX4_VLAN_CTRL_ETH_RX_BLOCK_TAGGED;
		} else if (0 != vp_oper->state.default_vlan) {
			qpc->pri_path.vlan_control =
				MLX4_VLAN_CTRL_ETH_TX_BLOCK_TAGGED |
				MLX4_VLAN_CTRL_ETH_RX_BLOCK_PRIO_TAGGED |
@@ -4002,8 +4012,14 @@ void mlx4_vf_immed_vlan_work_handler(struct work_struct *_work)
	mailbox = mlx4_alloc_cmd_mailbox(dev);
	if (IS_ERR(mailbox))
		goto out;

	if (!work->vlan_id)
	if (work->flags & MLX4_VF_IMMED_VLAN_FLAG_LINK_DISABLE) /* block all */
		vlan_control = MLX4_VLAN_CTRL_ETH_TX_BLOCK_TAGGED |
			MLX4_VLAN_CTRL_ETH_TX_BLOCK_PRIO_TAGGED |
			MLX4_VLAN_CTRL_ETH_TX_BLOCK_UNTAGGED |
			MLX4_VLAN_CTRL_ETH_RX_BLOCK_PRIO_TAGGED |
			MLX4_VLAN_CTRL_ETH_RX_BLOCK_UNTAGGED |
			MLX4_VLAN_CTRL_ETH_RX_BLOCK_TAGGED;
	else if (!work->vlan_id)
		vlan_control = MLX4_VLAN_CTRL_ETH_TX_BLOCK_TAGGED |
			MLX4_VLAN_CTRL_ETH_RX_BLOCK_TAGGED;
	else
+2 −0
Original line number Diff line number Diff line
@@ -152,6 +152,8 @@ enum { /* fl */
};
enum { /* vlan_control */
	MLX4_VLAN_CTRL_ETH_TX_BLOCK_TAGGED	= 1 << 6,
	MLX4_VLAN_CTRL_ETH_TX_BLOCK_PRIO_TAGGED	= 1 << 5, /* 802.1p priority tag */
	MLX4_VLAN_CTRL_ETH_TX_BLOCK_UNTAGGED	= 1 << 4,
	MLX4_VLAN_CTRL_ETH_RX_BLOCK_TAGGED	= 1 << 2,
	MLX4_VLAN_CTRL_ETH_RX_BLOCK_PRIO_TAGGED	= 1 << 1, /* 802.1p priority tag */
	MLX4_VLAN_CTRL_ETH_RX_BLOCK_UNTAGGED	= 1 << 0