106e9f13aSMaxim Mikityanskiy // SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB
206e9f13aSMaxim Mikityanskiy /* Copyright (c) 2021, Mellanox Technologies inc. All rights reserved. */
306e9f13aSMaxim Mikityanskiy 
406e9f13aSMaxim Mikityanskiy #include "rqt.h"
506e9f13aSMaxim Mikityanskiy #include <linux/mlx5/transobj.h>
606e9f13aSMaxim Mikityanskiy 
mlx5e_rss_params_indir_init_uniform(struct mlx5e_rss_params_indir * indir,unsigned int num_channels)7*43befe99SMaxim Mikityanskiy void mlx5e_rss_params_indir_init_uniform(struct mlx5e_rss_params_indir *indir,
8*43befe99SMaxim Mikityanskiy 					 unsigned int num_channels)
9*43befe99SMaxim Mikityanskiy {
10*43befe99SMaxim Mikityanskiy 	unsigned int i;
11*43befe99SMaxim Mikityanskiy 
12*43befe99SMaxim Mikityanskiy 	for (i = 0; i < MLX5E_INDIR_RQT_SIZE; i++)
13*43befe99SMaxim Mikityanskiy 		indir->table[i] = i % num_channels;
14*43befe99SMaxim Mikityanskiy }
15*43befe99SMaxim Mikityanskiy 
mlx5e_rqt_init(struct mlx5e_rqt * rqt,struct mlx5_core_dev * mdev,u16 max_size,u32 * init_rqns,u16 init_size)1606e9f13aSMaxim Mikityanskiy static int mlx5e_rqt_init(struct mlx5e_rqt *rqt, struct mlx5_core_dev *mdev,
1706e9f13aSMaxim Mikityanskiy 			  u16 max_size, u32 *init_rqns, u16 init_size)
1806e9f13aSMaxim Mikityanskiy {
1906e9f13aSMaxim Mikityanskiy 	void *rqtc;
2006e9f13aSMaxim Mikityanskiy 	int inlen;
2106e9f13aSMaxim Mikityanskiy 	int err;
2206e9f13aSMaxim Mikityanskiy 	u32 *in;
2306e9f13aSMaxim Mikityanskiy 	int i;
2406e9f13aSMaxim Mikityanskiy 
2506e9f13aSMaxim Mikityanskiy 	rqt->mdev = mdev;
2606e9f13aSMaxim Mikityanskiy 	rqt->size = max_size;
2706e9f13aSMaxim Mikityanskiy 
2806e9f13aSMaxim Mikityanskiy 	inlen = MLX5_ST_SZ_BYTES(create_rqt_in) + sizeof(u32) * init_size;
2906e9f13aSMaxim Mikityanskiy 	in = kvzalloc(inlen, GFP_KERNEL);
3006e9f13aSMaxim Mikityanskiy 	if (!in)
3106e9f13aSMaxim Mikityanskiy 		return -ENOMEM;
3206e9f13aSMaxim Mikityanskiy 
3306e9f13aSMaxim Mikityanskiy 	rqtc = MLX5_ADDR_OF(create_rqt_in, in, rqt_context);
3406e9f13aSMaxim Mikityanskiy 
3506e9f13aSMaxim Mikityanskiy 	MLX5_SET(rqtc, rqtc, rqt_max_size, rqt->size);
3606e9f13aSMaxim Mikityanskiy 
3706e9f13aSMaxim Mikityanskiy 	MLX5_SET(rqtc, rqtc, rqt_actual_size, init_size);
3806e9f13aSMaxim Mikityanskiy 	for (i = 0; i < init_size; i++)
3906e9f13aSMaxim Mikityanskiy 		MLX5_SET(rqtc, rqtc, rq_num[i], init_rqns[i]);
4006e9f13aSMaxim Mikityanskiy 
4106e9f13aSMaxim Mikityanskiy 	err = mlx5_core_create_rqt(rqt->mdev, in, inlen, &rqt->rqtn);
4206e9f13aSMaxim Mikityanskiy 
4306e9f13aSMaxim Mikityanskiy 	kvfree(in);
4406e9f13aSMaxim Mikityanskiy 	return err;
4506e9f13aSMaxim Mikityanskiy }
4606e9f13aSMaxim Mikityanskiy 
mlx5e_rqt_init_direct(struct mlx5e_rqt * rqt,struct mlx5_core_dev * mdev,bool indir_enabled,u32 init_rqn)4706e9f13aSMaxim Mikityanskiy int mlx5e_rqt_init_direct(struct mlx5e_rqt *rqt, struct mlx5_core_dev *mdev,
4806e9f13aSMaxim Mikityanskiy 			  bool indir_enabled, u32 init_rqn)
4906e9f13aSMaxim Mikityanskiy {
5006e9f13aSMaxim Mikityanskiy 	u16 max_size = indir_enabled ? MLX5E_INDIR_RQT_SIZE : 1;
5106e9f13aSMaxim Mikityanskiy 
5206e9f13aSMaxim Mikityanskiy 	return mlx5e_rqt_init(rqt, mdev, max_size, &init_rqn, 1);
5306e9f13aSMaxim Mikityanskiy }
5406e9f13aSMaxim Mikityanskiy 
mlx5e_bits_invert(unsigned long a,int size)5506e9f13aSMaxim Mikityanskiy static int mlx5e_bits_invert(unsigned long a, int size)
5606e9f13aSMaxim Mikityanskiy {
5706e9f13aSMaxim Mikityanskiy 	int inv = 0;
5806e9f13aSMaxim Mikityanskiy 	int i;
5906e9f13aSMaxim Mikityanskiy 
6006e9f13aSMaxim Mikityanskiy 	for (i = 0; i < size; i++)
6106e9f13aSMaxim Mikityanskiy 		inv |= (test_bit(size - i - 1, &a) ? 1 : 0) << i;
6206e9f13aSMaxim Mikityanskiy 
6306e9f13aSMaxim Mikityanskiy 	return inv;
6406e9f13aSMaxim Mikityanskiy }
6506e9f13aSMaxim Mikityanskiy 
mlx5e_calc_indir_rqns(u32 * rss_rqns,u32 * rqns,unsigned int num_rqns,u8 hfunc,struct mlx5e_rss_params_indir * indir)6606e9f13aSMaxim Mikityanskiy static int mlx5e_calc_indir_rqns(u32 *rss_rqns, u32 *rqns, unsigned int num_rqns,
6706e9f13aSMaxim Mikityanskiy 				 u8 hfunc, struct mlx5e_rss_params_indir *indir)
6806e9f13aSMaxim Mikityanskiy {
6906e9f13aSMaxim Mikityanskiy 	unsigned int i;
7006e9f13aSMaxim Mikityanskiy 
7106e9f13aSMaxim Mikityanskiy 	for (i = 0; i < MLX5E_INDIR_RQT_SIZE; i++) {
7206e9f13aSMaxim Mikityanskiy 		unsigned int ix = i;
7306e9f13aSMaxim Mikityanskiy 
7406e9f13aSMaxim Mikityanskiy 		if (hfunc == ETH_RSS_HASH_XOR)
7506e9f13aSMaxim Mikityanskiy 			ix = mlx5e_bits_invert(ix, ilog2(MLX5E_INDIR_RQT_SIZE));
7606e9f13aSMaxim Mikityanskiy 
7706e9f13aSMaxim Mikityanskiy 		ix = indir->table[ix];
7806e9f13aSMaxim Mikityanskiy 
7906e9f13aSMaxim Mikityanskiy 		if (WARN_ON(ix >= num_rqns))
8006e9f13aSMaxim Mikityanskiy 			/* Could be a bug in the driver or in the kernel part of
8106e9f13aSMaxim Mikityanskiy 			 * ethtool: indir table refers to non-existent RQs.
8206e9f13aSMaxim Mikityanskiy 			 */
8306e9f13aSMaxim Mikityanskiy 			return -EINVAL;
8406e9f13aSMaxim Mikityanskiy 		rss_rqns[i] = rqns[ix];
8506e9f13aSMaxim Mikityanskiy 	}
8606e9f13aSMaxim Mikityanskiy 
8706e9f13aSMaxim Mikityanskiy 	return 0;
8806e9f13aSMaxim Mikityanskiy }
8906e9f13aSMaxim Mikityanskiy 
mlx5e_rqt_init_indir(struct mlx5e_rqt * rqt,struct mlx5_core_dev * mdev,u32 * rqns,unsigned int num_rqns,u8 hfunc,struct mlx5e_rss_params_indir * indir)9006e9f13aSMaxim Mikityanskiy int mlx5e_rqt_init_indir(struct mlx5e_rqt *rqt, struct mlx5_core_dev *mdev,
9106e9f13aSMaxim Mikityanskiy 			 u32 *rqns, unsigned int num_rqns,
9206e9f13aSMaxim Mikityanskiy 			 u8 hfunc, struct mlx5e_rss_params_indir *indir)
9306e9f13aSMaxim Mikityanskiy {
9406e9f13aSMaxim Mikityanskiy 	u32 *rss_rqns;
9506e9f13aSMaxim Mikityanskiy 	int err;
9606e9f13aSMaxim Mikityanskiy 
9706e9f13aSMaxim Mikityanskiy 	rss_rqns = kvmalloc_array(MLX5E_INDIR_RQT_SIZE, sizeof(*rss_rqns), GFP_KERNEL);
9806e9f13aSMaxim Mikityanskiy 	if (!rss_rqns)
9906e9f13aSMaxim Mikityanskiy 		return -ENOMEM;
10006e9f13aSMaxim Mikityanskiy 
10106e9f13aSMaxim Mikityanskiy 	err = mlx5e_calc_indir_rqns(rss_rqns, rqns, num_rqns, hfunc, indir);
10206e9f13aSMaxim Mikityanskiy 	if (err)
10306e9f13aSMaxim Mikityanskiy 		goto out;
10406e9f13aSMaxim Mikityanskiy 
10506e9f13aSMaxim Mikityanskiy 	err = mlx5e_rqt_init(rqt, mdev, MLX5E_INDIR_RQT_SIZE, rss_rqns, MLX5E_INDIR_RQT_SIZE);
10606e9f13aSMaxim Mikityanskiy 
10706e9f13aSMaxim Mikityanskiy out:
10806e9f13aSMaxim Mikityanskiy 	kvfree(rss_rqns);
10906e9f13aSMaxim Mikityanskiy 	return err;
11006e9f13aSMaxim Mikityanskiy }
11106e9f13aSMaxim Mikityanskiy 
mlx5e_rqt_destroy(struct mlx5e_rqt * rqt)11206e9f13aSMaxim Mikityanskiy void mlx5e_rqt_destroy(struct mlx5e_rqt *rqt)
11306e9f13aSMaxim Mikityanskiy {
11406e9f13aSMaxim Mikityanskiy 	mlx5_core_destroy_rqt(rqt->mdev, rqt->rqtn);
11506e9f13aSMaxim Mikityanskiy }
11606e9f13aSMaxim Mikityanskiy 
mlx5e_rqt_redirect(struct mlx5e_rqt * rqt,u32 * rqns,unsigned int size)11706e9f13aSMaxim Mikityanskiy static int mlx5e_rqt_redirect(struct mlx5e_rqt *rqt, u32 *rqns, unsigned int size)
11806e9f13aSMaxim Mikityanskiy {
11906e9f13aSMaxim Mikityanskiy 	unsigned int i;
12006e9f13aSMaxim Mikityanskiy 	void *rqtc;
12106e9f13aSMaxim Mikityanskiy 	int inlen;
12206e9f13aSMaxim Mikityanskiy 	u32 *in;
12306e9f13aSMaxim Mikityanskiy 	int err;
12406e9f13aSMaxim Mikityanskiy 
12506e9f13aSMaxim Mikityanskiy 	inlen = MLX5_ST_SZ_BYTES(modify_rqt_in) + sizeof(u32) * size;
12606e9f13aSMaxim Mikityanskiy 	in = kvzalloc(inlen, GFP_KERNEL);
12706e9f13aSMaxim Mikityanskiy 	if (!in)
12806e9f13aSMaxim Mikityanskiy 		return -ENOMEM;
12906e9f13aSMaxim Mikityanskiy 
13006e9f13aSMaxim Mikityanskiy 	rqtc = MLX5_ADDR_OF(modify_rqt_in, in, ctx);
13106e9f13aSMaxim Mikityanskiy 
13206e9f13aSMaxim Mikityanskiy 	MLX5_SET(modify_rqt_in, in, bitmask.rqn_list, 1);
13306e9f13aSMaxim Mikityanskiy 	MLX5_SET(rqtc, rqtc, rqt_actual_size, size);
13406e9f13aSMaxim Mikityanskiy 	for (i = 0; i < size; i++)
13506e9f13aSMaxim Mikityanskiy 		MLX5_SET(rqtc, rqtc, rq_num[i], rqns[i]);
13606e9f13aSMaxim Mikityanskiy 
13706e9f13aSMaxim Mikityanskiy 	err = mlx5_core_modify_rqt(rqt->mdev, rqt->rqtn, in, inlen);
13806e9f13aSMaxim Mikityanskiy 
13906e9f13aSMaxim Mikityanskiy 	kvfree(in);
14006e9f13aSMaxim Mikityanskiy 	return err;
14106e9f13aSMaxim Mikityanskiy }
14206e9f13aSMaxim Mikityanskiy 
mlx5e_rqt_redirect_direct(struct mlx5e_rqt * rqt,u32 rqn)14306e9f13aSMaxim Mikityanskiy int mlx5e_rqt_redirect_direct(struct mlx5e_rqt *rqt, u32 rqn)
14406e9f13aSMaxim Mikityanskiy {
14506e9f13aSMaxim Mikityanskiy 	return mlx5e_rqt_redirect(rqt, &rqn, 1);
14606e9f13aSMaxim Mikityanskiy }
14706e9f13aSMaxim Mikityanskiy 
mlx5e_rqt_redirect_indir(struct mlx5e_rqt * rqt,u32 * rqns,unsigned int num_rqns,u8 hfunc,struct mlx5e_rss_params_indir * indir)14806e9f13aSMaxim Mikityanskiy int mlx5e_rqt_redirect_indir(struct mlx5e_rqt *rqt, u32 *rqns, unsigned int num_rqns,
14906e9f13aSMaxim Mikityanskiy 			     u8 hfunc, struct mlx5e_rss_params_indir *indir)
15006e9f13aSMaxim Mikityanskiy {
15106e9f13aSMaxim Mikityanskiy 	u32 *rss_rqns;
15206e9f13aSMaxim Mikityanskiy 	int err;
15306e9f13aSMaxim Mikityanskiy 
15406e9f13aSMaxim Mikityanskiy 	if (WARN_ON(rqt->size != MLX5E_INDIR_RQT_SIZE))
15506e9f13aSMaxim Mikityanskiy 		return -EINVAL;
15606e9f13aSMaxim Mikityanskiy 
15706e9f13aSMaxim Mikityanskiy 	rss_rqns = kvmalloc_array(MLX5E_INDIR_RQT_SIZE, sizeof(*rss_rqns), GFP_KERNEL);
15806e9f13aSMaxim Mikityanskiy 	if (!rss_rqns)
15906e9f13aSMaxim Mikityanskiy 		return -ENOMEM;
16006e9f13aSMaxim Mikityanskiy 
16106e9f13aSMaxim Mikityanskiy 	err = mlx5e_calc_indir_rqns(rss_rqns, rqns, num_rqns, hfunc, indir);
16206e9f13aSMaxim Mikityanskiy 	if (err)
16306e9f13aSMaxim Mikityanskiy 		goto out;
16406e9f13aSMaxim Mikityanskiy 
16506e9f13aSMaxim Mikityanskiy 	err = mlx5e_rqt_redirect(rqt, rss_rqns, MLX5E_INDIR_RQT_SIZE);
16606e9f13aSMaxim Mikityanskiy 
16706e9f13aSMaxim Mikityanskiy out:
16806e9f13aSMaxim Mikityanskiy 	kvfree(rss_rqns);
16906e9f13aSMaxim Mikityanskiy 	return err;
17006e9f13aSMaxim Mikityanskiy }
171