The function rte_mem_virt2iova() function was always returning BAD_IOVA on FreeBSD as it was not implemented. Unfortunately, this function was used by some drivers - expecting it to work as they used addresses from rte_malloc calls. Implement this call on FreeBSD to fix things and enable more drivers on BSD. To verify the function works as expected add a basic unit test to the memory_autotest for it.
At the same time, we can trivially use this to implement the rte_mem_virt2phy function for the case of using contigmem where IOVAs are physical addresses. Reported-by: Lewis Donzis <[email protected]> Signed-off-by: Bruce Richardson <[email protected]> --- NOTE: This is one of those patches that could be either a bugfix or a feature. For now, I'm treating it as adding new feature support, though in doing so it enables previously broken drivers. --- app/test/test_memory.c | 67 ++++++++++++++++++++++++++++++++++++ lib/eal/freebsd/eal_memory.c | 22 +++++++++--- 2 files changed, 84 insertions(+), 5 deletions(-) diff --git a/app/test/test_memory.c b/app/test/test_memory.c index 628714c0b8..260d5ed8f8 100644 --- a/app/test/test_memory.c +++ b/app/test/test_memory.c @@ -8,6 +8,7 @@ #include <rte_eal.h> #include <rte_errno.h> #include <rte_memory.h> +#include <rte_malloc.h> #include <rte_common.h> #include <rte_memzone.h> @@ -75,6 +76,68 @@ check_seg_fds(const struct rte_memseg_list *msl, const struct rte_memseg *ms, return 0; } +static int +check_malloc_virt2iova(void) +{ + const size_t alloc_sz = 128; + const size_t off = 32; + struct rte_memseg *ms; + char *p; + rte_iova_t iova, iova_off; + + p = rte_malloc("memory_autotest", alloc_sz, RTE_CACHE_LINE_SIZE); + if (p == NULL) { + printf("rte_malloc failed\n"); + return -1; + } + + iova = rte_mem_virt2iova(p); + if (iova == RTE_BAD_IOVA) { + printf("rte_mem_virt2iova failed for rte_malloc pointer\n"); + rte_free(p); + return -1; + } + + ms = rte_mem_virt2memseg(p, NULL); + if (ms == NULL) { + printf("failed to resolve memseg for rte_malloc pointer\n"); + rte_free(p); + return -1; + } + + if (rte_eal_iova_mode() == RTE_IOVA_PA) { + if (ms->iova == RTE_BAD_IOVA || iova < ms->iova || + iova >= ms->iova + ms->len) { + printf("translated iova is outside memseg range\n"); + rte_free(p); + return -1; + } + + phys_addr_t physaddr = rte_mem_virt2phy(p); + if (physaddr == RTE_BAD_PHYS_ADDR || physaddr != iova) { + printf("rte_mem_virt2phy failed for rte_malloc pointer\n"); + rte_free(p); + return -1; + } + } else if (rte_eal_iova_mode() == RTE_IOVA_VA) { + if (iova != (uintptr_t)p) { + printf("rte_mem_virt2iova did not return VA in VA mode\n"); + rte_free(p); + return -1; + } + } + + iova_off = rte_mem_virt2iova(p + off); + if (iova_off == RTE_BAD_IOVA || iova_off != iova + off) { + printf("translated iova for interior pointer is invalid\n"); + rte_free(p); + return -1; + } + + rte_free(p); + return 0; +} + static int test_memory(void) { @@ -107,6 +170,10 @@ test_memory(void) return -1; } + ret = check_malloc_virt2iova(); + if (ret < 0) + return ret; + return 0; } diff --git a/lib/eal/freebsd/eal_memory.c b/lib/eal/freebsd/eal_memory.c index e56d149a22..6952b38630 100644 --- a/lib/eal/freebsd/eal_memory.c +++ b/lib/eal/freebsd/eal_memory.c @@ -40,16 +40,28 @@ RTE_EXPORT_SYMBOL(rte_mem_virt2phy) phys_addr_t rte_mem_virt2phy(const void *virtaddr) { - /* XXX not implemented. This function is only used by - * rte_mempool_virt2iova() when hugepages are disabled. */ - (void)virtaddr; - return RTE_BAD_IOVA; + /* not implemented for FreeBSD when not using contigmem memory */ + if (virtaddr == NULL || rte_eal_iova_mode() != RTE_IOVA_PA) + return RTE_BAD_IOVA; + /* when IOVA == PA, return the IOVA */ + return rte_mem_virt2iova(virtaddr); } + RTE_EXPORT_SYMBOL(rte_mem_virt2iova) rte_iova_t rte_mem_virt2iova(const void *virtaddr) { - return rte_mem_virt2phy(virtaddr); + if (virtaddr == NULL) + return RTE_BAD_IOVA; + + if (rte_eal_iova_mode() == RTE_IOVA_VA) + return (uintptr_t)virtaddr; + + const struct rte_memseg *ms = rte_mem_virt2memseg(virtaddr, NULL); + if (ms != NULL && ms->iova != RTE_BAD_IOVA) + return ms->iova + RTE_PTR_DIFF(virtaddr, ms->addr); + + return RTE_BAD_IOVA; } int -- 2.53.0

