root/sys/dev/qat/qat_api/common/utils/lac_mem_pools.c
/* SPDX-License-Identifier: BSD-3-Clause */
/* Copyright(c) 2007-2022 Intel Corporation */
/**
 ***************************************************************************
 * @file lac_mem_pools.c
 *
 * @ingroup LacMemPool
 *
 * Memory Pool creation and mgmt function implementations
 *
 ***************************************************************************/

#include "cpa.h"
#include "qat_utils.h"
#include "icp_accel_devices.h"
#include "icp_adf_init.h"
#include "icp_adf_transport.h"
#include "icp_adf_debug.h"
#include "lac_lock_free_stack.h"
#include "lac_mem_pools.h"
#include "lac_mem.h"
#include "lac_common.h"
#include "cpa_dc.h"
#include "dc_session.h"
#include "dc_datapath.h"
#include "icp_qat_fw_comp.h"
#include "icp_buffer_desc.h"
#include "lac_sym.h"

#define LAC_MEM_POOLS_NUM_SUPPORTED 32000
/**< @ingroup LacMemPool
 * Number of mem pools supported */

#define LAC_MEM_POOLS_NAME_SIZE 17
/**< @ingroup LacMemPool
 * 16 bytes plus '\\0' terminator */

/**< @ingroup LacMemPool
 *     This structure is used to manage each pool created using this utility
 * feature. The client will maintain a pointer (identifier) to the created
 * structure per pool.
 */
typedef struct lac_mem_pool_hdr_s {
        lock_free_stack_t stack;
        char poolName[LAC_MEM_POOLS_NAME_SIZE]; /*16 bytes of a pool name */
        /**< up to 16 bytes of a pool name */
        unsigned int numElementsInPool;
        /**< number of elements in the Pool */
        unsigned int blkSizeInBytes;
        /**< Block size in bytes */
        unsigned int blkAlignmentInBytes;
        /**< block alignment in bytes */
        lac_mem_blk_t **trackBlks;
        /* An array of mem block pointers to track the allocated entries in pool
         */
        volatile size_t availBlks;
        /* Number of blocks available for allocation in this pool */
} lac_mem_pool_hdr_t;

static lac_mem_pool_hdr_t *lac_mem_pools[LAC_MEM_POOLS_NUM_SUPPORTED] = {
        NULL
};
/**< @ingroup LacMemPool
 * Array of pointers to the mem pool header structure
 */

LAC_DECLARE_HIGHEST_BIT_OF(lac_mem_blk_t);
/**< @ingroup LacMemPool
 * local constant for quickening computation of additional space allocated
 * for holding lac_mem_blk_t container-structure
 */

/**
 *******************************************************************************
 * @ingroup LacMemPool
 * This function cleans up a mem pool.
 ******************************************************************************/
void Lac_MemPoolCleanUpInternal(lac_mem_pool_hdr_t *pPoolID);

static inline Cpa32U
Lac_MemPoolGetElementRealSize(Cpa32U blkSizeInBytes, Cpa32U blkAlignmentInBytes)
{
        Cpa32U addSize = (blkAlignmentInBytes >= sizeof(lac_mem_blk_t) ?
                              blkAlignmentInBytes :
                              1 << (highest_bit_of_lac_mem_blk_t + 1));
        return blkSizeInBytes + addSize;
}

