net/softnic: fix memory leak as profile is freed
[dpdk.git] / drivers / net / mlx5 / mlx5_mr.c
1 /* SPDX-License-Identifier: BSD-3-Clause
2  * Copyright 2016 6WIND S.A.
3  * Copyright 2016 Mellanox Technologies, Ltd
4  */
5
6 #include <rte_eal_memconfig.h>
7 #include <rte_mempool.h>
8 #include <rte_malloc.h>
9 #include <rte_rwlock.h>
10
11 #include <mlx5_common_mp.h>
12 #include <mlx5_common_mr.h>
13
14 #include "mlx5.h"
15 #include "mlx5_mr.h"
16 #include "mlx5_rxtx.h"
17 #include "mlx5_rx.h"
18 #include "mlx5_tx.h"
19
20 struct mr_find_contig_memsegs_data {
21         uintptr_t addr;
22         uintptr_t start;
23         uintptr_t end;
24         const struct rte_memseg_list *msl;
25 };
26
27 struct mr_update_mp_data {
28         struct rte_eth_dev *dev;
29         struct mlx5_mr_ctrl *mr_ctrl;
30         int ret;
31 };
32
33 /**
34  * Callback for memory event. This can be called from both primary and secondary
35  * process.
36  *
37  * @param event_type
38  *   Memory event type.
39  * @param addr
40  *   Address of memory.
41  * @param len
42  *   Size of memory.
43  */
44 void
45 mlx5_mr_mem_event_cb(enum rte_mem_event event_type, const void *addr,
46                      size_t len, void *arg __rte_unused)
47 {
48         struct mlx5_dev_ctx_shared *sh;
49         struct mlx5_dev_list *dev_list = &mlx5_shared_data->mem_event_cb_list;
50
51         /* Must be called from the primary process. */
52         MLX5_ASSERT(rte_eal_process_type() == RTE_PROC_PRIMARY);
53         switch (event_type) {
54         case RTE_MEM_EVENT_FREE:
55                 rte_rwlock_write_lock(&mlx5_shared_data->mem_event_rwlock);
56                 /* Iterate all the existing mlx5 devices. */
57                 LIST_FOREACH(sh, dev_list, mem_event_cb)
58                         mlx5_free_mr_by_addr(&sh->share_cache,
59                                              sh->ibdev_name, addr, len);
60                 rte_rwlock_write_unlock(&mlx5_shared_data->mem_event_rwlock);
61                 break;
62         case RTE_MEM_EVENT_ALLOC:
63         default:
64                 break;
65         }
66 }
67
68 /**
69  * Bottom-half of LKey search on Rx.
70  *
71  * @param rxq
72  *   Pointer to Rx queue structure.
73  * @param addr
74  *   Search key.
75  *
76  * @return
77  *   Searched LKey on success, UINT32_MAX on no match.
78  */
79 uint32_t
80 mlx5_rx_addr2mr_bh(struct mlx5_rxq_data *rxq, uintptr_t addr)
81 {
82         struct mlx5_rxq_ctrl *rxq_ctrl =
83                 container_of(rxq, struct mlx5_rxq_ctrl, rxq);
84         struct mlx5_mr_ctrl *mr_ctrl = &rxq->mr_ctrl;
85         struct mlx5_priv *priv = rxq_ctrl->priv;
86
87         return mlx5_mr_addr2mr_bh(priv->sh->pd, &priv->mp_id,
88                                   &priv->sh->share_cache, mr_ctrl, addr,
89                                   priv->config.mr_ext_memseg_en);
90 }
91
92 /**
93  * Bottom-half of LKey search on Tx.
94  *
95  * @param txq
96  *   Pointer to Tx queue structure.
97  * @param addr
98  *   Search key.
99  *
100  * @return
101  *   Searched LKey on success, UINT32_MAX on no match.
102  */
103 static uint32_t
104 mlx5_tx_addr2mr_bh(struct mlx5_txq_data *txq, uintptr_t addr)
105 {
106         struct mlx5_txq_ctrl *txq_ctrl =
107                 container_of(txq, struct mlx5_txq_ctrl, txq);
108         struct mlx5_mr_ctrl *mr_ctrl = &txq->mr_ctrl;
109         struct mlx5_priv *priv = txq_ctrl->priv;
110
111         return mlx5_mr_addr2mr_bh(priv->sh->pd, &priv->mp_id,
112                                   &priv->sh->share_cache, mr_ctrl, addr,
113                                   priv->config.mr_ext_memseg_en);
114 }
115
116 /**
117  * Bottom-half of LKey search on Tx. If it can't be searched in the memseg
118  * list, register the mempool of the mbuf as externally allocated memory.
119  *
120  * @param txq
121  *   Pointer to Tx queue structure.
122  * @param mb
123  *   Pointer to mbuf.
124  *
125  * @return
126  *   Searched LKey on success, UINT32_MAX on no match.
127  */
128 uint32_t
129 mlx5_tx_mb2mr_bh(struct mlx5_txq_data *txq, struct rte_mbuf *mb)
130 {
131         uintptr_t addr = (uintptr_t)mb->buf_addr;
132         uint32_t lkey;
133
134         lkey = mlx5_tx_addr2mr_bh(txq, addr);
135         if (lkey == UINT32_MAX && rte_errno == ENXIO) {
136                 /* Mempool may have externally allocated memory. */
137                 return mlx5_tx_update_ext_mp(txq, addr, mlx5_mb2mp(mb));
138         }
139         return lkey;
140 }
141
142 /**
143  * Called during rte_mempool_mem_iter() by mlx5_mr_update_ext_mp().
144  *
145  * Externally allocated chunk is registered and a MR is created for the chunk.
146  * The MR object is added to the global list. If memseg list of a MR object
147  * (mr->msl) is null, the MR object can be regarded as externally allocated
148  * memory.
149  *
150  * Once external memory is registered, it should be static. If the memory is
151  * freed and the virtual address range has different physical memory mapped
152  * again, it may cause crash on device due to the wrong translation entry. PMD
153  * can't track the free event of the external memory for now.
154  */
155 static void
156 mlx5_mr_update_ext_mp_cb(struct rte_mempool *mp, void *opaque,
157                          struct rte_mempool_memhdr *memhdr,
158                          unsigned mem_idx __rte_unused)
159 {
160         struct mr_update_mp_data *data = opaque;
161         struct rte_eth_dev *dev = data->dev;
162         struct mlx5_priv *priv = dev->data->dev_private;
163         struct mlx5_dev_ctx_shared *sh = priv->sh;
164         struct mlx5_mr_ctrl *mr_ctrl = data->mr_ctrl;
165         struct mlx5_mr *mr = NULL;
166         uintptr_t addr = (uintptr_t)memhdr->addr;
167         size_t len = memhdr->len;
168         struct mr_cache_entry entry;
169         uint32_t lkey;
170
171         MLX5_ASSERT(rte_eal_process_type() == RTE_PROC_PRIMARY);
172         /* If already registered, it should return. */
173         rte_rwlock_read_lock(&sh->share_cache.rwlock);
174         lkey = mlx5_mr_lookup_cache(&sh->share_cache, &entry, addr);
175         rte_rwlock_read_unlock(&sh->share_cache.rwlock);
176         if (lkey != UINT32_MAX)
177                 return;
178         DRV_LOG(DEBUG, "port %u register MR for chunk #%d of mempool (%s)",
179                 dev->data->port_id, mem_idx, mp->name);
180         mr = mlx5_create_mr_ext(sh->pd, addr, len, mp->socket_id,
181                                 sh->share_cache.reg_mr_cb);
182         if (!mr) {
183                 DRV_LOG(WARNING,
184                         "port %u unable to allocate a new MR of"
185                         " mempool (%s).",
186                         dev->data->port_id, mp->name);
187                 data->ret = -1;
188                 return;
189         }
190         rte_rwlock_write_lock(&sh->share_cache.rwlock);
191         LIST_INSERT_HEAD(&sh->share_cache.mr_list, mr, mr);
192         /* Insert to the global cache table. */
193         mlx5_mr_insert_cache(&sh->share_cache, mr);
194         rte_rwlock_write_unlock(&sh->share_cache.rwlock);
195         /* Insert to the local cache table */
196         mlx5_mr_addr2mr_bh(sh->pd, &priv->mp_id, &sh->share_cache,
197                            mr_ctrl, addr, priv->config.mr_ext_memseg_en);
198 }
199
200 /**
201  * Finds the first ethdev that match the device.
202  * The existence of multiple ethdev per pci device is only with representors.
203  * On such case, it is enough to get only one of the ports as they all share
204  * the same ibv context.
205  *
206  * @param dev
207  *   Pointer to the device.
208  *
209  * @return
210  *   Pointer to the ethdev if found, NULL otherwise.
211  */
212 static struct rte_eth_dev *
213 dev_to_eth_dev(struct rte_device *dev)
214 {
215         uint16_t port_id;
216
217         port_id = rte_eth_find_next_of(0, dev);
218         if (port_id == RTE_MAX_ETHPORTS)
219                 return NULL;
220         return &rte_eth_devices[port_id];
221 }
222
223 /**
224  * Callback to DMA map external memory to a device.
225  *
226  * @param rte_dev
227  *   Pointer to the generic device.
228  * @param addr
229  *   Starting virtual address of memory to be mapped.
230  * @param iova
231  *   Starting IOVA address of memory to be mapped.
232  * @param len
233  *   Length of memory segment being mapped.
234  *
235  * @return
236  *   0 on success, negative value on error.
237  */
238 int
239 mlx5_net_dma_map(struct rte_device *rte_dev, void *addr,
240                  uint64_t iova __rte_unused, size_t len)
241 {
242         struct rte_eth_dev *dev;
243         struct mlx5_mr *mr;
244         struct mlx5_priv *priv;
245         struct mlx5_dev_ctx_shared *sh;
246
247         dev = dev_to_eth_dev(rte_dev);
248         if (!dev) {
249                 DRV_LOG(WARNING, "unable to find matching ethdev "
250                                  "to device %s", rte_dev->name);
251                 rte_errno = ENODEV;
252                 return -1;
253         }
254         priv = dev->data->dev_private;
255         sh = priv->sh;
256         mr = mlx5_create_mr_ext(sh->pd, (uintptr_t)addr, len, SOCKET_ID_ANY,
257                                 sh->share_cache.reg_mr_cb);
258         if (!mr) {
259                 DRV_LOG(WARNING,
260                         "port %u unable to dma map", dev->data->port_id);
261                 rte_errno = EINVAL;
262                 return -1;
263         }
264         rte_rwlock_write_lock(&sh->share_cache.rwlock);
265         LIST_INSERT_HEAD(&sh->share_cache.mr_list, mr, mr);
266         /* Insert to the global cache table. */
267         mlx5_mr_insert_cache(&sh->share_cache, mr);
268         rte_rwlock_write_unlock(&sh->share_cache.rwlock);
269         return 0;
270 }
271
272 /**
273  * Callback to DMA unmap external memory to a device.
274  *
275  * @param rte_dev
276  *   Pointer to the generic device.
277  * @param addr
278  *   Starting virtual address of memory to be unmapped.
279  * @param iova
280  *   Starting IOVA address of memory to be unmapped.
281  * @param len
282  *   Length of memory segment being unmapped.
283  *
284  * @return
285  *   0 on success, negative value on error.
286  */
287 int
288 mlx5_net_dma_unmap(struct rte_device *rte_dev, void *addr,
289                    uint64_t iova __rte_unused, size_t len __rte_unused)
290 {
291         struct rte_eth_dev *dev;
292         struct mlx5_priv *priv;
293         struct mlx5_dev_ctx_shared *sh;
294         struct mlx5_mr *mr;
295         struct mr_cache_entry entry;
296
297         dev = dev_to_eth_dev(rte_dev);
298         if (!dev) {
299                 DRV_LOG(WARNING, "unable to find matching ethdev to device %s",
300                         rte_dev->name);
301                 rte_errno = ENODEV;
302                 return -1;
303         }
304         priv = dev->data->dev_private;
305         sh = priv->sh;
306         rte_rwlock_write_lock(&sh->share_cache.rwlock);
307         mr = mlx5_mr_lookup_list(&sh->share_cache, &entry, (uintptr_t)addr);
308         if (!mr) {
309                 rte_rwlock_write_unlock(&sh->share_cache.rwlock);
310                 DRV_LOG(WARNING, "address 0x%" PRIxPTR " wasn't registered to device %s",
311                         (uintptr_t)addr, rte_dev->name);
312                 rte_errno = EINVAL;
313                 return -1;
314         }
315         LIST_REMOVE(mr, mr);
316         DRV_LOG(DEBUG, "port %u remove MR(%p) from list", dev->data->port_id,
317               (void *)mr);
318         mlx5_mr_free(mr, sh->share_cache.dereg_mr_cb);
319         mlx5_mr_rebuild_cache(&sh->share_cache);
320         /*
321          * No explicit wmb is needed after updating dev_gen due to
322          * store-release ordering in unlock that provides the
323          * implicit barrier at the software visible level.
324          */
325         ++sh->share_cache.dev_gen;
326         DRV_LOG(DEBUG, "broadcasting local cache flush, gen=%d",
327               sh->share_cache.dev_gen);
328         rte_rwlock_write_unlock(&sh->share_cache.rwlock);
329         return 0;
330 }
331
332 /**
333  * Register MR for entire memory chunks in a Mempool having externally allocated
334  * memory and fill in local cache.
335  *
336  * @param dev
337  *   Pointer to Ethernet device.
338  * @param mr_ctrl
339  *   Pointer to per-queue MR control structure.
340  * @param mp
341  *   Pointer to registering Mempool.
342  *
343  * @return
344  *   0 on success, -1 on failure.
345  */
346 static uint32_t
347 mlx5_mr_update_ext_mp(struct rte_eth_dev *dev, struct mlx5_mr_ctrl *mr_ctrl,
348                       struct rte_mempool *mp)
349 {
350         struct mr_update_mp_data data = {
351                 .dev = dev,
352                 .mr_ctrl = mr_ctrl,
353                 .ret = 0,
354         };
355
356         rte_mempool_mem_iter(mp, mlx5_mr_update_ext_mp_cb, &data);
357         return data.ret;
358 }
359
360 /**
361  * Register MR entire memory chunks in a Mempool having externally allocated
362  * memory and search LKey of the address to return.
363  *
364  * @param dev
365  *   Pointer to Ethernet device.
366  * @param addr
367  *   Search key.
368  * @param mp
369  *   Pointer to registering Mempool where addr belongs.
370  *
371  * @return
372  *   LKey for address on success, UINT32_MAX on failure.
373  */
374 uint32_t
375 mlx5_tx_update_ext_mp(struct mlx5_txq_data *txq, uintptr_t addr,
376                       struct rte_mempool *mp)
377 {
378         struct mlx5_txq_ctrl *txq_ctrl =
379                 container_of(txq, struct mlx5_txq_ctrl, txq);
380         struct mlx5_mr_ctrl *mr_ctrl = &txq->mr_ctrl;
381         struct mlx5_priv *priv = txq_ctrl->priv;
382
383         if (rte_eal_process_type() != RTE_PROC_PRIMARY) {
384                 DRV_LOG(WARNING,
385                         "port %u using address (%p) from unregistered mempool"
386                         " having externally allocated memory"
387                         " in secondary process, please create mempool"
388                         " prior to rte_eth_dev_start()",
389                         PORT_ID(priv), (void *)addr);
390                 return UINT32_MAX;
391         }
392         mlx5_mr_update_ext_mp(ETH_DEV(priv), mr_ctrl, mp);
393         return mlx5_tx_addr2mr_bh(txq, addr);
394 }
395
396 /* Called during rte_mempool_mem_iter() by mlx5_mr_update_mp(). */
397 static void
398 mlx5_mr_update_mp_cb(struct rte_mempool *mp __rte_unused, void *opaque,
399                      struct rte_mempool_memhdr *memhdr,
400                      unsigned mem_idx __rte_unused)
401 {
402         struct mr_update_mp_data *data = opaque;
403         struct rte_eth_dev *dev = data->dev;
404         struct mlx5_priv *priv = dev->data->dev_private;
405
406         uint32_t lkey;
407
408         /* Stop iteration if failed in the previous walk. */
409         if (data->ret < 0)
410                 return;
411         /* Register address of the chunk and update local caches. */
412         lkey = mlx5_mr_addr2mr_bh(priv->sh->pd, &priv->mp_id,
413                                   &priv->sh->share_cache, data->mr_ctrl,
414                                   (uintptr_t)memhdr->addr,
415                                   priv->config.mr_ext_memseg_en);
416         if (lkey == UINT32_MAX)
417                 data->ret = -1;
418 }
419
420 /**
421  * Register entire memory chunks in a Mempool.
422  *
423  * @param dev
424  *   Pointer to Ethernet device.
425  * @param mr_ctrl
426  *   Pointer to per-queue MR control structure.
427  * @param mp
428  *   Pointer to registering Mempool.
429  *
430  * @return
431  *   0 on success, -1 on failure.
432  */
433 int
434 mlx5_mr_update_mp(struct rte_eth_dev *dev, struct mlx5_mr_ctrl *mr_ctrl,
435                   struct rte_mempool *mp)
436 {
437         struct mr_update_mp_data data = {
438                 .dev = dev,
439                 .mr_ctrl = mr_ctrl,
440                 .ret = 0,
441         };
442         uint32_t flags = rte_pktmbuf_priv_flags(mp);
443
444         if (flags & RTE_PKTMBUF_POOL_F_PINNED_EXT_BUF) {
445                 /*
446                  * The pinned external buffer should be registered for DMA
447                  * operations by application. The mem_list of the pool contains
448                  * the list of chunks with mbuf structures w/o built-in data
449                  * buffers and DMA actually does not happen there, no need
450                  * to create MR for these chunks.
451                  */
452                 return 0;
453         }
454         DRV_LOG(DEBUG, "Port %u Rx queue registering mp %s "
455                        "having %u chunks.", dev->data->port_id,
456                        mp->name, mp->nb_mem_chunks);
457         rte_mempool_mem_iter(mp, mlx5_mr_update_mp_cb, &data);
458         if (data.ret < 0 && rte_errno == ENXIO) {
459                 /* Mempool may have externally allocated memory. */
460                 return mlx5_mr_update_ext_mp(dev, mr_ctrl, mp);
461         }
462         return data.ret;
463 }