1b4316404SKozlowski Mateusz /* SPDX-License-Identifier: BSD-3-Clause
2*a6dbe372Spaul luse * Copyright (C) 2022 Intel Corporation.
3b4316404SKozlowski Mateusz * All rights reserved.
4b4316404SKozlowski Mateusz */
5b4316404SKozlowski Mateusz
6b4316404SKozlowski Mateusz #include "spdk/stdinc.h"
7b4316404SKozlowski Mateusz #include "spdk/queue.h"
8b4316404SKozlowski Mateusz #include "spdk/util.h"
9b4316404SKozlowski Mateusz #include "spdk/env.h"
10b4316404SKozlowski Mateusz #include "spdk/likely.h"
11b4316404SKozlowski Mateusz
12b4316404SKozlowski Mateusz #include "ftl_mempool.h"
1371a17628SArtur Paszkiewicz #include "ftl_bitmap.h"
14b4316404SKozlowski Mateusz
15b4316404SKozlowski Mateusz struct ftl_mempool_element {
16b4316404SKozlowski Mateusz SLIST_ENTRY(ftl_mempool_element) entry;
17b4316404SKozlowski Mateusz };
18b4316404SKozlowski Mateusz
19b4316404SKozlowski Mateusz struct ftl_mempool {
20b4316404SKozlowski Mateusz SLIST_HEAD(, ftl_mempool_element) list;
21b4316404SKozlowski Mateusz size_t element_size;
22b4316404SKozlowski Mateusz void *buffer;
23b4316404SKozlowski Mateusz size_t buffer_size;
24b4316404SKozlowski Mateusz size_t count;
25b4316404SKozlowski Mateusz size_t alignment;
26b4316404SKozlowski Mateusz int socket_id;
2771a17628SArtur Paszkiewicz struct ftl_bitmap *inuse_bmp;
2871a17628SArtur Paszkiewicz void *inuse_buf;
29b4316404SKozlowski Mateusz };
30b4316404SKozlowski Mateusz
31be1883d9SMichal Berger static inline bool is_element_valid(struct ftl_mempool *mpool,
32be1883d9SMichal Berger void *element) __attribute__((unused));
33b4316404SKozlowski Mateusz
3459c10a2fSMichal Berger static inline bool ftl_mempool_is_initialized(struct ftl_mempool *mpool) __attribute__((unused));
3559c10a2fSMichal Berger
36b4316404SKozlowski Mateusz static size_t
element_size_aligned(size_t size,size_t alignment)37b4316404SKozlowski Mateusz element_size_aligned(size_t size, size_t alignment)
38b4316404SKozlowski Mateusz {
39b4316404SKozlowski Mateusz if (!alignment) {
40b4316404SKozlowski Mateusz return size;
41b4316404SKozlowski Mateusz }
42b4316404SKozlowski Mateusz
43b4316404SKozlowski Mateusz if (size % alignment) {
44b4316404SKozlowski Mateusz return (size / alignment + 1) * alignment;
45b4316404SKozlowski Mateusz }
46b4316404SKozlowski Mateusz
47b4316404SKozlowski Mateusz return size;
48b4316404SKozlowski Mateusz }
49b4316404SKozlowski Mateusz
50b4316404SKozlowski Mateusz static inline bool
is_element_valid(struct ftl_mempool * mpool,void * element)51b4316404SKozlowski Mateusz is_element_valid(struct ftl_mempool *mpool, void *element)
52b4316404SKozlowski Mateusz {
53b4316404SKozlowski Mateusz if (element < mpool->buffer) {
54b4316404SKozlowski Mateusz return false;
55b4316404SKozlowski Mateusz }
56b4316404SKozlowski Mateusz
57b4316404SKozlowski Mateusz if (element + mpool->element_size > mpool->buffer + mpool->buffer_size) {
58b4316404SKozlowski Mateusz return false;
59b4316404SKozlowski Mateusz }
60b4316404SKozlowski Mateusz
61b4316404SKozlowski Mateusz if (!mpool->alignment) {
62b4316404SKozlowski Mateusz return true;
63b4316404SKozlowski Mateusz }
64b4316404SKozlowski Mateusz
65b4316404SKozlowski Mateusz if ((size_t)element % mpool->alignment) {
66b4316404SKozlowski Mateusz return false;
67b4316404SKozlowski Mateusz }
68b4316404SKozlowski Mateusz
69b4316404SKozlowski Mateusz if ((element - mpool->buffer) % mpool->element_size != 0) {
70b4316404SKozlowski Mateusz return false;
71b4316404SKozlowski Mateusz }
72b4316404SKozlowski Mateusz
73b4316404SKozlowski Mateusz return true;
74b4316404SKozlowski Mateusz }
75b4316404SKozlowski Mateusz
ftl_mempool_create(size_t count,size_t size,size_t alignment,int socket_id)76b4316404SKozlowski Mateusz struct ftl_mempool *ftl_mempool_create(size_t count, size_t size,
77b4316404SKozlowski Mateusz size_t alignment, int socket_id)
78b4316404SKozlowski Mateusz {
79b4316404SKozlowski Mateusz struct ftl_mempool *mp;
80b4316404SKozlowski Mateusz void *buffer;
81b4316404SKozlowski Mateusz size_t i;
82b4316404SKozlowski Mateusz
83b4316404SKozlowski Mateusz assert(count > 0);
84b4316404SKozlowski Mateusz assert(size > 0);
85b4316404SKozlowski Mateusz
86b4316404SKozlowski Mateusz if (!spdk_u64_is_pow2(alignment)) {
87b4316404SKozlowski Mateusz return NULL;
88b4316404SKozlowski Mateusz }
89b4316404SKozlowski Mateusz
90b4316404SKozlowski Mateusz mp = calloc(1, sizeof(*mp));
91b4316404SKozlowski Mateusz if (!mp) {
92b4316404SKozlowski Mateusz return NULL;
93b4316404SKozlowski Mateusz }
94b4316404SKozlowski Mateusz
95b4316404SKozlowski Mateusz size = spdk_max(size, sizeof(struct ftl_mempool_element));
96b4316404SKozlowski Mateusz
97b4316404SKozlowski Mateusz mp->count = count;
98b4316404SKozlowski Mateusz mp->element_size = element_size_aligned(size, alignment);
99b4316404SKozlowski Mateusz mp->alignment = alignment;
100b4316404SKozlowski Mateusz mp->socket_id = socket_id;
101b4316404SKozlowski Mateusz SLIST_INIT(&mp->list);
102b4316404SKozlowski Mateusz
103b4316404SKozlowski Mateusz mp->buffer_size = mp->element_size * mp->count;
104b4316404SKozlowski Mateusz mp->buffer = spdk_dma_malloc_socket(mp->buffer_size, mp->alignment,
105b4316404SKozlowski Mateusz NULL, socket_id);
106b4316404SKozlowski Mateusz if (!mp->buffer) {
107b4316404SKozlowski Mateusz free(mp);
108b4316404SKozlowski Mateusz return NULL;
109b4316404SKozlowski Mateusz }
110b4316404SKozlowski Mateusz
111b4316404SKozlowski Mateusz buffer = mp->buffer;
112b4316404SKozlowski Mateusz for (i = 0; i < count; i++, buffer += mp->element_size) {
113b4316404SKozlowski Mateusz struct ftl_mempool_element *el = buffer;
114b4316404SKozlowski Mateusz assert(is_element_valid(mp, el));
115b4316404SKozlowski Mateusz SLIST_INSERT_HEAD(&mp->list, el, entry);
116b4316404SKozlowski Mateusz }
117b4316404SKozlowski Mateusz
118b4316404SKozlowski Mateusz return mp;
119b4316404SKozlowski Mateusz }
120b4316404SKozlowski Mateusz
121b4316404SKozlowski Mateusz void
ftl_mempool_destroy(struct ftl_mempool * mpool)122b4316404SKozlowski Mateusz ftl_mempool_destroy(struct ftl_mempool *mpool)
123b4316404SKozlowski Mateusz {
124b4316404SKozlowski Mateusz if (!mpool) {
125b4316404SKozlowski Mateusz return;
126b4316404SKozlowski Mateusz }
127b4316404SKozlowski Mateusz
128b4316404SKozlowski Mateusz spdk_dma_free(mpool->buffer);
129b4316404SKozlowski Mateusz free(mpool);
130b4316404SKozlowski Mateusz }
131b4316404SKozlowski Mateusz
13271a17628SArtur Paszkiewicz static inline bool
ftl_mempool_is_initialized(struct ftl_mempool * mpool)13371a17628SArtur Paszkiewicz ftl_mempool_is_initialized(struct ftl_mempool *mpool)
13471a17628SArtur Paszkiewicz {
13571a17628SArtur Paszkiewicz return mpool->inuse_buf == NULL;
13671a17628SArtur Paszkiewicz }
13771a17628SArtur Paszkiewicz
138b4316404SKozlowski Mateusz void *
ftl_mempool_get(struct ftl_mempool * mpool)139b4316404SKozlowski Mateusz ftl_mempool_get(struct ftl_mempool *mpool)
140b4316404SKozlowski Mateusz {
141b4316404SKozlowski Mateusz struct ftl_mempool_element *el;
142b4316404SKozlowski Mateusz
14371a17628SArtur Paszkiewicz assert(ftl_mempool_is_initialized(mpool));
144b4316404SKozlowski Mateusz if (spdk_unlikely(SLIST_EMPTY(&mpool->list))) {
145b4316404SKozlowski Mateusz return NULL;
146b4316404SKozlowski Mateusz }
147b4316404SKozlowski Mateusz
148b4316404SKozlowski Mateusz el = SLIST_FIRST(&mpool->list);
149b4316404SKozlowski Mateusz SLIST_REMOVE_HEAD(&mpool->list, entry);
150b4316404SKozlowski Mateusz
151b4316404SKozlowski Mateusz return el;
152b4316404SKozlowski Mateusz }
153b4316404SKozlowski Mateusz
154b4316404SKozlowski Mateusz void
ftl_mempool_put(struct ftl_mempool * mpool,void * element)155b4316404SKozlowski Mateusz ftl_mempool_put(struct ftl_mempool *mpool, void *element)
156b4316404SKozlowski Mateusz {
157b4316404SKozlowski Mateusz struct ftl_mempool_element *el = element;
158b4316404SKozlowski Mateusz
15971a17628SArtur Paszkiewicz assert(ftl_mempool_is_initialized(mpool));
160b4316404SKozlowski Mateusz assert(is_element_valid(mpool, element));
161b4316404SKozlowski Mateusz SLIST_INSERT_HEAD(&mpool->list, el, entry);
162b4316404SKozlowski Mateusz }
16371a17628SArtur Paszkiewicz
16471a17628SArtur Paszkiewicz struct ftl_mempool *
ftl_mempool_create_ext(void * buffer,size_t count,size_t size,size_t alignment)16571a17628SArtur Paszkiewicz ftl_mempool_create_ext(void *buffer, size_t count, size_t size, size_t alignment)
16671a17628SArtur Paszkiewicz {
16771a17628SArtur Paszkiewicz struct ftl_mempool *mp;
16871a17628SArtur Paszkiewicz size_t inuse_buf_sz;
16971a17628SArtur Paszkiewicz
17071a17628SArtur Paszkiewicz assert(buffer);
17171a17628SArtur Paszkiewicz assert(count > 0);
17271a17628SArtur Paszkiewicz assert(size > 0);
17371a17628SArtur Paszkiewicz
17471a17628SArtur Paszkiewicz mp = calloc(1, sizeof(*mp));
17571a17628SArtur Paszkiewicz if (!mp) {
17671a17628SArtur Paszkiewicz goto error;
17771a17628SArtur Paszkiewicz }
17871a17628SArtur Paszkiewicz
17971a17628SArtur Paszkiewicz size = spdk_max(size, sizeof(struct ftl_mempool_element));
18071a17628SArtur Paszkiewicz
18171a17628SArtur Paszkiewicz mp->count = count;
18271a17628SArtur Paszkiewicz mp->element_size = element_size_aligned(size, alignment);
18371a17628SArtur Paszkiewicz mp->alignment = alignment;
18471a17628SArtur Paszkiewicz SLIST_INIT(&mp->list);
18571a17628SArtur Paszkiewicz
18671a17628SArtur Paszkiewicz /* Calculate underlying inuse_bmp's buf size */
18771a17628SArtur Paszkiewicz inuse_buf_sz = spdk_divide_round_up(mp->count, 8);
18871a17628SArtur Paszkiewicz /* The bitmap size must be a multiple of word size (8b) - round up */
18971a17628SArtur Paszkiewicz if (inuse_buf_sz & 7UL) {
19071a17628SArtur Paszkiewicz inuse_buf_sz &= ~7UL;
19171a17628SArtur Paszkiewicz inuse_buf_sz += 8;
19271a17628SArtur Paszkiewicz }
19371a17628SArtur Paszkiewicz
19471a17628SArtur Paszkiewicz mp->inuse_buf = calloc(1, inuse_buf_sz);
19571a17628SArtur Paszkiewicz if (!mp->inuse_buf) {
19671a17628SArtur Paszkiewicz goto error;
19771a17628SArtur Paszkiewicz }
19871a17628SArtur Paszkiewicz
19971a17628SArtur Paszkiewicz mp->inuse_bmp = ftl_bitmap_create(mp->inuse_buf, inuse_buf_sz);
20071a17628SArtur Paszkiewicz if (!mp->inuse_bmp) {
20171a17628SArtur Paszkiewicz goto error;
20271a17628SArtur Paszkiewicz }
20371a17628SArtur Paszkiewicz
20471a17628SArtur Paszkiewicz /* Map the buffer */
20571a17628SArtur Paszkiewicz mp->buffer_size = mp->element_size * mp->count;
20671a17628SArtur Paszkiewicz mp->buffer = buffer;
20771a17628SArtur Paszkiewicz
20871a17628SArtur Paszkiewicz return mp;
20971a17628SArtur Paszkiewicz
21071a17628SArtur Paszkiewicz error:
21171a17628SArtur Paszkiewicz ftl_mempool_destroy_ext(mp);
21271a17628SArtur Paszkiewicz return NULL;
21371a17628SArtur Paszkiewicz }
21471a17628SArtur Paszkiewicz
21571a17628SArtur Paszkiewicz void
ftl_mempool_destroy_ext(struct ftl_mempool * mpool)21671a17628SArtur Paszkiewicz ftl_mempool_destroy_ext(struct ftl_mempool *mpool)
21771a17628SArtur Paszkiewicz {
21871a17628SArtur Paszkiewicz if (!mpool) {
21971a17628SArtur Paszkiewicz return;
22071a17628SArtur Paszkiewicz }
22171a17628SArtur Paszkiewicz
22271a17628SArtur Paszkiewicz if (mpool->inuse_bmp) {
22371a17628SArtur Paszkiewicz ftl_bitmap_destroy(mpool->inuse_bmp);
22471a17628SArtur Paszkiewicz }
22571a17628SArtur Paszkiewicz free(mpool->inuse_buf);
22671a17628SArtur Paszkiewicz free(mpool);
22771a17628SArtur Paszkiewicz }
22871a17628SArtur Paszkiewicz
22971a17628SArtur Paszkiewicz void
ftl_mempool_initialize_ext(struct ftl_mempool * mpool)23071a17628SArtur Paszkiewicz ftl_mempool_initialize_ext(struct ftl_mempool *mpool)
23171a17628SArtur Paszkiewicz {
23271a17628SArtur Paszkiewicz struct ftl_mempool_element *el;
23371a17628SArtur Paszkiewicz void *buffer = mpool->buffer;
23471a17628SArtur Paszkiewicz size_t i;
23571a17628SArtur Paszkiewicz
23671a17628SArtur Paszkiewicz assert(!ftl_mempool_is_initialized(mpool));
23771a17628SArtur Paszkiewicz
23871a17628SArtur Paszkiewicz for (i = 0; i < mpool->count; i++, buffer += mpool->element_size) {
23971a17628SArtur Paszkiewicz if (ftl_bitmap_get(mpool->inuse_bmp, i)) {
24071a17628SArtur Paszkiewicz continue;
24171a17628SArtur Paszkiewicz }
24271a17628SArtur Paszkiewicz el = buffer;
24371a17628SArtur Paszkiewicz assert(is_element_valid(mpool, el));
24471a17628SArtur Paszkiewicz SLIST_INSERT_HEAD(&mpool->list, el, entry);
24571a17628SArtur Paszkiewicz }
24671a17628SArtur Paszkiewicz
24771a17628SArtur Paszkiewicz ftl_bitmap_destroy(mpool->inuse_bmp);
24871a17628SArtur Paszkiewicz mpool->inuse_bmp = NULL;
24971a17628SArtur Paszkiewicz
25071a17628SArtur Paszkiewicz free(mpool->inuse_buf);
25171a17628SArtur Paszkiewicz mpool->inuse_buf = NULL;
25271a17628SArtur Paszkiewicz }
25371a17628SArtur Paszkiewicz
25471a17628SArtur Paszkiewicz ftl_df_obj_id
ftl_mempool_get_df_obj_id(struct ftl_mempool * mpool,void * df_obj_ptr)25571a17628SArtur Paszkiewicz ftl_mempool_get_df_obj_id(struct ftl_mempool *mpool, void *df_obj_ptr)
25671a17628SArtur Paszkiewicz {
25771a17628SArtur Paszkiewicz return ftl_df_get_obj_id(mpool->buffer, df_obj_ptr);
25871a17628SArtur Paszkiewicz }
25971a17628SArtur Paszkiewicz
26071a17628SArtur Paszkiewicz size_t
ftl_mempool_get_df_obj_index(struct ftl_mempool * mpool,void * df_obj_ptr)26171a17628SArtur Paszkiewicz ftl_mempool_get_df_obj_index(struct ftl_mempool *mpool, void *df_obj_ptr)
26271a17628SArtur Paszkiewicz {
26371a17628SArtur Paszkiewicz return ftl_mempool_get_df_obj_id(mpool, df_obj_ptr) / mpool->element_size;
26471a17628SArtur Paszkiewicz }
26571a17628SArtur Paszkiewicz
26671a17628SArtur Paszkiewicz void *
ftl_mempool_get_df_ptr(struct ftl_mempool * mpool,ftl_df_obj_id df_obj_id)26771a17628SArtur Paszkiewicz ftl_mempool_get_df_ptr(struct ftl_mempool *mpool, ftl_df_obj_id df_obj_id)
26871a17628SArtur Paszkiewicz {
26971a17628SArtur Paszkiewicz return ftl_df_get_obj_ptr(mpool->buffer, df_obj_id);
27071a17628SArtur Paszkiewicz }
27171a17628SArtur Paszkiewicz
27271a17628SArtur Paszkiewicz void *
ftl_mempool_claim_df(struct ftl_mempool * mpool,ftl_df_obj_id df_obj_id)27371a17628SArtur Paszkiewicz ftl_mempool_claim_df(struct ftl_mempool *mpool, ftl_df_obj_id df_obj_id)
27471a17628SArtur Paszkiewicz {
27571a17628SArtur Paszkiewicz struct ftl_mempool_element *el = ftl_df_get_obj_ptr(mpool->buffer, df_obj_id);
27671a17628SArtur Paszkiewicz
27771a17628SArtur Paszkiewicz assert(!ftl_mempool_is_initialized(mpool));
27871a17628SArtur Paszkiewicz assert(df_obj_id % mpool->element_size == 0);
27971a17628SArtur Paszkiewicz assert(df_obj_id / mpool->element_size < mpool->count);
28071a17628SArtur Paszkiewicz
28171a17628SArtur Paszkiewicz ftl_bitmap_set(mpool->inuse_bmp, df_obj_id / mpool->element_size);
28271a17628SArtur Paszkiewicz return el;
28371a17628SArtur Paszkiewicz }
28471a17628SArtur Paszkiewicz
28571a17628SArtur Paszkiewicz void
ftl_mempool_release_df(struct ftl_mempool * mpool,ftl_df_obj_id df_obj_id)28671a17628SArtur Paszkiewicz ftl_mempool_release_df(struct ftl_mempool *mpool, ftl_df_obj_id df_obj_id)
28771a17628SArtur Paszkiewicz {
28871a17628SArtur Paszkiewicz assert(!ftl_mempool_is_initialized(mpool));
28971a17628SArtur Paszkiewicz assert(df_obj_id % mpool->element_size == 0);
29071a17628SArtur Paszkiewicz assert(df_obj_id / mpool->element_size < mpool->count);
29171a17628SArtur Paszkiewicz
29271a17628SArtur Paszkiewicz ftl_bitmap_clear(mpool->inuse_bmp, df_obj_id / mpool->element_size);
29371a17628SArtur Paszkiewicz }
294