/* Copyright (c) 2008-2011 Freescale Semiconductor, Inc. * All rights reserved. * * 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_kg.c @Description FM PCD ... *//***************************************************************************/ #include "std_ext.h" #include "error_ext.h" #include "string_ext.h" #include "debug_ext.h" #include "net_ext.h" #include "fm_port_ext.h" #include "fm_common.h" #include "fm_pcd.h" #include "fm_hc.h" #include "fm_pcd_ipc.h" static t_Error WriteKgarWait(t_FmPcd *p_FmPcd, uint32_t kgar) { WRITE_UINT32(p_FmPcd->p_FmPcdKg->p_FmPcdKgRegs->kgar, kgar); /* Wait for GO to be idle and read error */ while ((kgar = GET_UINT32(p_FmPcd->p_FmPcdKg->p_FmPcdKgRegs->kgar)) & FM_PCD_KG_KGAR_GO) ; if (kgar & FM_PCD_KG_KGAR_ERR) RETURN_ERROR(MINOR, E_INVALID_STATE, ("Keygen scheme access violation")); return E_OK; } static e_FmPcdKgExtractDfltSelect GetGenericSwDefault(t_FmPcdKgExtractDflt swDefaults[], uint8_t numOfSwDefaults, uint8_t code) { int i; switch(code) { case( KG_SCH_GEN_PARSE_RESULT_N_FQID): case( KG_SCH_GEN_DEFAULT): case( KG_SCH_GEN_NEXTHDR): for(i=0 ; i mask 0x1-0x7F */ if(bitOffset<8) { mask = 0; for(i = 0 ; i < bitOffset ; i++, walking1Mask <<= 1) mask |= walking1Mask; } else { mask = 0xFF; numOfOnesToClear = 0; if(fqid && bitOffset>24) /* bitOffset 25-31 --> mask 0xFE-0x80 */ numOfOnesToClear = (uint8_t)(bitOffset-24); else /* bitOffset 9-15 --> mask 0xFE-0x80 */ if(!fqid && bitOffset>8) numOfOnesToClear = (uint8_t)(bitOffset-8); for(i = 0 ; i < numOfOnesToClear ; i++, walking1Mask <<= 1) mask &= ~walking1Mask; /* bitOffset 8-24 for FQID, 8 for PP --> no mask (0xFF)*/ } return mask; } t_Error FmPcdKgBuildClsPlanGrp(t_Handle h_FmPcd, t_FmPcdKgInterModuleClsPlanGrpParams *p_Grp, t_FmPcdKgInterModuleClsPlanSet *p_ClsPlanSet) { t_FmPcd *p_FmPcd = (t_FmPcd*)h_FmPcd; t_FmPcdKgClsPlanGrp *p_ClsPlanGrp; t_FmPcdIpcKgClsPlanParams kgAlloc; t_Error err = E_OK; uint32_t oredVectors = 0; uint32_t intFlags; int i, j; if (p_Grp->numOfOptions >= FM_PCD_MAX_NUM_OF_OPTIONS(FM_PCD_MAX_NUM_OF_CLS_PLANS)) RETURN_ERROR(MAJOR, E_INVALID_VALUE,("Too many classification plan basic options selected.")); intFlags = FmPcdLock(p_FmPcd); /* find a new clsPlan group */ for(i = 0;ip_FmPcdKg->clsPlanGrps[i].used) break; if(i== FM_MAX_NUM_OF_PORTS) { FmPcdUnlock(p_FmPcd, intFlags); RETURN_ERROR(MAJOR, E_FULL,("No classification plan groups available.")); } p_FmPcd->p_FmPcdKg->clsPlanGrps[i].used = TRUE; p_Grp->clsPlanGrpId = (uint8_t)i; if(p_Grp->numOfOptions == 0) p_FmPcd->p_FmPcdKg->emptyClsPlanGrpId = (uint8_t)i; if (!TRY_LOCK(NULL, &p_FmPcd->p_FmPcdKg->clsPlanGrps[p_Grp->clsPlanGrpId].lock)) { FmPcdUnlock(p_FmPcd, intFlags); return ERROR_CODE(E_BUSY); } FmPcdUnlock(p_FmPcd, intFlags); p_ClsPlanGrp = &p_FmPcd->p_FmPcdKg->clsPlanGrps[i]; p_ClsPlanGrp->netEnvId = p_Grp->netEnvId; p_ClsPlanGrp->owners = 0; FmPcdSetClsPlanGrpId(p_FmPcd, p_Grp->netEnvId, p_Grp->clsPlanGrpId); FmPcdIncNetEnvOwners(p_FmPcd, p_Grp->netEnvId); p_ClsPlanGrp->sizeOfGrp = (uint16_t)(1<numOfOptions); /* a minimal group of 8 is required */ if(p_ClsPlanGrp->sizeOfGrp < CLS_PLAN_NUM_PER_GRP) p_ClsPlanGrp->sizeOfGrp = CLS_PLAN_NUM_PER_GRP; if(p_FmPcd->guestId == NCSW_MASTER_ID) { err = KgAllocClsPlanEntries(h_FmPcd, p_ClsPlanGrp->sizeOfGrp, p_FmPcd->guestId, &p_ClsPlanGrp->baseEntry); if(err) { RELEASE_LOCK(p_FmPcd->p_FmPcdKg->clsPlanGrps[p_Grp->clsPlanGrpId].lock); RETURN_ERROR(MINOR, E_INVALID_STATE, NO_MSG); } } else { t_FmPcdIpcMsg msg; uint32_t replyLength; t_FmPcdIpcReply reply; /* in GUEST_PARTITION, we use the IPC, to also set a private driver group if required */ memset(&reply, 0, sizeof(reply)); memset(&msg, 0, sizeof(msg)); memset(&kgAlloc, 0, sizeof(kgAlloc)); kgAlloc.guestId = p_FmPcd->guestId; kgAlloc.numOfClsPlanEntries = p_ClsPlanGrp->sizeOfGrp; msg.msgId = FM_PCD_ALLOC_KG_CLSPLAN; memcpy(msg.msgBody, &kgAlloc, sizeof(kgAlloc)); replyLength = (sizeof(uint32_t) + sizeof(p_ClsPlanGrp->baseEntry)); if ((err = XX_IpcSendMessage(p_FmPcd->h_IpcSession, (uint8_t*)&msg, sizeof(msg.msgId) + sizeof(kgAlloc), (uint8_t*)&reply, &replyLength, NULL, NULL)) != E_OK) { RELEASE_LOCK(p_FmPcd->p_FmPcdKg->clsPlanGrps[p_Grp->clsPlanGrpId].lock); RETURN_ERROR(MAJOR, err, NO_MSG); } if (replyLength != (sizeof(uint32_t) + sizeof(p_ClsPlanGrp->baseEntry))) { RELEASE_LOCK(p_FmPcd->p_FmPcdKg->clsPlanGrps[p_Grp->clsPlanGrpId].lock); RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("IPC reply length mismatch")); } if ((t_Error)reply.error != E_OK) { RELEASE_LOCK(p_FmPcd->p_FmPcdKg->clsPlanGrps[p_Grp->clsPlanGrpId].lock); RETURN_ERROR(MINOR, (t_Error)reply.error, NO_MSG); } p_ClsPlanGrp->baseEntry = *(uint8_t*)(reply.replyBody); } /* build classification plan entries parameters */ p_ClsPlanSet->baseEntry = p_ClsPlanGrp->baseEntry; p_ClsPlanSet->numOfClsPlanEntries = p_ClsPlanGrp->sizeOfGrp; oredVectors = 0; for(i = 0; inumOfOptions; i++) { oredVectors |= p_Grp->optVectors[i]; /* save an array of used options - the indexes represent the power of 2 index */ p_ClsPlanGrp->optArray[i] = p_Grp->options[i]; } /* set the classification plan relevant entries so that all bits * relevant to the list of options is cleared */ for(j = 0; jsizeOfGrp; j++) p_ClsPlanSet->vectors[j] = ~oredVectors; for(i = 0; inumOfOptions; i++) { /* option i got the place 2^i in the clsPlan array. all entries that * have bit i set, should have the vector bit cleared. So each option * has one location that it is exclusive (1,2,4,8...) and represent the * presence of that option only, and other locations that represent a * combination of options. * e.g: * If ethernet-BC is option 1 it gets entry 2 in the table. Entry 2 * now represents a frame with ethernet-BC header - so the bit * representing ethernet-BC should be set and all other option bits * should be cleared. * Entries 2,3,6,7,10... also have ethernet-BC and therefore have bit * vector[1] set, but they also have other bits set: * 3=1+2, options 0 and 1 * 6=2+4, options 1 and 2 * 7=1+2+4, options 0,1,and 2 * 10=2+8, options 1 and 3 * etc. * */ /* now for each option (i), we set their bits in all entries (j) * that contain bit 2^i. */ for(j = 0; jsizeOfGrp; j++) { if(j & (1<vectors[j] |= p_Grp->optVectors[i]; } } RELEASE_LOCK(p_FmPcd->p_FmPcdKg->clsPlanGrps[p_Grp->clsPlanGrpId].lock); return E_OK; } void FmPcdKgDestroyClsPlanGrp(t_Handle h_FmPcd, uint8_t grpId) { t_FmPcd *p_FmPcd = (t_FmPcd*)h_FmPcd; t_FmPcdIpcKgClsPlanParams kgAlloc; t_Error err; t_FmPcdIpcMsg msg; uint32_t replyLength; t_FmPcdIpcReply reply; /* check that no port is bound to this clsPlan */ if(p_FmPcd->p_FmPcdKg->clsPlanGrps[grpId].owners) { REPORT_ERROR(MINOR, E_INVALID_STATE, ("Trying to delete a clsPlan grp that has ports bound to")); return; } FmPcdDecNetEnvOwners(p_FmPcd, p_FmPcd->p_FmPcdKg->clsPlanGrps[grpId].netEnvId); /* free blocks */ if(p_FmPcd->guestId == NCSW_MASTER_ID) { KgFreeClsPlanEntries(h_FmPcd, p_FmPcd->p_FmPcdKg->clsPlanGrps[grpId].sizeOfGrp, p_FmPcd->guestId, p_FmPcd->p_FmPcdKg->clsPlanGrps[grpId].baseEntry); } else /* in GUEST_PARTITION, we use the IPC, to also set a private driver group if required */ { memset(&reply, 0, sizeof(reply)); memset(&msg, 0, sizeof(msg)); kgAlloc.guestId = p_FmPcd->guestId; kgAlloc.numOfClsPlanEntries = p_FmPcd->p_FmPcdKg->clsPlanGrps[grpId].sizeOfGrp; kgAlloc.clsPlanBase = p_FmPcd->p_FmPcdKg->clsPlanGrps[grpId].baseEntry; msg.msgId = FM_PCD_FREE_KG_CLSPLAN; memcpy(msg.msgBody, &kgAlloc, sizeof(kgAlloc)); replyLength = sizeof(uint32_t); if ((err = XX_IpcSendMessage(p_FmPcd->h_IpcSession, (uint8_t*)&msg, sizeof(msg.msgId) + sizeof(kgAlloc), (uint8_t*)&reply, &replyLength, NULL, NULL)) != E_OK) { REPORT_ERROR(MINOR, err, NO_MSG); return; } if (replyLength != sizeof(uint32_t)) { REPORT_ERROR(MAJOR, E_INVALID_VALUE, ("IPC reply length mismatch")); return; } if((t_Error)reply.error != E_OK) { REPORT_ERROR(MAJOR, E_INVALID_STATE, ("Free KG clsPlan failed")); return; } } if(grpId == p_FmPcd->p_FmPcdKg->emptyClsPlanGrpId) p_FmPcd->p_FmPcdKg->emptyClsPlanGrpId = ILLEGAL_CLS_PLAN; /* clear clsPlan driver structure */ memset(&p_FmPcd->p_FmPcdKg->clsPlanGrps[grpId], 0, sizeof(t_FmPcdKgClsPlanGrp)); } t_Error FmPcdKgBuildBindPortToSchemes(t_Handle h_FmPcd , t_FmPcdKgInterModuleBindPortToSchemes *p_BindPort, uint32_t *p_SpReg, bool add) { t_FmPcd *p_FmPcd = (t_FmPcd*)h_FmPcd; uint32_t j, schemesPerPortVector = 0; t_FmPcdKgScheme *p_Scheme; uint8_t i, relativeSchemeId; uint32_t tmp, walking1Mask; uint8_t swPortIndex = 0; SANITY_CHECK_RETURN_ERROR(p_FmPcd, E_INVALID_HANDLE); SANITY_CHECK_RETURN_ERROR(p_FmPcd->p_FmPcdKg, E_INVALID_HANDLE); SANITY_CHECK_RETURN_ERROR(!p_FmPcd->p_FmPcdDriverParam, E_INVALID_STATE); /* for each scheme */ for(i = 0; inumOfSchemes; i++) { relativeSchemeId = FmPcdKgGetRelativeSchemeId(p_FmPcd, p_BindPort->schemesIds[i]); if(relativeSchemeId >= FM_PCD_KG_NUM_OF_SCHEMES) RETURN_ERROR(MAJOR, E_NOT_IN_RANGE, NO_MSG); if(add) { if (!FmPcdKgIsSchemeValidSw(h_FmPcd, relativeSchemeId)) RETURN_ERROR(MAJOR, E_INVALID_STATE, ("Requested scheme is invalid.")); p_Scheme = &p_FmPcd->p_FmPcdKg->schemes[relativeSchemeId]; /* check netEnvId of the port against the scheme netEnvId */ if((p_Scheme->netEnvId != p_BindPort->netEnvId) && (p_Scheme->netEnvId != ILLEGAL_NETENV)) RETURN_ERROR(MAJOR, E_INVALID_STATE, ("Port may not be bound to requested scheme - differ in netEnvId")); /* if next engine is private port policer profile, we need to check that it is valid */ HW_PORT_ID_TO_SW_PORT_INDX(swPortIndex, p_BindPort->hardwarePortId); if(p_Scheme->nextRelativePlcrProfile) { for(j = 0;jnumOfProfiles;j++) { ASSERT_COND(p_FmPcd->p_FmPcdPlcr->portsMapping[swPortIndex].h_FmPort); if(p_Scheme->relativeProfileId+j >= p_FmPcd->p_FmPcdPlcr->portsMapping[swPortIndex].numOfProfiles) RETURN_ERROR(MAJOR, E_INVALID_STATE, ("Relative profile not in range")); if(!FmPcdPlcrIsProfileValid(p_FmPcd, (uint16_t)(p_FmPcd->p_FmPcdPlcr->portsMapping[swPortIndex].profilesBase + p_Scheme->relativeProfileId + j))) RETURN_ERROR(MINOR, E_INVALID_STATE, ("Relative profile not valid.")); } } if(!p_BindPort->useClsPlan) { /* if this port does not use clsPlan, it may not be bound to schemes with units that contain cls plan options. Schemes that are used only directly, should not be checked. it also may not be bound to schemes that go to CC with units that are options - so we OR the match vector and the grpBits (= ccUnits) */ if ((p_Scheme->matchVector != SCHEME_ALWAYS_DIRECT) || p_Scheme->ccUnits) { walking1Mask = 0x80000000; tmp = (p_Scheme->matchVector == SCHEME_ALWAYS_DIRECT)? 0:p_Scheme->matchVector; tmp |= p_Scheme->ccUnits; while (tmp) { if(tmp & walking1Mask) { tmp &= ~walking1Mask; if(!PcdNetEnvIsUnitWithoutOpts(p_FmPcd, p_Scheme->netEnvId, walking1Mask)) RETURN_ERROR(MAJOR, E_INVALID_STATE, ("Port (without clsPlan) may not be bound to requested scheme - uses clsPlan options")); } walking1Mask >>= 1; } } } } /* build vector */ schemesPerPortVector |= 1 << (31 - p_BindPort->schemesIds[i]); } *p_SpReg = schemesPerPortVector; return E_OK; } void FmPcdKgIncSchemeOwners(t_Handle h_FmPcd , t_FmPcdKgInterModuleBindPortToSchemes *p_BindPort) { t_FmPcd *p_FmPcd = (t_FmPcd*)h_FmPcd; int i; t_FmPcdKgScheme *p_Scheme; /* for each scheme - update owners counters */ for(i = 0; inumOfSchemes; i++) { p_Scheme = &p_FmPcd->p_FmPcdKg->schemes[p_BindPort->schemesIds[i]]; /* increment owners number */ p_Scheme->owners++; } } void FmPcdKgDecSchemeOwners(t_Handle h_FmPcd , t_FmPcdKgInterModuleBindPortToSchemes *p_BindPort) { t_FmPcd *p_FmPcd = (t_FmPcd*)h_FmPcd; int i; t_FmPcdKgScheme *p_Scheme; /* for each scheme - update owners counters */ for(i = 0; inumOfSchemes; i++) { p_Scheme = &p_FmPcd->p_FmPcdKg->schemes[p_BindPort->schemesIds[i]]; /* increment owners number */ ASSERT_COND(p_Scheme->owners); p_Scheme->owners--; } } static t_Error KgWriteSp(t_FmPcd *p_FmPcd, uint8_t hardwarePortId, uint32_t spReg, bool add) { t_FmPcdKgPortConfigRegs *p_FmPcdKgPortRegs; uint32_t tmpKgarReg = 0, tmpKgpeSp, intFlags; t_Error err = E_OK; if (p_FmPcd->h_Hc) return FmHcKgWriteSp(p_FmPcd->h_Hc, hardwarePortId, spReg, add); p_FmPcdKgPortRegs = &p_FmPcd->p_FmPcdKg->p_FmPcdKgRegs->indirectAccessRegs.portRegs; tmpKgarReg = FmPcdKgBuildReadPortSchemeBindActionReg(hardwarePortId); intFlags = FmPcdLock(p_FmPcd); err = WriteKgarWait(p_FmPcd, tmpKgarReg); if(err) { FmPcdUnlock(p_FmPcd, intFlags); RETURN_ERROR(MINOR, err, NO_MSG); } tmpKgpeSp = GET_UINT32(p_FmPcdKgPortRegs->kgoe_sp); if(add) tmpKgpeSp |= spReg; else /* clear */ tmpKgpeSp &= ~spReg; WRITE_UINT32(p_FmPcdKgPortRegs->kgoe_sp, tmpKgpeSp); tmpKgarReg = FmPcdKgBuildWritePortSchemeBindActionReg(hardwarePortId); err = WriteKgarWait(p_FmPcd, tmpKgarReg); FmPcdUnlock(p_FmPcd, intFlags); return err; } static t_Error KgWriteCpp(t_FmPcd *p_FmPcd, uint8_t hardwarePortId, uint32_t cppReg) { t_FmPcdKgPortConfigRegs *p_FmPcdKgPortRegs; uint32_t tmpKgarReg, intFlags; t_Error err; if (p_FmPcd->h_Hc) return FmHcKgWriteCpp(p_FmPcd->h_Hc, hardwarePortId, cppReg); p_FmPcdKgPortRegs = &p_FmPcd->p_FmPcdKg->p_FmPcdKgRegs->indirectAccessRegs.portRegs; intFlags = FmPcdLock(p_FmPcd); WRITE_UINT32(p_FmPcdKgPortRegs->kgoe_cpp, cppReg); tmpKgarReg = FmPcdKgBuildWritePortClsPlanBindActionReg(hardwarePortId); err = WriteKgarWait(p_FmPcd, tmpKgarReg); FmPcdUnlock(p_FmPcd, intFlags); return err; } static void FmPcdKgUnbindPortToClsPlanGrp(t_FmPcd *p_FmPcd, uint8_t hardwarePortId) { KgWriteCpp(p_FmPcd, hardwarePortId, 0); } static t_Error KgBindPortToClsPlanGrp(t_FmPcd *p_FmPcd, uint8_t hardwarePortId, uint8_t clsPlanGrpId) { uint32_t tmpKgpeCpp = 0; tmpKgpeCpp = FmPcdKgBuildCppReg(p_FmPcd, clsPlanGrpId); return KgWriteCpp(p_FmPcd, hardwarePortId, tmpKgpeCpp); } t_Error FmPcdKgBindPortToSchemes(t_Handle h_FmPcd , t_FmPcdKgInterModuleBindPortToSchemes *p_SchemeBind) { t_FmPcd *p_FmPcd = (t_FmPcd*)h_FmPcd; uint32_t spReg; t_Error err = E_OK; err = FmPcdKgBuildBindPortToSchemes(h_FmPcd, p_SchemeBind, &spReg, TRUE); if(err) RETURN_ERROR(MAJOR, err, NO_MSG); err = KgWriteSp(p_FmPcd, p_SchemeBind->hardwarePortId, spReg, TRUE); if(err) RETURN_ERROR(MAJOR, err, NO_MSG); FmPcdKgIncSchemeOwners(h_FmPcd, p_SchemeBind); return E_OK; } t_Error FmPcdKgUnbindPortToSchemes(t_Handle h_FmPcd , t_FmPcdKgInterModuleBindPortToSchemes *p_SchemeBind) { t_FmPcd *p_FmPcd = (t_FmPcd*)h_FmPcd; uint32_t spReg; t_Error err = E_OK; err = FmPcdKgBuildBindPortToSchemes(h_FmPcd, p_SchemeBind, &spReg, FALSE); if(err) RETURN_ERROR(MAJOR, err, NO_MSG); err = KgWriteSp(p_FmPcd, p_SchemeBind->hardwarePortId, spReg, FALSE); if(err) RETURN_ERROR(MAJOR, err, NO_MSG); FmPcdKgDecSchemeOwners(h_FmPcd, p_SchemeBind); return E_OK; } bool FmPcdKgIsSchemeValidSw(t_Handle h_FmPcd, uint8_t schemeId) { t_FmPcd *p_FmPcd = (t_FmPcd*)h_FmPcd; return p_FmPcd->p_FmPcdKg->schemes[schemeId].valid; } bool KgIsSchemeAlwaysDirect(t_Handle h_FmPcd, uint8_t schemeId) { t_FmPcd *p_FmPcd = (t_FmPcd*)h_FmPcd; if(p_FmPcd->p_FmPcdKg->schemes[schemeId].matchVector == SCHEME_ALWAYS_DIRECT) return TRUE; else return FALSE; } t_Error FmPcdKgAllocSchemes(t_Handle h_FmPcd, uint8_t numOfSchemes, uint8_t guestId, uint8_t *p_SchemesIds) { t_FmPcd *p_FmPcd = (t_FmPcd*)h_FmPcd; uint32_t intFlags; uint8_t i,j; SANITY_CHECK_RETURN_ERROR(p_FmPcd, E_INVALID_HANDLE); SANITY_CHECK_RETURN_ERROR(p_FmPcd->p_FmPcdKg, E_INVALID_HANDLE); intFlags = FmPcdLock(p_FmPcd); for(j=0,i=0;ip_FmPcdKg->schemesMng[i].allocated) { p_FmPcd->p_FmPcdKg->schemesMng[i].allocated = TRUE; p_FmPcd->p_FmPcdKg->schemesMng[i].ownerId = guestId; p_SchemesIds[j] = i; j++; } } if (j != numOfSchemes) { /* roll back */ for(j--; j; j--) { p_FmPcd->p_FmPcdKg->schemesMng[p_SchemesIds[j]].allocated = FALSE; p_FmPcd->p_FmPcdKg->schemesMng[p_SchemesIds[j]].ownerId = 0; p_SchemesIds[j] = 0; } FmPcdUnlock(p_FmPcd, intFlags); RETURN_ERROR(MAJOR, E_NOT_AVAILABLE, ("No schemes found")); } FmPcdUnlock(p_FmPcd, intFlags); return E_OK; } t_Error FmPcdKgFreeSchemes(t_Handle h_FmPcd, uint8_t numOfSchemes, uint8_t guestId, uint8_t *p_SchemesIds) { t_FmPcd *p_FmPcd = (t_FmPcd*)h_FmPcd; uint32_t intFlags; uint8_t i; SANITY_CHECK_RETURN_ERROR(p_FmPcd, E_INVALID_HANDLE); SANITY_CHECK_RETURN_ERROR(p_FmPcd->p_FmPcdKg, E_INVALID_HANDLE); intFlags = FmPcdLock(p_FmPcd); for(i=0;ip_FmPcdKg->schemesMng[p_SchemesIds[i]].allocated) { FmPcdUnlock(p_FmPcd, intFlags); RETURN_ERROR(MAJOR, E_INVALID_STATE, ("Scheme was not previously allocated")); } if(p_FmPcd->p_FmPcdKg->schemesMng[p_SchemesIds[i]].ownerId != guestId) { FmPcdUnlock(p_FmPcd, intFlags); RETURN_ERROR(MAJOR, E_INVALID_STATE, ("Scheme is not owned by caller. ")); } p_FmPcd->p_FmPcdKg->schemesMng[p_SchemesIds[i]].allocated = FALSE; p_FmPcd->p_FmPcdKg->schemesMng[p_SchemesIds[i]].ownerId = 0; } FmPcdUnlock(p_FmPcd, intFlags); return E_OK; } t_Error KgAllocClsPlanEntries(t_Handle h_FmPcd, uint16_t numOfClsPlanEntries, uint8_t guestId, uint8_t *p_First) { t_FmPcd *p_FmPcd = (t_FmPcd*)h_FmPcd; uint32_t intFlags; uint8_t numOfBlocks, blocksFound=0, first=0; uint8_t i, j; intFlags = FmPcdLock(p_FmPcd); if(!numOfClsPlanEntries) { FmPcdUnlock(p_FmPcd, intFlags); return E_OK; } if ((numOfClsPlanEntries % CLS_PLAN_NUM_PER_GRP) || (!POWER_OF_2(numOfClsPlanEntries))) { FmPcdUnlock(p_FmPcd, intFlags); RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("numOfClsPlanEntries must be a power of 2 and divisible by 8")); } numOfBlocks = (uint8_t)(numOfClsPlanEntries/CLS_PLAN_NUM_PER_GRP); /* try to find consequent blocks */ first = 0; for(i=0;ip_FmPcdKg->clsPlanBlocksMng[i].allocated) { blocksFound++; i++; if(blocksFound == numOfBlocks) break; } else { blocksFound = 0; /* advance i to the next aligned address */ first = i = (uint8_t)(first + numOfBlocks); } } if(blocksFound == numOfBlocks) { *p_First = (uint8_t)(first*CLS_PLAN_NUM_PER_GRP); for(j = first; jp_FmPcdKg->clsPlanBlocksMng[j].allocated = TRUE; p_FmPcd->p_FmPcdKg->clsPlanBlocksMng[j].ownerId = guestId; } FmPcdUnlock(p_FmPcd, intFlags); return E_OK; } else { FmPcdUnlock(p_FmPcd, intFlags); RETURN_ERROR(MINOR, E_FULL, ("No recources for clsPlan")); } } void KgFreeClsPlanEntries(t_Handle h_FmPcd, uint16_t numOfClsPlanEntries, uint8_t guestId, uint8_t base) { t_FmPcd *p_FmPcd = (t_FmPcd*)h_FmPcd; uint32_t intFlags; uint8_t numOfBlocks; uint8_t i, baseBlock; UNUSED( guestId); intFlags = FmPcdLock(p_FmPcd); numOfBlocks = (uint8_t)(numOfClsPlanEntries/CLS_PLAN_NUM_PER_GRP); ASSERT_COND(!(base%CLS_PLAN_NUM_PER_GRP)); baseBlock = (uint8_t)(base/CLS_PLAN_NUM_PER_GRP); for(i=baseBlock;ip_FmPcdKg->clsPlanBlocksMng[i].allocated); ASSERT_COND(guestId == p_FmPcd->p_FmPcdKg->clsPlanBlocksMng[i].ownerId); p_FmPcd->p_FmPcdKg->clsPlanBlocksMng[i].allocated = FALSE; p_FmPcd->p_FmPcdKg->clsPlanBlocksMng[i].ownerId = 0; } FmPcdUnlock(p_FmPcd, intFlags); } void KgEnable(t_FmPcd *p_FmPcd) { t_FmPcdKgRegs *p_Regs = p_FmPcd->p_FmPcdKg->p_FmPcdKgRegs; ASSERT_COND(FmIsMaster(p_FmPcd->h_Fm)); WRITE_UINT32(p_Regs->kggcr,GET_UINT32(p_Regs->kggcr) | FM_PCD_KG_KGGCR_EN); } void KgDisable(t_FmPcd *p_FmPcd) { t_FmPcdKgRegs *p_Regs = p_FmPcd->p_FmPcdKg->p_FmPcdKgRegs; ASSERT_COND(FmIsMaster(p_FmPcd->h_Fm)); WRITE_UINT32(p_Regs->kggcr,GET_UINT32(p_Regs->kggcr) & ~FM_PCD_KG_KGGCR_EN); } void KgSetClsPlan(t_Handle h_FmPcd, t_FmPcdKgInterModuleClsPlanSet *p_Set) { t_FmPcd *p_FmPcd = (t_FmPcd*)h_FmPcd; t_FmPcdKgClsPlanRegs *p_FmPcdKgPortRegs; uint32_t tmpKgarReg=0, intFlags; uint16_t i, j; SANITY_CHECK_RETURN(p_FmPcd, E_INVALID_HANDLE); SANITY_CHECK_RETURN(p_FmPcd->p_FmPcdKg, E_INVALID_HANDLE); ASSERT_COND(FmIsMaster(p_FmPcd->h_Fm)); p_FmPcdKgPortRegs = &p_FmPcd->p_FmPcdKg->p_FmPcdKgRegs->indirectAccessRegs.clsPlanRegs; intFlags = FmPcdLock(p_FmPcd); for(i=p_Set->baseEntry;ibaseEntry+p_Set->numOfClsPlanEntries;i+=8) { tmpKgarReg = FmPcdKgBuildWriteClsPlanBlockActionReg((uint8_t)(i / CLS_PLAN_NUM_PER_GRP)); for (j = i; j < i+8; j++) { ASSERT_COND(IN_RANGE(0, (j - p_Set->baseEntry), FM_PCD_MAX_NUM_OF_CLS_PLANS-1)); WRITE_UINT32(p_FmPcdKgPortRegs->kgcpe[j % CLS_PLAN_NUM_PER_GRP],p_Set->vectors[j - p_Set->baseEntry]); } if(WriteKgarWait(p_FmPcd, tmpKgarReg) != E_OK) { REPORT_ERROR(MAJOR, E_INVALID_STATE, ("WriteKgarWait FAILED")); return; } } FmPcdUnlock(p_FmPcd, intFlags); } static void PcdKgErrorException(t_Handle h_FmPcd) { t_FmPcd *p_FmPcd = (t_FmPcd *)h_FmPcd; uint32_t event, force, schemeIndexes = 0,index = 0, mask = 0; ASSERT_COND(FmIsMaster(p_FmPcd->h_Fm)); event = GET_UINT32(p_FmPcd->p_FmPcdKg->p_FmPcdKgRegs->kgeer); mask = GET_UINT32(p_FmPcd->p_FmPcdKg->p_FmPcdKgRegs->kgeeer); schemeIndexes = GET_UINT32(p_FmPcd->p_FmPcdKg->p_FmPcdKgRegs->kgseer); schemeIndexes &= GET_UINT32(p_FmPcd->p_FmPcdKg->p_FmPcdKgRegs->kgseeer); event &= mask; /* clear the forced events */ force = GET_UINT32(p_FmPcd->p_FmPcdKg->p_FmPcdKgRegs->kgfeer); if(force & event) WRITE_UINT32(p_FmPcd->p_FmPcdKg->p_FmPcdKgRegs->kgfeer, force & ~event); WRITE_UINT32(p_FmPcd->p_FmPcdKg->p_FmPcdKgRegs->kgeer, event); WRITE_UINT32(p_FmPcd->p_FmPcdKg->p_FmPcdKgRegs->kgseer, schemeIndexes); if(event & FM_PCD_KG_DOUBLE_ECC) p_FmPcd->f_Exception(p_FmPcd->h_App,e_FM_PCD_KG_EXCEPTION_DOUBLE_ECC); if(event & FM_PCD_KG_KEYSIZE_OVERFLOW) { if(schemeIndexes) { while(schemeIndexes) { if(schemeIndexes & 0x1) p_FmPcd->f_FmPcdIndexedException(p_FmPcd->h_App,e_FM_PCD_KG_EXCEPTION_KEYSIZE_OVERFLOW, (uint16_t)(31 - index)); schemeIndexes >>= 1; index+=1; } } else /* this should happen only when interrupt is forced. */ p_FmPcd->f_Exception(p_FmPcd->h_App,e_FM_PCD_KG_EXCEPTION_KEYSIZE_OVERFLOW); } } static t_Error KgInitGuest(t_FmPcd *p_FmPcd) { t_Error err = E_OK; t_FmPcdIpcKgSchemesParams kgAlloc; uint32_t replyLength; t_FmPcdIpcReply reply; t_FmPcdIpcMsg msg; ASSERT_COND(p_FmPcd->guestId != NCSW_MASTER_ID); /* in GUEST_PARTITION, we use the IPC */ memset(&reply, 0, sizeof(reply)); memset(&msg, 0, sizeof(msg)); memset(&kgAlloc, 0, sizeof(t_FmPcdIpcKgSchemesParams)); kgAlloc.numOfSchemes = p_FmPcd->p_FmPcdKg->numOfSchemes; kgAlloc.guestId = p_FmPcd->guestId; msg.msgId = FM_PCD_ALLOC_KG_SCHEMES; memcpy(msg.msgBody, &kgAlloc, sizeof(kgAlloc)); replyLength = sizeof(uint32_t) + p_FmPcd->p_FmPcdKg->numOfSchemes*sizeof(uint8_t); if ((err = XX_IpcSendMessage(p_FmPcd->h_IpcSession, (uint8_t*)&msg, sizeof(msg.msgId) + sizeof(kgAlloc), (uint8_t*)&reply, &replyLength, NULL, NULL)) != E_OK) RETURN_ERROR(MAJOR, err, NO_MSG); if(replyLength != (sizeof(uint32_t) + p_FmPcd->p_FmPcdKg->numOfSchemes*sizeof(uint8_t))) RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("IPC reply length mismatch")); memcpy(p_FmPcd->p_FmPcdKg->schemesIds, (uint8_t*)(reply.replyBody),p_FmPcd->p_FmPcdKg->numOfSchemes*sizeof(uint8_t)); return (t_Error)reply.error; } static t_Error KgInitMaster(t_FmPcd *p_FmPcd) { t_Error err = E_OK; t_FmPcdKgRegs *p_Regs = p_FmPcd->p_FmPcdKg->p_FmPcdKgRegs; int i; uint8_t hardwarePortId = 0; uint32_t tmpReg; ASSERT_COND(p_FmPcd->guestId == NCSW_MASTER_ID); /**********************KGEER******************/ WRITE_UINT32(p_Regs->kgeer, (FM_PCD_KG_DOUBLE_ECC | FM_PCD_KG_KEYSIZE_OVERFLOW)); /**********************KGEER******************/ /**********************KGEEER******************/ tmpReg = 0; if(p_FmPcd->exceptions & FM_PCD_EX_KG_DOUBLE_ECC) { FmEnableRamsEcc(p_FmPcd->h_Fm); tmpReg |= FM_PCD_KG_DOUBLE_ECC; } if(p_FmPcd->exceptions & FM_PCD_EX_KG_KEYSIZE_OVERFLOW) tmpReg |= FM_PCD_KG_KEYSIZE_OVERFLOW; WRITE_UINT32(p_Regs->kgeeer,tmpReg); /**********************KGEEER******************/ /**********************KGFDOR******************/ WRITE_UINT32(p_Regs->kgfdor,0); /**********************KGFDOR******************/ /**********************KGGDV0R******************/ WRITE_UINT32(p_Regs->kggdv0r,0); /**********************KGGDV0R******************/ /**********************KGGDV1R******************/ WRITE_UINT32(p_Regs->kggdv1r,0); /**********************KGGDV1R******************/ /**********************KGGCR******************/ WRITE_UINT32(p_Regs->kggcr, NIA_ENG_BMI | NIA_BMI_AC_ENQ_FRAME); /**********************KGGCR******************/ /* register even if no interrupts enabled, to allow future enablement */ FmRegisterIntr(p_FmPcd->h_Fm, e_FM_MOD_KG, 0, e_FM_INTR_TYPE_ERR, PcdKgErrorException, p_FmPcd); /* clear binding between ports to schemes so that all ports are not bound to any schemes */ for (i=0;ikgseer, 0xFFFFFFFF); WRITE_UINT32(p_Regs->kgseeer, 0xFFFFFFFF); if(p_FmPcd->p_FmPcdKg->numOfSchemes) { err = FmPcdKgAllocSchemes(p_FmPcd, p_FmPcd->p_FmPcdKg->numOfSchemes, p_FmPcd->guestId, p_FmPcd->p_FmPcdKg->schemesIds); if(err) RETURN_ERROR(MINOR, err, NO_MSG); } return E_OK; } /****************************************/ /* API routines */ /****************************************/ t_Error FM_PCD_KgSetAdditionalDataAfterParsing(t_Handle h_FmPcd, uint8_t payloadOffset) { t_FmPcd *p_FmPcd = (t_FmPcd*)h_FmPcd; t_FmPcdKgRegs *p_Regs; SANITY_CHECK_RETURN_ERROR(p_FmPcd, E_INVALID_HANDLE); SANITY_CHECK_RETURN_ERROR(!p_FmPcd->p_FmPcdDriverParam, E_NULL_POINTER); SANITY_CHECK_RETURN_ERROR(p_FmPcd->p_FmPcdKg, E_NULL_POINTER); SANITY_CHECK_RETURN_ERROR(p_FmPcd->p_FmPcdKg->p_FmPcdKgRegs, E_NULL_POINTER); p_Regs = p_FmPcd->p_FmPcdKg->p_FmPcdKgRegs; if(!FmIsMaster(p_FmPcd->h_Fm)) RETURN_ERROR(MAJOR, E_NOT_SUPPORTED, ("FM_PCD_KgSetAdditionalDataAfterParsing - guest mode!")); /* not needed if(payloadOffset > 256) RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("data exatraction offset from parseing end can not be more than 256")); */ WRITE_UINT32(p_Regs->kgfdor,payloadOffset); return E_OK; } t_Error FM_PCD_KgSetDfltValue(t_Handle h_FmPcd, uint8_t valueId, uint32_t value) { t_FmPcd *p_FmPcd = (t_FmPcd*)h_FmPcd; t_FmPcdKgRegs *p_Regs; SANITY_CHECK_RETURN_ERROR(p_FmPcd, E_INVALID_HANDLE); SANITY_CHECK_RETURN_ERROR(((valueId == 0) || (valueId == 1)), E_INVALID_VALUE); SANITY_CHECK_RETURN_ERROR(!p_FmPcd->p_FmPcdDriverParam, E_NULL_POINTER); SANITY_CHECK_RETURN_ERROR(p_FmPcd->p_FmPcdKg, E_NULL_POINTER); SANITY_CHECK_RETURN_ERROR(p_FmPcd->p_FmPcdKg->p_FmPcdKgRegs, E_NULL_POINTER); p_Regs = p_FmPcd->p_FmPcdKg->p_FmPcdKgRegs; if(!FmIsMaster(p_FmPcd->h_Fm)) RETURN_ERROR(MAJOR, E_NOT_SUPPORTED, ("FM_PCD_KgSetDfltValue - guest mode!")); if(valueId == 0) WRITE_UINT32(p_Regs->kggdv0r,value); else WRITE_UINT32(p_Regs->kggdv1r,value); return E_OK; } #if (defined(DEBUG_ERRORS) && (DEBUG_ERRORS > 0)) t_Error FM_PCD_KgDumpRegs(t_Handle h_FmPcd) { t_FmPcd *p_FmPcd = (t_FmPcd*)h_FmPcd; int i = 0, j = 0; uint8_t hardwarePortId = 0; uint32_t tmpKgarReg, intFlags; t_Error err = E_OK; t_FmPcdIpcMsg msg; DECLARE_DUMP; SANITY_CHECK_RETURN_ERROR(p_FmPcd, E_INVALID_HANDLE); SANITY_CHECK_RETURN_ERROR(p_FmPcd->p_FmPcdKg, E_INVALID_HANDLE); SANITY_CHECK_RETURN_ERROR(!p_FmPcd->p_FmPcdDriverParam, E_INVALID_STATE); if(p_FmPcd->guestId != NCSW_MASTER_ID) { memset(&msg, 0, sizeof(msg)); msg.msgId = FM_PCD_KG_DUMP_REGS; return XX_IpcSendMessage(p_FmPcd->h_IpcSession, (uint8_t*)&msg, sizeof(msg.msgId), NULL, NULL, NULL, NULL); } DUMP_SUBTITLE(("\n")); DUMP_TITLE(p_FmPcd->p_FmPcdKg->p_FmPcdKgRegs, ("FmPcdKgRegs Regs")); DUMP_VAR(p_FmPcd->p_FmPcdKg->p_FmPcdKgRegs,kggcr); DUMP_VAR(p_FmPcd->p_FmPcdKg->p_FmPcdKgRegs,kgeer); DUMP_VAR(p_FmPcd->p_FmPcdKg->p_FmPcdKgRegs,kgeeer); DUMP_VAR(p_FmPcd->p_FmPcdKg->p_FmPcdKgRegs,kgseer); DUMP_VAR(p_FmPcd->p_FmPcdKg->p_FmPcdKgRegs,kgseeer); DUMP_VAR(p_FmPcd->p_FmPcdKg->p_FmPcdKgRegs,kggsr); DUMP_VAR(p_FmPcd->p_FmPcdKg->p_FmPcdKgRegs,kgtpc); DUMP_VAR(p_FmPcd->p_FmPcdKg->p_FmPcdKgRegs,kgserc); DUMP_VAR(p_FmPcd->p_FmPcdKg->p_FmPcdKgRegs,kgfdor); DUMP_VAR(p_FmPcd->p_FmPcdKg->p_FmPcdKgRegs,kggdv0r); DUMP_VAR(p_FmPcd->p_FmPcdKg->p_FmPcdKgRegs,kggdv1r); DUMP_VAR(p_FmPcd->p_FmPcdKg->p_FmPcdKgRegs,kgfer); DUMP_VAR(p_FmPcd->p_FmPcdKg->p_FmPcdKgRegs,kgfeer); DUMP_VAR(p_FmPcd->p_FmPcdKg->p_FmPcdKgRegs,kgar); DUMP_SUBTITLE(("\n")); intFlags = FmPcdLock(p_FmPcd); for(j = 0;jp_FmPcdKg->p_FmPcdKgRegs->indirectAccessRegs.schemeRegs, ("FmPcdKgIndirectAccessSchemeRegs Scheme %d Regs", j)); DUMP_VAR(&p_FmPcd->p_FmPcdKg->p_FmPcdKgRegs->indirectAccessRegs.schemeRegs,kgse_mode); DUMP_VAR(&p_FmPcd->p_FmPcdKg->p_FmPcdKgRegs->indirectAccessRegs.schemeRegs,kgse_ekfc); DUMP_VAR(&p_FmPcd->p_FmPcdKg->p_FmPcdKgRegs->indirectAccessRegs.schemeRegs,kgse_ekdv); DUMP_VAR(&p_FmPcd->p_FmPcdKg->p_FmPcdKgRegs->indirectAccessRegs.schemeRegs,kgse_bmch); DUMP_VAR(&p_FmPcd->p_FmPcdKg->p_FmPcdKgRegs->indirectAccessRegs.schemeRegs,kgse_bmcl); DUMP_VAR(&p_FmPcd->p_FmPcdKg->p_FmPcdKgRegs->indirectAccessRegs.schemeRegs,kgse_fqb); DUMP_VAR(&p_FmPcd->p_FmPcdKg->p_FmPcdKgRegs->indirectAccessRegs.schemeRegs,kgse_hc); DUMP_VAR(&p_FmPcd->p_FmPcdKg->p_FmPcdKgRegs->indirectAccessRegs.schemeRegs,kgse_ppc); DUMP_TITLE(&p_FmPcd->p_FmPcdKg->p_FmPcdKgRegs->indirectAccessRegs.schemeRegs.kgse_gec, ("kgse_gec")); DUMP_SUBSTRUCT_ARRAY(i, FM_PCD_KG_NUM_OF_GENERIC_REGS) { DUMP_MEMORY(&p_FmPcd->p_FmPcdKg->p_FmPcdKgRegs->indirectAccessRegs.schemeRegs.kgse_gec[i], sizeof(uint32_t)); } DUMP_VAR(&p_FmPcd->p_FmPcdKg->p_FmPcdKgRegs->indirectAccessRegs.schemeRegs,kgse_spc); DUMP_VAR(&p_FmPcd->p_FmPcdKg->p_FmPcdKgRegs->indirectAccessRegs.schemeRegs,kgse_dv0); DUMP_VAR(&p_FmPcd->p_FmPcdKg->p_FmPcdKgRegs->indirectAccessRegs.schemeRegs,kgse_dv1); DUMP_VAR(&p_FmPcd->p_FmPcdKg->p_FmPcdKgRegs->indirectAccessRegs.schemeRegs,kgse_ccbs); DUMP_VAR(&p_FmPcd->p_FmPcdKg->p_FmPcdKgRegs->indirectAccessRegs.schemeRegs,kgse_mv); } DUMP_SUBTITLE(("\n")); for (i=0;ip_FmPcdKg->p_FmPcdKgRegs->indirectAccessRegs.portRegs, ("FmPcdKgIndirectAccessPortRegs PCD Port %d regs", hardwarePortId)); DUMP_VAR(&p_FmPcd->p_FmPcdKg->p_FmPcdKgRegs->indirectAccessRegs.portRegs, kgoe_sp); DUMP_VAR(&p_FmPcd->p_FmPcdKg->p_FmPcdKgRegs->indirectAccessRegs.portRegs, kgoe_cpp); } DUMP_SUBTITLE(("\n")); for(j=0;jp_FmPcdKg->p_FmPcdKgRegs->indirectAccessRegs.clsPlanRegs, ("FmPcdKgIndirectAccessClsPlanRegs Regs group %d", j)); DUMP_TITLE(&p_FmPcd->p_FmPcdKg->p_FmPcdKgRegs->indirectAccessRegs.clsPlanRegs.kgcpe, ("kgcpe")); tmpKgarReg = FmPcdKgBuildReadClsPlanBlockActionReg((uint8_t)j); err = WriteKgarWait(p_FmPcd, tmpKgarReg); if(err) RETURN_ERROR(MINOR, err, NO_MSG); DUMP_SUBSTRUCT_ARRAY(i, 8) DUMP_MEMORY(&p_FmPcd->p_FmPcdKg->p_FmPcdKgRegs->indirectAccessRegs.clsPlanRegs.kgcpe[i], sizeof(uint32_t)); } FmPcdUnlock(p_FmPcd, intFlags); return E_OK; } #endif /* (defined(DEBUG_ERRORS) && ... */ t_Handle KgConfig( t_FmPcd *p_FmPcd, t_FmPcdParams *p_FmPcdParams) { t_FmPcdKg *p_FmPcdKg; UNUSED(p_FmPcd); if (p_FmPcdParams->numOfSchemes > FM_PCD_KG_NUM_OF_SCHEMES) { REPORT_ERROR(MAJOR, E_INVALID_VALUE, ("numOfSchemes should not exceed %d", FM_PCD_KG_NUM_OF_SCHEMES)); return NULL; } p_FmPcdKg = (t_FmPcdKg *)XX_Malloc(sizeof(t_FmPcdKg)); if (!p_FmPcdKg) { REPORT_ERROR(MAJOR, E_NO_MEMORY, ("FM Keygen allocation FAILED")); return NULL; } memset(p_FmPcdKg, 0, sizeof(t_FmPcdKg)); if(FmIsMaster(p_FmPcd->h_Fm)) { p_FmPcdKg->p_FmPcdKgRegs = (t_FmPcdKgRegs *)UINT_TO_PTR(FmGetPcdKgBaseAddr(p_FmPcdParams->h_Fm)); p_FmPcd->exceptions |= DEFAULT_fmPcdKgErrorExceptions; } p_FmPcdKg->numOfSchemes = p_FmPcdParams->numOfSchemes; if((p_FmPcd->guestId == NCSW_MASTER_ID) && !p_FmPcdKg->numOfSchemes) { p_FmPcdKg->numOfSchemes = FM_PCD_KG_NUM_OF_SCHEMES; DBG(WARNING, ("numOfSchemes was defined 0 by user, re-defined by driver to FM_PCD_KG_NUM_OF_SCHEMES")); } p_FmPcdKg->emptyClsPlanGrpId = ILLEGAL_CLS_PLAN; return p_FmPcdKg; } t_Error KgInit(t_FmPcd *p_FmPcd) { if (p_FmPcd->guestId == NCSW_MASTER_ID) return KgInitMaster(p_FmPcd); else return KgInitGuest(p_FmPcd); } t_Error KgFree(t_FmPcd *p_FmPcd) { t_FmPcdIpcKgSchemesParams kgAlloc; t_Error err = E_OK; t_FmPcdIpcMsg msg; uint32_t replyLength; t_FmPcdIpcReply reply; FmUnregisterIntr(p_FmPcd->h_Fm, e_FM_MOD_KG, 0, e_FM_INTR_TYPE_ERR); if(p_FmPcd->guestId == NCSW_MASTER_ID) return FmPcdKgFreeSchemes(p_FmPcd, p_FmPcd->p_FmPcdKg->numOfSchemes, p_FmPcd->guestId, p_FmPcd->p_FmPcdKg->schemesIds); /* guest */ memset(&reply, 0, sizeof(reply)); memset(&msg, 0, sizeof(msg)); kgAlloc.numOfSchemes = p_FmPcd->p_FmPcdKg->numOfSchemes; kgAlloc.guestId = p_FmPcd->guestId; ASSERT_COND(kgAlloc.numOfSchemes < FM_PCD_KG_NUM_OF_SCHEMES); memcpy(kgAlloc.schemesIds, p_FmPcd->p_FmPcdKg->schemesIds , (sizeof(uint8_t))*kgAlloc.numOfSchemes); msg.msgId = FM_PCD_FREE_KG_SCHEMES; memcpy(msg.msgBody, &kgAlloc, sizeof(kgAlloc)); replyLength = sizeof(uint32_t); if ((err = XX_IpcSendMessage(p_FmPcd->h_IpcSession, (uint8_t*)&msg, sizeof(msg.msgId) + sizeof(kgAlloc), (uint8_t*)&reply, &replyLength, NULL, NULL)) != E_OK) RETURN_ERROR(MAJOR, err, NO_MSG); if (replyLength != sizeof(uint32_t)) RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("IPC reply length mismatch")); return (t_Error)reply.error; } t_Error FmPcdKgSetOrBindToClsPlanGrp(t_Handle h_FmPcd, uint8_t hardwarePortId, uint8_t netEnvId, protocolOpt_t *p_OptArray, uint8_t *p_ClsPlanGrpId, bool *p_IsEmptyClsPlanGrp) { t_FmPcd *p_FmPcd = (t_FmPcd *)h_FmPcd; t_FmPcdKgInterModuleClsPlanGrpParams grpParams, *p_GrpParams; t_FmPcdKgClsPlanGrp *p_ClsPlanGrp; t_FmPcdKgInterModuleClsPlanSet *p_ClsPlanSet; t_Error err; memset(&grpParams, 0, sizeof(grpParams)); grpParams.clsPlanGrpId = ILLEGAL_CLS_PLAN; p_GrpParams = &grpParams; p_GrpParams->netEnvId = netEnvId; err = PcdGetClsPlanGrpParams(h_FmPcd, p_GrpParams); if(err) RETURN_ERROR(MINOR,err,NO_MSG); if(p_GrpParams->grpExists) *p_ClsPlanGrpId = p_GrpParams->clsPlanGrpId; else { p_ClsPlanSet = (t_FmPcdKgInterModuleClsPlanSet *)XX_Malloc(sizeof(t_FmPcdKgInterModuleClsPlanSet)); if (!p_ClsPlanSet) RETURN_ERROR(MAJOR, E_NO_MEMORY, ("memory allocation failed for p_ClsPlanSet")); memset(p_ClsPlanSet, 0, sizeof(t_FmPcdKgInterModuleClsPlanSet)); err = FmPcdKgBuildClsPlanGrp(h_FmPcd, p_GrpParams, p_ClsPlanSet); if (err) { XX_Free(p_ClsPlanSet); RETURN_ERROR(MINOR,err,NO_MSG); } *p_ClsPlanGrpId = p_GrpParams->clsPlanGrpId; if (p_FmPcd->h_Hc) { /* write clsPlan entries to memory */ err = FmHcPcdKgSetClsPlan(p_FmPcd->h_Hc, p_ClsPlanSet); if (err) { XX_Free(p_ClsPlanSet); RETURN_ERROR(MAJOR, err, NO_MSG); } } else /* write clsPlan entries to memory */ KgSetClsPlan(p_FmPcd, p_ClsPlanSet); XX_Free(p_ClsPlanSet); } /* mark if this is an empty classification group */ if(*p_ClsPlanGrpId == p_FmPcd->p_FmPcdKg->emptyClsPlanGrpId) *p_IsEmptyClsPlanGrp = TRUE; else *p_IsEmptyClsPlanGrp = FALSE; p_ClsPlanGrp = &p_FmPcd->p_FmPcdKg->clsPlanGrps[*p_ClsPlanGrpId]; /* increment owners number */ p_ClsPlanGrp->owners++; /* copy options array for port */ memcpy(p_OptArray, &p_FmPcd->p_FmPcdKg->clsPlanGrps[*p_ClsPlanGrpId].optArray, FM_PCD_MAX_NUM_OF_OPTIONS(FM_PCD_MAX_NUM_OF_CLS_PLANS)*sizeof(protocolOpt_t)); /* bind port to the new or existing group */ err = KgBindPortToClsPlanGrp(p_FmPcd, hardwarePortId, p_GrpParams->clsPlanGrpId); if(err) RETURN_ERROR(MINOR, err, NO_MSG); return E_OK; } t_Error FmPcdKgDeleteOrUnbindPortToClsPlanGrp(t_Handle h_FmPcd, uint8_t hardwarePortId, uint8_t clsPlanGrpId) { t_FmPcd *p_FmPcd = (t_FmPcd *)h_FmPcd; t_FmPcdKgClsPlanGrp *p_ClsPlanGrp = &p_FmPcd->p_FmPcdKg->clsPlanGrps[clsPlanGrpId]; t_FmPcdKgInterModuleClsPlanSet *p_ClsPlanSet; FmPcdKgUnbindPortToClsPlanGrp(p_FmPcd, hardwarePortId); /* decrement owners number */ ASSERT_COND(p_ClsPlanGrp->owners); p_ClsPlanGrp->owners--; if(!p_ClsPlanGrp->owners) { if (p_FmPcd->h_Hc) return FmHcPcdKgDeleteClsPlan(p_FmPcd->h_Hc, clsPlanGrpId); else { /* clear clsPlan entries in memory */ p_ClsPlanSet = (t_FmPcdKgInterModuleClsPlanSet *)XX_Malloc(sizeof(t_FmPcdKgInterModuleClsPlanSet)); if (!p_ClsPlanSet) RETURN_ERROR(MAJOR, E_NO_MEMORY, ("memory allocation failed for p_ClsPlanSet")); memset(p_ClsPlanSet, 0, sizeof(t_FmPcdKgInterModuleClsPlanSet)); p_ClsPlanSet->baseEntry = p_FmPcd->p_FmPcdKg->clsPlanGrps[clsPlanGrpId].baseEntry; p_ClsPlanSet->numOfClsPlanEntries = p_FmPcd->p_FmPcdKg->clsPlanGrps[clsPlanGrpId].sizeOfGrp; KgSetClsPlan(p_FmPcd, p_ClsPlanSet); XX_Free(p_ClsPlanSet); FmPcdKgDestroyClsPlanGrp(h_FmPcd, clsPlanGrpId); } } return E_OK; } t_Error FmPcdKgBuildScheme(t_Handle h_FmPcd, t_FmPcdKgSchemeParams *p_Scheme, t_FmPcdKgInterModuleSchemeRegs *p_SchemeRegs) { t_FmPcd *p_FmPcd = (t_FmPcd *)h_FmPcd; uint32_t grpBits = 0; uint8_t grpBase; bool direct=TRUE, absolute=FALSE; uint16_t profileId=0, numOfProfiles=0, relativeProfileId; t_Error err = E_OK; int i = 0; t_NetEnvParams netEnvParams; uint32_t tmpReg, fqbTmp = 0, ppcTmp = 0, selectTmp, maskTmp, knownTmp, genTmp; t_FmPcdKgKeyExtractAndHashParams *p_KeyAndHash = NULL; uint8_t j, curr, idx; uint8_t id, shift=0, code=0, offset=0, size=0; t_FmPcdExtractEntry *p_Extract = NULL; t_FmPcdKgExtractedOrParams *p_ExtractOr; bool generic = FALSE; t_KnownFieldsMasks bitMask; e_FmPcdKgExtractDfltSelect swDefault = (e_FmPcdKgExtractDfltSelect)0; t_FmPcdKgSchemesExtracts *p_LocalExtractsArray; uint8_t numOfSwDefaults = 0; t_FmPcdKgExtractDflt swDefaults[NUM_OF_SW_DEFAULTS]; uint8_t currGenId = 0, relativeSchemeId; if(!p_Scheme->modify) relativeSchemeId = p_Scheme->id.relativeSchemeId; else relativeSchemeId = FmPcdKgGetRelativeSchemeId(p_FmPcd, (uint8_t)(PTR_TO_UINT(p_Scheme->id.h_Scheme)-1)); memset(&p_FmPcd->p_FmPcdKg->schemes[relativeSchemeId], 0, sizeof(t_FmPcdKgScheme)); memset(swDefaults, 0, NUM_OF_SW_DEFAULTS*sizeof(t_FmPcdKgExtractDflt)); memset(p_SchemeRegs, 0, sizeof(t_FmPcdKgInterModuleSchemeRegs)); if (p_Scheme->netEnvParams.numOfDistinctionUnits > FM_PCD_MAX_NUM_OF_DISTINCTION_UNITS) RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("numOfDistinctionUnits should not exceed %d", FM_PCD_MAX_NUM_OF_DISTINCTION_UNITS)); /* by netEnv parameters, get match vector */ if(!p_Scheme->alwaysDirect) { p_FmPcd->p_FmPcdKg->schemes[relativeSchemeId].netEnvId = (uint8_t)(PTR_TO_UINT(p_Scheme->netEnvParams.h_NetEnv)-1); netEnvParams.netEnvId = p_FmPcd->p_FmPcdKg->schemes[relativeSchemeId].netEnvId; netEnvParams.numOfDistinctionUnits = p_Scheme->netEnvParams.numOfDistinctionUnits; memcpy(netEnvParams.unitIds, p_Scheme->netEnvParams.unitIds, (sizeof(uint8_t))*p_Scheme->netEnvParams.numOfDistinctionUnits); err = PcdGetUnitsVector(p_FmPcd, &netEnvParams); if(err) RETURN_ERROR(MAJOR, E_INVALID_STATE, NO_MSG); p_FmPcd->p_FmPcdKg->schemes[relativeSchemeId].matchVector = netEnvParams.vector; } else { p_FmPcd->p_FmPcdKg->schemes[relativeSchemeId].matchVector = SCHEME_ALWAYS_DIRECT; p_FmPcd->p_FmPcdKg->schemes[relativeSchemeId].netEnvId = ILLEGAL_NETENV; } if(p_Scheme->nextEngine == e_FM_PCD_INVALID) RETURN_ERROR(MAJOR, E_INVALID_STATE, ("Next Engine of the scheme is not Valid")); if(p_Scheme->bypassFqidGeneration) { #ifdef FM_KG_NO_BYPASS_FQID_GEN { t_FmRevisionInfo revInfo; FM_GetRevision(p_FmPcd->h_Fm, &revInfo); if (revInfo.majorRev != 4) RETURN_ERROR(MAJOR, E_NOT_SUPPORTED, ("bypassFqidGeneration.")); } #endif /* FM_KG_NO_BYPASS_FQID_GEN */ if(p_Scheme->baseFqid) RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("baseFqid set for a scheme that does not generate an FQID")); } else if(!p_Scheme->baseFqid) DBG(WARNING, ("baseFqid is 0.")); if(p_Scheme->nextEngine == e_FM_PCD_PLCR) { direct = p_Scheme->kgNextEngineParams.plcrProfile.direct; p_FmPcd->p_FmPcdKg->schemes[relativeSchemeId].directPlcr = direct; absolute = (bool)(p_Scheme->kgNextEngineParams.plcrProfile.sharedProfile ? TRUE : FALSE); if(!direct && absolute) RETURN_ERROR(MAJOR, E_INVALID_STATE, ("Indirect policing is not available when profile is shared.")); if(direct) { profileId = p_Scheme->kgNextEngineParams.plcrProfile.profileSelect.directRelativeProfileId; numOfProfiles = 1; } else { profileId = p_Scheme->kgNextEngineParams.plcrProfile.profileSelect.indirectProfile.fqidOffsetRelativeProfileIdBase; shift = p_Scheme->kgNextEngineParams.plcrProfile.profileSelect.indirectProfile.fqidOffsetShift; numOfProfiles = p_Scheme->kgNextEngineParams.plcrProfile.profileSelect.indirectProfile.numOfProfiles; } } if(p_Scheme->nextEngine == e_FM_PCD_CC) { #ifdef FM_KG_NO_BYPASS_PLCR_PROFILE_GEN if((p_Scheme->kgNextEngineParams.cc.plcrNext) && (p_Scheme->kgNextEngineParams.cc.bypassPlcrProfileGeneration)) { t_FmRevisionInfo revInfo; FM_GetRevision(p_FmPcd->h_Fm, &revInfo); if (revInfo.majorRev != 4) RETURN_ERROR(MAJOR, E_NOT_SUPPORTED, ("bypassPlcrProfileGeneration.")); } #endif /* FM_KG_NO_BYPASS_PLCR_PROFILE_GEN */ err = FmPcdCcGetGrpParams(p_Scheme->kgNextEngineParams.cc.h_CcTree, p_Scheme->kgNextEngineParams.cc.grpId, &grpBits, &grpBase); if(err) RETURN_ERROR(MAJOR, err, NO_MSG); p_FmPcd->p_FmPcdKg->schemes[relativeSchemeId].ccUnits = grpBits; if((p_Scheme->kgNextEngineParams.cc.plcrNext) && (!p_Scheme->kgNextEngineParams.cc.bypassPlcrProfileGeneration)) { if(p_Scheme->kgNextEngineParams.cc.plcrProfile.sharedProfile) RETURN_ERROR(MAJOR, E_INVALID_STATE, ("Shared profile may not be used after Coarse classification.")); absolute = FALSE; direct = p_Scheme->kgNextEngineParams.cc.plcrProfile.direct; if(direct) { profileId = p_Scheme->kgNextEngineParams.cc.plcrProfile.profileSelect.directRelativeProfileId; numOfProfiles = 1; } else { profileId = p_Scheme->kgNextEngineParams.cc.plcrProfile.profileSelect.indirectProfile.fqidOffsetRelativeProfileIdBase; shift = p_Scheme->kgNextEngineParams.cc.plcrProfile.profileSelect.indirectProfile.fqidOffsetShift; numOfProfiles = p_Scheme->kgNextEngineParams.cc.plcrProfile.profileSelect.indirectProfile.numOfProfiles; } } } /* if policer is used directly after KG, or after CC */ if((p_Scheme->nextEngine == e_FM_PCD_PLCR) || ((p_Scheme->nextEngine == e_FM_PCD_CC) && (p_Scheme->kgNextEngineParams.cc.plcrNext) && (!p_Scheme->kgNextEngineParams.cc.bypassPlcrProfileGeneration))) { /* if private policer profile, it may be uninitialized yet, therefore no checks are done at this stage */ if(absolute) { /* for absolute direct policy only, */ relativeProfileId = profileId; err = FmPcdPlcrGetAbsoluteProfileId(h_FmPcd,e_FM_PCD_PLCR_SHARED,NULL, relativeProfileId, &profileId); if(err) RETURN_ERROR(MAJOR, err, ("Shared profile not valid offset")); if(!FmPcdPlcrIsProfileValid(p_FmPcd, profileId)) RETURN_ERROR(MINOR, E_INVALID_STATE, ("Shared profile not valid.")); p_FmPcd->p_FmPcdKg->schemes[relativeSchemeId].relativeProfileId = profileId; } else { /* save relative profile id's for later check */ p_FmPcd->p_FmPcdKg->schemes[relativeSchemeId].nextRelativePlcrProfile = TRUE; p_FmPcd->p_FmPcdKg->schemes[relativeSchemeId].relativeProfileId = profileId; p_FmPcd->p_FmPcdKg->schemes[relativeSchemeId].numOfProfiles = numOfProfiles; } } else { /* if policer is NOT going to be used after KG at all than if bypassFqidGeneration is set, we do not need numOfUsedExtractedOrs and hashDistributionNumOfFqids */ if(p_Scheme->bypassFqidGeneration && p_Scheme->numOfUsedExtractedOrs) RETURN_ERROR(MAJOR, E_INVALID_STATE, ("numOfUsedExtractedOrs is set in a scheme that does not generate FQID or policer profile ID")); if(p_Scheme->bypassFqidGeneration && p_Scheme->useHash && p_Scheme->keyExtractAndHashParams.hashDistributionNumOfFqids) RETURN_ERROR(MAJOR, E_INVALID_STATE, ("hashDistributionNumOfFqids is set in a scheme that does not generate FQID or policer profile ID")); } /* configure all 21 scheme registers */ tmpReg = KG_SCH_MODE_EN; switch(p_Scheme->nextEngine) { case(e_FM_PCD_PLCR): /* add to mode register - NIA */ tmpReg |= KG_SCH_MODE_NIA_PLCR; tmpReg |= NIA_ENG_PLCR; tmpReg |= (uint32_t)(p_Scheme->kgNextEngineParams.plcrProfile.sharedProfile ? NIA_PLCR_ABSOLUTE:0); /* initialize policer profile command - */ /* configure kgse_ppc */ if(direct) /* use profileId as base, other fields are 0 */ p_SchemeRegs->kgse_ppc = (uint32_t)profileId; else { if(shift > MAX_PP_SHIFT) RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("fqidOffsetShift may not be larger than %d", MAX_PP_SHIFT)); if(!numOfProfiles || !POWER_OF_2(numOfProfiles)) RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("numOfProfiles must not be 0 and must be a power of 2")); ppcTmp = ((uint32_t)shift << KG_SCH_PP_SHIFT_HIGH_SHIFT) & KG_SCH_PP_SHIFT_HIGH; ppcTmp |= ((uint32_t)shift << KG_SCH_PP_SHIFT_LOW_SHIFT) & KG_SCH_PP_SHIFT_LOW; ppcTmp |= ((uint32_t)(numOfProfiles-1) << KG_SCH_PP_MASK_SHIFT); ppcTmp |= (uint32_t)profileId; p_SchemeRegs->kgse_ppc = ppcTmp; } break; case(e_FM_PCD_CC): /* mode reg - define NIA */ tmpReg |= (NIA_ENG_FM_CTL | NIA_FM_CTL_AC_CC); p_SchemeRegs->kgse_ccbs = grpBits; tmpReg |= (uint32_t)(grpBase << KG_SCH_MODE_CCOBASE_SHIFT); if(p_Scheme->kgNextEngineParams.cc.plcrNext) { if(!p_Scheme->kgNextEngineParams.cc.bypassPlcrProfileGeneration) { /* find out if absolute or relative */ if(absolute) RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("It is illegal to request a shared profile in a scheme that is in a KG->CC->PLCR flow")); if(direct) { /* mask = 0, base = directProfileId */ p_SchemeRegs->kgse_ppc = (uint32_t)profileId; } else { if(shift > MAX_PP_SHIFT) RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("fqidOffsetShift may not be larger than %d", MAX_PP_SHIFT)); if(!numOfProfiles || !POWER_OF_2(numOfProfiles)) RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("numOfProfiles must not be 0 and must be a power of 2")); ppcTmp = ((uint32_t)shift << KG_SCH_PP_SHIFT_HIGH_SHIFT) & KG_SCH_PP_SHIFT_HIGH; ppcTmp |= ((uint32_t)shift << KG_SCH_PP_SHIFT_LOW_SHIFT) & KG_SCH_PP_SHIFT_LOW; ppcTmp |= ((uint32_t)(numOfProfiles-1) << KG_SCH_PP_MASK_SHIFT); ppcTmp |= (uint32_t)profileId; p_SchemeRegs->kgse_ppc = ppcTmp; } } else ppcTmp = KG_SCH_PP_NO_GEN; } break; case(e_FM_PCD_DONE): if(p_Scheme->kgNextEngineParams.doneAction == e_FM_PCD_DROP_FRAME) tmpReg |= (NIA_ENG_BMI | NIA_BMI_AC_DISCARD); else tmpReg |= (NIA_ENG_BMI | NIA_BMI_AC_ENQ_FRAME); break; default: RETURN_ERROR(MAJOR, E_NOT_SUPPORTED, ("Next engine not supported")); } p_SchemeRegs->kgse_mode = tmpReg; p_SchemeRegs->kgse_mv = p_FmPcd->p_FmPcdKg->schemes[relativeSchemeId].matchVector; if(p_Scheme->useHash) { p_KeyAndHash = &p_Scheme->keyExtractAndHashParams; if (p_KeyAndHash->numOfUsedExtracts >= FM_PCD_KG_MAX_NUM_OF_EXTRACTS_PER_KEY) RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("numOfUsedExtracts out of range")); /* configure kgse_dv0 */ p_SchemeRegs->kgse_dv0 = p_KeyAndHash->privateDflt0; /* configure kgse_dv1 */ p_SchemeRegs->kgse_dv1 = p_KeyAndHash->privateDflt1; if(!p_Scheme->bypassFqidGeneration) { if(!p_KeyAndHash->hashDistributionNumOfFqids || !POWER_OF_2(p_KeyAndHash->hashDistributionNumOfFqids)) RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("hashDistributionNumOfFqids must not be 0 and must be a power of 2")); if((p_KeyAndHash->hashDistributionNumOfFqids-1) & p_Scheme->baseFqid) DBG(WARNING, ("baseFqid unaligned. Distribution may result in less than hashDistributionNumOfFqids queues.")); } /* configure kgse_ekdv */ tmpReg = 0; for( i=0 ;inumOfUsedDflts ; i++) { switch(p_KeyAndHash->dflts[i].type) { case(e_FM_PCD_KG_MAC_ADDR): tmpReg |= (p_KeyAndHash->dflts[i].dfltSelect << KG_SCH_DEF_MAC_ADDR_SHIFT); break; case(e_FM_PCD_KG_TCI): tmpReg |= (p_KeyAndHash->dflts[i].dfltSelect << KG_SCH_DEF_TCI_SHIFT); break; case(e_FM_PCD_KG_ENET_TYPE): tmpReg |= (p_KeyAndHash->dflts[i].dfltSelect << KG_SCH_DEF_ENET_TYPE_SHIFT); break; case(e_FM_PCD_KG_PPP_SESSION_ID): tmpReg |= (p_KeyAndHash->dflts[i].dfltSelect << KG_SCH_DEF_PPP_SESSION_ID_SHIFT); break; case(e_FM_PCD_KG_PPP_PROTOCOL_ID): tmpReg |= (p_KeyAndHash->dflts[i].dfltSelect << KG_SCH_DEF_PPP_PROTOCOL_ID_SHIFT); break; case(e_FM_PCD_KG_MPLS_LABEL): tmpReg |= (p_KeyAndHash->dflts[i].dfltSelect << KG_SCH_DEF_MPLS_LABEL_SHIFT); break; case(e_FM_PCD_KG_IP_ADDR): tmpReg |= (p_KeyAndHash->dflts[i].dfltSelect << KG_SCH_DEF_IP_ADDR_SHIFT); break; case(e_FM_PCD_KG_PROTOCOL_TYPE): tmpReg |= (p_KeyAndHash->dflts[i].dfltSelect << KG_SCH_DEF_PROTOCOL_TYPE_SHIFT); break; case(e_FM_PCD_KG_IP_TOS_TC): tmpReg |= (p_KeyAndHash->dflts[i].dfltSelect << KG_SCH_DEF_IP_TOS_TC_SHIFT); break; case(e_FM_PCD_KG_IPV6_FLOW_LABEL): tmpReg |= (p_KeyAndHash->dflts[i].dfltSelect << KG_SCH_DEF_L4_PORT_SHIFT); break; case(e_FM_PCD_KG_IPSEC_SPI): tmpReg |= (p_KeyAndHash->dflts[i].dfltSelect << KG_SCH_DEF_IPSEC_SPI_SHIFT); break; case(e_FM_PCD_KG_L4_PORT): tmpReg |= (p_KeyAndHash->dflts[i].dfltSelect << KG_SCH_DEF_L4_PORT_SHIFT); break; case(e_FM_PCD_KG_TCP_FLAG): tmpReg |= (p_KeyAndHash->dflts[i].dfltSelect << KG_SCH_DEF_TCP_FLAG_SHIFT); break; case(e_FM_PCD_KG_GENERIC_FROM_DATA): swDefaults[numOfSwDefaults].type = e_FM_PCD_KG_GENERIC_FROM_DATA; swDefaults[numOfSwDefaults].dfltSelect = p_KeyAndHash->dflts[i].dfltSelect; numOfSwDefaults ++; break; case(e_FM_PCD_KG_GENERIC_FROM_DATA_NO_V): swDefaults[numOfSwDefaults].type = e_FM_PCD_KG_GENERIC_FROM_DATA_NO_V; swDefaults[numOfSwDefaults].dfltSelect = p_KeyAndHash->dflts[i].dfltSelect; numOfSwDefaults ++; break; case(e_FM_PCD_KG_GENERIC_NOT_FROM_DATA): swDefaults[numOfSwDefaults].type = e_FM_PCD_KG_GENERIC_NOT_FROM_DATA; swDefaults[numOfSwDefaults].dfltSelect = p_KeyAndHash->dflts[i].dfltSelect; numOfSwDefaults ++; break; default: RETURN_ERROR(MAJOR, E_INVALID_SELECTION, NO_MSG); } } p_SchemeRegs->kgse_ekdv = tmpReg; p_LocalExtractsArray = (t_FmPcdKgSchemesExtracts *)XX_Malloc(sizeof(t_FmPcdKgSchemesExtracts)); if(!p_LocalExtractsArray) RETURN_ERROR(MAJOR, E_NO_MEMORY, ("No memory")); /* configure kgse_ekfc and kgse_gec */ knownTmp = 0; for( i=0 ;inumOfUsedExtracts ; i++) { p_Extract = &p_KeyAndHash->extractArray[i]; switch(p_Extract->type) { case(e_FM_PCD_KG_EXTRACT_PORT_PRIVATE_INFO): knownTmp |= KG_SCH_KN_PORT_ID; /* save in driver structure */ p_LocalExtractsArray->extractsArray[i].id = GetKnownFieldId(KG_SCH_KN_PORT_ID); p_LocalExtractsArray->extractsArray[i].known = TRUE; break; case(e_FM_PCD_EXTRACT_BY_HDR): switch(p_Extract->extractByHdr.hdr) { case(HEADER_TYPE_UDP_ENCAP_ESP): switch(p_Extract->extractByHdr.type) { case(e_FM_PCD_EXTRACT_FROM_HDR): /* case where extraction from ESP only */ if (p_Extract->extractByHdr.extractByHdrType.fromHdr.offset >= UDP_HEADER_SIZE) { p_Extract->extractByHdr.hdr = FmPcdGetAliasHdr(p_FmPcd, p_FmPcd->p_FmPcdKg->schemes[relativeSchemeId].netEnvId, HEADER_TYPE_UDP_ENCAP_ESP); p_Extract->extractByHdr.extractByHdrType.fromHdr.offset -= UDP_HEADER_SIZE; p_Extract->extractByHdr.ignoreProtocolValidation = TRUE; } else { p_Extract->extractByHdr.hdr = HEADER_TYPE_UDP; p_Extract->extractByHdr.ignoreProtocolValidation = FALSE; } break; case(e_FM_PCD_EXTRACT_FROM_FIELD): switch(p_Extract->extractByHdr.extractByHdrType.fromField.field.udpEncapEsp) { case(NET_HEADER_FIELD_UDP_ENCAP_ESP_PORT_SRC): case(NET_HEADER_FIELD_UDP_ENCAP_ESP_PORT_DST): case(NET_HEADER_FIELD_UDP_ENCAP_ESP_LEN): case(NET_HEADER_FIELD_UDP_ENCAP_ESP_CKSUM): p_Extract->extractByHdr.hdr = HEADER_TYPE_UDP; break; case(NET_HEADER_FIELD_UDP_ENCAP_ESP_SPI): p_Extract->extractByHdr.type = e_FM_PCD_EXTRACT_FROM_HDR; p_Extract->extractByHdr.hdr = FmPcdGetAliasHdr(p_FmPcd, p_FmPcd->p_FmPcdKg->schemes[relativeSchemeId].netEnvId, HEADER_TYPE_UDP_ENCAP_ESP); p_Extract->extractByHdr.extractByHdrType.fromField.size = p_Extract->extractByHdr.extractByHdrType.fromField.size; /*p_Extract->extractByHdr.extractByHdrType.fromField.offset += ESP_SPI_OFFSET;*/ p_Extract->extractByHdr.ignoreProtocolValidation = TRUE; break; case(NET_HEADER_FIELD_UDP_ENCAP_ESP_SEQUENCE_NUM): p_Extract->extractByHdr.type = e_FM_PCD_EXTRACT_FROM_HDR; p_Extract->extractByHdr.hdr = FmPcdGetAliasHdr(p_FmPcd, p_FmPcd->p_FmPcdKg->schemes[relativeSchemeId].netEnvId, HEADER_TYPE_UDP_ENCAP_ESP); p_Extract->extractByHdr.extractByHdrType.fromField.size = p_Extract->extractByHdr.extractByHdrType.fromField.size; p_Extract->extractByHdr.extractByHdrType.fromField.offset += ESP_SEQ_NUM_OFFSET; p_Extract->extractByHdr.ignoreProtocolValidation = TRUE; break; } break; case(e_FM_PCD_EXTRACT_FULL_FIELD): switch(p_Extract->extractByHdr.extractByHdrType.fullField.udpEncapEsp) { case(NET_HEADER_FIELD_UDP_ENCAP_ESP_PORT_SRC): case(NET_HEADER_FIELD_UDP_ENCAP_ESP_PORT_DST): case(NET_HEADER_FIELD_UDP_ENCAP_ESP_LEN): case(NET_HEADER_FIELD_UDP_ENCAP_ESP_CKSUM): p_Extract->extractByHdr.hdr = HEADER_TYPE_UDP; break; case(NET_HEADER_FIELD_UDP_ENCAP_ESP_SPI): p_Extract->extractByHdr.type = e_FM_PCD_EXTRACT_FROM_HDR; p_Extract->extractByHdr.hdr = FmPcdGetAliasHdr(p_FmPcd, p_FmPcd->p_FmPcdKg->schemes[relativeSchemeId].netEnvId, HEADER_TYPE_UDP_ENCAP_ESP); p_Extract->extractByHdr.extractByHdrType.fromHdr.size = ESP_SPI_SIZE; p_Extract->extractByHdr.extractByHdrType.fromHdr.offset = ESP_SPI_OFFSET; p_Extract->extractByHdr.ignoreProtocolValidation = TRUE; break; case(NET_HEADER_FIELD_UDP_ENCAP_ESP_SEQUENCE_NUM): p_Extract->extractByHdr.type = e_FM_PCD_EXTRACT_FROM_HDR; p_Extract->extractByHdr.hdr = FmPcdGetAliasHdr(p_FmPcd, p_FmPcd->p_FmPcdKg->schemes[relativeSchemeId].netEnvId, HEADER_TYPE_UDP_ENCAP_ESP); p_Extract->extractByHdr.extractByHdrType.fromHdr.size = ESP_SEQ_NUM_SIZE; p_Extract->extractByHdr.extractByHdrType.fromHdr.offset = ESP_SEQ_NUM_OFFSET; p_Extract->extractByHdr.ignoreProtocolValidation = TRUE; break; } break; } break; default: break; } switch(p_Extract->extractByHdr.type) { case(e_FM_PCD_EXTRACT_FROM_HDR): generic = TRUE; /* get the header code for the generic extract */ code = GetGenHdrCode(p_Extract->extractByHdr.hdr, p_Extract->extractByHdr.hdrIndex, p_Extract->extractByHdr.ignoreProtocolValidation); /* set generic register fields */ offset = p_Extract->extractByHdr.extractByHdrType.fromHdr.offset; size = p_Extract->extractByHdr.extractByHdrType.fromHdr.size; break; case(e_FM_PCD_EXTRACT_FROM_FIELD): generic = TRUE; /* get the field code for the generic extract */ code = GetGenFieldCode(p_Extract->extractByHdr.hdr, p_Extract->extractByHdr.extractByHdrType.fromField.field, p_Extract->extractByHdr.ignoreProtocolValidation,p_Extract->extractByHdr.hdrIndex); offset = p_Extract->extractByHdr.extractByHdrType.fromField.offset; size = p_Extract->extractByHdr.extractByHdrType.fromField.size; break; case(e_FM_PCD_EXTRACT_FULL_FIELD): if(!p_Extract->extractByHdr.ignoreProtocolValidation) { /* if we have a known field for it - use it, otherwise use generic */ bitMask = GetKnownProtMask(p_Extract->extractByHdr.hdr, p_Extract->extractByHdr.hdrIndex, p_Extract->extractByHdr.extractByHdrType.fullField); if(bitMask) { knownTmp |= bitMask; /* save in driver structure */ p_LocalExtractsArray->extractsArray[i].id = GetKnownFieldId(bitMask); p_LocalExtractsArray->extractsArray[i].known = TRUE; } else generic = TRUE; } else generic = TRUE; if(generic) { /* tmp - till we cover more headers under generic */ RETURN_ERROR(MAJOR, E_NOT_SUPPORTED, ("Full header selection not supported")); } break; default: RETURN_ERROR(MAJOR, E_INVALID_SELECTION, NO_MSG); } break; case(e_FM_PCD_EXTRACT_NON_HDR): /* use generic */ generic = TRUE; offset = 0; /* get the field code for the generic extract */ code = GetGenCode(p_Extract->extractNonHdr.src, &offset); offset += p_Extract->extractNonHdr.offset; size = p_Extract->extractNonHdr.size; break; default: RETURN_ERROR(MAJOR, E_INVALID_SELECTION, NO_MSG); } if(generic) { /* set generic register fields */ if(currGenId >= FM_PCD_KG_NUM_OF_GENERIC_REGS) RETURN_ERROR(MAJOR, E_FULL, ("Generic registers are fully used")); if(!code) RETURN_ERROR(MAJOR, E_NOT_SUPPORTED, NO_MSG); genTmp = KG_SCH_GEN_VALID; genTmp |= (uint32_t)(code << KG_SCH_GEN_HT_SHIFT); genTmp |= offset; if((size > MAX_KG_SCH_SIZE) || (size < 1)) RETURN_ERROR(MAJOR, E_NOT_SUPPORTED, ("Illegal extraction (size out of range)")); genTmp |= (uint32_t)((size - 1) << KG_SCH_GEN_SIZE_SHIFT); swDefault = GetGenericSwDefault(swDefaults, numOfSwDefaults, code); if(swDefault == e_FM_PCD_KG_DFLT_ILLEGAL) DBG(WARNING, ("No sw default configured")); genTmp |= swDefault << KG_SCH_GEN_DEF_SHIFT; genTmp |= KG_SCH_GEN_MASK; p_SchemeRegs->kgse_gec[currGenId] = genTmp; /* save in driver structure */ p_LocalExtractsArray->extractsArray[i].id = currGenId++; p_LocalExtractsArray->extractsArray[i].known = FALSE; generic = FALSE; } } p_SchemeRegs->kgse_ekfc = knownTmp; selectTmp = 0; maskTmp = 0xFFFFFFFF; /* configure kgse_bmch, kgse_bmcl and kgse_fqb */ if(p_KeyAndHash->numOfUsedMasks >= FM_PCD_KG_NUM_OF_EXTRACT_MASKS) RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("Only %d masks supported", FM_PCD_KG_NUM_OF_EXTRACT_MASKS)); for( i=0 ;inumOfUsedMasks ; i++) { /* Get the relative id of the extract (for known 0-0x1f, for generic 0-7) */ id = p_LocalExtractsArray->extractsArray[p_KeyAndHash->masks[i].extractArrayIndex].id; /* Get the shift of the select field (depending on i) */ GET_MASK_SEL_SHIFT(shift,i); if (p_LocalExtractsArray->extractsArray[p_KeyAndHash->masks[i].extractArrayIndex].known) selectTmp |= id << shift; else selectTmp |= (id + MASK_FOR_GENERIC_BASE_ID) << shift; /* Get the shift of the offset field (depending on i) - may be in kgse_bmch or in kgse_fqb (depending on i) */ GET_MASK_OFFSET_SHIFT(shift,i); if (i<=1) selectTmp |= p_KeyAndHash->masks[i].offset << shift; else fqbTmp |= p_KeyAndHash->masks[i].offset << shift; /* Get the shift of the mask field (depending on i) */ GET_MASK_SHIFT(shift,i); /* pass all bits */ maskTmp |= KG_SCH_BITMASK_MASK << shift; /* clear bits that need masking */ maskTmp &= ~(0xFF << shift) ; /* set mask bits */ maskTmp |= (p_KeyAndHash->masks[i].mask << shift) ; } p_SchemeRegs->kgse_bmch = selectTmp; p_SchemeRegs->kgse_bmcl = maskTmp; /* kgse_fqb will be written t the end of the routine */ /* configure kgse_hc */ if(p_KeyAndHash->hashShift > MAX_HASH_SHIFT) RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("hashShift must not be larger than %d", MAX_HASH_SHIFT)); if(p_KeyAndHash->hashDistributionFqidsShift > MAX_DIST_FQID_SHIFT) RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("hashDistributionFqidsShift must not be larger than %d", MAX_DIST_FQID_SHIFT)); tmpReg = 0; tmpReg |= ((p_KeyAndHash->hashDistributionNumOfFqids - 1) << p_KeyAndHash->hashDistributionFqidsShift); tmpReg |= p_KeyAndHash->hashShift << KG_SCH_HASH_CONFIG_SHIFT_SHIFT; if(p_KeyAndHash->symmetricHash) { if((!!(p_SchemeRegs->kgse_ekfc & KG_SCH_KN_MACSRC) != !!(p_SchemeRegs->kgse_ekfc & KG_SCH_KN_MACDST)) || (!!(p_SchemeRegs->kgse_ekfc & KG_SCH_KN_IPSRC1) != !!(p_SchemeRegs->kgse_ekfc & KG_SCH_KN_IPDST1)) || (!!(p_SchemeRegs->kgse_ekfc & KG_SCH_KN_IPSRC2) != !!(p_SchemeRegs->kgse_ekfc & KG_SCH_KN_IPDST2)) || (!!(p_SchemeRegs->kgse_ekfc & KG_SCH_KN_L4PSRC) != !!(p_SchemeRegs->kgse_ekfc & KG_SCH_KN_L4PDST))) RETURN_ERROR(MAJOR, E_INVALID_STATE, ("symmetricHash set but src/dest extractions missing")); tmpReg |= KG_SCH_HASH_CONFIG_SYM; } p_SchemeRegs->kgse_hc = tmpReg; /* build the return array describing the order of the extractions */ /* the last currGenId places of the array are for generic extracts that are always last. We now sort for the calculation of the order of the known extractions we sort the known extracts between orderedArray[0] and orderedArray[p_KeyAndHash->numOfUsedExtracts - currGenId - 1]. for the calculation of the order of the generic extractions we use: num_of_generic - currGenId num_of_known - p_KeyAndHash->numOfUsedExtracts - currGenId first_generic_index = num_of_known */ curr = 0; for (i=0;inumOfUsedExtracts ; i++) { if(p_LocalExtractsArray->extractsArray[i].known) { ASSERT_COND(curr<(p_KeyAndHash->numOfUsedExtracts - currGenId)); j = curr; /* id is the extract id (port id = 0, mac src = 1 etc.). the value in the array is the original index in the user's extractions array */ /* we compare the id of the current extract with the id of the extract in the orderedArray[j-1] location */ while((j > 0) && (p_LocalExtractsArray->extractsArray[i].id < p_LocalExtractsArray->extractsArray[p_FmPcd->p_FmPcdKg->schemes[relativeSchemeId].orderedArray[j-1]].id)) { p_FmPcd->p_FmPcdKg->schemes[relativeSchemeId].orderedArray[j] = p_FmPcd->p_FmPcdKg->schemes[relativeSchemeId].orderedArray[j-1]; j--; } p_FmPcd->p_FmPcdKg->schemes[relativeSchemeId].orderedArray[j] = (uint8_t)i; curr++; } else { /* index is first_generic_index + generic index (id) */ idx = (uint8_t)(p_KeyAndHash->numOfUsedExtracts - currGenId + p_LocalExtractsArray->extractsArray[i].id); ASSERT_COND(idx < FM_PCD_KG_MAX_NUM_OF_EXTRACTS_PER_KEY); p_FmPcd->p_FmPcdKg->schemes[relativeSchemeId].orderedArray[idx]= (uint8_t)i; } } XX_Free(p_LocalExtractsArray); p_LocalExtractsArray = NULL; } else { /* clear all unused registers: */ p_SchemeRegs->kgse_ekfc = 0; p_SchemeRegs->kgse_ekdv = 0; p_SchemeRegs->kgse_bmch = 0; p_SchemeRegs->kgse_bmcl = 0; p_SchemeRegs->kgse_hc = 0; p_SchemeRegs->kgse_dv0 = 0; p_SchemeRegs->kgse_dv1 = 0; } if(p_Scheme->bypassFqidGeneration) p_SchemeRegs->kgse_hc |= KG_SCH_HASH_CONFIG_NO_FQID; /* configure kgse_spc */ if( p_Scheme->schemeCounter.update) p_SchemeRegs->kgse_spc = p_Scheme->schemeCounter.value; /* check that are enough generic registers */ if(p_Scheme->numOfUsedExtractedOrs + currGenId > FM_PCD_KG_NUM_OF_GENERIC_REGS) RETURN_ERROR(MAJOR, E_FULL, ("Generic registers are fully used")); /* extracted OR mask on Qid */ for( i=0 ;inumOfUsedExtractedOrs ; i++) { p_FmPcd->p_FmPcdKg->schemes[relativeSchemeId].extractedOrs = TRUE; /* configure kgse_gec[i] */ p_ExtractOr = &p_Scheme->extractedOrs[i]; switch(p_ExtractOr->type) { case(e_FM_PCD_KG_EXTRACT_PORT_PRIVATE_INFO): code = KG_SCH_GEN_PARSE_RESULT_N_FQID; offset = 0; break; case(e_FM_PCD_EXTRACT_BY_HDR): /* get the header code for the generic extract */ code = GetGenHdrCode(p_ExtractOr->extractByHdr.hdr, p_ExtractOr->extractByHdr.hdrIndex, p_ExtractOr->extractByHdr.ignoreProtocolValidation); /* set generic register fields */ offset = p_ExtractOr->extractionOffset; break; case(e_FM_PCD_EXTRACT_NON_HDR): /* get the field code for the generic extract */ offset = 0; code = GetGenCode(p_ExtractOr->src, &offset); offset += p_ExtractOr->extractionOffset; break; default: RETURN_ERROR(MAJOR, E_INVALID_SELECTION, NO_MSG); } /* set generic register fields */ if(!code) RETURN_ERROR(MAJOR, E_NOT_SUPPORTED, NO_MSG); genTmp = KG_SCH_GEN_EXTRACT_TYPE | KG_SCH_GEN_VALID; genTmp |= (uint32_t)(code << KG_SCH_GEN_HT_SHIFT); genTmp |= offset; if(!!p_ExtractOr->bitOffsetInFqid == !!p_ExtractOr->bitOffsetInPlcrProfile) RETURN_ERROR(MAJOR, E_INVALID_VALUE, (" extracted byte must effect either FQID or Policer profile")); /************************************************************************************ bitOffsetInFqid and bitOffsetInPolicerProfile are translated to rotate parameter in the following way: Driver API and implementation: ============================== FQID: extracted OR byte may be shifted right 1-31 bits to effect parts of the FQID. if shifted less than 8 bits, or more than 24 bits a mask is set on the bits that are not overlapping FQID. ------------------------ | FQID (24) | ------------------------ -------- | | extracted OR byte -------- Policer Profile: extracted OR byte may be shifted right 1-15 bits to effect parts of the PP id. Unless shifted exactly 8 bits to overlap the PP id, a mask is set on the bits that are not overlapping PP id. -------- | PP (8) | -------- -------- | | extracted OR byte -------- HW implementation ================= FQID and PP construct a 32 bit word in the way describe below. Extracted byte is located as the highest byte of that word and may be rotated to effect any part os the FQID or the PP. ------------------------ -------- | FQID (24) || PP (8) | ------------------------ -------- -------- | | extracted OR byte -------- ************************************************************************************/ if(p_ExtractOr->bitOffsetInFqid) { if(p_ExtractOr->bitOffsetInFqid > MAX_KG_SCH_FQID_BIT_OFFSET ) RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("Illegal extraction (bitOffsetInFqid out of range)")); if(p_ExtractOr->bitOffsetInFqid<8) genTmp |= (uint32_t)((p_ExtractOr->bitOffsetInFqid+24) << KG_SCH_GEN_SIZE_SHIFT); else genTmp |= (uint32_t)((p_ExtractOr->bitOffsetInFqid-8) << KG_SCH_GEN_SIZE_SHIFT); p_ExtractOr->mask &= GetExtractedOrMask(p_ExtractOr->bitOffsetInFqid, TRUE); } else /* effect policer profile */ { if(p_ExtractOr->bitOffsetInPlcrProfile > MAX_KG_SCH_PP_BIT_OFFSET ) RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("Illegal extraction (bitOffsetInPlcrProfile out of range)")); p_FmPcd->p_FmPcdKg->schemes[relativeSchemeId].bitOffsetInPlcrProfile = p_ExtractOr->bitOffsetInPlcrProfile; genTmp |= (uint32_t)((p_ExtractOr->bitOffsetInPlcrProfile+16) << KG_SCH_GEN_SIZE_SHIFT); p_ExtractOr->mask &= GetExtractedOrMask(p_ExtractOr->bitOffsetInPlcrProfile, FALSE); } genTmp |= (uint32_t)(p_ExtractOr->extractionOffset << KG_SCH_GEN_DEF_SHIFT); /* clear bits that need masking */ genTmp &= ~KG_SCH_GEN_MASK ; /* set mask bits */ genTmp |= (uint32_t)(p_ExtractOr->mask << KG_SCH_GEN_MASK_SHIFT); p_SchemeRegs->kgse_gec[currGenId++] = genTmp; } /* clear all unused GEC registers */ for( i=currGenId ;ikgse_gec[i] = 0; /* add base Qid for this scheme */ /* add configuration for kgse_fqb */ if(p_Scheme->baseFqid & ~0x00FFFFFF) RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("baseFqid must be between 1 and 2^24-1")); fqbTmp |= p_Scheme->baseFqid; p_SchemeRegs->kgse_fqb = fqbTmp; p_FmPcd->p_FmPcdKg->schemes[relativeSchemeId].nextEngine = p_Scheme->nextEngine; p_FmPcd->p_FmPcdKg->schemes[relativeSchemeId].doneAction = p_Scheme->kgNextEngineParams.doneAction; return E_OK; } void FmPcdKgValidateSchemeSw(t_Handle h_FmPcd, uint8_t schemeId) { t_FmPcd *p_FmPcd = (t_FmPcd*)h_FmPcd; ASSERT_COND(!p_FmPcd->p_FmPcdKg->schemes[schemeId].valid); if(p_FmPcd->p_FmPcdKg->schemes[schemeId].netEnvId != ILLEGAL_NETENV) FmPcdIncNetEnvOwners(p_FmPcd, p_FmPcd->p_FmPcdKg->schemes[schemeId].netEnvId); p_FmPcd->p_FmPcdKg->schemes[schemeId].valid = TRUE; } void FmPcdKgInvalidateSchemeSw(t_Handle h_FmPcd, uint8_t schemeId) { t_FmPcd *p_FmPcd = (t_FmPcd*)h_FmPcd; if(p_FmPcd->p_FmPcdKg->schemes[schemeId].netEnvId != ILLEGAL_NETENV) FmPcdDecNetEnvOwners(h_FmPcd, p_FmPcd->p_FmPcdKg->schemes[schemeId].netEnvId); p_FmPcd->p_FmPcdKg->schemes[schemeId].valid = FALSE; } uint32_t FmPcdKgGetRequiredAction(t_Handle h_FmPcd, uint8_t schemeId) { t_FmPcd *p_FmPcd = (t_FmPcd*)h_FmPcd; ASSERT_COND(p_FmPcd->p_FmPcdKg->schemes[schemeId].valid); return p_FmPcd->p_FmPcdKg->schemes[schemeId].requiredAction; } uint32_t FmPcdKgGetPointedOwners(t_Handle h_FmPcd, uint8_t schemeId) { t_FmPcd *p_FmPcd = (t_FmPcd*)h_FmPcd; ASSERT_COND(p_FmPcd->p_FmPcdKg->schemes[schemeId].valid); return p_FmPcd->p_FmPcdKg->schemes[schemeId].pointedOwners; } bool FmPcdKgIsDirectPlcr(t_Handle h_FmPcd, uint8_t schemeId) { t_FmPcd *p_FmPcd = (t_FmPcd*)h_FmPcd; ASSERT_COND(p_FmPcd->p_FmPcdKg->schemes[schemeId].valid); return p_FmPcd->p_FmPcdKg->schemes[schemeId].directPlcr; } uint16_t FmPcdKgGetRelativeProfileId(t_Handle h_FmPcd, uint8_t schemeId) { t_FmPcd *p_FmPcd = (t_FmPcd*)h_FmPcd; ASSERT_COND(p_FmPcd->p_FmPcdKg->schemes[schemeId].valid); return p_FmPcd->p_FmPcdKg->schemes[schemeId].relativeProfileId; } bool FmPcdKgIsDistrOnPlcrProfile(t_Handle h_FmPcd, uint8_t schemeId) { t_FmPcd *p_FmPcd = (t_FmPcd*)h_FmPcd; ASSERT_COND(p_FmPcd->p_FmPcdKg->schemes[schemeId].valid); if((p_FmPcd->p_FmPcdKg->schemes[schemeId].extractedOrs && p_FmPcd->p_FmPcdKg->schemes[schemeId].bitOffsetInPlcrProfile) || p_FmPcd->p_FmPcdKg->schemes[schemeId].nextRelativePlcrProfile) return TRUE; else return FALSE; } void FmPcdKgUpatePointedOwner(t_Handle h_FmPcd, uint8_t schemeId, bool add) { t_FmPcd *p_FmPcd = (t_FmPcd*)h_FmPcd; ASSERT_COND(p_FmPcd->p_FmPcdKg->schemes[schemeId].valid); if(add) p_FmPcd->p_FmPcdKg->schemes[schemeId].pointedOwners++; else p_FmPcd->p_FmPcdKg->schemes[schemeId].pointedOwners--; } e_FmPcdEngine FmPcdKgGetNextEngine(t_Handle h_FmPcd, uint8_t schemeId) { t_FmPcd *p_FmPcd = (t_FmPcd*)h_FmPcd; ASSERT_COND(p_FmPcd->p_FmPcdKg->schemes[schemeId].valid); return p_FmPcd->p_FmPcdKg->schemes[schemeId].nextEngine; } e_FmPcdDoneAction FmPcdKgGetDoneAction(t_Handle h_FmPcd, uint8_t schemeId) { t_FmPcd *p_FmPcd = (t_FmPcd*)h_FmPcd; ASSERT_COND(p_FmPcd->p_FmPcdKg->schemes[schemeId].valid); return p_FmPcd->p_FmPcdKg->schemes[schemeId].doneAction; } void FmPcdKgUpdateRequiredAction(t_Handle h_FmPcd, uint8_t schemeId, uint32_t requiredAction) { t_FmPcd *p_FmPcd = (t_FmPcd*)h_FmPcd; ASSERT_COND(p_FmPcd->p_FmPcdKg->schemes[schemeId].valid); p_FmPcd->p_FmPcdKg->schemes[schemeId].requiredAction = requiredAction; } t_Error FmPcdKgCheckInvalidateSchemeSw(t_Handle h_FmPcd, uint8_t schemeId) { t_FmPcd *p_FmPcd = (t_FmPcd*)h_FmPcd; if(schemeId >= FM_PCD_KG_NUM_OF_SCHEMES) REPORT_ERROR(MAJOR, E_NOT_IN_RANGE, NO_MSG); /* check that no port is bound to this scheme */ if(p_FmPcd->p_FmPcdKg->schemes[schemeId].owners) RETURN_ERROR(MINOR, E_INVALID_STATE, ("Trying to delete a scheme that has ports bound to")); if(!p_FmPcd->p_FmPcdKg->schemes[schemeId].valid) RETURN_ERROR(MINOR, E_INVALID_STATE, ("Trying to delete an invalid scheme")); return E_OK; } uint32_t FmPcdKgBuildCppReg(t_Handle h_FmPcd, uint8_t clsPlanGrpId) { t_FmPcd *p_FmPcd = (t_FmPcd*)h_FmPcd; uint32_t tmpKgpeCpp; tmpKgpeCpp = (uint32_t)(p_FmPcd->p_FmPcdKg->clsPlanGrps[clsPlanGrpId].baseEntry / 8); tmpKgpeCpp |= (uint32_t)(((p_FmPcd->p_FmPcdKg->clsPlanGrps[clsPlanGrpId].sizeOfGrp / 8) - 1) << FM_PCD_KG_PE_CPP_MASK_SHIFT); return tmpKgpeCpp; } bool FmPcdKgHwSchemeIsValid(uint32_t schemeModeReg) { if(schemeModeReg & KG_SCH_MODE_EN) return TRUE; else return FALSE; } uint32_t FmPcdKgBuildWriteSchemeActionReg(uint8_t schemeId, bool updateCounter) { return (uint32_t)(((uint32_t)schemeId << FM_PCD_KG_KGAR_NUM_SHIFT)| FM_PCD_KG_KGAR_GO | FM_PCD_KG_KGAR_WRITE | FM_PCD_KG_KGAR_SEL_SCHEME_ENTRY | DUMMY_PORT_ID | (updateCounter ? FM_PCD_KG_KGAR_SCHEME_WSEL_UPDATE_CNT:0)); } uint32_t FmPcdKgBuildReadSchemeActionReg(uint8_t schemeId) { return (uint32_t)(((uint32_t)schemeId << FM_PCD_KG_KGAR_NUM_SHIFT)| FM_PCD_KG_KGAR_GO | FM_PCD_KG_KGAR_READ | FM_PCD_KG_KGAR_SEL_SCHEME_ENTRY | DUMMY_PORT_ID | FM_PCD_KG_KGAR_SCHEME_WSEL_UPDATE_CNT); } uint32_t FmPcdKgBuildWriteClsPlanBlockActionReg(uint8_t grpId) { return (uint32_t)(FM_PCD_KG_KGAR_GO | FM_PCD_KG_KGAR_WRITE | FM_PCD_KG_KGAR_SEL_CLS_PLAN_ENTRY | DUMMY_PORT_ID | ((uint32_t)grpId << FM_PCD_KG_KGAR_NUM_SHIFT) | FM_PCD_KG_KGAR_WSEL_MASK); /* if we ever want to write 1 by 1, use: sel = (uint8_t)(0x01 << (7- (entryId % CLS_PLAN_NUM_PER_GRP)));*/ } uint32_t FmPcdKgBuildReadClsPlanBlockActionReg(uint8_t grpId) { return (uint32_t)(FM_PCD_KG_KGAR_GO | FM_PCD_KG_KGAR_READ | FM_PCD_KG_KGAR_SEL_CLS_PLAN_ENTRY | DUMMY_PORT_ID | ((uint32_t)grpId << FM_PCD_KG_KGAR_NUM_SHIFT) | FM_PCD_KG_KGAR_WSEL_MASK); /* if we ever want to write 1 by 1, use: sel = (uint8_t)(0x01 << (7- (entryId % CLS_PLAN_NUM_PER_GRP)));*/ } uint32_t FmPcdKgBuildWritePortSchemeBindActionReg(uint8_t hardwarePortId) { return (uint32_t)(FM_PCD_KG_KGAR_GO | FM_PCD_KG_KGAR_WRITE | FM_PCD_KG_KGAR_SEL_PORT_ENTRY | hardwarePortId | FM_PCD_KG_KGAR_SEL_PORT_WSEL_SP); } uint32_t FmPcdKgBuildReadPortSchemeBindActionReg(uint8_t hardwarePortId) { return (uint32_t)(FM_PCD_KG_KGAR_GO | FM_PCD_KG_KGAR_READ | FM_PCD_KG_KGAR_SEL_PORT_ENTRY | hardwarePortId | FM_PCD_KG_KGAR_SEL_PORT_WSEL_SP); } uint32_t FmPcdKgBuildWritePortClsPlanBindActionReg(uint8_t hardwarePortId) { return (uint32_t)(FM_PCD_KG_KGAR_GO | FM_PCD_KG_KGAR_WRITE | FM_PCD_KG_KGAR_SEL_PORT_ENTRY | hardwarePortId | FM_PCD_KG_KGAR_SEL_PORT_WSEL_CPP); } uint8_t FmPcdKgGetClsPlanGrpBase(t_Handle h_FmPcd, uint8_t clsPlanGrp) { t_FmPcd *p_FmPcd = (t_FmPcd*)h_FmPcd; return p_FmPcd->p_FmPcdKg->clsPlanGrps[clsPlanGrp].baseEntry; } uint16_t FmPcdKgGetClsPlanGrpSize(t_Handle h_FmPcd, uint8_t clsPlanGrp) { t_FmPcd *p_FmPcd = (t_FmPcd*)h_FmPcd; return p_FmPcd->p_FmPcdKg->clsPlanGrps[clsPlanGrp].sizeOfGrp; } uint8_t FmPcdKgGetSchemeSwId(t_Handle h_FmPcd, uint8_t schemeHwId) { t_FmPcd *p_FmPcd = (t_FmPcd*)h_FmPcd; uint8_t i; for(i=0;ip_FmPcdKg->numOfSchemes;i++) if(p_FmPcd->p_FmPcdKg->schemesIds[i] == schemeHwId) return i; ASSERT_COND(i!=p_FmPcd->p_FmPcdKg->numOfSchemes); return FM_PCD_KG_NUM_OF_SCHEMES; } uint8_t FmPcdKgGetNumOfPartitionSchemes(t_Handle h_FmPcd) { return ((t_FmPcd*)h_FmPcd)->p_FmPcdKg->numOfSchemes; } uint8_t FmPcdKgGetPhysicalSchemeId(t_Handle h_FmPcd, uint8_t relativeSchemeId) { return ((t_FmPcd*)h_FmPcd)->p_FmPcdKg->schemesIds[relativeSchemeId]; } uint8_t FmPcdKgGetRelativeSchemeId(t_Handle h_FmPcd, uint8_t schemeId) { t_FmPcd *p_FmPcd = (t_FmPcd*)h_FmPcd; uint8_t i; for(i = 0;ip_FmPcdKg->numOfSchemes;i++) if(p_FmPcd->p_FmPcdKg->schemesIds[i] == schemeId) return i; if(i == p_FmPcd->p_FmPcdKg->numOfSchemes) REPORT_ERROR(MAJOR, E_NOT_IN_RANGE, ("Scheme is out of partition range")); return FM_PCD_KG_NUM_OF_SCHEMES; } t_Error FmPcdKgCcGetSetParams(t_Handle h_FmPcd, t_Handle h_Scheme, uint32_t requiredAction) { t_FmPcd *p_FmPcd = (t_FmPcd*)h_FmPcd; uint8_t relativeSchemeId, physicalSchemeId; uint32_t tmpKgarReg, tmpReg32 = 0, intFlags; t_Error err; SANITY_CHECK_RETURN_VALUE(h_FmPcd, E_INVALID_HANDLE, 0); SANITY_CHECK_RETURN_VALUE(p_FmPcd->p_FmPcdKg, E_INVALID_HANDLE, 0); SANITY_CHECK_RETURN_VALUE(!p_FmPcd->p_FmPcdDriverParam, E_INVALID_STATE, 0); if (p_FmPcd->h_Hc) return FmHcPcdKgCcGetSetParams(p_FmPcd->h_Hc, h_Scheme, requiredAction); physicalSchemeId = (uint8_t)(PTR_TO_UINT(h_Scheme)-1); relativeSchemeId = FmPcdKgGetRelativeSchemeId(p_FmPcd, physicalSchemeId); if(relativeSchemeId >= FM_PCD_KG_NUM_OF_SCHEMES) RETURN_ERROR(MAJOR, E_NOT_IN_RANGE, NO_MSG); if (FmPcdKgSchemeTryLock(p_FmPcd, relativeSchemeId, FALSE)) RETURN_ERROR(MAJOR, E_INVALID_STATE, ("Lock of the scheme FAILED")); if(!p_FmPcd->p_FmPcdKg->schemes[relativeSchemeId].pointedOwners || !(p_FmPcd->p_FmPcdKg->schemes[relativeSchemeId].requiredAction & requiredAction)) { if(requiredAction & UPDATE_NIA_ENQ_WITHOUT_DMA) { switch(p_FmPcd->p_FmPcdKg->schemes[relativeSchemeId].nextEngine) { case(e_FM_PCD_DONE): if(p_FmPcd->p_FmPcdKg->schemes[relativeSchemeId].doneAction == e_FM_PCD_ENQ_FRAME) { tmpKgarReg = FmPcdKgBuildReadSchemeActionReg(physicalSchemeId); intFlags = FmPcdLock(p_FmPcd); WriteKgarWait(p_FmPcd, tmpKgarReg); if (!(GET_UINT32(p_FmPcd->p_FmPcdKg->p_FmPcdKgRegs->indirectAccessRegs.schemeRegs.kgse_mode) & KG_SCH_MODE_EN)) { RELEASE_LOCK(p_FmPcd->p_FmPcdKg->schemes[relativeSchemeId].lock); RETURN_ERROR(MAJOR, E_ALREADY_EXISTS, ("Scheme is Invalid")); } tmpReg32 = GET_UINT32(p_FmPcd->p_FmPcdKg->p_FmPcdKgRegs->indirectAccessRegs.schemeRegs.kgse_mode); ASSERT_COND(tmpReg32 & (NIA_ENG_BMI | NIA_BMI_AC_ENQ_FRAME)); WRITE_UINT32(p_FmPcd->p_FmPcdKg->p_FmPcdKgRegs->indirectAccessRegs.schemeRegs.kgse_mode, tmpReg32 | NIA_BMI_AC_ENQ_FRAME_WITHOUT_DMA); /* call indirect command for scheme write */ tmpKgarReg = FmPcdKgBuildWriteSchemeActionReg(physicalSchemeId, FALSE); WriteKgarWait(p_FmPcd, tmpKgarReg); FmPcdUnlock(p_FmPcd, intFlags); } break; case(e_FM_PCD_PLCR): if(!p_FmPcd->p_FmPcdKg->schemes[relativeSchemeId].directPlcr || (p_FmPcd->p_FmPcdKg->schemes[relativeSchemeId].extractedOrs && p_FmPcd->p_FmPcdKg->schemes[relativeSchemeId].bitOffsetInPlcrProfile) || p_FmPcd->p_FmPcdKg->schemes[relativeSchemeId].nextRelativePlcrProfile) { RELEASE_LOCK(p_FmPcd->p_FmPcdKg->schemes[relativeSchemeId].lock); RETURN_ERROR(MAJOR, E_NOT_SUPPORTED, ("In this situation PP can not be with distribution and has to be shared")); } err = FmPcdPlcrCcGetSetParams(h_FmPcd, p_FmPcd->p_FmPcdKg->schemes[relativeSchemeId].relativeProfileId, requiredAction); if(err) { RELEASE_LOCK(p_FmPcd->p_FmPcdKg->schemes[relativeSchemeId].lock); RETURN_ERROR(MAJOR, err, NO_MSG); } break; default: RETURN_ERROR(MAJOR, E_INVALID_VALUE,("in this situation the next engine after scheme can be or PLCR or ENQ_FRAME")); } } } p_FmPcd->p_FmPcdKg->schemes[relativeSchemeId].pointedOwners += 1; p_FmPcd->p_FmPcdKg->schemes[relativeSchemeId].requiredAction |= requiredAction; RELEASE_LOCK(p_FmPcd->p_FmPcdKg->schemes[relativeSchemeId].lock); return E_OK; } t_Error FmPcdKgSchemeTryLock(t_Handle h_FmPcd, uint8_t schemeId, bool intr) { t_FmPcd *p_FmPcd = (t_FmPcd*)h_FmPcd; bool ans; if (intr) ans = TRY_LOCK(NULL, &p_FmPcd->p_FmPcdKg->schemes[schemeId].lock); else ans = TRY_LOCK(p_FmPcd->h_Spinlock, &p_FmPcd->p_FmPcdKg->schemes[schemeId].lock); if (ans) return E_OK; return ERROR_CODE(E_BUSY); } void FmPcdKgReleaseSchemeLock(t_Handle h_FmPcd, uint8_t schemeId) { RELEASE_LOCK(((t_FmPcd*)h_FmPcd)->p_FmPcdKg->schemes[schemeId].lock); } t_Handle FM_PCD_KgSetScheme(t_Handle h_FmPcd, t_FmPcdKgSchemeParams *p_Scheme) { t_FmPcd *p_FmPcd = (t_FmPcd*)h_FmPcd; uint32_t tmpReg; t_FmPcdKgInterModuleSchemeRegs schemeRegs; t_FmPcdKgInterModuleSchemeRegs *p_MemRegs; uint8_t i; t_Error err = E_OK; uint32_t tmpKgarReg; uint32_t intFlags; uint8_t physicalSchemeId, relativeSchemeId; SANITY_CHECK_RETURN_VALUE(p_FmPcd, E_INVALID_HANDLE, NULL); SANITY_CHECK_RETURN_VALUE(p_FmPcd->p_FmPcdKg, E_INVALID_HANDLE, NULL); SANITY_CHECK_RETURN_VALUE(!p_FmPcd->p_FmPcdDriverParam, E_INVALID_STATE, NULL); if (p_FmPcd->h_Hc) return FmHcPcdKgSetScheme(p_FmPcd->h_Hc, p_Scheme); /* if not called for modification, check first that this scheme is unused */ if(!p_Scheme->modify) { /* check that schemeId is in range */ if(p_Scheme->id.relativeSchemeId >= p_FmPcd->p_FmPcdKg->numOfSchemes) { REPORT_ERROR(MAJOR, E_NOT_IN_RANGE, ("Scheme is out of range")); return NULL; } relativeSchemeId = p_Scheme->id.relativeSchemeId; if (FmPcdKgSchemeTryLock(p_FmPcd, relativeSchemeId, FALSE)) return NULL; physicalSchemeId = p_FmPcd->p_FmPcdKg->schemesIds[relativeSchemeId]; /* read specified scheme into scheme registers */ tmpKgarReg = FmPcdKgBuildReadSchemeActionReg(physicalSchemeId); intFlags = FmPcdLock(p_FmPcd); WriteKgarWait(p_FmPcd, tmpKgarReg); tmpReg = GET_UINT32(p_FmPcd->p_FmPcdKg->p_FmPcdKgRegs->indirectAccessRegs.schemeRegs.kgse_mode); FmPcdUnlock(p_FmPcd, intFlags); if (tmpReg & KG_SCH_MODE_EN) { REPORT_ERROR(MAJOR, E_ALREADY_EXISTS, ("Scheme %d(phys %d) is already used", relativeSchemeId, physicalSchemeId)); RELEASE_LOCK(p_FmPcd->p_FmPcdKg->schemes[relativeSchemeId].lock); return NULL; } } else { SANITY_CHECK_RETURN_VALUE(p_Scheme->id.h_Scheme, E_INVALID_HANDLE, NULL); intFlags = FmPcdLock(p_FmPcd); physicalSchemeId = (uint8_t)(PTR_TO_UINT(p_Scheme->id.h_Scheme)-1); relativeSchemeId = FmPcdKgGetRelativeSchemeId(p_FmPcd, physicalSchemeId); /* check that schemeId is in range */ if(relativeSchemeId >= FM_PCD_KG_NUM_OF_SCHEMES) { REPORT_ERROR(MAJOR, E_NOT_IN_RANGE, NO_MSG); FmPcdUnlock(p_FmPcd, intFlags); return NULL; } err = FmPcdKgSchemeTryLock(p_FmPcd, relativeSchemeId, TRUE); FmPcdUnlock(p_FmPcd, intFlags); if (err) return NULL; } err = FmPcdKgBuildScheme(h_FmPcd, p_Scheme, &schemeRegs); if(err) { REPORT_ERROR(MAJOR, err, NO_MSG); FmPcdKgInvalidateSchemeSw(h_FmPcd, relativeSchemeId); RELEASE_LOCK(p_FmPcd->p_FmPcdKg->schemes[relativeSchemeId].lock); return NULL; } /* configure all 21 scheme registers */ p_MemRegs = &p_FmPcd->p_FmPcdKg->p_FmPcdKgRegs->indirectAccessRegs.schemeRegs; intFlags = FmPcdLock(p_FmPcd); WRITE_UINT32(p_MemRegs->kgse_ppc, schemeRegs.kgse_ppc); WRITE_UINT32(p_MemRegs->kgse_ccbs, schemeRegs.kgse_ccbs); WRITE_UINT32(p_MemRegs->kgse_mode, schemeRegs.kgse_mode); WRITE_UINT32(p_MemRegs->kgse_mv, schemeRegs.kgse_mv); WRITE_UINT32(p_MemRegs->kgse_dv0, schemeRegs.kgse_dv0); WRITE_UINT32(p_MemRegs->kgse_dv1, schemeRegs.kgse_dv1); WRITE_UINT32(p_MemRegs->kgse_ekdv, schemeRegs.kgse_ekdv); WRITE_UINT32(p_MemRegs->kgse_ekfc, schemeRegs.kgse_ekfc); WRITE_UINT32(p_MemRegs->kgse_bmch, schemeRegs.kgse_bmch); WRITE_UINT32(p_MemRegs->kgse_bmcl, schemeRegs.kgse_bmcl); WRITE_UINT32(p_MemRegs->kgse_hc, schemeRegs.kgse_hc); WRITE_UINT32(p_MemRegs->kgse_spc, schemeRegs.kgse_spc); WRITE_UINT32(p_MemRegs->kgse_fqb, schemeRegs.kgse_fqb); for(i=0 ; ikgse_gec[i], schemeRegs.kgse_gec[i]); /* call indirect command for scheme write */ tmpKgarReg = FmPcdKgBuildWriteSchemeActionReg(physicalSchemeId, p_Scheme->schemeCounter.update); WriteKgarWait(p_FmPcd, tmpKgarReg); FmPcdUnlock(p_FmPcd, intFlags); FmPcdKgValidateSchemeSw(h_FmPcd, relativeSchemeId); RELEASE_LOCK(p_FmPcd->p_FmPcdKg->schemes[relativeSchemeId].lock); return UINT_TO_PTR((uint64_t)physicalSchemeId+1); } t_Error FM_PCD_KgDeleteScheme(t_Handle h_FmPcd, t_Handle h_Scheme) { t_FmPcd *p_FmPcd = (t_FmPcd*)h_FmPcd; uint8_t physicalSchemeId; uint32_t tmpKgarReg, intFlags; t_Error err = E_OK; uint8_t relativeSchemeId; SANITY_CHECK_RETURN_ERROR(p_FmPcd, E_INVALID_HANDLE); SANITY_CHECK_RETURN_ERROR(p_FmPcd->p_FmPcdKg, E_INVALID_HANDLE); SANITY_CHECK_RETURN_ERROR(!p_FmPcd->p_FmPcdDriverParam, E_INVALID_STATE); if (p_FmPcd->h_Hc) return FmHcPcdKgDeleteScheme(p_FmPcd->h_Hc, h_Scheme); physicalSchemeId = (uint8_t)(PTR_TO_UINT(h_Scheme)-1); relativeSchemeId = FmPcdKgGetRelativeSchemeId(p_FmPcd, physicalSchemeId); if(relativeSchemeId >= FM_PCD_KG_NUM_OF_SCHEMES) RETURN_ERROR(MAJOR, E_NOT_IN_RANGE, NO_MSG); if ((err = FmPcdKgSchemeTryLock(p_FmPcd, relativeSchemeId, FALSE)) != E_OK) RETURN_ERROR(MINOR, err, NO_MSG); /* check that no port is bound to this scheme */ err = FmPcdKgCheckInvalidateSchemeSw(h_FmPcd, relativeSchemeId); if(err) RETURN_ERROR(MINOR, err, NO_MSG); intFlags = FmPcdLock(p_FmPcd); /* clear mode register, including enable bit */ WRITE_UINT32(p_FmPcd->p_FmPcdKg->p_FmPcdKgRegs->indirectAccessRegs.schemeRegs.kgse_mode, 0); /* call indirect command for scheme write */ tmpKgarReg = FmPcdKgBuildWriteSchemeActionReg(physicalSchemeId, FALSE); WriteKgarWait(p_FmPcd, tmpKgarReg); FmPcdUnlock(p_FmPcd, intFlags); FmPcdKgInvalidateSchemeSw(h_FmPcd, relativeSchemeId); RELEASE_LOCK(p_FmPcd->p_FmPcdKg->schemes[relativeSchemeId].lock); return E_OK; } uint32_t FM_PCD_KgGetSchemeCounter(t_Handle h_FmPcd, t_Handle h_Scheme) { t_FmPcd *p_FmPcd = (t_FmPcd*)h_FmPcd; uint32_t tmpKgarReg, spc, intFlags; uint8_t physicalSchemeId; SANITY_CHECK_RETURN_VALUE(h_FmPcd, E_INVALID_HANDLE, 0); SANITY_CHECK_RETURN_VALUE(p_FmPcd->p_FmPcdKg, E_INVALID_HANDLE, 0); SANITY_CHECK_RETURN_VALUE(!p_FmPcd->p_FmPcdDriverParam, E_INVALID_STATE, 0); if (p_FmPcd->h_Hc) return FmHcPcdKgGetSchemeCounter(p_FmPcd->h_Hc, h_Scheme); physicalSchemeId = (uint8_t)(PTR_TO_UINT(h_Scheme)-1); if(FmPcdKgGetRelativeSchemeId(p_FmPcd, physicalSchemeId) == FM_PCD_KG_NUM_OF_SCHEMES) REPORT_ERROR(MAJOR, E_NOT_IN_RANGE, NO_MSG); tmpKgarReg = FmPcdKgBuildReadSchemeActionReg(physicalSchemeId); intFlags = FmPcdLock(p_FmPcd); WriteKgarWait(p_FmPcd, tmpKgarReg); if (!(GET_UINT32(p_FmPcd->p_FmPcdKg->p_FmPcdKgRegs->indirectAccessRegs.schemeRegs.kgse_mode) & KG_SCH_MODE_EN)) REPORT_ERROR(MAJOR, E_ALREADY_EXISTS, ("Scheme is Invalid")); spc = GET_UINT32(p_FmPcd->p_FmPcdKg->p_FmPcdKgRegs->indirectAccessRegs.schemeRegs.kgse_spc); FmPcdUnlock(p_FmPcd, intFlags); return spc; } t_Error FM_PCD_KgSetSchemeCounter(t_Handle h_FmPcd, t_Handle h_Scheme, uint32_t value) { t_FmPcd *p_FmPcd = (t_FmPcd*)h_FmPcd; uint32_t tmpKgarReg, intFlags; uint8_t physicalSchemeId; SANITY_CHECK_RETURN_VALUE(h_FmPcd, E_INVALID_HANDLE, 0); SANITY_CHECK_RETURN_VALUE(p_FmPcd->p_FmPcdKg, E_INVALID_HANDLE, 0); SANITY_CHECK_RETURN_VALUE(!p_FmPcd->p_FmPcdDriverParam, E_INVALID_STATE, 0); if (p_FmPcd->h_Hc) return FmHcPcdKgSetSchemeCounter(p_FmPcd->h_Hc, h_Scheme, value); physicalSchemeId = (uint8_t)(PTR_TO_UINT(h_Scheme)-1); /* check that schemeId is in range */ if(FmPcdKgGetRelativeSchemeId(p_FmPcd, physicalSchemeId) == FM_PCD_KG_NUM_OF_SCHEMES) REPORT_ERROR(MAJOR, E_NOT_IN_RANGE, NO_MSG); /* read specified scheme into scheme registers */ tmpKgarReg = FmPcdKgBuildReadSchemeActionReg(physicalSchemeId); intFlags = FmPcdLock(p_FmPcd); WriteKgarWait(p_FmPcd, tmpKgarReg); if (!(GET_UINT32(p_FmPcd->p_FmPcdKg->p_FmPcdKgRegs->indirectAccessRegs.schemeRegs.kgse_mode) & KG_SCH_MODE_EN)) { FmPcdUnlock(p_FmPcd, intFlags); RETURN_ERROR(MAJOR, E_ALREADY_EXISTS, ("Scheme is Invalid")); } /* change counter value */ WRITE_UINT32(p_FmPcd->p_FmPcdKg->p_FmPcdKgRegs->indirectAccessRegs.schemeRegs.kgse_spc, value); /* call indirect command for scheme write */ tmpKgarReg = FmPcdKgBuildWriteSchemeActionReg(physicalSchemeId, TRUE); WriteKgarWait(p_FmPcd, tmpKgarReg); FmPcdUnlock(p_FmPcd, intFlags); return E_OK; }