CpaStatus
Lac_MemPoolCreate(lac_memory_pool_id_t *pPoolID,
                  char *poolName,
                  unsigned int numElementsInPool,   /*Number of elements*/
                  unsigned int blkSizeInBytes,      /*Block Size in bytes*/
                  unsigned int blkAlignmentInBytes, /*Block alignment (bytes)*/
                  CpaBoolean trackMemory,
                  Cpa32U node)
{
        unsigned int poolSearch = 0;
        unsigned int counter = 0;
        lac_mem_blk_t *pMemBlkCurrent = NULL;

        void *pMemBlk = NULL;

        if (pPoolID == NULL) {
                QAT_UTILS_LOG("Invalid Pool ID param\n");
                return CPA_STATUS_INVALID_PARAM; /*Error*/
        }

        /* Find First available Pool return error otherwise */
        while (lac_mem_pools[poolSearch] != NULL) {
                poolSearch++;
                if (LAC_MEM_POOLS_NUM_SUPPORTED == poolSearch) {
                        QAT_UTILS_LOG(
                            "No more memory pools available for allocation.\n");
                        return CPA_STATUS_FAIL;
                }
        }

        /* Allocate a Pool header */
        lac_mem_pools[poolSearch] = LAC_OS_MALLOC(sizeof(lac_mem_pool_hdr_t));
        if (NULL == lac_mem_pools[poolSearch]) {
                QAT_UTILS_LOG(
                    "Unable to allocate memory for creation of the pool.\n");
                return CPA_STATUS_RESOURCE; /*Error*/
        }
        memset(lac_mem_pools[poolSearch], 0, sizeof(lac_mem_pool_hdr_t));

        /* Copy in Pool Name */
        if (poolName != NULL) {
                snprintf(lac_mem_pools[poolSearch]->poolName,
                         LAC_MEM_POOLS_NAME_SIZE,
                         "%s",
                         poolName);
        } else {
                LAC_OS_FREE(lac_mem_pools[poolSearch]);
                lac_mem_pools[poolSearch] = NULL;
                QAT_UTILS_LOG("Invalid Pool Name pointer\n");
                return CPA_STATUS_INVALID_PARAM; /*Error*/
        }

        /* Allocate table for tracking memory blocks */
        if (CPA_TRUE == trackMemory) {
                lac_mem_pools[poolSearch]->trackBlks = LAC_OS_MALLOC(
                    (sizeof(lac_mem_blk_t *) * numElementsInPool));
                if (NULL == lac_mem_pools[poolSearch]->trackBlks) {
                        LAC_OS_FREE(lac_mem_pools[poolSearch]);
                        lac_mem_pools[poolSearch] = NULL;
                        QAT_UTILS_LOG(
                            "Unable to allocate memory for tracking memory blocks.\n");
                        return CPA_STATUS_RESOURCE; /*Error*/
                }
        } else {
                lac_mem_pools[poolSearch]->trackBlks = NULL;
        }

        lac_mem_pools[poolSearch]->availBlks = 0;
        lac_mem_pools[poolSearch]->stack = _init_stack();

        /* Calculate alignment needed for allocation   */
        for (counter = 0; counter < numElementsInPool; counter++) {
                CpaPhysicalAddr physAddr = 0;
                /* realSize is computed for allocation of  blkSize bytes +
                   additional
                   capacity for lac_mem_blk_t structure storage due to the some
                   OSes
                   (BSD) limitations for memory alignment to be power of 2;
                   sizeof(lac_mem_blk_t) is being round up to the closest power
                   of 2 -
                   optimised towards the least CPU overhead but at additional
                   memory
                   cost
                 */
                Cpa32U realSize =
                    Lac_MemPoolGetElementRealSize(blkSizeInBytes,
                                                  blkAlignmentInBytes);
                Cpa32U addSize = realSize - blkSizeInBytes;

                if (CPA_STATUS_SUCCESS != LAC_OS_CAMALLOC(&pMemBlk,
                                                          realSize,
                                                          blkAlignmentInBytes,
                                                          node)) {
                        Lac_MemPoolCleanUpInternal(lac_mem_pools[poolSearch]);
                        lac_mem_pools[poolSearch] = NULL;
                        QAT_UTILS_LOG(
                            "Unable to allocate contiguous chunk of memory.\n");
                        return CPA_STATUS_RESOURCE;
                }

                /* Calcaulate various offsets */
                physAddr = LAC_OS_VIRT_TO_PHYS_INTERNAL(
                    (void *)((LAC_ARCH_UINT)pMemBlk + addSize));

                /* physAddr is now already aligned to the greater power of 2:
                    blkAlignmentInBytes or sizeof(lac_mem_blk_t) round up
                    We safely put the structure right before the blkSize
                    real data block
                 */
                pMemBlkCurrent =
                    (lac_mem_blk_t *)(((LAC_ARCH_UINT)(pMemBlk)) + addSize -
                                      sizeof(lac_mem_blk_t));

                pMemBlkCurrent->physDataPtr = physAddr;
                pMemBlkCurrent->pMemAllocPtr = pMemBlk;
                pMemBlkCurrent->pPoolID = lac_mem_pools[poolSearch];
                pMemBlkCurrent->isInUse = CPA_FALSE;
                pMemBlkCurrent->pNext = NULL;

                push(&lac_mem_pools[poolSearch]->stack, pMemBlkCurrent);

                /* Store allocated memory pointer */
                if (lac_mem_pools[poolSearch]->trackBlks != NULL) {
                        (lac_mem_pools[poolSearch]->trackBlks[counter]) =
                            (lac_mem_blk_t *)pMemBlkCurrent;
                }
                __sync_add_and_fetch(&lac_mem_pools[poolSearch]->availBlks, 1);
                (lac_mem_pools[poolSearch])->numElementsInPool = counter + 1;
        }

        /* Set Pool details in the header */
        (lac_mem_pools[poolSearch])->blkSizeInBytes = blkSizeInBytes;
        (lac_mem_pools[poolSearch])->blkAlignmentInBytes = blkAlignmentInBytes;
        /* Set the Pool ID output parameter */
        *pPoolID = (LAC_ARCH_UINT)(lac_mem_pools[poolSearch]);
        /* Success */
        return CPA_STATUS_SUCCESS;
}

