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