ivshmem: remove library and its EAL integration
[dpdk.git] / lib / librte_eal / common / eal_common_memzone.c
index 9c1da71..64f4e0a 100644 (file)
 #include <rte_string_fns.h>
 #include <rte_common.h>
 
+#include "malloc_heap.h"
+#include "malloc_elem.h"
 #include "eal_private.h"
 
-/* internal copy of free memory segments */
-static struct rte_memseg *free_memseg = NULL;
-
 static inline const struct rte_memzone *
 memzone_lookup_thread_unsafe(const char *name)
 {
        const struct rte_mem_config *mcfg;
+       const struct rte_memzone *mz;
        unsigned i = 0;
 
        /* get pointer to global configuration */
@@ -68,73 +68,89 @@ memzone_lookup_thread_unsafe(const char *name)
         * the algorithm is not optimal (linear), but there are few
         * zones and this function should be called at init only
         */
-       for (i = 0; i < RTE_MAX_MEMZONE && mcfg->memzone[i].addr != NULL; i++) {
-               if (!strncmp(name, mcfg->memzone[i].name, RTE_MEMZONE_NAMESIZE))
+       for (i = 0; i < RTE_MAX_MEMZONE; i++) {
+               mz = &mcfg->memzone[i];
+               if (mz->addr != NULL && !strncmp(name, mz->name, RTE_MEMZONE_NAMESIZE))
                        return &mcfg->memzone[i];
        }
 
        return NULL;
 }
 
-/*
- * Helper function for memzone_reserve_aligned_thread_unsafe().
- * Calculate address offset from the start of the segment.
- * Align offset in that way that it satisfy istart alignmnet and
- * buffer of the  requested length would not cross specified boundary.
- */
-static inline phys_addr_t
-align_phys_boundary(const struct rte_memseg *ms, size_t len, size_t align,
-       size_t bound)
+static inline struct rte_memzone *
+get_next_free_memzone(void)
 {
-       phys_addr_t addr_offset, bmask, end, start;
-       size_t step;
+       struct rte_mem_config *mcfg;
+       unsigned i = 0;
 
-       step = RTE_MAX(align, bound);
-       bmask = ~((phys_addr_t)bound - 1);
+       /* get pointer to global configuration */
+       mcfg = rte_eal_get_configuration()->mem_config;
 
-       /* calculate offset to closest alignment */
-       start = RTE_ALIGN_CEIL(ms->phys_addr, align);
-       addr_offset = start - ms->phys_addr;
+       for (i = 0; i < RTE_MAX_MEMZONE; i++) {
+               if (mcfg->memzone[i].addr == NULL)
+                       return &mcfg->memzone[i];
+       }
 
-       while (addr_offset + len < ms->len) {
+       return NULL;
+}
 
-               /* check, do we meet boundary condition */
-               end = start + len - (len != 0);
-               if ((start & bmask) == (end & bmask))
-                       break;
+/* This function will return the greatest free block if a heap has been
+ * specified. If no heap has been specified, it will return the heap and
+ * length of the greatest free block available in all heaps */
+static size_t
+find_heap_max_free_elem(int *s, unsigned align)
+{
+       struct rte_mem_config *mcfg;
+       struct rte_malloc_socket_stats stats;
+       int i, socket = *s;
+       size_t len = 0;
+
+       /* get pointer to global configuration */
+       mcfg = rte_eal_get_configuration()->mem_config;
+
+       for (i = 0; i < RTE_MAX_NUMA_NODES; i++) {
+               if ((socket != SOCKET_ID_ANY) && (socket != i))
+                       continue;
 
-               /* calculate next offset */
-               start = RTE_ALIGN_CEIL(start + 1, step);
-               addr_offset = start - ms->phys_addr;
+               malloc_heap_get_stats(&mcfg->malloc_heaps[i], &stats);
+               if (stats.greatest_free_size > len) {
+                       len = stats.greatest_free_size;
+                       *s = i;
+               }
        }
 
-       return addr_offset;
+       if (len < MALLOC_ELEM_OVERHEAD + align)
+               return 0;
+
+       return len - MALLOC_ELEM_OVERHEAD - align;
 }
 
 static const struct rte_memzone *
 memzone_reserve_aligned_thread_unsafe(const char *name, size_t len,
-               int socket_id, uint64_t size_mask, unsigned align,
-               unsigned bound)
+               int socket_id, unsigned flags, unsigned align, unsigned bound)
 {
+       struct rte_memzone *mz;
        struct rte_mem_config *mcfg;
-       unsigned i = 0;
-       int memseg_idx = -1;
-       uint64_t addr_offset, seg_offset = 0;
        size_t requested_len;
-       size_t memseg_len = 0;
-       phys_addr_t memseg_physaddr;
-       void *memseg_addr;
+       int socket, i;
 
        /* get pointer to global configuration */
        mcfg = rte_eal_get_configuration()->mem_config;
 
        /* no more room in config */
-       if (mcfg->memzone_idx >= RTE_MAX_MEMZONE) {
+       if (mcfg->memzone_cnt >= RTE_MAX_MEMZONE) {
                RTE_LOG(ERR, EAL, "%s(): No more room in config\n", __func__);
                rte_errno = ENOSPC;
                return NULL;
        }
 
+       if (strlen(name) > sizeof(mz->name) - 1) {
+               RTE_LOG(DEBUG, EAL, "%s(): memzone <%s>: name too long\n",
+                       __func__, name);
+               rte_errno = ENAMETOOLONG;
+               return NULL;
+       }
+
        /* zone already exist */
        if ((memzone_lookup_thread_unsafe(name)) != NULL) {
                RTE_LOG(DEBUG, EAL, "%s(): memzone <%s> already exists\n",
@@ -155,7 +171,6 @@ memzone_reserve_aligned_thread_unsafe(const char *name, size_t len,
        if (align < RTE_CACHE_LINE_SIZE)
                align = RTE_CACHE_LINE_SIZE;
 
-
        /* align length on cache boundary. Check for overflow before doing so */
        if (len > SIZE_MAX - RTE_CACHE_LINE_MASK) {
                rte_errno = EINVAL; /* requested size too big */
@@ -169,108 +184,79 @@ memzone_reserve_aligned_thread_unsafe(const char *name, size_t len,
        requested_len = RTE_MAX((size_t)RTE_CACHE_LINE_SIZE,  len);
 
        /* check that boundary condition is valid */
-       if (bound != 0 &&
-                       (requested_len > bound || !rte_is_power_of_2(bound))) {
+       if (bound != 0 && (requested_len > bound || !rte_is_power_of_2(bound))) {
                rte_errno = EINVAL;
                return NULL;
        }
 
-       /* find the smallest segment matching requirements */
-       for (i = 0; i < RTE_MAX_MEMSEG; i++) {
-               /* last segment */
-               if (free_memseg[i].addr == NULL)
-                       break;
-
-               /* empty segment, skip it */
-               if (free_memseg[i].len == 0)
-                       continue;
-
-               /* bad socket ID */
-               if (socket_id != SOCKET_ID_ANY &&
-                   free_memseg[i].socket_id != SOCKET_ID_ANY &&
-                   socket_id != free_memseg[i].socket_id)
-                       continue;
-
-               /*
-                * calculate offset to closest alignment that
-                * meets boundary conditions.
-                */
-               addr_offset = align_phys_boundary(free_memseg + i,
-                       requested_len, align, bound);
-
-               /* check len */
-               if ((requested_len + addr_offset) > free_memseg[i].len)
-                       continue;
+       if ((socket_id != SOCKET_ID_ANY) && (socket_id >= RTE_MAX_NUMA_NODES)) {
+               rte_errno = EINVAL;
+               return NULL;
+       }
 
-               if ((size_mask & free_memseg[i].hugepage_sz) == 0)
-                       continue;
+       if (!rte_eal_has_hugepages())
+               socket_id = SOCKET_ID_ANY;
 
-               /* this segment is the best until now */
-               if (memseg_idx == -1) {
-                       memseg_idx = i;
-                       memseg_len = free_memseg[i].len;
-                       seg_offset = addr_offset;
-               }
-               /* find the biggest contiguous zone */
-               else if (len == 0) {
-                       if (free_memseg[i].len > memseg_len) {
-                               memseg_idx = i;
-                               memseg_len = free_memseg[i].len;
-                               seg_offset = addr_offset;
+       if (len == 0) {
+               if (bound != 0)
+                       requested_len = bound;
+               else {
+                       requested_len = find_heap_max_free_elem(&socket_id, align);
+                       if (requested_len == 0) {
+                               rte_errno = ENOMEM;
+                               return NULL;
                        }
                }
-               /*
-                * find the smallest (we already checked that current
-                * zone length is > len
-                */
-               else if (free_memseg[i].len + align < memseg_len ||
-                               (free_memseg[i].len <= memseg_len + align &&
-                               addr_offset < seg_offset)) {
-                       memseg_idx = i;
-                       memseg_len = free_memseg[i].len;
-                       seg_offset = addr_offset;
+       }
+
+       if (socket_id == SOCKET_ID_ANY)
+               socket = malloc_get_numa_socket();
+       else
+               socket = socket_id;
+
+       /* allocate memory on heap */
+       void *mz_addr = malloc_heap_alloc(&mcfg->malloc_heaps[socket], NULL,
+                       requested_len, flags, align, bound);
+
+       if ((mz_addr == NULL) && (socket_id == SOCKET_ID_ANY)) {
+               /* try other heaps */
+               for (i = 0; i < RTE_MAX_NUMA_NODES; i++) {
+                       if (socket == i)
+                               continue;
+
+                       mz_addr = malloc_heap_alloc(&mcfg->malloc_heaps[i],
+                                       NULL, requested_len, flags, align, bound);
+                       if (mz_addr != NULL)
+                               break;
                }
        }
 
-       /* no segment found */
-       if (memseg_idx == -1) {
+       if (mz_addr == NULL) {
                rte_errno = ENOMEM;
                return NULL;
        }
 
-       /* save aligned physical and virtual addresses */
-       memseg_physaddr = free_memseg[memseg_idx].phys_addr + seg_offset;
-       memseg_addr = RTE_PTR_ADD(free_memseg[memseg_idx].addr,
-                       (uintptr_t) seg_offset);
-
-       /* if we are looking for a biggest memzone */
-       if (len == 0) {
-               if (bound == 0)
-                       requested_len = memseg_len - seg_offset;
-               else
-                       requested_len = RTE_ALIGN_CEIL(memseg_physaddr + 1,
-                               bound) - memseg_physaddr;
-       }
+       const struct malloc_elem *elem = malloc_elem_from_data(mz_addr);
 
-       /* set length to correct value */
-       len = (size_t)seg_offset + requested_len;
+       /* fill the zone in config */
+       mz = get_next_free_memzone();
 
-       /* update our internal state */
-       free_memseg[memseg_idx].len -= len;
-       free_memseg[memseg_idx].phys_addr += len;
-       free_memseg[memseg_idx].addr =
-               (char *)free_memseg[memseg_idx].addr + len;
+       if (mz == NULL) {
+               RTE_LOG(ERR, EAL, "%s(): Cannot find free memzone but there is room "
+                               "in config!\n", __func__);
+               rte_errno = ENOSPC;
+               return NULL;
+       }
 
-       /* fill the zone in config */
-       struct rte_memzone *mz = &mcfg->memzone[mcfg->memzone_idx++];
+       mcfg->memzone_cnt++;
        snprintf(mz->name, sizeof(mz->name), "%s", name);
-       mz->phys_addr = memseg_physaddr;
-       mz->addr = memseg_addr;
-       mz->len = requested_len;
-       mz->hugepage_sz = free_memseg[memseg_idx].hugepage_sz;
-       mz->socket_id = free_memseg[memseg_idx].socket_id;
+       mz->phys_addr = rte_malloc_virt2phy(mz_addr);
+       mz->addr = mz_addr;
+       mz->len = (requested_len == 0 ? elem->size : requested_len);
+       mz->hugepage_sz = elem->ms->hugepage_sz;
+       mz->socket_id = elem->ms->socket_id;
        mz->flags = 0;
-       mz->memseg_id = memseg_idx;
+       mz->memseg_id = elem->ms - rte_eal_get_configuration()->mem_config->memseg;
 
        return mz;
 }
@@ -282,26 +268,6 @@ rte_memzone_reserve_thread_safe(const char *name, size_t len,
 {
        struct rte_mem_config *mcfg;
        const struct rte_memzone *mz = NULL;
-       uint64_t size_mask = 0;
-
-       if (flags & RTE_MEMZONE_256KB)
-               size_mask |= RTE_PGSIZE_256K;
-       if (flags & RTE_MEMZONE_2MB)
-               size_mask |= RTE_PGSIZE_2M;
-       if (flags & RTE_MEMZONE_16MB)
-               size_mask |= RTE_PGSIZE_16M;
-       if (flags & RTE_MEMZONE_256MB)
-               size_mask |= RTE_PGSIZE_256M;
-       if (flags & RTE_MEMZONE_512MB)
-               size_mask |= RTE_PGSIZE_512M;
-       if (flags & RTE_MEMZONE_1GB)
-               size_mask |= RTE_PGSIZE_1G;
-       if (flags & RTE_MEMZONE_4GB)
-               size_mask |= RTE_PGSIZE_4G;
-       if (flags & RTE_MEMZONE_16GB)
-               size_mask |= RTE_PGSIZE_16G;
-       if (!size_mask)
-               size_mask = UINT64_MAX;
 
        /* get pointer to global configuration */
        mcfg = rte_eal_get_configuration()->mem_config;
@@ -309,18 +275,7 @@ rte_memzone_reserve_thread_safe(const char *name, size_t len,
        rte_rwlock_write_lock(&mcfg->mlock);
 
        mz = memzone_reserve_aligned_thread_unsafe(
-               name, len, socket_id, size_mask, align, bound);
-
-       /*
-        * If we failed to allocate the requested page size, and the
-        * RTE_MEMZONE_SIZE_HINT_ONLY flag is specified, try allocating
-        * again.
-        */
-       if (!mz && rte_errno == ENOMEM && size_mask != UINT64_MAX &&
-           flags & RTE_MEMZONE_SIZE_HINT_ONLY) {
-               mz = memzone_reserve_aligned_thread_unsafe(
-                       name, len, socket_id, UINT64_MAX, align, bound);
-       }
+               name, len, socket_id, flags, align, bound);
 
        rte_rwlock_write_unlock(&mcfg->mlock);
 
@@ -364,6 +319,42 @@ rte_memzone_reserve(const char *name, size_t len, int socket_id,
                                               flags, RTE_CACHE_LINE_SIZE, 0);
 }
 
+int
+rte_memzone_free(const struct rte_memzone *mz)
+{
+       struct rte_mem_config *mcfg;
+       int ret = 0;
+       void *addr;
+       unsigned idx;
+
+       if (mz == NULL)
+               return -EINVAL;
+
+       mcfg = rte_eal_get_configuration()->mem_config;
+
+       rte_rwlock_write_lock(&mcfg->mlock);
+
+       idx = ((uintptr_t)mz - (uintptr_t)mcfg->memzone);
+       idx = idx / sizeof(struct rte_memzone);
+
+       addr = mcfg->memzone[idx].addr;
+       if (addr == NULL)
+               ret = -EINVAL;
+       else if (mcfg->memzone_cnt == 0) {
+               rte_panic("%s(): memzone address not NULL but memzone_cnt is 0!\n",
+                               __func__);
+       } else {
+               memset(&mcfg->memzone[idx], 0, sizeof(mcfg->memzone[idx]));
+               mcfg->memzone_cnt--;
+       }
+
+       rte_rwlock_write_unlock(&mcfg->mlock);
+
+       rte_free(addr);
+
+       return ret;
+}
+
 /*
  * Lookup for the memzone identified by the given name
  */
@@ -411,45 +402,6 @@ rte_memzone_dump(FILE *f)
        rte_rwlock_read_unlock(&mcfg->mlock);
 }
 
-/*
- * called by init: modify the free memseg list to have cache-aligned
- * addresses and cache-aligned lengths
- */
-static int
-memseg_sanitize(struct rte_memseg *memseg)
-{
-       unsigned phys_align;
-       unsigned virt_align;
-       unsigned off;
-
-       phys_align = memseg->phys_addr & RTE_CACHE_LINE_MASK;
-       virt_align = (unsigned long)memseg->addr & RTE_CACHE_LINE_MASK;
-
-       /*
-        * sanity check: phys_addr and addr must have the same
-        * alignment
-        */
-       if (phys_align != virt_align)
-               return -1;
-
-       /* memseg is really too small, don't bother with it */
-       if (memseg->len < (2 * RTE_CACHE_LINE_SIZE)) {
-               memseg->len = 0;
-               return 0;
-       }
-
-       /* align start address */
-       off = (RTE_CACHE_LINE_SIZE - phys_align) & RTE_CACHE_LINE_MASK;
-       memseg->phys_addr += off;
-       memseg->addr = (char *)memseg->addr + off;
-       memseg->len -= off;
-
-       /* align end address */
-       memseg->len &= ~((uint64_t)RTE_CACHE_LINE_MASK);
-
-       return 0;
-}
-
 /*
  * Init the memzone subsystem
  */
@@ -458,14 +410,10 @@ rte_eal_memzone_init(void)
 {
        struct rte_mem_config *mcfg;
        const struct rte_memseg *memseg;
-       unsigned i = 0;
 
        /* get pointer to global configuration */
        mcfg = rte_eal_get_configuration()->mem_config;
 
-       /* mirror the runtime memsegs from config */
-       free_memseg = mcfg->free_memseg;
-
        /* secondary processes don't need to initialise anything */
        if (rte_eal_process_type() == RTE_PROC_SECONDARY)
                return 0;
@@ -478,33 +426,13 @@ rte_eal_memzone_init(void)
 
        rte_rwlock_write_lock(&mcfg->mlock);
 
-       /* fill in uninitialized free_memsegs */
-       for (i = 0; i < RTE_MAX_MEMSEG; i++) {
-               if (memseg[i].addr == NULL)
-                       break;
-               if (free_memseg[i].addr != NULL)
-                       continue;
-               memcpy(&free_memseg[i], &memseg[i], sizeof(struct rte_memseg));
-       }
-
-       /* make all zones cache-aligned */
-       for (i = 0; i < RTE_MAX_MEMSEG; i++) {
-               if (free_memseg[i].addr == NULL)
-                       break;
-               if (memseg_sanitize(&free_memseg[i]) < 0) {
-                       RTE_LOG(ERR, EAL, "%s(): Sanity check failed\n", __func__);
-                       rte_rwlock_write_unlock(&mcfg->mlock);
-                       return -1;
-               }
-       }
-
        /* delete all zones */
-       mcfg->memzone_idx = 0;
+       mcfg->memzone_cnt = 0;
        memset(mcfg->memzone, 0, sizeof(mcfg->memzone));
 
        rte_rwlock_write_unlock(&mcfg->mlock);
 
-       return 0;
+       return rte_eal_malloc_heap_init();
 }
 
 /* Walk all reserved memory zones */