net/qede/base: support doorbell overflow recovery
[dpdk.git] / drivers / net / mlx5 / mlx5_rss.c
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         mlx5_dev_stop(dev);
354         priv_lock(priv);
355         ret = priv_dev_rss_reta_update(priv, reta_conf, reta_size);
356         priv_unlock(priv);
357         if (ret)
358                 return -ret;
359         return mlx5_dev_start(dev);
360 }