Path: blob/main/sys/contrib/ncsw/Peripherals/FM/Pcd/fm_replic.c
48524 views
/*1* Copyright 2008-2012 Freescale Semiconductor Inc.2*3* Redistribution and use in source and binary forms, with or without4* modification, are permitted provided that the following conditions are met:5* * Redistributions of source code must retain the above copyright6* notice, this list of conditions and the following disclaimer.7* * Redistributions in binary form must reproduce the above copyright8* notice, this list of conditions and the following disclaimer in the9* documentation and/or other materials provided with the distribution.10* * Neither the name of Freescale Semiconductor nor the11* names of its contributors may be used to endorse or promote products12* derived from this software without specific prior written permission.13*14*15* ALTERNATIVELY, this software may be distributed under the terms of the16* GNU General Public License ("GPL") as published by the Free Software17* Foundation, either version 2 of that License or (at your option) any18* later version.19*20* THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY21* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED22* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE23* DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY24* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES25* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;26* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND27* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT28* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS29* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.30*/313233/******************************************************************************34@File fm_replic.c3536@Description FM frame replicator37*//***************************************************************************/38#include "std_ext.h"39#include "error_ext.h"40#include "string_ext.h"41#include "debug_ext.h"42#include "fm_pcd_ext.h"43#include "fm_muram_ext.h"44#include "fm_common.h"45#include "fm_hc.h"46#include "fm_replic.h"47#include "fm_cc.h"48#include "list_ext.h"495051/****************************************/52/* static functions */53/****************************************/54static uint8_t GetMemberPosition(t_FmPcdFrmReplicGroup *p_ReplicGroup,55uint32_t memberIndex,56bool isAddOperation)57{58uint8_t memberPosition;59uint32_t lastMemberIndex;6061ASSERT_COND(p_ReplicGroup);6263/* the last member index is different between add and remove operation -64in case of remove - this is exactly the last member index65in case of add - this is the last member index + 1 - e.g.66if we have 4 members, the index of the actual last member is 3(because the67index starts from 0) therefore in order to add a new member as the last68member we shall use memberIndex = 4 and not 369*/70if (isAddOperation)71lastMemberIndex = p_ReplicGroup->numOfEntries;72else73lastMemberIndex = p_ReplicGroup->numOfEntries-1;7475/* last */76if (memberIndex == lastMemberIndex)77memberPosition = FRM_REPLIC_LAST_MEMBER_INDEX;78else79{80/* first */81if (memberIndex == 0)82memberPosition = FRM_REPLIC_FIRST_MEMBER_INDEX;83else84{85/* middle */86ASSERT_COND(memberIndex < lastMemberIndex);87memberPosition = FRM_REPLIC_MIDDLE_MEMBER_INDEX;88}89}90return memberPosition;91}9293static t_Error MemberCheckParams(t_Handle h_FmPcd,94t_FmPcdCcNextEngineParams *p_MemberParams)95{96t_Error err;979899if ((p_MemberParams->nextEngine != e_FM_PCD_DONE) &&100(p_MemberParams->nextEngine != e_FM_PCD_KG) &&101(p_MemberParams->nextEngine != e_FM_PCD_PLCR))102RETURN_ERROR(MAJOR, E_NOT_SUPPORTED, ("Next engine of a member should be MatchTable(cc) or Done or Policer"));103104/* check the regular parameters of the next engine */105err = ValidateNextEngineParams(h_FmPcd, p_MemberParams, e_FM_PCD_CC_STATS_MODE_NONE);106if (err)107RETURN_ERROR(MAJOR, err, ("member next engine parameters"));108109return E_OK;110}111112static t_Error CheckParams(t_Handle h_FmPcd,113t_FmPcdFrmReplicGroupParams *p_ReplicGroupParam)114{115int i;116t_Error err;117118/* check that max num of entries is at least 2 */119if (!IN_RANGE(2, p_ReplicGroupParam->maxNumOfEntries, FM_PCD_FRM_REPLIC_MAX_NUM_OF_ENTRIES))120RETURN_ERROR(MAJOR, E_NOT_IN_RANGE, ("maxNumOfEntries in the frame replicator parameters should be 2-%d",FM_PCD_FRM_REPLIC_MAX_NUM_OF_ENTRIES));121122/* check that number of entries is greater than zero */123if (!p_ReplicGroupParam->numOfEntries)124RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("numOFEntries in the frame replicator group should be greater than zero"));125126/* check that max num of entries is equal or greater than number of entries */127if (p_ReplicGroupParam->maxNumOfEntries < p_ReplicGroupParam->numOfEntries)128RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("maxNumOfEntries should be equal or greater than numOfEntries"));129130for (i=0; i<p_ReplicGroupParam->numOfEntries; i++)131{132err = MemberCheckParams(h_FmPcd, &p_ReplicGroupParam->nextEngineParams[i]);133if (err)134RETURN_ERROR(MAJOR, err, ("member check parameters"));135}136return E_OK;137}138139static t_FmPcdFrmReplicMember *GetAvailableMember(t_FmPcdFrmReplicGroup *p_ReplicGroup)140{141t_FmPcdFrmReplicMember *p_ReplicMember = NULL;142t_List *p_Next;143144if (!LIST_IsEmpty(&p_ReplicGroup->availableMembersList))145{146p_Next = LIST_FIRST(&p_ReplicGroup->availableMembersList);147p_ReplicMember = LIST_OBJECT(p_Next, t_FmPcdFrmReplicMember, node);148ASSERT_COND(p_ReplicMember);149LIST_DelAndInit(p_Next);150}151return p_ReplicMember;152}153154static void PutAvailableMember(t_FmPcdFrmReplicGroup *p_ReplicGroup,155t_FmPcdFrmReplicMember *p_ReplicMember)156{157LIST_AddToTail(&p_ReplicMember->node, &p_ReplicGroup->availableMembersList);158}159160static void AddMemberToList(t_FmPcdFrmReplicGroup *p_ReplicGroup,161t_FmPcdFrmReplicMember *p_CurrentMember,162t_List *p_ListHead)163{164LIST_Add(&p_CurrentMember->node, p_ListHead);165166p_ReplicGroup->numOfEntries++;167}168169static void RemoveMemberFromList(t_FmPcdFrmReplicGroup *p_ReplicGroup,170t_FmPcdFrmReplicMember *p_CurrentMember)171{172ASSERT_COND(p_ReplicGroup->numOfEntries);173LIST_DelAndInit(&p_CurrentMember->node);174p_ReplicGroup->numOfEntries--;175}176177static void LinkSourceToMember(t_FmPcdFrmReplicGroup *p_ReplicGroup,178t_AdOfTypeContLookup *p_SourceTd,179t_FmPcdFrmReplicMember *p_ReplicMember)180{181t_FmPcd *p_FmPcd;182183ASSERT_COND(p_SourceTd);184ASSERT_COND(p_ReplicMember);185ASSERT_COND(p_ReplicGroup);186ASSERT_COND(p_ReplicGroup->h_FmPcd);187188/* Link the first member in the group to the source TD */189p_FmPcd = p_ReplicGroup->h_FmPcd;190191WRITE_UINT32(p_SourceTd->matchTblPtr,192(uint32_t)(XX_VirtToPhys(p_ReplicMember->p_MemberAd) -193p_FmPcd->physicalMuramBase));194}195196static void LinkMemberToMember(t_FmPcdFrmReplicGroup *p_ReplicGroup,197t_FmPcdFrmReplicMember *p_CurrentMember,198t_FmPcdFrmReplicMember *p_NextMember)199{200t_AdOfTypeResult *p_CurrReplicAd = (t_AdOfTypeResult*)p_CurrentMember->p_MemberAd;201t_AdOfTypeResult *p_NextReplicAd = NULL;202t_FmPcd *p_FmPcd;203uint32_t offset = 0;204205/* Check if the next member exists or it's NULL (- means that this is the last member) */206if (p_NextMember)207{208p_NextReplicAd = (t_AdOfTypeResult*)p_NextMember->p_MemberAd;209p_FmPcd = p_ReplicGroup->h_FmPcd;210offset = (XX_VirtToPhys(p_NextReplicAd) - (p_FmPcd->physicalMuramBase));211offset = ((offset>>NEXT_FRM_REPLIC_ADDR_SHIFT)<< NEXT_FRM_REPLIC_MEMBER_INDEX_SHIFT);212}213214/* link the current AD to point to the AD of the next member */215WRITE_UINT32(p_CurrReplicAd->res, offset);216}217218static t_Error ModifyDescriptor(t_FmPcdFrmReplicGroup *p_ReplicGroup,219void *p_OldDescriptor,220void *p_NewDescriptor)221{222t_Handle h_Hc;223t_Error err;224t_FmPcd *p_FmPcd;225226ASSERT_COND(p_ReplicGroup);227ASSERT_COND(p_ReplicGroup->h_FmPcd);228ASSERT_COND(p_OldDescriptor);229ASSERT_COND(p_NewDescriptor);230231p_FmPcd = p_ReplicGroup->h_FmPcd;232h_Hc = FmPcdGetHcHandle(p_FmPcd);233if (!h_Hc)234RETURN_ERROR(MAJOR, E_INVALID_HANDLE, ("Host command"));235236err = FmHcPcdCcDoDynamicChange(h_Hc,237(uint32_t)(XX_VirtToPhys(p_OldDescriptor) - p_FmPcd->physicalMuramBase),238(uint32_t)(XX_VirtToPhys(p_NewDescriptor) - p_FmPcd->physicalMuramBase));239if (err)240RETURN_ERROR(MAJOR, err, ("Dynamic change host command"));241242return E_OK;243}244245static void FillReplicAdOfTypeResult(void *p_ReplicAd, bool last)246{247t_AdOfTypeResult *p_CurrReplicAd = (t_AdOfTypeResult*)p_ReplicAd;248uint32_t tmp;249250tmp = GET_UINT32(p_CurrReplicAd->plcrProfile);251if (last)252/* clear the NL bit in case it's the last member in the group*/253WRITE_UINT32(p_CurrReplicAd->plcrProfile,(tmp & ~FRM_REPLIC_NL_BIT));254else255/* set the NL bit in case it's not the last member in the group */256WRITE_UINT32(p_CurrReplicAd->plcrProfile, (tmp |FRM_REPLIC_NL_BIT));257258/* set FR bit in the action descriptor */259tmp = GET_UINT32(p_CurrReplicAd->nia);260WRITE_UINT32(p_CurrReplicAd->nia,261(tmp | FRM_REPLIC_FR_BIT | FM_PCD_AD_RESULT_EXTENDED_MODE ));262}263264static void BuildSourceTd(void *p_Ad)265{266t_AdOfTypeContLookup *p_SourceTd;267268ASSERT_COND(p_Ad);269270p_SourceTd = (t_AdOfTypeContLookup *)p_Ad;271272IOMemSet32((uint8_t*)p_SourceTd, 0, FM_PCD_CC_AD_ENTRY_SIZE);273274/* initialize the source table descriptor */275WRITE_UINT32(p_SourceTd->ccAdBase, FM_PCD_AD_CONT_LOOKUP_TYPE);276WRITE_UINT32(p_SourceTd->pcAndOffsets, FRM_REPLIC_SOURCE_TD_OPCODE);277}278279static t_Error BuildShadowAndModifyDescriptor(t_FmPcdFrmReplicGroup *p_ReplicGroup,280t_FmPcdFrmReplicMember *p_NextMember,281t_FmPcdFrmReplicMember *p_CurrentMember,282bool sourceDescriptor,283bool last)284{285t_FmPcd *p_FmPcd;286t_FmPcdFrmReplicMember shadowMember;287t_Error err;288289ASSERT_COND(p_ReplicGroup);290ASSERT_COND(p_ReplicGroup->h_FmPcd);291292p_FmPcd = p_ReplicGroup->h_FmPcd;293ASSERT_COND(p_FmPcd->p_CcShadow);294295if (!TRY_LOCK(p_FmPcd->h_ShadowSpinlock, &p_FmPcd->shadowLock))296return ERROR_CODE(E_BUSY);297298if (sourceDescriptor)299{300BuildSourceTd(p_FmPcd->p_CcShadow);301LinkSourceToMember(p_ReplicGroup, p_FmPcd->p_CcShadow, p_NextMember);302303/* Modify the source table descriptor according to the prepared shadow descriptor */304err = ModifyDescriptor(p_ReplicGroup,305p_ReplicGroup->p_SourceTd,306p_FmPcd->p_CcShadow/* new prepared source td */);307308RELEASE_LOCK(p_FmPcd->shadowLock);309if (err)310RETURN_ERROR(MAJOR, err, ("Modify source Descriptor in BuildShadowAndModifyDescriptor"));311312}313else314{315IO2IOCpy32(p_FmPcd->p_CcShadow,316p_CurrentMember->p_MemberAd,317FM_PCD_CC_AD_ENTRY_SIZE);318319/* update the last bit in the shadow ad */320FillReplicAdOfTypeResult(p_FmPcd->p_CcShadow, last);321322shadowMember.p_MemberAd = p_FmPcd->p_CcShadow;323324/* update the next FR member index */325LinkMemberToMember(p_ReplicGroup, &shadowMember, p_NextMember);326327/* Modify the next member according to the prepared shadow descriptor */328err = ModifyDescriptor(p_ReplicGroup,329p_CurrentMember->p_MemberAd,330p_FmPcd->p_CcShadow);331332RELEASE_LOCK(p_FmPcd->shadowLock);333if (err)334RETURN_ERROR(MAJOR, err, ("Modify Descriptor in BuildShadowAndModifyDescriptor"));335}336337338return E_OK;339}340341static t_FmPcdFrmReplicMember* GetMemberByIndex(t_FmPcdFrmReplicGroup *p_ReplicGroup,342uint16_t memberIndex)343{344int i=0;345t_List *p_Pos;346t_FmPcdFrmReplicMember *p_Member = NULL;347348LIST_FOR_EACH(p_Pos, &p_ReplicGroup->membersList)349{350if (i == memberIndex)351{352p_Member = LIST_OBJECT(p_Pos, t_FmPcdFrmReplicMember, node);353return p_Member;354}355i++;356}357return p_Member;358}359360static t_Error AllocMember(t_FmPcdFrmReplicGroup *p_ReplicGroup)361{362t_FmPcdFrmReplicMember *p_CurrentMember;363t_Handle h_Muram;364365ASSERT_COND(p_ReplicGroup);366367h_Muram = FmPcdGetMuramHandle(p_ReplicGroup->h_FmPcd);368ASSERT_COND(h_Muram);369370/* Initialize an internal structure of a member to add to the available members list */371p_CurrentMember = (t_FmPcdFrmReplicMember *)XX_Malloc(sizeof(t_FmPcdFrmReplicMember));372if (!p_CurrentMember)373RETURN_ERROR(MAJOR, E_NO_MEMORY, ("Frame replicator member"));374375memset(p_CurrentMember, 0 ,sizeof(t_FmPcdFrmReplicMember));376377/* Allocate the member AD */378p_CurrentMember->p_MemberAd =379(t_AdOfTypeResult*)FM_MURAM_AllocMem(h_Muram,380FM_PCD_CC_AD_ENTRY_SIZE,381FM_PCD_CC_AD_TABLE_ALIGN);382if (!p_CurrentMember->p_MemberAd)383{384XX_Free(p_CurrentMember);385RETURN_ERROR(MAJOR, E_NO_MEMORY, ("member AD table"));386}387IOMemSet32((uint8_t*)p_CurrentMember->p_MemberAd, 0, FM_PCD_CC_AD_ENTRY_SIZE);388389/* Add the new member to the available members list */390LIST_AddToTail(&p_CurrentMember->node, &(p_ReplicGroup->availableMembersList));391392return E_OK;393}394395static t_FmPcdFrmReplicMember* InitMember(t_FmPcdFrmReplicGroup *p_ReplicGroup,396t_FmPcdCcNextEngineParams *p_MemberParams,397bool last)398{399t_FmPcdFrmReplicMember *p_CurrentMember = NULL;400401ASSERT_COND(p_ReplicGroup);402403/* Get an available member from the internal members list */404p_CurrentMember = GetAvailableMember(p_ReplicGroup);405if (!p_CurrentMember)406{407REPORT_ERROR(MAJOR, E_NOT_FOUND, ("Available member"));408return NULL;409}410p_CurrentMember->h_Manip = NULL;411412/* clear the Ad of the new member */413IOMemSet32((uint8_t*)p_CurrentMember->p_MemberAd, 0, FM_PCD_CC_AD_ENTRY_SIZE);414415INIT_LIST(&p_CurrentMember->node);416417/* Initialize the Ad of the member */418NextStepAd(p_CurrentMember->p_MemberAd,419NULL,420p_MemberParams,421p_ReplicGroup->h_FmPcd);422423/* save Manip handle (for free needs) */424if (p_MemberParams->h_Manip)425p_CurrentMember->h_Manip = p_MemberParams->h_Manip;426427/* Initialize the relevant frame replicator fields in the AD */428FillReplicAdOfTypeResult(p_CurrentMember->p_MemberAd, last);429430return p_CurrentMember;431}432433static void FreeMember(t_FmPcdFrmReplicGroup *p_ReplicGroup,434t_FmPcdFrmReplicMember *p_Member)435{436/* Note: Can't free the member AD just returns the member to the available437member list - therefore only memset the AD */438439/* zero the AD */440IOMemSet32(p_Member->p_MemberAd, 0, FM_PCD_CC_AD_ENTRY_SIZE);441442443/* return the member to the available members list */444PutAvailableMember(p_ReplicGroup, p_Member);445}446447static t_Error RemoveMember(t_FmPcdFrmReplicGroup *p_ReplicGroup,448uint16_t memberIndex)449{450t_FmPcd *p_FmPcd = NULL;451t_FmPcdFrmReplicMember *p_CurrentMember = NULL, *p_PreviousMember = NULL, *p_NextMember = NULL;452t_Error err;453uint8_t memberPosition;454455p_FmPcd = p_ReplicGroup->h_FmPcd;456ASSERT_COND(p_FmPcd);457UNUSED(p_FmPcd);458459p_CurrentMember = GetMemberByIndex(p_ReplicGroup, memberIndex);460ASSERT_COND(p_CurrentMember);461462/* determine the member position in the group */463memberPosition = GetMemberPosition(p_ReplicGroup,464memberIndex,465FALSE/*remove operation*/);466467switch (memberPosition)468{469case FRM_REPLIC_FIRST_MEMBER_INDEX:470p_NextMember = GetMemberByIndex(p_ReplicGroup, (uint16_t)(memberIndex+1));471ASSERT_COND(p_NextMember);472473/* update the source td itself by using a host command */474err = BuildShadowAndModifyDescriptor(p_ReplicGroup,475p_NextMember,476NULL,477TRUE/*sourceDescriptor*/,478FALSE/*last*/);479break;480481case FRM_REPLIC_MIDDLE_MEMBER_INDEX:482p_PreviousMember = GetMemberByIndex(p_ReplicGroup, (uint16_t)(memberIndex-1));483ASSERT_COND(p_PreviousMember);484485p_NextMember = GetMemberByIndex(p_ReplicGroup, (uint16_t)(memberIndex+1));486ASSERT_COND(p_NextMember);487488err = BuildShadowAndModifyDescriptor(p_ReplicGroup,489p_NextMember,490p_PreviousMember,491FALSE/*sourceDescriptor*/,492FALSE/*last*/);493494break;495496case FRM_REPLIC_LAST_MEMBER_INDEX:497p_PreviousMember = GetMemberByIndex(p_ReplicGroup, (uint16_t)(memberIndex-1));498ASSERT_COND(p_PreviousMember);499500err = BuildShadowAndModifyDescriptor(p_ReplicGroup,501NULL,502p_PreviousMember,503FALSE/*sourceDescriptor*/,504TRUE/*last*/);505break;506507default:508RETURN_ERROR(MAJOR, E_INVALID_SELECTION, ("member position in remove member"));509}510511if (err)512RETURN_ERROR(MAJOR, err, NO_MSG);513514if (p_CurrentMember->h_Manip)515{516FmPcdManipUpdateOwner(p_CurrentMember->h_Manip, FALSE);517p_CurrentMember->h_Manip = NULL;518}519520/* remove the member from the driver internal members list */521RemoveMemberFromList(p_ReplicGroup, p_CurrentMember);522523/* return the member to the available members list */524FreeMember(p_ReplicGroup, p_CurrentMember);525526return E_OK;527}528529static void DeleteGroup(t_FmPcdFrmReplicGroup *p_ReplicGroup)530{531int i, j;532t_Handle h_Muram;533t_FmPcdFrmReplicMember *p_Member, *p_CurrentMember;534535if (p_ReplicGroup)536{537ASSERT_COND(p_ReplicGroup->h_FmPcd);538h_Muram = FmPcdGetMuramHandle(p_ReplicGroup->h_FmPcd);539ASSERT_COND(h_Muram);540541/* free the source table descriptor */542if (p_ReplicGroup->p_SourceTd)543{544FM_MURAM_FreeMem(h_Muram, p_ReplicGroup->p_SourceTd);545p_ReplicGroup->p_SourceTd = NULL;546}547548/* Remove all members from the members linked list (hw and sw) and549return the members to the available members list */550if (p_ReplicGroup->numOfEntries)551{552j = p_ReplicGroup->numOfEntries-1;553554/* manually removal of the member because there are no owners of555this group */556for (i=j; i>=0; i--)557{558p_CurrentMember = GetMemberByIndex(p_ReplicGroup, (uint16_t)i/*memberIndex*/);559ASSERT_COND(p_CurrentMember);560561if (p_CurrentMember->h_Manip)562{563FmPcdManipUpdateOwner(p_CurrentMember->h_Manip, FALSE);564p_CurrentMember->h_Manip = NULL;565}566567/* remove the member from the internal driver members list */568RemoveMemberFromList(p_ReplicGroup, p_CurrentMember);569570/* return the member to the available members list */571FreeMember(p_ReplicGroup, p_CurrentMember);572}573}574575/* Free members AD */576for (i=0; i<p_ReplicGroup->maxNumOfEntries; i++)577{578p_Member = GetAvailableMember(p_ReplicGroup);579ASSERT_COND(p_Member);580if (p_Member->p_MemberAd)581{582FM_MURAM_FreeMem(h_Muram, p_Member->p_MemberAd);583p_Member->p_MemberAd = NULL;584}585XX_Free(p_Member);586}587588/* release the group lock */589if (p_ReplicGroup->p_Lock)590FmPcdReleaseLock(p_ReplicGroup->h_FmPcd, p_ReplicGroup->p_Lock);591592/* free the replicator group */593XX_Free(p_ReplicGroup);594}595}596597598/*****************************************************************************/599/* Inter-module API routines */600/*****************************************************************************/601602/* NOTE: the inter-module routines are locked by cc in case of using them */603void * FrmReplicGroupGetSourceTableDescriptor(t_Handle h_ReplicGroup)604{605t_FmPcdFrmReplicGroup *p_ReplicGroup = (t_FmPcdFrmReplicGroup *)h_ReplicGroup;606ASSERT_COND(p_ReplicGroup);607608return (p_ReplicGroup->p_SourceTd);609}610611void FrmReplicGroupUpdateAd(t_Handle h_ReplicGroup,612void *p_Ad,613t_Handle *h_AdNew)614{615t_FmPcdFrmReplicGroup *p_ReplicGroup = (t_FmPcdFrmReplicGroup *)h_ReplicGroup;616t_AdOfTypeResult *p_AdResult = (t_AdOfTypeResult*)p_Ad;617t_FmPcd *p_FmPcd;618619ASSERT_COND(p_ReplicGroup);620p_FmPcd = p_ReplicGroup->h_FmPcd;621622/* build a bypass ad */623WRITE_UINT32(p_AdResult->fqid, FM_PCD_AD_BYPASS_TYPE |624(uint32_t)((XX_VirtToPhys(p_ReplicGroup->p_SourceTd)) - p_FmPcd->physicalMuramBase));625626*h_AdNew = NULL;627}628629void FrmReplicGroupUpdateOwner(t_Handle h_ReplicGroup,630bool add)631{632t_FmPcdFrmReplicGroup *p_ReplicGroup = (t_FmPcdFrmReplicGroup *)h_ReplicGroup;633ASSERT_COND(p_ReplicGroup);634635/* update the group owner counter */636if (add)637p_ReplicGroup->owners++;638else639{640ASSERT_COND(p_ReplicGroup->owners);641p_ReplicGroup->owners--;642}643}644645t_Error FrmReplicGroupTryLock(t_Handle h_ReplicGroup)646{647t_FmPcdFrmReplicGroup *p_ReplicGroup = (t_FmPcdFrmReplicGroup *)h_ReplicGroup;648649ASSERT_COND(h_ReplicGroup);650651if (FmPcdLockTryLock(p_ReplicGroup->p_Lock))652return E_OK;653654return ERROR_CODE(E_BUSY);655}656657void FrmReplicGroupUnlock(t_Handle h_ReplicGroup)658{659t_FmPcdFrmReplicGroup *p_ReplicGroup = (t_FmPcdFrmReplicGroup *)h_ReplicGroup;660661ASSERT_COND(h_ReplicGroup);662663FmPcdLockUnlock(p_ReplicGroup->p_Lock);664}665/*********************** End of inter-module routines ************************/666667668/****************************************/669/* API Init unit functions */670/****************************************/671t_Handle FM_PCD_FrmReplicSetGroup(t_Handle h_FmPcd,672t_FmPcdFrmReplicGroupParams *p_ReplicGroupParam)673{674t_FmPcdFrmReplicGroup *p_ReplicGroup;675t_FmPcdFrmReplicMember *p_CurrentMember, *p_NextMember = NULL;676int i;677t_Error err;678bool last = FALSE;679t_Handle h_Muram;680681SANITY_CHECK_RETURN_VALUE(h_FmPcd, E_INVALID_HANDLE, NULL);682SANITY_CHECK_RETURN_VALUE(p_ReplicGroupParam, E_INVALID_HANDLE, NULL);683684if (!FmPcdIsAdvancedOffloadSupported(h_FmPcd))685{686REPORT_ERROR(MAJOR, E_INVALID_STATE, ("Advanced-offload must be enabled"));687return NULL;688}689690err = CheckParams(h_FmPcd, p_ReplicGroupParam);691if (err)692{693REPORT_ERROR(MAJOR, err, (NO_MSG));694return NULL;695}696697p_ReplicGroup = (t_FmPcdFrmReplicGroup*)XX_Malloc(sizeof(t_FmPcdFrmReplicGroup));698if (!p_ReplicGroup)699{700REPORT_ERROR(MAJOR, E_NO_MEMORY, ("No memory"));701return NULL;702}703memset(p_ReplicGroup, 0, sizeof(t_FmPcdFrmReplicGroup));704705/* initialize lists for internal driver use */706INIT_LIST(&p_ReplicGroup->availableMembersList);707INIT_LIST(&p_ReplicGroup->membersList);708709p_ReplicGroup->h_FmPcd = h_FmPcd;710711h_Muram = FmPcdGetMuramHandle(p_ReplicGroup->h_FmPcd);712ASSERT_COND(h_Muram);713714/* initialize the group lock */715p_ReplicGroup->p_Lock = FmPcdAcquireLock(p_ReplicGroup->h_FmPcd);716if (!p_ReplicGroup->p_Lock)717{718REPORT_ERROR(MAJOR, E_NO_MEMORY, ("Replic group lock"));719DeleteGroup(p_ReplicGroup);720return NULL;721}722723/* Allocate the frame replicator source table descriptor */724p_ReplicGroup->p_SourceTd =725(t_Handle)FM_MURAM_AllocMem(h_Muram,726FM_PCD_CC_AD_ENTRY_SIZE,727FM_PCD_CC_AD_TABLE_ALIGN);728if (!p_ReplicGroup->p_SourceTd)729{730REPORT_ERROR(MAJOR, E_NO_MEMORY, ("frame replicator source table descriptor"));731DeleteGroup(p_ReplicGroup);732return NULL;733}734735/* update the shadow size - required for the host commands */736err = FmPcdUpdateCcShadow(p_ReplicGroup->h_FmPcd,737FM_PCD_CC_AD_ENTRY_SIZE,738FM_PCD_CC_AD_TABLE_ALIGN);739if (err)740{741REPORT_ERROR(MAJOR, err, ("Update CC shadow"));742DeleteGroup(p_ReplicGroup);743return NULL;744}745746p_ReplicGroup->maxNumOfEntries = p_ReplicGroupParam->maxNumOfEntries;747748/* Allocate the maximal number of members ADs and Statistics AD for the group749It prevents allocation of Muram in run-time */750for (i=0; i<p_ReplicGroup->maxNumOfEntries; i++)751{752err = AllocMember(p_ReplicGroup);753if (err)754{755REPORT_ERROR(MAJOR, err, ("allocate a new member"));756DeleteGroup(p_ReplicGroup);757return NULL;758}759}760761/* Initialize the members linked lists:762(hw - the one that is used by the FMan controller and763sw - the one that is managed by the driver internally) */764for (i=(p_ReplicGroupParam->numOfEntries-1); i>=0; i--)765{766/* check if this is the last member in the group */767if (i == (p_ReplicGroupParam->numOfEntries-1))768last = TRUE;769else770last = FALSE;771772/* Initialize a new member */773p_CurrentMember = InitMember(p_ReplicGroup,774&(p_ReplicGroupParam->nextEngineParams[i]),775last);776if (!p_CurrentMember)777{778REPORT_ERROR(MAJOR, E_INVALID_HANDLE, ("No available member"));779DeleteGroup(p_ReplicGroup);780return NULL;781}782783/* Build the members group - link two consecutive members in the hw linked list */784LinkMemberToMember(p_ReplicGroup, p_CurrentMember, p_NextMember);785786/* update the driver internal members list to be compatible to the hw members linked list */787AddMemberToList(p_ReplicGroup, p_CurrentMember, &p_ReplicGroup->membersList);788789p_NextMember = p_CurrentMember;790}791792/* initialize the source table descriptor */793BuildSourceTd(p_ReplicGroup->p_SourceTd);794795/* link the source table descriptor to point to the first member in the group */796LinkSourceToMember(p_ReplicGroup, p_ReplicGroup->p_SourceTd, p_NextMember);797798return p_ReplicGroup;799}800801t_Error FM_PCD_FrmReplicDeleteGroup(t_Handle h_ReplicGroup)802{803t_FmPcdFrmReplicGroup *p_ReplicGroup = (t_FmPcdFrmReplicGroup *)h_ReplicGroup;804805SANITY_CHECK_RETURN_ERROR(p_ReplicGroup, E_INVALID_HANDLE);806807if (p_ReplicGroup->owners)808RETURN_ERROR(MAJOR,809E_INVALID_STATE,810("the group has owners and can't be deleted"));811812DeleteGroup(p_ReplicGroup);813814return E_OK;815}816817818/*****************************************************************************/819/* API Run-time Frame replicator Control unit functions */820/*****************************************************************************/821t_Error FM_PCD_FrmReplicAddMember(t_Handle h_ReplicGroup,822uint16_t memberIndex,823t_FmPcdCcNextEngineParams *p_MemberParams)824{825t_FmPcdFrmReplicGroup *p_ReplicGroup = (t_FmPcdFrmReplicGroup*) h_ReplicGroup;826t_FmPcdFrmReplicMember *p_NewMember, *p_CurrentMember = NULL, *p_PreviousMember = NULL;827t_Error err;828uint8_t memberPosition;829830SANITY_CHECK_RETURN_ERROR(p_ReplicGroup, E_INVALID_HANDLE);831SANITY_CHECK_RETURN_ERROR(p_MemberParams, E_INVALID_HANDLE);832833/* group lock */834err = FrmReplicGroupTryLock(p_ReplicGroup);835if (GET_ERROR_TYPE(err) == E_BUSY)836return ERROR_CODE(E_BUSY);837838if (memberIndex > p_ReplicGroup->numOfEntries)839{840/* unlock */841FrmReplicGroupUnlock(p_ReplicGroup);842RETURN_ERROR(MAJOR, E_INVALID_SELECTION,843("memberIndex is greater than the members in the list"));844}845846if (memberIndex >= p_ReplicGroup->maxNumOfEntries)847{848/* unlock */849FrmReplicGroupUnlock(p_ReplicGroup);850RETURN_ERROR(MAJOR, E_INVALID_SELECTION, ("memberIndex is greater than the allowed number of members in the group"));851}852853if ((p_ReplicGroup->numOfEntries + 1) > FM_PCD_FRM_REPLIC_MAX_NUM_OF_ENTRIES)854{855/* unlock */856FrmReplicGroupUnlock(p_ReplicGroup);857RETURN_ERROR(MAJOR, E_INVALID_VALUE,858("numOfEntries with new entry can not be larger than %d\n",859FM_PCD_FRM_REPLIC_MAX_NUM_OF_ENTRIES));860}861862err = MemberCheckParams(p_ReplicGroup->h_FmPcd, p_MemberParams);863if (err)864{865/* unlock */866FrmReplicGroupUnlock(p_ReplicGroup);867RETURN_ERROR(MAJOR, err, ("member check parameters in add operation"));868}869/* determine the member position in the group */870memberPosition = GetMemberPosition(p_ReplicGroup,871memberIndex,872TRUE/* add operation */);873874/* Initialize a new member */875p_NewMember = InitMember(p_ReplicGroup,876p_MemberParams,877(memberPosition == FRM_REPLIC_LAST_MEMBER_INDEX ? TRUE : FALSE));878if (!p_NewMember)879{880/* unlock */881FrmReplicGroupUnlock(p_ReplicGroup);882RETURN_ERROR(MAJOR, E_INVALID_HANDLE, ("No available member"));883}884885switch (memberPosition)886{887case FRM_REPLIC_FIRST_MEMBER_INDEX:888p_CurrentMember = GetMemberByIndex(p_ReplicGroup, memberIndex);889ASSERT_COND(p_CurrentMember);890891LinkMemberToMember(p_ReplicGroup, p_NewMember, p_CurrentMember);892893/* update the internal group source TD */894LinkSourceToMember(p_ReplicGroup,895p_ReplicGroup->p_SourceTd,896p_NewMember);897898/* add member to the internal sw member list */899AddMemberToList(p_ReplicGroup,900p_NewMember,901&p_ReplicGroup->membersList);902break;903904case FRM_REPLIC_MIDDLE_MEMBER_INDEX:905p_CurrentMember = GetMemberByIndex(p_ReplicGroup, memberIndex);906ASSERT_COND(p_CurrentMember);907908p_PreviousMember = GetMemberByIndex(p_ReplicGroup, (uint16_t)(memberIndex-1));909ASSERT_COND(p_PreviousMember);910911LinkMemberToMember(p_ReplicGroup, p_NewMember, p_CurrentMember);912LinkMemberToMember(p_ReplicGroup, p_PreviousMember, p_NewMember);913914AddMemberToList(p_ReplicGroup, p_NewMember, &p_PreviousMember->node);915break;916917case FRM_REPLIC_LAST_MEMBER_INDEX:918p_PreviousMember = GetMemberByIndex(p_ReplicGroup, (uint16_t)(memberIndex-1));919ASSERT_COND(p_PreviousMember);920921LinkMemberToMember(p_ReplicGroup, p_PreviousMember, p_NewMember);922FillReplicAdOfTypeResult(p_PreviousMember->p_MemberAd, FALSE/*last*/);923924/* add the new member to the internal sw member list */925AddMemberToList(p_ReplicGroup, p_NewMember, &p_PreviousMember->node);926break;927928default:929/* unlock */930FrmReplicGroupUnlock(p_ReplicGroup);931RETURN_ERROR(MAJOR, E_INVALID_SELECTION, ("member position in add member"));932933}934935/* unlock */936FrmReplicGroupUnlock(p_ReplicGroup);937938return E_OK;939}940941t_Error FM_PCD_FrmReplicRemoveMember(t_Handle h_ReplicGroup,942uint16_t memberIndex)943{944t_FmPcdFrmReplicGroup *p_ReplicGroup = (t_FmPcdFrmReplicGroup*) h_ReplicGroup;945t_Error err;946947SANITY_CHECK_RETURN_ERROR(p_ReplicGroup, E_INVALID_HANDLE);948949/* lock */950err = FrmReplicGroupTryLock(p_ReplicGroup);951if (GET_ERROR_TYPE(err) == E_BUSY)952return ERROR_CODE(E_BUSY);953954if (memberIndex >= p_ReplicGroup->numOfEntries)955RETURN_ERROR(MAJOR, E_INVALID_SELECTION, ("member index to remove"));956957/* Design decision: group must contain at least one member958No possibility to remove the last member from the group */959if (p_ReplicGroup->numOfEntries == 1)960RETURN_ERROR(MAJOR, E_CONFLICT, ("Can't remove the last member. At least one member should be related to a group."));961962err = RemoveMember(p_ReplicGroup, memberIndex);963964/* unlock */965FrmReplicGroupUnlock(p_ReplicGroup);966967switch (GET_ERROR_TYPE(err))968{969case E_OK:970return E_OK;971972case E_BUSY:973DBG(TRACE, ("E_BUSY error"));974return ERROR_CODE(E_BUSY);975976default:977RETURN_ERROR(MAJOR, err, NO_MSG);978}979}980981/*********************** End of API routines ************************/982983984985986