New upstream version 17.11.5
[deb_dpdk.git] / drivers / net / mlx5 / mlx5_mr.c
1 /*-
2  *   BSD LICENSE
3  *
4  *   Copyright 2016 6WIND S.A.
5  *   Copyright 2016 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 /* Verbs header. */
35 /* ISO C doesn't support unnamed structs/unions, disabling -pedantic. */
36 #ifdef PEDANTIC
37 #pragma GCC diagnostic ignored "-Wpedantic"
38 #endif
39 #include <infiniband/verbs.h>
40 #ifdef PEDANTIC
41 #pragma GCC diagnostic error "-Wpedantic"
42 #endif
43
44 #include <rte_mempool.h>
45 #include <rte_malloc.h>
46
47 #include "mlx5.h"
48 #include "mlx5_rxtx.h"
49
50 struct mr_update_mempool_data {
51         struct rte_eth_dev *dev;
52         struct mlx5_mr_cache *lkp_tbl;
53         uint16_t tbl_sz;
54 };
55
56 /**
57  * Look up LKEY from given lookup table by Binary Search, store the last index
58  * and return searched LKEY.
59  *
60  * @param lkp_tbl
61  *   Pointer to lookup table.
62  * @param n
63  *   Size of lookup table.
64  * @param[out] idx
65  *   Pointer to index. Even on searh failure, returns index where it stops
66  *   searching so that index can be used when inserting a new entry.
67  * @param addr
68  *   Search key.
69  *
70  * @return
71  *   Searched LKEY on success, UINT32_MAX on no match.
72  */
73 static uint32_t
74 mlx5_mr_lookup(struct mlx5_mr_cache *lkp_tbl, uint16_t n, uint16_t *idx,
75                uintptr_t addr)
76 {
77         uint16_t base = 0;
78
79         /* First entry must be NULL for comparison. */
80         assert(n == 0 || (lkp_tbl[0].start == 0 &&
81                           lkp_tbl[0].lkey == UINT32_MAX));
82         /* Binary search. */
83         do {
84                 register uint16_t delta = n >> 1;
85
86                 if (addr < lkp_tbl[base + delta].start) {
87                         n = delta;
88                 } else {
89                         base += delta;
90                         n -= delta;
91                 }
92         } while (n > 1);
93         assert(addr >= lkp_tbl[base].start);
94         *idx = base;
95         if (addr < lkp_tbl[base].end)
96                 return lkp_tbl[base].lkey;
97         /* Not found. */
98         return UINT32_MAX;
99 }
100
101 /**
102  * Insert an entry to LKEY lookup table.
103  *
104  * @param lkp_tbl
105  *   Pointer to lookup table. The size of array must be enough to add one more
106  *   entry.
107  * @param n
108  *   Size of lookup table.
109  * @param entry
110  *   Pointer to new entry to insert.
111  *
112  * @return
113  *   Size of returning lookup table.
114  */
115 static int
116 mlx5_mr_insert(struct mlx5_mr_cache *lkp_tbl, uint16_t n,
117                struct mlx5_mr_cache *entry)
118 {
119         uint16_t idx = 0;
120         size_t shift;
121
122         /* Check if entry exist. */
123         if (mlx5_mr_lookup(lkp_tbl, n, &idx, entry->start) != UINT32_MAX)
124                 return n;
125         /* Insert entry. */
126         ++idx;
127         shift = (n - idx) * sizeof(struct mlx5_mr_cache);
128         if (shift)
129                 memmove(&lkp_tbl[idx + 1], &lkp_tbl[idx], shift);
130         lkp_tbl[idx] = *entry;
131         DRV_LOG(DEBUG, "%p: inserted lkp_tbl[%u], start = 0x%lx, end = 0x%lx",
132                 (void *)lkp_tbl, idx, lkp_tbl[idx].start, lkp_tbl[idx].end);
133         return n + 1;
134 }
135
136 /**
137  * Incrementally update LKEY lookup table for a specific address from registered
138  * Memory Regions.
139  *
140  * @param dev
141  *   Pointer to Ethernet device structure.
142  * @param lkp_tbl
143  *   Pointer to lookup table to fill. The size of array must be at least
144  *   (priv->mr_n + 1).
145  * @param n
146  *   Size of lookup table.
147  * @param addr
148  *   Search key.
149  *
150  * @return
151  *   Size of returning lookup table.
152  */
153 static int
154 mlx5_mr_update_addr(struct rte_eth_dev *dev, struct mlx5_mr_cache *lkp_tbl,
155                     uint16_t n, uintptr_t addr)
156 {
157         struct priv *priv = dev->data->dev_private;
158         uint16_t idx;
159         uint32_t ret __rte_unused;
160
161         if (n == 0) {
162                 /* First entry must be NULL for comparison. */
163                 lkp_tbl[n++] = (struct mlx5_mr_cache) {
164                         .lkey = UINT32_MAX,
165                 };
166         }
167         ret = mlx5_mr_lookup(*priv->mr_cache, MR_TABLE_SZ(priv->mr_n),
168                              &idx, addr);
169         /* Lookup must succeed, the global cache is all-inclusive. */
170         assert(ret != UINT32_MAX);
171         DRV_LOG(DEBUG, "port %u adding LKEY (0x%x) for addr 0x%lx",
172                 dev->data->port_id, (*priv->mr_cache)[idx].lkey, addr);
173         return mlx5_mr_insert(lkp_tbl, n, &(*priv->mr_cache)[idx]);
174 }
175
176 /**
177  * Bottom-half of LKEY search on datapath. Firstly search in cache_bh[] and if
178  * misses, search in the global MR cache table and update the new entry to
179  * per-queue local caches.
180  *
181  * @param dev
182  *   Pointer to Ethernet device structure.
183  * @param mr_ctrl
184  *   Pointer to per-queue MR control structure.
185  * @param addr
186  *   Search key.
187  *
188  * @return
189  *   LKEY on success.
190  */
191 static inline uint32_t
192 mlx5_mr_mb2mr_bh(struct rte_eth_dev *dev, struct mlx5_mr_ctrl *mr_ctrl,
193                  uintptr_t addr)
194 {
195         uint32_t lkey;
196         uint16_t bh_idx = 0;
197         struct mlx5_mr_cache *mr_cache = &mr_ctrl->cache[mr_ctrl->head];
198
199         /* Binary-search MR translation table. */
200         lkey = mlx5_mr_lookup(*mr_ctrl->cache_bh, mr_ctrl->bh_n, &bh_idx, addr);
201         if (likely(lkey != UINT32_MAX)) {
202                 /* Update cache. */
203                 *mr_cache = (*mr_ctrl->cache_bh)[bh_idx];
204                 mr_ctrl->mru = mr_ctrl->head;
205                 /* Point to the next victim, the oldest. */
206                 mr_ctrl->head = (mr_ctrl->head + 1) % MLX5_MR_CACHE_N;
207                 return lkey;
208         }
209         /* Missed in the per-queue lookup table. Search in the global cache. */
210         mr_ctrl->bh_n = mlx5_mr_update_addr(dev, *mr_ctrl->cache_bh,
211                                             mr_ctrl->bh_n, addr);
212         /* Search again with updated entries. */
213         lkey = mlx5_mr_lookup(*mr_ctrl->cache_bh, mr_ctrl->bh_n, &bh_idx, addr);
214         /* Must always succeed. */
215         assert(lkey != UINT32_MAX);
216         /* Update cache. */
217         *mr_cache = (*mr_ctrl->cache_bh)[bh_idx];
218         mr_ctrl->mru = mr_ctrl->head;
219         /* Point to the next victim, the oldest. */
220         mr_ctrl->head = (mr_ctrl->head + 1) % MLX5_MR_CACHE_N;
221         return lkey;
222 }
223
224 /**
225  * Bottom-half of mlx5_rx_mb2mr() if search on mr_cache_bh[] fails.
226  *
227  * @param rxq
228  *   Pointer to Rx queue structure.
229  * @param addr
230  *   Search key.
231  *
232  * @return
233  *   LKEY on success.
234  */
235 uint32_t
236 mlx5_rx_mb2mr_bh(struct mlx5_rxq_data *rxq, uintptr_t addr)
237 {
238         struct mlx5_rxq_ctrl *rxq_ctrl =
239                 container_of(rxq, struct mlx5_rxq_ctrl, rxq);
240
241         DRV_LOG(DEBUG,
242                 "port %u not found in rxq->mr_cache[], last-hit=%u, head=%u",
243                 PORT_ID(rxq_ctrl->priv), rxq->mr_ctrl.mru, rxq->mr_ctrl.head);
244         return mlx5_mr_mb2mr_bh(ETH_DEV(rxq_ctrl->priv), &rxq->mr_ctrl, addr);
245 }
246
247 /**
248  * Bottom-half of mlx5_tx_mb2mr() if search on cache_bh[] fails.
249  *
250  * @param txq
251  *   Pointer to Tx queue structure.
252  * @param addr
253  *   Search key.
254  *
255  * @return
256  *   LKEY on success.
257  */
258 uint32_t
259 mlx5_tx_mb2mr_bh(struct mlx5_txq_data *txq, uintptr_t addr)
260 {
261         struct mlx5_txq_ctrl *txq_ctrl =
262                 container_of(txq, struct mlx5_txq_ctrl, txq);
263
264         DRV_LOG(DEBUG,
265                 "port %u not found in txq->mr_cache[], last-hit=%u, head=%u",
266                 PORT_ID(txq_ctrl->priv), txq->mr_ctrl.mru, txq->mr_ctrl.head);
267         return mlx5_mr_mb2mr_bh(ETH_DEV(txq_ctrl->priv), &txq->mr_ctrl, addr);
268 }
269
270 /* Called by mr_update_mempool() when iterating the memory chunks. */
271 static void
272 mr_update_mempool_cb(struct rte_mempool *mp __rte_unused,
273                     void *opaque, struct rte_mempool_memhdr *memhdr,
274                     unsigned int mem_idx __rte_unused)
275 {
276         struct mr_update_mempool_data *data = opaque;
277
278         DRV_LOG(DEBUG, "port %u adding chunk[%u] of %s",
279                 data->dev->data->port_id, mem_idx, mp->name);
280         data->tbl_sz =
281                 mlx5_mr_update_addr(data->dev, data->lkp_tbl, data->tbl_sz,
282                                     (uintptr_t)memhdr->addr);
283 }
284
285 /**
286  * Incrementally update LKEY lookup table for a specific Memory Pool from
287  * registered Memory Regions.
288  *
289  * @param dev
290  *   Pointer to Ethernet device.
291  * @param[out] lkp_tbl
292  *   Pointer to lookup table to fill. The size of array must be at least
293  *   (priv->static_mr_n + 1).
294  * @param n
295  *   Size of lookup table.
296  * @param[in] mp
297  *   Pointer to Memory Pool.
298  *
299  * @return
300  *   Size of returning lookup table.
301  */
302 int
303 mlx5_mr_update_mp(struct rte_eth_dev *dev, struct mlx5_mr_cache *lkp_tbl,
304                   uint16_t n, struct rte_mempool *mp)
305 {
306         struct mr_update_mempool_data data = {
307                 .dev = dev,
308                 .lkp_tbl = lkp_tbl,
309                 .tbl_sz = n
310         };
311
312         rte_mempool_mem_iter(mp, mr_update_mempool_cb, &data);
313         return data.tbl_sz;
314 }
315
316 /* Called by qsort() to compare MR entries. */
317 static int
318 mr_comp_addr(const void *m1, const void *m2)
319 {
320         const struct mlx5_mr *mi1 = m1;
321         const struct mlx5_mr *mi2 = m2;
322
323         if (mi1->memseg->addr < mi2->memseg->addr)
324                 return -1;
325         else if (mi1->memseg->addr > mi2->memseg->addr)
326                 return 1;
327         else
328                 return 0;
329 }
330
331 /**
332  * Register entire physical memory to Verbs.
333  *
334  * @param dev
335  *   Pointer to Ethernet device.
336  *
337  * @return
338  *   0 on success, a negative errno value otherwise and rte_errno is set.
339  */
340 int
341 mlx5_mr_register_memseg(struct rte_eth_dev *dev)
342 {
343         struct priv *priv = dev->data->dev_private;
344         const struct rte_memseg *ms = rte_eal_get_physmem_layout();
345         struct mlx5_mr *mr;
346         struct mlx5_mr_cache *mr_cache;
347         unsigned int i;
348
349         if (priv->mr_n != 0)
350                 return 0;
351         /* Count the existing memsegs in the system. */
352         for (i = 0; (i < RTE_MAX_MEMSEG) && (ms[i].addr != NULL); ++i)
353                 ++priv->mr_n;
354         priv->mr = rte_calloc(__func__, priv->mr_n, sizeof(*mr), 0);
355         if (priv->mr == NULL) {
356                 DRV_LOG(ERR,
357                         "port %u cannot allocate memory for array of static MR",
358                         dev->data->port_id);
359                 rte_errno = ENOMEM;
360                 return -rte_errno;
361         }
362         priv->mr_cache = rte_calloc(__func__, MR_TABLE_SZ(priv->mr_n),
363                                     sizeof(*mr_cache), 0);
364         if (priv->mr_cache == NULL) {
365                 DRV_LOG(ERR,
366                         "port %u cannot allocate memory for array of MR cache",
367                         dev->data->port_id);
368                 rte_free(priv->mr);
369                 rte_errno = ENOMEM;
370                 return -rte_errno;
371         }
372         for (i = 0; i < priv->mr_n; ++i) {
373                 mr = &(*priv->mr)[i];
374                 mr->memseg = &ms[i];
375                 mr->ibv_mr = ibv_reg_mr(priv->pd,
376                                         mr->memseg->addr, mr->memseg->len,
377                                         IBV_ACCESS_LOCAL_WRITE);
378                 if (mr->ibv_mr == NULL) {
379                         rte_dump_physmem_layout(stderr);
380                         DRV_LOG(ERR, "port %u cannot register memseg[%u]",
381                                 dev->data->port_id, i);
382                         goto error;
383                 }
384         }
385         /* Sort by virtual address. */
386         qsort(*priv->mr, priv->mr_n, sizeof(struct mlx5_mr), mr_comp_addr);
387         /* First entry must be NULL for comparison. */
388         (*priv->mr_cache)[0] = (struct mlx5_mr_cache) {
389                 .lkey = UINT32_MAX,
390         };
391         /* Compile global all-inclusive MR cache table. */
392         for (i = 0; i < priv->mr_n; ++i) {
393                 mr = &(*priv->mr)[i];
394                 mr_cache = &(*priv->mr_cache)[i + 1];
395                 /* Paranoid, mr[] must be sorted. */
396                 assert(i == 0 || mr->memseg->addr > (mr - 1)->memseg->addr);
397                 *mr_cache = (struct mlx5_mr_cache) {
398                         .start = (uintptr_t)mr->memseg->addr,
399                         .end = (uintptr_t)mr->memseg->addr + mr->memseg->len,
400                         .lkey = rte_cpu_to_be_32(mr->ibv_mr->lkey)
401                 };
402         }
403         return 0;
404 error:
405         for (i = 0; i < priv->mr_n; ++i) {
406                 mr = &(*priv->mr)[i];
407                 if (mr->ibv_mr != NULL)
408                         ibv_dereg_mr(mr->ibv_mr);
409         }
410         rte_free(priv->mr);
411         rte_free(priv->mr_cache);
412         rte_errno = ENOMEM;
413         return -rte_errno;
414 }
415
416 /**
417  * Deregister all Memory Regions.
418  *
419  * @param dev
420  *   Pointer to Ethernet device.
421  */
422 void
423 mlx5_mr_deregister_memseg(struct rte_eth_dev *dev)
424 {
425         struct priv *priv = dev->data->dev_private;
426         unsigned int i;
427
428         if (priv->mr_n == 0)
429                 return;
430         for (i = 0; i < priv->mr_n; ++i) {
431                 struct mlx5_mr *mr;
432
433                 mr = &(*priv->mr)[i];
434                 /* Physical memory can't be changed dynamically. */
435                 assert(mr->memseg != NULL);
436                 assert(mr->ibv_mr != NULL);
437                 ibv_dereg_mr(mr->ibv_mr);
438         }
439         rte_free(priv->mr);
440         rte_free(priv->mr_cache);
441         priv->mr = NULL;
442         priv->mr_cache = NULL;
443         priv->mr_n = 0;
444 }