blob: 280d03d13fa0770e8393e67e7d71520c1c427aec [file] [log] [blame]
/* adapter_pcl_generic.c
*
* Packet Classification (PCL) Generic API implementation.
*
* Notes:
* - this implementation does not use SHDEVXS
*/
/*****************************************************************************
* Copyright (c) 2011-2020 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):
*/
// PCL API
#include "api_pcl.h" // PCL_DTL_*
// Adapter PCL Internal API
#include "adapter_pcl.h" // AdapterPCL_*
/*----------------------------------------------------------------------------
* This module uses (requires) the following interface(s):
*/
// Default Adapter configuration
#include "c_adapter_pcl.h"
// DMABuf API
#include "api_dmabuf.h" // DMABuf_*
// Adapter DMABuf internal API
#include "adapter_dmabuf.h"
// Convert address to pair of 32-bit words.
#include "adapter_addrpair.h"
// Buffer allocation (non-DMA) API
#include "adapter_alloc.h"
// sleeping API/
#include "adapter_sleep.h"
// Adapter Locking internal API
#include "adapter_lock.h" // Adapter_Lock_*
// Runtime Power Management Device Macros API
#include "rpm_device_macros.h" // RPM_*
// Logging API
#include "log.h"
// Driver Framework Device API
#include "device_types.h" // Device_Handle_t
#include "device_mgmt.h" // Device_find
// 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
// List API
#include "list.h" // List_*
// Driver Framework C Run-Time Library API
#include "clib.h" // memcpy, memset
// Driver Framework Basic Definitions API
#include "basic_defs.h" // bool, uint32_t
// EIP-207 Driver Library
#include "eip207_flow_generic.h"
/*----------------------------------------------------------------------------
* Definitions and macros
*/
#if ADAPTER_PCL_MAX_DEVICE_DIGITS > 2
#error "ADAPTER_PCL_MAX_DEVICE_DIGITS > 2 unsupported"
#endif
// Maximum number of 32-bit words in a 4Gb bank - representable as uint32_t
#define ADAPTER_PCL_MAX_BANK_WORDS ((uint32_t)((1ULL<<32) / sizeof(uint32_t)))
/*----------------------------------------------------------------------------
* Local variables
*/
static AdapterPCL_Device_Instance_Data_t Dev_Instance [ADAPTER_PCL_MAX_FLUE_DEVICES];
// DMA buffer allocation alignment, in bytes
static int AdapterPCL_DMA_Alignment_ByteCount =
ADAPTER_DMABUF_ALIGNMENT_INVALID;
// Global lock and critical section for PCL API
static ADAPTER_LOCK_DEFINE(AdapterPCL_Lock);
static Adapter_Lock_CS_t AdapterPCL_CS;
// Cached values for RPM device resume operation
static EIP207_Flow_Address_t EIP207_FlowBaseAddr;
static EIP207_Flow_Address_t EIP207_TransformBaseAddr;
static EIP207_Flow_Address_t EIP207_FlowAddr;
static EIP207_Flow_HT_t EIP207_HT_Params;
/*----------------------------------------------------------------------------
* Function definitions
*/
/*----------------------------------------------------------------------------
AdapterPCLLib_HashTable_Entries_Num_To_Size
Convert numerical value of number of hashtable entries, to corresponding enum
number (input)
value indicating number of hashtable entries (eg. 32)
Return:
EIP207_Flow_HashTable_Entry_Count_t value representing 'number'
or
EIP207_FLOW_HASH_TABLE_ENTRIES_MAX+1 indicating error
Note: implemented using macros to ensure numeric values in step with enums
*/
static EIP207_Flow_HashTable_Entry_Count_t
AdapterPCLLib_HashTable_Entries_Num_To_Size(
int number)
{
#define HASHTABLE_SIZE_CASE(num) \
case (num): return EIP207_FLOW_HASH_TABLE_ENTRIES_##num
switch (number)
{
HASHTABLE_SIZE_CASE(32);
HASHTABLE_SIZE_CASE(64);
HASHTABLE_SIZE_CASE(128);
HASHTABLE_SIZE_CASE(256);
HASHTABLE_SIZE_CASE(512);
HASHTABLE_SIZE_CASE(1024);
HASHTABLE_SIZE_CASE(2048);
HASHTABLE_SIZE_CASE(4096);
HASHTABLE_SIZE_CASE(8192);
HASHTABLE_SIZE_CASE(16384);
HASHTABLE_SIZE_CASE(32768);
HASHTABLE_SIZE_CASE(65536);
HASHTABLE_SIZE_CASE(131072);
HASHTABLE_SIZE_CASE(262144);
HASHTABLE_SIZE_CASE(524288);
HASHTABLE_SIZE_CASE(1048576);
default:
return EIP207_FLOW_HASH_TABLE_ENTRIES_MAX + 1; //invalid value
}
#undef HASHTABLE_SIZE_CASE
}
/*----------------------------------------------------------------------------
* AdapterPCLLib_Device_Find
*
* Returns device handle corresponding to device interface id (index)
* Appends characters corresponding to id number to the device base name.
* The base name ADAPTER_PCL_FLUE_DEFAULT_DEVICE_NAME may optionally end in zero '0'.
* @note Will handle interface index 0-99
*/
static Device_Handle_t
AdapterPCLLib_Device_Find(unsigned int InterfaceId)
{
char device_name_digit;
// base name
char device_name[]= ADAPTER_PCL_FLUE_DEFAULT_DEVICE_NAME "\0\0\0\0";
// string's last char
int device_name_digit_index = strlen(device_name) - 1;
// parameter validation
if (InterfaceId > 1 || // implementation max
InterfaceId >= ADAPTER_PCL_MAX_FLUE_DEVICES || // config max
InterfaceId > 99 // algorithm max
)
{
return NULL;
}
// use final digit (0) if it's present, otherwise skip to end of base name
device_name_digit = device_name[device_name_digit_index];
if (device_name_digit != '0')
{
++device_name_digit_index;
}
if (InterfaceId >= 10) // two digit identifier, write tens digit
{
device_name[device_name_digit_index] = (InterfaceId / 10) + '0';
++device_name_digit_index;
InterfaceId %= 10;
}
// write units digit
device_name[device_name_digit_index] = InterfaceId + '0';
// look up actual device
return Device_Find(device_name);
}
/*-----------------------------------------------------------------------------
* AdapterPCL_Int_To_Ptr
*/
static inline void *
AdapterPCL_Int_To_Ptr(
const unsigned int Value)
{
union Number
{
void * p;
uintptr_t Value;
} N;
N.Value = (uintptr_t)Value;
return N.p;
}
#ifdef ADAPTER_PCL_RPM_EIP207_DEVICE_ID
/*-----------------------------------------------------------------------------
* AdapterPCL_Resume
*/
static int
AdapterPCL_Resume(void * p)
{
EIP207_Flow_Error_t res;
AdapterPCL_Device_Instance_Data_t * Dev_p;
int InterfaceId = *(int *)p;
// only one hash table in this implementation
const unsigned int hashtable_id = 0;
LOG_INFO("\n\t %s \n", __func__);
if (InterfaceId < 0 || InterfaceId < ADAPTER_PCL_RPM_EIP207_DEVICE_ID)
return -1; // error
InterfaceId -= ADAPTER_PCL_RPM_EIP207_DEVICE_ID;
// select current device global instance data, on validated InterfaceId
Dev_p = &Dev_Instance[InterfaceId];
#ifdef ADAPTER_PCL_DMARESOURCE_BANKS_ENABLE
LOG_INFO("\n\t\t EIP207_Flow_RC_BaseAddr_Set \n");
// Restore base addresses for flow and transform records
res = EIP207_Flow_RC_BaseAddr_Set(Dev_p->EIP207_IOArea_p,
hashtable_id,
&EIP207_FlowBaseAddr,
&EIP207_TransformBaseAddr);
if (res != EIP207_FLOW_NO_ERROR)
{
LOG_CRIT("%s: set records base address failed, error %d\n",
__func__,
res);
return -3;
}
#endif // ADAPTER_PCL_DMARESOURCE_BANKS_ENABLE
LOG_INFO("\n\t\t EIP207_Flow_HashTable_Install \n");
// Restore FLUE hashtable
res = EIP207_Flow_HashTable_Install(Dev_p->EIP207_IOArea_p,
hashtable_id,
&EIP207_HT_Params,
ADAPTER_PCL_ENABLE_FLUE_CACHE,
false);
if (res != EIP207_FLOW_NO_ERROR)
{
LOG_CRIT("%s: EIP207_Flow_HashTable_Install() failed, error %d\n",
__func__,
res);
return -4;
}
return 0;
}
#endif
/*-----------------------------------------------------------------------------
* Adapter PCL Internal API functions implementation
*/
/*----------------------------------------------------------------------------
* AdapterPCL_DMABuf_To_TRDscr
*/
PCL_Status_t
AdapterPCL_DMABuf_To_TRDscr(
const DMABuf_Handle_t TransformHandle,
EIP207_Flow_TR_Dscr_t * const TR_Dscr_p,
DMAResource_Record_t ** Rec_pp)
{
DMAResource_Handle_t DMAHandle =
Adapter_DMABuf_Handle2DMAResourceHandle(TransformHandle);
DMAResource_AddrPair_t PhysAddr;
DMAResource_Record_t * Rec_p;
Rec_p = DMAResource_Handle2RecordPtr(DMAHandle);
if (Rec_p == NULL)
return PCL_ERROR;
#ifdef ADAPTER_PCL_DMARESOURCE_BANKS_ENABLE
if (Rec_p->Props.Bank != ADAPTER_PCL_BANK_TRANSFORM)
{
LOG_CRIT("PCL Adapter: Invalid bank for Transform\n");
return PCL_ERROR;
}
#endif
if (DMAResource_Translate(DMAHandle, DMARES_DOMAIN_BUS, &PhysAddr) < 0)
{
LOG_CRIT("PCL_Transform: Failed to obtain physical address.\n");
return PCL_ERROR;
}
Adapter_AddrToWordPair(PhysAddr.Address_p, 0,
&TR_Dscr_p->DMA_Addr.Addr,
&TR_Dscr_p->DMA_Addr.UpperAddr);
TR_Dscr_p->DMA_Handle = DMAHandle;
*Rec_pp = Rec_p;
return PCL_STATUS_OK;
}
/*-----------------------------------------------------------------------------
* AdapterPCL_Device_Get
*/
AdapterPCL_Device_Instance_Data_t *
AdapterPCL_Device_Get(
const unsigned int InterfaceId)
{
return &Dev_Instance[InterfaceId];
}
/*-----------------------------------------------------------------------------
* AdapterPCL_ListID_Get
*/
PCL_Status_t
AdapterPCL_ListID_Get(
const unsigned int InterfaceId,
unsigned int * const ListID_p)
{
// validate parameter
if (ListID_p == NULL)
return PCL_INVALID_PARAMETER;
*ListID_p = Dev_Instance[InterfaceId].FreeListID;
return PCL_STATUS_OK;
}
/*-----------------------------------------------------------------------------
* Adapter PCL API functions implementation
*/
/*----------------------------------------------------------------------------
* PCL_Init
*/
PCL_Status_t
PCL_Init(
const unsigned int InterfaceId,
const unsigned int NofFlowHashTables)
{
EIP207_Flow_Error_t res;
Device_Handle_t EIP207_Device;
AdapterPCL_Device_Instance_Data_t * Dev_p;
unsigned int ioarea_size_bytes;
unsigned int descr_total_size_bytes;
unsigned int hashtable_entry_size_words, hashtable_total_size_words;
List_Element_t * ElementPool_p = NULL;
unsigned char * RecDscrPool_p = NULL;
EIP207_Flow_IOArea_t * ioarea_p = NULL;
void * descr_area_ptr = NULL;
// includes overflow records
const unsigned int total_hasharea_element_count =
(ADAPTER_PCL_FLOW_HASH_OVERFLOW_COUNT +
ADAPTER_PCL_FLOW_HASH_ENTRIES_COUNT);
DMAResource_Handle_t hashtable_dma_handle = NULL;
// only one hash table in this implementation
const unsigned int hashtable_id = 0;
LOG_INFO("\n\t PCL_Init \n");
// check number of hash tables against implementation & config limits
if (NofFlowHashTables == 0 || // validity
NofFlowHashTables > 1 || // implementation limit
NofFlowHashTables > ADAPTER_CS_MAX_NOF_FLOW_HASH_TABLES_TO_USE)
{
LOG_CRIT("PCL_Init: Invalid number (%d) of hash tables\n",
NofFlowHashTables);
return PCL_INVALID_PARAMETER;
}
Adapter_Lock_CS_Set(&AdapterPCL_CS, &AdapterPCL_Lock);
if (!Adapter_Lock_CS_Enter(&AdapterPCL_CS))
return PCL_STATUS_BUSY;
// select current device global instance data, on validated InterfaceId
Dev_p = &Dev_Instance[InterfaceId];
// state consistency check
if (Dev_p->PCL_IsInitialized)
{
LOG_CRIT("PCL_Init: Already initialized\n");
Adapter_Lock_CS_Leave(&AdapterPCL_CS);
return PCL_ERROR;
}
// Initialize instance variables to 0/NULL defaults
ZEROINIT(*Dev_p);
// Allocate device lock
Dev_p->AdapterPCL_DevLock = Adapter_Lock_Alloc();
if (Dev_p->AdapterPCL_DevLock == Adapter_Lock_NULL)
{
LOG_CRIT("PCL_Init: PutLock allocation failed\n");
Adapter_Lock_CS_Leave(&AdapterPCL_CS);
return PCL_OUT_OF_MEMORY_ERROR;
}
Adapter_Lock_CS_Set(&Dev_p->AdapterPCL_DevCS,
Dev_p->AdapterPCL_DevLock);
// identify device, check InterfaceId
EIP207_Device = AdapterPCLLib_Device_Find(InterfaceId);
if (EIP207_Device == NULL)
{
LOG_CRIT("PCL_Init: Cannot find EIP-207 device, id=%d\n", InterfaceId);
goto error_exit;
}
// Get DMA buffer allocation alignment
AdapterPCL_DMA_Alignment_ByteCount = Adapter_DMAResource_Alignment_Get();
if (AdapterPCL_DMA_Alignment_ByteCount == ADAPTER_DMABUF_ALIGNMENT_INVALID)
{
#if ADAPTER_PCL_DMA_ALIGNMENT_BYTE_COUNT == 0
LOG_CRIT("PCL_Init: Failed to get DMA alignment\n");
goto error_exit;
#else
AdapterPCL_DMA_Alignment_ByteCount =
ADAPTER_PCL_DMA_ALIGNMENT_BYTE_COUNT;
#endif
}
// allocate IOArea non-DMA memory
ioarea_size_bytes = EIP207_Flow_IOArea_ByteCount_Get();
ioarea_p = Adapter_Alloc(ioarea_size_bytes);
if (ioarea_p == NULL)
{
LOG_CRIT("PCL_Init: Cannot allocate IOArea\n");
goto error_exit;
}
// store value for global use
Dev_p->EIP207_IOArea_p = ioarea_p;
if (RPM_DEVICE_INIT_START_MACRO(ADAPTER_PCL_RPM_EIP207_DEVICE_ID + InterfaceId,
0, // No suspend callback is used
AdapterPCL_Resume) != RPM_SUCCESS)
goto error_exit;
LOG_INFO("\n\t\t EIP207_Flow_Init \n");
// hand IOArea memory to driver
res = EIP207_Flow_Init(Dev_p->EIP207_IOArea_p,
EIP207_Device);
if (res != EIP207_FLOW_NO_ERROR)
{
LOG_CRIT("PCL_Init: EIP207_Flow_Init() failed\n");
goto fail; // exit which frees allocated resources
}
#ifdef ADAPTER_PCL_DMARESOURCE_BANKS_ENABLE
{
unsigned int RecordWordCount;
RecordWordCount = EIP207_Flow_TR_WordCount_Get();
if (RecordWordCount * sizeof(uint32_t) >
ADAPTER_TRANSFORM_RECORD_BYTE_COUNT)
{
LOG_CRIT("PCL_Init: Bad Record size in transform bank, "
"is %d, at least %d required\n",
(int)(ADAPTER_TRANSFORM_RECORD_BYTE_COUNT *
sizeof(uint32_t)),
RecordWordCount);
goto fail; // exit which frees allocated resources
}
RecordWordCount = EIP207_Flow_FR_WordCount_Get();
if (RecordWordCount * sizeof(uint32_t) >
ADAPTER_PCL_FLOW_RECORD_BYTE_COUNT)
{
LOG_CRIT("PCL_Init: Bad Record size in flow bank, "
"is %d, at least %d required\n",
(int)(ADAPTER_PCL_FLOW_RECORD_BYTE_COUNT *
sizeof(uint32_t)),
RecordWordCount);
goto fail; // exit which frees allocated resources
}
}
{ // Set the SA pool base address.
int dmares;
DMAResource_Handle_t DMAHandle;
DMAResource_Properties_t DMAProperties;
DMAResource_AddrPair_t DMAAddr;
ZEROINIT(EIP207_FlowBaseAddr);
ZEROINIT(EIP207_TransformBaseAddr);
// Perform a full-bank allocation in transform bank to obtain the bank base
// address.
{
DMAProperties.Alignment = AdapterPCL_DMA_Alignment_ByteCount;
DMAProperties.Bank = ADAPTER_PCL_BANK_TRANSFORM;
DMAProperties.fCached = false;
DMAProperties.Size = ADAPTER_TRANSFORM_RECORD_COUNT *
ADAPTER_TRANSFORM_RECORD_BYTE_COUNT;
dmares = DMAResource_Alloc(DMAProperties,
&DMAAddr,
&DMAHandle);
if (dmares != 0)
{
LOG_CRIT(
"PCL_Init: allocate transforms base address failed\n");
goto fail; // exit which frees allocated resources
}
// Derive the physical address from the DMA resource.
if (DMAResource_Translate(DMAHandle,
DMARES_DOMAIN_BUS,
&DMAAddr) < 0)
{
DMAResource_Release(DMAHandle);
LOG_CRIT(
"PCL_Init: translate transforms base address failed\n");
goto fail; // exit which frees allocated resources
}
Adapter_AddrToWordPair(DMAAddr.Address_p,
0,
&EIP207_TransformBaseAddr.Addr,
&EIP207_TransformBaseAddr.UpperAddr);
// Release the DMA resource
DMAResource_Release(DMAHandle);
}
// Perform a size 0 allocation in flow bank to obtain the bank base
// address.
DMAProperties.Alignment = AdapterPCL_DMA_Alignment_ByteCount;
DMAProperties.Bank = ADAPTER_PCL_BANK_FLOW;
DMAProperties.fCached = false;
DMAProperties.Size = ADAPTER_PCL_FLOW_RECORD_COUNT *
ADAPTER_PCL_FLOW_RECORD_BYTE_COUNT;
dmares = DMAResource_Alloc(DMAProperties,
&DMAAddr,
&DMAHandle);
if (dmares != 0)
{
LOG_CRIT("PCL_Init: allocate flow base address failed\n");
goto fail; // exit which frees allocated resources
}
// Derive the physical address from the DMA resource.
if (DMAResource_Translate(DMAHandle, DMARES_DOMAIN_BUS, &DMAAddr) < 0)
{
DMAResource_Release(DMAHandle);
LOG_CRIT("PCL_Init: translate flow base address failed\n");
goto fail; // exit which frees allocated resources
}
Adapter_AddrToWordPair(DMAAddr.Address_p, 0,
&EIP207_FlowBaseAddr.Addr,
&EIP207_FlowBaseAddr.UpperAddr);
// Release the DMA resource - handle to zero-size request.
DMAResource_Release(DMAHandle);
LOG_INFO("\n\t\t EIP207_Flow_RC_BaseAddr_Set \n");
// set base addresses for flow and transform records
res = EIP207_Flow_RC_BaseAddr_Set(
ioarea_p,
hashtable_id,
&EIP207_FlowBaseAddr,
&EIP207_TransformBaseAddr);
if (res != EIP207_FLOW_NO_ERROR)
{
LOG_CRIT("PCL_Init: set records base address failed\n");
goto fail; // exit which frees allocated resources
}
}
#endif // ADAPTER_PCL_DMARESOURCE_BANKS_ENABLE
// Install Hashtable:
// - calculate amount of required descriptor memory & allocate it
// - calculate amount of required DMA-safe hashtable+overflow memory &
// allocate it
// - fill in struct for HT install, call install function
// descriptor memory
descr_total_size_bytes = EIP207_Flow_HTE_Dscr_ByteCount_Get() *
total_hasharea_element_count;
descr_area_ptr = Adapter_Alloc(descr_total_size_bytes);
if (descr_area_ptr == NULL)
{
LOG_CRIT("PCL_Init: Cannot allocate descriptor area\n");
goto fail; // exit which frees allocated resources
}
// store value for global use
Dev_p->EIP207_Descriptor_Area_p = descr_area_ptr;
// get required memory size for hash table
// = (hash table size + overflow entries)*bucket size
hashtable_entry_size_words = EIP207_Flow_HT_Entry_WordCount_Get();
hashtable_total_size_words =
hashtable_entry_size_words * total_hasharea_element_count;
// check total size of hashtable region (lookup + overflow)
// would not exceed a 32-bit addressable bank of 4GB
if (hashtable_total_size_words >= ADAPTER_PCL_MAX_BANK_WORDS)
{
LOG_CRIT("PCL_Init: Too many hashtable lookup elements for bank\n");
goto fail; // exit which frees allocated resources
}
// get DMA-safe memory for hashtable in appropriate bank
{
DMAResource_Properties_t TableProperties;
DMAResource_AddrPair_t TableHostAddr;
DMAResource_AddrPair_t PhysAddr;
int dmares;
// required DMA buffer properties
TableProperties.Alignment = AdapterPCL_DMA_Alignment_ByteCount;
// Hash table DMA bank
TableProperties.Bank = ADAPTER_PCL_BANK_FLOWTABLE;
TableProperties.fCached = false;
// Check if this does not exceed 4 GB, do it somewhere above
// size in bytes
TableProperties.Size = hashtable_total_size_words *
sizeof(uint32_t);
// Perform a full-bank allocation in flow table bank to obtain
// the bank base address.
dmares = DMAResource_Alloc(TableProperties,
&TableHostAddr,
&hashtable_dma_handle);
#ifdef ADAPTER_PCL_ENABLE_SWAP
DMAResource_SwapEndianness_Set(hashtable_dma_handle, true);
#endif
if (dmares != 0)
{
LOG_CRIT("PCL_Init: Failed to allocate flow hash table\n");
goto fail; // exit which frees allocated resources
}
// get physical address from handle
if (DMAResource_Translate(hashtable_dma_handle,
DMARES_DOMAIN_BUS,
&PhysAddr) < 0)
{
LOG_CRIT("PCL_Init: Failed to obtain physical address.\n");
goto fail; // exit which frees allocated resources
}
ZEROINIT(EIP207_FlowAddr);
// physical address as upper and lower (EIP207_Flow_Address_t)
Adapter_AddrToWordPair(PhysAddr.Address_p, 0,
&EIP207_FlowAddr.Addr,
&EIP207_FlowAddr.UpperAddr);
// fill in FLUE hashtable descriptor fields
ZEROINIT(EIP207_HT_Params);
// handle
EIP207_HT_Params.HT_DMA_Handle = hashtable_dma_handle;
// translated addr
EIP207_HT_Params.HT_DMA_Address_p = &EIP207_FlowAddr;
// Convert numerical value to enum
EIP207_HT_Params.HT_TableSize =
AdapterPCLLib_HashTable_Entries_Num_To_Size(
ADAPTER_PCL_FLOW_HASH_ENTRIES_COUNT);
EIP207_HT_Params.DT_p = descr_area_ptr;
// hash table plus overflow
EIP207_HT_Params.DT_EntryCount = total_hasharea_element_count;
}
LOG_INFO("\n\t\t EIP207_Flow_HashTable_Install \n");
// install FLUE hashtable
res = EIP207_Flow_HashTable_Install(ioarea_p,
hashtable_id,
&EIP207_HT_Params,
ADAPTER_PCL_ENABLE_FLUE_CACHE,
true);
if (res != EIP207_FLOW_NO_ERROR)
{
LOG_CRIT("PCL_Init: EIP207_Flow_HashTable_Install failed\n");
goto fail; // exit which frees allocated resources
}
// Initialize the free list of record descriptors
{
unsigned int i;
List_Element_t * Element_p;
unsigned char * RecDscr_p;
unsigned int RecordByteCount = MAX(EIP207_Flow_FR_Dscr_ByteCount_Get(),
EIP207_Flow_TR_Dscr_ByteCount_Get());
// Set the free list ID
Dev_p->FreeListID = ADAPTER_PCL_LIST_ID_OFFSET + InterfaceId;
// Allocate a pool of list elements
ElementPool_p = Adapter_Alloc(sizeof(List_Element_t) *
total_hasharea_element_count);
if (ElementPool_p == NULL)
{
LOG_CRIT("PCL_Init: free list allocation failed\n");
goto fail;
}
if (List_Init(Dev_p->FreeListID, NULL) != LIST_STATUS_OK)
{
LOG_CRIT("PCL_Init: free list initialization failed\n");
goto fail;
}
// Allocate a pool of record descriptors
RecDscrPool_p = Adapter_Alloc( RecordByteCount *
total_hasharea_element_count);
if (RecDscrPool_p == NULL)
{
LOG_CRIT("PCL_Init: record descriptor allocation failed\n");
goto fail;
}
// Populate the free list with the elements (record descriptors)
Element_p = ElementPool_p;
Element_p->DataObject_p = RecDscr_p = RecDscrPool_p;
for(i = 0; i < total_hasharea_element_count; i++)
{
if (List_AddToHead(Dev_p->FreeListID,
NULL,
Element_p) == LIST_STATUS_OK)
{
if (i < total_hasharea_element_count - 1)
{
Element_p++;
RecDscr_p += RecordByteCount;
Element_p->DataObject_p = RecDscr_p;
}
}
else
{
LOG_CRIT("PCL_Init: free list population failed\n");
goto fail;
}
}
Dev_p->RecDscrPool_p = RecDscrPool_p;
Dev_p->ElementPool_p = ElementPool_p;
} // Record descriptors free list initialized
// set remaining instance variables, on success
Dev_p->EIP207_Hashtable_DMA_Handle = hashtable_dma_handle;
Dev_p->PCL_IsInitialized = true;
(void)RPM_DEVICE_INIT_STOP_MACRO(ADAPTER_PCL_RPM_EIP207_DEVICE_ID + InterfaceId);
Adapter_Lock_CS_Leave(&AdapterPCL_CS);
return PCL_STATUS_OK;
fail:
(void)RPM_DEVICE_INIT_STOP_MACRO(ADAPTER_PCL_RPM_EIP207_DEVICE_ID + InterfaceId);
// free List data structures
Adapter_Free(ElementPool_p);
Adapter_Free(RecDscrPool_p);
List_Uninit(Dev_p->FreeListID, NULL);
// free memory areas and DMA-safe memory
Adapter_Free(Dev_p->EIP207_IOArea_p);
Adapter_Free(Dev_p->EIP207_Descriptor_Area_p);
if (hashtable_dma_handle != NULL)
DMAResource_Release(hashtable_dma_handle);
error_exit:
Adapter_Lock_CS_Leave(&AdapterPCL_CS);
return PCL_ERROR;
}
/*----------------------------------------------------------------------------
* PCL_UnInit
*/
PCL_Status_t
PCL_UnInit(
const unsigned int InterfaceId)
{
AdapterPCL_Device_Instance_Data_t * Dev_p;
LOG_INFO("\n\t PCL_UnInit \n");
if (InterfaceId >= ADAPTER_PCL_MAX_FLUE_DEVICES)
{
return PCL_INVALID_PARAMETER;
}
Adapter_Lock_CS_Set(&AdapterPCL_CS, &AdapterPCL_Lock);
if (!Adapter_Lock_CS_Enter(&AdapterPCL_CS))
return PCL_STATUS_BUSY;
// select current device instance data, on validated InterfaceId
Dev_p = &Dev_Instance[InterfaceId];
if (!Dev_p->PCL_IsInitialized)
{
LOG_CRIT("PCL_UnInit: Not initialized\n");
Adapter_Lock_CS_Leave(&AdapterPCL_CS);
return PCL_ERROR;
}
if (!Adapter_Lock_CS_Enter(&Dev_p->AdapterPCL_DevCS))
{
Adapter_Lock_CS_Leave(&Dev_p->AdapterPCL_DevCS);
Adapter_Lock_CS_Leave(&AdapterPCL_CS);
return PCL_STATUS_BUSY;
}
if (RPM_DEVICE_UNINIT_START_MACRO(ADAPTER_PCL_RPM_EIP207_DEVICE_ID + InterfaceId,
false) != RPM_SUCCESS)
{
Adapter_Lock_CS_Leave(&Dev_p->AdapterPCL_DevCS);
Adapter_Lock_CS_Leave(&AdapterPCL_CS);
return PCL_ERROR;
}
// free List data structures
Adapter_Free(Dev_p->ElementPool_p);
Adapter_Free(Dev_p->RecDscrPool_p);
List_Uninit(Dev_p->FreeListID, NULL);
// pool list data structures
Adapter_Free(Dev_p->ListElementPool_p);
Adapter_Free(Dev_p->ListPool_p);
if (Dev_p->List_p)
{
List_Uninit(LIST_DUMMY_LIST_ID, Dev_p->List_p);
Dev_p->List_p = NULL;
}
// free memory areas and DMA-safe memory
Adapter_Free(Dev_p->EIP207_IOArea_p);
Adapter_Free(Dev_p->EIP207_Descriptor_Area_p);
DMAResource_Release(Dev_p->EIP207_Hashtable_DMA_Handle);
// reset globals
Dev_p->EIP207_IOArea_p = NULL;
Dev_p->EIP207_Hashtable_DMA_Handle = NULL;
Dev_p->EIP207_Descriptor_Area_p = NULL;
Dev_p->RecDscrPool_p = NULL;
Dev_p->ElementPool_p = NULL;
Dev_p->PCL_IsInitialized = false;
AdapterPCL_DMA_Alignment_ByteCount = ADAPTER_DMABUF_ALIGNMENT_INVALID;
Adapter_Lock_CS_Leave(&Dev_p->AdapterPCL_DevCS);
// Free device lock
Adapter_Lock_Free(Adapter_Lock_CS_Get(&Dev_p->AdapterPCL_DevCS));
Adapter_Lock_CS_Set(&Dev_p->AdapterPCL_DevCS, Adapter_Lock_NULL);
(void)RPM_DEVICE_UNINIT_STOP_MACRO(ADAPTER_PCL_RPM_EIP207_DEVICE_ID + InterfaceId);
Adapter_Lock_CS_Leave(&AdapterPCL_CS);
return PCL_STATUS_OK;
}
/*-----------------------------------------------------------------------------
* PCL_Flow_DMABuf_Handle_Get
*/
PCL_Status_t
PCL_Flow_DMABuf_Handle_Get(
const PCL_FlowHandle_t FlowHandle,
DMABuf_Handle_t * const DMAHandle_p)
{
DMAResource_Handle_t DMARes_Handle;
EIP207_Flow_FR_Dscr_t * FlowDescriptor_p;
List_Element_t * Element_p = (List_Element_t*)FlowHandle;
LOG_INFO("\n\t PCL_Flow_DMABuf_Handle_Get \n");
if (DMAHandle_p == NULL ||
Element_p == NULL)
{
LOG_CRIT("PCL_Flow_DMABuf_Handle_Get: failed, invalid DMABuf handle or Flow Handle\n");
return PCL_INVALID_PARAMETER;
}
FlowDescriptor_p = (EIP207_Flow_FR_Dscr_t *)Element_p->DataObject_p;
if (FlowDescriptor_p == NULL)
{
LOG_CRIT("PCL_Flow_DMABuf_Handle_Get: failed, invalid flow handle\n");
return PCL_INVALID_PARAMETER;
}
DMARes_Handle = FlowDescriptor_p->DMA_Handle;
*DMAHandle_p = Adapter_DMAResource_Handle2DMABufHandle(DMARes_Handle);
return PCL_STATUS_OK;
}
/*----------------------------------------------------------------------------
* PCL_Flow_Hash
*/
PCL_Status_t
PCL_Flow_Hash(
const PCL_SelectorParams_t * const SelectorParams,
uint32_t * FlowID_Word32ArrayOf4)
{
EIP207_Flow_SelectorParams_t EIP207_SelectorParams;
EIP207_Flow_ID_t FlowID;
EIP207_Flow_Error_t res;
const unsigned int hashtable_id = 0; // implementation limit
LOG_INFO("\n\t PCL_Flow_Hash \n");
if (SelectorParams == NULL || FlowID_Word32ArrayOf4 == NULL)
return PCL_ERROR;
ZEROINIT(EIP207_SelectorParams);
ZEROINIT(FlowID);
EIP207_SelectorParams.Flags = SelectorParams->flags;
EIP207_SelectorParams.SrcIp_p = SelectorParams->SrcIp;
EIP207_SelectorParams.DstIp_p = SelectorParams->DstIp;
EIP207_SelectorParams.IpProto = SelectorParams->IpProto;
EIP207_SelectorParams.SrcPort = SelectorParams->SrcPort;
EIP207_SelectorParams.DstPort = SelectorParams->DstPort;
EIP207_SelectorParams.SPI = SelectorParams->spi;
EIP207_SelectorParams.Epoch = SelectorParams->epoch;
if (RPM_DEVICE_IO_START_MACRO(ADAPTER_PCL_RPM_EIP207_DEVICE_ID,
RPM_FLAG_SYNC) != RPM_SUCCESS)
return PCL_ERROR;
LOG_INFO("\n\t\t EIP207_Flow_ID_Compute \n");
res = EIP207_Flow_ID_Compute(
Dev_Instance[hashtable_id].EIP207_IOArea_p,
hashtable_id,
&EIP207_SelectorParams,
&FlowID);
// Note: only one EIP-207 hash table is supported!
(void)RPM_DEVICE_IO_STOP_MACRO(ADAPTER_PCL_RPM_EIP207_DEVICE_ID,
RPM_FLAG_ASYNC);
if (res != EIP207_FLOW_NO_ERROR)
{
LOG_CRIT("PCL_Flow_Hash: operation failed\n");
return PCL_ERROR;
}
FlowID_Word32ArrayOf4[0] = FlowID.Word32[0];
FlowID_Word32ArrayOf4[1] = FlowID.Word32[1];
FlowID_Word32ArrayOf4[2] = FlowID.Word32[2];
FlowID_Word32ArrayOf4[3] = FlowID.Word32[3];
return PCL_STATUS_OK;
}
/*-----------------------------------------------------------------------------
* PCL_Flow_Alloc
*/
PCL_Status_t
PCL_Flow_Alloc(
const unsigned int InterfaceId,
const unsigned int FlowHashTableId,
PCL_FlowHandle_t * const FlowHandle_p)
{
PCL_Status_t PCL_Rc = PCL_ERROR;
DMAResource_Handle_t DMAHandle;
DMAResource_Properties_t DMAProperties;
DMAResource_AddrPair_t HostAddr;
DMAResource_AddrPair_t PhysAddr;
int dmares;
EIP207_Flow_FR_Dscr_t * FlowDescriptor_p;
unsigned int FR_WordCount;
List_Element_t * Element_p;
AdapterPCL_Device_Instance_Data_t * Dev_p;
LOG_INFO("\n\t PCL_Flow_Alloc \n");
IDENTIFIER_NOT_USED(FlowHashTableId);
// validate interface id
if (InterfaceId >= ADAPTER_PCL_MAX_FLUE_DEVICES)
return PCL_INVALID_PARAMETER;
Dev_p = &Dev_Instance[InterfaceId];
if (Adapter_Lock_CS_Get(&Dev_p->AdapterPCL_DevCS) == Adapter_Lock_NULL)
{
LOG_CRIT("PCL_Flow_Alloc: no device lock, not initialized?\n");
return PCL_ERROR;
}
if (!Adapter_Lock_CS_Enter(&Dev_p->AdapterPCL_DevCS))
return PCL_STATUS_BUSY;
// select current device instance data, on validated InterfaceId
if (!Dev_p->PCL_IsInitialized)
{
LOG_CRIT("PCL_Flow_Alloc: Not initialized\n");
goto error_exit;
}
*FlowHandle_p = NULL;
LOG_INFO("\n\t\t EIP207_Flow_FR_WordCount_Get \n");
// Get the required size of the DMA buffer for the flow record.
FR_WordCount = EIP207_Flow_FR_WordCount_Get();
// Allocate a buffer for the flow record (DMA).
DMAProperties.Alignment = AdapterPCL_DMA_Alignment_ByteCount;
DMAProperties.Bank = ADAPTER_PCL_BANK_FLOW;
DMAProperties.fCached = false;
DMAProperties.Size = 4 * FR_WordCount;
dmares = DMAResource_Alloc(DMAProperties, &HostAddr, &DMAHandle);
if (dmares != 0)
{
LOG_CRIT("PCL_Flow_Alloc: could not allocate buffer\n");
goto error_exit;
}
#ifdef ADAPTER_PCL_ENABLE_SWAP
DMAResource_SwapEndianness_Set(DMAHandle, true);
#endif
// Get a record descriptor from the free list
{
List_Status_t List_Rc =
List_RemoveFromTail(Dev_p->FreeListID,
NULL,
&Element_p);
if (List_Rc != LIST_STATUS_OK)
{
LOG_CRIT("PCL_Flow_Alloc: failed to allocate record\n");
goto error_exit;
}
// Get the flow record descriptor place-holder from the list element
FlowDescriptor_p = (EIP207_Flow_FR_Dscr_t*)Element_p->DataObject_p;
if (FlowDescriptor_p == NULL)
{
LOG_CRIT("PCL_Flow_Alloc: failed to get record descriptor\n");
goto error_exit;
}
}
// Fill in the descriptor.
FlowDescriptor_p->DMA_Handle = DMAHandle;
if (DMAResource_Translate(DMAHandle, DMARES_DOMAIN_BUS, &PhysAddr) < 0)
{
LOG_CRIT("PCL_FlowAlloc: Failed to obtain physical address.\n");
DMAResource_Release(DMAHandle);
goto error_exit;
}
Adapter_AddrToWordPair(PhysAddr.Address_p, 0,
&FlowDescriptor_p->DMA_Addr.Addr,
&FlowDescriptor_p->DMA_Addr.UpperAddr);
*FlowHandle_p = (PCL_FlowHandle_t)Element_p;
PCL_Rc = PCL_STATUS_OK;
error_exit:
Adapter_Lock_CS_Leave(&Dev_p->AdapterPCL_DevCS);
return PCL_Rc;
}
/*-----------------------------------------------------------------------------
* PCL_Flow_Add
*/
PCL_Status_t
PCL_Flow_Add(
const unsigned int InterfaceId,
const unsigned int FlowHashTableId,
const PCL_FlowParams_t * const FlowParams,
const PCL_FlowHandle_t FlowHandle)
{
PCL_Status_t PCL_Rc = PCL_ERROR;
DMAResource_Handle_t DMAHandle;
DMAResource_AddrPair_t PhysAddr;
EIP207_Flow_Error_t res;
EIP207_Flow_FR_InputData_t FlowData;
EIP207_Flow_FR_Dscr_t * FlowDescriptor_p;
List_Element_t * Element_p = (List_Element_t*)FlowHandle;
AdapterPCL_Device_Instance_Data_t * Dev_p;
LOG_INFO("\n\t PCL_Flow_Add \n");
// validate interface id
if (InterfaceId >= ADAPTER_PCL_MAX_FLUE_DEVICES)
return PCL_INVALID_PARAMETER;
// check valid flow handle
if (Element_p == NULL)
return PCL_INVALID_PARAMETER;
FlowDescriptor_p = (EIP207_Flow_FR_Dscr_t *)Element_p->DataObject_p;
// check valid flow record descriptor
if (FlowDescriptor_p == NULL)
return PCL_INVALID_PARAMETER;
Dev_p = &Dev_Instance[InterfaceId];
if (Adapter_Lock_CS_Get(&Dev_p->AdapterPCL_DevCS) == Adapter_Lock_NULL)
{
LOG_CRIT("PCL_Flow_Add: no device lock, not initialized?\n");
return PCL_ERROR;
}
if (!Adapter_Lock_CS_Enter(&Dev_p->AdapterPCL_DevCS))
return PCL_STATUS_BUSY;
// check interface is initialised
if (!Dev_p->PCL_IsInitialized)
{
LOG_CRIT("PCL_Flow_Add: Not initialized\n");
goto error_exit;
}
// Fill in the input data
DMAHandle = Adapter_DMABuf_Handle2DMAResourceHandle(FlowParams->transform);
if (DMAHandle)
{
if (DMAResource_Translate(DMAHandle, DMARES_DOMAIN_BUS, &PhysAddr) < 0)
{
LOG_CRIT("PCL_Flow_Add: Failed to obtain physical address.\n");
goto error_exit;
}
}
else
{
PhysAddr.Domain = DMARES_DOMAIN_BUS;
PhysAddr.Address_p = AdapterPCL_Int_To_Ptr(
EIP207_Flow_Record_Dummy_Addr_Get());
}
FlowData.Flags = FlowParams->flags;
FlowData.HashID.Word32[0] = FlowParams->FlowID[0];
FlowData.HashID.Word32[1] = FlowParams->FlowID[1];
FlowData.HashID.Word32[2] = FlowParams->FlowID[2];
FlowData.HashID.Word32[3] = FlowParams->FlowID[3];
FlowData.SW_FR_Reference = FlowParams->FlowIndex;
Adapter_AddrToWordPair(PhysAddr.Address_p,0,
&FlowData.Xform_DMA_Addr.Addr,
&FlowData.Xform_DMA_Addr.UpperAddr);
FlowData.fLarge = false;
#ifndef ADAPTER_PCL_USE_LARGE_TRANSFORM_DISABLE
/* Determine whether we have a large transform record. */
if (DMAHandle)
{
DMAResource_Record_t * Rec_p = DMAResource_Handle2RecordPtr(DMAHandle);
if (Rec_p->fIsLargeTransform)
FlowData.fLarge = true;
}
#endif // !ADAPTER_PCL_USE_LARGE_TRANSFORM_DISABLE
LOG_INFO("\n\t\t EIP207_Flow_FR_Add \n");
// Add the record
res = EIP207_Flow_FR_Add(Dev_p->EIP207_IOArea_p,
FlowHashTableId,
FlowDescriptor_p,
&FlowData);
if (res == EIP207_FLOW_OUT_OF_MEMORY_ERROR)
{
LOG_CRIT("PCL_FLow_Add: failed to install flow, out of memory\n");
}
else if (res == EIP207_FLOW_NO_ERROR)
{
PCL_Rc = PCL_STATUS_OK;
}
else
{
LOG_CRIT("PCL_FLow_Add: failed to install flow, internal error\n");
}
error_exit:
Adapter_Lock_CS_Leave(&Dev_p->AdapterPCL_DevCS);
return PCL_Rc;
}
/*-----------------------------------------------------------------------------
* PCL_Flow_Release
*/
PCL_Status_t
PCL_Flow_Release(
const unsigned int InterfaceId,
const unsigned int FlowHashTableId,
const PCL_FlowHandle_t FlowHandle)
{
PCL_Status_t PCL_Rc = PCL_ERROR;
EIP207_Flow_FR_Dscr_t * FlowDescriptor_p;
List_Element_t * Element_p = (List_Element_t*)FlowHandle;
AdapterPCL_Device_Instance_Data_t * Dev_p;
LOG_INFO("\n\t PCL_Flow_Release \n");
IDENTIFIER_NOT_USED(InterfaceId);
IDENTIFIER_NOT_USED(FlowHashTableId);
IDENTIFIER_NOT_USED(FlowHandle);
// check valid flow handle
if (Element_p == NULL)
return PCL_INVALID_PARAMETER;
FlowDescriptor_p = (EIP207_Flow_FR_Dscr_t *)Element_p->DataObject_p;
// check valid flow record descriptor
if (FlowDescriptor_p == NULL)
return PCL_INVALID_PARAMETER;
Dev_p = &Dev_Instance[InterfaceId];
if (Adapter_Lock_CS_Get(&Dev_p->AdapterPCL_DevCS) == Adapter_Lock_NULL)
{
LOG_CRIT("PCL_Flow_Release: no device lock, not initialized?\n");
return PCL_ERROR;
}
if (!Adapter_Lock_CS_Enter(&Dev_p->AdapterPCL_DevCS))
return PCL_STATUS_BUSY;
// check interface is initialised
if (!Dev_p->PCL_IsInitialized)
{
LOG_CRIT("PCL_Flow_Release: Not initialized\n");
goto error_exit;
}
DMAResource_Release(FlowDescriptor_p->DMA_Handle);
// Put the record descriptor back on the free list
{
List_Status_t List_Rc;
List_Rc = List_AddToHead(Dev_p->FreeListID,
NULL,
Element_p);
if (List_Rc != LIST_STATUS_OK)
{
LOG_CRIT("PCL_Flow_Release: "
"failed to put descriptor on the free list\n");
goto error_exit;
}
}
PCL_Rc = PCL_STATUS_OK;
error_exit:
Adapter_Lock_CS_Leave(&Dev_p->AdapterPCL_DevCS);
return PCL_Rc;
}
/*-----------------------------------------------------------------------------
* PCL_Flow_Get_ReadOnly
*/
PCL_Status_t
PCL_Flow_Get_ReadOnly(
const PCL_FlowHandle_t FlowHandle,
PCL_FlowParams_t * const FlowParams_p)
{
EIP207_Flow_FR_Dscr_t * FlowDescriptor_p;
EIP207_Flow_FR_OutputData_t FlowData;
EIP207_Flow_Error_t res;
List_Element_t * Element_p = (List_Element_t*)FlowHandle;
LOG_INFO("\n\t PCL_Flow_Get_ReadOnly \n");
// check valid flow handle
if (Element_p == NULL)
return PCL_INVALID_PARAMETER;
FlowDescriptor_p = (EIP207_Flow_FR_Dscr_t *)Element_p->DataObject_p;
// check valid flow record descriptor
if (FlowDescriptor_p == NULL)
return PCL_INVALID_PARAMETER;
LOG_INFO("\n\t\t EIP207_Flow_FR_Read \n");
res = EIP207_Flow_FR_Read(Dev_Instance[0].EIP207_IOArea_p,
0,
FlowDescriptor_p,
&FlowData);
if (res == EIP207_FLOW_ARGUMENT_ERROR)
{
return PCL_INVALID_PARAMETER;
}
else if (res != EIP207_FLOW_NO_ERROR)
{
return PCL_ERROR;
}
FlowParams_p->LastTimeLo = FlowData.LastTimeLo;
FlowParams_p->LastTimeHi = FlowData.LastTimeHi;
FlowParams_p->PacketsCounterLo = FlowData.PacketsCounter;
FlowParams_p->PacketsCounterHi = 0;
FlowParams_p->OctetsCounterLo = FlowData.OctetsCounterLo;
FlowParams_p->OctetsCounterHi = FlowData.OctetsCounterHi;
return PCL_STATUS_OK;
}
/* end of file adapter_pcl_generic.c */