Mempool is a generic allocator that is not necessarily used for device
IO operations and its memory for DMA. Add MEMPOOL_F_NON_IO flag to mark
such mempools automatically if their objects are not contiguous
or IOVA are not available. Components can inspect this flag
in order to optimize their memory management.
Discussion: https://mails.dpdk.org/archives/dev/2021-August/216654.html

Signed-off-by: Dmitry Kozlyuk <dkozl...@nvidia.com>
Acked-by: Matan Azrad <ma...@nvidia.com>
---
 app/test/test_mempool.c                | 76 ++++++++++++++++++++++++++
 doc/guides/rel_notes/release_21_11.rst |  3 +
 lib/mempool/rte_mempool.c              |  2 +
 lib/mempool/rte_mempool.h              |  5 ++
 4 files changed, 86 insertions(+)

diff --git a/app/test/test_mempool.c b/app/test/test_mempool.c
index bc0cc9ed48..15146dd737 100644
--- a/app/test/test_mempool.c
+++ b/app/test/test_mempool.c
@@ -672,6 +672,74 @@ test_mempool_events_safety(void)
        return 0;
 }
 
+static int
+test_mempool_flag_non_io_set_when_no_iova_contig_set(void)
+{
+       struct rte_mempool *mp;
+       int ret;
+
+       mp = rte_mempool_create_empty("empty", MEMPOOL_SIZE,
+                                     MEMPOOL_ELT_SIZE, 0, 0,
+                                     SOCKET_ID_ANY, MEMPOOL_F_NO_IOVA_CONTIG);
+       RTE_TEST_ASSERT_NOT_NULL(mp, "Cannot create mempool: %s",
+                                rte_strerror(rte_errno));
+       rte_mempool_set_ops_byname(mp, rte_mbuf_best_mempool_ops(), NULL);
+       ret = rte_mempool_populate_default(mp);
+       RTE_TEST_ASSERT(ret > 0, "Failed to populate mempool: %s",
+                       rte_strerror(rte_errno));
+       RTE_TEST_ASSERT(mp->flags & MEMPOOL_F_NON_IO,
+                       "NON_IO flag is not set when NO_IOVA_CONTIG is set");
+       rte_mempool_free(mp);
+       return 0;
+}
+
+static int
+test_mempool_flag_non_io_set_when_populated_with_bad_iova(void)
+{
+       void *addr;
+       size_t size = 1 << 16;
+       struct rte_mempool *mp;
+       int ret;
+
+       addr = rte_malloc("test_mempool", size, 0);
+       RTE_TEST_ASSERT_NOT_NULL(addr, "Cannot allocate memory");
+       mp = rte_mempool_create_empty("empty", MEMPOOL_SIZE,
+                                     MEMPOOL_ELT_SIZE, 0, 0,
+                                     SOCKET_ID_ANY, 0);
+       RTE_TEST_ASSERT_NOT_NULL(mp, "Cannot create mempool: %s",
+                                rte_strerror(rte_errno));
+       ret = rte_mempool_populate_iova(mp, addr, RTE_BAD_IOVA, size,
+                                       NULL, NULL);
+       /* The flag must be inferred even if population isn't full. */
+       RTE_TEST_ASSERT(ret > 0, "Failed to populate mempool: %s",
+                       rte_strerror(rte_errno));
+       RTE_TEST_ASSERT(mp->flags & MEMPOOL_F_NON_IO,
+                       "NON_IO flag is not set when mempool is populated with 
RTE_BAD_IOVA");
+       rte_mempool_free(mp);
+       rte_free(addr);
+       return 0;
+}
+
+static int
+test_mempool_flag_non_io_unset_by_default(void)
+{
+       struct rte_mempool *mp;
+       int ret;
+
+       mp = rte_mempool_create_empty("empty", MEMPOOL_SIZE,
+                                     MEMPOOL_ELT_SIZE, 0, 0,
+                                     SOCKET_ID_ANY, 0);
+       RTE_TEST_ASSERT_NOT_NULL(mp, "Cannot create mempool: %s",
+                                rte_strerror(rte_errno));
+       ret = rte_mempool_populate_default(mp);
+       RTE_TEST_ASSERT_EQUAL(ret, (int)mp->size, "Failed to populate mempool: 
%s",
+                             rte_strerror(rte_errno));
+       RTE_TEST_ASSERT(!(mp->flags & MEMPOOL_F_NON_IO),
+                       "NON_IO flag is set by default");
+       rte_mempool_free(mp);
+       return 0;
+}
+
 static int
 test_mempool(void)
 {
@@ -854,6 +922,14 @@ test_mempool(void)
        if (test_mempool_events_safety() < 0)
                GOTO_ERR(ret, err);
 
+       /* test NON_IO flag inference */
+       if (test_mempool_flag_non_io_unset_by_default() < 0)
+               GOTO_ERR(ret, err);
+       if (test_mempool_flag_non_io_set_when_no_iova_contig_set() < 0)
+               GOTO_ERR(ret, err);
+       if (test_mempool_flag_non_io_set_when_populated_with_bad_iova() < 0)
+               GOTO_ERR(ret, err);
+
        rte_mempool_list_dump(stdout);
 
        ret = 0;
diff --git a/doc/guides/rel_notes/release_21_11.rst 
b/doc/guides/rel_notes/release_21_11.rst
index f643a61f44..74e0e6f495 100644
--- a/doc/guides/rel_notes/release_21_11.rst
+++ b/doc/guides/rel_notes/release_21_11.rst
@@ -226,6 +226,9 @@ API Changes
   the crypto/security operation. This field will be used to communicate
   events such as soft expiry with IPsec in lookaside mode.
 
+* mempool: Added ``MEMPOOL_F_NON_IO`` flag to give a hint to DPDK components
+  that objects from this pool will not be used for device IO (e.g. DMA).
+
 
 ABI Changes
 -----------
diff --git a/lib/mempool/rte_mempool.c b/lib/mempool/rte_mempool.c
index 51c0ba2931..2204f140b3 100644
--- a/lib/mempool/rte_mempool.c
+++ b/lib/mempool/rte_mempool.c
@@ -371,6 +371,8 @@ rte_mempool_populate_iova(struct rte_mempool *mp, char 
*vaddr,
 
        STAILQ_INSERT_TAIL(&mp->mem_list, memhdr, next);
        mp->nb_mem_chunks++;
+       if (iova == RTE_BAD_IOVA)
+               mp->flags |= MEMPOOL_F_NON_IO;
 
        /* Report the mempool as ready only when fully populated. */
        if (mp->populated_size >= mp->size)
diff --git a/lib/mempool/rte_mempool.h b/lib/mempool/rte_mempool.h
index 663123042f..029b62a650 100644
--- a/lib/mempool/rte_mempool.h
+++ b/lib/mempool/rte_mempool.h
@@ -262,6 +262,8 @@ struct rte_mempool {
 #define MEMPOOL_F_SC_GET         0x0008 /**< Default get is 
"single-consumer".*/
 #define MEMPOOL_F_POOL_CREATED   0x0010 /**< Internal: pool is created. */
 #define MEMPOOL_F_NO_IOVA_CONTIG 0x0020 /**< Don't need IOVA contiguous objs. 
*/
+#define MEMPOOL_F_NON_IO         0x0040
+               /**< Internal: pool is not usable for device IO (DMA). */
 
 /**
  * @internal When debug is enabled, store some statistics.
@@ -991,6 +993,9 @@ typedef void (rte_mempool_ctor_t)(struct rte_mempool *, 
void *);
  *     "single-consumer". Otherwise, it is "multi-consumers".
  *   - MEMPOOL_F_NO_IOVA_CONTIG: If set, allocated objects won't
  *     necessarily be contiguous in IO memory.
+ *   - MEMPOOL_F_NON_IO: If set, the mempool is considered to be
+ *     never used for device IO, i.e. for DMA operations.
+ *     It's a hint to other components and does not affect the mempool 
behavior.
  * @return
  *   The pointer to the new allocated mempool, on success. NULL on error
  *   with rte_errno set appropriately. Possible rte_errno values include:
-- 
2.25.1

Reply via email to