Commit c73a3ab8 authored by Tariq Toukan's avatar Tariq Toukan Committed by Saeed Mahameed
Browse files

net/mlx5e: Support cross-vhca RSS



Implement driver support for the HW feature that allows RX steering of
one device to target other device's RQs.

In SD multi-mdev netdev mode, we set the secondaries into silent mode,
disconnecting them from the network. This feature is then used to steer
traffic from the primary to the secondaries.

Signed-off-by: default avatarTariq Toukan <tariqt@nvidia.com>
Reviewed-by: default avatarGal Pressman <gal@nvidia.com>
Signed-off-by: default avatarSaeed Mahameed <saeedm@nvidia.com>
parent e4f9686b
Loading
Loading
Loading
Loading
+8 −2
Original line number Diff line number Diff line
@@ -23,20 +23,26 @@ bool mlx5e_channels_is_xsk(struct mlx5e_channels *chs, unsigned int ix)
	return test_bit(MLX5E_CHANNEL_STATE_XSK, c->state);
}

void mlx5e_channels_get_regular_rqn(struct mlx5e_channels *chs, unsigned int ix, u32 *rqn)
void mlx5e_channels_get_regular_rqn(struct mlx5e_channels *chs, unsigned int ix, u32 *rqn,
				    u32 *vhca_id)
{
	struct mlx5e_channel *c = mlx5e_channels_get(chs, ix);

	*rqn = c->rq.rqn;
	if (vhca_id)
		*vhca_id = MLX5_CAP_GEN(c->mdev, vhca_id);
}

void mlx5e_channels_get_xsk_rqn(struct mlx5e_channels *chs, unsigned int ix, u32 *rqn)
void mlx5e_channels_get_xsk_rqn(struct mlx5e_channels *chs, unsigned int ix, u32 *rqn,
				u32 *vhca_id)
{
	struct mlx5e_channel *c = mlx5e_channels_get(chs, ix);

	WARN_ON_ONCE(!test_bit(MLX5E_CHANNEL_STATE_XSK, c->state));

	*rqn = c->xskrq.rqn;
	if (vhca_id)
		*vhca_id = MLX5_CAP_GEN(c->mdev, vhca_id);
}

bool mlx5e_channels_get_ptp_rqn(struct mlx5e_channels *chs, u32 *rqn)
+4 −2
Original line number Diff line number Diff line
@@ -10,8 +10,10 @@ struct mlx5e_channels;

unsigned int mlx5e_channels_get_num(struct mlx5e_channels *chs);
bool mlx5e_channels_is_xsk(struct mlx5e_channels *chs, unsigned int ix);
void mlx5e_channels_get_regular_rqn(struct mlx5e_channels *chs, unsigned int ix, u32 *rqn);
void mlx5e_channels_get_xsk_rqn(struct mlx5e_channels *chs, unsigned int ix, u32 *rqn);
void mlx5e_channels_get_regular_rqn(struct mlx5e_channels *chs, unsigned int ix, u32 *rqn,
				    u32 *vhca_id);
void mlx5e_channels_get_xsk_rqn(struct mlx5e_channels *chs, unsigned int ix, u32 *rqn,
				u32 *vhca_id);
bool mlx5e_channels_get_ptp_rqn(struct mlx5e_channels *chs, u32 *rqn);

#endif /* __MLX5_EN_CHANNELS_H__ */
+100 −23
Original line number Diff line number Diff line
@@ -4,6 +4,33 @@
#include "rqt.h"
#include <linux/mlx5/transobj.h>

static bool verify_num_vhca_ids(struct mlx5_core_dev *mdev, u32 *vhca_ids,
				unsigned int size)
{
	unsigned int max_num_vhca_id = MLX5_CAP_GEN_2(mdev, max_rqt_vhca_id);
	int i;

	/* Verify that all vhca_ids are in range [0, max_num_vhca_ids - 1] */
	for (i = 0; i < size; i++)
		if (vhca_ids[i] >= max_num_vhca_id)
			return false;
	return true;
}

