New upstream version 17.11.4
[deb_dpdk.git] / lib / librte_eal / linuxapp / eal / eal_memory.c
index 17c20d4..bac969a 100644 (file)
 
 static uint64_t baseaddr_offset;
 
+#ifdef RTE_ARCH_64
+/*
+ * Linux kernel uses a really high address as starting address for serving
+ * mmaps calls. If there exists addressing limitations and IOVA mode is VA,
+ * this starting address is likely too high for those devices. However, it
+ * is possible to use a lower address in the process virtual address space
+ * as with 64 bits there is a lot of available space.
+ *
+ * Current known limitations are 39 or 40 bits. Setting the starting address
+ * at 4GB implies there are 508GB or 1020GB for mapping the available
+ * hugepages. This is likely enough for most systems, although a device with
+ * addressing limitations should call rte_dev_check_dma_mask for ensuring all
+ * memory is within supported range.
+ */
+static uint64_t baseaddr = 0x100000000;
+#endif
+
 static bool phys_addrs_available = true;
 
 #define RANDOMIZE_VA_SPACE_FILE "/proc/sys/kernel/randomize_va_space"
@@ -95,7 +112,7 @@ static bool phys_addrs_available = true;
 static void
 test_phys_addrs_available(void)
 {
-       uint64_t tmp;
+       uint64_t tmp = 0;
        phys_addr_t physaddr;
 
        if (!rte_eal_has_hugepages()) {
@@ -250,6 +267,23 @@ aslr_enabled(void)
        }
 }
 
+static void *
+get_addr_hint(void)
+{
+       if (internal_config.base_virtaddr != 0) {
+               return (void *) (uintptr_t)
+                           (internal_config.base_virtaddr +
+                            baseaddr_offset);
+       } else {
+#ifdef RTE_ARCH_64
+               return (void *) (uintptr_t) (baseaddr +
+                               baseaddr_offset);
+#else
+               return NULL;
+#endif
+       }
+}
+
 /*
  * Try to mmap *size bytes in /dev/zero. If it is successful, return the
  * pointer to the mmap'd area and keep *size unmodified. Else, retry
@@ -260,16 +294,10 @@ aslr_enabled(void)
 static void *
 get_virtual_area(size_t *size, size_t hugepage_sz)
 {
-       void *addr;
+       void *addr, *addr_hint;
        int fd;
        long aligned_addr;
 
-       if (internal_config.base_virtaddr != 0) {
-               addr = (void*) (uintptr_t) (internal_config.base_virtaddr +
-                               baseaddr_offset);
-       }
-       else addr = NULL;
-
        RTE_LOG(DEBUG, EAL, "Ask a virtual area of 0x%zx bytes\n", *size);
 
        fd = open("/dev/zero", O_RDONLY);
@@ -278,7 +306,9 @@ get_virtual_area(size_t *size, size_t hugepage_sz)
                return NULL;
        }
        do {
-               addr = mmap(addr,
+               addr_hint = get_addr_hint();
+
+               addr = mmap(addr_hint,
                                (*size) + hugepage_sz, PROT_READ,
 #ifdef RTE_ARCH_PPC_64
                                MAP_PRIVATE | MAP_ANONYMOUS | MAP_HUGETLB,
@@ -286,8 +316,15 @@ get_virtual_area(size_t *size, size_t hugepage_sz)
                                MAP_PRIVATE,
 #endif
                                fd, 0);
-               if (addr == MAP_FAILED)
+               if (addr == MAP_FAILED) {
+                       /* map failed. Let's try with less memory */
                        *size -= hugepage_sz;
+               } else if (addr_hint && addr != addr_hint) {
+                       /* hint was not used. Try with another offset */
+                       munmap(addr, (*size) + hugepage_sz);
+                       addr = MAP_FAILED;
+                       baseaddr_offset += 0x100000000;
+               }
        } while (addr == MAP_FAILED && *size > 0);
 
        if (addr == MAP_FAILED) {