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