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

Commit c5531ca2 authored by David S. Miller's avatar David S. Miller
Browse files

Merge branch 'mlx4-next'



Or Gerlitz says:

====================
Mellanox mlx4 driver updates

The main feature added by this series are Ido's changes to support
Granular QoS for VFs, where for the time being only max rate is supported.

Muhammad added support for setting rx-fcs and rx-all through ethtool,
and Ido did the interface identify work.

Last, add Ido as a maintainer for the mlx4 Ethernet driver!

Some of next week is the Passover holiday here and I will be
mostly OOO. If needed (...) Ido or Amir will send V1 and such.

Rebased against net-next commit 033f46b3 "crypto: algif -
explicitly mark end of data".
====================

Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 9f0d34bc db603047
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -6323,6 +6323,7 @@ F: drivers/scsi/megaraid/

MELLANOX ETHERNET DRIVER (mlx4_en)
M:	Amir Vadai <amirv@mellanox.com>
M:	Ido Shamay <idos@mellanox.com>
L:	netdev@vger.kernel.org
S:	Supported
W:	http://www.mellanox.com
+6 −5
Original line number Diff line number Diff line
@@ -587,8 +587,9 @@ static int mlx4_ib_SET_PORT(struct mlx4_ib_dev *dev, u8 port, int reset_qkey_vio
		((__be32 *) mailbox->buf)[1] = cpu_to_be32(cap_mask);
	}

	err = mlx4_cmd(dev->dev, mailbox->dma, port, 0, MLX4_CMD_SET_PORT,
		       MLX4_CMD_TIME_CLASS_B, MLX4_CMD_WRAPPED);
	err = mlx4_cmd(dev->dev, mailbox->dma, port, MLX4_SET_PORT_IB_OPCODE,
		       MLX4_CMD_SET_PORT, MLX4_CMD_TIME_CLASS_B,
		       MLX4_CMD_WRAPPED);

	mlx4_free_cmd_mailbox(dev->dev, mailbox);
	return err;
@@ -1525,8 +1526,8 @@ static void update_gids_task(struct work_struct *work)
	memcpy(gids, gw->gids, sizeof gw->gids);

	err = mlx4_cmd(dev, mailbox->dma, MLX4_SET_PORT_GID_TABLE << 8 | gw->port,
		       1, MLX4_CMD_SET_PORT, MLX4_CMD_TIME_CLASS_B,
		       MLX4_CMD_WRAPPED);
		       MLX4_SET_PORT_ETH_OPCODE, MLX4_CMD_SET_PORT,
		       MLX4_CMD_TIME_CLASS_B, MLX4_CMD_WRAPPED);
	if (err)
		pr_warn("set port command failed\n");
	else