static bool rqt_verify_vhca_ids(struct mlx5_core_dev *mdev, u32 *vhca_ids,
				unsigned int size)
{
	if (!vhca_ids)
		return true;

	if (!MLX5_CAP_GEN(mdev, cross_vhca_rqt))
		return false;
	if (!verify_num_vhca_ids(mdev, vhca_ids, size))
		return false;

	return true;
}

void mlx5e_rss_params_indir_init_uniform(struct mlx5e_rss_params_indir *indir,
					 unsigned int num_channels)
{
@@ -13,19 +40,38 @@ void mlx5e_rss_params_indir_init_uniform(struct mlx5e_rss_params_indir *indir,
		indir->table[i] = i % num_channels;
}

static void fill_rqn_list(void *rqtc, u32 *rqns, u32 *vhca_ids, unsigned int size)
{
	unsigned int i;

	if (vhca_ids) {
		MLX5_SET(rqtc, rqtc, rq_vhca_id_format, 1);
		for (i = 0; i < size; i++) {
			MLX5_SET(rqtc, rqtc, rq_vhca[i].rq_num, rqns[i]);
			MLX5_SET(rqtc, rqtc, rq_vhca[i].rq_vhca_id, vhca_ids[i]);
		}
	} else {
		for (i = 0; i < size; i++)
			MLX5_SET(rqtc, rqtc, rq_num[i], rqns[i]);
	}
}
static int mlx5e_rqt_init(struct mlx5e_rqt *rqt, struct mlx5_core_dev *mdev,
			  u16 max_size, u32 *init_rqns, u16 init_size)
			  u16 max_size, u32 *init_rqns, u32 *init_vhca_ids, u16 init_size)
{
	int entry_sz;
	void *rqtc;
	int inlen;
	int err;
	u32 *in;
	int i;

	if (!rqt_verify_vhca_ids(mdev, init_vhca_ids, init_size))
		return -EOPNOTSUPP;

	rqt->mdev = mdev;
	rqt->size = max_size;

	inlen = MLX5_ST_SZ_BYTES(create_rqt_in) + sizeof(u32) * init_size;
	entry_sz = init_vhca_ids ? MLX5_ST_SZ_BYTES(rq_vhca) : MLX5_ST_SZ_BYTES(rq_num);
	inlen = MLX5_ST_SZ_BYTES(create_rqt_in) + entry_sz * init_size;
	in = kvzalloc(inlen, GFP_KERNEL);
	if (!in)
		return -ENOMEM;
@@ -33,10 +79,9 @@ static int mlx5e_rqt_init(struct mlx5e_rqt *rqt, struct mlx5_core_dev *mdev,
	rqtc = MLX5_ADDR_OF(create_rqt_in, in, rqt_context);

	MLX5_SET(rqtc, rqtc, rqt_max_size, rqt->size);

	MLX5_SET(rqtc, rqtc, rqt_actual_size, init_size);
	for (i = 0; i < init_size; i++)
		MLX5_SET(rqtc, rqtc, rq_num[i], init_rqns[i]);

	fill_rqn_list(rqtc, init_rqns, init_vhca_ids, init_size);

	err = mlx5_core_create_rqt(rqt->mdev, in, inlen, &rqt->rqtn);

@@ -49,7 +94,7 @@ int mlx5e_rqt_init_direct(struct mlx5e_rqt *rqt, struct mlx5_core_dev *mdev,
{
	u16 max_size = indir_enabled ? indir_table_size : 1;

	return mlx5e_rqt_init(rqt, mdev, max_size, &init_rqn, 1);
	return mlx5e_rqt_init(rqt, mdev, max_size, &init_rqn, NULL, 1);
}

static int mlx5e_bits_invert(unsigned long a, int size)
@@ -63,7 +108,8 @@ static int mlx5e_bits_invert(unsigned long a, int size)
	return inv;
}

static int mlx5e_calc_indir_rqns(u32 *rss_rqns, u32 *rqns, unsigned int num_rqns,
static int mlx5e_calc_indir_rqns(u32 *rss_rqns, u32 *rqns, u32 *rss_vhca_ids, u32 *vhca_ids,
				 unsigned int num_rqns,
				 u8 hfunc, struct mlx5e_rss_params_indir *indir)
{
	unsigned int i;
@@ -82,30 +128,42 @@ static int mlx5e_calc_indir_rqns(u32 *rss_rqns, u32 *rqns, unsigned int num_rqns
			 */
			return -EINVAL;
		rss_rqns[i] = rqns[ix];
		if (vhca_ids)
			rss_vhca_ids[i] = vhca_ids[ix];
	}

	return 0;
}

int mlx5e_rqt_init_indir(struct mlx5e_rqt *rqt, struct mlx5_core_dev *mdev,
			 u32 *rqns, unsigned int num_rqns,
			 u32 *rqns, u32 *vhca_ids, unsigned int num_rqns,
			 u8 hfunc, struct mlx5e_rss_params_indir *indir)
{
	u32 *rss_rqns;
	u32 *rss_rqns, *rss_vhca_ids = NULL;
	int err;

	rss_rqns = kvmalloc_array(indir->actual_table_size, sizeof(*rss_rqns), GFP_KERNEL);
	if (!rss_rqns)
		return -ENOMEM;

	err = mlx5e_calc_indir_rqns(rss_rqns, rqns, num_rqns, hfunc, indir);
	if (vhca_ids) {
		rss_vhca_ids = kvmalloc_array(indir->actual_table_size, sizeof(*rss_vhca_ids),
					      GFP_KERNEL);
		if (!rss_vhca_ids) {
			kvfree(rss_rqns);
			return -ENOMEM;
		}
	}

	err = mlx5e_calc_indir_rqns(rss_rqns, rqns, rss_vhca_ids, vhca_ids, num_rqns, hfunc, indir);
	if (err)
		goto out;

	err = mlx5e_rqt_init(rqt, mdev, indir->max_table_size, rss_rqns,
	err = mlx5e_rqt_init(rqt, mdev, indir->max_table_size, rss_rqns, rss_vhca_ids,
			     indir->actual_table_size);

out:
	kvfree(rss_vhca_ids);
	kvfree(rss_rqns);
	return err;
}
@@ -126,15 +184,20 @@ void mlx5e_rqt_destroy(struct mlx5e_rqt *rqt)
	mlx5_core_destroy_rqt(rqt->mdev, rqt->rqtn);
}

static int mlx5e_rqt_redirect(struct mlx5e_rqt *rqt, u32 *rqns, unsigned int size)
static int mlx5e_rqt_redirect(struct mlx5e_rqt *rqt, u32 *rqns, u32 *vhca_ids,
			      unsigned int size)
{
	unsigned int i;
	int entry_sz;
	void *rqtc;
	int inlen;
	u32 *in;
	int err;

	inlen = MLX5_ST_SZ_BYTES(modify_rqt_in) + sizeof(u32) * size;
	if (!rqt_verify_vhca_ids(rqt->mdev, vhca_ids, size))
		return -EINVAL;

	entry_sz = vhca_ids ? MLX5_ST_SZ_BYTES(rq_vhca) : MLX5_ST_SZ_BYTES(rq_num);
	inlen = MLX5_ST_SZ_BYTES(modify_rqt_in) + entry_sz * size;
	in = kvzalloc(inlen, GFP_KERNEL);
	if (!in)
		return -ENOMEM;
@@ -143,8 +206,8 @@ static int mlx5e_rqt_redirect(struct mlx5e_rqt *rqt, u32 *rqns, unsigned int siz

	MLX5_SET(modify_rqt_in, in, bitmask.rqn_list, 1);
	MLX5_SET(rqtc, rqtc, rqt_actual_size, size);
	for (i = 0; i < size; i++)
		MLX5_SET(rqtc, rqtc, rq_num[i], rqns[i]);

	fill_rqn_list(rqtc, rqns, vhca_ids, size);

	err = mlx5_core_modify_rqt(rqt->mdev, rqt->rqtn, in, inlen);

@@ -152,17 +215,21 @@ static int mlx5e_rqt_redirect(struct mlx5e_rqt *rqt, u32 *rqns, unsigned int siz
	return err;
}

int mlx5e_rqt_redirect_direct(struct mlx5e_rqt *rqt, u32 rqn)
int mlx5e_rqt_redirect_direct(struct mlx5e_rqt *rqt, u32 rqn, u32 *vhca_id)
{
	return mlx5e_rqt_redirect(rqt, &rqn, 1);
	return mlx5e_rqt_redirect(rqt, &rqn, vhca_id, 1);
}

int mlx5e_rqt_redirect_indir(struct mlx5e_rqt *rqt, u32 *rqns, unsigned int num_rqns,
int mlx5e_rqt_redirect_indir(struct mlx5e_rqt *rqt, u32 *rqns, u32 *vhca_ids,
			     unsigned int num_rqns,
			     u8 hfunc, struct mlx5e_rss_params_indir *indir)
{
	u32 *rss_rqns;
	u32 *rss_rqns, *rss_vhca_ids = NULL;
	int err;

	if (!rqt_verify_vhca_ids(rqt->mdev, vhca_ids, num_rqns))
		return -EINVAL;

	if (WARN_ON(rqt->size != indir->max_table_size))
		return -EINVAL;

@@ -170,13 +237,23 @@ int mlx5e_rqt_redirect_indir(struct mlx5e_rqt *rqt, u32 *rqns, unsigned int num_
	if (!rss_rqns)
		return -ENOMEM;

	err = mlx5e_calc_indir_rqns(rss_rqns, rqns, num_rqns, hfunc, indir);
	if (vhca_ids) {
		rss_vhca_ids = kvmalloc_array(indir->actual_table_size, sizeof(*rss_vhca_ids),
					      GFP_KERNEL);
		if (!rss_vhca_ids) {
			kvfree(rss_rqns);
			return -ENOMEM;
		}
	}

	err = mlx5e_calc_indir_rqns(rss_rqns, rqns, rss_vhca_ids, vhca_ids, num_rqns, hfunc, indir);
	if (err)
		goto out;

	err = mlx5e_rqt_redirect(rqt, rss_rqns, indir->actual_table_size);
	err = mlx5e_rqt_redirect(rqt, rss_rqns, rss_vhca_ids, indir->actual_table_size);

out:
	kvfree(rss_vhca_ids);
	kvfree(rss_rqns);
	return err;
}
+5 −4
Original line number Diff line number Diff line
@@ -20,7 +20,7 @@ void mlx5e_rss_params_indir_init_uniform(struct mlx5e_rss_params_indir *indir,
					 unsigned int num_channels);

struct mlx5e_rqt {
	struct mlx5_core_dev *mdev;
	struct mlx5_core_dev *mdev; /* primary */
	u32 rqtn;
	u16 size;
};
@@ -28,7 +28,7 @@ struct mlx5e_rqt {
int mlx5e_rqt_init_direct(struct mlx5e_rqt *rqt, struct mlx5_core_dev *mdev,
			  bool indir_enabled, u32 init_rqn, u32 indir_table_size);
int mlx5e_rqt_init_indir(struct mlx5e_rqt *rqt, struct mlx5_core_dev *mdev,
			 u32 *rqns, unsigned int num_rqns,
			 u32 *rqns, u32 *vhca_ids, unsigned int num_rqns,
			 u8 hfunc, struct mlx5e_rss_params_indir *indir);
void mlx5e_rqt_destroy(struct mlx5e_rqt *rqt);

@@ -38,8 +38,9 @@ static inline u32 mlx5e_rqt_get_rqtn(struct mlx5e_rqt *rqt)
}

u32 mlx5e_rqt_size(struct mlx5_core_dev *mdev, unsigned int num_channels);
int mlx5e_rqt_redirect_direct(struct mlx5e_rqt *rqt, u32 rqn);
int mlx5e_rqt_redirect_indir(struct mlx5e_rqt *rqt, u32 *rqns, unsigned int num_rqns,
int mlx5e_rqt_redirect_direct(struct mlx5e_rqt *rqt, u32 rqn, u32 *vhca_id);
int mlx5e_rqt_redirect_indir(struct mlx5e_rqt *rqt, u32 *rqns, u32 *vhca_ids,
			     unsigned int num_rqns,
			     u8 hfunc, struct mlx5e_rss_params_indir *indir);

#endif /* __MLX5_EN_RQT_H__ */
+9 −8
Original line number Diff line number Diff line
@@ -74,7 +74,7 @@ struct mlx5e_rss {
	struct mlx5e_tir *tir[MLX5E_NUM_INDIR_TIRS];
	struct mlx5e_tir *inner_tir[MLX5E_NUM_INDIR_TIRS];
	struct mlx5e_rqt rqt;
	struct mlx5_core_dev *mdev;
	struct mlx5_core_dev *mdev; /* primary */
	u32 drop_rqn;
	bool inner_ft_support;
	bool enabled;
@@ -473,21 +473,22 @@ int mlx5e_rss_obtain_tirn(struct mlx5e_rss *rss,
	return 0;
}

static int mlx5e_rss_apply(struct mlx5e_rss *rss, u32 *rqns, unsigned int num_rqns)
static int mlx5e_rss_apply(struct mlx5e_rss *rss, u32 *rqns, u32 *vhca_ids, unsigned int num_rqns)
{
	int err;

	err = mlx5e_rqt_redirect_indir(&rss->rqt, rqns, num_rqns, rss->hash.hfunc, &rss->indir);
	err = mlx5e_rqt_redirect_indir(&rss->rqt, rqns, vhca_ids, num_rqns, rss->hash.hfunc,
				       &rss->indir);
	if (err)
		mlx5e_rss_warn(rss->mdev, "Failed to redirect RQT %#x to channels: err = %d\n",
			       mlx5e_rqt_get_rqtn(&rss->rqt), err);
	return err;
}

void mlx5e_rss_enable(struct mlx5e_rss *rss, u32 *rqns, unsigned int num_rqns)
void mlx5e_rss_enable(struct mlx5e_rss *rss, u32 *rqns, u32 *vhca_ids, unsigned int num_rqns)
{
	rss->enabled = true;
	mlx5e_rss_apply(rss, rqns, num_rqns);
	mlx5e_rss_apply(rss, rqns, vhca_ids, num_rqns);
}

void mlx5e_rss_disable(struct mlx5e_rss *rss)
@@ -495,7 +496,7 @@ void mlx5e_rss_disable(struct mlx5e_rss *rss)
	int err;

	rss->enabled = false;
	err = mlx5e_rqt_redirect_direct(&rss->rqt, rss->drop_rqn);
	err = mlx5e_rqt_redirect_direct(&rss->rqt, rss->drop_rqn, NULL);
	if (err)
		mlx5e_rss_warn(rss->mdev, "Failed to redirect RQT %#x to drop RQ %#x: err = %d\n",
			       mlx5e_rqt_get_rqtn(&rss->rqt), rss->drop_rqn, err);
@@ -568,7 +569,7 @@ int mlx5e_rss_get_rxfh(struct mlx5e_rss *rss, u32 *indir, u8 *key, u8 *hfunc)

int mlx5e_rss_set_rxfh(struct mlx5e_rss *rss, const u32 *indir,
		       const u8 *key, const u8 *hfunc,
		       u32 *rqns, unsigned int num_rqns)
		       u32 *rqns, u32 *vhca_ids, unsigned int num_rqns)
{
	bool changed_indir = false;
	bool changed_hash = false;
@@ -608,7 +609,7 @@ int mlx5e_rss_set_rxfh(struct mlx5e_rss *rss, const u32 *indir,
	}

	if (changed_indir && rss->enabled) {
		err = mlx5e_rss_apply(rss, rqns, num_rqns);
		err = mlx5e_rss_apply(rss, rqns, vhca_ids, num_rqns);
		if (err) {
			mlx5e_rss_copy(rss, old_rss);
			goto out;
Loading