From 2a7fd3ef38da19b2805fecd29c527456364ae618 Mon Sep 17 00:00:00 2001 From: Anatoly Burakov Date: Thu, 14 Nov 2019 13:58:20 +0000 Subject: [PATCH] mempool: use actual IOVA addresses when populating Currently, when mempool is being populated, we get IOVA address of every segment using rte_mem_virt2iova(). This works for internal memory, but does not really work for external memory, and does not work on platforms which return RTE_BAD_IOVA as a result of this call (such as FreeBSD). Moreover, even when it works, the function in question will do unnecessary pagewalks in IOVA as PA mode, as it falls back to rte_mem_virt2phy() instead of just doing a lookup in internal memseg table. To fix it, replace the call to first attempt to look through the internal memseg table (this takes care of internal and external memory), and fall back to rte_mem_virt2iova() when unable to perform VA->IOVA translation via memseg table. Fixes: 66cc45e293ed ("mem: replace memseg with memseg lists") Cc: stable@dpdk.org Signed-off-by: Anatoly Burakov Acked-by: Olivier Matz Tested-by: Bo Chen --- lib/librte_mempool/rte_mempool.c | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/lib/librte_mempool/rte_mempool.c b/lib/librte_mempool/rte_mempool.c index 40cae3eb67..8da2e471c7 100644 --- a/lib/librte_mempool/rte_mempool.c +++ b/lib/librte_mempool/rte_mempool.c @@ -356,6 +356,19 @@ fail: return ret; } +static rte_iova_t +get_iova(void *addr) +{ + struct rte_memseg *ms; + + /* try registered memory first */ + ms = rte_mem_virt2memseg(addr, NULL); + if (ms == NULL || ms->iova == RTE_BAD_IOVA) + /* fall back to actual physical address */ + return rte_mem_virt2iova(addr); + return ms->iova + RTE_PTR_DIFF(addr, ms->addr); +} + /* Populate the mempool with a virtual area. Return the number of * objects added, or a negative value on error. */ @@ -375,7 +388,7 @@ rte_mempool_populate_virt(struct rte_mempool *mp, char *addr, for (off = 0; off < len && mp->populated_size < mp->size; off += phys_len) { - iova = rte_mem_virt2iova(addr + off); + iova = get_iova(addr + off); if (iova == RTE_BAD_IOVA && rte_eal_has_hugepages()) { ret = -EINVAL; @@ -391,7 +404,7 @@ rte_mempool_populate_virt(struct rte_mempool *mp, char *addr, phys_len = RTE_MIN(phys_len + pg_sz, len - off)) { rte_iova_t iova_tmp; - iova_tmp = rte_mem_virt2iova(addr + off + phys_len); + iova_tmp = get_iova(addr + off + phys_len); if (iova_tmp == RTE_BAD_IOVA || iova_tmp != iova + phys_len) -- 2.20.1