@@ -1564,7 +1565,7 @@ static void reset_gids_task(struct work_struct *work)
				    IB_LINK_LAYER_ETHERNET) {
		err = mlx4_cmd(dev, mailbox->dma,
			       MLX4_SET_PORT_GID_TABLE << 8 | gw->port,
			       1, MLX4_CMD_SET_PORT,
			       MLX4_SET_PORT_ETH_OPCODE, MLX4_CMD_SET_PORT,
			       MLX4_CMD_TIME_CLASS_B,
			       MLX4_CMD_WRAPPED);
		if (err)
+3 −2
Original line number Diff line number Diff line
obj-$(CONFIG_MLX4_CORE)		+= mlx4_core.o

mlx4_core-y :=	alloc.o catas.o cmd.o cq.o eq.o fw.o icm.o intf.o main.o mcg.o \
		mr.o pd.o port.o profile.o qp.o reset.o sense.o srq.o resource_tracker.o
mlx4_core-y :=	alloc.o catas.o cmd.o cq.o eq.o fw.o fw_qos.o icm.o intf.o \
		main.o mcg.o mr.o pd.o port.o profile.o qp.o reset.o sense.o \
		srq.o resource_tracker.o

obj-$(CONFIG_MLX4_EN)               += mlx4_en.o

+285 −7
Original line number Diff line number Diff line
@@ -48,6 +48,7 @@

#include "mlx4.h"
#include "fw.h"
#include "fw_qos.h"

#define CMD_POLL_TOKEN 0xffff
#define INBOX_MASK	0xffffffffffffff00ULL
@@ -725,7 +726,8 @@ static int mlx4_cmd_wait(struct mlx4_dev *dev, u64 in_param, u64 *out_param,
		 * specific command/input_mod/opcode_mod/fw-status to be debug.
		 */
		if (op == MLX4_CMD_SET_PORT && in_modifier == 1 &&
		    op_modifier == 0 && context->fw_status == CMD_STAT_BAD_SIZE)
		    op_modifier == MLX4_SET_PORT_IB_OPCODE &&
		    context->fw_status == CMD_STAT_BAD_SIZE)
			mlx4_dbg(dev, "command 0x%x failed: fw status = 0x%x\n",
				 op, context->fw_status);
		else
@@ -1454,6 +1456,24 @@ static struct mlx4_cmd_info cmd_info[] = {
		.verify = NULL,
		.wrapper = mlx4_CMD_EPERM_wrapper,
	},
	{
		.opcode = MLX4_CMD_ALLOCATE_VPP,
		.has_inbox = false,
		.has_outbox = true,
		.out_is_imm = false,
		.encode_slave_id = false,
		.verify = NULL,
		.wrapper = mlx4_CMD_EPERM_wrapper,
	},
	{
		.opcode = MLX4_CMD_SET_VPORT_QOS,
		.has_inbox = false,
		.has_outbox = true,
		.out_is_imm = false,
		.encode_slave_id = false,
		.verify = NULL,
		.wrapper = mlx4_CMD_EPERM_wrapper,
	},
	{
		.opcode = MLX4_CMD_CONF_SPECIAL_QP,
		.has_inbox = false,
@@ -1790,7 +1810,8 @@ static int mlx4_master_immediate_activate_vlan_qos(struct mlx4_priv *priv,

	if (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)
	    vp_oper->state.link_state == vp_admin->link_state &&
	    vp_oper->state.qos_vport == vp_admin->qos_vport)
		return 0;

	if (!(priv->mfunc.master.slave_state[slave].active &&
@@ -1848,6 +1869,7 @@ static 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;
	vp_oper->state.qos_vport = vp_admin->qos_vport;

	if (vp_admin->link_state == IFLA_VF_LINK_STATE_DISABLE)
		work->flags |= MLX4_VF_IMMED_VLAN_FLAG_LINK_DISABLE;
@@ -1856,6 +1878,7 @@ static int mlx4_master_immediate_activate_vlan_qos(struct mlx4_priv *priv,
	work->port = port;
	work->slave = slave;
	work->qos = vp_oper->state.default_qos;
	work->qos_vport = vp_oper->state.qos_vport;
	work->vlan_id = vp_oper->state.default_vlan;
	work->vlan_ix = vp_oper->vlan_idx;
	work->priv = priv;
@@ -1865,6 +1888,63 @@ static int mlx4_master_immediate_activate_vlan_qos(struct mlx4_priv *priv,
	return 0;
}

static void mlx4_set_default_port_qos(struct mlx4_dev *dev, int port)
{
	struct mlx4_qos_manager *port_qos_ctl;
	struct mlx4_priv *priv = mlx4_priv(dev);

	port_qos_ctl = &priv->mfunc.master.qos_ctl[port];
	bitmap_zero(port_qos_ctl->priority_bm, MLX4_NUM_UP);

	/* Enable only default prio at PF init routine */
	set_bit(MLX4_DEFAULT_QOS_PRIO, port_qos_ctl->priority_bm);
}

static void mlx4_allocate_port_vpps(struct mlx4_dev *dev, int port)
{
	int i;
	int err;
	int num_vfs;
	u16 availible_vpp;
	u8 vpp_param[MLX4_NUM_UP];
	struct mlx4_qos_manager *port_qos;
	struct mlx4_priv *priv = mlx4_priv(dev);

	err = mlx4_ALLOCATE_VPP_get(dev, port, &availible_vpp, vpp_param);
	if (err) {
		mlx4_info(dev, "Failed query availible VPPs\n");
		return;
	}

	port_qos = &priv->mfunc.master.qos_ctl[port];
	num_vfs = (availible_vpp /
		   bitmap_weight(port_qos->priority_bm, MLX4_NUM_UP));

	for (i = 0; i < MLX4_NUM_UP; i++) {
		if (test_bit(i, port_qos->priority_bm))
			vpp_param[i] = num_vfs;
	}

	err = mlx4_ALLOCATE_VPP_set(dev, port, vpp_param);
	if (err) {
		mlx4_info(dev, "Failed allocating VPPs\n");
		return;
	}

	/* Query actual allocated VPP, just to make sure */
	err = mlx4_ALLOCATE_VPP_get(dev, port, &availible_vpp, vpp_param);
	if (err) {
		mlx4_info(dev, "Failed query availible VPPs\n");
		return;
	}

	port_qos->num_of_qos_vfs = num_vfs;
	mlx4_dbg(dev, "Port %d Availible VPPs %d\n", port, availible_vpp);

	for (i = 0; i < MLX4_NUM_UP; i++)
		mlx4_dbg(dev, "Port %d UP %d Allocated %d VPPs\n", port, i,
			 vpp_param[i]);
}

static int mlx4_master_activate_admin_state(struct mlx4_priv *priv, int slave)
{
@@ -2212,6 +2292,9 @@ int mlx4_multi_func_init(struct mlx4_dev *dev)
	}

	if (mlx4_is_master(dev)) {
		struct mlx4_vf_oper_state *vf_oper;
		struct mlx4_vf_admin_state *vf_admin;

		priv->mfunc.master.slave_state =
			kzalloc(dev->num_slaves *
				sizeof(struct mlx4_slave_state), GFP_KERNEL);
@@ -2231,6 +2314,8 @@ int mlx4_multi_func_init(struct mlx4_dev *dev)
			goto err_comm_oper;

		for (i = 0; i < dev->num_slaves; ++i) {
			vf_admin = &priv->mfunc.master.vf_admin[i];
			vf_oper = &priv->mfunc.master.vf_oper[i];
			s_state = &priv->mfunc.master.slave_state[i];
			s_state->last_cmd = MLX4_COMM_CMD_RESET;
			mutex_init(&priv->mfunc.master.gen_eqe_mutex[i]);
@@ -2242,6 +2327,9 @@ int mlx4_multi_func_init(struct mlx4_dev *dev)
				     &priv->mfunc.comm[i].slave_read);
			mmiowb();
			for (port = 1; port <= MLX4_MAX_PORTS; port++) {
				struct mlx4_vport_state *admin_vport;
				struct mlx4_vport_state *oper_vport;

				s_state->vlan_filter[port] =
					kzalloc(sizeof(struct mlx4_vlan_fltr),
						GFP_KERNEL);
@@ -2250,15 +2338,30 @@ int mlx4_multi_func_init(struct mlx4_dev *dev)
						kfree(s_state->vlan_filter[port]);
					goto err_slaves;
				}

				admin_vport = &vf_admin->vport[port];
				oper_vport = &vf_oper->vport[port].state;
				INIT_LIST_HEAD(&s_state->mcast_filters[port]);
				priv->mfunc.master.vf_admin[i].vport[port].default_vlan = MLX4_VGT;
				priv->mfunc.master.vf_oper[i].vport[port].state.default_vlan = MLX4_VGT;
				priv->mfunc.master.vf_oper[i].vport[port].vlan_idx = NO_INDX;
				priv->mfunc.master.vf_oper[i].vport[port].mac_idx = NO_INDX;
				admin_vport->default_vlan = MLX4_VGT;
				oper_vport->default_vlan = MLX4_VGT;
				admin_vport->qos_vport =
						MLX4_VPP_DEFAULT_VPORT;
				oper_vport->qos_vport = MLX4_VPP_DEFAULT_VPORT;
				vf_oper->vport[port].vlan_idx = NO_INDX;
				vf_oper->vport[port].mac_idx = NO_INDX;
			}
			spin_lock_init(&s_state->lock);
		}

		if (dev->caps.flags2 & MLX4_DEV_CAP_FLAG2_QOS_VPP) {
			for (port = 1; port <= dev->caps.num_ports; port++) {
				if (mlx4_is_eth(dev, port)) {
					mlx4_set_default_port_qos(dev, port);
					mlx4_allocate_port_vpps(dev, port);
				}
			}
		}

		memset(&priv->mfunc.master.cmd_eqe, 0, dev->caps.eqe_size);
		priv->mfunc.master.cmd_eqe.type = MLX4_EVENT_TYPE_CMD;
		INIT_WORK(&priv->mfunc.master.comm_work,
@@ -2679,6 +2782,103 @@ static int mlx4_slaves_closest_port(struct mlx4_dev *dev, int slave, int port)
	return port;
}

static int mlx4_set_vport_qos(struct mlx4_priv *priv, int slave, int port,
			      int max_tx_rate)
{
	int i;
	int err;
	struct mlx4_qos_manager *port_qos;
	struct mlx4_dev *dev = &priv->dev;
	struct mlx4_vport_qos_param vpp_qos[MLX4_NUM_UP];

	port_qos = &priv->mfunc.master.qos_ctl[port];
	memset(vpp_qos, 0, sizeof(struct mlx4_vport_qos_param) * MLX4_NUM_UP);

	if (slave > port_qos->num_of_qos_vfs) {
		mlx4_info(dev, "No availible VPP resources for this VF\n");
		return -EINVAL;
	}

	/* Query for default QoS values from Vport 0 is needed */
	err = mlx4_SET_VPORT_QOS_get(dev, port, 0, vpp_qos);
	if (err) {
		mlx4_info(dev, "Failed to query Vport 0 QoS values\n");
		return err;
	}

	for (i = 0; i < MLX4_NUM_UP; i++) {
		if (test_bit(i, port_qos->priority_bm) && max_tx_rate) {
			vpp_qos[i].max_avg_bw = max_tx_rate;
			vpp_qos[i].enable = 1;
		} else {
			/* if user supplied tx_rate == 0, meaning no rate limit
			 * configuration is required. so we are leaving the
			 * value of max_avg_bw as queried from Vport 0.
			 */
			vpp_qos[i].enable = 0;
		}
	}

	err = mlx4_SET_VPORT_QOS_set(dev, port, slave, vpp_qos);
	if (err) {
		mlx4_info(dev, "Failed to set Vport %d QoS values\n", slave);
		return err;
	}

	return 0;
}

static bool mlx4_is_vf_vst_and_prio_qos(struct mlx4_dev *dev, int port,
					struct mlx4_vport_state *vf_admin)
{
	struct mlx4_qos_manager *info;
	struct mlx4_priv *priv = mlx4_priv(dev);

	if (!mlx4_is_master(dev) ||
	    !(dev->caps.flags2 & MLX4_DEV_CAP_FLAG2_QOS_VPP))
		return false;

	info = &priv->mfunc.master.qos_ctl[port];

	if (vf_admin->default_vlan != MLX4_VGT &&
	    test_bit(vf_admin->default_qos, info->priority_bm))
		return true;

	return false;
}

static bool mlx4_valid_vf_state_change(struct mlx4_dev *dev, int port,
				       struct mlx4_vport_state *vf_admin,
				       int vlan, int qos)
{
	struct mlx4_vport_state dummy_admin = {0};

	if (!mlx4_is_vf_vst_and_prio_qos(dev, port, vf_admin) ||
	    !vf_admin->tx_rate)
		return true;

	dummy_admin.default_qos = qos;
	dummy_admin.default_vlan = vlan;

	/* VF wants to move to other VST state which is valid with current
	 * rate limit. Either differnt default vlan in VST or other
	 * supported QoS priority. Otherwise we don't allow this change when
	 * the TX rate is still configured.
	 */
	if (mlx4_is_vf_vst_and_prio_qos(dev, port, &dummy_admin))
		return true;

	mlx4_info(dev, "Cannot change VF state to %s while rate is set\n",
		  (vlan == MLX4_VGT) ? "VGT" : "VST");

	if (vlan != MLX4_VGT)
		mlx4_info(dev, "VST priority %d not supported for QoS\n", qos);

	mlx4_info(dev, "Please set rate to 0 prior to this VF state change\n");

	return false;
}

int mlx4_set_vf_mac(struct mlx4_dev *dev, int port, int vf, u64 mac)
{
	struct mlx4_priv *priv = mlx4_priv(dev);
@@ -2722,12 +2922,22 @@ int mlx4_set_vf_vlan(struct mlx4_dev *dev, int port, int vf, u16 vlan, u8 qos)
	port = mlx4_slaves_closest_port(dev, slave, port);
	vf_admin = &priv->mfunc.master.vf_admin[slave].vport[port];

	if (!mlx4_valid_vf_state_change(dev, port, vf_admin, vlan, qos))
		return -EPERM;

	if ((0 == vlan) && (0 == qos))
		vf_admin->default_vlan = MLX4_VGT;
	else
		vf_admin->default_vlan = vlan;
	vf_admin->default_qos = qos;

	/* If rate was configured prior to VST, we saved the configured rate
	 * in vf_admin->rate and now, if priority supported we enforce the QoS
	 */
	if (mlx4_is_vf_vst_and_prio_qos(dev, port, vf_admin) &&
	    vf_admin->tx_rate)
		vf_admin->qos_vport = slave;

	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",
@@ -2736,6 +2946,69 @@ int mlx4_set_vf_vlan(struct mlx4_dev *dev, int port, int vf, u16 vlan, u8 qos)
}
EXPORT_SYMBOL_GPL(mlx4_set_vf_vlan);

int mlx4_set_vf_rate(struct mlx4_dev *dev, int port, int vf, int min_tx_rate,
		     int max_tx_rate)
{
	int err;
	int slave;
	struct mlx4_vport_state *vf_admin;
	struct mlx4_priv *priv = mlx4_priv(dev);

	if (!mlx4_is_master(dev) ||
	    !(dev->caps.flags2 & MLX4_DEV_CAP_FLAG2_QOS_VPP))
		return -EPROTONOSUPPORT;

	if (min_tx_rate) {
		mlx4_info(dev, "Minimum BW share not supported\n");
		return -EPROTONOSUPPORT;
	}

	slave = mlx4_get_slave_indx(dev, vf);
	if (slave < 0)
		return -EINVAL;

	port = mlx4_slaves_closest_port(dev, slave, port);
	vf_admin = &priv->mfunc.master.vf_admin[slave].vport[port];

	err = mlx4_set_vport_qos(priv, slave, port, max_tx_rate);
	if (err) {
		mlx4_info(dev, "vf %d failed to set rate %d\n", vf,
			  max_tx_rate);
		return err;
	}

	vf_admin->tx_rate = max_tx_rate;
	/* if VF is not in supported mode (VST with supported prio),
	 * we do not change vport configuration for its QPs, but save
	 * the rate, so it will be enforced when it moves to supported
	 * mode next time.
	 */
	if (!mlx4_is_vf_vst_and_prio_qos(dev, port, vf_admin)) {
		mlx4_info(dev,
			  "rate set for VF %d when not in valid state\n", vf);

		if (vf_admin->default_vlan != MLX4_VGT)
			mlx4_info(dev, "VST priority not supported by QoS\n");
		else
			mlx4_info(dev, "VF in VGT mode (needed VST)\n");

		mlx4_info(dev,
			  "rate %d take affect when VF moves to valid state\n",
			  max_tx_rate);
		return 0;
	}

	/* If user sets rate 0 assigning default vport for its QPs */
	vf_admin->qos_vport = max_tx_rate ? slave : MLX4_VPP_DEFAULT_VPORT;

	if (priv->mfunc.master.slave_state[slave].active &&
	    dev->caps.flags2 & MLX4_DEV_CAP_FLAG2_UPDATE_QP)
		mlx4_master_immediate_activate_vlan_qos(priv, slave, port);

	return 0;
}
EXPORT_SYMBOL_GPL(mlx4_set_vf_rate);

 /* mlx4_get_slave_default_vlan -
 * return true if VST ( default vlan)
 * if VST, will return vlan & qos (if not NULL)
@@ -2809,7 +3082,12 @@ int mlx4_get_vf_config(struct mlx4_dev *dev, int port, int vf, struct ifla_vf_in

	ivf->vlan		= s_info->default_vlan;
	ivf->qos		= s_info->default_qos;

	if (mlx4_is_vf_vst_and_prio_qos(dev, port, s_info))
		ivf->max_tx_rate = s_info->tx_rate;
	else
		ivf->max_tx_rate = 0;

	ivf->min_tx_rate	= 0;
	ivf->spoofchk		= s_info->spoofchk;
	ivf->linkstate		= s_info->link_state;
+1 −0
Original line number Diff line number Diff line
@@ -35,6 +35,7 @@
#include <linux/math64.h>

#include "mlx4_en.h"
#include "fw_qos.h"

/* Definitions for QCN
 */
Loading