diff options
author | Mandy Lavi <mandy.lavi@freescale.com> | 2013-03-24 16:40:18 (GMT) |
---|---|---|
committer | Fleming Andrew-AFLEMING <AFLEMING@freescale.com> | 2013-04-08 23:07:26 (GMT) |
commit | 3cc514986cb4e457458cc826288b6c2107c97907 (patch) | |
tree | 2985e48afc5dd20f44d51ef6aafdae917ce2698f /drivers/net/ethernet/freescale/fman/Peripherals/FM/Pcd/fm_replic.c | |
parent | 5767d52cec831b0e2927d34e91acd738cc1cb0ef (diff) | |
download | linux-fsl-qoriq-3cc514986cb4e457458cc826288b6c2107c97907.tar.xz |
fmd: fmd19 integration
Add fmd19 codebase, plus a minimal set of sources from dpaa-eth,
necessary for bare compilation
Change-Id: I390df8717671204e3d98a987135393bef4534e95
Signed-off-by: Mandy Lavi <mandy.lavi@freescale.com>
Signed-off-by: Bogdan Hamciuc <bogdan.hamciuc@freescale.com>
Reviewed-on: http://git.am.freescale.net:8181/1029
Reviewed-by: Fleming Andrew-AFLEMING <AFLEMING@freescale.com>
Tested-by: Fleming Andrew-AFLEMING <AFLEMING@freescale.com>
Diffstat (limited to 'drivers/net/ethernet/freescale/fman/Peripherals/FM/Pcd/fm_replic.c')
-rw-r--r-- | drivers/net/ethernet/freescale/fman/Peripherals/FM/Pcd/fm_replic.c | 993 |
1 files changed, 993 insertions, 0 deletions
diff --git a/drivers/net/ethernet/freescale/fman/Peripherals/FM/Pcd/fm_replic.c b/drivers/net/ethernet/freescale/fman/Peripherals/FM/Pcd/fm_replic.c new file mode 100644 index 0000000..ae72b25 --- /dev/null +++ b/drivers/net/ethernet/freescale/fman/Peripherals/FM/Pcd/fm_replic.c @@ -0,0 +1,993 @@ +/* + * Copyright 2008-2012 Freescale Semiconductor Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Freescale Semiconductor nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * + * ALTERNATIVELY, this software may be distributed under the terms of the + * GNU General Public License ("GPL") as published by the Free Software + * Foundation, either version 2 of that License or (at your option) any + * later version. + * + * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + +/****************************************************************************** + @File fm_replic.c + + @Description FM frame replicator +*//***************************************************************************/ +#include "std_ext.h" +#include "error_ext.h" +#include "string_ext.h" +#include "debug_ext.h" +#include "fm_pcd_ext.h" +#include "fm_muram_ext.h" +#include "fm_common.h" +#include "fm_hc.h" +#include "fm_replic.h" +#include "fm_cc.h" +#include "list_ext.h" + + +/****************************************/ +/* static functions */ +/****************************************/ +static uint8_t GetMemberPosition(t_FmPcdFrmReplicGroup *p_ReplicGroup, + uint32_t memberIndex, + bool isAddOperation) +{ + uint8_t memberPosition; + uint32_t lastMemberIndex; + + ASSERT_COND(p_ReplicGroup); + + /* the last member index is different between add and remove operation - + in case of remove - this is exactly the last member index + in case of add - this is the last member index + 1 - e.g. + if we have 4 members, the index of the actual last member is 3(because the + index starts from 0) therefore in order to add a new member as the last + member we shall use memberIndex = 4 and not 3 + */ + if (isAddOperation) + lastMemberIndex = p_ReplicGroup->numOfEntries; + else + lastMemberIndex = p_ReplicGroup->numOfEntries-1; + + /* last */ + if (memberIndex == lastMemberIndex) + memberPosition = FRM_REPLIC_LAST_MEMBER_INDEX; + else + { + /* first */ + if (memberIndex == 0) + memberPosition = FRM_REPLIC_FIRST_MEMBER_INDEX; + else + { + /* middle */ + ASSERT_COND(memberIndex < lastMemberIndex); + memberPosition = FRM_REPLIC_MIDDLE_MEMBER_INDEX; + } + } + return memberPosition; +} + +static t_Error MemberCheckParams(t_Handle h_FmPcd, + t_FmPcdCcNextEngineParams *p_MemberParams) +{ + t_Error err; + + + if ((p_MemberParams->nextEngine != e_FM_PCD_DONE) && + (p_MemberParams->nextEngine != e_FM_PCD_KG) && + (p_MemberParams->nextEngine != e_FM_PCD_PLCR)) + RETURN_ERROR(MAJOR, E_NOT_SUPPORTED, ("Next engine of a member should be MatchTable(cc) or Done or Policer")); + + /* check the regular parameters of the next engine */ + err = ValidateNextEngineParams(h_FmPcd, p_MemberParams, e_FM_PCD_CC_STATS_MODE_NONE); + if (err) + RETURN_ERROR(MAJOR, err, ("member next engine parameters")); + + return E_OK; +} + +static t_Error CheckParams(t_Handle h_FmPcd, + t_FmPcdFrmReplicGroupParams *p_ReplicGroupParam) +{ + int i; + t_Error err; + + /* check that max num of entries is at least 2 */ + if (!IN_RANGE(2, p_ReplicGroupParam->maxNumOfEntries, FM_PCD_FRM_REPLIC_MAX_NUM_OF_ENTRIES)) + RETURN_ERROR(MAJOR, E_NOT_IN_RANGE, ("maxNumOfEntries in the frame replicator parameters should be 2-%d",FM_PCD_FRM_REPLIC_MAX_NUM_OF_ENTRIES)); + + /* check that number of entries is greater than zero */ + if (!p_ReplicGroupParam->numOfEntries) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("numOFEntries in the frame replicator group should be greater than zero")); + + /* check that max num of entries is equal or greater than number of entries */ + if (p_ReplicGroupParam->maxNumOfEntries < p_ReplicGroupParam->numOfEntries) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("maxNumOfEntries should be equal or greater than numOfEntries")); + + for (i=0; i<p_ReplicGroupParam->numOfEntries; i++) + { + err = MemberCheckParams(h_FmPcd, &p_ReplicGroupParam->nextEngineParams[i]); + if (err) + RETURN_ERROR(MAJOR, err, ("member check parameters")); + } + return E_OK; +} + +static t_FmPcdFrmReplicMember *GetAvailableMember(t_FmPcdFrmReplicGroup *p_ReplicGroup) +{ + t_FmPcdFrmReplicMember *p_ReplicMember = NULL; + t_List *p_Next; + + if (!LIST_IsEmpty(&p_ReplicGroup->availableMembersList)) + { + p_Next = LIST_FIRST(&p_ReplicGroup->availableMembersList); + p_ReplicMember = LIST_OBJECT(p_Next, t_FmPcdFrmReplicMember, node); + ASSERT_COND(p_ReplicMember); + LIST_DelAndInit(p_Next); + } + return p_ReplicMember; +} + +static void PutAvailableMember(t_FmPcdFrmReplicGroup *p_ReplicGroup, + t_FmPcdFrmReplicMember *p_ReplicMember) +{ + LIST_AddToTail(&p_ReplicMember->node, &p_ReplicGroup->availableMembersList); +} + +static void AddMemberToList(t_FmPcdFrmReplicGroup *p_ReplicGroup, + t_FmPcdFrmReplicMember *p_CurrentMember, + t_List *p_ListHead) +{ + LIST_Add(&p_CurrentMember->node, p_ListHead); + + p_ReplicGroup->numOfEntries++; +} + +static void RemoveMemberFromList(t_FmPcdFrmReplicGroup *p_ReplicGroup, + t_FmPcdFrmReplicMember *p_CurrentMember) +{ + ASSERT_COND(p_ReplicGroup->numOfEntries); + LIST_DelAndInit(&p_CurrentMember->node); + p_ReplicGroup->numOfEntries--; +} + +static void LinkSourceToMember(t_FmPcdFrmReplicGroup *p_ReplicGroup, + t_AdOfTypeContLookup *p_SourceTd, + t_FmPcdFrmReplicMember *p_ReplicMember) +{ + t_FmPcd *p_FmPcd; + + ASSERT_COND(p_SourceTd); + ASSERT_COND(p_ReplicMember); + ASSERT_COND(p_ReplicGroup); + ASSERT_COND(p_ReplicGroup->h_FmPcd); + + /* Link the first member in the group to the source TD */ + p_FmPcd = p_ReplicGroup->h_FmPcd; + + WRITE_UINT32(p_SourceTd->matchTblPtr, + (uint32_t)(XX_VirtToPhys(p_ReplicMember->p_MemberAd) - + p_FmPcd->physicalMuramBase)); +} + +static void LinkMemberToMember(t_FmPcdFrmReplicGroup *p_ReplicGroup, + t_FmPcdFrmReplicMember *p_CurrentMember, + t_FmPcdFrmReplicMember *p_NextMember) +{ + t_AdOfTypeResult *p_CurrReplicAd = (t_AdOfTypeResult*)p_CurrentMember->p_MemberAd; + t_AdOfTypeResult *p_NextReplicAd = NULL; + t_FmPcd *p_FmPcd; + uint32_t offset = 0; + + /* Check if the next member exists or it's NULL (- means that this is the last member) */ + if (p_NextMember) + { + p_NextReplicAd = (t_AdOfTypeResult*)p_NextMember->p_MemberAd; + p_FmPcd = p_ReplicGroup->h_FmPcd; + offset = (XX_VirtToPhys(p_NextReplicAd) - (p_FmPcd->physicalMuramBase)); + offset = ((offset>>NEXT_FRM_REPLIC_ADDR_SHIFT)<< NEXT_FRM_REPLIC_MEMBER_INDEX_SHIFT); + } + + /* link the current AD to point to the AD of the next member */ + WRITE_UINT32(p_CurrReplicAd->res, offset); +} + +static t_Error ModifyDescriptor(t_FmPcdFrmReplicGroup *p_ReplicGroup, + void *p_OldDescriptor, + void *p_NewDescriptor) +{ + t_Handle h_Hc; + t_Error err; + t_FmPcd *p_FmPcd; + + ASSERT_COND(p_ReplicGroup); + ASSERT_COND(p_ReplicGroup->h_FmPcd); + ASSERT_COND(p_OldDescriptor); + ASSERT_COND(p_NewDescriptor); + + p_FmPcd = p_ReplicGroup->h_FmPcd; + h_Hc = FmPcdGetHcHandle(p_FmPcd); + if (!h_Hc) + RETURN_ERROR(MAJOR, E_INVALID_HANDLE, ("Host command")); + + err = FmHcPcdCcDoDynamicChange(h_Hc, + (uint32_t)(XX_VirtToPhys(p_OldDescriptor) - p_FmPcd->physicalMuramBase), + (uint32_t)(XX_VirtToPhys(p_NewDescriptor) - p_FmPcd->physicalMuramBase)); + if (err) + RETURN_ERROR(MAJOR, err, ("Dynamic change host command")); + + return E_OK; +} + +static void FillReplicAdOfTypeResult(void *p_ReplicAd, bool last) +{ + t_AdOfTypeResult *p_CurrReplicAd = (t_AdOfTypeResult*)p_ReplicAd; + uint32_t tmp; + + tmp = GET_UINT32(p_CurrReplicAd->plcrProfile); + if (last) + /* clear the NL bit in case it's the last member in the group*/ + WRITE_UINT32(p_CurrReplicAd->plcrProfile,(tmp & ~FRM_REPLIC_NL_BIT)); + else + /* set the NL bit in case it's not the last member in the group */ + WRITE_UINT32(p_CurrReplicAd->plcrProfile, (tmp |FRM_REPLIC_NL_BIT)); + + /* set FR bit in the action descriptor */ + tmp = GET_UINT32(p_CurrReplicAd->nia); + WRITE_UINT32(p_CurrReplicAd->nia, + (tmp | FRM_REPLIC_FR_BIT | FM_PCD_AD_RESULT_EXTENDED_MODE )); +} + +static void BuildSourceTd(void *p_Ad) +{ + t_AdOfTypeContLookup *p_SourceTd; + + ASSERT_COND(p_Ad); + + p_SourceTd = (t_AdOfTypeContLookup *)p_Ad; + + IOMemSet32((uint8_t*)p_SourceTd, 0, FM_PCD_CC_AD_ENTRY_SIZE); + + /* initialize the source table descriptor */ + WRITE_UINT32(p_SourceTd->ccAdBase, FM_PCD_AD_CONT_LOOKUP_TYPE); + WRITE_UINT32(p_SourceTd->pcAndOffsets, FRM_REPLIC_SOURCE_TD_OPCODE); +} + +static t_Error BuildShadowAndModifyDescriptor(t_FmPcdFrmReplicGroup *p_ReplicGroup, + t_FmPcdFrmReplicMember *p_NextMember, + t_FmPcdFrmReplicMember *p_CurrentMember, + bool sourceDescriptor, + bool last) +{ + t_FmPcd *p_FmPcd; + t_FmPcdFrmReplicMember shadowMember; + t_Error err; + + ASSERT_COND(p_ReplicGroup); + ASSERT_COND(p_ReplicGroup->h_FmPcd); + + p_FmPcd = p_ReplicGroup->h_FmPcd; + ASSERT_COND(p_FmPcd->p_CcShadow); + + if (!TRY_LOCK(p_FmPcd->h_ShadowSpinlock, &p_FmPcd->shadowLock)) + return ERROR_CODE(E_BUSY); + + if (sourceDescriptor) + { + BuildSourceTd(p_FmPcd->p_CcShadow); + LinkSourceToMember(p_ReplicGroup, p_FmPcd->p_CcShadow, p_NextMember); + + /* Modify the source table descriptor according to the prepared shadow descriptor */ + err = ModifyDescriptor(p_ReplicGroup, + p_ReplicGroup->p_SourceTd, + p_FmPcd->p_CcShadow/* new prepared source td */); + + RELEASE_LOCK(p_FmPcd->shadowLock); + if (err) + RETURN_ERROR(MAJOR, err, ("Modify source Descriptor in BuildShadowAndModifyDescriptor")); + + } + else + { + IO2IOCpy32(p_FmPcd->p_CcShadow, + p_CurrentMember->p_MemberAd, + FM_PCD_CC_AD_ENTRY_SIZE); + + /* update the last bit in the shadow ad */ + FillReplicAdOfTypeResult(p_FmPcd->p_CcShadow, last); + + shadowMember.p_MemberAd = p_FmPcd->p_CcShadow; + + /* update the next FR member index */ + LinkMemberToMember(p_ReplicGroup, &shadowMember, p_NextMember); + + /* Modify the next member according to the prepared shadow descriptor */ + err = ModifyDescriptor(p_ReplicGroup, + p_CurrentMember->p_MemberAd, + p_FmPcd->p_CcShadow); + + RELEASE_LOCK(p_FmPcd->shadowLock); + if (err) + RETURN_ERROR(MAJOR, err, ("Modify Descriptor in BuildShadowAndModifyDescriptor")); + } + + + return E_OK; +} + +static t_FmPcdFrmReplicMember* GetMemberByIndex(t_FmPcdFrmReplicGroup *p_ReplicGroup, + uint16_t memberIndex) +{ + int i=0; + t_List *p_Pos; + t_FmPcdFrmReplicMember *p_Member = NULL; + + LIST_FOR_EACH(p_Pos, &p_ReplicGroup->membersList) + { + if (i == memberIndex) + { + p_Member = LIST_OBJECT(p_Pos, t_FmPcdFrmReplicMember, node); + return p_Member; + } + i++; + } + return p_Member; +} + +static t_Error AllocMember(t_FmPcdFrmReplicGroup *p_ReplicGroup) +{ + t_FmPcdFrmReplicMember *p_CurrentMember; + t_Handle h_Muram; + + ASSERT_COND(p_ReplicGroup); + + h_Muram = FmPcdGetMuramHandle(p_ReplicGroup->h_FmPcd); + ASSERT_COND(h_Muram); + + /* Initialize an internal structure of a member to add to the available members list */ + p_CurrentMember = (t_FmPcdFrmReplicMember *)XX_Malloc(sizeof(t_FmPcdFrmReplicMember)); + if (!p_CurrentMember) + RETURN_ERROR(MAJOR, E_NO_MEMORY, ("Frame replicator member")); + + memset(p_CurrentMember, 0 ,sizeof(t_FmPcdFrmReplicMember)); + + /* Allocate the member AD */ + p_CurrentMember->p_MemberAd = + (t_AdOfTypeResult*)FM_MURAM_AllocMem(h_Muram, + FM_PCD_CC_AD_ENTRY_SIZE, + FM_PCD_CC_AD_TABLE_ALIGN); + + if (!p_CurrentMember->p_MemberAd) + RETURN_ERROR(MAJOR, E_NO_MEMORY, ("member AD table")); + + IOMemSet32((uint8_t*)p_CurrentMember->p_MemberAd, 0, FM_PCD_CC_AD_ENTRY_SIZE); + + /* Add the new member to the available members list */ + LIST_AddToTail(&p_CurrentMember->node, &(p_ReplicGroup->availableMembersList)); + + return E_OK; +} + +static t_FmPcdFrmReplicMember* InitMember(t_FmPcdFrmReplicGroup *p_ReplicGroup, + t_FmPcdCcNextEngineParams *p_MemberParams, + bool last) +{ + t_FmPcdFrmReplicMember *p_CurrentMember = NULL; + + ASSERT_COND(p_ReplicGroup); + + /* Get an available member from the internal members list */ + p_CurrentMember = GetAvailableMember(p_ReplicGroup); + if (!p_CurrentMember) + { + REPORT_ERROR(MAJOR, E_NOT_FOUND, ("Available member")); + return NULL; + } + p_CurrentMember->h_Manip = NULL; + + /* clear the Ad of the new member */ + IOMemSet32((uint8_t*)p_CurrentMember->p_MemberAd, 0, FM_PCD_CC_AD_ENTRY_SIZE); + + INIT_LIST(&p_CurrentMember->node); + + /* Initialize the Ad of the member */ + NextStepAd(p_CurrentMember->p_MemberAd, + NULL, + p_MemberParams, + p_ReplicGroup->h_FmPcd); + + /* save Manip handle (for free needs) */ + if (p_MemberParams->h_Manip) + p_CurrentMember->h_Manip = p_MemberParams->h_Manip; + + /* Initialize the relevant frame replicator fields in the AD */ + FillReplicAdOfTypeResult(p_CurrentMember->p_MemberAd, last); + + return p_CurrentMember; +} + +static void FreeMember(t_FmPcdFrmReplicGroup *p_ReplicGroup, + t_FmPcdFrmReplicMember *p_Member) +{ + /* Note: Can't free the member AD just returns the member to the available + member list - therefore only memset the AD */ + + /* zero the AD */ + IOMemSet32(p_Member->p_MemberAd, 0, FM_PCD_CC_AD_ENTRY_SIZE); + + + /* return the member to the available members list */ + PutAvailableMember(p_ReplicGroup, p_Member); +} + +static t_Error RemoveMember(t_FmPcdFrmReplicGroup *p_ReplicGroup, + uint16_t memberIndex) +{ + t_FmPcd *p_FmPcd = NULL; + t_FmPcdFrmReplicMember *p_CurrentMember = NULL, *p_PreviousMember = NULL, *p_NextMember = NULL; + t_Error err; + uint8_t memberPosition; + + p_FmPcd = p_ReplicGroup->h_FmPcd; + ASSERT_COND(p_FmPcd); + + p_CurrentMember = GetMemberByIndex(p_ReplicGroup, memberIndex); + ASSERT_COND(p_CurrentMember); + + /* determine the member position in the group */ + memberPosition = GetMemberPosition(p_ReplicGroup, + memberIndex, + FALSE/*remove operation*/); + + switch (memberPosition) + { + case FRM_REPLIC_FIRST_MEMBER_INDEX: + p_NextMember = GetMemberByIndex(p_ReplicGroup, (uint16_t)(memberIndex+1)); + ASSERT_COND(p_NextMember); + + /* update the source td itself by using a host command */ + err = BuildShadowAndModifyDescriptor(p_ReplicGroup, + p_NextMember, + NULL, + TRUE/*sourceDescriptor*/, + FALSE/*last*/); + break; + + case FRM_REPLIC_MIDDLE_MEMBER_INDEX: + p_PreviousMember = GetMemberByIndex(p_ReplicGroup, (uint16_t)(memberIndex-1)); + ASSERT_COND(p_PreviousMember); + + p_NextMember = GetMemberByIndex(p_ReplicGroup, (uint16_t)(memberIndex+1)); + ASSERT_COND(p_NextMember); + + err = BuildShadowAndModifyDescriptor(p_ReplicGroup, + p_NextMember, + p_PreviousMember, + FALSE/*sourceDescriptor*/, + FALSE/*last*/); + + break; + + case FRM_REPLIC_LAST_MEMBER_INDEX: + p_PreviousMember = GetMemberByIndex(p_ReplicGroup, (uint16_t)(memberIndex-1)); + ASSERT_COND(p_PreviousMember); + + err = BuildShadowAndModifyDescriptor(p_ReplicGroup, + NULL, + p_PreviousMember, + FALSE/*sourceDescriptor*/, + TRUE/*last*/); + break; + + default: + RETURN_ERROR(MAJOR, E_INVALID_SELECTION, ("member position in remove member")); + } + + if (err) + RETURN_ERROR(MAJOR, err, NO_MSG); + + if (p_CurrentMember->h_Manip) + { + FmPcdManipUpdateOwner(p_CurrentMember->h_Manip, FALSE); + p_CurrentMember->h_Manip = NULL; + } + + /* remove the member from the driver internal members list */ + RemoveMemberFromList(p_ReplicGroup, p_CurrentMember); + + /* return the member to the available members list */ + FreeMember(p_ReplicGroup, p_CurrentMember); + + return E_OK; +} + +static void DeleteGroup(t_FmPcdFrmReplicGroup *p_ReplicGroup) +{ + int i, j; + t_Handle h_Muram; + t_FmPcdFrmReplicMember *p_Member, *p_CurrentMember; + + if (p_ReplicGroup) + { + ASSERT_COND(p_ReplicGroup->h_FmPcd); + h_Muram = FmPcdGetMuramHandle(p_ReplicGroup->h_FmPcd); + ASSERT_COND(h_Muram); + + /* free the source table descriptor */ + if (p_ReplicGroup->p_SourceTd) + { + FM_MURAM_FreeMem(h_Muram, p_ReplicGroup->p_SourceTd); + p_ReplicGroup->p_SourceTd = NULL; + } + + /* Remove all members from the members linked list (hw and sw) and + return the members to the available members list */ + if (p_ReplicGroup->numOfEntries) + { + j = p_ReplicGroup->numOfEntries-1; + + /* manually removal of the member because there are no owners of + this group */ + for (i=j; i>=0; i--) + { + p_CurrentMember = GetMemberByIndex(p_ReplicGroup, (uint16_t)i/*memberIndex*/); + ASSERT_COND(p_CurrentMember); + + if (p_CurrentMember->h_Manip) + { + FmPcdManipUpdateOwner(p_CurrentMember->h_Manip, FALSE); + p_CurrentMember->h_Manip = NULL; + } + + /* remove the member from the internal driver members list */ + RemoveMemberFromList(p_ReplicGroup, p_CurrentMember); + + /* return the member to the available members list */ + FreeMember(p_ReplicGroup, p_CurrentMember); + } + } + + /* Free members AD */ + for (i=0; i<p_ReplicGroup->maxNumOfEntries; i++) + { + p_Member = GetAvailableMember(p_ReplicGroup); + ASSERT_COND(p_Member); + if (p_Member->p_MemberAd) + { + FM_MURAM_FreeMem(h_Muram, p_Member->p_MemberAd); + p_Member->p_MemberAd = NULL; + } + XX_Free(p_Member); + } + + /* release the group lock */ + if (p_ReplicGroup->p_Lock) + FmPcdReleaseLock(p_ReplicGroup->h_FmPcd, p_ReplicGroup->p_Lock); + + /* free the replicator group */ + XX_Free(p_ReplicGroup); + p_ReplicGroup = NULL; + } +} + + +/*****************************************************************************/ +/* Inter-module API routines */ +/*****************************************************************************/ + +/* NOTE: the inter-module routines are locked by cc in case of using them */ +void * FrmReplicGroupGetSourceTableDescriptor(t_Handle h_ReplicGroup) +{ + t_FmPcdFrmReplicGroup *p_ReplicGroup = (t_FmPcdFrmReplicGroup *)h_ReplicGroup; + ASSERT_COND(p_ReplicGroup); + + return (p_ReplicGroup->p_SourceTd); +} + +void FrmReplicGroupUpdateAd(t_Handle h_ReplicGroup, + void *p_Ad, + t_Handle *h_AdNew) +{ + t_FmPcdFrmReplicGroup *p_ReplicGroup = (t_FmPcdFrmReplicGroup *)h_ReplicGroup; + t_AdOfTypeResult *p_AdResult = (t_AdOfTypeResult*)p_Ad; + t_FmPcd *p_FmPcd; + + ASSERT_COND(p_ReplicGroup); + p_FmPcd = p_ReplicGroup->h_FmPcd; + + /* build a bypass ad */ + WRITE_UINT32(p_AdResult->fqid, FM_PCD_AD_BYPASS_TYPE | + (uint32_t)((XX_VirtToPhys(p_ReplicGroup->p_SourceTd)) - p_FmPcd->physicalMuramBase)); + + *h_AdNew = NULL; +} + +void FrmReplicGroupUpdateOwner(t_Handle h_ReplicGroup, + bool add) +{ + t_FmPcdFrmReplicGroup *p_ReplicGroup = (t_FmPcdFrmReplicGroup *)h_ReplicGroup; + ASSERT_COND(p_ReplicGroup); + + /* update the group owner counter */ + if (add) + p_ReplicGroup->owners++; + else + { + ASSERT_COND(p_ReplicGroup->owners); + p_ReplicGroup->owners--; + } +} + +t_Error FrmReplicGroupTryLock(t_Handle h_ReplicGroup) +{ + t_FmPcdFrmReplicGroup *p_ReplicGroup = (t_FmPcdFrmReplicGroup *)h_ReplicGroup; + + ASSERT_COND(h_ReplicGroup); + + if (FmPcdLockTryLock(p_ReplicGroup->p_Lock)) + return E_OK; + + return ERROR_CODE(E_BUSY); +} + +void FrmReplicGroupUnlock(t_Handle h_ReplicGroup) +{ + t_FmPcdFrmReplicGroup *p_ReplicGroup = (t_FmPcdFrmReplicGroup *)h_ReplicGroup; + + ASSERT_COND(h_ReplicGroup); + + FmPcdLockUnlock(p_ReplicGroup->p_Lock); +} +/*********************** End of inter-module routines ************************/ + + +/****************************************/ +/* API Init unit functions */ +/****************************************/ +t_Handle FM_PCD_FrmReplicSetGroup(t_Handle h_FmPcd, + t_FmPcdFrmReplicGroupParams *p_ReplicGroupParam) +{ + t_FmPcdFrmReplicGroup *p_ReplicGroup; + t_FmPcdFrmReplicMember *p_CurrentMember, *p_NextMember = NULL; + int i; + t_Error err; + bool last = FALSE; + t_Handle h_Muram; + + SANITY_CHECK_RETURN_VALUE(h_FmPcd, E_INVALID_HANDLE, NULL); + SANITY_CHECK_RETURN_VALUE(p_ReplicGroupParam, E_INVALID_HANDLE, NULL); + + if (!FmPcdIsAdvancedOffloadSupported(h_FmPcd)) + { + REPORT_ERROR(MAJOR, E_INVALID_STATE, ("Advanced-offload must be enabled")); + return NULL; + } + + err = CheckParams(h_FmPcd, p_ReplicGroupParam); + if (err) + { + REPORT_ERROR(MAJOR, err, (NO_MSG)); + return NULL; + } + + p_ReplicGroup = (t_FmPcdFrmReplicGroup*)XX_Malloc(sizeof(t_FmPcdFrmReplicGroup)); + if (!p_ReplicGroup) + { + REPORT_ERROR(MAJOR, E_NO_MEMORY, ("No memory")); + return NULL; + } + memset(p_ReplicGroup, 0, sizeof(t_FmPcdFrmReplicGroup)); + + /* initialize lists for internal driver use */ + INIT_LIST(&p_ReplicGroup->availableMembersList); + INIT_LIST(&p_ReplicGroup->membersList); + + p_ReplicGroup->h_FmPcd = h_FmPcd; + + h_Muram = FmPcdGetMuramHandle(p_ReplicGroup->h_FmPcd); + ASSERT_COND(h_Muram); + + /* initialize the group lock */ + p_ReplicGroup->p_Lock = FmPcdAcquireLock(p_ReplicGroup->h_FmPcd); + if (!p_ReplicGroup->p_Lock) + { + REPORT_ERROR(MAJOR, E_NO_MEMORY, ("Replic group lock")); + DeleteGroup(p_ReplicGroup); + return NULL; + } + + /* Allocate the frame replicator source table descriptor */ + p_ReplicGroup->p_SourceTd = + (t_Handle)FM_MURAM_AllocMem(h_Muram, + FM_PCD_CC_AD_ENTRY_SIZE, + FM_PCD_CC_AD_TABLE_ALIGN); + if (!p_ReplicGroup->p_SourceTd) + { + REPORT_ERROR(MAJOR, E_NO_MEMORY, ("frame replicator source table descriptor")); + DeleteGroup(p_ReplicGroup); + return NULL; + } + + /* update the shadow size - required for the host commands */ + err = FmPcdUpdateCcShadow(p_ReplicGroup->h_FmPcd, + FM_PCD_CC_AD_ENTRY_SIZE, + FM_PCD_CC_AD_TABLE_ALIGN); + if (err) + { + REPORT_ERROR(MAJOR, err, ("Update CC shadow")); + DeleteGroup(p_ReplicGroup); + return NULL; + } + + p_ReplicGroup->maxNumOfEntries = p_ReplicGroupParam->maxNumOfEntries; + + /* Allocate the maximal number of members ADs and Statistics AD for the group + It prevents allocation of Muram in run-time */ + for (i=0; i<p_ReplicGroup->maxNumOfEntries; i++) + { + err = AllocMember(p_ReplicGroup); + if (err) + { + REPORT_ERROR(MAJOR, err, ("allocate a new member")); + DeleteGroup(p_ReplicGroup); + return NULL; + } + } + + /* Initialize the members linked lists: + (hw - the one that is used by the FMan controller and + sw - the one that is managed by the driver internally) */ + for (i=(p_ReplicGroupParam->numOfEntries-1); i>=0; i--) + { + /* check if this is the last member in the group */ + if (i == (p_ReplicGroupParam->numOfEntries-1)) + last = TRUE; + else + last = FALSE; + + /* Initialize a new member */ + p_CurrentMember = InitMember(p_ReplicGroup, + &(p_ReplicGroupParam->nextEngineParams[i]), + last); + if (!p_CurrentMember) + { + REPORT_ERROR(MAJOR, E_INVALID_HANDLE, ("No available member")); + DeleteGroup(p_ReplicGroup); + return NULL; + } + + /* Build the members group - link two consecutive members in the hw linked list */ + LinkMemberToMember(p_ReplicGroup, p_CurrentMember, p_NextMember); + + /* update the driver internal members list to be compatible to the hw members linked list */ + AddMemberToList(p_ReplicGroup, p_CurrentMember, &p_ReplicGroup->membersList); + + p_NextMember = p_CurrentMember; + } + + /* initialize the source table descriptor */ + BuildSourceTd(p_ReplicGroup->p_SourceTd); + + /* link the source table descriptor to point to the first member in the group */ + LinkSourceToMember(p_ReplicGroup, p_ReplicGroup->p_SourceTd, p_NextMember); + + return p_ReplicGroup; +} + +t_Error FM_PCD_FrmReplicDeleteGroup(t_Handle h_ReplicGroup) +{ + t_FmPcdFrmReplicGroup *p_ReplicGroup = (t_FmPcdFrmReplicGroup *)h_ReplicGroup; + + SANITY_CHECK_RETURN_ERROR(p_ReplicGroup, E_INVALID_HANDLE); + + if (p_ReplicGroup->owners) + RETURN_ERROR(MAJOR, + E_INVALID_STATE, + ("the group has owners and can't be deleted")); + + DeleteGroup(p_ReplicGroup); + + return E_OK; +} + + +/*****************************************************************************/ +/* API Run-time Frame replicator Control unit functions */ +/*****************************************************************************/ +t_Error FM_PCD_FrmReplicAddMember(t_Handle h_ReplicGroup, + uint16_t memberIndex, + t_FmPcdCcNextEngineParams *p_MemberParams) +{ + t_FmPcdFrmReplicGroup *p_ReplicGroup = (t_FmPcdFrmReplicGroup*) h_ReplicGroup; + t_FmPcdFrmReplicMember *p_NewMember, *p_CurrentMember = NULL, *p_PreviousMember = NULL; + t_Error err; + uint8_t memberPosition; + + SANITY_CHECK_RETURN_ERROR(p_ReplicGroup, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_MemberParams, E_INVALID_HANDLE); + + /* group lock */ + err = FrmReplicGroupTryLock(p_ReplicGroup); + if (err) + { + if (GET_ERROR_TYPE(err) == E_BUSY) + return ERROR_CODE(E_BUSY); + else + RETURN_ERROR(MAJOR, err, ("try lock in Add member")); + } + + if (memberIndex > p_ReplicGroup->numOfEntries) + { + /* unlock */ + FrmReplicGroupUnlock(p_ReplicGroup); + RETURN_ERROR(MAJOR, E_INVALID_SELECTION, + ("memberIndex is greater than the members in the list")); + } + + if (memberIndex >= p_ReplicGroup->maxNumOfEntries) + { + /* unlock */ + FrmReplicGroupUnlock(p_ReplicGroup); + RETURN_ERROR(MAJOR, E_INVALID_SELECTION, ("memberIndex is greater than the allowed number of members in the group")); + } + + if ((p_ReplicGroup->numOfEntries + 1) > FM_PCD_FRM_REPLIC_MAX_NUM_OF_ENTRIES) + { + /* unlock */ + FrmReplicGroupUnlock(p_ReplicGroup); + RETURN_ERROR(MAJOR, E_INVALID_VALUE, + ("numOfEntries with new entry can not be larger than %d\n", + FM_PCD_FRM_REPLIC_MAX_NUM_OF_ENTRIES)); + } + + err = MemberCheckParams(p_ReplicGroup->h_FmPcd, p_MemberParams); + if (err) + { + /* unlock */ + FrmReplicGroupUnlock(p_ReplicGroup); + RETURN_ERROR(MAJOR, err, ("member check parameters in add operation")); + } + /* determine the member position in the group */ + memberPosition = GetMemberPosition(p_ReplicGroup, + memberIndex, + TRUE/* add operation */); + + /* Initialize a new member */ + p_NewMember = InitMember(p_ReplicGroup, + p_MemberParams, + (memberPosition == FRM_REPLIC_LAST_MEMBER_INDEX ? TRUE : FALSE)); + if (!p_NewMember) + { + /* unlock */ + FrmReplicGroupUnlock(p_ReplicGroup); + RETURN_ERROR(MAJOR, E_INVALID_HANDLE, ("No available member")); + } + + switch (memberPosition) + { + case FRM_REPLIC_FIRST_MEMBER_INDEX: + p_CurrentMember = GetMemberByIndex(p_ReplicGroup, memberIndex); + ASSERT_COND(p_CurrentMember); + + LinkMemberToMember(p_ReplicGroup, p_NewMember, p_CurrentMember); + + /* update the internal group source TD */ + LinkSourceToMember(p_ReplicGroup, + p_ReplicGroup->p_SourceTd, + p_NewMember); + + /* add member to the internal sw member list */ + AddMemberToList(p_ReplicGroup, + p_NewMember, + &p_ReplicGroup->membersList); + break; + + case FRM_REPLIC_MIDDLE_MEMBER_INDEX: + p_CurrentMember = GetMemberByIndex(p_ReplicGroup, memberIndex); + ASSERT_COND(p_CurrentMember); + + p_PreviousMember = GetMemberByIndex(p_ReplicGroup, (uint16_t)(memberIndex-1)); + ASSERT_COND(p_PreviousMember); + + LinkMemberToMember(p_ReplicGroup, p_NewMember, p_CurrentMember); + LinkMemberToMember(p_ReplicGroup, p_PreviousMember, p_NewMember); + + AddMemberToList(p_ReplicGroup, p_NewMember, &p_PreviousMember->node); + break; + + case FRM_REPLIC_LAST_MEMBER_INDEX: + p_PreviousMember = GetMemberByIndex(p_ReplicGroup, (uint16_t)(memberIndex-1)); + ASSERT_COND(p_PreviousMember); + + LinkMemberToMember(p_ReplicGroup, p_PreviousMember, p_NewMember); + FillReplicAdOfTypeResult(p_PreviousMember->p_MemberAd, FALSE/*last*/); + + /* add the new member to the internal sw member list */ + AddMemberToList(p_ReplicGroup, p_NewMember, &p_PreviousMember->node); + break; + + default: + /* unlock */ + FrmReplicGroupUnlock(p_ReplicGroup); + RETURN_ERROR(MAJOR, E_INVALID_SELECTION, ("member position in add member")); + + } + + /* unlock */ + FrmReplicGroupUnlock(p_ReplicGroup); + + return E_OK; +} + +t_Error FM_PCD_FrmReplicRemoveMember(t_Handle h_ReplicGroup, + uint16_t memberIndex) +{ + t_FmPcdFrmReplicGroup *p_ReplicGroup = (t_FmPcdFrmReplicGroup*) h_ReplicGroup; + t_Error err; + + SANITY_CHECK_RETURN_ERROR(p_ReplicGroup, E_INVALID_HANDLE); + + /* lock */ + err = FrmReplicGroupTryLock(p_ReplicGroup); + if (err) + { + if (GET_ERROR_TYPE(err) == E_BUSY) + return ERROR_CODE(E_BUSY); + else + RETURN_ERROR(MAJOR, err, ("try lock in Remove member")); + } + + if (memberIndex >= p_ReplicGroup->numOfEntries) + RETURN_ERROR(MAJOR, E_INVALID_SELECTION, ("member index to remove")); + + /* Design decision: group must contain at least one member + No possibility to remove the last member from the group */ + if (p_ReplicGroup->numOfEntries == 1) + RETURN_ERROR(MAJOR, E_CONFLICT, ("Can't remove the last member. At least one member should be related to a group.")); + + err = RemoveMember(p_ReplicGroup, memberIndex); + + /* unlock */ + FrmReplicGroupUnlock(p_ReplicGroup); + + switch (GET_ERROR_TYPE(err)) + { + case E_OK: + return E_OK; + + case E_BUSY: + DBG(TRACE, ("E_BUSY error")); + return ERROR_CODE(E_BUSY); + + default: + RETURN_ERROR(MAJOR, err, NO_MSG); + } +} + +/*********************** End of API routines ************************/ + + |