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