1 /* SPDX-License-Identifier: BSD-3-Clause
2 * Copyright(c) 2019-2021 Broadcom
8 #define BITALLOC_MAX_LEVELS 6
11 /* Finds the last bit set plus 1, equivalent to gcc __builtin_fls */
13 ba_fls(bitalloc_word_t v)
20 if (!(v & 0xFFFF0000u)) {
24 if (!(v & 0xFF000000u)) {
28 if (!(v & 0xF0000000u)) {
32 if (!(v & 0xC0000000u)) {
36 if (!(v & 0x80000000u)) {
44 /* Finds the first bit set plus 1, equivalent to gcc __builtin_ffs */
46 ba_ffs(bitalloc_word_t v)
48 int c; /* c will be the number of zero bits on the right plus 1 */
68 ba_init(struct bitalloc *pool, int size, bool free)
70 bitalloc_word_t *mem = (bitalloc_word_t *)pool;
76 if (size < 1 || size > BITALLOC_MAX_SIZE)
81 i < (int)(BITALLOC_SIZEOF(size) / sizeof(bitalloc_word_t));
88 /* Embed number of words of next level, after each level */
89 int words[BITALLOC_MAX_LEVELS];
93 words[0] = (size + 31) / 32;
94 while (words[lev] > 1) {
96 words[lev] = (words[lev - 1] + 31) / 32;
100 offset += words[lev];
101 pool->storage[offset++] = words[--lev];
104 /* Free the entire pool if it is required*/
106 for (i = 0; i < size; i++)
114 ba_alloc_helper(struct bitalloc *pool,
121 bitalloc_word_t *storage = &pool->storage[offset];
122 int loc = ba_ffs(storage[index]);
130 if (pool->size > size) {
131 r = ba_alloc_helper(pool,
138 r = index * 32 + loc;
144 storage[index] &= ~(1 << loc);
145 *clear = (storage[index] == 0);
152 ba_alloc(struct bitalloc *pool)
156 return ba_alloc_helper(pool, 0, 1, 32, 0, &clear);
160 * Help function to alloc entry from highest available index
162 * Searching the pool from highest index for the empty entry.
165 * Pointer to the resource pool
168 * Offset of the storage in the pool
171 * Number of words in this level
174 * Number of entries in this level
177 * Index of words that has the entry
180 * Indicate if a bit needs to be clear due to the entry is allocated
187 ba_alloc_reverse_helper(struct bitalloc *pool,
194 bitalloc_word_t *storage = &pool->storage[offset];
195 int loc = ba_fls(storage[index]);
203 if (pool->size > size) {
204 r = ba_alloc_reverse_helper(pool,
211 r = index * 32 + loc;
217 storage[index] &= ~(1 << loc);
218 *clear = (storage[index] == 0);
225 ba_alloc_reverse(struct bitalloc *pool)
229 return ba_alloc_reverse_helper(pool, 0, 1, 32, 0, &clear);
233 ba_alloc_index_helper(struct bitalloc *pool,
240 bitalloc_word_t *storage = &pool->storage[offset];
244 if (pool->size > size)
245 r = ba_alloc_index_helper(pool,
252 r = 1; /* Check if already allocated */
255 *index = *index / 32;
258 r = (storage[*index] & (1 << loc)) ? 0 : -1;
266 storage[*index] &= ~(1 << loc);
267 *clear = (storage[*index] == 0);
274 ba_alloc_index(struct bitalloc *pool, int index)
277 int index_copy = index;
279 if (index < 0 || index >= (int)pool->size)
282 if (ba_alloc_index_helper(pool, 0, 1, 32, &index_copy, &clear) >= 0)
289 ba_inuse_helper(struct bitalloc *pool,
295 bitalloc_word_t *storage = &pool->storage[offset];
299 if (pool->size > size)
300 r = ba_inuse_helper(pool,
306 r = 1; /* Check if in use */
309 *index = *index / 32;
312 r = (storage[*index] & (1 << loc)) ? -1 : 0;
318 ba_inuse(struct bitalloc *pool, int index)
320 if (index < 0 || index >= (int)pool->size)
323 return ba_inuse_helper(pool, 0, 1, 32, &index) == 0;
327 ba_free_helper(struct bitalloc *pool,
333 bitalloc_word_t *storage = &pool->storage[offset];
337 if (pool->size > size)
338 r = ba_free_helper(pool,
344 r = 1; /* Check if already free */
347 *index = *index / 32;
350 r = (storage[*index] & (1 << loc)) ? -1 : 0;
356 storage[*index] |= (1 << loc);
362 ba_free(struct bitalloc *pool, int index)
364 if (index < 0 || index >= (int)pool->size)
367 return ba_free_helper(pool, 0, 1, 32, &index);
371 ba_inuse_free(struct bitalloc *pool, int index)
373 if (index < 0 || index >= (int)pool->size)
376 return ba_free_helper(pool, 0, 1, 32, &index) + 1;
380 ba_free_count(struct bitalloc *pool)
382 return (int)pool->free_count;
385 int ba_inuse_count(struct bitalloc *pool)
387 return (int)(pool->size) - (int)(pool->free_count);
391 ba_find_next_helper(struct bitalloc *pool,
398 bitalloc_word_t *storage = &pool->storage[offset];
399 int loc, r, bottom = 0;
401 if (pool->size > size)
402 r = ba_find_next_helper(pool,
409 bottom = 1; /* Bottom of tree */
412 *index = *index / 32;
415 int bit_index = *index * 32;
417 loc = ba_ffs(~storage[*index] & ((bitalloc_word_t)-1 << loc));
420 r = (bit_index + loc);
421 if (r >= (int)pool->size)
424 /* Loop over array at bottom of tree */
428 while ((int)pool->size > bit_index) {
429 loc = ba_ffs(~storage[*index]);
433 r = (bit_index + loc);
434 if (r >= (int)pool->size)
444 if (r >= 0 && (free)) {
447 storage[*index] |= (1 << loc);
454 ba_find_next_inuse(struct bitalloc *pool, int index)
457 index >= (int)pool->size ||
458 pool->free_count == pool->size)
461 return ba_find_next_helper(pool, 0, 1, 32, &index, 0);
465 ba_find_next_inuse_free(struct bitalloc *pool, int index)
468 index >= (int)pool->size ||
469 pool->free_count == pool->size)
472 return ba_find_next_helper(pool, 0, 1, 32, &index, 1);