malloc: enable memory hotplug support
[dpdk.git] / lib / librte_eal / common / eal_common_memzone.c
index d60bde7..bce3321 100644 (file)
 static inline const struct rte_memzone *
 memzone_lookup_thread_unsafe(const char *name)
 {
-       const struct rte_mem_config *mcfg;
+       struct rte_mem_config *mcfg;
+       struct rte_fbarray *arr;
        const struct rte_memzone *mz;
-       unsigned i = 0;
+       int i = 0;
 
        /* get pointer to global configuration */
        mcfg = rte_eal_get_configuration()->mem_config;
+       arr = &mcfg->memzones;
 
        /*
         * 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; i++) {
-               mz = &mcfg->memzone[i];
-               if (mz->addr != NULL && !strncmp(name, mz->name, RTE_MEMZONE_NAMESIZE))
-                       return &mcfg->memzone[i];
+       i = rte_fbarray_find_next_used(arr, 0);
+       while (i >= 0) {
+               mz = rte_fbarray_get(arr, i);
+               if (mz->addr != NULL &&
+                               !strncmp(name, mz->name, RTE_MEMZONE_NAMESIZE))
+                       return mz;
+               i = rte_fbarray_find_next_used(arr, i + 1);
        }
-
        return NULL;
 }
 
-static inline struct rte_memzone *
-get_next_free_memzone(void)
-{
-       struct rte_mem_config *mcfg;
-       unsigned i = 0;
-
-       /* get pointer to global configuration */
-       mcfg = rte_eal_get_configuration()->mem_config;
-
-       for (i = 0; i < RTE_MAX_MEMZONE; i++) {
-               if (mcfg->memzone[i].addr == NULL)
-                       return &mcfg->memzone[i];
-       }
-
-       return NULL;
-}
 
 /* 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
@@ -103,15 +91,17 @@ memzone_reserve_aligned_thread_unsafe(const char *name, size_t len,
 {
        struct rte_memzone *mz;
        struct rte_mem_config *mcfg;
+       struct rte_fbarray *arr;
        size_t requested_len;
-       int socket, i;
+       int mz_idx;
        bool contig;
 
        /* get pointer to global configuration */
        mcfg = rte_eal_get_configuration()->mem_config;
+       arr = &mcfg->memzones;
 
        /* no more room in config */
