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

Reply via email to