void *
Lac_MemPoolEntryAlloc(lac_memory_pool_id_t poolID)
{
        lac_mem_pool_hdr_t *pPoolID = (lac_mem_pool_hdr_t *)poolID;
        lac_mem_blk_t *pMemBlkCurrent = NULL;

        /* Explicitly removing NULL PoolID check for speed */
        if (pPoolID == NULL) {
                QAT_UTILS_LOG("Invalid Pool ID");
                return NULL;
        }

        /* Remove block from pool */
        pMemBlkCurrent = pop(&pPoolID->stack);
        if (NULL == pMemBlkCurrent) {
                return (void *)CPA_STATUS_RETRY;
        }
        __sync_sub_and_fetch(&pPoolID->availBlks, 1);
        pMemBlkCurrent->isInUse = CPA_TRUE;
        return (void *)((LAC_ARCH_UINT)(pMemBlkCurrent) +
                        sizeof(lac_mem_blk_t));
}

void
Lac_MemPoolEntryFree(void *pEntry)
{
        lac_mem_blk_t *pMemBlk = NULL;

        /* Explicitly NULL pointer check */
        if (pEntry == NULL) {
                QAT_UTILS_LOG("Memory Handle NULL");
                return;
        }

        pMemBlk =
            (lac_mem_blk_t *)((LAC_ARCH_UINT)pEntry - sizeof(lac_mem_blk_t));
        pMemBlk->isInUse = CPA_FALSE;

        push(&pMemBlk->pPoolID->stack, pMemBlk);
        __sync_add_and_fetch(&pMemBlk->pPoolID->availBlks, 1);
}

void
Lac_MemPoolDestroy(lac_memory_pool_id_t poolID)
{
        unsigned int poolSearch = 0;
        lac_mem_pool_hdr_t *pPoolID = (lac_mem_pool_hdr_t *)poolID;

        if (pPoolID != NULL) {
                /*Remove entry from table*/
                while (lac_mem_pools[poolSearch] != pPoolID) {
                        poolSearch++;

                        if (LAC_MEM_POOLS_NUM_SUPPORTED == poolSearch) {
                                QAT_UTILS_LOG("Invalid Pool ID submitted.\n");
                                return;
                        }
                }

                lac_mem_pools[poolSearch] = NULL; /*Remove handle from pool*/

                Lac_MemPoolCleanUpInternal(pPoolID);
        }
}

void
Lac_MemPoolCleanUpInternal(lac_mem_pool_hdr_t *pPoolID)
{
        lac_mem_blk_t *pCurrentBlk = NULL;
        void *pFreePtr = NULL;
        Cpa32U count = 0;

        if (pPoolID->trackBlks == NULL) {
                pCurrentBlk = pop(&pPoolID->stack);

                while (pCurrentBlk != NULL) {
                        /* Free Data Blocks */
                        pFreePtr = pCurrentBlk->pMemAllocPtr;
                        pCurrentBlk = pop(&pPoolID->stack);
                        LAC_OS_CAFREE(pFreePtr);
                }
        } else {
                for (count = 0; count < pPoolID->numElementsInPool; count++) {
                        pFreePtr = (pPoolID->trackBlks[count])->pMemAllocPtr;
                        LAC_OS_CAFREE(pFreePtr);
                }
                LAC_OS_FREE(pPoolID->trackBlks);
        }
        LAC_OS_FREE(pPoolID);
}

unsigned int
Lac_MemPoolAvailableEntries(lac_memory_pool_id_t poolID)
{
        lac_mem_pool_hdr_t *pPoolID = (lac_mem_pool_hdr_t *)poolID;
        if (pPoolID == NULL) {
                QAT_UTILS_LOG("Invalid Pool ID\n");
                return 0;
        }
        return pPoolID->availBlks;
}

