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/* DPDK headers don't like -pedantic. */
51#ifdef PEDANTIC
52#pragma GCC diagnostic ignored "-Wpedantic"
53#endif
54#include <rte_malloc.h>
55#include <rte_ethdev.h>
56#ifdef PEDANTIC
57#pragma GCC diagnostic error "-Wpedantic"
58#endif
59
60#include "mlx5.h"
61#include "mlx5_rxtx.h"
62
63/**
64 * Get a RSS configuration hash key.
65 *
66 * @param priv
67 *   Pointer to private structure.
68 * @param rss_hf
69 *   RSS hash functions configuration must be retrieved for.
70 *
71 * @return
72 *   Pointer to a RSS configuration structure or NULL if rss_hf cannot
73 *   be matched.
74 */
75static struct rte_eth_rss_conf *
76rss_hash_get(struct priv *priv, uint64_t rss_hf)
77{
78	unsigned int i;
79
80	for (i = 0; (i != hash_rxq_init_n); ++i) {
81		uint64_t dpdk_rss_hf = hash_rxq_init[i].dpdk_rss_hf;
82
83		if (!(dpdk_rss_hf & rss_hf))
84			continue;
85		return (*priv->rss_conf)[i];
86	}
87	return NULL;
88}
89
90/**
91 * Register a RSS key.
92 *
93 * @param priv
94 *   Pointer to private structure.
95 * @param key
96 *   Hash key to register.
97 * @param key_len
98 *   Hash key length in bytes.
99 * @param rss_hf
100 *   RSS hash functions the provided key applies to.
101 *
102 * @return
103 *   0 on success, errno value on failure.
104 */
105int
106rss_hash_rss_conf_new_key(struct priv *priv, const uint8_t *key,
107			  unsigned int key_len, uint64_t rss_hf)
108{
109	unsigned int i;
110
111	for (i = 0; (i != hash_rxq_init_n); ++i) {
112		struct rte_eth_rss_conf *rss_conf;
113		uint64_t dpdk_rss_hf = hash_rxq_init[i].dpdk_rss_hf;
114
115		if (!(dpdk_rss_hf & rss_hf))
116			continue;
117		rss_conf = rte_realloc((*priv->rss_conf)[i],
118				       (sizeof(*rss_conf) + key_len),
119				       0);
120		if (!rss_conf)
121			return ENOMEM;
122		rss_conf->rss_key = (void *)(rss_conf + 1);
123		rss_conf->rss_key_len = key_len;
124		rss_conf->rss_hf = dpdk_rss_hf;
125		memcpy(rss_conf->rss_key, key, key_len);
126		(*priv->rss_conf)[i] = rss_conf;
127	}
128	return 0;
129}
130
131/**
132 * DPDK callback to update the RSS hash configuration.
133 *
134 * @param dev
135 *   Pointer to Ethernet device structure.
136 * @param[in] rss_conf
137 *   RSS configuration data.
138 *
139 * @return
140 *   0 on success, negative errno value on failure.
141 */
142int
143mlx5_rss_hash_update(struct rte_eth_dev *dev,
144		     struct rte_eth_rss_conf *rss_conf)
145{
146	struct priv *priv = dev->data->dev_private;
147	int err = 0;
148
149	priv_lock(priv);
150
151	assert(priv->rss_conf != NULL);
152
153	/* Apply configuration. */
154	if (rss_conf->rss_key)
155		err = rss_hash_rss_conf_new_key(priv,
156						rss_conf->rss_key,
157						rss_conf->rss_key_len,
158						rss_conf->rss_hf);
159	/* Store protocols for which RSS is enabled. */
160	priv->rss_hf = rss_conf->rss_hf;
161	priv_unlock(priv);
162	assert(err >= 0);
163	return -err;
164}
165
166/**
167 * DPDK callback to get the RSS hash configuration.
168 *
169 * @param dev
170 *   Pointer to Ethernet device structure.
171 * @param[in, out] rss_conf
172 *   RSS configuration data.
173 *
174 * @return
175 *   0 on success, negative errno value on failure.
176 */
177int
178mlx5_rss_hash_conf_get(struct rte_eth_dev *dev,
179		       struct rte_eth_rss_conf *rss_conf)
180{
181	struct priv *priv = dev->data->dev_private;
182	struct rte_eth_rss_conf *priv_rss_conf;
183
184	priv_lock(priv);
185
186	assert(priv->rss_conf != NULL);
187
188	priv_rss_conf = rss_hash_get(priv, rss_conf->rss_hf);
189	if (!priv_rss_conf) {
190		rss_conf->rss_hf = 0;
191		priv_unlock(priv);
192		return -EINVAL;
193	}
194	if (rss_conf->rss_key &&
195	    rss_conf->rss_key_len >= priv_rss_conf->rss_key_len)
196		memcpy(rss_conf->rss_key,
197		       priv_rss_conf->rss_key,
198		       priv_rss_conf->rss_key_len);
199	rss_conf->rss_key_len = priv_rss_conf->rss_key_len;
200	rss_conf->rss_hf = priv_rss_conf->rss_hf;
201
202	priv_unlock(priv);
203	return 0;
204}
205
206/**
207 * Allocate/reallocate RETA index table.
208 *
209 * @param priv
210 *   Pointer to private structure.
211 * @praram reta_size
212 *   The size of the array to allocate.
213 *
214 * @return
215 *   0 on success, errno value on failure.
216 */
217int
218priv_rss_reta_index_resize(struct priv *priv, unsigned int reta_size)
219{
220	void *mem;
221	unsigned int old_size = priv->reta_idx_n;
222
223	if (priv->reta_idx_n == reta_size)
224		return 0;
225
226	mem = rte_realloc(priv->reta_idx,
227			  reta_size * sizeof((*priv->reta_idx)[0]), 0);
228	if (!mem)
229		return ENOMEM;
230	priv->reta_idx = mem;
231	priv->reta_idx_n = reta_size;
232
233	if (old_size < reta_size)
234		memset(&(*priv->reta_idx)[old_size], 0,
235		       (reta_size - old_size) *
236		       sizeof((*priv->reta_idx)[0]));
237	return 0;
238}
239
240/**
241 * Query RETA table.
242 *
243 * @param priv
244 *   Pointer to private structure.
245 * @param[in, out] reta_conf
246 *   Pointer to the first RETA configuration structure.
247 * @param reta_size
248 *   Number of entries.
249 *
250 * @return
251 *   0 on success, errno value on failure.
252 */
253static int
254priv_dev_rss_reta_query(struct priv *priv,
255			struct rte_eth_rss_reta_entry64 *reta_conf,
256			unsigned int reta_size)
257{
258	unsigned int idx;
259	unsigned int i;
260	int ret;
261
262	/* See RETA comment in mlx5_dev_infos_get(). */
263	ret = priv_rss_reta_index_resize(priv, priv->ind_table_max_size);
264	if (ret)
265		return ret;
266
267	/* Fill each entry of the table even if its bit is not set. */
268	for (idx = 0, i = 0; (i != reta_size); ++i) {
269		idx = i / RTE_RETA_GROUP_SIZE;
270		reta_conf[idx].reta[i % RTE_RETA_GROUP_SIZE] =
271			(*priv->reta_idx)[i];
272	}
273	return 0;
274}
275
276/**
277 * Update RETA table.
278 *
279 * @param priv
280 *   Pointer to private structure.
281 * @param[in] reta_conf
282 *   Pointer to the first RETA configuration structure.
283 * @param reta_size
284 *   Number of entries.
285 *
286 * @return
287 *   0 on success, errno value on failure.
288 */
289static int
290priv_dev_rss_reta_update(struct priv *priv,
291			 struct rte_eth_rss_reta_entry64 *reta_conf,
292			 unsigned int reta_size)
293{
294	unsigned int idx;
295	unsigned int i;
296	unsigned int pos;
297	int ret;
298
299	/* See RETA comment in mlx5_dev_infos_get(). */
300	ret = priv_rss_reta_index_resize(priv, priv->ind_table_max_size);
301	if (ret)
302		return ret;
303
304	for (idx = 0, i = 0; (i != reta_size); ++i) {
305		idx = i / RTE_RETA_GROUP_SIZE;
306		pos = i % RTE_RETA_GROUP_SIZE;
307		if (((reta_conf[idx].mask >> i) & 0x1) == 0)
308			continue;
309		assert(reta_conf[idx].reta[pos] < priv->rxqs_n);
310		(*priv->reta_idx)[i] = reta_conf[idx].reta[pos];
311	}
312	return 0;
313}
314
315/**
316 * DPDK callback to get the RETA indirection table.
317 *
318 * @param dev
319 *   Pointer to Ethernet device structure.
320 * @param reta_conf
321 *   Pointer to RETA configuration structure array.
322 * @param reta_size
323 *   Size of the RETA table.
324 *
325 * @return
326 *   0 on success, negative errno value on failure.
327 */
328int
329mlx5_dev_rss_reta_query(struct rte_eth_dev *dev,
330			struct rte_eth_rss_reta_entry64 *reta_conf,
331			uint16_t reta_size)
332{
333	int ret;
334	struct priv *priv = dev->data->dev_private;
335
336	priv_lock(priv);
337	ret = priv_dev_rss_reta_query(priv, reta_conf, reta_size);
338	priv_unlock(priv);
339	return -ret;
340}
341
342/**
343 * DPDK callback to update the RETA indirection table.
344 *
345 * @param dev
346 *   Pointer to Ethernet device structure.
347 * @param reta_conf
348 *   Pointer to RETA configuration structure array.
349 * @param reta_size
350 *   Size of the RETA table.
351 *
352 * @return
353 *   0 on success, negative errno value on failure.
354 */
355int
356mlx5_dev_rss_reta_update(struct rte_eth_dev *dev,
357			 struct rte_eth_rss_reta_entry64 *reta_conf,
358			 uint16_t reta_size)
359{
360	int ret;
361	struct priv *priv = dev->data->dev_private;
362
363	priv_lock(priv);
364	ret = priv_dev_rss_reta_update(priv, reta_conf, reta_size);
365	priv_unlock(priv);
366	return -ret;
367}
368