mirror of https://github.com/F-Stack/f-stack.git
201 lines
3.9 KiB
C
201 lines
3.9 KiB
C
|
/* SPDX-License-Identifier: BSD-3-Clause
|
||
|
* Copyright (c) 2022 NVIDIA Corporation & Affiliates
|
||
|
*/
|
||
|
|
||
|
#include <rte_bitmap.h>
|
||
|
#include <rte_malloc.h>
|
||
|
#include "mlx5dr_internal.h"
|
||
|
#include "mlx5dr_buddy.h"
|
||
|
|
||
|
static struct rte_bitmap *bitmap_alloc0(int s)
|
||
|
{
|
||
|
struct rte_bitmap *bitmap;
|
||
|
uint32_t bmp_size;
|
||
|
void *mem;
|
||
|
|
||
|
bmp_size = rte_bitmap_get_memory_footprint(s);
|
||
|
mem = rte_zmalloc("create_bmap", bmp_size, RTE_CACHE_LINE_SIZE);
|
||
|
if (!mem) {
|
||
|
DR_LOG(ERR, "No mem for bitmap");
|
||
|
rte_errno = ENOMEM;
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
bitmap = rte_bitmap_init(s, mem, bmp_size);
|
||
|
if (!bitmap) {
|
||
|
DR_LOG(ERR, "%s Failed to initialize bitmap", __func__);
|
||
|
rte_errno = EINVAL;
|
||
|
goto err_mem_alloc;
|
||
|
}
|
||
|
|
||
|
return bitmap;
|
||
|
|
||
|
err_mem_alloc:
|
||
|
rte_free(mem);
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
static void bitmap_set_bit(struct rte_bitmap *bmp, uint32_t pos)
|
||
|
{
|
||
|
rte_bitmap_set(bmp, pos);
|
||
|
}
|
||
|
|
||
|
static void bitmap_clear_bit(struct rte_bitmap *bmp, uint32_t pos)
|
||
|
{
|
||
|
rte_bitmap_clear(bmp, pos);
|
||
|
}
|
||
|
|
||
|
static bool bitmap_test_bit(struct rte_bitmap *bmp, unsigned long n)
|
||
|
{
|
||
|
return !!rte_bitmap_get(bmp, n);
|
||
|
}
|
||
|
|
||
|
static unsigned long bitmap_ffs(struct rte_bitmap *bmap,
|
||
|
uint64_t n, unsigned long m)
|
||
|
{
|
||
|
uint64_t out_slab = 0;
|
||
|
uint32_t pos = 0; /* Compilation warn */
|
||
|
|
||
|
__rte_bitmap_scan_init(bmap);
|
||
|
if (!rte_bitmap_scan(bmap, &pos, &out_slab)) {
|
||
|
DR_LOG(ERR, "Failed to get slab from bitmap.");
|
||
|
return m;
|
||
|
}
|
||
|
pos = pos + __builtin_ctzll(out_slab);
|
||
|
|
||
|
if (pos < n) {
|
||
|
DR_LOG(ERR, "Unexpected bit (%d < %"PRIx64") from bitmap", pos, n);
|
||
|
return m;
|
||
|
}
|
||
|
return pos;
|
||
|
}
|
||
|
|
||
|
static unsigned long mlx5dr_buddy_find_first_bit(struct rte_bitmap *addr,
|
||
|
uint32_t size)
|
||
|
{
|
||
|
return bitmap_ffs(addr, 0, size);
|
||
|
}
|
||
|
|
||
|
static int mlx5dr_buddy_init(struct mlx5dr_buddy_mem *buddy, uint32_t max_order)
|
||
|
{
|
||
|
int i, s;
|
||
|
|
||
|
buddy->max_order = max_order;
|
||
|
|
||
|
buddy->bits = simple_calloc(buddy->max_order + 1, sizeof(long *));
|
||
|
if (!buddy->bits) {
|
||
|
rte_errno = ENOMEM;
|
||
|
return -1;
|
||
|
}
|
||
|
|
||
|
buddy->num_free = simple_calloc(buddy->max_order + 1, sizeof(*buddy->num_free));
|
||
|
if (!buddy->num_free) {
|
||
|
rte_errno = ENOMEM;
|
||
|
goto err_out_free_bits;
|
||
|
}
|
||
|
|
||
|
for (i = 0; i <= (int)buddy->max_order; ++i) {
|
||
|
s = 1 << (buddy->max_order - i);
|
||
|
buddy->bits[i] = bitmap_alloc0(s);
|
||
|
if (!buddy->bits[i])
|
||
|
goto err_out_free_num_free;
|
||
|
}
|
||
|
|
||
|
bitmap_set_bit(buddy->bits[buddy->max_order], 0);
|
||
|
|
||
|
buddy->num_free[buddy->max_order] = 1;
|
||
|
|
||
|
return 0;
|
||
|
|
||
|
err_out_free_num_free:
|
||
|
for (i = 0; i <= (int)buddy->max_order; ++i)
|
||
|
rte_free(buddy->bits[i]);
|
||
|
|
||
|
simple_free(buddy->num_free);
|
||
|
|
||
|
err_out_free_bits:
|
||
|
simple_free(buddy->bits);
|
||
|
return -1;
|
||
|
}
|
||
|
|
||
|
struct mlx5dr_buddy_mem *mlx5dr_buddy_create(uint32_t max_order)
|
||
|
{
|
||
|
struct mlx5dr_buddy_mem *buddy;
|
||
|
|
||
|
buddy = simple_calloc(1, sizeof(*buddy));
|
||
|
if (!buddy) {
|
||
|
rte_errno = ENOMEM;
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
if (mlx5dr_buddy_init(buddy, max_order))
|
||
|
goto free_buddy;
|
||
|
|
||
|
return buddy;
|
||
|
|
||
|
free_buddy:
|
||
|
simple_free(buddy);
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
void mlx5dr_buddy_cleanup(struct mlx5dr_buddy_mem *buddy)
|
||
|
{
|
||
|
int i;
|
||
|
|
||
|
for (i = 0; i <= (int)buddy->max_order; ++i)
|
||
|
rte_free(buddy->bits[i]);
|
||
|
|
||
|
simple_free(buddy->num_free);
|
||
|
simple_free(buddy->bits);
|
||
|
}
|
||
|
|
||
|
int mlx5dr_buddy_alloc_mem(struct mlx5dr_buddy_mem *buddy, int order)
|
||
|
{
|
||
|
int seg;
|
||
|
int o, m;
|
||
|
|
||
|
for (o = order; o <= (int)buddy->max_order; ++o)
|
||
|
if (buddy->num_free[o]) {
|
||
|
m = 1 << (buddy->max_order - o);
|
||
|
seg = mlx5dr_buddy_find_first_bit(buddy->bits[o], m);
|
||
|
if (m <= seg)
|
||
|
return -1;
|
||
|
|
||
|
goto found;
|
||
|
}
|
||
|
|
||
|
return -1;
|
||
|
|
||
|
found:
|
||
|
bitmap_clear_bit(buddy->bits[o], seg);
|
||
|
--buddy->num_free[o];
|
||
|
|
||
|
while (o > order) {
|
||
|
--o;
|
||
|
seg <<= 1;
|
||
|
bitmap_set_bit(buddy->bits[o], seg ^ 1);
|
||
|
++buddy->num_free[o];
|
||
|
}
|
||
|
|
||
|
seg <<= order;
|
||
|
|
||
|
return seg;
|
||
|
}
|
||
|
|
||
|
void mlx5dr_buddy_free_mem(struct mlx5dr_buddy_mem *buddy, uint32_t seg, int order)
|
||
|
{
|
||
|
seg >>= order;
|
||
|
|
||
|
while (bitmap_test_bit(buddy->bits[order], seg ^ 1)) {
|
||
|
bitmap_clear_bit(buddy->bits[order], seg ^ 1);
|
||
|
--buddy->num_free[order];
|
||
|
seg >>= 1;
|
||
|
++order;
|
||
|
}
|
||
|
|
||
|
bitmap_set_bit(buddy->bits[order], seg);
|
||
|
|
||
|
++buddy->num_free[order];
|
||
|
}
|
||
|
|