| /* eip207_flow_dtl.c |
| * |
| * Partial EIP-207 Flow Control Generic API implementation and |
| * full EIP-207 Flow Control DTL API implementation |
| */ |
| |
| /* -------------------------------------------------------------------------- */ |
| /* */ |
| /* Module : ddk197 */ |
| /* Version : 5.6.1 */ |
| /* Configuration : DDK-197-GPL */ |
| /* */ |
| /* Date : 2022-Dec-16 */ |
| /* */ |
| /* 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): |
| */ |
| |
| // EIP-207 Driver Library Flow Control Generic API |
| #include "eip207_flow_dtl.h" |
| |
| // EIP-207 Driver Library Flow Control Generic API |
| #include "eip207_flow_generic.h" |
| |
| |
| /*---------------------------------------------------------------------------- |
| * This module uses (requires) the following interface(s): |
| */ |
| |
| // Default configuration |
| #include "c_eip207_flow.h" |
| |
| // Driver Framework Basic Definitions API |
| #include "basic_defs.h" // uint32_t |
| |
| // Driver Framework C Run-time Library API |
| #include "clib.h" // ZEROINIT, memset, memcpy |
| |
| // Driver Framework Device API |
| #include "device_types.h" // Device_Handle_t |
| |
| // Driver Framework DMA Resource API |
| #include "dmares_types.h" |
| #include "dmares_rw.h" |
| |
| // EIP-207 Flow Control Driver Library Internal interfaces |
| #include "eip207_flow_level0.h" // EIP-207 Level 0 macros |
| #include "eip207_flow_hte_dscr_dtl.h" // HTE descriptor DTL |
| #include "eip207_flow_internal.h" |
| |
| #ifndef EIP207_FLUE_RC_HP |
| // EIP-207 (Global Control) Record Cache (RC) interface |
| #include "eip207_rc.h" |
| |
| // EIP-207s (Global Control) Flow Look-Up Engine Cache (FLUEC) interface |
| #include "eip207_fluec.h" |
| #endif // !EIP207_FLUE_RC_HP |
| |
| // EIP-207 Firmware API |
| #include "firmware_eip207_api_flow_cs.h" // Classification API: Flow Control |
| #include "firmware_eip207_api_cs.h" // Classification API: General |
| |
| |
| /*---------------------------------------------------------------------------- |
| * Definitions and macros |
| */ |
| |
| #define EIP207_FLOW_MAX_RECORDS_PER_BUCKET 3 |
| |
| |
| // Flow record input data required for the flow record creation |
| typedef struct |
| { |
| // Bitwise of zero or more EIP207_FLOW_FLAG_* flags, see above |
| uint32_t Flags; |
| |
| // Physical (DMA/bus) address of the transform record |
| EIP207_Flow_Address_t Xform_DMA_Addr; |
| |
| // Software flow record reference |
| uint32_t SW_FR_Reference; |
| |
| // Transform record type, true - large, false - small |
| bool fLarge; |
| } EIP207_Flow_FR_Data_t; |
| |
| // Transform record input data required for the transform record creation |
| typedef struct |
| { |
| // Transform record type, true - large, false - small |
| bool fLarge; |
| |
| } EIP207_Flow_TR_Data_t; |
| |
| // Transform record input data required for the Transform record creation |
| typedef struct |
| { |
| // Record hash ID |
| const EIP207_Flow_ID_t * HashID_p; |
| |
| // Flow record input data, fill with NULL if not used |
| const EIP207_Flow_FR_Data_t * FR_Data_p; |
| |
| // Transform record input data, fill with NULL if not used |
| const EIP207_Flow_TR_Data_t * TR_Data_p; |
| |
| // Note: FR_Data_p and TR_Data_p cannot be both NULL! |
| |
| } EIP207_Flow_Record_InputData_t; |
| |
| // Full record descriptor |
| typedef struct |
| { |
| EIP207_Flow_Dscr_t RecDscr; |
| |
| EIP207_Flow_HTE_Dscr_RecData_t RecData; |
| |
| void * Reserved_p; |
| } EIP207_Flow_Rec_Dscr_t; |
| |
| |
| /*---------------------------------------------------------------------------- |
| * Local variables |
| */ |
| |
| |
| /*---------------------------------------------------------------------------- |
| * EIP207Lib_Flow_Entry_Lookup |
| */ |
| static void |
| EIP207Lib_Flow_Entry_Lookup( |
| const uint32_t HashID_Word0, |
| const uint32_t TableSize, |
| unsigned int * const HT_Entry_ByteOffset, |
| unsigned int * const DT_Entry_Index) |
| { |
| uint32_t HashID_W0, Mask; |
| |
| // From the EIP-197 Programmer Manual: |
| // The hash engine completes the hash ID calculation and |
| // adds bits [(table_size+10):6] (with table_size coming from |
| // the FLUE_SIZE(_VM)_f register) of the hash ID, multiplied by 64, |
| // to the table base address given in the FLUE_HASHBASE(_VM)_f_* registers. |
| |
| // Calculate the entry byte offset in the HT for this record |
| HashID_W0 = (HashID_Word0 & (~MASK_6_BITS)); |
| |
| Mask = (1 << (TableSize + 10 + 1)) - 1; |
| |
| // Calculate the HT entry byte offset |
| *HT_Entry_ByteOffset = (unsigned int)(HashID_W0 & Mask); |
| |
| // Translate the HT entry byte offset to the index in the HT |
| // HT entry size is one hash bucket (16 words = 64 bytes) |
| *DT_Entry_Index = (*HT_Entry_ByteOffset) >> 6; // divide by 64 |
| } |
| |
| |
| /*---------------------------------------------------------------------------- |
| * EIP207Lib_Flow_TableSize_To_EntryCount |
| * |
| * Convert EIP207_Flow_HashTable_Entry_Count_t to a number |
| */ |
| static inline unsigned int |
| EIP207Lib_Flow_TableSize_To_EntryCount( |
| const unsigned int TableSize) |
| { |
| return (1 << (TableSize + 5)); |
| } |
| |
| |
| /*---------------------------------------------------------------------------- |
| * EIP207Lib_Flow_HTE_Dscr_ByteCount_Get |
| */ |
| static inline unsigned int |
| EIP207Lib_Flow_HTE_Dscr_ByteCount_Get(void) |
| { |
| return sizeof(EIP207_Flow_HTE_Dscr_t); |
| } |
| |
| |
| /*---------------------------------------------------------------------------- |
| * EIP207Lib_Flow_HB_Record_Add |
| * |
| * Updates Hash ID and record offset in the hash bucket, |
| * first Hash ID then record byte offset |
| */ |
| static inline void |
| EIP207Lib_Flow_HB_Record_Add( |
| const DMAResource_Handle_t HT_DMA_Handle, |
| const unsigned int HB_ByteOffset, |
| const unsigned int slot, |
| const uint32_t Rec_ByteOffset, |
| const uint32_t RecType, |
| const EIP207_Flow_ID_t * const HashID_p) |
| { |
| unsigned int i; |
| unsigned int HB_WordOffset = HB_ByteOffset >> 2; |
| |
| // Write record Hash ID words |
| for (i = 0; i < EIP207_FLOW_HASH_ID_WORD_COUNT; i++) |
| DMAResource_Write32(HT_DMA_Handle, |
| HB_WordOffset + |
| EIP207_FLOW_HB_HASH_ID_1_WORD_OFFSET + i + |
| EIP207_FLOW_HASH_ID_WORD_COUNT * (slot - 1), |
| HashID_p->Word32[i]); |
| |
| // Write record offset |
| DMAResource_Write32(HT_DMA_Handle, |
| HB_WordOffset + |
| EIP207_FLOW_HB_REC_1_WORD_OFFSET + (slot - 1), |
| Rec_ByteOffset | RecType); |
| |
| // Perform pre-DMA for this hash bucket |
| DMAResource_PreDMA(HT_DMA_Handle, |
| HB_ByteOffset, |
| EIP207_FLOW_HT_ENTRY_WORD_COUNT * |
| sizeof(uint32_t)); |
| } |
| |
| |
| /*---------------------------------------------------------------------------- |
| * EIP207Lib_Flow_HB_Record_Remove |
| * |
| * Updates Hash ID and record offset in the hash bucket, |
| * first record byte offset then Hash ID |
| */ |
| static inline void |
| EIP207Lib_Flow_HB_Record_Remove( |
| const DMAResource_Handle_t HT_DMA_Handle, |
| const unsigned int HB_ByteOffset, |
| const unsigned int slot, |
| EIP207_Flow_ID_t * HashID_p) |
| { |
| unsigned int i; |
| unsigned int HB_WordOffset = HB_ByteOffset >> 2; |
| EIP207_Flow_ID_t HashID; |
| |
| // Write record offset |
| DMAResource_Write32(HT_DMA_Handle, |
| HB_WordOffset + |
| EIP207_FLOW_HB_REC_1_WORD_OFFSET + (slot - 1), |
| EIP207_FLOW_RECORD_DUMMY_ADDRESS); |
| |
| // Read old record Hash ID words |
| for (i = 0; i < EIP207_FLOW_HASH_ID_WORD_COUNT; i++) |
| HashID.Word32[i] = DMAResource_Read32( |
| HT_DMA_Handle, |
| HB_WordOffset + |
| EIP207_FLOW_HB_HASH_ID_1_WORD_OFFSET + i + |
| EIP207_FLOW_HASH_ID_WORD_COUNT * (slot - 1)); |
| |
| // Write new record Hash ID words |
| for (i = 0; i < EIP207_FLOW_HASH_ID_WORD_COUNT; i++) |
| { |
| DMAResource_Write32(HT_DMA_Handle, |
| HB_WordOffset + |
| EIP207_FLOW_HB_HASH_ID_1_WORD_OFFSET + i + |
| EIP207_FLOW_HASH_ID_WORD_COUNT * (slot - 1), |
| HashID_p->Word32[i]); |
| |
| // Store old record Hash ID words |
| HashID_p->Word32[i] = HashID.Word32[i]; |
| } |
| |
| // Perform pre-DMA for this hash bucket |
| DMAResource_PreDMA(HT_DMA_Handle, |
| HB_ByteOffset, |
| EIP207_FLOW_HT_ENTRY_WORD_COUNT * |
| sizeof(uint32_t)); |
| } |
| |
| |
| /*---------------------------------------------------------------------------- |
| * EIP207Lib_Flow_HB_BuckOffs_Update |
| * |
| * Update bucket offset in the hash bucket (identified by HB_ByteOffset) |
| * by writing the Update_Value in there |
| */ |
| static inline void |
| EIP207Lib_Flow_HB_BuckOffs_Update( |
| const DMAResource_Handle_t HT_DMA_Handle, |
| const unsigned int HB_ByteOffset, |
| const uint32_t Update_Value) |
| { |
| unsigned int HB_WordOffset = HB_ByteOffset >> 2; |
| |
| // Write record offset |
| DMAResource_Write32(HT_DMA_Handle, |
| HB_WordOffset + |
| EIP207_FLOW_HB_OVFL_BUCKET_WORD_OFFSET, |
| Update_Value); |
| |
| // Perform pre-DMA for this hash bucket |
| DMAResource_PreDMA(HT_DMA_Handle, |
| HB_ByteOffset, |
| EIP207_FLOW_HT_ENTRY_WORD_COUNT * |
| sizeof(uint32_t)); |
| } |
| |
| |
| #ifdef EIP207_FLOW_CONSISTENCY_CHECK |
| /*---------------------------------------------------------------------------- |
| * EIP207Lib_Flow_HB_HashID_Match |
| * |
| * Checks if the hash bucket already contains this Hash ID |
| */ |
| static bool |
| EIP207Lib_Flow_HB_HashID_Match( |
| const DMAResource_Handle_t HT_DMA_Handle, |
| const unsigned int HB_ByteOffset, |
| const uint32_t RecType, |
| const EIP207_Flow_ID_t * const HashID_p) |
| { |
| uint32_t Word32; |
| bool fMatch; |
| unsigned int i, j; |
| unsigned int HB_WordOffset = HB_ByteOffset >> 2; |
| |
| // Read Hash ID's from the bucket |
| // (this DMA resource is read-only for the FLUE device) |
| for (i = 0; i < EIP207_FLOW_HTE_BKT_NOF_REC_MAX; i++) |
| { |
| for (j = 0; j < EIP207_FLOW_HASH_ID_WORD_COUNT; j++) |
| { |
| fMatch = true; |
| |
| Word32 = DMAResource_Read32( |
| HT_DMA_Handle, |
| HB_WordOffset + |
| EIP207_FLOW_HB_HASH_ID_1_WORD_OFFSET + |
| i * EIP207_FLOW_HASH_ID_WORD_COUNT + j); |
| |
| if (Word32 != HashID_p->Word32[j]) |
| { |
| fMatch = false; |
| break; // No match, skip this hash ID |
| } |
| } // for |
| |
| if (fMatch) |
| break; // Matching Hash ID found, stop searching |
| } // for |
| |
| if (fMatch) |
| { |
| uint32_t Match_RecType; |
| |
| // Check the record type in the record offset for Hash ID with index i |
| // to confirm the match |
| Word32 = DMAResource_Read32( |
| HT_DMA_Handle, |
| HB_WordOffset + |
| EIP207_FLOW_HB_REC_1_WORD_OFFSET + i); |
| |
| // Note: small transform record and large transform record |
| // fall under the same record type for this check! |
| Match_RecType = Word32 & RecType; |
| |
| if ((Match_RecType == EIP207_FLOW_RECORD_FR_ADDRESS && |
| (RecType == EIP207_FLOW_RECORD_TR_ADDRESS || |
| RecType == EIP207_FLOW_RECORD_TR_LARGE_ADDRESS)) || |
| |
| (RecType == EIP207_FLOW_RECORD_FR_ADDRESS && |
| (Match_RecType == EIP207_FLOW_RECORD_TR_ADDRESS || |
| Match_RecType == EIP207_FLOW_RECORD_TR_LARGE_ADDRESS))) |
| { |
| // Match not confirmed, a different record type is used |
| fMatch = false; |
| } |
| } |
| |
| return fMatch; |
| } |
| #endif // EIP207_FLOW_CONSISTENCY_CHECK |
| |
| |
| /*---------------------------------------------------------------------------- |
| * EIP207Lib_Flow_HB_Slot_Get |
| * |
| * Determine the free offset slot number (1,2 or 3) and claim it |
| */ |
| static inline EIP207_Flow_Error_t |
| EIP207Lib_Flow_HB_Slot_Get( |
| uint32_t * const RecOffsMask_p, |
| unsigned int * FreeSlot_p) |
| { |
| if ((*RecOffsMask_p & EIP207_FLOW_HTE_REC_OFFSET_1) == 0) |
| { |
| *FreeSlot_p = 1; |
| *RecOffsMask_p |= EIP207_FLOW_HTE_REC_OFFSET_1; |
| } |
| else if((*RecOffsMask_p & EIP207_FLOW_HTE_REC_OFFSET_2) == 0) |
| { |
| *FreeSlot_p = 2; |
| *RecOffsMask_p |= EIP207_FLOW_HTE_REC_OFFSET_2; |
| } |
| else if((*RecOffsMask_p & EIP207_FLOW_HTE_REC_OFFSET_3) == 0) |
| { |
| *FreeSlot_p = 3; |
| *RecOffsMask_p |= EIP207_FLOW_HTE_REC_OFFSET_3; |
| } |
| else |
| // Consistency checks for the found HTE descriptor |
| return EIP207_FLOW_INTERNAL_ERROR; |
| |
| return EIP207_FLOW_NO_ERROR; |
| } |
| |
| |
| /*---------------------------------------------------------------------------- |
| * EIP207Lib_Flow_HB_Slot_Put |
| * |
| * Determine the used offset slot number (1,2 or 3) and release it |
| */ |
| static inline EIP207_Flow_Error_t |
| EIP207Lib_Flow_HB_Slot_Put( |
| uint32_t * const RecOffsMask_p, |
| const unsigned int Slot) |
| { |
| switch (Slot) |
| { |
| case 1: |
| *RecOffsMask_p &= ~EIP207_FLOW_HTE_REC_OFFSET_1; |
| break; |
| |
| case 2: |
| *RecOffsMask_p &= ~EIP207_FLOW_HTE_REC_OFFSET_2; |
| break; |
| |
| case 3: |
| *RecOffsMask_p &= ~EIP207_FLOW_HTE_REC_OFFSET_3; |
| break; |
| |
| default: |
| // Consistency checks for the slot to release |
| return EIP207_FLOW_INTERNAL_ERROR; |
| } |
| |
| return EIP207_FLOW_NO_ERROR; |
| } |
| |
| |
| /*---------------------------------------------------------------------------- |
| * EIP207Lib_Flow_Dscr_InternalData_Set |
| */ |
| static inline void |
| EIP207Lib_Flow_Dscr_InternalData_Set( |
| EIP207_Flow_Dscr_t * const Dscr_p) |
| { |
| EIP207_Flow_Rec_Dscr_t * p = (EIP207_Flow_Rec_Dscr_t*)Dscr_p; |
| |
| Dscr_p->InternalData_p = &p->RecData; |
| } |
| |
| |
| /*---------------------------------------------------------------------------- |
| * EIP207Lib_Flow_FR_Write |
| */ |
| static void |
| EIP207Lib_Flow_FR_Write( |
| const DMAResource_Handle_t DMA_Handle, |
| const EIP207_Flow_FR_Data_t * const FR_Data_p, |
| const uint32_t Xform_ByteOffset, |
| const uint32_t Xform_Addr, |
| const uint32_t Xform_UpperAddr) |
| { |
| unsigned int i; |
| uint32_t Record_Type; |
| |
| // Write flow record with 0's |
| for (i = 0; i < FIRMWARE_EIP207_CS_FRC_RECORD_WORD_COUNT; i++) |
| DMAResource_Write32(DMA_Handle, i, 0); |
| |
| #ifdef EIP207_FLOW_NO_TYPE_BITS_IN_FLOW_RECORD |
| Record_Type = 0; |
| #else |
| Record_Type = FR_Data_p->fLarge ? |
| EIP207_FLOW_RECORD_TR_LARGE_ADDRESS : |
| EIP207_FLOW_RECORD_TR_ADDRESS; |
| #endif |
| |
| // Write Transform Record 32-bit offset |
| DMAResource_Write32(DMA_Handle, |
| FIRMWARE_EIP207_CS_FLOW_FR_XFORM_OFFS_WORD_OFFSET, |
| Xform_ByteOffset + Record_Type); |
| |
| // Write Transform Record low half of 64-bit address |
| DMAResource_Write32(DMA_Handle, |
| FIRMWARE_EIP207_CS_FLOW_FR_XFORM_ADDR_WORD_OFFSET, |
| Xform_Addr + Record_Type); |
| |
| // Write Transform Record high half of 64-bit address |
| DMAResource_Write32(DMA_Handle, |
| FIRMWARE_EIP207_CS_FLOW_FR_XFORM_ADDR_HI_WORD_OFFSET, |
| Xform_UpperAddr); |
| |
| // Not supported yet |
| // Write ARC4 State Record physical address |
| //DMAResource_Write32(FR_Dscr_p->Data.DMA_Handle, |
| // FIRMWARE_EIP207_CS_FLOW_FR_ARC4_ADDR_WORD_OFFSET, |
| // EIP207_FLOW_RECORD_DUMMY_ADDRESS); |
| |
| // Write Software Flow Record Reference |
| // NOTE: this is a 32-bit value! |
| DMAResource_Write32(DMA_Handle, |
| FIRMWARE_EIP207_CS_FLOW_FR_SW_ADDR_WORD_OFFSET, |
| FR_Data_p->SW_FR_Reference); |
| |
| // Write the Flags field |
| DMAResource_Write32(DMA_Handle, |
| FIRMWARE_EIP207_CS_FLOW_FR_FLAGS_WORD_OFFSET, |
| FR_Data_p->Flags); |
| |
| // Perform pre-DMA for the entire flow record |
| DMAResource_PreDMA(DMA_Handle, 0, 0); |
| } |
| |
| |
| /*---------------------------------------------------------------------------- |
| * EIP207Lib_Flow_DTL_Record_Add |
| */ |
| static EIP207_Flow_Error_t |
| EIP207Lib_Flow_DTL_Record_Add( |
| volatile EIP207_Flow_HT_Params_t * const HT_Params_p, |
| EIP207_Flow_Dscr_t * const Rec_Dscr_p, |
| const EIP207_Flow_Record_InputData_t * const RecData_p) |
| { |
| uint32_t Rec_ByteOffset; |
| unsigned int slot = 0; |
| EIP207_Flow_HTE_Dscr_t * HTE_Dscr_Updated_p = NULL; |
| |
| #ifdef EIP207_FLOW_CONSISTENCY_CHECK |
| // Consistency check for the provided record descriptor |
| if (Rec_Dscr_p->DMA_Addr.Addr == EIP207_FLOW_RECORD_DUMMY_ADDRESS) |
| return EIP207_FLOW_INTERNAL_ERROR; |
| #endif // EIP207_FLOW_CONSISTENCY_CHECK |
| |
| // Add the record to the Hash Table |
| { |
| EIP207_Flow_HTE_Dscr_t * HTE_Dscr_p; |
| unsigned int Entry_Index, HTE_ByteOffset, HT_TableSize; |
| uint32_t Record_Type = EIP207_FLOW_RECORD_DUMMY_ADDRESS; |
| DMAResource_Handle_t HT_DMA_Handle = HT_Params_p->HT_DMA_Handle; |
| |
| // Transform record |
| if (RecData_p->TR_Data_p != NULL) |
| Record_Type = RecData_p->TR_Data_p->fLarge ? |
| EIP207_FLOW_RECORD_TR_LARGE_ADDRESS : |
| EIP207_FLOW_RECORD_TR_ADDRESS; |
| // Flow record |
| else if (RecData_p->FR_Data_p != NULL) |
| Record_Type = EIP207_FLOW_RECORD_FR_ADDRESS; |
| else |
| return EIP207_FLOW_INTERNAL_ERROR; // Unknown record, error |
| |
| HT_TableSize = HT_Params_p->HT_TableSize; |
| |
| HTE_ByteOffset = 0; |
| Entry_Index = 0; |
| |
| EIP207Lib_Flow_Entry_Lookup( |
| RecData_p->HashID_p->Word32[0], // Word 0 is used for lookup |
| HT_TableSize, |
| &HTE_ByteOffset, |
| &Entry_Index); |
| |
| #ifdef EIP207_FLOW_CONSISTENCY_CHECK |
| { |
| unsigned int HT_EntryCount = |
| EIP207Lib_Flow_TableSize_To_EntryCount(HT_TableSize); |
| |
| if (Entry_Index >= HT_EntryCount) |
| return EIP207_FLOW_INTERNAL_ERROR; |
| } |
| #endif |
| |
| // Calculate the record byte offset, |
| // HT_Params_p->BaseAddr.Addr is the base |
| // address of the DMA bank where the record |
| // must have been allocated |
| Rec_ByteOffset = Rec_Dscr_p->DMA_Addr.Addr - HT_Params_p->BaseAddr.Addr; |
| |
| // Convert the DT entry index to the HTE descriptor pointer |
| { |
| void * p; |
| unsigned char * DT_p = (unsigned char*)HT_Params_p->DT_p; |
| |
| // Read the entry value at the calculated offset from the DT |
| p = DT_p + Entry_Index * EIP207Lib_Flow_HTE_Dscr_ByteCount_Get(); |
| |
| HTE_Dscr_p = (EIP207_Flow_HTE_Dscr_t*)p; |
| } |
| |
| #ifdef EIP207_FLOW_CONSISTENCY_CHECK |
| // Consistency checks for the found HTE descriptor |
| if (HTE_Dscr_p->Bucket_ByteOffset != (uint32_t)HTE_ByteOffset) |
| return EIP207_FLOW_INTERNAL_ERROR; |
| |
| // Check that this HTE is not an overflow one |
| if (HTE_Dscr_p->fOverflowBucket) |
| return EIP207_FLOW_INTERNAL_ERROR; |
| #endif // EIP207_FLOW_CONSISTENCY_CHECK |
| |
| do // Walk the bucket chain, look for bucket where record can be added |
| { |
| #ifdef EIP207_FLOW_CONSISTENCY_CHECK |
| if (HTE_Dscr_p->RecordCount > EIP207_FLOW_MAX_RECORDS_PER_BUCKET) |
| return EIP207_FLOW_INTERNAL_ERROR; |
| |
| // Check if the hash bucket does not contain this Hash ID already |
| if (HTE_Dscr_Updated_p == NULL && EIP207Lib_Flow_HB_HashID_Match( |
| HT_DMA_Handle, |
| HTE_Dscr_p->Bucket_ByteOffset, |
| Record_Type, |
| RecData_p->HashID_p)) |
| return EIP207_FLOW_INTERNAL_ERROR; |
| #endif // EIP207_FLOW_CONSISTENCY_CHECK |
| |
| // Check if the found hash bucket can be used to add |
| // the record or a next bucket in the chain must be used |
| if (HTE_Dscr_p->RecordCount < EIP207_FLOW_MAX_RECORDS_PER_BUCKET) |
| { |
| uint32_t TempMask = HTE_Dscr_p->UsedRecOffsMask; |
| uint32_t TempSlot = slot; |
| |
| // Use the found bucket to add the record |
| |
| // Determine the offset slot (1,2 or 3) where the record offset |
| // and Hash ID can be stored |
| { |
| EIP207_Flow_Error_t Flow_Rc = |
| EIP207Lib_Flow_HB_Slot_Get( |
| &TempMask, |
| &TempSlot); |
| |
| if(Flow_Rc != EIP207_FLOW_NO_ERROR) |
| return Flow_Rc; |
| } |
| |
| #ifdef EIP207_FLOW_CONSISTENCY_CHECK |
| // Check if the record offset in the HTE slot is a dummy pointer |
| { |
| // Read record offset |
| // (this DMA resource is read-only for the FLUE device) |
| uint32_t Record_ByteOffset = |
| DMAResource_Read32( |
| HT_DMA_Handle, |
| (HTE_Dscr_p->Bucket_ByteOffset >> 2) + |
| EIP207_FLOW_HB_REC_1_WORD_OFFSET + |
| (TempSlot - 1)); |
| |
| if ((Record_ByteOffset & |
| EIP207_FLOW_RECORD_ADDRESS_TYPE_BITS) != |
| EIP207_FLOW_RECORD_DUMMY_ADDRESS) |
| return EIP207_FLOW_INTERNAL_ERROR; |
| } |
| #endif // EIP207_FLOW_CONSISTENCY_CHECK |
| |
| // Add the record only if it has not been done already |
| if (HTE_Dscr_Updated_p == NULL) |
| { |
| HTE_Dscr_p->UsedRecOffsMask = TempMask; |
| slot = TempSlot; |
| |
| // If flow record is added then write it |
| if (RecData_p->FR_Data_p != NULL) |
| EIP207Lib_Flow_FR_Write( |
| Rec_Dscr_p->DMA_Handle, |
| RecData_p->FR_Data_p, |
| RecData_p->FR_Data_p->Xform_DMA_Addr.Addr - |
| HT_Params_p->BaseAddr.Addr, |
| RecData_p->FR_Data_p->Xform_DMA_Addr.Addr, |
| RecData_p->FR_Data_p->Xform_DMA_Addr.UpperAddr); |
| |
| // Update the found hash bucket with the |
| // record Hash ID and offset |
| |
| // CDS point: after this operation is done the FLUE |
| // hardware can find the transform record! |
| EIP207Lib_Flow_HB_Record_Add(HT_DMA_Handle, |
| HTE_Dscr_p->Bucket_ByteOffset, |
| slot, |
| Rec_ByteOffset, |
| Record_Type, |
| RecData_p->HashID_p); |
| |
| // Increase the HTE descriptor record count |
| // for the added record |
| HTE_Dscr_p->RecordCount++; |
| } |
| |
| // The found HTE is updated, record is added |
| if (HTE_Dscr_Updated_p == NULL) |
| HTE_Dscr_Updated_p = HTE_Dscr_p; |
| |
| #ifdef EIP207_FLOW_CONSISTENCY_CHECK |
| // Get the next HTE descriptor in the chain |
| HTE_Dscr_p = EIP207_Flow_HTE_Dscr_List_Next_Get(HTE_Dscr_p); |
| continue; // Validate the entire chain |
| #else |
| break; |
| #endif |
| } |
| else // Found bucket record count is max possible |
| { |
| EIP207_Flow_HTE_Dscr_t * HTE_Dscr_Next_p; |
| |
| // Use a next overflow bucket to add the record, find a bucket |
| // in the chain with a free slot for the new record |
| |
| // Get the next HTE descriptor in the chain |
| HTE_Dscr_Next_p = |
| EIP207_Flow_HTE_Dscr_List_Next_Get(HTE_Dscr_p); |
| |
| // Check if we have one and |
| // that the record has not been added already |
| if (HTE_Dscr_Next_p == NULL && HTE_Dscr_Updated_p == NULL) |
| { |
| // No chain is present for HTE_Dscr_p. |
| // Link a new HTE descriptor from the free list to |
| // the found HTE descriptor |
| |
| EIP207_Flow_HTE_Dscr_t * FreeList_Head_p; |
| |
| #ifdef EIP207_FLOW_CONSISTENCY_CHECK |
| // Check if the overflow bucket offset is a dummy pointer |
| { |
| // Read the overflow bucket offset |
| // (this DMA resource is read-only for the FLUE device) |
| uint32_t Bucket_ByteOffset = |
| DMAResource_Read32( |
| HT_DMA_Handle, |
| (HTE_Dscr_p->Bucket_ByteOffset >> 2) + |
| EIP207_FLOW_HB_OVFL_BUCKET_WORD_OFFSET); |
| |
| if (Bucket_ByteOffset != |
| EIP207_FLOW_RECORD_DUMMY_ADDRESS) |
| return EIP207_FLOW_INTERNAL_ERROR; |
| } |
| #endif // EIP207_FLOW_CONSISTENCY_CHECK |
| |
| FreeList_Head_p = |
| (EIP207_Flow_HTE_Dscr_t*)HT_Params_p->FreeList_Head_p; |
| |
| // Check if the record can be added |
| if (FreeList_Head_p == NULL) |
| // Out of descriptors for overflow buckets |
| return EIP207_FLOW_OUT_OF_MEMORY_ERROR; |
| |
| slot = 1; // start with slot 1 in the new bucket |
| |
| // Get a free HTE descriptor from the free list head |
| HTE_Dscr_Next_p = |
| EIP207_Flow_HTE_Dscr_List_Next_Get(FreeList_Head_p); |
| |
| // Check if the last descriptor is present in the free list |
| if (HTE_Dscr_Next_p == NULL) |
| { |
| HTE_Dscr_Next_p = FreeList_Head_p; |
| HT_Params_p->FreeList_Head_p = NULL; // List is empty |
| } |
| else |
| { |
| // Remove the got HTE descriptor from the free list |
| EIP207_Flow_HTE_Dscr_List_Remove(HTE_Dscr_Next_p); |
| } |
| |
| // Add the got HTE descriptor to the overflow chain, |
| // we know that HTE_Dscr_p is the last descriptor |
| // in the chain |
| EIP207_Flow_HTE_Dscr_List_Next_Set(HTE_Dscr_p, |
| HTE_Dscr_Next_p); |
| EIP207_Flow_HTE_Dscr_List_Prev_Set(HTE_Dscr_Next_p, |
| HTE_Dscr_p); |
| |
| // We add first record to the bucket which HTE descriptor |
| // just fresh-taken from the free list |
| HTE_Dscr_Next_p->UsedRecOffsMask = |
| EIP207_FLOW_HTE_REC_OFFSET_1; |
| |
| // If flow record is added then write it |
| if (RecData_p->FR_Data_p != NULL) |
| EIP207Lib_Flow_FR_Write( |
| Rec_Dscr_p->DMA_Handle, |
| RecData_p->FR_Data_p, |
| RecData_p->FR_Data_p->Xform_DMA_Addr.Addr - |
| HT_Params_p->BaseAddr.Addr, |
| RecData_p->FR_Data_p->Xform_DMA_Addr.Addr, |
| RecData_p->FR_Data_p->Xform_DMA_Addr.UpperAddr); |
| |
| // Update the overflow bucket with hash ID and record offset |
| EIP207Lib_Flow_HB_Record_Add(HT_DMA_Handle, |
| HTE_Dscr_Next_p->Bucket_ByteOffset, |
| slot, |
| Rec_ByteOffset, |
| Record_Type, |
| RecData_p->HashID_p); |
| |
| // CDS point: after the next write32() operation is done |
| // the FLUE HW can find the overflow bucket! |
| |
| // Update bucket offset to the found bucket |
| // Note: bucket offset can use any address (pointer) type |
| // but not NULL! |
| EIP207Lib_Flow_HB_BuckOffs_Update( |
| HT_DMA_Handle, |
| HTE_Dscr_p->Bucket_ByteOffset, |
| HTE_Dscr_Next_p->Bucket_ByteOffset | |
| EIP207_FLOW_RECORD_TR_ADDRESS); |
| |
| // Increment record count for the added record |
| HTE_Dscr_Next_p->RecordCount++; |
| |
| // Bucket is updated, record is added |
| if (HTE_Dscr_Updated_p == NULL) |
| HTE_Dscr_Updated_p = HTE_Dscr_Next_p; |
| |
| #ifdef EIP207_FLOW_CONSISTENCY_CHECK |
| HTE_Dscr_p = HTE_Dscr_Next_p; |
| continue; // Validate the entire chain |
| #else |
| break; |
| #endif |
| } |
| else // Overflow chain is present for the found HTE_Dscr_p |
| { |
| // HTE_Dscr_p - last found HTE descriptor in the chain |
| // HTE_Dscr_Next_p - next HTE descriptor for HTE_Dscr_p |
| |
| #ifdef EIP207_FLOW_CONSISTENCY_CHECK |
| if (HTE_Dscr_Next_p != NULL) |
| { |
| // Consistency checks: next HTE descriptor must be on |
| // the overflow chain |
| if (!HTE_Dscr_Next_p->fOverflowBucket) |
| return EIP207_FLOW_INTERNAL_ERROR; |
| |
| // Check if the overflow bucket offset is |
| // a dummy pointer |
| { |
| // Read the overflow bucket offset |
| // from the previous bucket |
| uint32_t Bucket_ByteOffset = |
| DMAResource_Read32( |
| HT_DMA_Handle, |
| (HTE_Dscr_p->Bucket_ByteOffset >> 2) + |
| EIP207_FLOW_HB_OVFL_BUCKET_WORD_OFFSET); |
| |
| if (Bucket_ByteOffset != |
| (HTE_Dscr_Next_p->Bucket_ByteOffset| |
| EIP207_FLOW_RECORD_TR_ADDRESS)) |
| return EIP207_FLOW_INTERNAL_ERROR; |
| } |
| } |
| #endif // EIP207_FLOW_CONSISTENCY_CHECK |
| |
| HTE_Dscr_p = HTE_Dscr_Next_p; |
| continue; |
| |
| } // overflow bucket is found |
| |
| } // "bucket full" handling is done |
| |
| } while(HTE_Dscr_p != NULL); |
| |
| } // Record is added to the Hash Table |
| |
| // Fill in record descriptor internal data |
| { |
| EIP207_Flow_HTE_Dscr_RecData_t * Rec_DscrData_p; |
| |
| #ifdef EIP207_FLOW_CONSISTENCY_CHECK |
| // Check if the free slot number was found and |
| // the HTE descriptor to update was found |
| if (slot == 0 || HTE_Dscr_Updated_p == NULL) |
| return EIP207_FLOW_INTERNAL_ERROR; |
| #endif |
| |
| EIP207Lib_Flow_Dscr_InternalData_Set(Rec_Dscr_p); |
| Rec_DscrData_p = |
| (EIP207_Flow_HTE_Dscr_RecData_t*)Rec_Dscr_p->InternalData_p; |
| |
| Rec_DscrData_p->Slot = slot; |
| Rec_DscrData_p->HTE_Dscr_p = HTE_Dscr_Updated_p; |
| |
| if (RecData_p->TR_Data_p != NULL) |
| { |
| if (RecData_p->TR_Data_p->fLarge) |
| Rec_DscrData_p->Type = EIP207_FLOW_REC_TRANSFORM_LARGE; |
| else |
| Rec_DscrData_p->Type = EIP207_FLOW_REC_TRANSFORM_SMALL; |
| } |
| else if (RecData_p->FR_Data_p != NULL) |
| Rec_DscrData_p->Type = EIP207_FLOW_REC_FLOW; |
| else |
| return EIP207_FLOW_INTERNAL_ERROR; |
| } |
| |
| return EIP207_FLOW_NO_ERROR; |
| } |
| |
| |
| /*---------------------------------------------------------------------------- |
| * EIP207Lib_Flow_DTL_Record_Remove |
| */ |
| static EIP207_Flow_Error_t |
| EIP207Lib_Flow_DTL_Record_Remove( |
| const Device_Handle_t Device, |
| const unsigned int HashTableId, |
| volatile EIP207_Flow_HT_Params_t * const HT_Params_p, |
| EIP207_Flow_Dscr_t * const Rec_Dscr_p) |
| { |
| EIP207_Flow_ID_t HashID; |
| DMAResource_Handle_t HT_DMA_Handle; |
| EIP207_Flow_HTE_Dscr_t * HTE_Dscr_p; |
| EIP207_Flow_HTE_Dscr_RecData_t * Rec_DscrData_p = |
| (EIP207_Flow_HTE_Dscr_RecData_t*)Rec_Dscr_p->InternalData_p; |
| |
| #ifdef EIP207_FLOW_CONSISTENCY_CHECK |
| // Consistency check for the provided TR descriptor |
| if (Rec_Dscr_p->DMA_Addr.Addr == EIP207_FLOW_RECORD_DUMMY_ADDRESS) |
| return EIP207_FLOW_INTERNAL_ERROR; |
| |
| if (Rec_DscrData_p == NULL) |
| return EIP207_FLOW_INTERNAL_ERROR; |
| #endif // EIP207_FLOW_CONSISTENCY_CHECK |
| |
| // get the HTE descriptor for the record to remove |
| HTE_Dscr_p = Rec_DscrData_p->HTE_Dscr_p; |
| |
| HT_DMA_Handle = HT_Params_p->HT_DMA_Handle; |
| |
| ZEROINIT(HashID); |
| |
| #ifdef EIP207_FLOW_CONSISTENCY_CHECK |
| // Check record count is sane |
| if (HTE_Dscr_p->RecordCount > EIP207_FLOW_MAX_RECORDS_PER_BUCKET || |
| HTE_Dscr_p->RecordCount == 0) |
| return EIP207_FLOW_INTERNAL_ERROR; |
| |
| // Check the record descriptor slot number |
| if (Rec_DscrData_p->Slot < 1 || Rec_DscrData_p->Slot > 3) |
| return EIP207_FLOW_INTERNAL_ERROR; // Incorrect record slot number |
| |
| // Check the record offset calculated from the record descriptor |
| // matches the one on the bucket |
| { |
| uint32_t Rec_ByteOffset2; |
| uint32_t Rec_ByteOffset1 = |
| DMAResource_Read32(HT_DMA_Handle, |
| (HTE_Dscr_p->Bucket_ByteOffset >> 2) + |
| EIP207_FLOW_HB_REC_1_WORD_OFFSET + |
| (Rec_DscrData_p->Slot - 1)); |
| |
| // Clear the bits that specify the record type |
| Rec_ByteOffset1 &= (~EIP207_FLOW_RECORD_ADDRESS_TYPE_BITS); |
| |
| // Calculate the record byte offset, |
| // HT_Params_p->BaseAddr.Addr is the base |
| // address of the DMA bank where the record |
| // must have been allocated |
| Rec_ByteOffset2 = Rec_Dscr_p->DMA_Addr.Addr - |
| HT_Params_p->BaseAddr.Addr; |
| |
| if (Rec_ByteOffset1 != Rec_ByteOffset2) |
| return EIP207_FLOW_INTERNAL_ERROR; // Incorrect record offset |
| } |
| #endif // EIP207_FLOW_CONSISTENCY_CHECK |
| |
| if (HTE_Dscr_p->RecordCount > 1) |
| { |
| // Remove the non-last record from the bucket |
| |
| EIP207_Flow_Error_t Flow_Rc; |
| |
| // CDS point: record is removed when the next function returns! |
| |
| // Update the record offset in the bucket. |
| // Update the Hash ID (optional) |
| EIP207Lib_Flow_HB_Record_Remove(HT_DMA_Handle, |
| HTE_Dscr_p->Bucket_ByteOffset, |
| Rec_DscrData_p->Slot, |
| &HashID); |
| |
| // Mark this record slot as free in the HTE descriptor |
| Flow_Rc = EIP207Lib_Flow_HB_Slot_Put(&HTE_Dscr_p->UsedRecOffsMask, |
| Rec_DscrData_p->Slot); |
| if (Flow_Rc != EIP207_FLOW_NO_ERROR) |
| return Flow_Rc; |
| |
| // Decrease record count in the HTE descriptor |
| HTE_Dscr_p->RecordCount--; |
| } |
| else // record count = 1, so when removing the record also remove the bucket |
| { |
| // Remove the last record from the removed bucket. |
| // Also remove the bucket from the chain first. |
| |
| if (HTE_Dscr_p->fOverflowBucket) |
| { |
| // Remove the last record from the overflow bucket |
| |
| EIP207_Flow_HTE_Dscr_t * FreeList_Head_p; |
| |
| // Get the neighboring HTE descriptors in the chain |
| EIP207_Flow_HTE_Dscr_t * HTE_Dscr_Prev_p = |
| EIP207_Flow_HTE_Dscr_List_Prev_Get(HTE_Dscr_p); |
| EIP207_Flow_HTE_Dscr_t * HTE_Dscr_Next_p = |
| EIP207_Flow_HTE_Dscr_List_Next_Get(HTE_Dscr_p); |
| |
| #ifdef EIP207_FLOW_CONSISTENCY_CHECK |
| // Check if the previous HTE descriptor is not NULL, |
| // it may not be NULL for the overflow bucket |
| if (HTE_Dscr_Prev_p == NULL) |
| return EIP207_FLOW_INTERNAL_ERROR; |
| #endif |
| |
| // CDS point: bucket (and record) is removed when |
| // the next function returns and the wait loop is done! |
| |
| // Remove HTE_Dscr_p bucket from the chain, |
| // make the HTE_Dscr_Prev_p bucket refer to HTE_Dscr_Next_p bucket |
| // Note: bucket offset can use any address (pointer) type |
| // but not NULL! |
| EIP207Lib_Flow_HB_BuckOffs_Update( |
| HT_DMA_Handle, |
| HTE_Dscr_Prev_p->Bucket_ByteOffset, |
| HTE_Dscr_Next_p ? // the last in chain? |
| (HTE_Dscr_Next_p->Bucket_ByteOffset | |
| EIP207_FLOW_RECORD_TR_ADDRESS) : |
| EIP207_FLOW_RECORD_DUMMY_ADDRESS); |
| |
| // Wait loop: this is to wait for the EIP-207 packet classification |
| // engine to complete processing using this bucket |
| // before it can be re-used for another record lookup |
| { |
| unsigned int LoopCount, Value = 1; |
| |
| for (LoopCount = 0; |
| LoopCount < EIP207_FLOW_RECORD_REMOVE_WAIT_COUNT; |
| LoopCount++) |
| { |
| // Do some work in the loop |
| if (LoopCount & BIT_0) |
| Value <<= 1; |
| else |
| Value >>= 1; |
| } |
| } // HB remove wait loop is done! |
| |
| // Remove record from the HTE_Dscr_p bucket |
| // which is not in the chain anymore |
| EIP207Lib_Flow_HB_Record_Remove(HT_DMA_Handle, |
| HTE_Dscr_p->Bucket_ByteOffset, |
| Rec_DscrData_p->Slot, |
| &HashID); |
| |
| // Update the bucket offset in the removed from the chain |
| // HTE_Dscr_p bucket |
| EIP207Lib_Flow_HB_BuckOffs_Update( |
| HT_DMA_Handle, |
| HTE_Dscr_p->Bucket_ByteOffset, |
| EIP207_FLOW_RECORD_DUMMY_ADDRESS); |
| |
| // Remove HTE descriptor from the chain |
| EIP207_Flow_HTE_Dscr_List_Remove(HTE_Dscr_p); |
| |
| // Add the HTE descriptor to the free list |
| FreeList_Head_p = |
| (EIP207_Flow_HTE_Dscr_t*)HT_Params_p->FreeList_Head_p; |
| |
| // Insert the HTE descriptor at the free list head |
| if (FreeList_Head_p != NULL) |
| EIP207_Flow_HTE_Dscr_List_Insert(FreeList_Head_p, HTE_Dscr_p); |
| } |
| else |
| { |
| // Remove the last record from the HT bucket |
| // Note: the chain may still be present for this HTE_Dscr_p bucket |
| |
| // CDS point: record is removed when the next function returns! |
| |
| // Update the record offset in the bucket. |
| // Update the Hash ID (optional) |
| EIP207Lib_Flow_HB_Record_Remove(HT_DMA_Handle, |
| HTE_Dscr_p->Bucket_ByteOffset, |
| Rec_DscrData_p->Slot, |
| &HashID); |
| |
| // Wait loop: this is to wait for the EIP-207 packet classification |
| // engine to complete processing using this bucket |
| // before it can be re-used for another record lookup |
| { |
| unsigned int LoopCount, Value = 1; |
| |
| for (LoopCount = 0; |
| LoopCount < EIP207_FLOW_RECORD_REMOVE_WAIT_COUNT; |
| LoopCount++) |
| { |
| // Do some work in the loop |
| if (LoopCount & BIT_0) |
| Value <<= 1; |
| else |
| Value >>= 1; |
| } |
| } // HB remove wait loop is done! |
| |
| // Mark this record slot as free in the HTE descriptor |
| EIP207Lib_Flow_HB_Slot_Put(&HTE_Dscr_p->UsedRecOffsMask, |
| Rec_DscrData_p->Slot); |
| } |
| |
| // Update the HTE_Dscr_p record offset mask and record count |
| HTE_Dscr_p->UsedRecOffsMask = 0; |
| HTE_Dscr_p->RecordCount = 0; |
| } |
| |
| #ifndef EIP207_FLUE_RC_HP |
| // Invalidate lookup result in the FLUEC |
| EIP207_FLUEC_Invalidate(Device, |
| (uint8_t)HashTableId, |
| HashID.Word32[0], |
| HashID.Word32[1], |
| HashID.Word32[2], |
| HashID.Word32[3]); |
| #else |
| IDENTIFIER_NOT_USED(Device); |
| IDENTIFIER_NOT_USED(HashTableId); |
| #endif |
| |
| // Invalidate the internal data of the DTL transform record descriptor |
| Rec_DscrData_p->Slot = 0; |
| Rec_DscrData_p->HTE_Dscr_p = NULL; |
| Rec_DscrData_p->Type = EIP207_FLOW_REC_INVALID; |
| |
| return EIP207_FLOW_NO_ERROR; |
| } |
| |
| #ifdef EIP207_FLOW_STRICT_ARGS |
| /*---------------------------------------------------------------------------- |
| * EIP207Lib_Flow_Is32bitAddressable |
| */ |
| static bool |
| EIP207Lib_Flow_Is32bitAddressable( |
| const uint32_t BaseAddrLo, |
| const uint32_t BaseAddrHi, |
| const uint32_t AddrLo, |
| const uint32_t AddrHi) |
| { |
| if(BaseAddrHi == AddrHi) |
| { |
| if(BaseAddrLo > AddrLo) |
| return false; |
| } |
| else if (BaseAddrHi < AddrHi && (BaseAddrHi == AddrHi + 1)) |
| { |
| if(BaseAddrLo <= AddrLo) |
| return false; |
| } |
| else |
| return false; |
| |
| return true; |
| } |
| #endif // EIP207_FLOW_STRICT_ARGS |
| |
| |
| /***************************************************************************** |
| * Generic API functions implemented in DTL-specific way |
| */ |
| |
| /*---------------------------------------------------------------------------- |
| * EIP207_Flow_HTE_Dscr_ByteCount_Get |
| */ |
| unsigned int |
| EIP207_Flow_HTE_Dscr_ByteCount_Get(void) |
| { |
| return EIP207Lib_Flow_HTE_Dscr_ByteCount_Get(); |
| } |
| |
| |
| /*---------------------------------------------------------------------------- |
| * EIP207_Flow_FR_Dscr_ByteCount_Get |
| */ |
| unsigned int |
| EIP207_Flow_FR_Dscr_ByteCount_Get(void) |
| { |
| return sizeof(EIP207_Flow_Rec_Dscr_t); |
| } |
| |
| |
| /*---------------------------------------------------------------------------- |
| * EIP207_Flow_TR_Dscr_ByteCount_Get |
| */ |
| unsigned int |
| EIP207_Flow_TR_Dscr_ByteCount_Get(void) |
| { |
| return sizeof(EIP207_Flow_Rec_Dscr_t); |
| } |
| |
| |
| /*---------------------------------------------------------------------------- |
| * EIP207_Flow_Record_Dummy_Addr_Get |
| */ |
| unsigned int |
| EIP207_Flow_Record_Dummy_Addr_Get(void) |
| { |
| return EIP207_FLOW_RECORD_DUMMY_ADDRESS; |
| } |
| |
| |
| /*---------------------------------------------------------------------------- |
| * EIP207_Flow_HashTable_Install |
| */ |
| EIP207_Flow_Error_t |
| EIP207_Flow_HashTable_Install( |
| EIP207_Flow_IOArea_t * const IOArea_p, |
| const unsigned int HashTableId, |
| const EIP207_Flow_HT_t * HT_p, |
| bool fLookupCached, |
| bool fReset) |
| { |
| unsigned int i, EntryCount; |
| Device_Handle_t Device; |
| volatile EIP207_Flow_True_IOArea_t * const TrueIOArea_p = IOAREA(IOArea_p); |
| |
| EIP207_FLOW_CHECK_POINTER(IOArea_p); |
| EIP207_FLOW_CHECK_POINTER(HT_p->HT_DMA_Address_p); |
| EIP207_FLOW_CHECK_POINTER(HT_p->DT_p); |
| EIP207_FLOW_CHECK_INT_ATMOST(HashTableId + 1, |
| EIP207_FLOW_MAX_NOF_FLOW_HASH_TABLES_TO_USE); |
| |
| EntryCount = (unsigned int)HT_p->HT_TableSize; |
| EIP207_FLOW_CHECK_INT_ATMOST(EntryCount, |
| EIP207_FLOW_HASH_TABLE_ENTRIES_MAX); |
| |
| // Convert EIP207_Flow_HashTable_Entry_Count_t to a number |
| EntryCount = EIP207Lib_Flow_TableSize_To_EntryCount(EntryCount); |
| EIP207_FLOW_CHECK_INT_ATMOST(EntryCount, HT_p->DT_EntryCount); |
| |
| // Check Flow Hash Table address alignment |
| if (HT_p->HT_DMA_Address_p->Addr == EIP207_FLOW_RECORD_DUMMY_ADDRESS) |
| return EIP207_FLOW_ARGUMENT_ERROR; |
| |
| // Save the flag that indicates whether the FLUEC must be used |
| // Note: FLUEC is enabled and configured via the Global Control interface |
| TrueIOArea_p->HT_Params[HashTableId].fLookupCached = fLookupCached; |
| |
| // Save the host address of the Flow Descriptor Table and its size |
| TrueIOArea_p->HT_Params[HashTableId].DT_p = HT_p->DT_p; |
| TrueIOArea_p->HT_Params[HashTableId].HT_TableSize = |
| (unsigned int)HT_p->HT_TableSize; |
| |
| // Save the DMA resource handle of the Flow Hash Table |
| TrueIOArea_p->HT_Params[HashTableId].HT_DMA_Handle = |
| HT_p->HT_DMA_Handle; |
| |
| Device = TrueIOArea_p->Device; |
| |
| // Initialize the HT and the DT free list with initial values |
| if (fReset) |
| { |
| EIP207_Flow_HTE_Dscr_t * HTE_Dscr_p = |
| (EIP207_Flow_HTE_Dscr_t*)HT_p->DT_p; |
| |
| // Initialize the Descriptor Table with initial values |
| memset(HT_p->DT_p, |
| 0, |
| HT_p->DT_EntryCount * sizeof(EIP207_Flow_HTE_Dscr_t)); |
| |
| // Number of HTE descriptors is equal to the number of hash buckets |
| // in the HT plus the number of overflow hash buckets. |
| |
| for (i = 0; i < HT_p->DT_EntryCount; i++) |
| { |
| unsigned int j; |
| |
| // Initialize with dummy address all the words (j) |
| // in HTE descriptor i |
| for (j = 0; j < EIP207_FLOW_HT_ENTRY_WORD_COUNT; j++) |
| DMAResource_Write32(HT_p->HT_DMA_Handle, |
| i * EIP207_FLOW_HT_ENTRY_WORD_COUNT + j, |
| EIP207_FLOW_RECORD_DUMMY_ADDRESS); |
| |
| // Add only the HTE descriptors for the overflow hash buckets |
| // to the free list. |
| if (i >= EntryCount) |
| { |
| // Descriptor Table free list initialization, |
| // all the HTE descriptors are added to the free list |
| |
| // First overflow HTE descriptor in DT? |
| if (i == EntryCount) |
| { |
| EIP207_Flow_HTE_Dscr_List_Prev_Set(HTE_Dscr_p, NULL); |
| EIP207_Flow_HTE_Dscr_List_Next_Set(HTE_Dscr_p, |
| HTE_Dscr_p + 1); |
| |
| // Set the free list head |
| TrueIOArea_p->HT_Params[HashTableId].FreeList_Head_p = |
| HTE_Dscr_p; |
| } |
| |
| // Last overflow HTE descriptor in DT? |
| if (i == HT_p->DT_EntryCount - 1) |
| { |
| // First and last overflow HTE descriptor in DT? |
| if (i != EntryCount) |
| EIP207_Flow_HTE_Dscr_List_Prev_Set(HTE_Dscr_p, |
| HTE_Dscr_p - 1); |
| EIP207_Flow_HTE_Dscr_List_Next_Set(HTE_Dscr_p, NULL); |
| } |
| |
| // Non-first and non-last overflow HTE descriptor in DT? |
| if (i != EntryCount && i != (HT_p->DT_EntryCount - 1)) |
| { |
| EIP207_Flow_HTE_Dscr_List_Prev_Set(HTE_Dscr_p, |
| HTE_Dscr_p - 1); |
| EIP207_Flow_HTE_Dscr_List_Next_Set(HTE_Dscr_p, |
| HTE_Dscr_p + 1); |
| } |
| |
| // Mark overflow hash buckets |
| HTE_Dscr_p->fOverflowBucket = true; |
| } |
| else |
| // Mark non-overflow hash buckets |
| HTE_Dscr_p->fOverflowBucket = false; |
| |
| // Set hash bucket byte offset |
| HTE_Dscr_p->Bucket_ByteOffset = i * |
| EIP207_FLOW_HT_ENTRY_WORD_COUNT * |
| sizeof(uint32_t); |
| |
| HTE_Dscr_p++; // Next HTE descriptor in the DT |
| } // for |
| |
| // Perform pre-DMA for the entire HT including the overflow buckets, |
| // both are expected to be in one linear contiguous DMA-safe buffer |
| DMAResource_PreDMA(HT_p->HT_DMA_Handle, 0, 0); |
| } |
| |
| // Install the FHT |
| EIP207_FLUE_HASHBASE_LO_WR(Device, |
| HashTableId, |
| HT_p->HT_DMA_Address_p->Addr); |
| EIP207_FLUE_HASHBASE_HI_WR(Device, |
| HashTableId, |
| HT_p->HT_DMA_Address_p->UpperAddr); |
| EIP207_FLUE_SIZE_UPDATE(Device, |
| HashTableId, |
| (uint8_t)HT_p->HT_TableSize); |
| |
| #ifdef EIP207_FLOW_DEBUG_FSM |
| if (fReset) |
| { |
| EIP207_Flow_Error_t rv; |
| uint32_t State = TrueIOArea_p->State; |
| |
| // Transit to a new state |
| rv = EIP207_Flow_State_Set( |
| (EIP207_Flow_State_t* const)&State, |
| EIP207_FLOW_STATE_ENABLED); |
| |
| TrueIOArea_p->State = State; |
| |
| if (rv != EIP207_FLOW_NO_ERROR) |
| return EIP207_FLOW_ILLEGAL_IN_STATE; |
| } |
| #endif // EIP207_FLOW_DEBUG_FSM |
| |
| return EIP207_FLOW_NO_ERROR; |
| } |
| |
| |
| /*---------------------------------------------------------------------------- |
| * EIP207_Flow_FR_Add |
| |
| */ |
| EIP207_Flow_Error_t |
| EIP207_Flow_FR_Add( |
| EIP207_Flow_IOArea_t * const IOArea_p, |
| const unsigned int HashTableId, |
| EIP207_Flow_FR_Dscr_t * const FR_Dscr_p, |
| const EIP207_Flow_FR_InputData_t * const FlowInData_p) |
| { |
| volatile EIP207_Flow_True_IOArea_t * const TrueIOArea_p = IOAREA(IOArea_p); |
| EIP207_Flow_Record_InputData_t Rec_Data; |
| EIP207_Flow_FR_Data_t FR_Data; |
| EIP207_Flow_Error_t Flow_Rc; |
| |
| EIP207_FLOW_CHECK_POINTER(IOArea_p); |
| EIP207_FLOW_CHECK_INT_ATMOST(HashTableId + 1, |
| EIP207_FLOW_MAX_NOF_FLOW_HASH_TABLES_TO_USE); |
| EIP207_FLOW_CHECK_POINTER(FR_Dscr_p); |
| EIP207_FLOW_CHECK_POINTER(FlowInData_p); |
| |
| #ifdef EIP207_FLOW_STRICT_ARGS |
| // Provided flow record physical DMA address must be addressable by |
| // a 32-bit offset to the Base Address installed via |
| // the EIP207_Flow_RC_BaseAddr_Set() function |
| if(!EIP207Lib_Flow_Is32bitAddressable( |
| TrueIOArea_p->HT_Params[HashTableId].BaseAddr.Addr, |
| TrueIOArea_p->HT_Params[HashTableId].BaseAddr.UpperAddr, |
| FR_Dscr_p->DMA_Addr.Addr, |
| FR_Dscr_p->DMA_Addr.UpperAddr)) |
| return EIP207_FLOW_ARGUMENT_ERROR; |
| |
| // Provided transform record physical DMA address must be addressable by |
| // a 32-bit offset to the Base Address installed via |
| // the EIP207_Flow_RC_BaseAddr_Set() function |
| if(FlowInData_p->Xform_DMA_Addr.Addr != EIP207_FLOW_RECORD_DUMMY_ADDRESS && |
| !EIP207Lib_Flow_Is32bitAddressable( |
| TrueIOArea_p->HT_Params[HashTableId].BaseAddr.Addr, |
| TrueIOArea_p->HT_Params[HashTableId].BaseAddr.UpperAddr, |
| FlowInData_p->Xform_DMA_Addr.Addr, |
| FlowInData_p->Xform_DMA_Addr.UpperAddr)) |
| return EIP207_FLOW_ARGUMENT_ERROR; |
| #endif // EIP207_FLOW_STRICT_ARGS |
| |
| ZEROINIT(Rec_Data); |
| ZEROINIT(FR_Data); |
| |
| FR_Data.Flags = FlowInData_p->Flags; |
| FR_Data.SW_FR_Reference = FlowInData_p->SW_FR_Reference; |
| FR_Data.Xform_DMA_Addr = FlowInData_p->Xform_DMA_Addr; |
| FR_Data.fLarge = FlowInData_p->fLarge; |
| |
| Rec_Data.HashID_p = &FlowInData_p->HashID; |
| Rec_Data.FR_Data_p = &FR_Data; |
| |
| Flow_Rc = EIP207Lib_Flow_DTL_Record_Add( |
| &TrueIOArea_p->HT_Params[HashTableId], |
| (EIP207_Flow_Dscr_t*)FR_Dscr_p, |
| &Rec_Data); |
| if (Flow_Rc != EIP207_FLOW_NO_ERROR) |
| return Flow_Rc; |
| |
| #ifdef EIP207_FLOW_DEBUG_FSM |
| { |
| EIP207_Flow_Error_t rv; |
| uint32_t State = TrueIOArea_p->State; |
| |
| TrueIOArea_p->Rec_InstalledCounter++; |
| |
| // Transit to a new state |
| rv = EIP207_Flow_State_Set((EIP207_Flow_State_t* const)&State, |
| EIP207_FLOW_STATE_INSTALLED); |
| |
| TrueIOArea_p->State = State; |
| |
| if (rv != EIP207_FLOW_NO_ERROR) |
| return EIP207_FLOW_ILLEGAL_IN_STATE; |
| } |
| #endif // EIP207_FLOW_DEBUG_FSM |
| |
| return EIP207_FLOW_NO_ERROR; |
| } |
| |
| |
| /*---------------------------------------------------------------------------- |
| * EIP207_Flow_RC_BaseAddr_Set |
| */ |
| EIP207_Flow_Error_t |
| EIP207_Flow_RC_BaseAddr_Set( |
| EIP207_Flow_IOArea_t * const IOArea_p, |
| const unsigned int HashTableId, |
| const EIP207_Flow_Address_t * const FlowBaseAddr_p, |
| const EIP207_Flow_Address_t * const TransformBaseAddr_p) |
| { |
| Device_Handle_t Device; |
| volatile EIP207_Flow_True_IOArea_t * const TrueIOArea_p = IOAREA(IOArea_p); |
| |
| EIP207_FLOW_CHECK_POINTER(IOArea_p); |
| EIP207_FLOW_CHECK_INT_ATMOST(HashTableId + 1, |
| EIP207_FLOW_MAX_NOF_FLOW_HASH_TABLES_TO_USE); |
| |
| IDENTIFIER_NOT_USED(TransformBaseAddr_p); |
| |
| Device = TrueIOArea_p->Device; |
| |
| // Set the common base address for all the records which can be looked up |
| // Note: Standard (legacy) record cache should have |
| // EIP207_RC_SET_NR_DEFAULT set (which is 0, just one Hash Table); |
| // High-performance (HP) record cache should have |
| // HashTableId set |
| #ifndef EIP207_FLUE_RC_HP |
| EIP207_RC_BaseAddr_Set(Device, |
| EIP207_FRC_REG_BASE, |
| HashTableId, // EIP207_RC_SET_NR_DEFAULT |
| FlowBaseAddr_p->Addr, |
| FlowBaseAddr_p->UpperAddr); |
| #else |
| EIP207_FLUE_CACHEBASE_LO_WR(Device, HashTableId, FlowBaseAddr_p->Addr); |
| EIP207_FLUE_CACHEBASE_HI_WR(Device, HashTableId, FlowBaseAddr_p->UpperAddr); |
| #endif |
| |
| TrueIOArea_p->HT_Params[HashTableId].BaseAddr.Addr = FlowBaseAddr_p->Addr; |
| TrueIOArea_p->HT_Params[HashTableId].BaseAddr.UpperAddr = |
| FlowBaseAddr_p->UpperAddr; |
| |
| return EIP207_FLOW_NO_ERROR; |
| } |
| |
| |
| /***************************************************************************** |
| * DTL-specific API functions |
| */ |
| |
| /*---------------------------------------------------------------------------- |
| * EIP207_Flow_DTL_FR_Remove |
| */ |
| EIP207_Flow_Error_t |
| EIP207_Flow_DTL_FR_Remove( |
| EIP207_Flow_IOArea_t * const IOArea_p, |
| const unsigned int HashTableId, |
| EIP207_Flow_FR_Dscr_t * const FR_Dscr_p) |
| { |
| volatile EIP207_Flow_True_IOArea_t * const TrueIOArea_p = IOAREA(IOArea_p); |
| EIP207_Flow_HTE_Dscr_RecData_t * FR_Data_p; |
| EIP207_Flow_Error_t Flow_Rc; |
| |
| EIP207_FLOW_CHECK_POINTER(IOArea_p); |
| EIP207_FLOW_CHECK_INT_ATMOST(HashTableId + 1, |
| EIP207_FLOW_MAX_NOF_FLOW_HASH_TABLES_TO_USE); |
| EIP207_FLOW_CHECK_POINTER(FR_Dscr_p); |
| |
| FR_Data_p = (EIP207_Flow_HTE_Dscr_RecData_t*)FR_Dscr_p->InternalData_p; |
| |
| EIP207_FLOW_CHECK_POINTER(FR_Data_p); |
| EIP207_FLOW_CHECK_POINTER(FR_Data_p->HTE_Dscr_p); |
| |
| #ifdef EIP207_FLOW_STRICT_ARGS |
| // Provided flow record physical DMA address must be addressable by |
| // a 32-bit offset to the Based Address installed via |
| // the EIP207_Flow_RC_BaseAddr_Set() function |
| if(!EIP207Lib_Flow_Is32bitAddressable( |
| TrueIOArea_p->HT_Params[HashTableId].BaseAddr.Addr, |
| TrueIOArea_p->HT_Params[HashTableId].BaseAddr.UpperAddr, |
| FR_Dscr_p->DMA_Addr.Addr, |
| FR_Dscr_p->DMA_Addr.UpperAddr)) |
| return EIP207_FLOW_ARGUMENT_ERROR; |
| |
| if (FR_Data_p->Type != EIP207_FLOW_REC_FLOW) |
| return EIP207_FLOW_INTERNAL_ERROR; |
| #endif // EIP207_FLOW_STRICT_ARGS |
| |
| Flow_Rc = EIP207Lib_Flow_DTL_Record_Remove( |
| TrueIOArea_p->Device, |
| HashTableId, |
| &TrueIOArea_p->HT_Params[HashTableId], |
| (EIP207_Flow_Dscr_t*)FR_Dscr_p); |
| if (Flow_Rc != EIP207_FLOW_NO_ERROR) |
| return Flow_Rc; |
| |
| IDENTIFIER_NOT_USED(FR_Data_p); |
| |
| #ifdef EIP207_FLOW_DEBUG_FSM |
| { |
| EIP207_Flow_Error_t rv; |
| uint32_t State = TrueIOArea_p->State; |
| |
| TrueIOArea_p->Rec_InstalledCounter--; |
| |
| // Transit to a new state |
| if (TrueIOArea_p->Rec_InstalledCounter == 0) |
| // Last record is removed |
| rv = EIP207_Flow_State_Set( |
| (EIP207_Flow_State_t* const)&State, |
| EIP207_FLOW_STATE_ENABLED); |
| else |
| // Non-last record is removed |
| rv = EIP207_Flow_State_Set( |
| (EIP207_Flow_State_t* const)&State, |
| EIP207_FLOW_STATE_INSTALLED); |
| |
| TrueIOArea_p->State = State; |
| |
| if (rv != EIP207_FLOW_NO_ERROR) |
| return EIP207_FLOW_ILLEGAL_IN_STATE; |
| } |
| #endif // EIP207_FLOW_DEBUG_FSM |
| |
| return EIP207_FLOW_NO_ERROR; |
| } |
| |
| |
| #ifndef EIP207_FLOW_REMOVE_TR_LARGE_SUPPORT |
| /*---------------------------------------------------------------------------- |
| * EIP207_Flow_DTL_TR_Large_WordCount_Get |
| */ |
| unsigned int |
| EIP207_Flow_DTL_TR_Large_WordCount_Get(void) |
| { |
| return FIRMWARE_EIP207_CS_FLOW_TRC_RECORD_WORD_COUNT_LARGE; |
| } |
| #endif // !EIP207_FLOW_REMOVE_TR_LARGE_SUPPORT |
| |
| |
| /*---------------------------------------------------------------------------- |
| * EIP207_Flow_DTL_TR_Add |
| */ |
| EIP207_Flow_Error_t |
| EIP207_Flow_DTL_TR_Add( |
| EIP207_Flow_IOArea_t * const IOArea_p, |
| const unsigned int HashTableId, |
| EIP207_Flow_TR_Dscr_t * const TR_Dscr_p, |
| const EIP207_Flow_TR_InputData_t * const XformInData_p) |
| { |
| volatile EIP207_Flow_True_IOArea_t * const TrueIOArea_p = IOAREA(IOArea_p); |
| EIP207_Flow_Record_InputData_t Rec_Data; |
| EIP207_Flow_TR_Data_t TR_Data; |
| EIP207_Flow_Error_t Flow_Rc; |
| |
| EIP207_FLOW_CHECK_POINTER(IOArea_p); |
| EIP207_FLOW_CHECK_INT_ATMOST(HashTableId + 1, |
| EIP207_FLOW_MAX_NOF_FLOW_HASH_TABLES_TO_USE); |
| EIP207_FLOW_CHECK_POINTER(TR_Dscr_p); |
| EIP207_FLOW_CHECK_POINTER(XformInData_p); |
| |
| #ifdef EIP207_FLOW_STRICT_ARGS |
| // Provided transform record physical DMA address must be addressable by |
| // a 32-bit offset to the Transform Based Address installed via |
| // the EIP207_Flow_RC_BaseAddr_Set() function |
| if(!EIP207Lib_Flow_Is32bitAddressable( |
| TrueIOArea_p->HT_Params[HashTableId].BaseAddr.Addr, |
| TrueIOArea_p->HT_Params[HashTableId].BaseAddr.UpperAddr, |
| TR_Dscr_p->DMA_Addr.Addr, |
| TR_Dscr_p->DMA_Addr.UpperAddr)) |
| return EIP207_FLOW_ARGUMENT_ERROR; |
| #endif // EIP207_FLOW_STRICT_ARGS |
| |
| ZEROINIT(Rec_Data); |
| ZEROINIT(TR_Data); |
| |
| TR_Data.fLarge = XformInData_p->fLarge; |
| |
| Rec_Data.HashID_p = &XformInData_p->HashID; |
| Rec_Data.TR_Data_p = &TR_Data; |
| |
| Flow_Rc = EIP207Lib_Flow_DTL_Record_Add( |
| &TrueIOArea_p->HT_Params[HashTableId], |
| (EIP207_Flow_Dscr_t*)TR_Dscr_p, |
| &Rec_Data); |
| if (Flow_Rc != EIP207_FLOW_NO_ERROR) |
| return Flow_Rc; |
| |
| #ifdef EIP207_FLOW_DEBUG_FSM |
| { |
| EIP207_Flow_Error_t rv; |
| uint32_t State = TrueIOArea_p->State; |
| |
| TrueIOArea_p->Rec_InstalledCounter++; |
| |
| // Transit to a new state |
| rv = EIP207_Flow_State_Set((EIP207_Flow_State_t* const)&State, |
| EIP207_FLOW_STATE_INSTALLED); |
| |
| TrueIOArea_p->State = State; |
| |
| if (rv != EIP207_FLOW_NO_ERROR) |
| return EIP207_FLOW_ILLEGAL_IN_STATE; |
| } |
| #endif // EIP207_FLOW_DEBUG_FSM |
| |
| return EIP207_FLOW_NO_ERROR; |
| } |
| |
| |
| #ifndef EIP207_FLOW_REMOVE_TR_LARGE_SUPPORT |
| /*---------------------------------------------------------------------------- |
| * EIP207_Flow_DTL_TR_Large_Read |
| */ |
| EIP207_Flow_Error_t |
| EIP207_Flow_DTL_TR_Large_Read( |
| EIP207_Flow_IOArea_t * const IOArea_p, |
| const unsigned int HashTableId, |
| const EIP207_Flow_TR_Dscr_t * const TR_Dscr_p, |
| EIP207_Flow_TR_OutputData_t * const XformData_p) |
| { |
| EIP207_Flow_Error_t rv; |
| uint32_t Value32, SeqNrWordOffset; |
| |
| EIP207_FLOW_CHECK_POINTER(IOArea_p); |
| EIP207_FLOW_CHECK_POINTER(TR_Dscr_p); |
| EIP207_FLOW_CHECK_POINTER(XformData_p); |
| EIP207_FLOW_CHECK_INT_ATMOST(HashTableId + 1, |
| EIP207_FLOW_MAX_NOF_FLOW_HASH_TABLES_TO_USE); |
| |
| IDENTIFIER_NOT_USED(IOArea_p); |
| IDENTIFIER_NOT_USED(HashTableId); |
| |
| // Prepare the transform record for reading |
| DMAResource_PostDMA(TR_Dscr_p->DMA_Handle, 0, 0); |
| |
| // Read the transform record data |
| |
| // Recent record Packets Counter |
| XformData_p->PacketsCounter = |
| DMAResource_Read32( |
| TR_Dscr_p->DMA_Handle, |
| FIRMWARE_EIP207_CS_FLOW_TR_STAT_PKT_WORD_OFFSET_LARGE); |
| |
| // Read Token Context Instruction word |
| Value32 = |
| DMAResource_Read32(TR_Dscr_p->DMA_Handle, |
| FIRMWARE_EIP207_CS_FLOW_TR_TK_CTX_INST_WORD_OFFSET_LARGE); |
| |
| // Extract the Sequence Number word offset from the read value |
| FIRMWARE_EIP207_CS_Flow_SeqNum_Offset_Read(Value32, &SeqNrWordOffset); |
| |
| // Read the sequence number |
| XformData_p->SequenceNumber = |
| DMAResource_Read32(TR_Dscr_p->DMA_Handle, SeqNrWordOffset); |
| |
| // Recent record time stamp |
| rv = EIP207_Flow_Internal_Read64( |
| TR_Dscr_p->DMA_Handle, |
| FIRMWARE_EIP207_CS_FLOW_TR_TIME_STAMP_LO_WORD_OFFSET_LARGE, |
| FIRMWARE_EIP207_CS_FLOW_TR_TIME_STAMP_HI_WORD_OFFSET_LARGE, |
| &XformData_p->LastTimeLo, |
| &XformData_p->LastTimeHi); |
| if (rv != EIP207_FLOW_NO_ERROR) |
| return rv; |
| |
| // Recent record Octets Counter |
| rv = EIP207_Flow_Internal_Read64( |
| TR_Dscr_p->DMA_Handle, |
| FIRMWARE_EIP207_CS_FLOW_TR_STAT_OCT_LO_WORD_OFFSET_LARGE, |
| FIRMWARE_EIP207_CS_FLOW_TR_STAT_OCT_HI_WORD_OFFSET_LARGE, |
| &XformData_p->OctetsCounterLo, |
| &XformData_p->OctetsCounterHi); |
| if (rv != EIP207_FLOW_NO_ERROR) |
| return rv; |
| |
| return EIP207_FLOW_NO_ERROR; |
| } |
| #endif // !EIP207_FLOW_REMOVE_TR_LARGE_SUPPORT |
| |
| |
| /*---------------------------------------------------------------------------- |
| * EIP207_Flow_DTL_TR_Remove |
| */ |
| EIP207_Flow_Error_t |
| EIP207_Flow_DTL_TR_Remove( |
| EIP207_Flow_IOArea_t * const IOArea_p, |
| const unsigned int HashTableId, |
| EIP207_Flow_TR_Dscr_t * const TR_Dscr_p) |
| { |
| volatile EIP207_Flow_True_IOArea_t * const TrueIOArea_p = IOAREA(IOArea_p); |
| EIP207_Flow_HTE_Dscr_RecData_t * TR_Data_p; |
| EIP207_Flow_Error_t Flow_Rc; |
| |
| EIP207_FLOW_CHECK_POINTER(IOArea_p); |
| EIP207_FLOW_CHECK_INT_ATMOST(HashTableId + 1, |
| EIP207_FLOW_MAX_NOF_FLOW_HASH_TABLES_TO_USE); |
| EIP207_FLOW_CHECK_POINTER(TR_Dscr_p); |
| |
| TR_Data_p = (EIP207_Flow_HTE_Dscr_RecData_t*)TR_Dscr_p->InternalData_p; |
| |
| EIP207_FLOW_CHECK_POINTER(TR_Data_p); |
| EIP207_FLOW_CHECK_POINTER(TR_Data_p->HTE_Dscr_p); |
| |
| #ifdef EIP207_FLOW_STRICT_ARGS |
| // Provided transform record physical DMA address must be addressable by |
| // a 32-bit offset to the Transform Based Address installed via |
| // the EIP207_Flow_RC_BaseAddr_Set() function |
| if(!EIP207Lib_Flow_Is32bitAddressable( |
| TrueIOArea_p->HT_Params[HashTableId].BaseAddr.Addr, |
| TrueIOArea_p->HT_Params[HashTableId].BaseAddr.UpperAddr, |
| TR_Dscr_p->DMA_Addr.Addr, |
| TR_Dscr_p->DMA_Addr.UpperAddr)) |
| return EIP207_FLOW_ARGUMENT_ERROR; |
| |
| if (TR_Data_p->Type != EIP207_FLOW_REC_TRANSFORM_SMALL && |
| TR_Data_p->Type != EIP207_FLOW_REC_TRANSFORM_LARGE) |
| return EIP207_FLOW_INTERNAL_ERROR; |
| #endif // EIP207_FLOW_STRICT_ARGS |
| |
| Flow_Rc = EIP207Lib_Flow_DTL_Record_Remove( |
| TrueIOArea_p->Device, |
| HashTableId, |
| &TrueIOArea_p->HT_Params[HashTableId], |
| (EIP207_Flow_Dscr_t*)TR_Dscr_p); |
| if (Flow_Rc != EIP207_FLOW_NO_ERROR) |
| return Flow_Rc; |
| |
| IDENTIFIER_NOT_USED(TR_Data_p); |
| |
| #ifdef EIP207_FLOW_DEBUG_FSM |
| { |
| EIP207_Flow_Error_t rv; |
| uint32_t State = TrueIOArea_p->State; |
| |
| TrueIOArea_p->Rec_InstalledCounter--; |
| |
| // Transit to a new state |
| if (TrueIOArea_p->Rec_InstalledCounter == 0) |
| // Last record is removed |
| rv = EIP207_Flow_State_Set( |
| (EIP207_Flow_State_t* const)&State, |
| EIP207_FLOW_STATE_ENABLED); |
| else |
| // Non-last record is removed |
| rv = EIP207_Flow_State_Set( |
| (EIP207_Flow_State_t* const)&State, |
| EIP207_FLOW_STATE_INSTALLED); |
| |
| TrueIOArea_p->State = State; |
| |
| if (rv != EIP207_FLOW_NO_ERROR) |
| return EIP207_FLOW_ILLEGAL_IN_STATE; |
| } |
| #endif // EIP207_FLOW_DEBUG_FSM |
| |
| return EIP207_FLOW_NO_ERROR; |
| } |
| |
| |
| /* end of file eip207_flow_dtl.c */ |