xref: /dpdk/drivers/net/mlx5/mlx5_rss.c (revision b7091f1dcfbc62f358b4c1882d51c434471d51da)
1 /*-
2  *   BSD LICENSE
3  *
4  *   Copyright 2015 6WIND S.A.
5  *   Copyright 2015 Mellanox.
6  *
7  *   Redistribution and use in source and binary forms, with or without
8  *   modification, are permitted provided that the following conditions
9  *   are met:
10  *
11  *     * Redistributions of source code must retain the above copyright
12  *       notice, this list of conditions and the following disclaimer.
13  *     * Redistributions in binary form must reproduce the above copyright
14  *       notice, this list of conditions and the following disclaimer in
15  *       the documentation and/or other materials provided with the
16  *       distribution.
17  *     * Neither the name of 6WIND S.A. nor the names of its
18  *       contributors may be used to endorse or promote products derived
19  *       from this software without specific prior written permission.
20  *
21  *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22  *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23  *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
24  *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
25  *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26  *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
27  *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28  *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29  *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30  *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
31  *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32  */
33 
34 #include <stddef.h>
35 #include <stdint.h>
36 #include <errno.h>
37 #include <string.h>
38 #include <assert.h>
39 
40 /* Verbs header. */
41 /* ISO C doesn't support unnamed structs/unions, disabling -pedantic. */
42 #ifdef PEDANTIC
43 #pragma GCC diagnostic ignored "-Wpedantic"
44 #endif
45 #include <infiniband/verbs.h>
46 #ifdef PEDANTIC
47 #pragma GCC diagnostic error "-Wpedantic"
48 #endif
49 
50 #include <rte_malloc.h>
51 #include <rte_ethdev.h>
52 
53 #include "mlx5.h"
54 #include "mlx5_rxtx.h"
55 
56 /**
57  * Get a RSS configuration hash key.
58  *
59  * @param priv
60  *   Pointer to private structure.
61  * @param rss_hf
62  *   RSS hash functions configuration must be retrieved for.
63  *
64  * @return
65  *   Pointer to a RSS configuration structure or NULL if rss_hf cannot
66  *   be matched.
67  */
68 static struct rte_eth_rss_conf *
69 rss_hash_get(struct priv *priv, uint64_t rss_hf)
70 {
71 	unsigned int i;
72 
73 	for (i = 0; (i != hash_rxq_init_n); ++i) {
74 		uint64_t dpdk_rss_hf = hash_rxq_init[i].dpdk_rss_hf;
75 
76 		if (!(dpdk_rss_hf & rss_hf))
77 			continue;
78 		return (*priv->rss_conf)[i];
79 	}
80 	return NULL;
81 }
82 
83 /**
84  * Register a RSS key.
85  *
86  * @param priv
87  *   Pointer to private structure.
88  * @param key
89  *   Hash key to register.
90  * @param key_len
91  *   Hash key length in bytes.
92  * @param rss_hf
93  *   RSS hash functions the provided key applies to.
94  *
95  * @return
96  *   0 on success, errno value on failure.
97  */
98 int
99 rss_hash_rss_conf_new_key(struct priv *priv, const uint8_t *key,
100 			  unsigned int key_len, uint64_t rss_hf)
101 {
102 	unsigned int i;
103 
104 	for (i = 0; (i != hash_rxq_init_n); ++i) {
105 		struct rte_eth_rss_conf *rss_conf;
106 		uint64_t dpdk_rss_hf = hash_rxq_init[i].dpdk_rss_hf;
107 
108 		if (!(dpdk_rss_hf & rss_hf))
109 			continue;
110 		rss_conf = rte_realloc((*priv->rss_conf)[i],
111 				       (sizeof(*rss_conf) + key_len),
112 				       0);
113 		if (!rss_conf)
114 			return ENOMEM;
115 		rss_conf->rss_key = (void *)(rss_conf + 1);
116 		rss_conf->rss_key_len = key_len;
117 		rss_conf->rss_hf = dpdk_rss_hf;
118 		memcpy(rss_conf->rss_key, key, key_len);
119 		(*priv->rss_conf)[i] = rss_conf;
120 	}
121 	return 0;
122 }
123 
124 /**
125  * DPDK callback to update the RSS hash configuration.
126  *
127  * @param dev
128  *   Pointer to Ethernet device structure.
129  * @param[in] rss_conf
130  *   RSS configuration data.
131  *
132  * @return
133  *   0 on success, negative errno value on failure.
134  */
135 int
136 mlx5_rss_hash_update(struct rte_eth_dev *dev,
137 		     struct rte_eth_rss_conf *rss_conf)
138 {
139 	struct priv *priv = dev->data->dev_private;
140 	int err = 0;
141 
142 	priv_lock(priv);
143 
144 	assert(priv->rss_conf != NULL);
145 
146 	/* Apply configuration. */
147 	if (rss_conf->rss_key)
148 		err = rss_hash_rss_conf_new_key(priv,
149 						rss_conf->rss_key,
150 						rss_conf->rss_key_len,
151 						rss_conf->rss_hf);
152 	/* Store protocols for which RSS is enabled. */
153 	priv->rss_hf = rss_conf->rss_hf;
154 	priv_unlock(priv);
155 	assert(err >= 0);
156 	return -err;
157 }
158 
159 /**
160  * DPDK callback to get the RSS hash configuration.
161  *
162  * @param dev
163  *   Pointer to Ethernet device structure.
164  * @param[in, out] rss_conf
165  *   RSS configuration data.
166  *
167  * @return
168  *   0 on success, negative errno value on failure.
169  */
170 int
171 mlx5_rss_hash_conf_get(struct rte_eth_dev *dev,
172 		       struct rte_eth_rss_conf *rss_conf)
173 {
174 	struct priv *priv = dev->data->dev_private;
175 	struct rte_eth_rss_conf *priv_rss_conf;
176 
177 	priv_lock(priv);
178 
179 	assert(priv->rss_conf != NULL);
180 
181 	priv_rss_conf = rss_hash_get(priv, rss_conf->rss_hf);
182 	if (!priv_rss_conf) {
183 		rss_conf->rss_hf = 0;
184 		priv_unlock(priv);
185 		return -EINVAL;
186 	}
187 	if (rss_conf->rss_key &&
188 	    rss_conf->rss_key_len >= priv_rss_conf->rss_key_len)
189 		memcpy(rss_conf->rss_key,
190 		       priv_rss_conf->rss_key,
191 		       priv_rss_conf->rss_key_len);
192 	rss_conf->rss_key_len = priv_rss_conf->rss_key_len;
193 	rss_conf->rss_hf = priv_rss_conf->rss_hf;
194 
195 	priv_unlock(priv);
196 	return 0;
197 }
198 
199 /**
200  * Allocate/reallocate RETA index table.
201  *
202  * @param priv
203  *   Pointer to private structure.
204  * @praram reta_size
205  *   The size of the array to allocate.
206  *
207  * @return
208  *   0 on success, errno value on failure.
209  */
210 int
211 priv_rss_reta_index_resize(struct priv *priv, unsigned int reta_size)
212 {
213 	void *mem;
214 	unsigned int old_size = priv->reta_idx_n;
215 
216 	if (priv->reta_idx_n == reta_size)
217 		return 0;
218 
219 	mem = rte_realloc(priv->reta_idx,
220 			  reta_size * sizeof((*priv->reta_idx)[0]), 0);
221 	if (!mem)
222 		return ENOMEM;
223 	priv->reta_idx = mem;
224 	priv->reta_idx_n = reta_size;
225 
226 	if (old_size < reta_size)
227 		memset(&(*priv->reta_idx)[old_size], 0,
228 		       (reta_size - old_size) *
229 		       sizeof((*priv->reta_idx)[0]));
230 	return 0;
231 }
232 
233 /**
234  * Query RETA table.
235  *
236  * @param priv
237  *   Pointer to private structure.
238  * @param[in, out] reta_conf
239  *   Pointer to the first RETA configuration structure.
240  * @param reta_size
241  *   Number of entries.
242  *
243  * @return
244  *   0 on success, errno value on failure.
245  */
246 static int
247 priv_dev_rss_reta_query(struct priv *priv,
248 			struct rte_eth_rss_reta_entry64 *reta_conf,
249 			unsigned int reta_size)
250 {
251 	unsigned int idx;
252 	unsigned int i;
253 
254 	if (!reta_size || reta_size > priv->reta_idx_n)
255 		return EINVAL;
256 	/* Fill each entry of the table even if its bit is not set. */
257 	for (idx = 0, i = 0; (i != reta_size); ++i) {
258 		idx = i / RTE_RETA_GROUP_SIZE;
259 		reta_conf[idx].reta[i % RTE_RETA_GROUP_SIZE] =
260 			(*priv->reta_idx)[i];
261 	}
262 	return 0;
263 }
264 
265 /**
266  * Update RETA table.
267  *
268  * @param priv
269  *   Pointer to private structure.
270  * @param[in] reta_conf
271  *   Pointer to the first RETA configuration structure.
272  * @param reta_size
273  *   Number of entries.
274  *
275  * @return
276  *   0 on success, errno value on failure.
277  */
278 static int
279 priv_dev_rss_reta_update(struct priv *priv,
280 			 struct rte_eth_rss_reta_entry64 *reta_conf,
281 			 unsigned int reta_size)
282 {
283 	unsigned int idx;
284 	unsigned int i;
285 	unsigned int pos;
286 	int ret;
287 
288 	if (!reta_size)
289 		return EINVAL;
290 	ret = priv_rss_reta_index_resize(priv, reta_size);
291 	if (ret)
292 		return ret;
293 
294 	for (idx = 0, i = 0; (i != reta_size); ++i) {
295 		idx = i / RTE_RETA_GROUP_SIZE;
296 		pos = i % RTE_RETA_GROUP_SIZE;
297 		if (((reta_conf[idx].mask >> i) & 0x1) == 0)
298 			continue;
299 		assert(reta_conf[idx].reta[pos] < priv->rxqs_n);
300 		(*priv->reta_idx)[i] = reta_conf[idx].reta[pos];
301 	}
302 	return 0;
303 }
304 
305 /**
306  * DPDK callback to get the RETA indirection table.
307  *
308  * @param dev
309  *   Pointer to Ethernet device structure.
310  * @param reta_conf
311  *   Pointer to RETA configuration structure array.
312  * @param reta_size
313  *   Size of the RETA table.
314  *
315  * @return
316  *   0 on success, negative errno value on failure.
317  */
318 int
319 mlx5_dev_rss_reta_query(struct rte_eth_dev *dev,
320 			struct rte_eth_rss_reta_entry64 *reta_conf,
321 			uint16_t reta_size)
322 {
323 	int ret;
324 	struct priv *priv = dev->data->dev_private;
325 
326 	priv_lock(priv);
327 	ret = priv_dev_rss_reta_query(priv, reta_conf, reta_size);
328 	priv_unlock(priv);
329 	return -ret;
330 }
331 
332 /**
333  * DPDK callback to update the RETA indirection table.
334  *
335  * @param dev
336  *   Pointer to Ethernet device structure.
337  * @param reta_conf
338  *   Pointer to RETA configuration structure array.
339  * @param reta_size
340  *   Size of the RETA table.
341  *
342  * @return
343  *   0 on success, negative errno value on failure.
344  */
345 int
346 mlx5_dev_rss_reta_update(struct rte_eth_dev *dev,
347 			 struct rte_eth_rss_reta_entry64 *reta_conf,
348 			 uint16_t reta_size)
349 {
350 	int ret;
351 	struct priv *priv = dev->data->dev_private;
352 
353 	assert(!mlx5_is_secondary());
354 	mlx5_dev_stop(dev);
355 	priv_lock(priv);
356 	ret = priv_dev_rss_reta_update(priv, reta_conf, reta_size);
357 	priv_unlock(priv);
358 	if (ret)
359 		return -ret;
360 	return mlx5_dev_start(dev);
361 }
362