blob: 7ecf2077d9918bf2db46d9c5def49d65b53c7eae [file] [log] [blame]
/* adapter_sglist.c
*
* Packet Engine Control (PEC) Scatter Gather list API implementation.
*
*/
/*****************************************************************************
* Copyright (c) 2008-2022 by Rambus, Inc. and/or its subsidiaries.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 2 of the License, or
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*****************************************************************************/
/*----------------------------------------------------------------------------
* This module implements (provides) the following interface(s):
*/
#include "api_pec_sg.h" // PEC_SG_* (the API we implement here)
/*----------------------------------------------------------------------------
* This module uses (requires) the following interface(s):
*/
// Default Adapter PEC configuration
#include "c_adapter_pec.h"
// DMABuf API
#include "api_dmabuf.h" // DMABuf_*
// Adapter DMABuf internal API
#include "adapter_dmabuf.h"
// Logging API
#include "log.h"
// Driver Framework DMAResource API
#include "dmares_types.h" // DMAResource_Handle_t
#include "dmares_mgmt.h" // DMAResource management functions
#include "dmares_rw.h" // DMAResource buffer access.
#include "dmares_addr.h" // DMAResource addr translation functions.
#include "dmares_buf.h" // DMAResource buffer allocations
// Driver Framework C Run-Time Library API
#include "clib.h" // memcpy, memset
// Driver Framework Basic Definitions API
#include "basic_defs.h" // bool, uint32_t
/*----------------------------------------------------------------------------
* Definitions and macros
*/
#ifdef ADAPTER_PEC_ENABLE_SCATTERGATHER
// our internal definition of a scatter/gather list
// the DMA buffer for SGList store this (variable-length) structure
typedef struct
{
unsigned int ListCapacity;
struct
{
DMABuf_Handle_t Handle;
unsigned int ByteCount; // set by PEC_SGList_Write and PEC_Packet_Get
} Entries[1]; // variable-size allocated!!!
} PEC_SGList_t;
/*----------------------------------------------------------------------------
* Adapter_Handle2SGList
*
* This function validates that the DMAResource handle is indeed an
* SGList handle
* and then returns the pointer to the PEC_SGList_t structure contained in
* the buffer related to this handle.
*/
static PEC_SGList_t *
Adapter_Handle2SGListPtr(
DMABuf_Handle_t SGList_Handle)
{
DMAResource_Handle_t * DMA_Handle =
Adapter_DMABuf_Handle2DMAResourceHandle(SGList_Handle);
DMAResource_Record_t * Rec_p;
if (DMAResource_IsValidHandle(DMA_Handle))
Rec_p = DMAResource_Handle2RecordPtr(DMA_Handle);
else
return NULL;
// ensure it is an SGList
if (Rec_p->sg.IsSGList != true)
return NULL;
return Adapter_DMAResource_HostAddr(
Adapter_DMABuf_Handle2DMAResourceHandle(SGList_Handle));
}
/*----------------------------------------------------------------------------
* Adapter_SGList_CalcAllocSize
*
* This function calculates the size of the buffer to be allocated to hold
* an PEC_SGList_t with a given capacity.
*/
static inline unsigned int
Adapter_SGList_CalcAllocSize(
const unsigned int ListCapacity)
{
PEC_SGList_t SG;
unsigned int S = sizeof(PEC_SGList_t);
S += (ListCapacity - 1) * sizeof(SG.Entries[1]);
return S;
}
#endif /* ADAPTER_PEC_ENABLE_SCATTERGATHER */
/*----------------------------------------------------------------------------
* PEC_SGList_Create
*
* This function must be used to create a list that can hold references to
* packet buffer fragments. The returned handle can be used in PEC_Packet_Put
* instead of a normal (contiguous) buffers.
*
* ListCapacity (input)
* The number of scatter and/or gather fragments that this list can hold.
*
* SGList_Handle_p (output)
* Pointer to the output parameter that will be filled in with the handle
* that represents the newly created SGList.
*/
PEC_Status_t
PEC_SGList_Create(
const unsigned int ListCapacity,
DMABuf_Handle_t * const SGList_Handle_p)
{
#ifdef ADAPTER_PEC_ENABLE_SCATTERGATHER
DMAResource_AddrPair_t HostAddr;
int dmares;
DMAResource_Properties_t Props;
ZEROINIT(Props);
if (ListCapacity == 0 ||
SGList_Handle_p == NULL)
{
return PEC_ERROR_BAD_PARAMETER;
}
// initialize the output parameter
*SGList_Handle_p = DMABuf_NULLHandle;
Props.Size = Adapter_SGList_CalcAllocSize(ListCapacity);
Props.Alignment = Adapter_DMAResource_Alignment_Get();
dmares = DMAResource_Alloc(Props, &HostAddr, &SGList_Handle_p->p);
if (dmares != 0)
return PEC_ERROR_INTERNAL;
// set the special flag in the DMA Resource record for SGLists
{
DMAResource_Handle_t DMAHandle;
DMAResource_Record_t * Rec_p;
DMAHandle = SGList_Handle_p->p;
Rec_p = DMAResource_Handle2RecordPtr(DMAHandle);
if (!Rec_p)
{
// corner case - avoid memory leak
DMAResource_Release(Adapter_DMABuf_Handle2DMAResourceHandle(
*SGList_Handle_p));
*SGList_Handle_p = DMABuf_NULLHandle;
return PEC_ERROR_INTERNAL;
}
Rec_p->sg.IsSGList = true;
}
// initialize the SGList
{
PEC_SGList_t * const p = HostAddr.Address_p;
memset(p, 0, Props.Size);
p->ListCapacity = ListCapacity;
}
return PEC_STATUS_OK;
#else
IDENTIFIER_NOT_USED(ListCapacity);
IDENTIFIER_NOT_USED(SGList_Handle_p);
return PEC_ERROR_NOT_IMPLEMENTED;
#endif /* ADAPTER_PEC_ENABLE_SCATTERGATHER */
}
/*----------------------------------------------------------------------------
* PEC_SGList_Destroy
*
* This function must be used to destroy a SGList that was previously created
* with PEC_SGList_Create. The potentially referred fragments in the list are
* not freed by the implementation!
*
* SGList_Handle (input)
* The handle to the SGList as returned by PEC_SGList_Create.
*
* DMABuf_Release may be called instead of this function.
*/
PEC_Status_t
PEC_SGList_Destroy(
DMABuf_Handle_t SGList_Handle)
{
#ifdef ADAPTER_PEC_ENABLE_SCATTERGATHER
int dmares;
dmares = DMAResource_Release(
Adapter_DMABuf_Handle2DMAResourceHandle(SGList_Handle));
if (dmares == 0)
return PEC_STATUS_OK;
return PEC_ERROR_BAD_HANDLE;
#else
IDENTIFIER_NOT_USED(SGList_Handle.p);
return PEC_ERROR_NOT_IMPLEMENTED;
#endif /* ADAPTER_PEC_ENABLE_SCATTERGATHER */
}
/*----------------------------------------------------------------------------
* PEC_SGList_Write
*/
PEC_Status_t
PEC_SGList_Write(
DMABuf_Handle_t SGList_Handle,
const unsigned int Index,
DMABuf_Handle_t FragmentHandle,
const unsigned int FragmentByteCount)
{
#ifdef ADAPTER_PEC_ENABLE_SCATTERGATHER
PEC_SGList_t * SGList_p;
SGList_p = Adapter_Handle2SGListPtr(SGList_Handle);
if (SGList_p == NULL)
return PEC_ERROR_BAD_HANDLE;
if (Index >= SGList_p->ListCapacity)
return PEC_ERROR_BAD_PARAMETER;
SGList_p->Entries[Index].Handle = FragmentHandle;
SGList_p->Entries[Index].ByteCount = FragmentByteCount;
return PEC_STATUS_OK;
#else
IDENTIFIER_NOT_USED(SGList_Handle.p);
IDENTIFIER_NOT_USED(Index);
IDENTIFIER_NOT_USED(FragmentHandle.p);
IDENTIFIER_NOT_USED(FragmentByteCount);
return PEC_ERROR_NOT_IMPLEMENTED;
#endif /* ADAPTER_PEC_ENABLE_SCATTERGATHER */
}
/*----------------------------------------------------------------------------
* PEC_SGList_Read
*/
PEC_Status_t
PEC_SGList_Read(
DMABuf_Handle_t SGList_Handle,
const unsigned int Index,
DMABuf_Handle_t * const FragmentHandle_p,
unsigned int * const FragmentSizeInBytes_p,
uint8_t ** const FragmentPtr_p)
{
#ifdef ADAPTER_PEC_ENABLE_SCATTERGATHER
PEC_SGList_t * SGList_p;
// initialize the output parameters
{
if (FragmentHandle_p)
*FragmentHandle_p = DMABuf_NULLHandle;
if (FragmentSizeInBytes_p)
*FragmentSizeInBytes_p = 0;
if (FragmentPtr_p)
*FragmentPtr_p = NULL;
}
SGList_p = Adapter_Handle2SGListPtr(SGList_Handle);
if (SGList_p == NULL)
return PEC_ERROR_BAD_HANDLE;
if (Index >= SGList_p->ListCapacity)
return PEC_ERROR_BAD_PARAMETER;
// fill in the output parameters
{
if (FragmentHandle_p)
*FragmentHandle_p = SGList_p->Entries[Index].Handle;
if (FragmentSizeInBytes_p)
*FragmentSizeInBytes_p = SGList_p->Entries[Index].ByteCount;
if (FragmentPtr_p)
{
// retrieve the host address from the DMA resource record
DMAResource_Handle_t DMAHandle;
DMAResource_Record_t * Rec_p;
DMAHandle = Adapter_DMABuf_Handle2DMAResourceHandle(
SGList_p->Entries[Index].Handle);
Rec_p = DMAResource_Handle2RecordPtr(DMAHandle);
if (Rec_p)
{
// it is a valid handle
*FragmentPtr_p = Adapter_DMAResource_HostAddr(DMAHandle);
}
}
}
return PEC_STATUS_OK;
#else
IDENTIFIER_NOT_USED(SGList_Handle.p);
IDENTIFIER_NOT_USED(Index);
IDENTIFIER_NOT_USED(FragmentHandle_p);
IDENTIFIER_NOT_USED(FragmentSizeInBytes_p);
IDENTIFIER_NOT_USED(FragmentPtr_p);
return PEC_ERROR_NOT_IMPLEMENTED;
#endif /* ADAPTER_PEC_ENABLE_SCATTERGATHER */
}
/*----------------------------------------------------------------------------
* PEC_SGList_GetCapacity
*/
PEC_Status_t
PEC_SGList_GetCapacity(
DMABuf_Handle_t SGList_Handle,
unsigned int * const ListCapacity_p)
{
#ifdef ADAPTER_PEC_ENABLE_SCATTERGATHER
PEC_SGList_t * SGList_p;
if (ListCapacity_p == NULL)
return PEC_ERROR_BAD_PARAMETER;
// initialize the output parameter
*ListCapacity_p = 0;
SGList_p = Adapter_Handle2SGListPtr(SGList_Handle);
if (SGList_p != NULL)
*ListCapacity_p = SGList_p->ListCapacity;
return PEC_STATUS_OK;
#else
IDENTIFIER_NOT_USED(SGList_Handle.p);
IDENTIFIER_NOT_USED(ListCapacity_p);
return PEC_ERROR_NOT_IMPLEMENTED;
#endif /* ADAPTER_PEC_ENABLE_SCATTERGATHER */
}
/* end of file adapter_pec_sglist.c */