-       if (mcfg->memzone_cnt >= RTE_MAX_MEMZONE) {
+       if (arr->count >= arr->len) {
                RTE_LOG(ERR, EAL, "%s(): No more room in config\n", __func__);
                rte_errno = ENOSPC;
                return NULL;
@@ -193,29 +183,9 @@ memzone_reserve_aligned_thread_unsafe(const char *name, size_t len,
                }
        }
 
-       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, contig);
-
-       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, contig);
-                       if (mz_addr != NULL)
-                               break;
-               }
-       }
-
+       void *mz_addr = malloc_heap_alloc(NULL, requested_len, socket_id, flags,
+                       align, bound, contig);
        if (mz_addr == NULL) {
                rte_errno = ENOMEM;
                return NULL;
@@ -224,25 +194,29 @@ memzone_reserve_aligned_thread_unsafe(const char *name, size_t len,
        struct malloc_elem *elem = malloc_elem_from_data(mz_addr);
 
        /* fill the zone in config */
-       mz = get_next_free_memzone();
+       mz_idx = rte_fbarray_find_next_free(arr, 0);
+
+       if (mz_idx < 0) {
+               mz = NULL;
+       } else {
+               rte_fbarray_set_used(arr, mz_idx);
+               mz = rte_fbarray_get(arr, mz_idx);
+       }
 
        if (mz == NULL) {
-               RTE_LOG(ERR, EAL, "%s(): Cannot find free memzone but there is room "
-                               "in config!\n", __func__);
+               RTE_LOG(ERR, EAL, "%s(): Cannot find free memzone\n", __func__);
                malloc_elem_free(elem);
                rte_errno = ENOSPC;
                return NULL;
        }
 
-       mcfg->memzone_cnt++;
        snprintf(mz->name, sizeof(mz->name), "%s", name);
        mz->iova = rte_malloc_virt2iova(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->hugepage_sz = elem->msl->page_sz;
+       mz->socket_id = elem->msl->socket_id;
        mz->flags = 0;
-       mz->memseg_id = elem->ms - rte_eal_get_configuration()->mem_config->memseg;
 
        return mz;
 }
@@ -308,34 +282,38 @@ int
 rte_memzone_free(const struct rte_memzone *mz)
 {
        struct rte_mem_config *mcfg;
+       struct rte_fbarray *arr;
+       struct rte_memzone *found_mz;
        int ret = 0;
-       void *addr;
+       void *addr = NULL;
        unsigned idx;
 
        if (mz == NULL)
                return -EINVAL;
 
        mcfg = rte_eal_get_configuration()->mem_config;
+       arr = &mcfg->memzones;
 
        rte_rwlock_write_lock(&mcfg->mlock);
 
-       idx = ((uintptr_t)mz - (uintptr_t)mcfg->memzone);
-       idx = idx / sizeof(struct rte_memzone);
+       idx = rte_fbarray_find_idx(arr, mz);
+       found_mz = rte_fbarray_get(arr, idx);
 
-       addr = mcfg->memzone[idx].addr;
-       if (addr == NULL)
+       if (found_mz == NULL) {
+               ret = -EINVAL;
+       } else if (found_mz->addr == NULL) {
+               RTE_LOG(ERR, EAL, "Memzone is not allocated\n");
                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--;
+               addr = found_mz->addr;
+               memset(found_mz, 0, sizeof(*found_mz));
+               rte_fbarray_set_free(arr, idx);
        }
 
        rte_rwlock_write_unlock(&mcfg->mlock);
 
-       rte_free(addr);
+       if (addr != NULL)
+               rte_free(addr);
 
        return ret;
 }
@@ -364,20 +342,50 @@ static void
 dump_memzone(const struct rte_memzone *mz, void *arg)
 {
        struct rte_mem_config *mcfg = rte_eal_get_configuration()->mem_config;
+       struct rte_memseg_list *msl = NULL;
+       void *cur_addr, *mz_end;
+       struct rte_memseg *ms;
+       int mz_idx, ms_idx;
+       size_t page_sz;
        FILE *f = arg;
-       int mz_idx;
 
-       mz_idx = mz - mcfg->memzone;
+       mz_idx = rte_fbarray_find_idx(&mcfg->memzones, mz);
 
-       fprintf(f, "Zone %u: name:<%s>, IO:0x%"PRIx64", len:0x%zx, virt:%p, "
+       fprintf(f, "Zone %u: name:<%s>, len:0x%zx, virt:%p, "
                                "socket_id:%"PRId32", flags:%"PRIx32"\n",
                        mz_idx,
                        mz->name,
-                       mz->iova,
                        mz->len,
                        mz->addr,
                        mz->socket_id,
                        mz->flags);
+
+       /* go through each page occupied by this memzone */
+       msl = rte_mem_virt2memseg_list(mz->addr);
+       if (!msl) {
+               RTE_LOG(DEBUG, EAL, "Skipping bad memzone\n");
+               return;
+       }
+       page_sz = (size_t)mz->hugepage_sz;
+       cur_addr = RTE_PTR_ALIGN_FLOOR(mz->addr, page_sz);
+       mz_end = RTE_PTR_ADD(cur_addr, mz->len);
+
+       fprintf(f, "physical segments used:\n");
+       ms_idx = RTE_PTR_DIFF(mz->addr, msl->base_va) / page_sz;
+       ms = rte_fbarray_get(&msl->memseg_arr, ms_idx);
+
+       do {
+               fprintf(f, "  addr: %p iova: 0x%" PRIx64 " "
+                               "len: 0x%zx "
+                               "pagesz: 0x%zx\n",
+                       cur_addr, ms->iova, ms->len, page_sz);
+
+               /* advance VA to next page */
+               cur_addr = RTE_PTR_ADD(cur_addr, page_sz);
+
+               /* memzones occupy contiguous segments */
+               ++ms;
+       } while (cur_addr < mz_end);
 }
 
 /* Dump all reserved memory zones on console */
@@ -394,30 +402,27 @@ int
 rte_eal_memzone_init(void)
 {
        struct rte_mem_config *mcfg;
-       const struct rte_memseg *memseg;
 
        /* get pointer to global configuration */
        mcfg = rte_eal_get_configuration()->mem_config;
 
-       /* secondary processes don't need to initialise anything */
-       if (rte_eal_process_type() == RTE_PROC_SECONDARY)
-               return 0;
+       rte_rwlock_write_lock(&mcfg->mlock);
 
-       memseg = rte_eal_get_physmem_layout();
-       if (memseg == NULL) {
-               RTE_LOG(ERR, EAL, "%s(): Cannot get physical layout\n", __func__);
+       if (rte_eal_process_type() == RTE_PROC_PRIMARY &&
+                       rte_fbarray_init(&mcfg->memzones, "memzone",
+                       RTE_MAX_MEMZONE, sizeof(struct rte_memzone))) {
+               RTE_LOG(ERR, EAL, "Cannot allocate memzone list\n");
+               return -1;
+       } else if (rte_eal_process_type() == RTE_PROC_SECONDARY &&
+                       rte_fbarray_attach(&mcfg->memzones)) {
+               RTE_LOG(ERR, EAL, "Cannot attach to memzone list\n");
+               rte_rwlock_write_unlock(&mcfg->mlock);
                return -1;
        }
 
-       rte_rwlock_write_lock(&mcfg->mlock);
-
-       /* delete all zones */
-       mcfg->memzone_cnt = 0;
-       memset(mcfg->memzone, 0, sizeof(mcfg->memzone));
-
        rte_rwlock_write_unlock(&mcfg->mlock);
 
-       return rte_eal_malloc_heap_init();
+       return 0;
 }
 
 /* Walk all reserved memory zones */
@@ -425,14 +430,18 @@ void rte_memzone_walk(void (*func)(const struct rte_memzone *, void *),
                      void *arg)
 {
        struct rte_mem_config *mcfg;
-       unsigned i;
+       struct rte_fbarray *arr;
+       int i;
 
        mcfg = rte_eal_get_configuration()->mem_config;
+       arr = &mcfg->memzones;
 
        rte_rwlock_read_lock(&mcfg->mlock);
-       for (i=0; i<RTE_MAX_MEMZONE; i++) {
-               if (mcfg->memzone[i].addr != NULL)
-                       (*func)(&mcfg->memzone[i], arg);
+       i = rte_fbarray_find_next_used(arr, 0);
+       while (i >= 0) {
+               struct rte_memzone *mz = rte_fbarray_get(arr, i);
+               (*func)(mz, arg);
+               i = rte_fbarray_find_next_used(arr, i + 1);
        }
        rte_rwlock_read_unlock(&mcfg->mlock);
 }