root/drivers/net/ethernet/microchip/sparx5/sparx5_pool.c
// SPDX-License-Identifier: GPL-2.0+
/* Microchip Sparx5 Switch driver
 *
 * Copyright (c) 2023 Microchip Technology Inc. and its subsidiaries.
 */

#include "sparx5_main_regs.h"
#include "sparx5_main.h"

static u32 sparx5_pool_id_to_idx(u32 id)
{
        return --id;
}

u32 sparx5_pool_idx_to_id(u32 idx)
{
        return ++idx;
}

/* Release resource from pool.
 * Return reference count on success, otherwise return error.
 */
int sparx5_pool_put(struct sparx5_pool_entry *pool, int size, u32 id)
{
        struct sparx5_pool_entry *e_itr;

        e_itr = (pool + sparx5_pool_id_to_idx(id));
        if (e_itr->ref_cnt == 0)
                return -EINVAL;

        return --e_itr->ref_cnt;
}

/* Get resource from pool.
 * Return reference count on success, otherwise return error.
 */
int sparx5_pool_get(struct sparx5_pool_entry *pool, int size, u32 *id)
{
        struct sparx5_pool_entry *e_itr;
        int i;

        for (i = 0, e_itr = pool; i < size; i++, e_itr++) {
                if (e_itr->ref_cnt == 0) {
                        *id = sparx5_pool_idx_to_id(i);
                        return ++e_itr->ref_cnt;
                }
        }

        return -ENOSPC;
}

/* Get resource from pool that matches index.
 * Return reference count on success, otherwise return error.
 */
int sparx5_pool_get_with_idx(struct sparx5_pool_entry *pool, int size, u32 idx,
                             u32 *id)
{
        struct sparx5_pool_entry *e_itr;
        int i, ret = -ENOSPC;

        for (i = 0, e_itr = pool; i < size; i++, e_itr++) {
                /* Pool index of first free entry */
                if (e_itr->ref_cnt == 0 && ret == -ENOSPC)
                        ret = i;
                /* Tc index already in use ? */
                if (e_itr->idx == idx && e_itr->ref_cnt > 0) {
                        ret = i;
                        break;
                }
        }

        /* Did we find a free entry? */
        if (ret >= 0) {
                *id = sparx5_pool_idx_to_id(ret);
                e_itr = (pool + ret);
                e_itr->idx = idx;
                return ++e_itr->ref_cnt;
        }

        return ret;
}