void
Lac_MemPoolStatsShow(void)
{
        unsigned int index = 0;
        QAT_UTILS_LOG(SEPARATOR BORDER
                      "           Memory Pools Stats\n" SEPARATOR);

        while (index < LAC_MEM_POOLS_NUM_SUPPORTED) {
                if (lac_mem_pools[index] != NULL) {
                        QAT_UTILS_LOG(
                            BORDER " Pool Name:             %s \n" BORDER
                                   " No. Elements in Pool:  %10u \n" BORDER
                                   " Element Size in Bytes: %10u \n" BORDER
                                   " Alignment in Bytes:    %10u \n" BORDER
                                   " No. Available Blocks:  %10zu \n" SEPARATOR,
                            lac_mem_pools[index]->poolName,
                            lac_mem_pools[index]->numElementsInPool,
                            lac_mem_pools[index]->blkSizeInBytes,
                            lac_mem_pools[index]->blkAlignmentInBytes,
                            lac_mem_pools[index]->availBlks);
                }
                index++;
        }
}

static void
Lac_MemPoolInitSymCookies(lac_sym_cookie_t *pSymCookie)
{
        pSymCookie->keyContentDescPhyAddr =
            LAC_OS_VIRT_TO_PHYS_INTERNAL(pSymCookie->u.keyCookie.contentDesc);
        pSymCookie->keyHashStateBufferPhyAddr = LAC_OS_VIRT_TO_PHYS_INTERNAL(
            pSymCookie->u.keyCookie.hashStateBuffer);
        pSymCookie->keySslKeyInputPhyAddr = LAC_OS_VIRT_TO_PHYS_INTERNAL(
            &(pSymCookie->u.keyCookie.u.sslKeyInput));
        pSymCookie->keyTlsKeyInputPhyAddr = LAC_OS_VIRT_TO_PHYS_INTERNAL(
            &(pSymCookie->u.keyCookie.u.tlsKeyInput));
}

CpaStatus
Lac_MemPoolInitSymCookiesPhyAddr(lac_memory_pool_id_t poolID)
{
        lac_mem_pool_hdr_t *pPoolID = (lac_mem_pool_hdr_t *)poolID;
        lac_sym_cookie_t *pSymCookie = NULL;
        lac_mem_blk_t *pCurrentBlk = NULL;

        if (NULL == pPoolID) {
                QAT_UTILS_LOG("Invalid Pool ID\n");
                return CPA_STATUS_FAIL;
        }

        if (pPoolID->trackBlks == NULL) {
                pCurrentBlk = top(&pPoolID->stack);

                while (pCurrentBlk != NULL) {
                        pSymCookie =
                            (lac_sym_cookie_t *)((LAC_ARCH_UINT)(pCurrentBlk) +
                                                 sizeof(lac_mem_blk_t));
                        pCurrentBlk = pCurrentBlk->pNext;
                        Lac_MemPoolInitSymCookies(pSymCookie);
                }
        } else {
                Cpa32U count = 0;

                for (count = 0; count < pPoolID->numElementsInPool; count++) {
                        pCurrentBlk = pPoolID->trackBlks[count];
                        pSymCookie =
                            (lac_sym_cookie_t *)((LAC_ARCH_UINT)(pCurrentBlk) +
                                                 sizeof(lac_mem_blk_t));
                        Lac_MemPoolInitSymCookies(pSymCookie);
                }
        }
        return CPA_STATUS_SUCCESS;
}

CpaStatus
Lac_MemPoolInitDcCookiePhyAddr(lac_memory_pool_id_t poolID)
{
        lac_mem_pool_hdr_t *pPoolID = (lac_mem_pool_hdr_t *)poolID;
        lac_mem_blk_t *pCurrentBlk = NULL;

        if (NULL == pPoolID) {
                QAT_UTILS_LOG("Invalid Pool ID\n");
                return CPA_STATUS_FAIL;
        }

        if (NULL == pPoolID->trackBlks) {
                pCurrentBlk = top(&pPoolID->stack);

                while (pCurrentBlk != NULL) {
                        pCurrentBlk = pCurrentBlk->pNext;
                }
        } else {
                Cpa32U count = 0;

                for (count = 0; count < pPoolID->numElementsInPool; count++) {
                        pCurrentBlk = pPoolID->trackBlks[count];
                }
        }
        return CPA_STATUS_SUCCESS;
}