1 /* SPDX-License-Identifier: BSD-3-Clause 2 * Copyright (c) Intel Corporation. 3 * All rights reserved. 4 */ 5 6 #include "spdk/stdinc.h" 7 #include "spdk/queue.h" 8 #include "spdk/util.h" 9 #include "spdk/env.h" 10 #include "spdk/likely.h" 11 12 #include "ftl_mempool.h" 13 14 struct ftl_mempool_element { 15 SLIST_ENTRY(ftl_mempool_element) entry; 16 }; 17 18 struct ftl_mempool { 19 SLIST_HEAD(, ftl_mempool_element) list; 20 size_t element_size; 21 void *buffer; 22 size_t buffer_size; 23 size_t count; 24 size_t alignment; 25 int socket_id; 26 }; 27 28 static inline bool is_element_valid(struct ftl_mempool *mpool, 29 void *element) __attribute__((unused)); 30 31 static size_t 32 element_size_aligned(size_t size, size_t alignment) 33 { 34 if (!alignment) { 35 return size; 36 } 37 38 if (size % alignment) { 39 return (size / alignment + 1) * alignment; 40 } 41 42 return size; 43 } 44 45 static inline bool 46 is_element_valid(struct ftl_mempool *mpool, void *element) 47 { 48 if (element < mpool->buffer) { 49 return false; 50 } 51 52 if (element + mpool->element_size > mpool->buffer + mpool->buffer_size) { 53 return false; 54 } 55 56 if (!mpool->alignment) { 57 return true; 58 } 59 60 if ((size_t)element % mpool->alignment) { 61 return false; 62 } 63 64 if ((element - mpool->buffer) % mpool->element_size != 0) { 65 return false; 66 } 67 68 return true; 69 } 70 71 struct ftl_mempool *ftl_mempool_create(size_t count, size_t size, 72 size_t alignment, int socket_id) 73 { 74 struct ftl_mempool *mp; 75 void *buffer; 76 size_t i; 77 78 assert(count > 0); 79 assert(size > 0); 80 81 if (!spdk_u64_is_pow2(alignment)) { 82 return NULL; 83 } 84 85 mp = calloc(1, sizeof(*mp)); 86 if (!mp) { 87 return NULL; 88 } 89 90 size = spdk_max(size, sizeof(struct ftl_mempool_element)); 91 92 mp->count = count; 93 mp->element_size = element_size_aligned(size, alignment); 94 mp->alignment = alignment; 95 mp->socket_id = socket_id; 96 SLIST_INIT(&mp->list); 97 98 mp->buffer_size = mp->element_size * mp->count; 99 mp->buffer = spdk_dma_malloc_socket(mp->buffer_size, mp->alignment, 100 NULL, socket_id); 101 if (!mp->buffer) { 102 free(mp); 103 return NULL; 104 } 105 106 buffer = mp->buffer; 107 for (i = 0; i < count; i++, buffer += mp->element_size) { 108 struct ftl_mempool_element *el = buffer; 109 assert(is_element_valid(mp, el)); 110 SLIST_INSERT_HEAD(&mp->list, el, entry); 111 } 112 113 return mp; 114 } 115 116 void 117 ftl_mempool_destroy(struct ftl_mempool *mpool) 118 { 119 if (!mpool) { 120 return; 121 } 122 123 spdk_dma_free(mpool->buffer); 124 free(mpool); 125 } 126 127 void * 128 ftl_mempool_get(struct ftl_mempool *mpool) 129 { 130 struct ftl_mempool_element *el; 131 132 if (spdk_unlikely(SLIST_EMPTY(&mpool->list))) { 133 return NULL; 134 } 135 136 el = SLIST_FIRST(&mpool->list); 137 SLIST_REMOVE_HEAD(&mpool->list, entry); 138 139 return el; 140 } 141 142 void 143 ftl_mempool_put(struct ftl_mempool *mpool, void *element) 144 { 145 struct ftl_mempool_element *el = element; 146 147 assert(is_element_valid(mpool, element)); 148 SLIST_INSERT_HEAD(&mpool->list, el, entry); 149 } 150