1 // SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB 2 /* Copyright (c) 2021, Mellanox Technologies inc. All rights reserved. */ 3 4 #include "rqt.h" 5 #include <linux/mlx5/transobj.h> 6 7 void mlx5e_rss_params_indir_init_uniform(struct mlx5e_rss_params_indir *indir, 8 unsigned int num_channels) 9 { 10 unsigned int i; 11 12 for (i = 0; i < MLX5E_INDIR_RQT_SIZE; i++) 13 indir->table[i] = i % num_channels; 14 } 15 16 static int mlx5e_rqt_init(struct mlx5e_rqt *rqt, struct mlx5_core_dev *mdev, 17 u16 max_size, u32 *init_rqns, u16 init_size) 18 { 19 void *rqtc; 20 int inlen; 21 int err; 22 u32 *in; 23 int i; 24 25 rqt->mdev = mdev; 26 rqt->size = max_size; 27 28 inlen = MLX5_ST_SZ_BYTES(create_rqt_in) + sizeof(u32) * init_size; 29 in = kvzalloc(inlen, GFP_KERNEL); 30 if (!in) 31 return -ENOMEM; 32 33 rqtc = MLX5_ADDR_OF(create_rqt_in, in, rqt_context); 34 35 MLX5_SET(rqtc, rqtc, rqt_max_size, rqt->size); 36 37 MLX5_SET(rqtc, rqtc, rqt_actual_size, init_size); 38 for (i = 0; i < init_size; i++) 39 MLX5_SET(rqtc, rqtc, rq_num[i], init_rqns[i]); 40 41 err = mlx5_core_create_rqt(rqt->mdev, in, inlen, &rqt->rqtn); 42 43 kvfree(in); 44 return err; 45 } 46 47 int mlx5e_rqt_init_direct(struct mlx5e_rqt *rqt, struct mlx5_core_dev *mdev, 48 bool indir_enabled, u32 init_rqn) 49 { 50 u16 max_size = indir_enabled ? MLX5E_INDIR_RQT_SIZE : 1; 51 52 return mlx5e_rqt_init(rqt, mdev, max_size, &init_rqn, 1); 53 } 54 55 static int mlx5e_bits_invert(unsigned long a, int size) 56 { 57 int inv = 0; 58 int i; 59 60 for (i = 0; i < size; i++) 61 inv |= (test_bit(size - i - 1, &a) ? 1 : 0) << i; 62 63 return inv; 64 } 65 66 static int mlx5e_calc_indir_rqns(u32 *rss_rqns, u32 *rqns, unsigned int num_rqns, 67 u8 hfunc, struct mlx5e_rss_params_indir *indir) 68 { 69 unsigned int i; 70 71 for (i = 0; i < MLX5E_INDIR_RQT_SIZE; i++) { 72 unsigned int ix = i; 73 74 if (hfunc == ETH_RSS_HASH_XOR) 75 ix = mlx5e_bits_invert(ix, ilog2(MLX5E_INDIR_RQT_SIZE)); 76 77 ix = indir->table[ix]; 78 79 if (WARN_ON(ix >= num_rqns)) 80 /* Could be a bug in the driver or in the kernel part of 81 * ethtool: indir table refers to non-existent RQs. 82 */ 83 return -EINVAL; 84 rss_rqns[i] = rqns[ix]; 85 } 86 87 return 0; 88 } 89 90 int mlx5e_rqt_init_indir(struct mlx5e_rqt *rqt, struct mlx5_core_dev *mdev, 91 u32 *rqns, unsigned int num_rqns, 92 u8 hfunc, struct mlx5e_rss_params_indir *indir) 93 { 94 u32 *rss_rqns; 95 int err; 96 97 rss_rqns = kvmalloc_array(MLX5E_INDIR_RQT_SIZE, sizeof(*rss_rqns), GFP_KERNEL); 98 if (!rss_rqns) 99 return -ENOMEM; 100 101 err = mlx5e_calc_indir_rqns(rss_rqns, rqns, num_rqns, hfunc, indir); 102 if (err) 103 goto out; 104 105 err = mlx5e_rqt_init(rqt, mdev, MLX5E_INDIR_RQT_SIZE, rss_rqns, MLX5E_INDIR_RQT_SIZE); 106 107 out: 108 kvfree(rss_rqns); 109 return err; 110 } 111 112 void mlx5e_rqt_destroy(struct mlx5e_rqt *rqt) 113 { 114 mlx5_core_destroy_rqt(rqt->mdev, rqt->rqtn); 115 } 116 117 static int mlx5e_rqt_redirect(struct mlx5e_rqt *rqt, u32 *rqns, unsigned int size) 118 { 119 unsigned int i; 120 void *rqtc; 121 int inlen; 122 u32 *in; 123 int err; 124 125 inlen = MLX5_ST_SZ_BYTES(modify_rqt_in) + sizeof(u32) * size; 126 in = kvzalloc(inlen, GFP_KERNEL); 127 if (!in) 128 return -ENOMEM; 129 130 rqtc = MLX5_ADDR_OF(modify_rqt_in, in, ctx); 131 132 MLX5_SET(modify_rqt_in, in, bitmask.rqn_list, 1); 133 MLX5_SET(rqtc, rqtc, rqt_actual_size, size); 134 for (i = 0; i < size; i++) 135 MLX5_SET(rqtc, rqtc, rq_num[i], rqns[i]); 136 137 err = mlx5_core_modify_rqt(rqt->mdev, rqt->rqtn, in, inlen); 138 139 kvfree(in); 140 return err; 141 } 142 143 int mlx5e_rqt_redirect_direct(struct mlx5e_rqt *rqt, u32 rqn) 144 { 145 return mlx5e_rqt_redirect(rqt, &rqn, 1); 146 } 147 148 int mlx5e_rqt_redirect_indir(struct mlx5e_rqt *rqt, u32 *rqns, unsigned int num_rqns, 149 u8 hfunc, struct mlx5e_rss_params_indir *indir) 150 { 151 u32 *rss_rqns; 152 int err; 153 154 if (WARN_ON(rqt->size != MLX5E_INDIR_RQT_SIZE)) 155 return -EINVAL; 156 157 rss_rqns = kvmalloc_array(MLX5E_INDIR_RQT_SIZE, sizeof(*rss_rqns), GFP_KERNEL); 158 if (!rss_rqns) 159 return -ENOMEM; 160 161 err = mlx5e_calc_indir_rqns(rss_rqns, rqns, num_rqns, hfunc, indir); 162 if (err) 163 goto out; 164 165 err = mlx5e_rqt_redirect(rqt, rss_rqns, MLX5E_INDIR_RQT_SIZE); 166 167 out: 168 kvfree(rss_rqns); 169 return err; 170 } 171