root/sys/dev/qat/qat_api/common/crypto/sym/lac_sym_queue.c
/* SPDX-License-Identifier: BSD-3-Clause */
/* Copyright(c) 2007-2025 Intel Corporation */

/**
 ***************************************************************************
 * @file lac_sym_queue.c     Functions for sending/queuing symmetric requests
 *
 * @ingroup LacSym
 *
 ***************************************************************************/

/*
*******************************************************************************
* Include public/global header files
*******************************************************************************
*/
#include "cpa.h"
#include "cpa_cy_sym.h"

/*
*******************************************************************************
* Include private header files
*******************************************************************************
*/
#include "icp_accel_devices.h"
#include "icp_adf_init.h"
#include "icp_adf_debug.h"
#include "icp_adf_transport.h"
#include "lac_sym_queue.h"
#include "lac_sym_qat.h"
#include "lac_session.h"
#include "lac_sym.h"
#include "lac_log.h"
#include "icp_qat_fw_la.h"
#include "lac_sal_types_crypto.h"

#define GetSingleBitFromByte(byte, bit) ((byte) & (1 << (bit)))

/*
*******************************************************************************
* Define public/global function definitions
*******************************************************************************
*/

CpaStatus
LacSymQueue_RequestSend(const CpaInstanceHandle instanceHandle,
                        lac_sym_bulk_cookie_t *pRequest,
                        lac_session_desc_t *pSessionDesc)
{
        CpaStatus status = CPA_STATUS_SUCCESS;
        CpaBoolean enqueued = CPA_FALSE;
        sal_crypto_service_t *pService = (sal_crypto_service_t *)instanceHandle;
        /* Enqueue the message instead of sending directly if:
         * (i) a blocking operation is in progress
         * (ii) there are previous requests already in the queue
         */
        if ((CPA_FALSE == pSessionDesc->nonBlockingOpsInProgress) ||
            (NULL != pSessionDesc->pRequestQueueTail)) {
                LAC_SPINLOCK(&pSessionDesc->requestQueueLock);

                /* Re-check blockingOpsInProgress and pRequestQueueTail in case
                 * either
                 * changed before the lock was acquired.  The lock is shared
                 * with
                 * the callback context which drains this queue
                 */
                if ((CPA_FALSE == pSessionDesc->nonBlockingOpsInProgress) ||
                    (NULL != pSessionDesc->pRequestQueueTail)) {
                        /* Enqueue the message and exit */
                        /* The FIFO queue is made up of a head and tail pointer.
                         * The head pointer points to the first/oldest, entry
                         * in the queue, and the tail pointer points to the
                         * last/newest
                         * entry in the queue
                         */

                        if (NULL != pSessionDesc->pRequestQueueTail) {
                                /* Queue is non-empty. Add this request to the
                                 * list */
                                pSessionDesc->pRequestQueueTail->pNext =
                                    pRequest;
                        } else {
                                /* Queue is empty. Initialise the head pointer
                                 * as well */
                                pSessionDesc->pRequestQueueHead = pRequest;
                        }

                        pSessionDesc->pRequestQueueTail = pRequest;

                        /* request is queued, don't send to QAT here */
                        enqueued = CPA_TRUE;
                }
                LAC_SPINUNLOCK(&pSessionDesc->requestQueueLock);
        }

        if (CPA_FALSE == enqueued) {
                /* If we send a partial packet request, set the
                 * blockingOpsInProgress
                 * flag for the session to indicate that subsequent requests
                 * must be
                 * queued up until this request completes
                 *
                 * @assumption
                 * If we have got here it means that there were no previous
                 * blocking
                 * operations in progress and, since multiple partial packet
                 * requests
                 * on a given session cannot be issued concurrently, there
                 * should be
                 * no need for a critical section around the following code
                 */
                if (CPA_CY_SYM_PACKET_TYPE_FULL !=
                    pRequest->pOpData->packetType) {
                        /* Select blocking operations which this request will
                         * complete */
                        pSessionDesc->nonBlockingOpsInProgress = CPA_FALSE;
                }

                /* At this point, we're clear to send the request.  For cipher
                 * requests,
                 * we need to check if the session IV needs to be updated.  This
                 * can
                 * only be done when no other partials are in flight for this
                 * session,
                 * to ensure the cipherPartialOpState buffer in the session
                 * descriptor
                 * is not currently in use
                 */
                if (CPA_TRUE == pRequest->updateSessionIvOnSend) {
                        if (LAC_CIPHER_IS_ARC4(pSessionDesc->cipherAlgorithm)) {
                                memcpy(pSessionDesc->cipherPartialOpState,
                                       pSessionDesc->cipherARC4InitialState,
                                       LAC_CIPHER_ARC4_STATE_LEN_BYTES);
                        } else {
                                memcpy(pSessionDesc->cipherPartialOpState,
                                       pRequest->pOpData->pIv,
                                       pRequest->pOpData->ivLenInBytes);
                        }
                }

                /* Send to QAT */
                status = icp_adf_transPutMsg(pService->trans_handle_sym_tx,
                                             (void *)&(pRequest->qatMsg),
                                             LAC_QAT_SYM_REQ_SZ_LW);

                /* if fail to send request, we need to change
                 * nonBlockingOpsInProgress
                 * to CPA_TRUE
                 */
                if ((CPA_STATUS_SUCCESS != status) &&
                    (CPA_CY_SYM_PACKET_TYPE_FULL !=
                     pRequest->pOpData->packetType)) {
                        pSessionDesc->nonBlockingOpsInProgress = CPA_TRUE;
                }
        }
        return status;
}