diff options
Diffstat (limited to 'drivers/net/ethernet/freescale/sdk_fman/Peripherals')
74 files changed, 59739 insertions, 0 deletions
diff --git a/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/HC/Makefile b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/HC/Makefile new file mode 100644 index 000000000000..d0e76727b98b --- /dev/null +++ b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/HC/Makefile @@ -0,0 +1,15 @@ +# +# Makefile for the Freescale Ethernet controllers +# +ccflags-y += -DVERSION=\"\" +# +#Include netcomm SW specific definitions +include $(srctree)/drivers/net/ethernet/freescale/sdk_fman/ncsw_config.mk + +NCSW_FM_INC = $(srctree)/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/inc + +ccflags-y += -I$(NCSW_FM_INC) + +obj-y += fsl-ncsw-Hc.o + +fsl-ncsw-Hc-objs := hc.o diff --git a/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/HC/hc.c b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/HC/hc.c new file mode 100644 index 000000000000..7f8139ee9a81 --- /dev/null +++ b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/HC/hc.c @@ -0,0 +1,1236 @@ +/* + * Copyright 2008-2012 Freescale Semiconductor Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Freescale Semiconductor nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * + * ALTERNATIVELY, this software may be distributed under the terms of the + * GNU General Public License ("GPL") as published by the Free Software + * Foundation, either version 2 of that License or (at your option) any + * later version. + * + * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + +#include "std_ext.h" +#include "error_ext.h" +#include "sprint_ext.h" +#include "string_ext.h" + +#include "fm_common.h" +#include "fm_hc.h" + + +/**************************************************************************//** + @Description defaults +*//***************************************************************************/ +#define DEFAULT_dataMemId 0 + +#define HC_HCOR_OPCODE_PLCR_PRFL 0x0 +#define HC_HCOR_OPCODE_KG_SCM 0x1 +#define HC_HCOR_OPCODE_SYNC 0x2 +#define HC_HCOR_OPCODE_CC 0x3 +#define HC_HCOR_OPCODE_CC_AGE_MASK 0x4 +#define HC_HCOR_OPCODE_CC_CAPWAP_REASSM_TIMEOUT 0x5 +#define HC_HCOR_OPCODE_CC_REASSM_TIMEOUT 0x10 +#define HC_HCOR_OPCODE_CC_IP_FRAG_INITIALIZATION 0x11 +#define HC_HCOR_OPCODE_CC_UPDATE_WITH_AGING 0x13 +#define HC_HCOR_ACTION_REG_REASSM_TIMEOUT_ACTIVE_SHIFT 24 +#define HC_HCOR_EXTRA_REG_REASSM_TIMEOUT_TSBS_SHIFT 24 +#define HC_HCOR_EXTRA_REG_CC_AGING_ADD 0x80000000 +#define HC_HCOR_EXTRA_REG_CC_AGING_REMOVE 0x40000000 +#define HC_HCOR_EXTRA_REG_CC_AGING_CHANGE_MASK 0xC0000000 +#define HC_HCOR_EXTRA_REG_CC_REMOVE_INDX_SHIFT 24 +#define HC_HCOR_EXTRA_REG_CC_REMOVE_INDX_MASK 0x1F000000 +#define HC_HCOR_ACTION_REG_REASSM_TIMEOUT_RES_SHIFT 16 +#define HC_HCOR_ACTION_REG_REASSM_TIMEOUT_RES_MASK 0xF +#define HC_HCOR_ACTION_REG_IP_FRAG_SCRATCH_POOL_CMD_SHIFT 24 +#define HC_HCOR_ACTION_REG_IP_FRAG_SCRATCH_POOL_BPID 16 + +#define HC_HCOR_GBL 0x20000000 + +#define HC_HCOR_KG_SCHEME_COUNTER 0x00000400 + +#if (DPAA_VERSION == 10) +#define HC_HCOR_KG_SCHEME_REGS_MASK 0xFFFFF800 +#else +#define HC_HCOR_KG_SCHEME_REGS_MASK 0xFFFFFE00 +#endif /* (DPAA_VERSION == 10) */ + +#define SIZE_OF_HC_FRAME_PORT_REGS (sizeof(t_HcFrame)-sizeof(struct fman_kg_scheme_regs)+sizeof(t_FmPcdKgPortRegs)) +#define SIZE_OF_HC_FRAME_SCHEME_REGS sizeof(t_HcFrame) +#define SIZE_OF_HC_FRAME_PROFILES_REGS (sizeof(t_HcFrame)-sizeof(struct fman_kg_scheme_regs)+sizeof(t_FmPcdPlcrProfileRegs)) +#define SIZE_OF_HC_FRAME_PROFILE_CNT (sizeof(t_HcFrame)-sizeof(t_FmPcdPlcrProfileRegs)+sizeof(uint32_t)) +#define SIZE_OF_HC_FRAME_READ_OR_CC_DYNAMIC 16 + +#define HC_CMD_POOL_SIZE (INTG_MAX_NUM_OF_CORES) + +#define BUILD_FD(len) \ +do { \ + memset(&fmFd, 0, sizeof(t_DpaaFD)); \ + DPAA_FD_SET_ADDR(&fmFd, p_HcFrame); \ + DPAA_FD_SET_OFFSET(&fmFd, 0); \ + DPAA_FD_SET_LENGTH(&fmFd, len); \ +} while (0) + + +#if defined(__MWERKS__) && !defined(__GNUC__) +#pragma pack(push,1) +#endif /* defined(__MWERKS__) && ... */ + +typedef struct t_FmPcdKgPortRegs { + volatile uint32_t spReg; + volatile uint32_t cppReg; +} t_FmPcdKgPortRegs; + +typedef struct t_HcFrame { + volatile uint32_t opcode; + volatile uint32_t actionReg; + volatile uint32_t extraReg; + volatile uint32_t commandSequence; + union { + struct fman_kg_scheme_regs schemeRegs; + struct fman_kg_scheme_regs schemeRegsWithoutCounter; + t_FmPcdPlcrProfileRegs profileRegs; + volatile uint32_t singleRegForWrite; /* for writing SP, CPP, profile counter */ + t_FmPcdKgPortRegs portRegsForRead; + volatile uint32_t clsPlanEntries[CLS_PLAN_NUM_PER_GRP]; + t_FmPcdCcCapwapReassmTimeoutParams ccCapwapReassmTimeout; + t_FmPcdCcReassmTimeoutParams ccReassmTimeout; + } hcSpecificData; +} t_HcFrame; + +#if defined(__MWERKS__) && !defined(__GNUC__) +#pragma pack(pop) +#endif /* defined(__MWERKS__) && ... */ + + +typedef struct t_FmHc { + t_Handle h_FmPcd; + t_Handle h_HcPortDev; + t_FmPcdQmEnqueueCallback *f_QmEnqueue; /**< A callback for enqueuing frames to the QM */ + t_Handle h_QmArg; /**< A handle to the QM module */ + uint8_t dataMemId; /**< Memory partition ID for data buffers */ + + uint32_t seqNum[HC_CMD_POOL_SIZE]; /* FIFO of seqNum to use when + taking buffer */ + uint32_t nextSeqNumLocation; /* seqNum location in seqNum[] for next buffer */ + volatile bool enqueued[HC_CMD_POOL_SIZE]; /* HC is active - frame is enqueued + and not confirmed yet */ + t_HcFrame *p_Frm[HC_CMD_POOL_SIZE]; +} t_FmHc; + + +static t_Error FillBufPool(t_FmHc *p_FmHc) +{ + uint32_t i; + + ASSERT_COND(p_FmHc); + + for (i = 0; i < HC_CMD_POOL_SIZE; i++) + { +#ifdef FM_LOCKUP_ALIGNMENT_ERRATA_FMAN_SW004 + p_FmHc->p_Frm[i] = (t_HcFrame *)XX_MallocSmart((sizeof(t_HcFrame) + (16 - (sizeof(t_FmHc) % 16))), + p_FmHc->dataMemId, + 16); +#else + p_FmHc->p_Frm[i] = (t_HcFrame *)XX_MallocSmart(sizeof(t_HcFrame), + p_FmHc->dataMemId, + 16); +#endif /* FM_LOCKUP_ALIGNMENT_ERRATA_FMAN_SW004 */ + if (!p_FmHc->p_Frm[i]) + RETURN_ERROR(MAJOR, E_NO_MEMORY, ("FM HC frames!")); + } + + /* Initialize FIFO of seqNum to use during GetBuf */ + for (i = 0; i < HC_CMD_POOL_SIZE; i++) + { + p_FmHc->seqNum[i] = i; + } + p_FmHc->nextSeqNumLocation = 0; + + return E_OK; +} + +static __inline__ t_HcFrame * GetBuf(t_FmHc *p_FmHc, uint32_t *p_SeqNum) +{ + uint32_t intFlags; + + ASSERT_COND(p_FmHc); + + intFlags = FmPcdLock(p_FmHc->h_FmPcd); + + if (p_FmHc->nextSeqNumLocation == HC_CMD_POOL_SIZE) + { + /* No more buffers */ + FmPcdUnlock(p_FmHc->h_FmPcd, intFlags); + return NULL; + } + + *p_SeqNum = p_FmHc->seqNum[p_FmHc->nextSeqNumLocation]; + p_FmHc->nextSeqNumLocation++; + + FmPcdUnlock(p_FmHc->h_FmPcd, intFlags); + return p_FmHc->p_Frm[*p_SeqNum]; +} + +static __inline__ void PutBuf(t_FmHc *p_FmHc, t_HcFrame *p_Buf, uint32_t seqNum) +{ + uint32_t intFlags; + + UNUSED(p_Buf); + + intFlags = FmPcdLock(p_FmHc->h_FmPcd); + ASSERT_COND(p_FmHc->nextSeqNumLocation); + p_FmHc->nextSeqNumLocation--; + p_FmHc->seqNum[p_FmHc->nextSeqNumLocation] = seqNum; + FmPcdUnlock(p_FmHc->h_FmPcd, intFlags); +} + +static __inline__ t_Error EnQFrm(t_FmHc *p_FmHc, t_DpaaFD *p_FmFd, uint32_t seqNum) +{ + t_Error err = E_OK; + uint32_t intFlags; + uint32_t timeout=100; + + intFlags = FmPcdLock(p_FmHc->h_FmPcd); + ASSERT_COND(!p_FmHc->enqueued[seqNum]); + p_FmHc->enqueued[seqNum] = TRUE; + FmPcdUnlock(p_FmHc->h_FmPcd, intFlags); + DBG(TRACE, ("Send Hc, SeqNum %d, buff@0x%x, fd offset 0x%x", + seqNum, + DPAA_FD_GET_ADDR(p_FmFd), + DPAA_FD_GET_OFFSET(p_FmFd))); + err = p_FmHc->f_QmEnqueue(p_FmHc->h_QmArg, (void *)p_FmFd); + if (err) + RETURN_ERROR(MINOR, err, ("HC enqueue failed")); + + while (p_FmHc->enqueued[seqNum] && --timeout) + XX_UDelay(100); + + if (!timeout) + RETURN_ERROR(MINOR, E_TIMEOUT, ("HC Callback, timeout exceeded")); + + return err; +} + + +t_Handle FmHcConfigAndInit(t_FmHcParams *p_FmHcParams) +{ + t_FmHc *p_FmHc; + t_FmPortParams fmPortParam; + t_Error err; + + p_FmHc = (t_FmHc *)XX_Malloc(sizeof(t_FmHc)); + if (!p_FmHc) + { + REPORT_ERROR(MINOR, E_NO_MEMORY, ("HC obj")); + return NULL; + } + memset(p_FmHc,0,sizeof(t_FmHc)); + + p_FmHc->h_FmPcd = p_FmHcParams->h_FmPcd; + p_FmHc->f_QmEnqueue = p_FmHcParams->params.f_QmEnqueue; + p_FmHc->h_QmArg = p_FmHcParams->params.h_QmArg; + p_FmHc->dataMemId = DEFAULT_dataMemId; + + err = FillBufPool(p_FmHc); + if (err != E_OK) + { + REPORT_ERROR(MAJOR, err, NO_MSG); + FmHcFree(p_FmHc); + return NULL; + } + + if (!FmIsMaster(p_FmHcParams->h_Fm)) + return (t_Handle)p_FmHc; + + memset(&fmPortParam, 0, sizeof(fmPortParam)); + fmPortParam.baseAddr = p_FmHcParams->params.portBaseAddr; + fmPortParam.portType = e_FM_PORT_TYPE_OH_HOST_COMMAND; + fmPortParam.portId = p_FmHcParams->params.portId; + fmPortParam.liodnBase = p_FmHcParams->params.liodnBase; + fmPortParam.h_Fm = p_FmHcParams->h_Fm; + + fmPortParam.specificParams.nonRxParams.errFqid = p_FmHcParams->params.errFqid; + fmPortParam.specificParams.nonRxParams.dfltFqid = p_FmHcParams->params.confFqid; + fmPortParam.specificParams.nonRxParams.qmChannel = p_FmHcParams->params.qmChannel; + + p_FmHc->h_HcPortDev = FM_PORT_Config(&fmPortParam); + if (!p_FmHc->h_HcPortDev) + { + REPORT_ERROR(MAJOR, E_INVALID_HANDLE, ("FM HC port!")); + XX_Free(p_FmHc); + return NULL; + } + + err = FM_PORT_ConfigMaxFrameLength(p_FmHc->h_HcPortDev, + (uint16_t)sizeof(t_HcFrame)); + + if (err != E_OK) + { + REPORT_ERROR(MAJOR, err, ("FM HC port init!")); + FmHcFree(p_FmHc); + return NULL; + } + + /* final init */ + err = FM_PORT_Init(p_FmHc->h_HcPortDev); + if (err != E_OK) + { + REPORT_ERROR(MAJOR, err, ("FM HC port init!")); + FmHcFree(p_FmHc); + return NULL; + } + + err = FM_PORT_Enable(p_FmHc->h_HcPortDev); + if (err != E_OK) + { + REPORT_ERROR(MAJOR, err, ("FM HC port enable!")); + FmHcFree(p_FmHc); + return NULL; + } + + return (t_Handle)p_FmHc; +} + +void FmHcFree(t_Handle h_FmHc) +{ + t_FmHc *p_FmHc = (t_FmHc*)h_FmHc; + int i; + + if (!p_FmHc) + return; + + for (i=0; i<HC_CMD_POOL_SIZE; i++) + if (p_FmHc->p_Frm[i]) + XX_FreeSmart(p_FmHc->p_Frm[i]); + else + break; + + if (p_FmHc->h_HcPortDev) + FM_PORT_Free(p_FmHc->h_HcPortDev); + + XX_Free(p_FmHc); +} + +/*****************************************************************************/ +t_Error FmHcSetFramesDataMemory(t_Handle h_FmHc, + uint8_t memId) +{ + t_FmHc *p_FmHc = (t_FmHc*)h_FmHc; + int i; + + SANITY_CHECK_RETURN_ERROR(p_FmHc, E_INVALID_HANDLE); + + p_FmHc->dataMemId = memId; + + for (i=0; i<HC_CMD_POOL_SIZE; i++) + if (p_FmHc->p_Frm[i]) + XX_FreeSmart(p_FmHc->p_Frm[i]); + + return FillBufPool(p_FmHc); +} + +void FmHcTxConf(t_Handle h_FmHc, t_DpaaFD *p_Fd) +{ + t_FmHc *p_FmHc = (t_FmHc*)h_FmHc; + t_HcFrame *p_HcFrame; + uint32_t intFlags; + + ASSERT_COND(p_FmHc); + + intFlags = FmPcdLock(p_FmHc->h_FmPcd); + p_HcFrame = (t_HcFrame *)PTR_MOVE(DPAA_FD_GET_ADDR(p_Fd), DPAA_FD_GET_OFFSET(p_Fd)); + + DBG(TRACE, ("Hc Conf, SeqNum %d, FD@0x%x, fd offset 0x%x", + p_HcFrame->commandSequence, DPAA_FD_GET_ADDR(p_Fd), DPAA_FD_GET_OFFSET(p_Fd))); + + if (!(p_FmHc->enqueued[p_HcFrame->commandSequence])) + REPORT_ERROR(MINOR, E_INVALID_FRAME, ("Not an Host-Command frame received!")); + else + p_FmHc->enqueued[p_HcFrame->commandSequence] = FALSE; + FmPcdUnlock(p_FmHc->h_FmPcd, intFlags); +} + +t_Error FmHcPcdKgSetScheme(t_Handle h_FmHc, + t_Handle h_Scheme, + struct fman_kg_scheme_regs *p_SchemeRegs, + bool updateCounter) +{ + t_FmHc *p_FmHc = (t_FmHc*)h_FmHc; + t_Error err = E_OK; + t_HcFrame *p_HcFrame; + t_DpaaFD fmFd; + uint8_t physicalSchemeId; + uint32_t seqNum; + + p_HcFrame = GetBuf(p_FmHc, &seqNum); + if (!p_HcFrame) + RETURN_ERROR(MINOR, E_NO_MEMORY, ("HC Frame object")); + + physicalSchemeId = FmPcdKgGetSchemeId(h_Scheme); + + memset(p_HcFrame, 0, sizeof(t_HcFrame)); + p_HcFrame->opcode = (uint32_t)(HC_HCOR_GBL | HC_HCOR_OPCODE_KG_SCM); + p_HcFrame->actionReg = FmPcdKgBuildWriteSchemeActionReg(physicalSchemeId, updateCounter); + p_HcFrame->extraReg = HC_HCOR_KG_SCHEME_REGS_MASK; + memcpy(&p_HcFrame->hcSpecificData.schemeRegs, p_SchemeRegs, sizeof(struct fman_kg_scheme_regs)); + if (!updateCounter) + { + p_HcFrame->hcSpecificData.schemeRegs.kgse_dv0 = p_SchemeRegs->kgse_dv0; + p_HcFrame->hcSpecificData.schemeRegs.kgse_dv1 = p_SchemeRegs->kgse_dv1; + p_HcFrame->hcSpecificData.schemeRegs.kgse_ccbs = p_SchemeRegs->kgse_ccbs; + p_HcFrame->hcSpecificData.schemeRegs.kgse_mv = p_SchemeRegs->kgse_mv; + } + p_HcFrame->commandSequence = seqNum; + + BUILD_FD(sizeof(t_HcFrame)); + + err = EnQFrm(p_FmHc, &fmFd, seqNum); + + PutBuf(p_FmHc, p_HcFrame, seqNum); + + if (err != E_OK) + RETURN_ERROR(MINOR, err, NO_MSG); + + return E_OK; +} + +t_Error FmHcPcdKgDeleteScheme(t_Handle h_FmHc, t_Handle h_Scheme) +{ + t_FmHc *p_FmHc = (t_FmHc*)h_FmHc; + t_Error err = E_OK; + t_HcFrame *p_HcFrame; + t_DpaaFD fmFd; + uint8_t physicalSchemeId = FmPcdKgGetSchemeId(h_Scheme); + uint32_t seqNum; + + p_HcFrame = GetBuf(p_FmHc, &seqNum); + if (!p_HcFrame) + RETURN_ERROR(MINOR, E_NO_MEMORY, ("HC Frame object")); + + memset(p_HcFrame, 0, sizeof(t_HcFrame)); + p_HcFrame->opcode = (uint32_t)(HC_HCOR_GBL | HC_HCOR_OPCODE_KG_SCM); + p_HcFrame->actionReg = FmPcdKgBuildWriteSchemeActionReg(physicalSchemeId, TRUE); + p_HcFrame->extraReg = HC_HCOR_KG_SCHEME_REGS_MASK; + memset(&p_HcFrame->hcSpecificData.schemeRegs, 0, sizeof(struct fman_kg_scheme_regs)); + p_HcFrame->commandSequence = seqNum; + + BUILD_FD(sizeof(t_HcFrame)); + + err = EnQFrm(p_FmHc, &fmFd, seqNum); + + PutBuf(p_FmHc, p_HcFrame, seqNum); + + if (err != E_OK) + RETURN_ERROR(MINOR, err, NO_MSG); + + return E_OK; +} + +t_Error FmHcPcdKgCcGetSetParams(t_Handle h_FmHc, t_Handle h_Scheme, uint32_t requiredAction, uint32_t value) +{ + t_FmHc *p_FmHc = (t_FmHc*)h_FmHc; + t_Error err = E_OK; + t_HcFrame *p_HcFrame; + t_DpaaFD fmFd; + uint8_t relativeSchemeId; + uint8_t physicalSchemeId = FmPcdKgGetSchemeId(h_Scheme); + uint32_t tmpReg32 = 0; + uint32_t seqNum; + + /* Scheme is locked by calling routine */ + /* WARNING - this lock will not be efficient if other HC routine will attempt to change + * "kgse_mode" or "kgse_om" without locking scheme ! + */ + + relativeSchemeId = FmPcdKgGetRelativeSchemeId(p_FmHc->h_FmPcd, physicalSchemeId); + if ( relativeSchemeId == FM_PCD_KG_NUM_OF_SCHEMES) + RETURN_ERROR(MAJOR, E_NOT_IN_RANGE, NO_MSG); + + if (!FmPcdKgGetRequiredActionFlag(p_FmHc->h_FmPcd, relativeSchemeId) || + !(FmPcdKgGetRequiredAction(p_FmHc->h_FmPcd, relativeSchemeId) & requiredAction)) + { + if ((requiredAction & UPDATE_NIA_ENQ_WITHOUT_DMA) && + (FmPcdKgGetNextEngine(p_FmHc->h_FmPcd, relativeSchemeId) == e_FM_PCD_PLCR)) + { + if ((FmPcdKgIsDirectPlcr(p_FmHc->h_FmPcd, relativeSchemeId) == FALSE) || + (FmPcdKgIsDistrOnPlcrProfile(p_FmHc->h_FmPcd, relativeSchemeId) == TRUE)) + RETURN_ERROR(MAJOR, E_NOT_SUPPORTED, ("In this situation PP can not be with distribution and has to be shared")); + err = FmPcdPlcrCcGetSetParams(p_FmHc->h_FmPcd, FmPcdKgGetRelativeProfileId(p_FmHc->h_FmPcd, relativeSchemeId), requiredAction); + if (err) + RETURN_ERROR(MAJOR, err, NO_MSG); + } + else /* From here we deal with KG-Schemes only */ + { + /* Pre change general code */ + p_HcFrame = GetBuf(p_FmHc, &seqNum); + if (!p_HcFrame) + RETURN_ERROR(MINOR, E_NO_MEMORY, ("HC Frame object")); + memset(p_HcFrame, 0, sizeof(t_HcFrame)); + p_HcFrame->opcode = (uint32_t)(HC_HCOR_GBL | HC_HCOR_OPCODE_KG_SCM); + p_HcFrame->actionReg = FmPcdKgBuildReadSchemeActionReg(physicalSchemeId); + p_HcFrame->extraReg = HC_HCOR_KG_SCHEME_REGS_MASK; + p_HcFrame->commandSequence = seqNum; + BUILD_FD(SIZE_OF_HC_FRAME_READ_OR_CC_DYNAMIC); + if ((err = EnQFrm(p_FmHc, &fmFd, seqNum)) != E_OK) + { + PutBuf(p_FmHc, p_HcFrame, seqNum); + RETURN_ERROR(MINOR, err, NO_MSG); + } + + /* specific change */ + if ((requiredAction & UPDATE_NIA_ENQ_WITHOUT_DMA) && + ((FmPcdKgGetNextEngine(p_FmHc->h_FmPcd, relativeSchemeId) == e_FM_PCD_DONE) && + (FmPcdKgGetDoneAction(p_FmHc->h_FmPcd, relativeSchemeId) == e_FM_PCD_ENQ_FRAME))) + { + tmpReg32 = p_HcFrame->hcSpecificData.schemeRegs.kgse_mode; + ASSERT_COND(tmpReg32 & (NIA_ENG_BMI | NIA_BMI_AC_ENQ_FRAME)); + p_HcFrame->hcSpecificData.schemeRegs.kgse_mode = tmpReg32 | NIA_BMI_AC_ENQ_FRAME_WITHOUT_DMA; + } + + if ((requiredAction & UPDATE_KG_NIA_CC_WA) && + (FmPcdKgGetNextEngine(p_FmHc->h_FmPcd, relativeSchemeId) == e_FM_PCD_CC)) + { + tmpReg32 = p_HcFrame->hcSpecificData.schemeRegs.kgse_mode; + ASSERT_COND(tmpReg32 & (NIA_ENG_FM_CTL | NIA_FM_CTL_AC_CC)); + tmpReg32 &= ~NIA_FM_CTL_AC_CC; + p_HcFrame->hcSpecificData.schemeRegs.kgse_mode = tmpReg32 | NIA_FM_CTL_AC_PRE_CC; + } + + if (requiredAction & UPDATE_KG_OPT_MODE) + p_HcFrame->hcSpecificData.schemeRegs.kgse_om = value; + + if (requiredAction & UPDATE_KG_NIA) + { + tmpReg32 = p_HcFrame->hcSpecificData.schemeRegs.kgse_mode; + tmpReg32 &= ~(NIA_ENG_MASK | NIA_AC_MASK); + tmpReg32 |= value; + p_HcFrame->hcSpecificData.schemeRegs.kgse_mode = tmpReg32; + } + + /* Post change general code */ + p_HcFrame->opcode = (uint32_t)(HC_HCOR_GBL | HC_HCOR_OPCODE_KG_SCM); + p_HcFrame->actionReg = FmPcdKgBuildWriteSchemeActionReg(physicalSchemeId, FALSE); + p_HcFrame->extraReg = HC_HCOR_KG_SCHEME_REGS_MASK; + + BUILD_FD(sizeof(t_HcFrame)); + err = EnQFrm(p_FmHc, &fmFd, seqNum); + + PutBuf(p_FmHc, p_HcFrame, seqNum); + + if (err != E_OK) + RETURN_ERROR(MINOR, err, NO_MSG); + } + } + + return E_OK; +} + +uint32_t FmHcPcdKgGetSchemeCounter(t_Handle h_FmHc, t_Handle h_Scheme) +{ + t_FmHc *p_FmHc = (t_FmHc*)h_FmHc; + t_Error err; + t_HcFrame *p_HcFrame; + t_DpaaFD fmFd; + uint32_t retVal; + uint8_t relativeSchemeId; + uint8_t physicalSchemeId = FmPcdKgGetSchemeId(h_Scheme); + uint32_t seqNum; + + relativeSchemeId = FmPcdKgGetRelativeSchemeId(p_FmHc->h_FmPcd, physicalSchemeId); + if ( relativeSchemeId == FM_PCD_KG_NUM_OF_SCHEMES) + { + REPORT_ERROR(MAJOR, E_NOT_IN_RANGE, NO_MSG); + return 0; + } + + /* first read scheme and check that it is valid */ + p_HcFrame = GetBuf(p_FmHc, &seqNum); + if (!p_HcFrame) + { + REPORT_ERROR(MINOR, E_NO_MEMORY, ("HC Frame object")); + return 0; + } + memset(p_HcFrame, 0, sizeof(t_HcFrame)); + p_HcFrame->opcode = (uint32_t)(HC_HCOR_GBL | HC_HCOR_OPCODE_KG_SCM); + p_HcFrame->actionReg = FmPcdKgBuildReadSchemeActionReg(physicalSchemeId); + p_HcFrame->extraReg = HC_HCOR_KG_SCHEME_REGS_MASK; + p_HcFrame->commandSequence = seqNum; + + BUILD_FD(SIZE_OF_HC_FRAME_READ_OR_CC_DYNAMIC); + + err = EnQFrm(p_FmHc, &fmFd, seqNum); + if (err != E_OK) + { + PutBuf(p_FmHc, p_HcFrame, seqNum); + REPORT_ERROR(MINOR, err, NO_MSG); + return 0; + } + + if (!FmPcdKgHwSchemeIsValid(p_HcFrame->hcSpecificData.schemeRegs.kgse_mode)) + { + PutBuf(p_FmHc, p_HcFrame, seqNum); + REPORT_ERROR(MAJOR, E_ALREADY_EXISTS, ("Scheme is invalid")); + return 0; + } + + retVal = p_HcFrame->hcSpecificData.schemeRegs.kgse_spc; + PutBuf(p_FmHc, p_HcFrame, seqNum); + + return retVal; +} + +t_Error FmHcPcdKgSetSchemeCounter(t_Handle h_FmHc, t_Handle h_Scheme, uint32_t value) +{ + t_FmHc *p_FmHc = (t_FmHc*)h_FmHc; + t_Error err = E_OK; + t_HcFrame *p_HcFrame; + t_DpaaFD fmFd; + uint8_t relativeSchemeId, physicalSchemeId; + uint32_t seqNum; + + physicalSchemeId = FmPcdKgGetSchemeId(h_Scheme); + relativeSchemeId = FmPcdKgGetRelativeSchemeId(p_FmHc->h_FmPcd, physicalSchemeId); + if ( relativeSchemeId == FM_PCD_KG_NUM_OF_SCHEMES) + RETURN_ERROR(MAJOR, E_NOT_IN_RANGE, NO_MSG); + + /* first read scheme and check that it is valid */ + p_HcFrame = GetBuf(p_FmHc, &seqNum); + if (!p_HcFrame) + RETURN_ERROR(MINOR, E_NO_MEMORY, ("HC Frame object")); + memset(p_HcFrame, 0, sizeof(t_HcFrame)); + p_HcFrame->opcode = (uint32_t)(HC_HCOR_GBL | HC_HCOR_OPCODE_KG_SCM); + p_HcFrame->actionReg = FmPcdKgBuildWriteSchemeActionReg(physicalSchemeId, TRUE); + p_HcFrame->extraReg = HC_HCOR_KG_SCHEME_COUNTER; + /* write counter */ + p_HcFrame->hcSpecificData.singleRegForWrite = value; + p_HcFrame->commandSequence = seqNum; + + BUILD_FD(sizeof(t_HcFrame)); + + err = EnQFrm(p_FmHc, &fmFd, seqNum); + + PutBuf(p_FmHc, p_HcFrame, seqNum); + return err; +} + +t_Error FmHcPcdKgSetClsPlan(t_Handle h_FmHc, t_FmPcdKgInterModuleClsPlanSet *p_Set) +{ + t_FmHc *p_FmHc = (t_FmHc*)h_FmHc; + t_HcFrame *p_HcFrame; + t_DpaaFD fmFd; + uint8_t i, idx; + uint32_t seqNum; + const void *src; + void *dest; + t_Error err = E_OK; + + ASSERT_COND(p_FmHc); + + p_HcFrame = GetBuf(p_FmHc, &seqNum); + if (!p_HcFrame) + RETURN_ERROR(MINOR, E_NO_MEMORY, ("HC Frame object")); + + for (i = p_Set->baseEntry; i < (p_Set->baseEntry+p_Set->numOfClsPlanEntries); i+=8) + { + memset(p_HcFrame, 0, sizeof(t_HcFrame)); + p_HcFrame->opcode = (uint32_t)(HC_HCOR_GBL | HC_HCOR_OPCODE_KG_SCM); + p_HcFrame->actionReg = FmPcdKgBuildWriteClsPlanBlockActionReg((uint8_t)(i / CLS_PLAN_NUM_PER_GRP)); + p_HcFrame->extraReg = HC_HCOR_KG_SCHEME_REGS_MASK; + + idx = (uint8_t)(i - p_Set->baseEntry); + ASSERT_COND(idx < FM_PCD_MAX_NUM_OF_CLS_PLANS); + dest = (void *)&p_HcFrame->hcSpecificData.clsPlanEntries; + src = &p_Set->vectors[idx]; + memcpy(dest, src, CLS_PLAN_NUM_PER_GRP*sizeof(uint32_t)); + p_HcFrame->commandSequence = seqNum; + + BUILD_FD(sizeof(t_HcFrame)); + + if ((err = EnQFrm(p_FmHc, &fmFd, seqNum)) != E_OK) + { + PutBuf(p_FmHc, p_HcFrame, seqNum); + RETURN_ERROR(MINOR, err, NO_MSG); + } + } + + PutBuf(p_FmHc, p_HcFrame, seqNum); + return err; +} + +t_Error FmHcPcdKgDeleteClsPlan(t_Handle h_FmHc, uint8_t grpId) +{ + t_FmHc *p_FmHc = (t_FmHc*)h_FmHc; + t_FmPcdKgInterModuleClsPlanSet *p_ClsPlanSet; + + p_ClsPlanSet = (t_FmPcdKgInterModuleClsPlanSet *)XX_Malloc(sizeof(t_FmPcdKgInterModuleClsPlanSet)); + if (!p_ClsPlanSet) + RETURN_ERROR(MAJOR, E_NO_MEMORY, ("Classification plan set")); + + memset(p_ClsPlanSet, 0, sizeof(t_FmPcdKgInterModuleClsPlanSet)); + + p_ClsPlanSet->baseEntry = FmPcdKgGetClsPlanGrpBase(p_FmHc->h_FmPcd, grpId); + p_ClsPlanSet->numOfClsPlanEntries = FmPcdKgGetClsPlanGrpSize(p_FmHc->h_FmPcd, grpId); + ASSERT_COND(p_ClsPlanSet->numOfClsPlanEntries <= FM_PCD_MAX_NUM_OF_CLS_PLANS); + + if (FmHcPcdKgSetClsPlan(p_FmHc, p_ClsPlanSet) != E_OK) + { + XX_Free(p_ClsPlanSet); + RETURN_ERROR(MAJOR, E_INVALID_STATE, NO_MSG); + } + + XX_Free(p_ClsPlanSet); + FmPcdKgDestroyClsPlanGrp(p_FmHc->h_FmPcd, grpId); + + return E_OK; +} + +t_Error FmHcPcdCcCapwapTimeoutReassm(t_Handle h_FmHc, t_FmPcdCcCapwapReassmTimeoutParams *p_CcCapwapReassmTimeoutParams ) +{ + t_FmHc *p_FmHc = (t_FmHc*)h_FmHc; + t_HcFrame *p_HcFrame; + t_DpaaFD fmFd; + t_Error err; + uint32_t seqNum; + + SANITY_CHECK_RETURN_VALUE(h_FmHc, E_INVALID_HANDLE,0); + + p_HcFrame = GetBuf(p_FmHc, &seqNum); + if (!p_HcFrame) + RETURN_ERROR(MINOR, E_NO_MEMORY, ("HC Frame object")); + + memset(p_HcFrame, 0, sizeof(t_HcFrame)); + p_HcFrame->opcode = (uint32_t)(HC_HCOR_GBL | HC_HCOR_OPCODE_CC_CAPWAP_REASSM_TIMEOUT); + memcpy(&p_HcFrame->hcSpecificData.ccCapwapReassmTimeout, p_CcCapwapReassmTimeoutParams, sizeof(t_FmPcdCcCapwapReassmTimeoutParams)); + p_HcFrame->commandSequence = seqNum; + BUILD_FD(sizeof(t_HcFrame)); + + err = EnQFrm(p_FmHc, &fmFd, seqNum); + + PutBuf(p_FmHc, p_HcFrame, seqNum); + return err; +} + +t_Error FmHcPcdCcIpFragScratchPollCmd(t_Handle h_FmHc, bool fill, t_FmPcdCcFragScratchPoolCmdParams *p_FmPcdCcFragScratchPoolCmdParams) +{ + t_FmHc *p_FmHc = (t_FmHc*)h_FmHc; + t_HcFrame *p_HcFrame; + t_DpaaFD fmFd; + t_Error err; + uint32_t seqNum; + + SANITY_CHECK_RETURN_VALUE(h_FmHc, E_INVALID_HANDLE,0); + + p_HcFrame = GetBuf(p_FmHc, &seqNum); + if (!p_HcFrame) + RETURN_ERROR(MINOR, E_NO_MEMORY, ("HC Frame object")); + + memset(p_HcFrame, 0, sizeof(t_HcFrame)); + + p_HcFrame->opcode = (uint32_t)(HC_HCOR_GBL | HC_HCOR_OPCODE_CC_IP_FRAG_INITIALIZATION); + p_HcFrame->actionReg = (uint32_t)(((fill == TRUE) ? 0 : 1) << HC_HCOR_ACTION_REG_IP_FRAG_SCRATCH_POOL_CMD_SHIFT); + p_HcFrame->actionReg |= p_FmPcdCcFragScratchPoolCmdParams->bufferPoolId << HC_HCOR_ACTION_REG_IP_FRAG_SCRATCH_POOL_BPID; + if (fill == TRUE) + { + p_HcFrame->extraReg = p_FmPcdCcFragScratchPoolCmdParams->numOfBuffers; + } + p_HcFrame->commandSequence = seqNum; + + BUILD_FD(sizeof(t_HcFrame)); + if ((err = EnQFrm(p_FmHc, &fmFd, seqNum)) != E_OK) + { + PutBuf(p_FmHc, p_HcFrame, seqNum); + RETURN_ERROR(MINOR, err, NO_MSG); + } + + p_FmPcdCcFragScratchPoolCmdParams->numOfBuffers = p_HcFrame->extraReg; + + PutBuf(p_FmHc, p_HcFrame, seqNum); + return E_OK; +} + +t_Error FmHcPcdCcTimeoutReassm(t_Handle h_FmHc, t_FmPcdCcReassmTimeoutParams *p_CcReassmTimeoutParams, uint8_t *p_Result) +{ + t_FmHc *p_FmHc = (t_FmHc*)h_FmHc; + t_HcFrame *p_HcFrame; + t_DpaaFD fmFd; + t_Error err; + uint32_t seqNum; + + SANITY_CHECK_RETURN_VALUE(h_FmHc, E_INVALID_HANDLE,0); + + p_HcFrame = GetBuf(p_FmHc, &seqNum); + if (!p_HcFrame) + RETURN_ERROR(MINOR, E_NO_MEMORY, ("HC Frame object")); + + memset(p_HcFrame, 0, sizeof(t_HcFrame)); + p_HcFrame->opcode = (uint32_t)(HC_HCOR_GBL | HC_HCOR_OPCODE_CC_REASSM_TIMEOUT); + p_HcFrame->actionReg = (uint32_t)((p_CcReassmTimeoutParams->activate ? 0 : 1) << HC_HCOR_ACTION_REG_REASSM_TIMEOUT_ACTIVE_SHIFT); + p_HcFrame->extraReg = (p_CcReassmTimeoutParams->tsbs << HC_HCOR_EXTRA_REG_REASSM_TIMEOUT_TSBS_SHIFT) | p_CcReassmTimeoutParams->iprcpt; + p_HcFrame->commandSequence = seqNum; + + BUILD_FD(sizeof(t_HcFrame)); + if ((err = EnQFrm(p_FmHc, &fmFd, seqNum)) != E_OK) + { + PutBuf(p_FmHc, p_HcFrame, seqNum); + RETURN_ERROR(MINOR, err, NO_MSG); + } + + *p_Result = (uint8_t) + ((p_HcFrame->actionReg >> HC_HCOR_ACTION_REG_REASSM_TIMEOUT_RES_SHIFT) & HC_HCOR_ACTION_REG_REASSM_TIMEOUT_RES_MASK); + + PutBuf(p_FmHc, p_HcFrame, seqNum); + return E_OK; +} + +t_Error FmHcPcdPlcrCcGetSetParams(t_Handle h_FmHc,uint16_t absoluteProfileId, uint32_t requiredAction) +{ + t_FmHc *p_FmHc = (t_FmHc*)h_FmHc; + t_HcFrame *p_HcFrame; + t_DpaaFD fmFd; + t_Error err; + uint32_t tmpReg32 = 0; + uint32_t requiredActionTmp, requiredActionFlag; + uint32_t seqNum; + + SANITY_CHECK_RETURN_VALUE(h_FmHc, E_INVALID_HANDLE,0); + + /* Profile is locked by calling routine */ + /* WARNING - this lock will not be efficient if other HC routine will attempt to change + * "fmpl_pegnia" "fmpl_peynia" or "fmpl_pernia" without locking Profile ! + */ + + requiredActionTmp = FmPcdPlcrGetRequiredAction(p_FmHc->h_FmPcd, absoluteProfileId); + requiredActionFlag = FmPcdPlcrGetRequiredActionFlag(p_FmHc->h_FmPcd, absoluteProfileId); + + if (!requiredActionFlag || !(requiredActionTmp & requiredAction)) + { + if (requiredAction & UPDATE_NIA_ENQ_WITHOUT_DMA) + { + p_HcFrame = GetBuf(p_FmHc, &seqNum); + if (!p_HcFrame) + RETURN_ERROR(MINOR, E_NO_MEMORY, ("HC Frame object")); + /* first read scheme and check that it is valid */ + memset(p_HcFrame, 0, sizeof(t_HcFrame)); + p_HcFrame->opcode = (uint32_t)(HC_HCOR_GBL | HC_HCOR_OPCODE_PLCR_PRFL); + p_HcFrame->actionReg = FmPcdPlcrBuildReadPlcrActionReg(absoluteProfileId); + p_HcFrame->extraReg = 0x00008000; + p_HcFrame->commandSequence = seqNum; + + BUILD_FD(SIZE_OF_HC_FRAME_READ_OR_CC_DYNAMIC); + + if ((err = EnQFrm(p_FmHc, &fmFd, seqNum)) != E_OK) + { + PutBuf(p_FmHc, p_HcFrame, seqNum); + RETURN_ERROR(MINOR, err, NO_MSG); + } + + tmpReg32 = p_HcFrame->hcSpecificData.profileRegs.fmpl_pegnia; + if (!(tmpReg32 & (NIA_ENG_BMI | NIA_BMI_AC_ENQ_FRAME))) + { + PutBuf(p_FmHc, p_HcFrame, seqNum); + RETURN_ERROR(MAJOR, E_INVALID_STATE, + ("Next engine of this policer profile has to be assigned to FM_PCD_DONE")); + } + + tmpReg32 |= NIA_BMI_AC_ENQ_FRAME_WITHOUT_DMA; + + p_HcFrame->opcode = (uint32_t)(HC_HCOR_GBL | HC_HCOR_OPCODE_PLCR_PRFL); + p_HcFrame->actionReg = FmPcdPlcrBuildWritePlcrActionReg(absoluteProfileId); + p_HcFrame->actionReg |= FmPcdPlcrBuildNiaProfileReg(TRUE, FALSE, FALSE); + p_HcFrame->extraReg = 0x00008000; + p_HcFrame->hcSpecificData.singleRegForWrite = tmpReg32; + + BUILD_FD(SIZE_OF_HC_FRAME_PROFILE_CNT); + + if ((err = EnQFrm(p_FmHc, &fmFd, seqNum)) != E_OK) + { + PutBuf(p_FmHc, p_HcFrame, seqNum); + RETURN_ERROR(MINOR, err, NO_MSG); + } + + tmpReg32 = p_HcFrame->hcSpecificData.profileRegs.fmpl_peynia; + if (!(tmpReg32 & (NIA_ENG_BMI | NIA_BMI_AC_ENQ_FRAME))) + { + PutBuf(p_FmHc, p_HcFrame, seqNum); + RETURN_ERROR(MAJOR, E_INVALID_STATE, ("Next engine of this policer profile has to be assigned to FM_PCD_DONE")); + } + + tmpReg32 |= NIA_BMI_AC_ENQ_FRAME_WITHOUT_DMA; + + p_HcFrame->opcode = (uint32_t)(HC_HCOR_GBL | HC_HCOR_OPCODE_PLCR_PRFL); + p_HcFrame->actionReg = FmPcdPlcrBuildWritePlcrActionReg(absoluteProfileId); + p_HcFrame->actionReg |= FmPcdPlcrBuildNiaProfileReg(FALSE, TRUE, FALSE); + p_HcFrame->extraReg = 0x00008000; + p_HcFrame->hcSpecificData.singleRegForWrite = tmpReg32; + + BUILD_FD(SIZE_OF_HC_FRAME_PROFILE_CNT); + + if ((err = EnQFrm(p_FmHc, &fmFd, seqNum)) != E_OK) + { + PutBuf(p_FmHc, p_HcFrame, seqNum); + RETURN_ERROR(MINOR, err, NO_MSG); + } + + tmpReg32 = p_HcFrame->hcSpecificData.profileRegs.fmpl_pernia; + if (!(tmpReg32 & (NIA_ENG_BMI | NIA_BMI_AC_ENQ_FRAME))) + { + PutBuf(p_FmHc, p_HcFrame, seqNum); + RETURN_ERROR(MAJOR, E_INVALID_STATE, ("Next engine of this policer profile has to be assigned to FM_PCD_DONE")); + } + + tmpReg32 |= NIA_BMI_AC_ENQ_FRAME_WITHOUT_DMA; + + p_HcFrame->opcode = (uint32_t)(HC_HCOR_GBL | HC_HCOR_OPCODE_PLCR_PRFL); + p_HcFrame->actionReg = FmPcdPlcrBuildWritePlcrActionReg(absoluteProfileId); + p_HcFrame->actionReg |= FmPcdPlcrBuildNiaProfileReg(FALSE, FALSE, TRUE); + p_HcFrame->extraReg = 0x00008000; + p_HcFrame->hcSpecificData.singleRegForWrite = tmpReg32; + + BUILD_FD(SIZE_OF_HC_FRAME_PROFILE_CNT); + + if ((err = EnQFrm(p_FmHc, &fmFd, seqNum)) != E_OK) + { + PutBuf(p_FmHc, p_HcFrame, seqNum); + RETURN_ERROR(MINOR, err, NO_MSG); + } + + PutBuf(p_FmHc, p_HcFrame, seqNum); + } + } + + return E_OK; +} + +t_Error FmHcPcdPlcrSetProfile(t_Handle h_FmHc, t_Handle h_Profile, t_FmPcdPlcrProfileRegs *p_PlcrRegs) +{ + t_FmHc *p_FmHc = (t_FmHc*)h_FmHc; + t_Error err = E_OK; + uint16_t profileIndx; + t_HcFrame *p_HcFrame; + t_DpaaFD fmFd; + uint32_t seqNum; + + p_HcFrame = GetBuf(p_FmHc, &seqNum); + if (!p_HcFrame) + RETURN_ERROR(MINOR, E_NO_MEMORY, ("HC Frame object")); + + profileIndx = FmPcdPlcrProfileGetAbsoluteId(h_Profile); + + memset(p_HcFrame, 0, sizeof(t_HcFrame)); + p_HcFrame->opcode = (uint32_t)(HC_HCOR_GBL | HC_HCOR_OPCODE_PLCR_PRFL); + p_HcFrame->actionReg = FmPcdPlcrBuildWritePlcrActionRegs(profileIndx); + p_HcFrame->extraReg = 0x00008000; + memcpy(&p_HcFrame->hcSpecificData.profileRegs, p_PlcrRegs, sizeof(t_FmPcdPlcrProfileRegs)); + p_HcFrame->commandSequence = seqNum; + + BUILD_FD(sizeof(t_HcFrame)); + + err = EnQFrm(p_FmHc, &fmFd, seqNum); + + PutBuf(p_FmHc, p_HcFrame, seqNum); + + if (err != E_OK) + RETURN_ERROR(MINOR, err, NO_MSG); + + return E_OK; +} + +t_Error FmHcPcdPlcrDeleteProfile(t_Handle h_FmHc, t_Handle h_Profile) +{ + t_FmHc *p_FmHc = (t_FmHc*)h_FmHc; + uint16_t absoluteProfileId = FmPcdPlcrProfileGetAbsoluteId(h_Profile); + t_Error err = E_OK; + t_HcFrame *p_HcFrame; + t_DpaaFD fmFd; + uint32_t seqNum; + + p_HcFrame = GetBuf(p_FmHc, &seqNum); + if (!p_HcFrame) + RETURN_ERROR(MINOR, E_NO_MEMORY, ("HC Frame object")); + memset(p_HcFrame, 0, sizeof(t_HcFrame)); + p_HcFrame->opcode = (uint32_t)(HC_HCOR_GBL | HC_HCOR_OPCODE_PLCR_PRFL); + p_HcFrame->actionReg = FmPcdPlcrBuildWritePlcrActionReg(absoluteProfileId); + p_HcFrame->actionReg |= 0x00008000; + p_HcFrame->extraReg = 0x00008000; + memset(&p_HcFrame->hcSpecificData.profileRegs, 0, sizeof(t_FmPcdPlcrProfileRegs)); + p_HcFrame->commandSequence = seqNum; + + BUILD_FD(sizeof(t_HcFrame)); + + err = EnQFrm(p_FmHc, &fmFd, seqNum); + + PutBuf(p_FmHc, p_HcFrame, seqNum); + + if (err != E_OK) + RETURN_ERROR(MINOR, err, NO_MSG); + + return E_OK; +} + +t_Error FmHcPcdPlcrSetProfileCounter(t_Handle h_FmHc, t_Handle h_Profile, e_FmPcdPlcrProfileCounters counter, uint32_t value) +{ + + t_FmHc *p_FmHc = (t_FmHc*)h_FmHc; + uint16_t absoluteProfileId = FmPcdPlcrProfileGetAbsoluteId(h_Profile); + t_Error err = E_OK; + t_HcFrame *p_HcFrame; + t_DpaaFD fmFd; + uint32_t seqNum; + + /* first read scheme and check that it is valid */ + p_HcFrame = GetBuf(p_FmHc, &seqNum); + if (!p_HcFrame) + RETURN_ERROR(MINOR, E_NO_MEMORY, ("HC Frame object")); + memset(p_HcFrame, 0, sizeof(t_HcFrame)); + p_HcFrame->opcode = (uint32_t)(HC_HCOR_GBL | HC_HCOR_OPCODE_PLCR_PRFL); + p_HcFrame->actionReg = FmPcdPlcrBuildWritePlcrActionReg(absoluteProfileId); + p_HcFrame->actionReg |= FmPcdPlcrBuildCounterProfileReg(counter); + p_HcFrame->extraReg = 0x00008000; + p_HcFrame->hcSpecificData.singleRegForWrite = value; + p_HcFrame->commandSequence = seqNum; + + BUILD_FD(SIZE_OF_HC_FRAME_PROFILE_CNT); + + err = EnQFrm(p_FmHc, &fmFd, seqNum); + + PutBuf(p_FmHc, p_HcFrame, seqNum); + + if (err != E_OK) + RETURN_ERROR(MINOR, err, NO_MSG); + + return E_OK; +} + +uint32_t FmHcPcdPlcrGetProfileCounter(t_Handle h_FmHc, t_Handle h_Profile, e_FmPcdPlcrProfileCounters counter) +{ + t_FmHc *p_FmHc = (t_FmHc*)h_FmHc; + uint16_t absoluteProfileId = FmPcdPlcrProfileGetAbsoluteId(h_Profile); + t_Error err; + t_HcFrame *p_HcFrame; + t_DpaaFD fmFd; + uint32_t retVal = 0; + uint32_t seqNum; + + SANITY_CHECK_RETURN_VALUE(h_FmHc, E_INVALID_HANDLE,0); + + /* first read scheme and check that it is valid */ + p_HcFrame = GetBuf(p_FmHc, &seqNum); + if (!p_HcFrame) + { + REPORT_ERROR(MINOR, E_NO_MEMORY, ("HC Frame object")); + return 0; + } + memset(p_HcFrame, 0, sizeof(t_HcFrame)); + p_HcFrame->opcode = (uint32_t)(HC_HCOR_GBL | HC_HCOR_OPCODE_PLCR_PRFL); + p_HcFrame->actionReg = FmPcdPlcrBuildReadPlcrActionReg(absoluteProfileId); + p_HcFrame->extraReg = 0x00008000; + p_HcFrame->commandSequence = seqNum; + + BUILD_FD(SIZE_OF_HC_FRAME_READ_OR_CC_DYNAMIC); + + err = EnQFrm(p_FmHc, &fmFd, seqNum); + if (err != E_OK) + { + PutBuf(p_FmHc, p_HcFrame, seqNum); + REPORT_ERROR(MINOR, err, NO_MSG); + return 0; + } + + switch (counter) + { + case e_FM_PCD_PLCR_PROFILE_GREEN_PACKET_TOTAL_COUNTER: + retVal = p_HcFrame->hcSpecificData.profileRegs.fmpl_pegpc; + break; + case e_FM_PCD_PLCR_PROFILE_YELLOW_PACKET_TOTAL_COUNTER: + retVal = p_HcFrame->hcSpecificData.profileRegs.fmpl_peypc; + break; + case e_FM_PCD_PLCR_PROFILE_RED_PACKET_TOTAL_COUNTER: + retVal = p_HcFrame->hcSpecificData.profileRegs.fmpl_perpc; + break; + case e_FM_PCD_PLCR_PROFILE_RECOLOURED_YELLOW_PACKET_TOTAL_COUNTER: + retVal = p_HcFrame->hcSpecificData.profileRegs.fmpl_perypc; + break; + case e_FM_PCD_PLCR_PROFILE_RECOLOURED_RED_PACKET_TOTAL_COUNTER: + retVal = p_HcFrame->hcSpecificData.profileRegs.fmpl_perrpc; + break; + default: + REPORT_ERROR(MAJOR, E_INVALID_SELECTION, NO_MSG); + } + + PutBuf(p_FmHc, p_HcFrame, seqNum); + return retVal; +} + +t_Error FmHcKgWriteSp(t_Handle h_FmHc, uint8_t hardwarePortId, uint32_t spReg, bool add) +{ + t_FmHc *p_FmHc = (t_FmHc*)h_FmHc; + t_HcFrame *p_HcFrame; + t_DpaaFD fmFd; + t_Error err = E_OK; + uint32_t seqNum; + + ASSERT_COND(p_FmHc); + + p_HcFrame = GetBuf(p_FmHc, &seqNum); + if (!p_HcFrame) + RETURN_ERROR(MINOR, E_NO_MEMORY, ("HC Frame object")); + memset(p_HcFrame, 0, sizeof(t_HcFrame)); + /* first read SP register */ + p_HcFrame->opcode = (uint32_t)(HC_HCOR_GBL | HC_HCOR_OPCODE_KG_SCM); + p_HcFrame->actionReg = FmPcdKgBuildReadPortSchemeBindActionReg(hardwarePortId); + p_HcFrame->extraReg = HC_HCOR_KG_SCHEME_REGS_MASK; + p_HcFrame->commandSequence = seqNum; + + BUILD_FD(SIZE_OF_HC_FRAME_PORT_REGS); + + if ((err = EnQFrm(p_FmHc, &fmFd, seqNum)) != E_OK) + { + PutBuf(p_FmHc, p_HcFrame, seqNum); + RETURN_ERROR(MINOR, err, NO_MSG); + } + + /* spReg is the first reg, so we can use it both for read and for write */ + if (add) + p_HcFrame->hcSpecificData.portRegsForRead.spReg |= spReg; + else + p_HcFrame->hcSpecificData.portRegsForRead.spReg &= ~spReg; + + p_HcFrame->actionReg = FmPcdKgBuildWritePortSchemeBindActionReg(hardwarePortId); + + BUILD_FD(sizeof(t_HcFrame)); + + err = EnQFrm(p_FmHc, &fmFd, seqNum); + + PutBuf(p_FmHc, p_HcFrame, seqNum); + + if (err != E_OK) + RETURN_ERROR(MINOR, err, NO_MSG); + + return E_OK; +} + +t_Error FmHcKgWriteCpp(t_Handle h_FmHc, uint8_t hardwarePortId, uint32_t cppReg) +{ + t_FmHc *p_FmHc = (t_FmHc*)h_FmHc; + t_HcFrame *p_HcFrame; + t_DpaaFD fmFd; + t_Error err = E_OK; + uint32_t seqNum; + + ASSERT_COND(p_FmHc); + + p_HcFrame = GetBuf(p_FmHc, &seqNum); + if (!p_HcFrame) + RETURN_ERROR(MINOR, E_NO_MEMORY, ("HC Frame object")); + memset(p_HcFrame, 0, sizeof(t_HcFrame)); + /* first read SP register */ + p_HcFrame->opcode = (uint32_t)(HC_HCOR_GBL | HC_HCOR_OPCODE_KG_SCM); + p_HcFrame->actionReg = FmPcdKgBuildWritePortClsPlanBindActionReg(hardwarePortId); + p_HcFrame->extraReg = HC_HCOR_KG_SCHEME_REGS_MASK; + p_HcFrame->hcSpecificData.singleRegForWrite = cppReg; + p_HcFrame->commandSequence = seqNum; + + BUILD_FD(sizeof(t_HcFrame)); + + err = EnQFrm(p_FmHc, &fmFd, seqNum); + + PutBuf(p_FmHc, p_HcFrame, seqNum); + + if (err != E_OK) + RETURN_ERROR(MINOR, err, NO_MSG); + + return E_OK; +} + +t_Error FmHcPcdCcDoDynamicChange(t_Handle h_FmHc, uint32_t oldAdAddrOffset, uint32_t newAdAddrOffset) +{ + t_FmHc *p_FmHc = (t_FmHc*)h_FmHc; + t_HcFrame *p_HcFrame; + t_DpaaFD fmFd; + t_Error err = E_OK; + uint32_t seqNum; + + SANITY_CHECK_RETURN_ERROR(p_FmHc, E_INVALID_HANDLE); + + p_HcFrame = GetBuf(p_FmHc, &seqNum); + if (!p_HcFrame) + RETURN_ERROR(MINOR, E_NO_MEMORY, ("HC Frame object")); + memset(p_HcFrame, 0, sizeof(t_HcFrame)); + + p_HcFrame->opcode = (uint32_t)(HC_HCOR_GBL | HC_HCOR_OPCODE_CC); + p_HcFrame->actionReg = newAdAddrOffset; + p_HcFrame->actionReg |= 0xc0000000; + p_HcFrame->extraReg = oldAdAddrOffset; + p_HcFrame->commandSequence = seqNum; + + BUILD_FD(SIZE_OF_HC_FRAME_READ_OR_CC_DYNAMIC); + + err = EnQFrm(p_FmHc, &fmFd, seqNum); + + PutBuf(p_FmHc, p_HcFrame, seqNum); + + if (err != E_OK) + RETURN_ERROR(MAJOR, err, NO_MSG); + + return E_OK; +} + +t_Error FmHcPcdSync(t_Handle h_FmHc) +{ + t_FmHc *p_FmHc = (t_FmHc*)h_FmHc; + t_HcFrame *p_HcFrame; + t_DpaaFD fmFd; + t_Error err = E_OK; + uint32_t seqNum; + + ASSERT_COND(p_FmHc); + + p_HcFrame = GetBuf(p_FmHc, &seqNum); + if (!p_HcFrame) + RETURN_ERROR(MINOR, E_NO_MEMORY, ("HC Frame object")); + memset(p_HcFrame, 0, sizeof(t_HcFrame)); + /* first read SP register */ + p_HcFrame->opcode = (uint32_t)(HC_HCOR_GBL | HC_HCOR_OPCODE_SYNC); + p_HcFrame->actionReg = 0; + p_HcFrame->extraReg = 0; + p_HcFrame->commandSequence = seqNum; + + BUILD_FD(sizeof(t_HcFrame)); + + err = EnQFrm(p_FmHc, &fmFd, seqNum); + + PutBuf(p_FmHc, p_HcFrame, seqNum); + + if (err != E_OK) + RETURN_ERROR(MINOR, err, NO_MSG); + + return E_OK; +} + +t_Handle FmHcGetPort(t_Handle h_FmHc) +{ + t_FmHc *p_FmHc = (t_FmHc*)h_FmHc; + return p_FmHc->h_HcPortDev; +} diff --git a/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MAC/Makefile b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MAC/Makefile new file mode 100644 index 000000000000..f6b090daa268 --- /dev/null +++ b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MAC/Makefile @@ -0,0 +1,28 @@ +# +# Makefile for the Freescale Ethernet controllers +# +ccflags-y += -DVERSION=\"\" +# +#Include netcomm SW specific definitions +include $(srctree)/drivers/net/ethernet/freescale/sdk_fman/ncsw_config.mk + +NCSW_FM_INC = $(srctree)/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/inc + +ccflags-y += -I$(NCSW_FM_INC) + +obj-y += fsl-ncsw-MAC.o + +fsl-ncsw-MAC-objs := dtsec.o dtsec_mii_acc.o fm_mac.o tgec.o tgec_mii_acc.o \ + fman_dtsec.o fman_dtsec_mii_acc.o fman_memac.o \ + fman_tgec.o fman_crc32.o + +ifeq ($(CONFIG_FMAN_V3H),y) +fsl-ncsw-MAC-objs += memac.o memac_mii_acc.o fman_memac_mii_acc.o +endif +ifeq ($(CONFIG_FMAN_V3L),y) +fsl-ncsw-MAC-objs += memac.o memac_mii_acc.o fman_memac_mii_acc.o +endif +ifeq ($(CONFIG_FMAN_ARM),y) +fsl-ncsw-MAC-objs += memac.o memac_mii_acc.o fman_memac_mii_acc.o +endif + diff --git a/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MAC/dtsec.c b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MAC/dtsec.c new file mode 100644 index 000000000000..071fa4627f17 --- /dev/null +++ b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MAC/dtsec.c @@ -0,0 +1,1504 @@ +/* + * Copyright 2008-2013 Freescale Semiconductor Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Freescale Semiconductor nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * + * ALTERNATIVELY, this software may be distributed under the terms of the + * GNU General Public License ("GPL") as published by the Free Software + * Foundation, either version 2 of that License or (at your option) any + * later version. + * + * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/****************************************************************************** + @File dtsec.c + + @Description FMan dTSEC driver +*//***************************************************************************/ + +#include "std_ext.h" +#include "error_ext.h" +#include "string_ext.h" +#include "xx_ext.h" +#include "endian_ext.h" +#include "debug_ext.h" +#include "crc_mac_addr_ext.h" + +#include "fm_common.h" +#include "dtsec.h" +#include "fsl_fman_dtsec.h" +#include "fsl_fman_dtsec_mii_acc.h" + +/*****************************************************************************/ +/* Internal routines */ +/*****************************************************************************/ + +static t_Error CheckInitParameters(t_Dtsec *p_Dtsec) +{ + if (ENET_SPEED_FROM_MODE(p_Dtsec->enetMode) >= e_ENET_SPEED_10000) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("Ethernet 1G MAC driver only supports 1G or lower speeds")); + if (p_Dtsec->macId >= FM_MAX_NUM_OF_1G_MACS) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("macId can not be greater than the number of 1G MACs")); + if (p_Dtsec->addr == 0) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("Ethernet MAC Must have a valid MAC Address")); + if ((ENET_SPEED_FROM_MODE(p_Dtsec->enetMode) >= e_ENET_SPEED_1000) && + p_Dtsec->p_DtsecDriverParam->halfdup_on) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("Ethernet MAC 1G can't work in half duplex")); + if (p_Dtsec->p_DtsecDriverParam->halfdup_on && (p_Dtsec->p_DtsecDriverParam)->loopback) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("LoopBack is not supported in halfDuplex mode")); +#ifdef FM_RX_PREAM_4_ERRATA_DTSEC_A001 + if (p_Dtsec->fmMacControllerDriver.fmRevInfo.majorRev <= 6) /* fixed for rev3 */ + if (p_Dtsec->p_DtsecDriverParam->rx_preamble) + RETURN_ERROR(MAJOR, E_NOT_SUPPORTED, ("preambleRxEn")); +#endif /* FM_RX_PREAM_4_ERRATA_DTSEC_A001 */ + if (((p_Dtsec->p_DtsecDriverParam)->tx_preamble || (p_Dtsec->p_DtsecDriverParam)->rx_preamble) &&( (p_Dtsec->p_DtsecDriverParam)->preamble_len != 0x7)) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("Preamble length should be 0x7 bytes")); + if ((p_Dtsec->p_DtsecDriverParam)->halfdup_on && + (p_Dtsec->p_DtsecDriverParam->tx_time_stamp_en || p_Dtsec->p_DtsecDriverParam->rx_time_stamp_en)) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("dTSEC in half duplex mode has to be with 1588 timeStamping diable")); + if ((p_Dtsec->p_DtsecDriverParam)->rx_flow && (p_Dtsec->p_DtsecDriverParam)->rx_ctrl_acc ) + RETURN_ERROR(MAJOR, E_INVALID_STATE, ("Receive control frame are not passed to the system memory so it can not be accept ")); + if ((p_Dtsec->p_DtsecDriverParam)->rx_prepend > MAX_PACKET_ALIGNMENT) + RETURN_ERROR(MAJOR, E_INVALID_STATE, ("packetAlignmentPadding can't be greater than %d ",MAX_PACKET_ALIGNMENT )); + if (((p_Dtsec->p_DtsecDriverParam)->non_back_to_back_ipg1 > MAX_INTER_PACKET_GAP) || + ((p_Dtsec->p_DtsecDriverParam)->non_back_to_back_ipg2 > MAX_INTER_PACKET_GAP) || + ((p_Dtsec->p_DtsecDriverParam)->back_to_back_ipg > MAX_INTER_PACKET_GAP)) + RETURN_ERROR(MAJOR, E_INVALID_STATE, ("Inter packet gap can't be greater than %d ",MAX_INTER_PACKET_GAP )); + if ((p_Dtsec->p_DtsecDriverParam)->halfdup_alt_backoff_val > MAX_INTER_PALTERNATE_BEB) + RETURN_ERROR(MAJOR, E_INVALID_STATE, ("alternateBackoffVal can't be greater than %d ",MAX_INTER_PALTERNATE_BEB )); + if ((p_Dtsec->p_DtsecDriverParam)->halfdup_retransmit > MAX_RETRANSMISSION) + RETURN_ERROR(MAJOR, E_INVALID_STATE, ("maxRetransmission can't be greater than %d ",MAX_RETRANSMISSION )); + if ((p_Dtsec->p_DtsecDriverParam)->halfdup_coll_window > MAX_COLLISION_WINDOW) + RETURN_ERROR(MAJOR, E_INVALID_STATE, ("collisionWindow can't be greater than %d ",MAX_COLLISION_WINDOW )); + + /* If Auto negotiation process is disabled, need to */ + /* Set up the PHY using the MII Management Interface */ + if (p_Dtsec->p_DtsecDriverParam->tbipa > MAX_PHYS) + RETURN_ERROR(MAJOR, E_NOT_IN_RANGE, ("PHY address (should be 0-%d)", MAX_PHYS)); + if (!p_Dtsec->f_Exception) + RETURN_ERROR(MAJOR, E_INVALID_HANDLE, ("uninitialized f_Exception")); + if (!p_Dtsec->f_Event) + RETURN_ERROR(MAJOR, E_INVALID_HANDLE, ("uninitialized f_Event")); + +#ifdef FM_LEN_CHECK_ERRATA_FMAN_SW002 + if (p_Dtsec->p_DtsecDriverParam->rx_len_check) + RETURN_ERROR(MINOR, E_NOT_SUPPORTED, ("LengthCheck!")); +#endif /* FM_LEN_CHECK_ERRATA_FMAN_SW002 */ + + return E_OK; +} + +/* ......................................................................... */ + +static uint32_t GetMacAddrHashCode(uint64_t ethAddr) +{ + uint32_t crc; + + /* CRC calculation */ + GET_MAC_ADDR_CRC(ethAddr, crc); + + crc = GetMirror32(crc); + + return crc; +} + +/* ......................................................................... */ + +static void UpdateStatistics(t_Dtsec *p_Dtsec) +{ + uint32_t car1, car2; + + fman_dtsec_get_clear_carry_regs(p_Dtsec->p_MemMap, &car1, &car2); + + if (car1) + { + if (car1 & CAR1_TR64) + p_Dtsec->internalStatistics.tr64 += VAL22BIT; + if (car1 & CAR1_TR127) + p_Dtsec->internalStatistics.tr127 += VAL22BIT; + if (car1 & CAR1_TR255) + p_Dtsec->internalStatistics.tr255 += VAL22BIT; + if (car1 & CAR1_TR511) + p_Dtsec->internalStatistics.tr511 += VAL22BIT; + if (car1 & CAR1_TRK1) + p_Dtsec->internalStatistics.tr1k += VAL22BIT; + if (car1 & CAR1_TRMAX) + p_Dtsec->internalStatistics.trmax += VAL22BIT; + if (car1 & CAR1_TRMGV) + p_Dtsec->internalStatistics.trmgv += VAL22BIT; + if (car1 & CAR1_RBYT) + p_Dtsec->internalStatistics.rbyt += (uint64_t)VAL32BIT; + if (car1 & CAR1_RPKT) + p_Dtsec->internalStatistics.rpkt += VAL22BIT; + if (car1 & CAR1_RMCA) + p_Dtsec->internalStatistics.rmca += VAL22BIT; + if (car1 & CAR1_RBCA) + p_Dtsec->internalStatistics.rbca += VAL22BIT; + if (car1 & CAR1_RXPF) + p_Dtsec->internalStatistics.rxpf += VAL16BIT; + if (car1 & CAR1_RALN) + p_Dtsec->internalStatistics.raln += VAL16BIT; + if (car1 & CAR1_RFLR) + p_Dtsec->internalStatistics.rflr += VAL16BIT; + if (car1 & CAR1_RCDE) + p_Dtsec->internalStatistics.rcde += VAL16BIT; + if (car1 & CAR1_RCSE) + p_Dtsec->internalStatistics.rcse += VAL16BIT; + if (car1 & CAR1_RUND) + p_Dtsec->internalStatistics.rund += VAL16BIT; + if (car1 & CAR1_ROVR) + p_Dtsec->internalStatistics.rovr += VAL16BIT; + if (car1 & CAR1_RFRG) + p_Dtsec->internalStatistics.rfrg += VAL16BIT; + if (car1 & CAR1_RJBR) + p_Dtsec->internalStatistics.rjbr += VAL16BIT; + if (car1 & CAR1_RDRP) + p_Dtsec->internalStatistics.rdrp += VAL16BIT; + } + if (car2) + { + if (car2 & CAR2_TFCS) + p_Dtsec->internalStatistics.tfcs += VAL12BIT; + if (car2 & CAR2_TBYT) + p_Dtsec->internalStatistics.tbyt += (uint64_t)VAL32BIT; + if (car2 & CAR2_TPKT) + p_Dtsec->internalStatistics.tpkt += VAL22BIT; + if (car2 & CAR2_TMCA) + p_Dtsec->internalStatistics.tmca += VAL22BIT; + if (car2 & CAR2_TBCA) + p_Dtsec->internalStatistics.tbca += VAL22BIT; + if (car2 & CAR2_TXPF) + p_Dtsec->internalStatistics.txpf += VAL16BIT; + if (car2 & CAR2_TDRP) + p_Dtsec->internalStatistics.tdrp += VAL16BIT; + } +} + +/* .............................................................................. */ + +static uint16_t DtsecGetMaxFrameLength(t_Handle h_Dtsec) +{ + t_Dtsec *p_Dtsec = (t_Dtsec *)h_Dtsec; + + SANITY_CHECK_RETURN_VALUE(p_Dtsec, E_INVALID_HANDLE, 0); + SANITY_CHECK_RETURN_VALUE(!p_Dtsec->p_DtsecDriverParam, E_INVALID_STATE, 0); + + return fman_dtsec_get_max_frame_len(p_Dtsec->p_MemMap); +} + +/* .............................................................................. */ + +static void DtsecIsr(t_Handle h_Dtsec) +{ + t_Dtsec *p_Dtsec = (t_Dtsec *)h_Dtsec; + uint32_t event; + struct dtsec_regs *p_DtsecMemMap = p_Dtsec->p_MemMap; + + /* do not handle MDIO events */ + event = fman_dtsec_get_event(p_DtsecMemMap, (uint32_t)(~(DTSEC_IMASK_MMRDEN | DTSEC_IMASK_MMWREN))); + + event &= fman_dtsec_get_interrupt_mask(p_DtsecMemMap); + + fman_dtsec_ack_event(p_DtsecMemMap, event); + + if (event & DTSEC_IMASK_BREN) + p_Dtsec->f_Exception(p_Dtsec->h_App, e_FM_MAC_EX_1G_BAB_RX); + if (event & DTSEC_IMASK_RXCEN) + p_Dtsec->f_Exception(p_Dtsec->h_App, e_FM_MAC_EX_1G_RX_CTL); + if (event & DTSEC_IMASK_MSROEN) + UpdateStatistics(p_Dtsec); + if (event & DTSEC_IMASK_GTSCEN) + p_Dtsec->f_Exception(p_Dtsec->h_App, e_FM_MAC_EX_1G_GRATEFUL_TX_STP_COMPLET); + if (event & DTSEC_IMASK_BTEN) + p_Dtsec->f_Exception(p_Dtsec->h_App, e_FM_MAC_EX_1G_BAB_TX); + if (event & DTSEC_IMASK_TXCEN) + p_Dtsec->f_Exception(p_Dtsec->h_App, e_FM_MAC_EX_1G_TX_CTL); + if (event & DTSEC_IMASK_TXEEN) + p_Dtsec->f_Exception(p_Dtsec->h_App, e_FM_MAC_EX_1G_TX_ERR); + if (event & DTSEC_IMASK_LCEN) + p_Dtsec->f_Exception(p_Dtsec->h_App, e_FM_MAC_EX_1G_LATE_COL); + if (event & DTSEC_IMASK_CRLEN) + p_Dtsec->f_Exception(p_Dtsec->h_App, e_FM_MAC_EX_1G_COL_RET_LMT); + if (event & DTSEC_IMASK_XFUNEN) + { +#ifdef FM_TX_LOCKUP_ERRATA_DTSEC6 + if (p_Dtsec->fmMacControllerDriver.fmRevInfo.majorRev == 2) + { + uint32_t tpkt1, tmpReg1, tpkt2, tmpReg2, i; + /* a. Write 0x00E0_0C00 to DTSEC_ID */ + /* This is a read only regidter */ + + /* b. Read and save the value of TPKT */ + tpkt1 = GET_UINT32(p_DtsecMemMap->tpkt); + + /* c. Read the register at dTSEC address offset 0x32C */ + tmpReg1 = GET_UINT32(*(uint32_t*)((uint8_t*)p_DtsecMemMap + 0x32c)); + + /* d. Compare bits [9:15] to bits [25:31] of the register at address offset 0x32C. */ + if ((tmpReg1 & 0x007F0000) != (tmpReg1 & 0x0000007F)) + { + /* If they are not equal, save the value of this register and wait for at least + * MAXFRM*16 ns */ + XX_UDelay((uint32_t)(MIN(DtsecGetMaxFrameLength(p_Dtsec)*16/1000, 1))); + } + + /* e. Read and save TPKT again and read the register at dTSEC address offset + 0x32C again*/ + tpkt2 = GET_UINT32(p_DtsecMemMap->tpkt); + tmpReg2 = GET_UINT32(*(uint32_t*)((uint8_t*)p_DtsecMemMap + 0x32c)); + + /* f. Compare the value of TPKT saved in step b to value read in step e. Also + compare bits [9:15] of the register at offset 0x32C saved in step d to the value + of bits [9:15] saved in step e. If the two registers values are unchanged, then + the transmit portion of the dTSEC controller is locked up and the user should + proceed to the recover sequence. */ + if ((tpkt1 == tpkt2) && ((tmpReg1 & 0x007F0000) == (tmpReg2 & 0x007F0000))) + { + /* recover sequence */ + + /* a.Write a 1 to RCTRL[GRS]*/ + + WRITE_UINT32(p_DtsecMemMap->rctrl, GET_UINT32(p_DtsecMemMap->rctrl) | RCTRL_GRS); + + /* b.Wait until IEVENT[GRSC]=1, or at least 100 us has elapsed. */ + for (i = 0 ; i < 100 ; i++ ) + { + if (GET_UINT32(p_DtsecMemMap->ievent) & DTSEC_IMASK_GRSCEN) + break; + XX_UDelay(1); + } + if (GET_UINT32(p_DtsecMemMap->ievent) & DTSEC_IMASK_GRSCEN) + WRITE_UINT32(p_DtsecMemMap->ievent, DTSEC_IMASK_GRSCEN); + else + DBG(INFO,("Rx lockup due to dTSEC Tx lockup")); + + /* c.Write a 1 to bit n of FM_RSTC (offset 0x0CC of FPM)*/ + FmResetMac(p_Dtsec->fmMacControllerDriver.h_Fm, e_FM_MAC_1G, p_Dtsec->fmMacControllerDriver.macId); + + /* d.Wait 4 Tx clocks (32 ns) */ + XX_UDelay(1); + + /* e.Write a 0 to bit n of FM_RSTC. */ + /* cleared by FMAN */ + } + } +#endif /* FM_TX_LOCKUP_ERRATA_DTSEC6 */ + + p_Dtsec->f_Exception(p_Dtsec->h_App, e_FM_MAC_EX_1G_TX_FIFO_UNDRN); + } + if (event & DTSEC_IMASK_MAGEN) + p_Dtsec->f_Exception(p_Dtsec->h_App, e_FM_MAC_EX_1G_MAG_PCKT); + if (event & DTSEC_IMASK_GRSCEN) + p_Dtsec->f_Exception(p_Dtsec->h_App, e_FM_MAC_EX_1G_GRATEFUL_RX_STP_COMPLET); + if (event & DTSEC_IMASK_TDPEEN) + p_Dtsec->f_Exception(p_Dtsec->h_App, e_FM_MAC_EX_1G_TX_DATA_ERR); + if (event & DTSEC_IMASK_RDPEEN) + p_Dtsec->f_Exception(p_Dtsec->h_App, e_FM_MAC_EX_1G_RX_DATA_ERR); + + /* - masked interrupts */ + ASSERT_COND(!(event & DTSEC_IMASK_ABRTEN)); + ASSERT_COND(!(event & DTSEC_IMASK_IFERREN)); +} + +static void DtsecMdioIsr(t_Handle h_Dtsec) +{ + t_Dtsec *p_Dtsec = (t_Dtsec *)h_Dtsec; + uint32_t event; + struct dtsec_regs *p_DtsecMemMap = p_Dtsec->p_MemMap; + + event = GET_UINT32(p_DtsecMemMap->ievent); + /* handle only MDIO events */ + event &= (DTSEC_IMASK_MMRDEN | DTSEC_IMASK_MMWREN); + if (event) + { + event &= GET_UINT32(p_DtsecMemMap->imask); + + WRITE_UINT32(p_DtsecMemMap->ievent, event); + + if (event & DTSEC_IMASK_MMRDEN) + p_Dtsec->f_Event(p_Dtsec->h_App, e_FM_MAC_EX_1G_MII_MNG_RD_COMPLET); + if (event & DTSEC_IMASK_MMWREN) + p_Dtsec->f_Event(p_Dtsec->h_App, e_FM_MAC_EX_1G_MII_MNG_WR_COMPLET); + } +} + +static void Dtsec1588Isr(t_Handle h_Dtsec) +{ + t_Dtsec *p_Dtsec = (t_Dtsec *)h_Dtsec; + uint32_t event; + struct dtsec_regs *p_DtsecMemMap = p_Dtsec->p_MemMap; + + if (p_Dtsec->ptpTsuEnabled) + { + event = fman_dtsec_check_and_clear_tmr_event(p_DtsecMemMap); + + if (event) + { + ASSERT_COND(event & TMR_PEVENT_TSRE); + p_Dtsec->f_Exception(p_Dtsec->h_App, e_FM_MAC_EX_1G_1588_TS_RX_ERR); + } + } +} + +/* ........................................................................... */ + +static void FreeInitResources(t_Dtsec *p_Dtsec) +{ + if (p_Dtsec->mdioIrq != NO_IRQ) + { + XX_DisableIntr(p_Dtsec->mdioIrq); + XX_FreeIntr(p_Dtsec->mdioIrq); + } + FmUnregisterIntr(p_Dtsec->fmMacControllerDriver.h_Fm, e_FM_MOD_1G_MAC, p_Dtsec->macId, e_FM_INTR_TYPE_ERR); + FmUnregisterIntr(p_Dtsec->fmMacControllerDriver.h_Fm, e_FM_MOD_1G_MAC, p_Dtsec->macId, e_FM_INTR_TYPE_NORMAL); + + /* release the driver's group hash table */ + FreeHashTable(p_Dtsec->p_MulticastAddrHash); + p_Dtsec->p_MulticastAddrHash = NULL; + + /* release the driver's individual hash table */ + FreeHashTable(p_Dtsec->p_UnicastAddrHash); + p_Dtsec->p_UnicastAddrHash = NULL; +} + +/* ........................................................................... */ + +static t_Error GracefulStop(t_Dtsec *p_Dtsec, e_CommMode mode) +{ + struct dtsec_regs *p_MemMap; + int pollTimeout = 0; + + ASSERT_COND(p_Dtsec); + + p_MemMap = p_Dtsec->p_MemMap; + ASSERT_COND(p_MemMap); + + /* Assert the graceful transmit stop bit */ + if (mode & e_COMM_MODE_RX) + { + fman_dtsec_stop_rx(p_MemMap); + +#ifdef FM_GRS_ERRATA_DTSEC_A002 + if (p_Dtsec->fmMacControllerDriver.fmRevInfo.majorRev == 2) + XX_UDelay(100); +#else /* FM_GRS_ERRATA_DTSEC_A002 */ +#ifdef FM_GTS_AFTER_DROPPED_FRAME_ERRATA_DTSEC_A004839 + XX_UDelay(10); +#endif /* FM_GTS_AFTER_DROPPED_FRAME_ERRATA_DTSEC_A004839 */ +#endif /* FM_GRS_ERRATA_DTSEC_A002 */ + } + + if (mode & e_COMM_MODE_TX) + { +#if defined(FM_GTS_ERRATA_DTSEC_A004) + if (p_Dtsec->fmMacControllerDriver.fmRevInfo.majorRev == 2) + DBG(INFO, ("GTS not supported due to DTSEC_A004 errata.")); +#else /* not defined(FM_GTS_ERRATA_DTSEC_A004) */ + + fman_dtsec_stop_tx(p_MemMap); + +#if defined(FM_GTS_UNDERRUN_ERRATA_DTSEC_A0014) || defined(FM_GTS_AFTER_MAC_ABORTED_FRAME_ERRATA_DTSEC_A0012) + XX_UDelay(10); +#endif /* FM_GTS_UNDERRUN_ERRATA_DTSEC_A0014 || FM_GTS_AFTER_MAC_ABORTED_FRAME_ERRATA_DTSEC_A0012 */ +#endif /* defined(FM_GTS_ERRATA_DTSEC_A004) */ + } + + /* Poll GRSC/GTSC bits in IEVENT register until both are set */ +#if defined(FM_GRS_ERRATA_DTSEC_A002) || defined(FM_GTS_ERRATA_DTSEC_A004) || defined(FM_GTS_AFTER_MAC_ABORTED_FRAME_ERRATA_DTSEC_A0012) || defined(FM_GTS_UNDERRUN_ERRATA_DTSEC_A0014) || defined(FM_GTS_AFTER_DROPPED_FRAME_ERRATA_DTSEC_A004839) + XX_UDelay(10); +#else + while (fman_dtsec_get_event(p_MemMap, DTSEC_IMASK_GRSCEN | DTSEC_IMASK_GTSCEN) != (DTSEC_IMASK_GRSCEN | DTSEC_IMASK_GTSCEN)) + { + if (pollTimeout == 100) + break; + XX_UDelay(1); + pollTimeout++; + } +#endif + + return E_OK; +} + +/* .............................................................................. */ + +static t_Error GracefulRestart(t_Dtsec *p_Dtsec, e_CommMode mode) +{ + struct dtsec_regs *p_MemMap; + + ASSERT_COND(p_Dtsec); + p_MemMap = p_Dtsec->p_MemMap; + ASSERT_COND(p_MemMap); + + /* clear the graceful receive stop bit */ + if (mode & e_COMM_MODE_TX) + fman_dtsec_start_tx(p_MemMap); + + if (mode & e_COMM_MODE_RX) + fman_dtsec_start_rx(p_MemMap); + + return E_OK; +} + + +/*****************************************************************************/ +/* dTSEC Configs modification functions */ +/*****************************************************************************/ + +/* .............................................................................. */ + +static t_Error DtsecConfigLoopback(t_Handle h_Dtsec, bool newVal) +{ + + t_Dtsec *p_Dtsec = (t_Dtsec *)h_Dtsec; + + SANITY_CHECK_RETURN_ERROR(p_Dtsec, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_Dtsec->p_DtsecDriverParam, E_INVALID_STATE); + + p_Dtsec->p_DtsecDriverParam->loopback = newVal; + + return E_OK; +} + +/* .............................................................................. */ + +static t_Error DtsecConfigMaxFrameLength(t_Handle h_Dtsec, uint16_t newVal) +{ + t_Dtsec *p_Dtsec = (t_Dtsec *)h_Dtsec; + + SANITY_CHECK_RETURN_ERROR(p_Dtsec, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_Dtsec->p_DtsecDriverParam, E_INVALID_STATE); + + p_Dtsec->p_DtsecDriverParam->maximum_frame = newVal; + + return E_OK; +} + +/* .............................................................................. */ + +static t_Error DtsecConfigPadAndCrc(t_Handle h_Dtsec, bool newVal) +{ + t_Dtsec *p_Dtsec = (t_Dtsec *)h_Dtsec; + + SANITY_CHECK_RETURN_ERROR(p_Dtsec, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_Dtsec->p_DtsecDriverParam, E_INVALID_STATE); + + p_Dtsec->p_DtsecDriverParam->tx_pad_crc = newVal; + + return E_OK; +} + +/* .............................................................................. */ + +static t_Error DtsecConfigHalfDuplex(t_Handle h_Dtsec, bool newVal) +{ + t_Dtsec *p_Dtsec = (t_Dtsec *)h_Dtsec; + + SANITY_CHECK_RETURN_ERROR(p_Dtsec, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_Dtsec->p_DtsecDriverParam, E_INVALID_STATE); + + p_Dtsec->p_DtsecDriverParam->halfdup_on = newVal; + + return E_OK; +} + +/* .............................................................................. */ + +static t_Error DtsecConfigTbiPhyAddr(t_Handle h_Dtsec, uint8_t newVal) +{ + t_Dtsec *p_Dtsec = (t_Dtsec *)h_Dtsec; + + SANITY_CHECK_RETURN_ERROR(p_Dtsec, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_Dtsec->p_DtsecDriverParam, E_INVALID_STATE); + + p_Dtsec->p_DtsecDriverParam->tbi_phy_addr = newVal; + + return E_OK; +} + +/* .............................................................................. */ + +static t_Error DtsecConfigLengthCheck(t_Handle h_Dtsec, bool newVal) +{ + t_Dtsec *p_Dtsec = (t_Dtsec *)h_Dtsec; + + SANITY_CHECK_RETURN_ERROR(p_Dtsec, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_Dtsec->p_DtsecDriverParam, E_INVALID_STATE); + + p_Dtsec->p_DtsecDriverParam->rx_len_check = newVal; + + return E_OK; +} + +/* .............................................................................. */ + +static t_Error DtsecConfigException(t_Handle h_Dtsec, e_FmMacExceptions exception, bool enable) +{ + t_Dtsec *p_Dtsec = (t_Dtsec *)h_Dtsec; + uint32_t bitMask = 0; + + SANITY_CHECK_RETURN_ERROR(p_Dtsec, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_Dtsec->p_DtsecDriverParam, E_INVALID_STATE); + + if (exception != e_FM_MAC_EX_1G_1588_TS_RX_ERR) + { + GET_EXCEPTION_FLAG(bitMask, exception); + if (bitMask) + { + if (enable) + p_Dtsec->exceptions |= bitMask; + else + p_Dtsec->exceptions &= ~bitMask; + } + else + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("Undefined exception")); + } + else + { + if (!p_Dtsec->ptpTsuEnabled) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("Exception valid for 1588 only")); + + if (enable) + p_Dtsec->enTsuErrExeption = TRUE; + else + p_Dtsec->enTsuErrExeption = FALSE; + } + + return E_OK; +} + + +/*****************************************************************************/ +/* dTSEC Run Time API functions */ +/*****************************************************************************/ + +/* .............................................................................. */ + +static t_Error DtsecEnable(t_Handle h_Dtsec, e_CommMode mode) +{ + t_Dtsec *p_Dtsec = (t_Dtsec *)h_Dtsec; + + SANITY_CHECK_RETURN_ERROR(p_Dtsec, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(!p_Dtsec->p_DtsecDriverParam, E_INVALID_STATE); + + fman_dtsec_enable(p_Dtsec->p_MemMap, + (bool)!!(mode & e_COMM_MODE_RX), + (bool)!!(mode & e_COMM_MODE_TX)); + + GracefulRestart(p_Dtsec, mode); + + return E_OK; +} + +/* .............................................................................. */ + +static t_Error DtsecDisable (t_Handle h_Dtsec, e_CommMode mode) +{ + t_Dtsec *p_Dtsec = (t_Dtsec *)h_Dtsec; + + SANITY_CHECK_RETURN_ERROR(p_Dtsec, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(!p_Dtsec->p_DtsecDriverParam, E_INVALID_STATE); + + GracefulStop(p_Dtsec, mode); + + fman_dtsec_disable(p_Dtsec->p_MemMap, + (bool)!!(mode & e_COMM_MODE_RX), + (bool)!!(mode & e_COMM_MODE_TX)); + + return E_OK; +} + +/* .............................................................................. */ + +static t_Error DtsecSetTxPauseFrames(t_Handle h_Dtsec, + uint8_t priority, + uint16_t pauseTime, + uint16_t threshTime) +{ + t_Dtsec *p_Dtsec = (t_Dtsec *)h_Dtsec; + + UNUSED(priority);UNUSED(threshTime); + + SANITY_CHECK_RETURN_ERROR(p_Dtsec, E_INVALID_STATE); + SANITY_CHECK_RETURN_ERROR(!p_Dtsec->p_DtsecDriverParam, E_INVALID_STATE); + +#ifdef FM_BAD_TX_TS_IN_B_2_B_ERRATA_DTSEC_A003 + if (p_Dtsec->fmMacControllerDriver.fmRevInfo.majorRev == 2) + if (0 < pauseTime && pauseTime <= 320) + RETURN_ERROR(MINOR, E_INVALID_VALUE, + ("This pause-time value of %d is illegal due to errata dTSEC-A003!" + " value should be greater than 320.")); +#endif /* FM_BAD_TX_TS_IN_B_2_B_ERRATA_DTSEC_A003 */ + + GracefulStop(p_Dtsec, e_COMM_MODE_RX_AND_TX); + + fman_dtsec_set_tx_pause_frames(p_Dtsec->p_MemMap, pauseTime); + + GracefulRestart(p_Dtsec, e_COMM_MODE_RX_AND_TX); + + return E_OK; +} + +/* .............................................................................. */ +/* backward compatibility. will be removed in the future. */ +static t_Error DtsecTxMacPause(t_Handle h_Dtsec, uint16_t pauseTime) +{ + return DtsecSetTxPauseFrames(h_Dtsec, 0, pauseTime, 0); +} + +/* .............................................................................. */ + +static t_Error DtsecRxIgnoreMacPause(t_Handle h_Dtsec, bool en) +{ + t_Dtsec *p_Dtsec = (t_Dtsec *)h_Dtsec; + bool accept_pause = !en; + + SANITY_CHECK_RETURN_ERROR(p_Dtsec, E_INVALID_STATE); + SANITY_CHECK_RETURN_ERROR(!p_Dtsec->p_DtsecDriverParam, E_INVALID_STATE); + + GracefulStop(p_Dtsec, e_COMM_MODE_RX_AND_TX); + + fman_dtsec_handle_rx_pause(p_Dtsec->p_MemMap, accept_pause); + + GracefulRestart(p_Dtsec, e_COMM_MODE_RX_AND_TX); + + return E_OK; +} + +/* .............................................................................. */ + +static t_Error DtsecEnable1588TimeStamp(t_Handle h_Dtsec) +{ + t_Dtsec *p_Dtsec = (t_Dtsec *)h_Dtsec; + + SANITY_CHECK_RETURN_ERROR(p_Dtsec, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(!p_Dtsec->p_DtsecDriverParam, E_INVALID_STATE); + + p_Dtsec->ptpTsuEnabled = TRUE; + fman_dtsec_set_ts(p_Dtsec->p_MemMap, TRUE); + + return E_OK; +} + +/* .............................................................................. */ + +static t_Error DtsecDisable1588TimeStamp(t_Handle h_Dtsec) +{ + t_Dtsec *p_Dtsec = (t_Dtsec *)h_Dtsec; + + SANITY_CHECK_RETURN_ERROR(p_Dtsec, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(!p_Dtsec->p_DtsecDriverParam, E_INVALID_STATE); + + p_Dtsec->ptpTsuEnabled = FALSE; + fman_dtsec_set_ts(p_Dtsec->p_MemMap, FALSE); + + return E_OK; +} + +/* .............................................................................. */ + +static t_Error DtsecGetStatistics(t_Handle h_Dtsec, t_FmMacStatistics *p_Statistics) +{ + t_Dtsec *p_Dtsec = (t_Dtsec *)h_Dtsec; + struct dtsec_regs *p_DtsecMemMap; + + SANITY_CHECK_RETURN_ERROR(p_Dtsec, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(!p_Dtsec->p_DtsecDriverParam, E_INVALID_STATE); + SANITY_CHECK_RETURN_ERROR(p_Statistics, E_NULL_POINTER); + + p_DtsecMemMap = p_Dtsec->p_MemMap; + + if (p_Dtsec->statisticsLevel == e_FM_MAC_NONE_STATISTICS) + RETURN_ERROR(MINOR, E_INVALID_STATE, ("Statistics disabled")); + + memset(p_Statistics, 0xff, sizeof(t_FmMacStatistics)); + + if (p_Dtsec->statisticsLevel == e_FM_MAC_FULL_STATISTICS) + { + p_Statistics->eStatPkts64 = fman_dtsec_get_stat_counter(p_DtsecMemMap, E_DTSEC_STAT_TR64) + + p_Dtsec->internalStatistics.tr64; + p_Statistics->eStatPkts65to127 = fman_dtsec_get_stat_counter(p_DtsecMemMap, E_DTSEC_STAT_TR127) + + p_Dtsec->internalStatistics.tr127; + p_Statistics->eStatPkts128to255 = fman_dtsec_get_stat_counter(p_DtsecMemMap, E_DTSEC_STAT_TR255) + + p_Dtsec->internalStatistics.tr255; + p_Statistics->eStatPkts256to511 = fman_dtsec_get_stat_counter(p_DtsecMemMap, E_DTSEC_STAT_TR511) + + p_Dtsec->internalStatistics.tr511; + p_Statistics->eStatPkts512to1023 = fman_dtsec_get_stat_counter(p_DtsecMemMap, E_DTSEC_STAT_TR1K) + + p_Dtsec->internalStatistics.tr1k; + p_Statistics->eStatPkts1024to1518 = fman_dtsec_get_stat_counter(p_DtsecMemMap, E_DTSEC_STAT_TRMAX) + + p_Dtsec->internalStatistics.trmax; + p_Statistics->eStatPkts1519to1522 = fman_dtsec_get_stat_counter(p_DtsecMemMap, E_DTSEC_STAT_TRMGV) + + p_Dtsec->internalStatistics.trmgv; + + /* MIB II */ + p_Statistics->ifInOctets = fman_dtsec_get_stat_counter(p_DtsecMemMap, E_DTSEC_STAT_RBYT) + + p_Dtsec->internalStatistics.rbyt; + p_Statistics->ifInPkts = fman_dtsec_get_stat_counter(p_DtsecMemMap, E_DTSEC_STAT_RPKT) + + p_Dtsec->internalStatistics.rpkt; + p_Statistics->ifInUcastPkts = 0; + p_Statistics->ifInMcastPkts = fman_dtsec_get_stat_counter(p_DtsecMemMap, E_DTSEC_STAT_RMCA) + + p_Dtsec->internalStatistics.rmca; + p_Statistics->ifInBcastPkts = fman_dtsec_get_stat_counter(p_DtsecMemMap, E_DTSEC_STAT_RBCA) + + p_Dtsec->internalStatistics.rbca; + p_Statistics->ifOutOctets = fman_dtsec_get_stat_counter(p_DtsecMemMap, E_DTSEC_STAT_TBYT) + + p_Dtsec->internalStatistics.tbyt; + p_Statistics->ifOutPkts = fman_dtsec_get_stat_counter(p_DtsecMemMap, E_DTSEC_STAT_TPKT) + + p_Dtsec->internalStatistics.tpkt; + p_Statistics->ifOutUcastPkts = 0; + p_Statistics->ifOutMcastPkts = fman_dtsec_get_stat_counter(p_DtsecMemMap, E_DTSEC_STAT_TMCA) + + p_Dtsec->internalStatistics.tmca; + p_Statistics->ifOutBcastPkts = fman_dtsec_get_stat_counter(p_DtsecMemMap, E_DTSEC_STAT_TBCA) + + p_Dtsec->internalStatistics.tbca; + } + + p_Statistics->eStatFragments = fman_dtsec_get_stat_counter(p_DtsecMemMap, E_DTSEC_STAT_RFRG) + + p_Dtsec->internalStatistics.rfrg; + p_Statistics->eStatJabbers = fman_dtsec_get_stat_counter(p_DtsecMemMap, E_DTSEC_STAT_RJBR) + + p_Dtsec->internalStatistics.rjbr; + p_Statistics->eStatsDropEvents = fman_dtsec_get_stat_counter(p_DtsecMemMap, E_DTSEC_STAT_RDRP) + + p_Dtsec->internalStatistics.rdrp; + p_Statistics->eStatCRCAlignErrors = fman_dtsec_get_stat_counter(p_DtsecMemMap, E_DTSEC_STAT_RALN) + + p_Dtsec->internalStatistics.raln; + p_Statistics->eStatUndersizePkts = fman_dtsec_get_stat_counter(p_DtsecMemMap, E_DTSEC_STAT_RUND) + + p_Dtsec->internalStatistics.rund; + p_Statistics->eStatOversizePkts = fman_dtsec_get_stat_counter(p_DtsecMemMap, E_DTSEC_STAT_ROVR) + + p_Dtsec->internalStatistics.rovr; + p_Statistics->reStatPause = fman_dtsec_get_stat_counter(p_DtsecMemMap, E_DTSEC_STAT_RXPF) + + p_Dtsec->internalStatistics.rxpf; + p_Statistics->teStatPause = fman_dtsec_get_stat_counter(p_DtsecMemMap, E_DTSEC_STAT_TXPF) + + p_Dtsec->internalStatistics.txpf; + p_Statistics->ifInDiscards = p_Statistics->eStatsDropEvents; + p_Statistics->ifInErrors = p_Statistics->eStatsDropEvents + p_Statistics->eStatCRCAlignErrors + + fman_dtsec_get_stat_counter(p_DtsecMemMap,E_DTSEC_STAT_RFLR) + p_Dtsec->internalStatistics.rflr + + fman_dtsec_get_stat_counter(p_DtsecMemMap,E_DTSEC_STAT_RCDE) + p_Dtsec->internalStatistics.rcde + + fman_dtsec_get_stat_counter(p_DtsecMemMap,E_DTSEC_STAT_RCSE) + p_Dtsec->internalStatistics.rcse; + + p_Statistics->ifOutDiscards = fman_dtsec_get_stat_counter(p_DtsecMemMap, E_DTSEC_STAT_TDRP) + + p_Dtsec->internalStatistics.tdrp; + p_Statistics->ifOutErrors = p_Statistics->ifOutDiscards /**< Number of frames transmitted with error: */ + + fman_dtsec_get_stat_counter(p_DtsecMemMap,E_DTSEC_STAT_TFCS) + + p_Dtsec->internalStatistics.tfcs; + + return E_OK; +} + +/* .............................................................................. */ + +static t_Error DtsecModifyMacAddress (t_Handle h_Dtsec, t_EnetAddr *p_EnetAddr) +{ + t_Dtsec *p_Dtsec = (t_Dtsec *)h_Dtsec; + + SANITY_CHECK_RETURN_ERROR(p_Dtsec, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(!p_Dtsec->p_DtsecDriverParam, E_INVALID_STATE); + + /* Initialize MAC Station Address registers (1 & 2) */ + /* Station address have to be swapped (big endian to little endian */ + p_Dtsec->addr = ENET_ADDR_TO_UINT64(*p_EnetAddr); + + GracefulStop(p_Dtsec, e_COMM_MODE_RX_AND_TX); + + fman_dtsec_set_mac_address(p_Dtsec->p_MemMap, (uint8_t *)(*p_EnetAddr)); + + GracefulRestart(p_Dtsec, e_COMM_MODE_RX_AND_TX); + + return E_OK; +} + +/* .............................................................................. */ + +static t_Error DtsecResetCounters (t_Handle h_Dtsec) +{ + t_Dtsec *p_Dtsec = (t_Dtsec *)h_Dtsec; + + SANITY_CHECK_RETURN_ERROR(p_Dtsec, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(!p_Dtsec->p_DtsecDriverParam, E_INVALID_STATE); + + /* clear HW counters */ + fman_dtsec_reset_stat(p_Dtsec->p_MemMap); + + /* clear SW counters holding carries */ + memset(&p_Dtsec->internalStatistics, 0, sizeof(t_InternalStatistics)); + + return E_OK; +} + +/* .............................................................................. */ + +static t_Error DtsecAddExactMatchMacAddress(t_Handle h_Dtsec, t_EnetAddr *p_EthAddr) +{ + t_Dtsec *p_Dtsec = (t_Dtsec *) h_Dtsec; + uint64_t ethAddr; + uint8_t paddrNum; + + SANITY_CHECK_RETURN_ERROR(p_Dtsec, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(!p_Dtsec->p_DtsecDriverParam, E_INVALID_STATE); + + ethAddr = ENET_ADDR_TO_UINT64(*p_EthAddr); + + if (ethAddr & GROUP_ADDRESS) + /* Multicast address has no effect in PADDR */ + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("Multicast address")); + + /* Make sure no PADDR contains this address */ + for (paddrNum = 0; paddrNum < DTSEC_NUM_OF_PADDRS; paddrNum++) + if (p_Dtsec->indAddrRegUsed[paddrNum]) + if (p_Dtsec->paddr[paddrNum] == ethAddr) + RETURN_ERROR(MAJOR, E_ALREADY_EXISTS, NO_MSG); + + /* Find first unused PADDR */ + for (paddrNum = 0; paddrNum < DTSEC_NUM_OF_PADDRS; paddrNum++) + if (!(p_Dtsec->indAddrRegUsed[paddrNum])) + { + /* mark this PADDR as used */ + p_Dtsec->indAddrRegUsed[paddrNum] = TRUE; + /* store address */ + p_Dtsec->paddr[paddrNum] = ethAddr; + + /* put in hardware */ + fman_dtsec_add_addr_in_paddr(p_Dtsec->p_MemMap, (uint64_t)PTR_TO_UINT(ðAddr), paddrNum); + p_Dtsec->numOfIndAddrInRegs++; + + return E_OK; + } + + /* No free PADDR */ + RETURN_ERROR(MAJOR, E_FULL, NO_MSG); +} + +/* .............................................................................. */ + +static t_Error DtsecDelExactMatchMacAddress(t_Handle h_Dtsec, t_EnetAddr *p_EthAddr) +{ + t_Dtsec *p_Dtsec = (t_Dtsec *) h_Dtsec; + uint64_t ethAddr; + uint8_t paddrNum; + + SANITY_CHECK_RETURN_ERROR(p_Dtsec, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(!p_Dtsec->p_DtsecDriverParam, E_INVALID_STATE); + + ethAddr = ENET_ADDR_TO_UINT64(*p_EthAddr); + + /* Find used PADDR containing this address */ + for (paddrNum = 0; paddrNum < DTSEC_NUM_OF_PADDRS; paddrNum++) + { + if ((p_Dtsec->indAddrRegUsed[paddrNum]) && + (p_Dtsec->paddr[paddrNum] == ethAddr)) + { + /* mark this PADDR as not used */ + p_Dtsec->indAddrRegUsed[paddrNum] = FALSE; + /* clear in hardware */ + fman_dtsec_clear_addr_in_paddr(p_Dtsec->p_MemMap, paddrNum); + p_Dtsec->numOfIndAddrInRegs--; + + return E_OK; + } + } + + RETURN_ERROR(MAJOR, E_NOT_FOUND, NO_MSG); +} + +/* .............................................................................. */ + +static t_Error DtsecAddHashMacAddress(t_Handle h_Dtsec, t_EnetAddr *p_EthAddr) +{ + t_Dtsec *p_Dtsec = (t_Dtsec *)h_Dtsec; + t_EthHashEntry *p_HashEntry; + uint64_t ethAddr; + int32_t bucket; + uint32_t crc; + bool mcast, ghtx; + + SANITY_CHECK_RETURN_ERROR(p_Dtsec, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(!p_Dtsec->p_DtsecDriverParam, E_INVALID_STATE); + + ethAddr = ENET_ADDR_TO_UINT64(*p_EthAddr); + + ghtx = (bool)((fman_dtsec_get_rctrl(p_Dtsec->p_MemMap) & RCTRL_GHTX) ? TRUE : FALSE); + mcast = (bool)((ethAddr & MAC_GROUP_ADDRESS) ? TRUE : FALSE); + + if (ghtx && !mcast) /* Cannot handle unicast mac addr when GHTX is on */ + RETURN_ERROR(MAJOR, E_INVALID_STATE, ("Could not compute hash bucket")); + + crc = GetMacAddrHashCode(ethAddr); + + /* considering the 9 highest order bits in crc H[8:0]: + * if ghtx = 0 H[8:6] (highest order 3 bits) identify the hash register + * and H[5:1] (next 5 bits) identify the hash bit + * if ghts = 1 H[8:5] (highest order 4 bits) identify the hash register + * and H[4:0] (next 5 bits) identify the hash bit. + * + * In bucket index output the low 5 bits identify the hash register bit, + * while the higher 4 bits identify the hash register + */ + + if (ghtx) + bucket = (int32_t)((crc >> 23) & 0x1ff); + else { + bucket = (int32_t)((crc >> 24) & 0xff); + /* if !ghtx and mcast the bit must be set in gaddr instead of igaddr. */ + if (mcast) + bucket += 0x100; + } + + fman_dtsec_set_bucket(p_Dtsec->p_MemMap, bucket, TRUE); + + /* Create element to be added to the driver hash table */ + p_HashEntry = (t_EthHashEntry *)XX_Malloc(sizeof(t_EthHashEntry)); + p_HashEntry->addr = ethAddr; + INIT_LIST(&p_HashEntry->node); + + if (ethAddr & MAC_GROUP_ADDRESS) + /* Group Address */ + LIST_AddToTail(&(p_HashEntry->node), &(p_Dtsec->p_MulticastAddrHash->p_Lsts[bucket])); + else + LIST_AddToTail(&(p_HashEntry->node), &(p_Dtsec->p_UnicastAddrHash->p_Lsts[bucket])); + + return E_OK; +} + +/* .............................................................................. */ + +static t_Error DtsecDelHashMacAddress(t_Handle h_Dtsec, t_EnetAddr *p_EthAddr) +{ + t_Dtsec *p_Dtsec = (t_Dtsec *)h_Dtsec; + t_List *p_Pos; + t_EthHashEntry *p_HashEntry = NULL; + uint64_t ethAddr; + int32_t bucket; + uint32_t crc; + bool mcast, ghtx; + + SANITY_CHECK_RETURN_ERROR(p_Dtsec, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(!p_Dtsec->p_DtsecDriverParam, E_INVALID_STATE); + + ethAddr = ENET_ADDR_TO_UINT64(*p_EthAddr); + + ghtx = (bool)((fman_dtsec_get_rctrl(p_Dtsec->p_MemMap) & RCTRL_GHTX) ? TRUE : FALSE); + mcast = (bool)((ethAddr & MAC_GROUP_ADDRESS) ? TRUE : FALSE); + + if (ghtx && !mcast) /* Cannot handle unicast mac addr when GHTX is on */ + RETURN_ERROR(MAJOR, E_INVALID_STATE, ("Could not compute hash bucket")); + + crc = GetMacAddrHashCode(ethAddr); + + if (ghtx) + bucket = (int32_t)((crc >> 23) & 0x1ff); + else { + bucket = (int32_t)((crc >> 24) & 0xff); + /* if !ghtx and mcast the bit must be set in gaddr instead of igaddr. */ + if (mcast) + bucket += 0x100; + } + + if (ethAddr & MAC_GROUP_ADDRESS) + { + /* Group Address */ + LIST_FOR_EACH(p_Pos, &(p_Dtsec->p_MulticastAddrHash->p_Lsts[bucket])) + { + p_HashEntry = ETH_HASH_ENTRY_OBJ(p_Pos); + if (p_HashEntry->addr == ethAddr) + { + LIST_DelAndInit(&p_HashEntry->node); + XX_Free(p_HashEntry); + break; + } + } + if (LIST_IsEmpty(&p_Dtsec->p_MulticastAddrHash->p_Lsts[bucket])) + fman_dtsec_set_bucket(p_Dtsec->p_MemMap, bucket, FALSE); + } + else + { + /* Individual Address */ + LIST_FOR_EACH(p_Pos, &(p_Dtsec->p_UnicastAddrHash->p_Lsts[bucket])) + { + p_HashEntry = ETH_HASH_ENTRY_OBJ(p_Pos); + if (p_HashEntry->addr == ethAddr) + { + LIST_DelAndInit(&p_HashEntry->node); + XX_Free(p_HashEntry); + break; + } + } + if (LIST_IsEmpty(&p_Dtsec->p_UnicastAddrHash->p_Lsts[bucket])) + fman_dtsec_set_bucket(p_Dtsec->p_MemMap, bucket, FALSE); + } + + /* address does not exist */ + ASSERT_COND(p_HashEntry != NULL); + + return E_OK; +} + +/* .............................................................................. */ + +static t_Error DtsecSetPromiscuous(t_Handle h_Dtsec, bool newVal) +{ + t_Dtsec *p_Dtsec = (t_Dtsec *)h_Dtsec; + + SANITY_CHECK_RETURN_ERROR(p_Dtsec, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(!p_Dtsec->p_DtsecDriverParam, E_INVALID_STATE); + + fman_dtsec_set_uc_promisc(p_Dtsec->p_MemMap, newVal); + fman_dtsec_set_mc_promisc(p_Dtsec->p_MemMap, newVal); + + return E_OK; +} + +/* .............................................................................. */ + +static t_Error DtsecSetStatistics(t_Handle h_Dtsec, e_FmMacStatisticsLevel statisticsLevel) +{ + t_Dtsec *p_Dtsec = (t_Dtsec *)h_Dtsec; + t_Error err; + + SANITY_CHECK_RETURN_ERROR(p_Dtsec, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(!p_Dtsec->p_DtsecDriverParam, E_INVALID_STATE); + + p_Dtsec->statisticsLevel = statisticsLevel; + + err = (t_Error)fman_dtsec_set_stat_level(p_Dtsec->p_MemMap, + (enum dtsec_stat_level)statisticsLevel); + if (err != E_OK) + return err; + + switch (statisticsLevel) + { + case (e_FM_MAC_NONE_STATISTICS): + p_Dtsec->exceptions &= ~DTSEC_IMASK_MSROEN; + break; + case (e_FM_MAC_PARTIAL_STATISTICS): + p_Dtsec->exceptions |= DTSEC_IMASK_MSROEN; + break; + case (e_FM_MAC_FULL_STATISTICS): + p_Dtsec->exceptions |= DTSEC_IMASK_MSROEN; + break; + default: + RETURN_ERROR(MINOR, E_INVALID_SELECTION, NO_MSG); + } + + return E_OK; +} + +/* .............................................................................. */ + +static t_Error DtsecSetWakeOnLan(t_Handle h_Dtsec, bool en) +{ + t_Dtsec *p_Dtsec = (t_Dtsec *)h_Dtsec; + + SANITY_CHECK_RETURN_ERROR(p_Dtsec, E_INVALID_STATE); + SANITY_CHECK_RETURN_ERROR(!p_Dtsec->p_DtsecDriverParam, E_INVALID_STATE); + + GracefulStop(p_Dtsec, e_COMM_MODE_RX_AND_TX); + + fman_dtsec_set_wol(p_Dtsec->p_MemMap, en); + + GracefulRestart(p_Dtsec, e_COMM_MODE_RX_AND_TX); + + return E_OK; +} + +/* .............................................................................. */ + +static t_Error DtsecAdjustLink(t_Handle h_Dtsec, e_EnetSpeed speed, bool fullDuplex) +{ + t_Dtsec *p_Dtsec = (t_Dtsec *)h_Dtsec; + int err; + enum enet_interface enet_interface; + enum enet_speed enet_speed; + + SANITY_CHECK_RETURN_ERROR(p_Dtsec, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(!p_Dtsec->p_DtsecDriverParam, E_INVALID_STATE); + + p_Dtsec->enetMode = MAKE_ENET_MODE(ENET_INTERFACE_FROM_MODE(p_Dtsec->enetMode), speed); + enet_interface = (enum enet_interface) ENET_INTERFACE_FROM_MODE(p_Dtsec->enetMode); + enet_speed = (enum enet_speed) ENET_SPEED_FROM_MODE(p_Dtsec->enetMode); + p_Dtsec->halfDuplex = !fullDuplex; + + GracefulStop(p_Dtsec, e_COMM_MODE_RX_AND_TX); + + err = fman_dtsec_adjust_link(p_Dtsec->p_MemMap, enet_interface, enet_speed, fullDuplex); + + if (err == -EINVAL) + RETURN_ERROR(MAJOR, E_CONFLICT, ("Ethernet interface does not support Half Duplex mode")); + + GracefulRestart(p_Dtsec, e_COMM_MODE_RX_AND_TX); + + return (t_Error)err; +} + +/* .............................................................................. */ + +static t_Error DtsecRestartAutoneg(t_Handle h_Dtsec) +{ + t_Dtsec *p_Dtsec = (t_Dtsec *)h_Dtsec; + uint16_t tmpReg16; + + SANITY_CHECK_RETURN_ERROR(p_Dtsec, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(!p_Dtsec->p_DtsecDriverParam, E_INVALID_STATE); + + DTSEC_MII_ReadPhyReg(p_Dtsec, p_Dtsec->tbi_phy_addr, 0, &tmpReg16); + + tmpReg16 &= ~( PHY_CR_SPEED0 | PHY_CR_SPEED1 ); + tmpReg16 |= (PHY_CR_ANE | PHY_CR_RESET_AN | PHY_CR_FULLDUPLEX | PHY_CR_SPEED1); + + DTSEC_MII_WritePhyReg(p_Dtsec, p_Dtsec->tbi_phy_addr, 0, tmpReg16); + + return E_OK; +} + +/* .............................................................................. */ + +static t_Error DtsecGetId(t_Handle h_Dtsec, uint32_t *macId) +{ + t_Dtsec *p_Dtsec = (t_Dtsec *)h_Dtsec; + + SANITY_CHECK_RETURN_ERROR(p_Dtsec, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(!p_Dtsec->p_DtsecDriverParam, E_INVALID_STATE); + + *macId = p_Dtsec->macId; + + return E_OK; +} + +/* .............................................................................. */ + +static t_Error DtsecGetVersion(t_Handle h_Dtsec, uint32_t *macVersion) +{ + t_Dtsec *p_Dtsec = (t_Dtsec *)h_Dtsec; + + SANITY_CHECK_RETURN_ERROR(p_Dtsec, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(!p_Dtsec->p_DtsecDriverParam, E_INVALID_STATE); + + *macVersion = fman_dtsec_get_revision(p_Dtsec->p_MemMap); + + return E_OK; +} + +/* .............................................................................. */ + +static t_Error DtsecSetException(t_Handle h_Dtsec, e_FmMacExceptions exception, bool enable) +{ + t_Dtsec *p_Dtsec = (t_Dtsec *)h_Dtsec; + uint32_t bitMask = 0; + + SANITY_CHECK_RETURN_ERROR(p_Dtsec, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(!p_Dtsec->p_DtsecDriverParam, E_INVALID_STATE); + + if (exception != e_FM_MAC_EX_1G_1588_TS_RX_ERR) + { + GET_EXCEPTION_FLAG(bitMask, exception); + if (bitMask) + { + if (enable) + p_Dtsec->exceptions |= bitMask; + else + p_Dtsec->exceptions &= ~bitMask; + } + else + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("Undefined exception")); + + if (enable) + fman_dtsec_enable_interrupt(p_Dtsec->p_MemMap, bitMask); + else + fman_dtsec_disable_interrupt(p_Dtsec->p_MemMap, bitMask); + } + else + { + if (!p_Dtsec->ptpTsuEnabled) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("Exception valid for 1588 only")); + + if (enable) + { + p_Dtsec->enTsuErrExeption = TRUE; + fman_dtsec_enable_tmr_interrupt(p_Dtsec->p_MemMap); + } + else + { + p_Dtsec->enTsuErrExeption = FALSE; + fman_dtsec_disable_tmr_interrupt(p_Dtsec->p_MemMap); + } + } + + return E_OK; +} + + +/*****************************************************************************/ +/* dTSEC Init & Free API */ +/*****************************************************************************/ + +/* .............................................................................. */ + +static t_Error DtsecInit(t_Handle h_Dtsec) +{ + t_Dtsec *p_Dtsec = (t_Dtsec *)h_Dtsec; + struct dtsec_cfg *p_DtsecDriverParam; + t_Error err; + uint16_t maxFrmLn; + enum enet_interface enet_interface; + enum enet_speed enet_speed; + t_EnetAddr ethAddr; + + SANITY_CHECK_RETURN_ERROR(p_Dtsec, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_Dtsec->p_DtsecDriverParam, E_INVALID_STATE); + SANITY_CHECK_RETURN_ERROR(p_Dtsec->fmMacControllerDriver.h_Fm, E_INVALID_HANDLE); + + FM_GetRevision(p_Dtsec->fmMacControllerDriver.h_Fm, &p_Dtsec->fmMacControllerDriver.fmRevInfo); + CHECK_INIT_PARAMETERS(p_Dtsec, CheckInitParameters); + + p_DtsecDriverParam = p_Dtsec->p_DtsecDriverParam; + p_Dtsec->halfDuplex = p_DtsecDriverParam->halfdup_on; + + enet_interface = (enum enet_interface)ENET_INTERFACE_FROM_MODE(p_Dtsec->enetMode); + enet_speed = (enum enet_speed)ENET_SPEED_FROM_MODE(p_Dtsec->enetMode); + MAKE_ENET_ADDR_FROM_UINT64(p_Dtsec->addr, ethAddr); + + err = (t_Error)fman_dtsec_init(p_Dtsec->p_MemMap, + p_DtsecDriverParam, + enet_interface, + enet_speed, + (uint8_t*)ethAddr, + p_Dtsec->fmMacControllerDriver.fmRevInfo.majorRev, + p_Dtsec->fmMacControllerDriver.fmRevInfo.minorRev, + p_Dtsec->exceptions); + if (err) + { + FreeInitResources(p_Dtsec); + RETURN_ERROR(MAJOR, err, ("This DTSEC version does not support the required i/f mode")); + } + + if (ENET_INTERFACE_FROM_MODE(p_Dtsec->enetMode) == e_ENET_IF_SGMII) + { + uint16_t tmpReg16; + + /* Configure the TBI PHY Control Register */ + tmpReg16 = PHY_TBICON_CLK_SEL | PHY_TBICON_SRESET; + DTSEC_MII_WritePhyReg(p_Dtsec, (uint8_t)p_DtsecDriverParam->tbipa, 17, tmpReg16); + + tmpReg16 = PHY_TBICON_CLK_SEL; + DTSEC_MII_WritePhyReg(p_Dtsec, (uint8_t)p_DtsecDriverParam->tbipa, 17, tmpReg16); + + tmpReg16 = (PHY_CR_PHY_RESET | PHY_CR_ANE | PHY_CR_FULLDUPLEX | PHY_CR_SPEED1); + DTSEC_MII_WritePhyReg(p_Dtsec, (uint8_t)p_DtsecDriverParam->tbipa, 0, tmpReg16); + + if (p_Dtsec->enetMode & ENET_IF_SGMII_BASEX) + tmpReg16 = PHY_TBIANA_1000X; + else + tmpReg16 = PHY_TBIANA_SGMII; + DTSEC_MII_WritePhyReg(p_Dtsec, (uint8_t)p_DtsecDriverParam->tbipa, 4, tmpReg16); + + tmpReg16 = (PHY_CR_ANE | PHY_CR_RESET_AN | PHY_CR_FULLDUPLEX | PHY_CR_SPEED1); + + DTSEC_MII_WritePhyReg(p_Dtsec, (uint8_t)p_DtsecDriverParam->tbipa, 0, tmpReg16); + } + + /* Max Frame Length */ + maxFrmLn = fman_dtsec_get_max_frame_len(p_Dtsec->p_MemMap); + err = FmSetMacMaxFrame(p_Dtsec->fmMacControllerDriver.h_Fm, e_FM_MAC_1G, + p_Dtsec->fmMacControllerDriver.macId, maxFrmLn); + if (err) + RETURN_ERROR(MINOR,err, NO_MSG); + + p_Dtsec->p_MulticastAddrHash = AllocHashTable(EXTENDED_HASH_TABLE_SIZE); + if (!p_Dtsec->p_MulticastAddrHash) { + FreeInitResources(p_Dtsec); + RETURN_ERROR(MAJOR, E_NO_MEMORY, ("MC hash table is FAILED")); + } + + p_Dtsec->p_UnicastAddrHash = AllocHashTable(HASH_TABLE_SIZE); + if (!p_Dtsec->p_UnicastAddrHash) + { + FreeInitResources(p_Dtsec); + RETURN_ERROR(MAJOR, E_NO_MEMORY, ("UC hash table is FAILED")); + } + + /* register err intr handler for dtsec to FPM (err)*/ + FmRegisterIntr(p_Dtsec->fmMacControllerDriver.h_Fm, + e_FM_MOD_1G_MAC, + p_Dtsec->macId, + e_FM_INTR_TYPE_ERR, + DtsecIsr, + p_Dtsec); + /* register 1588 intr handler for TMR to FPM (normal)*/ + FmRegisterIntr(p_Dtsec->fmMacControllerDriver.h_Fm, + e_FM_MOD_1G_MAC, + p_Dtsec->macId, + e_FM_INTR_TYPE_NORMAL, + Dtsec1588Isr, + p_Dtsec); + /* register normal intr handler for dtsec to main interrupt controller. */ + if (p_Dtsec->mdioIrq != NO_IRQ) + { + XX_SetIntr(p_Dtsec->mdioIrq, DtsecMdioIsr, p_Dtsec); + XX_EnableIntr(p_Dtsec->mdioIrq); + } + + XX_Free(p_DtsecDriverParam); + p_Dtsec->p_DtsecDriverParam = NULL; + + err = DtsecSetStatistics(h_Dtsec, e_FM_MAC_FULL_STATISTICS); + if (err) + { + FreeInitResources(p_Dtsec); + RETURN_ERROR(MAJOR, err, ("Undefined statistics level")); + } + + return E_OK; +} + +/* ........................................................................... */ + +static t_Error DtsecFree(t_Handle h_Dtsec) +{ + t_Dtsec *p_Dtsec = (t_Dtsec *)h_Dtsec; + + SANITY_CHECK_RETURN_ERROR(p_Dtsec, E_INVALID_HANDLE); + + if (p_Dtsec->p_DtsecDriverParam) + { + /* Called after config */ + XX_Free(p_Dtsec->p_DtsecDriverParam); + p_Dtsec->p_DtsecDriverParam = NULL; + } + else + /* Called after init */ + FreeInitResources(p_Dtsec); + + XX_Free(p_Dtsec); + + return E_OK; +} + +/* .............................................................................. */ + +static void InitFmMacControllerDriver(t_FmMacControllerDriver *p_FmMacControllerDriver) +{ + p_FmMacControllerDriver->f_FM_MAC_Init = DtsecInit; + p_FmMacControllerDriver->f_FM_MAC_Free = DtsecFree; + + p_FmMacControllerDriver->f_FM_MAC_SetStatistics = DtsecSetStatistics; + p_FmMacControllerDriver->f_FM_MAC_ConfigLoopback = DtsecConfigLoopback; + p_FmMacControllerDriver->f_FM_MAC_ConfigMaxFrameLength = DtsecConfigMaxFrameLength; + + p_FmMacControllerDriver->f_FM_MAC_ConfigWan = NULL; /* Not supported on dTSEC */ + + p_FmMacControllerDriver->f_FM_MAC_ConfigPadAndCrc = DtsecConfigPadAndCrc; + p_FmMacControllerDriver->f_FM_MAC_ConfigHalfDuplex = DtsecConfigHalfDuplex; + p_FmMacControllerDriver->f_FM_MAC_ConfigLengthCheck = DtsecConfigLengthCheck; + p_FmMacControllerDriver->f_FM_MAC_ConfigTbiPhyAddr = DtsecConfigTbiPhyAddr; + p_FmMacControllerDriver->f_FM_MAC_ConfigException = DtsecConfigException; + p_FmMacControllerDriver->f_FM_MAC_ConfigResetOnInit = NULL; + + p_FmMacControllerDriver->f_FM_MAC_Enable = DtsecEnable; + p_FmMacControllerDriver->f_FM_MAC_Disable = DtsecDisable; + p_FmMacControllerDriver->f_FM_MAC_Resume = NULL; + + p_FmMacControllerDriver->f_FM_MAC_SetException = DtsecSetException; + + p_FmMacControllerDriver->f_FM_MAC_SetPromiscuous = DtsecSetPromiscuous; + p_FmMacControllerDriver->f_FM_MAC_AdjustLink = DtsecAdjustLink; + p_FmMacControllerDriver->f_FM_MAC_SetWakeOnLan = DtsecSetWakeOnLan; + p_FmMacControllerDriver->f_FM_MAC_RestartAutoneg = DtsecRestartAutoneg; + + p_FmMacControllerDriver->f_FM_MAC_Enable1588TimeStamp = DtsecEnable1588TimeStamp; + p_FmMacControllerDriver->f_FM_MAC_Disable1588TimeStamp = DtsecDisable1588TimeStamp; + + p_FmMacControllerDriver->f_FM_MAC_SetTxAutoPauseFrames = DtsecTxMacPause; + p_FmMacControllerDriver->f_FM_MAC_SetTxPauseFrames = DtsecSetTxPauseFrames; + p_FmMacControllerDriver->f_FM_MAC_SetRxIgnorePauseFrames = DtsecRxIgnoreMacPause; + + p_FmMacControllerDriver->f_FM_MAC_ResetCounters = DtsecResetCounters; + p_FmMacControllerDriver->f_FM_MAC_GetStatistics = DtsecGetStatistics; + p_FmMacControllerDriver->f_FM_MAC_GetFrameSizeCounters = NULL; + + p_FmMacControllerDriver->f_FM_MAC_ModifyMacAddr = DtsecModifyMacAddress; + p_FmMacControllerDriver->f_FM_MAC_AddHashMacAddr = DtsecAddHashMacAddress; + p_FmMacControllerDriver->f_FM_MAC_RemoveHashMacAddr = DtsecDelHashMacAddress; + p_FmMacControllerDriver->f_FM_MAC_AddExactMatchMacAddr = DtsecAddExactMatchMacAddress; + p_FmMacControllerDriver->f_FM_MAC_RemovelExactMatchMacAddr = DtsecDelExactMatchMacAddress; + p_FmMacControllerDriver->f_FM_MAC_GetId = DtsecGetId; + p_FmMacControllerDriver->f_FM_MAC_GetVersion = DtsecGetVersion; + p_FmMacControllerDriver->f_FM_MAC_GetMaxFrameLength = DtsecGetMaxFrameLength; + + p_FmMacControllerDriver->f_FM_MAC_MII_WritePhyReg = DTSEC_MII_WritePhyReg; + p_FmMacControllerDriver->f_FM_MAC_MII_ReadPhyReg = DTSEC_MII_ReadPhyReg; + +} + + +/*****************************************************************************/ +/* dTSEC Config Main Entry */ +/*****************************************************************************/ + +/* .............................................................................. */ + +t_Handle DTSEC_Config(t_FmMacParams *p_FmMacParam) +{ + t_Dtsec *p_Dtsec; + struct dtsec_cfg *p_DtsecDriverParam; + uintptr_t baseAddr; + + SANITY_CHECK_RETURN_VALUE(p_FmMacParam, E_NULL_POINTER, NULL); + + baseAddr = p_FmMacParam->baseAddr; + + /* allocate memory for the UCC GETH data structure. */ + p_Dtsec = (t_Dtsec *)XX_Malloc(sizeof(t_Dtsec)); + if (!p_Dtsec) + { + REPORT_ERROR(MAJOR, E_NO_MEMORY, ("dTSEC driver structure")); + return NULL; + } + memset(p_Dtsec, 0, sizeof(t_Dtsec)); + InitFmMacControllerDriver(&p_Dtsec->fmMacControllerDriver); + + /* allocate memory for the dTSEC driver parameters data structure. */ + p_DtsecDriverParam = (struct dtsec_cfg *) XX_Malloc(sizeof(struct dtsec_cfg)); + if (!p_DtsecDriverParam) + { + XX_Free(p_Dtsec); + REPORT_ERROR(MAJOR, E_NO_MEMORY, ("dTSEC driver parameters")); + return NULL; + } + memset(p_DtsecDriverParam, 0, sizeof(struct dtsec_cfg)); + + /* Plant parameter structure pointer */ + p_Dtsec->p_DtsecDriverParam = p_DtsecDriverParam; + + fman_dtsec_defconfig(p_DtsecDriverParam); + + p_Dtsec->p_MemMap = (struct dtsec_regs *)UINT_TO_PTR(baseAddr); + p_Dtsec->p_MiiMemMap = (struct dtsec_mii_reg *)UINT_TO_PTR(baseAddr + DTSEC_TO_MII_OFFSET); + p_Dtsec->addr = ENET_ADDR_TO_UINT64(p_FmMacParam->addr); + p_Dtsec->enetMode = p_FmMacParam->enetMode; + p_Dtsec->macId = p_FmMacParam->macId; + p_Dtsec->exceptions = DEFAULT_exceptions; + p_Dtsec->mdioIrq = p_FmMacParam->mdioIrq; + p_Dtsec->f_Exception = p_FmMacParam->f_Exception; + p_Dtsec->f_Event = p_FmMacParam->f_Event; + p_Dtsec->h_App = p_FmMacParam->h_App; + p_Dtsec->ptpTsuEnabled = p_Dtsec->p_DtsecDriverParam->ptp_tsu_en; + p_Dtsec->enTsuErrExeption = p_Dtsec->p_DtsecDriverParam->ptp_exception_en; + p_Dtsec->tbi_phy_addr = p_Dtsec->p_DtsecDriverParam->tbi_phy_addr; + + return p_Dtsec; +} diff --git a/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MAC/dtsec.h b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MAC/dtsec.h new file mode 100644 index 000000000000..c26f40cc9664 --- /dev/null +++ b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MAC/dtsec.h @@ -0,0 +1,228 @@ +/* + * Copyright 2008-2013 Freescale Semiconductor Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Freescale Semiconductor nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * + * ALTERNATIVELY, this software may be distributed under the terms of the + * GNU General Public License ("GPL") as published by the Free Software + * Foundation, either version 2 of that License or (at your option) any + * later version. + * + * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/****************************************************************************** + @File dtsec.h + + @Description FM dTSEC ... +*//***************************************************************************/ +#ifndef __DTSEC_H +#define __DTSEC_H + +#include "std_ext.h" +#include "error_ext.h" +#include "list_ext.h" +#include "enet_ext.h" + +#include "dtsec_mii_acc.h" +#include "fm_mac.h" + + +#define DEFAULT_exceptions \ + ((uint32_t)(DTSEC_IMASK_BREN | \ + DTSEC_IMASK_RXCEN | \ + DTSEC_IMASK_BTEN | \ + DTSEC_IMASK_TXCEN | \ + DTSEC_IMASK_TXEEN | \ + DTSEC_IMASK_ABRTEN | \ + DTSEC_IMASK_LCEN | \ + DTSEC_IMASK_CRLEN | \ + DTSEC_IMASK_XFUNEN | \ + DTSEC_IMASK_IFERREN | \ + DTSEC_IMASK_MAGEN | \ + DTSEC_IMASK_TDPEEN | \ + DTSEC_IMASK_RDPEEN)) + +#define GET_EXCEPTION_FLAG(bitMask, exception) switch (exception){ \ + case e_FM_MAC_EX_1G_BAB_RX: \ + bitMask = DTSEC_IMASK_BREN; break; \ + case e_FM_MAC_EX_1G_RX_CTL: \ + bitMask = DTSEC_IMASK_RXCEN; break; \ + case e_FM_MAC_EX_1G_GRATEFUL_TX_STP_COMPLET: \ + bitMask = DTSEC_IMASK_GTSCEN ; break; \ + case e_FM_MAC_EX_1G_BAB_TX: \ + bitMask = DTSEC_IMASK_BTEN ; break; \ + case e_FM_MAC_EX_1G_TX_CTL: \ + bitMask = DTSEC_IMASK_TXCEN ; break; \ + case e_FM_MAC_EX_1G_TX_ERR: \ + bitMask = DTSEC_IMASK_TXEEN ; break; \ + case e_FM_MAC_EX_1G_LATE_COL: \ + bitMask = DTSEC_IMASK_LCEN ; break; \ + case e_FM_MAC_EX_1G_COL_RET_LMT: \ + bitMask = DTSEC_IMASK_CRLEN ; break; \ + case e_FM_MAC_EX_1G_TX_FIFO_UNDRN: \ + bitMask = DTSEC_IMASK_XFUNEN ; break; \ + case e_FM_MAC_EX_1G_MAG_PCKT: \ + bitMask = DTSEC_IMASK_MAGEN ; break; \ + case e_FM_MAC_EX_1G_MII_MNG_RD_COMPLET: \ + bitMask = DTSEC_IMASK_MMRDEN; break; \ + case e_FM_MAC_EX_1G_MII_MNG_WR_COMPLET: \ + bitMask = DTSEC_IMASK_MMWREN ; break; \ + case e_FM_MAC_EX_1G_GRATEFUL_RX_STP_COMPLET: \ + bitMask = DTSEC_IMASK_GRSCEN; break; \ + case e_FM_MAC_EX_1G_TX_DATA_ERR: \ + bitMask = DTSEC_IMASK_TDPEEN; break; \ + case e_FM_MAC_EX_1G_RX_MIB_CNT_OVFL: \ + bitMask = DTSEC_IMASK_MSROEN ; break; \ + default: bitMask = 0;break;} + + +#define MAX_PACKET_ALIGNMENT 31 +#define MAX_INTER_PACKET_GAP 0x7f +#define MAX_INTER_PALTERNATE_BEB 0x0f +#define MAX_RETRANSMISSION 0x0f +#define MAX_COLLISION_WINDOW 0x03ff + + +/********************* From mac ext ******************************************/ +typedef uint32_t t_ErrorDisable; + +#define ERROR_DISABLE_TRANSMIT 0x00400000 +#define ERROR_DISABLE_LATE_COLLISION 0x00040000 +#define ERROR_DISABLE_COLLISION_RETRY_LIMIT 0x00020000 +#define ERROR_DISABLE_TxFIFO_UNDERRUN 0x00010000 +#define ERROR_DISABLE_TxABORT 0x00008000 +#define ERROR_DISABLE_INTERFACE 0x00004000 +#define ERROR_DISABLE_TxDATA_PARITY 0x00000002 +#define ERROR_DISABLE_RxDATA_PARITY 0x00000001 + +/*****************************************************************************/ +#define DTSEC_NUM_OF_PADDRS 15 /* number of pattern match registers (entries) */ + +#define GROUP_ADDRESS 0x0000010000000000LL /* Group address bit indication */ + +#define HASH_TABLE_SIZE 256 /* Hash table size (= 32 bits * 8 regs) */ + +#define HASH_TABLE_SIZE 256 /* Hash table size (32 bits * 8 regs) */ +#define EXTENDED_HASH_TABLE_SIZE 512 /* Extended Hash table size (32 bits * 16 regs) */ + +#define DTSEC_TO_MII_OFFSET 0x1000 /* number of pattern match registers (entries) */ + +#define MAX_PHYS 32 /* maximum number of phys */ + +#define VAL32BIT 0x100000000LL +#define VAL22BIT 0x00400000 +#define VAL16BIT 0x00010000 +#define VAL12BIT 0x00001000 + +/* CAR1/2 bits */ +#define CAR1_TR64 0x80000000 +#define CAR1_TR127 0x40000000 +#define CAR1_TR255 0x20000000 +#define CAR1_TR511 0x10000000 +#define CAR1_TRK1 0x08000000 +#define CAR1_TRMAX 0x04000000 +#define CAR1_TRMGV 0x02000000 + +#define CAR1_RBYT 0x00010000 +#define CAR1_RPKT 0x00008000 +#define CAR1_RMCA 0x00002000 +#define CAR1_RBCA 0x00001000 +#define CAR1_RXPF 0x00000400 +#define CAR1_RALN 0x00000100 +#define CAR1_RFLR 0x00000080 +#define CAR1_RCDE 0x00000040 +#define CAR1_RCSE 0x00000020 +#define CAR1_RUND 0x00000010 +#define CAR1_ROVR 0x00000008 +#define CAR1_RFRG 0x00000004 +#define CAR1_RJBR 0x00000002 +#define CAR1_RDRP 0x00000001 + +#define CAR2_TFCS 0x00040000 +#define CAR2_TBYT 0x00002000 +#define CAR2_TPKT 0x00001000 +#define CAR2_TMCA 0x00000800 +#define CAR2_TBCA 0x00000400 +#define CAR2_TXPF 0x00000200 +#define CAR2_TDRP 0x00000001 + +typedef struct t_InternalStatistics +{ + uint64_t tr64; + uint64_t tr127; + uint64_t tr255; + uint64_t tr511; + uint64_t tr1k; + uint64_t trmax; + uint64_t trmgv; + uint64_t rfrg; + uint64_t rjbr; + uint64_t rdrp; + uint64_t raln; + uint64_t rund; + uint64_t rovr; + uint64_t rxpf; + uint64_t txpf; + uint64_t rbyt; + uint64_t rpkt; + uint64_t rmca; + uint64_t rbca; + uint64_t rflr; + uint64_t rcde; + uint64_t rcse; + uint64_t tbyt; + uint64_t tpkt; + uint64_t tmca; + uint64_t tbca; + uint64_t tdrp; + uint64_t tfcs; +} t_InternalStatistics; + +typedef struct { + t_FmMacControllerDriver fmMacControllerDriver; + t_Handle h_App; /**< Handle to the upper layer application */ + struct dtsec_regs *p_MemMap; /**< pointer to dTSEC memory mapped registers. */ + struct dtsec_mii_reg *p_MiiMemMap; /**< pointer to dTSEC MII memory mapped registers. */ + uint64_t addr; /**< MAC address of device; */ + e_EnetMode enetMode; /**< Ethernet physical interface */ + t_FmMacExceptionCallback *f_Exception; + int mdioIrq; + t_FmMacExceptionCallback *f_Event; + bool indAddrRegUsed[DTSEC_NUM_OF_PADDRS]; /**< Whether a particular individual address recognition register is being used */ + uint64_t paddr[DTSEC_NUM_OF_PADDRS]; /**< MAC address for particular individual address recognition register */ + uint8_t numOfIndAddrInRegs; /**< Number of individual addresses in registers for this station. */ + bool halfDuplex; + t_InternalStatistics internalStatistics; + t_EthHash *p_MulticastAddrHash; /* pointer to driver's global address hash table */ + t_EthHash *p_UnicastAddrHash; /* pointer to driver's individual address hash table */ + uint8_t macId; + uint8_t tbi_phy_addr; + uint32_t exceptions; + bool ptpTsuEnabled; + bool enTsuErrExeption; + e_FmMacStatisticsLevel statisticsLevel; + struct dtsec_cfg *p_DtsecDriverParam; +} t_Dtsec; + + +#endif /* __DTSEC_H */ diff --git a/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MAC/dtsec_mii_acc.c b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MAC/dtsec_mii_acc.c new file mode 100644 index 000000000000..87da25ff9e35 --- /dev/null +++ b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MAC/dtsec_mii_acc.c @@ -0,0 +1,97 @@ +/* + * Copyright 2008-2013 Freescale Semiconductor Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Freescale Semiconductor nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * + * ALTERNATIVELY, this software may be distributed under the terms of the + * GNU General Public License ("GPL") as published by the Free Software + * Foundation, either version 2 of that License or (at your option) any + * later version. + * + * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + +/****************************************************************************** + @File dtsec_mii_acc.c + + @Description FM dtsec MII register access MAC ... +*//***************************************************************************/ + +#include "error_ext.h" +#include "std_ext.h" +#include "fm_mac.h" +#include "dtsec.h" +#include "fsl_fman_dtsec_mii_acc.h" + + +/*****************************************************************************/ +t_Error DTSEC_MII_WritePhyReg(t_Handle h_Dtsec, + uint8_t phyAddr, + uint8_t reg, + uint16_t data) +{ + t_Dtsec *p_Dtsec = (t_Dtsec *)h_Dtsec; + struct dtsec_mii_reg *miiregs; + uint16_t dtsec_freq; + t_Error err; + + SANITY_CHECK_RETURN_ERROR(p_Dtsec, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_Dtsec->p_MiiMemMap, E_INVALID_HANDLE); + + dtsec_freq = (uint16_t)(p_Dtsec->fmMacControllerDriver.clkFreq >> 1); + miiregs = p_Dtsec->p_MiiMemMap; + + err = (t_Error)fman_dtsec_mii_write_reg(miiregs, phyAddr, reg, data, dtsec_freq); + + return err; +} + +/*****************************************************************************/ +t_Error DTSEC_MII_ReadPhyReg(t_Handle h_Dtsec, + uint8_t phyAddr, + uint8_t reg, + uint16_t *p_Data) +{ + t_Dtsec *p_Dtsec = (t_Dtsec *)h_Dtsec; + struct dtsec_mii_reg *miiregs; + uint16_t dtsec_freq; + t_Error err; + + SANITY_CHECK_RETURN_ERROR(p_Dtsec, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_Dtsec->p_MiiMemMap, E_INVALID_HANDLE); + + dtsec_freq = (uint16_t)(p_Dtsec->fmMacControllerDriver.clkFreq >> 1); + miiregs = p_Dtsec->p_MiiMemMap; + + err = fman_dtsec_mii_read_reg(miiregs, phyAddr, reg, p_Data, dtsec_freq); + + if (*p_Data == 0xffff) + RETURN_ERROR(MINOR, E_NO_DEVICE, + ("Read wrong data (0xffff): phyAddr 0x%x, reg 0x%x", + phyAddr, reg)); + if (err) + RETURN_ERROR(MINOR, (t_Error)err, NO_MSG); + + return E_OK; +} + diff --git a/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MAC/dtsec_mii_acc.h b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MAC/dtsec_mii_acc.h new file mode 100644 index 000000000000..75cc658a5c50 --- /dev/null +++ b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MAC/dtsec_mii_acc.h @@ -0,0 +1,42 @@ +/* + * Copyright 2008-2013 Freescale Semiconductor Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Freescale Semiconductor nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * + * ALTERNATIVELY, this software may be distributed under the terms of the + * GNU General Public License ("GPL") as published by the Free Software + * Foundation, either version 2 of that License or (at your option) any + * later version. + * + * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __DTSEC_MII_ACC_H +#define __DTSEC_MII_ACC_H + +#include "std_ext.h" + + +t_Error DTSEC_MII_WritePhyReg(t_Handle h_Dtsec, uint8_t phyAddr, uint8_t reg, uint16_t data); +t_Error DTSEC_MII_ReadPhyReg(t_Handle h_Dtsec, uint8_t phyAddr, uint8_t reg, uint16_t *p_Data); + +#endif /* __DTSEC_MII_ACC_H */ diff --git a/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MAC/fm_mac.c b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MAC/fm_mac.c new file mode 100644 index 000000000000..caf3940ad9df --- /dev/null +++ b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MAC/fm_mac.c @@ -0,0 +1,674 @@ +/* + * Copyright 2008-2012 Freescale Semiconductor Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Freescale Semiconductor nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * + * ALTERNATIVELY, this software may be distributed under the terms of the + * GNU General Public License ("GPL") as published by the Free Software + * Foundation, either version 2 of that License or (at your option) any + * later version. + * + * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + +/****************************************************************************** + @File fm_mac.c + + @Description FM MAC ... +*//***************************************************************************/ +#include "std_ext.h" +#include "string_ext.h" +#include "sprint_ext.h" +#include "error_ext.h" +#include "fm_ext.h" + +#include "fm_common.h" +#include "fm_mac.h" + + +/* ......................................................................... */ + +t_Handle FM_MAC_Config (t_FmMacParams *p_FmMacParam) +{ + t_FmMacControllerDriver *p_FmMacControllerDriver; + uint16_t fmClkFreq; + + SANITY_CHECK_RETURN_VALUE(p_FmMacParam, E_INVALID_HANDLE, NULL); + + fmClkFreq = FmGetClockFreq(p_FmMacParam->h_Fm); + if (fmClkFreq == 0) + { + REPORT_ERROR(MAJOR, E_INVALID_STATE, ("Can't get clock for MAC!")); + return NULL; + } + +#if (DPAA_VERSION == 10) + if (ENET_SPEED_FROM_MODE(p_FmMacParam->enetMode) < e_ENET_SPEED_10000) + p_FmMacControllerDriver = (t_FmMacControllerDriver *)DTSEC_Config(p_FmMacParam); + else +#if FM_MAX_NUM_OF_10G_MACS > 0 + p_FmMacControllerDriver = (t_FmMacControllerDriver *)TGEC_Config(p_FmMacParam); +#else + p_FmMacControllerDriver = NULL; +#endif /* FM_MAX_NUM_OF_10G_MACS > 0 */ +#else + p_FmMacControllerDriver = (t_FmMacControllerDriver *)MEMAC_Config(p_FmMacParam); +#endif /* (DPAA_VERSION == 10) */ + + if (!p_FmMacControllerDriver) + return NULL; + + p_FmMacControllerDriver->h_Fm = p_FmMacParam->h_Fm; + p_FmMacControllerDriver->enetMode = p_FmMacParam->enetMode; + p_FmMacControllerDriver->macId = p_FmMacParam->macId; + p_FmMacControllerDriver->resetOnInit = DEFAULT_resetOnInit; + + p_FmMacControllerDriver->clkFreq = fmClkFreq; + + return (t_Handle)p_FmMacControllerDriver; +} + +/* ......................................................................... */ + +t_Error FM_MAC_Init (t_Handle h_FmMac) +{ + t_FmMacControllerDriver *p_FmMacControllerDriver = (t_FmMacControllerDriver *)h_FmMac; + + SANITY_CHECK_RETURN_ERROR(p_FmMacControllerDriver, E_INVALID_HANDLE); + + if (p_FmMacControllerDriver->resetOnInit && + !p_FmMacControllerDriver->f_FM_MAC_ConfigResetOnInit && + (FmResetMac(p_FmMacControllerDriver->h_Fm, + ((ENET_INTERFACE_FROM_MODE(p_FmMacControllerDriver->enetMode) == e_ENET_IF_XGMII) ? + e_FM_MAC_10G : e_FM_MAC_1G), + p_FmMacControllerDriver->macId) != E_OK)) + RETURN_ERROR(MAJOR, E_INVALID_STATE, ("Can't reset MAC!")); + + if (p_FmMacControllerDriver->f_FM_MAC_Init) + return p_FmMacControllerDriver->f_FM_MAC_Init(h_FmMac); + RETURN_ERROR(MINOR, E_NOT_SUPPORTED, NO_MSG); +} + +/* ......................................................................... */ + +t_Error FM_MAC_Free (t_Handle h_FmMac) +{ + t_FmMacControllerDriver *p_FmMacControllerDriver = (t_FmMacControllerDriver *)h_FmMac; + + SANITY_CHECK_RETURN_ERROR(p_FmMacControllerDriver, E_INVALID_HANDLE); + + if (p_FmMacControllerDriver->f_FM_MAC_Free) + return p_FmMacControllerDriver->f_FM_MAC_Free(h_FmMac); + + RETURN_ERROR(MINOR, E_NOT_SUPPORTED, NO_MSG); +} + +/* ......................................................................... */ + +t_Error FM_MAC_ConfigResetOnInit (t_Handle h_FmMac, bool enable) +{ + t_FmMacControllerDriver *p_FmMacControllerDriver = (t_FmMacControllerDriver *)h_FmMac; + + SANITY_CHECK_RETURN_ERROR(p_FmMacControllerDriver, E_INVALID_HANDLE); + + if (p_FmMacControllerDriver->f_FM_MAC_ConfigResetOnInit) + return p_FmMacControllerDriver->f_FM_MAC_ConfigResetOnInit(h_FmMac, enable); + + p_FmMacControllerDriver->resetOnInit = enable; + + return E_OK; +} + +/* ......................................................................... */ + +t_Error FM_MAC_ConfigLoopback (t_Handle h_FmMac, bool newVal) +{ + t_FmMacControllerDriver *p_FmMacControllerDriver = (t_FmMacControllerDriver *)h_FmMac; + + SANITY_CHECK_RETURN_ERROR(p_FmMacControllerDriver, E_INVALID_HANDLE); + + if (p_FmMacControllerDriver->f_FM_MAC_ConfigLoopback) + return p_FmMacControllerDriver->f_FM_MAC_ConfigLoopback(h_FmMac, newVal); + + RETURN_ERROR(MINOR, E_NOT_SUPPORTED, NO_MSG); +} + +/* ......................................................................... */ + +t_Error FM_MAC_ConfigMaxFrameLength (t_Handle h_FmMac, uint16_t newVal) +{ + t_FmMacControllerDriver *p_FmMacControllerDriver = (t_FmMacControllerDriver *)h_FmMac; + + SANITY_CHECK_RETURN_ERROR(p_FmMacControllerDriver, E_INVALID_HANDLE); + + if (p_FmMacControllerDriver->f_FM_MAC_ConfigMaxFrameLength) + return p_FmMacControllerDriver->f_FM_MAC_ConfigMaxFrameLength(h_FmMac, newVal); + RETURN_ERROR(MINOR, E_NOT_SUPPORTED, NO_MSG); +} + +/* ......................................................................... */ + +t_Error FM_MAC_ConfigWan (t_Handle h_FmMac, bool flag) +{ + t_FmMacControllerDriver *p_FmMacControllerDriver = (t_FmMacControllerDriver *)h_FmMac; + + SANITY_CHECK_RETURN_ERROR(p_FmMacControllerDriver, E_INVALID_HANDLE); + + if (p_FmMacControllerDriver->f_FM_MAC_ConfigWan) + return p_FmMacControllerDriver->f_FM_MAC_ConfigWan(h_FmMac, flag); + + RETURN_ERROR(MINOR, E_NOT_SUPPORTED, NO_MSG); +} + +/* ......................................................................... */ + +t_Error FM_MAC_ConfigPadAndCrc (t_Handle h_FmMac, bool newVal) +{ + t_FmMacControllerDriver *p_FmMacControllerDriver = (t_FmMacControllerDriver *)h_FmMac; + + SANITY_CHECK_RETURN_ERROR(p_FmMacControllerDriver, E_INVALID_HANDLE); + + if (p_FmMacControllerDriver->f_FM_MAC_ConfigPadAndCrc) + return p_FmMacControllerDriver->f_FM_MAC_ConfigPadAndCrc(h_FmMac, newVal); + + RETURN_ERROR(MINOR, E_NOT_SUPPORTED, NO_MSG); +} + +/* ......................................................................... */ + +t_Error FM_MAC_ConfigHalfDuplex (t_Handle h_FmMac, bool newVal) +{ + t_FmMacControllerDriver *p_FmMacControllerDriver = (t_FmMacControllerDriver *)h_FmMac; + + SANITY_CHECK_RETURN_ERROR(p_FmMacControllerDriver, E_INVALID_HANDLE); + + if (p_FmMacControllerDriver->f_FM_MAC_ConfigHalfDuplex) + return p_FmMacControllerDriver->f_FM_MAC_ConfigHalfDuplex(h_FmMac,newVal); + + RETURN_ERROR(MINOR, E_NOT_SUPPORTED, NO_MSG); +} + +/* ......................................................................... */ + +t_Error FM_MAC_ConfigTbiPhyAddr (t_Handle h_FmMac, uint8_t newVal) +{ + t_FmMacControllerDriver *p_FmMacControllerDriver = (t_FmMacControllerDriver *)h_FmMac; + + SANITY_CHECK_RETURN_ERROR(p_FmMacControllerDriver, E_INVALID_HANDLE); + + if (p_FmMacControllerDriver->f_FM_MAC_ConfigTbiPhyAddr) + return p_FmMacControllerDriver->f_FM_MAC_ConfigTbiPhyAddr(h_FmMac,newVal); + + RETURN_ERROR(MINOR, E_NOT_SUPPORTED, NO_MSG); +} + +/* ......................................................................... */ + +t_Error FM_MAC_ConfigLengthCheck (t_Handle h_FmMac, bool newVal) +{ + t_FmMacControllerDriver *p_FmMacControllerDriver = (t_FmMacControllerDriver *)h_FmMac; + + SANITY_CHECK_RETURN_ERROR(p_FmMacControllerDriver, E_INVALID_HANDLE); + + if (p_FmMacControllerDriver->f_FM_MAC_ConfigLengthCheck) + return p_FmMacControllerDriver->f_FM_MAC_ConfigLengthCheck(h_FmMac,newVal); + + RETURN_ERROR(MINOR, E_NOT_SUPPORTED, NO_MSG); +} + +/* ......................................................................... */ + +t_Error FM_MAC_ConfigException (t_Handle h_FmMac, e_FmMacExceptions ex, bool enable) +{ + t_FmMacControllerDriver *p_FmMacControllerDriver = (t_FmMacControllerDriver *)h_FmMac; + + SANITY_CHECK_RETURN_ERROR(p_FmMacControllerDriver, E_INVALID_HANDLE); + + if (p_FmMacControllerDriver->f_FM_MAC_ConfigException) + return p_FmMacControllerDriver->f_FM_MAC_ConfigException(h_FmMac, ex, enable); + + RETURN_ERROR(MINOR, E_NOT_SUPPORTED, NO_MSG); +} + +#ifdef FM_TX_ECC_FRMS_ERRATA_10GMAC_A004 +/* ......................................................................... */ + +t_Error FM_MAC_ConfigSkipFman11Workaround (t_Handle h_FmMac) +{ + t_FmMacControllerDriver *p_FmMacControllerDriver = (t_FmMacControllerDriver *)h_FmMac; + + SANITY_CHECK_RETURN_ERROR(p_FmMacControllerDriver, E_INVALID_HANDLE); + + if (p_FmMacControllerDriver->f_FM_MAC_ConfigSkipFman11Workaround) + return p_FmMacControllerDriver->f_FM_MAC_ConfigSkipFman11Workaround(h_FmMac); + + RETURN_ERROR(MINOR, E_NOT_SUPPORTED, NO_MSG); +} +#endif /* FM_TX_ECC_FRMS_ERRATA_10GMAC_A004 */ + + +/*****************************************************************************/ +/* Run Time Control */ +/*****************************************************************************/ + +/* ......................................................................... */ + +t_Error FM_MAC_Enable (t_Handle h_FmMac, e_CommMode mode) +{ + t_FmMacControllerDriver *p_FmMacControllerDriver = (t_FmMacControllerDriver *)h_FmMac; + + SANITY_CHECK_RETURN_ERROR(p_FmMacControllerDriver, E_INVALID_HANDLE); + + if (p_FmMacControllerDriver->f_FM_MAC_Enable) + return p_FmMacControllerDriver->f_FM_MAC_Enable(h_FmMac, mode); + + RETURN_ERROR(MINOR, E_NOT_SUPPORTED, NO_MSG); +} + +/* ......................................................................... */ + +t_Error FM_MAC_Disable (t_Handle h_FmMac, e_CommMode mode) +{ + t_FmMacControllerDriver *p_FmMacControllerDriver = (t_FmMacControllerDriver *)h_FmMac; + + SANITY_CHECK_RETURN_ERROR(p_FmMacControllerDriver, E_INVALID_HANDLE); + + if (p_FmMacControllerDriver->f_FM_MAC_Disable) + return p_FmMacControllerDriver->f_FM_MAC_Disable(h_FmMac, mode); + + RETURN_ERROR(MINOR, E_NOT_SUPPORTED, NO_MSG); +} + +t_Error FM_MAC_Resume (t_Handle h_FmMac) +{ + t_FmMacControllerDriver *p_FmMacControllerDriver = (t_FmMacControllerDriver *)h_FmMac; + + SANITY_CHECK_RETURN_ERROR(p_FmMacControllerDriver, E_INVALID_HANDLE); + + if (p_FmMacControllerDriver->f_FM_MAC_Resume) + return p_FmMacControllerDriver->f_FM_MAC_Resume(h_FmMac); + + return E_OK; +} + +/* ......................................................................... */ + +t_Error FM_MAC_Enable1588TimeStamp (t_Handle h_FmMac) +{ + t_FmMacControllerDriver *p_FmMacControllerDriver = (t_FmMacControllerDriver *)h_FmMac; + + SANITY_CHECK_RETURN_ERROR(p_FmMacControllerDriver, E_INVALID_HANDLE); + + if (p_FmMacControllerDriver->f_FM_MAC_Enable1588TimeStamp) + return p_FmMacControllerDriver->f_FM_MAC_Enable1588TimeStamp(h_FmMac); + + RETURN_ERROR(MINOR, E_NOT_SUPPORTED, NO_MSG); +} + +/* ......................................................................... */ + +t_Error FM_MAC_Disable1588TimeStamp (t_Handle h_FmMac) +{ + t_FmMacControllerDriver *p_FmMacControllerDriver = (t_FmMacControllerDriver *)h_FmMac; + + SANITY_CHECK_RETURN_ERROR(p_FmMacControllerDriver, E_INVALID_HANDLE); + + if (p_FmMacControllerDriver->f_FM_MAC_Disable1588TimeStamp) + return p_FmMacControllerDriver->f_FM_MAC_Disable1588TimeStamp(h_FmMac); + + RETURN_ERROR(MINOR, E_NOT_SUPPORTED, NO_MSG); +} + +/* ......................................................................... */ + +t_Error FM_MAC_SetTxAutoPauseFrames(t_Handle h_FmMac, + uint16_t pauseTime) +{ + t_FmMacControllerDriver *p_FmMacControllerDriver = (t_FmMacControllerDriver *)h_FmMac; + + SANITY_CHECK_RETURN_ERROR(p_FmMacControllerDriver, E_INVALID_HANDLE); + + if (p_FmMacControllerDriver->f_FM_MAC_SetTxAutoPauseFrames) + return p_FmMacControllerDriver->f_FM_MAC_SetTxAutoPauseFrames(h_FmMac, + pauseTime); + + RETURN_ERROR(MINOR, E_NOT_SUPPORTED, NO_MSG); +} + +/* ......................................................................... */ + +t_Error FM_MAC_SetTxPauseFrames(t_Handle h_FmMac, + uint8_t priority, + uint16_t pauseTime, + uint16_t threshTime) +{ + t_FmMacControllerDriver *p_FmMacControllerDriver = (t_FmMacControllerDriver *)h_FmMac; + + SANITY_CHECK_RETURN_ERROR(p_FmMacControllerDriver, E_INVALID_HANDLE); + + if (p_FmMacControllerDriver->f_FM_MAC_SetTxPauseFrames) + return p_FmMacControllerDriver->f_FM_MAC_SetTxPauseFrames(h_FmMac, + priority, + pauseTime, + threshTime); + + RETURN_ERROR(MAJOR, E_NOT_SUPPORTED, NO_MSG); +} + +/* ......................................................................... */ + +t_Error FM_MAC_SetRxIgnorePauseFrames (t_Handle h_FmMac, bool en) +{ + t_FmMacControllerDriver *p_FmMacControllerDriver = (t_FmMacControllerDriver *)h_FmMac; + + SANITY_CHECK_RETURN_ERROR(p_FmMacControllerDriver, E_INVALID_HANDLE); + + if (p_FmMacControllerDriver->f_FM_MAC_SetRxIgnorePauseFrames) + return p_FmMacControllerDriver->f_FM_MAC_SetRxIgnorePauseFrames(h_FmMac, en); + + RETURN_ERROR(MINOR, E_NOT_SUPPORTED, NO_MSG); +} + +/* ......................................................................... */ + +t_Error FM_MAC_SetWakeOnLan (t_Handle h_FmMac, bool en) +{ + t_FmMacControllerDriver *p_FmMacControllerDriver = (t_FmMacControllerDriver *)h_FmMac; + + SANITY_CHECK_RETURN_ERROR(p_FmMacControllerDriver, E_INVALID_HANDLE); + + if (p_FmMacControllerDriver->f_FM_MAC_SetWakeOnLan) + return p_FmMacControllerDriver->f_FM_MAC_SetWakeOnLan(h_FmMac, en); + + RETURN_ERROR(MINOR, E_NOT_SUPPORTED, NO_MSG); +} + +/* ......................................................................... */ + +t_Error FM_MAC_ResetCounters (t_Handle h_FmMac) +{ + t_FmMacControllerDriver *p_FmMacControllerDriver = (t_FmMacControllerDriver *)h_FmMac; + + SANITY_CHECK_RETURN_ERROR(p_FmMacControllerDriver, E_INVALID_HANDLE); + + if (p_FmMacControllerDriver->f_FM_MAC_ResetCounters) + return p_FmMacControllerDriver->f_FM_MAC_ResetCounters(h_FmMac); + + RETURN_ERROR(MINOR, E_NOT_SUPPORTED, NO_MSG); +} + +/* ......................................................................... */ + +t_Error FM_MAC_SetException(t_Handle h_FmMac, e_FmMacExceptions ex, bool enable) +{ + t_FmMacControllerDriver *p_FmMacControllerDriver = (t_FmMacControllerDriver *)h_FmMac; + + SANITY_CHECK_RETURN_ERROR(p_FmMacControllerDriver, E_INVALID_HANDLE); + + if (p_FmMacControllerDriver->f_FM_MAC_SetException) + return p_FmMacControllerDriver->f_FM_MAC_SetException(h_FmMac, ex, enable); + + RETURN_ERROR(MINOR, E_NOT_SUPPORTED, NO_MSG); +} + +/* ......................................................................... */ + +t_Error FM_MAC_SetStatistics (t_Handle h_FmMac, e_FmMacStatisticsLevel statisticsLevel) +{ + t_FmMacControllerDriver *p_FmMacControllerDriver = (t_FmMacControllerDriver *)h_FmMac; + + SANITY_CHECK_RETURN_ERROR(p_FmMacControllerDriver, E_INVALID_HANDLE); + + if (p_FmMacControllerDriver->f_FM_MAC_SetStatistics) + return p_FmMacControllerDriver->f_FM_MAC_SetStatistics(h_FmMac, statisticsLevel); + + RETURN_ERROR(MINOR, E_NOT_SUPPORTED, NO_MSG); +} + +/* ......................................................................... */ + +t_Error FM_MAC_GetStatistics (t_Handle h_FmMac, t_FmMacStatistics *p_Statistics) +{ + t_FmMacControllerDriver *p_FmMacControllerDriver = (t_FmMacControllerDriver *)h_FmMac; + + SANITY_CHECK_RETURN_ERROR(p_FmMacControllerDriver, E_INVALID_HANDLE); + + if (p_FmMacControllerDriver->f_FM_MAC_GetStatistics) + return p_FmMacControllerDriver->f_FM_MAC_GetStatistics(h_FmMac, p_Statistics); + + RETURN_ERROR(MINOR, E_NOT_SUPPORTED, NO_MSG); +} + +/* ......................................................................... */ + +t_Error FM_MAC_GetFrameSizeCounters(t_Handle h_FmMac, t_FmMacFrameSizeCounters *p_FrameSizeCounters, e_CommMode type) +{ + t_FmMacControllerDriver *p_FmMacControllerDriver = (t_FmMacControllerDriver *)h_FmMac; + + SANITY_CHECK_RETURN_ERROR(p_FmMacControllerDriver, E_INVALID_HANDLE); + + memset(p_FrameSizeCounters, 0, sizeof(t_FmMacFrameSizeCounters)); + + if (p_FmMacControllerDriver->f_FM_MAC_GetFrameSizeCounters) + return p_FmMacControllerDriver->f_FM_MAC_GetFrameSizeCounters(h_FmMac, p_FrameSizeCounters, type); + + RETURN_ERROR(MINOR, E_NOT_SUPPORTED, NO_MSG); +} + +/* ......................................................................... */ + +t_Error FM_MAC_ModifyMacAddr (t_Handle h_FmMac, t_EnetAddr *p_EnetAddr) +{ + t_FmMacControllerDriver *p_FmMacControllerDriver = (t_FmMacControllerDriver *)h_FmMac; + + SANITY_CHECK_RETURN_ERROR(p_FmMacControllerDriver, E_INVALID_HANDLE); + + if (p_FmMacControllerDriver->f_FM_MAC_ModifyMacAddr) + return p_FmMacControllerDriver->f_FM_MAC_ModifyMacAddr(h_FmMac, p_EnetAddr); + + RETURN_ERROR(MINOR, E_NOT_SUPPORTED, NO_MSG); +} + +/* ......................................................................... */ + +t_Error FM_MAC_AddHashMacAddr (t_Handle h_FmMac, t_EnetAddr *p_EnetAddr) +{ + t_FmMacControllerDriver *p_FmMacControllerDriver = (t_FmMacControllerDriver *)h_FmMac; + + SANITY_CHECK_RETURN_ERROR(p_FmMacControllerDriver, E_INVALID_HANDLE); + + if (p_FmMacControllerDriver->f_FM_MAC_AddHashMacAddr) + return p_FmMacControllerDriver->f_FM_MAC_AddHashMacAddr(h_FmMac, p_EnetAddr); + + RETURN_ERROR(MINOR, E_NOT_SUPPORTED, NO_MSG); +} + +/* ......................................................................... */ + +t_Error FM_MAC_RemoveHashMacAddr (t_Handle h_FmMac, t_EnetAddr *p_EnetAddr) +{ + t_FmMacControllerDriver *p_FmMacControllerDriver = (t_FmMacControllerDriver *)h_FmMac; + + SANITY_CHECK_RETURN_ERROR(p_FmMacControllerDriver, E_INVALID_HANDLE); + + if (p_FmMacControllerDriver->f_FM_MAC_RemoveHashMacAddr) + return p_FmMacControllerDriver->f_FM_MAC_RemoveHashMacAddr(h_FmMac, p_EnetAddr); + + RETURN_ERROR(MINOR, E_NOT_SUPPORTED, NO_MSG); +} + +/* ......................................................................... */ + +t_Error FM_MAC_AddExactMatchMacAddr (t_Handle h_FmMac, t_EnetAddr *p_EnetAddr) +{ + t_FmMacControllerDriver *p_FmMacControllerDriver = (t_FmMacControllerDriver *)h_FmMac; + + SANITY_CHECK_RETURN_ERROR(p_FmMacControllerDriver, E_INVALID_HANDLE); + + if (p_FmMacControllerDriver->f_FM_MAC_AddExactMatchMacAddr) + return p_FmMacControllerDriver->f_FM_MAC_AddExactMatchMacAddr(h_FmMac, p_EnetAddr); + + RETURN_ERROR(MINOR, E_NOT_SUPPORTED, NO_MSG); +} + +/* ......................................................................... */ + +t_Error FM_MAC_RemovelExactMatchMacAddr (t_Handle h_FmMac, t_EnetAddr *p_EnetAddr) +{ + t_FmMacControllerDriver *p_FmMacControllerDriver = (t_FmMacControllerDriver *)h_FmMac; + + SANITY_CHECK_RETURN_ERROR(p_FmMacControllerDriver, E_INVALID_HANDLE); + + if (p_FmMacControllerDriver->f_FM_MAC_RemovelExactMatchMacAddr) + return p_FmMacControllerDriver->f_FM_MAC_RemovelExactMatchMacAddr(h_FmMac, p_EnetAddr); + + RETURN_ERROR(MINOR, E_NOT_SUPPORTED, NO_MSG); +} + +/* ......................................................................... */ + +t_Error FM_MAC_GetVesrion (t_Handle h_FmMac, uint32_t *macVresion) +{ + t_FmMacControllerDriver *p_FmMacControllerDriver = (t_FmMacControllerDriver *)h_FmMac; + + SANITY_CHECK_RETURN_ERROR(p_FmMacControllerDriver, E_INVALID_HANDLE); + + if (p_FmMacControllerDriver->f_FM_MAC_GetVersion) + return p_FmMacControllerDriver->f_FM_MAC_GetVersion(h_FmMac, macVresion); + + RETURN_ERROR(MINOR, E_NOT_SUPPORTED, NO_MSG); + +} + +/* ......................................................................... */ + +t_Error FM_MAC_GetId (t_Handle h_FmMac, uint32_t *macId) +{ + t_FmMacControllerDriver *p_FmMacControllerDriver = (t_FmMacControllerDriver *)h_FmMac; + + SANITY_CHECK_RETURN_ERROR(p_FmMacControllerDriver, E_INVALID_HANDLE); + + if (p_FmMacControllerDriver->f_FM_MAC_GetId) + return p_FmMacControllerDriver->f_FM_MAC_GetId(h_FmMac, macId); + + RETURN_ERROR(MINOR, E_NOT_SUPPORTED, NO_MSG); +} + +/* ......................................................................... */ + +t_Error FM_MAC_SetPromiscuous (t_Handle h_FmMac, bool newVal) +{ + t_FmMacControllerDriver *p_FmMacControllerDriver = (t_FmMacControllerDriver *)h_FmMac; + + SANITY_CHECK_RETURN_ERROR(p_FmMacControllerDriver, E_INVALID_HANDLE); + + if (p_FmMacControllerDriver->f_FM_MAC_SetPromiscuous) + return p_FmMacControllerDriver->f_FM_MAC_SetPromiscuous(h_FmMac, newVal); + + RETURN_ERROR(MINOR, E_NOT_SUPPORTED, NO_MSG); +} + +/* ......................................................................... */ + +t_Error FM_MAC_AdjustLink(t_Handle h_FmMac, e_EnetSpeed speed, bool fullDuplex) +{ + t_FmMacControllerDriver *p_FmMacControllerDriver = (t_FmMacControllerDriver *)h_FmMac; + + SANITY_CHECK_RETURN_ERROR(p_FmMacControllerDriver, E_INVALID_HANDLE); + + if (p_FmMacControllerDriver->f_FM_MAC_AdjustLink) + return p_FmMacControllerDriver->f_FM_MAC_AdjustLink(h_FmMac, speed, fullDuplex); + + RETURN_ERROR(MINOR, E_NOT_SUPPORTED, NO_MSG); +} + +/* ......................................................................... */ + +t_Error FM_MAC_RestartAutoneg(t_Handle h_FmMac) +{ + t_FmMacControllerDriver *p_FmMacControllerDriver = (t_FmMacControllerDriver *)h_FmMac; + + SANITY_CHECK_RETURN_ERROR(p_FmMacControllerDriver, E_INVALID_HANDLE); + + if (p_FmMacControllerDriver->f_FM_MAC_RestartAutoneg) + return p_FmMacControllerDriver->f_FM_MAC_RestartAutoneg(h_FmMac); + + RETURN_ERROR(MINOR, E_NOT_SUPPORTED, NO_MSG); +} + +/* ......................................................................... */ + +t_Error FM_MAC_MII_WritePhyReg (t_Handle h_FmMac, uint8_t phyAddr, uint8_t reg, uint16_t data) +{ + t_FmMacControllerDriver *p_FmMacControllerDriver = (t_FmMacControllerDriver *)h_FmMac; + + SANITY_CHECK_RETURN_ERROR(p_FmMacControllerDriver, E_INVALID_HANDLE); + + if (p_FmMacControllerDriver->f_FM_MAC_MII_WritePhyReg) + return p_FmMacControllerDriver->f_FM_MAC_MII_WritePhyReg(h_FmMac, phyAddr, reg, data); + + RETURN_ERROR(MINOR, E_NOT_SUPPORTED, NO_MSG); +} + +/* ......................................................................... */ + +t_Error FM_MAC_MII_ReadPhyReg(t_Handle h_FmMac, uint8_t phyAddr, uint8_t reg, uint16_t *p_Data) +{ + t_FmMacControllerDriver *p_FmMacControllerDriver = (t_FmMacControllerDriver *)h_FmMac; + + SANITY_CHECK_RETURN_ERROR(p_FmMacControllerDriver, E_INVALID_HANDLE); + + if (p_FmMacControllerDriver->f_FM_MAC_MII_ReadPhyReg) + return p_FmMacControllerDriver->f_FM_MAC_MII_ReadPhyReg(h_FmMac, phyAddr, reg, p_Data); + + RETURN_ERROR(MINOR, E_NOT_SUPPORTED, NO_MSG); +} + +/* ......................................................................... */ + +uint16_t FM_MAC_GetMaxFrameLength(t_Handle h_FmMac) +{ + t_FmMacControllerDriver *p_FmMacControllerDriver = (t_FmMacControllerDriver *)h_FmMac; + + SANITY_CHECK_RETURN_VALUE(p_FmMacControllerDriver, E_INVALID_HANDLE, 0); + + if (p_FmMacControllerDriver->f_FM_MAC_GetMaxFrameLength) + return p_FmMacControllerDriver->f_FM_MAC_GetMaxFrameLength(h_FmMac); + + REPORT_ERROR(MINOR, E_NOT_SUPPORTED, NO_MSG); + return 0; +} + +#if (defined(DEBUG_ERRORS) && (DEBUG_ERRORS > 0)) +/*****************************************************************************/ +t_Error FM_MAC_DumpRegs(t_Handle h_FmMac) +{ + t_FmMacControllerDriver *p_FmMacControllerDriver = (t_FmMacControllerDriver *)h_FmMac; + + SANITY_CHECK_RETURN_ERROR(p_FmMacControllerDriver, E_INVALID_HANDLE); + + if (p_FmMacControllerDriver->f_FM_MAC_DumpRegs) + return p_FmMacControllerDriver->f_FM_MAC_DumpRegs(h_FmMac); + RETURN_ERROR(MINOR, E_NOT_SUPPORTED, NO_MSG); +} +#endif /* (defined(DEBUG_ERRORS) && ... */ diff --git a/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MAC/fm_mac.h b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MAC/fm_mac.h new file mode 100644 index 000000000000..ba3b9133a88f --- /dev/null +++ b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MAC/fm_mac.h @@ -0,0 +1,226 @@ +/* + * Copyright 2008-2012 Freescale Semiconductor Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Freescale Semiconductor nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * + * ALTERNATIVELY, this software may be distributed under the terms of the + * GNU General Public License ("GPL") as published by the Free Software + * Foundation, either version 2 of that License or (at your option) any + * later version. + * + * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + +/****************************************************************************** + @File fm_mac.h + + @Description FM MAC ... +*//***************************************************************************/ +#ifndef __FM_MAC_H +#define __FM_MAC_H + +#include "std_ext.h" +#include "error_ext.h" +#include "list_ext.h" +#include "fm_mac_ext.h" +#include "fm_common.h" + + +#define __ERR_MODULE__ MODULE_FM_MAC + +/**************************************************************************//** + @Description defaults +*//***************************************************************************/ + + +#define DEFAULT_halfDuplex FALSE +#define DEFAULT_padAndCrcEnable TRUE +#define DEFAULT_resetOnInit FALSE + + +typedef struct { + uint64_t addr; /* Ethernet Address */ + t_List node; +} t_EthHashEntry; +#define ETH_HASH_ENTRY_OBJ(ptr) LIST_OBJECT(ptr, t_EthHashEntry, node) + +typedef struct { + uint16_t size; + t_List *p_Lsts; +} t_EthHash; + +typedef struct { + t_Error (*f_FM_MAC_Init) (t_Handle h_FmMac); + t_Error (*f_FM_MAC_Free) (t_Handle h_FmMac); + + t_Error (*f_FM_MAC_SetStatistics) (t_Handle h_FmMac, e_FmMacStatisticsLevel statisticsLevel); + t_Error (*f_FM_MAC_ConfigLoopback) (t_Handle h_FmMac, bool newVal); + t_Error (*f_FM_MAC_ConfigMaxFrameLength) (t_Handle h_FmMac, uint16_t newVal); + t_Error (*f_FM_MAC_ConfigWan) (t_Handle h_FmMac, bool flag); + t_Error (*f_FM_MAC_ConfigPadAndCrc) (t_Handle h_FmMac, bool newVal); + t_Error (*f_FM_MAC_ConfigHalfDuplex) (t_Handle h_FmMac, bool newVal); + t_Error (*f_FM_MAC_ConfigLengthCheck) (t_Handle h_FmMac, bool newVal); + t_Error (*f_FM_MAC_ConfigTbiPhyAddr) (t_Handle h_FmMac, uint8_t newVal); + t_Error (*f_FM_MAC_ConfigException) (t_Handle h_FmMac, e_FmMacExceptions, bool enable); + t_Error (*f_FM_MAC_ConfigResetOnInit) (t_Handle h_FmMac, bool enable); +#ifdef FM_TX_ECC_FRMS_ERRATA_10GMAC_A004 + t_Error (*f_FM_MAC_ConfigSkipFman11Workaround) (t_Handle h_FmMac); +#endif /* FM_TX_ECC_FRMS_ERRATA_10GMAC_A004 */ + + t_Error (*f_FM_MAC_SetException) (t_Handle h_FmMac, e_FmMacExceptions ex, bool enable); + + t_Error (*f_FM_MAC_Enable) (t_Handle h_FmMac, e_CommMode mode); + t_Error (*f_FM_MAC_Disable) (t_Handle h_FmMac, e_CommMode mode); + t_Error (*f_FM_MAC_Resume) (t_Handle h_FmMac); + t_Error (*f_FM_MAC_Enable1588TimeStamp) (t_Handle h_FmMac); + t_Error (*f_FM_MAC_Disable1588TimeStamp) (t_Handle h_FmMac); + t_Error (*f_FM_MAC_Reset) (t_Handle h_FmMac, bool wait); + + t_Error (*f_FM_MAC_SetTxAutoPauseFrames) (t_Handle h_FmMac, + uint16_t pauseTime); + t_Error (*f_FM_MAC_SetTxPauseFrames) (t_Handle h_FmMac, + uint8_t priority, + uint16_t pauseTime, + uint16_t threshTime); + t_Error (*f_FM_MAC_SetRxIgnorePauseFrames) (t_Handle h_FmMac, bool en); + + t_Error (*f_FM_MAC_ResetCounters) (t_Handle h_FmMac); + t_Error (*f_FM_MAC_GetStatistics) (t_Handle h_FmMac, t_FmMacStatistics *p_Statistics); + t_Error (*f_FM_MAC_GetFrameSizeCounters) (t_Handle h_FmMac, t_FmMacFrameSizeCounters *p_FrameSizeCounters, e_CommMode type); + + t_Error (*f_FM_MAC_ModifyMacAddr) (t_Handle h_FmMac, t_EnetAddr *p_EnetAddr); + t_Error (*f_FM_MAC_AddHashMacAddr) (t_Handle h_FmMac, t_EnetAddr *p_EnetAddr); + t_Error (*f_FM_MAC_RemoveHashMacAddr) (t_Handle h_FmMac, t_EnetAddr *p_EnetAddr); + t_Error (*f_FM_MAC_AddExactMatchMacAddr) (t_Handle h_FmMac, t_EnetAddr *p_EnetAddr); + t_Error (*f_FM_MAC_RemovelExactMatchMacAddr) (t_Handle h_FmMac, t_EnetAddr *p_EnetAddr); + + t_Error (*f_FM_MAC_SetPromiscuous) (t_Handle h_FmMac, bool newVal); + t_Error (*f_FM_MAC_AdjustLink) (t_Handle h_FmMac, e_EnetSpeed speed, bool fullDuplex); + t_Error (*f_FM_MAC_RestartAutoneg) (t_Handle h_FmMac); + + t_Error (*f_FM_MAC_SetWakeOnLan) (t_Handle h_FmMac, bool en); + + t_Error (*f_FM_MAC_GetId) (t_Handle h_FmMac, uint32_t *macId); + + t_Error (*f_FM_MAC_GetVersion) (t_Handle h_FmMac, uint32_t *macVersion); + + uint16_t (*f_FM_MAC_GetMaxFrameLength) (t_Handle h_FmMac); + + t_Error (*f_FM_MAC_MII_WritePhyReg)(t_Handle h_FmMac, uint8_t phyAddr, uint8_t reg, uint16_t data); + t_Error (*f_FM_MAC_MII_ReadPhyReg)(t_Handle h_FmMac, uint8_t phyAddr, uint8_t reg, uint16_t *p_Data); + +#if (defined(DEBUG_ERRORS) && (DEBUG_ERRORS > 0)) + t_Error (*f_FM_MAC_DumpRegs) (t_Handle h_FmMac); +#endif /* (defined(DEBUG_ERRORS) && ... */ + + t_Handle h_Fm; + t_FmRevisionInfo fmRevInfo; + e_EnetMode enetMode; + uint8_t macId; + bool resetOnInit; + uint16_t clkFreq; +} t_FmMacControllerDriver; + + +#if (DPAA_VERSION == 10) +t_Handle DTSEC_Config(t_FmMacParams *p_FmMacParam); +t_Handle TGEC_Config(t_FmMacParams *p_FmMacParams); +#else +t_Handle MEMAC_Config(t_FmMacParams *p_FmMacParam); +#endif /* (DPAA_VERSION == 10) */ +uint16_t FM_MAC_GetMaxFrameLength(t_Handle FmMac); + + +/* ........................................................................... */ + +static __inline__ t_EthHashEntry *DequeueAddrFromHashEntry(t_List *p_AddrLst) +{ + t_EthHashEntry *p_HashEntry = NULL; + if (!LIST_IsEmpty(p_AddrLst)) + { + p_HashEntry = ETH_HASH_ENTRY_OBJ(p_AddrLst->p_Next); + LIST_DelAndInit(&p_HashEntry->node); + } + return p_HashEntry; +} + +/* ........................................................................... */ + +static __inline__ void FreeHashTable(t_EthHash *p_Hash) +{ + t_EthHashEntry *p_HashEntry; + int i = 0; + + if (p_Hash) + { + if (p_Hash->p_Lsts) + { + for (i=0; i<p_Hash->size; i++) + { + p_HashEntry = DequeueAddrFromHashEntry(&p_Hash->p_Lsts[i]); + while (p_HashEntry) + { + XX_Free(p_HashEntry); + p_HashEntry = DequeueAddrFromHashEntry(&p_Hash->p_Lsts[i]); + } + } + + XX_Free(p_Hash->p_Lsts); + } + + XX_Free(p_Hash); + } +} + +/* ........................................................................... */ + +static __inline__ t_EthHash * AllocHashTable(uint16_t size) +{ + uint32_t i; + t_EthHash *p_Hash; + + /* Allocate address hash table */ + p_Hash = (t_EthHash *)XX_Malloc(sizeof(t_EthHash)); + if (!p_Hash) + { + REPORT_ERROR(MAJOR, E_NO_MEMORY, ("Address hash table")); + return NULL; + } + p_Hash->size = size; + + p_Hash->p_Lsts = (t_List *)XX_Malloc(p_Hash->size*sizeof(t_List)); + if (!p_Hash->p_Lsts) + { + REPORT_ERROR(MAJOR, E_NO_MEMORY, ("Address hash table")); + XX_Free(p_Hash); + return NULL; + } + + for (i=0 ; i<p_Hash->size; i++) + INIT_LIST(&p_Hash->p_Lsts[i]); + + return p_Hash; +} + + +#endif /* __FM_MAC_H */ diff --git a/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MAC/fman_crc32.c b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MAC/fman_crc32.c new file mode 100644 index 000000000000..b6a4ca25f80c --- /dev/null +++ b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MAC/fman_crc32.c @@ -0,0 +1,119 @@ +/* + * Copyright 2008-2012 Freescale Semiconductor Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Freescale Semiconductor nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * + * ALTERNATIVELY, this software may be distributed under the terms of the + * GNU General Public License ("GPL") as published by the Free Software + * Foundation, either version 2 of that License or (at your option) any + * later version. + * + * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + +#include "fman_crc32.h" +#include "common/general.h" + + +/* precomputed CRC values for address hashing */ +static const uint32_t crc_tbl[256] = { + 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f, + 0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988, + 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2, + 0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, + 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9, + 0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172, + 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa, 0x42b2986c, + 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59, + 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, + 0xcfba9599, 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, + 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, 0x01db7106, + 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433, + 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, + 0x91646c97, 0xe6635c01, 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, + 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950, + 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65, + 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7, + 0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0, + 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa, + 0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f, + 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81, + 0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a, + 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, 0xe3630b12, 0x94643b84, + 0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, + 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb, + 0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc, + 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8, 0xa1d1937e, + 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b, + 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, + 0x316e8eef, 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, + 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28, + 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d, + 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f, + 0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, + 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242, + 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777, + 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69, + 0x616bffd3, 0x166ccf45, 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2, + 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc, + 0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9, + 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693, + 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94, + 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d +}; + +/* Get the mirrored value of a byte size number. (0x11010011 --> 0x11001011) */ +static inline uint8_t get_mirror8(uint8_t n) +{ + uint8_t mirror[16] = { + 0x00, 0x08, 0x04, 0x0c, 0x02, 0x0a, 0x06, 0x0e, + 0x01, 0x09, 0x05, 0x0d, 0x03, 0x0b, 0x07, 0x0f + }; + return (uint8_t)(((mirror[n & 0x0f] << 4) | (mirror[n >> 4]))); +} + +static inline uint32_t get_mirror32(uint32_t n) +{ + return ((uint32_t)get_mirror8((uint8_t)(n))<<24) | + ((uint32_t)get_mirror8((uint8_t)(n>>8))<<16) | + ((uint32_t)get_mirror8((uint8_t)(n>>16))<<8) | + ((uint32_t)get_mirror8((uint8_t)(n>>24))); +} + +uint32_t get_mac_addr_crc(uint64_t _addr) +{ + uint32_t i; + uint8_t data; + uint32_t crc; + + /* CRC calculation */ + crc = 0xffffffff; + for (i = 0; i < 6; i++) { + data = (uint8_t)(_addr >> ((5-i)*8)); + crc = crc ^ data; + crc = crc_tbl[crc&0xff] ^ (crc>>8); + } + + crc = get_mirror32(crc); + return crc; +} diff --git a/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MAC/fman_crc32.h b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MAC/fman_crc32.h new file mode 100644 index 000000000000..6e32fdc6c5f6 --- /dev/null +++ b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MAC/fman_crc32.h @@ -0,0 +1,43 @@ +/* + * Copyright 2008-2012 Freescale Semiconductor Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Freescale Semiconductor nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * + * ALTERNATIVELY, this software may be distributed under the terms of the + * GNU General Public License ("GPL") as published by the Free Software + * Foundation, either version 2 of that License or (at your option) any + * later version. + * + * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + +#ifndef __FMAN_CRC32_H +#define __FMAN_CRC32_H + +#include "common/general.h" + + +uint32_t get_mac_addr_crc(uint64_t _addr); + + +#endif /* __FMAN_CRC32_H */ diff --git a/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MAC/fman_dtsec.c b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MAC/fman_dtsec.c new file mode 100644 index 000000000000..60dc2df0bc62 --- /dev/null +++ b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MAC/fman_dtsec.c @@ -0,0 +1,847 @@ +/* + * Copyright 2008-2012 Freescale Semiconductor Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Freescale Semiconductor nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * + * ALTERNATIVELY, this software may be distributed under the terms of the + * GNU General Public License ("GPL") as published by the Free Software + * Foundation, either version 2 of that License or (at your option) any + * later version. + * + * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + +#include "std_ext.h" +#include "error_ext.h" +#include "fsl_fman_dtsec.h" + + +void fman_dtsec_stop_rx(struct dtsec_regs *regs) +{ + /* Assert the graceful stop bit */ + iowrite32be(ioread32be(®s->rctrl) | RCTRL_GRS, ®s->rctrl); +} + +void fman_dtsec_stop_tx(struct dtsec_regs *regs) +{ + /* Assert the graceful stop bit */ + iowrite32be(ioread32be(®s->tctrl) | DTSEC_TCTRL_GTS, ®s->tctrl); +} + +void fman_dtsec_start_tx(struct dtsec_regs *regs) +{ + /* clear the graceful stop bit */ + iowrite32be(ioread32be(®s->tctrl) & ~DTSEC_TCTRL_GTS, ®s->tctrl); +} + +void fman_dtsec_start_rx(struct dtsec_regs *regs) +{ + /* clear the graceful stop bit */ + iowrite32be(ioread32be(®s->rctrl) & ~RCTRL_GRS, ®s->rctrl); +} + +void fman_dtsec_defconfig(struct dtsec_cfg *cfg) +{ + cfg->halfdup_on = DEFAULT_HALFDUP_ON; + cfg->halfdup_retransmit = DEFAULT_HALFDUP_RETRANSMIT; + cfg->halfdup_coll_window = DEFAULT_HALFDUP_COLL_WINDOW; + cfg->halfdup_excess_defer = DEFAULT_HALFDUP_EXCESS_DEFER; + cfg->halfdup_no_backoff = DEFAULT_HALFDUP_NO_BACKOFF; + cfg->halfdup_bp_no_backoff = DEFAULT_HALFDUP_BP_NO_BACKOFF; + cfg->halfdup_alt_backoff_val = DEFAULT_HALFDUP_ALT_BACKOFF_VAL; + cfg->halfdup_alt_backoff_en = DEFAULT_HALFDUP_ALT_BACKOFF_EN; + cfg->rx_drop_bcast = DEFAULT_RX_DROP_BCAST; + cfg->rx_short_frm = DEFAULT_RX_SHORT_FRM; + cfg->rx_len_check = DEFAULT_RX_LEN_CHECK; + cfg->tx_pad_crc = DEFAULT_TX_PAD_CRC; + cfg->tx_crc = DEFAULT_TX_CRC; + cfg->rx_ctrl_acc = DEFAULT_RX_CTRL_ACC; + cfg->tx_pause_time = DEFAULT_TX_PAUSE_TIME; + cfg->tbipa = DEFAULT_TBIPA; /* PHY address 0 is reserved (DPAA RM)*/ + cfg->rx_prepend = DEFAULT_RX_PREPEND; + cfg->ptp_tsu_en = DEFAULT_PTP_TSU_EN; + cfg->ptp_exception_en = DEFAULT_PTP_EXCEPTION_EN; + cfg->preamble_len = DEFAULT_PREAMBLE_LEN; + cfg->rx_preamble = DEFAULT_RX_PREAMBLE; + cfg->tx_preamble = DEFAULT_TX_PREAMBLE; + cfg->loopback = DEFAULT_LOOPBACK; + cfg->rx_time_stamp_en = DEFAULT_RX_TIME_STAMP_EN; + cfg->tx_time_stamp_en = DEFAULT_TX_TIME_STAMP_EN; + cfg->rx_flow = DEFAULT_RX_FLOW; + cfg->tx_flow = DEFAULT_TX_FLOW; + cfg->rx_group_hash_exd = DEFAULT_RX_GROUP_HASH_EXD; + cfg->tx_pause_time_extd = DEFAULT_TX_PAUSE_TIME_EXTD; + cfg->rx_promisc = DEFAULT_RX_PROMISC; + cfg->non_back_to_back_ipg1 = DEFAULT_NON_BACK_TO_BACK_IPG1; + cfg->non_back_to_back_ipg2 = DEFAULT_NON_BACK_TO_BACK_IPG2; + cfg->min_ifg_enforcement = DEFAULT_MIN_IFG_ENFORCEMENT; + cfg->back_to_back_ipg = DEFAULT_BACK_TO_BACK_IPG; + cfg->maximum_frame = DEFAULT_MAXIMUM_FRAME; + cfg->tbi_phy_addr = DEFAULT_TBI_PHY_ADDR; + cfg->wake_on_lan = DEFAULT_WAKE_ON_LAN; +} + +int fman_dtsec_init(struct dtsec_regs *regs, struct dtsec_cfg *cfg, + enum enet_interface iface_mode, + enum enet_speed iface_speed, + uint8_t *macaddr, + uint8_t fm_rev_maj, + uint8_t fm_rev_min, + uint32_t exception_mask) +{ + bool is_rgmii = FALSE; + bool is_sgmii = FALSE; + bool is_qsgmii = FALSE; + int i; + uint32_t tmp; + +UNUSED(fm_rev_maj);UNUSED(fm_rev_min); + + /* let's start with a soft reset */ + iowrite32be(MACCFG1_SOFT_RESET, ®s->maccfg1); + iowrite32be(0, ®s->maccfg1); + + /*************dtsec_id2******************/ + tmp = ioread32be(®s->tsec_id2); + + /* check RGMII support */ + if (iface_mode == E_ENET_IF_RGMII || + iface_mode == E_ENET_IF_RMII) + if (tmp & DTSEC_ID2_INT_REDUCED_OFF) + return -EINVAL; + + if (iface_mode == E_ENET_IF_SGMII || + iface_mode == E_ENET_IF_MII) + if (tmp & DTSEC_ID2_INT_REDUCED_OFF) + return -EINVAL; + + /***************ECNTRL************************/ + + is_rgmii = (bool)((iface_mode == E_ENET_IF_RGMII) ? TRUE : FALSE); + is_sgmii = (bool)((iface_mode == E_ENET_IF_SGMII) ? TRUE : FALSE); + is_qsgmii = (bool)((iface_mode == E_ENET_IF_QSGMII) ? TRUE : FALSE); + + tmp = 0; + if (is_rgmii || iface_mode == E_ENET_IF_GMII) + tmp |= DTSEC_ECNTRL_GMIIM; + if (is_sgmii) + tmp |= (DTSEC_ECNTRL_SGMIIM | DTSEC_ECNTRL_TBIM); + if (is_qsgmii) + tmp |= (DTSEC_ECNTRL_SGMIIM | DTSEC_ECNTRL_TBIM | + DTSEC_ECNTRL_QSGMIIM); + if (is_rgmii) + tmp |= DTSEC_ECNTRL_RPM; + if (iface_speed == E_ENET_SPEED_100) + tmp |= DTSEC_ECNTRL_R100M; + + iowrite32be(tmp, ®s->ecntrl); + /***************ECNTRL************************/ + + /***************TCTRL************************/ + tmp = 0; + if (cfg->halfdup_on) + tmp |= DTSEC_TCTRL_THDF; + if (cfg->tx_time_stamp_en) + tmp |= DTSEC_TCTRL_TTSE; + + iowrite32be(tmp, ®s->tctrl); + + /***************TCTRL************************/ + + /***************PTV************************/ + tmp = 0; + +#ifdef FM_SHORT_PAUSE_TIME_ERRATA_DTSEC1 + if ((fm_rev_maj == 1) && (fm_rev_min == 0)) + cfg->tx_pause_time += 2; +#endif /* FM_SHORT_PAUSE_TIME_ERRATA_DTSEC1 */ + + if (cfg->tx_pause_time) + tmp |= cfg->tx_pause_time; + if (cfg->tx_pause_time_extd) + tmp |= cfg->tx_pause_time_extd << PTV_PTE_OFST; + iowrite32be(tmp, ®s->ptv); + + /***************RCTRL************************/ + tmp = 0; + tmp |= ((uint32_t)(cfg->rx_prepend & 0x0000001f)) << 16; + if (cfg->rx_ctrl_acc) + tmp |= RCTRL_CFA; + if (cfg->rx_group_hash_exd) + tmp |= RCTRL_GHTX; + if (cfg->rx_time_stamp_en) + tmp |= RCTRL_RTSE; + if (cfg->rx_drop_bcast) + tmp |= RCTRL_BC_REJ; + if (cfg->rx_short_frm) + tmp |= RCTRL_RSF; + if (cfg->rx_promisc) + tmp |= RCTRL_PROM; + + iowrite32be(tmp, ®s->rctrl); + /***************RCTRL************************/ + + /* + * Assign a Phy Address to the TBI (TBIPA). + * Done also in cases where TBI is not selected to avoid conflict with + * the external PHY's Physical address + */ + iowrite32be(cfg->tbipa, ®s->tbipa); + + /***************TMR_CTL************************/ + iowrite32be(0, ®s->tmr_ctrl); + + if (cfg->ptp_tsu_en) { + tmp = 0; + tmp |= TMR_PEVENT_TSRE; + iowrite32be(tmp, ®s->tmr_pevent); + + if (cfg->ptp_exception_en) { + tmp = 0; + tmp |= TMR_PEMASK_TSREEN; + iowrite32be(tmp, ®s->tmr_pemask); + } + } + + /***************MACCFG1***********************/ + tmp = 0; + if (cfg->loopback) + tmp |= MACCFG1_LOOPBACK; + if (cfg->rx_flow) + tmp |= MACCFG1_RX_FLOW; + if (cfg->tx_flow) + tmp |= MACCFG1_TX_FLOW; + iowrite32be(tmp, ®s->maccfg1); + + /***************MACCFG1***********************/ + + /***************MACCFG2***********************/ + tmp = 0; + + if (iface_speed < E_ENET_SPEED_1000) + tmp |= MACCFG2_NIBBLE_MODE; + else if (iface_speed == E_ENET_SPEED_1000) + tmp |= MACCFG2_BYTE_MODE; + + tmp |= ((uint32_t) cfg->preamble_len & 0x0000000f) + << PREAMBLE_LENGTH_SHIFT; + + if (cfg->rx_preamble) + tmp |= MACCFG2_PRE_AM_Rx_EN; + if (cfg->tx_preamble) + tmp |= MACCFG2_PRE_AM_Tx_EN; + if (cfg->rx_len_check) + tmp |= MACCFG2_LENGTH_CHECK; + if (cfg->tx_pad_crc) + tmp |= MACCFG2_PAD_CRC_EN; + if (cfg->tx_crc) + tmp |= MACCFG2_CRC_EN; + if (!cfg->halfdup_on) + tmp |= MACCFG2_FULL_DUPLEX; + iowrite32be(tmp, ®s->maccfg2); + + /***************MACCFG2***********************/ + + /***************IPGIFG************************/ + tmp = (((cfg->non_back_to_back_ipg1 << + IPGIFG_NON_BACK_TO_BACK_IPG_1_SHIFT) + & IPGIFG_NON_BACK_TO_BACK_IPG_1) + | ((cfg->non_back_to_back_ipg2 << + IPGIFG_NON_BACK_TO_BACK_IPG_2_SHIFT) + & IPGIFG_NON_BACK_TO_BACK_IPG_2) + | ((cfg->min_ifg_enforcement << + IPGIFG_MIN_IFG_ENFORCEMENT_SHIFT) + & IPGIFG_MIN_IFG_ENFORCEMENT) + | (cfg->back_to_back_ipg & IPGIFG_BACK_TO_BACK_IPG)); + iowrite32be(tmp, ®s->ipgifg); + + /***************IPGIFG************************/ + + /***************HAFDUP************************/ + tmp = 0; + + if (cfg->halfdup_alt_backoff_en) + tmp = (uint32_t)(HAFDUP_ALT_BEB | + ((cfg->halfdup_alt_backoff_val & 0x0000000f) + << HAFDUP_ALTERNATE_BEB_TRUNCATION_SHIFT)); + if (cfg->halfdup_bp_no_backoff) + tmp |= HAFDUP_BP_NO_BACKOFF; + if (cfg->halfdup_no_backoff) + tmp |= HAFDUP_NO_BACKOFF; + if (cfg->halfdup_excess_defer) + tmp |= HAFDUP_EXCESS_DEFER; + tmp |= ((cfg->halfdup_retransmit << HAFDUP_RETRANSMISSION_MAX_SHIFT) + & HAFDUP_RETRANSMISSION_MAX); + tmp |= (cfg->halfdup_coll_window & HAFDUP_COLLISION_WINDOW); + + iowrite32be(tmp, ®s->hafdup); + /***************HAFDUP************************/ + + /***************MAXFRM************************/ + /* Initialize MAXFRM */ + iowrite32be(cfg->maximum_frame, ®s->maxfrm); + + /***************MAXFRM************************/ + + /***************CAM1************************/ + iowrite32be(0xffffffff, ®s->cam1); + iowrite32be(0xffffffff, ®s->cam2); + + /***************IMASK************************/ + iowrite32be(exception_mask, ®s->imask); + /***************IMASK************************/ + + /***************IEVENT************************/ + iowrite32be(0xffffffff, ®s->ievent); + + /***************MACSTNADDR1/2*****************/ + + tmp = (uint32_t)((macaddr[5] << 24) | + (macaddr[4] << 16) | + (macaddr[3] << 8) | + macaddr[2]); + iowrite32be(tmp, ®s->macstnaddr1); + + tmp = (uint32_t)((macaddr[1] << 24) | + (macaddr[0] << 16)); + iowrite32be(tmp, ®s->macstnaddr2); + + /***************MACSTNADDR1/2*****************/ + + /*****************HASH************************/ + for (i = 0; i < NUM_OF_HASH_REGS ; i++) { + /* Initialize IADDRx */ + iowrite32be(0, ®s->igaddr[i]); + /* Initialize GADDRx */ + iowrite32be(0, ®s->gaddr[i]); + } + + fman_dtsec_reset_stat(regs); + + return 0; +} + +uint16_t fman_dtsec_get_max_frame_len(struct dtsec_regs *regs) +{ + return (uint16_t)ioread32be(®s->maxfrm); +} + +void fman_dtsec_set_max_frame_len(struct dtsec_regs *regs, uint16_t length) +{ + iowrite32be(length, ®s->maxfrm); +} + +void fman_dtsec_set_mac_address(struct dtsec_regs *regs, uint8_t *adr) +{ + uint32_t tmp; + + tmp = (uint32_t)((adr[5] << 24) | + (adr[4] << 16) | + (adr[3] << 8) | + adr[2]); + iowrite32be(tmp, ®s->macstnaddr1); + + tmp = (uint32_t)((adr[1] << 24) | + (adr[0] << 16)); + iowrite32be(tmp, ®s->macstnaddr2); +} + +void fman_dtsec_get_mac_address(struct dtsec_regs *regs, uint8_t *macaddr) +{ + uint32_t tmp1, tmp2; + + tmp1 = ioread32be(®s->macstnaddr1); + tmp2 = ioread32be(®s->macstnaddr2); + + macaddr[0] = (uint8_t)((tmp2 & 0x00ff0000) >> 16); + macaddr[1] = (uint8_t)((tmp2 & 0xff000000) >> 24); + macaddr[2] = (uint8_t)(tmp1 & 0x000000ff); + macaddr[3] = (uint8_t)((tmp1 & 0x0000ff00) >> 8); + macaddr[4] = (uint8_t)((tmp1 & 0x00ff0000) >> 16); + macaddr[5] = (uint8_t)((tmp1 & 0xff000000) >> 24); +} + +void fman_dtsec_set_hash_table(struct dtsec_regs *regs, uint32_t crc, bool mcast, bool ghtx) +{ + int32_t bucket; + if (ghtx) + bucket = (int32_t)((crc >> 23) & 0x1ff); + else { + bucket = (int32_t)((crc >> 24) & 0xff); + /* if !ghtx and mcast the bit must be set in gaddr instead of igaddr. */ + if (mcast) + bucket += 0x100; + } + fman_dtsec_set_bucket(regs, bucket, TRUE); +} + +void fman_dtsec_set_bucket(struct dtsec_regs *regs, int bucket, bool enable) +{ + int reg_idx = (bucket >> 5) & 0xf; + int bit_idx = bucket & 0x1f; + uint32_t bit_mask = 0x80000000 >> bit_idx; + uint32_t *reg; + + if (reg_idx > 7) + reg = ®s->gaddr[reg_idx-8]; + else + reg = ®s->igaddr[reg_idx]; + + if (enable) + iowrite32be(ioread32be(reg) | bit_mask, reg); + else + iowrite32be(ioread32be(reg) & (~bit_mask), reg); +} + +void fman_dtsec_reset_filter_table(struct dtsec_regs *regs, bool mcast, bool ucast) +{ + int i; + bool ghtx; + + ghtx = (bool)((ioread32be(®s->rctrl) & RCTRL_GHTX) ? TRUE : FALSE); + + if (ucast || (ghtx && mcast)) { + for (i = 0; i < NUM_OF_HASH_REGS; i++) + iowrite32be(0, ®s->igaddr[i]); + } + if (mcast) { + for (i = 0; i < NUM_OF_HASH_REGS; i++) + iowrite32be(0, ®s->gaddr[i]); + } +} + +int fman_dtsec_set_tbi_phy_addr(struct dtsec_regs *regs, + uint8_t addr) +{ + if (addr > 0 && addr < 32) + iowrite32be(addr, ®s->tbipa); + else + return -EINVAL; + + return 0; +} + +void fman_dtsec_set_wol(struct dtsec_regs *regs, bool en) +{ + uint32_t tmp; + + tmp = ioread32be(®s->maccfg2); + if (en) + tmp |= MACCFG2_MAGIC_PACKET_EN; + else + tmp &= ~MACCFG2_MAGIC_PACKET_EN; + iowrite32be(tmp, ®s->maccfg2); +} + +int fman_dtsec_adjust_link(struct dtsec_regs *regs, + enum enet_interface iface_mode, + enum enet_speed speed, bool full_dx) +{ + uint32_t tmp; + + UNUSED(iface_mode); + + if ((speed == E_ENET_SPEED_1000) && !full_dx) + return -EINVAL; + + tmp = ioread32be(®s->maccfg2); + if (!full_dx) + tmp &= ~MACCFG2_FULL_DUPLEX; + else + tmp |= MACCFG2_FULL_DUPLEX; + + tmp &= ~(MACCFG2_NIBBLE_MODE | MACCFG2_BYTE_MODE); + if (speed < E_ENET_SPEED_1000) + tmp |= MACCFG2_NIBBLE_MODE; + else if (speed == E_ENET_SPEED_1000) + tmp |= MACCFG2_BYTE_MODE; + iowrite32be(tmp, ®s->maccfg2); + + tmp = ioread32be(®s->ecntrl); + if (speed == E_ENET_SPEED_100) + tmp |= DTSEC_ECNTRL_R100M; + else + tmp &= ~DTSEC_ECNTRL_R100M; + iowrite32be(tmp, ®s->ecntrl); + + return 0; +} + +void fman_dtsec_set_uc_promisc(struct dtsec_regs *regs, bool enable) +{ + uint32_t tmp; + + tmp = ioread32be(®s->rctrl); + + if (enable) + tmp |= RCTRL_UPROM; + else + tmp &= ~RCTRL_UPROM; + + iowrite32be(tmp, ®s->rctrl); +} + +void fman_dtsec_set_mc_promisc(struct dtsec_regs *regs, bool enable) +{ + uint32_t tmp; + + tmp = ioread32be(®s->rctrl); + + if (enable) + tmp |= RCTRL_MPROM; + else + tmp &= ~RCTRL_MPROM; + + iowrite32be(tmp, ®s->rctrl); +} + +bool fman_dtsec_get_clear_carry_regs(struct dtsec_regs *regs, + uint32_t *car1, uint32_t *car2) +{ + /* read carry registers */ + *car1 = ioread32be(®s->car1); + *car2 = ioread32be(®s->car2); + /* clear carry registers */ + if (*car1) + iowrite32be(*car1, ®s->car1); + if (*car2) + iowrite32be(*car2, ®s->car2); + + return (bool)((*car1 | *car2) ? TRUE : FALSE); +} + +void fman_dtsec_reset_stat(struct dtsec_regs *regs) +{ + /* clear HW counters */ + iowrite32be(ioread32be(®s->ecntrl) | + DTSEC_ECNTRL_CLRCNT, ®s->ecntrl); +} + +int fman_dtsec_set_stat_level(struct dtsec_regs *regs, enum dtsec_stat_level level) +{ + switch (level) { + case E_MAC_STAT_NONE: + iowrite32be(0xffffffff, ®s->cam1); + iowrite32be(0xffffffff, ®s->cam2); + iowrite32be(ioread32be(®s->ecntrl) & ~DTSEC_ECNTRL_STEN, + ®s->ecntrl); + iowrite32be(ioread32be(®s->imask) & ~DTSEC_IMASK_MSROEN, + ®s->imask); + break; + case E_MAC_STAT_PARTIAL: + iowrite32be(CAM1_ERRORS_ONLY, ®s->cam1); + iowrite32be(CAM2_ERRORS_ONLY, ®s->cam2); + iowrite32be(ioread32be(®s->ecntrl) | DTSEC_ECNTRL_STEN, + ®s->ecntrl); + iowrite32be(ioread32be(®s->imask) | DTSEC_IMASK_MSROEN, + ®s->imask); + break; + case E_MAC_STAT_MIB_GRP1: + iowrite32be((uint32_t)~CAM1_MIB_GRP_1, ®s->cam1); + iowrite32be((uint32_t)~CAM2_MIB_GRP_1, ®s->cam2); + iowrite32be(ioread32be(®s->ecntrl) | DTSEC_ECNTRL_STEN, + ®s->ecntrl); + iowrite32be(ioread32be(®s->imask) | DTSEC_IMASK_MSROEN, + ®s->imask); + break; + case E_MAC_STAT_FULL: + iowrite32be(0, ®s->cam1); + iowrite32be(0, ®s->cam2); + iowrite32be(ioread32be(®s->ecntrl) | DTSEC_ECNTRL_STEN, + ®s->ecntrl); + iowrite32be(ioread32be(®s->imask) | DTSEC_IMASK_MSROEN, + ®s->imask); + break; + default: + return -EINVAL; + } + + return 0; +} + +void fman_dtsec_set_ts(struct dtsec_regs *regs, bool en) +{ + if (en) { + iowrite32be(ioread32be(®s->rctrl) | RCTRL_RTSE, + ®s->rctrl); + iowrite32be(ioread32be(®s->tctrl) | DTSEC_TCTRL_TTSE, + ®s->tctrl); + } else { + iowrite32be(ioread32be(®s->rctrl) & ~RCTRL_RTSE, + ®s->rctrl); + iowrite32be(ioread32be(®s->tctrl) & ~DTSEC_TCTRL_TTSE, + ®s->tctrl); + } +} + +void fman_dtsec_enable(struct dtsec_regs *regs, bool apply_rx, bool apply_tx) +{ + uint32_t tmp; + + tmp = ioread32be(®s->maccfg1); + + if (apply_rx) + tmp |= MACCFG1_RX_EN ; + + if (apply_tx) + tmp |= MACCFG1_TX_EN ; + + iowrite32be(tmp, ®s->maccfg1); +} + +void fman_dtsec_clear_addr_in_paddr(struct dtsec_regs *regs, uint8_t paddr_num) +{ + iowrite32be(0, ®s->macaddr[paddr_num].exact_match1); + iowrite32be(0, ®s->macaddr[paddr_num].exact_match2); +} + +void fman_dtsec_add_addr_in_paddr(struct dtsec_regs *regs, + uint64_t addr, + uint8_t paddr_num) +{ + uint32_t tmp; + + tmp = (uint32_t)(addr); + /* swap */ + tmp = (((tmp & 0x000000FF) << 24) | + ((tmp & 0x0000FF00) << 8) | + ((tmp & 0x00FF0000) >> 8) | + ((tmp & 0xFF000000) >> 24)); + iowrite32be(tmp, ®s->macaddr[paddr_num].exact_match1); + + tmp = (uint32_t)(addr>>32); + /* swap */ + tmp = (((tmp & 0x000000FF) << 24) | + ((tmp & 0x0000FF00) << 8) | + ((tmp & 0x00FF0000) >> 8) | + ((tmp & 0xFF000000) >> 24)); + iowrite32be(tmp, ®s->macaddr[paddr_num].exact_match2); +} + +void fman_dtsec_disable(struct dtsec_regs *regs, bool apply_rx, bool apply_tx) +{ + uint32_t tmp; + + tmp = ioread32be(®s->maccfg1); + + if (apply_rx) + tmp &= ~MACCFG1_RX_EN; + + if (apply_tx) + tmp &= ~MACCFG1_TX_EN; + + iowrite32be(tmp, ®s->maccfg1); +} + +void fman_dtsec_set_tx_pause_frames(struct dtsec_regs *regs, uint16_t time) +{ + uint32_t ptv = 0; + + /* fixme: don't enable tx pause for half-duplex */ + + if (time) { + ptv = ioread32be(®s->ptv); + ptv &= 0xffff0000; + ptv |= time & 0x0000ffff; + iowrite32be(ptv, ®s->ptv); + + /* trigger the transmission of a flow-control pause frame */ + iowrite32be(ioread32be(®s->maccfg1) | MACCFG1_TX_FLOW, + ®s->maccfg1); + } else + iowrite32be(ioread32be(®s->maccfg1) & ~MACCFG1_TX_FLOW, + ®s->maccfg1); +} + +void fman_dtsec_handle_rx_pause(struct dtsec_regs *regs, bool en) +{ + uint32_t tmp; + + /* todo: check if mac is set to full-duplex */ + + tmp = ioread32be(®s->maccfg1); + if (en) + tmp |= MACCFG1_RX_FLOW; + else + tmp &= ~MACCFG1_RX_FLOW; + iowrite32be(tmp, ®s->maccfg1); +} + +uint32_t fman_dtsec_get_rctrl(struct dtsec_regs *regs) +{ + return ioread32be(®s->rctrl); +} + +uint32_t fman_dtsec_get_revision(struct dtsec_regs *regs) +{ + return ioread32be(®s->tsec_id); +} + +uint32_t fman_dtsec_get_event(struct dtsec_regs *regs, uint32_t ev_mask) +{ + return ioread32be(®s->ievent) & ev_mask; +} + +void fman_dtsec_ack_event(struct dtsec_regs *regs, uint32_t ev_mask) +{ + iowrite32be(ev_mask, ®s->ievent); +} + +uint32_t fman_dtsec_get_interrupt_mask(struct dtsec_regs *regs) +{ + return ioread32be(®s->imask); +} + +uint32_t fman_dtsec_check_and_clear_tmr_event(struct dtsec_regs *regs) +{ + uint32_t event; + + event = ioread32be(®s->tmr_pevent); + event &= ioread32be(®s->tmr_pemask); + + if (event) + iowrite32be(event, ®s->tmr_pevent); + return event; +} + +void fman_dtsec_enable_tmr_interrupt(struct dtsec_regs *regs) +{ + iowrite32be(ioread32be(®s->tmr_pemask) | TMR_PEMASK_TSREEN, + ®s->tmr_pemask); +} + +void fman_dtsec_disable_tmr_interrupt(struct dtsec_regs *regs) +{ + iowrite32be(ioread32be(®s->tmr_pemask) & ~TMR_PEMASK_TSREEN, + ®s->tmr_pemask); +} + +void fman_dtsec_enable_interrupt(struct dtsec_regs *regs, uint32_t ev_mask) +{ + iowrite32be(ioread32be(®s->imask) | ev_mask, ®s->imask); +} + +void fman_dtsec_disable_interrupt(struct dtsec_regs *regs, uint32_t ev_mask) +{ + iowrite32be(ioread32be(®s->imask) & ~ev_mask, ®s->imask); +} + +uint32_t fman_dtsec_get_stat_counter(struct dtsec_regs *regs, + enum dtsec_stat_counters reg_name) +{ + uint32_t ret_val; + + switch (reg_name) { + case E_DTSEC_STAT_TR64: + ret_val = ioread32be(®s->tr64); + break; + case E_DTSEC_STAT_TR127: + ret_val = ioread32be(®s->tr127); + break; + case E_DTSEC_STAT_TR255: + ret_val = ioread32be(®s->tr255); + break; + case E_DTSEC_STAT_TR511: + ret_val = ioread32be(®s->tr511); + break; + case E_DTSEC_STAT_TR1K: + ret_val = ioread32be(®s->tr1k); + break; + case E_DTSEC_STAT_TRMAX: + ret_val = ioread32be(®s->trmax); + break; + case E_DTSEC_STAT_TRMGV: + ret_val = ioread32be(®s->trmgv); + break; + case E_DTSEC_STAT_RBYT: + ret_val = ioread32be(®s->rbyt); + break; + case E_DTSEC_STAT_RPKT: + ret_val = ioread32be(®s->rpkt); + break; + case E_DTSEC_STAT_RMCA: + ret_val = ioread32be(®s->rmca); + break; + case E_DTSEC_STAT_RBCA: + ret_val = ioread32be(®s->rbca); + break; + case E_DTSEC_STAT_RXPF: + ret_val = ioread32be(®s->rxpf); + break; + case E_DTSEC_STAT_RALN: + ret_val = ioread32be(®s->raln); + break; + case E_DTSEC_STAT_RFLR: + ret_val = ioread32be(®s->rflr); + break; + case E_DTSEC_STAT_RCDE: + ret_val = ioread32be(®s->rcde); + break; + case E_DTSEC_STAT_RCSE: + ret_val = ioread32be(®s->rcse); + break; + case E_DTSEC_STAT_RUND: + ret_val = ioread32be(®s->rund); + break; + case E_DTSEC_STAT_ROVR: + ret_val = ioread32be(®s->rovr); + break; + case E_DTSEC_STAT_RFRG: + ret_val = ioread32be(®s->rfrg); + break; + case E_DTSEC_STAT_RJBR: + ret_val = ioread32be(®s->rjbr); + break; + case E_DTSEC_STAT_RDRP: + ret_val = ioread32be(®s->rdrp); + break; + case E_DTSEC_STAT_TFCS: + ret_val = ioread32be(®s->tfcs); + break; + case E_DTSEC_STAT_TBYT: + ret_val = ioread32be(®s->tbyt); + break; + case E_DTSEC_STAT_TPKT: + ret_val = ioread32be(®s->tpkt); + break; + case E_DTSEC_STAT_TMCA: + ret_val = ioread32be(®s->tmca); + break; + case E_DTSEC_STAT_TBCA: + ret_val = ioread32be(®s->tbca); + break; + case E_DTSEC_STAT_TXPF: + ret_val = ioread32be(®s->txpf); + break; + case E_DTSEC_STAT_TNCL: + ret_val = ioread32be(®s->tncl); + break; + case E_DTSEC_STAT_TDRP: + ret_val = ioread32be(®s->tdrp); + break; + default: + ret_val = 0; + } + + return ret_val; +} diff --git a/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MAC/fman_dtsec_mii_acc.c b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MAC/fman_dtsec_mii_acc.c new file mode 100644 index 000000000000..54e7b4a60669 --- /dev/null +++ b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MAC/fman_dtsec_mii_acc.c @@ -0,0 +1,165 @@ +/* + * Copyright 2008-2013 Freescale Semiconductor Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Freescale Semiconductor nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * + * ALTERNATIVELY, this software may be distributed under the terms of the + * GNU General Public License ("GPL") as published by the Free Software + * Foundation, either version 2 of that License or (at your option) any + * later version. + * + * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + +#include "std_ext.h" +#include "error_ext.h" +#include "common/general.h" +#include "fsl_fman_dtsec_mii_acc.h" + + +/** + * dtsec_mii_get_div() - calculates the value of the dtsec mii divider + * @dtsec_freq: dtsec clock frequency (in Mhz) + * + * This function calculates the dtsec mii clock divider that determines + * the MII MDC clock. MII MDC clock will be set to work in the range + * of 1.5 to 2.5Mhz + * The output of this function is the value of MIIMCFG[MgmtClk] which + * implicitly determines the divider value. + * Note: the dTSEC system clock is equal to 1/2 of the FMan clock. + * + * The table below which reflects dtsec_mii_get_div() functionality + * shows the relations among dtsec_freq, MgmtClk, actual divider + * and the MII frequency: + * + * dtsec freq MgmtClk div MII freq Mhz + * [0.....80] 1 (1/4)(1/8) [0 to 2.5] + * [81...120] 2 (1/6)(1/8) [1.6 to 2.5] + * [121..160] 3 (1/8)(1/8) [1.8 to 2.5] + * [161..200] 4 (1/10)(1/8) [2.0 to 2.5] + * [201..280] 5 (1/14)(1/8) [1.8 to 2.5] + * [281..400] 6 (1/20)(1/8) [1.1 to 2.5] + * [401..560] 7 (1/28)(1/8) [1.8 to 2.5] + * [560..frq] 7 (1/28)(1/8) [frq/224] + * + * Returns: the MIIMCFG[MgmtClk] appropriate value + */ + +static uint8_t dtsec_mii_get_div(uint16_t dtsec_freq) +{ + uint16_t mgmt_clk; + + if (dtsec_freq < 80) mgmt_clk = 1; + else if (dtsec_freq < 120) mgmt_clk = 2; + else if (dtsec_freq < 160) mgmt_clk = 3; + else if (dtsec_freq < 200) mgmt_clk = 4; + else if (dtsec_freq < 280) mgmt_clk = 5; + else if (dtsec_freq < 400) mgmt_clk = 6; + else mgmt_clk = 7; + + return (uint8_t)mgmt_clk; +} + +void fman_dtsec_mii_reset(struct dtsec_mii_reg *regs) +{ + /* Reset the management interface */ + iowrite32be(ioread32be(®s->miimcfg) | MIIMCFG_RESET_MGMT, + ®s->miimcfg); + iowrite32be(ioread32be(®s->miimcfg) & ~MIIMCFG_RESET_MGMT, + ®s->miimcfg); +} + + +int fman_dtsec_mii_write_reg(struct dtsec_mii_reg *regs, uint8_t addr, + uint8_t reg, uint16_t data, uint16_t dtsec_freq) +{ + uint32_t tmp; + + /* Setup the MII Mgmt clock speed */ + iowrite32be((uint32_t)dtsec_mii_get_div(dtsec_freq), ®s->miimcfg); + wmb(); + + /* Stop the MII management read cycle */ + iowrite32be(0, ®s->miimcom); + /* Dummy read to make sure MIIMCOM is written */ + tmp = ioread32be(®s->miimcom); + wmb(); + + /* Setting up MII Management Address Register */ + tmp = (uint32_t)((addr << MIIMADD_PHY_ADDR_SHIFT) | reg); + iowrite32be(tmp, ®s->miimadd); + wmb(); + + /* Setting up MII Management Control Register with data */ + iowrite32be((uint32_t)data, ®s->miimcon); + /* Dummy read to make sure MIIMCON is written */ + tmp = ioread32be(®s->miimcon); + wmb(); + + /* Wait until MII management write is complete */ + /* todo: a timeout could be useful here */ + while ((ioread32be(®s->miimind)) & MIIMIND_BUSY) + /* busy wait */; + + return 0; +} + +int fman_dtsec_mii_read_reg(struct dtsec_mii_reg *regs, uint8_t addr, + uint8_t reg, uint16_t *data, uint16_t dtsec_freq) +{ + uint32_t tmp; + + /* Setup the MII Mgmt clock speed */ + iowrite32be((uint32_t)dtsec_mii_get_div(dtsec_freq), ®s->miimcfg); + wmb(); + + /* Setting up the MII Management Address Register */ + tmp = (uint32_t)((addr << MIIMADD_PHY_ADDR_SHIFT) | reg); + iowrite32be(tmp, ®s->miimadd); + wmb(); + + /* Perform an MII management read cycle */ + iowrite32be(MIIMCOM_READ_CYCLE, ®s->miimcom); + /* Dummy read to make sure MIIMCOM is written */ + tmp = ioread32be(®s->miimcom); + wmb(); + + /* Wait until MII management read is complete */ + /* todo: a timeout could be useful here */ + while ((ioread32be(®s->miimind)) & MIIMIND_BUSY) + /* busy wait */; + + /* Read MII management status */ + *data = (uint16_t)ioread32be(®s->miimstat); + wmb(); + + iowrite32be(0, ®s->miimcom); + /* Dummy read to make sure MIIMCOM is written */ + tmp = ioread32be(®s->miimcom); + + if (*data == 0xffff) + return -ENXIO; + + return 0; +} + diff --git a/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MAC/fman_memac.c b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MAC/fman_memac.c new file mode 100644 index 000000000000..f31a92a2bc0b --- /dev/null +++ b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MAC/fman_memac.c @@ -0,0 +1,532 @@ +/* + * Copyright 2008-2012 Freescale Semiconductor Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Freescale Semiconductor nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * + * ALTERNATIVELY, this software may be distributed under the terms of the + * GNU General Public License ("GPL") as published by the Free Software + * Foundation, either version 2 of that License or (at your option) any + * later version. + * + * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + +#include "fsl_fman_memac.h" + + +uint32_t fman_memac_get_event(struct memac_regs *regs, uint32_t ev_mask) +{ + return ioread32be(®s->ievent) & ev_mask; +} + +uint32_t fman_memac_get_interrupt_mask(struct memac_regs *regs) +{ + return ioread32be(®s->imask); +} + +void fman_memac_ack_event(struct memac_regs *regs, uint32_t ev_mask) +{ + iowrite32be(ev_mask, ®s->ievent); +} + +void fman_memac_set_promiscuous(struct memac_regs *regs, bool val) +{ + uint32_t tmp; + + tmp = ioread32be(®s->command_config); + + if (val) + tmp |= CMD_CFG_PROMIS_EN; + else + tmp &= ~CMD_CFG_PROMIS_EN; + + iowrite32be(tmp, ®s->command_config); +} + +void fman_memac_clear_addr_in_paddr(struct memac_regs *regs, + uint8_t paddr_num) +{ + if (paddr_num == 0) { + iowrite32be(0, ®s->mac_addr0.mac_addr_l); + iowrite32be(0, ®s->mac_addr0.mac_addr_u); + } else { + iowrite32be(0x0, ®s->mac_addr[paddr_num - 1].mac_addr_l); + iowrite32be(0x0, ®s->mac_addr[paddr_num - 1].mac_addr_u); + } +} + +void fman_memac_add_addr_in_paddr(struct memac_regs *regs, + uint8_t *adr, + uint8_t paddr_num) +{ + uint32_t tmp0, tmp1; + + tmp0 = (uint32_t)(adr[0] | + adr[1] << 8 | + adr[2] << 16 | + adr[3] << 24); + tmp1 = (uint32_t)(adr[4] | adr[5] << 8); + + if (paddr_num == 0) { + iowrite32be(tmp0, ®s->mac_addr0.mac_addr_l); + iowrite32be(tmp1, ®s->mac_addr0.mac_addr_u); + } else { + iowrite32be(tmp0, ®s->mac_addr[paddr_num-1].mac_addr_l); + iowrite32be(tmp1, ®s->mac_addr[paddr_num-1].mac_addr_u); + } +} + +void fman_memac_enable(struct memac_regs *regs, bool apply_rx, bool apply_tx) +{ + uint32_t tmp; + + tmp = ioread32be(®s->command_config); + + if (apply_rx) + tmp |= CMD_CFG_RX_EN; + + if (apply_tx) + tmp |= CMD_CFG_TX_EN; + + iowrite32be(tmp, ®s->command_config); +} + +void fman_memac_disable(struct memac_regs *regs, bool apply_rx, bool apply_tx) +{ + uint32_t tmp; + + tmp = ioread32be(®s->command_config); + + if (apply_rx) + tmp &= ~CMD_CFG_RX_EN; + + if (apply_tx) + tmp &= ~CMD_CFG_TX_EN; + + iowrite32be(tmp, ®s->command_config); +} + +void fman_memac_reset_stat(struct memac_regs *regs) +{ + uint32_t tmp; + + tmp = ioread32be(®s->statn_config); + + tmp |= STATS_CFG_CLR; + + iowrite32be(tmp, ®s->statn_config); + + while (ioread32be(®s->statn_config) & STATS_CFG_CLR); +} + +void fman_memac_reset(struct memac_regs *regs) +{ + uint32_t tmp; + + tmp = ioread32be(®s->command_config); + + tmp |= CMD_CFG_SW_RESET; + + iowrite32be(tmp, ®s->command_config); + + while (ioread32be(®s->command_config) & CMD_CFG_SW_RESET); +} + +int fman_memac_init(struct memac_regs *regs, + struct memac_cfg *cfg, + enum enet_interface enet_interface, + enum enet_speed enet_speed, + bool slow_10g_if, + uint32_t exceptions) +{ + uint32_t tmp; + + /* Config */ + tmp = 0; + if (cfg->wan_mode_enable) + tmp |= CMD_CFG_WAN_MODE; + if (cfg->promiscuous_mode_enable) + tmp |= CMD_CFG_PROMIS_EN; + if (cfg->pause_forward_enable) + tmp |= CMD_CFG_PAUSE_FWD; + if (cfg->pause_ignore) + tmp |= CMD_CFG_PAUSE_IGNORE; + if (cfg->tx_addr_ins_enable) + tmp |= CMD_CFG_TX_ADDR_INS; + if (cfg->loopback_enable) + tmp |= CMD_CFG_LOOPBACK_EN; + if (cfg->cmd_frame_enable) + tmp |= CMD_CFG_CNT_FRM_EN; + if (cfg->send_idle_enable) + tmp |= CMD_CFG_SEND_IDLE; + if (cfg->no_length_check_enable) + tmp |= CMD_CFG_NO_LEN_CHK; + if (cfg->rx_sfd_any) + tmp |= CMD_CFG_SFD_ANY; + if (cfg->pad_enable) + tmp |= CMD_CFG_TX_PAD_EN; + if (cfg->wake_on_lan) + tmp |= CMD_CFG_MG; + + tmp |= CMD_CFG_CRC_FWD; + + iowrite32be(tmp, ®s->command_config); + + /* Max Frame Length */ + iowrite32be((uint32_t)cfg->max_frame_length, ®s->maxfrm); + + /* Pause Time */ + iowrite32be((uint32_t)cfg->pause_quanta, ®s->pause_quanta[0]); + iowrite32be((uint32_t)0, ®s->pause_thresh[0]); + + /* IF_MODE */ + tmp = 0; + switch (enet_interface) { + case E_ENET_IF_XGMII: + case E_ENET_IF_XFI: + tmp |= IF_MODE_XGMII; + break; + default: + tmp |= IF_MODE_GMII; + if (enet_interface == E_ENET_IF_RGMII && !cfg->loopback_enable) + tmp |= IF_MODE_RGMII | IF_MODE_RGMII_AUTO; + } + iowrite32be(tmp, ®s->if_mode); + + /* TX_FIFO_SECTIONS */ + tmp = 0; + if (enet_interface == E_ENET_IF_XGMII || + enet_interface == E_ENET_IF_XFI) { + if(slow_10g_if) { + tmp |= (TX_FIFO_SECTIONS_TX_AVAIL_SLOW_10G | + TX_FIFO_SECTIONS_TX_EMPTY_DEFAULT_10G); + } else { + tmp |= (TX_FIFO_SECTIONS_TX_AVAIL_10G | + TX_FIFO_SECTIONS_TX_EMPTY_DEFAULT_10G); + } + } else { + tmp |= (TX_FIFO_SECTIONS_TX_AVAIL_1G | + TX_FIFO_SECTIONS_TX_EMPTY_DEFAULT_1G); + } + iowrite32be(tmp, ®s->tx_fifo_sections); + + /* clear all pending events and set-up interrupts */ + fman_memac_ack_event(regs, 0xffffffff); + fman_memac_set_exception(regs, exceptions, TRUE); + + return 0; +} + +void fman_memac_set_exception(struct memac_regs *regs, uint32_t val, bool enable) +{ + uint32_t tmp; + + tmp = ioread32be(®s->imask); + if (enable) + tmp |= val; + else + tmp &= ~val; + + iowrite32be(tmp, ®s->imask); +} + +void fman_memac_reset_filter_table(struct memac_regs *regs) +{ + uint32_t i; + for (i = 0; i < 64; i++) + iowrite32be(i & ~HASH_CTRL_MCAST_EN, ®s->hashtable_ctrl); +} + +void fman_memac_set_hash_table_entry(struct memac_regs *regs, uint32_t crc) +{ + iowrite32be(crc | HASH_CTRL_MCAST_EN, ®s->hashtable_ctrl); +} + +void fman_memac_set_hash_table(struct memac_regs *regs, uint32_t val) +{ + iowrite32be(val, ®s->hashtable_ctrl); +} + +uint16_t fman_memac_get_max_frame_len(struct memac_regs *regs) +{ + uint32_t tmp; + + tmp = ioread32be(®s->maxfrm); + + return(uint16_t)tmp; +} + + +void fman_memac_set_tx_pause_frames(struct memac_regs *regs, + uint8_t priority, + uint16_t pause_time, + uint16_t thresh_time) +{ + uint32_t tmp; + + tmp = ioread32be(®s->tx_fifo_sections); + + if (priority == 0xff) { + GET_TX_EMPTY_DEFAULT_VALUE(tmp); + iowrite32be(tmp, ®s->tx_fifo_sections); + + tmp = ioread32be(®s->command_config); + tmp &= ~CMD_CFG_PFC_MODE; + priority = 0; + } else { + GET_TX_EMPTY_PFC_VALUE(tmp); + iowrite32be(tmp, ®s->tx_fifo_sections); + + tmp = ioread32be(®s->command_config); + tmp |= CMD_CFG_PFC_MODE; + } + + iowrite32be(tmp, ®s->command_config); + + tmp = ioread32be(®s->pause_quanta[priority / 2]); + if (priority % 2) + tmp &= 0x0000FFFF; + else + tmp &= 0xFFFF0000; + tmp |= ((uint32_t)pause_time << (16 * (priority % 2))); + iowrite32be(tmp, ®s->pause_quanta[priority / 2]); + + tmp = ioread32be(®s->pause_thresh[priority / 2]); + if (priority % 2) + tmp &= 0x0000FFFF; + else + tmp &= 0xFFFF0000; + tmp |= ((uint32_t)thresh_time<<(16 * (priority % 2))); + iowrite32be(tmp, ®s->pause_thresh[priority / 2]); +} + +void fman_memac_set_rx_ignore_pause_frames(struct memac_regs *regs,bool enable) +{ + uint32_t tmp; + + tmp = ioread32be(®s->command_config); + if (enable) + tmp |= CMD_CFG_PAUSE_IGNORE; + else + tmp &= ~CMD_CFG_PAUSE_IGNORE; + + iowrite32be(tmp, ®s->command_config); +} + +void fman_memac_set_wol(struct memac_regs *regs, bool enable) +{ + uint32_t tmp; + + tmp = ioread32be(®s->command_config); + + if (enable) + tmp |= CMD_CFG_MG; + else + tmp &= ~CMD_CFG_MG; + + iowrite32be(tmp, ®s->command_config); +} + +#define GET_MEMAC_CNTR_64(bn) \ + (ioread32be(®s->bn ## _l) | \ + ((uint64_t)ioread32be(®s->bn ## _u) << 32)) + +uint64_t fman_memac_get_counter(struct memac_regs *regs, + enum memac_counters reg_name) +{ + uint64_t ret_val; + + switch (reg_name) { + case E_MEMAC_COUNTER_R64: + ret_val = GET_MEMAC_CNTR_64(r64); + break; + case E_MEMAC_COUNTER_T64: + ret_val = GET_MEMAC_CNTR_64(t64); + break; + case E_MEMAC_COUNTER_R127: + ret_val = GET_MEMAC_CNTR_64(r127); + break; + case E_MEMAC_COUNTER_T127: + ret_val = GET_MEMAC_CNTR_64(t127); + break; + case E_MEMAC_COUNTER_R255: + ret_val = GET_MEMAC_CNTR_64(r255); + break; + case E_MEMAC_COUNTER_T255: + ret_val = GET_MEMAC_CNTR_64(t255); + break; + case E_MEMAC_COUNTER_R511: + ret_val = GET_MEMAC_CNTR_64(r511); + break; + case E_MEMAC_COUNTER_T511: + ret_val = GET_MEMAC_CNTR_64(t511); + break; + case E_MEMAC_COUNTER_R1023: + ret_val = GET_MEMAC_CNTR_64(r1023); + break; + case E_MEMAC_COUNTER_T1023: + ret_val = GET_MEMAC_CNTR_64(t1023); + break; + case E_MEMAC_COUNTER_R1518: + ret_val = GET_MEMAC_CNTR_64(r1518); + break; + case E_MEMAC_COUNTER_T1518: + ret_val = GET_MEMAC_CNTR_64(t1518); + break; + case E_MEMAC_COUNTER_R1519X: + ret_val = GET_MEMAC_CNTR_64(r1519x); + break; + case E_MEMAC_COUNTER_T1519X: + ret_val = GET_MEMAC_CNTR_64(t1519x); + break; + case E_MEMAC_COUNTER_RFRG: + ret_val = GET_MEMAC_CNTR_64(rfrg); + break; + case E_MEMAC_COUNTER_RJBR: + ret_val = GET_MEMAC_CNTR_64(rjbr); + break; + case E_MEMAC_COUNTER_RDRP: + ret_val = GET_MEMAC_CNTR_64(rdrp); + break; + case E_MEMAC_COUNTER_RALN: + ret_val = GET_MEMAC_CNTR_64(raln); + break; + case E_MEMAC_COUNTER_TUND: + ret_val = GET_MEMAC_CNTR_64(tund); + break; + case E_MEMAC_COUNTER_ROVR: + ret_val = GET_MEMAC_CNTR_64(rovr); + break; + case E_MEMAC_COUNTER_RXPF: + ret_val = GET_MEMAC_CNTR_64(rxpf); + break; + case E_MEMAC_COUNTER_TXPF: + ret_val = GET_MEMAC_CNTR_64(txpf); + break; + case E_MEMAC_COUNTER_ROCT: + ret_val = GET_MEMAC_CNTR_64(roct); + break; + case E_MEMAC_COUNTER_RMCA: + ret_val = GET_MEMAC_CNTR_64(rmca); + break; + case E_MEMAC_COUNTER_RBCA: + ret_val = GET_MEMAC_CNTR_64(rbca); + break; + case E_MEMAC_COUNTER_RPKT: + ret_val = GET_MEMAC_CNTR_64(rpkt); + break; + case E_MEMAC_COUNTER_RUCA: + ret_val = GET_MEMAC_CNTR_64(ruca); + break; + case E_MEMAC_COUNTER_RERR: + ret_val = GET_MEMAC_CNTR_64(rerr); + break; + case E_MEMAC_COUNTER_TOCT: + ret_val = GET_MEMAC_CNTR_64(toct); + break; + case E_MEMAC_COUNTER_TMCA: + ret_val = GET_MEMAC_CNTR_64(tmca); + break; + case E_MEMAC_COUNTER_TBCA: + ret_val = GET_MEMAC_CNTR_64(tbca); + break; + case E_MEMAC_COUNTER_TUCA: + ret_val = GET_MEMAC_CNTR_64(tuca); + break; + case E_MEMAC_COUNTER_TERR: + ret_val = GET_MEMAC_CNTR_64(terr); + break; + default: + ret_val = 0; + } + + return ret_val; +} + +void fman_memac_adjust_link(struct memac_regs *regs, + enum enet_interface iface_mode, + enum enet_speed speed, bool full_dx) +{ + uint32_t tmp; + + tmp = ioread32be(®s->if_mode); + + if (full_dx) + tmp &= ~IF_MODE_HD; + else + tmp |= IF_MODE_HD; + + if (iface_mode == E_ENET_IF_RGMII) { + /* Configure RGMII in manual mode */ + tmp &= ~IF_MODE_RGMII_AUTO; + tmp &= ~IF_MODE_RGMII_SP_MASK; + + if (full_dx) + tmp |= IF_MODE_RGMII_FD; + else + tmp &= ~IF_MODE_RGMII_FD; + + switch (speed) { + case E_ENET_SPEED_1000: + tmp |= IF_MODE_RGMII_1000; + break; + case E_ENET_SPEED_100: + tmp |= IF_MODE_RGMII_100; + break; + case E_ENET_SPEED_10: + tmp |= IF_MODE_RGMII_10; + break; + default: + break; + } + } + + iowrite32be(tmp, ®s->if_mode); +} + +void fman_memac_defconfig(struct memac_cfg *cfg) +{ + cfg->reset_on_init = FALSE; + cfg->wan_mode_enable = FALSE; + cfg->promiscuous_mode_enable = FALSE; + cfg->pause_forward_enable = FALSE; + cfg->pause_ignore = FALSE; + cfg->tx_addr_ins_enable = FALSE; + cfg->loopback_enable = FALSE; + cfg->cmd_frame_enable = FALSE; + cfg->rx_error_discard = FALSE; + cfg->send_idle_enable = FALSE; + cfg->no_length_check_enable = TRUE; + cfg->lgth_check_nostdr = FALSE; + cfg->time_stamp_enable = FALSE; + cfg->tx_ipg_length = DEFAULT_TX_IPG_LENGTH; + cfg->max_frame_length = DEFAULT_FRAME_LENGTH; + cfg->pause_quanta = DEFAULT_PAUSE_QUANTA; + cfg->pad_enable = TRUE; + cfg->phy_tx_ena_on = FALSE; + cfg->rx_sfd_any = FALSE; + cfg->rx_pbl_fwd = FALSE; + cfg->tx_pbl_fwd = FALSE; + cfg->debug_mode = FALSE; + cfg->wake_on_lan = FALSE; +} diff --git a/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MAC/fman_memac_mii_acc.c b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MAC/fman_memac_mii_acc.c new file mode 100755 index 000000000000..e785e4c111af --- /dev/null +++ b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MAC/fman_memac_mii_acc.c @@ -0,0 +1,215 @@ +/* + * Copyright 2008-2013 Freescale Semiconductor Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Freescale Semiconductor nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * + * ALTERNATIVELY, this software may be distributed under the terms of the + * GNU General Public License ("GPL") as published by the Free Software + * Foundation, either version 2 of that License or (at your option) any + * later version. + * + * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + +#include "std_ext.h" +#include "error_ext.h" +#include "fsl_fman_memac_mii_acc.h" + +static void write_phy_reg_10g(struct memac_mii_access_mem_map *mii_regs, + uint8_t phy_addr, uint8_t reg, uint16_t data) +{ + uint32_t tmp_reg; + + tmp_reg = ioread32be(&mii_regs->mdio_cfg); + /* Leave only MDIO_CLK_DIV bits set on */ + tmp_reg &= MDIO_CFG_CLK_DIV_MASK; + /* Set maximum MDIO_HOLD value to allow phy to see + change of data signal */ + tmp_reg |= MDIO_CFG_HOLD_MASK; + /* Add 10G interface mode */ + tmp_reg |= MDIO_CFG_ENC45; + iowrite32be(tmp_reg, &mii_regs->mdio_cfg); + + /* Wait for command completion */ + while ((ioread32be(&mii_regs->mdio_cfg)) & MDIO_CFG_BSY) + udelay(1); + + /* Specify phy and register to be accessed */ + iowrite32be(phy_addr, &mii_regs->mdio_ctrl); + iowrite32be(reg, &mii_regs->mdio_addr); + wmb(); + + while ((ioread32be(&mii_regs->mdio_cfg)) & MDIO_CFG_BSY) + udelay(1); + + /* Write data */ + iowrite32be(data, &mii_regs->mdio_data); + wmb(); + + /* Wait for write transaction end */ + while ((ioread32be(&mii_regs->mdio_data)) & MDIO_DATA_BSY) + udelay(1); +} + +static uint32_t read_phy_reg_10g(struct memac_mii_access_mem_map *mii_regs, + uint8_t phy_addr, uint8_t reg, uint16_t *data) +{ + uint32_t tmp_reg; + + tmp_reg = ioread32be(&mii_regs->mdio_cfg); + /* Leave only MDIO_CLK_DIV bits set on */ + tmp_reg &= MDIO_CFG_CLK_DIV_MASK; + /* Set maximum MDIO_HOLD value to allow phy to see + change of data signal */ + tmp_reg |= MDIO_CFG_HOLD_MASK; + /* Add 10G interface mode */ + tmp_reg |= MDIO_CFG_ENC45; + iowrite32be(tmp_reg, &mii_regs->mdio_cfg); + + /* Wait for command completion */ + while ((ioread32be(&mii_regs->mdio_cfg)) & MDIO_CFG_BSY) + udelay(1); + + /* Specify phy and register to be accessed */ + iowrite32be(phy_addr, &mii_regs->mdio_ctrl); + iowrite32be(reg, &mii_regs->mdio_addr); + wmb(); + + while ((ioread32be(&mii_regs->mdio_cfg)) & MDIO_CFG_BSY) + udelay(1); + + /* Read cycle */ + tmp_reg = phy_addr; + tmp_reg |= MDIO_CTL_READ; + iowrite32be(tmp_reg, &mii_regs->mdio_ctrl); + wmb(); + + /* Wait for data to be available */ + while ((ioread32be(&mii_regs->mdio_data)) & MDIO_DATA_BSY) + udelay(1); + + *data = (uint16_t)ioread32be(&mii_regs->mdio_data); + + /* Check if there was an error */ + return ioread32be(&mii_regs->mdio_cfg); +} + +static void write_phy_reg_1g(struct memac_mii_access_mem_map *mii_regs, + uint8_t phy_addr, uint8_t reg, uint16_t data) +{ + uint32_t tmp_reg; + + /* Leave only MDIO_CLK_DIV and MDIO_HOLD bits set on */ + tmp_reg = ioread32be(&mii_regs->mdio_cfg); + tmp_reg &= (MDIO_CFG_CLK_DIV_MASK | MDIO_CFG_HOLD_MASK); + iowrite32be(tmp_reg, &mii_regs->mdio_cfg); + + /* Wait for command completion */ + while ((ioread32be(&mii_regs->mdio_cfg)) & MDIO_CFG_BSY) + udelay(1); + + /* Write transaction */ + tmp_reg = (phy_addr << MDIO_CTL_PHY_ADDR_SHIFT); + tmp_reg |= reg; + iowrite32be(tmp_reg, &mii_regs->mdio_ctrl); + + while ((ioread32be(&mii_regs->mdio_cfg)) & MDIO_CFG_BSY) + udelay(1); + + iowrite32be(data, &mii_regs->mdio_data); + + wmb(); + + /* Wait for write transaction to end */ + while ((ioread32be(&mii_regs->mdio_data)) & MDIO_DATA_BSY) + udelay(1); +} + +static uint32_t read_phy_reg_1g(struct memac_mii_access_mem_map *mii_regs, + uint8_t phy_addr, uint8_t reg, uint16_t *data) +{ + uint32_t tmp_reg; + + /* Leave only MDIO_CLK_DIV and MDIO_HOLD bits set on */ + tmp_reg = ioread32be(&mii_regs->mdio_cfg); + tmp_reg &= (MDIO_CFG_CLK_DIV_MASK | MDIO_CFG_HOLD_MASK); + iowrite32be(tmp_reg, &mii_regs->mdio_cfg); + + /* Wait for command completion */ + while ((ioread32be(&mii_regs->mdio_cfg)) & MDIO_CFG_BSY) + udelay(1); + + /* Read transaction */ + tmp_reg = (phy_addr << MDIO_CTL_PHY_ADDR_SHIFT); + tmp_reg |= reg; + tmp_reg |= MDIO_CTL_READ; + iowrite32be(tmp_reg, &mii_regs->mdio_ctrl); + + while ((ioread32be(&mii_regs->mdio_cfg)) & MDIO_CFG_BSY) + udelay(1); + + /* Wait for data to be available */ + while ((ioread32be(&mii_regs->mdio_data)) & MDIO_DATA_BSY) + udelay(1); + + *data = (uint16_t)ioread32be(&mii_regs->mdio_data); + + /* Check error */ + return ioread32be(&mii_regs->mdio_cfg); +} + +/*****************************************************************************/ +int fman_memac_mii_write_phy_reg(struct memac_mii_access_mem_map *mii_regs, + uint8_t phy_addr, uint8_t reg, uint16_t data, + enum enet_speed enet_speed) +{ + /* Figure out interface type - 10G vs 1G. + In 10G interface both phy_addr and devAddr present. */ + if (enet_speed == E_ENET_SPEED_10000) + write_phy_reg_10g(mii_regs, phy_addr, reg, data); + else + write_phy_reg_1g(mii_regs, phy_addr, reg, data); + + return 0; +} + +/*****************************************************************************/ +int fman_memac_mii_read_phy_reg(struct memac_mii_access_mem_map *mii_regs, + uint8_t phy_addr, uint8_t reg, uint16_t *data, + enum enet_speed enet_speed) +{ + uint32_t ans; + /* Figure out interface type - 10G vs 1G. + In 10G interface both phy_addr and devAddr present. */ + if (enet_speed == E_ENET_SPEED_10000) + ans = read_phy_reg_10g(mii_regs, phy_addr, reg, data); + else + ans = read_phy_reg_1g(mii_regs, phy_addr, reg, data); + + if (ans & MDIO_CFG_READ_ERR) + return -EINVAL; + return 0; +} + +/* ......................................................................... */ + diff --git a/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MAC/fman_tgec.c b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MAC/fman_tgec.c new file mode 100644 index 000000000000..fff9d5de80e3 --- /dev/null +++ b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MAC/fman_tgec.c @@ -0,0 +1,367 @@ +/* + * Copyright 2008-2012 Freescale Semiconductor Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Freescale Semiconductor nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * + * ALTERNATIVELY, this software may be distributed under the terms of the + * GNU General Public License ("GPL") as published by the Free Software + * Foundation, either version 2 of that License or (at your option) any + * later version. + * + * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + +#include "fsl_fman_tgec.h" + + +void fman_tgec_set_mac_address(struct tgec_regs *regs, uint8_t *adr) +{ + uint32_t tmp0, tmp1; + + tmp0 = (uint32_t)(adr[0] | + adr[1] << 8 | + adr[2] << 16 | + adr[3] << 24); + tmp1 = (uint32_t)(adr[4] | adr[5] << 8); + iowrite32be(tmp0, ®s->mac_addr_0); + iowrite32be(tmp1, ®s->mac_addr_1); +} + +void fman_tgec_reset_stat(struct tgec_regs *regs) +{ + uint32_t tmp; + + tmp = ioread32be(®s->command_config); + + tmp |= CMD_CFG_STAT_CLR; + + iowrite32be(tmp, ®s->command_config); + + while (ioread32be(®s->command_config) & CMD_CFG_STAT_CLR) ; +} + +#define GET_TGEC_CNTR_64(bn) \ + (((uint64_t)ioread32be(®s->bn ## _u) << 32) | \ + ioread32be(®s->bn ## _l)) + +uint64_t fman_tgec_get_counter(struct tgec_regs *regs, enum tgec_counters reg_name) +{ + uint64_t ret_val; + + switch (reg_name) { + case E_TGEC_COUNTER_R64: + ret_val = GET_TGEC_CNTR_64(r64); + break; + case E_TGEC_COUNTER_R127: + ret_val = GET_TGEC_CNTR_64(r127); + break; + case E_TGEC_COUNTER_R255: + ret_val = GET_TGEC_CNTR_64(r255); + break; + case E_TGEC_COUNTER_R511: + ret_val = GET_TGEC_CNTR_64(r511); + break; + case E_TGEC_COUNTER_R1023: + ret_val = GET_TGEC_CNTR_64(r1023); + break; + case E_TGEC_COUNTER_R1518: + ret_val = GET_TGEC_CNTR_64(r1518); + break; + case E_TGEC_COUNTER_R1519X: + ret_val = GET_TGEC_CNTR_64(r1519x); + break; + case E_TGEC_COUNTER_TRFRG: + ret_val = GET_TGEC_CNTR_64(trfrg); + break; + case E_TGEC_COUNTER_TRJBR: + ret_val = GET_TGEC_CNTR_64(trjbr); + break; + case E_TGEC_COUNTER_RDRP: + ret_val = GET_TGEC_CNTR_64(rdrp); + break; + case E_TGEC_COUNTER_RALN: + ret_val = GET_TGEC_CNTR_64(raln); + break; + case E_TGEC_COUNTER_TRUND: + ret_val = GET_TGEC_CNTR_64(trund); + break; + case E_TGEC_COUNTER_TROVR: + ret_val = GET_TGEC_CNTR_64(trovr); + break; + case E_TGEC_COUNTER_RXPF: + ret_val = GET_TGEC_CNTR_64(rxpf); + break; + case E_TGEC_COUNTER_TXPF: + ret_val = GET_TGEC_CNTR_64(txpf); + break; + case E_TGEC_COUNTER_ROCT: + ret_val = GET_TGEC_CNTR_64(roct); + break; + case E_TGEC_COUNTER_RMCA: + ret_val = GET_TGEC_CNTR_64(rmca); + break; + case E_TGEC_COUNTER_RBCA: + ret_val = GET_TGEC_CNTR_64(rbca); + break; + case E_TGEC_COUNTER_RPKT: + ret_val = GET_TGEC_CNTR_64(rpkt); + break; + case E_TGEC_COUNTER_RUCA: + ret_val = GET_TGEC_CNTR_64(ruca); + break; + case E_TGEC_COUNTER_RERR: + ret_val = GET_TGEC_CNTR_64(rerr); + break; + case E_TGEC_COUNTER_TOCT: + ret_val = GET_TGEC_CNTR_64(toct); + break; + case E_TGEC_COUNTER_TMCA: + ret_val = GET_TGEC_CNTR_64(tmca); + break; + case E_TGEC_COUNTER_TBCA: + ret_val = GET_TGEC_CNTR_64(tbca); + break; + case E_TGEC_COUNTER_TUCA: + ret_val = GET_TGEC_CNTR_64(tuca); + break; + case E_TGEC_COUNTER_TERR: + ret_val = GET_TGEC_CNTR_64(terr); + break; + default: + ret_val = 0; + } + + return ret_val; +} + +void fman_tgec_enable(struct tgec_regs *regs, bool apply_rx, bool apply_tx) +{ + uint32_t tmp; + + tmp = ioread32be(®s->command_config); + if (apply_rx) + tmp |= CMD_CFG_RX_EN; + if (apply_tx) + tmp |= CMD_CFG_TX_EN; + iowrite32be(tmp, ®s->command_config); +} + +void fman_tgec_disable(struct tgec_regs *regs, bool apply_rx, bool apply_tx) +{ + uint32_t tmp_reg_32; + + tmp_reg_32 = ioread32be(®s->command_config); + if (apply_rx) + tmp_reg_32 &= ~CMD_CFG_RX_EN; + if (apply_tx) + tmp_reg_32 &= ~CMD_CFG_TX_EN; + iowrite32be(tmp_reg_32, ®s->command_config); +} + +void fman_tgec_set_promiscuous(struct tgec_regs *regs, bool val) +{ + uint32_t tmp; + + tmp = ioread32be(®s->command_config); + if (val) + tmp |= CMD_CFG_PROMIS_EN; + else + tmp &= ~CMD_CFG_PROMIS_EN; + iowrite32be(tmp, ®s->command_config); +} + +void fman_tgec_reset_filter_table(struct tgec_regs *regs) +{ + uint32_t i; + for (i = 0; i < 512; i++) + iowrite32be(i & ~TGEC_HASH_MCAST_EN, ®s->hashtable_ctrl); +} + +void fman_tgec_set_hash_table_entry(struct tgec_regs *regs, uint32_t crc) +{ + uint32_t hash = (crc >> TGEC_HASH_MCAST_SHIFT) & TGEC_HASH_ADR_MSK; /* Take 9 MSB bits */ + iowrite32be(hash | TGEC_HASH_MCAST_EN, ®s->hashtable_ctrl); +} + +void fman_tgec_set_hash_table(struct tgec_regs *regs, uint32_t value) +{ + iowrite32be(value, ®s->hashtable_ctrl); +} + +void fman_tgec_set_tx_pause_frames(struct tgec_regs *regs, uint16_t pause_time) +{ + iowrite32be((uint32_t)pause_time, ®s->pause_quant); +} + +void fman_tgec_set_rx_ignore_pause_frames(struct tgec_regs *regs, bool en) +{ + uint32_t tmp; + + tmp = ioread32be(®s->command_config); + if (en) + tmp |= CMD_CFG_PAUSE_IGNORE; + else + tmp &= ~CMD_CFG_PAUSE_IGNORE; + iowrite32be(tmp, ®s->command_config); +} + +void fman_tgec_enable_1588_time_stamp(struct tgec_regs *regs, bool en) +{ + uint32_t tmp; + + tmp = ioread32be(®s->command_config); + if (en) + tmp |= CMD_CFG_EN_TIMESTAMP; + else + tmp &= ~CMD_CFG_EN_TIMESTAMP; + iowrite32be(tmp, ®s->command_config); +} + +uint32_t fman_tgec_get_event(struct tgec_regs *regs, uint32_t ev_mask) +{ + return ioread32be(®s->ievent) & ev_mask; +} + +void fman_tgec_ack_event(struct tgec_regs *regs, uint32_t ev_mask) +{ + iowrite32be(ev_mask, ®s->ievent); +} + +uint32_t fman_tgec_get_interrupt_mask(struct tgec_regs *regs) +{ + return ioread32be(®s->imask); +} + +void fman_tgec_add_addr_in_paddr(struct tgec_regs *regs, uint8_t *adr) +{ + uint32_t tmp0, tmp1; + + tmp0 = (uint32_t)(adr[0] | + adr[1] << 8 | + adr[2] << 16 | + adr[3] << 24); + tmp1 = (uint32_t)(adr[4] | adr[5] << 8); + iowrite32be(tmp0, ®s->mac_addr_2); + iowrite32be(tmp1, ®s->mac_addr_3); +} + +void fman_tgec_clear_addr_in_paddr(struct tgec_regs *regs) +{ + iowrite32be(0, ®s->mac_addr_2); + iowrite32be(0, ®s->mac_addr_3); +} + +uint32_t fman_tgec_get_revision(struct tgec_regs *regs) +{ + return ioread32be(®s->tgec_id); +} + +void fman_tgec_enable_interrupt(struct tgec_regs *regs, uint32_t ev_mask) +{ + iowrite32be(ioread32be(®s->imask) | ev_mask, ®s->imask); +} + +void fman_tgec_disable_interrupt(struct tgec_regs *regs, uint32_t ev_mask) +{ + iowrite32be(ioread32be(®s->imask) & ~ev_mask, ®s->imask); +} + +uint16_t fman_tgec_get_max_frame_len(struct tgec_regs *regs) +{ + return (uint16_t) ioread32be(®s->maxfrm); +} + +void fman_tgec_defconfig(struct tgec_cfg *cfg) +{ + cfg->wan_mode_enable = DEFAULT_WAN_MODE_ENABLE; + cfg->promiscuous_mode_enable = DEFAULT_PROMISCUOUS_MODE_ENABLE; + cfg->pause_forward_enable = DEFAULT_PAUSE_FORWARD_ENABLE; + cfg->pause_ignore = DEFAULT_PAUSE_IGNORE; + cfg->tx_addr_ins_enable = DEFAULT_TX_ADDR_INS_ENABLE; + cfg->loopback_enable = DEFAULT_LOOPBACK_ENABLE; + cfg->cmd_frame_enable = DEFAULT_CMD_FRAME_ENABLE; + cfg->rx_error_discard = DEFAULT_RX_ERROR_DISCARD; + cfg->send_idle_enable = DEFAULT_SEND_IDLE_ENABLE; + cfg->no_length_check_enable = DEFAULT_NO_LENGTH_CHECK_ENABLE; + cfg->lgth_check_nostdr = DEFAULT_LGTH_CHECK_NOSTDR; + cfg->time_stamp_enable = DEFAULT_TIME_STAMP_ENABLE; + cfg->tx_ipg_length = DEFAULT_TX_IPG_LENGTH; + cfg->max_frame_length = DEFAULT_MAX_FRAME_LENGTH; + cfg->pause_quant = DEFAULT_PAUSE_QUANT; +#ifdef FM_TX_ECC_FRMS_ERRATA_10GMAC_A004 + cfg->skip_fman11_workaround = FALSE; +#endif /* FM_TX_ECC_FRMS_ERRATA_10GMAC_A004 */ +} + +int fman_tgec_init(struct tgec_regs *regs, struct tgec_cfg *cfg, + uint32_t exception_mask) +{ + uint32_t tmp; + + /* Config */ + tmp = 0x40; /* CRC forward */ + if (cfg->wan_mode_enable) + tmp |= CMD_CFG_WAN_MODE; + if (cfg->promiscuous_mode_enable) + tmp |= CMD_CFG_PROMIS_EN; + if (cfg->pause_forward_enable) + tmp |= CMD_CFG_PAUSE_FWD; + if (cfg->pause_ignore) + tmp |= CMD_CFG_PAUSE_IGNORE; + if (cfg->tx_addr_ins_enable) + tmp |= CMD_CFG_TX_ADDR_INS; + if (cfg->loopback_enable) + tmp |= CMD_CFG_LOOPBACK_EN; + if (cfg->cmd_frame_enable) + tmp |= CMD_CFG_CMD_FRM_EN; + if (cfg->rx_error_discard) + tmp |= CMD_CFG_RX_ER_DISC; + if (cfg->send_idle_enable) + tmp |= CMD_CFG_SEND_IDLE; + if (cfg->no_length_check_enable) + tmp |= CMD_CFG_NO_LEN_CHK; + if (cfg->time_stamp_enable) + tmp |= CMD_CFG_EN_TIMESTAMP; + iowrite32be(tmp, ®s->command_config); + + /* Max Frame Length */ + iowrite32be((uint32_t)cfg->max_frame_length, ®s->maxfrm); + /* Pause Time */ + iowrite32be(cfg->pause_quant, ®s->pause_quant); + + /* clear all pending events and set-up interrupts */ + fman_tgec_ack_event(regs, 0xffffffff); + fman_tgec_enable_interrupt(regs, exception_mask); + + return 0; +} + +void fman_tgec_set_erratum_tx_fifo_corruption_10gmac_a007(struct tgec_regs *regs) +{ + uint32_t tmp; + + /* restore the default tx ipg Length */ + tmp = (ioread32be(®s->tx_ipg_len) & ~TGEC_TX_IPG_LENGTH_MASK) | 12; + + iowrite32be(tmp, ®s->tx_ipg_len); +} diff --git a/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MAC/memac.c b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MAC/memac.c new file mode 100644 index 000000000000..0d86f5b05a35 --- /dev/null +++ b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MAC/memac.c @@ -0,0 +1,1159 @@ +/* + * Copyright 2008-2012 Freescale Semiconductor Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Freescale Semiconductor nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * + * ALTERNATIVELY, this software may be distributed under the terms of the + * GNU General Public License ("GPL") as published by the Free Software + * Foundation, either version 2 of that License or (at your option) any + * later version. + * + * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + +/****************************************************************************** + @File memac.c + + @Description FM mEMAC driver +*//***************************************************************************/ + +#include "std_ext.h" +#include "string_ext.h" +#include "error_ext.h" +#include "xx_ext.h" +#include "endian_ext.h" +#include "debug_ext.h" + +#include "fm_common.h" +#include "memac.h" + + +/*****************************************************************************/ +/* Internal routines */ +/*****************************************************************************/ + +/* ......................................................................... */ + +static uint32_t GetMacAddrHashCode(uint64_t ethAddr) +{ + uint64_t mask1, mask2; + uint32_t xorVal = 0; + uint8_t i, j; + + for (i=0; i<6; i++) + { + mask1 = ethAddr & (uint64_t)0x01; + ethAddr >>= 1; + + for (j=0; j<7; j++) + { + mask2 = ethAddr & (uint64_t)0x01; + mask1 ^= mask2; + ethAddr >>= 1; + } + + xorVal |= (mask1 << (5-i)); + } + + return xorVal; +} + +/* ......................................................................... */ + +static void SetupSgmiiInternalPhy(t_Memac *p_Memac, uint8_t phyAddr) +{ + uint16_t tmpReg16; + e_EnetMode enetMode; + bool autoneg_disabled = p_Memac->enetMode == e_ENET_MODE_SGMII_2500; + + /* In case the higher MACs are used (i.e. the MACs that should support 10G), + speed=10000 is provided for SGMII ports. Temporary modify enet mode + to 1G one, so MII functions can work correctly. */ + enetMode = p_Memac->enetMode; + + /* SGMII mode + AN enable */ + tmpReg16 = PHY_SGMII_IF_MODE_AN | PHY_SGMII_IF_MODE_SGMII; + /* unless SGMII 2500 where AN needs to be disabled */ + if (autoneg_disabled) + tmpReg16 = PHY_SGMII_IF_SPEED_GIGABIT | PHY_SGMII_IF_MODE_SGMII; + + p_Memac->enetMode = MAKE_ENET_MODE(ENET_INTERFACE_FROM_MODE(p_Memac->enetMode), e_ENET_SPEED_1000); + MEMAC_MII_WritePhyReg(p_Memac, phyAddr, 0x14, tmpReg16); + + /* Device ability according to SGMII specification */ + tmpReg16 = PHY_SGMII_DEV_ABILITY_SGMII; + MEMAC_MII_WritePhyReg(p_Memac, phyAddr, 0x4, tmpReg16); + + /* Adjust link timer for SGMII - + According to Cisco SGMII specification the timer should be 1.6 ms. + The link_timer register is configured in units of the clock. + - When running as 1G SGMII, Serdes clock is 125 MHz, so + unit = 1 / (125*10^6 Hz) = 8 ns. + 1.6 ms in units of 8 ns = 1.6ms / 8ns = 2 * 10^5 = 0x30d40 + - When running as 2.5G SGMII, Serdes clock is 312.5 MHz, so + unit = 1 / (312.5*10^6 Hz) = 3.2 ns. + 1.6 ms in units of 3.2 ns = 1.6ms / 3.2ns = 5 * 10^5 = 0x7a120. + Since link_timer value of 1G SGMII will be too short for 2.5 SGMII, + we always set up here a value of 2.5 SGMII. */ + MEMAC_MII_WritePhyReg(p_Memac, phyAddr, 0x13, 0x0007); + MEMAC_MII_WritePhyReg(p_Memac, phyAddr, 0x12, 0xa120); + + if (!autoneg_disabled) + /* Restart AN */ + tmpReg16 = PHY_SGMII_CR_DEF_VAL | PHY_SGMII_CR_RESET_AN; + else + /* Disable AN */ + tmpReg16 = PHY_SGMII_CR_DEF_VAL & ~PHY_SGMII_CR_AN_EN; + MEMAC_MII_WritePhyReg(p_Memac, phyAddr, 0x0, tmpReg16); + + /* Restore original enet mode */ + p_Memac->enetMode = enetMode; +} + +/* ......................................................................... */ + +static void SetupSgmiiInternalPhyBaseX(t_Memac *p_Memac, uint8_t phyAddr) +{ + uint16_t tmpReg16; + e_EnetMode enetMode; + + /* In case the higher MACs are used (i.e. the MACs that should support 10G), + speed=10000 is provided for SGMII ports. Temporary modify enet mode + to 1G one, so MII functions can work correctly. */ + enetMode = p_Memac->enetMode; + p_Memac->enetMode = MAKE_ENET_MODE(ENET_INTERFACE_FROM_MODE(p_Memac->enetMode), e_ENET_SPEED_1000); + + /* 1000BaseX mode */ + tmpReg16 = PHY_SGMII_IF_MODE_1000X; + MEMAC_MII_WritePhyReg(p_Memac, phyAddr, 0x14, tmpReg16); + + /* AN Device capability */ + tmpReg16 = PHY_SGMII_DEV_ABILITY_1000X; + MEMAC_MII_WritePhyReg(p_Memac, phyAddr, 0x4, tmpReg16); + + /* Adjust link timer for SGMII - + For Serdes 1000BaseX auto-negotiation the timer should be 10 ms. + The link_timer register is configured in units of the clock. + - When running as 1G SGMII, Serdes clock is 125 MHz, so + unit = 1 / (125*10^6 Hz) = 8 ns. + 10 ms in units of 8 ns = 10ms / 8ns = 1250000 = 0x1312d0 + - When running as 2.5G SGMII, Serdes clock is 312.5 MHz, so + unit = 1 / (312.5*10^6 Hz) = 3.2 ns. + 10 ms in units of 3.2 ns = 10ms / 3.2ns = 3125000 = 0x2faf08. + Since link_timer value of 1G SGMII will be too short for 2.5 SGMII, + we always set up here a value of 2.5 SGMII. */ + MEMAC_MII_WritePhyReg(p_Memac, phyAddr, 0x13, 0x002f); + MEMAC_MII_WritePhyReg(p_Memac, phyAddr, 0x12, 0xaf08); + + /* Restart AN */ + tmpReg16 = PHY_SGMII_CR_DEF_VAL | PHY_SGMII_CR_RESET_AN; + MEMAC_MII_WritePhyReg(p_Memac, phyAddr, 0x0, tmpReg16); + + /* Restore original enet mode */ + p_Memac->enetMode = enetMode; +} + +/* ......................................................................... */ + +static t_Error CheckInitParameters(t_Memac *p_Memac) +{ + e_FmMacType portType; + + portType = ((ENET_SPEED_FROM_MODE(p_Memac->enetMode) < e_ENET_SPEED_10000) ? e_FM_MAC_1G : e_FM_MAC_10G); + +#if (FM_MAX_NUM_OF_10G_MACS > 0) + if ((portType == e_FM_MAC_10G) && (p_Memac->macId >= FM_MAX_NUM_OF_10G_MACS)) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("10G MAC ID must be less than %d", FM_MAX_NUM_OF_10G_MACS)); +#endif /* (FM_MAX_NUM_OF_10G_MACS > 0) */ + + if ((portType == e_FM_MAC_1G) && (p_Memac->macId >= FM_MAX_NUM_OF_1G_MACS)) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("1G MAC ID must be less than %d", FM_MAX_NUM_OF_1G_MACS)); + if (p_Memac->addr == 0) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("Ethernet MAC must have a valid MAC address")); + if (!p_Memac->f_Exception) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("Uninitialized f_Exception")); + if (!p_Memac->f_Event) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("Uninitialized f_Event")); +#ifdef FM_LEN_CHECK_ERRATA_FMAN_SW002 + if (!p_Memac->p_MemacDriverParam->no_length_check_enable) + RETURN_ERROR(MINOR, E_NOT_SUPPORTED, ("LengthCheck!")); +#endif /* FM_LEN_CHECK_ERRATA_FMAN_SW002 */ + + return E_OK; +} + +/* ........................................................................... */ + +static void MemacErrException(t_Handle h_Memac) +{ + t_Memac *p_Memac = (t_Memac *)h_Memac; + uint32_t event, imask; + + event = fman_memac_get_event(p_Memac->p_MemMap, 0xffffffff); + imask = fman_memac_get_interrupt_mask(p_Memac->p_MemMap); + + /* Imask include both error and notification/event bits. + Leaving only error bits enabled by imask. + The imask error bits are shifted by 16 bits offset from + their corresponding location in the ievent - hence the >> 16 */ + event &= ((imask & MEMAC_ALL_ERRS_IMASK) >> 16); + + fman_memac_ack_event(p_Memac->p_MemMap, event); + + if (event & MEMAC_IEVNT_TS_ECC_ER) + p_Memac->f_Exception(p_Memac->h_App, e_FM_MAC_EX_TS_FIFO_ECC_ERR); + if (event & MEMAC_IEVNT_TX_ECC_ER) + p_Memac->f_Exception(p_Memac->h_App, e_FM_MAC_EX_10G_1TX_ECC_ER); + if (event & MEMAC_IEVNT_RX_ECC_ER) + p_Memac->f_Exception(p_Memac->h_App, e_FM_MAC_EX_10G_RX_ECC_ER); +} + +static void MemacException(t_Handle h_Memac) +{ + t_Memac *p_Memac = (t_Memac *)h_Memac; + uint32_t event, imask; + + event = fman_memac_get_event(p_Memac->p_MemMap, 0xffffffff); + imask = fman_memac_get_interrupt_mask(p_Memac->p_MemMap); + + /* Imask include both error and notification/event bits. + Leaving only error bits enabled by imask. + The imask error bits are shifted by 16 bits offset from + their corresponding location in the ievent - hence the >> 16 */ + event &= ((imask & MEMAC_ALL_ERRS_IMASK) >> 16); + + fman_memac_ack_event(p_Memac->p_MemMap, event); + + if (event & MEMAC_IEVNT_MGI) + p_Memac->f_Exception(p_Memac->h_App, e_FM_MAC_EX_MAGIC_PACKET_INDICATION); +} + +/* ......................................................................... */ + +static void FreeInitResources(t_Memac *p_Memac) +{ + e_FmMacType portType; + + portType = + ((ENET_SPEED_FROM_MODE(p_Memac->enetMode) < e_ENET_SPEED_10000) ? e_FM_MAC_1G : e_FM_MAC_10G); + + if (portType == e_FM_MAC_10G) + FmUnregisterIntr(p_Memac->fmMacControllerDriver.h_Fm, e_FM_MOD_10G_MAC, p_Memac->macId, e_FM_INTR_TYPE_ERR); + else + FmUnregisterIntr(p_Memac->fmMacControllerDriver.h_Fm, e_FM_MOD_1G_MAC, p_Memac->macId, e_FM_INTR_TYPE_ERR); + + /* release the driver's group hash table */ + FreeHashTable(p_Memac->p_MulticastAddrHash); + p_Memac->p_MulticastAddrHash = NULL; + + /* release the driver's individual hash table */ + FreeHashTable(p_Memac->p_UnicastAddrHash); + p_Memac->p_UnicastAddrHash = NULL; +} + + +/*****************************************************************************/ +/* mEMAC API routines */ +/*****************************************************************************/ + +/* ......................................................................... */ + +static t_Error MemacEnable(t_Handle h_Memac, e_CommMode mode) +{ + t_Memac *p_Memac = (t_Memac *)h_Memac; + + SANITY_CHECK_RETURN_ERROR(p_Memac, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(!p_Memac->p_MemacDriverParam, E_INVALID_STATE); + + fman_memac_enable(p_Memac->p_MemMap, (mode & e_COMM_MODE_RX), (mode & e_COMM_MODE_TX)); + + return E_OK; +} + +/* ......................................................................... */ + +static t_Error MemacDisable (t_Handle h_Memac, e_CommMode mode) +{ + t_Memac *p_Memac = (t_Memac *)h_Memac; + + SANITY_CHECK_RETURN_ERROR(p_Memac, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(!p_Memac->p_MemacDriverParam, E_INVALID_STATE); + + fman_memac_disable(p_Memac->p_MemMap, (mode & e_COMM_MODE_RX), (mode & e_COMM_MODE_TX)); + + return E_OK; +} + +/* ......................................................................... */ + +static t_Error MemacSetPromiscuous(t_Handle h_Memac, bool newVal) +{ + t_Memac *p_Memac = (t_Memac *)h_Memac; + + SANITY_CHECK_RETURN_ERROR(p_Memac, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(!p_Memac->p_MemacDriverParam, E_INVALID_STATE); + + fman_memac_set_promiscuous(p_Memac->p_MemMap, newVal); + + return E_OK; +} + +/* .............................................................................. */ + +static t_Error MemacAdjustLink(t_Handle h_Memac, e_EnetSpeed speed, bool fullDuplex) +{ + t_Memac *p_Memac = (t_Memac *)h_Memac; + + SANITY_CHECK_RETURN_ERROR(p_Memac, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(!p_Memac->p_MemacDriverParam, E_INVALID_STATE); + + if ((speed >= e_ENET_SPEED_1000) && (!fullDuplex)) + RETURN_ERROR(MAJOR, E_CONFLICT, + ("Ethernet MAC 1G or 10G does not support half-duplex")); + + fman_memac_adjust_link(p_Memac->p_MemMap, + (enum enet_interface)ENET_INTERFACE_FROM_MODE(p_Memac->enetMode), + (enum enet_speed)speed, + fullDuplex); + return E_OK; +} + + +/*****************************************************************************/ +/* Memac Configs modification functions */ +/*****************************************************************************/ + +/* ......................................................................... */ + +static t_Error MemacConfigLoopback(t_Handle h_Memac, bool newVal) +{ + t_Memac *p_Memac = (t_Memac *)h_Memac; + + SANITY_CHECK_RETURN_ERROR(p_Memac, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_Memac->p_MemacDriverParam, E_INVALID_STATE); + + p_Memac->p_MemacDriverParam->loopback_enable = newVal; + + return E_OK; +} + +/* ......................................................................... */ + +static t_Error MemacConfigWan(t_Handle h_Memac, bool newVal) +{ + t_Memac *p_Memac = (t_Memac *)h_Memac; + + SANITY_CHECK_RETURN_ERROR(p_Memac, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_Memac->p_MemacDriverParam, E_INVALID_STATE); + + p_Memac->p_MemacDriverParam->wan_mode_enable = newVal; + + return E_OK; +} + +/* ......................................................................... */ + +static t_Error MemacConfigMaxFrameLength(t_Handle h_Memac, uint16_t newVal) +{ + t_Memac *p_Memac = (t_Memac *)h_Memac; + + SANITY_CHECK_RETURN_ERROR(p_Memac, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_Memac->p_MemacDriverParam, E_INVALID_STATE); + + p_Memac->p_MemacDriverParam->max_frame_length = newVal; + + return E_OK; +} + +/* ......................................................................... */ + +static t_Error MemacConfigPad(t_Handle h_Memac, bool newVal) +{ + t_Memac *p_Memac = (t_Memac *)h_Memac; + + SANITY_CHECK_RETURN_ERROR(p_Memac, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_Memac->p_MemacDriverParam, E_INVALID_STATE); + + p_Memac->p_MemacDriverParam->pad_enable = newVal; + + return E_OK; +} + +/* ......................................................................... */ + +static t_Error MemacConfigLengthCheck(t_Handle h_Memac, bool newVal) +{ + t_Memac *p_Memac = (t_Memac *)h_Memac; + + SANITY_CHECK_RETURN_ERROR(p_Memac, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_Memac->p_MemacDriverParam, E_INVALID_STATE); + + p_Memac->p_MemacDriverParam->no_length_check_enable = !newVal; + + return E_OK; +} + +/* ......................................................................... */ + +static t_Error MemacConfigException(t_Handle h_Memac, e_FmMacExceptions exception, bool enable) +{ + t_Memac *p_Memac = (t_Memac *)h_Memac; + uint32_t bitMask = 0; + + SANITY_CHECK_RETURN_ERROR(p_Memac, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_Memac->p_MemacDriverParam, E_INVALID_STATE); + + GET_EXCEPTION_FLAG(bitMask, exception); + if (bitMask) + { + if (enable) + p_Memac->exceptions |= bitMask; + else + p_Memac->exceptions &= ~bitMask; + } + else + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("Undefined exception")); + + return E_OK; +} + +/* ......................................................................... */ + +static t_Error MemacConfigResetOnInit(t_Handle h_Memac, bool enable) +{ + t_Memac *p_Memac = (t_Memac *)h_Memac; + + SANITY_CHECK_RETURN_ERROR(p_Memac, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_Memac->p_MemacDriverParam, E_INVALID_STATE); + + p_Memac->p_MemacDriverParam->reset_on_init = enable; + + return E_OK; +} + + +/*****************************************************************************/ +/* Memac Run Time API functions */ +/*****************************************************************************/ + +/* ......................................................................... */ + +static t_Error MemacSetTxPauseFrames(t_Handle h_Memac, + uint8_t priority, + uint16_t pauseTime, + uint16_t threshTime) +{ + t_Memac *p_Memac = (t_Memac *)h_Memac; + + SANITY_CHECK_RETURN_ERROR(p_Memac, E_INVALID_STATE); + SANITY_CHECK_RETURN_ERROR(!p_Memac->p_MemacDriverParam, E_INVALID_STATE); + + if (priority != 0xFF) + { + bool PortConfigured, PreFetchEnabled; + + if (FmGetTnumAgingPeriod(p_Memac->fmMacControllerDriver.h_Fm) == 0) + RETURN_ERROR(MAJOR, E_CONFLICT, ("For PFC operation, TNUM aging must be enabled")); + + FmGetPortPreFetchConfiguration(p_Memac->fmMacControllerDriver.h_Fm, + p_Memac->fmMacControllerDriver.macId, + &PortConfigured, + &PreFetchEnabled); + + if ((ENET_SPEED_FROM_MODE(p_Memac->fmMacControllerDriver.enetMode) == e_ENET_SPEED_1000) && !PortConfigured) + DBG(INFO, ("For PFC correct operation, prefetch must be configured on the FM Tx PORT")); + + if ((ENET_SPEED_FROM_MODE(p_Memac->fmMacControllerDriver.enetMode) == e_ENET_SPEED_1000) && PortConfigured && !PreFetchEnabled) + DBG(WARNING, ("For PFC correct operation, prefetch must be configured on the FM Tx PORT")); + } + + fman_memac_set_tx_pause_frames(p_Memac->p_MemMap, priority, pauseTime, threshTime); + + return E_OK; +} + +/* ......................................................................... */ + +static t_Error MemacSetTxAutoPauseFrames(t_Handle h_Memac, + uint16_t pauseTime) +{ + return MemacSetTxPauseFrames(h_Memac, FM_MAC_NO_PFC, pauseTime, 0); +} + +/* ......................................................................... */ + +static t_Error MemacSetRxIgnorePauseFrames(t_Handle h_Memac, bool en) +{ + t_Memac *p_Memac = (t_Memac *)h_Memac; + + SANITY_CHECK_RETURN_ERROR(p_Memac, E_INVALID_STATE); + SANITY_CHECK_RETURN_ERROR(!p_Memac->p_MemacDriverParam, E_INVALID_STATE); + + fman_memac_set_rx_ignore_pause_frames(p_Memac->p_MemMap, en); + + return E_OK; +} + +/* ......................................................................... */ + +static t_Error MemacSetWakeOnLan(t_Handle h_Memac, bool en) +{ + t_Memac *p_Memac = (t_Memac *)h_Memac; + + SANITY_CHECK_RETURN_ERROR(p_Memac, E_INVALID_STATE); + SANITY_CHECK_RETURN_ERROR(!p_Memac->p_MemacDriverParam, E_INVALID_STATE); + + fman_memac_set_wol(p_Memac->p_MemMap, en); + + return E_OK; +} + +/* .............................................................................. */ + +static t_Error MemacEnable1588TimeStamp(t_Handle h_Memac) +{ + t_Memac *p_Memac = (t_Memac *)h_Memac; + + SANITY_CHECK_RETURN_ERROR(p_Memac, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(!p_Memac->p_MemacDriverParam, E_INVALID_STATE); +UNUSED(p_Memac); +DBG(WARNING, ("mEMAC has 1588 always enabled!")); + + return E_OK; +} + +/* Counters handling */ +/* ......................................................................... */ + +static t_Error MemacGetStatistics(t_Handle h_Memac, t_FmMacStatistics *p_Statistics) +{ + t_Memac *p_Memac = (t_Memac *)h_Memac; + + SANITY_CHECK_RETURN_ERROR(p_Memac, E_NULL_POINTER); + SANITY_CHECK_RETURN_ERROR(!p_Memac->p_MemacDriverParam, E_INVALID_STATE); + SANITY_CHECK_RETURN_ERROR(p_Statistics, E_NULL_POINTER); + + p_Statistics->eStatPkts64 = fman_memac_get_counter(p_Memac->p_MemMap, E_MEMAC_COUNTER_R64); + p_Statistics->eStatPkts65to127 = fman_memac_get_counter(p_Memac->p_MemMap, E_MEMAC_COUNTER_R127); + p_Statistics->eStatPkts128to255 = fman_memac_get_counter(p_Memac->p_MemMap, E_MEMAC_COUNTER_R255); + p_Statistics->eStatPkts256to511 = fman_memac_get_counter(p_Memac->p_MemMap, E_MEMAC_COUNTER_R511); + p_Statistics->eStatPkts512to1023 = fman_memac_get_counter(p_Memac->p_MemMap, E_MEMAC_COUNTER_R1023); + p_Statistics->eStatPkts1024to1518 = fman_memac_get_counter(p_Memac->p_MemMap, E_MEMAC_COUNTER_R1518); + p_Statistics->eStatPkts1519to1522 = fman_memac_get_counter(p_Memac->p_MemMap, E_MEMAC_COUNTER_R1519X); +/* */ + p_Statistics->eStatFragments = fman_memac_get_counter(p_Memac->p_MemMap, E_MEMAC_COUNTER_RFRG); + p_Statistics->eStatJabbers = fman_memac_get_counter(p_Memac->p_MemMap, E_MEMAC_COUNTER_RJBR); + + p_Statistics->eStatsDropEvents = fman_memac_get_counter(p_Memac->p_MemMap, E_MEMAC_COUNTER_RDRP); + p_Statistics->eStatCRCAlignErrors = fman_memac_get_counter(p_Memac->p_MemMap, E_MEMAC_COUNTER_RALN); + + p_Statistics->eStatUndersizePkts = fman_memac_get_counter(p_Memac->p_MemMap, E_MEMAC_COUNTER_TUND); + p_Statistics->eStatOversizePkts = fman_memac_get_counter(p_Memac->p_MemMap, E_MEMAC_COUNTER_ROVR); +/* Pause */ + p_Statistics->reStatPause = fman_memac_get_counter(p_Memac->p_MemMap, E_MEMAC_COUNTER_RXPF); + p_Statistics->teStatPause = fman_memac_get_counter(p_Memac->p_MemMap, E_MEMAC_COUNTER_TXPF); + +/* MIB II */ + p_Statistics->ifInOctets = fman_memac_get_counter(p_Memac->p_MemMap, E_MEMAC_COUNTER_ROCT); + p_Statistics->ifInUcastPkts = fman_memac_get_counter(p_Memac->p_MemMap, E_MEMAC_COUNTER_RUCA); + p_Statistics->ifInMcastPkts = fman_memac_get_counter(p_Memac->p_MemMap, E_MEMAC_COUNTER_RMCA); + p_Statistics->ifInBcastPkts = fman_memac_get_counter(p_Memac->p_MemMap, E_MEMAC_COUNTER_RBCA); + p_Statistics->ifInPkts = p_Statistics->ifInUcastPkts + + p_Statistics->ifInMcastPkts + + p_Statistics->ifInBcastPkts; + p_Statistics->ifInDiscards = 0; + p_Statistics->ifInErrors = fman_memac_get_counter(p_Memac->p_MemMap, E_MEMAC_COUNTER_RERR); + + p_Statistics->ifOutOctets = fman_memac_get_counter(p_Memac->p_MemMap, E_MEMAC_COUNTER_TOCT); + p_Statistics->ifOutUcastPkts = fman_memac_get_counter(p_Memac->p_MemMap, E_MEMAC_COUNTER_TUCA); + p_Statistics->ifOutMcastPkts = fman_memac_get_counter(p_Memac->p_MemMap, E_MEMAC_COUNTER_TMCA); + p_Statistics->ifOutBcastPkts = fman_memac_get_counter(p_Memac->p_MemMap, E_MEMAC_COUNTER_TBCA); + p_Statistics->ifOutPkts = p_Statistics->ifOutUcastPkts + + p_Statistics->ifOutMcastPkts + + p_Statistics->ifOutBcastPkts; + p_Statistics->ifOutDiscards = 0; + p_Statistics->ifOutErrors = fman_memac_get_counter(p_Memac->p_MemMap, E_MEMAC_COUNTER_TERR); + + return E_OK; +} + +/* ......................................................................... */ + +static t_Error MemacGetFrameSizeCounters(t_Handle h_Memac, t_FmMacFrameSizeCounters *p_FrameSizeCounters, e_CommMode type) +{ + t_Memac *p_Memac = (t_Memac *)h_Memac; + + SANITY_CHECK_RETURN_ERROR(p_Memac, E_NULL_POINTER); + SANITY_CHECK_RETURN_ERROR(!p_Memac->p_MemacDriverParam, E_INVALID_STATE); + SANITY_CHECK_RETURN_ERROR(p_FrameSizeCounters, E_NULL_POINTER); + + switch (type) + { + case e_COMM_MODE_NONE: + break; + + case e_COMM_MODE_RX: + p_FrameSizeCounters->count_pkts_64 = fman_memac_get_counter(p_Memac->p_MemMap, E_MEMAC_COUNTER_R64); + p_FrameSizeCounters->count_pkts_65_to_127 = fman_memac_get_counter(p_Memac->p_MemMap, E_MEMAC_COUNTER_R127); + p_FrameSizeCounters->count_pkts_128_to_255 = fman_memac_get_counter(p_Memac->p_MemMap, E_MEMAC_COUNTER_R255); + p_FrameSizeCounters->count_pkts_256_to_511 = fman_memac_get_counter(p_Memac->p_MemMap, E_MEMAC_COUNTER_R511); + p_FrameSizeCounters->count_pkts_512_to_1023 = fman_memac_get_counter(p_Memac->p_MemMap, E_MEMAC_COUNTER_R1023); + p_FrameSizeCounters->count_pkts_1024_to_1518 = fman_memac_get_counter(p_Memac->p_MemMap, E_MEMAC_COUNTER_R1518); + p_FrameSizeCounters->count_pkts_1519_to_1522 = fman_memac_get_counter(p_Memac->p_MemMap, E_MEMAC_COUNTER_R1519X); + break; + + case e_COMM_MODE_TX: + p_FrameSizeCounters->count_pkts_64 = fman_memac_get_counter(p_Memac->p_MemMap, E_MEMAC_COUNTER_T64); + p_FrameSizeCounters->count_pkts_65_to_127 = fman_memac_get_counter(p_Memac->p_MemMap, E_MEMAC_COUNTER_T127); + p_FrameSizeCounters->count_pkts_128_to_255 = fman_memac_get_counter(p_Memac->p_MemMap, E_MEMAC_COUNTER_T255); + p_FrameSizeCounters->count_pkts_256_to_511 = fman_memac_get_counter(p_Memac->p_MemMap, E_MEMAC_COUNTER_T511); + p_FrameSizeCounters->count_pkts_512_to_1023 = fman_memac_get_counter(p_Memac->p_MemMap, E_MEMAC_COUNTER_T1023); + p_FrameSizeCounters->count_pkts_1024_to_1518 = fman_memac_get_counter(p_Memac->p_MemMap, E_MEMAC_COUNTER_T1518); + p_FrameSizeCounters->count_pkts_1519_to_1522 = fman_memac_get_counter(p_Memac->p_MemMap, E_MEMAC_COUNTER_T1519X); + break; + + case e_COMM_MODE_RX_AND_TX: + p_FrameSizeCounters->count_pkts_64 = fman_memac_get_counter(p_Memac->p_MemMap, E_MEMAC_COUNTER_R64) + + fman_memac_get_counter(p_Memac->p_MemMap, E_MEMAC_COUNTER_T64); + p_FrameSizeCounters->count_pkts_65_to_127 = fman_memac_get_counter(p_Memac->p_MemMap, E_MEMAC_COUNTER_R127) + + fman_memac_get_counter(p_Memac->p_MemMap, E_MEMAC_COUNTER_T127); + p_FrameSizeCounters->count_pkts_128_to_255 = fman_memac_get_counter(p_Memac->p_MemMap, E_MEMAC_COUNTER_R255) + + fman_memac_get_counter(p_Memac->p_MemMap, E_MEMAC_COUNTER_T255); + p_FrameSizeCounters->count_pkts_256_to_511 = fman_memac_get_counter(p_Memac->p_MemMap, E_MEMAC_COUNTER_R511) + + fman_memac_get_counter(p_Memac->p_MemMap, E_MEMAC_COUNTER_T511); + p_FrameSizeCounters->count_pkts_512_to_1023 = fman_memac_get_counter(p_Memac->p_MemMap, E_MEMAC_COUNTER_R1023) + + fman_memac_get_counter(p_Memac->p_MemMap, E_MEMAC_COUNTER_T1023); + p_FrameSizeCounters->count_pkts_1024_to_1518 = fman_memac_get_counter(p_Memac->p_MemMap, E_MEMAC_COUNTER_R1518) + + fman_memac_get_counter(p_Memac->p_MemMap, E_MEMAC_COUNTER_T1518); + p_FrameSizeCounters->count_pkts_1519_to_1522 = fman_memac_get_counter(p_Memac->p_MemMap, E_MEMAC_COUNTER_R1519X) + + fman_memac_get_counter(p_Memac->p_MemMap, E_MEMAC_COUNTER_T1519X); + break; + } + + return E_OK; +} + +/* ......................................................................... */ + +static t_Error MemacModifyMacAddress (t_Handle h_Memac, t_EnetAddr *p_EnetAddr) +{ + t_Memac *p_Memac = (t_Memac *)h_Memac; + + SANITY_CHECK_RETURN_ERROR(p_Memac, E_NULL_POINTER); + SANITY_CHECK_RETURN_ERROR(!p_Memac->p_MemacDriverParam, E_INVALID_STATE); + + fman_memac_add_addr_in_paddr(p_Memac->p_MemMap, (uint8_t *)(*p_EnetAddr), 0); + + return E_OK; +} + +/* ......................................................................... */ + +static t_Error MemacResetCounters (t_Handle h_Memac) +{ + t_Memac *p_Memac = (t_Memac *)h_Memac; + + SANITY_CHECK_RETURN_ERROR(p_Memac, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(!p_Memac->p_MemacDriverParam, E_INVALID_STATE); + + fman_memac_reset_stat(p_Memac->p_MemMap); + + return E_OK; +} + +/* ......................................................................... */ + +static t_Error MemacAddExactMatchMacAddress(t_Handle h_Memac, t_EnetAddr *p_EthAddr) +{ + t_Memac *p_Memac = (t_Memac *) h_Memac; + uint64_t ethAddr; + uint8_t paddrNum; + + SANITY_CHECK_RETURN_ERROR(p_Memac, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(!p_Memac->p_MemacDriverParam, E_INVALID_STATE); + + ethAddr = ENET_ADDR_TO_UINT64(*p_EthAddr); + + if (ethAddr & GROUP_ADDRESS) + /* Multicast address has no effect in PADDR */ + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("Multicast address")); + + /* Make sure no PADDR contains this address */ + for (paddrNum = 0; paddrNum < MEMAC_NUM_OF_PADDRS; paddrNum++) + if (p_Memac->indAddrRegUsed[paddrNum]) + if (p_Memac->paddr[paddrNum] == ethAddr) + RETURN_ERROR(MAJOR, E_ALREADY_EXISTS, NO_MSG); + + /* Find first unused PADDR */ + for (paddrNum = 0; paddrNum < MEMAC_NUM_OF_PADDRS; paddrNum++) + if (!(p_Memac->indAddrRegUsed[paddrNum])) + { + /* mark this PADDR as used */ + p_Memac->indAddrRegUsed[paddrNum] = TRUE; + /* store address */ + p_Memac->paddr[paddrNum] = ethAddr; + + /* put in hardware */ + fman_memac_add_addr_in_paddr(p_Memac->p_MemMap, (uint8_t*)(*p_EthAddr), paddrNum); + p_Memac->numOfIndAddrInRegs++; + + return E_OK; + } + + /* No free PADDR */ + RETURN_ERROR(MAJOR, E_FULL, NO_MSG); +} + +/* ......................................................................... */ + +static t_Error MemacDelExactMatchMacAddress(t_Handle h_Memac, t_EnetAddr *p_EthAddr) +{ + t_Memac *p_Memac = (t_Memac *) h_Memac; + uint64_t ethAddr; + uint8_t paddrNum; + + SANITY_CHECK_RETURN_ERROR(p_Memac, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(!p_Memac->p_MemacDriverParam, E_INVALID_STATE); + + ethAddr = ENET_ADDR_TO_UINT64(*p_EthAddr); + + /* Find used PADDR containing this address */ + for (paddrNum = 0; paddrNum < MEMAC_NUM_OF_PADDRS; paddrNum++) + { + if ((p_Memac->indAddrRegUsed[paddrNum]) && + (p_Memac->paddr[paddrNum] == ethAddr)) + { + /* mark this PADDR as not used */ + p_Memac->indAddrRegUsed[paddrNum] = FALSE; + /* clear in hardware */ + fman_memac_clear_addr_in_paddr(p_Memac->p_MemMap, paddrNum); + p_Memac->numOfIndAddrInRegs--; + + return E_OK; + } + } + + RETURN_ERROR(MAJOR, E_NOT_FOUND, NO_MSG); +} + +/* ......................................................................... */ + +static t_Error MemacGetId(t_Handle h_Memac, uint32_t *macId) +{ + t_Memac *p_Memac = (t_Memac *)h_Memac; + + SANITY_CHECK_RETURN_ERROR(p_Memac, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(!p_Memac->p_MemacDriverParam, E_INVALID_STATE); + + *macId = p_Memac->macId; + + return E_OK; +} + +/* ......................................................................... */ + + +static t_Error MemacAddHashMacAddress(t_Handle h_Memac, t_EnetAddr *p_EthAddr) +{ + t_Memac *p_Memac = (t_Memac *)h_Memac; + t_EthHashEntry *p_HashEntry; + uint32_t hash; + uint64_t ethAddr; + + SANITY_CHECK_RETURN_ERROR(p_Memac, E_NULL_POINTER); + SANITY_CHECK_RETURN_ERROR(!p_Memac->p_MemacDriverParam, E_INVALID_STATE); + + ethAddr = ENET_ADDR_TO_UINT64(*p_EthAddr); + + if (!(ethAddr & GROUP_ADDRESS)) + /* Unicast addresses not supported in hash */ + RETURN_ERROR(MAJOR, E_NOT_SUPPORTED, ("Unicast Address")); + + hash = GetMacAddrHashCode(ethAddr) & HASH_CTRL_ADDR_MASK; + + /* Create element to be added to the driver hash table */ + p_HashEntry = (t_EthHashEntry *)XX_Malloc(sizeof(t_EthHashEntry)); + p_HashEntry->addr = ethAddr; + INIT_LIST(&p_HashEntry->node); + + LIST_AddToTail(&(p_HashEntry->node), &(p_Memac->p_MulticastAddrHash->p_Lsts[hash])); + fman_memac_set_hash_table(p_Memac->p_MemMap, (hash | HASH_CTRL_MCAST_EN)); + + return E_OK; +} + +/* ......................................................................... */ + +static t_Error MemacDelHashMacAddress(t_Handle h_Memac, t_EnetAddr *p_EthAddr) +{ + t_Memac *p_Memac = (t_Memac *)h_Memac; + t_EthHashEntry *p_HashEntry = NULL; + t_List *p_Pos; + uint32_t hash; + uint64_t ethAddr; + + SANITY_CHECK_RETURN_ERROR(p_Memac, E_NULL_POINTER); + SANITY_CHECK_RETURN_ERROR(!p_Memac->p_MemacDriverParam, E_INVALID_STATE); + + ethAddr = ENET_ADDR_TO_UINT64(*p_EthAddr); + + hash = GetMacAddrHashCode(ethAddr) & HASH_CTRL_ADDR_MASK; + + LIST_FOR_EACH(p_Pos, &(p_Memac->p_MulticastAddrHash->p_Lsts[hash])) + { + p_HashEntry = ETH_HASH_ENTRY_OBJ(p_Pos); + if (p_HashEntry->addr == ethAddr) + { + LIST_DelAndInit(&p_HashEntry->node); + XX_Free(p_HashEntry); + break; + } + } + if (LIST_IsEmpty(&p_Memac->p_MulticastAddrHash->p_Lsts[hash])) + fman_memac_set_hash_table(p_Memac->p_MemMap, (hash & ~HASH_CTRL_MCAST_EN)); + + return E_OK; +} + + +/* ......................................................................... */ + +static t_Error MemacSetException(t_Handle h_Memac, e_FmMacExceptions exception, bool enable) +{ + t_Memac *p_Memac = (t_Memac *)h_Memac; + uint32_t bitMask = 0; + + SANITY_CHECK_RETURN_ERROR(p_Memac, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(!p_Memac->p_MemacDriverParam, E_INVALID_STATE); + + GET_EXCEPTION_FLAG(bitMask, exception); + if (bitMask) + { + if (enable) + p_Memac->exceptions |= bitMask; + else + p_Memac->exceptions &= ~bitMask; + } + else + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("Undefined exception")); + + fman_memac_set_exception(p_Memac->p_MemMap, bitMask, enable); + + return E_OK; +} + +/* ......................................................................... */ + +static uint16_t MemacGetMaxFrameLength(t_Handle h_Memac) +{ + t_Memac *p_Memac = (t_Memac *)h_Memac; + + SANITY_CHECK_RETURN_VALUE(p_Memac, E_INVALID_HANDLE, 0); + SANITY_CHECK_RETURN_VALUE(!p_Memac->p_MemacDriverParam, E_INVALID_STATE, 0); + + return fman_memac_get_max_frame_len(p_Memac->p_MemMap); +} + +static t_Error MemacInitInternalPhy(t_Handle h_Memac) +{ + t_Memac *p_Memac = (t_Memac *)h_Memac; + uint8_t i, phyAddr; + + if (ENET_INTERFACE_FROM_MODE(p_Memac->enetMode) == e_ENET_IF_SGMII) + { + /* Configure internal SGMII PHY */ + if (p_Memac->enetMode & ENET_IF_SGMII_BASEX) + SetupSgmiiInternalPhyBaseX(p_Memac, PHY_MDIO_ADDR); + else + SetupSgmiiInternalPhy(p_Memac, PHY_MDIO_ADDR); + } + else if (ENET_INTERFACE_FROM_MODE(p_Memac->enetMode) == e_ENET_IF_QSGMII) + { + /* Configure 4 internal SGMII PHYs */ + for (i = 0; i < 4; i++) + { + /* QSGMII PHY address occupies 3 upper bits of 5-bit + phyAddress; the lower 2 bits are used to extend + register address space and access each one of 4 + ports inside QSGMII. */ + phyAddr = (uint8_t)((PHY_MDIO_ADDR << 2) | i); + if (p_Memac->enetMode & ENET_IF_SGMII_BASEX) + SetupSgmiiInternalPhyBaseX(p_Memac, phyAddr); + else + SetupSgmiiInternalPhy(p_Memac, phyAddr); + } + } + return E_OK; +} + +/*****************************************************************************/ +/* mEMAC Init & Free API */ +/*****************************************************************************/ + +/* ......................................................................... */ +void *g_MemacRegs; +static t_Error MemacInit(t_Handle h_Memac) +{ + t_Memac *p_Memac = (t_Memac *)h_Memac; + struct memac_cfg *p_MemacDriverParam; + enum enet_interface enet_interface; + enum enet_speed enet_speed; + t_EnetAddr ethAddr; + e_FmMacType portType; + t_Error err; + bool slow_10g_if = FALSE; + if (p_Memac->macId == 3) /* This is a quick WA */ + g_MemacRegs = p_Memac->p_MemMap; + + SANITY_CHECK_RETURN_ERROR(p_Memac, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_Memac->p_MemacDriverParam, E_INVALID_STATE); + SANITY_CHECK_RETURN_ERROR(p_Memac->fmMacControllerDriver.h_Fm, E_INVALID_HANDLE); + + FM_GetRevision(p_Memac->fmMacControllerDriver.h_Fm, &p_Memac->fmMacControllerDriver.fmRevInfo); + if (p_Memac->fmMacControllerDriver.fmRevInfo.majorRev == 6 && + p_Memac->fmMacControllerDriver.fmRevInfo.minorRev == 4) + slow_10g_if = TRUE; + + CHECK_INIT_PARAMETERS(p_Memac, CheckInitParameters); + + p_MemacDriverParam = p_Memac->p_MemacDriverParam; + + portType = + ((ENET_SPEED_FROM_MODE(p_Memac->enetMode) < e_ENET_SPEED_10000) ? e_FM_MAC_1G : e_FM_MAC_10G); + + /* First, reset the MAC if desired. */ + if (p_MemacDriverParam->reset_on_init) + fman_memac_reset(p_Memac->p_MemMap); + + /* MAC Address */ + MAKE_ENET_ADDR_FROM_UINT64(p_Memac->addr, ethAddr); + fman_memac_add_addr_in_paddr(p_Memac->p_MemMap, (uint8_t*)ethAddr, 0); + + enet_interface = (enum enet_interface) ENET_INTERFACE_FROM_MODE(p_Memac->enetMode); + enet_speed = (enum enet_speed) ENET_SPEED_FROM_MODE(p_Memac->enetMode); + + fman_memac_init(p_Memac->p_MemMap, + p_Memac->p_MemacDriverParam, + enet_interface, + enet_speed, + slow_10g_if, + p_Memac->exceptions); + +#ifdef FM_RX_FIFO_CORRUPT_ERRATA_10GMAC_A006320 + { + uint32_t tmpReg = 0; + + FM_GetRevision(p_Memac->fmMacControllerDriver.h_Fm, &p_Memac->fmMacControllerDriver.fmRevInfo); + /* check the FMAN version - the bug exists only in rev1 */ + if ((p_Memac->fmMacControllerDriver.fmRevInfo.majorRev == 6) && + (p_Memac->fmMacControllerDriver.fmRevInfo.minorRev == 0)) + { + /* MAC strips CRC from received frames - this workaround should + decrease the likelihood of bug appearance + */ + tmpReg = GET_UINT32(p_Memac->p_MemMap->command_config); + tmpReg &= ~CMD_CFG_CRC_FWD; + WRITE_UINT32(p_Memac->p_MemMap->command_config, tmpReg); + /* DBG(WARNING, ("mEMAC strips CRC from received frames as part of A006320 errata workaround"));*/ + } + } +#endif /* FM_RX_FIFO_CORRUPT_ERRATA_10GMAC_A006320 */ + + MemacInitInternalPhy(h_Memac); + + /* Max Frame Length */ + err = FmSetMacMaxFrame(p_Memac->fmMacControllerDriver.h_Fm, + portType, + p_Memac->fmMacControllerDriver.macId, + p_MemacDriverParam->max_frame_length); + if (err) + RETURN_ERROR(MAJOR, err, ("settings Mac max frame length is FAILED")); + + p_Memac->p_MulticastAddrHash = AllocHashTable(HASH_TABLE_SIZE); + if (!p_Memac->p_MulticastAddrHash) + { + FreeInitResources(p_Memac); + RETURN_ERROR(MAJOR, E_NO_MEMORY, ("allocation hash table is FAILED")); + } + + p_Memac->p_UnicastAddrHash = AllocHashTable(HASH_TABLE_SIZE); + if (!p_Memac->p_UnicastAddrHash) + { + FreeInitResources(p_Memac); + RETURN_ERROR(MAJOR, E_NO_MEMORY, ("allocation hash table is FAILED")); + } + + FmRegisterIntr(p_Memac->fmMacControllerDriver.h_Fm, + (portType == e_FM_MAC_10G) ? e_FM_MOD_10G_MAC : e_FM_MOD_1G_MAC, + p_Memac->macId, + e_FM_INTR_TYPE_ERR, + MemacErrException, + p_Memac); + + FmRegisterIntr(p_Memac->fmMacControllerDriver.h_Fm, + (portType == e_FM_MAC_10G) ? e_FM_MOD_10G_MAC : e_FM_MOD_1G_MAC, + p_Memac->macId, + e_FM_INTR_TYPE_NORMAL, + MemacException, + p_Memac); + + XX_Free(p_MemacDriverParam); + p_Memac->p_MemacDriverParam = NULL; + + return E_OK; +} + +/* ......................................................................... */ + +static t_Error MemacFree(t_Handle h_Memac) +{ + t_Memac *p_Memac = (t_Memac *)h_Memac; + + SANITY_CHECK_RETURN_ERROR(p_Memac, E_INVALID_HANDLE); + + if (p_Memac->p_MemacDriverParam) + { + /* Called after config */ + XX_Free(p_Memac->p_MemacDriverParam); + p_Memac->p_MemacDriverParam = NULL; + } + else + /* Called after init */ + FreeInitResources(p_Memac); + + XX_Free(p_Memac); + + return E_OK; +} + +/* ......................................................................... */ + +static void InitFmMacControllerDriver(t_FmMacControllerDriver *p_FmMacControllerDriver) +{ + p_FmMacControllerDriver->f_FM_MAC_Init = MemacInit; + p_FmMacControllerDriver->f_FM_MAC_Free = MemacFree; + + p_FmMacControllerDriver->f_FM_MAC_SetStatistics = NULL; + p_FmMacControllerDriver->f_FM_MAC_ConfigLoopback = MemacConfigLoopback; + p_FmMacControllerDriver->f_FM_MAC_ConfigMaxFrameLength = MemacConfigMaxFrameLength; + + p_FmMacControllerDriver->f_FM_MAC_ConfigWan = MemacConfigWan; + + p_FmMacControllerDriver->f_FM_MAC_ConfigPadAndCrc = MemacConfigPad; + p_FmMacControllerDriver->f_FM_MAC_ConfigHalfDuplex = NULL; /* half-duplex is detected automatically */ + p_FmMacControllerDriver->f_FM_MAC_ConfigLengthCheck = MemacConfigLengthCheck; + + p_FmMacControllerDriver->f_FM_MAC_ConfigException = MemacConfigException; + p_FmMacControllerDriver->f_FM_MAC_ConfigResetOnInit = MemacConfigResetOnInit; + + p_FmMacControllerDriver->f_FM_MAC_SetException = MemacSetException; + + p_FmMacControllerDriver->f_FM_MAC_Enable1588TimeStamp = MemacEnable1588TimeStamp; /* always enabled */ + p_FmMacControllerDriver->f_FM_MAC_Disable1588TimeStamp = NULL; + + p_FmMacControllerDriver->f_FM_MAC_SetPromiscuous = MemacSetPromiscuous; + p_FmMacControllerDriver->f_FM_MAC_AdjustLink = MemacAdjustLink; + p_FmMacControllerDriver->f_FM_MAC_RestartAutoneg = NULL; + + p_FmMacControllerDriver->f_FM_MAC_Enable = MemacEnable; + p_FmMacControllerDriver->f_FM_MAC_Disable = MemacDisable; + p_FmMacControllerDriver->f_FM_MAC_Resume = MemacInitInternalPhy; + + p_FmMacControllerDriver->f_FM_MAC_SetTxAutoPauseFrames = MemacSetTxAutoPauseFrames; + p_FmMacControllerDriver->f_FM_MAC_SetTxPauseFrames = MemacSetTxPauseFrames; + p_FmMacControllerDriver->f_FM_MAC_SetRxIgnorePauseFrames = MemacSetRxIgnorePauseFrames; + + p_FmMacControllerDriver->f_FM_MAC_SetWakeOnLan = MemacSetWakeOnLan; + + p_FmMacControllerDriver->f_FM_MAC_ResetCounters = MemacResetCounters; + p_FmMacControllerDriver->f_FM_MAC_GetStatistics = MemacGetStatistics; + p_FmMacControllerDriver->f_FM_MAC_GetFrameSizeCounters = MemacGetFrameSizeCounters; + + p_FmMacControllerDriver->f_FM_MAC_ModifyMacAddr = MemacModifyMacAddress; + p_FmMacControllerDriver->f_FM_MAC_AddHashMacAddr = MemacAddHashMacAddress; + p_FmMacControllerDriver->f_FM_MAC_RemoveHashMacAddr = MemacDelHashMacAddress; + p_FmMacControllerDriver->f_FM_MAC_AddExactMatchMacAddr = MemacAddExactMatchMacAddress; + p_FmMacControllerDriver->f_FM_MAC_RemovelExactMatchMacAddr = MemacDelExactMatchMacAddress; + p_FmMacControllerDriver->f_FM_MAC_GetId = MemacGetId; + p_FmMacControllerDriver->f_FM_MAC_GetVersion = NULL; + p_FmMacControllerDriver->f_FM_MAC_GetMaxFrameLength = MemacGetMaxFrameLength; + + p_FmMacControllerDriver->f_FM_MAC_MII_WritePhyReg = MEMAC_MII_WritePhyReg; + p_FmMacControllerDriver->f_FM_MAC_MII_ReadPhyReg = MEMAC_MII_ReadPhyReg; +} + + +/*****************************************************************************/ +/* mEMAC Config Main Entry */ +/*****************************************************************************/ + +/* ......................................................................... */ + +t_Handle MEMAC_Config(t_FmMacParams *p_FmMacParam) +{ + t_Memac *p_Memac; + struct memac_cfg *p_MemacDriverParam; + uintptr_t baseAddr; + + SANITY_CHECK_RETURN_VALUE(p_FmMacParam, E_NULL_POINTER, NULL); + + baseAddr = p_FmMacParam->baseAddr; + /* Allocate memory for the mEMAC data structure */ + p_Memac = (t_Memac *)XX_Malloc(sizeof(t_Memac)); + if (!p_Memac) + { + REPORT_ERROR(MAJOR, E_NO_MEMORY, ("mEMAC driver structure")); + return NULL; + } + memset(p_Memac, 0, sizeof(t_Memac)); + InitFmMacControllerDriver(&p_Memac->fmMacControllerDriver); + + /* Allocate memory for the mEMAC driver parameters data structure */ + p_MemacDriverParam = (struct memac_cfg *)XX_Malloc(sizeof(struct memac_cfg)); + if (!p_MemacDriverParam) + { + REPORT_ERROR(MAJOR, E_NO_MEMORY, ("mEMAC driver parameters")); + XX_Free(p_Memac); + return NULL; + } + memset(p_MemacDriverParam, 0, sizeof(struct memac_cfg)); + + /* Plant parameter structure pointer */ + p_Memac->p_MemacDriverParam = p_MemacDriverParam; + + fman_memac_defconfig(p_MemacDriverParam); + + p_Memac->addr = ENET_ADDR_TO_UINT64(p_FmMacParam->addr); + + p_Memac->p_MemMap = (struct memac_regs *)UINT_TO_PTR(baseAddr); + p_Memac->p_MiiMemMap = (struct memac_mii_access_mem_map*)UINT_TO_PTR(baseAddr + MEMAC_TO_MII_OFFSET); + + p_Memac->enetMode = p_FmMacParam->enetMode; + p_Memac->macId = p_FmMacParam->macId; + p_Memac->exceptions = MEMAC_default_exceptions; + p_Memac->f_Exception = p_FmMacParam->f_Exception; + p_Memac->f_Event = p_FmMacParam->f_Event; + p_Memac->h_App = p_FmMacParam->h_App; + + return p_Memac; +} diff --git a/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MAC/memac.h b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MAC/memac.h new file mode 100644 index 000000000000..d361af42b0c2 --- /dev/null +++ b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MAC/memac.h @@ -0,0 +1,111 @@ +/* + * Copyright 2008-2012 Freescale Semiconductor Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Freescale Semiconductor nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * + * ALTERNATIVELY, this software may be distributed under the terms of the + * GNU General Public License ("GPL") as published by the Free Software + * Foundation, either version 2 of that License or (at your option) any + * later version. + * + * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + +/****************************************************************************** + @File memac.h + + @Description FM Multirate Ethernet MAC (mEMAC) +*//***************************************************************************/ +#ifndef __MEMAC_H +#define __MEMAC_H + +#include "std_ext.h" +#include "error_ext.h" +#include "list_ext.h" + +#include "fsl_fman_memac_mii_acc.h" +#include "fm_mac.h" +#include "fsl_fman_memac.h" + + +#define MEMAC_default_exceptions \ + ((uint32_t)(MEMAC_IMASK_TSECC_ER | MEMAC_IMASK_TECC_ER | MEMAC_IMASK_RECC_ER | MEMAC_IMASK_MGI)) + +#define GET_EXCEPTION_FLAG(bitMask, exception) switch (exception){ \ + case e_FM_MAC_EX_10G_1TX_ECC_ER: \ + bitMask = MEMAC_IMASK_TECC_ER; break; \ + case e_FM_MAC_EX_10G_RX_ECC_ER: \ + bitMask = MEMAC_IMASK_RECC_ER; break; \ + case e_FM_MAC_EX_TS_FIFO_ECC_ERR: \ + bitMask = MEMAC_IMASK_TSECC_ER; break; \ + case e_FM_MAC_EX_MAGIC_PACKET_INDICATION: \ + bitMask = MEMAC_IMASK_MGI; break; \ + default: bitMask = 0;break;} + + +typedef struct +{ + t_FmMacControllerDriver fmMacControllerDriver; /**< Upper Mac control block */ + t_Handle h_App; /**< Handle to the upper layer application */ + struct memac_regs *p_MemMap; /**< Pointer to MAC memory mapped registers */ + struct memac_mii_access_mem_map *p_MiiMemMap; /**< Pointer to MII memory mapped registers */ + uint64_t addr; /**< MAC address of device */ + e_EnetMode enetMode; /**< Ethernet physical interface */ + t_FmMacExceptionCallback *f_Exception; + int mdioIrq; + t_FmMacExceptionCallback *f_Event; + bool indAddrRegUsed[MEMAC_NUM_OF_PADDRS]; /**< Whether a particular individual address recognition register is being used */ + uint64_t paddr[MEMAC_NUM_OF_PADDRS]; /**< MAC address for particular individual address recognition register */ + uint8_t numOfIndAddrInRegs; /**< Number of individual addresses in registers for this station. */ + t_EthHash *p_MulticastAddrHash; /**< Pointer to driver's global address hash table */ + t_EthHash *p_UnicastAddrHash; /**< Pointer to driver's individual address hash table */ + bool debugMode; + uint8_t macId; + uint32_t exceptions; + struct memac_cfg *p_MemacDriverParam; +} t_Memac; + + +/* Internal PHY access */ +#define PHY_MDIO_ADDR 0 + +/* Internal PHY Registers - SGMII */ +#define PHY_SGMII_CR_PHY_RESET 0x8000 +#define PHY_SGMII_CR_RESET_AN 0x0200 +#define PHY_SGMII_CR_DEF_VAL 0x1140 +#define PHY_SGMII_CR_AN_EN 0x1000 +#define PHY_SGMII_DEV_ABILITY_SGMII 0x4001 +#define PHY_SGMII_DEV_ABILITY_1000X 0x01A0 +#define PHY_SGMII_IF_SPEED_GIGABIT 0x0008 +#define PHY_SGMII_IF_MODE_AN 0x0002 +#define PHY_SGMII_IF_MODE_SGMII 0x0001 +#define PHY_SGMII_IF_MODE_1000X 0x0000 + + +#define MEMAC_TO_MII_OFFSET 0x030 /* Offset from the MEM map to the MDIO mem map */ + +t_Error MEMAC_MII_WritePhyReg(t_Handle h_Memac, uint8_t phyAddr, uint8_t reg, uint16_t data); +t_Error MEMAC_MII_ReadPhyReg(t_Handle h_Memac, uint8_t phyAddr, uint8_t reg, uint16_t *p_Data); + + +#endif /* __MEMAC_H */ diff --git a/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MAC/memac_mii_acc.c b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MAC/memac_mii_acc.c new file mode 100644 index 000000000000..56eaffbcf66d --- /dev/null +++ b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MAC/memac_mii_acc.c @@ -0,0 +1,78 @@ +/* + * Copyright 2008-2012 Freescale Semiconductor Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Freescale Semiconductor nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * + * ALTERNATIVELY, this software may be distributed under the terms of the + * GNU General Public License ("GPL") as published by the Free Software + * Foundation, either version 2 of that License or (at your option) any + * later version. + * + * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + +#include "error_ext.h" +#include "std_ext.h" +#include "fm_mac.h" +#include "memac.h" +#include "xx_ext.h" + +#include "fm_common.h" +#include "memac_mii_acc.h" + + +/*****************************************************************************/ +t_Error MEMAC_MII_WritePhyReg(t_Handle h_Memac, + uint8_t phyAddr, + uint8_t reg, + uint16_t data) +{ + t_Memac *p_Memac = (t_Memac *)h_Memac; + + SANITY_CHECK_RETURN_ERROR(p_Memac, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_Memac->p_MiiMemMap, E_INVALID_HANDLE); + + return (t_Error)fman_memac_mii_write_phy_reg(p_Memac->p_MiiMemMap, + phyAddr, + reg, + data, + (enum enet_speed)ENET_SPEED_FROM_MODE(p_Memac->enetMode)); +} + +/*****************************************************************************/ +t_Error MEMAC_MII_ReadPhyReg(t_Handle h_Memac, + uint8_t phyAddr, + uint8_t reg, + uint16_t *p_Data) +{ + t_Memac *p_Memac = (t_Memac *)h_Memac; + + SANITY_CHECK_RETURN_ERROR(p_Memac, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_Memac->p_MiiMemMap, E_INVALID_HANDLE); + + return fman_memac_mii_read_phy_reg(p_Memac->p_MiiMemMap, + phyAddr, + reg, + p_Data, + (enum enet_speed)ENET_SPEED_FROM_MODE(p_Memac->enetMode)); +} diff --git a/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MAC/memac_mii_acc.h b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MAC/memac_mii_acc.h new file mode 100644 index 000000000000..325ec082ffde --- /dev/null +++ b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MAC/memac_mii_acc.h @@ -0,0 +1,73 @@ +/* + * Copyright 2008-2012 Freescale Semiconductor Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Freescale Semiconductor nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * + * ALTERNATIVELY, this software may be distributed under the terms of the + * GNU General Public License ("GPL") as published by the Free Software + * Foundation, either version 2 of that License or (at your option) any + * later version. + * + * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + +#ifndef __MEMAC_MII_ACC_H +#define __MEMAC_MII_ACC_H + +#include "std_ext.h" + + +/* MII Management Registers */ +#define MDIO_CFG_CLK_DIV_MASK 0x0080ff80 +#define MDIO_CFG_CLK_DIV_SHIFT 7 +#define MDIO_CFG_HOLD_MASK 0x0000001c +#define MDIO_CFG_ENC45 0x00000040 +#define MDIO_CFG_READ_ERR 0x00000002 +#define MDIO_CFG_BSY 0x00000001 + +#define MDIO_CTL_PHY_ADDR_SHIFT 5 +#define MDIO_CTL_READ 0x00008000 + +#define MDIO_DATA_BSY 0x80000000 + +#if defined(__MWERKS__) && !defined(__GNUC__) +#pragma pack(push,1) +#endif /* defined(__MWERKS__) && ... */ + +/*----------------------------------------------------*/ +/* MII Configuration Control Memory Map Registers */ +/*----------------------------------------------------*/ +typedef struct t_MemacMiiAccessMemMap +{ + volatile uint32_t mdio_cfg; /* 0x030 */ + volatile uint32_t mdio_ctrl; /* 0x034 */ + volatile uint32_t mdio_data; /* 0x038 */ + volatile uint32_t mdio_addr; /* 0x03c */ +} t_MemacMiiAccessMemMap ; + +#if defined(__MWERKS__) && !defined(__GNUC__) +#pragma pack(pop) +#endif /* defined(__MWERKS__) && ... */ + + +#endif /* __MEMAC_MII_ACC_H */ diff --git a/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MAC/tgec.c b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MAC/tgec.c new file mode 100644 index 000000000000..eb00759f9f46 --- /dev/null +++ b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MAC/tgec.c @@ -0,0 +1,1017 @@ +/* + * Copyright 2008-2012 Freescale Semiconductor Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Freescale Semiconductor nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * + * ALTERNATIVELY, this software may be distributed under the terms of the + * GNU General Public License ("GPL") as published by the Free Software + * Foundation, either version 2 of that License or (at your option) any + * later version. + * + * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + +/****************************************************************************** + @File tgec.c + + @Description FM 10G MAC ... +*//***************************************************************************/ + +#include "std_ext.h" +#include "string_ext.h" +#include "error_ext.h" +#include "xx_ext.h" +#include "endian_ext.h" +#include "debug_ext.h" +#include "crc_mac_addr_ext.h" + +#include "fm_common.h" +#include "fsl_fman_tgec.h" +#include "tgec.h" + + +/*****************************************************************************/ +/* Internal routines */ +/*****************************************************************************/ + +static t_Error CheckInitParameters(t_Tgec *p_Tgec) +{ + if (ENET_SPEED_FROM_MODE(p_Tgec->enetMode) < e_ENET_SPEED_10000) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("Ethernet 10G MAC driver only support 10G speed")); +#if (FM_MAX_NUM_OF_10G_MACS > 0) + if (p_Tgec->macId >= FM_MAX_NUM_OF_10G_MACS) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("macId of 10G can not be greater than 0")); +#endif /* (FM_MAX_NUM_OF_10G_MACS > 0) */ + + if (p_Tgec->addr == 0) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("Ethernet 10G MAC Must have a valid MAC Address")); + if (!p_Tgec->f_Exception) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("uninitialized f_Exception")); + if (!p_Tgec->f_Event) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("uninitialized f_Event")); +#ifdef FM_LEN_CHECK_ERRATA_FMAN_SW002 + if (!p_Tgec->p_TgecDriverParam->no_length_check_enable) + RETURN_ERROR(MINOR, E_NOT_SUPPORTED, ("LengthCheck!")); +#endif /* FM_LEN_CHECK_ERRATA_FMAN_SW002 */ + return E_OK; +} + +/* ......................................................................... */ + +static uint32_t GetMacAddrHashCode(uint64_t ethAddr) +{ + uint32_t crc; + + /* CRC calculation */ + GET_MAC_ADDR_CRC(ethAddr, crc); + + crc = GetMirror32(crc); + + return crc; +} + +/* ......................................................................... */ + +static void TgecErrException(t_Handle h_Tgec) +{ + t_Tgec *p_Tgec = (t_Tgec *)h_Tgec; + uint32_t event; + struct tgec_regs *p_TgecMemMap = p_Tgec->p_MemMap; + + /* do not handle MDIO events */ + event = fman_tgec_get_event(p_TgecMemMap, ~(TGEC_IMASK_MDIO_SCAN_EVENT | TGEC_IMASK_MDIO_CMD_CMPL)); + event &= fman_tgec_get_interrupt_mask(p_TgecMemMap); + + fman_tgec_ack_event(p_TgecMemMap, event); + + if (event & TGEC_IMASK_REM_FAULT) + p_Tgec->f_Exception(p_Tgec->h_App, e_FM_MAC_EX_10G_REM_FAULT); + if (event & TGEC_IMASK_LOC_FAULT) + p_Tgec->f_Exception(p_Tgec->h_App, e_FM_MAC_EX_10G_LOC_FAULT); + if (event & TGEC_IMASK_TX_ECC_ER) + p_Tgec->f_Exception(p_Tgec->h_App, e_FM_MAC_EX_10G_1TX_ECC_ER); + if (event & TGEC_IMASK_TX_FIFO_UNFL) + p_Tgec->f_Exception(p_Tgec->h_App, e_FM_MAC_EX_10G_TX_FIFO_UNFL); + if (event & TGEC_IMASK_TX_FIFO_OVFL) + p_Tgec->f_Exception(p_Tgec->h_App, e_FM_MAC_EX_10G_TX_FIFO_OVFL); + if (event & TGEC_IMASK_TX_ER) + p_Tgec->f_Exception(p_Tgec->h_App, e_FM_MAC_EX_10G_TX_ER); + if (event & TGEC_IMASK_RX_FIFO_OVFL) + p_Tgec->f_Exception(p_Tgec->h_App, e_FM_MAC_EX_10G_RX_FIFO_OVFL); + if (event & TGEC_IMASK_RX_ECC_ER) + p_Tgec->f_Exception(p_Tgec->h_App, e_FM_MAC_EX_10G_RX_ECC_ER); + if (event & TGEC_IMASK_RX_JAB_FRM) + p_Tgec->f_Exception(p_Tgec->h_App, e_FM_MAC_EX_10G_RX_JAB_FRM); + if (event & TGEC_IMASK_RX_OVRSZ_FRM) + p_Tgec->f_Exception(p_Tgec->h_App, e_FM_MAC_EX_10G_RX_OVRSZ_FRM); + if (event & TGEC_IMASK_RX_RUNT_FRM) + p_Tgec->f_Exception(p_Tgec->h_App, e_FM_MAC_EX_10G_RX_RUNT_FRM); + if (event & TGEC_IMASK_RX_FRAG_FRM) + p_Tgec->f_Exception(p_Tgec->h_App, e_FM_MAC_EX_10G_RX_FRAG_FRM); + if (event & TGEC_IMASK_RX_LEN_ER) + p_Tgec->f_Exception(p_Tgec->h_App, e_FM_MAC_EX_10G_RX_LEN_ER); + if (event & TGEC_IMASK_RX_CRC_ER) + p_Tgec->f_Exception(p_Tgec->h_App, e_FM_MAC_EX_10G_RX_CRC_ER); + if (event & TGEC_IMASK_RX_ALIGN_ER) + p_Tgec->f_Exception(p_Tgec->h_App, e_FM_MAC_EX_10G_RX_ALIGN_ER); +} + +/* ......................................................................... */ + +static void TgecException(t_Handle h_Tgec) +{ + t_Tgec *p_Tgec = (t_Tgec *)h_Tgec; + uint32_t event; + struct tgec_regs *p_TgecMemMap = p_Tgec->p_MemMap; + + /* handle only MDIO events */ + event = fman_tgec_get_event(p_TgecMemMap, (TGEC_IMASK_MDIO_SCAN_EVENT | TGEC_IMASK_MDIO_CMD_CMPL)); + event &= fman_tgec_get_interrupt_mask(p_TgecMemMap); + + fman_tgec_ack_event(p_TgecMemMap, event); + + if (event & TGEC_IMASK_MDIO_SCAN_EVENT) + p_Tgec->f_Event(p_Tgec->h_App, e_FM_MAC_EX_10G_MDIO_SCAN_EVENTMDIO); + if (event & TGEC_IMASK_MDIO_CMD_CMPL) + p_Tgec->f_Event(p_Tgec->h_App, e_FM_MAC_EX_10G_MDIO_CMD_CMPL); +} + +/* ......................................................................... */ + +static void FreeInitResources(t_Tgec *p_Tgec) +{ + if (p_Tgec->mdioIrq != NO_IRQ) + { + XX_DisableIntr(p_Tgec->mdioIrq); + XX_FreeIntr(p_Tgec->mdioIrq); + } + + FmUnregisterIntr(p_Tgec->fmMacControllerDriver.h_Fm, e_FM_MOD_10G_MAC, p_Tgec->macId, e_FM_INTR_TYPE_ERR); + + /* release the driver's group hash table */ + FreeHashTable(p_Tgec->p_MulticastAddrHash); + p_Tgec->p_MulticastAddrHash = NULL; + + /* release the driver's individual hash table */ + FreeHashTable(p_Tgec->p_UnicastAddrHash); + p_Tgec->p_UnicastAddrHash = NULL; +} + + +/*****************************************************************************/ +/* 10G MAC API routines */ +/*****************************************************************************/ + +/* ......................................................................... */ + +static t_Error TgecEnable(t_Handle h_Tgec, e_CommMode mode) +{ + t_Tgec *p_Tgec = (t_Tgec *)h_Tgec; + + SANITY_CHECK_RETURN_ERROR(p_Tgec, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(!p_Tgec->p_TgecDriverParam, E_INVALID_STATE); + + fman_tgec_enable(p_Tgec->p_MemMap, (mode & e_COMM_MODE_RX), (mode & e_COMM_MODE_TX)); + + return E_OK; +} + +/* ......................................................................... */ + +static t_Error TgecDisable (t_Handle h_Tgec, e_CommMode mode) +{ + t_Tgec *p_Tgec = (t_Tgec *)h_Tgec; + + SANITY_CHECK_RETURN_ERROR(p_Tgec, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(!p_Tgec->p_TgecDriverParam, E_INVALID_STATE); + + fman_tgec_disable(p_Tgec->p_MemMap, (mode & e_COMM_MODE_RX), (mode & e_COMM_MODE_TX)); + + return E_OK; +} + +/* ......................................................................... */ + +static t_Error TgecSetPromiscuous(t_Handle h_Tgec, bool newVal) +{ + t_Tgec *p_Tgec = (t_Tgec *)h_Tgec; + + SANITY_CHECK_RETURN_ERROR(p_Tgec, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(!p_Tgec->p_TgecDriverParam, E_INVALID_STATE); + + fman_tgec_set_promiscuous(p_Tgec->p_MemMap, newVal); + + return E_OK; +} + + +/*****************************************************************************/ +/* Tgec Configs modification functions */ +/*****************************************************************************/ + +/* ......................................................................... */ + +static t_Error TgecConfigLoopback(t_Handle h_Tgec, bool newVal) +{ + t_Tgec *p_Tgec = (t_Tgec *)h_Tgec; + + SANITY_CHECK_RETURN_ERROR(p_Tgec, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_Tgec->p_TgecDriverParam, E_INVALID_STATE); + + p_Tgec->p_TgecDriverParam->loopback_enable = newVal; + + return E_OK; +} + +/* ......................................................................... */ + +static t_Error TgecConfigWan(t_Handle h_Tgec, bool newVal) +{ + t_Tgec *p_Tgec = (t_Tgec *)h_Tgec; + + SANITY_CHECK_RETURN_ERROR(p_Tgec, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_Tgec->p_TgecDriverParam, E_INVALID_STATE); + + p_Tgec->p_TgecDriverParam->wan_mode_enable = newVal; + + return E_OK; +} + +/* ......................................................................... */ + +static t_Error TgecConfigMaxFrameLength(t_Handle h_Tgec, uint16_t newVal) +{ + t_Tgec *p_Tgec = (t_Tgec *)h_Tgec; + + SANITY_CHECK_RETURN_ERROR(p_Tgec, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_Tgec->p_TgecDriverParam, E_INVALID_STATE); + + p_Tgec->p_TgecDriverParam->max_frame_length = newVal; + + return E_OK; +} + +/* ......................................................................... */ + +static t_Error TgecConfigLengthCheck(t_Handle h_Tgec, bool newVal) +{ + t_Tgec *p_Tgec = (t_Tgec *)h_Tgec; + + UNUSED(newVal); + + SANITY_CHECK_RETURN_ERROR(p_Tgec, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_Tgec->p_TgecDriverParam, E_INVALID_STATE); + + p_Tgec->p_TgecDriverParam->no_length_check_enable = !newVal; + + return E_OK; +} + +/* ......................................................................... */ + +static t_Error TgecConfigException(t_Handle h_Tgec, e_FmMacExceptions exception, bool enable) +{ + t_Tgec *p_Tgec = (t_Tgec *)h_Tgec; + uint32_t bitMask = 0; + + SANITY_CHECK_RETURN_ERROR(p_Tgec, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_Tgec->p_TgecDriverParam, E_INVALID_STATE); + + GET_EXCEPTION_FLAG(bitMask, exception); + if (bitMask) + { + if (enable) + p_Tgec->exceptions |= bitMask; + else + p_Tgec->exceptions &= ~bitMask; + } + else + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("Undefined exception")); + + return E_OK; +} + +#ifdef FM_TX_ECC_FRMS_ERRATA_10GMAC_A004 +/* ......................................................................... */ + +static t_Error TgecConfigSkipFman11Workaround(t_Handle h_Tgec) +{ + t_Tgec *p_Tgec = (t_Tgec *)h_Tgec; + + SANITY_CHECK_RETURN_ERROR(p_Tgec, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_Tgec->p_TgecDriverParam, E_INVALID_STATE); + + p_Tgec->p_TgecDriverParam->skip_fman11_workaround = TRUE; + + return E_OK; +} +#endif /* FM_TX_ECC_FRMS_ERRATA_10GMAC_A004 */ + + +/*****************************************************************************/ +/* Tgec Run Time API functions */ +/*****************************************************************************/ + +/* ......................................................................... */ +/* backward compatibility. will be removed in the future. */ +static t_Error TgecTxMacPause(t_Handle h_Tgec, uint16_t pauseTime) +{ + t_Tgec *p_Tgec = (t_Tgec *)h_Tgec; + + SANITY_CHECK_RETURN_ERROR(p_Tgec, E_INVALID_STATE); + SANITY_CHECK_RETURN_ERROR(!p_Tgec->p_TgecDriverParam, E_INVALID_STATE); + fman_tgec_set_tx_pause_frames(p_Tgec->p_MemMap, pauseTime); + + + return E_OK; +} + +/* ......................................................................... */ + +static t_Error TgecSetTxPauseFrames(t_Handle h_Tgec, + uint8_t priority, + uint16_t pauseTime, + uint16_t threshTime) +{ + t_Tgec *p_Tgec = (t_Tgec *)h_Tgec; + + SANITY_CHECK_RETURN_ERROR(p_Tgec, E_INVALID_STATE); + SANITY_CHECK_RETURN_ERROR(!p_Tgec->p_TgecDriverParam, E_INVALID_STATE); + + UNUSED(priority); UNUSED(threshTime); + + fman_tgec_set_tx_pause_frames(p_Tgec->p_MemMap, pauseTime); + + return E_OK; +} + +/* ......................................................................... */ + +static t_Error TgecRxIgnoreMacPause(t_Handle h_Tgec, bool en) +{ + t_Tgec *p_Tgec = (t_Tgec *)h_Tgec; + + SANITY_CHECK_RETURN_ERROR(p_Tgec, E_INVALID_STATE); + SANITY_CHECK_RETURN_ERROR(!p_Tgec->p_TgecDriverParam, E_INVALID_STATE); + + fman_tgec_set_rx_ignore_pause_frames(p_Tgec->p_MemMap, en); + + return E_OK; +} + +/* ......................................................................... */ + +static t_Error TgecGetStatistics(t_Handle h_Tgec, t_FmMacStatistics *p_Statistics) +{ + t_Tgec *p_Tgec = (t_Tgec *)h_Tgec; + struct tgec_regs *p_TgecMemMap; + + SANITY_CHECK_RETURN_ERROR(p_Tgec, E_NULL_POINTER); + SANITY_CHECK_RETURN_ERROR(!p_Tgec->p_TgecDriverParam, E_INVALID_STATE); + SANITY_CHECK_RETURN_ERROR(p_Statistics, E_NULL_POINTER); + + p_TgecMemMap = p_Tgec->p_MemMap; + + p_Statistics->eStatPkts64 = fman_tgec_get_counter(p_TgecMemMap, E_TGEC_COUNTER_R64); + p_Statistics->eStatPkts65to127 = fman_tgec_get_counter(p_TgecMemMap, E_TGEC_COUNTER_R127); + p_Statistics->eStatPkts128to255 = fman_tgec_get_counter(p_TgecMemMap, E_TGEC_COUNTER_R255); + p_Statistics->eStatPkts256to511 = fman_tgec_get_counter(p_TgecMemMap, E_TGEC_COUNTER_R511); + p_Statistics->eStatPkts512to1023 = fman_tgec_get_counter(p_TgecMemMap, E_TGEC_COUNTER_R1023); + p_Statistics->eStatPkts1024to1518 = fman_tgec_get_counter(p_TgecMemMap, E_TGEC_COUNTER_R1518); + p_Statistics->eStatPkts1519to1522 = fman_tgec_get_counter(p_TgecMemMap, E_TGEC_COUNTER_R1519X); +/* */ + p_Statistics->eStatFragments = fman_tgec_get_counter(p_TgecMemMap, E_TGEC_COUNTER_TRFRG); + p_Statistics->eStatJabbers = fman_tgec_get_counter(p_TgecMemMap, E_TGEC_COUNTER_TRJBR); + + p_Statistics->eStatsDropEvents = fman_tgec_get_counter(p_TgecMemMap, E_TGEC_COUNTER_RDRP); + p_Statistics->eStatCRCAlignErrors = fman_tgec_get_counter(p_TgecMemMap, E_TGEC_COUNTER_RALN); + + p_Statistics->eStatUndersizePkts = fman_tgec_get_counter(p_TgecMemMap, E_TGEC_COUNTER_TRUND); + p_Statistics->eStatOversizePkts = fman_tgec_get_counter(p_TgecMemMap, E_TGEC_COUNTER_TROVR); +/* Pause */ + p_Statistics->reStatPause = fman_tgec_get_counter(p_TgecMemMap, E_TGEC_COUNTER_RXPF); + p_Statistics->teStatPause = fman_tgec_get_counter(p_TgecMemMap, E_TGEC_COUNTER_TXPF); + +/* MIB II */ + p_Statistics->ifInOctets = fman_tgec_get_counter(p_TgecMemMap, E_TGEC_COUNTER_ROCT); + p_Statistics->ifInUcastPkts = fman_tgec_get_counter(p_TgecMemMap, E_TGEC_COUNTER_RUCA); + p_Statistics->ifInMcastPkts = fman_tgec_get_counter(p_TgecMemMap, E_TGEC_COUNTER_RMCA); + p_Statistics->ifInBcastPkts = fman_tgec_get_counter(p_TgecMemMap, E_TGEC_COUNTER_RBCA); + p_Statistics->ifInPkts = p_Statistics->ifInUcastPkts + + p_Statistics->ifInMcastPkts + + p_Statistics->ifInBcastPkts; + p_Statistics->ifInDiscards = 0; + p_Statistics->ifInErrors = fman_tgec_get_counter(p_TgecMemMap, E_TGEC_COUNTER_RERR); + + p_Statistics->ifOutOctets = fman_tgec_get_counter(p_TgecMemMap, E_TGEC_COUNTER_TOCT); + p_Statistics->ifOutUcastPkts = fman_tgec_get_counter(p_TgecMemMap, E_TGEC_COUNTER_TUCA); + p_Statistics->ifOutMcastPkts = fman_tgec_get_counter(p_TgecMemMap, E_TGEC_COUNTER_TMCA); + p_Statistics->ifOutBcastPkts = fman_tgec_get_counter(p_TgecMemMap, E_TGEC_COUNTER_TBCA); + p_Statistics->ifOutPkts = p_Statistics->ifOutUcastPkts + + p_Statistics->ifOutMcastPkts + + p_Statistics->ifOutBcastPkts; + p_Statistics->ifOutDiscards = 0; + p_Statistics->ifOutErrors = fman_tgec_get_counter(p_TgecMemMap, E_TGEC_COUNTER_TERR); + + return E_OK; +} + +/* ......................................................................... */ + +static t_Error TgecGetFrameSizeCounters(t_Handle h_Tgec, t_FmMacFrameSizeCounters *p_FrameSizeCounters, e_CommMode type) +{ + t_Tgec *p_Tgec = (t_Tgec *)h_Tgec; + struct tgec_regs *p_TgecMemMap; + + SANITY_CHECK_RETURN_ERROR(p_Tgec, E_NULL_POINTER); + SANITY_CHECK_RETURN_ERROR(!p_Tgec->p_TgecDriverParam, E_INVALID_STATE); + SANITY_CHECK_RETURN_ERROR(p_FrameSizeCounters, E_NULL_POINTER); + + p_TgecMemMap = p_Tgec->p_MemMap; + + switch (type) + { + case e_COMM_MODE_NONE: + break; + + case e_COMM_MODE_RX: + p_FrameSizeCounters->count_pkts_64 = fman_tgec_get_counter(p_TgecMemMap, E_TGEC_COUNTER_R64); + p_FrameSizeCounters->count_pkts_65_to_127 = fman_tgec_get_counter(p_TgecMemMap, E_TGEC_COUNTER_R127); + p_FrameSizeCounters->count_pkts_128_to_255 = fman_tgec_get_counter(p_TgecMemMap, E_TGEC_COUNTER_R255); + p_FrameSizeCounters->count_pkts_256_to_511 = fman_tgec_get_counter(p_TgecMemMap, E_TGEC_COUNTER_R511); + p_FrameSizeCounters->count_pkts_512_to_1023 = fman_tgec_get_counter(p_TgecMemMap, E_TGEC_COUNTER_R1023); + p_FrameSizeCounters->count_pkts_1024_to_1518 = fman_tgec_get_counter(p_TgecMemMap, E_TGEC_COUNTER_R1518); + p_FrameSizeCounters->count_pkts_1519_to_1522 = fman_tgec_get_counter(p_TgecMemMap, E_TGEC_COUNTER_R1519X); + break; + + case e_COMM_MODE_TX: + //Tx counters not supported + break; + + case e_COMM_MODE_RX_AND_TX: + //Tx counters not supported + break; + } + + return E_OK; +} + + +/* ......................................................................... */ + +static t_Error TgecEnable1588TimeStamp(t_Handle h_Tgec) +{ + t_Tgec *p_Tgec = (t_Tgec *)h_Tgec; + + SANITY_CHECK_RETURN_ERROR(p_Tgec, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(!p_Tgec->p_TgecDriverParam, E_INVALID_STATE); + + fman_tgec_enable_1588_time_stamp(p_Tgec->p_MemMap, 1); + + return E_OK; +} + +/* ......................................................................... */ + +static t_Error TgecDisable1588TimeStamp(t_Handle h_Tgec) +{ + t_Tgec *p_Tgec = (t_Tgec *)h_Tgec; + + SANITY_CHECK_RETURN_ERROR(p_Tgec, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(!p_Tgec->p_TgecDriverParam, E_INVALID_STATE); + + fman_tgec_enable_1588_time_stamp(p_Tgec->p_MemMap, 0); + + return E_OK; +} + +/* ......................................................................... */ + +static t_Error TgecModifyMacAddress (t_Handle h_Tgec, t_EnetAddr *p_EnetAddr) +{ + t_Tgec *p_Tgec = (t_Tgec *)h_Tgec; + + SANITY_CHECK_RETURN_ERROR(p_Tgec, E_NULL_POINTER); + SANITY_CHECK_RETURN_ERROR(!p_Tgec->p_TgecDriverParam, E_INVALID_STATE); + + p_Tgec->addr = ENET_ADDR_TO_UINT64(*p_EnetAddr); + fman_tgec_set_mac_address(p_Tgec->p_MemMap, (uint8_t *)(*p_EnetAddr)); + + return E_OK; +} + +/* ......................................................................... */ + +static t_Error TgecResetCounters (t_Handle h_Tgec) +{ + t_Tgec *p_Tgec = (t_Tgec *)h_Tgec; + + SANITY_CHECK_RETURN_ERROR(p_Tgec, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(!p_Tgec->p_TgecDriverParam, E_INVALID_STATE); + + fman_tgec_reset_stat(p_Tgec->p_MemMap); + + return E_OK; +} + +/* ......................................................................... */ + +static t_Error TgecAddExactMatchMacAddress(t_Handle h_Tgec, t_EnetAddr *p_EthAddr) +{ + t_Tgec *p_Tgec = (t_Tgec *) h_Tgec; + uint64_t ethAddr; + uint8_t paddrNum; + + SANITY_CHECK_RETURN_ERROR(p_Tgec, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(!p_Tgec->p_TgecDriverParam, E_INVALID_STATE); + + ethAddr = ENET_ADDR_TO_UINT64(*p_EthAddr); + + if (ethAddr & GROUP_ADDRESS) + /* Multicast address has no effect in PADDR */ + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("Multicast address")); + + /* Make sure no PADDR contains this address */ + for (paddrNum = 0; paddrNum < TGEC_NUM_OF_PADDRS; paddrNum++) + if (p_Tgec->indAddrRegUsed[paddrNum]) + if (p_Tgec->paddr[paddrNum] == ethAddr) + RETURN_ERROR(MAJOR, E_ALREADY_EXISTS, NO_MSG); + + /* Find first unused PADDR */ + for (paddrNum = 0; paddrNum < TGEC_NUM_OF_PADDRS; paddrNum++) + { + if (!(p_Tgec->indAddrRegUsed[paddrNum])) + { + /* mark this PADDR as used */ + p_Tgec->indAddrRegUsed[paddrNum] = TRUE; + /* store address */ + p_Tgec->paddr[paddrNum] = ethAddr; + + /* put in hardware */ + fman_tgec_add_addr_in_paddr(p_Tgec->p_MemMap, (uint8_t*)(*p_EthAddr)/* , paddrNum */); + p_Tgec->numOfIndAddrInRegs++; + + return E_OK; + } + } + + /* No free PADDR */ + RETURN_ERROR(MAJOR, E_FULL, NO_MSG); +} + +/* ......................................................................... */ + +static t_Error TgecDelExactMatchMacAddress(t_Handle h_Tgec, t_EnetAddr *p_EthAddr) +{ + t_Tgec *p_Tgec = (t_Tgec *) h_Tgec; + uint64_t ethAddr; + uint8_t paddrNum; + + SANITY_CHECK_RETURN_ERROR(p_Tgec, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(!p_Tgec->p_TgecDriverParam, E_INVALID_STATE); + + ethAddr = ENET_ADDR_TO_UINT64(*p_EthAddr); + + /* Find used PADDR containing this address */ + for (paddrNum = 0; paddrNum < TGEC_NUM_OF_PADDRS; paddrNum++) + { + if ((p_Tgec->indAddrRegUsed[paddrNum]) && + (p_Tgec->paddr[paddrNum] == ethAddr)) + { + /* mark this PADDR as not used */ + p_Tgec->indAddrRegUsed[paddrNum] = FALSE; + /* clear in hardware */ + fman_tgec_clear_addr_in_paddr(p_Tgec->p_MemMap /*, paddrNum */); + p_Tgec->numOfIndAddrInRegs--; + + return E_OK; + } + } + + RETURN_ERROR(MAJOR, E_NOT_FOUND, NO_MSG); +} + +/* ......................................................................... */ + +static t_Error TgecAddHashMacAddress(t_Handle h_Tgec, t_EnetAddr *p_EthAddr) +{ + t_Tgec *p_Tgec = (t_Tgec *)h_Tgec; + t_EthHashEntry *p_HashEntry; + uint32_t crc; + uint32_t hash; + uint64_t ethAddr; + + SANITY_CHECK_RETURN_ERROR(p_Tgec, E_NULL_POINTER); + SANITY_CHECK_RETURN_ERROR(!p_Tgec->p_TgecDriverParam, E_INVALID_STATE); + + ethAddr = ENET_ADDR_TO_UINT64(*p_EthAddr); + + if (!(ethAddr & GROUP_ADDRESS)) + /* Unicast addresses not supported in hash */ + RETURN_ERROR(MAJOR, E_NOT_SUPPORTED, ("Unicast Address")); + + /* CRC calculation */ + crc = GetMacAddrHashCode(ethAddr); + + hash = (crc >> TGEC_HASH_MCAST_SHIFT) & TGEC_HASH_ADR_MSK; /* Take 9 MSB bits */ + + /* Create element to be added to the driver hash table */ + p_HashEntry = (t_EthHashEntry *)XX_Malloc(sizeof(t_EthHashEntry)); + p_HashEntry->addr = ethAddr; + INIT_LIST(&p_HashEntry->node); + + LIST_AddToTail(&(p_HashEntry->node), &(p_Tgec->p_MulticastAddrHash->p_Lsts[hash])); + fman_tgec_set_hash_table(p_Tgec->p_MemMap, (hash | TGEC_HASH_MCAST_EN)); + + return E_OK; +} + +/* ......................................................................... */ + +static t_Error TgecDelHashMacAddress(t_Handle h_Tgec, t_EnetAddr *p_EthAddr) +{ + t_Tgec *p_Tgec = (t_Tgec *)h_Tgec; + t_EthHashEntry *p_HashEntry = NULL; + t_List *p_Pos; + uint32_t crc; + uint32_t hash; + uint64_t ethAddr; + + SANITY_CHECK_RETURN_ERROR(p_Tgec, E_NULL_POINTER); + SANITY_CHECK_RETURN_ERROR(!p_Tgec->p_TgecDriverParam, E_INVALID_STATE); + + ethAddr = ((*(uint64_t *)p_EthAddr) >> 16); + + /* CRC calculation */ + crc = GetMacAddrHashCode(ethAddr); + + hash = (crc >> TGEC_HASH_MCAST_SHIFT) & TGEC_HASH_ADR_MSK; /* Take 9 MSB bits */ + + LIST_FOR_EACH(p_Pos, &(p_Tgec->p_MulticastAddrHash->p_Lsts[hash])) + { + p_HashEntry = ETH_HASH_ENTRY_OBJ(p_Pos); + if (p_HashEntry->addr == ethAddr) + { + LIST_DelAndInit(&p_HashEntry->node); + XX_Free(p_HashEntry); + break; + } + } + if (LIST_IsEmpty(&p_Tgec->p_MulticastAddrHash->p_Lsts[hash])) + fman_tgec_set_hash_table(p_Tgec->p_MemMap, (hash & ~TGEC_HASH_MCAST_EN)); + + return E_OK; +} + +/* ......................................................................... */ + +static t_Error TgecGetId(t_Handle h_Tgec, uint32_t *macId) +{ + t_Tgec *p_Tgec = (t_Tgec *)h_Tgec; + + SANITY_CHECK_RETURN_ERROR(p_Tgec, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(!p_Tgec->p_TgecDriverParam, E_INVALID_STATE); + + UNUSED(p_Tgec); + UNUSED(macId); + RETURN_ERROR(MINOR, E_NOT_SUPPORTED, ("TgecGetId Not Supported")); +} + +/* ......................................................................... */ + +static t_Error TgecGetVersion(t_Handle h_Tgec, uint32_t *macVersion) +{ + t_Tgec *p_Tgec = (t_Tgec *)h_Tgec; + + SANITY_CHECK_RETURN_ERROR(p_Tgec, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(!p_Tgec->p_TgecDriverParam, E_INVALID_STATE); + + *macVersion = fman_tgec_get_revision(p_Tgec->p_MemMap); + + return E_OK; +} + +/* ......................................................................... */ + +static t_Error TgecSetExcpetion(t_Handle h_Tgec, e_FmMacExceptions exception, bool enable) +{ + t_Tgec *p_Tgec = (t_Tgec *)h_Tgec; + uint32_t bitMask = 0; + + SANITY_CHECK_RETURN_ERROR(p_Tgec, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(!p_Tgec->p_TgecDriverParam, E_INVALID_STATE); + + GET_EXCEPTION_FLAG(bitMask, exception); + if (bitMask) + { + if (enable) + p_Tgec->exceptions |= bitMask; + else + p_Tgec->exceptions &= ~bitMask; + } + else + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("Undefined exception")); + + if (enable) + fman_tgec_enable_interrupt(p_Tgec->p_MemMap, bitMask); + else + fman_tgec_disable_interrupt(p_Tgec->p_MemMap, bitMask); + + return E_OK; +} + +/* ......................................................................... */ + +static uint16_t TgecGetMaxFrameLength(t_Handle h_Tgec) +{ + t_Tgec *p_Tgec = (t_Tgec *)h_Tgec; + + SANITY_CHECK_RETURN_VALUE(p_Tgec, E_INVALID_HANDLE, 0); + SANITY_CHECK_RETURN_VALUE(!p_Tgec->p_TgecDriverParam, E_INVALID_STATE, 0); + + return fman_tgec_get_max_frame_len(p_Tgec->p_MemMap); +} + +/* ......................................................................... */ + +#ifdef FM_TX_ECC_FRMS_ERRATA_10GMAC_A004 +static t_Error TgecTxEccWorkaround(t_Tgec *p_Tgec) +{ + t_Error err; + +#if defined(DEBUG_ERRORS) && (DEBUG_ERRORS > 0) + XX_Print("Applying 10G TX ECC workaround (10GMAC-A004) ... "); +#endif /* (DEBUG_ERRORS > 0) */ + /* enable and set promiscuous */ + fman_tgec_enable(p_Tgec->p_MemMap, TRUE, TRUE); + fman_tgec_set_promiscuous(p_Tgec->p_MemMap, TRUE); + err = Fm10GTxEccWorkaround(p_Tgec->fmMacControllerDriver.h_Fm, p_Tgec->macId); + /* disable */ + fman_tgec_set_promiscuous(p_Tgec->p_MemMap, FALSE); + fman_tgec_enable(p_Tgec->p_MemMap, FALSE, FALSE); + fman_tgec_reset_stat(p_Tgec->p_MemMap); + fman_tgec_ack_event(p_Tgec->p_MemMap, 0xffffffff); +#if defined(DEBUG_ERRORS) && (DEBUG_ERRORS > 0) + if (err) + XX_Print("FAILED!\n"); + else + XX_Print("done.\n"); +#endif /* (DEBUG_ERRORS > 0) */ + + return err; +} +#endif /* FM_TX_ECC_FRMS_ERRATA_10GMAC_A004 */ + +/*****************************************************************************/ +/* FM Init & Free API */ +/*****************************************************************************/ + +/* ......................................................................... */ + +static t_Error TgecInit(t_Handle h_Tgec) +{ + t_Tgec *p_Tgec = (t_Tgec *)h_Tgec; + struct tgec_cfg *p_TgecDriverParam; + t_EnetAddr ethAddr; + t_Error err; + + SANITY_CHECK_RETURN_ERROR(p_Tgec, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_Tgec->p_TgecDriverParam, E_INVALID_STATE); + SANITY_CHECK_RETURN_ERROR(p_Tgec->fmMacControllerDriver.h_Fm, E_INVALID_HANDLE); + + FM_GetRevision(p_Tgec->fmMacControllerDriver.h_Fm, &p_Tgec->fmMacControllerDriver.fmRevInfo); + CHECK_INIT_PARAMETERS(p_Tgec, CheckInitParameters); + + p_TgecDriverParam = p_Tgec->p_TgecDriverParam; + + MAKE_ENET_ADDR_FROM_UINT64(p_Tgec->addr, ethAddr); + fman_tgec_set_mac_address(p_Tgec->p_MemMap, (uint8_t *)ethAddr); + + /* interrupts */ +#ifdef FM_10G_REM_N_LCL_FLT_EX_10GMAC_ERRATA_SW005 + { + if (p_Tgec->fmMacControllerDriver.fmRevInfo.majorRev <=2) + p_Tgec->exceptions &= ~(TGEC_IMASK_REM_FAULT | TGEC_IMASK_LOC_FAULT); + } +#endif /* FM_10G_REM_N_LCL_FLT_EX_10GMAC_ERRATA_SW005 */ + +#ifdef FM_TX_ECC_FRMS_ERRATA_10GMAC_A004 + if (!p_Tgec->p_TgecDriverParam->skip_fman11_workaround && + ((err = TgecTxEccWorkaround(p_Tgec)) != E_OK)) + { + FreeInitResources(p_Tgec); + REPORT_ERROR(MINOR, err, ("TgecTxEccWorkaround FAILED")); + } +#endif /* FM_TX_ECC_FRMS_ERRATA_10GMAC_A004 */ + + err = fman_tgec_init(p_Tgec->p_MemMap, p_TgecDriverParam, p_Tgec->exceptions); + if (err) + { + FreeInitResources(p_Tgec); + RETURN_ERROR(MAJOR, err, ("This TGEC version does not support the required i/f mode")); + } + + /* Max Frame Length */ + err = FmSetMacMaxFrame(p_Tgec->fmMacControllerDriver.h_Fm, + e_FM_MAC_10G, + p_Tgec->fmMacControllerDriver.macId, + p_TgecDriverParam->max_frame_length); + if (err != E_OK) + { + FreeInitResources(p_Tgec); + RETURN_ERROR(MINOR, err, NO_MSG); + } +/* we consider having no IPC a non crasher... */ + +#ifdef FM_TX_FIFO_CORRUPTION_ERRATA_10GMAC_A007 + if (p_Tgec->fmMacControllerDriver.fmRevInfo.majorRev == 2) + fman_tgec_set_erratum_tx_fifo_corruption_10gmac_a007(p_Tgec->p_MemMap); +#endif /* FM_TX_FIFO_CORRUPTION_ERRATA_10GMAC_A007 */ + + p_Tgec->p_MulticastAddrHash = AllocHashTable(HASH_TABLE_SIZE); + if (!p_Tgec->p_MulticastAddrHash) + { + FreeInitResources(p_Tgec); + RETURN_ERROR(MAJOR, E_NO_MEMORY, ("allocation hash table is FAILED")); + } + + p_Tgec->p_UnicastAddrHash = AllocHashTable(HASH_TABLE_SIZE); + if (!p_Tgec->p_UnicastAddrHash) + { + FreeInitResources(p_Tgec); + RETURN_ERROR(MAJOR, E_NO_MEMORY, ("allocation hash table is FAILED")); + } + + FmRegisterIntr(p_Tgec->fmMacControllerDriver.h_Fm, + e_FM_MOD_10G_MAC, + p_Tgec->macId, + e_FM_INTR_TYPE_ERR, + TgecErrException, + p_Tgec); + if (p_Tgec->mdioIrq != NO_IRQ) + { + XX_SetIntr(p_Tgec->mdioIrq, TgecException, p_Tgec); + XX_EnableIntr(p_Tgec->mdioIrq); + } + + XX_Free(p_TgecDriverParam); + p_Tgec->p_TgecDriverParam = NULL; + + return E_OK; +} + +/* ......................................................................... */ + +static t_Error TgecFree(t_Handle h_Tgec) +{ + t_Tgec *p_Tgec = (t_Tgec *)h_Tgec; + + SANITY_CHECK_RETURN_ERROR(p_Tgec, E_INVALID_HANDLE); + + if (p_Tgec->p_TgecDriverParam) + { + /* Called after config */ + XX_Free(p_Tgec->p_TgecDriverParam); + p_Tgec->p_TgecDriverParam = NULL; + } + else + /* Called after init */ + FreeInitResources(p_Tgec); + + XX_Free(p_Tgec); + + return E_OK; +} + +/* ......................................................................... */ + +static void InitFmMacControllerDriver(t_FmMacControllerDriver *p_FmMacControllerDriver) +{ + p_FmMacControllerDriver->f_FM_MAC_Init = TgecInit; + p_FmMacControllerDriver->f_FM_MAC_Free = TgecFree; + + p_FmMacControllerDriver->f_FM_MAC_SetStatistics = NULL; + p_FmMacControllerDriver->f_FM_MAC_ConfigLoopback = TgecConfigLoopback; + p_FmMacControllerDriver->f_FM_MAC_ConfigMaxFrameLength = TgecConfigMaxFrameLength; + + p_FmMacControllerDriver->f_FM_MAC_ConfigWan = TgecConfigWan; + + p_FmMacControllerDriver->f_FM_MAC_ConfigPadAndCrc = NULL; /* TGEC always works with pad+crc */ + p_FmMacControllerDriver->f_FM_MAC_ConfigHalfDuplex = NULL; /* half-duplex is not supported in xgec */ + p_FmMacControllerDriver->f_FM_MAC_ConfigLengthCheck = TgecConfigLengthCheck; + p_FmMacControllerDriver->f_FM_MAC_ConfigException = TgecConfigException; + p_FmMacControllerDriver->f_FM_MAC_ConfigResetOnInit = NULL; + +#ifdef FM_TX_ECC_FRMS_ERRATA_10GMAC_A004 + p_FmMacControllerDriver->f_FM_MAC_ConfigSkipFman11Workaround= TgecConfigSkipFman11Workaround; +#endif /* FM_TX_ECC_FRMS_ERRATA_10GMAC_A004 */ + + p_FmMacControllerDriver->f_FM_MAC_SetException = TgecSetExcpetion; + + p_FmMacControllerDriver->f_FM_MAC_Enable1588TimeStamp = TgecEnable1588TimeStamp; + p_FmMacControllerDriver->f_FM_MAC_Disable1588TimeStamp = TgecDisable1588TimeStamp; + + p_FmMacControllerDriver->f_FM_MAC_SetPromiscuous = TgecSetPromiscuous; + p_FmMacControllerDriver->f_FM_MAC_AdjustLink = NULL; + p_FmMacControllerDriver->f_FM_MAC_SetWakeOnLan = NULL; + p_FmMacControllerDriver->f_FM_MAC_RestartAutoneg = NULL; + + p_FmMacControllerDriver->f_FM_MAC_Enable = TgecEnable; + p_FmMacControllerDriver->f_FM_MAC_Disable = TgecDisable; + p_FmMacControllerDriver->f_FM_MAC_Resume = NULL; + + p_FmMacControllerDriver->f_FM_MAC_SetTxAutoPauseFrames = TgecTxMacPause; + p_FmMacControllerDriver->f_FM_MAC_SetTxPauseFrames = TgecSetTxPauseFrames; + p_FmMacControllerDriver->f_FM_MAC_SetRxIgnorePauseFrames = TgecRxIgnoreMacPause; + + p_FmMacControllerDriver->f_FM_MAC_ResetCounters = TgecResetCounters; + p_FmMacControllerDriver->f_FM_MAC_GetStatistics = TgecGetStatistics; + p_FmMacControllerDriver->f_FM_MAC_GetFrameSizeCounters = TgecGetFrameSizeCounters; + + p_FmMacControllerDriver->f_FM_MAC_ModifyMacAddr = TgecModifyMacAddress; + p_FmMacControllerDriver->f_FM_MAC_AddHashMacAddr = TgecAddHashMacAddress; + p_FmMacControllerDriver->f_FM_MAC_RemoveHashMacAddr = TgecDelHashMacAddress; + p_FmMacControllerDriver->f_FM_MAC_AddExactMatchMacAddr = TgecAddExactMatchMacAddress; + p_FmMacControllerDriver->f_FM_MAC_RemovelExactMatchMacAddr = TgecDelExactMatchMacAddress; + p_FmMacControllerDriver->f_FM_MAC_GetId = TgecGetId; + p_FmMacControllerDriver->f_FM_MAC_GetVersion = TgecGetVersion; + p_FmMacControllerDriver->f_FM_MAC_GetMaxFrameLength = TgecGetMaxFrameLength; + + p_FmMacControllerDriver->f_FM_MAC_MII_WritePhyReg = TGEC_MII_WritePhyReg; + p_FmMacControllerDriver->f_FM_MAC_MII_ReadPhyReg = TGEC_MII_ReadPhyReg; +} + + +/*****************************************************************************/ +/* Tgec Config Main Entry */ +/*****************************************************************************/ + +/* ......................................................................... */ + +t_Handle TGEC_Config(t_FmMacParams *p_FmMacParam) +{ + t_Tgec *p_Tgec; + struct tgec_cfg *p_TgecDriverParam; + uintptr_t baseAddr; + + SANITY_CHECK_RETURN_VALUE(p_FmMacParam, E_NULL_POINTER, NULL); + + baseAddr = p_FmMacParam->baseAddr; + /* allocate memory for the UCC GETH data structure. */ + p_Tgec = (t_Tgec *)XX_Malloc(sizeof(t_Tgec)); + if (!p_Tgec) + { + REPORT_ERROR(MAJOR, E_NO_MEMORY, ("10G MAC driver structure")); + return NULL; + } + memset(p_Tgec, 0, sizeof(t_Tgec)); + InitFmMacControllerDriver(&p_Tgec->fmMacControllerDriver); + + /* allocate memory for the 10G MAC driver parameters data structure. */ + p_TgecDriverParam = (struct tgec_cfg *) XX_Malloc(sizeof(struct tgec_cfg)); + if (!p_TgecDriverParam) + { + REPORT_ERROR(MAJOR, E_NO_MEMORY, ("10G MAC driver parameters")); + XX_Free(p_Tgec); + return NULL; + } + memset(p_TgecDriverParam, 0, sizeof(struct tgec_cfg)); + + /* Plant parameter structure pointer */ + p_Tgec->p_TgecDriverParam = p_TgecDriverParam; + + fman_tgec_defconfig(p_TgecDriverParam); + + p_Tgec->p_MemMap = (struct tgec_regs *)UINT_TO_PTR(baseAddr); + p_Tgec->p_MiiMemMap = (t_TgecMiiAccessMemMap *)UINT_TO_PTR(baseAddr + TGEC_TO_MII_OFFSET); + p_Tgec->addr = ENET_ADDR_TO_UINT64(p_FmMacParam->addr); + p_Tgec->enetMode = p_FmMacParam->enetMode; + p_Tgec->macId = p_FmMacParam->macId; + p_Tgec->exceptions = DEFAULT_exceptions; + p_Tgec->mdioIrq = p_FmMacParam->mdioIrq; + p_Tgec->f_Exception = p_FmMacParam->f_Exception; + p_Tgec->f_Event = p_FmMacParam->f_Event; + p_Tgec->h_App = p_FmMacParam->h_App; + + return p_Tgec; +} diff --git a/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MAC/tgec.h b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MAC/tgec.h new file mode 100644 index 000000000000..2aa392385588 --- /dev/null +++ b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MAC/tgec.h @@ -0,0 +1,151 @@ +/* + * Copyright 2008-2012 Freescale Semiconductor Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Freescale Semiconductor nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * + * ALTERNATIVELY, this software may be distributed under the terms of the + * GNU General Public License ("GPL") as published by the Free Software + * Foundation, either version 2 of that License or (at your option) any + * later version. + * + * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + +/****************************************************************************** + @File tgec.h + + @Description FM 10G MAC ... +*//***************************************************************************/ +#ifndef __TGEC_H +#define __TGEC_H + +#include "std_ext.h" +#include "error_ext.h" +#include "list_ext.h" +#include "enet_ext.h" + +#include "tgec_mii_acc.h" +#include "fm_mac.h" + + +#define DEFAULT_exceptions \ + ((uint32_t)(TGEC_IMASK_MDIO_SCAN_EVENT | \ + TGEC_IMASK_REM_FAULT | \ + TGEC_IMASK_LOC_FAULT | \ + TGEC_IMASK_TX_ECC_ER | \ + TGEC_IMASK_TX_FIFO_UNFL | \ + TGEC_IMASK_TX_FIFO_OVFL | \ + TGEC_IMASK_TX_ER | \ + TGEC_IMASK_RX_FIFO_OVFL | \ + TGEC_IMASK_RX_ECC_ER | \ + TGEC_IMASK_RX_JAB_FRM | \ + TGEC_IMASK_RX_OVRSZ_FRM | \ + TGEC_IMASK_RX_RUNT_FRM | \ + TGEC_IMASK_RX_FRAG_FRM | \ + TGEC_IMASK_RX_CRC_ER | \ + TGEC_IMASK_RX_ALIGN_ER)) + +#define GET_EXCEPTION_FLAG(bitMask, exception) switch (exception){ \ + case e_FM_MAC_EX_10G_MDIO_SCAN_EVENTMDIO: \ + bitMask = TGEC_IMASK_MDIO_SCAN_EVENT ; break; \ + case e_FM_MAC_EX_10G_MDIO_CMD_CMPL: \ + bitMask = TGEC_IMASK_MDIO_CMD_CMPL ; break; \ + case e_FM_MAC_EX_10G_REM_FAULT: \ + bitMask = TGEC_IMASK_REM_FAULT ; break; \ + case e_FM_MAC_EX_10G_LOC_FAULT: \ + bitMask = TGEC_IMASK_LOC_FAULT ; break; \ + case e_FM_MAC_EX_10G_1TX_ECC_ER: \ + bitMask = TGEC_IMASK_TX_ECC_ER ; break; \ + case e_FM_MAC_EX_10G_TX_FIFO_UNFL: \ + bitMask = TGEC_IMASK_TX_FIFO_UNFL ; break; \ + case e_FM_MAC_EX_10G_TX_FIFO_OVFL: \ + bitMask = TGEC_IMASK_TX_FIFO_OVFL ; break; \ + case e_FM_MAC_EX_10G_TX_ER: \ + bitMask = TGEC_IMASK_TX_ER ; break; \ + case e_FM_MAC_EX_10G_RX_FIFO_OVFL: \ + bitMask = TGEC_IMASK_RX_FIFO_OVFL ; break; \ + case e_FM_MAC_EX_10G_RX_ECC_ER: \ + bitMask = TGEC_IMASK_RX_ECC_ER ; break; \ + case e_FM_MAC_EX_10G_RX_JAB_FRM: \ + bitMask = TGEC_IMASK_RX_JAB_FRM ; break; \ + case e_FM_MAC_EX_10G_RX_OVRSZ_FRM: \ + bitMask = TGEC_IMASK_RX_OVRSZ_FRM ; break; \ + case e_FM_MAC_EX_10G_RX_RUNT_FRM: \ + bitMask = TGEC_IMASK_RX_RUNT_FRM ; break; \ + case e_FM_MAC_EX_10G_RX_FRAG_FRM: \ + bitMask = TGEC_IMASK_RX_FRAG_FRM ; break; \ + case e_FM_MAC_EX_10G_RX_LEN_ER: \ + bitMask = TGEC_IMASK_RX_LEN_ER ; break; \ + case e_FM_MAC_EX_10G_RX_CRC_ER: \ + bitMask = TGEC_IMASK_RX_CRC_ER ; break; \ + case e_FM_MAC_EX_10G_RX_ALIGN_ER: \ + bitMask = TGEC_IMASK_RX_ALIGN_ER ; break; \ + default: bitMask = 0;break;} + +#define MAX_PACKET_ALIGNMENT 31 +#define MAX_INTER_PACKET_GAP 0x7f +#define MAX_INTER_PALTERNATE_BEB 0x0f +#define MAX_RETRANSMISSION 0x0f +#define MAX_COLLISION_WINDOW 0x03ff + +#define TGEC_NUM_OF_PADDRS 1 /* number of pattern match registers (entries) */ + +#define GROUP_ADDRESS 0x0000010000000000LL /* Group address bit indication */ + +#define HASH_TABLE_SIZE 512 /* Hash table size (= 32 bits * 8 regs) */ + +#define TGEC_TO_MII_OFFSET 0x1030 /* Offset from the MEM map to the MDIO mem map */ + +/* 10-gigabit Ethernet MAC Controller ID (10GEC_ID) */ +#define TGEC_ID_ID 0xffff0000 +#define TGEC_ID_MAC_VERSION 0x0000FF00 +#define TGEC_ID_MAC_REV 0x000000ff + + +typedef struct { + t_FmMacControllerDriver fmMacControllerDriver; /**< Upper Mac control block */ + t_Handle h_App; /**< Handle to the upper layer application */ + struct tgec_regs *p_MemMap; /**< pointer to 10G memory mapped registers. */ + t_TgecMiiAccessMemMap *p_MiiMemMap; /**< pointer to MII memory mapped registers. */ + uint64_t addr; /**< MAC address of device; */ + e_EnetMode enetMode; /**< Ethernet physical interface */ + t_FmMacExceptionCallback *f_Exception; + int mdioIrq; + t_FmMacExceptionCallback *f_Event; + bool indAddrRegUsed[TGEC_NUM_OF_PADDRS]; /**< Whether a particular individual address recognition register is being used */ + uint64_t paddr[TGEC_NUM_OF_PADDRS]; /**< MAC address for particular individual address recognition register */ + uint8_t numOfIndAddrInRegs; /**< Number of individual addresses in registers for this station. */ + t_EthHash *p_MulticastAddrHash; /**< pointer to driver's global address hash table */ + t_EthHash *p_UnicastAddrHash; /**< pointer to driver's individual address hash table */ + bool debugMode; + uint8_t macId; + uint32_t exceptions; + struct tgec_cfg *p_TgecDriverParam; +} t_Tgec; + + +t_Error TGEC_MII_WritePhyReg(t_Handle h_Tgec, uint8_t phyAddr, uint8_t reg, uint16_t data); +t_Error TGEC_MII_ReadPhyReg(t_Handle h_Tgec, uint8_t phyAddr, uint8_t reg, uint16_t *p_Data); + + +#endif /* __TGEC_H */ diff --git a/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MAC/tgec_mii_acc.c b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MAC/tgec_mii_acc.c new file mode 100644 index 000000000000..e0fafd1d174d --- /dev/null +++ b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MAC/tgec_mii_acc.c @@ -0,0 +1,139 @@ +/* + * Copyright 2008-2012 Freescale Semiconductor Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Freescale Semiconductor nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * + * ALTERNATIVELY, this software may be distributed under the terms of the + * GNU General Public License ("GPL") as published by the Free Software + * Foundation, either version 2 of that License or (at your option) any + * later version. + * + * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + + +#include "error_ext.h" +#include "std_ext.h" +#include "fm_mac.h" +#include "tgec.h" +#include "xx_ext.h" + +#include "fm_common.h" + + +/*****************************************************************************/ +t_Error TGEC_MII_WritePhyReg(t_Handle h_Tgec, + uint8_t phyAddr, + uint8_t reg, + uint16_t data) +{ + t_Tgec *p_Tgec = (t_Tgec *)h_Tgec; + t_TgecMiiAccessMemMap *p_MiiAccess; + uint32_t cfgStatusReg; + + SANITY_CHECK_RETURN_ERROR(p_Tgec, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_Tgec->p_MiiMemMap, E_INVALID_HANDLE); + + p_MiiAccess = p_Tgec->p_MiiMemMap; + + /* Configure MII */ + cfgStatusReg = GET_UINT32(p_MiiAccess->mdio_cfg_status); + cfgStatusReg &= ~MIIMCOM_DIV_MASK; + /* (one half of fm clock => 2.5Mhz) */ + cfgStatusReg |=((((p_Tgec->fmMacControllerDriver.clkFreq*10)/2)/25) << MIIMCOM_DIV_SHIFT); + WRITE_UINT32(p_MiiAccess->mdio_cfg_status, cfgStatusReg); + + while ((GET_UINT32(p_MiiAccess->mdio_cfg_status)) & MIIMIND_BUSY) + XX_UDelay (1); + + WRITE_UINT32(p_MiiAccess->mdio_command, phyAddr); + + WRITE_UINT32(p_MiiAccess->mdio_regaddr, reg); + + CORE_MemoryBarrier(); + + while ((GET_UINT32(p_MiiAccess->mdio_cfg_status)) & MIIMIND_BUSY) + XX_UDelay (1); + + WRITE_UINT32(p_MiiAccess->mdio_data, data); + + CORE_MemoryBarrier(); + + while ((GET_UINT32(p_MiiAccess->mdio_data)) & MIIDATA_BUSY) + XX_UDelay (1); + + return E_OK; +} + +/*****************************************************************************/ +t_Error TGEC_MII_ReadPhyReg(t_Handle h_Tgec, + uint8_t phyAddr, + uint8_t reg, + uint16_t *p_Data) +{ + t_Tgec *p_Tgec = (t_Tgec *)h_Tgec; + t_TgecMiiAccessMemMap *p_MiiAccess; + uint32_t cfgStatusReg; + + SANITY_CHECK_RETURN_ERROR(p_Tgec, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_Tgec->p_MiiMemMap, E_INVALID_HANDLE); + + p_MiiAccess = p_Tgec->p_MiiMemMap; + + /* Configure MII */ + cfgStatusReg = GET_UINT32(p_MiiAccess->mdio_cfg_status); + cfgStatusReg &= ~MIIMCOM_DIV_MASK; + /* (one half of fm clock => 2.5Mhz) */ + cfgStatusReg |=((((p_Tgec->fmMacControllerDriver.clkFreq*10)/2)/25) << MIIMCOM_DIV_SHIFT); + WRITE_UINT32(p_MiiAccess->mdio_cfg_status, cfgStatusReg); + + while ((GET_UINT32(p_MiiAccess->mdio_cfg_status)) & MIIMIND_BUSY) + XX_UDelay (1); + + WRITE_UINT32(p_MiiAccess->mdio_command, phyAddr); + + WRITE_UINT32(p_MiiAccess->mdio_regaddr, reg); + + CORE_MemoryBarrier(); + + while ((GET_UINT32(p_MiiAccess->mdio_cfg_status)) & MIIMIND_BUSY) + XX_UDelay (1); + + WRITE_UINT32(p_MiiAccess->mdio_command, (uint32_t)(phyAddr | MIIMCOM_READ_CYCLE)); + + CORE_MemoryBarrier(); + + while ((GET_UINT32(p_MiiAccess->mdio_data)) & MIIDATA_BUSY) + XX_UDelay (1); + + *p_Data = (uint16_t)GET_UINT32(p_MiiAccess->mdio_data); + + cfgStatusReg = GET_UINT32(p_MiiAccess->mdio_cfg_status); + + if (cfgStatusReg & MIIMIND_READ_ERROR) + RETURN_ERROR(MINOR, E_INVALID_VALUE, + ("Read Error: phyAddr 0x%x, dev 0x%x, reg 0x%x, cfgStatusReg 0x%x", + ((phyAddr & 0xe0)>>5), (phyAddr & 0x1f), reg, cfgStatusReg)); + + return E_OK; +} diff --git a/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MAC/tgec_mii_acc.h b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MAC/tgec_mii_acc.h new file mode 100644 index 000000000000..645cdde57973 --- /dev/null +++ b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MAC/tgec_mii_acc.h @@ -0,0 +1,80 @@ +/* + * Copyright 2008-2012 Freescale Semiconductor Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Freescale Semiconductor nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * + * ALTERNATIVELY, this software may be distributed under the terms of the + * GNU General Public License ("GPL") as published by the Free Software + * Foundation, either version 2 of that License or (at your option) any + * later version. + * + * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + +#ifndef __TGEC_MII_ACC_H +#define __TGEC_MII_ACC_H + +#include "std_ext.h" + + +/* MII Management Command Register */ +#define MIIMCOM_READ_POST_INCREMENT 0x00004000 +#define MIIMCOM_READ_CYCLE 0x00008000 +#define MIIMCOM_SCAN_CYCLE 0x00000800 +#define MIIMCOM_PREAMBLE_DISABLE 0x00000400 + +#define MIIMCOM_MDIO_HOLD_1_REG_CLK 0 +#define MIIMCOM_MDIO_HOLD_2_REG_CLK 1 +#define MIIMCOM_MDIO_HOLD_3_REG_CLK 2 +#define MIIMCOM_MDIO_HOLD_4_REG_CLK 3 + +#define MIIMCOM_DIV_MASK 0x0000ff00 +#define MIIMCOM_DIV_SHIFT 8 + +/* MII Management Indicator Register */ +#define MIIMIND_BUSY 0x00000001 +#define MIIMIND_READ_ERROR 0x00000002 + +#define MIIDATA_BUSY 0x80000000 + +#if defined(__MWERKS__) && !defined(__GNUC__) +#pragma pack(push,1) +#endif /* defined(__MWERKS__) && ... */ + +/*----------------------------------------------------*/ +/* MII Configuration Control Memory Map Registers */ +/*----------------------------------------------------*/ +typedef _Packed struct t_TgecMiiAccessMemMap +{ + volatile uint32_t mdio_cfg_status; /* 0x030 */ + volatile uint32_t mdio_command; /* 0x034 */ + volatile uint32_t mdio_data; /* 0x038 */ + volatile uint32_t mdio_regaddr; /* 0x03c */ +} _PackedType t_TgecMiiAccessMemMap ; + +#if defined(__MWERKS__) && !defined(__GNUC__) +#pragma pack(pop) +#endif /* defined(__MWERKS__) && ... */ + + +#endif /* __TGEC_MII_ACC_H */ diff --git a/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MACSEC/Makefile b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MACSEC/Makefile new file mode 100644 index 000000000000..bfa02f5ee92d --- /dev/null +++ b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MACSEC/Makefile @@ -0,0 +1,15 @@ +# +# Makefile for the Freescale Ethernet controllers +# +ccflags-y += -DVERSION=\"\" +# +#Include netcomm SW specific definitions +include $(srctree)/drivers/net/ethernet/freescale/sdk_fman/ncsw_config.mk + +NCSW_FM_INC = $(srctree)/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/inc + +ccflags-y += -I$(NCSW_FM_INC) + +obj-y += fsl-ncsw-macsec.o + +fsl-ncsw-macsec-objs := fm_macsec.o fm_macsec_guest.o fm_macsec_master.o fm_macsec_secy.o diff --git a/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MACSEC/fm_macsec.c b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MACSEC/fm_macsec.c new file mode 100644 index 000000000000..0a1b31f11d5f --- /dev/null +++ b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MACSEC/fm_macsec.c @@ -0,0 +1,237 @@ +/* + * Copyright 2008-2015 Freescale Semiconductor Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Freescale Semiconductor nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * + * ALTERNATIVELY, this software may be distributed under the terms of the + * GNU General Public License ("GPL") as published by the Free Software + * Foundation, either version 2 of that License or (at your option) any + * later version. + * + * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +/****************************************************************************** + + @File fm_macsec.c + + @Description FM MACSEC driver routines implementation. +*//***************************************************************************/ + +#include "std_ext.h" +#include "error_ext.h" +#include "xx_ext.h" +#include "string_ext.h" +#include "sprint_ext.h" +#include "debug_ext.h" + +#include "fm_macsec.h" + + +/****************************************/ +/* API Init unit functions */ +/****************************************/ +t_Handle FM_MACSEC_Config(t_FmMacsecParams *p_FmMacsecParam) +{ + t_FmMacsecControllerDriver *p_FmMacsecControllerDriver; + + SANITY_CHECK_RETURN_VALUE(p_FmMacsecParam, E_INVALID_HANDLE, NULL); + + if (p_FmMacsecParam->guestMode) + p_FmMacsecControllerDriver = (t_FmMacsecControllerDriver *)FM_MACSEC_GUEST_Config(p_FmMacsecParam); + else + p_FmMacsecControllerDriver = (t_FmMacsecControllerDriver *)FM_MACSEC_MASTER_Config(p_FmMacsecParam); + + if (!p_FmMacsecControllerDriver) + return NULL; + + return (t_Handle)p_FmMacsecControllerDriver; +} + +t_Error FM_MACSEC_Init(t_Handle h_FmMacsec) +{ + t_FmMacsecControllerDriver *p_FmMacsecControllerDriver = (t_FmMacsecControllerDriver *)h_FmMacsec; + + SANITY_CHECK_RETURN_ERROR(p_FmMacsecControllerDriver, E_INVALID_HANDLE); + + if (p_FmMacsecControllerDriver->f_FM_MACSEC_Init) + return p_FmMacsecControllerDriver->f_FM_MACSEC_Init(h_FmMacsec); + + RETURN_ERROR(MINOR, E_NOT_SUPPORTED, NO_MSG); +} + +t_Error FM_MACSEC_Free(t_Handle h_FmMacsec) +{ + t_FmMacsecControllerDriver *p_FmMacsecControllerDriver = (t_FmMacsecControllerDriver *)h_FmMacsec; + + SANITY_CHECK_RETURN_ERROR(p_FmMacsecControllerDriver, E_INVALID_HANDLE); + + if (p_FmMacsecControllerDriver->f_FM_MACSEC_Free) + return p_FmMacsecControllerDriver->f_FM_MACSEC_Free(h_FmMacsec); + + RETURN_ERROR(MINOR, E_NOT_SUPPORTED, NO_MSG); +} + +t_Error FM_MACSEC_ConfigUnknownSciFrameTreatment(t_Handle h_FmMacsec, e_FmMacsecUnknownSciFrameTreatment treatMode) +{ + t_FmMacsecControllerDriver *p_FmMacsecControllerDriver = (t_FmMacsecControllerDriver *)h_FmMacsec; + + SANITY_CHECK_RETURN_ERROR(p_FmMacsecControllerDriver, E_INVALID_HANDLE); + + if (p_FmMacsecControllerDriver->f_FM_MACSEC_ConfigUnknownSciFrameTreatment) + return p_FmMacsecControllerDriver->f_FM_MACSEC_ConfigUnknownSciFrameTreatment(h_FmMacsec, treatMode); + + RETURN_ERROR(MINOR, E_NOT_SUPPORTED, NO_MSG); +} + +t_Error FM_MACSEC_ConfigInvalidTagsFrameTreatment(t_Handle h_FmMacsec, bool deliverUncontrolled) +{ + t_FmMacsecControllerDriver *p_FmMacsecControllerDriver = (t_FmMacsecControllerDriver *)h_FmMacsec; + + SANITY_CHECK_RETURN_ERROR(p_FmMacsecControllerDriver, E_INVALID_HANDLE); + + if (p_FmMacsecControllerDriver->f_FM_MACSEC_ConfigInvalidTagsFrameTreatment) + return p_FmMacsecControllerDriver->f_FM_MACSEC_ConfigInvalidTagsFrameTreatment(h_FmMacsec, deliverUncontrolled); + + RETURN_ERROR(MINOR, E_NOT_SUPPORTED, NO_MSG); +} + +t_Error FM_MACSEC_ConfigEncryptWithNoChangedTextFrameTreatment(t_Handle h_FmMacsec, bool discardUncontrolled) +{ + t_FmMacsecControllerDriver *p_FmMacsecControllerDriver = (t_FmMacsecControllerDriver *)h_FmMacsec; + + SANITY_CHECK_RETURN_ERROR(p_FmMacsecControllerDriver, E_INVALID_HANDLE); + + if (p_FmMacsecControllerDriver->f_FM_MACSEC_ConfigEncryptWithNoChangedTextFrameTreatment) + return p_FmMacsecControllerDriver->f_FM_MACSEC_ConfigEncryptWithNoChangedTextFrameTreatment(h_FmMacsec, discardUncontrolled); + + RETURN_ERROR(MINOR, E_NOT_SUPPORTED, NO_MSG); +} + +t_Error FM_MACSEC_ConfigUntagFrameTreatment(t_Handle h_FmMacsec, e_FmMacsecUntagFrameTreatment treatMode) +{ + t_FmMacsecControllerDriver *p_FmMacsecControllerDriver = (t_FmMacsecControllerDriver *)h_FmMacsec; + + SANITY_CHECK_RETURN_ERROR(p_FmMacsecControllerDriver, E_INVALID_HANDLE); + + if (p_FmMacsecControllerDriver->f_FM_MACSEC_ConfigUntagFrameTreatment) + return p_FmMacsecControllerDriver->f_FM_MACSEC_ConfigUntagFrameTreatment(h_FmMacsec, treatMode); + + RETURN_ERROR(MINOR, E_NOT_SUPPORTED, NO_MSG); +} + +t_Error FM_MACSEC_ConfigPnExhaustionThreshold(t_Handle h_FmMacsec, uint32_t pnExhThr) +{ + t_FmMacsecControllerDriver *p_FmMacsecControllerDriver = (t_FmMacsecControllerDriver *)h_FmMacsec; + + SANITY_CHECK_RETURN_ERROR(p_FmMacsecControllerDriver, E_INVALID_HANDLE); + + if (p_FmMacsecControllerDriver->f_FM_MACSEC_ConfigPnExhaustionThreshold) + return p_FmMacsecControllerDriver->f_FM_MACSEC_ConfigPnExhaustionThreshold(h_FmMacsec, pnExhThr); + + RETURN_ERROR(MINOR, E_NOT_SUPPORTED, NO_MSG); +} + +t_Error FM_MACSEC_ConfigKeysUnreadable(t_Handle h_FmMacsec) +{ + t_FmMacsecControllerDriver *p_FmMacsecControllerDriver = (t_FmMacsecControllerDriver *)h_FmMacsec; + + SANITY_CHECK_RETURN_ERROR(p_FmMacsecControllerDriver, E_INVALID_HANDLE); + + if (p_FmMacsecControllerDriver->f_FM_MACSEC_ConfigKeysUnreadable) + return p_FmMacsecControllerDriver->f_FM_MACSEC_ConfigKeysUnreadable(h_FmMacsec); + + RETURN_ERROR(MINOR, E_NOT_SUPPORTED, NO_MSG); +} + +t_Error FM_MACSEC_ConfigSectagWithoutSCI(t_Handle h_FmMacsec) +{ + t_FmMacsecControllerDriver *p_FmMacsecControllerDriver = (t_FmMacsecControllerDriver *)h_FmMacsec; + + SANITY_CHECK_RETURN_ERROR(p_FmMacsecControllerDriver, E_INVALID_HANDLE); + + if (p_FmMacsecControllerDriver->f_FM_MACSEC_ConfigSectagWithoutSCI) + return p_FmMacsecControllerDriver->f_FM_MACSEC_ConfigSectagWithoutSCI(h_FmMacsec); + + RETURN_ERROR(MINOR, E_NOT_SUPPORTED, NO_MSG); +} + +t_Error FM_MACSEC_ConfigException(t_Handle h_FmMacsec, e_FmMacsecExceptions exception, bool enable) +{ + t_FmMacsecControllerDriver *p_FmMacsecControllerDriver = (t_FmMacsecControllerDriver *)h_FmMacsec; + + SANITY_CHECK_RETURN_ERROR(p_FmMacsecControllerDriver, E_INVALID_HANDLE); + + if (p_FmMacsecControllerDriver->f_FM_MACSEC_ConfigException) + return p_FmMacsecControllerDriver->f_FM_MACSEC_ConfigException(h_FmMacsec, exception, enable); + + RETURN_ERROR(MINOR, E_NOT_SUPPORTED, NO_MSG); +} + +t_Error FM_MACSEC_GetRevision(t_Handle h_FmMacsec, uint32_t *p_MacsecRevision) +{ + t_FmMacsecControllerDriver *p_FmMacsecControllerDriver = (t_FmMacsecControllerDriver *)h_FmMacsec; + + SANITY_CHECK_RETURN_ERROR(p_FmMacsecControllerDriver, E_INVALID_HANDLE); + + if (p_FmMacsecControllerDriver->f_FM_MACSEC_GetRevision) + return p_FmMacsecControllerDriver->f_FM_MACSEC_GetRevision(h_FmMacsec, p_MacsecRevision); + + RETURN_ERROR(MINOR, E_NOT_SUPPORTED, NO_MSG); +} + + +t_Error FM_MACSEC_Enable(t_Handle h_FmMacsec) +{ + t_FmMacsecControllerDriver *p_FmMacsecControllerDriver = (t_FmMacsecControllerDriver *)h_FmMacsec; + + SANITY_CHECK_RETURN_ERROR(p_FmMacsecControllerDriver, E_INVALID_HANDLE); + + if (p_FmMacsecControllerDriver->f_FM_MACSEC_Enable) + return p_FmMacsecControllerDriver->f_FM_MACSEC_Enable(h_FmMacsec); + + RETURN_ERROR(MINOR, E_NOT_SUPPORTED, NO_MSG); +} + +t_Error FM_MACSEC_Disable(t_Handle h_FmMacsec) +{ + t_FmMacsecControllerDriver *p_FmMacsecControllerDriver = (t_FmMacsecControllerDriver *)h_FmMacsec; + + SANITY_CHECK_RETURN_ERROR(p_FmMacsecControllerDriver, E_INVALID_HANDLE); + + if (p_FmMacsecControllerDriver->f_FM_MACSEC_Disable) + return p_FmMacsecControllerDriver->f_FM_MACSEC_Disable(h_FmMacsec); + + RETURN_ERROR(MINOR, E_NOT_SUPPORTED, NO_MSG); +} + +t_Error FM_MACSEC_SetException(t_Handle h_FmMacsec, e_FmMacsecExceptions exception, bool enable) +{ + t_FmMacsecControllerDriver *p_FmMacsecControllerDriver = (t_FmMacsecControllerDriver *)h_FmMacsec; + + SANITY_CHECK_RETURN_ERROR(p_FmMacsecControllerDriver, E_INVALID_HANDLE); + + if (p_FmMacsecControllerDriver->f_FM_MACSEC_SetException) + return p_FmMacsecControllerDriver->f_FM_MACSEC_SetException(h_FmMacsec, exception, enable); + + RETURN_ERROR(MINOR, E_NOT_SUPPORTED, NO_MSG); +} + diff --git a/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MACSEC/fm_macsec.h b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MACSEC/fm_macsec.h new file mode 100644 index 000000000000..fbe51875f92f --- /dev/null +++ b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MACSEC/fm_macsec.h @@ -0,0 +1,203 @@ +/* + * Copyright 2008-2015 Freescale Semiconductor Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Freescale Semiconductor nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * + * ALTERNATIVELY, this software may be distributed under the terms of the + * GNU General Public License ("GPL") as published by the Free Software + * Foundation, either version 2 of that License or (at your option) any + * later version. + * + * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/****************************************************************************** + @File fm_macsec.h + + @Description FM MACSEC internal structures and definitions. +*//***************************************************************************/ +#ifndef __FM_MACSEC_H +#define __FM_MACSEC_H + +#include "error_ext.h" +#include "std_ext.h" +#include "fm_macsec_ext.h" + +#include "fm_common.h" + + +#define __ERR_MODULE__ MODULE_FM_MACSEC + + +typedef struct +{ + t_Error (*f_FM_MACSEC_Init) (t_Handle h_FmMacsec); + t_Error (*f_FM_MACSEC_Free) (t_Handle h_FmMacsec); + + t_Error (*f_FM_MACSEC_ConfigUnknownSciFrameTreatment) (t_Handle h_FmMacsec, e_FmMacsecUnknownSciFrameTreatment treatMode); + t_Error (*f_FM_MACSEC_ConfigInvalidTagsFrameTreatment) (t_Handle h_FmMacsec, bool deliverUncontrolled); + t_Error (*f_FM_MACSEC_ConfigEncryptWithNoChangedTextFrameTreatment) (t_Handle h_FmMacsec, bool discardUncontrolled); + t_Error (*f_FM_MACSEC_ConfigChangedTextWithNoEncryptFrameTreatment) (t_Handle h_FmMacsec, bool deliverUncontrolled); + t_Error (*f_FM_MACSEC_ConfigUntagFrameTreatment) (t_Handle h_FmMacsec, e_FmMacsecUntagFrameTreatment treatMode); + t_Error (*f_FM_MACSEC_ConfigOnlyScbIsSetFrameTreatment) (t_Handle h_FmMacsec, bool deliverUncontrolled); + t_Error (*f_FM_MACSEC_ConfigPnExhaustionThreshold) (t_Handle h_FmMacsec, uint32_t pnExhThr); + t_Error (*f_FM_MACSEC_ConfigKeysUnreadable) (t_Handle h_FmMacsec); + t_Error (*f_FM_MACSEC_ConfigSectagWithoutSCI) (t_Handle h_FmMacsec); + t_Error (*f_FM_MACSEC_ConfigException) (t_Handle h_FmMacsec, e_FmMacsecExceptions exception, bool enable); + + t_Error (*f_FM_MACSEC_GetRevision) (t_Handle h_FmMacsec, uint32_t *p_MacsecRevision); + t_Error (*f_FM_MACSEC_Enable) (t_Handle h_FmMacsec); + t_Error (*f_FM_MACSEC_Disable) (t_Handle h_FmMacsec); + t_Error (*f_FM_MACSEC_SetException) (t_Handle h_FmMacsec, e_FmMacsecExceptions exception, bool enable); + +} t_FmMacsecControllerDriver; + +t_Handle FM_MACSEC_GUEST_Config(t_FmMacsecParams *p_FmMacsecParam); +t_Handle FM_MACSEC_MASTER_Config(t_FmMacsecParams *p_FmMacsecParams); + +/***********************************************************************/ +/* MACSEC internal routines */ +/***********************************************************************/ + +/**************************************************************************//** + + @Group FM_MACSEC_InterModule_grp FM MACSEC Inter-Module Unit + + @Description FM MACSEC Inter Module functions - + These are not User API routines but routines that may be called + from other modules. This will be the case in a single core environment, + where instead of using the XX messaging mechanism, the routines may be + called from other modules. In a multicore environment, the other modules may + be run by other cores and therefore these routines may not be called directly. + + @{ +*//***************************************************************************/ + +#define MAX_NUM_OF_SA_PER_SC 4 + +typedef enum +{ + e_SC_RX = 0, + e_SC_TX +} e_ScType; + +typedef enum +{ + e_SC_SA_A = 0, + e_SC_SA_B , + e_SC_SA_C , + e_SC_SA_D +} e_ScSaId; + +typedef struct +{ + uint32_t scId; + macsecSCI_t sci; + bool replayProtect; + uint32_t replayWindow; + e_FmMacsecValidFrameBehavior validateFrames; + uint16_t confidentialityOffset; + e_FmMacsecSecYCipherSuite cipherSuite; +} t_RxScParams; + +typedef struct +{ + uint32_t scId; + macsecSCI_t sci; + bool protectFrames; + e_FmMacsecSciInsertionMode sciInsertionMode; + bool confidentialityEnable; + uint16_t confidentialityOffset; + e_FmMacsecSecYCipherSuite cipherSuite; +} t_TxScParams; + +typedef enum e_FmMacsecGlobalExceptions { + e_FM_MACSEC_EX_TX_SC, /**< Tx Sc 0 frame discarded error. */ + e_FM_MACSEC_EX_ECC /**< MACSEC memory ECC multiple-bit error. */ +} e_FmMacsecGlobalExceptions; + +typedef enum e_FmMacsecGlobalEvents { + e_FM_MACSEC_EV_TX_SC_NEXT_PN /**< Tx Sc 0 Next Pn exhaustion threshold reached. */ +} e_FmMacsecGlobalEvents; + +/**************************************************************************//** + @Description Enum for inter-module interrupts registration +*//***************************************************************************/ +typedef enum e_FmMacsecEventModules{ + e_FM_MACSEC_MOD_SC_TX, + e_FM_MACSEC_MOD_DUMMY_LAST +} e_FmMacsecEventModules; + +typedef enum e_FmMacsecInterModuleEvent { + e_FM_MACSEC_EV_SC_TX, + e_FM_MACSEC_EV_ERR_SC_TX, + e_FM_MACSEC_EV_DUMMY_LAST +} e_FmMacsecInterModuleEvent; + +#define NUM_OF_INTER_MODULE_EVENTS (NUM_OF_TX_SC * 2) + +#define GET_MACSEC_MODULE_EVENT(mod, id, intrType, event) \ + switch(mod){ \ + case e_FM_MACSEC_MOD_SC_TX: \ + event = (intrType == e_FM_INTR_TYPE_ERR) ? \ + e_FM_MACSEC_EV_ERR_SC_TX: \ + e_FM_MACSEC_EV_SC_TX; \ + event += (uint8_t)(2 * id);break; \ + break; \ + default:event = e_FM_MACSEC_EV_DUMMY_LAST; \ + break;} + +void FmMacsecRegisterIntr(t_Handle h_FmMacsec, + e_FmMacsecEventModules module, + uint8_t modId, + e_FmIntrType intrType, + void (*f_Isr) (t_Handle h_Arg, uint32_t id), + t_Handle h_Arg); + +void FmMacsecUnregisterIntr(t_Handle h_FmMacsec, + e_FmMacsecEventModules module, + uint8_t modId, + e_FmIntrType intrType); + +t_Error FmMacsecAllocScs(t_Handle h_FmMacsec, e_ScType type, bool isPtp, uint32_t numOfScs, uint32_t *p_ScIds); +t_Error FmMacsecFreeScs(t_Handle h_FmMacsec, e_ScType type, uint32_t numOfScs, uint32_t *p_ScIds); +t_Error FmMacsecCreateRxSc(t_Handle h_FmMacsec, t_RxScParams *p_RxScParams); +t_Error FmMacsecDeleteRxSc(t_Handle h_FmMacsec, uint32_t scId); +t_Error FmMacsecCreateTxSc(t_Handle h_FmMacsec, t_TxScParams *p_RxScParams); +t_Error FmMacsecDeleteTxSc(t_Handle h_FmMacsec, uint32_t scId); +t_Error FmMacsecCreateRxSa(t_Handle h_FmMacsec, uint32_t scId, e_ScSaId saId, macsecAN_t an, uint32_t lowestPn, macsecSAKey_t key); +t_Error FmMacsecCreateTxSa(t_Handle h_FmMacsec, uint32_t scId, e_ScSaId saId, macsecSAKey_t key); +t_Error FmMacsecDeleteRxSa(t_Handle h_FmMacsec, uint32_t scId, e_ScSaId saId); +t_Error FmMacsecDeleteTxSa(t_Handle h_FmMacsec, uint32_t scId, e_ScSaId saId); +t_Error FmMacsecRxSaSetReceive(t_Handle h_FmMacsec, uint32_t scId, e_ScSaId saId, bool enableReceive); +t_Error FmMacsecRxSaUpdateNextPn(t_Handle h_FmMacsec, uint32_t scId, e_ScSaId saId, uint32_t updtNextPN); +t_Error FmMacsecRxSaUpdateLowestPn(t_Handle h_FmMacsec, uint32_t scId, e_ScSaId saId, uint32_t updtLowestPN); +t_Error FmMacsecTxSaSetActive(t_Handle h_FmMacsec, uint32_t scId, e_ScSaId saId, macsecAN_t an); +t_Error FmMacsecTxSaGetActive(t_Handle h_FmMacsec, uint32_t scId, macsecAN_t *p_An); +t_Error FmMacsecSetPTP(t_Handle h_FmMacsec, bool enable); + +t_Error FmMacsecSetException(t_Handle h_FmMacsec, e_FmMacsecGlobalExceptions exception, uint32_t scId, bool enable); +t_Error FmMacsecSetEvent(t_Handle h_FmMacsec, e_FmMacsecGlobalEvents event, uint32_t scId, bool enable); + + + +#endif /* __FM_MACSEC_H */ diff --git a/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MACSEC/fm_macsec_guest.c b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MACSEC/fm_macsec_guest.c new file mode 100644 index 000000000000..31d789d042a7 --- /dev/null +++ b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MACSEC/fm_macsec_guest.c @@ -0,0 +1,59 @@ +/* + * Copyright 2008-2015 Freescale Semiconductor Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Freescale Semiconductor nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * + * ALTERNATIVELY, this software may be distributed under the terms of the + * GNU General Public License ("GPL") as published by the Free Software + * Foundation, either version 2 of that License or (at your option) any + * later version. + * + * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/****************************************************************************** + @File fm_macsec.c + + @Description FM MACSEC driver routines implementation. +*//***************************************************************************/ + +#include "std_ext.h" +#include "error_ext.h" +#include "xx_ext.h" +#include "string_ext.h" +#include "sprint_ext.h" +#include "debug_ext.h" +#include "fm_macsec.h" + + +/****************************************/ +/* static functions */ +/****************************************/ + +/****************************************/ +/* API Init unit functions */ +/****************************************/ +t_Handle FM_MACSEC_GUEST_Config(t_FmMacsecParams *p_FmMacsecParam) +{ + UNUSED(p_FmMacsecParam); + return NULL; +} diff --git a/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MACSEC/fm_macsec_master.c b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MACSEC/fm_macsec_master.c new file mode 100644 index 000000000000..623612aca2d0 --- /dev/null +++ b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MACSEC/fm_macsec_master.c @@ -0,0 +1,1031 @@ +/* + * Copyright 2008-2015 Freescale Semiconductor Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Freescale Semiconductor nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * + * ALTERNATIVELY, this software may be distributed under the terms of the + * GNU General Public License ("GPL") as published by the Free Software + * Foundation, either version 2 of that License or (at your option) any + * later version. + * + * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/****************************************************************************** + @File fm_macsec.c + + @Description FM MACSEC driver routines implementation. +*//***************************************************************************/ + +#include "std_ext.h" +#include "error_ext.h" +#include "xx_ext.h" +#include "string_ext.h" +#include "sprint_ext.h" +#include "fm_mac_ext.h" + +#include "fm_macsec_master.h" + + +extern uint16_t FM_MAC_GetMaxFrameLength(t_Handle FmMac); + + +/****************************************/ +/* static functions */ +/****************************************/ +static t_Error CheckFmMacsecParameters(t_FmMacsec *p_FmMacsec) +{ + if (!p_FmMacsec->f_Exception) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("Exceptions callback not provided")); + + return E_OK; +} + +static void UnimplementedIsr(t_Handle h_Arg, uint32_t id) +{ + UNUSED(h_Arg); UNUSED(id); + + REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Unimplemented Isr!")); +} + +static void MacsecEventIsr(t_Handle h_FmMacsec) +{ + t_FmMacsec *p_FmMacsec = (t_FmMacsec*)h_FmMacsec; + uint32_t events,event,i; + + SANITY_CHECK_RETURN(p_FmMacsec, E_INVALID_HANDLE); + + events = GET_UINT32(p_FmMacsec->p_FmMacsecRegs->evr); + events |= GET_UINT32(p_FmMacsec->p_FmMacsecRegs->ever); + WRITE_UINT32(p_FmMacsec->p_FmMacsecRegs->evr,events); + + for (i=0; i<NUM_OF_TX_SC; i++) + if (events & FM_MACSEC_EV_TX_SC_NEXT_PN(i)) + { + GET_MACSEC_MODULE_EVENT(e_FM_MACSEC_MOD_SC_TX, i, e_FM_INTR_TYPE_NORMAL, event); + p_FmMacsec->intrMng[event].f_Isr(p_FmMacsec->intrMng[event].h_SrcHandle, i); + } +} + +static void MacsecErrorIsr(t_Handle h_FmMacsec) +{ + t_FmMacsec *p_FmMacsec = (t_FmMacsec*)h_FmMacsec; + uint32_t errors,error,i; + + SANITY_CHECK_RETURN(p_FmMacsec, E_INVALID_HANDLE); + + errors = GET_UINT32(p_FmMacsec->p_FmMacsecRegs->err); + errors |= GET_UINT32(p_FmMacsec->p_FmMacsecRegs->erer); + WRITE_UINT32(p_FmMacsec->p_FmMacsecRegs->err,errors); + + for (i=0; i<NUM_OF_TX_SC; i++) + if (errors & FM_MACSEC_EX_TX_SC(i)) + { + GET_MACSEC_MODULE_EVENT(e_FM_MACSEC_MOD_SC_TX, i, e_FM_INTR_TYPE_ERR, error); + p_FmMacsec->intrMng[error].f_Isr(p_FmMacsec->intrMng[error].h_SrcHandle, i); + } + + if (errors & FM_MACSEC_EX_ECC) + { + uint8_t eccType; + uint32_t tmpReg; + + tmpReg = GET_UINT32(p_FmMacsec->p_FmMacsecRegs->meec); + ASSERT_COND(tmpReg & MECC_CAP); + eccType = (uint8_t)((tmpReg & MECC_CET) >> MECC_CET_SHIFT); + + if (!eccType && (p_FmMacsec->userExceptions & FM_MACSEC_USER_EX_SINGLE_BIT_ECC)) + p_FmMacsec->f_Exception(p_FmMacsec->h_App,e_FM_MACSEC_EX_SINGLE_BIT_ECC); + else if (eccType && (p_FmMacsec->userExceptions & FM_MACSEC_USER_EX_MULTI_BIT_ECC)) + p_FmMacsec->f_Exception(p_FmMacsec->h_App,e_FM_MACSEC_EX_MULTI_BIT_ECC); + else + WRITE_UINT32(p_FmMacsec->p_FmMacsecRegs->meec,tmpReg); + } +} + +static t_Error MacsecInit(t_Handle h_FmMacsec) +{ + t_FmMacsec *p_FmMacsec = (t_FmMacsec*)h_FmMacsec; + t_FmMacsecDriverParam *p_FmMacsecDriverParam = NULL; + uint32_t tmpReg,i,macId; + + SANITY_CHECK_RETURN_ERROR(p_FmMacsec, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_FmMacsec->p_FmMacsecDriverParam, E_INVALID_HANDLE); + + CHECK_INIT_PARAMETERS(p_FmMacsec, CheckFmMacsecParameters); + + p_FmMacsecDriverParam = p_FmMacsec->p_FmMacsecDriverParam; + + for (i=0;i<e_FM_MACSEC_EV_DUMMY_LAST;i++) + p_FmMacsec->intrMng[i].f_Isr = UnimplementedIsr; + + tmpReg = 0; + tmpReg |= (p_FmMacsecDriverParam->changedTextWithNoEncryptDeliverUncontrolled << CFG_UECT_SHIFT)| + (p_FmMacsecDriverParam->onlyScbIsSetDeliverUncontrolled << CFG_ESCBT_SHIFT) | + (p_FmMacsecDriverParam->unknownSciTreatMode << CFG_USFT_SHIFT) | + (p_FmMacsecDriverParam->invalidTagsDeliverUncontrolled << CFG_ITT_SHIFT) | + (p_FmMacsecDriverParam->encryptWithNoChangedTextDiscardUncontrolled << CFG_KFT_SHIFT) | + (p_FmMacsecDriverParam->untagTreatMode << CFG_UFT_SHIFT) | + (p_FmMacsecDriverParam->keysUnreadable << CFG_KSS_SHIFT) | + (p_FmMacsecDriverParam->reservedSc0 << CFG_S0I_SHIFT) | + (p_FmMacsecDriverParam->byPassMode << CFG_BYPN_SHIFT); + WRITE_UINT32(p_FmMacsec->p_FmMacsecRegs->cfg, tmpReg); + + tmpReg = FM_MAC_GetMaxFrameLength(p_FmMacsec->h_FmMac); + /* At least Ethernet FCS (4 bytes) overhead must be subtracted from MFL. + * In addition, the SCI (8 bytes) overhead might be subtracted as well. */ + tmpReg -= p_FmMacsecDriverParam->mflSubtract; + WRITE_UINT32(p_FmMacsec->p_FmMacsecRegs->mfl, tmpReg); + + WRITE_UINT32(p_FmMacsec->p_FmMacsecRegs->tpnet, p_FmMacsecDriverParam->pnExhThr); + + if (!p_FmMacsec->userExceptions) + p_FmMacsec->exceptions &= ~FM_MACSEC_EX_ECC; + WRITE_UINT32(p_FmMacsec->p_FmMacsecRegs->erer, p_FmMacsec->exceptions); + + p_FmMacsec->numRxScAvailable = NUM_OF_RX_SC; + if (p_FmMacsecDriverParam->reservedSc0) + p_FmMacsec->numRxScAvailable --; + p_FmMacsec->numTxScAvailable = NUM_OF_TX_SC; + + XX_Free(p_FmMacsecDriverParam); + p_FmMacsec->p_FmMacsecDriverParam = NULL; + + FM_MAC_GetId(p_FmMacsec->h_FmMac, &macId); + FmRegisterIntr(p_FmMacsec->h_Fm, + e_FM_MOD_MACSEC, + (uint8_t)macId, + e_FM_INTR_TYPE_NORMAL, + MacsecEventIsr, + p_FmMacsec); + + FmRegisterIntr(p_FmMacsec->h_Fm, + e_FM_MOD_MACSEC, + 0, + e_FM_INTR_TYPE_ERR, + MacsecErrorIsr, + p_FmMacsec); + + return E_OK; +} + +static t_Error MacsecFree(t_Handle h_FmMacsec) +{ + t_FmMacsec *p_FmMacsec = (t_FmMacsec*)h_FmMacsec; + uint32_t macId; + + SANITY_CHECK_RETURN_ERROR(p_FmMacsec, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(!p_FmMacsec->p_FmMacsecDriverParam, E_INVALID_HANDLE); + + FM_MAC_GetId(p_FmMacsec->h_FmMac, &macId); + FmUnregisterIntr(p_FmMacsec->h_Fm, + e_FM_MOD_MACSEC, + (uint8_t)macId, + e_FM_INTR_TYPE_NORMAL); + + FmUnregisterIntr(p_FmMacsec->h_Fm, + e_FM_MOD_MACSEC, + 0, + e_FM_INTR_TYPE_ERR); + + if (p_FmMacsec->rxScSpinLock) + XX_FreeSpinlock(p_FmMacsec->rxScSpinLock); + if (p_FmMacsec->txScSpinLock) + XX_FreeSpinlock(p_FmMacsec->txScSpinLock); + + XX_Free(p_FmMacsec); + + return E_OK; +} + +static t_Error MacsecConfigUnknownSciFrameTreatment(t_Handle h_FmMacsec, e_FmMacsecUnknownSciFrameTreatment treatMode) +{ + t_FmMacsec *p_FmMacsec = (t_FmMacsec*)h_FmMacsec; + + SANITY_CHECK_RETURN_ERROR(p_FmMacsec, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_FmMacsec->p_FmMacsecDriverParam, E_INVALID_HANDLE); + + p_FmMacsec->p_FmMacsecDriverParam->unknownSciTreatMode = treatMode; + + return E_OK; +} + +static t_Error MacsecConfigInvalidTagsFrameTreatment(t_Handle h_FmMacsec, bool deliverUncontrolled) +{ + t_FmMacsec *p_FmMacsec = (t_FmMacsec*)h_FmMacsec; + + SANITY_CHECK_RETURN_ERROR(p_FmMacsec, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_FmMacsec->p_FmMacsecDriverParam, E_INVALID_HANDLE); + + p_FmMacsec->p_FmMacsecDriverParam->invalidTagsDeliverUncontrolled = deliverUncontrolled; + + return E_OK; +} + +static t_Error MacsecConfigChangedTextWithNoEncryptFrameTreatment(t_Handle h_FmMacsec, bool deliverUncontrolled) +{ + t_FmMacsec *p_FmMacsec = (t_FmMacsec*)h_FmMacsec; + + SANITY_CHECK_RETURN_ERROR(p_FmMacsec, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_FmMacsec->p_FmMacsecDriverParam, E_INVALID_HANDLE); + + p_FmMacsec->p_FmMacsecDriverParam->changedTextWithNoEncryptDeliverUncontrolled = deliverUncontrolled; + + return E_OK; +} + +static t_Error MacsecConfigOnlyScbIsSetFrameTreatment(t_Handle h_FmMacsec, bool deliverUncontrolled) +{ + t_FmMacsec *p_FmMacsec = (t_FmMacsec*)h_FmMacsec; + + SANITY_CHECK_RETURN_ERROR(p_FmMacsec, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_FmMacsec->p_FmMacsecDriverParam, E_INVALID_HANDLE); + + p_FmMacsec->p_FmMacsecDriverParam->onlyScbIsSetDeliverUncontrolled = deliverUncontrolled; + + return E_OK; +} + +static t_Error MacsecConfigEncryptWithNoChangedTextFrameTreatment(t_Handle h_FmMacsec, bool discardUncontrolled) +{ + t_FmMacsec *p_FmMacsec = (t_FmMacsec*)h_FmMacsec; + + SANITY_CHECK_RETURN_ERROR(p_FmMacsec, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_FmMacsec->p_FmMacsecDriverParam, E_INVALID_HANDLE); + + p_FmMacsec->p_FmMacsecDriverParam->encryptWithNoChangedTextDiscardUncontrolled = discardUncontrolled; + + return E_OK; +} + +static t_Error MacsecConfigUntagFrameTreatment(t_Handle h_FmMacsec, e_FmMacsecUntagFrameTreatment treatMode) +{ + t_FmMacsec *p_FmMacsec = (t_FmMacsec*)h_FmMacsec; + + SANITY_CHECK_RETURN_ERROR(p_FmMacsec, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_FmMacsec->p_FmMacsecDriverParam, E_INVALID_HANDLE); + + p_FmMacsec->p_FmMacsecDriverParam->untagTreatMode = treatMode; + + return E_OK; +} + +static t_Error MacsecConfigPnExhaustionThreshold(t_Handle h_FmMacsec, uint32_t pnExhThr) +{ + t_FmMacsec *p_FmMacsec = (t_FmMacsec*)h_FmMacsec; + + SANITY_CHECK_RETURN_ERROR(p_FmMacsec, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_FmMacsec->p_FmMacsecDriverParam, E_INVALID_HANDLE); + + p_FmMacsec->p_FmMacsecDriverParam->pnExhThr = pnExhThr; + + return E_OK; +} + +static t_Error MacsecConfigKeysUnreadable(t_Handle h_FmMacsec) +{ + t_FmMacsec *p_FmMacsec = (t_FmMacsec*)h_FmMacsec; + + SANITY_CHECK_RETURN_ERROR(p_FmMacsec, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_FmMacsec->p_FmMacsecDriverParam, E_INVALID_HANDLE); + + p_FmMacsec->p_FmMacsecDriverParam->keysUnreadable = TRUE; + + return E_OK; +} + +static t_Error MacsecConfigSectagWithoutSCI(t_Handle h_FmMacsec) +{ + t_FmMacsec *p_FmMacsec = (t_FmMacsec*)h_FmMacsec; + + SANITY_CHECK_RETURN_ERROR(p_FmMacsec, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_FmMacsec->p_FmMacsecDriverParam, E_INVALID_HANDLE); + + p_FmMacsec->p_FmMacsecDriverParam->sectagOverhead -= MACSEC_SCI_SIZE; + p_FmMacsec->p_FmMacsecDriverParam->mflSubtract += MACSEC_SCI_SIZE; + + return E_OK; +} + +static t_Error MacsecConfigException(t_Handle h_FmMacsec, e_FmMacsecExceptions exception, bool enable) +{ + t_FmMacsec *p_FmMacsec = (t_FmMacsec*)h_FmMacsec; + uint32_t bitMask = 0; + + SANITY_CHECK_RETURN_ERROR(p_FmMacsec, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_FmMacsec->p_FmMacsecDriverParam, E_INVALID_HANDLE); + + GET_USER_EXCEPTION_FLAG(bitMask, exception); + if (bitMask) + { + if (enable) + p_FmMacsec->userExceptions |= bitMask; + else + p_FmMacsec->userExceptions &= ~bitMask; + } + else + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("Undefined exception")); + + return E_OK; +} + +static t_Error MacsecGetRevision(t_Handle h_FmMacsec, uint32_t *p_MacsecRevision) +{ + t_FmMacsec *p_FmMacsec = (t_FmMacsec*)h_FmMacsec; + + SANITY_CHECK_RETURN_ERROR(p_FmMacsec, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(!p_FmMacsec->p_FmMacsecDriverParam, E_INVALID_HANDLE); + + *p_MacsecRevision = GET_UINT32(p_FmMacsec->p_FmMacsecRegs->ip_rev1); + + return E_OK; +} + +static t_Error MacsecEnable(t_Handle h_FmMacsec) +{ + t_FmMacsec *p_FmMacsec = (t_FmMacsec*)h_FmMacsec; + uint32_t tmpReg; + + SANITY_CHECK_RETURN_ERROR(p_FmMacsec, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(!p_FmMacsec->p_FmMacsecDriverParam, E_INVALID_HANDLE); + + tmpReg = GET_UINT32(p_FmMacsec->p_FmMacsecRegs->cfg); + tmpReg |= CFG_BYPN; + WRITE_UINT32(p_FmMacsec->p_FmMacsecRegs->cfg,tmpReg); + + return E_OK; +} + +static t_Error MacsecDisable(t_Handle h_FmMacsec) +{ + t_FmMacsec *p_FmMacsec = (t_FmMacsec*)h_FmMacsec; + uint32_t tmpReg; + + SANITY_CHECK_RETURN_ERROR(p_FmMacsec, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(!p_FmMacsec->p_FmMacsecDriverParam, E_INVALID_HANDLE); + + tmpReg = GET_UINT32(p_FmMacsec->p_FmMacsecRegs->cfg); + tmpReg &= ~CFG_BYPN; + WRITE_UINT32(p_FmMacsec->p_FmMacsecRegs->cfg,tmpReg); + + return E_OK; +} + +static t_Error MacsecSetException(t_Handle h_FmMacsec, e_FmMacsecExceptions exception, bool enable) +{ + t_FmMacsec *p_FmMacsec = (t_FmMacsec*)h_FmMacsec; + uint32_t bitMask; + + SANITY_CHECK_RETURN_ERROR(p_FmMacsec, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(!p_FmMacsec->p_FmMacsecDriverParam, E_INVALID_HANDLE); + + GET_USER_EXCEPTION_FLAG(bitMask, exception); + if (bitMask) + { + if (enable) + p_FmMacsec->userExceptions |= bitMask; + else + p_FmMacsec->userExceptions &= ~bitMask; + } + else + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("Undefined exception")); + + if (!p_FmMacsec->userExceptions) + p_FmMacsec->exceptions &= ~FM_MACSEC_EX_ECC; + else + p_FmMacsec->exceptions |= FM_MACSEC_EX_ECC; + WRITE_UINT32(p_FmMacsec->p_FmMacsecRegs->erer, p_FmMacsec->exceptions); + + return E_OK; +} + +static void InitFmMacsecControllerDriver(t_FmMacsecControllerDriver *p_FmMacsecControllerDriver) +{ + p_FmMacsecControllerDriver->f_FM_MACSEC_Init = MacsecInit; + p_FmMacsecControllerDriver->f_FM_MACSEC_Free = MacsecFree; + p_FmMacsecControllerDriver->f_FM_MACSEC_ConfigUnknownSciFrameTreatment = MacsecConfigUnknownSciFrameTreatment; + p_FmMacsecControllerDriver->f_FM_MACSEC_ConfigInvalidTagsFrameTreatment = MacsecConfigInvalidTagsFrameTreatment; + p_FmMacsecControllerDriver->f_FM_MACSEC_ConfigEncryptWithNoChangedTextFrameTreatment = MacsecConfigEncryptWithNoChangedTextFrameTreatment; + p_FmMacsecControllerDriver->f_FM_MACSEC_ConfigUntagFrameTreatment = MacsecConfigUntagFrameTreatment; + p_FmMacsecControllerDriver->f_FM_MACSEC_ConfigChangedTextWithNoEncryptFrameTreatment = MacsecConfigChangedTextWithNoEncryptFrameTreatment; + p_FmMacsecControllerDriver->f_FM_MACSEC_ConfigOnlyScbIsSetFrameTreatment = MacsecConfigOnlyScbIsSetFrameTreatment; + p_FmMacsecControllerDriver->f_FM_MACSEC_ConfigPnExhaustionThreshold = MacsecConfigPnExhaustionThreshold; + p_FmMacsecControllerDriver->f_FM_MACSEC_ConfigKeysUnreadable = MacsecConfigKeysUnreadable; + p_FmMacsecControllerDriver->f_FM_MACSEC_ConfigSectagWithoutSCI = MacsecConfigSectagWithoutSCI; + p_FmMacsecControllerDriver->f_FM_MACSEC_ConfigException = MacsecConfigException; + p_FmMacsecControllerDriver->f_FM_MACSEC_GetRevision = MacsecGetRevision; + p_FmMacsecControllerDriver->f_FM_MACSEC_Enable = MacsecEnable; + p_FmMacsecControllerDriver->f_FM_MACSEC_Disable = MacsecDisable; + p_FmMacsecControllerDriver->f_FM_MACSEC_SetException = MacsecSetException; +} + +/****************************************/ +/* Inter-Module functions */ +/****************************************/ + +void FmMacsecRegisterIntr(t_Handle h_FmMacsec, + e_FmMacsecEventModules module, + uint8_t modId, + e_FmIntrType intrType, + void (*f_Isr) (t_Handle h_Arg, uint32_t id), + t_Handle h_Arg) +{ + t_FmMacsec *p_FmMacsec = (t_FmMacsec*)h_FmMacsec; + uint8_t event= 0; + + SANITY_CHECK_RETURN(p_FmMacsec, E_INVALID_HANDLE); + + GET_MACSEC_MODULE_EVENT(module, modId, intrType, event); + + ASSERT_COND(event != e_FM_MACSEC_EV_DUMMY_LAST); + p_FmMacsec->intrMng[event].f_Isr = f_Isr; + p_FmMacsec->intrMng[event].h_SrcHandle = h_Arg; +} + +void FmMacsecUnregisterIntr(t_Handle h_FmMacsec, + e_FmMacsecEventModules module, + uint8_t modId, + e_FmIntrType intrType) +{ + t_FmMacsec *p_FmMacsec = (t_FmMacsec*)h_FmMacsec; + uint8_t event= 0; + + SANITY_CHECK_RETURN(p_FmMacsec, E_INVALID_HANDLE); + + GET_MACSEC_MODULE_EVENT(module, modId,intrType, event); + + ASSERT_COND(event != e_FM_MACSEC_EV_DUMMY_LAST); + p_FmMacsec->intrMng[event].f_Isr = NULL; + p_FmMacsec->intrMng[event].h_SrcHandle = NULL; +} + +t_Error FmMacsecAllocScs(t_Handle h_FmMacsec, e_ScType type, bool isPtp, uint32_t numOfScs, uint32_t *p_ScIds) +{ + t_FmMacsec *p_FmMacsec = (t_FmMacsec*)h_FmMacsec; + t_Error err = E_OK; + bool *p_ScTable; + uint32_t *p_ScAvailable,i; + + SANITY_CHECK_RETURN_ERROR(p_FmMacsec, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_ScIds, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(numOfScs, E_INVALID_HANDLE); + + if (type == e_SC_RX) + { + p_ScTable = (bool *)p_FmMacsec->rxScTable; + p_ScAvailable = &p_FmMacsec->numRxScAvailable; + i = (NUM_OF_RX_SC - 1); + } + else + { + p_ScTable = (bool *)p_FmMacsec->txScTable; + p_ScAvailable = &p_FmMacsec->numTxScAvailable; + i = (NUM_OF_TX_SC - 1); + + } + if (*p_ScAvailable < numOfScs) + RETURN_ERROR(MINOR, E_NOT_AVAILABLE, ("Not enough SCs available")); + + if (isPtp) + { + i = 0; + if (p_ScTable[i]) + RETURN_ERROR(MINOR, E_NOT_AVAILABLE, ("Sc 0 Not available")); + } + + for (;numOfScs;i--) + { + if (p_ScTable[i]) + continue; + numOfScs --; + (*p_ScAvailable)--; + p_ScIds[numOfScs] = i; + p_ScTable[i] = TRUE; + } + + return err; +} + +t_Error FmMacsecFreeScs(t_Handle h_FmMacsec, e_ScType type, uint32_t numOfScs, uint32_t *p_ScIds) +{ + t_FmMacsec *p_FmMacsec = (t_FmMacsec*)h_FmMacsec; + t_Error err = E_OK; + bool *p_ScTable; + uint32_t *p_ScAvailable,maxNumOfSc,i; + + SANITY_CHECK_RETURN_ERROR(p_FmMacsec, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_ScIds, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(numOfScs, E_INVALID_HANDLE); + + if (type == e_SC_RX) + { + p_ScTable = (bool *)p_FmMacsec->rxScTable; + p_ScAvailable = &p_FmMacsec->numRxScAvailable; + maxNumOfSc = NUM_OF_RX_SC; + } + else + { + p_ScTable = (bool *)p_FmMacsec->txScTable; + p_ScAvailable = &p_FmMacsec->numTxScAvailable; + maxNumOfSc = NUM_OF_TX_SC; + } + + if ((*p_ScAvailable + numOfScs) > maxNumOfSc) + RETURN_ERROR(MINOR, E_FULL, ("Too much SCs")); + + for (i=0;i<numOfScs;i++) + { + p_ScTable[p_ScIds[i]] = FALSE; + (*p_ScAvailable)++; + } + + return err; + +} + +t_Error FmMacsecSetPTP(t_Handle h_FmMacsec, bool enable) +{ + t_FmMacsec *p_FmMacsec = (t_FmMacsec*)h_FmMacsec; + uint32_t tmpReg = 0; + + SANITY_CHECK_RETURN_ERROR(p_FmMacsec, E_INVALID_HANDLE); + + tmpReg = GET_UINT32(p_FmMacsec->p_FmMacsecRegs->cfg); + if (enable && (tmpReg & CFG_S0I)) + RETURN_ERROR(MINOR, E_INVALID_STATE, ("MACSEC already in point-to-point mode")); + + if (enable) + tmpReg |= CFG_S0I; + else + tmpReg &= ~CFG_S0I; + WRITE_UINT32(p_FmMacsec->p_FmMacsecRegs->cfg, tmpReg); + + return E_OK; +} + +t_Error FmMacsecCreateRxSc(t_Handle h_FmMacsec, t_RxScParams *p_RxScParams) +{ + t_FmMacsec *p_FmMacsec = (t_FmMacsec*)h_FmMacsec; + t_Error err = E_OK; + uint32_t tmpReg = 0, intFlags; + + SANITY_CHECK_RETURN_ERROR(p_FmMacsec, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_RxScParams, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_RxScParams->scId < NUM_OF_RX_SC, E_INVALID_HANDLE); + + intFlags = XX_LockIntrSpinlock(p_FmMacsec->rxScSpinLock); + + WRITE_UINT32(p_FmMacsec->p_FmMacsecRegs->rxsca, p_RxScParams->scId); + tmpReg = GET_UINT32(p_FmMacsec->p_FmMacsecRegs->rxsccfg); + if (tmpReg & RX_SCCFG_SCI_EN_MASK) + { + XX_UnlockIntrSpinlock(p_FmMacsec->rxScSpinLock, intFlags); + RETURN_ERROR(MINOR, E_INVALID_STATE, ("Rx Sc %d must be disable",p_RxScParams->scId)); + } + + WRITE_UINT32(p_FmMacsec->p_FmMacsecRegs->rxsci1h, GET_SCI_FIRST_HALF(p_RxScParams->sci)); + WRITE_UINT32(p_FmMacsec->p_FmMacsecRegs->rxsci2h, GET_SCI_SECOND_HALF(p_RxScParams->sci)); + tmpReg |= ((p_RxScParams->replayProtect << RX_SCCFG_RP_SHIFT) & RX_SCCFG_RP_MASK); + tmpReg |= ((p_RxScParams->validateFrames << RX_SCCFG_VF_SHIFT) & RX_SCCFG_VF_MASK); + tmpReg |= ((p_RxScParams->confidentialityOffset << RX_SCCFG_CO_SHIFT) & RX_SCCFG_CO_MASK); + tmpReg |= RX_SCCFG_SCI_EN_MASK; + tmpReg |= (p_RxScParams->cipherSuite << RX_SCCFG_CS_SHIFT); + WRITE_UINT32(p_FmMacsec->p_FmMacsecRegs->rxsccfg, tmpReg); + + WRITE_UINT32(p_FmMacsec->p_FmMacsecRegs->rpw, p_RxScParams->replayWindow); + + XX_UnlockIntrSpinlock(p_FmMacsec->rxScSpinLock, intFlags); + + return err; +} + +t_Error FmMacsecDeleteRxSc(t_Handle h_FmMacsec, uint32_t scId) +{ + t_FmMacsec *p_FmMacsec = (t_FmMacsec*)h_FmMacsec; + t_Error err = E_OK; + uint32_t tmpReg = 0, intFlags; + + SANITY_CHECK_RETURN_ERROR(p_FmMacsec, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(scId < NUM_OF_RX_SC, E_INVALID_HANDLE); + + intFlags = XX_LockIntrSpinlock(p_FmMacsec->rxScSpinLock); + + tmpReg &= ~RX_SCCFG_SCI_EN_MASK; + WRITE_UINT32(p_FmMacsec->p_FmMacsecRegs->rxsca, scId); + WRITE_UINT32(p_FmMacsec->p_FmMacsecRegs->rxsccfg, tmpReg); + + XX_UnlockIntrSpinlock(p_FmMacsec->rxScSpinLock, intFlags); + + return err; +} + +t_Error FmMacsecCreateTxSc(t_Handle h_FmMacsec, t_TxScParams *p_TxScParams) +{ + t_FmMacsec *p_FmMacsec = (t_FmMacsec*)h_FmMacsec; + t_Error err = E_OK; + uint32_t tmpReg = 0, intFlags; + bool alwaysIncludeSCI = FALSE, useES = FALSE, useSCB = FALSE; + + SANITY_CHECK_RETURN_ERROR(p_FmMacsec, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_TxScParams, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_TxScParams->scId < NUM_OF_TX_SC, E_INVALID_HANDLE); + + intFlags = XX_LockIntrSpinlock(p_FmMacsec->txScSpinLock); + + WRITE_UINT32(p_FmMacsec->p_FmMacsecRegs->txsca, p_TxScParams->scId); + + tmpReg = GET_UINT32(p_FmMacsec->p_FmMacsecRegs->txsccfg); + if (tmpReg & TX_SCCFG_SCE_MASK) + { + XX_UnlockIntrSpinlock(p_FmMacsec->txScSpinLock, intFlags); + RETURN_ERROR(MINOR, E_INVALID_STATE, ("Tx Sc %d must be disable",p_TxScParams->scId)); + } + + WRITE_UINT32(p_FmMacsec->p_FmMacsecRegs->txsci1h, GET_SCI_FIRST_HALF(p_TxScParams->sci)); + WRITE_UINT32(p_FmMacsec->p_FmMacsecRegs->txsci2h, GET_SCI_SECOND_HALF(p_TxScParams->sci)); + alwaysIncludeSCI = (p_TxScParams->sciInsertionMode == e_FM_MACSEC_SCI_INSERTION_MODE_EXPLICIT_SECTAG); + useES = (p_TxScParams->sciInsertionMode == e_FM_MACSEC_SCI_INSERTION_MODE_EXPLICIT_MAC_SA); + + tmpReg |= ((p_TxScParams->protectFrames << TX_SCCFG_PF_SHIFT) & TX_SCCFG_PF_MASK); + tmpReg |= ((alwaysIncludeSCI << TX_SCCFG_AIS_SHIFT) & TX_SCCFG_AIS_MASK); + tmpReg |= ((useES << TX_SCCFG_UES_SHIFT) & TX_SCCFG_UES_MASK); + tmpReg |= ((useSCB << TX_SCCFG_USCB_SHIFT) & TX_SCCFG_USCB_MASK); + tmpReg |= ((p_TxScParams->confidentialityEnable << TX_SCCFG_CE_SHIFT) & TX_SCCFG_CE_MASK); + tmpReg |= ((p_TxScParams->confidentialityOffset << TX_SCCFG_CO_SHIFT) & TX_SCCFG_CO_MASK); + tmpReg |= TX_SCCFG_SCE_MASK; + tmpReg |= (p_TxScParams->cipherSuite << TX_SCCFG_CS_SHIFT); + WRITE_UINT32(p_FmMacsec->p_FmMacsecRegs->txsccfg, tmpReg); + + XX_UnlockIntrSpinlock(p_FmMacsec->txScSpinLock, intFlags); + + return err; +} + +t_Error FmMacsecDeleteTxSc(t_Handle h_FmMacsec, uint32_t scId) +{ + t_FmMacsec *p_FmMacsec = (t_FmMacsec*)h_FmMacsec; + t_Error err = E_OK; + uint32_t tmpReg = 0, intFlags; + + SANITY_CHECK_RETURN_ERROR(p_FmMacsec, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(scId < NUM_OF_TX_SC, E_INVALID_HANDLE); + + intFlags = XX_LockIntrSpinlock(p_FmMacsec->txScSpinLock); + + tmpReg &= ~TX_SCCFG_SCE_MASK; + WRITE_UINT32(p_FmMacsec->p_FmMacsecRegs->txsca, scId); + WRITE_UINT32(p_FmMacsec->p_FmMacsecRegs->txsccfg, tmpReg); + + XX_UnlockIntrSpinlock(p_FmMacsec->txScSpinLock, intFlags); + + return err; +} + +t_Error FmMacsecCreateRxSa(t_Handle h_FmMacsec, uint32_t scId, e_ScSaId saId, macsecAN_t an, uint32_t lowestPn, macsecSAKey_t key) +{ + t_FmMacsec *p_FmMacsec = (t_FmMacsec*)h_FmMacsec; + t_Error err = E_OK; + uint32_t tmpReg = 0, intFlags; + + SANITY_CHECK_RETURN_ERROR(p_FmMacsec, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(scId < NUM_OF_RX_SC, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(saId < NUM_OF_SA_PER_RX_SC, E_INVALID_HANDLE); + + intFlags = XX_LockIntrSpinlock(p_FmMacsec->rxScSpinLock); + + WRITE_UINT32(p_FmMacsec->p_FmMacsecRegs->rxsca, scId); + WRITE_UINT32(p_FmMacsec->p_FmMacsecRegs->fmMacsecRxScSa[saId].rxsanpn, DEFAULT_initNextPn); + WRITE_UINT32(p_FmMacsec->p_FmMacsecRegs->fmMacsecRxScSa[saId].rxsalpn, lowestPn); + MemCpy8((void*)p_FmMacsec->p_FmMacsecRegs->fmMacsecRxScSa[saId].rxsak, key, sizeof(macsecSAKey_t)); + + tmpReg |= RX_SACFG_ACTIVE; + tmpReg |= ((an << RX_SACFG_AN_SHIFT) & RX_SACFG_AN_MASK); + WRITE_UINT32(p_FmMacsec->p_FmMacsecRegs->fmMacsecRxScSa[saId].rxsacs, tmpReg); + + XX_UnlockIntrSpinlock(p_FmMacsec->rxScSpinLock, intFlags); + + return err; +} + +t_Error FmMacsecCreateTxSa(t_Handle h_FmMacsec, uint32_t scId, e_ScSaId saId, macsecSAKey_t key) +{ + t_FmMacsec *p_FmMacsec = (t_FmMacsec*)h_FmMacsec; + t_Error err = E_OK; + uint32_t tmpReg = 0, intFlags; + + SANITY_CHECK_RETURN_ERROR(p_FmMacsec, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(scId < NUM_OF_RX_SC, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(saId < NUM_OF_SA_PER_TX_SC, E_INVALID_HANDLE); + + intFlags = XX_LockIntrSpinlock(p_FmMacsec->txScSpinLock); + + WRITE_UINT32(p_FmMacsec->p_FmMacsecRegs->txsca, scId); + WRITE_UINT32(p_FmMacsec->p_FmMacsecRegs->fmMacsecTxScSa[saId].txsanpn, DEFAULT_initNextPn); + MemCpy8((void*)p_FmMacsec->p_FmMacsecRegs->fmMacsecTxScSa[saId].txsak, key, sizeof(macsecSAKey_t)); + + tmpReg |= TX_SACFG_ACTIVE; + WRITE_UINT32(p_FmMacsec->p_FmMacsecRegs->fmMacsecTxScSa[saId].txsacs, tmpReg); + + XX_UnlockIntrSpinlock(p_FmMacsec->txScSpinLock, intFlags); + + return err; +} + +t_Error FmMacsecDeleteRxSa(t_Handle h_FmMacsec, uint32_t scId, e_ScSaId saId) +{ + t_FmMacsec *p_FmMacsec = (t_FmMacsec*)h_FmMacsec; + t_Error err = E_OK; + uint32_t tmpReg = 0, i, intFlags; + + SANITY_CHECK_RETURN_ERROR(p_FmMacsec, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(scId < NUM_OF_RX_SC, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(saId < NUM_OF_SA_PER_RX_SC, E_INVALID_HANDLE); + + intFlags = XX_LockIntrSpinlock(p_FmMacsec->rxScSpinLock); + + WRITE_UINT32(p_FmMacsec->p_FmMacsecRegs->rxsca, scId); + WRITE_UINT32(p_FmMacsec->p_FmMacsecRegs->fmMacsecRxScSa[saId].rxsanpn, 0x0); + WRITE_UINT32(p_FmMacsec->p_FmMacsecRegs->fmMacsecRxScSa[saId].rxsalpn, 0x0); + for (i=0; i<4; i++) + WRITE_UINT32(p_FmMacsec->p_FmMacsecRegs->fmMacsecRxScSa[saId].rxsak[i], 0x0); + + tmpReg |= RX_SACFG_ACTIVE; + tmpReg &= ~RX_SACFG_EN_MASK; + WRITE_UINT32(p_FmMacsec->p_FmMacsecRegs->fmMacsecRxScSa[saId].rxsacs, tmpReg); + + XX_UnlockIntrSpinlock(p_FmMacsec->rxScSpinLock, intFlags); + + return err; +} + +t_Error FmMacsecDeleteTxSa(t_Handle h_FmMacsec, uint32_t scId, e_ScSaId saId) +{ + t_FmMacsec *p_FmMacsec = (t_FmMacsec*)h_FmMacsec; + t_Error err = E_OK; + uint32_t tmpReg = 0, i, intFlags; + + SANITY_CHECK_RETURN_ERROR(p_FmMacsec, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(scId < NUM_OF_RX_SC, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(saId < NUM_OF_SA_PER_TX_SC, E_INVALID_HANDLE); + + intFlags = XX_LockIntrSpinlock(p_FmMacsec->txScSpinLock); + + WRITE_UINT32(p_FmMacsec->p_FmMacsecRegs->txsca, scId); + WRITE_UINT32(p_FmMacsec->p_FmMacsecRegs->fmMacsecTxScSa[saId].txsanpn, 0x0); + for (i=0; i<4; i++) + WRITE_UINT32(p_FmMacsec->p_FmMacsecRegs->fmMacsecTxScSa[saId].txsak[i], 0x0); + + tmpReg |= TX_SACFG_ACTIVE; + WRITE_UINT32(p_FmMacsec->p_FmMacsecRegs->fmMacsecTxScSa[saId].txsacs, tmpReg); + + XX_UnlockIntrSpinlock(p_FmMacsec->txScSpinLock, intFlags); + + return err; +} + +t_Error FmMacsecRxSaSetReceive(t_Handle h_FmMacsec, uint32_t scId, e_ScSaId saId, bool enableReceive) +{ + t_FmMacsec *p_FmMacsec = (t_FmMacsec*)h_FmMacsec; + t_Error err = E_OK; + uint32_t tmpReg = 0, intFlags; + + SANITY_CHECK_RETURN_ERROR(p_FmMacsec, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(scId < NUM_OF_RX_SC, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(saId < NUM_OF_SA_PER_RX_SC, E_INVALID_HANDLE); + + intFlags = XX_LockIntrSpinlock(p_FmMacsec->rxScSpinLock); + + WRITE_UINT32(p_FmMacsec->p_FmMacsecRegs->rxsca, scId); + tmpReg = GET_UINT32(p_FmMacsec->p_FmMacsecRegs->fmMacsecRxScSa[saId].rxsacs); + if (enableReceive) + tmpReg |= RX_SACFG_EN_MASK; + else + tmpReg &= ~RX_SACFG_EN_MASK; + + WRITE_UINT32(p_FmMacsec->p_FmMacsecRegs->fmMacsecRxScSa[saId].rxsacs, tmpReg); + + XX_UnlockIntrSpinlock(p_FmMacsec->rxScSpinLock, intFlags); + + return err; +} + +t_Error FmMacsecRxSaUpdateNextPn(t_Handle h_FmMacsec, uint32_t scId, e_ScSaId saId, uint32_t updtNextPN) +{ + t_FmMacsec *p_FmMacsec = (t_FmMacsec*)h_FmMacsec; + t_Error err = E_OK; + uint32_t intFlags; + + SANITY_CHECK_RETURN_ERROR(p_FmMacsec, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(scId < NUM_OF_RX_SC, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(saId < NUM_OF_SA_PER_RX_SC, E_INVALID_HANDLE); + + intFlags = XX_LockIntrSpinlock(p_FmMacsec->rxScSpinLock); + + WRITE_UINT32(p_FmMacsec->p_FmMacsecRegs->rxsca, scId); + WRITE_UINT32(p_FmMacsec->p_FmMacsecRegs->fmMacsecRxScSa[saId].rxsanpn, updtNextPN); + + XX_UnlockIntrSpinlock(p_FmMacsec->rxScSpinLock, intFlags); + + return err; +} + +t_Error FmMacsecRxSaUpdateLowestPn(t_Handle h_FmMacsec, uint32_t scId, e_ScSaId saId, uint32_t updtLowestPN) +{ + t_FmMacsec *p_FmMacsec = (t_FmMacsec*)h_FmMacsec; + t_Error err = E_OK; + uint32_t intFlags; + + SANITY_CHECK_RETURN_ERROR(p_FmMacsec, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(scId < NUM_OF_RX_SC, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(saId < NUM_OF_SA_PER_RX_SC, E_INVALID_HANDLE); + + intFlags = XX_LockIntrSpinlock(p_FmMacsec->rxScSpinLock); + + WRITE_UINT32(p_FmMacsec->p_FmMacsecRegs->rxsca, scId); + WRITE_UINT32(p_FmMacsec->p_FmMacsecRegs->fmMacsecRxScSa[saId].rxsalpn, updtLowestPN); + + XX_UnlockIntrSpinlock(p_FmMacsec->rxScSpinLock, intFlags); + + return err; +} + +t_Error FmMacsecTxSaSetActive(t_Handle h_FmMacsec, uint32_t scId, e_ScSaId saId, macsecAN_t an) +{ + t_FmMacsec *p_FmMacsec = (t_FmMacsec*)h_FmMacsec; + t_Error err = E_OK; + uint32_t tmpReg = 0, intFlags; + + SANITY_CHECK_RETURN_ERROR(p_FmMacsec, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(scId < NUM_OF_RX_SC, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(saId < NUM_OF_SA_PER_TX_SC, E_INVALID_HANDLE); + + intFlags = XX_LockIntrSpinlock(p_FmMacsec->txScSpinLock); + + WRITE_UINT32(p_FmMacsec->p_FmMacsecRegs->txsca, scId); + + tmpReg = GET_UINT32(p_FmMacsec->p_FmMacsecRegs->txsccfg); + + tmpReg |= ((an << TX_SCCFG_AN_SHIFT) & TX_SCCFG_AN_MASK); + tmpReg |= ((saId << TX_SCCFG_ASA_SHIFT) & TX_SCCFG_ASA_MASK); + + WRITE_UINT32(p_FmMacsec->p_FmMacsecRegs->txsccfg, tmpReg); + + XX_UnlockIntrSpinlock(p_FmMacsec->txScSpinLock, intFlags); + + return err; +} + +t_Error FmMacsecTxSaGetActive(t_Handle h_FmMacsec, uint32_t scId, macsecAN_t *p_An) +{ + t_FmMacsec *p_FmMacsec = (t_FmMacsec*)h_FmMacsec; + t_Error err = E_OK; + uint32_t tmpReg = 0, intFlags; + + SANITY_CHECK_RETURN_ERROR(p_FmMacsec, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(scId < NUM_OF_RX_SC, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_An, E_INVALID_HANDLE); + + intFlags = XX_LockIntrSpinlock(p_FmMacsec->txScSpinLock); + + WRITE_UINT32(p_FmMacsec->p_FmMacsecRegs->txsca, scId); + + tmpReg = GET_UINT32(p_FmMacsec->p_FmMacsecRegs->txsccfg); + + XX_UnlockIntrSpinlock(p_FmMacsec->txScSpinLock, intFlags); + + *p_An = (macsecAN_t)((tmpReg & TX_SCCFG_AN_MASK) >> TX_SCCFG_AN_SHIFT); + + return err; +} + +t_Error FmMacsecSetException(t_Handle h_FmMacsec, e_FmMacsecGlobalExceptions exception, uint32_t scId, bool enable) +{ + t_FmMacsec *p_FmMacsec = (t_FmMacsec*)h_FmMacsec; + uint32_t bitMask; + + SANITY_CHECK_RETURN_ERROR(p_FmMacsec, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(!p_FmMacsec->p_FmMacsecDriverParam, E_INVALID_HANDLE); + + GET_EXCEPTION_FLAG(bitMask, exception, scId); + if (bitMask) + { + if (enable) + p_FmMacsec->exceptions |= bitMask; + else + p_FmMacsec->exceptions &= ~bitMask; + } + else + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("Undefined exception")); + + WRITE_UINT32(p_FmMacsec->p_FmMacsecRegs->erer, p_FmMacsec->exceptions); + + return E_OK; +} + +t_Error FmMacsecSetEvent(t_Handle h_FmMacsec, e_FmMacsecGlobalEvents event, uint32_t scId, bool enable) +{ + t_FmMacsec *p_FmMacsec = (t_FmMacsec*)h_FmMacsec; + uint32_t bitMask; + + SANITY_CHECK_RETURN_ERROR(p_FmMacsec, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(!p_FmMacsec->p_FmMacsecDriverParam, E_INVALID_HANDLE); + + GET_EVENT_FLAG(bitMask, event, scId); + if (bitMask) + { + if (enable) + p_FmMacsec->events |= bitMask; + else + p_FmMacsec->events &= ~bitMask; + } + else + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("Undefined event")); + + WRITE_UINT32(p_FmMacsec->p_FmMacsecRegs->ever, p_FmMacsec->events); + + return E_OK; +} + +/****************************************/ +/* API Init unit functions */ +/****************************************/ +t_Handle FM_MACSEC_MASTER_Config(t_FmMacsecParams *p_FmMacsecParam) +{ + t_FmMacsec *p_FmMacsec; + uint32_t macId; + + /* Allocate FM MACSEC structure */ + p_FmMacsec = (t_FmMacsec *) XX_Malloc(sizeof(t_FmMacsec)); + if (!p_FmMacsec) + { + REPORT_ERROR(MAJOR, E_NO_MEMORY, ("FM MACSEC driver structure")); + return NULL; + } + memset(p_FmMacsec, 0, sizeof(t_FmMacsec)); + InitFmMacsecControllerDriver(&p_FmMacsec->fmMacsecControllerDriver); + + /* Allocate the FM MACSEC driver's parameters structure */ + p_FmMacsec->p_FmMacsecDriverParam = (t_FmMacsecDriverParam *)XX_Malloc(sizeof(t_FmMacsecDriverParam)); + if (!p_FmMacsec->p_FmMacsecDriverParam) + { + XX_Free(p_FmMacsec); + REPORT_ERROR(MAJOR, E_NO_MEMORY, ("FM MACSEC driver parameters")); + return NULL; + } + memset(p_FmMacsec->p_FmMacsecDriverParam, 0, sizeof(t_FmMacsecDriverParam)); + + /* Initialize FM MACSEC parameters which will be kept by the driver */ + p_FmMacsec->h_Fm = p_FmMacsecParam->h_Fm; + p_FmMacsec->h_FmMac = p_FmMacsecParam->nonGuestParams.h_FmMac; + p_FmMacsec->p_FmMacsecRegs = (t_FmMacsecRegs *)UINT_TO_PTR(p_FmMacsecParam->nonGuestParams.baseAddr); + p_FmMacsec->f_Exception = p_FmMacsecParam->nonGuestParams.f_Exception; + p_FmMacsec->h_App = p_FmMacsecParam->nonGuestParams.h_App; + p_FmMacsec->userExceptions = DEFAULT_userExceptions; + p_FmMacsec->exceptions = DEFAULT_exceptions; + p_FmMacsec->events = DEFAULT_events; + p_FmMacsec->rxScSpinLock = XX_InitSpinlock(); + p_FmMacsec->txScSpinLock = XX_InitSpinlock(); + + /* Initialize FM MACSEC driver parameters parameters (for initialization phase only) */ + p_FmMacsec->p_FmMacsecDriverParam->unknownSciTreatMode = DEFAULT_unknownSciFrameTreatment; + p_FmMacsec->p_FmMacsecDriverParam->invalidTagsDeliverUncontrolled = DEFAULT_invalidTagsFrameTreatment; + p_FmMacsec->p_FmMacsecDriverParam->encryptWithNoChangedTextDiscardUncontrolled = DEFAULT_encryptWithNoChangedTextFrameTreatment; + p_FmMacsec->p_FmMacsecDriverParam->untagTreatMode = DEFAULT_untagFrameTreatment; + p_FmMacsec->p_FmMacsecDriverParam->keysUnreadable = DEFAULT_keysUnreadable; + p_FmMacsec->p_FmMacsecDriverParam->reservedSc0 = DEFAULT_sc0ReservedForPTP; + p_FmMacsec->p_FmMacsecDriverParam->byPassMode = !DEFAULT_normalMode; + p_FmMacsec->p_FmMacsecDriverParam->pnExhThr = DEFAULT_pnExhThr; + p_FmMacsec->p_FmMacsecDriverParam->sectagOverhead = DEFAULT_sectagOverhead; + p_FmMacsec->p_FmMacsecDriverParam->mflSubtract = DEFAULT_mflSubtract; + /* build the FM MACSEC master IPC address */ + memset(p_FmMacsec->fmMacsecModuleName, 0, (sizeof(char))*MODULE_NAME_SIZE); + FM_MAC_GetId(p_FmMacsec->h_FmMac,&macId); + if (Sprint (p_FmMacsec->fmMacsecModuleName, "FM-%d-MAC-%d-MACSEC-Master", + FmGetId(p_FmMacsec->h_Fm),macId) != 24) + { + XX_Free(p_FmMacsec->p_FmMacsecDriverParam); + XX_Free(p_FmMacsec); + REPORT_ERROR(MAJOR, E_INVALID_STATE, ("Sprint failed")); + return NULL; + } + return p_FmMacsec; +} diff --git a/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MACSEC/fm_macsec_master.h b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MACSEC/fm_macsec_master.h new file mode 100644 index 000000000000..2296a0f10d54 --- /dev/null +++ b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MACSEC/fm_macsec_master.h @@ -0,0 +1,479 @@ +/* + * Copyright 2008-2015 Freescale Semiconductor Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Freescale Semiconductor nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * + * ALTERNATIVELY, this software may be distributed under the terms of the + * GNU General Public License ("GPL") as published by the Free Software + * Foundation, either version 2 of that License or (at your option) any + * later version. + * + * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/****************************************************************************** + @File fm_macsec_master.h + + @Description FM MACSEC internal structures and definitions. +*//***************************************************************************/ +#ifndef __FM_MACSEC_MASTER_H +#define __FM_MACSEC_MASTER_H + +#include "error_ext.h" +#include "std_ext.h" + +#include "fm_macsec.h" + + +#define MACSEC_ICV_SIZE 16 +#define MACSEC_SECTAG_SIZE 16 +#define MACSEC_SCI_SIZE 8 +#define MACSEC_FCS_SIZE 4 + +/**************************************************************************//** + @Description Exceptions +*//***************************************************************************/ + +#define FM_MACSEC_EX_TX_SC_0 0x80000000 +#define FM_MACSEC_EX_TX_SC(sc) (FM_MACSEC_EX_TX_SC_0 >> (sc)) +#define FM_MACSEC_EX_ECC 0x00000001 + +#define GET_EXCEPTION_FLAG(bitMask, exception, id) switch (exception){ \ + case e_FM_MACSEC_EX_TX_SC: \ + bitMask = FM_MACSEC_EX_TX_SC(id); break; \ + case e_FM_MACSEC_EX_ECC: \ + bitMask = FM_MACSEC_EX_ECC; break; \ + default: bitMask = 0;break;} + +#define FM_MACSEC_USER_EX_SINGLE_BIT_ECC 0x80000000 +#define FM_MACSEC_USER_EX_MULTI_BIT_ECC 0x40000000 + +#define GET_USER_EXCEPTION_FLAG(bitMask, exception) switch (exception){ \ + case e_FM_MACSEC_EX_SINGLE_BIT_ECC: \ + bitMask = FM_MACSEC_USER_EX_SINGLE_BIT_ECC; break; \ + case e_FM_MACSEC_EX_MULTI_BIT_ECC: \ + bitMask = FM_MACSEC_USER_EX_MULTI_BIT_ECC; break; \ + default: bitMask = 0;break;} + +/**************************************************************************//** + @Description Events +*//***************************************************************************/ + +#define FM_MACSEC_EV_TX_SC_0_NEXT_PN 0x80000000 +#define FM_MACSEC_EV_TX_SC_NEXT_PN(sc) (FM_MACSEC_EV_TX_SC_0_NEXT_PN >> (sc)) + +#define GET_EVENT_FLAG(bitMask, event, id) switch (event){ \ + case e_FM_MACSEC_EV_TX_SC_NEXT_PN: \ + bitMask = FM_MACSEC_EV_TX_SC_NEXT_PN(id); break; \ + default: bitMask = 0;break;} + +/**************************************************************************//** + @Description Defaults +*//***************************************************************************/ +#define DEFAULT_userExceptions (FM_MACSEC_USER_EX_SINGLE_BIT_ECC |\ + FM_MACSEC_USER_EX_MULTI_BIT_ECC) + +#define DEFAULT_exceptions (FM_MACSEC_EX_TX_SC(0) |\ + FM_MACSEC_EX_TX_SC(1) |\ + FM_MACSEC_EX_TX_SC(2) |\ + FM_MACSEC_EX_TX_SC(3) |\ + FM_MACSEC_EX_TX_SC(4) |\ + FM_MACSEC_EX_TX_SC(5) |\ + FM_MACSEC_EX_TX_SC(6) |\ + FM_MACSEC_EX_TX_SC(7) |\ + FM_MACSEC_EX_TX_SC(8) |\ + FM_MACSEC_EX_TX_SC(9) |\ + FM_MACSEC_EX_TX_SC(10) |\ + FM_MACSEC_EX_TX_SC(11) |\ + FM_MACSEC_EX_TX_SC(12) |\ + FM_MACSEC_EX_TX_SC(13) |\ + FM_MACSEC_EX_TX_SC(14) |\ + FM_MACSEC_EX_TX_SC(15) |\ + FM_MACSEC_EX_ECC ) + +#define DEFAULT_events (FM_MACSEC_EV_TX_SC_NEXT_PN(0) |\ + FM_MACSEC_EV_TX_SC_NEXT_PN(1) |\ + FM_MACSEC_EV_TX_SC_NEXT_PN(2) |\ + FM_MACSEC_EV_TX_SC_NEXT_PN(3) |\ + FM_MACSEC_EV_TX_SC_NEXT_PN(4) |\ + FM_MACSEC_EV_TX_SC_NEXT_PN(5) |\ + FM_MACSEC_EV_TX_SC_NEXT_PN(6) |\ + FM_MACSEC_EV_TX_SC_NEXT_PN(7) |\ + FM_MACSEC_EV_TX_SC_NEXT_PN(8) |\ + FM_MACSEC_EV_TX_SC_NEXT_PN(9) |\ + FM_MACSEC_EV_TX_SC_NEXT_PN(10) |\ + FM_MACSEC_EV_TX_SC_NEXT_PN(11) |\ + FM_MACSEC_EV_TX_SC_NEXT_PN(12) |\ + FM_MACSEC_EV_TX_SC_NEXT_PN(13) |\ + FM_MACSEC_EV_TX_SC_NEXT_PN(14) |\ + FM_MACSEC_EV_TX_SC_NEXT_PN(15) ) + +#define DEFAULT_unknownSciFrameTreatment e_FM_MACSEC_UNKNOWN_SCI_FRAME_TREATMENT_DISCARD_BOTH +#define DEFAULT_invalidTagsFrameTreatment FALSE +#define DEFAULT_encryptWithNoChangedTextFrameTreatment FALSE +#define DEFAULT_untagFrameTreatment e_FM_MACSEC_UNTAG_FRAME_TREATMENT_DELIVER_UNCONTROLLED_DISCARD_CONTROLLED +#define DEFAULT_changedTextWithNoEncryptFrameTreatment FALSE +#define DEFAULT_onlyScbIsSetFrameTreatment FALSE +#define DEFAULT_keysUnreadable FALSE +#define DEFAULT_normalMode TRUE +#define DEFAULT_sc0ReservedForPTP FALSE +#define DEFAULT_initNextPn 1 +#define DEFAULT_pnExhThr 0xffffffff +#define DEFAULT_sectagOverhead (MACSEC_ICV_SIZE + MACSEC_SECTAG_SIZE) +#define DEFAULT_mflSubtract MACSEC_FCS_SIZE + + +/**************************************************************************//** + @Description Memory Mapped Registers +*//***************************************************************************/ + +#if defined(__MWERKS__) && !defined(__GNUC__) +#pragma pack(push,1) +#endif /* defined(__MWERKS__) && ... */ + +typedef _Packed struct +{ + /* MACsec configuration */ + volatile uint32_t cfg; /**< MACsec configuration */ + volatile uint32_t et; /**< MACsec EtherType */ + volatile uint8_t res1[56]; /**< reserved */ + volatile uint32_t mfl; /**< Maximum Frame Length */ + volatile uint32_t tpnet; /**< TX Packet Number exhaustion threshold */ + volatile uint8_t res2[56]; /**< reserved */ + volatile uint32_t rxsca; /**< RX SC access select */ + volatile uint8_t res3[60]; /**< reserved */ + volatile uint32_t txsca; /**< TX SC access select */ + volatile uint8_t res4[60]; /**< reserved */ + + /* RX configuration, status and statistic */ + volatile uint32_t rxsci1h; /**< RX Secure Channel Identifier first half */ + volatile uint32_t rxsci2h; /**< RX Secure Channel Identifier second half */ + volatile uint8_t res5[8]; /**< reserved */ + volatile uint32_t ifio1hs; /**< ifInOctets first half Statistic */ + volatile uint32_t ifio2hs; /**< ifInOctets second half Statistic */ + volatile uint32_t ifiups; /**< ifInUcastPkts Statistic */ + volatile uint8_t res6[4]; /**< reserved */ + volatile uint32_t ifimps; /**< ifInMulticastPkts Statistic */ + volatile uint32_t ifibps; /**< ifInBroadcastPkts Statistic */ + volatile uint32_t rxsccfg; /**< RX Secure Channel configuration */ + volatile uint32_t rpw; /**< replayWindow */ + volatile uint8_t res7[16]; /**< reserved */ + volatile uint32_t inov1hs; /**< InOctetsValidated first half Statistic */ + volatile uint32_t inov2hs; /**< InOctetsValidated second half Statistic */ + volatile uint32_t inod1hs; /**< InOctetsDecrypted first half Statistic */ + volatile uint32_t inod2hs; /**< InOctetsDecrypted second half Statistic */ + volatile uint32_t rxscipus; /**< RX Secure Channel InPktsUnchecked Statistic */ + volatile uint32_t rxscipds; /**< RX Secure Channel InPktsDelayed Statistic */ + volatile uint32_t rxscipls; /**< RX Secure Channel InPktsLate Statistic */ + volatile uint8_t res8[4]; /**< reserved */ + volatile uint32_t rxaninuss[MAX_NUM_OF_SA_PER_SC]; /**< RX AN 0-3 InNotUsingSA Statistic */ + volatile uint32_t rxanipuss[MAX_NUM_OF_SA_PER_SC]; /**< RX AN 0-3 InPktsUnusedSA Statistic */ + _Packed struct + { + volatile uint32_t rxsacs; /**< RX Security Association configuration and status */ + volatile uint32_t rxsanpn; /**< RX Security Association nextPN */ + volatile uint32_t rxsalpn; /**< RX Security Association lowestPN */ + volatile uint32_t rxsaipos; /**< RX Security Association InPktsOK Statistic */ + volatile uint32_t rxsak[4]; /**< RX Security Association key (128 bit) */ + volatile uint32_t rxsah[4]; /**< RX Security Association hash (128 bit) */ + volatile uint32_t rxsaipis; /**< RX Security Association InPktsInvalid Statistic */ + volatile uint32_t rxsaipnvs; /**< RX Security Association InPktsNotValid Statistic */ + volatile uint8_t res9[8]; /**< reserved */ + } _PackedType fmMacsecRxScSa[NUM_OF_SA_PER_RX_SC]; + + /* TX configuration, status and statistic */ + volatile uint32_t txsci1h; /**< TX Secure Channel Identifier first half */ + volatile uint32_t txsci2h; /**< TX Secure Channel Identifier second half */ + volatile uint8_t res10[8]; /**< reserved */ + volatile uint32_t ifoo1hs; /**< ifOutOctets first half Statistic */ + volatile uint32_t ifoo2hs; /**< ifOutOctets second half Statistic */ + volatile uint32_t ifoups; /**< ifOutUcastPkts Statistic */ + volatile uint32_t opus; /**< OutPktsUntagged Statistic */ + volatile uint32_t ifomps; /**< ifOutMulticastPkts Statistic */ + volatile uint32_t ifobps; /**< ifOutBroadcastPkts Statistic */ + volatile uint32_t txsccfg; /**< TX Secure Channel configuration */ + volatile uint32_t optls; /**< OutPktsTooLong Statistic */ + volatile uint8_t res11[16]; /**< reserved */ + volatile uint32_t oop1hs; /**< OutOctetsProtected first half Statistic */ + volatile uint32_t oop2hs; /**< OutOctetsProtected second half Statistic */ + volatile uint32_t ooe1hs; /**< OutOctetsEncrypted first half Statistic */ + volatile uint32_t ooe2hs; /**< OutOctetsEncrypted second half Statistic */ + volatile uint8_t res12[48]; /**< reserved */ + _Packed struct + { + volatile uint32_t txsacs; /**< TX Security Association configuration and status */ + volatile uint32_t txsanpn; /**< TX Security Association nextPN */ + volatile uint32_t txsaopps; /**< TX Security Association OutPktsProtected Statistic */ + volatile uint32_t txsaopes; /**< TX Security Association OutPktsEncrypted Statistic */ + volatile uint32_t txsak[4]; /**< TX Security Association key (128 bit) */ + volatile uint32_t txsah[4]; /**< TX Security Association hash (128 bit) */ + volatile uint8_t res13[16]; /**< reserved */ + } _PackedType fmMacsecTxScSa[NUM_OF_SA_PER_TX_SC]; + volatile uint8_t res14[248]; /**< reserved */ + + /* Global configuration and status */ + volatile uint32_t ip_rev1; /**< MACsec IP Block Revision 1 register */ + volatile uint32_t ip_rev2; /**< MACsec IP Block Revision 2 register */ + volatile uint32_t evr; /**< MACsec Event Register */ + volatile uint32_t ever; /**< MACsec Event Enable Register */ + volatile uint32_t evfr; /**< MACsec Event Force Register */ + volatile uint32_t err; /**< MACsec Error Register */ + volatile uint32_t erer; /**< MACsec Error Enable Register */ + volatile uint32_t erfr; /**< MACsec Error Force Register */ + volatile uint8_t res15[40]; /**< reserved */ + volatile uint32_t meec; /**< MACsec Memory ECC Error Capture Register */ + volatile uint32_t idle; /**< MACsec Idle status Register */ + volatile uint8_t res16[184]; /**< reserved */ + /* DEBUG */ + volatile uint32_t rxec; /**< MACsec RX error capture Register */ + volatile uint8_t res17[28]; /**< reserved */ + volatile uint32_t txec; /**< MACsec TX error capture Register */ + volatile uint8_t res18[220]; /**< reserved */ + + /* Macsec Rx global statistic */ + volatile uint32_t ifiocp1hs; /**< ifInOctetsCp first half Statistic */ + volatile uint32_t ifiocp2hs; /**< ifInOctetsCp second half Statistic */ + volatile uint32_t ifiupcps; /**< ifInUcastPktsCp Statistic */ + volatile uint8_t res19[4]; /**< reserved */ + volatile uint32_t ifioup1hs; /**< ifInOctetsUp first half Statistic */ + volatile uint32_t ifioup2hs; /**< ifInOctetsUp second half Statistic */ + volatile uint32_t ifiupups; /**< ifInUcastPktsUp Statistic */ + volatile uint8_t res20[4]; /**< reserved */ + volatile uint32_t ifimpcps; /**< ifInMulticastPktsCp Statistic */ + volatile uint32_t ifibpcps; /**< ifInBroadcastPktsCp Statistic */ + volatile uint32_t ifimpups; /**< ifInMulticastPktsUp Statistic */ + volatile uint32_t ifibpups; /**< ifInBroadcastPktsUp Statistic */ + volatile uint32_t ipwts; /**< InPktsWithoutTag Statistic */ + volatile uint32_t ipkays; /**< InPktsKaY Statistic */ + volatile uint32_t ipbts; /**< InPktsBadTag Statistic */ + volatile uint32_t ipsnfs; /**< InPktsSCINotFound Statistic */ + volatile uint32_t ipuecs; /**< InPktsUnsupportedEC Statistic */ + volatile uint32_t ipescbs; /**< InPktsEponSingleCopyBroadcast Statistic */ + volatile uint32_t iptls; /**< InPktsTooLong Statistic */ + volatile uint8_t res21[52]; /**< reserved */ + + /* Macsec Tx global statistic */ + volatile uint32_t opds; /**< OutPktsDiscarded Statistic */ +#if (DPAA_VERSION >= 11) + volatile uint8_t res22[124]; /**< reserved */ + _Packed struct + { + volatile uint32_t rxsak[8]; /**< RX Security Association key (128/256 bit) */ + volatile uint8_t res23[32]; /**< reserved */ + } _PackedType rxScSaKey[NUM_OF_SA_PER_RX_SC]; + _Packed struct + { + volatile uint32_t txsak[8]; /**< TX Security Association key (128/256 bit) */ + volatile uint8_t res24[32]; /**< reserved */ + } _PackedType txScSaKey[NUM_OF_SA_PER_TX_SC]; +#endif /* (DPAA_VERSION >= 11) */ +} _PackedType t_FmMacsecRegs; + +#if defined(__MWERKS__) && !defined(__GNUC__) +#pragma pack(pop) +#endif /* defined(__MWERKS__) && ... */ + + +/**************************************************************************//** + @Description General defines +*//***************************************************************************/ + +#define SCI_HIGH_MASK 0xffffffff00000000LL +#define SCI_LOW_MASK 0x00000000ffffffffLL + +#define LONG_SHIFT 32 + +#define GET_SCI_FIRST_HALF(sci) (uint32_t)((macsecSCI_t)((macsecSCI_t)(sci) & SCI_HIGH_MASK) >> LONG_SHIFT) +#define GET_SCI_SECOND_HALF(sci) (uint32_t)((macsecSCI_t)(sci) & SCI_LOW_MASK) + +/**************************************************************************//** + @Description Configuration defines +*//***************************************************************************/ + +/* masks */ +#define CFG_UECT 0x00000800 +#define CFG_ESCBT 0x00000400 +#define CFG_USFT 0x00000300 +#define CFG_ITT 0x00000080 +#define CFG_KFT 0x00000040 +#define CFG_UFT 0x00000030 +#define CFG_KSS 0x00000004 +#define CFG_BYPN 0x00000002 +#define CFG_S0I 0x00000001 + +#define ET_TYPE 0x0000ffff + +#define MFL_MAX_LEN 0x0000ffff + +#define RXSCA_SC_SEL 0x0000000f + +#define TXSCA_SC_SEL 0x0000000f + +#define IP_REV_1_IP_ID 0xffff0000 +#define IP_REV_1_IP_MJ 0x0000ff00 +#define IP_REV_1_IP_MM 0x000000ff + +#define IP_REV_2_IP_INT 0x00ff0000 +#define IP_REV_2_IP_ERR 0x0000ff00 +#define IP_REV_2_IP_CFG 0x000000ff + +#define MECC_CAP 0x80000000 +#define MECC_CET 0x40000000 +#define MECC_SERCNT 0x00ff0000 +#define MECC_MEMADDR 0x000001ff + +/* shifts */ +#define CFG_UECT_SHIFT (31-20) +#define CFG_ESCBT_SHIFT (31-21) +#define CFG_USFT_SHIFT (31-23) +#define CFG_ITT_SHIFT (31-24) +#define CFG_KFT_SHIFT (31-25) +#define CFG_UFT_SHIFT (31-27) +#define CFG_KSS_SHIFT (31-29) +#define CFG_BYPN_SHIFT (31-30) +#define CFG_S0I_SHIFT (31-31) + +#define IP_REV_1_IP_ID_SHIFT (31-15) +#define IP_REV_1_IP_MJ_SHIFT (31-23) +#define IP_REV_1_IP_MM_SHIFT (31-31) + +#define IP_REV_2_IP_INT_SHIFT (31-15) +#define IP_REV_2_IP_ERR_SHIFT (31-23) +#define IP_REV_2_IP_CFG_SHIFT (31-31) + +#define MECC_CAP_SHIFT (31-0) +#define MECC_CET_SHIFT (31-1) +#define MECC_SERCNT_SHIFT (31-15) +#define MECC_MEMADDR_SHIFT (31-31) + +/**************************************************************************//** + @Description RX SC defines +*//***************************************************************************/ + +/* masks */ +#define RX_SCCFG_SCI_EN_MASK 0x00000800 +#define RX_SCCFG_RP_MASK 0x00000400 +#define RX_SCCFG_VF_MASK 0x00000300 +#define RX_SCCFG_CO_MASK 0x0000003f + +/* shifts */ +#define RX_SCCFG_SCI_EN_SHIFT (31-20) +#define RX_SCCFG_RP_SHIFT (31-21) +#define RX_SCCFG_VF_SHIFT (31-23) +#define RX_SCCFG_CO_SHIFT (31-31) +#define RX_SCCFG_CS_SHIFT (31-7) + +/**************************************************************************//** + @Description RX SA defines +*//***************************************************************************/ + +/* masks */ +#define RX_SACFG_ACTIVE 0x80000000 +#define RX_SACFG_AN_MASK 0x00000006 +#define RX_SACFG_EN_MASK 0x00000001 + +/* shifts */ +#define RX_SACFG_AN_SHIFT (31-30) +#define RX_SACFG_EN_SHIFT (31-31) + +/**************************************************************************//** + @Description TX SC defines +*//***************************************************************************/ + +/* masks */ +#define TX_SCCFG_AN_MASK 0x000c0000 +#define TX_SCCFG_ASA_MASK 0x00020000 +#define TX_SCCFG_SCE_MASK 0x00010000 +#define TX_SCCFG_CO_MASK 0x00003f00 +#define TX_SCCFG_CE_MASK 0x00000010 +#define TX_SCCFG_PF_MASK 0x00000008 +#define TX_SCCFG_AIS_MASK 0x00000004 +#define TX_SCCFG_UES_MASK 0x00000002 +#define TX_SCCFG_USCB_MASK 0x00000001 + +/* shifts */ +#define TX_SCCFG_AN_SHIFT (31-13) +#define TX_SCCFG_ASA_SHIFT (31-14) +#define TX_SCCFG_SCE_SHIFT (31-15) +#define TX_SCCFG_CO_SHIFT (31-23) +#define TX_SCCFG_CE_SHIFT (31-27) +#define TX_SCCFG_PF_SHIFT (31-28) +#define TX_SCCFG_AIS_SHIFT (31-29) +#define TX_SCCFG_UES_SHIFT (31-30) +#define TX_SCCFG_USCB_SHIFT (31-31) +#define TX_SCCFG_CS_SHIFT (31-7) + +/**************************************************************************//** + @Description TX SA defines +*//***************************************************************************/ + +/* masks */ +#define TX_SACFG_ACTIVE 0x80000000 + + +typedef struct +{ + void (*f_Isr) (t_Handle h_Arg, uint32_t id); + t_Handle h_SrcHandle; +} t_FmMacsecIntrSrc; + +typedef struct +{ + e_FmMacsecUnknownSciFrameTreatment unknownSciTreatMode; + bool invalidTagsDeliverUncontrolled; + bool changedTextWithNoEncryptDeliverUncontrolled; + bool onlyScbIsSetDeliverUncontrolled; + bool encryptWithNoChangedTextDiscardUncontrolled; + e_FmMacsecUntagFrameTreatment untagTreatMode; + uint32_t pnExhThr; + bool keysUnreadable; + bool byPassMode; + bool reservedSc0; + uint32_t sectagOverhead; + uint32_t mflSubtract; +} t_FmMacsecDriverParam; + +typedef struct +{ + t_FmMacsecControllerDriver fmMacsecControllerDriver; + t_Handle h_Fm; + t_FmMacsecRegs *p_FmMacsecRegs; + t_Handle h_FmMac; /**< A handle to the FM MAC object related to */ + char fmMacsecModuleName[MODULE_NAME_SIZE]; + t_FmMacsecIntrSrc intrMng[NUM_OF_INTER_MODULE_EVENTS]; + uint32_t events; + uint32_t exceptions; + uint32_t userExceptions; + t_FmMacsecExceptionsCallback *f_Exception; /**< Exception Callback Routine */ + t_Handle h_App; /**< A handle to an application layer object; This handle will + be passed by the driver upon calling the above callbacks */ + bool rxScTable[NUM_OF_RX_SC]; + uint32_t numRxScAvailable; + bool txScTable[NUM_OF_TX_SC]; + uint32_t numTxScAvailable; + t_Handle rxScSpinLock; + t_Handle txScSpinLock; + t_FmMacsecDriverParam *p_FmMacsecDriverParam; +} t_FmMacsec; + + +#endif /* __FM_MACSEC_MASTER_H */ diff --git a/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MACSEC/fm_macsec_secy.c b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MACSEC/fm_macsec_secy.c new file mode 100644 index 000000000000..7c72dc98e7f1 --- /dev/null +++ b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MACSEC/fm_macsec_secy.c @@ -0,0 +1,883 @@ +/* + * Copyright 2008-2015 Freescale Semiconductor Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Freescale Semiconductor nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * + * ALTERNATIVELY, this software may be distributed under the terms of the + * GNU General Public License ("GPL") as published by the Free Software + * Foundation, either version 2 of that License or (at your option) any + * later version. + * + * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/****************************************************************************** + @File fm_macsec_secy.c + + @Description FM MACSEC SECY driver routines implementation. +*//***************************************************************************/ + +#include "std_ext.h" +#include "error_ext.h" +#include "xx_ext.h" +#include "string_ext.h" +#include "sprint_ext.h" + +#include "fm_macsec_secy.h" + + +/****************************************/ +/* static functions */ +/****************************************/ +static void FmMacsecSecYExceptionsIsr(t_Handle h_FmMacsecSecY, uint32_t id) +{ + t_FmMacsecSecY *p_FmMacsecSecY = (t_FmMacsecSecY *)h_FmMacsecSecY; + + UNUSED(id); + SANITY_CHECK_RETURN(p_FmMacsecSecY, E_INVALID_HANDLE); + + if (p_FmMacsecSecY->exceptions & FM_MACSEC_SECY_EX_FRAME_DISCARDED) + p_FmMacsecSecY->f_Exception(p_FmMacsecSecY->h_App, e_FM_MACSEC_SECY_EX_FRAME_DISCARDED); +} + +static void FmMacsecSecYEventsIsr(t_Handle h_FmMacsecSecY, uint32_t id) +{ + t_FmMacsecSecY *p_FmMacsecSecY = (t_FmMacsecSecY *)h_FmMacsecSecY; + + UNUSED(id); + SANITY_CHECK_RETURN(p_FmMacsecSecY, E_INVALID_HANDLE); + + if (p_FmMacsecSecY->events & FM_MACSEC_SECY_EV_NEXT_PN) + p_FmMacsecSecY->f_Event(p_FmMacsecSecY->h_App, e_FM_MACSEC_SECY_EV_NEXT_PN); +} + +static t_Error CheckFmMacsecSecYParameters(t_FmMacsecSecY *p_FmMacsecSecY) +{ + if (!p_FmMacsecSecY->f_Exception) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("Exceptions callback not provided")); + + if (!p_FmMacsecSecY->f_Event) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("Events callback not provided")); + + if (!p_FmMacsecSecY->numOfRxSc) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("Num of Rx Scs must be greater than '0'")); + + + return E_OK; +} + +static t_Handle FmMacsecSecYCreateSc(t_FmMacsecSecY *p_FmMacsecSecY, + macsecSCI_t sci, + e_FmMacsecSecYCipherSuite cipherSuite, + e_ScType type) +{ + t_SecYSc *p_ScTable; + void *p_Params; + uint32_t numOfSc,i; + t_Error err = E_OK; + t_RxScParams rxScParams; + t_TxScParams txScParams; + + ASSERT_COND(p_FmMacsecSecY); + ASSERT_COND(p_FmMacsecSecY->h_FmMacsec); + + if (type == e_SC_RX) + { + memset(&rxScParams, 0, sizeof(rxScParams)); + i = (NUM_OF_RX_SC - 1); + p_ScTable = p_FmMacsecSecY->p_RxSc; + numOfSc = p_FmMacsecSecY->numOfRxSc; + rxScParams.confidentialityOffset = p_FmMacsecSecY->confidentialityOffset; + rxScParams.replayProtect = p_FmMacsecSecY->replayProtect; + rxScParams.replayWindow = p_FmMacsecSecY->replayWindow; + rxScParams.validateFrames = p_FmMacsecSecY->validateFrames; + rxScParams.cipherSuite = cipherSuite; + p_Params = &rxScParams; + } + else + { + memset(&txScParams, 0, sizeof(txScParams)); + i = (NUM_OF_TX_SC - 1); + p_ScTable = p_FmMacsecSecY->p_TxSc; + numOfSc = p_FmMacsecSecY->numOfTxSc; + txScParams.sciInsertionMode = p_FmMacsecSecY->sciInsertionMode; + txScParams.protectFrames = p_FmMacsecSecY->protectFrames; + txScParams.confidentialityEnable = p_FmMacsecSecY->confidentialityEnable; + txScParams.confidentialityOffset = p_FmMacsecSecY->confidentialityOffset; + txScParams.cipherSuite = cipherSuite; + p_Params = &txScParams; + } + + for (i=0;i<numOfSc;i++) + if (!p_ScTable[i].inUse) + break; + if (i == numOfSc) + { + REPORT_ERROR(MAJOR, E_FULL, ("FM MACSEC SECY SC")); + return NULL; + } + + if (type == e_SC_RX) + { + ((t_RxScParams *)p_Params)->scId = p_ScTable[i].scId; + ((t_RxScParams *)p_Params)->sci = sci; + if ((err = FmMacsecCreateRxSc(p_FmMacsecSecY->h_FmMacsec, (t_RxScParams *)p_Params)) != E_OK) + { + REPORT_ERROR(MAJOR, E_NO_MEMORY, ("FM MACSEC SECY RX SC")); + return NULL; + } + } + else + { + ((t_TxScParams *)p_Params)->scId = p_ScTable[i].scId; + ((t_TxScParams *)p_Params)->sci = sci; + if ((err = FmMacsecCreateTxSc(p_FmMacsecSecY->h_FmMacsec, (t_TxScParams *)p_Params)) != E_OK) + { + REPORT_ERROR(MAJOR, E_NO_MEMORY, ("FM MACSEC SECY TX SC")); + return NULL; + } + } + + p_ScTable[i].inUse = TRUE; + return &p_ScTable[i]; +} + +static t_Error FmMacsecSecYDeleteSc(t_FmMacsecSecY *p_FmMacsecSecY, t_SecYSc *p_FmSecYSc, e_ScType type) +{ + t_Error err = E_OK; + + ASSERT_COND(p_FmMacsecSecY); + ASSERT_COND(p_FmMacsecSecY->h_FmMacsec); + ASSERT_COND(p_FmSecYSc); + + if (type == e_SC_RX) + { + if ((err = FmMacsecDeleteRxSc(p_FmMacsecSecY->h_FmMacsec, p_FmSecYSc->scId)) != E_OK) + RETURN_ERROR(MINOR, err, NO_MSG); + } + else + if ((err = FmMacsecDeleteTxSc(p_FmMacsecSecY->h_FmMacsec, p_FmSecYSc->scId)) != E_OK) + RETURN_ERROR(MINOR, err, NO_MSG); + + p_FmSecYSc->inUse = FALSE; + + return err; +} + +/****************************************/ +/* API Init unit functions */ +/****************************************/ +t_Handle FM_MACSEC_SECY_Config(t_FmMacsecSecYParams *p_FmMacsecSecYParam) +{ + t_FmMacsecSecY *p_FmMacsecSecY; + + /* Allocate FM MACSEC structure */ + p_FmMacsecSecY = (t_FmMacsecSecY *) XX_Malloc(sizeof(t_FmMacsecSecY)); + if (!p_FmMacsecSecY) + { + REPORT_ERROR(MAJOR, E_NO_MEMORY, ("FM MACSEC SECY driver structure")); + return NULL; + } + memset(p_FmMacsecSecY, 0, sizeof(t_FmMacsecSecY)); + + /* Allocate the FM MACSEC driver's parameters structure */ + p_FmMacsecSecY->p_FmMacsecSecYDriverParam = (t_FmMacsecSecYDriverParam *)XX_Malloc(sizeof(t_FmMacsecSecYDriverParam)); + if (!p_FmMacsecSecY->p_FmMacsecSecYDriverParam) + { + XX_Free(p_FmMacsecSecY); + REPORT_ERROR(MAJOR, E_NO_MEMORY, ("FM MACSEC SECY driver parameters")); + return NULL; + } + memset(p_FmMacsecSecY->p_FmMacsecSecYDriverParam, 0, sizeof(t_FmMacsecSecYDriverParam)); + + /* Initialize FM MACSEC SECY parameters which will be kept by the driver */ + p_FmMacsecSecY->h_FmMacsec = p_FmMacsecSecYParam->h_FmMacsec; + p_FmMacsecSecY->f_Event = p_FmMacsecSecYParam->f_Event; + p_FmMacsecSecY->f_Exception = p_FmMacsecSecYParam->f_Exception; + p_FmMacsecSecY->h_App = p_FmMacsecSecYParam->h_App; + p_FmMacsecSecY->confidentialityEnable = DEFAULT_confidentialityEnable; + p_FmMacsecSecY->confidentialityOffset = DEFAULT_confidentialityOffset; + p_FmMacsecSecY->validateFrames = DEFAULT_validateFrames; + p_FmMacsecSecY->replayProtect = DEFAULT_replayEnable; + p_FmMacsecSecY->replayWindow = DEFAULT_replayWindow; + p_FmMacsecSecY->protectFrames = DEFAULT_protectFrames; + p_FmMacsecSecY->sciInsertionMode = DEFAULT_sciInsertionMode; + p_FmMacsecSecY->isPointToPoint = DEFAULT_ptp; + p_FmMacsecSecY->numOfRxSc = p_FmMacsecSecYParam->numReceiveChannels; + p_FmMacsecSecY->numOfTxSc = DEFAULT_numOfTxSc; + p_FmMacsecSecY->exceptions = DEFAULT_exceptions; + p_FmMacsecSecY->events = DEFAULT_events; + + memcpy(&p_FmMacsecSecY->p_FmMacsecSecYDriverParam->txScParams, + &p_FmMacsecSecYParam->txScParams, + sizeof(t_FmMacsecSecYSCParams)); + return p_FmMacsecSecY; +} + +t_Error FM_MACSEC_SECY_Init(t_Handle h_FmMacsecSecY) +{ + t_FmMacsecSecY *p_FmMacsecSecY = (t_FmMacsecSecY *)h_FmMacsecSecY; + t_FmMacsecSecYDriverParam *p_FmMacsecSecYDriverParam = NULL; + uint32_t rxScIds[NUM_OF_RX_SC], txScIds[NUM_OF_TX_SC], i, j; + t_Error err; + + SANITY_CHECK_RETURN_ERROR(p_FmMacsecSecY, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_FmMacsecSecY->p_FmMacsecSecYDriverParam, E_INVALID_HANDLE); + + CHECK_INIT_PARAMETERS(p_FmMacsecSecY, CheckFmMacsecSecYParameters); + + p_FmMacsecSecYDriverParam = p_FmMacsecSecY->p_FmMacsecSecYDriverParam; + + if ((p_FmMacsecSecY->isPointToPoint) && + ((err = FmMacsecSetPTP(p_FmMacsecSecY->h_FmMacsec, TRUE)) != E_OK)) + RETURN_ERROR(MAJOR, err, ("Can't set Poin-to-Point")); + + /* Rx Sc Allocation */ + p_FmMacsecSecY->p_RxSc = (t_SecYSc *)XX_Malloc(sizeof(t_SecYSc) * p_FmMacsecSecY->numOfRxSc); + if (!p_FmMacsecSecY->p_RxSc) + RETURN_ERROR(MAJOR, E_NO_MEMORY, ("FM MACSEC SECY RX SC")); + memset(p_FmMacsecSecY->p_RxSc, 0, sizeof(t_SecYSc) * p_FmMacsecSecY->numOfRxSc); + if ((err = FmMacsecAllocScs(p_FmMacsecSecY->h_FmMacsec, e_SC_RX, p_FmMacsecSecY->isPointToPoint, p_FmMacsecSecY->numOfRxSc, rxScIds)) != E_OK) + { + if (p_FmMacsecSecY->p_TxSc) + XX_Free(p_FmMacsecSecY->p_TxSc); + if (p_FmMacsecSecY->p_RxSc) + XX_Free(p_FmMacsecSecY->p_RxSc); + return ERROR_CODE(err); + } + for (i=0; i<p_FmMacsecSecY->numOfRxSc; i++) + { + p_FmMacsecSecY->p_RxSc[i].scId = rxScIds[i]; + p_FmMacsecSecY->p_RxSc[i].type = e_SC_RX; + for (j=0; j<MAX_NUM_OF_SA_PER_SC;j++) + p_FmMacsecSecY->p_RxSc[i].sa[j].saId = (e_ScSaId)SECY_AN_FREE_VALUE; + } + + /* Tx Sc Allocation */ + p_FmMacsecSecY->p_TxSc = (t_SecYSc *)XX_Malloc(sizeof(t_SecYSc) * p_FmMacsecSecY->numOfTxSc); + if (!p_FmMacsecSecY->p_TxSc) + RETURN_ERROR(MAJOR, E_NO_MEMORY, ("FM MACSEC SECY TX SC")); + memset(p_FmMacsecSecY->p_TxSc, 0, sizeof(t_SecYSc) * p_FmMacsecSecY->numOfTxSc); + + if ((err = FmMacsecAllocScs(p_FmMacsecSecY->h_FmMacsec, e_SC_TX, p_FmMacsecSecY->isPointToPoint, p_FmMacsecSecY->numOfTxSc, txScIds)) != E_OK) + { + if (p_FmMacsecSecY->p_TxSc) + XX_Free(p_FmMacsecSecY->p_TxSc); + if (p_FmMacsecSecY->p_RxSc) + XX_Free(p_FmMacsecSecY->p_RxSc); + return ERROR_CODE(err); + } + for (i=0; i<p_FmMacsecSecY->numOfTxSc; i++) + { + p_FmMacsecSecY->p_TxSc[i].scId = txScIds[i]; + p_FmMacsecSecY->p_TxSc[i].type = e_SC_TX; + for (j=0; j<MAX_NUM_OF_SA_PER_SC;j++) + p_FmMacsecSecY->p_TxSc[i].sa[j].saId = (e_ScSaId)SECY_AN_FREE_VALUE; + FmMacsecRegisterIntr(p_FmMacsecSecY->h_FmMacsec, + e_FM_MACSEC_MOD_SC_TX, + (uint8_t)txScIds[i], + e_FM_INTR_TYPE_ERR, + FmMacsecSecYExceptionsIsr, + p_FmMacsecSecY); + FmMacsecRegisterIntr(p_FmMacsecSecY->h_FmMacsec, + e_FM_MACSEC_MOD_SC_TX, + (uint8_t)txScIds[i], + e_FM_INTR_TYPE_NORMAL, + FmMacsecSecYEventsIsr, + p_FmMacsecSecY); + + if (p_FmMacsecSecY->exceptions & FM_MACSEC_SECY_EX_FRAME_DISCARDED) + FmMacsecSetException(p_FmMacsecSecY->h_FmMacsec, e_FM_MACSEC_EX_TX_SC, txScIds[i], TRUE); + if (p_FmMacsecSecY->events & FM_MACSEC_SECY_EV_NEXT_PN) + FmMacsecSetEvent(p_FmMacsecSecY->h_FmMacsec, e_FM_MACSEC_EV_TX_SC_NEXT_PN, txScIds[i], TRUE); + } + + FmMacsecSecYCreateSc(p_FmMacsecSecY, + p_FmMacsecSecYDriverParam->txScParams.sci, + p_FmMacsecSecYDriverParam->txScParams.cipherSuite, + e_SC_TX); + XX_Free(p_FmMacsecSecYDriverParam); + p_FmMacsecSecY->p_FmMacsecSecYDriverParam = NULL; + + return E_OK; +} + +t_Error FM_MACSEC_SECY_Free(t_Handle h_FmMacsecSecY) +{ + t_FmMacsecSecY *p_FmMacsecSecY = (t_FmMacsecSecY *)h_FmMacsecSecY; + t_Error err = E_OK; + uint32_t rxScIds[NUM_OF_RX_SC], txScIds[NUM_OF_TX_SC], i; + + SANITY_CHECK_RETURN_ERROR(p_FmMacsecSecY, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(!p_FmMacsecSecY->p_FmMacsecSecYDriverParam, E_INVALID_STATE); + + if (p_FmMacsecSecY->isPointToPoint) + FmMacsecSetPTP(p_FmMacsecSecY->h_FmMacsec, FALSE); + if (p_FmMacsecSecY->p_RxSc) + { + for (i=0; i<p_FmMacsecSecY->numOfRxSc; i++) + rxScIds[i] = p_FmMacsecSecY->p_RxSc[i].scId; + if ((err = FmMacsecFreeScs(p_FmMacsecSecY->h_FmMacsec, e_SC_RX, p_FmMacsecSecY->numOfRxSc, rxScIds)) != E_OK) + return ERROR_CODE(err); + XX_Free(p_FmMacsecSecY->p_RxSc); + } + if (p_FmMacsecSecY->p_TxSc) + { + FmMacsecSecYDeleteSc(p_FmMacsecSecY, &p_FmMacsecSecY->p_TxSc[0], e_SC_TX); + + for (i=0; i<p_FmMacsecSecY->numOfTxSc; i++) { + txScIds[i] = p_FmMacsecSecY->p_TxSc[i].scId; + FmMacsecUnregisterIntr(p_FmMacsecSecY->h_FmMacsec, + e_FM_MACSEC_MOD_SC_TX, + (uint8_t)txScIds[i], + e_FM_INTR_TYPE_ERR); + FmMacsecUnregisterIntr(p_FmMacsecSecY->h_FmMacsec, + e_FM_MACSEC_MOD_SC_TX, + (uint8_t)txScIds[i], + e_FM_INTR_TYPE_NORMAL); + + if (p_FmMacsecSecY->exceptions & FM_MACSEC_SECY_EX_FRAME_DISCARDED) + FmMacsecSetException(p_FmMacsecSecY->h_FmMacsec, e_FM_MACSEC_EX_TX_SC, txScIds[i], FALSE); + if (p_FmMacsecSecY->events & FM_MACSEC_SECY_EV_NEXT_PN) + FmMacsecSetEvent(p_FmMacsecSecY->h_FmMacsec, e_FM_MACSEC_EV_TX_SC_NEXT_PN, txScIds[i], FALSE); + } + + if ((err = FmMacsecFreeScs(p_FmMacsecSecY->h_FmMacsec, e_SC_TX, p_FmMacsecSecY->numOfTxSc, txScIds)) != E_OK) + return ERROR_CODE(err); + XX_Free(p_FmMacsecSecY->p_TxSc); + } + + XX_Free(p_FmMacsecSecY); + + return err; +} + +t_Error FM_MACSEC_SECY_ConfigSciInsertionMode(t_Handle h_FmMacsecSecY, e_FmMacsecSciInsertionMode sciInsertionMode) +{ + t_FmMacsecSecY *p_FmMacsecSecY = (t_FmMacsecSecY *)h_FmMacsecSecY; + + SANITY_CHECK_RETURN_ERROR(p_FmMacsecSecY, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_FmMacsecSecY->p_FmMacsecSecYDriverParam, E_INVALID_STATE); + + p_FmMacsecSecY->sciInsertionMode = sciInsertionMode; + + return E_OK; +} + +t_Error FM_MACSEC_SECY_ConfigProtectFrames(t_Handle h_FmMacsecSecY, bool protectFrames) +{ + t_FmMacsecSecY *p_FmMacsecSecY = (t_FmMacsecSecY *)h_FmMacsecSecY; + + SANITY_CHECK_RETURN_ERROR(p_FmMacsecSecY, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_FmMacsecSecY->p_FmMacsecSecYDriverParam, E_INVALID_STATE); + + p_FmMacsecSecY->protectFrames = protectFrames; + + return E_OK; +} + +t_Error FM_MACSEC_SECY_ConfigReplayWindow(t_Handle h_FmMacsecSecY, bool replayProtect, uint32_t replayWindow) +{ + t_FmMacsecSecY *p_FmMacsecSecY = (t_FmMacsecSecY *)h_FmMacsecSecY; + + SANITY_CHECK_RETURN_ERROR(p_FmMacsecSecY, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_FmMacsecSecY->p_FmMacsecSecYDriverParam, E_INVALID_STATE); + + p_FmMacsecSecY->replayProtect = replayProtect; + p_FmMacsecSecY->replayWindow = replayWindow; + + return E_OK; +} + +t_Error FM_MACSEC_SECY_ConfigValidationMode(t_Handle h_FmMacsecSecY, e_FmMacsecValidFrameBehavior validateFrames) +{ + t_FmMacsecSecY *p_FmMacsecSecY = (t_FmMacsecSecY *)h_FmMacsecSecY; + + SANITY_CHECK_RETURN_ERROR(p_FmMacsecSecY, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_FmMacsecSecY->p_FmMacsecSecYDriverParam, E_INVALID_STATE); + + p_FmMacsecSecY->validateFrames = validateFrames; + + return E_OK; +} + +t_Error FM_MACSEC_SECY_ConfigConfidentiality(t_Handle h_FmMacsecSecY, bool confidentialityEnable, uint16_t confidentialityOffset) +{ + t_FmMacsecSecY *p_FmMacsecSecY = (t_FmMacsecSecY *)h_FmMacsecSecY; + + SANITY_CHECK_RETURN_ERROR(p_FmMacsecSecY, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_FmMacsecSecY->p_FmMacsecSecYDriverParam, E_INVALID_STATE); + + p_FmMacsecSecY->confidentialityEnable = confidentialityEnable; + p_FmMacsecSecY->confidentialityOffset = confidentialityOffset; + + return E_OK; +} + +t_Error FM_MACSEC_SECY_ConfigPointToPoint(t_Handle h_FmMacsecSecY) +{ + t_FmMacsecSecY *p_FmMacsecSecY = (t_FmMacsecSecY *)h_FmMacsecSecY; + + SANITY_CHECK_RETURN_ERROR(p_FmMacsecSecY, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_FmMacsecSecY->p_FmMacsecSecYDriverParam, E_INVALID_STATE); + + p_FmMacsecSecY->numOfRxSc = 1; + p_FmMacsecSecY->isPointToPoint = TRUE; + p_FmMacsecSecY->sciInsertionMode = e_FM_MACSEC_SCI_INSERTION_MODE_IMPLICT_PTP; + + return E_OK; +} + +t_Error FM_MACSEC_SECY_ConfigException(t_Handle h_FmMacsecSecY, e_FmMacsecSecYExceptions exception, bool enable) +{ + t_FmMacsecSecY *p_FmMacsecSecY = (t_FmMacsecSecY *)h_FmMacsecSecY; + uint32_t bitMask = 0; + + SANITY_CHECK_RETURN_ERROR(p_FmMacsecSecY, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_FmMacsecSecY->p_FmMacsecSecYDriverParam, E_INVALID_STATE); + + GET_EXCEPTION_FLAG(bitMask, exception); + if (bitMask) + { + if (enable) + p_FmMacsecSecY->exceptions |= bitMask; + else + p_FmMacsecSecY->exceptions &= ~bitMask; + } + else + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("Undefined exception")); + + return E_OK; +} + +t_Error FM_MACSEC_SECY_ConfigEvent(t_Handle h_FmMacsecSecY, e_FmMacsecSecYEvents event, bool enable) +{ + t_FmMacsecSecY *p_FmMacsecSecY = (t_FmMacsecSecY *)h_FmMacsecSecY; + uint32_t bitMask = 0; + + SANITY_CHECK_RETURN_ERROR(p_FmMacsecSecY, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_FmMacsecSecY->p_FmMacsecSecYDriverParam, E_INVALID_STATE); + + GET_EVENT_FLAG(bitMask, event); + if (bitMask) + { + if (enable) + p_FmMacsecSecY->events |= bitMask; + else + p_FmMacsecSecY->events &= ~bitMask; + } + else + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("Undefined event")); + + return E_OK; +} + +t_Handle FM_MACSEC_SECY_CreateRxSc(t_Handle h_FmMacsecSecY, t_FmMacsecSecYSCParams *p_ScParams) +{ + t_FmMacsecSecY *p_FmMacsecSecY = (t_FmMacsecSecY *)h_FmMacsecSecY; + + SANITY_CHECK_RETURN_VALUE(p_FmMacsecSecY, E_INVALID_HANDLE, NULL); + SANITY_CHECK_RETURN_VALUE(p_FmMacsecSecY->h_FmMacsec, E_INVALID_HANDLE, NULL); + SANITY_CHECK_RETURN_VALUE(p_ScParams, E_NULL_POINTER, NULL); + SANITY_CHECK_RETURN_VALUE(!p_FmMacsecSecY->p_FmMacsecSecYDriverParam, E_INVALID_STATE, NULL); + + return FmMacsecSecYCreateSc(p_FmMacsecSecY, p_ScParams->sci, p_ScParams->cipherSuite, e_SC_RX); +} + +t_Error FM_MACSEC_SECY_DeleteRxSc(t_Handle h_FmMacsecSecY, t_Handle h_Sc) +{ + t_FmMacsecSecY *p_FmMacsecSecY = (t_FmMacsecSecY *)h_FmMacsecSecY; + t_SecYSc *p_FmSecYSc = (t_SecYSc *)h_Sc; + + SANITY_CHECK_RETURN_ERROR(p_FmMacsecSecY, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_FmMacsecSecY->h_FmMacsec, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(!p_FmMacsecSecY->p_FmMacsecSecYDriverParam, E_INVALID_STATE); + SANITY_CHECK_RETURN_ERROR(p_FmSecYSc, E_INVALID_HANDLE); + + return FmMacsecSecYDeleteSc(p_FmMacsecSecY, p_FmSecYSc, e_SC_RX); +} + +t_Error FM_MACSEC_SECY_CreateRxSa(t_Handle h_FmMacsecSecY, t_Handle h_Sc, macsecAN_t an, uint32_t lowestPn, macsecSAKey_t key) +{ + t_FmMacsecSecY *p_FmMacsecSecY = (t_FmMacsecSecY *)h_FmMacsecSecY; + t_SecYSc *p_FmSecYSc = (t_SecYSc *)h_Sc; + t_Error err = E_OK; + + SANITY_CHECK_RETURN_ERROR(p_FmMacsecSecY, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_FmMacsecSecY->h_FmMacsec, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(!p_FmMacsecSecY->p_FmMacsecSecYDriverParam, E_INVALID_STATE); + SANITY_CHECK_RETURN_ERROR(p_FmSecYSc, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(an < MAX_NUM_OF_SA_PER_SC, E_INVALID_STATE); + + if (p_FmSecYSc->sa[an].saId != SECY_AN_FREE_VALUE) + RETURN_ERROR(MINOR, E_INVALID_STATE, ("An %d is already assigned",an)); + + if ((err = FmMacsecCreateRxSa(p_FmMacsecSecY->h_FmMacsec, p_FmSecYSc->scId, (e_ScSaId)p_FmSecYSc->numOfSa, an, lowestPn, key)) != E_OK) + RETURN_ERROR(MINOR, err, NO_MSG); + + p_FmSecYSc->sa[an].saId = (e_ScSaId)p_FmSecYSc->numOfSa++; + return err; +} + +t_Error FM_MACSEC_SECY_DeleteRxSa(t_Handle h_FmMacsecSecY, t_Handle h_Sc, macsecAN_t an) +{ + t_FmMacsecSecY *p_FmMacsecSecY = (t_FmMacsecSecY *)h_FmMacsecSecY; + t_SecYSc *p_FmSecYSc = (t_SecYSc *)h_Sc; + t_Error err = E_OK; + + SANITY_CHECK_RETURN_ERROR(p_FmMacsecSecY, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_FmMacsecSecY->h_FmMacsec, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(!p_FmMacsecSecY->p_FmMacsecSecYDriverParam, E_INVALID_STATE); + SANITY_CHECK_RETURN_ERROR(p_FmSecYSc, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(an < MAX_NUM_OF_SA_PER_SC, E_INVALID_STATE); + + if (p_FmSecYSc->sa[an].saId == SECY_AN_FREE_VALUE) + RETURN_ERROR(MINOR, E_INVALID_STATE, ("An %d is already deleted",an)); + + if ((err = FmMacsecDeleteRxSa(p_FmMacsecSecY->h_FmMacsec, p_FmSecYSc->scId, p_FmSecYSc->sa[an].saId)) != E_OK) + RETURN_ERROR(MINOR, err, NO_MSG); + + p_FmSecYSc->numOfSa--; + p_FmSecYSc->sa[an].saId = (e_ScSaId)SECY_AN_FREE_VALUE; + /* TODO - check if statistics need to be read*/ + return err; +} + +t_Error FM_MACSEC_SECY_RxSaEnableReceive(t_Handle h_FmMacsecSecY, t_Handle h_Sc, macsecAN_t an) +{ + t_FmMacsecSecY *p_FmMacsecSecY = (t_FmMacsecSecY *)h_FmMacsecSecY; + t_SecYSc *p_FmSecYSc = (t_SecYSc *)h_Sc; + t_Error err = E_OK; + + SANITY_CHECK_RETURN_ERROR(p_FmMacsecSecY, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_FmMacsecSecY->h_FmMacsec, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(!p_FmMacsecSecY->p_FmMacsecSecYDriverParam, E_INVALID_STATE); + SANITY_CHECK_RETURN_ERROR(p_FmSecYSc, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(an < MAX_NUM_OF_SA_PER_SC, E_INVALID_STATE); + + if (p_FmSecYSc->sa[an].saId == SECY_AN_FREE_VALUE) + RETURN_ERROR(MINOR, E_INVALID_STATE, ("An %d is not configured",an)); + + if ((err = FmMacsecRxSaSetReceive(p_FmMacsecSecY->h_FmMacsec,p_FmSecYSc->scId, p_FmSecYSc->sa[an].saId, TRUE)) != E_OK) + RETURN_ERROR(MINOR, err, NO_MSG); + + p_FmSecYSc->sa[an].active = TRUE; + return err; +} + +t_Error FM_MACSEC_SECY_RxSaDisableReceive(t_Handle h_FmMacsecSecY, t_Handle h_Sc, macsecAN_t an) +{ + t_FmMacsecSecY *p_FmMacsecSecY = (t_FmMacsecSecY *)h_FmMacsecSecY; + t_SecYSc *p_FmSecYSc = (t_SecYSc *)h_Sc; + t_Error err = E_OK; + + SANITY_CHECK_RETURN_ERROR(p_FmMacsecSecY, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_FmMacsecSecY->h_FmMacsec, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(!p_FmMacsecSecY->p_FmMacsecSecYDriverParam, E_INVALID_STATE); + SANITY_CHECK_RETURN_ERROR(p_FmSecYSc, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(an < MAX_NUM_OF_SA_PER_SC, E_INVALID_STATE); + + if (p_FmSecYSc->sa[an].saId == SECY_AN_FREE_VALUE) + RETURN_ERROR(MINOR, E_INVALID_STATE, ("An %d is not configured",an)); + + if ((err = FmMacsecRxSaSetReceive(p_FmMacsecSecY->h_FmMacsec,p_FmSecYSc->scId, p_FmSecYSc->sa[an].saId, FALSE)) != E_OK) + RETURN_ERROR(MINOR, err, NO_MSG); + + p_FmSecYSc->sa[an].active = FALSE; + return err; +} + +t_Error FM_MACSEC_SECY_RxSaUpdateNextPn(t_Handle h_FmMacsecSecY, t_Handle h_Sc, macsecAN_t an, uint32_t updtNextPN) +{ + t_FmMacsecSecY *p_FmMacsecSecY = (t_FmMacsecSecY *)h_FmMacsecSecY; + t_SecYSc *p_FmSecYSc = (t_SecYSc *)h_Sc; + t_Error err = E_OK; + + SANITY_CHECK_RETURN_ERROR(p_FmMacsecSecY, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_FmMacsecSecY->h_FmMacsec, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(!p_FmMacsecSecY->p_FmMacsecSecYDriverParam, E_INVALID_STATE); + SANITY_CHECK_RETURN_ERROR(p_FmSecYSc, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(an < MAX_NUM_OF_SA_PER_SC, E_INVALID_STATE); + + if (p_FmSecYSc->sa[an].saId == SECY_AN_FREE_VALUE) + RETURN_ERROR(MINOR, E_INVALID_STATE, ("An %d is not configured",an)); + + if ((err = FmMacsecRxSaUpdateNextPn(p_FmMacsecSecY->h_FmMacsec,p_FmSecYSc->scId, p_FmSecYSc->sa[an].saId, updtNextPN)) != E_OK) + RETURN_ERROR(MINOR, err, NO_MSG); + + return err; +} + +t_Error FM_MACSEC_SECY_RxSaUpdateLowestPn(t_Handle h_FmMacsecSecY, t_Handle h_Sc, macsecAN_t an, uint32_t updtLowestPN) +{ + t_FmMacsecSecY *p_FmMacsecSecY = (t_FmMacsecSecY *)h_FmMacsecSecY; + t_SecYSc *p_FmSecYSc = (t_SecYSc *)h_Sc; + t_Error err = E_OK; + + SANITY_CHECK_RETURN_ERROR(p_FmMacsecSecY, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_FmMacsecSecY->h_FmMacsec, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(!p_FmMacsecSecY->p_FmMacsecSecYDriverParam, E_INVALID_STATE); + SANITY_CHECK_RETURN_ERROR(p_FmSecYSc, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(an < MAX_NUM_OF_SA_PER_SC, E_INVALID_STATE); + + if (p_FmSecYSc->sa[an].saId == SECY_AN_FREE_VALUE) + RETURN_ERROR(MINOR, E_INVALID_STATE, ("An %d is not configured",an)); + + if ((err = FmMacsecRxSaUpdateLowestPn(p_FmMacsecSecY->h_FmMacsec,p_FmSecYSc->scId, p_FmSecYSc->sa[an].saId, updtLowestPN)) != E_OK) + RETURN_ERROR(MINOR, err, NO_MSG); + + return err; +} + +t_Error FM_MACSEC_SECY_RxSaModifyKey(t_Handle h_FmMacsecSecY, t_Handle h_Sc, macsecAN_t an, macsecSAKey_t key) +{ + t_FmMacsecSecY *p_FmMacsecSecY = (t_FmMacsecSecY *)h_FmMacsecSecY; + t_SecYSc *p_FmSecYSc = (t_SecYSc *)h_Sc; + t_Error err = E_OK; + + SANITY_CHECK_RETURN_ERROR(p_FmMacsecSecY, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_FmMacsecSecY->h_FmMacsec, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(!p_FmMacsecSecY->p_FmMacsecSecYDriverParam, E_INVALID_STATE); + SANITY_CHECK_RETURN_ERROR(p_FmSecYSc, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(an < MAX_NUM_OF_SA_PER_SC, E_INVALID_STATE); + + if (p_FmSecYSc->sa[an].saId == SECY_AN_FREE_VALUE) + RETURN_ERROR(MINOR, E_INVALID_STATE, ("An %d is not configured",an)); + + if (p_FmSecYSc->sa[an].active) + if ((err = FmMacsecRxSaSetReceive(p_FmMacsecSecY->h_FmMacsec, p_FmSecYSc->scId, p_FmSecYSc->sa[an].saId, FALSE)) != E_OK) + RETURN_ERROR(MINOR, err, NO_MSG); + + /* TODO - statistics should be read */ + + if ((err = FmMacsecCreateRxSa(p_FmMacsecSecY->h_FmMacsec, p_FmSecYSc->scId, p_FmSecYSc->sa[an].saId, an, 1, key)) != E_OK) + RETURN_ERROR(MINOR, err, NO_MSG); + + if (p_FmSecYSc->sa[an].active) + if ((err = FmMacsecRxSaSetReceive(p_FmMacsecSecY->h_FmMacsec, p_FmSecYSc->scId, p_FmSecYSc->sa[an].saId, TRUE)) != E_OK) + RETURN_ERROR(MINOR, err, NO_MSG); + return err; +} + + +t_Error FM_MACSEC_SECY_CreateTxSa(t_Handle h_FmMacsecSecY, macsecAN_t an, macsecSAKey_t key) +{ + t_FmMacsecSecY *p_FmMacsecSecY = (t_FmMacsecSecY *)h_FmMacsecSecY; + t_SecYSc *p_FmSecYSc; + t_Error err = E_OK; + + SANITY_CHECK_RETURN_ERROR(p_FmMacsecSecY, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_FmMacsecSecY->h_FmMacsec, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(!p_FmMacsecSecY->p_FmMacsecSecYDriverParam, E_INVALID_STATE); + p_FmSecYSc = &p_FmMacsecSecY->p_TxSc[0]; + SANITY_CHECK_RETURN_ERROR(p_FmSecYSc, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(an < MAX_NUM_OF_SA_PER_SC, E_INVALID_STATE); + + if (p_FmSecYSc->sa[an].saId != SECY_AN_FREE_VALUE) + RETURN_ERROR(MINOR, err, ("An %d is already assigned",an)); + + if ((err = FmMacsecCreateTxSa(p_FmMacsecSecY->h_FmMacsec,p_FmSecYSc->scId, (e_ScSaId)p_FmSecYSc->numOfSa, key)) != E_OK) + RETURN_ERROR(MINOR, err, NO_MSG); + + p_FmSecYSc->sa[an].saId = (e_ScSaId)p_FmSecYSc->numOfSa++; + return err; +} + +t_Error FM_MACSEC_SECY_DeleteTxSa(t_Handle h_FmMacsecSecY, macsecAN_t an) +{ + t_FmMacsecSecY *p_FmMacsecSecY = (t_FmMacsecSecY *)h_FmMacsecSecY; + t_SecYSc *p_FmSecYSc; + t_Error err = E_OK; + + SANITY_CHECK_RETURN_ERROR(p_FmMacsecSecY, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_FmMacsecSecY->h_FmMacsec, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(!p_FmMacsecSecY->p_FmMacsecSecYDriverParam, E_INVALID_STATE); + p_FmSecYSc = &p_FmMacsecSecY->p_TxSc[0]; + SANITY_CHECK_RETURN_ERROR(p_FmSecYSc, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(an < MAX_NUM_OF_SA_PER_SC, E_INVALID_STATE); + + if (p_FmSecYSc->sa[an].saId == SECY_AN_FREE_VALUE) + RETURN_ERROR(MINOR, E_INVALID_STATE, ("An %d is already deleted",an)); + + if ((err = FmMacsecDeleteTxSa(p_FmMacsecSecY->h_FmMacsec, p_FmSecYSc->scId, p_FmSecYSc->sa[an].saId)) != E_OK) + RETURN_ERROR(MINOR, err, NO_MSG); + + p_FmSecYSc->numOfSa--; + p_FmSecYSc->sa[an].saId = (e_ScSaId)SECY_AN_FREE_VALUE; + /* TODO - check if statistics need to be read*/ + return err; +} + +t_Error FM_MACSEC_SECY_TxSaModifyKey(t_Handle h_FmMacsecSecY, macsecAN_t nextActiveAn, macsecSAKey_t key) +{ + t_FmMacsecSecY *p_FmMacsecSecY = (t_FmMacsecSecY *)h_FmMacsecSecY; + t_SecYSc *p_FmSecYSc; + macsecAN_t currentAn; + t_Error err = E_OK; + + SANITY_CHECK_RETURN_ERROR(p_FmMacsecSecY, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_FmMacsecSecY->h_FmMacsec, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(!p_FmMacsecSecY->p_FmMacsecSecYDriverParam, E_INVALID_STATE); + p_FmSecYSc = &p_FmMacsecSecY->p_TxSc[0]; + SANITY_CHECK_RETURN_ERROR(p_FmSecYSc, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(nextActiveAn < MAX_NUM_OF_SA_PER_SC, E_INVALID_STATE); + + if ((err = FmMacsecTxSaGetActive(p_FmMacsecSecY->h_FmMacsec, + p_FmSecYSc->scId, + ¤tAn)) != E_OK) + RETURN_ERROR(MINOR, err, NO_MSG); + + if ((err = FmMacsecTxSaSetActive(p_FmMacsecSecY->h_FmMacsec, + p_FmSecYSc->scId, + p_FmSecYSc->sa[nextActiveAn].saId, + nextActiveAn)) != E_OK) + RETURN_ERROR(MINOR, err, NO_MSG); + + /* TODO - statistics should be read */ + + if ((err = FmMacsecCreateTxSa(p_FmMacsecSecY->h_FmMacsec, p_FmSecYSc->scId, p_FmSecYSc->sa[currentAn].saId, key)) != E_OK) + RETURN_ERROR(MINOR, err, NO_MSG); + + return err; +} + +t_Error FM_MACSEC_SECY_TxSaSetActive(t_Handle h_FmMacsecSecY, macsecAN_t an) +{ + t_FmMacsecSecY *p_FmMacsecSecY = (t_FmMacsecSecY *)h_FmMacsecSecY; + t_SecYSc *p_FmSecYSc; + t_Error err = E_OK; + + SANITY_CHECK_RETURN_ERROR(p_FmMacsecSecY, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_FmMacsecSecY->h_FmMacsec, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(!p_FmMacsecSecY->p_FmMacsecSecYDriverParam, E_INVALID_STATE); + p_FmSecYSc = &p_FmMacsecSecY->p_TxSc[0]; + SANITY_CHECK_RETURN_ERROR(p_FmSecYSc, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(an < MAX_NUM_OF_SA_PER_SC, E_INVALID_STATE); + + if (p_FmSecYSc->sa[an].saId == SECY_AN_FREE_VALUE) + RETURN_ERROR(MINOR, E_INVALID_STATE, ("An %d is not configured",an)); + + if ((err = FmMacsecTxSaSetActive(p_FmMacsecSecY->h_FmMacsec, + p_FmSecYSc->scId, + p_FmSecYSc->sa[an].saId, + an)) != E_OK) + RETURN_ERROR(MINOR, err, NO_MSG); + + return err; +} + +t_Error FM_MACSEC_SECY_TxSaGetActive(t_Handle h_FmMacsecSecY, macsecAN_t *p_An) +{ + t_FmMacsecSecY *p_FmMacsecSecY = (t_FmMacsecSecY *)h_FmMacsecSecY; + t_SecYSc *p_FmSecYSc; + t_Error err = E_OK; + + SANITY_CHECK_RETURN_ERROR(p_FmMacsecSecY, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_FmMacsecSecY->h_FmMacsec, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(!p_FmMacsecSecY->p_FmMacsecSecYDriverParam, E_INVALID_STATE); + p_FmSecYSc = &p_FmMacsecSecY->p_TxSc[0]; + SANITY_CHECK_RETURN_ERROR(p_FmSecYSc, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_An, E_INVALID_HANDLE); + + if ((err = FmMacsecTxSaGetActive(p_FmMacsecSecY->h_FmMacsec, + p_FmSecYSc->scId, + p_An)) != E_OK) + RETURN_ERROR(MINOR, err, NO_MSG); + + return err; +} + +t_Error FM_MACSEC_SECY_GetRxScPhysId(t_Handle h_FmMacsecSecY, t_Handle h_Sc, uint32_t *p_ScPhysId) +{ + t_SecYSc *p_FmSecYSc = (t_SecYSc *)h_Sc; + t_Error err = E_OK; + + SANITY_CHECK_RETURN_ERROR(h_FmMacsecSecY, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(((t_FmMacsecSecY *)h_FmMacsecSecY)->h_FmMacsec, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(!((t_FmMacsecSecY *)h_FmMacsecSecY)->p_FmMacsecSecYDriverParam, E_INVALID_STATE); + SANITY_CHECK_RETURN_ERROR(p_FmSecYSc, E_INVALID_HANDLE); +#ifdef DISABLE_SANITY_CHECKS + UNUSED(h_FmMacsecSecY); +#endif /* DISABLE_SANITY_CHECKS */ + + *p_ScPhysId = p_FmSecYSc->scId; + return err; +} + +t_Error FM_MACSEC_SECY_GetTxScPhysId(t_Handle h_FmMacsecSecY, uint32_t *p_ScPhysId) +{ + t_FmMacsecSecY *p_FmMacsecSecY = (t_FmMacsecSecY *)h_FmMacsecSecY; + t_SecYSc *p_FmSecYSc; + t_Error err = E_OK; + + SANITY_CHECK_RETURN_ERROR(p_FmMacsecSecY, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_FmMacsecSecY->h_FmMacsec, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(!p_FmMacsecSecY->p_FmMacsecSecYDriverParam, E_INVALID_STATE); + p_FmSecYSc = &p_FmMacsecSecY->p_TxSc[0]; + SANITY_CHECK_RETURN_ERROR(p_FmSecYSc, E_INVALID_HANDLE); + + *p_ScPhysId = p_FmSecYSc->scId; + return err; +} + +t_Error FM_MACSEC_SECY_SetException(t_Handle h_FmMacsecSecY, e_FmMacsecExceptions exception, bool enable) +{ + UNUSED(h_FmMacsecSecY);UNUSED(exception);UNUSED(enable); + RETURN_ERROR(MINOR, E_NOT_SUPPORTED, NO_MSG); +} + +t_Error FM_MACSEC_SECY_SetEvent(t_Handle h_FmMacsecSecY, e_FmMacsecSecYEvents event, bool enable) +{ + UNUSED(h_FmMacsecSecY);UNUSED(event);UNUSED(enable); + RETURN_ERROR(MINOR, E_NOT_SUPPORTED, NO_MSG); +} + +t_Error FM_MACSEC_SECY_GetStatistics(t_Handle h_FmMacsecSecY, t_FmMacsecSecYStatistics *p_Statistics) +{ + UNUSED(h_FmMacsecSecY);UNUSED(p_Statistics); + RETURN_ERROR(MINOR, E_NOT_SUPPORTED, NO_MSG); +} + +t_Error FM_MACSEC_SECY_RxScGetStatistics(t_Handle h_FmMacsecSecY, t_Handle h_Sc, t_FmMacsecSecYRxScStatistics *p_Statistics) +{ + UNUSED(h_FmMacsecSecY);UNUSED(h_Sc);UNUSED(p_Statistics); + RETURN_ERROR(MINOR, E_NOT_SUPPORTED, NO_MSG); +} + +t_Error FM_MACSEC_SECY_RxSaGetStatistics(t_Handle h_FmMacsecSecY, t_Handle h_Sc, macsecAN_t an, t_FmMacsecSecYRxSaStatistics *p_Statistics) +{ + UNUSED(h_FmMacsecSecY);UNUSED(h_Sc);UNUSED(an);UNUSED(p_Statistics); + RETURN_ERROR(MINOR, E_NOT_SUPPORTED, NO_MSG); +} + +t_Error FM_MACSEC_SECY_TxScGetStatistics(t_Handle h_FmMacsecSecY, t_FmMacsecSecYTxScStatistics *p_Statistics) +{ + UNUSED(h_FmMacsecSecY);UNUSED(p_Statistics); + RETURN_ERROR(MINOR, E_NOT_SUPPORTED, NO_MSG); +} + +t_Error FM_MACSEC_SECY_TxSaGetStatistics(t_Handle h_FmMacsecSecY, macsecAN_t an, t_FmMacsecSecYTxSaStatistics *p_Statistics) +{ + UNUSED(h_FmMacsecSecY);UNUSED(an);UNUSED(p_Statistics); + RETURN_ERROR(MINOR, E_NOT_SUPPORTED, NO_MSG); +} + diff --git a/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MACSEC/fm_macsec_secy.h b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MACSEC/fm_macsec_secy.h new file mode 100644 index 000000000000..0cf624e68e2a --- /dev/null +++ b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/MACSEC/fm_macsec_secy.h @@ -0,0 +1,144 @@ +/* + * Copyright 2008-2015 Freescale Semiconductor Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Freescale Semiconductor nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * + * ALTERNATIVELY, this software may be distributed under the terms of the + * GNU General Public License ("GPL") as published by the Free Software + * Foundation, either version 2 of that License or (at your option) any + * later version. + * + * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/****************************************************************************** + @File fm_macsec_secy.h + + @Description FM MACSEC SecY internal structures and definitions. +*//***************************************************************************/ +#ifndef __FM_MACSEC_SECY_H +#define __FM_MACSEC_SECY_H + +#include "error_ext.h" +#include "std_ext.h" + +#include "fm_macsec.h" + + +/**************************************************************************//** + @Description Exceptions +*//***************************************************************************/ + +#define FM_MACSEC_SECY_EX_FRAME_DISCARDED 0x80000000 + +#define GET_EXCEPTION_FLAG(bitMask, exception) switch (exception){ \ + case e_FM_MACSEC_SECY_EX_FRAME_DISCARDED: \ + bitMask = FM_MACSEC_SECY_EX_FRAME_DISCARDED; break; \ + default: bitMask = 0;break;} + +/**************************************************************************//** + @Description Events +*//***************************************************************************/ + +#define FM_MACSEC_SECY_EV_NEXT_PN 0x80000000 + +#define GET_EVENT_FLAG(bitMask, event) switch (event){ \ + case e_FM_MACSEC_SECY_EV_NEXT_PN: \ + bitMask = FM_MACSEC_SECY_EV_NEXT_PN; break; \ + default: bitMask = 0;break;} + +/**************************************************************************//** + @Description Defaults +*//***************************************************************************/ + +#define DEFAULT_exceptions (FM_MACSEC_SECY_EX_FRAME_DISCARDED) +#define DEFAULT_events (FM_MACSEC_SECY_EV_NEXT_PN) +#define DEFAULT_numOfTxSc 1 +#define DEFAULT_confidentialityEnable FALSE +#define DEFAULT_confidentialityOffset 0 +#define DEFAULT_sciInsertionMode e_FM_MACSEC_SCI_INSERTION_MODE_EXPLICIT_SECTAG +#define DEFAULT_validateFrames e_FM_MACSEC_VALID_FRAME_BEHAVIOR_STRICT +#define DEFAULT_replayEnable FALSE +#define DEFAULT_replayWindow 0 +#define DEFAULT_protectFrames TRUE +#define DEFAULT_ptp FALSE + +/**************************************************************************//** + @Description General defines +*//***************************************************************************/ + +#define SECY_AN_FREE_VALUE MAX_NUM_OF_SA_PER_SC + + +typedef struct { + e_ScSaId saId; + bool active; + union { + t_FmMacsecSecYRxSaStatistics rxSaStatistics; + t_FmMacsecSecYTxSaStatistics txSaStatistics; + }; +} t_SecYSa; + +typedef struct { + bool inUse; + uint32_t scId; + e_ScType type; + uint8_t numOfSa; + t_SecYSa sa[MAX_NUM_OF_SA_PER_SC]; + union { + t_FmMacsecSecYRxScStatistics rxScStatistics; + t_FmMacsecSecYTxScStatistics txScStatistics; + }; +} t_SecYSc; + +typedef struct { + t_FmMacsecSecYSCParams txScParams; /**< Tx SC Params */ +} t_FmMacsecSecYDriverParam; + +typedef struct { + t_Handle h_FmMacsec; + bool confidentialityEnable; /**< TRUE - confidentiality protection and integrity protection + FALSE - no confidentiality protection, only integrity protection*/ + uint16_t confidentialityOffset; /**< The number of initial octets of each MSDU without confidentiality protection + common values are 0, 30, and 50 */ + bool replayProtect; /**< replay protection function mode */ + uint32_t replayWindow; /**< the size of the replay window */ + e_FmMacsecValidFrameBehavior validateFrames; /**< validation function mode */ + e_FmMacsecSciInsertionMode sciInsertionMode; + bool protectFrames; + bool isPointToPoint; + e_FmMacsecSecYCipherSuite cipherSuite; /**< Cipher suite to be used for this SecY */ + uint32_t numOfRxSc; /**< Number of receive channels */ + uint32_t numOfTxSc; /**< Number of transmit channels */ + t_SecYSc *p_RxSc; + t_SecYSc *p_TxSc; + uint32_t events; + uint32_t exceptions; + t_FmMacsecSecYExceptionsCallback *f_Exception; /**< TODO */ + t_FmMacsecSecYEventsCallback *f_Event; /**< TODO */ + t_Handle h_App; + t_FmMacsecSecYStatistics statistics; + t_FmMacsecSecYDriverParam *p_FmMacsecSecYDriverParam; +} t_FmMacsecSecY; + + +#endif /* __FM_MACSEC_SECY_H */ diff --git a/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Makefile b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Makefile new file mode 100644 index 000000000000..65e8344d185e --- /dev/null +++ b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Makefile @@ -0,0 +1,24 @@ +# +# Makefile for the Freescale Ethernet controllers +# +ccflags-y += -DVERSION=\"\" +# +#Include netcomm SW specific definitions +include $(srctree)/drivers/net/ethernet/freescale/sdk_fman/ncsw_config.mk +NCSW_FM_INC = $(srctree)/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/inc + +ccflags-y += -I$(NCSW_FM_INC) + + +obj-y += fsl-ncsw-PFM1.o + +fsl-ncsw-PFM1-objs := fm.o fm_muram.o fman.o + +obj-y += MAC/ +obj-y += Pcd/ +obj-y += SP/ +obj-y += Port/ +obj-y += HC/ +obj-y += MACSEC/ + +obj-$(CONFIG_FSL_SDK_FMAN_RTC_API) += Rtc/ diff --git a/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Pcd/Makefile b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Pcd/Makefile new file mode 100644 index 000000000000..62fbd73c8797 --- /dev/null +++ b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Pcd/Makefile @@ -0,0 +1,26 @@ +# +# Makefile for the Freescale Ethernet controllers +# +ccflags-y += -DVERSION=\"\" +# +#Include netcomm SW specific definitions +include $(srctree)/drivers/net/ethernet/freescale/sdk_fman/ncsw_config.mk + +NCSW_FM_INC = $(srctree)/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/inc + +ccflags-y += -I$(NCSW_FM_INC) + +obj-y += fsl-ncsw-Pcd.o + +fsl-ncsw-Pcd-objs := fman_kg.o fman_prs.o fm_cc.o fm_kg.o fm_pcd.o fm_plcr.o fm_prs.o fm_manip.o + +ifeq ($(CONFIG_FMAN_V3H),y) +fsl-ncsw-Pcd-objs += fm_replic.o +endif +ifeq ($(CONFIG_FMAN_V3L),y) +fsl-ncsw-Pcd-objs += fm_replic.o +endif +ifeq ($(CONFIG_FMAN_ARM),y) +fsl-ncsw-Pcd-objs += fm_replic.o +endif + diff --git a/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Pcd/crc64.h b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Pcd/crc64.h new file mode 100644 index 000000000000..335ee6819188 --- /dev/null +++ b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Pcd/crc64.h @@ -0,0 +1,360 @@ +/* + * Copyright 2008-2012 Freescale Semiconductor Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Freescale Semiconductor nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * + * ALTERNATIVELY, this software may be distributed under the terms of the + * GNU General Public License ("GPL") as published by the Free Software + * Foundation, either version 2 of that License or (at your option) any + * later version. + * + * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + + /**************************************************************************//** + @File crc64.h + + @Description brief This file contains the CRC64 Table, and __inline__ + functions used for calculating crc. +*//***************************************************************************/ +#ifndef __CRC64_H +#define __CRC64_H + +#include "std_ext.h" + + +#define BITS_PER_BYTE 8 + +#define CRC64_EXPON_ECMA_182 0xC96C5795D7870F42ULL +#define CRC64_DEFAULT_INITVAL 0xFFFFFFFFFFFFFFFFULL + +#define CRC64_BYTE_MASK 0xFF +#define CRC64_TABLE_ENTRIES ( 1 << BITS_PER_BYTE ) +#define CRC64_ODD_MASK 1 + + +/** + \brief '64 bit crc' Table + */ +struct crc64_t { + uint64_t initial; /**< Initial seed */ + uint64_t table[CRC64_TABLE_ENTRIES]; /**< CRC table entries */ +}; + + +static struct crc64_t CRC64_ECMA_182 = { + CRC64_DEFAULT_INITVAL, + { + 0x0000000000000000ULL, + 0xb32e4cbe03a75f6fULL, + 0xf4843657a840a05bULL, + 0x47aa7ae9abe7ff34ULL, + 0x7bd0c384ff8f5e33ULL, + 0xc8fe8f3afc28015cULL, + 0x8f54f5d357cffe68ULL, + 0x3c7ab96d5468a107ULL, + 0xf7a18709ff1ebc66ULL, + 0x448fcbb7fcb9e309ULL, + 0x0325b15e575e1c3dULL, + 0xb00bfde054f94352ULL, + 0x8c71448d0091e255ULL, + 0x3f5f08330336bd3aULL, + 0x78f572daa8d1420eULL, + 0xcbdb3e64ab761d61ULL, + 0x7d9ba13851336649ULL, + 0xceb5ed8652943926ULL, + 0x891f976ff973c612ULL, + 0x3a31dbd1fad4997dULL, + 0x064b62bcaebc387aULL, + 0xb5652e02ad1b6715ULL, + 0xf2cf54eb06fc9821ULL, + 0x41e11855055bc74eULL, + 0x8a3a2631ae2dda2fULL, + 0x39146a8fad8a8540ULL, + 0x7ebe1066066d7a74ULL, + 0xcd905cd805ca251bULL, + 0xf1eae5b551a2841cULL, + 0x42c4a90b5205db73ULL, + 0x056ed3e2f9e22447ULL, + 0xb6409f5cfa457b28ULL, + 0xfb374270a266cc92ULL, + 0x48190ecea1c193fdULL, + 0x0fb374270a266cc9ULL, + 0xbc9d3899098133a6ULL, + 0x80e781f45de992a1ULL, + 0x33c9cd4a5e4ecdceULL, + 0x7463b7a3f5a932faULL, + 0xc74dfb1df60e6d95ULL, + 0x0c96c5795d7870f4ULL, + 0xbfb889c75edf2f9bULL, + 0xf812f32ef538d0afULL, + 0x4b3cbf90f69f8fc0ULL, + 0x774606fda2f72ec7ULL, + 0xc4684a43a15071a8ULL, + 0x83c230aa0ab78e9cULL, + 0x30ec7c140910d1f3ULL, + 0x86ace348f355aadbULL, + 0x3582aff6f0f2f5b4ULL, + 0x7228d51f5b150a80ULL, + 0xc10699a158b255efULL, + 0xfd7c20cc0cdaf4e8ULL, + 0x4e526c720f7dab87ULL, + 0x09f8169ba49a54b3ULL, + 0xbad65a25a73d0bdcULL, + 0x710d64410c4b16bdULL, + 0xc22328ff0fec49d2ULL, + 0x85895216a40bb6e6ULL, + 0x36a71ea8a7ace989ULL, + 0x0adda7c5f3c4488eULL, + 0xb9f3eb7bf06317e1ULL, + 0xfe5991925b84e8d5ULL, + 0x4d77dd2c5823b7baULL, + 0x64b62bcaebc387a1ULL, + 0xd7986774e864d8ceULL, + 0x90321d9d438327faULL, + 0x231c512340247895ULL, + 0x1f66e84e144cd992ULL, + 0xac48a4f017eb86fdULL, + 0xebe2de19bc0c79c9ULL, + 0x58cc92a7bfab26a6ULL, + 0x9317acc314dd3bc7ULL, + 0x2039e07d177a64a8ULL, + 0x67939a94bc9d9b9cULL, + 0xd4bdd62abf3ac4f3ULL, + 0xe8c76f47eb5265f4ULL, + 0x5be923f9e8f53a9bULL, + 0x1c4359104312c5afULL, + 0xaf6d15ae40b59ac0ULL, + 0x192d8af2baf0e1e8ULL, + 0xaa03c64cb957be87ULL, + 0xeda9bca512b041b3ULL, + 0x5e87f01b11171edcULL, + 0x62fd4976457fbfdbULL, + 0xd1d305c846d8e0b4ULL, + 0x96797f21ed3f1f80ULL, + 0x2557339fee9840efULL, + 0xee8c0dfb45ee5d8eULL, + 0x5da24145464902e1ULL, + 0x1a083bacedaefdd5ULL, + 0xa9267712ee09a2baULL, + 0x955cce7fba6103bdULL, + 0x267282c1b9c65cd2ULL, + 0x61d8f8281221a3e6ULL, + 0xd2f6b4961186fc89ULL, + 0x9f8169ba49a54b33ULL, + 0x2caf25044a02145cULL, + 0x6b055fede1e5eb68ULL, + 0xd82b1353e242b407ULL, + 0xe451aa3eb62a1500ULL, + 0x577fe680b58d4a6fULL, + 0x10d59c691e6ab55bULL, + 0xa3fbd0d71dcdea34ULL, + 0x6820eeb3b6bbf755ULL, + 0xdb0ea20db51ca83aULL, + 0x9ca4d8e41efb570eULL, + 0x2f8a945a1d5c0861ULL, + 0x13f02d374934a966ULL, + 0xa0de61894a93f609ULL, + 0xe7741b60e174093dULL, + 0x545a57dee2d35652ULL, + 0xe21ac88218962d7aULL, + 0x5134843c1b317215ULL, + 0x169efed5b0d68d21ULL, + 0xa5b0b26bb371d24eULL, + 0x99ca0b06e7197349ULL, + 0x2ae447b8e4be2c26ULL, + 0x6d4e3d514f59d312ULL, + 0xde6071ef4cfe8c7dULL, + 0x15bb4f8be788911cULL, + 0xa6950335e42fce73ULL, + 0xe13f79dc4fc83147ULL, + 0x521135624c6f6e28ULL, + 0x6e6b8c0f1807cf2fULL, + 0xdd45c0b11ba09040ULL, + 0x9aefba58b0476f74ULL, + 0x29c1f6e6b3e0301bULL, + 0xc96c5795d7870f42ULL, + 0x7a421b2bd420502dULL, + 0x3de861c27fc7af19ULL, + 0x8ec62d7c7c60f076ULL, + 0xb2bc941128085171ULL, + 0x0192d8af2baf0e1eULL, + 0x4638a2468048f12aULL, + 0xf516eef883efae45ULL, + 0x3ecdd09c2899b324ULL, + 0x8de39c222b3eec4bULL, + 0xca49e6cb80d9137fULL, + 0x7967aa75837e4c10ULL, + 0x451d1318d716ed17ULL, + 0xf6335fa6d4b1b278ULL, + 0xb199254f7f564d4cULL, + 0x02b769f17cf11223ULL, + 0xb4f7f6ad86b4690bULL, + 0x07d9ba1385133664ULL, + 0x4073c0fa2ef4c950ULL, + 0xf35d8c442d53963fULL, + 0xcf273529793b3738ULL, + 0x7c0979977a9c6857ULL, + 0x3ba3037ed17b9763ULL, + 0x888d4fc0d2dcc80cULL, + 0x435671a479aad56dULL, + 0xf0783d1a7a0d8a02ULL, + 0xb7d247f3d1ea7536ULL, + 0x04fc0b4dd24d2a59ULL, + 0x3886b22086258b5eULL, + 0x8ba8fe9e8582d431ULL, + 0xcc0284772e652b05ULL, + 0x7f2cc8c92dc2746aULL, + 0x325b15e575e1c3d0ULL, + 0x8175595b76469cbfULL, + 0xc6df23b2dda1638bULL, + 0x75f16f0cde063ce4ULL, + 0x498bd6618a6e9de3ULL, + 0xfaa59adf89c9c28cULL, + 0xbd0fe036222e3db8ULL, + 0x0e21ac88218962d7ULL, + 0xc5fa92ec8aff7fb6ULL, + 0x76d4de52895820d9ULL, + 0x317ea4bb22bfdfedULL, + 0x8250e80521188082ULL, + 0xbe2a516875702185ULL, + 0x0d041dd676d77eeaULL, + 0x4aae673fdd3081deULL, + 0xf9802b81de97deb1ULL, + 0x4fc0b4dd24d2a599ULL, + 0xfceef8632775faf6ULL, + 0xbb44828a8c9205c2ULL, + 0x086ace348f355aadULL, + 0x34107759db5dfbaaULL, + 0x873e3be7d8faa4c5ULL, + 0xc094410e731d5bf1ULL, + 0x73ba0db070ba049eULL, + 0xb86133d4dbcc19ffULL, + 0x0b4f7f6ad86b4690ULL, + 0x4ce50583738cb9a4ULL, + 0xffcb493d702be6cbULL, + 0xc3b1f050244347ccULL, + 0x709fbcee27e418a3ULL, + 0x3735c6078c03e797ULL, + 0x841b8ab98fa4b8f8ULL, + 0xadda7c5f3c4488e3ULL, + 0x1ef430e13fe3d78cULL, + 0x595e4a08940428b8ULL, + 0xea7006b697a377d7ULL, + 0xd60abfdbc3cbd6d0ULL, + 0x6524f365c06c89bfULL, + 0x228e898c6b8b768bULL, + 0x91a0c532682c29e4ULL, + 0x5a7bfb56c35a3485ULL, + 0xe955b7e8c0fd6beaULL, + 0xaeffcd016b1a94deULL, + 0x1dd181bf68bdcbb1ULL, + 0x21ab38d23cd56ab6ULL, + 0x9285746c3f7235d9ULL, + 0xd52f0e859495caedULL, + 0x6601423b97329582ULL, + 0xd041dd676d77eeaaULL, + 0x636f91d96ed0b1c5ULL, + 0x24c5eb30c5374ef1ULL, + 0x97eba78ec690119eULL, + 0xab911ee392f8b099ULL, + 0x18bf525d915feff6ULL, + 0x5f1528b43ab810c2ULL, + 0xec3b640a391f4fadULL, + 0x27e05a6e926952ccULL, + 0x94ce16d091ce0da3ULL, + 0xd3646c393a29f297ULL, + 0x604a2087398eadf8ULL, + 0x5c3099ea6de60cffULL, + 0xef1ed5546e415390ULL, + 0xa8b4afbdc5a6aca4ULL, + 0x1b9ae303c601f3cbULL, + 0x56ed3e2f9e224471ULL, + 0xe5c372919d851b1eULL, + 0xa26908783662e42aULL, + 0x114744c635c5bb45ULL, + 0x2d3dfdab61ad1a42ULL, + 0x9e13b115620a452dULL, + 0xd9b9cbfcc9edba19ULL, + 0x6a978742ca4ae576ULL, + 0xa14cb926613cf817ULL, + 0x1262f598629ba778ULL, + 0x55c88f71c97c584cULL, + 0xe6e6c3cfcadb0723ULL, + 0xda9c7aa29eb3a624ULL, + 0x69b2361c9d14f94bULL, + 0x2e184cf536f3067fULL, + 0x9d36004b35545910ULL, + 0x2b769f17cf112238ULL, + 0x9858d3a9ccb67d57ULL, + 0xdff2a94067518263ULL, + 0x6cdce5fe64f6dd0cULL, + 0x50a65c93309e7c0bULL, + 0xe388102d33392364ULL, + 0xa4226ac498dedc50ULL, + 0x170c267a9b79833fULL, + 0xdcd7181e300f9e5eULL, + 0x6ff954a033a8c131ULL, + 0x28532e49984f3e05ULL, + 0x9b7d62f79be8616aULL, + 0xa707db9acf80c06dULL, + 0x14299724cc279f02ULL, + 0x5383edcd67c06036ULL, + 0xe0ada17364673f59ULL + } +}; + + +/** + \brief Initializes the crc seed + */ +static __inline__ uint64_t crc64_init(void) +{ + return CRC64_ECMA_182.initial; +} + +/** + \brief Computes 64 bit the crc + \param[in] data Pointer to the Data in the frame + \param[in] len Length of the Data + \param[in] crc seed + \return calculated crc + */ +static __inline__ uint64_t crc64_compute(void const *data, + uint32_t len, + uint64_t seed) +{ + uint32_t i; + uint64_t crc = seed; + uint8_t *bdata = (uint8_t *) data; + + for (i = 0; i < len; i++) + crc = + CRC64_ECMA_182. + table[(crc ^ *bdata++) & CRC64_BYTE_MASK] ^ (crc >> 8); + + return crc; +} + + +#endif /* __CRC64_H */ diff --git a/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Pcd/fm_cc.c b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Pcd/fm_cc.c new file mode 100644 index 000000000000..8b8221755760 --- /dev/null +++ b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Pcd/fm_cc.c @@ -0,0 +1,7583 @@ +/* + * Copyright 2008-2012 Freescale Semiconductor Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Freescale Semiconductor nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * + * ALTERNATIVELY, this software may be distributed under the terms of the + * GNU General Public License ("GPL") as published by the Free Software + * Foundation, either version 2 of that License or (at your option) any + * later version. + * + * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + +/****************************************************************************** + @File fm_cc.c + + @Description FM Coarse Classifier implementation + *//***************************************************************************/ +#include <linux/math64.h> +#include "std_ext.h" +#include "error_ext.h" +#include "string_ext.h" +#include "debug_ext.h" +#include "fm_pcd_ext.h" +#include "fm_muram_ext.h" + +#include "fm_common.h" +#include "fm_pcd.h" +#include "fm_hc.h" +#include "fm_cc.h" +#include "crc64.h" + +/****************************************/ +/* static functions */ +/****************************************/ + + +static t_Error CcRootTryLock(t_Handle h_FmPcdCcTree) +{ + t_FmPcdCcTree *p_FmPcdCcTree = (t_FmPcdCcTree *)h_FmPcdCcTree; + + ASSERT_COND(h_FmPcdCcTree); + + if (FmPcdLockTryLock(p_FmPcdCcTree->p_Lock)) + return E_OK; + + return ERROR_CODE(E_BUSY); +} + +static void CcRootReleaseLock(t_Handle h_FmPcdCcTree) +{ + t_FmPcdCcTree *p_FmPcdCcTree = (t_FmPcdCcTree *)h_FmPcdCcTree; + + ASSERT_COND(h_FmPcdCcTree); + + FmPcdLockUnlock(p_FmPcdCcTree->p_Lock); +} + +static void UpdateNodeOwner(t_FmPcdCcNode *p_CcNode, bool add) +{ + uint32_t intFlags; + + ASSERT_COND(p_CcNode); + + intFlags = XX_LockIntrSpinlock(p_CcNode->h_Spinlock); + + if (add) + p_CcNode->owners++; + else + { + ASSERT_COND(p_CcNode->owners); + p_CcNode->owners--; + } + + XX_UnlockIntrSpinlock(p_CcNode->h_Spinlock, intFlags); +} + +static __inline__ t_FmPcdStatsObj* DequeueStatsObj(t_List *p_List) +{ + t_FmPcdStatsObj *p_StatsObj = NULL; + t_List *p_Next; + + if (!LIST_IsEmpty(p_List)) + { + p_Next = LIST_FIRST(p_List); + p_StatsObj = LIST_OBJECT(p_Next, t_FmPcdStatsObj, node); + ASSERT_COND(p_StatsObj); + LIST_DelAndInit(p_Next); + } + + return p_StatsObj; +} + +static __inline__ void EnqueueStatsObj(t_List *p_List, + t_FmPcdStatsObj *p_StatsObj) +{ + LIST_AddToTail(&p_StatsObj->node, p_List); +} + +static void FreeStatObjects(t_List *p_List, t_Handle h_FmMuram) +{ + t_FmPcdStatsObj *p_StatsObj; + + while (!LIST_IsEmpty(p_List)) + { + p_StatsObj = DequeueStatsObj(p_List); + ASSERT_COND(p_StatsObj); + + FM_MURAM_FreeMem(h_FmMuram, p_StatsObj->h_StatsAd); + FM_MURAM_FreeMem(h_FmMuram, p_StatsObj->h_StatsCounters); + + XX_Free(p_StatsObj); + } +} + +static t_FmPcdStatsObj* GetStatsObj(t_FmPcdCcNode *p_CcNode) +{ + t_FmPcdStatsObj* p_StatsObj; + t_Handle h_FmMuram; + + ASSERT_COND(p_CcNode); + + /* If 'maxNumOfKeys' was passed, all statistics object were preallocated + upon node initialization */ + if (p_CcNode->maxNumOfKeys) + { + p_StatsObj = DequeueStatsObj(&p_CcNode->availableStatsLst); + + /* Clean statistics counters & ADs */ + MemSet8(p_StatsObj->h_StatsAd, 0, FM_PCD_CC_AD_ENTRY_SIZE); + MemSet8(p_StatsObj->h_StatsCounters, 0, p_CcNode->countersArraySize); + } + else + { + h_FmMuram = ((t_FmPcd *)(p_CcNode->h_FmPcd))->h_FmMuram; + ASSERT_COND(h_FmMuram); + + p_StatsObj = XX_Malloc(sizeof(t_FmPcdStatsObj)); + if (!p_StatsObj) + { + REPORT_ERROR(MAJOR, E_NO_MEMORY, ("statistics object")); + return NULL; + } + + p_StatsObj->h_StatsAd = (t_Handle)FM_MURAM_AllocMem( + h_FmMuram, FM_PCD_CC_AD_ENTRY_SIZE, FM_PCD_CC_AD_TABLE_ALIGN); + if (!p_StatsObj->h_StatsAd) + { + XX_Free(p_StatsObj); + REPORT_ERROR(MAJOR, E_NO_MEMORY, ("MURAM allocation for statistics ADs")); + return NULL; + } + MemSet8(p_StatsObj->h_StatsAd, 0, FM_PCD_CC_AD_ENTRY_SIZE); + + p_StatsObj->h_StatsCounters = (t_Handle)FM_MURAM_AllocMem( + h_FmMuram, p_CcNode->countersArraySize, + FM_PCD_CC_AD_TABLE_ALIGN); + if (!p_StatsObj->h_StatsCounters) + { + FM_MURAM_FreeMem(h_FmMuram, p_StatsObj->h_StatsAd); + XX_Free(p_StatsObj); + REPORT_ERROR(MAJOR, E_NO_MEMORY, ("MURAM allocation for statistics counters")); + return NULL; + } + MemSet8(p_StatsObj->h_StatsCounters, 0, p_CcNode->countersArraySize); + } + + return p_StatsObj; +} + +static void PutStatsObj(t_FmPcdCcNode *p_CcNode, t_FmPcdStatsObj *p_StatsObj) +{ + t_Handle h_FmMuram; + + ASSERT_COND(p_CcNode); + ASSERT_COND(p_StatsObj); + + /* If 'maxNumOfKeys' was passed, all statistics object were preallocated + upon node initialization and now will be enqueued back to the list */ + if (p_CcNode->maxNumOfKeys) + { + /* Clean statistics counters */ + MemSet8(p_StatsObj->h_StatsCounters, 0, p_CcNode->countersArraySize); + + /* Clean statistics ADs */ + MemSet8(p_StatsObj->h_StatsAd, 0, FM_PCD_CC_AD_ENTRY_SIZE); + + EnqueueStatsObj(&p_CcNode->availableStatsLst, p_StatsObj); + } + else + { + h_FmMuram = ((t_FmPcd *)(p_CcNode->h_FmPcd))->h_FmMuram; + ASSERT_COND(h_FmMuram); + + FM_MURAM_FreeMem(h_FmMuram, p_StatsObj->h_StatsAd); + FM_MURAM_FreeMem(h_FmMuram, p_StatsObj->h_StatsCounters); + + XX_Free(p_StatsObj); + } +} + +static void SetStatsCounters(t_AdOfTypeStats *p_StatsAd, + uint32_t statsCountersAddr) +{ + uint32_t tmp = (statsCountersAddr & FM_PCD_AD_STATS_COUNTERS_ADDR_MASK); + + WRITE_UINT32(p_StatsAd->statsTableAddr, tmp); +} + + +static void UpdateStatsAd(t_FmPcdCcStatsParams *p_FmPcdCcStatsParams, + t_Handle h_Ad, uint64_t physicalMuramBase) +{ + t_AdOfTypeStats *p_StatsAd; + uint32_t statsCountersAddr, nextActionAddr, tmp; +#if (DPAA_VERSION >= 11) + uint32_t frameLengthRangesAddr; +#endif /* (DPAA_VERSION >= 11) */ + + p_StatsAd = (t_AdOfTypeStats *)p_FmPcdCcStatsParams->h_StatsAd; + + tmp = FM_PCD_AD_STATS_TYPE; + +#if (DPAA_VERSION >= 11) + if (p_FmPcdCcStatsParams->h_StatsFLRs) + { + frameLengthRangesAddr = (uint32_t)((XX_VirtToPhys( + p_FmPcdCcStatsParams->h_StatsFLRs) - physicalMuramBase)); + tmp |= (frameLengthRangesAddr & FM_PCD_AD_STATS_FLR_ADDR_MASK); + } +#endif /* (DPAA_VERSION >= 11) */ + WRITE_UINT32(p_StatsAd->profileTableAddr, tmp); + + nextActionAddr = (uint32_t)((XX_VirtToPhys(h_Ad) - physicalMuramBase)); + tmp = 0; + tmp |= (uint32_t)((nextActionAddr << FM_PCD_AD_STATS_NEXT_ACTION_SHIFT) + & FM_PCD_AD_STATS_NEXT_ACTION_MASK); + tmp |= (FM_PCD_AD_STATS_NAD_EN | FM_PCD_AD_STATS_OP_CODE); + +#if (DPAA_VERSION >= 11) + if (p_FmPcdCcStatsParams->h_StatsFLRs) + tmp |= FM_PCD_AD_STATS_FLR_EN; +#endif /* (DPAA_VERSION >= 11) */ + + WRITE_UINT32(p_StatsAd->nextActionIndx, tmp); + + statsCountersAddr = (uint32_t)((XX_VirtToPhys( + p_FmPcdCcStatsParams->h_StatsCounters) - physicalMuramBase)); + SetStatsCounters(p_StatsAd, statsCountersAddr); +} + +static void FillAdOfTypeContLookup(t_Handle h_Ad, + t_FmPcdCcStatsParams *p_FmPcdCcStatsParams, + t_Handle h_FmPcd, t_Handle p_CcNode, + t_Handle h_Manip, t_Handle h_FrmReplic) +{ + t_FmPcdCcNode *p_Node = (t_FmPcdCcNode *)p_CcNode; + t_AdOfTypeContLookup *p_AdContLookup = (t_AdOfTypeContLookup *)h_Ad; + t_Handle h_TmpAd; + t_FmPcd *p_FmPcd = (t_FmPcd*)h_FmPcd; + uint32_t tmpReg32; + t_Handle p_AdNewPtr = NULL; + + UNUSED(h_Manip); + UNUSED(h_FrmReplic); + + /* there are 3 cases handled in this routine of building a "Continue lookup" type AD. + * Case 1: No Manip. The action descriptor is built within the match table. + * p_AdResult = p_AdNewPtr; + * Case 2: Manip exists. A new AD is created - p_AdNewPtr. It is initialized + * either in the FmPcdManipUpdateAdResultForCc routine or it was already + * initialized and returned here. + * p_AdResult (within the match table) will be initialized after + * this routine returns and point to the existing AD. + * Case 3: Manip exists. The action descriptor is built within the match table. + * FmPcdManipUpdateAdContLookupForCc returns a NULL p_AdNewPtr. + */ + + /* As default, the "new" ptr is the current one. i.e. the content of the result + * AD will be written into the match table itself (case (1))*/ + p_AdNewPtr = p_AdContLookup; + + /* Initialize an action descriptor, if current statistics mode requires an Ad */ + if (p_FmPcdCcStatsParams) + { + ASSERT_COND(p_FmPcdCcStatsParams->h_StatsAd); + ASSERT_COND(p_FmPcdCcStatsParams->h_StatsCounters); + + /* Swapping addresses between statistics Ad and the current lookup AD */ + h_TmpAd = p_FmPcdCcStatsParams->h_StatsAd; + p_FmPcdCcStatsParams->h_StatsAd = h_Ad; + h_Ad = h_TmpAd; + + p_AdNewPtr = h_Ad; + p_AdContLookup = h_Ad; + + /* Init statistics Ad and connect current lookup AD as 'next action' from statistics Ad */ + UpdateStatsAd(p_FmPcdCcStatsParams, h_Ad, p_FmPcd->physicalMuramBase); + } + +#if DPAA_VERSION >= 11 + if (h_Manip && h_FrmReplic) + FmPcdManipUpdateAdContLookupForCc( + h_Manip, + h_Ad, + &p_AdNewPtr, + (uint32_t)((XX_VirtToPhys( + FrmReplicGroupGetSourceTableDescriptor(h_FrmReplic)) + - p_FmPcd->physicalMuramBase))); + else + if (h_FrmReplic) + FrmReplicGroupUpdateAd(h_FrmReplic, h_Ad, &p_AdNewPtr); + else +#endif /* (DPAA_VERSION >= 11) */ + if (h_Manip) + FmPcdManipUpdateAdContLookupForCc( + h_Manip, + h_Ad, + &p_AdNewPtr, + +#ifdef FM_CAPWAP_SUPPORT + /*no check for opcode of manip - this step can be reached only with capwap_applic_specific*/ + (uint32_t)((XX_VirtToPhys(p_Node->h_AdTable) - p_FmPcd->physicalMuramBase)) +#else /* not FM_CAPWAP_SUPPORT */ + (uint32_t)((XX_VirtToPhys(p_Node->h_Ad) + - p_FmPcd->physicalMuramBase)) +#endif /* not FM_CAPWAP_SUPPORT */ + ); + + /* if (p_AdNewPtr = NULL) --> Done. (case (3)) */ + if (p_AdNewPtr) + { + /* cases (1) & (2) */ + tmpReg32 = 0; + tmpReg32 |= FM_PCD_AD_CONT_LOOKUP_TYPE; + tmpReg32 |= + p_Node->sizeOfExtraction ? ((p_Node->sizeOfExtraction - 1) << 24) : + 0; + tmpReg32 |= (uint32_t)(XX_VirtToPhys(p_Node->h_AdTable) + - p_FmPcd->physicalMuramBase); + WRITE_UINT32(p_AdContLookup->ccAdBase, tmpReg32); + + tmpReg32 = 0; + tmpReg32 |= p_Node->numOfKeys << 24; + tmpReg32 |= (p_Node->lclMask ? FM_PCD_AD_CONT_LOOKUP_LCL_MASK : 0); + tmpReg32 |= + p_Node->h_KeysMatchTable ? (uint32_t)(XX_VirtToPhys( + p_Node->h_KeysMatchTable) - p_FmPcd->physicalMuramBase) : + 0; + WRITE_UINT32(p_AdContLookup->matchTblPtr, tmpReg32); + + tmpReg32 = 0; + tmpReg32 |= p_Node->prsArrayOffset << 24; + tmpReg32 |= p_Node->offset << 16; + tmpReg32 |= p_Node->parseCode; + WRITE_UINT32(p_AdContLookup->pcAndOffsets, tmpReg32); + + MemCpy8((void*)&p_AdContLookup->gmask, p_Node->p_GlblMask, + CC_GLBL_MASK_SIZE); + } +} + +static t_Error AllocAndFillAdForContLookupManip(t_Handle h_CcNode) +{ + t_FmPcdCcNode *p_CcNode = (t_FmPcdCcNode *)h_CcNode; + uint32_t intFlags; + + ASSERT_COND(p_CcNode); + + intFlags = XX_LockIntrSpinlock(p_CcNode->h_Spinlock); + + if (!p_CcNode->h_Ad) + { + if (p_CcNode->maxNumOfKeys) + p_CcNode->h_Ad = p_CcNode->h_TmpAd; + else + p_CcNode->h_Ad = (t_Handle)FM_MURAM_AllocMem( + ((t_FmPcd *)(p_CcNode->h_FmPcd))->h_FmMuram, + FM_PCD_CC_AD_ENTRY_SIZE, FM_PCD_CC_AD_TABLE_ALIGN); + + XX_UnlockIntrSpinlock(p_CcNode->h_Spinlock, intFlags); + + if (!p_CcNode->h_Ad) + RETURN_ERROR(MAJOR, E_NO_MEMORY, + ("MURAM allocation for CC action descriptor")); + + MemSet8(p_CcNode->h_Ad, 0, FM_PCD_CC_AD_ENTRY_SIZE); + + FillAdOfTypeContLookup(p_CcNode->h_Ad, NULL, p_CcNode->h_FmPcd, + p_CcNode, NULL, NULL); + } + else + XX_UnlockIntrSpinlock(p_CcNode->h_Spinlock, intFlags); + + return E_OK; +} + +static t_Error SetRequiredAction1( + t_Handle h_FmPcd, uint32_t requiredAction, + t_FmPcdCcKeyAndNextEngineParams *p_CcKeyAndNextEngineParamsTmp, + t_Handle h_AdTmp, uint16_t numOfEntries, t_Handle h_Tree) +{ + t_AdOfTypeResult *p_AdTmp = (t_AdOfTypeResult *)h_AdTmp; + uint32_t tmpReg32; + t_Error err; + t_FmPcdCcNode *p_CcNode; + int i = 0; + uint16_t tmp = 0; + uint16_t profileId; + uint8_t relativeSchemeId, physicalSchemeId; + t_CcNodeInformation ccNodeInfo; + + for (i = 0; i < numOfEntries; i++) + { + if (i == 0) + h_AdTmp = PTR_MOVE(h_AdTmp, i*FM_PCD_CC_AD_ENTRY_SIZE); + else + h_AdTmp = PTR_MOVE(h_AdTmp, FM_PCD_CC_AD_ENTRY_SIZE); + + switch (p_CcKeyAndNextEngineParamsTmp[i].nextEngineParams.nextEngine) + { + case (e_FM_PCD_CC): + if (requiredAction) + { + p_CcNode = + p_CcKeyAndNextEngineParamsTmp[i].nextEngineParams.params.ccParams.h_CcNode; + ASSERT_COND(p_CcNode); + if (p_CcNode->shadowAction == requiredAction) + break; + if ((requiredAction & UPDATE_CC_WITH_TREE) + && !(p_CcNode->shadowAction & UPDATE_CC_WITH_TREE)) + { + + memset(&ccNodeInfo, 0, sizeof(t_CcNodeInformation)); + ccNodeInfo.h_CcNode = h_Tree; + EnqueueNodeInfoToRelevantLst(&p_CcNode->ccTreesLst, + &ccNodeInfo, NULL); + p_CcKeyAndNextEngineParamsTmp[i].shadowAction |= + UPDATE_CC_WITH_TREE; + } + if ((requiredAction & UPDATE_CC_SHADOW_CLEAR) + && !(p_CcNode->shadowAction & UPDATE_CC_SHADOW_CLEAR)) + { + + p_CcNode->shadowAction = 0; + } + + if ((requiredAction & UPDATE_CC_WITH_DELETE_TREE) + && !(p_CcNode->shadowAction + & UPDATE_CC_WITH_DELETE_TREE)) + { + DequeueNodeInfoFromRelevantLst(&p_CcNode->ccTreesLst, + h_Tree, NULL); + p_CcKeyAndNextEngineParamsTmp[i].shadowAction |= + UPDATE_CC_WITH_DELETE_TREE; + } + if (p_CcNode->keyAndNextEngineParams[p_CcNode->numOfKeys].nextEngineParams.nextEngine + != e_FM_PCD_INVALID) + tmp = (uint8_t)(p_CcNode->numOfKeys + 1); + else + tmp = p_CcNode->numOfKeys; + err = SetRequiredAction1(h_FmPcd, requiredAction, + p_CcNode->keyAndNextEngineParams, + p_CcNode->h_AdTable, tmp, h_Tree); + if (err != E_OK) + return err; + if (requiredAction != UPDATE_CC_SHADOW_CLEAR) + p_CcNode->shadowAction |= requiredAction; + } + break; + + case (e_FM_PCD_KG): + if ((requiredAction & UPDATE_NIA_ENQ_WITHOUT_DMA) + && !(p_CcKeyAndNextEngineParamsTmp[i].shadowAction + & UPDATE_NIA_ENQ_WITHOUT_DMA)) + { + physicalSchemeId = + FmPcdKgGetSchemeId( + p_CcKeyAndNextEngineParamsTmp[i].nextEngineParams.params.kgParams.h_DirectScheme); + relativeSchemeId = FmPcdKgGetRelativeSchemeId( + h_FmPcd, physicalSchemeId); + if (relativeSchemeId == FM_PCD_KG_NUM_OF_SCHEMES) + RETURN_ERROR(MAJOR, E_NOT_IN_RANGE, NO_MSG); + if (!FmPcdKgIsSchemeValidSw( + p_CcKeyAndNextEngineParamsTmp[i].nextEngineParams.params.kgParams.h_DirectScheme)) + RETURN_ERROR(MAJOR, E_INVALID_STATE, + ("Invalid direct scheme.")); + if (!KgIsSchemeAlwaysDirect(h_FmPcd, relativeSchemeId)) + RETURN_ERROR( + MAJOR, E_INVALID_STATE, + ("For this action scheme has to be direct.")); + err = + FmPcdKgCcGetSetParams( + h_FmPcd, + p_CcKeyAndNextEngineParamsTmp[i].nextEngineParams.params.kgParams.h_DirectScheme, + requiredAction, 0); + if (err != E_OK) + RETURN_ERROR(MAJOR, err, NO_MSG); + p_CcKeyAndNextEngineParamsTmp[i].shadowAction |= + requiredAction; + } + break; + + case (e_FM_PCD_PLCR): + if ((requiredAction & UPDATE_NIA_ENQ_WITHOUT_DMA) + && !(p_CcKeyAndNextEngineParamsTmp[i].shadowAction + & UPDATE_NIA_ENQ_WITHOUT_DMA)) + { + if (!p_CcKeyAndNextEngineParamsTmp[i].nextEngineParams.params.plcrParams.overrideParams) + RETURN_ERROR( + MAJOR, + E_NOT_SUPPORTED, + ("In this initialization only overrideFqid can be initialized")); + if (!p_CcKeyAndNextEngineParamsTmp[i].nextEngineParams.params.plcrParams.sharedProfile) + RETURN_ERROR( + MAJOR, + E_NOT_SUPPORTED, + ("In this initialization only overrideFqid can be initialized")); + err = + FmPcdPlcrGetAbsoluteIdByProfileParams( + h_FmPcd, + e_FM_PCD_PLCR_SHARED, + NULL, + p_CcKeyAndNextEngineParamsTmp[i].nextEngineParams.params.plcrParams.newRelativeProfileId, + &profileId); + if (err != E_OK) + RETURN_ERROR(MAJOR, err, NO_MSG); + err = FmPcdPlcrCcGetSetParams(h_FmPcd, profileId, + requiredAction); + if (err != E_OK) + RETURN_ERROR(MAJOR, err, NO_MSG); + p_CcKeyAndNextEngineParamsTmp[i].shadowAction |= + requiredAction; + } + break; + + case (e_FM_PCD_DONE): + if ((requiredAction & UPDATE_NIA_ENQ_WITHOUT_DMA) + && !(p_CcKeyAndNextEngineParamsTmp[i].shadowAction + & UPDATE_NIA_ENQ_WITHOUT_DMA)) + { + tmpReg32 = GET_UINT32(p_AdTmp->nia); + if ((tmpReg32 & GET_NIA_BMI_AC_ENQ_FRAME(h_FmPcd)) + != GET_NIA_BMI_AC_ENQ_FRAME(h_FmPcd)) + RETURN_ERROR( + MAJOR, + E_INVALID_STATE, + ("Next engine was previously assigned not as PCD_DONE")); + tmpReg32 |= NIA_BMI_AC_ENQ_FRAME_WITHOUT_DMA; + WRITE_UINT32(p_AdTmp->nia, tmpReg32); + p_CcKeyAndNextEngineParamsTmp[i].shadowAction |= + requiredAction; + } + break; + + default: + break; + } + } + + return E_OK; +} + +static t_Error SetRequiredAction( + t_Handle h_FmPcd, uint32_t requiredAction, + t_FmPcdCcKeyAndNextEngineParams *p_CcKeyAndNextEngineParamsTmp, + t_Handle h_AdTmp, uint16_t numOfEntries, t_Handle h_Tree) +{ + t_Error err = SetRequiredAction1(h_FmPcd, requiredAction, + p_CcKeyAndNextEngineParamsTmp, h_AdTmp, + numOfEntries, h_Tree); + if (err != E_OK) + return err; + return SetRequiredAction1(h_FmPcd, UPDATE_CC_SHADOW_CLEAR, + p_CcKeyAndNextEngineParamsTmp, h_AdTmp, + numOfEntries, h_Tree); +} + +static t_Error ReleaseModifiedDataStructure( + t_Handle h_FmPcd, t_List *h_FmPcdOldPointersLst, + t_List *h_FmPcdNewPointersLst, + t_FmPcdModifyCcKeyAdditionalParams *p_AdditionalParams, + bool useShadowStructs) +{ + t_List *p_Pos; + t_Error err = E_OK; + t_CcNodeInformation ccNodeInfo, *p_CcNodeInformation; + t_Handle h_Muram; + t_FmPcdCcNode *p_FmPcdCcNextNode, *p_FmPcdCcWorkingOnNode; + t_List *p_UpdateLst; + uint32_t intFlags; + + SANITY_CHECK_RETURN_ERROR(h_FmPcd, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_AdditionalParams->h_CurrentNode, + E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(h_FmPcdOldPointersLst, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(h_FmPcdNewPointersLst, E_INVALID_HANDLE); + + /* We don't update subtree of the new node with new tree because it was done in the previous stage */ + if (p_AdditionalParams->h_NodeForAdd) + { + p_FmPcdCcNextNode = (t_FmPcdCcNode*)p_AdditionalParams->h_NodeForAdd; + + if (!p_AdditionalParams->tree) + p_UpdateLst = &p_FmPcdCcNextNode->ccPrevNodesLst; + else + p_UpdateLst = &p_FmPcdCcNextNode->ccTreeIdLst; + + p_CcNodeInformation = FindNodeInfoInReleventLst( + p_UpdateLst, p_AdditionalParams->h_CurrentNode, + p_FmPcdCcNextNode->h_Spinlock); + + if (p_CcNodeInformation) + p_CcNodeInformation->index++; + else + { + memset(&ccNodeInfo, 0, sizeof(t_CcNodeInformation)); + ccNodeInfo.h_CcNode = (t_Handle)p_AdditionalParams->h_CurrentNode; + ccNodeInfo.index = 1; + EnqueueNodeInfoToRelevantLst(p_UpdateLst, &ccNodeInfo, + p_FmPcdCcNextNode->h_Spinlock); + } + if (p_AdditionalParams->h_ManipForAdd) + { + p_CcNodeInformation = FindNodeInfoInReleventLst( + FmPcdManipGetNodeLstPointedOnThisManip( + p_AdditionalParams->h_ManipForAdd), + p_AdditionalParams->h_CurrentNode, + FmPcdManipGetSpinlock(p_AdditionalParams->h_ManipForAdd)); + + if (p_CcNodeInformation) + p_CcNodeInformation->index++; + else + { + memset(&ccNodeInfo, 0, sizeof(t_CcNodeInformation)); + ccNodeInfo.h_CcNode = + (t_Handle)p_AdditionalParams->h_CurrentNode; + ccNodeInfo.index = 1; + EnqueueNodeInfoToRelevantLst( + FmPcdManipGetNodeLstPointedOnThisManip( + p_AdditionalParams->h_ManipForAdd), + &ccNodeInfo, + FmPcdManipGetSpinlock( + p_AdditionalParams->h_ManipForAdd)); + } + } + } + + if (p_AdditionalParams->h_NodeForRmv) + { + p_FmPcdCcNextNode = (t_FmPcdCcNode*)p_AdditionalParams->h_NodeForRmv; + + if (!p_AdditionalParams->tree) + { + p_UpdateLst = &p_FmPcdCcNextNode->ccPrevNodesLst; + p_FmPcdCcWorkingOnNode = + (t_FmPcdCcNode *)(p_AdditionalParams->h_CurrentNode); + + for (p_Pos = LIST_FIRST(&p_FmPcdCcWorkingOnNode->ccTreesLst); + p_Pos != (&p_FmPcdCcWorkingOnNode->ccTreesLst); p_Pos = + LIST_NEXT(p_Pos)) + { + p_CcNodeInformation = CC_NODE_F_OBJECT(p_Pos); + + ASSERT_COND(p_CcNodeInformation->h_CcNode); + + err = + SetRequiredAction( + h_FmPcd, + UPDATE_CC_WITH_DELETE_TREE, + &((t_FmPcdCcNode *)(p_AdditionalParams->h_CurrentNode))->keyAndNextEngineParams[p_AdditionalParams->savedKeyIndex], + PTR_MOVE(((t_FmPcdCcNode *)(p_AdditionalParams->h_CurrentNode))->h_AdTable, p_AdditionalParams->savedKeyIndex*FM_PCD_CC_AD_ENTRY_SIZE), + 1, p_CcNodeInformation->h_CcNode); + } + } + else + { + p_UpdateLst = &p_FmPcdCcNextNode->ccTreeIdLst; + + err = + SetRequiredAction( + h_FmPcd, + UPDATE_CC_WITH_DELETE_TREE, + &((t_FmPcdCcTree *)(p_AdditionalParams->h_CurrentNode))->keyAndNextEngineParams[p_AdditionalParams->savedKeyIndex], + UINT_TO_PTR(((t_FmPcdCcTree *)(p_AdditionalParams->h_CurrentNode))->ccTreeBaseAddr + p_AdditionalParams->savedKeyIndex*FM_PCD_CC_AD_ENTRY_SIZE), + 1, p_AdditionalParams->h_CurrentNode); + } + if (err) + return err; + + /* We remove from the subtree of the removed node tree because it wasn't done in the previous stage + Update ccPrevNodesLst or ccTreeIdLst of the removed node + Update of the node owner */ + p_CcNodeInformation = FindNodeInfoInReleventLst( + p_UpdateLst, p_AdditionalParams->h_CurrentNode, + p_FmPcdCcNextNode->h_Spinlock); + + ASSERT_COND(p_CcNodeInformation); + ASSERT_COND(p_CcNodeInformation->index); + + p_CcNodeInformation->index--; + + if (p_CcNodeInformation->index == 0) + DequeueNodeInfoFromRelevantLst(p_UpdateLst, + p_AdditionalParams->h_CurrentNode, + p_FmPcdCcNextNode->h_Spinlock); + + UpdateNodeOwner(p_FmPcdCcNextNode, FALSE); + + if (p_AdditionalParams->h_ManipForRmv) + { + p_CcNodeInformation = FindNodeInfoInReleventLst( + FmPcdManipGetNodeLstPointedOnThisManip( + p_AdditionalParams->h_ManipForRmv), + p_AdditionalParams->h_CurrentNode, + FmPcdManipGetSpinlock(p_AdditionalParams->h_ManipForRmv)); + + ASSERT_COND(p_CcNodeInformation); + ASSERT_COND(p_CcNodeInformation->index); + + p_CcNodeInformation->index--; + + if (p_CcNodeInformation->index == 0) + DequeueNodeInfoFromRelevantLst( + FmPcdManipGetNodeLstPointedOnThisManip( + p_AdditionalParams->h_ManipForRmv), + p_AdditionalParams->h_CurrentNode, + FmPcdManipGetSpinlock( + p_AdditionalParams->h_ManipForRmv)); + } + } + + if (p_AdditionalParams->h_ManipForRmv) + FmPcdManipUpdateOwner(p_AdditionalParams->h_ManipForRmv, FALSE); + + if (p_AdditionalParams->p_StatsObjForRmv) + PutStatsObj((t_FmPcdCcNode *)(p_AdditionalParams->h_CurrentNode), + p_AdditionalParams->p_StatsObjForRmv); + +#if (DPAA_VERSION >= 11) + if (p_AdditionalParams->h_FrmReplicForRmv) + FrmReplicGroupUpdateOwner(p_AdditionalParams->h_FrmReplicForRmv, + FALSE/* remove */); +#endif /* (DPAA_VERSION >= 11) */ + + if (!useShadowStructs) + { + h_Muram = FmPcdGetMuramHandle(h_FmPcd); + ASSERT_COND(h_Muram); + + if ((p_AdditionalParams->tree && !((t_FmPcd *)h_FmPcd)->p_CcShadow) + || (!p_AdditionalParams->tree + && !((t_FmPcdCcNode *)(p_AdditionalParams->h_CurrentNode))->maxNumOfKeys)) + { + /* We release new AD which was allocated and updated for copy from to actual AD */ + for (p_Pos = LIST_FIRST(h_FmPcdNewPointersLst); + p_Pos != (h_FmPcdNewPointersLst); p_Pos = LIST_NEXT(p_Pos)) + { + + p_CcNodeInformation = CC_NODE_F_OBJECT(p_Pos); + ASSERT_COND(p_CcNodeInformation->h_CcNode); + FM_MURAM_FreeMem(h_Muram, p_CcNodeInformation->h_CcNode); + } + } + + /* Free Old data structure if it has to be freed - new data structure was allocated*/ + if (p_AdditionalParams->p_AdTableOld) + FM_MURAM_FreeMem(h_Muram, p_AdditionalParams->p_AdTableOld); + + if (p_AdditionalParams->p_KeysMatchTableOld) + FM_MURAM_FreeMem(h_Muram, p_AdditionalParams->p_KeysMatchTableOld); + } + + /* Update current modified node with changed fields if it's required*/ + if (!p_AdditionalParams->tree) + { + if (p_AdditionalParams->p_AdTableNew) + ((t_FmPcdCcNode *)(p_AdditionalParams->h_CurrentNode))->h_AdTable = + p_AdditionalParams->p_AdTableNew; + + if (p_AdditionalParams->p_KeysMatchTableNew) + ((t_FmPcdCcNode *)(p_AdditionalParams->h_CurrentNode))->h_KeysMatchTable = + p_AdditionalParams->p_KeysMatchTableNew; + + /* Locking node's spinlock before updating 'keys and next engine' structure, + as it maybe used to retrieve keys statistics */ + intFlags = + XX_LockIntrSpinlock( + ((t_FmPcdCcNode *)(p_AdditionalParams->h_CurrentNode))->h_Spinlock); + + ((t_FmPcdCcNode *)(p_AdditionalParams->h_CurrentNode))->numOfKeys = + p_AdditionalParams->numOfKeys; + + memcpy(((t_FmPcdCcNode *)(p_AdditionalParams->h_CurrentNode))->keyAndNextEngineParams, + &p_AdditionalParams->keyAndNextEngineParams, + sizeof(t_FmPcdCcKeyAndNextEngineParams) * (CC_MAX_NUM_OF_KEYS)); + + XX_UnlockIntrSpinlock( + ((t_FmPcdCcNode *)(p_AdditionalParams->h_CurrentNode))->h_Spinlock, + intFlags); + } + else + { + uint8_t numEntries = + ((t_FmPcdCcTree *)(p_AdditionalParams->h_CurrentNode))->numOfEntries; + ASSERT_COND(numEntries < FM_PCD_MAX_NUM_OF_CC_GROUPS); + memcpy(&((t_FmPcdCcTree *)(p_AdditionalParams->h_CurrentNode))->keyAndNextEngineParams, + &p_AdditionalParams->keyAndNextEngineParams, + sizeof(t_FmPcdCcKeyAndNextEngineParams) * numEntries); + } + + ReleaseLst(h_FmPcdOldPointersLst); + ReleaseLst(h_FmPcdNewPointersLst); + + XX_Free(p_AdditionalParams); + + return E_OK; +} + +static t_Handle BuildNewAd( + t_Handle h_Ad, + t_FmPcdModifyCcKeyAdditionalParams *p_FmPcdModifyCcKeyAdditionalParams, + t_FmPcdCcNode *p_CcNode, + t_FmPcdCcNextEngineParams *p_FmPcdCcNextEngineParams) +{ + t_FmPcdCcNode *p_FmPcdCcNodeTmp; + t_Handle h_OrigAd = NULL; + + p_FmPcdCcNodeTmp = (t_FmPcdCcNode*)XX_Malloc(sizeof(t_FmPcdCcNode)); + if (!p_FmPcdCcNodeTmp) + { + REPORT_ERROR(MAJOR, E_NO_MEMORY, ("p_FmPcdCcNodeTmp")); + return NULL; + } + memset(p_FmPcdCcNodeTmp, 0, sizeof(t_FmPcdCcNode)); + + p_FmPcdCcNodeTmp->numOfKeys = p_FmPcdModifyCcKeyAdditionalParams->numOfKeys; + p_FmPcdCcNodeTmp->h_KeysMatchTable = + p_FmPcdModifyCcKeyAdditionalParams->p_KeysMatchTableNew; + p_FmPcdCcNodeTmp->h_AdTable = + p_FmPcdModifyCcKeyAdditionalParams->p_AdTableNew; + + p_FmPcdCcNodeTmp->lclMask = p_CcNode->lclMask; + p_FmPcdCcNodeTmp->parseCode = p_CcNode->parseCode; + p_FmPcdCcNodeTmp->offset = p_CcNode->offset; + p_FmPcdCcNodeTmp->prsArrayOffset = p_CcNode->prsArrayOffset; + p_FmPcdCcNodeTmp->ctrlFlow = p_CcNode->ctrlFlow; + p_FmPcdCcNodeTmp->ccKeySizeAccExtraction = p_CcNode->ccKeySizeAccExtraction; + p_FmPcdCcNodeTmp->sizeOfExtraction = p_CcNode->sizeOfExtraction; + p_FmPcdCcNodeTmp->glblMaskSize = p_CcNode->glblMaskSize; + p_FmPcdCcNodeTmp->p_GlblMask = p_CcNode->p_GlblMask; + + if (p_FmPcdCcNextEngineParams->nextEngine == e_FM_PCD_CC) + { + if (p_FmPcdCcNextEngineParams->h_Manip) + { + h_OrigAd = p_CcNode->h_Ad; + if (AllocAndFillAdForContLookupManip( + p_FmPcdCcNextEngineParams->params.ccParams.h_CcNode) + != E_OK) + { + REPORT_ERROR(MAJOR, E_INVALID_STATE, NO_MSG); + XX_Free(p_FmPcdCcNodeTmp); + return NULL; + } + } + FillAdOfTypeContLookup(h_Ad, NULL, p_CcNode->h_FmPcd, p_FmPcdCcNodeTmp, + h_OrigAd ? NULL : p_FmPcdCcNextEngineParams->h_Manip, NULL); + } + +#if (DPAA_VERSION >= 11) + if ((p_FmPcdCcNextEngineParams->nextEngine == e_FM_PCD_FR) + && (p_FmPcdCcNextEngineParams->params.frParams.h_FrmReplic)) + { + FillAdOfTypeContLookup( + h_Ad, NULL, p_CcNode->h_FmPcd, p_FmPcdCcNodeTmp, + p_FmPcdCcNextEngineParams->h_Manip, + p_FmPcdCcNextEngineParams->params.frParams.h_FrmReplic); + } +#endif /* (DPAA_VERSION >= 11) */ + + XX_Free(p_FmPcdCcNodeTmp); + + return E_OK; +} + +static t_Error DynamicChangeHc( + t_Handle h_FmPcd, t_List *h_OldPointersLst, t_List *h_NewPointersLst, + t_FmPcdModifyCcKeyAdditionalParams *p_AdditionalParams, + bool useShadowStructs) +{ + t_List *p_PosOld, *p_PosNew; + uint32_t oldAdAddrOffset, newAdAddrOffset; + uint16_t i = 0; + t_Error err = E_OK; + uint8_t numOfModifiedPtr; + + ASSERT_COND(h_FmPcd); + ASSERT_COND(h_OldPointersLst); + ASSERT_COND(h_NewPointersLst); + + numOfModifiedPtr = (uint8_t)LIST_NumOfObjs(h_OldPointersLst); + + if (numOfModifiedPtr) + { + p_PosNew = LIST_FIRST(h_NewPointersLst); + p_PosOld = LIST_FIRST(h_OldPointersLst); + + /* Retrieve address of new AD */ + newAdAddrOffset = FmPcdCcGetNodeAddrOffsetFromNodeInfo(h_FmPcd, + p_PosNew); + if (newAdAddrOffset == (uint32_t)ILLEGAL_BASE) + { + ReleaseModifiedDataStructure(h_FmPcd, h_OldPointersLst, + h_NewPointersLst, + p_AdditionalParams, useShadowStructs); + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("New AD address")); + } + + for (i = 0; i < numOfModifiedPtr; i++) + { + /* Retrieve address of current AD */ + oldAdAddrOffset = FmPcdCcGetNodeAddrOffsetFromNodeInfo(h_FmPcd, + p_PosOld); + if (oldAdAddrOffset == (uint32_t)ILLEGAL_BASE) + { + ReleaseModifiedDataStructure(h_FmPcd, h_OldPointersLst, + h_NewPointersLst, + p_AdditionalParams, + useShadowStructs); + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("Old AD address")); + } + + /* Invoke host command to copy from new AD to old AD */ + err = FmHcPcdCcDoDynamicChange(((t_FmPcd *)h_FmPcd)->h_Hc, + oldAdAddrOffset, newAdAddrOffset); + if (err) + { + ReleaseModifiedDataStructure(h_FmPcd, h_OldPointersLst, + h_NewPointersLst, + p_AdditionalParams, + useShadowStructs); + RETURN_ERROR( + MAJOR, + err, + ("For part of nodes changes are done - situation is danger")); + } + + p_PosOld = LIST_NEXT(p_PosOld); + } + } + return E_OK; +} + +static t_Error DoDynamicChange( + t_Handle h_FmPcd, t_List *h_OldPointersLst, t_List *h_NewPointersLst, + t_FmPcdModifyCcKeyAdditionalParams *p_AdditionalParams, + bool useShadowStructs) +{ + t_FmPcdCcNode *p_CcNode = + (t_FmPcdCcNode *)(p_AdditionalParams->h_CurrentNode); + t_List *p_PosNew; + t_CcNodeInformation *p_CcNodeInfo; + t_FmPcdCcNextEngineParams nextEngineParams; + t_Handle h_Ad; + uint32_t keySize; + t_Error err = E_OK; + uint8_t numOfModifiedPtr; + + ASSERT_COND(h_FmPcd); + + memset(&nextEngineParams, 0, sizeof(t_FmPcdCcNextEngineParams)); + + numOfModifiedPtr = (uint8_t)LIST_NumOfObjs(h_OldPointersLst); + + if (numOfModifiedPtr) + { + + p_PosNew = LIST_FIRST(h_NewPointersLst); + + /* Invoke host-command to copy from the new Ad to existing Ads */ + err = DynamicChangeHc(h_FmPcd, h_OldPointersLst, h_NewPointersLst, + p_AdditionalParams, useShadowStructs); + if (err) + RETURN_ERROR(MAJOR, err, NO_MSG); + + if (useShadowStructs) + { + /* When the host-command above has ended, the old structures are 'free'and we can update + them by copying from the new shadow structures. */ + if (p_CcNode->lclMask) + keySize = (uint32_t)(2 * p_CcNode->ccKeySizeAccExtraction); + else + keySize = p_CcNode->ccKeySizeAccExtraction; + + MemCpy8(p_AdditionalParams->p_KeysMatchTableOld, + p_AdditionalParams->p_KeysMatchTableNew, + p_CcNode->maxNumOfKeys * keySize * sizeof(uint8_t)); + + MemCpy8( + p_AdditionalParams->p_AdTableOld, + p_AdditionalParams->p_AdTableNew, + (uint32_t)((p_CcNode->maxNumOfKeys + 1) + * FM_PCD_CC_AD_ENTRY_SIZE)); + + /* Retrieve the address of the allocated Ad */ + p_CcNodeInfo = CC_NODE_F_OBJECT(p_PosNew); + h_Ad = p_CcNodeInfo->h_CcNode; + + /* Build a new Ad that holds the old (now updated) structures */ + p_AdditionalParams->p_KeysMatchTableNew = + p_AdditionalParams->p_KeysMatchTableOld; + p_AdditionalParams->p_AdTableNew = p_AdditionalParams->p_AdTableOld; + + nextEngineParams.nextEngine = e_FM_PCD_CC; + nextEngineParams.params.ccParams.h_CcNode = (t_Handle)p_CcNode; + + BuildNewAd(h_Ad, p_AdditionalParams, p_CcNode, &nextEngineParams); + + /* HC to copy from the new Ad (old updated structures) to current Ad (uses shadow structures) */ + err = DynamicChangeHc(h_FmPcd, h_OldPointersLst, h_NewPointersLst, + p_AdditionalParams, useShadowStructs); + if (err) + RETURN_ERROR(MAJOR, err, NO_MSG); + } + } + + err = ReleaseModifiedDataStructure(h_FmPcd, h_OldPointersLst, + h_NewPointersLst, + p_AdditionalParams, useShadowStructs); + if (err) + RETURN_ERROR(MAJOR, err, NO_MSG); + + return E_OK; +} + +#ifdef FM_CAPWAP_SUPPORT +static bool IsCapwapApplSpecific(t_Handle h_Node) +{ + t_FmPcdCcNode *p_CcNode = (t_FmPcdCcNode *)h_Node; + bool isManipForCapwapApplSpecificBuild = FALSE; + int i = 0; + + ASSERT_COND(h_Node); + /* assumption that this function called only for INDEXED_FLOW_ID - so no miss*/ + for (i = 0; i < p_CcNode->numOfKeys; i++) + { + if ( p_CcNode->keyAndNextEngineParams[i].nextEngineParams.h_Manip && + FmPcdManipIsCapwapApplSpecific(p_CcNode->keyAndNextEngineParams[i].nextEngineParams.h_Manip)) + { + isManipForCapwapApplSpecificBuild = TRUE; + break; + } + } + return isManipForCapwapApplSpecificBuild; + +} +#endif /* FM_CAPWAP_SUPPORT */ + +static t_Error CcUpdateParam( + t_Handle h_FmPcd, t_Handle h_PcdParams, t_Handle h_FmPort, + t_FmPcdCcKeyAndNextEngineParams *p_CcKeyAndNextEngineParams, + uint16_t numOfEntries, t_Handle h_Ad, bool validate, uint16_t level, + t_Handle h_FmTree, bool modify) +{ + t_FmPcdCcNode *p_CcNode; + t_Error err; + uint16_t tmp = 0; + int i = 0; + t_FmPcdCcTree *p_CcTree = (t_FmPcdCcTree *)h_FmTree; + + level++; + + if (p_CcTree->h_IpReassemblyManip) + { + err = FmPcdManipUpdate(h_FmPcd, h_PcdParams, h_FmPort, + p_CcTree->h_IpReassemblyManip, NULL, validate, + level, h_FmTree, modify); + if (err) + RETURN_ERROR(MAJOR, err, NO_MSG); + } + + if (p_CcTree->h_CapwapReassemblyManip) + { + err = FmPcdManipUpdate(h_FmPcd, h_PcdParams, h_FmPort, + p_CcTree->h_CapwapReassemblyManip, NULL, validate, + level, h_FmTree, modify); + if (err) + RETURN_ERROR(MAJOR, err, NO_MSG); + } + + if (numOfEntries) + { + for (i = 0; i < numOfEntries; i++) + { + if (i == 0) + h_Ad = PTR_MOVE(h_Ad, i*FM_PCD_CC_AD_ENTRY_SIZE); + else + h_Ad = PTR_MOVE(h_Ad, FM_PCD_CC_AD_ENTRY_SIZE); + + if (p_CcKeyAndNextEngineParams[i].nextEngineParams.nextEngine + == e_FM_PCD_CC) + { + p_CcNode = + p_CcKeyAndNextEngineParams[i].nextEngineParams.params.ccParams.h_CcNode; + ASSERT_COND(p_CcNode); + + if (p_CcKeyAndNextEngineParams[i].nextEngineParams.h_Manip) + { + err = + FmPcdManipUpdate( + h_FmPcd, + NULL, + h_FmPort, + p_CcKeyAndNextEngineParams[i].nextEngineParams.h_Manip, + h_Ad, validate, level, h_FmTree, modify); + if (err) + RETURN_ERROR(MAJOR, err, NO_MSG); + } + + if (p_CcNode->keyAndNextEngineParams[p_CcNode->numOfKeys].nextEngineParams.nextEngine + != e_FM_PCD_INVALID) + tmp = (uint8_t)(p_CcNode->numOfKeys + 1); + else + tmp = p_CcNode->numOfKeys; + + err = CcUpdateParam(h_FmPcd, h_PcdParams, h_FmPort, + p_CcNode->keyAndNextEngineParams, tmp, + p_CcNode->h_AdTable, validate, level, + h_FmTree, modify); + if (err) + RETURN_ERROR(MAJOR, err, NO_MSG); + } + else + { + if (p_CcKeyAndNextEngineParams[i].nextEngineParams.h_Manip) + { + err = + FmPcdManipUpdate( + h_FmPcd, + NULL, + h_FmPort, + p_CcKeyAndNextEngineParams[i].nextEngineParams.h_Manip, + h_Ad, validate, level, h_FmTree, modify); + if (err) + RETURN_ERROR(MAJOR, err, NO_MSG); + } + } + } + } + + return E_OK; +} + +static ccPrivateInfo_t IcDefineCode(t_FmPcdCcNodeParams *p_CcNodeParam) +{ + switch (p_CcNodeParam->extractCcParams.extractNonHdr.action) + { + case (e_FM_PCD_ACTION_EXACT_MATCH): + switch (p_CcNodeParam->extractCcParams.extractNonHdr.src) + { + case (e_FM_PCD_EXTRACT_FROM_KEY): + return CC_PRIVATE_INFO_IC_KEY_EXACT_MATCH; + case (e_FM_PCD_EXTRACT_FROM_HASH): + return CC_PRIVATE_INFO_IC_HASH_EXACT_MATCH; + default: + return CC_PRIVATE_INFO_NONE; + } + + case (e_FM_PCD_ACTION_INDEXED_LOOKUP): + switch (p_CcNodeParam->extractCcParams.extractNonHdr.src) + { + case (e_FM_PCD_EXTRACT_FROM_HASH): + return CC_PRIVATE_INFO_IC_HASH_INDEX_LOOKUP; + case (e_FM_PCD_EXTRACT_FROM_FLOW_ID): + return CC_PRIVATE_INFO_IC_DEQ_FQID_INDEX_LOOKUP; + default: + return CC_PRIVATE_INFO_NONE; + } + + default: + break; + } + + return CC_PRIVATE_INFO_NONE; +} + +static t_CcNodeInformation * DequeueAdditionalInfoFromRelevantLst( + t_List *p_List) +{ + t_CcNodeInformation *p_CcNodeInfo = NULL; + + if (!LIST_IsEmpty(p_List)) + { + p_CcNodeInfo = CC_NODE_F_OBJECT(p_List->p_Next); + LIST_DelAndInit(&p_CcNodeInfo->node); + } + + return p_CcNodeInfo; +} + +void ReleaseLst(t_List *p_List) +{ + t_CcNodeInformation *p_CcNodeInfo = NULL; + + if (!LIST_IsEmpty(p_List)) + { + p_CcNodeInfo = DequeueAdditionalInfoFromRelevantLst(p_List); + while (p_CcNodeInfo) + { + XX_Free(p_CcNodeInfo); + p_CcNodeInfo = DequeueAdditionalInfoFromRelevantLst(p_List); + } + } + + LIST_Del(p_List); +} + +static void DeleteNode(t_FmPcdCcNode *p_CcNode) +{ + uint32_t i; + + if (!p_CcNode) + return; + + if (p_CcNode->p_GlblMask) + { + XX_Free(p_CcNode->p_GlblMask); + p_CcNode->p_GlblMask = NULL; + } + + if (p_CcNode->h_KeysMatchTable) + { + FM_MURAM_FreeMem(FmPcdGetMuramHandle(p_CcNode->h_FmPcd), + p_CcNode->h_KeysMatchTable); + p_CcNode->h_KeysMatchTable = NULL; + } + + if (p_CcNode->h_AdTable) + { + FM_MURAM_FreeMem(FmPcdGetMuramHandle(p_CcNode->h_FmPcd), + p_CcNode->h_AdTable); + p_CcNode->h_AdTable = NULL; + } + + if (p_CcNode->h_Ad) + { + FM_MURAM_FreeMem(FmPcdGetMuramHandle(p_CcNode->h_FmPcd), + p_CcNode->h_Ad); + p_CcNode->h_Ad = NULL; + p_CcNode->h_TmpAd = NULL; + } + + if (p_CcNode->h_StatsFLRs) + { + FM_MURAM_FreeMem(FmPcdGetMuramHandle(p_CcNode->h_FmPcd), + p_CcNode->h_StatsFLRs); + p_CcNode->h_StatsFLRs = NULL; + } + + if (p_CcNode->h_Spinlock) + { + XX_FreeSpinlock(p_CcNode->h_Spinlock); + p_CcNode->h_Spinlock = NULL; + } + + /* Restore the original counters pointer instead of the mutual pointer (mutual to all hash buckets) */ + if (p_CcNode->isHashBucket + && (p_CcNode->statisticsMode != e_FM_PCD_CC_STATS_MODE_NONE)) + p_CcNode->keyAndNextEngineParams[p_CcNode->numOfKeys].p_StatsObj->h_StatsCounters = + p_CcNode->h_PrivMissStatsCounters; + + /* Releasing all currently used statistics objects, including 'miss' entry */ + for (i = 0; i < p_CcNode->numOfKeys + 1; i++) + if (p_CcNode->keyAndNextEngineParams[i].p_StatsObj) + PutStatsObj(p_CcNode, + p_CcNode->keyAndNextEngineParams[i].p_StatsObj); + + if (!LIST_IsEmpty(&p_CcNode->availableStatsLst)) + { + t_Handle h_FmMuram = FmPcdGetMuramHandle(p_CcNode->h_FmPcd); + ASSERT_COND(h_FmMuram); + + FreeStatObjects(&p_CcNode->availableStatsLst, h_FmMuram); + } + + LIST_Del(&p_CcNode->availableStatsLst); + + ReleaseLst(&p_CcNode->availableStatsLst); + ReleaseLst(&p_CcNode->ccPrevNodesLst); + ReleaseLst(&p_CcNode->ccTreeIdLst); + ReleaseLst(&p_CcNode->ccTreesLst); + + XX_Free(p_CcNode); +} + +static void DeleteTree(t_FmPcdCcTree *p_FmPcdTree, t_FmPcd *p_FmPcd) +{ + if (p_FmPcdTree) + { + if (p_FmPcdTree->ccTreeBaseAddr) + { + FM_MURAM_FreeMem(FmPcdGetMuramHandle(p_FmPcd), + UINT_TO_PTR(p_FmPcdTree->ccTreeBaseAddr)); + p_FmPcdTree->ccTreeBaseAddr = 0; + } + + ReleaseLst(&p_FmPcdTree->fmPortsLst); + + XX_Free(p_FmPcdTree); + } +} + +static void GetCcExtractKeySize(uint8_t parseCodeRealSize, + uint8_t *parseCodeCcSize) +{ + if ((parseCodeRealSize > 0) && (parseCodeRealSize < 2)) + *parseCodeCcSize = 1; + else + if (parseCodeRealSize == 2) + *parseCodeCcSize = 2; + else + if ((parseCodeRealSize > 2) && (parseCodeRealSize <= 4)) + *parseCodeCcSize = 4; + else + if ((parseCodeRealSize > 4) && (parseCodeRealSize <= 8)) + *parseCodeCcSize = 8; + else + if ((parseCodeRealSize > 8) && (parseCodeRealSize <= 16)) + *parseCodeCcSize = 16; + else + if ((parseCodeRealSize > 16) + && (parseCodeRealSize <= 24)) + *parseCodeCcSize = 24; + else + if ((parseCodeRealSize > 24) + && (parseCodeRealSize <= 32)) + *parseCodeCcSize = 32; + else + if ((parseCodeRealSize > 32) + && (parseCodeRealSize <= 40)) + *parseCodeCcSize = 40; + else + if ((parseCodeRealSize > 40) + && (parseCodeRealSize <= 48)) + *parseCodeCcSize = 48; + else + if ((parseCodeRealSize > 48) + && (parseCodeRealSize <= 56)) + *parseCodeCcSize = 56; + else + *parseCodeCcSize = 0; +} + +static void GetSizeHeaderField(e_NetHeaderType hdr, t_FmPcdFields field, + uint8_t *parseCodeRealSize) +{ + switch (hdr) + { + case (HEADER_TYPE_ETH): + switch (field.eth) + { + case (NET_HEADER_FIELD_ETH_DA): + *parseCodeRealSize = 6; + break; + + case (NET_HEADER_FIELD_ETH_SA): + *parseCodeRealSize = 6; + break; + + case (NET_HEADER_FIELD_ETH_TYPE): + *parseCodeRealSize = 2; + break; + + default: + REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Extraction not supported1")); + *parseCodeRealSize = CC_SIZE_ILLEGAL; + break; + } + break; + + case (HEADER_TYPE_PPPoE): + switch (field.pppoe) + { + case (NET_HEADER_FIELD_PPPoE_PID): + *parseCodeRealSize = 2; + break; + + default: + REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Extraction not supported1")); + *parseCodeRealSize = CC_SIZE_ILLEGAL; + break; + } + break; + + case (HEADER_TYPE_VLAN): + switch (field.vlan) + { + case (NET_HEADER_FIELD_VLAN_TCI): + *parseCodeRealSize = 2; + break; + + default: + REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Extraction not supported2")); + *parseCodeRealSize = CC_SIZE_ILLEGAL; + break; + } + break; + + case (HEADER_TYPE_MPLS): + switch (field.mpls) + { + case (NET_HEADER_FIELD_MPLS_LABEL_STACK): + *parseCodeRealSize = 4; + break; + + default: + REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Extraction not supported3")); + *parseCodeRealSize = CC_SIZE_ILLEGAL; + break; + } + break; + + case (HEADER_TYPE_IPv4): + switch (field.ipv4) + { + case (NET_HEADER_FIELD_IPv4_DST_IP): + case (NET_HEADER_FIELD_IPv4_SRC_IP): + *parseCodeRealSize = 4; + break; + + case (NET_HEADER_FIELD_IPv4_TOS): + case (NET_HEADER_FIELD_IPv4_PROTO): + *parseCodeRealSize = 1; + break; + + case (NET_HEADER_FIELD_IPv4_DST_IP + | NET_HEADER_FIELD_IPv4_SRC_IP): + *parseCodeRealSize = 8; + break; + + case (NET_HEADER_FIELD_IPv4_TTL): + *parseCodeRealSize = 1; + break; + + default: + REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Extraction not supported4")); + *parseCodeRealSize = CC_SIZE_ILLEGAL; + break; + } + break; + + case (HEADER_TYPE_IPv6): + switch (field.ipv6) + { + case (NET_HEADER_FIELD_IPv6_VER | NET_HEADER_FIELD_IPv6_FL + | NET_HEADER_FIELD_IPv6_TC): + *parseCodeRealSize = 4; + break; + + case (NET_HEADER_FIELD_IPv6_NEXT_HDR): + case (NET_HEADER_FIELD_IPv6_HOP_LIMIT): + *parseCodeRealSize = 1; + break; + + case (NET_HEADER_FIELD_IPv6_DST_IP): + case (NET_HEADER_FIELD_IPv6_SRC_IP): + *parseCodeRealSize = 16; + break; + + default: + REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Extraction not supported5")); + *parseCodeRealSize = CC_SIZE_ILLEGAL; + break; + } + break; + + case (HEADER_TYPE_IP): + switch (field.ip) + { + case (NET_HEADER_FIELD_IP_DSCP): + case (NET_HEADER_FIELD_IP_PROTO): + *parseCodeRealSize = 1; + break; + + default: + REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Extraction not supported5")); + *parseCodeRealSize = CC_SIZE_ILLEGAL; + break; + } + break; + + case (HEADER_TYPE_GRE): + switch (field.gre) + { + case (NET_HEADER_FIELD_GRE_TYPE): + *parseCodeRealSize = 2; + break; + + default: + REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Extraction not supported6")); + *parseCodeRealSize = CC_SIZE_ILLEGAL; + break; + } + break; + + case (HEADER_TYPE_MINENCAP): + switch (field.minencap) + { + case (NET_HEADER_FIELD_MINENCAP_TYPE): + *parseCodeRealSize = 1; + break; + + case (NET_HEADER_FIELD_MINENCAP_DST_IP): + case (NET_HEADER_FIELD_MINENCAP_SRC_IP): + *parseCodeRealSize = 4; + break; + + case (NET_HEADER_FIELD_MINENCAP_SRC_IP + | NET_HEADER_FIELD_MINENCAP_DST_IP): + *parseCodeRealSize = 8; + break; + + default: + REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Extraction not supported7")); + *parseCodeRealSize = CC_SIZE_ILLEGAL; + break; + } + break; + + case (HEADER_TYPE_TCP): + switch (field.tcp) + { + case (NET_HEADER_FIELD_TCP_PORT_SRC): + case (NET_HEADER_FIELD_TCP_PORT_DST): + *parseCodeRealSize = 2; + break; + + case (NET_HEADER_FIELD_TCP_PORT_SRC + | NET_HEADER_FIELD_TCP_PORT_DST): + *parseCodeRealSize = 4; + break; + + default: + REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Extraction not supported8")); + *parseCodeRealSize = CC_SIZE_ILLEGAL; + break; + } + break; + + case (HEADER_TYPE_UDP): + switch (field.udp) + { + case (NET_HEADER_FIELD_UDP_PORT_SRC): + case (NET_HEADER_FIELD_UDP_PORT_DST): + *parseCodeRealSize = 2; + break; + + case (NET_HEADER_FIELD_UDP_PORT_SRC + | NET_HEADER_FIELD_UDP_PORT_DST): + *parseCodeRealSize = 4; + break; + + default: + REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Extraction not supported9")); + *parseCodeRealSize = CC_SIZE_ILLEGAL; + break; + } + break; + + default: + REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Extraction not supported10")); + *parseCodeRealSize = CC_SIZE_ILLEGAL; + break; + } +} + +t_Error ValidateNextEngineParams( + t_Handle h_FmPcd, t_FmPcdCcNextEngineParams *p_FmPcdCcNextEngineParams, + e_FmPcdCcStatsMode statsMode) +{ + uint16_t absoluteProfileId; + t_Error err = E_OK; + uint8_t relativeSchemeId; + + if ((statsMode == e_FM_PCD_CC_STATS_MODE_NONE) + && (p_FmPcdCcNextEngineParams->statisticsEn)) + RETURN_ERROR( + MAJOR, + E_CONFLICT, + ("Statistics are requested for a key, but statistics mode was set" + "to 'NONE' upon initialization")); + + switch (p_FmPcdCcNextEngineParams->nextEngine) + { + case (e_FM_PCD_INVALID): + err = E_NOT_SUPPORTED; + break; + + case (e_FM_PCD_DONE): + if ((p_FmPcdCcNextEngineParams->params.enqueueParams.action + == e_FM_PCD_ENQ_FRAME) + && p_FmPcdCcNextEngineParams->params.enqueueParams.overrideFqid) + { + if (!p_FmPcdCcNextEngineParams->params.enqueueParams.newFqid) + RETURN_ERROR( + MAJOR, + E_CONFLICT, + ("When overrideFqid is set, newFqid must not be zero")); + if (p_FmPcdCcNextEngineParams->params.enqueueParams.newFqid + & ~0x00FFFFFF) + RETURN_ERROR( + MAJOR, E_INVALID_VALUE, + ("fqidForCtrlFlow must be between 1 and 2^24-1")); + } + break; + + case (e_FM_PCD_KG): + relativeSchemeId = + FmPcdKgGetRelativeSchemeId( + h_FmPcd, + FmPcdKgGetSchemeId( + p_FmPcdCcNextEngineParams->params.kgParams.h_DirectScheme)); + if (relativeSchemeId == FM_PCD_KG_NUM_OF_SCHEMES) + RETURN_ERROR(MAJOR, E_NOT_IN_RANGE, NO_MSG); + if (!FmPcdKgIsSchemeValidSw( + p_FmPcdCcNextEngineParams->params.kgParams.h_DirectScheme)) + RETURN_ERROR(MAJOR, E_INVALID_STATE, + ("not valid schemeIndex in KG next engine param")); + if (!KgIsSchemeAlwaysDirect(h_FmPcd, relativeSchemeId)) + RETURN_ERROR( + MAJOR, + E_INVALID_STATE, + ("CC Node may point only to a scheme that is always direct.")); + break; + + case (e_FM_PCD_PLCR): + if (p_FmPcdCcNextEngineParams->params.plcrParams.overrideParams) + { + /* if private policer profile, it may be uninitialized yet, therefore no checks are done at this stage */ + if (p_FmPcdCcNextEngineParams->params.plcrParams.sharedProfile) + { + err = + FmPcdPlcrGetAbsoluteIdByProfileParams( + h_FmPcd, + e_FM_PCD_PLCR_SHARED, + NULL, + p_FmPcdCcNextEngineParams->params.plcrParams.newRelativeProfileId, + &absoluteProfileId); + if (err) + RETURN_ERROR(MAJOR, err, + ("Shared profile offset is out of range")); + if (!FmPcdPlcrIsProfileValid(h_FmPcd, absoluteProfileId)) + RETURN_ERROR(MAJOR, E_INVALID_STATE, + ("Invalid profile")); + } + } + break; + + case (e_FM_PCD_HASH): + p_FmPcdCcNextEngineParams->nextEngine = e_FM_PCD_CC; + /* fall through */ + case (e_FM_PCD_CC): + if (!p_FmPcdCcNextEngineParams->params.ccParams.h_CcNode) + RETURN_ERROR(MAJOR, E_NULL_POINTER, + ("handler to next Node is NULL")); + break; + +#if (DPAA_VERSION >= 11) + case (e_FM_PCD_FR): + if (!p_FmPcdCcNextEngineParams->params.frParams.h_FrmReplic) + err = E_NOT_SUPPORTED; + break; +#endif /* (DPAA_VERSION >= 11) */ + + default: + RETURN_ERROR(MAJOR, E_INVALID_STATE, + ("Next engine is not correct")); + } + + + return err; +} + +static uint8_t GetGenParseCode(e_FmPcdExtractFrom src, + uint32_t offset, bool glblMask, + uint8_t *parseArrayOffset, bool fromIc, + ccPrivateInfo_t icCode) +{ + if (!fromIc) + { + switch (src) + { + case (e_FM_PCD_EXTRACT_FROM_FRAME_START): + if (glblMask) + return CC_PC_GENERIC_WITH_MASK; + else + return CC_PC_GENERIC_WITHOUT_MASK; + + case (e_FM_PCD_EXTRACT_FROM_CURR_END_OF_PARSE): + *parseArrayOffset = CC_PC_PR_NEXT_HEADER_OFFSET; + if (offset) + return CC_PR_OFFSET; + else + return CC_PR_WITHOUT_OFFSET; + + default: + REPORT_ERROR(MAJOR, E_INVALID_VALUE, ("Illegal 'extract from' src")); + return CC_PC_ILLEGAL; + } + } + else + { + switch (icCode) + { + case (CC_PRIVATE_INFO_IC_KEY_EXACT_MATCH): + *parseArrayOffset = 0x50; + return CC_PC_GENERIC_IC_GMASK; + + case (CC_PRIVATE_INFO_IC_HASH_EXACT_MATCH): + *parseArrayOffset = 0x48; + return CC_PC_GENERIC_IC_GMASK; + + case (CC_PRIVATE_INFO_IC_HASH_INDEX_LOOKUP): + *parseArrayOffset = 0x48; + return CC_PC_GENERIC_IC_HASH_INDEXED; + + case (CC_PRIVATE_INFO_IC_DEQ_FQID_INDEX_LOOKUP): + *parseArrayOffset = 0x16; + return CC_PC_GENERIC_IC_HASH_INDEXED; + + default: + REPORT_ERROR(MAJOR, E_INVALID_VALUE, ("Illegal 'extract from' src")); + break; + } + } + + return CC_PC_ILLEGAL; +} + +static uint8_t GetFullFieldParseCode(e_NetHeaderType hdr, e_FmPcdHdrIndex index, + t_FmPcdFields field) +{ + switch (hdr) + { + case (HEADER_TYPE_NONE): + ASSERT_COND(FALSE); + return CC_PC_ILLEGAL; + + case (HEADER_TYPE_ETH): + switch (field.eth) + { + case (NET_HEADER_FIELD_ETH_DA): + return CC_PC_FF_MACDST; + case (NET_HEADER_FIELD_ETH_SA): + return CC_PC_FF_MACSRC; + case (NET_HEADER_FIELD_ETH_TYPE): + return CC_PC_FF_ETYPE; + default: + REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Extraction not supported")); + return CC_PC_ILLEGAL; + } + + case (HEADER_TYPE_VLAN): + switch (field.vlan) + { + case (NET_HEADER_FIELD_VLAN_TCI): + if ((index == e_FM_PCD_HDR_INDEX_NONE) + || (index == e_FM_PCD_HDR_INDEX_1)) + return CC_PC_FF_TCI1; + if (index == e_FM_PCD_HDR_INDEX_LAST) + return CC_PC_FF_TCI2; + REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Extraction not supported")); + return CC_PC_ILLEGAL; + default: + REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Extraction not supported")); + return CC_PC_ILLEGAL; + } + + case (HEADER_TYPE_MPLS): + switch (field.mpls) + { + case (NET_HEADER_FIELD_MPLS_LABEL_STACK): + if ((index == e_FM_PCD_HDR_INDEX_NONE) + || (index == e_FM_PCD_HDR_INDEX_1)) + return CC_PC_FF_MPLS1; + if (index == e_FM_PCD_HDR_INDEX_LAST) + return CC_PC_FF_MPLS_LAST; + REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Illegal MPLS index")); + return CC_PC_ILLEGAL; + default: + REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Extraction not supported")); + return CC_PC_ILLEGAL; + } + + case (HEADER_TYPE_IPv4): + switch (field.ipv4) + { + case (NET_HEADER_FIELD_IPv4_DST_IP): + if ((index == e_FM_PCD_HDR_INDEX_NONE) + || (index == e_FM_PCD_HDR_INDEX_1)) + return CC_PC_FF_IPV4DST1; + if (index == e_FM_PCD_HDR_INDEX_2) + return CC_PC_FF_IPV4DST2; + REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Illegal IPv4 index")); + return CC_PC_ILLEGAL; + case (NET_HEADER_FIELD_IPv4_TOS): + if ((index == e_FM_PCD_HDR_INDEX_NONE) + || (index == e_FM_PCD_HDR_INDEX_1)) + return CC_PC_FF_IPV4IPTOS_TC1; + if (index == e_FM_PCD_HDR_INDEX_2) + return CC_PC_FF_IPV4IPTOS_TC2; + REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Illegal IPv4 index")); + return CC_PC_ILLEGAL; + case (NET_HEADER_FIELD_IPv4_PROTO): + if ((index == e_FM_PCD_HDR_INDEX_NONE) + || (index == e_FM_PCD_HDR_INDEX_1)) + return CC_PC_FF_IPV4PTYPE1; + if (index == e_FM_PCD_HDR_INDEX_2) + return CC_PC_FF_IPV4PTYPE2; + REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Illegal IPv4 index")); + return CC_PC_ILLEGAL; + case (NET_HEADER_FIELD_IPv4_SRC_IP): + if ((index == e_FM_PCD_HDR_INDEX_NONE) + || (index == e_FM_PCD_HDR_INDEX_1)) + return CC_PC_FF_IPV4SRC1; + if (index == e_FM_PCD_HDR_INDEX_2) + return CC_PC_FF_IPV4SRC2; + REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Illegal IPv4 index")); + return CC_PC_ILLEGAL; + case (NET_HEADER_FIELD_IPv4_SRC_IP + | NET_HEADER_FIELD_IPv4_DST_IP): + if ((index == e_FM_PCD_HDR_INDEX_NONE) + || (index == e_FM_PCD_HDR_INDEX_1)) + return CC_PC_FF_IPV4SRC1_IPV4DST1; + if (index == e_FM_PCD_HDR_INDEX_2) + return CC_PC_FF_IPV4SRC2_IPV4DST2; + REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Illegal IPv4 index")); + return CC_PC_ILLEGAL; + case (NET_HEADER_FIELD_IPv4_TTL): + return CC_PC_FF_IPV4TTL; + default: + REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Extraction not supported")); + return CC_PC_ILLEGAL; + } + + case (HEADER_TYPE_IPv6): + switch (field.ipv6) + { + case (NET_HEADER_FIELD_IPv6_VER | NET_HEADER_FIELD_IPv6_FL + | NET_HEADER_FIELD_IPv6_TC): + if ((index == e_FM_PCD_HDR_INDEX_NONE) + || (index == e_FM_PCD_HDR_INDEX_1)) + return CC_PC_FF_IPTOS_IPV6TC1_IPV6FLOW1; + if (index == e_FM_PCD_HDR_INDEX_2) + return CC_PC_FF_IPTOS_IPV6TC2_IPV6FLOW2; + REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Illegal IPv6 index")); + return CC_PC_ILLEGAL; + + case (NET_HEADER_FIELD_IPv6_NEXT_HDR): + if ((index == e_FM_PCD_HDR_INDEX_NONE) + || (index == e_FM_PCD_HDR_INDEX_1)) + return CC_PC_FF_IPV6PTYPE1; + if (index == e_FM_PCD_HDR_INDEX_2) + return CC_PC_FF_IPV6PTYPE2; + if (index == e_FM_PCD_HDR_INDEX_LAST) + return CC_PC_FF_IPPID; + REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Illegal IPv6 index")); + return CC_PC_ILLEGAL; + + case (NET_HEADER_FIELD_IPv6_DST_IP): + if ((index == e_FM_PCD_HDR_INDEX_NONE) + || (index == e_FM_PCD_HDR_INDEX_1)) + return CC_PC_FF_IPV6DST1; + if (index == e_FM_PCD_HDR_INDEX_2) + return CC_PC_FF_IPV6DST2; + REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Illegal IPv6 index")); + return CC_PC_ILLEGAL; + + case (NET_HEADER_FIELD_IPv6_SRC_IP): + if ((index == e_FM_PCD_HDR_INDEX_NONE) + || (index == e_FM_PCD_HDR_INDEX_1)) + return CC_PC_FF_IPV6SRC1; + if (index == e_FM_PCD_HDR_INDEX_2) + return CC_PC_FF_IPV6SRC2; + REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Illegal IPv6 index")); + return CC_PC_ILLEGAL; + + case (NET_HEADER_FIELD_IPv6_HOP_LIMIT): + return CC_PC_FF_IPV6HOP_LIMIT; + + default: + REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Extraction not supported")); + return CC_PC_ILLEGAL; + } + + case (HEADER_TYPE_IP): + switch (field.ip) + { + case (NET_HEADER_FIELD_IP_DSCP): + if ((index == e_FM_PCD_HDR_INDEX_NONE) + || (index == e_FM_PCD_HDR_INDEX_1)) + return CC_PC_FF_IPDSCP; + REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Illegal IP index")); + return CC_PC_ILLEGAL; + + case (NET_HEADER_FIELD_IP_PROTO): + if (index == e_FM_PCD_HDR_INDEX_LAST) + return CC_PC_FF_IPPID; + REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Illegal IP index")); + return CC_PC_ILLEGAL; + + default: + REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Extraction not supported")); + return CC_PC_ILLEGAL; + } + + case (HEADER_TYPE_GRE): + switch (field.gre) + { + case (NET_HEADER_FIELD_GRE_TYPE): + return CC_PC_FF_GREPTYPE; + + default: + REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Extraction not supported")); + return CC_PC_ILLEGAL; + } + + case (HEADER_TYPE_MINENCAP): + switch (field.minencap) + { + case (NET_HEADER_FIELD_MINENCAP_TYPE): + return CC_PC_FF_MINENCAP_PTYPE; + + case (NET_HEADER_FIELD_MINENCAP_DST_IP): + return CC_PC_FF_MINENCAP_IPDST; + + case (NET_HEADER_FIELD_MINENCAP_SRC_IP): + return CC_PC_FF_MINENCAP_IPSRC; + + case (NET_HEADER_FIELD_MINENCAP_SRC_IP + | NET_HEADER_FIELD_MINENCAP_DST_IP): + return CC_PC_FF_MINENCAP_IPSRC_IPDST; + + default: + REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Extraction not supported")); + return CC_PC_ILLEGAL; + } + + case (HEADER_TYPE_TCP): + switch (field.tcp) + { + case (NET_HEADER_FIELD_TCP_PORT_SRC): + return CC_PC_FF_L4PSRC; + + case (NET_HEADER_FIELD_TCP_PORT_DST): + return CC_PC_FF_L4PDST; + + case (NET_HEADER_FIELD_TCP_PORT_DST + | NET_HEADER_FIELD_TCP_PORT_SRC): + return CC_PC_FF_L4PSRC_L4PDST; + + default: + REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Extraction not supported")); + return CC_PC_ILLEGAL; + } + + case (HEADER_TYPE_PPPoE): + switch (field.pppoe) + { + case (NET_HEADER_FIELD_PPPoE_PID): + return CC_PC_FF_PPPPID; + + default: + REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Extraction not supported")); + return CC_PC_ILLEGAL; + } + + case (HEADER_TYPE_UDP): + switch (field.udp) + { + case (NET_HEADER_FIELD_UDP_PORT_SRC): + return CC_PC_FF_L4PSRC; + + case (NET_HEADER_FIELD_UDP_PORT_DST): + return CC_PC_FF_L4PDST; + + case (NET_HEADER_FIELD_UDP_PORT_DST + | NET_HEADER_FIELD_UDP_PORT_SRC): + return CC_PC_FF_L4PSRC_L4PDST; + + default: + REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Extraction not supported")); + return CC_PC_ILLEGAL; + } + + default: + REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Extraction not supported")); + return CC_PC_ILLEGAL; + } +} + +static uint8_t GetPrParseCode(e_NetHeaderType hdr, e_FmPcdHdrIndex hdrIndex, + uint32_t offset, bool glblMask, + uint8_t *parseArrayOffset) +{ + bool offsetRelevant = FALSE; + + if (offset) + offsetRelevant = TRUE; + + switch (hdr) + { + case (HEADER_TYPE_NONE): + ASSERT_COND(FALSE); + return CC_PC_ILLEGAL; + + case (HEADER_TYPE_ETH): + *parseArrayOffset = (uint8_t)CC_PC_PR_ETH_OFFSET; + break; + + case (HEADER_TYPE_USER_DEFINED_SHIM1): + if (offset || glblMask) + *parseArrayOffset = (uint8_t)CC_PC_PR_USER_DEFINED_SHIM1_OFFSET; + else + return CC_PC_PR_SHIM1; + break; + + case (HEADER_TYPE_USER_DEFINED_SHIM2): + if (offset || glblMask) + *parseArrayOffset = (uint8_t)CC_PC_PR_USER_DEFINED_SHIM2_OFFSET; + else + return CC_PC_PR_SHIM2; + break; + + case (HEADER_TYPE_LLC_SNAP): + *parseArrayOffset = CC_PC_PR_USER_LLC_SNAP_OFFSET; + break; + + case (HEADER_TYPE_PPPoE): + *parseArrayOffset = CC_PC_PR_PPPOE_OFFSET; + break; + + case (HEADER_TYPE_MPLS): + if ((hdrIndex == e_FM_PCD_HDR_INDEX_NONE) + || (hdrIndex == e_FM_PCD_HDR_INDEX_1)) + *parseArrayOffset = CC_PC_PR_MPLS1_OFFSET; + else + if (hdrIndex == e_FM_PCD_HDR_INDEX_LAST) + *parseArrayOffset = CC_PC_PR_MPLS_LAST_OFFSET; + else + { + REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Illegal MPLS header index")); + return CC_PC_ILLEGAL; + } + break; + + case (HEADER_TYPE_IPv4): + case (HEADER_TYPE_IPv6): + if ((hdrIndex == e_FM_PCD_HDR_INDEX_NONE) + || (hdrIndex == e_FM_PCD_HDR_INDEX_1)) + *parseArrayOffset = CC_PC_PR_IP1_OFFSET; + else + if (hdrIndex == e_FM_PCD_HDR_INDEX_2) + *parseArrayOffset = CC_PC_PR_IP_LAST_OFFSET; + else + { + REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Illegal IP header index")); + return CC_PC_ILLEGAL; + } + break; + + case (HEADER_TYPE_MINENCAP): + *parseArrayOffset = CC_PC_PR_MINENC_OFFSET; + break; + + case (HEADER_TYPE_GRE): + *parseArrayOffset = CC_PC_PR_GRE_OFFSET; + break; + + case (HEADER_TYPE_TCP): + case (HEADER_TYPE_UDP): + case (HEADER_TYPE_IPSEC_AH): + case (HEADER_TYPE_IPSEC_ESP): + case (HEADER_TYPE_DCCP): + case (HEADER_TYPE_SCTP): + *parseArrayOffset = CC_PC_PR_L4_OFFSET; + break; + + default: + REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Illegal IP header for this type of operation")); + return CC_PC_ILLEGAL; + } + + if (offsetRelevant) + return CC_PR_OFFSET; + else + return CC_PR_WITHOUT_OFFSET; +} + +static uint8_t GetFieldParseCode(e_NetHeaderType hdr, t_FmPcdFields field, + uint32_t offset, uint8_t *parseArrayOffset, + e_FmPcdHdrIndex hdrIndex) +{ + bool offsetRelevant = FALSE; + + if (offset) + offsetRelevant = TRUE; + + switch (hdr) + { + case (HEADER_TYPE_NONE): + ASSERT_COND(FALSE); + break; + case (HEADER_TYPE_ETH): + switch (field.eth) + { + case (NET_HEADER_FIELD_ETH_TYPE): + *parseArrayOffset = CC_PC_PR_ETYPE_LAST_OFFSET; + break; + + default: + REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Extraction not supported")); + return CC_PC_ILLEGAL; + } + break; + + case (HEADER_TYPE_VLAN): + switch (field.vlan) + { + case (NET_HEADER_FIELD_VLAN_TCI): + if ((hdrIndex == e_FM_PCD_HDR_INDEX_NONE) + || (hdrIndex == e_FM_PCD_HDR_INDEX_1)) + *parseArrayOffset = CC_PC_PR_VLAN1_OFFSET; + else + if (hdrIndex == e_FM_PCD_HDR_INDEX_LAST) + *parseArrayOffset = CC_PC_PR_VLAN2_OFFSET; + break; + + default: + REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Extraction not supported")); + return CC_PC_ILLEGAL; + } + break; + + default: + REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Illegal header ")); + return CC_PC_ILLEGAL; + } + + if (offsetRelevant) + return CC_PR_OFFSET; + else + return CC_PR_WITHOUT_OFFSET; +} + +static void FillAdOfTypeResult(t_Handle h_Ad, + t_FmPcdCcStatsParams *p_FmPcdCcStatsParams, + t_FmPcd *p_FmPcd, + t_FmPcdCcNextEngineParams *p_CcNextEngineParams) +{ + t_AdOfTypeResult *p_AdResult = (t_AdOfTypeResult *)h_Ad; + t_Handle h_TmpAd; + uint32_t tmp = 0, tmpNia = 0; + uint16_t profileId; + t_Handle p_AdNewPtr = NULL; + t_Error err = E_OK; + + /* There are 3 cases handled in this routine of building a "result" type AD. + * Case 1: No Manip. The action descriptor is built within the match table. + * Case 2: Manip exists. A new AD is created - p_AdNewPtr. It is initialized + * either in the FmPcdManipUpdateAdResultForCc routine or it was already + * initialized and returned here. + * p_AdResult (within the match table) will be initialized after + * this routine returns and point to the existing AD. + * Case 3: Manip exists. The action descriptor is built within the match table. + * FmPcdManipUpdateAdResultForCc returns a NULL p_AdNewPtr. + * + * If statistics were enabled and the statistics mode of this node requires + * a statistics Ad, it will be placed after the result Ad and before the + * manip Ad, if manip Ad exists here. + */ + + /* As default, the "new" ptr is the current one. i.e. the content of the result + * AD will be written into the match table itself (case (1))*/ + p_AdNewPtr = p_AdResult; + + /* Initialize an action descriptor, if current statistics mode requires an Ad */ + if (p_FmPcdCcStatsParams) + { + ASSERT_COND(p_FmPcdCcStatsParams->h_StatsAd); + ASSERT_COND(p_FmPcdCcStatsParams->h_StatsCounters); + + /* Swapping addresses between statistics Ad and the current lookup AD addresses */ + h_TmpAd = p_FmPcdCcStatsParams->h_StatsAd; + p_FmPcdCcStatsParams->h_StatsAd = h_Ad; + h_Ad = h_TmpAd; + + p_AdNewPtr = h_Ad; + p_AdResult = h_Ad; + + /* Init statistics Ad and connect current lookup AD as 'next action' from statistics Ad */ + UpdateStatsAd(p_FmPcdCcStatsParams, h_Ad, p_FmPcd->physicalMuramBase); + } + + /* Create manip and return p_AdNewPtr to either a new descriptor or NULL */ + if (p_CcNextEngineParams->h_Manip) + FmPcdManipUpdateAdResultForCc(p_CcNextEngineParams->h_Manip, + p_CcNextEngineParams, h_Ad, &p_AdNewPtr); + + /* if (p_AdNewPtr = NULL) --> Done. (case (3)) */ + if (p_AdNewPtr) + { + /* case (1) and (2) */ + switch (p_CcNextEngineParams->nextEngine) + { + case (e_FM_PCD_DONE): + if (p_CcNextEngineParams->params.enqueueParams.action + == e_FM_PCD_ENQ_FRAME) + { + if (p_CcNextEngineParams->params.enqueueParams.overrideFqid) + { + tmp = FM_PCD_AD_RESULT_CONTRL_FLOW_TYPE; + tmp |= + p_CcNextEngineParams->params.enqueueParams.newFqid; +#if (DPAA_VERSION >= 11) + tmp |= + (p_CcNextEngineParams->params.enqueueParams.newRelativeStorageProfileId + & FM_PCD_AD_RESULT_VSP_MASK) + << FM_PCD_AD_RESULT_VSP_SHIFT; +#endif /* (DPAA_VERSION >= 11) */ + } + else + { + tmp = FM_PCD_AD_RESULT_DATA_FLOW_TYPE; + tmp |= FM_PCD_AD_RESULT_PLCR_DIS; + } + } + + if (p_CcNextEngineParams->params.enqueueParams.action + == e_FM_PCD_DROP_FRAME) + tmpNia |= GET_NIA_BMI_AC_DISCARD_FRAME(p_FmPcd); + else + tmpNia |= GET_NIA_BMI_AC_ENQ_FRAME(p_FmPcd); + break; + + case (e_FM_PCD_KG): + if (p_CcNextEngineParams->params.kgParams.overrideFqid) + { + tmp = FM_PCD_AD_RESULT_CONTRL_FLOW_TYPE; + tmp |= p_CcNextEngineParams->params.kgParams.newFqid; +#if (DPAA_VERSION >= 11) + tmp |= + (p_CcNextEngineParams->params.kgParams.newRelativeStorageProfileId + & FM_PCD_AD_RESULT_VSP_MASK) + << FM_PCD_AD_RESULT_VSP_SHIFT; +#endif /* (DPAA_VERSION >= 11) */ + } + else + { + tmp = FM_PCD_AD_RESULT_DATA_FLOW_TYPE; + tmp |= FM_PCD_AD_RESULT_PLCR_DIS; + } + tmpNia = NIA_KG_DIRECT; + tmpNia |= NIA_ENG_KG; + tmpNia |= NIA_KG_CC_EN; + tmpNia |= FmPcdKgGetSchemeId( + p_CcNextEngineParams->params.kgParams.h_DirectScheme); + break; + + case (e_FM_PCD_PLCR): + if (p_CcNextEngineParams->params.plcrParams.overrideParams) + { + tmp = FM_PCD_AD_RESULT_CONTRL_FLOW_TYPE; + + /* if private policer profile, it may be uninitialized yet, therefore no checks are done at this stage */ + if (p_CcNextEngineParams->params.plcrParams.sharedProfile) + { + tmpNia |= NIA_PLCR_ABSOLUTE; + err = FmPcdPlcrGetAbsoluteIdByProfileParams( + (t_Handle)p_FmPcd, + e_FM_PCD_PLCR_SHARED, + NULL, + p_CcNextEngineParams->params.plcrParams.newRelativeProfileId, + &profileId); + + if (err != E_OK) { + REPORT_ERROR(MAJOR, err, NO_MSG); + return; + } + + } + else + profileId = + p_CcNextEngineParams->params.plcrParams.newRelativeProfileId; + + tmp |= p_CcNextEngineParams->params.plcrParams.newFqid; +#if (DPAA_VERSION >= 11) + tmp |= + (p_CcNextEngineParams->params.plcrParams.newRelativeStorageProfileId + & FM_PCD_AD_RESULT_VSP_MASK) + << FM_PCD_AD_RESULT_VSP_SHIFT; +#endif /* (DPAA_VERSION >= 11) */ + WRITE_UINT32( + p_AdResult->plcrProfile, + (uint32_t)((uint32_t)profileId << FM_PCD_AD_PROFILEID_FOR_CNTRL_SHIFT)); + } + else + tmp = FM_PCD_AD_RESULT_DATA_FLOW_TYPE; + + tmpNia |= + NIA_ENG_PLCR + | p_CcNextEngineParams->params.plcrParams.newRelativeProfileId; + break; + + default: + return; + }WRITE_UINT32(p_AdResult->fqid, tmp); + + if (p_CcNextEngineParams->h_Manip) + { + tmp = GET_UINT32(p_AdResult->plcrProfile); + tmp |= (uint32_t)(XX_VirtToPhys(p_AdNewPtr) + - (p_FmPcd->physicalMuramBase)) >> 4; + WRITE_UINT32(p_AdResult->plcrProfile, tmp); + + tmpNia |= FM_PCD_AD_RESULT_EXTENDED_MODE; + tmpNia |= FM_PCD_AD_RESULT_NADEN; + } + +#if (DPAA_VERSION >= 11) + tmpNia |= FM_PCD_AD_RESULT_NO_OM_VSPE; +#endif /* (DPAA_VERSION >= 11) */ + WRITE_UINT32(p_AdResult->nia, tmpNia); + } +} + +static t_Error CcUpdateParams(t_Handle h_FmPcd, t_Handle h_PcdParams, + t_Handle h_FmPort, t_Handle h_FmTree, + bool validate) +{ + t_FmPcdCcTree *p_CcTree = (t_FmPcdCcTree *)h_FmTree; + + return CcUpdateParam(h_FmPcd, h_PcdParams, h_FmPort, + p_CcTree->keyAndNextEngineParams, + p_CcTree->numOfEntries, + UINT_TO_PTR(p_CcTree->ccTreeBaseAddr), validate, 0, + h_FmTree, FALSE); +} + + +static void ReleaseNewNodeCommonPart( + t_FmPcdModifyCcKeyAdditionalParams *p_AdditionalInfo) +{ + if (p_AdditionalInfo->p_AdTableNew) + FM_MURAM_FreeMem( + FmPcdGetMuramHandle( + ((t_FmPcdCcNode *)(p_AdditionalInfo->h_CurrentNode))->h_FmPcd), + p_AdditionalInfo->p_AdTableNew); + + if (p_AdditionalInfo->p_KeysMatchTableNew) + FM_MURAM_FreeMem( + FmPcdGetMuramHandle( + ((t_FmPcdCcNode *)(p_AdditionalInfo->h_CurrentNode))->h_FmPcd), + p_AdditionalInfo->p_KeysMatchTableNew); +} + +static t_Error UpdateGblMask(t_FmPcdCcNode *p_CcNode, uint8_t keySize, + uint8_t *p_Mask) +{ + uint8_t prvGlblMaskSize = p_CcNode->glblMaskSize; + + if (p_Mask && !p_CcNode->glblMaskUpdated && (keySize <= 4) + && !p_CcNode->lclMask) + { + if (p_CcNode->parseCode && (p_CcNode->parseCode != CC_PC_FF_TCI1) + && (p_CcNode->parseCode != CC_PC_FF_TCI2) + && (p_CcNode->parseCode != CC_PC_FF_MPLS1) + && (p_CcNode->parseCode != CC_PC_FF_MPLS_LAST) + && (p_CcNode->parseCode != CC_PC_FF_IPV4IPTOS_TC1) + && (p_CcNode->parseCode != CC_PC_FF_IPV4IPTOS_TC2) + && (p_CcNode->parseCode != CC_PC_FF_IPTOS_IPV6TC1_IPV6FLOW1) + && (p_CcNode->parseCode != CC_PC_FF_IPDSCP) + && (p_CcNode->parseCode != CC_PC_FF_IPTOS_IPV6TC2_IPV6FLOW2)) + { + p_CcNode->glblMaskSize = 0; + p_CcNode->lclMask = TRUE; + } + else + { + memcpy(p_CcNode->p_GlblMask, p_Mask, (sizeof(uint8_t)) * keySize); + p_CcNode->glblMaskUpdated = TRUE; + p_CcNode->glblMaskSize = 4; + } + } + else + if (p_Mask && (keySize <= 4) && !p_CcNode->lclMask) + { + if (memcmp(p_CcNode->p_GlblMask, p_Mask, keySize) != 0) + { + p_CcNode->lclMask = TRUE; + p_CcNode->glblMaskSize = 0; + } + } + else + if (!p_Mask && p_CcNode->glblMaskUpdated && (keySize <= 4)) + { + uint32_t tmpMask = 0xffffffff; + if (memcmp(p_CcNode->p_GlblMask, &tmpMask, 4) != 0) + { + p_CcNode->lclMask = TRUE; + p_CcNode->glblMaskSize = 0; + } + } + else + if (p_Mask) + { + p_CcNode->lclMask = TRUE; + p_CcNode->glblMaskSize = 0; + } + + /* In static mode (maxNumOfKeys > 0), local mask is supported + only is mask support was enabled at initialization */ + if (p_CcNode->maxNumOfKeys && (!p_CcNode->maskSupport) && p_CcNode->lclMask) + { + p_CcNode->lclMask = FALSE; + p_CcNode->glblMaskSize = prvGlblMaskSize; + return ERROR_CODE(E_NOT_SUPPORTED); + } + + return E_OK; +} + +static __inline__ t_Handle GetNewAd(t_Handle h_FmPcdCcNodeOrTree, bool isTree) +{ + t_FmPcd *p_FmPcd; + t_Handle h_Ad; + + if (isTree) + p_FmPcd = (t_FmPcd *)(((t_FmPcdCcTree *)h_FmPcdCcNodeOrTree)->h_FmPcd); + else + p_FmPcd = (t_FmPcd *)(((t_FmPcdCcNode *)h_FmPcdCcNodeOrTree)->h_FmPcd); + + if ((isTree && p_FmPcd->p_CcShadow) + || (!isTree && ((t_FmPcdCcNode *)h_FmPcdCcNodeOrTree)->maxNumOfKeys)) + { + /* The allocated shadow is divided as follows: + 0 . . . 16 . . . + --------------------------------------------------- + | Shadow | Shadow Keys | Shadow Next | + | Ad | Match Table | Engine Table | + | (16 bytes) | (maximal size) | (maximal size) | + --------------------------------------------------- + */ + if (!p_FmPcd->p_CcShadow) + { + REPORT_ERROR(MAJOR, E_NO_MEMORY, ("CC Shadow not allocated")); + return NULL; + } + + h_Ad = p_FmPcd->p_CcShadow; + } + else + { + h_Ad = (t_Handle)FM_MURAM_AllocMem(FmPcdGetMuramHandle(p_FmPcd), + FM_PCD_CC_AD_ENTRY_SIZE, + FM_PCD_CC_AD_TABLE_ALIGN); + if (!h_Ad) + { + REPORT_ERROR(MAJOR, E_NO_MEMORY, ("MURAM allocation for CC node action descriptor")); + return NULL; + } + } + + return h_Ad; +} + +static t_Error BuildNewNodeCommonPart( + t_FmPcdCcNode *p_CcNode, int *size, + t_FmPcdModifyCcKeyAdditionalParams *p_AdditionalInfo) +{ + t_FmPcd *p_FmPcd = (t_FmPcd *)p_CcNode->h_FmPcd; + + if (p_CcNode->lclMask) + *size = 2 * p_CcNode->ccKeySizeAccExtraction; + else + *size = p_CcNode->ccKeySizeAccExtraction; + + if (p_CcNode->maxNumOfKeys == 0) + { + p_AdditionalInfo->p_AdTableNew = (t_Handle)FM_MURAM_AllocMem( + FmPcdGetMuramHandle(p_FmPcd), + (uint32_t)((p_AdditionalInfo->numOfKeys + 1) + * FM_PCD_CC_AD_ENTRY_SIZE), + FM_PCD_CC_AD_TABLE_ALIGN); + if (!p_AdditionalInfo->p_AdTableNew) + RETURN_ERROR( + MAJOR, E_NO_MEMORY, + ("MURAM allocation for CC node action descriptors table")); + + p_AdditionalInfo->p_KeysMatchTableNew = (t_Handle)FM_MURAM_AllocMem( + FmPcdGetMuramHandle(p_FmPcd), + (uint32_t)(*size * sizeof(uint8_t) + * (p_AdditionalInfo->numOfKeys + 1)), + FM_PCD_CC_KEYS_MATCH_TABLE_ALIGN); + if (!p_AdditionalInfo->p_KeysMatchTableNew) + { + FM_MURAM_FreeMem(FmPcdGetMuramHandle(p_CcNode->h_FmPcd), + p_AdditionalInfo->p_AdTableNew); + p_AdditionalInfo->p_AdTableNew = NULL; + RETURN_ERROR(MAJOR, E_NO_MEMORY, + ("MURAM allocation for CC node key match table")); + } + + MemSet8( + (uint8_t*)p_AdditionalInfo->p_AdTableNew, + 0, + (uint32_t)((p_AdditionalInfo->numOfKeys + 1) + * FM_PCD_CC_AD_ENTRY_SIZE)); + MemSet8((uint8_t*)p_AdditionalInfo->p_KeysMatchTableNew, 0, + *size * sizeof(uint8_t) * (p_AdditionalInfo->numOfKeys + 1)); + } + else + { + /* The allocated shadow is divided as follows: + 0 . . . 16 . . . + --------------------------------------------------- + | Shadow | Shadow Keys | Shadow Next | + | Ad | Match Table | Engine Table | + | (16 bytes) | (maximal size) | (maximal size) | + --------------------------------------------------- + */ + + if (!p_FmPcd->p_CcShadow) + RETURN_ERROR(MAJOR, E_NO_MEMORY, ("CC Shadow not allocated")); + + p_AdditionalInfo->p_KeysMatchTableNew = + PTR_MOVE(p_FmPcd->p_CcShadow, FM_PCD_CC_AD_ENTRY_SIZE); + p_AdditionalInfo->p_AdTableNew = + PTR_MOVE(p_AdditionalInfo->p_KeysMatchTableNew, p_CcNode->keysMatchTableMaxSize); + + MemSet8( + (uint8_t*)p_AdditionalInfo->p_AdTableNew, + 0, + (uint32_t)((p_CcNode->maxNumOfKeys + 1) + * FM_PCD_CC_AD_ENTRY_SIZE)); + MemSet8((uint8_t*)p_AdditionalInfo->p_KeysMatchTableNew, 0, + (*size) * sizeof(uint8_t) * (p_CcNode->maxNumOfKeys)); + } + + p_AdditionalInfo->p_AdTableOld = p_CcNode->h_AdTable; + p_AdditionalInfo->p_KeysMatchTableOld = p_CcNode->h_KeysMatchTable; + + return E_OK; +} + +static t_Error BuildNewNodeAddOrMdfyKeyAndNextEngine( + t_Handle h_FmPcd, t_FmPcdCcNode *p_CcNode, uint16_t keyIndex, + t_FmPcdCcKeyParams *p_KeyParams, + t_FmPcdModifyCcKeyAdditionalParams *p_AdditionalInfo, bool add) +{ + t_Error err = E_OK; + t_Handle p_AdTableNewTmp, p_KeysMatchTableNewTmp; + t_Handle p_KeysMatchTableOldTmp, p_AdTableOldTmp; + int size; + int i = 0, j = 0; + t_FmPcd *p_FmPcd = (t_FmPcd*)h_FmPcd; + uint32_t requiredAction = 0; + bool prvLclMask; + t_CcNodeInformation *p_CcNodeInformation; + t_FmPcdCcStatsParams statsParams = { 0 }; + t_List *p_Pos; + t_FmPcdStatsObj *p_StatsObj; + + /* Check that new NIA is legal */ + err = ValidateNextEngineParams(h_FmPcd, &p_KeyParams->ccNextEngineParams, + p_CcNode->statisticsMode); + if (err) + RETURN_ERROR(MAJOR, err, NO_MSG); + + prvLclMask = p_CcNode->lclMask; + + /* Check that new key is not require update of localMask */ + err = UpdateGblMask(p_CcNode, p_CcNode->ccKeySizeAccExtraction, + p_KeyParams->p_Mask); + if (err) + RETURN_ERROR(MAJOR, err, (NO_MSG)); + + /* Update internal data structure with new next engine for the given index */ + memcpy(&p_AdditionalInfo->keyAndNextEngineParams[keyIndex].nextEngineParams, + &p_KeyParams->ccNextEngineParams, sizeof(t_FmPcdCcNextEngineParams)); + + memcpy(p_AdditionalInfo->keyAndNextEngineParams[keyIndex].key, + p_KeyParams->p_Key, p_CcNode->userSizeOfExtraction); + + if ((p_AdditionalInfo->keyAndNextEngineParams[keyIndex].nextEngineParams.nextEngine + == e_FM_PCD_CC) + && p_AdditionalInfo->keyAndNextEngineParams[keyIndex].nextEngineParams.h_Manip) + { + err = + AllocAndFillAdForContLookupManip( + p_AdditionalInfo->keyAndNextEngineParams[keyIndex].nextEngineParams.params.ccParams.h_CcNode); + if (err) + RETURN_ERROR(MAJOR, err, (NO_MSG)); + } + + if (p_KeyParams->p_Mask) + memcpy(p_AdditionalInfo->keyAndNextEngineParams[keyIndex].mask, + p_KeyParams->p_Mask, p_CcNode->userSizeOfExtraction); + else + memset(p_AdditionalInfo->keyAndNextEngineParams[keyIndex].mask, 0xFF, + p_CcNode->userSizeOfExtraction); + + /* Update numOfKeys */ + if (add) + p_AdditionalInfo->numOfKeys = (uint8_t)(p_CcNode->numOfKeys + 1); + else + p_AdditionalInfo->numOfKeys = (uint8_t)p_CcNode->numOfKeys; + + /* Allocate new tables in MURAM: keys match table and action descriptors table */ + err = BuildNewNodeCommonPart(p_CcNode, &size, p_AdditionalInfo); + if (err) + RETURN_ERROR(MAJOR, err, NO_MSG); + + /* Check that manip is legal and what requiredAction is necessary for this manip */ + if (p_KeyParams->ccNextEngineParams.h_Manip) + { + err = FmPcdManipCheckParamsForCcNextEngine( + &p_KeyParams->ccNextEngineParams, &requiredAction); + if (err) + RETURN_ERROR(MAJOR, err, (NO_MSG)); + } + + p_AdditionalInfo->keyAndNextEngineParams[keyIndex].requiredAction = + requiredAction; + p_AdditionalInfo->keyAndNextEngineParams[keyIndex].requiredAction |= + UPDATE_CC_WITH_TREE; + + /* Update new Ad and new Key Table according to new requirement */ + i = 0; + for (j = 0; j < p_AdditionalInfo->numOfKeys; j++) + { + p_AdTableNewTmp = + PTR_MOVE(p_AdditionalInfo->p_AdTableNew, j*FM_PCD_CC_AD_ENTRY_SIZE); + + if (j == keyIndex) + { + if (p_KeyParams->ccNextEngineParams.statisticsEn) + { + /* Allocate a statistics object that holds statistics AD and counters. + - For added key - New statistics AD and counters pointer need to be allocated + new statistics object. If statistics were enabled, we need to replace the + existing descriptor with a new descriptor with nullified counters. + */ + p_StatsObj = GetStatsObj(p_CcNode); + ASSERT_COND(p_StatsObj); + + /* Store allocated statistics object */ + ASSERT_COND(keyIndex < CC_MAX_NUM_OF_KEYS); + p_AdditionalInfo->keyAndNextEngineParams[keyIndex].p_StatsObj = + p_StatsObj; + + statsParams.h_StatsAd = p_StatsObj->h_StatsAd; + statsParams.h_StatsCounters = p_StatsObj->h_StatsCounters; +#if (DPAA_VERSION >= 11) + statsParams.h_StatsFLRs = p_CcNode->h_StatsFLRs; + +#endif /* (DPAA_VERSION >= 11) */ + + /* Building action descriptor for the received new key */ + NextStepAd(p_AdTableNewTmp, &statsParams, + &p_KeyParams->ccNextEngineParams, p_FmPcd); + } + else + { + /* Building action descriptor for the received new key */ + NextStepAd(p_AdTableNewTmp, NULL, + &p_KeyParams->ccNextEngineParams, p_FmPcd); + } + + /* Copy the received new key into keys match table */ + p_KeysMatchTableNewTmp = + PTR_MOVE(p_AdditionalInfo->p_KeysMatchTableNew, j*size*sizeof(uint8_t)); + + MemCpy8((void*)p_KeysMatchTableNewTmp, p_KeyParams->p_Key, + p_CcNode->userSizeOfExtraction); + + /* Update mask for the received new key */ + if (p_CcNode->lclMask) + { + if (p_KeyParams->p_Mask) + { + MemCpy8(PTR_MOVE(p_KeysMatchTableNewTmp, + p_CcNode->ccKeySizeAccExtraction), + p_KeyParams->p_Mask, + p_CcNode->userSizeOfExtraction); + } + else + if (p_CcNode->ccKeySizeAccExtraction > 4) + { + MemSet8(PTR_MOVE(p_KeysMatchTableNewTmp, + p_CcNode->ccKeySizeAccExtraction), + 0xff, p_CcNode->userSizeOfExtraction); + } + else + { + MemCpy8(PTR_MOVE(p_KeysMatchTableNewTmp, + p_CcNode->ccKeySizeAccExtraction), + p_CcNode->p_GlblMask, + p_CcNode->userSizeOfExtraction); + } + } + + /* If key modification requested, the old entry is omitted and replaced by the new parameters */ + if (!add) + i++; + } + else + { + /* Copy existing action descriptors to the newly allocated Ad table */ + p_AdTableOldTmp = + PTR_MOVE(p_AdditionalInfo->p_AdTableOld, i*FM_PCD_CC_AD_ENTRY_SIZE); + MemCpy8(p_AdTableNewTmp, p_AdTableOldTmp, + FM_PCD_CC_AD_ENTRY_SIZE); + + /* Copy existing keys and their masks to the newly allocated keys match table */ + p_KeysMatchTableNewTmp = + PTR_MOVE(p_AdditionalInfo->p_KeysMatchTableNew, j * size * sizeof(uint8_t)); + p_KeysMatchTableOldTmp = + PTR_MOVE(p_AdditionalInfo->p_KeysMatchTableOld, i * size * sizeof(uint8_t)); + + if (p_CcNode->lclMask) + { + if (prvLclMask) + { + MemCpy8( + PTR_MOVE(p_KeysMatchTableNewTmp, p_CcNode->ccKeySizeAccExtraction), + PTR_MOVE(p_KeysMatchTableOldTmp, p_CcNode->ccKeySizeAccExtraction), + p_CcNode->ccKeySizeAccExtraction); + } + else + { + p_KeysMatchTableOldTmp = + PTR_MOVE(p_CcNode->h_KeysMatchTable, + i * (int)p_CcNode->ccKeySizeAccExtraction * sizeof(uint8_t)); + + if (p_CcNode->ccKeySizeAccExtraction > 4) + { + MemSet8(PTR_MOVE(p_KeysMatchTableNewTmp, + p_CcNode->ccKeySizeAccExtraction), + 0xff, p_CcNode->userSizeOfExtraction); + } + else + { + MemCpy8(PTR_MOVE(p_KeysMatchTableNewTmp, + p_CcNode->ccKeySizeAccExtraction), + p_CcNode->p_GlblMask, + p_CcNode->userSizeOfExtraction); + } + } + } + + MemCpy8(p_KeysMatchTableNewTmp, p_KeysMatchTableOldTmp, + p_CcNode->ccKeySizeAccExtraction); + + i++; + } + } + + /* Miss action descriptor */ + p_AdTableNewTmp = + PTR_MOVE(p_AdditionalInfo->p_AdTableNew, j * FM_PCD_CC_AD_ENTRY_SIZE); + p_AdTableOldTmp = + PTR_MOVE(p_AdditionalInfo->p_AdTableOld, i * FM_PCD_CC_AD_ENTRY_SIZE); + MemCpy8(p_AdTableNewTmp, p_AdTableOldTmp, FM_PCD_CC_AD_ENTRY_SIZE); + + if (!LIST_IsEmpty(&p_CcNode->ccTreesLst)) + { + LIST_FOR_EACH(p_Pos, &p_CcNode->ccTreesLst) + { + p_CcNodeInformation = CC_NODE_F_OBJECT(p_Pos); + ASSERT_COND(p_CcNodeInformation->h_CcNode); + /* Update the manipulation which has to be updated from parameters of the port */ + /* It's has to be updated with restrictions defined in the function */ + err = + SetRequiredAction( + p_CcNode->h_FmPcd, + p_CcNode->shadowAction + | p_AdditionalInfo->keyAndNextEngineParams[keyIndex].requiredAction, + &p_AdditionalInfo->keyAndNextEngineParams[keyIndex], + PTR_MOVE(p_AdditionalInfo->p_AdTableNew, keyIndex*FM_PCD_CC_AD_ENTRY_SIZE), + 1, p_CcNodeInformation->h_CcNode); + if (err) + RETURN_ERROR(MAJOR, err, (NO_MSG)); + + err = + CcUpdateParam( + p_CcNode->h_FmPcd, + NULL, + NULL, + &p_AdditionalInfo->keyAndNextEngineParams[keyIndex], + 1, + PTR_MOVE(p_AdditionalInfo->p_AdTableNew, keyIndex*FM_PCD_CC_AD_ENTRY_SIZE), + TRUE, p_CcNodeInformation->index, + p_CcNodeInformation->h_CcNode, TRUE); + if (err) + RETURN_ERROR(MAJOR, err, (NO_MSG)); + } + } + + if (p_CcNode->lclMask) + memset(p_CcNode->p_GlblMask, 0xff, CC_GLBL_MASK_SIZE * sizeof(uint8_t)); + + if (p_KeyParams->ccNextEngineParams.nextEngine == e_FM_PCD_CC) + p_AdditionalInfo->h_NodeForAdd = + p_KeyParams->ccNextEngineParams.params.ccParams.h_CcNode; + if (p_KeyParams->ccNextEngineParams.h_Manip) + p_AdditionalInfo->h_ManipForAdd = + p_KeyParams->ccNextEngineParams.h_Manip; + +#if (DPAA_VERSION >= 11) + if ((p_KeyParams->ccNextEngineParams.nextEngine == e_FM_PCD_FR) + && (p_KeyParams->ccNextEngineParams.params.frParams.h_FrmReplic)) + p_AdditionalInfo->h_FrmReplicForAdd = + p_KeyParams->ccNextEngineParams.params.frParams.h_FrmReplic; +#endif /* (DPAA_VERSION >= 11) */ + + if (!add) + { + if (p_CcNode->keyAndNextEngineParams[keyIndex].nextEngineParams.nextEngine + == e_FM_PCD_CC) + p_AdditionalInfo->h_NodeForRmv = + p_CcNode->keyAndNextEngineParams[keyIndex].nextEngineParams.params.ccParams.h_CcNode; + + if (p_CcNode->keyAndNextEngineParams[keyIndex].nextEngineParams.h_Manip) + p_AdditionalInfo->h_ManipForRmv = + p_CcNode->keyAndNextEngineParams[keyIndex].nextEngineParams.h_Manip; + + /* If statistics were previously enabled, store the old statistics object to be released */ + if (p_CcNode->keyAndNextEngineParams[keyIndex].p_StatsObj) + { + p_AdditionalInfo->p_StatsObjForRmv = + p_CcNode->keyAndNextEngineParams[keyIndex].p_StatsObj; + } + +#if (DPAA_VERSION >= 11) + if ((p_CcNode->keyAndNextEngineParams[keyIndex].nextEngineParams.nextEngine + == e_FM_PCD_FR) + && (p_CcNode->keyAndNextEngineParams[keyIndex].nextEngineParams.params.frParams.h_FrmReplic)) + p_AdditionalInfo->h_FrmReplicForRmv = + p_CcNode->keyAndNextEngineParams[keyIndex].nextEngineParams.params.frParams.h_FrmReplic; +#endif /* (DPAA_VERSION >= 11) */ + } + + return E_OK; +} + +static t_Error BuildNewNodeRemoveKey( + t_FmPcdCcNode *p_CcNode, uint16_t keyIndex, + t_FmPcdModifyCcKeyAdditionalParams *p_AdditionalInfo) +{ + int i = 0, j = 0; + t_Handle p_AdTableNewTmp, p_KeysMatchTableNewTmp; + t_Handle p_KeysMatchTableOldTmp, p_AdTableOldTmp; + int size; + t_Error err = E_OK; + + /*save new numOfKeys*/ + p_AdditionalInfo->numOfKeys = (uint16_t)(p_CcNode->numOfKeys - 1); + + /*function which allocates in the memory new KeyTbl, AdTbl*/ + err = BuildNewNodeCommonPart(p_CcNode, &size, p_AdditionalInfo); + if (err) + RETURN_ERROR(MAJOR, err, NO_MSG); + + /*update new Ad and new Key Table according to new requirement*/ + for (i = 0, j = 0; j < p_CcNode->numOfKeys; i++, j++) + { + if (j == keyIndex) + j++; + + if (j == p_CcNode->numOfKeys) + break; + p_AdTableNewTmp = + PTR_MOVE(p_AdditionalInfo->p_AdTableNew, i * FM_PCD_CC_AD_ENTRY_SIZE); + p_AdTableOldTmp = + PTR_MOVE(p_AdditionalInfo->p_AdTableOld, j * FM_PCD_CC_AD_ENTRY_SIZE); + MemCpy8(p_AdTableNewTmp, p_AdTableOldTmp, FM_PCD_CC_AD_ENTRY_SIZE); + + p_KeysMatchTableOldTmp = + PTR_MOVE(p_AdditionalInfo->p_KeysMatchTableOld, j * size * sizeof(uint8_t)); + p_KeysMatchTableNewTmp = + PTR_MOVE(p_AdditionalInfo->p_KeysMatchTableNew, i * size * sizeof(uint8_t)); + MemCpy8(p_KeysMatchTableNewTmp, p_KeysMatchTableOldTmp, + size * sizeof(uint8_t)); + } + + p_AdTableNewTmp = + PTR_MOVE(p_AdditionalInfo->p_AdTableNew, i * FM_PCD_CC_AD_ENTRY_SIZE); + p_AdTableOldTmp = + PTR_MOVE(p_AdditionalInfo->p_AdTableOld, j * FM_PCD_CC_AD_ENTRY_SIZE); + MemCpy8(p_AdTableNewTmp, p_AdTableOldTmp, FM_PCD_CC_AD_ENTRY_SIZE); + + if (p_CcNode->keyAndNextEngineParams[keyIndex].nextEngineParams.nextEngine + == e_FM_PCD_CC) + p_AdditionalInfo->h_NodeForRmv = + p_CcNode->keyAndNextEngineParams[keyIndex].nextEngineParams.params.ccParams.h_CcNode; + + if (p_CcNode->keyAndNextEngineParams[keyIndex].nextEngineParams.h_Manip) + p_AdditionalInfo->h_ManipForRmv = + p_CcNode->keyAndNextEngineParams[keyIndex].nextEngineParams.h_Manip; + + /* If statistics were previously enabled, store the old statistics object to be released */ + if (p_CcNode->keyAndNextEngineParams[keyIndex].p_StatsObj) + { + p_AdditionalInfo->p_StatsObjForRmv = + p_CcNode->keyAndNextEngineParams[keyIndex].p_StatsObj; + } + +#if (DPAA_VERSION >= 11) + if ((p_CcNode->keyAndNextEngineParams[keyIndex].nextEngineParams.nextEngine + == e_FM_PCD_FR) + && (p_CcNode->keyAndNextEngineParams[keyIndex].nextEngineParams.params.frParams.h_FrmReplic)) + p_AdditionalInfo->h_FrmReplicForRmv = + p_CcNode->keyAndNextEngineParams[keyIndex].nextEngineParams.params.frParams.h_FrmReplic; +#endif /* (DPAA_VERSION >= 11) */ + + return E_OK; +} + +static t_Error BuildNewNodeModifyKey( + t_FmPcdCcNode *p_CcNode, uint16_t keyIndex, uint8_t *p_Key, + uint8_t *p_Mask, t_FmPcdModifyCcKeyAdditionalParams *p_AdditionalInfo) +{ + t_FmPcd *p_FmPcd = (t_FmPcd *)p_CcNode->h_FmPcd; + t_Error err = E_OK; + t_Handle p_AdTableNewTmp, p_KeysMatchTableNewTmp; + t_Handle p_KeysMatchTableOldTmp, p_AdTableOldTmp; + int size; + int i = 0, j = 0; + bool prvLclMask; + t_FmPcdStatsObj *p_StatsObj, tmpStatsObj; + p_AdditionalInfo->numOfKeys = p_CcNode->numOfKeys; + + prvLclMask = p_CcNode->lclMask; + + /* Check that new key is not require update of localMask */ + err = UpdateGblMask(p_CcNode, p_CcNode->ccKeySizeAccExtraction, p_Mask); + if (err) + RETURN_ERROR(MAJOR, err, (NO_MSG)); + + /* Update internal data structure with new next engine for the given index */ + memcpy(p_AdditionalInfo->keyAndNextEngineParams[keyIndex].key, p_Key, + p_CcNode->userSizeOfExtraction); + + if (p_Mask) + memcpy(p_AdditionalInfo->keyAndNextEngineParams[keyIndex].mask, p_Mask, + p_CcNode->userSizeOfExtraction); + else + memset(p_AdditionalInfo->keyAndNextEngineParams[keyIndex].mask, 0xFF, + p_CcNode->userSizeOfExtraction); + + /*function which build in the memory new KeyTbl, AdTbl*/ + err = BuildNewNodeCommonPart(p_CcNode, &size, p_AdditionalInfo); + if (err) + RETURN_ERROR(MAJOR, err, NO_MSG); + + /*fill the New AdTable and New KeyTable*/ + for (j = 0, i = 0; j < p_AdditionalInfo->numOfKeys; j++, i++) + { + p_AdTableNewTmp = + PTR_MOVE(p_AdditionalInfo->p_AdTableNew, j*FM_PCD_CC_AD_ENTRY_SIZE); + p_AdTableOldTmp = + PTR_MOVE(p_AdditionalInfo->p_AdTableOld, i*FM_PCD_CC_AD_ENTRY_SIZE); + + MemCpy8(p_AdTableNewTmp, p_AdTableOldTmp, FM_PCD_CC_AD_ENTRY_SIZE); + + if (j == keyIndex) + { + ASSERT_COND(keyIndex < CC_MAX_NUM_OF_KEYS); + if (p_CcNode->keyAndNextEngineParams[keyIndex].p_StatsObj) + { + /* As statistics were enabled, we need to update the existing + statistics descriptor with a new nullified counters. */ + p_StatsObj = GetStatsObj(p_CcNode); + ASSERT_COND(p_StatsObj); + + SetStatsCounters( + p_AdTableNewTmp, + (uint32_t)((XX_VirtToPhys(p_StatsObj->h_StatsCounters) + - p_FmPcd->physicalMuramBase))); + + tmpStatsObj.h_StatsAd = p_StatsObj->h_StatsAd; + tmpStatsObj.h_StatsCounters = p_StatsObj->h_StatsCounters; + + /* As we need to replace only the counters, we build a new statistics + object that holds the old AD and the new counters - this will be the + currently used statistics object. + The newly allocated AD is not required and may be released back to + the available objects with the previous counters pointer. */ + p_StatsObj->h_StatsAd = + p_CcNode->keyAndNextEngineParams[keyIndex].p_StatsObj->h_StatsAd; + + p_CcNode->keyAndNextEngineParams[keyIndex].p_StatsObj->h_StatsAd = + tmpStatsObj.h_StatsAd; + + /* Store allocated statistics object */ + p_AdditionalInfo->keyAndNextEngineParams[keyIndex].p_StatsObj = + p_StatsObj; + + /* As statistics were previously enabled, store the old statistics object to be released */ + p_AdditionalInfo->p_StatsObjForRmv = + p_CcNode->keyAndNextEngineParams[keyIndex].p_StatsObj; + } + + p_KeysMatchTableNewTmp = + PTR_MOVE(p_AdditionalInfo->p_KeysMatchTableNew, j * size * sizeof(uint8_t)); + + MemCpy8(p_KeysMatchTableNewTmp, p_Key, + p_CcNode->userSizeOfExtraction); + + if (p_CcNode->lclMask) + { + if (p_Mask) + MemCpy8(PTR_MOVE(p_KeysMatchTableNewTmp, + p_CcNode->ccKeySizeAccExtraction), + p_Mask, p_CcNode->userSizeOfExtraction); + else + if (p_CcNode->ccKeySizeAccExtraction > 4) + MemSet8(PTR_MOVE(p_KeysMatchTableNewTmp, + p_CcNode->ccKeySizeAccExtraction), + 0xff, p_CcNode->userSizeOfExtraction); + else + MemCpy8(PTR_MOVE(p_KeysMatchTableNewTmp, + p_CcNode->ccKeySizeAccExtraction), + p_CcNode->p_GlblMask, + p_CcNode->userSizeOfExtraction); + } + } + else + { + p_KeysMatchTableNewTmp = + PTR_MOVE(p_AdditionalInfo->p_KeysMatchTableNew, j * size * sizeof(uint8_t)); + p_KeysMatchTableOldTmp = + PTR_MOVE(p_CcNode->h_KeysMatchTable, i * size * sizeof(uint8_t)); + + if (p_CcNode->lclMask) + { + if (prvLclMask) + MemCpy8( + PTR_MOVE(p_KeysMatchTableNewTmp, p_CcNode->ccKeySizeAccExtraction), + PTR_MOVE(p_KeysMatchTableOldTmp, p_CcNode->ccKeySizeAccExtraction), + p_CcNode->userSizeOfExtraction); + else + { + p_KeysMatchTableOldTmp = + PTR_MOVE(p_CcNode->h_KeysMatchTable, + i * (int)p_CcNode->ccKeySizeAccExtraction * sizeof(uint8_t)); + + if (p_CcNode->ccKeySizeAccExtraction > 4) + MemSet8(PTR_MOVE(p_KeysMatchTableNewTmp, + p_CcNode->ccKeySizeAccExtraction), + 0xff, p_CcNode->userSizeOfExtraction); + else + MemCpy8( + PTR_MOVE(p_KeysMatchTableNewTmp, p_CcNode->ccKeySizeAccExtraction), + p_CcNode->p_GlblMask, + p_CcNode->userSizeOfExtraction); + } + } + MemCpy8((void*)p_KeysMatchTableNewTmp, p_KeysMatchTableOldTmp, + p_CcNode->ccKeySizeAccExtraction); + } + } + + p_AdTableNewTmp = + PTR_MOVE(p_AdditionalInfo->p_AdTableNew, j * FM_PCD_CC_AD_ENTRY_SIZE); + p_AdTableOldTmp = PTR_MOVE(p_CcNode->h_AdTable, i * FM_PCD_CC_AD_ENTRY_SIZE); + + MemCpy8(p_AdTableNewTmp, p_AdTableOldTmp, FM_PCD_CC_AD_ENTRY_SIZE); + + return E_OK; +} + +static t_Error BuildNewNodeModifyNextEngine( + t_Handle h_FmPcd, t_Handle h_FmPcdCcNodeOrTree, uint16_t keyIndex, + t_FmPcdCcNextEngineParams *p_CcNextEngineParams, t_List *h_OldLst, + t_List *h_NewLst, t_FmPcdModifyCcKeyAdditionalParams *p_AdditionalInfo) +{ + t_Error err = E_OK; + uint32_t requiredAction = 0; + t_List *p_Pos; + t_CcNodeInformation *p_CcNodeInformation, ccNodeInfo; + t_Handle p_Ad; + t_FmPcdCcNode *p_FmPcdCcNode1 = NULL; + t_FmPcdCcTree *p_FmPcdCcTree = NULL; + t_FmPcdStatsObj *p_StatsObj; + t_FmPcdCcStatsParams statsParams = { 0 }; + + ASSERT_COND(p_CcNextEngineParams); + + /* check that new NIA is legal */ + if (!p_AdditionalInfo->tree) + err = ValidateNextEngineParams( + h_FmPcd, p_CcNextEngineParams, + ((t_FmPcdCcNode *)h_FmPcdCcNodeOrTree)->statisticsMode); + else + /* Statistics are not supported for CC root */ + err = ValidateNextEngineParams(h_FmPcd, p_CcNextEngineParams, + e_FM_PCD_CC_STATS_MODE_NONE); + if (err) + RETURN_ERROR(MAJOR, err, NO_MSG); + + /* Update internal data structure for next engine per index (index - key) */ + memcpy(&p_AdditionalInfo->keyAndNextEngineParams[keyIndex].nextEngineParams, + p_CcNextEngineParams, sizeof(t_FmPcdCcNextEngineParams)); + + /* Check that manip is legal and what requiredAction is necessary for this manip */ + if (p_CcNextEngineParams->h_Manip) + { + err = FmPcdManipCheckParamsForCcNextEngine(p_CcNextEngineParams, + &requiredAction); + if (err) + RETURN_ERROR(MAJOR, err, (NO_MSG)); + } + + if (!p_AdditionalInfo->tree) + { + p_FmPcdCcNode1 = (t_FmPcdCcNode *)h_FmPcdCcNodeOrTree; + p_AdditionalInfo->numOfKeys = p_FmPcdCcNode1->numOfKeys; + p_Ad = p_FmPcdCcNode1->h_AdTable; + + if (p_FmPcdCcNode1->keyAndNextEngineParams[keyIndex].nextEngineParams.nextEngine + == e_FM_PCD_CC) + p_AdditionalInfo->h_NodeForRmv = + p_FmPcdCcNode1->keyAndNextEngineParams[keyIndex].nextEngineParams.params.ccParams.h_CcNode; + + if (p_FmPcdCcNode1->keyAndNextEngineParams[keyIndex].nextEngineParams.h_Manip) + p_AdditionalInfo->h_ManipForRmv = + p_FmPcdCcNode1->keyAndNextEngineParams[keyIndex].nextEngineParams.h_Manip; + +#if (DPAA_VERSION >= 11) + if ((p_FmPcdCcNode1->keyAndNextEngineParams[keyIndex].nextEngineParams.nextEngine + == e_FM_PCD_FR) + && (p_FmPcdCcNode1->keyAndNextEngineParams[keyIndex].nextEngineParams.params.frParams.h_FrmReplic)) + p_AdditionalInfo->h_FrmReplicForRmv = + p_FmPcdCcNode1->keyAndNextEngineParams[keyIndex].nextEngineParams.params.frParams.h_FrmReplic; +#endif /* (DPAA_VERSION >= 11) */ + } + else + { + p_FmPcdCcTree = (t_FmPcdCcTree *)h_FmPcdCcNodeOrTree; + p_Ad = UINT_TO_PTR(p_FmPcdCcTree->ccTreeBaseAddr); + + if (p_FmPcdCcTree->keyAndNextEngineParams[keyIndex].nextEngineParams.nextEngine + == e_FM_PCD_CC) + p_AdditionalInfo->h_NodeForRmv = + p_FmPcdCcTree->keyAndNextEngineParams[keyIndex].nextEngineParams.params.ccParams.h_CcNode; + + if (p_FmPcdCcTree->keyAndNextEngineParams[keyIndex].nextEngineParams.h_Manip) + p_AdditionalInfo->h_ManipForRmv = + p_FmPcdCcTree->keyAndNextEngineParams[keyIndex].nextEngineParams.h_Manip; + +#if (DPAA_VERSION >= 11) + if ((p_FmPcdCcTree->keyAndNextEngineParams[keyIndex].nextEngineParams.nextEngine + == e_FM_PCD_FR) + && (p_FmPcdCcTree->keyAndNextEngineParams[keyIndex].nextEngineParams.params.frParams.h_FrmReplic)) + p_AdditionalInfo->h_FrmReplicForRmv = + p_FmPcdCcTree->keyAndNextEngineParams[keyIndex].nextEngineParams.params.frParams.h_FrmReplic; +#endif /* (DPAA_VERSION >= 11) */ + } + + if ((p_CcNextEngineParams->nextEngine == e_FM_PCD_CC) + && p_CcNextEngineParams->h_Manip) + { + err = AllocAndFillAdForContLookupManip( + p_CcNextEngineParams->params.ccParams.h_CcNode); + if (err) + RETURN_ERROR(MAJOR, err, (NO_MSG)); + } + + ASSERT_COND(p_Ad); + + memset(&ccNodeInfo, 0, sizeof(t_CcNodeInformation)); + ccNodeInfo.h_CcNode = PTR_MOVE(p_Ad, keyIndex * FM_PCD_CC_AD_ENTRY_SIZE); + + /* If statistics were enabled, this Ad is the statistics Ad. Need to follow its + nextAction to retrieve the actual Nia-Ad. If statistics should remain enabled, + only the actual Nia-Ad should be modified. */ + if ((!p_AdditionalInfo->tree) + && (((t_FmPcdCcNode *)h_FmPcdCcNodeOrTree)->keyAndNextEngineParams[keyIndex].p_StatsObj) + && (p_CcNextEngineParams->statisticsEn)) + ccNodeInfo.h_CcNode = + ((t_FmPcdCcNode *)h_FmPcdCcNodeOrTree)->keyAndNextEngineParams[keyIndex].p_StatsObj->h_StatsAd; + + EnqueueNodeInfoToRelevantLst(h_OldLst, &ccNodeInfo, NULL); + + memset(&ccNodeInfo, 0, sizeof(t_CcNodeInformation)); + p_Ad = GetNewAd(h_FmPcdCcNodeOrTree, p_AdditionalInfo->tree); + if (!p_Ad) + RETURN_ERROR(MAJOR, E_NO_MEMORY, + ("MURAM allocation for CC node action descriptor")); + MemSet8((uint8_t *)p_Ad, 0, FM_PCD_CC_AD_ENTRY_SIZE); + + /* If statistics were not enabled before, but requested now - Allocate a statistics + object that holds statistics AD and counters. */ + if ((!p_AdditionalInfo->tree) + && (!((t_FmPcdCcNode *)h_FmPcdCcNodeOrTree)->keyAndNextEngineParams[keyIndex].p_StatsObj) + && (p_CcNextEngineParams->statisticsEn)) + { + p_StatsObj = GetStatsObj((t_FmPcdCcNode *)h_FmPcdCcNodeOrTree); + ASSERT_COND(p_StatsObj); + + /* Store allocated statistics object */ + p_AdditionalInfo->keyAndNextEngineParams[keyIndex].p_StatsObj = + p_StatsObj; + + statsParams.h_StatsAd = p_StatsObj->h_StatsAd; + statsParams.h_StatsCounters = p_StatsObj->h_StatsCounters; + +#if (DPAA_VERSION >= 11) + statsParams.h_StatsFLRs = + ((t_FmPcdCcNode *)h_FmPcdCcNodeOrTree)->h_StatsFLRs; + +#endif /* (DPAA_VERSION >= 11) */ + + NextStepAd(p_Ad, &statsParams, p_CcNextEngineParams, h_FmPcd); + } + else + NextStepAd(p_Ad, NULL, p_CcNextEngineParams, h_FmPcd); + + ccNodeInfo.h_CcNode = p_Ad; + EnqueueNodeInfoToRelevantLst(h_NewLst, &ccNodeInfo, NULL); + + p_AdditionalInfo->keyAndNextEngineParams[keyIndex].requiredAction = + requiredAction; + p_AdditionalInfo->keyAndNextEngineParams[keyIndex].requiredAction |= + UPDATE_CC_WITH_TREE; + + if (!p_AdditionalInfo->tree) + { + ASSERT_COND(p_FmPcdCcNode1); + if (!LIST_IsEmpty(&p_FmPcdCcNode1->ccTreesLst)) + { + LIST_FOR_EACH(p_Pos, &p_FmPcdCcNode1->ccTreesLst) + { + p_CcNodeInformation = CC_NODE_F_OBJECT(p_Pos); + + ASSERT_COND(p_CcNodeInformation->h_CcNode); + /* Update the manipulation which has to be updated from parameters of the port + it's has to be updated with restrictions defined in the function */ + + err = + SetRequiredAction( + p_FmPcdCcNode1->h_FmPcd, + p_FmPcdCcNode1->shadowAction + | p_AdditionalInfo->keyAndNextEngineParams[keyIndex].requiredAction, + &p_AdditionalInfo->keyAndNextEngineParams[keyIndex], + p_Ad, 1, p_CcNodeInformation->h_CcNode); + if (err) + RETURN_ERROR(MAJOR, err, (NO_MSG)); + + err = CcUpdateParam( + p_FmPcdCcNode1->h_FmPcd, NULL, NULL, + &p_AdditionalInfo->keyAndNextEngineParams[keyIndex], 1, + p_Ad, TRUE, p_CcNodeInformation->index, + p_CcNodeInformation->h_CcNode, TRUE); + if (err) + RETURN_ERROR(MAJOR, err, (NO_MSG)); + } + } + } + else + { + ASSERT_COND(p_FmPcdCcTree); + + err = + SetRequiredAction( + h_FmPcd, + p_FmPcdCcTree->requiredAction + | p_AdditionalInfo->keyAndNextEngineParams[keyIndex].requiredAction, + &p_AdditionalInfo->keyAndNextEngineParams[keyIndex], + p_Ad, 1, (t_Handle)p_FmPcdCcTree); + if (err) + RETURN_ERROR(MAJOR, err, (NO_MSG)); + + err = CcUpdateParam(h_FmPcd, NULL, NULL, + &p_AdditionalInfo->keyAndNextEngineParams[keyIndex], + 1, p_Ad, TRUE, 0, (t_Handle)p_FmPcdCcTree, TRUE); + if (err) + RETURN_ERROR(MAJOR, err, (NO_MSG)); + } + + if (p_CcNextEngineParams->nextEngine == e_FM_PCD_CC) + p_AdditionalInfo->h_NodeForAdd = + p_CcNextEngineParams->params.ccParams.h_CcNode; + if (p_CcNextEngineParams->h_Manip) + p_AdditionalInfo->h_ManipForAdd = p_CcNextEngineParams->h_Manip; + + /* If statistics were previously enabled, but now are disabled, + store the old statistics object to be released */ + if ((!p_AdditionalInfo->tree) + && (((t_FmPcdCcNode *)h_FmPcdCcNodeOrTree)->keyAndNextEngineParams[keyIndex].p_StatsObj) + && (!p_CcNextEngineParams->statisticsEn)) + { + p_AdditionalInfo->p_StatsObjForRmv = + ((t_FmPcdCcNode *)h_FmPcdCcNodeOrTree)->keyAndNextEngineParams[keyIndex].p_StatsObj; + + + p_AdditionalInfo->keyAndNextEngineParams[keyIndex].p_StatsObj = NULL; + } +#if (DPAA_VERSION >= 11) + if ((p_CcNextEngineParams->nextEngine == e_FM_PCD_FR) + && (p_CcNextEngineParams->params.frParams.h_FrmReplic)) + p_AdditionalInfo->h_FrmReplicForAdd = + p_CcNextEngineParams->params.frParams.h_FrmReplic; +#endif /* (DPAA_VERSION >= 11) */ + + return E_OK; +} + +static void UpdateAdPtrOfNodesWhichPointsOnCrntMdfNode( + t_FmPcdCcNode *p_CrntMdfNode, t_List *h_OldLst, + t_FmPcdCcNextEngineParams **p_NextEngineParams) +{ + t_CcNodeInformation *p_CcNodeInformation; + t_FmPcdCcNode *p_NodePtrOnCurrentMdfNode = NULL; + t_List *p_Pos; + int i = 0; + t_Handle p_AdTablePtOnCrntCurrentMdfNode/*, p_AdTableNewModified*/; + t_CcNodeInformation ccNodeInfo; + + LIST_FOR_EACH(p_Pos, &p_CrntMdfNode->ccPrevNodesLst) + { + p_CcNodeInformation = CC_NODE_F_OBJECT(p_Pos); + p_NodePtrOnCurrentMdfNode = + (t_FmPcdCcNode *)p_CcNodeInformation->h_CcNode; + + ASSERT_COND(p_NodePtrOnCurrentMdfNode); + + /* Search in the previous node which exact index points on this current modified node for getting AD */ + for (i = 0; i < p_NodePtrOnCurrentMdfNode->numOfKeys + 1; i++) + { + if (p_NodePtrOnCurrentMdfNode->keyAndNextEngineParams[i].nextEngineParams.nextEngine + == e_FM_PCD_CC) + { + if (p_NodePtrOnCurrentMdfNode->keyAndNextEngineParams[i].nextEngineParams.params.ccParams.h_CcNode + == (t_Handle)p_CrntMdfNode) + { + if (p_NodePtrOnCurrentMdfNode->keyAndNextEngineParams[i].nextEngineParams.h_Manip) + p_AdTablePtOnCrntCurrentMdfNode = p_CrntMdfNode->h_Ad; + else + if (p_NodePtrOnCurrentMdfNode->keyAndNextEngineParams[i].p_StatsObj) + p_AdTablePtOnCrntCurrentMdfNode = + p_NodePtrOnCurrentMdfNode->keyAndNextEngineParams[i].p_StatsObj->h_StatsAd; + else + p_AdTablePtOnCrntCurrentMdfNode = + PTR_MOVE(p_NodePtrOnCurrentMdfNode->h_AdTable, i*FM_PCD_CC_AD_ENTRY_SIZE); + + memset(&ccNodeInfo, 0, sizeof(t_CcNodeInformation)); + ccNodeInfo.h_CcNode = p_AdTablePtOnCrntCurrentMdfNode; + EnqueueNodeInfoToRelevantLst(h_OldLst, &ccNodeInfo, NULL); + + if (!(*p_NextEngineParams)) + *p_NextEngineParams = + &p_NodePtrOnCurrentMdfNode->keyAndNextEngineParams[i].nextEngineParams; + } + } + } + + ASSERT_COND(i != p_NodePtrOnCurrentMdfNode->numOfKeys); + } +} + +static void UpdateAdPtrOfTreesWhichPointsOnCrntMdfNode( + t_FmPcdCcNode *p_CrntMdfNode, t_List *h_OldLst, + t_FmPcdCcNextEngineParams **p_NextEngineParams) +{ + t_CcNodeInformation *p_CcNodeInformation; + t_FmPcdCcTree *p_TreePtrOnCurrentMdfNode = NULL; + t_List *p_Pos; + int i = 0; + t_Handle p_AdTableTmp; + t_CcNodeInformation ccNodeInfo; + + LIST_FOR_EACH(p_Pos, &p_CrntMdfNode->ccTreeIdLst) + { + p_CcNodeInformation = CC_NODE_F_OBJECT(p_Pos); + p_TreePtrOnCurrentMdfNode = + (t_FmPcdCcTree *)p_CcNodeInformation->h_CcNode; + + ASSERT_COND(p_TreePtrOnCurrentMdfNode); + + /*search in the trees which exact index points on this current modified node for getting AD */ + for (i = 0; i < p_TreePtrOnCurrentMdfNode->numOfEntries; i++) + { + if (p_TreePtrOnCurrentMdfNode->keyAndNextEngineParams[i].nextEngineParams.nextEngine + == e_FM_PCD_CC) + { + if (p_TreePtrOnCurrentMdfNode->keyAndNextEngineParams[i].nextEngineParams.params.ccParams.h_CcNode + == (t_Handle)p_CrntMdfNode) + { + p_AdTableTmp = + UINT_TO_PTR(p_TreePtrOnCurrentMdfNode->ccTreeBaseAddr + i*FM_PCD_CC_AD_ENTRY_SIZE); + memset(&ccNodeInfo, 0, sizeof(t_CcNodeInformation)); + ccNodeInfo.h_CcNode = p_AdTableTmp; + EnqueueNodeInfoToRelevantLst(h_OldLst, &ccNodeInfo, NULL); + + if (!(*p_NextEngineParams)) + *p_NextEngineParams = + &p_TreePtrOnCurrentMdfNode->keyAndNextEngineParams[i].nextEngineParams; + } + } + } + + ASSERT_COND(i == p_TreePtrOnCurrentMdfNode->numOfEntries); + } +} + +static t_FmPcdModifyCcKeyAdditionalParams * ModifyNodeCommonPart( + t_Handle h_FmPcdCcNodeOrTree, uint16_t keyIndex, + e_ModifyState modifyState, bool ttlCheck, bool hashCheck, bool tree) +{ + t_FmPcdModifyCcKeyAdditionalParams *p_FmPcdModifyCcKeyAdditionalParams; + int i = 0, j = 0; + bool wasUpdate = FALSE; + t_FmPcdCcNode *p_CcNode = NULL; + t_FmPcdCcTree *p_FmPcdCcTree; + uint16_t numOfKeys; + t_FmPcdCcKeyAndNextEngineParams *p_KeyAndNextEngineParams; + + SANITY_CHECK_RETURN_VALUE(h_FmPcdCcNodeOrTree, E_INVALID_HANDLE, NULL); + + if (!tree) + { + p_CcNode = (t_FmPcdCcNode *)h_FmPcdCcNodeOrTree; + numOfKeys = p_CcNode->numOfKeys; + + /* node has to be pointed by another node or tree */ + + p_KeyAndNextEngineParams = (t_FmPcdCcKeyAndNextEngineParams *)XX_Malloc( + sizeof(t_FmPcdCcKeyAndNextEngineParams) * (numOfKeys + 1)); + if (!p_KeyAndNextEngineParams) + { + REPORT_ERROR(MAJOR, E_NO_MEMORY, ("Next engine and required action structure")); + return NULL; + } + memcpy(p_KeyAndNextEngineParams, p_CcNode->keyAndNextEngineParams, + (numOfKeys + 1) * sizeof(t_FmPcdCcKeyAndNextEngineParams)); + + if (ttlCheck) + { + if ((p_CcNode->parseCode == CC_PC_FF_IPV4TTL) + || (p_CcNode->parseCode == CC_PC_FF_IPV6HOP_LIMIT)) + { + XX_Free(p_KeyAndNextEngineParams); + REPORT_ERROR(MAJOR, E_INVALID_VALUE, ("nodeId of CC_PC_FF_IPV4TTL or CC_PC_FF_IPV6HOP_LIMIT can not be used for this operation")); + return NULL; + } + } + + if (hashCheck) + { + if (p_CcNode->parseCode == CC_PC_GENERIC_IC_HASH_INDEXED) + { + XX_Free(p_KeyAndNextEngineParams); + REPORT_ERROR(MAJOR, E_INVALID_VALUE, ("nodeId of CC_PC_GENERIC_IC_HASH_INDEXED can not be used for this operation")); + return NULL; + } + } + } + else + { + p_FmPcdCcTree = (t_FmPcdCcTree *)h_FmPcdCcNodeOrTree; + numOfKeys = p_FmPcdCcTree->numOfEntries; + + p_KeyAndNextEngineParams = (t_FmPcdCcKeyAndNextEngineParams *)XX_Malloc( + sizeof(t_FmPcdCcKeyAndNextEngineParams) + * FM_PCD_MAX_NUM_OF_CC_GROUPS); + if (!p_KeyAndNextEngineParams) + { + REPORT_ERROR(MAJOR, E_NO_MEMORY, ("Next engine and required action structure")); + return NULL; + } + memcpy(p_KeyAndNextEngineParams, + p_FmPcdCcTree->keyAndNextEngineParams, + FM_PCD_MAX_NUM_OF_CC_GROUPS + * sizeof(t_FmPcdCcKeyAndNextEngineParams)); + } + + p_FmPcdModifyCcKeyAdditionalParams = + (t_FmPcdModifyCcKeyAdditionalParams *)XX_Malloc( + sizeof(t_FmPcdModifyCcKeyAdditionalParams)); + if (!p_FmPcdModifyCcKeyAdditionalParams) + { + XX_Free(p_KeyAndNextEngineParams); + REPORT_ERROR(MAJOR, E_NO_MEMORY, ("Allocation of internal data structure FAILED")); + return NULL; + } + memset(p_FmPcdModifyCcKeyAdditionalParams, 0, + sizeof(t_FmPcdModifyCcKeyAdditionalParams)); + + p_FmPcdModifyCcKeyAdditionalParams->h_CurrentNode = h_FmPcdCcNodeOrTree; + p_FmPcdModifyCcKeyAdditionalParams->savedKeyIndex = keyIndex; + + while (i < numOfKeys) + { + if ((j == keyIndex) && !wasUpdate) + { + if (modifyState == e_MODIFY_STATE_ADD) + j++; + else + if (modifyState == e_MODIFY_STATE_REMOVE) + i++; + wasUpdate = TRUE; + } + else + { + memcpy(&p_FmPcdModifyCcKeyAdditionalParams->keyAndNextEngineParams[j], + p_KeyAndNextEngineParams + i, + sizeof(t_FmPcdCcKeyAndNextEngineParams)); + i++; + j++; + } + } + + if (keyIndex == numOfKeys) + { + if (modifyState == e_MODIFY_STATE_ADD) + j++; + } + + memcpy(&p_FmPcdModifyCcKeyAdditionalParams->keyAndNextEngineParams[j], + p_KeyAndNextEngineParams + numOfKeys, + sizeof(t_FmPcdCcKeyAndNextEngineParams)); + + XX_Free(p_KeyAndNextEngineParams); + + return p_FmPcdModifyCcKeyAdditionalParams; +} + +static t_Error UpdatePtrWhichPointOnCrntMdfNode( + t_FmPcdCcNode *p_CcNode, + t_FmPcdModifyCcKeyAdditionalParams *p_FmPcdModifyCcKeyAdditionalParams, + t_List *h_OldLst, t_List *h_NewLst) +{ + t_FmPcdCcNextEngineParams *p_NextEngineParams = NULL; + t_CcNodeInformation ccNodeInfo = { 0 }; + t_Handle h_NewAd; + t_Handle h_OrigAd = NULL; + + /* Building a list of all action descriptors that point to the previous node */ + if (!LIST_IsEmpty(&p_CcNode->ccPrevNodesLst)) + UpdateAdPtrOfNodesWhichPointsOnCrntMdfNode(p_CcNode, h_OldLst, + &p_NextEngineParams); + + if (!LIST_IsEmpty(&p_CcNode->ccTreeIdLst)) + UpdateAdPtrOfTreesWhichPointsOnCrntMdfNode(p_CcNode, h_OldLst, + &p_NextEngineParams); + + /* This node must be found as next engine of one of its previous nodes or trees*/ + if (p_NextEngineParams) + { + /* Building a new action descriptor that points to the modified node */ + h_NewAd = GetNewAd(p_CcNode, FALSE); + if (!h_NewAd) + RETURN_ERROR(MAJOR, E_NO_MEMORY, NO_MSG); + MemSet8(h_NewAd, 0, FM_PCD_CC_AD_ENTRY_SIZE); + + h_OrigAd = p_CcNode->h_Ad; + BuildNewAd(h_NewAd, p_FmPcdModifyCcKeyAdditionalParams, p_CcNode, + p_NextEngineParams); + + ccNodeInfo.h_CcNode = h_NewAd; + EnqueueNodeInfoToRelevantLst(h_NewLst, &ccNodeInfo, NULL); + + if (p_NextEngineParams->h_Manip && !h_OrigAd) + FmPcdManipUpdateOwner(p_NextEngineParams->h_Manip, FALSE); + } + return E_OK; +} + +static void UpdateCcRootOwner(t_FmPcdCcTree *p_FmPcdCcTree, bool add) +{ + ASSERT_COND(p_FmPcdCcTree); + + /* this routine must be protected by the calling routine! */ + + if (add) + p_FmPcdCcTree->owners++; + else + { + ASSERT_COND(p_FmPcdCcTree->owners); + p_FmPcdCcTree->owners--; + } +} + +static t_Error CheckAndSetManipParamsWithCcNodeParams(t_FmPcdCcNode *p_CcNode) +{ + t_Error err = E_OK; + int i = 0; + + for (i = 0; i < p_CcNode->numOfKeys; i++) + { + if (p_CcNode->keyAndNextEngineParams[i].nextEngineParams.h_Manip) + { + err = + FmPcdManipCheckParamsWithCcNodeParams( + p_CcNode->keyAndNextEngineParams[i].nextEngineParams.h_Manip, + (t_Handle)p_CcNode); + if (err) + return err; + } + } + + return err; +} +static t_Error ValidateAndCalcStatsParams(t_FmPcdCcNode *p_CcNode, + t_FmPcdCcNodeParams *p_CcNodeParam, + uint32_t *p_NumOfRanges, + uint32_t *p_CountersArraySize) +{ + e_FmPcdCcStatsMode statisticsMode = p_CcNode->statisticsMode; + uint32_t i; + + UNUSED(p_CcNodeParam); + + switch (statisticsMode) + { + case e_FM_PCD_CC_STATS_MODE_NONE: + for (i = 0; i < p_CcNode->numOfKeys; i++) + if (p_CcNodeParam->keysParams.keyParams[i].ccNextEngineParams.statisticsEn) + RETURN_ERROR( + MAJOR, + E_INVALID_VALUE, + ("Statistics cannot be enabled for key %d when statistics mode was set to 'NONE'", i)); + return E_OK; + + case e_FM_PCD_CC_STATS_MODE_FRAME: + case e_FM_PCD_CC_STATS_MODE_BYTE_AND_FRAME: + *p_NumOfRanges = 1; + *p_CountersArraySize = 2 * FM_PCD_CC_STATS_COUNTER_SIZE; + return E_OK; + +#if (DPAA_VERSION >= 11) + case e_FM_PCD_CC_STATS_MODE_RMON: + { + uint16_t *p_FrameLengthRanges = + p_CcNodeParam->keysParams.frameLengthRanges; + uint32_t i; + + if (p_FrameLengthRanges[0] <= 0) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("Statistics mode")); + + if (p_FrameLengthRanges[0] == 0xFFFF) + { + *p_NumOfRanges = 1; + *p_CountersArraySize = 2 * FM_PCD_CC_STATS_COUNTER_SIZE; + return E_OK; + } + + for (i = 1; i < FM_PCD_CC_STATS_MAX_NUM_OF_FLR; i++) + { + if (p_FrameLengthRanges[i - 1] >= p_FrameLengthRanges[i]) + RETURN_ERROR( + MAJOR, + E_INVALID_VALUE, + ("Frame length range must be larger at least by 1 from preceding range")); + + /* Stop when last range is reached */ + if (p_FrameLengthRanges[i] == 0xFFFF) + break; + } + + if ((i >= FM_PCD_CC_STATS_MAX_NUM_OF_FLR) + || (p_FrameLengthRanges[i] != 0xFFFF)) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, + ("Last Frame length range must be 0xFFFF")); + + *p_NumOfRanges = i + 1; + + /* Allocate an extra counter for byte count, as counters + array always begins with byte count */ + *p_CountersArraySize = (*p_NumOfRanges + 1) + * FM_PCD_CC_STATS_COUNTER_SIZE; + + } + return E_OK; +#endif /* (DPAA_VERSION >= 11) */ + + default: + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("Statistics mode")); + } +} + +static t_Error CheckParams(t_Handle h_FmPcd, t_FmPcdCcNodeParams *p_CcNodeParam, + t_FmPcdCcNode *p_CcNode, bool *isKeyTblAlloc) +{ + int tmp = 0; + t_FmPcdCcKeyParams *p_KeyParams; + t_Error err; + uint32_t requiredAction = 0; + + /* Validate statistics parameters */ + err = ValidateAndCalcStatsParams(p_CcNode, p_CcNodeParam, + &(p_CcNode->numOfStatsFLRs), + &(p_CcNode->countersArraySize)); + if (err) + RETURN_ERROR(MAJOR, err, ("Invalid statistics parameters")); + + /* Validate next engine parameters on Miss */ + err = ValidateNextEngineParams( + h_FmPcd, &p_CcNodeParam->keysParams.ccNextEngineParamsForMiss, + p_CcNode->statisticsMode); + if (err) + RETURN_ERROR(MAJOR, err, + ("For this node MissNextEngineParams are not valid")); + + if (p_CcNodeParam->keysParams.ccNextEngineParamsForMiss.h_Manip) + { + err = FmPcdManipCheckParamsForCcNextEngine( + &p_CcNodeParam->keysParams.ccNextEngineParamsForMiss, + &requiredAction); + if (err) + RETURN_ERROR(MAJOR, err, (NO_MSG)); + } + + memcpy(&p_CcNode->keyAndNextEngineParams[p_CcNode->numOfKeys].nextEngineParams, + &p_CcNodeParam->keysParams.ccNextEngineParamsForMiss, + sizeof(t_FmPcdCcNextEngineParams)); + + p_CcNode->keyAndNextEngineParams[p_CcNode->numOfKeys].requiredAction = + requiredAction; + + if ((p_CcNode->keyAndNextEngineParams[p_CcNode->numOfKeys].nextEngineParams.nextEngine + == e_FM_PCD_CC) + && p_CcNode->keyAndNextEngineParams[p_CcNode->numOfKeys].nextEngineParams.h_Manip) + { + err = + AllocAndFillAdForContLookupManip( + p_CcNode->keyAndNextEngineParams[p_CcNode->numOfKeys].nextEngineParams.params.ccParams.h_CcNode); + if (err) + RETURN_ERROR(MAJOR, err, (NO_MSG)); + } + + for (tmp = 0; tmp < p_CcNode->numOfKeys; tmp++) + { + p_KeyParams = &p_CcNodeParam->keysParams.keyParams[tmp]; + + if (!p_KeyParams->p_Key) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("p_Key is not initialized")); + + err = ValidateNextEngineParams(h_FmPcd, + &p_KeyParams->ccNextEngineParams, + p_CcNode->statisticsMode); + if (err) + RETURN_ERROR(MAJOR, err, (NO_MSG)); + + err = UpdateGblMask(p_CcNode, p_CcNodeParam->keysParams.keySize, + p_KeyParams->p_Mask); + if (err) + RETURN_ERROR(MAJOR, err, (NO_MSG)); + + if (p_KeyParams->ccNextEngineParams.h_Manip) + { + err = FmPcdManipCheckParamsForCcNextEngine( + &p_KeyParams->ccNextEngineParams, &requiredAction); + if (err) + RETURN_ERROR(MAJOR, err, (NO_MSG)); + } + + /* Store 'key' parameters - key, mask (if passed by the user) */ + memcpy(p_CcNode->keyAndNextEngineParams[tmp].key, p_KeyParams->p_Key, + p_CcNodeParam->keysParams.keySize); + + if (p_KeyParams->p_Mask) + memcpy(p_CcNode->keyAndNextEngineParams[tmp].mask, + p_KeyParams->p_Mask, p_CcNodeParam->keysParams.keySize); + else + memset((void *)(p_CcNode->keyAndNextEngineParams[tmp].mask), 0xFF, + p_CcNodeParam->keysParams.keySize); + + /* Store next engine parameters */ + memcpy(&p_CcNode->keyAndNextEngineParams[tmp].nextEngineParams, + &p_KeyParams->ccNextEngineParams, + sizeof(t_FmPcdCcNextEngineParams)); + + p_CcNode->keyAndNextEngineParams[tmp].requiredAction = requiredAction; + + if ((p_CcNode->keyAndNextEngineParams[tmp].nextEngineParams.nextEngine + == e_FM_PCD_CC) + && p_CcNode->keyAndNextEngineParams[tmp].nextEngineParams.h_Manip) + { + err = + AllocAndFillAdForContLookupManip( + p_CcNode->keyAndNextEngineParams[tmp].nextEngineParams.params.ccParams.h_CcNode); + if (err) + RETURN_ERROR(MAJOR, err, (NO_MSG)); + } + } + + if (p_CcNode->maxNumOfKeys) + { + if (p_CcNode->maxNumOfKeys < p_CcNode->numOfKeys) + RETURN_ERROR( + MAJOR, + E_INVALID_VALUE, + ("Number of keys exceed the provided maximal number of keys")); + } + + *isKeyTblAlloc = TRUE; + + return E_OK; +} + +static t_Error Ipv4TtlOrIpv6HopLimitCheckParams( + t_Handle h_FmPcd, t_FmPcdCcNodeParams *p_CcNodeParam, + t_FmPcdCcNode *p_CcNode, bool *isKeyTblAlloc) +{ + int tmp = 0; + t_FmPcdCcKeyParams *p_KeyParams; + t_Error err; + uint8_t key = 0x01; + uint32_t requiredAction = 0; + + if (p_CcNode->numOfKeys != 1) + RETURN_ERROR( + MAJOR, + E_INVALID_VALUE, + ("For node of the type IPV4_TTL or IPV6_HOP_LIMIT the maximal supported 'numOfKeys' is 1")); + + if ((p_CcNodeParam->keysParams.maxNumOfKeys) + && (p_CcNodeParam->keysParams.maxNumOfKeys != 1)) + RETURN_ERROR( + MAJOR, + E_INVALID_VALUE, + ("For node of the type IPV4_TTL or IPV6_HOP_LIMIT the maximal supported 'maxNumOfKeys' is 1")); + + /* Validate statistics parameters */ + err = ValidateAndCalcStatsParams(p_CcNode, p_CcNodeParam, + &(p_CcNode->numOfStatsFLRs), + &(p_CcNode->countersArraySize)); + if (err) + RETURN_ERROR(MAJOR, err, ("Invalid statistics parameters")); + + err = ValidateNextEngineParams( + h_FmPcd, &p_CcNodeParam->keysParams.ccNextEngineParamsForMiss, + p_CcNodeParam->keysParams.statisticsMode); + if (err) + RETURN_ERROR(MAJOR, err, + ("For this node MissNextEngineParams are not valid")); + + if (p_CcNodeParam->keysParams.ccNextEngineParamsForMiss.h_Manip) + { + err = FmPcdManipCheckParamsForCcNextEngine( + &p_CcNodeParam->keysParams.ccNextEngineParamsForMiss, + &requiredAction); + if (err) + RETURN_ERROR(MAJOR, err, (NO_MSG)); + } + + memcpy(&p_CcNode->keyAndNextEngineParams[p_CcNode->numOfKeys].nextEngineParams, + &p_CcNodeParam->keysParams.ccNextEngineParamsForMiss, + sizeof(t_FmPcdCcNextEngineParams)); + + p_CcNode->keyAndNextEngineParams[p_CcNode->numOfKeys].requiredAction = + requiredAction; + + if ((p_CcNode->keyAndNextEngineParams[p_CcNode->numOfKeys].nextEngineParams.nextEngine + == e_FM_PCD_CC) + && p_CcNode->keyAndNextEngineParams[p_CcNode->numOfKeys].nextEngineParams.h_Manip) + { + err = + AllocAndFillAdForContLookupManip( + p_CcNode->keyAndNextEngineParams[p_CcNode->numOfKeys].nextEngineParams.params.ccParams.h_CcNode); + if (err) + RETURN_ERROR(MAJOR, err, (NO_MSG)); + } + + for (tmp = 0; tmp < p_CcNode->numOfKeys; tmp++) + { + p_KeyParams = &p_CcNodeParam->keysParams.keyParams[tmp]; + + if (p_KeyParams->p_Mask) + RETURN_ERROR( + MAJOR, + E_INVALID_VALUE, + ("For node of the type IPV4_TTL or IPV6_HOP_LIMIT p_Mask can not be initialized")); + + if (memcmp(p_KeyParams->p_Key, &key, 1) != 0) + RETURN_ERROR( + MAJOR, + E_INVALID_VALUE, + ("For node of the type IPV4_TTL or IPV6_HOP_LIMIT p_Key has to be 1")); + + err = ValidateNextEngineParams(h_FmPcd, + &p_KeyParams->ccNextEngineParams, + p_CcNode->statisticsMode); + if (err) + RETURN_ERROR(MAJOR, err, (NO_MSG)); + + if (p_KeyParams->ccNextEngineParams.h_Manip) + { + err = FmPcdManipCheckParamsForCcNextEngine( + &p_KeyParams->ccNextEngineParams, &requiredAction); + if (err) + RETURN_ERROR(MAJOR, err, (NO_MSG)); + } + + /* Store 'key' parameters - key (fixed to 0x01), key size of 1 byte and full mask */ + p_CcNode->keyAndNextEngineParams[tmp].key[0] = key; + p_CcNode->keyAndNextEngineParams[tmp].mask[0] = 0xFF; + + /* Store NextEngine parameters */ + memcpy(&p_CcNode->keyAndNextEngineParams[tmp].nextEngineParams, + &p_KeyParams->ccNextEngineParams, + sizeof(t_FmPcdCcNextEngineParams)); + + if ((p_CcNode->keyAndNextEngineParams[tmp].nextEngineParams.nextEngine + == e_FM_PCD_CC) + && p_CcNode->keyAndNextEngineParams[tmp].nextEngineParams.h_Manip) + { + err = + AllocAndFillAdForContLookupManip( + p_CcNode->keyAndNextEngineParams[tmp].nextEngineParams.params.ccParams.h_CcNode); + if (err) + RETURN_ERROR(MAJOR, err, (NO_MSG)); + } + p_CcNode->keyAndNextEngineParams[tmp].requiredAction = requiredAction; + } + + *isKeyTblAlloc = FALSE; + + return E_OK; +} + +static t_Error IcHashIndexedCheckParams(t_Handle h_FmPcd, + t_FmPcdCcNodeParams *p_CcNodeParam, + t_FmPcdCcNode *p_CcNode, + bool *isKeyTblAlloc) +{ + int tmp = 0, countOnes = 0; + t_FmPcdCcKeyParams *p_KeyParams; + t_Error err; + uint16_t glblMask = p_CcNodeParam->extractCcParams.extractNonHdr.icIndxMask; + uint16_t countMask = (uint16_t)(glblMask >> 4); + uint32_t requiredAction = 0; + + if (glblMask & 0x000f) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, + ("icIndxMask has to be with last nibble 0")); + + while (countMask) + { + countOnes++; + countMask = (uint16_t)(countMask >> 1); + } + + if (!POWER_OF_2(p_CcNode->numOfKeys)) + RETURN_ERROR( + MAJOR, + E_INVALID_VALUE, + ("For Node of the type INDEXED numOfKeys has to be powerOfTwo")); + + if (p_CcNode->numOfKeys != ((uint32_t)1 << countOnes)) + RETURN_ERROR( + MAJOR, + E_INVALID_VALUE, + ("For Node of the type IC_HASH_INDEXED numOfKeys has to be powerOfTwo")); + + if (p_CcNodeParam->keysParams.maxNumOfKeys + && (p_CcNodeParam->keysParams.maxNumOfKeys != p_CcNode->numOfKeys)) + RETURN_ERROR( + MAJOR, + E_INVALID_VALUE, + ("For Node of the type INDEXED 'maxNumOfKeys' should be 0 or equal 'numOfKeys'")); + + /* Validate statistics parameters */ + err = ValidateAndCalcStatsParams(p_CcNode, p_CcNodeParam, + &(p_CcNode->numOfStatsFLRs), + &(p_CcNode->countersArraySize)); + if (err) + RETURN_ERROR(MAJOR, err, ("Invalid statistics parameters")); + + err = ValidateNextEngineParams( + h_FmPcd, &p_CcNodeParam->keysParams.ccNextEngineParamsForMiss, + p_CcNode->statisticsMode); + if (GET_ERROR_TYPE(err) != E_NOT_SUPPORTED) + RETURN_ERROR( + MAJOR, + err, + ("MissNextEngineParams for the node of the type IC_INDEX_HASH has to be UnInitialized")); + + for (tmp = 0; tmp < p_CcNode->numOfKeys; tmp++) + { + p_KeyParams = &p_CcNodeParam->keysParams.keyParams[tmp]; + + if (p_KeyParams->p_Mask || p_KeyParams->p_Key) + RETURN_ERROR( + MAJOR, + E_INVALID_VALUE, + ("For Node of the type IC_HASH_INDEXED p_Key or p_Mask has to be NULL")); + + if ((glblMask & (tmp * 16)) == (tmp * 16)) + { + err = ValidateNextEngineParams(h_FmPcd, + &p_KeyParams->ccNextEngineParams, + p_CcNode->statisticsMode); + if (err) + RETURN_ERROR( + MAJOR, + err, + ("This index has to be initialized for the node of the type IC_INDEX_HASH according to settings of GlobalMask ")); + + if (p_KeyParams->ccNextEngineParams.h_Manip) + { + err = FmPcdManipCheckParamsForCcNextEngine( + &p_KeyParams->ccNextEngineParams, &requiredAction); + if (err) + RETURN_ERROR(MAJOR, err, (NO_MSG)); + p_CcNode->keyAndNextEngineParams[tmp].requiredAction = + requiredAction; + } + + memcpy(&p_CcNode->keyAndNextEngineParams[tmp].nextEngineParams, + &p_KeyParams->ccNextEngineParams, + sizeof(t_FmPcdCcNextEngineParams)); + + if ((p_CcNode->keyAndNextEngineParams[tmp].nextEngineParams.nextEngine + == e_FM_PCD_CC) + && p_CcNode->keyAndNextEngineParams[tmp].nextEngineParams.h_Manip) + { + err = + AllocAndFillAdForContLookupManip( + p_CcNode->keyAndNextEngineParams[tmp].nextEngineParams.params.ccParams.h_CcNode); + if (err) + RETURN_ERROR(MAJOR, err, (NO_MSG)); + } + } + else + { + err = ValidateNextEngineParams(h_FmPcd, + &p_KeyParams->ccNextEngineParams, + p_CcNode->statisticsMode); + if (GET_ERROR_TYPE(err) != E_NOT_SUPPORTED) + RETURN_ERROR( + MAJOR, + err, + ("This index has to be UnInitialized for the node of the type IC_INDEX_HASH according to settings of GlobalMask")); + } + } + + *isKeyTblAlloc = FALSE; + cpu_to_be16s(&glblMask); + memcpy(PTR_MOVE(p_CcNode->p_GlblMask, 2), &glblMask, 2); + + return E_OK; +} + +static t_Error ModifyNextEngineParamNode( + t_Handle h_FmPcd, t_Handle h_FmPcdCcNode, uint16_t keyIndex, + t_FmPcdCcNextEngineParams *p_FmPcdCcNextEngineParams) +{ + t_FmPcdCcNode *p_CcNode = (t_FmPcdCcNode *)h_FmPcdCcNode; + t_FmPcd *p_FmPcd; + t_List h_OldPointersLst, h_NewPointersLst; + t_FmPcdModifyCcKeyAdditionalParams *p_ModifyKeyParams; + t_Error err = E_OK; + + SANITY_CHECK_RETURN_ERROR(h_FmPcd, E_INVALID_VALUE); + SANITY_CHECK_RETURN_ERROR(p_CcNode, E_INVALID_HANDLE); + + if (keyIndex >= p_CcNode->numOfKeys) + RETURN_ERROR(MAJOR, E_INVALID_STATE, + ("keyIndex > previously cleared last index + 1")); + + p_FmPcd = (t_FmPcd *)p_CcNode->h_FmPcd; + + INIT_LIST(&h_OldPointersLst); + INIT_LIST(&h_NewPointersLst); + + p_ModifyKeyParams = ModifyNodeCommonPart(p_CcNode, keyIndex, + e_MODIFY_STATE_CHANGE, FALSE, + FALSE, FALSE); + if (!p_ModifyKeyParams) + RETURN_ERROR(MAJOR, E_INVALID_STATE, NO_MSG); + + if (p_CcNode->maxNumOfKeys + && !TRY_LOCK(p_FmPcd->h_ShadowSpinlock, &p_FmPcd->shadowLock)) + { + XX_Free(p_ModifyKeyParams); + return ERROR_CODE(E_BUSY); + } + + err = BuildNewNodeModifyNextEngine(h_FmPcd, p_CcNode, keyIndex, + p_FmPcdCcNextEngineParams, + &h_OldPointersLst, &h_NewPointersLst, + p_ModifyKeyParams); + if (err) + { + XX_Free(p_ModifyKeyParams); + if (p_CcNode->maxNumOfKeys) + RELEASE_LOCK(p_FmPcd->shadowLock); + RETURN_ERROR(MAJOR, err, NO_MSG); + } + + err = DoDynamicChange(p_FmPcd, &h_OldPointersLst, &h_NewPointersLst, + p_ModifyKeyParams, FALSE); + + if (p_CcNode->maxNumOfKeys) + RELEASE_LOCK(p_FmPcd->shadowLock); + + ReleaseLst(&h_OldPointersLst); + ReleaseLst(&h_NewPointersLst); + + return err; +} + +static t_Error FindKeyIndex(t_Handle h_CcNode, uint8_t keySize, uint8_t *p_Key, + uint8_t *p_Mask, uint16_t *p_KeyIndex) +{ + t_FmPcdCcNode *p_CcNode = (t_FmPcdCcNode *)h_CcNode; + uint8_t tmpMask[FM_PCD_MAX_SIZE_OF_KEY]; + uint16_t i; + + ASSERT_COND(p_Key); + ASSERT_COND(p_KeyIndex); + ASSERT_COND(keySize < FM_PCD_MAX_SIZE_OF_KEY); + + if (keySize != p_CcNode->userSizeOfExtraction) + RETURN_ERROR( + MINOR, E_INVALID_VALUE, + ("Key size doesn't match the extraction size of the node")); + + /* If user didn't pass a mask for this key, we'll look for full extraction mask */ + if (!p_Mask) + memset(tmpMask, 0xFF, keySize); + + for (i = 0; i < p_CcNode->numOfKeys; i++) + { + /* Comparing received key */ + if (memcmp(p_Key, p_CcNode->keyAndNextEngineParams[i].key, keySize) + == 0) + { + if (p_Mask) + { + /* If a user passed a mask for this key, it must match to the existing key's mask for a correct match */ + if (memcmp(p_Mask, p_CcNode->keyAndNextEngineParams[i].mask, + keySize) == 0) + { + *p_KeyIndex = i; + return E_OK; + } + } + else + { + /* If user didn't pass a mask for this key, check if the existing key mask is full extraction */ + if (memcmp(tmpMask, p_CcNode->keyAndNextEngineParams[i].mask, + keySize) == 0) + { + *p_KeyIndex = i; + return E_OK; + } + } + } + } + + return ERROR_CODE(E_NOT_FOUND); +} + +static t_Error CalcAndUpdateCcShadow(t_FmPcdCcNode *p_CcNode, + bool isKeyTblAlloc, + uint32_t *p_MatchTableSize, + uint32_t *p_AdTableSize) +{ + uint32_t shadowSize; + t_Error err; + + /* Calculate keys table maximal size - each entry consists of a key and a mask, + (if local mask support is requested) */ + *p_MatchTableSize = p_CcNode->ccKeySizeAccExtraction * sizeof(uint8_t) + * p_CcNode->maxNumOfKeys; + + if (p_CcNode->maskSupport) + *p_MatchTableSize *= 2; + + /* Calculate next action descriptors table, including one more entry for miss */ + *p_AdTableSize = (uint32_t)((p_CcNode->maxNumOfKeys + 1) + * FM_PCD_CC_AD_ENTRY_SIZE); + + /* Calculate maximal shadow size of this node. + All shadow structures will be used for runtime modifications host command. If + keys table was allocated for this node, the keys table and next engines table may + be modified in run time (entries added or removed), so shadow tables are requires. + Otherwise, the only supported runtime modification is a specific next engine update + and this requires shadow memory of a single AD */ + + /* Shadow size should be enough to hold the following 3 structures: + * 1 - an action descriptor */ + shadowSize = FM_PCD_CC_AD_ENTRY_SIZE; + + /* 2 - keys match table, if was allocated for the current node */ + if (isKeyTblAlloc) + shadowSize += *p_MatchTableSize; + + /* 3 - next action descriptors table */ + shadowSize += *p_AdTableSize; + + /* Update shadow to the calculated size */ + err = FmPcdUpdateCcShadow(p_CcNode->h_FmPcd, (uint32_t)shadowSize, + FM_PCD_CC_AD_TABLE_ALIGN); + if (err != E_OK) + { + DeleteNode(p_CcNode); + RETURN_ERROR(MAJOR, E_NO_MEMORY, ("MURAM allocation for CC node shadow")); + } + + return E_OK; +} + +static t_Error AllocStatsObjs(t_FmPcdCcNode *p_CcNode) +{ + t_FmPcdStatsObj *p_StatsObj; + t_Handle h_FmMuram, h_StatsAd, h_StatsCounters; + uint32_t i; + + h_FmMuram = FmPcdGetMuramHandle(p_CcNode->h_FmPcd); + if (!h_FmMuram) + RETURN_ERROR(MAJOR, E_INVALID_HANDLE, ("FM MURAM")); + + /* Allocate statistics ADs and statistics counter. An extra pair (AD + counters) + will be allocated to support runtime modifications */ + for (i = 0; i < p_CcNode->maxNumOfKeys + 2; i++) + { + /* Allocate list object structure */ + p_StatsObj = XX_Malloc(sizeof(t_FmPcdStatsObj)); + if (!p_StatsObj) + { + FreeStatObjects(&p_CcNode->availableStatsLst, h_FmMuram); + RETURN_ERROR(MAJOR, E_NO_MEMORY, ("Statistics object")); + } + memset(p_StatsObj, 0, sizeof(t_FmPcdStatsObj)); + + /* Allocate statistics AD from MURAM */ + h_StatsAd = (t_Handle)FM_MURAM_AllocMem(h_FmMuram, + FM_PCD_CC_AD_ENTRY_SIZE, + FM_PCD_CC_AD_TABLE_ALIGN); + if (!h_StatsAd) + { + FreeStatObjects(&p_CcNode->availableStatsLst, h_FmMuram); + XX_Free(p_StatsObj); + RETURN_ERROR(MAJOR, E_NO_MEMORY, + ("MURAM allocation for statistics ADs")); + } + MemSet8(h_StatsAd, 0, FM_PCD_CC_AD_ENTRY_SIZE); + + /* Allocate statistics counters from MURAM */ + h_StatsCounters = (t_Handle)FM_MURAM_AllocMem( + h_FmMuram, p_CcNode->countersArraySize, + FM_PCD_CC_AD_TABLE_ALIGN); + if (!h_StatsCounters) + { + FreeStatObjects(&p_CcNode->availableStatsLst, h_FmMuram); + FM_MURAM_FreeMem(h_FmMuram, h_StatsAd); + XX_Free(p_StatsObj); + RETURN_ERROR(MAJOR, E_NO_MEMORY, + ("MURAM allocation for statistics counters")); + } + MemSet8(h_StatsCounters, 0, p_CcNode->countersArraySize); + + p_StatsObj->h_StatsAd = h_StatsAd; + p_StatsObj->h_StatsCounters = h_StatsCounters; + + EnqueueStatsObj(&p_CcNode->availableStatsLst, p_StatsObj); + } + + return E_OK; +} + +static t_Error MatchTableGetKeyStatistics( + t_FmPcdCcNode *p_CcNode, uint16_t keyIndex, + t_FmPcdCcKeyStatistics *p_KeyStatistics) +{ + uint32_t *p_StatsCounters, i; + + if (p_CcNode->statisticsMode == e_FM_PCD_CC_STATS_MODE_NONE) + RETURN_ERROR(MAJOR, E_INVALID_STATE, + ("Statistics were not enabled for this match table")); + + if (!p_CcNode->keyAndNextEngineParams[keyIndex].p_StatsObj) + RETURN_ERROR(MAJOR, E_INVALID_STATE, + ("Statistics were not enabled for this key")); + + memset(p_KeyStatistics, 0, sizeof(t_FmPcdCcKeyStatistics)); + + p_StatsCounters = + p_CcNode->keyAndNextEngineParams[keyIndex].p_StatsObj->h_StatsCounters; + ASSERT_COND(p_StatsCounters); + + p_KeyStatistics->byteCount = GET_UINT32(*p_StatsCounters); + + for (i = 1; i <= p_CcNode->numOfStatsFLRs; i++) + { + p_StatsCounters = + PTR_MOVE(p_StatsCounters, FM_PCD_CC_STATS_COUNTER_SIZE); + + p_KeyStatistics->frameCount += GET_UINT32(*p_StatsCounters); + +#if (DPAA_VERSION >= 11) + p_KeyStatistics->frameLengthRangeCount[i - 1] = + GET_UINT32(*p_StatsCounters); +#endif /* (DPAA_VERSION >= 11) */ + } + + return E_OK; +} + +static t_Error MatchTableSet(t_Handle h_FmPcd, t_FmPcdCcNode *p_CcNode, + t_FmPcdCcNodeParams *p_CcNodeParam) +{ + t_FmPcd *p_FmPcd = (t_FmPcd *)h_FmPcd; + t_FmPcdCcNode *p_FmPcdCcNextNode; + t_Error err = E_OK; + uint32_t tmp, keySize; + bool glblMask = FALSE; + t_FmPcdCcKeyParams *p_KeyParams; + t_Handle h_FmMuram, p_KeysMatchTblTmp, p_AdTableTmp; +#if (DPAA_VERSION >= 11) + t_Handle h_StatsFLRs; +#endif /* (DPAA_VERSION >= 11) */ + bool fullField = FALSE; + ccPrivateInfo_t icCode = CC_PRIVATE_INFO_NONE; + bool isKeyTblAlloc, fromIc = FALSE; + uint32_t matchTableSize, adTableSize; + t_CcNodeInformation ccNodeInfo, *p_CcInformation; + t_FmPcdStatsObj *p_StatsObj; + t_FmPcdCcStatsParams statsParams = { 0 }; + t_Handle h_Manip; + + ASSERT_COND(h_FmPcd); + ASSERT_COND(p_CcNode); + ASSERT_COND(p_CcNodeParam); + + p_CcNode->p_GlblMask = (t_Handle)XX_Malloc( + CC_GLBL_MASK_SIZE * sizeof(uint8_t)); + memset(p_CcNode->p_GlblMask, 0, CC_GLBL_MASK_SIZE * sizeof(uint8_t)); + + p_CcNode->h_FmPcd = h_FmPcd; + p_CcNode->numOfKeys = p_CcNodeParam->keysParams.numOfKeys; + p_CcNode->maxNumOfKeys = p_CcNodeParam->keysParams.maxNumOfKeys; + p_CcNode->maskSupport = p_CcNodeParam->keysParams.maskSupport; + p_CcNode->statisticsMode = p_CcNodeParam->keysParams.statisticsMode; + + /* For backward compatibility - even if statistics mode is nullified, + we'll fix it to frame mode so we can support per-key request for + statistics using 'statisticsEn' in next engine parameters */ + if (!p_CcNode->maxNumOfKeys + && (p_CcNode->statisticsMode == e_FM_PCD_CC_STATS_MODE_NONE)) + p_CcNode->statisticsMode = e_FM_PCD_CC_STATS_MODE_FRAME; + + h_FmMuram = FmPcdGetMuramHandle(h_FmPcd); + if (!h_FmMuram) + RETURN_ERROR(MAJOR, E_INVALID_HANDLE, ("FM MURAM")); + + INIT_LIST(&p_CcNode->ccPrevNodesLst); + INIT_LIST(&p_CcNode->ccTreeIdLst); + INIT_LIST(&p_CcNode->ccTreesLst); + INIT_LIST(&p_CcNode->availableStatsLst); + + p_CcNode->h_Spinlock = XX_InitSpinlock(); + if (!p_CcNode->h_Spinlock) + { + DeleteNode(p_CcNode); + RETURN_ERROR(MAJOR, E_NO_MEMORY, ("CC node spinlock")); + } + + if ((p_CcNodeParam->extractCcParams.type == e_FM_PCD_EXTRACT_BY_HDR) + && ((p_CcNodeParam->extractCcParams.extractByHdr.hdr + == HEADER_TYPE_IPv4) + || (p_CcNodeParam->extractCcParams.extractByHdr.hdr + == HEADER_TYPE_IPv6)) + && (p_CcNodeParam->extractCcParams.extractByHdr.type + == e_FM_PCD_EXTRACT_FULL_FIELD) + && ((p_CcNodeParam->extractCcParams.extractByHdr.extractByHdrType.fullField.ipv6 + == NET_HEADER_FIELD_IPv6_HOP_LIMIT) + || (p_CcNodeParam->extractCcParams.extractByHdr.extractByHdrType.fullField.ipv4 + == NET_HEADER_FIELD_IPv4_TTL))) + { + err = Ipv4TtlOrIpv6HopLimitCheckParams(h_FmPcd, p_CcNodeParam, p_CcNode, + &isKeyTblAlloc); + glblMask = FALSE; + } + else + if ((p_CcNodeParam->extractCcParams.type == e_FM_PCD_EXTRACT_NON_HDR) + && ((p_CcNodeParam->extractCcParams.extractNonHdr.src + == e_FM_PCD_EXTRACT_FROM_KEY) + || (p_CcNodeParam->extractCcParams.extractNonHdr.src + == e_FM_PCD_EXTRACT_FROM_HASH) + || (p_CcNodeParam->extractCcParams.extractNonHdr.src + == e_FM_PCD_EXTRACT_FROM_FLOW_ID))) + { + if ((p_CcNodeParam->extractCcParams.extractNonHdr.src + == e_FM_PCD_EXTRACT_FROM_FLOW_ID) + && (p_CcNodeParam->extractCcParams.extractNonHdr.offset != 0)) + { + DeleteNode(p_CcNode); + RETURN_ERROR( + MAJOR, + E_INVALID_VALUE, + ("In the case of the extraction from e_FM_PCD_EXTRACT_FROM_FLOW_ID offset has to be 0")); + } + + icCode = IcDefineCode(p_CcNodeParam); + fromIc = TRUE; + if (icCode == CC_PRIVATE_INFO_NONE) + { + DeleteNode(p_CcNode); + RETURN_ERROR( + MAJOR, + E_INVALID_STATE, + ("user asked extraction from IC and field in internal context or action wasn't initialized in the right way")); + } + + if ((icCode == CC_PRIVATE_INFO_IC_DEQ_FQID_INDEX_LOOKUP) + || (icCode == CC_PRIVATE_INFO_IC_HASH_INDEX_LOOKUP)) + { + err = IcHashIndexedCheckParams(h_FmPcd, p_CcNodeParam, p_CcNode, + &isKeyTblAlloc); + glblMask = TRUE; + } + else + { + err = CheckParams(h_FmPcd, p_CcNodeParam, p_CcNode, + &isKeyTblAlloc); + if (p_CcNode->glblMaskSize) + glblMask = TRUE; + } + } + else + { + err = CheckParams(h_FmPcd, p_CcNodeParam, p_CcNode, &isKeyTblAlloc); + if (p_CcNode->glblMaskSize) + glblMask = TRUE; + } + + if (err) + { + DeleteNode(p_CcNode); + RETURN_ERROR(MAJOR, err, NO_MSG); + } + + switch (p_CcNodeParam->extractCcParams.type) + { + case (e_FM_PCD_EXTRACT_BY_HDR): + switch (p_CcNodeParam->extractCcParams.extractByHdr.type) + { + case (e_FM_PCD_EXTRACT_FULL_FIELD): + p_CcNode->parseCode = + GetFullFieldParseCode( + p_CcNodeParam->extractCcParams.extractByHdr.hdr, + p_CcNodeParam->extractCcParams.extractByHdr.hdrIndex, + p_CcNodeParam->extractCcParams.extractByHdr.extractByHdrType.fullField); + GetSizeHeaderField( + p_CcNodeParam->extractCcParams.extractByHdr.hdr, + p_CcNodeParam->extractCcParams.extractByHdr.extractByHdrType.fullField, + &p_CcNode->sizeOfExtraction); + fullField = TRUE; + if ((p_CcNode->parseCode != CC_PC_FF_TCI1) + && (p_CcNode->parseCode != CC_PC_FF_TCI2) + && (p_CcNode->parseCode != CC_PC_FF_MPLS1) + && (p_CcNode->parseCode != CC_PC_FF_MPLS_LAST) + && (p_CcNode->parseCode != CC_PC_FF_IPV4IPTOS_TC1) + && (p_CcNode->parseCode != CC_PC_FF_IPV4IPTOS_TC2) + && (p_CcNode->parseCode + != CC_PC_FF_IPTOS_IPV6TC1_IPV6FLOW1) + && (p_CcNode->parseCode != CC_PC_FF_IPDSCP) + && (p_CcNode->parseCode + != CC_PC_FF_IPTOS_IPV6TC2_IPV6FLOW2) + && glblMask) + { + glblMask = FALSE; + p_CcNode->glblMaskSize = 4; + p_CcNode->lclMask = TRUE; + } + break; + + case (e_FM_PCD_EXTRACT_FROM_HDR): + p_CcNode->sizeOfExtraction = + p_CcNodeParam->extractCcParams.extractByHdr.extractByHdrType.fromHdr.size; + p_CcNode->offset = + p_CcNodeParam->extractCcParams.extractByHdr.extractByHdrType.fromHdr.offset; + p_CcNode->userOffset = + p_CcNodeParam->extractCcParams.extractByHdr.extractByHdrType.fromHdr.offset; + p_CcNode->parseCode = + GetPrParseCode( + p_CcNodeParam->extractCcParams.extractByHdr.hdr, + p_CcNodeParam->extractCcParams.extractByHdr.hdrIndex, + p_CcNode->offset, glblMask, + &p_CcNode->prsArrayOffset); + break; + + case (e_FM_PCD_EXTRACT_FROM_FIELD): + p_CcNode->offset = + p_CcNodeParam->extractCcParams.extractByHdr.extractByHdrType.fromField.offset; + p_CcNode->userOffset = + p_CcNodeParam->extractCcParams.extractByHdr.extractByHdrType.fromField.offset; + p_CcNode->sizeOfExtraction = + p_CcNodeParam->extractCcParams.extractByHdr.extractByHdrType.fromField.size; + p_CcNode->parseCode = + GetFieldParseCode( + p_CcNodeParam->extractCcParams.extractByHdr.hdr, + p_CcNodeParam->extractCcParams.extractByHdr.extractByHdrType.fromField.field, + p_CcNode->offset, + &p_CcNode->prsArrayOffset, + p_CcNodeParam->extractCcParams.extractByHdr.hdrIndex); + break; + + default: + DeleteNode(p_CcNode); + RETURN_ERROR(MAJOR, E_INVALID_SELECTION, NO_MSG); + } + break; + + case (e_FM_PCD_EXTRACT_NON_HDR): + /* get the field code for the generic extract */ + p_CcNode->sizeOfExtraction = + p_CcNodeParam->extractCcParams.extractNonHdr.size; + p_CcNode->offset = + p_CcNodeParam->extractCcParams.extractNonHdr.offset; + p_CcNode->userOffset = + p_CcNodeParam->extractCcParams.extractNonHdr.offset; + p_CcNode->parseCode = GetGenParseCode( + p_CcNodeParam->extractCcParams.extractNonHdr.src, + p_CcNode->offset, glblMask, &p_CcNode->prsArrayOffset, + fromIc, icCode); + + if (p_CcNode->parseCode == CC_PC_GENERIC_IC_HASH_INDEXED) + { + if ((p_CcNode->offset + p_CcNode->sizeOfExtraction) > 8) + { + DeleteNode(p_CcNode); + RETURN_ERROR( + MAJOR, + E_INVALID_SELECTION, + ("when node of the type CC_PC_GENERIC_IC_HASH_INDEXED offset + size can not be bigger then size of HASH 64 bits (8 bytes)")); + } + } + if ((p_CcNode->parseCode == CC_PC_GENERIC_IC_GMASK) + || (p_CcNode->parseCode == CC_PC_GENERIC_IC_HASH_INDEXED)) + { + p_CcNode->offset += p_CcNode->prsArrayOffset; + p_CcNode->prsArrayOffset = 0; + } + break; + + default: + DeleteNode(p_CcNode); + RETURN_ERROR(MAJOR, E_INVALID_SELECTION, NO_MSG); + } + + if (p_CcNode->parseCode == CC_PC_ILLEGAL) + { + DeleteNode(p_CcNode); + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("illegal extraction type")); + } + + if ((p_CcNode->sizeOfExtraction > FM_PCD_MAX_SIZE_OF_KEY) + || !p_CcNode->sizeOfExtraction) + { + DeleteNode(p_CcNode); + RETURN_ERROR(MAJOR, E_INVALID_VALUE, + ("sizeOfExatrction can not be greater than 56 and not 0")); + } + + if (p_CcNodeParam->keysParams.keySize != p_CcNode->sizeOfExtraction) + { + DeleteNode(p_CcNode); + RETURN_ERROR(MAJOR, E_INVALID_VALUE, + ("keySize has to be equal to sizeOfExtraction")); + } + + p_CcNode->userSizeOfExtraction = p_CcNode->sizeOfExtraction; + + if (!glblMask) + memset(p_CcNode->p_GlblMask, 0xff, CC_GLBL_MASK_SIZE * sizeof(uint8_t)); + + err = CheckAndSetManipParamsWithCcNodeParams(p_CcNode); + if (err != E_OK) + { + DeleteNode(p_CcNode); + RETURN_ERROR(MAJOR, E_INVALID_VALUE, + ("keySize has to be equal to sizeOfExtraction")); + } + + /* Calculating matching table entry size by rounding up the user-defined size of extraction to valid entry size */ + GetCcExtractKeySize(p_CcNode->sizeOfExtraction, + &p_CcNode->ccKeySizeAccExtraction); + + /* If local mask is used, it is stored next to each key in the keys match table */ + if (p_CcNode->lclMask) + keySize = (uint32_t)(2 * p_CcNode->ccKeySizeAccExtraction); + else + keySize = p_CcNode->ccKeySizeAccExtraction; + + /* Update CC shadow with maximal size required by this node */ + if (p_CcNode->maxNumOfKeys) + { + err = CalcAndUpdateCcShadow(p_CcNode, isKeyTblAlloc, &matchTableSize, + &adTableSize); + if (err != E_OK) + { + DeleteNode(p_CcNode); + RETURN_ERROR(MAJOR, err, NO_MSG); + } + + p_CcNode->keysMatchTableMaxSize = matchTableSize; + + if (p_CcNode->statisticsMode != e_FM_PCD_CC_STATS_MODE_NONE) + { + err = AllocStatsObjs(p_CcNode); + if (err != E_OK) + { + DeleteNode(p_CcNode); + RETURN_ERROR(MAJOR, err, NO_MSG); + } + } + + /* If manipulation will be initialized before this node, it will use the table + descriptor in the AD table of previous node and this node will need an extra + AD as his table descriptor. */ + p_CcNode->h_TmpAd = (t_Handle)FM_MURAM_AllocMem( + h_FmMuram, FM_PCD_CC_AD_ENTRY_SIZE, FM_PCD_CC_AD_TABLE_ALIGN); + if (!p_CcNode->h_TmpAd) + { + DeleteNode(p_CcNode); + RETURN_ERROR(MAJOR, E_NO_MEMORY, + ("MURAM allocation for CC action descriptor")); + } + } + else + { + matchTableSize = (uint32_t)(keySize * sizeof(uint8_t) + * (p_CcNode->numOfKeys + 1)); + adTableSize = (uint32_t)(FM_PCD_CC_AD_ENTRY_SIZE + * (p_CcNode->numOfKeys + 1)); + } + +#if (DPAA_VERSION >= 11) + switch (p_CcNode->statisticsMode) + { + + case e_FM_PCD_CC_STATS_MODE_RMON: + /* If RMON statistics or RMON conditional statistics modes are requested, + allocate frame length ranges array */ + p_CcNode->h_StatsFLRs = FM_MURAM_AllocMem( + h_FmMuram, + (uint32_t)(p_CcNode->numOfStatsFLRs) + * FM_PCD_CC_STATS_FLR_SIZE, + FM_PCD_CC_AD_TABLE_ALIGN); + + if (!p_CcNode->h_StatsFLRs) + { + DeleteNode(p_CcNode); + RETURN_ERROR( + MAJOR, E_NO_MEMORY, + ("MURAM allocation for CC frame length ranges array")); + } + + /* Initialize using value received from the user */ + for (tmp = 0; tmp < p_CcNode->numOfStatsFLRs; tmp++) + { + uint16_t flr = + cpu_to_be16(p_CcNodeParam->keysParams.frameLengthRanges[tmp]); + + h_StatsFLRs = + PTR_MOVE(p_CcNode->h_StatsFLRs, tmp * FM_PCD_CC_STATS_FLR_SIZE); + + MemCpy8(h_StatsFLRs, + &flr, + FM_PCD_CC_STATS_FLR_SIZE); + } + break; + + default: + break; + } +#endif /* (DPAA_VERSION >= 11) */ + + /* Allocate keys match table. Not required for some CC nodes, for example for IPv4 TTL + identification, IPv6 hop count identification, etc. */ + if (isKeyTblAlloc) + { + p_CcNode->h_KeysMatchTable = (t_Handle)FM_MURAM_AllocMem( + h_FmMuram, matchTableSize, FM_PCD_CC_KEYS_MATCH_TABLE_ALIGN); + if (!p_CcNode->h_KeysMatchTable) + { + DeleteNode(p_CcNode); + RETURN_ERROR(MAJOR, E_NO_MEMORY, + ("MURAM allocation for CC node key match table")); + } + MemSet8((uint8_t *)p_CcNode->h_KeysMatchTable, 0, matchTableSize); + } + + /* Allocate action descriptors table */ + p_CcNode->h_AdTable = (t_Handle)FM_MURAM_AllocMem(h_FmMuram, adTableSize, + FM_PCD_CC_AD_TABLE_ALIGN); + if (!p_CcNode->h_AdTable) + { + DeleteNode(p_CcNode); + RETURN_ERROR(MAJOR, E_NO_MEMORY, + ("MURAM allocation for CC node action descriptors table")); + } + MemSet8((uint8_t *)p_CcNode->h_AdTable, 0, adTableSize); + + p_KeysMatchTblTmp = p_CcNode->h_KeysMatchTable; + p_AdTableTmp = p_CcNode->h_AdTable; + + /* For each key, create the key and the next step AD */ + for (tmp = 0; tmp < p_CcNode->numOfKeys; tmp++) + { + p_KeyParams = &p_CcNodeParam->keysParams.keyParams[tmp]; + + if (p_KeysMatchTblTmp) + { + /* Copy the key */ + MemCpy8((void*)p_KeysMatchTblTmp, p_KeyParams->p_Key, + p_CcNode->sizeOfExtraction); + + /* Copy the key mask or initialize it to 0xFF..F */ + if (p_CcNode->lclMask && p_KeyParams->p_Mask) + { + MemCpy8(PTR_MOVE(p_KeysMatchTblTmp, + p_CcNode->ccKeySizeAccExtraction), /* User's size of extraction rounded up to a valid matching table entry size */ + p_KeyParams->p_Mask, p_CcNode->sizeOfExtraction); /* Exact size of extraction as received from the user */ + } + else + if (p_CcNode->lclMask) + { + MemSet8(PTR_MOVE(p_KeysMatchTblTmp, + p_CcNode->ccKeySizeAccExtraction), /* User's size of extraction rounded up to a valid matching table entry size */ + 0xff, p_CcNode->sizeOfExtraction); /* Exact size of extraction as received from the user */ + } + + p_KeysMatchTblTmp = + PTR_MOVE(p_KeysMatchTblTmp, keySize * sizeof(uint8_t)); + } + + /* Create the next action descriptor in the match table */ + if (p_KeyParams->ccNextEngineParams.statisticsEn) + { + p_StatsObj = GetStatsObj(p_CcNode); + ASSERT_COND(p_StatsObj); + + statsParams.h_StatsAd = p_StatsObj->h_StatsAd; + statsParams.h_StatsCounters = p_StatsObj->h_StatsCounters; +#if (DPAA_VERSION >= 11) + statsParams.h_StatsFLRs = p_CcNode->h_StatsFLRs; + +#endif /* (DPAA_VERSION >= 11) */ + NextStepAd(p_AdTableTmp, &statsParams, + &p_KeyParams->ccNextEngineParams, p_FmPcd); + + p_CcNode->keyAndNextEngineParams[tmp].p_StatsObj = p_StatsObj; + } + else + { + NextStepAd(p_AdTableTmp, NULL, &p_KeyParams->ccNextEngineParams, + p_FmPcd); + + p_CcNode->keyAndNextEngineParams[tmp].p_StatsObj = NULL; + } + + p_AdTableTmp = PTR_MOVE(p_AdTableTmp, FM_PCD_CC_AD_ENTRY_SIZE); + } + + /* Update next engine for the 'miss' entry */ + if (p_CcNodeParam->keysParams.ccNextEngineParamsForMiss.statisticsEn) + { + p_StatsObj = GetStatsObj(p_CcNode); + ASSERT_COND(p_StatsObj); + + /* All 'bucket' nodes of a hash table should share the same statistics counters, + allocated by the hash table. So, if this node is a bucket of a hash table, + we'll replace the locally allocated counters with the shared counters. */ + if (p_CcNode->isHashBucket) + { + ASSERT_COND(p_CcNode->h_MissStatsCounters); + + /* Store original counters pointer and replace it with mutual preallocated pointer */ + p_CcNode->h_PrivMissStatsCounters = p_StatsObj->h_StatsCounters; + p_StatsObj->h_StatsCounters = p_CcNode->h_MissStatsCounters; + } + + statsParams.h_StatsAd = p_StatsObj->h_StatsAd; + statsParams.h_StatsCounters = p_StatsObj->h_StatsCounters; +#if (DPAA_VERSION >= 11) + statsParams.h_StatsFLRs = p_CcNode->h_StatsFLRs; + +#endif /* (DPAA_VERSION >= 11) */ + + NextStepAd(p_AdTableTmp, &statsParams, + &p_CcNodeParam->keysParams.ccNextEngineParamsForMiss, + p_FmPcd); + + p_CcNode->keyAndNextEngineParams[tmp].p_StatsObj = p_StatsObj; + } + else + { + NextStepAd(p_AdTableTmp, NULL, + &p_CcNodeParam->keysParams.ccNextEngineParamsForMiss, + p_FmPcd); + + p_CcNode->keyAndNextEngineParams[tmp].p_StatsObj = NULL; + } + + /* This parameter will be used to initialize the "key length" field in the action descriptor + that points to this node and it should be 0 for full field extraction */ + if (fullField == TRUE) + p_CcNode->sizeOfExtraction = 0; + + for (tmp = 0; tmp < MIN(p_CcNode->numOfKeys + 1, CC_MAX_NUM_OF_KEYS); tmp++) + { + if (p_CcNode->keyAndNextEngineParams[tmp].nextEngineParams.nextEngine + == e_FM_PCD_CC) + { + p_FmPcdCcNextNode = + (t_FmPcdCcNode*)p_CcNode->keyAndNextEngineParams[tmp].nextEngineParams.params.ccParams.h_CcNode; + p_CcInformation = FindNodeInfoInReleventLst( + &p_FmPcdCcNextNode->ccPrevNodesLst, (t_Handle)p_CcNode, + p_FmPcdCcNextNode->h_Spinlock); + if (!p_CcInformation) + { + memset(&ccNodeInfo, 0, sizeof(t_CcNodeInformation)); + ccNodeInfo.h_CcNode = (t_Handle)p_CcNode; + ccNodeInfo.index = 1; + EnqueueNodeInfoToRelevantLst(&p_FmPcdCcNextNode->ccPrevNodesLst, + &ccNodeInfo, + p_FmPcdCcNextNode->h_Spinlock); + } + else + p_CcInformation->index++; + + if (p_CcNode->keyAndNextEngineParams[tmp].nextEngineParams.h_Manip) + { + h_Manip = + p_CcNode->keyAndNextEngineParams[tmp].nextEngineParams.h_Manip; + p_CcInformation = FindNodeInfoInReleventLst( + FmPcdManipGetNodeLstPointedOnThisManip(h_Manip), + (t_Handle)p_CcNode, FmPcdManipGetSpinlock(h_Manip)); + if (!p_CcInformation) + { + memset(&ccNodeInfo, 0, sizeof(t_CcNodeInformation)); + ccNodeInfo.h_CcNode = (t_Handle)p_CcNode; + ccNodeInfo.index = 1; + EnqueueNodeInfoToRelevantLst( + FmPcdManipGetNodeLstPointedOnThisManip(h_Manip), + &ccNodeInfo, FmPcdManipGetSpinlock(h_Manip)); + } + else + p_CcInformation->index++; + } + } + } + + p_AdTableTmp = p_CcNode->h_AdTable; + + if (!FmPcdLockTryLockAll(h_FmPcd)) + { + FM_PCD_MatchTableDelete((t_Handle)p_CcNode); + DBG(TRACE, ("FmPcdLockTryLockAll failed")); + return ERROR_CODE(E_BUSY); + } + + /* Required action for each next engine */ + for (tmp = 0; tmp < MIN(p_CcNode->numOfKeys + 1, CC_MAX_NUM_OF_KEYS); tmp++) + { + if (p_CcNode->keyAndNextEngineParams[tmp].requiredAction) + { + err = SetRequiredAction( + h_FmPcd, + p_CcNode->keyAndNextEngineParams[tmp].requiredAction, + &p_CcNode->keyAndNextEngineParams[tmp], p_AdTableTmp, 1, + NULL); + if (err) + { + FmPcdLockUnlockAll(h_FmPcd); + FM_PCD_MatchTableDelete((t_Handle)p_CcNode); + RETURN_ERROR(MAJOR, err, NO_MSG); + } + p_AdTableTmp = PTR_MOVE(p_AdTableTmp, FM_PCD_CC_AD_ENTRY_SIZE); + } + } + + FmPcdLockUnlockAll(h_FmPcd); + + return E_OK; +} +/************************** End of static functions **************************/ + +/*****************************************************************************/ +/* Inter-module API routines */ +/*****************************************************************************/ + +t_CcNodeInformation* FindNodeInfoInReleventLst(t_List *p_List, t_Handle h_Info, + t_Handle h_Spinlock) +{ + t_CcNodeInformation *p_CcInformation; + t_List *p_Pos; + uint32_t intFlags; + + intFlags = XX_LockIntrSpinlock(h_Spinlock); + + for (p_Pos = LIST_FIRST(p_List); p_Pos != (p_List); + p_Pos = LIST_NEXT(p_Pos)) + { + p_CcInformation = CC_NODE_F_OBJECT(p_Pos); + + ASSERT_COND(p_CcInformation->h_CcNode); + + if (p_CcInformation->h_CcNode == h_Info) + { + XX_UnlockIntrSpinlock(h_Spinlock, intFlags); + return p_CcInformation; + } + } + + XX_UnlockIntrSpinlock(h_Spinlock, intFlags); + + return NULL; +} + +void EnqueueNodeInfoToRelevantLst(t_List *p_List, t_CcNodeInformation *p_CcInfo, + t_Handle h_Spinlock) +{ + t_CcNodeInformation *p_CcInformation; + uint32_t intFlags = 0; + + p_CcInformation = (t_CcNodeInformation *)XX_Malloc( + sizeof(t_CcNodeInformation)); + + if (p_CcInformation) + { + memset(p_CcInformation, 0, sizeof(t_CcNodeInformation)); + memcpy(p_CcInformation, p_CcInfo, sizeof(t_CcNodeInformation)); + INIT_LIST(&p_CcInformation->node); + + if (h_Spinlock) + intFlags = XX_LockIntrSpinlock(h_Spinlock); + + LIST_AddToTail(&p_CcInformation->node, p_List); + + if (h_Spinlock) + XX_UnlockIntrSpinlock(h_Spinlock, intFlags); + } + else + REPORT_ERROR(MAJOR, E_NO_MEMORY, ("CC Node Information")); +} + +void DequeueNodeInfoFromRelevantLst(t_List *p_List, t_Handle h_Info, + t_Handle h_Spinlock) +{ + t_CcNodeInformation *p_CcInformation = NULL; + uint32_t intFlags = 0; + t_List *p_Pos; + + if (h_Spinlock) + intFlags = XX_LockIntrSpinlock(h_Spinlock); + + if (LIST_IsEmpty(p_List)) + { + XX_RestoreAllIntr(intFlags); + return; + } + + for (p_Pos = LIST_FIRST(p_List); p_Pos != (p_List); + p_Pos = LIST_NEXT(p_Pos)) + { + p_CcInformation = CC_NODE_F_OBJECT(p_Pos); + ASSERT_COND(p_CcInformation); + ASSERT_COND(p_CcInformation->h_CcNode); + if (p_CcInformation->h_CcNode == h_Info) + break; + } + + if (p_CcInformation) + { + LIST_DelAndInit(&p_CcInformation->node); + XX_Free(p_CcInformation); + } + + if (h_Spinlock) + XX_UnlockIntrSpinlock(h_Spinlock, intFlags); +} + +void NextStepAd(t_Handle h_Ad, t_FmPcdCcStatsParams *p_FmPcdCcStatsParams, + t_FmPcdCcNextEngineParams *p_FmPcdCcNextEngineParams, + t_FmPcd *p_FmPcd) +{ + switch (p_FmPcdCcNextEngineParams->nextEngine) + { + case (e_FM_PCD_KG): + case (e_FM_PCD_PLCR): + case (e_FM_PCD_DONE): + /* if NIA is not CC, create a "result" type AD */ + FillAdOfTypeResult(h_Ad, p_FmPcdCcStatsParams, p_FmPcd, + p_FmPcdCcNextEngineParams); + break; +#if (DPAA_VERSION >= 11) + case (e_FM_PCD_FR): + if (p_FmPcdCcNextEngineParams->params.frParams.h_FrmReplic) + { + FillAdOfTypeContLookup( + h_Ad, p_FmPcdCcStatsParams, p_FmPcd, + p_FmPcdCcNextEngineParams->params.ccParams.h_CcNode, + p_FmPcdCcNextEngineParams->h_Manip, + p_FmPcdCcNextEngineParams->params.frParams.h_FrmReplic); + FrmReplicGroupUpdateOwner( + p_FmPcdCcNextEngineParams->params.frParams.h_FrmReplic, + TRUE/* add */); + } + break; +#endif /* (DPAA_VERSION >= 11) */ + + case (e_FM_PCD_CC): + /* if NIA is not CC, create a TD to continue the CC lookup */ + FillAdOfTypeContLookup( + h_Ad, p_FmPcdCcStatsParams, p_FmPcd, + p_FmPcdCcNextEngineParams->params.ccParams.h_CcNode, + p_FmPcdCcNextEngineParams->h_Manip, NULL); + + UpdateNodeOwner(p_FmPcdCcNextEngineParams->params.ccParams.h_CcNode, + TRUE); + break; + + default: + return; + } +} + +t_Error FmPcdCcTreeAddIPR(t_Handle h_FmPcd, t_Handle h_FmTree, + t_Handle h_NetEnv, t_Handle h_IpReassemblyManip, + bool createSchemes) +{ + t_FmPcdCcTree *p_FmPcdCcTree = (t_FmPcdCcTree *)h_FmTree; + t_FmPcdCcNextEngineParams nextEngineParams; + t_NetEnvParams netEnvParams; + t_Handle h_Ad; + bool isIpv6Present; + uint8_t ipv4GroupId, ipv6GroupId; + t_Error err; + + ASSERT_COND(p_FmPcdCcTree); + + /* this routine must be protected by the calling routine! */ + + memset(&nextEngineParams, 0, sizeof(t_FmPcdCcNextEngineParams)); + memset(&netEnvParams, 0, sizeof(t_NetEnvParams)); + + h_Ad = UINT_TO_PTR(p_FmPcdCcTree->ccTreeBaseAddr); + + isIpv6Present = FmPcdManipIpReassmIsIpv6Hdr(h_IpReassemblyManip); + + if (isIpv6Present + && (p_FmPcdCcTree->numOfEntries > (FM_PCD_MAX_NUM_OF_CC_GROUPS - 2))) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("need two free entries for IPR")); + + if (p_FmPcdCcTree->numOfEntries > (FM_PCD_MAX_NUM_OF_CC_GROUPS - 1)) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("need two free entries for IPR")); + + nextEngineParams.nextEngine = e_FM_PCD_DONE; + nextEngineParams.h_Manip = h_IpReassemblyManip; + + /* Lock tree */ + err = CcRootTryLock(p_FmPcdCcTree); + if (err) + return ERROR_CODE(E_BUSY); + + if (p_FmPcdCcTree->h_IpReassemblyManip == h_IpReassemblyManip) + { + CcRootReleaseLock(p_FmPcdCcTree); + return E_OK; + } + + if ((p_FmPcdCcTree->h_IpReassemblyManip) + && (p_FmPcdCcTree->h_IpReassemblyManip != h_IpReassemblyManip)) + { + CcRootReleaseLock(p_FmPcdCcTree); + RETURN_ERROR(MAJOR, E_INVALID_STATE, + ("This tree was previously updated with different IPR")); + } + + /* Initialize IPR for the first time for this tree */ + if (isIpv6Present) + { + ipv6GroupId = p_FmPcdCcTree->numOfGrps++; + p_FmPcdCcTree->fmPcdGroupParam[ipv6GroupId].baseGroupEntry = + (FM_PCD_MAX_NUM_OF_CC_GROUPS - 2); + + if (createSchemes) + { + err = FmPcdManipBuildIpReassmScheme(h_FmPcd, h_NetEnv, + p_FmPcdCcTree, + h_IpReassemblyManip, FALSE, + ipv6GroupId); + if (err) + { + p_FmPcdCcTree->numOfGrps--; + CcRootReleaseLock(p_FmPcdCcTree); + RETURN_ERROR(MAJOR, err, NO_MSG); + } + } + + NextStepAd( + PTR_MOVE(h_Ad, (FM_PCD_MAX_NUM_OF_CC_GROUPS-2) * FM_PCD_CC_AD_ENTRY_SIZE), + NULL, &nextEngineParams, h_FmPcd); + } + + ipv4GroupId = p_FmPcdCcTree->numOfGrps++; + p_FmPcdCcTree->fmPcdGroupParam[ipv4GroupId].totalBitsMask = 0; + p_FmPcdCcTree->fmPcdGroupParam[ipv4GroupId].baseGroupEntry = + (FM_PCD_MAX_NUM_OF_CC_GROUPS - 1); + + if (createSchemes) + { + err = FmPcdManipBuildIpReassmScheme(h_FmPcd, h_NetEnv, p_FmPcdCcTree, + h_IpReassemblyManip, TRUE, + ipv4GroupId); + if (err) + { + p_FmPcdCcTree->numOfGrps--; + if (isIpv6Present) + { + p_FmPcdCcTree->numOfGrps--; + FmPcdManipDeleteIpReassmSchemes(h_IpReassemblyManip); + } + CcRootReleaseLock(p_FmPcdCcTree); + RETURN_ERROR(MAJOR, err, NO_MSG); + } + } + + NextStepAd( + PTR_MOVE(h_Ad, (FM_PCD_MAX_NUM_OF_CC_GROUPS-1) * FM_PCD_CC_AD_ENTRY_SIZE), + NULL, &nextEngineParams, h_FmPcd); + + p_FmPcdCcTree->h_IpReassemblyManip = h_IpReassemblyManip; + + CcRootReleaseLock(p_FmPcdCcTree); + + return E_OK; +} + +t_Error FmPcdCcTreeAddCPR(t_Handle h_FmPcd, t_Handle h_FmTree, + t_Handle h_NetEnv, t_Handle h_ReassemblyManip, + bool createSchemes) +{ + t_FmPcdCcTree *p_FmPcdCcTree = (t_FmPcdCcTree *)h_FmTree; + t_FmPcdCcNextEngineParams nextEngineParams; + t_NetEnvParams netEnvParams; + t_Handle h_Ad; + uint8_t groupId; + t_Error err; + + ASSERT_COND(p_FmPcdCcTree); + + /* this routine must be protected by the calling routine! */ + memset(&nextEngineParams, 0, sizeof(t_FmPcdCcNextEngineParams)); + memset(&netEnvParams, 0, sizeof(t_NetEnvParams)); + + h_Ad = UINT_TO_PTR(p_FmPcdCcTree->ccTreeBaseAddr); + + if (p_FmPcdCcTree->numOfEntries > (FM_PCD_MAX_NUM_OF_CC_GROUPS - 1)) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("need one free entries for CPR")); + + nextEngineParams.nextEngine = e_FM_PCD_DONE; + nextEngineParams.h_Manip = h_ReassemblyManip; + + /* Lock tree */ + err = CcRootTryLock(p_FmPcdCcTree); + if (err) + return ERROR_CODE(E_BUSY); + + if (p_FmPcdCcTree->h_CapwapReassemblyManip == h_ReassemblyManip) + { + CcRootReleaseLock(p_FmPcdCcTree); + return E_OK; + } + + if ((p_FmPcdCcTree->h_CapwapReassemblyManip) + && (p_FmPcdCcTree->h_CapwapReassemblyManip != h_ReassemblyManip)) + { + CcRootReleaseLock(p_FmPcdCcTree); + RETURN_ERROR(MAJOR, E_INVALID_STATE, + ("This tree was previously updated with different CPR")); + } + + groupId = p_FmPcdCcTree->numOfGrps++; + p_FmPcdCcTree->fmPcdGroupParam[groupId].baseGroupEntry = + (FM_PCD_MAX_NUM_OF_CC_GROUPS - 1); + + if (createSchemes) + { + err = FmPcdManipBuildCapwapReassmScheme(h_FmPcd, h_NetEnv, + p_FmPcdCcTree, + h_ReassemblyManip, groupId); + if (err) + { + p_FmPcdCcTree->numOfGrps--; + CcRootReleaseLock(p_FmPcdCcTree); + RETURN_ERROR(MAJOR, err, NO_MSG); + } + } + + NextStepAd( + PTR_MOVE(h_Ad, (FM_PCD_MAX_NUM_OF_CC_GROUPS-1) * FM_PCD_CC_AD_ENTRY_SIZE), + NULL, &nextEngineParams, h_FmPcd); + + p_FmPcdCcTree->h_CapwapReassemblyManip = h_ReassemblyManip; + + CcRootReleaseLock(p_FmPcdCcTree); + + return E_OK; +} + +t_Handle FmPcdCcTreeGetSavedManipParams(t_Handle h_FmTree) +{ + t_FmPcdCcTree *p_FmPcdCcTree = (t_FmPcdCcTree *)h_FmTree; + + ASSERT_COND(p_FmPcdCcTree); + + return p_FmPcdCcTree->h_FmPcdCcSavedManipParams; +} + +void FmPcdCcTreeSetSavedManipParams(t_Handle h_FmTree, + t_Handle h_SavedManipParams) +{ + t_FmPcdCcTree *p_FmPcdCcTree = (t_FmPcdCcTree *)h_FmTree; + + ASSERT_COND(p_FmPcdCcTree); + + p_FmPcdCcTree->h_FmPcdCcSavedManipParams = h_SavedManipParams; +} + +uint8_t FmPcdCcGetParseCode(t_Handle h_CcNode) +{ + t_FmPcdCcNode *p_CcNode = (t_FmPcdCcNode *)h_CcNode; + + ASSERT_COND(p_CcNode); + + return p_CcNode->parseCode; +} + +uint8_t FmPcdCcGetOffset(t_Handle h_CcNode) +{ + t_FmPcdCcNode *p_CcNode = (t_FmPcdCcNode *)h_CcNode; + + ASSERT_COND(p_CcNode); + + return p_CcNode->offset; +} + +uint16_t FmPcdCcGetNumOfKeys(t_Handle h_CcNode) +{ + t_FmPcdCcNode *p_CcNode = (t_FmPcdCcNode *)h_CcNode; + + ASSERT_COND(p_CcNode); + + return p_CcNode->numOfKeys; +} + +t_Error FmPcdCcModifyNextEngineParamTree( + t_Handle h_FmPcd, t_Handle h_FmPcdCcTree, uint8_t grpId, uint8_t index, + t_FmPcdCcNextEngineParams *p_FmPcdCcNextEngineParams) +{ + t_FmPcdCcTree *p_FmPcdCcTree = (t_FmPcdCcTree *)h_FmPcdCcTree; + t_FmPcd *p_FmPcd; + t_List h_OldPointersLst, h_NewPointersLst; + uint16_t keyIndex; + t_FmPcdModifyCcKeyAdditionalParams *p_ModifyKeyParams; + t_Error err = E_OK; + + SANITY_CHECK_RETURN_ERROR(h_FmPcd, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(h_FmPcdCcTree, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR((grpId <= 7), E_INVALID_VALUE); + + if (grpId >= p_FmPcdCcTree->numOfGrps) + RETURN_ERROR(MAJOR, E_INVALID_HANDLE, + ("grpId you asked > numOfGroup of relevant tree")); + + if (index >= p_FmPcdCcTree->fmPcdGroupParam[grpId].numOfEntriesInGroup) + RETURN_ERROR(MAJOR, E_INVALID_HANDLE, ("index > numOfEntriesInGroup")); + + p_FmPcd = (t_FmPcd *)h_FmPcd; + + INIT_LIST(&h_OldPointersLst); + INIT_LIST(&h_NewPointersLst); + + keyIndex = (uint16_t)(p_FmPcdCcTree->fmPcdGroupParam[grpId].baseGroupEntry + + index); + + p_ModifyKeyParams = ModifyNodeCommonPart(p_FmPcdCcTree, keyIndex, + e_MODIFY_STATE_CHANGE, FALSE, + FALSE, TRUE); + if (!p_ModifyKeyParams) + RETURN_ERROR(MAJOR, E_INVALID_STATE, NO_MSG); + + p_ModifyKeyParams->tree = TRUE; + + if (p_FmPcd->p_CcShadow + && !TRY_LOCK(p_FmPcd->h_ShadowSpinlock, &p_FmPcd->shadowLock)) + { + XX_Free(p_ModifyKeyParams); + return ERROR_CODE(E_BUSY); + } + + err = BuildNewNodeModifyNextEngine(p_FmPcd, p_FmPcdCcTree, keyIndex, + p_FmPcdCcNextEngineParams, + &h_OldPointersLst, &h_NewPointersLst, + p_ModifyKeyParams); + if (err) + { + XX_Free(p_ModifyKeyParams); + RETURN_ERROR(MAJOR, err, NO_MSG); + } + + err = DoDynamicChange(p_FmPcd, &h_OldPointersLst, &h_NewPointersLst, + p_ModifyKeyParams, FALSE); + + if (p_FmPcd->p_CcShadow) + RELEASE_LOCK(p_FmPcd->shadowLock); + + ReleaseLst(&h_OldPointersLst); + ReleaseLst(&h_NewPointersLst); + + return err; + +} + +t_Error FmPcdCcRemoveKey(t_Handle h_FmPcd, t_Handle h_FmPcdCcNode, + uint16_t keyIndex) +{ + + t_FmPcdCcNode *p_CcNode = (t_FmPcdCcNode *)h_FmPcdCcNode; + t_FmPcd *p_FmPcd; + t_FmPcdModifyCcKeyAdditionalParams *p_ModifyKeyParams; + t_List h_OldPointersLst, h_NewPointersLst; + bool useShadowStructs = FALSE; + t_Error err = E_OK; + + if (keyIndex >= p_CcNode->numOfKeys) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, + ("impossible to remove key when numOfKeys <= keyIndex")); + + if (p_CcNode->h_FmPcd != h_FmPcd) + RETURN_ERROR( + MAJOR, + E_INVALID_VALUE, + ("handler to FmPcd is different from the handle provided at node initialization time")); + + p_FmPcd = (t_FmPcd *)p_CcNode->h_FmPcd; + + INIT_LIST(&h_OldPointersLst); + INIT_LIST(&h_NewPointersLst); + + p_ModifyKeyParams = ModifyNodeCommonPart(p_CcNode, keyIndex, + e_MODIFY_STATE_REMOVE, TRUE, TRUE, + FALSE); + if (!p_ModifyKeyParams) + RETURN_ERROR(MAJOR, E_INVALID_STATE, NO_MSG); + + if (p_CcNode->maxNumOfKeys) + { + if (!TRY_LOCK(p_FmPcd->h_ShadowSpinlock, &p_FmPcd->shadowLock)) + { + XX_Free(p_ModifyKeyParams); + return ERROR_CODE(E_BUSY); + } + + useShadowStructs = TRUE; + } + + err = BuildNewNodeRemoveKey(p_CcNode, keyIndex, p_ModifyKeyParams); + if (err) + { + XX_Free(p_ModifyKeyParams); + if (p_CcNode->maxNumOfKeys) + RELEASE_LOCK(p_FmPcd->shadowLock); + RETURN_ERROR(MAJOR, err, NO_MSG); + } + + err = UpdatePtrWhichPointOnCrntMdfNode(p_CcNode, p_ModifyKeyParams, + &h_OldPointersLst, + &h_NewPointersLst); + if (err) + { + ReleaseNewNodeCommonPart(p_ModifyKeyParams); + XX_Free(p_ModifyKeyParams); + if (p_CcNode->maxNumOfKeys) + RELEASE_LOCK(p_FmPcd->shadowLock); + RETURN_ERROR(MAJOR, err, NO_MSG); + } + + err = DoDynamicChange(p_FmPcd, &h_OldPointersLst, &h_NewPointersLst, + p_ModifyKeyParams, useShadowStructs); + + if (p_CcNode->maxNumOfKeys) + RELEASE_LOCK(p_FmPcd->shadowLock); + + ReleaseLst(&h_OldPointersLst); + ReleaseLst(&h_NewPointersLst); + + return err; +} + +t_Error FmPcdCcModifyKey(t_Handle h_FmPcd, t_Handle h_FmPcdCcNode, + uint16_t keyIndex, uint8_t keySize, uint8_t *p_Key, + uint8_t *p_Mask) +{ + t_FmPcdCcNode *p_CcNode = (t_FmPcdCcNode *)h_FmPcdCcNode; + t_FmPcd *p_FmPcd; + t_List h_OldPointersLst, h_NewPointersLst; + t_FmPcdModifyCcKeyAdditionalParams *p_ModifyKeyParams; + uint16_t tmpKeyIndex; + bool useShadowStructs = FALSE; + t_Error err = E_OK; + + if (keyIndex >= p_CcNode->numOfKeys) + RETURN_ERROR(MAJOR, E_INVALID_STATE, + ("keyIndex > previously cleared last index + 1")); + + if (keySize != p_CcNode->userSizeOfExtraction) + RETURN_ERROR( + MAJOR, + E_INVALID_VALUE, + ("size for ModifyKey has to be the same as defined in SetNode")); + + if (p_CcNode->h_FmPcd != h_FmPcd) + RETURN_ERROR( + MAJOR, + E_INVALID_VALUE, + ("handler to FmPcd is different from the handle provided at node initialization time")); + + err = FindKeyIndex(h_FmPcdCcNode, keySize, p_Key, p_Mask, &tmpKeyIndex); + if (GET_ERROR_TYPE(err) != E_NOT_FOUND) + RETURN_ERROR( + MINOR, + E_ALREADY_EXISTS, + ("The received key and mask pair was already found in the match table of the provided node")); + + p_FmPcd = (t_FmPcd *)p_CcNode->h_FmPcd; + + INIT_LIST(&h_OldPointersLst); + INIT_LIST(&h_NewPointersLst); + + p_ModifyKeyParams = ModifyNodeCommonPart(p_CcNode, keyIndex, + e_MODIFY_STATE_CHANGE, TRUE, TRUE, + FALSE); + if (!p_ModifyKeyParams) + RETURN_ERROR(MAJOR, E_INVALID_STATE, NO_MSG); + + if (p_CcNode->maxNumOfKeys) + { + if (!TRY_LOCK(p_FmPcd->h_ShadowSpinlock, &p_FmPcd->shadowLock)) + { + XX_Free(p_ModifyKeyParams); + return ERROR_CODE(E_BUSY); + } + + useShadowStructs = TRUE; + } + + err = BuildNewNodeModifyKey(p_CcNode, keyIndex, p_Key, p_Mask, + p_ModifyKeyParams); + if (err) + { + XX_Free(p_ModifyKeyParams); + if (p_CcNode->maxNumOfKeys) + RELEASE_LOCK(p_FmPcd->shadowLock); + RETURN_ERROR(MAJOR, err, NO_MSG); + } + + err = UpdatePtrWhichPointOnCrntMdfNode(p_CcNode, p_ModifyKeyParams, + &h_OldPointersLst, + &h_NewPointersLst); + if (err) + { + ReleaseNewNodeCommonPart(p_ModifyKeyParams); + XX_Free(p_ModifyKeyParams); + if (p_CcNode->maxNumOfKeys) + RELEASE_LOCK(p_FmPcd->shadowLock); + RETURN_ERROR(MAJOR, err, NO_MSG); + } + + err = DoDynamicChange(p_FmPcd, &h_OldPointersLst, &h_NewPointersLst, + p_ModifyKeyParams, useShadowStructs); + + if (p_CcNode->maxNumOfKeys) + RELEASE_LOCK(p_FmPcd->shadowLock); + + ReleaseLst(&h_OldPointersLst); + ReleaseLst(&h_NewPointersLst); + + return err; +} + +t_Error FmPcdCcModifyMissNextEngineParamNode( + t_Handle h_FmPcd, t_Handle h_FmPcdCcNode, + t_FmPcdCcNextEngineParams *p_FmPcdCcNextEngineParams) +{ + t_FmPcdCcNode *p_CcNode = (t_FmPcdCcNode *)h_FmPcdCcNode; + t_FmPcd *p_FmPcd; + t_List h_OldPointersLst, h_NewPointersLst; + uint16_t keyIndex; + t_FmPcdModifyCcKeyAdditionalParams *p_ModifyKeyParams; + t_Error err = E_OK; + + SANITY_CHECK_RETURN_ERROR(p_CcNode, E_INVALID_VALUE); + + keyIndex = p_CcNode->numOfKeys; + + p_FmPcd = (t_FmPcd *)p_CcNode->h_FmPcd; + + INIT_LIST(&h_OldPointersLst); + INIT_LIST(&h_NewPointersLst); + + p_ModifyKeyParams = ModifyNodeCommonPart(p_CcNode, keyIndex, + e_MODIFY_STATE_CHANGE, FALSE, TRUE, + FALSE); + if (!p_ModifyKeyParams) + RETURN_ERROR(MAJOR, E_INVALID_STATE, NO_MSG); + + if (p_CcNode->maxNumOfKeys + && !TRY_LOCK(p_FmPcd->h_ShadowSpinlock, &p_FmPcd->shadowLock)) + { + XX_Free(p_ModifyKeyParams); + return ERROR_CODE(E_BUSY); + } + + err = BuildNewNodeModifyNextEngine(h_FmPcd, p_CcNode, keyIndex, + p_FmPcdCcNextEngineParams, + &h_OldPointersLst, &h_NewPointersLst, + p_ModifyKeyParams); + if (err) + { + XX_Free(p_ModifyKeyParams); + if (p_CcNode->maxNumOfKeys) + RELEASE_LOCK(p_FmPcd->shadowLock); + RETURN_ERROR(MAJOR, err, NO_MSG); + } + + err = DoDynamicChange(p_FmPcd, &h_OldPointersLst, &h_NewPointersLst, + p_ModifyKeyParams, FALSE); + + if (p_CcNode->maxNumOfKeys) + RELEASE_LOCK(p_FmPcd->shadowLock); + + ReleaseLst(&h_OldPointersLst); + ReleaseLst(&h_NewPointersLst); + + return err; +} + +t_Error FmPcdCcAddKey(t_Handle h_FmPcd, t_Handle h_FmPcdCcNode, + uint16_t keyIndex, uint8_t keySize, + t_FmPcdCcKeyParams *p_FmPcdCcKeyParams) +{ + t_FmPcdCcNode *p_CcNode = (t_FmPcdCcNode *)h_FmPcdCcNode; + t_FmPcd *p_FmPcd; + t_FmPcdModifyCcKeyAdditionalParams *p_ModifyKeyParams; + t_List h_OldPointersLst, h_NewPointersLst; + bool useShadowStructs = FALSE; + uint16_t tmpKeyIndex; + t_Error err = E_OK; + + if (keyIndex > p_CcNode->numOfKeys) + RETURN_ERROR(MAJOR, E_NOT_IN_RANGE, + ("keyIndex > previously cleared last index + 1")); + + if (keySize != p_CcNode->userSizeOfExtraction) + RETURN_ERROR( + MAJOR, + E_INVALID_VALUE, + ("keySize has to be defined as it was defined in initialization step")); + + if (p_CcNode->h_FmPcd != h_FmPcd) + RETURN_ERROR( + MAJOR, + E_INVALID_VALUE, + ("handler to FmPcd is different from the handle provided at node initialization time")); + + if (p_CcNode->maxNumOfKeys) + { + if (p_CcNode->numOfKeys == p_CcNode->maxNumOfKeys) + RETURN_ERROR( + MAJOR, + E_FULL, + ("number of keys exceeds the maximal number of keys provided at node initialization time")); + } + else + if (p_CcNode->numOfKeys == FM_PCD_MAX_NUM_OF_KEYS) + RETURN_ERROR( + MAJOR, + E_INVALID_VALUE, + ("number of keys can not be larger than %d", FM_PCD_MAX_NUM_OF_KEYS)); + + err = FindKeyIndex(h_FmPcdCcNode, keySize, p_FmPcdCcKeyParams->p_Key, + p_FmPcdCcKeyParams->p_Mask, &tmpKeyIndex); + if (GET_ERROR_TYPE(err) != E_NOT_FOUND) + RETURN_ERROR( + MAJOR, + E_ALREADY_EXISTS, + ("The received key and mask pair was already found in the match table of the provided node")); + + p_FmPcd = (t_FmPcd *)p_CcNode->h_FmPcd; + + INIT_LIST(&h_OldPointersLst); + INIT_LIST(&h_NewPointersLst); + + p_ModifyKeyParams = ModifyNodeCommonPart(p_CcNode, keyIndex, + e_MODIFY_STATE_ADD, TRUE, TRUE, + FALSE); + if (!p_ModifyKeyParams) + RETURN_ERROR(MAJOR, E_INVALID_STATE, NO_MSG); + + if (p_CcNode->maxNumOfKeys) + { + if (!TRY_LOCK(p_FmPcd->h_ShadowSpinlock, &p_FmPcd->shadowLock)) + { + XX_Free(p_ModifyKeyParams); + return ERROR_CODE(E_BUSY); + } + + useShadowStructs = TRUE; + } + + err = BuildNewNodeAddOrMdfyKeyAndNextEngine(h_FmPcd, p_CcNode, keyIndex, + p_FmPcdCcKeyParams, + p_ModifyKeyParams, TRUE); + if (err) + { + ReleaseNewNodeCommonPart(p_ModifyKeyParams); + XX_Free(p_ModifyKeyParams); + if (p_CcNode->maxNumOfKeys) + RELEASE_LOCK(p_FmPcd->shadowLock); + RETURN_ERROR(MAJOR, err, NO_MSG); + } + + err = UpdatePtrWhichPointOnCrntMdfNode(p_CcNode, p_ModifyKeyParams, + &h_OldPointersLst, + &h_NewPointersLst); + if (err) + { + ReleaseNewNodeCommonPart(p_ModifyKeyParams); + XX_Free(p_ModifyKeyParams); + if (p_CcNode->maxNumOfKeys) + RELEASE_LOCK(p_FmPcd->shadowLock); + RETURN_ERROR(MAJOR, err, NO_MSG); + } + + err = DoDynamicChange(p_FmPcd, &h_OldPointersLst, &h_NewPointersLst, + p_ModifyKeyParams, useShadowStructs); + if (p_CcNode->maxNumOfKeys) + RELEASE_LOCK(p_FmPcd->shadowLock); + + ReleaseLst(&h_OldPointersLst); + ReleaseLst(&h_NewPointersLst); + + return err; +} + +t_Error FmPcdCcModifyKeyAndNextEngine(t_Handle h_FmPcd, t_Handle h_FmPcdCcNode, + uint16_t keyIndex, uint8_t keySize, + t_FmPcdCcKeyParams *p_FmPcdCcKeyParams) +{ + t_FmPcdCcNode *p_CcNode = (t_FmPcdCcNode *)h_FmPcdCcNode; + t_FmPcd *p_FmPcd; + t_List h_OldPointersLst, h_NewPointersLst; + t_FmPcdModifyCcKeyAdditionalParams *p_ModifyKeyParams; + uint16_t tmpKeyIndex; + bool useShadowStructs = FALSE; + t_Error err = E_OK; + + if (keyIndex > p_CcNode->numOfKeys) + RETURN_ERROR(MAJOR, E_INVALID_STATE, + ("keyIndex > previously cleared last index + 1")); + + if (keySize != p_CcNode->userSizeOfExtraction) + RETURN_ERROR( + MAJOR, + E_INVALID_VALUE, + ("keySize has to be defined as it was defined in initialization step")); + + if (p_CcNode->h_FmPcd != h_FmPcd) + RETURN_ERROR( + MAJOR, + E_INVALID_VALUE, + ("handler to FmPcd is different from the handle provided at node initialization time")); + + err = FindKeyIndex(h_FmPcdCcNode, keySize, p_FmPcdCcKeyParams->p_Key, + p_FmPcdCcKeyParams->p_Mask, &tmpKeyIndex); + if (GET_ERROR_TYPE(err) != E_NOT_FOUND) + RETURN_ERROR( + MINOR, + E_ALREADY_EXISTS, + ("The received key and mask pair was already found in the match table of the provided node")); + + p_FmPcd = (t_FmPcd *)p_CcNode->h_FmPcd; + + INIT_LIST(&h_OldPointersLst); + INIT_LIST(&h_NewPointersLst); + + p_ModifyKeyParams = ModifyNodeCommonPart(p_CcNode, keyIndex, + e_MODIFY_STATE_CHANGE, TRUE, TRUE, + FALSE); + if (!p_ModifyKeyParams) + RETURN_ERROR(MAJOR, E_INVALID_STATE, NO_MSG); + + if (p_CcNode->maxNumOfKeys) + { + if (!TRY_LOCK(p_FmPcd->h_ShadowSpinlock, &p_FmPcd->shadowLock)) + { + XX_Free(p_ModifyKeyParams); + return ERROR_CODE(E_BUSY); + } + + useShadowStructs = TRUE; + } + + err = BuildNewNodeAddOrMdfyKeyAndNextEngine(h_FmPcd, p_CcNode, keyIndex, + p_FmPcdCcKeyParams, + p_ModifyKeyParams, FALSE); + if (err) + { + ReleaseNewNodeCommonPart(p_ModifyKeyParams); + XX_Free(p_ModifyKeyParams); + if (p_CcNode->maxNumOfKeys) + RELEASE_LOCK(p_FmPcd->shadowLock); + RETURN_ERROR(MAJOR, err, NO_MSG); + } + + err = UpdatePtrWhichPointOnCrntMdfNode(p_CcNode, p_ModifyKeyParams, + &h_OldPointersLst, + &h_NewPointersLst); + if (err) + { + ReleaseNewNodeCommonPart(p_ModifyKeyParams); + XX_Free(p_ModifyKeyParams); + if (p_CcNode->maxNumOfKeys) + RELEASE_LOCK(p_FmPcd->shadowLock); + RETURN_ERROR(MAJOR, err, NO_MSG); + } + + err = DoDynamicChange(p_FmPcd, &h_OldPointersLst, &h_NewPointersLst, + p_ModifyKeyParams, useShadowStructs); + + if (p_CcNode->maxNumOfKeys) + RELEASE_LOCK(p_FmPcd->shadowLock); + + ReleaseLst(&h_OldPointersLst); + ReleaseLst(&h_NewPointersLst); + + return err; +} + +uint32_t FmPcdCcGetNodeAddrOffsetFromNodeInfo(t_Handle h_FmPcd, + t_Handle h_Pointer) +{ + t_FmPcd *p_FmPcd = (t_FmPcd *)h_FmPcd; + t_CcNodeInformation *p_CcNodeInfo; + + SANITY_CHECK_RETURN_VALUE(h_FmPcd, E_INVALID_HANDLE, + (uint32_t)ILLEGAL_BASE); + + p_CcNodeInfo = CC_NODE_F_OBJECT(h_Pointer); + + return (uint32_t)(XX_VirtToPhys(p_CcNodeInfo->h_CcNode) + - p_FmPcd->physicalMuramBase); +} + +t_Error FmPcdCcGetGrpParams(t_Handle h_FmPcdCcTree, uint8_t grpId, + uint32_t *p_GrpBits, uint8_t *p_GrpBase) +{ + t_FmPcdCcTree *p_FmPcdCcTree = (t_FmPcdCcTree *)h_FmPcdCcTree; + + SANITY_CHECK_RETURN_ERROR(h_FmPcdCcTree, E_INVALID_HANDLE); + + if (grpId >= p_FmPcdCcTree->numOfGrps) + RETURN_ERROR(MAJOR, E_INVALID_HANDLE, + ("grpId you asked > numOfGroup of relevant tree")); + + *p_GrpBits = p_FmPcdCcTree->fmPcdGroupParam[grpId].totalBitsMask; + *p_GrpBase = p_FmPcdCcTree->fmPcdGroupParam[grpId].baseGroupEntry; + + return E_OK; +} + +t_Error FmPcdCcBindTree(t_Handle h_FmPcd, t_Handle h_PcdParams, + t_Handle h_FmPcdCcTree, uint32_t *p_Offset, + t_Handle h_FmPort) +{ + t_FmPcd *p_FmPcd = (t_FmPcd*)h_FmPcd; + t_FmPcdCcTree *p_FmPcdCcTree = (t_FmPcdCcTree *)h_FmPcdCcTree; + t_Error err = E_OK; + + SANITY_CHECK_RETURN_ERROR(h_FmPcd, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(h_FmPcdCcTree, E_INVALID_HANDLE); + + /* this routine must be protected by the calling routine by locking all PCD modules! */ + + err = CcUpdateParams(h_FmPcd, h_PcdParams, h_FmPort, h_FmPcdCcTree, TRUE); + + if (err == E_OK) + UpdateCcRootOwner(p_FmPcdCcTree, TRUE); + + *p_Offset = (uint32_t)(XX_VirtToPhys( + UINT_TO_PTR(p_FmPcdCcTree->ccTreeBaseAddr)) + - p_FmPcd->physicalMuramBase); + + return err; +} + +t_Error FmPcdCcUnbindTree(t_Handle h_FmPcd, t_Handle h_FmPcdCcTree) +{ + t_FmPcdCcTree *p_FmPcdCcTree = (t_FmPcdCcTree *)h_FmPcdCcTree; + + /* this routine must be protected by the calling routine by locking all PCD modules! */ + + UNUSED(h_FmPcd); + + SANITY_CHECK_RETURN_ERROR(h_FmPcdCcTree, E_INVALID_HANDLE); + + UpdateCcRootOwner(p_FmPcdCcTree, FALSE); + + return E_OK; +} + +t_Error FmPcdCcNodeTreeTryLock(t_Handle h_FmPcd, t_Handle h_FmPcdCcNode, + t_List *p_List) +{ + t_FmPcdCcNode *p_CcNode = (t_FmPcdCcNode *)h_FmPcdCcNode; + t_List *p_Pos, *p_Tmp; + t_CcNodeInformation *p_CcNodeInfo, nodeInfo; + uint32_t intFlags; + t_Error err = E_OK; + + intFlags = FmPcdLock(h_FmPcd); + + LIST_FOR_EACH(p_Pos, &p_CcNode->ccTreesLst) + { + p_CcNodeInfo = CC_NODE_F_OBJECT(p_Pos); + ASSERT_COND(p_CcNodeInfo->h_CcNode); + + err = CcRootTryLock(p_CcNodeInfo->h_CcNode); + + if (err) + { + LIST_FOR_EACH(p_Tmp, &p_CcNode->ccTreesLst) + { + if (p_Tmp == p_Pos) + break; + + CcRootReleaseLock(p_CcNodeInfo->h_CcNode); + } + break; + } + + memset(&nodeInfo, 0, sizeof(t_CcNodeInformation)); + nodeInfo.h_CcNode = p_CcNodeInfo->h_CcNode; + EnqueueNodeInfoToRelevantLst(p_List, &nodeInfo, NULL); + } + + FmPcdUnlock(h_FmPcd, intFlags); + CORE_MemoryBarrier(); + + return err; +} + +void FmPcdCcNodeTreeReleaseLock(t_Handle h_FmPcd, t_List *p_List) +{ + t_List *p_Pos; + t_CcNodeInformation *p_CcNodeInfo; + t_Handle h_FmPcdCcTree; + uint32_t intFlags; + + intFlags = FmPcdLock(h_FmPcd); + + LIST_FOR_EACH(p_Pos, p_List) + { + p_CcNodeInfo = CC_NODE_F_OBJECT(p_Pos); + h_FmPcdCcTree = p_CcNodeInfo->h_CcNode; + CcRootReleaseLock(h_FmPcdCcTree); + } + + ReleaseLst(p_List); + + FmPcdUnlock(h_FmPcd, intFlags); + CORE_MemoryBarrier(); +} + +t_Error FmPcdUpdateCcShadow(t_FmPcd *p_FmPcd, uint32_t size, uint32_t align) +{ + uint32_t intFlags; + uint32_t newSize = 0, newAlign = 0; + bool allocFail = FALSE; + + ASSERT_COND(p_FmPcd); + + if (!size) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("size must be larger then 0")); + + if (!POWER_OF_2(align)) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("alignment must be power of 2")); + + newSize = p_FmPcd->ccShadowSize; + newAlign = p_FmPcd->ccShadowAlign; + + /* Check if current shadow is large enough to hold the requested size */ + if (size > p_FmPcd->ccShadowSize) + newSize = size; + + /* Check if current shadow matches the requested alignment */ + if (align > p_FmPcd->ccShadowAlign) + newAlign = align; + + /* If a bigger shadow size or bigger shadow alignment are required, + a new shadow will be allocated */ + if ((newSize != p_FmPcd->ccShadowSize) + || (newAlign != p_FmPcd->ccShadowAlign)) + { + intFlags = FmPcdLock(p_FmPcd); + + if (p_FmPcd->p_CcShadow) + { + FM_MURAM_FreeMem(FmPcdGetMuramHandle(p_FmPcd), p_FmPcd->p_CcShadow); + p_FmPcd->ccShadowSize = 0; + p_FmPcd->ccShadowAlign = 0; + } + + p_FmPcd->p_CcShadow = FM_MURAM_AllocMem(FmPcdGetMuramHandle(p_FmPcd), + newSize, newAlign); + if (!p_FmPcd->p_CcShadow) + { + allocFail = TRUE; + + /* If new shadow size allocation failed, + re-allocate with previous parameters */ + p_FmPcd->p_CcShadow = FM_MURAM_AllocMem( + FmPcdGetMuramHandle(p_FmPcd), p_FmPcd->ccShadowSize, + p_FmPcd->ccShadowAlign); + } + + FmPcdUnlock(p_FmPcd, intFlags); + + if (allocFail) + RETURN_ERROR(MAJOR, E_NO_MEMORY, + ("MURAM allocation for CC Shadow memory")); + + p_FmPcd->ccShadowSize = newSize; + p_FmPcd->ccShadowAlign = newAlign; + } + + return E_OK; +} + +#if (DPAA_VERSION >= 11) +void FmPcdCcGetAdTablesThatPointOnReplicGroup(t_Handle h_Node, + t_Handle h_ReplicGroup, + t_List *p_AdTables, + uint32_t *p_NumOfAdTables) +{ + t_FmPcdCcNode *p_CurrentNode = (t_FmPcdCcNode *)h_Node; + int i = 0; + void * p_AdTable; + t_CcNodeInformation ccNodeInfo; + + ASSERT_COND(h_Node); + *p_NumOfAdTables = 0; + + /* search in the current node which exact index points on this current replicator group for getting AD */ + for (i = 0; i < p_CurrentNode->numOfKeys + 1; i++) + { + if ((p_CurrentNode->keyAndNextEngineParams[i].nextEngineParams.nextEngine + == e_FM_PCD_FR) + && ((p_CurrentNode->keyAndNextEngineParams[i].nextEngineParams.params.frParams.h_FrmReplic + == (t_Handle)h_ReplicGroup))) + { + /* save the current ad table in the list */ + /* this entry uses the input replicator group */ + p_AdTable = + PTR_MOVE(p_CurrentNode->h_AdTable, i*FM_PCD_CC_AD_ENTRY_SIZE); + memset(&ccNodeInfo, 0, sizeof(t_CcNodeInformation)); + ccNodeInfo.h_CcNode = p_AdTable; + EnqueueNodeInfoToRelevantLst(p_AdTables, &ccNodeInfo, NULL); + (*p_NumOfAdTables)++; + } + } + + ASSERT_COND(i != p_CurrentNode->numOfKeys); +} +#endif /* (DPAA_VERSION >= 11) */ +/*********************** End of inter-module routines ************************/ + +/****************************************/ +/* API Init unit functions */ +/****************************************/ + +t_Handle FM_PCD_CcRootBuild(t_Handle h_FmPcd, + t_FmPcdCcTreeParams *p_PcdGroupsParam) +{ + t_FmPcd *p_FmPcd = (t_FmPcd *)h_FmPcd; + t_Error err = E_OK; + int i = 0, j = 0, k = 0; + t_FmPcdCcTree *p_FmPcdCcTree; + uint8_t numOfEntries; + t_Handle p_CcTreeTmp; + t_FmPcdCcGrpParams *p_FmPcdCcGroupParams; + t_FmPcdCcKeyAndNextEngineParams *p_Params, *p_KeyAndNextEngineParams; + t_NetEnvParams netEnvParams; + uint8_t lastOne = 0; + uint32_t requiredAction = 0; + t_FmPcdCcNode *p_FmPcdCcNextNode; + t_CcNodeInformation ccNodeInfo, *p_CcInformation; + + SANITY_CHECK_RETURN_VALUE(h_FmPcd, E_INVALID_HANDLE, NULL); + SANITY_CHECK_RETURN_VALUE(p_PcdGroupsParam, E_INVALID_HANDLE, NULL); + + if (p_PcdGroupsParam->numOfGrps > FM_PCD_MAX_NUM_OF_CC_GROUPS) + { + REPORT_ERROR(MAJOR, E_INVALID_VALUE, ("numOfGrps should not exceed %d", FM_PCD_MAX_NUM_OF_CC_GROUPS)); + return NULL; + } + + p_FmPcdCcTree = (t_FmPcdCcTree*)XX_Malloc(sizeof(t_FmPcdCcTree)); + if (!p_FmPcdCcTree) + { + REPORT_ERROR(MAJOR, E_NO_MEMORY, ("PCD tree structure")); + return NULL; + } + memset(p_FmPcdCcTree, 0, sizeof(t_FmPcdCcTree)); + p_FmPcdCcTree->h_FmPcd = h_FmPcd; + + p_Params = (t_FmPcdCcKeyAndNextEngineParams*)XX_Malloc( + FM_PCD_MAX_NUM_OF_CC_GROUPS + * sizeof(t_FmPcdCcKeyAndNextEngineParams)); + memset(p_Params, + 0, + FM_PCD_MAX_NUM_OF_CC_GROUPS + * sizeof(t_FmPcdCcKeyAndNextEngineParams)); + + INIT_LIST(&p_FmPcdCcTree->fmPortsLst); + +#ifdef FM_CAPWAP_SUPPORT + if ((p_PcdGroupsParam->numOfGrps == 1) && + (p_PcdGroupsParam->ccGrpParams[0].numOfDistinctionUnits == 0) && + (p_PcdGroupsParam->ccGrpParams[0].nextEnginePerEntriesInGrp[0].nextEngine == e_FM_PCD_CC) && + p_PcdGroupsParam->ccGrpParams[0].nextEnginePerEntriesInGrp[0].params.ccParams.h_CcNode && + IsCapwapApplSpecific(p_PcdGroupsParam->ccGrpParams[0].nextEnginePerEntriesInGrp[0].params.ccParams.h_CcNode)) + { + p_PcdGroupsParam->ccGrpParams[0].nextEnginePerEntriesInGrp[0].h_Manip = FmPcdManipApplSpecificBuild(); + if (!p_PcdGroupsParam->ccGrpParams[0].nextEnginePerEntriesInGrp[0].h_Manip) + { + DeleteTree(p_FmPcdCcTree,p_FmPcd); + XX_Free(p_Params); + REPORT_ERROR(MAJOR, E_INVALID_STATE, NO_MSG); + return NULL; + } + } +#endif /* FM_CAPWAP_SUPPORT */ + + numOfEntries = 0; + p_FmPcdCcTree->netEnvId = FmPcdGetNetEnvId(p_PcdGroupsParam->h_NetEnv); + + for (i = 0; i < p_PcdGroupsParam->numOfGrps; i++) + { + p_FmPcdCcGroupParams = &p_PcdGroupsParam->ccGrpParams[i]; + + if (p_FmPcdCcGroupParams->numOfDistinctionUnits + > FM_PCD_MAX_NUM_OF_CC_UNITS) + { + DeleteTree(p_FmPcdCcTree, p_FmPcd); + XX_Free(p_Params); + REPORT_ERROR(MAJOR, E_INVALID_VALUE, + ("numOfDistinctionUnits (group %d) should not exceed %d", i, FM_PCD_MAX_NUM_OF_CC_UNITS)); + return NULL; + } + + p_FmPcdCcTree->fmPcdGroupParam[i].baseGroupEntry = numOfEntries; + p_FmPcdCcTree->fmPcdGroupParam[i].numOfEntriesInGroup = (uint8_t)(0x01 + << p_FmPcdCcGroupParams->numOfDistinctionUnits); + numOfEntries += p_FmPcdCcTree->fmPcdGroupParam[i].numOfEntriesInGroup; + if (numOfEntries > FM_PCD_MAX_NUM_OF_CC_GROUPS) + { + DeleteTree(p_FmPcdCcTree, p_FmPcd); + XX_Free(p_Params); + REPORT_ERROR(MAJOR, E_INVALID_VALUE, ("numOfEntries can not be larger than %d", FM_PCD_MAX_NUM_OF_CC_GROUPS)); + return NULL; + } + + if (lastOne) + { + if (p_FmPcdCcTree->fmPcdGroupParam[i].numOfEntriesInGroup > lastOne) + { + DeleteTree(p_FmPcdCcTree, p_FmPcd); + XX_Free(p_Params); + REPORT_ERROR(MAJOR, E_CONFLICT, ("numOfEntries per group must be set in descending order")); + return NULL; + } + } + + lastOne = p_FmPcdCcTree->fmPcdGroupParam[i].numOfEntriesInGroup; + + netEnvParams.netEnvId = p_FmPcdCcTree->netEnvId; + netEnvParams.numOfDistinctionUnits = + p_FmPcdCcGroupParams->numOfDistinctionUnits; + + memcpy(netEnvParams.unitIds, &p_FmPcdCcGroupParams->unitIds, + (sizeof(uint8_t)) * p_FmPcdCcGroupParams->numOfDistinctionUnits); + + err = PcdGetUnitsVector(p_FmPcd, &netEnvParams); + if (err) + { + DeleteTree(p_FmPcdCcTree, p_FmPcd); + XX_Free(p_Params); + REPORT_ERROR(MAJOR, err, NO_MSG); + return NULL; + } + + p_FmPcdCcTree->fmPcdGroupParam[i].totalBitsMask = netEnvParams.vector; + for (j = 0; j < p_FmPcdCcTree->fmPcdGroupParam[i].numOfEntriesInGroup; + j++) + { + err = ValidateNextEngineParams( + h_FmPcd, + &p_FmPcdCcGroupParams->nextEnginePerEntriesInGrp[j], + e_FM_PCD_CC_STATS_MODE_NONE); + if (err) + { + DeleteTree(p_FmPcdCcTree, p_FmPcd); + XX_Free(p_Params); + REPORT_ERROR(MAJOR, err, (NO_MSG)); + return NULL; + } + + if (p_FmPcdCcGroupParams->nextEnginePerEntriesInGrp[j].h_Manip) + { + err = FmPcdManipCheckParamsForCcNextEngine( + &p_FmPcdCcGroupParams->nextEnginePerEntriesInGrp[j], + &requiredAction); + if (err) + { + DeleteTree(p_FmPcdCcTree, p_FmPcd); + XX_Free(p_Params); + REPORT_ERROR(MAJOR, E_INVALID_STATE, NO_MSG); + return NULL; + } + } + p_KeyAndNextEngineParams = p_Params + k; + + memcpy(&p_KeyAndNextEngineParams->nextEngineParams, + &p_FmPcdCcGroupParams->nextEnginePerEntriesInGrp[j], + sizeof(t_FmPcdCcNextEngineParams)); + + if ((p_KeyAndNextEngineParams->nextEngineParams.nextEngine + == e_FM_PCD_CC) + && p_KeyAndNextEngineParams->nextEngineParams.h_Manip) + { + err = + AllocAndFillAdForContLookupManip( + p_KeyAndNextEngineParams->nextEngineParams.params.ccParams.h_CcNode); + if (err) + { + DeleteTree(p_FmPcdCcTree, p_FmPcd); + XX_Free(p_Params); + REPORT_ERROR(MAJOR, E_NO_MEMORY, ("MURAM allocation for CC Tree")); + return NULL; + } + } + + requiredAction |= UPDATE_CC_WITH_TREE; + p_KeyAndNextEngineParams->requiredAction = requiredAction; + + k++; + } + } + + p_FmPcdCcTree->numOfEntries = (uint8_t)k; + p_FmPcdCcTree->numOfGrps = p_PcdGroupsParam->numOfGrps; + + p_FmPcdCcTree->ccTreeBaseAddr = + PTR_TO_UINT(FM_MURAM_AllocMem(FmPcdGetMuramHandle(h_FmPcd), + (uint32_t)( FM_PCD_MAX_NUM_OF_CC_GROUPS * FM_PCD_CC_AD_ENTRY_SIZE), + FM_PCD_CC_TREE_ADDR_ALIGN)); + if (!p_FmPcdCcTree->ccTreeBaseAddr) + { + DeleteTree(p_FmPcdCcTree, p_FmPcd); + XX_Free(p_Params); + REPORT_ERROR(MAJOR, E_NO_MEMORY, ("MURAM allocation for CC Tree")); + return NULL; + } + MemSet8( + UINT_TO_PTR(p_FmPcdCcTree->ccTreeBaseAddr), 0, + (uint32_t)(FM_PCD_MAX_NUM_OF_CC_GROUPS * FM_PCD_CC_AD_ENTRY_SIZE)); + + p_CcTreeTmp = UINT_TO_PTR(p_FmPcdCcTree->ccTreeBaseAddr); + + for (i = 0; i < numOfEntries; i++) + { + p_KeyAndNextEngineParams = p_Params + i; + + NextStepAd(p_CcTreeTmp, NULL, + &p_KeyAndNextEngineParams->nextEngineParams, p_FmPcd); + + p_CcTreeTmp = PTR_MOVE(p_CcTreeTmp, FM_PCD_CC_AD_ENTRY_SIZE); + + memcpy(&p_FmPcdCcTree->keyAndNextEngineParams[i], + p_KeyAndNextEngineParams, + sizeof(t_FmPcdCcKeyAndNextEngineParams)); + + if (p_FmPcdCcTree->keyAndNextEngineParams[i].nextEngineParams.nextEngine + == e_FM_PCD_CC) + { + p_FmPcdCcNextNode = + (t_FmPcdCcNode*)p_FmPcdCcTree->keyAndNextEngineParams[i].nextEngineParams.params.ccParams.h_CcNode; + p_CcInformation = FindNodeInfoInReleventLst( + &p_FmPcdCcNextNode->ccTreeIdLst, (t_Handle)p_FmPcdCcTree, + p_FmPcdCcNextNode->h_Spinlock); + + if (!p_CcInformation) + { + memset(&ccNodeInfo, 0, sizeof(t_CcNodeInformation)); + ccNodeInfo.h_CcNode = (t_Handle)p_FmPcdCcTree; + ccNodeInfo.index = 1; + EnqueueNodeInfoToRelevantLst(&p_FmPcdCcNextNode->ccTreeIdLst, + &ccNodeInfo, + p_FmPcdCcNextNode->h_Spinlock); + } + else + p_CcInformation->index++; + } + } + + FmPcdIncNetEnvOwners(h_FmPcd, p_FmPcdCcTree->netEnvId); + p_CcTreeTmp = UINT_TO_PTR(p_FmPcdCcTree->ccTreeBaseAddr); + + if (!FmPcdLockTryLockAll(p_FmPcd)) + { + FM_PCD_CcRootDelete(p_FmPcdCcTree); + XX_Free(p_Params); + DBG(TRACE, ("FmPcdLockTryLockAll failed")); + return NULL; + } + + for (i = 0; i < numOfEntries; i++) + { + if (p_FmPcdCcTree->keyAndNextEngineParams[i].requiredAction) + { + err = SetRequiredAction( + h_FmPcd, + p_FmPcdCcTree->keyAndNextEngineParams[i].requiredAction, + &p_FmPcdCcTree->keyAndNextEngineParams[i], p_CcTreeTmp, 1, + p_FmPcdCcTree); + if (err) + { + FmPcdLockUnlockAll(p_FmPcd); + FM_PCD_CcRootDelete(p_FmPcdCcTree); + XX_Free(p_Params); + REPORT_ERROR(MAJOR, E_NO_MEMORY, ("No memory")); + return NULL; + } + p_CcTreeTmp = PTR_MOVE(p_CcTreeTmp, FM_PCD_CC_AD_ENTRY_SIZE); + } + } + + FmPcdLockUnlockAll(p_FmPcd); + p_FmPcdCcTree->p_Lock = FmPcdAcquireLock(p_FmPcd); + if (!p_FmPcdCcTree->p_Lock) + { + FM_PCD_CcRootDelete(p_FmPcdCcTree); + XX_Free(p_Params); + REPORT_ERROR(MAJOR, E_NO_MEMORY, ("FM CC lock")); + return NULL; + } + + XX_Free(p_Params); + + return p_FmPcdCcTree; +} + +t_Error FM_PCD_CcRootDelete(t_Handle h_CcTree) +{ + t_FmPcd *p_FmPcd; + t_FmPcdCcTree *p_CcTree = (t_FmPcdCcTree *)h_CcTree; + int i = 0; + + SANITY_CHECK_RETURN_ERROR(p_CcTree, E_INVALID_STATE); + p_FmPcd = (t_FmPcd *)p_CcTree->h_FmPcd; + SANITY_CHECK_RETURN_ERROR(p_FmPcd, E_INVALID_HANDLE); + + FmPcdDecNetEnvOwners(p_FmPcd, p_CcTree->netEnvId); + + if (p_CcTree->owners) + RETURN_ERROR( + MAJOR, + E_INVALID_SELECTION, + ("the tree with this ID can not be removed because this tree is occupied, first - unbind this tree")); + + /* Delete ip-reassembly schemes if exist */ + if (p_CcTree->h_IpReassemblyManip) + { + FmPcdManipDeleteIpReassmSchemes(p_CcTree->h_IpReassemblyManip); + FmPcdManipUpdateOwner(p_CcTree->h_IpReassemblyManip, FALSE); + } + + /* Delete capwap-reassembly schemes if exist */ + if (p_CcTree->h_CapwapReassemblyManip) + { + FmPcdManipDeleteCapwapReassmSchemes(p_CcTree->h_CapwapReassemblyManip); + FmPcdManipUpdateOwner(p_CcTree->h_CapwapReassemblyManip, FALSE); + } + + for (i = 0; i < p_CcTree->numOfEntries; i++) + { + if (p_CcTree->keyAndNextEngineParams[i].nextEngineParams.nextEngine + == e_FM_PCD_CC) + UpdateNodeOwner( + p_CcTree->keyAndNextEngineParams[i].nextEngineParams.params.ccParams.h_CcNode, + FALSE); + + if (p_CcTree->keyAndNextEngineParams[i].nextEngineParams.h_Manip) + FmPcdManipUpdateOwner( + p_CcTree->keyAndNextEngineParams[i].nextEngineParams.h_Manip, + FALSE); + +#ifdef FM_CAPWAP_SUPPORT + if ((p_CcTree->numOfGrps == 1) && + (p_CcTree->fmPcdGroupParam[0].numOfEntriesInGroup == 1) && + (p_CcTree->keyAndNextEngineParams[0].nextEngineParams.nextEngine == e_FM_PCD_CC) && + p_CcTree->keyAndNextEngineParams[0].nextEngineParams.params.ccParams.h_CcNode && + IsCapwapApplSpecific(p_CcTree->keyAndNextEngineParams[0].nextEngineParams.params.ccParams.h_CcNode)) + { + if (FM_PCD_ManipNodeDelete(p_CcTree->keyAndNextEngineParams[0].nextEngineParams.h_Manip) != E_OK) + return E_INVALID_STATE; + } +#endif /* FM_CAPWAP_SUPPORT */ + +#if (DPAA_VERSION >= 11) + if ((p_CcTree->keyAndNextEngineParams[i].nextEngineParams.nextEngine + == e_FM_PCD_FR) + && (p_CcTree->keyAndNextEngineParams[i].nextEngineParams.params.frParams.h_FrmReplic)) + FrmReplicGroupUpdateOwner( + p_CcTree->keyAndNextEngineParams[i].nextEngineParams.params.frParams.h_FrmReplic, + FALSE); +#endif /* (DPAA_VERSION >= 11) */ + } + + if (p_CcTree->p_Lock) + FmPcdReleaseLock(p_CcTree->h_FmPcd, p_CcTree->p_Lock); + + DeleteTree(p_CcTree, p_FmPcd); + + return E_OK; +} + +t_Error FM_PCD_CcRootModifyNextEngine( + t_Handle h_CcTree, uint8_t grpId, uint8_t index, + t_FmPcdCcNextEngineParams *p_FmPcdCcNextEngineParams) +{ + t_FmPcd *p_FmPcd; + t_FmPcdCcTree *p_CcTree = (t_FmPcdCcTree *)h_CcTree; + t_Error err = E_OK; + + SANITY_CHECK_RETURN_ERROR(p_FmPcdCcNextEngineParams, E_NULL_POINTER); + SANITY_CHECK_RETURN_ERROR(p_CcTree, E_INVALID_STATE); + p_FmPcd = (t_FmPcd *)p_CcTree->h_FmPcd; + SANITY_CHECK_RETURN_ERROR(p_FmPcd, E_INVALID_HANDLE); + + if (!FmPcdLockTryLockAll(p_FmPcd)) + { + DBG(TRACE, ("FmPcdLockTryLockAll failed")); + return ERROR_CODE(E_BUSY); + } + + err = FmPcdCcModifyNextEngineParamTree(p_FmPcd, p_CcTree, grpId, index, + p_FmPcdCcNextEngineParams); + FmPcdLockUnlockAll(p_FmPcd); + + if (err) + { + RETURN_ERROR(MAJOR, err, NO_MSG); + } + + return E_OK; +} + +t_Handle FM_PCD_MatchTableSet(t_Handle h_FmPcd, + t_FmPcdCcNodeParams *p_CcNodeParam) +{ + t_FmPcdCcNode *p_CcNode; + t_Error err; + + SANITY_CHECK_RETURN_VALUE(h_FmPcd, E_INVALID_HANDLE, NULL); + SANITY_CHECK_RETURN_VALUE(p_CcNodeParam, E_NULL_POINTER, NULL); + + p_CcNode = (t_FmPcdCcNode*)XX_Malloc(sizeof(t_FmPcdCcNode)); + if (!p_CcNode) + { + REPORT_ERROR(MAJOR, E_NO_MEMORY, ("No memory")); + return NULL; + } + memset(p_CcNode, 0, sizeof(t_FmPcdCcNode)); + + err = MatchTableSet(h_FmPcd, p_CcNode, p_CcNodeParam); + + switch(GET_ERROR_TYPE(err) +) { + case E_OK: + break; + + case E_BUSY: + DBG(TRACE, ("E_BUSY error")); + return NULL; + + default: + REPORT_ERROR(MAJOR, err, NO_MSG); + return NULL; + } + + return p_CcNode; +} + +t_Error FM_PCD_MatchTableDelete(t_Handle h_CcNode) +{ + t_FmPcdCcNode *p_CcNode = (t_FmPcdCcNode *)h_CcNode; + int i = 0; + + SANITY_CHECK_RETURN_ERROR(p_CcNode, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_CcNode->h_FmPcd, E_INVALID_HANDLE); + + if (p_CcNode->owners) + RETURN_ERROR( + MAJOR, + E_INVALID_STATE, + ("This node cannot be removed because it is occupied; first unbind this node")); + + for (i = 0; i < p_CcNode->numOfKeys; i++) + if (p_CcNode->keyAndNextEngineParams[i].nextEngineParams.nextEngine + == e_FM_PCD_CC) + UpdateNodeOwner( + p_CcNode->keyAndNextEngineParams[i].nextEngineParams.params.ccParams.h_CcNode, + FALSE); + + if (p_CcNode->keyAndNextEngineParams[i].nextEngineParams.nextEngine + == e_FM_PCD_CC) + UpdateNodeOwner( + p_CcNode->keyAndNextEngineParams[i].nextEngineParams.params.ccParams.h_CcNode, + FALSE); + + /* Handle also Miss entry */ + for (i = 0; i < p_CcNode->numOfKeys + 1; i++) + { + if (p_CcNode->keyAndNextEngineParams[i].nextEngineParams.h_Manip) + FmPcdManipUpdateOwner( + p_CcNode->keyAndNextEngineParams[i].nextEngineParams.h_Manip, + FALSE); + +#if (DPAA_VERSION >= 11) + if ((p_CcNode->keyAndNextEngineParams[i].nextEngineParams.nextEngine + == e_FM_PCD_FR) + && (p_CcNode->keyAndNextEngineParams[i].nextEngineParams.params.frParams.h_FrmReplic)) + { + FrmReplicGroupUpdateOwner( + p_CcNode->keyAndNextEngineParams[i].nextEngineParams.params.frParams.h_FrmReplic, + FALSE); + } +#endif /* (DPAA_VERSION >= 11) */ + } + + DeleteNode(p_CcNode); + + return E_OK; +} + +t_Error FM_PCD_MatchTableAddKey(t_Handle h_CcNode, uint16_t keyIndex, + uint8_t keySize, + t_FmPcdCcKeyParams *p_KeyParams) +{ + t_FmPcd *p_FmPcd; + t_FmPcdCcNode *p_CcNode = (t_FmPcdCcNode *)h_CcNode; + t_Error err = E_OK; + + SANITY_CHECK_RETURN_ERROR(p_KeyParams, E_NULL_POINTER); + SANITY_CHECK_RETURN_ERROR(p_CcNode, E_INVALID_HANDLE); + p_FmPcd = (t_FmPcd *)p_CcNode->h_FmPcd; + SANITY_CHECK_RETURN_ERROR(p_FmPcd, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_FmPcd->h_Hc, E_INVALID_HANDLE); + + if (keyIndex == FM_PCD_LAST_KEY_INDEX) + keyIndex = p_CcNode->numOfKeys; + + if (!FmPcdLockTryLockAll(p_FmPcd)) + { + DBG(TRACE, ("FmPcdLockTryLockAll failed")); + return ERROR_CODE(E_BUSY); + } + + err = FmPcdCcAddKey(p_FmPcd, p_CcNode, keyIndex, keySize, p_KeyParams); + + FmPcdLockUnlockAll(p_FmPcd); + + switch(GET_ERROR_TYPE(err) +) { + case E_OK: + return E_OK; + + case E_BUSY: + DBG(TRACE, ("E_BUSY error")); + return ERROR_CODE(E_BUSY); + + default: + RETURN_ERROR(MAJOR, err, NO_MSG); + } +} + +t_Error FM_PCD_MatchTableRemoveKey(t_Handle h_CcNode, uint16_t keyIndex) +{ + t_FmPcd *p_FmPcd; + t_FmPcdCcNode *p_CcNode = (t_FmPcdCcNode *)h_CcNode; + t_Error err = E_OK; + + SANITY_CHECK_RETURN_ERROR(p_CcNode, E_INVALID_HANDLE); + p_FmPcd = (t_FmPcd *)p_CcNode->h_FmPcd; + SANITY_CHECK_RETURN_ERROR(p_FmPcd, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_FmPcd->h_Hc, E_INVALID_HANDLE); + + if (!FmPcdLockTryLockAll(p_FmPcd)) + { + DBG(TRACE, ("FmPcdLockTryLockAll failed")); + return ERROR_CODE(E_BUSY); + } + + err = FmPcdCcRemoveKey(p_FmPcd, p_CcNode, keyIndex); + + FmPcdLockUnlockAll(p_FmPcd); + + switch(GET_ERROR_TYPE(err) +) { + case E_OK: + return E_OK; + + case E_BUSY: + DBG(TRACE, ("E_BUSY error")); + return ERROR_CODE(E_BUSY); + + default: + RETURN_ERROR(MAJOR, err, NO_MSG); + } + + return E_OK; +} + +t_Error FM_PCD_MatchTableModifyKey(t_Handle h_CcNode, uint16_t keyIndex, + uint8_t keySize, uint8_t *p_Key, + uint8_t *p_Mask) +{ + t_FmPcd *p_FmPcd; + t_FmPcdCcNode *p_CcNode = (t_FmPcdCcNode *)h_CcNode; + t_Error err = E_OK; + + SANITY_CHECK_RETURN_ERROR(p_CcNode, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_Key, E_NULL_POINTER); + p_FmPcd = (t_FmPcd *)p_CcNode->h_FmPcd; + SANITY_CHECK_RETURN_ERROR(p_FmPcd, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_FmPcd->h_Hc, E_INVALID_HANDLE); + + + if (!FmPcdLockTryLockAll(p_FmPcd)) + { + DBG(TRACE, ("FmPcdLockTryLockAll failed")); + return ERROR_CODE(E_BUSY); + } + + err = FmPcdCcModifyKey(p_FmPcd, p_CcNode, keyIndex, keySize, p_Key, p_Mask); + + FmPcdLockUnlockAll(p_FmPcd); + + switch(GET_ERROR_TYPE(err) +) { + case E_OK: + return E_OK; + + case E_BUSY: + DBG(TRACE, ("E_BUSY error")); + return ERROR_CODE(E_BUSY); + + default: + RETURN_ERROR(MAJOR, err, NO_MSG); + } +} + +t_Error FM_PCD_MatchTableModifyNextEngine( + t_Handle h_CcNode, uint16_t keyIndex, + t_FmPcdCcNextEngineParams *p_FmPcdCcNextEngineParams) +{ + t_FmPcd *p_FmPcd; + t_FmPcdCcNode *p_CcNode = (t_FmPcdCcNode *)h_CcNode; + t_Error err = E_OK; + + SANITY_CHECK_RETURN_ERROR(p_FmPcdCcNextEngineParams, E_NULL_POINTER); + SANITY_CHECK_RETURN_ERROR(p_CcNode, E_INVALID_HANDLE); + p_FmPcd = (t_FmPcd *)p_CcNode->h_FmPcd; + SANITY_CHECK_RETURN_ERROR(p_FmPcd, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_FmPcd->h_Hc, E_INVALID_HANDLE); + + if (!FmPcdLockTryLockAll(p_FmPcd)) + { + DBG(TRACE, ("FmPcdLockTryLockAll failed")); + return ERROR_CODE(E_BUSY); + } + + err = ModifyNextEngineParamNode(p_FmPcd, p_CcNode, keyIndex, + p_FmPcdCcNextEngineParams); + + FmPcdLockUnlockAll(p_FmPcd); + + switch(GET_ERROR_TYPE(err) +) { + case E_OK: + return E_OK; + + case E_BUSY: + DBG(TRACE, ("E_BUSY error")); + return ERROR_CODE(E_BUSY); + + default: + RETURN_ERROR(MAJOR, err, NO_MSG); + } +} + +t_Error FM_PCD_MatchTableModifyMissNextEngine( + t_Handle h_CcNode, t_FmPcdCcNextEngineParams *p_FmPcdCcNextEngineParams) +{ + t_FmPcd *p_FmPcd; + t_FmPcdCcNode *p_CcNode = (t_FmPcdCcNode *)h_CcNode; + t_Error err = E_OK; + + SANITY_CHECK_RETURN_ERROR(p_FmPcdCcNextEngineParams, E_NULL_POINTER); + SANITY_CHECK_RETURN_ERROR(p_CcNode, E_INVALID_HANDLE); + p_FmPcd = (t_FmPcd *)p_CcNode->h_FmPcd; + SANITY_CHECK_RETURN_ERROR(p_FmPcd, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_FmPcd->h_Hc, E_INVALID_HANDLE); + + if (!FmPcdLockTryLockAll(p_FmPcd)) + { + DBG(TRACE, ("FmPcdLockTryLockAll failed")); + return ERROR_CODE(E_BUSY); + } + + err = FmPcdCcModifyMissNextEngineParamNode(p_FmPcd, p_CcNode, + p_FmPcdCcNextEngineParams); + + FmPcdLockUnlockAll(p_FmPcd); + + switch(GET_ERROR_TYPE(err) +) { + case E_OK: + return E_OK; + + case E_BUSY: + DBG(TRACE, ("E_BUSY error")); + return ERROR_CODE(E_BUSY); + + default: + RETURN_ERROR(MAJOR, err, NO_MSG); + } +} + +t_Error FM_PCD_MatchTableModifyKeyAndNextEngine(t_Handle h_CcNode, + uint16_t keyIndex, + uint8_t keySize, + t_FmPcdCcKeyParams *p_KeyParams) +{ + t_FmPcd *p_FmPcd; + t_FmPcdCcNode *p_CcNode = (t_FmPcdCcNode *)h_CcNode; + t_Error err = E_OK; + + SANITY_CHECK_RETURN_ERROR(p_KeyParams, E_NULL_POINTER); + SANITY_CHECK_RETURN_ERROR(p_CcNode, E_INVALID_HANDLE); + p_FmPcd = (t_FmPcd *)p_CcNode->h_FmPcd; + SANITY_CHECK_RETURN_ERROR(p_FmPcd, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_FmPcd->h_Hc, E_INVALID_HANDLE); + + if (!FmPcdLockTryLockAll(p_FmPcd)) + { + DBG(TRACE, ("FmPcdLockTryLockAll failed")); + return ERROR_CODE(E_BUSY); + } + + err = FmPcdCcModifyKeyAndNextEngine(p_FmPcd, p_CcNode, keyIndex, keySize, + p_KeyParams); + + FmPcdLockUnlockAll(p_FmPcd); + + switch(GET_ERROR_TYPE(err) +) { + case E_OK: + return E_OK; + + case E_BUSY: + DBG(TRACE, ("E_BUSY error")); + return ERROR_CODE(E_BUSY); + + default: + RETURN_ERROR(MAJOR, err, NO_MSG); + } +} + +t_Error FM_PCD_MatchTableFindNRemoveKey(t_Handle h_CcNode, uint8_t keySize, + uint8_t *p_Key, uint8_t *p_Mask) +{ + t_FmPcd *p_FmPcd; + t_FmPcdCcNode *p_CcNode = (t_FmPcdCcNode *)h_CcNode; + uint16_t keyIndex; + t_Error err; + + SANITY_CHECK_RETURN_ERROR(p_Key, E_NULL_POINTER); + SANITY_CHECK_RETURN_ERROR(p_CcNode, E_INVALID_HANDLE); + p_FmPcd = (t_FmPcd *)p_CcNode->h_FmPcd; + SANITY_CHECK_RETURN_ERROR(p_FmPcd, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_FmPcd->h_Hc, E_INVALID_HANDLE); + + if (!FmPcdLockTryLockAll(p_FmPcd)) + { + DBG(TRACE, ("FmPcdLockTryLockAll failed")); + return ERROR_CODE(E_BUSY); + } + + err = FindKeyIndex(p_CcNode, keySize, p_Key, p_Mask, &keyIndex); + if (GET_ERROR_TYPE(err) != E_OK) + { + FmPcdLockUnlockAll(p_FmPcd); + RETURN_ERROR( + MAJOR, + err, + ("The received key and mask pair was not found in the match table of the provided node")); + } + + err = FmPcdCcRemoveKey(p_FmPcd, p_CcNode, keyIndex); + + FmPcdLockUnlockAll(p_FmPcd); + + switch(GET_ERROR_TYPE(err) +) { + case E_OK: + return E_OK; + + case E_BUSY: + DBG(TRACE, ("E_BUSY error")); + return ERROR_CODE(E_BUSY); + + default: + RETURN_ERROR(MAJOR, err, NO_MSG); + } +} + +t_Error FM_PCD_MatchTableFindNModifyNextEngine( + t_Handle h_CcNode, uint8_t keySize, uint8_t *p_Key, uint8_t *p_Mask, + t_FmPcdCcNextEngineParams *p_FmPcdCcNextEngineParams) +{ + t_FmPcd *p_FmPcd; + t_FmPcdCcNode *p_CcNode = (t_FmPcdCcNode *)h_CcNode; + uint16_t keyIndex; + t_Error err; + + SANITY_CHECK_RETURN_ERROR(p_Key, E_NULL_POINTER); + SANITY_CHECK_RETURN_ERROR(p_FmPcdCcNextEngineParams, E_NULL_POINTER); + SANITY_CHECK_RETURN_ERROR(p_CcNode, E_INVALID_HANDLE); + p_FmPcd = (t_FmPcd *)p_CcNode->h_FmPcd; + SANITY_CHECK_RETURN_ERROR(p_FmPcd, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_FmPcd->h_Hc, E_INVALID_HANDLE); + + if (!FmPcdLockTryLockAll(p_FmPcd)) + { + DBG(TRACE, ("FmPcdLockTryLockAll failed")); + return ERROR_CODE(E_BUSY); + } + + err = FindKeyIndex(p_CcNode, keySize, p_Key, p_Mask, &keyIndex); + if (GET_ERROR_TYPE(err) != E_OK) + { + FmPcdLockUnlockAll(p_FmPcd); + RETURN_ERROR( + MAJOR, + err, + ("The received key and mask pair was not found in the match table of the provided node")); + } + + err = ModifyNextEngineParamNode(p_FmPcd, p_CcNode, keyIndex, + p_FmPcdCcNextEngineParams); + + FmPcdLockUnlockAll(p_FmPcd); + + switch(GET_ERROR_TYPE(err) +) { + case E_OK: + return E_OK; + + case E_BUSY: + DBG(TRACE, ("E_BUSY error")); + return ERROR_CODE(E_BUSY); + + default: + RETURN_ERROR(MAJOR, err, NO_MSG); + } +} + +t_Error FM_PCD_MatchTableFindNModifyKeyAndNextEngine( + t_Handle h_CcNode, uint8_t keySize, uint8_t *p_Key, uint8_t *p_Mask, + t_FmPcdCcKeyParams *p_KeyParams) +{ + t_FmPcd *p_FmPcd; + t_FmPcdCcNode *p_CcNode = (t_FmPcdCcNode *)h_CcNode; + uint16_t keyIndex; + t_Error err; + + SANITY_CHECK_RETURN_ERROR(p_Key, E_NULL_POINTER); + SANITY_CHECK_RETURN_ERROR(p_KeyParams, E_NULL_POINTER); + SANITY_CHECK_RETURN_ERROR(p_CcNode, E_INVALID_HANDLE); + p_FmPcd = (t_FmPcd *)p_CcNode->h_FmPcd; + SANITY_CHECK_RETURN_ERROR(p_FmPcd, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_FmPcd->h_Hc, E_INVALID_HANDLE); + + if (!FmPcdLockTryLockAll(p_FmPcd)) + { + DBG(TRACE, ("FmPcdLockTryLockAll failed")); + return ERROR_CODE(E_BUSY); + } + + err = FindKeyIndex(p_CcNode, keySize, p_Key, p_Mask, &keyIndex); + if (GET_ERROR_TYPE(err) != E_OK) + { + FmPcdLockUnlockAll(p_FmPcd); + RETURN_ERROR( + MAJOR, + err, + ("The received key and mask pair was not found in the match table of the provided node")); + } + + err = FmPcdCcModifyKeyAndNextEngine(p_FmPcd, h_CcNode, keyIndex, keySize, + p_KeyParams); + + FmPcdLockUnlockAll(p_FmPcd); + + switch(GET_ERROR_TYPE(err) +) { + case E_OK: + return E_OK; + + case E_BUSY: + DBG(TRACE, ("E_BUSY error")); + return ERROR_CODE(E_BUSY); + + default: + RETURN_ERROR(MAJOR, err, NO_MSG); + } +} + +t_Error FM_PCD_MatchTableFindNModifyKey(t_Handle h_CcNode, uint8_t keySize, + uint8_t *p_Key, uint8_t *p_Mask, + uint8_t *p_NewKey, uint8_t *p_NewMask) +{ + t_FmPcd *p_FmPcd; + t_FmPcdCcNode *p_CcNode = (t_FmPcdCcNode *)h_CcNode; + t_List h_List; + uint16_t keyIndex; + t_Error err; + + SANITY_CHECK_RETURN_ERROR(p_Key, E_NULL_POINTER); + SANITY_CHECK_RETURN_ERROR(p_NewKey, E_NULL_POINTER); + SANITY_CHECK_RETURN_ERROR(p_CcNode, E_INVALID_HANDLE); + p_FmPcd = (t_FmPcd *)p_CcNode->h_FmPcd; + SANITY_CHECK_RETURN_ERROR(p_FmPcd, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_FmPcd->h_Hc, E_INVALID_HANDLE); + + INIT_LIST(&h_List); + + err = FmPcdCcNodeTreeTryLock(p_FmPcd, p_CcNode, &h_List); + if (err) + { + DBG(TRACE, ("Node's trees lock failed")); + return ERROR_CODE(E_BUSY); + } + + err = FindKeyIndex(p_CcNode, keySize, p_Key, p_Mask, &keyIndex); + if (GET_ERROR_TYPE(err) != E_OK) + { + FmPcdCcNodeTreeReleaseLock(p_FmPcd, &h_List); + RETURN_ERROR(MAJOR, err, + ("The received key and mask pair was not found in the " + "match table of the provided node")); + } + + err = FmPcdCcModifyKey(p_FmPcd, p_CcNode, keyIndex, keySize, p_NewKey, + p_NewMask); + + FmPcdCcNodeTreeReleaseLock(p_FmPcd, &h_List); + + switch(GET_ERROR_TYPE(err) +) { + case E_OK: + return E_OK; + + case E_BUSY: + DBG(TRACE, ("E_BUSY error")); + return ERROR_CODE(E_BUSY); + + default: + RETURN_ERROR(MAJOR, err, NO_MSG); + } +} + +t_Error FM_PCD_MatchTableGetNextEngine( + t_Handle h_CcNode, uint16_t keyIndex, + t_FmPcdCcNextEngineParams *p_FmPcdCcNextEngineParams) +{ + t_FmPcdCcNode *p_CcNode = (t_FmPcdCcNode *)h_CcNode; + + SANITY_CHECK_RETURN_ERROR(p_CcNode, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_FmPcdCcNextEngineParams, E_NULL_POINTER); + + if (keyIndex >= p_CcNode->numOfKeys) + RETURN_ERROR(MAJOR, E_INVALID_STATE, + ("keyIndex exceeds current number of keys")); + + if (keyIndex > (FM_PCD_MAX_NUM_OF_KEYS - 1)) + RETURN_ERROR( + MAJOR, + E_INVALID_VALUE, + ("keyIndex can not be larger than %d", (FM_PCD_MAX_NUM_OF_KEYS - 1))); + + memcpy(p_FmPcdCcNextEngineParams, + &p_CcNode->keyAndNextEngineParams[keyIndex].nextEngineParams, + sizeof(t_FmPcdCcNextEngineParams)); + + return E_OK; +} + + +uint32_t FM_PCD_MatchTableGetKeyCounter(t_Handle h_CcNode, uint16_t keyIndex) +{ + t_FmPcdCcNode *p_CcNode = (t_FmPcdCcNode *)h_CcNode; + uint32_t *p_StatsCounters, frameCount; + uint32_t intFlags; + + SANITY_CHECK_RETURN_VALUE(p_CcNode, E_INVALID_HANDLE, 0); + + if (p_CcNode->statisticsMode == e_FM_PCD_CC_STATS_MODE_NONE) + { + REPORT_ERROR(MAJOR, E_INVALID_STATE, ("Statistics were not enabled for this match table")); + return 0; + } + + if ((p_CcNode->statisticsMode != e_FM_PCD_CC_STATS_MODE_FRAME) + && (p_CcNode->statisticsMode + != e_FM_PCD_CC_STATS_MODE_BYTE_AND_FRAME)) + { + REPORT_ERROR(MAJOR, E_INVALID_STATE, ("Frame count is not supported in the statistics mode of this match table")); + return 0; + } + + intFlags = XX_LockIntrSpinlock(p_CcNode->h_Spinlock); + + if (keyIndex >= p_CcNode->numOfKeys) + { + XX_UnlockIntrSpinlock(p_CcNode->h_Spinlock, intFlags); + REPORT_ERROR(MAJOR, E_INVALID_STATE, ("The provided keyIndex exceeds the number of keys in this match table")); + return 0; + } + + if (!p_CcNode->keyAndNextEngineParams[keyIndex].p_StatsObj) + { + XX_UnlockIntrSpinlock(p_CcNode->h_Spinlock, intFlags); + REPORT_ERROR(MAJOR, E_INVALID_STATE, ("Statistics were not enabled for this key")); + return 0; + } + + p_StatsCounters = + p_CcNode->keyAndNextEngineParams[keyIndex].p_StatsObj->h_StatsCounters; + ASSERT_COND(p_StatsCounters); + + /* The first counter is byte counter, so we need to advance to the next counter */ + frameCount = GET_UINT32(*(uint32_t *)(PTR_MOVE(p_StatsCounters, + FM_PCD_CC_STATS_COUNTER_SIZE))); + + XX_UnlockIntrSpinlock(p_CcNode->h_Spinlock, intFlags); + + return frameCount; +} + +t_Error FM_PCD_MatchTableGetKeyStatistics( + t_Handle h_CcNode, uint16_t keyIndex, + t_FmPcdCcKeyStatistics *p_KeyStatistics) +{ + t_FmPcdCcNode *p_CcNode = (t_FmPcdCcNode *)h_CcNode; + uint32_t intFlags; + t_Error err; + + SANITY_CHECK_RETURN_ERROR(h_CcNode, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_KeyStatistics, E_NULL_POINTER); + + intFlags = XX_LockIntrSpinlock(p_CcNode->h_Spinlock); + + if (keyIndex >= p_CcNode->numOfKeys) + RETURN_ERROR( + MAJOR, + E_INVALID_STATE, + ("The provided keyIndex exceeds the number of keys in this match table")); + + err = MatchTableGetKeyStatistics(p_CcNode, keyIndex, p_KeyStatistics); + + XX_UnlockIntrSpinlock(p_CcNode->h_Spinlock, intFlags); + + if (err != E_OK) + RETURN_ERROR(MAJOR, err, NO_MSG); + + return E_OK; +} + +t_Error FM_PCD_MatchTableGetMissStatistics( + t_Handle h_CcNode, t_FmPcdCcKeyStatistics *p_MissStatistics) +{ + t_FmPcdCcNode *p_CcNode = (t_FmPcdCcNode *)h_CcNode; + uint32_t intFlags; + t_Error err; + + SANITY_CHECK_RETURN_ERROR(h_CcNode, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_MissStatistics, E_NULL_POINTER); + + intFlags = XX_LockIntrSpinlock(p_CcNode->h_Spinlock); + + err = MatchTableGetKeyStatistics(p_CcNode, p_CcNode->numOfKeys, + p_MissStatistics); + + XX_UnlockIntrSpinlock(p_CcNode->h_Spinlock, intFlags); + + if (err != E_OK) + RETURN_ERROR(MAJOR, err, NO_MSG); + + return E_OK; +} + +t_Error FM_PCD_MatchTableFindNGetKeyStatistics( + t_Handle h_CcNode, uint8_t keySize, uint8_t *p_Key, uint8_t *p_Mask, + t_FmPcdCcKeyStatistics *p_KeyStatistics) +{ + t_FmPcdCcNode *p_CcNode = (t_FmPcdCcNode *)h_CcNode; + uint16_t keyIndex; + uint32_t intFlags; + t_Error err; + + SANITY_CHECK_RETURN_ERROR(p_Key, E_NULL_POINTER); + SANITY_CHECK_RETURN_ERROR(p_KeyStatistics, E_NULL_POINTER); + + intFlags = XX_LockIntrSpinlock(p_CcNode->h_Spinlock); + + err = FindKeyIndex(p_CcNode, keySize, p_Key, p_Mask, &keyIndex); + if (GET_ERROR_TYPE(err) != E_OK) + { + XX_UnlockIntrSpinlock(p_CcNode->h_Spinlock, intFlags); + RETURN_ERROR(MAJOR, err, + ("The received key and mask pair was not found in the " + "match table of the provided node")); + } + + ASSERT_COND(keyIndex < p_CcNode->numOfKeys); + + err = MatchTableGetKeyStatistics(p_CcNode, keyIndex, p_KeyStatistics); + + XX_UnlockIntrSpinlock(p_CcNode->h_Spinlock, intFlags); + + if (err != E_OK) + RETURN_ERROR(MAJOR, err, NO_MSG); + + return E_OK; +} + +t_Error FM_PCD_MatchTableGetIndexedHashBucket(t_Handle h_CcNode, + uint8_t keySize, uint8_t *p_Key, + uint8_t hashShift, + t_Handle *p_CcNodeBucketHandle, + uint8_t *p_BucketIndex, + uint16_t *p_LastIndex) +{ + t_FmPcdCcNode *p_CcNode = (t_FmPcdCcNode *)h_CcNode; + uint16_t glblMask; + uint64_t crc64 = 0; + + SANITY_CHECK_RETURN_ERROR(h_CcNode, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR( + p_CcNode->parseCode == CC_PC_GENERIC_IC_HASH_INDEXED, + E_INVALID_STATE); + SANITY_CHECK_RETURN_ERROR(p_Key, E_NULL_POINTER); + SANITY_CHECK_RETURN_ERROR(p_CcNodeBucketHandle, E_NULL_POINTER); + + memcpy(&glblMask, PTR_MOVE(p_CcNode->p_GlblMask, 2), 2); + be16_to_cpus(&glblMask); + + crc64 = crc64_init(); + crc64 = crc64_compute(p_Key, keySize, crc64); + crc64 >>= hashShift; + + *p_BucketIndex = (uint8_t)(((crc64 >> (8 * (6 - p_CcNode->userOffset))) + & glblMask) >> 4); + if (*p_BucketIndex >= p_CcNode->numOfKeys) + RETURN_ERROR(MINOR, E_NOT_IN_RANGE, ("bucket index!")); + + *p_CcNodeBucketHandle = + p_CcNode->keyAndNextEngineParams[*p_BucketIndex].nextEngineParams.params.ccParams.h_CcNode; + if (!*p_CcNodeBucketHandle) + RETURN_ERROR(MINOR, E_NOT_FOUND, ("bucket!")); + + *p_LastIndex = ((t_FmPcdCcNode *)*p_CcNodeBucketHandle)->numOfKeys; + + return E_OK; +} + +t_Handle FM_PCD_HashTableSet(t_Handle h_FmPcd, t_FmPcdHashTableParams *p_Param) +{ + t_FmPcdCcNode *p_CcNodeHashTbl; + t_FmPcdCcNodeParams *p_IndxHashCcNodeParam, *p_ExactMatchCcNodeParam; + t_FmPcdCcNode *p_CcNode; + t_Handle h_MissStatsCounters = NULL; + t_FmPcdCcKeyParams *p_HashKeyParams; + int i; + uint16_t numOfSets, numOfWays, countMask, onesCount = 0; + bool statsEnForMiss = FALSE; + t_Error err; + + SANITY_CHECK_RETURN_VALUE(h_FmPcd, E_INVALID_HANDLE, NULL); + SANITY_CHECK_RETURN_VALUE(p_Param, E_NULL_POINTER, NULL); + + if (p_Param->maxNumOfKeys == 0) + { + REPORT_ERROR(MINOR, E_INVALID_VALUE, ("Max number of keys must be higher then 0")); + return NULL; + } + + if (p_Param->hashResMask == 0) + { + REPORT_ERROR(MINOR, E_INVALID_VALUE, ("Hash result mask must differ from 0")); + return NULL; + } + + /*Fix: QorIQ SDK / QSDK-2131*/ + if (p_Param->ccNextEngineParamsForMiss.nextEngine == e_FM_PCD_INVALID) + { + REPORT_ERROR(MAJOR, E_INVALID_VALUE, ("Next PCD Engine for on-miss entry is invalid. On-miss entry is always required. You can use e_FM_PCD_DONE.")); + return NULL; + } + +#if (DPAA_VERSION >= 11) + if (p_Param->statisticsMode == e_FM_PCD_CC_STATS_MODE_RMON) + { + REPORT_ERROR(MAJOR, E_INVALID_VALUE, + ("RMON statistics mode is not supported for hash table")); + return NULL; + } +#endif /* (DPAA_VERSION >= 11) */ + + p_ExactMatchCcNodeParam = (t_FmPcdCcNodeParams*)XX_Malloc( + sizeof(t_FmPcdCcNodeParams)); + if (!p_ExactMatchCcNodeParam) + { + REPORT_ERROR(MAJOR, E_NO_MEMORY, ("p_ExactMatchCcNodeParam")); + return NULL; + } + memset(p_ExactMatchCcNodeParam, 0, sizeof(t_FmPcdCcNodeParams)); + + p_IndxHashCcNodeParam = (t_FmPcdCcNodeParams*)XX_Malloc( + sizeof(t_FmPcdCcNodeParams)); + if (!p_IndxHashCcNodeParam) + { + XX_Free(p_ExactMatchCcNodeParam); + REPORT_ERROR(MAJOR, E_NO_MEMORY, ("p_IndxHashCcNodeParam")); + return NULL; + } + memset(p_IndxHashCcNodeParam, 0, sizeof(t_FmPcdCcNodeParams)); + + /* Calculate number of sets and number of ways of the hash table */ + countMask = (uint16_t)(p_Param->hashResMask >> 4); + while (countMask) + { + onesCount++; + countMask = (uint16_t)(countMask >> 1); + } + + numOfSets = (uint16_t)(1 << onesCount); + numOfWays = (uint16_t)DIV_CEIL(p_Param->maxNumOfKeys, numOfSets); + + if (p_Param->maxNumOfKeys % numOfSets) + DBG(INFO, ("'maxNumOfKeys' is not a multiple of hash number of ways, so number of ways will be rounded up")); + + if ((p_Param->statisticsMode == e_FM_PCD_CC_STATS_MODE_FRAME) + || (p_Param->statisticsMode == e_FM_PCD_CC_STATS_MODE_BYTE_AND_FRAME)) + { + /* Allocating a statistics counters table that will be used by all + 'miss' entries of the hash table */ + h_MissStatsCounters = (t_Handle)FM_MURAM_AllocMem( + FmPcdGetMuramHandle(h_FmPcd), 2 * FM_PCD_CC_STATS_COUNTER_SIZE, + FM_PCD_CC_AD_TABLE_ALIGN); + if (!h_MissStatsCounters) + { + REPORT_ERROR(MAJOR, E_NO_MEMORY, ("MURAM allocation for statistics table for hash miss")); + XX_Free(p_IndxHashCcNodeParam); + XX_Free(p_ExactMatchCcNodeParam); + return NULL; + } + memset(h_MissStatsCounters, 0, (2 * FM_PCD_CC_STATS_COUNTER_SIZE)); + + /* Always enable statistics for 'miss', so that a statistics AD will be + initialized from the start. We'll store the requested 'statistics enable' + value and it will be used when statistics are read by the user. */ + statsEnForMiss = p_Param->ccNextEngineParamsForMiss.statisticsEn; + p_Param->ccNextEngineParamsForMiss.statisticsEn = TRUE; + } + + /* Building exact-match node params, will be used to create the hash buckets */ + p_ExactMatchCcNodeParam->extractCcParams.type = e_FM_PCD_EXTRACT_NON_HDR; + + p_ExactMatchCcNodeParam->extractCcParams.extractNonHdr.src = + e_FM_PCD_EXTRACT_FROM_KEY; + p_ExactMatchCcNodeParam->extractCcParams.extractNonHdr.action = + e_FM_PCD_ACTION_EXACT_MATCH; + p_ExactMatchCcNodeParam->extractCcParams.extractNonHdr.offset = 0; + p_ExactMatchCcNodeParam->extractCcParams.extractNonHdr.size = + p_Param->matchKeySize; + + p_ExactMatchCcNodeParam->keysParams.maxNumOfKeys = numOfWays; + p_ExactMatchCcNodeParam->keysParams.maskSupport = FALSE; + p_ExactMatchCcNodeParam->keysParams.statisticsMode = + p_Param->statisticsMode; + p_ExactMatchCcNodeParam->keysParams.numOfKeys = 0; + p_ExactMatchCcNodeParam->keysParams.keySize = p_Param->matchKeySize; + p_ExactMatchCcNodeParam->keysParams.ccNextEngineParamsForMiss = + p_Param->ccNextEngineParamsForMiss; + + p_HashKeyParams = p_IndxHashCcNodeParam->keysParams.keyParams; + + for (i = 0; i < numOfSets; i++) + { + /* Each exact-match node will be marked as a 'bucket' and provided with + a pointer to statistics counters, to be used for 'miss' entry + statistics */ + p_CcNode = (t_FmPcdCcNode *)XX_Malloc(sizeof(t_FmPcdCcNode)); + if (!p_CcNode) + break; + memset(p_CcNode, 0, sizeof(t_FmPcdCcNode)); + + p_CcNode->isHashBucket = TRUE; + p_CcNode->h_MissStatsCounters = h_MissStatsCounters; + + err = MatchTableSet(h_FmPcd, p_CcNode, p_ExactMatchCcNodeParam); + if (err) + break; + + p_HashKeyParams[i].ccNextEngineParams.nextEngine = e_FM_PCD_CC; + p_HashKeyParams[i].ccNextEngineParams.statisticsEn = FALSE; + p_HashKeyParams[i].ccNextEngineParams.params.ccParams.h_CcNode = + p_CcNode; + } + + if (i < numOfSets) + { + for (i = i - 1; i >= 0; i--) + FM_PCD_MatchTableDelete( + p_HashKeyParams[i].ccNextEngineParams.params.ccParams.h_CcNode); + + FM_MURAM_FreeMem(FmPcdGetMuramHandle(h_FmPcd), h_MissStatsCounters); + + REPORT_ERROR(MAJOR, E_NULL_POINTER, NO_MSG); + XX_Free(p_IndxHashCcNodeParam); + XX_Free(p_ExactMatchCcNodeParam); + return NULL; + } + + /* Creating indexed-hash CC node */ + p_IndxHashCcNodeParam->extractCcParams.type = e_FM_PCD_EXTRACT_NON_HDR; + p_IndxHashCcNodeParam->extractCcParams.extractNonHdr.src = + e_FM_PCD_EXTRACT_FROM_HASH; + p_IndxHashCcNodeParam->extractCcParams.extractNonHdr.action = + e_FM_PCD_ACTION_INDEXED_LOOKUP; + p_IndxHashCcNodeParam->extractCcParams.extractNonHdr.icIndxMask = + p_Param->hashResMask; + p_IndxHashCcNodeParam->extractCcParams.extractNonHdr.offset = + p_Param->hashShift; + p_IndxHashCcNodeParam->extractCcParams.extractNonHdr.size = 2; + + p_IndxHashCcNodeParam->keysParams.maxNumOfKeys = numOfSets; + p_IndxHashCcNodeParam->keysParams.maskSupport = FALSE; + p_IndxHashCcNodeParam->keysParams.statisticsMode = + e_FM_PCD_CC_STATS_MODE_NONE; + /* Number of keys of this node is number of sets of the hash */ + p_IndxHashCcNodeParam->keysParams.numOfKeys = numOfSets; + p_IndxHashCcNodeParam->keysParams.keySize = 2; + + p_CcNodeHashTbl = FM_PCD_MatchTableSet(h_FmPcd, p_IndxHashCcNodeParam); + + if (p_CcNodeHashTbl) + { + p_CcNodeHashTbl->kgHashShift = p_Param->kgHashShift; + + /* Storing the allocated counters for buckets 'miss' in the hash table + and if statistics for miss were enabled. */ + p_CcNodeHashTbl->h_MissStatsCounters = h_MissStatsCounters; + p_CcNodeHashTbl->statsEnForMiss = statsEnForMiss; + } + + XX_Free(p_IndxHashCcNodeParam); + XX_Free(p_ExactMatchCcNodeParam); + + return p_CcNodeHashTbl; +} + +t_Error FM_PCD_HashTableDelete(t_Handle h_HashTbl) +{ + t_FmPcdCcNode *p_HashTbl = (t_FmPcdCcNode *)h_HashTbl; + t_Handle h_FmPcd; + t_Handle *p_HashBuckets, h_MissStatsCounters; + uint16_t i, numOfBuckets; + t_Error err; + + SANITY_CHECK_RETURN_ERROR(p_HashTbl, E_INVALID_HANDLE); + + /* Store all hash buckets before the hash is freed */ + numOfBuckets = p_HashTbl->numOfKeys; + + p_HashBuckets = (t_Handle *)XX_Malloc(numOfBuckets * sizeof(t_Handle)); + if (!p_HashBuckets) + RETURN_ERROR(MAJOR, E_NO_MEMORY, NO_MSG); + + for (i = 0; i < numOfBuckets; i++) + p_HashBuckets[i] = + p_HashTbl->keyAndNextEngineParams[i].nextEngineParams.params.ccParams.h_CcNode; + + h_FmPcd = p_HashTbl->h_FmPcd; + h_MissStatsCounters = p_HashTbl->h_MissStatsCounters; + + /* Free the hash */ + err = FM_PCD_MatchTableDelete(p_HashTbl); + + /* Free each hash bucket */ + for (i = 0; i < numOfBuckets; i++) + err |= FM_PCD_MatchTableDelete(p_HashBuckets[i]); + + XX_Free(p_HashBuckets); + + /* Free statistics counters for 'miss', if these were allocated */ + if (h_MissStatsCounters) + FM_MURAM_FreeMem(FmPcdGetMuramHandle(h_FmPcd), h_MissStatsCounters); + + if (err) + RETURN_ERROR(MAJOR, err, NO_MSG); + + return E_OK; +} + +t_Error FM_PCD_HashTableAddKey(t_Handle h_HashTbl, uint8_t keySize, + t_FmPcdCcKeyParams *p_KeyParams) +{ + t_FmPcdCcNode *p_HashTbl = (t_FmPcdCcNode *)h_HashTbl; + t_Handle h_HashBucket; + uint8_t bucketIndex; + uint16_t lastIndex; + t_Error err; + + SANITY_CHECK_RETURN_ERROR(p_HashTbl, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_KeyParams, E_NULL_POINTER); + SANITY_CHECK_RETURN_ERROR(p_KeyParams->p_Key, E_NULL_POINTER); + + if (p_KeyParams->p_Mask) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, + ("Keys masks not supported for hash table")); + + err = FM_PCD_MatchTableGetIndexedHashBucket(p_HashTbl, keySize, + p_KeyParams->p_Key, + p_HashTbl->kgHashShift, + &h_HashBucket, &bucketIndex, + &lastIndex); + if (err) + RETURN_ERROR(MAJOR, err, NO_MSG); + + return FM_PCD_MatchTableAddKey(h_HashBucket, FM_PCD_LAST_KEY_INDEX, keySize, + p_KeyParams); +} + +t_Error FM_PCD_HashTableRemoveKey(t_Handle h_HashTbl, uint8_t keySize, + uint8_t *p_Key) +{ + t_FmPcdCcNode *p_HashTbl = (t_FmPcdCcNode *)h_HashTbl; + t_Handle h_HashBucket; + uint8_t bucketIndex; + uint16_t lastIndex; + t_Error err; + + SANITY_CHECK_RETURN_ERROR(p_HashTbl, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_Key, E_NULL_POINTER); + + err = FM_PCD_MatchTableGetIndexedHashBucket(p_HashTbl, keySize, p_Key, + p_HashTbl->kgHashShift, + &h_HashBucket, &bucketIndex, + &lastIndex); + if (err) + RETURN_ERROR(MAJOR, err, NO_MSG); + + return FM_PCD_MatchTableFindNRemoveKey(h_HashBucket, keySize, p_Key, NULL); +} + +t_Error FM_PCD_HashTableModifyNextEngine( + t_Handle h_HashTbl, uint8_t keySize, uint8_t *p_Key, + t_FmPcdCcNextEngineParams *p_FmPcdCcNextEngineParams) +{ + t_FmPcdCcNode *p_HashTbl = (t_FmPcdCcNode *)h_HashTbl; + t_Handle h_HashBucket; + uint8_t bucketIndex; + uint16_t lastIndex; + t_Error err; + + SANITY_CHECK_RETURN_ERROR(p_HashTbl, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_Key, E_NULL_POINTER); + SANITY_CHECK_RETURN_ERROR(p_FmPcdCcNextEngineParams, E_NULL_POINTER); + + err = FM_PCD_MatchTableGetIndexedHashBucket(p_HashTbl, keySize, p_Key, + p_HashTbl->kgHashShift, + &h_HashBucket, &bucketIndex, + &lastIndex); + if (err) + RETURN_ERROR(MAJOR, err, NO_MSG); + + return FM_PCD_MatchTableFindNModifyNextEngine(h_HashBucket, keySize, p_Key, + NULL, + p_FmPcdCcNextEngineParams); +} + +t_Error FM_PCD_HashTableModifyMissNextEngine( + t_Handle h_HashTbl, + t_FmPcdCcNextEngineParams *p_FmPcdCcNextEngineParams) +{ + t_FmPcdCcNode *p_HashTbl = (t_FmPcdCcNode *)h_HashTbl; + t_Handle h_HashBucket; + uint8_t i; + bool nullifyMissStats = FALSE; + t_Error err; + + SANITY_CHECK_RETURN_ERROR(h_HashTbl, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_FmPcdCcNextEngineParams, E_NULL_POINTER); + + if ((!p_HashTbl->h_MissStatsCounters) + && (p_FmPcdCcNextEngineParams->statisticsEn)) + RETURN_ERROR( + MAJOR, + E_CONFLICT, + ("Statistics are requested for a key, but statistics mode was set" + "to 'NONE' upon initialization")); + + if (p_HashTbl->h_MissStatsCounters) + { + if ((!p_HashTbl->statsEnForMiss) + && (p_FmPcdCcNextEngineParams->statisticsEn)) + nullifyMissStats = TRUE; + + if ((p_HashTbl->statsEnForMiss) + && (!p_FmPcdCcNextEngineParams->statisticsEn)) + { + p_HashTbl->statsEnForMiss = FALSE; + p_FmPcdCcNextEngineParams->statisticsEn = TRUE; + } + } + + for (i = 0; i < p_HashTbl->numOfKeys; i++) + { + h_HashBucket = + p_HashTbl->keyAndNextEngineParams[i].nextEngineParams.params.ccParams.h_CcNode; + + err = FM_PCD_MatchTableModifyMissNextEngine(h_HashBucket, + p_FmPcdCcNextEngineParams); + if (err) + RETURN_ERROR(MAJOR, err, NO_MSG); + } + + if (nullifyMissStats) + { + memset(p_HashTbl->h_MissStatsCounters, 0, + (2 * FM_PCD_CC_STATS_COUNTER_SIZE)); + memset(p_HashTbl->h_MissStatsCounters, 0, + (2 * FM_PCD_CC_STATS_COUNTER_SIZE)); + p_HashTbl->statsEnForMiss = TRUE; + } + + return E_OK; +} + + +t_Error FM_PCD_HashTableGetMissNextEngine( + t_Handle h_HashTbl, + t_FmPcdCcNextEngineParams *p_FmPcdCcNextEngineParams) +{ + t_FmPcdCcNode *p_HashTbl = (t_FmPcdCcNode *)h_HashTbl; + t_FmPcdCcNode *p_HashBucket; + + SANITY_CHECK_RETURN_ERROR(p_HashTbl, E_INVALID_HANDLE); + + /* Miss next engine of each bucket was initialized with the next engine of the hash table */ + p_HashBucket = + p_HashTbl->keyAndNextEngineParams[0].nextEngineParams.params.ccParams.h_CcNode; + + memcpy(p_FmPcdCcNextEngineParams, + &p_HashBucket->keyAndNextEngineParams[p_HashBucket->numOfKeys].nextEngineParams, + sizeof(t_FmPcdCcNextEngineParams)); + + return E_OK; +} + +t_Error FM_PCD_HashTableFindNGetKeyStatistics( + t_Handle h_HashTbl, uint8_t keySize, uint8_t *p_Key, + t_FmPcdCcKeyStatistics *p_KeyStatistics) +{ + t_FmPcdCcNode *p_HashTbl = (t_FmPcdCcNode *)h_HashTbl; + t_Handle h_HashBucket; + uint8_t bucketIndex; + uint16_t lastIndex; + t_Error err; + + SANITY_CHECK_RETURN_ERROR(p_HashTbl, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_Key, E_NULL_POINTER); + SANITY_CHECK_RETURN_ERROR(p_KeyStatistics, E_NULL_POINTER); + + err = FM_PCD_MatchTableGetIndexedHashBucket(p_HashTbl, keySize, p_Key, + p_HashTbl->kgHashShift, + &h_HashBucket, &bucketIndex, + &lastIndex); + if (err) + RETURN_ERROR(MAJOR, err, NO_MSG); + + return FM_PCD_MatchTableFindNGetKeyStatistics(h_HashBucket, keySize, p_Key, + NULL, p_KeyStatistics); +} + +t_Error FM_PCD_HashTableGetMissStatistics( + t_Handle h_HashTbl, t_FmPcdCcKeyStatistics *p_MissStatistics) +{ + t_FmPcdCcNode *p_HashTbl = (t_FmPcdCcNode *)h_HashTbl; + t_Handle h_HashBucket; + + SANITY_CHECK_RETURN_ERROR(p_HashTbl, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_MissStatistics, E_NULL_POINTER); + + if (!p_HashTbl->statsEnForMiss) + RETURN_ERROR(MAJOR, E_INVALID_STATE, + ("Statistics were not enabled for miss")); + + h_HashBucket = + p_HashTbl->keyAndNextEngineParams[0].nextEngineParams.params.ccParams.h_CcNode; + + return FM_PCD_MatchTableGetMissStatistics(h_HashBucket, p_MissStatistics); +} diff --git a/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Pcd/fm_cc.h b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Pcd/fm_cc.h new file mode 100644 index 000000000000..3456bb565fd7 --- /dev/null +++ b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Pcd/fm_cc.h @@ -0,0 +1,399 @@ +/* + * Copyright 2008-2012 Freescale Semiconductor Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Freescale Semiconductor nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * + * ALTERNATIVELY, this software may be distributed under the terms of the + * GNU General Public License ("GPL") as published by the Free Software + * Foundation, either version 2 of that License or (at your option) any + * later version. + * + * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + +/****************************************************************************** + @File fm_cc.h + + @Description FM PCD CC ... +*//***************************************************************************/ +#ifndef __FM_CC_H +#define __FM_CC_H + +#include "std_ext.h" +#include "error_ext.h" +#include "list_ext.h" + +#include "fm_pcd.h" + + +/***********************************************************************/ +/* Coarse classification defines */ +/***********************************************************************/ + +#define CC_MAX_NUM_OF_KEYS (FM_PCD_MAX_NUM_OF_KEYS + 1) + +#define CC_PC_FF_MACDST 0x00 +#define CC_PC_FF_MACSRC 0x01 +#define CC_PC_FF_ETYPE 0x02 + +#define CC_PC_FF_TCI1 0x03 +#define CC_PC_FF_TCI2 0x04 + +#define CC_PC_FF_MPLS1 0x06 +#define CC_PC_FF_MPLS_LAST 0x07 + +#define CC_PC_FF_IPV4DST1 0x08 +#define CC_PC_FF_IPV4DST2 0x16 +#define CC_PC_FF_IPV4IPTOS_TC1 0x09 +#define CC_PC_FF_IPV4IPTOS_TC2 0x17 +#define CC_PC_FF_IPV4PTYPE1 0x0A +#define CC_PC_FF_IPV4PTYPE2 0x18 +#define CC_PC_FF_IPV4SRC1 0x0b +#define CC_PC_FF_IPV4SRC2 0x19 +#define CC_PC_FF_IPV4SRC1_IPV4DST1 0x0c +#define CC_PC_FF_IPV4SRC2_IPV4DST2 0x1a +#define CC_PC_FF_IPV4TTL 0x29 + + +#define CC_PC_FF_IPTOS_IPV6TC1_IPV6FLOW1 0x0d /*TODO - CLASS - what is it? TOS*/ +#define CC_PC_FF_IPTOS_IPV6TC2_IPV6FLOW2 0x1b +#define CC_PC_FF_IPV6PTYPE1 0x0e +#define CC_PC_FF_IPV6PTYPE2 0x1c +#define CC_PC_FF_IPV6DST1 0x0f +#define CC_PC_FF_IPV6DST2 0x1d +#define CC_PC_FF_IPV6SRC1 0x10 +#define CC_PC_FF_IPV6SRC2 0x1e +#define CC_PC_FF_IPV6HOP_LIMIT 0x2a +#define CC_PC_FF_IPPID 0x24 +#define CC_PC_FF_IPDSCP 0x76 + +#define CC_PC_FF_GREPTYPE 0x11 + +#define CC_PC_FF_MINENCAP_PTYPE 0x12 +#define CC_PC_FF_MINENCAP_IPDST 0x13 +#define CC_PC_FF_MINENCAP_IPSRC 0x14 +#define CC_PC_FF_MINENCAP_IPSRC_IPDST 0x15 + +#define CC_PC_FF_L4PSRC 0x1f +#define CC_PC_FF_L4PDST 0x20 +#define CC_PC_FF_L4PSRC_L4PDST 0x21 + +#define CC_PC_FF_PPPPID 0x05 + +#define CC_PC_PR_SHIM1 0x22 +#define CC_PC_PR_SHIM2 0x23 + +#define CC_PC_GENERIC_WITHOUT_MASK 0x27 +#define CC_PC_GENERIC_WITH_MASK 0x28 +#define CC_PC_GENERIC_IC_GMASK 0x2B +#define CC_PC_GENERIC_IC_HASH_INDEXED 0x2C +#define CC_PC_GENERIC_IC_AGING_MASK 0x2D + +#define CC_PR_OFFSET 0x25 +#define CC_PR_WITHOUT_OFFSET 0x26 + +#define CC_PC_PR_ETH_OFFSET 19 +#define CC_PC_PR_USER_DEFINED_SHIM1_OFFSET 16 +#define CC_PC_PR_USER_DEFINED_SHIM2_OFFSET 17 +#define CC_PC_PR_USER_LLC_SNAP_OFFSET 20 +#define CC_PC_PR_VLAN1_OFFSET 21 +#define CC_PC_PR_VLAN2_OFFSET 22 +#define CC_PC_PR_PPPOE_OFFSET 24 +#define CC_PC_PR_MPLS1_OFFSET 25 +#define CC_PC_PR_MPLS_LAST_OFFSET 26 +#define CC_PC_PR_IP1_OFFSET 27 +#define CC_PC_PR_IP_LAST_OFFSET 28 +#define CC_PC_PR_MINENC_OFFSET 28 +#define CC_PC_PR_L4_OFFSET 30 +#define CC_PC_PR_GRE_OFFSET 29 +#define CC_PC_PR_ETYPE_LAST_OFFSET 23 +#define CC_PC_PR_NEXT_HEADER_OFFSET 31 + +#define CC_PC_ILLEGAL 0xff +#define CC_SIZE_ILLEGAL 0 + +#define FM_PCD_CC_KEYS_MATCH_TABLE_ALIGN 16 +#define FM_PCD_CC_AD_TABLE_ALIGN 16 +#define FM_PCD_CC_AD_ENTRY_SIZE 16 +#define FM_PCD_CC_NUM_OF_KEYS 255 +#define FM_PCD_CC_TREE_ADDR_ALIGN 256 + +#define FM_PCD_AD_RESULT_CONTRL_FLOW_TYPE 0x00000000 +#define FM_PCD_AD_RESULT_DATA_FLOW_TYPE 0x80000000 +#define FM_PCD_AD_RESULT_PLCR_DIS 0x20000000 +#define FM_PCD_AD_RESULT_EXTENDED_MODE 0x80000000 +#define FM_PCD_AD_RESULT_NADEN 0x20000000 +#define FM_PCD_AD_RESULT_STATISTICS_EN 0x40000000 + +#define FM_PCD_AD_CONT_LOOKUP_TYPE 0x40000000 +#define FM_PCD_AD_CONT_LOOKUP_LCL_MASK 0x00800000 + +#define FM_PCD_AD_STATS_TYPE 0x40000000 +#define FM_PCD_AD_STATS_FLR_ADDR_MASK 0x00FFFFFF +#define FM_PCD_AD_STATS_COUNTERS_ADDR_MASK 0x00FFFFFF +#define FM_PCD_AD_STATS_NEXT_ACTION_MASK 0xFFFF0000 +#define FM_PCD_AD_STATS_NEXT_ACTION_SHIFT 12 +#define FM_PCD_AD_STATS_NAD_EN 0x00008000 +#define FM_PCD_AD_STATS_OP_CODE 0x00000036 +#define FM_PCD_AD_STATS_FLR_EN 0x00004000 +#define FM_PCD_AD_STATS_COND_EN 0x00002000 + + + +#define FM_PCD_AD_BYPASS_TYPE 0xc0000000 + +#define FM_PCD_AD_TYPE_MASK 0xc0000000 +#define FM_PCD_AD_OPCODE_MASK 0x0000000f + +#define FM_PCD_AD_PROFILEID_FOR_CNTRL_SHIFT 16 +#if (DPAA_VERSION >= 11) +#define FM_PCD_AD_RESULT_VSP_SHIFT 24 +#define FM_PCD_AD_RESULT_NO_OM_VSPE 0x02000000 +#define FM_PCD_AD_RESULT_VSP_MASK 0x3f +#define FM_PCD_AD_NCSPFQIDM_MASK 0x80000000 +#endif /* (DPAA_VERSION >= 11) */ + +#define GLBL_MASK_FOR_HASH_INDEXED 0xfff00000 +#define CC_GLBL_MASK_SIZE 4 +#define CC_AGING_MASK_SIZE 4 + +typedef uint32_t ccPrivateInfo_t; /**< private info of CC: */ + +#define CC_PRIVATE_INFO_NONE 0 +#define CC_PRIVATE_INFO_IC_HASH_INDEX_LOOKUP 0x80000000 +#define CC_PRIVATE_INFO_IC_HASH_EXACT_MATCH 0x40000000 +#define CC_PRIVATE_INFO_IC_KEY_EXACT_MATCH 0x20000000 +#define CC_PRIVATE_INFO_IC_DEQ_FQID_INDEX_LOOKUP 0x10000000 + +#define CC_BUILD_AGING_MASK(numOfKeys) ((((1LL << ((numOfKeys) + 1)) - 1)) << (31 - (numOfKeys))) +/***********************************************************************/ +/* Memory map */ +/***********************************************************************/ +#if defined(__MWERKS__) && !defined(__GNUC__) +#pragma pack(push,1) +#endif /* defined(__MWERKS__) && ... */ + +typedef struct +{ + volatile uint32_t fqid; + volatile uint32_t plcrProfile; + volatile uint32_t nia; + volatile uint32_t res; +} t_AdOfTypeResult; + +typedef struct +{ + volatile uint32_t ccAdBase; + volatile uint32_t matchTblPtr; + volatile uint32_t pcAndOffsets; + volatile uint32_t gmask; +} t_AdOfTypeContLookup; + +typedef struct +{ + volatile uint32_t profileTableAddr; + volatile uint32_t reserved; + volatile uint32_t nextActionIndx; + volatile uint32_t statsTableAddr; +} t_AdOfTypeStats; + +typedef union +{ + volatile t_AdOfTypeResult adResult; + volatile t_AdOfTypeContLookup adContLookup; +} t_Ad; + +#if defined(__MWERKS__) && !defined(__GNUC__) +#pragma pack(pop) +#endif /* defined(__MWERKS__) && ... */ + + +/***********************************************************************/ +/* Driver's internal structures */ +/***********************************************************************/ + +typedef struct t_FmPcdStatsObj +{ + t_Handle h_StatsAd; + t_Handle h_StatsCounters; + t_List node; +} t_FmPcdStatsObj; + +typedef struct +{ + uint8_t key[FM_PCD_MAX_SIZE_OF_KEY]; + uint8_t mask[FM_PCD_MAX_SIZE_OF_KEY]; + + t_FmPcdCcNextEngineParams nextEngineParams; + uint32_t requiredAction; + uint32_t shadowAction; + + t_FmPcdStatsObj *p_StatsObj; + +} t_FmPcdCcKeyAndNextEngineParams; + +typedef struct +{ + t_Handle p_Ad; + e_FmPcdEngine fmPcdEngine; + bool adAllocated; + bool isTree; + + uint32_t myInfo; + t_List *h_CcNextNodesLst; + t_Handle h_AdditionalInfo; + t_Handle h_Node; +} t_FmPcdModifyCcAdditionalParams; + +typedef struct +{ + t_Handle p_AdTableNew; + t_Handle p_KeysMatchTableNew; + t_Handle p_AdTableOld; + t_Handle p_KeysMatchTableOld; + uint16_t numOfKeys; + t_Handle h_CurrentNode; + uint16_t savedKeyIndex; + t_Handle h_NodeForAdd; + t_Handle h_NodeForRmv; + t_Handle h_ManipForRmv; + t_Handle h_ManipForAdd; + t_FmPcdStatsObj *p_StatsObjForRmv; +#if (DPAA_VERSION >= 11) + t_Handle h_FrmReplicForAdd; + t_Handle h_FrmReplicForRmv; +#endif /* (DPAA_VERSION >= 11) */ + bool tree; + + t_FmPcdCcKeyAndNextEngineParams keyAndNextEngineParams[CC_MAX_NUM_OF_KEYS]; +} t_FmPcdModifyCcKeyAdditionalParams; + +typedef struct +{ + t_Handle h_Manip; + t_Handle h_CcNode; +} t_CcNextEngineInfo; + +typedef struct +{ + uint16_t numOfKeys; + uint16_t maxNumOfKeys; + + bool maskSupport; + uint32_t keysMatchTableMaxSize; + + e_FmPcdCcStatsMode statisticsMode; + uint32_t numOfStatsFLRs; + uint32_t countersArraySize; + + bool isHashBucket; /**< Valid for match table node that is a bucket of a hash table only */ + t_Handle h_MissStatsCounters; /**< Valid for hash table node and match table that is a bucket; + Holds the statistics counters allocated by the hash table and + are shared by all hash table buckets; */ + t_Handle h_PrivMissStatsCounters; /**< Valid for match table node that is a bucket of a hash table only; + Holds the statistics counters that were allocated for this node + and replaced by the shared counters (allocated by the hash table); */ + bool statsEnForMiss; /**< Valid for hash table node only; TRUE is statistics are currently + enabled for hash 'miss', FALSE otherwise; This parameter effects the + returned statistics count to user, statistics AD always present for 'miss' + for all hash buckets; */ + bool glblMaskUpdated; + t_Handle p_GlblMask; + bool lclMask; + uint8_t parseCode; + uint8_t offset; + uint8_t prsArrayOffset; + bool ctrlFlow; + uint16_t owners; + + uint8_t ccKeySizeAccExtraction; + uint8_t sizeOfExtraction; + uint8_t glblMaskSize; + + t_Handle h_KeysMatchTable; + t_Handle h_AdTable; + t_Handle h_StatsAds; + t_Handle h_TmpAd; + t_Handle h_Ad; + t_Handle h_StatsFLRs; + + t_List availableStatsLst; + + t_List ccPrevNodesLst; + + t_List ccTreeIdLst; + t_List ccTreesLst; + + t_Handle h_FmPcd; + uint32_t shadowAction; + uint8_t userSizeOfExtraction; + uint8_t userOffset; + uint8_t kgHashShift; /* used in hash-table */ + + t_Handle h_Spinlock; + + t_FmPcdCcKeyAndNextEngineParams keyAndNextEngineParams[CC_MAX_NUM_OF_KEYS]; +} t_FmPcdCcNode; + +typedef struct +{ + t_FmPcdCcNode *p_FmPcdCcNode; + bool occupied; + uint16_t owners; + volatile bool lock; +} t_FmPcdCcNodeArray; + +typedef struct +{ + uint8_t numOfEntriesInGroup; + uint32_t totalBitsMask; + uint8_t baseGroupEntry; +} t_FmPcdCcGroupParam; + +typedef struct +{ + t_Handle h_FmPcd; + uint8_t netEnvId; + uintptr_t ccTreeBaseAddr; + uint8_t numOfGrps; + t_FmPcdCcGroupParam fmPcdGroupParam[FM_PCD_MAX_NUM_OF_CC_GROUPS]; + t_List fmPortsLst; + t_FmPcdLock *p_Lock; + uint8_t numOfEntries; + uint16_t owners; + t_Handle h_FmPcdCcSavedManipParams; + bool modifiedState; + uint32_t requiredAction; + t_Handle h_IpReassemblyManip; + t_Handle h_CapwapReassemblyManip; + + t_FmPcdCcKeyAndNextEngineParams keyAndNextEngineParams[FM_PCD_MAX_NUM_OF_CC_GROUPS]; +} t_FmPcdCcTree; + + +t_Error FmPcdCcNodeTreeTryLock(t_Handle h_FmPcd,t_Handle h_FmPcdCcNode, t_List *p_List); +void FmPcdCcNodeTreeReleaseLock(t_Handle h_FmPcd, t_List *p_List); +t_Error FmPcdUpdateCcShadow (t_FmPcd *p_FmPcd, uint32_t size, uint32_t align); + + +#endif /* __FM_CC_H */ diff --git a/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Pcd/fm_kg.c b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Pcd/fm_kg.c new file mode 100644 index 000000000000..811a0de9c700 --- /dev/null +++ b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Pcd/fm_kg.c @@ -0,0 +1,3246 @@ +/* + * Copyright 2008-2012 Freescale Semiconductor Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Freescale Semiconductor nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * + * ALTERNATIVELY, this software may be distributed under the terms of the + * GNU General Public License ("GPL") as published by the Free Software + * Foundation, either version 2 of that License or (at your option) any + * later version. + * + * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + +/****************************************************************************** + @File fm_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" +#include "fm_kg.h" +#include "fsl_fman_kg.h" + + +/****************************************/ +/* static functions */ +/****************************************/ + +static uint32_t KgHwLock(t_Handle h_FmPcdKg) +{ + ASSERT_COND(h_FmPcdKg); + return XX_LockIntrSpinlock(((t_FmPcdKg *)h_FmPcdKg)->h_HwSpinlock); +} + +static void KgHwUnlock(t_Handle h_FmPcdKg, uint32_t intFlags) +{ + ASSERT_COND(h_FmPcdKg); + XX_UnlockIntrSpinlock(((t_FmPcdKg *)h_FmPcdKg)->h_HwSpinlock, intFlags); +} + +static uint32_t KgSchemeLock(t_Handle h_Scheme) +{ + ASSERT_COND(h_Scheme); + return FmPcdLockSpinlock(((t_FmPcdKgScheme *)h_Scheme)->p_Lock); +} + +static void KgSchemeUnlock(t_Handle h_Scheme, uint32_t intFlags) +{ + ASSERT_COND(h_Scheme); + FmPcdUnlockSpinlock(((t_FmPcdKgScheme *)h_Scheme)->p_Lock, intFlags); +} + +static bool KgSchemeFlagTryLock(t_Handle h_Scheme) +{ + ASSERT_COND(h_Scheme); + return FmPcdLockTryLock(((t_FmPcdKgScheme *)h_Scheme)->p_Lock); +} + +static void KgSchemeFlagUnlock(t_Handle h_Scheme) +{ + ASSERT_COND(h_Scheme); + FmPcdLockUnlock(((t_FmPcdKgScheme *)h_Scheme)->p_Lock); +} + +static t_Error WriteKgarWait(t_FmPcd *p_FmPcd, uint32_t fmkg_ar) +{ + + struct fman_kg_regs *regs = p_FmPcd->p_FmPcdKg->p_FmPcdKgRegs; + + if (fman_kg_write_ar_wait(regs, fmkg_ar)) + 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<numOfSwDefaults ; i++) + if (swDefaults[i].type == e_FM_PCD_KG_GENERIC_NOT_FROM_DATA) + return swDefaults[i].dfltSelect; + break; + case (KG_SCH_GEN_SHIM1): + case (KG_SCH_GEN_SHIM2): + case (KG_SCH_GEN_IP_PID_NO_V): + case (KG_SCH_GEN_ETH_NO_V): + case (KG_SCH_GEN_SNAP_NO_V): + case (KG_SCH_GEN_VLAN1_NO_V): + case (KG_SCH_GEN_VLAN2_NO_V): + case (KG_SCH_GEN_ETH_TYPE_NO_V): + case (KG_SCH_GEN_PPP_NO_V): + case (KG_SCH_GEN_MPLS1_NO_V): + case (KG_SCH_GEN_MPLS_LAST_NO_V): + case (KG_SCH_GEN_L3_NO_V): + case (KG_SCH_GEN_IP2_NO_V): + case (KG_SCH_GEN_GRE_NO_V): + case (KG_SCH_GEN_L4_NO_V): + for (i=0 ; i<numOfSwDefaults ; i++) + if (swDefaults[i].type == e_FM_PCD_KG_GENERIC_FROM_DATA_NO_V) + return swDefaults[i].dfltSelect; + break; + case (KG_SCH_GEN_START_OF_FRM): + case (KG_SCH_GEN_ETH): + case (KG_SCH_GEN_SNAP): + case (KG_SCH_GEN_VLAN1): + case (KG_SCH_GEN_VLAN2): + case (KG_SCH_GEN_ETH_TYPE): + case (KG_SCH_GEN_PPP): + case (KG_SCH_GEN_MPLS1): + case (KG_SCH_GEN_MPLS2): + case (KG_SCH_GEN_MPLS3): + case (KG_SCH_GEN_MPLS_LAST): + case (KG_SCH_GEN_IPV4): + case (KG_SCH_GEN_IPV6): + case (KG_SCH_GEN_IPV4_TUNNELED): + case (KG_SCH_GEN_IPV6_TUNNELED): + case (KG_SCH_GEN_MIN_ENCAP): + case (KG_SCH_GEN_GRE): + case (KG_SCH_GEN_TCP): + case (KG_SCH_GEN_UDP): + case (KG_SCH_GEN_IPSEC_AH): + case (KG_SCH_GEN_SCTP): + case (KG_SCH_GEN_DCCP): + case (KG_SCH_GEN_IPSEC_ESP): + for (i=0 ; i<numOfSwDefaults ; i++) + if (swDefaults[i].type == e_FM_PCD_KG_GENERIC_FROM_DATA) + return swDefaults[i].dfltSelect; + break; + default: + break; + } + + return e_FM_PCD_KG_DFLT_ILLEGAL; +} + +static uint8_t GetGenCode(e_FmPcdExtractFrom src, uint8_t *p_Offset) +{ + *p_Offset = 0; + + switch (src) + { + case (e_FM_PCD_EXTRACT_FROM_FRAME_START): + return KG_SCH_GEN_START_OF_FRM; + case (e_FM_PCD_EXTRACT_FROM_DFLT_VALUE): + return KG_SCH_GEN_DEFAULT; + case (e_FM_PCD_EXTRACT_FROM_PARSE_RESULT): + return KG_SCH_GEN_PARSE_RESULT_N_FQID; + case (e_FM_PCD_EXTRACT_FROM_ENQ_FQID): + *p_Offset = 32; + return KG_SCH_GEN_PARSE_RESULT_N_FQID; + case (e_FM_PCD_EXTRACT_FROM_CURR_END_OF_PARSE): + return KG_SCH_GEN_NEXTHDR; + default: + REPORT_ERROR(MAJOR, E_INVALID_VALUE, ("Illegal 'extract from' src")); + return 0; + } +} + +static uint8_t GetGenHdrCode(e_NetHeaderType hdr, e_FmPcdHdrIndex hdrIndex, bool ignoreProtocolValidation) +{ + if (!ignoreProtocolValidation) + switch (hdr) + { + case (HEADER_TYPE_NONE): + ASSERT_COND(FALSE); + /* Else fall through */ + case (HEADER_TYPE_ETH): + return KG_SCH_GEN_ETH; + case (HEADER_TYPE_LLC_SNAP): + return KG_SCH_GEN_SNAP; + case (HEADER_TYPE_PPPoE): + return KG_SCH_GEN_PPP; + case (HEADER_TYPE_MPLS): + if ((hdrIndex == e_FM_PCD_HDR_INDEX_NONE) || (hdrIndex == e_FM_PCD_HDR_INDEX_1)) + return KG_SCH_GEN_MPLS1; + if (hdrIndex == e_FM_PCD_HDR_INDEX_2) + return KG_SCH_GEN_MPLS2; + if (hdrIndex == e_FM_PCD_HDR_INDEX_3) + return KG_SCH_GEN_MPLS3; + if (hdrIndex == e_FM_PCD_HDR_INDEX_LAST) + return KG_SCH_GEN_MPLS_LAST; + REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Illegal MPLS header index")); + return 0; + case (HEADER_TYPE_IPv4): + if ((hdrIndex == e_FM_PCD_HDR_INDEX_NONE) || (hdrIndex == e_FM_PCD_HDR_INDEX_1)) + return KG_SCH_GEN_IPV4; + if ((hdrIndex == e_FM_PCD_HDR_INDEX_2) || (hdrIndex == e_FM_PCD_HDR_INDEX_LAST)) + return KG_SCH_GEN_IPV4_TUNNELED; + REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Illegal IPv4 header index")); + return 0; + case (HEADER_TYPE_IPv6): + if ((hdrIndex == e_FM_PCD_HDR_INDEX_NONE) || (hdrIndex == e_FM_PCD_HDR_INDEX_1)) + return KG_SCH_GEN_IPV6; + if ((hdrIndex == e_FM_PCD_HDR_INDEX_2) || (hdrIndex == e_FM_PCD_HDR_INDEX_LAST)) + return KG_SCH_GEN_IPV6_TUNNELED; + REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Illegal IPv6 header index")); + return 0; + case (HEADER_TYPE_GRE): + return KG_SCH_GEN_GRE; + case (HEADER_TYPE_TCP): + return KG_SCH_GEN_TCP; + case (HEADER_TYPE_UDP): + return KG_SCH_GEN_UDP; + case (HEADER_TYPE_IPSEC_AH): + return KG_SCH_GEN_IPSEC_AH; + case (HEADER_TYPE_IPSEC_ESP): + return KG_SCH_GEN_IPSEC_ESP; + case (HEADER_TYPE_SCTP): + return KG_SCH_GEN_SCTP; + case (HEADER_TYPE_DCCP): + return KG_SCH_GEN_DCCP; + default: + REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Extraction not supported")); + return 0; + } + else + switch (hdr) + { + case (HEADER_TYPE_NONE): + ASSERT_COND(FALSE); + /* Else fall through */ + case (HEADER_TYPE_ETH): + return KG_SCH_GEN_ETH_NO_V; + case (HEADER_TYPE_LLC_SNAP): + return KG_SCH_GEN_SNAP_NO_V; + case (HEADER_TYPE_PPPoE): + return KG_SCH_GEN_PPP_NO_V; + case (HEADER_TYPE_MPLS): + if ((hdrIndex == e_FM_PCD_HDR_INDEX_NONE) || (hdrIndex == e_FM_PCD_HDR_INDEX_1)) + return KG_SCH_GEN_MPLS1_NO_V; + if (hdrIndex == e_FM_PCD_HDR_INDEX_LAST) + return KG_SCH_GEN_MPLS_LAST_NO_V; + if ((hdrIndex == e_FM_PCD_HDR_INDEX_2) || (hdrIndex == e_FM_PCD_HDR_INDEX_3) ) + REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Indexed MPLS Extraction not supported")); + else + REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Illegal MPLS header index")); + return 0; + case (HEADER_TYPE_IPv4): + /* fall through */ + case (HEADER_TYPE_IPv6): + if ((hdrIndex == e_FM_PCD_HDR_INDEX_NONE) || (hdrIndex == e_FM_PCD_HDR_INDEX_1)) + return KG_SCH_GEN_L3_NO_V; + if ((hdrIndex == e_FM_PCD_HDR_INDEX_2) || (hdrIndex == e_FM_PCD_HDR_INDEX_LAST)) + return KG_SCH_GEN_IP2_NO_V; + REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Illegal IP header index")); + /* fall through */ + case (HEADER_TYPE_MINENCAP): + return KG_SCH_GEN_IP2_NO_V; + case (HEADER_TYPE_USER_DEFINED_L3): + return KG_SCH_GEN_L3_NO_V; + case (HEADER_TYPE_GRE): + return KG_SCH_GEN_GRE_NO_V; + case (HEADER_TYPE_TCP): + case (HEADER_TYPE_UDP): + case (HEADER_TYPE_IPSEC_AH): + case (HEADER_TYPE_IPSEC_ESP): + case (HEADER_TYPE_SCTP): + case (HEADER_TYPE_DCCP): + return KG_SCH_GEN_L4_NO_V; + case (HEADER_TYPE_USER_DEFINED_SHIM1): + return KG_SCH_GEN_SHIM1; + case (HEADER_TYPE_USER_DEFINED_SHIM2): + return KG_SCH_GEN_SHIM2; + default: + REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Extraction not supported")); + return 0; + } +} +static t_GenericCodes GetGenFieldCode(e_NetHeaderType hdr, t_FmPcdFields field, bool ignoreProtocolValidation, e_FmPcdHdrIndex hdrIndex) +{ + if (!ignoreProtocolValidation) + switch (hdr) + { + case (HEADER_TYPE_NONE): + ASSERT_COND(FALSE); + break; + case (HEADER_TYPE_ETH): + switch (field.eth) + { + case (NET_HEADER_FIELD_ETH_TYPE): + return KG_SCH_GEN_ETH_TYPE; + default: + REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Extraction not supported")); + return 0; + } + break; + case (HEADER_TYPE_VLAN): + switch (field.vlan) + { + case (NET_HEADER_FIELD_VLAN_TCI): + if ((hdrIndex == e_FM_PCD_HDR_INDEX_NONE) || (hdrIndex == e_FM_PCD_HDR_INDEX_1)) + return KG_SCH_GEN_VLAN1; + if (hdrIndex == e_FM_PCD_HDR_INDEX_LAST) + return KG_SCH_GEN_VLAN2; + REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Illegal VLAN header index")); + return 0; + } + break; + case (HEADER_TYPE_MPLS): + case (HEADER_TYPE_IPSEC_AH): + case (HEADER_TYPE_IPSEC_ESP): + case (HEADER_TYPE_LLC_SNAP): + case (HEADER_TYPE_PPPoE): + case (HEADER_TYPE_IPv4): + case (HEADER_TYPE_IPv6): + case (HEADER_TYPE_GRE): + case (HEADER_TYPE_MINENCAP): + case (HEADER_TYPE_USER_DEFINED_L3): + case (HEADER_TYPE_TCP): + case (HEADER_TYPE_UDP): + case (HEADER_TYPE_SCTP): + case (HEADER_TYPE_DCCP): + case (HEADER_TYPE_USER_DEFINED_L4): + REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Extraction not supported")); + return 0; + default: + break; + + } + else + switch (hdr) + { + case (HEADER_TYPE_NONE): + ASSERT_COND(FALSE); + break; + case (HEADER_TYPE_ETH): + switch (field.eth) + { + case (NET_HEADER_FIELD_ETH_TYPE): + return KG_SCH_GEN_ETH_TYPE_NO_V; + default: + REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Extraction not supported")); + return 0; + } + break; + case (HEADER_TYPE_VLAN): + switch (field.vlan) + { + case (NET_HEADER_FIELD_VLAN_TCI) : + if ((hdrIndex == e_FM_PCD_HDR_INDEX_NONE) || (hdrIndex == e_FM_PCD_HDR_INDEX_1)) + return KG_SCH_GEN_VLAN1_NO_V; + if (hdrIndex == e_FM_PCD_HDR_INDEX_LAST) + return KG_SCH_GEN_VLAN2_NO_V; + REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Illegal VLAN header index")); + return 0; + } + break; + case (HEADER_TYPE_IPv4): + switch (field.ipv4) + { + case (NET_HEADER_FIELD_IPv4_PROTO): + return KG_SCH_GEN_IP_PID_NO_V; + default: + REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Extraction not supported")); + return 0; + } + break; + case (HEADER_TYPE_IPv6): + switch (field.ipv6) + { + case (NET_HEADER_FIELD_IPv6_NEXT_HDR): + return KG_SCH_GEN_IP_PID_NO_V; + default: + REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Extraction not supported")); + return 0; + } + break; + case (HEADER_TYPE_MPLS): + case (HEADER_TYPE_LLC_SNAP): + case (HEADER_TYPE_PPPoE): + case (HEADER_TYPE_GRE): + case (HEADER_TYPE_MINENCAP): + case (HEADER_TYPE_USER_DEFINED_L3): + case (HEADER_TYPE_TCP): + case (HEADER_TYPE_UDP): + case (HEADER_TYPE_IPSEC_AH): + case (HEADER_TYPE_IPSEC_ESP): + case (HEADER_TYPE_SCTP): + case (HEADER_TYPE_DCCP): + case (HEADER_TYPE_USER_DEFINED_L4): + REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Extraction not supported")); + return 0; + default: + break; + } + REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Header not supported")); + return 0; +} + +static t_KnownFieldsMasks GetKnownProtMask(t_FmPcd *p_FmPcd, e_NetHeaderType hdr, e_FmPcdHdrIndex index, t_FmPcdFields field) +{ + UNUSED(p_FmPcd); + + switch (hdr) + { + case (HEADER_TYPE_NONE): + ASSERT_COND(FALSE); + break; + case (HEADER_TYPE_ETH): + switch (field.eth) + { + case (NET_HEADER_FIELD_ETH_DA): + return KG_SCH_KN_MACDST; + case (NET_HEADER_FIELD_ETH_SA): + return KG_SCH_KN_MACSRC; + case (NET_HEADER_FIELD_ETH_TYPE): + return KG_SCH_KN_ETYPE; + default: + REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Extraction not supported")); + return 0; + } + case (HEADER_TYPE_LLC_SNAP): + switch (field.llcSnap) + { + case (NET_HEADER_FIELD_LLC_SNAP_TYPE): + return KG_SCH_KN_ETYPE; + default: + REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Extraction not supported")); + return 0; + } + case (HEADER_TYPE_VLAN): + switch (field.vlan) + { + case (NET_HEADER_FIELD_VLAN_TCI): + if ((index == e_FM_PCD_HDR_INDEX_NONE) || (index == e_FM_PCD_HDR_INDEX_1)) + return KG_SCH_KN_TCI1; + if (index == e_FM_PCD_HDR_INDEX_LAST) + return KG_SCH_KN_TCI2; + else + { + REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Extraction not supported")); + return 0; + } + default: + REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Extraction not supported")); + return 0; + } + case (HEADER_TYPE_MPLS): + switch (field.mpls) + { + case (NET_HEADER_FIELD_MPLS_LABEL_STACK): + if ((index == e_FM_PCD_HDR_INDEX_NONE) || (index == e_FM_PCD_HDR_INDEX_1)) + return KG_SCH_KN_MPLS1; + if (index == e_FM_PCD_HDR_INDEX_2) + return KG_SCH_KN_MPLS2; + if (index == e_FM_PCD_HDR_INDEX_LAST) + return KG_SCH_KN_MPLS_LAST; + REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Illegal MPLS index")); + return 0; + default: + REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Extraction not supported")); + return 0; + } + case (HEADER_TYPE_IPv4): + switch (field.ipv4) + { + case (NET_HEADER_FIELD_IPv4_SRC_IP): + if ((index == e_FM_PCD_HDR_INDEX_NONE) || (index == e_FM_PCD_HDR_INDEX_1)) + return KG_SCH_KN_IPSRC1; + if ((index == e_FM_PCD_HDR_INDEX_2) || (index == e_FM_PCD_HDR_INDEX_LAST)) + return KG_SCH_KN_IPSRC2; + REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Illegal IPv4 index")); + return 0; + case (NET_HEADER_FIELD_IPv4_DST_IP): + if ((index == e_FM_PCD_HDR_INDEX_NONE) || (index == e_FM_PCD_HDR_INDEX_1)) + return KG_SCH_KN_IPDST1; + if ((index == e_FM_PCD_HDR_INDEX_2) || (index == e_FM_PCD_HDR_INDEX_LAST)) + return KG_SCH_KN_IPDST2; + REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Illegal IPv4 index")); + return 0; + case (NET_HEADER_FIELD_IPv4_PROTO): + if ((index == e_FM_PCD_HDR_INDEX_NONE) || (index == e_FM_PCD_HDR_INDEX_1)) + return KG_SCH_KN_PTYPE1; + if ((index == e_FM_PCD_HDR_INDEX_2) || (index == e_FM_PCD_HDR_INDEX_LAST)) + return KG_SCH_KN_PTYPE2; + REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Illegal IPv4 index")); + return 0; + case (NET_HEADER_FIELD_IPv4_TOS): + if ((index == e_FM_PCD_HDR_INDEX_NONE) || (index == e_FM_PCD_HDR_INDEX_1)) + return KG_SCH_KN_IPTOS_TC1; + if ((index == e_FM_PCD_HDR_INDEX_2) || (index == e_FM_PCD_HDR_INDEX_LAST)) + return KG_SCH_KN_IPTOS_TC2; + REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Illegal IPv4 index")); + return 0; + default: + REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Extraction not supported")); + return 0; + } + case (HEADER_TYPE_IPv6): + switch (field.ipv6) + { + case (NET_HEADER_FIELD_IPv6_SRC_IP): + if ((index == e_FM_PCD_HDR_INDEX_NONE) || (index == e_FM_PCD_HDR_INDEX_1)) + return KG_SCH_KN_IPSRC1; + if ((index == e_FM_PCD_HDR_INDEX_2) || (index == e_FM_PCD_HDR_INDEX_LAST)) + return KG_SCH_KN_IPSRC2; + REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Illegal IPv6 index")); + return 0; + case (NET_HEADER_FIELD_IPv6_DST_IP): + if ((index == e_FM_PCD_HDR_INDEX_NONE) || (index == e_FM_PCD_HDR_INDEX_1)) + return KG_SCH_KN_IPDST1; + if ((index == e_FM_PCD_HDR_INDEX_2) || (index == e_FM_PCD_HDR_INDEX_LAST)) + return KG_SCH_KN_IPDST2; + REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Illegal IPv6 index")); + return 0; + case (NET_HEADER_FIELD_IPv6_NEXT_HDR): + if ((index == e_FM_PCD_HDR_INDEX_NONE) || (index == e_FM_PCD_HDR_INDEX_1)) + return KG_SCH_KN_PTYPE1; + if (index == e_FM_PCD_HDR_INDEX_2) + return KG_SCH_KN_PTYPE2; + if (index == e_FM_PCD_HDR_INDEX_LAST) +#ifdef FM_KG_NO_IPPID_SUPPORT + if (p_FmPcd->fmRevInfo.majorRev < 6) + return KG_SCH_KN_PTYPE2; +#endif /* FM_KG_NO_IPPID_SUPPORT */ + return KG_SCH_KN_IPPID; + REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Illegal IPv6 index")); + return 0; + case (NET_HEADER_FIELD_IPv6_VER | NET_HEADER_FIELD_IPv6_FL | NET_HEADER_FIELD_IPv6_TC): + if ((index == e_FM_PCD_HDR_INDEX_NONE) || (index == e_FM_PCD_HDR_INDEX_1)) + return (KG_SCH_KN_IPV6FL1 | KG_SCH_KN_IPTOS_TC1); + if ((index == e_FM_PCD_HDR_INDEX_2) || (index == e_FM_PCD_HDR_INDEX_LAST)) + return (KG_SCH_KN_IPV6FL2 | KG_SCH_KN_IPTOS_TC2); + REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Illegal IPv6 index")); + return 0; + case (NET_HEADER_FIELD_IPv6_VER | NET_HEADER_FIELD_IPv6_TC): + if ((index == e_FM_PCD_HDR_INDEX_NONE) || (index == e_FM_PCD_HDR_INDEX_1)) + return KG_SCH_KN_IPTOS_TC1; + if ((index == e_FM_PCD_HDR_INDEX_2) || (index == e_FM_PCD_HDR_INDEX_LAST)) + return KG_SCH_KN_IPTOS_TC2; + REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Illegal IPv6 index")); + return 0; + case (NET_HEADER_FIELD_IPv6_FL): + if ((index == e_FM_PCD_HDR_INDEX_NONE) || (index == e_FM_PCD_HDR_INDEX_1)) + return KG_SCH_KN_IPV6FL1; + if ((index == e_FM_PCD_HDR_INDEX_2) || (index == e_FM_PCD_HDR_INDEX_LAST)) + return KG_SCH_KN_IPV6FL2; + REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Illegal IPv6 index")); + return 0; + default: + REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Extraction not supported")); + return 0; + } + case (HEADER_TYPE_GRE): + switch (field.gre) + { + case (NET_HEADER_FIELD_GRE_TYPE): + return KG_SCH_KN_GREPTYPE; + default: + REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Extraction not supported")); + return 0; + } + case (HEADER_TYPE_MINENCAP): + switch (field.minencap) + { + case (NET_HEADER_FIELD_MINENCAP_SRC_IP): + return KG_SCH_KN_IPSRC2; + case (NET_HEADER_FIELD_MINENCAP_DST_IP): + return KG_SCH_KN_IPDST2; + case (NET_HEADER_FIELD_MINENCAP_TYPE): + return KG_SCH_KN_PTYPE2; + default: + REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Extraction not supported")); + return 0; + } + case (HEADER_TYPE_TCP): + switch (field.tcp) + { + case (NET_HEADER_FIELD_TCP_PORT_SRC): + return KG_SCH_KN_L4PSRC; + case (NET_HEADER_FIELD_TCP_PORT_DST): + return KG_SCH_KN_L4PDST; + case (NET_HEADER_FIELD_TCP_FLAGS): + return KG_SCH_KN_TFLG; + default: + REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Extraction not supported")); + return 0; + } + case (HEADER_TYPE_UDP): + switch (field.udp) + { + case (NET_HEADER_FIELD_UDP_PORT_SRC): + return KG_SCH_KN_L4PSRC; + case (NET_HEADER_FIELD_UDP_PORT_DST): + return KG_SCH_KN_L4PDST; + default: + REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Extraction not supported")); + return 0; + } + case (HEADER_TYPE_IPSEC_AH): + switch (field.ipsecAh) + { + case (NET_HEADER_FIELD_IPSEC_AH_SPI): + return KG_SCH_KN_IPSEC_SPI; + case (NET_HEADER_FIELD_IPSEC_AH_NH): + return KG_SCH_KN_IPSEC_NH; + default: + REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Extraction not supported")); + return 0; + } + case (HEADER_TYPE_IPSEC_ESP): + switch (field.ipsecEsp) + { + case (NET_HEADER_FIELD_IPSEC_ESP_SPI): + return KG_SCH_KN_IPSEC_SPI; + default: + REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Extraction not supported")); + return 0; + } + case (HEADER_TYPE_SCTP): + switch (field.sctp) + { + case (NET_HEADER_FIELD_SCTP_PORT_SRC): + return KG_SCH_KN_L4PSRC; + case (NET_HEADER_FIELD_SCTP_PORT_DST): + return KG_SCH_KN_L4PDST; + default: + REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Extraction not supported")); + return 0; + } + case (HEADER_TYPE_DCCP): + switch (field.dccp) + { + case (NET_HEADER_FIELD_DCCP_PORT_SRC): + return KG_SCH_KN_L4PSRC; + case (NET_HEADER_FIELD_DCCP_PORT_DST): + return KG_SCH_KN_L4PDST; + default: + REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Extraction not supported")); + return 0; + } + case (HEADER_TYPE_PPPoE): + switch (field.pppoe) + { + case (NET_HEADER_FIELD_PPPoE_PID): + return KG_SCH_KN_PPPID; + case (NET_HEADER_FIELD_PPPoE_SID): + return KG_SCH_KN_PPPSID; + default: + REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Extraction not supported")); + return 0; + } + default: + break; + + } + + REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Extraction not supported")); + return 0; +} + + +static uint8_t GetKnownFieldId(uint32_t bitMask) +{ + uint8_t cnt = 0; + + while (bitMask) + if (bitMask & 0x80000000) + break; + else + { + cnt++; + bitMask <<= 1; + } + return cnt; + +} + +static uint8_t GetExtractedOrMask(uint8_t bitOffset, bool fqid) +{ + uint8_t i, mask, numOfOnesToClear, walking1Mask = 1; + + /* bitOffset 1-7 --> 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; +} + +static void IncSchemeOwners(t_FmPcd *p_FmPcd, t_FmPcdKgInterModuleBindPortToSchemes *p_BindPort) +{ + t_FmPcdKg *p_FmPcdKg; + t_FmPcdKgScheme *p_Scheme; + uint32_t intFlags; + uint8_t relativeSchemeId; + int i; + + p_FmPcdKg = p_FmPcd->p_FmPcdKg; + + /* for each scheme - update owners counters */ + for (i = 0; i < p_BindPort->numOfSchemes; i++) + { + relativeSchemeId = FmPcdKgGetRelativeSchemeId(p_FmPcd, p_BindPort->schemesIds[i]); + ASSERT_COND(relativeSchemeId < FM_PCD_KG_NUM_OF_SCHEMES); + + p_Scheme = &p_FmPcdKg->schemes[relativeSchemeId]; + + /* increment owners number */ + intFlags = KgSchemeLock(p_Scheme); + p_Scheme->owners++; + KgSchemeUnlock(p_Scheme, intFlags); + } +} + +static void DecSchemeOwners(t_FmPcd *p_FmPcd, t_FmPcdKgInterModuleBindPortToSchemes *p_BindPort) +{ + t_FmPcdKg *p_FmPcdKg; + t_FmPcdKgScheme *p_Scheme; + uint32_t intFlags; + uint8_t relativeSchemeId; + int i; + + p_FmPcdKg = p_FmPcd->p_FmPcdKg; + + /* for each scheme - update owners counters */ + for (i = 0; i < p_BindPort->numOfSchemes; i++) + { + relativeSchemeId = FmPcdKgGetRelativeSchemeId(p_FmPcd, p_BindPort->schemesIds[i]); + ASSERT_COND(relativeSchemeId < FM_PCD_KG_NUM_OF_SCHEMES); + + p_Scheme = &p_FmPcdKg->schemes[relativeSchemeId]; + + /* increment owners number */ + ASSERT_COND(p_Scheme->owners); + intFlags = KgSchemeLock(p_Scheme); + p_Scheme->owners--; + KgSchemeUnlock(p_Scheme, intFlags); + } +} + +static void UpdateRequiredActionFlag(t_FmPcdKgScheme *p_Scheme, bool set) +{ + /* this routine is locked by the calling routine */ + ASSERT_COND(p_Scheme); + ASSERT_COND(p_Scheme->valid); + + if (set) + p_Scheme->requiredActionFlag = TRUE; + else + { + p_Scheme->requiredAction = 0; + p_Scheme->requiredActionFlag = FALSE; + } +} + +static t_Error KgWriteSp(t_FmPcd *p_FmPcd, uint8_t hardwarePortId, uint32_t spReg, bool add) +{ + struct fman_kg_regs *p_KgRegs; + + uint32_t tmpKgarReg = 0, intFlags; + t_Error err = E_OK; + + /* The calling routine had locked the port, so for each port only one core can access + * (so we don't need a lock here) */ + + if (p_FmPcd->h_Hc) + return FmHcKgWriteSp(p_FmPcd->h_Hc, hardwarePortId, spReg, add); + + p_KgRegs = p_FmPcd->p_FmPcdKg->p_FmPcdKgRegs; + + tmpKgarReg = FmPcdKgBuildReadPortSchemeBindActionReg(hardwarePortId); + /* lock a common KG reg */ + intFlags = KgHwLock(p_FmPcd->p_FmPcdKg); + err = WriteKgarWait(p_FmPcd, tmpKgarReg); + if (err) + { + KgHwUnlock(p_FmPcd->p_FmPcdKg, intFlags); + RETURN_ERROR(MINOR, err, NO_MSG); + } + + fman_kg_write_sp(p_KgRegs, spReg, add); + + tmpKgarReg = FmPcdKgBuildWritePortSchemeBindActionReg(hardwarePortId); + + err = WriteKgarWait(p_FmPcd, tmpKgarReg); + KgHwUnlock(p_FmPcd->p_FmPcdKg, intFlags); + return err; +} + +static t_Error KgWriteCpp(t_FmPcd *p_FmPcd, uint8_t hardwarePortId, uint32_t cppReg) +{ + struct fman_kg_regs *p_KgRegs; + uint32_t tmpKgarReg, intFlags; + t_Error err; + + p_KgRegs = p_FmPcd->p_FmPcdKg->p_FmPcdKgRegs; + + if (p_FmPcd->h_Hc) + { + err = FmHcKgWriteCpp(p_FmPcd->h_Hc, hardwarePortId, cppReg); + return err; + } + + intFlags = KgHwLock(p_FmPcd->p_FmPcdKg); + fman_kg_write_cpp(p_KgRegs, cppReg); + tmpKgarReg = FmPcdKgBuildWritePortClsPlanBindActionReg(hardwarePortId); + err = WriteKgarWait(p_FmPcd, tmpKgarReg); + KgHwUnlock(p_FmPcd->p_FmPcdKg, intFlags); + + return err; +} + +static uint32_t BuildCppReg(t_FmPcd *p_FmPcd, uint8_t clsPlanGrpId) +{ + 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_KG_PE_CPP_MASK_SHIFT); + + return tmpKgpeCpp; +} + +static t_Error BindPortToClsPlanGrp(t_FmPcd *p_FmPcd, uint8_t hardwarePortId, uint8_t clsPlanGrpId) +{ + uint32_t tmpKgpeCpp = 0; + + tmpKgpeCpp = BuildCppReg(p_FmPcd, clsPlanGrpId); + return KgWriteCpp(p_FmPcd, hardwarePortId, tmpKgpeCpp); +} + +static void UnbindPortToClsPlanGrp(t_FmPcd *p_FmPcd, uint8_t hardwarePortId) +{ + KgWriteCpp(p_FmPcd, hardwarePortId, 0); +} + +#if (defined(DEBUG_ERRORS) && (DEBUG_ERRORS > 0)) +static uint32_t __attribute__((unused)) ReadClsPlanBlockActionReg(uint8_t grpId) +{ + return (uint32_t)(FM_KG_KGAR_GO | + FM_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))); + */ +} +#endif /* (defined(DEBUG_ERRORS) && ... */ + +static void PcdKgErrorException(t_Handle h_FmPcd) +{ + t_FmPcd *p_FmPcd = (t_FmPcd *)h_FmPcd; + uint32_t event,schemeIndexes = 0, index = 0; + struct fman_kg_regs *p_KgRegs; + + ASSERT_COND(FmIsMaster(p_FmPcd->h_Fm)); + p_KgRegs = p_FmPcd->p_FmPcdKg->p_FmPcdKgRegs; + fman_kg_get_event(p_KgRegs, &event, &schemeIndexes); + + if (event & FM_EX_KG_DOUBLE_ECC) + p_FmPcd->f_Exception(p_FmPcd->h_App,e_FM_PCD_KG_EXCEPTION_DOUBLE_ECC); + if (event & FM_EX_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; + struct fman_kg_regs *p_Regs = p_FmPcd->p_FmPcdKg->p_FmPcdKgRegs; + + ASSERT_COND(p_FmPcd->guestId == NCSW_MASTER_ID); + + if (p_FmPcd->exceptions & FM_EX_KG_DOUBLE_ECC) + FmEnableRamsEcc(p_FmPcd->h_Fm); + + fman_kg_init(p_Regs, p_FmPcd->exceptions, GET_NIA_BMI_AC_ENQ_FRAME(p_FmPcd)); + + /* 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); + + fman_kg_enable_scheme_interrupts(p_Regs); + + 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; +} + +static void ValidateSchemeSw(t_FmPcdKgScheme *p_Scheme) +{ + ASSERT_COND(!p_Scheme->valid); + if (p_Scheme->netEnvId != ILLEGAL_NETENV) + FmPcdIncNetEnvOwners(p_Scheme->h_FmPcd, p_Scheme->netEnvId); + p_Scheme->valid = TRUE; +} + +static t_Error InvalidateSchemeSw(t_FmPcdKgScheme *p_Scheme) +{ + if (p_Scheme->owners) + RETURN_ERROR(MINOR, E_INVALID_STATE, ("Trying to delete a scheme that has ports bound to")); + + if (p_Scheme->netEnvId != ILLEGAL_NETENV) + FmPcdDecNetEnvOwners(p_Scheme->h_FmPcd, p_Scheme->netEnvId); + p_Scheme->valid = FALSE; + + return E_OK; +} + +static t_Error BuildSchemeRegs(t_FmPcdKgScheme *p_Scheme, + t_FmPcdKgSchemeParams *p_SchemeParams, + struct fman_kg_scheme_regs *p_SchemeRegs) +{ + t_FmPcd *p_FmPcd = (t_FmPcd *)(p_Scheme->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; + + memset(swDefaults, 0, NUM_OF_SW_DEFAULTS*sizeof(t_FmPcdKgExtractDflt)); + memset(p_SchemeRegs, 0, sizeof(struct fman_kg_scheme_regs)); + + if (p_SchemeParams->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_SchemeParams->alwaysDirect) + { + p_Scheme->netEnvId = FmPcdGetNetEnvId(p_SchemeParams->netEnvParams.h_NetEnv); + netEnvParams.netEnvId = p_Scheme->netEnvId; + netEnvParams.numOfDistinctionUnits = p_SchemeParams->netEnvParams.numOfDistinctionUnits; + memcpy(netEnvParams.unitIds, p_SchemeParams->netEnvParams.unitIds, (sizeof(uint8_t))*p_SchemeParams->netEnvParams.numOfDistinctionUnits); + err = PcdGetUnitsVector(p_FmPcd, &netEnvParams); + if (err) + RETURN_ERROR(MAJOR, E_INVALID_STATE, NO_MSG); + p_Scheme->matchVector = netEnvParams.vector; + } + else + { + p_Scheme->matchVector = SCHEME_ALWAYS_DIRECT; + p_Scheme->netEnvId = ILLEGAL_NETENV; + } + + if (p_SchemeParams->nextEngine == e_FM_PCD_INVALID) + RETURN_ERROR(MAJOR, E_INVALID_STATE, ("Next Engine of the scheme is not Valid")); + + if (p_SchemeParams->bypassFqidGeneration) + { +#ifdef FM_KG_NO_BYPASS_FQID_GEN + if ((p_FmPcd->fmRevInfo.majorRev != 4) && (p_FmPcd->fmRevInfo.majorRev < 6)) + RETURN_ERROR(MAJOR, E_NOT_SUPPORTED, ("bypassFqidGeneration.")); +#endif /* FM_KG_NO_BYPASS_FQID_GEN */ + if (p_SchemeParams->baseFqid) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("baseFqid set for a scheme that does not generate an FQID")); + } + else + if (!p_SchemeParams->baseFqid) + DBG(WARNING, ("baseFqid is 0.")); + + if (p_SchemeParams->nextEngine == e_FM_PCD_PLCR) + { + direct = p_SchemeParams->kgNextEngineParams.plcrProfile.direct; + p_Scheme->directPlcr = direct; + absolute = (bool)(p_SchemeParams->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_SchemeParams->kgNextEngineParams.plcrProfile.profileSelect.directRelativeProfileId; + numOfProfiles = 1; + } + else + { + profileId = p_SchemeParams->kgNextEngineParams.plcrProfile.profileSelect.indirectProfile.fqidOffsetRelativeProfileIdBase; + shift = p_SchemeParams->kgNextEngineParams.plcrProfile.profileSelect.indirectProfile.fqidOffsetShift; + numOfProfiles = p_SchemeParams->kgNextEngineParams.plcrProfile.profileSelect.indirectProfile.numOfProfiles; + } + } + + if (p_SchemeParams->nextEngine == e_FM_PCD_CC) + { +#ifdef FM_KG_NO_BYPASS_PLCR_PROFILE_GEN + if ((p_SchemeParams->kgNextEngineParams.cc.plcrNext) && (p_SchemeParams->kgNextEngineParams.cc.bypassPlcrProfileGeneration)) + { + if ((p_FmPcd->fmRevInfo.majorRev != 4) && (p_FmPcd->fmRevInfo.majorRev < 6)) + RETURN_ERROR(MAJOR, E_NOT_SUPPORTED, ("bypassPlcrProfileGeneration.")); + } +#endif /* FM_KG_NO_BYPASS_PLCR_PROFILE_GEN */ + + err = FmPcdCcGetGrpParams(p_SchemeParams->kgNextEngineParams.cc.h_CcTree, + p_SchemeParams->kgNextEngineParams.cc.grpId, + &grpBits, + &grpBase); + if (err) + RETURN_ERROR(MAJOR, err, NO_MSG); + p_Scheme->ccUnits = grpBits; + + if ((p_SchemeParams->kgNextEngineParams.cc.plcrNext) && + (!p_SchemeParams->kgNextEngineParams.cc.bypassPlcrProfileGeneration)) + { + if (p_SchemeParams->kgNextEngineParams.cc.plcrProfile.sharedProfile) + RETURN_ERROR(MAJOR, E_INVALID_STATE, ("Shared profile may not be used after Coarse classification.")); + absolute = FALSE; + direct = p_SchemeParams->kgNextEngineParams.cc.plcrProfile.direct; + if (direct) + { + profileId = p_SchemeParams->kgNextEngineParams.cc.plcrProfile.profileSelect.directRelativeProfileId; + numOfProfiles = 1; + } + else + { + profileId = p_SchemeParams->kgNextEngineParams.cc.plcrProfile.profileSelect.indirectProfile.fqidOffsetRelativeProfileIdBase; + shift = p_SchemeParams->kgNextEngineParams.cc.plcrProfile.profileSelect.indirectProfile.fqidOffsetShift; + numOfProfiles = p_SchemeParams->kgNextEngineParams.cc.plcrProfile.profileSelect.indirectProfile.numOfProfiles; + } + } + } + + /* if policer is used directly after KG, or after CC */ + if ((p_SchemeParams->nextEngine == e_FM_PCD_PLCR) || + ((p_SchemeParams->nextEngine == e_FM_PCD_CC) && + (p_SchemeParams->kgNextEngineParams.cc.plcrNext) && + (!p_SchemeParams->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 = FmPcdPlcrGetAbsoluteIdByProfileParams((t_Handle)p_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_Scheme->relativeProfileId = profileId; + } + else + { + /* save relative profile id's for later check */ + p_Scheme->nextRelativePlcrProfile = TRUE; + p_Scheme->relativeProfileId = profileId; + p_Scheme->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_SchemeParams->bypassFqidGeneration && p_SchemeParams->numOfUsedExtractedOrs) + RETURN_ERROR(MAJOR, E_INVALID_STATE, + ("numOfUsedExtractedOrs is set in a scheme that does not generate FQID or policer profile ID")); + if (p_SchemeParams->bypassFqidGeneration && + p_SchemeParams->useHash && + p_SchemeParams->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_SchemeParams->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_SchemeParams->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_SchemeParams->kgNextEngineParams.cc.plcrNext) + { + if (!p_SchemeParams->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; + } + } + } + break; + case (e_FM_PCD_DONE): + if (p_SchemeParams->kgNextEngineParams.doneAction == e_FM_PCD_DROP_FRAME) + tmpReg |= GET_NIA_BMI_AC_DISCARD_FRAME(p_FmPcd); + else + tmpReg |= GET_NIA_BMI_AC_ENQ_FRAME(p_FmPcd); + break; + default: + RETURN_ERROR(MAJOR, E_NOT_SUPPORTED, ("Next engine not supported")); + } + p_SchemeRegs->kgse_mode = tmpReg; + + p_SchemeRegs->kgse_mv = p_Scheme->matchVector; + +#if (DPAA_VERSION >= 11) + if (p_SchemeParams->overrideStorageProfile) + { + p_SchemeRegs->kgse_om |= KG_SCH_OM_VSPE; + + if (p_SchemeParams->storageProfile.direct) + { + profileId = p_SchemeParams->storageProfile.profileSelect.directRelativeProfileId; + shift = 0; + numOfProfiles = 1; + } + else + { + profileId = p_SchemeParams->storageProfile.profileSelect.indirectProfile.fqidOffsetRelativeProfileIdBase; + shift = p_SchemeParams->storageProfile.profileSelect.indirectProfile.fqidOffsetShift; + numOfProfiles = p_SchemeParams->storageProfile.profileSelect.indirectProfile.numOfProfiles; + } + if (shift > MAX_SP_SHIFT) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("fqidOffsetShift may not be larger than %d", MAX_SP_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")); + + tmpReg = (uint32_t)shift << KG_SCH_VSP_SHIFT; + tmpReg |= ((uint32_t)(numOfProfiles-1) << KG_SCH_VSP_MASK_SHIFT); + tmpReg |= (uint32_t)profileId; + + + p_SchemeRegs->kgse_vsp = tmpReg; + + p_Scheme->vspe = TRUE; + + } + else + p_SchemeRegs->kgse_vsp = KG_SCH_VSP_NO_KSP_EN; +#endif /* (DPAA_VERSION >= 11) */ + + if (p_SchemeParams->useHash) + { + p_KeyAndHash = &p_SchemeParams->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_SchemeParams->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_SchemeParams->baseFqid) + DBG(WARNING, ("baseFqid unaligned. Distribution may result in less than hashDistributionNumOfFqids queues.")); + } + + /* configure kgse_ekdv */ + tmpReg = 0; + for ( i=0 ;i<p_KeyAndHash->numOfUsedDflts ; 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 ;i<p_KeyAndHash->numOfUsedExtracts ; 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) + { +#if (DPAA_VERSION >= 11) || ((DPAA_VERSION == 10) && defined(FM_CAPWAP_SUPPORT)) + case (HEADER_TYPE_UDP_LITE): + p_Extract->extractByHdr.hdr = HEADER_TYPE_UDP; + break; +#endif /* (DPAA_VERSION >= 11) || ((DPAA_VERSION == 10) && defined(FM_CAPWAP_SUPPORT)) */ + 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_Scheme->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_Scheme->netEnvId, HEADER_TYPE_UDP_ENCAP_ESP); + /*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_Scheme->netEnvId, HEADER_TYPE_UDP_ENCAP_ESP); + 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_Scheme->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_Scheme->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_FmPcd, 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 */ + XX_Free(p_LocalExtractsArray); + RETURN_ERROR(MAJOR, E_NOT_SUPPORTED, ("Full header selection not supported")); + } + break; + default: + XX_Free(p_LocalExtractsArray); + 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_KG_NUM_OF_GENERIC_REGS) + { + XX_Free(p_LocalExtractsArray); + RETURN_ERROR(MAJOR, E_FULL, ("Generic registers are fully used")); + } + if (!code) + { + XX_Free(p_LocalExtractsArray); + 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)) + { + XX_Free(p_LocalExtractsArray); + 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")); + else + 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) + { + XX_Free(p_LocalExtractsArray); + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("Only %d masks supported", FM_PCD_KG_NUM_OF_EXTRACT_MASKS)); + } + for ( i=0 ;i<p_KeyAndHash->numOfUsedMasks ; 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) + { + XX_Free(p_LocalExtractsArray); + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("hashShift must not be larger than %d", MAX_HASH_SHIFT)); + } + if (p_KeyAndHash->hashDistributionFqidsShift > MAX_DIST_FQID_SHIFT) + { + XX_Free(p_LocalExtractsArray); + 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))) + { + XX_Free(p_LocalExtractsArray); + 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;i<p_KeyAndHash->numOfUsedExtracts ; 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_Scheme->orderedArray[j-1]].id)) + { + p_Scheme->orderedArray[j] = + p_Scheme->orderedArray[j-1]; + j--; + } + p_Scheme->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_Scheme->orderedArray[idx]= (uint8_t)i; + } + } + XX_Free(p_LocalExtractsArray); + } + 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_SchemeParams->bypassFqidGeneration) + p_SchemeRegs->kgse_hc |= KG_SCH_HASH_CONFIG_NO_FQID; + + /* configure kgse_spc */ + if ( p_SchemeParams->schemeCounter.update) + p_SchemeRegs->kgse_spc = p_SchemeParams->schemeCounter.value; + + + /* check that are enough generic registers */ + if (p_SchemeParams->numOfUsedExtractedOrs + currGenId > FM_KG_NUM_OF_GENERIC_REGS) + RETURN_ERROR(MAJOR, E_FULL, ("Generic registers are fully used")); + + /* extracted OR mask on Qid */ + for ( i=0 ;i<p_SchemeParams->numOfUsedExtractedOrs ; i++) + { + + p_Scheme->extractedOrs = TRUE; + /* configure kgse_gec[i] */ + p_ExtractOr = &p_SchemeParams->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_Scheme->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 ;i<FM_KG_NUM_OF_GENERIC_REGS ; i++) + p_SchemeRegs->kgse_gec[i] = 0; + + /* add base Qid for this scheme */ + /* add configuration for kgse_fqb */ + if (p_SchemeParams->baseFqid & ~0x00FFFFFF) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("baseFqid must be between 1 and 2^24-1")); + + fqbTmp |= p_SchemeParams->baseFqid; + p_SchemeRegs->kgse_fqb = fqbTmp; + + p_Scheme->nextEngine = p_SchemeParams->nextEngine; + p_Scheme->doneAction = p_SchemeParams->kgNextEngineParams.doneAction; + + return E_OK; +} + + +/*****************************************************************************/ +/* Inter-module API routines */ +/*****************************************************************************/ + +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; + int i, j; + + /* this routine is protected by the calling routine ! */ + 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.")); + + /* find a new clsPlan group */ + for (i = 0; i < FM_MAX_NUM_OF_PORTS; i++) + if (!p_FmPcd->p_FmPcdKg->clsPlanGrps[i].used) + break; + if (i == FM_MAX_NUM_OF_PORTS) + 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; + + 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); + if (p_Grp->numOfOptions != 0) + FmPcdIncNetEnvOwners(p_FmPcd, p_Grp->netEnvId); + + p_ClsPlanGrp->sizeOfGrp = (uint16_t)(1 << p_Grp->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) + 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) + RETURN_ERROR(MAJOR, err, NO_MSG); + + if (replyLength != (sizeof(uint32_t) + sizeof(p_ClsPlanGrp->baseEntry))) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("IPC reply length mismatch")); + if ((t_Error)reply.error != E_OK) + 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; i<p_Grp->numOfOptions; 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; j<p_ClsPlanGrp->sizeOfGrp; j++) + p_ClsPlanSet->vectors[j] = ~oredVectors; + + for (i = 0; i<p_Grp->numOfOptions; 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; j<p_ClsPlanGrp->sizeOfGrp; j++) + { + if (j & (1<<i)) + p_ClsPlanSet->vectors[j] |= p_Grp->optVectors[i]; + } + } + + 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; + } + + FmPcdSetClsPlanGrpId(p_FmPcd, p_FmPcd->p_FmPcdKg->clsPlanGrps[grpId].netEnvId, ILLEGAL_CLS_PLAN); + + if (grpId == p_FmPcd->p_FmPcdKg->emptyClsPlanGrpId) + p_FmPcd->p_FmPcdKg->emptyClsPlanGrpId = ILLEGAL_CLS_PLAN; + else + 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); + err = XX_IpcSendMessage(p_FmPcd->h_IpcSession, + (uint8_t*)&msg, + sizeof(msg.msgId) + sizeof(kgAlloc), + (uint8_t*)&reply, + &replyLength, + NULL, + NULL); + if (err != 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; + } + } + + /* 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; i<p_BindPort->numOfSchemes; 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) + { + p_Scheme = &p_FmPcd->p_FmPcdKg->schemes[relativeSchemeId]; + if (!FmPcdKgIsSchemeValidSw(p_Scheme)) + RETURN_ERROR(MAJOR, E_INVALID_STATE, ("Requested scheme is invalid.")); + /* 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;j<p_Scheme->numOfProfiles;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) + { + /* This check may be redundant as port is a assigned to the whole NetEnv */ + + /* 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) + { + uint8_t netEnvId; + walking1Mask = 0x80000000; + netEnvId = (p_Scheme->netEnvId == ILLEGAL_NETENV)? p_BindPort->netEnvId:p_Scheme->netEnvId; + 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, 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; +} + +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); + + IncSchemeOwners(p_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(p_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); + + DecSchemeOwners(p_FmPcd, p_SchemeBind); + + return E_OK; +} + +bool FmPcdKgIsSchemeValidSw(t_Handle h_Scheme) +{ + t_FmPcdKgScheme *p_Scheme = (t_FmPcdKgScheme*)h_Scheme; + + return p_Scheme->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; + uint8_t i, j; + + SANITY_CHECK_RETURN_ERROR(p_FmPcd, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_FmPcd->p_FmPcdKg, E_INVALID_HANDLE); + + /* This routine is issued only on master core of master partition - + either directly or through IPC, so no need for lock */ + + for (j = 0, i = 0; i < FM_PCD_KG_NUM_OF_SCHEMES && j < numOfSchemes; i++) + { + if (!p_FmPcd->p_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; + } + + RETURN_ERROR(MAJOR, E_NOT_AVAILABLE, ("No schemes found")); + } + + 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; + uint8_t i; + + SANITY_CHECK_RETURN_ERROR(p_FmPcd, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_FmPcd->p_FmPcdKg, E_INVALID_HANDLE); + + /* This routine is issued only on master core of master partition - + either directly or through IPC */ + + for (i = 0; i < numOfSchemes; i++) + { + if (!p_FmPcd->p_FmPcdKg->schemesMng[p_SchemesIds[i]].allocated) + { + RETURN_ERROR(MAJOR, E_INVALID_STATE, ("Scheme was not previously allocated")); + } + if (p_FmPcd->p_FmPcdKg->schemesMng[p_SchemesIds[i]].ownerId != guestId) + { + 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; + } + + 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; + uint8_t numOfBlocks, blocksFound=0, first=0; + uint8_t i, j; + + /* This routine is issued only on master core of master partition - + either directly or through IPC, so no need for lock */ + + if (!numOfClsPlanEntries) + return E_OK; + + if ((numOfClsPlanEntries % CLS_PLAN_NUM_PER_GRP) || (!POWER_OF_2(numOfClsPlanEntries))) + 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; i < FM_PCD_MAX_NUM_OF_CLS_PLANS/CLS_PLAN_NUM_PER_GRP;) + { + if (!p_FmPcd->p_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; j < (first + numOfBlocks); j++) + { + p_FmPcd->p_FmPcdKg->clsPlanBlocksMng[j].allocated = TRUE; + p_FmPcd->p_FmPcdKg->clsPlanBlocksMng[j].ownerId = guestId; + } + return E_OK; + } + else + RETURN_ERROR(MINOR, E_FULL, ("No resources 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; + uint8_t numOfBlocks; + uint8_t i, baseBlock; + +#ifdef DISABLE_ASSERTIONS +UNUSED(guestId); +#endif /* DISABLE_ASSERTIONS */ + + /* This routine is issued only on master core of master partition - + either directly or through IPC, so no need for lock */ + + 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;i<baseBlock+numOfBlocks;i++) + { + ASSERT_COND(p_FmPcd->p_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; + } +} + +void KgEnable(t_FmPcd *p_FmPcd) +{ + struct fman_kg_regs *p_Regs = p_FmPcd->p_FmPcdKg->p_FmPcdKgRegs; + + ASSERT_COND(FmIsMaster(p_FmPcd->h_Fm)); + fman_kg_enable(p_Regs); +} + +void KgDisable(t_FmPcd *p_FmPcd) +{ + struct fman_kg_regs *p_Regs = p_FmPcd->p_FmPcdKg->p_FmPcdKgRegs; + + ASSERT_COND(FmIsMaster(p_FmPcd->h_Fm)); + fman_kg_disable(p_Regs); +} + +void KgSetClsPlan(t_Handle h_FmPcd, t_FmPcdKgInterModuleClsPlanSet *p_Set) +{ + t_FmPcd *p_FmPcd = (t_FmPcd *)h_FmPcd; + struct fman_kg_cp_regs *p_FmPcdKgPortRegs; + uint32_t tmpKgarReg = 0, intFlags; + uint16_t i, j; + + /* This routine is protected by the calling routine ! */ + ASSERT_COND(FmIsMaster(p_FmPcd->h_Fm)); + p_FmPcdKgPortRegs = &p_FmPcd->p_FmPcdKg->p_IndirectAccessRegs->clsPlanRegs; + + intFlags = KgHwLock(p_FmPcd->p_FmPcdKg); + for (i=p_Set->baseEntry;i<p_Set->baseEntry+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")); + KgHwUnlock(p_FmPcd->p_FmPcdKg, intFlags); + return; + } + } + KgHwUnlock(p_FmPcd->p_FmPcdKg, intFlags); +} + +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 = (struct fman_kg_regs *)UINT_TO_PTR(FmGetPcdKgBaseAddr(p_FmPcdParams->h_Fm)); + p_FmPcd->exceptions |= DEFAULT_fmPcdKgErrorExceptions; + p_FmPcdKg->p_IndirectAccessRegs = (u_FmPcdKgIndirectAccessRegs *)&p_FmPcdKg->p_FmPcdKgRegs->fmkg_indirect[0]; + } + + 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) +{ + t_Error err = E_OK; + + p_FmPcd->p_FmPcdKg->h_HwSpinlock = XX_InitSpinlock(); + if (!p_FmPcd->p_FmPcdKg->h_HwSpinlock) + RETURN_ERROR(MAJOR, E_NO_MEMORY, ("FM KG HW spinlock")); + + if (p_FmPcd->guestId == NCSW_MASTER_ID) + err = KgInitMaster(p_FmPcd); + else + err = KgInitGuest(p_FmPcd); + + if (err != E_OK) + { + if (p_FmPcd->p_FmPcdKg->h_HwSpinlock) + XX_FreeSpinlock(p_FmPcd->p_FmPcdKg->h_HwSpinlock); + } + + return err; +} + +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) + { + err = FmPcdKgFreeSchemes(p_FmPcd, + p_FmPcd->p_FmPcdKg->numOfSchemes, + p_FmPcd->guestId, + p_FmPcd->p_FmPcdKg->schemesIds); + if (err) + RETURN_ERROR(MAJOR, err, NO_MSG); + + if (p_FmPcd->p_FmPcdKg->h_HwSpinlock) + XX_FreeSpinlock(p_FmPcd->p_FmPcdKg->h_HwSpinlock); + + return E_OK; + } + + /* 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")); + + if (p_FmPcd->p_FmPcdKg->h_HwSpinlock) + XX_FreeSpinlock(p_FmPcd->p_FmPcdKg->h_HwSpinlock); + + 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; + + /* This function is issued only from FM_PORT_SetPcd which locked all PCD modules, + so no need for lock here */ + + memset(&grpParams, 0, sizeof(grpParams)); + grpParams.clsPlanGrpId = ILLEGAL_CLS_PLAN; + p_GrpParams = &grpParams; + + p_GrpParams->netEnvId = netEnvId; + + /* Get from the NetEnv the information of the clsPlan (can be already created, + * or needs to build) */ + err = PcdGetClsPlanGrpParams(h_FmPcd, p_GrpParams); + if (err) + RETURN_ERROR(MINOR,err,NO_MSG); + + if (p_GrpParams->grpExists) + { + /* this group was already updated (at least) in SW */ + *p_ClsPlanGrpId = p_GrpParams->clsPlanGrpId; + } + else + { + p_ClsPlanSet = (t_FmPcdKgInterModuleClsPlanSet *)XX_Malloc(sizeof(t_FmPcdKgInterModuleClsPlanSet)); + if (!p_ClsPlanSet) + RETURN_ERROR(MAJOR, E_NO_MEMORY, ("Classification plan set")); + memset(p_ClsPlanSet, 0, sizeof(t_FmPcdKgInterModuleClsPlanSet)); + /* Build (in SW) the clsPlan parameters, including the vectors to be written to HW */ + 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); + } + + /* Set caller parameters */ + + /* 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 = BindPortToClsPlanGrp(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; + t_Error err; + + /* This function is issued only from FM_PORT_DeletePcd which locked all PCD modules, + so no need for lock here */ + + UnbindPortToClsPlanGrp(p_FmPcd, hardwarePortId); + + /* decrement owners number */ + ASSERT_COND(p_ClsPlanGrp->owners); + p_ClsPlanGrp->owners--; + + if (!p_ClsPlanGrp->owners) + { + if (p_FmPcd->h_Hc) + { + err = FmHcPcdKgDeleteClsPlan(p_FmPcd->h_Hc, clsPlanGrpId); + return err; + } + else + { + /* clear clsPlan entries in memory */ + p_ClsPlanSet = (t_FmPcdKgInterModuleClsPlanSet *)XX_Malloc(sizeof(t_FmPcdKgInterModuleClsPlanSet)); + if (!p_ClsPlanSet) + { + RETURN_ERROR(MAJOR, E_NO_MEMORY, ("Classification plan set")); + } + 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; +} + +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 FmPcdKgGetRequiredActionFlag(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].requiredActionFlag; +} + +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; + +} + +e_FmPcdEngine FmPcdKgGetNextEngine(t_Handle h_FmPcd, uint8_t relativeSchemeId) +{ + t_FmPcd *p_FmPcd = (t_FmPcd*)h_FmPcd; + + ASSERT_COND(p_FmPcd->p_FmPcdKg->schemes[relativeSchemeId].valid); + + return p_FmPcd->p_FmPcdKg->schemes[relativeSchemeId].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_Scheme, uint32_t requiredAction) +{ + t_FmPcdKgScheme *p_Scheme = (t_FmPcdKgScheme *)h_Scheme; + + /* this routine is protected by calling routine */ + + ASSERT_COND(p_Scheme->valid); + + p_Scheme->requiredAction |= requiredAction; +} + +bool FmPcdKgHwSchemeIsValid(uint32_t schemeModeReg) +{ + return (bool)!!(schemeModeReg & KG_SCH_MODE_EN); +} + +uint32_t FmPcdKgBuildWriteSchemeActionReg(uint8_t schemeId, bool updateCounter) +{ + return (uint32_t)(((uint32_t)schemeId << FM_PCD_KG_KGAR_NUM_SHIFT) | + FM_KG_KGAR_GO | + FM_KG_KGAR_WRITE | + FM_KG_KGAR_SEL_SCHEME_ENTRY | + DUMMY_PORT_ID | + (updateCounter ? FM_KG_KGAR_SCM_WSEL_UPDATE_CNT:0)); +} + +uint32_t FmPcdKgBuildReadSchemeActionReg(uint8_t schemeId) +{ + return (uint32_t)(((uint32_t)schemeId << FM_PCD_KG_KGAR_NUM_SHIFT) | + FM_KG_KGAR_GO | + FM_KG_KGAR_READ | + FM_KG_KGAR_SEL_SCHEME_ENTRY | + DUMMY_PORT_ID | + FM_KG_KGAR_SCM_WSEL_UPDATE_CNT); + +} + +uint32_t FmPcdKgBuildWriteClsPlanBlockActionReg(uint8_t grpId) +{ + return (uint32_t)(FM_KG_KGAR_GO | + FM_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 FmPcdKgBuildWritePortSchemeBindActionReg(uint8_t hardwarePortId) +{ + + return (uint32_t)(FM_KG_KGAR_GO | + FM_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_KG_KGAR_GO | + FM_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_KG_KGAR_GO | + FM_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 FmPcdKgGetSchemeId(t_Handle h_Scheme) +{ + return ((t_FmPcdKgScheme*)h_Scheme)->schemeId; + +} + +#if (DPAA_VERSION >= 11) +bool FmPcdKgGetVspe(t_Handle h_Scheme) +{ + return ((t_FmPcdKgScheme*)h_Scheme)->vspe; + +} +#endif /* (DPAA_VERSION >= 11) */ + +uint8_t FmPcdKgGetRelativeSchemeId(t_Handle h_FmPcd, uint8_t schemeId) +{ + t_FmPcd *p_FmPcd = (t_FmPcd*)h_FmPcd; + uint8_t i; + + for (i = 0;i<p_FmPcd->p_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_Handle FmPcdKgGetSchemeHandle(t_Handle h_FmPcd, uint8_t relativeSchemeId) +{ + t_FmPcd *p_FmPcd = (t_FmPcd*)h_FmPcd; + + ASSERT_COND(p_FmPcd); + + /* check that schemeId is in range */ + if (relativeSchemeId >= p_FmPcd->p_FmPcdKg->numOfSchemes) + { + REPORT_ERROR(MAJOR, E_NOT_IN_RANGE, ("relative-scheme-id %d!", relativeSchemeId)); + return NULL; + } + + if (!FmPcdKgIsSchemeValidSw(&p_FmPcd->p_FmPcdKg->schemes[relativeSchemeId])) + return NULL; + + return &p_FmPcd->p_FmPcdKg->schemes[relativeSchemeId]; +} + +bool FmPcdKgIsSchemeHasOwners(t_Handle h_Scheme) +{ + return (((t_FmPcdKgScheme*)h_Scheme)->owners == 0)?FALSE:TRUE; +} + +t_Error FmPcdKgCcGetSetParams(t_Handle h_FmPcd, t_Handle h_Scheme, uint32_t requiredAction, uint32_t value) +{ + t_FmPcd *p_FmPcd = (t_FmPcd*)h_FmPcd; + uint8_t relativeSchemeId, physicalSchemeId; + uint32_t tmpKgarReg, tmpReg32 = 0, intFlags; + t_Error err; + t_FmPcdKgScheme *p_Scheme = (t_FmPcdKgScheme*)h_Scheme; + + 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); + + /* Calling function locked all PCD modules, so no need to lock here */ + + if (!FmPcdKgIsSchemeValidSw(h_Scheme)) + RETURN_ERROR(MAJOR, E_ALREADY_EXISTS, ("Scheme is Invalid")); + + if (p_FmPcd->h_Hc) + { + err = FmHcPcdKgCcGetSetParams(p_FmPcd->h_Hc, h_Scheme, requiredAction, value); + + UpdateRequiredActionFlag(h_Scheme,TRUE); + FmPcdKgUpdateRequiredAction(h_Scheme,requiredAction); + return err; + } + + physicalSchemeId = p_Scheme->schemeId; + + relativeSchemeId = FmPcdKgGetRelativeSchemeId(p_FmPcd, physicalSchemeId); + if (relativeSchemeId >= FM_PCD_KG_NUM_OF_SCHEMES) + RETURN_ERROR(MAJOR, E_NOT_IN_RANGE, NO_MSG); + + if (!p_FmPcd->p_FmPcdKg->schemes[relativeSchemeId].requiredActionFlag || + !(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 = KgHwLock(p_FmPcd->p_FmPcdKg); + WriteKgarWait(p_FmPcd, tmpKgarReg); + tmpReg32 = GET_UINT32(p_FmPcd->p_FmPcdKg->p_IndirectAccessRegs->schemeRegs.kgse_mode); + ASSERT_COND(tmpReg32 & (NIA_ENG_BMI | NIA_BMI_AC_ENQ_FRAME)); + WRITE_UINT32(p_FmPcd->p_FmPcdKg->p_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); + KgHwUnlock(p_FmPcd->p_FmPcdKg, 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) + { + 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) + { + 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")); + } + } + if (requiredAction & UPDATE_KG_NIA_CC_WA) + { + if (p_FmPcd->p_FmPcdKg->schemes[relativeSchemeId].nextEngine == e_FM_PCD_CC) + { + tmpKgarReg = FmPcdKgBuildReadSchemeActionReg(physicalSchemeId); + intFlags = KgHwLock(p_FmPcd->p_FmPcdKg); + WriteKgarWait(p_FmPcd, tmpKgarReg); + tmpReg32 = GET_UINT32(p_FmPcd->p_FmPcdKg->p_IndirectAccessRegs->schemeRegs.kgse_mode); + ASSERT_COND(tmpReg32 & (NIA_ENG_FM_CTL | NIA_FM_CTL_AC_CC)); + tmpReg32 &= ~NIA_FM_CTL_AC_CC; + WRITE_UINT32(p_FmPcd->p_FmPcdKg->p_IndirectAccessRegs->schemeRegs.kgse_mode, tmpReg32 | NIA_FM_CTL_AC_PRE_CC); + /* call indirect command for scheme write */ + tmpKgarReg = FmPcdKgBuildWriteSchemeActionReg(physicalSchemeId, FALSE); + WriteKgarWait(p_FmPcd, tmpKgarReg); + KgHwUnlock(p_FmPcd->p_FmPcdKg, intFlags); + } + } + if (requiredAction & UPDATE_KG_OPT_MODE) + { + tmpKgarReg = FmPcdKgBuildReadSchemeActionReg(physicalSchemeId); + intFlags = KgHwLock(p_FmPcd->p_FmPcdKg); + WriteKgarWait(p_FmPcd, tmpKgarReg); + WRITE_UINT32(p_FmPcd->p_FmPcdKg->p_IndirectAccessRegs->schemeRegs.kgse_om, value); + /* call indirect command for scheme write */ + tmpKgarReg = FmPcdKgBuildWriteSchemeActionReg(physicalSchemeId, FALSE); + WriteKgarWait(p_FmPcd, tmpKgarReg); + KgHwUnlock(p_FmPcd->p_FmPcdKg, intFlags); + } + if (requiredAction & UPDATE_KG_NIA) + { + tmpKgarReg = FmPcdKgBuildReadSchemeActionReg(physicalSchemeId); + intFlags = KgHwLock(p_FmPcd->p_FmPcdKg); + WriteKgarWait(p_FmPcd, tmpKgarReg); + tmpReg32 = GET_UINT32(p_FmPcd->p_FmPcdKg->p_IndirectAccessRegs->schemeRegs.kgse_mode); + tmpReg32 &= ~(NIA_ENG_MASK | NIA_AC_MASK); + tmpReg32 |= value; + WRITE_UINT32(p_FmPcd->p_FmPcdKg->p_IndirectAccessRegs->schemeRegs.kgse_mode, tmpReg32); + /* call indirect command for scheme write */ + tmpKgarReg = FmPcdKgBuildWriteSchemeActionReg(physicalSchemeId, FALSE); + WriteKgarWait(p_FmPcd, tmpKgarReg); + KgHwUnlock(p_FmPcd->p_FmPcdKg, intFlags); + } + } + + UpdateRequiredActionFlag(h_Scheme, TRUE); + FmPcdKgUpdateRequiredAction(h_Scheme, requiredAction); + + return E_OK; +} +/*********************** End of inter-module routines ************************/ + + +/****************************************/ +/* API routines */ +/****************************************/ + +t_Handle FM_PCD_KgSchemeSet(t_Handle h_FmPcd, t_FmPcdKgSchemeParams *p_SchemeParams) +{ + t_FmPcd *p_FmPcd; + struct fman_kg_scheme_regs schemeRegs; + struct fman_kg_scheme_regs *p_MemRegs; + uint8_t i; + t_Error err = E_OK; + uint32_t tmpKgarReg; + uint32_t intFlags; + uint8_t physicalSchemeId, relativeSchemeId = 0; + t_FmPcdKgScheme *p_Scheme; + + if (p_SchemeParams->modify) + { + p_Scheme = (t_FmPcdKgScheme *)p_SchemeParams->id.h_Scheme; + p_FmPcd = p_Scheme->h_FmPcd; + + SANITY_CHECK_RETURN_VALUE(p_FmPcd, E_INVALID_HANDLE, NULL); + SANITY_CHECK_RETURN_VALUE(p_FmPcd->p_FmPcdKg, E_INVALID_HANDLE, NULL); + + if (!FmPcdKgIsSchemeValidSw(p_Scheme)) + { + REPORT_ERROR(MAJOR, E_ALREADY_EXISTS, + ("Scheme is invalid")); + return NULL; + } + + if (!KgSchemeFlagTryLock(p_Scheme)) + { + DBG(TRACE, ("Scheme Try Lock - BUSY")); + /* Signal to caller BUSY condition */ + p_SchemeParams->id.h_Scheme = NULL; + return NULL; + } + } + else + { + p_FmPcd = (t_FmPcd*)h_FmPcd; + + SANITY_CHECK_RETURN_VALUE(p_FmPcd, E_INVALID_HANDLE, NULL); + SANITY_CHECK_RETURN_VALUE(p_FmPcd->p_FmPcdKg, E_INVALID_HANDLE, NULL); + + relativeSchemeId = p_SchemeParams->id.relativeSchemeId; + /* check that schemeId is in range */ + if (relativeSchemeId >= p_FmPcd->p_FmPcdKg->numOfSchemes) + { + REPORT_ERROR(MAJOR, E_NOT_IN_RANGE, ("relative-scheme-id %d!", relativeSchemeId)); + return NULL; + } + + p_Scheme = &p_FmPcd->p_FmPcdKg->schemes[relativeSchemeId]; + if (FmPcdKgIsSchemeValidSw(p_Scheme)) + { + REPORT_ERROR(MAJOR, E_ALREADY_EXISTS, + ("Scheme id (%d)!", relativeSchemeId)); + return NULL; + } + /* Clear all fields, scheme may have beed previously used */ + memset(p_Scheme, 0, sizeof(t_FmPcdKgScheme)); + + p_Scheme->schemeId = p_FmPcd->p_FmPcdKg->schemesIds[relativeSchemeId]; + p_Scheme->h_FmPcd = p_FmPcd; + + p_Scheme->p_Lock = FmPcdAcquireLock(p_FmPcd); + if (!p_Scheme->p_Lock) + REPORT_ERROR(MAJOR, E_NOT_AVAILABLE, ("FM KG Scheme lock obj!")); + } + + err = BuildSchemeRegs((t_Handle)p_Scheme, p_SchemeParams, &schemeRegs); + if (err) + { + REPORT_ERROR(MAJOR, err, NO_MSG); + if (p_SchemeParams->modify) + KgSchemeFlagUnlock(p_Scheme); + if (!p_SchemeParams->modify && + p_Scheme->p_Lock) + FmPcdReleaseLock(p_FmPcd, p_Scheme->p_Lock); + return NULL; + } + + if (p_FmPcd->h_Hc) + { + err = FmHcPcdKgSetScheme(p_FmPcd->h_Hc, + (t_Handle)p_Scheme, + &schemeRegs, + p_SchemeParams->schemeCounter.update); + if (p_SchemeParams->modify) + KgSchemeFlagUnlock(p_Scheme); + if (err) + { + if (!p_SchemeParams->modify && + p_Scheme->p_Lock) + FmPcdReleaseLock(p_FmPcd, p_Scheme->p_Lock); + return NULL; + } + if (!p_SchemeParams->modify) + ValidateSchemeSw(p_Scheme); + return (t_Handle)p_Scheme; + } + + physicalSchemeId = p_Scheme->schemeId; + + /* configure all 21 scheme registers */ + p_MemRegs = &p_FmPcd->p_FmPcdKg->p_IndirectAccessRegs->schemeRegs; + intFlags = KgHwLock(p_FmPcd->p_FmPcdKg); + 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); + WRITE_UINT32(p_MemRegs->kgse_om, schemeRegs.kgse_om); + WRITE_UINT32(p_MemRegs->kgse_vsp, schemeRegs.kgse_vsp); + for (i=0 ; i<FM_KG_NUM_OF_GENERIC_REGS ; i++) + WRITE_UINT32(p_MemRegs->kgse_gec[i], schemeRegs.kgse_gec[i]); + + /* call indirect command for scheme write */ + tmpKgarReg = FmPcdKgBuildWriteSchemeActionReg(physicalSchemeId, p_SchemeParams->schemeCounter.update); + + WriteKgarWait(p_FmPcd, tmpKgarReg); + KgHwUnlock(p_FmPcd->p_FmPcdKg, intFlags); + + if (!p_SchemeParams->modify) + ValidateSchemeSw(p_Scheme); + else + KgSchemeFlagUnlock(p_Scheme); + + return (t_Handle)p_Scheme; +} + +t_Error FM_PCD_KgSchemeDelete(t_Handle h_Scheme) +{ + t_FmPcd *p_FmPcd; + uint8_t physicalSchemeId; + uint32_t tmpKgarReg, intFlags; + t_Error err = E_OK; + t_FmPcdKgScheme *p_Scheme = (t_FmPcdKgScheme *)h_Scheme; + + SANITY_CHECK_RETURN_ERROR(h_Scheme, E_INVALID_HANDLE); + + p_FmPcd = (t_FmPcd*)(p_Scheme->h_FmPcd); + + UpdateRequiredActionFlag(h_Scheme, FALSE); + + /* check that no port is bound to this scheme */ + err = InvalidateSchemeSw(h_Scheme); + if (err) + RETURN_ERROR(MINOR, err, NO_MSG); + + if (p_FmPcd->h_Hc) + { + err = FmHcPcdKgDeleteScheme(p_FmPcd->h_Hc, h_Scheme); + if (p_Scheme->p_Lock) + FmPcdReleaseLock(p_FmPcd, p_Scheme->p_Lock); + return err; + } + + physicalSchemeId = ((t_FmPcdKgScheme *)h_Scheme)->schemeId; + + intFlags = KgHwLock(p_FmPcd->p_FmPcdKg); + /* clear mode register, including enable bit */ + WRITE_UINT32(p_FmPcd->p_FmPcdKg->p_IndirectAccessRegs->schemeRegs.kgse_mode, 0); + + /* call indirect command for scheme write */ + tmpKgarReg = FmPcdKgBuildWriteSchemeActionReg(physicalSchemeId, FALSE); + + WriteKgarWait(p_FmPcd, tmpKgarReg); + KgHwUnlock(p_FmPcd->p_FmPcdKg, intFlags); + + if (p_Scheme->p_Lock) + FmPcdReleaseLock(p_FmPcd, p_Scheme->p_Lock); + + return E_OK; +} + +uint32_t FM_PCD_KgSchemeGetCounter(t_Handle h_Scheme) +{ + t_FmPcd *p_FmPcd; + uint32_t tmpKgarReg, spc, intFlags; + uint8_t physicalSchemeId; + + SANITY_CHECK_RETURN_VALUE(h_Scheme, E_INVALID_HANDLE, 0); + + p_FmPcd = (t_FmPcd*)(((t_FmPcdKgScheme *)h_Scheme)->h_FmPcd); + if (p_FmPcd->h_Hc) + return FmHcPcdKgGetSchemeCounter(p_FmPcd->h_Hc, h_Scheme); + + physicalSchemeId = ((t_FmPcdKgScheme *)h_Scheme)->schemeId; + + if (FmPcdKgGetRelativeSchemeId(p_FmPcd, physicalSchemeId) == FM_PCD_KG_NUM_OF_SCHEMES) + REPORT_ERROR(MAJOR, E_NOT_IN_RANGE, NO_MSG); + + tmpKgarReg = FmPcdKgBuildReadSchemeActionReg(physicalSchemeId); + intFlags = KgHwLock(p_FmPcd->p_FmPcdKg); + WriteKgarWait(p_FmPcd, tmpKgarReg); + if (!(GET_UINT32(p_FmPcd->p_FmPcdKg->p_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_IndirectAccessRegs->schemeRegs.kgse_spc); + KgHwUnlock(p_FmPcd->p_FmPcdKg, intFlags); + + return spc; +} + +t_Error FM_PCD_KgSchemeSetCounter(t_Handle h_Scheme, uint32_t value) +{ + t_FmPcd *p_FmPcd; + uint32_t tmpKgarReg, intFlags; + uint8_t physicalSchemeId; + + SANITY_CHECK_RETURN_VALUE(h_Scheme, E_INVALID_HANDLE, 0); + + p_FmPcd = (t_FmPcd*)(((t_FmPcdKgScheme *)h_Scheme)->h_FmPcd); + + if (!FmPcdKgIsSchemeValidSw(h_Scheme)) + RETURN_ERROR(MAJOR, E_INVALID_STATE, ("Requested scheme is invalid.")); + + if (p_FmPcd->h_Hc) + return FmHcPcdKgSetSchemeCounter(p_FmPcd->h_Hc, h_Scheme, value); + + physicalSchemeId = ((t_FmPcdKgScheme *)h_Scheme)->schemeId; + /* 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 = KgHwLock(p_FmPcd->p_FmPcdKg); + WriteKgarWait(p_FmPcd, tmpKgarReg); + if (!(GET_UINT32(p_FmPcd->p_FmPcdKg->p_IndirectAccessRegs->schemeRegs.kgse_mode) & KG_SCH_MODE_EN)) + { + KgHwUnlock(p_FmPcd->p_FmPcdKg, intFlags); + RETURN_ERROR(MAJOR, E_ALREADY_EXISTS, ("Scheme is Invalid")); + } + + /* change counter value */ + WRITE_UINT32(p_FmPcd->p_FmPcdKg->p_IndirectAccessRegs->schemeRegs.kgse_spc, value); + + /* call indirect command for scheme write */ + tmpKgarReg = FmPcdKgBuildWriteSchemeActionReg(physicalSchemeId, TRUE); + + WriteKgarWait(p_FmPcd, tmpKgarReg); + KgHwUnlock(p_FmPcd->p_FmPcdKg, intFlags); + + return E_OK; +} + +t_Error FM_PCD_KgSetAdditionalDataAfterParsing(t_Handle h_FmPcd, uint8_t payloadOffset) +{ + t_FmPcd *p_FmPcd = (t_FmPcd*)h_FmPcd; + struct fman_kg_regs *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!")); + + WRITE_UINT32(p_Regs->fmkg_fdor,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; + struct fman_kg_regs *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->fmkg_gdv0r,value); + else + WRITE_UINT32(p_Regs->fmkg_gdv1r,value); + return E_OK; +} diff --git a/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Pcd/fm_kg.h b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Pcd/fm_kg.h new file mode 100644 index 000000000000..cb7521a11397 --- /dev/null +++ b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Pcd/fm_kg.h @@ -0,0 +1,206 @@ +/* + * Copyright 2008-2012 Freescale Semiconductor Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Freescale Semiconductor nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * + * ALTERNATIVELY, this software may be distributed under the terms of the + * GNU General Public License ("GPL") as published by the Free Software + * Foundation, either version 2 of that License or (at your option) any + * later version. + * + * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + +/****************************************************************************** + @File fm_kg.h + + @Description FM KG private header +*//***************************************************************************/ +#ifndef __FM_KG_H +#define __FM_KG_H + +#include "std_ext.h" + +/***********************************************************************/ +/* Keygen defines */ +/***********************************************************************/ +/* maskes */ +#if (DPAA_VERSION >= 11) +#define KG_SCH_VSP_SHIFT_MASK 0x0003f000 +#define KG_SCH_OM_VSPE 0x00000001 +#define KG_SCH_VSP_NO_KSP_EN 0x80000000 + +#define MAX_SP_SHIFT 23 +#define KG_SCH_VSP_MASK_SHIFT 12 +#define KG_SCH_VSP_SHIFT 24 +#endif /* (DPAA_VERSION >= 11) */ + +typedef uint32_t t_KnownFieldsMasks; +#define KG_SCH_KN_PORT_ID 0x80000000 +#define KG_SCH_KN_MACDST 0x40000000 +#define KG_SCH_KN_MACSRC 0x20000000 +#define KG_SCH_KN_TCI1 0x10000000 +#define KG_SCH_KN_TCI2 0x08000000 +#define KG_SCH_KN_ETYPE 0x04000000 +#define KG_SCH_KN_PPPSID 0x02000000 +#define KG_SCH_KN_PPPID 0x01000000 +#define KG_SCH_KN_MPLS1 0x00800000 +#define KG_SCH_KN_MPLS2 0x00400000 +#define KG_SCH_KN_MPLS_LAST 0x00200000 +#define KG_SCH_KN_IPSRC1 0x00100000 +#define KG_SCH_KN_IPDST1 0x00080000 +#define KG_SCH_KN_PTYPE1 0x00040000 +#define KG_SCH_KN_IPTOS_TC1 0x00020000 +#define KG_SCH_KN_IPV6FL1 0x00010000 +#define KG_SCH_KN_IPSRC2 0x00008000 +#define KG_SCH_KN_IPDST2 0x00004000 +#define KG_SCH_KN_PTYPE2 0x00002000 +#define KG_SCH_KN_IPTOS_TC2 0x00001000 +#define KG_SCH_KN_IPV6FL2 0x00000800 +#define KG_SCH_KN_GREPTYPE 0x00000400 +#define KG_SCH_KN_IPSEC_SPI 0x00000200 +#define KG_SCH_KN_IPSEC_NH 0x00000100 +#define KG_SCH_KN_IPPID 0x00000080 +#define KG_SCH_KN_L4PSRC 0x00000004 +#define KG_SCH_KN_L4PDST 0x00000002 +#define KG_SCH_KN_TFLG 0x00000001 + +typedef uint8_t t_GenericCodes; +#define KG_SCH_GEN_SHIM1 0x70 +#define KG_SCH_GEN_DEFAULT 0x10 +#define KG_SCH_GEN_PARSE_RESULT_N_FQID 0x20 +#define KG_SCH_GEN_START_OF_FRM 0x40 +#define KG_SCH_GEN_SHIM2 0x71 +#define KG_SCH_GEN_IP_PID_NO_V 0x72 +#define KG_SCH_GEN_ETH 0x03 +#define KG_SCH_GEN_ETH_NO_V 0x73 +#define KG_SCH_GEN_SNAP 0x04 +#define KG_SCH_GEN_SNAP_NO_V 0x74 +#define KG_SCH_GEN_VLAN1 0x05 +#define KG_SCH_GEN_VLAN1_NO_V 0x75 +#define KG_SCH_GEN_VLAN2 0x06 +#define KG_SCH_GEN_VLAN2_NO_V 0x76 +#define KG_SCH_GEN_ETH_TYPE 0x07 +#define KG_SCH_GEN_ETH_TYPE_NO_V 0x77 +#define KG_SCH_GEN_PPP 0x08 +#define KG_SCH_GEN_PPP_NO_V 0x78 +#define KG_SCH_GEN_MPLS1 0x09 +#define KG_SCH_GEN_MPLS2 0x19 +#define KG_SCH_GEN_MPLS3 0x29 +#define KG_SCH_GEN_MPLS1_NO_V 0x79 +#define KG_SCH_GEN_MPLS_LAST 0x0a +#define KG_SCH_GEN_MPLS_LAST_NO_V 0x7a +#define KG_SCH_GEN_IPV4 0x0b +#define KG_SCH_GEN_IPV6 0x1b +#define KG_SCH_GEN_L3_NO_V 0x7b +#define KG_SCH_GEN_IPV4_TUNNELED 0x0c +#define KG_SCH_GEN_IPV6_TUNNELED 0x1c +#define KG_SCH_GEN_MIN_ENCAP 0x2c +#define KG_SCH_GEN_IP2_NO_V 0x7c +#define KG_SCH_GEN_GRE 0x0d +#define KG_SCH_GEN_GRE_NO_V 0x7d +#define KG_SCH_GEN_TCP 0x0e +#define KG_SCH_GEN_UDP 0x1e +#define KG_SCH_GEN_IPSEC_AH 0x2e +#define KG_SCH_GEN_SCTP 0x3e +#define KG_SCH_GEN_DCCP 0x4e +#define KG_SCH_GEN_IPSEC_ESP 0x6e +#define KG_SCH_GEN_L4_NO_V 0x7e +#define KG_SCH_GEN_NEXTHDR 0x7f +/* shifts */ +#define KG_SCH_PP_SHIFT_HIGH_SHIFT 27 +#define KG_SCH_PP_SHIFT_LOW_SHIFT 12 +#define KG_SCH_PP_MASK_SHIFT 16 +#define KG_SCH_MODE_CCOBASE_SHIFT 24 +#define KG_SCH_DEF_MAC_ADDR_SHIFT 30 +#define KG_SCH_DEF_TCI_SHIFT 28 +#define KG_SCH_DEF_ENET_TYPE_SHIFT 26 +#define KG_SCH_DEF_PPP_SESSION_ID_SHIFT 24 +#define KG_SCH_DEF_PPP_PROTOCOL_ID_SHIFT 22 +#define KG_SCH_DEF_MPLS_LABEL_SHIFT 20 +#define KG_SCH_DEF_IP_ADDR_SHIFT 18 +#define KG_SCH_DEF_PROTOCOL_TYPE_SHIFT 16 +#define KG_SCH_DEF_IP_TOS_TC_SHIFT 14 +#define KG_SCH_DEF_IPV6_FLOW_LABEL_SHIFT 12 +#define KG_SCH_DEF_IPSEC_SPI_SHIFT 10 +#define KG_SCH_DEF_L4_PORT_SHIFT 8 +#define KG_SCH_DEF_TCP_FLAG_SHIFT 6 +#define KG_SCH_HASH_CONFIG_SHIFT_SHIFT 24 +#define KG_SCH_GEN_MASK_SHIFT 16 +#define KG_SCH_GEN_HT_SHIFT 8 +#define KG_SCH_GEN_SIZE_SHIFT 24 +#define KG_SCH_GEN_DEF_SHIFT 29 +#define FM_PCD_KG_KGAR_NUM_SHIFT 16 + +/* others */ +#define NUM_OF_SW_DEFAULTS 3 +#define MAX_PP_SHIFT 23 +#define MAX_KG_SCH_SIZE 16 +#define MASK_FOR_GENERIC_BASE_ID 0x20 +#define MAX_HASH_SHIFT 40 +#define MAX_KG_SCH_FQID_BIT_OFFSET 31 +#define MAX_KG_SCH_PP_BIT_OFFSET 15 +#define MAX_DIST_FQID_SHIFT 23 + +#define GET_MASK_SEL_SHIFT(shift,i) \ +switch (i) { \ + case (0):shift = 26;break; \ + case (1):shift = 20;break; \ + case (2):shift = 10;break; \ + case (3):shift = 4;break; \ + default: \ + RETURN_ERROR(MAJOR, E_INVALID_VALUE, NO_MSG); \ +} + +#define GET_MASK_OFFSET_SHIFT(shift,i) \ +switch (i) { \ + case (0):shift = 16;break; \ + case (1):shift = 0;break; \ + case (2):shift = 28;break; \ + case (3):shift = 24;break; \ + default: \ + RETURN_ERROR(MAJOR, E_INVALID_VALUE, NO_MSG); \ +} + +#define GET_MASK_SHIFT(shift,i) \ +switch (i) { \ + case (0):shift = 24;break; \ + case (1):shift = 16;break; \ + case (2):shift = 8;break; \ + case (3):shift = 0;break; \ + default: \ + RETURN_ERROR(MAJOR, E_INVALID_VALUE, NO_MSG); \ +} + +/***********************************************************************/ +/* Keygen defines */ +/***********************************************************************/ + +#define KG_DOUBLE_MEANING_REGS_OFFSET 0x100 +#define NO_VALIDATION 0x70 +#define KG_ACTION_REG_TO 1024 +#define KG_MAX_PROFILE 255 +#define SCHEME_ALWAYS_DIRECT 0xFFFFFFFF + + +#endif /* __FM_KG_H */ diff --git a/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Pcd/fm_manip.c b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Pcd/fm_manip.c new file mode 100644 index 000000000000..d79e8723a1c1 --- /dev/null +++ b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Pcd/fm_manip.c @@ -0,0 +1,5572 @@ +/* + * Copyright 2008-2012 Freescale Semiconductor Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Freescale Semiconductor nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * + * ALTERNATIVELY, this software may be distributed under the terms of the + * GNU General Public License ("GPL") as published by the Free Software + * Foundation, either version 2 of that License or (at your option) any + * later version. + * + * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + +/****************************************************************************** + @File fm_manip.c + + @Description FM PCD manip ... + *//***************************************************************************/ +#include "std_ext.h" +#include "error_ext.h" +#include "string_ext.h" +#include "debug_ext.h" +#include "fm_pcd_ext.h" +#include "fm_port_ext.h" +#include "fm_muram_ext.h" +#include "memcpy_ext.h" + +#include "fm_common.h" +#include "fm_hc.h" +#include "fm_manip.h" + +/****************************************/ +/* static functions */ +/****************************************/ +static t_Handle GetManipInfo(t_FmPcdManip *p_Manip, e_ManipInfo manipInfo) +{ + t_FmPcdManip *p_CurManip = p_Manip; + + if (!MANIP_IS_UNIFIED(p_Manip)) + p_CurManip = p_Manip; + else + { + /* go to first unified */ + while (MANIP_IS_UNIFIED_NON_FIRST(p_CurManip)) + p_CurManip = p_CurManip->h_PrevManip; + } + + switch (manipInfo) + { + case (e_MANIP_HMCT): + return p_CurManip->p_Hmct; + case (e_MANIP_HMTD): + return p_CurManip->h_Ad; + case (e_MANIP_HANDLER_TABLE_OWNER): + return (t_Handle)p_CurManip; + default: + return NULL; + } +} + +static uint16_t GetHmctSize(t_FmPcdManip *p_Manip) +{ + uint16_t size = 0; + t_FmPcdManip *p_CurManip = p_Manip; + + if (!MANIP_IS_UNIFIED(p_Manip)) + return p_Manip->tableSize; + + /* accumulate sizes, starting with the first node */ + while (MANIP_IS_UNIFIED_NON_FIRST(p_CurManip)) + p_CurManip = p_CurManip->h_PrevManip; + + while (MANIP_IS_UNIFIED_NON_LAST(p_CurManip)) + { + size += p_CurManip->tableSize; + p_CurManip = (t_FmPcdManip *)p_CurManip->h_NextManip; + } + size += p_CurManip->tableSize; /* add last size */ + + return (size); +} + +static uint16_t GetDataSize(t_FmPcdManip *p_Manip) +{ + uint16_t size = 0; + t_FmPcdManip *p_CurManip = p_Manip; + + if (!MANIP_IS_UNIFIED(p_Manip)) + return p_Manip->dataSize; + + /* accumulate sizes, starting with the first node */ + while (MANIP_IS_UNIFIED_NON_FIRST(p_CurManip)) + p_CurManip = p_CurManip->h_PrevManip; + + while (MANIP_IS_UNIFIED_NON_LAST(p_CurManip)) + { + size += p_CurManip->dataSize; + p_CurManip = (t_FmPcdManip *)p_CurManip->h_NextManip; + } + size += p_CurManip->dataSize; /* add last size */ + + return (size); +} + +static t_Error CalculateTableSize(t_FmPcdManipParams *p_FmPcdManipParams, + uint16_t *p_TableSize, uint8_t *p_DataSize) +{ + uint8_t localDataSize, remain, tableSize = 0, dataSize = 0; + + if (p_FmPcdManipParams->u.hdr.rmv) + { + switch (p_FmPcdManipParams->u.hdr.rmvParams.type) + { + case (e_FM_PCD_MANIP_RMV_GENERIC): + tableSize += HMCD_BASIC_SIZE; + break; + case (e_FM_PCD_MANIP_RMV_BY_HDR): + switch (p_FmPcdManipParams->u.hdr.rmvParams.u.byHdr.type) + { + case (e_FM_PCD_MANIP_RMV_BY_HDR_SPECIFIC_L2): +#if (DPAA_VERSION >= 11) + case (e_FM_PCD_MANIP_RMV_BY_HDR_CAPWAP): + case (e_FM_PCD_MANIP_RMV_BY_HDR_FROM_START): +#endif /* (DPAA_VERSION >= 11) */ + tableSize += HMCD_BASIC_SIZE; + break; + default: + RETURN_ERROR(MINOR, E_INVALID_SELECTION, + ("Unknown byHdr.type")); + } + break; + default: + RETURN_ERROR(MINOR, E_INVALID_SELECTION, + ("Unknown rmvParams.type")); + } + } + + if (p_FmPcdManipParams->u.hdr.insrt) + { + switch (p_FmPcdManipParams->u.hdr.insrtParams.type) + { + case (e_FM_PCD_MANIP_INSRT_GENERIC): + remain = + (uint8_t)(p_FmPcdManipParams->u.hdr.insrtParams.u.generic.size + % 4); + if (remain) + localDataSize = + (uint8_t)(p_FmPcdManipParams->u.hdr.insrtParams.u.generic.size + + 4 - remain); + else + localDataSize = + p_FmPcdManipParams->u.hdr.insrtParams.u.generic.size; + tableSize += (uint8_t)(HMCD_BASIC_SIZE + localDataSize); + break; + case (e_FM_PCD_MANIP_INSRT_BY_HDR): + { + switch (p_FmPcdManipParams->u.hdr.insrtParams.u.byHdr.type) + { + + case (e_FM_PCD_MANIP_INSRT_BY_HDR_SPECIFIC_L2): + tableSize += HMCD_BASIC_SIZE + HMCD_PTR_SIZE; + switch (p_FmPcdManipParams->u.hdr.insrtParams.u.byHdr.u.specificL2Params.specificL2) + { + case (e_FM_PCD_MANIP_HDR_INSRT_MPLS): + case (e_FM_PCD_MANIP_HDR_INSRT_PPPOE): + dataSize += + p_FmPcdManipParams->u.hdr.insrtParams.u.byHdr.u.specificL2Params.size; + break; + default: + RETURN_ERROR(MINOR, E_NOT_SUPPORTED, NO_MSG); + } + break; +#if (DPAA_VERSION >= 11) + case (e_FM_PCD_MANIP_INSRT_BY_HDR_IP): + tableSize += + (HMCD_BASIC_SIZE + HMCD_PTR_SIZE + + HMCD_PARAM_SIZE + + p_FmPcdManipParams->u.hdr.insrtParams.u.byHdr.u.ipParams.insrt.size); + dataSize += 2; + break; + + case (e_FM_PCD_MANIP_INSRT_BY_HDR_UDP): + case (e_FM_PCD_MANIP_INSRT_BY_HDR_UDP_LITE): + tableSize += (HMCD_BASIC_SIZE + HMCD_L4_HDR_SIZE); + + break; + + case (e_FM_PCD_MANIP_INSRT_BY_HDR_CAPWAP): + tableSize += + (HMCD_BASIC_SIZE + + p_FmPcdManipParams->u.hdr.insrtParams.u.byHdr.u.insrt.size); + break; +#endif /* (DPAA_VERSION >= 11) */ + default: + RETURN_ERROR(MINOR, E_INVALID_SELECTION, + ("Unknown byHdr.type")); + } + } + break; + default: + RETURN_ERROR(MINOR, E_INVALID_SELECTION, + ("Unknown insrtParams.type")); + } + } + + if (p_FmPcdManipParams->u.hdr.fieldUpdate) + { + switch (p_FmPcdManipParams->u.hdr.fieldUpdateParams.type) + { + case (e_FM_PCD_MANIP_HDR_FIELD_UPDATE_VLAN): + tableSize += HMCD_BASIC_SIZE; + if (p_FmPcdManipParams->u.hdr.fieldUpdateParams.u.vlan.updateType + == e_FM_PCD_MANIP_HDR_FIELD_UPDATE_DSCP_TO_VLAN) + { + tableSize += HMCD_PTR_SIZE; + dataSize += DSCP_TO_VLAN_TABLE_SIZE; + } + break; + case (e_FM_PCD_MANIP_HDR_FIELD_UPDATE_IPV4): + tableSize += HMCD_BASIC_SIZE; + if (p_FmPcdManipParams->u.hdr.fieldUpdateParams.u.ipv4.validUpdates + & HDR_MANIP_IPV4_ID) + { + tableSize += HMCD_PARAM_SIZE; + dataSize += 2; + } + if (p_FmPcdManipParams->u.hdr.fieldUpdateParams.u.ipv4.validUpdates + & HDR_MANIP_IPV4_SRC) + tableSize += HMCD_IPV4_ADDR_SIZE; + if (p_FmPcdManipParams->u.hdr.fieldUpdateParams.u.ipv4.validUpdates + & HDR_MANIP_IPV4_DST) + tableSize += HMCD_IPV4_ADDR_SIZE; + break; + case (e_FM_PCD_MANIP_HDR_FIELD_UPDATE_IPV6): + tableSize += HMCD_BASIC_SIZE; + if (p_FmPcdManipParams->u.hdr.fieldUpdateParams.u.ipv4.validUpdates + & HDR_MANIP_IPV6_SRC) + tableSize += HMCD_IPV6_ADDR_SIZE; + if (p_FmPcdManipParams->u.hdr.fieldUpdateParams.u.ipv4.validUpdates + & HDR_MANIP_IPV6_DST) + tableSize += HMCD_IPV6_ADDR_SIZE; + break; + case (e_FM_PCD_MANIP_HDR_FIELD_UPDATE_TCP_UDP): + if (p_FmPcdManipParams->u.hdr.fieldUpdateParams.u.tcpUdp.validUpdates + == HDR_MANIP_TCP_UDP_CHECKSUM) + /* we implement this case with the update-checksum descriptor */ + tableSize += HMCD_BASIC_SIZE; + else + /* we implement this case with the TCP/UDP-update descriptor */ + tableSize += HMCD_BASIC_SIZE + HMCD_PARAM_SIZE; + break; + default: + RETURN_ERROR(MINOR, E_INVALID_SELECTION, + ("Unknown fieldUpdateParams.type")); + } + } + + if (p_FmPcdManipParams->u.hdr.custom) + { + switch (p_FmPcdManipParams->u.hdr.customParams.type) + { + case (e_FM_PCD_MANIP_HDR_CUSTOM_IP_REPLACE): + { + tableSize += HMCD_BASIC_SIZE + HMCD_PARAM_SIZE + HMCD_PARAM_SIZE; + dataSize += + p_FmPcdManipParams->u.hdr.customParams.u.ipHdrReplace.hdrSize; + if ((p_FmPcdManipParams->u.hdr.customParams.u.ipHdrReplace.replaceType + == e_FM_PCD_MANIP_HDR_CUSTOM_REPLACE_IPV6_BY_IPV4) + && (p_FmPcdManipParams->u.hdr.customParams.u.ipHdrReplace.updateIpv4Id)) + dataSize += 2; + } + break; + case (e_FM_PCD_MANIP_HDR_CUSTOM_GEN_FIELD_REPLACE): + tableSize += HMCD_BASIC_SIZE + HMCD_PARAM_SIZE; + break; + default: + RETURN_ERROR(MINOR, E_INVALID_SELECTION, + ("Unknown customParams.type")); + } + } + + *p_TableSize = tableSize; + *p_DataSize = dataSize; + + return E_OK; +} + +static t_Error GetPrOffsetByHeaderOrField(t_FmManipHdrInfo *p_HdrInfo, + uint8_t *parseArrayOffset) +{ + e_NetHeaderType hdr = p_HdrInfo->hdr; + e_FmPcdHdrIndex hdrIndex = p_HdrInfo->hdrIndex; + bool byField = p_HdrInfo->byField; + t_FmPcdFields field; + + if (byField) + field = p_HdrInfo->fullField; + + if (byField) + { + switch (hdr) + { + case (HEADER_TYPE_ETH): + switch (field.eth) + { + case (NET_HEADER_FIELD_ETH_TYPE): + *parseArrayOffset = CC_PC_PR_ETYPE_LAST_OFFSET; + break; + default: + RETURN_ERROR( + MAJOR, + E_NOT_SUPPORTED, + ("Header manipulation of the type Ethernet with this field not supported")); + } + break; + case (HEADER_TYPE_VLAN): + switch (field.vlan) + { + case (NET_HEADER_FIELD_VLAN_TCI): + if ((hdrIndex == e_FM_PCD_HDR_INDEX_NONE) + || (hdrIndex == e_FM_PCD_HDR_INDEX_1)) + *parseArrayOffset = CC_PC_PR_VLAN1_OFFSET; + else + if (hdrIndex == e_FM_PCD_HDR_INDEX_LAST) + *parseArrayOffset = CC_PC_PR_VLAN2_OFFSET; + break; + default: + RETURN_ERROR( + MAJOR, + E_NOT_SUPPORTED, + ("Header manipulation of the type VLAN with this field not supported")); + } + break; + default: + RETURN_ERROR( + MAJOR, + E_NOT_SUPPORTED, + ("Header manipulation of this header by field not supported")); + } + } + else + { + switch (hdr) + { + case (HEADER_TYPE_ETH): + *parseArrayOffset = (uint8_t)CC_PC_PR_ETH_OFFSET; + break; + case (HEADER_TYPE_USER_DEFINED_SHIM1): + *parseArrayOffset = (uint8_t)CC_PC_PR_USER_DEFINED_SHIM1_OFFSET; + break; + case (HEADER_TYPE_USER_DEFINED_SHIM2): + *parseArrayOffset = (uint8_t)CC_PC_PR_USER_DEFINED_SHIM2_OFFSET; + break; + case (HEADER_TYPE_LLC_SNAP): + *parseArrayOffset = CC_PC_PR_USER_LLC_SNAP_OFFSET; + break; + case (HEADER_TYPE_PPPoE): + *parseArrayOffset = CC_PC_PR_PPPOE_OFFSET; + break; + case (HEADER_TYPE_MPLS): + if ((hdrIndex == e_FM_PCD_HDR_INDEX_NONE) + || (hdrIndex == e_FM_PCD_HDR_INDEX_1)) + *parseArrayOffset = CC_PC_PR_MPLS1_OFFSET; + else + if (hdrIndex == e_FM_PCD_HDR_INDEX_LAST) + *parseArrayOffset = CC_PC_PR_MPLS_LAST_OFFSET; + break; + case (HEADER_TYPE_IPv4): + case (HEADER_TYPE_IPv6): + if ((hdrIndex == e_FM_PCD_HDR_INDEX_NONE) + || (hdrIndex == e_FM_PCD_HDR_INDEX_1)) + *parseArrayOffset = CC_PC_PR_IP1_OFFSET; + else + if (hdrIndex == e_FM_PCD_HDR_INDEX_2) + *parseArrayOffset = CC_PC_PR_IP_LAST_OFFSET; + break; + case (HEADER_TYPE_MINENCAP): + *parseArrayOffset = CC_PC_PR_MINENC_OFFSET; + break; + case (HEADER_TYPE_GRE): + *parseArrayOffset = CC_PC_PR_GRE_OFFSET; + break; + case (HEADER_TYPE_TCP): + case (HEADER_TYPE_UDP): + case (HEADER_TYPE_IPSEC_AH): + case (HEADER_TYPE_IPSEC_ESP): + case (HEADER_TYPE_DCCP): + case (HEADER_TYPE_SCTP): + *parseArrayOffset = CC_PC_PR_L4_OFFSET; + break; + case (HEADER_TYPE_CAPWAP): + case (HEADER_TYPE_CAPWAP_DTLS): + *parseArrayOffset = CC_PC_PR_NEXT_HEADER_OFFSET; + break; + default: + RETURN_ERROR( + MAJOR, + E_NOT_SUPPORTED, + ("Header manipulation of this header is not supported")); + } + } + return E_OK; +} + +static t_Error BuildHmct(t_FmPcdManip *p_Manip, + t_FmPcdManipParams *p_FmPcdManipParams, + uint8_t *p_DestHmct, uint8_t *p_DestData, bool new) +{ + uint32_t *p_TmpHmct = (uint32_t*)p_DestHmct, *p_LocalData; + uint32_t tmpReg = 0, *p_Last = NULL, tmp_ipv6_addr; + uint8_t remain, i, size = 0, origSize, *p_UsrData = NULL, *p_TmpData = + p_DestData; + t_Handle h_FmPcd = p_Manip->h_FmPcd; + uint8_t j = 0; + + if (p_FmPcdManipParams->u.hdr.rmv) + { + if (p_FmPcdManipParams->u.hdr.rmvParams.type + == e_FM_PCD_MANIP_RMV_GENERIC) + { + /* initialize HMCD */ + tmpReg = (uint32_t)(HMCD_OPCODE_GENERIC_RMV) << HMCD_OC_SHIFT; + /* tmp, should be conditional */ + tmpReg |= p_FmPcdManipParams->u.hdr.rmvParams.u.generic.offset + << HMCD_RMV_OFFSET_SHIFT; + tmpReg |= p_FmPcdManipParams->u.hdr.rmvParams.u.generic.size + << HMCD_RMV_SIZE_SHIFT; + } + else + if (p_FmPcdManipParams->u.hdr.rmvParams.type + == e_FM_PCD_MANIP_RMV_BY_HDR) + { + switch (p_FmPcdManipParams->u.hdr.rmvParams.u.byHdr.type) + { + case (e_FM_PCD_MANIP_RMV_BY_HDR_SPECIFIC_L2): + { + uint8_t hmcdOpt; + + /* initialize HMCD */ + tmpReg = (uint32_t)(HMCD_OPCODE_L2_RMV) << HMCD_OC_SHIFT; + + switch (p_FmPcdManipParams->u.hdr.rmvParams.u.byHdr.u.specificL2) + { + case (e_FM_PCD_MANIP_HDR_RMV_ETHERNET): + hmcdOpt = HMCD_RMV_L2_ETHERNET; + break; + case (e_FM_PCD_MANIP_HDR_RMV_STACKED_QTAGS): + hmcdOpt = HMCD_RMV_L2_STACKED_QTAGS; + break; + case (e_FM_PCD_MANIP_HDR_RMV_ETHERNET_AND_MPLS): + hmcdOpt = HMCD_RMV_L2_ETHERNET_AND_MPLS; + break; + case (e_FM_PCD_MANIP_HDR_RMV_MPLS): + hmcdOpt = HMCD_RMV_L2_MPLS; + break; + case (e_FM_PCD_MANIP_HDR_RMV_PPPOE): + hmcdOpt = HMCD_RMV_L2_PPPOE; + break; + default: + RETURN_ERROR(MINOR, E_NOT_SUPPORTED, NO_MSG); + } + tmpReg |= hmcdOpt << HMCD_L2_MODE_SHIFT; + break; + } +#if (DPAA_VERSION >= 11) + case (e_FM_PCD_MANIP_RMV_BY_HDR_CAPWAP): + tmpReg = (uint32_t)(HMCD_OPCODE_CAPWAP_RMV) + << HMCD_OC_SHIFT; + break; + case (e_FM_PCD_MANIP_RMV_BY_HDR_FROM_START): + { + uint8_t prsArrayOffset; + t_Error err = E_OK; + + tmpReg = (uint32_t)(HMCD_OPCODE_RMV_TILL) + << HMCD_OC_SHIFT; + + err = + GetPrOffsetByHeaderOrField( + &p_FmPcdManipParams->u.hdr.rmvParams.u.byHdr.u.hdrInfo, + &prsArrayOffset); + ASSERT_COND(!err); + /* was previously checked */ + + tmpReg |= ((uint32_t)prsArrayOffset << 16); + } + break; +#endif /* (DPAA_VERSION >= 11) */ + default: + RETURN_ERROR(MINOR, E_NOT_SUPPORTED, + ("manip header remove by hdr type!")); + } + } + + WRITE_UINT32(*p_TmpHmct, tmpReg); + /* save a pointer to the "last" indication word */ + p_Last = p_TmpHmct; + /* advance to next command */ + p_TmpHmct += HMCD_BASIC_SIZE / 4; + } + + if (p_FmPcdManipParams->u.hdr.insrt) + { + if (p_FmPcdManipParams->u.hdr.insrtParams.type + == e_FM_PCD_MANIP_INSRT_GENERIC) + { + /* initialize HMCD */ + if (p_FmPcdManipParams->u.hdr.insrtParams.u.generic.replace) + tmpReg = (uint32_t)(HMCD_OPCODE_GENERIC_REPLACE) + << HMCD_OC_SHIFT; + else + tmpReg = (uint32_t)(HMCD_OPCODE_GENERIC_INSRT) << HMCD_OC_SHIFT; + + tmpReg |= p_FmPcdManipParams->u.hdr.insrtParams.u.generic.offset + << HMCD_INSRT_OFFSET_SHIFT; + tmpReg |= p_FmPcdManipParams->u.hdr.insrtParams.u.generic.size + << HMCD_INSRT_SIZE_SHIFT; + + size = p_FmPcdManipParams->u.hdr.insrtParams.u.generic.size; + p_UsrData = p_FmPcdManipParams->u.hdr.insrtParams.u.generic.p_Data; + + WRITE_UINT32(*p_TmpHmct, tmpReg); + /* save a pointer to the "last" indication word */ + p_Last = p_TmpHmct; + + p_TmpHmct += HMCD_BASIC_SIZE / 4; + + /* initialize data to be inserted */ + /* if size is not a multiple of 4, padd with 0's */ + origSize = size; + remain = (uint8_t)(size % 4); + if (remain) + { + size += (uint8_t)(4 - remain); + p_LocalData = (uint32_t *)XX_Malloc(size); + memset((uint8_t *)p_LocalData, 0, size); + memcpy((uint8_t *)p_LocalData, p_UsrData, origSize); + } + else + p_LocalData = (uint32_t*)p_UsrData; + + /* initialize data and advance pointer to next command */ + MemCpy8(p_TmpHmct, p_LocalData, size); + p_TmpHmct += size / sizeof(uint32_t); + + if (remain) + XX_Free(p_LocalData); + } + + else + if (p_FmPcdManipParams->u.hdr.insrtParams.type + == e_FM_PCD_MANIP_INSRT_BY_HDR) + { + switch (p_FmPcdManipParams->u.hdr.insrtParams.u.byHdr.type) + { + case (e_FM_PCD_MANIP_INSRT_BY_HDR_SPECIFIC_L2): + { + uint8_t hmcdOpt; + + /* initialize HMCD */ + tmpReg = (uint32_t)(HMCD_OPCODE_L2_INSRT) + << HMCD_OC_SHIFT; + + switch (p_FmPcdManipParams->u.hdr.insrtParams.u.byHdr.u.specificL2Params.specificL2) + { + case (e_FM_PCD_MANIP_HDR_INSRT_MPLS): + if (p_FmPcdManipParams->u.hdr.insrtParams.u.byHdr.u.specificL2Params.update) + hmcdOpt = HMCD_INSRT_N_UPDATE_L2_MPLS; + else + hmcdOpt = HMCD_INSRT_L2_MPLS; + break; + case (e_FM_PCD_MANIP_HDR_INSRT_PPPOE): + hmcdOpt = HMCD_INSRT_L2_PPPOE; + break; + default: + RETURN_ERROR(MINOR, E_NOT_SUPPORTED, NO_MSG); + } + tmpReg |= hmcdOpt << HMCD_L2_MODE_SHIFT; + + WRITE_UINT32(*p_TmpHmct, tmpReg); + /* save a pointer to the "last" indication word */ + p_Last = p_TmpHmct; + + p_TmpHmct += HMCD_BASIC_SIZE / 4; + + /* set size and pointer of user's data */ + size = + (uint8_t)p_FmPcdManipParams->u.hdr.insrtParams.u.byHdr.u.specificL2Params.size; + + ASSERT_COND(p_TmpData); + MemCpy8( + p_TmpData, + p_FmPcdManipParams->u.hdr.insrtParams.u.byHdr.u.specificL2Params.p_Data, + size); + tmpReg = + (size << HMCD_INSRT_L2_SIZE_SHIFT) + | (uint32_t)(XX_VirtToPhys(p_TmpData) + - (((t_FmPcd*)h_FmPcd)->physicalMuramBase)); + WRITE_UINT32(*p_TmpHmct, tmpReg); + p_TmpHmct += HMCD_PTR_SIZE / 4; + p_TmpData += size; + } + break; +#if (DPAA_VERSION >= 11) + case (e_FM_PCD_MANIP_INSRT_BY_HDR_IP): + tmpReg = (uint32_t)(HMCD_OPCODE_IP_INSRT) + << HMCD_OC_SHIFT; + if (p_FmPcdManipParams->u.hdr.insrtParams.u.byHdr.u.ipParams.calcL4Checksum) + tmpReg |= HMCD_IP_L4_CS_CALC; + if (p_FmPcdManipParams->u.hdr.insrtParams.u.byHdr.u.ipParams.mappingMode + == e_FM_PCD_MANIP_HDR_QOS_MAPPING_AS_IS) + tmpReg |= HMCD_IP_OR_QOS; + tmpReg |= + p_FmPcdManipParams->u.hdr.insrtParams.u.byHdr.u.ipParams.lastPidOffset + & HMCD_IP_LAST_PID_MASK; + tmpReg |= + ((p_FmPcdManipParams->u.hdr.insrtParams.u.byHdr.u.ipParams.insrt.size + << HMCD_IP_SIZE_SHIFT) + & HMCD_IP_SIZE_MASK); + if (p_FmPcdManipParams->u.hdr.insrtParams.u.byHdr.u.ipParams.dontFragOverwrite) + tmpReg |= HMCD_IP_DF_MODE; + + WRITE_UINT32(*p_TmpHmct, tmpReg); + + /* save a pointer to the "last" indication word */ + p_Last = p_TmpHmct; + + p_TmpHmct += HMCD_BASIC_SIZE / 4; + + /* set IP id */ + ASSERT_COND(p_TmpData); + WRITE_UINT16( + *(uint16_t*)p_TmpData, + p_FmPcdManipParams->u.hdr.insrtParams.u.byHdr.u.ipParams.id); + WRITE_UINT32( + *p_TmpHmct, + (uint32_t)(XX_VirtToPhys(p_TmpData) - (((t_FmPcd*)p_Manip->h_FmPcd)->physicalMuramBase))); + p_TmpData += 2; + p_TmpHmct += HMCD_PTR_SIZE / 4; + + WRITE_UINT8(*p_TmpHmct, p_FmPcdManipParams->u.hdr.insrtParams.u.byHdr.u.ipParams.lastDstOffset); + p_TmpHmct += HMCD_PARAM_SIZE / 4; + + MemCpy8( + p_TmpHmct, + p_FmPcdManipParams->u.hdr.insrtParams.u.byHdr.u.ipParams.insrt.p_Data, + p_FmPcdManipParams->u.hdr.insrtParams.u.byHdr.u.ipParams.insrt.size); + p_TmpHmct += + p_FmPcdManipParams->u.hdr.insrtParams.u.byHdr.u.ipParams.insrt.size + / 4; + break; + case (e_FM_PCD_MANIP_INSRT_BY_HDR_UDP_LITE): + tmpReg = HMCD_INSRT_UDP_LITE; + /* fall through */ + case (e_FM_PCD_MANIP_INSRT_BY_HDR_UDP): + tmpReg |= (uint32_t)(HMCD_OPCODE_UDP_INSRT) + << HMCD_OC_SHIFT; + + WRITE_UINT32(*p_TmpHmct, tmpReg); + + /* save a pointer to the "last" indication word */ + p_Last = p_TmpHmct; + + p_TmpHmct += HMCD_BASIC_SIZE / 4; + + MemCpy8( + p_TmpHmct, + p_FmPcdManipParams->u.hdr.insrtParams.u.byHdr.u.insrt.p_Data, + p_FmPcdManipParams->u.hdr.insrtParams.u.byHdr.u.insrt.size); + p_TmpHmct += + p_FmPcdManipParams->u.hdr.insrtParams.u.byHdr.u.insrt.size + / 4; + break; + case (e_FM_PCD_MANIP_INSRT_BY_HDR_CAPWAP): + tmpReg = (uint32_t)(HMCD_OPCODE_CAPWAP_INSRT) + << HMCD_OC_SHIFT; + tmpReg |= HMCD_CAPWAP_INSRT; + + WRITE_UINT32(*p_TmpHmct, tmpReg); + + /* save a pointer to the "last" indication word */ + p_Last = p_TmpHmct; + + p_TmpHmct += HMCD_BASIC_SIZE / 4; + + MemCpy8( + p_TmpHmct, + p_FmPcdManipParams->u.hdr.insrtParams.u.byHdr.u.insrt.p_Data, + p_FmPcdManipParams->u.hdr.insrtParams.u.byHdr.u.insrt.size); + p_TmpHmct += + p_FmPcdManipParams->u.hdr.insrtParams.u.byHdr.u.insrt.size + / 4; + break; +#endif /* (DPAA_VERSION >= 11) */ + default: + RETURN_ERROR(MINOR, E_NOT_SUPPORTED, + ("manip header insert by header type!")); + + } + } + } + + if (p_FmPcdManipParams->u.hdr.fieldUpdate) + { + switch (p_FmPcdManipParams->u.hdr.fieldUpdateParams.type) + { + case (e_FM_PCD_MANIP_HDR_FIELD_UPDATE_VLAN): + /* set opcode */ + tmpReg = (uint32_t)(HMCD_OPCODE_VLAN_PRI_UPDATE) + << HMCD_OC_SHIFT; + + /* set mode & table pointer */ + if (p_FmPcdManipParams->u.hdr.fieldUpdateParams.u.vlan.updateType + == e_FM_PCD_MANIP_HDR_FIELD_UPDATE_DSCP_TO_VLAN) + { + /* set Mode */ + tmpReg |= (uint32_t)(HMCD_VLAN_PRI_UPDATE_DSCP_TO_VPRI) + << HMCD_VLAN_PRI_REP_MODE_SHIFT; + /* set VPRI default */ + tmpReg |= + p_FmPcdManipParams->u.hdr.fieldUpdateParams.u.vlan.u.dscpToVpri.vpriDefVal; + WRITE_UINT32(*p_TmpHmct, tmpReg); + /* save a pointer to the "last" indication word */ + p_Last = p_TmpHmct; + /* write the table pointer into the Manip descriptor */ + p_TmpHmct += HMCD_BASIC_SIZE / 4; + + tmpReg = 0; + ASSERT_COND(p_TmpData); + for (i = 0; i < HMCD_DSCP_VALUES; i++) + { + /* first we build from each 8 values a 32bit register */ + tmpReg |= + (p_FmPcdManipParams->u.hdr.fieldUpdateParams.u.vlan.u.dscpToVpri.dscpToVpriTable[i]) + << (32 - 4 * (j + 1)); + j++; + /* Than we write this register to the next table word + * (i=7-->word 0, i=15-->word 1,... i=63-->word 7) */ + if ((i % 8) == 7) + { + WRITE_UINT32(*((uint32_t*)p_TmpData + (i+1)/8-1), + tmpReg); + tmpReg = 0; + j = 0; + } + } + + WRITE_UINT32( + *p_TmpHmct, + (uint32_t)(XX_VirtToPhys(p_TmpData) - (((t_FmPcd*)h_FmPcd)->physicalMuramBase))); + p_TmpHmct += HMCD_PTR_SIZE / 4; + + p_TmpData += DSCP_TO_VLAN_TABLE_SIZE; + } + else + if (p_FmPcdManipParams->u.hdr.fieldUpdateParams.u.vlan.updateType + == e_FM_PCD_MANIP_HDR_FIELD_UPDATE_VLAN_VPRI) + { + /* set Mode */ + /* line commented out as it has no-side-effect ('0' value). */ + /*tmpReg |= HMCD_VLAN_PRI_UPDATE << HMCD_VLAN_PRI_REP_MODE_SHIFT*/; + /* set VPRI parameter */ + tmpReg |= + p_FmPcdManipParams->u.hdr.fieldUpdateParams.u.vlan.u.vpri; + WRITE_UINT32(*p_TmpHmct, tmpReg); + /* save a pointer to the "last" indication word */ + p_Last = p_TmpHmct; + p_TmpHmct += HMCD_BASIC_SIZE / 4; + } + break; + + case (e_FM_PCD_MANIP_HDR_FIELD_UPDATE_IPV4): + /* set opcode */ + tmpReg = (uint32_t)(HMCD_OPCODE_IPV4_UPDATE) << HMCD_OC_SHIFT; + if (p_FmPcdManipParams->u.hdr.fieldUpdateParams.u.ipv4.validUpdates + & HDR_MANIP_IPV4_TTL) + tmpReg |= HMCD_IPV4_UPDATE_TTL; + if (p_FmPcdManipParams->u.hdr.fieldUpdateParams.u.ipv4.validUpdates + & HDR_MANIP_IPV4_TOS) + { + tmpReg |= HMCD_IPV4_UPDATE_TOS; + tmpReg |= + p_FmPcdManipParams->u.hdr.fieldUpdateParams.u.ipv4.tos + << HMCD_IPV4_UPDATE_TOS_SHIFT; + } + if (p_FmPcdManipParams->u.hdr.fieldUpdateParams.u.ipv4.validUpdates + & HDR_MANIP_IPV4_ID) + tmpReg |= HMCD_IPV4_UPDATE_ID; + if (p_FmPcdManipParams->u.hdr.fieldUpdateParams.u.ipv4.validUpdates + & HDR_MANIP_IPV4_SRC) + tmpReg |= HMCD_IPV4_UPDATE_SRC; + if (p_FmPcdManipParams->u.hdr.fieldUpdateParams.u.ipv4.validUpdates + & HDR_MANIP_IPV4_DST) + tmpReg |= HMCD_IPV4_UPDATE_DST; + /* write the first 4 bytes of the descriptor */ + WRITE_UINT32(*p_TmpHmct, tmpReg); + /* save a pointer to the "last" indication word */ + p_Last = p_TmpHmct; + + p_TmpHmct += HMCD_BASIC_SIZE / 4; + + if (p_FmPcdManipParams->u.hdr.fieldUpdateParams.u.ipv4.validUpdates + & HDR_MANIP_IPV4_ID) + { + ASSERT_COND(p_TmpData); + WRITE_UINT16( + *(uint16_t*)p_TmpData, + p_FmPcdManipParams->u.hdr.fieldUpdateParams.u.ipv4.id); + WRITE_UINT32( + *p_TmpHmct, + (uint32_t)(XX_VirtToPhys(p_TmpData) - (((t_FmPcd*)p_Manip->h_FmPcd)->physicalMuramBase))); + p_TmpData += 2; + p_TmpHmct += HMCD_PTR_SIZE / 4; + } + + if (p_FmPcdManipParams->u.hdr.fieldUpdateParams.u.ipv4.validUpdates + & HDR_MANIP_IPV4_SRC) + { + WRITE_UINT32( + *p_TmpHmct, + p_FmPcdManipParams->u.hdr.fieldUpdateParams.u.ipv4.src); + p_TmpHmct += HMCD_IPV4_ADDR_SIZE / 4; + } + + if (p_FmPcdManipParams->u.hdr.fieldUpdateParams.u.ipv4.validUpdates + & HDR_MANIP_IPV4_DST) + { + WRITE_UINT32( + *p_TmpHmct, + p_FmPcdManipParams->u.hdr.fieldUpdateParams.u.ipv4.dst); + p_TmpHmct += HMCD_IPV4_ADDR_SIZE / 4; + } + break; + + case (e_FM_PCD_MANIP_HDR_FIELD_UPDATE_IPV6): + /* set opcode */ + tmpReg = (uint32_t)(HMCD_OPCODE_IPV6_UPDATE) << HMCD_OC_SHIFT; + if (p_FmPcdManipParams->u.hdr.fieldUpdateParams.u.ipv6.validUpdates + & HDR_MANIP_IPV6_HL) + tmpReg |= HMCD_IPV6_UPDATE_HL; + if (p_FmPcdManipParams->u.hdr.fieldUpdateParams.u.ipv6.validUpdates + & HDR_MANIP_IPV6_TC) + { + tmpReg |= HMCD_IPV6_UPDATE_TC; + tmpReg |= + p_FmPcdManipParams->u.hdr.fieldUpdateParams.u.ipv6.trafficClass + << HMCD_IPV6_UPDATE_TC_SHIFT; + } + if (p_FmPcdManipParams->u.hdr.fieldUpdateParams.u.ipv6.validUpdates + & HDR_MANIP_IPV6_SRC) + tmpReg |= HMCD_IPV6_UPDATE_SRC; + if (p_FmPcdManipParams->u.hdr.fieldUpdateParams.u.ipv6.validUpdates + & HDR_MANIP_IPV6_DST) + tmpReg |= HMCD_IPV6_UPDATE_DST; + /* write the first 4 bytes of the descriptor */ + WRITE_UINT32(*p_TmpHmct, tmpReg); + /* save a pointer to the "last" indication word */ + p_Last = p_TmpHmct; + + p_TmpHmct += HMCD_BASIC_SIZE / 4; + if (p_FmPcdManipParams->u.hdr.fieldUpdateParams.u.ipv6.validUpdates + & HDR_MANIP_IPV6_SRC) + { + for (i = 0; i < NET_HEADER_FIELD_IPv6_ADDR_SIZE; i += 4) + { + memcpy(&tmp_ipv6_addr, + &p_FmPcdManipParams->u.hdr.fieldUpdateParams.u.ipv6.src[i], + sizeof(uint32_t)); + WRITE_UINT32(*p_TmpHmct, tmp_ipv6_addr); + p_TmpHmct += HMCD_PTR_SIZE / 4; + } + } + if (p_FmPcdManipParams->u.hdr.fieldUpdateParams.u.ipv6.validUpdates + & HDR_MANIP_IPV6_DST) + { + for (i = 0; i < NET_HEADER_FIELD_IPv6_ADDR_SIZE; i += 4) + { + memcpy(&tmp_ipv6_addr, + &p_FmPcdManipParams->u.hdr.fieldUpdateParams.u.ipv6.dst[i], + sizeof(uint32_t)); + WRITE_UINT32(*p_TmpHmct, tmp_ipv6_addr); + p_TmpHmct += HMCD_PTR_SIZE / 4; + } + } + break; + + case (e_FM_PCD_MANIP_HDR_FIELD_UPDATE_TCP_UDP): + if (p_FmPcdManipParams->u.hdr.fieldUpdateParams.u.tcpUdp.validUpdates + == HDR_MANIP_TCP_UDP_CHECKSUM) + { + /* we implement this case with the update-checksum descriptor */ + /* set opcode */ + tmpReg = (uint32_t)(HMCD_OPCODE_TCP_UDP_CHECKSUM) + << HMCD_OC_SHIFT; + /* write the first 4 bytes of the descriptor */ + WRITE_UINT32(*p_TmpHmct, tmpReg); + /* save a pointer to the "last" indication word */ + p_Last = p_TmpHmct; + + p_TmpHmct += HMCD_BASIC_SIZE / 4; + } + else + { + /* we implement this case with the TCP/UDP update descriptor */ + /* set opcode */ + tmpReg = (uint32_t)(HMCD_OPCODE_TCP_UDP_UPDATE) + << HMCD_OC_SHIFT; + if (p_FmPcdManipParams->u.hdr.fieldUpdateParams.u.tcpUdp.validUpdates + & HDR_MANIP_TCP_UDP_DST) + tmpReg |= HMCD_TCP_UDP_UPDATE_DST; + if (p_FmPcdManipParams->u.hdr.fieldUpdateParams.u.tcpUdp.validUpdates + & HDR_MANIP_TCP_UDP_SRC) + tmpReg |= HMCD_TCP_UDP_UPDATE_SRC; + /* write the first 4 bytes of the descriptor */ + WRITE_UINT32(*p_TmpHmct, tmpReg); + /* save a pointer to the "last" indication word */ + p_Last = p_TmpHmct; + + p_TmpHmct += HMCD_BASIC_SIZE / 4; + + tmpReg = 0; + if (p_FmPcdManipParams->u.hdr.fieldUpdateParams.u.tcpUdp.validUpdates + & HDR_MANIP_TCP_UDP_SRC) + tmpReg |= + ((uint32_t)p_FmPcdManipParams->u.hdr.fieldUpdateParams.u.tcpUdp.src) + << HMCD_TCP_UDP_UPDATE_SRC_SHIFT; + if (p_FmPcdManipParams->u.hdr.fieldUpdateParams.u.tcpUdp.validUpdates + & HDR_MANIP_TCP_UDP_DST) + tmpReg |= + ((uint32_t)p_FmPcdManipParams->u.hdr.fieldUpdateParams.u.tcpUdp.dst); + WRITE_UINT32(*p_TmpHmct, tmpReg); + p_TmpHmct += HMCD_PTR_SIZE / 4; + } + break; + + default: + RETURN_ERROR(MINOR, E_INVALID_SELECTION, + ("Unknown fieldUpdateParams.type")); + } + } + + if (p_FmPcdManipParams->u.hdr.custom) + { + switch (p_FmPcdManipParams->u.hdr.customParams.type) + { + case (e_FM_PCD_MANIP_HDR_CUSTOM_IP_REPLACE): + /* set opcode */ + tmpReg = (uint32_t)(HMCD_OPCODE_REPLACE_IP) << HMCD_OC_SHIFT; + + if (p_FmPcdManipParams->u.hdr.customParams.u.ipHdrReplace.decTtlHl) + tmpReg |= HMCD_IP_REPLACE_TTL_HL; + if (p_FmPcdManipParams->u.hdr.customParams.u.ipHdrReplace.replaceType + == e_FM_PCD_MANIP_HDR_CUSTOM_REPLACE_IPV4_BY_IPV6) + /* line commented out as it has no-side-effect ('0' value). */ + /*tmpReg |= HMCD_IP_REPLACE_REPLACE_IPV4*/; + else + if (p_FmPcdManipParams->u.hdr.customParams.u.ipHdrReplace.replaceType + == e_FM_PCD_MANIP_HDR_CUSTOM_REPLACE_IPV6_BY_IPV4) + { + tmpReg |= HMCD_IP_REPLACE_REPLACE_IPV6; + if (p_FmPcdManipParams->u.hdr.customParams.u.ipHdrReplace.updateIpv4Id) + tmpReg |= HMCD_IP_REPLACE_ID; + } + else + RETURN_ERROR( + MINOR, + E_NOT_SUPPORTED, + ("One flag out of HDR_MANIP_IP_REPLACE_IPV4, HDR_MANIP_IP_REPLACE_IPV6 - must be set.")); + + /* write the first 4 bytes of the descriptor */ + WRITE_UINT32(*p_TmpHmct, tmpReg); + /* save a pointer to the "last" indication word */ + p_Last = p_TmpHmct; + + p_TmpHmct += HMCD_BASIC_SIZE / 4; + + size = + p_FmPcdManipParams->u.hdr.customParams.u.ipHdrReplace.hdrSize; + ASSERT_COND(p_TmpData); + MemCpy8( + p_TmpData, + p_FmPcdManipParams->u.hdr.customParams.u.ipHdrReplace.hdr, + size); + tmpReg = (uint32_t)(size << HMCD_IP_REPLACE_L3HDRSIZE_SHIFT); + tmpReg |= (uint32_t)(XX_VirtToPhys(p_TmpData) + - (((t_FmPcd*)h_FmPcd)->physicalMuramBase)); + WRITE_UINT32(*p_TmpHmct, tmpReg); + p_TmpHmct += HMCD_PTR_SIZE / 4; + p_TmpData += size; + + if ((p_FmPcdManipParams->u.hdr.customParams.u.ipHdrReplace.replaceType + == e_FM_PCD_MANIP_HDR_CUSTOM_REPLACE_IPV6_BY_IPV4) + && (p_FmPcdManipParams->u.hdr.customParams.u.ipHdrReplace.updateIpv4Id)) + { + WRITE_UINT16( + *(uint16_t*)p_TmpData, + p_FmPcdManipParams->u.hdr.customParams.u.ipHdrReplace.id); + WRITE_UINT32( + *p_TmpHmct, + (uint32_t)(XX_VirtToPhys(p_TmpData) - (((t_FmPcd*)h_FmPcd)->physicalMuramBase))); + p_TmpData += 2; + } + p_TmpHmct += HMCD_PTR_SIZE / 4; + break; + case (e_FM_PCD_MANIP_HDR_CUSTOM_GEN_FIELD_REPLACE): + /* set opcode */ + tmpReg = (uint32_t)(HMCD_OPCODE_GEN_FIELD_REPLACE) << HMCD_OC_SHIFT; + tmpReg |= p_FmPcdManipParams->u.hdr.customParams.u.genFieldReplace.size << HMCD_GEN_FIELD_SIZE_SHIFT; + tmpReg |= p_FmPcdManipParams->u.hdr.customParams.u.genFieldReplace.srcOffset << HMCD_GEN_FIELD_SRC_OFF_SHIFT; + tmpReg |= p_FmPcdManipParams->u.hdr.customParams.u.genFieldReplace.dstOffset << HMCD_GEN_FIELD_DST_OFF_SHIFT; + if (p_FmPcdManipParams->u.hdr.customParams.u.genFieldReplace.mask) + tmpReg |= HMCD_GEN_FIELD_MASK_EN; + + /* write the first 4 bytes of the descriptor */ + WRITE_UINT32(*p_TmpHmct, tmpReg); + /* save a pointer to the "last" indication word */ + p_Last = p_TmpHmct; + + p_TmpHmct += HMCD_BASIC_SIZE/4; + + if (p_FmPcdManipParams->u.hdr.customParams.u.genFieldReplace.mask) + { + tmpReg = p_FmPcdManipParams->u.hdr.customParams.u.genFieldReplace.mask << HMCD_GEN_FIELD_MASK_SHIFT; + tmpReg |= p_FmPcdManipParams->u.hdr.customParams.u.genFieldReplace.maskOffset << HMCD_GEN_FIELD_MASK_OFF_SHIFT; + /* write the next 4 bytes of the descriptor */ + WRITE_UINT32(*p_TmpHmct, tmpReg); + } + p_TmpHmct += HMCD_PARAM_SIZE/4; + break; + default: + RETURN_ERROR(MINOR, E_INVALID_SELECTION, + ("Unknown customParams.type")); + } + } + + /* If this node has a nextManip, and no parsing is required, the old table must be copied to the new table + the old table and should be freed */ + if (p_FmPcdManipParams->h_NextManip + && (p_Manip->nextManipType == e_FM_PCD_MANIP_HDR) + && (MANIP_DONT_REPARSE(p_Manip))) + { + if (new) + { + /* If this is the first time this manip is created we need to free unused memory. If it + * is a dynamic changes case, the memory used is either the CC shadow or the existing + * table - no allocation, no free */ + MANIP_UPDATE_UNIFIED_POSITION(p_FmPcdManipParams->h_NextManip); + + p_Manip->unifiedPosition = e_MANIP_UNIFIED_FIRST; + } + } + else + { + ASSERT_COND(p_Last); + /* set the "last" indication on the last command of the current table */ + WRITE_UINT32(*p_Last, GET_UINT32(*p_Last) | HMCD_LAST); + } + + return E_OK; +} + +static t_Error CreateManipActionNew(t_FmPcdManip *p_Manip, + t_FmPcdManipParams *p_FmPcdManipParams) +{ + t_FmPcdManip *p_CurManip; + t_Error err; + uint32_t nextSize = 0, totalSize; + uint16_t tmpReg; + uint8_t *p_OldHmct, *p_TmpHmctPtr, *p_TmpDataPtr; + + /* set Manip structure */ + + p_Manip->dontParseAfterManip = + p_FmPcdManipParams->u.hdr.dontParseAfterManip; + + if (p_FmPcdManipParams->h_NextManip) + { /* Next Header manipulation exists */ + p_Manip->nextManipType = MANIP_GET_TYPE(p_FmPcdManipParams->h_NextManip); + + if ((p_Manip->nextManipType == e_FM_PCD_MANIP_HDR) && p_Manip->dontParseAfterManip) + nextSize = (uint32_t)(GetHmctSize(p_FmPcdManipParams->h_NextManip) + + GetDataSize(p_FmPcdManipParams->h_NextManip)); + else /* either parsing is required or next manip is Frag; no table merging. */ + p_Manip->cascaded = TRUE; + /* pass up the "cascaded" attribute. The whole chain is cascaded + * if something is cascaded along the way. */ + if (MANIP_IS_CASCADED(p_FmPcdManipParams->h_NextManip)) + p_Manip->cascaded = TRUE; + } + + /* Allocate new table */ + /* calculate table size according to manip parameters */ + err = CalculateTableSize(p_FmPcdManipParams, &p_Manip->tableSize, + &p_Manip->dataSize); + if (err) + RETURN_ERROR(MINOR, err, NO_MSG); + + totalSize = (uint16_t)(p_Manip->tableSize + p_Manip->dataSize + nextSize); + + p_Manip->p_Hmct = (uint8_t*)FM_MURAM_AllocMem( + ((t_FmPcd *)p_Manip->h_FmPcd)->h_FmMuram, totalSize, 4); + if (!p_Manip->p_Hmct) + RETURN_ERROR(MAJOR, E_NO_MEMORY, ("MURAM alloc failed")); + + if (p_Manip->dataSize) + p_Manip->p_Data = + (uint8_t*)PTR_MOVE(p_Manip->p_Hmct, (p_Manip->tableSize + nextSize)); + + /* update shadow size to allow runtime replacement of Header manipulation */ + /* The allocated shadow is divided as follows: + 0 . . . 16 . . . + -------------------------------- + | Shadow | Shadow HMTD | + | HMTD | Match Table | + | (16 bytes) | (maximal size) | + -------------------------------- + */ + + err = FmPcdUpdateCcShadow(p_Manip->h_FmPcd, (uint32_t)(totalSize + 16), + (uint16_t)FM_PCD_CC_AD_TABLE_ALIGN); + if (err != E_OK) + { + FM_MURAM_FreeMem(p_Manip->h_FmPcd, p_Manip->p_Hmct); + RETURN_ERROR(MAJOR, E_NO_MEMORY, + ("MURAM allocation for HdrManip node shadow")); + } + + if (p_FmPcdManipParams->h_NextManip + && (p_Manip->nextManipType == e_FM_PCD_MANIP_HDR) + && (MANIP_DONT_REPARSE(p_Manip))) + { + p_OldHmct = (uint8_t *)GetManipInfo(p_FmPcdManipParams->h_NextManip, + e_MANIP_HMCT); + p_CurManip = p_FmPcdManipParams->h_NextManip; + /* Run till the last Manip (which is the first to configure) */ + while (MANIP_IS_UNIFIED_NON_LAST(p_CurManip)) + p_CurManip = p_CurManip->h_NextManip; + + while (p_CurManip) + { + /* If this is a unified table, point to the part of the table + * which is the relative offset in HMCT. + */ + p_TmpHmctPtr = (uint8_t*)PTR_MOVE(p_Manip->p_Hmct, + (p_Manip->tableSize + + (PTR_TO_UINT(p_CurManip->p_Hmct) - + PTR_TO_UINT(p_OldHmct)))); + if (p_CurManip->p_Data) + p_TmpDataPtr = (uint8_t*)PTR_MOVE(p_Manip->p_Hmct, + (p_Manip->tableSize + + (PTR_TO_UINT(p_CurManip->p_Data) - + PTR_TO_UINT(p_OldHmct)))); + else + p_TmpDataPtr = NULL; + + BuildHmct(p_CurManip, &p_CurManip->manipParams, p_TmpHmctPtr, + p_TmpDataPtr, FALSE); + /* update old manip table pointer */ + MANIP_SET_HMCT_PTR(p_CurManip, p_TmpHmctPtr); + MANIP_SET_DATA_PTR(p_CurManip, p_TmpDataPtr); + + p_CurManip = p_CurManip->h_PrevManip; + } + /* We copied the HMCT to create a new large HMCT so we can free the old one */ + FM_MURAM_FreeMem(MANIP_GET_MURAM(p_FmPcdManipParams->h_NextManip), + p_OldHmct); + } + + /* Fill table */ + err = BuildHmct(p_Manip, p_FmPcdManipParams, p_Manip->p_Hmct, + p_Manip->p_Data, TRUE); + if (err) + { + FM_MURAM_FreeMem(p_Manip->h_FmPcd, p_Manip->p_Hmct); + RETURN_ERROR(MINOR, err, NO_MSG); + } + + /* Build HMTD (table descriptor) */ + tmpReg = HMTD_CFG_TYPE; /* NADEN = 0 */ + + /* add parseAfterManip */ + if (!p_Manip->dontParseAfterManip) + tmpReg |= HMTD_CFG_PRS_AFTER_HM; + + /* create cascade */ + /*if (p_FmPcdManipParams->h_NextManip + && (!MANIP_DONT_REPARSE(p_Manip) || (p_Manip->nextManipType != e_FM_PCD_MANIP_HDR)))*/ + if (p_Manip->cascaded) + { + uint16_t nextAd; + /* indicate that there's another HM table descriptor */ + tmpReg |= HMTD_CFG_NEXT_AD_EN; + /* get address of next HMTD (table descriptor; h_Ad). + * If the next HMTD was removed due to table unifing, get the address + * of the "next next" as written in the h_Ad of the next h_Manip node. + */ + if (p_Manip->unifiedPosition != e_MANIP_UNIFIED_FIRST) + nextAd = (uint16_t)((uint32_t)(XX_VirtToPhys(MANIP_GET_HMTD_PTR(p_FmPcdManipParams->h_NextManip)) - (((t_FmPcd*)p_Manip->h_FmPcd)->physicalMuramBase)) >> 4); + else + nextAd = ((t_Hmtd *)((t_FmPcdManip *)p_FmPcdManipParams->h_NextManip)->h_Ad)->nextAdIdx; + + WRITE_UINT16(((t_Hmtd *)p_Manip->h_Ad)->nextAdIdx, nextAd); + } + + WRITE_UINT16(((t_Hmtd *)p_Manip->h_Ad)->cfg, tmpReg); + WRITE_UINT32( + ((t_Hmtd *)p_Manip->h_Ad)->hmcdBasePtr, + (uint32_t)(XX_VirtToPhys(p_Manip->p_Hmct) - (((t_FmPcd*)p_Manip->h_FmPcd)->physicalMuramBase))); + + WRITE_UINT8(((t_Hmtd *)p_Manip->h_Ad)->opCode, HMAN_OC); + + if (p_Manip->unifiedPosition == e_MANIP_UNIFIED_FIRST) + { + /* The HMTD of the next Manip is never going to be used */ + if (((t_FmPcdManip *)p_FmPcdManipParams->h_NextManip)->muramAllocate) + FM_MURAM_FreeMem( + ((t_FmPcd *)((t_FmPcdManip *)p_FmPcdManipParams->h_NextManip)->h_FmPcd)->h_FmMuram, + ((t_FmPcdManip *)p_FmPcdManipParams->h_NextManip)->h_Ad); + else + XX_Free(((t_FmPcdManip *)p_FmPcdManipParams->h_NextManip)->h_Ad); + ((t_FmPcdManip *)p_FmPcdManipParams->h_NextManip)->h_Ad = NULL; + } + + return E_OK; +} + +static t_Error CreateManipActionShadow(t_FmPcdManip *p_Manip, + t_FmPcdManipParams *p_FmPcdManipParams) +{ + uint8_t *p_WholeHmct, *p_TmpHmctPtr, newDataSize, *p_TmpDataPtr = NULL; + uint16_t newSize; + t_FmPcd *p_FmPcd = (t_FmPcd *)p_Manip->h_FmPcd; + t_Error err; + t_FmPcdManip *p_CurManip = p_Manip; + + err = CalculateTableSize(p_FmPcdManipParams, &newSize, &newDataSize); + if (err) + RETURN_ERROR(MINOR, err, NO_MSG); + + /* check coherency of new table parameters */ + if (newSize > p_Manip->tableSize) + RETURN_ERROR( + MINOR, + E_INVALID_VALUE, + ("New Hdr Manip configuration requires larger size than current one (command table).")); + if (newDataSize > p_Manip->dataSize) + RETURN_ERROR( + MINOR, + E_INVALID_VALUE, + ("New Hdr Manip configuration requires larger size than current one (data).")); + if (p_FmPcdManipParams->h_NextManip) + RETURN_ERROR( + MINOR, E_INVALID_VALUE, + ("New Hdr Manip configuration can not contain h_NextManip.")); + if (MANIP_IS_UNIFIED(p_Manip) && (newSize != p_Manip->tableSize)) + RETURN_ERROR( + MINOR, + E_INVALID_VALUE, + ("New Hdr Manip configuration in a chained manipulation requires different size than current one.")); + if (p_Manip->dontParseAfterManip + != p_FmPcdManipParams->u.hdr.dontParseAfterManip) + RETURN_ERROR( + MINOR, + E_INVALID_VALUE, + ("New Hdr Manip configuration differs in dontParseAfterManip value.")); + + p_Manip->tableSize = newSize; + p_Manip->dataSize = newDataSize; + + /* Build the new table in the shadow */ + if (!MANIP_IS_UNIFIED(p_Manip)) + { + p_TmpHmctPtr = (uint8_t*)PTR_MOVE(p_FmPcd->p_CcShadow, 16); + if (p_Manip->p_Data) + p_TmpDataPtr = + (uint8_t*)PTR_MOVE(p_TmpHmctPtr, + (PTR_TO_UINT(p_Manip->p_Data) - PTR_TO_UINT(p_Manip->p_Hmct))); + + BuildHmct(p_Manip, p_FmPcdManipParams, p_TmpHmctPtr, p_Manip->p_Data, + FALSE); + } + else + { + p_WholeHmct = (uint8_t *)GetManipInfo(p_Manip, e_MANIP_HMCT); + ASSERT_COND(p_WholeHmct); + + /* Run till the last Manip (which is the first to configure) */ + while (MANIP_IS_UNIFIED_NON_LAST(p_CurManip)) + p_CurManip = p_CurManip->h_NextManip; + + while (p_CurManip) + { + /* If this is a non-head node in a unified table, point to the part of the shadow + * which is the relative offset in HMCT. + * else, point to the beginning of the + * shadow table (we save 16 for the HMTD. + */ + p_TmpHmctPtr = + (uint8_t*)PTR_MOVE(p_FmPcd->p_CcShadow, + (16 + PTR_TO_UINT(p_CurManip->p_Hmct) - PTR_TO_UINT(p_WholeHmct))); + if (p_CurManip->p_Data) + p_TmpDataPtr = + (uint8_t*)PTR_MOVE(p_FmPcd->p_CcShadow, + (16 + PTR_TO_UINT(p_CurManip->p_Data) - PTR_TO_UINT(p_WholeHmct))); + + BuildHmct(p_CurManip, &p_CurManip->manipParams, p_TmpHmctPtr, + p_TmpDataPtr, FALSE); + p_CurManip = p_CurManip->h_PrevManip; + } + } + + return E_OK; +} + +static t_Error CreateManipActionBackToOrig( + t_FmPcdManip *p_Manip, t_FmPcdManipParams *p_FmPcdManipParams) +{ + uint8_t *p_WholeHmct = NULL, *p_TmpHmctPtr, *p_TmpDataPtr; + t_FmPcdManip *p_CurManip = p_Manip; + + /* Build the new table in the shadow */ + if (!MANIP_IS_UNIFIED(p_Manip)) + BuildHmct(p_Manip, p_FmPcdManipParams, p_Manip->p_Hmct, p_Manip->p_Data, + FALSE); + else + { + p_WholeHmct = (uint8_t *)GetManipInfo(p_Manip, e_MANIP_HMCT); + ASSERT_COND(p_WholeHmct); + + /* Run till the last Manip (which is the first to configure) */ + while (MANIP_IS_UNIFIED_NON_LAST(p_CurManip)) + p_CurManip = p_CurManip->h_NextManip; + + while (p_CurManip) + { + /* If this is a unified table, point to the part of the table + * which is the relative offset in HMCT. + */ + p_TmpHmctPtr = p_CurManip->p_Hmct; /*- (uint32_t)p_WholeHmct*/ + p_TmpDataPtr = p_CurManip->p_Data; /*- (uint32_t)p_WholeHmct*/ + + BuildHmct(p_CurManip, &p_CurManip->manipParams, p_TmpHmctPtr, + p_TmpDataPtr, FALSE); + + p_CurManip = p_CurManip->h_PrevManip; + } + } + + return E_OK; +} + +#if (defined(FM_CAPWAP_SUPPORT) && (DPAA_VERSION == 10)) +static t_Error UpdateManipIc(t_Handle h_Manip, uint8_t icOffset) +{ + t_FmPcdManip *p_Manip = (t_FmPcdManip *)h_Manip; + t_Handle p_Ad; + uint32_t tmpReg32 = 0; + SANITY_CHECK_RETURN_ERROR(h_Manip, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_Manip->h_Ad, E_INVALID_HANDLE); + + switch (p_Manip->opcode) + { + case (HMAN_OC_MV_INT_FRAME_HDR_FROM_FRM_TO_BUFFER_PREFFIX): + p_Ad = (t_AdOfTypeContLookup *)p_Manip->h_Ad; + if (p_Manip->updateParams & INTERNAL_CONTEXT_OFFSET) + { + tmpReg32 = + *(uint32_t *)&((t_AdOfTypeContLookup *)p_Ad)->pcAndOffsets; + tmpReg32 |= (uint32_t)((uint32_t)icOffset << 16); + *(uint32_t *)&((t_AdOfTypeContLookup *)p_Ad)->pcAndOffsets = + tmpReg32; + p_Manip->updateParams &= ~INTERNAL_CONTEXT_OFFSET; + p_Manip->icOffset = icOffset; + } + else + { + if (p_Manip->icOffset != icOffset) + RETURN_ERROR( + MAJOR, + E_INVALID_VALUE, + ("this manipulation was updated previously by different value");); + } + break; + case (HMAN_OC_CAPWAP_RMV_DTLS_IF_EXIST): + if (p_Manip->h_Frag) + { + if (p_Manip->updateParams & INTERNAL_CONTEXT_OFFSET) + { + p_Ad = (t_AdOfTypeContLookup *)p_Manip->h_Ad; + tmpReg32 |= GET_UINT32(((t_AdOfTypeContLookup *)p_Ad)->pcAndOffsets); + tmpReg32 |= (uint32_t)((uint32_t)icOffset << 16); + WRITE_UINT32(((t_AdOfTypeContLookup *)p_Ad)->pcAndOffsets, tmpReg32); + p_Manip->updateParams &= ~INTERNAL_CONTEXT_OFFSET; + p_Manip->icOffset = icOffset; + } + else + { + if (p_Manip->icOffset != icOffset) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("this manipulation was updated previousely by different value");); + } + } + break; + } + + return E_OK; +} + +static t_Error UpdateInitMvIntFrameHeaderFromFrameToBufferPrefix( + t_Handle h_FmPort, t_FmPcdManip *p_Manip, t_Handle h_Ad, bool validate) +{ + + t_AdOfTypeContLookup *p_Ad = (t_AdOfTypeContLookup *)h_Ad; + t_FmPortGetSetCcParams fmPortGetSetCcParams; + t_Error err; + uint32_t tmpReg32; + + memset(&fmPortGetSetCcParams, 0, sizeof(t_FmPortGetSetCcParams)); + + SANITY_CHECK_RETURN_ERROR(p_Manip, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR( + (p_Manip->opcode & HMAN_OC_MV_INT_FRAME_HDR_FROM_FRM_TO_BUFFER_PREFFIX), + E_INVALID_STATE); + SANITY_CHECK_RETURN_ERROR(!p_Manip->muramAllocate, E_INVALID_STATE); + + if (p_Manip->updateParams) + { + if ((!(p_Manip->updateParams & OFFSET_OF_PR)) + || (p_Manip->shadowUpdateParams & OFFSET_OF_PR)) + RETURN_ERROR( + MAJOR, E_INVALID_STATE, + ("in this stage parameters from Port has not be updated")); + + fmPortGetSetCcParams.getCcParams.type = p_Manip->updateParams; + fmPortGetSetCcParams.setCcParams.type = UPDATE_PSO; + fmPortGetSetCcParams.setCcParams.psoSize = 16; + + err = FmPortGetSetCcParams(h_FmPort, &fmPortGetSetCcParams); + if (err) + RETURN_ERROR(MAJOR, err, NO_MSG); + if (fmPortGetSetCcParams.getCcParams.type & OFFSET_OF_PR) + RETURN_ERROR( + MAJOR, E_INVALID_STATE, + ("Parser result offset wasn't configured previousely")); +#ifdef FM_LOCKUP_ALIGNMENT_ERRATA_FMAN_SW004 + ASSERT_COND(!(fmPortGetSetCcParams.getCcParams.prOffset % 16)); +#endif + } + else + if (validate) + { + if ((!(p_Manip->shadowUpdateParams & OFFSET_OF_PR)) + || (p_Manip->updateParams & OFFSET_OF_PR)) + RETURN_ERROR( + MAJOR, E_INVALID_STATE, + ("in this stage parameters from Port has be updated")); + fmPortGetSetCcParams.getCcParams.type = p_Manip->shadowUpdateParams; + fmPortGetSetCcParams.setCcParams.type = UPDATE_PSO; + fmPortGetSetCcParams.setCcParams.psoSize = 16; + + err = FmPortGetSetCcParams(h_FmPort, &fmPortGetSetCcParams); + if (err) + RETURN_ERROR(MAJOR, err, NO_MSG); + if (fmPortGetSetCcParams.getCcParams.type & OFFSET_OF_PR) + RETURN_ERROR( + MAJOR, E_INVALID_STATE, + ("Parser result offset wasn't configured previousely")); + + } + + ASSERT_COND(p_Ad); + + if (p_Manip->updateParams & OFFSET_OF_PR) + { + tmpReg32 = 0; + tmpReg32 |= fmPortGetSetCcParams.getCcParams.prOffset; + WRITE_UINT32(p_Ad->matchTblPtr, + (GET_UINT32(p_Ad->matchTblPtr) | tmpReg32)); + p_Manip->updateParams &= ~OFFSET_OF_PR; + p_Manip->shadowUpdateParams |= OFFSET_OF_PR; + } + else + if (validate) + { + tmpReg32 = GET_UINT32(p_Ad->matchTblPtr); + if ((uint8_t)tmpReg32 != fmPortGetSetCcParams.getCcParams.prOffset) + RETURN_ERROR( + MAJOR, + E_INVALID_STATE, + ("this manipulation was updated previousely by different value");); + } + + return E_OK; +} + +static t_Error UpdateModifyCapwapFragmenation(t_FmPcdManip *p_Manip, t_Handle h_Ad, bool validate,t_Handle h_FmTree) +{ + t_AdOfTypeContLookup *p_Ad = (t_AdOfTypeContLookup *)h_Ad; + t_FmPcdCcSavedManipParams *p_SavedManipParams = NULL; + uint32_t tmpReg32 = 0; + + SANITY_CHECK_RETURN_ERROR(p_Manip,E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_Manip->h_Frag,E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_Manip->frag,E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(((p_Manip->opcode == HMAN_OC_CAPWAP_FRAGMENTATION) || (p_Manip->opcode == HMAN_OC_INSRT_HDR_BY_TEMPL_N_OR_FRAG_AFTER)), E_INVALID_STATE); + + p_Ad = (t_AdOfTypeContLookup *)p_Manip->h_Frag; + + if (p_Manip->updateParams) + { + + if ((!(p_Manip->updateParams & OFFSET_OF_DATA)) || + ((p_Manip->shadowUpdateParams & OFFSET_OF_DATA))) + RETURN_ERROR(MAJOR, E_INVALID_STATE, ("in this stage parameters from Port has not be updated")); + p_SavedManipParams = FmPcdCcTreeGetSavedManipParams(h_FmTree); + if (!p_SavedManipParams) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("for this manipulation tree has to be configured previosely with this type")); + p_Manip->capwapFragParams.dataOffset = p_SavedManipParams->capwapParams.dataOffset; + + tmpReg32 = GET_UINT32(p_Ad->pcAndOffsets); + tmpReg32 |= ((uint32_t)p_Manip->capwapFragParams.dataOffset<< 16); + WRITE_UINT32(p_Ad->pcAndOffsets,tmpReg32); + + p_Manip->updateParams &= ~OFFSET_OF_DATA; + p_Manip->shadowUpdateParams |= OFFSET_OF_DATA; + } + else if (validate) + { + + p_SavedManipParams = FmPcdCcTreeGetSavedManipParams(h_FmTree); + if (!p_SavedManipParams) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("for this manipulation tree has to be configured previosely with this type")); + if (p_Manip->capwapFragParams.dataOffset != p_SavedManipParams->capwapParams.dataOffset) + RETURN_ERROR(MAJOR, E_INVALID_STATE, ("this manipulation was updated previousely by different value")); + } + + return E_OK; +} + +static t_Error UpdateInitCapwapFragmentation(t_Handle h_FmPort, + t_FmPcdManip *p_Manip, + t_Handle h_Ad, + bool validate, + t_Handle h_FmTree) +{ + t_AdOfTypeContLookup *p_Ad; + t_FmPortGetSetCcParams fmPortGetSetCcParams; + t_Error err; + uint32_t tmpReg32 = 0; + t_FmPcdCcSavedManipParams *p_SavedManipParams; + + UNUSED(h_Ad); + + SANITY_CHECK_RETURN_ERROR(p_Manip,E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_Manip->h_Frag,E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_Manip->frag,E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(((p_Manip->opcode == HMAN_OC_CAPWAP_FRAGMENTATION) || + (p_Manip->opcode == HMAN_OC_INSRT_HDR_BY_TEMPL_N_OR_FRAG_AFTER)), E_INVALID_STATE); + + p_Ad = (t_AdOfTypeContLookup *)p_Manip->h_Frag; + + if (p_Manip->updateParams) + { + if ((!(p_Manip->updateParams & OFFSET_OF_DATA)) || + ((p_Manip->shadowUpdateParams & OFFSET_OF_DATA))) + RETURN_ERROR(MAJOR, E_INVALID_STATE, ("in this stage parameters from Port has not be updated")); + fmPortGetSetCcParams.getCcParams.type = p_Manip->updateParams; + fmPortGetSetCcParams.setCcParams.type = UPDATE_NIA_PNEN | UPDATE_FMFP_PRC_WITH_ONE_RISC_ONLY; + fmPortGetSetCcParams.setCcParams.nia = NIA_FM_CTL_AC_POP_TO_N_STEP | NIA_ENG_FM_CTL; + /* For CAPWAP Rassembly used FMAN_CTRL2 hardcoded - so for fragmentation its better to use FMAN_CTRL1 */ + fmPortGetSetCcParams.setCcParams.orFmanCtrl = FPM_PORT_FM_CTL1; + + err = FmPortGetSetCcParams(h_FmPort, &fmPortGetSetCcParams); + if (err) + RETURN_ERROR(MAJOR, err, NO_MSG); + + if (fmPortGetSetCcParams.getCcParams.type & OFFSET_OF_DATA) + RETURN_ERROR(MAJOR, E_INVALID_STATE, ("Data offset wasn't configured previousely")); + + p_SavedManipParams = (t_FmPcdCcSavedManipParams *)XX_Malloc(sizeof(t_FmPcdCcSavedManipParams)); + p_SavedManipParams->capwapParams.dataOffset = fmPortGetSetCcParams.getCcParams.dataOffset; + +#ifdef FM_LOCKUP_ALIGNMENT_ERRATA_FMAN_SW004 + ASSERT_COND(!(p_SavedManipParams->capwapParams.dataOffset % 16)); +#endif /* FM_LOCKUP_ALIGNMENT_ERRATA_FMAN_SW004 */ + + FmPcdCcTreeSetSavedManipParams(h_FmTree, (t_Handle)p_SavedManipParams); + } + else if (validate) + { + if ((!(p_Manip->shadowUpdateParams & OFFSET_OF_DATA)) || + ((p_Manip->updateParams & OFFSET_OF_DATA))) + RETURN_ERROR(MAJOR, E_INVALID_STATE, ("in this stage parameters from Port has be updated")); + fmPortGetSetCcParams.getCcParams.type = p_Manip->shadowUpdateParams; + fmPortGetSetCcParams.setCcParams.type = UPDATE_NIA_PNEN | UPDATE_FMFP_PRC_WITH_ONE_RISC_ONLY; + fmPortGetSetCcParams.setCcParams.nia = NIA_FM_CTL_AC_POP_TO_N_STEP | NIA_ENG_FM_CTL; + err = FmPortGetSetCcParams(h_FmPort, &fmPortGetSetCcParams); + if (err) + RETURN_ERROR(MAJOR, err, NO_MSG); + + if (fmPortGetSetCcParams.getCcParams.type & OFFSET_OF_DATA) + RETURN_ERROR(MAJOR, E_INVALID_STATE, ("Data offset wasn't configured previousely")); + } + + if (p_Manip->updateParams) + { + tmpReg32 = GET_UINT32(p_Ad->pcAndOffsets); + tmpReg32 |= ((uint32_t)fmPortGetSetCcParams.getCcParams.dataOffset<< 16); + WRITE_UINT32(p_Ad->pcAndOffsets,tmpReg32); + + p_Manip->updateParams &= ~OFFSET_OF_DATA; + p_Manip->shadowUpdateParams |= OFFSET_OF_DATA; + p_Manip->capwapFragParams.dataOffset = fmPortGetSetCcParams.getCcParams.dataOffset; + } + else if (validate) + { + if (p_Manip->capwapFragParams.dataOffset != fmPortGetSetCcParams.getCcParams.dataOffset) + RETURN_ERROR(MAJOR, E_INVALID_STATE, ("this manipulation was updated previousely by different value")); + } + + return E_OK; +} + +static t_Error UpdateInitCapwapReasm(t_Handle h_FmPcd, + t_Handle h_FmPort, + t_FmPcdManip *p_Manip, + t_Handle h_Ad, + bool validate) +{ + t_CapwapReasmPram *p_ReassmTbl; + t_Error err; + t_FmPortGetSetCcParams fmPortGetSetCcParams; + uint8_t i = 0; + uint16_t size; + uint32_t tmpReg32; + t_FmPcd *p_FmPcd = (t_FmPcd *)h_FmPcd; + t_FmPcdCcCapwapReassmTimeoutParams ccCapwapReassmTimeoutParams; + + SANITY_CHECK_RETURN_ERROR(p_Manip,E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_Manip->h_Frag,E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(!p_Manip->frag,E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR((p_Manip->opcode == HMAN_OC_CAPWAP_RMV_DTLS_IF_EXIST), E_INVALID_STATE); + SANITY_CHECK_RETURN_ERROR(h_FmPcd,E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_FmPcd->h_Hc,E_INVALID_HANDLE); + + if (p_Manip->h_FmPcd != h_FmPcd) + RETURN_ERROR(MAJOR, E_INVALID_STATE, + ("handler of PCD previously was initiated by different value")); + + UNUSED(h_Ad); + + memset(&fmPortGetSetCcParams, 0, sizeof(t_FmPortGetSetCcParams)); + p_ReassmTbl = (t_CapwapReasmPram *)p_Manip->h_Frag; + + if (p_Manip->updateParams) + { + if ((!(p_Manip->updateParams & NUM_OF_TASKS) && + !(p_Manip->updateParams & OFFSET_OF_DATA) && + !(p_Manip->updateParams & OFFSET_OF_PR) && + !(p_Manip->updateParams & HW_PORT_ID)) || + ((p_Manip->shadowUpdateParams & NUM_OF_TASKS) || + (p_Manip->shadowUpdateParams & OFFSET_OF_DATA) || (p_Manip->shadowUpdateParams & OFFSET_OF_PR) || + (p_Manip->shadowUpdateParams & HW_PORT_ID))) + RETURN_ERROR(MAJOR, E_INVALID_STATE, ("in this stage parameters from Port has not be updated")); + + fmPortGetSetCcParams.getCcParams.type = p_Manip->updateParams; + fmPortGetSetCcParams.setCcParams.type = UPDATE_NIA_PNEN; + fmPortGetSetCcParams.setCcParams.nia = NIA_FM_CTL_AC_POP_TO_N_STEP | NIA_ENG_FM_CTL; + + err = FmPortGetSetCcParams(h_FmPort, &fmPortGetSetCcParams); + if (err) + RETURN_ERROR(MAJOR, err, NO_MSG); + + if (fmPortGetSetCcParams.getCcParams.type & NUM_OF_TASKS) + RETURN_ERROR(MAJOR, E_INVALID_STATE, ("Num of tasks wasn't configured previousely")); + if (fmPortGetSetCcParams.getCcParams.type & OFFSET_OF_DATA) + RETURN_ERROR(MAJOR, E_INVALID_STATE, ("offset of the data wasn't configured previousely")); + if (fmPortGetSetCcParams.getCcParams.type & HW_PORT_ID) + RETURN_ERROR(MAJOR, E_INVALID_STATE, ("hwPortId wasn't updated")); +#ifdef FM_LOCKUP_ALIGNMENT_ERRATA_FMAN_SW004 + ASSERT_COND((fmPortGetSetCcParams.getCcParams.dataOffset % 16) == 0); +#endif /* FM_LOCKUP_ALIGNMENT_ERRATA_FMAN_SW004 */ + } + else if (validate) + { + if ((!(p_Manip->shadowUpdateParams & NUM_OF_TASKS) && + !(p_Manip->shadowUpdateParams & OFFSET_OF_DATA) && + !(p_Manip->shadowUpdateParams & OFFSET_OF_PR) && + !(p_Manip->shadowUpdateParams & HW_PORT_ID)) && + ((p_Manip->updateParams & NUM_OF_TASKS) || + (p_Manip->updateParams & OFFSET_OF_DATA) || (p_Manip->updateParams & OFFSET_OF_PR) || + (p_Manip->updateParams & HW_PORT_ID))) + RETURN_ERROR(MAJOR, E_INVALID_STATE, ("in this stage parameters from Port has be updated")); + + fmPortGetSetCcParams.getCcParams.type = p_Manip->shadowUpdateParams; + fmPortGetSetCcParams.setCcParams.type = UPDATE_NIA_PNEN; + fmPortGetSetCcParams.setCcParams.nia = NIA_FM_CTL_AC_POP_TO_N_STEP | NIA_ENG_FM_CTL; + + err = FmPortGetSetCcParams(h_FmPort, &fmPortGetSetCcParams); + if (err) + RETURN_ERROR(MAJOR, err, NO_MSG); + + if (fmPortGetSetCcParams.getCcParams.type & NUM_OF_TASKS) + RETURN_ERROR(MAJOR, E_INVALID_STATE, ("NumOfTasks wasn't configured previously")); + if (fmPortGetSetCcParams.getCcParams.type & OFFSET_OF_DATA) + RETURN_ERROR(MAJOR, E_INVALID_STATE, ("offset of the data wasn't configured previously")); + if (fmPortGetSetCcParams.getCcParams.type & HW_PORT_ID) + RETURN_ERROR(MAJOR, E_INVALID_STATE, ("hwPortId wasn't updated")); + } + + if (p_Manip->updateParams) + { + if (p_Manip->updateParams & NUM_OF_TASKS) + { + /*recommendation of Microcode team - (maxNumFramesInProcess * 2) */ + size = (uint16_t)(p_Manip->capwapFragParams.maxNumFramesInProcess*2 + fmPortGetSetCcParams.getCcParams.numOfTasks); + if (size > 255) + RETURN_ERROR(MAJOR,E_INVALID_VALUE, ("numOfOpenReassmEntries + numOfTasks per port can not be greater than 256")); + + p_Manip->capwapFragParams.numOfTasks = fmPortGetSetCcParams.getCcParams.numOfTasks; + + /*p_ReassmFrmDescrIndxPoolTbl*/ + p_Manip->capwapFragParams.p_ReassmFrmDescrIndxPoolTbl = + (t_Handle)FM_MURAM_AllocMem(p_FmPcd->h_FmMuram, + (uint32_t)(size + 1), + 4); + if (!p_Manip->capwapFragParams.p_ReassmFrmDescrIndxPoolTbl) + RETURN_ERROR(MAJOR, E_NO_MEMORY, ("MURAM alloc for CAPWAP Reassembly frame buffer index pool table")); + + MemSet8(p_Manip->capwapFragParams.p_ReassmFrmDescrIndxPoolTbl, 0, (uint32_t)(size + 1)); + + for ( i = 0; i < size; i++) + WRITE_UINT8(*(uint8_t *)PTR_MOVE(p_Manip->capwapFragParams.p_ReassmFrmDescrIndxPoolTbl, i), (uint8_t)(i+1)); + + tmpReg32 = (uint32_t)(XX_VirtToPhys(p_Manip->capwapFragParams.p_ReassmFrmDescrIndxPoolTbl) - p_FmPcd->physicalMuramBase); + + WRITE_UINT32(p_ReassmTbl->reasmFrmDescIndexPoolTblPtr, tmpReg32); + + /*p_ReassmFrmDescrPoolTbl*/ + p_Manip->capwapFragParams.p_ReassmFrmDescrPoolTbl = + (t_Handle)FM_MURAM_AllocMem(p_FmPcd->h_FmMuram, + (uint32_t)((size + 1) * FM_PCD_MANIP_CAPWAP_REASM_RFD_SIZE), + 4); + + if (!p_Manip->capwapFragParams.p_ReassmFrmDescrPoolTbl) + RETURN_ERROR(MAJOR, E_NO_MEMORY, ("MURAM alloc for CAPWAP Reassembly frame buffer pool table")); + + MemSet8(p_Manip->capwapFragParams.p_ReassmFrmDescrPoolTbl, 0, (uint32_t)((size +1)* FM_PCD_MANIP_CAPWAP_REASM_RFD_SIZE)); + + tmpReg32 = (uint32_t)(XX_VirtToPhys(p_Manip->capwapFragParams.p_ReassmFrmDescrPoolTbl) - p_FmPcd->physicalMuramBase); + + WRITE_UINT32(p_ReassmTbl->reasmFrmDescPoolTblPtr, tmpReg32); + + /*p_TimeOutTbl*/ + + p_Manip->capwapFragParams.p_TimeOutTbl = + (t_Handle)FM_MURAM_AllocMem(p_FmPcd->h_FmMuram, + (uint32_t)((size + 1)* FM_PCD_MANIP_CAPWAP_REASM_TIME_OUT_ENTRY_SIZE), + 4); + + if (!p_Manip->capwapFragParams.p_TimeOutTbl) + RETURN_ERROR(MAJOR, E_NO_MEMORY, ("MURAM alloc for CAPWAP Reassembly timeout table")); + + MemSet8(p_Manip->capwapFragParams.p_TimeOutTbl, 0, (uint16_t)((size + 1)*FM_PCD_MANIP_CAPWAP_REASM_TIME_OUT_ENTRY_SIZE)); + + tmpReg32 = (uint32_t)(XX_VirtToPhys(p_Manip->capwapFragParams.p_TimeOutTbl) - p_FmPcd->physicalMuramBase); + WRITE_UINT32(p_ReassmTbl->timeOutTblPtr, tmpReg32); + + p_Manip->updateParams &= ~NUM_OF_TASKS; + p_Manip->shadowUpdateParams |= NUM_OF_TASKS; + } + + if (p_Manip->updateParams & OFFSET_OF_DATA) + { + p_Manip->capwapFragParams.dataOffset = fmPortGetSetCcParams.getCcParams.dataOffset; + tmpReg32 = GET_UINT32(p_ReassmTbl->mode); + tmpReg32|= p_Manip->capwapFragParams.dataOffset; + WRITE_UINT32(p_ReassmTbl->mode, tmpReg32); + p_Manip->updateParams &= ~OFFSET_OF_DATA; + p_Manip->shadowUpdateParams |= OFFSET_OF_DATA; + } + + if (!(fmPortGetSetCcParams.getCcParams.type & OFFSET_OF_PR)) + { + p_Manip->capwapFragParams.prOffset = fmPortGetSetCcParams.getCcParams.prOffset; + + tmpReg32 = GET_UINT32(p_ReassmTbl->mode); + tmpReg32|= FM_PCD_MANIP_CAPWAP_REASM_PR_COPY; + WRITE_UINT32(p_ReassmTbl->mode, tmpReg32); + + tmpReg32 = GET_UINT32(p_ReassmTbl->intStatsTblPtr); + tmpReg32 |= (uint32_t)p_Manip->capwapFragParams.prOffset << 24; + WRITE_UINT32(p_ReassmTbl->intStatsTblPtr, tmpReg32); + p_Manip->updateParams &= ~OFFSET_OF_PR; + p_Manip->shadowUpdateParams |= OFFSET_OF_PR; + } + else + { + p_Manip->capwapFragParams.prOffset = 0xff; + p_Manip->updateParams &= ~OFFSET_OF_PR; + p_Manip->shadowUpdateParams |= OFFSET_OF_PR; + } + + p_Manip->capwapFragParams.hwPortId = fmPortGetSetCcParams.getCcParams.hardwarePortId; + p_Manip->updateParams &= ~HW_PORT_ID; + p_Manip->shadowUpdateParams |= HW_PORT_ID; + + /*timeout hc */ + ccCapwapReassmTimeoutParams.fqidForTimeOutFrames = p_Manip->capwapFragParams.fqidForTimeOutFrames; + ccCapwapReassmTimeoutParams.portIdAndCapwapReassmTbl = (uint32_t)p_Manip->capwapFragParams.hwPortId << 24; + ccCapwapReassmTimeoutParams.portIdAndCapwapReassmTbl |= (uint32_t)((XX_VirtToPhys(p_ReassmTbl) - p_FmPcd->physicalMuramBase)); + ccCapwapReassmTimeoutParams.timeoutRequestTime = (((uint32_t)1<<p_Manip->capwapFragParams.bitFor1Micro) * p_Manip->capwapFragParams.timeoutRoutineRequestTime)/2; + return FmHcPcdCcCapwapTimeoutReassm(p_FmPcd->h_Hc,&ccCapwapReassmTimeoutParams); + } + + else if (validate) + { + if (fmPortGetSetCcParams.getCcParams.hardwarePortId != p_Manip->capwapFragParams.hwPortId) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("Reassembly manipulation previously was assigned to another port")); + if (fmPortGetSetCcParams.getCcParams.numOfTasks != p_Manip->capwapFragParams.numOfTasks) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("numOfTasks for this manipulation previously was defined by another value ")); + + if (!(fmPortGetSetCcParams.getCcParams.type & OFFSET_OF_PR)) + { + if (p_Manip->capwapFragParams.prOffset != fmPortGetSetCcParams.getCcParams.prOffset) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("Parse result offset previously was defined by another value ")); + } + else + { + if (p_Manip->capwapFragParams.prOffset != 0xff) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("Parse result offset previously was defined by another value ")); + } + if (fmPortGetSetCcParams.getCcParams.dataOffset != p_Manip->capwapFragParams.dataOffset) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("Data offset previously was defined by another value ")); + } + + return E_OK; +} +#endif /* (defined(FM_CAPWAP_SUPPORT) && (DPAA_VERSION == 10)) */ + +t_Error FmPcdRegisterReassmPort(t_Handle h_FmPcd, t_Handle h_ReasmCommonPramTbl) +{ + t_FmPcd *p_FmPcd = (t_FmPcd*)h_FmPcd; + t_FmPcdCcReassmTimeoutParams ccReassmTimeoutParams = { 0 }; + t_Error err = E_OK; + uint8_t result; + uint32_t bitFor1Micro, tsbs, log2num; + + ASSERT_COND(p_FmPcd); + ASSERT_COND(h_ReasmCommonPramTbl); + + bitFor1Micro = FmGetTimeStampScale(p_FmPcd->h_Fm); + if (bitFor1Micro == 0) + RETURN_ERROR(MAJOR, E_NOT_AVAILABLE, ("Timestamp scale")); + + bitFor1Micro = 32 - bitFor1Micro; + LOG2(FM_PCD_MANIP_REASM_TIMEOUT_THREAD_THRESH, log2num); + tsbs = bitFor1Micro - log2num; + + ccReassmTimeoutParams.iprcpt = (uint32_t)(XX_VirtToPhys( + h_ReasmCommonPramTbl) - p_FmPcd->physicalMuramBase); + ccReassmTimeoutParams.tsbs = (uint8_t)tsbs; + ccReassmTimeoutParams.activate = TRUE; + if ((err = FmHcPcdCcTimeoutReassm(p_FmPcd->h_Hc, &ccReassmTimeoutParams, + &result)) != E_OK) + RETURN_ERROR(MAJOR, err, NO_MSG); + + switch (result) + { + case (0): + return E_OK; + case (1): + RETURN_ERROR(MAJOR, E_NO_MEMORY, ("failed to allocate TNUM")); + case (2): + RETURN_ERROR( + MAJOR, E_NO_MEMORY, + ("failed to allocate internal buffer from the HC-Port")); + case (3): + RETURN_ERROR(MAJOR, E_INVALID_VALUE, + ("'Disable Timeout Task' with invalid IPRCPT")); + case (4): + RETURN_ERROR(MAJOR, E_FULL, ("too many timeout tasks")); + case (5): + RETURN_ERROR(MAJOR, E_INVALID_SELECTION, ("invalid sub command")); + default: + RETURN_ERROR(MAJOR, E_INVALID_VALUE, NO_MSG); + } + return E_OK; +} + +static t_Error CreateReassCommonTable(t_FmPcdManip *p_Manip) +{ + uint32_t tmpReg32 = 0, i, bitFor1Micro; + uint64_t tmpReg64, size; + t_FmPcd *p_FmPcd = (t_FmPcd *)p_Manip->h_FmPcd; + t_Error err = E_OK; + + bitFor1Micro = FmGetTimeStampScale(p_FmPcd->h_Fm); + if (bitFor1Micro == 0) + RETURN_ERROR(MAJOR, E_NOT_AVAILABLE, ("Timestamp scale")); + + /* Allocation of the Reassembly Common Parameters table. This table is located in the + MURAM. Its size is 64 bytes and its base address should be 8-byte aligned. */ + p_Manip->reassmParams.p_ReassCommonTbl = + (t_ReassCommonTbl *)FM_MURAM_AllocMem( + p_FmPcd->h_FmMuram, + FM_PCD_MANIP_REASM_COMMON_PARAM_TABLE_SIZE, + FM_PCD_MANIP_REASM_COMMON_PARAM_TABLE_ALIGN); + + if (!p_Manip->reassmParams.p_ReassCommonTbl) + RETURN_ERROR(MAJOR, E_NO_MEMORY, + ("MURAM alloc for Reassembly common parameters table")); + + MemSet8(p_Manip->reassmParams.p_ReassCommonTbl, 0, + FM_PCD_MANIP_REASM_COMMON_PARAM_TABLE_SIZE); + + /* Setting the TimeOut Mode.*/ + tmpReg32 = 0; + if (p_Manip->reassmParams.timeOutMode + == e_FM_PCD_MANIP_TIME_OUT_BETWEEN_FRAMES) + tmpReg32 |= FM_PCD_MANIP_REASM_TIME_OUT_BETWEEN_FRAMES; + + /* Setting TimeOut FQID - Frames that time out are enqueued to this FQID. + In order to cause TimeOut frames to be discarded, this queue should be configured accordingly*/ + tmpReg32 |= p_Manip->reassmParams.fqidForTimeOutFrames; + WRITE_UINT32(p_Manip->reassmParams.p_ReassCommonTbl->timeoutModeAndFqid, + tmpReg32); + + /* Calculation the size of IP Reassembly Frame Descriptor - number of frames that are allowed to be reassembled simultaneously + 129.*/ + size = p_Manip->reassmParams.maxNumFramesInProcess + 129; + + /*Allocation of IP Reassembly Frame Descriptor Indexes Pool - This pool resides in the MURAM */ + p_Manip->reassmParams.reassFrmDescrIndxPoolTblAddr = + PTR_TO_UINT(FM_MURAM_AllocMem(p_FmPcd->h_FmMuram, + (uint32_t)(size * 2), + 256)); + if (!p_Manip->reassmParams.reassFrmDescrIndxPoolTblAddr) + RETURN_ERROR( + MAJOR, E_NO_MEMORY, + ("MURAM alloc for Reassembly frame descriptor indexes pool")); + + MemSet8(UINT_TO_PTR(p_Manip->reassmParams.reassFrmDescrIndxPoolTblAddr), + 0, (uint32_t)(size * 2)); + + /* The entries in IP Reassembly Frame Descriptor Indexes Pool contains indexes starting with 1 up to + the maximum number of frames that are allowed to be reassembled simultaneously + 128. + The last entry in this pool must contain the index zero*/ + for (i = 0; i < (size - 1); i++) + WRITE_UINT16( + *(uint16_t *)PTR_MOVE(UINT_TO_PTR(p_Manip->reassmParams.reassFrmDescrIndxPoolTblAddr), (i<<1)), + (uint16_t)(i+1)); + + /* Sets the IP Reassembly Frame Descriptor Indexes Pool offset from MURAM */ + tmpReg32 = (uint32_t)(XX_VirtToPhys( + UINT_TO_PTR(p_Manip->reassmParams.reassFrmDescrIndxPoolTblAddr)) + - p_FmPcd->physicalMuramBase); + WRITE_UINT32( + p_Manip->reassmParams.p_ReassCommonTbl->reassFrmDescIndexPoolTblPtr, + tmpReg32); + + /* Allocation of the Reassembly Frame Descriptors Pool - This pool resides in external memory. + The number of entries in this pool should be equal to the number of entries in IP Reassembly Frame Descriptor Indexes Pool.*/ + p_Manip->reassmParams.reassFrmDescrPoolTblAddr = + PTR_TO_UINT(XX_MallocSmart((uint32_t)(size * 64), p_Manip->reassmParams.dataMemId, 64)); + + if (!p_Manip->reassmParams.reassFrmDescrPoolTblAddr) + RETURN_ERROR(MAJOR, E_NO_MEMORY, ("Memory allocation FAILED")); + + MemSet8(UINT_TO_PTR(p_Manip->reassmParams.reassFrmDescrPoolTblAddr), 0, + (uint32_t)(size * 64)); + + /* Sets the Reassembly Frame Descriptors Pool and liodn offset*/ + tmpReg64 = (uint64_t)(XX_VirtToPhys( + UINT_TO_PTR(p_Manip->reassmParams.reassFrmDescrPoolTblAddr))); + tmpReg64 |= ((uint64_t)(p_Manip->reassmParams.dataLiodnOffset + & FM_PCD_MANIP_REASM_LIODN_MASK) + << (uint64_t)FM_PCD_MANIP_REASM_LIODN_SHIFT); + tmpReg64 |= ((uint64_t)(p_Manip->reassmParams.dataLiodnOffset + & FM_PCD_MANIP_REASM_ELIODN_MASK) + << (uint64_t)FM_PCD_MANIP_REASM_ELIODN_SHIFT); + WRITE_UINT32( + p_Manip->reassmParams.p_ReassCommonTbl->liodnAndReassFrmDescPoolPtrHi, + (uint32_t)(tmpReg64 >> 32)); + WRITE_UINT32( + p_Manip->reassmParams.p_ReassCommonTbl->reassFrmDescPoolPtrLow, + (uint32_t)tmpReg64); + + /*Allocation of the TimeOut table - This table resides in the MURAM. + The number of entries in this table is identical to the number of entries in the Reassembly Frame Descriptors Pool*/ + p_Manip->reassmParams.timeOutTblAddr = + PTR_TO_UINT(FM_MURAM_AllocMem(p_FmPcd->h_FmMuram, (uint32_t)(size * 8),8)); + + if (!p_Manip->reassmParams.timeOutTblAddr) + RETURN_ERROR(MAJOR, E_NO_MEMORY, + ("MURAM alloc for Reassembly timeout table")); + + MemSet8(UINT_TO_PTR(p_Manip->reassmParams.timeOutTblAddr), 0, + (uint16_t)(size * 8)); + + /* Sets the TimeOut table offset from MURAM */ + tmpReg32 = (uint32_t)(XX_VirtToPhys( + UINT_TO_PTR(p_Manip->reassmParams.timeOutTblAddr)) + - p_FmPcd->physicalMuramBase); + WRITE_UINT32(p_Manip->reassmParams.p_ReassCommonTbl->timeOutTblPtr, + tmpReg32); + + /* Sets the Expiration Delay */ + tmpReg32 = 0; + tmpReg32 |= (((uint32_t)(1 << bitFor1Micro)) + * p_Manip->reassmParams.timeoutThresholdForReassmProcess); + WRITE_UINT32(p_Manip->reassmParams.p_ReassCommonTbl->expirationDelay, + tmpReg32); + + err = FmPcdRegisterReassmPort(p_FmPcd, + p_Manip->reassmParams.p_ReassCommonTbl); + if (err != E_OK) + { + FM_MURAM_FreeMem(p_FmPcd->h_FmMuram, + p_Manip->reassmParams.p_ReassCommonTbl); + RETURN_ERROR(MAJOR, err, ("port registration")); + } + + return err; +} + +static t_Error CreateReassTable(t_FmPcdManip *p_Manip, e_NetHeaderType hdr) +{ + t_FmPcd *p_FmPcd = p_Manip->h_FmPcd; + uint32_t tmpReg32, autoLearnHashTblSize; + uint32_t numOfWays, setSize, setSizeCode, keySize; + uint32_t waySize, numOfSets, numOfEntries; + uint64_t tmpReg64; + uint16_t minFragSize; + uint16_t maxReassemSize; + uintptr_t *p_AutoLearnHashTblAddr, *p_AutoLearnSetLockTblAddr; + t_ReassTbl **p_ReassTbl; + + switch (hdr) + { + case HEADER_TYPE_IPv4: + p_ReassTbl = &p_Manip->reassmParams.ip.p_Ipv4ReassTbl; + p_AutoLearnHashTblAddr = + &p_Manip->reassmParams.ip.ipv4AutoLearnHashTblAddr; + p_AutoLearnSetLockTblAddr = + &p_Manip->reassmParams.ip.ipv4AutoLearnSetLockTblAddr; + minFragSize = p_Manip->reassmParams.ip.minFragSize[0]; + maxReassemSize = 0; + numOfWays = p_Manip->reassmParams.ip.numOfFramesPerHashEntry[0]; + keySize = 4 + 4 + 1 + 2; /* 3-tuple + IP-Id */ + break; + case HEADER_TYPE_IPv6: + p_ReassTbl = &p_Manip->reassmParams.ip.p_Ipv6ReassTbl; + p_AutoLearnHashTblAddr = + &p_Manip->reassmParams.ip.ipv6AutoLearnHashTblAddr; + p_AutoLearnSetLockTblAddr = + &p_Manip->reassmParams.ip.ipv6AutoLearnSetLockTblAddr; + minFragSize = p_Manip->reassmParams.ip.minFragSize[1]; + maxReassemSize = 0; + numOfWays = p_Manip->reassmParams.ip.numOfFramesPerHashEntry[1]; + keySize = 16 + 16 + 4; /* 2-tuple + IP-Id */ + if (numOfWays > e_FM_PCD_MANIP_SIX_WAYS_HASH) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("num of ways")); + break; + case HEADER_TYPE_CAPWAP: + p_ReassTbl = &p_Manip->reassmParams.capwap.p_ReassTbl; + p_AutoLearnHashTblAddr = + &p_Manip->reassmParams.capwap.autoLearnHashTblAddr; + p_AutoLearnSetLockTblAddr = + &p_Manip->reassmParams.capwap.autoLearnSetLockTblAddr; + minFragSize = 0; + maxReassemSize = p_Manip->reassmParams.capwap.maxRessembledsSize; + numOfWays = p_Manip->reassmParams.capwap.numOfFramesPerHashEntry; + keySize = 4; + break; + default: + RETURN_ERROR(MAJOR, E_NOT_SUPPORTED, ("header type")); + } + keySize += 2; /* 2 bytes reserved for RFDIndex */ +#if (DPAA_VERSION >= 11) + keySize += 2; /* 2 bytes reserved */ +#endif /* (DPAA_VERSION >= 11) */ + waySize = ROUND_UP(keySize, 8); + + /* Allocates the Reassembly Parameters Table - This table is located in the MURAM.*/ + *p_ReassTbl = (t_ReassTbl *)FM_MURAM_AllocMem( + p_FmPcd->h_FmMuram, FM_PCD_MANIP_REASM_TABLE_SIZE, + FM_PCD_MANIP_REASM_TABLE_ALIGN); + if (!*p_ReassTbl) + RETURN_ERROR( MAJOR, E_NO_MEMORY, + ("MURAM alloc for Reassembly specific parameters table")); + memset(*p_ReassTbl, 0, sizeof(t_ReassTbl)); + + /* Sets the Reassembly common Parameters table offset from MURAM in the Reassembly Table descriptor*/ + tmpReg32 = (uint32_t)(XX_VirtToPhys(p_Manip->reassmParams.p_ReassCommonTbl) + - p_FmPcd->physicalMuramBase); + WRITE_UINT32((*p_ReassTbl)->reassCommonPrmTblPtr, tmpReg32); + + /* Calculate set size (set size is rounded-up to next power of 2) */ + NEXT_POWER_OF_2(numOfWays * waySize, setSize); + + /* Get set size code */ + LOG2(setSize, setSizeCode); + + /* Sets ways number and set size code */ + WRITE_UINT16((*p_ReassTbl)->waysNumAndSetSize, + (uint16_t)((numOfWays << 8) | setSizeCode)); + + /* It is recommended that the total number of entries in this table + (number of sets * number of ways) will be twice the number of frames that + are expected to be reassembled simultaneously.*/ + numOfEntries = (uint32_t)(p_Manip->reassmParams.maxNumFramesInProcess * 2); + + /* sets number calculation - number of entries = number of sets * number of ways */ + numOfSets = numOfEntries / numOfWays; + + /* Sets AutoLearnHashKeyMask*/ + NEXT_POWER_OF_2(numOfSets, numOfSets); + + WRITE_UINT16((*p_ReassTbl)->autoLearnHashKeyMask, + (uint16_t)(numOfSets - 1)); + + /* Allocation of Reassembly Automatic Learning Hash Table - This table resides in external memory. + The size of this table is determined by the number of sets and the set size. + Table size = set size * number of sets + This table base address should be aligned to SetSize.*/ + autoLearnHashTblSize = numOfSets * setSize; + + *p_AutoLearnHashTblAddr = + PTR_TO_UINT(XX_MallocSmart(autoLearnHashTblSize, p_Manip->reassmParams.dataMemId, setSize)); + if (!*p_AutoLearnHashTblAddr) + { + FM_MURAM_FreeMem(p_FmPcd->h_FmMuram, *p_ReassTbl); + *p_ReassTbl = NULL; + RETURN_ERROR(MAJOR, E_NO_MEMORY, ("Memory allocation FAILED")); + } + MemSet8(UINT_TO_PTR(*p_AutoLearnHashTblAddr), 0, autoLearnHashTblSize); + + /* Sets the Reassembly Automatic Learning Hash Table and liodn offset */ + tmpReg64 = ((uint64_t)(p_Manip->reassmParams.dataLiodnOffset + & FM_PCD_MANIP_REASM_LIODN_MASK) + << (uint64_t)FM_PCD_MANIP_REASM_LIODN_SHIFT); + tmpReg64 |= ((uint64_t)(p_Manip->reassmParams.dataLiodnOffset + & FM_PCD_MANIP_REASM_ELIODN_MASK) + << (uint64_t)FM_PCD_MANIP_REASM_ELIODN_SHIFT); + tmpReg64 |= XX_VirtToPhys(UINT_TO_PTR(*p_AutoLearnHashTblAddr)); + WRITE_UINT32( (*p_ReassTbl)->liodnAlAndAutoLearnHashTblPtrHi, + (uint32_t)(tmpReg64 >> 32)); + WRITE_UINT32((*p_ReassTbl)->autoLearnHashTblPtrLow, (uint32_t)tmpReg64); + + /* Allocation of the Set Lock table - This table resides in external memory + The size of this table is (number of sets in the Reassembly Automatic Learning Hash table)*4 bytes. + This table resides in external memory and its base address should be 4-byte aligned */ + *p_AutoLearnSetLockTblAddr = + PTR_TO_UINT(XX_MallocSmart((uint32_t)(numOfSets * 4), p_Manip->reassmParams.dataMemId, 4)); + if (!*p_AutoLearnSetLockTblAddr) + { + FM_MURAM_FreeMem(p_FmPcd->h_FmMuram, *p_ReassTbl); + *p_ReassTbl = NULL; + XX_FreeSmart(UINT_TO_PTR(*p_AutoLearnHashTblAddr)); + *p_AutoLearnHashTblAddr = 0; + RETURN_ERROR(MAJOR, E_NO_MEMORY, ("Memory allocation FAILED")); + } + MemSet8(UINT_TO_PTR(*p_AutoLearnSetLockTblAddr), 0, (numOfSets * 4)); + + /* sets Set Lock table pointer and liodn offset*/ + tmpReg64 = ((uint64_t)(p_Manip->reassmParams.dataLiodnOffset + & FM_PCD_MANIP_REASM_LIODN_MASK) + << (uint64_t)FM_PCD_MANIP_REASM_LIODN_SHIFT); + tmpReg64 |= ((uint64_t)(p_Manip->reassmParams.dataLiodnOffset + & FM_PCD_MANIP_REASM_ELIODN_MASK) + << (uint64_t)FM_PCD_MANIP_REASM_ELIODN_SHIFT); + tmpReg64 |= XX_VirtToPhys(UINT_TO_PTR(*p_AutoLearnSetLockTblAddr)); + WRITE_UINT32( (*p_ReassTbl)->liodnSlAndAutoLearnSetLockTblPtrHi, + (uint32_t)(tmpReg64 >> 32)); + WRITE_UINT32((*p_ReassTbl)->autoLearnSetLockTblPtrLow, (uint32_t)tmpReg64); + + /* Sets user's requested minimum fragment size (in Bytes) for First/Middle fragment */ + WRITE_UINT16((*p_ReassTbl)->minFragSize, minFragSize); + + WRITE_UINT16((*p_ReassTbl)->maxReassemblySize, maxReassemSize); + + return E_OK; +} + +static t_Error UpdateInitReasm(t_Handle h_FmPcd, t_Handle h_PcdParams, + t_Handle h_FmPort, t_FmPcdManip *p_Manip, + t_Handle h_Ad, bool validate) +{ + t_FmPortGetSetCcParams fmPortGetSetCcParams; + uint32_t tmpReg32; + t_Error err; + t_FmPortPcdParams *p_PcdParams = (t_FmPortPcdParams *)h_PcdParams; +#if (DPAA_VERSION >= 11) + t_FmPcdCtrlParamsPage *p_ParamsPage; +#endif /* (DPAA_VERSION >= 11) */ + + SANITY_CHECK_RETURN_ERROR(p_Manip, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(!p_Manip->frag, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR( + (p_Manip->opcode == HMAN_OC_IP_REASSEMBLY) || (p_Manip->opcode == HMAN_OC_CAPWAP_REASSEMBLY), + E_INVALID_STATE); + SANITY_CHECK_RETURN_ERROR(h_FmPcd, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(!p_Manip->updateParams || h_PcdParams, + E_INVALID_HANDLE); + + UNUSED(h_Ad); + + if (!p_Manip->updateParams) + return E_OK; + + if (p_Manip->h_FmPcd != h_FmPcd) + RETURN_ERROR( + MAJOR, E_INVALID_STATE, + ("handler of PCD previously was initiated by different value")); + + if (p_Manip->updateParams) + { + if ((!(p_Manip->updateParams + & (NUM_OF_TASKS | NUM_OF_EXTRA_TASKS | DISCARD_MASK))) + || ((p_Manip->shadowUpdateParams + & (NUM_OF_TASKS | NUM_OF_EXTRA_TASKS | DISCARD_MASK)))) + RETURN_ERROR( + MAJOR, E_INVALID_STATE, + ("in this stage parameters from Port has not be updated")); + + fmPortGetSetCcParams.setCcParams.type = 0; + if (p_Manip->opcode == HMAN_OC_CAPWAP_REASSEMBLY) + { + fmPortGetSetCcParams.setCcParams.type |= UPDATE_OFP_DPTE; + fmPortGetSetCcParams.setCcParams.ofpDpde = 0xF; + } + fmPortGetSetCcParams.getCcParams.type = p_Manip->updateParams | FM_REV; + if ((err = FmPortGetSetCcParams(h_FmPort, &fmPortGetSetCcParams)) + != E_OK) + RETURN_ERROR(MAJOR, err, NO_MSG); + if (fmPortGetSetCcParams.getCcParams.type + & (NUM_OF_TASKS | NUM_OF_EXTRA_TASKS | DISCARD_MASK | FM_REV)) + RETURN_ERROR(MAJOR, E_INVALID_STATE, + ("offset of the data wasn't configured previously")); + if (p_Manip->updateParams + & (NUM_OF_TASKS | NUM_OF_EXTRA_TASKS | DISCARD_MASK)) + { + t_FmPcd *p_FmPcd = (t_FmPcd *)h_FmPcd; + uint8_t *p_Ptr, i, totalNumOfTnums; + + totalNumOfTnums = + (uint8_t)(fmPortGetSetCcParams.getCcParams.numOfTasks + + fmPortGetSetCcParams.getCcParams.numOfExtraTasks); + + p_Manip->reassmParams.internalBufferPoolAddr = + PTR_TO_UINT(FM_MURAM_AllocMem(p_FmPcd->h_FmMuram, + (uint32_t)(totalNumOfTnums * BMI_FIFO_UNITS), + BMI_FIFO_UNITS)); + if (!p_Manip->reassmParams.internalBufferPoolAddr) + RETURN_ERROR( + MAJOR, E_NO_MEMORY, + ("MURAM alloc for Reassembly internal buffers pool")); + MemSet8( + UINT_TO_PTR(p_Manip->reassmParams.internalBufferPoolAddr), + 0, (uint32_t)(totalNumOfTnums * BMI_FIFO_UNITS)); + + p_Manip->reassmParams.internalBufferPoolManagementIndexAddr = + PTR_TO_UINT(FM_MURAM_AllocMem(p_FmPcd->h_FmMuram, + (uint32_t)(5 + totalNumOfTnums), + 4)); + if (!p_Manip->reassmParams.internalBufferPoolManagementIndexAddr) + RETURN_ERROR( + MAJOR, + E_NO_MEMORY, + ("MURAM alloc for Reassembly internal buffers management")); + + p_Ptr = + (uint8_t*)UINT_TO_PTR(p_Manip->reassmParams.internalBufferPoolManagementIndexAddr); + WRITE_UINT32( + *(uint32_t*)p_Ptr, + (uint32_t)(XX_VirtToPhys(UINT_TO_PTR(p_Manip->reassmParams.internalBufferPoolAddr)) - p_FmPcd->physicalMuramBase)); + for (i = 0, p_Ptr += 4; i < totalNumOfTnums; i++, p_Ptr++) + WRITE_UINT8(*p_Ptr, i); + WRITE_UINT8(*p_Ptr, 0xFF); + + tmpReg32 = + (4 << FM_PCD_MANIP_REASM_COMMON_INT_BUFFER_IDX_SHIFT) + | ((uint32_t)(XX_VirtToPhys( + UINT_TO_PTR(p_Manip->reassmParams.internalBufferPoolManagementIndexAddr)) + - p_FmPcd->physicalMuramBase)); + WRITE_UINT32( + p_Manip->reassmParams.p_ReassCommonTbl->internalBufferManagement, + tmpReg32); + + p_Manip->updateParams &= ~(NUM_OF_TASKS | NUM_OF_EXTRA_TASKS + | DISCARD_MASK); + p_Manip->shadowUpdateParams |= (NUM_OF_TASKS | NUM_OF_EXTRA_TASKS + | DISCARD_MASK); + } + } + + if (p_Manip->opcode == HMAN_OC_CAPWAP_REASSEMBLY) + { + if (p_Manip->reassmParams.capwap.h_Scheme) + { + p_PcdParams->p_KgParams->h_Schemes[p_PcdParams->p_KgParams->numOfSchemes] = + p_Manip->reassmParams.capwap.h_Scheme; + p_PcdParams->p_KgParams->numOfSchemes++; + } + + } + else + { + if (p_Manip->reassmParams.ip.h_Ipv4Scheme) + { + p_PcdParams->p_KgParams->h_Schemes[p_PcdParams->p_KgParams->numOfSchemes] = + p_Manip->reassmParams.ip.h_Ipv4Scheme; + p_PcdParams->p_KgParams->numOfSchemes++; + } + if (p_Manip->reassmParams.ip.h_Ipv6Scheme) + { + p_PcdParams->p_KgParams->h_Schemes[p_PcdParams->p_KgParams->numOfSchemes] = + p_Manip->reassmParams.ip.h_Ipv6Scheme; + p_PcdParams->p_KgParams->numOfSchemes++; + } +#if (DPAA_VERSION >= 11) + if (fmPortGetSetCcParams.getCcParams.revInfo.majorRev >= 6) + { + if ((err = FmPortSetGprFunc(h_FmPort, e_FM_PORT_GPR_MURAM_PAGE, + (void**)&p_ParamsPage)) != E_OK) + RETURN_ERROR(MAJOR, err, NO_MSG); + + tmpReg32 = NIA_ENG_KG; + if (p_Manip->reassmParams.ip.h_Ipv4Scheme) + { + tmpReg32 |= NIA_KG_DIRECT; + tmpReg32 |= NIA_KG_CC_EN; + tmpReg32 |= FmPcdKgGetSchemeId( + p_Manip->reassmParams.ip.h_Ipv4Scheme); + WRITE_UINT32(p_ParamsPage->iprIpv4Nia, tmpReg32); + } + if (p_Manip->reassmParams.ip.h_Ipv6Scheme) + { + tmpReg32 &= ~NIA_AC_MASK; + tmpReg32 |= NIA_KG_DIRECT; + tmpReg32 |= NIA_KG_CC_EN; + tmpReg32 |= FmPcdKgGetSchemeId( + p_Manip->reassmParams.ip.h_Ipv6Scheme); + WRITE_UINT32(p_ParamsPage->iprIpv6Nia, tmpReg32); + } + } +#else + if (fmPortGetSetCcParams.getCcParams.revInfo.majorRev < 6) + { + WRITE_UINT32(p_Manip->reassmParams.p_ReassCommonTbl->discardMask, + fmPortGetSetCcParams.getCcParams.discardMask); + } +#endif /* (DPAA_VERSION >= 11) */ + } + return E_OK; +} + +#if (DPAA_VERSION == 10) +static t_Error FmPcdFragHcScratchPoolFill(t_Handle h_FmPcd, uint8_t scratchBpid) +{ + t_FmPcd *p_FmPcd = (t_FmPcd*)h_FmPcd; + t_FmPcdCcFragScratchPoolCmdParams fmPcdCcFragScratchPoolCmdParams; + t_Error err; + + SANITY_CHECK_RETURN_ERROR(p_FmPcd, E_INVALID_HANDLE); + + memset(&fmPcdCcFragScratchPoolCmdParams, 0, sizeof(t_FmPcdCcFragScratchPoolCmdParams)); + + fmPcdCcFragScratchPoolCmdParams.numOfBuffers = NUM_OF_SCRATCH_POOL_BUFFERS; + fmPcdCcFragScratchPoolCmdParams.bufferPoolId = scratchBpid; + if ((err = FmHcPcdCcIpFragScratchPollCmd(p_FmPcd->h_Hc, TRUE, &fmPcdCcFragScratchPoolCmdParams)) != E_OK) + RETURN_ERROR(MAJOR, err, NO_MSG); + + if (fmPcdCcFragScratchPoolCmdParams.numOfBuffers != 0) + RETURN_ERROR(MAJOR, E_INVALID_STATE, ("Fill scratch pool failed," + "Failed to release %d buffers to the BM (missing FBPRs)", + fmPcdCcFragScratchPoolCmdParams.numOfBuffers)); + + return E_OK; +} + +static t_Error FmPcdFragHcScratchPoolEmpty(t_Handle h_FmPcd, uint8_t scratchBpid) +{ + t_FmPcd *p_FmPcd = (t_FmPcd*)h_FmPcd; + t_FmPcdCcFragScratchPoolCmdParams fmPcdCcFragScratchPoolCmdParams; + t_Error err; + + SANITY_CHECK_RETURN_ERROR(p_FmPcd, E_INVALID_HANDLE); + + memset(&fmPcdCcFragScratchPoolCmdParams, 0, sizeof(t_FmPcdCcFragScratchPoolCmdParams)); + + fmPcdCcFragScratchPoolCmdParams.bufferPoolId = scratchBpid; + if ((err = FmHcPcdCcIpFragScratchPollCmd(p_FmPcd->h_Hc, FALSE, &fmPcdCcFragScratchPoolCmdParams)) != E_OK) + RETURN_ERROR(MAJOR, err, NO_MSG); + + return E_OK; +} +#endif /* (DPAA_VERSION == 10) */ + +static void ReleaseManipHandler(t_FmPcdManip *p_Manip, t_FmPcd *p_FmPcd) +{ + if (p_Manip->h_Ad) + { + if (p_Manip->muramAllocate) + FM_MURAM_FreeMem(p_FmPcd->h_FmMuram, p_Manip->h_Ad); + else + XX_Free(p_Manip->h_Ad); + p_Manip->h_Ad = NULL; + } + if (p_Manip->p_Template) + { + FM_MURAM_FreeMem(p_FmPcd->h_FmMuram, p_Manip->p_Template); + p_Manip->p_Template = NULL; + } +#if (defined(FM_CAPWAP_SUPPORT) && (DPAA_VERSION == 10)) + if (p_Manip->h_Frag) + { + if (p_Manip->capwapFragParams.p_AutoLearnHashTbl) + FM_MURAM_FreeMem(p_FmPcd->h_FmMuram, + p_Manip->capwapFragParams.p_AutoLearnHashTbl); + if (p_Manip->capwapFragParams.p_ReassmFrmDescrPoolTbl) + FM_MURAM_FreeMem(p_FmPcd->h_FmMuram, + p_Manip->capwapFragParams.p_ReassmFrmDescrPoolTbl); + if (p_Manip->capwapFragParams.p_ReassmFrmDescrIndxPoolTbl) + FM_MURAM_FreeMem(p_FmPcd->h_FmMuram, + p_Manip->capwapFragParams.p_ReassmFrmDescrIndxPoolTbl); + if (p_Manip->capwapFragParams.p_TimeOutTbl) + FM_MURAM_FreeMem(p_FmPcd->h_FmMuram, + p_Manip->capwapFragParams.p_TimeOutTbl); + FM_MURAM_FreeMem(p_FmPcd->h_FmMuram, p_Manip->h_Frag); + + } +#endif /* (defined(FM_CAPWAP_SUPPORT) && (DPAA_VERSION == 10)) */ + if (p_Manip->frag) + { + if (p_Manip->fragParams.p_Frag) + { +#if (DPAA_VERSION == 10) + FmPcdFragHcScratchPoolEmpty((t_Handle)p_FmPcd, p_Manip->fragParams.scratchBpid); +#endif /* (DPAA_VERSION == 10) */ + + FM_MURAM_FreeMem(p_FmPcd->h_FmMuram, p_Manip->fragParams.p_Frag); + } + } + else + if (p_Manip->reassm) + { + FmPcdUnregisterReassmPort(p_FmPcd, + p_Manip->reassmParams.p_ReassCommonTbl); + + if (p_Manip->reassmParams.timeOutTblAddr) + FM_MURAM_FreeMem( + p_FmPcd->h_FmMuram, + UINT_TO_PTR(p_Manip->reassmParams.timeOutTblAddr)); + if (p_Manip->reassmParams.reassFrmDescrPoolTblAddr) + XX_FreeSmart( + UINT_TO_PTR(p_Manip->reassmParams.reassFrmDescrPoolTblAddr)); + if (p_Manip->reassmParams.p_ReassCommonTbl) + FM_MURAM_FreeMem(p_FmPcd->h_FmMuram, + p_Manip->reassmParams.p_ReassCommonTbl); + if (p_Manip->reassmParams.reassFrmDescrIndxPoolTblAddr) + FM_MURAM_FreeMem( + p_FmPcd->h_FmMuram, + UINT_TO_PTR(p_Manip->reassmParams.reassFrmDescrIndxPoolTblAddr)); + if (p_Manip->reassmParams.internalBufferPoolManagementIndexAddr) + FM_MURAM_FreeMem( + p_FmPcd->h_FmMuram, + UINT_TO_PTR(p_Manip->reassmParams.internalBufferPoolManagementIndexAddr)); + if (p_Manip->reassmParams.internalBufferPoolAddr) + FM_MURAM_FreeMem( + p_FmPcd->h_FmMuram, + UINT_TO_PTR(p_Manip->reassmParams.internalBufferPoolAddr)); + if (p_Manip->reassmParams.hdr == HEADER_TYPE_CAPWAP) + { + + } + else + { + if (p_Manip->reassmParams.ip.ipv4AutoLearnHashTblAddr) + XX_FreeSmart( + UINT_TO_PTR(p_Manip->reassmParams.ip.ipv4AutoLearnHashTblAddr)); + if (p_Manip->reassmParams.ip.ipv6AutoLearnHashTblAddr) + XX_FreeSmart( + UINT_TO_PTR(p_Manip->reassmParams.ip.ipv6AutoLearnHashTblAddr)); + if (p_Manip->reassmParams.ip.ipv4AutoLearnSetLockTblAddr) + XX_FreeSmart( + UINT_TO_PTR(p_Manip->reassmParams.ip.ipv4AutoLearnSetLockTblAddr)); + if (p_Manip->reassmParams.ip.ipv6AutoLearnSetLockTblAddr) + XX_FreeSmart( + UINT_TO_PTR(p_Manip->reassmParams.ip.ipv6AutoLearnSetLockTblAddr)); + if (p_Manip->reassmParams.ip.p_Ipv4ReassTbl) + FM_MURAM_FreeMem(p_FmPcd->h_FmMuram, + p_Manip->reassmParams.ip.p_Ipv4ReassTbl); + if (p_Manip->reassmParams.ip.p_Ipv6ReassTbl) + FM_MURAM_FreeMem(p_FmPcd->h_FmMuram, + p_Manip->reassmParams.ip.p_Ipv6ReassTbl); + if (p_Manip->reassmParams.ip.h_Ipv6Ad) + XX_FreeSmart(p_Manip->reassmParams.ip.h_Ipv6Ad); + if (p_Manip->reassmParams.ip.h_Ipv4Ad) + XX_FreeSmart(p_Manip->reassmParams.ip.h_Ipv4Ad); + } + } + + if (p_Manip->p_StatsTbl) + FM_MURAM_FreeMem(p_FmPcd->h_FmMuram, p_Manip->p_StatsTbl); +} + +#if (defined(FM_CAPWAP_SUPPORT) && (DPAA_VERSION == 10)) +static t_Error CheckManipParamsAndSetType(t_FmPcdManip *p_Manip, t_FmPcdManipParams *p_ManipParams) +{ + if (p_ManipParams->u.hdr.rmv) + { + switch (p_ManipParams->u.hdr.rmvParams.type) + { + case (e_FM_PCD_MANIP_RMV_BY_HDR): + switch (p_ManipParams->u.hdr.rmvParams.u.byHdr.type) + { + case (e_FM_PCD_MANIP_RMV_BY_HDR_FROM_START) : + if (p_ManipParams->u.hdr.rmvParams.u.byHdr.u.fromStartByHdr.include) + { + switch (p_ManipParams->u.hdr.rmvParams.u.byHdr.u.fromStartByHdr.hdrInfo.hdr) + { + case (HEADER_TYPE_CAPWAP_DTLS) : + p_Manip->opcode = HMAN_OC_CAPWAP_RMV_DTLS_IF_EXIST; + p_Manip->muramAllocate = TRUE; + if (p_ManipParams->u.hdr.insrt) + RETURN_ERROR(MAJOR, E_INVALID_STATE, ("for CAPWAP_DTLS_HDR remove can not be insrt manipualtion after")); + if (p_ManipParams->fragOrReasm) + { + if (!p_ManipParams->fragOrReasmParams.frag) + { + switch (p_ManipParams->fragOrReasmParams.hdr) + { + case (HEADER_TYPE_CAPWAP): + p_Manip->opcode = HMAN_OC_CAPWAP_REASSEMBLY; + break; + default: + RETURN_ERROR(MAJOR, E_INVALID_STATE, ("unsupported header for Reassembly")); + } + } + else + RETURN_ERROR(MAJOR, E_INVALID_STATE, ("for this type of manipulation frag can not be TRUE")); + } + break; + default: + RETURN_ERROR(MAJOR, E_INVALID_STATE, ("non valid net header of remove location")); + } + } + else + { + switch (p_ManipParams->u.hdr.rmvParams.u.byHdr.u.fromStartByHdr.hdrInfo.hdr) + { + case (HEADER_TYPE_CAPWAP_DTLS) : + case (HEADER_TYPE_CAPWAP) : + if (p_ManipParams->fragOrReasm || p_ManipParams->u.hdr.insrt) + RETURN_ERROR(MAJOR, E_INVALID_STATE, ("for the type of remove e_FM_PCD_MANIP_RMV_FROM_START_OF_FRAME_TILL_CAPWAP can not be insert or fragOrReasm TRUE")); + p_Manip->opcode = HMAN_OC_RMV_N_OR_INSRT_INT_FRM_HDR; + p_Manip->muramAllocate = TRUE; + p_ManipParams->u.hdr.insrt = TRUE; //internal frame header + break; + default : + RETURN_ERROR(MAJOR, E_INVALID_STATE, ("invalid type of remove manipulation")); + } + } + break; + default : + RETURN_ERROR(MAJOR, E_INVALID_STATE, ("invalid type of remove manipulation")); + } + break; + default: + RETURN_ERROR(MAJOR, E_INVALID_STATE, ("invalid type of remove manipulation")); + } + } + else if (p_ManipParams->u.hdr.insrt) + { + switch (p_ManipParams->u.hdr.insrtParams.type) + { + case (e_FM_PCD_MANIP_INSRT_BY_TEMPLATE) : + + p_Manip->opcode = HMAN_OC_INSRT_HDR_BY_TEMPL_N_OR_FRAG_AFTER; + p_Manip->muramAllocate = FALSE; + if (p_ManipParams->fragOrReasm) + { + if (p_ManipParams->fragOrReasmParams.frag) + { + switch (p_ManipParams->fragOrReasmParams.hdr) + { + case (HEADER_TYPE_CAPWAP): + p_Manip->opcode = HMAN_OC_CAPWAP_FRAGMENTATION; + break; + default: + RETURN_ERROR(MAJOR, E_INVALID_STATE, ("Invalid header for fragmentation")); + } + } + else + RETURN_ERROR(MAJOR, E_INVALID_STATE,("can not reach this point")); + } + break; + + default: + RETURN_ERROR(MAJOR, E_INVALID_STATE, ("for only isert manipulation unsupported type")); + } + } + else if (p_ManipParams->fragOrReasm) + { + if (p_ManipParams->fragOrReasmParams.frag) + { + switch (p_ManipParams->fragOrReasmParams.hdr) + { + case (HEADER_TYPE_CAPWAP): + p_Manip->opcode = HMAN_OC_CAPWAP_FRAGMENTATION; + p_Manip->muramAllocate = FALSE; + break; + default: + RETURN_ERROR(MAJOR, E_INVALID_STATE, ("Unsupported header for fragmentation")); + } + } + else + { + switch (p_ManipParams->fragOrReasmParams.hdr) + { + case (HEADER_TYPE_CAPWAP): + RETURN_ERROR(MAJOR, E_INVALID_STATE, ("Reassembly has to be with additional operation - rmv = TRUE, type of remove - e_FM_PCD_MANIP_RMV_FROM_START_OF_FRAME_INCLUDE_SPECIFIC_LOCATION,type = e_FM_PCD_MANIP_LOC_BY_HDR, hdr = HEADER_TYPE_CAPWAP_DTLS")); + default: + RETURN_ERROR(MAJOR, E_INVALID_STATE, ("Unsupported header for reassembly")); + } + } + + } + else + RETURN_ERROR(MAJOR, E_INVALID_STATE, ("User didn't ask for any manipulation")); + + p_Manip->insrt = p_ManipParams->u.hdr.insrt; + p_Manip->rmv = p_ManipParams->u.hdr.rmv; + + return E_OK; +} + +#else /* not (defined(FM_CAPWAP_SUPPORT) && (DPAA_VERSION == 10)) */ +static t_Error CheckManipParamsAndSetType(t_FmPcdManip *p_Manip, + t_FmPcdManipParams *p_ManipParams) +{ + switch (p_ManipParams->type) + { + case e_FM_PCD_MANIP_HDR: + /* Check that next-manip is not already used */ + if (p_ManipParams->h_NextManip) + { + if (!MANIP_IS_FIRST(p_ManipParams->h_NextManip)) + RETURN_ERROR( + MAJOR, E_INVALID_STATE, + ("h_NextManip is already a part of another chain")); + if ((MANIP_GET_TYPE(p_ManipParams->h_NextManip) + != e_FM_PCD_MANIP_HDR) && + (MANIP_GET_TYPE(p_ManipParams->h_NextManip) + != e_FM_PCD_MANIP_FRAG)) + RETURN_ERROR( + MAJOR, + E_NOT_SUPPORTED, + ("For a Header Manipulation node - no support of h_NextManip of type other than Header Manipulation or Fragmentation.")); + } + + if (p_ManipParams->u.hdr.rmv) + { + switch (p_ManipParams->u.hdr.rmvParams.type) + { + case (e_FM_PCD_MANIP_RMV_BY_HDR): + switch (p_ManipParams->u.hdr.rmvParams.u.byHdr.type) + { + case (e_FM_PCD_MANIP_RMV_BY_HDR_SPECIFIC_L2): + break; +#if (DPAA_VERSION >= 11) + case (e_FM_PCD_MANIP_RMV_BY_HDR_CAPWAP): + break; + case (e_FM_PCD_MANIP_RMV_BY_HDR_FROM_START): + { + t_Error err; + uint8_t prsArrayOffset; + + err = + GetPrOffsetByHeaderOrField( + &p_ManipParams->u.hdr.rmvParams.u.byHdr.u.hdrInfo, + &prsArrayOffset); + if (err) + RETURN_ERROR(MAJOR, err, NO_MSG); + break; + } +#endif /* (DPAA_VERSION >= 11) */ + default: + RETURN_ERROR( + MAJOR, + E_INVALID_STATE, + ("invalid type of remove manipulation")); + } + break; + case (e_FM_PCD_MANIP_RMV_GENERIC): + break; + default: + RETURN_ERROR(MAJOR, E_INVALID_STATE, + ("invalid type of remove manipulation")); + } + p_Manip->opcode = HMAN_OC; + p_Manip->muramAllocate = TRUE; + p_Manip->rmv = TRUE; + } + else + if (p_ManipParams->u.hdr.insrt) + { + switch (p_ManipParams->u.hdr.insrtParams.type) + { + case (e_FM_PCD_MANIP_INSRT_BY_HDR): + { + switch (p_ManipParams->u.hdr.insrtParams.u.byHdr.type) + { + case (e_FM_PCD_MANIP_INSRT_BY_HDR_SPECIFIC_L2): + /* nothing to check */ + break; +#if (DPAA_VERSION >= 11) + case (e_FM_PCD_MANIP_INSRT_BY_HDR_IP): + if (p_ManipParams->u.hdr.insrtParams.u.byHdr.u.ipParams.insrt.size + % 4) + RETURN_ERROR( + MAJOR, + E_INVALID_VALUE, + ("IP inserted header must be of size which is a multiple of four bytes")); + break; + case (e_FM_PCD_MANIP_INSRT_BY_HDR_CAPWAP): + if (p_ManipParams->u.hdr.insrtParams.u.byHdr.u.insrt.size + % 4) + RETURN_ERROR( + MAJOR, + E_INVALID_VALUE, + ("CAPWAP inserted header must be of size which is a multiple of four bytes")); + break; + case (e_FM_PCD_MANIP_INSRT_BY_HDR_UDP): + case (e_FM_PCD_MANIP_INSRT_BY_HDR_UDP_LITE): + if (p_ManipParams->u.hdr.insrtParams.u.byHdr.u.insrt.size + != 8) + RETURN_ERROR( + MAJOR, + E_INVALID_VALUE, + ("Inserted header must be of size 8")); + break; +#endif /* (DPAA_VERSION >= 11) */ + default: + RETURN_ERROR( + MAJOR, + E_INVALID_STATE, + ("unsupported insert by header type")); + } + } + case (e_FM_PCD_MANIP_INSRT_GENERIC): + break; + default: + RETURN_ERROR( + MAJOR, + E_INVALID_STATE, + ("for only insert manipulation unsupported type")); + } + p_Manip->opcode = HMAN_OC; + p_Manip->muramAllocate = TRUE; + p_Manip->insrt = TRUE; + } + else + if (p_ManipParams->u.hdr.fieldUpdate) + { + /* Check parameters */ + if (p_ManipParams->u.hdr.fieldUpdateParams.type + == e_FM_PCD_MANIP_HDR_FIELD_UPDATE_VLAN) + { + if ((p_ManipParams->u.hdr.fieldUpdateParams.u.vlan.updateType + == e_FM_PCD_MANIP_HDR_FIELD_UPDATE_VLAN_VPRI) + && (p_ManipParams->u.hdr.fieldUpdateParams.u.vlan.u.vpri + > 7)) + RETURN_ERROR( + MAJOR, E_INVALID_VALUE, + ("vpri should get values of 0-7 ")); + if (p_ManipParams->u.hdr.fieldUpdateParams.u.vlan.updateType + == e_FM_PCD_MANIP_HDR_FIELD_UPDATE_DSCP_TO_VLAN) + { + int i; + + if (p_ManipParams->u.hdr.fieldUpdateParams.u.vlan.u.dscpToVpri.vpriDefVal + > 7) + RETURN_ERROR( + MAJOR, + E_INVALID_VALUE, + ("vpriDefVal should get values of 0-7 ")); + for (i = 0; i < FM_PCD_MANIP_DSCP_TO_VLAN_TRANS; + i++) + if (p_ManipParams->u.hdr.fieldUpdateParams.u.vlan.u.dscpToVpri.dscpToVpriTable[i] + & 0xf0) + RETURN_ERROR( + MAJOR, + E_INVALID_VALUE, + ("dscpToVpriTabl value out of range (0-15)")); + } + + } + + p_Manip->opcode = HMAN_OC; + p_Manip->muramAllocate = TRUE; + p_Manip->fieldUpdate = TRUE; + } + else + if (p_ManipParams->u.hdr.custom) + { + if (p_ManipParams->u.hdr.customParams.type == e_FM_PCD_MANIP_HDR_CUSTOM_GEN_FIELD_REPLACE) + { + + if ((p_ManipParams->u.hdr.customParams.u.genFieldReplace.size == 0) || + (p_ManipParams->u.hdr.customParams.u.genFieldReplace.size > 8)) + RETURN_ERROR( + MAJOR, E_INVALID_VALUE, + ("size should get values of 1-8 ")); + + if (p_ManipParams->u.hdr.customParams.u.genFieldReplace.srcOffset > 7) + RETURN_ERROR( + MAJOR, E_INVALID_VALUE, + ("srcOffset should be <= 7")); + + if ((p_ManipParams->u.hdr.customParams.u.genFieldReplace.srcOffset + + p_ManipParams->u.hdr.customParams.u.genFieldReplace.size) > 8) + RETURN_ERROR( + MAJOR, E_INVALID_VALUE, + ("(srcOffset + size) should be <= 8")); + + if ((p_ManipParams->u.hdr.customParams.u.genFieldReplace.dstOffset + + p_ManipParams->u.hdr.customParams.u.genFieldReplace.size) > 256) + RETURN_ERROR( + MAJOR, E_INVALID_VALUE, + ("(dstOffset + size) should be <= 256")); + + } + + p_Manip->opcode = HMAN_OC; + p_Manip->muramAllocate = TRUE; + p_Manip->custom = TRUE; + } + break; + case e_FM_PCD_MANIP_REASSEM: + if (p_ManipParams->h_NextManip) + RETURN_ERROR(MAJOR, E_NOT_SUPPORTED, + ("next manip with reassembly")); + switch (p_ManipParams->u.reassem.hdr) + { + case (HEADER_TYPE_IPv4): + p_Manip->reassmParams.hdr = HEADER_TYPE_IPv4; + p_Manip->opcode = HMAN_OC_IP_REASSEMBLY; + break; + case (HEADER_TYPE_IPv6): + p_Manip->reassmParams.hdr = HEADER_TYPE_IPv6; + p_Manip->opcode = HMAN_OC_IP_REASSEMBLY; + break; +#if (DPAA_VERSION >= 11) + case (HEADER_TYPE_CAPWAP): + p_Manip->reassmParams.hdr = HEADER_TYPE_CAPWAP; + p_Manip->opcode = HMAN_OC_CAPWAP_REASSEMBLY; + break; +#endif /* (DPAA_VERSION >= 11) */ + default: + RETURN_ERROR(MAJOR, E_NOT_SUPPORTED, + ("header for reassembly")); + } + break; + case e_FM_PCD_MANIP_FRAG: + if (p_ManipParams->h_NextManip) + RETURN_ERROR(MAJOR, E_NOT_SUPPORTED, + ("next manip with fragmentation")); + switch (p_ManipParams->u.frag.hdr) + { + case (HEADER_TYPE_IPv4): + case (HEADER_TYPE_IPv6): + p_Manip->opcode = HMAN_OC_IP_FRAGMENTATION; + break; +#if (DPAA_VERSION >= 11) + case (HEADER_TYPE_CAPWAP): + p_Manip->opcode = HMAN_OC_CAPWAP_FRAGMENTATION; + break; +#endif /* (DPAA_VERSION >= 11) */ + default: + RETURN_ERROR(MAJOR, E_NOT_SUPPORTED, + ("header for fragmentation")); + } + p_Manip->muramAllocate = TRUE; + break; + case e_FM_PCD_MANIP_SPECIAL_OFFLOAD: + switch (p_ManipParams->u.specialOffload.type) + { + case (e_FM_PCD_MANIP_SPECIAL_OFFLOAD_IPSEC): + p_Manip->opcode = HMAN_OC_IPSEC_MANIP; + p_Manip->muramAllocate = TRUE; + break; +#if (DPAA_VERSION >= 11) + case (e_FM_PCD_MANIP_SPECIAL_OFFLOAD_CAPWAP): + p_Manip->opcode = HMAN_OC_CAPWAP_MANIP; + p_Manip->muramAllocate = TRUE; + break; +#endif /* (DPAA_VERSION >= 11) */ + default: + RETURN_ERROR(MAJOR, E_NOT_SUPPORTED, + ("special offload type")); + } + break; + default: + RETURN_ERROR(MAJOR, E_NOT_SUPPORTED, ("manip type")); + } + + return E_OK; +} +#endif /* not (defined(FM_CAPWAP_SUPPORT) && (DPAA_VERSION == 10)) */ + +#if (defined(FM_CAPWAP_SUPPORT) && (DPAA_VERSION == 10)) + +static t_Error UpdateIndxStats(t_Handle h_FmPcd, + t_Handle h_FmPort, + t_FmPcdManip *p_Manip) +{ + t_FmPcd *p_FmPcd = (t_FmPcd *)h_FmPcd; + uint32_t tmpReg32 = 0; + t_AdOfTypeContLookup *p_Ad; + t_FmPortGetSetCcParams fmPortGetSetCcParams; + t_Error err; + + SANITY_CHECK_RETURN_ERROR(p_Manip,E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_Manip->h_Ad,E_INVALID_HANDLE); + + p_Ad = (t_AdOfTypeContLookup *)p_Manip->h_Ad; + if (p_Manip->h_FmPcd != h_FmPcd) + RETURN_ERROR(MAJOR, E_INVALID_STATE, + ("handler of PCD previously was initiated by different value")); + + memset(&fmPortGetSetCcParams, 0, sizeof(t_FmPortGetSetCcParams)); + + if (!p_Manip->p_StatsTbl) + { + + fmPortGetSetCcParams.setCcParams.type = UPDATE_NIA_PNDN; + fmPortGetSetCcParams.setCcParams.nia = NIA_FM_CTL_AC_CC; + err = FmPortGetSetCcParams(h_FmPort, &fmPortGetSetCcParams); + if (err) + RETURN_ERROR(MAJOR, err, NO_MSG); + + tmpReg32 = GET_UINT32(p_Ad->ccAdBase); + + p_Manip->p_StatsTbl = + (t_Handle)FM_MURAM_AllocMem(p_FmPcd->h_FmMuram, + (uint32_t)p_Manip->owner * FM_PCD_MANIP_INDEXED_STATS_ENTRY_SIZE, + 4); + if (!p_Manip->p_StatsTbl) + RETURN_ERROR(MAJOR, E_NO_MEMORY, ("MURAM alloc for Manipulation indexed statistics table")); + + MemSet8(p_Manip->p_StatsTbl, 0, (uint32_t)(p_Manip->owner * 4)); + + tmpReg32 |= (uint32_t)(XX_VirtToPhys(p_Manip->p_StatsTbl) - p_FmPcd->physicalMuramBase); + + if (p_Manip->cnia) + tmpReg32 |= FM_PCD_MANIP_INDEXED_STATS_CNIA; + + tmpReg32 |= FM_PCD_MANIP_INDEXED_STATS_DPD; + WRITE_UINT32(p_Ad->ccAdBase, tmpReg32); + } + else + { + fmPortGetSetCcParams.setCcParams.type = UPDATE_NIA_PNDN; + fmPortGetSetCcParams.setCcParams.nia = NIA_FM_CTL_AC_CC; + err = FmPortGetSetCcParams(h_FmPort, &fmPortGetSetCcParams); + if (err) + RETURN_ERROR(MAJOR, err, NO_MSG); + } + + return E_OK; +} + +static t_Error RmvHdrTillSpecLocNOrInsrtIntFrmHdr(t_FmPcdManipHdrRmvParams *p_ManipParams, t_FmPcdManip *p_Manip) +{ + t_AdOfTypeContLookup *p_Ad; + uint32_t tmpReg32 = 0; + uint8_t prsArrayOffset = 0; + t_Error err; + + SANITY_CHECK_RETURN_ERROR(p_Manip,E_NULL_POINTER); + SANITY_CHECK_RETURN_ERROR(p_ManipParams,E_NULL_POINTER); + SANITY_CHECK_RETURN_ERROR(p_Manip->h_Ad,E_INVALID_HANDLE); + + p_Ad = (t_AdOfTypeContLookup *)p_Manip->h_Ad; + if (p_Manip->rmv) + { + err = GetPrOffsetByHeaderOrField(&p_ManipParams->u.byHdr.u.fromStartByHdr.hdrInfo, &prsArrayOffset); + if (err) + RETURN_ERROR(MAJOR, err, NO_MSG); + + tmpReg32 |= (uint32_t)prsArrayOffset << 24; + tmpReg32 |= HMAN_RMV_HDR; + } + + if (p_Manip->insrt) + tmpReg32 |= HMAN_INSRT_INT_FRM_HDR; + + tmpReg32 |= (uint32_t)HMAN_OC_RMV_N_OR_INSRT_INT_FRM_HDR; + + WRITE_UINT32(p_Ad->pcAndOffsets, tmpReg32); + + tmpReg32 = 0; + tmpReg32 |= FM_PCD_AD_CONT_LOOKUP_TYPE; + WRITE_UINT32(p_Ad->ccAdBase, tmpReg32); + + return E_OK; +} + +static t_Error MvIntFrameHeaderFromFrameToBufferPrefix(t_FmPcdManip *p_Manip, + bool caamUsed) +{ + t_AdOfTypeContLookup *p_Ad = (t_AdOfTypeContLookup *)p_Manip->h_Ad; + uint32_t tmpReg32 = 0; + + SANITY_CHECK_RETURN_ERROR(p_Ad, E_INVALID_HANDLE); + + p_Manip->updateParams |= OFFSET_OF_PR | INTERNAL_CONTEXT_OFFSET; + + tmpReg32 = 0; + tmpReg32 |= FM_PCD_AD_CONT_LOOKUP_TYPE; + *(uint32_t *)&p_Ad->ccAdBase = tmpReg32; + + tmpReg32 = 0; + tmpReg32 |= HMAN_OC_MV_INT_FRAME_HDR_FROM_FRM_TO_BUFFER_PREFFIX; + tmpReg32 |= (uint32_t)0x16 << 16; + *(uint32_t *)&p_Ad->pcAndOffsets = tmpReg32; + + if (caamUsed) + *(uint32_t *)&p_Ad->gmask = 0xf0000000; + + return E_OK; +} + +static t_Error CapwapRmvDtlsHdr(t_FmPcd *p_FmPcd, t_FmPcdManip *p_Manip) +{ + t_AdOfTypeContLookup *p_Ad; + uint32_t tmpReg32 = 0; + t_Error err = E_OK; + + SANITY_CHECK_RETURN_ERROR(p_Manip->h_Ad,E_INVALID_HANDLE); + + p_Ad = (t_AdOfTypeContLookup *)p_Manip->h_Ad; + + tmpReg32 = 0; + tmpReg32 |= (uint32_t)HMAN_OC_CAPWAP_RMV_DTLS_IF_EXIST; + WRITE_UINT32(p_Ad->pcAndOffsets, tmpReg32); + + tmpReg32 = 0; + tmpReg32 |= FM_PCD_AD_CONT_LOOKUP_TYPE; + + + if (p_Manip->h_Frag) + { + p_Manip->updateParams |= INTERNAL_CONTEXT_OFFSET; + tmpReg32 |= (uint32_t)(XX_VirtToPhys(p_Manip->h_Frag) - (p_FmPcd->physicalMuramBase)); + } + + WRITE_UINT32(p_Ad->ccAdBase, tmpReg32); + + return err; +} + +static t_Error CapwapReassembly(t_CapwapReassemblyParams *p_ManipParams, + t_FmPcdManip *p_Manip, + t_FmPcd *p_FmPcd, + uint8_t poolId) +{ + t_Handle p_Table; + uint32_t tmpReg32 = 0; + int i = 0; + uint8_t log2Num; + uint8_t numOfSets; + uint32_t j = 0; + uint32_t bitFor1Micro; + + SANITY_CHECK_RETURN_ERROR(p_Manip->h_Ad, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_FmPcd->h_Hc, E_INVALID_HANDLE); + + if (!p_FmPcd->h_Hc) + RETURN_ERROR(MAJOR, E_INVALID_VALUE,("hc port has to be initialized in this mode")); + if (!POWER_OF_2(p_ManipParams->timeoutRoutineRequestTime)) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("timeoutRoutineRequestTime has to be power of 2")); + if (!POWER_OF_2(p_ManipParams->maxNumFramesInProcess)) + RETURN_ERROR(MAJOR, E_INVALID_VALUE,("maxNumFramesInProcess has to be power of 2")); + if (!p_ManipParams->timeoutRoutineRequestTime && p_ManipParams->timeoutThresholdForReassmProcess) + DBG(WARNING, ("if timeoutRoutineRequestTime 0, timeoutThresholdForReassmProcess is uselessly")); + if (p_ManipParams->numOfFramesPerHashEntry == e_FM_PCD_MANIP_FOUR_WAYS_HASH) + { + if ((p_ManipParams->maxNumFramesInProcess < 4) || + (p_ManipParams->maxNumFramesInProcess > 512)) + RETURN_ERROR(MAJOR,E_INVALID_VALUE, ("In the case of numOfFramesPerHashEntry = e_FM_PCD_MANIP_EIGHT_WAYS_HASH maxNumFramesInProcess has to be in the range 4-512")); + } + else + { + if ((p_ManipParams->maxNumFramesInProcess < 8) || + (p_ManipParams->maxNumFramesInProcess > 2048)) + RETURN_ERROR(MAJOR,E_INVALID_VALUE, ("In the case of numOfFramesPerHashEntry = e_FM_PCD_MANIP_FOUR_WAYS_HASH maxNumFramesInProcess has to be in the range 8-2048")); + } + + bitFor1Micro = FmGetTimeStampScale(p_FmPcd->h_Fm); + if (bitFor1Micro == 0) + RETURN_ERROR(MAJOR, E_NOT_AVAILABLE, ("Timestamp scale")); + + p_Manip->updateParams |= (NUM_OF_TASKS | OFFSET_OF_PR | OFFSET_OF_DATA | HW_PORT_ID); + + p_Manip->h_Frag = (t_Handle)FM_MURAM_AllocMem(p_FmPcd->h_FmMuram, + FM_PCD_MANIP_CAPWAP_REASM_TABLE_SIZE, + FM_PCD_MANIP_CAPWAP_REASM_TABLE_ALIGN); + if (!p_Manip->h_Frag) + RETURN_ERROR(MAJOR, E_NO_MEMORY, ("MURAM alloc CAPWAP reassembly parameters table")); + + MemSet8(p_Manip->h_Frag, 0, FM_PCD_MANIP_CAPWAP_REASM_TABLE_SIZE); + + p_Table = (t_CapwapReasmPram *)p_Manip->h_Frag; + + p_Manip->capwapFragParams.p_AutoLearnHashTbl = + (t_Handle)FM_MURAM_AllocMem(p_FmPcd->h_FmMuram, + (uint32_t)(p_ManipParams->maxNumFramesInProcess * 2 * FM_PCD_MANIP_CAPWAP_REASM_AUTO_LEARNING_HASH_ENTRY_SIZE), + FM_PCD_MANIP_CAPWAP_REASM_TABLE_ALIGN); + + if (!p_Manip->capwapFragParams.p_AutoLearnHashTbl) + RETURN_ERROR(MAJOR, E_NO_MEMORY,("MURAM alloc for CAPWAP automatic learning hash table")); + + MemSet8(p_Manip->capwapFragParams.p_AutoLearnHashTbl, 0, (uint32_t)(p_ManipParams->maxNumFramesInProcess * 2 * FM_PCD_MANIP_CAPWAP_REASM_AUTO_LEARNING_HASH_ENTRY_SIZE)); + + tmpReg32 = (uint32_t)(XX_VirtToPhys(p_Manip->capwapFragParams.p_AutoLearnHashTbl) - p_FmPcd->physicalMuramBase); + + WRITE_UINT32(((t_CapwapReasmPram *)p_Table)->autoLearnHashTblPtr, tmpReg32); + + tmpReg32 = 0; + if (p_ManipParams->timeOutMode == e_FM_PCD_MANIP_TIME_OUT_BETWEEN_FRAMES) + tmpReg32 |= FM_PCD_MANIP_CAPWAP_REASM_TIME_OUT_BETWEEN_FRAMES; + if (p_ManipParams->haltOnDuplicationFrag) + tmpReg32 |= FM_PCD_MANIP_CAPWAP_REASM_HALT_ON_DUPLICATE_FRAG; + if (p_ManipParams->numOfFramesPerHashEntry == e_FM_PCD_MANIP_EIGHT_WAYS_HASH) + { + i = 8; + tmpReg32 |= FM_PCD_MANIP_CAPWAP_REASM_AUTOMATIC_LEARNIN_HASH_8_WAYS; + } + else + i = 4; + + numOfSets = (uint8_t)((p_ManipParams->maxNumFramesInProcess * 2) / i); + LOG2(numOfSets, log2Num); + tmpReg32 |= (uint32_t)(log2Num - 1) << 24; + + WRITE_UINT32(((t_CapwapReasmPram *)p_Table)->mode, tmpReg32); + + for (j=0; j<p_ManipParams->maxNumFramesInProcess*2; j++) + if (((j / i) % 2)== 0) + WRITE_UINT32(*(uint32_t *)PTR_MOVE(p_Manip->capwapFragParams.p_AutoLearnHashTbl, j * FM_PCD_MANIP_CAPWAP_REASM_AUTO_LEARNING_HASH_ENTRY_SIZE), 0x80000000); + + tmpReg32 = 0x00008000; + tmpReg32 |= (uint32_t)poolId << 16; + WRITE_UINT32(((t_CapwapReasmPram *)p_Table)->bufferPoolIdAndRisc1SetIndexes, tmpReg32); + WRITE_UINT32(((t_CapwapReasmPram *)p_Table)->risc23SetIndexes, 0x80008000); + WRITE_UINT32(((t_CapwapReasmPram *)p_Table)->risc4SetIndexesAndExtendedStatsTblPtr, 0x80000000); + + p_Manip->capwapFragParams.maxNumFramesInProcess = p_ManipParams->maxNumFramesInProcess; + + p_Manip->capwapFragParams.sgBpid = poolId; + + p_Manip->capwapFragParams.fqidForTimeOutFrames = p_ManipParams->fqidForTimeOutFrames; + p_Manip->capwapFragParams.timeoutRoutineRequestTime = p_ManipParams->timeoutRoutineRequestTime; + p_Manip->capwapFragParams.bitFor1Micro = bitFor1Micro; + + tmpReg32 = 0; + tmpReg32 |= (((uint32_t)1<<p_Manip->capwapFragParams.bitFor1Micro) * p_ManipParams->timeoutThresholdForReassmProcess); + WRITE_UINT32(((t_CapwapReasmPram *)p_Table)->expirationDelay, tmpReg32); + + return E_OK; +} + +static t_Error CapwapFragmentation(t_CapwapFragmentationParams *p_ManipParams, + t_FmPcdManip *p_Manip, + t_FmPcd *p_FmPcd, + uint8_t poolId) +{ + t_AdOfTypeContLookup *p_Ad; + uint32_t tmpReg32 = 0; + + SANITY_CHECK_RETURN_ERROR(p_Manip->h_Ad,E_INVALID_HANDLE); + + p_Manip->updateParams |= OFFSET_OF_DATA; + + p_Manip->frag = TRUE; + + p_Manip->h_Frag = (t_Handle)FM_MURAM_AllocMem(p_FmPcd->h_FmMuram, + FM_PCD_CC_AD_ENTRY_SIZE, + FM_PCD_CC_AD_TABLE_ALIGN); + if (!p_Manip->h_Frag) + RETURN_ERROR(MAJOR, E_NO_MEMORY, ("MURAM alloc for CAPWAP fragmentation table descriptor")); + + MemSet8(p_Manip->h_Frag, 0, FM_PCD_CC_AD_ENTRY_SIZE); + + p_Ad = (t_AdOfTypeContLookup *)p_Manip->h_Frag; + + tmpReg32 = 0; + tmpReg32 |= (uint32_t)HMAN_OC_CAPWAP_FRAGMENTATION; + + if (p_ManipParams->headerOptionsCompr) + tmpReg32 |= FM_PCD_MANIP_CAPWAP_FRAG_COMPR_OPTION_FIELD_EN; + tmpReg32 |= ((uint32_t)poolId << 8); + WRITE_UINT32(p_Ad->pcAndOffsets, tmpReg32); + + tmpReg32 = 0; + tmpReg32 |= FM_PCD_AD_CONT_LOOKUP_TYPE; + WRITE_UINT32(p_Ad->ccAdBase, tmpReg32); + + p_Manip->sizeForFragmentation = p_ManipParams->sizeForFragmentation; + p_Manip->capwapFragParams.sgBpid = poolId; + + return E_OK; +} + +static t_Error IndxStats(t_FmPcdStatsParams *p_StatsParams,t_FmPcdManip *p_Manip,t_FmPcd *p_FmPcd) +{ + t_AdOfTypeContLookup *p_Ad; + uint32_t tmpReg32 = 0; + + SANITY_CHECK_RETURN_ERROR(p_Manip->h_Ad,E_INVALID_HANDLE); + + UNUSED(p_FmPcd); + + p_Ad = (t_AdOfTypeContLookup *)p_Manip->h_Ad; + + tmpReg32 = 0; + tmpReg32 |= (uint32_t)HMAN_OC_CAPWAP_INDEXED_STATS; + if (p_StatsParams->type == e_FM_PCD_STATS_PER_FLOWID) + tmpReg32 |= (uint32_t)0x16 << 16; + WRITE_UINT32(p_Ad->pcAndOffsets, tmpReg32); + + tmpReg32 = 0; + tmpReg32 |= FM_PCD_AD_CONT_LOOKUP_TYPE; + WRITE_UINT32(p_Ad->ccAdBase, tmpReg32); + + return E_OK; +} + +static t_Error InsrtHdrByTempl(t_FmPcdManipHdrInsrtParams *p_ManipParams, t_FmPcdManip *p_Manip, t_FmPcd *p_FmPcd) +{ + t_FmPcdManipHdrInsrtByTemplateParams *p_InsrtByTemplate = &p_ManipParams->u.byTemplate; + uint8_t tmpReg8 = 0xff; + t_AdOfTypeContLookup *p_Ad; + bool ipModify = FALSE; + uint32_t tmpReg32 = 0, tmpRegNia = 0; + uint16_t tmpReg16 = 0; + t_Error err = E_OK; + uint8_t extraAddedBytes = 0, blockSize = 0, extraAddedBytesAlignedToBlockSize = 0, log2Num = 0; + uint8_t *p_Template = NULL; + + SANITY_CHECK_RETURN_ERROR(p_ManipParams,E_NULL_POINTER); + SANITY_CHECK_RETURN_ERROR(p_Manip,E_NULL_POINTER); + SANITY_CHECK_RETURN_ERROR(p_Manip->h_Ad,E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_FmPcd,E_NULL_POINTER); + + p_Ad = (t_AdOfTypeContLookup *)p_Manip->h_Ad; + if (p_Manip->insrt) + { + if ((!p_InsrtByTemplate->size && p_InsrtByTemplate->modifyOuterIp) || + (!p_InsrtByTemplate->size && p_InsrtByTemplate->modifyOuterVlan)) + RETURN_ERROR(MAJOR, E_INVALID_STATE, ("Inconsistent parameters : asking for header template modifications with no template for insertion (template size)")); + + if (p_InsrtByTemplate->size && p_InsrtByTemplate->modifyOuterIp && (p_InsrtByTemplate->size <= p_InsrtByTemplate->modifyOuterIpParams.ipOuterOffset)) + RETURN_ERROR(MAJOR, E_INVALID_STATE, ("Inconsistent parameters : size of template < ipOuterOffset")); + + if (p_InsrtByTemplate->size > 128) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("Size of header template for insertion can not be more than 128")); + + if (p_InsrtByTemplate->size) + { + p_Manip->p_Template = (uint8_t *)FM_MURAM_AllocMem(p_FmPcd->h_FmMuram, + p_InsrtByTemplate->size, + FM_PCD_CC_AD_TABLE_ALIGN); + if(!p_Manip->p_Template) + RETURN_ERROR(MAJOR, E_NO_MEMORY, ("Memory allocation in MURAM FAILED")); + + tmpReg32 = (uint32_t)(XX_VirtToPhys(p_Manip->p_Template) - (p_FmPcd->physicalMuramBase)); + tmpReg32 |= (uint32_t)p_InsrtByTemplate->size << 24; + *(uint32_t *)&p_Ad->matchTblPtr = tmpReg32; + } + + tmpReg32 = 0; + + p_Template = (uint8_t *)XX_Malloc(p_InsrtByTemplate->size * sizeof(uint8_t)); + + if (!p_Template) + RETURN_ERROR(MAJOR, E_NO_MEMORY, ("XX_Malloc allocation FAILED")); + + memcpy(p_Template, p_InsrtByTemplate->hdrTemplate, p_InsrtByTemplate->size * sizeof(uint8_t)); + + if (p_InsrtByTemplate->modifyOuterIp) + { + ipModify = TRUE; + + tmpReg8 = (uint8_t)p_Template[p_InsrtByTemplate->modifyOuterIpParams.ipOuterOffset]; + + if((tmpReg8 & 0xf0) == 0x40) + tmpReg8 = 4; + else if((tmpReg8 & 0xf0) == 0x60) + tmpReg8 = 6; + else + tmpReg8 = 0xff; + + if (tmpReg8 != 0xff) + { + if(p_InsrtByTemplate->modifyOuterIpParams.dscpEcn & 0xff00) + RETURN_ERROR(MAJOR, E_INVALID_STATE, ("Inconsistent parameters : IPV4 present in header template, dscpEcn has to be only 1 byte")); + if(p_InsrtByTemplate->modifyOuterIpParams.recalculateLength) + { + + if((p_InsrtByTemplate->modifyOuterIpParams.recalculateLengthParams.extraBytesAddedAlignedToBlockSize + p_InsrtByTemplate->modifyOuterIpParams.recalculateLengthParams.extraBytesAddedNotAlignedToBlockSize) > 255) + RETURN_ERROR(MAJOR, E_INVALID_STATE, ("extra Byte added can not be more than 256 bytes")); + extraAddedBytes = (uint8_t) (p_InsrtByTemplate->modifyOuterIpParams.recalculateLengthParams.extraBytesAddedAlignedToBlockSize + p_InsrtByTemplate->modifyOuterIpParams.recalculateLengthParams.extraBytesAddedNotAlignedToBlockSize); + blockSize = p_InsrtByTemplate->modifyOuterIpParams.recalculateLengthParams.blockSize; + extraAddedBytesAlignedToBlockSize = p_InsrtByTemplate->modifyOuterIpParams.recalculateLengthParams.extraBytesAddedAlignedToBlockSize; + /*IP header template - IP totalLength - + (1 byte) extraByteForIp = headerTemplateSize - ipOffset + insertedBytesAfterThisStage , + in the case of SEC insertedBytesAfterThisStage - SEC trailer (21/31) + header(13) + second byte - extraByteForIp = headerTemplate - ipOffset + insertedBytesAfterThisStage*/ + } + if (blockSize) + { + if (!POWER_OF_2(blockSize)) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("inputFrmPaddingUpToBlockSize has to be power of 2")); + } + + } + if (tmpReg8 == 4) + { + if ((IPv4_HDRCHECKSUM_FIELD_OFFSET_FROM_IP + p_InsrtByTemplate->modifyOuterIpParams.ipOuterOffset) > p_InsrtByTemplate->size) + RETURN_ERROR(MAJOR, E_INVALID_STATE, ("Inconsistent parameters : IP present in header template, user asked for IP modifications but ipOffset + ipTotalLengthFieldOffset in header template bigger than template size")); + + p_Template[p_InsrtByTemplate->modifyOuterIpParams.ipOuterOffset + IPv4_DSCECN_FIELD_OFFSET_FROM_IP] = (uint8_t)p_InsrtByTemplate->modifyOuterIpParams.dscpEcn; + + if (blockSize) + blockSize -= 1; + + if ((p_InsrtByTemplate->size - p_InsrtByTemplate->modifyOuterIpParams.ipOuterOffset + extraAddedBytes) > 255) + RETURN_ERROR(MAJOR, E_INVALID_STATE, ("p_InsrtByTemplate->size - p_InsrtByTemplate->modifyOuterIpParams.ipOuterOffset + extraAddedBytes has to be less than 255")); + + p_Template[p_InsrtByTemplate->modifyOuterIpParams.ipOuterOffset + IPv4_TOTALLENGTH_FIELD_OFFSET_FROM_IP + 1] = blockSize; // IPV6 - in AD instead of SEQ IND + p_Template[p_InsrtByTemplate->modifyOuterIpParams.ipOuterOffset + IPv4_TOTALLENGTH_FIELD_OFFSET_FROM_IP] = (uint8_t)(p_InsrtByTemplate->size - p_InsrtByTemplate->modifyOuterIpParams.ipOuterOffset + extraAddedBytes);// for IPV6 decrement additional 40 bytes of IPV6 heade size + + p_Template[p_InsrtByTemplate->modifyOuterIpParams.ipOuterOffset + IPv4_ID_FIELD_OFFSET_FROM_IP] = 0x00; + p_Template[p_InsrtByTemplate->modifyOuterIpParams.ipOuterOffset + IPv4_ID_FIELD_OFFSET_FROM_IP + 1] = extraAddedBytesAlignedToBlockSize; + + /*IP header template - relevant only for ipv4 CheckSum = 0*/ + p_Template[p_InsrtByTemplate->modifyOuterIpParams.ipOuterOffset + IPv4_HDRCHECKSUM_FIELD_OFFSET_FROM_IP] = 0x00; + p_Template[p_InsrtByTemplate->modifyOuterIpParams.ipOuterOffset + IPv4_HDRCHECKSUM_FIELD_OFFSET_FROM_IP + 1] = 0x00; + + /*UDP checksum has to be 0*/ + if (p_InsrtByTemplate->modifyOuterIpParams.udpPresent) + { + if ((p_InsrtByTemplate->modifyOuterIpParams.udpOffset + UDP_CHECKSUM_FIELD_OFFSET_FROM_UDP + UDP_CHECKSUM_FIELD_SIZE) > p_InsrtByTemplate->size) + RETURN_ERROR(MAJOR, E_INVALID_STATE, ("Inconsistent parameters : UDP present according to user but (UDP offset + UDP header size) < size of header template")); + + p_Template[p_InsrtByTemplate->modifyOuterIpParams.udpOffset + UDP_CHECKSUM_FIELD_OFFSET_FROM_UDP ] = 0x00; + p_Template[p_InsrtByTemplate->modifyOuterIpParams.udpOffset + UDP_CHECKSUM_FIELD_OFFSET_FROM_UDP + 1] = 0x00; + + } + + if (p_InsrtByTemplate->modifyOuterIpParams.ipIdentGenId > 7) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("ipIdentGenId has to be one out of 8 sequence number generators (0 - 7) for IP identification field")); + + tmpRegNia |= (uint32_t)p_InsrtByTemplate->modifyOuterIpParams.ipIdentGenId<<24; + } + else if (tmpReg8 == 6) + { + /*TODO - add check for maximum value of blockSize;*/ + if (blockSize) + LOG2(blockSize, log2Num); + tmpRegNia |= (uint32_t)log2Num << 24; + + // for IPV6 decrement additional 40 bytes of IPV6 heade size - because IPV6 header size is not included in payloadLength + p_Template[p_InsrtByTemplate->modifyOuterIpParams.ipOuterOffset + IPv6_PAYLOAD_LENGTH_OFFSET_FROM_IP] = (uint8_t)(p_InsrtByTemplate->size - p_InsrtByTemplate->modifyOuterIpParams.ipOuterOffset + extraAddedBytes - 40); + p_Template[p_InsrtByTemplate->modifyOuterIpParams.ipOuterOffset + IPv6_PAYLOAD_LENGTH_OFFSET_FROM_IP + 1] = extraAddedBytesAlignedToBlockSize; + if (p_InsrtByTemplate->modifyOuterIpParams.udpPresent) + { + if ((p_InsrtByTemplate->modifyOuterIpParams.udpOffset + UDP_CHECKSUM_FIELD_OFFSET_FROM_UDP + UDP_CHECKSUM_FIELD_SIZE) > p_InsrtByTemplate->size) + RETURN_ERROR(MAJOR, E_INVALID_STATE, ("Inconsistent parameters : UDP present according to user but (UDP offset + UDP header size) < size of header template")); + if (p_Template[p_InsrtByTemplate->modifyOuterIpParams.ipOuterOffset + IPv6_NEXT_HEADER_OFFSET_FROM_IP] != 0x88) + RETURN_ERROR(MAJOR, E_INVALID_STATE, ("OUr suppport is only IPv6/UDPLite")); + p_Template[p_InsrtByTemplate->modifyOuterIpParams.udpOffset + UDP_LENGTH_FIELD_OFFSET_FROM_UDP] = 0x00; + p_Template[p_InsrtByTemplate->modifyOuterIpParams.udpOffset + UDP_LENGTH_FIELD_OFFSET_FROM_UDP + 1] = 0x08; + p_Template[p_InsrtByTemplate->modifyOuterIpParams.udpOffset + UDP_CHECKSUM_FIELD_OFFSET_FROM_UDP] = 0x00; + p_Template[p_InsrtByTemplate->modifyOuterIpParams.udpOffset + UDP_CHECKSUM_FIELD_OFFSET_FROM_UDP + 1] = 0x00; + } + } + else + RETURN_ERROR(MAJOR, E_INVALID_STATE, ("IP version supported only IPV4")); + } + + tmpReg32 = tmpReg16 = tmpReg8 = 0; + /*TODO - check it*/ + if (p_InsrtByTemplate->modifyOuterVlan) + { + if (p_InsrtByTemplate->modifyOuterVlanParams.vpri & ~0x07) + RETURN_ERROR(MAJOR, E_INVALID_STATE,("Inconsistent parameters : user asked for VLAN modifications but VPRI more than 3 bits")); + + memcpy(&tmpReg16, &p_Template[VLAN_TAG_FIELD_OFFSET_FROM_ETH], 2*(sizeof(uint8_t))); + if ((tmpReg16 != 0x9100) && (tmpReg16!= 0x9200) && (tmpReg16 != 0x8100)) + RETURN_ERROR(MAJOR, E_INVALID_STATE,("Inconsistent parameters : user asked for VLAN modifications but Tag Protocol identifier is not VLAN ")); + + memcpy(&tmpReg8, &p_Template[14],1*(sizeof(uint8_t))); + tmpReg8 &= 0x1f; + tmpReg8 |= (uint8_t)(p_InsrtByTemplate->modifyOuterVlanParams.vpri << 5); + + p_Template[14] = tmpReg8; + } + + MemCpy8(p_Manip->p_Template, p_Template, p_InsrtByTemplate->size); + + XX_Free(p_Template); + } + + tmpReg32 = 0; + if (p_Manip->h_Frag) + { + tmpRegNia |= (uint32_t)(XX_VirtToPhys(p_Manip->h_Frag) - (p_FmPcd->physicalMuramBase)); + tmpReg32 |= (uint32_t)p_Manip->sizeForFragmentation << 16; + } + else + tmpReg32 = 0xffff0000; + + if (ipModify) + tmpReg32 |= (uint32_t)p_InsrtByTemplate->modifyOuterIpParams.ipOuterOffset << 8; + else + tmpReg32 |= (uint32_t)0x0000ff00; + + tmpReg32 |= (uint32_t)HMAN_OC_INSRT_HDR_BY_TEMPL_N_OR_FRAG_AFTER; + *(uint32_t *)&p_Ad->pcAndOffsets = tmpReg32; + + tmpRegNia |= FM_PCD_AD_CONT_LOOKUP_TYPE; + *(uint32_t *)&p_Ad->ccAdBase = tmpRegNia; + + return err; +} + +static t_Error CheckStatsParamsAndSetType(t_FmPcdManip *p_Manip, t_FmPcdStatsParams *p_StatsParams) +{ + + switch (p_StatsParams->type) + { + case (e_FM_PCD_STATS_PER_FLOWID): + p_Manip->opcode = HMAN_OC_CAPWAP_INDEXED_STATS; + p_Manip->muramAllocate = TRUE; + break; + default: + RETURN_ERROR(MAJOR, E_INVALID_STATE, ("Unsupported statistics type")); + } + + return E_OK; +} +#endif /* (defined(FM_CAPWAP_SUPPORT) && (DPAA_VERSION == 10)) */ + +static t_Error FillReassmManipParams(t_FmPcdManip *p_Manip, e_NetHeaderType hdr) +{ + t_AdOfTypeContLookup *p_Ad; + t_FmPcd *p_FmPcd = (t_FmPcd *)p_Manip->h_FmPcd; + uint32_t tmpReg32; + t_Error err = E_OK; + + /* Creates the Reassembly Parameters table. It contains parameters that are specific to either the IPv4 reassembly + function or to the IPv6 reassembly function. If both IPv4 reassembly and IPv6 reassembly are required, then + two separate IP Reassembly Parameter tables are required.*/ + if ((err = CreateReassTable(p_Manip, hdr)) != E_OK) + RETURN_ERROR(MAJOR, err, NO_MSG); + + /* Sets the first Ad register (ccAdBase) - Action Descriptor Type and Pointer to the Reassembly Parameters Table offset from MURAM*/ + tmpReg32 = 0; + tmpReg32 |= FM_PCD_AD_CONT_LOOKUP_TYPE; + + /* Gets the required Action descriptor table pointer */ + switch (hdr) + { + case HEADER_TYPE_IPv4: + p_Ad = (t_AdOfTypeContLookup *)p_Manip->reassmParams.ip.h_Ipv4Ad; + tmpReg32 |= (uint32_t)(XX_VirtToPhys( + p_Manip->reassmParams.ip.p_Ipv4ReassTbl) + - (p_FmPcd->physicalMuramBase)); + break; + case HEADER_TYPE_IPv6: + p_Ad = (t_AdOfTypeContLookup *)p_Manip->reassmParams.ip.h_Ipv6Ad; + tmpReg32 |= (uint32_t)(XX_VirtToPhys( + p_Manip->reassmParams.ip.p_Ipv6ReassTbl) + - (p_FmPcd->physicalMuramBase)); + break; + case HEADER_TYPE_CAPWAP: + p_Ad = (t_AdOfTypeContLookup *)p_Manip->reassmParams.capwap.h_Ad; + tmpReg32 |= (uint32_t)(XX_VirtToPhys( + p_Manip->reassmParams.capwap.p_ReassTbl) + - (p_FmPcd->physicalMuramBase)); + break; + default: + RETURN_ERROR(MAJOR, E_NOT_SUPPORTED, ("header type")); + } + + WRITE_UINT32(p_Ad->ccAdBase, tmpReg32); + + /* Sets the second Ad register (matchTblPtr) - Buffer pool ID (BPID for V2) and Scatter/Gather table offset*/ + /* mark the Scatter/Gather table offset to be set later on when the port will be known */ + p_Manip->updateParams = (NUM_OF_TASKS | NUM_OF_EXTRA_TASKS | DISCARD_MASK); + + if ((hdr == HEADER_TYPE_IPv6) || (hdr == HEADER_TYPE_IPv4)) + { +#if (DPAA_VERSION == 10) + tmpReg32 = (uint32_t)(p_Manip->reassmParams.sgBpid << 8); + WRITE_UINT32(p_Ad->matchTblPtr, tmpReg32); +#endif /* (DPAA_VERSION == 10) */ +#if (DPAA_VERSION >= 11) + if (p_Manip->reassmParams.ip.nonConsistentSpFqid != 0) + { + tmpReg32 = FM_PCD_AD_NCSPFQIDM_MASK + | (uint32_t)(p_Manip->reassmParams.ip.nonConsistentSpFqid); + WRITE_UINT32(p_Ad->gmask, tmpReg32); + } +#endif /* (DPAA_VERSION >= 11) */ + /* Sets the third Ad register (pcAndOffsets)- IP Reassemble Operation Code*/ + tmpReg32 = 0; + tmpReg32 |= (uint32_t)HMAN_OC_IP_REASSEMBLY; + } +#if (DPAA_VERSION >= 11) + else + if (hdr == HEADER_TYPE_CAPWAP) + { + tmpReg32 = 0; + tmpReg32 |= (uint32_t)HMAN_OC_CAPWAP_REASSEMBLY; + } +#endif /* (DPAA_VERSION >= 11) */ + + WRITE_UINT32(p_Ad->pcAndOffsets, tmpReg32); + + p_Manip->reassm = TRUE; + + return E_OK; +} + +static t_Error SetIpv4ReassmManip(t_FmPcdManip *p_Manip) +{ + t_FmPcd *p_FmPcd = (t_FmPcd *)p_Manip->h_FmPcd; + + /* Allocation if IPv4 Action descriptor */ + p_Manip->reassmParams.ip.h_Ipv4Ad = (t_Handle)XX_MallocSmart( + FM_PCD_CC_AD_ENTRY_SIZE, p_Manip->reassmParams.dataMemId, + FM_PCD_CC_AD_TABLE_ALIGN); + if (!p_Manip->reassmParams.ip.h_Ipv4Ad) + { + ReleaseManipHandler(p_Manip, p_FmPcd); + RETURN_ERROR(MAJOR, E_NO_MEMORY, + ("Allocation of IPv4 table descriptor")); + } + + memset(p_Manip->reassmParams.ip.h_Ipv4Ad, 0, FM_PCD_CC_AD_ENTRY_SIZE); + + /* Fill reassembly manipulation parameter in the IP Reassembly Action Descriptor */ + return FillReassmManipParams(p_Manip, HEADER_TYPE_IPv4); +} + +static t_Error SetIpv6ReassmManip(t_FmPcdManip *p_Manip) +{ + t_FmPcd *p_FmPcd = (t_FmPcd *)p_Manip->h_FmPcd; + + /* Allocation if IPv6 Action descriptor */ + p_Manip->reassmParams.ip.h_Ipv6Ad = (t_Handle)XX_MallocSmart( + FM_PCD_CC_AD_ENTRY_SIZE, p_Manip->reassmParams.dataMemId, + FM_PCD_CC_AD_TABLE_ALIGN); + if (!p_Manip->reassmParams.ip.h_Ipv6Ad) + { + ReleaseManipHandler(p_Manip, p_FmPcd); + RETURN_ERROR(MAJOR, E_NO_MEMORY, + ("Allocation of IPv6 table descriptor")); + } + + memset(p_Manip->reassmParams.ip.h_Ipv6Ad, 0, FM_PCD_CC_AD_ENTRY_SIZE); + + /* Fill reassembly manipulation parameter in the IP Reassembly Action Descriptor */ + return FillReassmManipParams(p_Manip, HEADER_TYPE_IPv6); +} + +static t_Error IpReassembly(t_FmPcdManipReassemParams *p_ManipReassmParams, + t_FmPcdManip *p_Manip) +{ + uint32_t maxSetNumber = 10000; + t_FmPcdManipReassemIpParams reassmManipParams = + p_ManipReassmParams->u.ipReassem; + t_Error res; + + SANITY_CHECK_RETURN_ERROR(p_Manip->h_FmPcd, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(((t_FmPcd *)p_Manip->h_FmPcd)->h_Hc, + E_INVALID_HANDLE); + + /* Check validation of user's parameter.*/ + if ((reassmManipParams.timeoutThresholdForReassmProcess < 1000) + || (reassmManipParams.timeoutThresholdForReassmProcess > 8000000)) + RETURN_ERROR( + MAJOR, E_INVALID_VALUE, + ("timeoutThresholdForReassmProcess should be 1msec - 8sec")); + /* It is recommended that the total number of entries in this table (number of sets * number of ways) + will be twice the number of frames that are expected to be reassembled simultaneously.*/ + if (reassmManipParams.maxNumFramesInProcess + > (reassmManipParams.maxNumFramesInProcess * maxSetNumber / 2)) + RETURN_ERROR( + MAJOR, + E_INVALID_VALUE, + ("maxNumFramesInProcess has to be less than (maximun set number * number of ways / 2)")); + + if ((p_ManipReassmParams->hdr == HEADER_TYPE_IPv6) + && (reassmManipParams.minFragSize[1] < 256)) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("minFragSize[1] must be >= 256")); + + /* Saves user's reassembly manipulation parameters */ + p_Manip->reassmParams.ip.relativeSchemeId[0] = + reassmManipParams.relativeSchemeId[0]; + p_Manip->reassmParams.ip.relativeSchemeId[1] = + reassmManipParams.relativeSchemeId[1]; + p_Manip->reassmParams.ip.numOfFramesPerHashEntry[0] = + reassmManipParams.numOfFramesPerHashEntry[0]; + p_Manip->reassmParams.ip.numOfFramesPerHashEntry[1] = + reassmManipParams.numOfFramesPerHashEntry[1]; + p_Manip->reassmParams.ip.minFragSize[0] = reassmManipParams.minFragSize[0]; + p_Manip->reassmParams.ip.minFragSize[1] = reassmManipParams.minFragSize[1]; + p_Manip->reassmParams.maxNumFramesInProcess = + reassmManipParams.maxNumFramesInProcess; + p_Manip->reassmParams.timeOutMode = reassmManipParams.timeOutMode; + p_Manip->reassmParams.fqidForTimeOutFrames = + reassmManipParams.fqidForTimeOutFrames; + p_Manip->reassmParams.timeoutThresholdForReassmProcess = + reassmManipParams.timeoutThresholdForReassmProcess; + p_Manip->reassmParams.dataMemId = reassmManipParams.dataMemId; + p_Manip->reassmParams.dataLiodnOffset = reassmManipParams.dataLiodnOffset; +#if (DPAA_VERSION == 10) + p_Manip->reassmParams.sgBpid = reassmManipParams.sgBpid; +#endif /* (DPAA_VERSION == 10) */ +#if (DPAA_VERSION >= 11) + if (reassmManipParams.nonConsistentSpFqid != 0) + { + p_Manip->reassmParams.ip.nonConsistentSpFqid = + reassmManipParams.nonConsistentSpFqid; + } +#endif /* (DPAA_VERSION >= 11) */ + + /* Creates and initializes the IP Reassembly common parameter table */ + CreateReassCommonTable(p_Manip); + + /* Creation of IPv4 reassembly manipulation */ + if ((p_Manip->reassmParams.hdr == HEADER_TYPE_IPv6) + || (p_Manip->reassmParams.hdr == HEADER_TYPE_IPv4)) + { + res = SetIpv4ReassmManip(p_Manip); + if (res != E_OK) + return res; + } + + /* Creation of IPv6 reassembly manipulation */ + if (p_Manip->reassmParams.hdr == HEADER_TYPE_IPv6) + { + res = SetIpv6ReassmManip(p_Manip); + if (res != E_OK) + return res; + } + + return E_OK; +} + +static void setIpReassmSchemeParams(t_FmPcd* p_FmPcd, + t_FmPcdKgSchemeParams *p_Scheme, + t_Handle h_CcTree, bool ipv4, + uint8_t groupId) +{ + uint32_t j; + uint8_t res; + + /* Configures scheme's network environment parameters */ + p_Scheme->netEnvParams.numOfDistinctionUnits = 2; + if (ipv4) + res = FmPcdNetEnvGetUnitId( + p_FmPcd, FmPcdGetNetEnvId(p_Scheme->netEnvParams.h_NetEnv), + HEADER_TYPE_IPv4, FALSE, 0); + else + res = FmPcdNetEnvGetUnitId( + p_FmPcd, FmPcdGetNetEnvId(p_Scheme->netEnvParams.h_NetEnv), + HEADER_TYPE_IPv6, FALSE, 0); + ASSERT_COND(res != FM_PCD_MAX_NUM_OF_DISTINCTION_UNITS); + p_Scheme->netEnvParams.unitIds[0] = res; + + res = FmPcdNetEnvGetUnitId( + p_FmPcd, FmPcdGetNetEnvId(p_Scheme->netEnvParams.h_NetEnv), + HEADER_TYPE_USER_DEFINED_SHIM2, FALSE, 0); + ASSERT_COND(res != FM_PCD_MAX_NUM_OF_DISTINCTION_UNITS); + p_Scheme->netEnvParams.unitIds[1] = res; + + /* Configures scheme's next engine parameters*/ + p_Scheme->nextEngine = e_FM_PCD_CC; + p_Scheme->kgNextEngineParams.cc.h_CcTree = h_CcTree; + p_Scheme->kgNextEngineParams.cc.grpId = groupId; + p_Scheme->useHash = TRUE; + + /* Configures scheme's key*/ + if (ipv4 == TRUE) + { + p_Scheme->keyExtractAndHashParams.numOfUsedExtracts = 4; + p_Scheme->keyExtractAndHashParams.extractArray[0].type = + e_FM_PCD_EXTRACT_BY_HDR; + p_Scheme->keyExtractAndHashParams.extractArray[0].extractByHdr.type = + e_FM_PCD_EXTRACT_FULL_FIELD; + p_Scheme->keyExtractAndHashParams.extractArray[0].extractByHdr.hdr = + HEADER_TYPE_IPv4; + p_Scheme->keyExtractAndHashParams.extractArray[0].extractByHdr.extractByHdrType.fullField.ipv4 = + NET_HEADER_FIELD_IPv4_DST_IP; + p_Scheme->keyExtractAndHashParams.extractArray[1].type = + e_FM_PCD_EXTRACT_BY_HDR; + p_Scheme->keyExtractAndHashParams.extractArray[1].extractByHdr.type = + e_FM_PCD_EXTRACT_FULL_FIELD; + p_Scheme->keyExtractAndHashParams.extractArray[1].extractByHdr.hdr = + HEADER_TYPE_IPv4; + p_Scheme->keyExtractAndHashParams.extractArray[1].extractByHdr.extractByHdrType.fullField.ipv4 = + NET_HEADER_FIELD_IPv4_SRC_IP; + p_Scheme->keyExtractAndHashParams.extractArray[2].type = + e_FM_PCD_EXTRACT_BY_HDR; + p_Scheme->keyExtractAndHashParams.extractArray[2].extractByHdr.type = + e_FM_PCD_EXTRACT_FULL_FIELD; + p_Scheme->keyExtractAndHashParams.extractArray[2].extractByHdr.hdr = + HEADER_TYPE_IPv4; + p_Scheme->keyExtractAndHashParams.extractArray[2].extractByHdr.extractByHdrType.fullField.ipv4 = + NET_HEADER_FIELD_IPv4_PROTO; + p_Scheme->keyExtractAndHashParams.extractArray[3].type = + e_FM_PCD_EXTRACT_BY_HDR; + p_Scheme->keyExtractAndHashParams.extractArray[3].extractByHdr.hdr = + HEADER_TYPE_IPv4; + p_Scheme->keyExtractAndHashParams.extractArray[3].extractByHdr.type = + e_FM_PCD_EXTRACT_FROM_HDR; + p_Scheme->keyExtractAndHashParams.extractArray[3].extractByHdr.ignoreProtocolValidation = + FALSE; + p_Scheme->keyExtractAndHashParams.extractArray[3].extractByHdr.extractByHdrType.fromHdr.size = + 2; + p_Scheme->keyExtractAndHashParams.extractArray[3].extractByHdr.extractByHdrType.fromHdr.offset = + 4; + } + else /* IPv6 */ + { + p_Scheme->keyExtractAndHashParams.numOfUsedExtracts = 3; + p_Scheme->keyExtractAndHashParams.extractArray[0].type = + e_FM_PCD_EXTRACT_BY_HDR; + p_Scheme->keyExtractAndHashParams.extractArray[0].extractByHdr.type = + e_FM_PCD_EXTRACT_FULL_FIELD; + p_Scheme->keyExtractAndHashParams.extractArray[0].extractByHdr.hdr = + HEADER_TYPE_IPv6; + p_Scheme->keyExtractAndHashParams.extractArray[0].extractByHdr.extractByHdrType.fullField.ipv6 = + NET_HEADER_FIELD_IPv6_DST_IP; + p_Scheme->keyExtractAndHashParams.extractArray[1].type = + e_FM_PCD_EXTRACT_BY_HDR; + p_Scheme->keyExtractAndHashParams.extractArray[1].extractByHdr.type = + e_FM_PCD_EXTRACT_FULL_FIELD; + p_Scheme->keyExtractAndHashParams.extractArray[1].extractByHdr.hdr = + HEADER_TYPE_IPv6; + p_Scheme->keyExtractAndHashParams.extractArray[1].extractByHdr.extractByHdrType.fullField.ipv6 = + NET_HEADER_FIELD_IPv6_SRC_IP; + p_Scheme->keyExtractAndHashParams.extractArray[2].type = + e_FM_PCD_EXTRACT_BY_HDR; + p_Scheme->keyExtractAndHashParams.extractArray[2].extractByHdr.hdr = + HEADER_TYPE_USER_DEFINED_SHIM2; + p_Scheme->keyExtractAndHashParams.extractArray[2].extractByHdr.type = + e_FM_PCD_EXTRACT_FROM_HDR; + p_Scheme->keyExtractAndHashParams.extractArray[2].extractByHdr.extractByHdrType.fromHdr.size = + 4; + p_Scheme->keyExtractAndHashParams.extractArray[2].extractByHdr.extractByHdrType.fromHdr.offset = + 4; + p_Scheme->keyExtractAndHashParams.extractArray[2].extractByHdr.ignoreProtocolValidation = + TRUE; + } + + p_Scheme->keyExtractAndHashParams.privateDflt0 = 0x01020304; + p_Scheme->keyExtractAndHashParams.privateDflt1 = 0x11121314; + p_Scheme->keyExtractAndHashParams.numOfUsedDflts = + FM_PCD_KG_NUM_OF_DEFAULT_GROUPS; + for (j = 0; j < FM_PCD_KG_NUM_OF_DEFAULT_GROUPS; j++) + { + p_Scheme->keyExtractAndHashParams.dflts[j].type = + (e_FmPcdKgKnownFieldsDfltTypes)j; /* all types */ + p_Scheme->keyExtractAndHashParams.dflts[j].dfltSelect = + e_FM_PCD_KG_DFLT_GBL_0; + } +} + +static t_Error IpReassemblyStats(t_FmPcdManip *p_Manip, + t_FmPcdManipReassemIpStats *p_Stats) +{ + ASSERT_COND(p_Manip); + ASSERT_COND(p_Stats); + ASSERT_COND(p_Manip->reassmParams.p_ReassCommonTbl); + + p_Stats->timeout = + GET_UINT32(p_Manip->reassmParams.p_ReassCommonTbl->totalTimeOutCounter); + p_Stats->rfdPoolBusy = + GET_UINT32(p_Manip->reassmParams.p_ReassCommonTbl->totalRfdPoolBusyCounter); + p_Stats->internalBufferBusy = + GET_UINT32(p_Manip->reassmParams.p_ReassCommonTbl->totalInternalBufferBusy); + p_Stats->externalBufferBusy = + GET_UINT32(p_Manip->reassmParams.p_ReassCommonTbl->totalExternalBufferBusy); + p_Stats->sgFragments = + GET_UINT32(p_Manip->reassmParams.p_ReassCommonTbl->totalSgFragmentCounter); + p_Stats->dmaSemaphoreDepletion = + GET_UINT32(p_Manip->reassmParams.p_ReassCommonTbl->totalDmaSemaphoreDepletionCounter); +#if (DPAA_VERSION >= 11) + p_Stats->nonConsistentSp = + GET_UINT32(p_Manip->reassmParams.p_ReassCommonTbl->totalNCSPCounter); +#endif /* (DPAA_VERSION >= 11) */ + + if (p_Manip->reassmParams.ip.p_Ipv4ReassTbl) + { + p_Stats->specificHdrStatistics[0].successfullyReassembled = + GET_UINT32(p_Manip->reassmParams.ip.p_Ipv4ReassTbl->totalSuccessfullyReasmFramesCounter); + p_Stats->specificHdrStatistics[0].validFragments = + GET_UINT32(p_Manip->reassmParams.ip.p_Ipv4ReassTbl->totalValidFragmentCounter); + p_Stats->specificHdrStatistics[0].processedFragments = + GET_UINT32(p_Manip->reassmParams.ip.p_Ipv4ReassTbl->totalProcessedFragCounter); + p_Stats->specificHdrStatistics[0].malformedFragments = + GET_UINT32(p_Manip->reassmParams.ip.p_Ipv4ReassTbl->totalMalformdFragCounter); + p_Stats->specificHdrStatistics[0].autoLearnBusy = + GET_UINT32(p_Manip->reassmParams.ip.p_Ipv4ReassTbl->totalSetBusyCounter); + p_Stats->specificHdrStatistics[0].discardedFragments = + GET_UINT32(p_Manip->reassmParams.ip.p_Ipv4ReassTbl->totalDiscardedFragsCounter); + p_Stats->specificHdrStatistics[0].moreThan16Fragments = + GET_UINT32(p_Manip->reassmParams.ip.p_Ipv4ReassTbl->totalMoreThan16FramesCounter); + } + if (p_Manip->reassmParams.ip.p_Ipv6ReassTbl) + { + p_Stats->specificHdrStatistics[1].successfullyReassembled = + GET_UINT32(p_Manip->reassmParams.ip.p_Ipv6ReassTbl->totalSuccessfullyReasmFramesCounter); + p_Stats->specificHdrStatistics[1].validFragments = + GET_UINT32(p_Manip->reassmParams.ip.p_Ipv6ReassTbl->totalValidFragmentCounter); + p_Stats->specificHdrStatistics[1].processedFragments = + GET_UINT32(p_Manip->reassmParams.ip.p_Ipv6ReassTbl->totalProcessedFragCounter); + p_Stats->specificHdrStatistics[1].malformedFragments = + GET_UINT32(p_Manip->reassmParams.ip.p_Ipv6ReassTbl->totalMalformdFragCounter); + p_Stats->specificHdrStatistics[1].autoLearnBusy = + GET_UINT32(p_Manip->reassmParams.ip.p_Ipv6ReassTbl->totalSetBusyCounter); + p_Stats->specificHdrStatistics[1].discardedFragments = + GET_UINT32(p_Manip->reassmParams.ip.p_Ipv6ReassTbl->totalDiscardedFragsCounter); + p_Stats->specificHdrStatistics[1].moreThan16Fragments = + GET_UINT32(p_Manip->reassmParams.ip.p_Ipv6ReassTbl->totalMoreThan16FramesCounter); + } + return E_OK; +} + +static t_Error IpFragmentationStats(t_FmPcdManip *p_Manip, + t_FmPcdManipFragIpStats *p_Stats) +{ + t_AdOfTypeContLookup *p_Ad; + + ASSERT_COND(p_Manip); + ASSERT_COND(p_Stats); + ASSERT_COND(p_Manip->h_Ad); + ASSERT_COND(p_Manip->fragParams.p_Frag); + + p_Ad = (t_AdOfTypeContLookup *)p_Manip->h_Ad; + + p_Stats->totalFrames = GET_UINT32(p_Ad->gmask); + p_Stats->fragmentedFrames = GET_UINT32(p_Manip->fragParams.p_Frag->ccAdBase) + & 0x00ffffff; + p_Stats->generatedFragments = + GET_UINT32(p_Manip->fragParams.p_Frag->matchTblPtr); + + return E_OK; +} + +static t_Error IpFragmentation(t_FmPcdManipFragIpParams *p_ManipParams, + t_FmPcdManip *p_Manip) +{ + uint32_t pcAndOffsetsReg = 0, ccAdBaseReg = 0, gmaskReg = 0; + t_FmPcd *p_FmPcd; +#if (DPAA_VERSION == 10) + t_Error err = E_OK; +#endif /* (DPAA_VERSION == 10) */ + + SANITY_CHECK_RETURN_ERROR(p_Manip->h_Ad, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_ManipParams->sizeForFragmentation != 0xFFFF, + E_INVALID_VALUE); + + p_FmPcd = p_Manip->h_FmPcd; + /* Allocation of fragmentation Action Descriptor */ + p_Manip->fragParams.p_Frag = (t_AdOfTypeContLookup *)FM_MURAM_AllocMem( + p_FmPcd->h_FmMuram, FM_PCD_CC_AD_ENTRY_SIZE, + FM_PCD_CC_AD_TABLE_ALIGN); + if (!p_Manip->fragParams.p_Frag) + RETURN_ERROR(MAJOR, E_NO_MEMORY, + ("MURAM alloc for Fragmentation table descriptor")); + MemSet8(p_Manip->fragParams.p_Frag, 0, FM_PCD_CC_AD_ENTRY_SIZE); + + /* Prepare the third Ad register (pcAndOffsets)- OperationCode */ + pcAndOffsetsReg = (uint32_t)HMAN_OC_IP_FRAGMENTATION; + + /* Prepare the first Ad register (ccAdBase) - Don't frag action and Action descriptor type*/ + ccAdBaseReg = FM_PCD_AD_CONT_LOOKUP_TYPE; + ccAdBaseReg |= (p_ManipParams->dontFragAction + << FM_PCD_MANIP_IP_FRAG_DF_SHIFT); + + + /* Set Scatter/Gather BPid */ + if (p_ManipParams->sgBpidEn) + { + ccAdBaseReg |= FM_PCD_MANIP_IP_FRAG_SG_BDID_EN; + pcAndOffsetsReg |= ((p_ManipParams->sgBpid + << FM_PCD_MANIP_IP_FRAG_SG_BDID_SHIFT) + & FM_PCD_MANIP_IP_FRAG_SG_BDID_MASK); + } + + /* Prepare the first Ad register (gmask) - scratch buffer pool id and Pointer to fragment ID */ + gmaskReg = (uint32_t)(XX_VirtToPhys(UINT_TO_PTR(p_FmPcd->ipv6FrameIdAddr)) + - p_FmPcd->physicalMuramBase); +#if (DPAA_VERSION == 10) + gmaskReg |= p_ManipParams->scratchBpid << FM_PCD_MANIP_IP_FRAG_SCRATCH_BPID; +#else + gmaskReg |= (0xFF) << FM_PCD_MANIP_IP_FRAG_SCRATCH_BPID; +#endif /* (DPAA_VERSION == 10) */ + + /* Set all Ad registers */ + WRITE_UINT32(p_Manip->fragParams.p_Frag->pcAndOffsets, pcAndOffsetsReg); + WRITE_UINT32(p_Manip->fragParams.p_Frag->ccAdBase, ccAdBaseReg); + WRITE_UINT32(p_Manip->fragParams.p_Frag->gmask, gmaskReg); + + /* Saves user's fragmentation manipulation parameters */ + p_Manip->frag = TRUE; + p_Manip->sizeForFragmentation = p_ManipParams->sizeForFragmentation; + +#if (DPAA_VERSION == 10) + p_Manip->fragParams.scratchBpid = p_ManipParams->scratchBpid; + + /* scratch buffer pool initialization */ + if ((err = FmPcdFragHcScratchPoolFill((t_Handle)p_FmPcd, p_ManipParams->scratchBpid)) != E_OK) + { + FM_MURAM_FreeMem(p_FmPcd->h_FmMuram, p_Manip->fragParams.p_Frag); + p_Manip->fragParams.p_Frag = NULL; + RETURN_ERROR(MAJOR, err, NO_MSG); + } +#endif /* (DPAA_VERSION == 10) */ + + return E_OK; +} + +static t_Error IPManip(t_FmPcdManip *p_Manip) +{ + t_Error err = E_OK; + t_FmPcd *p_FmPcd; + t_AdOfTypeContLookup *p_Ad; + uint32_t tmpReg32 = 0, tmpRegNia = 0; + + SANITY_CHECK_RETURN_ERROR(p_Manip, E_INVALID_HANDLE); + p_FmPcd = p_Manip->h_FmPcd; + SANITY_CHECK_RETURN_ERROR(p_FmPcd, E_INVALID_HANDLE); + + p_Ad = (t_AdOfTypeContLookup *)p_Manip->h_Ad; + + tmpReg32 = FM_PCD_MANIP_IP_NO_FRAGMENTATION; + if (p_Manip->frag == TRUE) + { + tmpRegNia = (uint32_t)(XX_VirtToPhys(p_Manip->fragParams.p_Frag) + - (p_FmPcd->physicalMuramBase)); + tmpReg32 = (uint32_t)p_Manip->sizeForFragmentation + << FM_PCD_MANIP_IP_MTU_SHIFT; + } + + tmpRegNia |= FM_PCD_AD_CONT_LOOKUP_TYPE; + tmpReg32 |= HMAN_OC_IP_MANIP; + +#if (DPAA_VERSION >= 11) + tmpRegNia |= FM_PCD_MANIP_IP_CNIA; +#endif /* (DPAA_VERSION >= 11) */ + + WRITE_UINT32(p_Ad->pcAndOffsets, tmpReg32); + WRITE_UINT32(p_Ad->ccAdBase, tmpRegNia); + WRITE_UINT32(p_Ad->gmask, 0); + /* Total frame counter - MUST be initialized to zero.*/ + + return err; +} + +static t_Error UpdateInitIpFrag(t_Handle h_FmPcd, t_Handle h_PcdParams, + t_Handle h_FmPort, t_FmPcdManip *p_Manip, + t_Handle h_Ad, bool validate) +{ + t_FmPortGetSetCcParams fmPortGetSetCcParams; + t_Error err; + + SANITY_CHECK_RETURN_ERROR(p_Manip, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR((p_Manip->opcode == HMAN_OC_IP_FRAGMENTATION), + E_INVALID_STATE); + SANITY_CHECK_RETURN_ERROR(h_FmPcd, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(h_FmPort, E_INVALID_HANDLE); + + UNUSED(h_FmPcd); + UNUSED(h_Ad); + UNUSED(h_PcdParams); + UNUSED(validate); + UNUSED(p_Manip); + + fmPortGetSetCcParams.setCcParams.type = 0; + fmPortGetSetCcParams.getCcParams.type = MANIP_EXTRA_SPACE; + if ((err = FmPortGetSetCcParams(h_FmPort, &fmPortGetSetCcParams)) != E_OK) + RETURN_ERROR(MAJOR, err, NO_MSG); + + if (!fmPortGetSetCcParams.getCcParams.internalBufferOffset) + DBG(WARNING, ("manipExtraSpace must be larger than '0'")); + + return E_OK; +} + +static t_Error IPSecManip(t_FmPcdManipParams *p_ManipParams, + t_FmPcdManip *p_Manip) +{ + t_AdOfTypeContLookup *p_Ad; + t_FmPcdManipSpecialOffloadIPSecParams *p_IPSecParams; + t_Error err = E_OK; + uint32_t tmpReg32 = 0; + uint32_t power; + + SANITY_CHECK_RETURN_ERROR(p_Manip, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_ManipParams, E_INVALID_HANDLE); + + p_IPSecParams = &p_ManipParams->u.specialOffload.u.ipsec; + + SANITY_CHECK_RETURN_ERROR( + !p_IPSecParams->variableIpHdrLen || p_IPSecParams->decryption, + E_INVALID_VALUE); + SANITY_CHECK_RETURN_ERROR( + !p_IPSecParams->variableIpVersion || !p_IPSecParams->decryption, + E_INVALID_VALUE); + SANITY_CHECK_RETURN_ERROR( + !p_IPSecParams->variableIpVersion || p_IPSecParams->outerIPHdrLen, + E_INVALID_VALUE); + SANITY_CHECK_RETURN_ERROR( + !p_IPSecParams->arwSize || p_IPSecParams->arwAddr, + E_INVALID_VALUE); + SANITY_CHECK_RETURN_ERROR( + !p_IPSecParams->arwSize || p_IPSecParams->decryption, + E_INVALID_VALUE); + SANITY_CHECK_RETURN_ERROR((p_IPSecParams->arwSize % 16) == 0, E_INVALID_VALUE); + + p_Ad = (t_AdOfTypeContLookup *)p_Manip->h_Ad; + + tmpReg32 |= FM_PCD_AD_CONT_LOOKUP_TYPE; + tmpReg32 |= (p_IPSecParams->decryption) ? FM_PCD_MANIP_IPSEC_DEC : 0; + tmpReg32 |= (p_IPSecParams->ecnCopy) ? FM_PCD_MANIP_IPSEC_ECN_EN : 0; + tmpReg32 |= (p_IPSecParams->dscpCopy) ? FM_PCD_MANIP_IPSEC_DSCP_EN : 0; + tmpReg32 |= + (p_IPSecParams->variableIpHdrLen) ? FM_PCD_MANIP_IPSEC_VIPL_EN : 0; + tmpReg32 |= + (p_IPSecParams->variableIpVersion) ? FM_PCD_MANIP_IPSEC_VIPV_EN : 0; + if (p_IPSecParams->arwSize) + tmpReg32 |= (uint32_t)((XX_VirtToPhys(UINT_TO_PTR(p_IPSecParams->arwAddr))-FM_MM_MURAM) + & (FM_MURAM_SIZE-1)); + WRITE_UINT32(p_Ad->ccAdBase, tmpReg32); + + tmpReg32 = 0; + if (p_IPSecParams->arwSize) { + NEXT_POWER_OF_2((p_IPSecParams->arwSize + 32), power); + LOG2(power, power); + tmpReg32 = (p_IPSecParams->arwSize | (power - 5)) << FM_PCD_MANIP_IPSEC_ARW_SIZE_SHIFT; + } + + if (p_ManipParams->h_NextManip) + tmpReg32 |= + (uint32_t)(XX_VirtToPhys(((t_FmPcdManip *)p_ManipParams->h_NextManip)->h_Ad)- + (((t_FmPcd *)p_Manip->h_FmPcd)->physicalMuramBase)) >> 4; + WRITE_UINT32(p_Ad->matchTblPtr, tmpReg32); + + tmpReg32 = HMAN_OC_IPSEC_MANIP; + tmpReg32 |= p_IPSecParams->outerIPHdrLen + << FM_PCD_MANIP_IPSEC_IP_HDR_LEN_SHIFT; + if (p_ManipParams->h_NextManip) + tmpReg32 |= FM_PCD_MANIP_IPSEC_NADEN; + WRITE_UINT32(p_Ad->pcAndOffsets, tmpReg32); + + return err; +} + +static t_Error SetCapwapReassmManip(t_FmPcdManip *p_Manip) +{ + t_FmPcd *p_FmPcd = (t_FmPcd *)p_Manip->h_FmPcd; + + /* Allocation if CAPWAP Action descriptor */ + p_Manip->reassmParams.capwap.h_Ad = (t_Handle)XX_MallocSmart( + FM_PCD_CC_AD_ENTRY_SIZE, p_Manip->reassmParams.dataMemId, + FM_PCD_CC_AD_TABLE_ALIGN); + if (!p_Manip->reassmParams.capwap.h_Ad) + { + ReleaseManipHandler(p_Manip, p_FmPcd); + RETURN_ERROR(MAJOR, E_NO_MEMORY, + ("Allocation of CAPWAP table descriptor")); + } + + memset(p_Manip->reassmParams.capwap.h_Ad, 0, FM_PCD_CC_AD_ENTRY_SIZE); + + /* Fill reassembly manipulation parameter in the Reassembly Action Descriptor */ + return FillReassmManipParams(p_Manip, HEADER_TYPE_CAPWAP); +} + +static void setCapwapReassmSchemeParams(t_FmPcd* p_FmPcd, + t_FmPcdKgSchemeParams *p_Scheme, + t_Handle h_CcTree, uint8_t groupId) +{ + uint8_t res; + + /* Configures scheme's network environment parameters */ + p_Scheme->netEnvParams.numOfDistinctionUnits = 1; + res = FmPcdNetEnvGetUnitId( + p_FmPcd, FmPcdGetNetEnvId(p_Scheme->netEnvParams.h_NetEnv), + HEADER_TYPE_USER_DEFINED_SHIM2, FALSE, 0); + ASSERT_COND(res != FM_PCD_MAX_NUM_OF_DISTINCTION_UNITS); + p_Scheme->netEnvParams.unitIds[0] = res; + + /* Configures scheme's next engine parameters*/ + p_Scheme->nextEngine = e_FM_PCD_CC; + p_Scheme->kgNextEngineParams.cc.h_CcTree = h_CcTree; + p_Scheme->kgNextEngineParams.cc.grpId = groupId; + p_Scheme->useHash = TRUE; + + /* Configures scheme's key*/ + p_Scheme->keyExtractAndHashParams.numOfUsedExtracts = 2; + p_Scheme->keyExtractAndHashParams.extractArray[0].type = + e_FM_PCD_EXTRACT_NON_HDR; + p_Scheme->keyExtractAndHashParams.extractArray[0].extractNonHdr.src = + e_FM_PCD_EXTRACT_FROM_PARSE_RESULT; + p_Scheme->keyExtractAndHashParams.extractArray[0].extractNonHdr.action = + e_FM_PCD_ACTION_NONE; + p_Scheme->keyExtractAndHashParams.extractArray[0].extractNonHdr.offset = 20; + p_Scheme->keyExtractAndHashParams.extractArray[0].extractNonHdr.size = 4; + p_Scheme->keyExtractAndHashParams.extractArray[1].type = + e_FM_PCD_EXTRACT_NON_HDR; + p_Scheme->keyExtractAndHashParams.extractArray[1].extractNonHdr.src = + e_FM_PCD_EXTRACT_FROM_DFLT_VALUE; + p_Scheme->keyExtractAndHashParams.extractArray[1].extractNonHdr.action = + e_FM_PCD_ACTION_NONE; + p_Scheme->keyExtractAndHashParams.extractArray[1].extractNonHdr.offset = 0; + p_Scheme->keyExtractAndHashParams.extractArray[1].extractNonHdr.size = 1; + + p_Scheme->keyExtractAndHashParams.privateDflt0 = 0x0; + p_Scheme->keyExtractAndHashParams.privateDflt1 = 0x0; + p_Scheme->keyExtractAndHashParams.numOfUsedDflts = 1; + p_Scheme->keyExtractAndHashParams.dflts[0].type = e_FM_PCD_KG_GENERIC_NOT_FROM_DATA; + p_Scheme->keyExtractAndHashParams.dflts[0].dfltSelect = e_FM_PCD_KG_DFLT_PRIVATE_0; +} + +#if (DPAA_VERSION >= 11) +static t_Error CapwapReassemblyStats(t_FmPcdManip *p_Manip, + t_FmPcdManipReassemCapwapStats *p_Stats) +{ + ASSERT_COND(p_Manip); + ASSERT_COND(p_Stats); + ASSERT_COND(p_Manip->reassmParams.p_ReassCommonTbl); + + p_Stats->timeout = + GET_UINT32(p_Manip->reassmParams.p_ReassCommonTbl->totalTimeOutCounter); + p_Stats->rfdPoolBusy = + GET_UINT32(p_Manip->reassmParams.p_ReassCommonTbl->totalRfdPoolBusyCounter); + p_Stats->internalBufferBusy = + GET_UINT32(p_Manip->reassmParams.p_ReassCommonTbl->totalInternalBufferBusy); + p_Stats->externalBufferBusy = + GET_UINT32(p_Manip->reassmParams.p_ReassCommonTbl->totalExternalBufferBusy); + p_Stats->sgFragments = + GET_UINT32(p_Manip->reassmParams.p_ReassCommonTbl->totalSgFragmentCounter); + p_Stats->dmaSemaphoreDepletion = + GET_UINT32(p_Manip->reassmParams.p_ReassCommonTbl->totalDmaSemaphoreDepletionCounter); + p_Stats->exceedMaxReassemblyFrameLen = + GET_UINT32(p_Manip->reassmParams.p_ReassCommonTbl->totalNCSPCounter); + + p_Stats->successfullyReassembled = + GET_UINT32(p_Manip->reassmParams.capwap.p_ReassTbl->totalSuccessfullyReasmFramesCounter); + p_Stats->validFragments = + GET_UINT32(p_Manip->reassmParams.capwap.p_ReassTbl->totalValidFragmentCounter); + p_Stats->processedFragments = + GET_UINT32(p_Manip->reassmParams.capwap.p_ReassTbl->totalProcessedFragCounter); + p_Stats->malformedFragments = + GET_UINT32(p_Manip->reassmParams.capwap.p_ReassTbl->totalMalformdFragCounter); + p_Stats->autoLearnBusy = + GET_UINT32(p_Manip->reassmParams.capwap.p_ReassTbl->totalSetBusyCounter); + p_Stats->discardedFragments = + GET_UINT32(p_Manip->reassmParams.capwap.p_ReassTbl->totalDiscardedFragsCounter); + p_Stats->moreThan16Fragments = + GET_UINT32(p_Manip->reassmParams.capwap.p_ReassTbl->totalMoreThan16FramesCounter); + + return E_OK; +} + +static t_Error CapwapFragmentationStats(t_FmPcdManip *p_Manip, + t_FmPcdManipFragCapwapStats *p_Stats) +{ + t_AdOfTypeContLookup *p_Ad; + + ASSERT_COND(p_Manip); + ASSERT_COND(p_Stats); + ASSERT_COND(p_Manip->h_Ad); + ASSERT_COND(p_Manip->fragParams.p_Frag); + + p_Ad = (t_AdOfTypeContLookup *)p_Manip->h_Ad; + + p_Stats->totalFrames = GET_UINT32(p_Ad->gmask); + + return E_OK; +} + +static t_Error CapwapReassembly(t_FmPcdManipReassemParams *p_ManipReassmParams, + t_FmPcdManip *p_Manip) +{ + uint32_t maxSetNumber = 10000; + t_FmPcdManipReassemCapwapParams reassmManipParams = + p_ManipReassmParams->u.capwapReassem; + t_Error res; + + SANITY_CHECK_RETURN_ERROR(p_Manip->h_FmPcd, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(((t_FmPcd *)p_Manip->h_FmPcd)->h_Hc, + E_INVALID_HANDLE); + + /* Check validation of user's parameter.*/ + if ((reassmManipParams.timeoutThresholdForReassmProcess < 1000) + || (reassmManipParams.timeoutThresholdForReassmProcess > 8000000)) + RETURN_ERROR( + MAJOR, E_INVALID_VALUE, + ("timeoutThresholdForReassmProcess should be 1msec - 8sec")); + /* It is recommended that the total number of entries in this table (number of sets * number of ways) + will be twice the number of frames that are expected to be reassembled simultaneously.*/ + if (reassmManipParams.maxNumFramesInProcess + > (reassmManipParams.maxNumFramesInProcess * maxSetNumber / 2)) + RETURN_ERROR( + MAJOR, + E_INVALID_VALUE, + ("maxNumFramesInProcess has to be less than (maximun set number * number of ways / 2)")); + + /* Saves user's reassembly manipulation parameters */ + p_Manip->reassmParams.capwap.relativeSchemeId = + reassmManipParams.relativeSchemeId; + p_Manip->reassmParams.capwap.numOfFramesPerHashEntry = + reassmManipParams.numOfFramesPerHashEntry; + p_Manip->reassmParams.capwap.maxRessembledsSize = + reassmManipParams.maxReassembledFrameLength; + p_Manip->reassmParams.maxNumFramesInProcess = + reassmManipParams.maxNumFramesInProcess; + p_Manip->reassmParams.timeOutMode = reassmManipParams.timeOutMode; + p_Manip->reassmParams.fqidForTimeOutFrames = + reassmManipParams.fqidForTimeOutFrames; + p_Manip->reassmParams.timeoutThresholdForReassmProcess = + reassmManipParams.timeoutThresholdForReassmProcess; + p_Manip->reassmParams.dataMemId = reassmManipParams.dataMemId; + p_Manip->reassmParams.dataLiodnOffset = reassmManipParams.dataLiodnOffset; + + /* Creates and initializes the Reassembly common parameter table */ + CreateReassCommonTable(p_Manip); + + res = SetCapwapReassmManip(p_Manip); + if (res != E_OK) + return res; + + return E_OK; +} + +static t_Error CapwapFragmentation(t_FmPcdManipFragCapwapParams *p_ManipParams, + t_FmPcdManip *p_Manip) +{ + t_FmPcd *p_FmPcd; + t_AdOfTypeContLookup *p_Ad; + uint32_t pcAndOffsetsReg = 0, ccAdBaseReg = 0, gmaskReg = 0; + uint32_t tmpReg32 = 0, tmpRegNia = 0; + + SANITY_CHECK_RETURN_ERROR(p_Manip->h_Ad, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_ManipParams->sizeForFragmentation != 0xFFFF, + E_INVALID_VALUE); + p_FmPcd = p_Manip->h_FmPcd; + SANITY_CHECK_RETURN_ERROR(p_FmPcd, E_INVALID_HANDLE); + + /* Allocation of fragmentation Action Descriptor */ + p_Manip->fragParams.p_Frag = (t_AdOfTypeContLookup *)FM_MURAM_AllocMem( + p_FmPcd->h_FmMuram, FM_PCD_CC_AD_ENTRY_SIZE, + FM_PCD_CC_AD_TABLE_ALIGN); + if (!p_Manip->fragParams.p_Frag) + RETURN_ERROR(MAJOR, E_NO_MEMORY, + ("MURAM alloc for Fragmentation table descriptor")); + MemSet8(p_Manip->fragParams.p_Frag, 0, FM_PCD_CC_AD_ENTRY_SIZE); + + /* Prepare the third Ad register (pcAndOffsets)- OperationCode */ + pcAndOffsetsReg = (uint32_t)HMAN_OC_CAPWAP_FRAGMENTATION; + + /* Prepare the first Ad register (ccAdBase) - Don't frag action and Action descriptor type*/ + ccAdBaseReg = FM_PCD_AD_CONT_LOOKUP_TYPE; + ccAdBaseReg |= + (p_ManipParams->compressModeEn) ? FM_PCD_MANIP_CAPWAP_FRAG_COMPRESS_EN : + 0; + + /* Set Scatter/Gather BPid */ + if (p_ManipParams->sgBpidEn) + { + ccAdBaseReg |= FM_PCD_MANIP_CAPWAP_FRAG_SG_BDID_EN; + pcAndOffsetsReg |= ((p_ManipParams->sgBpid + << FM_PCD_MANIP_CAPWAP_FRAG_SG_BDID_SHIFT) + & FM_PCD_MANIP_CAPWAP_FRAG_SG_BDID_MASK); + } + + /* Prepare the first Ad register (gmask) - scratch buffer pool id and Pointer to fragment ID */ + gmaskReg = (uint32_t)(XX_VirtToPhys(UINT_TO_PTR(p_FmPcd->capwapFrameIdAddr)) + - p_FmPcd->physicalMuramBase); + gmaskReg |= (0xFF) << FM_PCD_MANIP_IP_FRAG_SCRATCH_BPID; + + /* Set all Ad registers */ + WRITE_UINT32(p_Manip->fragParams.p_Frag->pcAndOffsets, pcAndOffsetsReg); + WRITE_UINT32(p_Manip->fragParams.p_Frag->ccAdBase, ccAdBaseReg); + WRITE_UINT32(p_Manip->fragParams.p_Frag->gmask, gmaskReg); + + /* Saves user's fragmentation manipulation parameters */ + p_Manip->frag = TRUE; + p_Manip->sizeForFragmentation = p_ManipParams->sizeForFragmentation; + + p_Ad = (t_AdOfTypeContLookup *)p_Manip->h_Ad; + + tmpRegNia = (uint32_t)(XX_VirtToPhys(p_Manip->fragParams.p_Frag) + - (p_FmPcd->physicalMuramBase)); + tmpReg32 = (uint32_t)p_Manip->sizeForFragmentation + << FM_PCD_MANIP_CAPWAP_FRAG_CHECK_MTU_SHIFT; + + tmpRegNia |= FM_PCD_AD_CONT_LOOKUP_TYPE; + tmpReg32 |= HMAN_OC_CAPWAP_FRAG_CHECK; + + tmpRegNia |= FM_PCD_MANIP_CAPWAP_FRAG_CHECK_CNIA; + + WRITE_UINT32(p_Ad->pcAndOffsets, tmpReg32); + WRITE_UINT32(p_Ad->ccAdBase, tmpRegNia); + WRITE_UINT32(p_Ad->gmask, 0); + /* Total frame counter - MUST be initialized to zero.*/ + + return E_OK; +} + +static t_Error UpdateInitCapwapFrag(t_Handle h_FmPcd, t_Handle h_PcdParams, + t_Handle h_FmPort, t_FmPcdManip *p_Manip, + t_Handle h_Ad, bool validate) +{ + t_FmPortGetSetCcParams fmPortGetSetCcParams; + t_Error err; + + SANITY_CHECK_RETURN_ERROR(p_Manip, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR((p_Manip->opcode == HMAN_OC_CAPWAP_FRAGMENTATION), + E_INVALID_STATE); + SANITY_CHECK_RETURN_ERROR(h_FmPcd, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(h_FmPort, E_INVALID_HANDLE); + + UNUSED(h_FmPcd); + UNUSED(h_Ad); + UNUSED(h_PcdParams); + UNUSED(validate); + UNUSED(p_Manip); + + fmPortGetSetCcParams.setCcParams.type = 0; + fmPortGetSetCcParams.getCcParams.type = MANIP_EXTRA_SPACE; + if ((err = FmPortGetSetCcParams(h_FmPort, &fmPortGetSetCcParams)) != E_OK) + RETURN_ERROR(MAJOR, err, NO_MSG); + + if (!fmPortGetSetCcParams.getCcParams.internalBufferOffset) + DBG(WARNING, ("manipExtraSpace must be larger than '0'")); + + return E_OK; +} + +static t_Error CapwapManip(t_FmPcdManipParams *p_ManipParams, + t_FmPcdManip *p_Manip) +{ + t_AdOfTypeContLookup *p_Ad; + t_FmPcdManipSpecialOffloadCapwapParams *p_Params; + t_Error err = E_OK; + uint32_t tmpReg32 = 0; + + SANITY_CHECK_RETURN_ERROR(p_Manip, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_ManipParams, E_INVALID_HANDLE); + + p_Params = &p_ManipParams->u.specialOffload.u.capwap; + + p_Ad = (t_AdOfTypeContLookup *)p_Manip->h_Ad; + tmpReg32 |= FM_PCD_AD_CONT_LOOKUP_TYPE; + tmpReg32 |= (p_Params->dtls) ? FM_PCD_MANIP_CAPWAP_DTLS : 0; + /* TODO - add 'qosSrc' */ + WRITE_UINT32(p_Ad->ccAdBase, tmpReg32); + + tmpReg32 = HMAN_OC_CAPWAP_MANIP; + if (p_ManipParams->h_NextManip) + { + WRITE_UINT32( + p_Ad->matchTblPtr, + (uint32_t)(XX_VirtToPhys(((t_FmPcdManip *)p_ManipParams->h_NextManip)->h_Ad)- (((t_FmPcd *)p_Manip->h_FmPcd)->physicalMuramBase)) >> 4); + + tmpReg32 |= FM_PCD_MANIP_CAPWAP_NADEN; + } + + WRITE_UINT32(p_Ad->pcAndOffsets, tmpReg32); + + return err; +} +#endif /* (DPAA_VERSION >= 11) */ + +static t_Handle ManipOrStatsSetNode(t_Handle h_FmPcd, t_Handle *p_Params, + bool stats) +{ + t_FmPcdManip *p_Manip; + t_Error err; + t_FmPcd *p_FmPcd = (t_FmPcd *)h_FmPcd; + + p_Manip = (t_FmPcdManip*)XX_Malloc(sizeof(t_FmPcdManip)); + if (!p_Manip) + { + REPORT_ERROR(MAJOR, E_NO_MEMORY, ("No memory")); + return NULL; + } + memset(p_Manip, 0, sizeof(t_FmPcdManip)); + + p_Manip->type = ((t_FmPcdManipParams *)p_Params)->type; + memcpy((uint8_t*)&p_Manip->manipParams, p_Params, + sizeof(p_Manip->manipParams)); + + if (!stats) + err = CheckManipParamsAndSetType(p_Manip, + (t_FmPcdManipParams *)p_Params); +#if (defined(FM_CAPWAP_SUPPORT) && (DPAA_VERSION == 10)) + else + err = CheckStatsParamsAndSetType(p_Manip, (t_FmPcdStatsParams *)p_Params); +#else /* not (defined(FM_CAPWAP_SUPPORT) && (DPAA_VERSION == 10)) */ + else + { + REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Statistics node!")); + XX_Free(p_Manip); + return NULL; + } +#endif /* (defined(FM_CAPWAP_SUPPORT) && (DPAA_VERSION == 10)) */ + if (err) + { + REPORT_ERROR(MAJOR, E_INVALID_VALUE, ("Invalid header manipulation type")); + XX_Free(p_Manip); + return NULL; + } + + if ((p_Manip->opcode != HMAN_OC_IP_REASSEMBLY) && (p_Manip->opcode != HMAN_OC_CAPWAP_REASSEMBLY)) + { + /* In Case of reassembly manipulation the reassembly action descriptor will + be defines later on */ + if (p_Manip->muramAllocate) + { + p_Manip->h_Ad = (t_Handle)FM_MURAM_AllocMem( + p_FmPcd->h_FmMuram, FM_PCD_CC_AD_ENTRY_SIZE, + FM_PCD_CC_AD_TABLE_ALIGN); + if (!p_Manip->h_Ad) + { + REPORT_ERROR(MAJOR, E_NO_MEMORY, ("MURAM alloc for Manipulation action descriptor")); + ReleaseManipHandler(p_Manip, p_FmPcd); + XX_Free(p_Manip); + return NULL; + } + + MemSet8(p_Manip->h_Ad, 0, FM_PCD_CC_AD_ENTRY_SIZE); + } + else + { + p_Manip->h_Ad = (t_Handle)XX_Malloc( + FM_PCD_CC_AD_ENTRY_SIZE * sizeof(uint8_t)); + if (!p_Manip->h_Ad) + { + REPORT_ERROR(MAJOR, E_NO_MEMORY, ("Allocation of Manipulation action descriptor")); + ReleaseManipHandler(p_Manip, p_FmPcd); + XX_Free(p_Manip); + return NULL; + } + + memset(p_Manip->h_Ad, 0, FM_PCD_CC_AD_ENTRY_SIZE * sizeof(uint8_t)); + } + } + + p_Manip->h_FmPcd = h_FmPcd; + + return p_Manip; +} + +static void UpdateAdPtrOfNodesWhichPointsOnCrntMdfManip( + t_FmPcdManip *p_CrntMdfManip, t_List *h_NodesLst) +{ + t_CcNodeInformation *p_CcNodeInformation; + t_FmPcdCcNode *p_NodePtrOnCurrentMdfManip = NULL; + t_List *p_Pos; + int i = 0; + t_Handle p_AdTablePtOnCrntCurrentMdfNode/*, p_AdTableNewModified*/; + t_CcNodeInformation ccNodeInfo; + + LIST_FOR_EACH(p_Pos, &p_CrntMdfManip->nodesLst) + { + p_CcNodeInformation = CC_NODE_F_OBJECT(p_Pos); + p_NodePtrOnCurrentMdfManip = + (t_FmPcdCcNode *)p_CcNodeInformation->h_CcNode; + + ASSERT_COND(p_NodePtrOnCurrentMdfManip); + + /* Search in the previous node which exact index points on this current modified node for getting AD */ + for (i = 0; i < p_NodePtrOnCurrentMdfManip->numOfKeys + 1; i++) + { + if (p_NodePtrOnCurrentMdfManip->keyAndNextEngineParams[i].nextEngineParams.nextEngine + == e_FM_PCD_CC) + { + if (p_NodePtrOnCurrentMdfManip->keyAndNextEngineParams[i].nextEngineParams.h_Manip + == (t_Handle)p_CrntMdfManip) + { + if (p_NodePtrOnCurrentMdfManip->keyAndNextEngineParams[i].p_StatsObj) + p_AdTablePtOnCrntCurrentMdfNode = + p_NodePtrOnCurrentMdfManip->keyAndNextEngineParams[i].p_StatsObj->h_StatsAd; + else + p_AdTablePtOnCrntCurrentMdfNode = + PTR_MOVE(p_NodePtrOnCurrentMdfManip->h_AdTable, i*FM_PCD_CC_AD_ENTRY_SIZE); + + memset(&ccNodeInfo, 0, sizeof(t_CcNodeInformation)); + ccNodeInfo.h_CcNode = p_AdTablePtOnCrntCurrentMdfNode; + EnqueueNodeInfoToRelevantLst(h_NodesLst, &ccNodeInfo, NULL); + } + } + } + + ASSERT_COND(i != p_NodePtrOnCurrentMdfManip->numOfKeys); + } +} + +static void BuildHmtd(uint8_t *p_Dest, uint8_t *p_Src, uint8_t *p_Hmcd, + t_FmPcd *p_FmPcd) +{ + t_Error err; + + /* Copy the HMTD */ + MemCpy8(p_Dest, (uint8_t*)p_Src, 16); + /* Replace the HMCT table pointer */ + WRITE_UINT32( + ((t_Hmtd *)p_Dest)->hmcdBasePtr, + (uint32_t)(XX_VirtToPhys(p_Hmcd) - ((t_FmPcd*)p_FmPcd)->physicalMuramBase)); + /* Call Host Command to replace HMTD by a new HMTD */ + err = FmHcPcdCcDoDynamicChange( + p_FmPcd->h_Hc, + (uint32_t)(XX_VirtToPhys(p_Src) - p_FmPcd->physicalMuramBase), + (uint32_t)(XX_VirtToPhys(p_Dest) - p_FmPcd->physicalMuramBase)); + if (err) + REPORT_ERROR(MINOR, err, ("Failed in dynamic manip change, continued to the rest of the owners.")); +} + +static t_Error FmPcdManipInitUpdate(t_Handle h_FmPcd, t_Handle h_PcdParams, + t_Handle h_FmPort, t_Handle h_Manip, + t_Handle h_Ad, bool validate, int level, + t_Handle h_FmTree) +{ + t_FmPcdManip *p_Manip = (t_FmPcdManip *)h_Manip; + t_Error err = E_OK; + + SANITY_CHECK_RETURN_ERROR(h_Manip, E_INVALID_HANDLE); + + UNUSED(level); + UNUSED(h_FmTree); + + switch (p_Manip->opcode) + { +#if (defined(FM_CAPWAP_SUPPORT) && (DPAA_VERSION == 10)) + case (HMAN_OC_MV_INT_FRAME_HDR_FROM_FRM_TO_BUFFER_PREFFIX): + err = UpdateInitMvIntFrameHeaderFromFrameToBufferPrefix(h_FmPort, + p_Manip, + h_Ad, + validate); + break; + case (HMAN_OC_INSRT_HDR_BY_TEMPL_N_OR_FRAG_AFTER): + if (!p_Manip->h_Frag) + break; + case (HMAN_OC_CAPWAP_FRAGMENTATION): + err = UpdateInitCapwapFragmentation(h_FmPort, p_Manip, h_Ad, validate, h_FmTree); + break; + case (HMAN_OC_CAPWAP_RMV_DTLS_IF_EXIST): + if (p_Manip->h_Frag) + err = UpdateInitCapwapReasm(h_FmPcd, h_FmPort, p_Manip, h_Ad, validate); + break; + case (HMAN_OC_CAPWAP_INDEXED_STATS): + err = UpdateIndxStats(h_FmPcd, h_FmPort, p_Manip); + break; +#endif /* (defined(FM_CAPWAP_SUPPORT) && (DPAA_VERSION == 10)) */ + case (HMAN_OC_IP_REASSEMBLY): + err = UpdateInitReasm(h_FmPcd, h_PcdParams, h_FmPort, p_Manip, h_Ad, + validate); + break; + case (HMAN_OC_IP_FRAGMENTATION): + err = UpdateInitIpFrag(h_FmPcd, h_PcdParams, h_FmPort, p_Manip, + h_Ad, validate); + break; +#if (DPAA_VERSION >= 11) + case (HMAN_OC_CAPWAP_FRAGMENTATION): + err = UpdateInitCapwapFrag(h_FmPcd, h_PcdParams, h_FmPort, p_Manip, + h_Ad, validate); + break; + case (HMAN_OC_CAPWAP_REASSEMBLY): + err = UpdateInitReasm(h_FmPcd, h_PcdParams, h_FmPort, p_Manip, h_Ad, + validate); + break; +#endif /* (DPAA_VERSION >= 11) */ + default: + return E_OK; + } + + return err; +} + +static t_Error FmPcdManipModifyUpdate(t_Handle h_Manip, t_Handle h_Ad, + bool validate, int level, + t_Handle h_FmTree) +{ + + t_FmPcdManip *p_Manip = (t_FmPcdManip *)h_Manip; + t_Error err = E_OK; + + UNUSED(level); + + switch (p_Manip->opcode) + { +#if (defined(FM_CAPWAP_SUPPORT) && (DPAA_VERSION == 10)) + case (HMAN_OC_MV_INT_FRAME_HDR_FROM_FRM_TO_BUFFER_PREFFIX): + RETURN_ERROR( + MAJOR, + E_INVALID_STATE, + ("modify node with this type of manipulation is not suppported")); + case (HMAN_OC_CAPWAP_RMV_DTLS_IF_EXIST): + + if (p_Manip->h_Frag) + { + if (!(p_Manip->shadowUpdateParams & NUM_OF_TASKS) + && !(p_Manip->shadowUpdateParams & OFFSET_OF_DATA) + && !(p_Manip->shadowUpdateParams & OFFSET_OF_PR)) + RETURN_ERROR( + MAJOR, + E_INVALID_STATE, + ("modify node with this type of manipulation requires manipulation be updated previously in SetPcd function")); + } + break; + case (HMAN_OC_INSRT_HDR_BY_TEMPL_N_OR_FRAG_AFTER): + if (p_Manip->h_Frag) + err = UpdateModifyCapwapFragmenation(p_Manip, h_Ad, validate, h_FmTree); + break; +#endif /* (defined(FM_CAPWAP_SUPPORT) && (DPAA_VERSION == 10)) */ + default: + return E_OK; + } + + return err; +} + +/*****************************************************************************/ +/* Inter-module API routines */ +/*****************************************************************************/ + +t_Error FmPcdManipUpdate(t_Handle h_FmPcd, t_Handle h_PcdParams, + t_Handle h_FmPort, t_Handle h_Manip, t_Handle h_Ad, + bool validate, int level, t_Handle h_FmTree, + bool modify) +{ + t_Error err; + + if (!modify) + err = FmPcdManipInitUpdate(h_FmPcd, h_PcdParams, h_FmPort, h_Manip, + h_Ad, validate, level, h_FmTree); + else + err = FmPcdManipModifyUpdate(h_Manip, h_Ad, validate, level, h_FmTree); + + return err; +} + +void FmPcdManipUpdateOwner(t_Handle h_Manip, bool add) +{ + + uint32_t intFlags; + + intFlags = XX_LockIntrSpinlock(((t_FmPcdManip *)h_Manip)->h_Spinlock); + if (add) + ((t_FmPcdManip *)h_Manip)->owner++; + else + { + ASSERT_COND(((t_FmPcdManip *)h_Manip)->owner); + ((t_FmPcdManip *)h_Manip)->owner--; + } + XX_UnlockIntrSpinlock(((t_FmPcdManip *)h_Manip)->h_Spinlock, intFlags); +} + +t_List *FmPcdManipGetNodeLstPointedOnThisManip(t_Handle h_Manip) +{ + ASSERT_COND(h_Manip); + return &((t_FmPcdManip *)h_Manip)->nodesLst; +} + +t_List *FmPcdManipGetSpinlock(t_Handle h_Manip) +{ + ASSERT_COND(h_Manip); + return ((t_FmPcdManip *)h_Manip)->h_Spinlock; +} + +t_Error FmPcdManipCheckParamsForCcNextEngine( + t_FmPcdCcNextEngineParams *p_FmPcdCcNextEngineParams, + uint32_t *requiredAction) +{ + t_FmPcdManip *p_Manip; +#if (defined(FM_CAPWAP_SUPPORT) && (DPAA_VERSION == 10)) + t_Error err = E_OK; +#endif /* (defined(FM_CAPWAP_SUPPORT) && (DPAA_VERSION == 10))*/ + bool pointFromCc = TRUE; + + SANITY_CHECK_RETURN_ERROR(p_FmPcdCcNextEngineParams, E_NULL_POINTER); + SANITY_CHECK_RETURN_ERROR(p_FmPcdCcNextEngineParams->h_Manip, + E_NULL_POINTER); + + p_Manip = (t_FmPcdManip *)(p_FmPcdCcNextEngineParams->h_Manip); + *requiredAction = 0; + + while (p_Manip) + { + switch (p_Manip->opcode) + { +#if (defined(FM_CAPWAP_SUPPORT) && (DPAA_VERSION == 10)) + case (HMAN_OC_CAPWAP_INDEXED_STATS): + if (p_FmPcdCcNextEngineParams->nextEngine != e_FM_PCD_DONE) + RETURN_ERROR(MAJOR, E_INVALID_STATE, ("For this type of header manipulation has to be nextEngine e_FM_PCD_DONE")); + if (p_FmPcdCcNextEngineParams->params.enqueueParams.overrideFqid) + p_Manip->cnia = TRUE; + case (HMAN_OC_CAPWAP_RMV_DTLS_IF_EXIST): + *requiredAction = UPDATE_NIA_ENQ_WITHOUT_DMA; + case (HMAN_OC_RMV_N_OR_INSRT_INT_FRM_HDR): + p_Manip->ownerTmp++; + break; + case (HMAN_OC_INSRT_HDR_BY_TEMPL_N_OR_FRAG_AFTER): + if ((p_FmPcdCcNextEngineParams->nextEngine != e_FM_PCD_DONE) + && !p_FmPcdCcNextEngineParams->params.enqueueParams.overrideFqid) + RETURN_ERROR( + MAJOR, + E_INVALID_STATE, + ("For this type of header manipulation has to be nextEngine e_FM_PCD_DONE with fqidForCtrlFlow FALSE")); + p_Manip->ownerTmp++; + break; + case (HMAN_OC_MV_INT_FRAME_HDR_FROM_FRM_TO_BUFFER_PREFFIX): + if ((p_FmPcdCcNextEngineParams->nextEngine != e_FM_PCD_CC) + && (FmPcdCcGetParseCode(p_FmPcdCcNextEngineParams->params.ccParams.h_CcNode) + != CC_PC_GENERIC_IC_HASH_INDEXED)) + RETURN_ERROR(MAJOR, E_INVALID_STATE, ("For this type of header manipulation next engine has to be CC and action = e_FM_PCD_ACTION_INDEXED_LOOKUP")); + err = UpdateManipIc(p_FmPcdCcNextEngineParams->h_Manip, + FmPcdCcGetOffset(p_FmPcdCcNextEngineParams->params.ccParams.h_CcNode)); + if (err) + RETURN_ERROR(MAJOR, err, NO_MSG); + *requiredAction = UPDATE_NIA_ENQ_WITHOUT_DMA; + break; + #endif /* (defined(FM_CAPWAP_SUPPORT) && (DPAA_VERSION == 10)) */ + case (HMAN_OC_IP_FRAGMENTATION): + case (HMAN_OC_IP_REASSEMBLY): +#if (DPAA_VERSION >= 11) + case (HMAN_OC_CAPWAP_REASSEMBLY): + case (HMAN_OC_CAPWAP_FRAGMENTATION): +#endif /* (DPAA_VERSION >= 11) */ + if (p_FmPcdCcNextEngineParams->nextEngine != e_FM_PCD_DONE) + RETURN_ERROR( + MAJOR, + E_INVALID_STATE, + ("For this type of header manipulation has to be nextEngine e_FM_PCD_DONE")); + p_Manip->ownerTmp++; + break; + case (HMAN_OC_IPSEC_MANIP): +#if (DPAA_VERSION >= 11) + case (HMAN_OC_CAPWAP_MANIP): +#endif /* (DPAA_VERSION >= 11) */ + p_Manip->ownerTmp++; + break; + case (HMAN_OC): + if ((p_FmPcdCcNextEngineParams->nextEngine == e_FM_PCD_CC) + && MANIP_IS_CASCADED(p_Manip)) + RETURN_ERROR( + MINOR, + E_INVALID_STATE, + ("Can't have a cascaded manipulation when and Next Engine is CC")); + if (!MANIP_IS_FIRST(p_Manip) && pointFromCc) + RETURN_ERROR( + MAJOR, + E_INVALID_STATE, + ("h_Manip is already used and may not be shared (no sharing of non-head manip nodes)")); + break; + default: + RETURN_ERROR( + MAJOR, E_INVALID_STATE, + ("invalid type of header manipulation for this state")); + } + p_Manip = p_Manip->h_NextManip; + pointFromCc = FALSE; + } + return E_OK; +} + + +t_Error FmPcdManipCheckParamsWithCcNodeParams(t_Handle h_Manip, + t_Handle h_FmPcdCcNode) +{ + t_FmPcdManip *p_Manip = (t_FmPcdManip *)h_Manip; + t_Error err = E_OK; + + SANITY_CHECK_RETURN_ERROR(h_Manip, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(h_FmPcdCcNode, E_INVALID_HANDLE); + + switch (p_Manip->opcode) + { +#if (defined(FM_CAPWAP_SUPPORT) && (DPAA_VERSION == 10)) + case (HMAN_OC_CAPWAP_INDEXED_STATS): + if (p_Manip->ownerTmp != FmPcdCcGetNumOfKeys(h_FmPcdCcNode)) + RETURN_ERROR( + MAJOR, + E_INVALID_VALUE, + ("The manipulation of the type statistics flowId if exist has to be pointed by all numOfKeys")); + break; + case (HMAN_OC_CAPWAP_RMV_DTLS_IF_EXIST): + if (p_Manip->h_Frag) + { + if (p_Manip->ownerTmp != FmPcdCcGetNumOfKeys(h_FmPcdCcNode)) + RETURN_ERROR( + MAJOR, + E_INVALID_VALUE, + ("The manipulation of the type remove DTLS if exist has to be pointed by all numOfKeys")); + err = UpdateManipIc(h_Manip, FmPcdCcGetOffset(h_FmPcdCcNode)); + if (err) + RETURN_ERROR(MAJOR, err, NO_MSG); + } + break; +#endif /* (defined(FM_CAPWAP_SUPPORT) && (DPAA_VERSION == 10)) */ + default: + break; + } + + return err; +} + +void FmPcdManipUpdateAdResultForCc( + t_Handle h_Manip, t_FmPcdCcNextEngineParams *p_CcNextEngineParams, + t_Handle p_Ad, t_Handle *p_AdNewPtr) +{ + t_FmPcdManip *p_Manip = (t_FmPcdManip *)h_Manip; + + /* This routine creates a Manip AD and can return in "p_AdNewPtr" + * either the new descriptor or NULL if it writes the Manip AD into p_AD (into the match table) */ + + ASSERT_COND(p_Manip); + ASSERT_COND(p_CcNextEngineParams); + ASSERT_COND(p_Ad); + ASSERT_COND(p_AdNewPtr); + + FmPcdManipUpdateOwner(h_Manip, TRUE); + + /* According to "type", either build & initialize a new AD (p_AdNew) or initialize + * p_Ad ( the AD in the match table) and set p_AdNew = NULL. */ + switch (p_Manip->opcode) + { +#if (defined(FM_CAPWAP_SUPPORT) && (DPAA_VERSION == 10)) + case (HMAN_OC_RMV_N_OR_INSRT_INT_FRM_HDR): + case (HMAN_OC_CAPWAP_RMV_DTLS_IF_EXIST): + case (HMAN_OC_CAPWAP_INDEXED_STATS): + *p_AdNewPtr = p_Manip->h_Ad; + break; + case (HMAN_OC_INSRT_HDR_BY_TEMPL_N_OR_FRAG_AFTER): + case (HMAN_OC_CAPWAP_FRAGMENTATION): + WRITE_UINT32(((t_AdOfTypeResult *)p_Ad)->fqid, + ((t_AdOfTypeResult *)(p_Manip->h_Ad))->fqid); + WRITE_UINT32(((t_AdOfTypeResult *)p_Ad)->plcrProfile, + ((t_AdOfTypeResult *)(p_Manip->h_Ad))->plcrProfile); + WRITE_UINT32(((t_AdOfTypeResult *)p_Ad)->nia, + ((t_AdOfTypeResult *)(p_Manip->h_Ad))->nia); + *p_AdNewPtr = NULL; + break; +#endif /* (defined(FM_CAPWAP_SUPPORT) && (DPAA_VERSION == 10)) */ + case (HMAN_OC_IPSEC_MANIP): +#if (DPAA_VERSION >= 11) + case (HMAN_OC_CAPWAP_MANIP): +#endif /* (DPAA_VERSION >= 11) */ + *p_AdNewPtr = p_Manip->h_Ad; + break; + case (HMAN_OC_IP_FRAGMENTATION): +#if (DPAA_VERSION >= 11) + case (HMAN_OC_CAPWAP_FRAGMENTATION): +#endif /* (DPAA_VERSION >= 11) */ + if ((p_CcNextEngineParams->nextEngine == e_FM_PCD_DONE) + && (!p_CcNextEngineParams->params.enqueueParams.overrideFqid)) + { + memcpy((uint8_t *)p_Ad, (uint8_t *)p_Manip->h_Ad, + sizeof(t_AdOfTypeContLookup)); +#if (DPAA_VERSION >= 11) + WRITE_UINT32( + ((t_AdOfTypeContLookup *)p_Ad)->ccAdBase, + GET_UINT32(((t_AdOfTypeContLookup *)p_Ad)->ccAdBase) & ~FM_PCD_MANIP_IP_CNIA); +#endif /* (DPAA_VERSION >= 11) */ + *p_AdNewPtr = NULL; + } + else + *p_AdNewPtr = p_Manip->h_Ad; + break; + case (HMAN_OC_IP_REASSEMBLY): + if (FmPcdManipIpReassmIsIpv6Hdr(p_Manip)) + { + if (!p_Manip->reassmParams.ip.ipv6Assigned) + { + *p_AdNewPtr = p_Manip->reassmParams.ip.h_Ipv6Ad; + p_Manip->reassmParams.ip.ipv6Assigned = TRUE; + FmPcdManipUpdateOwner(h_Manip, FALSE); + } + else + { + *p_AdNewPtr = p_Manip->reassmParams.ip.h_Ipv4Ad; + p_Manip->reassmParams.ip.ipv6Assigned = FALSE; + } + } + else + *p_AdNewPtr = p_Manip->reassmParams.ip.h_Ipv4Ad; + memcpy((uint8_t *)p_Ad, (uint8_t *)*p_AdNewPtr, + sizeof(t_AdOfTypeContLookup)); + *p_AdNewPtr = NULL; + break; +#if (DPAA_VERSION >= 11) + case (HMAN_OC_CAPWAP_REASSEMBLY): + *p_AdNewPtr = p_Manip->reassmParams.capwap.h_Ad; + memcpy((uint8_t *)p_Ad, (uint8_t *)*p_AdNewPtr, + sizeof(t_AdOfTypeContLookup)); + *p_AdNewPtr = NULL; + break; +#endif /* (DPAA_VERSION >= 11) */ + case (HMAN_OC): + /* Allocate and initialize HMTD */ + *p_AdNewPtr = p_Manip->h_Ad; + break; + default: + break; + } +} + +void FmPcdManipUpdateAdContLookupForCc(t_Handle h_Manip, t_Handle p_Ad, + t_Handle *p_AdNewPtr, + uint32_t adTableOffset) +{ + t_FmPcdManip *p_Manip = (t_FmPcdManip *)h_Manip; + + /* This routine creates a Manip AD and can return in "p_AdNewPtr" + * either the new descriptor or NULL if it writes the Manip AD into p_AD (into the match table) */ + ASSERT_COND(p_Manip); + + FmPcdManipUpdateOwner(h_Manip, TRUE); + + switch (p_Manip->opcode) + { +#if (defined(FM_CAPWAP_SUPPORT) && (DPAA_VERSION == 10)) + case (HMAN_OC_MV_INT_FRAME_HDR_FROM_FRM_TO_BUFFER_PREFFIX): + WRITE_UINT32(((t_AdOfTypeContLookup *)p_Ad)->ccAdBase, + ((t_AdOfTypeContLookup *)(p_Manip->h_Ad))->ccAdBase); + WRITE_UINT32( + ((t_AdOfTypeContLookup *)p_Ad)->matchTblPtr, + ((t_AdOfTypeContLookup *)(p_Manip->h_Ad))->matchTblPtr); + WRITE_UINT32( + ((t_AdOfTypeContLookup *)p_Ad)->pcAndOffsets, + ((t_AdOfTypeContLookup *)(p_Manip->h_Ad))->pcAndOffsets); + WRITE_UINT32(((t_AdOfTypeContLookup *)p_Ad)->gmask, + ((t_AdOfTypeContLookup *)(p_Manip->h_Ad))->gmask); + WRITE_UINT32( + ((t_AdOfTypeContLookup *)p_Ad)->ccAdBase, + (GET_UINT32(((t_AdOfTypeContLookup *)p_Ad)->ccAdBase) | adTableOffset)); + *p_AdNewPtr = NULL; + break; +#endif /* (defined(FM_CAPWAP_SUPPORT) && (DPAA_VERSION == 10)) */ + case (HMAN_OC): + /* Initialize HMTD within the match table*/ + MemSet8(p_Ad, 0, FM_PCD_CC_AD_ENTRY_SIZE); + /* copy the existing HMTD *//* ask Alla - memcpy??? */ + memcpy((uint8_t*)p_Ad, p_Manip->h_Ad, sizeof(t_Hmtd)); + /* update NADEN to be "1"*/ + WRITE_UINT16( + ((t_Hmtd *)p_Ad)->cfg, + (uint16_t)(GET_UINT16(((t_Hmtd *)p_Ad)->cfg) | HMTD_CFG_NEXT_AD_EN)); + /* update next action descriptor */ + WRITE_UINT16(((t_Hmtd *)p_Ad)->nextAdIdx, + (uint16_t)(adTableOffset >> 4)); + /* mark that Manip's HMTD is not used */ + *p_AdNewPtr = NULL; + break; + + default: + break; + } +} + +t_Error FmPcdManipBuildIpReassmScheme(t_FmPcd *p_FmPcd, t_Handle h_NetEnv, + t_Handle h_CcTree, t_Handle h_Manip, + bool isIpv4, uint8_t groupId) +{ + t_FmPcdManip *p_Manip = (t_FmPcdManip *)h_Manip; + t_FmPcdKgSchemeParams *p_SchemeParams = NULL; + t_Handle h_Scheme; + + ASSERT_COND(p_FmPcd); + ASSERT_COND(h_NetEnv); + ASSERT_COND(p_Manip); + + /* scheme was already build, no need to check for IPv6 */ + if (p_Manip->reassmParams.ip.h_Ipv4Scheme) + return E_OK; + + if (isIpv4) { + h_Scheme = FmPcdKgGetSchemeHandle(p_FmPcd, p_Manip->reassmParams.ip.relativeSchemeId[0]); + if (h_Scheme) { + /* scheme was found */ + p_Manip->reassmParams.ip.h_Ipv4Scheme = h_Scheme; + return E_OK; + } + } else { + h_Scheme = FmPcdKgGetSchemeHandle(p_FmPcd, p_Manip->reassmParams.ip.relativeSchemeId[1]); + if (h_Scheme) { + /* scheme was found */ + p_Manip->reassmParams.ip.h_Ipv6Scheme = h_Scheme; + return E_OK; + } + } + + p_SchemeParams = XX_Malloc(sizeof(t_FmPcdKgSchemeParams)); + if (!p_SchemeParams) + RETURN_ERROR(MAJOR, E_NO_MEMORY, + ("Memory allocation failed for scheme")); + + /* Configures the IPv4 or IPv6 scheme*/ + memset(p_SchemeParams, 0, sizeof(t_FmPcdKgSchemeParams)); + p_SchemeParams->netEnvParams.h_NetEnv = h_NetEnv; + p_SchemeParams->id.relativeSchemeId = (uint8_t)( + (isIpv4 == TRUE) ? p_Manip->reassmParams.ip.relativeSchemeId[0] : + p_Manip->reassmParams.ip.relativeSchemeId[1]); + p_SchemeParams->schemeCounter.update = TRUE; +#if (DPAA_VERSION >= 11) + p_SchemeParams->alwaysDirect = TRUE; + p_SchemeParams->bypassFqidGeneration = TRUE; +#else + p_SchemeParams->keyExtractAndHashParams.hashDistributionNumOfFqids = 1; + p_SchemeParams->baseFqid = 0xFFFFFF; /*TODO- baseFqid*/ +#endif /* (DPAA_VERSION >= 11) */ + + setIpReassmSchemeParams(p_FmPcd, p_SchemeParams, h_CcTree, isIpv4, groupId); + + /* Sets the new scheme */ + if (isIpv4) + p_Manip->reassmParams.ip.h_Ipv4Scheme = FM_PCD_KgSchemeSet( + p_FmPcd, p_SchemeParams); + else + p_Manip->reassmParams.ip.h_Ipv6Scheme = FM_PCD_KgSchemeSet( + p_FmPcd, p_SchemeParams); + + XX_Free(p_SchemeParams); + + return E_OK; +} + +t_Error FmPcdManipDeleteIpReassmSchemes(t_Handle h_Manip) +{ + t_FmPcdManip *p_Manip = (t_FmPcdManip *)h_Manip; + + ASSERT_COND(p_Manip); + + if ((p_Manip->reassmParams.ip.h_Ipv4Scheme) && + !FmPcdKgIsSchemeHasOwners(p_Manip->reassmParams.ip.h_Ipv4Scheme)) + FM_PCD_KgSchemeDelete(p_Manip->reassmParams.ip.h_Ipv4Scheme); + + if ((p_Manip->reassmParams.ip.h_Ipv6Scheme) && + !FmPcdKgIsSchemeHasOwners(p_Manip->reassmParams.ip.h_Ipv6Scheme)) + FM_PCD_KgSchemeDelete(p_Manip->reassmParams.ip.h_Ipv6Scheme); + + return E_OK; +} + +bool FmPcdManipIpReassmIsIpv6Hdr(t_Handle h_Manip) +{ + t_FmPcdManip *p_Manip = (t_FmPcdManip *)h_Manip; + + ASSERT_COND(p_Manip); + + return (p_Manip->reassmParams.hdr == HEADER_TYPE_IPv6); +} + +t_Error FmPcdManipBuildCapwapReassmScheme(t_FmPcd *p_FmPcd, t_Handle h_NetEnv, + t_Handle h_CcTree, t_Handle h_Manip, + uint8_t groupId) +{ + t_FmPcdManip *p_Manip = (t_FmPcdManip *)h_Manip; + t_FmPcdKgSchemeParams *p_SchemeParams = NULL; + + ASSERT_COND(p_FmPcd); + ASSERT_COND(h_NetEnv); + ASSERT_COND(p_Manip); + + /* scheme was already build, no need to check for IPv6 */ + if (p_Manip->reassmParams.capwap.h_Scheme) + return E_OK; + + p_SchemeParams = XX_Malloc(sizeof(t_FmPcdKgSchemeParams)); + if (!p_SchemeParams) + RETURN_ERROR(MAJOR, E_NO_MEMORY, + ("Memory allocation failed for scheme")); + + memset(p_SchemeParams, 0, sizeof(t_FmPcdKgSchemeParams)); + p_SchemeParams->netEnvParams.h_NetEnv = h_NetEnv; + p_SchemeParams->id.relativeSchemeId = + (uint8_t)p_Manip->reassmParams.capwap.relativeSchemeId; + p_SchemeParams->schemeCounter.update = TRUE; + p_SchemeParams->bypassFqidGeneration = TRUE; + + setCapwapReassmSchemeParams(p_FmPcd, p_SchemeParams, h_CcTree, groupId); + + p_Manip->reassmParams.capwap.h_Scheme = FM_PCD_KgSchemeSet(p_FmPcd, + p_SchemeParams); + + XX_Free(p_SchemeParams); + + return E_OK; +} + +t_Error FmPcdManipDeleteCapwapReassmSchemes(t_Handle h_Manip) +{ + t_FmPcdManip *p_Manip = (t_FmPcdManip *)h_Manip; + + ASSERT_COND(p_Manip); + + if (p_Manip->reassmParams.capwap.h_Scheme) + FM_PCD_KgSchemeDelete(p_Manip->reassmParams.capwap.h_Scheme); + + return E_OK; +} + +#if (defined(FM_CAPWAP_SUPPORT) && (DPAA_VERSION == 10)) +t_Handle FmPcdManipApplSpecificBuild(void) +{ + t_FmPcdManip *p_Manip; + + p_Manip = (t_FmPcdManip*)XX_Malloc(sizeof(t_FmPcdManip)); + if (!p_Manip) + { + REPORT_ERROR(MAJOR, E_NO_MEMORY, ("No memory")); + return NULL; + } + memset(p_Manip, 0, sizeof(t_FmPcdManip)); + + p_Manip->opcode = HMAN_OC_MV_INT_FRAME_HDR_FROM_FRM_TO_BUFFER_PREFFIX; + p_Manip->muramAllocate = FALSE; + + p_Manip->h_Ad = (t_Handle)XX_Malloc(FM_PCD_CC_AD_ENTRY_SIZE * sizeof(uint8_t)); + if (!p_Manip->h_Ad) + { + REPORT_ERROR(MAJOR, E_NO_MEMORY, ("Allocation of Manipulation action descriptor")); + XX_Free(p_Manip); + return NULL; + } + + memset(p_Manip->h_Ad, 0, FM_PCD_CC_AD_ENTRY_SIZE * sizeof(uint8_t)); + + /*treatFdStatusFieldsAsErrors = TRUE hardcoded - assumption its always come after CAAM*/ + /*Application specific = type of flowId index, move internal frame header from data to IC, + SEC errors check*/ + if (MvIntFrameHeaderFromFrameToBufferPrefix(p_Manip, TRUE)!= E_OK) + { + XX_Free(p_Manip->h_Ad); + XX_Free(p_Manip); + return NULL; + } + return p_Manip; +} + +bool FmPcdManipIsCapwapApplSpecific(t_Handle h_Manip) +{ + t_FmPcdManip *p_Manip = (t_FmPcdManip *)h_Manip; + ASSERT_COND(h_Manip); + + return (bool)((p_Manip->opcode == HMAN_OC_CAPWAP_RMV_DTLS_IF_EXIST) ? TRUE : FALSE); +} +#endif /* (defined(FM_CAPWAP_SUPPORT) && (DPAA_VERSION == 10)) */ +/*********************** End of inter-module routines ************************/ + +/****************************************/ +/* API Init unit functions */ +/****************************************/ + +t_Handle FM_PCD_ManipNodeSet(t_Handle h_FmPcd, + t_FmPcdManipParams *p_ManipParams) +{ + t_FmPcd *p_FmPcd = (t_FmPcd *)h_FmPcd; + t_FmPcdManip *p_Manip; + t_Error err; + + SANITY_CHECK_RETURN_VALUE(h_FmPcd, E_INVALID_HANDLE, NULL); + SANITY_CHECK_RETURN_VALUE(p_ManipParams, E_INVALID_HANDLE, NULL); + + p_Manip = ManipOrStatsSetNode(h_FmPcd, (t_Handle)p_ManipParams, FALSE); + if (!p_Manip) + return NULL; + + if (((p_Manip->opcode == HMAN_OC_IP_REASSEMBLY) + || (p_Manip->opcode == HMAN_OC_IP_FRAGMENTATION) + || (p_Manip->opcode == HMAN_OC) + || (p_Manip->opcode == HMAN_OC_IPSEC_MANIP) +#if (DPAA_VERSION >= 11) + || (p_Manip->opcode == HMAN_OC_CAPWAP_MANIP) + || (p_Manip->opcode == HMAN_OC_CAPWAP_FRAGMENTATION) + || (p_Manip->opcode == HMAN_OC_CAPWAP_REASSEMBLY) +#endif /* (DPAA_VERSION >= 11) */ + ) && (!FmPcdIsAdvancedOffloadSupported(p_FmPcd))) + { + REPORT_ERROR(MAJOR, E_INVALID_STATE, ("Advanced-offload must be enabled")); + XX_Free(p_Manip); + return NULL; + } + p_Manip->h_Spinlock = XX_InitSpinlock(); + if (!p_Manip->h_Spinlock) + { + REPORT_ERROR(MAJOR, E_INVALID_VALUE, ("UNSUPPORTED HEADER MANIPULATION TYPE")); + ReleaseManipHandler(p_Manip, p_FmPcd); + XX_Free(p_Manip); + return NULL; + }INIT_LIST(&p_Manip->nodesLst); + + switch (p_Manip->opcode) + { + case (HMAN_OC_IP_REASSEMBLY): + /* IpReassembly */ + err = IpReassembly(&p_ManipParams->u.reassem, p_Manip); + break; + case (HMAN_OC_IP_FRAGMENTATION): + /* IpFragmentation */ + err = IpFragmentation(&p_ManipParams->u.frag.u.ipFrag, p_Manip); + if (err) + break; + err = IPManip(p_Manip); + break; + case (HMAN_OC_IPSEC_MANIP): + err = IPSecManip(p_ManipParams, p_Manip); + break; +#if (DPAA_VERSION >= 11) + case (HMAN_OC_CAPWAP_REASSEMBLY): + /* CapwapReassembly */ + err = CapwapReassembly(&p_ManipParams->u.reassem, p_Manip); + break; + case (HMAN_OC_CAPWAP_FRAGMENTATION): + /* CapwapFragmentation */ + err = CapwapFragmentation(&p_ManipParams->u.frag.u.capwapFrag, + p_Manip); + break; + case (HMAN_OC_CAPWAP_MANIP): + err = CapwapManip(p_ManipParams, p_Manip); + break; +#endif /* (DPAA_VERSION >= 11) */ +#if (defined(FM_CAPWAP_SUPPORT) && (DPAA_VERSION == 10)) + case (HMAN_OC_RMV_N_OR_INSRT_INT_FRM_HDR): + /* HmanType1 */ + err = RmvHdrTillSpecLocNOrInsrtIntFrmHdr(&p_ManipParams->u.hdr.rmvParams, p_Manip); + break; + case (HMAN_OC_CAPWAP_FRAGMENTATION): + err = CapwapFragmentation(&p_ManipParams->fragOrReasmParams.u.capwapFragParams, + p_Manip, + p_FmPcd, + p_ManipParams->fragOrReasmParams.sgBpid); + if (err) + { + REPORT_ERROR(MAJOR, E_INVALID_VALUE, ("UNSUPPORTED HEADER MANIPULATION TYPE")); + ReleaseManipHandler(p_Manip, p_FmPcd); + XX_Free(p_Manip); + return NULL; + } + if (p_Manip->insrt) + p_Manip->opcode = HMAN_OC_INSRT_HDR_BY_TEMPL_N_OR_FRAG_AFTER; + case (HMAN_OC_INSRT_HDR_BY_TEMPL_N_OR_FRAG_AFTER): + /* HmanType2 + if user asked only for fragmentation still need to allocate HmanType2 */ + err = InsrtHdrByTempl(&p_ManipParams->u.hdr.insrtParams, p_Manip, p_FmPcd); + break; + case (HMAN_OC_CAPWAP_REASSEMBLY): + err = CapwapReassembly(&p_ManipParams->fragOrReasmParams.u.capwapReasmParams, + p_Manip, + p_FmPcd, + p_ManipParams->fragOrReasmParams.sgBpid); + if (err) + { + REPORT_ERROR(MAJOR, E_INVALID_VALUE, ("UNSUPPORTED HEADER MANIPULATION TYPE")); + ReleaseManipHandler(p_Manip, p_FmPcd); + XX_Free(p_Manip); + return NULL; + } + if (p_Manip->rmv) + p_Manip->opcode = HMAN_OC_CAPWAP_RMV_DTLS_IF_EXIST; + case (HMAN_OC_CAPWAP_RMV_DTLS_IF_EXIST): + /*CAPWAP decapsulation + if user asked only for reassembly still need to allocate CAPWAP decapsulation*/ + err = CapwapRmvDtlsHdr(p_FmPcd, p_Manip); + break; + case (HMAN_OC_MV_INT_FRAME_HDR_FROM_FRM_TO_BUFFER_PREFFIX): + /*Application Specific type 1*/ + err = MvIntFrameHeaderFromFrameToBufferPrefix(p_Manip, TRUE); + break; +#endif /* (defined(FM_CAPWAP_SUPPORT) && (DPAA_VERSION == 10)) */ + case (HMAN_OC): + /* New Manip */ + err = CreateManipActionNew(p_Manip, p_ManipParams); + break; + default: + REPORT_ERROR(MAJOR, E_INVALID_VALUE, ("UNSUPPORTED HEADER MANIPULATION TYPE")); + ReleaseManipHandler(p_Manip, p_FmPcd); + XX_Free(p_Manip); + return NULL; + } + + if (err) + { + REPORT_ERROR(MAJOR, err, NO_MSG); + ReleaseManipHandler(p_Manip, p_FmPcd); + XX_Free(p_Manip); + return NULL; + } + + if (p_ManipParams->h_NextManip) + { + /* in the check routine we've verified that h_NextManip has no owners + * and that only supported types are allowed. */ + p_Manip->h_NextManip = p_ManipParams->h_NextManip; + /* save a "prev" pointer in h_NextManip */ + MANIP_SET_PREV(p_Manip->h_NextManip, p_Manip); + FmPcdManipUpdateOwner(p_Manip->h_NextManip, TRUE); + } + + return p_Manip; +} + +t_Error FM_PCD_ManipNodeReplace(t_Handle h_Manip, + t_FmPcdManipParams *p_ManipParams) +{ + t_FmPcdManip *p_Manip = (t_FmPcdManip *)h_Manip, *p_FirstManip; + t_FmPcd *p_FmPcd = (t_FmPcd *)(p_Manip->h_FmPcd); + t_Error err; + uint8_t *p_WholeHmct = NULL, *p_ShadowHmct = NULL, *p_Hmtd = NULL; + t_List lstOfNodeshichPointsOnCrntMdfManip, *p_Pos; + t_CcNodeInformation *p_CcNodeInfo; + SANITY_CHECK_RETURN_ERROR(h_Manip, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_ManipParams, E_INVALID_HANDLE); + + INIT_LIST(&lstOfNodeshichPointsOnCrntMdfManip); + + if ((p_ManipParams->type != e_FM_PCD_MANIP_HDR) + || (p_Manip->type != e_FM_PCD_MANIP_HDR)) + RETURN_ERROR( + MINOR, + E_NOT_SUPPORTED, + ("FM_PCD_ManipNodeReplace Functionality supported only for Header Manipulation.")); + + ASSERT_COND(p_Manip->opcode == HMAN_OC); + ASSERT_COND(p_Manip->manipParams.h_NextManip == p_Manip->h_NextManip); + memcpy((uint8_t*)&p_Manip->manipParams, p_ManipParams, + sizeof(p_Manip->manipParams)); + p_Manip->manipParams.h_NextManip = p_Manip->h_NextManip; + + /* The replacement of the HdrManip depends on the node type.*/ + /* + * (1) If this is an independent node, all its owners should be updated. + * + * (2) If it is the head of a cascaded chain (it does not have a "prev" but + * it has a "next" and it has a "cascaded" indication), the next + * node remains unchanged, and the behavior is as in (1). + * + * (3) If it is not the head, but a part of a cascaded chain, in can be + * also replaced as a regular node with just one owner. + * + * (4) If it is a part of a chain implemented as a unified table, the + * whole table is replaced and the owners of the head node must be updated. + * + */ + /* lock shadow */ + if (!p_FmPcd->p_CcShadow) + RETURN_ERROR(MAJOR, E_NO_MEMORY, ("CC Shadow not allocated")); + + if (!TRY_LOCK(p_FmPcd->h_ShadowSpinlock, &p_FmPcd->shadowLock)) + return ERROR_CODE(E_BUSY); + + /* this routine creates a new manip action in the CC Shadow. */ + err = CreateManipActionShadow(p_Manip, p_ManipParams); + if (err) + RETURN_ERROR(MINOR, err, NO_MSG); + + /* If the owners list is empty (these are NOT the "owners" counter, but pointers from CC) + * replace only HMTD and no lcok is required. Otherwise + * lock the whole PCD + * In case 4 MANIP_IS_UNIFIED_NON_FIRST(p_Manip) - Use the head node instead. */ + if (!FmPcdLockTryLockAll(p_FmPcd)) + { + DBG(TRACE, ("FmPcdLockTryLockAll failed")); + return ERROR_CODE(E_BUSY); + } + + p_ShadowHmct = (uint8_t*)PTR_MOVE(p_FmPcd->p_CcShadow, 16); + + p_FirstManip = (t_FmPcdManip*)GetManipInfo(p_Manip, + e_MANIP_HANDLER_TABLE_OWNER); + ASSERT_COND(p_FirstManip); + + if (!LIST_IsEmpty(&p_FirstManip->nodesLst)) + UpdateAdPtrOfNodesWhichPointsOnCrntMdfManip( + p_FirstManip, &lstOfNodeshichPointsOnCrntMdfManip); + + p_Hmtd = (uint8_t *)GetManipInfo(p_Manip, e_MANIP_HMTD); + ASSERT_COND(p_Hmtd); + BuildHmtd(p_FmPcd->p_CcShadow, (uint8_t *)p_Hmtd, p_ShadowHmct, + ((t_FmPcd*)(p_Manip->h_FmPcd))); + + LIST_FOR_EACH(p_Pos, &lstOfNodeshichPointsOnCrntMdfManip) + { + p_CcNodeInfo = CC_NODE_F_OBJECT(p_Pos); + BuildHmtd(p_FmPcd->p_CcShadow, (uint8_t *)p_CcNodeInfo->h_CcNode, + p_ShadowHmct, ((t_FmPcd*)(p_Manip->h_FmPcd))); + } + + p_WholeHmct = (uint8_t *)GetManipInfo(p_Manip, e_MANIP_HMCT); + ASSERT_COND(p_WholeHmct); + + /* re-build the HMCT n the original location */ + err = CreateManipActionBackToOrig(p_Manip, p_ManipParams); + if (err) + { + RELEASE_LOCK(p_FmPcd->shadowLock); + RETURN_ERROR(MINOR, err, NO_MSG); + } + + p_Hmtd = (uint8_t *)GetManipInfo(p_Manip, e_MANIP_HMTD); + ASSERT_COND(p_Hmtd); + BuildHmtd(p_FmPcd->p_CcShadow, (uint8_t *)p_Hmtd, p_WholeHmct, + ((t_FmPcd*)p_Manip->h_FmPcd)); + + /* If LIST > 0, create a list of p_Ad's that point to the HMCT. Join also t_HMTD to this list. + * For each p_Hmct (from list+fixed): + * call Host Command to replace HMTD by a new one */LIST_FOR_EACH(p_Pos, &lstOfNodeshichPointsOnCrntMdfManip) + { + p_CcNodeInfo = CC_NODE_F_OBJECT(p_Pos); + BuildHmtd(p_FmPcd->p_CcShadow, (uint8_t *)p_CcNodeInfo->h_CcNode, + p_WholeHmct, ((t_FmPcd*)(p_Manip->h_FmPcd))); + } + + + ReleaseLst(&lstOfNodeshichPointsOnCrntMdfManip); + + FmPcdLockUnlockAll(p_FmPcd); + + /* unlock shadow */ + RELEASE_LOCK(p_FmPcd->shadowLock); + + return E_OK; +} + +t_Error FM_PCD_ManipNodeDelete(t_Handle h_ManipNode) +{ + t_FmPcdManip *p_Manip = (t_FmPcdManip *)h_ManipNode; + + SANITY_CHECK_RETURN_ERROR(p_Manip, E_INVALID_HANDLE); + + if (p_Manip->owner) + RETURN_ERROR( + MAJOR, + E_INVALID_STATE, + ("This manipulation node not be removed because this node is occupied, first - unbind this node ")); + + if (p_Manip->h_NextManip) + { + MANIP_SET_PREV(p_Manip->h_NextManip, NULL); + FmPcdManipUpdateOwner(p_Manip->h_NextManip, FALSE); + } + + if (p_Manip->p_Hmct + && (MANIP_IS_UNIFIED_FIRST(p_Manip) || !MANIP_IS_UNIFIED(p_Manip))) + FM_MURAM_FreeMem(((t_FmPcd *)p_Manip->h_FmPcd)->h_FmMuram, + p_Manip->p_Hmct); + + if (p_Manip->h_Spinlock) + { + XX_FreeSpinlock(p_Manip->h_Spinlock); + p_Manip->h_Spinlock = NULL; + } + + ReleaseManipHandler(p_Manip, p_Manip->h_FmPcd); + + XX_Free(h_ManipNode); + + return E_OK; +} + +t_Error FM_PCD_ManipGetStatistics(t_Handle h_ManipNode, + t_FmPcdManipStats *p_FmPcdManipStats) +{ + t_FmPcdManip *p_Manip = (t_FmPcdManip *)h_ManipNode; + + SANITY_CHECK_RETURN_ERROR(p_Manip, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_FmPcdManipStats, E_NULL_POINTER); + + switch (p_Manip->opcode) + { + case (HMAN_OC_IP_REASSEMBLY): + return IpReassemblyStats(p_Manip, + &p_FmPcdManipStats->u.reassem.u.ipReassem); + case (HMAN_OC_IP_FRAGMENTATION): + return IpFragmentationStats(p_Manip, + &p_FmPcdManipStats->u.frag.u.ipFrag); +#if (DPAA_VERSION >= 11) + case (HMAN_OC_CAPWAP_REASSEMBLY): + return CapwapReassemblyStats( + p_Manip, &p_FmPcdManipStats->u.reassem.u.capwapReassem); + case (HMAN_OC_CAPWAP_FRAGMENTATION): + return CapwapFragmentationStats( + p_Manip, &p_FmPcdManipStats->u.frag.u.capwapFrag); +#endif /* (DPAA_VERSION >= 11) */ + default: + RETURN_ERROR(MAJOR, E_NOT_SUPPORTED, + ("no statistics to this type of manip")); + } + + return E_OK; +} + +#if (defined(FM_CAPWAP_SUPPORT) && (DPAA_VERSION == 10)) +t_Handle FM_PCD_StatisticsSetNode(t_Handle h_FmPcd, t_FmPcdStatsParams *p_StatsParams) +{ + t_FmPcd *p_FmPcd = (t_FmPcd *)h_FmPcd; + t_FmPcdManip *p_Manip; + t_Error err; + + SANITY_CHECK_RETURN_VALUE(h_FmPcd,E_INVALID_HANDLE,NULL); + SANITY_CHECK_RETURN_VALUE(p_StatsParams,E_INVALID_HANDLE,NULL); + + p_Manip = ManipOrStatsSetNode(h_FmPcd, (t_Handle)p_StatsParams, TRUE); + if (!p_Manip) + return NULL; + + switch (p_Manip->opcode) + { + case (HMAN_OC_CAPWAP_INDEXED_STATS): + /* Indexed statistics */ + err = IndxStats(p_StatsParams, p_Manip, p_FmPcd); + break; + default: + REPORT_ERROR(MAJOR, E_INVALID_VALUE, ("UNSUPPORTED Statistics type")); + ReleaseManipHandler(p_Manip, p_FmPcd); + XX_Free(p_Manip); + return NULL; + } + + if (err) + { + REPORT_ERROR(MAJOR, err, NO_MSG); + ReleaseManipHandler(p_Manip, p_FmPcd); + XX_Free(p_Manip); + return NULL; + } + + return p_Manip; +} +#endif /* (defined(FM_CAPWAP_SUPPORT) && (DPAA_VERSION == 10)) */ diff --git a/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Pcd/fm_manip.h b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Pcd/fm_manip.h new file mode 100644 index 000000000000..853bb834dedf --- /dev/null +++ b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Pcd/fm_manip.h @@ -0,0 +1,555 @@ +/* + * Copyright 2008-2012 Freescale Semiconductor Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Freescale Semiconductor nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * + * ALTERNATIVELY, this software may be distributed under the terms of the + * GNU General Public License ("GPL") as published by the Free Software + * Foundation, either version 2 of that License or (at your option) any + * later version. + * + * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + +/****************************************************************************** + @File fm_manip.h + + @Description FM PCD manip... +*//***************************************************************************/ +#ifndef __FM_MANIP_H +#define __FM_MANIP_H + +#include "std_ext.h" +#include "error_ext.h" +#include "list_ext.h" + +#include "fm_cc.h" + + +/***********************************************************************/ +/* Header manipulations defines */ +/***********************************************************************/ + +#define NUM_OF_SCRATCH_POOL_BUFFERS 1000 /*TODO - Change it!!*/ + +#if (defined(FM_CAPWAP_SUPPORT) && (DPAA_VERSION == 10)) +#define HMAN_OC_RMV_N_OR_INSRT_INT_FRM_HDR 0x2e +#define HMAN_OC_INSRT_HDR_BY_TEMPL_N_OR_FRAG_AFTER 0x31 +#define HMAN_OC_MV_INT_FRAME_HDR_FROM_FRM_TO_BUFFER_PREFFIX 0x2f +#define HMAN_OC_CAPWAP_RMV_DTLS_IF_EXIST 0x30 +#define HMAN_OC_CAPWAP_REASSEMBLY 0x11 /* dummy */ +#define HMAN_OC_CAPWAP_INDEXED_STATS 0x32 /* dummy */ +#define HMAN_OC_CAPWAP_FRAGMENTATION 0x33 +#else +#define HMAN_OC_CAPWAP_MANIP 0x2F +#define HMAN_OC_CAPWAP_FRAG_CHECK 0x2E +#define HMAN_OC_CAPWAP_FRAGMENTATION 0x33 +#define HMAN_OC_CAPWAP_REASSEMBLY 0x30 +#endif /* (defined(FM_CAPWAP_SUPPORT) && (DPAA_VERSION == 10)) */ +#define HMAN_OC_IP_MANIP 0x34 +#define HMAN_OC_IP_FRAGMENTATION 0x74 +#define HMAN_OC_IP_REASSEMBLY 0xB4 +#define HMAN_OC_IPSEC_MANIP 0xF4 +#define HMAN_OC 0x35 + +#if (defined(FM_CAPWAP_SUPPORT) && (DPAA_VERSION == 10)) +#define HMAN_RMV_HDR 0x80000000 +#define HMAN_INSRT_INT_FRM_HDR 0x40000000 + +#define UDP_CHECKSUM_FIELD_OFFSET_FROM_UDP 6 +#define UDP_CHECKSUM_FIELD_SIZE 2 +#define UDP_LENGTH_FIELD_OFFSET_FROM_UDP 4 + +#define IPv4_DSCECN_FIELD_OFFSET_FROM_IP 1 +#define IPv4_TOTALLENGTH_FIELD_OFFSET_FROM_IP 2 +#define IPv4_HDRCHECKSUM_FIELD_OFFSET_FROM_IP 10 +#define VLAN_TAG_FIELD_OFFSET_FROM_ETH 12 +#define IPv4_ID_FIELD_OFFSET_FROM_IP 4 + +#define IPv6_PAYLOAD_LENGTH_OFFSET_FROM_IP 4 +#define IPv6_NEXT_HEADER_OFFSET_FROM_IP 6 + +#define FM_PCD_MANIP_CAPWAP_REASM_TABLE_SIZE 0x80 +#define FM_PCD_MANIP_CAPWAP_REASM_TABLE_ALIGN 8 +#define FM_PCD_MANIP_CAPWAP_REASM_RFD_SIZE 32 +#define FM_PCD_MANIP_CAPWAP_REASM_AUTO_LEARNING_HASH_ENTRY_SIZE 4 +#define FM_PCD_MANIP_CAPWAP_REASM_TIME_OUT_ENTRY_SIZE 8 + + +#define FM_PCD_MANIP_CAPWAP_REASM_TIME_OUT_BETWEEN_FRAMES 0x40000000 +#define FM_PCD_MANIP_CAPWAP_REASM_HALT_ON_DUPLICATE_FRAG 0x10000000 +#define FM_PCD_MANIP_CAPWAP_REASM_AUTOMATIC_LEARNIN_HASH_8_WAYS 0x08000000 +#define FM_PCD_MANIP_CAPWAP_REASM_PR_COPY 0x00800000 + +#define FM_PCD_MANIP_CAPWAP_FRAG_COMPR_OPTION_FIELD_EN 0x80000000 + +#define FM_PCD_MANIP_INDEXED_STATS_ENTRY_SIZE 4 +#define FM_PCD_MANIP_INDEXED_STATS_CNIA 0x20000000 +#define FM_PCD_MANIP_INDEXED_STATS_DPD 0x10000000 +#endif /* (defined(FM_CAPWAP_SUPPORT) && (DPAA_VERSION == 10)) */ + +#if (DPAA_VERSION >= 11) +#define FM_PCD_MANIP_CAPWAP_DTLS 0x00040000 +#define FM_PCD_MANIP_CAPWAP_NADEN 0x20000000 + +#define FM_PCD_MANIP_CAPWAP_FRAG_CHECK_MTU_SHIFT 16 +#define FM_PCD_MANIP_CAPWAP_FRAG_CHECK_NO_FRAGMENTATION 0xFFFF0000 +#define FM_PCD_MANIP_CAPWAP_FRAG_CHECK_CNIA 0x20000000 + +#define FM_PCD_MANIP_CAPWAP_FRAG_COMPRESS_EN 0x04000000 +#define FM_PCD_MANIP_CAPWAP_FRAG_SCRATCH_BPID 24 +#define FM_PCD_MANIP_CAPWAP_FRAG_SG_BDID_EN 0x08000000 +#define FM_PCD_MANIP_CAPWAP_FRAG_SG_BDID_MASK 0xFF000000 +#define FM_PCD_MANIP_CAPWAP_FRAG_SG_BDID_SHIFT 24 +#endif /* (DPAA_VERSION >= 11) */ + +#define FM_PCD_MANIP_REASM_TABLE_SIZE 0x40 +#define FM_PCD_MANIP_REASM_TABLE_ALIGN 8 + +#define FM_PCD_MANIP_REASM_COMMON_PARAM_TABLE_SIZE 64 +#define FM_PCD_MANIP_REASM_COMMON_PARAM_TABLE_ALIGN 8 +#define FM_PCD_MANIP_REASM_TIME_OUT_BETWEEN_FRAMES 0x80000000 +#define FM_PCD_MANIP_REASM_COUPLING_ENABLE 0x40000000 +#define FM_PCD_MANIP_REASM_COUPLING_MASK 0xFF000000 +#define FM_PCD_MANIP_REASM_COUPLING_SHIFT 24 +#define FM_PCD_MANIP_REASM_LIODN_MASK 0x0000003F +#define FM_PCD_MANIP_REASM_LIODN_SHIFT 56 +#define FM_PCD_MANIP_REASM_ELIODN_MASK 0x000003c0 +#define FM_PCD_MANIP_REASM_ELIODN_SHIFT 38 +#define FM_PCD_MANIP_REASM_COMMON_INT_BUFFER_IDX_MASK 0x000000FF +#define FM_PCD_MANIP_REASM_COMMON_INT_BUFFER_IDX_SHIFT 24 +#define FM_PCD_MANIP_REASM_TIMEOUT_THREAD_THRESH 1024 + +#define FM_PCD_MANIP_IP_MTU_SHIFT 16 +#define FM_PCD_MANIP_IP_NO_FRAGMENTATION 0xFFFF0000 +#define FM_PCD_MANIP_IP_CNIA 0x20000000 + +#define FM_PCD_MANIP_IP_FRAG_DF_SHIFT 28 +#define FM_PCD_MANIP_IP_FRAG_SCRATCH_BPID 24 +#define FM_PCD_MANIP_IP_FRAG_SG_BDID_EN 0x08000000 +#define FM_PCD_MANIP_IP_FRAG_SG_BDID_MASK 0xFF000000 +#define FM_PCD_MANIP_IP_FRAG_SG_BDID_SHIFT 24 + +#define FM_PCD_MANIP_IPSEC_DEC 0x10000000 +#define FM_PCD_MANIP_IPSEC_VIPV_EN 0x08000000 +#define FM_PCD_MANIP_IPSEC_ECN_EN 0x04000000 +#define FM_PCD_MANIP_IPSEC_DSCP_EN 0x02000000 +#define FM_PCD_MANIP_IPSEC_VIPL_EN 0x01000000 +#define FM_PCD_MANIP_IPSEC_NADEN 0x20000000 + +#define FM_PCD_MANIP_IPSEC_IP_HDR_LEN_MASK 0x00FF0000 +#define FM_PCD_MANIP_IPSEC_IP_HDR_LEN_SHIFT 16 + +#define FM_PCD_MANIP_IPSEC_ARW_SIZE_MASK 0xFFFF0000 +#define FM_PCD_MANIP_IPSEC_ARW_SIZE_SHIFT 16 + +#define e_FM_MANIP_IP_INDX 1 + +#define HMCD_OPCODE_GENERIC_RMV 0x01 +#define HMCD_OPCODE_GENERIC_INSRT 0x02 +#define HMCD_OPCODE_GENERIC_REPLACE 0x05 +#define HMCD_OPCODE_L2_RMV 0x08 +#define HMCD_OPCODE_L2_INSRT 0x09 +#define HMCD_OPCODE_VLAN_PRI_UPDATE 0x0B +#define HMCD_OPCODE_IPV4_UPDATE 0x0C +#define HMCD_OPCODE_IPV6_UPDATE 0x10 +#define HMCD_OPCODE_TCP_UDP_UPDATE 0x0E +#define HMCD_OPCODE_TCP_UDP_CHECKSUM 0x14 +#define HMCD_OPCODE_REPLACE_IP 0x12 +#define HMCD_OPCODE_RMV_TILL 0x15 +#define HMCD_OPCODE_UDP_INSRT 0x16 +#define HMCD_OPCODE_IP_INSRT 0x17 +#define HMCD_OPCODE_CAPWAP_RMV 0x18 +#define HMCD_OPCODE_CAPWAP_INSRT 0x18 +#define HMCD_OPCODE_GEN_FIELD_REPLACE 0x19 + +#define HMCD_LAST 0x00800000 + +#define HMCD_DSCP_VALUES 64 + +#define HMCD_BASIC_SIZE 4 +#define HMCD_PTR_SIZE 4 +#define HMCD_PARAM_SIZE 4 +#define HMCD_IPV4_ADDR_SIZE 4 +#define HMCD_IPV6_ADDR_SIZE 0x10 +#define HMCD_L4_HDR_SIZE 8 + +#define HMCD_CAPWAP_INSRT 0x00010000 +#define HMCD_INSRT_UDP_LITE 0x00010000 +#define HMCD_IP_ID_MASK 0x0000FFFF +#define HMCD_IP_SIZE_MASK 0x0000FF00 +#define HMCD_IP_SIZE_SHIFT 8 +#define HMCD_IP_LAST_PID_MASK 0x000000FF +#define HMCD_IP_OR_QOS 0x00010000 +#define HMCD_IP_L4_CS_CALC 0x00040000 +#define HMCD_IP_DF_MODE 0x00400000 + + +#define HMCD_OC_SHIFT 24 + +#define HMCD_RMV_OFFSET_SHIFT 0 +#define HMCD_RMV_SIZE_SHIFT 8 + +#define HMCD_INSRT_OFFSET_SHIFT 0 +#define HMCD_INSRT_SIZE_SHIFT 8 + +#define HMTD_CFG_TYPE 0x4000 +#define HMTD_CFG_EXT_HMCT 0x0080 +#define HMTD_CFG_PRS_AFTER_HM 0x0040 +#define HMTD_CFG_NEXT_AD_EN 0x0020 + +#define HMCD_RMV_L2_ETHERNET 0 +#define HMCD_RMV_L2_STACKED_QTAGS 1 +#define HMCD_RMV_L2_ETHERNET_AND_MPLS 2 +#define HMCD_RMV_L2_MPLS 3 +#define HMCD_RMV_L2_PPPOE 4 + +#define HMCD_INSRT_L2_MPLS 0 +#define HMCD_INSRT_N_UPDATE_L2_MPLS 1 +#define HMCD_INSRT_L2_PPPOE 2 +#define HMCD_INSRT_L2_SIZE_SHIFT 24 + +#define HMCD_L2_MODE_SHIFT 16 + +#define HMCD_VLAN_PRI_REP_MODE_SHIFT 16 +#define HMCD_VLAN_PRI_UPDATE 0 +#define HMCD_VLAN_PRI_UPDATE_DSCP_TO_VPRI 1 + +#define HMCD_IPV4_UPDATE_TTL 0x00000001 +#define HMCD_IPV4_UPDATE_TOS 0x00000002 +#define HMCD_IPV4_UPDATE_DST 0x00000020 +#define HMCD_IPV4_UPDATE_SRC 0x00000040 +#define HMCD_IPV4_UPDATE_ID 0x00000080 +#define HMCD_IPV4_UPDATE_TOS_SHIFT 8 + +#define HMCD_IPV6_UPDATE_HL 0x00000001 +#define HMCD_IPV6_UPDATE_TC 0x00000002 +#define HMCD_IPV6_UPDATE_DST 0x00000040 +#define HMCD_IPV6_UPDATE_SRC 0x00000080 +#define HMCD_IPV6_UPDATE_TC_SHIFT 8 + +#define HMCD_TCP_UDP_UPDATE_DST 0x00004000 +#define HMCD_TCP_UDP_UPDATE_SRC 0x00008000 +#define HMCD_TCP_UDP_UPDATE_SRC_SHIFT 16 + +#define HMCD_IP_REPLACE_REPLACE_IPV4 0x00000000 +#define HMCD_IP_REPLACE_REPLACE_IPV6 0x00010000 +#define HMCD_IP_REPLACE_TTL_HL 0x00200000 +#define HMCD_IP_REPLACE_ID 0x00400000 + +#define HMCD_IP_REPLACE_L3HDRSIZE_SHIFT 24 + +#define HMCD_GEN_FIELD_SIZE_SHIFT 16 +#define HMCD_GEN_FIELD_SRC_OFF_SHIFT 8 +#define HMCD_GEN_FIELD_DST_OFF_SHIFT 0 +#define HMCD_GEN_FIELD_MASK_EN 0x00400000 + +#define HMCD_GEN_FIELD_MASK_OFF_SHIFT 16 +#define HMCD_GEN_FIELD_MASK_SHIFT 24 + +#define DSCP_TO_VLAN_TABLE_SIZE 32 + +#define MANIP_GET_HMCT_SIZE(h_Manip) (((t_FmPcdManip *)h_Manip)->tableSize) +#define MANIP_GET_DATA_SIZE(h_Manip) (((t_FmPcdManip *)h_Manip)->dataSize) + +#define MANIP_GET_HMCT_PTR(h_Manip) (((t_FmPcdManip *)h_Manip)->p_Hmct) +#define MANIP_GET_DATA_PTR(h_Manip) (((t_FmPcdManip *)h_Manip)->p_Data) + +#define MANIP_SET_HMCT_PTR(h_Manip, h_NewPtr) (((t_FmPcdManip *)h_Manip)->p_Hmct = h_NewPtr) +#define MANIP_SET_DATA_PTR(h_Manip, h_NewPtr) (((t_FmPcdManip *)h_Manip)->p_Data = h_NewPtr) + +#define MANIP_GET_HMTD_PTR(h_Manip) (((t_FmPcdManip *)h_Manip)->h_Ad) +#define MANIP_DONT_REPARSE(h_Manip) (((t_FmPcdManip *)h_Manip)->dontParseAfterManip) +#define MANIP_SET_PREV(h_Manip, h_Prev) (((t_FmPcdManip *)h_Manip)->h_PrevManip = h_Prev) +#define MANIP_GET_OWNERS(h_Manip) (((t_FmPcdManip *)h_Manip)->owner) +#define MANIP_GET_TYPE(h_Manip) (((t_FmPcdManip *)h_Manip)->type) +#define MANIP_SET_UNIFIED_TBL_PTR_INDICATION(h_Manip) (((t_FmPcdManip *)h_Manip)->unifiedTablePtr = TRUE) +#define MANIP_GET_MURAM(h_Manip) (((t_FmPcd *)((t_FmPcdManip *)h_Manip)->h_FmPcd)->h_FmMuram) +#define MANIP_FREE_HMTD(h_Manip) \ + {if (((t_FmPcdManip *)h_Manip)->muramAllocate) \ + FM_MURAM_FreeMem(((t_FmPcd *)((t_FmPcdManip *)h_Manip)->h_FmPcd)->h_FmMuram, ((t_FmPcdManip *)h_Manip)->h_Ad);\ + else \ + XX_Free(((t_FmPcdManip *)h_Manip)->h_Ad); \ + ((t_FmPcdManip *)h_Manip)->h_Ad = NULL; \ + } +/* position regarding Manip SW structure */ +#define MANIP_IS_FIRST(h_Manip) (!(((t_FmPcdManip *)h_Manip)->h_PrevManip)) +#define MANIP_IS_CASCADED(h_Manip) (((t_FmPcdManip *)h_Manip)->cascaded) +#define MANIP_IS_UNIFIED(h_Manip) (!(((t_FmPcdManip *)h_Manip)->unifiedPosition == e_MANIP_UNIFIED_NONE)) +#define MANIP_IS_UNIFIED_NON_FIRST(h_Manip) ((((t_FmPcdManip *)h_Manip)->unifiedPosition == e_MANIP_UNIFIED_MID) || \ + (((t_FmPcdManip *)h_Manip)->unifiedPosition == e_MANIP_UNIFIED_LAST)) +#define MANIP_IS_UNIFIED_NON_LAST(h_Manip) ((((t_FmPcdManip *)h_Manip)->unifiedPosition == e_MANIP_UNIFIED_FIRST) ||\ + (((t_FmPcdManip *)h_Manip)->unifiedPosition == e_MANIP_UNIFIED_MID)) +#define MANIP_IS_UNIFIED_FIRST(h_Manip) (((t_FmPcdManip *)h_Manip)->unifiedPosition == e_MANIP_UNIFIED_FIRST) +#define MANIP_IS_UNIFIED_LAST(h_Manip) (((t_FmPcdManip *)h_Manip)->unifiedPosition == e_MANIP_UNIFIED_LAST) + +#define MANIP_UPDATE_UNIFIED_POSITION(h_Manip) (((t_FmPcdManip *)h_Manip)->unifiedPosition = \ + (((t_FmPcdManip *)h_Manip)->unifiedPosition == e_MANIP_UNIFIED_NONE)? \ + e_MANIP_UNIFIED_LAST : e_MANIP_UNIFIED_MID) + +typedef enum e_ManipUnifiedPosition { + e_MANIP_UNIFIED_NONE = 0, + e_MANIP_UNIFIED_FIRST, + e_MANIP_UNIFIED_MID, + e_MANIP_UNIFIED_LAST +} e_ManipUnifiedPosition; + +typedef enum e_ManipInfo { + e_MANIP_HMTD, + e_MANIP_HMCT, + e_MANIP_HANDLER_TABLE_OWNER +}e_ManipInfo; +/***********************************************************************/ +/* Memory map */ +/***********************************************************************/ +#if defined(__MWERKS__) && !defined(__GNUC__) +#pragma pack(push,1) +#endif /* defined(__MWERKS__) && ... */ + +#if (defined(FM_CAPWAP_SUPPORT) && (DPAA_VERSION == 10)) +typedef struct t_CapwapReasmPram { + volatile uint32_t mode; + volatile uint32_t autoLearnHashTblPtr; + volatile uint32_t intStatsTblPtr; + volatile uint32_t reasmFrmDescPoolTblPtr; + volatile uint32_t reasmFrmDescIndexPoolTblPtr; + volatile uint32_t timeOutTblPtr; + volatile uint32_t bufferPoolIdAndRisc1SetIndexes; + volatile uint32_t risc23SetIndexes; + volatile uint32_t risc4SetIndexesAndExtendedStatsTblPtr; + volatile uint32_t extendedStatsTblPtr; + volatile uint32_t expirationDelay; + volatile uint32_t totalProcessedFragCounter; + volatile uint32_t totalUnsuccessfulReasmFramesCounter; + volatile uint32_t totalDuplicatedFragCounter; + volatile uint32_t totalMalformdFragCounter; + volatile uint32_t totalTimeOutCounter; + volatile uint32_t totalSetBusyCounter; + volatile uint32_t totalRfdPoolBusyCounter; + volatile uint32_t totalDiscardedFragsCounter; + volatile uint32_t totalMoreThan16FramesCounter; + volatile uint32_t internalBufferBusy; + volatile uint32_t externalBufferBusy; + volatile uint32_t reserved1[4]; +} t_CapwapReasmPram; +#endif /* (defined(FM_CAPWAP_SUPPORT) && (DPAA_VERSION == 10)) */ + +typedef _Packed struct t_ReassTbl { + volatile uint16_t waysNumAndSetSize; + volatile uint16_t autoLearnHashKeyMask; + volatile uint32_t reassCommonPrmTblPtr; + volatile uint32_t liodnAlAndAutoLearnHashTblPtrHi; + volatile uint32_t autoLearnHashTblPtrLow; + volatile uint32_t liodnSlAndAutoLearnSetLockTblPtrHi; + volatile uint32_t autoLearnSetLockTblPtrLow; + volatile uint16_t minFragSize; /* Not relevant for CAPWAP*/ + volatile uint16_t maxReassemblySize; /* Only relevant for CAPWAP*/ + volatile uint32_t totalSuccessfullyReasmFramesCounter; + volatile uint32_t totalValidFragmentCounter; + volatile uint32_t totalProcessedFragCounter; + volatile uint32_t totalMalformdFragCounter; + volatile uint32_t totalSetBusyCounter; + volatile uint32_t totalDiscardedFragsCounter; + volatile uint32_t totalMoreThan16FramesCounter; + volatile uint32_t reserved2[2]; +} _PackedType t_ReassTbl; + +typedef struct t_ReassCommonTbl { + volatile uint32_t timeoutModeAndFqid; + volatile uint32_t reassFrmDescIndexPoolTblPtr; + volatile uint32_t liodnAndReassFrmDescPoolPtrHi; + volatile uint32_t reassFrmDescPoolPtrLow; + volatile uint32_t timeOutTblPtr; + volatile uint32_t expirationDelay; + volatile uint32_t internalBufferManagement; + volatile uint32_t reserved2; + volatile uint32_t totalTimeOutCounter; + volatile uint32_t totalRfdPoolBusyCounter; + volatile uint32_t totalInternalBufferBusy; + volatile uint32_t totalExternalBufferBusy; + volatile uint32_t totalSgFragmentCounter; + volatile uint32_t totalDmaSemaphoreDepletionCounter; + volatile uint32_t totalNCSPCounter; + volatile uint32_t discardMask; +} t_ReassCommonTbl; + +typedef _Packed struct t_Hmtd { + volatile uint16_t cfg; + volatile uint8_t eliodnOffset; + volatile uint8_t extHmcdBasePtrHi; + volatile uint32_t hmcdBasePtr; + volatile uint16_t nextAdIdx; + volatile uint8_t res1; + volatile uint8_t opCode; + volatile uint32_t res2; +} _PackedType t_Hmtd; + +#if defined(__MWERKS__) && !defined(__GNUC__) +#pragma pack(pop) +#endif /* defined(__MWERKS__) && ... */ + + +/***********************************************************************/ +/* Driver's internal structures */ +/***********************************************************************/ +#if (defined(FM_CAPWAP_SUPPORT) && (DPAA_VERSION == 10)) +typedef struct +{ + t_Handle p_AutoLearnHashTbl; + t_Handle p_ReassmFrmDescrPoolTbl; + t_Handle p_ReassmFrmDescrIndxPoolTbl; + t_Handle p_TimeOutTbl; + uint16_t maxNumFramesInProcess; + uint8_t numOfTasks; + //uint8_t poolId; + uint8_t prOffset; + uint16_t dataOffset; + uint8_t sgBpid; + uint8_t hwPortId; + uint32_t fqidForTimeOutFrames; + uint32_t timeoutRoutineRequestTime; + uint32_t bitFor1Micro; +} t_CapwapFragParams; +#endif /* (defined(FM_CAPWAP_SUPPORT) && (DPAA_VERSION == 10)) */ + +typedef struct +{ + t_AdOfTypeContLookup *p_Frag; +#if (DPAA_VERSION == 10) + uint8_t scratchBpid; +#endif /* (DPAA_VERSION == 10) */ +} t_FragParams; + +typedef struct t_ReassmParams +{ + e_NetHeaderType hdr; /* Header selection */ + t_ReassCommonTbl *p_ReassCommonTbl; + uintptr_t reassFrmDescrIndxPoolTblAddr; + uintptr_t reassFrmDescrPoolTblAddr; + uintptr_t timeOutTblAddr; + uintptr_t internalBufferPoolManagementIndexAddr; + uintptr_t internalBufferPoolAddr; + uint32_t maxNumFramesInProcess; + uint8_t sgBpid; + uint8_t dataMemId; + uint16_t dataLiodnOffset; + uint32_t fqidForTimeOutFrames; + e_FmPcdManipReassemTimeOutMode timeOutMode; + uint32_t timeoutThresholdForReassmProcess; + union { + struct { + t_Handle h_Ipv4Ad; + t_Handle h_Ipv6Ad; + bool ipv6Assigned; + t_ReassTbl *p_Ipv4ReassTbl; + t_ReassTbl *p_Ipv6ReassTbl; + uintptr_t ipv4AutoLearnHashTblAddr; + uintptr_t ipv6AutoLearnHashTblAddr; + uintptr_t ipv4AutoLearnSetLockTblAddr; + uintptr_t ipv6AutoLearnSetLockTblAddr; + uint16_t minFragSize[2]; + e_FmPcdManipReassemWaysNumber numOfFramesPerHashEntry[2]; + uint8_t relativeSchemeId[2]; + t_Handle h_Ipv4Scheme; + t_Handle h_Ipv6Scheme; + uint32_t nonConsistentSpFqid; + } ip; + struct { + t_Handle h_Ad; + t_ReassTbl *p_ReassTbl; + uintptr_t autoLearnHashTblAddr; + uintptr_t autoLearnSetLockTblAddr; + uint16_t maxRessembledsSize; + e_FmPcdManipReassemWaysNumber numOfFramesPerHashEntry; + uint8_t relativeSchemeId; + t_Handle h_Scheme; + } capwap; + }; +} t_ReassmParams; + +typedef struct{ + e_FmPcdManipType type; + t_FmPcdManipParams manipParams; + bool muramAllocate; + t_Handle h_Ad; + uint32_t opcode; + bool rmv; + bool insrt; + t_Handle h_NextManip; + t_Handle h_PrevManip; + e_FmPcdManipType nextManipType; + /* HdrManip parameters*/ + uint8_t *p_Hmct; + uint8_t *p_Data; + bool dontParseAfterManip; + bool fieldUpdate; + bool custom; + uint16_t tableSize; + uint8_t dataSize; + bool cascaded; + e_ManipUnifiedPosition unifiedPosition; + /* end HdrManip */ + uint8_t *p_Template; + uint16_t owner; + uint32_t updateParams; + uint32_t shadowUpdateParams; + bool frag; + bool reassm; + uint16_t sizeForFragmentation; +#if (defined(FM_CAPWAP_SUPPORT) && (DPAA_VERSION == 10)) + t_Handle h_Frag; + t_CapwapFragParams capwapFragParams; +#endif /* (defined(FM_CAPWAP_SUPPORT) && (DPAA_VERSION == 10)) */ + union { + t_ReassmParams reassmParams; + t_FragParams fragParams; + }; + uint8_t icOffset; + uint16_t ownerTmp; + bool cnia; + t_Handle p_StatsTbl; + t_Handle h_FmPcd; + t_List nodesLst; + t_Handle h_Spinlock; +} t_FmPcdManip; + +typedef struct t_FmPcdCcSavedManipParams +{ + union + { + struct + { + uint16_t dataOffset; + //uint8_t poolId; + }capwapParams; + struct + { + uint16_t dataOffset; + uint8_t poolId; + }ipParams; + }; + +} t_FmPcdCcSavedManipParams; + + +#endif /* __FM_MANIP_H */ diff --git a/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Pcd/fm_pcd.c b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Pcd/fm_pcd.c new file mode 100644 index 000000000000..91f70a1a290e --- /dev/null +++ b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Pcd/fm_pcd.c @@ -0,0 +1,2095 @@ +/* + * Copyright 2008-2012 Freescale Semiconductor Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Freescale Semiconductor nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * + * ALTERNATIVELY, this software may be distributed under the terms of the + * GNU General Public License ("GPL") as published by the Free Software + * Foundation, either version 2 of that License or (at your option) any + * later version. + * + * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + +/****************************************************************************** + @File fm_pcd.c + + @Description FM PCD ... +*//***************************************************************************/ +#include "std_ext.h" +#include "error_ext.h" +#include "string_ext.h" +#include "xx_ext.h" +#include "sprint_ext.h" +#include "debug_ext.h" +#include "net_ext.h" +#include "fm_ext.h" +#include "fm_pcd_ext.h" + +#include "fm_common.h" +#include "fm_pcd.h" +#include "fm_pcd_ipc.h" +#include "fm_hc.h" +#include "fm_muram_ext.h" + + +/****************************************/ +/* static functions */ +/****************************************/ + +static t_Error CheckFmPcdParameters(t_FmPcd *p_FmPcd) +{ + if (!p_FmPcd->h_Fm) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("h_Fm has to be initialized")); + + if (p_FmPcd->guestId == NCSW_MASTER_ID) + { + if (p_FmPcd->p_FmPcdKg && !p_FmPcd->p_FmPcdKg->p_FmPcdKgRegs) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("Something WRONG")); + + if (p_FmPcd->p_FmPcdPlcr && !p_FmPcd->p_FmPcdPlcr->p_FmPcdPlcrRegs) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("Something WRONG")); + + if (!p_FmPcd->f_Exception) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("f_FmPcdExceptions has to be initialized")); + + if ((!p_FmPcd->f_FmPcdIndexedException) && (p_FmPcd->p_FmPcdPlcr || p_FmPcd->p_FmPcdKg)) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("f_FmPcdIndexedException has to be initialized")); + + if (p_FmPcd->p_FmPcdDriverParam->prsMaxParseCycleLimit > PRS_MAX_CYCLE_LIMIT) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("prsMaxParseCycleLimit has to be less than 8191")); + } + + return E_OK; +} + +static volatile bool blockingFlag = FALSE; +static void IpcMsgCompletionCB(t_Handle h_FmPcd, + uint8_t *p_Msg, + uint8_t *p_Reply, + uint32_t replyLength, + t_Error status) +{ + UNUSED(h_FmPcd);UNUSED(p_Msg);UNUSED(p_Reply);UNUSED(replyLength);UNUSED(status); + blockingFlag = FALSE; +} + +static t_Error IpcMsgHandlerCB(t_Handle h_FmPcd, + uint8_t *p_Msg, + uint32_t msgLength, + uint8_t *p_Reply, + uint32_t *p_ReplyLength) +{ + t_FmPcd *p_FmPcd = (t_FmPcd*)h_FmPcd; + t_Error err = E_OK; + t_FmPcdIpcMsg *p_IpcMsg = (t_FmPcdIpcMsg*)p_Msg; + t_FmPcdIpcReply *p_IpcReply = (t_FmPcdIpcReply*)p_Reply; + + SANITY_CHECK_RETURN_ERROR(p_FmPcd, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR((msgLength >= sizeof(uint32_t)), E_INVALID_VALUE); + +#ifdef DISABLE_SANITY_CHECKS + UNUSED(msgLength); +#endif /* DISABLE_SANITY_CHECKS */ + + ASSERT_COND(p_Msg); + + memset(p_IpcReply, 0, (sizeof(uint8_t) * FM_PCD_MAX_REPLY_SIZE)); + *p_ReplyLength = 0; + + switch (p_IpcMsg->msgId) + { + case (FM_PCD_MASTER_IS_ALIVE): + *(uint8_t*)(p_IpcReply->replyBody) = 1; + p_IpcReply->error = E_OK; + *p_ReplyLength = sizeof(uint32_t) + sizeof(uint8_t); + break; + case (FM_PCD_MASTER_IS_ENABLED): + /* count partitions registrations */ + if (p_FmPcd->enabled) + p_FmPcd->numOfEnabledGuestPartitionsPcds++; + *(uint8_t*)(p_IpcReply->replyBody) = (uint8_t)p_FmPcd->enabled; + p_IpcReply->error = E_OK; + *p_ReplyLength = sizeof(uint32_t) + sizeof(uint8_t); + break; + case (FM_PCD_GUEST_DISABLE): + if (p_FmPcd->numOfEnabledGuestPartitionsPcds) + { + p_FmPcd->numOfEnabledGuestPartitionsPcds--; + p_IpcReply->error = E_OK; + } + else + { + REPORT_ERROR(MINOR, E_INVALID_STATE,("Trying to disable an unregistered partition")); + p_IpcReply->error = E_INVALID_STATE; + } + *p_ReplyLength = sizeof(uint32_t); + break; + case (FM_PCD_GET_COUNTER): + { + e_FmPcdCounters inCounter; + uint32_t outCounter; + + memcpy((uint8_t*)&inCounter, p_IpcMsg->msgBody, sizeof(uint32_t)); + outCounter = FM_PCD_GetCounter(h_FmPcd, inCounter); + memcpy(p_IpcReply->replyBody, (uint8_t*)&outCounter, sizeof(uint32_t)); + p_IpcReply->error = E_OK; + *p_ReplyLength = sizeof(uint32_t) + sizeof(uint32_t); + break; + } + case (FM_PCD_ALLOC_KG_SCHEMES): + { + t_FmPcdIpcKgSchemesParams ipcSchemesParams; + + memcpy((uint8_t*)&ipcSchemesParams, p_IpcMsg->msgBody, sizeof(t_FmPcdIpcKgSchemesParams)); + err = FmPcdKgAllocSchemes(h_FmPcd, + ipcSchemesParams.numOfSchemes, + ipcSchemesParams.guestId, + p_IpcReply->replyBody); + p_IpcReply->error = err; + *p_ReplyLength = sizeof(uint32_t) + ipcSchemesParams.numOfSchemes*sizeof(uint8_t); + break; + } + case (FM_PCD_FREE_KG_SCHEMES): + { + t_FmPcdIpcKgSchemesParams ipcSchemesParams; + + memcpy((uint8_t*)&ipcSchemesParams, p_IpcMsg->msgBody, sizeof(t_FmPcdIpcKgSchemesParams)); + err = FmPcdKgFreeSchemes(h_FmPcd, + ipcSchemesParams.numOfSchemes, + ipcSchemesParams.guestId, + ipcSchemesParams.schemesIds); + p_IpcReply->error = err; + *p_ReplyLength = sizeof(uint32_t); + break; + } + case (FM_PCD_ALLOC_KG_CLSPLAN): + { + t_FmPcdIpcKgClsPlanParams ipcKgClsPlanParams; + + memcpy((uint8_t*)&ipcKgClsPlanParams, p_IpcMsg->msgBody, sizeof(t_FmPcdIpcKgClsPlanParams)); + err = KgAllocClsPlanEntries(h_FmPcd, + ipcKgClsPlanParams.numOfClsPlanEntries, + ipcKgClsPlanParams.guestId, + p_IpcReply->replyBody); + p_IpcReply->error = err; + *p_ReplyLength = sizeof(uint32_t) + sizeof(uint8_t); + break; + } + case (FM_PCD_FREE_KG_CLSPLAN): + { + t_FmPcdIpcKgClsPlanParams ipcKgClsPlanParams; + + memcpy((uint8_t*)&ipcKgClsPlanParams, p_IpcMsg->msgBody, sizeof(t_FmPcdIpcKgClsPlanParams)); + KgFreeClsPlanEntries(h_FmPcd, + ipcKgClsPlanParams.numOfClsPlanEntries, + ipcKgClsPlanParams.guestId, + ipcKgClsPlanParams.clsPlanBase); + *p_ReplyLength = sizeof(uint32_t); + break; + } + case (FM_PCD_ALLOC_PROFILES): + { + t_FmIpcResourceAllocParams ipcAllocParams; + uint16_t base; + memcpy(&ipcAllocParams, p_IpcMsg->msgBody, sizeof(t_FmIpcResourceAllocParams)); + base = PlcrAllocProfilesForPartition(h_FmPcd, + ipcAllocParams.base, + ipcAllocParams.num, + ipcAllocParams.guestId); + memcpy(p_IpcReply->replyBody, (uint16_t*)&base, sizeof(uint16_t)); + *p_ReplyLength = sizeof(uint32_t) + sizeof(uint16_t); + break; + } + case (FM_PCD_FREE_PROFILES): + { + t_FmIpcResourceAllocParams ipcAllocParams; + memcpy(&ipcAllocParams, p_IpcMsg->msgBody, sizeof(t_FmIpcResourceAllocParams)); + PlcrFreeProfilesForPartition(h_FmPcd, + ipcAllocParams.base, + ipcAllocParams.num, + ipcAllocParams.guestId); + break; + } + case (FM_PCD_SET_PORT_PROFILES): + { + t_FmIpcResourceAllocParams ipcAllocParams; + memcpy(&ipcAllocParams, p_IpcMsg->msgBody, sizeof(t_FmIpcResourceAllocParams)); + PlcrSetPortProfiles(h_FmPcd, + ipcAllocParams.guestId, + ipcAllocParams.num, + ipcAllocParams.base); + break; + } + case (FM_PCD_CLEAR_PORT_PROFILES): + { + t_FmIpcResourceAllocParams ipcAllocParams; + memcpy(&ipcAllocParams, p_IpcMsg->msgBody, sizeof(t_FmIpcResourceAllocParams)); + PlcrClearPortProfiles(h_FmPcd, + ipcAllocParams.guestId); + break; + } + case (FM_PCD_GET_SW_PRS_OFFSET): + { + t_FmPcdIpcSwPrsLable ipcSwPrsLable; + uint32_t swPrsOffset; + + memcpy((uint8_t*)&ipcSwPrsLable, p_IpcMsg->msgBody, sizeof(t_FmPcdIpcSwPrsLable)); + swPrsOffset = + FmPcdGetSwPrsOffset(h_FmPcd, + (e_NetHeaderType)ipcSwPrsLable.enumHdr, + ipcSwPrsLable.indexPerHdr); + memcpy(p_IpcReply->replyBody, (uint8_t*)&swPrsOffset, sizeof(uint32_t)); + *p_ReplyLength = sizeof(uint32_t) + sizeof(uint32_t); + break; + } + case (FM_PCD_PRS_INC_PORT_STATS): + { + t_FmPcdIpcPrsIncludePort ipcPrsIncludePort; + + memcpy((uint8_t*)&ipcPrsIncludePort, p_IpcMsg->msgBody, sizeof(t_FmPcdIpcPrsIncludePort)); + PrsIncludePortInStatistics(h_FmPcd, + ipcPrsIncludePort.hardwarePortId, + ipcPrsIncludePort.include); + break; + } + default: + *p_ReplyLength = 0; + RETURN_ERROR(MINOR, E_INVALID_SELECTION, ("command not found!!!")); + } + return E_OK; +} + +static uint32_t NetEnvLock(t_Handle h_NetEnv) +{ + ASSERT_COND(h_NetEnv); + return XX_LockIntrSpinlock(((t_FmPcdNetEnv*)h_NetEnv)->h_Spinlock); +} + +static void NetEnvUnlock(t_Handle h_NetEnv, uint32_t intFlags) +{ + ASSERT_COND(h_NetEnv); + XX_UnlockIntrSpinlock(((t_FmPcdNetEnv*)h_NetEnv)->h_Spinlock, intFlags); +} + +static void EnqueueLockToFreeLst(t_FmPcd *p_FmPcd, t_FmPcdLock *p_Lock) +{ + uint32_t intFlags; + + intFlags = XX_LockIntrSpinlock(p_FmPcd->h_Spinlock); + LIST_AddToTail(&p_Lock->node, &p_FmPcd->freeLocksLst); + XX_UnlockIntrSpinlock(p_FmPcd->h_Spinlock, intFlags); +} + +static t_FmPcdLock * DequeueLockFromFreeLst(t_FmPcd *p_FmPcd) +{ + t_FmPcdLock *p_Lock = NULL; + uint32_t intFlags; + + intFlags = XX_LockIntrSpinlock(p_FmPcd->h_Spinlock); + if (!LIST_IsEmpty(&p_FmPcd->freeLocksLst)) + { + p_Lock = FM_PCD_LOCK_OBJ(p_FmPcd->freeLocksLst.p_Next); + LIST_DelAndInit(&p_Lock->node); + } + if (p_FmPcd->h_Spinlock) + XX_UnlockIntrSpinlock(p_FmPcd->h_Spinlock, intFlags); + + return p_Lock; +} + +static void EnqueueLockToAcquiredLst(t_FmPcd *p_FmPcd, t_FmPcdLock *p_Lock) +{ + uint32_t intFlags; + + intFlags = XX_LockIntrSpinlock(p_FmPcd->h_Spinlock); + LIST_AddToTail(&p_Lock->node, &p_FmPcd->acquiredLocksLst); + XX_UnlockIntrSpinlock(p_FmPcd->h_Spinlock, intFlags); +} + +static t_Error FillFreeLocksLst(t_FmPcd *p_FmPcd) +{ + t_FmPcdLock *p_Lock; + int i; + + for (i=0; i<10; i++) + { + p_Lock = (t_FmPcdLock *)XX_Malloc(sizeof(t_FmPcdLock)); + if (!p_Lock) + RETURN_ERROR(MINOR, E_NO_MEMORY, ("FM-PCD lock obj!")); + memset(p_Lock, 0, sizeof(t_FmPcdLock)); + INIT_LIST(&p_Lock->node); + p_Lock->h_Spinlock = XX_InitSpinlock(); + if (!p_Lock->h_Spinlock) + { + XX_Free(p_Lock); + RETURN_ERROR(MINOR, E_INVALID_STATE, ("FM-PCD spinlock obj!")); + } + EnqueueLockToFreeLst(p_FmPcd, p_Lock); + } + + return E_OK; +} + +static void ReleaseFreeLocksLst(t_FmPcd *p_FmPcd) +{ + t_FmPcdLock *p_Lock; + + p_Lock = DequeueLockFromFreeLst(p_FmPcd); + while (p_Lock) + { + XX_FreeSpinlock(p_Lock->h_Spinlock); + XX_Free(p_Lock); + p_Lock = DequeueLockFromFreeLst(p_FmPcd); + } +} + + + +/*****************************************************************************/ +/* Inter-module API routines */ +/*****************************************************************************/ + +void FmPcdSetClsPlanGrpId(t_FmPcd *p_FmPcd, uint8_t netEnvId, uint8_t clsPlanGrpId) +{ + ASSERT_COND(p_FmPcd); + p_FmPcd->netEnvs[netEnvId].clsPlanGrpId = clsPlanGrpId; +} + +t_Error PcdGetClsPlanGrpParams(t_FmPcd *p_FmPcd, t_FmPcdKgInterModuleClsPlanGrpParams *p_GrpParams) +{ + uint8_t netEnvId = p_GrpParams->netEnvId; + int i, k, j; + + ASSERT_COND(p_FmPcd); + if (p_FmPcd->netEnvs[netEnvId].clsPlanGrpId != ILLEGAL_CLS_PLAN) + { + p_GrpParams->grpExists = TRUE; + p_GrpParams->clsPlanGrpId = p_FmPcd->netEnvs[netEnvId].clsPlanGrpId; + return E_OK; + } + + for (i=0; ((i < FM_PCD_MAX_NUM_OF_DISTINCTION_UNITS) && + (p_FmPcd->netEnvs[netEnvId].units[i].hdrs[0].hdr != HEADER_TYPE_NONE)); i++) + { + for (k=0; ((k < FM_PCD_MAX_NUM_OF_INTERCHANGEABLE_HDRS) && + (p_FmPcd->netEnvs[netEnvId].units[i].hdrs[k].hdr != HEADER_TYPE_NONE)); k++) + { + /* if an option exists, add it to the opts list */ + if (p_FmPcd->netEnvs[netEnvId].units[i].hdrs[k].opt) + { + /* check if this option already exists, add if it doesn't */ + for (j = 0;j<p_GrpParams->numOfOptions;j++) + { + if (p_GrpParams->options[j] == p_FmPcd->netEnvs[netEnvId].units[i].hdrs[k].opt) + break; + } + p_GrpParams->optVectors[j] |= p_FmPcd->netEnvs[netEnvId].unitsVectors[i]; + if (j == p_GrpParams->numOfOptions) + { + p_GrpParams->options[p_GrpParams->numOfOptions] = p_FmPcd->netEnvs[netEnvId].units[i].hdrs[k].opt; + p_GrpParams->numOfOptions++; + } + } + } + } + + if (p_GrpParams->numOfOptions == 0) + { + if (p_FmPcd->p_FmPcdKg->emptyClsPlanGrpId != ILLEGAL_CLS_PLAN) + { + p_GrpParams->grpExists = TRUE; + p_GrpParams->clsPlanGrpId = p_FmPcd->p_FmPcdKg->emptyClsPlanGrpId; + } + } + + return E_OK; + +} + +t_Error PcdGetVectorForOpt(t_FmPcd *p_FmPcd, uint8_t netEnvId, protocolOpt_t opt, uint32_t *p_Vector) +{ + uint8_t j,k; + + *p_Vector = 0; + + ASSERT_COND(p_FmPcd); + for (j=0; ((j < FM_PCD_MAX_NUM_OF_DISTINCTION_UNITS) && + (p_FmPcd->netEnvs[netEnvId].units[j].hdrs[0].hdr != HEADER_TYPE_NONE)); j++) + { + for (k=0; ((k < FM_PCD_MAX_NUM_OF_INTERCHANGEABLE_HDRS) && + (p_FmPcd->netEnvs[netEnvId].units[j].hdrs[k].hdr != HEADER_TYPE_NONE)); k++) + { + if (p_FmPcd->netEnvs[netEnvId].units[j].hdrs[k].opt == opt) + *p_Vector |= p_FmPcd->netEnvs[netEnvId].unitsVectors[j]; + } + } + + if (!*p_Vector) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("Requested option was not defined for this Network Environment Characteristics module")); + else + return E_OK; +} + +t_Error PcdGetUnitsVector(t_FmPcd *p_FmPcd, t_NetEnvParams *p_Params) +{ + int i; + + ASSERT_COND(p_FmPcd); + ASSERT_COND(p_Params->netEnvId < FM_MAX_NUM_OF_PORTS); + + p_Params->vector = 0; + for (i=0; i<p_Params->numOfDistinctionUnits ;i++) + { + if (p_FmPcd->netEnvs[p_Params->netEnvId].units[p_Params->unitIds[i]].hdrs[0].hdr == HEADER_TYPE_NONE) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("Requested unit was not defined for this Network Environment Characteristics module")); + ASSERT_COND(p_FmPcd->netEnvs[p_Params->netEnvId].unitsVectors[p_Params->unitIds[i]]); + p_Params->vector |= p_FmPcd->netEnvs[p_Params->netEnvId].unitsVectors[p_Params->unitIds[i]]; + } + + return E_OK; +} + +bool PcdNetEnvIsUnitWithoutOpts(t_FmPcd *p_FmPcd, uint8_t netEnvId, uint32_t unitVector) +{ + int i=0, k; + + ASSERT_COND(p_FmPcd); + /* check whether a given unit may be used by non-clsPlan users. */ + /* first, recognize the unit by its vector */ + while (p_FmPcd->netEnvs[netEnvId].units[i].hdrs[0].hdr != HEADER_TYPE_NONE) + { + if (p_FmPcd->netEnvs[netEnvId].unitsVectors[i] == unitVector) + { + for (k=0; + ((k < FM_PCD_MAX_NUM_OF_INTERCHANGEABLE_HDRS) && + (p_FmPcd->netEnvs[netEnvId].units[i].hdrs[k].hdr != HEADER_TYPE_NONE)); + k++) + /* check that no option exists */ + if ((protocolOpt_t)p_FmPcd->netEnvs[netEnvId].units[i].hdrs[k].opt) + return FALSE; + break; + } + i++; + } + /* assert that a unit was found to mach the vector */ + ASSERT_COND(p_FmPcd->netEnvs[netEnvId].units[i].hdrs[0].hdr != HEADER_TYPE_NONE); + + return TRUE; +} +bool FmPcdNetEnvIsHdrExist(t_Handle h_FmPcd, uint8_t netEnvId, e_NetHeaderType hdr) +{ + t_FmPcd *p_FmPcd = (t_FmPcd*)h_FmPcd; + int i, k; + + ASSERT_COND(p_FmPcd); + + for (i=0; ((i < FM_PCD_MAX_NUM_OF_DISTINCTION_UNITS) && + (p_FmPcd->netEnvs[netEnvId].units[i].hdrs[0].hdr != HEADER_TYPE_NONE)); i++) + { + for (k=0; ((k < FM_PCD_MAX_NUM_OF_INTERCHANGEABLE_HDRS) && + (p_FmPcd->netEnvs[netEnvId].units[i].hdrs[k].hdr != HEADER_TYPE_NONE)); k++) + if (p_FmPcd->netEnvs[netEnvId].units[i].hdrs[k].hdr == hdr) + return TRUE; + } + for (i=0; ((i < FM_PCD_MAX_NUM_OF_ALIAS_HDRS) && + (p_FmPcd->netEnvs[netEnvId].aliasHdrs[i].hdr != HEADER_TYPE_NONE)); i++) + { + if (p_FmPcd->netEnvs[netEnvId].aliasHdrs[i].hdr == hdr) + return TRUE; + } + + return FALSE; +} + +uint8_t FmPcdNetEnvGetUnitId(t_FmPcd *p_FmPcd, uint8_t netEnvId, e_NetHeaderType hdr, bool interchangeable, protocolOpt_t opt) +{ + uint8_t i, k; + + ASSERT_COND(p_FmPcd); + + if (interchangeable) + { + for (i=0; (i < FM_PCD_MAX_NUM_OF_DISTINCTION_UNITS) && + (p_FmPcd->netEnvs[netEnvId].units[i].hdrs[0].hdr != HEADER_TYPE_NONE); i++) + { + for (k=0; (k < FM_PCD_MAX_NUM_OF_INTERCHANGEABLE_HDRS) && + (p_FmPcd->netEnvs[netEnvId].units[i].hdrs[k].hdr != HEADER_TYPE_NONE); k++) + { + if ((p_FmPcd->netEnvs[netEnvId].units[i].hdrs[k].hdr == hdr) && + (p_FmPcd->netEnvs[netEnvId].units[i].hdrs[k].opt == opt)) + + return i; + } + } + } + else + { + for (i=0; (i < FM_PCD_MAX_NUM_OF_DISTINCTION_UNITS) && + (p_FmPcd->netEnvs[netEnvId].units[i].hdrs[0].hdr != HEADER_TYPE_NONE); i++) + if ((p_FmPcd->netEnvs[netEnvId].units[i].hdrs[0].hdr == hdr) && + (p_FmPcd->netEnvs[netEnvId].units[i].hdrs[0].opt == opt) && + (p_FmPcd->netEnvs[netEnvId].units[i].hdrs[1].hdr == HEADER_TYPE_NONE)) + return i; + + for (i=0; (i < FM_PCD_MAX_NUM_OF_ALIAS_HDRS) && + (p_FmPcd->netEnvs[netEnvId].aliasHdrs[i].hdr != HEADER_TYPE_NONE); i++) + if ((p_FmPcd->netEnvs[netEnvId].aliasHdrs[i].hdr == hdr) && + (p_FmPcd->netEnvs[netEnvId].aliasHdrs[i].opt == opt)) + return p_FmPcd->netEnvs[netEnvId].aliasHdrs[i].aliasHdr; + } + + return FM_PCD_MAX_NUM_OF_DISTINCTION_UNITS; +} + +t_Error FmPcdUnregisterReassmPort(t_Handle h_FmPcd, t_Handle h_ReasmCommonPramTbl) +{ + t_FmPcd *p_FmPcd = (t_FmPcd*)h_FmPcd; + t_FmPcdCcReassmTimeoutParams ccReassmTimeoutParams = {0}; + uint8_t result; + t_Error err = E_OK; + + ASSERT_COND(p_FmPcd); + ASSERT_COND(h_ReasmCommonPramTbl); + + ccReassmTimeoutParams.iprcpt = (uint32_t)(XX_VirtToPhys(h_ReasmCommonPramTbl) - p_FmPcd->physicalMuramBase); + ccReassmTimeoutParams.activate = FALSE; /*Disable Timeout Task*/ + + if ((err = FmHcPcdCcTimeoutReassm(p_FmPcd->h_Hc, &ccReassmTimeoutParams, &result)) != E_OK) + RETURN_ERROR(MAJOR, err, NO_MSG); + + switch (result) + { + case (0): + return E_OK; + case (1): + RETURN_ERROR(MAJOR, E_INVALID_STATE, ("")); + case (2): + RETURN_ERROR(MAJOR, E_INVALID_STATE, ("")); + case (3): + RETURN_ERROR(MAJOR, E_INVALID_HANDLE, ("Disable Timeout Task with invalid IPRCPT")); + default: + RETURN_ERROR(MAJOR, E_INVALID_VALUE, NO_MSG); + } + + return E_OK; +} + +e_NetHeaderType FmPcdGetAliasHdr(t_FmPcd *p_FmPcd, uint8_t netEnvId, e_NetHeaderType hdr) +{ + int i; + + ASSERT_COND(p_FmPcd); + ASSERT_COND(netEnvId < FM_MAX_NUM_OF_PORTS); + + for (i=0; (i < FM_PCD_MAX_NUM_OF_ALIAS_HDRS) + && (p_FmPcd->netEnvs[netEnvId].aliasHdrs[i].hdr != HEADER_TYPE_NONE); i++) + { + if (p_FmPcd->netEnvs[netEnvId].aliasHdrs[i].hdr == hdr) + return p_FmPcd->netEnvs[netEnvId].aliasHdrs[i].aliasHdr; + } + + return HEADER_TYPE_NONE; +} + +void FmPcdPortRegister(t_Handle h_FmPcd, t_Handle h_FmPort, uint8_t hardwarePortId) +{ + t_FmPcd *p_FmPcd = (t_FmPcd*)h_FmPcd; + uint16_t swPortIndex = 0; + + ASSERT_COND(h_FmPcd); + HW_PORT_ID_TO_SW_PORT_INDX(swPortIndex, hardwarePortId); + p_FmPcd->p_FmPcdPlcr->portsMapping[swPortIndex].h_FmPort = h_FmPort; +} + +uint32_t FmPcdGetLcv(t_Handle h_FmPcd, uint32_t netEnvId, uint8_t hdrNum) +{ + t_FmPcd *p_FmPcd = (t_FmPcd*)h_FmPcd; + + ASSERT_COND(h_FmPcd); + return p_FmPcd->netEnvs[netEnvId].lcvs[hdrNum]; +} + +uint32_t FmPcdGetMacsecLcv(t_Handle h_FmPcd, uint32_t netEnvId) +{ + t_FmPcd *p_FmPcd = (t_FmPcd*)h_FmPcd; + + ASSERT_COND(h_FmPcd); + return p_FmPcd->netEnvs[netEnvId].macsecVector; +} + +uint8_t FmPcdGetNetEnvId(t_Handle h_NetEnv) +{ + return ((t_FmPcdNetEnv*)h_NetEnv)->netEnvId; +} + +void FmPcdIncNetEnvOwners(t_Handle h_FmPcd, uint8_t netEnvId) +{ + uint32_t intFlags; + + ASSERT_COND(h_FmPcd); + + intFlags = NetEnvLock(&((t_FmPcd*)h_FmPcd)->netEnvs[netEnvId]); + ((t_FmPcd*)h_FmPcd)->netEnvs[netEnvId].owners++; + NetEnvUnlock(&((t_FmPcd*)h_FmPcd)->netEnvs[netEnvId], intFlags); +} + +void FmPcdDecNetEnvOwners(t_Handle h_FmPcd, uint8_t netEnvId) +{ + uint32_t intFlags; + + ASSERT_COND(h_FmPcd); + ASSERT_COND(((t_FmPcd*)h_FmPcd)->netEnvs[netEnvId].owners); + + intFlags = NetEnvLock(&((t_FmPcd*)h_FmPcd)->netEnvs[netEnvId]); + ((t_FmPcd*)h_FmPcd)->netEnvs[netEnvId].owners--; + NetEnvUnlock(&((t_FmPcd*)h_FmPcd)->netEnvs[netEnvId], intFlags); +} + +uint32_t FmPcdLock(t_Handle h_FmPcd) +{ + ASSERT_COND(h_FmPcd); + return XX_LockIntrSpinlock(((t_FmPcd*)h_FmPcd)->h_Spinlock); +} + +void FmPcdUnlock(t_Handle h_FmPcd, uint32_t intFlags) +{ + ASSERT_COND(h_FmPcd); + XX_UnlockIntrSpinlock(((t_FmPcd*)h_FmPcd)->h_Spinlock, intFlags); +} + +t_FmPcdLock * FmPcdAcquireLock(t_Handle h_FmPcd) +{ + t_FmPcdLock *p_Lock; + ASSERT_COND(h_FmPcd); + p_Lock = DequeueLockFromFreeLst((t_FmPcd*)h_FmPcd); + if (!p_Lock) + { + FillFreeLocksLst(h_FmPcd); + p_Lock = DequeueLockFromFreeLst((t_FmPcd*)h_FmPcd); + } + + if (p_Lock) + EnqueueLockToAcquiredLst((t_FmPcd*)h_FmPcd, p_Lock); + return p_Lock; +} + +void FmPcdReleaseLock(t_Handle h_FmPcd, t_FmPcdLock *p_Lock) +{ + uint32_t intFlags; + ASSERT_COND(h_FmPcd); + intFlags = FmPcdLock(h_FmPcd); + LIST_DelAndInit(&p_Lock->node); + FmPcdUnlock(h_FmPcd, intFlags); + EnqueueLockToFreeLst((t_FmPcd*)h_FmPcd, p_Lock); +} + +bool FmPcdLockTryLockAll(t_Handle h_FmPcd) +{ + uint32_t intFlags; + t_List *p_Pos, *p_SavedPos=NULL; + + ASSERT_COND(h_FmPcd); + intFlags = FmPcdLock(h_FmPcd); + LIST_FOR_EACH(p_Pos, &((t_FmPcd*)h_FmPcd)->acquiredLocksLst) + { + t_FmPcdLock *p_Lock = FM_PCD_LOCK_OBJ(p_Pos); + if (!FmPcdLockTryLock(p_Lock)) + { + p_SavedPos = p_Pos; + break; + } + } + if (p_SavedPos) + { + LIST_FOR_EACH(p_Pos, &((t_FmPcd*)h_FmPcd)->acquiredLocksLst) + { + t_FmPcdLock *p_Lock = FM_PCD_LOCK_OBJ(p_Pos); + if (p_Pos == p_SavedPos) + break; + FmPcdLockUnlock(p_Lock); + } + } + FmPcdUnlock(h_FmPcd, intFlags); + + CORE_MemoryBarrier(); + + if (p_SavedPos) + return FALSE; + + return TRUE; +} + +void FmPcdLockUnlockAll(t_Handle h_FmPcd) +{ + uint32_t intFlags; + t_List *p_Pos; + + ASSERT_COND(h_FmPcd); + intFlags = FmPcdLock(h_FmPcd); + LIST_FOR_EACH(p_Pos, &((t_FmPcd*)h_FmPcd)->acquiredLocksLst) + { + t_FmPcdLock *p_Lock = FM_PCD_LOCK_OBJ(p_Pos); + p_Lock->flag = FALSE; + } + FmPcdUnlock(h_FmPcd, intFlags); + + CORE_MemoryBarrier(); +} + +t_Error FmPcdHcSync(t_Handle h_FmPcd) +{ + ASSERT_COND(h_FmPcd); + ASSERT_COND(((t_FmPcd*)h_FmPcd)->h_Hc); + + return FmHcPcdSync(((t_FmPcd*)h_FmPcd)->h_Hc); +} + +t_Handle FmPcdGetHcHandle(t_Handle h_FmPcd) +{ + ASSERT_COND(h_FmPcd); + return ((t_FmPcd*)h_FmPcd)->h_Hc; +} + +bool FmPcdIsAdvancedOffloadSupported(t_Handle h_FmPcd) +{ + ASSERT_COND(h_FmPcd); + return ((t_FmPcd*)h_FmPcd)->advancedOffloadSupport; +} +/*********************** End of inter-module routines ************************/ + + +/****************************************/ +/* API Init unit functions */ +/****************************************/ + +t_Handle FM_PCD_Config(t_FmPcdParams *p_FmPcdParams) +{ + t_FmPcd *p_FmPcd = NULL; + t_FmPhysAddr physicalMuramBase; + uint8_t i; + + SANITY_CHECK_RETURN_VALUE(p_FmPcdParams, E_INVALID_HANDLE,NULL); + + p_FmPcd = (t_FmPcd *) XX_Malloc(sizeof(t_FmPcd)); + if (!p_FmPcd) + { + REPORT_ERROR(MAJOR, E_NO_MEMORY, ("FM PCD")); + return NULL; + } + memset(p_FmPcd, 0, sizeof(t_FmPcd)); + + p_FmPcd->p_FmPcdDriverParam = (t_FmPcdDriverParam *) XX_Malloc(sizeof(t_FmPcdDriverParam)); + if (!p_FmPcd->p_FmPcdDriverParam) + { + XX_Free(p_FmPcd); + REPORT_ERROR(MAJOR, E_NO_MEMORY, ("FM PCD Driver Param")); + return NULL; + } + memset(p_FmPcd->p_FmPcdDriverParam, 0, sizeof(t_FmPcdDriverParam)); + + p_FmPcd->h_Fm = p_FmPcdParams->h_Fm; + p_FmPcd->guestId = FmGetGuestId(p_FmPcd->h_Fm); + p_FmPcd->h_FmMuram = FmGetMuramHandle(p_FmPcd->h_Fm); + if (p_FmPcd->h_FmMuram) + { + FmGetPhysicalMuramBase(p_FmPcdParams->h_Fm, &physicalMuramBase); + p_FmPcd->physicalMuramBase = (uint64_t)((uint64_t)(&physicalMuramBase)->low | ((uint64_t)(&physicalMuramBase)->high << 32)); + } + + for (i = 0; i<FM_MAX_NUM_OF_PORTS; i++) + p_FmPcd->netEnvs[i].clsPlanGrpId = ILLEGAL_CLS_PLAN; + + if (p_FmPcdParams->useHostCommand) + { + t_FmHcParams hcParams; + + memset(&hcParams, 0, sizeof(hcParams)); + hcParams.h_Fm = p_FmPcd->h_Fm; + hcParams.h_FmPcd = (t_Handle)p_FmPcd; + memcpy((uint8_t*)&hcParams.params, (uint8_t*)&p_FmPcdParams->hc, sizeof(t_FmPcdHcParams)); + p_FmPcd->h_Hc = FmHcConfigAndInit(&hcParams); + if (!p_FmPcd->h_Hc) + { + REPORT_ERROR(MAJOR, E_NO_MEMORY, ("FM PCD HC")); + FM_PCD_Free(p_FmPcd); + return NULL; + } + } + else if (p_FmPcd->guestId != NCSW_MASTER_ID) + REPORT_ERROR(MAJOR, E_INVALID_STATE, ("No Host Command defined for a guest partition.")); + + if (p_FmPcdParams->kgSupport) + { + p_FmPcd->p_FmPcdKg = (t_FmPcdKg *)KgConfig(p_FmPcd, p_FmPcdParams); + if (!p_FmPcd->p_FmPcdKg) + { + REPORT_ERROR(MAJOR, E_NO_MEMORY, ("FM PCD Keygen")); + FM_PCD_Free(p_FmPcd); + return NULL; + } + } + + if (p_FmPcdParams->plcrSupport) + { + p_FmPcd->p_FmPcdPlcr = (t_FmPcdPlcr *)PlcrConfig(p_FmPcd, p_FmPcdParams); + if (!p_FmPcd->p_FmPcdPlcr) + { + REPORT_ERROR(MAJOR, E_NO_MEMORY, ("FM PCD Policer")); + FM_PCD_Free(p_FmPcd); + return NULL; + } + } + + if (p_FmPcdParams->prsSupport) + { + p_FmPcd->p_FmPcdPrs = (t_FmPcdPrs *)PrsConfig(p_FmPcd, p_FmPcdParams); + if (!p_FmPcd->p_FmPcdPrs) + { + REPORT_ERROR(MAJOR, E_NO_MEMORY, ("FM PCD Parser")); + FM_PCD_Free(p_FmPcd); + return NULL; + } + } + + p_FmPcd->h_Spinlock = XX_InitSpinlock(); + if (!p_FmPcd->h_Spinlock) + { + REPORT_ERROR(MAJOR, E_NO_MEMORY, ("FM PCD spinlock")); + FM_PCD_Free(p_FmPcd); + return NULL; + } + INIT_LIST(&p_FmPcd->freeLocksLst); + INIT_LIST(&p_FmPcd->acquiredLocksLst); + + p_FmPcd->numOfEnabledGuestPartitionsPcds = 0; + + p_FmPcd->f_Exception = p_FmPcdParams->f_Exception; + p_FmPcd->f_FmPcdIndexedException = p_FmPcdParams->f_ExceptionId; + p_FmPcd->h_App = p_FmPcdParams->h_App; + + p_FmPcd->p_CcShadow = NULL; + p_FmPcd->ccShadowSize = 0; + p_FmPcd->ccShadowAlign = 0; + + p_FmPcd->h_ShadowSpinlock = XX_InitSpinlock(); + if (!p_FmPcd->h_ShadowSpinlock) + { + REPORT_ERROR(MAJOR, E_NO_MEMORY, ("FM PCD shadow spinlock")); + FM_PCD_Free(p_FmPcd); + return NULL; + } + + return p_FmPcd; +} + +t_Error FM_PCD_Init(t_Handle h_FmPcd) +{ + t_FmPcd *p_FmPcd = (t_FmPcd*)h_FmPcd; + t_Error err = E_OK; + t_FmPcdIpcMsg msg; + + SANITY_CHECK_RETURN_ERROR(p_FmPcd, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_FmPcd->p_FmPcdDriverParam, E_INVALID_HANDLE); + + FM_GetRevision(p_FmPcd->h_Fm, &p_FmPcd->fmRevInfo); + + if (p_FmPcd->guestId != NCSW_MASTER_ID) + { + memset(p_FmPcd->fmPcdIpcHandlerModuleName, 0, (sizeof(char)) * MODULE_NAME_SIZE); + if (Sprint (p_FmPcd->fmPcdIpcHandlerModuleName, "FM_PCD_%d_%d", FmGetId(p_FmPcd->h_Fm), NCSW_MASTER_ID) != 10) + RETURN_ERROR(MAJOR, E_INVALID_STATE, ("Sprint failed")); + memset(p_FmPcd->fmPcdModuleName, 0, (sizeof(char)) * MODULE_NAME_SIZE); + if (Sprint (p_FmPcd->fmPcdModuleName, "FM_PCD_%d_%d",FmGetId(p_FmPcd->h_Fm), p_FmPcd->guestId) != (p_FmPcd->guestId<10 ? 10:11)) + RETURN_ERROR(MAJOR, E_INVALID_STATE, ("Sprint failed")); + + p_FmPcd->h_IpcSession = XX_IpcInitSession(p_FmPcd->fmPcdIpcHandlerModuleName, p_FmPcd->fmPcdModuleName); + if (p_FmPcd->h_IpcSession) + { + t_FmPcdIpcReply reply; + uint32_t replyLength; + uint8_t isMasterAlive = 0; + + memset(&msg, 0, sizeof(msg)); + memset(&reply, 0, sizeof(reply)); + msg.msgId = FM_PCD_MASTER_IS_ALIVE; + msg.msgBody[0] = p_FmPcd->guestId; + blockingFlag = TRUE; + + do + { + replyLength = sizeof(uint32_t) + sizeof(isMasterAlive); + if ((err = XX_IpcSendMessage(p_FmPcd->h_IpcSession, + (uint8_t*)&msg, + sizeof(msg.msgId)+sizeof(p_FmPcd->guestId), + (uint8_t*)&reply, + &replyLength, + IpcMsgCompletionCB, + h_FmPcd)) != E_OK) + REPORT_ERROR(MAJOR, err, NO_MSG); + while (blockingFlag) ; + if (replyLength != (sizeof(uint32_t) + sizeof(isMasterAlive))) + REPORT_ERROR(MAJOR, E_INVALID_VALUE, ("IPC reply length mismatch")); + isMasterAlive = *(uint8_t*)(reply.replyBody); + } while (!isMasterAlive); + } + } + + CHECK_INIT_PARAMETERS(p_FmPcd, CheckFmPcdParameters); + + if (p_FmPcd->p_FmPcdKg) + { + err = KgInit(p_FmPcd); + if (err) + RETURN_ERROR(MAJOR, err, NO_MSG); + } + + if (p_FmPcd->p_FmPcdPlcr) + { + err = PlcrInit(p_FmPcd); + if (err) + RETURN_ERROR(MAJOR, err, NO_MSG); + } + + if (p_FmPcd->p_FmPcdPrs) + { + err = PrsInit(p_FmPcd); + if (err) + RETURN_ERROR(MAJOR, err, NO_MSG); + } + + if (p_FmPcd->guestId == NCSW_MASTER_ID) + { + /* register to inter-core messaging mechanism */ + memset(p_FmPcd->fmPcdModuleName, 0, (sizeof(char)) * MODULE_NAME_SIZE); + if (Sprint (p_FmPcd->fmPcdModuleName, "FM_PCD_%d_%d",FmGetId(p_FmPcd->h_Fm),NCSW_MASTER_ID) != 10) + RETURN_ERROR(MAJOR, E_INVALID_STATE, ("Sprint failed")); + err = XX_IpcRegisterMsgHandler(p_FmPcd->fmPcdModuleName, IpcMsgHandlerCB, p_FmPcd, FM_PCD_MAX_REPLY_SIZE); + if (err) + RETURN_ERROR(MAJOR, err, NO_MSG); + } + + /* IPv6 Frame-Id used for fragmentation */ + p_FmPcd->ipv6FrameIdAddr = PTR_TO_UINT(FM_MURAM_AllocMem(p_FmPcd->h_FmMuram, 4, 4)); + if (!p_FmPcd->ipv6FrameIdAddr) + { + FM_PCD_Free(p_FmPcd); + RETURN_ERROR(MAJOR, E_NO_MEMORY, ("MURAM allocation for IPv6 Frame-Id")); + } + IOMemSet32(UINT_TO_PTR(p_FmPcd->ipv6FrameIdAddr), 0, 4); + + /* CAPWAP Frame-Id used for fragmentation */ + p_FmPcd->capwapFrameIdAddr = PTR_TO_UINT(FM_MURAM_AllocMem(p_FmPcd->h_FmMuram, 2, 4)); + if (!p_FmPcd->capwapFrameIdAddr) + { + FM_PCD_Free(p_FmPcd); + RETURN_ERROR(MAJOR, E_NO_MEMORY, ("MURAM allocation for CAPWAP Frame-Id")); + } + IOMemSet32(UINT_TO_PTR(p_FmPcd->capwapFrameIdAddr), 0, 2); + + XX_Free(p_FmPcd->p_FmPcdDriverParam); + p_FmPcd->p_FmPcdDriverParam = NULL; + + FmRegisterPcd(p_FmPcd->h_Fm, p_FmPcd); + + return E_OK; +} + +t_Error FM_PCD_Free(t_Handle h_FmPcd) +{ + t_FmPcd *p_FmPcd =(t_FmPcd *)h_FmPcd; + t_Error err = E_OK; + + if (p_FmPcd->ipv6FrameIdAddr) + FM_MURAM_FreeMem(p_FmPcd->h_FmMuram, UINT_TO_PTR(p_FmPcd->ipv6FrameIdAddr)); + + if (p_FmPcd->capwapFrameIdAddr) + FM_MURAM_FreeMem(p_FmPcd->h_FmMuram, UINT_TO_PTR(p_FmPcd->capwapFrameIdAddr)); + + if (p_FmPcd->enabled) + FM_PCD_Disable(p_FmPcd); + + if (p_FmPcd->p_FmPcdDriverParam) + { + XX_Free(p_FmPcd->p_FmPcdDriverParam); + p_FmPcd->p_FmPcdDriverParam = NULL; + } + + if (p_FmPcd->p_FmPcdKg) + { + if ((err = KgFree(p_FmPcd)) != E_OK) + RETURN_ERROR(MINOR, err, NO_MSG); + XX_Free(p_FmPcd->p_FmPcdKg); + p_FmPcd->p_FmPcdKg = NULL; + } + + if (p_FmPcd->p_FmPcdPlcr) + { + PlcrFree(p_FmPcd); + XX_Free(p_FmPcd->p_FmPcdPlcr); + p_FmPcd->p_FmPcdPlcr = NULL; + } + + if (p_FmPcd->p_FmPcdPrs) + { + if (p_FmPcd->guestId == NCSW_MASTER_ID) + PrsFree(p_FmPcd); + XX_Free(p_FmPcd->p_FmPcdPrs); + p_FmPcd->p_FmPcdPrs = NULL; + } + + if (p_FmPcd->h_Hc) + { + FmHcFree(p_FmPcd->h_Hc); + p_FmPcd->h_Hc = NULL; + } + + XX_IpcUnregisterMsgHandler(p_FmPcd->fmPcdModuleName); + + FmUnregisterPcd(p_FmPcd->h_Fm); + + ReleaseFreeLocksLst(p_FmPcd); + + if (p_FmPcd->h_Spinlock) + XX_FreeSpinlock(p_FmPcd->h_Spinlock); + + if (p_FmPcd->h_ShadowSpinlock) + XX_FreeSpinlock(p_FmPcd->h_ShadowSpinlock); + + XX_Free(p_FmPcd); + + return E_OK; +} + +t_Error FM_PCD_ConfigException(t_Handle h_FmPcd, e_FmPcdExceptions exception, bool enable) +{ + t_FmPcd *p_FmPcd = (t_FmPcd*)h_FmPcd; + uint32_t bitMask = 0; + + SANITY_CHECK_RETURN_ERROR(p_FmPcd, E_INVALID_HANDLE); + + if (p_FmPcd->guestId != NCSW_MASTER_ID) + RETURN_ERROR(MAJOR, E_NOT_SUPPORTED, ("FM_PCD_ConfigException - guest mode!")); + + GET_FM_PCD_EXCEPTION_FLAG(bitMask, exception); + if (bitMask) + { + if (enable) + p_FmPcd->exceptions |= bitMask; + else + p_FmPcd->exceptions &= ~bitMask; + } + else + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("Undefined exception")); + + return E_OK; +} + +t_Error FM_PCD_ConfigHcFramesDataMemory(t_Handle h_FmPcd, uint8_t memId) +{ + t_FmPcd *p_FmPcd = (t_FmPcd*)h_FmPcd; + + SANITY_CHECK_RETURN_ERROR(p_FmPcd, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_FmPcd->h_Hc, E_INVALID_HANDLE); + + return FmHcSetFramesDataMemory(p_FmPcd->h_Hc, memId); +} + +t_Error FM_PCD_Enable(t_Handle h_FmPcd) +{ + t_FmPcd *p_FmPcd = (t_FmPcd*)h_FmPcd; + t_Error err = E_OK; + + SANITY_CHECK_RETURN_ERROR(h_FmPcd, E_INVALID_HANDLE); + + if (p_FmPcd->enabled) + return E_OK; + + if ((p_FmPcd->guestId != NCSW_MASTER_ID) && + p_FmPcd->h_IpcSession) + { + uint8_t enabled; + t_FmPcdIpcMsg msg; + t_FmPcdIpcReply reply; + uint32_t replyLength; + + memset(&reply, 0, sizeof(reply)); + memset(&msg, 0, sizeof(msg)); + msg.msgId = FM_PCD_MASTER_IS_ENABLED; + replyLength = sizeof(uint32_t) + sizeof(enabled); + if ((err = XX_IpcSendMessage(p_FmPcd->h_IpcSession, + (uint8_t*)&msg, + sizeof(msg.msgId), + (uint8_t*)&reply, + &replyLength, + NULL, + NULL)) != E_OK) + RETURN_ERROR(MAJOR, err, NO_MSG); + if (replyLength != sizeof(uint32_t) + sizeof(enabled)) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("IPC reply length mismatch")); + p_FmPcd->enabled = (bool)!!(*(uint8_t*)(reply.replyBody)); + if (!p_FmPcd->enabled) + RETURN_ERROR(MAJOR, E_INVALID_STATE, ("FM-PCD master should be enabled first!")); + + return E_OK; + } + else if (p_FmPcd->guestId != NCSW_MASTER_ID) + RETURN_ERROR(MINOR, E_NOT_SUPPORTED, + ("running in guest-mode without IPC!")); + + if (p_FmPcd->p_FmPcdKg) + KgEnable(p_FmPcd); + + if (p_FmPcd->p_FmPcdPlcr) + PlcrEnable(p_FmPcd); + + if (p_FmPcd->p_FmPcdPrs) + PrsEnable(p_FmPcd); + + p_FmPcd->enabled = TRUE; + + return E_OK; +} + +t_Error FM_PCD_Disable(t_Handle h_FmPcd) +{ + t_FmPcd *p_FmPcd = (t_FmPcd*)h_FmPcd; + t_Error err = E_OK; + + SANITY_CHECK_RETURN_ERROR(h_FmPcd, E_INVALID_HANDLE); + + if (!p_FmPcd->enabled) + return E_OK; + + if ((p_FmPcd->guestId != NCSW_MASTER_ID) && + p_FmPcd->h_IpcSession) + { + t_FmPcdIpcMsg msg; + t_FmPcdIpcReply reply; + uint32_t replyLength; + + memset(&reply, 0, sizeof(reply)); + memset(&msg, 0, sizeof(msg)); + msg.msgId = FM_PCD_GUEST_DISABLE; + replyLength = sizeof(uint32_t); + if ((err = XX_IpcSendMessage(p_FmPcd->h_IpcSession, + (uint8_t*)&msg, + sizeof(msg.msgId), + (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")); + if (reply.error == E_OK) + p_FmPcd->enabled = FALSE; + + return (t_Error)(reply.error); + } + else if (p_FmPcd->guestId != NCSW_MASTER_ID) + RETURN_ERROR(MINOR, E_NOT_SUPPORTED, + ("running in guest-mode without IPC!")); + + if (p_FmPcd->numOfEnabledGuestPartitionsPcds != 0) + RETURN_ERROR(MAJOR, E_INVALID_STATE, + ("Trying to disable a master partition PCD while" + "guest partitions are still enabled!")); + + if (p_FmPcd->p_FmPcdKg) + KgDisable(p_FmPcd); + + if (p_FmPcd->p_FmPcdPlcr) + PlcrDisable(p_FmPcd); + + if (p_FmPcd->p_FmPcdPrs) + PrsDisable(p_FmPcd); + + p_FmPcd->enabled = FALSE; + + return E_OK; +} + +t_Handle FM_PCD_NetEnvCharacteristicsSet(t_Handle h_FmPcd, t_FmPcdNetEnvParams *p_NetEnvParams) +{ + t_FmPcd *p_FmPcd = (t_FmPcd*)h_FmPcd; + uint32_t intFlags, specialUnits = 0; + uint8_t bitId = 0; + uint8_t i, j, k; + uint8_t netEnvCurrId; + uint8_t ipsecAhUnit = 0,ipsecEspUnit = 0; + bool ipsecAhExists = FALSE, ipsecEspExists = FALSE, shim1Selected = FALSE; + uint8_t hdrNum; + t_FmPcdNetEnvParams *p_ModifiedNetEnvParams; + + SANITY_CHECK_RETURN_VALUE(h_FmPcd, E_INVALID_STATE, NULL); + SANITY_CHECK_RETURN_VALUE(!p_FmPcd->p_FmPcdDriverParam, E_INVALID_STATE, NULL); + SANITY_CHECK_RETURN_VALUE(p_NetEnvParams, E_NULL_POINTER, NULL); + + intFlags = FmPcdLock(p_FmPcd); + + /* find a new netEnv */ + for (i = 0; i < FM_MAX_NUM_OF_PORTS; i++) + if (!p_FmPcd->netEnvs[i].used) + break; + + if (i== FM_MAX_NUM_OF_PORTS) + { + REPORT_ERROR(MAJOR, E_FULL,("No more than %d netEnv's allowed.", FM_MAX_NUM_OF_PORTS)); + FmPcdUnlock(p_FmPcd, intFlags); + return NULL; + } + + p_FmPcd->netEnvs[i].used = TRUE; + FmPcdUnlock(p_FmPcd, intFlags); + + /* As anyone doesn't have handle of this netEnv yet, no need + to protect it with spinlocks */ + + p_ModifiedNetEnvParams = (t_FmPcdNetEnvParams *)XX_Malloc(sizeof(t_FmPcdNetEnvParams)); + if (!p_ModifiedNetEnvParams) + { + REPORT_ERROR(MAJOR, E_NO_MEMORY, ("FmPcdNetEnvParams")); + return NULL; + } + + memcpy(p_ModifiedNetEnvParams, p_NetEnvParams, sizeof(t_FmPcdNetEnvParams)); + p_NetEnvParams = p_ModifiedNetEnvParams; + + netEnvCurrId = (uint8_t)i; + + /* clear from previous use */ + memset(&p_FmPcd->netEnvs[netEnvCurrId].units, 0, FM_PCD_MAX_NUM_OF_DISTINCTION_UNITS * sizeof(t_FmPcdIntDistinctionUnit)); + memset(&p_FmPcd->netEnvs[netEnvCurrId].aliasHdrs, 0, FM_PCD_MAX_NUM_OF_ALIAS_HDRS * sizeof(t_FmPcdNetEnvAliases)); + memcpy(&p_FmPcd->netEnvs[netEnvCurrId].units, p_NetEnvParams->units, p_NetEnvParams->numOfDistinctionUnits*sizeof(t_FmPcdIntDistinctionUnit)); + + p_FmPcd->netEnvs[netEnvCurrId].netEnvId = netEnvCurrId; + p_FmPcd->netEnvs[netEnvCurrId].h_FmPcd = p_FmPcd; + + p_FmPcd->netEnvs[netEnvCurrId].clsPlanGrpId = ILLEGAL_CLS_PLAN; + + /* check that header with opt is not interchanged with the same header */ + for (i = 0; (i < FM_PCD_MAX_NUM_OF_DISTINCTION_UNITS) + && (p_FmPcd->netEnvs[netEnvCurrId].units[i].hdrs[0].hdr != HEADER_TYPE_NONE); i++) + { + for (k = 0; (k < FM_PCD_MAX_NUM_OF_INTERCHANGEABLE_HDRS) + && (p_FmPcd->netEnvs[netEnvCurrId].units[i].hdrs[k].hdr != HEADER_TYPE_NONE); k++) + { + /* if an option exists, check that other headers are not the same header + without option */ + if (p_FmPcd->netEnvs[netEnvCurrId].units[i].hdrs[k].opt) + { + for (j = 0; (j < FM_PCD_MAX_NUM_OF_INTERCHANGEABLE_HDRS) + && (p_FmPcd->netEnvs[netEnvCurrId].units[i].hdrs[j].hdr != HEADER_TYPE_NONE); j++) + { + if ((p_FmPcd->netEnvs[netEnvCurrId].units[i].hdrs[j].hdr == p_FmPcd->netEnvs[netEnvCurrId].units[i].hdrs[k].hdr) && + !p_FmPcd->netEnvs[netEnvCurrId].units[i].hdrs[j].opt) + { + REPORT_ERROR(MINOR, E_FULL, + ("Illegal unit - header with opt may not be interchangeable with the same header without opt")); + XX_Free(p_ModifiedNetEnvParams); + return NULL; + } + } + } + } + } + + /* Specific headers checking */ + for (i = 0; (i < FM_PCD_MAX_NUM_OF_DISTINCTION_UNITS) + && (p_FmPcd->netEnvs[netEnvCurrId].units[i].hdrs[0].hdr != HEADER_TYPE_NONE); i++) + { + for (k = 0; (k < FM_PCD_MAX_NUM_OF_INTERCHANGEABLE_HDRS) + && (p_FmPcd->netEnvs[netEnvCurrId].units[i].hdrs[k].hdr != HEADER_TYPE_NONE); k++) + { + /* Some headers pairs may not be defined on different units as the parser + doesn't distinguish */ + /* IPSEC_AH and IPSEC_SPI can't be 2 units, */ + /* check that header with opt is not interchanged with the same header */ + if (p_FmPcd->netEnvs[netEnvCurrId].units[i].hdrs[k].hdr == HEADER_TYPE_IPSEC_AH) + { + if (ipsecEspExists && (ipsecEspUnit != i)) + { + REPORT_ERROR(MINOR, E_INVALID_STATE, ("HEADER_TYPE_IPSEC_AH and HEADER_TYPE_IPSEC_ESP may not be defined in separate units")); + XX_Free(p_ModifiedNetEnvParams); + return NULL; + } + else + { + ipsecAhUnit = i; + ipsecAhExists = TRUE; + } + } + if (p_FmPcd->netEnvs[netEnvCurrId].units[i].hdrs[k].hdr == HEADER_TYPE_IPSEC_ESP) + { + if (ipsecAhExists && (ipsecAhUnit != i)) + { + REPORT_ERROR(MINOR, E_INVALID_STATE, ("HEADER_TYPE_IPSEC_AH and HEADER_TYPE_IPSEC_ESP may not be defined in separate units")); + XX_Free(p_ModifiedNetEnvParams); + return NULL; + } + else + { + ipsecEspUnit = i; + ipsecEspExists = TRUE; + } + } + /* ENCAP_ESP */ + if (p_FmPcd->netEnvs[netEnvCurrId].units[i].hdrs[k].hdr == HEADER_TYPE_UDP_ENCAP_ESP) + { + /* IPSec UDP encapsulation is currently set to use SHIM1 */ + p_FmPcd->netEnvs[netEnvCurrId].aliasHdrs[specialUnits].hdr = HEADER_TYPE_UDP_ENCAP_ESP; + p_FmPcd->netEnvs[netEnvCurrId].aliasHdrs[specialUnits++].aliasHdr = HEADER_TYPE_USER_DEFINED_SHIM1; + p_FmPcd->netEnvs[netEnvCurrId].units[i].hdrs[k].hdr = HEADER_TYPE_USER_DEFINED_SHIM1; + p_FmPcd->netEnvs[netEnvCurrId].units[i].hdrs[k].opt = 0; + } +#if (DPAA_VERSION >= 11) || ((DPAA_VERSION == 10) && defined(FM_CAPWAP_SUPPORT)) + /* UDP_LITE */ + if (p_FmPcd->netEnvs[netEnvCurrId].units[i].hdrs[k].hdr == HEADER_TYPE_UDP_LITE) + { + p_FmPcd->netEnvs[netEnvCurrId].aliasHdrs[specialUnits].hdr = HEADER_TYPE_UDP_LITE; + p_FmPcd->netEnvs[netEnvCurrId].aliasHdrs[specialUnits++].aliasHdr = HEADER_TYPE_UDP; + p_FmPcd->netEnvs[netEnvCurrId].units[i].hdrs[k].hdr = HEADER_TYPE_UDP; + p_FmPcd->netEnvs[netEnvCurrId].units[i].hdrs[k].opt = 0; + } +#endif /* (DPAA_VERSION >= 11) || ((DPAA_VERSION == 10) && defined(FM_CAPWAP_SUPPORT)) */ + + /* IP FRAG */ + if ((p_FmPcd->netEnvs[netEnvCurrId].units[i].hdrs[k].hdr == HEADER_TYPE_IPv4) && + (p_FmPcd->netEnvs[netEnvCurrId].units[i].hdrs[k].opt == IPV4_FRAG_1)) + { + /* If IPv4+Frag, we need to set 2 units - SHIM 2 and IPv4. We first set SHIM2, and than check if + * IPv4 exists. If so we don't need to set an extra unit + * We consider as "having IPv4" any IPv4 without interchangable headers + * but including any options. */ + p_FmPcd->netEnvs[netEnvCurrId].aliasHdrs[specialUnits].hdr = HEADER_TYPE_IPv4; + p_FmPcd->netEnvs[netEnvCurrId].aliasHdrs[specialUnits].opt = IPV4_FRAG_1; + p_FmPcd->netEnvs[netEnvCurrId].aliasHdrs[specialUnits++].aliasHdr = HEADER_TYPE_USER_DEFINED_SHIM2; + p_FmPcd->netEnvs[netEnvCurrId].units[i].hdrs[k].hdr = HEADER_TYPE_USER_DEFINED_SHIM2; + p_FmPcd->netEnvs[netEnvCurrId].units[i].hdrs[k].opt = 0; + + /* check if IPv4 header exists by itself */ + if (FmPcdNetEnvGetUnitId(p_FmPcd, netEnvCurrId, HEADER_TYPE_IPv4, FALSE, 0) == FM_PCD_MAX_NUM_OF_DISTINCTION_UNITS) + { + p_FmPcd->netEnvs[netEnvCurrId].units[p_NetEnvParams->numOfDistinctionUnits].hdrs[0].hdr = HEADER_TYPE_IPv4; + p_FmPcd->netEnvs[netEnvCurrId].units[p_NetEnvParams->numOfDistinctionUnits++].hdrs[0].opt = 0; + } + } + if ((p_FmPcd->netEnvs[netEnvCurrId].units[i].hdrs[k].hdr == HEADER_TYPE_IPv6) && + (p_FmPcd->netEnvs[netEnvCurrId].units[i].hdrs[k].opt == IPV6_FRAG_1)) + { + /* If IPv6+Frag, we need to set 2 units - SHIM 2 and IPv6. We first set SHIM2, and than check if + * IPv4 exists. If so we don't need to set an extra unit + * We consider as "having IPv6" any IPv6 without interchangable headers + * but including any options. */ + p_FmPcd->netEnvs[netEnvCurrId].aliasHdrs[specialUnits].hdr = HEADER_TYPE_IPv6; + p_FmPcd->netEnvs[netEnvCurrId].aliasHdrs[specialUnits].opt = IPV6_FRAG_1; + p_FmPcd->netEnvs[netEnvCurrId].aliasHdrs[specialUnits++].aliasHdr = HEADER_TYPE_USER_DEFINED_SHIM2; + p_FmPcd->netEnvs[netEnvCurrId].units[i].hdrs[k].hdr = HEADER_TYPE_USER_DEFINED_SHIM2; + p_FmPcd->netEnvs[netEnvCurrId].units[i].hdrs[k].opt = 0; + + /* check if IPv6 header exists by itself */ + if (FmPcdNetEnvGetUnitId(p_FmPcd, netEnvCurrId, HEADER_TYPE_IPv6, FALSE, 0) == FM_PCD_MAX_NUM_OF_DISTINCTION_UNITS) + { + p_FmPcd->netEnvs[netEnvCurrId].units[p_NetEnvParams->numOfDistinctionUnits].hdrs[0].hdr = HEADER_TYPE_IPv6; + p_FmPcd->netEnvs[netEnvCurrId].units[p_NetEnvParams->numOfDistinctionUnits++].hdrs[0].opt = 0; + } + } +#if (DPAA_VERSION >= 11) + /* CAPWAP FRAG */ + if ((p_FmPcd->netEnvs[netEnvCurrId].units[i].hdrs[k].hdr == HEADER_TYPE_CAPWAP) && + (p_FmPcd->netEnvs[netEnvCurrId].units[i].hdrs[k].opt == CAPWAP_FRAG_1)) + { + p_FmPcd->netEnvs[netEnvCurrId].aliasHdrs[specialUnits].hdr = HEADER_TYPE_CAPWAP; + p_FmPcd->netEnvs[netEnvCurrId].aliasHdrs[specialUnits].opt = CAPWAP_FRAG_1; + p_FmPcd->netEnvs[netEnvCurrId].aliasHdrs[specialUnits++].aliasHdr = HEADER_TYPE_USER_DEFINED_SHIM2; + p_FmPcd->netEnvs[netEnvCurrId].units[i].hdrs[k].hdr = HEADER_TYPE_USER_DEFINED_SHIM2; + p_FmPcd->netEnvs[netEnvCurrId].units[i].hdrs[k].opt = 0; + } +#endif /* (DPAA_VERSION >= 11) */ + } + } + + /* if private header (shim), check that no other headers specified */ + for (i = 0; (i < FM_PCD_MAX_NUM_OF_DISTINCTION_UNITS) + && (p_FmPcd->netEnvs[netEnvCurrId].units[i].hdrs[0].hdr != HEADER_TYPE_NONE); i++) + { + if (IS_PRIVATE_HEADER(p_FmPcd->netEnvs[netEnvCurrId].units[i].hdrs[0].hdr)) + if (p_FmPcd->netEnvs[netEnvCurrId].units[i].hdrs[1].hdr != HEADER_TYPE_NONE) + { + REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("SHIM header may not be interchanged with other headers")); + XX_Free(p_ModifiedNetEnvParams); + return NULL; + } + } + + for (i = 0; i < p_NetEnvParams->numOfDistinctionUnits; i++) + { + if (IS_PRIVATE_HEADER(p_FmPcd->netEnvs[netEnvCurrId].units[i].hdrs[0].hdr)) + switch (p_FmPcd->netEnvs[netEnvCurrId].units[i].hdrs[0].hdr) + { + case (HEADER_TYPE_USER_DEFINED_SHIM1): + if (shim1Selected) + { + REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("SHIM header cannot be selected with UDP_IPSEC_ESP")); + XX_Free(p_ModifiedNetEnvParams); + return NULL; + } + shim1Selected = TRUE; + p_FmPcd->netEnvs[netEnvCurrId].unitsVectors[i] = 0x00000001; + break; + case (HEADER_TYPE_USER_DEFINED_SHIM2): + p_FmPcd->netEnvs[netEnvCurrId].unitsVectors[i] = 0x00000002; + break; + default: + REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Requested SHIM not supported")); + } + else + { + p_FmPcd->netEnvs[netEnvCurrId].unitsVectors[i] = (uint32_t)(0x80000000 >> bitId++); + + if (IS_SPECIAL_HEADER(p_FmPcd->netEnvs[netEnvCurrId].units[i].hdrs[0].hdr)) + p_FmPcd->netEnvs[netEnvCurrId].macsecVector = p_FmPcd->netEnvs[netEnvCurrId].unitsVectors[i]; + } + } + + /* define a set of hardware parser LCV's according to the defined netenv */ + + /* set an array of LCV's for each header in the netEnv */ + for (i = 0; (i < FM_PCD_MAX_NUM_OF_DISTINCTION_UNITS) + && (p_FmPcd->netEnvs[netEnvCurrId].units[i].hdrs[0].hdr != HEADER_TYPE_NONE); i++) + { + /* private headers have no LCV in the hard parser */ + if (!IS_PRIVATE_HEADER(p_FmPcd->netEnvs[netEnvCurrId].units[i].hdrs[0].hdr)) + { + for (k = 0; (k < FM_PCD_MAX_NUM_OF_INTERCHANGEABLE_HDRS) + && (p_FmPcd->netEnvs[netEnvCurrId].units[i].hdrs[k].hdr != HEADER_TYPE_NONE); k++) + { + hdrNum = GetPrsHdrNum(p_FmPcd->netEnvs[netEnvCurrId].units[i].hdrs[k].hdr); + if ((hdrNum == ILLEGAL_HDR_NUM) || (hdrNum == NO_HDR_NUM)) + { + REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, NO_MSG); + XX_Free(p_ModifiedNetEnvParams); + return NULL; + } + p_FmPcd->netEnvs[netEnvCurrId].lcvs[hdrNum] |= p_FmPcd->netEnvs[netEnvCurrId].unitsVectors[i]; + } + } + } + XX_Free(p_ModifiedNetEnvParams); + + p_FmPcd->netEnvs[netEnvCurrId].h_Spinlock = XX_InitSpinlock(); + if (!p_FmPcd->netEnvs[netEnvCurrId].h_Spinlock) + { + REPORT_ERROR(MAJOR, E_NO_MEMORY, ("FM Pcd NetEnv spinlock")); + return NULL; + } + return &p_FmPcd->netEnvs[netEnvCurrId]; +} + +t_Error FM_PCD_NetEnvCharacteristicsDelete(t_Handle h_NetEnv) +{ + t_FmPcdNetEnv *p_NetEnv = (t_FmPcdNetEnv*)h_NetEnv; + t_FmPcd *p_FmPcd = p_NetEnv->h_FmPcd; + uint32_t intFlags; + uint8_t netEnvId = p_NetEnv->netEnvId; + + SANITY_CHECK_RETURN_ERROR(p_FmPcd, E_INVALID_STATE); + SANITY_CHECK_RETURN_ERROR(!p_FmPcd->p_FmPcdDriverParam, E_INVALID_STATE); + + /* check that no port is bound to this netEnv */ + if (p_FmPcd->netEnvs[netEnvId].owners) + { + RETURN_ERROR(MINOR, E_INVALID_STATE, + ("Trying to delete a netEnv that has ports/schemes/trees/clsPlanGrps bound to")); + } + + intFlags = FmPcdLock(p_FmPcd); + + p_FmPcd->netEnvs[netEnvId].used = FALSE; + p_FmPcd->netEnvs[netEnvId].clsPlanGrpId = ILLEGAL_CLS_PLAN; + + memset(p_FmPcd->netEnvs[netEnvId].units, 0, sizeof(t_FmPcdIntDistinctionUnit)*FM_PCD_MAX_NUM_OF_DISTINCTION_UNITS); + memset(p_FmPcd->netEnvs[netEnvId].unitsVectors, 0, sizeof(uint32_t)*FM_PCD_MAX_NUM_OF_DISTINCTION_UNITS); + memset(p_FmPcd->netEnvs[netEnvId].lcvs, 0, sizeof(uint32_t)*FM_PCD_PRS_NUM_OF_HDRS); + + if (p_FmPcd->netEnvs[netEnvId].h_Spinlock) + XX_FreeSpinlock(p_FmPcd->netEnvs[netEnvId].h_Spinlock); + + FmPcdUnlock(p_FmPcd, intFlags); + return E_OK; +} + +void FM_PCD_HcTxConf(t_Handle h_FmPcd, t_DpaaFD *p_Fd) +{ + t_FmPcd *p_FmPcd = (t_FmPcd*)h_FmPcd; + + SANITY_CHECK_RETURN(h_FmPcd, E_INVALID_STATE); + + FmHcTxConf(p_FmPcd->h_Hc, p_Fd); +} + +t_Error FM_PCD_SetAdvancedOffloadSupport(t_Handle h_FmPcd) +{ + t_FmPcd *p_FmPcd = (t_FmPcd*)h_FmPcd; + t_FmCtrlCodeRevisionInfo revInfo; + t_Error err; + + SANITY_CHECK_RETURN_ERROR(p_FmPcd, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(!p_FmPcd->p_FmPcdDriverParam, E_INVALID_STATE); + SANITY_CHECK_RETURN_ERROR(!p_FmPcd->enabled, E_INVALID_STATE); + + if ((err = FM_GetFmanCtrlCodeRevision(p_FmPcd->h_Fm, &revInfo)) != E_OK) + { + DBG(WARNING, ("FM in guest-mode without IPC, can't validate firmware revision.")); + revInfo.packageRev = IP_OFFLOAD_PACKAGE_NUMBER; + } + if (!IS_OFFLOAD_PACKAGE(revInfo.packageRev)) + RETURN_ERROR(MAJOR, E_NOT_SUPPORTED, ("Fman ctrl code package")); + + if (!p_FmPcd->h_Hc) + RETURN_ERROR(MAJOR, E_INVALID_HANDLE, ("HC must be initialized in this mode")); + + p_FmPcd->advancedOffloadSupport = TRUE; + + return E_OK; +} + +uint32_t FM_PCD_GetCounter(t_Handle h_FmPcd, e_FmPcdCounters counter) +{ + t_FmPcd *p_FmPcd = (t_FmPcd*)h_FmPcd; + uint32_t outCounter = 0; + t_Error err; + + SANITY_CHECK_RETURN_VALUE(h_FmPcd, E_INVALID_HANDLE, 0); + SANITY_CHECK_RETURN_VALUE(!p_FmPcd->p_FmPcdDriverParam, E_INVALID_STATE, 0); + + switch (counter) + { + case (e_FM_PCD_KG_COUNTERS_TOTAL): + if (!p_FmPcd->p_FmPcdKg) + { + REPORT_ERROR(MAJOR, E_INVALID_STATE, ("KeyGen is not activated")); + return 0; + } + if ((p_FmPcd->guestId != NCSW_MASTER_ID) && + !p_FmPcd->p_FmPcdKg->p_FmPcdKgRegs && + !p_FmPcd->h_IpcSession) + { + REPORT_ERROR(MINOR, E_NOT_SUPPORTED, + ("running in guest-mode without neither IPC nor mapped register!")); + return 0; + } + break; + + case (e_FM_PCD_PLCR_COUNTERS_YELLOW): + case (e_FM_PCD_PLCR_COUNTERS_RED): + case (e_FM_PCD_PLCR_COUNTERS_RECOLORED_TO_RED): + case (e_FM_PCD_PLCR_COUNTERS_RECOLORED_TO_YELLOW): + case (e_FM_PCD_PLCR_COUNTERS_TOTAL): + case (e_FM_PCD_PLCR_COUNTERS_LENGTH_MISMATCH): + if (!p_FmPcd->p_FmPcdPlcr) + { + REPORT_ERROR(MAJOR, E_INVALID_STATE, ("Policer is not activated")); + return 0; + } + if ((p_FmPcd->guestId != NCSW_MASTER_ID) && + !p_FmPcd->p_FmPcdPlcr->p_FmPcdPlcrRegs && + !p_FmPcd->h_IpcSession) + { + REPORT_ERROR(MINOR, E_NOT_SUPPORTED, + ("running in \"guest-mode\" without neither IPC nor mapped register!")); + return 0; + } + + /* check that counters are enabled */ + if (p_FmPcd->p_FmPcdPlcr->p_FmPcdPlcrRegs && + !(GET_UINT32(p_FmPcd->p_FmPcdPlcr->p_FmPcdPlcrRegs->fmpl_gcr) & FM_PCD_PLCR_GCR_STEN)) + { + REPORT_ERROR(MINOR, E_INVALID_STATE, ("Requested counter was not enabled")); + return 0; + } + ASSERT_COND(p_FmPcd->p_FmPcdPlcr->p_FmPcdPlcrRegs || + ((p_FmPcd->guestId != NCSW_MASTER_ID) && p_FmPcd->h_IpcSession)); + break; + + case (e_FM_PCD_PRS_COUNTERS_PARSE_DISPATCH): + case (e_FM_PCD_PRS_COUNTERS_L2_PARSE_RESULT_RETURNED): + case (e_FM_PCD_PRS_COUNTERS_L3_PARSE_RESULT_RETURNED): + case (e_FM_PCD_PRS_COUNTERS_L4_PARSE_RESULT_RETURNED): + case (e_FM_PCD_PRS_COUNTERS_SHIM_PARSE_RESULT_RETURNED): + case (e_FM_PCD_PRS_COUNTERS_L2_PARSE_RESULT_RETURNED_WITH_ERR): + case (e_FM_PCD_PRS_COUNTERS_L3_PARSE_RESULT_RETURNED_WITH_ERR): + case (e_FM_PCD_PRS_COUNTERS_L4_PARSE_RESULT_RETURNED_WITH_ERR): + case (e_FM_PCD_PRS_COUNTERS_SHIM_PARSE_RESULT_RETURNED_WITH_ERR): + case (e_FM_PCD_PRS_COUNTERS_SOFT_PRS_CYCLES): + case (e_FM_PCD_PRS_COUNTERS_SOFT_PRS_STALL_CYCLES): + case (e_FM_PCD_PRS_COUNTERS_HARD_PRS_CYCLE_INCL_STALL_CYCLES): + case (e_FM_PCD_PRS_COUNTERS_MURAM_READ_CYCLES): + case (e_FM_PCD_PRS_COUNTERS_MURAM_READ_STALL_CYCLES): + case (e_FM_PCD_PRS_COUNTERS_MURAM_WRITE_CYCLES): + case (e_FM_PCD_PRS_COUNTERS_MURAM_WRITE_STALL_CYCLES): + case (e_FM_PCD_PRS_COUNTERS_FPM_COMMAND_STALL_CYCLES): + if (!p_FmPcd->p_FmPcdPrs) + { + REPORT_ERROR(MAJOR, E_INVALID_STATE, ("Parser is not activated")); + return 0; + } + if ((p_FmPcd->guestId != NCSW_MASTER_ID) && + !p_FmPcd->p_FmPcdPrs->p_FmPcdPrsRegs && + !p_FmPcd->h_IpcSession) + { + REPORT_ERROR(MINOR, E_NOT_SUPPORTED, + ("running in guest-mode without neither IPC nor mapped register!")); + return 0; + } + break; + default: + REPORT_ERROR(MAJOR, E_INVALID_STATE, ("Unsupported type of counter")); + return 0; + } + + if ((p_FmPcd->guestId != NCSW_MASTER_ID) && + p_FmPcd->h_IpcSession) + { + t_FmPcdIpcMsg msg; + t_FmPcdIpcReply reply; + uint32_t replyLength; + + memset(&msg, 0, sizeof(msg)); + memset(&reply, 0, sizeof(reply)); + msg.msgId = FM_PCD_GET_COUNTER; + memcpy(msg.msgBody, (uint8_t *)&counter, sizeof(uint32_t)); + replyLength = sizeof(uint32_t) + sizeof(uint32_t); + if ((err = XX_IpcSendMessage(p_FmPcd->h_IpcSession, + (uint8_t*)&msg, + sizeof(msg.msgId) +sizeof(uint32_t), + (uint8_t*)&reply, + &replyLength, + NULL, + NULL)) != E_OK) + RETURN_ERROR(MAJOR, err, NO_MSG); + if (replyLength != sizeof(uint32_t) + sizeof(uint32_t)) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("IPC reply length mismatch")); + + memcpy((uint8_t*)&outCounter, reply.replyBody, sizeof(uint32_t)); + return outCounter; + } + + switch (counter) + { + /* Parser statistics */ + case (e_FM_PCD_PRS_COUNTERS_PARSE_DISPATCH): + return GET_UINT32(p_FmPcd->p_FmPcdPrs->p_FmPcdPrsRegs->fmpr_pds); + case (e_FM_PCD_PRS_COUNTERS_L2_PARSE_RESULT_RETURNED): + return GET_UINT32(p_FmPcd->p_FmPcdPrs->p_FmPcdPrsRegs->fmpr_l2rrs); + case (e_FM_PCD_PRS_COUNTERS_L3_PARSE_RESULT_RETURNED): + return GET_UINT32(p_FmPcd->p_FmPcdPrs->p_FmPcdPrsRegs->fmpr_l3rrs); + case (e_FM_PCD_PRS_COUNTERS_L4_PARSE_RESULT_RETURNED): + return GET_UINT32(p_FmPcd->p_FmPcdPrs->p_FmPcdPrsRegs->fmpr_l4rrs); + case (e_FM_PCD_PRS_COUNTERS_SHIM_PARSE_RESULT_RETURNED): + return GET_UINT32(p_FmPcd->p_FmPcdPrs->p_FmPcdPrsRegs->fmpr_srrs); + case (e_FM_PCD_PRS_COUNTERS_L2_PARSE_RESULT_RETURNED_WITH_ERR): + return GET_UINT32(p_FmPcd->p_FmPcdPrs->p_FmPcdPrsRegs->fmpr_l2rres); + case (e_FM_PCD_PRS_COUNTERS_L3_PARSE_RESULT_RETURNED_WITH_ERR): + return GET_UINT32(p_FmPcd->p_FmPcdPrs->p_FmPcdPrsRegs->fmpr_l3rres); + case (e_FM_PCD_PRS_COUNTERS_L4_PARSE_RESULT_RETURNED_WITH_ERR): + return GET_UINT32(p_FmPcd->p_FmPcdPrs->p_FmPcdPrsRegs->fmpr_l4rres); + case (e_FM_PCD_PRS_COUNTERS_SHIM_PARSE_RESULT_RETURNED_WITH_ERR): + return GET_UINT32(p_FmPcd->p_FmPcdPrs->p_FmPcdPrsRegs->fmpr_srres); + case (e_FM_PCD_PRS_COUNTERS_SOFT_PRS_CYCLES): + return GET_UINT32(p_FmPcd->p_FmPcdPrs->p_FmPcdPrsRegs->fmpr_spcs); + case (e_FM_PCD_PRS_COUNTERS_SOFT_PRS_STALL_CYCLES): + return GET_UINT32(p_FmPcd->p_FmPcdPrs->p_FmPcdPrsRegs->fmpr_spscs); + case (e_FM_PCD_PRS_COUNTERS_HARD_PRS_CYCLE_INCL_STALL_CYCLES): + return GET_UINT32(p_FmPcd->p_FmPcdPrs->p_FmPcdPrsRegs->fmpr_hxscs); + case (e_FM_PCD_PRS_COUNTERS_MURAM_READ_CYCLES): + return GET_UINT32(p_FmPcd->p_FmPcdPrs->p_FmPcdPrsRegs->fmpr_mrcs); + case (e_FM_PCD_PRS_COUNTERS_MURAM_READ_STALL_CYCLES): + return GET_UINT32(p_FmPcd->p_FmPcdPrs->p_FmPcdPrsRegs->fmpr_mrscs); + case (e_FM_PCD_PRS_COUNTERS_MURAM_WRITE_CYCLES): + return GET_UINT32(p_FmPcd->p_FmPcdPrs->p_FmPcdPrsRegs->fmpr_mwcs); + case (e_FM_PCD_PRS_COUNTERS_MURAM_WRITE_STALL_CYCLES): + return GET_UINT32(p_FmPcd->p_FmPcdPrs->p_FmPcdPrsRegs->fmpr_mwscs); + case (e_FM_PCD_PRS_COUNTERS_FPM_COMMAND_STALL_CYCLES): + return GET_UINT32(p_FmPcd->p_FmPcdPrs->p_FmPcdPrsRegs->fmpr_fcscs); + case (e_FM_PCD_KG_COUNTERS_TOTAL): + return GET_UINT32(p_FmPcd->p_FmPcdKg->p_FmPcdKgRegs->fmkg_tpc); + + /* Policer statistics */ + case (e_FM_PCD_PLCR_COUNTERS_YELLOW): + return GET_UINT32(p_FmPcd->p_FmPcdPlcr->p_FmPcdPlcrRegs->fmpl_ypcnt); + case (e_FM_PCD_PLCR_COUNTERS_RED): + return GET_UINT32(p_FmPcd->p_FmPcdPlcr->p_FmPcdPlcrRegs->fmpl_rpcnt); + case (e_FM_PCD_PLCR_COUNTERS_RECOLORED_TO_RED): + return GET_UINT32(p_FmPcd->p_FmPcdPlcr->p_FmPcdPlcrRegs->fmpl_rrpcnt); + case (e_FM_PCD_PLCR_COUNTERS_RECOLORED_TO_YELLOW): + return GET_UINT32(p_FmPcd->p_FmPcdPlcr->p_FmPcdPlcrRegs->fmpl_rypcnt); + case (e_FM_PCD_PLCR_COUNTERS_TOTAL): + return GET_UINT32(p_FmPcd->p_FmPcdPlcr->p_FmPcdPlcrRegs->fmpl_tpcnt); + case (e_FM_PCD_PLCR_COUNTERS_LENGTH_MISMATCH): + return GET_UINT32(p_FmPcd->p_FmPcdPlcr->p_FmPcdPlcrRegs->fmpl_flmcnt); + } + return 0; +} + +t_Error FM_PCD_SetException(t_Handle h_FmPcd, e_FmPcdExceptions exception, bool enable) +{ + t_FmPcd *p_FmPcd = (t_FmPcd*)h_FmPcd; + uint32_t bitMask = 0, tmpReg; + + SANITY_CHECK_RETURN_ERROR(p_FmPcd, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(!p_FmPcd->p_FmPcdDriverParam, E_INVALID_STATE); + + if (p_FmPcd->guestId != NCSW_MASTER_ID) + RETURN_ERROR(MAJOR, E_NOT_SUPPORTED, ("FM_PCD_SetException - guest mode!")); + + GET_FM_PCD_EXCEPTION_FLAG(bitMask, exception); + + if (bitMask) + { + if (enable) + p_FmPcd->exceptions |= bitMask; + else + p_FmPcd->exceptions &= ~bitMask; + + switch (exception) + { + case (e_FM_PCD_KG_EXCEPTION_DOUBLE_ECC): + case (e_FM_PCD_KG_EXCEPTION_KEYSIZE_OVERFLOW): + if (!p_FmPcd->p_FmPcdKg) + RETURN_ERROR(MINOR, E_INVALID_STATE, ("Can't ask for this interrupt - keygen is not working")); + break; + case (e_FM_PCD_PLCR_EXCEPTION_DOUBLE_ECC): + case (e_FM_PCD_PLCR_EXCEPTION_INIT_ENTRY_ERROR): + case (e_FM_PCD_PLCR_EXCEPTION_PRAM_SELF_INIT_COMPLETE): + case (e_FM_PCD_PLCR_EXCEPTION_ATOMIC_ACTION_COMPLETE): + if (!p_FmPcd->p_FmPcdPlcr) + RETURN_ERROR(MINOR, E_INVALID_STATE, ("Can't ask for this interrupt - policer is not working")); + break; + case (e_FM_PCD_PRS_EXCEPTION_DOUBLE_ECC): + case (e_FM_PCD_PRS_EXCEPTION_SINGLE_ECC): + if (!p_FmPcd->p_FmPcdPrs) + RETURN_ERROR(MINOR, E_INVALID_STATE, ("Can't ask for this interrupt - parser is not working")); + break; + } + + switch (exception) + { + case (e_FM_PCD_KG_EXCEPTION_DOUBLE_ECC): + tmpReg = GET_UINT32(p_FmPcd->p_FmPcdKg->p_FmPcdKgRegs->fmkg_eeer); + if (enable) + tmpReg |= FM_EX_KG_DOUBLE_ECC; + else + tmpReg &= ~FM_EX_KG_DOUBLE_ECC; + WRITE_UINT32(p_FmPcd->p_FmPcdKg->p_FmPcdKgRegs->fmkg_eeer, tmpReg); + break; + case (e_FM_PCD_KG_EXCEPTION_KEYSIZE_OVERFLOW): + tmpReg = GET_UINT32(p_FmPcd->p_FmPcdKg->p_FmPcdKgRegs->fmkg_eeer); + if (enable) + tmpReg |= FM_EX_KG_KEYSIZE_OVERFLOW; + else + tmpReg &= ~FM_EX_KG_KEYSIZE_OVERFLOW; + WRITE_UINT32(p_FmPcd->p_FmPcdKg->p_FmPcdKgRegs->fmkg_eeer, tmpReg); + break; + case (e_FM_PCD_PRS_EXCEPTION_DOUBLE_ECC): + tmpReg = GET_UINT32(p_FmPcd->p_FmPcdPrs->p_FmPcdPrsRegs->fmpr_perer); + if (enable) + tmpReg |= FM_PCD_PRS_DOUBLE_ECC; + else + tmpReg &= ~FM_PCD_PRS_DOUBLE_ECC; + WRITE_UINT32(p_FmPcd->p_FmPcdPrs->p_FmPcdPrsRegs->fmpr_perer, tmpReg); + break; + case (e_FM_PCD_PRS_EXCEPTION_SINGLE_ECC): + tmpReg = GET_UINT32(p_FmPcd->p_FmPcdPrs->p_FmPcdPrsRegs->fmpr_pever); + if (enable) + tmpReg |= FM_PCD_PRS_SINGLE_ECC; + else + tmpReg &= ~FM_PCD_PRS_SINGLE_ECC; + WRITE_UINT32(p_FmPcd->p_FmPcdPrs->p_FmPcdPrsRegs->fmpr_pever, tmpReg); + break; + case (e_FM_PCD_PLCR_EXCEPTION_DOUBLE_ECC): + tmpReg = GET_UINT32(p_FmPcd->p_FmPcdPlcr->p_FmPcdPlcrRegs->fmpl_eier); + if (enable) + tmpReg |= FM_PCD_PLCR_DOUBLE_ECC; + else + tmpReg &= ~FM_PCD_PLCR_DOUBLE_ECC; + WRITE_UINT32(p_FmPcd->p_FmPcdPlcr->p_FmPcdPlcrRegs->fmpl_eier, tmpReg); + break; + case (e_FM_PCD_PLCR_EXCEPTION_INIT_ENTRY_ERROR): + tmpReg = GET_UINT32(p_FmPcd->p_FmPcdPlcr->p_FmPcdPlcrRegs->fmpl_eier); + if (enable) + tmpReg |= FM_PCD_PLCR_INIT_ENTRY_ERROR; + else + tmpReg &= ~FM_PCD_PLCR_INIT_ENTRY_ERROR; + WRITE_UINT32(p_FmPcd->p_FmPcdPlcr->p_FmPcdPlcrRegs->fmpl_eier, tmpReg); + break; + case (e_FM_PCD_PLCR_EXCEPTION_PRAM_SELF_INIT_COMPLETE): + tmpReg = GET_UINT32(p_FmPcd->p_FmPcdPlcr->p_FmPcdPlcrRegs->fmpl_ier); + if (enable) + tmpReg |= FM_PCD_PLCR_PRAM_SELF_INIT_COMPLETE; + else + tmpReg &= ~FM_PCD_PLCR_PRAM_SELF_INIT_COMPLETE; + WRITE_UINT32(p_FmPcd->p_FmPcdPlcr->p_FmPcdPlcrRegs->fmpl_ier, tmpReg); + break; + case (e_FM_PCD_PLCR_EXCEPTION_ATOMIC_ACTION_COMPLETE): + tmpReg = GET_UINT32(p_FmPcd->p_FmPcdPlcr->p_FmPcdPlcrRegs->fmpl_ier); + if (enable) + tmpReg |= FM_PCD_PLCR_ATOMIC_ACTION_COMPLETE; + else + tmpReg &= ~FM_PCD_PLCR_ATOMIC_ACTION_COMPLETE; + WRITE_UINT32(p_FmPcd->p_FmPcdPlcr->p_FmPcdPlcrRegs->fmpl_ier, tmpReg); + break; + } + /* for ECC exceptions driver automatically enables ECC mechanism, if disabled. + Driver may disable them automatically, depending on driver's status */ + if (enable && ((exception == e_FM_PCD_KG_EXCEPTION_DOUBLE_ECC) | + (exception == e_FM_PCD_PLCR_EXCEPTION_DOUBLE_ECC) | + (exception == e_FM_PCD_PRS_EXCEPTION_DOUBLE_ECC) | + (exception == e_FM_PCD_PRS_EXCEPTION_SINGLE_ECC))) + FmEnableRamsEcc(p_FmPcd->h_Fm); + if (!enable && ((exception == e_FM_PCD_KG_EXCEPTION_DOUBLE_ECC) | + (exception == e_FM_PCD_PLCR_EXCEPTION_DOUBLE_ECC) | + (exception == e_FM_PCD_PRS_EXCEPTION_DOUBLE_ECC) | + (exception == e_FM_PCD_PRS_EXCEPTION_SINGLE_ECC))) + FmDisableRamsEcc(p_FmPcd->h_Fm); + } + + return E_OK; +} + +t_Error FM_PCD_ForceIntr (t_Handle h_FmPcd, e_FmPcdExceptions exception) +{ + t_FmPcd *p_FmPcd = (t_FmPcd*)h_FmPcd; + + SANITY_CHECK_RETURN_ERROR(h_FmPcd, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(!p_FmPcd->p_FmPcdDriverParam, E_INVALID_STATE); + + if (p_FmPcd->guestId != NCSW_MASTER_ID) + RETURN_ERROR(MAJOR, E_NOT_SUPPORTED, ("FM_PCD_ForceIntr - guest mode!")); + + switch (exception) + { + case (e_FM_PCD_KG_EXCEPTION_DOUBLE_ECC): + case (e_FM_PCD_KG_EXCEPTION_KEYSIZE_OVERFLOW): + if (!p_FmPcd->p_FmPcdKg) + RETURN_ERROR(MINOR, E_INVALID_STATE, ("Can't ask for this interrupt - keygen is not working")); + break; + case (e_FM_PCD_PLCR_EXCEPTION_DOUBLE_ECC): + case (e_FM_PCD_PLCR_EXCEPTION_INIT_ENTRY_ERROR): + case (e_FM_PCD_PLCR_EXCEPTION_PRAM_SELF_INIT_COMPLETE): + case (e_FM_PCD_PLCR_EXCEPTION_ATOMIC_ACTION_COMPLETE): + if (!p_FmPcd->p_FmPcdPlcr) + RETURN_ERROR(MINOR, E_INVALID_STATE, ("Can't ask for this interrupt - policer is not working")); + break; + case (e_FM_PCD_PRS_EXCEPTION_DOUBLE_ECC): + case (e_FM_PCD_PRS_EXCEPTION_SINGLE_ECC): + if (!p_FmPcd->p_FmPcdPrs) + RETURN_ERROR(MINOR, E_INVALID_STATE, ("Can't ask for this interrupt -parsrer is not working")); + break; + default: + RETURN_ERROR(MAJOR, E_INVALID_STATE, ("Invalid interrupt requested")); + } + switch (exception) + { + case e_FM_PCD_PRS_EXCEPTION_DOUBLE_ECC: + if (!(p_FmPcd->exceptions & FM_PCD_EX_PRS_DOUBLE_ECC)) + RETURN_ERROR(MINOR, E_NOT_SUPPORTED, ("The selected exception is masked")); + break; + case e_FM_PCD_PRS_EXCEPTION_SINGLE_ECC: + if (!(p_FmPcd->exceptions & FM_PCD_EX_PRS_SINGLE_ECC)) + RETURN_ERROR(MINOR, E_NOT_SUPPORTED, ("The selected exception is masked")); + break; + case e_FM_PCD_KG_EXCEPTION_DOUBLE_ECC: + if (!(p_FmPcd->exceptions & FM_EX_KG_DOUBLE_ECC)) + RETURN_ERROR(MINOR, E_NOT_SUPPORTED, ("The selected exception is masked")); + WRITE_UINT32(p_FmPcd->p_FmPcdKg->p_FmPcdKgRegs->fmkg_feer, FM_EX_KG_DOUBLE_ECC); + break; + case e_FM_PCD_KG_EXCEPTION_KEYSIZE_OVERFLOW: + if (!(p_FmPcd->exceptions & FM_EX_KG_KEYSIZE_OVERFLOW)) + RETURN_ERROR(MINOR, E_NOT_SUPPORTED, ("The selected exception is masked")); + WRITE_UINT32(p_FmPcd->p_FmPcdKg->p_FmPcdKgRegs->fmkg_feer, FM_EX_KG_KEYSIZE_OVERFLOW); + break; + case e_FM_PCD_PLCR_EXCEPTION_DOUBLE_ECC: + if (!(p_FmPcd->exceptions & FM_PCD_EX_PLCR_DOUBLE_ECC)) + RETURN_ERROR(MINOR, E_NOT_SUPPORTED, ("The selected exception is masked")); + WRITE_UINT32(p_FmPcd->p_FmPcdPlcr->p_FmPcdPlcrRegs->fmpl_eifr, FM_PCD_PLCR_DOUBLE_ECC); + break; + case e_FM_PCD_PLCR_EXCEPTION_INIT_ENTRY_ERROR: + if (!(p_FmPcd->exceptions & FM_PCD_EX_PLCR_INIT_ENTRY_ERROR)) + RETURN_ERROR(MINOR, E_NOT_SUPPORTED, ("The selected exception is masked")); + WRITE_UINT32(p_FmPcd->p_FmPcdPlcr->p_FmPcdPlcrRegs->fmpl_eifr, FM_PCD_PLCR_INIT_ENTRY_ERROR); + break; + case e_FM_PCD_PLCR_EXCEPTION_PRAM_SELF_INIT_COMPLETE: + if (!(p_FmPcd->exceptions & FM_PCD_EX_PLCR_PRAM_SELF_INIT_COMPLETE)) + RETURN_ERROR(MINOR, E_NOT_SUPPORTED, ("The selected exception is masked")); + WRITE_UINT32(p_FmPcd->p_FmPcdPlcr->p_FmPcdPlcrRegs->fmpl_ifr, FM_PCD_PLCR_PRAM_SELF_INIT_COMPLETE); + break; + case e_FM_PCD_PLCR_EXCEPTION_ATOMIC_ACTION_COMPLETE: + if (!(p_FmPcd->exceptions & FM_PCD_EX_PLCR_ATOMIC_ACTION_COMPLETE)) + RETURN_ERROR(MINOR, E_NOT_SUPPORTED, ("The selected exception is masked")); + WRITE_UINT32(p_FmPcd->p_FmPcdPlcr->p_FmPcdPlcrRegs->fmpl_ifr, FM_PCD_PLCR_ATOMIC_ACTION_COMPLETE); + break; + } + + return E_OK; +} + + +t_Error FM_PCD_ModifyCounter(t_Handle h_FmPcd, e_FmPcdCounters counter, uint32_t value) +{ + t_FmPcd *p_FmPcd = (t_FmPcd*)h_FmPcd; + + SANITY_CHECK_RETURN_ERROR(h_FmPcd, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(!p_FmPcd->p_FmPcdDriverParam, E_INVALID_STATE); + + if (p_FmPcd->guestId != NCSW_MASTER_ID) + RETURN_ERROR(MAJOR, E_NOT_SUPPORTED, ("FM_PCD_ModifyCounter - guest mode!")); + + switch (counter) + { + case (e_FM_PCD_KG_COUNTERS_TOTAL): + if (!p_FmPcd->p_FmPcdKg) + RETURN_ERROR(MINOR, E_INVALID_STATE, ("Invalid counters - KeyGen is not working")); + break; + case (e_FM_PCD_PLCR_COUNTERS_YELLOW): + case (e_FM_PCD_PLCR_COUNTERS_RED): + case (e_FM_PCD_PLCR_COUNTERS_RECOLORED_TO_RED): + case (e_FM_PCD_PLCR_COUNTERS_RECOLORED_TO_YELLOW): + case (e_FM_PCD_PLCR_COUNTERS_TOTAL): + case (e_FM_PCD_PLCR_COUNTERS_LENGTH_MISMATCH): + if (!p_FmPcd->p_FmPcdPlcr) + RETURN_ERROR(MINOR, E_INVALID_STATE, ("Invalid counters - Policer is not working")); + if (!(GET_UINT32(p_FmPcd->p_FmPcdPlcr->p_FmPcdPlcrRegs->fmpl_gcr) & FM_PCD_PLCR_GCR_STEN)) + RETURN_ERROR(MINOR, E_INVALID_STATE, ("Requested counter was not enabled")); + break; + case (e_FM_PCD_PRS_COUNTERS_PARSE_DISPATCH): + case (e_FM_PCD_PRS_COUNTERS_L2_PARSE_RESULT_RETURNED): + case (e_FM_PCD_PRS_COUNTERS_L3_PARSE_RESULT_RETURNED): + case (e_FM_PCD_PRS_COUNTERS_L4_PARSE_RESULT_RETURNED): + case (e_FM_PCD_PRS_COUNTERS_SHIM_PARSE_RESULT_RETURNED): + case (e_FM_PCD_PRS_COUNTERS_L2_PARSE_RESULT_RETURNED_WITH_ERR): + case (e_FM_PCD_PRS_COUNTERS_L3_PARSE_RESULT_RETURNED_WITH_ERR): + case (e_FM_PCD_PRS_COUNTERS_L4_PARSE_RESULT_RETURNED_WITH_ERR): + case (e_FM_PCD_PRS_COUNTERS_SHIM_PARSE_RESULT_RETURNED_WITH_ERR): + case (e_FM_PCD_PRS_COUNTERS_SOFT_PRS_CYCLES): + case (e_FM_PCD_PRS_COUNTERS_SOFT_PRS_STALL_CYCLES): + case (e_FM_PCD_PRS_COUNTERS_HARD_PRS_CYCLE_INCL_STALL_CYCLES): + case (e_FM_PCD_PRS_COUNTERS_MURAM_READ_CYCLES): + case (e_FM_PCD_PRS_COUNTERS_MURAM_READ_STALL_CYCLES): + case (e_FM_PCD_PRS_COUNTERS_MURAM_WRITE_CYCLES): + case (e_FM_PCD_PRS_COUNTERS_MURAM_WRITE_STALL_CYCLES): + case (e_FM_PCD_PRS_COUNTERS_FPM_COMMAND_STALL_CYCLES): + if (!p_FmPcd->p_FmPcdPrs) + RETURN_ERROR(MINOR, E_INVALID_STATE, ("Unsupported type of counter")); + break; + default: + RETURN_ERROR(MINOR, E_INVALID_STATE, ("Unsupported type of counter")); + } + switch (counter) + { + case (e_FM_PCD_PRS_COUNTERS_PARSE_DISPATCH): + WRITE_UINT32(p_FmPcd->p_FmPcdPrs->p_FmPcdPrsRegs->fmpr_pds, value); + break; + case (e_FM_PCD_PRS_COUNTERS_L2_PARSE_RESULT_RETURNED): + WRITE_UINT32(p_FmPcd->p_FmPcdPrs->p_FmPcdPrsRegs->fmpr_l2rrs, value); + break; + case (e_FM_PCD_PRS_COUNTERS_L3_PARSE_RESULT_RETURNED): + WRITE_UINT32(p_FmPcd->p_FmPcdPrs->p_FmPcdPrsRegs->fmpr_l3rrs, value); + break; + case (e_FM_PCD_PRS_COUNTERS_L4_PARSE_RESULT_RETURNED): + WRITE_UINT32(p_FmPcd->p_FmPcdPrs->p_FmPcdPrsRegs->fmpr_l4rrs, value); + break; + case (e_FM_PCD_PRS_COUNTERS_SHIM_PARSE_RESULT_RETURNED): + WRITE_UINT32(p_FmPcd->p_FmPcdPrs->p_FmPcdPrsRegs->fmpr_srrs, value); + break; + case (e_FM_PCD_PRS_COUNTERS_L2_PARSE_RESULT_RETURNED_WITH_ERR): + WRITE_UINT32(p_FmPcd->p_FmPcdPrs->p_FmPcdPrsRegs->fmpr_l2rres, value); + break; + case (e_FM_PCD_PRS_COUNTERS_L3_PARSE_RESULT_RETURNED_WITH_ERR): + WRITE_UINT32(p_FmPcd->p_FmPcdPrs->p_FmPcdPrsRegs->fmpr_l3rres, value); + break; + case (e_FM_PCD_PRS_COUNTERS_L4_PARSE_RESULT_RETURNED_WITH_ERR): + WRITE_UINT32(p_FmPcd->p_FmPcdPrs->p_FmPcdPrsRegs->fmpr_l4rres, value); + break; + case (e_FM_PCD_PRS_COUNTERS_SHIM_PARSE_RESULT_RETURNED_WITH_ERR): + WRITE_UINT32(p_FmPcd->p_FmPcdPrs->p_FmPcdPrsRegs->fmpr_srres, value); + break; + case (e_FM_PCD_PRS_COUNTERS_SOFT_PRS_CYCLES): + WRITE_UINT32(p_FmPcd->p_FmPcdPrs->p_FmPcdPrsRegs->fmpr_spcs, value); + break; + case (e_FM_PCD_PRS_COUNTERS_SOFT_PRS_STALL_CYCLES): + WRITE_UINT32(p_FmPcd->p_FmPcdPrs->p_FmPcdPrsRegs->fmpr_spscs, value); + break; + case (e_FM_PCD_PRS_COUNTERS_HARD_PRS_CYCLE_INCL_STALL_CYCLES): + WRITE_UINT32(p_FmPcd->p_FmPcdPrs->p_FmPcdPrsRegs->fmpr_hxscs, value); + break; + case (e_FM_PCD_PRS_COUNTERS_MURAM_READ_CYCLES): + WRITE_UINT32(p_FmPcd->p_FmPcdPrs->p_FmPcdPrsRegs->fmpr_mrcs, value); + break; + case (e_FM_PCD_PRS_COUNTERS_MURAM_READ_STALL_CYCLES): + WRITE_UINT32(p_FmPcd->p_FmPcdPrs->p_FmPcdPrsRegs->fmpr_mrscs, value); + break; + case (e_FM_PCD_PRS_COUNTERS_MURAM_WRITE_CYCLES): + WRITE_UINT32(p_FmPcd->p_FmPcdPrs->p_FmPcdPrsRegs->fmpr_mwcs, value); + break; + case (e_FM_PCD_PRS_COUNTERS_MURAM_WRITE_STALL_CYCLES): + WRITE_UINT32(p_FmPcd->p_FmPcdPrs->p_FmPcdPrsRegs->fmpr_mwscs, value); + break; + case (e_FM_PCD_PRS_COUNTERS_FPM_COMMAND_STALL_CYCLES): + WRITE_UINT32(p_FmPcd->p_FmPcdPrs->p_FmPcdPrsRegs->fmpr_fcscs, value); + break; + case (e_FM_PCD_KG_COUNTERS_TOTAL): + WRITE_UINT32(p_FmPcd->p_FmPcdKg->p_FmPcdKgRegs->fmkg_tpc,value); + break; + + /*Policer counters*/ + case (e_FM_PCD_PLCR_COUNTERS_YELLOW): + WRITE_UINT32(p_FmPcd->p_FmPcdPlcr->p_FmPcdPlcrRegs->fmpl_ypcnt, value); + break; + case (e_FM_PCD_PLCR_COUNTERS_RED): + WRITE_UINT32(p_FmPcd->p_FmPcdPlcr->p_FmPcdPlcrRegs->fmpl_rpcnt, value); + break; + case (e_FM_PCD_PLCR_COUNTERS_RECOLORED_TO_RED): + WRITE_UINT32(p_FmPcd->p_FmPcdPlcr->p_FmPcdPlcrRegs->fmpl_rrpcnt, value); + break; + case (e_FM_PCD_PLCR_COUNTERS_RECOLORED_TO_YELLOW): + WRITE_UINT32(p_FmPcd->p_FmPcdPlcr->p_FmPcdPlcrRegs->fmpl_rypcnt, value); + break; + case (e_FM_PCD_PLCR_COUNTERS_TOTAL): + WRITE_UINT32(p_FmPcd->p_FmPcdPlcr->p_FmPcdPlcrRegs->fmpl_tpcnt, value); + break; + case (e_FM_PCD_PLCR_COUNTERS_LENGTH_MISMATCH): + WRITE_UINT32(p_FmPcd->p_FmPcdPlcr->p_FmPcdPlcrRegs->fmpl_flmcnt, value); + break; + } + + return E_OK; +} + +t_Handle FM_PCD_GetHcPort(t_Handle h_FmPcd) +{ + t_FmPcd *p_FmPcd = (t_FmPcd*)h_FmPcd; + return FmHcGetPort(p_FmPcd->h_Hc); +} + diff --git a/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Pcd/fm_pcd.h b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Pcd/fm_pcd.h new file mode 100644 index 000000000000..27ec9c5bf672 --- /dev/null +++ b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Pcd/fm_pcd.h @@ -0,0 +1,543 @@ +/* + * Copyright 2008-2012 Freescale Semiconductor Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Freescale Semiconductor nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * + * ALTERNATIVELY, this software may be distributed under the terms of the + * GNU General Public License ("GPL") as published by the Free Software + * Foundation, either version 2 of that License or (at your option) any + * later version. + * + * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + +/****************************************************************************** + @File fm_pcd.h + + @Description FM PCD ... +*//***************************************************************************/ +#ifndef __FM_PCD_H +#define __FM_PCD_H + +#include "std_ext.h" +#include "error_ext.h" +#include "list_ext.h" +#include "fm_pcd_ext.h" +#include "fm_common.h" +#include "fsl_fman_prs.h" +#include "fsl_fman_kg.h" + +#define __ERR_MODULE__ MODULE_FM_PCD + + +/****************************/ +/* Defaults */ +/****************************/ +#define DEFAULT_plcrAutoRefresh FALSE +#define DEFAULT_fmPcdKgErrorExceptions (FM_EX_KG_DOUBLE_ECC | FM_EX_KG_KEYSIZE_OVERFLOW) +#define DEFAULT_fmPcdPlcrErrorExceptions (FM_PCD_EX_PLCR_DOUBLE_ECC | FM_PCD_EX_PLCR_INIT_ENTRY_ERROR) +#define DEFAULT_fmPcdPlcrExceptions 0 +#define DEFAULT_fmPcdPrsErrorExceptions (FM_PCD_EX_PRS_DOUBLE_ECC) + +#define DEFAULT_fmPcdPrsExceptions FM_PCD_EX_PRS_SINGLE_ECC +#define DEFAULT_numOfUsedProfilesPerWindow 16 +#define DEFAULT_numOfSharedPlcrProfiles 4 + +/****************************/ +/* Network defines */ +/****************************/ +#define UDP_HEADER_SIZE 8 + +#define ESP_SPI_OFFSET 0 +#define ESP_SPI_SIZE 4 +#define ESP_SEQ_NUM_OFFSET ESP_SPI_SIZE +#define ESP_SEQ_NUM_SIZE 4 + +/****************************/ +/* General defines */ +/****************************/ +#define ILLEGAL_CLS_PLAN 0xff +#define ILLEGAL_NETENV 0xff + +#define FM_PCD_MAX_NUM_OF_ALIAS_HDRS 3 + +/****************************/ +/* Error defines */ +/****************************/ + +#define FM_PCD_EX_PLCR_DOUBLE_ECC 0x20000000 +#define FM_PCD_EX_PLCR_INIT_ENTRY_ERROR 0x10000000 +#define FM_PCD_EX_PLCR_PRAM_SELF_INIT_COMPLETE 0x08000000 +#define FM_PCD_EX_PLCR_ATOMIC_ACTION_COMPLETE 0x04000000 + +#define GET_FM_PCD_EXCEPTION_FLAG(bitMask, exception) \ +switch (exception){ \ + case e_FM_PCD_KG_EXCEPTION_DOUBLE_ECC: \ + bitMask = FM_EX_KG_DOUBLE_ECC; break; \ + case e_FM_PCD_PLCR_EXCEPTION_DOUBLE_ECC: \ + bitMask = FM_PCD_EX_PLCR_DOUBLE_ECC; break; \ + case e_FM_PCD_KG_EXCEPTION_KEYSIZE_OVERFLOW: \ + bitMask = FM_EX_KG_KEYSIZE_OVERFLOW; break; \ + case e_FM_PCD_PLCR_EXCEPTION_INIT_ENTRY_ERROR: \ + bitMask = FM_PCD_EX_PLCR_INIT_ENTRY_ERROR; break; \ + case e_FM_PCD_PLCR_EXCEPTION_PRAM_SELF_INIT_COMPLETE: \ + bitMask = FM_PCD_EX_PLCR_PRAM_SELF_INIT_COMPLETE; break; \ + case e_FM_PCD_PLCR_EXCEPTION_ATOMIC_ACTION_COMPLETE: \ + bitMask = FM_PCD_EX_PLCR_ATOMIC_ACTION_COMPLETE; break; \ + case e_FM_PCD_PRS_EXCEPTION_DOUBLE_ECC: \ + bitMask = FM_PCD_EX_PRS_DOUBLE_ECC; break; \ + case e_FM_PCD_PRS_EXCEPTION_SINGLE_ECC: \ + bitMask = FM_PCD_EX_PRS_SINGLE_ECC; break; \ + default: bitMask = 0;break;} + +/***********************************************************************/ +/* Policer defines */ +/***********************************************************************/ +#define FM_PCD_PLCR_GCR_STEN 0x40000000 +#define FM_PCD_PLCR_DOUBLE_ECC 0x80000000 +#define FM_PCD_PLCR_INIT_ENTRY_ERROR 0x40000000 +#define FM_PCD_PLCR_PRAM_SELF_INIT_COMPLETE 0x80000000 +#define FM_PCD_PLCR_ATOMIC_ACTION_COMPLETE 0x40000000 + +/***********************************************************************/ +/* Memory map */ +/***********************************************************************/ +#if defined(__MWERKS__) && !defined(__GNUC__) +#pragma pack(push,1) +#endif /* defined(__MWERKS__) && ... */ + + +typedef struct { +/* General Configuration and Status Registers */ + volatile uint32_t fmpl_gcr; /* 0x000 FMPL_GCR - FM Policer General Configuration */ + volatile uint32_t fmpl_gsr; /* 0x004 FMPL_GSR - FM Policer Global Status Register */ + volatile uint32_t fmpl_evr; /* 0x008 FMPL_EVR - FM Policer Event Register */ + volatile uint32_t fmpl_ier; /* 0x00C FMPL_IER - FM Policer Interrupt Enable Register */ + volatile uint32_t fmpl_ifr; /* 0x010 FMPL_IFR - FM Policer Interrupt Force Register */ + volatile uint32_t fmpl_eevr; /* 0x014 FMPL_EEVR - FM Policer Error Event Register */ + volatile uint32_t fmpl_eier; /* 0x018 FMPL_EIER - FM Policer Error Interrupt Enable Register */ + volatile uint32_t fmpl_eifr; /* 0x01C FMPL_EIFR - FM Policer Error Interrupt Force Register */ +/* Global Statistic Counters */ + volatile uint32_t fmpl_rpcnt; /* 0x020 FMPL_RPC - FM Policer RED Packets Counter */ + volatile uint32_t fmpl_ypcnt; /* 0x024 FMPL_YPC - FM Policer YELLOW Packets Counter */ + volatile uint32_t fmpl_rrpcnt; /* 0x028 FMPL_RRPC - FM Policer Recolored RED Packet Counter */ + volatile uint32_t fmpl_rypcnt; /* 0x02C FMPL_RYPC - FM Policer Recolored YELLOW Packet Counter */ + volatile uint32_t fmpl_tpcnt; /* 0x030 FMPL_TPC - FM Policer Total Packet Counter */ + volatile uint32_t fmpl_flmcnt; /* 0x034 FMPL_FLMC - FM Policer Frame Length Mismatch Counter */ + volatile uint32_t fmpl_res0[21]; /* 0x038 - 0x08B Reserved */ +/* Profile RAM Access Registers */ + volatile uint32_t fmpl_par; /* 0x08C FMPL_PAR - FM Policer Profile Action Register*/ + t_FmPcdPlcrProfileRegs profileRegs; +/* Error Capture Registers */ + volatile uint32_t fmpl_serc; /* 0x100 FMPL_SERC - FM Policer Soft Error Capture */ + volatile uint32_t fmpl_upcr; /* 0x104 FMPL_UPCR - FM Policer Uninitialized Profile Capture Register */ + volatile uint32_t fmpl_res2; /* 0x108 Reserved */ +/* Debug Registers */ + volatile uint32_t fmpl_res3[61]; /* 0x10C-0x200 Reserved Debug*/ +/* Profile Selection Mapping Registers Per Port-ID (n=1-11, 16) */ + volatile uint32_t fmpl_dpmr; /* 0x200 FMPL_DPMR - FM Policer Default Mapping Register */ + volatile uint32_t fmpl_pmr[63]; /*+default 0x204-0x2FF FMPL_PMR1 - FMPL_PMR63, - FM Policer Profile Mapping Registers. + (for port-ID 1-11, only for supported Port-ID registers) */ +} t_FmPcdPlcrRegs; + +#if defined(__MWERKS__) && !defined(__GNUC__) +#pragma pack(pop) +#endif /* defined(__MWERKS__) && ... */ + + +/***********************************************************************/ +/* Driver's internal structures */ +/***********************************************************************/ + +typedef struct { + bool known; + uint8_t id; +} t_FmPcdKgSchemesExtractsEntry; + +typedef struct { + t_FmPcdKgSchemesExtractsEntry extractsArray[FM_PCD_KG_MAX_NUM_OF_EXTRACTS_PER_KEY]; +} t_FmPcdKgSchemesExtracts; + +typedef struct { + t_Handle h_Manip; + bool keepRes; + e_FmPcdEngine nextEngine; + uint8_t parseCode; +} t_FmPcdInfoForManip; + +/**************************************************************************//** + @Description A structure of parameters to communicate + between the port and PCD regarding the KG scheme. +*//***************************************************************************/ +typedef struct { + uint8_t netEnvId; /* in */ + uint8_t numOfDistinctionUnits; /* in */ + uint8_t unitIds[FM_PCD_MAX_NUM_OF_DISTINCTION_UNITS]; /* in */ + uint32_t vector; /* out */ +} t_NetEnvParams; + +typedef struct { + bool allocated; + uint8_t ownerId; /* guestId for KG in multi-partition only. + portId for PLCR in any environment */ +} t_FmPcdAllocMng; + +typedef struct { + volatile bool lock; + bool used; + uint8_t owners; + uint8_t netEnvId; + uint8_t guestId; + uint8_t baseEntry; + uint16_t sizeOfGrp; + protocolOpt_t optArray[FM_PCD_MAX_NUM_OF_OPTIONS(FM_PCD_MAX_NUM_OF_CLS_PLANS)]; +} t_FmPcdKgClsPlanGrp; + +typedef struct { + t_Handle h_FmPcd; + uint8_t schemeId; + t_FmPcdLock *p_Lock; + bool valid; + uint8_t netEnvId; + uint8_t owners; + uint32_t matchVector; + uint32_t ccUnits; + bool nextRelativePlcrProfile; + uint16_t relativeProfileId; + uint16_t numOfProfiles; + t_FmPcdKgKeyOrder orderedArray; + e_FmPcdEngine nextEngine; + e_FmPcdDoneAction doneAction; + bool requiredActionFlag; + uint32_t requiredAction; + bool extractedOrs; + uint8_t bitOffsetInPlcrProfile; + bool directPlcr; +#if (DPAA_VERSION >= 11) + bool vspe; +#endif +} t_FmPcdKgScheme; + +typedef union { + struct fman_kg_scheme_regs schemeRegs; + struct fman_kg_pe_regs portRegs; + struct fman_kg_cp_regs clsPlanRegs; +} u_FmPcdKgIndirectAccessRegs; + +typedef struct { + struct fman_kg_regs *p_FmPcdKgRegs; + uint32_t schemeExceptionsBitMask; + uint8_t numOfSchemes; + t_Handle h_HwSpinlock; + uint8_t schemesIds[FM_PCD_KG_NUM_OF_SCHEMES]; + t_FmPcdKgScheme schemes[FM_PCD_KG_NUM_OF_SCHEMES]; + t_FmPcdKgClsPlanGrp clsPlanGrps[FM_MAX_NUM_OF_PORTS]; + uint8_t emptyClsPlanGrpId; + t_FmPcdAllocMng schemesMng[FM_PCD_KG_NUM_OF_SCHEMES]; /* only for MASTER ! */ + t_FmPcdAllocMng clsPlanBlocksMng[FM_PCD_MAX_NUM_OF_CLS_PLANS/CLS_PLAN_NUM_PER_GRP]; + u_FmPcdKgIndirectAccessRegs *p_IndirectAccessRegs; +} t_FmPcdKg; + +typedef struct { + uint16_t profilesBase; + uint16_t numOfProfiles; + t_Handle h_FmPort; +} t_FmPcdPlcrMapParam; + +typedef struct { + uint16_t absoluteProfileId; + t_Handle h_FmPcd; + bool valid; + t_FmPcdLock *p_Lock; + t_FmPcdAllocMng profilesMng; + bool requiredActionFlag; + uint32_t requiredAction; + e_FmPcdEngine nextEngineOnGreen; /**< Green next engine type */ + u_FmPcdPlcrNextEngineParams paramsOnGreen; /**< Green next engine params */ + + e_FmPcdEngine nextEngineOnYellow; /**< Yellow next engine type */ + u_FmPcdPlcrNextEngineParams paramsOnYellow; /**< Yellow next engine params */ + + e_FmPcdEngine nextEngineOnRed; /**< Red next engine type */ + u_FmPcdPlcrNextEngineParams paramsOnRed; /**< Red next engine params */ +} t_FmPcdPlcrProfile; + +typedef struct { + t_FmPcdPlcrRegs *p_FmPcdPlcrRegs; + uint16_t partPlcrProfilesBase; + uint16_t partNumOfPlcrProfiles; + t_FmPcdPlcrProfile profiles[FM_PCD_PLCR_NUM_ENTRIES]; + uint16_t numOfSharedProfiles; + uint16_t sharedProfilesIds[FM_PCD_PLCR_NUM_ENTRIES]; + t_FmPcdPlcrMapParam portsMapping[FM_MAX_NUM_OF_PORTS]; + t_Handle h_HwSpinlock; + t_Handle h_SwSpinlock; +} t_FmPcdPlcr; + +typedef struct { + uint32_t *p_SwPrsCode; + uint32_t *p_CurrSwPrs; + uint8_t currLabel; + struct fman_prs_regs *p_FmPcdPrsRegs; + t_FmPcdPrsLabelParams labelsTable[FM_PCD_PRS_NUM_OF_LABELS]; + uint32_t fmPcdPrsPortIdStatistics; +} t_FmPcdPrs; + +typedef struct { + struct { + e_NetHeaderType hdr; + protocolOpt_t opt; /* only one option !! */ + } hdrs[FM_PCD_MAX_NUM_OF_INTERCHANGEABLE_HDRS]; +} t_FmPcdIntDistinctionUnit; + +typedef struct { + e_NetHeaderType hdr; + protocolOpt_t opt; /* only one option !! */ + e_NetHeaderType aliasHdr; +} t_FmPcdNetEnvAliases; + +typedef struct { + uint8_t netEnvId; + t_Handle h_FmPcd; + t_Handle h_Spinlock; + bool used; + uint8_t owners; + uint8_t clsPlanGrpId; + t_FmPcdIntDistinctionUnit units[FM_PCD_MAX_NUM_OF_DISTINCTION_UNITS]; + uint32_t unitsVectors[FM_PCD_MAX_NUM_OF_DISTINCTION_UNITS]; + uint32_t lcvs[FM_PCD_PRS_NUM_OF_HDRS]; + uint32_t macsecVector; + t_FmPcdNetEnvAliases aliasHdrs[FM_PCD_MAX_NUM_OF_ALIAS_HDRS]; +} t_FmPcdNetEnv; + +typedef struct { + struct fman_prs_cfg dfltCfg; + bool plcrAutoRefresh; + uint16_t prsMaxParseCycleLimit; +} t_FmPcdDriverParam; + +typedef struct { + t_Handle h_Fm; + t_Handle h_FmMuram; + t_FmRevisionInfo fmRevInfo; + + uint64_t physicalMuramBase; + + t_Handle h_Spinlock; + t_List freeLocksLst; + t_List acquiredLocksLst; + + t_Handle h_IpcSession; /* relevant for guest only */ + bool enabled; + uint8_t guestId; /**< Guest Partition Id */ + uint8_t numOfEnabledGuestPartitionsPcds; + char fmPcdModuleName[MODULE_NAME_SIZE]; + char fmPcdIpcHandlerModuleName[MODULE_NAME_SIZE]; /* relevant for guest only - this is the master's name */ + t_FmPcdNetEnv netEnvs[FM_MAX_NUM_OF_PORTS]; + t_FmPcdKg *p_FmPcdKg; + t_FmPcdPlcr *p_FmPcdPlcr; + t_FmPcdPrs *p_FmPcdPrs; + + void *p_CcShadow; /**< CC MURAM shadow */ + uint32_t ccShadowSize; + uint32_t ccShadowAlign; + volatile bool shadowLock; + t_Handle h_ShadowSpinlock; + + t_Handle h_Hc; + + uint32_t exceptions; + t_FmPcdExceptionCallback *f_Exception; + t_FmPcdIdExceptionCallback *f_FmPcdIndexedException; + t_Handle h_App; + uintptr_t ipv6FrameIdAddr; + uintptr_t capwapFrameIdAddr; + bool advancedOffloadSupport; + + t_FmPcdDriverParam *p_FmPcdDriverParam; +} t_FmPcd; + +#if (DPAA_VERSION >= 11) +typedef uint8_t t_FmPcdFrmReplicUpdateType; +#define FRM_REPLIC_UPDATE_COUNTER 0x01 +#define FRM_REPLIC_UPDATE_INFO 0x02 +#endif /* (DPAA_VERSION >= 11) */ +/***********************************************************************/ +/* PCD internal routines */ +/***********************************************************************/ + +t_Error PcdGetVectorForOpt(t_FmPcd *p_FmPcd, uint8_t netEnvId, protocolOpt_t opt, uint32_t *p_Vector); +t_Error PcdGetUnitsVector(t_FmPcd *p_FmPcd, t_NetEnvParams *p_Params); +bool PcdNetEnvIsUnitWithoutOpts(t_FmPcd *p_FmPcd, uint8_t netEnvId, uint32_t unitVector); +t_Error PcdGetClsPlanGrpParams(t_FmPcd *p_FmPcd, t_FmPcdKgInterModuleClsPlanGrpParams *p_GrpParams); +void FmPcdSetClsPlanGrpId(t_FmPcd *p_FmPcd, uint8_t netEnvId, uint8_t clsPlanGrpId); +e_NetHeaderType FmPcdGetAliasHdr(t_FmPcd *p_FmPcd, uint8_t netEnvId, e_NetHeaderType hdr); +uint8_t FmPcdNetEnvGetUnitIdForSingleHdr(t_FmPcd *p_FmPcd, uint8_t netEnvId, e_NetHeaderType hdr); +uint8_t FmPcdNetEnvGetUnitId(t_FmPcd *p_FmPcd, uint8_t netEnvId, e_NetHeaderType hdr, bool interchangeable, protocolOpt_t opt); + +t_Error FmPcdManipBuildIpReassmScheme(t_FmPcd *p_FmPcd, t_Handle h_NetEnv, t_Handle h_CcTree, t_Handle h_Manip, bool isIpv4, uint8_t groupId); +t_Error FmPcdManipDeleteIpReassmSchemes(t_Handle h_Manip); +t_Error FmPcdManipBuildCapwapReassmScheme(t_FmPcd *p_FmPcd, t_Handle h_NetEnv, t_Handle h_CcTree, t_Handle h_Manip, uint8_t groupId); +t_Error FmPcdManipDeleteCapwapReassmSchemes(t_Handle h_Manip); +bool FmPcdManipIpReassmIsIpv6Hdr(t_Handle h_Manip); + +t_Handle KgConfig( t_FmPcd *p_FmPcd, t_FmPcdParams *p_FmPcdParams); +t_Error KgInit(t_FmPcd *p_FmPcd); +t_Error KgFree(t_FmPcd *p_FmPcd); +void KgSetClsPlan(t_Handle h_FmPcd, t_FmPcdKgInterModuleClsPlanSet *p_Set); +bool KgIsSchemeAlwaysDirect(t_Handle h_FmPcd, uint8_t schemeId); +void KgEnable(t_FmPcd *p_FmPcd); +void KgDisable(t_FmPcd *p_FmPcd); +t_Error KgAllocClsPlanEntries(t_Handle h_FmPcd, uint16_t numOfClsPlanEntries, uint8_t guestId, uint8_t *p_First); +void KgFreeClsPlanEntries(t_Handle h_FmPcd, uint16_t numOfClsPlanEntries, uint8_t guestId, uint8_t base); + +/* only for MULTI partittion */ +t_Error FmPcdKgAllocSchemes(t_Handle h_FmPcd, uint8_t numOfSchemes, uint8_t guestId, uint8_t *p_SchemesIds); +t_Error FmPcdKgFreeSchemes(t_Handle h_FmPcd, uint8_t numOfSchemes, uint8_t guestId, uint8_t *p_SchemesIds); +/* only for SINGLE partittion */ +t_Error KgBindPortToSchemes(t_Handle h_FmPcd , uint8_t hardwarePortId, uint32_t spReg); + +t_FmPcdLock *FmPcdAcquireLock(t_Handle h_FmPcd); +void FmPcdReleaseLock(t_Handle h_FmPcd, t_FmPcdLock *p_Lock); + +t_Handle PlcrConfig(t_FmPcd *p_FmPcd, t_FmPcdParams *p_FmPcdParams); +t_Error PlcrInit(t_FmPcd *p_FmPcd); +t_Error PlcrFree(t_FmPcd *p_FmPcd); +void PlcrEnable(t_FmPcd *p_FmPcd); +void PlcrDisable(t_FmPcd *p_FmPcd); +uint16_t PlcrAllocProfilesForPartition(t_FmPcd *p_FmPcd, uint16_t base, uint16_t numOfProfiles, uint8_t guestId); +void PlcrFreeProfilesForPartition(t_FmPcd *p_FmPcd, uint16_t base, uint16_t numOfProfiles, uint8_t guestId); +t_Error PlcrSetPortProfiles(t_FmPcd *p_FmPcd, + uint8_t hardwarePortId, + uint16_t numOfProfiles, + uint16_t base); +t_Error PlcrClearPortProfiles(t_FmPcd *p_FmPcd, uint8_t hardwarePortId); + +t_Handle PrsConfig(t_FmPcd *p_FmPcd,t_FmPcdParams *p_FmPcdParams); +t_Error PrsInit(t_FmPcd *p_FmPcd); +void PrsEnable(t_FmPcd *p_FmPcd); +void PrsDisable(t_FmPcd *p_FmPcd); +void PrsFree(t_FmPcd *p_FmPcd ); +t_Error PrsIncludePortInStatistics(t_FmPcd *p_FmPcd, uint8_t hardwarePortId, bool include); + +t_Error FmPcdCcGetGrpParams(t_Handle treeId, uint8_t grpId, uint32_t *p_GrpBits, uint8_t *p_GrpBase); +uint8_t FmPcdCcGetOffset(t_Handle h_CcNode); +uint8_t FmPcdCcGetParseCode(t_Handle h_CcNode); +uint16_t FmPcdCcGetNumOfKeys(t_Handle h_CcNode); +t_Error ValidateNextEngineParams(t_Handle h_FmPcd, t_FmPcdCcNextEngineParams *p_FmPcdCcNextEngineParams, e_FmPcdCcStatsMode supportedStatsMode); + +void FmPcdManipUpdateOwner(t_Handle h_Manip, bool add); +t_Error FmPcdManipCheckParamsForCcNextEngine(t_FmPcdCcNextEngineParams *p_InfoForManip, uint32_t *requiredAction); +void FmPcdManipUpdateAdResultForCc(t_Handle h_Manip, + t_FmPcdCcNextEngineParams *p_CcNextEngineParams, + t_Handle p_Ad, + t_Handle *p_AdNewPtr); +void FmPcdManipUpdateAdContLookupForCc(t_Handle h_Manip, t_Handle p_Ad, t_Handle *p_AdNew, uint32_t adTableOffset); +void FmPcdManipUpdateOwner(t_Handle h_Manip, bool add); +t_Error FmPcdManipCheckParamsWithCcNodeParams(t_Handle h_Manip, t_Handle h_FmPcdCcNode); +#ifdef FM_CAPWAP_SUPPORT +t_Handle FmPcdManipApplSpecificBuild(void); +bool FmPcdManipIsCapwapApplSpecific(t_Handle h_Manip); +#endif /* FM_CAPWAP_SUPPORT */ +#if (DPAA_VERSION >= 11) +void * FrmReplicGroupGetSourceTableDescriptor(t_Handle h_ReplicGroup); +void FrmReplicGroupUpdateOwner(t_Handle h_ReplicGroup, bool add); +void FrmReplicGroupUpdateAd(t_Handle h_ReplicGroup, void *p_Ad, t_Handle *h_AdNew); + +void FmPcdCcGetAdTablesThatPointOnReplicGroup(t_Handle h_Node, + t_Handle h_ReplicGroup, + t_List *p_AdTables, + uint32_t *p_NumOfAdTables); +#endif /* (DPAA_VERSION >= 11) */ + +void EnqueueNodeInfoToRelevantLst(t_List *p_List, t_CcNodeInformation *p_CcInfo, t_Handle h_Spinlock); +void DequeueNodeInfoFromRelevantLst(t_List *p_List, t_Handle h_Info, t_Handle h_Spinlock); +t_CcNodeInformation* FindNodeInfoInReleventLst(t_List *p_List, t_Handle h_Info, t_Handle h_Spinlock); +t_List *FmPcdManipGetSpinlock(t_Handle h_Manip); +t_List *FmPcdManipGetNodeLstPointedOnThisManip(t_Handle h_Manip); + +typedef struct +{ + t_Handle h_StatsAd; + t_Handle h_StatsCounters; +#if (DPAA_VERSION >= 11) + t_Handle h_StatsFLRs; +#endif /* (DPAA_VERSION >= 11) */ +} t_FmPcdCcStatsParams; + +void NextStepAd(t_Handle h_Ad, + t_FmPcdCcStatsParams *p_FmPcdCcStatsParams, + t_FmPcdCcNextEngineParams *p_FmPcdCcNextEngineParams, + t_FmPcd *p_FmPcd); +void ReleaseLst(t_List *p_List); + +static __inline__ t_Handle FmPcdGetMuramHandle(t_Handle h_FmPcd) +{ + t_FmPcd *p_FmPcd = (t_FmPcd*)h_FmPcd; + ASSERT_COND(p_FmPcd); + return p_FmPcd->h_FmMuram; +} + +static __inline__ uint64_t FmPcdGetMuramPhysBase(t_Handle h_FmPcd) +{ + t_FmPcd *p_FmPcd = (t_FmPcd*)h_FmPcd; + ASSERT_COND(p_FmPcd); + return p_FmPcd->physicalMuramBase; +} + +static __inline__ uint32_t FmPcdLockSpinlock(t_FmPcdLock *p_Lock) +{ + ASSERT_COND(p_Lock); + return XX_LockIntrSpinlock(p_Lock->h_Spinlock); +} + +static __inline__ void FmPcdUnlockSpinlock(t_FmPcdLock *p_Lock, uint32_t flags) +{ + ASSERT_COND(p_Lock); + XX_UnlockIntrSpinlock(p_Lock->h_Spinlock, flags); +} + +static __inline__ bool FmPcdLockTryLock(t_FmPcdLock *p_Lock) +{ + uint32_t intFlags; + + ASSERT_COND(p_Lock); + intFlags = XX_LockIntrSpinlock(p_Lock->h_Spinlock); + if (p_Lock->flag) + { + XX_UnlockIntrSpinlock(p_Lock->h_Spinlock, intFlags); + return FALSE; + } + p_Lock->flag = TRUE; + XX_UnlockIntrSpinlock(p_Lock->h_Spinlock, intFlags); + return TRUE; +} + +static __inline__ void FmPcdLockUnlock(t_FmPcdLock *p_Lock) +{ + ASSERT_COND(p_Lock); + p_Lock->flag = FALSE; +} + + +#endif /* __FM_PCD_H */ diff --git a/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Pcd/fm_pcd_ipc.h b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Pcd/fm_pcd_ipc.h new file mode 100644 index 000000000000..325d3e335f02 --- /dev/null +++ b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Pcd/fm_pcd_ipc.h @@ -0,0 +1,280 @@ +/* + * Copyright 2008-2012 Freescale Semiconductor Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Freescale Semiconductor nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * + * ALTERNATIVELY, this software may be distributed under the terms of the + * GNU General Public License ("GPL") as published by the Free Software + * Foundation, either version 2 of that License or (at your option) any + * later version. + * + * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + +/**************************************************************************//** + @File fm_pcd_ipc.h + + @Description FM PCD Inter-Partition prototypes, structures and definitions. +*//***************************************************************************/ +#ifndef __FM_PCD_IPC_H +#define __FM_PCD_IPC_H + +#include "std_ext.h" + + +/**************************************************************************//** + @Group FM_grp Frame Manager API + + @Description FM API functions, definitions and enums + + @{ +*//***************************************************************************/ + + +#if defined(__MWERKS__) && !defined(__GNUC__) +#pragma pack(push,1) +#endif /* defined(__MWERKS__) && ... */ + +/**************************************************************************//** + @Description Structure for getting a sw parser address according to a label + Fields commented 'IN' are passed by the port module to be used + by the FM module. + Fields commented 'OUT' will be filled by FM before returning to port. +*//***************************************************************************/ +typedef _Packed struct t_FmPcdIpcSwPrsLable +{ + uint32_t enumHdr; /**< IN. The existence of this header will invoke + the sw parser code. */ + uint8_t indexPerHdr; /**< IN. Normally 0, if more than one sw parser + attachments for the same header, use this + + index to distinguish between them. */ +} _PackedType t_FmPcdIpcSwPrsLable; + +/**************************************************************************//** + @Description Structure for port-PCD communication. + Fields commented 'IN' are passed by the port module to be used + by the FM module. + Fields commented 'OUT' will be filled by FM before returning to port. + Some fields are optional (depending on configuration) and + will be analized by the port and FM modules accordingly. +*//***************************************************************************/ + +typedef struct t_FmPcdIpcKgSchemesParams +{ + uint8_t guestId; + uint8_t numOfSchemes; + uint8_t schemesIds[FM_PCD_KG_NUM_OF_SCHEMES]; +} _PackedType t_FmPcdIpcKgSchemesParams; + +typedef struct t_FmPcdIpcKgClsPlanParams +{ + uint8_t guestId; + uint16_t numOfClsPlanEntries; + uint8_t clsPlanBase; +} _PackedType t_FmPcdIpcKgClsPlanParams; + +typedef _Packed struct t_FmPcdIpcPrsIncludePort +{ + uint8_t hardwarePortId; + bool include; +} _PackedType t_FmPcdIpcPrsIncludePort; + + +#define FM_PCD_MAX_REPLY_SIZE 16 +#define FM_PCD_MAX_MSG_SIZE 36 +#define FM_PCD_MAX_REPLY_BODY_SIZE 36 + +typedef _Packed struct { + uint32_t msgId; + uint8_t msgBody[FM_PCD_MAX_MSG_SIZE]; +} _PackedType t_FmPcdIpcMsg; + +typedef _Packed struct t_FmPcdIpcReply { + uint32_t error; + uint8_t replyBody[FM_PCD_MAX_REPLY_BODY_SIZE]; +} _PackedType t_FmPcdIpcReply; + +typedef _Packed struct t_FmIpcResourceAllocParams { + uint8_t guestId; + uint16_t base; + uint16_t num; +}_PackedType t_FmIpcResourceAllocParams; + +#if defined(__MWERKS__) && !defined(__GNUC__) +#pragma pack(pop) +#endif /* defined(__MWERKS__) && ... */ + + + +/**************************************************************************//** + @Function FM_PCD_ALLOC_KG_SCHEMES + + @Description Used by FM PCD front-end in order to allocate KG resources + + @Param[in/out] t_FmPcdIpcKgAllocParams Pointer +*//***************************************************************************/ +#define FM_PCD_ALLOC_KG_SCHEMES 3 + +/**************************************************************************//** + @Function FM_PCD_FREE_KG_SCHEMES + + @Description Used by FM PCD front-end in order to Free KG resources + + @Param[in/out] t_FmPcdIpcKgSchemesParams Pointer +*//***************************************************************************/ +#define FM_PCD_FREE_KG_SCHEMES 4 + +/**************************************************************************//** + @Function FM_PCD_ALLOC_PROFILES + + @Description Used by FM PCD front-end in order to allocate Policer profiles + + @Param[in/out] t_FmIpcResourceAllocParams Pointer +*//***************************************************************************/ +#define FM_PCD_ALLOC_PROFILES 5 + +/**************************************************************************//** + @Function FM_PCD_FREE_PROFILES + + @Description Used by FM PCD front-end in order to Free Policer profiles + + @Param[in/out] t_FmIpcResourceAllocParams Pointer +*//***************************************************************************/ +#define FM_PCD_FREE_PROFILES 6 + +/**************************************************************************//** + @Function FM_PCD_SET_PORT_PROFILES + + @Description Used by FM PCD front-end in order to allocate Policer profiles + for specific port + + @Param[in/out] t_FmIpcResourceAllocParams Pointer +*//***************************************************************************/ +#define FM_PCD_SET_PORT_PROFILES 7 + +/**************************************************************************//** + @Function FM_PCD_CLEAR_PORT_PROFILES + + @Description Used by FM PCD front-end in order to allocate Policer profiles + for specific port + + @Param[in/out] t_FmIpcResourceAllocParams Pointer +*//***************************************************************************/ +#define FM_PCD_CLEAR_PORT_PROFILES 8 + +/**************************************************************************//** + @Function FM_PCD_GET_PHYS_MURAM_BASE + + @Description Used by FM PCD front-end in order to get MURAM base address + + @Param[in/out] t_FmPcdIcPhysAddr Pointer +*//***************************************************************************/ +#define FM_PCD_GET_PHYS_MURAM_BASE 9 + +/**************************************************************************//** + @Function FM_PCD_GET_SW_PRS_OFFSET + + @Description Used by FM front-end to get the SW parser offset of the start of + code relevant to a given label. + + @Param[in/out] t_FmPcdIpcSwPrsLable Pointer +*//***************************************************************************/ +#define FM_PCD_GET_SW_PRS_OFFSET 10 + +/**************************************************************************//** + @Function FM_PCD_MASTER_IS_ENABLED + + @Description Used by FM front-end in order to verify + PCD enablement. + + @Param[in] bool Pointer +*//***************************************************************************/ +#define FM_PCD_MASTER_IS_ENABLED 15 + +/**************************************************************************//** + @Function FM_PCD_GUEST_DISABLE + + @Description Used by FM front-end to inform back-end when + front-end PCD is disabled + + @Param[in] None +*//***************************************************************************/ +#define FM_PCD_GUEST_DISABLE 16 + +/**************************************************************************//** + @Function FM_PCD_FREE_KG_CLSPLAN + + @Description Used by FM PCD front-end in order to Free KG classification plan entries + + @Param[in/out] t_FmPcdIpcKgClsPlanParams Pointer +*//***************************************************************************/ +#define FM_PCD_FREE_KG_CLSPLAN 22 + +/**************************************************************************//** + @Function FM_PCD_ALLOC_KG_CLSPLAN + + @Description Used by FM PCD front-end in order to allocate KG classification plan entries + + @Param[in/out] t_FmPcdIpcKgClsPlanParams Pointer +*//***************************************************************************/ +#define FM_PCD_ALLOC_KG_CLSPLAN 23 + +/**************************************************************************//** + @Function FM_PCD_MASTER_IS_ALIVE + + @Description Used by FM front-end to check that back-end exists + + @Param[in] None +*//***************************************************************************/ +#define FM_PCD_MASTER_IS_ALIVE 24 + +/**************************************************************************//** + @Function FM_PCD_GET_COUNTER + + @Description Used by FM front-end to read PCD counters + + @Param[in/out] t_FmPcdIpcGetCounter Pointer +*//***************************************************************************/ +#define FM_PCD_GET_COUNTER 25 + +/**************************************************************************//** + @Function FM_PCD_PRS_INC_PORT_STATS + + @Description Used by FM front-end to set/clear statistics for port + + @Param[in/out] t_FmPcdIpcPrsIncludePort Pointer +*//***************************************************************************/ +#define FM_PCD_PRS_INC_PORT_STATS 26 + +#if (DPAA_VERSION >= 11) +/* TODO - doc */ +#define FM_PCD_ALLOC_SP 27 +#endif /* (DPAA_VERSION >= 11) */ + + +/** @} */ /* end of FM_PCD_IPC_grp group */ +/** @} */ /* end of FM_grp group */ + + +#endif /* __FM_PCD_IPC_H */ diff --git a/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Pcd/fm_plcr.c b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Pcd/fm_plcr.c new file mode 100644 index 000000000000..e3753305a75f --- /dev/null +++ b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Pcd/fm_plcr.c @@ -0,0 +1,1847 @@ +/* + * Copyright 2008-2012 Freescale Semiconductor Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Freescale Semiconductor nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * + * ALTERNATIVELY, this software may be distributed under the terms of the + * GNU General Public License ("GPL") as published by the Free Software + * Foundation, either version 2 of that License or (at your option) any + * later version. + * + * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + +/****************************************************************************** + @File fm_plcr.c + + @Description FM PCD POLICER... +*//***************************************************************************/ +#include <linux/math64.h> +#include "std_ext.h" +#include "error_ext.h" +#include "string_ext.h" +#include "debug_ext.h" +#include "net_ext.h" +#include "fm_ext.h" + +#include "fm_common.h" +#include "fm_pcd.h" +#include "fm_hc.h" +#include "fm_pcd_ipc.h" +#include "fm_plcr.h" + + +/****************************************/ +/* static functions */ +/****************************************/ + +static uint32_t PlcrProfileLock(t_Handle h_Profile) +{ + ASSERT_COND(h_Profile); + return FmPcdLockSpinlock(((t_FmPcdPlcrProfile *)h_Profile)->p_Lock); +} + +static void PlcrProfileUnlock(t_Handle h_Profile, uint32_t intFlags) +{ + ASSERT_COND(h_Profile); + FmPcdUnlockSpinlock(((t_FmPcdPlcrProfile *)h_Profile)->p_Lock, intFlags); +} + +static bool PlcrProfileFlagTryLock(t_Handle h_Profile) +{ + ASSERT_COND(h_Profile); + return FmPcdLockTryLock(((t_FmPcdPlcrProfile *)h_Profile)->p_Lock); +} + +static void PlcrProfileFlagUnlock(t_Handle h_Profile) +{ + ASSERT_COND(h_Profile); + FmPcdLockUnlock(((t_FmPcdPlcrProfile *)h_Profile)->p_Lock); +} + +static uint32_t PlcrHwLock(t_Handle h_FmPcdPlcr) +{ + ASSERT_COND(h_FmPcdPlcr); + return XX_LockIntrSpinlock(((t_FmPcdPlcr*)h_FmPcdPlcr)->h_HwSpinlock); +} + +static void PlcrHwUnlock(t_Handle h_FmPcdPlcr, uint32_t intFlags) +{ + ASSERT_COND(h_FmPcdPlcr); + XX_UnlockIntrSpinlock(((t_FmPcdPlcr*)h_FmPcdPlcr)->h_HwSpinlock, intFlags); +} + +static uint32_t PlcrSwLock(t_Handle h_FmPcdPlcr) +{ + ASSERT_COND(h_FmPcdPlcr); + return XX_LockIntrSpinlock(((t_FmPcdPlcr*)h_FmPcdPlcr)->h_SwSpinlock); +} + +static void PlcrSwUnlock(t_Handle h_FmPcdPlcr, uint32_t intFlags) +{ + ASSERT_COND(h_FmPcdPlcr); + XX_UnlockIntrSpinlock(((t_FmPcdPlcr*)h_FmPcdPlcr)->h_SwSpinlock, intFlags); +} + +static bool IsProfileShared(t_Handle h_FmPcd, uint16_t absoluteProfileId) +{ + t_FmPcd *p_FmPcd = (t_FmPcd*)h_FmPcd; + uint16_t i; + + SANITY_CHECK_RETURN_VALUE(p_FmPcd, E_INVALID_HANDLE, FALSE); + + for (i=0;i<p_FmPcd->p_FmPcdPlcr->numOfSharedProfiles;i++) + if (p_FmPcd->p_FmPcdPlcr->sharedProfilesIds[i] == absoluteProfileId) + return TRUE; + return FALSE; +} + +static t_Error SetProfileNia(t_FmPcd *p_FmPcd, e_FmPcdEngine nextEngine, u_FmPcdPlcrNextEngineParams *p_NextEngineParams, uint32_t *nextAction) +{ + uint32_t nia; + uint16_t absoluteProfileId; + uint8_t relativeSchemeId, physicalSchemeId; + + nia = FM_PCD_PLCR_NIA_VALID; + + switch (nextEngine) + { + case e_FM_PCD_DONE : + switch (p_NextEngineParams->action) + { + case e_FM_PCD_DROP_FRAME : + nia |= GET_NIA_BMI_AC_DISCARD_FRAME(p_FmPcd); + break; + case e_FM_PCD_ENQ_FRAME: + nia |= GET_NIA_BMI_AC_ENQ_FRAME(p_FmPcd); + break; + default: + RETURN_ERROR(MAJOR, E_INVALID_SELECTION, NO_MSG); + } + break; + case e_FM_PCD_KG: + physicalSchemeId = FmPcdKgGetSchemeId(p_NextEngineParams->h_DirectScheme); + relativeSchemeId = FmPcdKgGetRelativeSchemeId(p_FmPcd, physicalSchemeId); + if (relativeSchemeId >= FM_PCD_KG_NUM_OF_SCHEMES) + RETURN_ERROR(MAJOR, E_NOT_IN_RANGE, NO_MSG); + if (!FmPcdKgIsSchemeValidSw(p_NextEngineParams->h_DirectScheme)) + RETURN_ERROR(MAJOR, E_INVALID_STATE, ("Invalid direct scheme.")); + if (!KgIsSchemeAlwaysDirect(p_FmPcd, relativeSchemeId)) + RETURN_ERROR(MAJOR, E_INVALID_STATE, ("Policer Profile may point only to a scheme that is always direct.")); + nia |= NIA_ENG_KG | NIA_KG_DIRECT | physicalSchemeId; + break; + case e_FM_PCD_PLCR: + absoluteProfileId = ((t_FmPcdPlcrProfile *)p_NextEngineParams->h_Profile)->absoluteProfileId; + if (!IsProfileShared(p_FmPcd, absoluteProfileId)) + RETURN_ERROR(MAJOR, E_INVALID_STATE, ("Next profile must be a shared profile")); + if (!FmPcdPlcrIsProfileValid(p_FmPcd, absoluteProfileId)) + RETURN_ERROR(MAJOR, E_INVALID_STATE, ("Invalid profile ")); + nia |= NIA_ENG_PLCR | NIA_PLCR_ABSOLUTE | absoluteProfileId; + break; + default: + RETURN_ERROR(MAJOR, E_INVALID_SELECTION, NO_MSG); + } + + *nextAction = nia; + + return E_OK; +} + +static uint32_t CalcFPP(uint32_t fpp) +{ + if (fpp > 15) + return 15 - (0x1f - fpp); + else + return 16 + fpp; +} + +static void GetInfoRateReg(e_FmPcdPlcrRateMode rateMode, + uint32_t rate, + uint64_t tsuInTenthNano, + uint32_t fppShift, + uint64_t *p_Integer, + uint64_t *p_Fraction) +{ + uint64_t tmp, div; + + if (rateMode == e_FM_PCD_PLCR_BYTE_MODE) + { + /* now we calculate the initial integer for the bigger rate */ + /* from Kbps to Bytes/TSU */ + tmp = (uint64_t)rate; + tmp *= 1000; /* kb --> b */ + tmp *= tsuInTenthNano; /* bps --> bpTsu(in 10nano) */ + + div = 1000000000; /* nano */ + div *= 10; /* 10 nano */ + div *= 8; /* bit to byte */ + } + else + { + /* now we calculate the initial integer for the bigger rate */ + /* from Kbps to Bytes/TSU */ + tmp = (uint64_t)rate; + tmp *= tsuInTenthNano; /* bps --> bpTsu(in 10nano) */ + + div = 1000000000; /* nano */ + div *= 10; /* 10 nano */ + } + *p_Integer = div64_u64(tmp<<fppShift, div); + + /* for calculating the fraction, we will recalculate cir and deduct the integer. + * For precision, we will multiply by 2^16. we do not divid back, since we write + * this value as fraction - see spec. + */ + *p_Fraction = div64_u64(((tmp<<fppShift)<<16) - ((*p_Integer<<16)*div), div); +} + +/* .......... */ + +static void CalcRates(uint32_t bitFor1Micro, + t_FmPcdPlcrNonPassthroughAlgParams *p_NonPassthroughAlgParam, + uint32_t *cir, + uint32_t *cbs, + uint32_t *pir_eir, + uint32_t *pbs_ebs, + uint32_t *fpp) +{ + uint64_t integer, fraction; + uint32_t temp, tsuInTenthNanos; + uint8_t fppShift=0; + + /* we want the tsu to count 10 nano for better precision normally tsu is 3.9 nano, now we will get 39 */ + tsuInTenthNanos = (uint32_t)(1000*10/(1 << bitFor1Micro)); + + /* we choose the faster rate to calibrate fpp */ + /* The meaning of this step: + * when fppShift is 0 it means all TS bits are treated as integer and TSU is the TS LSB count. + * In this configuration we calculate the integer and fraction that represent the higher infoRate + * When this is done, we can tell where we have "spare" unused bits and optimize the division of TS + * into "integer" and "fraction" where the logic is - as many bits as possible for integer at + * high rate, as many bits as possible for fraction at low rate. + */ + if (p_NonPassthroughAlgParam->committedInfoRate > p_NonPassthroughAlgParam->peakOrExcessInfoRate) + GetInfoRateReg(p_NonPassthroughAlgParam->rateMode, p_NonPassthroughAlgParam->committedInfoRate, tsuInTenthNanos, 0, &integer, &fraction); + else + GetInfoRateReg(p_NonPassthroughAlgParam->rateMode, p_NonPassthroughAlgParam->peakOrExcessInfoRate, tsuInTenthNanos, 0, &integer, &fraction); + + /* we shift integer, as in cir/pir it is represented by the MSB 16 bits, and + * the LSB bits are for the fraction */ + temp = (uint32_t)((integer<<16) & 0x00000000FFFFFFFF); + /* temp is effected by the rate. For low rates it may be as low as 0, and then we'll + * take max FP = 31. + * For high rates it will never exceed the 32 bit reg (after the 16 shift), as it is + * limited by the 10G physical port. + */ + if (temp != 0) + { + /* In this case, the largest rate integer is non 0, if it does not occupy all (high) 16 + * bits of the PIR_EIR we can use this fact and enlarge it to occupy all 16 bits. + * The logic is to have as many bits for integer in the higher rates, but if we have "0"s + * in the integer part of the cir/pir register, than these bits are wasted. So we want + * to use these bits for the fraction. in this way we will have for fraction - the number + * of "0" bits and the rest - for integer. + * In other words: For each bit we shift it in PIR_EIR, we move the FP in the TS + * one bit to the left - preserving the relationship and achieving more bits + * for integer in the TS. + */ + + /* count zeroes left of the higher used bit (in order to shift the value such that + * unused bits may be used for fraction). + */ + while ((temp & 0x80000000) == 0) + { + temp = temp << 1; + fppShift++; + } + if (fppShift > 15) + { + REPORT_ERROR(MAJOR, E_INVALID_SELECTION, ("timeStampPeriod to Information rate ratio is too small")); + return; + } + } + else + { + temp = (uint32_t)fraction; /* fraction will alyas be smaller than 2^16 */ + if (!temp) + /* integer and fraction are 0, we set FP to its max val */ + fppShift = 31; + else + { + /* integer was 0 but fraction is not. FP is 16 for the fraction, + * + all left zeroes of the fraction. */ + fppShift=16; + /* count zeroes left of the higher used bit (in order to shift the value such that + * unused bits may be used for fraction). + */ + while ((temp & 0x8000) == 0) + { + temp = temp << 1; + fppShift++; + } + } + } + + /* + * This means that the FM TS register will now be used so that 'fppShift' bits are for + * fraction and the rest for integer */ + /* now we re-calculate cir and pir_eir with the calculated FP */ + GetInfoRateReg(p_NonPassthroughAlgParam->rateMode, p_NonPassthroughAlgParam->committedInfoRate, tsuInTenthNanos, fppShift, &integer, &fraction); + *cir = (uint32_t)(integer << 16 | (fraction & 0xFFFF)); + GetInfoRateReg(p_NonPassthroughAlgParam->rateMode, p_NonPassthroughAlgParam->peakOrExcessInfoRate, tsuInTenthNanos, fppShift, &integer, &fraction); + *pir_eir = (uint32_t)(integer << 16 | (fraction & 0xFFFF)); + + *cbs = p_NonPassthroughAlgParam->committedBurstSize; + *pbs_ebs = p_NonPassthroughAlgParam->peakOrExcessBurstSize; + + /* convert FP as it should be written to reg. + * 0-15 --> 16-31 + * 16-31 --> 0-15 + */ + *fpp = CalcFPP(fppShift); +} + +static void WritePar(t_FmPcd *p_FmPcd, uint32_t par) +{ + t_FmPcdPlcrRegs *p_FmPcdPlcrRegs = p_FmPcd->p_FmPcdPlcr->p_FmPcdPlcrRegs; + + ASSERT_COND(FmIsMaster(p_FmPcd->h_Fm)); + WRITE_UINT32(p_FmPcdPlcrRegs->fmpl_par, par); + + while (GET_UINT32(p_FmPcdPlcrRegs->fmpl_par) & FM_PCD_PLCR_PAR_GO) ; +} + +static t_Error BuildProfileRegs(t_FmPcd *p_FmPcd, + t_FmPcdPlcrProfileParams *p_ProfileParams, + t_FmPcdPlcrProfileRegs *p_PlcrRegs) +{ + t_Error err = E_OK; + uint32_t pemode, gnia, ynia, rnia, bitFor1Micro; + + ASSERT_COND(p_FmPcd); + + bitFor1Micro = FmGetTimeStampScale(p_FmPcd->h_Fm); + if (bitFor1Micro == 0) + RETURN_ERROR(MAJOR, E_NOT_AVAILABLE, ("Timestamp scale")); + +/* Set G, Y, R Nia */ + err = SetProfileNia(p_FmPcd, p_ProfileParams->nextEngineOnGreen, &(p_ProfileParams->paramsOnGreen), &gnia); + if (err) + RETURN_ERROR(MAJOR, err, NO_MSG); + err = SetProfileNia(p_FmPcd, p_ProfileParams->nextEngineOnYellow, &(p_ProfileParams->paramsOnYellow), &ynia); + if (err) + RETURN_ERROR(MAJOR, err, NO_MSG); + err = SetProfileNia(p_FmPcd, p_ProfileParams->nextEngineOnRed, &(p_ProfileParams->paramsOnRed), &rnia); + if (err) + RETURN_ERROR(MAJOR, err, NO_MSG); + +/* Mode fmpl_pemode */ + pemode = FM_PCD_PLCR_PEMODE_PI; + + switch (p_ProfileParams->algSelection) + { + case e_FM_PCD_PLCR_PASS_THROUGH: + p_PlcrRegs->fmpl_pecir = 0; + p_PlcrRegs->fmpl_pecbs = 0; + p_PlcrRegs->fmpl_pepepir_eir = 0; + p_PlcrRegs->fmpl_pepbs_ebs = 0; + p_PlcrRegs->fmpl_pelts = 0; + p_PlcrRegs->fmpl_pects = 0; + p_PlcrRegs->fmpl_pepts_ets = 0; + pemode &= ~FM_PCD_PLCR_PEMODE_ALG_MASK; + switch (p_ProfileParams->colorMode) + { + case e_FM_PCD_PLCR_COLOR_BLIND: + pemode |= FM_PCD_PLCR_PEMODE_CBLND; + switch (p_ProfileParams->color.dfltColor) + { + case e_FM_PCD_PLCR_GREEN: + pemode &= ~FM_PCD_PLCR_PEMODE_DEFC_MASK; + break; + case e_FM_PCD_PLCR_YELLOW: + pemode |= FM_PCD_PLCR_PEMODE_DEFC_Y; + break; + case e_FM_PCD_PLCR_RED: + pemode |= FM_PCD_PLCR_PEMODE_DEFC_R; + break; + case e_FM_PCD_PLCR_OVERRIDE: + pemode |= FM_PCD_PLCR_PEMODE_DEFC_OVERRIDE; + break; + default: + RETURN_ERROR(MAJOR, E_INVALID_SELECTION, NO_MSG); + } + + break; + case e_FM_PCD_PLCR_COLOR_AWARE: + pemode &= ~FM_PCD_PLCR_PEMODE_CBLND; + break; + default: + RETURN_ERROR(MAJOR, E_INVALID_SELECTION, NO_MSG); + } + break; + + case e_FM_PCD_PLCR_RFC_2698: + /* Select algorithm MODE[ALG] = "01" */ + pemode |= FM_PCD_PLCR_PEMODE_ALG_RFC2698; + if (p_ProfileParams->nonPassthroughAlgParams.committedInfoRate > p_ProfileParams->nonPassthroughAlgParams.peakOrExcessInfoRate) + RETURN_ERROR(MAJOR, E_INVALID_SELECTION, ("in RFC2698 Peak rate must be equal or larger than committedInfoRate.")); + goto cont_rfc; + case e_FM_PCD_PLCR_RFC_4115: + /* Select algorithm MODE[ALG] = "10" */ + pemode |= FM_PCD_PLCR_PEMODE_ALG_RFC4115; +cont_rfc: + /* Select Color-Blind / Color-Aware operation (MODE[CBLND]) */ + switch (p_ProfileParams->colorMode) + { + case e_FM_PCD_PLCR_COLOR_BLIND: + pemode |= FM_PCD_PLCR_PEMODE_CBLND; + break; + case e_FM_PCD_PLCR_COLOR_AWARE: + pemode &= ~FM_PCD_PLCR_PEMODE_CBLND; + /*In color aware more select override color interpretation (MODE[OVCLR]) */ + switch (p_ProfileParams->color.override) + { + case e_FM_PCD_PLCR_GREEN: + pemode &= ~FM_PCD_PLCR_PEMODE_OVCLR_MASK; + break; + case e_FM_PCD_PLCR_YELLOW: + pemode |= FM_PCD_PLCR_PEMODE_OVCLR_Y; + break; + case e_FM_PCD_PLCR_RED: + pemode |= FM_PCD_PLCR_PEMODE_OVCLR_R; + break; + case e_FM_PCD_PLCR_OVERRIDE: + pemode |= FM_PCD_PLCR_PEMODE_OVCLR_G_NC; + break; + default: + RETURN_ERROR(MAJOR, E_INVALID_SELECTION, NO_MSG); + } + break; + default: + RETURN_ERROR(MAJOR, E_INVALID_SELECTION, NO_MSG); + } + /* Select Measurement Unit Mode to BYTE or PACKET (MODE[PKT]) */ + switch (p_ProfileParams->nonPassthroughAlgParams.rateMode) + { + case e_FM_PCD_PLCR_BYTE_MODE : + pemode &= ~FM_PCD_PLCR_PEMODE_PKT; + switch (p_ProfileParams->nonPassthroughAlgParams.byteModeParams.frameLengthSelection) + { + case e_FM_PCD_PLCR_L2_FRM_LEN: + pemode |= FM_PCD_PLCR_PEMODE_FLS_L2; + break; + case e_FM_PCD_PLCR_L3_FRM_LEN: + pemode |= FM_PCD_PLCR_PEMODE_FLS_L3; + break; + case e_FM_PCD_PLCR_L4_FRM_LEN: + pemode |= FM_PCD_PLCR_PEMODE_FLS_L4; + break; + case e_FM_PCD_PLCR_FULL_FRM_LEN: + pemode |= FM_PCD_PLCR_PEMODE_FLS_FULL; + break; + default: + RETURN_ERROR(MAJOR, E_INVALID_SELECTION, NO_MSG); + } + switch (p_ProfileParams->nonPassthroughAlgParams.byteModeParams.rollBackFrameSelection) + { + case e_FM_PCD_PLCR_ROLLBACK_L2_FRM_LEN: + pemode &= ~FM_PCD_PLCR_PEMODE_RBFLS; + break; + case e_FM_PCD_PLCR_ROLLBACK_FULL_FRM_LEN: + pemode |= FM_PCD_PLCR_PEMODE_RBFLS; + break; + default: + RETURN_ERROR(MAJOR, E_INVALID_SELECTION, NO_MSG); + } + break; + case e_FM_PCD_PLCR_PACKET_MODE : + pemode |= FM_PCD_PLCR_PEMODE_PKT; + break; + default: + RETURN_ERROR(MAJOR, E_INVALID_SELECTION, NO_MSG); + } + /* Select timeStamp floating point position (MODE[FPP]) to fit the actual traffic rates. For PACKET + mode with low traffic rates move the fixed point to the left to increase fraction accuracy. For BYTE + mode with high traffic rates move the fixed point to the right to increase integer accuracy. */ + + /* Configure Traffic Parameters*/ + { + uint32_t cir=0, cbs=0, pir_eir=0, pbs_ebs=0, fpp=0; + + CalcRates(bitFor1Micro, &p_ProfileParams->nonPassthroughAlgParams, &cir, &cbs, &pir_eir, &pbs_ebs, &fpp); + + /* Set Committed Information Rate (CIR) */ + p_PlcrRegs->fmpl_pecir = cir; + /* Set Committed Burst Size (CBS). */ + p_PlcrRegs->fmpl_pecbs = cbs; + /* Set Peak Information Rate (PIR_EIR used as PIR) */ + p_PlcrRegs->fmpl_pepepir_eir = pir_eir; + /* Set Peak Burst Size (PBS_EBS used as PBS) */ + p_PlcrRegs->fmpl_pepbs_ebs = pbs_ebs; + + /* Initialize the Metering Buckets to be full (write them with 0xFFFFFFFF. */ + /* Peak Rate Token Bucket Size (PTS_ETS used as PTS) */ + p_PlcrRegs->fmpl_pepts_ets = 0xFFFFFFFF; + /* Committed Rate Token Bucket Size (CTS) */ + p_PlcrRegs->fmpl_pects = 0xFFFFFFFF; + + /* Set the FPP based on calculation */ + pemode |= (fpp << FM_PCD_PLCR_PEMODE_FPP_SHIFT); + } + break; /* FM_PCD_PLCR_PEMODE_ALG_RFC2698 , FM_PCD_PLCR_PEMODE_ALG_RFC4115 */ + default: + RETURN_ERROR(MAJOR, E_INVALID_SELECTION, NO_MSG); + } + + p_PlcrRegs->fmpl_pemode = pemode; + + p_PlcrRegs->fmpl_pegnia = gnia; + p_PlcrRegs->fmpl_peynia = ynia; + p_PlcrRegs->fmpl_pernia = rnia; + + /* Zero Counters */ + p_PlcrRegs->fmpl_pegpc = 0; + p_PlcrRegs->fmpl_peypc = 0; + p_PlcrRegs->fmpl_perpc = 0; + p_PlcrRegs->fmpl_perypc = 0; + p_PlcrRegs->fmpl_perrpc = 0; + + return E_OK; +} + +static t_Error AllocSharedProfiles(t_FmPcd *p_FmPcd, uint16_t numOfProfiles, uint16_t *profilesIds) +{ + uint32_t profilesFound; + uint16_t i, k=0; + uint32_t intFlags; + + SANITY_CHECK_RETURN_ERROR(p_FmPcd, E_INVALID_HANDLE); + + if (!numOfProfiles) + return E_OK; + + if (numOfProfiles>FM_PCD_PLCR_NUM_ENTRIES) + RETURN_ERROR(MINOR, E_INVALID_VALUE, ("numProfiles is too big.")); + + intFlags = PlcrSwLock(p_FmPcd->p_FmPcdPlcr); + /* Find numOfProfiles free profiles (may be spread) */ + profilesFound = 0; + for (i=0;i<FM_PCD_PLCR_NUM_ENTRIES; i++) + if (!p_FmPcd->p_FmPcdPlcr->profiles[i].profilesMng.allocated) + { + profilesFound++; + profilesIds[k] = i; + k++; + if (profilesFound == numOfProfiles) + break; + } + + if (profilesFound != numOfProfiles) + { + PlcrSwUnlock(p_FmPcd->p_FmPcdPlcr, intFlags); + RETURN_ERROR(MAJOR, E_INVALID_STATE,NO_MSG); + } + + for (i = 0;i<k;i++) + { + p_FmPcd->p_FmPcdPlcr->profiles[profilesIds[i]].profilesMng.allocated = TRUE; + p_FmPcd->p_FmPcdPlcr->profiles[profilesIds[i]].profilesMng.ownerId = 0; + } + PlcrSwUnlock(p_FmPcd->p_FmPcdPlcr, intFlags); + + return E_OK; +} + +static void FreeSharedProfiles(t_FmPcd *p_FmPcd, uint16_t numOfProfiles, uint16_t *profilesIds) +{ + uint16_t i; + + SANITY_CHECK_RETURN(p_FmPcd, E_INVALID_HANDLE); + + ASSERT_COND(numOfProfiles); + + for (i=0; i < numOfProfiles; i++) + { + ASSERT_COND(p_FmPcd->p_FmPcdPlcr->profiles[profilesIds[i]].profilesMng.allocated); + p_FmPcd->p_FmPcdPlcr->profiles[profilesIds[i]].profilesMng.allocated = FALSE; + p_FmPcd->p_FmPcdPlcr->profiles[profilesIds[i]].profilesMng.ownerId = p_FmPcd->guestId; + } +} + +static void UpdateRequiredActionFlag(t_Handle h_FmPcd, uint16_t absoluteProfileId, bool set) +{ + t_FmPcd *p_FmPcd = (t_FmPcd*)h_FmPcd; + + /* this routine is protected by calling routine */ + + ASSERT_COND(p_FmPcd->p_FmPcdPlcr->profiles[absoluteProfileId].valid); + + if (set) + p_FmPcd->p_FmPcdPlcr->profiles[absoluteProfileId].requiredActionFlag = TRUE; + else + { + p_FmPcd->p_FmPcdPlcr->profiles[absoluteProfileId].requiredAction = 0; + p_FmPcd->p_FmPcdPlcr->profiles[absoluteProfileId].requiredActionFlag = FALSE; + } +} + +/*********************************************/ +/*............Policer Exception..............*/ +/*********************************************/ +static void EventsCB(t_Handle h_FmPcd) +{ + t_FmPcd *p_FmPcd = (t_FmPcd *)h_FmPcd; + uint32_t event, mask, force; + + ASSERT_COND(FmIsMaster(p_FmPcd->h_Fm)); + event = GET_UINT32(p_FmPcd->p_FmPcdPlcr->p_FmPcdPlcrRegs->fmpl_evr); + mask = GET_UINT32(p_FmPcd->p_FmPcdPlcr->p_FmPcdPlcrRegs->fmpl_ier); + + event &= mask; + + /* clear the forced events */ + force = GET_UINT32(p_FmPcd->p_FmPcdPlcr->p_FmPcdPlcrRegs->fmpl_ifr); + if (force & event) + WRITE_UINT32(p_FmPcd->p_FmPcdPlcr->p_FmPcdPlcrRegs->fmpl_ifr, force & ~event); + + + WRITE_UINT32(p_FmPcd->p_FmPcdPlcr->p_FmPcdPlcrRegs->fmpl_evr, event); + + if (event & FM_PCD_PLCR_PRAM_SELF_INIT_COMPLETE) + p_FmPcd->f_Exception(p_FmPcd->h_App,e_FM_PCD_PLCR_EXCEPTION_PRAM_SELF_INIT_COMPLETE); + if (event & FM_PCD_PLCR_ATOMIC_ACTION_COMPLETE) + p_FmPcd->f_Exception(p_FmPcd->h_App,e_FM_PCD_PLCR_EXCEPTION_ATOMIC_ACTION_COMPLETE); +} + +/* ..... */ + +static void ErrorExceptionsCB(t_Handle h_FmPcd) +{ + t_FmPcd *p_FmPcd = (t_FmPcd *)h_FmPcd; + uint32_t event, force, captureReg, mask; + + ASSERT_COND(FmIsMaster(p_FmPcd->h_Fm)); + event = GET_UINT32(p_FmPcd->p_FmPcdPlcr->p_FmPcdPlcrRegs->fmpl_eevr); + mask = GET_UINT32(p_FmPcd->p_FmPcdPlcr->p_FmPcdPlcrRegs->fmpl_eier); + + event &= mask; + + /* clear the forced events */ + force = GET_UINT32(p_FmPcd->p_FmPcdPlcr->p_FmPcdPlcrRegs->fmpl_eifr); + if (force & event) + WRITE_UINT32(p_FmPcd->p_FmPcdPlcr->p_FmPcdPlcrRegs->fmpl_eifr, force & ~event); + + WRITE_UINT32(p_FmPcd->p_FmPcdPlcr->p_FmPcdPlcrRegs->fmpl_eevr, event); + + if (event & FM_PCD_PLCR_DOUBLE_ECC) + p_FmPcd->f_Exception(p_FmPcd->h_App,e_FM_PCD_PLCR_EXCEPTION_DOUBLE_ECC); + if (event & FM_PCD_PLCR_INIT_ENTRY_ERROR) + { + captureReg = GET_UINT32(p_FmPcd->p_FmPcdPlcr->p_FmPcdPlcrRegs->fmpl_upcr); + /*ASSERT_COND(captureReg & PLCR_ERR_UNINIT_CAP); + p_UnInitCapt->profileNum = (uint8_t)(captureReg & PLCR_ERR_UNINIT_NUM_MASK); + p_UnInitCapt->portId = (uint8_t)((captureReg & PLCR_ERR_UNINIT_PID_MASK) >>PLCR_ERR_UNINIT_PID_SHIFT) ; + p_UnInitCapt->absolute = (bool)(captureReg & PLCR_ERR_UNINIT_ABSOLUTE_MASK);*/ + p_FmPcd->f_FmPcdIndexedException(p_FmPcd->h_App,e_FM_PCD_PLCR_EXCEPTION_INIT_ENTRY_ERROR,(uint16_t)(captureReg & PLCR_ERR_UNINIT_NUM_MASK)); + WRITE_UINT32(p_FmPcd->p_FmPcdPlcr->p_FmPcdPlcrRegs->fmpl_upcr, PLCR_ERR_UNINIT_CAP); + } +} + + +/*****************************************************************************/ +/* Inter-module API routines */ +/*****************************************************************************/ + +t_Handle PlcrConfig(t_FmPcd *p_FmPcd, t_FmPcdParams *p_FmPcdParams) +{ + t_FmPcdPlcr *p_FmPcdPlcr; + uint16_t i=0; + + UNUSED(p_FmPcd); + UNUSED(p_FmPcdParams); + + p_FmPcdPlcr = (t_FmPcdPlcr *) XX_Malloc(sizeof(t_FmPcdPlcr)); + if (!p_FmPcdPlcr) + { + REPORT_ERROR(MAJOR, E_NO_MEMORY, ("FM Policer structure allocation FAILED")); + return NULL; + } + memset(p_FmPcdPlcr, 0, sizeof(t_FmPcdPlcr)); + if (p_FmPcd->guestId == NCSW_MASTER_ID) + { + p_FmPcdPlcr->p_FmPcdPlcrRegs = (t_FmPcdPlcrRegs *)UINT_TO_PTR(FmGetPcdPlcrBaseAddr(p_FmPcdParams->h_Fm)); + p_FmPcd->p_FmPcdDriverParam->plcrAutoRefresh = DEFAULT_plcrAutoRefresh; + p_FmPcd->exceptions |= (DEFAULT_fmPcdPlcrExceptions | DEFAULT_fmPcdPlcrErrorExceptions); + } + + p_FmPcdPlcr->numOfSharedProfiles = DEFAULT_numOfSharedPlcrProfiles; + + p_FmPcdPlcr->partPlcrProfilesBase = p_FmPcdParams->partPlcrProfilesBase; + p_FmPcdPlcr->partNumOfPlcrProfiles = p_FmPcdParams->partNumOfPlcrProfiles; + /* for backward compatabilty. if no policer profile, will set automatically to the max */ + if ((p_FmPcd->guestId == NCSW_MASTER_ID) && + (p_FmPcdPlcr->partNumOfPlcrProfiles == 0)) + p_FmPcdPlcr->partNumOfPlcrProfiles = FM_PCD_PLCR_NUM_ENTRIES; + + for (i=0; i<FM_PCD_PLCR_NUM_ENTRIES; i++) + p_FmPcdPlcr->profiles[i].profilesMng.ownerId = (uint8_t)ILLEGAL_BASE; + + return p_FmPcdPlcr; +} + +t_Error PlcrInit(t_FmPcd *p_FmPcd) +{ + t_FmPcdDriverParam *p_Param = p_FmPcd->p_FmPcdDriverParam; + t_FmPcdPlcr *p_FmPcdPlcr = p_FmPcd->p_FmPcdPlcr; + t_FmPcdPlcrRegs *p_Regs = p_FmPcd->p_FmPcdPlcr->p_FmPcdPlcrRegs; + t_Error err = E_OK; + uint32_t tmpReg32 = 0; + uint16_t base; + + if ((p_FmPcdPlcr->partPlcrProfilesBase + p_FmPcdPlcr->partNumOfPlcrProfiles) > FM_PCD_PLCR_NUM_ENTRIES) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("partPlcrProfilesBase+partNumOfPlcrProfiles out of range!!!")); + + p_FmPcdPlcr->h_HwSpinlock = XX_InitSpinlock(); + if (!p_FmPcdPlcr->h_HwSpinlock) + RETURN_ERROR(MAJOR, E_NO_MEMORY, ("FM Policer HW spinlock")); + + p_FmPcdPlcr->h_SwSpinlock = XX_InitSpinlock(); + if (!p_FmPcdPlcr->h_SwSpinlock) + RETURN_ERROR(MAJOR, E_NO_MEMORY, ("FM Policer SW spinlock")); + + base = PlcrAllocProfilesForPartition(p_FmPcd, + p_FmPcdPlcr->partPlcrProfilesBase, + p_FmPcdPlcr->partNumOfPlcrProfiles, + p_FmPcd->guestId); + if (base == (uint16_t)ILLEGAL_BASE) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, NO_MSG); + + if (p_FmPcdPlcr->numOfSharedProfiles) + { + err = AllocSharedProfiles(p_FmPcd, + p_FmPcdPlcr->numOfSharedProfiles, + p_FmPcdPlcr->sharedProfilesIds); + if (err) + RETURN_ERROR(MAJOR, err,NO_MSG); + } + + if (p_FmPcd->guestId != NCSW_MASTER_ID) + return E_OK; + + /**********************FMPL_GCR******************/ + tmpReg32 = 0; + tmpReg32 |= FM_PCD_PLCR_GCR_STEN; + if (p_Param->plcrAutoRefresh) + tmpReg32 |= FM_PCD_PLCR_GCR_DAR; + tmpReg32 |= GET_NIA_BMI_AC_ENQ_FRAME(p_FmPcd); + + WRITE_UINT32(p_Regs->fmpl_gcr, tmpReg32); + /**********************FMPL_GCR******************/ + + /**********************FMPL_EEVR******************/ + WRITE_UINT32(p_Regs->fmpl_eevr, (FM_PCD_PLCR_DOUBLE_ECC | FM_PCD_PLCR_INIT_ENTRY_ERROR)); + /**********************FMPL_EEVR******************/ + /**********************FMPL_EIER******************/ + tmpReg32 = 0; + if (p_FmPcd->exceptions & FM_PCD_EX_PLCR_DOUBLE_ECC) + { + FmEnableRamsEcc(p_FmPcd->h_Fm); + tmpReg32 |= FM_PCD_PLCR_DOUBLE_ECC; + } + if (p_FmPcd->exceptions & FM_PCD_EX_PLCR_INIT_ENTRY_ERROR) + tmpReg32 |= FM_PCD_PLCR_INIT_ENTRY_ERROR; + WRITE_UINT32(p_Regs->fmpl_eier, tmpReg32); + /**********************FMPL_EIER******************/ + + /**********************FMPL_EVR******************/ + WRITE_UINT32(p_Regs->fmpl_evr, (FM_PCD_PLCR_PRAM_SELF_INIT_COMPLETE | FM_PCD_PLCR_ATOMIC_ACTION_COMPLETE)); + /**********************FMPL_EVR******************/ + /**********************FMPL_IER******************/ + tmpReg32 = 0; + if (p_FmPcd->exceptions & FM_PCD_EX_PLCR_PRAM_SELF_INIT_COMPLETE) + tmpReg32 |= FM_PCD_PLCR_PRAM_SELF_INIT_COMPLETE; + if (p_FmPcd->exceptions & FM_PCD_EX_PLCR_ATOMIC_ACTION_COMPLETE) + tmpReg32 |= FM_PCD_PLCR_ATOMIC_ACTION_COMPLETE; + WRITE_UINT32(p_Regs->fmpl_ier, tmpReg32); + /**********************FMPL_IER******************/ + + /* register even if no interrupts enabled, to allow future enablement */ + FmRegisterIntr(p_FmPcd->h_Fm, + e_FM_MOD_PLCR, + 0, + e_FM_INTR_TYPE_ERR, + ErrorExceptionsCB, + p_FmPcd); + FmRegisterIntr(p_FmPcd->h_Fm, + e_FM_MOD_PLCR, + 0, + e_FM_INTR_TYPE_NORMAL, + EventsCB, + p_FmPcd); + + /* driver initializes one DFLT profile at the last entry*/ + /**********************FMPL_DPMR******************/ + tmpReg32 = 0; + WRITE_UINT32(p_Regs->fmpl_dpmr, tmpReg32); + p_FmPcd->p_FmPcdPlcr->profiles[0].profilesMng.allocated = TRUE; + + return E_OK; +} + +t_Error PlcrFree(t_FmPcd *p_FmPcd) +{ + FmUnregisterIntr(p_FmPcd->h_Fm, e_FM_MOD_PLCR, 0, e_FM_INTR_TYPE_ERR); + FmUnregisterIntr(p_FmPcd->h_Fm, e_FM_MOD_PLCR, 0, e_FM_INTR_TYPE_NORMAL); + + if (p_FmPcd->p_FmPcdPlcr->numOfSharedProfiles) + FreeSharedProfiles(p_FmPcd, + p_FmPcd->p_FmPcdPlcr->numOfSharedProfiles, + p_FmPcd->p_FmPcdPlcr->sharedProfilesIds); + + if (p_FmPcd->p_FmPcdPlcr->partNumOfPlcrProfiles) + PlcrFreeProfilesForPartition(p_FmPcd, + p_FmPcd->p_FmPcdPlcr->partPlcrProfilesBase, + p_FmPcd->p_FmPcdPlcr->partNumOfPlcrProfiles, + p_FmPcd->guestId); + + if (p_FmPcd->p_FmPcdPlcr->h_SwSpinlock) + XX_FreeSpinlock(p_FmPcd->p_FmPcdPlcr->h_SwSpinlock); + + if (p_FmPcd->p_FmPcdPlcr->h_HwSpinlock) + XX_FreeSpinlock(p_FmPcd->p_FmPcdPlcr->h_HwSpinlock); + + return E_OK; +} + +void PlcrEnable(t_FmPcd *p_FmPcd) +{ + t_FmPcdPlcrRegs *p_Regs = p_FmPcd->p_FmPcdPlcr->p_FmPcdPlcrRegs; + + WRITE_UINT32(p_Regs->fmpl_gcr, GET_UINT32(p_Regs->fmpl_gcr) | FM_PCD_PLCR_GCR_EN); +} + +void PlcrDisable(t_FmPcd *p_FmPcd) +{ + t_FmPcdPlcrRegs *p_Regs = p_FmPcd->p_FmPcdPlcr->p_FmPcdPlcrRegs; + + WRITE_UINT32(p_Regs->fmpl_gcr, GET_UINT32(p_Regs->fmpl_gcr) & ~FM_PCD_PLCR_GCR_EN); +} + +uint16_t PlcrAllocProfilesForPartition(t_FmPcd *p_FmPcd, uint16_t base, uint16_t numOfProfiles, uint8_t guestId) +{ + uint32_t intFlags; + uint16_t profilesFound = 0; + int i = 0; + + ASSERT_COND(p_FmPcd); + ASSERT_COND(p_FmPcd->p_FmPcdPlcr); + + if (!numOfProfiles) + return 0; + + if ((numOfProfiles > FM_PCD_PLCR_NUM_ENTRIES) || + (base + numOfProfiles > FM_PCD_PLCR_NUM_ENTRIES)) + return (uint16_t)ILLEGAL_BASE; + + if (p_FmPcd->h_IpcSession) + { + t_FmIpcResourceAllocParams ipcAllocParams; + t_FmPcdIpcMsg msg; + t_FmPcdIpcReply reply; + t_Error err; + uint32_t replyLength; + + memset(&msg, 0, sizeof(msg)); + memset(&reply, 0, sizeof(reply)); + memset(&ipcAllocParams, 0, sizeof(t_FmIpcResourceAllocParams)); + ipcAllocParams.guestId = p_FmPcd->guestId; + ipcAllocParams.num = p_FmPcd->p_FmPcdPlcr->partNumOfPlcrProfiles; + ipcAllocParams.base = p_FmPcd->p_FmPcdPlcr->partPlcrProfilesBase; + msg.msgId = FM_PCD_ALLOC_PROFILES; + memcpy(msg.msgBody, &ipcAllocParams, sizeof(t_FmIpcResourceAllocParams)); + replyLength = sizeof(uint32_t) + sizeof(uint16_t); + err = XX_IpcSendMessage(p_FmPcd->h_IpcSession, + (uint8_t*)&msg, + sizeof(msg.msgId) + sizeof(t_FmIpcResourceAllocParams), + (uint8_t*)&reply, + &replyLength, + NULL, + NULL); + if ((err != E_OK) || + (replyLength != (sizeof(uint32_t) + sizeof(uint16_t)))) + { + REPORT_ERROR(MAJOR, err, NO_MSG); + return (uint16_t)ILLEGAL_BASE; + } + else + memcpy((uint8_t*)&p_FmPcd->p_FmPcdPlcr->partPlcrProfilesBase, reply.replyBody, sizeof(uint16_t)); + if (p_FmPcd->p_FmPcdPlcr->partPlcrProfilesBase == (uint16_t)ILLEGAL_BASE) + { + REPORT_ERROR(MAJOR, err, NO_MSG); + return (uint16_t)ILLEGAL_BASE; + } + } + else if (p_FmPcd->guestId != NCSW_MASTER_ID) + { + DBG(WARNING, ("FM Guest mode, without IPC - can't validate Policer-profiles range!")); + return (uint16_t)ILLEGAL_BASE; + } + + intFlags = XX_LockIntrSpinlock(p_FmPcd->h_Spinlock); + for (i=base; i<(base+numOfProfiles); i++) + if (p_FmPcd->p_FmPcdPlcr->profiles[i].profilesMng.ownerId == (uint8_t)ILLEGAL_BASE) + profilesFound++; + else + break; + + if (profilesFound == numOfProfiles) + for (i=base; i<(base+numOfProfiles); i++) + p_FmPcd->p_FmPcdPlcr->profiles[i].profilesMng.ownerId = guestId; + else + { + XX_UnlockIntrSpinlock(p_FmPcd->h_Spinlock, intFlags); + return (uint16_t)ILLEGAL_BASE; + } + XX_UnlockIntrSpinlock(p_FmPcd->h_Spinlock, intFlags); + + return base; +} + +void PlcrFreeProfilesForPartition(t_FmPcd *p_FmPcd, uint16_t base, uint16_t numOfProfiles, uint8_t guestId) +{ + int i = 0; + + ASSERT_COND(p_FmPcd); + ASSERT_COND(p_FmPcd->p_FmPcdPlcr); + + if (p_FmPcd->h_IpcSession) + { + t_FmIpcResourceAllocParams ipcAllocParams; + t_FmPcdIpcMsg msg; + t_Error err; + + memset(&msg, 0, sizeof(msg)); + memset(&ipcAllocParams, 0, sizeof(t_FmIpcResourceAllocParams)); + ipcAllocParams.guestId = p_FmPcd->guestId; + ipcAllocParams.num = p_FmPcd->p_FmPcdPlcr->partNumOfPlcrProfiles; + ipcAllocParams.base = p_FmPcd->p_FmPcdPlcr->partPlcrProfilesBase; + msg.msgId = FM_PCD_FREE_PROFILES; + memcpy(msg.msgBody, &ipcAllocParams, sizeof(t_FmIpcResourceAllocParams)); + err = XX_IpcSendMessage(p_FmPcd->h_IpcSession, + (uint8_t*)&msg, + sizeof(msg.msgId) + sizeof(t_FmIpcResourceAllocParams), + NULL, + NULL, + NULL, + NULL); + if (err != E_OK) + REPORT_ERROR(MAJOR, err, NO_MSG); + return; + } + else if (p_FmPcd->guestId != NCSW_MASTER_ID) + { + DBG(WARNING, ("FM Guest mode, without IPC - can't validate Policer-profiles range!")); + return; + } + + for (i=base; i<(base+numOfProfiles); i++) + { + if (p_FmPcd->p_FmPcdPlcr->profiles[i].profilesMng.ownerId == guestId) + p_FmPcd->p_FmPcdPlcr->profiles[i].profilesMng.ownerId = (uint8_t)ILLEGAL_BASE; + else + DBG(WARNING, ("Request for freeing storage profile window which wasn't allocated to this partition")); + } +} + +t_Error PlcrSetPortProfiles(t_FmPcd *p_FmPcd, + uint8_t hardwarePortId, + uint16_t numOfProfiles, + uint16_t base) +{ + t_FmPcdPlcrRegs *p_Regs = p_FmPcd->p_FmPcdPlcr->p_FmPcdPlcrRegs; + uint32_t log2Num, tmpReg32; + + if ((p_FmPcd->guestId != NCSW_MASTER_ID) && + !p_Regs && + p_FmPcd->h_IpcSession) + { + t_FmIpcResourceAllocParams ipcAllocParams; + t_FmPcdIpcMsg msg; + t_Error err; + + memset(&msg, 0, sizeof(msg)); + memset(&ipcAllocParams, 0, sizeof(t_FmIpcResourceAllocParams)); + ipcAllocParams.guestId = hardwarePortId; + ipcAllocParams.num = numOfProfiles; + ipcAllocParams.base = base; + msg.msgId = FM_PCD_SET_PORT_PROFILES; + memcpy(msg.msgBody, &ipcAllocParams, sizeof(t_FmIpcResourceAllocParams)); + err = XX_IpcSendMessage(p_FmPcd->h_IpcSession, + (uint8_t*)&msg, + sizeof(msg.msgId) + sizeof(t_FmIpcResourceAllocParams), + NULL, + NULL, + NULL, + NULL); + if (err != E_OK) + RETURN_ERROR(MAJOR, err, NO_MSG); + return E_OK; + } + else if (!p_Regs) + RETURN_ERROR(MINOR, E_NOT_SUPPORTED, + ("Either IPC or 'baseAddress' is required!")); + + ASSERT_COND(IN_RANGE(1, hardwarePortId, 63)); + + if (GET_UINT32(p_Regs->fmpl_pmr[hardwarePortId-1]) & FM_PCD_PLCR_PMR_V) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, + ("The requesting port has already an allocated profiles window.")); + + /**********************FMPL_PMRx******************/ + LOG2((uint64_t)numOfProfiles, log2Num); + tmpReg32 = base; + tmpReg32 |= log2Num << 16; + tmpReg32 |= FM_PCD_PLCR_PMR_V; + WRITE_UINT32(p_Regs->fmpl_pmr[hardwarePortId-1], tmpReg32); + + return E_OK; +} + +t_Error PlcrClearPortProfiles(t_FmPcd *p_FmPcd, uint8_t hardwarePortId) +{ + t_FmPcdPlcrRegs *p_Regs = p_FmPcd->p_FmPcdPlcr->p_FmPcdPlcrRegs; + + if ((p_FmPcd->guestId != NCSW_MASTER_ID) && + !p_Regs && + p_FmPcd->h_IpcSession) + { + t_FmIpcResourceAllocParams ipcAllocParams; + t_FmPcdIpcMsg msg; + t_Error err; + + memset(&msg, 0, sizeof(msg)); + memset(&ipcAllocParams, 0, sizeof(t_FmIpcResourceAllocParams)); + ipcAllocParams.guestId = hardwarePortId; + msg.msgId = FM_PCD_CLEAR_PORT_PROFILES; + memcpy(msg.msgBody, &ipcAllocParams, sizeof(t_FmIpcResourceAllocParams)); + err = XX_IpcSendMessage(p_FmPcd->h_IpcSession, + (uint8_t*)&msg, + sizeof(msg.msgId) + sizeof(t_FmIpcResourceAllocParams), + NULL, + NULL, + NULL, + NULL); + if (err != E_OK) + RETURN_ERROR(MAJOR, err, NO_MSG); + return E_OK; + } + else if (!p_Regs) + RETURN_ERROR(MINOR, E_NOT_SUPPORTED, + ("Either IPC or 'baseAddress' is required!")); + + ASSERT_COND(IN_RANGE(1, hardwarePortId, 63)); + WRITE_UINT32(p_Regs->fmpl_pmr[hardwarePortId-1], 0); + + return E_OK; +} + +t_Error FmPcdPlcrAllocProfiles(t_Handle h_FmPcd, uint8_t hardwarePortId, uint16_t numOfProfiles) +{ + t_FmPcd *p_FmPcd = (t_FmPcd*)h_FmPcd; + t_Error err = E_OK; + uint32_t profilesFound; + uint32_t intFlags; + uint16_t i, first, swPortIndex = 0; + + SANITY_CHECK_RETURN_ERROR(p_FmPcd, E_INVALID_HANDLE); + + if (!numOfProfiles) + return E_OK; + + ASSERT_COND(hardwarePortId); + + if (numOfProfiles>FM_PCD_PLCR_NUM_ENTRIES) + RETURN_ERROR(MINOR, E_INVALID_VALUE, ("numProfiles is too big.")); + + if (!POWER_OF_2(numOfProfiles)) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("numProfiles must be a power of 2.")); + + first = 0; + profilesFound = 0; + intFlags = PlcrSwLock(p_FmPcd->p_FmPcdPlcr); + + for (i=0; i<FM_PCD_PLCR_NUM_ENTRIES; ) + { + if (!p_FmPcd->p_FmPcdPlcr->profiles[i].profilesMng.allocated) + { + profilesFound++; + i++; + if (profilesFound == numOfProfiles) + break; + } + else + { + profilesFound = 0; + /* advance i to the next aligned address */ + i = first = (uint16_t)(first + numOfProfiles); + } + } + + if (profilesFound == numOfProfiles) + { + for (i=first; i<first + numOfProfiles; i++) + { + p_FmPcd->p_FmPcdPlcr->profiles[i].profilesMng.allocated = TRUE; + p_FmPcd->p_FmPcdPlcr->profiles[i].profilesMng.ownerId = hardwarePortId; + } + } + else + { + PlcrSwUnlock(p_FmPcd->p_FmPcdPlcr, intFlags); + RETURN_ERROR(MINOR, E_FULL, ("No profiles.")); + } + PlcrSwUnlock(p_FmPcd->p_FmPcdPlcr, intFlags); + + err = PlcrSetPortProfiles(p_FmPcd, hardwarePortId, numOfProfiles, first); + if (err) + { + RETURN_ERROR(MAJOR, err, NO_MSG); + } + + HW_PORT_ID_TO_SW_PORT_INDX(swPortIndex, hardwarePortId); + + p_FmPcd->p_FmPcdPlcr->portsMapping[swPortIndex].numOfProfiles = numOfProfiles; + p_FmPcd->p_FmPcdPlcr->portsMapping[swPortIndex].profilesBase = first; + + return E_OK; +} + +t_Error FmPcdPlcrFreeProfiles(t_Handle h_FmPcd, uint8_t hardwarePortId) +{ + t_FmPcd *p_FmPcd = (t_FmPcd*)h_FmPcd; + t_Error err = E_OK; + uint32_t intFlags; + uint16_t i, swPortIndex = 0; + + ASSERT_COND(IN_RANGE(1, hardwarePortId, 63)); + + SANITY_CHECK_RETURN_ERROR(p_FmPcd, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(!p_FmPcd->p_FmPcdDriverParam, E_INVALID_HANDLE); + + HW_PORT_ID_TO_SW_PORT_INDX(swPortIndex, hardwarePortId); + + err = PlcrClearPortProfiles(p_FmPcd, hardwarePortId); + if (err) + RETURN_ERROR(MAJOR, err,NO_MSG); + + intFlags = PlcrSwLock(p_FmPcd->p_FmPcdPlcr); + for (i=p_FmPcd->p_FmPcdPlcr->portsMapping[swPortIndex].profilesBase; + i<(p_FmPcd->p_FmPcdPlcr->portsMapping[swPortIndex].profilesBase + + p_FmPcd->p_FmPcdPlcr->portsMapping[swPortIndex].numOfProfiles); + i++) + { + ASSERT_COND(p_FmPcd->p_FmPcdPlcr->profiles[i].profilesMng.ownerId == hardwarePortId); + ASSERT_COND(p_FmPcd->p_FmPcdPlcr->profiles[i].profilesMng.allocated); + + p_FmPcd->p_FmPcdPlcr->profiles[i].profilesMng.allocated = FALSE; + p_FmPcd->p_FmPcdPlcr->profiles[i].profilesMng.ownerId = p_FmPcd->guestId; + } + PlcrSwUnlock(p_FmPcd->p_FmPcdPlcr, intFlags); + + p_FmPcd->p_FmPcdPlcr->portsMapping[swPortIndex].numOfProfiles = 0; + p_FmPcd->p_FmPcdPlcr->portsMapping[swPortIndex].profilesBase = 0; + + return E_OK; +} + +t_Error FmPcdPlcrCcGetSetParams(t_Handle h_FmPcd, uint16_t profileIndx ,uint32_t requiredAction) +{ + t_FmPcd *p_FmPcd = (t_FmPcd *)h_FmPcd; + t_FmPcdPlcr *p_FmPcdPlcr = p_FmPcd->p_FmPcdPlcr; + t_FmPcdPlcrRegs *p_FmPcdPlcrRegs = p_FmPcdPlcr->p_FmPcdPlcrRegs; + uint32_t tmpReg32, intFlags; + t_Error err; + + /* Calling function locked all PCD modules, so no need to lock here */ + + if (profileIndx >= FM_PCD_PLCR_NUM_ENTRIES) + RETURN_ERROR(MAJOR, E_INVALID_VALUE,("Policer profile out of range")); + + if (!FmPcdPlcrIsProfileValid(p_FmPcd, profileIndx)) + RETURN_ERROR(MAJOR, E_INVALID_VALUE,("Policer profile is not valid")); + + /*intFlags = PlcrProfileLock(&p_FmPcd->p_FmPcdPlcr->profiles[profileIndx]);*/ + + if (p_FmPcd->h_Hc) + { + err = FmHcPcdPlcrCcGetSetParams(p_FmPcd->h_Hc, profileIndx, requiredAction); + + UpdateRequiredActionFlag(p_FmPcd, profileIndx, TRUE); + FmPcdPlcrUpdateRequiredAction(p_FmPcd, profileIndx, requiredAction); + + /*PlcrProfileUnlock(&p_FmPcd->p_FmPcdPlcr->profiles[profileIndx], intFlags);*/ + return err; + } + + /* lock the HW because once we read the registers we don't want them to be changed + * by another access. (We can copy to a tmp location and release the lock!) */ + + intFlags = PlcrHwLock(p_FmPcdPlcr); + WritePar(p_FmPcd, FmPcdPlcrBuildReadPlcrActionReg(profileIndx)); + + if (!p_FmPcd->p_FmPcdPlcr->profiles[profileIndx].requiredActionFlag || + !(p_FmPcd->p_FmPcdPlcr->profiles[profileIndx].requiredAction & requiredAction)) + { + if (requiredAction & UPDATE_NIA_ENQ_WITHOUT_DMA) + { + if ((p_FmPcd->p_FmPcdPlcr->profiles[profileIndx].nextEngineOnGreen!= e_FM_PCD_DONE) || + (p_FmPcd->p_FmPcdPlcr->profiles[profileIndx].nextEngineOnYellow!= e_FM_PCD_DONE) || + (p_FmPcd->p_FmPcdPlcr->profiles[profileIndx].nextEngineOnRed!= e_FM_PCD_DONE)) + { + PlcrHwUnlock(p_FmPcdPlcr, intFlags); + /*PlcrProfileUnlock(&p_FmPcd->p_FmPcdPlcr->profiles[profileIndx], intFlags);*/ + RETURN_ERROR (MAJOR, E_OK, ("In this case the next engine can be e_FM_PCD_DONE")); + } + + if (p_FmPcd->p_FmPcdPlcr->profiles[profileIndx].paramsOnGreen.action == e_FM_PCD_ENQ_FRAME) + { + tmpReg32 = GET_UINT32(p_FmPcdPlcrRegs->profileRegs.fmpl_pegnia); + if (!(tmpReg32 & (NIA_ENG_BMI | NIA_BMI_AC_ENQ_FRAME))) + { + PlcrHwUnlock(p_FmPcdPlcr, intFlags); + /*PlcrProfileUnlock(&p_FmPcd->p_FmPcdPlcr->profiles[profileIndx], intFlags);*/ + RETURN_ERROR(MAJOR, E_INVALID_STATE, ("Next engine of this policer profile has to be assigned to FM_PCD_DONE")); + } + tmpReg32 |= NIA_BMI_AC_ENQ_FRAME_WITHOUT_DMA; + WRITE_UINT32(p_FmPcdPlcrRegs->profileRegs.fmpl_pegnia, tmpReg32); + tmpReg32 = FmPcdPlcrBuildWritePlcrActionReg(profileIndx); + tmpReg32 |= FM_PCD_PLCR_PAR_PWSEL_PEGNIA; + WritePar(p_FmPcd, tmpReg32); + } + + if (p_FmPcd->p_FmPcdPlcr->profiles[profileIndx].paramsOnYellow.action == e_FM_PCD_ENQ_FRAME) + { + tmpReg32 = GET_UINT32(p_FmPcdPlcrRegs->profileRegs.fmpl_peynia); + if (!(tmpReg32 & (NIA_ENG_BMI | NIA_BMI_AC_ENQ_FRAME))) + { + PlcrHwUnlock(p_FmPcdPlcr, intFlags); + /*PlcrProfileUnlock(&p_FmPcd->p_FmPcdPlcr->profiles[profileIndx], intFlags);*/ + RETURN_ERROR(MAJOR, E_INVALID_STATE, ("Next engine of this policer profile has to be assigned to FM_PCD_DONE")); + } + tmpReg32 |= NIA_BMI_AC_ENQ_FRAME_WITHOUT_DMA; + WRITE_UINT32(p_FmPcdPlcrRegs->profileRegs.fmpl_peynia, tmpReg32); + tmpReg32 = FmPcdPlcrBuildWritePlcrActionReg(profileIndx); + tmpReg32 |= FM_PCD_PLCR_PAR_PWSEL_PEYNIA; + WritePar(p_FmPcd, tmpReg32); + PlcrHwUnlock(p_FmPcdPlcr, intFlags); + } + + if (p_FmPcd->p_FmPcdPlcr->profiles[profileIndx].paramsOnRed.action == e_FM_PCD_ENQ_FRAME) + { + tmpReg32 = GET_UINT32(p_FmPcdPlcrRegs->profileRegs.fmpl_pernia); + if (!(tmpReg32 & (NIA_ENG_BMI | NIA_BMI_AC_ENQ_FRAME))) + { + PlcrHwUnlock(p_FmPcdPlcr, intFlags); + /*PlcrProfileUnlock(&p_FmPcd->p_FmPcdPlcr->profiles[profileIndx], intFlags);*/ + RETURN_ERROR(MAJOR, E_INVALID_STATE, ("Next engine of this policer profile has to be assigned to FM_PCD_DONE")); + } + tmpReg32 |= NIA_BMI_AC_ENQ_FRAME_WITHOUT_DMA; + WRITE_UINT32(p_FmPcdPlcrRegs->profileRegs.fmpl_pernia, tmpReg32); + tmpReg32 = FmPcdPlcrBuildWritePlcrActionReg(profileIndx); + tmpReg32 |= FM_PCD_PLCR_PAR_PWSEL_PERNIA; + WritePar(p_FmPcd, tmpReg32); + + } + } + } + PlcrHwUnlock(p_FmPcdPlcr, intFlags); + + UpdateRequiredActionFlag(p_FmPcd, profileIndx, TRUE); + FmPcdPlcrUpdateRequiredAction(p_FmPcd, profileIndx, requiredAction); + + /*PlcrProfileUnlock(&p_FmPcd->p_FmPcdPlcr->profiles[profileIndx], intFlags);*/ + + return E_OK; +} + +uint32_t FmPcdPlcrGetRequiredActionFlag(t_Handle h_FmPcd, uint16_t absoluteProfileId) +{ + t_FmPcd *p_FmPcd = (t_FmPcd*)h_FmPcd; + + ASSERT_COND(p_FmPcd->p_FmPcdPlcr->profiles[absoluteProfileId].valid); + + return p_FmPcd->p_FmPcdPlcr->profiles[absoluteProfileId].requiredActionFlag; +} + +uint32_t FmPcdPlcrGetRequiredAction(t_Handle h_FmPcd, uint16_t absoluteProfileId) +{ + t_FmPcd *p_FmPcd = (t_FmPcd*)h_FmPcd; + + ASSERT_COND(p_FmPcd->p_FmPcdPlcr->profiles[absoluteProfileId].valid); + + return p_FmPcd->p_FmPcdPlcr->profiles[absoluteProfileId].requiredAction; +} + +bool FmPcdPlcrIsProfileValid(t_Handle h_FmPcd, uint16_t absoluteProfileId) +{ + t_FmPcd *p_FmPcd = (t_FmPcd*)h_FmPcd; + t_FmPcdPlcr *p_FmPcdPlcr = p_FmPcd->p_FmPcdPlcr; + + ASSERT_COND(absoluteProfileId < FM_PCD_PLCR_NUM_ENTRIES); + + return p_FmPcdPlcr->profiles[absoluteProfileId].valid; +} + +void FmPcdPlcrValidateProfileSw(t_Handle h_FmPcd, uint16_t absoluteProfileId) +{ + t_FmPcd *p_FmPcd = (t_FmPcd*)h_FmPcd; + uint32_t intFlags; + + ASSERT_COND(!p_FmPcd->p_FmPcdPlcr->profiles[absoluteProfileId].valid); + + intFlags = PlcrProfileLock(&p_FmPcd->p_FmPcdPlcr->profiles[absoluteProfileId]); + p_FmPcd->p_FmPcdPlcr->profiles[absoluteProfileId].valid = TRUE; + PlcrProfileUnlock(&p_FmPcd->p_FmPcdPlcr->profiles[absoluteProfileId], intFlags); +} + +void FmPcdPlcrInvalidateProfileSw(t_Handle h_FmPcd, uint16_t absoluteProfileId) +{ + t_FmPcd *p_FmPcd = (t_FmPcd*)h_FmPcd; + uint32_t intFlags; + + ASSERT_COND(p_FmPcd->p_FmPcdPlcr->profiles[absoluteProfileId].valid); + + intFlags = PlcrProfileLock(&p_FmPcd->p_FmPcdPlcr->profiles[absoluteProfileId]); + p_FmPcd->p_FmPcdPlcr->profiles[absoluteProfileId].valid = FALSE; + PlcrProfileUnlock(&p_FmPcd->p_FmPcdPlcr->profiles[absoluteProfileId], intFlags); +} + +uint16_t FmPcdPlcrProfileGetAbsoluteId(t_Handle h_Profile) +{ + return ((t_FmPcdPlcrProfile*)h_Profile)->absoluteProfileId; +} + +t_Error FmPcdPlcrGetAbsoluteIdByProfileParams(t_Handle h_FmPcd, + e_FmPcdProfileTypeSelection profileType, + t_Handle h_FmPort, + uint16_t relativeProfile, + uint16_t *p_AbsoluteId) +{ + t_FmPcd *p_FmPcd = (t_FmPcd*)h_FmPcd; + t_FmPcdPlcr *p_FmPcdPlcr = p_FmPcd->p_FmPcdPlcr; + uint8_t i; + + switch (profileType) + { + case e_FM_PCD_PLCR_PORT_PRIVATE: + /* get port PCD id from port handle */ + for (i=0;i<FM_MAX_NUM_OF_PORTS;i++) + if (p_FmPcd->p_FmPcdPlcr->portsMapping[i].h_FmPort == h_FmPort) + break; + if (i == FM_MAX_NUM_OF_PORTS) + RETURN_ERROR(MAJOR, E_INVALID_STATE , ("Invalid port handle.")); + + if (!p_FmPcd->p_FmPcdPlcr->portsMapping[i].numOfProfiles) + RETURN_ERROR(MAJOR, E_INVALID_SELECTION , ("Port has no allocated profiles")); + if (relativeProfile >= p_FmPcd->p_FmPcdPlcr->portsMapping[i].numOfProfiles) + RETURN_ERROR(MAJOR, E_INVALID_SELECTION , ("Profile id is out of range")); + *p_AbsoluteId = (uint16_t)(p_FmPcd->p_FmPcdPlcr->portsMapping[i].profilesBase + relativeProfile); + break; + case e_FM_PCD_PLCR_SHARED: + if (relativeProfile >= p_FmPcdPlcr->numOfSharedProfiles) + RETURN_ERROR(MAJOR, E_INVALID_SELECTION , ("Profile id is out of range")); + *p_AbsoluteId = (uint16_t)(p_FmPcdPlcr->sharedProfilesIds[relativeProfile]); + break; + default: + RETURN_ERROR(MAJOR, E_INVALID_SELECTION, ("Invalid policer profile type")); + } + + return E_OK; +} + +uint16_t FmPcdPlcrGetPortProfilesBase(t_Handle h_FmPcd, uint8_t hardwarePortId) +{ + t_FmPcd *p_FmPcd = (t_FmPcd *)h_FmPcd; + uint16_t swPortIndex = 0; + + HW_PORT_ID_TO_SW_PORT_INDX(swPortIndex, hardwarePortId); + + return p_FmPcd->p_FmPcdPlcr->portsMapping[swPortIndex].profilesBase; +} + +uint16_t FmPcdPlcrGetPortNumOfProfiles(t_Handle h_FmPcd, uint8_t hardwarePortId) +{ + t_FmPcd *p_FmPcd = (t_FmPcd *)h_FmPcd; + uint16_t swPortIndex = 0; + + HW_PORT_ID_TO_SW_PORT_INDX(swPortIndex, hardwarePortId); + + return p_FmPcd->p_FmPcdPlcr->portsMapping[swPortIndex].numOfProfiles; + +} +uint32_t FmPcdPlcrBuildWritePlcrActionReg(uint16_t absoluteProfileId) +{ + return (uint32_t)(FM_PCD_PLCR_PAR_GO | + ((uint32_t)absoluteProfileId << FM_PCD_PLCR_PAR_PNUM_SHIFT)); +} + +uint32_t FmPcdPlcrBuildWritePlcrActionRegs(uint16_t absoluteProfileId) +{ + return (uint32_t)(FM_PCD_PLCR_PAR_GO | + ((uint32_t)absoluteProfileId << FM_PCD_PLCR_PAR_PNUM_SHIFT) | + FM_PCD_PLCR_PAR_PWSEL_MASK); +} + +bool FmPcdPlcrHwProfileIsValid(uint32_t profileModeReg) +{ + + if (profileModeReg & FM_PCD_PLCR_PEMODE_PI) + return TRUE; + else + return FALSE; +} + +uint32_t FmPcdPlcrBuildReadPlcrActionReg(uint16_t absoluteProfileId) +{ + return (uint32_t)(FM_PCD_PLCR_PAR_GO | + FM_PCD_PLCR_PAR_R | + ((uint32_t)absoluteProfileId << FM_PCD_PLCR_PAR_PNUM_SHIFT) | + FM_PCD_PLCR_PAR_PWSEL_MASK); +} + +uint32_t FmPcdPlcrBuildCounterProfileReg(e_FmPcdPlcrProfileCounters counter) +{ + switch (counter) + { + case (e_FM_PCD_PLCR_PROFILE_GREEN_PACKET_TOTAL_COUNTER): + return FM_PCD_PLCR_PAR_PWSEL_PEGPC; + case (e_FM_PCD_PLCR_PROFILE_YELLOW_PACKET_TOTAL_COUNTER): + return FM_PCD_PLCR_PAR_PWSEL_PEYPC; + case (e_FM_PCD_PLCR_PROFILE_RED_PACKET_TOTAL_COUNTER) : + return FM_PCD_PLCR_PAR_PWSEL_PERPC; + case (e_FM_PCD_PLCR_PROFILE_RECOLOURED_YELLOW_PACKET_TOTAL_COUNTER) : + return FM_PCD_PLCR_PAR_PWSEL_PERYPC; + case (e_FM_PCD_PLCR_PROFILE_RECOLOURED_RED_PACKET_TOTAL_COUNTER) : + return FM_PCD_PLCR_PAR_PWSEL_PERRPC; + default: + REPORT_ERROR(MAJOR, E_INVALID_SELECTION, NO_MSG); + return 0; + } +} + +uint32_t FmPcdPlcrBuildNiaProfileReg(bool green, bool yellow, bool red) +{ + + uint32_t tmpReg32 = 0; + + if (green) + tmpReg32 |= FM_PCD_PLCR_PAR_PWSEL_PEGNIA; + if (yellow) + tmpReg32 |= FM_PCD_PLCR_PAR_PWSEL_PEYNIA; + if (red) + tmpReg32 |= FM_PCD_PLCR_PAR_PWSEL_PERNIA; + + return tmpReg32; +} + +void FmPcdPlcrUpdateRequiredAction(t_Handle h_FmPcd, uint16_t absoluteProfileId, uint32_t requiredAction) +{ + t_FmPcd *p_FmPcd = (t_FmPcd*)h_FmPcd; + + /* this routine is protected by calling routine */ + + ASSERT_COND(p_FmPcd->p_FmPcdPlcr->profiles[absoluteProfileId].valid); + + p_FmPcd->p_FmPcdPlcr->profiles[absoluteProfileId].requiredAction |= requiredAction; +} + +/*********************** End of inter-module routines ************************/ + + +/**************************************************/ +/*............Policer API.........................*/ +/**************************************************/ + +t_Error FM_PCD_ConfigPlcrAutoRefreshMode(t_Handle h_FmPcd, bool enable) +{ + t_FmPcd *p_FmPcd = (t_FmPcd*)h_FmPcd; + + SANITY_CHECK_RETURN_ERROR(p_FmPcd, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_FmPcd->p_FmPcdDriverParam, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_FmPcd->p_FmPcdPlcr, E_INVALID_HANDLE); + + if (!FmIsMaster(p_FmPcd->h_Fm)) + RETURN_ERROR(MAJOR, E_NOT_SUPPORTED, ("FM_PCD_ConfigPlcrAutoRefreshMode - guest mode!")); + + p_FmPcd->p_FmPcdDriverParam->plcrAutoRefresh = enable; + + return E_OK; +} + +t_Error FM_PCD_ConfigPlcrNumOfSharedProfiles(t_Handle h_FmPcd, uint16_t numOfSharedPlcrProfiles) +{ + t_FmPcd *p_FmPcd = (t_FmPcd*)h_FmPcd; + + SANITY_CHECK_RETURN_ERROR(p_FmPcd, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_FmPcd->p_FmPcdDriverParam, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_FmPcd->p_FmPcdPlcr, E_INVALID_HANDLE); + + p_FmPcd->p_FmPcdPlcr->numOfSharedProfiles = numOfSharedPlcrProfiles; + + return E_OK; +} + +t_Error FM_PCD_SetPlcrStatistics(t_Handle h_FmPcd, bool enable) +{ + t_FmPcd *p_FmPcd = (t_FmPcd*)h_FmPcd; + uint32_t tmpReg32; + + SANITY_CHECK_RETURN_ERROR(p_FmPcd, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(!p_FmPcd->p_FmPcdDriverParam, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_FmPcd->p_FmPcdPlcr, E_INVALID_HANDLE); + + if (!FmIsMaster(p_FmPcd->h_Fm)) + RETURN_ERROR(MAJOR, E_NOT_SUPPORTED, ("FM_PCD_SetPlcrStatistics - guest mode!")); + + tmpReg32 = GET_UINT32(p_FmPcd->p_FmPcdPlcr->p_FmPcdPlcrRegs->fmpl_gcr); + if (enable) + tmpReg32 |= FM_PCD_PLCR_GCR_STEN; + else + tmpReg32 &= ~FM_PCD_PLCR_GCR_STEN; + + WRITE_UINT32(p_FmPcd->p_FmPcdPlcr->p_FmPcdPlcrRegs->fmpl_gcr, tmpReg32); + return E_OK; +} + +t_Handle FM_PCD_PlcrProfileSet(t_Handle h_FmPcd, + t_FmPcdPlcrProfileParams *p_ProfileParams) +{ + t_FmPcd *p_FmPcd; + t_FmPcdPlcrRegs *p_FmPcdPlcrRegs; + t_FmPcdPlcrProfileRegs plcrProfileReg; + uint32_t intFlags; + uint16_t absoluteProfileId; + t_Error err = E_OK; + uint32_t tmpReg32; + t_FmPcdPlcrProfile *p_Profile; + + SANITY_CHECK_RETURN_VALUE(h_FmPcd, E_INVALID_HANDLE, NULL); + + if (p_ProfileParams->modify) + { + p_Profile = (t_FmPcdPlcrProfile *)p_ProfileParams->id.h_Profile; + p_FmPcd = p_Profile->h_FmPcd; + absoluteProfileId = p_Profile->absoluteProfileId; + if (absoluteProfileId >= FM_PCD_PLCR_NUM_ENTRIES) + { + REPORT_ERROR(MAJOR, E_INVALID_VALUE, ("profileId too Big ")); + return NULL; + } + + SANITY_CHECK_RETURN_VALUE(p_FmPcd->p_FmPcdPlcr, E_INVALID_HANDLE, NULL); + + /* Try lock profile using flag */ + if (!PlcrProfileFlagTryLock(p_Profile)) + { + DBG(TRACE, ("Profile Try Lock - BUSY")); + /* Signal to caller BUSY condition */ + p_ProfileParams->id.h_Profile = NULL; + return NULL; + } + } + else + { + p_FmPcd = (t_FmPcd*)h_FmPcd; + + SANITY_CHECK_RETURN_VALUE(p_FmPcd->p_FmPcdPlcr, E_INVALID_HANDLE, NULL); + + /* SMP: needs to be protected only if another core now changes the windows */ + err = FmPcdPlcrGetAbsoluteIdByProfileParams(h_FmPcd, + p_ProfileParams->id.newParams.profileType, + p_ProfileParams->id.newParams.h_FmPort, + p_ProfileParams->id.newParams.relativeProfileId, + &absoluteProfileId); + if (err) + { + REPORT_ERROR(MAJOR, err, NO_MSG); + return NULL; + } + + if (absoluteProfileId >= FM_PCD_PLCR_NUM_ENTRIES) + { + REPORT_ERROR(MAJOR, E_INVALID_VALUE, ("profileId too Big ")); + return NULL; + } + + if (FmPcdPlcrIsProfileValid(p_FmPcd, absoluteProfileId)) + { + REPORT_ERROR(MAJOR, E_ALREADY_EXISTS, ("Policer Profile is already used")); + return NULL; + } + + /* initialize profile struct */ + p_Profile = &p_FmPcd->p_FmPcdPlcr->profiles[absoluteProfileId]; + + p_Profile->h_FmPcd = p_FmPcd; + p_Profile->absoluteProfileId = absoluteProfileId; + + p_Profile->p_Lock = FmPcdAcquireLock(p_FmPcd); + if (!p_Profile->p_Lock) + REPORT_ERROR(MAJOR, E_NOT_AVAILABLE, ("FM Policer Profile lock obj!")); + } + + SANITY_CHECK_RETURN_VALUE(!p_FmPcd->p_FmPcdDriverParam, E_INVALID_STATE, NULL); + + p_Profile->nextEngineOnGreen = p_ProfileParams->nextEngineOnGreen; + memcpy(&p_Profile->paramsOnGreen, &(p_ProfileParams->paramsOnGreen), sizeof(u_FmPcdPlcrNextEngineParams)); + + p_Profile->nextEngineOnYellow = p_ProfileParams->nextEngineOnYellow; + memcpy(&p_Profile->paramsOnYellow, &(p_ProfileParams->paramsOnYellow), sizeof(u_FmPcdPlcrNextEngineParams)); + + p_Profile->nextEngineOnRed = p_ProfileParams->nextEngineOnRed; + memcpy(&p_Profile->paramsOnRed, &(p_ProfileParams->paramsOnRed), sizeof(u_FmPcdPlcrNextEngineParams)); + + memset(&plcrProfileReg, 0, sizeof(t_FmPcdPlcrProfileRegs)); + + /* build the policer profile registers */ + err = BuildProfileRegs(h_FmPcd, p_ProfileParams, &plcrProfileReg); + if (err) + { + REPORT_ERROR(MAJOR, err, NO_MSG); + if (p_ProfileParams->modify) + /* unlock */ + PlcrProfileFlagUnlock(p_Profile); + if (!p_ProfileParams->modify && + p_Profile->p_Lock) + /* release allocated Profile lock */ + FmPcdReleaseLock(p_FmPcd, p_Profile->p_Lock); + return NULL; + } + + if (p_FmPcd->h_Hc) + { + err = FmHcPcdPlcrSetProfile(p_FmPcd->h_Hc, (t_Handle)p_Profile, &plcrProfileReg); + if (p_ProfileParams->modify) + PlcrProfileFlagUnlock(p_Profile); + if (err) + { + /* release the allocated scheme lock */ + if (!p_ProfileParams->modify && + p_Profile->p_Lock) + FmPcdReleaseLock(p_FmPcd, p_Profile->p_Lock); + + return NULL; + } + if (!p_ProfileParams->modify) + FmPcdPlcrValidateProfileSw(p_FmPcd,absoluteProfileId); + return (t_Handle)p_Profile; + } + + p_FmPcdPlcrRegs = p_FmPcd->p_FmPcdPlcr->p_FmPcdPlcrRegs; + SANITY_CHECK_RETURN_VALUE(p_FmPcdPlcrRegs, E_INVALID_HANDLE, NULL); + + intFlags = PlcrHwLock(p_FmPcd->p_FmPcdPlcr); + WRITE_UINT32(p_FmPcdPlcrRegs->profileRegs.fmpl_pemode , plcrProfileReg.fmpl_pemode); + WRITE_UINT32(p_FmPcdPlcrRegs->profileRegs.fmpl_pegnia , plcrProfileReg.fmpl_pegnia); + WRITE_UINT32(p_FmPcdPlcrRegs->profileRegs.fmpl_peynia , plcrProfileReg.fmpl_peynia); + WRITE_UINT32(p_FmPcdPlcrRegs->profileRegs.fmpl_pernia , plcrProfileReg.fmpl_pernia); + WRITE_UINT32(p_FmPcdPlcrRegs->profileRegs.fmpl_pecir , plcrProfileReg.fmpl_pecir); + WRITE_UINT32(p_FmPcdPlcrRegs->profileRegs.fmpl_pecbs , plcrProfileReg.fmpl_pecbs); + WRITE_UINT32(p_FmPcdPlcrRegs->profileRegs.fmpl_pepepir_eir,plcrProfileReg.fmpl_pepepir_eir); + WRITE_UINT32(p_FmPcdPlcrRegs->profileRegs.fmpl_pepbs_ebs,plcrProfileReg.fmpl_pepbs_ebs); + WRITE_UINT32(p_FmPcdPlcrRegs->profileRegs.fmpl_pelts , plcrProfileReg.fmpl_pelts); + WRITE_UINT32(p_FmPcdPlcrRegs->profileRegs.fmpl_pects , plcrProfileReg.fmpl_pects); + WRITE_UINT32(p_FmPcdPlcrRegs->profileRegs.fmpl_pepts_ets,plcrProfileReg.fmpl_pepts_ets); + WRITE_UINT32(p_FmPcdPlcrRegs->profileRegs.fmpl_pegpc , plcrProfileReg.fmpl_pegpc); + WRITE_UINT32(p_FmPcdPlcrRegs->profileRegs.fmpl_peypc , plcrProfileReg.fmpl_peypc); + WRITE_UINT32(p_FmPcdPlcrRegs->profileRegs.fmpl_perpc , plcrProfileReg.fmpl_perpc); + WRITE_UINT32(p_FmPcdPlcrRegs->profileRegs.fmpl_perypc , plcrProfileReg.fmpl_perypc); + WRITE_UINT32(p_FmPcdPlcrRegs->profileRegs.fmpl_perrpc , plcrProfileReg.fmpl_perrpc); + + tmpReg32 = FmPcdPlcrBuildWritePlcrActionRegs(absoluteProfileId); + WritePar(p_FmPcd, tmpReg32); + + PlcrHwUnlock(p_FmPcd->p_FmPcdPlcr, intFlags); + + if (!p_ProfileParams->modify) + FmPcdPlcrValidateProfileSw(p_FmPcd,absoluteProfileId); + else + PlcrProfileFlagUnlock(p_Profile); + + return (t_Handle)p_Profile; +} + +t_Error FM_PCD_PlcrProfileDelete(t_Handle h_Profile) +{ + t_FmPcdPlcrProfile *p_Profile = (t_FmPcdPlcrProfile*)h_Profile; + t_FmPcd *p_FmPcd; + uint16_t profileIndx; + uint32_t tmpReg32, intFlags; + t_Error err; + + SANITY_CHECK_RETURN_ERROR(p_Profile, E_INVALID_HANDLE); + p_FmPcd = p_Profile->h_FmPcd; + SANITY_CHECK_RETURN_ERROR(p_FmPcd, E_INVALID_HANDLE); + + profileIndx = p_Profile->absoluteProfileId; + + UpdateRequiredActionFlag(p_FmPcd, profileIndx, FALSE); + + FmPcdPlcrInvalidateProfileSw(p_FmPcd,profileIndx); + + if (p_FmPcd->h_Hc) + { + err = FmHcPcdPlcrDeleteProfile(p_FmPcd->h_Hc, h_Profile); + if (p_Profile->p_Lock) + /* release allocated Profile lock */ + FmPcdReleaseLock(p_FmPcd, p_Profile->p_Lock); + + return err; + } + + intFlags = PlcrHwLock(p_FmPcd->p_FmPcdPlcr); + WRITE_UINT32(p_FmPcd->p_FmPcdPlcr->p_FmPcdPlcrRegs->profileRegs.fmpl_pemode, ~FM_PCD_PLCR_PEMODE_PI); + + tmpReg32 = FmPcdPlcrBuildWritePlcrActionRegs(profileIndx); + WritePar(p_FmPcd, tmpReg32); + PlcrHwUnlock(p_FmPcd->p_FmPcdPlcr, intFlags); + + + if (p_Profile->p_Lock) + /* release allocated Profile lock */ + FmPcdReleaseLock(p_FmPcd, p_Profile->p_Lock); + + /* we do not memset profile as all its fields are being re-initialized at "set", + * plus its allocation information is still valid. */ + return E_OK; +} + +/***************************************************/ +/*............Policer Profile Counter..............*/ +/***************************************************/ +uint32_t FM_PCD_PlcrProfileGetCounter(t_Handle h_Profile, e_FmPcdPlcrProfileCounters counter) +{ + t_FmPcdPlcrProfile *p_Profile = (t_FmPcdPlcrProfile*)h_Profile; + t_FmPcd *p_FmPcd; + uint16_t profileIndx; + uint32_t intFlags, counterVal = 0; + t_FmPcdPlcrRegs *p_FmPcdPlcrRegs; + + SANITY_CHECK_RETURN_ERROR(p_Profile, E_INVALID_HANDLE); + p_FmPcd = p_Profile->h_FmPcd; + SANITY_CHECK_RETURN_ERROR(p_FmPcd, E_INVALID_HANDLE); + + if (p_FmPcd->h_Hc) + return FmHcPcdPlcrGetProfileCounter(p_FmPcd->h_Hc, h_Profile, counter); + + p_FmPcdPlcrRegs = p_FmPcd->p_FmPcdPlcr->p_FmPcdPlcrRegs; + SANITY_CHECK_RETURN_VALUE(p_FmPcdPlcrRegs, E_INVALID_HANDLE, 0); + + profileIndx = p_Profile->absoluteProfileId; + + if (profileIndx >= FM_PCD_PLCR_NUM_ENTRIES) + { + REPORT_ERROR(MAJOR, E_INVALID_VALUE, ("profileId too Big ")); + return 0; + } + intFlags = PlcrHwLock(p_FmPcd->p_FmPcdPlcr); + WritePar(p_FmPcd, FmPcdPlcrBuildReadPlcrActionReg(profileIndx)); + + switch (counter) + { + case e_FM_PCD_PLCR_PROFILE_GREEN_PACKET_TOTAL_COUNTER: + counterVal = (GET_UINT32(p_FmPcdPlcrRegs->profileRegs.fmpl_pegpc)); + break; + case e_FM_PCD_PLCR_PROFILE_YELLOW_PACKET_TOTAL_COUNTER: + counterVal = GET_UINT32(p_FmPcdPlcrRegs->profileRegs.fmpl_peypc); + break; + case e_FM_PCD_PLCR_PROFILE_RED_PACKET_TOTAL_COUNTER: + counterVal = GET_UINT32(p_FmPcdPlcrRegs->profileRegs.fmpl_perpc); + break; + case e_FM_PCD_PLCR_PROFILE_RECOLOURED_YELLOW_PACKET_TOTAL_COUNTER: + counterVal = GET_UINT32(p_FmPcdPlcrRegs->profileRegs.fmpl_perypc); + break; + case e_FM_PCD_PLCR_PROFILE_RECOLOURED_RED_PACKET_TOTAL_COUNTER: + counterVal = GET_UINT32(p_FmPcdPlcrRegs->profileRegs.fmpl_perrpc); + break; + default: + REPORT_ERROR(MAJOR, E_INVALID_SELECTION, NO_MSG); + break; + } + PlcrHwUnlock(p_FmPcd->p_FmPcdPlcr, intFlags); + + return counterVal; +} + +t_Error FM_PCD_PlcrProfileSetCounter(t_Handle h_Profile, e_FmPcdPlcrProfileCounters counter, uint32_t value) +{ + t_FmPcdPlcrProfile *p_Profile = (t_FmPcdPlcrProfile*)h_Profile; + t_FmPcd *p_FmPcd; + uint16_t profileIndx; + uint32_t tmpReg32, intFlags; + t_FmPcdPlcrRegs *p_FmPcdPlcrRegs; + + SANITY_CHECK_RETURN_ERROR(p_Profile, E_INVALID_HANDLE); + + p_FmPcd = p_Profile->h_FmPcd; + profileIndx = p_Profile->absoluteProfileId; + + if (p_FmPcd->h_Hc) + return FmHcPcdPlcrSetProfileCounter(p_FmPcd->h_Hc, h_Profile, counter, value); + + p_FmPcdPlcrRegs = p_FmPcd->p_FmPcdPlcr->p_FmPcdPlcrRegs; + SANITY_CHECK_RETURN_ERROR(p_FmPcdPlcrRegs, E_INVALID_HANDLE); + + intFlags = PlcrHwLock(p_FmPcd->p_FmPcdPlcr); + switch (counter) + { + case e_FM_PCD_PLCR_PROFILE_GREEN_PACKET_TOTAL_COUNTER: + WRITE_UINT32(p_FmPcdPlcrRegs->profileRegs.fmpl_pegpc, value); + break; + case e_FM_PCD_PLCR_PROFILE_YELLOW_PACKET_TOTAL_COUNTER: + WRITE_UINT32(p_FmPcdPlcrRegs->profileRegs.fmpl_peypc, value); + break; + case e_FM_PCD_PLCR_PROFILE_RED_PACKET_TOTAL_COUNTER: + WRITE_UINT32(p_FmPcdPlcrRegs->profileRegs.fmpl_perpc, value); + break; + case e_FM_PCD_PLCR_PROFILE_RECOLOURED_YELLOW_PACKET_TOTAL_COUNTER: + WRITE_UINT32(p_FmPcdPlcrRegs->profileRegs.fmpl_perypc ,value); + break; + case e_FM_PCD_PLCR_PROFILE_RECOLOURED_RED_PACKET_TOTAL_COUNTER: + WRITE_UINT32(p_FmPcdPlcrRegs->profileRegs.fmpl_perrpc ,value); + break; + default: + PlcrHwUnlock(p_FmPcd->p_FmPcdPlcr, intFlags); + RETURN_ERROR(MAJOR, E_INVALID_SELECTION, NO_MSG); + } + + /* Activate the atomic write action by writing FMPL_PAR with: GO=1, RW=1, PSI=0, PNUM = + * Profile Number, PWSEL=0xFFFF (select all words). + */ + tmpReg32 = FmPcdPlcrBuildWritePlcrActionReg(profileIndx); + tmpReg32 |= FmPcdPlcrBuildCounterProfileReg(counter); + WritePar(p_FmPcd, tmpReg32); + PlcrHwUnlock(p_FmPcd->p_FmPcdPlcr, intFlags); + + return E_OK; +} diff --git a/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Pcd/fm_plcr.h b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Pcd/fm_plcr.h new file mode 100644 index 000000000000..2bb8b969956c --- /dev/null +++ b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Pcd/fm_plcr.h @@ -0,0 +1,165 @@ +/* + * Copyright 2008-2012 Freescale Semiconductor Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Freescale Semiconductor nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * + * ALTERNATIVELY, this software may be distributed under the terms of the + * GNU General Public License ("GPL") as published by the Free Software + * Foundation, either version 2 of that License or (at your option) any + * later version. + * + * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + +/****************************************************************************** + @File fm_plcr.h + + @Description FM Policer private header +*//***************************************************************************/ +#ifndef __FM_PLCR_H +#define __FM_PLCR_H + +#include "std_ext.h" + + +/***********************************************************************/ +/* Policer defines */ +/***********************************************************************/ + +#define FM_PCD_PLCR_PAR_GO 0x80000000 +#define FM_PCD_PLCR_PAR_PWSEL_MASK 0x0000FFFF +#define FM_PCD_PLCR_PAR_R 0x40000000 + +/* shifts */ +#define FM_PCD_PLCR_PAR_PNUM_SHIFT 16 + +/* masks */ +#define FM_PCD_PLCR_PEMODE_PI 0x80000000 +#define FM_PCD_PLCR_PEMODE_CBLND 0x40000000 +#define FM_PCD_PLCR_PEMODE_ALG_MASK 0x30000000 +#define FM_PCD_PLCR_PEMODE_ALG_RFC2698 0x10000000 +#define FM_PCD_PLCR_PEMODE_ALG_RFC4115 0x20000000 +#define FM_PCD_PLCR_PEMODE_DEFC_MASK 0x0C000000 +#define FM_PCD_PLCR_PEMODE_DEFC_Y 0x04000000 +#define FM_PCD_PLCR_PEMODE_DEFC_R 0x08000000 +#define FM_PCD_PLCR_PEMODE_DEFC_OVERRIDE 0x0C000000 +#define FM_PCD_PLCR_PEMODE_OVCLR_MASK 0x03000000 +#define FM_PCD_PLCR_PEMODE_OVCLR_Y 0x01000000 +#define FM_PCD_PLCR_PEMODE_OVCLR_R 0x02000000 +#define FM_PCD_PLCR_PEMODE_OVCLR_G_NC 0x03000000 +#define FM_PCD_PLCR_PEMODE_PKT 0x00800000 +#define FM_PCD_PLCR_PEMODE_FPP_MASK 0x001F0000 +#define FM_PCD_PLCR_PEMODE_FPP_SHIFT 16 +#define FM_PCD_PLCR_PEMODE_FLS_MASK 0x0000F000 +#define FM_PCD_PLCR_PEMODE_FLS_L2 0x00003000 +#define FM_PCD_PLCR_PEMODE_FLS_L3 0x0000B000 +#define FM_PCD_PLCR_PEMODE_FLS_L4 0x0000E000 +#define FM_PCD_PLCR_PEMODE_FLS_FULL 0x0000F000 +#define FM_PCD_PLCR_PEMODE_RBFLS 0x00000800 +#define FM_PCD_PLCR_PEMODE_TRA 0x00000004 +#define FM_PCD_PLCR_PEMODE_TRB 0x00000002 +#define FM_PCD_PLCR_PEMODE_TRC 0x00000001 +#define FM_PCD_PLCR_DOUBLE_ECC 0x80000000 +#define FM_PCD_PLCR_INIT_ENTRY_ERROR 0x40000000 +#define FM_PCD_PLCR_PRAM_SELF_INIT_COMPLETE 0x80000000 +#define FM_PCD_PLCR_ATOMIC_ACTION_COMPLETE 0x40000000 + +#define FM_PCD_PLCR_NIA_VALID 0x80000000 + +#define FM_PCD_PLCR_GCR_EN 0x80000000 +#define FM_PCD_PLCR_GCR_STEN 0x40000000 +#define FM_PCD_PLCR_GCR_DAR 0x20000000 +#define FM_PCD_PLCR_GCR_DEFNIA 0x00FFFFFF +#define FM_PCD_PLCR_NIA_ABS 0x00000100 + +#define FM_PCD_PLCR_GSR_BSY 0x80000000 +#define FM_PCD_PLCR_GSR_DQS 0x60000000 +#define FM_PCD_PLCR_GSR_RPB 0x20000000 +#define FM_PCD_PLCR_GSR_FQS 0x0C000000 +#define FM_PCD_PLCR_GSR_LPALG 0x0000C000 +#define FM_PCD_PLCR_GSR_LPCA 0x00003000 +#define FM_PCD_PLCR_GSR_LPNUM 0x000000FF + +#define FM_PCD_PLCR_EVR_PSIC 0x80000000 +#define FM_PCD_PLCR_EVR_AAC 0x40000000 + +#define FM_PCD_PLCR_PAR_PSI 0x20000000 +#define FM_PCD_PLCR_PAR_PNUM 0x00FF0000 +/* PWSEL Selctive select options */ +#define FM_PCD_PLCR_PAR_PWSEL_PEMODE 0x00008000 /* 0 */ +#define FM_PCD_PLCR_PAR_PWSEL_PEGNIA 0x00004000 /* 1 */ +#define FM_PCD_PLCR_PAR_PWSEL_PEYNIA 0x00002000 /* 2 */ +#define FM_PCD_PLCR_PAR_PWSEL_PERNIA 0x00001000 /* 3 */ +#define FM_PCD_PLCR_PAR_PWSEL_PECIR 0x00000800 /* 4 */ +#define FM_PCD_PLCR_PAR_PWSEL_PECBS 0x00000400 /* 5 */ +#define FM_PCD_PLCR_PAR_PWSEL_PEPIR_EIR 0x00000200 /* 6 */ +#define FM_PCD_PLCR_PAR_PWSEL_PEPBS_EBS 0x00000100 /* 7 */ +#define FM_PCD_PLCR_PAR_PWSEL_PELTS 0x00000080 /* 8 */ +#define FM_PCD_PLCR_PAR_PWSEL_PECTS 0x00000040 /* 9 */ +#define FM_PCD_PLCR_PAR_PWSEL_PEPTS_ETS 0x00000020 /* 10 */ +#define FM_PCD_PLCR_PAR_PWSEL_PEGPC 0x00000010 /* 11 */ +#define FM_PCD_PLCR_PAR_PWSEL_PEYPC 0x00000008 /* 12 */ +#define FM_PCD_PLCR_PAR_PWSEL_PERPC 0x00000004 /* 13 */ +#define FM_PCD_PLCR_PAR_PWSEL_PERYPC 0x00000002 /* 14 */ +#define FM_PCD_PLCR_PAR_PWSEL_PERRPC 0x00000001 /* 15 */ + +#define FM_PCD_PLCR_PAR_PMR_BRN_1TO1 0x0000 /* - Full bit replacement. {PBNUM[0:N-1] + 1-> 2^N specific locations. */ +#define FM_PCD_PLCR_PAR_PMR_BRN_2TO2 0x1 /* - {PBNUM[0:N-2],PNUM[N-1]}. + 2-> 2^(N-1) base locations. */ +#define FM_PCD_PLCR_PAR_PMR_BRN_4TO4 0x2 /* - {PBNUM[0:N-3],PNUM[N-2:N-1]}. + 4-> 2^(N-2) base locations. */ +#define FM_PCD_PLCR_PAR_PMR_BRN_8TO8 0x3 /* - {PBNUM[0:N-4],PNUM[N-3:N-1]}. + 8->2^(N-3) base locations. */ +#define FM_PCD_PLCR_PAR_PMR_BRN_16TO16 0x4 /* - {PBNUM[0:N-5],PNUM[N-4:N-1]}. + 16-> 2^(N-4) base locations. */ +#define FM_PCD_PLCR_PAR_PMR_BRN_32TO32 0x5 /* {PBNUM[0:N-6],PNUM[N-5:N-1]}. + 32-> 2^(N-5) base locations. */ +#define FM_PCD_PLCR_PAR_PMR_BRN_64TO64 0x6 /* {PBNUM[0:N-7],PNUM[N-6:N-1]}. + 64-> 2^(N-6) base locations. */ +#define FM_PCD_PLCR_PAR_PMR_BRN_128TO128 0x7 /* {PBNUM[0:N-8],PNUM[N-7:N-1]}. + 128-> 2^(N-7) base locations. */ +#define FM_PCD_PLCR_PAR_PMR_BRN_256TO256 0x8 /* - No bit replacement for N=8. {PNUM[N-8:N-1]}. + When N=8 this option maps all 256 profiles by the DISPATCH bus into one group. */ + +#define FM_PCD_PLCR_PMR_V 0x80000000 +#define PLCR_ERR_ECC_CAP 0x80000000 +#define PLCR_ERR_ECC_TYPE_DOUBLE 0x40000000 +#define PLCR_ERR_ECC_PNUM_MASK 0x00000FF0 +#define PLCR_ERR_ECC_OFFSET_MASK 0x0000000F + +#define PLCR_ERR_UNINIT_CAP 0x80000000 +#define PLCR_ERR_UNINIT_NUM_MASK 0x000000FF +#define PLCR_ERR_UNINIT_PID_MASK 0x003f0000 +#define PLCR_ERR_UNINIT_ABSOLUTE_MASK 0x00008000 + +/* shifts */ +#define PLCR_ERR_ECC_PNUM_SHIFT 4 +#define PLCR_ERR_UNINIT_PID_SHIFT 16 + +#define FM_PCD_PLCR_PMR_BRN_SHIFT 16 + +#define PLCR_PORT_WINDOW_SIZE(hardwarePortId) + + +#endif /* __FM_PLCR_H */ diff --git a/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Pcd/fm_prs.c b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Pcd/fm_prs.c new file mode 100644 index 000000000000..ff4f0a2f23cb --- /dev/null +++ b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Pcd/fm_prs.c @@ -0,0 +1,423 @@ +/* + * Copyright 2008-2012 Freescale Semiconductor Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Freescale Semiconductor nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * + * ALTERNATIVELY, this software may be distributed under the terms of the + * GNU General Public License ("GPL") as published by the Free Software + * Foundation, either version 2 of that License or (at your option) any + * later version. + * + * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + +/****************************************************************************** + @File fm_pcd.c + + @Description FM PCD ... +*//***************************************************************************/ +#include <linux/math64.h> +#include "std_ext.h" +#include "error_ext.h" +#include "string_ext.h" +#include "debug_ext.h" +#include "net_ext.h" + +#include "fm_common.h" +#include "fm_pcd.h" +#include "fm_pcd_ipc.h" +#include "fm_prs.h" +#include "fsl_fman_prs.h" + + +static void PcdPrsErrorException(t_Handle h_FmPcd) +{ + t_FmPcd *p_FmPcd = (t_FmPcd *)h_FmPcd; + uint32_t event, ev_mask; + struct fman_prs_regs *PrsRegs = (struct fman_prs_regs *)p_FmPcd->p_FmPcdPrs->p_FmPcdPrsRegs; + + ASSERT_COND(p_FmPcd->guestId == NCSW_MASTER_ID); + ev_mask = fman_prs_get_err_ev_mask(PrsRegs); + + event = fman_prs_get_err_event(PrsRegs, ev_mask); + + fman_prs_ack_err_event(PrsRegs, event); + + DBG(TRACE, ("parser error - 0x%08x\n",event)); + + if(event & FM_PCD_PRS_DOUBLE_ECC) + p_FmPcd->f_Exception(p_FmPcd->h_App,e_FM_PCD_PRS_EXCEPTION_DOUBLE_ECC); +} + +static void PcdPrsException(t_Handle h_FmPcd) +{ + t_FmPcd *p_FmPcd = (t_FmPcd *)h_FmPcd; + uint32_t event, ev_mask; + struct fman_prs_regs *PrsRegs = (struct fman_prs_regs *)p_FmPcd->p_FmPcdPrs->p_FmPcdPrsRegs; + + ASSERT_COND(p_FmPcd->guestId == NCSW_MASTER_ID); + ev_mask = fman_prs_get_expt_ev_mask(PrsRegs); + event = fman_prs_get_expt_event(PrsRegs, ev_mask); + + ASSERT_COND(event & FM_PCD_PRS_SINGLE_ECC); + + DBG(TRACE, ("parser event - 0x%08x\n",event)); + + fman_prs_ack_expt_event(PrsRegs, event); + + p_FmPcd->f_Exception(p_FmPcd->h_App,e_FM_PCD_PRS_EXCEPTION_SINGLE_ECC); +} + +t_Handle PrsConfig(t_FmPcd *p_FmPcd,t_FmPcdParams *p_FmPcdParams) +{ + t_FmPcdPrs *p_FmPcdPrs; + uintptr_t baseAddr; + + UNUSED(p_FmPcd); + UNUSED(p_FmPcdParams); + + p_FmPcdPrs = (t_FmPcdPrs *) XX_Malloc(sizeof(t_FmPcdPrs)); + if (!p_FmPcdPrs) + { + REPORT_ERROR(MAJOR, E_NO_MEMORY, ("FM Parser structure allocation FAILED")); + return NULL; + } + memset(p_FmPcdPrs, 0, sizeof(t_FmPcdPrs)); + fman_prs_defconfig(&p_FmPcd->p_FmPcdDriverParam->dfltCfg); + + if (p_FmPcd->guestId == NCSW_MASTER_ID) + { + baseAddr = FmGetPcdPrsBaseAddr(p_FmPcdParams->h_Fm); + p_FmPcdPrs->p_SwPrsCode = (uint32_t *)UINT_TO_PTR(baseAddr); + p_FmPcdPrs->p_FmPcdPrsRegs = (struct fman_prs_regs *)UINT_TO_PTR(baseAddr + PRS_REGS_OFFSET); + } + + p_FmPcdPrs->fmPcdPrsPortIdStatistics = p_FmPcd->p_FmPcdDriverParam->dfltCfg.port_id_stat; + p_FmPcd->p_FmPcdDriverParam->prsMaxParseCycleLimit = p_FmPcd->p_FmPcdDriverParam->dfltCfg.max_prs_cyc_lim; + p_FmPcd->exceptions |= p_FmPcd->p_FmPcdDriverParam->dfltCfg.prs_exceptions; + + return p_FmPcdPrs; +} + +#if ((DPAA_VERSION == 10) && defined(FM_CAPWAP_SUPPORT)) + static uint8_t swPrsPatch[] = SW_PRS_UDP_LITE_PATCH; +#else + static uint8_t swPrsPatch[] = SW_PRS_OFFLOAD_PATCH; +#endif /* FM_CAPWAP_SUPPORT */ + +t_Error PrsInit(t_FmPcd *p_FmPcd) +{ + t_FmPcdDriverParam *p_Param = p_FmPcd->p_FmPcdDriverParam; + uint32_t *p_TmpCode; + uint32_t *p_LoadTarget = (uint32_t *)PTR_MOVE(p_FmPcd->p_FmPcdPrs->p_SwPrsCode, + FM_PCD_SW_PRS_SIZE-FM_PCD_PRS_SW_PATCHES_SIZE); + struct fman_prs_regs *PrsRegs = (struct fman_prs_regs *)p_FmPcd->p_FmPcdPrs->p_FmPcdPrsRegs; + uint32_t i; + + ASSERT_COND(sizeof(swPrsPatch) <= (FM_PCD_PRS_SW_PATCHES_SIZE-FM_PCD_PRS_SW_TAIL_SIZE)); + + /* nothing to do in guest-partition */ + if (p_FmPcd->guestId != NCSW_MASTER_ID) + return E_OK; + + p_TmpCode = (uint32_t *)XX_MallocSmart(ROUND_UP(sizeof(swPrsPatch),4), 0, sizeof(uint32_t)); + if (!p_TmpCode) + RETURN_ERROR(MAJOR, E_NO_MEMORY, ("Tmp Sw-Parser code allocation FAILED")); + memset((uint8_t *)p_TmpCode, 0, ROUND_UP(sizeof(swPrsPatch),4)); + memcpy((uint8_t *)p_TmpCode, (uint8_t *)swPrsPatch, sizeof(swPrsPatch)); + + fman_prs_init(PrsRegs, &p_Param->dfltCfg); + + /* register even if no interrupts enabled, to allow future enablement */ + FmRegisterIntr(p_FmPcd->h_Fm, e_FM_MOD_PRS, 0, e_FM_INTR_TYPE_ERR, PcdPrsErrorException, p_FmPcd); + + /* register even if no interrupts enabled, to allow future enablement */ + FmRegisterIntr(p_FmPcd->h_Fm, e_FM_MOD_PRS, 0, e_FM_INTR_TYPE_NORMAL, PcdPrsException, p_FmPcd); + + if(p_FmPcd->exceptions & FM_PCD_EX_PRS_SINGLE_ECC) + FmEnableRamsEcc(p_FmPcd->h_Fm); + + if(p_FmPcd->exceptions & FM_PCD_EX_PRS_DOUBLE_ECC) + FmEnableRamsEcc(p_FmPcd->h_Fm); + + /* load sw parser Ip-Frag patch */ + for (i=0; i<DIV_CEIL(sizeof(swPrsPatch), 4); i++) + WRITE_UINT32(p_LoadTarget[i], GET_UINT32(p_TmpCode[i])); + + XX_FreeSmart(p_TmpCode); + + return E_OK; +} + +void PrsFree(t_FmPcd *p_FmPcd) +{ + ASSERT_COND(p_FmPcd->guestId == NCSW_MASTER_ID); + FmUnregisterIntr(p_FmPcd->h_Fm, e_FM_MOD_PRS, 0, e_FM_INTR_TYPE_ERR); + /* register even if no interrupts enabled, to allow future enablement */ + FmUnregisterIntr(p_FmPcd->h_Fm, e_FM_MOD_PRS, 0, e_FM_INTR_TYPE_NORMAL); +} + +void PrsEnable(t_FmPcd *p_FmPcd) +{ + struct fman_prs_regs *PrsRegs = (struct fman_prs_regs *)p_FmPcd->p_FmPcdPrs->p_FmPcdPrsRegs; + + ASSERT_COND(p_FmPcd->guestId == NCSW_MASTER_ID); + fman_prs_enable(PrsRegs); +} + +void PrsDisable(t_FmPcd *p_FmPcd) +{ + struct fman_prs_regs *PrsRegs = (struct fman_prs_regs *)p_FmPcd->p_FmPcdPrs->p_FmPcdPrsRegs; + + ASSERT_COND(p_FmPcd->guestId == NCSW_MASTER_ID); + fman_prs_disable(PrsRegs); +} + +int PrsIsEnabled(t_FmPcd *p_FmPcd) +{ + struct fman_prs_regs *PrsRegs = (struct fman_prs_regs *)p_FmPcd->p_FmPcdPrs->p_FmPcdPrsRegs; + + ASSERT_COND(p_FmPcd->guestId == NCSW_MASTER_ID); + return fman_prs_is_enabled(PrsRegs); +} + +t_Error PrsIncludePortInStatistics(t_FmPcd *p_FmPcd, uint8_t hardwarePortId, bool include) +{ + struct fman_prs_regs *PrsRegs; + uint32_t bitMask = 0; + uint8_t prsPortId; + + SANITY_CHECK_RETURN_ERROR((hardwarePortId >=1 && hardwarePortId <= 16), E_INVALID_VALUE); + SANITY_CHECK_RETURN_ERROR(p_FmPcd, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_FmPcd->p_FmPcdPrs, E_INVALID_HANDLE); + + PrsRegs = (struct fman_prs_regs *)p_FmPcd->p_FmPcdPrs->p_FmPcdPrsRegs; + + GET_FM_PCD_PRS_PORT_ID(prsPortId, hardwarePortId); + GET_FM_PCD_INDEX_FLAG(bitMask, prsPortId); + + if (include) + p_FmPcd->p_FmPcdPrs->fmPcdPrsPortIdStatistics |= bitMask; + else + p_FmPcd->p_FmPcdPrs->fmPcdPrsPortIdStatistics &= ~bitMask; + + fman_prs_set_stst_port_msk(PrsRegs, + p_FmPcd->p_FmPcdPrs->fmPcdPrsPortIdStatistics); + + return E_OK; +} + +t_Error FmPcdPrsIncludePortInStatistics(t_Handle h_FmPcd, uint8_t hardwarePortId, bool include) +{ + t_FmPcd *p_FmPcd = (t_FmPcd *)h_FmPcd; + t_Error err; + + SANITY_CHECK_RETURN_ERROR((hardwarePortId >=1 && hardwarePortId <= 16), E_INVALID_VALUE); + SANITY_CHECK_RETURN_ERROR(p_FmPcd, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_FmPcd->p_FmPcdPrs, E_INVALID_HANDLE); + + if ((p_FmPcd->guestId != NCSW_MASTER_ID) && + p_FmPcd->h_IpcSession) + { + t_FmPcdIpcPrsIncludePort prsIncludePortParams; + t_FmPcdIpcMsg msg; + + prsIncludePortParams.hardwarePortId = hardwarePortId; + prsIncludePortParams.include = include; + memset(&msg, 0, sizeof(msg)); + msg.msgId = FM_PCD_PRS_INC_PORT_STATS; + memcpy(msg.msgBody, &prsIncludePortParams, sizeof(prsIncludePortParams)); + err = XX_IpcSendMessage(p_FmPcd->h_IpcSession, + (uint8_t*)&msg, + sizeof(msg.msgId) +sizeof(prsIncludePortParams), + NULL, + NULL, + NULL, + NULL); + if (err != E_OK) + RETURN_ERROR(MAJOR, err, NO_MSG); + return E_OK; + } + else if (p_FmPcd->guestId != NCSW_MASTER_ID) + RETURN_ERROR(MINOR, E_NOT_SUPPORTED, + ("running in guest-mode without IPC!")); + + return PrsIncludePortInStatistics(p_FmPcd, hardwarePortId, include); +} + +uint32_t FmPcdGetSwPrsOffset(t_Handle h_FmPcd, e_NetHeaderType hdr, uint8_t indexPerHdr) +{ + t_FmPcd *p_FmPcd = (t_FmPcd *)h_FmPcd; + t_FmPcdPrsLabelParams *p_Label; + int i; + + SANITY_CHECK_RETURN_VALUE(p_FmPcd, E_INVALID_HANDLE, 0); + SANITY_CHECK_RETURN_VALUE(!p_FmPcd->p_FmPcdDriverParam, E_INVALID_HANDLE, 0); + + if ((p_FmPcd->guestId != NCSW_MASTER_ID) && + p_FmPcd->h_IpcSession) + { + t_Error err = E_OK; + t_FmPcdIpcSwPrsLable labelParams; + t_FmPcdIpcMsg msg; + uint32_t prsOffset = 0; + t_FmPcdIpcReply reply; + uint32_t replyLength; + + memset(&reply, 0, sizeof(reply)); + memset(&msg, 0, sizeof(msg)); + labelParams.enumHdr = (uint32_t)hdr; + labelParams.indexPerHdr = indexPerHdr; + msg.msgId = FM_PCD_GET_SW_PRS_OFFSET; + memcpy(msg.msgBody, &labelParams, sizeof(labelParams)); + replyLength = sizeof(uint32_t) + sizeof(uint32_t); + err = XX_IpcSendMessage(p_FmPcd->h_IpcSession, + (uint8_t*)&msg, + sizeof(msg.msgId) +sizeof(labelParams), + (uint8_t*)&reply, + &replyLength, + NULL, + NULL); + if (err != E_OK) + RETURN_ERROR(MAJOR, err, NO_MSG); + if (replyLength != sizeof(uint32_t) + sizeof(uint32_t)) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("IPC reply length mismatch")); + + memcpy((uint8_t*)&prsOffset, reply.replyBody, sizeof(uint32_t)); + return prsOffset; + } + else if (p_FmPcd->guestId != NCSW_MASTER_ID) + RETURN_ERROR(MINOR, E_NOT_SUPPORTED, + ("running in guest-mode without IPC!")); + + ASSERT_COND(p_FmPcd->p_FmPcdPrs->currLabel < FM_PCD_PRS_NUM_OF_LABELS); + + for (i=0; i<p_FmPcd->p_FmPcdPrs->currLabel; i++) + { + p_Label = &p_FmPcd->p_FmPcdPrs->labelsTable[i]; + + if ((hdr == p_Label->hdr) && (indexPerHdr == p_Label->indexPerHdr)) + return p_Label->instructionOffset; + } + + REPORT_ERROR(MAJOR, E_NOT_FOUND, ("Sw Parser attachment Not found")); + return (uint32_t)ILLEGAL_BASE; +} + +void FM_PCD_SetPrsStatistics(t_Handle h_FmPcd, bool enable) +{ + t_FmPcd *p_FmPcd = (t_FmPcd*)h_FmPcd; + struct fman_prs_regs *PrsRegs; + + SANITY_CHECK_RETURN(p_FmPcd, E_INVALID_HANDLE); + SANITY_CHECK_RETURN(p_FmPcd->p_FmPcdPrs, E_INVALID_HANDLE); + + PrsRegs = (struct fman_prs_regs *)p_FmPcd->p_FmPcdPrs->p_FmPcdPrsRegs; + + + if(p_FmPcd->guestId != NCSW_MASTER_ID) + { + REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("FM_PCD_SetPrsStatistics - guest mode!")); + return; + } + + fman_prs_set_stst(PrsRegs, enable); +} + +t_Error FM_PCD_PrsLoadSw(t_Handle h_FmPcd, t_FmPcdPrsSwParams *p_SwPrs) +{ + t_FmPcd *p_FmPcd = (t_FmPcd*)h_FmPcd; + uint32_t *p_LoadTarget; + uint32_t *p_TmpCode; + int i; + + SANITY_CHECK_RETURN_ERROR(p_FmPcd, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(!p_FmPcd->p_FmPcdDriverParam, E_INVALID_STATE); + SANITY_CHECK_RETURN_ERROR(p_FmPcd->p_FmPcdPrs, E_INVALID_STATE); + SANITY_CHECK_RETURN_ERROR(p_SwPrs, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(!p_FmPcd->enabled, E_INVALID_HANDLE); + + if (p_FmPcd->guestId != NCSW_MASTER_ID) + RETURN_ERROR(MAJOR, E_NOT_SUPPORTED, ("FM in guest-mode!")); + + if (!p_SwPrs->override) + { + if(p_FmPcd->p_FmPcdPrs->p_CurrSwPrs > p_FmPcd->p_FmPcdPrs->p_SwPrsCode + p_SwPrs->base*2/4) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("SW parser base must be larger than current loaded code")); + } + else + p_FmPcd->p_FmPcdPrs->currLabel = 0; + + if (p_SwPrs->size > FM_PCD_SW_PRS_SIZE - FM_PCD_PRS_SW_TAIL_SIZE - p_SwPrs->base*2) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("p_SwPrs->size may not be larger than MAX_SW_PRS_CODE_SIZE")); + + if (p_FmPcd->p_FmPcdPrs->currLabel + p_SwPrs->numOfLabels > FM_PCD_PRS_NUM_OF_LABELS) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("Exceeded number of labels allowed ")); + + p_TmpCode = (uint32_t *)XX_MallocSmart(ROUND_UP(p_SwPrs->size,4), 0, sizeof(uint32_t)); + if (!p_TmpCode) + RETURN_ERROR(MAJOR, E_NO_MEMORY, ("Tmp Sw-Parser code allocation FAILED")); + memset((uint8_t *)p_TmpCode, 0, ROUND_UP(p_SwPrs->size,4)); + memcpy((uint8_t *)p_TmpCode, p_SwPrs->p_Code, p_SwPrs->size); + + /* save sw parser labels */ + memcpy(&p_FmPcd->p_FmPcdPrs->labelsTable[p_FmPcd->p_FmPcdPrs->currLabel], + p_SwPrs->labelsTable, + p_SwPrs->numOfLabels*sizeof(t_FmPcdPrsLabelParams)); + p_FmPcd->p_FmPcdPrs->currLabel += p_SwPrs->numOfLabels; + + /* load sw parser code */ + p_LoadTarget = p_FmPcd->p_FmPcdPrs->p_SwPrsCode + p_SwPrs->base*2/4; + + for(i=0; i<DIV_CEIL(p_SwPrs->size, 4); i++) + WRITE_UINT32(p_LoadTarget[i], GET_UINT32(p_TmpCode[i])); + + p_FmPcd->p_FmPcdPrs->p_CurrSwPrs = + p_FmPcd->p_FmPcdPrs->p_SwPrsCode + p_SwPrs->base*2/4 + ROUND_UP(p_SwPrs->size,4); + + /* copy data parameters */ + for (i=0;i<FM_PCD_PRS_NUM_OF_HDRS;i++) + WRITE_UINT32(*(p_FmPcd->p_FmPcdPrs->p_SwPrsCode+PRS_SW_DATA/4+i), p_SwPrs->swPrsDataParams[i]); + + /* Clear last 4 bytes */ + WRITE_UINT32(*(p_FmPcd->p_FmPcdPrs->p_SwPrsCode+(PRS_SW_DATA-FM_PCD_PRS_SW_TAIL_SIZE)/4), 0); + + XX_FreeSmart(p_TmpCode); + + return E_OK; +} + +t_Error FM_PCD_ConfigPrsMaxCycleLimit(t_Handle h_FmPcd,uint16_t value) +{ + t_FmPcd *p_FmPcd = (t_FmPcd*)h_FmPcd; + + SANITY_CHECK_RETURN_ERROR(p_FmPcd, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_FmPcd->p_FmPcdDriverParam, E_INVALID_HANDLE); + + if(p_FmPcd->guestId != NCSW_MASTER_ID) + RETURN_ERROR(MAJOR, E_NOT_SUPPORTED, ("FM_PCD_ConfigPrsMaxCycleLimit - guest mode!")); + + p_FmPcd->p_FmPcdDriverParam->prsMaxParseCycleLimit = value; + + return E_OK; +} diff --git a/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Pcd/fm_prs.h b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Pcd/fm_prs.h new file mode 100644 index 000000000000..056f225ef221 --- /dev/null +++ b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Pcd/fm_prs.h @@ -0,0 +1,316 @@ +/* + * Copyright 2008-2012 Freescale Semiconductor Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Freescale Semiconductor nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * + * ALTERNATIVELY, this software may be distributed under the terms of the + * GNU General Public License ("GPL") as published by the Free Software + * Foundation, either version 2 of that License or (at your option) any + * later version. + * + * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + +/****************************************************************************** + @File fm_prs.h + + @Description FM Parser private header + *//***************************************************************************/ +#ifndef __FM_PRS_H +#define __FM_PRS_H + +#include "std_ext.h" + +/***********************************************************************/ +/* SW parser IP_FRAG patch */ +/***********************************************************************/ + +#if ((DPAA_VERSION == 10) && defined(FM_CAPWAP_SUPPORT)) +#define SW_PRS_UDP_LITE_PATCH \ +{\ + 0x31,0x52,0x00,0xDA,0xFC,0x00,0x00,0x00,0x00,0x00, \ + 0x00,0x00,0x50,0x2C,0x40,0x00,0x31,0x92,0x50,0x2C, \ + 0x00,0x88,0x18,0x2F,0x00,0x01,0x1B,0xFE,0x18,0x71, \ + 0x02,0x1F,0x00,0x08,0x00,0x83,0x02,0x1F,0x00,0x20, \ + 0x28,0x1B,0x00,0x05,0x29,0x1F,0x30,0xD0,0x60,0x4F, \ + 0x00,0x07,0x00,0x05,0x00,0x00,0xC3,0x8F,0x00,0x52, \ + 0x00,0x01,0x07,0x01,0x60,0x3B,0x00,0x00,0x30,0xD0, \ + 0x00,0xDA,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00, \ + 0x40,0x4C,0x00,0x00,0x02,0x8F,0x00,0x00,0x30,0xF2, \ + 0x00,0x06,0x18,0x5D,0x00,0x00,0x9F,0xFF,0x30,0xF2, \ + 0x00,0x06,0x29,0x1E,0x07,0x08,0x30,0xD0,0x00,0x52, \ + 0x00,0x08,0x28,0x1A,0x60,0x37,0x00,0x00,0x30,0xF2, \ + 0x18,0x5D,0x06,0x00,0x29,0x1E,0x30,0xF2,0x2F,0x0E, \ + 0x30,0x72,0x00,0x00,0x9B,0x8F,0x00,0x06,0x2F,0x0E, \ + 0x32,0xF1,0x32,0xB0,0x00,0x4F,0x00,0x57,0x00,0x28, \ + 0x00,0x00,0x97,0x9E,0x00,0x4E,0x30,0x72,0x00,0x06, \ + 0x2F,0x0E,0x32,0xC1,0x32,0xF0,0x00,0x4A,0x00,0x80, \ + 0x00,0x02,0x00,0x00,0x97,0x9E,0x40,0x7E,0x00,0x08, \ + 0x08,0x16,0x00,0x54,0x00,0x01,0x1B,0xFE,0x00,0x00, \ + 0x9F,0x9E,0x40,0xB3,0x00,0x00,0x02,0x1F,0x00,0x08, \ + 0x28,0x1B,0x30,0x73,0x29,0x1F,0x30,0xD0,0x60,0x9F, \ + 0x00,0x07,0x00,0x05,0x00,0x00,0xC3,0x8F,0x00,0x52, \ + 0x00,0x01,0x07,0x01,0x60,0x8B,0x00,0x00,0x30,0xD0, \ + 0x00,0xDA,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00, \ + 0x40,0x9C,0x00,0x00,0x02,0x8F,0x00,0x00,0x30,0xF2, \ + 0x00,0x06,0x18,0xAD,0x00,0x00,0x9F,0xFF,0x30,0xF2, \ + 0x00,0x06,0x29,0x1E,0x07,0x08,0x30,0xD0,0x00,0x52, \ + 0x00,0x08,0x28,0x1A,0x60,0x87,0x00,0x00,0x30,0xF2, \ + 0x18,0xAD,0x06,0x00,0x29,0x1E,0x30,0xF2,0x50,0xB3, \ + 0xFF,0xFF,0x18,0xB8,0x08,0x16,0x00,0x54,0x00,0x01, \ + 0x1B,0xFE,0x18,0xC5,0x32,0xF1,0x28,0x5D,0x32,0xF1, \ + 0x00,0x55,0x00,0x08,0x28,0x5F,0x00,0x00,0x8F,0x9F, \ + 0x29,0x33,0x08,0x16,0x00,0x49,0x00,0x01,0x1B,0xFF, \ + 0x00,0x01,0x1B,0xFF \ +} +#endif /* ((DPAA_VERSION == 10) && defined(FM_CAPWAP_SUPPORT)) */ + +#if (DPAA_VERSION == 10) +/* Version: 106.1.9 */ +#define SW_PRS_OFFLOAD_PATCH \ +{ \ + 0x31,0x52,0x00,0xDA,0x0A,0x00,0x00,0x00,0x00,0x00, \ + 0x00,0x00,0x43,0x0A,0x00,0x00,0x00,0x01,0x1B,0xFE, \ + 0x00,0x00,0x99,0x00,0x53,0x13,0x00,0x00,0x00,0x00, \ + 0x9F,0x98,0x53,0x13,0x00,0x00,0x1B,0x23,0x33,0xF1, \ + 0x00,0xF9,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00, \ + 0x28,0x7F,0x00,0x03,0x00,0x02,0x00,0x00,0x00,0x01, \ + 0x32,0xC1,0x32,0xF0,0x00,0x4A,0x00,0x80,0x1F,0xFF, \ + 0x00,0x01,0x1B,0xFE,0x31,0x52,0x00,0xDA,0x06,0x00, \ + 0x00,0x00,0x00,0x00,0x00,0x00,0x43,0x2F,0x00,0x00, \ + 0x00,0x01,0x1B,0xFE,0x31,0x52,0x00,0xDA,0x00,0x40, \ + 0x00,0x00,0x00,0x00,0x00,0x00,0x53,0x95,0x00,0x00, \ + 0x00,0x00,0x9B,0x8F,0x2F,0x0F,0x32,0xC1,0x00,0x55, \ + 0x00,0x28,0x28,0x43,0x30,0x7E,0x43,0x45,0x00,0x00, \ + 0x30,0x7E,0x43,0x45,0x00,0x3C,0x1B,0x5D,0x32,0x11, \ + 0x32,0xC0,0x00,0x4F,0x00,0x81,0x00,0x00,0x83,0x8F, \ + 0x2F,0x0F,0x06,0x00,0x32,0x11,0x32,0xC0,0x00,0x4F, \ + 0x00,0x55,0x00,0x01,0x00,0x81,0x32,0x11,0x00,0x00, \ + 0x83,0x8E,0x00,0x50,0x00,0x01,0x01,0x04,0x00,0x4D, \ + 0x28,0x43,0x06,0x00,0x1B,0x3E,0x30,0x7E,0x53,0x79, \ + 0x00,0x2B,0x32,0x11,0x32,0xC0,0x00,0x4F,0x00,0x81, \ + 0x00,0x00,0x87,0x8F,0x28,0x23,0x06,0x00,0x32,0x11, \ + 0x32,0xC0,0x00,0x4F,0x00,0x55,0x00,0x01,0x00,0x81, \ + 0x32,0x11,0x00,0x00,0x83,0x8E,0x00,0x50,0x00,0x01, \ + 0x01,0x04,0x00,0x4D,0x28,0x43,0x06,0x00,0x00,0x01, \ + 0x1B,0xFE,0x00,0x00,0x9B,0x8E,0x53,0x90,0x00,0x00, \ + 0x06,0x29,0x00,0x00,0x83,0x8F,0x28,0x23,0x06,0x00, \ + 0x06,0x29,0x32,0xC1,0x00,0x55,0x00,0x28,0x00,0x00, \ + 0x83,0x8E,0x00,0x50,0x00,0x01,0x01,0x04,0x00,0x4D, \ + 0x28,0x43,0x06,0x00,0x00,0x01,0x1B,0xFE,0x32,0xC1, \ + 0x00,0x55,0x00,0x28,0x28,0x43,0x1B,0xCF,0x00,0x00, \ + 0x9B,0x8F,0x2F,0x0F,0x32,0xC1,0x00,0x55,0x00,0x28, \ + 0x28,0x43,0x30,0x7E,0x43,0xBF,0x00,0x2C,0x32,0x11, \ + 0x32,0xC0,0x00,0x4F,0x00,0x81,0x00,0x00,0x87,0x8F, \ + 0x28,0x23,0x06,0x00,0x32,0x11,0x32,0xC0,0x00,0x4F, \ + 0x00,0x81,0x00,0x00,0x83,0x8F,0x2F,0x0F,0x06,0x00, \ + 0x32,0x11,0x32,0xC0,0x00,0x4F,0x00,0x55,0x00,0x01, \ + 0x00,0x81,0x32,0x11,0x00,0x00,0x83,0x8E,0x00,0x50, \ + 0x00,0x01,0x01,0x04,0x00,0x4D,0x28,0x43,0x06,0x00, \ + 0x1B,0x9C,0x33,0xF1,0x00,0xF9,0x00,0x01,0x00,0x00, \ + 0x00,0x00,0x00,0x00,0x28,0x7F,0x00,0x03,0x00,0x02, \ + 0x00,0x00,0x00,0x01,0x32,0xC1,0x32,0xF0,0x00,0x4A, \ + 0x00,0x80,0x1F,0xFF,0x00,0x01,0x1B,0xFE, \ +} + +#else +#define SW_PRS_OFFLOAD_PATCH \ +{ \ + 0x31,0x52,0x00,0xDA,0x0E,0x4F,0x00,0x00,0x00,0x00, \ + 0x00,0x00,0x51,0x16,0x08,0x4B,0x31,0x53,0x00,0xFB, \ + 0xFF,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x29,0x2B, \ + 0x33,0xF1,0x00,0xFB,0x00,0xDF,0x00,0x00,0x00,0x00, \ + 0x00,0x00,0x28,0x7F,0x31,0x52,0x00,0xDA,0x0A,0x00, \ + 0x00,0x00,0x00,0x00,0x00,0x00,0x41,0x20,0x00,0x00, \ + 0x00,0x01,0x1B,0xFE,0x00,0x00,0x99,0x00,0x51,0x29, \ + 0x00,0x00,0x00,0x00,0x9F,0x98,0x51,0x29,0x00,0x00, \ + 0x19,0x44,0x09,0x5F,0x00,0x20,0x00,0x00,0x09,0x4F, \ + 0x00,0x20,0x00,0x00,0x34,0xB7,0x00,0xF9,0x00,0x00, \ + 0x01,0x00,0x00,0x00,0x00,0x00,0x2B,0x97,0x31,0xB3, \ + 0x29,0x8F,0x33,0xF1,0x00,0xF9,0x00,0x01,0x00,0x00, \ + 0x00,0x00,0x00,0x00,0x28,0x7F,0x00,0x03,0x00,0x02, \ + 0x00,0x00,0x00,0x01,0x1B,0xFE,0x00,0x01,0x1B,0xFE, \ + 0x31,0x52,0x00,0xDA,0xFC,0x00,0x00,0x00,0x00,0x00, \ + 0x00,0x00,0x51,0x52,0x40,0x00,0x31,0x92,0x51,0x52, \ + 0x00,0x88,0x19,0x55,0x08,0x05,0x00,0x00,0x19,0x99, \ + 0x02,0x1F,0x00,0x08,0x00,0x83,0x02,0x1F,0x00,0x20, \ + 0x28,0x1B,0x00,0x05,0x29,0x1F,0x30,0xD0,0x61,0x75, \ + 0x00,0x07,0x00,0x05,0x00,0x00,0xC3,0x8F,0x00,0x52, \ + 0x00,0x01,0x07,0x01,0x61,0x61,0x00,0x00,0x30,0xD0, \ + 0x00,0xDA,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00, \ + 0x41,0x72,0x00,0x00,0x02,0x8F,0x00,0x00,0x30,0xF2, \ + 0x00,0x06,0x19,0x83,0x00,0x00,0x9F,0xFF,0x30,0xF2, \ + 0x00,0x06,0x29,0x1E,0x07,0x08,0x30,0xD0,0x00,0x52, \ + 0x00,0x08,0x28,0x1A,0x61,0x5D,0x00,0x00,0x30,0xF2, \ + 0x19,0x83,0x06,0x00,0x29,0x1E,0x30,0xF2,0x29,0x0E, \ + 0x30,0x72,0x00,0x00,0x9B,0x8F,0x00,0x06,0x29,0x0E, \ + 0x32,0xF1,0x32,0xB0,0x00,0x4F,0x00,0x57,0x00,0x28, \ + 0x00,0x00,0x97,0x9E,0x00,0x4E,0x30,0x72,0x00,0x06, \ + 0x29,0x0E,0x08,0x05,0x00,0x01,0x31,0x52,0x00,0xDA, \ + 0x0E,0x4F,0x00,0x00,0x00,0x00,0x00,0x00,0x51,0xAF, \ + 0x04,0x4B,0x31,0x53,0x00,0xFB,0xFF,0xF0,0x00,0x00, \ + 0x00,0x00,0x00,0x00,0x29,0x2B,0x33,0xF1,0x00,0xFB, \ + 0x00,0xDF,0x00,0x00,0x00,0x00,0x00,0x00,0x28,0x7F, \ + 0x31,0x52,0x00,0xDA,0x06,0x00,0x00,0x00,0x00,0x00, \ + 0x00,0x00,0x41,0xB9,0x00,0x00,0x00,0x01,0x1B,0xFE, \ + 0x31,0x52,0x00,0xDA,0x00,0x40,0x00,0x00,0x00,0x00, \ + 0x00,0x00,0x42,0x06,0x00,0x00,0x00,0x00,0x9B,0x8F, \ + 0x28,0x01,0x32,0xC1,0x00,0x55,0x00,0x28,0x28,0x43, \ + 0x30,0x00,0x41,0xEB,0x00,0x2C,0x32,0x11,0x32,0xC0, \ + 0x00,0x4F,0x00,0x81,0x00,0x00,0x87,0x8F,0x28,0x23, \ + 0x06,0x00,0x32,0x11,0x32,0xC0,0x00,0x4F,0x00,0x81, \ + 0x00,0x00,0x83,0x8F,0x28,0x01,0x06,0x00,0x32,0x11, \ + 0x32,0xC0,0x00,0x4F,0x00,0x55,0x00,0x01,0x00,0x81, \ + 0x32,0x11,0x00,0x00,0x83,0x8E,0x00,0x50,0x00,0x01, \ + 0x01,0x04,0x00,0x4D,0x28,0x43,0x06,0x00,0x19,0xC8, \ + 0x09,0x5F,0x00,0x20,0x00,0x00,0x09,0x4F,0x00,0x20, \ + 0x00,0x00,0x34,0xB7,0x00,0xF9,0x00,0x00,0x01,0x00, \ + 0x00,0x00,0x00,0x00,0x2B,0x97,0x31,0xB3,0x29,0x8F, \ + 0x33,0xF1,0x00,0xF9,0x00,0x01,0x00,0x00,0x00,0x00, \ + 0x00,0x00,0x28,0x7F,0x00,0x03,0x00,0x02,0x00,0x00, \ + 0x00,0x01,0x1B,0xFE,0x30,0x50,0x52,0x0B,0x00,0x00, \ + 0x00,0x01,0x1B,0xFE,0x32,0xF1,0x32,0xC0,0x00,0x4F, \ + 0x00,0x81,0x00,0x02,0x00,0x00,0x97,0x9E,0x42,0x18, \ + 0x00,0x08,0x08,0x16,0x00,0x54,0x00,0x01,0x1B,0xFE, \ + 0x00,0x00,0x9F,0x9E,0x42,0x4D,0x00,0x00,0x02,0x1F, \ + 0x00,0x08,0x28,0x1B,0x30,0x73,0x29,0x1F,0x30,0xD0, \ + 0x62,0x39,0x00,0x07,0x00,0x05,0x00,0x00,0xC3,0x8F, \ + 0x00,0x52,0x00,0x01,0x07,0x01,0x62,0x25,0x00,0x00, \ + 0x30,0xD0,0x00,0xDA,0x00,0x01,0x00,0x00,0x00,0x00, \ + 0x00,0x00,0x42,0x36,0x00,0x00,0x02,0x8F,0x00,0x00, \ + 0x30,0xF2,0x00,0x06,0x1A,0x47,0x00,0x00,0x9F,0xFF, \ + 0x30,0xF2,0x00,0x06,0x29,0x1E,0x07,0x08,0x30,0xD0, \ + 0x00,0x52,0x00,0x08,0x28,0x1A,0x62,0x21,0x00,0x00, \ + 0x30,0xF2,0x1A,0x47,0x06,0x00,0x29,0x1E,0x30,0xF2, \ + 0x52,0x4D,0xFF,0xFF,0x1A,0x52,0x08,0x16,0x00,0x54, \ + 0x00,0x01,0x1B,0xFE,0x1A,0x5F,0x32,0xF1,0x28,0x5D, \ + 0x32,0xF1,0x00,0x55,0x00,0x08,0x28,0x5F,0x00,0x00, \ + 0x8F,0x9F,0x29,0x33,0x08,0x16,0x00,0x49,0x00,0x01, \ + 0x1B,0xFF,0x00,0x01,0x1B,0xFF,0x31,0x52,0x00,0xDA, \ + 0xFC,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x52,0x6D, \ + 0x40,0x00,0x31,0x92,0x52,0x6D,0x00,0x88,0x1A,0x70, \ + 0x08,0x05,0x00,0x00,0x1A,0xB4,0x02,0x1F,0x00,0x08, \ + 0x00,0x83,0x02,0x1F,0x00,0x20,0x28,0x1B,0x00,0x05, \ + 0x29,0x1F,0x30,0xD0,0x62,0x90,0x00,0x07,0x00,0x05, \ + 0x00,0x00,0xC3,0x8F,0x00,0x52,0x00,0x01,0x07,0x01, \ + 0x62,0x7C,0x00,0x00,0x30,0xD0,0x00,0xDA,0x00,0x01, \ + 0x00,0x00,0x00,0x00,0x00,0x00,0x42,0x8D,0x00,0x00, \ + 0x02,0x8F,0x00,0x00,0x30,0xF2,0x00,0x06,0x1A,0x9E, \ + 0x00,0x00,0x9F,0xFF,0x30,0xF2,0x00,0x06,0x29,0x1E, \ + 0x07,0x08,0x30,0xD0,0x00,0x52,0x00,0x08,0x28,0x1A, \ + 0x62,0x78,0x00,0x00,0x30,0xF2,0x1A,0x9E,0x06,0x00, \ + 0x29,0x1E,0x30,0xF2,0x29,0x0E,0x30,0x72,0x00,0x00, \ + 0x9B,0x8F,0x00,0x06,0x29,0x0E,0x32,0xF1,0x32,0xB0, \ + 0x00,0x4F,0x00,0x57,0x00,0x28,0x00,0x00,0x97,0x9E, \ + 0x00,0x4E,0x30,0x72,0x00,0x06,0x29,0x0E,0x08,0x05, \ + 0x00,0x01,0x31,0x52,0x00,0xDA,0x0E,0x4F,0x00,0x00, \ + 0x00,0x00,0x00,0x00,0x52,0xCA,0x04,0x4B,0x31,0x53, \ + 0x00,0xFB,0xFF,0xF0,0x00,0x00,0x00,0x00,0x00,0x00, \ + 0x29,0x2B,0x33,0xF1,0x00,0xFB,0x00,0xDF,0x00,0x00, \ + 0x00,0x00,0x00,0x00,0x28,0x7F,0x31,0x52,0x00,0xDA, \ + 0x06,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x42,0xD4, \ + 0x00,0x00,0x00,0x01,0x1B,0xFE,0x31,0x52,0x00,0xDA, \ + 0x00,0x40,0x00,0x00,0x00,0x00,0x00,0x00,0x53,0x37, \ + 0x00,0x00,0x00,0x00,0x9B,0x8F,0x28,0x01,0x32,0xC1, \ + 0x00,0x55,0x00,0x28,0x28,0x43,0x30,0x00,0x42,0xEA, \ + 0x00,0x00,0x30,0x00,0x42,0xEA,0x00,0x3C,0x1B,0x02, \ + 0x32,0x11,0x32,0xC0,0x00,0x4F,0x00,0x81,0x00,0x00, \ + 0x83,0x8F,0x28,0x01,0x06,0x00,0x32,0x11,0x32,0xC0, \ + 0x00,0x4F,0x00,0x55,0x00,0x01,0x00,0x81,0x32,0x11, \ + 0x00,0x00,0x83,0x8E,0x00,0x50,0x00,0x01,0x01,0x04, \ + 0x00,0x4D,0x28,0x43,0x06,0x00,0x1A,0xE3,0x30,0x00, \ + 0x43,0x20,0x00,0x2B,0x00,0x00,0x9B,0x8E,0x43,0x0E, \ + 0x00,0x00,0x32,0xC1,0x00,0x55,0x00,0x28,0x28,0x43, \ + 0x1B,0x1F,0x06,0x29,0x00,0x00,0x83,0x8F,0x28,0x23, \ + 0x06,0x00,0x06,0x29,0x32,0xC1,0x00,0x55,0x00,0x28, \ + 0x00,0x00,0x83,0x8E,0x00,0x50,0x00,0x01,0x01,0x04, \ + 0x00,0x4D,0x28,0x43,0x06,0x00,0x1B,0x37,0x32,0x11, \ + 0x32,0xC0,0x00,0x4F,0x00,0x81,0x00,0x00,0x87,0x8F, \ + 0x28,0x23,0x06,0x00,0x32,0x11,0x32,0xC0,0x00,0x4F, \ + 0x00,0x55,0x00,0x01,0x00,0x81,0x32,0x11,0x00,0x00, \ + 0x83,0x8E,0x00,0x50,0x00,0x01,0x01,0x04,0x00,0x4D, \ + 0x28,0x43,0x06,0x00,0x30,0x50,0x53,0x3C,0x00,0x00, \ + 0x00,0x01,0x1B,0xFE,0x32,0xF1,0x32,0xC0,0x00,0x4F, \ + 0x00,0x81,0x00,0x02,0x00,0x00,0x97,0x9E,0x43,0x49, \ + 0x00,0x08,0x08,0x16,0x00,0x54,0x00,0x01,0x1B,0xFE, \ + 0x00,0x00,0x9F,0x9E,0x43,0x7E,0x00,0x00,0x02,0x1F, \ + 0x00,0x08,0x28,0x1B,0x30,0x73,0x29,0x1F,0x30,0xD0, \ + 0x63,0x6A,0x00,0x07,0x00,0x05,0x00,0x00,0xC3,0x8F, \ + 0x00,0x52,0x00,0x01,0x07,0x01,0x63,0x56,0x00,0x00, \ + 0x30,0xD0,0x00,0xDA,0x00,0x01,0x00,0x00,0x00,0x00, \ + 0x00,0x00,0x43,0x67,0x00,0x00,0x02,0x8F,0x00,0x00, \ + 0x30,0xF2,0x00,0x06,0x1B,0x78,0x00,0x00,0x9F,0xFF, \ + 0x30,0xF2,0x00,0x06,0x29,0x1E,0x07,0x08,0x30,0xD0, \ + 0x00,0x52,0x00,0x08,0x28,0x1A,0x63,0x52,0x00,0x00, \ + 0x30,0xF2,0x1B,0x78,0x06,0x00,0x29,0x1E,0x30,0xF2, \ + 0x53,0x7E,0xFF,0xFF,0x1B,0x83,0x08,0x16,0x00,0x54, \ + 0x00,0x01,0x1B,0xFE,0x1B,0x90,0x32,0xF1,0x28,0x5D, \ + 0x32,0xF1,0x00,0x55,0x00,0x08,0x28,0x5F,0x00,0x00, \ + 0x8F,0x9F,0x29,0x33,0x08,0x16,0x00,0x49,0x00,0x01, \ + 0x1B,0xFF,0x00,0x01,0x1B,0xFF,0x08,0x07,0x00,0x02, \ + 0x00,0x00,0x8D,0x80,0x53,0x9C,0x00,0x01,0x30,0x71, \ + 0x00,0x55,0x00,0x01,0x28,0x0F,0x00,0x00,0x8D,0x00, \ + 0x53,0xA4,0x00,0x01,0x30,0x71,0x00,0x55,0x00,0x01, \ + 0x28,0x0F,0x00,0x00,0x83,0x8E,0x53,0xB9,0x00,0x00, \ + 0x00,0x00,0x86,0x08,0x30,0x71,0x00,0x7B,0x03,0xB9, \ + 0x33,0xB4,0x00,0xDA,0xFF,0xFF,0x00,0x0F,0x00,0x00, \ + 0x00,0x00,0x00,0x00,0x86,0x09,0x01,0x03,0x00,0x7D, \ + 0x03,0xB9,0x1B,0xC8,0x33,0xD1,0x00,0xF9,0x00,0x10, \ + 0x00,0x00,0x00,0x00,0x00,0x00,0x28,0x7B,0x09,0x5F, \ + 0x00,0x1A,0x00,0x00,0x09,0x4F,0x00,0x1A,0x00,0x00, \ + 0x00,0x01,0x1B,0xFF,0x00,0x00,0x8C,0x00,0x53,0xF0, \ + 0x00,0x01,0x34,0xF5,0x00,0xFB,0xFF,0xFF,0x00,0x7F, \ + 0x00,0x00,0x00,0x00,0x2A,0x9F,0x00,0x00,0x93,0x8F, \ + 0x28,0x49,0x00,0x00,0x97,0x8F,0x28,0x4B,0x34,0x61, \ + 0x28,0x4D,0x34,0x71,0x28,0x4F,0x34,0xB7,0x00,0xF9, \ + 0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x2B,0x97, \ + 0x33,0xF1,0x00,0xF9,0x00,0x01,0x00,0x00,0x00,0x00, \ + 0x00,0x00,0x28,0x7F,0x00,0x03,0x00,0x02,0x00,0x00, \ + 0x00,0x01,0x1B,0xFF,0x00,0x01,0x1B,0xFF, \ +} +#endif /* (DPAA_VERSION == 10) */ + +/****************************/ +/* Parser defines */ +/****************************/ +#define FM_PCD_PRS_SW_TAIL_SIZE 4 /**< Number of bytes that must be cleared at + the end of the SW parser area */ + +/* masks */ +#define PRS_ERR_CAP 0x80000000 +#define PRS_ERR_TYPE_DOUBLE 0x40000000 +#define PRS_ERR_SINGLE_ECC_CNT_MASK 0x00FF0000 +#define PRS_ERR_ADDR_MASK 0x000001FF + +/* others */ +#define PRS_MAX_CYCLE_LIMIT 8191 +#define PRS_SW_DATA 0x00000800 +#define PRS_REGS_OFFSET 0x00000840 + +#define GET_FM_PCD_PRS_PORT_ID(prsPortId,hardwarePortId) \ + prsPortId = (uint8_t)(hardwarePortId & 0x0f) + +#define GET_FM_PCD_INDEX_FLAG(bitMask, prsPortId) \ + bitMask = 0x80000000>>prsPortId + +#endif /* __FM_PRS_H */ diff --git a/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Pcd/fm_replic.c b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Pcd/fm_replic.c new file mode 100644 index 000000000000..ee82f73014b6 --- /dev/null +++ b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Pcd/fm_replic.c @@ -0,0 +1,984 @@ +/* + * Copyright 2008-2012 Freescale Semiconductor Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Freescale Semiconductor nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * + * ALTERNATIVELY, this software may be distributed under the terms of the + * GNU General Public License ("GPL") as published by the Free Software + * Foundation, either version 2 of that License or (at your option) any + * later version. + * + * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + +/****************************************************************************** + @File fm_replic.c + + @Description FM frame replicator +*//***************************************************************************/ +#include "std_ext.h" +#include "error_ext.h" +#include "string_ext.h" +#include "debug_ext.h" +#include "fm_pcd_ext.h" +#include "fm_muram_ext.h" +#include "fm_common.h" +#include "fm_hc.h" +#include "fm_replic.h" +#include "fm_cc.h" +#include "list_ext.h" + + +/****************************************/ +/* static functions */ +/****************************************/ +static uint8_t GetMemberPosition(t_FmPcdFrmReplicGroup *p_ReplicGroup, + uint32_t memberIndex, + bool isAddOperation) +{ + uint8_t memberPosition; + uint32_t lastMemberIndex; + + ASSERT_COND(p_ReplicGroup); + + /* the last member index is different between add and remove operation - + in case of remove - this is exactly the last member index + in case of add - this is the last member index + 1 - e.g. + if we have 4 members, the index of the actual last member is 3(because the + index starts from 0) therefore in order to add a new member as the last + member we shall use memberIndex = 4 and not 3 + */ + if (isAddOperation) + lastMemberIndex = p_ReplicGroup->numOfEntries; + else + lastMemberIndex = p_ReplicGroup->numOfEntries-1; + + /* last */ + if (memberIndex == lastMemberIndex) + memberPosition = FRM_REPLIC_LAST_MEMBER_INDEX; + else + { + /* first */ + if (memberIndex == 0) + memberPosition = FRM_REPLIC_FIRST_MEMBER_INDEX; + else + { + /* middle */ + ASSERT_COND(memberIndex < lastMemberIndex); + memberPosition = FRM_REPLIC_MIDDLE_MEMBER_INDEX; + } + } + return memberPosition; +} + +static t_Error MemberCheckParams(t_Handle h_FmPcd, + t_FmPcdCcNextEngineParams *p_MemberParams) +{ + t_Error err; + + + if ((p_MemberParams->nextEngine != e_FM_PCD_DONE) && + (p_MemberParams->nextEngine != e_FM_PCD_KG) && + (p_MemberParams->nextEngine != e_FM_PCD_PLCR)) + RETURN_ERROR(MAJOR, E_NOT_SUPPORTED, ("Next engine of a member should be MatchTable(cc) or Done or Policer")); + + /* check the regular parameters of the next engine */ + err = ValidateNextEngineParams(h_FmPcd, p_MemberParams, e_FM_PCD_CC_STATS_MODE_NONE); + if (err) + RETURN_ERROR(MAJOR, err, ("member next engine parameters")); + + return E_OK; +} + +static t_Error CheckParams(t_Handle h_FmPcd, + t_FmPcdFrmReplicGroupParams *p_ReplicGroupParam) +{ + int i; + t_Error err; + + /* check that max num of entries is at least 2 */ + if (!IN_RANGE(2, p_ReplicGroupParam->maxNumOfEntries, FM_PCD_FRM_REPLIC_MAX_NUM_OF_ENTRIES)) + RETURN_ERROR(MAJOR, E_NOT_IN_RANGE, ("maxNumOfEntries in the frame replicator parameters should be 2-%d",FM_PCD_FRM_REPLIC_MAX_NUM_OF_ENTRIES)); + + /* check that number of entries is greater than zero */ + if (!p_ReplicGroupParam->numOfEntries) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("numOFEntries in the frame replicator group should be greater than zero")); + + /* check that max num of entries is equal or greater than number of entries */ + if (p_ReplicGroupParam->maxNumOfEntries < p_ReplicGroupParam->numOfEntries) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("maxNumOfEntries should be equal or greater than numOfEntries")); + + for (i=0; i<p_ReplicGroupParam->numOfEntries; i++) + { + err = MemberCheckParams(h_FmPcd, &p_ReplicGroupParam->nextEngineParams[i]); + if (err) + RETURN_ERROR(MAJOR, err, ("member check parameters")); + } + return E_OK; +} + +static t_FmPcdFrmReplicMember *GetAvailableMember(t_FmPcdFrmReplicGroup *p_ReplicGroup) +{ + t_FmPcdFrmReplicMember *p_ReplicMember = NULL; + t_List *p_Next; + + if (!LIST_IsEmpty(&p_ReplicGroup->availableMembersList)) + { + p_Next = LIST_FIRST(&p_ReplicGroup->availableMembersList); + p_ReplicMember = LIST_OBJECT(p_Next, t_FmPcdFrmReplicMember, node); + ASSERT_COND(p_ReplicMember); + LIST_DelAndInit(p_Next); + } + return p_ReplicMember; +} + +static void PutAvailableMember(t_FmPcdFrmReplicGroup *p_ReplicGroup, + t_FmPcdFrmReplicMember *p_ReplicMember) +{ + LIST_AddToTail(&p_ReplicMember->node, &p_ReplicGroup->availableMembersList); +} + +static void AddMemberToList(t_FmPcdFrmReplicGroup *p_ReplicGroup, + t_FmPcdFrmReplicMember *p_CurrentMember, + t_List *p_ListHead) +{ + LIST_Add(&p_CurrentMember->node, p_ListHead); + + p_ReplicGroup->numOfEntries++; +} + +static void RemoveMemberFromList(t_FmPcdFrmReplicGroup *p_ReplicGroup, + t_FmPcdFrmReplicMember *p_CurrentMember) +{ + ASSERT_COND(p_ReplicGroup->numOfEntries); + LIST_DelAndInit(&p_CurrentMember->node); + p_ReplicGroup->numOfEntries--; +} + +static void LinkSourceToMember(t_FmPcdFrmReplicGroup *p_ReplicGroup, + t_AdOfTypeContLookup *p_SourceTd, + t_FmPcdFrmReplicMember *p_ReplicMember) +{ + t_FmPcd *p_FmPcd; + + ASSERT_COND(p_SourceTd); + ASSERT_COND(p_ReplicMember); + ASSERT_COND(p_ReplicGroup); + ASSERT_COND(p_ReplicGroup->h_FmPcd); + + /* Link the first member in the group to the source TD */ + p_FmPcd = p_ReplicGroup->h_FmPcd; + + WRITE_UINT32(p_SourceTd->matchTblPtr, + (uint32_t)(XX_VirtToPhys(p_ReplicMember->p_MemberAd) - + p_FmPcd->physicalMuramBase)); +} + +static void LinkMemberToMember(t_FmPcdFrmReplicGroup *p_ReplicGroup, + t_FmPcdFrmReplicMember *p_CurrentMember, + t_FmPcdFrmReplicMember *p_NextMember) +{ + t_AdOfTypeResult *p_CurrReplicAd = (t_AdOfTypeResult*)p_CurrentMember->p_MemberAd; + t_AdOfTypeResult *p_NextReplicAd = NULL; + t_FmPcd *p_FmPcd; + uint32_t offset = 0; + + /* Check if the next member exists or it's NULL (- means that this is the last member) */ + if (p_NextMember) + { + p_NextReplicAd = (t_AdOfTypeResult*)p_NextMember->p_MemberAd; + p_FmPcd = p_ReplicGroup->h_FmPcd; + offset = (XX_VirtToPhys(p_NextReplicAd) - (p_FmPcd->physicalMuramBase)); + offset = ((offset>>NEXT_FRM_REPLIC_ADDR_SHIFT)<< NEXT_FRM_REPLIC_MEMBER_INDEX_SHIFT); + } + + /* link the current AD to point to the AD of the next member */ + WRITE_UINT32(p_CurrReplicAd->res, offset); +} + +static t_Error ModifyDescriptor(t_FmPcdFrmReplicGroup *p_ReplicGroup, + void *p_OldDescriptor, + void *p_NewDescriptor) +{ + t_Handle h_Hc; + t_Error err; + t_FmPcd *p_FmPcd; + + ASSERT_COND(p_ReplicGroup); + ASSERT_COND(p_ReplicGroup->h_FmPcd); + ASSERT_COND(p_OldDescriptor); + ASSERT_COND(p_NewDescriptor); + + p_FmPcd = p_ReplicGroup->h_FmPcd; + h_Hc = FmPcdGetHcHandle(p_FmPcd); + if (!h_Hc) + RETURN_ERROR(MAJOR, E_INVALID_HANDLE, ("Host command")); + + err = FmHcPcdCcDoDynamicChange(h_Hc, + (uint32_t)(XX_VirtToPhys(p_OldDescriptor) - p_FmPcd->physicalMuramBase), + (uint32_t)(XX_VirtToPhys(p_NewDescriptor) - p_FmPcd->physicalMuramBase)); + if (err) + RETURN_ERROR(MAJOR, err, ("Dynamic change host command")); + + return E_OK; +} + +static void FillReplicAdOfTypeResult(void *p_ReplicAd, bool last) +{ + t_AdOfTypeResult *p_CurrReplicAd = (t_AdOfTypeResult*)p_ReplicAd; + uint32_t tmp; + + tmp = GET_UINT32(p_CurrReplicAd->plcrProfile); + if (last) + /* clear the NL bit in case it's the last member in the group*/ + WRITE_UINT32(p_CurrReplicAd->plcrProfile,(tmp & ~FRM_REPLIC_NL_BIT)); + else + /* set the NL bit in case it's not the last member in the group */ + WRITE_UINT32(p_CurrReplicAd->plcrProfile, (tmp |FRM_REPLIC_NL_BIT)); + + /* set FR bit in the action descriptor */ + tmp = GET_UINT32(p_CurrReplicAd->nia); + WRITE_UINT32(p_CurrReplicAd->nia, + (tmp | FRM_REPLIC_FR_BIT | FM_PCD_AD_RESULT_EXTENDED_MODE )); +} + +static void BuildSourceTd(void *p_Ad) +{ + t_AdOfTypeContLookup *p_SourceTd; + + ASSERT_COND(p_Ad); + + p_SourceTd = (t_AdOfTypeContLookup *)p_Ad; + + IOMemSet32((uint8_t*)p_SourceTd, 0, FM_PCD_CC_AD_ENTRY_SIZE); + + /* initialize the source table descriptor */ + WRITE_UINT32(p_SourceTd->ccAdBase, FM_PCD_AD_CONT_LOOKUP_TYPE); + WRITE_UINT32(p_SourceTd->pcAndOffsets, FRM_REPLIC_SOURCE_TD_OPCODE); +} + +static t_Error BuildShadowAndModifyDescriptor(t_FmPcdFrmReplicGroup *p_ReplicGroup, + t_FmPcdFrmReplicMember *p_NextMember, + t_FmPcdFrmReplicMember *p_CurrentMember, + bool sourceDescriptor, + bool last) +{ + t_FmPcd *p_FmPcd; + t_FmPcdFrmReplicMember shadowMember; + t_Error err; + + ASSERT_COND(p_ReplicGroup); + ASSERT_COND(p_ReplicGroup->h_FmPcd); + + p_FmPcd = p_ReplicGroup->h_FmPcd; + ASSERT_COND(p_FmPcd->p_CcShadow); + + if (!TRY_LOCK(p_FmPcd->h_ShadowSpinlock, &p_FmPcd->shadowLock)) + return ERROR_CODE(E_BUSY); + + if (sourceDescriptor) + { + BuildSourceTd(p_FmPcd->p_CcShadow); + LinkSourceToMember(p_ReplicGroup, p_FmPcd->p_CcShadow, p_NextMember); + + /* Modify the source table descriptor according to the prepared shadow descriptor */ + err = ModifyDescriptor(p_ReplicGroup, + p_ReplicGroup->p_SourceTd, + p_FmPcd->p_CcShadow/* new prepared source td */); + + RELEASE_LOCK(p_FmPcd->shadowLock); + if (err) + RETURN_ERROR(MAJOR, err, ("Modify source Descriptor in BuildShadowAndModifyDescriptor")); + + } + else + { + IO2IOCpy32(p_FmPcd->p_CcShadow, + p_CurrentMember->p_MemberAd, + FM_PCD_CC_AD_ENTRY_SIZE); + + /* update the last bit in the shadow ad */ + FillReplicAdOfTypeResult(p_FmPcd->p_CcShadow, last); + + shadowMember.p_MemberAd = p_FmPcd->p_CcShadow; + + /* update the next FR member index */ + LinkMemberToMember(p_ReplicGroup, &shadowMember, p_NextMember); + + /* Modify the next member according to the prepared shadow descriptor */ + err = ModifyDescriptor(p_ReplicGroup, + p_CurrentMember->p_MemberAd, + p_FmPcd->p_CcShadow); + + RELEASE_LOCK(p_FmPcd->shadowLock); + if (err) + RETURN_ERROR(MAJOR, err, ("Modify Descriptor in BuildShadowAndModifyDescriptor")); + } + + + return E_OK; +} + +static t_FmPcdFrmReplicMember* GetMemberByIndex(t_FmPcdFrmReplicGroup *p_ReplicGroup, + uint16_t memberIndex) +{ + int i=0; + t_List *p_Pos; + t_FmPcdFrmReplicMember *p_Member = NULL; + + LIST_FOR_EACH(p_Pos, &p_ReplicGroup->membersList) + { + if (i == memberIndex) + { + p_Member = LIST_OBJECT(p_Pos, t_FmPcdFrmReplicMember, node); + return p_Member; + } + i++; + } + return p_Member; +} + +static t_Error AllocMember(t_FmPcdFrmReplicGroup *p_ReplicGroup) +{ + t_FmPcdFrmReplicMember *p_CurrentMember; + t_Handle h_Muram; + + ASSERT_COND(p_ReplicGroup); + + h_Muram = FmPcdGetMuramHandle(p_ReplicGroup->h_FmPcd); + ASSERT_COND(h_Muram); + + /* Initialize an internal structure of a member to add to the available members list */ + p_CurrentMember = (t_FmPcdFrmReplicMember *)XX_Malloc(sizeof(t_FmPcdFrmReplicMember)); + if (!p_CurrentMember) + RETURN_ERROR(MAJOR, E_NO_MEMORY, ("Frame replicator member")); + + memset(p_CurrentMember, 0 ,sizeof(t_FmPcdFrmReplicMember)); + + /* Allocate the member AD */ + p_CurrentMember->p_MemberAd = + (t_AdOfTypeResult*)FM_MURAM_AllocMem(h_Muram, + FM_PCD_CC_AD_ENTRY_SIZE, + FM_PCD_CC_AD_TABLE_ALIGN); + if (!p_CurrentMember->p_MemberAd) + { + XX_Free(p_CurrentMember); + RETURN_ERROR(MAJOR, E_NO_MEMORY, ("member AD table")); + } + IOMemSet32((uint8_t*)p_CurrentMember->p_MemberAd, 0, FM_PCD_CC_AD_ENTRY_SIZE); + + /* Add the new member to the available members list */ + LIST_AddToTail(&p_CurrentMember->node, &(p_ReplicGroup->availableMembersList)); + + return E_OK; +} + +static t_FmPcdFrmReplicMember* InitMember(t_FmPcdFrmReplicGroup *p_ReplicGroup, + t_FmPcdCcNextEngineParams *p_MemberParams, + bool last) +{ + t_FmPcdFrmReplicMember *p_CurrentMember = NULL; + + ASSERT_COND(p_ReplicGroup); + + /* Get an available member from the internal members list */ + p_CurrentMember = GetAvailableMember(p_ReplicGroup); + if (!p_CurrentMember) + { + REPORT_ERROR(MAJOR, E_NOT_FOUND, ("Available member")); + return NULL; + } + p_CurrentMember->h_Manip = NULL; + + /* clear the Ad of the new member */ + IOMemSet32((uint8_t*)p_CurrentMember->p_MemberAd, 0, FM_PCD_CC_AD_ENTRY_SIZE); + + INIT_LIST(&p_CurrentMember->node); + + /* Initialize the Ad of the member */ + NextStepAd(p_CurrentMember->p_MemberAd, + NULL, + p_MemberParams, + p_ReplicGroup->h_FmPcd); + + /* save Manip handle (for free needs) */ + if (p_MemberParams->h_Manip) + p_CurrentMember->h_Manip = p_MemberParams->h_Manip; + + /* Initialize the relevant frame replicator fields in the AD */ + FillReplicAdOfTypeResult(p_CurrentMember->p_MemberAd, last); + + return p_CurrentMember; +} + +static void FreeMember(t_FmPcdFrmReplicGroup *p_ReplicGroup, + t_FmPcdFrmReplicMember *p_Member) +{ + /* Note: Can't free the member AD just returns the member to the available + member list - therefore only memset the AD */ + + /* zero the AD */ + IOMemSet32(p_Member->p_MemberAd, 0, FM_PCD_CC_AD_ENTRY_SIZE); + + + /* return the member to the available members list */ + PutAvailableMember(p_ReplicGroup, p_Member); +} + +static t_Error RemoveMember(t_FmPcdFrmReplicGroup *p_ReplicGroup, + uint16_t memberIndex) +{ + t_FmPcd *p_FmPcd = NULL; + t_FmPcdFrmReplicMember *p_CurrentMember = NULL, *p_PreviousMember = NULL, *p_NextMember = NULL; + t_Error err; + uint8_t memberPosition; + + p_FmPcd = p_ReplicGroup->h_FmPcd; + ASSERT_COND(p_FmPcd); + UNUSED(p_FmPcd); + + p_CurrentMember = GetMemberByIndex(p_ReplicGroup, memberIndex); + ASSERT_COND(p_CurrentMember); + + /* determine the member position in the group */ + memberPosition = GetMemberPosition(p_ReplicGroup, + memberIndex, + FALSE/*remove operation*/); + + switch (memberPosition) + { + case FRM_REPLIC_FIRST_MEMBER_INDEX: + p_NextMember = GetMemberByIndex(p_ReplicGroup, (uint16_t)(memberIndex+1)); + ASSERT_COND(p_NextMember); + + /* update the source td itself by using a host command */ + err = BuildShadowAndModifyDescriptor(p_ReplicGroup, + p_NextMember, + NULL, + TRUE/*sourceDescriptor*/, + FALSE/*last*/); + break; + + case FRM_REPLIC_MIDDLE_MEMBER_INDEX: + p_PreviousMember = GetMemberByIndex(p_ReplicGroup, (uint16_t)(memberIndex-1)); + ASSERT_COND(p_PreviousMember); + + p_NextMember = GetMemberByIndex(p_ReplicGroup, (uint16_t)(memberIndex+1)); + ASSERT_COND(p_NextMember); + + err = BuildShadowAndModifyDescriptor(p_ReplicGroup, + p_NextMember, + p_PreviousMember, + FALSE/*sourceDescriptor*/, + FALSE/*last*/); + + break; + + case FRM_REPLIC_LAST_MEMBER_INDEX: + p_PreviousMember = GetMemberByIndex(p_ReplicGroup, (uint16_t)(memberIndex-1)); + ASSERT_COND(p_PreviousMember); + + err = BuildShadowAndModifyDescriptor(p_ReplicGroup, + NULL, + p_PreviousMember, + FALSE/*sourceDescriptor*/, + TRUE/*last*/); + break; + + default: + RETURN_ERROR(MAJOR, E_INVALID_SELECTION, ("member position in remove member")); + } + + if (err) + RETURN_ERROR(MAJOR, err, NO_MSG); + + if (p_CurrentMember->h_Manip) + { + FmPcdManipUpdateOwner(p_CurrentMember->h_Manip, FALSE); + p_CurrentMember->h_Manip = NULL; + } + + /* remove the member from the driver internal members list */ + RemoveMemberFromList(p_ReplicGroup, p_CurrentMember); + + /* return the member to the available members list */ + FreeMember(p_ReplicGroup, p_CurrentMember); + + return E_OK; +} + +static void DeleteGroup(t_FmPcdFrmReplicGroup *p_ReplicGroup) +{ + int i, j; + t_Handle h_Muram; + t_FmPcdFrmReplicMember *p_Member, *p_CurrentMember; + + if (p_ReplicGroup) + { + ASSERT_COND(p_ReplicGroup->h_FmPcd); + h_Muram = FmPcdGetMuramHandle(p_ReplicGroup->h_FmPcd); + ASSERT_COND(h_Muram); + + /* free the source table descriptor */ + if (p_ReplicGroup->p_SourceTd) + { + FM_MURAM_FreeMem(h_Muram, p_ReplicGroup->p_SourceTd); + p_ReplicGroup->p_SourceTd = NULL; + } + + /* Remove all members from the members linked list (hw and sw) and + return the members to the available members list */ + if (p_ReplicGroup->numOfEntries) + { + j = p_ReplicGroup->numOfEntries-1; + + /* manually removal of the member because there are no owners of + this group */ + for (i=j; i>=0; i--) + { + p_CurrentMember = GetMemberByIndex(p_ReplicGroup, (uint16_t)i/*memberIndex*/); + ASSERT_COND(p_CurrentMember); + + if (p_CurrentMember->h_Manip) + { + FmPcdManipUpdateOwner(p_CurrentMember->h_Manip, FALSE); + p_CurrentMember->h_Manip = NULL; + } + + /* remove the member from the internal driver members list */ + RemoveMemberFromList(p_ReplicGroup, p_CurrentMember); + + /* return the member to the available members list */ + FreeMember(p_ReplicGroup, p_CurrentMember); + } + } + + /* Free members AD */ + for (i=0; i<p_ReplicGroup->maxNumOfEntries; i++) + { + p_Member = GetAvailableMember(p_ReplicGroup); + ASSERT_COND(p_Member); + if (p_Member->p_MemberAd) + { + FM_MURAM_FreeMem(h_Muram, p_Member->p_MemberAd); + p_Member->p_MemberAd = NULL; + } + XX_Free(p_Member); + } + + /* release the group lock */ + if (p_ReplicGroup->p_Lock) + FmPcdReleaseLock(p_ReplicGroup->h_FmPcd, p_ReplicGroup->p_Lock); + + /* free the replicator group */ + XX_Free(p_ReplicGroup); + } +} + + +/*****************************************************************************/ +/* Inter-module API routines */ +/*****************************************************************************/ + +/* NOTE: the inter-module routines are locked by cc in case of using them */ +void * FrmReplicGroupGetSourceTableDescriptor(t_Handle h_ReplicGroup) +{ + t_FmPcdFrmReplicGroup *p_ReplicGroup = (t_FmPcdFrmReplicGroup *)h_ReplicGroup; + ASSERT_COND(p_ReplicGroup); + + return (p_ReplicGroup->p_SourceTd); +} + +void FrmReplicGroupUpdateAd(t_Handle h_ReplicGroup, + void *p_Ad, + t_Handle *h_AdNew) +{ + t_FmPcdFrmReplicGroup *p_ReplicGroup = (t_FmPcdFrmReplicGroup *)h_ReplicGroup; + t_AdOfTypeResult *p_AdResult = (t_AdOfTypeResult*)p_Ad; + t_FmPcd *p_FmPcd; + + ASSERT_COND(p_ReplicGroup); + p_FmPcd = p_ReplicGroup->h_FmPcd; + + /* build a bypass ad */ + WRITE_UINT32(p_AdResult->fqid, FM_PCD_AD_BYPASS_TYPE | + (uint32_t)((XX_VirtToPhys(p_ReplicGroup->p_SourceTd)) - p_FmPcd->physicalMuramBase)); + + *h_AdNew = NULL; +} + +void FrmReplicGroupUpdateOwner(t_Handle h_ReplicGroup, + bool add) +{ + t_FmPcdFrmReplicGroup *p_ReplicGroup = (t_FmPcdFrmReplicGroup *)h_ReplicGroup; + ASSERT_COND(p_ReplicGroup); + + /* update the group owner counter */ + if (add) + p_ReplicGroup->owners++; + else + { + ASSERT_COND(p_ReplicGroup->owners); + p_ReplicGroup->owners--; + } +} + +t_Error FrmReplicGroupTryLock(t_Handle h_ReplicGroup) +{ + t_FmPcdFrmReplicGroup *p_ReplicGroup = (t_FmPcdFrmReplicGroup *)h_ReplicGroup; + + ASSERT_COND(h_ReplicGroup); + + if (FmPcdLockTryLock(p_ReplicGroup->p_Lock)) + return E_OK; + + return ERROR_CODE(E_BUSY); +} + +void FrmReplicGroupUnlock(t_Handle h_ReplicGroup) +{ + t_FmPcdFrmReplicGroup *p_ReplicGroup = (t_FmPcdFrmReplicGroup *)h_ReplicGroup; + + ASSERT_COND(h_ReplicGroup); + + FmPcdLockUnlock(p_ReplicGroup->p_Lock); +} +/*********************** End of inter-module routines ************************/ + + +/****************************************/ +/* API Init unit functions */ +/****************************************/ +t_Handle FM_PCD_FrmReplicSetGroup(t_Handle h_FmPcd, + t_FmPcdFrmReplicGroupParams *p_ReplicGroupParam) +{ + t_FmPcdFrmReplicGroup *p_ReplicGroup; + t_FmPcdFrmReplicMember *p_CurrentMember, *p_NextMember = NULL; + int i; + t_Error err; + bool last = FALSE; + t_Handle h_Muram; + + SANITY_CHECK_RETURN_VALUE(h_FmPcd, E_INVALID_HANDLE, NULL); + SANITY_CHECK_RETURN_VALUE(p_ReplicGroupParam, E_INVALID_HANDLE, NULL); + + if (!FmPcdIsAdvancedOffloadSupported(h_FmPcd)) + { + REPORT_ERROR(MAJOR, E_INVALID_STATE, ("Advanced-offload must be enabled")); + return NULL; + } + + err = CheckParams(h_FmPcd, p_ReplicGroupParam); + if (err) + { + REPORT_ERROR(MAJOR, err, (NO_MSG)); + return NULL; + } + + p_ReplicGroup = (t_FmPcdFrmReplicGroup*)XX_Malloc(sizeof(t_FmPcdFrmReplicGroup)); + if (!p_ReplicGroup) + { + REPORT_ERROR(MAJOR, E_NO_MEMORY, ("No memory")); + return NULL; + } + memset(p_ReplicGroup, 0, sizeof(t_FmPcdFrmReplicGroup)); + + /* initialize lists for internal driver use */ + INIT_LIST(&p_ReplicGroup->availableMembersList); + INIT_LIST(&p_ReplicGroup->membersList); + + p_ReplicGroup->h_FmPcd = h_FmPcd; + + h_Muram = FmPcdGetMuramHandle(p_ReplicGroup->h_FmPcd); + ASSERT_COND(h_Muram); + + /* initialize the group lock */ + p_ReplicGroup->p_Lock = FmPcdAcquireLock(p_ReplicGroup->h_FmPcd); + if (!p_ReplicGroup->p_Lock) + { + REPORT_ERROR(MAJOR, E_NO_MEMORY, ("Replic group lock")); + DeleteGroup(p_ReplicGroup); + return NULL; + } + + /* Allocate the frame replicator source table descriptor */ + p_ReplicGroup->p_SourceTd = + (t_Handle)FM_MURAM_AllocMem(h_Muram, + FM_PCD_CC_AD_ENTRY_SIZE, + FM_PCD_CC_AD_TABLE_ALIGN); + if (!p_ReplicGroup->p_SourceTd) + { + REPORT_ERROR(MAJOR, E_NO_MEMORY, ("frame replicator source table descriptor")); + DeleteGroup(p_ReplicGroup); + return NULL; + } + + /* update the shadow size - required for the host commands */ + err = FmPcdUpdateCcShadow(p_ReplicGroup->h_FmPcd, + FM_PCD_CC_AD_ENTRY_SIZE, + FM_PCD_CC_AD_TABLE_ALIGN); + if (err) + { + REPORT_ERROR(MAJOR, err, ("Update CC shadow")); + DeleteGroup(p_ReplicGroup); + return NULL; + } + + p_ReplicGroup->maxNumOfEntries = p_ReplicGroupParam->maxNumOfEntries; + + /* Allocate the maximal number of members ADs and Statistics AD for the group + It prevents allocation of Muram in run-time */ + for (i=0; i<p_ReplicGroup->maxNumOfEntries; i++) + { + err = AllocMember(p_ReplicGroup); + if (err) + { + REPORT_ERROR(MAJOR, err, ("allocate a new member")); + DeleteGroup(p_ReplicGroup); + return NULL; + } + } + + /* Initialize the members linked lists: + (hw - the one that is used by the FMan controller and + sw - the one that is managed by the driver internally) */ + for (i=(p_ReplicGroupParam->numOfEntries-1); i>=0; i--) + { + /* check if this is the last member in the group */ + if (i == (p_ReplicGroupParam->numOfEntries-1)) + last = TRUE; + else + last = FALSE; + + /* Initialize a new member */ + p_CurrentMember = InitMember(p_ReplicGroup, + &(p_ReplicGroupParam->nextEngineParams[i]), + last); + if (!p_CurrentMember) + { + REPORT_ERROR(MAJOR, E_INVALID_HANDLE, ("No available member")); + DeleteGroup(p_ReplicGroup); + return NULL; + } + + /* Build the members group - link two consecutive members in the hw linked list */ + LinkMemberToMember(p_ReplicGroup, p_CurrentMember, p_NextMember); + + /* update the driver internal members list to be compatible to the hw members linked list */ + AddMemberToList(p_ReplicGroup, p_CurrentMember, &p_ReplicGroup->membersList); + + p_NextMember = p_CurrentMember; + } + + /* initialize the source table descriptor */ + BuildSourceTd(p_ReplicGroup->p_SourceTd); + + /* link the source table descriptor to point to the first member in the group */ + LinkSourceToMember(p_ReplicGroup, p_ReplicGroup->p_SourceTd, p_NextMember); + + return p_ReplicGroup; +} + +t_Error FM_PCD_FrmReplicDeleteGroup(t_Handle h_ReplicGroup) +{ + t_FmPcdFrmReplicGroup *p_ReplicGroup = (t_FmPcdFrmReplicGroup *)h_ReplicGroup; + + SANITY_CHECK_RETURN_ERROR(p_ReplicGroup, E_INVALID_HANDLE); + + if (p_ReplicGroup->owners) + RETURN_ERROR(MAJOR, + E_INVALID_STATE, + ("the group has owners and can't be deleted")); + + DeleteGroup(p_ReplicGroup); + + return E_OK; +} + + +/*****************************************************************************/ +/* API Run-time Frame replicator Control unit functions */ +/*****************************************************************************/ +t_Error FM_PCD_FrmReplicAddMember(t_Handle h_ReplicGroup, + uint16_t memberIndex, + t_FmPcdCcNextEngineParams *p_MemberParams) +{ + t_FmPcdFrmReplicGroup *p_ReplicGroup = (t_FmPcdFrmReplicGroup*) h_ReplicGroup; + t_FmPcdFrmReplicMember *p_NewMember, *p_CurrentMember = NULL, *p_PreviousMember = NULL; + t_Error err; + uint8_t memberPosition; + + SANITY_CHECK_RETURN_ERROR(p_ReplicGroup, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_MemberParams, E_INVALID_HANDLE); + + /* group lock */ + err = FrmReplicGroupTryLock(p_ReplicGroup); + if (GET_ERROR_TYPE(err) == E_BUSY) + return ERROR_CODE(E_BUSY); + + if (memberIndex > p_ReplicGroup->numOfEntries) + { + /* unlock */ + FrmReplicGroupUnlock(p_ReplicGroup); + RETURN_ERROR(MAJOR, E_INVALID_SELECTION, + ("memberIndex is greater than the members in the list")); + } + + if (memberIndex >= p_ReplicGroup->maxNumOfEntries) + { + /* unlock */ + FrmReplicGroupUnlock(p_ReplicGroup); + RETURN_ERROR(MAJOR, E_INVALID_SELECTION, ("memberIndex is greater than the allowed number of members in the group")); + } + + if ((p_ReplicGroup->numOfEntries + 1) > FM_PCD_FRM_REPLIC_MAX_NUM_OF_ENTRIES) + { + /* unlock */ + FrmReplicGroupUnlock(p_ReplicGroup); + RETURN_ERROR(MAJOR, E_INVALID_VALUE, + ("numOfEntries with new entry can not be larger than %d\n", + FM_PCD_FRM_REPLIC_MAX_NUM_OF_ENTRIES)); + } + + err = MemberCheckParams(p_ReplicGroup->h_FmPcd, p_MemberParams); + if (err) + { + /* unlock */ + FrmReplicGroupUnlock(p_ReplicGroup); + RETURN_ERROR(MAJOR, err, ("member check parameters in add operation")); + } + /* determine the member position in the group */ + memberPosition = GetMemberPosition(p_ReplicGroup, + memberIndex, + TRUE/* add operation */); + + /* Initialize a new member */ + p_NewMember = InitMember(p_ReplicGroup, + p_MemberParams, + (memberPosition == FRM_REPLIC_LAST_MEMBER_INDEX ? TRUE : FALSE)); + if (!p_NewMember) + { + /* unlock */ + FrmReplicGroupUnlock(p_ReplicGroup); + RETURN_ERROR(MAJOR, E_INVALID_HANDLE, ("No available member")); + } + + switch (memberPosition) + { + case FRM_REPLIC_FIRST_MEMBER_INDEX: + p_CurrentMember = GetMemberByIndex(p_ReplicGroup, memberIndex); + ASSERT_COND(p_CurrentMember); + + LinkMemberToMember(p_ReplicGroup, p_NewMember, p_CurrentMember); + + /* update the internal group source TD */ + LinkSourceToMember(p_ReplicGroup, + p_ReplicGroup->p_SourceTd, + p_NewMember); + + /* add member to the internal sw member list */ + AddMemberToList(p_ReplicGroup, + p_NewMember, + &p_ReplicGroup->membersList); + break; + + case FRM_REPLIC_MIDDLE_MEMBER_INDEX: + p_CurrentMember = GetMemberByIndex(p_ReplicGroup, memberIndex); + ASSERT_COND(p_CurrentMember); + + p_PreviousMember = GetMemberByIndex(p_ReplicGroup, (uint16_t)(memberIndex-1)); + ASSERT_COND(p_PreviousMember); + + LinkMemberToMember(p_ReplicGroup, p_NewMember, p_CurrentMember); + LinkMemberToMember(p_ReplicGroup, p_PreviousMember, p_NewMember); + + AddMemberToList(p_ReplicGroup, p_NewMember, &p_PreviousMember->node); + break; + + case FRM_REPLIC_LAST_MEMBER_INDEX: + p_PreviousMember = GetMemberByIndex(p_ReplicGroup, (uint16_t)(memberIndex-1)); + ASSERT_COND(p_PreviousMember); + + LinkMemberToMember(p_ReplicGroup, p_PreviousMember, p_NewMember); + FillReplicAdOfTypeResult(p_PreviousMember->p_MemberAd, FALSE/*last*/); + + /* add the new member to the internal sw member list */ + AddMemberToList(p_ReplicGroup, p_NewMember, &p_PreviousMember->node); + break; + + default: + /* unlock */ + FrmReplicGroupUnlock(p_ReplicGroup); + RETURN_ERROR(MAJOR, E_INVALID_SELECTION, ("member position in add member")); + + } + + /* unlock */ + FrmReplicGroupUnlock(p_ReplicGroup); + + return E_OK; +} + +t_Error FM_PCD_FrmReplicRemoveMember(t_Handle h_ReplicGroup, + uint16_t memberIndex) +{ + t_FmPcdFrmReplicGroup *p_ReplicGroup = (t_FmPcdFrmReplicGroup*) h_ReplicGroup; + t_Error err; + + SANITY_CHECK_RETURN_ERROR(p_ReplicGroup, E_INVALID_HANDLE); + + /* lock */ + err = FrmReplicGroupTryLock(p_ReplicGroup); + if (GET_ERROR_TYPE(err) == E_BUSY) + return ERROR_CODE(E_BUSY); + + if (memberIndex >= p_ReplicGroup->numOfEntries) + RETURN_ERROR(MAJOR, E_INVALID_SELECTION, ("member index to remove")); + + /* Design decision: group must contain at least one member + No possibility to remove the last member from the group */ + if (p_ReplicGroup->numOfEntries == 1) + RETURN_ERROR(MAJOR, E_CONFLICT, ("Can't remove the last member. At least one member should be related to a group.")); + + err = RemoveMember(p_ReplicGroup, memberIndex); + + /* unlock */ + FrmReplicGroupUnlock(p_ReplicGroup); + + switch (GET_ERROR_TYPE(err)) + { + case E_OK: + return E_OK; + + case E_BUSY: + DBG(TRACE, ("E_BUSY error")); + return ERROR_CODE(E_BUSY); + + default: + RETURN_ERROR(MAJOR, err, NO_MSG); + } +} + +/*********************** End of API routines ************************/ + + diff --git a/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Pcd/fm_replic.h b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Pcd/fm_replic.h new file mode 100644 index 000000000000..0e8e8bc00cb2 --- /dev/null +++ b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Pcd/fm_replic.h @@ -0,0 +1,101 @@ +/* + * Copyright 2008-2012 Freescale Semiconductor Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Freescale Semiconductor nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * + * ALTERNATIVELY, this software may be distributed under the terms of the + * GNU General Public License ("GPL") as published by the Free Software + * Foundation, either version 2 of that License or (at your option) any + * later version. + * + * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + +/****************************************************************************** + @File fm_replic.h + + @Description FM frame replicator +*//***************************************************************************/ +#ifndef __FM_REPLIC_H +#define __FM_REPLIC_H + +#include "std_ext.h" +#include "error_ext.h" + + +#define FRM_REPLIC_SOURCE_TD_OPCODE 0x75 +#define NEXT_FRM_REPLIC_ADDR_SHIFT 4 +#define NEXT_FRM_REPLIC_MEMBER_INDEX_SHIFT 16 +#define FRM_REPLIC_FR_BIT 0x08000000 +#define FRM_REPLIC_NL_BIT 0x10000000 +#define FRM_REPLIC_INVALID_MEMBER_INDEX 0xffff +#define FRM_REPLIC_FIRST_MEMBER_INDEX 0 + +#define FRM_REPLIC_MIDDLE_MEMBER_INDEX 1 +#define FRM_REPLIC_LAST_MEMBER_INDEX 2 + +#define SOURCE_TD_ITSELF_OPTION 0x01 +#define SOURCE_TD_COPY_OPTION 0x02 +#define SOURCE_TD_ITSELF_AND_COPY_OPTION SOURCE_TD_ITSELF_OPTION | SOURCE_TD_COPY_OPTION +#define SOURCE_TD_NONE 0x04 + +/*typedef enum e_SourceTdOption +{ + e_SOURCE_TD_NONE = 0, + e_SOURCE_TD_ITSELF_OPTION = 1, + e_SOURCE_TD_COPY_OPTION = 2, + e_SOURCE_TD_ITSELF_AND_COPY_OPTION = e_SOURCE_TD_ITSELF_OPTION | e_SOURCE_TD_COPY_OPTION +} e_SourceTdOption; +*/ + +typedef struct +{ + volatile uint32_t type; + volatile uint32_t frGroupPointer; + volatile uint32_t operationCode; + volatile uint32_t reserved; +} t_FrmReplicGroupSourceAd; + +typedef struct t_FmPcdFrmReplicMember +{ + void *p_MemberAd; /**< pointer to the member AD */ + void *p_StatisticsAd;/**< pointer to the statistics AD of the member */ + t_Handle h_Manip; /**< manip handle - need for free routines */ + t_List node; +} t_FmPcdFrmReplicMember; + +typedef struct t_FmPcdFrmReplicGroup +{ + t_Handle h_FmPcd; + + uint8_t maxNumOfEntries;/**< maximal number of members in the group */ + uint8_t numOfEntries; /**< actual number of members in the group */ + uint16_t owners; /**< how many keys share this frame replicator group */ + void *p_SourceTd; /**< pointer to the frame replicator source table descriptor */ + t_List membersList; /**< the members list - should reflect the order of the members as in the hw linked list*/ + t_List availableMembersList;/**< list of all the available members in the group */ + t_FmPcdLock *p_Lock; +} t_FmPcdFrmReplicGroup; + + +#endif /* __FM_REPLIC_H */ diff --git a/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Pcd/fman_kg.c b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Pcd/fman_kg.c new file mode 100644 index 000000000000..9939a755ab31 --- /dev/null +++ b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Pcd/fman_kg.c @@ -0,0 +1,890 @@ +/* + * Copyright 2008-2012 Freescale Semiconductor Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Freescale Semiconductor nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * + * ALTERNATIVELY, this software may be distributed under the terms of the + * GNU General Public License ("GPL") as published by the Free Software + * Foundation, either version 2 of that License or (at your option) any + * later version. + * + * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "std_ext.h" +#include "error_ext.h" +#include "fsl_fman_kg.h" + +/****************************************/ +/* static functions */ +/****************************************/ + + +static uint32_t build_ar_bind_scheme(uint8_t hwport_id, bool write) +{ + uint32_t rw; + + rw = write ? (uint32_t)FM_KG_KGAR_WRITE : (uint32_t)FM_KG_KGAR_READ; + + return (uint32_t)(FM_KG_KGAR_GO | + rw | + FM_PCD_KG_KGAR_SEL_PORT_ENTRY | + hwport_id | + FM_PCD_KG_KGAR_SEL_PORT_WSEL_SP); +} + +static void clear_pe_all_scheme(struct fman_kg_regs *regs, uint8_t hwport_id) +{ + uint32_t ar; + + fman_kg_write_sp(regs, 0xffffffff, 0); + + ar = build_ar_bind_scheme(hwport_id, TRUE); + fman_kg_write_ar_wait(regs, ar); +} + +static uint32_t build_ar_bind_cls_plan(uint8_t hwport_id, bool write) +{ + uint32_t rw; + + rw = write ? (uint32_t)FM_KG_KGAR_WRITE : (uint32_t)FM_KG_KGAR_READ; + + return (uint32_t)(FM_KG_KGAR_GO | + rw | + FM_PCD_KG_KGAR_SEL_PORT_ENTRY | + hwport_id | + FM_PCD_KG_KGAR_SEL_PORT_WSEL_CPP); +} + +static void clear_pe_all_cls_plan(struct fman_kg_regs *regs, uint8_t hwport_id) +{ + uint32_t ar; + + fman_kg_write_cpp(regs, 0); + + ar = build_ar_bind_cls_plan(hwport_id, TRUE); + fman_kg_write_ar_wait(regs, ar); +} + +static uint8_t get_gen_ht_code(enum fman_kg_gen_extract_src src, + bool no_validation, + uint8_t *offset) +{ + int code; + + switch (src) { + case E_FMAN_KG_GEN_EXTRACT_ETH: + code = no_validation ? 0x73 : 0x3; + break; + + case E_FMAN_KG_GEN_EXTRACT_ETYPE: + code = no_validation ? 0x77 : 0x7; + break; + + case E_FMAN_KG_GEN_EXTRACT_SNAP: + code = no_validation ? 0x74 : 0x4; + break; + + case E_FMAN_KG_GEN_EXTRACT_VLAN_TCI_1: + code = no_validation ? 0x75 : 0x5; + break; + + case E_FMAN_KG_GEN_EXTRACT_VLAN_TCI_N: + code = no_validation ? 0x76 : 0x6; + break; + + case E_FMAN_KG_GEN_EXTRACT_PPPoE: + code = no_validation ? 0x78 : 0x8; + break; + + case E_FMAN_KG_GEN_EXTRACT_MPLS_1: + code = no_validation ? 0x79 : 0x9; + break; + + case E_FMAN_KG_GEN_EXTRACT_MPLS_2: + code = no_validation ? FM_KG_SCH_GEN_HT_INVALID : 0x19; + break; + + case E_FMAN_KG_GEN_EXTRACT_MPLS_3: + code = no_validation ? FM_KG_SCH_GEN_HT_INVALID : 0x29; + break; + + case E_FMAN_KG_GEN_EXTRACT_MPLS_N: + code = no_validation ? 0x7a : 0xa; + break; + + case E_FMAN_KG_GEN_EXTRACT_IPv4_1: + code = no_validation ? 0x7b : 0xb; + break; + + case E_FMAN_KG_GEN_EXTRACT_IPv6_1: + code = no_validation ? 0x7b : 0x1b; + break; + + case E_FMAN_KG_GEN_EXTRACT_IPv4_2: + code = no_validation ? 0x7c : 0xc; + break; + + case E_FMAN_KG_GEN_EXTRACT_IPv6_2: + code = no_validation ? 0x7c : 0x1c; + break; + + case E_FMAN_KG_GEN_EXTRACT_MINENCAP: + code = no_validation ? 0x7c : 0x2c; + break; + + case E_FMAN_KG_GEN_EXTRACT_IP_PID: + code = no_validation ? 0x72 : 0x2; + break; + + case E_FMAN_KG_GEN_EXTRACT_GRE: + code = no_validation ? 0x7d : 0xd; + break; + + case E_FMAN_KG_GEN_EXTRACT_TCP: + code = no_validation ? 0x7e : 0xe; + break; + + case E_FMAN_KG_GEN_EXTRACT_UDP: + code = no_validation ? 0x7e : 0x1e; + break; + + case E_FMAN_KG_GEN_EXTRACT_SCTP: + code = no_validation ? 0x7e : 0x3e; + break; + + case E_FMAN_KG_GEN_EXTRACT_DCCP: + code = no_validation ? 0x7e : 0x4e; + break; + + case E_FMAN_KG_GEN_EXTRACT_IPSEC_AH: + code = no_validation ? 0x7e : 0x2e; + break; + + case E_FMAN_KG_GEN_EXTRACT_IPSEC_ESP: + code = no_validation ? 0x7e : 0x6e; + break; + + case E_FMAN_KG_GEN_EXTRACT_SHIM_1: + code = 0x70; + break; + + case E_FMAN_KG_GEN_EXTRACT_SHIM_2: + code = 0x71; + break; + + case E_FMAN_KG_GEN_EXTRACT_FROM_DFLT: + code = 0x10; + break; + + case E_FMAN_KG_GEN_EXTRACT_FROM_FRAME_START: + code = 0x40; + break; + + case E_FMAN_KG_GEN_EXTRACT_FROM_PARSE_RESULT: + code = 0x20; + break; + + case E_FMAN_KG_GEN_EXTRACT_FROM_END_OF_PARSE: + code = 0x7f; + break; + + case E_FMAN_KG_GEN_EXTRACT_FROM_FQID: + code = 0x20; + *offset += 0x20; + break; + + default: + code = FM_KG_SCH_GEN_HT_INVALID; + } + + return (uint8_t)code; +} + +static uint32_t build_ar_scheme(uint8_t scheme, + uint8_t hwport_id, + bool update_counter, + bool write) +{ + uint32_t rw; + + rw = (uint32_t)(write ? FM_KG_KGAR_WRITE : FM_KG_KGAR_READ); + + return (uint32_t)(FM_KG_KGAR_GO | + rw | + FM_KG_KGAR_SEL_SCHEME_ENTRY | + hwport_id | + ((uint32_t)scheme << FM_KG_KGAR_NUM_SHIFT) | + (update_counter ? FM_KG_KGAR_SCM_WSEL_UPDATE_CNT : 0)); +} + +static uint32_t build_ar_cls_plan(uint8_t grp, + uint8_t entries_mask, + uint8_t hwport_id, + bool write) +{ + uint32_t rw; + + rw = (uint32_t)(write ? FM_KG_KGAR_WRITE : FM_KG_KGAR_READ); + + return (uint32_t)(FM_KG_KGAR_GO | + rw | + FM_PCD_KG_KGAR_SEL_CLS_PLAN_ENTRY | + hwport_id | + ((uint32_t)grp << FM_KG_KGAR_NUM_SHIFT) | + ((uint32_t)entries_mask << FM_KG_KGAR_WSEL_SHIFT)); +} + +int fman_kg_write_ar_wait(struct fman_kg_regs *regs, uint32_t fmkg_ar) +{ + iowrite32be(fmkg_ar, ®s->fmkg_ar); + /* Wait for GO to be idle and read error */ + while ((fmkg_ar = ioread32be(®s->fmkg_ar)) & FM_KG_KGAR_GO) ; + if (fmkg_ar & FM_PCD_KG_KGAR_ERR) + return -EINVAL; + return 0; +} + +void fman_kg_write_sp(struct fman_kg_regs *regs, uint32_t sp, bool add) +{ + + struct fman_kg_pe_regs *kgpe_regs; + uint32_t tmp; + + kgpe_regs = (struct fman_kg_pe_regs *)&(regs->fmkg_indirect[0]); + tmp = ioread32be(&kgpe_regs->fmkg_pe_sp); + + if (add) + tmp |= sp; + else /* clear */ + tmp &= ~sp; + + iowrite32be(tmp, &kgpe_regs->fmkg_pe_sp); + +} + +void fman_kg_write_cpp(struct fman_kg_regs *regs, uint32_t cpp) +{ + struct fman_kg_pe_regs *kgpe_regs; + + kgpe_regs = (struct fman_kg_pe_regs *)&(regs->fmkg_indirect[0]); + + iowrite32be(cpp, &kgpe_regs->fmkg_pe_cpp); +} + +void fman_kg_get_event(struct fman_kg_regs *regs, + uint32_t *event, + uint32_t *scheme_idx) +{ + uint32_t mask, force; + + *event = ioread32be(®s->fmkg_eer); + mask = ioread32be(®s->fmkg_eeer); + *scheme_idx = ioread32be(®s->fmkg_seer); + *scheme_idx &= ioread32be(®s->fmkg_seeer); + + *event &= mask; + + /* clear the forced events */ + force = ioread32be(®s->fmkg_feer); + if (force & *event) + iowrite32be(force & ~*event ,®s->fmkg_feer); + + iowrite32be(*event, ®s->fmkg_eer); + iowrite32be(*scheme_idx, ®s->fmkg_seer); +} + + +void fman_kg_init(struct fman_kg_regs *regs, + uint32_t exceptions, + uint32_t dflt_nia) +{ + uint32_t tmp; + int i; + + iowrite32be(FM_EX_KG_DOUBLE_ECC | FM_EX_KG_KEYSIZE_OVERFLOW, + ®s->fmkg_eer); + + tmp = 0; + if (exceptions & FM_EX_KG_DOUBLE_ECC) + tmp |= FM_EX_KG_DOUBLE_ECC; + + if (exceptions & FM_EX_KG_KEYSIZE_OVERFLOW) + tmp |= FM_EX_KG_KEYSIZE_OVERFLOW; + + iowrite32be(tmp, ®s->fmkg_eeer); + iowrite32be(0, ®s->fmkg_fdor); + iowrite32be(0, ®s->fmkg_gdv0r); + iowrite32be(0, ®s->fmkg_gdv1r); + iowrite32be(dflt_nia, ®s->fmkg_gcr); + + /* Clear binding between ports to schemes and classification plans + * so that all ports are not bound to any scheme/classification plan */ + for (i = 0; i < FMAN_MAX_NUM_OF_HW_PORTS; i++) { + clear_pe_all_scheme(regs, (uint8_t)i); + clear_pe_all_cls_plan(regs, (uint8_t)i); + } +} + +void fman_kg_enable_scheme_interrupts(struct fman_kg_regs *regs) +{ + /* enable and enable all scheme interrupts */ + iowrite32be(0xFFFFFFFF, ®s->fmkg_seer); + iowrite32be(0xFFFFFFFF, ®s->fmkg_seeer); +} + +void fman_kg_enable(struct fman_kg_regs *regs) +{ + iowrite32be(ioread32be(®s->fmkg_gcr) | FM_KG_KGGCR_EN, + ®s->fmkg_gcr); +} + +void fman_kg_disable(struct fman_kg_regs *regs) +{ + iowrite32be(ioread32be(®s->fmkg_gcr) & ~FM_KG_KGGCR_EN, + ®s->fmkg_gcr); +} + +void fman_kg_set_data_after_prs(struct fman_kg_regs *regs, uint8_t offset) +{ + iowrite32be(offset, ®s->fmkg_fdor); +} + +void fman_kg_set_dflt_val(struct fman_kg_regs *regs, + uint8_t def_id, + uint32_t val) +{ + if(def_id == 0) + iowrite32be(val, ®s->fmkg_gdv0r); + else + iowrite32be(val, ®s->fmkg_gdv1r); +} + + +void fman_kg_set_exception(struct fman_kg_regs *regs, + uint32_t exception, + bool enable) +{ + uint32_t tmp; + + tmp = ioread32be(®s->fmkg_eeer); + + if (enable) { + tmp |= exception; + } else { + tmp &= ~exception; + } + + iowrite32be(tmp, ®s->fmkg_eeer); +} + +void fman_kg_get_exception(struct fman_kg_regs *regs, + uint32_t *events, + uint32_t *scheme_ids, + bool clear) +{ + uint32_t mask; + + *events = ioread32be(®s->fmkg_eer); + mask = ioread32be(®s->fmkg_eeer); + *events &= mask; + + *scheme_ids = 0; + + if (*events & FM_EX_KG_KEYSIZE_OVERFLOW) { + *scheme_ids = ioread32be(®s->fmkg_seer); + mask = ioread32be(®s->fmkg_seeer); + *scheme_ids &= mask; + } + + if (clear) { + iowrite32be(*scheme_ids, ®s->fmkg_seer); + iowrite32be(*events, ®s->fmkg_eer); + } +} + +void fman_kg_get_capture(struct fman_kg_regs *regs, + struct fman_kg_ex_ecc_attr *ecc_attr, + bool clear) +{ + uint32_t tmp; + + tmp = ioread32be(®s->fmkg_serc); + + if (tmp & KG_FMKG_SERC_CAP) { + /* Captured data is valid */ + ecc_attr->valid = TRUE; + ecc_attr->double_ecc = + (bool)((tmp & KG_FMKG_SERC_CET) ? TRUE : FALSE); + ecc_attr->single_ecc_count = + (uint8_t)((tmp & KG_FMKG_SERC_CNT_MSK) >> + KG_FMKG_SERC_CNT_SHIFT); + ecc_attr->addr = (uint16_t)(tmp & KG_FMKG_SERC_ADDR_MSK); + + if (clear) + iowrite32be(KG_FMKG_SERC_CAP, ®s->fmkg_serc); + } else { + /* No ECC error is captured */ + ecc_attr->valid = FALSE; + } +} + +int fman_kg_build_scheme(struct fman_kg_scheme_params *params, + struct fman_kg_scheme_regs *scheme_regs) +{ + struct fman_kg_extract_params *extract_params; + struct fman_kg_gen_extract_params *gen_params; + uint32_t tmp_reg, i, select, mask, fqb; + uint8_t offset, shift, ht; + + /* Zero out all registers so no need to care about unused ones */ + memset(scheme_regs, 0, sizeof(struct fman_kg_scheme_regs)); + + /* Mode register */ + tmp_reg = fm_kg_build_nia(params->next_engine, + params->next_engine_action); + if (tmp_reg == KG_NIA_INVALID) { + return -EINVAL; + } + + if (params->next_engine == E_FMAN_PCD_PLCR) { + tmp_reg |= FMAN_KG_SCH_MODE_NIA_PLCR; + } + else if (params->next_engine == E_FMAN_PCD_CC) { + tmp_reg |= (uint32_t)params->cc_params.base_offset << + FMAN_KG_SCH_MODE_CCOBASE_SHIFT; + } + + tmp_reg |= FMAN_KG_SCH_MODE_EN; + scheme_regs->kgse_mode = tmp_reg; + + /* Match vector */ + scheme_regs->kgse_mv = params->match_vector; + + extract_params = ¶ms->extract_params; + + /* Scheme default values registers */ + scheme_regs->kgse_dv0 = extract_params->def_scheme_0; + scheme_regs->kgse_dv1 = extract_params->def_scheme_1; + + /* Extract Known Fields Command register */ + scheme_regs->kgse_ekfc = extract_params->known_fields; + + /* Entry Extract Known Default Value register */ + tmp_reg = 0; + tmp_reg |= extract_params->known_fields_def.mac_addr << + FMAN_KG_SCH_DEF_MAC_ADDR_SHIFT; + tmp_reg |= extract_params->known_fields_def.vlan_tci << + FMAN_KG_SCH_DEF_VLAN_TCI_SHIFT; + tmp_reg |= extract_params->known_fields_def.etype << + FMAN_KG_SCH_DEF_ETYPE_SHIFT; + tmp_reg |= extract_params->known_fields_def.ppp_sid << + FMAN_KG_SCH_DEF_PPP_SID_SHIFT; + tmp_reg |= extract_params->known_fields_def.ppp_pid << + FMAN_KG_SCH_DEF_PPP_PID_SHIFT; + tmp_reg |= extract_params->known_fields_def.mpls << + FMAN_KG_SCH_DEF_MPLS_SHIFT; + tmp_reg |= extract_params->known_fields_def.ip_addr << + FMAN_KG_SCH_DEF_IP_ADDR_SHIFT; + tmp_reg |= extract_params->known_fields_def.ptype << + FMAN_KG_SCH_DEF_PTYPE_SHIFT; + tmp_reg |= extract_params->known_fields_def.ip_tos_tc << + FMAN_KG_SCH_DEF_IP_TOS_TC_SHIFT; + tmp_reg |= extract_params->known_fields_def.ipv6_fl << + FMAN_KG_SCH_DEF_IPv6_FL_SHIFT; + tmp_reg |= extract_params->known_fields_def.ipsec_spi << + FMAN_KG_SCH_DEF_IPSEC_SPI_SHIFT; + tmp_reg |= extract_params->known_fields_def.l4_port << + FMAN_KG_SCH_DEF_L4_PORT_SHIFT; + tmp_reg |= extract_params->known_fields_def.tcp_flg << + FMAN_KG_SCH_DEF_TCP_FLG_SHIFT; + + scheme_regs->kgse_ekdv = tmp_reg; + + /* Generic extract registers */ + if (extract_params->gen_extract_num > FM_KG_NUM_OF_GENERIC_REGS) { + return -EINVAL; + } + + for (i = 0; i < extract_params->gen_extract_num; i++) { + gen_params = extract_params->gen_extract + i; + + tmp_reg = FMAN_KG_SCH_GEN_VALID; + tmp_reg |= (uint32_t)gen_params->def_val << + FMAN_KG_SCH_GEN_DEF_SHIFT; + + if (gen_params->type == E_FMAN_KG_HASH_EXTRACT) { + if ((gen_params->extract > FMAN_KG_SCH_GEN_SIZE_MAX) || + (gen_params->extract == 0)) { + return -EINVAL; + } + } else { + tmp_reg |= FMAN_KG_SCH_GEN_OR; + } + + tmp_reg |= (uint32_t)gen_params->extract << + FMAN_KG_SCH_GEN_SIZE_SHIFT; + tmp_reg |= (uint32_t)gen_params->mask << + FMAN_KG_SCH_GEN_MASK_SHIFT; + + offset = gen_params->offset; + ht = get_gen_ht_code(gen_params->src, + gen_params->no_validation, + &offset); + tmp_reg |= (uint32_t)ht << FMAN_KG_SCH_GEN_HT_SHIFT; + tmp_reg |= offset; + + scheme_regs->kgse_gec[i] = tmp_reg; + } + + /* Masks registers */ + if (extract_params->masks_num > FM_KG_EXTRACT_MASKS_NUM) { + return -EINVAL; + } + + select = 0; + mask = 0; + fqb = 0; + for (i = 0; i < extract_params->masks_num; i++) { + /* MCSx fields */ + KG_GET_MASK_SEL_SHIFT(shift, i); + if (extract_params->masks[i].is_known) { + /* Mask known field */ + select |= extract_params->masks[i].field_or_gen_idx << + shift; + } else { + /* Mask generic extract */ + select |= (extract_params->masks[i].field_or_gen_idx + + FM_KG_MASK_SEL_GEN_BASE) << shift; + } + + /* MOx fields - spread between se_bmch and se_fqb registers */ + KG_GET_MASK_OFFSET_SHIFT(shift, i); + if (i < 2) { + select |= (uint32_t)extract_params->masks[i].offset << + shift; + } else { + fqb |= (uint32_t)extract_params->masks[i].offset << + shift; + } + + /* BMx fields */ + KG_GET_MASK_SHIFT(shift, i); + mask |= (uint32_t)extract_params->masks[i].mask << shift; + } + + /* Finish with rest of BMx fileds - + * don't mask bits for unused masks by setting + * corresponding BMx field = 0xFF */ + for (i = extract_params->masks_num; i < FM_KG_EXTRACT_MASKS_NUM; i++) { + KG_GET_MASK_SHIFT(shift, i); + mask |= 0xFF << shift; + } + + scheme_regs->kgse_bmch = select; + scheme_regs->kgse_bmcl = mask; + + /* Finish with FQB register initialization. + * Check fqid is 24-bit value. */ + if (params->base_fqid & ~0x00FFFFFF) { + return -EINVAL; + } + + fqb |= params->base_fqid; + scheme_regs->kgse_fqb = fqb; + + /* Hash Configuration register */ + tmp_reg = 0; + if (params->hash_params.use_hash) { + /* Check hash mask is 24-bit value */ + if (params->hash_params.mask & ~0x00FFFFFF) { + return -EINVAL; + } + + /* Hash function produces 64-bit value, 24 bits of that + * are used to generate fq_id and policer profile. + * Thus, maximal shift is 40 bits to allow 24 bits out of 64. + */ + if (params->hash_params.shift_r > FMAN_KG_SCH_HASH_HSHIFT_MAX) { + return -EINVAL; + } + + tmp_reg |= params->hash_params.mask; + tmp_reg |= (uint32_t)params->hash_params.shift_r << + FMAN_KG_SCH_HASH_HSHIFT_SHIFT; + + if (params->hash_params.sym) { + tmp_reg |= FMAN_KG_SCH_HASH_SYM; + } + + } + + if (params->bypass_fqid_gen) { + tmp_reg |= FMAN_KG_SCH_HASH_NO_FQID_GEN; + } + + scheme_regs->kgse_hc = tmp_reg; + + /* Policer Profile register */ + if (params->policer_params.bypass_pp_gen) { + tmp_reg = 0; + } else { + /* Lower 8 bits of 24-bits extracted from hash result + * are used for policer profile generation. + * That leaves maximum shift value = 23. */ + if (params->policer_params.shift > FMAN_KG_SCH_PP_SHIFT_MAX) { + return -EINVAL; + } + + tmp_reg = params->policer_params.base; + tmp_reg |= ((uint32_t)params->policer_params.shift << + FMAN_KG_SCH_PP_SH_SHIFT) & + FMAN_KG_SCH_PP_SH_MASK; + tmp_reg |= ((uint32_t)params->policer_params.shift << + FMAN_KG_SCH_PP_SL_SHIFT) & + FMAN_KG_SCH_PP_SL_MASK; + tmp_reg |= (uint32_t)params->policer_params.mask << + FMAN_KG_SCH_PP_MASK_SHIFT; + } + + scheme_regs->kgse_ppc = tmp_reg; + + /* Coarse Classification Bit Select register */ + if (params->next_engine == E_FMAN_PCD_CC) { + scheme_regs->kgse_ccbs = params->cc_params.qlcv_bits_sel; + } + + /* Packets Counter register */ + if (params->update_counter) { + scheme_regs->kgse_spc = params->counter_value; + } + + return 0; +} + +int fman_kg_write_scheme(struct fman_kg_regs *regs, + uint8_t scheme_id, + uint8_t hwport_id, + struct fman_kg_scheme_regs *scheme_regs, + bool update_counter) +{ + struct fman_kg_scheme_regs *kgse_regs; + uint32_t tmp_reg; + int err, i; + + /* Write indirect scheme registers */ + kgse_regs = (struct fman_kg_scheme_regs *)&(regs->fmkg_indirect[0]); + + iowrite32be(scheme_regs->kgse_mode, &kgse_regs->kgse_mode); + iowrite32be(scheme_regs->kgse_ekfc, &kgse_regs->kgse_ekfc); + iowrite32be(scheme_regs->kgse_ekdv, &kgse_regs->kgse_ekdv); + iowrite32be(scheme_regs->kgse_bmch, &kgse_regs->kgse_bmch); + iowrite32be(scheme_regs->kgse_bmcl, &kgse_regs->kgse_bmcl); + iowrite32be(scheme_regs->kgse_fqb, &kgse_regs->kgse_fqb); + iowrite32be(scheme_regs->kgse_hc, &kgse_regs->kgse_hc); + iowrite32be(scheme_regs->kgse_ppc, &kgse_regs->kgse_ppc); + iowrite32be(scheme_regs->kgse_spc, &kgse_regs->kgse_spc); + iowrite32be(scheme_regs->kgse_dv0, &kgse_regs->kgse_dv0); + iowrite32be(scheme_regs->kgse_dv1, &kgse_regs->kgse_dv1); + iowrite32be(scheme_regs->kgse_ccbs, &kgse_regs->kgse_ccbs); + iowrite32be(scheme_regs->kgse_mv, &kgse_regs->kgse_mv); + + for (i = 0 ; i < FM_KG_NUM_OF_GENERIC_REGS ; i++) + iowrite32be(scheme_regs->kgse_gec[i], &kgse_regs->kgse_gec[i]); + + /* Write AR (Action register) */ + tmp_reg = build_ar_scheme(scheme_id, hwport_id, update_counter, TRUE); + err = fman_kg_write_ar_wait(regs, tmp_reg); + return err; +} + +int fman_kg_delete_scheme(struct fman_kg_regs *regs, + uint8_t scheme_id, + uint8_t hwport_id) +{ + struct fman_kg_scheme_regs *kgse_regs; + uint32_t tmp_reg; + int err, i; + + kgse_regs = (struct fman_kg_scheme_regs *)&(regs->fmkg_indirect[0]); + + /* Clear all registers including enable bit in mode register */ + for (i = 0; i < (sizeof(struct fman_kg_scheme_regs)) / 4; ++i) { + iowrite32be(0, ((uint32_t *)kgse_regs + i)); + } + + /* Write AR (Action register) */ + tmp_reg = build_ar_scheme(scheme_id, hwport_id, FALSE, TRUE); + err = fman_kg_write_ar_wait(regs, tmp_reg); + return err; +} + +int fman_kg_get_scheme_counter(struct fman_kg_regs *regs, + uint8_t scheme_id, + uint8_t hwport_id, + uint32_t *counter) +{ + struct fman_kg_scheme_regs *kgse_regs; + uint32_t tmp_reg; + int err; + + kgse_regs = (struct fman_kg_scheme_regs *)&(regs->fmkg_indirect[0]); + + tmp_reg = build_ar_scheme(scheme_id, hwport_id, TRUE, FALSE); + err = fman_kg_write_ar_wait(regs, tmp_reg); + + if (err != 0) + return err; + + *counter = ioread32be(&kgse_regs->kgse_spc); + + return 0; +} + +int fman_kg_set_scheme_counter(struct fman_kg_regs *regs, + uint8_t scheme_id, + uint8_t hwport_id, + uint32_t counter) +{ + struct fman_kg_scheme_regs *kgse_regs; + uint32_t tmp_reg; + int err; + + kgse_regs = (struct fman_kg_scheme_regs *)&(regs->fmkg_indirect[0]); + + tmp_reg = build_ar_scheme(scheme_id, hwport_id, TRUE, FALSE); + + err = fman_kg_write_ar_wait(regs, tmp_reg); + if (err != 0) + return err; + + /* Keygen indirect access memory contains all scheme_id registers + * by now. Change only counter value. */ + iowrite32be(counter, &kgse_regs->kgse_spc); + + /* Write back scheme registers */ + tmp_reg = build_ar_scheme(scheme_id, hwport_id, TRUE, TRUE); + err = fman_kg_write_ar_wait(regs, tmp_reg); + + return err; +} + +uint32_t fman_kg_get_schemes_total_counter(struct fman_kg_regs *regs) +{ + return ioread32be(®s->fmkg_tpc); +} + +int fman_kg_build_cls_plan(struct fman_kg_cls_plan_params *params, + struct fman_kg_cp_regs *cls_plan_regs) +{ + uint8_t entries_set, entry_bit; + int i; + + /* Zero out all group's register */ + memset(cls_plan_regs, 0, sizeof(struct fman_kg_cp_regs)); + + /* Go over all classification entries in params->entries_mask and + * configure the corresponding cpe register */ + entries_set = params->entries_mask; + for (i = 0; entries_set; i++) { + entry_bit = (uint8_t)(0x80 >> i); + if ((entry_bit & entries_set) == 0) + continue; + entries_set ^= entry_bit; + cls_plan_regs->kgcpe[i] = params->mask_vector[i]; + } + + return 0; +} + +int fman_kg_write_cls_plan(struct fman_kg_regs *regs, + uint8_t grp_id, + uint8_t entries_mask, + uint8_t hwport_id, + struct fman_kg_cp_regs *cls_plan_regs) +{ + struct fman_kg_cp_regs *kgcpe_regs; + uint32_t tmp_reg; + int i, err; + + /* Check group index is valid and the group isn't empty */ + if (grp_id >= FM_KG_CLS_PLAN_GRPS_NUM) + return -EINVAL; + + /* Write indirect classification plan registers */ + kgcpe_regs = (struct fman_kg_cp_regs *)&(regs->fmkg_indirect[0]); + + for (i = 0; i < FM_KG_NUM_CLS_PLAN_ENTR; i++) { + iowrite32be(cls_plan_regs->kgcpe[i], &kgcpe_regs->kgcpe[i]); + } + + tmp_reg = build_ar_cls_plan(grp_id, entries_mask, hwport_id, TRUE); + err = fman_kg_write_ar_wait(regs, tmp_reg); + return err; +} + +int fman_kg_write_bind_schemes(struct fman_kg_regs *regs, + uint8_t hwport_id, + uint32_t schemes) +{ + struct fman_kg_pe_regs *kg_pe_regs; + uint32_t tmp_reg; + int err; + + kg_pe_regs = (struct fman_kg_pe_regs *)&(regs->fmkg_indirect[0]); + + iowrite32be(schemes, &kg_pe_regs->fmkg_pe_sp); + + tmp_reg = build_ar_bind_scheme(hwport_id, TRUE); + err = fman_kg_write_ar_wait(regs, tmp_reg); + return err; +} + +int fman_kg_build_bind_cls_plans(uint8_t grp_base, + uint8_t grp_mask, + uint32_t *bind_cls_plans) +{ + /* Check grp_base and grp_mask are 5-bits values */ + if ((grp_base & ~0x0000001F) || (grp_mask & ~0x0000001F)) + return -EINVAL; + + *bind_cls_plans = (uint32_t) ((grp_mask << FMAN_KG_PE_CPP_MASK_SHIFT) | grp_base); + return 0; +} + + +int fman_kg_write_bind_cls_plans(struct fman_kg_regs *regs, + uint8_t hwport_id, + uint32_t bind_cls_plans) +{ + struct fman_kg_pe_regs *kg_pe_regs; + uint32_t tmp_reg; + int err; + + kg_pe_regs = (struct fman_kg_pe_regs *)&(regs->fmkg_indirect[0]); + + iowrite32be(bind_cls_plans, &kg_pe_regs->fmkg_pe_cpp); + + tmp_reg = build_ar_bind_cls_plan(hwport_id, TRUE); + err = fman_kg_write_ar_wait(regs, tmp_reg); + return err; +} diff --git a/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Pcd/fman_prs.c b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Pcd/fman_prs.c new file mode 100644 index 000000000000..108779dbaf40 --- /dev/null +++ b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Pcd/fman_prs.c @@ -0,0 +1,129 @@ +/* + * Copyright 2012 Freescale Semiconductor Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Freescale Semiconductor nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * + * ALTERNATIVELY, this software may be distributed under the terms of the + * GNU General Public License ("GPL") as published by the Free Software + * Foundation, either version 2 of that License or (at your option) any + * later version. + * + * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "fsl_fman_prs.h" + +uint32_t fman_prs_get_err_event(struct fman_prs_regs *regs, uint32_t ev_mask) +{ + return ioread32be(®s->fmpr_perr) & ev_mask; +} + +uint32_t fman_prs_get_err_ev_mask(struct fman_prs_regs *regs) +{ + return ioread32be(®s->fmpr_perer); +} + +void fman_prs_ack_err_event(struct fman_prs_regs *regs, uint32_t event) +{ + iowrite32be(event, ®s->fmpr_perr); +} + +uint32_t fman_prs_get_expt_event(struct fman_prs_regs *regs, uint32_t ev_mask) +{ + return ioread32be(®s->fmpr_pevr) & ev_mask; +} + +uint32_t fman_prs_get_expt_ev_mask(struct fman_prs_regs *regs) +{ + return ioread32be(®s->fmpr_pever); +} + +void fman_prs_ack_expt_event(struct fman_prs_regs *regs, uint32_t event) +{ + iowrite32be(event, ®s->fmpr_pevr); +} + +void fman_prs_defconfig(struct fman_prs_cfg *cfg) +{ + cfg->port_id_stat = 0; + cfg->max_prs_cyc_lim = DEFAULT_MAX_PRS_CYC_LIM; + cfg->prs_exceptions = 0x03000000; +} + +int fman_prs_init(struct fman_prs_regs *regs, struct fman_prs_cfg *cfg) +{ + uint32_t tmp; + + iowrite32be(cfg->max_prs_cyc_lim, ®s->fmpr_rpclim); + iowrite32be((FM_PCD_PRS_SINGLE_ECC | FM_PCD_PRS_PORT_IDLE_STS), + ®s->fmpr_pevr); + + if (cfg->prs_exceptions & FM_PCD_EX_PRS_SINGLE_ECC) + iowrite32be(FM_PCD_PRS_SINGLE_ECC, ®s->fmpr_pever); + else + iowrite32be(0, ®s->fmpr_pever); + + iowrite32be(FM_PCD_PRS_DOUBLE_ECC, ®s->fmpr_perr); + + tmp = 0; + if (cfg->prs_exceptions & FM_PCD_EX_PRS_DOUBLE_ECC) + tmp |= FM_PCD_PRS_DOUBLE_ECC; + iowrite32be(tmp, ®s->fmpr_perer); + + iowrite32be(cfg->port_id_stat, ®s->fmpr_ppsc); + + return 0; +} + +void fman_prs_enable(struct fman_prs_regs *regs) +{ + uint32_t tmp; + + tmp = ioread32be(®s->fmpr_rpimac) | FM_PCD_PRS_RPIMAC_EN; + iowrite32be(tmp, ®s->fmpr_rpimac); +} + +void fman_prs_disable(struct fman_prs_regs *regs) +{ + uint32_t tmp; + + tmp = ioread32be(®s->fmpr_rpimac) & ~FM_PCD_PRS_RPIMAC_EN; + iowrite32be(tmp, ®s->fmpr_rpimac); +} + +int fman_prs_is_enabled(struct fman_prs_regs *regs) +{ + return ioread32be(®s->fmpr_rpimac) & FM_PCD_PRS_RPIMAC_EN; +} + +void fman_prs_set_stst_port_msk(struct fman_prs_regs *regs, uint32_t pid_msk) +{ + iowrite32be(pid_msk, ®s->fmpr_ppsc); +} + +void fman_prs_set_stst(struct fman_prs_regs *regs, bool enable) +{ + if (enable) + iowrite32be(FM_PCD_PRS_PPSC_ALL_PORTS, ®s->fmpr_ppsc); + else + iowrite32be(0, ®s->fmpr_ppsc); +} diff --git a/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Port/Makefile b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Port/Makefile new file mode 100644 index 000000000000..7d928e0a4aac --- /dev/null +++ b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Port/Makefile @@ -0,0 +1,15 @@ +# +# Makefile for the Freescale Ethernet controllers +# +ccflags-y += -DVERSION=\"\" +# +#Include netcomm SW specific definitions +include $(srctree)/drivers/net/ethernet/freescale/sdk_fman/ncsw_config.mk + +NCSW_FM_INC = $(srctree)/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/inc + +ccflags-y += -I$(NCSW_FM_INC) + +obj-y += fsl-ncsw-Pcd.o + +fsl-ncsw-Pcd-objs := fm_port.o fm_port_im.o fman_port.o diff --git a/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Port/fm_port.c b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Port/fm_port.c new file mode 100644 index 000000000000..73a28bf5b163 --- /dev/null +++ b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Port/fm_port.c @@ -0,0 +1,6442 @@ +/* + * Copyright 2008-2012 Freescale Semiconductor Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Freescale Semiconductor nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * + * ALTERNATIVELY, this software may be distributed under the terms of the + * GNU General Public License ("GPL") as published by the Free Software + * Foundation, either version 2 of that License or (at your option) any + * later version. + * + * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + +/****************************************************************************** + @File fm_port.c + + @Description FM driver routines implementation. + *//***************************************************************************/ +#include "error_ext.h" +#include "std_ext.h" +#include "string_ext.h" +#include "sprint_ext.h" +#include "debug_ext.h" +#include "fm_muram_ext.h" + +#include "fman_common.h" +#include "fm_port.h" +#include "fm_port_dsar.h" +#include "common/general.h" + +/****************************************/ +/* static functions */ +/****************************************/ +static t_Error FmPortConfigAutoResForDeepSleepSupport1(t_FmPort *p_FmPort); + +static t_Error CheckInitParameters(t_FmPort *p_FmPort) +{ + t_FmPortDriverParam *p_Params = p_FmPort->p_FmPortDriverParam; + struct fman_port_cfg *p_DfltConfig = &p_Params->dfltCfg; + t_Error ans = E_OK; + uint32_t unusedMask; + + if (p_FmPort->imEn) + { + if (p_FmPort->portType == e_FM_PORT_TYPE_RX_10G) + if (p_FmPort->p_FmPortDriverParam->dfltCfg.tx_fifo_deq_pipeline_depth + > 2) + RETURN_ERROR( + MAJOR, + E_INVALID_VALUE, + ("fifoDeqPipelineDepth for IM 10G can't be larger than 2")); + + if ((ans = FmPortImCheckInitParameters(p_FmPort)) != E_OK) + return ERROR_CODE(ans); + } + else + { + /****************************************/ + /* Rx only */ + /****************************************/ + if ((p_FmPort->portType == e_FM_PORT_TYPE_RX) + || (p_FmPort->portType == e_FM_PORT_TYPE_RX_10G)) + { + /* external buffer pools */ + if (!p_Params->extBufPools.numOfPoolsUsed) + RETURN_ERROR( + MAJOR, + E_INVALID_VALUE, + ("extBufPools.numOfPoolsUsed=0. At least one buffer pool must be defined")); + + if (FmSpCheckBufPoolsParams(&p_Params->extBufPools, + p_Params->p_BackupBmPools, + &p_Params->bufPoolDepletion) != E_OK) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, NO_MSG); + + /* Check that part of IC that needs copying is small enough to enter start margin */ + if (p_Params->intContext.size + && (p_Params->intContext.size + + p_Params->intContext.extBufOffset + > p_Params->bufMargins.startMargins)) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, + ("intContext.size is larger than start margins")); + + if ((p_Params->liodnOffset != (uint16_t)DPAA_LIODN_DONT_OVERRIDE) + && (p_Params->liodnOffset & ~FM_LIODN_OFFSET_MASK)) + RETURN_ERROR( + MAJOR, + E_INVALID_VALUE, + ("liodnOffset is larger than %d", FM_LIODN_OFFSET_MASK+1)); + +#ifdef FM_NO_BACKUP_POOLS + if ((p_FmPort->fmRevInfo.majorRev != 4) && (p_FmPort->fmRevInfo.majorRev < 6)) + if (p_FmPort->p_FmPortDriverParam->p_BackupBmPools) + RETURN_ERROR(MAJOR, E_NOT_SUPPORTED, ("BackupBmPools")); +#endif /* FM_NO_BACKUP_POOLS */ + } + + /****************************************/ + /* Non Rx ports */ + /****************************************/ + else + { + if (p_Params->deqSubPortal >= FM_MAX_NUM_OF_SUB_PORTALS) + RETURN_ERROR( + MAJOR, + E_INVALID_VALUE, + (" deqSubPortal has to be in the range of 0 - %d", FM_MAX_NUM_OF_SUB_PORTALS)); + + /* to protect HW internal-context from overwrite */ + if ((p_Params->intContext.size) + && (p_Params->intContext.intContextOffset + < MIN_TX_INT_OFFSET)) + RETURN_ERROR( + MAJOR, + E_INVALID_VALUE, + ("non-Rx intContext.intContextOffset can't be smaller than %d", MIN_TX_INT_OFFSET)); + + if ((p_FmPort->portType == e_FM_PORT_TYPE_TX) + || (p_FmPort->portType == e_FM_PORT_TYPE_TX_10G) + /* in O/H DEFAULT_notSupported indicates that it is not supported and should not be checked */ + || (p_FmPort->p_FmPortDriverParam->dfltCfg.tx_fifo_deq_pipeline_depth + != DEFAULT_notSupported)) + { + /* Check that not larger than 8 */ + if ((!p_FmPort->p_FmPortDriverParam->dfltCfg.tx_fifo_deq_pipeline_depth) + || (p_FmPort->p_FmPortDriverParam->dfltCfg.tx_fifo_deq_pipeline_depth + > MAX_FIFO_PIPELINE_DEPTH)) + RETURN_ERROR( + MAJOR, + E_INVALID_VALUE, + ("fifoDeqPipelineDepth can't be larger than %d", MAX_FIFO_PIPELINE_DEPTH)); + } + } + + /****************************************/ + /* Rx Or Offline Parsing */ + /****************************************/ + if ((p_FmPort->portType == e_FM_PORT_TYPE_RX) + || (p_FmPort->portType == e_FM_PORT_TYPE_RX_10G) + || (p_FmPort->portType == e_FM_PORT_TYPE_OH_OFFLINE_PARSING)) + { + if (!p_Params->dfltFqid) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, + ("dfltFqid must be between 1 and 2^24-1")); +#if defined(FM_CAPWAP_SUPPORT) && defined(FM_LOCKUP_ALIGNMENT_ERRATA_FMAN_SW004) + if (p_FmPort->p_FmPortDriverParam->bufferPrefixContent.manipExtraSpace % 16) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("bufferPrefixContent.manipExtraSpace has to be devidable by 16")); +#endif /* defined(FM_CAPWAP_SUPPORT) && ... */ + } + + /****************************************/ + /* All ports */ + /****************************************/ + /* common BMI registers values */ + /* Check that Queue Id is not larger than 2^24, and is not 0 */ + if ((p_Params->errFqid & ~0x00FFFFFF) || !p_Params->errFqid) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, + ("errFqid must be between 1 and 2^24-1")); + if (p_Params->dfltFqid & ~0x00FFFFFF) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, + ("dfltFqid must be between 1 and 2^24-1")); + } + + /****************************************/ + /* Rx only */ + /****************************************/ + if ((p_FmPort->portType == e_FM_PORT_TYPE_RX) + || (p_FmPort->portType == e_FM_PORT_TYPE_RX_10G)) + { + if (p_DfltConfig->rx_pri_elevation % BMI_FIFO_UNITS) + RETURN_ERROR( + MAJOR, + E_INVALID_VALUE, + ("rxFifoPriElevationLevel has to be divisible by %d", BMI_FIFO_UNITS)); + if ((p_DfltConfig->rx_pri_elevation < BMI_FIFO_UNITS) + || (p_DfltConfig->rx_pri_elevation > MAX_PORT_FIFO_SIZE)) + RETURN_ERROR( + MAJOR, + E_INVALID_VALUE, + ("rxFifoPriElevationLevel has to be in the range of 256 - %d", MAX_PORT_FIFO_SIZE)); + if (p_DfltConfig->rx_fifo_thr % BMI_FIFO_UNITS) + RETURN_ERROR( + MAJOR, + E_INVALID_VALUE, + ("rxFifoThreshold has to be divisible by %d", BMI_FIFO_UNITS)); + if ((p_DfltConfig->rx_fifo_thr < BMI_FIFO_UNITS) + || (p_DfltConfig->rx_fifo_thr > MAX_PORT_FIFO_SIZE)) + RETURN_ERROR( + MAJOR, + E_INVALID_VALUE, + ("rxFifoThreshold has to be in the range of 256 - %d", MAX_PORT_FIFO_SIZE)); + + /* Check that not larger than 16 */ + if (p_DfltConfig->rx_cut_end_bytes > FRAME_END_DATA_SIZE) + RETURN_ERROR( + MAJOR, + E_INVALID_VALUE, + ("cutBytesFromEnd can't be larger than %d", FRAME_END_DATA_SIZE)); + + if (FmSpCheckBufMargins(&p_Params->bufMargins) != E_OK) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, NO_MSG); + + /* extra FIFO size (allowed only to Rx ports) */ + if (p_Params->setSizeOfFifo + && (p_FmPort->fifoBufs.extra % BMI_FIFO_UNITS)) + RETURN_ERROR( + MAJOR, + E_INVALID_VALUE, + ("fifoBufs.extra has to be divisible by %d", BMI_FIFO_UNITS)); + + if (p_Params->bufPoolDepletion.poolsGrpModeEnable + && !p_Params->bufPoolDepletion.numOfPools) + RETURN_ERROR( + MAJOR, + E_INVALID_VALUE, + ("bufPoolDepletion.numOfPools can not be 0 when poolsGrpModeEnable=TRUE")); +#ifdef FM_CSI_CFED_LIMIT + if (p_FmPort->fmRevInfo.majorRev == 4) + { + /* Check that not larger than 16 */ + if (p_DfltConfig->rx_cut_end_bytes + p_DfltConfig->checksum_bytes_ignore > FRAME_END_DATA_SIZE) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("cheksumLastBytesIgnore + cutBytesFromEnd can't be larger than %d", FRAME_END_DATA_SIZE)); + } +#endif /* FM_CSI_CFED_LIMIT */ + } + + /****************************************/ + /* Non Rx ports */ + /****************************************/ + /* extra FIFO size (allowed only to Rx ports) */ + else + if (p_FmPort->fifoBufs.extra) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, + (" No fifoBufs.extra for non Rx ports")); + + /****************************************/ + /* Tx only */ + /****************************************/ + if ((p_FmPort->portType == e_FM_PORT_TYPE_TX) + || (p_FmPort->portType == e_FM_PORT_TYPE_TX_10G)) + { + if (p_DfltConfig->tx_fifo_min_level % BMI_FIFO_UNITS) + RETURN_ERROR( + MAJOR, + E_INVALID_VALUE, + ("txFifoMinFillLevel has to be divisible by %d", BMI_FIFO_UNITS)); + if (p_DfltConfig->tx_fifo_min_level > (MAX_PORT_FIFO_SIZE - 256)) + RETURN_ERROR( + MAJOR, + E_INVALID_VALUE, + ("txFifoMinFillLevel has to be in the range of 0 - %d", (MAX_PORT_FIFO_SIZE - 256))); + if (p_DfltConfig->tx_fifo_low_comf_level % BMI_FIFO_UNITS) + RETURN_ERROR( + MAJOR, + E_INVALID_VALUE, + ("txFifoLowComfLevel has to be divisible by %d", BMI_FIFO_UNITS)); + if ((p_DfltConfig->tx_fifo_low_comf_level < BMI_FIFO_UNITS) + || (p_DfltConfig->tx_fifo_low_comf_level > MAX_PORT_FIFO_SIZE)) + RETURN_ERROR( + MAJOR, + E_INVALID_VALUE, + ("txFifoLowComfLevel has to be in the range of 256 - %d", MAX_PORT_FIFO_SIZE)); + + if (p_FmPort->portType == e_FM_PORT_TYPE_TX) + if (p_FmPort->p_FmPortDriverParam->dfltCfg.tx_fifo_deq_pipeline_depth + > 2) + RETURN_ERROR( + MAJOR, E_INVALID_VALUE, + ("fifoDeqPipelineDepth for 1G can't be larger than 2")); + } + + /****************************************/ + /* Non Tx Ports */ + /****************************************/ + /* If discard override was selected , no frames may be discarded. */ + else + if (p_DfltConfig->discard_override && p_Params->errorsToDiscard) + RETURN_ERROR( + MAJOR, + E_CONFLICT, + ("errorsToDiscard is not empty, but frmDiscardOverride selected (all discarded frames to be enqueued to error queue).")); + + /****************************************/ + /* Rx and Offline parsing */ + /****************************************/ + if ((p_FmPort->portType == e_FM_PORT_TYPE_RX) + || (p_FmPort->portType == e_FM_PORT_TYPE_RX_10G) + || (p_FmPort->portType == e_FM_PORT_TYPE_OH_OFFLINE_PARSING)) + { + if (p_FmPort->portType == e_FM_PORT_TYPE_OH_OFFLINE_PARSING) + unusedMask = BMI_STATUS_OP_MASK_UNUSED; + else + unusedMask = BMI_STATUS_RX_MASK_UNUSED; + + /* Check that no common bits with BMI_STATUS_MASK_UNUSED */ + if (p_Params->errorsToDiscard & unusedMask) + RETURN_ERROR(MAJOR, E_INVALID_SELECTION, + ("errorsToDiscard contains undefined bits")); + } + + /****************************************/ + /* Offline Ports */ + /****************************************/ +#ifdef FM_OP_OPEN_DMA_MIN_LIMIT + if ((p_FmPort->fmRevInfo.majorRev >= 6) + && (p_FmPort->portType == e_FM_PORT_TYPE_OH_OFFLINE_PARSING) + && p_Params->setNumOfOpenDmas + && (p_FmPort->openDmas.num < MIN_NUM_OF_OP_DMAS)) + RETURN_ERROR( + MAJOR, + E_INVALID_VALUE, + ("For Offline port, openDmas.num can't be smaller than %d", MIN_NUM_OF_OP_DMAS)); +#endif /* FM_OP_OPEN_DMA_MIN_LIMIT */ + + /****************************************/ + /* Offline & HC Ports */ + /****************************************/ + if ((p_FmPort->portType == e_FM_PORT_TYPE_OH_OFFLINE_PARSING) + || (p_FmPort->portType == e_FM_PORT_TYPE_OH_HOST_COMMAND)) + { +#ifndef FM_FRAME_END_PARAMS_FOR_OP + if ((p_FmPort->fmRevInfo.majorRev < 6) && + (p_FmPort->p_FmPortDriverParam->cheksumLastBytesIgnore != DEFAULT_notSupported)) + /* this is an indication that user called config for this mode which is not supported in this integration */ + RETURN_ERROR(MAJOR, E_NOT_SUPPORTED, ("cheksumLastBytesIgnore is available for Rx & Tx ports only")); +#endif /* !FM_FRAME_END_PARAMS_FOR_OP */ + +#ifndef FM_DEQ_PIPELINE_PARAMS_FOR_OP + if ((!((p_FmPort->fmRevInfo.majorRev == 4) || + (p_FmPort->fmRevInfo.majorRev >= 6))) && + (p_FmPort->p_FmPortDriverParam->dfltCfg.tx_fifo_deq_pipeline_depth != DEFAULT_notSupported)) + /* this is an indication that user called config for this mode which is not supported in this integration */ + RETURN_ERROR(MAJOR, E_INVALID_OPERATION, ("fifoDeqPipelineDepth is available for Tx ports only")); +#endif /* !FM_DEQ_PIPELINE_PARAMS_FOR_OP */ + } + + /****************************************/ + /* All ports */ + /****************************************/ + /* Check that not larger than 16 */ + if ((p_Params->cheksumLastBytesIgnore > FRAME_END_DATA_SIZE) + && ((p_Params->cheksumLastBytesIgnore != DEFAULT_notSupported))) + RETURN_ERROR( + MAJOR, + E_INVALID_VALUE, + ("cheksumLastBytesIgnore can't be larger than %d", FRAME_END_DATA_SIZE)); + + if (FmSpCheckIntContextParams(&p_Params->intContext) != E_OK) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, NO_MSG); + + /* common BMI registers values */ + if (p_Params->setNumOfTasks + && ((!p_FmPort->tasks.num) + || (p_FmPort->tasks.num > MAX_NUM_OF_TASKS))) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, + ("tasks.num can't be larger than %d", MAX_NUM_OF_TASKS)); + if (p_Params->setNumOfTasks + && (p_FmPort->tasks.extra > MAX_NUM_OF_EXTRA_TASKS)) + RETURN_ERROR( + MAJOR, + E_INVALID_VALUE, + ("tasks.extra can't be larger than %d", MAX_NUM_OF_EXTRA_TASKS)); + if (p_Params->setNumOfOpenDmas + && ((!p_FmPort->openDmas.num) + || (p_FmPort->openDmas.num > MAX_NUM_OF_DMAS))) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, + ("openDmas.num can't be larger than %d", MAX_NUM_OF_DMAS)); + if (p_Params->setNumOfOpenDmas + && (p_FmPort->openDmas.extra > MAX_NUM_OF_EXTRA_DMAS)) + RETURN_ERROR( + MAJOR, + E_INVALID_VALUE, + ("openDmas.extra can't be larger than %d", MAX_NUM_OF_EXTRA_DMAS)); + if (p_Params->setSizeOfFifo + && (!p_FmPort->fifoBufs.num + || (p_FmPort->fifoBufs.num > MAX_PORT_FIFO_SIZE))) + RETURN_ERROR( + MAJOR, + E_INVALID_VALUE, + ("fifoBufs.num has to be in the range of 256 - %d", MAX_PORT_FIFO_SIZE)); + if (p_Params->setSizeOfFifo && (p_FmPort->fifoBufs.num % BMI_FIFO_UNITS)) + RETURN_ERROR( + MAJOR, E_INVALID_VALUE, + ("fifoBufs.num has to be divisible by %d", BMI_FIFO_UNITS)); + +#ifdef FM_QMI_NO_DEQ_OPTIONS_SUPPORT + if (p_FmPort->fmRevInfo.majorRev == 4) + if (p_FmPort->p_FmPortDriverParam->deqPrefetchOption != DEFAULT_notSupported) + /* this is an indication that user called config for this mode which is not supported in this integration */ + RETURN_ERROR(MAJOR, E_INVALID_OPERATION, ("deqPrefetchOption")); +#endif /* FM_QMI_NO_DEQ_OPTIONS_SUPPORT */ + + return E_OK; +} + +static t_Error VerifySizeOfFifo(t_FmPort *p_FmPort) +{ + uint32_t minFifoSizeRequired = 0, optFifoSizeForB2B = 0; + + /*************************/ + /* TX PORTS */ + /*************************/ + if ((p_FmPort->portType == e_FM_PORT_TYPE_TX) + || (p_FmPort->portType == e_FM_PORT_TYPE_TX_10G)) + { + minFifoSizeRequired = + (uint32_t)(ROUND_UP(p_FmPort->maxFrameLength, BMI_FIFO_UNITS) + + (3 * BMI_FIFO_UNITS)); + if (!p_FmPort->imEn) + minFifoSizeRequired += + p_FmPort->p_FmPortDriverParam->dfltCfg.tx_fifo_deq_pipeline_depth + * BMI_FIFO_UNITS; + + optFifoSizeForB2B = minFifoSizeRequired; + + /* Add some margin for back-to-back capability to improve performance, + allows the hardware to pipeline new frame dma while the previous + frame not yet transmitted. */ + if (p_FmPort->portType == e_FM_PORT_TYPE_TX_10G) + optFifoSizeForB2B += 3 * BMI_FIFO_UNITS; + else + optFifoSizeForB2B += 2 * BMI_FIFO_UNITS; + } + + /*************************/ + /* RX IM PORTS */ + /*************************/ + else + if (((p_FmPort->portType == e_FM_PORT_TYPE_RX) + || (p_FmPort->portType == e_FM_PORT_TYPE_RX_10G)) + && p_FmPort->imEn) + { + optFifoSizeForB2B = + minFifoSizeRequired = + (uint32_t)(ROUND_UP(p_FmPort->maxFrameLength, BMI_FIFO_UNITS) + + (4 * BMI_FIFO_UNITS)); + } + + /*************************/ + /* RX non-IM PORTS */ + /*************************/ + else + if (((p_FmPort->portType == e_FM_PORT_TYPE_RX) + || (p_FmPort->portType == e_FM_PORT_TYPE_RX_10G)) + && !p_FmPort->imEn) + { + if (p_FmPort->fmRevInfo.majorRev == 4) + { + if (p_FmPort->rxPoolsParams.numOfPools == 1) + minFifoSizeRequired = 8 * BMI_FIFO_UNITS; + else + minFifoSizeRequired = + (uint32_t)(ROUND_UP(p_FmPort->rxPoolsParams.secondLargestBufSize, BMI_FIFO_UNITS) + + (7 * BMI_FIFO_UNITS)); + } + else + { +#if (DPAA_VERSION >= 11) + minFifoSizeRequired = + (uint32_t)(ROUND_UP(p_FmPort->maxFrameLength, BMI_FIFO_UNITS) + + (5 * BMI_FIFO_UNITS)); + /* 4 according to spec + 1 for FOF>0 */ +#else + minFifoSizeRequired = (uint32_t) + (ROUND_UP(MIN(p_FmPort->maxFrameLength, p_FmPort->rxPoolsParams.largestBufSize), BMI_FIFO_UNITS) + + (7*BMI_FIFO_UNITS)); +#endif /* (DPAA_VERSION >= 11) */ + } + + optFifoSizeForB2B = minFifoSizeRequired; + + /* Add some margin for back-to-back capability to improve performance, + allows the hardware to pipeline new frame dma while the previous + frame not yet transmitted. */ + if (p_FmPort->portType == e_FM_PORT_TYPE_RX_10G) + optFifoSizeForB2B += 8 * BMI_FIFO_UNITS; + else + optFifoSizeForB2B += 3 * BMI_FIFO_UNITS; + } + + /* For O/H ports, check fifo size and update if necessary */ + else + if ((p_FmPort->portType == e_FM_PORT_TYPE_OH_OFFLINE_PARSING) + || (p_FmPort->portType == e_FM_PORT_TYPE_OH_HOST_COMMAND)) + { +#if (DPAA_VERSION >= 11) + optFifoSizeForB2B = + minFifoSizeRequired = + (uint32_t)(ROUND_UP(p_FmPort->maxFrameLength, BMI_FIFO_UNITS) + + ((p_FmPort->p_FmPortDriverParam->dfltCfg.tx_fifo_deq_pipeline_depth + + 5) * BMI_FIFO_UNITS)); + /* 4 according to spec + 1 for FOF>0 */ +#else + optFifoSizeForB2B = minFifoSizeRequired = (uint32_t)((p_FmPort->tasks.num + 2) * BMI_FIFO_UNITS); +#endif /* (DPAA_VERSION >= 11) */ + } + + ASSERT_COND(minFifoSizeRequired > 0); + ASSERT_COND(optFifoSizeForB2B >= minFifoSizeRequired); + + /* Verify the size */ + if (p_FmPort->fifoBufs.num < minFifoSizeRequired) + DBG(INFO, + ("FIFO size is %d and should be enlarged to %d bytes",p_FmPort->fifoBufs.num, minFifoSizeRequired)); + else if (p_FmPort->fifoBufs.num < optFifoSizeForB2B) + DBG(INFO, + ("For back-to-back frames processing, FIFO size is %d and needs to enlarge to %d bytes", p_FmPort->fifoBufs.num, optFifoSizeForB2B)); + + return E_OK; +} + +static void FmPortDriverParamFree(t_FmPort *p_FmPort) +{ + if (p_FmPort->p_FmPortDriverParam) + { + XX_Free(p_FmPort->p_FmPortDriverParam); + p_FmPort->p_FmPortDriverParam = NULL; + } +} + +static t_Error SetExtBufferPools(t_FmPort *p_FmPort) +{ + t_FmExtPools *p_ExtBufPools = &p_FmPort->p_FmPortDriverParam->extBufPools; + t_FmBufPoolDepletion *p_BufPoolDepletion = + &p_FmPort->p_FmPortDriverParam->bufPoolDepletion; + uint8_t orderedArray[FM_PORT_MAX_NUM_OF_EXT_POOLS]; + uint16_t sizesArray[BM_MAX_NUM_OF_POOLS]; + int i = 0, j = 0, err; + struct fman_port_bpools bpools; + + memset(&orderedArray, 0, sizeof(uint8_t) * FM_PORT_MAX_NUM_OF_EXT_POOLS); + memset(&sizesArray, 0, sizeof(uint16_t) * BM_MAX_NUM_OF_POOLS); + memcpy(&p_FmPort->extBufPools, p_ExtBufPools, sizeof(t_FmExtPools)); + + FmSpSetBufPoolsInAscOrderOfBufSizes(p_ExtBufPools, orderedArray, + sizesArray); + + /* Prepare flibs bpools structure */ + memset(&bpools, 0, sizeof(struct fman_port_bpools)); + bpools.count = p_ExtBufPools->numOfPoolsUsed; + bpools.counters_enable = TRUE; + for (i = 0; i < p_ExtBufPools->numOfPoolsUsed; i++) + { + bpools.bpool[i].bpid = orderedArray[i]; + bpools.bpool[i].size = sizesArray[orderedArray[i]]; + /* functionality available only for some derivatives (limited by config) */ + if (p_FmPort->p_FmPortDriverParam->p_BackupBmPools) + for (j = 0; + j + < p_FmPort->p_FmPortDriverParam->p_BackupBmPools->numOfBackupPools; + j++) + if (orderedArray[i] + == p_FmPort->p_FmPortDriverParam->p_BackupBmPools->poolIds[j]) + { + bpools.bpool[i].is_backup = TRUE; + break; + } + } + + /* save pools parameters for later use */ + p_FmPort->rxPoolsParams.numOfPools = p_ExtBufPools->numOfPoolsUsed; + p_FmPort->rxPoolsParams.largestBufSize = + sizesArray[orderedArray[p_ExtBufPools->numOfPoolsUsed - 1]]; + if (p_ExtBufPools->numOfPoolsUsed > 1) + p_FmPort->rxPoolsParams.secondLargestBufSize = + sizesArray[orderedArray[p_ExtBufPools->numOfPoolsUsed - 2]]; + + /* FMBM_RMPD reg. - pool depletion */ + if (p_BufPoolDepletion->poolsGrpModeEnable) + { + bpools.grp_bp_depleted_num = p_BufPoolDepletion->numOfPools; + for (i = 0; i < BM_MAX_NUM_OF_POOLS; i++) + { + if (p_BufPoolDepletion->poolsToConsider[i]) + { + for (j = 0; j < p_ExtBufPools->numOfPoolsUsed; j++) + { + if (i == orderedArray[j]) + { + bpools.bpool[j].grp_bp_depleted = TRUE; + break; + } + } + } + } + } + + if (p_BufPoolDepletion->singlePoolModeEnable) + { + for (i = 0; i < BM_MAX_NUM_OF_POOLS; i++) + { + if (p_BufPoolDepletion->poolsToConsiderForSingleMode[i]) + { + for (j = 0; j < p_ExtBufPools->numOfPoolsUsed; j++) + { + if (i == orderedArray[j]) + { + bpools.bpool[j].single_bp_depleted = TRUE; + break; + } + } + } + } + } + +#if (DPAA_VERSION >= 11) + /* fill QbbPEV */ + if (p_BufPoolDepletion->poolsGrpModeEnable + || p_BufPoolDepletion->singlePoolModeEnable) + { + for (i = 0; i < FM_MAX_NUM_OF_PFC_PRIORITIES; i++) + { + if (p_BufPoolDepletion->pfcPrioritiesEn[i] == TRUE) + { + bpools.bpool[i].pfc_priorities_en = TRUE; + } + } + } +#endif /* (DPAA_VERSION >= 11) */ + + /* Issue flibs function */ + err = fman_port_set_bpools(&p_FmPort->port, &bpools); + if (err != 0) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("fman_port_set_bpools")); + + if (p_FmPort->p_FmPortDriverParam->p_BackupBmPools) + XX_Free(p_FmPort->p_FmPortDriverParam->p_BackupBmPools); + + return E_OK; +} + +static t_Error ClearPerfCnts(t_FmPort *p_FmPort) +{ + if (p_FmPort->portType != e_FM_PORT_TYPE_OH_OFFLINE_PARSING) + FM_PORT_ModifyCounter(p_FmPort, e_FM_PORT_COUNTERS_QUEUE_UTIL, 0); + FM_PORT_ModifyCounter(p_FmPort, e_FM_PORT_COUNTERS_TASK_UTIL, 0); + FM_PORT_ModifyCounter(p_FmPort, e_FM_PORT_COUNTERS_DMA_UTIL, 0); + FM_PORT_ModifyCounter(p_FmPort, e_FM_PORT_COUNTERS_FIFO_UTIL, 0); + return E_OK; +} + +static t_Error InitLowLevelDriver(t_FmPort *p_FmPort) +{ + t_FmPortDriverParam *p_DriverParams = p_FmPort->p_FmPortDriverParam; + struct fman_port_params portParams; + uint32_t tmpVal; + t_Error err; + + /* Set up flibs parameters and issue init function */ + + memset(&portParams, 0, sizeof(struct fman_port_params)); + portParams.discard_mask = p_DriverParams->errorsToDiscard; + portParams.dflt_fqid = p_DriverParams->dfltFqid; + portParams.err_fqid = p_DriverParams->errFqid; + portParams.deq_sp = p_DriverParams->deqSubPortal; + portParams.dont_release_buf = p_DriverParams->dontReleaseBuf; + switch (p_FmPort->portType) + { + case (e_FM_PORT_TYPE_RX_10G): + case (e_FM_PORT_TYPE_RX): + portParams.err_mask = (RX_ERRS_TO_ENQ & ~portParams.discard_mask); + if (!p_FmPort->imEn) + { + if (p_DriverParams->forwardReuseIntContext) + p_DriverParams->dfltCfg.rx_fd_bits = + (uint8_t)(BMI_PORT_RFNE_FRWD_RPD >> 24); + } + break; + + case (e_FM_PORT_TYPE_OH_OFFLINE_PARSING): + portParams.err_mask = (OP_ERRS_TO_ENQ & ~portParams.discard_mask); + break; + break; + + default: + break; + } + + tmpVal = + (uint32_t)( + (p_FmPort->internalBufferOffset % OFFSET_UNITS) ? (p_FmPort->internalBufferOffset + / OFFSET_UNITS + 1) : + (p_FmPort->internalBufferOffset / OFFSET_UNITS)); + p_FmPort->internalBufferOffset = (uint8_t)(tmpVal * OFFSET_UNITS); + p_DriverParams->dfltCfg.int_buf_start_margin = + p_FmPort->internalBufferOffset; + + p_DriverParams->dfltCfg.ext_buf_start_margin = + p_DriverParams->bufMargins.startMargins; + p_DriverParams->dfltCfg.ext_buf_end_margin = + p_DriverParams->bufMargins.endMargins; + + p_DriverParams->dfltCfg.ic_ext_offset = + p_DriverParams->intContext.extBufOffset; + p_DriverParams->dfltCfg.ic_int_offset = + p_DriverParams->intContext.intContextOffset; + p_DriverParams->dfltCfg.ic_size = p_DriverParams->intContext.size; + + p_DriverParams->dfltCfg.stats_counters_enable = TRUE; + p_DriverParams->dfltCfg.perf_counters_enable = TRUE; + p_DriverParams->dfltCfg.queue_counters_enable = TRUE; + + p_DriverParams->dfltCfg.perf_cnt_params.task_val = + (uint8_t)p_FmPort->tasks.num; + if (p_FmPort->portType == e_FM_PORT_TYPE_OH_OFFLINE_PARSING || + p_FmPort->portType == e_FM_PORT_TYPE_OH_HOST_COMMAND)p_DriverParams->dfltCfg.perf_cnt_params.queue_val = 0; + else + p_DriverParams->dfltCfg.perf_cnt_params.queue_val = 1; + p_DriverParams->dfltCfg.perf_cnt_params.dma_val = + (uint8_t)p_FmPort->openDmas.num; + p_DriverParams->dfltCfg.perf_cnt_params.fifo_val = p_FmPort->fifoBufs.num; + + if (0 + != fman_port_init(&p_FmPort->port, &p_DriverParams->dfltCfg, + &portParams)) + RETURN_ERROR(MAJOR, E_NO_DEVICE, ("fman_port_init")); + + if (p_FmPort->imEn && ((err = FmPortImInit(p_FmPort)) != E_OK)) + RETURN_ERROR(MAJOR, err, NO_MSG); + else + { + // from QMIInit + if ((p_FmPort->portType != e_FM_PORT_TYPE_RX_10G) + && (p_FmPort->portType != e_FM_PORT_TYPE_RX)) + { + if (p_DriverParams->deqPrefetchOption == e_FM_PORT_DEQ_NO_PREFETCH) + FmSetPortPreFetchConfiguration(p_FmPort->h_Fm, p_FmPort->portId, + FALSE); + else + FmSetPortPreFetchConfiguration(p_FmPort->h_Fm, p_FmPort->portId, + TRUE); + } + } + /* The code bellow is a trick so the FM will not release the buffer + to BM nor will try to enqueue the frame to QM */ + if (((p_FmPort->portType == e_FM_PORT_TYPE_TX_10G) + || (p_FmPort->portType == e_FM_PORT_TYPE_TX)) && (!p_FmPort->imEn)) + { + if (!p_DriverParams->dfltFqid && p_DriverParams->dontReleaseBuf) + { + /* override fmbm_tcfqid 0 with a false non-0 value. This will force FM to + * act according to tfene. Otherwise, if fmbm_tcfqid is 0 the FM will release + * buffers to BM regardless of fmbm_tfene + */ + WRITE_UINT32(p_FmPort->port.bmi_regs->tx.fmbm_tcfqid, 0xFFFFFF); + WRITE_UINT32(p_FmPort->port.bmi_regs->tx.fmbm_tfene, + NIA_ENG_BMI | NIA_BMI_AC_TX_RELEASE); + } + } + + return E_OK; +} + +static bool CheckRxBmiCounter(t_FmPort *p_FmPort, e_FmPortCounters counter) +{ + UNUSED(p_FmPort); + + switch (counter) + { + case (e_FM_PORT_COUNTERS_CYCLE): + case (e_FM_PORT_COUNTERS_TASK_UTIL): + case (e_FM_PORT_COUNTERS_QUEUE_UTIL): + case (e_FM_PORT_COUNTERS_DMA_UTIL): + case (e_FM_PORT_COUNTERS_FIFO_UTIL): + case (e_FM_PORT_COUNTERS_RX_PAUSE_ACTIVATION): + case (e_FM_PORT_COUNTERS_FRAME): + case (e_FM_PORT_COUNTERS_DISCARD_FRAME): + case (e_FM_PORT_COUNTERS_RX_BAD_FRAME): + case (e_FM_PORT_COUNTERS_RX_LARGE_FRAME): + case (e_FM_PORT_COUNTERS_RX_FILTER_FRAME): + case (e_FM_PORT_COUNTERS_RX_LIST_DMA_ERR): + case (e_FM_PORT_COUNTERS_RX_OUT_OF_BUFFERS_DISCARD): + case (e_FM_PORT_COUNTERS_DEALLOC_BUF): + case (e_FM_PORT_COUNTERS_PREPARE_TO_ENQUEUE_COUNTER): + return TRUE; + default: + return FALSE; + } +} + +static bool CheckTxBmiCounter(t_FmPort *p_FmPort, e_FmPortCounters counter) +{ + UNUSED(p_FmPort); + + switch (counter) + { + case (e_FM_PORT_COUNTERS_CYCLE): + case (e_FM_PORT_COUNTERS_TASK_UTIL): + case (e_FM_PORT_COUNTERS_QUEUE_UTIL): + case (e_FM_PORT_COUNTERS_DMA_UTIL): + case (e_FM_PORT_COUNTERS_FIFO_UTIL): + case (e_FM_PORT_COUNTERS_FRAME): + case (e_FM_PORT_COUNTERS_DISCARD_FRAME): + case (e_FM_PORT_COUNTERS_LENGTH_ERR): + case (e_FM_PORT_COUNTERS_UNSUPPRTED_FORMAT): + case (e_FM_PORT_COUNTERS_DEALLOC_BUF): + return TRUE; + default: + return FALSE; + } +} + +static bool CheckOhBmiCounter(t_FmPort *p_FmPort, e_FmPortCounters counter) +{ + switch (counter) + { + case (e_FM_PORT_COUNTERS_CYCLE): + case (e_FM_PORT_COUNTERS_TASK_UTIL): + case (e_FM_PORT_COUNTERS_DMA_UTIL): + case (e_FM_PORT_COUNTERS_FIFO_UTIL): + case (e_FM_PORT_COUNTERS_FRAME): + case (e_FM_PORT_COUNTERS_DISCARD_FRAME): + case (e_FM_PORT_COUNTERS_RX_LIST_DMA_ERR): + case (e_FM_PORT_COUNTERS_WRED_DISCARD): + case (e_FM_PORT_COUNTERS_LENGTH_ERR): + case (e_FM_PORT_COUNTERS_UNSUPPRTED_FORMAT): + case (e_FM_PORT_COUNTERS_DEALLOC_BUF): + return TRUE; + case (e_FM_PORT_COUNTERS_RX_FILTER_FRAME): + if (p_FmPort->portType == e_FM_PORT_TYPE_OH_HOST_COMMAND) + return FALSE; + else + return TRUE; + default: + return FALSE; + } +} + +static t_Error BmiPortCheckAndGetCounterType( + t_FmPort *p_FmPort, e_FmPortCounters counter, + enum fman_port_stats_counters *p_StatsType, + enum fman_port_perf_counters *p_PerfType, bool *p_IsStats) +{ + volatile uint32_t *p_Reg; + bool isValid; + + switch (p_FmPort->portType) + { + case (e_FM_PORT_TYPE_RX_10G): + case (e_FM_PORT_TYPE_RX): + p_Reg = &p_FmPort->port.bmi_regs->rx.fmbm_rstc; + isValid = CheckRxBmiCounter(p_FmPort, counter); + break; + case (e_FM_PORT_TYPE_TX_10G): + case (e_FM_PORT_TYPE_TX): + p_Reg = &p_FmPort->port.bmi_regs->tx.fmbm_tstc; + isValid = CheckTxBmiCounter(p_FmPort, counter); + break; + case (e_FM_PORT_TYPE_OH_OFFLINE_PARSING): + case (e_FM_PORT_TYPE_OH_HOST_COMMAND): + p_Reg = &p_FmPort->port.bmi_regs->oh.fmbm_ostc; + isValid = CheckOhBmiCounter(p_FmPort, counter); + break; + default: + RETURN_ERROR(MINOR, E_INVALID_STATE, ("Unsupported port type")); + } + + if (!isValid) + RETURN_ERROR(MINOR, E_INVALID_STATE, + ("Requested counter is not available for this port type")); + + /* check that counters are enabled */ + switch (counter) + { + case (e_FM_PORT_COUNTERS_CYCLE): + case (e_FM_PORT_COUNTERS_TASK_UTIL): + case (e_FM_PORT_COUNTERS_QUEUE_UTIL): + case (e_FM_PORT_COUNTERS_DMA_UTIL): + case (e_FM_PORT_COUNTERS_FIFO_UTIL): + case (e_FM_PORT_COUNTERS_RX_PAUSE_ACTIVATION): + /* performance counters - may be read when disabled */ + *p_IsStats = FALSE; + break; + case (e_FM_PORT_COUNTERS_FRAME): + case (e_FM_PORT_COUNTERS_DISCARD_FRAME): + case (e_FM_PORT_COUNTERS_DEALLOC_BUF): + case (e_FM_PORT_COUNTERS_RX_BAD_FRAME): + case (e_FM_PORT_COUNTERS_RX_LARGE_FRAME): + case (e_FM_PORT_COUNTERS_RX_FILTER_FRAME): + case (e_FM_PORT_COUNTERS_RX_LIST_DMA_ERR): + case (e_FM_PORT_COUNTERS_RX_OUT_OF_BUFFERS_DISCARD): + case (e_FM_PORT_COUNTERS_LENGTH_ERR): + case (e_FM_PORT_COUNTERS_UNSUPPRTED_FORMAT): + case (e_FM_PORT_COUNTERS_WRED_DISCARD): + *p_IsStats = TRUE; + if (!(GET_UINT32(*p_Reg) & BMI_COUNTERS_EN)) + RETURN_ERROR(MINOR, E_INVALID_STATE, + ("Requested counter was not enabled")); + break; + default: + break; + } + + /* Set counter */ + switch (counter) + { + case (e_FM_PORT_COUNTERS_CYCLE): + *p_PerfType = E_FMAN_PORT_PERF_CNT_CYCLE; + break; + case (e_FM_PORT_COUNTERS_TASK_UTIL): + *p_PerfType = E_FMAN_PORT_PERF_CNT_TASK_UTIL; + break; + case (e_FM_PORT_COUNTERS_QUEUE_UTIL): + *p_PerfType = E_FMAN_PORT_PERF_CNT_QUEUE_UTIL; + break; + case (e_FM_PORT_COUNTERS_DMA_UTIL): + *p_PerfType = E_FMAN_PORT_PERF_CNT_DMA_UTIL; + break; + case (e_FM_PORT_COUNTERS_FIFO_UTIL): + *p_PerfType = E_FMAN_PORT_PERF_CNT_FIFO_UTIL; + break; + case (e_FM_PORT_COUNTERS_RX_PAUSE_ACTIVATION): + *p_PerfType = E_FMAN_PORT_PERF_CNT_RX_PAUSE; + break; + case (e_FM_PORT_COUNTERS_FRAME): + *p_StatsType = E_FMAN_PORT_STATS_CNT_FRAME; + break; + case (e_FM_PORT_COUNTERS_DISCARD_FRAME): + *p_StatsType = E_FMAN_PORT_STATS_CNT_DISCARD; + break; + case (e_FM_PORT_COUNTERS_DEALLOC_BUF): + *p_StatsType = E_FMAN_PORT_STATS_CNT_DEALLOC_BUF; + break; + case (e_FM_PORT_COUNTERS_RX_BAD_FRAME): + *p_StatsType = E_FMAN_PORT_STATS_CNT_RX_BAD_FRAME; + break; + case (e_FM_PORT_COUNTERS_RX_LARGE_FRAME): + *p_StatsType = E_FMAN_PORT_STATS_CNT_RX_LARGE_FRAME; + break; + case (e_FM_PORT_COUNTERS_RX_OUT_OF_BUFFERS_DISCARD): + *p_StatsType = E_FMAN_PORT_STATS_CNT_RX_OUT_OF_BUF; + break; + case (e_FM_PORT_COUNTERS_RX_FILTER_FRAME): + *p_StatsType = E_FMAN_PORT_STATS_CNT_FILTERED_FRAME; + break; + case (e_FM_PORT_COUNTERS_RX_LIST_DMA_ERR): + *p_StatsType = E_FMAN_PORT_STATS_CNT_DMA_ERR; + break; + case (e_FM_PORT_COUNTERS_WRED_DISCARD): + *p_StatsType = E_FMAN_PORT_STATS_CNT_WRED_DISCARD; + break; + case (e_FM_PORT_COUNTERS_LENGTH_ERR): + *p_StatsType = E_FMAN_PORT_STATS_CNT_LEN_ERR; + break; + case (e_FM_PORT_COUNTERS_UNSUPPRTED_FORMAT): + *p_StatsType = E_FMAN_PORT_STATS_CNT_UNSUPPORTED_FORMAT; + break; + default: + break; + } + + return E_OK; +} + +static t_Error AdditionalPrsParams(t_FmPort *p_FmPort, + t_FmPcdPrsAdditionalHdrParams *p_HdrParams, + uint32_t *p_SoftSeqAttachReg) +{ + uint8_t hdrNum, Ipv4HdrNum; + u_FmPcdHdrPrsOpts *p_prsOpts; + uint32_t tmpReg = *p_SoftSeqAttachReg, tmpPrsOffset; + + if (IS_PRIVATE_HEADER(p_HdrParams->hdr) + || IS_SPECIAL_HEADER(p_HdrParams->hdr)) + RETURN_ERROR( + MAJOR, E_NOT_SUPPORTED, + ("No additional parameters for private or special headers.")); + + if (p_HdrParams->errDisable) + tmpReg |= PRS_HDR_ERROR_DIS; + + /* Set parser options */ + if (p_HdrParams->usePrsOpts) + { + p_prsOpts = &p_HdrParams->prsOpts; + switch (p_HdrParams->hdr) + { + case (HEADER_TYPE_MPLS): + if (p_prsOpts->mplsPrsOptions.labelInterpretationEnable) + tmpReg |= PRS_HDR_MPLS_LBL_INTER_EN; + hdrNum = GetPrsHdrNum(p_prsOpts->mplsPrsOptions.nextParse); + if (hdrNum == ILLEGAL_HDR_NUM) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, NO_MSG); + Ipv4HdrNum = GetPrsHdrNum(HEADER_TYPE_IPv4); + if (hdrNum < Ipv4HdrNum) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, + ("Header must be equal or higher than IPv4")); + tmpReg |= ((uint32_t)hdrNum * PRS_HDR_ENTRY_SIZE) + << PRS_HDR_MPLS_NEXT_HDR_SHIFT; + break; + case (HEADER_TYPE_PPPoE): + if (p_prsOpts->pppoePrsOptions.enableMTUCheck) + tmpReg |= PRS_HDR_PPPOE_MTU_CHECK_EN; + break; + case (HEADER_TYPE_IPv6): + if (p_prsOpts->ipv6PrsOptions.routingHdrEnable) + tmpReg |= PRS_HDR_IPV6_ROUTE_HDR_EN; + break; + case (HEADER_TYPE_TCP): + if (p_prsOpts->tcpPrsOptions.padIgnoreChecksum) + tmpReg |= PRS_HDR_TCP_PAD_REMOVAL; + else + tmpReg &= ~PRS_HDR_TCP_PAD_REMOVAL; + break; + case (HEADER_TYPE_UDP): + if (p_prsOpts->udpPrsOptions.padIgnoreChecksum) + tmpReg |= PRS_HDR_UDP_PAD_REMOVAL; + else + tmpReg &= ~PRS_HDR_UDP_PAD_REMOVAL; + break; + default: + RETURN_ERROR(MAJOR, E_INVALID_STATE, ("Invalid header")); + } + } + + /* set software parsing (address is divided in 2 since parser uses 2 byte access. */ + if (p_HdrParams->swPrsEnable) + { + tmpPrsOffset = FmPcdGetSwPrsOffset(p_FmPort->h_FmPcd, p_HdrParams->hdr, + p_HdrParams->indexPerHdr); + if (tmpPrsOffset == ILLEGAL_BASE) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, NO_MSG); + tmpReg |= (PRS_HDR_SW_PRS_EN | tmpPrsOffset); + } + *p_SoftSeqAttachReg = tmpReg; + + return E_OK; +} + +static uint32_t GetPortSchemeBindParams( + t_Handle h_FmPort, t_FmPcdKgInterModuleBindPortToSchemes *p_SchemeBind) +{ + t_FmPort *p_FmPort = (t_FmPort*)h_FmPort; + uint32_t walking1Mask = 0x80000000, tmp; + uint8_t idx = 0; + + p_SchemeBind->netEnvId = p_FmPort->netEnvId; + p_SchemeBind->hardwarePortId = p_FmPort->hardwarePortId; + p_SchemeBind->useClsPlan = p_FmPort->useClsPlan; + p_SchemeBind->numOfSchemes = 0; + tmp = p_FmPort->schemesPerPortVector; + if (tmp) + { + while (tmp) + { + if (tmp & walking1Mask) + { + p_SchemeBind->schemesIds[p_SchemeBind->numOfSchemes] = idx; + p_SchemeBind->numOfSchemes++; + tmp &= ~walking1Mask; + } + walking1Mask >>= 1; + idx++; + } + } + + return tmp; +} + +static void FmPortCheckNApplyMacsec(t_Handle h_FmPort) +{ + t_FmPort *p_FmPort = (t_FmPort*)h_FmPort; + volatile uint32_t *p_BmiCfgReg = NULL; + uint32_t macsecEn = BMI_PORT_CFG_EN_MACSEC; + uint32_t lcv, walking1Mask = 0x80000000; + uint8_t cnt = 0; + + ASSERT_COND(p_FmPort); + ASSERT_COND(p_FmPort->h_FmPcd); + ASSERT_COND(!p_FmPort->p_FmPortDriverParam); + + if ((p_FmPort->portType != e_FM_PORT_TYPE_RX_10G) + && (p_FmPort->portType != e_FM_PORT_TYPE_RX)) + return; + + p_BmiCfgReg = &p_FmPort->port.bmi_regs->rx.fmbm_rcfg; + /* get LCV for MACSEC */ + if ((lcv = FmPcdGetMacsecLcv(p_FmPort->h_FmPcd, p_FmPort->netEnvId)) + != 0) + { + while (!(lcv & walking1Mask)) + { + cnt++; + walking1Mask >>= 1; + } + + macsecEn |= (uint32_t)cnt << BMI_PORT_CFG_MS_SEL_SHIFT; + WRITE_UINT32(*p_BmiCfgReg, GET_UINT32(*p_BmiCfgReg) | macsecEn); + } +} + +static t_Error SetPcd(t_FmPort *p_FmPort, t_FmPortPcdParams *p_PcdParams) +{ + t_Error err = E_OK; + uint32_t tmpReg; + volatile uint32_t *p_BmiNia = NULL; + volatile uint32_t *p_BmiPrsNia = NULL; + volatile uint32_t *p_BmiPrsStartOffset = NULL; + volatile uint32_t *p_BmiInitPrsResult = NULL; + volatile uint32_t *p_BmiCcBase = NULL; + uint16_t hdrNum, L3HdrNum, greHdrNum; + int i; + bool isEmptyClsPlanGrp; + uint32_t tmpHxs[FM_PCD_PRS_NUM_OF_HDRS]; + uint16_t absoluteProfileId; + uint8_t physicalSchemeId; + uint32_t ccTreePhysOffset; + t_FmPcdKgInterModuleBindPortToSchemes schemeBind; + uint32_t initialSwPrs = 0; + + ASSERT_COND(p_FmPort); + SANITY_CHECK_RETURN_ERROR(!p_FmPort->p_FmPortDriverParam, E_INVALID_STATE); + + if (p_FmPort->imEn) + RETURN_ERROR(MAJOR, E_INVALID_OPERATION, + ("available for non-independant mode ports only")); + + if ((p_FmPort->portType != e_FM_PORT_TYPE_RX_10G) + && (p_FmPort->portType != e_FM_PORT_TYPE_RX) + && (p_FmPort->portType != e_FM_PORT_TYPE_OH_OFFLINE_PARSING)) + RETURN_ERROR(MAJOR, E_INVALID_OPERATION, + ("available for Rx and offline parsing ports only")); + + p_FmPort->netEnvId = FmPcdGetNetEnvId(p_PcdParams->h_NetEnv); + + p_FmPort->pcdEngines = 0; + + /* initialize p_FmPort->pcdEngines field in port's structure */ + switch (p_PcdParams->pcdSupport) + { + case (e_FM_PORT_PCD_SUPPORT_NONE): + RETURN_ERROR( + MAJOR, + E_INVALID_STATE, + ("No PCD configuration required if e_FM_PORT_PCD_SUPPORT_NONE selected")); + case (e_FM_PORT_PCD_SUPPORT_PRS_ONLY): + p_FmPort->pcdEngines |= FM_PCD_PRS; + break; + case (e_FM_PORT_PCD_SUPPORT_PLCR_ONLY): + p_FmPort->pcdEngines |= FM_PCD_PLCR; + break; + case (e_FM_PORT_PCD_SUPPORT_PRS_AND_PLCR): + p_FmPort->pcdEngines |= FM_PCD_PRS; + p_FmPort->pcdEngines |= FM_PCD_PLCR; + break; + case (e_FM_PORT_PCD_SUPPORT_PRS_AND_KG): + p_FmPort->pcdEngines |= FM_PCD_PRS; + p_FmPort->pcdEngines |= FM_PCD_KG; + break; + case (e_FM_PORT_PCD_SUPPORT_PRS_AND_KG_AND_CC): + p_FmPort->pcdEngines |= FM_PCD_PRS; + p_FmPort->pcdEngines |= FM_PCD_CC; + p_FmPort->pcdEngines |= FM_PCD_KG; + break; + case (e_FM_PORT_PCD_SUPPORT_PRS_AND_KG_AND_CC_AND_PLCR): + p_FmPort->pcdEngines |= FM_PCD_PRS; + p_FmPort->pcdEngines |= FM_PCD_KG; + p_FmPort->pcdEngines |= FM_PCD_CC; + p_FmPort->pcdEngines |= FM_PCD_PLCR; + break; + case (e_FM_PORT_PCD_SUPPORT_PRS_AND_CC): + p_FmPort->pcdEngines |= FM_PCD_PRS; + p_FmPort->pcdEngines |= FM_PCD_CC; + break; + case (e_FM_PORT_PCD_SUPPORT_PRS_AND_CC_AND_PLCR): + p_FmPort->pcdEngines |= FM_PCD_PRS; + p_FmPort->pcdEngines |= FM_PCD_CC; + p_FmPort->pcdEngines |= FM_PCD_PLCR; + break; + case (e_FM_PORT_PCD_SUPPORT_PRS_AND_KG_AND_PLCR): + p_FmPort->pcdEngines |= FM_PCD_PRS; + p_FmPort->pcdEngines |= FM_PCD_KG; + p_FmPort->pcdEngines |= FM_PCD_PLCR; + break; + case (e_FM_PORT_PCD_SUPPORT_CC_ONLY): + p_FmPort->pcdEngines |= FM_PCD_CC; + break; +#ifdef FM_CAPWAP_SUPPORT + case (e_FM_PORT_PCD_SUPPORT_CC_AND_KG): + p_FmPort->pcdEngines |= FM_PCD_CC; + p_FmPort->pcdEngines |= FM_PCD_KG; + break; + case (e_FM_PORT_PCD_SUPPORT_CC_AND_KG_AND_PLCR): + p_FmPort->pcdEngines |= FM_PCD_CC; + p_FmPort->pcdEngines |= FM_PCD_KG; + p_FmPort->pcdEngines |= FM_PCD_PLCR; + break; +#endif /* FM_CAPWAP_SUPPORT */ + + default: + RETURN_ERROR(MAJOR, E_INVALID_STATE, ("invalid pcdSupport")); + } + + if ((p_FmPort->pcdEngines & FM_PCD_PRS) + && (p_PcdParams->p_PrsParams->numOfHdrsWithAdditionalParams + > FM_PCD_PRS_NUM_OF_HDRS)) + RETURN_ERROR( + MAJOR, + E_INVALID_VALUE, + ("Port parser numOfHdrsWithAdditionalParams may not exceed %d", FM_PCD_PRS_NUM_OF_HDRS)); + + /* check that parameters exist for each and only each defined engine */ + if ((!!(p_FmPort->pcdEngines & FM_PCD_PRS) != !!p_PcdParams->p_PrsParams) + || (!!(p_FmPort->pcdEngines & FM_PCD_KG) + != !!p_PcdParams->p_KgParams) + || (!!(p_FmPort->pcdEngines & FM_PCD_CC) + != !!p_PcdParams->p_CcParams)) + RETURN_ERROR( + MAJOR, + E_INVALID_STATE, + ("PCD initialization structure is not consistent with pcdSupport")); + + /* get PCD registers pointers */ + switch (p_FmPort->portType) + { + case (e_FM_PORT_TYPE_RX_10G): + case (e_FM_PORT_TYPE_RX): + p_BmiNia = &p_FmPort->port.bmi_regs->rx.fmbm_rfne; + p_BmiPrsNia = &p_FmPort->port.bmi_regs->rx.fmbm_rfpne; + p_BmiPrsStartOffset = &p_FmPort->port.bmi_regs->rx.fmbm_rpso; + p_BmiInitPrsResult = &p_FmPort->port.bmi_regs->rx.fmbm_rprai[0]; + p_BmiCcBase = &p_FmPort->port.bmi_regs->rx.fmbm_rccb; + break; + case (e_FM_PORT_TYPE_OH_OFFLINE_PARSING): + p_BmiNia = &p_FmPort->port.bmi_regs->oh.fmbm_ofne; + p_BmiPrsNia = &p_FmPort->port.bmi_regs->oh.fmbm_ofpne; + p_BmiPrsStartOffset = &p_FmPort->port.bmi_regs->oh.fmbm_opso; + p_BmiInitPrsResult = &p_FmPort->port.bmi_regs->oh.fmbm_oprai[0]; + p_BmiCcBase = &p_FmPort->port.bmi_regs->oh.fmbm_occb; + break; + default: + RETURN_ERROR(MAJOR, E_INVALID_STATE, ("Invalid port type")); + } + + /* set PCD port parameter */ + if (p_FmPort->pcdEngines & FM_PCD_CC) + { + err = FmPcdCcBindTree(p_FmPort->h_FmPcd, p_PcdParams, + p_PcdParams->p_CcParams->h_CcTree, + &ccTreePhysOffset, p_FmPort); + if (err) + RETURN_ERROR(MAJOR, err, NO_MSG); + + WRITE_UINT32(*p_BmiCcBase, ccTreePhysOffset); + p_FmPort->ccTreeId = p_PcdParams->p_CcParams->h_CcTree; + } + + if (p_FmPort->pcdEngines & FM_PCD_KG) + { + if (p_PcdParams->p_KgParams->numOfSchemes == 0) + RETURN_ERROR( + MAJOR, + E_INVALID_VALUE, + ("For ports using Keygen, at least one scheme must be bound. ")); + + err = FmPcdKgSetOrBindToClsPlanGrp(p_FmPort->h_FmPcd, + p_FmPort->hardwarePortId, + p_FmPort->netEnvId, + p_FmPort->optArray, + &p_FmPort->clsPlanGrpId, + &isEmptyClsPlanGrp); + if (err) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, + ("FmPcdKgSetOrBindToClsPlanGrp failed. ")); + + p_FmPort->useClsPlan = !isEmptyClsPlanGrp; + + schemeBind.netEnvId = p_FmPort->netEnvId; + schemeBind.hardwarePortId = p_FmPort->hardwarePortId; + schemeBind.numOfSchemes = p_PcdParams->p_KgParams->numOfSchemes; + schemeBind.useClsPlan = p_FmPort->useClsPlan; + + /* for each scheme */ + for (i = 0; i < p_PcdParams->p_KgParams->numOfSchemes; i++) + { + ASSERT_COND(p_PcdParams->p_KgParams->h_Schemes[i]); + physicalSchemeId = FmPcdKgGetSchemeId( + p_PcdParams->p_KgParams->h_Schemes[i]); + schemeBind.schemesIds[i] = physicalSchemeId; + /* build vector */ + p_FmPort->schemesPerPortVector |= 1 + << (31 - (uint32_t)physicalSchemeId); +#if (DPAA_VERSION >= 11) + /*because of the state that VSPE is defined per port - all PCD path should be according to this requirement + if !VSPE - in port, for relevant scheme VSPE can not be set*/ + if (!p_FmPort->vspe + && FmPcdKgGetVspe((p_PcdParams->p_KgParams->h_Schemes[i]))) + RETURN_ERROR(MAJOR, E_INVALID_STATE, + ("VSPE is not at port level")); +#endif /* (DPAA_VERSION >= 11) */ + } + + err = FmPcdKgBindPortToSchemes(p_FmPort->h_FmPcd, &schemeBind); + if (err) + RETURN_ERROR(MAJOR, err, NO_MSG); + } + + /***************************/ + /* configure NIA after BMI */ + /***************************/ + /* rfne may contain FDCS bits, so first we read them. */ + p_FmPort->savedBmiNia = GET_UINT32(*p_BmiNia) & BMI_RFNE_FDCS_MASK; + + /* If policer is used directly after BMI or PRS */ + if ((p_FmPort->pcdEngines & FM_PCD_PLCR) + && ((p_PcdParams->pcdSupport == e_FM_PORT_PCD_SUPPORT_PLCR_ONLY) + || (p_PcdParams->pcdSupport + == e_FM_PORT_PCD_SUPPORT_PRS_AND_PLCR))) + { + if (!p_PcdParams->p_PlcrParams->h_Profile) + RETURN_ERROR(MAJOR, E_INVALID_STATE, + ("Profile should be initialized")); + + absoluteProfileId = (uint16_t)FmPcdPlcrProfileGetAbsoluteId( + p_PcdParams->p_PlcrParams->h_Profile); + + if (!FmPcdPlcrIsProfileValid(p_FmPort->h_FmPcd, absoluteProfileId)) + RETURN_ERROR(MAJOR, E_INVALID_STATE, + ("Private port profile not valid.")); + + tmpReg = (uint32_t)(absoluteProfileId | NIA_PLCR_ABSOLUTE); + + if (p_FmPort->pcdEngines & FM_PCD_PRS) /* e_FM_PCD_SUPPORT_PRS_AND_PLCR */ + /* update BMI HPNIA */ + WRITE_UINT32(*p_BmiPrsNia, (uint32_t)(NIA_ENG_PLCR | tmpReg)); + else + /* e_FM_PCD_SUPPORT_PLCR_ONLY */ + /* update BMI NIA */ + p_FmPort->savedBmiNia |= (uint32_t)(NIA_ENG_PLCR); + } + + /* if CC is used directly after BMI */ + if ((p_PcdParams->pcdSupport == e_FM_PORT_PCD_SUPPORT_CC_ONLY) +#ifdef FM_CAPWAP_SUPPORT + || (p_PcdParams->pcdSupport == e_FM_PORT_PCD_SUPPORT_CC_AND_KG) + || (p_PcdParams->pcdSupport == e_FM_PORT_PCD_SUPPORT_CC_AND_KG_AND_PLCR) +#endif /* FM_CAPWAP_SUPPORT */ + ) + { + if (p_FmPort->portType != e_FM_PORT_TYPE_OH_OFFLINE_PARSING) + RETURN_ERROR( + MAJOR, + E_INVALID_OPERATION, + ("e_FM_PORT_PCD_SUPPORT_CC_xx available for offline parsing ports only")); + p_FmPort->savedBmiNia |= (uint32_t)(NIA_ENG_FM_CTL | NIA_FM_CTL_AC_CC); + /* check that prs start offset == RIM[FOF] */ + } + + if (p_FmPort->pcdEngines & FM_PCD_PRS) + { + ASSERT_COND(p_PcdParams->p_PrsParams); +#if (DPAA_VERSION >= 11) + if (p_PcdParams->p_PrsParams->firstPrsHdr == HEADER_TYPE_CAPWAP) + hdrNum = OFFLOAD_SW_PATCH_CAPWAP_LABEL; + else + { +#endif /* (DPAA_VERSION >= 11) */ + /* if PRS is used it is always first */ + hdrNum = GetPrsHdrNum(p_PcdParams->p_PrsParams->firstPrsHdr); + if (hdrNum == ILLEGAL_HDR_NUM) + RETURN_ERROR(MAJOR, E_NOT_SUPPORTED, ("Unsupported header.")); +#if (DPAA_VERSION >= 11) + } +#endif /* (DPAA_VERSION >= 11) */ + p_FmPort->savedBmiNia |= (uint32_t)(NIA_ENG_PRS | (uint32_t)(hdrNum)); + /* set after parser NIA */ + tmpReg = 0; + switch (p_PcdParams->pcdSupport) + { + case (e_FM_PORT_PCD_SUPPORT_PRS_ONLY): + WRITE_UINT32(*p_BmiPrsNia, + GET_NIA_BMI_AC_ENQ_FRAME(p_FmPort->h_FmPcd)); + break; + case (e_FM_PORT_PCD_SUPPORT_PRS_AND_KG_AND_CC): + case (e_FM_PORT_PCD_SUPPORT_PRS_AND_KG_AND_CC_AND_PLCR): + tmpReg = NIA_KG_CC_EN; + /* fall through */ + case (e_FM_PORT_PCD_SUPPORT_PRS_AND_KG): + case (e_FM_PORT_PCD_SUPPORT_PRS_AND_KG_AND_PLCR): + if (p_PcdParams->p_KgParams->directScheme) + { + physicalSchemeId = FmPcdKgGetSchemeId( + p_PcdParams->p_KgParams->h_DirectScheme); + /* check that this scheme was bound to this port */ + for (i = 0; i < p_PcdParams->p_KgParams->numOfSchemes; i++) + if (p_PcdParams->p_KgParams->h_DirectScheme + == p_PcdParams->p_KgParams->h_Schemes[i]) + break; + if (i == p_PcdParams->p_KgParams->numOfSchemes) + RETURN_ERROR( + MAJOR, + E_INVALID_VALUE, + ("Direct scheme is not one of the port selected schemes.")); + tmpReg |= (uint32_t)(NIA_KG_DIRECT | physicalSchemeId); + } + WRITE_UINT32(*p_BmiPrsNia, NIA_ENG_KG | tmpReg); + break; + case (e_FM_PORT_PCD_SUPPORT_PRS_AND_CC): + case (e_FM_PORT_PCD_SUPPORT_PRS_AND_CC_AND_PLCR): + WRITE_UINT32(*p_BmiPrsNia, + (uint32_t)(NIA_ENG_FM_CTL | NIA_FM_CTL_AC_CC)); + break; + case (e_FM_PORT_PCD_SUPPORT_PRS_AND_PLCR): + break; + default: + RETURN_ERROR(MAJOR, E_INVALID_STATE, ("Invalid PCD support")); + } + + /* set start parsing offset */ + WRITE_UINT32(*p_BmiPrsStartOffset, + p_PcdParams->p_PrsParams->parsingOffset); + + /************************************/ + /* Parser port parameters */ + /************************************/ + /* stop before configuring */ + WRITE_UINT32(p_FmPort->p_FmPortPrsRegs->pcac, PRS_CAC_STOP); + /* wait for parser to be in idle state */ + while (GET_UINT32(p_FmPort->p_FmPortPrsRegs->pcac) & PRS_CAC_ACTIVE) + ; + + /* set soft seq attachment register */ + memset(tmpHxs, 0, FM_PCD_PRS_NUM_OF_HDRS * sizeof(uint32_t)); + + /* set protocol options */ + for (i = 0; p_FmPort->optArray[i]; i++) + switch (p_FmPort->optArray[i]) + { + case (ETH_BROADCAST): + hdrNum = GetPrsHdrNum(HEADER_TYPE_ETH); + tmpHxs[hdrNum] |= (i + 1) << PRS_HDR_ETH_BC_SHIFT; + break; + case (ETH_MULTICAST): + hdrNum = GetPrsHdrNum(HEADER_TYPE_ETH); + tmpHxs[hdrNum] |= (i + 1) << PRS_HDR_ETH_MC_SHIFT; + break; + case (VLAN_STACKED): + hdrNum = GetPrsHdrNum(HEADER_TYPE_VLAN); + tmpHxs[hdrNum] |= (i + 1) << PRS_HDR_VLAN_STACKED_SHIFT; + break; + case (MPLS_STACKED): + hdrNum = GetPrsHdrNum(HEADER_TYPE_MPLS); + tmpHxs[hdrNum] |= (i + 1) << PRS_HDR_MPLS_STACKED_SHIFT; + break; + case (IPV4_BROADCAST_1): + hdrNum = GetPrsHdrNum(HEADER_TYPE_IPv4); + tmpHxs[hdrNum] |= (i + 1) << PRS_HDR_IPV4_1_BC_SHIFT; + break; + case (IPV4_MULTICAST_1): + hdrNum = GetPrsHdrNum(HEADER_TYPE_IPv4); + tmpHxs[hdrNum] |= (i + 1) << PRS_HDR_IPV4_1_MC_SHIFT; + break; + case (IPV4_UNICAST_2): + hdrNum = GetPrsHdrNum(HEADER_TYPE_IPv4); + tmpHxs[hdrNum] |= (i + 1) << PRS_HDR_IPV4_2_UC_SHIFT; + break; + case (IPV4_MULTICAST_BROADCAST_2): + hdrNum = GetPrsHdrNum(HEADER_TYPE_IPv4); + tmpHxs[hdrNum] |= (i + 1) << PRS_HDR_IPV4_2_MC_BC_SHIFT; + break; + case (IPV6_MULTICAST_1): + hdrNum = GetPrsHdrNum(HEADER_TYPE_IPv6); + tmpHxs[hdrNum] |= (i + 1) << PRS_HDR_IPV6_1_MC_SHIFT; + break; + case (IPV6_UNICAST_2): + hdrNum = GetPrsHdrNum(HEADER_TYPE_IPv6); + tmpHxs[hdrNum] |= (i + 1) << PRS_HDR_IPV6_2_UC_SHIFT; + break; + case (IPV6_MULTICAST_2): + hdrNum = GetPrsHdrNum(HEADER_TYPE_IPv6); + tmpHxs[hdrNum] |= (i + 1) << PRS_HDR_IPV6_2_MC_SHIFT; + break; + } + + if (FmPcdNetEnvIsHdrExist(p_FmPort->h_FmPcd, p_FmPort->netEnvId, + HEADER_TYPE_UDP_ENCAP_ESP)) + { + if (p_PcdParams->p_PrsParams->numOfHdrsWithAdditionalParams == FM_PCD_PRS_NUM_OF_HDRS) + RETURN_ERROR( + MINOR, E_INVALID_VALUE, + ("If HEADER_TYPE_UDP_ENCAP_ESP is used, numOfHdrsWithAdditionalParams may be up to FM_PCD_PRS_NUM_OF_HDRS - 1")); + + p_PcdParams->p_PrsParams->additionalParams[p_PcdParams->p_PrsParams->numOfHdrsWithAdditionalParams].hdr = + HEADER_TYPE_UDP; + p_PcdParams->p_PrsParams->additionalParams[p_PcdParams->p_PrsParams->numOfHdrsWithAdditionalParams].swPrsEnable = + TRUE; + p_PcdParams->p_PrsParams->numOfHdrsWithAdditionalParams++; + } + + /* set MPLS default next header - HW reset workaround */ + hdrNum = GetPrsHdrNum(HEADER_TYPE_MPLS); + tmpHxs[hdrNum] |= PRS_HDR_MPLS_LBL_INTER_EN; + L3HdrNum = GetPrsHdrNum(HEADER_TYPE_USER_DEFINED_L3); + tmpHxs[hdrNum] |= (uint32_t)L3HdrNum << PRS_HDR_MPLS_NEXT_HDR_SHIFT; + + /* for GRE, disable errors */ + greHdrNum = GetPrsHdrNum(HEADER_TYPE_GRE); + tmpHxs[greHdrNum] |= PRS_HDR_ERROR_DIS; + + /* For UDP remove PAD from L4 checksum calculation */ + hdrNum = GetPrsHdrNum(HEADER_TYPE_UDP); + tmpHxs[hdrNum] |= PRS_HDR_UDP_PAD_REMOVAL; + /* For TCP remove PAD from L4 checksum calculation */ + hdrNum = GetPrsHdrNum(HEADER_TYPE_TCP); + tmpHxs[hdrNum] |= PRS_HDR_TCP_PAD_REMOVAL; + + /* config additional params for specific headers */ + for (i = 0; i < p_PcdParams->p_PrsParams->numOfHdrsWithAdditionalParams; + i++) + { + /* case for using sw parser as the initial NIA address, before + * HW parsing + */ + if ((p_PcdParams->p_PrsParams->additionalParams[i].hdr == HEADER_TYPE_NONE) && + p_PcdParams->p_PrsParams->additionalParams[i].swPrsEnable) + { + initialSwPrs = FmPcdGetSwPrsOffset(p_FmPort->h_FmPcd, HEADER_TYPE_NONE, + p_PcdParams->p_PrsParams->additionalParams[i].indexPerHdr); + if (initialSwPrs == ILLEGAL_BASE) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, NO_MSG); + + /* clear parser first HXS */ + p_FmPort->savedBmiNia &= ~BMI_RFNE_HXS_MASK; /* 0x000000FF */ + /* rewrite with soft parser start */ + p_FmPort->savedBmiNia |= initialSwPrs; + continue; + } + + hdrNum = + GetPrsHdrNum(p_PcdParams->p_PrsParams->additionalParams[i].hdr); + if (hdrNum == ILLEGAL_HDR_NUM) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, NO_MSG); + if (hdrNum == NO_HDR_NUM) + RETURN_ERROR( + MAJOR, E_INVALID_VALUE, + ("Private headers may not use additional parameters")); + + err = AdditionalPrsParams( + p_FmPort, &p_PcdParams->p_PrsParams->additionalParams[i], + &tmpHxs[hdrNum]); + if (err) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, NO_MSG); + } + + /* Check if ip-reassembly port - need to link sw-parser code */ + if (p_FmPort->h_IpReassemblyManip) + { + /* link to sw parser code for IP Frag - only if no other code is applied. */ + hdrNum = GetPrsHdrNum(HEADER_TYPE_IPv4); + if (!(tmpHxs[hdrNum] & PRS_HDR_SW_PRS_EN)) + tmpHxs[hdrNum] |= (PRS_HDR_SW_PRS_EN | OFFLOAD_SW_PATCH_IPv4_IPR_LABEL); + hdrNum = GetPrsHdrNum(HEADER_TYPE_IPv6); + if (!(tmpHxs[hdrNum] & PRS_HDR_SW_PRS_EN)) + tmpHxs[hdrNum] |= (PRS_HDR_SW_PRS_EN | OFFLOAD_SW_PATCH_IPv6_IPR_LABEL); + } else { + if (FmPcdNetEnvIsHdrExist(p_FmPort->h_FmPcd, p_FmPort->netEnvId, HEADER_TYPE_UDP_LITE)) + { + hdrNum = GetPrsHdrNum(HEADER_TYPE_IPv6); + if (!(tmpHxs[hdrNum] & PRS_HDR_SW_PRS_EN)) + tmpHxs[hdrNum] |= (PRS_HDR_SW_PRS_EN | OFFLOAD_SW_PATCH_IPv6_IPF_LABEL); + } else if ((FmPcdIsAdvancedOffloadSupported(p_FmPort->h_FmPcd) + && (p_FmPort->portType == e_FM_PORT_TYPE_OH_OFFLINE_PARSING))) + { + hdrNum = GetPrsHdrNum(HEADER_TYPE_IPv6); + if (!(tmpHxs[hdrNum] & PRS_HDR_SW_PRS_EN)) + tmpHxs[hdrNum] |= (PRS_HDR_SW_PRS_EN | OFFLOAD_SW_PATCH_IPv6_IPF_LABEL); + } + } + +#if ((DPAA_VERSION == 10) && defined(FM_CAPWAP_SUPPORT)) + if (FmPcdNetEnvIsHdrExist(p_FmPort->h_FmPcd, p_FmPort->netEnvId, + HEADER_TYPE_UDP_LITE)) + { + /* link to sw parser code for udp lite - only if no other code is applied. */ + hdrNum = GetPrsHdrNum(HEADER_TYPE_IPv6); + if (!(tmpHxs[hdrNum] & PRS_HDR_SW_PRS_EN)) + tmpHxs[hdrNum] |= (PRS_HDR_SW_PRS_EN | UDP_LITE_SW_PATCH_LABEL); + } +#endif /* ((DPAA_VERSION == 10) && defined(FM_CAPWAP_SUPPORT)) */ + for (i = 0; i < FM_PCD_PRS_NUM_OF_HDRS; i++) + { + /* For all header set LCV as taken from netEnv*/ + WRITE_UINT32( + p_FmPort->p_FmPortPrsRegs->hdrs[i].lcv, + FmPcdGetLcv(p_FmPort->h_FmPcd, p_FmPort->netEnvId, (uint8_t)i)); + /* set HXS register according to default+Additional params+protocol options */ + WRITE_UINT32(p_FmPort->p_FmPortPrsRegs->hdrs[i].softSeqAttach, + tmpHxs[i]); + } + + /* set tpid. */ + tmpReg = PRS_TPID_DFLT; + if (p_PcdParams->p_PrsParams->setVlanTpid1) + { + tmpReg &= PRS_TPID2_MASK; + tmpReg |= (uint32_t)p_PcdParams->p_PrsParams->vlanTpid1 + << PRS_PCTPID_SHIFT; + } + if (p_PcdParams->p_PrsParams->setVlanTpid2) + { + tmpReg &= PRS_TPID1_MASK; + tmpReg |= (uint32_t)p_PcdParams->p_PrsParams->vlanTpid2; + }WRITE_UINT32(p_FmPort->p_FmPortPrsRegs->pctpid, tmpReg); + + /* enable parser */ + WRITE_UINT32(p_FmPort->p_FmPortPrsRegs->pcac, 0); + + if (p_PcdParams->p_PrsParams->prsResultPrivateInfo) + p_FmPort->privateInfo = + p_PcdParams->p_PrsParams->prsResultPrivateInfo; + + } /* end parser */ + else { + if (FmPcdIsAdvancedOffloadSupported(p_FmPort->h_FmPcd) + && (p_FmPort->portType == e_FM_PORT_TYPE_OH_OFFLINE_PARSING)) + { + hdrNum = GetPrsHdrNum(HEADER_TYPE_IPv6); + WRITE_UINT32(p_FmPort->p_FmPortPrsRegs->hdrs[hdrNum].softSeqAttach, + (PRS_HDR_SW_PRS_EN | OFFLOAD_SW_PATCH_IPv6_IPF_LABEL)); + } + + WRITE_UINT32(*p_BmiPrsStartOffset, 0); + + p_FmPort->privateInfo = 0; + } + + FmPortCheckNApplyMacsec(p_FmPort); + + WRITE_UINT32( + *p_BmiPrsStartOffset, + GET_UINT32(*p_BmiPrsStartOffset) + p_FmPort->internalBufferOffset); + + /* set initial parser result - used for all engines */ + for (i = 0; i < FM_PORT_PRS_RESULT_NUM_OF_WORDS; i++) + { + if (!i) + WRITE_UINT32( + *(p_BmiInitPrsResult), + (uint32_t)(((uint32_t)p_FmPort->privateInfo << BMI_PR_PORTID_SHIFT) | BMI_PRS_RESULT_HIGH)); + else + { + if (i < FM_PORT_PRS_RESULT_NUM_OF_WORDS / 2) + WRITE_UINT32(*(p_BmiInitPrsResult+i), BMI_PRS_RESULT_HIGH); + else + WRITE_UINT32(*(p_BmiInitPrsResult+i), BMI_PRS_RESULT_LOW); + } + } + + return E_OK; +} + +static t_Error DeletePcd(t_FmPort *p_FmPort) +{ + t_Error err = E_OK; + volatile uint32_t *p_BmiNia = NULL; + volatile uint32_t *p_BmiPrsStartOffset = NULL; + + ASSERT_COND(p_FmPort); + SANITY_CHECK_RETURN_ERROR(!p_FmPort->p_FmPortDriverParam, E_INVALID_STATE); + + if (p_FmPort->imEn) + RETURN_ERROR(MAJOR, E_INVALID_OPERATION, + ("available for non-independant mode ports only")); + + if ((p_FmPort->portType != e_FM_PORT_TYPE_RX_10G) + && (p_FmPort->portType != e_FM_PORT_TYPE_RX) + && (p_FmPort->portType != e_FM_PORT_TYPE_OH_OFFLINE_PARSING)) + RETURN_ERROR( MAJOR, E_INVALID_OPERATION, + ("available for Rx and offline parsing ports only")); + + if (!p_FmPort->pcdEngines) + RETURN_ERROR(MAJOR, E_INVALID_OPERATION, ("called for non PCD port")); + + /* get PCD registers pointers */ + switch (p_FmPort->portType) + { + case (e_FM_PORT_TYPE_RX_10G): + case (e_FM_PORT_TYPE_RX): + p_BmiNia = &p_FmPort->port.bmi_regs->rx.fmbm_rfne; + p_BmiPrsStartOffset = &p_FmPort->port.bmi_regs->rx.fmbm_rpso; + break; + case (e_FM_PORT_TYPE_OH_OFFLINE_PARSING): + p_BmiNia = &p_FmPort->port.bmi_regs->oh.fmbm_ofne; + p_BmiPrsStartOffset = &p_FmPort->port.bmi_regs->oh.fmbm_opso; + break; + default: + RETURN_ERROR(MAJOR, E_INVALID_STATE, ("Invalid port type")); + } + + if ((GET_UINT32(*p_BmiNia) & GET_NO_PCD_NIA_BMI_AC_ENQ_FRAME()) + != GET_NO_PCD_NIA_BMI_AC_ENQ_FRAME()) + RETURN_ERROR(MAJOR, E_INVALID_OPERATION, + ("port has to be detached previousely")); + + WRITE_UINT32(*p_BmiPrsStartOffset, 0); + + /* "cut" PCD out of the port's flow - go to BMI */ + /* WRITE_UINT32(*p_BmiNia, (p_FmPort->savedBmiNia & BMI_RFNE_FDCS_MASK) | (NIA_ENG_BMI | NIA_BMI_AC_ENQ_FRAME)); */ + + if (p_FmPort->pcdEngines & FM_PCD_PRS) + { + /* stop parser */ + WRITE_UINT32(p_FmPort->p_FmPortPrsRegs->pcac, PRS_CAC_STOP); + /* wait for parser to be in idle state */ + while (GET_UINT32(p_FmPort->p_FmPortPrsRegs->pcac) & PRS_CAC_ACTIVE) + ; + } + + if (p_FmPort->pcdEngines & FM_PCD_KG) + { + t_FmPcdKgInterModuleBindPortToSchemes schemeBind; + + /* unbind all schemes */ + p_FmPort->schemesPerPortVector = GetPortSchemeBindParams(p_FmPort, + &schemeBind); + + err = FmPcdKgUnbindPortToSchemes(p_FmPort->h_FmPcd, &schemeBind); + if (err) + RETURN_ERROR(MAJOR, err, NO_MSG); + + err = FmPcdKgDeleteOrUnbindPortToClsPlanGrp(p_FmPort->h_FmPcd, + p_FmPort->hardwarePortId, + p_FmPort->clsPlanGrpId); + if (err) + RETURN_ERROR(MAJOR, err, NO_MSG); + p_FmPort->useClsPlan = FALSE; + } + + if (p_FmPort->pcdEngines & FM_PCD_CC) + { + /* unbind - we need to get the treeId too */ + err = FmPcdCcUnbindTree(p_FmPort->h_FmPcd, p_FmPort->ccTreeId); + if (err) + RETURN_ERROR(MAJOR, err, NO_MSG); + } + + p_FmPort->pcdEngines = 0; + + return E_OK; +} + +static t_Error AttachPCD(t_FmPort *p_FmPort) +{ + volatile uint32_t *p_BmiNia = NULL; + + ASSERT_COND(p_FmPort); + + /* get PCD registers pointers */ + if (p_FmPort->portType == e_FM_PORT_TYPE_OH_OFFLINE_PARSING) + p_BmiNia = &p_FmPort->port.bmi_regs->oh.fmbm_ofne; + else + p_BmiNia = &p_FmPort->port.bmi_regs->rx.fmbm_rfne; + + /* check that current NIA is BMI to BMI */ + if ((GET_UINT32(*p_BmiNia) & ~BMI_RFNE_FDCS_MASK) + != GET_NO_PCD_NIA_BMI_AC_ENQ_FRAME()) + RETURN_ERROR( MAJOR, E_INVALID_OPERATION, + ("may be called only for ports in BMI-to-BMI state.")); + + if (p_FmPort->requiredAction & UPDATE_FMFP_PRC_WITH_ONE_RISC_ONLY) + if (FmSetNumOfRiscsPerPort(p_FmPort->h_Fm, p_FmPort->hardwarePortId, 1, + p_FmPort->orFmanCtrl) != E_OK) + RETURN_ERROR(MAJOR, E_INVALID_STATE, NO_MSG); + + if (p_FmPort->requiredAction & UPDATE_NIA_CMNE) + { + if (p_FmPort->portType == e_FM_PORT_TYPE_OH_OFFLINE_PARSING) + WRITE_UINT32(p_FmPort->port.bmi_regs->oh.fmbm_ocmne, + p_FmPort->savedBmiCmne); + else + WRITE_UINT32(p_FmPort->port.bmi_regs->rx.fmbm_rcmne, + p_FmPort->savedBmiCmne); + } + + if (p_FmPort->requiredAction & UPDATE_NIA_PNEN) + WRITE_UINT32(p_FmPort->p_FmPortQmiRegs->fmqm_pnen, + p_FmPort->savedQmiPnen); + + if (p_FmPort->requiredAction & UPDATE_NIA_FENE) + { + if (p_FmPort->portType == e_FM_PORT_TYPE_OH_OFFLINE_PARSING) + WRITE_UINT32(p_FmPort->port.bmi_regs->oh.fmbm_ofene, + p_FmPort->savedBmiFene); + else + WRITE_UINT32(p_FmPort->port.bmi_regs->rx.fmbm_rfene, + p_FmPort->savedBmiFene); + } + + if (p_FmPort->requiredAction & UPDATE_NIA_FPNE) + { + if (p_FmPort->portType == e_FM_PORT_TYPE_OH_OFFLINE_PARSING) + WRITE_UINT32(p_FmPort->port.bmi_regs->oh.fmbm_ofpne, + p_FmPort->savedBmiFpne); + else + WRITE_UINT32(p_FmPort->port.bmi_regs->rx.fmbm_rfpne, + p_FmPort->savedBmiFpne); + } + + if (p_FmPort->requiredAction & UPDATE_OFP_DPTE) + { + ASSERT_COND(p_FmPort->portType == e_FM_PORT_TYPE_OH_OFFLINE_PARSING); + + WRITE_UINT32(p_FmPort->port.bmi_regs->oh.fmbm_ofp, + p_FmPort->savedBmiOfp); + } + + WRITE_UINT32(*p_BmiNia, p_FmPort->savedBmiNia); + + if (p_FmPort->requiredAction & UPDATE_NIA_PNDN) + { + p_FmPort->origNonRxQmiRegsPndn = + GET_UINT32(p_FmPort->port.qmi_regs->fmqm_pndn); + WRITE_UINT32(p_FmPort->port.qmi_regs->fmqm_pndn, + p_FmPort->savedNonRxQmiRegsPndn); + } + + return E_OK; +} + +static t_Error DetachPCD(t_FmPort *p_FmPort) +{ + volatile uint32_t *p_BmiNia = NULL; + + ASSERT_COND(p_FmPort); + + /* get PCD registers pointers */ + if (p_FmPort->requiredAction & UPDATE_NIA_PNDN) + WRITE_UINT32(p_FmPort->port.qmi_regs->fmqm_pndn, + p_FmPort->origNonRxQmiRegsPndn); + + if (p_FmPort->portType == e_FM_PORT_TYPE_OH_OFFLINE_PARSING) + p_BmiNia = &p_FmPort->port.bmi_regs->oh.fmbm_ofne; + else + p_BmiNia = &p_FmPort->port.bmi_regs->rx.fmbm_rfne; + + WRITE_UINT32( + *p_BmiNia, + (p_FmPort->savedBmiNia & BMI_RFNE_FDCS_MASK) | GET_NO_PCD_NIA_BMI_AC_ENQ_FRAME()); + + if (FmPcdGetHcHandle(p_FmPort->h_FmPcd)) + FmPcdHcSync(p_FmPort->h_FmPcd); + + if (p_FmPort->requiredAction & UPDATE_NIA_FENE) + { + if (p_FmPort->portType == e_FM_PORT_TYPE_OH_OFFLINE_PARSING) + WRITE_UINT32(p_FmPort->port.bmi_regs->oh.fmbm_ofene, + NIA_ENG_QMI_ENQ | NIA_ORDER_RESTOR); + else + WRITE_UINT32(p_FmPort->port.bmi_regs->rx.fmbm_rfene, + NIA_ENG_QMI_ENQ | NIA_ORDER_RESTOR); + } + + if (p_FmPort->requiredAction & UPDATE_NIA_PNEN) + WRITE_UINT32(p_FmPort->port.qmi_regs->fmqm_pnen, + NIA_ENG_BMI | NIA_BMI_AC_RELEASE); + + if (p_FmPort->requiredAction & UPDATE_FMFP_PRC_WITH_ONE_RISC_ONLY) + if (FmSetNumOfRiscsPerPort(p_FmPort->h_Fm, p_FmPort->hardwarePortId, 2, + p_FmPort->orFmanCtrl) != E_OK) + RETURN_ERROR(MAJOR, E_INVALID_STATE, NO_MSG); + + p_FmPort->requiredAction = 0; + + return E_OK; +} + +/*****************************************************************************/ +/* Inter-module API routines */ +/*****************************************************************************/ +void FmPortSetMacsecCmd(t_Handle h_FmPort, uint8_t dfltSci) +{ + t_FmPort *p_FmPort = (t_FmPort*)h_FmPort; + volatile uint32_t *p_BmiCfgReg = NULL; + uint32_t tmpReg; + + SANITY_CHECK_RETURN(p_FmPort, E_INVALID_HANDLE); + SANITY_CHECK_RETURN(p_FmPort->p_FmPortDriverParam, E_INVALID_STATE); + + if ((p_FmPort->portType != e_FM_PORT_TYPE_TX_10G) + && (p_FmPort->portType != e_FM_PORT_TYPE_TX)) + { + REPORT_ERROR(MAJOR, E_INVALID_OPERATION, ("The routine is relevant for Tx ports only")); + return; + } + + p_BmiCfgReg = &p_FmPort->port.bmi_regs->tx.fmbm_tfca; + tmpReg = GET_UINT32(*p_BmiCfgReg) & ~BMI_CMD_ATTR_MACCMD_MASK; + tmpReg |= BMI_CMD_ATTR_MACCMD_SECURED; + tmpReg |= (((uint32_t)dfltSci << BMI_CMD_ATTR_MACCMD_SC_SHIFT) + & BMI_CMD_ATTR_MACCMD_SC_MASK); + + WRITE_UINT32(*p_BmiCfgReg, tmpReg); +} + +uint8_t FmPortGetNetEnvId(t_Handle h_FmPort) +{ + return ((t_FmPort*)h_FmPort)->netEnvId; +} + +uint8_t FmPortGetHardwarePortId(t_Handle h_FmPort) +{ + return ((t_FmPort*)h_FmPort)->hardwarePortId; +} + +uint32_t FmPortGetPcdEngines(t_Handle h_FmPort) +{ + return ((t_FmPort*)h_FmPort)->pcdEngines; +} + +#if (DPAA_VERSION >= 11) +t_Error FmPortSetGprFunc(t_Handle h_FmPort, e_FmPortGprFuncType gprFunc, + void **p_Value) +{ + t_FmPort *p_FmPort = (t_FmPort*)h_FmPort; + uint32_t muramPageOffset; + + ASSERT_COND(p_FmPort); + ASSERT_COND(p_Value); + + if (p_FmPort->gprFunc != e_FM_PORT_GPR_EMPTY) + { + if (p_FmPort->gprFunc != gprFunc) + RETURN_ERROR(MAJOR, E_INVALID_STATE, + ("gpr was assigned with different func")); + } + else + { + switch (gprFunc) + { + case (e_FM_PORT_GPR_MURAM_PAGE): + p_FmPort->p_ParamsPage = FM_MURAM_AllocMem(p_FmPort->h_FmMuram, + 256, 8); + if (!p_FmPort->p_ParamsPage) + RETURN_ERROR(MAJOR, E_NO_MEMORY, ("MURAM alloc for page")); + + IOMemSet32(p_FmPort->p_ParamsPage, 0, 256); + muramPageOffset = + (uint32_t)(XX_VirtToPhys(p_FmPort->p_ParamsPage) + - p_FmPort->fmMuramPhysBaseAddr); + switch (p_FmPort->portType) + { + case (e_FM_PORT_TYPE_RX_10G): + case (e_FM_PORT_TYPE_RX): + WRITE_UINT32( + p_FmPort->p_FmPortBmiRegs->rxPortBmiRegs.fmbm_rgpr, + muramPageOffset); + break; + case (e_FM_PORT_TYPE_OH_OFFLINE_PARSING): + WRITE_UINT32( + p_FmPort->p_FmPortBmiRegs->ohPortBmiRegs.fmbm_ogpr, + muramPageOffset); + break; + default: + RETURN_ERROR(MAJOR, E_INVALID_STATE, + ("Invalid port type")); + } + break; + default: + RETURN_ERROR(MAJOR, E_INVALID_SELECTION, NO_MSG); + } + p_FmPort->gprFunc = gprFunc; + } + + switch (p_FmPort->gprFunc) + { + case (e_FM_PORT_GPR_MURAM_PAGE): + *p_Value = p_FmPort->p_ParamsPage; + break; + default: + RETURN_ERROR(MAJOR, E_INVALID_SELECTION, NO_MSG); + } + + return E_OK; +} +#endif /* (DPAA_VERSION >= 11) */ + +t_Error FmPortGetSetCcParams(t_Handle h_FmPort, + t_FmPortGetSetCcParams *p_CcParams) +{ + t_FmPort *p_FmPort = (t_FmPort*)h_FmPort; + int tmpInt; + volatile uint32_t *p_BmiPrsStartOffset = NULL; + + /* this function called from Cc for pass and receive parameters port params between CC and PORT*/ + + if ((p_CcParams->getCcParams.type & OFFSET_OF_PR) + && (p_FmPort->bufferOffsets.prsResultOffset != ILLEGAL_BASE)) + { + p_CcParams->getCcParams.prOffset = + (uint8_t)p_FmPort->bufferOffsets.prsResultOffset; + p_CcParams->getCcParams.type &= ~OFFSET_OF_PR; + } + if (p_CcParams->getCcParams.type & HW_PORT_ID) + { + p_CcParams->getCcParams.hardwarePortId = + (uint8_t)p_FmPort->hardwarePortId; + p_CcParams->getCcParams.type &= ~HW_PORT_ID; + } + if ((p_CcParams->getCcParams.type & OFFSET_OF_DATA) + && (p_FmPort->bufferOffsets.dataOffset != ILLEGAL_BASE)) + { + p_CcParams->getCcParams.dataOffset = + (uint16_t)p_FmPort->bufferOffsets.dataOffset; + p_CcParams->getCcParams.type &= ~OFFSET_OF_DATA; + } + if (p_CcParams->getCcParams.type & NUM_OF_TASKS) + { + p_CcParams->getCcParams.numOfTasks = (uint8_t)p_FmPort->tasks.num; + p_CcParams->getCcParams.type &= ~NUM_OF_TASKS; + } + if (p_CcParams->getCcParams.type & NUM_OF_EXTRA_TASKS) + { + p_CcParams->getCcParams.numOfExtraTasks = + (uint8_t)p_FmPort->tasks.extra; + p_CcParams->getCcParams.type &= ~NUM_OF_EXTRA_TASKS; + } + if (p_CcParams->getCcParams.type & FM_REV) + { + p_CcParams->getCcParams.revInfo.majorRev = p_FmPort->fmRevInfo.majorRev; + p_CcParams->getCcParams.revInfo.minorRev = p_FmPort->fmRevInfo.minorRev; + p_CcParams->getCcParams.type &= ~FM_REV; + } + if (p_CcParams->getCcParams.type & DISCARD_MASK) + { + if (p_FmPort->portType == e_FM_PORT_TYPE_OH_OFFLINE_PARSING) + p_CcParams->getCcParams.discardMask = + GET_UINT32(p_FmPort->p_FmPortBmiRegs->ohPortBmiRegs.fmbm_ofsdm); + else + p_CcParams->getCcParams.discardMask = + GET_UINT32(p_FmPort->p_FmPortBmiRegs->rxPortBmiRegs.fmbm_rfsdm); + p_CcParams->getCcParams.type &= ~DISCARD_MASK; + } + if (p_CcParams->getCcParams.type & MANIP_EXTRA_SPACE) + { + p_CcParams->getCcParams.internalBufferOffset = + p_FmPort->internalBufferOffset; + p_CcParams->getCcParams.type &= ~MANIP_EXTRA_SPACE; + } + if (p_CcParams->getCcParams.type & GET_NIA_FPNE) + { + if (p_FmPort->portType == e_FM_PORT_TYPE_OH_OFFLINE_PARSING) + p_CcParams->getCcParams.nia = + GET_UINT32(p_FmPort->port.bmi_regs->oh.fmbm_ofpne); + else + p_CcParams->getCcParams.nia = + GET_UINT32(p_FmPort->port.bmi_regs->rx.fmbm_rfpne); + p_CcParams->getCcParams.type &= ~GET_NIA_FPNE; + } + if (p_CcParams->getCcParams.type & GET_NIA_PNDN) + { + if (p_FmPort->portType != e_FM_PORT_TYPE_OH_OFFLINE_PARSING) + RETURN_ERROR(MAJOR, E_INVALID_STATE, ("Invalid port type")); + p_CcParams->getCcParams.nia = + GET_UINT32(p_FmPort->p_FmPortQmiRegs->nonRxQmiRegs.fmqm_pndn); + p_CcParams->getCcParams.type &= ~GET_NIA_PNDN; + } + + if ((p_CcParams->setCcParams.type & UPDATE_FMFP_PRC_WITH_ONE_RISC_ONLY) + && !(p_FmPort->requiredAction & UPDATE_FMFP_PRC_WITH_ONE_RISC_ONLY)) + { + p_FmPort->requiredAction |= UPDATE_FMFP_PRC_WITH_ONE_RISC_ONLY; + p_FmPort->orFmanCtrl = p_CcParams->setCcParams.orFmanCtrl; + } + + if ((p_CcParams->setCcParams.type & UPDATE_NIA_PNEN) + && !(p_FmPort->requiredAction & UPDATE_NIA_PNEN)) + { + p_FmPort->savedQmiPnen = p_CcParams->setCcParams.nia; + p_FmPort->requiredAction |= UPDATE_NIA_PNEN; + } + else + if (p_CcParams->setCcParams.type & UPDATE_NIA_PNEN) + { + if (p_FmPort->savedQmiPnen != p_CcParams->setCcParams.nia) + RETURN_ERROR(MAJOR, E_INVALID_STATE, + ("PNEN was defined previously different")); + } + + if ((p_CcParams->setCcParams.type & UPDATE_NIA_PNDN) + && !(p_FmPort->requiredAction & UPDATE_NIA_PNDN)) + { + p_FmPort->savedNonRxQmiRegsPndn = p_CcParams->setCcParams.nia; + p_FmPort->requiredAction |= UPDATE_NIA_PNDN; + } + else + if (p_CcParams->setCcParams.type & UPDATE_NIA_PNDN) + { + if (p_FmPort->savedNonRxQmiRegsPndn != p_CcParams->setCcParams.nia) + RETURN_ERROR(MAJOR, E_INVALID_STATE, + ("PNDN was defined previously different")); + } + + if ((p_CcParams->setCcParams.type & UPDATE_NIA_FENE) + && (p_CcParams->setCcParams.overwrite + || !(p_FmPort->requiredAction & UPDATE_NIA_FENE))) + { + p_FmPort->savedBmiFene = p_CcParams->setCcParams.nia; + p_FmPort->requiredAction |= UPDATE_NIA_FENE; + } + else + if (p_CcParams->setCcParams.type & UPDATE_NIA_FENE) + { + if (p_FmPort->savedBmiFene != p_CcParams->setCcParams.nia) + RETURN_ERROR( MAJOR, E_INVALID_STATE, + ("xFENE was defined previously different")); + } + + if ((p_CcParams->setCcParams.type & UPDATE_NIA_FPNE) + && !(p_FmPort->requiredAction & UPDATE_NIA_FPNE)) + { + p_FmPort->savedBmiFpne = p_CcParams->setCcParams.nia; + p_FmPort->requiredAction |= UPDATE_NIA_FPNE; + } + else + if (p_CcParams->setCcParams.type & UPDATE_NIA_FPNE) + { + if (p_FmPort->savedBmiFpne != p_CcParams->setCcParams.nia) + RETURN_ERROR( MAJOR, E_INVALID_STATE, + ("xFPNE was defined previously different")); + } + + if ((p_CcParams->setCcParams.type & UPDATE_NIA_CMNE) + && !(p_FmPort->requiredAction & UPDATE_NIA_CMNE)) + { + p_FmPort->savedBmiCmne = p_CcParams->setCcParams.nia; + p_FmPort->requiredAction |= UPDATE_NIA_CMNE; + } + else + if (p_CcParams->setCcParams.type & UPDATE_NIA_CMNE) + { + if (p_FmPort->savedBmiCmne != p_CcParams->setCcParams.nia) + RETURN_ERROR( MAJOR, E_INVALID_STATE, + ("xCMNE was defined previously different")); + } + + if ((p_CcParams->setCcParams.type & UPDATE_PSO) + && !(p_FmPort->requiredAction & UPDATE_PSO)) + { + /* get PCD registers pointers */ + switch (p_FmPort->portType) + { + case (e_FM_PORT_TYPE_RX_10G): + case (e_FM_PORT_TYPE_RX): + p_BmiPrsStartOffset = &p_FmPort->port.bmi_regs->rx.fmbm_rpso; + break; + case (e_FM_PORT_TYPE_OH_OFFLINE_PARSING): + p_BmiPrsStartOffset = &p_FmPort->port.bmi_regs->oh.fmbm_opso; + break; + default: + RETURN_ERROR(MAJOR, E_INVALID_STATE, ("Invalid port type")); + } + + /* set start parsing offset */ + tmpInt = (int)GET_UINT32(*p_BmiPrsStartOffset) + + p_CcParams->setCcParams.psoSize; + if (tmpInt > 0) + WRITE_UINT32(*p_BmiPrsStartOffset, (uint32_t)tmpInt); + + p_FmPort->requiredAction |= UPDATE_PSO; + p_FmPort->savedPrsStartOffset = p_CcParams->setCcParams.psoSize; + } + else + if (p_CcParams->setCcParams.type & UPDATE_PSO) + { + if (p_FmPort->savedPrsStartOffset + != p_CcParams->setCcParams.psoSize) + RETURN_ERROR( + MAJOR, + E_INVALID_STATE, + ("parser start offset was defoned previousley different")); + } + + if ((p_CcParams->setCcParams.type & UPDATE_OFP_DPTE) + && !(p_FmPort->requiredAction & UPDATE_OFP_DPTE)) + { + if (p_FmPort->portType != e_FM_PORT_TYPE_OH_OFFLINE_PARSING) + RETURN_ERROR(MAJOR, E_INVALID_STATE, ("Invalid port type")); + p_FmPort->savedBmiOfp = GET_UINT32(p_FmPort->port.bmi_regs->oh.fmbm_ofp); + p_FmPort->savedBmiOfp &= ~BMI_FIFO_PIPELINE_DEPTH_MASK; + p_FmPort->savedBmiOfp |= p_CcParams->setCcParams.ofpDpde + << BMI_FIFO_PIPELINE_DEPTH_SHIFT; + p_FmPort->requiredAction |= UPDATE_OFP_DPTE; + } + + return E_OK; +} +/*********************** End of inter-module routines ************************/ + +/****************************************/ +/* API Init unit functions */ +/****************************************/ + +t_Handle FM_PORT_Config(t_FmPortParams *p_FmPortParams) +{ + t_FmPort *p_FmPort; + uintptr_t baseAddr = p_FmPortParams->baseAddr; + uint32_t tmpReg; + + /* Allocate FM structure */ + p_FmPort = (t_FmPort *)XX_Malloc(sizeof(t_FmPort)); + if (!p_FmPort) + { + REPORT_ERROR(MAJOR, E_NO_MEMORY, ("FM Port driver structure")); + return NULL; + } + memset(p_FmPort, 0, sizeof(t_FmPort)); + + /* Allocate the FM driver's parameters structure */ + p_FmPort->p_FmPortDriverParam = (t_FmPortDriverParam *)XX_Malloc( + sizeof(t_FmPortDriverParam)); + if (!p_FmPort->p_FmPortDriverParam) + { + XX_Free(p_FmPort); + REPORT_ERROR(MAJOR, E_NO_MEMORY, ("FM Port driver parameters")); + return NULL; + } + memset(p_FmPort->p_FmPortDriverParam, 0, sizeof(t_FmPortDriverParam)); + + /* Initialize FM port parameters which will be kept by the driver */ + p_FmPort->portType = p_FmPortParams->portType; + p_FmPort->portId = p_FmPortParams->portId; + p_FmPort->pcdEngines = FM_PCD_NONE; + p_FmPort->f_Exception = p_FmPortParams->f_Exception; + p_FmPort->h_App = p_FmPortParams->h_App; + p_FmPort->h_Fm = p_FmPortParams->h_Fm; + + /* get FM revision */ + FM_GetRevision(p_FmPort->h_Fm, &p_FmPort->fmRevInfo); + + /* calculate global portId number */ + p_FmPort->hardwarePortId = SwPortIdToHwPortId(p_FmPort->portType, + p_FmPortParams->portId, + p_FmPort->fmRevInfo.majorRev, + p_FmPort->fmRevInfo.minorRev); + + if (p_FmPort->fmRevInfo.majorRev >= 6) + { + if ((p_FmPort->portType == e_FM_PORT_TYPE_OH_HOST_COMMAND) + && (p_FmPortParams->portId != FM_OH_PORT_ID)) + DBG(WARNING, + ("Port ID %d is recommended for HC port. Overwriting HW defaults to be suitable for HC.", + FM_OH_PORT_ID)); + + if ((p_FmPort->portType == e_FM_PORT_TYPE_OH_OFFLINE_PARSING) + && (p_FmPortParams->portId == FM_OH_PORT_ID)) + DBG(WARNING, ("Use non-zero portId for OP port due to insufficient resources on portId 0.")); + } + + /* Set up FM port parameters for initialization phase only */ + + /* First, fill in flibs struct */ + fman_port_defconfig(&p_FmPort->p_FmPortDriverParam->dfltCfg, + (enum fman_port_type)p_FmPort->portType); + /* Overwrite some integration specific parameters */ + p_FmPort->p_FmPortDriverParam->dfltCfg.rx_pri_elevation = + DEFAULT_PORT_rxFifoPriElevationLevel; + p_FmPort->p_FmPortDriverParam->dfltCfg.rx_fifo_thr = + DEFAULT_PORT_rxFifoThreshold; + +#if defined(FM_OP_NO_VSP_NO_RELEASE_ERRATA_FMAN_A006675) || defined(FM_ERROR_VSP_NO_MATCH_SW006) + p_FmPort->p_FmPortDriverParam->dfltCfg.errata_A006675 = TRUE; +#else + p_FmPort->p_FmPortDriverParam->dfltCfg.errata_A006675 = FALSE; +#endif + if ((p_FmPort->fmRevInfo.majorRev == 6) + && (p_FmPort->fmRevInfo.minorRev == 0)) + p_FmPort->p_FmPortDriverParam->dfltCfg.errata_A006320 = TRUE; + else + p_FmPort->p_FmPortDriverParam->dfltCfg.errata_A006320 = FALSE; + + /* Excessive Threshold register - exists for pre-FMv3 chips only */ + if (p_FmPort->fmRevInfo.majorRev < 6) + { +#ifdef FM_NO_RESTRICT_ON_ACCESS_RSRC + p_FmPort->p_FmPortDriverParam->dfltCfg.excessive_threshold_register = + TRUE; +#endif + p_FmPort->p_FmPortDriverParam->dfltCfg.fmbm_rebm_has_sgd = FALSE; + p_FmPort->p_FmPortDriverParam->dfltCfg.fmbm_tfne_has_features = FALSE; + } + else + { + p_FmPort->p_FmPortDriverParam->dfltCfg.excessive_threshold_register = + FALSE; + p_FmPort->p_FmPortDriverParam->dfltCfg.fmbm_rebm_has_sgd = TRUE; + p_FmPort->p_FmPortDriverParam->dfltCfg.fmbm_tfne_has_features = TRUE; + } + if (p_FmPort->fmRevInfo.majorRev == 4) + p_FmPort->p_FmPortDriverParam->dfltCfg.qmi_deq_options_support = FALSE; + else + p_FmPort->p_FmPortDriverParam->dfltCfg.qmi_deq_options_support = TRUE; + + /* Continue with other parameters */ + p_FmPort->p_FmPortDriverParam->baseAddr = baseAddr; + /* set memory map pointers */ + p_FmPort->p_FmPortQmiRegs = + (t_FmPortQmiRegs *)UINT_TO_PTR(baseAddr + QMI_PORT_REGS_OFFSET); + p_FmPort->p_FmPortBmiRegs = + (u_FmPortBmiRegs *)UINT_TO_PTR(baseAddr + BMI_PORT_REGS_OFFSET); + p_FmPort->p_FmPortPrsRegs = + (t_FmPortPrsRegs *)UINT_TO_PTR(baseAddr + PRS_PORT_REGS_OFFSET); + + p_FmPort->p_FmPortDriverParam->bufferPrefixContent.privDataSize = + DEFAULT_PORT_bufferPrefixContent_privDataSize; + p_FmPort->p_FmPortDriverParam->bufferPrefixContent.passPrsResult = + DEFAULT_PORT_bufferPrefixContent_passPrsResult; + p_FmPort->p_FmPortDriverParam->bufferPrefixContent.passTimeStamp = + DEFAULT_PORT_bufferPrefixContent_passTimeStamp; + p_FmPort->p_FmPortDriverParam->bufferPrefixContent.passAllOtherPCDInfo = + DEFAULT_PORT_bufferPrefixContent_passTimeStamp; + p_FmPort->p_FmPortDriverParam->bufferPrefixContent.dataAlign = + DEFAULT_PORT_bufferPrefixContent_dataAlign; + /* p_FmPort->p_FmPortDriverParam->dmaSwapData = (e_FmDmaSwapOption)DEFAULT_PORT_dmaSwapData; + p_FmPort->p_FmPortDriverParam->dmaIntContextCacheAttr = (e_FmDmaCacheOption)DEFAULT_PORT_dmaIntContextCacheAttr; + p_FmPort->p_FmPortDriverParam->dmaHeaderCacheAttr = (e_FmDmaCacheOption)DEFAULT_PORT_dmaHeaderCacheAttr; + p_FmPort->p_FmPortDriverParam->dmaScatterGatherCacheAttr = (e_FmDmaCacheOption)DEFAULT_PORT_dmaScatterGatherCacheAttr; + p_FmPort->p_FmPortDriverParam->dmaWriteOptimize = DEFAULT_PORT_dmaWriteOptimize; + */ + p_FmPort->p_FmPortDriverParam->liodnBase = p_FmPortParams->liodnBase; + p_FmPort->p_FmPortDriverParam->cheksumLastBytesIgnore = + DEFAULT_PORT_cheksumLastBytesIgnore; + + p_FmPort->maxFrameLength = DEFAULT_PORT_maxFrameLength; + /* resource distribution. */ + p_FmPort->fifoBufs.num = DEFAULT_PORT_numOfFifoBufs(p_FmPort->portType) + * BMI_FIFO_UNITS; + p_FmPort->fifoBufs.extra = DEFAULT_PORT_extraNumOfFifoBufs + * BMI_FIFO_UNITS; + p_FmPort->openDmas.num = DEFAULT_PORT_numOfOpenDmas(p_FmPort->portType); + p_FmPort->openDmas.extra = + DEFAULT_PORT_extraNumOfOpenDmas(p_FmPort->portType); + p_FmPort->tasks.num = DEFAULT_PORT_numOfTasks(p_FmPort->portType); + p_FmPort->tasks.extra = DEFAULT_PORT_extraNumOfTasks(p_FmPort->portType); + + +#ifdef FM_HEAVY_TRAFFIC_SEQUENCER_HANG_ERRATA_FMAN_A006981 + if ((p_FmPort->fmRevInfo.majorRev == 6) + && (p_FmPort->fmRevInfo.minorRev == 0) + && ((p_FmPort->portType == e_FM_PORT_TYPE_OH_OFFLINE_PARSING) + || (p_FmPort->portType == e_FM_PORT_TYPE_TX))) + { + p_FmPort->openDmas.num = 16; + p_FmPort->openDmas.extra = 0; + } +#endif /* FM_HEAVY_TRAFFIC_SEQUENCER_HANG_ERRATA_FMAN_A006981 */ + + /* Port type specific initialization: */ + switch (p_FmPort->portType) + { + case (e_FM_PORT_TYPE_RX): + case (e_FM_PORT_TYPE_RX_10G): + /* Initialize FM port parameters for initialization phase only */ + p_FmPort->p_FmPortDriverParam->cutBytesFromEnd = + DEFAULT_PORT_cutBytesFromEnd; + p_FmPort->p_FmPortDriverParam->enBufPoolDepletion = FALSE; + p_FmPort->p_FmPortDriverParam->frmDiscardOverride = + DEFAULT_PORT_frmDiscardOverride; + + tmpReg = + GET_UINT32(p_FmPort->p_FmPortBmiRegs->rxPortBmiRegs.fmbm_rfp); + p_FmPort->p_FmPortDriverParam->rxFifoPriElevationLevel = + (((tmpReg & BMI_RX_FIFO_PRI_ELEVATION_MASK) + >> BMI_RX_FIFO_PRI_ELEVATION_SHIFT) + 1) + * BMI_FIFO_UNITS; + p_FmPort->p_FmPortDriverParam->rxFifoThreshold = (((tmpReg + & BMI_RX_FIFO_THRESHOLD_MASK) + >> BMI_RX_FIFO_THRESHOLD_SHIFT) + 1) * BMI_FIFO_UNITS; + + p_FmPort->p_FmPortDriverParam->bufMargins.endMargins = + DEFAULT_PORT_BufMargins_endMargins; + p_FmPort->p_FmPortDriverParam->errorsToDiscard = + DEFAULT_PORT_errorsToDiscard; + p_FmPort->p_FmPortDriverParam->forwardReuseIntContext = + DEFAULT_PORT_forwardIntContextReuse; +#if (DPAA_VERSION >= 11) + p_FmPort->p_FmPortDriverParam->noScatherGather = + DEFAULT_PORT_noScatherGather; +#endif /* (DPAA_VERSION >= 11) */ + break; + + case (e_FM_PORT_TYPE_TX): + p_FmPort->p_FmPortDriverParam->dontReleaseBuf = FALSE; +#ifdef FM_WRONG_RESET_VALUES_ERRATA_FMAN_A005127 + tmpReg = 0x00001013; + WRITE_UINT32( p_FmPort->p_FmPortBmiRegs->txPortBmiRegs.fmbm_tfp, + tmpReg); +#endif /* FM_WRONG_RESET_VALUES_ERRATA_FMAN_A005127 */ + + /* fall through */ + case (e_FM_PORT_TYPE_TX_10G): + tmpReg = + GET_UINT32(p_FmPort->p_FmPortBmiRegs->txPortBmiRegs.fmbm_tfp); + p_FmPort->p_FmPortDriverParam->txFifoMinFillLevel = ((tmpReg + & BMI_TX_FIFO_MIN_FILL_MASK) + >> BMI_TX_FIFO_MIN_FILL_SHIFT) * BMI_FIFO_UNITS; + p_FmPort->p_FmPortDriverParam->dfltCfg.tx_fifo_deq_pipeline_depth = + (uint8_t)(((tmpReg & BMI_FIFO_PIPELINE_DEPTH_MASK) + >> BMI_FIFO_PIPELINE_DEPTH_SHIFT) + 1); + p_FmPort->p_FmPortDriverParam->txFifoLowComfLevel = (((tmpReg + & BMI_TX_LOW_COMF_MASK) >> BMI_TX_LOW_COMF_SHIFT) + 1) + * BMI_FIFO_UNITS; + + p_FmPort->p_FmPortDriverParam->deqType = DEFAULT_PORT_deqType; + p_FmPort->p_FmPortDriverParam->deqPrefetchOption = + DEFAULT_PORT_deqPrefetchOption; + p_FmPort->p_FmPortDriverParam->deqHighPriority = + (bool)((p_FmPort->portType == e_FM_PORT_TYPE_TX) ? DEFAULT_PORT_deqHighPriority_1G : + DEFAULT_PORT_deqHighPriority_10G); + p_FmPort->p_FmPortDriverParam->deqByteCnt = + (uint16_t)( + (p_FmPort->portType == e_FM_PORT_TYPE_TX) ? DEFAULT_PORT_deqByteCnt_1G : + DEFAULT_PORT_deqByteCnt_10G); + break; + case (e_FM_PORT_TYPE_OH_OFFLINE_PARSING): + p_FmPort->p_FmPortDriverParam->errorsToDiscard = + DEFAULT_PORT_errorsToDiscard; +#if (DPAA_VERSION >= 11) + p_FmPort->p_FmPortDriverParam->noScatherGather = + DEFAULT_PORT_noScatherGather; +#endif /* (DPAA_VERSION >= 11) */ + /* fall through */ + case (e_FM_PORT_TYPE_OH_HOST_COMMAND): + p_FmPort->p_FmPortDriverParam->deqPrefetchOption = + DEFAULT_PORT_deqPrefetchOption_HC; + p_FmPort->p_FmPortDriverParam->deqHighPriority = + DEFAULT_PORT_deqHighPriority_1G; + p_FmPort->p_FmPortDriverParam->deqType = DEFAULT_PORT_deqType; + p_FmPort->p_FmPortDriverParam->deqByteCnt = + DEFAULT_PORT_deqByteCnt_1G; + + tmpReg = + GET_UINT32(p_FmPort->p_FmPortBmiRegs->ohPortBmiRegs.fmbm_ofp); + p_FmPort->p_FmPortDriverParam->dfltCfg.tx_fifo_deq_pipeline_depth = + (uint8_t)(((tmpReg & BMI_FIFO_PIPELINE_DEPTH_MASK) + >> BMI_FIFO_PIPELINE_DEPTH_SHIFT) + 1); + if ((p_FmPort->portType == e_FM_PORT_TYPE_OH_HOST_COMMAND) + && (p_FmPortParams->portId != FM_OH_PORT_ID)) + { + /* Overwrite HC defaults */ + p_FmPort->p_FmPortDriverParam->dfltCfg.tx_fifo_deq_pipeline_depth = + DEFAULT_PORT_fifoDeqPipelineDepth_OH; + } + +#ifndef FM_FRAME_END_PARAMS_FOR_OP + if (p_FmPort->fmRevInfo.majorRev < 6) + p_FmPort->p_FmPortDriverParam->cheksumLastBytesIgnore = DEFAULT_notSupported; +#endif /* !FM_FRAME_END_PARAMS_FOR_OP */ + +#ifndef FM_DEQ_PIPELINE_PARAMS_FOR_OP + if (!((p_FmPort->fmRevInfo.majorRev == 4) || + (p_FmPort->fmRevInfo.majorRev >= 6))) + p_FmPort->p_FmPortDriverParam->dfltCfg.tx_fifo_deq_pipeline_depth = DEFAULT_notSupported; +#endif /* !FM_DEQ_PIPELINE_PARAMS_FOR_OP */ + break; + + default: + XX_Free(p_FmPort->p_FmPortDriverParam); + XX_Free(p_FmPort); + REPORT_ERROR(MAJOR, E_INVALID_STATE, ("Invalid port type")); + return NULL; + } +#ifdef FM_QMI_NO_DEQ_OPTIONS_SUPPORT + if (p_FmPort->fmRevInfo.majorRev == 4) + p_FmPort->p_FmPortDriverParam->deqPrefetchOption = (e_FmPortDeqPrefetchOption)DEFAULT_notSupported; +#endif /* FM_QMI_NO_DEQ_OPTIONS_SUPPORT */ + + p_FmPort->imEn = p_FmPortParams->independentModeEnable; + + if (p_FmPort->imEn) + { + if ((p_FmPort->portType == e_FM_PORT_TYPE_TX) + || (p_FmPort->portType == e_FM_PORT_TYPE_TX_10G)) + p_FmPort->p_FmPortDriverParam->dfltCfg.tx_fifo_deq_pipeline_depth = + DEFAULT_PORT_fifoDeqPipelineDepth_IM; + FmPortConfigIM(p_FmPort, p_FmPortParams); + } + else + { + switch (p_FmPort->portType) + { + case (e_FM_PORT_TYPE_RX): + case (e_FM_PORT_TYPE_RX_10G): + /* Initialize FM port parameters for initialization phase only */ + memcpy(&p_FmPort->p_FmPortDriverParam->extBufPools, + &p_FmPortParams->specificParams.rxParams.extBufPools, + sizeof(t_FmExtPools)); + p_FmPort->p_FmPortDriverParam->errFqid = + p_FmPortParams->specificParams.rxParams.errFqid; + p_FmPort->p_FmPortDriverParam->dfltFqid = + p_FmPortParams->specificParams.rxParams.dfltFqid; + p_FmPort->p_FmPortDriverParam->liodnOffset = + p_FmPortParams->specificParams.rxParams.liodnOffset; + break; + case (e_FM_PORT_TYPE_OH_OFFLINE_PARSING): + case (e_FM_PORT_TYPE_TX): + case (e_FM_PORT_TYPE_TX_10G): + case (e_FM_PORT_TYPE_OH_HOST_COMMAND): + p_FmPort->p_FmPortDriverParam->errFqid = + p_FmPortParams->specificParams.nonRxParams.errFqid; + p_FmPort->p_FmPortDriverParam->deqSubPortal = + (uint8_t)(p_FmPortParams->specificParams.nonRxParams.qmChannel + & QMI_DEQ_CFG_SUBPORTAL_MASK); + p_FmPort->p_FmPortDriverParam->dfltFqid = + p_FmPortParams->specificParams.nonRxParams.dfltFqid; + break; + default: + XX_Free(p_FmPort->p_FmPortDriverParam); + XX_Free(p_FmPort); + REPORT_ERROR(MAJOR, E_INVALID_STATE, ("Invalid port type")); + return NULL; + } + } + + memset(p_FmPort->name, 0, (sizeof(char)) * MODULE_NAME_SIZE); + if (Sprint( + p_FmPort->name, + "FM-%d-port-%s-%d", + FmGetId(p_FmPort->h_Fm), + ((p_FmPort->portType == e_FM_PORT_TYPE_OH_OFFLINE_PARSING + || (p_FmPort->portType == e_FM_PORT_TYPE_OH_HOST_COMMAND)) ? "OH" : + (p_FmPort->portType == e_FM_PORT_TYPE_RX ? "1g-RX" : + (p_FmPort->portType == e_FM_PORT_TYPE_TX ? "1g-TX" : + (p_FmPort->portType + == e_FM_PORT_TYPE_RX_10G ? "10g-RX" : + "10g-TX")))), + p_FmPort->portId) == 0) + { + XX_Free(p_FmPort->p_FmPortDriverParam); + XX_Free(p_FmPort); + REPORT_ERROR(MAJOR, E_INVALID_STATE, ("Sprint failed")); + return NULL; + } + + p_FmPort->h_Spinlock = XX_InitSpinlock(); + if (!p_FmPort->h_Spinlock) + { + XX_Free(p_FmPort->p_FmPortDriverParam); + XX_Free(p_FmPort); + REPORT_ERROR(MAJOR, E_INVALID_STATE, ("Sprint failed")); + return NULL; + } + + return p_FmPort; +} + +t_FmPort *rx_port = 0; +t_FmPort *tx_port = 0; + +/**************************************************************************//** + @Function FM_PORT_Init + + @Description Initializes the FM module + + @Param[in] h_FmPort - FM module descriptor + + @Return E_OK on success; Error code otherwise. + *//***************************************************************************/ +t_Error FM_PORT_Init(t_Handle h_FmPort) +{ + t_FmPort *p_FmPort = (t_FmPort*)h_FmPort; + t_FmPortDriverParam *p_DriverParams; + t_Error errCode; + t_FmInterModulePortInitParams fmParams; + t_FmRevisionInfo revInfo; + + SANITY_CHECK_RETURN_ERROR(h_FmPort, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_FmPort->p_FmPortDriverParam, E_INVALID_HANDLE); + + errCode = FmSpBuildBufferStructure( + &p_FmPort->p_FmPortDriverParam->intContext, + &p_FmPort->p_FmPortDriverParam->bufferPrefixContent, + &p_FmPort->p_FmPortDriverParam->bufMargins, + &p_FmPort->bufferOffsets, &p_FmPort->internalBufferOffset); + if (errCode != E_OK) + RETURN_ERROR(MAJOR, errCode, NO_MSG); +#ifdef FM_HEAVY_TRAFFIC_HANG_ERRATA_FMAN_A005669 + if ((p_FmPort->p_FmPortDriverParam->bcbWorkaround) && + (p_FmPort->portType == e_FM_PORT_TYPE_RX)) + { + p_FmPort->p_FmPortDriverParam->errorsToDiscard |= FM_PORT_FRM_ERR_PHYSICAL; + if (!p_FmPort->fifoBufs.num) + p_FmPort->fifoBufs.num = DEFAULT_PORT_numOfFifoBufs(p_FmPort->portType)*BMI_FIFO_UNITS; + p_FmPort->fifoBufs.num += 4*KILOBYTE; + } +#endif /* FM_HEAVY_TRAFFIC_HANG_ERRATA_FMAN_A005669 */ + + CHECK_INIT_PARAMETERS(p_FmPort, CheckInitParameters); + + p_DriverParams = p_FmPort->p_FmPortDriverParam; + + /* Set up flibs port structure */ + memset(&p_FmPort->port, 0, sizeof(struct fman_port)); + p_FmPort->port.type = (enum fman_port_type)p_FmPort->portType; + FM_GetRevision(p_FmPort->h_Fm, &revInfo); + p_FmPort->port.fm_rev_maj = revInfo.majorRev; + p_FmPort->port.fm_rev_min = revInfo.minorRev; + p_FmPort->port.bmi_regs = + (union fman_port_bmi_regs *)UINT_TO_PTR(p_DriverParams->baseAddr + BMI_PORT_REGS_OFFSET); + p_FmPort->port.qmi_regs = + (struct fman_port_qmi_regs *)UINT_TO_PTR(p_DriverParams->baseAddr + QMI_PORT_REGS_OFFSET); + p_FmPort->port.ext_pools_num = (uint8_t)((revInfo.majorRev == 4) ? 4 : 8); + p_FmPort->port.im_en = p_FmPort->imEn; + p_FmPort->p_FmPortPrsRegs = + (t_FmPortPrsRegs *)UINT_TO_PTR(p_DriverParams->baseAddr + PRS_PORT_REGS_OFFSET); + + if (((p_FmPort->portType == e_FM_PORT_TYPE_RX_10G) + || (p_FmPort->portType == e_FM_PORT_TYPE_RX)) && !p_FmPort->imEn) + { + /* Call the external Buffer routine which also checks fifo + size and updates it if necessary */ + /* define external buffer pools and pool depletion*/ + errCode = SetExtBufferPools(p_FmPort); + if (errCode) + RETURN_ERROR(MAJOR, errCode, NO_MSG); + /* check if the largest external buffer pool is large enough */ + if (p_DriverParams->bufMargins.startMargins + MIN_EXT_BUF_SIZE + + p_DriverParams->bufMargins.endMargins + > p_FmPort->rxPoolsParams.largestBufSize) + RETURN_ERROR( + MAJOR, + E_INVALID_VALUE, + ("bufMargins.startMargins (%d) + minimum buf size (64) + bufMargins.endMargins (%d) is larger than maximum external buffer size (%d)", p_DriverParams->bufMargins.startMargins, p_DriverParams->bufMargins.endMargins, p_FmPort->rxPoolsParams.largestBufSize)); + } + if (p_FmPort->portType == e_FM_PORT_TYPE_OH_OFFLINE_PARSING) + { + { +#ifdef FM_NO_OP_OBSERVED_POOLS + t_FmRevisionInfo revInfo; + + FM_GetRevision(p_FmPort->h_Fm, &revInfo); + if ((revInfo.majorRev == 4) && (p_DriverParams->enBufPoolDepletion)) +#endif /* FM_NO_OP_OBSERVED_POOLS */ + { + /* define external buffer pools */ + errCode = SetExtBufferPools(p_FmPort); + if (errCode) + RETURN_ERROR(MAJOR, errCode, NO_MSG); + } + } + } + + /************************************************************/ + /* Call FM module routine for communicating parameters */ + /************************************************************/ + memset(&fmParams, 0, sizeof(fmParams)); + fmParams.hardwarePortId = p_FmPort->hardwarePortId; + fmParams.portType = (e_FmPortType)p_FmPort->portType; + fmParams.numOfTasks = (uint8_t)p_FmPort->tasks.num; + fmParams.numOfExtraTasks = (uint8_t)p_FmPort->tasks.extra; + fmParams.numOfOpenDmas = (uint8_t)p_FmPort->openDmas.num; + fmParams.numOfExtraOpenDmas = (uint8_t)p_FmPort->openDmas.extra; + + if (p_FmPort->fifoBufs.num) + { + errCode = VerifySizeOfFifo(p_FmPort); + if (errCode != E_OK) + RETURN_ERROR(MAJOR, errCode, NO_MSG); + } + fmParams.sizeOfFifo = p_FmPort->fifoBufs.num; + fmParams.extraSizeOfFifo = p_FmPort->fifoBufs.extra; + fmParams.independentMode = p_FmPort->imEn; + fmParams.liodnOffset = p_DriverParams->liodnOffset; + fmParams.liodnBase = p_DriverParams->liodnBase; + fmParams.deqPipelineDepth = + p_FmPort->p_FmPortDriverParam->dfltCfg.tx_fifo_deq_pipeline_depth; + fmParams.maxFrameLength = p_FmPort->maxFrameLength; +#ifndef FM_DEQ_PIPELINE_PARAMS_FOR_OP + if ((p_FmPort->portType == e_FM_PORT_TYPE_OH_OFFLINE_PARSING) || + (p_FmPort->portType == e_FM_PORT_TYPE_OH_HOST_COMMAND)) + { + if (!((p_FmPort->fmRevInfo.majorRev == 4) || + (p_FmPort->fmRevInfo.majorRev >= 6))) + /* HC ports do not have fifoDeqPipelineDepth, but it is needed only + * for deq threshold calculation. + */ + fmParams.deqPipelineDepth = 2; + } +#endif /* !FM_DEQ_PIPELINE_PARAMS_FOR_OP */ + + errCode = FmGetSetPortParams(p_FmPort->h_Fm, &fmParams); + if (errCode) + RETURN_ERROR(MAJOR, errCode, NO_MSG); + + /* get params for use in init */ + p_FmPort->fmMuramPhysBaseAddr = + (uint64_t)((uint64_t)(fmParams.fmMuramPhysBaseAddr.low) + | ((uint64_t)(fmParams.fmMuramPhysBaseAddr.high) << 32)); + p_FmPort->h_FmMuram = FmGetMuramHandle(p_FmPort->h_Fm); + + errCode = InitLowLevelDriver(p_FmPort); + if (errCode != E_OK) + RETURN_ERROR(MAJOR, errCode, NO_MSG); + + FmPortDriverParamFree(p_FmPort); + +#if (DPAA_VERSION >= 11) + if ((p_FmPort->portType == e_FM_PORT_TYPE_RX_10G) + || (p_FmPort->portType == e_FM_PORT_TYPE_RX) + || (p_FmPort->portType == e_FM_PORT_TYPE_OH_OFFLINE_PARSING)) + { + t_FmPcdCtrlParamsPage *p_ParamsPage; + + FmPortSetGprFunc(p_FmPort, e_FM_PORT_GPR_MURAM_PAGE, + (void**)&p_ParamsPage); + ASSERT_COND(p_ParamsPage); + + WRITE_UINT32(p_ParamsPage->misc, FM_CTL_PARAMS_PAGE_ALWAYS_ON); +#ifdef FM_OP_NO_VSP_NO_RELEASE_ERRATA_FMAN_A006675 + if (p_FmPort->portType == e_FM_PORT_TYPE_OH_OFFLINE_PARSING) + { + WRITE_UINT32( + p_ParamsPage->misc, + (GET_UINT32(p_ParamsPage->misc) | FM_CTL_PARAMS_PAGE_OP_FIX_EN)); + WRITE_UINT32( + p_ParamsPage->discardMask, + GET_UINT32(p_FmPort->p_FmPortBmiRegs->ohPortBmiRegs.fmbm_ofsdm)); + } +#endif /* FM_OP_NO_VSP_NO_RELEASE_ERRATA_FMAN_A006675 */ +#ifdef FM_ERROR_VSP_NO_MATCH_SW006 + if (p_FmPort->portType == e_FM_PORT_TYPE_OH_OFFLINE_PARSING) + WRITE_UINT32( + p_ParamsPage->errorsDiscardMask, + (GET_UINT32(p_FmPort->p_FmPortBmiRegs->ohPortBmiRegs.fmbm_ofsdm) | GET_UINT32(p_FmPort->p_FmPortBmiRegs->ohPortBmiRegs.fmbm_ofsem))); + else + WRITE_UINT32( + p_ParamsPage->errorsDiscardMask, + (GET_UINT32(p_FmPort->p_FmPortBmiRegs->rxPortBmiRegs.fmbm_rfsdm) | GET_UINT32(p_FmPort->p_FmPortBmiRegs->rxPortBmiRegs.fmbm_rfsem))); +#endif /* FM_ERROR_VSP_NO_MATCH_SW006 */ + } +#endif /* (DPAA_VERSION >= 11) */ + + if (p_FmPort->deepSleepVars.autoResMaxSizes) + FmPortConfigAutoResForDeepSleepSupport1(p_FmPort); + return E_OK; +} + +/**************************************************************************//** + @Function FM_PORT_Free + + @Description Frees all resources that were assigned to FM module. + + Calling this routine invalidates the descriptor. + + @Param[in] h_FmPort - FM module descriptor + + @Return E_OK on success; Error code otherwise. + *//***************************************************************************/ +t_Error FM_PORT_Free(t_Handle h_FmPort) +{ + t_FmPort *p_FmPort = (t_FmPort*)h_FmPort; + t_FmInterModulePortFreeParams fmParams; + + SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE); + + if (p_FmPort->pcdEngines) + RETURN_ERROR( + MAJOR, + E_INVALID_STATE, + ("Trying to free a port with PCD. FM_PORT_DeletePCD must be called first.")); + + if (p_FmPort->enabled) + { + if (FM_PORT_Disable(p_FmPort) != E_OK) + RETURN_ERROR(MAJOR, E_INVALID_STATE, ("FM_PORT_Disable FAILED")); + } + + if (p_FmPort->imEn) + FmPortImFree(p_FmPort); + + FmPortDriverParamFree(p_FmPort); + + memset(&fmParams, 0, sizeof(fmParams)); + fmParams.hardwarePortId = p_FmPort->hardwarePortId; + fmParams.portType = (e_FmPortType)p_FmPort->portType; + fmParams.deqPipelineDepth = + p_FmPort->p_FmPortDriverParam->dfltCfg.tx_fifo_deq_pipeline_depth; + + FmFreePortParams(p_FmPort->h_Fm, &fmParams); + +#if (DPAA_VERSION >= 11) + if (FmVSPFreeForPort(p_FmPort->h_Fm, p_FmPort->portType, p_FmPort->portId) + != E_OK) + RETURN_ERROR(MAJOR, E_INVALID_STATE, ("VSP free of port FAILED")); + + if (p_FmPort->p_ParamsPage) + FM_MURAM_FreeMem(p_FmPort->h_FmMuram, p_FmPort->p_ParamsPage); +#endif /* (DPAA_VERSION >= 11) */ + + if (p_FmPort->h_Spinlock) + XX_FreeSpinlock(p_FmPort->h_Spinlock); + + XX_Free(p_FmPort); + + return E_OK; +} + +/*************************************************/ +/* API Advanced Init unit functions */ +/*************************************************/ + +t_Error FM_PORT_ConfigNumOfOpenDmas(t_Handle h_FmPort, t_FmPortRsrc *p_OpenDmas) +{ + t_FmPort *p_FmPort = (t_FmPort*)h_FmPort; + + SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_FmPort->p_FmPortDriverParam, E_INVALID_HANDLE); + + p_FmPort->p_FmPortDriverParam->setNumOfOpenDmas = TRUE; + memcpy(&p_FmPort->openDmas, p_OpenDmas, sizeof(t_FmPortRsrc)); + + return E_OK; +} + +t_Error FM_PORT_ConfigNumOfTasks(t_Handle h_FmPort, t_FmPortRsrc *p_NumOfTasks) +{ + t_FmPort *p_FmPort = (t_FmPort*)h_FmPort; + + SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_FmPort->p_FmPortDriverParam, E_INVALID_HANDLE); + + memcpy(&p_FmPort->tasks, p_NumOfTasks, sizeof(t_FmPortRsrc)); + p_FmPort->p_FmPortDriverParam->setNumOfTasks = TRUE; + return E_OK; +} + +t_Error FM_PORT_ConfigSizeOfFifo(t_Handle h_FmPort, t_FmPortRsrc *p_SizeOfFifo) +{ + t_FmPort *p_FmPort = (t_FmPort*)h_FmPort; + + SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_FmPort->p_FmPortDriverParam, E_INVALID_HANDLE); + + p_FmPort->p_FmPortDriverParam->setSizeOfFifo = TRUE; + memcpy(&p_FmPort->fifoBufs, p_SizeOfFifo, sizeof(t_FmPortRsrc)); + + return E_OK; +} + +t_Error FM_PORT_ConfigDeqHighPriority(t_Handle h_FmPort, bool highPri) +{ + t_FmPort *p_FmPort = (t_FmPort*)h_FmPort; + + SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_FmPort->p_FmPortDriverParam, E_INVALID_HANDLE); + if ((p_FmPort->portType == e_FM_PORT_TYPE_RX_10G) + || (p_FmPort->portType == e_FM_PORT_TYPE_RX)) + RETURN_ERROR(MAJOR, E_NO_MEMORY, ("not available for Rx ports")); + + p_FmPort->p_FmPortDriverParam->dfltCfg.deq_high_pri = highPri; + + return E_OK; +} + +t_Error FM_PORT_ConfigDeqType(t_Handle h_FmPort, e_FmPortDeqType deqType) +{ + t_FmPort *p_FmPort = (t_FmPort*)h_FmPort; + + SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_FmPort->p_FmPortDriverParam, E_INVALID_HANDLE); + if ((p_FmPort->portType == e_FM_PORT_TYPE_RX_10G) + || (p_FmPort->portType == e_FM_PORT_TYPE_RX)) + RETURN_ERROR(MAJOR, E_INVALID_OPERATION, + ("not available for Rx ports")); + + p_FmPort->p_FmPortDriverParam->dfltCfg.deq_type = + (enum fman_port_deq_type)deqType; + + return E_OK; +} + +t_Error FM_PORT_ConfigDeqPrefetchOption( + t_Handle h_FmPort, e_FmPortDeqPrefetchOption deqPrefetchOption) +{ + t_FmPort *p_FmPort = (t_FmPort*)h_FmPort; + + SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_FmPort->p_FmPortDriverParam, E_INVALID_HANDLE); + if ((p_FmPort->portType == e_FM_PORT_TYPE_RX_10G) + || (p_FmPort->portType == e_FM_PORT_TYPE_RX)) + RETURN_ERROR(MAJOR, E_INVALID_OPERATION, + ("not available for Rx ports")); + p_FmPort->p_FmPortDriverParam->dfltCfg.deq_prefetch_opt = + (enum fman_port_deq_prefetch)deqPrefetchOption; + + return E_OK; +} + +t_Error FM_PORT_ConfigBackupPools(t_Handle h_FmPort, + t_FmBackupBmPools *p_BackupBmPools) +{ + t_FmPort *p_FmPort = (t_FmPort*)h_FmPort; + + SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_FmPort->p_FmPortDriverParam, E_INVALID_HANDLE); + if ((p_FmPort->portType != e_FM_PORT_TYPE_RX_10G) + && (p_FmPort->portType != e_FM_PORT_TYPE_RX)) + RETURN_ERROR(MAJOR, E_INVALID_OPERATION, + ("available for Rx ports only")); + + p_FmPort->p_FmPortDriverParam->p_BackupBmPools = + (t_FmBackupBmPools *)XX_Malloc(sizeof(t_FmBackupBmPools)); + if (!p_FmPort->p_FmPortDriverParam->p_BackupBmPools) + RETURN_ERROR(MAJOR, E_NO_MEMORY, ("p_BackupBmPools allocation failed")); + memcpy(p_FmPort->p_FmPortDriverParam->p_BackupBmPools, p_BackupBmPools, + sizeof(t_FmBackupBmPools)); + + return E_OK; +} + +t_Error FM_PORT_ConfigDeqByteCnt(t_Handle h_FmPort, uint16_t deqByteCnt) +{ + t_FmPort *p_FmPort = (t_FmPort*)h_FmPort; + + SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_FmPort->p_FmPortDriverParam, E_INVALID_HANDLE); + if ((p_FmPort->portType == e_FM_PORT_TYPE_RX_10G) + || (p_FmPort->portType == e_FM_PORT_TYPE_RX)) + RETURN_ERROR(MAJOR, E_INVALID_OPERATION, + ("not available for Rx ports")); + + p_FmPort->p_FmPortDriverParam->dfltCfg.deq_byte_cnt = deqByteCnt; + + return E_OK; +} + +t_Error FM_PORT_ConfigBufferPrefixContent( + t_Handle h_FmPort, t_FmBufferPrefixContent *p_FmBufferPrefixContent) +{ + t_FmPort *p_FmPort = (t_FmPort*)h_FmPort; + + SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_FmPort->p_FmPortDriverParam, E_INVALID_HANDLE); + + memcpy(&p_FmPort->p_FmPortDriverParam->bufferPrefixContent, + p_FmBufferPrefixContent, sizeof(t_FmBufferPrefixContent)); + /* if dataAlign was not initialized by user, we return to driver's default */ + if (!p_FmPort->p_FmPortDriverParam->bufferPrefixContent.dataAlign) + p_FmPort->p_FmPortDriverParam->bufferPrefixContent.dataAlign = + DEFAULT_PORT_bufferPrefixContent_dataAlign; + + return E_OK; +} + +t_Error FM_PORT_ConfigCheksumLastBytesIgnore(t_Handle h_FmPort, + uint8_t checksumLastBytesIgnore) +{ + t_FmPort *p_FmPort = (t_FmPort*)h_FmPort; + + SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_FmPort->p_FmPortDriverParam, E_INVALID_HANDLE); + + p_FmPort->p_FmPortDriverParam->dfltCfg.checksum_bytes_ignore = + checksumLastBytesIgnore; + + return E_OK; +} + +t_Error FM_PORT_ConfigCutBytesFromEnd(t_Handle h_FmPort, + uint8_t cutBytesFromEnd) +{ + t_FmPort *p_FmPort = (t_FmPort*)h_FmPort; + + SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_FmPort->p_FmPortDriverParam, E_INVALID_HANDLE); + if ((p_FmPort->portType != e_FM_PORT_TYPE_RX_10G) + && (p_FmPort->portType != e_FM_PORT_TYPE_RX)) + RETURN_ERROR(MAJOR, E_INVALID_OPERATION, + ("available for Rx ports only")); + + p_FmPort->p_FmPortDriverParam->dfltCfg.rx_cut_end_bytes = cutBytesFromEnd; + + return E_OK; +} + +t_Error FM_PORT_ConfigPoolDepletion(t_Handle h_FmPort, + t_FmBufPoolDepletion *p_BufPoolDepletion) +{ + t_FmPort *p_FmPort = (t_FmPort*)h_FmPort; + + SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_FmPort->p_FmPortDriverParam, E_INVALID_HANDLE); + if ((p_FmPort->portType != e_FM_PORT_TYPE_RX_10G) + && (p_FmPort->portType != e_FM_PORT_TYPE_RX)) + RETURN_ERROR(MAJOR, E_INVALID_OPERATION, + ("available for Rx ports only")); + + p_FmPort->p_FmPortDriverParam->enBufPoolDepletion = TRUE; + memcpy(&p_FmPort->p_FmPortDriverParam->bufPoolDepletion, p_BufPoolDepletion, + sizeof(t_FmBufPoolDepletion)); + + return E_OK; +} + +t_Error FM_PORT_ConfigObservedPoolDepletion( + t_Handle h_FmPort, + t_FmPortObservedBufPoolDepletion *p_FmPortObservedBufPoolDepletion) +{ + t_FmPort *p_FmPort = (t_FmPort*)h_FmPort; + + SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_FmPort->p_FmPortDriverParam, E_INVALID_HANDLE); + if (p_FmPort->portType != e_FM_PORT_TYPE_OH_OFFLINE_PARSING) + RETURN_ERROR(MAJOR, E_INVALID_OPERATION, + ("available for OP ports only")); + + p_FmPort->p_FmPortDriverParam->enBufPoolDepletion = TRUE; + memcpy(&p_FmPort->p_FmPortDriverParam->bufPoolDepletion, + &p_FmPortObservedBufPoolDepletion->poolDepletionParams, + sizeof(t_FmBufPoolDepletion)); + memcpy(&p_FmPort->p_FmPortDriverParam->extBufPools, + &p_FmPortObservedBufPoolDepletion->poolsParams, + sizeof(t_FmExtPools)); + + return E_OK; +} + +t_Error FM_PORT_ConfigExtBufPools(t_Handle h_FmPort, t_FmExtPools *p_FmExtPools) +{ + t_FmPort *p_FmPort = (t_FmPort*)h_FmPort; + + SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_FmPort->p_FmPortDriverParam, E_INVALID_HANDLE); + + if (p_FmPort->portType != e_FM_PORT_TYPE_OH_OFFLINE_PARSING) + RETURN_ERROR(MAJOR, E_INVALID_OPERATION, + ("available for OP ports only")); + + memcpy(&p_FmPort->p_FmPortDriverParam->extBufPools, p_FmExtPools, + sizeof(t_FmExtPools)); + + return E_OK; +} + +t_Error FM_PORT_ConfigDontReleaseTxBufToBM(t_Handle h_FmPort) +{ + t_FmPort *p_FmPort = (t_FmPort*)h_FmPort; + + SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_FmPort->p_FmPortDriverParam, E_INVALID_HANDLE); + if ((p_FmPort->portType != e_FM_PORT_TYPE_TX_10G) + && (p_FmPort->portType != e_FM_PORT_TYPE_TX)) + RETURN_ERROR(MAJOR, E_INVALID_OPERATION, + ("available for Tx ports only")); + + p_FmPort->p_FmPortDriverParam->dontReleaseBuf = TRUE; + + return E_OK; +} + +t_Error FM_PORT_ConfigDfltColor(t_Handle h_FmPort, e_FmPortColor color) +{ + t_FmPort *p_FmPort = (t_FmPort*)h_FmPort; + + SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_FmPort->p_FmPortDriverParam, E_INVALID_HANDLE); + p_FmPort->p_FmPortDriverParam->dfltCfg.color = (enum fman_port_color)color; + + return E_OK; +} + +t_Error FM_PORT_ConfigSyncReq(t_Handle h_FmPort, bool syncReq) +{ + t_FmPort *p_FmPort = (t_FmPort*)h_FmPort; + + SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_FmPort->p_FmPortDriverParam, E_INVALID_HANDLE); + + if ((p_FmPort->portType == e_FM_PORT_TYPE_TX_10G) + || (p_FmPort->portType == e_FM_PORT_TYPE_TX)) + RETURN_ERROR(MAJOR, E_INVALID_OPERATION, + ("Not available for Tx ports")); + + p_FmPort->p_FmPortDriverParam->dfltCfg.sync_req = syncReq; + + return E_OK; +} + +t_Error FM_PORT_ConfigFrmDiscardOverride(t_Handle h_FmPort, bool override) +{ + t_FmPort *p_FmPort = (t_FmPort*)h_FmPort; + + SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_FmPort->p_FmPortDriverParam, E_INVALID_HANDLE); + if ((p_FmPort->portType == e_FM_PORT_TYPE_TX_10G) + || (p_FmPort->portType == e_FM_PORT_TYPE_TX)) + RETURN_ERROR(MAJOR, E_INVALID_OPERATION, + ("Not available for Tx ports")); + + p_FmPort->p_FmPortDriverParam->dfltCfg.discard_override = override; + + return E_OK; +} + +t_Error FM_PORT_ConfigErrorsToDiscard(t_Handle h_FmPort, + fmPortFrameErrSelect_t errs) +{ + t_FmPort *p_FmPort = (t_FmPort*)h_FmPort; + + SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_FmPort->p_FmPortDriverParam, E_INVALID_HANDLE); + if ((p_FmPort->portType != e_FM_PORT_TYPE_RX_10G) + && (p_FmPort->portType != e_FM_PORT_TYPE_RX) + && (p_FmPort->portType != e_FM_PORT_TYPE_OH_OFFLINE_PARSING)) + RETURN_ERROR( MAJOR, E_INVALID_OPERATION, + ("available for Rx and offline parsing ports only")); + + p_FmPort->p_FmPortDriverParam->errorsToDiscard = errs; + + return E_OK; +} + +t_Error FM_PORT_ConfigDmaSwapData(t_Handle h_FmPort, e_FmDmaSwapOption swapData) +{ + t_FmPort *p_FmPort = (t_FmPort*)h_FmPort; + + SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_FmPort->p_FmPortDriverParam, E_INVALID_HANDLE); + + p_FmPort->p_FmPortDriverParam->dfltCfg.dma_swap_data = + (enum fman_port_dma_swap)swapData; + + return E_OK; +} + +t_Error FM_PORT_ConfigDmaIcCacheAttr(t_Handle h_FmPort, + e_FmDmaCacheOption intContextCacheAttr) +{ + t_FmPort *p_FmPort = (t_FmPort*)h_FmPort; + + SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_FmPort->p_FmPortDriverParam, E_INVALID_HANDLE); + + p_FmPort->p_FmPortDriverParam->dfltCfg.dma_ic_stash_on = + (bool)(intContextCacheAttr == e_FM_DMA_STASH); + + return E_OK; +} + +t_Error FM_PORT_ConfigDmaHdrAttr(t_Handle h_FmPort, + e_FmDmaCacheOption headerCacheAttr) +{ + t_FmPort *p_FmPort = (t_FmPort*)h_FmPort; + + SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_FmPort->p_FmPortDriverParam, E_INVALID_HANDLE); + + p_FmPort->p_FmPortDriverParam->dfltCfg.dma_header_stash_on = + (bool)(headerCacheAttr == e_FM_DMA_STASH); + + return E_OK; +} + +t_Error FM_PORT_ConfigDmaScatterGatherAttr( + t_Handle h_FmPort, e_FmDmaCacheOption scatterGatherCacheAttr) +{ + t_FmPort *p_FmPort = (t_FmPort*)h_FmPort; + + SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_FmPort->p_FmPortDriverParam, E_INVALID_HANDLE); + + p_FmPort->p_FmPortDriverParam->dfltCfg.dma_sg_stash_on = + (bool)(scatterGatherCacheAttr == e_FM_DMA_STASH); + + return E_OK; +} + +t_Error FM_PORT_ConfigDmaWriteOptimize(t_Handle h_FmPort, bool optimize) +{ + t_FmPort *p_FmPort = (t_FmPort*)h_FmPort; + + SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_FmPort->p_FmPortDriverParam, E_INVALID_HANDLE); + + if ((p_FmPort->portType == e_FM_PORT_TYPE_TX_10G) + || (p_FmPort->portType == e_FM_PORT_TYPE_TX)) + RETURN_ERROR(MAJOR, E_INVALID_OPERATION, + ("Not available for Tx ports")); + + p_FmPort->p_FmPortDriverParam->dfltCfg.dma_write_optimize = optimize; + + return E_OK; +} + +#if (DPAA_VERSION >= 11) +t_Error FM_PORT_ConfigNoScatherGather(t_Handle h_FmPort, bool noScatherGather) +{ + t_FmPort *p_FmPort = (t_FmPort*)h_FmPort; + + UNUSED(noScatherGather); + UNUSED(p_FmPort); + + SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_FmPort->p_FmPortDriverParam, E_INVALID_HANDLE); + + p_FmPort->p_FmPortDriverParam->noScatherGather = noScatherGather; + + return E_OK; +} +#endif /* (DPAA_VERSION >= 11) */ + +t_Error FM_PORT_ConfigForwardReuseIntContext(t_Handle h_FmPort, + bool forwardReuse) +{ + t_FmPort *p_FmPort = (t_FmPort*)h_FmPort; + + SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_FmPort->p_FmPortDriverParam, E_INVALID_HANDLE); + + if ((p_FmPort->portType != e_FM_PORT_TYPE_RX_10G) + && (p_FmPort->portType != e_FM_PORT_TYPE_RX)) + RETURN_ERROR(MAJOR, E_INVALID_OPERATION, + ("available for Rx ports only")); + + p_FmPort->p_FmPortDriverParam->forwardReuseIntContext = forwardReuse; + + return E_OK; +} + +t_Error FM_PORT_ConfigMaxFrameLength(t_Handle h_FmPort, uint16_t length) +{ + t_FmPort *p_FmPort = (t_FmPort*)h_FmPort; + + SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_FmPort->p_FmPortDriverParam, E_INVALID_HANDLE); + + p_FmPort->maxFrameLength = length; + + return E_OK; +} + +#ifdef FM_HEAVY_TRAFFIC_HANG_ERRATA_FMAN_A005669 +t_Error FM_PORT_ConfigBCBWorkaround(t_Handle h_FmPort) +{ + t_FmPort *p_FmPort = (t_FmPort*)h_FmPort; + + SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_FmPort->p_FmPortDriverParam, E_INVALID_HANDLE); + + p_FmPort->p_FmPortDriverParam->bcbWorkaround = TRUE; + + return E_OK; +} +#endif /* FM_HEAVY_TRAFFIC_HANG_ERRATA_FMAN_A005669 */ + +/****************************************************/ +/* Hidden-DEBUG Only API */ +/****************************************************/ + +t_Error FM_PORT_ConfigTxFifoMinFillLevel(t_Handle h_FmPort, + uint32_t minFillLevel) +{ + t_FmPort *p_FmPort = (t_FmPort*)h_FmPort; + + SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_FmPort->p_FmPortDriverParam, E_INVALID_HANDLE); + if ((p_FmPort->portType != e_FM_PORT_TYPE_TX_10G) + && (p_FmPort->portType != e_FM_PORT_TYPE_TX)) + RETURN_ERROR(MAJOR, E_INVALID_OPERATION, + ("available for Tx ports only")); + + p_FmPort->p_FmPortDriverParam->dfltCfg.tx_fifo_min_level = minFillLevel; + + return E_OK; +} + +t_Error FM_PORT_ConfigFifoDeqPipelineDepth(t_Handle h_FmPort, + uint8_t deqPipelineDepth) +{ + t_FmPort *p_FmPort = (t_FmPort*)h_FmPort; + + SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_FmPort->p_FmPortDriverParam, E_INVALID_HANDLE); + + if ((p_FmPort->portType == e_FM_PORT_TYPE_RX_10G) + || (p_FmPort->portType == e_FM_PORT_TYPE_RX)) + RETURN_ERROR(MAJOR, E_INVALID_OPERATION, + ("Not available for Rx ports")); + + if (p_FmPort->imEn) + RETURN_ERROR(MAJOR, E_INVALID_OPERATION, + ("Not available for IM ports!")); + + p_FmPort->p_FmPortDriverParam->dfltCfg.tx_fifo_deq_pipeline_depth = + deqPipelineDepth; + + return E_OK; +} + +t_Error FM_PORT_ConfigTxFifoLowComfLevel(t_Handle h_FmPort, + uint32_t fifoLowComfLevel) +{ + t_FmPort *p_FmPort = (t_FmPort*)h_FmPort; + + SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_FmPort->p_FmPortDriverParam, E_INVALID_HANDLE); + if ((p_FmPort->portType != e_FM_PORT_TYPE_TX_10G) + && (p_FmPort->portType != e_FM_PORT_TYPE_TX)) + RETURN_ERROR(MAJOR, E_INVALID_OPERATION, + ("available for Tx ports only")); + + p_FmPort->p_FmPortDriverParam->dfltCfg.tx_fifo_low_comf_level = + fifoLowComfLevel; + + return E_OK; +} + +t_Error FM_PORT_ConfigRxFifoThreshold(t_Handle h_FmPort, uint32_t fifoThreshold) +{ + t_FmPort *p_FmPort = (t_FmPort*)h_FmPort; + + SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_FmPort->p_FmPortDriverParam, E_INVALID_HANDLE); + if ((p_FmPort->portType != e_FM_PORT_TYPE_RX_10G) + && (p_FmPort->portType != e_FM_PORT_TYPE_RX)) + RETURN_ERROR(MAJOR, E_INVALID_OPERATION, + ("available for Rx ports only")); + + p_FmPort->p_FmPortDriverParam->dfltCfg.rx_fifo_thr = fifoThreshold; + + return E_OK; +} + +t_Error FM_PORT_ConfigRxFifoPriElevationLevel(t_Handle h_FmPort, + uint32_t priElevationLevel) +{ + t_FmPort *p_FmPort = (t_FmPort*)h_FmPort; + + SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_FmPort->p_FmPortDriverParam, E_INVALID_HANDLE); + if ((p_FmPort->portType != e_FM_PORT_TYPE_RX_10G) + && (p_FmPort->portType != e_FM_PORT_TYPE_RX)) + RETURN_ERROR(MAJOR, E_INVALID_OPERATION, + ("available for Rx ports only")); + + p_FmPort->p_FmPortDriverParam->dfltCfg.rx_pri_elevation = priElevationLevel; + + return E_OK; +} +/****************************************************/ +/* API Run-time Control unit functions */ +/****************************************************/ + +t_Error FM_PORT_SetNumOfOpenDmas(t_Handle h_FmPort, + t_FmPortRsrc *p_NumOfOpenDmas) +{ + t_FmPort *p_FmPort = (t_FmPort*)h_FmPort; + t_Error err; + + SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(!p_FmPort->p_FmPortDriverParam, E_INVALID_HANDLE); + + if ((!p_NumOfOpenDmas->num) || (p_NumOfOpenDmas->num > MAX_NUM_OF_DMAS)) + RETURN_ERROR( MAJOR, E_INVALID_VALUE, + ("openDmas-num can't be larger than %d", MAX_NUM_OF_DMAS)); + if (p_NumOfOpenDmas->extra > MAX_NUM_OF_EXTRA_DMAS) + RETURN_ERROR( + MAJOR, + E_INVALID_VALUE, + ("openDmas-extra can't be larger than %d", MAX_NUM_OF_EXTRA_DMAS)); + err = FmSetNumOfOpenDmas(p_FmPort->h_Fm, p_FmPort->hardwarePortId, + (uint8_t*)&p_NumOfOpenDmas->num, + (uint8_t*)&p_NumOfOpenDmas->extra, FALSE); + if (err) + RETURN_ERROR(MAJOR, err, NO_MSG); + + memcpy(&p_FmPort->openDmas, p_NumOfOpenDmas, sizeof(t_FmPortRsrc)); + + return E_OK; +} + +t_Error FM_PORT_SetNumOfTasks(t_Handle h_FmPort, t_FmPortRsrc *p_NumOfTasks) +{ + t_FmPort *p_FmPort = (t_FmPort*)h_FmPort; + t_Error err; + + SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(!p_FmPort->p_FmPortDriverParam, E_INVALID_HANDLE); + + /* only driver uses host command port, so ASSERT rather than RETURN_ERROR */ + ASSERT_COND(p_FmPort->portType != e_FM_PORT_TYPE_OH_HOST_COMMAND); + + if ((!p_NumOfTasks->num) || (p_NumOfTasks->num > MAX_NUM_OF_TASKS)) + RETURN_ERROR( + MAJOR, E_INVALID_VALUE, + ("NumOfTasks-num can't be larger than %d", MAX_NUM_OF_TASKS)); + if (p_NumOfTasks->extra > MAX_NUM_OF_EXTRA_TASKS) + RETURN_ERROR( + MAJOR, + E_INVALID_VALUE, + ("NumOfTasks-extra can't be larger than %d", MAX_NUM_OF_EXTRA_TASKS)); + + err = FmSetNumOfTasks(p_FmPort->h_Fm, p_FmPort->hardwarePortId, + (uint8_t*)&p_NumOfTasks->num, + (uint8_t*)&p_NumOfTasks->extra, FALSE); + if (err) + RETURN_ERROR(MAJOR, err, NO_MSG); + + /* update driver's struct */ + memcpy(&p_FmPort->tasks, p_NumOfTasks, sizeof(t_FmPortRsrc)); + return E_OK; +} + +t_Error FM_PORT_SetSizeOfFifo(t_Handle h_FmPort, t_FmPortRsrc *p_SizeOfFifo) +{ + t_FmPort *p_FmPort = (t_FmPort*)h_FmPort; + t_Error err; + + SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(!p_FmPort->p_FmPortDriverParam, E_INVALID_HANDLE); + + if (!p_SizeOfFifo->num || (p_SizeOfFifo->num > MAX_PORT_FIFO_SIZE)) + RETURN_ERROR( + MAJOR, + E_INVALID_VALUE, + ("SizeOfFifo-num has to be in the range of 256 - %d", MAX_PORT_FIFO_SIZE)); + if (p_SizeOfFifo->num % BMI_FIFO_UNITS) + RETURN_ERROR( + MAJOR, E_INVALID_VALUE, + ("SizeOfFifo-num has to be divisible by %d", BMI_FIFO_UNITS)); + if ((p_FmPort->portType == e_FM_PORT_TYPE_RX) + || (p_FmPort->portType == e_FM_PORT_TYPE_RX_10G)) + { + /* extra FIFO size (allowed only to Rx ports) */ + if (p_SizeOfFifo->extra % BMI_FIFO_UNITS) + RETURN_ERROR( + MAJOR, + E_INVALID_VALUE, + ("SizeOfFifo-extra has to be divisible by %d", BMI_FIFO_UNITS)); + } + else + if (p_SizeOfFifo->extra) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, + (" No SizeOfFifo-extra for non Rx ports")); + + memcpy(&p_FmPort->fifoBufs, p_SizeOfFifo, sizeof(t_FmPortRsrc)); + + /* we do not change user's parameter */ + err = VerifySizeOfFifo(p_FmPort); + if (err) + RETURN_ERROR(MAJOR, err, NO_MSG); + + err = FmSetSizeOfFifo(p_FmPort->h_Fm, p_FmPort->hardwarePortId, + &p_SizeOfFifo->num, &p_SizeOfFifo->extra, FALSE); + if (err) + RETURN_ERROR(MAJOR, err, NO_MSG); + + return E_OK; +} + +uint32_t FM_PORT_GetBufferDataOffset(t_Handle h_FmPort) +{ + t_FmPort *p_FmPort = (t_FmPort*)h_FmPort; + + SANITY_CHECK_RETURN_VALUE(p_FmPort, E_INVALID_HANDLE, 0); + SANITY_CHECK_RETURN_VALUE(!p_FmPort->p_FmPortDriverParam, E_INVALID_STATE, + 0); + + return p_FmPort->bufferOffsets.dataOffset; +} + +uint8_t * FM_PORT_GetBufferICInfo(t_Handle h_FmPort, char *p_Data) +{ + t_FmPort *p_FmPort = (t_FmPort*)h_FmPort; + + SANITY_CHECK_RETURN_VALUE(p_FmPort, E_INVALID_HANDLE, NULL); + SANITY_CHECK_RETURN_VALUE(!p_FmPort->p_FmPortDriverParam, E_INVALID_STATE, + NULL); + + if (p_FmPort->bufferOffsets.pcdInfoOffset == ILLEGAL_BASE) + return NULL; + + return (uint8_t *)PTR_MOVE(p_Data, p_FmPort->bufferOffsets.pcdInfoOffset); +} + +t_FmPrsResult * FM_PORT_GetBufferPrsResult(t_Handle h_FmPort, char *p_Data) +{ + t_FmPort *p_FmPort = (t_FmPort*)h_FmPort; + + SANITY_CHECK_RETURN_VALUE(p_FmPort, E_INVALID_HANDLE, NULL); + SANITY_CHECK_RETURN_VALUE(!p_FmPort->p_FmPortDriverParam, E_INVALID_STATE, + NULL); + + if (p_FmPort->bufferOffsets.prsResultOffset == ILLEGAL_BASE) + return NULL; + + return (t_FmPrsResult *)PTR_MOVE(p_Data, p_FmPort->bufferOffsets.prsResultOffset); +} + +uint64_t * FM_PORT_GetBufferTimeStamp(t_Handle h_FmPort, char *p_Data) +{ + t_FmPort *p_FmPort = (t_FmPort*)h_FmPort; + + SANITY_CHECK_RETURN_VALUE(p_FmPort, E_INVALID_HANDLE, NULL); + SANITY_CHECK_RETURN_VALUE(!p_FmPort->p_FmPortDriverParam, E_INVALID_STATE, + NULL); + + if (p_FmPort->bufferOffsets.timeStampOffset == ILLEGAL_BASE) + return NULL; + + return (uint64_t *)PTR_MOVE(p_Data, p_FmPort->bufferOffsets.timeStampOffset); +} + +uint8_t * FM_PORT_GetBufferHashResult(t_Handle h_FmPort, char *p_Data) +{ + t_FmPort *p_FmPort = (t_FmPort*)h_FmPort; + + SANITY_CHECK_RETURN_VALUE(p_FmPort, E_INVALID_HANDLE, NULL); + SANITY_CHECK_RETURN_VALUE(!p_FmPort->p_FmPortDriverParam, E_INVALID_STATE, + NULL); + + if (p_FmPort->bufferOffsets.hashResultOffset == ILLEGAL_BASE) + return NULL; + + return (uint8_t *)PTR_MOVE(p_Data, p_FmPort->bufferOffsets.hashResultOffset); +} + +t_Error FM_PORT_Disable(t_Handle h_FmPort) +{ + t_FmPort *p_FmPort = (t_FmPort*)h_FmPort; + int err; + + SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(!p_FmPort->p_FmPortDriverParam, E_INVALID_STATE); + + if (p_FmPort->imEn) + FmPortImDisable(p_FmPort); + + err = fman_port_disable(&p_FmPort->port); + if (err == -EBUSY) + { + DBG(WARNING, ("%s: BMI or QMI is Busy. Port forced down", + p_FmPort->name)); + } + else + if (err != 0) + { + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("fman_port_disable")); + } + + p_FmPort->enabled = FALSE; + + return E_OK; +} + +t_Error FM_PORT_Enable(t_Handle h_FmPort) +{ + t_FmPort *p_FmPort = (t_FmPort*)h_FmPort; + int err; + + SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(!p_FmPort->p_FmPortDriverParam, E_INVALID_STATE); + + /* Used by FM_PORT_Free routine as indication + if to disable port. Thus set it to TRUE prior + to enabling itself. This way if part of enable + process fails there will be still things + to disable during Free. For example, if BMI + enable succeeded but QMI failed, still BMI + needs to be disabled by Free. */ + p_FmPort->enabled = TRUE; + + if (p_FmPort->imEn) + FmPortImEnable(p_FmPort); + + err = fman_port_enable(&p_FmPort->port); + if (err != 0) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("fman_port_enable")); + + return E_OK; +} + +t_Error FM_PORT_SetRateLimit(t_Handle h_FmPort, t_FmPortRateLimit *p_RateLimit) +{ + t_FmPort *p_FmPort = (t_FmPort*)h_FmPort; + uint8_t factor, countUnitBit; + uint16_t baseGran; + struct fman_port_rate_limiter params; + int err; + + SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(!p_FmPort->p_FmPortDriverParam, E_INVALID_HANDLE); + + switch (p_FmPort->portType) + { + case (e_FM_PORT_TYPE_TX_10G): + case (e_FM_PORT_TYPE_TX): + baseGran = BMI_RATE_LIMIT_GRAN_TX; + break; + case (e_FM_PORT_TYPE_OH_OFFLINE_PARSING): + baseGran = BMI_RATE_LIMIT_GRAN_OP; + break; + default: + RETURN_ERROR( MAJOR, E_INVALID_OPERATION, + ("available for Tx and Offline parsing ports only")); + } + + countUnitBit = (uint8_t)FmGetTimeStampScale(p_FmPort->h_Fm); /* TimeStamp per nano seconds units */ + /* normally, we use 1 usec as the reference count */ + factor = 1; + /* if ratelimit is too small for a 1usec factor, multiply the factor */ + while (p_RateLimit->rateLimit < baseGran / factor) + { + if (countUnitBit == 31) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("Rate limit is too small")); + + countUnitBit++; + factor <<= 1; + } + /* if ratelimit is too large for a 1usec factor, it is also larger than max rate*/ + if (p_RateLimit->rateLimit + > ((uint32_t)baseGran * (1 << 10) * (uint32_t)factor)) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("Rate limit is too large")); + + if (!p_RateLimit->maxBurstSize + || (p_RateLimit->maxBurstSize > BMI_RATE_LIMIT_MAX_BURST_SIZE)) + RETURN_ERROR( + MAJOR, + E_INVALID_VALUE, + ("maxBurstSize must be between 1K and %dk", BMI_RATE_LIMIT_MAX_BURST_SIZE)); + + params.count_1micro_bit = (uint8_t)FmGetTimeStampScale(p_FmPort->h_Fm); + params.high_burst_size_gran = FALSE; + params.burst_size = p_RateLimit->maxBurstSize; + params.rate = p_RateLimit->rateLimit; + params.rate_factor = E_FMAN_PORT_RATE_DOWN_NONE; + + if (p_FmPort->portType == e_FM_PORT_TYPE_OH_OFFLINE_PARSING) + { +#ifndef FM_NO_ADVANCED_RATE_LIMITER + + if ((p_FmPort->fmRevInfo.majorRev == 4) + || (p_FmPort->fmRevInfo.majorRev >= 6)) + { + params.high_burst_size_gran = TRUE; + } + else +#endif /* ! FM_NO_ADVANCED_RATE_LIMITER */ + { + if (p_RateLimit->rateLimitDivider + != e_FM_PORT_DUAL_RATE_LIMITER_NONE) + RETURN_ERROR(MAJOR, E_NOT_SUPPORTED, + ("FM_PORT_ConfigDualRateLimitScaleDown")); + + if (p_RateLimit->maxBurstSize % 1000) + { + p_RateLimit->maxBurstSize = + (uint16_t)((p_RateLimit->maxBurstSize / 1000) + 1); + DBG(WARNING, ("rateLimit.maxBurstSize rounded up to %d", (p_RateLimit->maxBurstSize/1000+1)*1000)); + } + else + p_RateLimit->maxBurstSize = (uint16_t)(p_RateLimit->maxBurstSize + / 1000); + } + params.rate_factor = + (enum fman_port_rate_limiter_scale_down)p_RateLimit->rateLimitDivider; + params.burst_size = p_RateLimit->maxBurstSize; + } + + err = fman_port_set_rate_limiter(&p_FmPort->port, ¶ms); + if (err != 0) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("fman_port_set_rate_limiter")); + + return E_OK; +} + +t_Error FM_PORT_DeleteRateLimit(t_Handle h_FmPort) +{ + t_FmPort *p_FmPort = (t_FmPort*)h_FmPort; + int err; + + SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(!p_FmPort->p_FmPortDriverParam, E_INVALID_HANDLE); + + if ((p_FmPort->portType == e_FM_PORT_TYPE_RX_10G) + || (p_FmPort->portType == e_FM_PORT_TYPE_RX) + || (p_FmPort->portType == e_FM_PORT_TYPE_OH_HOST_COMMAND)) + RETURN_ERROR( MAJOR, E_INVALID_OPERATION, + ("available for Tx and Offline parsing ports only")); + + err = fman_port_delete_rate_limiter(&p_FmPort->port); + if (err != 0) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("fman_port_set_rate_limiter")); + return E_OK; +} + +t_Error FM_PORT_SetPfcPrioritiesMappingToQmanWQ(t_Handle h_FmPort, uint8_t prio, + uint8_t wq) +{ + t_FmPort *p_FmPort = (t_FmPort*)h_FmPort; + uint32_t tmpReg; + uint32_t wqTmpReg; + + SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(!p_FmPort->p_FmPortDriverParam, E_INVALID_STATE); + + if ((p_FmPort->portType != e_FM_PORT_TYPE_TX) + && (p_FmPort->portType != e_FM_PORT_TYPE_TX_10G)) + RETURN_ERROR(MAJOR, E_INVALID_OPERATION, + ("PFC mapping is available for Tx ports only")); + + if (prio > 7) + RETURN_ERROR(MAJOR, E_NOT_IN_RANGE, + ("PFC priority (%d) is out of range (0-7)", prio)); + if (wq > 7) + RETURN_ERROR(MAJOR, E_NOT_IN_RANGE, + ("WQ (%d) is out of range (0-7)", wq)); + + tmpReg = GET_UINT32(p_FmPort->p_FmPortBmiRegs->txPortBmiRegs.fmbm_tpfcm[0]); + tmpReg &= ~(0xf << ((7 - prio) * 4)); + wqTmpReg = ((uint32_t)wq << ((7 - prio) * 4)); + tmpReg |= wqTmpReg; + + WRITE_UINT32(p_FmPort->p_FmPortBmiRegs->txPortBmiRegs.fmbm_tpfcm[0], + tmpReg); + + return E_OK; +} + +t_Error FM_PORT_SetFrameQueueCounters(t_Handle h_FmPort, bool enable) +{ + t_FmPort *p_FmPort = (t_FmPort*)h_FmPort; + + SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(!p_FmPort->p_FmPortDriverParam, E_INVALID_STATE); + + fman_port_set_queue_cnt_mode(&p_FmPort->port, enable); + + return E_OK; +} + +t_Error FM_PORT_SetPerformanceCounters(t_Handle h_FmPort, bool enable) +{ + t_FmPort *p_FmPort = (t_FmPort*)h_FmPort; + int err; + + SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(!p_FmPort->p_FmPortDriverParam, E_INVALID_STATE); + + err = fman_port_set_perf_cnt_mode(&p_FmPort->port, enable); + if (err != 0) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("fman_port_set_perf_cnt_mode")); + return E_OK; +} + +t_Error FM_PORT_SetPerformanceCountersParams( + t_Handle h_FmPort, t_FmPortPerformanceCnt *p_FmPortPerformanceCnt) +{ + t_FmPort *p_FmPort = (t_FmPort*)h_FmPort; + struct fman_port_perf_cnt_params params; + int err; + + SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE); + + /* check parameters */ + if (!p_FmPortPerformanceCnt->taskCompVal + || (p_FmPortPerformanceCnt->taskCompVal > p_FmPort->tasks.num)) + RETURN_ERROR( + MAJOR, + E_INVALID_VALUE, + ("taskCompVal (%d) has to be in the range of 1 - %d (current value)!", p_FmPortPerformanceCnt->taskCompVal, p_FmPort->tasks.num)); + if (!p_FmPortPerformanceCnt->dmaCompVal + || (p_FmPortPerformanceCnt->dmaCompVal > p_FmPort->openDmas.num)) + RETURN_ERROR( + MAJOR, + E_INVALID_VALUE, + ("dmaCompVal (%d) has to be in the range of 1 - %d (current value)!", p_FmPortPerformanceCnt->dmaCompVal, p_FmPort->openDmas.num)); + if (!p_FmPortPerformanceCnt->fifoCompVal + || (p_FmPortPerformanceCnt->fifoCompVal > p_FmPort->fifoBufs.num)) + RETURN_ERROR( + MAJOR, + E_INVALID_VALUE, + ("fifoCompVal (%d) has to be in the range of 256 - %d (current value)!", p_FmPortPerformanceCnt->fifoCompVal, p_FmPort->fifoBufs.num)); + if (p_FmPortPerformanceCnt->fifoCompVal % BMI_FIFO_UNITS) + RETURN_ERROR( + MAJOR, + E_INVALID_VALUE, + ("fifoCompVal (%d) has to be divisible by %d", p_FmPortPerformanceCnt->fifoCompVal, BMI_FIFO_UNITS)); + + switch (p_FmPort->portType) + { + case (e_FM_PORT_TYPE_RX_10G): + case (e_FM_PORT_TYPE_RX): + if (!p_FmPortPerformanceCnt->queueCompVal + || (p_FmPortPerformanceCnt->queueCompVal + > MAX_PERFORMANCE_RX_QUEUE_COMP)) + RETURN_ERROR( + MAJOR, + E_INVALID_VALUE, + ("performanceCnt.queueCompVal for Rx has to be in the range of 1 - %d", MAX_PERFORMANCE_RX_QUEUE_COMP)); + break; + case (e_FM_PORT_TYPE_TX_10G): + case (e_FM_PORT_TYPE_TX): + if (!p_FmPortPerformanceCnt->queueCompVal + || (p_FmPortPerformanceCnt->queueCompVal + > MAX_PERFORMANCE_TX_QUEUE_COMP)) + RETURN_ERROR( + MAJOR, + E_INVALID_VALUE, + ("performanceCnt.queueCompVal for Tx has to be in the range of 1 - %d", MAX_PERFORMANCE_TX_QUEUE_COMP)); + break; + case (e_FM_PORT_TYPE_OH_OFFLINE_PARSING): + case (e_FM_PORT_TYPE_OH_HOST_COMMAND): + if (p_FmPortPerformanceCnt->queueCompVal) + RETURN_ERROR( + MAJOR, + E_INVALID_VALUE, + ("performanceCnt.queueCompVal is not relevant for H/O ports.")); + break; + default: + RETURN_ERROR(MAJOR, E_INVALID_STATE, ("Invalid port type")); + } + + params.task_val = p_FmPortPerformanceCnt->taskCompVal; + params.queue_val = p_FmPortPerformanceCnt->queueCompVal; + params.dma_val = p_FmPortPerformanceCnt->dmaCompVal; + params.fifo_val = p_FmPortPerformanceCnt->fifoCompVal; + + err = fman_port_set_perf_cnt_params(&p_FmPort->port, ¶ms); + if (err != 0) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("fman_port_set_perf_cnt_params")); + + return E_OK; +} + +t_Error FM_PORT_AnalyzePerformanceParams(t_Handle h_FmPort) +{ + t_FmPort *p_FmPort = (t_FmPort*)h_FmPort; + t_FmPortPerformanceCnt currParams, savedParams; + t_Error err; + bool underTest, failed = FALSE; + + SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE); + + XX_Print("Analyzing Performance parameters for port (type %d, id%d)\n", + p_FmPort->portType, p_FmPort->portId); + + currParams.taskCompVal = (uint8_t)p_FmPort->tasks.num; + if ((p_FmPort->portType == e_FM_PORT_TYPE_OH_OFFLINE_PARSING) + || (p_FmPort->portType == e_FM_PORT_TYPE_OH_HOST_COMMAND)) + currParams.queueCompVal = 0; + else + currParams.queueCompVal = 1; + currParams.dmaCompVal = (uint8_t)p_FmPort->openDmas.num; + currParams.fifoCompVal = p_FmPort->fifoBufs.num; + + FM_PORT_SetPerformanceCounters(p_FmPort, FALSE); + ClearPerfCnts(p_FmPort); + if ((err = FM_PORT_SetPerformanceCountersParams(p_FmPort, &currParams)) + != E_OK) + RETURN_ERROR(MAJOR, err, NO_MSG); + FM_PORT_SetPerformanceCounters(p_FmPort, TRUE); + XX_UDelay(1000000); + FM_PORT_SetPerformanceCounters(p_FmPort, FALSE); + if (FM_PORT_GetCounter(p_FmPort, e_FM_PORT_COUNTERS_TASK_UTIL)) + { + XX_Print( + "Max num of defined port tasks (%d) utilized - Please enlarge\n", + p_FmPort->tasks.num); + failed = TRUE; + } + if (FM_PORT_GetCounter(p_FmPort, e_FM_PORT_COUNTERS_DMA_UTIL)) + { + XX_Print( + "Max num of defined port openDmas (%d) utilized - Please enlarge\n", + p_FmPort->openDmas.num); + failed = TRUE; + } + if (FM_PORT_GetCounter(p_FmPort, e_FM_PORT_COUNTERS_FIFO_UTIL)) + { + XX_Print( + "Max size of defined port fifo (%d) utilized - Please enlarge\n", + p_FmPort->fifoBufs.num); + failed = TRUE; + } + if (failed) + RETURN_ERROR(MAJOR, E_INVALID_STATE, NO_MSG); + + memset(&savedParams, 0, sizeof(savedParams)); + while (TRUE) + { + underTest = FALSE; + if ((currParams.taskCompVal != 1) && !savedParams.taskCompVal) + { + currParams.taskCompVal--; + underTest = TRUE; + } + if ((currParams.dmaCompVal != 1) && !savedParams.dmaCompVal) + { + currParams.dmaCompVal--; + underTest = TRUE; + } + if ((currParams.fifoCompVal != BMI_FIFO_UNITS) + && !savedParams.fifoCompVal) + { + currParams.fifoCompVal -= BMI_FIFO_UNITS; + underTest = TRUE; + } + if (!underTest) + break; + + ClearPerfCnts(p_FmPort); + if ((err = FM_PORT_SetPerformanceCountersParams(p_FmPort, &currParams)) + != E_OK) + RETURN_ERROR(MAJOR, err, NO_MSG); + FM_PORT_SetPerformanceCounters(p_FmPort, TRUE); + XX_UDelay(1000000); + FM_PORT_SetPerformanceCounters(p_FmPort, FALSE); + + if (!savedParams.taskCompVal + && FM_PORT_GetCounter(p_FmPort, e_FM_PORT_COUNTERS_TASK_UTIL)) + savedParams.taskCompVal = (uint8_t)(currParams.taskCompVal + 2); + if (!savedParams.dmaCompVal + && FM_PORT_GetCounter(p_FmPort, e_FM_PORT_COUNTERS_DMA_UTIL)) + savedParams.dmaCompVal = (uint8_t)(currParams.dmaCompVal + 2); + if (!savedParams.fifoCompVal + && FM_PORT_GetCounter(p_FmPort, e_FM_PORT_COUNTERS_FIFO_UTIL)) + savedParams.fifoCompVal = currParams.fifoCompVal + + (2 * BMI_FIFO_UNITS); + } + + XX_Print("best vals: tasks %d, dmas %d, fifos %d\n", + savedParams.taskCompVal, savedParams.dmaCompVal, + savedParams.fifoCompVal); + return E_OK; +} + +t_Error FM_PORT_SetStatisticsCounters(t_Handle h_FmPort, bool enable) +{ + t_FmPort *p_FmPort = (t_FmPort*)h_FmPort; + int err; + + SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(!p_FmPort->p_FmPortDriverParam, E_INVALID_STATE); + + err = fman_port_set_stats_cnt_mode(&p_FmPort->port, enable); + if (err != 0) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("fman_port_set_stats_cnt_mode")); + return E_OK; +} + +t_Error FM_PORT_SetErrorsRoute(t_Handle h_FmPort, fmPortFrameErrSelect_t errs) +{ + t_FmPort *p_FmPort = (t_FmPort*)h_FmPort; + volatile uint32_t *p_ErrDiscard = NULL; + int err; + + UNUSED(p_ErrDiscard); + err = fman_port_set_err_mask(&p_FmPort->port, (uint32_t)errs); + if (err != 0) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("fman_port_set_err_mask")); + +#ifdef FM_ERROR_VSP_NO_MATCH_SW006 + if (p_FmPort->fmRevInfo.majorRev >= 6) + { + t_FmPcdCtrlParamsPage *p_ParamsPage; + + FmPortSetGprFunc(p_FmPort, e_FM_PORT_GPR_MURAM_PAGE, + (void**)&p_ParamsPage); + ASSERT_COND(p_ParamsPage); + switch (p_FmPort->portType) + { + case (e_FM_PORT_TYPE_RX_10G): + case (e_FM_PORT_TYPE_RX): + p_ErrDiscard = + &p_FmPort->p_FmPortBmiRegs->rxPortBmiRegs.fmbm_rfsdm; + break; + case (e_FM_PORT_TYPE_OH_OFFLINE_PARSING): + p_ErrDiscard = + &p_FmPort->p_FmPortBmiRegs->ohPortBmiRegs.fmbm_ofsdm; + break; + default: + RETURN_ERROR( + MAJOR, E_INVALID_OPERATION, + ("available for Rx and offline parsing ports only")); + } + WRITE_UINT32(p_ParamsPage->errorsDiscardMask, + GET_UINT32(*p_ErrDiscard) | errs); + } +#endif /* FM_ERROR_VSP_NO_MATCH_SW006 */ + + return E_OK; +} + +t_Error FM_PORT_SetAllocBufCounter(t_Handle h_FmPort, uint8_t poolId, + bool enable) +{ + t_FmPort *p_FmPort = (t_FmPort*)h_FmPort; + int err; + + SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(poolId<BM_MAX_NUM_OF_POOLS, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(!p_FmPort->p_FmPortDriverParam, E_INVALID_STATE); + + if ((p_FmPort->portType != e_FM_PORT_TYPE_RX_10G) + && (p_FmPort->portType != e_FM_PORT_TYPE_RX)) + RETURN_ERROR(MAJOR, E_INVALID_OPERATION, + ("available for Rx ports only")); + + err = fman_port_set_bpool_cnt_mode(&p_FmPort->port, poolId, enable); + if (err != 0) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("fman_port_set_bpool_cnt_mode")); + return E_OK; +} + +t_Error FM_PORT_GetBmiCounters(t_Handle h_FmPort, t_FmPortBmiStats *p_BmiStats) +{ + t_FmPort *p_FmPort = (t_FmPort*)h_FmPort; + + if ((p_FmPort->portType == e_FM_PORT_TYPE_RX) + || (p_FmPort->portType == e_FM_PORT_TYPE_RX_10G)){ + p_BmiStats->cntCycle = + FM_PORT_GetCounter(h_FmPort, e_FM_PORT_COUNTERS_CYCLE); + /* fmbm_rccn */ + p_BmiStats->cntTaskUtil = + FM_PORT_GetCounter(h_FmPort, e_FM_PORT_COUNTERS_TASK_UTIL); + /* fmbm_rtuc */ + p_BmiStats->cntQueueUtil = + FM_PORT_GetCounter(h_FmPort, e_FM_PORT_COUNTERS_QUEUE_UTIL); + /* fmbm_rrquc */ + p_BmiStats->cntDmaUtil = + FM_PORT_GetCounter(h_FmPort, e_FM_PORT_COUNTERS_DMA_UTIL); + /* fmbm_rduc */ + p_BmiStats->cntFifoUtil = + FM_PORT_GetCounter(h_FmPort, e_FM_PORT_COUNTERS_FIFO_UTIL); + /* fmbm_rfuc */ + p_BmiStats->cntRxPauseActivation = + FM_PORT_GetCounter(h_FmPort, e_FM_PORT_COUNTERS_RX_PAUSE_ACTIVATION); + /* fmbm_rpac */ + p_BmiStats->cntFrame = + FM_PORT_GetCounter(h_FmPort, e_FM_PORT_COUNTERS_FRAME); + /* fmbm_rfrc */ + p_BmiStats->cntDiscardFrame = + FM_PORT_GetCounter(h_FmPort, e_FM_PORT_COUNTERS_DISCARD_FRAME); + /* fmbm_rfdc */ + p_BmiStats->cntDeallocBuf = + FM_PORT_GetCounter(h_FmPort, e_FM_PORT_COUNTERS_DEALLOC_BUF); + /* fmbm_rbdc */ + p_BmiStats->cntRxBadFrame = + FM_PORT_GetCounter(h_FmPort, e_FM_PORT_COUNTERS_RX_BAD_FRAME); + /* fmbm_rfbc */ + p_BmiStats->cntRxLargeFrame = + FM_PORT_GetCounter(h_FmPort, e_FM_PORT_COUNTERS_RX_LARGE_FRAME); + /* fmbm_rlfc */ + p_BmiStats->cntRxFilterFrame = + FM_PORT_GetCounter(h_FmPort, e_FM_PORT_COUNTERS_RX_FILTER_FRAME); + /* fmbm_rffc */ + p_BmiStats->cntRxListDmaErr = + FM_PORT_GetCounter(h_FmPort, e_FM_PORT_COUNTERS_RX_LIST_DMA_ERR); + /* fmbm_rfldec */ + p_BmiStats->cntRxOutOfBuffersDiscard = + FM_PORT_GetCounter(h_FmPort, e_FM_PORT_COUNTERS_RX_OUT_OF_BUFFERS_DISCARD); + /* fmbm_rodc */ + p_BmiStats->cntWredDiscard = 0; + p_BmiStats->cntLengthErr = 0; + p_BmiStats->cntUnsupportedFormat = 0; + } + else if ((p_FmPort->portType == e_FM_PORT_TYPE_TX) + || (p_FmPort->portType == e_FM_PORT_TYPE_TX_10G)){ + p_BmiStats->cntCycle = + FM_PORT_GetCounter(h_FmPort, e_FM_PORT_COUNTERS_CYCLE); + /* fmbm_tccn */ + p_BmiStats->cntTaskUtil = + FM_PORT_GetCounter(h_FmPort, e_FM_PORT_COUNTERS_TASK_UTIL); + /* fmbm_ttuc */ + p_BmiStats->cntQueueUtil = + FM_PORT_GetCounter(h_FmPort, e_FM_PORT_COUNTERS_QUEUE_UTIL); + /* fmbm_ttcquc */ + p_BmiStats->cntDmaUtil = + FM_PORT_GetCounter(h_FmPort, e_FM_PORT_COUNTERS_DMA_UTIL); + /* fmbm_tduc */ + p_BmiStats->cntFifoUtil = + FM_PORT_GetCounter(h_FmPort, e_FM_PORT_COUNTERS_FIFO_UTIL); + /* fmbm_tfuc */ + p_BmiStats->cntRxPauseActivation = 0; + p_BmiStats->cntFrame = + FM_PORT_GetCounter(h_FmPort, e_FM_PORT_COUNTERS_FRAME); + /* fmbm_tfrc */ + p_BmiStats->cntDiscardFrame = + FM_PORT_GetCounter(h_FmPort, e_FM_PORT_COUNTERS_DISCARD_FRAME); + /* fmbm_tfdc */ + p_BmiStats->cntDeallocBuf = + FM_PORT_GetCounter(h_FmPort, e_FM_PORT_COUNTERS_DEALLOC_BUF); + /* fmbm_tbdc */ + p_BmiStats->cntRxBadFrame = 0; + p_BmiStats->cntRxLargeFrame = 0; + p_BmiStats->cntRxFilterFrame = 0; + p_BmiStats->cntRxListDmaErr = 0; + p_BmiStats->cntRxOutOfBuffersDiscard = 0; + p_BmiStats->cntWredDiscard = 0; + p_BmiStats->cntLengthErr = + FM_PORT_GetCounter(h_FmPort, e_FM_PORT_COUNTERS_LENGTH_ERR); + /* fmbm_tfledc */ + p_BmiStats->cntUnsupportedFormat = + FM_PORT_GetCounter(h_FmPort, e_FM_PORT_COUNTERS_UNSUPPRTED_FORMAT); + /* fmbm_tfufdc */ + } + else if (p_FmPort->portType == e_FM_PORT_TYPE_OH_OFFLINE_PARSING) { + p_BmiStats->cntCycle = + FM_PORT_GetCounter(h_FmPort, e_FM_PORT_COUNTERS_CYCLE); + /* fmbm_occn */ + p_BmiStats->cntTaskUtil = + FM_PORT_GetCounter(h_FmPort, e_FM_PORT_COUNTERS_TASK_UTIL); + /* fmbm_otuc */ + p_BmiStats->cntQueueUtil = 0; + p_BmiStats->cntDmaUtil = + FM_PORT_GetCounter(h_FmPort, e_FM_PORT_COUNTERS_DMA_UTIL); + /* fmbm_oduc */ + p_BmiStats->cntFifoUtil = + FM_PORT_GetCounter(h_FmPort, e_FM_PORT_COUNTERS_FIFO_UTIL); + /* fmbm_ofuc*/ + p_BmiStats->cntRxPauseActivation = 0; + p_BmiStats->cntFrame = + FM_PORT_GetCounter(h_FmPort, e_FM_PORT_COUNTERS_FRAME); + /* fmbm_ofrc */ + p_BmiStats->cntDiscardFrame = + FM_PORT_GetCounter(h_FmPort, e_FM_PORT_COUNTERS_DISCARD_FRAME); + /* fmbm_ofdc */ + p_BmiStats->cntDeallocBuf = + FM_PORT_GetCounter(h_FmPort, e_FM_PORT_COUNTERS_DEALLOC_BUF); + /* fmbm_obdc*/ + p_BmiStats->cntRxBadFrame = 0; + p_BmiStats->cntRxLargeFrame = 0; + p_BmiStats->cntRxFilterFrame = + FM_PORT_GetCounter(h_FmPort, e_FM_PORT_COUNTERS_RX_FILTER_FRAME); + /* fmbm_offc */ + p_BmiStats->cntRxListDmaErr = + FM_PORT_GetCounter(h_FmPort, e_FM_PORT_COUNTERS_RX_LIST_DMA_ERR); + /* fmbm_ofldec */ + p_BmiStats->cntRxOutOfBuffersDiscard = + FM_PORT_GetCounter(h_FmPort, e_FM_PORT_COUNTERS_RX_OUT_OF_BUFFERS_DISCARD); + /* fmbm_rodc */ + p_BmiStats->cntWredDiscard = + FM_PORT_GetCounter(h_FmPort, e_FM_PORT_COUNTERS_WRED_DISCARD); + /* fmbm_ofwdc */ + p_BmiStats->cntLengthErr = + FM_PORT_GetCounter(h_FmPort, e_FM_PORT_COUNTERS_LENGTH_ERR); + /* fmbm_ofledc */ + p_BmiStats->cntUnsupportedFormat = + FM_PORT_GetCounter(h_FmPort, e_FM_PORT_COUNTERS_UNSUPPRTED_FORMAT); + /* fmbm_ofufdc */ + } + return E_OK; +} + +uint32_t FM_PORT_GetCounter(t_Handle h_FmPort, e_FmPortCounters counter) +{ + t_FmPort *p_FmPort = (t_FmPort*)h_FmPort; + bool bmiCounter = FALSE; + enum fman_port_stats_counters statsType; + enum fman_port_perf_counters perfType; + enum fman_port_qmi_counters queueType; + bool isStats; + t_Error errCode; + + SANITY_CHECK_RETURN_VALUE(p_FmPort, E_INVALID_HANDLE, 0); + SANITY_CHECK_RETURN_ERROR(!p_FmPort->p_FmPortDriverParam, E_INVALID_STATE); + + switch (counter) + { + case (e_FM_PORT_COUNTERS_DEQ_TOTAL): + case (e_FM_PORT_COUNTERS_DEQ_FROM_DEFAULT): + case (e_FM_PORT_COUNTERS_DEQ_CONFIRM): + /* check that counter is available for the port type */ + if ((p_FmPort->portType == e_FM_PORT_TYPE_RX) + || (p_FmPort->portType == e_FM_PORT_TYPE_RX_10G)) + { + REPORT_ERROR(MINOR, E_INVALID_STATE, + ("Requested counter is not available for Rx ports")); + return 0; + } + bmiCounter = FALSE; + break; + case (e_FM_PORT_COUNTERS_ENQ_TOTAL): + bmiCounter = FALSE; + break; + default: /* BMI counters (or error - will be checked in BMI routine )*/ + bmiCounter = TRUE; + break; + } + + if (bmiCounter) + { + errCode = BmiPortCheckAndGetCounterType(p_FmPort, counter, &statsType, + &perfType, &isStats); + if (errCode != E_OK) + { + REPORT_ERROR(MINOR, errCode, NO_MSG); + return 0; + } + if (isStats) + return fman_port_get_stats_counter(&p_FmPort->port, statsType); + else + return fman_port_get_perf_counter(&p_FmPort->port, perfType); + } + else /* QMI counter */ + { + /* check that counters are enabled */ + if (!(GET_UINT32(p_FmPort->port.qmi_regs->fmqm_pnc) + & QMI_PORT_CFG_EN_COUNTERS)) + + { + REPORT_ERROR(MINOR, E_INVALID_STATE, ("Requested counter was not enabled")); + return 0; + } + + /* Set counter */ + switch (counter) + { + case (e_FM_PORT_COUNTERS_ENQ_TOTAL): + queueType = E_FMAN_PORT_ENQ_TOTAL; + break; + case (e_FM_PORT_COUNTERS_DEQ_TOTAL): + queueType = E_FMAN_PORT_DEQ_TOTAL; + break; + case (e_FM_PORT_COUNTERS_DEQ_FROM_DEFAULT): + queueType = E_FMAN_PORT_DEQ_FROM_DFLT; + break; + case (e_FM_PORT_COUNTERS_DEQ_CONFIRM): + queueType = E_FMAN_PORT_DEQ_CONFIRM; + break; + default: + REPORT_ERROR(MINOR, E_INVALID_STATE, ("Requested counter is not available")); + return 0; + } + + return fman_port_get_qmi_counter(&p_FmPort->port, queueType); + } + + return 0; +} + +t_Error FM_PORT_ModifyCounter(t_Handle h_FmPort, e_FmPortCounters counter, + uint32_t value) +{ + t_FmPort *p_FmPort = (t_FmPort*)h_FmPort; + bool bmiCounter = FALSE; + enum fman_port_stats_counters statsType; + enum fman_port_perf_counters perfType; + enum fman_port_qmi_counters queueType; + bool isStats; + t_Error errCode; + + SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(!p_FmPort->p_FmPortDriverParam, E_INVALID_STATE); + + switch (counter) + { + case (e_FM_PORT_COUNTERS_DEQ_TOTAL): + case (e_FM_PORT_COUNTERS_DEQ_FROM_DEFAULT): + case (e_FM_PORT_COUNTERS_DEQ_CONFIRM): + /* check that counter is available for the port type */ + if ((p_FmPort->portType == e_FM_PORT_TYPE_RX) + || (p_FmPort->portType == e_FM_PORT_TYPE_RX_10G)) + RETURN_ERROR( + MINOR, E_INVALID_STATE, + ("Requested counter is not available for Rx ports")); + /* fall through */ + case (e_FM_PORT_COUNTERS_ENQ_TOTAL): + bmiCounter = FALSE; + break; + default: /* BMI counters (or error - will be checked in BMI routine )*/ + bmiCounter = TRUE; + break; + } + + if (bmiCounter) + { + errCode = BmiPortCheckAndGetCounterType(p_FmPort, counter, &statsType, + &perfType, &isStats); + if (errCode != E_OK) + { + RETURN_ERROR(MINOR, errCode, NO_MSG); + } + if (isStats) + fman_port_set_stats_counter(&p_FmPort->port, statsType, value); + else + fman_port_set_perf_counter(&p_FmPort->port, perfType, value); + } + else /* QMI counter */ + { + /* check that counters are enabled */ + if (!(GET_UINT32(p_FmPort->port.qmi_regs->fmqm_pnc) + & QMI_PORT_CFG_EN_COUNTERS)) + { + RETURN_ERROR(MINOR, E_INVALID_STATE, + ("Requested counter was not enabled")); + } + + /* Set counter */ + switch (counter) + { + case (e_FM_PORT_COUNTERS_ENQ_TOTAL): + queueType = E_FMAN_PORT_ENQ_TOTAL; + break; + case (e_FM_PORT_COUNTERS_DEQ_TOTAL): + queueType = E_FMAN_PORT_DEQ_TOTAL; + break; + case (e_FM_PORT_COUNTERS_DEQ_FROM_DEFAULT): + queueType = E_FMAN_PORT_DEQ_FROM_DFLT; + break; + case (e_FM_PORT_COUNTERS_DEQ_CONFIRM): + queueType = E_FMAN_PORT_DEQ_CONFIRM; + break; + default: + RETURN_ERROR(MAJOR, E_INVALID_STATE, + ("Requested counter is not available")); + } + + fman_port_set_qmi_counter(&p_FmPort->port, queueType, value); + } + + return E_OK; +} + +uint32_t FM_PORT_GetAllocBufCounter(t_Handle h_FmPort, uint8_t poolId) +{ + t_FmPort *p_FmPort = (t_FmPort*)h_FmPort; + + SANITY_CHECK_RETURN_VALUE(p_FmPort, E_INVALID_HANDLE, 0); + SANITY_CHECK_RETURN_ERROR(!p_FmPort->p_FmPortDriverParam, E_INVALID_STATE); + + if ((p_FmPort->portType != e_FM_PORT_TYPE_RX) + && (p_FmPort->portType == e_FM_PORT_TYPE_RX_10G)) + { + REPORT_ERROR(MINOR, E_INVALID_STATE, ("Requested counter is not available for non-Rx ports")); + return 0; + } + return fman_port_get_bpool_counter(&p_FmPort->port, poolId); +} + +t_Error FM_PORT_ModifyAllocBufCounter(t_Handle h_FmPort, uint8_t poolId, + uint32_t value) +{ + t_FmPort *p_FmPort = (t_FmPort *)h_FmPort; + + SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(!p_FmPort->p_FmPortDriverParam, E_INVALID_STATE); + + if ((p_FmPort->portType != e_FM_PORT_TYPE_RX) + && (p_FmPort->portType == e_FM_PORT_TYPE_RX_10G)) + RETURN_ERROR( MINOR, E_INVALID_STATE, + ("Requested counter is not available for non-Rx ports")); + + fman_port_set_bpool_counter(&p_FmPort->port, poolId, value); + return E_OK; +} +bool FM_PORT_IsStalled(t_Handle h_FmPort) +{ + t_FmPort *p_FmPort = (t_FmPort*)h_FmPort; + t_Error err; + bool isStalled; + + SANITY_CHECK_RETURN_VALUE(p_FmPort, E_INVALID_HANDLE, FALSE); + SANITY_CHECK_RETURN_VALUE(!p_FmPort->p_FmPortDriverParam, E_INVALID_STATE, + FALSE); + + err = FmIsPortStalled(p_FmPort->h_Fm, p_FmPort->hardwarePortId, &isStalled); + if (err != E_OK) + { + REPORT_ERROR(MAJOR, err, NO_MSG); + return TRUE; + } + return isStalled; +} + +t_Error FM_PORT_ReleaseStalled(t_Handle h_FmPort) +{ + t_FmPort *p_FmPort = (t_FmPort*)h_FmPort; + + SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(!p_FmPort->p_FmPortDriverParam, E_INVALID_STATE); + + return FmResumeStalledPort(p_FmPort->h_Fm, p_FmPort->hardwarePortId); +} + +t_Error FM_PORT_SetRxL4ChecksumVerify(t_Handle h_FmPort, bool l4Checksum) +{ + t_FmPort *p_FmPort = (t_FmPort*)h_FmPort; + int err; + + SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(!p_FmPort->p_FmPortDriverParam, E_INVALID_STATE); + + if ((p_FmPort->portType != e_FM_PORT_TYPE_RX_10G) + && (p_FmPort->portType != e_FM_PORT_TYPE_RX)) + RETURN_ERROR(MAJOR, E_INVALID_OPERATION, + ("available for Rx ports only")); + + if (l4Checksum) + err = fman_port_modify_rx_fd_bits( + &p_FmPort->port, (uint8_t)(BMI_PORT_RFNE_FRWD_DCL4C >> 24), + TRUE); + else + err = fman_port_modify_rx_fd_bits( + &p_FmPort->port, (uint8_t)(BMI_PORT_RFNE_FRWD_DCL4C >> 24), + FALSE); + if (err != 0) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("fman_port_modify_rx_fd_bits")); + + return E_OK; +} + +/*****************************************************************************/ +/* API Run-time PCD Control unit functions */ +/*****************************************************************************/ + +#if (DPAA_VERSION >= 11) +t_Error FM_PORT_VSPAlloc(t_Handle h_FmPort, t_FmPortVSPAllocParams *p_VSPParams) +{ + t_FmPort *p_FmPort = (t_FmPort*)h_FmPort; + t_Error err = E_OK; + volatile uint32_t *p_BmiStorageProfileId = NULL, *p_BmiVspe = NULL; + uint32_t tmpReg = 0, tmp = 0; + uint16_t hwStoragePrflId; + + SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_FmPort->h_Fm, E_INVALID_HANDLE); + /*for numOfProfiles = 0 don't call this function*/ + SANITY_CHECK_RETURN_ERROR(p_VSPParams->numOfProfiles, E_INVALID_VALUE); + /*dfltRelativeId should be in the range of numOfProfiles*/ + SANITY_CHECK_RETURN_ERROR( + p_VSPParams->dfltRelativeId < p_VSPParams->numOfProfiles, + E_INVALID_VALUE); + /*p_FmPort should be from Rx type or OP*/ + SANITY_CHECK_RETURN_ERROR( + ((p_FmPort->portType == e_FM_PORT_TYPE_RX_10G) || (p_FmPort->portType == e_FM_PORT_TYPE_RX) || (p_FmPort->portType == e_FM_PORT_TYPE_OH_OFFLINE_PARSING)), + E_INVALID_VALUE); + /*port should be disabled*/ + SANITY_CHECK_RETURN_ERROR(!p_FmPort->enabled, E_INVALID_STATE); + /*if its called for Rx port relevant Tx Port should be passed (initialized) too and it should be disabled*/ + SANITY_CHECK_RETURN_ERROR( + ((p_VSPParams->h_FmTxPort && !((t_FmPort *)(p_VSPParams->h_FmTxPort))->enabled) || (p_FmPort->portType == e_FM_PORT_TYPE_OH_OFFLINE_PARSING)), + E_INVALID_VALUE); + /*should be called before SetPCD - this port should be without PCD*/ + SANITY_CHECK_RETURN_ERROR(!p_FmPort->pcdEngines, E_INVALID_STATE); + + /*alloc window of VSPs for this port*/ + err = FmVSPAllocForPort(p_FmPort->h_Fm, p_FmPort->portType, + p_FmPort->portId, p_VSPParams->numOfProfiles); + if (err != E_OK) + RETURN_ERROR(MAJOR, err, NO_MSG); + + /*get absolute VSP ID for dfltRelative*/ + err = FmVSPGetAbsoluteProfileId(p_FmPort->h_Fm, p_FmPort->portType, + p_FmPort->portId, + p_VSPParams->dfltRelativeId, + &hwStoragePrflId); + if (err != E_OK) + RETURN_ERROR(MAJOR, err, NO_MSG); + + /*fill relevant registers for p_FmPort and relative TxPort in the case p_FmPort from Rx type*/ + switch (p_FmPort->portType) + { + case (e_FM_PORT_TYPE_RX_10G): + case (e_FM_PORT_TYPE_RX): + p_BmiStorageProfileId = + &(((t_FmPort *)(p_VSPParams->h_FmTxPort))->p_FmPortBmiRegs->txPortBmiRegs.fmbm_tcfqid); + p_BmiVspe = + &(((t_FmPort *)(p_VSPParams->h_FmTxPort))->p_FmPortBmiRegs->txPortBmiRegs.fmbm_tfne); + + tmpReg = GET_UINT32(*p_BmiStorageProfileId) & ~BMI_SP_ID_MASK; + tmpReg |= (uint32_t)hwStoragePrflId << BMI_SP_ID_SHIFT; + WRITE_UINT32(*p_BmiStorageProfileId, tmpReg); + + tmpReg = GET_UINT32(*p_BmiVspe); + WRITE_UINT32(*p_BmiVspe, tmpReg | BMI_SP_EN); + + p_BmiStorageProfileId = + &p_FmPort->p_FmPortBmiRegs->rxPortBmiRegs.fmbm_rfqid; + p_BmiVspe = &p_FmPort->p_FmPortBmiRegs->rxPortBmiRegs.fmbm_rpp; + hwStoragePrflId = p_VSPParams->dfltRelativeId; + break; + + case (e_FM_PORT_TYPE_OH_OFFLINE_PARSING): + tmpReg = NIA_ENG_BMI | NIA_BMI_AC_FETCH_ALL_FRAME; + WRITE_UINT32( p_FmPort->p_FmPortQmiRegs->nonRxQmiRegs.fmqm_pndn, + tmpReg); + + p_BmiStorageProfileId = + &p_FmPort->p_FmPortBmiRegs->ohPortBmiRegs.fmbm_ofqid; + p_BmiVspe = &p_FmPort->p_FmPortBmiRegs->ohPortBmiRegs.fmbm_opp; + tmp |= BMI_EBD_EN; + break; + + default: + RETURN_ERROR( MAJOR, E_INVALID_OPERATION, + ("available for Rx and offline parsing ports only")); + } + + p_FmPort->vspe = TRUE; + p_FmPort->dfltRelativeId = p_VSPParams->dfltRelativeId; + + tmpReg = GET_UINT32(*p_BmiStorageProfileId) & ~BMI_SP_ID_MASK; + tmpReg |= (uint32_t)hwStoragePrflId << BMI_SP_ID_SHIFT; + WRITE_UINT32(*p_BmiStorageProfileId, tmpReg); + + tmpReg = GET_UINT32(*p_BmiVspe); + WRITE_UINT32(*p_BmiVspe, tmpReg | BMI_SP_EN | tmp); + return E_OK; +} +#endif /* (DPAA_VERSION >= 11) */ + +t_Error FM_PORT_PcdPlcrAllocProfiles(t_Handle h_FmPort, uint16_t numOfProfiles) +{ + t_FmPort *p_FmPort = (t_FmPort*)h_FmPort; + t_Error err = E_OK; + + p_FmPort->h_FmPcd = FmGetPcdHandle(p_FmPort->h_Fm); + ASSERT_COND(p_FmPort->h_FmPcd); + + if (!TRY_LOCK(p_FmPort->h_Spinlock, &p_FmPort->lock)) + { + DBG(TRACE, ("FM Port Try Lock - BUSY")); + return ERROR_CODE(E_BUSY); + } + + if (numOfProfiles) + { + err = FmPcdPlcrAllocProfiles(p_FmPort->h_FmPcd, + p_FmPort->hardwarePortId, numOfProfiles); + if (err) + RETURN_ERROR(MAJOR, err, NO_MSG); + } + /* set the port handle within the PCD policer, even if no profiles defined */ + FmPcdPortRegister(p_FmPort->h_FmPcd, h_FmPort, p_FmPort->hardwarePortId); + + RELEASE_LOCK(p_FmPort->lock); + + return E_OK; +} + +t_Error FM_PORT_PcdPlcrFreeProfiles(t_Handle h_FmPort) +{ + t_FmPort *p_FmPort = (t_FmPort*)h_FmPort; + t_Error err = E_OK; + + if (!TRY_LOCK(p_FmPort->h_Spinlock, &p_FmPort->lock)) + { + DBG(TRACE, ("FM Port Try Lock - BUSY")); + return ERROR_CODE(E_BUSY); + } + + err = FmPcdPlcrFreeProfiles(p_FmPort->h_FmPcd, p_FmPort->hardwarePortId); + + RELEASE_LOCK(p_FmPort->lock); + + if (err) + RETURN_ERROR(MAJOR, err, NO_MSG); + + return E_OK; +} + +t_Error FM_PORT_PcdKgModifyInitialScheme(t_Handle h_FmPort, + t_FmPcdKgSchemeSelect *p_FmPcdKgScheme) +{ + t_FmPort *p_FmPort = (t_FmPort*)h_FmPort; + volatile uint32_t *p_BmiHpnia = NULL; + uint32_t tmpReg; + uint8_t relativeSchemeId; + uint8_t physicalSchemeId; + + SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(!p_FmPort->p_FmPortDriverParam, E_INVALID_STATE); + SANITY_CHECK_RETURN_ERROR(p_FmPort->pcdEngines & FM_PCD_KG, + E_INVALID_STATE); + + tmpReg = (uint32_t)((p_FmPort->pcdEngines & FM_PCD_CC) ? NIA_KG_CC_EN : 0); + switch (p_FmPort->portType) + { + case (e_FM_PORT_TYPE_RX_10G): + case (e_FM_PORT_TYPE_RX): + p_BmiHpnia = &p_FmPort->port.bmi_regs->rx.fmbm_rfpne; + break; + case (e_FM_PORT_TYPE_OH_OFFLINE_PARSING): + p_BmiHpnia = &p_FmPort->port.bmi_regs->oh.fmbm_ofpne; + break; + default: + RETURN_ERROR( MAJOR, E_INVALID_OPERATION, + ("available for Rx and offline parsing ports only")); + } + + if (!TRY_LOCK(p_FmPort->h_Spinlock, &p_FmPort->lock)) + { + DBG(TRACE, ("FM Port Try Lock - BUSY")); + return ERROR_CODE(E_BUSY); + } + + /* if we want to change to direct scheme, we need to check that this scheme is valid */ + if (p_FmPcdKgScheme->direct) + { + physicalSchemeId = FmPcdKgGetSchemeId(p_FmPcdKgScheme->h_DirectScheme); + /* check that this scheme is bound to this port */ + if (!(p_FmPort->schemesPerPortVector + & (uint32_t)(1 << (31 - (uint32_t)physicalSchemeId)))) + { + RELEASE_LOCK(p_FmPort->lock); + RETURN_ERROR( + MAJOR, E_INVALID_STATE, + ("called with a scheme that is not bound to this port")); + } + + relativeSchemeId = FmPcdKgGetRelativeSchemeId(p_FmPort->h_FmPcd, + physicalSchemeId); + if (relativeSchemeId >= FM_PCD_KG_NUM_OF_SCHEMES) + { + RELEASE_LOCK(p_FmPort->lock); + RETURN_ERROR(MAJOR, E_NOT_IN_RANGE, + ("called with invalid Scheme ")); + } + + if (!FmPcdKgIsSchemeValidSw(p_FmPcdKgScheme->h_DirectScheme)) + { + RELEASE_LOCK(p_FmPort->lock); + RETURN_ERROR(MAJOR, E_INVALID_STATE, + ("called with uninitialized Scheme ")); + } + + WRITE_UINT32( + *p_BmiHpnia, + NIA_ENG_KG | tmpReg | NIA_KG_DIRECT | (uint32_t)physicalSchemeId); + } + else + /* change to indirect scheme */ + WRITE_UINT32(*p_BmiHpnia, NIA_ENG_KG | tmpReg); + RELEASE_LOCK(p_FmPort->lock); + + return E_OK; +} + +t_Error FM_PORT_PcdPlcrModifyInitialProfile(t_Handle h_FmPort, + t_Handle h_Profile) +{ + t_FmPort *p_FmPort = (t_FmPort*)h_FmPort; + volatile uint32_t *p_BmiNia; + volatile uint32_t *p_BmiHpnia; + uint32_t tmpReg; + uint16_t absoluteProfileId = FmPcdPlcrProfileGetAbsoluteId(h_Profile); + + SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(!p_FmPort->p_FmPortDriverParam, E_INVALID_STATE); + SANITY_CHECK_RETURN_ERROR(p_FmPort->pcdEngines & FM_PCD_PLCR, + E_INVALID_STATE); + + /* check relevance of this routine - only when policer is used + directly after BMI or Parser */ + if ((p_FmPort->pcdEngines & FM_PCD_KG) + || (p_FmPort->pcdEngines & FM_PCD_CC)) + RETURN_ERROR( + MAJOR, + E_INVALID_STATE, + ("relevant only when PCD support mode is e_FM_PCD_SUPPORT_PLCR_ONLY or e_FM_PCD_SUPPORT_PRS_AND_PLCR")); + + switch (p_FmPort->portType) + { + case (e_FM_PORT_TYPE_RX_10G): + case (e_FM_PORT_TYPE_RX): + p_BmiNia = &p_FmPort->port.bmi_regs->rx.fmbm_rfne; + p_BmiHpnia = &p_FmPort->port.bmi_regs->rx.fmbm_rfpne; + tmpReg = GET_UINT32(*p_BmiNia) & BMI_RFNE_FDCS_MASK; + break; + case (e_FM_PORT_TYPE_OH_OFFLINE_PARSING): + p_BmiNia = &p_FmPort->port.bmi_regs->oh.fmbm_ofne; + p_BmiHpnia = &p_FmPort->port.bmi_regs->oh.fmbm_ofpne; + tmpReg = 0; + break; + default: + RETURN_ERROR( MAJOR, E_INVALID_OPERATION, + ("available for Rx and offline parsing ports only")); + } + + if (!TRY_LOCK(p_FmPort->h_Spinlock, &p_FmPort->lock)) + { + DBG(TRACE, ("FM Port Try Lock - BUSY")); + return ERROR_CODE(E_BUSY); + } + + if (!FmPcdPlcrIsProfileValid(p_FmPort->h_FmPcd, absoluteProfileId)) + { + RELEASE_LOCK(p_FmPort->lock); + RETURN_ERROR(MAJOR, E_INVALID_OPERATION, ("Invalid profile")); + } + + tmpReg |= (uint32_t)(NIA_ENG_PLCR | NIA_PLCR_ABSOLUTE | absoluteProfileId); + + if (p_FmPort->pcdEngines & FM_PCD_PRS) /* e_FM_PCD_SUPPORT_PRS_AND_PLCR */ + { + /* update BMI HPNIA */ + WRITE_UINT32(*p_BmiHpnia, tmpReg); + } + else /* e_FM_PCD_SUPPORT_PLCR_ONLY */ + { + /* rfne may contain FDCS bits, so first we read them. */ + tmpReg |= (GET_UINT32(*p_BmiNia) & BMI_RFNE_FDCS_MASK); + /* update BMI NIA */ + WRITE_UINT32(*p_BmiNia, tmpReg); + }RELEASE_LOCK(p_FmPort->lock); + + return E_OK; +} + +t_Error FM_PORT_PcdCcModifyTree(t_Handle h_FmPort, t_Handle h_CcTree) +{ + t_FmPort *p_FmPort = (t_FmPort*)h_FmPort; + t_Error err = E_OK; + volatile uint32_t *p_BmiCcBase = NULL; + volatile uint32_t *p_BmiNia = NULL; + uint32_t ccTreePhysOffset; + + SANITY_CHECK_RETURN_ERROR(h_FmPort, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(h_CcTree, E_INVALID_HANDLE); + + if (p_FmPort->imEn) + RETURN_ERROR(MAJOR, E_INVALID_OPERATION, + ("available for non-independent mode ports only")); + + /* get PCD registers pointers */ + switch (p_FmPort->portType) + { + case (e_FM_PORT_TYPE_RX_10G): + case (e_FM_PORT_TYPE_RX): + p_BmiNia = &p_FmPort->port.bmi_regs->rx.fmbm_rfne; + break; + case (e_FM_PORT_TYPE_OH_OFFLINE_PARSING): + p_BmiNia = &p_FmPort->port.bmi_regs->oh.fmbm_ofne; + break; + default: + RETURN_ERROR( MAJOR, E_INVALID_OPERATION, + ("available for Rx and offline parsing ports only")); + } + + /* check that current NIA is BMI to BMI */ + if ((GET_UINT32(*p_BmiNia) & ~BMI_RFNE_FDCS_MASK) + != GET_NIA_BMI_AC_ENQ_FRAME(p_FmPort->h_FmPcd)) + RETURN_ERROR( MAJOR, E_INVALID_OPERATION, + ("may be called only for ports in BMI-to-BMI state.")); + + if (p_FmPort->pcdEngines & FM_PCD_CC) + { + if (p_FmPort->h_IpReassemblyManip) + { + err = FmPcdCcTreeAddIPR(p_FmPort->h_FmPcd, h_CcTree, NULL, + p_FmPort->h_IpReassemblyManip, FALSE); + if (err != E_OK) + { + RETURN_ERROR(MAJOR, err, NO_MSG); + } + } + else + if (p_FmPort->h_CapwapReassemblyManip) + { + err = FmPcdCcTreeAddCPR(p_FmPort->h_FmPcd, h_CcTree, NULL, + p_FmPort->h_CapwapReassemblyManip, + FALSE); + if (err != E_OK) + { + RETURN_ERROR(MAJOR, err, NO_MSG); + } + } + switch (p_FmPort->portType) + { + case (e_FM_PORT_TYPE_RX_10G): + case (e_FM_PORT_TYPE_RX): + p_BmiCcBase = &p_FmPort->port.bmi_regs->rx.fmbm_rccb; + break; + case (e_FM_PORT_TYPE_OH_OFFLINE_PARSING): + p_BmiCcBase = &p_FmPort->port.bmi_regs->oh.fmbm_occb; + break; + default: + RETURN_ERROR(MAJOR, E_INVALID_STATE, ("Invalid port type")); + } + + if (!TRY_LOCK(p_FmPort->h_Spinlock, &p_FmPort->lock)) + { + DBG(TRACE, ("FM Port Try Lock - BUSY")); + return ERROR_CODE(E_BUSY); + } + err = FmPcdCcBindTree(p_FmPort->h_FmPcd, NULL, h_CcTree, + &ccTreePhysOffset, h_FmPort); + if (err) + { + RELEASE_LOCK(p_FmPort->lock); + RETURN_ERROR(MAJOR, err, NO_MSG); + }WRITE_UINT32(*p_BmiCcBase, ccTreePhysOffset); + + p_FmPort->ccTreeId = h_CcTree; + RELEASE_LOCK(p_FmPort->lock); + } + else + RETURN_ERROR( MAJOR, E_INVALID_STATE, + ("Coarse Classification not defined for this port.")); + + return E_OK; +} + +t_Error FM_PORT_AttachPCD(t_Handle h_FmPort) +{ + t_FmPort *p_FmPort = (t_FmPort*)h_FmPort; + t_Error err = E_OK; + + SANITY_CHECK_RETURN_ERROR(h_FmPort, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(!p_FmPort->p_FmPortDriverParam, E_INVALID_STATE); + + if (p_FmPort->imEn) + RETURN_ERROR(MAJOR, E_INVALID_OPERATION, + ("available for non-independent mode ports only")); + + if ((p_FmPort->portType != e_FM_PORT_TYPE_RX_10G) + && (p_FmPort->portType != e_FM_PORT_TYPE_RX) + && (p_FmPort->portType != e_FM_PORT_TYPE_OH_OFFLINE_PARSING)) + RETURN_ERROR( MAJOR, E_INVALID_OPERATION, + ("available for Rx and offline parsing ports only")); + + if (!TRY_LOCK(p_FmPort->h_Spinlock, &p_FmPort->lock)) + { + DBG(TRACE, ("FM Port Try Lock - BUSY")); + return ERROR_CODE(E_BUSY); + } + + if (p_FmPort->h_ReassemblyTree) + p_FmPort->pcdEngines |= FM_PCD_CC; + + err = AttachPCD(h_FmPort); + RELEASE_LOCK(p_FmPort->lock); + + return err; +} + +t_Error FM_PORT_DetachPCD(t_Handle h_FmPort) +{ + t_FmPort *p_FmPort = (t_FmPort*)h_FmPort; + t_Error err = E_OK; + + SANITY_CHECK_RETURN_ERROR(h_FmPort, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(!p_FmPort->p_FmPortDriverParam, E_INVALID_STATE); + + if (p_FmPort->imEn) + RETURN_ERROR(MAJOR, E_INVALID_OPERATION, + ("available for non-independent mode ports only")); + + if ((p_FmPort->portType != e_FM_PORT_TYPE_RX_10G) + && (p_FmPort->portType != e_FM_PORT_TYPE_RX) + && (p_FmPort->portType != e_FM_PORT_TYPE_OH_OFFLINE_PARSING)) + RETURN_ERROR( MAJOR, E_INVALID_OPERATION, + ("available for Rx and offline parsing ports only")); + + if (!TRY_LOCK(p_FmPort->h_Spinlock, &p_FmPort->lock)) + { + DBG(TRACE, ("FM Port Try Lock - BUSY")); + return ERROR_CODE(E_BUSY); + } + + err = DetachPCD(h_FmPort); + if (err != E_OK) + { + RELEASE_LOCK(p_FmPort->lock); + RETURN_ERROR(MAJOR, err, NO_MSG); + } + + if (p_FmPort->h_ReassemblyTree) + p_FmPort->pcdEngines &= ~FM_PCD_CC; + RELEASE_LOCK(p_FmPort->lock); + + return E_OK; +} + +t_Error FM_PORT_SetPCD(t_Handle h_FmPort, t_FmPortPcdParams *p_PcdParam) +{ + t_FmPort *p_FmPort = (t_FmPort*)h_FmPort; + t_Error err = E_OK; + t_FmPortPcdParams modifiedPcdParams, *p_PcdParams; + t_FmPcdCcTreeParams *p_FmPcdCcTreeParams; + t_FmPortPcdCcParams fmPortPcdCcParams; + t_FmPortGetSetCcParams fmPortGetSetCcParams; + + SANITY_CHECK_RETURN_ERROR(h_FmPort, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_PcdParam, E_NULL_POINTER); + SANITY_CHECK_RETURN_ERROR(!p_FmPort->p_FmPortDriverParam, E_INVALID_STATE); + + if (p_FmPort->imEn) + RETURN_ERROR(MAJOR, E_INVALID_OPERATION, + ("available for non-independent mode ports only")); + + if ((p_FmPort->portType != e_FM_PORT_TYPE_RX_10G) + && (p_FmPort->portType != e_FM_PORT_TYPE_RX) + && (p_FmPort->portType != e_FM_PORT_TYPE_OH_OFFLINE_PARSING)) + RETURN_ERROR( MAJOR, E_INVALID_OPERATION, + ("available for Rx and offline parsing ports only")); + + if (!TRY_LOCK(p_FmPort->h_Spinlock, &p_FmPort->lock)) + { + DBG(TRACE, ("FM Port Try Lock - BUSY")); + return ERROR_CODE(E_BUSY); + } + + p_FmPort->h_FmPcd = FmGetPcdHandle(p_FmPort->h_Fm); + ASSERT_COND(p_FmPort->h_FmPcd); + + if (p_PcdParam->p_CcParams && !p_PcdParam->p_CcParams->h_CcTree) + RETURN_ERROR(MAJOR, E_INVALID_HANDLE, + ("Tree handle must be given if CC is required")); + + memcpy(&modifiedPcdParams, p_PcdParam, sizeof(t_FmPortPcdParams)); + p_PcdParams = &modifiedPcdParams; + if ((p_PcdParams->h_IpReassemblyManip) +#if (DPAA_VERSION >= 11) + || (p_PcdParams->h_CapwapReassemblyManip) +#endif /* (DPAA_VERSION >= 11) */ + ) + { + if ((p_PcdParams->pcdSupport != e_FM_PORT_PCD_SUPPORT_PRS_AND_KG) + && (p_PcdParams->pcdSupport + != e_FM_PORT_PCD_SUPPORT_PRS_AND_KG_AND_CC) + && (p_PcdParams->pcdSupport + != e_FM_PORT_PCD_SUPPORT_PRS_AND_KG_AND_CC_AND_PLCR) + && (p_PcdParams->pcdSupport + != e_FM_PORT_PCD_SUPPORT_PRS_AND_KG_AND_PLCR)) + { + RELEASE_LOCK(p_FmPort->lock); + RETURN_ERROR( MAJOR, E_INVALID_STATE, + ("pcdSupport must have KG for supporting Reassembly")); + } + p_FmPort->h_IpReassemblyManip = p_PcdParams->h_IpReassemblyManip; +#if (DPAA_VERSION >= 11) + if ((p_PcdParams->h_IpReassemblyManip) + && (p_PcdParams->h_CapwapReassemblyManip)) + RETURN_ERROR(MAJOR, E_INVALID_STATE, + ("Either IP-R or CAPWAP-R is allowed")); + if ((p_PcdParams->h_CapwapReassemblyManip) + && (p_FmPort->portType != e_FM_PORT_TYPE_OH_OFFLINE_PARSING)) + RETURN_ERROR(MAJOR, E_INVALID_STATE, + ("CAPWAP-R is allowed only on offline-port")); + if (p_PcdParams->h_CapwapReassemblyManip) + p_FmPort->h_CapwapReassemblyManip = + p_PcdParams->h_CapwapReassemblyManip; +#endif /* (DPAA_VERSION >= 11) */ + + if (!p_PcdParams->p_CcParams) + { + if (!((p_PcdParams->pcdSupport == e_FM_PORT_PCD_SUPPORT_PRS_AND_KG) + || (p_PcdParams->pcdSupport + == e_FM_PORT_PCD_SUPPORT_PRS_AND_KG_AND_PLCR))) + { + RELEASE_LOCK(p_FmPort->lock); + RETURN_ERROR( + MAJOR, + E_INVALID_STATE, + ("PCD initialization structure is not consistent with pcdSupport")); + } + + /* No user-tree, need to build internal tree */ + p_FmPcdCcTreeParams = (t_FmPcdCcTreeParams*)XX_Malloc( + sizeof(t_FmPcdCcTreeParams)); + if (!p_FmPcdCcTreeParams) + RETURN_ERROR(MAJOR, E_NO_MEMORY, ("p_FmPcdCcTreeParams")); + memset(p_FmPcdCcTreeParams, 0, sizeof(t_FmPcdCcTreeParams)); + p_FmPcdCcTreeParams->h_NetEnv = p_PcdParams->h_NetEnv; + p_FmPort->h_ReassemblyTree = FM_PCD_CcRootBuild( + p_FmPort->h_FmPcd, p_FmPcdCcTreeParams); + + if (!p_FmPort->h_ReassemblyTree) + { + RELEASE_LOCK(p_FmPort->lock); + XX_Free(p_FmPcdCcTreeParams); + RETURN_ERROR( MAJOR, E_INVALID_HANDLE, + ("FM_PCD_CcBuildTree for Reassembly failed")); + } + if (p_PcdParams->pcdSupport == e_FM_PORT_PCD_SUPPORT_PRS_AND_KG) + p_PcdParams->pcdSupport = + e_FM_PORT_PCD_SUPPORT_PRS_AND_KG_AND_CC; + else + p_PcdParams->pcdSupport = + e_FM_PORT_PCD_SUPPORT_PRS_AND_KG_AND_CC_AND_PLCR; + + memset(&fmPortPcdCcParams, 0, sizeof(t_FmPortPcdCcParams)); + fmPortPcdCcParams.h_CcTree = p_FmPort->h_ReassemblyTree; + p_PcdParams->p_CcParams = &fmPortPcdCcParams; + XX_Free(p_FmPcdCcTreeParams); + } + + if (p_FmPort->h_IpReassemblyManip) + err = FmPcdCcTreeAddIPR(p_FmPort->h_FmPcd, + p_PcdParams->p_CcParams->h_CcTree, + p_PcdParams->h_NetEnv, + p_FmPort->h_IpReassemblyManip, TRUE); +#if (DPAA_VERSION >= 11) + else + if (p_FmPort->h_CapwapReassemblyManip) + err = FmPcdCcTreeAddCPR(p_FmPort->h_FmPcd, + p_PcdParams->p_CcParams->h_CcTree, + p_PcdParams->h_NetEnv, + p_FmPort->h_CapwapReassemblyManip, + TRUE); +#endif /* (DPAA_VERSION >= 11) */ + + if (err != E_OK) + { + if (p_FmPort->h_ReassemblyTree) + { + FM_PCD_CcRootDelete(p_FmPort->h_ReassemblyTree); + p_FmPort->h_ReassemblyTree = NULL; + }RELEASE_LOCK(p_FmPort->lock); + RETURN_ERROR(MAJOR, err, NO_MSG); + } + } + + if (!FmPcdLockTryLockAll(p_FmPort->h_FmPcd)) + { + if (p_FmPort->h_ReassemblyTree) + { + FM_PCD_CcRootDelete(p_FmPort->h_ReassemblyTree); + p_FmPort->h_ReassemblyTree = NULL; + }RELEASE_LOCK(p_FmPort->lock); + DBG(TRACE, ("Try LockAll - BUSY")); + return ERROR_CODE(E_BUSY); + } + + err = SetPcd(h_FmPort, p_PcdParams); + if (err) + { + if (p_FmPort->h_ReassemblyTree) + { + FM_PCD_CcRootDelete(p_FmPort->h_ReassemblyTree); + p_FmPort->h_ReassemblyTree = NULL; + } + FmPcdLockUnlockAll(p_FmPort->h_FmPcd); + RELEASE_LOCK(p_FmPort->lock); + RETURN_ERROR(MAJOR, err, NO_MSG); + } + + if ((p_FmPort->pcdEngines & FM_PCD_PRS) + && (p_PcdParams->p_PrsParams->includeInPrsStatistics)) + { + err = FmPcdPrsIncludePortInStatistics(p_FmPort->h_FmPcd, + p_FmPort->hardwarePortId, TRUE); + if (err) + { + DeletePcd(p_FmPort); + if (p_FmPort->h_ReassemblyTree) + { + FM_PCD_CcRootDelete(p_FmPort->h_ReassemblyTree); + p_FmPort->h_ReassemblyTree = NULL; + } + FmPcdLockUnlockAll(p_FmPort->h_FmPcd); + RELEASE_LOCK(p_FmPort->lock); + RETURN_ERROR(MAJOR, err, NO_MSG); + } + p_FmPort->includeInPrsStatistics = TRUE; + } + + FmPcdIncNetEnvOwners(p_FmPort->h_FmPcd, p_FmPort->netEnvId); + + if (FmPcdIsAdvancedOffloadSupported(p_FmPort->h_FmPcd)) + { + memset(&fmPortGetSetCcParams, 0, sizeof(t_FmPortGetSetCcParams)); + + if (p_FmPort->portType == e_FM_PORT_TYPE_OH_OFFLINE_PARSING) + { +#ifdef FM_KG_ERASE_FLOW_ID_ERRATA_FMAN_SW004 + if ((p_FmPort->fmRevInfo.majorRev < 6) && + (p_FmPort->pcdEngines & FM_PCD_KG)) + { + int i; + for (i = 0; i<p_PcdParams->p_KgParams->numOfSchemes; i++) + /* The following function must be locked */ + FmPcdKgCcGetSetParams(p_FmPort->h_FmPcd, + p_PcdParams->p_KgParams->h_Schemes[i], + UPDATE_KG_NIA_CC_WA, + 0); + } +#endif /* FM_KG_ERASE_FLOW_ID_ERRATA_FMAN_SW004 */ + +#if (DPAA_VERSION >= 11) + { + t_FmPcdCtrlParamsPage *p_ParamsPage; + + FmPortSetGprFunc(p_FmPort, e_FM_PORT_GPR_MURAM_PAGE, + (void**)&p_ParamsPage); + ASSERT_COND(p_ParamsPage); + WRITE_UINT32(p_ParamsPage->postBmiFetchNia, + p_FmPort->savedBmiNia); + } +#endif /* (DPAA_VERSION >= 11) */ + + /* Set post-bmi-fetch nia */ + p_FmPort->savedBmiNia &= BMI_RFNE_FDCS_MASK; + p_FmPort->savedBmiNia |= (NIA_FM_CTL_AC_POST_BMI_FETCH + | NIA_ENG_FM_CTL); + + /* Set pre-bmi-fetch nia */ + fmPortGetSetCcParams.setCcParams.type = UPDATE_NIA_PNDN; +#if (DPAA_VERSION >= 11) + fmPortGetSetCcParams.setCcParams.nia = + (NIA_FM_CTL_AC_PRE_BMI_FETCH_FULL_FRAME | NIA_ENG_FM_CTL); +#else + fmPortGetSetCcParams.setCcParams.nia = (NIA_FM_CTL_AC_PRE_BMI_FETCH_HEADER | NIA_ENG_FM_CTL); +#endif /* (DPAA_VERSION >= 11) */ + if ((err = FmPortGetSetCcParams(p_FmPort, &fmPortGetSetCcParams)) + != E_OK) + { + DeletePcd(p_FmPort); + if (p_FmPort->h_ReassemblyTree) + { + FM_PCD_CcRootDelete(p_FmPort->h_ReassemblyTree); + p_FmPort->h_ReassemblyTree = NULL; + } + FmPcdLockUnlockAll(p_FmPort->h_FmPcd); + RELEASE_LOCK(p_FmPort->lock); + RETURN_ERROR(MAJOR, err, NO_MSG); + } + } + + FmPcdLockUnlockAll(p_FmPort->h_FmPcd); + + /* Set pop-to-next-step nia */ +#if (DPAA_VERSION == 10) + if (p_FmPort->fmRevInfo.majorRev < 6) + { + fmPortGetSetCcParams.setCcParams.type = UPDATE_NIA_PNEN; + fmPortGetSetCcParams.setCcParams.nia = NIA_FM_CTL_AC_POP_TO_N_STEP | NIA_ENG_FM_CTL; + } + else + { +#endif /* (DPAA_VERSION == 10) */ + fmPortGetSetCcParams.getCcParams.type = GET_NIA_FPNE; +#if (DPAA_VERSION == 10) + } +#endif /* (DPAA_VERSION == 10) */ + if ((err = FmPortGetSetCcParams(h_FmPort, &fmPortGetSetCcParams)) + != E_OK) + { + DeletePcd(p_FmPort); + if (p_FmPort->h_ReassemblyTree) + { + FM_PCD_CcRootDelete(p_FmPort->h_ReassemblyTree); + p_FmPort->h_ReassemblyTree = NULL; + }RELEASE_LOCK(p_FmPort->lock); + RETURN_ERROR(MAJOR, err, NO_MSG); + } + + /* Set post-bmi-prepare-to-enq nia */ + fmPortGetSetCcParams.setCcParams.type = UPDATE_NIA_FENE; + fmPortGetSetCcParams.setCcParams.nia = (NIA_FM_CTL_AC_POST_BMI_ENQ + | NIA_ENG_FM_CTL); + if ((err = FmPortGetSetCcParams(h_FmPort, &fmPortGetSetCcParams)) + != E_OK) + { + DeletePcd(p_FmPort); + if (p_FmPort->h_ReassemblyTree) + { + FM_PCD_CcRootDelete(p_FmPort->h_ReassemblyTree); + p_FmPort->h_ReassemblyTree = NULL; + }RELEASE_LOCK(p_FmPort->lock); + RETURN_ERROR(MAJOR, err, NO_MSG); + } + + if ((p_FmPort->h_IpReassemblyManip) + || (p_FmPort->h_CapwapReassemblyManip)) + { +#if (DPAA_VERSION == 10) + if (p_FmPort->fmRevInfo.majorRev < 6) + { + /* Overwrite post-bmi-prepare-to-enq nia */ + fmPortGetSetCcParams.setCcParams.type = UPDATE_NIA_FENE; + fmPortGetSetCcParams.setCcParams.nia = (NIA_FM_CTL_AC_POST_BMI_ENQ_ORR | NIA_ENG_FM_CTL | NIA_ORDER_RESTOR); + fmPortGetSetCcParams.setCcParams.overwrite = TRUE; + } + else + { +#endif /* (DPAA_VERSION == 10) */ + /* Set the ORR bit (for order-restoration) */ + fmPortGetSetCcParams.setCcParams.type = UPDATE_NIA_FPNE; + fmPortGetSetCcParams.setCcParams.nia = + fmPortGetSetCcParams.getCcParams.nia | NIA_ORDER_RESTOR; +#if (DPAA_VERSION == 10) + } +#endif /* (DPAA_VERSION == 10) */ + if ((err = FmPortGetSetCcParams(h_FmPort, &fmPortGetSetCcParams)) + != E_OK) + { + DeletePcd(p_FmPort); + if (p_FmPort->h_ReassemblyTree) + { + FM_PCD_CcRootDelete(p_FmPort->h_ReassemblyTree); + p_FmPort->h_ReassemblyTree = NULL; + }RELEASE_LOCK(p_FmPort->lock); + RETURN_ERROR(MAJOR, err, NO_MSG); + } + } + } + else + FmPcdLockUnlockAll(p_FmPort->h_FmPcd); + +#if (DPAA_VERSION >= 11) + { + t_FmPcdCtrlParamsPage *p_ParamsPage; + + memset(&fmPortGetSetCcParams, 0, sizeof(t_FmPortGetSetCcParams)); + + fmPortGetSetCcParams.setCcParams.type = UPDATE_NIA_CMNE; + if (FmPcdIsAdvancedOffloadSupported(p_FmPort->h_FmPcd)) + fmPortGetSetCcParams.setCcParams.nia = NIA_FM_CTL_AC_POP_TO_N_STEP + | NIA_ENG_FM_CTL; + else + fmPortGetSetCcParams.setCcParams.nia = + NIA_FM_CTL_AC_NO_IPACC_POP_TO_N_STEP | NIA_ENG_FM_CTL; + if ((err = FmPortGetSetCcParams(h_FmPort, &fmPortGetSetCcParams)) + != E_OK) + { + DeletePcd(p_FmPort); + if (p_FmPort->h_ReassemblyTree) + { + FM_PCD_CcRootDelete(p_FmPort->h_ReassemblyTree); + p_FmPort->h_ReassemblyTree = NULL; + }RELEASE_LOCK(p_FmPort->lock); + RETURN_ERROR(MAJOR, err, NO_MSG); + } + + FmPortSetGprFunc(p_FmPort, e_FM_PORT_GPR_MURAM_PAGE, + (void**)&p_ParamsPage); + ASSERT_COND(p_ParamsPage); + + if (FmPcdIsAdvancedOffloadSupported(p_FmPort->h_FmPcd)) + WRITE_UINT32( + p_ParamsPage->misc, + GET_UINT32(p_ParamsPage->misc) | FM_CTL_PARAMS_PAGE_OFFLOAD_SUPPORT_EN); + + if ((p_FmPort->h_IpReassemblyManip) + || (p_FmPort->h_CapwapReassemblyManip)) + { + if (p_FmPort->portType == e_FM_PORT_TYPE_OH_OFFLINE_PARSING) + WRITE_UINT32( + p_ParamsPage->discardMask, + GET_UINT32(p_FmPort->p_FmPortBmiRegs->ohPortBmiRegs.fmbm_ofsdm)); + else + WRITE_UINT32( + p_ParamsPage->discardMask, + GET_UINT32(p_FmPort->p_FmPortBmiRegs->rxPortBmiRegs.fmbm_rfsdm)); + } +#ifdef FM_ERROR_VSP_NO_MATCH_SW006 + if (p_FmPort->vspe) + WRITE_UINT32( + p_ParamsPage->misc, + GET_UINT32(p_ParamsPage->misc) | (p_FmPort->dfltRelativeId & FM_CTL_PARAMS_PAGE_ERROR_VSP_MASK)); +#endif /* FM_ERROR_VSP_NO_MATCH_SW006 */ + } +#endif /* (DPAA_VERSION >= 11) */ + + err = AttachPCD(h_FmPort); + if (err) + { + DeletePcd(p_FmPort); + if (p_FmPort->h_ReassemblyTree) + { + FM_PCD_CcRootDelete(p_FmPort->h_ReassemblyTree); + p_FmPort->h_ReassemblyTree = NULL; + }RELEASE_LOCK(p_FmPort->lock); + RETURN_ERROR(MAJOR, err, NO_MSG); + } + + RELEASE_LOCK(p_FmPort->lock); + + return err; +} + +t_Error FM_PORT_DeletePCD(t_Handle h_FmPort) +{ + t_FmPort *p_FmPort = (t_FmPort*)h_FmPort; + t_Error err = E_OK; + + SANITY_CHECK_RETURN_ERROR(h_FmPort, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(!p_FmPort->p_FmPortDriverParam, E_INVALID_STATE); + + if (p_FmPort->imEn) + RETURN_ERROR(MAJOR, E_INVALID_OPERATION, + ("available for non-independant mode ports only")); + + if ((p_FmPort->portType != e_FM_PORT_TYPE_RX_10G) + && (p_FmPort->portType != e_FM_PORT_TYPE_RX) + && (p_FmPort->portType != e_FM_PORT_TYPE_OH_OFFLINE_PARSING)) + RETURN_ERROR( MAJOR, E_INVALID_OPERATION, + ("available for Rx and offline parsing ports only")); + + if (!TRY_LOCK(p_FmPort->h_Spinlock, &p_FmPort->lock)) + { + DBG(TRACE, ("FM Port Try Lock - BUSY")); + return ERROR_CODE(E_BUSY); + } + + err = DetachPCD(h_FmPort); + if (err) + { + RELEASE_LOCK(p_FmPort->lock); + RETURN_ERROR(MAJOR, err, NO_MSG); + } + + FmPcdDecNetEnvOwners(p_FmPort->h_FmPcd, p_FmPort->netEnvId); + + /* we do it anyway, instead of checking if included */ + if ((p_FmPort->pcdEngines & FM_PCD_PRS) && p_FmPort->includeInPrsStatistics) + { + FmPcdPrsIncludePortInStatistics(p_FmPort->h_FmPcd, + p_FmPort->hardwarePortId, FALSE); + p_FmPort->includeInPrsStatistics = FALSE; + } + + if (!FmPcdLockTryLockAll(p_FmPort->h_FmPcd)) + { + RELEASE_LOCK(p_FmPort->lock); + DBG(TRACE, ("Try LockAll - BUSY")); + return ERROR_CODE(E_BUSY); + } + + err = DeletePcd(h_FmPort); + FmPcdLockUnlockAll(p_FmPort->h_FmPcd); + if (err) + { + RELEASE_LOCK(p_FmPort->lock); + RETURN_ERROR(MAJOR, err, NO_MSG); + } + + if (p_FmPort->h_ReassemblyTree) + { + err = FM_PCD_CcRootDelete(p_FmPort->h_ReassemblyTree); + if (err) + { + RELEASE_LOCK(p_FmPort->lock); + RETURN_ERROR(MAJOR, err, NO_MSG); + } + p_FmPort->h_ReassemblyTree = NULL; + }RELEASE_LOCK(p_FmPort->lock); + + return err; +} + +t_Error FM_PORT_PcdKgBindSchemes(t_Handle h_FmPort, + t_FmPcdPortSchemesParams *p_PortScheme) +{ + t_FmPort *p_FmPort = (t_FmPort*)h_FmPort; + t_FmPcdKgInterModuleBindPortToSchemes schemeBind; + t_Error err = E_OK; + uint32_t tmpScmVec = 0; + int i; + + SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(!p_FmPort->p_FmPortDriverParam, E_INVALID_STATE); + SANITY_CHECK_RETURN_ERROR(p_FmPort->pcdEngines & FM_PCD_KG, + E_INVALID_STATE); + + schemeBind.netEnvId = p_FmPort->netEnvId; + schemeBind.hardwarePortId = p_FmPort->hardwarePortId; + schemeBind.numOfSchemes = p_PortScheme->numOfSchemes; + schemeBind.useClsPlan = p_FmPort->useClsPlan; + for (i = 0; i < schemeBind.numOfSchemes; i++) + { + schemeBind.schemesIds[i] = FmPcdKgGetSchemeId( + p_PortScheme->h_Schemes[i]); + /* build vector */ + tmpScmVec |= 1 << (31 - (uint32_t)schemeBind.schemesIds[i]); + } + + if (!TRY_LOCK(p_FmPort->h_Spinlock, &p_FmPort->lock)) + { + DBG(TRACE, ("FM Port Try Lock - BUSY")); + return ERROR_CODE(E_BUSY); + } + + err = FmPcdKgBindPortToSchemes(p_FmPort->h_FmPcd, &schemeBind); + if (err == E_OK) + p_FmPort->schemesPerPortVector |= tmpScmVec; + +#ifdef FM_KG_ERASE_FLOW_ID_ERRATA_FMAN_SW004 + if ((FmPcdIsAdvancedOffloadSupported(p_FmPort->h_FmPcd)) && + (p_FmPort->portType == e_FM_PORT_TYPE_OH_OFFLINE_PARSING) && + (p_FmPort->fmRevInfo.majorRev < 6)) + { + for (i=0; i<p_PortScheme->numOfSchemes; i++) + FmPcdKgCcGetSetParams(p_FmPort->h_FmPcd, p_PortScheme->h_Schemes[i], UPDATE_KG_NIA_CC_WA, 0); + } +#endif /* FM_KG_ERASE_FLOW_ID_ERRATA_FMAN_SW004 */ + + RELEASE_LOCK(p_FmPort->lock); + + return err; +} + +t_Error FM_PORT_PcdKgUnbindSchemes(t_Handle h_FmPort, + t_FmPcdPortSchemesParams *p_PortScheme) +{ + t_FmPort *p_FmPort = (t_FmPort*)h_FmPort; + t_FmPcdKgInterModuleBindPortToSchemes schemeBind; + t_Error err = E_OK; + uint32_t tmpScmVec = 0; + int i; + + SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(!p_FmPort->p_FmPortDriverParam, E_INVALID_STATE); + SANITY_CHECK_RETURN_ERROR(p_FmPort->pcdEngines & FM_PCD_KG, + E_INVALID_STATE); + + schemeBind.netEnvId = p_FmPort->netEnvId; + schemeBind.hardwarePortId = p_FmPort->hardwarePortId; + schemeBind.numOfSchemes = p_PortScheme->numOfSchemes; + for (i = 0; i < schemeBind.numOfSchemes; i++) + { + schemeBind.schemesIds[i] = FmPcdKgGetSchemeId( + p_PortScheme->h_Schemes[i]); + /* build vector */ + tmpScmVec |= 1 << (31 - (uint32_t)schemeBind.schemesIds[i]); + } + + if (!TRY_LOCK(p_FmPort->h_Spinlock, &p_FmPort->lock)) + { + DBG(TRACE, ("FM Port Try Lock - BUSY")); + return ERROR_CODE(E_BUSY); + } + + err = FmPcdKgUnbindPortToSchemes(p_FmPort->h_FmPcd, &schemeBind); + if (err == E_OK) + p_FmPort->schemesPerPortVector &= ~tmpScmVec; + RELEASE_LOCK(p_FmPort->lock); + + return err; +} + +t_Error FM_PORT_AddCongestionGrps(t_Handle h_FmPort, + t_FmPortCongestionGrps *p_CongestionGrps) +{ + t_FmPort *p_FmPort = (t_FmPort*)h_FmPort; + uint8_t priorityTmpArray[FM_PORT_NUM_OF_CONGESTION_GRPS]; + uint8_t mod, index; + uint32_t i, grpsMap[FMAN_PORT_CG_MAP_NUM]; + int err; +#if (DPAA_VERSION >= 11) + int j; +#endif /* (DPAA_VERSION >= 11) */ + + SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE); + + /* un-necessary check of the indexes; probably will be needed in the future when there + will be more CGs available .... + for (i=0; i<p_CongestionGrps->numOfCongestionGrpsToConsider; i++) + if (p_CongestionGrps->congestionGrpsToConsider[i] >= FM_PORT_NUM_OF_CONGESTION_GRPS) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("CG id!")); + */ + +#ifdef FM_NO_OP_OBSERVED_CGS + if ((p_FmPort->fmRevInfo.majorRev != 4) && + (p_FmPort->fmRevInfo.majorRev < 6)) + { + if ((p_FmPort->portType != e_FM_PORT_TYPE_RX_10G) && + (p_FmPort->portType != e_FM_PORT_TYPE_RX)) + RETURN_ERROR(MAJOR, E_NOT_SUPPORTED, ("Available for Rx ports only")); + } + else +#endif /* FM_NO_OP_OBSERVED_CGS */ + if ((p_FmPort->portType != e_FM_PORT_TYPE_RX_10G) + && (p_FmPort->portType != e_FM_PORT_TYPE_RX) + && (p_FmPort->portType != e_FM_PORT_TYPE_OH_OFFLINE_PARSING)) + RETURN_ERROR(MAJOR, E_NOT_SUPPORTED, + ("Available for Rx & OP ports only")); + + /* Prepare groups map array */ + memset(grpsMap, 0, FMAN_PORT_CG_MAP_NUM * sizeof(uint32_t)); + for (i = 0; i < p_CongestionGrps->numOfCongestionGrpsToConsider; i++) + { + index = (uint8_t)(p_CongestionGrps->congestionGrpsToConsider[i] / 32); + mod = (uint8_t)(p_CongestionGrps->congestionGrpsToConsider[i] % 32); + if (p_FmPort->fmRevInfo.majorRev != 4) + grpsMap[7 - index] |= (uint32_t)(1 << mod); + else + grpsMap[0] |= (uint32_t)(1 << mod); + } + + memset(&priorityTmpArray, 0, + FM_PORT_NUM_OF_CONGESTION_GRPS * sizeof(uint8_t)); + + for (i = 0; i < p_CongestionGrps->numOfCongestionGrpsToConsider; i++) + { +#if (DPAA_VERSION >= 11) + for (j = 0; j < FM_MAX_NUM_OF_PFC_PRIORITIES; j++) + if (p_CongestionGrps->pfcPrioritiesEn[i][j]) + priorityTmpArray[p_CongestionGrps->congestionGrpsToConsider[i]] |= + (0x01 << (FM_MAX_NUM_OF_PFC_PRIORITIES - j - 1)); +#endif /* (DPAA_VERSION >= 11) */ + } + +#if (DPAA_VERSION >= 11) + for (i = 0; i < FM_PORT_NUM_OF_CONGESTION_GRPS; i++) + { + err = FmSetCongestionGroupPFCpriority(p_FmPort->h_Fm, i, + priorityTmpArray[i]); + if (err) + return err; + } +#endif /* (DPAA_VERSION >= 11) */ + + err = fman_port_add_congestion_grps(&p_FmPort->port, grpsMap); + if (err != 0) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("fman_port_add_congestion_grps")); + + return E_OK; +} + +t_Error FM_PORT_RemoveCongestionGrps(t_Handle h_FmPort, + t_FmPortCongestionGrps *p_CongestionGrps) +{ + t_FmPort *p_FmPort = (t_FmPort*)h_FmPort; + uint8_t mod, index; + uint32_t i, grpsMap[FMAN_PORT_CG_MAP_NUM]; + int err; + + SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE); + + { +#ifdef FM_NO_OP_OBSERVED_CGS + t_FmRevisionInfo revInfo; + + FM_GetRevision(p_FmPort->h_Fm, &revInfo); + if (revInfo.majorRev != 4) + { + if ((p_FmPort->portType != e_FM_PORT_TYPE_RX_10G) && + (p_FmPort->portType != e_FM_PORT_TYPE_RX)) + RETURN_ERROR(MAJOR, E_NOT_SUPPORTED, ("Available for Rx ports only")); + } + else +#endif /* FM_NO_OP_OBSERVED_CGS */ + if ((p_FmPort->portType != e_FM_PORT_TYPE_RX_10G) + && (p_FmPort->portType != e_FM_PORT_TYPE_RX) + && (p_FmPort->portType != e_FM_PORT_TYPE_OH_OFFLINE_PARSING)) + RETURN_ERROR(MAJOR, E_NOT_SUPPORTED, + ("Available for Rx & OP ports only")); + } + + /* Prepare groups map array */ + memset(grpsMap, 0, FMAN_PORT_CG_MAP_NUM * sizeof(uint32_t)); + for (i = 0; i < p_CongestionGrps->numOfCongestionGrpsToConsider; i++) + { + index = (uint8_t)(p_CongestionGrps->congestionGrpsToConsider[i] / 32); + mod = (uint8_t)(p_CongestionGrps->congestionGrpsToConsider[i] % 32); + if (p_FmPort->fmRevInfo.majorRev != 4) + grpsMap[7 - index] |= (uint32_t)(1 << mod); + else + grpsMap[0] |= (uint32_t)(1 << mod); + } + +#if (DPAA_VERSION >= 11) + for (i = 0; i < p_CongestionGrps->numOfCongestionGrpsToConsider; i++) + { + t_Error err = FmSetCongestionGroupPFCpriority( + p_FmPort->h_Fm, p_CongestionGrps->congestionGrpsToConsider[i], + 0); + if (err) + return err; + } +#endif /* (DPAA_VERSION >= 11) */ + + err = fman_port_remove_congestion_grps(&p_FmPort->port, grpsMap); + if (err != 0) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, + ("fman_port_remove_congestion_grps")); + return E_OK; +} + +#if (DPAA_VERSION >= 11) +t_Error FM_PORT_GetIPv4OptionsCount(t_Handle h_FmPort, + uint32_t *p_Ipv4OptionsCount) +{ + t_FmPort *p_FmPort = (t_FmPort*)h_FmPort; + + SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR( + (p_FmPort->portType == e_FM_PORT_TYPE_OH_OFFLINE_PARSING), + E_INVALID_VALUE); + SANITY_CHECK_RETURN_ERROR(p_FmPort->p_ParamsPage, E_INVALID_STATE); + SANITY_CHECK_RETURN_ERROR(p_Ipv4OptionsCount, E_NULL_POINTER); + + *p_Ipv4OptionsCount = GET_UINT32(p_FmPort->p_ParamsPage->ipfOptionsCounter); + + return E_OK; +} +#endif /* (DPAA_VERSION >= 11) */ + +t_Error FM_PORT_ConfigDsarSupport(t_Handle h_FmPortRx, + t_FmPortDsarTablesSizes *params) +{ + t_FmPort *p_FmPort = (t_FmPort *)h_FmPortRx; + p_FmPort->deepSleepVars.autoResMaxSizes = XX_Malloc( + sizeof(struct t_FmPortDsarTablesSizes)); + memcpy(p_FmPort->deepSleepVars.autoResMaxSizes, params, + sizeof(struct t_FmPortDsarTablesSizes)); + return E_OK; +} + +static t_Error FmPortConfigAutoResForDeepSleepSupport1(t_FmPort *p_FmPort) +{ + uint32_t *param_page; + t_FmPortDsarTablesSizes *params = p_FmPort->deepSleepVars.autoResMaxSizes; + t_ArCommonDesc *ArCommonDescPtr; + uint32_t size = sizeof(t_ArCommonDesc); + // ARP + // should put here if (params->max_num_of_arp_entries)? + size = ROUND_UP(size,4); + size += sizeof(t_DsarArpDescriptor); + size += sizeof(t_DsarArpBindingEntry) * params->maxNumOfArpEntries; + size += sizeof(t_DsarArpStatistics); + //ICMPV4 + size = ROUND_UP(size,4); + size += sizeof(t_DsarIcmpV4Descriptor); + size += sizeof(t_DsarIcmpV4BindingEntry) * params->maxNumOfEchoIpv4Entries; + size += sizeof(t_DsarIcmpV4Statistics); + //ICMPV6 + size = ROUND_UP(size,4); + size += sizeof(t_DsarIcmpV6Descriptor); + size += sizeof(t_DsarIcmpV6BindingEntry) * params->maxNumOfEchoIpv6Entries; + size += sizeof(t_DsarIcmpV6Statistics); + //ND + size = ROUND_UP(size,4); + size += sizeof(t_DsarNdDescriptor); + size += sizeof(t_DsarIcmpV6BindingEntry) * params->maxNumOfNdpEntries; + size += sizeof(t_DsarIcmpV6Statistics); + //SNMP + size = ROUND_UP(size,4); + size += sizeof(t_DsarSnmpDescriptor); + size += sizeof(t_DsarSnmpIpv4AddrTblEntry) + * params->maxNumOfSnmpIPV4Entries; + size += sizeof(t_DsarSnmpIpv6AddrTblEntry) + * params->maxNumOfSnmpIPV6Entries; + size += sizeof(t_OidsTblEntry) * params->maxNumOfSnmpOidEntries; + size += params->maxNumOfSnmpOidChar; + size += sizeof(t_DsarIcmpV6Statistics); + //filters + size = ROUND_UP(size,4); + size += params->maxNumOfIpProtFiltering; + size = ROUND_UP(size,4); + size += params->maxNumOfUdpPortFiltering * sizeof(t_PortTblEntry); + size = ROUND_UP(size,4); + size += params->maxNumOfTcpPortFiltering * sizeof(t_PortTblEntry); + + // add here for more protocols + + // statistics + size = ROUND_UP(size,4); + size += sizeof(t_ArStatistics); + + ArCommonDescPtr = FM_MURAM_AllocMem(p_FmPort->h_FmMuram, size, 0x10); + + param_page = + XX_PhysToVirt( + p_FmPort->fmMuramPhysBaseAddr + + GET_UINT32(p_FmPort->p_FmPortBmiRegs->rxPortBmiRegs.fmbm_rgpr)); + WRITE_UINT32( + *param_page, + (uint32_t)(XX_VirtToPhys(ArCommonDescPtr) - p_FmPort->fmMuramPhysBaseAddr)); + return E_OK; +} + +t_FmPortDsarTablesSizes* FM_PORT_GetDsarTablesMaxSizes(t_Handle h_FmPortRx) +{ + t_FmPort *p_FmPort = (t_FmPort *)h_FmPortRx; + return p_FmPort->deepSleepVars.autoResMaxSizes; +} + +struct arOffsets +{ + uint32_t arp; + uint32_t nd; + uint32_t icmpv4; + uint32_t icmpv6; + uint32_t snmp; + uint32_t stats; + uint32_t filtIp; + uint32_t filtUdp; + uint32_t filtTcp; +}; + +static uint32_t AR_ComputeOffsets(struct arOffsets* of, + struct t_FmPortDsarParams *params, + t_FmPort *p_FmPort) +{ + uint32_t size = sizeof(t_ArCommonDesc); + // ARP + if (params->p_AutoResArpInfo) + { + size = ROUND_UP(size,4); + of->arp = size; + size += sizeof(t_DsarArpDescriptor); + size += sizeof(t_DsarArpBindingEntry) + * params->p_AutoResArpInfo->tableSize; + size += sizeof(t_DsarArpStatistics); + } + // ICMPV4 + if (params->p_AutoResEchoIpv4Info) + { + size = ROUND_UP(size,4); + of->icmpv4 = size; + size += sizeof(t_DsarIcmpV4Descriptor); + size += sizeof(t_DsarIcmpV4BindingEntry) + * params->p_AutoResEchoIpv4Info->tableSize; + size += sizeof(t_DsarIcmpV4Statistics); + } + // ICMPV6 + if (params->p_AutoResEchoIpv6Info) + { + size = ROUND_UP(size,4); + of->icmpv6 = size; + size += sizeof(t_DsarIcmpV6Descriptor); + size += sizeof(t_DsarIcmpV6BindingEntry) + * params->p_AutoResEchoIpv6Info->tableSize; + size += sizeof(t_DsarIcmpV6Statistics); + } + // ND + if (params->p_AutoResNdpInfo) + { + size = ROUND_UP(size,4); + of->nd = size; + size += sizeof(t_DsarNdDescriptor); + size += sizeof(t_DsarIcmpV6BindingEntry) + * (params->p_AutoResNdpInfo->tableSizeAssigned + + params->p_AutoResNdpInfo->tableSizeTmp); + size += sizeof(t_DsarIcmpV6Statistics); + } + // SNMP + if (params->p_AutoResSnmpInfo) + { + size = ROUND_UP(size,4); + of->snmp = size; + size += sizeof(t_DsarSnmpDescriptor); + size += sizeof(t_DsarSnmpIpv4AddrTblEntry) + * params->p_AutoResSnmpInfo->numOfIpv4Addresses; + size += sizeof(t_DsarSnmpIpv6AddrTblEntry) + * params->p_AutoResSnmpInfo->numOfIpv6Addresses; + size += sizeof(t_OidsTblEntry) * params->p_AutoResSnmpInfo->oidsTblSize; + size += p_FmPort->deepSleepVars.autoResMaxSizes->maxNumOfSnmpOidChar; + size += sizeof(t_DsarIcmpV6Statistics); + } + //filters + size = ROUND_UP(size,4); + if (params->p_AutoResFilteringInfo) + { + of->filtIp = size; + size += params->p_AutoResFilteringInfo->ipProtTableSize; + size = ROUND_UP(size,4); + of->filtUdp = size; + size += params->p_AutoResFilteringInfo->udpPortsTableSize + * sizeof(t_PortTblEntry); + size = ROUND_UP(size,4); + of->filtTcp = size; + size += params->p_AutoResFilteringInfo->tcpPortsTableSize + * sizeof(t_PortTblEntry); + } + // add here for more protocols + // statistics + size = ROUND_UP(size,4); + of->stats = size; + size += sizeof(t_ArStatistics); + return size; +} + +uint32_t* ARDesc; +void PrsEnable(t_Handle p_FmPcd); +void PrsDisable(t_Handle p_FmPcd); +int PrsIsEnabled(t_Handle p_FmPcd); +t_Handle FM_PCD_GetHcPort(t_Handle h_FmPcd); + +static t_Error DsarCheckParams(t_FmPortDsarParams *params, + t_FmPortDsarTablesSizes *sizes) +{ + bool macInit = FALSE; + uint8_t mac[6]; + int i = 0; + + // check table sizes + if (params->p_AutoResArpInfo + && sizes->maxNumOfArpEntries < params->p_AutoResArpInfo->tableSize) + RETURN_ERROR( + MAJOR, E_INVALID_VALUE, + ("DSAR: Arp table size exceeds the configured maximum size.")); + if (params->p_AutoResEchoIpv4Info + && sizes->maxNumOfEchoIpv4Entries + < params->p_AutoResEchoIpv4Info->tableSize) + RETURN_ERROR( + MAJOR, + E_INVALID_VALUE, + ("DSAR: EchoIpv4 table size exceeds the configured maximum size.")); + if (params->p_AutoResNdpInfo + && sizes->maxNumOfNdpEntries + < params->p_AutoResNdpInfo->tableSizeAssigned + + params->p_AutoResNdpInfo->tableSizeTmp) + RETURN_ERROR( + MAJOR, E_INVALID_VALUE, + ("DSAR: NDP table size exceeds the configured maximum size.")); + if (params->p_AutoResEchoIpv6Info + && sizes->maxNumOfEchoIpv6Entries + < params->p_AutoResEchoIpv6Info->tableSize) + RETURN_ERROR( + MAJOR, + E_INVALID_VALUE, + ("DSAR: EchoIpv6 table size exceeds the configured maximum size.")); + if (params->p_AutoResSnmpInfo + && sizes->maxNumOfSnmpOidEntries + < params->p_AutoResSnmpInfo->oidsTblSize) + RETURN_ERROR( + MAJOR, + E_INVALID_VALUE, + ("DSAR: Snmp Oid table size exceeds the configured maximum size.")); + if (params->p_AutoResSnmpInfo + && sizes->maxNumOfSnmpIPV4Entries + < params->p_AutoResSnmpInfo->numOfIpv4Addresses) + RETURN_ERROR( + MAJOR, + E_INVALID_VALUE, + ("DSAR: Snmp ipv4 table size exceeds the configured maximum size.")); + if (params->p_AutoResSnmpInfo + && sizes->maxNumOfSnmpIPV6Entries + < params->p_AutoResSnmpInfo->numOfIpv6Addresses) + RETURN_ERROR( + MAJOR, + E_INVALID_VALUE, + ("DSAR: Snmp ipv6 table size exceeds the configured maximum size.")); + if (params->p_AutoResFilteringInfo) + { + if (sizes->maxNumOfIpProtFiltering + < params->p_AutoResFilteringInfo->ipProtTableSize) + RETURN_ERROR( + MAJOR, + E_INVALID_VALUE, + ("DSAR: ip filter table size exceeds the configured maximum size.")); + if (sizes->maxNumOfTcpPortFiltering + < params->p_AutoResFilteringInfo->udpPortsTableSize) + RETURN_ERROR( + MAJOR, + E_INVALID_VALUE, + ("DSAR: udp filter table size exceeds the configured maximum size.")); + if (sizes->maxNumOfUdpPortFiltering + < params->p_AutoResFilteringInfo->tcpPortsTableSize) + RETURN_ERROR( + MAJOR, + E_INVALID_VALUE, + ("DSAR: tcp filter table size exceeds the configured maximum size.")); + } + /* check only 1 MAC address is configured (this is what ucode currently supports) */ + if (params->p_AutoResArpInfo && params->p_AutoResArpInfo->tableSize) + { + memcpy(mac, params->p_AutoResArpInfo->p_AutoResTable[0].mac, 6); + i = 1; + macInit = TRUE; + + for (; i < params->p_AutoResArpInfo->tableSize; i++) + if (memcmp(mac, params->p_AutoResArpInfo->p_AutoResTable[i].mac, 6)) + RETURN_ERROR( + MAJOR, E_INVALID_VALUE, + ("DSAR: Only 1 mac address is currently supported.")); + } + if (params->p_AutoResEchoIpv4Info + && params->p_AutoResEchoIpv4Info->tableSize) + { + i = 0; + if (!macInit) + { + memcpy(mac, params->p_AutoResEchoIpv4Info->p_AutoResTable[0].mac, + 6); + i = 1; + macInit = TRUE; + } + for (; i < params->p_AutoResEchoIpv4Info->tableSize; i++) + if (memcmp(mac, + params->p_AutoResEchoIpv4Info->p_AutoResTable[i].mac, 6)) + RETURN_ERROR( + MAJOR, E_INVALID_VALUE, + ("DSAR: Only 1 mac address is currently supported.")); + } + if (params->p_AutoResEchoIpv6Info + && params->p_AutoResEchoIpv6Info->tableSize) + { + i = 0; + if (!macInit) + { + memcpy(mac, params->p_AutoResEchoIpv6Info->p_AutoResTable[0].mac, + 6); + i = 1; + macInit = TRUE; + } + for (; i < params->p_AutoResEchoIpv6Info->tableSize; i++) + if (memcmp(mac, + params->p_AutoResEchoIpv6Info->p_AutoResTable[i].mac, 6)) + RETURN_ERROR( + MAJOR, E_INVALID_VALUE, + ("DSAR: Only 1 mac address is currently supported.")); + } + if (params->p_AutoResNdpInfo && params->p_AutoResNdpInfo->tableSizeAssigned) + { + i = 0; + if (!macInit) + { + memcpy(mac, params->p_AutoResNdpInfo->p_AutoResTableAssigned[0].mac, + 6); + i = 1; + macInit = TRUE; + } + for (; i < params->p_AutoResNdpInfo->tableSizeAssigned; i++) + if (memcmp(mac, + params->p_AutoResNdpInfo->p_AutoResTableAssigned[i].mac, + 6)) + RETURN_ERROR( + MAJOR, E_INVALID_VALUE, + ("DSAR: Only 1 mac address is currently supported.")); + } + if (params->p_AutoResNdpInfo && params->p_AutoResNdpInfo->tableSizeTmp) + { + i = 0; + if (!macInit) + { + memcpy(mac, params->p_AutoResNdpInfo->p_AutoResTableTmp[0].mac, 6); + i = 1; + } + for (; i < params->p_AutoResNdpInfo->tableSizeTmp; i++) + if (memcmp(mac, params->p_AutoResNdpInfo->p_AutoResTableTmp[i].mac, + 6)) + RETURN_ERROR( + MAJOR, E_INVALID_VALUE, + ("DSAR: Only 1 mac address is currently supported.")); + } + return E_OK; +} + +static int GetBERLen(uint8_t* buf) +{ + if (*buf & 0x80) + { + if ((*buf & 0x7F) == 1) + return buf[1]; + else + return *(uint16_t*)&buf[1]; // assuming max len is 2 + } + else + return buf[0]; +} +#define TOTAL_BER_LEN(len) (len < 128) ? len + 2 : len + 3 + +#define SCFG_FMCLKDPSLPCR_ADDR 0xFFE0FC00C +#define SCFG_FMCLKDPSLPCR_DS_VAL 0x08402000 +#define SCFG_FMCLKDPSLPCR_NORMAL_VAL 0x00402000 +static int fm_soc_suspend(void) +{ + uint32_t *fmclk, tmp32; + fmclk = ioremap(SCFG_FMCLKDPSLPCR_ADDR, 4); + tmp32 = GET_UINT32(*fmclk); + WRITE_UINT32(*fmclk, SCFG_FMCLKDPSLPCR_DS_VAL); + tmp32 = GET_UINT32(*fmclk); + iounmap(fmclk); + return 0; +} + +void fm_clk_down(void) +{ + uint32_t *fmclk, tmp32; + fmclk = ioremap(SCFG_FMCLKDPSLPCR_ADDR, 4); + tmp32 = GET_UINT32(*fmclk); + WRITE_UINT32(*fmclk, SCFG_FMCLKDPSLPCR_DS_VAL | 0x40000000); + tmp32 = GET_UINT32(*fmclk); + iounmap(fmclk); +} + +t_Error FM_PORT_EnterDsar(t_Handle h_FmPortRx, t_FmPortDsarParams *params) +{ + int i, j; + t_Error err; + uint32_t nia; + t_FmPort *p_FmPort = (t_FmPort *)h_FmPortRx; + t_FmPort *p_FmPortTx = (t_FmPort *)params->h_FmPortTx; + t_DsarArpDescriptor *ArpDescriptor; + t_DsarIcmpV4Descriptor* ICMPV4Descriptor; + t_DsarIcmpV6Descriptor* ICMPV6Descriptor; + t_DsarNdDescriptor* NDDescriptor; + + uint64_t fmMuramVirtBaseAddr = (uint64_t)PTR_TO_UINT(XX_PhysToVirt(p_FmPort->fmMuramPhysBaseAddr)); + uint32_t *param_page = XX_PhysToVirt(p_FmPort->fmMuramPhysBaseAddr + GET_UINT32(p_FmPort->p_FmPortBmiRegs->rxPortBmiRegs.fmbm_rgpr)); + t_ArCommonDesc *ArCommonDescPtr = (t_ArCommonDesc*)(XX_PhysToVirt(p_FmPort->fmMuramPhysBaseAddr + GET_UINT32(*param_page))); + struct arOffsets* of; + uint8_t tmp = 0; + t_FmGetSetParams fmGetSetParams; + memset(&fmGetSetParams, 0, sizeof (t_FmGetSetParams)); + fmGetSetParams.setParams.type = UPDATE_FPM_BRKC_SLP; + fmGetSetParams.setParams.sleep = 1; + + err = DsarCheckParams(params, p_FmPort->deepSleepVars.autoResMaxSizes); + if (err != E_OK) + return err; + + p_FmPort->deepSleepVars.autoResOffsets = XX_Malloc(sizeof(struct arOffsets)); + of = (struct arOffsets *)p_FmPort->deepSleepVars.autoResOffsets; + IOMemSet32(ArCommonDescPtr, 0, AR_ComputeOffsets(of, params, p_FmPort)); + + // common + WRITE_UINT8(ArCommonDescPtr->arTxPort, p_FmPortTx->hardwarePortId); + nia = GET_UINT32(p_FmPort->p_FmPortBmiRegs->rxPortBmiRegs.fmbm_rfne); // bmi nia + if ((nia & 0x007C0000) == 0x00440000) // bmi nia is parser + WRITE_UINT32(ArCommonDescPtr->activeHPNIA, GET_UINT32(p_FmPort->p_FmPortBmiRegs->rxPortBmiRegs.fmbm_rfpne)); + else + WRITE_UINT32(ArCommonDescPtr->activeHPNIA, nia); + WRITE_UINT16(ArCommonDescPtr->snmpPort, 161); + + // ARP + if (params->p_AutoResArpInfo) + { + t_DsarArpBindingEntry* arp_bindings; + ArpDescriptor = (t_DsarArpDescriptor*)(PTR_TO_UINT(ArCommonDescPtr) + of->arp); + WRITE_UINT32(ArCommonDescPtr->p_ArpDescriptor, PTR_TO_UINT(ArpDescriptor) - fmMuramVirtBaseAddr); + arp_bindings = (t_DsarArpBindingEntry*)(PTR_TO_UINT(ArpDescriptor) + sizeof(t_DsarArpDescriptor)); + if (params->p_AutoResArpInfo->enableConflictDetection) + WRITE_UINT16(ArpDescriptor->control, 1); + else + WRITE_UINT16(ArpDescriptor->control, 0); + if (params->p_AutoResArpInfo->tableSize) + { + t_FmPortDsarArpEntry* arp_entry = params->p_AutoResArpInfo->p_AutoResTable; + WRITE_UINT16(*(uint16_t*)&ArCommonDescPtr->macStationAddr[0], *(uint16_t*)&arp_entry[0].mac[0]); + WRITE_UINT32(*(uint32_t*)&ArCommonDescPtr->macStationAddr[2], *(uint32_t*)&arp_entry[0].mac[2]); + WRITE_UINT16(ArpDescriptor->numOfBindings, params->p_AutoResArpInfo->tableSize); + + for (i = 0; i < params->p_AutoResArpInfo->tableSize; i++) + { + WRITE_UINT32(arp_bindings[i].ipv4Addr, arp_entry[i].ipAddress); + if (arp_entry[i].isVlan) + WRITE_UINT16(arp_bindings[i].vlanId, arp_entry[i].vid & 0xFFF); + } + WRITE_UINT32(ArpDescriptor->p_Bindings, PTR_TO_UINT(arp_bindings) - fmMuramVirtBaseAddr); + } + WRITE_UINT32(ArpDescriptor->p_Statistics, PTR_TO_UINT(arp_bindings) + + sizeof(t_DsarArpBindingEntry) * params->p_AutoResArpInfo->tableSize - fmMuramVirtBaseAddr); + } + + // ICMPV4 + if (params->p_AutoResEchoIpv4Info) + { + t_DsarIcmpV4BindingEntry* icmpv4_bindings; + ICMPV4Descriptor = (t_DsarIcmpV4Descriptor*)(PTR_TO_UINT(ArCommonDescPtr) + of->icmpv4); + WRITE_UINT32(ArCommonDescPtr->p_IcmpV4Descriptor, PTR_TO_UINT(ICMPV4Descriptor) - fmMuramVirtBaseAddr); + icmpv4_bindings = (t_DsarIcmpV4BindingEntry*)(PTR_TO_UINT(ICMPV4Descriptor) + sizeof(t_DsarIcmpV4Descriptor)); + WRITE_UINT16(ICMPV4Descriptor->control, 0); + if (params->p_AutoResEchoIpv4Info->tableSize) + { + t_FmPortDsarArpEntry* arp_entry = params->p_AutoResEchoIpv4Info->p_AutoResTable; + WRITE_UINT16(*(uint16_t*)&ArCommonDescPtr->macStationAddr[0], *(uint16_t*)&arp_entry[0].mac[0]); + WRITE_UINT32(*(uint32_t*)&ArCommonDescPtr->macStationAddr[2], *(uint32_t*)&arp_entry[0].mac[2]); + WRITE_UINT16(ICMPV4Descriptor->numOfBindings, params->p_AutoResEchoIpv4Info->tableSize); + + for (i = 0; i < params->p_AutoResEchoIpv4Info->tableSize; i++) + { + WRITE_UINT32(icmpv4_bindings[i].ipv4Addr, arp_entry[i].ipAddress); + if (arp_entry[i].isVlan) + WRITE_UINT16(icmpv4_bindings[i].vlanId, arp_entry[i].vid & 0xFFF); + } + WRITE_UINT32(ICMPV4Descriptor->p_Bindings, PTR_TO_UINT(icmpv4_bindings) - fmMuramVirtBaseAddr); + } + WRITE_UINT32(ICMPV4Descriptor->p_Statistics, PTR_TO_UINT(icmpv4_bindings) + + sizeof(t_DsarIcmpV4BindingEntry) * params->p_AutoResEchoIpv4Info->tableSize - fmMuramVirtBaseAddr); + } + + // ICMPV6 + if (params->p_AutoResEchoIpv6Info) + { + t_DsarIcmpV6BindingEntry* icmpv6_bindings; + ICMPV6Descriptor = (t_DsarIcmpV6Descriptor*)(PTR_TO_UINT(ArCommonDescPtr) + of->icmpv6); + WRITE_UINT32(ArCommonDescPtr->p_IcmpV6Descriptor, PTR_TO_UINT(ICMPV6Descriptor) - fmMuramVirtBaseAddr); + icmpv6_bindings = (t_DsarIcmpV6BindingEntry*)(PTR_TO_UINT(ICMPV6Descriptor) + sizeof(t_DsarIcmpV6Descriptor)); + WRITE_UINT16(ICMPV6Descriptor->control, 0); + if (params->p_AutoResEchoIpv6Info->tableSize) + { + t_FmPortDsarNdpEntry* ndp_entry = params->p_AutoResEchoIpv6Info->p_AutoResTable; + WRITE_UINT16(*(uint16_t*)&ArCommonDescPtr->macStationAddr[0], *(uint16_t*)&ndp_entry[0].mac[0]); + WRITE_UINT32(*(uint32_t*)&ArCommonDescPtr->macStationAddr[2], *(uint32_t*)&ndp_entry[0].mac[2]); + WRITE_UINT16(ICMPV6Descriptor->numOfBindings, params->p_AutoResEchoIpv6Info->tableSize); + + for (i = 0; i < params->p_AutoResEchoIpv6Info->tableSize; i++) + { + for (j = 0; j < 4; j++) + WRITE_UINT32(icmpv6_bindings[i].ipv6Addr[j], ndp_entry[i].ipAddress[j]); + if (ndp_entry[i].isVlan) + WRITE_UINT16(*(uint16_t*)&icmpv6_bindings[i].ipv6Addr[4], ndp_entry[i].vid & 0xFFF); // writing vlan + } + WRITE_UINT32(ICMPV6Descriptor->p_Bindings, PTR_TO_UINT(icmpv6_bindings) - fmMuramVirtBaseAddr); + } + WRITE_UINT32(ICMPV6Descriptor->p_Statistics, PTR_TO_UINT(icmpv6_bindings) + + sizeof(t_DsarIcmpV6BindingEntry) * params->p_AutoResEchoIpv6Info->tableSize - fmMuramVirtBaseAddr); + } + + // ND + if (params->p_AutoResNdpInfo) + { + t_DsarIcmpV6BindingEntry* icmpv6_bindings; + NDDescriptor = (t_DsarNdDescriptor*)(PTR_TO_UINT(ArCommonDescPtr) + of->nd); + WRITE_UINT32(ArCommonDescPtr->p_NdDescriptor, PTR_TO_UINT(NDDescriptor) - fmMuramVirtBaseAddr); + icmpv6_bindings = (t_DsarIcmpV6BindingEntry*)(PTR_TO_UINT(NDDescriptor) + sizeof(t_DsarNdDescriptor)); + if (params->p_AutoResNdpInfo->enableConflictDetection) + WRITE_UINT16(NDDescriptor->control, 1); + else + WRITE_UINT16(NDDescriptor->control, 0); + if (params->p_AutoResNdpInfo->tableSizeAssigned + params->p_AutoResNdpInfo->tableSizeTmp) + { + t_FmPortDsarNdpEntry* ndp_entry = params->p_AutoResNdpInfo->p_AutoResTableAssigned; + WRITE_UINT16(*(uint16_t*)&ArCommonDescPtr->macStationAddr[0], *(uint16_t*)&ndp_entry[0].mac[0]); + WRITE_UINT32(*(uint32_t*)&ArCommonDescPtr->macStationAddr[2], *(uint32_t*)&ndp_entry[0].mac[2]); + WRITE_UINT16(NDDescriptor->numOfBindings, params->p_AutoResNdpInfo->tableSizeAssigned + + params->p_AutoResNdpInfo->tableSizeTmp); + + for (i = 0; i < params->p_AutoResNdpInfo->tableSizeAssigned; i++) + { + for (j = 0; j < 4; j++) + WRITE_UINT32(icmpv6_bindings[i].ipv6Addr[j], ndp_entry[i].ipAddress[j]); + if (ndp_entry[i].isVlan) + WRITE_UINT16(*(uint16_t*)&icmpv6_bindings[i].ipv6Addr[4], ndp_entry[i].vid & 0xFFF); // writing vlan + } + ndp_entry = params->p_AutoResNdpInfo->p_AutoResTableTmp; + for (i = 0; i < params->p_AutoResNdpInfo->tableSizeTmp; i++) + { + for (j = 0; j < 4; j++) + WRITE_UINT32(icmpv6_bindings[i + params->p_AutoResNdpInfo->tableSizeAssigned].ipv6Addr[j], ndp_entry[i].ipAddress[j]); + if (ndp_entry[i].isVlan) + WRITE_UINT16(*(uint16_t*)&icmpv6_bindings[i + params->p_AutoResNdpInfo->tableSizeAssigned].ipv6Addr[4], ndp_entry[i].vid & 0xFFF); // writing vlan + } + WRITE_UINT32(NDDescriptor->p_Bindings, PTR_TO_UINT(icmpv6_bindings) - fmMuramVirtBaseAddr); + } + WRITE_UINT32(NDDescriptor->p_Statistics, PTR_TO_UINT(icmpv6_bindings) + sizeof(t_DsarIcmpV6BindingEntry) + * (params->p_AutoResNdpInfo->tableSizeAssigned + params->p_AutoResNdpInfo->tableSizeTmp) + - fmMuramVirtBaseAddr); + WRITE_UINT32(NDDescriptor->solicitedAddr, 0xFFFFFFFF); + } + + // SNMP + if (params->p_AutoResSnmpInfo) + { + t_FmPortDsarSnmpInfo *snmpSrc = params->p_AutoResSnmpInfo; + t_DsarSnmpIpv4AddrTblEntry* snmpIpv4Addr; + t_DsarSnmpIpv6AddrTblEntry* snmpIpv6Addr; + t_OidsTblEntry* snmpOid; + uint8_t *charPointer; + int len; + t_DsarSnmpDescriptor* SnmpDescriptor = (t_DsarSnmpDescriptor*)(PTR_TO_UINT(ArCommonDescPtr) + of->snmp); + WRITE_UINT32(ArCommonDescPtr->p_SnmpDescriptor, PTR_TO_UINT(SnmpDescriptor) - fmMuramVirtBaseAddr); + WRITE_UINT16(SnmpDescriptor->control, snmpSrc->control); + WRITE_UINT16(SnmpDescriptor->maxSnmpMsgLength, snmpSrc->maxSnmpMsgLength); + snmpIpv4Addr = (t_DsarSnmpIpv4AddrTblEntry*)(PTR_TO_UINT(SnmpDescriptor) + sizeof(t_DsarSnmpDescriptor)); + if (snmpSrc->numOfIpv4Addresses) + { + t_FmPortDsarSnmpIpv4AddrTblEntry* snmpIpv4AddrSrc = snmpSrc->p_Ipv4AddrTbl; + WRITE_UINT16(SnmpDescriptor->numOfIpv4Addresses, snmpSrc->numOfIpv4Addresses); + for (i = 0; i < snmpSrc->numOfIpv4Addresses; i++) + { + WRITE_UINT32(snmpIpv4Addr[i].ipv4Addr, snmpIpv4AddrSrc[i].ipv4Addr); + if (snmpIpv4AddrSrc[i].isVlan) + WRITE_UINT16(snmpIpv4Addr[i].vlanId, snmpIpv4AddrSrc[i].vid & 0xFFF); + } + WRITE_UINT32(SnmpDescriptor->p_Ipv4AddrTbl, PTR_TO_UINT(snmpIpv4Addr) - fmMuramVirtBaseAddr); + } + snmpIpv6Addr = (t_DsarSnmpIpv6AddrTblEntry*)(PTR_TO_UINT(snmpIpv4Addr) + + sizeof(t_DsarSnmpIpv4AddrTblEntry) * snmpSrc->numOfIpv4Addresses); + if (snmpSrc->numOfIpv6Addresses) + { + t_FmPortDsarSnmpIpv6AddrTblEntry* snmpIpv6AddrSrc = snmpSrc->p_Ipv6AddrTbl; + WRITE_UINT16(SnmpDescriptor->numOfIpv6Addresses, snmpSrc->numOfIpv6Addresses); + for (i = 0; i < snmpSrc->numOfIpv6Addresses; i++) + { + for (j = 0; j < 4; j++) + WRITE_UINT32(snmpIpv6Addr[i].ipv6Addr[j], snmpIpv6AddrSrc[i].ipv6Addr[j]); + if (snmpIpv6AddrSrc[i].isVlan) + WRITE_UINT16(snmpIpv6Addr[i].vlanId, snmpIpv6AddrSrc[i].vid & 0xFFF); + } + WRITE_UINT32(SnmpDescriptor->p_Ipv6AddrTbl, PTR_TO_UINT(snmpIpv6Addr) - fmMuramVirtBaseAddr); + } + snmpOid = (t_OidsTblEntry*)(PTR_TO_UINT(snmpIpv6Addr) + + sizeof(t_DsarSnmpIpv6AddrTblEntry) * snmpSrc->numOfIpv6Addresses); + charPointer = (uint8_t*)(PTR_TO_UINT(snmpOid) + + sizeof(t_OidsTblEntry) * snmpSrc->oidsTblSize); + len = TOTAL_BER_LEN(GetBERLen(&snmpSrc->p_RdOnlyCommunityStr[1])); + Mem2IOCpy32(charPointer, snmpSrc->p_RdOnlyCommunityStr, len); + WRITE_UINT32(SnmpDescriptor->p_RdOnlyCommunityStr, PTR_TO_UINT(charPointer) - fmMuramVirtBaseAddr); + charPointer += len; + len = TOTAL_BER_LEN(GetBERLen(&snmpSrc->p_RdWrCommunityStr[1])); + Mem2IOCpy32(charPointer, snmpSrc->p_RdWrCommunityStr, len); + WRITE_UINT32(SnmpDescriptor->p_RdWrCommunityStr, PTR_TO_UINT(charPointer) - fmMuramVirtBaseAddr); + charPointer += len; + WRITE_UINT32(SnmpDescriptor->oidsTblSize, snmpSrc->oidsTblSize); + WRITE_UINT32(SnmpDescriptor->p_OidsTbl, PTR_TO_UINT(snmpOid) - fmMuramVirtBaseAddr); + for (i = 0; i < snmpSrc->oidsTblSize; i++) + { + WRITE_UINT16(snmpOid->oidSize, snmpSrc->p_OidsTbl[i].oidSize); + WRITE_UINT16(snmpOid->resSize, snmpSrc->p_OidsTbl[i].resSize); + Mem2IOCpy32(charPointer, snmpSrc->p_OidsTbl[i].oidVal, snmpSrc->p_OidsTbl[i].oidSize); + WRITE_UINT32(snmpOid->p_Oid, PTR_TO_UINT(charPointer) - fmMuramVirtBaseAddr); + charPointer += snmpSrc->p_OidsTbl[i].oidSize; + if (snmpSrc->p_OidsTbl[i].resSize <= 4) + WRITE_UINT32(snmpOid->resValOrPtr, *snmpSrc->p_OidsTbl[i].resVal); + else + { + Mem2IOCpy32(charPointer, snmpSrc->p_OidsTbl[i].resVal, snmpSrc->p_OidsTbl[i].resSize); + WRITE_UINT32(snmpOid->resValOrPtr, PTR_TO_UINT(charPointer) - fmMuramVirtBaseAddr); + charPointer += snmpSrc->p_OidsTbl[i].resSize; + } + snmpOid++; + } + charPointer = UINT_TO_PTR(ROUND_UP(PTR_TO_UINT(charPointer),4)); + WRITE_UINT32(SnmpDescriptor->p_Statistics, PTR_TO_UINT(charPointer) - fmMuramVirtBaseAddr); + } + + // filtering + if (params->p_AutoResFilteringInfo) + { + if (params->p_AutoResFilteringInfo->ipProtPassOnHit) + tmp |= IP_PROT_TBL_PASS_MASK; + if (params->p_AutoResFilteringInfo->udpPortPassOnHit) + tmp |= UDP_PORT_TBL_PASS_MASK; + if (params->p_AutoResFilteringInfo->tcpPortPassOnHit) + tmp |= TCP_PORT_TBL_PASS_MASK; + WRITE_UINT8(ArCommonDescPtr->filterControl, tmp); + WRITE_UINT16(ArCommonDescPtr->tcpControlPass, params->p_AutoResFilteringInfo->tcpFlagsMask); + + // ip filtering + if (params->p_AutoResFilteringInfo->ipProtTableSize) + { + uint8_t* ip_tbl = (uint8_t*)(PTR_TO_UINT(ArCommonDescPtr) + of->filtIp); + WRITE_UINT8(ArCommonDescPtr->ipProtocolTblSize, params->p_AutoResFilteringInfo->ipProtTableSize); + for (i = 0; i < params->p_AutoResFilteringInfo->ipProtTableSize; i++) + WRITE_UINT8(ip_tbl[i], params->p_AutoResFilteringInfo->p_IpProtTablePtr[i]); + WRITE_UINT32(ArCommonDescPtr->p_IpProtocolFiltTbl, PTR_TO_UINT(ip_tbl) - fmMuramVirtBaseAddr); + } + + // udp filtering + if (params->p_AutoResFilteringInfo->udpPortsTableSize) + { + t_PortTblEntry* udp_tbl = (t_PortTblEntry*)(PTR_TO_UINT(ArCommonDescPtr) + of->filtUdp); + WRITE_UINT8(ArCommonDescPtr->udpPortTblSize, params->p_AutoResFilteringInfo->udpPortsTableSize); + for (i = 0; i < params->p_AutoResFilteringInfo->udpPortsTableSize; i++) + { + WRITE_UINT32(udp_tbl[i].Ports, + (params->p_AutoResFilteringInfo->p_UdpPortsTablePtr[i].srcPort << 16) + + params->p_AutoResFilteringInfo->p_UdpPortsTablePtr[i].dstPort); + WRITE_UINT32(udp_tbl[i].PortsMask, + (params->p_AutoResFilteringInfo->p_UdpPortsTablePtr[i].srcPortMask << 16) + + params->p_AutoResFilteringInfo->p_UdpPortsTablePtr[i].dstPortMask); + } + WRITE_UINT32(ArCommonDescPtr->p_UdpPortFiltTbl, PTR_TO_UINT(udp_tbl) - fmMuramVirtBaseAddr); + } + + // tcp filtering + if (params->p_AutoResFilteringInfo->tcpPortsTableSize) + { + t_PortTblEntry* tcp_tbl = (t_PortTblEntry*)(PTR_TO_UINT(ArCommonDescPtr) + of->filtTcp); + WRITE_UINT8(ArCommonDescPtr->tcpPortTblSize, params->p_AutoResFilteringInfo->tcpPortsTableSize); + for (i = 0; i < params->p_AutoResFilteringInfo->tcpPortsTableSize; i++) + { + WRITE_UINT32(tcp_tbl[i].Ports, + (params->p_AutoResFilteringInfo->p_TcpPortsTablePtr[i].srcPort << 16) + + params->p_AutoResFilteringInfo->p_TcpPortsTablePtr[i].dstPort); + WRITE_UINT32(tcp_tbl[i].PortsMask, + (params->p_AutoResFilteringInfo->p_TcpPortsTablePtr[i].srcPortMask << 16) + + params->p_AutoResFilteringInfo->p_TcpPortsTablePtr[i].dstPortMask); + } + WRITE_UINT32(ArCommonDescPtr->p_TcpPortFiltTbl, PTR_TO_UINT(tcp_tbl) - fmMuramVirtBaseAddr); + } + } + // common stats + WRITE_UINT32(ArCommonDescPtr->p_ArStats, PTR_TO_UINT(ArCommonDescPtr) + of->stats - fmMuramVirtBaseAddr); + + // get into Deep Sleep sequence: + + // Ensures that FMan do not enter the idle state. This is done by programing + // FMDPSLPCR[FM_STOP] to one. + fm_soc_suspend(); + + ARDesc = UINT_TO_PTR(XX_VirtToPhys(ArCommonDescPtr)); + return E_OK; + +} + +void FM_ChangeClock(t_Handle h_Fm, int hardwarePortId); +t_Error FM_PORT_EnterDsarFinal(t_Handle h_DsarRxPort, t_Handle h_DsarTxPort) +{ + t_FmGetSetParams fmGetSetParams; + t_FmPort *p_FmPort = (t_FmPort *)h_DsarRxPort; + t_FmPort *p_FmPortTx = (t_FmPort *)h_DsarTxPort; + t_Handle *h_FmPcd = FmGetPcd(p_FmPort->h_Fm); + t_FmPort *p_FmPortHc = FM_PCD_GetHcPort(h_FmPcd); + memset(&fmGetSetParams, 0, sizeof (t_FmGetSetParams)); + fmGetSetParams.setParams.type = UPDATE_FM_CLD; + FmGetSetParams(p_FmPort->h_Fm, &fmGetSetParams); + + /* Issue graceful stop to HC port */ + FM_PORT_Disable(p_FmPortHc); + + // config tx port + p_FmPort->deepSleepVars.fmbm_tcfg = GET_UINT32(p_FmPortTx->p_FmPortBmiRegs->txPortBmiRegs.fmbm_tcfg); + WRITE_UINT32(p_FmPortTx->p_FmPortBmiRegs->txPortBmiRegs.fmbm_tcfg, GET_UINT32(p_FmPortTx->p_FmPortBmiRegs->txPortBmiRegs.fmbm_tcfg) | BMI_PORT_CFG_IM | BMI_PORT_CFG_EN); + // ???? + p_FmPort->deepSleepVars.fmbm_tcmne = GET_UINT32(p_FmPortTx->p_FmPortBmiRegs->txPortBmiRegs.fmbm_tcmne); + WRITE_UINT32(p_FmPortTx->p_FmPortBmiRegs->txPortBmiRegs.fmbm_tcmne, 0xE); + // Stage 7:echo + p_FmPort->deepSleepVars.fmbm_rfpne = GET_UINT32(p_FmPort->p_FmPortBmiRegs->rxPortBmiRegs.fmbm_rfpne); + WRITE_UINT32(p_FmPort->p_FmPortBmiRegs->rxPortBmiRegs.fmbm_rfpne, 0x2E); + if (!PrsIsEnabled(h_FmPcd)) + { + p_FmPort->deepSleepVars.dsarEnabledParser = TRUE; + PrsEnable(h_FmPcd); + } + else + p_FmPort->deepSleepVars.dsarEnabledParser = FALSE; + + p_FmPort->deepSleepVars.fmbm_rfne = GET_UINT32(p_FmPort->p_FmPortBmiRegs->rxPortBmiRegs.fmbm_rfne); + WRITE_UINT32(p_FmPort->p_FmPortBmiRegs->rxPortBmiRegs.fmbm_rfne, 0x440000); + + // save rcfg for restoring: accumulate mode is changed by ucode + p_FmPort->deepSleepVars.fmbm_rcfg = GET_UINT32(p_FmPort->port.bmi_regs->rx.fmbm_rcfg); + WRITE_UINT32(p_FmPort->port.bmi_regs->rx.fmbm_rcfg, p_FmPort->deepSleepVars.fmbm_rcfg | BMI_PORT_CFG_AM); + memset(&fmGetSetParams, 0, sizeof (t_FmGetSetParams)); + fmGetSetParams.setParams.type = UPDATE_FPM_BRKC_SLP; + fmGetSetParams.setParams.sleep = 1; + FmGetSetParams(p_FmPort->h_Fm, &fmGetSetParams); + +// ***** issue external request sync command + memset(&fmGetSetParams, 0, sizeof (t_FmGetSetParams)); + fmGetSetParams.setParams.type = UPDATE_FPM_EXTC; + FmGetSetParams(p_FmPort->h_Fm, &fmGetSetParams); + // get + memset(&fmGetSetParams, 0, sizeof (t_FmGetSetParams)); + fmGetSetParams.getParams.type = GET_FMFP_EXTC; + FmGetSetParams(p_FmPort->h_Fm, &fmGetSetParams); + if (fmGetSetParams.getParams.fmfp_extc != 0) + { + // clear + memset(&fmGetSetParams, 0, sizeof (t_FmGetSetParams)); + fmGetSetParams.setParams.type = UPDATE_FPM_EXTC_CLEAR; + FmGetSetParams(p_FmPort->h_Fm, &fmGetSetParams); +} + + memset(&fmGetSetParams, 0, sizeof (t_FmGetSetParams)); + fmGetSetParams.getParams.type = GET_FMFP_EXTC | GET_FM_NPI; + do + { + FmGetSetParams(p_FmPort->h_Fm, &fmGetSetParams); + } while (fmGetSetParams.getParams.fmfp_extc != 0 && fmGetSetParams.getParams.fm_npi == 0); + if (fmGetSetParams.getParams.fm_npi != 0) + XX_Print("FM: Sync did not finish\n"); + + // check that all stoped + memset(&fmGetSetParams, 0, sizeof (t_FmGetSetParams)); + fmGetSetParams.getParams.type = GET_FMQM_GS | GET_FM_NPI; + FmGetSetParams(p_FmPort->h_Fm, &fmGetSetParams); + while (fmGetSetParams.getParams.fmqm_gs & 0xF0000000) + FmGetSetParams(p_FmPort->h_Fm, &fmGetSetParams); + if (fmGetSetParams.getParams.fmqm_gs == 0 && fmGetSetParams.getParams.fm_npi == 0) + XX_Print("FM: Sleeping\n"); +// FM_ChangeClock(p_FmPort->h_Fm, p_FmPort->hardwarePortId); + + return E_OK; +} + +EXPORT_SYMBOL(FM_PORT_EnterDsarFinal); + +void FM_PORT_Dsar_DumpRegs() +{ + uint32_t* hh = XX_PhysToVirt(PTR_TO_UINT(ARDesc)); + DUMP_MEMORY(hh, 0x220); +} + +void FM_PORT_ExitDsar(t_Handle h_FmPortRx, t_Handle h_FmPortTx) +{ + t_FmPort *p_FmPort = (t_FmPort *)h_FmPortRx; + t_FmPort *p_FmPortTx = (t_FmPort *)h_FmPortTx; + t_Handle *h_FmPcd = FmGetPcd(p_FmPort->h_Fm); + t_FmPort *p_FmPortHc = FM_PCD_GetHcPort(h_FmPcd); + t_FmGetSetParams fmGetSetParams; + memset(&fmGetSetParams, 0, sizeof (t_FmGetSetParams)); + fmGetSetParams.setParams.type = UPDATE_FPM_BRKC_SLP; + fmGetSetParams.setParams.sleep = 0; + if (p_FmPort->deepSleepVars.autoResOffsets) + { + XX_Free(p_FmPort->deepSleepVars.autoResOffsets); + p_FmPort->deepSleepVars.autoResOffsets = 0; + } + + if (p_FmPort->deepSleepVars.dsarEnabledParser) + PrsDisable(FmGetPcd(p_FmPort->h_Fm)); + WRITE_UINT32(p_FmPort->p_FmPortBmiRegs->rxPortBmiRegs.fmbm_rfpne, p_FmPort->deepSleepVars.fmbm_rfpne); + WRITE_UINT32(p_FmPort->p_FmPortBmiRegs->rxPortBmiRegs.fmbm_rfne, p_FmPort->deepSleepVars.fmbm_rfne); + WRITE_UINT32(p_FmPort->p_FmPortBmiRegs->rxPortBmiRegs.fmbm_rcfg, p_FmPort->deepSleepVars.fmbm_rcfg); + FmGetSetParams(p_FmPort->h_Fm, &fmGetSetParams); + WRITE_UINT32(p_FmPortTx->p_FmPortBmiRegs->txPortBmiRegs.fmbm_tcmne, p_FmPort->deepSleepVars.fmbm_tcmne); + WRITE_UINT32(p_FmPortTx->p_FmPortBmiRegs->txPortBmiRegs.fmbm_tcfg, p_FmPort->deepSleepVars.fmbm_tcfg); + FM_PORT_Enable(p_FmPortHc); +} + +bool FM_PORT_IsInDsar(t_Handle h_FmPort) +{ + t_FmPort *p_FmPort = (t_FmPort *)h_FmPort; + return PTR_TO_UINT(p_FmPort->deepSleepVars.autoResOffsets); +} + +t_Error FM_PORT_GetDsarStats(t_Handle h_FmPortRx, t_FmPortDsarStats *stats) +{ + t_FmPort *p_FmPort = (t_FmPort *)h_FmPortRx; + struct arOffsets *of = (struct arOffsets*)p_FmPort->deepSleepVars.autoResOffsets; + uint8_t* fmMuramVirtBaseAddr = XX_PhysToVirt(p_FmPort->fmMuramPhysBaseAddr); + uint32_t *param_page = XX_PhysToVirt(p_FmPort->fmMuramPhysBaseAddr + GET_UINT32(p_FmPort->p_FmPortBmiRegs->rxPortBmiRegs.fmbm_rgpr)); + t_ArCommonDesc *ArCommonDescPtr = (t_ArCommonDesc*)(XX_PhysToVirt(p_FmPort->fmMuramPhysBaseAddr + GET_UINT32(*param_page))); + t_DsarArpDescriptor *ArpDescriptor = (t_DsarArpDescriptor*)(PTR_TO_UINT(ArCommonDescPtr) + of->arp); + t_DsarArpStatistics* arp_stats = (t_DsarArpStatistics*)(PTR_TO_UINT(ArpDescriptor->p_Statistics) + fmMuramVirtBaseAddr); + t_DsarIcmpV4Descriptor* ICMPV4Descriptor = (t_DsarIcmpV4Descriptor*)(PTR_TO_UINT(ArCommonDescPtr) + of->icmpv4); + t_DsarIcmpV4Statistics* icmpv4_stats = (t_DsarIcmpV4Statistics*)(PTR_TO_UINT(ICMPV4Descriptor->p_Statistics) + fmMuramVirtBaseAddr); + t_DsarNdDescriptor* NDDescriptor = (t_DsarNdDescriptor*)(PTR_TO_UINT(ArCommonDescPtr) + of->nd); + t_NdStatistics* nd_stats = (t_NdStatistics*)(PTR_TO_UINT(NDDescriptor->p_Statistics) + fmMuramVirtBaseAddr); + t_DsarIcmpV6Descriptor* ICMPV6Descriptor = (t_DsarIcmpV6Descriptor*)(PTR_TO_UINT(ArCommonDescPtr) + of->icmpv6); + t_DsarIcmpV6Statistics* icmpv6_stats = (t_DsarIcmpV6Statistics*)(PTR_TO_UINT(ICMPV6Descriptor->p_Statistics) + fmMuramVirtBaseAddr); + t_DsarSnmpDescriptor* SnmpDescriptor = (t_DsarSnmpDescriptor*)(PTR_TO_UINT(ArCommonDescPtr) + of->snmp); + t_DsarSnmpStatistics* snmp_stats = (t_DsarSnmpStatistics*)(PTR_TO_UINT(SnmpDescriptor->p_Statistics) + fmMuramVirtBaseAddr); + stats->arpArCnt = arp_stats->arCnt; + stats->echoIcmpv4ArCnt = icmpv4_stats->arCnt; + stats->ndpArCnt = nd_stats->arCnt; + stats->echoIcmpv6ArCnt = icmpv6_stats->arCnt; + stats->snmpGetCnt = snmp_stats->snmpGetReqCnt; + stats->snmpGetNextCnt = snmp_stats->snmpGetNextReqCnt; + return E_OK; +} diff --git a/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Port/fm_port.h b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Port/fm_port.h new file mode 100644 index 000000000000..85986f553c3f --- /dev/null +++ b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Port/fm_port.h @@ -0,0 +1,999 @@ +/* + * Copyright 2008-2012 Freescale Semiconductor Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Freescale Semiconductor nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * + * ALTERNATIVELY, this software may be distributed under the terms of the + * GNU General Public License ("GPL") as published by the Free Software + * Foundation, either version 2 of that License or (at your option) any + * later version. + * + * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + +/****************************************************************************** + @File fm_port.h + + @Description FM Port internal structures and definitions. +*//***************************************************************************/ +#ifndef __FM_PORT_H +#define __FM_PORT_H + +#include "error_ext.h" +#include "std_ext.h" +#include "fm_port_ext.h" + +#include "fm_common.h" +#include "fm_sp_common.h" +#include "fsl_fman_sp.h" +#include "fm_port_ext.h" +#include "fsl_fman_port.h" + +#define __ERR_MODULE__ MODULE_FM_PORT + + +#define MIN_EXT_BUF_SIZE 64 +#define DATA_ALIGNMENT 64 +#define MAX_LIODN_OFFSET 64 +#define MAX_PORT_FIFO_SIZE MIN(BMI_MAX_FIFO_SIZE, 1024*BMI_FIFO_UNITS) + +/**************************************************************************//** + @Description Memory Map defines +*//***************************************************************************/ +#define BMI_PORT_REGS_OFFSET 0 +#define QMI_PORT_REGS_OFFSET 0x400 +#define PRS_PORT_REGS_OFFSET 0x800 + +/**************************************************************************//** + @Description defaults +*//***************************************************************************/ +#define DEFAULT_PORT_deqHighPriority_1G FALSE +#define DEFAULT_PORT_deqHighPriority_10G TRUE +#define DEFAULT_PORT_deqType e_FM_PORT_DEQ_TYPE1 +#define DEFAULT_PORT_deqPrefetchOption e_FM_PORT_DEQ_FULL_PREFETCH +#define DEFAULT_PORT_deqPrefetchOption_HC e_FM_PORT_DEQ_NO_PREFETCH +#define DEFAULT_PORT_deqByteCnt_10G 0x1400 +#define DEFAULT_PORT_deqByteCnt_1G 0x400 +#define DEFAULT_PORT_bufferPrefixContent_privDataSize DEFAULT_FM_SP_bufferPrefixContent_privDataSize +#define DEFAULT_PORT_bufferPrefixContent_passPrsResult DEFAULT_FM_SP_bufferPrefixContent_passPrsResult +#define DEFAULT_PORT_bufferPrefixContent_passTimeStamp DEFAULT_FM_SP_bufferPrefixContent_passTimeStamp +#define DEFAULT_PORT_bufferPrefixContent_allOtherPCDInfo DEFAULT_FM_SP_bufferPrefixContent_allOtherPCDInfo +#define DEFAULT_PORT_bufferPrefixContent_dataAlign DEFAULT_FM_SP_bufferPrefixContent_dataAlign +#define DEFAULT_PORT_cheksumLastBytesIgnore 0 +#define DEFAULT_PORT_cutBytesFromEnd 4 +#define DEFAULT_PORT_fifoDeqPipelineDepth_IM 2 + +#define DEFAULT_PORT_frmDiscardOverride FALSE + +#define DEFAULT_PORT_dmaSwapData (e_FmDmaSwapOption)DEFAULT_FMAN_SP_DMA_SWAP_DATA +#define DEFAULT_PORT_dmaIntContextCacheAttr (e_FmDmaCacheOption)DEFAULT_FMAN_SP_DMA_INT_CONTEXT_CACHE_ATTR +#define DEFAULT_PORT_dmaHeaderCacheAttr (e_FmDmaCacheOption)DEFAULT_FMAN_SP_DMA_HEADER_CACHE_ATTR +#define DEFAULT_PORT_dmaScatterGatherCacheAttr (e_FmDmaCacheOption)DEFAULT_FMAN_SP_DMA_SCATTER_GATHER_CACHE_ATTR +#define DEFAULT_PORT_dmaWriteOptimize DEFAULT_FMAN_SP_DMA_WRITE_OPTIMIZE + +#define DEFAULT_PORT_noScatherGather DEFAULT_FMAN_SP_NO_SCATTER_GATHER +#define DEFAULT_PORT_forwardIntContextReuse FALSE +#define DEFAULT_PORT_BufMargins_startMargins 32 +#define DEFAULT_PORT_BufMargins_endMargins 0 +#define DEFAULT_PORT_syncReq TRUE +#define DEFAULT_PORT_syncReqForHc FALSE +#define DEFAULT_PORT_color e_FM_PORT_COLOR_GREEN +#define DEFAULT_PORT_errorsToDiscard FM_PORT_FRM_ERR_CLS_DISCARD +/* #define DEFAULT_PORT_dualRateLimitScaleDown e_FM_PORT_DUAL_RATE_LIMITER_NONE */ +/* #define DEFAULT_PORT_rateLimitBurstSizeHighGranularity FALSE */ +#define DEFAULT_PORT_exception IM_EV_BSY +#define DEFAULT_PORT_maxFrameLength 9600 + +#define DEFAULT_notSupported 0xff + +#if (DPAA_VERSION < 11) +#define DEFAULT_PORT_rxFifoPriElevationLevel MAX_PORT_FIFO_SIZE +#define DEFAULT_PORT_rxFifoThreshold (MAX_PORT_FIFO_SIZE*3/4) + +#define DEFAULT_PORT_txFifoMinFillLevel 0 +#define DEFAULT_PORT_txFifoLowComfLevel (5*KILOBYTE) +#define DEFAULT_PORT_fifoDeqPipelineDepth_1G 1 +#define DEFAULT_PORT_fifoDeqPipelineDepth_10G 4 + +#define DEFAULT_PORT_fifoDeqPipelineDepth_OH 2 + +/* Host command port MUST NOT be changed to more than 1 !!! */ +#define DEFAULT_PORT_numOfTasks(type) \ + (uint32_t)((((type) == e_FM_PORT_TYPE_RX_10G) || \ + ((type) == e_FM_PORT_TYPE_TX_10G)) ? 16 : \ + ((((type) == e_FM_PORT_TYPE_RX) || \ + ((type) == e_FM_PORT_TYPE_TX) || \ + ((type) == e_FM_PORT_TYPE_OH_OFFLINE_PARSING)) ? 3 : 1)) + +#define DEFAULT_PORT_extraNumOfTasks(type) \ + (uint32_t)(((type) == e_FM_PORT_TYPE_RX_10G) ? 8 : \ + (((type) == e_FM_PORT_TYPE_RX) ? 2 : 0)) + +#define DEFAULT_PORT_numOfOpenDmas(type) \ + (uint32_t)((((type) == e_FM_PORT_TYPE_TX_10G) || \ + ((type) == e_FM_PORT_TYPE_RX_10G)) ? 8 : 1 ) + +#define DEFAULT_PORT_extraNumOfOpenDmas(type) \ + (uint32_t)(((type) == e_FM_PORT_TYPE_RX_10G) ? 8 : \ + (((type) == e_FM_PORT_TYPE_RX) ? 1 : 0)) + +#define DEFAULT_PORT_numOfFifoBufs(type) \ + (uint32_t)((((type) == e_FM_PORT_TYPE_RX_10G) || \ + ((type) == e_FM_PORT_TYPE_TX_10G)) ? 48 : \ + ((type) == e_FM_PORT_TYPE_RX) ? 45 : \ + ((type) == e_FM_PORT_TYPE_TX) ? 44 : 8) + +#define DEFAULT_PORT_extraNumOfFifoBufs 0 + +#else /* (DPAA_VERSION < 11) */ +/* Defaults are registers' reset values */ +#define DEFAULT_PORT_rxFifoPriElevationLevel MAX_PORT_FIFO_SIZE +#define DEFAULT_PORT_rxFifoThreshold MAX_PORT_FIFO_SIZE + +#define DEFAULT_PORT_txFifoMinFillLevel 0 +#define DEFAULT_PORT_txFifoLowComfLevel (5 * KILOBYTE) +#define DEFAULT_PORT_fifoDeqPipelineDepth_1G 2 +#define DEFAULT_PORT_fifoDeqPipelineDepth_10G 4 + +#define DEFAULT_PORT_fifoDeqPipelineDepth_OH 2 + +#define DEFAULT_PORT_numOfTasks(type) \ + (uint32_t)((((type) == e_FM_PORT_TYPE_RX_10G) || \ + ((type) == e_FM_PORT_TYPE_TX_10G)) ? 14 : \ + (((type) == e_FM_PORT_TYPE_RX) || \ + ((type) == e_FM_PORT_TYPE_TX)) ? 4 : \ + ((type) == e_FM_PORT_TYPE_OH_OFFLINE_PARSING) ? 6 : 1) + +#define DEFAULT_PORT_extraNumOfTasks(type) 0 + +#define DEFAULT_PORT_numOfOpenDmas(type) \ + (uint32_t)(((type) == e_FM_PORT_TYPE_RX_10G) ? 8 : \ + ((type) == e_FM_PORT_TYPE_TX_10G) ? 12 : \ + ((type) == e_FM_PORT_TYPE_RX) ? 2 : \ + ((type) == e_FM_PORT_TYPE_TX) ? 3 : \ + ((type) == e_FM_PORT_TYPE_OH_HOST_COMMAND) ? 2 : 4) + +#define DEFAULT_PORT_extraNumOfOpenDmas(type) 0 + +#define DEFAULT_PORT_numOfFifoBufs(type) \ + (uint32_t) (((type) == e_FM_PORT_TYPE_RX_10G) ? 96 : \ + ((type) == e_FM_PORT_TYPE_TX_10G) ? 64 : \ + ((type) == e_FM_PORT_TYPE_OH_HOST_COMMAND) ? 10 : 50) + +#define DEFAULT_PORT_extraNumOfFifoBufs 0 + +#endif /* (DPAA_VERSION < 11) */ + +#define DEFAULT_PORT_txBdRingLength 16 +#define DEFAULT_PORT_rxBdRingLength 128 +#define DEFAULT_PORT_ImfwExtStructsMemId 0 +#define DEFAULT_PORT_ImfwExtStructsMemAttr MEMORY_ATTR_CACHEABLE + +#define FM_PORT_CG_REG_NUM(_cgId) (((FM_PORT_NUM_OF_CONGESTION_GRPS/32)-1)-_cgId/32) + +/**************************************************************************//** + @Collection PCD Engines +*//***************************************************************************/ +typedef uint32_t fmPcdEngines_t; /**< options as defined below: */ + +#define FM_PCD_NONE 0 /**< No PCD Engine indicated */ +#define FM_PCD_PRS 0x80000000 /**< Parser indicated */ +#define FM_PCD_KG 0x40000000 /**< Keygen indicated */ +#define FM_PCD_CC 0x20000000 /**< Coarse classification indicated */ +#define FM_PCD_PLCR 0x10000000 /**< Policer indicated */ +#define FM_PCD_MANIP 0x08000000 /**< Manipulation indicated */ +/* @} */ + +#define FM_PORT_MAX_NUM_OF_EXT_POOLS_ALL_INTEGRATIONS 8 +#define FM_PORT_MAX_NUM_OF_CONGESTION_GRPS_ALL_INTEGRATIONS 256 +#define FM_PORT_CG_REG_NUM(_cgId) (((FM_PORT_NUM_OF_CONGESTION_GRPS/32)-1)-_cgId/32) + +#define FM_OH_PORT_ID 0 + +/***********************************************************************/ +/* SW parser OFFLOAD labels (offsets) */ +/***********************************************************************/ +#if (DPAA_VERSION == 10) +#define OFFLOAD_SW_PATCH_IPv4_IPR_LABEL 0x300 +#define OFFLOAD_SW_PATCH_IPv6_IPR_LABEL 0x325 +#define OFFLOAD_SW_PATCH_IPv6_IPF_LABEL 0x325 +#else +#define OFFLOAD_SW_PATCH_IPv4_IPR_LABEL 0x100 +/* Will be used for: + * 1. identify fragments + * 2. udp-lite + */ +#define OFFLOAD_SW_PATCH_IPv6_IPR_LABEL 0x146 +/* Will be used for: + * 1. will identify the fragmentable area + * 2. udp-lite + */ +#define OFFLOAD_SW_PATCH_IPv6_IPF_LABEL 0x261 +#define OFFLOAD_SW_PATCH_CAPWAP_LABEL 0x38d +#endif /* (DPAA_VERSION == 10) */ + +#if ((DPAA_VERSION == 10) && defined(FM_CAPWAP_SUPPORT)) +#define UDP_LITE_SW_PATCH_LABEL 0x2E0 +#endif /* ((DPAA_VERSION == 10) && defined(FM_CAPWAP_SUPPORT)) */ + + +/**************************************************************************//** + @Description Memory Mapped Registers +*//***************************************************************************/ + +#if defined(__MWERKS__) && !defined(__GNUC__) +#pragma pack(push,1) +#endif /* defined(__MWERKS__) && ... */ + +typedef struct +{ + volatile uint32_t fmbm_rcfg; /**< Rx Configuration */ + volatile uint32_t fmbm_rst; /**< Rx Status */ + volatile uint32_t fmbm_rda; /**< Rx DMA attributes*/ + volatile uint32_t fmbm_rfp; /**< Rx FIFO Parameters*/ + volatile uint32_t fmbm_rfed; /**< Rx Frame End Data*/ + volatile uint32_t fmbm_ricp; /**< Rx Internal Context Parameters*/ + volatile uint32_t fmbm_rim; /**< Rx Internal Buffer Margins*/ + volatile uint32_t fmbm_rebm; /**< Rx External Buffer Margins*/ + volatile uint32_t fmbm_rfne; /**< Rx Frame Next Engine*/ + volatile uint32_t fmbm_rfca; /**< Rx Frame Command Attributes.*/ + volatile uint32_t fmbm_rfpne; /**< Rx Frame Parser Next Engine*/ + volatile uint32_t fmbm_rpso; /**< Rx Parse Start Offset*/ + volatile uint32_t fmbm_rpp; /**< Rx Policer Profile */ + volatile uint32_t fmbm_rccb; /**< Rx Coarse Classification Base */ + volatile uint32_t fmbm_reth; /**< Rx Excessive Threshold */ + volatile uint32_t reserved1[0x01];/**< (0x03C) */ + volatile uint32_t fmbm_rprai[FM_PORT_PRS_RESULT_NUM_OF_WORDS]; + /**< Rx Parse Results Array Initialization*/ + volatile uint32_t fmbm_rfqid; /**< Rx Frame Queue ID*/ + volatile uint32_t fmbm_refqid; /**< Rx Error Frame Queue ID*/ + volatile uint32_t fmbm_rfsdm; /**< Rx Frame Status Discard Mask*/ + volatile uint32_t fmbm_rfsem; /**< Rx Frame Status Error Mask*/ + volatile uint32_t fmbm_rfene; /**< Rx Frame Enqueue Next Engine */ + volatile uint32_t reserved2[0x02];/**< (0x074-0x078) */ + volatile uint32_t fmbm_rcmne; /**< Rx Frame Continuous Mode Next Engine */ + volatile uint32_t reserved3[0x20];/**< (0x080 0x0FF) */ + volatile uint32_t fmbm_ebmpi[FM_PORT_MAX_NUM_OF_EXT_POOLS_ALL_INTEGRATIONS]; + /**< Buffer Manager pool Information-*/ + volatile uint32_t fmbm_acnt[FM_PORT_MAX_NUM_OF_EXT_POOLS_ALL_INTEGRATIONS]; + /**< Allocate Counter-*/ + volatile uint32_t reserved4[0x08]; + /**< 0x130/0x140 - 0x15F reserved -*/ + volatile uint32_t fmbm_rcgm[FM_PORT_MAX_NUM_OF_CONGESTION_GRPS_ALL_INTEGRATIONS/32]; + /**< Congestion Group Map*/ + volatile uint32_t fmbm_rmpd; /**< BM Pool Depletion */ + volatile uint32_t reserved5[0x1F];/**< (0x184 0x1FF) */ + volatile uint32_t fmbm_rstc; /**< Rx Statistics Counters*/ + volatile uint32_t fmbm_rfrc; /**< Rx Frame Counter*/ + volatile uint32_t fmbm_rfbc; /**< Rx Bad Frames Counter*/ + volatile uint32_t fmbm_rlfc; /**< Rx Large Frames Counter*/ + volatile uint32_t fmbm_rffc; /**< Rx Filter Frames Counter*/ + volatile uint32_t fmbm_rfcd; /**< Rx Frame Discard Counter*/ + volatile uint32_t fmbm_rfldec; /**< Rx Frames List DMA Error Counter*/ + volatile uint32_t fmbm_rodc; /**< Rx Out of Buffers Discard Counter-*/ + volatile uint32_t fmbm_rbdc; /**< Rx Buffers Deallocate Counter-*/ + volatile uint32_t fmbm_rpec; /**< Rx RX Prepare to enqueue Counter-*/ + volatile uint32_t reserved6[0x16];/**< (0x228 0x27F) */ + volatile uint32_t fmbm_rpc; /**< Rx Performance Counters*/ + volatile uint32_t fmbm_rpcp; /**< Rx Performance Count Parameters*/ + volatile uint32_t fmbm_rccn; /**< Rx Cycle Counter*/ + volatile uint32_t fmbm_rtuc; /**< Rx Tasks Utilization Counter*/ + volatile uint32_t fmbm_rrquc; /**< Rx Receive Queue Utilization Counter*/ + volatile uint32_t fmbm_rduc; /**< Rx DMA Utilization Counter*/ + volatile uint32_t fmbm_rfuc; /**< Rx FIFO Utilization Counter*/ + volatile uint32_t fmbm_rpac; /**< Rx Pause Activation Counter*/ + volatile uint32_t reserved7[0x18];/**< (0x2A0-0x2FF) */ + volatile uint32_t fmbm_rdcfg[0x3];/**< Rx Debug-*/ + volatile uint32_t fmbm_rgpr; /**< Rx General Purpose Register. */ + volatile uint32_t reserved8[0x3a];/**< (0x310-0x3FF) */ +} t_FmPortRxBmiRegs; + +typedef struct +{ + volatile uint32_t fmbm_tcfg; /**< Tx Configuration */ + volatile uint32_t fmbm_tst; /**< Tx Status */ + volatile uint32_t fmbm_tda; /**< Tx DMA attributes */ + volatile uint32_t fmbm_tfp; /**< Tx FIFO Parameters */ + volatile uint32_t fmbm_tfed; /**< Tx Frame End Data */ + volatile uint32_t fmbm_ticp; /**< Tx Internal Context Parameters */ + volatile uint32_t fmbm_tfdne; /**< Tx Frame Dequeue Next Engine. */ + volatile uint32_t fmbm_tfca; /**< Tx Frame Command attribute. */ + volatile uint32_t fmbm_tcfqid; /**< Tx Confirmation Frame Queue ID. */ + volatile uint32_t fmbm_tfeqid; /**< Tx Frame Error Queue ID */ + volatile uint32_t fmbm_tfene; /**< Tx Frame Enqueue Next Engine */ + volatile uint32_t fmbm_trlmts; /**< Tx Rate Limiter Scale */ + volatile uint32_t fmbm_trlmt; /**< Tx Rate Limiter */ + volatile uint32_t fmbm_tccb; /**< Tx Coarse Classification Base */ + volatile uint32_t reserved0[0x0e];/**< (0x038-0x070) */ + volatile uint32_t fmbm_tfne; /**< Tx Frame Next Engine */ + volatile uint32_t fmbm_tpfcm[0x02];/**< Tx Priority based Flow Control (PFC) Mapping */ + volatile uint32_t fmbm_tcmne; /**< Tx Frame Continuous Mode Next Engine */ + volatile uint32_t reserved2[0x60];/**< (0x080-0x200) */ + volatile uint32_t fmbm_tstc; /**< Tx Statistics Counters */ + volatile uint32_t fmbm_tfrc; /**< Tx Frame Counter */ + volatile uint32_t fmbm_tfdc; /**< Tx Frames Discard Counter */ + volatile uint32_t fmbm_tfledc; /**< Tx Frame Length error discard counter */ + volatile uint32_t fmbm_tfufdc; /**< Tx Frame unsupported format discard Counter */ + volatile uint32_t fmbm_tbdc; /**< Tx Buffers Deallocate Counter */ + volatile uint32_t reserved3[0x1A];/**< (0x218-0x280) */ + volatile uint32_t fmbm_tpc; /**< Tx Performance Counters*/ + volatile uint32_t fmbm_tpcp; /**< Tx Performance Count Parameters*/ + volatile uint32_t fmbm_tccn; /**< Tx Cycle Counter*/ + volatile uint32_t fmbm_ttuc; /**< Tx Tasks Utilization Counter*/ + volatile uint32_t fmbm_ttcquc; /**< Tx Transmit Confirm Queue Utilization Counter*/ + volatile uint32_t fmbm_tduc; /**< Tx DMA Utilization Counter*/ + volatile uint32_t fmbm_tfuc; /**< Tx FIFO Utilization Counter*/ + volatile uint32_t reserved4[16]; /**< (0x29C-0x2FF) */ + volatile uint32_t fmbm_tdcfg[0x3];/**< Tx Debug-*/ + volatile uint32_t fmbm_tgpr; /**< O/H General Purpose Register */ + volatile uint32_t reserved5[0x3a];/**< (0x310-0x3FF) */ +} t_FmPortTxBmiRegs; + +typedef struct +{ + volatile uint32_t fmbm_ocfg; /**< O/H Configuration */ + volatile uint32_t fmbm_ost; /**< O/H Status */ + volatile uint32_t fmbm_oda; /**< O/H DMA attributes */ + volatile uint32_t fmbm_oicp; /**< O/H Internal Context Parameters */ + volatile uint32_t fmbm_ofdne; /**< O/H Frame Dequeue Next Engine */ + volatile uint32_t fmbm_ofne; /**< O/H Frame Next Engine */ + volatile uint32_t fmbm_ofca; /**< O/H Frame Command Attributes. */ + volatile uint32_t fmbm_ofpne; /**< O/H Frame Parser Next Engine */ + volatile uint32_t fmbm_opso; /**< O/H Parse Start Offset */ + volatile uint32_t fmbm_opp; /**< O/H Policer Profile */ + volatile uint32_t fmbm_occb; /**< O/H Coarse Classification base */ + volatile uint32_t fmbm_oim; /**< O/H Internal margins*/ + volatile uint32_t fmbm_ofp; /**< O/H Fifo Parameters*/ + volatile uint32_t fmbm_ofed; /**< O/H Frame End Data*/ + volatile uint32_t reserved0[2]; /**< (0x038 - 0x03F) */ + volatile uint32_t fmbm_oprai[FM_PORT_PRS_RESULT_NUM_OF_WORDS]; + /**< O/H Parse Results Array Initialization */ + volatile uint32_t fmbm_ofqid; /**< O/H Frame Queue ID */ + volatile uint32_t fmbm_oefqid; /**< O/H Error Frame Queue ID */ + volatile uint32_t fmbm_ofsdm; /**< O/H Frame Status Discard Mask */ + volatile uint32_t fmbm_ofsem; /**< O/H Frame Status Error Mask */ + volatile uint32_t fmbm_ofene; /**< O/H Frame Enqueue Next Engine */ + volatile uint32_t fmbm_orlmts; /**< O/H Rate Limiter Scale */ + volatile uint32_t fmbm_orlmt; /**< O/H Rate Limiter */ + volatile uint32_t fmbm_ocmne; /**< O/H Continuous Mode Next Engine */ + volatile uint32_t reserved1[0x20];/**< (0x080 - 0x0FF) */ + volatile uint32_t fmbm_oebmpi[2]; /**< Buffer Manager Observed Pool Information */ + volatile uint32_t reserved2[0x16];/**< (0x108 - 0x15F) */ + volatile uint32_t fmbm_ocgm; /**< Observed Congestion Group Map */ + volatile uint32_t reserved3[0x7]; /**< (0x164 - 0x17F) */ + volatile uint32_t fmbm_ompd; /**< Observed BMan Pool Depletion */ + volatile uint32_t reserved4[0x1F];/**< (0x184 - 0x1FF) */ + volatile uint32_t fmbm_ostc; /**< O/H Statistics Counters */ + volatile uint32_t fmbm_ofrc; /**< O/H Frame Counter */ + volatile uint32_t fmbm_ofdc; /**< O/H Frames Discard Counter */ + volatile uint32_t fmbm_ofledc; /**< O/H Frames Length Error Discard Counter */ + volatile uint32_t fmbm_ofufdc; /**< O/H Frames Unsupported Format Discard Counter */ + volatile uint32_t fmbm_offc; /**< O/H Filter Frames Counter */ + volatile uint32_t fmbm_ofwdc; /**< - Rx Frames WRED Discard Counter */ + volatile uint32_t fmbm_ofldec; /**< O/H Frames List DMA Error Counter */ + volatile uint32_t fmbm_obdc; /**< O/H Buffers Deallocate Counter */ + volatile uint32_t fmbm_oodc; /**< O/H Out of Buffers Discard Counter */ + volatile uint32_t fmbm_opec; /**< O/H Prepare to enqueue Counter */ + volatile uint32_t reserved5[0x15];/**< ( - 0x27F) */ + volatile uint32_t fmbm_opc; /**< O/H Performance Counters */ + volatile uint32_t fmbm_opcp; /**< O/H Performance Count Parameters */ + volatile uint32_t fmbm_occn; /**< O/H Cycle Counter */ + volatile uint32_t fmbm_otuc; /**< O/H Tasks Utilization Counter */ + volatile uint32_t fmbm_oduc; /**< O/H DMA Utilization Counter */ + volatile uint32_t fmbm_ofuc; /**< O/H FIFO Utilization Counter */ + volatile uint32_t reserved6[26]; /**< (0x298-0x2FF) */ + volatile uint32_t fmbm_odcfg[0x3];/**< O/H Debug (only 1 in P1023) */ + volatile uint32_t fmbm_ogpr; /**< O/H General Purpose Register. */ + volatile uint32_t reserved7[0x3a];/**< (0x310 0x3FF) */ +} t_FmPortOhBmiRegs; + +typedef union +{ + t_FmPortRxBmiRegs rxPortBmiRegs; + t_FmPortTxBmiRegs txPortBmiRegs; + t_FmPortOhBmiRegs ohPortBmiRegs; +} u_FmPortBmiRegs; + +typedef struct +{ + volatile uint32_t reserved1[2]; /**< 0xn024 - 0x02B */ + volatile uint32_t fmqm_pndn; /**< PortID n Dequeue NIA Register */ + volatile uint32_t fmqm_pndc; /**< PortID n Dequeue Config Register */ + volatile uint32_t fmqm_pndtfc; /**< PortID n Dequeue Total Frame Counter */ + volatile uint32_t fmqm_pndfdc; /**< PortID n Dequeue FQID from Default Counter */ + volatile uint32_t fmqm_pndcc; /**< PortID n Dequeue Confirm Counter */ +} t_FmPortNonRxQmiRegs; + +typedef struct +{ + volatile uint32_t fmqm_pnc; /**< PortID n Configuration Register */ + volatile uint32_t fmqm_pns; /**< PortID n Status Register */ + volatile uint32_t fmqm_pnts; /**< PortID n Task Status Register */ + volatile uint32_t reserved0[4]; /**< 0xn00C - 0xn01B */ + volatile uint32_t fmqm_pnen; /**< PortID n Enqueue NIA Register */ + volatile uint32_t fmqm_pnetfc; /**< PortID n Enqueue Total Frame Counter */ + t_FmPortNonRxQmiRegs nonRxQmiRegs; /**< Registers for Tx Hc & Op ports */ +} t_FmPortQmiRegs; + +typedef struct +{ + struct + { + volatile uint32_t softSeqAttach; /**< Soft Sequence Attachment */ + volatile uint32_t lcv; /**< Line-up Enable Confirmation Mask */ + } hdrs[FM_PCD_PRS_NUM_OF_HDRS]; + volatile uint32_t reserved0[0xde]; + volatile uint32_t pcac; /**< Parse Internal Memory Configuration Access Control Register */ + volatile uint32_t pctpid; /**< Parse Internal Memory Configured TPID Register */ +} t_FmPortPrsRegs; + +/**************************************************************************//* + @Description Basic buffer descriptor (BD) structure +*//***************************************************************************/ +typedef _Packed struct +{ + volatile uint16_t status; + volatile uint16_t length; + volatile uint8_t reserved0[0x6]; + volatile uint8_t reserved1[0x1]; + volatile t_FmPhysAddr buff; +} _PackedType t_FmImBd; + +typedef _Packed struct +{ + volatile uint16_t gen; /**< tbd */ + volatile uint8_t reserved0[0x1]; + volatile t_FmPhysAddr bdRingBase; /**< tbd */ + volatile uint16_t bdRingSize; /**< tbd */ + volatile uint16_t offsetIn; /**< tbd */ + volatile uint16_t offsetOut; /**< tbd */ + volatile uint8_t reserved1[0x12]; /**< 0x0e - 0x1f */ +} _PackedType t_FmPortImQd; + +typedef _Packed struct +{ + volatile uint32_t mode; /**< Mode register */ + volatile uint32_t rxQdPtr; /**< tbd */ + volatile uint32_t txQdPtr; /**< tbd */ + volatile uint16_t mrblr; /**< tbd */ + volatile uint16_t rxQdBsyCnt; /**< tbd */ + volatile uint8_t reserved0[0x10]; /**< 0x10 - 0x1f */ + t_FmPortImQd rxQd; + t_FmPortImQd txQd; + volatile uint8_t reserved1[0xa0]; /**< 0x60 - 0xff */ +} _PackedType t_FmPortImPram; + +#if defined(__MWERKS__) && !defined(__GNUC__) +#pragma pack(pop) +#endif /* defined(__MWERKS__) && ... */ + + +/**************************************************************************//** + @Description Registers bit fields +*//***************************************************************************/ + +/**************************************************************************//** + @Description BMI defines +*//***************************************************************************/ +#if (DPAA_VERSION >= 11) +#define BMI_SP_ID_MASK 0xff000000 +#define BMI_SP_ID_SHIFT 24 +#define BMI_SP_EN 0x01000000 +#endif /* (DPAA_VERSION >= 11) */ + +#define BMI_PORT_CFG_EN 0x80000000 +#define BMI_PORT_CFG_EN_MACSEC 0x00800000 +#define BMI_PORT_CFG_FDOVR 0x02000000 +#define BMI_PORT_CFG_IM 0x01000000 +#define BMI_PORT_CFG_AM 0x00000040 +#define BMI_PORT_STATUS_BSY 0x80000000 +#define BMI_COUNTERS_EN 0x80000000 + +#define BMI_PORT_RFNE_FRWD_DCL4C 0x10000000 +#define BMI_PORT_RFNE_FRWD_RPD 0x40000000 +#define BMI_RFNE_FDCS_MASK 0xFF000000 +#define BMI_RFNE_HXS_MASK 0x000000FF + +#define BMI_CMD_MR_LEAC 0x00200000 +#define BMI_CMD_MR_SLEAC 0x00100000 +#define BMI_CMD_MR_MA 0x00080000 +#define BMI_CMD_MR_DEAS 0x00040000 +#define BMI_CMD_RX_MR_DEF (BMI_CMD_MR_LEAC | \ + BMI_CMD_MR_SLEAC | \ + BMI_CMD_MR_MA | \ + BMI_CMD_MR_DEAS) +#define BMI_CMD_ATTR_ORDER 0x80000000 +#define BMI_CMD_ATTR_SYNC 0x02000000 +#define BMI_CMD_ATTR_MODE_MISS_ALLIGN_ADDR_EN 0x00080000 +#define BMI_CMD_ATTR_MACCMD_MASK 0x0000ff00 +#define BMI_CMD_ATTR_MACCMD_OVERRIDE 0x00008000 +#define BMI_CMD_ATTR_MACCMD_SECURED 0x00001000 +#define BMI_CMD_ATTR_MACCMD_SC_MASK 0x00000f00 + +#define BMI_EXT_BUF_POOL_ID_MASK 0x003F0000 +#define BMI_STATUS_RX_MASK_UNUSED (uint32_t)(~(FM_PORT_FRM_ERR_DMA | \ + FM_PORT_FRM_ERR_PHYSICAL | \ + FM_PORT_FRM_ERR_SIZE | \ + FM_PORT_FRM_ERR_CLS_DISCARD | \ + FM_PORT_FRM_ERR_EXTRACTION | \ + FM_PORT_FRM_ERR_NO_SCHEME | \ + FM_PORT_FRM_ERR_COLOR_RED | \ + FM_PORT_FRM_ERR_COLOR_YELLOW | \ + FM_PORT_FRM_ERR_ILL_PLCR | \ + FM_PORT_FRM_ERR_PLCR_FRAME_LEN | \ + FM_PORT_FRM_ERR_PRS_TIMEOUT | \ + FM_PORT_FRM_ERR_PRS_ILL_INSTRUCT | \ + FM_PORT_FRM_ERR_BLOCK_LIMIT_EXCEEDED | \ + FM_PORT_FRM_ERR_PRS_HDR_ERR | \ + FM_PORT_FRM_ERR_IPRE | \ + FM_PORT_FRM_ERR_IPR_NCSP | \ + FM_PORT_FRM_ERR_KEYSIZE_OVERFLOW)) + +#define BMI_STATUS_OP_MASK_UNUSED (uint32_t)(BMI_STATUS_RX_MASK_UNUSED & \ + ~(FM_PORT_FRM_ERR_LENGTH | \ + FM_PORT_FRM_ERR_NON_FM | \ + FM_PORT_FRM_ERR_UNSUPPORTED_FORMAT)) + +#define BMI_RATE_LIMIT_EN 0x80000000 +#define BMI_RATE_LIMIT_BURST_SIZE_GRAN 0x80000000 +#define BMI_RATE_LIMIT_SCALE_BY_2 0x00000001 +#define BMI_RATE_LIMIT_SCALE_BY_4 0x00000002 +#define BMI_RATE_LIMIT_SCALE_BY_8 0x00000003 + +#define BMI_RX_FIFO_THRESHOLD_BC 0x80000000 + +#define BMI_PRS_RESULT_HIGH 0x00000000 +#define BMI_PRS_RESULT_LOW 0xFFFFFFFF + + +#define RX_ERRS_TO_ENQ (FM_PORT_FRM_ERR_DMA | \ + FM_PORT_FRM_ERR_PHYSICAL | \ + FM_PORT_FRM_ERR_SIZE | \ + FM_PORT_FRM_ERR_EXTRACTION | \ + FM_PORT_FRM_ERR_NO_SCHEME | \ + FM_PORT_FRM_ERR_ILL_PLCR | \ + FM_PORT_FRM_ERR_PLCR_FRAME_LEN | \ + FM_PORT_FRM_ERR_PRS_TIMEOUT | \ + FM_PORT_FRM_ERR_PRS_ILL_INSTRUCT | \ + FM_PORT_FRM_ERR_BLOCK_LIMIT_EXCEEDED | \ + FM_PORT_FRM_ERR_PRS_HDR_ERR | \ + FM_PORT_FRM_ERR_KEYSIZE_OVERFLOW | \ + FM_PORT_FRM_ERR_IPRE) + +#define OP_ERRS_TO_ENQ (RX_ERRS_TO_ENQ | \ + FM_PORT_FRM_ERR_LENGTH | \ + FM_PORT_FRM_ERR_NON_FM | \ + FM_PORT_FRM_ERR_UNSUPPORTED_FORMAT) + + +#define BMI_RX_FIFO_PRI_ELEVATION_MASK 0x03FF0000 +#define BMI_RX_FIFO_THRESHOLD_MASK 0x000003FF +#define BMI_TX_FIFO_MIN_FILL_MASK 0x03FF0000 +#define BMI_FIFO_PIPELINE_DEPTH_MASK 0x0000F000 +#define BMI_TX_LOW_COMF_MASK 0x000003FF + +/* shifts */ +#define BMI_PORT_CFG_MS_SEL_SHIFT 16 +#define BMI_DMA_ATTR_IC_CACHE_SHIFT FMAN_SP_DMA_ATTR_IC_CACHE_SHIFT +#define BMI_DMA_ATTR_HDR_CACHE_SHIFT FMAN_SP_DMA_ATTR_HDR_CACHE_SHIFT +#define BMI_DMA_ATTR_SG_CACHE_SHIFT FMAN_SP_DMA_ATTR_SG_CACHE_SHIFT + +#define BMI_IM_FOF_SHIFT 28 +#define BMI_PR_PORTID_SHIFT 24 + +#define BMI_RX_FIFO_PRI_ELEVATION_SHIFT 16 +#define BMI_RX_FIFO_THRESHOLD_SHIFT 0 + +#define BMI_RX_FRAME_END_CS_IGNORE_SHIFT 24 +#define BMI_RX_FRAME_END_CUT_SHIFT 16 + +#define BMI_IC_SIZE_SHIFT FMAN_SP_IC_SIZE_SHIFT + +#define BMI_INT_BUF_MARG_SHIFT 28 + +#define BMI_EXT_BUF_MARG_END_SHIFT FMAN_SP_EXT_BUF_MARG_END_SHIFT + +#define BMI_CMD_ATTR_COLOR_SHIFT 26 +#define BMI_CMD_ATTR_COM_MODE_SHIFT 16 +#define BMI_CMD_ATTR_MACCMD_SHIFT 8 +#define BMI_CMD_ATTR_MACCMD_OVERRIDE_SHIFT 15 +#define BMI_CMD_ATTR_MACCMD_SECURED_SHIFT 12 +#define BMI_CMD_ATTR_MACCMD_SC_SHIFT 8 + +#define BMI_POOL_DEP_NUM_OF_POOLS_VECTOR_SHIFT 24 + +#define BMI_TX_FIFO_MIN_FILL_SHIFT 16 +#define BMI_TX_LOW_COMF_SHIFT 0 + +#define BMI_PERFORMANCE_TASK_COMP_SHIFT 24 +#define BMI_PERFORMANCE_PORT_COMP_SHIFT 16 +#define BMI_PERFORMANCE_DMA_COMP_SHIFT 12 +#define BMI_PERFORMANCE_FIFO_COMP_SHIFT 0 + +#define BMI_MAX_BURST_SHIFT 16 +#define BMI_COUNT_RATE_UNIT_SHIFT 16 + +/* sizes */ +#define FRAME_END_DATA_SIZE 16 +#define FRAME_OFFSET_UNITS 16 +#define MIN_TX_INT_OFFSET 16 +#define MAX_FRAME_OFFSET 64 +#define MAX_FIFO_PIPELINE_DEPTH 8 +#define MAX_PERFORMANCE_TASK_COMP 64 +#define MAX_PERFORMANCE_TX_QUEUE_COMP 8 +#define MAX_PERFORMANCE_RX_QUEUE_COMP 64 +#define MAX_PERFORMANCE_DMA_COMP 16 +#define MAX_NUM_OF_TASKS 64 +#define MAX_NUM_OF_EXTRA_TASKS 8 +#define MAX_NUM_OF_DMAS 16 +#define MAX_NUM_OF_EXTRA_DMAS 8 +#define MAX_BURST_SIZE 1024 +#define MIN_NUM_OF_OP_DMAS 2 + + +/**************************************************************************//** + @Description QMI defines +*//***************************************************************************/ +/* masks */ +#define QMI_PORT_CFG_EN 0x80000000 +#define QMI_PORT_CFG_EN_COUNTERS 0x10000000 +#define QMI_PORT_STATUS_DEQ_TNUM_BSY 0x80000000 +#define QMI_PORT_STATUS_DEQ_FD_BSY 0x20000000 + +#define QMI_DEQ_CFG_PREFETCH_NO_TNUM 0x02000000 +#define QMI_DEQ_CFG_PREFETCH_WAITING_TNUM 0 +#define QMI_DEQ_CFG_PREFETCH_1_FRAME 0 +#define QMI_DEQ_CFG_PREFETCH_3_FRAMES 0x01000000 + +#define QMI_DEQ_CFG_PRI 0x80000000 +#define QMI_DEQ_CFG_TYPE1 0x10000000 +#define QMI_DEQ_CFG_TYPE2 0x20000000 +#define QMI_DEQ_CFG_TYPE3 0x30000000 + +#define QMI_DEQ_CFG_SUBPORTAL_MASK 0x1f +#define QMI_DEQ_CFG_SUBPORTAL_SHIFT 20 + +/**************************************************************************//** + @Description PARSER defines +*//***************************************************************************/ +/* masks */ +#define PRS_HDR_ERROR_DIS 0x00000800 +#define PRS_HDR_SW_PRS_EN 0x00000400 +#define PRS_CP_OFFSET_MASK 0x0000000F +#define PRS_TPID1_MASK 0xFFFF0000 +#define PRS_TPID2_MASK 0x0000FFFF +#define PRS_TPID_DFLT 0x91009100 + +#define PRS_HDR_MPLS_LBL_INTER_EN 0x00200000 +#define PRS_HDR_IPV6_ROUTE_HDR_EN 0x00008000 +#define PRS_HDR_PPPOE_MTU_CHECK_EN 0x80000000 +#define PRS_HDR_UDP_PAD_REMOVAL 0x80000000 +#define PRS_HDR_TCP_PAD_REMOVAL 0x80000000 +#define PRS_CAC_STOP 0x00000001 +#define PRS_CAC_ACTIVE 0x00000100 + +/* shifts */ +#define PRS_PCTPID_SHIFT 16 +#define PRS_HDR_MPLS_NEXT_HDR_SHIFT 22 +#define PRS_HDR_ETH_BC_SHIFT 28 +#define PRS_HDR_ETH_MC_SHIFT 24 +#define PRS_HDR_VLAN_STACKED_SHIFT 16 +#define PRS_HDR_MPLS_STACKED_SHIFT 16 +#define PRS_HDR_IPV4_1_BC_SHIFT 28 +#define PRS_HDR_IPV4_1_MC_SHIFT 24 +#define PRS_HDR_IPV4_2_UC_SHIFT 20 +#define PRS_HDR_IPV4_2_MC_BC_SHIFT 16 +#define PRS_HDR_IPV6_1_MC_SHIFT 24 +#define PRS_HDR_IPV6_2_UC_SHIFT 20 +#define PRS_HDR_IPV6_2_MC_SHIFT 16 + +#define PRS_HDR_ETH_BC_MASK 0x0fffffff +#define PRS_HDR_ETH_MC_MASK 0xf0ffffff +#define PRS_HDR_VLAN_STACKED_MASK 0xfff0ffff +#define PRS_HDR_MPLS_STACKED_MASK 0xfff0ffff +#define PRS_HDR_IPV4_1_BC_MASK 0x0fffffff +#define PRS_HDR_IPV4_1_MC_MASK 0xf0ffffff +#define PRS_HDR_IPV4_2_UC_MASK 0xff0fffff +#define PRS_HDR_IPV4_2_MC_BC_MASK 0xfff0ffff +#define PRS_HDR_IPV6_1_MC_MASK 0xf0ffffff +#define PRS_HDR_IPV6_2_UC_MASK 0xff0fffff +#define PRS_HDR_IPV6_2_MC_MASK 0xfff0ffff + +/* others */ +#define PRS_HDR_ENTRY_SIZE 8 +#define DEFAULT_CLS_PLAN_VECTOR 0xFFFFFFFF + +#define IPSEC_SW_PATCH_START 0x20 +#define SCTP_SW_PATCH_START 0x4D +#define DCCP_SW_PATCH_START 0x41 + +/**************************************************************************//** + @Description IM defines +*//***************************************************************************/ +#define BD_R_E 0x80000000 +#define BD_L 0x08000000 + +#define BD_RX_CRE 0x00080000 +#define BD_RX_FTL 0x00040000 +#define BD_RX_FTS 0x00020000 +#define BD_RX_OV 0x00010000 + +#define BD_RX_ERRORS (BD_RX_CRE | BD_RX_FTL | BD_RX_FTS | BD_RX_OV) + +#define FM_IM_SIZEOF_BD sizeof(t_FmImBd) + +#define BD_STATUS_MASK 0xffff0000 +#define BD_LENGTH_MASK 0x0000ffff + +#define BD_STATUS_AND_LENGTH_SET(bd, val) WRITE_UINT32(*(volatile uint32_t*)(bd), (val)) + +#define BD_STATUS_AND_LENGTH(bd) GET_UINT32(*(volatile uint32_t*)(bd)) + +#define BD_GET(id) &p_FmPort->im.p_BdRing[id] + +#define IM_ILEGAL_BD_ID 0xffff + +/* others */ +#define IM_PRAM_ALIGN 0x100 + +/* masks */ +#define IM_MODE_GBL 0x20000000 +#define IM_MODE_BO_MASK 0x18000000 +#define IM_MODE_BO_SHIFT 3 +#define IM_MODE_GRC_STP 0x00800000 + +#define IM_MODE_SET_BO(val) (uint32_t)((val << (31-IM_MODE_BO_SHIFT)) & IM_MODE_BO_MASK) + +#define IM_RXQD_BSYINTM 0x0008 +#define IM_RXQD_RXFINTM 0x0010 +#define IM_RXQD_FPMEVT_SEL_MASK 0x0003 + +#define IM_EV_BSY 0x40000000 +#define IM_EV_RX 0x80000000 + + +/**************************************************************************//** + @Description Additional defines +*//***************************************************************************/ + +typedef struct { + t_Handle h_FmMuram; + t_FmPortImPram *p_FmPortImPram; + uint8_t fwExtStructsMemId; + uint32_t fwExtStructsMemAttr; + uint16_t bdRingSize; + t_FmImBd *p_BdRing; + t_Handle *p_BdShadow; + uint16_t currBdId; + uint16_t firstBdOfFrameId; + + /* Rx port parameters */ + uint8_t dataMemId; /**< Memory partition ID for data buffers */ + uint32_t dataMemAttributes; /**< Memory attributes for data buffers */ + t_BufferPoolInfo rxPool; + uint16_t mrblr; + uint16_t rxFrameAccumLength; + t_FmPortImRxStoreCallback *f_RxStore; + + /* Tx port parameters */ + uint32_t txFirstBdStatus; + t_FmPortImTxConfCallback *f_TxConf; +} t_FmMacIm; + + +typedef struct { + struct fman_port_cfg dfltCfg; + uint32_t dfltFqid; + uint32_t confFqid; + uint32_t errFqid; + uintptr_t baseAddr; + uint8_t deqSubPortal; + bool deqHighPriority; + e_FmPortDeqType deqType; + e_FmPortDeqPrefetchOption deqPrefetchOption; + uint16_t deqByteCnt; + uint8_t cheksumLastBytesIgnore; + uint8_t cutBytesFromEnd; + t_FmBufPoolDepletion bufPoolDepletion; + uint8_t pipelineDepth; + uint16_t fifoLowComfLevel; + bool frmDiscardOverride; + bool enRateLimit; + t_FmPortRateLimit rateLimit; + e_FmPortDualRateLimiterScaleDown rateLimitDivider; + bool enBufPoolDepletion; + uint16_t liodnOffset; + uint16_t liodnBase; + t_FmExtPools extBufPools; + e_FmDmaSwapOption dmaSwapData; + e_FmDmaCacheOption dmaIntContextCacheAttr; + e_FmDmaCacheOption dmaHeaderCacheAttr; + e_FmDmaCacheOption dmaScatterGatherCacheAttr; + bool dmaReadOptimize; + bool dmaWriteOptimize; + uint32_t txFifoMinFillLevel; + uint32_t txFifoLowComfLevel; + uint32_t rxFifoPriElevationLevel; + uint32_t rxFifoThreshold; + t_FmSpBufMargins bufMargins; + t_FmSpIntContextDataCopy intContext; + bool syncReq; + e_FmPortColor color; + fmPortFrameErrSelect_t errorsToDiscard; + fmPortFrameErrSelect_t errorsToEnq; + bool forwardReuseIntContext; + t_FmBufferPrefixContent bufferPrefixContent; + t_FmBackupBmPools *p_BackupBmPools; + bool dontReleaseBuf; + bool setNumOfTasks; + bool setNumOfOpenDmas; + bool setSizeOfFifo; +#if (DPAA_VERSION >= 11) + bool noScatherGather; +#endif /* (DPAA_VERSION >= 11) */ + +#ifdef FM_HEAVY_TRAFFIC_HANG_ERRATA_FMAN_A005669 + bool bcbWorkaround; +#endif /* FM_HEAVY_TRAFFIC_HANG_ERRATA_FMAN_A005669 */ +} t_FmPortDriverParam; + + +typedef struct t_FmPortRxPoolsParams +{ + uint8_t numOfPools; + uint16_t secondLargestBufSize; + uint16_t largestBufSize; +} t_FmPortRxPoolsParams; + +typedef struct t_FmPortDsarVars { + t_Handle *autoResOffsets; + t_FmPortDsarTablesSizes *autoResMaxSizes; + uint32_t fmbm_tcfg; + uint32_t fmbm_tcmne; + uint32_t fmbm_rfne; + uint32_t fmbm_rfpne; + uint32_t fmbm_rcfg; + bool dsarEnabledParser; +} t_FmPortDsarVars; +typedef struct { + struct fman_port port; + t_Handle h_Fm; + t_Handle h_FmPcd; + t_Handle h_FmMuram; + t_FmRevisionInfo fmRevInfo; + uint8_t portId; + e_FmPortType portType; + int enabled; + char name[MODULE_NAME_SIZE]; + uint8_t hardwarePortId; + uint16_t fmClkFreq; + t_FmPortQmiRegs *p_FmPortQmiRegs; + u_FmPortBmiRegs *p_FmPortBmiRegs; + t_FmPortPrsRegs *p_FmPortPrsRegs; + fmPcdEngines_t pcdEngines; + uint32_t savedBmiNia; + uint8_t netEnvId; + uint32_t optArray[FM_PCD_MAX_NUM_OF_OPTIONS(FM_PCD_MAX_NUM_OF_CLS_PLANS)]; + uint32_t lcvs[FM_PCD_PRS_NUM_OF_HDRS]; + uint8_t privateInfo; + uint32_t schemesPerPortVector; + bool useClsPlan; + uint8_t clsPlanGrpId; + t_Handle ccTreeId; + t_Handle completeArg; + void (*f_Complete)(t_Handle arg); + t_FmSpBufferOffsets bufferOffsets; + /* Independent-Mode parameters support */ + bool imEn; + t_FmMacIm im; + volatile bool lock; + t_Handle h_Spinlock; + t_FmPortExceptionCallback *f_Exception; + t_Handle h_App; + uint8_t internalBufferOffset; + uint8_t fmanCtrlEventId; + uint32_t exceptions; + bool polling; + t_FmExtPools extBufPools; + uint32_t requiredAction; + uint32_t savedQmiPnen; + uint32_t savedBmiFene; + uint32_t savedBmiFpne; + uint32_t savedBmiCmne; + uint32_t savedBmiOfp; + uint32_t savedNonRxQmiRegsPndn; + uint32_t origNonRxQmiRegsPndn; + int savedPrsStartOffset; + bool includeInPrsStatistics; + uint16_t maxFrameLength; + t_FmFmanCtrl orFmanCtrl; + t_FmPortRsrc openDmas; + t_FmPortRsrc tasks; + t_FmPortRsrc fifoBufs; + t_FmPortRxPoolsParams rxPoolsParams; +// bool explicitUserSizeOfFifo; + t_Handle h_IpReassemblyManip; + t_Handle h_CapwapReassemblyManip; + t_Handle h_ReassemblyTree; + uint64_t fmMuramPhysBaseAddr; +#if (DPAA_VERSION >= 11) + bool vspe; + uint8_t dfltRelativeId; + e_FmPortGprFuncType gprFunc; + t_FmPcdCtrlParamsPage *p_ParamsPage; +#endif /* (DPAA_VERSION >= 11) */ + t_FmPortDsarVars deepSleepVars; + t_FmPortDriverParam *p_FmPortDriverParam; +} t_FmPort; + + +void FmPortConfigIM (t_FmPort *p_FmPort, t_FmPortParams *p_FmPortParams); +t_Error FmPortImCheckInitParameters(t_FmPort *p_FmPort); + +t_Error FmPortImInit(t_FmPort *p_FmPort); +void FmPortImFree(t_FmPort *p_FmPort); + +t_Error FmPortImEnable (t_FmPort *p_FmPort); +t_Error FmPortImDisable (t_FmPort *p_FmPort); +t_Error FmPortImRx (t_FmPort *p_FmPort); + +void FmPortSetMacsecLcv(t_Handle h_FmPort); +void FmPortSetMacsecCmd(t_Handle h_FmPort, uint8_t dfltSci); + + +t_Error FM_PORT_SetNumOfOpenDmas(t_Handle h_FmPort, t_FmPortRsrc *p_NumOfOpenDmas); +t_Error FM_PORT_SetNumOfTasks(t_Handle h_FmPort, t_FmPortRsrc *p_NumOfTasks); +t_Error FM_PORT_SetSizeOfFifo(t_Handle h_FmPort, t_FmPortRsrc *p_SizeOfFifo); + +static __inline__ uint8_t * BdBufferGet (t_PhysToVirt *f_PhysToVirt, t_FmImBd *p_Bd) +{ + uint64_t physAddr = (uint64_t)((uint64_t)GET_UINT8(p_Bd->buff.high) << 32); + physAddr |= GET_UINT32(p_Bd->buff.low); + + return (uint8_t *)f_PhysToVirt((physAddress_t)(physAddr)); +} + +static __inline__ void SET_ADDR(volatile t_FmPhysAddr *fmPhysAddr, uint64_t value) +{ + WRITE_UINT8(fmPhysAddr->high,(uint8_t)((value & 0x000000ff00000000LL) >> 32)); + WRITE_UINT32(fmPhysAddr->low,(uint32_t)value); +} + +static __inline__ void BdBufferSet(t_VirtToPhys *f_VirtToPhys, t_FmImBd *p_Bd, uint8_t *p_Buffer) +{ + uint64_t physAddr = (uint64_t)(f_VirtToPhys(p_Buffer)); + SET_ADDR(&p_Bd->buff, physAddr); +} + +static __inline__ uint16_t GetNextBdId(t_FmPort *p_FmPort, uint16_t id) +{ + if (id < p_FmPort->im.bdRingSize-1) + return (uint16_t)(id+1); + else + return 0; +} + +void FM_PORT_Dsar_DumpRegs(void); + + +#endif /* __FM_PORT_H */ diff --git a/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Port/fm_port_dsar.h b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Port/fm_port_dsar.h new file mode 100755 index 000000000000..95619eff0bee --- /dev/null +++ b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Port/fm_port_dsar.h @@ -0,0 +1,494 @@ +/* + * Copyright 2008-2012 Freescale Semiconductor Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Freescale Semiconductor nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * + * ALTERNATIVELY, this software may be distributed under the terms of the + * GNU General Public License ("GPL") as published by the Free Software + * Foundation, either version 2 of that License or (at your option) any + * later version. + * + * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/**************************************************************************//** + @File fm_port_dsar.h + + @Description Deep Sleep Auto Response project - common module header file. + + Author - Eyal Harari + + @Cautions See the FMan Controller spec and design document for more information. +*//***************************************************************************/ + +#ifndef __FM_PORT_DSAR_H_ +#define __FM_PORT_DSAR_H_ + +#define DSAR_GETSER_MASK 0xFF0000FF + +#if defined(__MWERKS__) && !defined(__GNUC__) +#pragma pack(push,1) +#endif /* defined(__MWERKS__) && ... */ + +/**************************************************************************//** + @Description Deep Sleep Auto Response VLAN-IPv4 Binding Table (for ARP/ICMPv4) + Refer to the FMan Controller spec for more details. +*//***************************************************************************/ +typedef _Packed struct +{ + uint32_t ipv4Addr; /*!< 32 bit IPv4 Address. */ + uint16_t vlanId; /*!< 12 bits VLAN ID. The 4 left-most bits should be cleared */ + /*!< This field should be 0x0000 for an entry with no VLAN tag or a null VLAN ID. */ + uint16_t reserved; +} _PackedType t_DsarArpBindingEntry; + +/**************************************************************************//** + @Description Deep Sleep Auto Response Address Resolution Protocol Statistics Descriptor + Refer to the FMan Controller spec for more details. + 0x00 INVAL_CNT Invalid ARP IPv4-Ethernet counter + 0x04 ECHO_CNT Echo counter + 0x08 CD_CNT Conflict Detection counter + 0x0C AR_CNT Auto-Response counter + 0x10 RATM_CNT Replies Addressed To Me counter + 0x14 UKOP_CNT Unknown Operation counter + 0x18 NMTP_CNT Not my TPA counter + 0x1C NMVLAN_CNT Not My VLAN counter +*//***************************************************************************/ +typedef _Packed struct +{ + uint32_t invalCnt; /**< Invalid ARP IPv4-Ethernet counter. */ + uint32_t echoCnt; /**< Echo counter. */ + uint32_t cdCnt; /**< Conflict Detection counter. */ + uint32_t arCnt; /**< Auto-Response counter. */ + uint32_t ratmCnt; /**< Replies Addressed To Me counter. */ + uint32_t ukopCnt; /**< Unknown Operation counter. */ + uint32_t nmtpCnt; /**< Not my TPA counter. */ + uint32_t nmVlanCnt; /**< Not My VLAN counter */ +} _PackedType t_DsarArpStatistics; + + +/**************************************************************************//** + @Description Deep Sleep Auto Response Address Resolution Protocol Descriptor + 0x0 0-15 Control bits [0-15]. Bit 15 = CDEN. + 0x2 0-15 NumOfBindings Number of entries in the binding list. + 0x4 0-15 BindingsPointer Bindings Pointer. This points to an IPv4-MAC Addresses Bindings list. + 0x6 0-15 + 0x8 0-15 StatisticsPointer Statistics Pointer. This field points to the ARP Descriptors statistics data structure. + 0xA 0-15 + 0xC 0-15 Reserved Reserved. Must be cleared. + 0xE 015 + +*//***************************************************************************/ +typedef _Packed struct +{ + uint16_t control; /** Control bits [0-15]. Bit 15 = CDEN */ + uint16_t numOfBindings; /**< Number of VLAN-IPv4 */ + uint32_t p_Bindings; /**< VLAN-IPv4 Bindings table pointer. */ + uint32_t p_Statistics; /**< Statistics Data Structure pointer. */ + uint32_t reserved1; /**< Reserved. */ +} _PackedType t_DsarArpDescriptor; + + +/**************************************************************************//** + @Description Deep Sleep Auto Response VLAN-IPv4 Binding Table (for ARP/ICMPv4) + Refer to the FMan Controller spec for more details. +*//***************************************************************************/ +typedef _Packed struct +{ + uint32_t ipv4Addr; /*!< 32 bit IPv4 Address. */ + uint16_t vlanId; /*!< 12 bits VLAN ID. The 4 left-most bits should be cleared */ + /*!< This field should be 0x0000 for an entry with no VLAN tag or a null VLAN ID. */ + uint16_t reserved; +} _PackedType t_DsarIcmpV4BindingEntry; + +/**************************************************************************//** + @Description Deep Sleep Auto Response ICMPv4 Statistics Descriptor + Refer to the FMan Controller spec for more details. + 0x00 INVAL_CNT Invalid ICMPv4 header counter + 0x04 NMVLAN_CNT Not My VLAN counter + 0x08 NMIP_CNT Not My IP counter + 0x0C AR_CNT Auto-Response counter + 0x10 CSERR_CNT Checksum Error counter + 0x14 Reserved Reserved + 0x18 Reserved Reserved + 0x1C Reserved Reserved + +*//***************************************************************************/ +typedef _Packed struct +{ + uint32_t invalCnt; /**< Invalid ICMPv4 Echo counter. */ + uint32_t nmVlanCnt; /**< Not My VLAN counter */ + uint32_t nmIpCnt; /**< Not My IP counter */ + uint32_t arCnt; /**< Auto-Response counter */ + uint32_t cserrCnt; /**< Checksum Error counter */ + uint32_t reserved0; /**< Reserved */ + uint32_t reserved1; /**< Reserved */ + uint32_t reserved2; /**< Reserved */ +} _PackedType t_DsarIcmpV4Statistics; + + + +/**************************************************************************//** + @Description Deep Sleep Auto Response ICMPv4 Descriptor + 0x0 0-15 Control bits [0-15] + 0x2 0-15 NumOfBindings Number of entries in the binding list. + 0x4 0-15 BindingsPointer Bindings Pointer. This points to an VLAN-IPv4 Addresses Bindings list. + 0x6 0-15 + 0x8 0-15 StatisticsPointer Statistics Pointer. This field points to the ICMPv4 statistics data structure. + 0xA 0-15 + 0xC 0-15 Reserved Reserved. Must be cleared. + 0xE 015 + +*//***************************************************************************/ +typedef _Packed struct +{ + uint16_t control; /** Control bits [0-15]. */ + uint16_t numOfBindings; /**< Number of VLAN-IPv4 */ + uint32_t p_Bindings; /**< VLAN-IPv4 Bindings table pointer. */ + uint32_t p_Statistics; /**< Statistics Data Structure pointer. */ + uint32_t reserved1; /**< Reserved. */ +} _PackedType t_DsarIcmpV4Descriptor; + +/**************************************************************************//** + @Description Deep Sleep Auto Response VLAN-IPv4 Binding Table (for ARP/ICMPv4) + The 4 left-most bits (15:12) of the VlanId parameter are control flags. + Flags[3:1] (VlanId[15:13]): Reserved, should be cleared. + Flags[0] (VlanId[12]): Temporary address. + • 0 - Assigned IP address. + • 1- Temporary (tentative) IP address. + Refer to the FMan Controller spec for more details. +*//***************************************************************************/ +typedef _Packed struct +{ + uint32_t ipv6Addr[4]; /*!< 3 * 32 bit IPv4 Address. */ + uint16_t resFlags:4; /*!< reserved flags. should be cleared */ + uint16_t vlanId:12; /*!< 12 bits VLAN ID. */ + /*!< This field should be 0x000 for an entry with no VLAN tag or a null VLAN ID. */ + uint16_t reserved; +} _PackedType t_DsarIcmpV6BindingEntry; + +/**************************************************************************//** + @Description Deep Sleep Auto Response ICMPv4 Statistics Descriptor + Refer to the FMan Controller spec for more details. + 0x00 INVAL_CNT Invalid ICMPv4 header counter + 0x04 NMVLAN_CNT Not My VLAN counter + 0x08 NMIP_CNT Not My IP counter + 0x0C AR_CNT Auto-Response counter + 0x10 CSERR_CNT Checksum Error counter + 0x14 MCAST_CNT Multicast counter + 0x18 Reserved Reserved + 0x1C Reserved Reserved + +*//***************************************************************************/ +typedef _Packed struct +{ + uint32_t invalCnt; /**< Invalid ICMPv4 Echo counter. */ + uint32_t nmVlanCnt; /**< Not My VLAN counter */ + uint32_t nmIpCnt; /**< Not My IP counter */ + uint32_t arCnt; /**< Auto-Response counter */ + uint32_t reserved1; /**< Reserved */ + uint32_t reserved2; /**< Reserved */ + uint32_t reserved3; /**< Reserved */ + uint32_t reserved4; /**< Reserved */ +} _PackedType t_DsarIcmpV6Statistics; + +/**************************************************************************//** + @Description Deep Sleep Auto Response Neighbor Discovery Statistics Descriptor + 0x00 INVAL_CNT Invalid Neighbor Discovery message counter + 0x04 NMVLAN_CNT Not My VLAN counter + 0x08 NMIP_CNT Not My IP counter + 0x0C AR_CNT Auto-Response counter + 0x10 CSERR_CNT Checksum Error counter + 0x14 USADVERT_CNT Unsolicited Neighbor Advertisements counter + 0x18 NMMCAST_CNT Not My Multicast group counter + 0x1C NSLLA_CNT No Source Link-Layer Address counter. Indicates that there was a match on a Target + Address of a packet that its source IP address is a unicast address, but the ICMPv6 + Source Link-layer Address option is omitted +*//***************************************************************************/ +typedef _Packed struct +{ + uint32_t invalCnt; /**< Invalid ICMPv4 Echo counter. */ + uint32_t nmVlanCnt; /**< Not My VLAN counter */ + uint32_t nmIpCnt; /**< Not My IP counter */ + uint32_t arCnt; /**< Auto-Response counter */ + uint32_t reserved1; /**< Reserved */ + uint32_t usadvertCnt; /**< Unsolicited Neighbor Advertisements counter */ + uint32_t nmmcastCnt; /**< Not My Multicast group counter */ + uint32_t nsllaCnt; /**< No Source Link-Layer Address counter */ +} _PackedType t_NdStatistics; + +/**************************************************************************//** + @Description Deep Sleep Auto Response ICMPv6 Descriptor + 0x0 0-15 Control bits [0-15] + 0x2 0-15 NumOfBindings Number of entries in the binding list. + 0x4 0-15 BindingsPointer Bindings Pointer. This points to an VLAN-IPv4 Addresses Bindings list. + 0x6 0-15 + 0x8 0-15 StatisticsPointer Statistics Pointer. This field points to the ICMPv4 statistics data structure. + 0xA 0-15 + 0xC 0-15 Reserved Reserved. Must be cleared. + 0xE 015 + +*//***************************************************************************/ +typedef _Packed struct +{ + uint16_t control; /** Control bits [0-15]. */ + uint16_t numOfBindings; /**< Number of VLAN-IPv6 */ + uint32_t p_Bindings; /**< VLAN-IPv4 Bindings table pointer. */ + uint32_t p_Statistics; /**< Statistics Data Structure pointer. */ + uint32_t reserved1; /**< Reserved. */ +} _PackedType t_DsarIcmpV6Descriptor; + + +/**************************************************************************//** + @Description Internet Control Message Protocol (ICMPv6) Echo message header + The fields names are taken from RFC 4443. +*//***************************************************************************/ +/* 0 1 2 3 */ +/* 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 */ +/* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ */ +/* | Type | Code | Checksum | */ +/* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ */ +/* | Identifier | Sequence Number | */ +/* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ */ +/* | Data ... */ +/* +-+-+-+-+- */ +typedef _Packed struct +{ + uint8_t type; + uint8_t code; + uint16_t checksum; + uint16_t identifier; + uint16_t sequenceNumber; +} _PackedType t_IcmpV6EchoHdr; + +/**************************************************************************//** + @Description Internet Control Message Protocol (ICMPv6) + Neighbor Solicitation/Advertisement header + The fields names are taken from RFC 4861. + The R/S/O fields are valid for Neighbor Advertisement only +*//***************************************************************************/ +/* 0 1 2 3 + * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Type | Code | Checksum | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * |R|S|O| Reserved | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | | + * + + + * | | + * + Target Address + + * | | + * + + + * | | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Options ... + * +-+-+-+-+-+-+-+-+-+-+-+- + * + * Options Format: + * 0 1 2 3 + * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Type | Length | Link-Layer Address ... | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Link-Layer Address | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +*/ +typedef _Packed struct +{ + uint8_t type; + uint8_t code; + uint16_t checksum; + uint32_t router:1; + uint32_t solicited:1; + uint32_t override:1; + uint32_t reserved:29; + uint32_t targetAddr[4]; + uint8_t optionType; + uint8_t optionLength; + uint8_t linkLayerAddr[6]; +} _PackedType t_IcmpV6NdHdr; + +/**************************************************************************//** + @Description Deep Sleep Auto Response ICMPv6 Descriptor + 0x0 0-15 Control bits [0-15] + 0x2 0-15 NumOfBindings Number of entries in the binding list. + 0x4 0-15 BindingsPointer Bindings Pointer. This points to an VLAN-IPv4 Addresses Bindings list. + 0x6 0-15 + 0x8 0-15 StatisticsPointer Statistics Pointer. This field points to the ICMPv4 statistics data structure. + 0xA 0-15 + 0xC 0-15 Reserved Reserved. Must be cleared. + 0xE 015 + +*//***************************************************************************/ +typedef _Packed struct +{ + uint16_t control; /** Control bits [0-15]. */ + uint16_t numOfBindings; /**< Number of VLAN-IPv6 */ + uint32_t p_Bindings; /**< VLAN-IPv4 Bindings table pointer. */ + uint32_t p_Statistics; /**< Statistics Data Structure pointer. */ + uint32_t solicitedAddr; /**< Solicited Node Multicast Group Address */ +} _PackedType t_DsarNdDescriptor; + +/**************************************************************************//** +@Description Deep Sleep Auto Response SNMP OIDs table entry + +*//***************************************************************************/ +typedef struct { + uint16_t oidSize; /**< Size in octets of the OID. */ + uint16_t resSize; /**< Size in octets of the value that is attached to the OID. */ + uint32_t p_Oid; /**< Pointer to the OID. OID is encoded in BER but type and length are excluded. */ + uint32_t resValOrPtr; /**< Value (for up to 4 octets) or pointer to the Value. Encoded in BER. */ + uint32_t reserved; +} t_OidsTblEntry; + +/**************************************************************************//** + @Description Deep Sleep Auto Response SNMP IPv4 Addresses Table Entry + Refer to the FMan Controller spec for more details. +*//***************************************************************************/ +typedef struct +{ + uint32_t ipv4Addr; /*!< 32 bit IPv4 Address. */ + uint16_t vlanId; /*!< 12 bits VLAN ID. The 4 left-most bits should be cleared */ + /*!< This field should be 0x0000 for an entry with no VLAN tag or a null VLAN ID. */ + uint16_t reserved; +} t_DsarSnmpIpv4AddrTblEntry; + +/**************************************************************************//** + @Description Deep Sleep Auto Response SNMP IPv6 Addresses Table Entry + Refer to the FMan Controller spec for more details. +*//***************************************************************************/ +#pragma pack(push,1) +typedef struct +{ + uint32_t ipv6Addr[4]; /*!< 4 * 32 bit IPv6 Address. */ + uint16_t vlanId; /*!< 12 bits VLAN ID. The 4 left-most bits should be cleared */ + /*!< This field should be 0x0000 for an entry with no VLAN tag or a null VLAN ID. */ + uint16_t reserved; +} t_DsarSnmpIpv6AddrTblEntry; +#pragma pack(pop) + +/**************************************************************************//** +@Description Deep Sleep Auto Response SNMP statistics table + +*//***************************************************************************/ +typedef struct { + uint32_t snmpErrCnt; /**< Counts SNMP errors (wrong version, BER encoding, format). */ + uint32_t snmpCommunityErrCnt; /**< Counts messages that were dropped due to insufficient permission. */ + uint32_t snmpTotalDiscardCnt; /**< Counts any message that was dropped. */ + uint32_t snmpGetReqCnt; /**< Counts the number of get-request messages */ + uint32_t snmpGetNextReqCnt; /**< Counts the number of get-next-request messages */ +} t_DsarSnmpStatistics; + +/**************************************************************************//** + @Description Deep Sleep Auto Response SNMP Descriptor + +*//***************************************************************************/ +typedef struct +{ + uint16_t control; /**< Control bits [0-15]. */ + uint16_t maxSnmpMsgLength; /**< Maximal allowed SNMP message length. */ + uint16_t numOfIpv4Addresses; /**< Number of entries in IPv4 addresses table. */ + uint16_t numOfIpv6Addresses; /**< Number of entries in IPv6 addresses table. */ + uint32_t p_Ipv4AddrTbl; /**< Pointer to IPv4 addresses table. */ + uint32_t p_Ipv6AddrTbl; /**< Pointer to IPv6 addresses table. */ + uint32_t p_RdOnlyCommunityStr; /**< Pointer to the Read Only Community String. */ + uint32_t p_RdWrCommunityStr; /**< Pointer to the Read Write Community String. */ + uint32_t p_OidsTbl; /**< Pointer to OIDs table. */ + uint32_t oidsTblSize; /**< Number of entries in OIDs table. */ + uint32_t p_Statistics; /**< Pointer to SNMP statistics table. */ +} t_DsarSnmpDescriptor; + +/**************************************************************************//** +@Description Deep Sleep Auto Response (Common) Statistics + +*//***************************************************************************/ +typedef _Packed struct { + uint32_t dsarDiscarded; + uint32_t dsarErrDiscarded; + uint32_t dsarFragDiscarded; + uint32_t dsarTunnelDiscarded; + uint32_t dsarArpDiscarded; + uint32_t dsarIpDiscarded; + uint32_t dsarTcpDiscarded; + uint32_t dsarUdpDiscarded; + uint32_t dsarIcmpV6ChecksumErr; /* ICMPv6 Checksum Error counter */ + uint32_t dsarIcmpV6OtherType; /* ICMPv6 'Other' type (not Echo or Neighbor Solicitaion/Advertisement counter */ + uint32_t dsarIcmpV4OtherType; /* ICMPv4 'Other' type (not Echo) counter */ +} _PackedType t_ArStatistics; + + +/**************************************************************************//** +@Description Deep Sleep Auto Response TCP/UDP port filter table entry + +*//***************************************************************************/ +typedef _Packed struct { + uint32_t Ports; + uint32_t PortsMask; +} _PackedType t_PortTblEntry; + + + +/**************************************************************************//** +@Description Deep Sleep Auto Response Common Parameters Descriptor + +*//***************************************************************************/ +typedef _Packed struct { + uint8_t arTxPort; /* 0x00 0-7 Auto Response Transmit Port number */ + uint8_t controlBits; /* 0x00 8-15 Auto Response control bits */ + uint16_t res1; /* 0x00 16-31 Reserved */ + uint32_t activeHPNIA; /* 0x04 0-31 Active mode Hardware Parser NIA */ + uint16_t snmpPort; /* 0x08 0-15 SNMP Port. */ + uint8_t macStationAddr[6]; /* 0x08 16-31 and 0x0C 0-31 MAC Station Address */ + uint8_t res2; /* 0x10 0-7 Reserved */ + uint8_t filterControl; /* 0x10 8-15 Filtering Control Bits. */ + uint16_t tcpControlPass; /* 0x10 16-31 TCP control pass flags */ + uint8_t ipProtocolTblSize; /* 0x14 0-7 IP Protocol Table Size. */ + uint8_t udpPortTblSize; /* 0x14 8-15 UDP Port Table Size. */ + uint8_t tcpPortTblSize; /* 0x14 16-23 TCP Port Table Size. */ + uint8_t res3; /* 0x14 24-31 Reserved */ + uint32_t p_IpProtocolFiltTbl; /* 0x18 0-31 Pointer to IP Protocol Filter Table */ + uint32_t p_UdpPortFiltTbl; /* 0x1C 0-31 Pointer to UDP Port Filter Table */ + uint32_t p_TcpPortFiltTbl; /* 0x20 0-31 Pointer to TCP Port Filter Table */ + uint32_t res4; /* 0x24 Reserved */ + uint32_t p_ArpDescriptor; /* 0x28 0-31 ARP Descriptor Pointer. */ + uint32_t p_NdDescriptor; /* 0x2C 0-31 Neighbor Discovery Descriptor. */ + uint32_t p_IcmpV4Descriptor; /* 0x30 0-31 ICMPv4 Descriptor pointer. */ + uint32_t p_IcmpV6Descriptor; /* 0x34 0-31 ICMPv6 Descriptor pointer. */ + uint32_t p_SnmpDescriptor; /* 0x38 0-31 SNMP Descriptor pointer. */ + uint32_t p_ArStats; /* 0x3C 0-31 Pointer to Auto Response Statistics */ +} _PackedType t_ArCommonDesc; + +#if defined(__MWERKS__) && !defined(__GNUC__) +#pragma pack(pop) +#endif /* defined(__MWERKS__) && ... */ + +/* t_ArCommonDesc.filterControl bits */ +#define IP_PROT_TBL_PASS_MASK 0x08 +#define UDP_PORT_TBL_PASS_MASK 0x04 +#define TCP_PORT_TBL_PASS_MASK 0x02 + +/* Offset of TCF flags within TCP packet */ +#define TCP_FLAGS_OFFSET 12 + + +#endif /* __FM_PORT_DSAR_H_ */ diff --git a/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Port/fm_port_im.c b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Port/fm_port_im.c new file mode 100644 index 000000000000..8de8f5fd9ddb --- /dev/null +++ b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Port/fm_port_im.c @@ -0,0 +1,753 @@ +/* + * Copyright 2008-2012 Freescale Semiconductor Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Freescale Semiconductor nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * + * ALTERNATIVELY, this software may be distributed under the terms of the + * GNU General Public License ("GPL") as published by the Free Software + * Foundation, either version 2 of that License or (at your option) any + * later version. + * + * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + +/****************************************************************************** + @File fm_port_im.c + + @Description FM Port Independent-Mode ... +*//***************************************************************************/ +#include "std_ext.h" +#include "string_ext.h" +#include "error_ext.h" +#include "memcpy_ext.h" +#include "fm_muram_ext.h" + +#include "fm_port.h" + + +#define TX_CONF_STATUS_UNSENT 0x1 + + +typedef enum e_TxConfType +{ + e_TX_CONF_TYPE_CHECK = 0 /**< check if all the buffers were touched by the muxator, no confirmation callback */ + ,e_TX_CONF_TYPE_CALLBACK = 1 /**< confirm to user all the available sent buffers */ + ,e_TX_CONF_TYPE_FLUSH = 3 /**< confirm all buffers plus the unsent one with an appropriate status */ +} e_TxConfType; + + +static void ImException(t_Handle h_FmPort, uint32_t event) +{ + t_FmPort *p_FmPort = (t_FmPort*)h_FmPort; + + ASSERT_COND(((event & (IM_EV_RX | IM_EV_BSY)) && FmIsMaster(p_FmPort->h_Fm)) || + !FmIsMaster(p_FmPort->h_Fm)); + + if (event & IM_EV_RX) + FmPortImRx(p_FmPort); + if ((event & IM_EV_BSY) && p_FmPort->f_Exception) + p_FmPort->f_Exception(p_FmPort->h_App, e_FM_PORT_EXCEPTION_IM_BUSY); +} + + +static t_Error TxConf(t_FmPort *p_FmPort, e_TxConfType confType) +{ + t_Error retVal = E_BUSY; + uint32_t bdStatus; + uint16_t savedStartBdId, confBdId; + + ASSERT_COND(p_FmPort); + + /* + if (confType==e_TX_CONF_TYPE_CHECK) + return (WfqEntryIsQueueEmpty(p_FmPort->im.h_WfqEntry) ? E_OK : E_BUSY); + */ + + confBdId = savedStartBdId = p_FmPort->im.currBdId; + bdStatus = BD_STATUS_AND_LENGTH(BD_GET(confBdId)); + + /* If R bit is set, we don't enter, or we break. + we run till we get to R, or complete the loop */ + while ((!(bdStatus & BD_R_E) || (confType == e_TX_CONF_TYPE_FLUSH)) && (retVal != E_OK)) + { + if (confType & e_TX_CONF_TYPE_CALLBACK) /* if it is confirmation with user callbacks */ + BD_STATUS_AND_LENGTH_SET(BD_GET(confBdId), 0); + + /* case 1: R bit is 0 and Length is set -> confirm! */ + if ((confType & e_TX_CONF_TYPE_CALLBACK) && (bdStatus & BD_LENGTH_MASK)) + { + if (p_FmPort->im.f_TxConf) + { + if ((confType == e_TX_CONF_TYPE_FLUSH) && (bdStatus & BD_R_E)) + p_FmPort->im.f_TxConf(p_FmPort->h_App, + BdBufferGet(XX_PhysToVirt, BD_GET(confBdId)), + TX_CONF_STATUS_UNSENT, + p_FmPort->im.p_BdShadow[confBdId]); + else + p_FmPort->im.f_TxConf(p_FmPort->h_App, + BdBufferGet(XX_PhysToVirt, BD_GET(confBdId)), + 0, + p_FmPort->im.p_BdShadow[confBdId]); + } + } + /* case 2: R bit is 0 and Length is 0 -> not used yet, nop! */ + + confBdId = GetNextBdId(p_FmPort, confBdId); + if (confBdId == savedStartBdId) + retVal = E_OK; + bdStatus = BD_STATUS_AND_LENGTH(BD_GET(confBdId)); + } + + return retVal; +} + +t_Error FmPortImEnable(t_FmPort *p_FmPort) +{ + uint32_t tmpReg = GET_UINT32(p_FmPort->im.p_FmPortImPram->mode); + WRITE_UINT32(p_FmPort->im.p_FmPortImPram->mode, (uint32_t)(tmpReg & ~IM_MODE_GRC_STP)); + return E_OK; +} + +t_Error FmPortImDisable(t_FmPort *p_FmPort) +{ + uint32_t tmpReg = GET_UINT32(p_FmPort->im.p_FmPortImPram->mode); + WRITE_UINT32(p_FmPort->im.p_FmPortImPram->mode, (uint32_t)(tmpReg | IM_MODE_GRC_STP)); + return E_OK; +} + +t_Error FmPortImRx(t_FmPort *p_FmPort) +{ + t_Handle h_CurrUserPriv, h_NewUserPriv; + uint32_t bdStatus; + volatile uint8_t buffPos; + uint16_t length; + uint16_t errors; + uint8_t *p_CurData, *p_Data; + uint32_t flags; + + ASSERT_COND(p_FmPort); + + flags = XX_LockIntrSpinlock(p_FmPort->h_Spinlock); + if (p_FmPort->lock) + { + XX_UnlockIntrSpinlock(p_FmPort->h_Spinlock, flags); + return E_OK; + } + p_FmPort->lock = TRUE; + XX_UnlockIntrSpinlock(p_FmPort->h_Spinlock, flags); + + bdStatus = BD_STATUS_AND_LENGTH(BD_GET(p_FmPort->im.currBdId)); + + while (!(bdStatus & BD_R_E)) /* while there is data in the Rx BD */ + { + if ((p_Data = p_FmPort->im.rxPool.f_GetBuf(p_FmPort->im.rxPool.h_BufferPool, &h_NewUserPriv)) == NULL) + { + p_FmPort->lock = FALSE; + RETURN_ERROR(MAJOR, E_NOT_AVAILABLE, ("Data buffer")); + } + + if (p_FmPort->im.firstBdOfFrameId == IM_ILEGAL_BD_ID) + p_FmPort->im.firstBdOfFrameId = p_FmPort->im.currBdId; + + p_CurData = BdBufferGet(p_FmPort->im.rxPool.f_PhysToVirt, BD_GET(p_FmPort->im.currBdId)); + h_CurrUserPriv = p_FmPort->im.p_BdShadow[p_FmPort->im.currBdId]; + length = (uint16_t)((bdStatus & BD_L) ? + ((bdStatus & BD_LENGTH_MASK) - p_FmPort->im.rxFrameAccumLength): + (bdStatus & BD_LENGTH_MASK)); + p_FmPort->im.rxFrameAccumLength += length; + + /* determine whether buffer is first, last, first and last (single */ + /* buffer frame) or middle (not first and not last) */ + buffPos = (uint8_t)((p_FmPort->im.currBdId == p_FmPort->im.firstBdOfFrameId) ? + ((bdStatus & BD_L) ? SINGLE_BUF : FIRST_BUF) : + ((bdStatus & BD_L) ? LAST_BUF : MIDDLE_BUF)); + + if (bdStatus & BD_L) + { + p_FmPort->im.rxFrameAccumLength = 0; + p_FmPort->im.firstBdOfFrameId = IM_ILEGAL_BD_ID; + } + + BdBufferSet(p_FmPort->im.rxPool.f_VirtToPhys, BD_GET(p_FmPort->im.currBdId), p_Data); + + BD_STATUS_AND_LENGTH_SET(BD_GET(p_FmPort->im.currBdId), BD_R_E); + + errors = (uint16_t)((bdStatus & BD_RX_ERRORS) >> 16); + p_FmPort->im.p_BdShadow[p_FmPort->im.currBdId] = h_NewUserPriv; + + p_FmPort->im.currBdId = GetNextBdId(p_FmPort, p_FmPort->im.currBdId); + WRITE_UINT16(p_FmPort->im.p_FmPortImPram->rxQd.offsetOut, (uint16_t)(p_FmPort->im.currBdId<<4)); + /* Pass the buffer if one of the conditions is true: + - There are no errors + - This is a part of a larger frame ( the application has already received some buffers ) */ + if ((buffPos != SINGLE_BUF) || !errors) + { + if (p_FmPort->im.f_RxStore(p_FmPort->h_App, + p_CurData, + length, + errors, + buffPos, + h_CurrUserPriv) == e_RX_STORE_RESPONSE_PAUSE) + break; + } + else if (p_FmPort->im.rxPool.f_PutBuf(p_FmPort->im.rxPool.h_BufferPool, + p_CurData, + h_CurrUserPriv)) + { + p_FmPort->lock = FALSE; + RETURN_ERROR(MAJOR, E_INVALID_STATE, ("Failed freeing data buffer")); + } + + bdStatus = BD_STATUS_AND_LENGTH(BD_GET(p_FmPort->im.currBdId)); + } + p_FmPort->lock = FALSE; + return E_OK; +} + +void FmPortConfigIM (t_FmPort *p_FmPort, t_FmPortParams *p_FmPortParams) +{ + ASSERT_COND(p_FmPort); + + SANITY_CHECK_RETURN(p_FmPort->p_FmPortDriverParam, E_INVALID_HANDLE); + + p_FmPort->im.h_FmMuram = p_FmPortParams->specificParams.imRxTxParams.h_FmMuram; + p_FmPort->p_FmPortDriverParam->liodnOffset = p_FmPortParams->specificParams.imRxTxParams.liodnOffset; + p_FmPort->im.dataMemId = p_FmPortParams->specificParams.imRxTxParams.dataMemId; + p_FmPort->im.dataMemAttributes = p_FmPortParams->specificParams.imRxTxParams.dataMemAttributes; + + p_FmPort->im.fwExtStructsMemId = DEFAULT_PORT_ImfwExtStructsMemId; + p_FmPort->im.fwExtStructsMemAttr = DEFAULT_PORT_ImfwExtStructsMemAttr; + + if ((p_FmPort->portType == e_FM_PORT_TYPE_RX) || + (p_FmPort->portType == e_FM_PORT_TYPE_RX_10G)) + { + p_FmPort->im.rxPool.h_BufferPool = p_FmPortParams->specificParams.imRxTxParams.rxPoolParams.h_BufferPool; + p_FmPort->im.rxPool.f_GetBuf = p_FmPortParams->specificParams.imRxTxParams.rxPoolParams.f_GetBuf; + p_FmPort->im.rxPool.f_PutBuf = p_FmPortParams->specificParams.imRxTxParams.rxPoolParams.f_PutBuf; + p_FmPort->im.rxPool.bufferSize = p_FmPortParams->specificParams.imRxTxParams.rxPoolParams.bufferSize; + p_FmPort->im.rxPool.f_PhysToVirt = p_FmPortParams->specificParams.imRxTxParams.rxPoolParams.f_PhysToVirt; + if (!p_FmPort->im.rxPool.f_PhysToVirt) + p_FmPort->im.rxPool.f_PhysToVirt = XX_PhysToVirt; + p_FmPort->im.rxPool.f_VirtToPhys = p_FmPortParams->specificParams.imRxTxParams.rxPoolParams.f_VirtToPhys; + if (!p_FmPort->im.rxPool.f_VirtToPhys) + p_FmPort->im.rxPool.f_VirtToPhys = XX_VirtToPhys; + p_FmPort->im.f_RxStore = p_FmPortParams->specificParams.imRxTxParams.f_RxStore; + + p_FmPort->im.mrblr = 0x8000; + while (p_FmPort->im.mrblr) + { + if (p_FmPort->im.rxPool.bufferSize & p_FmPort->im.mrblr) + break; + p_FmPort->im.mrblr >>= 1; + } + if (p_FmPort->im.mrblr != p_FmPort->im.rxPool.bufferSize) + DBG(WARNING, ("Max-Rx-Buffer-Length set to %d", p_FmPort->im.mrblr)); + p_FmPort->im.bdRingSize = DEFAULT_PORT_rxBdRingLength; + p_FmPort->exceptions = DEFAULT_PORT_exception; + if (FmIsMaster(p_FmPort->h_Fm)) + p_FmPort->polling = FALSE; + else + p_FmPort->polling = TRUE; + p_FmPort->fmanCtrlEventId = (uint8_t)NO_IRQ; + } + else + { + p_FmPort->im.f_TxConf = p_FmPortParams->specificParams.imRxTxParams.f_TxConf; + + p_FmPort->im.bdRingSize = DEFAULT_PORT_txBdRingLength; + } +} + +t_Error FmPortImCheckInitParameters(t_FmPort *p_FmPort) +{ + if ((p_FmPort->portType != e_FM_PORT_TYPE_RX) && + (p_FmPort->portType != e_FM_PORT_TYPE_RX_10G) && + (p_FmPort->portType != e_FM_PORT_TYPE_TX) && + (p_FmPort->portType != e_FM_PORT_TYPE_TX_10G)) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, NO_MSG); + + if ((p_FmPort->portType == e_FM_PORT_TYPE_RX) || + (p_FmPort->portType == e_FM_PORT_TYPE_RX_10G)) + { + if (!POWER_OF_2(p_FmPort->im.mrblr)) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("max Rx buffer length must be power of 2!!!")); + if (p_FmPort->im.mrblr < 256) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("max Rx buffer length must at least 256!!!")); + if (p_FmPort->p_FmPortDriverParam->liodnOffset & ~FM_LIODN_OFFSET_MASK) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("liodnOffset is larger than %d", FM_LIODN_OFFSET_MASK+1)); + } + + return E_OK; +} + +t_Error FmPortImInit(t_FmPort *p_FmPort) +{ + t_FmImBd *p_Bd=NULL; + t_Handle h_BufContext; + uint64_t tmpPhysBase; + uint16_t log2Num; + uint8_t *p_Data/*, *p_Tmp*/; + int i; + t_Error err; + uint16_t tmpReg16; + uint32_t tmpReg32; + + ASSERT_COND(p_FmPort); + + p_FmPort->im.p_FmPortImPram = + (t_FmPortImPram *)FM_MURAM_AllocMem(p_FmPort->im.h_FmMuram, sizeof(t_FmPortImPram), IM_PRAM_ALIGN); + if (!p_FmPort->im.p_FmPortImPram) + RETURN_ERROR(MAJOR, E_NO_MEMORY, ("Independent-Mode Parameter-RAM!!!")); + WRITE_BLOCK(p_FmPort->im.p_FmPortImPram, 0, sizeof(t_FmPortImPram)); + + if ((p_FmPort->portType == e_FM_PORT_TYPE_RX) || + (p_FmPort->portType == e_FM_PORT_TYPE_RX_10G)) + { + p_FmPort->im.p_BdRing = + (t_FmImBd *)XX_MallocSmart((uint32_t)(sizeof(t_FmImBd)*p_FmPort->im.bdRingSize), + p_FmPort->im.fwExtStructsMemId, + 4); + if (!p_FmPort->im.p_BdRing) + RETURN_ERROR(MAJOR, E_NO_MEMORY, ("Independent-Mode Rx BD ring!!!")); + IOMemSet32(p_FmPort->im.p_BdRing, 0, (uint32_t)(sizeof(t_FmImBd)*p_FmPort->im.bdRingSize)); + + p_FmPort->im.p_BdShadow = (t_Handle *)XX_Malloc((uint32_t)(sizeof(t_Handle)*p_FmPort->im.bdRingSize)); + if (!p_FmPort->im.p_BdShadow) + RETURN_ERROR(MAJOR, E_NO_MEMORY, ("Independent-Mode Rx BD shadow!!!")); + memset(p_FmPort->im.p_BdShadow, 0, (uint32_t)(sizeof(t_Handle)*p_FmPort->im.bdRingSize)); + + /* Initialize the Rx-BD ring */ + for (i=0; i<p_FmPort->im.bdRingSize; i++) + { + p_Bd = BD_GET(i); + BD_STATUS_AND_LENGTH_SET (p_Bd, BD_R_E); + + if ((p_Data = p_FmPort->im.rxPool.f_GetBuf(p_FmPort->im.rxPool.h_BufferPool, &h_BufContext)) == NULL) + RETURN_ERROR(MAJOR, E_NOT_AVAILABLE, ("Data buffer")); + BdBufferSet(p_FmPort->im.rxPool.f_VirtToPhys, p_Bd, p_Data); + p_FmPort->im.p_BdShadow[i] = h_BufContext; + } + + if ((p_FmPort->im.dataMemAttributes & MEMORY_ATTR_CACHEABLE) || + (p_FmPort->im.fwExtStructsMemAttr & MEMORY_ATTR_CACHEABLE)) + WRITE_UINT32(p_FmPort->im.p_FmPortImPram->mode, IM_MODE_GBL | IM_MODE_SET_BO(2)); + else + WRITE_UINT32(p_FmPort->im.p_FmPortImPram->mode, IM_MODE_SET_BO(2)); + + WRITE_UINT32(p_FmPort->im.p_FmPortImPram->rxQdPtr, + (uint32_t)((uint64_t)(XX_VirtToPhys(p_FmPort->im.p_FmPortImPram)) - + p_FmPort->fmMuramPhysBaseAddr + 0x20)); + + LOG2((uint64_t)p_FmPort->im.mrblr, log2Num); + WRITE_UINT16(p_FmPort->im.p_FmPortImPram->mrblr, log2Num); + + /* Initialize Rx QD */ + tmpPhysBase = (uint64_t)(XX_VirtToPhys(p_FmPort->im.p_BdRing)); + SET_ADDR(&p_FmPort->im.p_FmPortImPram->rxQd.bdRingBase, tmpPhysBase); + WRITE_UINT16(p_FmPort->im.p_FmPortImPram->rxQd.bdRingSize, (uint16_t)(sizeof(t_FmImBd)*p_FmPort->im.bdRingSize)); + + /* Update the IM PRAM address in the BMI */ + WRITE_UINT32(p_FmPort->p_FmPortBmiRegs->rxPortBmiRegs.fmbm_rfqid, + (uint32_t)((uint64_t)(XX_VirtToPhys(p_FmPort->im.p_FmPortImPram)) - + p_FmPort->fmMuramPhysBaseAddr)); + if (!p_FmPort->polling || p_FmPort->exceptions) + { + /* Allocate, configure and register interrupts */ + err = FmAllocFmanCtrlEventReg(p_FmPort->h_Fm, &p_FmPort->fmanCtrlEventId); + if (err) + RETURN_ERROR(MAJOR, err, NO_MSG); + + ASSERT_COND(!(p_FmPort->fmanCtrlEventId & ~IM_RXQD_FPMEVT_SEL_MASK)); + tmpReg16 = (uint16_t)(p_FmPort->fmanCtrlEventId & IM_RXQD_FPMEVT_SEL_MASK); + tmpReg32 = 0; + + if (p_FmPort->exceptions & IM_EV_BSY) + { + tmpReg16 |= IM_RXQD_BSYINTM; + tmpReg32 |= IM_EV_BSY; + } + if (!p_FmPort->polling) + { + tmpReg16 |= IM_RXQD_RXFINTM; + tmpReg32 |= IM_EV_RX; + } + WRITE_UINT16(p_FmPort->im.p_FmPortImPram->rxQd.gen, tmpReg16); + + FmRegisterFmanCtrlIntr(p_FmPort->h_Fm, p_FmPort->fmanCtrlEventId, ImException , (t_Handle)p_FmPort); + + FmSetFmanCtrlIntr(p_FmPort->h_Fm, p_FmPort->fmanCtrlEventId, tmpReg32); + } + else + p_FmPort->fmanCtrlEventId = (uint8_t)NO_IRQ; + } + else + { + p_FmPort->im.p_BdRing = (t_FmImBd *)XX_MallocSmart((uint32_t)(sizeof(t_FmImBd)*p_FmPort->im.bdRingSize), p_FmPort->im.fwExtStructsMemId, 4); + if (!p_FmPort->im.p_BdRing) + RETURN_ERROR(MAJOR, E_NO_MEMORY, ("Independent-Mode Tx BD ring!!!")); + IOMemSet32(p_FmPort->im.p_BdRing, 0, (uint32_t)(sizeof(t_FmImBd)*p_FmPort->im.bdRingSize)); + + p_FmPort->im.p_BdShadow = (t_Handle *)XX_Malloc((uint32_t)(sizeof(t_Handle)*p_FmPort->im.bdRingSize)); + if (!p_FmPort->im.p_BdShadow) + RETURN_ERROR(MAJOR, E_NO_MEMORY, ("Independent-Mode Rx BD shadow!!!")); + memset(p_FmPort->im.p_BdShadow, 0, (uint32_t)(sizeof(t_Handle)*p_FmPort->im.bdRingSize)); + p_FmPort->im.firstBdOfFrameId = IM_ILEGAL_BD_ID; + + if ((p_FmPort->im.dataMemAttributes & MEMORY_ATTR_CACHEABLE) || + (p_FmPort->im.fwExtStructsMemAttr & MEMORY_ATTR_CACHEABLE)) + WRITE_UINT32(p_FmPort->im.p_FmPortImPram->mode, IM_MODE_GBL | IM_MODE_SET_BO(2)); + else + WRITE_UINT32(p_FmPort->im.p_FmPortImPram->mode, IM_MODE_SET_BO(2)); + + WRITE_UINT32(p_FmPort->im.p_FmPortImPram->txQdPtr, + (uint32_t)((uint64_t)(XX_VirtToPhys(p_FmPort->im.p_FmPortImPram)) - + p_FmPort->fmMuramPhysBaseAddr + 0x40)); + + /* Initialize Tx QD */ + tmpPhysBase = (uint64_t)(XX_VirtToPhys(p_FmPort->im.p_BdRing)); + SET_ADDR(&p_FmPort->im.p_FmPortImPram->txQd.bdRingBase, tmpPhysBase); + WRITE_UINT16(p_FmPort->im.p_FmPortImPram->txQd.bdRingSize, (uint16_t)(sizeof(t_FmImBd)*p_FmPort->im.bdRingSize)); + + /* Update the IM PRAM address in the BMI */ + WRITE_UINT32(p_FmPort->p_FmPortBmiRegs->txPortBmiRegs.fmbm_tcfqid, + (uint32_t)((uint64_t)(XX_VirtToPhys(p_FmPort->im.p_FmPortImPram)) - + p_FmPort->fmMuramPhysBaseAddr)); + } + + + return E_OK; +} + +void FmPortImFree(t_FmPort *p_FmPort) +{ + uint32_t bdStatus; + uint8_t *p_CurData; + + ASSERT_COND(p_FmPort); + ASSERT_COND(p_FmPort->im.p_FmPortImPram); + + if ((p_FmPort->portType == e_FM_PORT_TYPE_RX) || + (p_FmPort->portType == e_FM_PORT_TYPE_RX_10G)) + { + if (!p_FmPort->polling || p_FmPort->exceptions) + { + /* Deallocate and unregister interrupts */ + FmSetFmanCtrlIntr(p_FmPort->h_Fm, p_FmPort->fmanCtrlEventId, 0); + + FmFreeFmanCtrlEventReg(p_FmPort->h_Fm, p_FmPort->fmanCtrlEventId); + + WRITE_UINT16(p_FmPort->im.p_FmPortImPram->rxQd.gen, 0); + + FmUnregisterFmanCtrlIntr(p_FmPort->h_Fm, p_FmPort->fmanCtrlEventId); + } + /* Try first clean what has received */ + FmPortImRx(p_FmPort); + + /* Now, get rid of the the empty buffer! */ + bdStatus = BD_STATUS_AND_LENGTH(BD_GET(p_FmPort->im.currBdId)); + + while (bdStatus & BD_R_E) /* while there is data in the Rx BD */ + { + p_CurData = BdBufferGet(p_FmPort->im.rxPool.f_PhysToVirt, BD_GET(p_FmPort->im.currBdId)); + + BdBufferSet(p_FmPort->im.rxPool.f_VirtToPhys, BD_GET(p_FmPort->im.currBdId), NULL); + BD_STATUS_AND_LENGTH_SET(BD_GET(p_FmPort->im.currBdId), 0); + + p_FmPort->im.rxPool.f_PutBuf(p_FmPort->im.rxPool.h_BufferPool, + p_CurData, + p_FmPort->im.p_BdShadow[p_FmPort->im.currBdId]); + + p_FmPort->im.currBdId = GetNextBdId(p_FmPort, p_FmPort->im.currBdId); + bdStatus = BD_STATUS_AND_LENGTH(BD_GET(p_FmPort->im.currBdId)); + } + } + else + TxConf(p_FmPort, e_TX_CONF_TYPE_FLUSH); + + FM_MURAM_FreeMem(p_FmPort->im.h_FmMuram, p_FmPort->im.p_FmPortImPram); + + if (p_FmPort->im.p_BdShadow) + XX_Free(p_FmPort->im.p_BdShadow); + + if (p_FmPort->im.p_BdRing) + XX_FreeSmart(p_FmPort->im.p_BdRing); +} + + +t_Error FM_PORT_ConfigIMMaxRxBufLength(t_Handle h_FmPort, uint16_t newVal) +{ + t_FmPort *p_FmPort = (t_FmPort*)h_FmPort; + + SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_FmPort->imEn, E_INVALID_STATE); + SANITY_CHECK_RETURN_ERROR(p_FmPort->p_FmPortDriverParam, E_INVALID_HANDLE); + + p_FmPort->im.mrblr = newVal; + + return E_OK; +} + +t_Error FM_PORT_ConfigIMRxBdRingLength(t_Handle h_FmPort, uint16_t newVal) +{ + t_FmPort *p_FmPort = (t_FmPort*)h_FmPort; + + SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_FmPort->imEn, E_INVALID_STATE); + SANITY_CHECK_RETURN_ERROR(p_FmPort->p_FmPortDriverParam, E_INVALID_HANDLE); + + p_FmPort->im.bdRingSize = newVal; + + return E_OK; +} + +t_Error FM_PORT_ConfigIMTxBdRingLength(t_Handle h_FmPort, uint16_t newVal) +{ + t_FmPort *p_FmPort = (t_FmPort*)h_FmPort; + + SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_FmPort->imEn, E_INVALID_STATE); + SANITY_CHECK_RETURN_ERROR(p_FmPort->p_FmPortDriverParam, E_INVALID_HANDLE); + + p_FmPort->im.bdRingSize = newVal; + + return E_OK; +} + +t_Error FM_PORT_ConfigIMFmanCtrlExternalStructsMemory(t_Handle h_FmPort, + uint8_t memId, + uint32_t memAttributes) +{ + t_FmPort *p_FmPort = (t_FmPort*)h_FmPort; + + SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_FmPort->imEn, E_INVALID_STATE); + SANITY_CHECK_RETURN_ERROR(p_FmPort->p_FmPortDriverParam, E_INVALID_HANDLE); + + p_FmPort->im.fwExtStructsMemId = memId; + p_FmPort->im.fwExtStructsMemAttr = memAttributes; + + return E_OK; +} + +t_Error FM_PORT_ConfigIMPolling(t_Handle h_FmPort) +{ + t_FmPort *p_FmPort = (t_FmPort*)h_FmPort; + + SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_FmPort->imEn, E_INVALID_STATE); + SANITY_CHECK_RETURN_ERROR(p_FmPort->p_FmPortDriverParam, E_INVALID_HANDLE); + + if ((p_FmPort->portType != e_FM_PORT_TYPE_RX_10G) && (p_FmPort->portType != e_FM_PORT_TYPE_RX)) + RETURN_ERROR(MAJOR, E_INVALID_OPERATION, ("Available for Rx ports only")); + + if (!FmIsMaster(p_FmPort->h_Fm)) + RETURN_ERROR(MAJOR, E_INVALID_OPERATION, ("Available on master-partition only;" + "in guest-partitions, IM is always in polling!")); + + p_FmPort->polling = TRUE; + + return E_OK; +} + +t_Error FM_PORT_SetIMExceptions(t_Handle h_FmPort, e_FmPortExceptions exception, bool enable) +{ + t_FmPort *p_FmPort = (t_FmPort*)h_FmPort; + t_Error err; + uint16_t tmpReg16; + uint32_t tmpReg32; + + SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_FmPort->imEn, E_INVALID_STATE); + SANITY_CHECK_RETURN_ERROR(!p_FmPort->p_FmPortDriverParam, E_INVALID_HANDLE); + + if (exception == e_FM_PORT_EXCEPTION_IM_BUSY) + { + if (enable) + { + p_FmPort->exceptions |= IM_EV_BSY; + if (p_FmPort->fmanCtrlEventId == (uint8_t)NO_IRQ) + { + /* Allocate, configure and register interrupts */ + err = FmAllocFmanCtrlEventReg(p_FmPort->h_Fm, &p_FmPort->fmanCtrlEventId); + if (err) + RETURN_ERROR(MAJOR, err, NO_MSG); + ASSERT_COND(!(p_FmPort->fmanCtrlEventId & ~IM_RXQD_FPMEVT_SEL_MASK)); + + FmRegisterFmanCtrlIntr(p_FmPort->h_Fm, p_FmPort->fmanCtrlEventId, ImException, (t_Handle)p_FmPort); + tmpReg16 = (uint16_t)((p_FmPort->fmanCtrlEventId & IM_RXQD_FPMEVT_SEL_MASK) | IM_RXQD_BSYINTM); + tmpReg32 = IM_EV_BSY; + } + else + { + tmpReg16 = (uint16_t)(GET_UINT16(p_FmPort->im.p_FmPortImPram->rxQd.gen) | IM_RXQD_BSYINTM); + tmpReg32 = FmGetFmanCtrlIntr(p_FmPort->h_Fm, p_FmPort->fmanCtrlEventId) | IM_EV_BSY; + } + + WRITE_UINT16(p_FmPort->im.p_FmPortImPram->rxQd.gen, tmpReg16); + FmSetFmanCtrlIntr(p_FmPort->h_Fm, p_FmPort->fmanCtrlEventId, tmpReg32); + } + else + { + p_FmPort->exceptions &= ~IM_EV_BSY; + if (!p_FmPort->exceptions && p_FmPort->polling) + { + FmFreeFmanCtrlEventReg(p_FmPort->h_Fm, p_FmPort->fmanCtrlEventId); + FmUnregisterFmanCtrlIntr(p_FmPort->h_Fm, p_FmPort->fmanCtrlEventId); + FmSetFmanCtrlIntr(p_FmPort->h_Fm, p_FmPort->fmanCtrlEventId, 0); + WRITE_UINT16(p_FmPort->im.p_FmPortImPram->rxQd.gen, 0); + p_FmPort->fmanCtrlEventId = (uint8_t)NO_IRQ; + } + else + { + tmpReg16 = (uint16_t)(GET_UINT16(p_FmPort->im.p_FmPortImPram->rxQd.gen) & ~IM_RXQD_BSYINTM); + WRITE_UINT16(p_FmPort->im.p_FmPortImPram->rxQd.gen, tmpReg16); + tmpReg32 = FmGetFmanCtrlIntr(p_FmPort->h_Fm, p_FmPort->fmanCtrlEventId) & ~IM_EV_BSY; + FmSetFmanCtrlIntr(p_FmPort->h_Fm, p_FmPort->fmanCtrlEventId, tmpReg32); + } + } + } + else + RETURN_ERROR(MINOR, E_INVALID_SELECTION, ("Invalid exception.")); + + return E_OK; +} + +t_Error FM_PORT_ImTx( t_Handle h_FmPort, + uint8_t *p_Data, + uint16_t length, + bool lastBuffer, + t_Handle h_BufContext) +{ + t_FmPort *p_FmPort = (t_FmPort*)h_FmPort; + uint16_t nextBdId; + uint32_t bdStatus, nextBdStatus; + bool firstBuffer; + + SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_FmPort->imEn, E_INVALID_STATE); + SANITY_CHECK_RETURN_ERROR(!p_FmPort->p_FmPortDriverParam, E_INVALID_HANDLE); + + bdStatus = BD_STATUS_AND_LENGTH(BD_GET(p_FmPort->im.currBdId)); + nextBdId = GetNextBdId(p_FmPort, p_FmPort->im.currBdId); + nextBdStatus = BD_STATUS_AND_LENGTH(BD_GET(nextBdId)); + + if (!(bdStatus & BD_R_E) && !(nextBdStatus & BD_R_E)) + { + /* Confirm the current BD - BD is available */ + if ((bdStatus & BD_LENGTH_MASK) && (p_FmPort->im.f_TxConf)) + p_FmPort->im.f_TxConf (p_FmPort->h_App, + BdBufferGet(XX_PhysToVirt, BD_GET(p_FmPort->im.currBdId)), + 0, + p_FmPort->im.p_BdShadow[p_FmPort->im.currBdId]); + + bdStatus = length; + + /* if this is the first BD of a frame */ + if (p_FmPort->im.firstBdOfFrameId == IM_ILEGAL_BD_ID) + { + firstBuffer = TRUE; + p_FmPort->im.txFirstBdStatus = (bdStatus | BD_R_E); + + if (!lastBuffer) + p_FmPort->im.firstBdOfFrameId = p_FmPort->im.currBdId; + } + else + firstBuffer = FALSE; + + BdBufferSet(XX_VirtToPhys, BD_GET(p_FmPort->im.currBdId), p_Data); + p_FmPort->im.p_BdShadow[p_FmPort->im.currBdId] = h_BufContext; + + /* deal with last */ + if (lastBuffer) + { + /* if single buffer frame */ + if (firstBuffer) + BD_STATUS_AND_LENGTH_SET(BD_GET(p_FmPort->im.currBdId), p_FmPort->im.txFirstBdStatus | BD_L); + else + { + /* Set the last BD of the frame */ + BD_STATUS_AND_LENGTH_SET (BD_GET(p_FmPort->im.currBdId), (bdStatus | BD_R_E | BD_L)); + /* Set the first BD of the frame */ + BD_STATUS_AND_LENGTH_SET(BD_GET(p_FmPort->im.firstBdOfFrameId), p_FmPort->im.txFirstBdStatus); + p_FmPort->im.firstBdOfFrameId = IM_ILEGAL_BD_ID; + } + WRITE_UINT16(p_FmPort->im.p_FmPortImPram->txQd.offsetIn, (uint16_t)(GetNextBdId(p_FmPort, p_FmPort->im.currBdId)<<4)); + } + else if (!firstBuffer) /* mid frame buffer */ + BD_STATUS_AND_LENGTH_SET (BD_GET(p_FmPort->im.currBdId), bdStatus | BD_R_E); + + p_FmPort->im.currBdId = GetNextBdId(p_FmPort, p_FmPort->im.currBdId); + } + else + { + /* Discard current frame. Return error. */ + if (p_FmPort->im.firstBdOfFrameId != IM_ILEGAL_BD_ID) + { + /* Error: No free BD */ + /* Response: Discard current frame. Return error. */ + uint16_t cleanBdId = p_FmPort->im.firstBdOfFrameId; + + ASSERT_COND(p_FmPort->im.firstBdOfFrameId != p_FmPort->im.currBdId); + + /* Since firstInFrame is not NULL, one buffer at least has already been + inserted into the BD ring. Using do-while covers the situation of a + frame spanned throughout the whole Tx BD ring (p_CleanBd is incremented + prior to testing whether or not it's equal to TxBd). */ + do + { + BD_STATUS_AND_LENGTH_SET(BD_GET(cleanBdId), 0); + /* Advance BD pointer */ + cleanBdId = GetNextBdId(p_FmPort, cleanBdId); + } while (cleanBdId != p_FmPort->im.currBdId); + + p_FmPort->im.currBdId = cleanBdId; + p_FmPort->im.firstBdOfFrameId = IM_ILEGAL_BD_ID; + } + + return ERROR_CODE(E_FULL); + } + + return E_OK; +} + +void FM_PORT_ImTxConf(t_Handle h_FmPort) +{ + t_FmPort *p_FmPort = (t_FmPort*)h_FmPort; + + SANITY_CHECK_RETURN(p_FmPort, E_INVALID_HANDLE); + SANITY_CHECK_RETURN(p_FmPort->imEn, E_INVALID_STATE); + SANITY_CHECK_RETURN(!p_FmPort->p_FmPortDriverParam, E_INVALID_HANDLE); + + TxConf(p_FmPort, e_TX_CONF_TYPE_CALLBACK); +} + +t_Error FM_PORT_ImRx(t_Handle h_FmPort) +{ + t_FmPort *p_FmPort = (t_FmPort*)h_FmPort; + + SANITY_CHECK_RETURN_ERROR(p_FmPort, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_FmPort->imEn, E_INVALID_STATE); + SANITY_CHECK_RETURN_ERROR(!p_FmPort->p_FmPortDriverParam, E_INVALID_HANDLE); + + return FmPortImRx(p_FmPort); +} diff --git a/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Port/fman_port.c b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Port/fman_port.c new file mode 100755 index 000000000000..aaca1d711c78 --- /dev/null +++ b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Port/fman_port.c @@ -0,0 +1,1570 @@ +/* + * Copyright 2008-2012 Freescale Semiconductor Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Freescale Semiconductor nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * + * ALTERNATIVELY, this software may be distributed under the terms of the + * GNU General Public License ("GPL") as published by the Free Software + * Foundation, either version 2 of that License or (at your option) any + * later version. + * + * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + +#include "std_ext.h" +#include "error_ext.h" +#include "common/general.h" + +#include "fman_common.h" +#include "fsl_fman_port.h" + + +/* problem Eyal: the following should not be here*/ +#define NIA_FM_CTL_AC_NO_IPACC_PRE_BMI_ENQ_FRAME 0x00000028 + +static uint32_t get_no_pcd_nia_bmi_ac_enc_frame(struct fman_port_cfg *cfg) +{ + if (cfg->errata_A006675) + return NIA_ENG_FM_CTL | + NIA_FM_CTL_AC_NO_IPACC_PRE_BMI_ENQ_FRAME; + else + return NIA_ENG_BMI | NIA_BMI_AC_ENQ_FRAME; +} + +static int init_bmi_rx(struct fman_port *port, + struct fman_port_cfg *cfg, + struct fman_port_params *params) +{ + struct fman_port_rx_bmi_regs *regs = &port->bmi_regs->rx; + uint32_t tmp; + + /* Rx Configuration register */ + tmp = 0; + if (port->im_en) + tmp |= BMI_PORT_CFG_IM; + else if (cfg->discard_override) + tmp |= BMI_PORT_CFG_FDOVR; + iowrite32be(tmp, ®s->fmbm_rcfg); + + /* DMA attributes */ + tmp = (uint32_t)cfg->dma_swap_data << BMI_DMA_ATTR_SWP_SHIFT; + if (cfg->dma_ic_stash_on) + tmp |= BMI_DMA_ATTR_IC_STASH_ON; + if (cfg->dma_header_stash_on) + tmp |= BMI_DMA_ATTR_HDR_STASH_ON; + if (cfg->dma_sg_stash_on) + tmp |= BMI_DMA_ATTR_SG_STASH_ON; + if (cfg->dma_write_optimize) + tmp |= BMI_DMA_ATTR_WRITE_OPTIMIZE; + iowrite32be(tmp, ®s->fmbm_rda); + + /* Rx FIFO parameters */ + tmp = (cfg->rx_pri_elevation / FMAN_PORT_BMI_FIFO_UNITS - 1) << + BMI_RX_FIFO_PRI_ELEVATION_SHIFT; + tmp |= cfg->rx_fifo_thr / FMAN_PORT_BMI_FIFO_UNITS - 1; + iowrite32be(tmp, ®s->fmbm_rfp); + + if (cfg->excessive_threshold_register) + /* always allow access to the extra resources */ + iowrite32be(BMI_RX_FIFO_THRESHOLD_ETHE, ®s->fmbm_reth); + + /* Frame end data */ + tmp = (uint32_t)cfg->checksum_bytes_ignore << + BMI_RX_FRAME_END_CS_IGNORE_SHIFT; + tmp |= (uint32_t)cfg->rx_cut_end_bytes << + BMI_RX_FRAME_END_CUT_SHIFT; + if (cfg->errata_A006320) + tmp &= 0xffe0ffff; + iowrite32be(tmp, ®s->fmbm_rfed); + + /* Internal context parameters */ + tmp = ((uint32_t)cfg->ic_ext_offset / FMAN_PORT_IC_OFFSET_UNITS) << + BMI_IC_TO_EXT_SHIFT; + tmp |= ((uint32_t)cfg->ic_int_offset / FMAN_PORT_IC_OFFSET_UNITS) << + BMI_IC_FROM_INT_SHIFT; + tmp |= cfg->ic_size / FMAN_PORT_IC_OFFSET_UNITS; + iowrite32be(tmp, ®s->fmbm_ricp); + + /* Internal buffer offset */ + tmp = ((uint32_t)cfg->int_buf_start_margin / FMAN_PORT_IC_OFFSET_UNITS) + << BMI_INT_BUF_MARG_SHIFT; + iowrite32be(tmp, ®s->fmbm_rim); + + /* External buffer margins */ + if (!port->im_en) + { + tmp = (uint32_t)cfg->ext_buf_start_margin << + BMI_EXT_BUF_MARG_START_SHIFT; + tmp |= (uint32_t)cfg->ext_buf_end_margin; + if (cfg->fmbm_rebm_has_sgd && cfg->no_scatter_gather) + tmp |= BMI_SG_DISABLE; + iowrite32be(tmp, ®s->fmbm_rebm); + } + + /* Frame attributes */ + tmp = BMI_CMD_RX_MR_DEF; + if (!port->im_en) + { + tmp |= BMI_CMD_ATTR_ORDER; + tmp |= (uint32_t)cfg->color << BMI_CMD_ATTR_COLOR_SHIFT; + if (cfg->sync_req) + tmp |= BMI_CMD_ATTR_SYNC; + } + iowrite32be(tmp, ®s->fmbm_rfca); + + /* NIA */ + if (port->im_en) + tmp = NIA_ENG_FM_CTL | NIA_FM_CTL_AC_IND_MODE_RX; + else + { + tmp = (uint32_t)cfg->rx_fd_bits << BMI_NEXT_ENG_FD_BITS_SHIFT; + tmp |= get_no_pcd_nia_bmi_ac_enc_frame(cfg); + } + iowrite32be(tmp, ®s->fmbm_rfne); + + /* Enqueue NIA */ + iowrite32be(NIA_ENG_QMI_ENQ | NIA_ORDER_RESTOR, ®s->fmbm_rfene); + + /* Default/error queues */ + if (!port->im_en) + { + iowrite32be((params->dflt_fqid & 0x00FFFFFF), ®s->fmbm_rfqid); + iowrite32be((params->err_fqid & 0x00FFFFFF), ®s->fmbm_refqid); + } + + /* Discard/error masks */ + iowrite32be(params->discard_mask, ®s->fmbm_rfsdm); + iowrite32be(params->err_mask, ®s->fmbm_rfsem); + + /* Statistics counters */ + tmp = 0; + if (cfg->stats_counters_enable) + tmp = BMI_COUNTERS_EN; + iowrite32be(tmp, ®s->fmbm_rstc); + + /* Performance counters */ + fman_port_set_perf_cnt_params(port, &cfg->perf_cnt_params); + tmp = 0; + if (cfg->perf_counters_enable) + tmp = BMI_COUNTERS_EN; + iowrite32be(tmp, ®s->fmbm_rpc); + + return 0; +} + +static int init_bmi_tx(struct fman_port *port, + struct fman_port_cfg *cfg, + struct fman_port_params *params) +{ + struct fman_port_tx_bmi_regs *regs = &port->bmi_regs->tx; + uint32_t tmp; + + /* Tx Configuration register */ + tmp = 0; + if (port->im_en) + tmp |= BMI_PORT_CFG_IM; + iowrite32be(tmp, ®s->fmbm_tcfg); + + /* DMA attributes */ + tmp = (uint32_t)cfg->dma_swap_data << BMI_DMA_ATTR_SWP_SHIFT; + if (cfg->dma_ic_stash_on) + tmp |= BMI_DMA_ATTR_IC_STASH_ON; + if (cfg->dma_header_stash_on) + tmp |= BMI_DMA_ATTR_HDR_STASH_ON; + if (cfg->dma_sg_stash_on) + tmp |= BMI_DMA_ATTR_SG_STASH_ON; + iowrite32be(tmp, ®s->fmbm_tda); + + /* Tx FIFO parameters */ + tmp = (cfg->tx_fifo_min_level / FMAN_PORT_BMI_FIFO_UNITS) << + BMI_TX_FIFO_MIN_FILL_SHIFT; + tmp |= ((uint32_t)cfg->tx_fifo_deq_pipeline_depth - 1) << + BMI_FIFO_PIPELINE_DEPTH_SHIFT; + tmp |= (uint32_t)(cfg->tx_fifo_low_comf_level / + FMAN_PORT_BMI_FIFO_UNITS - 1); + iowrite32be(tmp, ®s->fmbm_tfp); + + /* Frame end data */ + tmp = (uint32_t)cfg->checksum_bytes_ignore << + BMI_FRAME_END_CS_IGNORE_SHIFT; + iowrite32be(tmp, ®s->fmbm_tfed); + + /* Internal context parameters */ + if (!port->im_en) + { + tmp = ((uint32_t)cfg->ic_ext_offset / FMAN_PORT_IC_OFFSET_UNITS) << + BMI_IC_TO_EXT_SHIFT; + tmp |= ((uint32_t)cfg->ic_int_offset / FMAN_PORT_IC_OFFSET_UNITS) << + BMI_IC_FROM_INT_SHIFT; + tmp |= cfg->ic_size / FMAN_PORT_IC_OFFSET_UNITS; + iowrite32be(tmp, ®s->fmbm_ticp); + } + /* Frame attributes */ + tmp = BMI_CMD_TX_MR_DEF; + if (port->im_en) + tmp |= BMI_CMD_MR_DEAS; + else + { + tmp |= BMI_CMD_ATTR_ORDER; + tmp |= (uint32_t)cfg->color << BMI_CMD_ATTR_COLOR_SHIFT; + } + iowrite32be(tmp, ®s->fmbm_tfca); + + /* Dequeue NIA + enqueue NIA */ + if (port->im_en) + { + iowrite32be(NIA_ENG_FM_CTL | NIA_FM_CTL_AC_IND_MODE_TX, ®s->fmbm_tfdne); + iowrite32be(NIA_ENG_FM_CTL | NIA_FM_CTL_AC_IND_MODE_TX, ®s->fmbm_tfene); + } + else + { + iowrite32be(NIA_ENG_QMI_DEQ, ®s->fmbm_tfdne); + iowrite32be(NIA_ENG_QMI_ENQ | NIA_ORDER_RESTOR, ®s->fmbm_tfene); + if (cfg->fmbm_tfne_has_features) + iowrite32be(!params->dflt_fqid ? + BMI_EBD_EN | NIA_BMI_AC_FETCH_ALL_FRAME : + NIA_BMI_AC_FETCH_ALL_FRAME, ®s->fmbm_tfne); + if (!params->dflt_fqid && params->dont_release_buf) + { + iowrite32be(0x00FFFFFF, ®s->fmbm_tcfqid); + iowrite32be(NIA_ENG_BMI | NIA_BMI_AC_TX_RELEASE, ®s->fmbm_tfene); + if (cfg->fmbm_tfne_has_features) + iowrite32be(ioread32be(®s->fmbm_tfne) & ~BMI_EBD_EN, ®s->fmbm_tfne); + } + } + + /* Confirmation/error queues */ + if (!port->im_en) + { + if (params->dflt_fqid || !params->dont_release_buf) + iowrite32be(params->dflt_fqid & 0x00FFFFFF, ®s->fmbm_tcfqid); + iowrite32be((params->err_fqid & 0x00FFFFFF), ®s->fmbm_tefqid); + } + /* Statistics counters */ + tmp = 0; + if (cfg->stats_counters_enable) + tmp = BMI_COUNTERS_EN; + iowrite32be(tmp, ®s->fmbm_tstc); + + /* Performance counters */ + fman_port_set_perf_cnt_params(port, &cfg->perf_cnt_params); + tmp = 0; + if (cfg->perf_counters_enable) + tmp = BMI_COUNTERS_EN; + iowrite32be(tmp, ®s->fmbm_tpc); + + return 0; +} + +static int init_bmi_oh(struct fman_port *port, + struct fman_port_cfg *cfg, + struct fman_port_params *params) +{ + struct fman_port_oh_bmi_regs *regs = &port->bmi_regs->oh; + uint32_t tmp; + + /* OP Configuration register */ + tmp = 0; + if (cfg->discard_override) + tmp |= BMI_PORT_CFG_FDOVR; + iowrite32be(tmp, ®s->fmbm_ocfg); + + /* DMA attributes */ + tmp = (uint32_t)cfg->dma_swap_data << BMI_DMA_ATTR_SWP_SHIFT; + if (cfg->dma_ic_stash_on) + tmp |= BMI_DMA_ATTR_IC_STASH_ON; + if (cfg->dma_header_stash_on) + tmp |= BMI_DMA_ATTR_HDR_STASH_ON; + if (cfg->dma_sg_stash_on) + tmp |= BMI_DMA_ATTR_SG_STASH_ON; + if (cfg->dma_write_optimize) + tmp |= BMI_DMA_ATTR_WRITE_OPTIMIZE; + iowrite32be(tmp, ®s->fmbm_oda); + + /* Tx FIFO parameters */ + tmp = ((uint32_t)cfg->tx_fifo_deq_pipeline_depth - 1) << + BMI_FIFO_PIPELINE_DEPTH_SHIFT; + iowrite32be(tmp, ®s->fmbm_ofp); + + /* Internal context parameters */ + tmp = ((uint32_t)cfg->ic_ext_offset / FMAN_PORT_IC_OFFSET_UNITS) << + BMI_IC_TO_EXT_SHIFT; + tmp |= ((uint32_t)cfg->ic_int_offset / FMAN_PORT_IC_OFFSET_UNITS) << + BMI_IC_FROM_INT_SHIFT; + tmp |= cfg->ic_size / FMAN_PORT_IC_OFFSET_UNITS; + iowrite32be(tmp, ®s->fmbm_oicp); + + /* Frame attributes */ + tmp = BMI_CMD_OP_MR_DEF; + tmp |= (uint32_t)cfg->color << BMI_CMD_ATTR_COLOR_SHIFT; + if (cfg->sync_req) + tmp |= BMI_CMD_ATTR_SYNC; + if (port->type == E_FMAN_PORT_TYPE_OP) + tmp |= BMI_CMD_ATTR_ORDER; + iowrite32be(tmp, ®s->fmbm_ofca); + + /* Internal buffer offset */ + tmp = ((uint32_t)cfg->int_buf_start_margin / FMAN_PORT_IC_OFFSET_UNITS) + << BMI_INT_BUF_MARG_SHIFT; + iowrite32be(tmp, ®s->fmbm_oim); + + /* Dequeue NIA */ + iowrite32be(NIA_ENG_QMI_DEQ, ®s->fmbm_ofdne); + + /* NIA and Enqueue NIA */ + if (port->type == E_FMAN_PORT_TYPE_HC) { + iowrite32be(NIA_ENG_FM_CTL | NIA_FM_CTL_AC_HC, + ®s->fmbm_ofne); + iowrite32be(NIA_ENG_QMI_ENQ, ®s->fmbm_ofene); + } else { + iowrite32be(get_no_pcd_nia_bmi_ac_enc_frame(cfg), + ®s->fmbm_ofne); + iowrite32be(NIA_ENG_QMI_ENQ | NIA_ORDER_RESTOR, + ®s->fmbm_ofene); + } + + /* Default/error queues */ + iowrite32be((params->dflt_fqid & 0x00FFFFFF), ®s->fmbm_ofqid); + iowrite32be((params->err_fqid & 0x00FFFFFF), ®s->fmbm_oefqid); + + /* Discard/error masks */ + if (port->type == E_FMAN_PORT_TYPE_OP) { + iowrite32be(params->discard_mask, ®s->fmbm_ofsdm); + iowrite32be(params->err_mask, ®s->fmbm_ofsem); + } + + /* Statistics counters */ + tmp = 0; + if (cfg->stats_counters_enable) + tmp = BMI_COUNTERS_EN; + iowrite32be(tmp, ®s->fmbm_ostc); + + /* Performance counters */ + fman_port_set_perf_cnt_params(port, &cfg->perf_cnt_params); + tmp = 0; + if (cfg->perf_counters_enable) + tmp = BMI_COUNTERS_EN; + iowrite32be(tmp, ®s->fmbm_opc); + + return 0; +} + +static int init_qmi(struct fman_port *port, + struct fman_port_cfg *cfg, + struct fman_port_params *params) +{ + struct fman_port_qmi_regs *regs = port->qmi_regs; + uint32_t tmp; + + tmp = 0; + if (cfg->queue_counters_enable) + tmp |= QMI_PORT_CFG_EN_COUNTERS; + iowrite32be(tmp, ®s->fmqm_pnc); + + /* Rx port configuration */ + if ((port->type == E_FMAN_PORT_TYPE_RX) || + (port->type == E_FMAN_PORT_TYPE_RX_10G)) { + /* Enqueue NIA */ + iowrite32be(NIA_ENG_BMI | NIA_BMI_AC_RELEASE, ®s->fmqm_pnen); + return 0; + } + + /* Continue with Tx and O/H port configuration */ + if ((port->type == E_FMAN_PORT_TYPE_TX) || + (port->type == E_FMAN_PORT_TYPE_TX_10G)) { + /* Enqueue NIA */ + iowrite32be(NIA_ENG_BMI | NIA_BMI_AC_TX_RELEASE, + ®s->fmqm_pnen); + /* Dequeue NIA */ + iowrite32be(NIA_ENG_BMI | NIA_BMI_AC_TX, ®s->fmqm_pndn); + } else { + /* Enqueue NIA */ + iowrite32be(NIA_ENG_BMI | NIA_BMI_AC_RELEASE, ®s->fmqm_pnen); + /* Dequeue NIA */ + iowrite32be(NIA_ENG_BMI | NIA_BMI_AC_FETCH, ®s->fmqm_pndn); + } + + /* Dequeue Configuration register */ + tmp = 0; + if (cfg->deq_high_pri) + tmp |= QMI_DEQ_CFG_PRI; + + switch (cfg->deq_type) { + case E_FMAN_PORT_DEQ_BY_PRI: + tmp |= QMI_DEQ_CFG_TYPE1; + break; + case E_FMAN_PORT_DEQ_ACTIVE_FQ: + tmp |= QMI_DEQ_CFG_TYPE2; + break; + case E_FMAN_PORT_DEQ_ACTIVE_FQ_NO_ICS: + tmp |= QMI_DEQ_CFG_TYPE3; + break; + default: + return -EINVAL; + } + + if (cfg->qmi_deq_options_support) { + if ((port->type == E_FMAN_PORT_TYPE_HC) && + (cfg->deq_prefetch_opt != E_FMAN_PORT_DEQ_NO_PREFETCH)) + return -EINVAL; + + switch (cfg->deq_prefetch_opt) { + case E_FMAN_PORT_DEQ_NO_PREFETCH: + break; + case E_FMAN_PORT_DEQ_PART_PREFETCH: + tmp |= QMI_DEQ_CFG_PREFETCH_PARTIAL; + break; + case E_FMAN_PORT_DEQ_FULL_PREFETCH: + tmp |= QMI_DEQ_CFG_PREFETCH_FULL; + break; + default: + return -EINVAL; + } + } + tmp |= (uint32_t)(params->deq_sp & QMI_DEQ_CFG_SP_MASK) << + QMI_DEQ_CFG_SP_SHIFT; + tmp |= cfg->deq_byte_cnt; + iowrite32be(tmp, ®s->fmqm_pndc); + + return 0; +} + +static void get_rx_stats_reg(struct fman_port *port, + enum fman_port_stats_counters counter, + uint32_t **stats_reg) +{ + struct fman_port_rx_bmi_regs *regs = &port->bmi_regs->rx; + + switch (counter) { + case E_FMAN_PORT_STATS_CNT_FRAME: + *stats_reg = ®s->fmbm_rfrc; + break; + case E_FMAN_PORT_STATS_CNT_DISCARD: + *stats_reg = ®s->fmbm_rfdc; + break; + case E_FMAN_PORT_STATS_CNT_DEALLOC_BUF: + *stats_reg = ®s->fmbm_rbdc; + break; + case E_FMAN_PORT_STATS_CNT_RX_BAD_FRAME: + *stats_reg = ®s->fmbm_rfbc; + break; + case E_FMAN_PORT_STATS_CNT_RX_LARGE_FRAME: + *stats_reg = ®s->fmbm_rlfc; + break; + case E_FMAN_PORT_STATS_CNT_RX_OUT_OF_BUF: + *stats_reg = ®s->fmbm_rodc; + break; + case E_FMAN_PORT_STATS_CNT_FILTERED_FRAME: + *stats_reg = ®s->fmbm_rffc; + break; + case E_FMAN_PORT_STATS_CNT_DMA_ERR: + *stats_reg = ®s->fmbm_rfldec; + break; + default: + *stats_reg = NULL; + } +} + +static void get_tx_stats_reg(struct fman_port *port, + enum fman_port_stats_counters counter, + uint32_t **stats_reg) +{ + struct fman_port_tx_bmi_regs *regs = &port->bmi_regs->tx; + + switch (counter) { + case E_FMAN_PORT_STATS_CNT_FRAME: + *stats_reg = ®s->fmbm_tfrc; + break; + case E_FMAN_PORT_STATS_CNT_DISCARD: + *stats_reg = ®s->fmbm_tfdc; + break; + case E_FMAN_PORT_STATS_CNT_DEALLOC_BUF: + *stats_reg = ®s->fmbm_tbdc; + break; + case E_FMAN_PORT_STATS_CNT_LEN_ERR: + *stats_reg = ®s->fmbm_tfledc; + break; + case E_FMAN_PORT_STATS_CNT_UNSUPPORTED_FORMAT: + *stats_reg = ®s->fmbm_tfufdc; + break; + default: + *stats_reg = NULL; + } +} + +static void get_oh_stats_reg(struct fman_port *port, + enum fman_port_stats_counters counter, + uint32_t **stats_reg) +{ + struct fman_port_oh_bmi_regs *regs = &port->bmi_regs->oh; + + switch (counter) { + case E_FMAN_PORT_STATS_CNT_FRAME: + *stats_reg = ®s->fmbm_ofrc; + break; + case E_FMAN_PORT_STATS_CNT_DISCARD: + *stats_reg = ®s->fmbm_ofdc; + break; + case E_FMAN_PORT_STATS_CNT_DEALLOC_BUF: + *stats_reg = ®s->fmbm_obdc; + break; + case E_FMAN_PORT_STATS_CNT_FILTERED_FRAME: + *stats_reg = ®s->fmbm_offc; + break; + case E_FMAN_PORT_STATS_CNT_DMA_ERR: + *stats_reg = ®s->fmbm_ofldec; + break; + case E_FMAN_PORT_STATS_CNT_LEN_ERR: + *stats_reg = ®s->fmbm_ofledc; + break; + case E_FMAN_PORT_STATS_CNT_UNSUPPORTED_FORMAT: + *stats_reg = ®s->fmbm_ofufdc; + break; + case E_FMAN_PORT_STATS_CNT_WRED_DISCARD: + *stats_reg = ®s->fmbm_ofwdc; + break; + default: + *stats_reg = NULL; + } +} + +static void get_rx_perf_reg(struct fman_port *port, + enum fman_port_perf_counters counter, + uint32_t **perf_reg) +{ + struct fman_port_rx_bmi_regs *regs = &port->bmi_regs->rx; + + switch (counter) { + case E_FMAN_PORT_PERF_CNT_CYCLE: + *perf_reg = ®s->fmbm_rccn; + break; + case E_FMAN_PORT_PERF_CNT_TASK_UTIL: + *perf_reg = ®s->fmbm_rtuc; + break; + case E_FMAN_PORT_PERF_CNT_QUEUE_UTIL: + *perf_reg = ®s->fmbm_rrquc; + break; + case E_FMAN_PORT_PERF_CNT_DMA_UTIL: + *perf_reg = ®s->fmbm_rduc; + break; + case E_FMAN_PORT_PERF_CNT_FIFO_UTIL: + *perf_reg = ®s->fmbm_rfuc; + break; + case E_FMAN_PORT_PERF_CNT_RX_PAUSE: + *perf_reg = ®s->fmbm_rpac; + break; + default: + *perf_reg = NULL; + } +} + +static void get_tx_perf_reg(struct fman_port *port, + enum fman_port_perf_counters counter, + uint32_t **perf_reg) +{ + struct fman_port_tx_bmi_regs *regs = &port->bmi_regs->tx; + + switch (counter) { + case E_FMAN_PORT_PERF_CNT_CYCLE: + *perf_reg = ®s->fmbm_tccn; + break; + case E_FMAN_PORT_PERF_CNT_TASK_UTIL: + *perf_reg = ®s->fmbm_ttuc; + break; + case E_FMAN_PORT_PERF_CNT_QUEUE_UTIL: + *perf_reg = ®s->fmbm_ttcquc; + break; + case E_FMAN_PORT_PERF_CNT_DMA_UTIL: + *perf_reg = ®s->fmbm_tduc; + break; + case E_FMAN_PORT_PERF_CNT_FIFO_UTIL: + *perf_reg = ®s->fmbm_tfuc; + break; + default: + *perf_reg = NULL; + } +} + +static void get_oh_perf_reg(struct fman_port *port, + enum fman_port_perf_counters counter, + uint32_t **perf_reg) +{ + struct fman_port_oh_bmi_regs *regs = &port->bmi_regs->oh; + + switch (counter) { + case E_FMAN_PORT_PERF_CNT_CYCLE: + *perf_reg = ®s->fmbm_occn; + break; + case E_FMAN_PORT_PERF_CNT_TASK_UTIL: + *perf_reg = ®s->fmbm_otuc; + break; + case E_FMAN_PORT_PERF_CNT_DMA_UTIL: + *perf_reg = ®s->fmbm_oduc; + break; + case E_FMAN_PORT_PERF_CNT_FIFO_UTIL: + *perf_reg = ®s->fmbm_ofuc; + break; + default: + *perf_reg = NULL; + } +} + +static void get_qmi_counter_reg(struct fman_port *port, + enum fman_port_qmi_counters counter, + uint32_t **queue_reg) +{ + struct fman_port_qmi_regs *regs = port->qmi_regs; + + switch (counter) { + case E_FMAN_PORT_ENQ_TOTAL: + *queue_reg = ®s->fmqm_pnetfc; + break; + case E_FMAN_PORT_DEQ_TOTAL: + if ((port->type == E_FMAN_PORT_TYPE_RX) || + (port->type == E_FMAN_PORT_TYPE_RX_10G)) + /* Counter not available for Rx ports */ + *queue_reg = NULL; + else + *queue_reg = ®s->fmqm_pndtfc; + break; + case E_FMAN_PORT_DEQ_FROM_DFLT: + if ((port->type == E_FMAN_PORT_TYPE_RX) || + (port->type == E_FMAN_PORT_TYPE_RX_10G)) + /* Counter not available for Rx ports */ + *queue_reg = NULL; + else + *queue_reg = ®s->fmqm_pndfdc; + break; + case E_FMAN_PORT_DEQ_CONFIRM: + if ((port->type == E_FMAN_PORT_TYPE_RX) || + (port->type == E_FMAN_PORT_TYPE_RX_10G)) + /* Counter not available for Rx ports */ + *queue_reg = NULL; + else + *queue_reg = ®s->fmqm_pndcc; + break; + default: + *queue_reg = NULL; + } +} + +void fman_port_defconfig(struct fman_port_cfg *cfg, enum fman_port_type type) +{ + cfg->dma_swap_data = E_FMAN_PORT_DMA_NO_SWAP; + cfg->dma_ic_stash_on = FALSE; + cfg->dma_header_stash_on = FALSE; + cfg->dma_sg_stash_on = FALSE; + cfg->dma_write_optimize = TRUE; + cfg->color = E_FMAN_PORT_COLOR_GREEN; + cfg->discard_override = FALSE; + cfg->checksum_bytes_ignore = 0; + cfg->rx_cut_end_bytes = 4; + cfg->rx_pri_elevation = ((0x3FF + 1) * FMAN_PORT_BMI_FIFO_UNITS); + cfg->rx_fifo_thr = ((0x3FF + 1) * FMAN_PORT_BMI_FIFO_UNITS); + cfg->rx_fd_bits = 0; + cfg->ic_ext_offset = 0; + cfg->ic_int_offset = 0; + cfg->ic_size = 0; + cfg->int_buf_start_margin = 0; + cfg->ext_buf_start_margin = 0; + cfg->ext_buf_end_margin = 0; + cfg->tx_fifo_min_level = 0; + cfg->tx_fifo_low_comf_level = (5 * KILOBYTE); + cfg->stats_counters_enable = TRUE; + cfg->perf_counters_enable = TRUE; + cfg->deq_type = E_FMAN_PORT_DEQ_BY_PRI; + + if (type == E_FMAN_PORT_TYPE_HC) { + cfg->sync_req = FALSE; + cfg->deq_prefetch_opt = E_FMAN_PORT_DEQ_NO_PREFETCH; + } else { + cfg->sync_req = TRUE; + cfg->deq_prefetch_opt = E_FMAN_PORT_DEQ_FULL_PREFETCH; + } + + if (type == E_FMAN_PORT_TYPE_TX_10G) { + cfg->tx_fifo_deq_pipeline_depth = 4; + cfg->deq_high_pri = TRUE; + cfg->deq_byte_cnt = 0x1400; + } else { + if ((type == E_FMAN_PORT_TYPE_HC) || + (type == E_FMAN_PORT_TYPE_OP)) + cfg->tx_fifo_deq_pipeline_depth = 2; + else + cfg->tx_fifo_deq_pipeline_depth = 1; + + cfg->deq_high_pri = FALSE; + cfg->deq_byte_cnt = 0x400; + } + cfg->no_scatter_gather = DEFAULT_FMAN_SP_NO_SCATTER_GATHER; +} + +static uint8_t fman_port_find_bpool(struct fman_port *port, uint8_t bpid) +{ + uint32_t *bp_reg, tmp; + uint8_t i, id; + + /* Find the pool */ + bp_reg = port->bmi_regs->rx.fmbm_ebmpi; + for (i = 0; + (i < port->ext_pools_num && (i < FMAN_PORT_MAX_EXT_POOLS_NUM)); + i++) { + tmp = ioread32be(&bp_reg[i]); + id = (uint8_t)((tmp & BMI_EXT_BUF_POOL_ID_MASK) >> + BMI_EXT_BUF_POOL_ID_SHIFT); + + if (id == bpid) + break; + } + + return i; +} + +int fman_port_init(struct fman_port *port, + struct fman_port_cfg *cfg, + struct fman_port_params *params) +{ + int err; + + /* Init BMI registers */ + switch (port->type) { + case E_FMAN_PORT_TYPE_RX: + case E_FMAN_PORT_TYPE_RX_10G: + err = init_bmi_rx(port, cfg, params); + break; + case E_FMAN_PORT_TYPE_TX: + case E_FMAN_PORT_TYPE_TX_10G: + err = init_bmi_tx(port, cfg, params); + break; + case E_FMAN_PORT_TYPE_OP: + case E_FMAN_PORT_TYPE_HC: + err = init_bmi_oh(port, cfg, params); + break; + default: + return -EINVAL; + } + + if (err) + return err; + + /* Init QMI registers */ + if (!port->im_en) + { + err = init_qmi(port, cfg, params); + return err; + } + return 0; +} + +int fman_port_enable(struct fman_port *port) +{ + uint32_t *bmi_cfg_reg, tmp; + bool rx_port; + + switch (port->type) { + case E_FMAN_PORT_TYPE_RX: + case E_FMAN_PORT_TYPE_RX_10G: + bmi_cfg_reg = &port->bmi_regs->rx.fmbm_rcfg; + rx_port = TRUE; + break; + case E_FMAN_PORT_TYPE_TX: + case E_FMAN_PORT_TYPE_TX_10G: + bmi_cfg_reg = &port->bmi_regs->tx.fmbm_tcfg; + rx_port = FALSE; + break; + case E_FMAN_PORT_TYPE_OP: + case E_FMAN_PORT_TYPE_HC: + bmi_cfg_reg = &port->bmi_regs->oh.fmbm_ocfg; + rx_port = FALSE; + break; + default: + return -EINVAL; + } + + /* Enable QMI */ + if (!rx_port) { + tmp = ioread32be(&port->qmi_regs->fmqm_pnc) | QMI_PORT_CFG_EN; + iowrite32be(tmp, &port->qmi_regs->fmqm_pnc); + } + + /* Enable BMI */ + tmp = ioread32be(bmi_cfg_reg) | BMI_PORT_CFG_EN; + iowrite32be(tmp, bmi_cfg_reg); + + return 0; +} + +int fman_port_disable(const struct fman_port *port) +{ + uint32_t *bmi_cfg_reg, *bmi_status_reg, tmp; + bool rx_port, failure = FALSE; + int count; + + switch (port->type) { + case E_FMAN_PORT_TYPE_RX: + case E_FMAN_PORT_TYPE_RX_10G: + bmi_cfg_reg = &port->bmi_regs->rx.fmbm_rcfg; + bmi_status_reg = &port->bmi_regs->rx.fmbm_rst; + rx_port = TRUE; + break; + case E_FMAN_PORT_TYPE_TX: + case E_FMAN_PORT_TYPE_TX_10G: + bmi_cfg_reg = &port->bmi_regs->tx.fmbm_tcfg; + bmi_status_reg = &port->bmi_regs->tx.fmbm_tst; + rx_port = FALSE; + break; + case E_FMAN_PORT_TYPE_OP: + case E_FMAN_PORT_TYPE_HC: + bmi_cfg_reg = &port->bmi_regs->oh.fmbm_ocfg; + bmi_status_reg = &port->bmi_regs->oh.fmbm_ost; + rx_port = FALSE; + break; + default: + return -EINVAL; + } + + /* Disable QMI */ + if (!rx_port) { + tmp = ioread32be(&port->qmi_regs->fmqm_pnc) & ~QMI_PORT_CFG_EN; + iowrite32be(tmp, &port->qmi_regs->fmqm_pnc); + + /* Wait for QMI to finish FD handling */ + count = 100; + do { + udelay(10); + tmp = ioread32be(&port->qmi_regs->fmqm_pns); + } while ((tmp & QMI_PORT_STATUS_DEQ_FD_BSY) && --count); + + if (count == 0) + { + /* Timeout */ + failure = TRUE; + } + } + + /* Disable BMI */ + tmp = ioread32be(bmi_cfg_reg) & ~BMI_PORT_CFG_EN; + iowrite32be(tmp, bmi_cfg_reg); + + /* Wait for graceful stop end */ + count = 500; + do { + udelay(10); + tmp = ioread32be(bmi_status_reg); + } while ((tmp & BMI_PORT_STATUS_BSY) && --count); + + if (count == 0) + { + /* Timeout */ + failure = TRUE; + } + + if (failure) + return -EBUSY; + + return 0; +} + +int fman_port_set_bpools(const struct fman_port *port, + const struct fman_port_bpools *bp) +{ + uint32_t tmp, *bp_reg, *bp_depl_reg; + uint8_t i, max_bp_num; + bool grp_depl_used = FALSE, rx_port; + + switch (port->type) { + case E_FMAN_PORT_TYPE_RX: + case E_FMAN_PORT_TYPE_RX_10G: + max_bp_num = port->ext_pools_num; + rx_port = TRUE; + bp_reg = port->bmi_regs->rx.fmbm_ebmpi; + bp_depl_reg = &port->bmi_regs->rx.fmbm_mpd; + break; + case E_FMAN_PORT_TYPE_OP: + if (port->fm_rev_maj != 4) + return -EINVAL; + max_bp_num = FMAN_PORT_OBS_EXT_POOLS_NUM; + rx_port = FALSE; + bp_reg = port->bmi_regs->oh.fmbm_oebmpi; + bp_depl_reg = &port->bmi_regs->oh.fmbm_ompd; + break; + default: + return -EINVAL; + } + + if (rx_port) { + /* Check buffers are provided in ascending order */ + for (i = 0; + (i < (bp->count-1) && (i < FMAN_PORT_MAX_EXT_POOLS_NUM - 1)); + i++) { + if (bp->bpool[i].size > bp->bpool[i+1].size) + return -EINVAL; + } + } + + /* Set up external buffers pools */ + for (i = 0; i < bp->count; i++) { + tmp = BMI_EXT_BUF_POOL_VALID; + tmp |= ((uint32_t)bp->bpool[i].bpid << + BMI_EXT_BUF_POOL_ID_SHIFT) & BMI_EXT_BUF_POOL_ID_MASK; + + if (rx_port) { + if (bp->counters_enable) + tmp |= BMI_EXT_BUF_POOL_EN_COUNTER; + + if (bp->bpool[i].is_backup) + tmp |= BMI_EXT_BUF_POOL_BACKUP; + + tmp |= (uint32_t)bp->bpool[i].size; + } + + iowrite32be(tmp, &bp_reg[i]); + } + + /* Clear unused pools */ + for (i = bp->count; i < max_bp_num; i++) + iowrite32be(0, &bp_reg[i]); + + /* Pools depletion */ + tmp = 0; + for (i = 0; i < FMAN_PORT_MAX_EXT_POOLS_NUM; i++) { + if (bp->bpool[i].grp_bp_depleted) { + grp_depl_used = TRUE; + tmp |= 0x80000000 >> i; + } + + if (bp->bpool[i].single_bp_depleted) + tmp |= 0x80 >> i; + + if (bp->bpool[i].pfc_priorities_en) + tmp |= 0x0100 << i; + } + + if (grp_depl_used) + tmp |= ((uint32_t)bp->grp_bp_depleted_num - 1) << + BMI_POOL_DEP_NUM_OF_POOLS_SHIFT; + + iowrite32be(tmp, bp_depl_reg); + return 0; +} + +int fman_port_set_rate_limiter(struct fman_port *port, + struct fman_port_rate_limiter *rate_limiter) +{ + uint32_t *rate_limit_reg, *rate_limit_scale_reg; + uint32_t granularity, tmp; + uint8_t usec_bit, factor; + + switch (port->type) { + case E_FMAN_PORT_TYPE_TX: + case E_FMAN_PORT_TYPE_TX_10G: + rate_limit_reg = &port->bmi_regs->tx.fmbm_trlmt; + rate_limit_scale_reg = &port->bmi_regs->tx.fmbm_trlmts; + granularity = BMI_RATE_LIMIT_GRAN_TX; + break; + case E_FMAN_PORT_TYPE_OP: + rate_limit_reg = &port->bmi_regs->oh.fmbm_orlmt; + rate_limit_scale_reg = &port->bmi_regs->oh.fmbm_orlmts; + granularity = BMI_RATE_LIMIT_GRAN_OP; + break; + default: + return -EINVAL; + } + + /* Factor is per 1 usec count */ + factor = 1; + usec_bit = rate_limiter->count_1micro_bit; + + /* If rate limit is too small for an 1usec factor, adjust timestamp + * scale and multiply the factor */ + while (rate_limiter->rate < (granularity / factor)) { + if (usec_bit == 31) + /* Can't configure rate limiter - rate is too small */ + return -EINVAL; + + usec_bit++; + factor <<= 1; + } + + /* Figure out register value. The "while" above quarantees that + * (rate_limiter->rate * factor / granularity) >= 1 */ + tmp = (uint32_t)(rate_limiter->rate * factor / granularity - 1); + + /* Check rate limit isn't too large */ + if (tmp >= BMI_RATE_LIMIT_MAX_RATE_IN_GRAN_UNITS) + return -EINVAL; + + /* Check burst size is in allowed range */ + if ((rate_limiter->burst_size == 0) || + (rate_limiter->burst_size > + BMI_RATE_LIMIT_MAX_BURST_SIZE)) + return -EINVAL; + + tmp |= (uint32_t)(rate_limiter->burst_size - 1) << + BMI_RATE_LIMIT_MAX_BURST_SHIFT; + + if ((port->type == E_FMAN_PORT_TYPE_OP) && + (port->fm_rev_maj == 4)) { + if (rate_limiter->high_burst_size_gran) + tmp |= BMI_RATE_LIMIT_HIGH_BURST_SIZE_GRAN; + } + + iowrite32be(tmp, rate_limit_reg); + + /* Set up rate limiter scale register */ + tmp = BMI_RATE_LIMIT_SCALE_EN; + tmp |= (31 - (uint32_t)usec_bit) << BMI_RATE_LIMIT_SCALE_TSBS_SHIFT; + + if ((port->type == E_FMAN_PORT_TYPE_OP) && + (port->fm_rev_maj == 4)) + tmp |= rate_limiter->rate_factor; + + iowrite32be(tmp, rate_limit_scale_reg); + + return 0; +} + +int fman_port_delete_rate_limiter(struct fman_port *port) +{ + uint32_t *rate_limit_scale_reg; + + switch (port->type) { + case E_FMAN_PORT_TYPE_TX: + case E_FMAN_PORT_TYPE_TX_10G: + rate_limit_scale_reg = &port->bmi_regs->tx.fmbm_trlmts; + break; + case E_FMAN_PORT_TYPE_OP: + rate_limit_scale_reg = &port->bmi_regs->oh.fmbm_orlmts; + break; + default: + return -EINVAL; + } + + iowrite32be(0, rate_limit_scale_reg); + return 0; +} + +int fman_port_set_err_mask(struct fman_port *port, uint32_t err_mask) +{ + uint32_t *err_mask_reg; + + /* Obtain register address */ + switch (port->type) { + case E_FMAN_PORT_TYPE_RX: + case E_FMAN_PORT_TYPE_RX_10G: + err_mask_reg = &port->bmi_regs->rx.fmbm_rfsem; + break; + case E_FMAN_PORT_TYPE_OP: + err_mask_reg = &port->bmi_regs->oh.fmbm_ofsem; + break; + default: + return -EINVAL; + } + + iowrite32be(err_mask, err_mask_reg); + return 0; +} + +int fman_port_set_discard_mask(struct fman_port *port, uint32_t discard_mask) +{ + uint32_t *discard_mask_reg; + + /* Obtain register address */ + switch (port->type) { + case E_FMAN_PORT_TYPE_RX: + case E_FMAN_PORT_TYPE_RX_10G: + discard_mask_reg = &port->bmi_regs->rx.fmbm_rfsdm; + break; + case E_FMAN_PORT_TYPE_OP: + discard_mask_reg = &port->bmi_regs->oh.fmbm_ofsdm; + break; + default: + return -EINVAL; + } + + iowrite32be(discard_mask, discard_mask_reg); + return 0; +} + +int fman_port_modify_rx_fd_bits(struct fman_port *port, + uint8_t rx_fd_bits, + bool add) +{ + uint32_t tmp; + + switch (port->type) { + case E_FMAN_PORT_TYPE_RX: + case E_FMAN_PORT_TYPE_RX_10G: + break; + default: + return -EINVAL; + } + + tmp = ioread32be(&port->bmi_regs->rx.fmbm_rfne); + + if (add) + tmp |= (uint32_t)rx_fd_bits << BMI_NEXT_ENG_FD_BITS_SHIFT; + else + tmp &= ~((uint32_t)rx_fd_bits << BMI_NEXT_ENG_FD_BITS_SHIFT); + + iowrite32be(tmp, &port->bmi_regs->rx.fmbm_rfne); + return 0; +} + +int fman_port_set_perf_cnt_params(struct fman_port *port, + struct fman_port_perf_cnt_params *params) +{ + uint32_t *pcp_reg, tmp; + + /* Obtain register address and check parameters are in range */ + switch (port->type) { + case E_FMAN_PORT_TYPE_RX: + case E_FMAN_PORT_TYPE_RX_10G: + pcp_reg = &port->bmi_regs->rx.fmbm_rpcp; + if ((params->queue_val == 0) || + (params->queue_val > MAX_PERFORMANCE_RX_QUEUE_COMP)) + return -EINVAL; + break; + case E_FMAN_PORT_TYPE_TX: + case E_FMAN_PORT_TYPE_TX_10G: + pcp_reg = &port->bmi_regs->tx.fmbm_tpcp; + if ((params->queue_val == 0) || + (params->queue_val > MAX_PERFORMANCE_TX_QUEUE_COMP)) + return -EINVAL; + break; + case E_FMAN_PORT_TYPE_OP: + case E_FMAN_PORT_TYPE_HC: + pcp_reg = &port->bmi_regs->oh.fmbm_opcp; + if (params->queue_val != 0) + return -EINVAL; + break; + default: + return -EINVAL; + } + + if ((params->task_val == 0) || + (params->task_val > MAX_PERFORMANCE_TASK_COMP)) + return -EINVAL; + if ((params->dma_val == 0) || + (params->dma_val > MAX_PERFORMANCE_DMA_COMP)) + return -EINVAL; + if ((params->fifo_val == 0) || + ((params->fifo_val / FMAN_PORT_BMI_FIFO_UNITS) > + MAX_PERFORMANCE_FIFO_COMP)) + return -EINVAL; + tmp = (uint32_t)(params->task_val - 1) << + BMI_PERFORMANCE_TASK_COMP_SHIFT; + tmp |= (uint32_t)(params->dma_val - 1) << + BMI_PERFORMANCE_DMA_COMP_SHIFT; + tmp |= (uint32_t)(params->fifo_val / FMAN_PORT_BMI_FIFO_UNITS - 1); + + switch (port->type) { + case E_FMAN_PORT_TYPE_RX: + case E_FMAN_PORT_TYPE_RX_10G: + case E_FMAN_PORT_TYPE_TX: + case E_FMAN_PORT_TYPE_TX_10G: + tmp |= (uint32_t)(params->queue_val - 1) << + BMI_PERFORMANCE_QUEUE_COMP_SHIFT; + break; + default: + break; + } + + + iowrite32be(tmp, pcp_reg); + return 0; +} + +int fman_port_set_stats_cnt_mode(struct fman_port *port, bool enable) +{ + uint32_t *stats_reg, tmp; + + switch (port->type) { + case E_FMAN_PORT_TYPE_RX: + case E_FMAN_PORT_TYPE_RX_10G: + stats_reg = &port->bmi_regs->rx.fmbm_rstc; + break; + case E_FMAN_PORT_TYPE_TX: + case E_FMAN_PORT_TYPE_TX_10G: + stats_reg = &port->bmi_regs->tx.fmbm_tstc; + break; + case E_FMAN_PORT_TYPE_OP: + case E_FMAN_PORT_TYPE_HC: + stats_reg = &port->bmi_regs->oh.fmbm_ostc; + break; + default: + return -EINVAL; + } + + tmp = ioread32be(stats_reg); + + if (enable) + tmp |= BMI_COUNTERS_EN; + else + tmp &= ~BMI_COUNTERS_EN; + + iowrite32be(tmp, stats_reg); + return 0; +} + +int fman_port_set_perf_cnt_mode(struct fman_port *port, bool enable) +{ + uint32_t *stats_reg, tmp; + + switch (port->type) { + case E_FMAN_PORT_TYPE_RX: + case E_FMAN_PORT_TYPE_RX_10G: + stats_reg = &port->bmi_regs->rx.fmbm_rpc; + break; + case E_FMAN_PORT_TYPE_TX: + case E_FMAN_PORT_TYPE_TX_10G: + stats_reg = &port->bmi_regs->tx.fmbm_tpc; + break; + case E_FMAN_PORT_TYPE_OP: + case E_FMAN_PORT_TYPE_HC: + stats_reg = &port->bmi_regs->oh.fmbm_opc; + break; + default: + return -EINVAL; + } + + tmp = ioread32be(stats_reg); + + if (enable) + tmp |= BMI_COUNTERS_EN; + else + tmp &= ~BMI_COUNTERS_EN; + + iowrite32be(tmp, stats_reg); + return 0; +} + +int fman_port_set_queue_cnt_mode(struct fman_port *port, bool enable) +{ + uint32_t tmp; + + tmp = ioread32be(&port->qmi_regs->fmqm_pnc); + + if (enable) + tmp |= QMI_PORT_CFG_EN_COUNTERS; + else + tmp &= ~QMI_PORT_CFG_EN_COUNTERS; + + iowrite32be(tmp, &port->qmi_regs->fmqm_pnc); + return 0; +} + +int fman_port_set_bpool_cnt_mode(struct fman_port *port, + uint8_t bpid, + bool enable) +{ + uint8_t index; + uint32_t tmp; + + switch (port->type) { + case E_FMAN_PORT_TYPE_RX: + case E_FMAN_PORT_TYPE_RX_10G: + break; + default: + return -EINVAL; + } + + /* Find the pool */ + index = fman_port_find_bpool(port, bpid); + if (index == port->ext_pools_num || index == FMAN_PORT_MAX_EXT_POOLS_NUM) + /* Not found */ + return -EINVAL; + + tmp = ioread32be(&port->bmi_regs->rx.fmbm_ebmpi[index]); + + if (enable) + tmp |= BMI_EXT_BUF_POOL_EN_COUNTER; + else + tmp &= ~BMI_EXT_BUF_POOL_EN_COUNTER; + + iowrite32be(tmp, &port->bmi_regs->rx.fmbm_ebmpi[index]); + return 0; +} + +uint32_t fman_port_get_stats_counter(struct fman_port *port, + enum fman_port_stats_counters counter) +{ + uint32_t *stats_reg, ret_val; + + switch (port->type) { + case E_FMAN_PORT_TYPE_RX: + case E_FMAN_PORT_TYPE_RX_10G: + get_rx_stats_reg(port, counter, &stats_reg); + break; + case E_FMAN_PORT_TYPE_TX: + case E_FMAN_PORT_TYPE_TX_10G: + get_tx_stats_reg(port, counter, &stats_reg); + break; + case E_FMAN_PORT_TYPE_OP: + case E_FMAN_PORT_TYPE_HC: + get_oh_stats_reg(port, counter, &stats_reg); + break; + default: + stats_reg = NULL; + } + + if (stats_reg == NULL) + return 0; + + ret_val = ioread32be(stats_reg); + return ret_val; +} + +void fman_port_set_stats_counter(struct fman_port *port, + enum fman_port_stats_counters counter, + uint32_t value) +{ + uint32_t *stats_reg; + + switch (port->type) { + case E_FMAN_PORT_TYPE_RX: + case E_FMAN_PORT_TYPE_RX_10G: + get_rx_stats_reg(port, counter, &stats_reg); + break; + case E_FMAN_PORT_TYPE_TX: + case E_FMAN_PORT_TYPE_TX_10G: + get_tx_stats_reg(port, counter, &stats_reg); + break; + case E_FMAN_PORT_TYPE_OP: + case E_FMAN_PORT_TYPE_HC: + get_oh_stats_reg(port, counter, &stats_reg); + break; + default: + stats_reg = NULL; + } + + if (stats_reg == NULL) + return; + + iowrite32be(value, stats_reg); +} + +uint32_t fman_port_get_perf_counter(struct fman_port *port, + enum fman_port_perf_counters counter) +{ + uint32_t *perf_reg, ret_val; + + switch (port->type) { + case E_FMAN_PORT_TYPE_RX: + case E_FMAN_PORT_TYPE_RX_10G: + get_rx_perf_reg(port, counter, &perf_reg); + break; + case E_FMAN_PORT_TYPE_TX: + case E_FMAN_PORT_TYPE_TX_10G: + get_tx_perf_reg(port, counter, &perf_reg); + break; + case E_FMAN_PORT_TYPE_OP: + case E_FMAN_PORT_TYPE_HC: + get_oh_perf_reg(port, counter, &perf_reg); + break; + default: + perf_reg = NULL; + } + + if (perf_reg == NULL) + return 0; + + ret_val = ioread32be(perf_reg); + return ret_val; +} + +void fman_port_set_perf_counter(struct fman_port *port, + enum fman_port_perf_counters counter, + uint32_t value) +{ + uint32_t *perf_reg; + + switch (port->type) { + case E_FMAN_PORT_TYPE_RX: + case E_FMAN_PORT_TYPE_RX_10G: + get_rx_perf_reg(port, counter, &perf_reg); + break; + case E_FMAN_PORT_TYPE_TX: + case E_FMAN_PORT_TYPE_TX_10G: + get_tx_perf_reg(port, counter, &perf_reg); + break; + case E_FMAN_PORT_TYPE_OP: + case E_FMAN_PORT_TYPE_HC: + get_oh_perf_reg(port, counter, &perf_reg); + break; + default: + perf_reg = NULL; + } + + if (perf_reg == NULL) + return; + + iowrite32be(value, perf_reg); +} + +uint32_t fman_port_get_qmi_counter(struct fman_port *port, + enum fman_port_qmi_counters counter) +{ + uint32_t *queue_reg, ret_val; + + get_qmi_counter_reg(port, counter, &queue_reg); + + if (queue_reg == NULL) + return 0; + + ret_val = ioread32be(queue_reg); + return ret_val; +} + +void fman_port_set_qmi_counter(struct fman_port *port, + enum fman_port_qmi_counters counter, + uint32_t value) +{ + uint32_t *queue_reg; + + get_qmi_counter_reg(port, counter, &queue_reg); + + if (queue_reg == NULL) + return; + + iowrite32be(value, queue_reg); +} + +uint32_t fman_port_get_bpool_counter(struct fman_port *port, uint8_t bpid) +{ + uint8_t index; + uint32_t ret_val; + + switch (port->type) { + case E_FMAN_PORT_TYPE_RX: + case E_FMAN_PORT_TYPE_RX_10G: + break; + default: + return 0; + } + + /* Find the pool */ + index = fman_port_find_bpool(port, bpid); + if (index == port->ext_pools_num || index == FMAN_PORT_MAX_EXT_POOLS_NUM) + /* Not found */ + return 0; + + ret_val = ioread32be(&port->bmi_regs->rx.fmbm_acnt[index]); + return ret_val; +} + +void fman_port_set_bpool_counter(struct fman_port *port, + uint8_t bpid, + uint32_t value) +{ + uint8_t index; + + switch (port->type) { + case E_FMAN_PORT_TYPE_RX: + case E_FMAN_PORT_TYPE_RX_10G: + break; + default: + return; + } + + /* Find the pool */ + index = fman_port_find_bpool(port, bpid); + if (index == port->ext_pools_num || index == FMAN_PORT_MAX_EXT_POOLS_NUM) + /* Not found */ + return; + + iowrite32be(value, &port->bmi_regs->rx.fmbm_acnt[index]); +} + +int fman_port_add_congestion_grps(struct fman_port *port, + uint32_t grps_map[FMAN_PORT_CG_MAP_NUM]) +{ + int i; + uint32_t tmp, *grp_map_reg; + uint8_t max_grp_map_num; + + switch (port->type) { + case E_FMAN_PORT_TYPE_RX: + case E_FMAN_PORT_TYPE_RX_10G: + if (port->fm_rev_maj == 4) + max_grp_map_num = 1; + else + max_grp_map_num = FMAN_PORT_CG_MAP_NUM; + grp_map_reg = port->bmi_regs->rx.fmbm_rcgm; + break; + case E_FMAN_PORT_TYPE_OP: + max_grp_map_num = 1; + if (port->fm_rev_maj != 4) + return -EINVAL; + grp_map_reg = port->bmi_regs->oh.fmbm_ocgm; + break; + default: + return -EINVAL; + } + + for (i = (max_grp_map_num - 1); i >= 0; i--) { + if (grps_map[i] == 0) + continue; + tmp = ioread32be(&grp_map_reg[i]); + tmp |= grps_map[i]; + iowrite32be(tmp, &grp_map_reg[i]); + } + + return 0; +} + +int fman_port_remove_congestion_grps(struct fman_port *port, + uint32_t grps_map[FMAN_PORT_CG_MAP_NUM]) +{ + int i; + uint32_t tmp, *grp_map_reg; + uint8_t max_grp_map_num; + + switch (port->type) { + case E_FMAN_PORT_TYPE_RX: + case E_FMAN_PORT_TYPE_RX_10G: + if (port->fm_rev_maj == 4) + max_grp_map_num = 1; + else + max_grp_map_num = FMAN_PORT_CG_MAP_NUM; + grp_map_reg = port->bmi_regs->rx.fmbm_rcgm; + break; + case E_FMAN_PORT_TYPE_OP: + max_grp_map_num = 1; + if (port->fm_rev_maj != 4) + return -EINVAL; + grp_map_reg = port->bmi_regs->oh.fmbm_ocgm; + break; + default: + return -EINVAL; + } + + for (i = (max_grp_map_num - 1); i >= 0; i--) { + if (grps_map[i] == 0) + continue; + tmp = ioread32be(&grp_map_reg[i]); + tmp &= ~grps_map[i]; + iowrite32be(tmp, &grp_map_reg[i]); + } + return 0; +} diff --git a/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Rtc/Makefile b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Rtc/Makefile new file mode 100644 index 000000000000..d2c21d347538 --- /dev/null +++ b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Rtc/Makefile @@ -0,0 +1,15 @@ +# +# Makefile for the Freescale Ethernet controllers +# +ccflags-y += -DVERSION=\"\" +# +#Include netcomm SW specific definitions +include $(srctree)/drivers/net/ethernet/freescale/sdk_fman/ncsw_config.mk + +NCSW_FM_INC = $(srctree)/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/inc + +ccflags-y += -I$(NCSW_FM_INC) + +obj-y += fsl-ncsw-RTC.o + +fsl-ncsw-RTC-objs := fm_rtc.o fman_rtc.o diff --git a/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Rtc/fm_rtc.c b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Rtc/fm_rtc.c new file mode 100644 index 000000000000..99de427b3ae8 --- /dev/null +++ b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Rtc/fm_rtc.c @@ -0,0 +1,692 @@ +/* + * Copyright 2008-2012 Freescale Semiconductor Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Freescale Semiconductor nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * + * ALTERNATIVELY, this software may be distributed under the terms of the + * GNU General Public License ("GPL") as published by the Free Software + * Foundation, either version 2 of that License or (at your option) any + * later version. + * + * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + +/****************************************************************************** + @File fm_rtc.c + + @Description FM RTC driver implementation. + + @Cautions None +*//***************************************************************************/ +#include <linux/math64.h> +#include "error_ext.h" +#include "debug_ext.h" +#include "string_ext.h" +#include "part_ext.h" +#include "xx_ext.h" +#include "ncsw_ext.h" + +#include "fm_rtc.h" +#include "fm_common.h" + + + +/*****************************************************************************/ +static t_Error CheckInitParameters(t_FmRtc *p_Rtc) +{ + struct rtc_cfg *p_RtcDriverParam = p_Rtc->p_RtcDriverParam; + int i; + + if ((p_RtcDriverParam->src_clk != E_FMAN_RTC_SOURCE_CLOCK_EXTERNAL) && + (p_RtcDriverParam->src_clk != E_FMAN_RTC_SOURCE_CLOCK_SYSTEM) && + (p_RtcDriverParam->src_clk != E_FMAN_RTC_SOURCE_CLOCK_OSCILATOR)) + RETURN_ERROR(MAJOR, E_INVALID_CLOCK, ("Source clock undefined")); + + if (p_Rtc->outputClockDivisor == 0) + { + RETURN_ERROR(MAJOR, E_INVALID_VALUE, + ("Divisor for output clock (should be positive)")); + } + + for (i=0; i < FM_RTC_NUM_OF_ALARMS; i++) + { + if ((p_RtcDriverParam->alarm_polarity[i] != E_FMAN_RTC_ALARM_POLARITY_ACTIVE_LOW) && + (p_RtcDriverParam->alarm_polarity[i] != E_FMAN_RTC_ALARM_POLARITY_ACTIVE_HIGH)) + { + RETURN_ERROR(MAJOR, E_INVALID_SELECTION, ("Alarm %d signal polarity", i)); + } + } + for (i=0; i < FM_RTC_NUM_OF_EXT_TRIGGERS; i++) + { + if ((p_RtcDriverParam->trigger_polarity[i] != E_FMAN_RTC_TRIGGER_ON_FALLING_EDGE) && + (p_RtcDriverParam->trigger_polarity[i] != E_FMAN_RTC_TRIGGER_ON_RISING_EDGE)) + { + RETURN_ERROR(MAJOR, E_INVALID_SELECTION, ("Trigger %d signal polarity", i)); + } + } + + return E_OK; +} + +/*****************************************************************************/ +static void RtcExceptions(t_Handle h_FmRtc) +{ + t_FmRtc *p_Rtc = (t_FmRtc *)h_FmRtc; + struct rtc_regs *p_MemMap; + register uint32_t events; + + ASSERT_COND(p_Rtc); + p_MemMap = p_Rtc->p_MemMap; + + events = fman_rtc_check_and_clear_event(p_MemMap); + if (events & FMAN_RTC_TMR_TEVENT_ALM1) + { + if (p_Rtc->alarmParams[0].clearOnExpiration) + { + fman_rtc_set_timer_alarm_l(p_MemMap, 0, 0); + fman_rtc_disable_interupt(p_MemMap, FMAN_RTC_TMR_TEVENT_ALM1); + } + ASSERT_COND(p_Rtc->alarmParams[0].f_AlarmCallback); + p_Rtc->alarmParams[0].f_AlarmCallback(p_Rtc->h_App, 0); + } + if (events & FMAN_RTC_TMR_TEVENT_ALM2) + { + if (p_Rtc->alarmParams[1].clearOnExpiration) + { + fman_rtc_set_timer_alarm_l(p_MemMap, 1, 0); + fman_rtc_disable_interupt(p_MemMap, FMAN_RTC_TMR_TEVENT_ALM2); + } + ASSERT_COND(p_Rtc->alarmParams[1].f_AlarmCallback); + p_Rtc->alarmParams[1].f_AlarmCallback(p_Rtc->h_App, 1); + } + if (events & FMAN_RTC_TMR_TEVENT_PP1) + { + ASSERT_COND(p_Rtc->periodicPulseParams[0].f_PeriodicPulseCallback); + p_Rtc->periodicPulseParams[0].f_PeriodicPulseCallback(p_Rtc->h_App, 0); + } + if (events & FMAN_RTC_TMR_TEVENT_PP2) + { + ASSERT_COND(p_Rtc->periodicPulseParams[1].f_PeriodicPulseCallback); + p_Rtc->periodicPulseParams[1].f_PeriodicPulseCallback(p_Rtc->h_App, 1); + } + if (events & FMAN_RTC_TMR_TEVENT_ETS1) + { + ASSERT_COND(p_Rtc->externalTriggerParams[0].f_ExternalTriggerCallback); + p_Rtc->externalTriggerParams[0].f_ExternalTriggerCallback(p_Rtc->h_App, 0); + } + if (events & FMAN_RTC_TMR_TEVENT_ETS2) + { + ASSERT_COND(p_Rtc->externalTriggerParams[1].f_ExternalTriggerCallback); + p_Rtc->externalTriggerParams[1].f_ExternalTriggerCallback(p_Rtc->h_App, 1); + } +} + + +/*****************************************************************************/ +t_Handle FM_RTC_Config(t_FmRtcParams *p_FmRtcParam) +{ + t_FmRtc *p_Rtc; + + SANITY_CHECK_RETURN_VALUE(p_FmRtcParam, E_NULL_POINTER, NULL); + + /* Allocate memory for the FM RTC driver parameters */ + p_Rtc = (t_FmRtc *)XX_Malloc(sizeof(t_FmRtc)); + if (!p_Rtc) + { + REPORT_ERROR(MAJOR, E_NO_MEMORY, ("FM RTC driver structure")); + return NULL; + } + + memset(p_Rtc, 0, sizeof(t_FmRtc)); + + /* Allocate memory for the FM RTC driver parameters */ + p_Rtc->p_RtcDriverParam = (struct rtc_cfg *)XX_Malloc(sizeof(struct rtc_cfg)); + if (!p_Rtc->p_RtcDriverParam) + { + REPORT_ERROR(MAJOR, E_NO_MEMORY, ("FM RTC driver parameters")); + XX_Free(p_Rtc); + return NULL; + } + + memset(p_Rtc->p_RtcDriverParam, 0, sizeof(struct rtc_cfg)); + + /* Store RTC configuration parameters */ + p_Rtc->h_Fm = p_FmRtcParam->h_Fm; + + /* Set default RTC configuration parameters */ + fman_rtc_defconfig(p_Rtc->p_RtcDriverParam); + + p_Rtc->outputClockDivisor = DEFAULT_OUTPUT_CLOCK_DIVISOR; + p_Rtc->p_RtcDriverParam->bypass = DEFAULT_BYPASS; + p_Rtc->clockPeriodNanoSec = DEFAULT_CLOCK_PERIOD; /* 1 usec */ + + + /* Store RTC parameters in the RTC control structure */ + p_Rtc->p_MemMap = (struct rtc_regs *)UINT_TO_PTR(p_FmRtcParam->baseAddress); + p_Rtc->h_App = p_FmRtcParam->h_App; + + return p_Rtc; +} + +/*****************************************************************************/ +t_Error FM_RTC_Init(t_Handle h_FmRtc) +{ + t_FmRtc *p_Rtc = (t_FmRtc *)h_FmRtc; + struct rtc_cfg *p_RtcDriverParam; + struct rtc_regs *p_MemMap; + uint32_t freqCompensation = 0; + uint64_t tmpDouble; + bool init_freq_comp = FALSE; + + p_RtcDriverParam = p_Rtc->p_RtcDriverParam; + p_MemMap = p_Rtc->p_MemMap; + + if (CheckInitParameters(p_Rtc)!=E_OK) + RETURN_ERROR(MAJOR, E_CONFLICT, + ("Init Parameters are not Valid")); + + /* TODO check that no timestamping MACs are working in this stage. */ + + /* find source clock frequency in Mhz */ + if (p_Rtc->p_RtcDriverParam->src_clk != E_FMAN_RTC_SOURCE_CLOCK_SYSTEM) + p_Rtc->srcClkFreqMhz = p_Rtc->p_RtcDriverParam->ext_src_clk_freq; + else + p_Rtc->srcClkFreqMhz = (uint32_t)(FmGetMacClockFreq(p_Rtc->h_Fm)); + + /* if timer in Master mode Initialize TMR_CTRL */ + /* We want the counter (TMR_CNT) to count in nano-seconds */ + if (!p_RtcDriverParam->timer_slave_mode && p_Rtc->p_RtcDriverParam->bypass) + p_Rtc->clockPeriodNanoSec = (1000 / p_Rtc->srcClkFreqMhz); + else + { + /* Initialize TMR_ADD with the initial frequency compensation value: + freqCompensation = (2^32 / frequency ratio) */ + /* frequency ratio = sorce clock/rtc clock = + * (p_Rtc->srcClkFreqMhz*1000000))/ 1/(p_Rtc->clockPeriodNanoSec * 1000000000) */ + init_freq_comp = TRUE; + freqCompensation = (uint32_t)DIV_CEIL(ACCUMULATOR_OVERFLOW * 1000, + p_Rtc->clockPeriodNanoSec * p_Rtc->srcClkFreqMhz); + } + + /* check the legality of the relation between source and destination clocks */ + /* should be larger than 1.0001 */ + tmpDouble = 10000 * (uint64_t)p_Rtc->clockPeriodNanoSec * (uint64_t)p_Rtc->srcClkFreqMhz; + if ((tmpDouble) <= 10001) + RETURN_ERROR(MAJOR, E_CONFLICT, + ("Invalid relation between source and destination clocks. Should be larger than 1.0001")); + + fman_rtc_init(p_RtcDriverParam, + p_MemMap, + FM_RTC_NUM_OF_ALARMS, + FM_RTC_NUM_OF_PERIODIC_PULSES, + FM_RTC_NUM_OF_EXT_TRIGGERS, + init_freq_comp, + freqCompensation, + p_Rtc->outputClockDivisor); + + /* Register the FM RTC interrupt */ + FmRegisterIntr(p_Rtc->h_Fm, e_FM_MOD_TMR, 0, e_FM_INTR_TYPE_NORMAL, RtcExceptions , p_Rtc); + + /* Free parameters structures */ + XX_Free(p_Rtc->p_RtcDriverParam); + p_Rtc->p_RtcDriverParam = NULL; + + return E_OK; +} + +/*****************************************************************************/ +t_Error FM_RTC_Free(t_Handle h_FmRtc) +{ + t_FmRtc *p_Rtc = (t_FmRtc *)h_FmRtc; + + SANITY_CHECK_RETURN_ERROR(p_Rtc, E_INVALID_HANDLE); + + if (p_Rtc->p_RtcDriverParam) + { + XX_Free(p_Rtc->p_RtcDriverParam); + } + else + { + FM_RTC_Disable(h_FmRtc); + } + + /* Unregister FM RTC interrupt */ + FmUnregisterIntr(p_Rtc->h_Fm, e_FM_MOD_TMR, 0, e_FM_INTR_TYPE_NORMAL); + XX_Free(p_Rtc); + + return E_OK; +} + +/*****************************************************************************/ +t_Error FM_RTC_ConfigSourceClock(t_Handle h_FmRtc, + e_FmSrcClk srcClk, + uint32_t freqInMhz) +{ + t_FmRtc *p_Rtc = (t_FmRtc *)h_FmRtc; + + SANITY_CHECK_RETURN_ERROR(p_Rtc, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_Rtc->p_RtcDriverParam, E_INVALID_STATE); + + p_Rtc->p_RtcDriverParam->src_clk = (enum fman_src_clock)srcClk; + if (srcClk != e_FM_RTC_SOURCE_CLOCK_SYSTEM) + p_Rtc->p_RtcDriverParam->ext_src_clk_freq = freqInMhz; + + return E_OK; +} + +/*****************************************************************************/ +t_Error FM_RTC_ConfigPeriod(t_Handle h_FmRtc, uint32_t period) +{ + t_FmRtc *p_Rtc = (t_FmRtc *)h_FmRtc; + + SANITY_CHECK_RETURN_ERROR(p_Rtc, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_Rtc->p_RtcDriverParam, E_INVALID_STATE); + + p_Rtc->clockPeriodNanoSec = period; + + return E_OK; +} + +/*****************************************************************************/ +t_Error FM_RTC_ConfigFrequencyBypass(t_Handle h_FmRtc, bool enabled) +{ + t_FmRtc *p_Rtc = (t_FmRtc *)h_FmRtc; + + SANITY_CHECK_RETURN_ERROR(p_Rtc, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_Rtc->p_RtcDriverParam, E_INVALID_STATE); + + p_Rtc->p_RtcDriverParam->bypass = enabled; + + return E_OK; +} + +/*****************************************************************************/ +t_Error FM_RTC_ConfigInvertedInputClockPhase(t_Handle h_FmRtc, bool inverted) +{ + t_FmRtc *p_Rtc = (t_FmRtc *)h_FmRtc; + + SANITY_CHECK_RETURN_ERROR(p_Rtc, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_Rtc->p_RtcDriverParam, E_INVALID_STATE); + + p_Rtc->p_RtcDriverParam->invert_input_clk_phase = inverted; + + return E_OK; +} + +/*****************************************************************************/ +t_Error FM_RTC_ConfigInvertedOutputClockPhase(t_Handle h_FmRtc, bool inverted) +{ + t_FmRtc *p_Rtc = (t_FmRtc *)h_FmRtc; + + SANITY_CHECK_RETURN_ERROR(p_Rtc, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_Rtc->p_RtcDriverParam, E_INVALID_STATE); + + p_Rtc->p_RtcDriverParam->invert_output_clk_phase = inverted; + + return E_OK; +} + +/*****************************************************************************/ +t_Error FM_RTC_ConfigOutputClockDivisor(t_Handle h_FmRtc, uint16_t divisor) +{ + t_FmRtc *p_Rtc = (t_FmRtc *)h_FmRtc; + + SANITY_CHECK_RETURN_ERROR(p_Rtc, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_Rtc->p_RtcDriverParam, E_INVALID_STATE); + + p_Rtc->outputClockDivisor = divisor; + + return E_OK; +} + +/*****************************************************************************/ +t_Error FM_RTC_ConfigPulseRealignment(t_Handle h_FmRtc, bool enable) +{ + t_FmRtc *p_Rtc = (t_FmRtc *)h_FmRtc; + + SANITY_CHECK_RETURN_ERROR(p_Rtc, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_Rtc->p_RtcDriverParam, E_INVALID_STATE); + + p_Rtc->p_RtcDriverParam->pulse_realign = enable; + + return E_OK; +} + +/*****************************************************************************/ +t_Error FM_RTC_ConfigAlarmPolarity(t_Handle h_FmRtc, + uint8_t alarmId, + e_FmRtcAlarmPolarity alarmPolarity) +{ + t_FmRtc *p_Rtc = (t_FmRtc *)h_FmRtc; + + SANITY_CHECK_RETURN_ERROR(p_Rtc, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_Rtc->p_RtcDriverParam, E_INVALID_STATE); + + if (alarmId >= FM_RTC_NUM_OF_ALARMS) + RETURN_ERROR(MAJOR, E_INVALID_SELECTION, ("Alarm ID")); + + p_Rtc->p_RtcDriverParam->alarm_polarity[alarmId] = + (enum fman_rtc_alarm_polarity)alarmPolarity; + + return E_OK; +} + +/*****************************************************************************/ +t_Error FM_RTC_ConfigExternalTriggerPolarity(t_Handle h_FmRtc, + uint8_t triggerId, + e_FmRtcTriggerPolarity triggerPolarity) +{ + t_FmRtc *p_Rtc = (t_FmRtc *)h_FmRtc; + + SANITY_CHECK_RETURN_ERROR(p_Rtc, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_Rtc->p_RtcDriverParam, E_INVALID_STATE); + + if (triggerId >= FM_RTC_NUM_OF_EXT_TRIGGERS) + { + RETURN_ERROR(MAJOR, E_INVALID_SELECTION, ("External trigger ID")); + } + + p_Rtc->p_RtcDriverParam->trigger_polarity[triggerId] = + (enum fman_rtc_trigger_polarity)triggerPolarity; + + return E_OK; +} + +/*****************************************************************************/ +t_Error FM_RTC_Enable(t_Handle h_FmRtc, bool resetClock) +{ + t_FmRtc *p_Rtc = (t_FmRtc *)h_FmRtc; + + SANITY_CHECK_RETURN_ERROR(p_Rtc, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(!p_Rtc->p_RtcDriverParam, E_INVALID_STATE); + + fman_rtc_enable(p_Rtc->p_MemMap, resetClock); + return E_OK; +} + +/*****************************************************************************/ +t_Error FM_RTC_Disable(t_Handle h_FmRtc) +{ + t_FmRtc *p_Rtc = (t_FmRtc *)h_FmRtc; + + SANITY_CHECK_RETURN_ERROR(p_Rtc, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(!p_Rtc->p_RtcDriverParam, E_INVALID_STATE); + + /* TODO A check must be added here, that no timestamping MAC's + * are working in this stage. */ + fman_rtc_disable(p_Rtc->p_MemMap); + + return E_OK; +} + +/*****************************************************************************/ +t_Error FM_RTC_SetClockOffset(t_Handle h_FmRtc, int64_t offset) +{ + t_FmRtc *p_Rtc = (t_FmRtc *)h_FmRtc; + + SANITY_CHECK_RETURN_ERROR(p_Rtc, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(!p_Rtc->p_RtcDriverParam, E_INVALID_STATE); + + fman_rtc_set_timer_offset(p_Rtc->p_MemMap, offset); + return E_OK; +} + +/*****************************************************************************/ +t_Error FM_RTC_SetAlarm(t_Handle h_FmRtc, t_FmRtcAlarmParams *p_FmRtcAlarmParams) +{ + t_FmRtc *p_Rtc = (t_FmRtc *)h_FmRtc; + uint64_t tmpAlarm; + bool enable = FALSE; + + SANITY_CHECK_RETURN_ERROR(p_Rtc, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(!p_Rtc->p_RtcDriverParam, E_INVALID_STATE); + + if (p_FmRtcAlarmParams->alarmId >= FM_RTC_NUM_OF_ALARMS) + { + RETURN_ERROR(MAJOR, E_INVALID_SELECTION, ("Alarm ID")); + } + + if (p_FmRtcAlarmParams->alarmTime < p_Rtc->clockPeriodNanoSec) + RETURN_ERROR(MAJOR, E_INVALID_SELECTION, + ("Alarm time must be equal or larger than RTC period - %d nanoseconds", + p_Rtc->clockPeriodNanoSec)); + tmpAlarm = p_FmRtcAlarmParams->alarmTime; + if (do_div(tmpAlarm, p_Rtc->clockPeriodNanoSec)) + RETURN_ERROR(MAJOR, E_INVALID_SELECTION, + ("Alarm time must be a multiple of RTC period - %d nanoseconds", + p_Rtc->clockPeriodNanoSec)); + + if (p_FmRtcAlarmParams->f_AlarmCallback) + { + p_Rtc->alarmParams[p_FmRtcAlarmParams->alarmId].f_AlarmCallback = p_FmRtcAlarmParams->f_AlarmCallback; + p_Rtc->alarmParams[p_FmRtcAlarmParams->alarmId].clearOnExpiration = p_FmRtcAlarmParams->clearOnExpiration; + enable = TRUE; + } + + fman_rtc_set_alarm(p_Rtc->p_MemMap, p_FmRtcAlarmParams->alarmId, (unsigned long)tmpAlarm, enable); + + return E_OK; +} + +/*****************************************************************************/ +t_Error FM_RTC_SetPeriodicPulse(t_Handle h_FmRtc, t_FmRtcPeriodicPulseParams *p_FmRtcPeriodicPulseParams) +{ + t_FmRtc *p_Rtc = (t_FmRtc *)h_FmRtc; + bool enable = FALSE; + uint64_t tmpFiper; + + SANITY_CHECK_RETURN_ERROR(p_Rtc, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(!p_Rtc->p_RtcDriverParam, E_INVALID_STATE); + + if (p_FmRtcPeriodicPulseParams->periodicPulseId >= FM_RTC_NUM_OF_PERIODIC_PULSES) + { + RETURN_ERROR(MAJOR, E_INVALID_SELECTION, ("Periodic pulse ID")); + } + if (fman_rtc_is_enabled(p_Rtc->p_MemMap)) + RETURN_ERROR(MAJOR, E_INVALID_SELECTION, ("Can't set Periodic pulse when RTC is enabled.")); + if (p_FmRtcPeriodicPulseParams->periodicPulsePeriod < p_Rtc->clockPeriodNanoSec) + RETURN_ERROR(MAJOR, E_INVALID_SELECTION, + ("Periodic pulse must be equal or larger than RTC period - %d nanoseconds", + p_Rtc->clockPeriodNanoSec)); + tmpFiper = p_FmRtcPeriodicPulseParams->periodicPulsePeriod; + if (do_div(tmpFiper, p_Rtc->clockPeriodNanoSec)) + RETURN_ERROR(MAJOR, E_INVALID_SELECTION, + ("Periodic pulse must be a multiple of RTC period - %d nanoseconds", + p_Rtc->clockPeriodNanoSec)); + if (tmpFiper & 0xffffffff00000000LL) + RETURN_ERROR(MAJOR, E_INVALID_SELECTION, + ("Periodic pulse/RTC Period must be smaller than 4294967296", + p_Rtc->clockPeriodNanoSec)); + + if (p_FmRtcPeriodicPulseParams->f_PeriodicPulseCallback) + { + p_Rtc->periodicPulseParams[p_FmRtcPeriodicPulseParams->periodicPulseId].f_PeriodicPulseCallback = + p_FmRtcPeriodicPulseParams->f_PeriodicPulseCallback; + enable = TRUE; + } + fman_rtc_set_periodic_pulse(p_Rtc->p_MemMap, p_FmRtcPeriodicPulseParams->periodicPulseId, (uint32_t)tmpFiper, enable); + return E_OK; +} + +/*****************************************************************************/ +t_Error FM_RTC_ClearPeriodicPulse(t_Handle h_FmRtc, uint8_t periodicPulseId) +{ + t_FmRtc *p_Rtc = (t_FmRtc *)h_FmRtc; + + SANITY_CHECK_RETURN_ERROR(p_Rtc, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(!p_Rtc->p_RtcDriverParam, E_INVALID_STATE); + + if (periodicPulseId >= FM_RTC_NUM_OF_PERIODIC_PULSES) + { + RETURN_ERROR(MAJOR, E_INVALID_SELECTION, ("Periodic pulse ID")); + } + + p_Rtc->periodicPulseParams[periodicPulseId].f_PeriodicPulseCallback = NULL; + fman_rtc_clear_periodic_pulse(p_Rtc->p_MemMap, periodicPulseId); + + return E_OK; +} + +/*****************************************************************************/ +t_Error FM_RTC_SetExternalTrigger(t_Handle h_FmRtc, t_FmRtcExternalTriggerParams *p_FmRtcExternalTriggerParams) +{ + t_FmRtc *p_Rtc = (t_FmRtc *)h_FmRtc; + bool enable = FALSE; + + SANITY_CHECK_RETURN_ERROR(p_Rtc, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(!p_Rtc->p_RtcDriverParam, E_INVALID_STATE); + + if (p_FmRtcExternalTriggerParams->externalTriggerId >= FM_RTC_NUM_OF_EXT_TRIGGERS) + { + RETURN_ERROR(MAJOR, E_INVALID_SELECTION, ("External Trigger ID")); + } + + if (p_FmRtcExternalTriggerParams->f_ExternalTriggerCallback) + { + p_Rtc->externalTriggerParams[p_FmRtcExternalTriggerParams->externalTriggerId].f_ExternalTriggerCallback = p_FmRtcExternalTriggerParams->f_ExternalTriggerCallback; + enable = TRUE; + } + + fman_rtc_set_ext_trigger(p_Rtc->p_MemMap, p_FmRtcExternalTriggerParams->externalTriggerId, enable, p_FmRtcExternalTriggerParams->usePulseAsInput); + return E_OK; +} + +/*****************************************************************************/ +t_Error FM_RTC_ClearExternalTrigger(t_Handle h_FmRtc, uint8_t externalTriggerId) +{ + t_FmRtc *p_Rtc = (t_FmRtc *)h_FmRtc; + + SANITY_CHECK_RETURN_ERROR(p_Rtc, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(!p_Rtc->p_RtcDriverParam, E_INVALID_STATE); + + if (externalTriggerId >= FM_RTC_NUM_OF_EXT_TRIGGERS) + RETURN_ERROR(MAJOR, E_INVALID_SELECTION, ("External Trigger ID")); + + p_Rtc->externalTriggerParams[externalTriggerId].f_ExternalTriggerCallback = NULL; + + fman_rtc_clear_external_trigger(p_Rtc->p_MemMap, externalTriggerId); + + return E_OK; +} + +/*****************************************************************************/ +t_Error FM_RTC_GetExternalTriggerTimeStamp(t_Handle h_FmRtc, + uint8_t triggerId, + uint64_t *p_TimeStamp) +{ + t_FmRtc *p_Rtc = (t_FmRtc *)h_FmRtc; + + SANITY_CHECK_RETURN_ERROR(p_Rtc, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(!p_Rtc->p_RtcDriverParam, E_INVALID_STATE); + + if (triggerId >= FM_RTC_NUM_OF_EXT_TRIGGERS) + RETURN_ERROR(MAJOR, E_INVALID_SELECTION, ("External trigger ID")); + + *p_TimeStamp = fman_rtc_get_trigger_stamp(p_Rtc->p_MemMap, triggerId)*p_Rtc->clockPeriodNanoSec; + + return E_OK; +} + +/*****************************************************************************/ +t_Error FM_RTC_GetCurrentTime(t_Handle h_FmRtc, uint64_t *p_Ts) +{ + t_FmRtc *p_Rtc = (t_FmRtc *)h_FmRtc; + + SANITY_CHECK_RETURN_ERROR(p_Rtc, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(!p_Rtc->p_RtcDriverParam, E_INVALID_STATE); + + *p_Ts = fman_rtc_get_timer(p_Rtc->p_MemMap)*p_Rtc->clockPeriodNanoSec; + + return E_OK; +} + +/*****************************************************************************/ +t_Error FM_RTC_SetCurrentTime(t_Handle h_FmRtc, uint64_t ts) +{ + t_FmRtc *p_Rtc = (t_FmRtc *)h_FmRtc; + + SANITY_CHECK_RETURN_ERROR(p_Rtc, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(!p_Rtc->p_RtcDriverParam, E_INVALID_STATE); + + do_div(ts, p_Rtc->clockPeriodNanoSec); + fman_rtc_set_timer(p_Rtc->p_MemMap, (int64_t)ts); + + return E_OK; +} + +/*****************************************************************************/ +t_Error FM_RTC_GetFreqCompensation(t_Handle h_FmRtc, uint32_t *p_Compensation) +{ + t_FmRtc *p_Rtc = (t_FmRtc *)h_FmRtc; + + SANITY_CHECK_RETURN_ERROR(p_Rtc, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(!p_Rtc->p_RtcDriverParam, E_INVALID_STATE); + + *p_Compensation = fman_rtc_get_frequency_compensation(p_Rtc->p_MemMap); + + return E_OK; +} + +/*****************************************************************************/ +t_Error FM_RTC_SetFreqCompensation(t_Handle h_FmRtc, uint32_t freqCompensation) +{ + t_FmRtc *p_Rtc = (t_FmRtc *)h_FmRtc; + + SANITY_CHECK_RETURN_ERROR(p_Rtc, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(!p_Rtc->p_RtcDriverParam, E_INVALID_STATE); + + /* set the new freqCompensation */ + fman_rtc_set_frequency_compensation(p_Rtc->p_MemMap, freqCompensation); + + return E_OK; +} + +#ifdef CONFIG_PTP_1588_CLOCK_DPAA +/*****************************************************************************/ +t_Error FM_RTC_EnableInterrupt(t_Handle h_FmRtc, uint32_t events) +{ + t_FmRtc *p_Rtc = (t_FmRtc *)h_FmRtc; + + SANITY_CHECK_RETURN_ERROR(p_Rtc, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(!p_Rtc->p_RtcDriverParam, E_INVALID_STATE); + + /* enable interrupt */ + fman_rtc_enable_interupt(p_Rtc->p_MemMap, events); + + return E_OK; +} + +/*****************************************************************************/ +t_Error FM_RTC_DisableInterrupt(t_Handle h_FmRtc, uint32_t events) +{ + t_FmRtc *p_Rtc = (t_FmRtc *)h_FmRtc; + + SANITY_CHECK_RETURN_ERROR(p_Rtc, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(!p_Rtc->p_RtcDriverParam, E_INVALID_STATE); + + /* disable interrupt */ + fman_rtc_disable_interupt(p_Rtc->p_MemMap, events); + + return E_OK; +} +#endif diff --git a/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Rtc/fm_rtc.h b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Rtc/fm_rtc.h new file mode 100644 index 000000000000..843ca008ff8b --- /dev/null +++ b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Rtc/fm_rtc.h @@ -0,0 +1,96 @@ +/* + * Copyright 2008-2012 Freescale Semiconductor Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Freescale Semiconductor nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * + * ALTERNATIVELY, this software may be distributed under the terms of the + * GNU General Public License ("GPL") as published by the Free Software + * Foundation, either version 2 of that License or (at your option) any + * later version. + * + * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + +/****************************************************************************** + @File fm_rtc.h + + @Description Memory map and internal definitions for FM RTC IEEE1588 Timer driver. + + @Cautions None +*//***************************************************************************/ + +#ifndef __FM_RTC_H__ +#define __FM_RTC_H__ + +#include "std_ext.h" +#include "fm_rtc_ext.h" + + +#define __ERR_MODULE__ MODULE_FM_RTC + +/* General definitions */ + +#define ACCUMULATOR_OVERFLOW ((uint64_t)(1LL << 32)) +#define DEFAULT_OUTPUT_CLOCK_DIVISOR 0x00000002 +#define DEFAULT_BYPASS FALSE +#define DEFAULT_CLOCK_PERIOD 1000 + + + +typedef struct t_FmRtcAlarm +{ + t_FmRtcExceptionsCallback *f_AlarmCallback; + bool clearOnExpiration; +} t_FmRtcAlarm; + +typedef struct t_FmRtcPeriodicPulse +{ + t_FmRtcExceptionsCallback *f_PeriodicPulseCallback; +} t_FmRtcPeriodicPulse; + +typedef struct t_FmRtcExternalTrigger +{ + t_FmRtcExceptionsCallback *f_ExternalTriggerCallback; +} t_FmRtcExternalTrigger; + + +/**************************************************************************//** + @Description RTC FM driver control structure. +*//***************************************************************************/ +typedef struct t_FmRtc +{ + t_Part *p_Part; /**< Pointer to the integration device */ + t_Handle h_Fm; + t_Handle h_App; /**< Application handle */ + struct rtc_regs *p_MemMap; + uint32_t clockPeriodNanoSec; /**< RTC clock period in nano-seconds (for FS mode) */ + uint32_t srcClkFreqMhz; + uint16_t outputClockDivisor; /**< Output clock divisor (for FS mode) */ + t_FmRtcAlarm alarmParams[FM_RTC_NUM_OF_ALARMS]; + t_FmRtcPeriodicPulse periodicPulseParams[FM_RTC_NUM_OF_PERIODIC_PULSES]; + t_FmRtcExternalTrigger externalTriggerParams[FM_RTC_NUM_OF_EXT_TRIGGERS]; + struct rtc_cfg *p_RtcDriverParam; /**< RTC Driver parameters (for Init phase) */ +} t_FmRtc; + + +#endif /* __FM_RTC_H__ */ diff --git a/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Rtc/fman_rtc.c b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Rtc/fman_rtc.c new file mode 100755 index 000000000000..acdf507e096d --- /dev/null +++ b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Rtc/fman_rtc.c @@ -0,0 +1,334 @@ +/* + * Copyright 2008-2013 Freescale Semiconductor Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Freescale Semiconductor nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * + * ALTERNATIVELY, this software may be distributed under the terms of the + * GNU General Public License ("GPL") as published by the Free Software + * Foundation, either version 2 of that License or (at your option) any + * later version. + * + * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "fsl_fman_rtc.h" + +void fman_rtc_defconfig(struct rtc_cfg *cfg) +{ + int i; + cfg->src_clk = DEFAULT_SRC_CLOCK; + cfg->invert_input_clk_phase = DEFAULT_INVERT_INPUT_CLK_PHASE; + cfg->invert_output_clk_phase = DEFAULT_INVERT_OUTPUT_CLK_PHASE; + cfg->pulse_realign = DEFAULT_PULSE_REALIGN; + for (i = 0; i < FMAN_RTC_MAX_NUM_OF_ALARMS; i++) + cfg->alarm_polarity[i] = DEFAULT_ALARM_POLARITY; + for (i = 0; i < FMAN_RTC_MAX_NUM_OF_EXT_TRIGGERS; i++) + cfg->trigger_polarity[i] = DEFAULT_TRIGGER_POLARITY; +} + +uint32_t fman_rtc_get_events(struct rtc_regs *regs) +{ + return ioread32be(®s->tmr_tevent); +} + +uint32_t fman_rtc_get_event(struct rtc_regs *regs, uint32_t ev_mask) +{ + return ioread32be(®s->tmr_tevent) & ev_mask; +} + +uint32_t fman_rtc_get_interrupt_mask(struct rtc_regs *regs) +{ + return ioread32be(®s->tmr_temask); +} + +void fman_rtc_set_interrupt_mask(struct rtc_regs *regs, uint32_t mask) +{ + iowrite32be(mask, ®s->tmr_temask); +} + +void fman_rtc_ack_event(struct rtc_regs *regs, uint32_t events) +{ + iowrite32be(events, ®s->tmr_tevent); +} + +uint32_t fman_rtc_check_and_clear_event(struct rtc_regs *regs) +{ + uint32_t event; + + event = ioread32be(®s->tmr_tevent); + event &= ioread32be(®s->tmr_temask); + + if (event) + iowrite32be(event, ®s->tmr_tevent); + return event; +} + +uint32_t fman_rtc_get_frequency_compensation(struct rtc_regs *regs) +{ + return ioread32be(®s->tmr_add); +} + +void fman_rtc_set_frequency_compensation(struct rtc_regs *regs, uint32_t val) +{ + iowrite32be(val, ®s->tmr_add); +} + +void fman_rtc_enable_interupt(struct rtc_regs *regs, uint32_t events) +{ + fman_rtc_set_interrupt_mask(regs, fman_rtc_get_interrupt_mask(regs) | events); +} + +void fman_rtc_disable_interupt(struct rtc_regs *regs, uint32_t events) +{ + fman_rtc_set_interrupt_mask(regs, fman_rtc_get_interrupt_mask(regs) & ~events); +} + +void fman_rtc_set_timer_alarm_l(struct rtc_regs *regs, int index, uint32_t val) +{ + iowrite32be(val, ®s->tmr_alarm[index].tmr_alarm_l); +} + +void fman_rtc_set_timer_fiper(struct rtc_regs *regs, int index, uint32_t val) +{ + iowrite32be(val, ®s->tmr_fiper[index]); +} + +void fman_rtc_set_timer_alarm(struct rtc_regs *regs, int index, int64_t val) +{ + iowrite32be((uint32_t)val, ®s->tmr_alarm[index].tmr_alarm_l); + iowrite32be((uint32_t)(val >> 32), ®s->tmr_alarm[index].tmr_alarm_h); +} + +void fman_rtc_set_timer_offset(struct rtc_regs *regs, int64_t val) +{ + iowrite32be((uint32_t)val, ®s->tmr_off_l); + iowrite32be((uint32_t)(val >> 32), ®s->tmr_off_h); +} + +uint64_t fman_rtc_get_trigger_stamp(struct rtc_regs *regs, int id) +{ + uint64_t time; + /* TMR_CNT_L must be read first to get an accurate value */ + time = (uint64_t)ioread32be(®s->tmr_etts[id].tmr_etts_l); + time |= ((uint64_t)ioread32be(®s->tmr_etts[id].tmr_etts_h) + << 32); + + return time; +} + +uint32_t fman_rtc_get_timer_ctrl(struct rtc_regs *regs) +{ + return ioread32be(®s->tmr_ctrl); +} + +void fman_rtc_set_timer_ctrl(struct rtc_regs *regs, uint32_t val) +{ + iowrite32be(val, ®s->tmr_ctrl); +} + +void fman_rtc_timers_soft_reset(struct rtc_regs *regs) +{ + fman_rtc_set_timer_ctrl(regs, FMAN_RTC_TMR_CTRL_TMSR); + udelay(10); + fman_rtc_set_timer_ctrl(regs, 0); +} + +void fman_rtc_init(struct rtc_cfg *cfg, struct rtc_regs *regs, int num_alarms, + int num_fipers, int num_ext_triggers, bool init_freq_comp, + uint32_t freq_compensation, uint32_t output_clock_divisor) +{ + uint32_t tmr_ctrl; + int i; + + fman_rtc_timers_soft_reset(regs); + + /* Set the source clock */ + switch (cfg->src_clk) { + case E_FMAN_RTC_SOURCE_CLOCK_SYSTEM: + tmr_ctrl = FMAN_RTC_TMR_CTRL_CKSEL_MAC_CLK; + break; + case E_FMAN_RTC_SOURCE_CLOCK_OSCILATOR: + tmr_ctrl = FMAN_RTC_TMR_CTRL_CKSEL_OSC_CLK; + break; + default: + /* Use a clock from the External TMR reference clock.*/ + tmr_ctrl = FMAN_RTC_TMR_CTRL_CKSEL_EXT_CLK; + break; + } + + /* whatever period the user picked, the timestamp will advance in '1' + * every time the period passed. */ + tmr_ctrl |= ((1 << FMAN_RTC_TMR_CTRL_TCLK_PERIOD_SHIFT) & + FMAN_RTC_TMR_CTRL_TCLK_PERIOD_MASK); + + if (cfg->invert_input_clk_phase) + tmr_ctrl |= FMAN_RTC_TMR_CTRL_CIPH; + if (cfg->invert_output_clk_phase) + tmr_ctrl |= FMAN_RTC_TMR_CTRL_COPH; + + for (i = 0; i < num_alarms; i++) { + if (cfg->alarm_polarity[i] == + E_FMAN_RTC_ALARM_POLARITY_ACTIVE_LOW) + tmr_ctrl |= (FMAN_RTC_TMR_CTRL_ALMP1 >> i); + } + + for (i = 0; i < num_ext_triggers; i++) + if (cfg->trigger_polarity[i] == + E_FMAN_RTC_TRIGGER_ON_FALLING_EDGE) + tmr_ctrl |= (FMAN_RTC_TMR_CTRL_ETEP1 << i); + + if (!cfg->timer_slave_mode && cfg->bypass) + tmr_ctrl |= FMAN_RTC_TMR_CTRL_BYP; + + fman_rtc_set_timer_ctrl(regs, tmr_ctrl); + if (init_freq_comp) + fman_rtc_set_frequency_compensation(regs, freq_compensation); + + /* Clear TMR_ALARM registers */ + for (i = 0; i < num_alarms; i++) + fman_rtc_set_timer_alarm(regs, i, 0xFFFFFFFFFFFFFFFFLL); + + /* Clear TMR_TEVENT */ + fman_rtc_ack_event(regs, FMAN_RTC_TMR_TEVENT_ALL); + + /* Initialize TMR_TEMASK */ + fman_rtc_set_interrupt_mask(regs, 0); + + /* Clear TMR_FIPER registers */ + for (i = 0; i < num_fipers; i++) + fman_rtc_set_timer_fiper(regs, i, 0xFFFFFFFF); + + /* Initialize TMR_PRSC */ + iowrite32be(output_clock_divisor, ®s->tmr_prsc); + + /* Clear TMR_OFF */ + fman_rtc_set_timer_offset(regs, 0); +} + +bool fman_rtc_is_enabled(struct rtc_regs *regs) +{ + return (bool)(fman_rtc_get_timer_ctrl(regs) & FMAN_RTC_TMR_CTRL_TE); +} + +void fman_rtc_enable(struct rtc_regs *regs, bool reset_clock) +{ + uint32_t tmr_ctrl = fman_rtc_get_timer_ctrl(regs); + + /* TODO check that no timestamping MACs are working in this stage. */ + if (reset_clock) { + fman_rtc_set_timer_ctrl(regs, (tmr_ctrl | FMAN_RTC_TMR_CTRL_TMSR)); + + udelay(10); + /* Clear TMR_OFF */ + fman_rtc_set_timer_offset(regs, 0); + } + + fman_rtc_set_timer_ctrl(regs, (tmr_ctrl | FMAN_RTC_TMR_CTRL_TE)); +} + +void fman_rtc_disable(struct rtc_regs *regs) +{ + fman_rtc_set_timer_ctrl(regs, (fman_rtc_get_timer_ctrl(regs) + & ~(FMAN_RTC_TMR_CTRL_TE))); +} + +void fman_rtc_clear_periodic_pulse(struct rtc_regs *regs, int id) +{ + uint32_t tmp_reg; + if (id == 0) + tmp_reg = FMAN_RTC_TMR_TEVENT_PP1; + else + tmp_reg = FMAN_RTC_TMR_TEVENT_PP2; + fman_rtc_disable_interupt(regs, tmp_reg); + + tmp_reg = fman_rtc_get_timer_ctrl(regs); + if (tmp_reg & FMAN_RTC_TMR_CTRL_FS) + fman_rtc_set_timer_ctrl(regs, tmp_reg & ~FMAN_RTC_TMR_CTRL_FS); + + fman_rtc_set_timer_fiper(regs, id, 0xFFFFFFFF); +} + +void fman_rtc_clear_external_trigger(struct rtc_regs *regs, int id) +{ + uint32_t tmpReg, tmp_ctrl; + + if (id == 0) + tmpReg = FMAN_RTC_TMR_TEVENT_ETS1; + else + tmpReg = FMAN_RTC_TMR_TEVENT_ETS2; + fman_rtc_disable_interupt(regs, tmpReg); + + if (id == 0) + tmpReg = FMAN_RTC_TMR_CTRL_PP1L; + else + tmpReg = FMAN_RTC_TMR_CTRL_PP2L; + tmp_ctrl = fman_rtc_get_timer_ctrl(regs); + if (tmp_ctrl & tmpReg) + fman_rtc_set_timer_ctrl(regs, tmp_ctrl & ~tmpReg); +} + +void fman_rtc_set_alarm(struct rtc_regs *regs, int id, uint32_t val, bool enable) +{ + uint32_t tmpReg; + fman_rtc_set_timer_alarm(regs, id, val); + if (enable) { + if (id == 0) + tmpReg = FMAN_RTC_TMR_TEVENT_ALM1; + else + tmpReg = FMAN_RTC_TMR_TEVENT_ALM2; + fman_rtc_enable_interupt(regs, tmpReg); + } +} + +void fman_rtc_set_periodic_pulse(struct rtc_regs *regs, int id, uint32_t val, + bool enable) +{ + uint32_t tmpReg; + fman_rtc_set_timer_fiper(regs, id, val); + if (enable) { + if (id == 0) + tmpReg = FMAN_RTC_TMR_TEVENT_PP1; + else + tmpReg = FMAN_RTC_TMR_TEVENT_PP2; + fman_rtc_enable_interupt(regs, tmpReg); + } +} + +void fman_rtc_set_ext_trigger(struct rtc_regs *regs, int id, bool enable, + bool use_pulse_as_input) +{ + uint32_t tmpReg; + if (enable) { + if (id == 0) + tmpReg = FMAN_RTC_TMR_TEVENT_ETS1; + else + tmpReg = FMAN_RTC_TMR_TEVENT_ETS2; + fman_rtc_enable_interupt(regs, tmpReg); + } + if (use_pulse_as_input) { + if (id == 0) + tmpReg = FMAN_RTC_TMR_CTRL_PP1L; + else + tmpReg = FMAN_RTC_TMR_CTRL_PP2L; + fman_rtc_set_timer_ctrl(regs, fman_rtc_get_timer_ctrl(regs) | tmpReg); + } +} diff --git a/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/SP/Makefile b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/SP/Makefile new file mode 100644 index 000000000000..fae50ce440a2 --- /dev/null +++ b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/SP/Makefile @@ -0,0 +1,15 @@ +# +# Makefile for the Freescale Ethernet controllers +# +ccflags-y += -DVERSION=\"\" +# +#Include netcomm SW specific definitions +include $(srctree)/drivers/net/ethernet/freescale/sdk_fman/ncsw_config.mk + +NCSW_FM_INC = $(srctree)/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/inc + +ccflags-y += -I$(NCSW_FM_INC) + +obj-y += fsl-ncsw-sp.o + +fsl-ncsw-sp-objs := fm_sp.o fman_sp.o diff --git a/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/SP/fm_sp.c b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/SP/fm_sp.c new file mode 100644 index 000000000000..0994f34d392d --- /dev/null +++ b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/SP/fm_sp.c @@ -0,0 +1,757 @@ +/* + * Copyright 2008-2012 Freescale Semiconductor Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Freescale Semiconductor nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * + * ALTERNATIVELY, this software may be distributed under the terms of the + * GNU General Public License ("GPL") as published by the Free Software + * Foundation, either version 2 of that License or (at your option) any + * later version. + * + * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + +/****************************************************************************** + @File fm_sp.c + + @Description FM PCD Storage profile ... +*//***************************************************************************/ + +#include "std_ext.h" +#include "error_ext.h" +#include "string_ext.h" +#include "debug_ext.h" +#include "net_ext.h" + +#include "fm_vsp_ext.h" +#include "fm_sp.h" +#include "fm_common.h" +#include "fsl_fman_sp.h" + + +#if (DPAA_VERSION >= 11) +static t_Error CheckParamsGeneratedInternally(t_FmVspEntry *p_FmVspEntry) +{ + t_Error err = E_OK; + + if ((err = FmSpCheckIntContextParams(&p_FmVspEntry->intContext))!= E_OK) + RETURN_ERROR(MAJOR, err, NO_MSG); + if ((err = FmSpCheckBufMargins(&p_FmVspEntry->bufMargins)) != E_OK) + RETURN_ERROR(MAJOR, err, NO_MSG); + return err; + +} + +static t_Error CheckParams(t_FmVspEntry *p_FmVspEntry) +{ + t_Error err = E_OK; + + SANITY_CHECK_RETURN_ERROR(p_FmVspEntry, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_FmVspEntry->p_FmVspEntryDriverParams, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_FmVspEntry->h_Fm, E_INVALID_HANDLE); + + if ((err = FmSpCheckBufPoolsParams(&p_FmVspEntry->p_FmVspEntryDriverParams->extBufPools, + p_FmVspEntry->p_FmVspEntryDriverParams->p_BackupBmPools, + p_FmVspEntry->p_FmVspEntryDriverParams->p_BufPoolDepletion)) != E_OK) + + RETURN_ERROR(MAJOR, err, NO_MSG); + + if (p_FmVspEntry->p_FmVspEntryDriverParams->liodnOffset & ~FM_LIODN_OFFSET_MASK) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("liodnOffset is larger than %d", FM_LIODN_OFFSET_MASK+1)); + + err = FmVSPCheckRelativeProfile(p_FmVspEntry->h_Fm, + p_FmVspEntry->portType, + p_FmVspEntry->portId, + p_FmVspEntry->relativeProfileId); + + return err; +} +#endif /* (DPAA_VERSION >= 11) */ + + +/*****************************************************************************/ +/* Inter-module API routines */ +/*****************************************************************************/ +void FmSpSetBufPoolsInAscOrderOfBufSizes(t_FmExtPools *p_FmExtPools, + uint8_t *orderedArray, + uint16_t *sizesArray) +{ + uint16_t bufSize = 0; + int i=0, j=0, k=0; + + /* First we copy the external buffers pools information to an ordered local array */ + for (i=0;i<p_FmExtPools->numOfPoolsUsed;i++) + { + /* get pool size */ + bufSize = p_FmExtPools->extBufPool[i].size; + + /* keep sizes in an array according to poolId for direct access */ + sizesArray[p_FmExtPools->extBufPool[i].id] = bufSize; + + /* save poolId in an ordered array according to size */ + for (j=0;j<=i;j++) + { + /* this is the next free place in the array */ + if (j==i) + orderedArray[i] = p_FmExtPools->extBufPool[i].id; + else + { + /* find the right place for this poolId */ + if (bufSize < sizesArray[orderedArray[j]]) + { + /* move the poolIds one place ahead to make room for this poolId */ + for (k=i;k>j;k--) + orderedArray[k] = orderedArray[k-1]; + + /* now k==j, this is the place for the new size */ + orderedArray[k] = p_FmExtPools->extBufPool[i].id; + break; + } + } + } + } +} + +t_Error FmSpCheckBufPoolsParams(t_FmExtPools *p_FmExtPools, + t_FmBackupBmPools *p_FmBackupBmPools, + t_FmBufPoolDepletion *p_FmBufPoolDepletion) +{ + + int i = 0, j = 0; + bool found; + uint8_t count = 0; + + if (p_FmExtPools) + { + if (p_FmExtPools->numOfPoolsUsed > FM_PORT_MAX_NUM_OF_EXT_POOLS) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("numOfPoolsUsed can't be larger than %d", FM_PORT_MAX_NUM_OF_EXT_POOLS)); + + for (i=0;i<p_FmExtPools->numOfPoolsUsed;i++) + { + if (p_FmExtPools->extBufPool[i].id >= BM_MAX_NUM_OF_POOLS) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("extBufPools.extBufPool[%d].id can't be larger than %d", i, BM_MAX_NUM_OF_POOLS)); + if (!p_FmExtPools->extBufPool[i].size) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("extBufPools.extBufPool[%d].size is 0", i)); + } + } + if (!p_FmExtPools && (p_FmBackupBmPools || p_FmBufPoolDepletion)) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("backupBmPools ot bufPoolDepletion can not be defined without external pools")); + + /* backup BM pools indication is valid only for some chip derivatives + (limited by the config routine) */ + if (p_FmBackupBmPools) + { + if (p_FmBackupBmPools->numOfBackupPools >= p_FmExtPools->numOfPoolsUsed) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("p_BackupBmPools must be smaller than extBufPools.numOfPoolsUsed")); + found = FALSE; + for (i = 0;i<p_FmBackupBmPools->numOfBackupPools;i++) + { + + for (j=0;j<p_FmExtPools->numOfPoolsUsed;j++) + { + if (p_FmBackupBmPools->poolIds[i] == p_FmExtPools->extBufPool[j].id) + { + found = TRUE; + break; + } + } + if (!found) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("All p_BackupBmPools.poolIds must be included in extBufPools.extBufPool[n].id")); + else + found = FALSE; + } + } + + /* up to extBufPools.numOfPoolsUsed pools may be defined */ + if (p_FmBufPoolDepletion && p_FmBufPoolDepletion->poolsGrpModeEnable) + { + if ((p_FmBufPoolDepletion->numOfPools > p_FmExtPools->numOfPoolsUsed)) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("bufPoolDepletion.numOfPools can't be larger than %d and can't be larger than numOfPoolsUsed", FM_PORT_MAX_NUM_OF_EXT_POOLS)); + + if (!p_FmBufPoolDepletion->numOfPools) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("bufPoolDepletion.numOfPoolsToConsider can not be 0 when poolsGrpModeEnable=TRUE")); + + found = FALSE; + count = 0; + /* for each pool that is in poolsToConsider, check if it is defined + in extBufPool */ + for (i=0;i<BM_MAX_NUM_OF_POOLS;i++) + { + if (p_FmBufPoolDepletion->poolsToConsider[i]) + { + for (j=0;j<p_FmExtPools->numOfPoolsUsed;j++) + { + if (i == p_FmExtPools->extBufPool[j].id) + { + found = TRUE; + count++; + break; + } + } + if (!found) + RETURN_ERROR(MAJOR, E_INVALID_STATE, ("Pools selected for depletion are not used.")); + else + found = FALSE; + } + } + /* check that the number of pools that we have checked is equal to the number announced by the user */ + if (count != p_FmBufPoolDepletion->numOfPools) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("bufPoolDepletion.numOfPools is larger than the number of pools defined.")); + } + + if (p_FmBufPoolDepletion && p_FmBufPoolDepletion->singlePoolModeEnable) + { + /* calculate vector for number of pools depletion */ + found = FALSE; + count = 0; + for (i=0;i<BM_MAX_NUM_OF_POOLS;i++) + { + if (p_FmBufPoolDepletion->poolsToConsiderForSingleMode[i]) + { + for (j=0;j<p_FmExtPools->numOfPoolsUsed;j++) + { + if (i == p_FmExtPools->extBufPool[j].id) + { + found = TRUE; + count++; + break; + } + } + if (!found) + RETURN_ERROR(MAJOR, E_INVALID_STATE, ("Pools selected for depletion are not used.")); + else + found = FALSE; + } + } + if (!count) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("No pools defined for single buffer mode pool depletion.")); + } + + return E_OK; +} + +t_Error FmSpCheckIntContextParams(t_FmSpIntContextDataCopy *p_FmSpIntContextDataCopy) +{ + /* Check that divisible by 16 and not larger than 240 */ + if (p_FmSpIntContextDataCopy->intContextOffset >MAX_INT_OFFSET) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("intContext.intContextOffset can't be larger than %d", MAX_INT_OFFSET)); + if (p_FmSpIntContextDataCopy->intContextOffset % OFFSET_UNITS) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("intContext.intContextOffset has to be divisible by %d", OFFSET_UNITS)); + + /* check that ic size+ic internal offset, does not exceed ic block size */ + if (p_FmSpIntContextDataCopy->size + p_FmSpIntContextDataCopy->intContextOffset > MAX_IC_SIZE) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("intContext.size + intContext.intContextOffset has to be smaller than %d", MAX_IC_SIZE)); + /* Check that divisible by 16 and not larger than 256 */ + if (p_FmSpIntContextDataCopy->size % OFFSET_UNITS) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("intContext.size has to be divisible by %d", OFFSET_UNITS)); + + /* Check that divisible by 16 and not larger than 4K */ + if (p_FmSpIntContextDataCopy->extBufOffset > MAX_EXT_OFFSET) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("intContext.extBufOffset can't be larger than %d", MAX_EXT_OFFSET)); + if (p_FmSpIntContextDataCopy->extBufOffset % OFFSET_UNITS) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("intContext.extBufOffset has to be divisible by %d", OFFSET_UNITS)); + + return E_OK; +} + +t_Error FmSpCheckBufMargins(t_FmSpBufMargins *p_FmSpBufMargins) +{ + /* Check the margin definition */ + if (p_FmSpBufMargins->startMargins > MAX_EXT_BUFFER_OFFSET) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("bufMargins.startMargins can't be larger than %d", MAX_EXT_BUFFER_OFFSET)); + if (p_FmSpBufMargins->endMargins > MAX_EXT_BUFFER_OFFSET) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("bufMargins.endMargins can't be larger than %d", MAX_EXT_BUFFER_OFFSET)); + + return E_OK; +} + +t_Error FmSpBuildBufferStructure(t_FmSpIntContextDataCopy *p_FmSpIntContextDataCopy, + t_FmBufferPrefixContent *p_BufferPrefixContent, + t_FmSpBufMargins *p_FmSpBufMargins, + t_FmSpBufferOffsets *p_FmSpBufferOffsets, + uint8_t *internalBufferOffset) +{ + uint32_t tmp; + + SANITY_CHECK_RETURN_ERROR(p_FmSpIntContextDataCopy, E_INVALID_VALUE); + ASSERT_COND(p_FmSpIntContextDataCopy); + ASSERT_COND(p_BufferPrefixContent); + ASSERT_COND(p_FmSpBufMargins); + ASSERT_COND(p_FmSpBufferOffsets); + + /* Align start of internal context data to 16 byte */ + p_FmSpIntContextDataCopy->extBufOffset = + (uint16_t)((p_BufferPrefixContent->privDataSize & (OFFSET_UNITS-1)) ? + ((p_BufferPrefixContent->privDataSize + OFFSET_UNITS) & ~(uint16_t)(OFFSET_UNITS-1)) : + p_BufferPrefixContent->privDataSize); + + /* Translate margin and intContext params to FM parameters */ + /* Initialize with illegal value. Later we'll set legal values. */ + p_FmSpBufferOffsets->prsResultOffset = (uint32_t)ILLEGAL_BASE; + p_FmSpBufferOffsets->timeStampOffset = (uint32_t)ILLEGAL_BASE; + p_FmSpBufferOffsets->hashResultOffset= (uint32_t)ILLEGAL_BASE; + p_FmSpBufferOffsets->pcdInfoOffset = (uint32_t)ILLEGAL_BASE; + + /* Internally the driver supports 4 options + 1. prsResult/timestamp/hashResult selection (in fact 8 options, but for simplicity we'll + relate to it as 1). + 2. All IC context (from AD) not including debug.*/ + + /* This 'if' covers option 2. We copy from beginning of context. */ + if (p_BufferPrefixContent->passAllOtherPCDInfo) + { + p_FmSpIntContextDataCopy->size = 128; /* must be aligned to 16 */ + /* Start copying data after 16 bytes (FD) from the beginning of the internal context */ + p_FmSpIntContextDataCopy->intContextOffset = 16; + + if (p_BufferPrefixContent->passAllOtherPCDInfo) + p_FmSpBufferOffsets->pcdInfoOffset = p_FmSpIntContextDataCopy->extBufOffset; + if (p_BufferPrefixContent->passPrsResult) + p_FmSpBufferOffsets->prsResultOffset = + (uint32_t)(p_FmSpIntContextDataCopy->extBufOffset + 16); + if (p_BufferPrefixContent->passTimeStamp) + p_FmSpBufferOffsets->timeStampOffset = + (uint32_t)(p_FmSpIntContextDataCopy->extBufOffset + 48); + if (p_BufferPrefixContent->passHashResult) + p_FmSpBufferOffsets->hashResultOffset = + (uint32_t)(p_FmSpIntContextDataCopy->extBufOffset + 56); + } + else + { + /* This case covers the options under 1 */ + /* Copy size must be in 16-byte granularity. */ + p_FmSpIntContextDataCopy->size = + (uint16_t)((p_BufferPrefixContent->passPrsResult ? 32 : 0) + + ((p_BufferPrefixContent->passTimeStamp || + p_BufferPrefixContent->passHashResult) ? 16 : 0)); + + /* Align start of internal context data to 16 byte */ + p_FmSpIntContextDataCopy->intContextOffset = + (uint8_t)(p_BufferPrefixContent->passPrsResult ? 32 : + ((p_BufferPrefixContent->passTimeStamp || + p_BufferPrefixContent->passHashResult) ? 64 : 0)); + + if (p_BufferPrefixContent->passPrsResult) + p_FmSpBufferOffsets->prsResultOffset = p_FmSpIntContextDataCopy->extBufOffset; + if (p_BufferPrefixContent->passTimeStamp) + p_FmSpBufferOffsets->timeStampOffset = p_BufferPrefixContent->passPrsResult ? + (p_FmSpIntContextDataCopy->extBufOffset + sizeof(t_FmPrsResult)) : + p_FmSpIntContextDataCopy->extBufOffset; + if (p_BufferPrefixContent->passHashResult) + /* If PR is not requested, whether TS is requested or not, IC will be copied from TS */ + p_FmSpBufferOffsets->hashResultOffset = p_BufferPrefixContent->passPrsResult ? + (p_FmSpIntContextDataCopy->extBufOffset + sizeof(t_FmPrsResult) + 8) : + p_FmSpIntContextDataCopy->extBufOffset + 8; + } + + if (p_FmSpIntContextDataCopy->size) + p_FmSpBufMargins->startMargins = + (uint16_t)(p_FmSpIntContextDataCopy->extBufOffset + + p_FmSpIntContextDataCopy->size); + else + /* No Internal Context passing, STartMargin is immediately after privateInfo */ + p_FmSpBufMargins->startMargins = p_BufferPrefixContent->privDataSize; + + /* save extra space for manip in both external and internal buffers */ + if (p_BufferPrefixContent->manipExtraSpace) + { + uint8_t extraSpace; +#ifdef FM_CAPWAP_SUPPORT + if ((p_BufferPrefixContent->manipExtraSpace + CAPWAP_FRAG_EXTRA_SPACE) >= 256) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, + ("p_BufferPrefixContent->manipExtraSpace should be less than %d", + 256-CAPWAP_FRAG_EXTRA_SPACE)); + extraSpace = (uint8_t)(p_BufferPrefixContent->manipExtraSpace + CAPWAP_FRAG_EXTRA_SPACE); +#else + extraSpace = p_BufferPrefixContent->manipExtraSpace; +#endif /* FM_CAPWAP_SUPPORT */ + p_FmSpBufferOffsets->manipOffset = p_FmSpBufMargins->startMargins; + p_FmSpBufMargins->startMargins += extraSpace; + *internalBufferOffset = extraSpace; + } + + /* align data start */ + tmp = (uint32_t)(p_FmSpBufMargins->startMargins % p_BufferPrefixContent->dataAlign); + if (tmp) + p_FmSpBufMargins->startMargins += (p_BufferPrefixContent->dataAlign-tmp); + p_FmSpBufferOffsets->dataOffset = p_FmSpBufMargins->startMargins; + + return E_OK; +} +/*********************** End of inter-module routines ************************/ + + +#if (DPAA_VERSION >= 11) +/*****************************************************************************/ +/* API routines */ +/*****************************************************************************/ +t_Handle FM_VSP_Config(t_FmVspParams *p_FmVspParams) +{ + t_FmVspEntry *p_FmVspEntry = NULL; + struct fm_storage_profile_params fm_vsp_params; + + p_FmVspEntry = (t_FmVspEntry *)XX_Malloc(sizeof(t_FmVspEntry)); + if (!p_FmVspEntry) + { + REPORT_ERROR(MAJOR, E_NO_MEMORY, ("p_StorageProfile allocation failed")); + return NULL; + } + memset(p_FmVspEntry, 0, sizeof(t_FmVspEntry)); + + p_FmVspEntry->p_FmVspEntryDriverParams = (t_FmVspEntryDriverParams *)XX_Malloc(sizeof(t_FmVspEntryDriverParams)); + if (!p_FmVspEntry->p_FmVspEntryDriverParams) + { + REPORT_ERROR(MAJOR, E_NO_MEMORY, ("p_StorageProfile allocation failed")); + XX_Free(p_FmVspEntry); + return NULL; + } + memset(p_FmVspEntry->p_FmVspEntryDriverParams, 0, sizeof(t_FmVspEntryDriverParams)); + fman_vsp_defconfig(&fm_vsp_params); + p_FmVspEntry->p_FmVspEntryDriverParams->dmaHeaderCacheAttr = fm_vsp_params.header_cache_attr; + p_FmVspEntry->p_FmVspEntryDriverParams->dmaIntContextCacheAttr = fm_vsp_params.int_context_cache_attr; + p_FmVspEntry->p_FmVspEntryDriverParams->dmaScatterGatherCacheAttr = fm_vsp_params.scatter_gather_cache_attr; + p_FmVspEntry->p_FmVspEntryDriverParams->dmaSwapData = fm_vsp_params.dma_swap_data; + p_FmVspEntry->p_FmVspEntryDriverParams->dmaWriteOptimize = fm_vsp_params.dma_write_optimize; + p_FmVspEntry->p_FmVspEntryDriverParams->noScatherGather = fm_vsp_params.no_scather_gather; + p_FmVspEntry->p_FmVspEntryDriverParams->bufferPrefixContent.privDataSize = DEFAULT_FM_SP_bufferPrefixContent_privDataSize; + p_FmVspEntry->p_FmVspEntryDriverParams->bufferPrefixContent.passPrsResult= DEFAULT_FM_SP_bufferPrefixContent_passPrsResult; + p_FmVspEntry->p_FmVspEntryDriverParams->bufferPrefixContent.passTimeStamp= DEFAULT_FM_SP_bufferPrefixContent_passTimeStamp; + p_FmVspEntry->p_FmVspEntryDriverParams->bufferPrefixContent.passAllOtherPCDInfo + = DEFAULT_FM_SP_bufferPrefixContent_passTimeStamp; + p_FmVspEntry->p_FmVspEntryDriverParams->bufferPrefixContent.dataAlign = DEFAULT_FM_SP_bufferPrefixContent_dataAlign; + p_FmVspEntry->p_FmVspEntryDriverParams->liodnOffset = p_FmVspParams->liodnOffset; + + memcpy(&p_FmVspEntry->p_FmVspEntryDriverParams->extBufPools, &p_FmVspParams->extBufPools, sizeof(t_FmExtPools)); + p_FmVspEntry->h_Fm = p_FmVspParams->h_Fm; + p_FmVspEntry->portType = p_FmVspParams->portParams.portType; + p_FmVspEntry->portId = p_FmVspParams->portParams.portId; + + p_FmVspEntry->relativeProfileId = p_FmVspParams->relativeProfileId; + + return p_FmVspEntry; +} + +t_Error FM_VSP_Init(t_Handle h_FmVsp) +{ + + t_FmVspEntry *p_FmVspEntry = (t_FmVspEntry *)h_FmVsp; + struct fm_storage_profile_params fm_vsp_params; + uint8_t orderedArray[FM_PORT_MAX_NUM_OF_EXT_POOLS]; + uint16_t sizesArray[BM_MAX_NUM_OF_POOLS]; + t_Error err; + uint16_t absoluteProfileId = 0; + int i = 0; + + SANITY_CHECK_RETURN_ERROR(p_FmVspEntry, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_FmVspEntry->p_FmVspEntryDriverParams,E_INVALID_HANDLE); + + CHECK_INIT_PARAMETERS(p_FmVspEntry, CheckParams); + + memset(&orderedArray, 0, sizeof(uint8_t) * FM_PORT_MAX_NUM_OF_EXT_POOLS); + memset(&sizesArray, 0, sizeof(uint16_t) * BM_MAX_NUM_OF_POOLS); + + err = FmSpBuildBufferStructure(&p_FmVspEntry->intContext, + &p_FmVspEntry->p_FmVspEntryDriverParams->bufferPrefixContent, + &p_FmVspEntry->bufMargins, + &p_FmVspEntry->bufferOffsets, + &p_FmVspEntry->internalBufferOffset); + if (err != E_OK) + RETURN_ERROR(MAJOR, err, NO_MSG); + + + err = CheckParamsGeneratedInternally(p_FmVspEntry); + if (err != E_OK) + RETURN_ERROR(MAJOR, err, NO_MSG); + + + p_FmVspEntry->p_FmSpRegsBase = + (struct fm_pcd_storage_profile_regs *)FmGetVSPBaseAddr(p_FmVspEntry->h_Fm); + if (!p_FmVspEntry->p_FmSpRegsBase) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("impossible to initialize SpRegsBase")); + + /* order external buffer pools in ascending order of buffer pools sizes */ + FmSpSetBufPoolsInAscOrderOfBufSizes(&(p_FmVspEntry->p_FmVspEntryDriverParams)->extBufPools, + orderedArray, + sizesArray); + + p_FmVspEntry->extBufPools.numOfPoolsUsed = + p_FmVspEntry->p_FmVspEntryDriverParams->extBufPools.numOfPoolsUsed; + for (i = 0; i < p_FmVspEntry->extBufPools.numOfPoolsUsed; i++) + { + p_FmVspEntry->extBufPools.extBufPool[i].id = orderedArray[i]; + p_FmVspEntry->extBufPools.extBufPool[i].size = sizesArray[orderedArray[i]]; + } + + /* on user responsibility to fill it according requirement */ + memset(&fm_vsp_params, 0, sizeof(struct fm_storage_profile_params)); + fm_vsp_params.dma_swap_data = p_FmVspEntry->p_FmVspEntryDriverParams->dmaSwapData; + fm_vsp_params.int_context_cache_attr = p_FmVspEntry->p_FmVspEntryDriverParams->dmaIntContextCacheAttr; + fm_vsp_params.header_cache_attr = p_FmVspEntry->p_FmVspEntryDriverParams->dmaHeaderCacheAttr; + fm_vsp_params.scatter_gather_cache_attr = p_FmVspEntry->p_FmVspEntryDriverParams->dmaScatterGatherCacheAttr; + fm_vsp_params.dma_write_optimize = p_FmVspEntry->p_FmVspEntryDriverParams->dmaWriteOptimize; + fm_vsp_params.liodn_offset = p_FmVspEntry->p_FmVspEntryDriverParams->liodnOffset; + fm_vsp_params.no_scather_gather = p_FmVspEntry->p_FmVspEntryDriverParams->noScatherGather; + + if (p_FmVspEntry->p_FmVspEntryDriverParams->p_BufPoolDepletion) + { + fm_vsp_params.buf_pool_depletion.buf_pool_depletion_enabled = TRUE; + fm_vsp_params.buf_pool_depletion.pools_grp_mode_enable = p_FmVspEntry->p_FmVspEntryDriverParams->p_BufPoolDepletion->poolsGrpModeEnable; + fm_vsp_params.buf_pool_depletion.num_pools = p_FmVspEntry->p_FmVspEntryDriverParams->p_BufPoolDepletion->numOfPools; + fm_vsp_params.buf_pool_depletion.pools_to_consider = p_FmVspEntry->p_FmVspEntryDriverParams->p_BufPoolDepletion->poolsToConsider; + fm_vsp_params.buf_pool_depletion.single_pool_mode_enable = p_FmVspEntry->p_FmVspEntryDriverParams->p_BufPoolDepletion->singlePoolModeEnable; + fm_vsp_params.buf_pool_depletion.pools_to_consider_for_single_mode = p_FmVspEntry->p_FmVspEntryDriverParams->p_BufPoolDepletion->poolsToConsiderForSingleMode; + fm_vsp_params.buf_pool_depletion.has_pfc_priorities = TRUE; + fm_vsp_params.buf_pool_depletion.pfc_priorities_en = p_FmVspEntry->p_FmVspEntryDriverParams->p_BufPoolDepletion->pfcPrioritiesEn; + } + else + fm_vsp_params.buf_pool_depletion.buf_pool_depletion_enabled = FALSE; + + if (p_FmVspEntry->p_FmVspEntryDriverParams->p_BackupBmPools) + { + fm_vsp_params.backup_pools.num_backup_pools = p_FmVspEntry->p_FmVspEntryDriverParams->p_BackupBmPools->numOfBackupPools; + fm_vsp_params.backup_pools.pool_ids = p_FmVspEntry->p_FmVspEntryDriverParams->p_BackupBmPools->poolIds; + } + else + fm_vsp_params.backup_pools.num_backup_pools = 0; + + fm_vsp_params.fm_ext_pools.num_pools_used = p_FmVspEntry->extBufPools.numOfPoolsUsed; + fm_vsp_params.fm_ext_pools.ext_buf_pool = (struct fman_ext_pool_params*)&p_FmVspEntry->extBufPools.extBufPool; + fm_vsp_params.buf_margins = (struct fman_sp_buf_margins*)&p_FmVspEntry->bufMargins; + fm_vsp_params.int_context = (struct fman_sp_int_context_data_copy*)&p_FmVspEntry->intContext; + + /* no check on err - it was checked earlier */ + FmVSPGetAbsoluteProfileId(p_FmVspEntry->h_Fm, + p_FmVspEntry->portType, + p_FmVspEntry->portId, + p_FmVspEntry->relativeProfileId, + &absoluteProfileId); + + ASSERT_COND(p_FmVspEntry->p_FmSpRegsBase); + ASSERT_COND(fm_vsp_params.int_context); + ASSERT_COND(fm_vsp_params.buf_margins); + ASSERT_COND((absoluteProfileId <= FM_VSP_MAX_NUM_OF_ENTRIES)); + + /* Set all registers related to VSP */ + fman_vsp_init(p_FmVspEntry->p_FmSpRegsBase, absoluteProfileId, &fm_vsp_params,FM_PORT_MAX_NUM_OF_EXT_POOLS, BM_MAX_NUM_OF_POOLS, FM_MAX_NUM_OF_PFC_PRIORITIES); + + p_FmVspEntry->absoluteSpId = absoluteProfileId; + + if (p_FmVspEntry->p_FmVspEntryDriverParams) + XX_Free(p_FmVspEntry->p_FmVspEntryDriverParams); + p_FmVspEntry->p_FmVspEntryDriverParams = NULL; + + return E_OK; +} + +t_Error FM_VSP_Free(t_Handle h_FmVsp) +{ + t_FmVspEntry *p_FmVspEntry = (t_FmVspEntry *)h_FmVsp; + SANITY_CHECK_RETURN_ERROR(h_FmVsp, E_INVALID_HANDLE); + XX_Free(p_FmVspEntry); + return E_OK; +} + +t_Error FM_VSP_ConfigBufferPrefixContent(t_Handle h_FmVsp, t_FmBufferPrefixContent *p_FmBufferPrefixContent) +{ + t_FmVspEntry *p_FmVspEntry = (t_FmVspEntry*)h_FmVsp; + + SANITY_CHECK_RETURN_ERROR(p_FmVspEntry, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_FmVspEntry->p_FmVspEntryDriverParams, E_INVALID_HANDLE); + + memcpy(&p_FmVspEntry->p_FmVspEntryDriverParams->bufferPrefixContent, p_FmBufferPrefixContent, sizeof(t_FmBufferPrefixContent)); + /* if dataAlign was not initialized by user, we return to driver's default */ + if (!p_FmVspEntry->p_FmVspEntryDriverParams->bufferPrefixContent.dataAlign) + p_FmVspEntry->p_FmVspEntryDriverParams->bufferPrefixContent.dataAlign = DEFAULT_FM_SP_bufferPrefixContent_dataAlign; + + return E_OK; +} + +t_Error FM_VSP_ConfigDmaSwapData(t_Handle h_FmVsp, e_FmDmaSwapOption swapData) +{ + t_FmVspEntry *p_FmVspEntry = (t_FmVspEntry*)h_FmVsp; + + SANITY_CHECK_RETURN_ERROR(p_FmVspEntry, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_FmVspEntry->p_FmVspEntryDriverParams, E_INVALID_HANDLE); + + p_FmVspEntry->p_FmVspEntryDriverParams->dmaSwapData = swapData; + + return E_OK; +} + +t_Error FM_VSP_ConfigDmaIcCacheAttr(t_Handle h_FmVsp, e_FmDmaCacheOption intContextCacheAttr) +{ + t_FmVspEntry *p_FmVspEntry = (t_FmVspEntry*)h_FmVsp; + + SANITY_CHECK_RETURN_ERROR(p_FmVspEntry, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_FmVspEntry->p_FmVspEntryDriverParams, E_INVALID_HANDLE); + + p_FmVspEntry->p_FmVspEntryDriverParams->dmaIntContextCacheAttr = intContextCacheAttr; + + return E_OK; +} + +t_Error FM_VSP_ConfigDmaHdrAttr(t_Handle h_FmVsp, e_FmDmaCacheOption headerCacheAttr) +{ + t_FmVspEntry *p_FmVspEntry = (t_FmVspEntry*)h_FmVsp; + + SANITY_CHECK_RETURN_ERROR(p_FmVspEntry, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_FmVspEntry->p_FmVspEntryDriverParams, E_INVALID_HANDLE); + + p_FmVspEntry->p_FmVspEntryDriverParams->dmaHeaderCacheAttr = headerCacheAttr; + + return E_OK; +} + +t_Error FM_VSP_ConfigDmaScatterGatherAttr(t_Handle h_FmVsp, e_FmDmaCacheOption scatterGatherCacheAttr) +{ + t_FmVspEntry *p_FmVspEntry = (t_FmVspEntry*)h_FmVsp; + + SANITY_CHECK_RETURN_ERROR(p_FmVspEntry, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_FmVspEntry->p_FmVspEntryDriverParams, E_INVALID_HANDLE); + + p_FmVspEntry->p_FmVspEntryDriverParams->dmaScatterGatherCacheAttr = scatterGatherCacheAttr; + + return E_OK; +} + +t_Error FM_VSP_ConfigDmaWriteOptimize(t_Handle h_FmVsp, bool optimize) +{ + t_FmVspEntry *p_FmVspEntry = (t_FmVspEntry*)h_FmVsp; + + SANITY_CHECK_RETURN_ERROR(p_FmVspEntry, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_FmVspEntry->p_FmVspEntryDriverParams, E_INVALID_HANDLE); + + + p_FmVspEntry->p_FmVspEntryDriverParams->dmaWriteOptimize = optimize; + + return E_OK; +} + +t_Error FM_VSP_ConfigNoScatherGather(t_Handle h_FmVsp, bool noScatherGather) +{ + t_FmVspEntry *p_FmVspEntry = (t_FmVspEntry*)h_FmVsp; + + SANITY_CHECK_RETURN_ERROR(p_FmVspEntry, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_FmVspEntry->p_FmVspEntryDriverParams, E_INVALID_HANDLE); + + + p_FmVspEntry->p_FmVspEntryDriverParams->noScatherGather = noScatherGather; + + return E_OK; +} + +t_Error FM_VSP_ConfigPoolDepletion(t_Handle h_FmVsp, t_FmBufPoolDepletion *p_BufPoolDepletion) +{ + t_FmVspEntry *p_FmVspEntry = (t_FmVspEntry*)h_FmVsp; + + SANITY_CHECK_RETURN_ERROR(h_FmVsp, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_FmVspEntry->p_FmVspEntryDriverParams, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_BufPoolDepletion, E_INVALID_HANDLE); + + p_FmVspEntry->p_FmVspEntryDriverParams->p_BufPoolDepletion = (t_FmBufPoolDepletion *)XX_Malloc(sizeof(t_FmBufPoolDepletion)); + if (!p_FmVspEntry->p_FmVspEntryDriverParams->p_BufPoolDepletion) + RETURN_ERROR(MAJOR, E_NO_MEMORY, ("p_BufPoolDepletion allocation failed")); + memcpy(p_FmVspEntry->p_FmVspEntryDriverParams->p_BufPoolDepletion, p_BufPoolDepletion, sizeof(t_FmBufPoolDepletion)); + + return E_OK; +} + +t_Error FM_VSP_ConfigBackupPools(t_Handle h_FmVsp, t_FmBackupBmPools *p_BackupBmPools) +{ + t_FmVspEntry *p_FmVspEntry = (t_FmVspEntry*)h_FmVsp; + + SANITY_CHECK_RETURN_ERROR(h_FmVsp, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_FmVspEntry->p_FmVspEntryDriverParams, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_BackupBmPools, E_INVALID_HANDLE); + + p_FmVspEntry->p_FmVspEntryDriverParams->p_BackupBmPools = (t_FmBackupBmPools *)XX_Malloc(sizeof(t_FmBackupBmPools)); + if (!p_FmVspEntry->p_FmVspEntryDriverParams->p_BackupBmPools) + RETURN_ERROR(MAJOR, E_NO_MEMORY, ("p_BackupBmPools allocation failed")); + memcpy(p_FmVspEntry->p_FmVspEntryDriverParams->p_BackupBmPools, p_BackupBmPools, sizeof(t_FmBackupBmPools)); + + return E_OK; +} + +uint32_t FM_VSP_GetBufferDataOffset(t_Handle h_FmVsp) +{ + t_FmVspEntry *p_FmVspEntry = (t_FmVspEntry*)h_FmVsp; + + SANITY_CHECK_RETURN_VALUE(p_FmVspEntry, E_INVALID_HANDLE, 0); + SANITY_CHECK_RETURN_VALUE(!p_FmVspEntry->p_FmVspEntryDriverParams, E_INVALID_STATE, 0); + + return p_FmVspEntry->bufferOffsets.dataOffset; +} + +uint8_t * FM_VSP_GetBufferICInfo(t_Handle h_FmVsp, char *p_Data) +{ + t_FmVspEntry *p_FmVspEntry = (t_FmVspEntry*)h_FmVsp; + + SANITY_CHECK_RETURN_VALUE(p_FmVspEntry, E_INVALID_HANDLE, NULL); + SANITY_CHECK_RETURN_VALUE(!p_FmVspEntry->p_FmVspEntryDriverParams, E_INVALID_STATE, NULL); + + if (p_FmVspEntry->bufferOffsets.pcdInfoOffset == ILLEGAL_BASE) + return NULL; + + return (uint8_t *)PTR_MOVE(p_Data, p_FmVspEntry->bufferOffsets.pcdInfoOffset); +} + +t_FmPrsResult * FM_VSP_GetBufferPrsResult(t_Handle h_FmVsp, char *p_Data) +{ + t_FmVspEntry *p_FmVspEntry = (t_FmVspEntry*)h_FmVsp; + + SANITY_CHECK_RETURN_VALUE(p_FmVspEntry, E_INVALID_HANDLE, NULL); + SANITY_CHECK_RETURN_VALUE(!p_FmVspEntry->p_FmVspEntryDriverParams, E_INVALID_STATE, NULL); + + if (p_FmVspEntry->bufferOffsets.prsResultOffset == ILLEGAL_BASE) + return NULL; + + return (t_FmPrsResult *)PTR_MOVE(p_Data, p_FmVspEntry->bufferOffsets.prsResultOffset); +} + +uint64_t * FM_VSP_GetBufferTimeStamp(t_Handle h_FmVsp, char *p_Data) +{ + t_FmVspEntry *p_FmVspEntry = (t_FmVspEntry*)h_FmVsp; + + SANITY_CHECK_RETURN_VALUE(p_FmVspEntry, E_INVALID_HANDLE, NULL); + SANITY_CHECK_RETURN_VALUE(!p_FmVspEntry->p_FmVspEntryDriverParams, E_INVALID_STATE, NULL); + + if (p_FmVspEntry->bufferOffsets.timeStampOffset == ILLEGAL_BASE) + return NULL; + + return (uint64_t *)PTR_MOVE(p_Data, p_FmVspEntry->bufferOffsets.timeStampOffset); +} + +uint8_t * FM_VSP_GetBufferHashResult(t_Handle h_FmVsp, char *p_Data) +{ + t_FmVspEntry *p_FmVspEntry = (t_FmVspEntry*)h_FmVsp; + + SANITY_CHECK_RETURN_VALUE(p_FmVspEntry, E_INVALID_HANDLE, NULL); + SANITY_CHECK_RETURN_VALUE(!p_FmVspEntry->p_FmVspEntryDriverParams, E_INVALID_STATE, NULL); + + if (p_FmVspEntry->bufferOffsets.hashResultOffset == ILLEGAL_BASE) + return NULL; + + return (uint8_t *)PTR_MOVE(p_Data, p_FmVspEntry->bufferOffsets.hashResultOffset); +} + +#endif /* (DPAA_VERSION >= 11) */ diff --git a/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/SP/fm_sp.h b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/SP/fm_sp.h new file mode 100644 index 000000000000..9c171d85a5bb --- /dev/null +++ b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/SP/fm_sp.h @@ -0,0 +1,85 @@ +/* + * Copyright 2008-2012 Freescale Semiconductor Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Freescale Semiconductor nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * + * ALTERNATIVELY, this software may be distributed under the terms of the + * GNU General Public License ("GPL") as published by the Free Software + * Foundation, either version 2 of that License or (at your option) any + * later version. + * + * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + +/****************************************************************************** + @File fm_sp.h + + @Description FM SP ... +*//***************************************************************************/ +#ifndef __FM_SP_H +#define __FM_SP_H + +#include "std_ext.h" +#include "error_ext.h" +#include "list_ext.h" + +#include "fm_sp_common.h" +#include "fm_common.h" + + +#define __ERR_MODULE__ MODULE_FM_SP + +typedef struct { + t_FmBufferPrefixContent bufferPrefixContent; + e_FmDmaSwapOption dmaSwapData; + e_FmDmaCacheOption dmaIntContextCacheAttr; + e_FmDmaCacheOption dmaHeaderCacheAttr; + e_FmDmaCacheOption dmaScatterGatherCacheAttr; + bool dmaWriteOptimize; + uint16_t liodnOffset; + bool noScatherGather; + t_FmBufPoolDepletion *p_BufPoolDepletion; + t_FmBackupBmPools *p_BackupBmPools; + t_FmExtPools extBufPools; +} t_FmVspEntryDriverParams; + +typedef struct { + bool valid; + volatile bool lock; + uint8_t pointedOwners; + uint16_t absoluteSpId; + uint8_t internalBufferOffset; + t_FmSpBufMargins bufMargins; + t_FmSpIntContextDataCopy intContext; + t_FmSpBufferOffsets bufferOffsets; + t_Handle h_Fm; + e_FmPortType portType; /**< Port type */ + uint8_t portId; /**< Port Id - relative to type */ + uint8_t relativeProfileId; + struct fm_pcd_storage_profile_regs *p_FmSpRegsBase; + t_FmExtPools extBufPools; + t_FmVspEntryDriverParams *p_FmVspEntryDriverParams; +} t_FmVspEntry; + + +#endif /* __FM_SP_H */ diff --git a/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/SP/fman_sp.c b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/SP/fman_sp.c new file mode 100755 index 000000000000..0f772e919792 --- /dev/null +++ b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/SP/fman_sp.c @@ -0,0 +1,197 @@ +/* + * Copyright 2013 Freescale Semiconductor Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Freescale Semiconductor nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * + * ALTERNATIVELY, this software may be distributed under the terms of the + * GNU General Public License ("GPL") as published by the Free Software + * Foundation, either version 2 of that License or (at your option) any + * later version. + * + * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "fsl_fman_sp.h" + + +uint32_t fman_vsp_get_statistics(struct fm_pcd_storage_profile_regs *regs, + uint16_t index) +{ + struct fm_pcd_storage_profile_regs *sp_regs; + sp_regs = ®s[index]; + return ioread32be(&sp_regs->fm_sp_acnt); +} + +void fman_vsp_set_statistics(struct fm_pcd_storage_profile_regs *regs, + uint16_t index, uint32_t value) +{ + struct fm_pcd_storage_profile_regs *sp_regs; + sp_regs = ®s[index]; + iowrite32be(value, &sp_regs->fm_sp_acnt); +} + +void fman_vsp_defconfig(struct fm_storage_profile_params *cfg) +{ + cfg->dma_swap_data = + DEFAULT_FMAN_SP_DMA_SWAP_DATA; + cfg->int_context_cache_attr = + DEFAULT_FMAN_SP_DMA_INT_CONTEXT_CACHE_ATTR; + cfg->header_cache_attr = + DEFAULT_FMAN_SP_DMA_HEADER_CACHE_ATTR; + cfg->scatter_gather_cache_attr = + DEFAULT_FMAN_SP_DMA_SCATTER_GATHER_CACHE_ATTR; + cfg->dma_write_optimize = + DEFAULT_FMAN_SP_DMA_WRITE_OPTIMIZE; + cfg->no_scather_gather = + DEFAULT_FMAN_SP_NO_SCATTER_GATHER; +} + +static inline uint32_t calc_vec_dep(int max_pools, bool *pools, + struct fman_ext_pools *ext_buf_pools, uint32_t mask) +{ + int i, j; + uint32_t vector = 0; + for (i = 0; i < max_pools; i++) + if (pools[i]) + for (j = 0; j < ext_buf_pools->num_pools_used; j++) + if (i == ext_buf_pools->ext_buf_pool[j].id) { + vector |= mask >> j; + break; + } + return vector; +} + +void fman_vsp_init(struct fm_pcd_storage_profile_regs *regs, + uint16_t index, struct fm_storage_profile_params *fm_vsp_params, + int port_max_num_of_ext_pools, int bm_max_num_of_pools, + int max_num_of_pfc_priorities) +{ + int i = 0, j = 0; + struct fm_pcd_storage_profile_regs *sp_regs; + uint32_t tmp_reg, vector; + struct fman_ext_pools *ext_buf_pools = &fm_vsp_params->fm_ext_pools; + struct fman_buf_pool_depletion *buf_pool_depletion = + &fm_vsp_params->buf_pool_depletion; + struct fman_backup_bm_pools *backup_pools = + &fm_vsp_params->backup_pools; + struct fman_sp_int_context_data_copy *int_context_data_copy = + fm_vsp_params->int_context; + struct fman_sp_buf_margins *external_buffer_margins = + fm_vsp_params->buf_margins; + bool no_scather_gather = fm_vsp_params->no_scather_gather; + uint16_t liodn_offset = fm_vsp_params->liodn_offset; + + sp_regs = ®s[index]; + + /* fill external buffers manager pool information register*/ + for (i = 0; i < ext_buf_pools->num_pools_used; i++) { + tmp_reg = FMAN_SP_EXT_BUF_POOL_VALID | + FMAN_SP_EXT_BUF_POOL_EN_COUNTER; + tmp_reg |= ((uint32_t)ext_buf_pools->ext_buf_pool[i].id << + FMAN_SP_EXT_BUF_POOL_ID_SHIFT); + tmp_reg |= ext_buf_pools->ext_buf_pool[i].size; + /* functionality available only for some deriviatives + (limited by config) */ + for (j = 0; j < backup_pools->num_backup_pools; j++) + if (ext_buf_pools->ext_buf_pool[i].id == + backup_pools->pool_ids[j]) { + tmp_reg |= FMAN_SP_EXT_BUF_POOL_BACKUP; + break; + } + iowrite32be(tmp_reg, &sp_regs->fm_sp_ebmpi[i]); + } + + /* clear unused pools */ + for (i = ext_buf_pools->num_pools_used; + i < port_max_num_of_ext_pools; i++) + iowrite32be(0, &sp_regs->fm_sp_ebmpi[i]); + + /* fill pool depletion register*/ + tmp_reg = 0; + if (buf_pool_depletion->buf_pool_depletion_enabled && buf_pool_depletion->pools_grp_mode_enable) { + /* calculate vector for number of pools depletion */ + vector = calc_vec_dep(bm_max_num_of_pools, buf_pool_depletion-> + pools_to_consider, ext_buf_pools, 0x80000000); + + /* configure num of pools and vector for number of pools mode */ + tmp_reg |= (((uint32_t)buf_pool_depletion->num_pools - 1) << + FMAN_SP_POOL_DEP_NUM_OF_POOLS_SHIFT); + tmp_reg |= vector; + } + + if (buf_pool_depletion->buf_pool_depletion_enabled && buf_pool_depletion->single_pool_mode_enable) { + /* calculate vector for number of pools depletion */ + vector = calc_vec_dep(bm_max_num_of_pools, buf_pool_depletion-> + pools_to_consider_for_single_mode, + ext_buf_pools, 0x00000080); + + /* configure num of pools and vector for number of pools mode */ + tmp_reg |= vector; + } + + /* fill QbbPEV */ + if (buf_pool_depletion->buf_pool_depletion_enabled) { + vector = 0; + for (i = 0; i < max_num_of_pfc_priorities; i++) + if (buf_pool_depletion->pfc_priorities_en[i] == TRUE) + vector |= 0x00000100 << i; + tmp_reg |= vector; + } + iowrite32be(tmp_reg, &sp_regs->fm_sp_mpd); + + /* fill dma attributes register */ + tmp_reg = 0; + tmp_reg |= (uint32_t)fm_vsp_params->dma_swap_data << + FMAN_SP_DMA_ATTR_SWP_SHIFT; + tmp_reg |= (uint32_t)fm_vsp_params->int_context_cache_attr << + FMAN_SP_DMA_ATTR_IC_CACHE_SHIFT; + tmp_reg |= (uint32_t)fm_vsp_params->header_cache_attr << + FMAN_SP_DMA_ATTR_HDR_CACHE_SHIFT; + tmp_reg |= (uint32_t)fm_vsp_params->scatter_gather_cache_attr << + FMAN_SP_DMA_ATTR_SG_CACHE_SHIFT; + if (fm_vsp_params->dma_write_optimize) + tmp_reg |= FMAN_SP_DMA_ATTR_WRITE_OPTIMIZE; + iowrite32be(tmp_reg, &sp_regs->fm_sp_da); + + /* IC parameters - fill internal context parameters register */ + tmp_reg = 0; + tmp_reg |= (((uint32_t)int_context_data_copy->ext_buf_offset/ + OFFSET_UNITS) << FMAN_SP_IC_TO_EXT_SHIFT); + tmp_reg |= (((uint32_t)int_context_data_copy->int_context_offset/ + OFFSET_UNITS) << FMAN_SP_IC_FROM_INT_SHIFT); + tmp_reg |= (((uint32_t)int_context_data_copy->size/OFFSET_UNITS) << + FMAN_SP_IC_SIZE_SHIFT); + iowrite32be(tmp_reg, &sp_regs->fm_sp_icp); + + /* buffer margins - fill external buffer margins register */ + tmp_reg = 0; + tmp_reg |= (((uint32_t)external_buffer_margins->start_margins) << + FMAN_SP_EXT_BUF_MARG_START_SHIFT); + tmp_reg |= (((uint32_t)external_buffer_margins->end_margins) << + FMAN_SP_EXT_BUF_MARG_END_SHIFT); + if (no_scather_gather) + tmp_reg |= FMAN_SP_SG_DISABLE; + iowrite32be(tmp_reg, &sp_regs->fm_sp_ebm); + + /* buffer margins - fill spliodn register */ + iowrite32be(liodn_offset, &sp_regs->fm_sp_spliodn); +} diff --git a/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/fm.c b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/fm.c new file mode 100644 index 000000000000..c96c2a12f29e --- /dev/null +++ b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/fm.c @@ -0,0 +1,5223 @@ +/* + * Copyright 2008-2012 Freescale Semiconductor Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Freescale Semiconductor nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * + * ALTERNATIVELY, this software may be distributed under the terms of the + * GNU General Public License ("GPL") as published by the Free Software + * Foundation, either version 2 of that License or (at your option) any + * later version. + * + * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + +/****************************************************************************** + @File fm.c + + @Description FM driver routines implementation. +*//***************************************************************************/ +#include "std_ext.h" +#include "error_ext.h" +#include "xx_ext.h" +#include "string_ext.h" +#include "sprint_ext.h" +#include "debug_ext.h" +#include "fm_muram_ext.h" +#include <linux/math64.h> + +#include "fm_common.h" +#include "fm_ipc.h" +#include "fm.h" +#ifndef CONFIG_FMAN_ARM +#include <linux/fsl/svr.h> +#endif +#include "fsl_fman.h" + + +/****************************************/ +/* static functions */ +/****************************************/ + +static volatile bool blockingFlag = FALSE; +static void IpcMsgCompletionCB(t_Handle h_Fm, + uint8_t *p_Msg, + uint8_t *p_Reply, + uint32_t replyLength, + t_Error status) +{ + UNUSED(h_Fm);UNUSED(p_Msg);UNUSED(p_Reply);UNUSED(replyLength);UNUSED(status); + blockingFlag = FALSE; +} + +static void FreeInitResources(t_Fm *p_Fm) +{ + if (p_Fm->camBaseAddr) + FM_MURAM_FreeMem(p_Fm->h_FmMuram, UINT_TO_PTR(p_Fm->camBaseAddr)); + if (p_Fm->fifoBaseAddr) + FM_MURAM_FreeMem(p_Fm->h_FmMuram, UINT_TO_PTR(p_Fm->fifoBaseAddr)); + if (p_Fm->resAddr) + FM_MURAM_FreeMem(p_Fm->h_FmMuram, UINT_TO_PTR(p_Fm->resAddr)); +} + +static bool IsFmanCtrlCodeLoaded(t_Fm *p_Fm) +{ + t_FMIramRegs *p_Iram; + + ASSERT_COND(p_Fm); + p_Iram = (t_FMIramRegs *)UINT_TO_PTR(p_Fm->baseAddr + FM_MM_IMEM); + + return (bool)!!(GET_UINT32(p_Iram->iready) & IRAM_READY); +} + +static t_Error CheckFmParameters(t_Fm *p_Fm) +{ + if (IsFmanCtrlCodeLoaded(p_Fm) && !p_Fm->resetOnInit) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("Old FMan CTRL code is loaded; FM must be reset!")); +#if (DPAA_VERSION < 11) + if (!p_Fm->p_FmDriverParam->dma_axi_dbg_num_of_beats || + (p_Fm->p_FmDriverParam->dma_axi_dbg_num_of_beats > DMA_MODE_MAX_AXI_DBG_NUM_OF_BEATS)) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, + ("axiDbgNumOfBeats has to be in the range 1 - %d", DMA_MODE_MAX_AXI_DBG_NUM_OF_BEATS)); +#endif /* (DPAA_VERSION < 11) */ + if (p_Fm->p_FmDriverParam->dma_cam_num_of_entries % DMA_CAM_UNITS) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("dma_cam_num_of_entries has to be divisble by %d", DMA_CAM_UNITS)); +// if (!p_Fm->p_FmDriverParam->dma_cam_num_of_entries || (p_Fm->p_FmDriverParam->dma_cam_num_of_entries > DMA_MODE_MAX_CAM_NUM_OF_ENTRIES)) +// RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("dma_cam_num_of_entries has to be in the range 1 - %d", DMA_MODE_MAX_CAM_NUM_OF_ENTRIES)); + if (p_Fm->p_FmDriverParam->dma_comm_qtsh_asrt_emer > DMA_THRESH_MAX_COMMQ) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("dma_comm_qtsh_asrt_emer can not be larger than %d", DMA_THRESH_MAX_COMMQ)); + if (p_Fm->p_FmDriverParam->dma_comm_qtsh_clr_emer > DMA_THRESH_MAX_COMMQ) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("dma_comm_qtsh_clr_emer can not be larger than %d", DMA_THRESH_MAX_COMMQ)); + if (p_Fm->p_FmDriverParam->dma_comm_qtsh_clr_emer >= p_Fm->p_FmDriverParam->dma_comm_qtsh_asrt_emer) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("dma_comm_qtsh_clr_emer must be smaller than dma_comm_qtsh_asrt_emer")); +#if (DPAA_VERSION < 11) + if (p_Fm->p_FmDriverParam->dma_read_buf_tsh_asrt_emer > DMA_THRESH_MAX_BUF) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("dma_read_buf_tsh_asrt_emer can not be larger than %d", DMA_THRESH_MAX_BUF)); + if (p_Fm->p_FmDriverParam->dma_read_buf_tsh_clr_emer > DMA_THRESH_MAX_BUF) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("dma_read_buf_tsh_clr_emer can not be larger than %d", DMA_THRESH_MAX_BUF)); + if (p_Fm->p_FmDriverParam->dma_read_buf_tsh_clr_emer >= p_Fm->p_FmDriverParam->dma_read_buf_tsh_asrt_emer) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("dma_read_buf_tsh_clr_emer must be smaller than dma_read_buf_tsh_asrt_emer")); + if (p_Fm->p_FmDriverParam->dma_write_buf_tsh_asrt_emer > DMA_THRESH_MAX_BUF) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("dma_write_buf_tsh_asrt_emer can not be larger than %d", DMA_THRESH_MAX_BUF)); + if (p_Fm->p_FmDriverParam->dma_write_buf_tsh_clr_emer > DMA_THRESH_MAX_BUF) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("dma_write_buf_tsh_clr_emer can not be larger than %d", DMA_THRESH_MAX_BUF)); + if (p_Fm->p_FmDriverParam->dma_write_buf_tsh_clr_emer >= p_Fm->p_FmDriverParam->dma_write_buf_tsh_asrt_emer) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("dma_write_buf_tsh_clr_emer must be smaller than dma_write_buf_tsh_asrt_emer")); +#else /* (DPAA_VERSION >= 11) */ + if ((p_Fm->p_FmDriverParam->dma_dbg_cnt_mode == E_FMAN_DMA_DBG_CNT_INT_READ_EM)|| + (p_Fm->p_FmDriverParam->dma_dbg_cnt_mode == E_FMAN_DMA_DBG_CNT_INT_WRITE_EM) || + (p_Fm->p_FmDriverParam->dma_dbg_cnt_mode == E_FMAN_DMA_DBG_CNT_RAW_WAR_PROT)) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("dma_dbg_cnt_mode value not supported by this integration.")); + if ((p_Fm->p_FmDriverParam->dma_emergency_bus_select == FM_DMA_MURAM_READ_EMERGENCY)|| + (p_Fm->p_FmDriverParam->dma_emergency_bus_select == FM_DMA_MURAM_WRITE_EMERGENCY)) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("emergencyBusSelect value not supported by this integration.")); + if (p_Fm->p_FmDriverParam->dma_stop_on_bus_error) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("dma_stop_on_bus_error not supported by this integration.")); +#ifdef FM_AID_MODE_NO_TNUM_SW005 + if (p_Fm->p_FmDriverParam->dma_aid_mode != E_FMAN_DMA_AID_OUT_PORT_ID) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("dma_aid_mode not supported by this integration.")); +#endif /* FM_AID_MODE_NO_TNUM_SW005 */ + if (p_Fm->p_FmDriverParam->dma_axi_dbg_num_of_beats) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("dma_axi_dbg_num_of_beats not supported by this integration.")); +#endif /* (DPAA_VERSION < 11) */ + + if (!p_Fm->p_FmStateStruct->fmClkFreq) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("fmClkFreq must be set.")); + if (USEC_TO_CLK(p_Fm->p_FmDriverParam->dma_watchdog, p_Fm->p_FmStateStruct->fmClkFreq) > DMA_MAX_WATCHDOG) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, + ("dma_watchdog depends on FM clock. dma_watchdog(in microseconds) * clk (in Mhz), may not exceed 0x08x", DMA_MAX_WATCHDOG)); + +#if (DPAA_VERSION >= 11) + if ((p_Fm->partVSPBase + p_Fm->partNumOfVSPs) > FM_VSP_MAX_NUM_OF_ENTRIES) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("partVSPBase+partNumOfVSPs out of range!!!")); +#endif /* (DPAA_VERSION >= 11) */ + + if (p_Fm->p_FmStateStruct->totalFifoSize % BMI_FIFO_UNITS) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("totalFifoSize number has to be divisible by %d", BMI_FIFO_UNITS)); + if (!p_Fm->p_FmStateStruct->totalFifoSize || + (p_Fm->p_FmStateStruct->totalFifoSize > BMI_MAX_FIFO_SIZE)) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, + ("totalFifoSize (currently defined as %d) has to be in the range of 256 to %d", + p_Fm->p_FmStateStruct->totalFifoSize, + BMI_MAX_FIFO_SIZE)); + if (!p_Fm->p_FmStateStruct->totalNumOfTasks || + (p_Fm->p_FmStateStruct->totalNumOfTasks > BMI_MAX_NUM_OF_TASKS)) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("totalNumOfTasks number has to be in the range 1 - %d", BMI_MAX_NUM_OF_TASKS)); + +#ifdef FM_HAS_TOTAL_DMAS + if (!p_Fm->p_FmStateStruct->maxNumOfOpenDmas || + (p_Fm->p_FmStateStruct->maxNumOfOpenDmas > BMI_MAX_NUM_OF_DMAS)) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("maxNumOfOpenDmas number has to be in the range 1 - %d", BMI_MAX_NUM_OF_DMAS)); +#endif /* FM_HAS_TOTAL_DMAS */ + + if (p_Fm->p_FmDriverParam->disp_limit_tsh > FPM_MAX_DISP_LIMIT) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("disp_limit_tsh can't be greater than %d", FPM_MAX_DISP_LIMIT)); + + if (!p_Fm->f_Exception) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("Exceptions callback not provided")); + if (!p_Fm->f_BusError) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("Exceptions callback not provided")); + +#ifdef FM_NO_WATCHDOG + if ((p_Fm->p_FmStateStruct->revInfo.majorRev == 2) && + (p_Fm->p_FmDriverParam->dma_watchdog)) + RETURN_ERROR(MAJOR, E_NOT_SUPPORTED, ("watchdog!")); +#endif /* FM_NO_WATCHDOG */ + +#ifdef FM_ECC_HALT_NO_SYNC_ERRATA_10GMAC_A008 + if ((p_Fm->p_FmStateStruct->revInfo.majorRev < 6) && + (p_Fm->p_FmDriverParam->halt_on_unrecov_ecc_err)) + RETURN_ERROR(MAJOR, E_NOT_SUPPORTED, ("HaltOnEccError!")); +#endif /* FM_ECC_HALT_NO_SYNC_ERRATA_10GMAC_A008 */ + +#ifdef FM_NO_TNUM_AGING + if ((p_Fm->p_FmStateStruct->revInfo.majorRev != 4) && + (p_Fm->p_FmStateStruct->revInfo.majorRev < 6)) + if (p_Fm->p_FmDriverParam->tnum_aging_period) + RETURN_ERROR(MAJOR, E_NOT_SUPPORTED, ("Tnum aging!")); +#endif /* FM_NO_TNUM_AGING */ + + /* check that user did not set revision-dependent exceptions */ +#ifdef FM_NO_DISPATCH_RAM_ECC + if ((p_Fm->p_FmStateStruct->revInfo.majorRev != 4) && + (p_Fm->p_FmStateStruct->revInfo.majorRev < 6)) + if (p_Fm->userSetExceptions & FM_EX_BMI_DISPATCH_RAM_ECC) + RETURN_ERROR(MAJOR, E_NOT_SUPPORTED, ("exception e_FM_EX_BMI_DISPATCH_RAM_ECC!")); +#endif /* FM_NO_DISPATCH_RAM_ECC */ + +#ifdef FM_QMI_NO_ECC_EXCEPTIONS + if (p_Fm->p_FmStateStruct->revInfo.majorRev == 4) + if (p_Fm->userSetExceptions & (FM_EX_QMI_SINGLE_ECC | FM_EX_QMI_DOUBLE_ECC)) + RETURN_ERROR(MAJOR, E_NOT_SUPPORTED, ("exception e_FM_EX_QMI_SINGLE_ECC/e_FM_EX_QMI_DOUBLE_ECC!")); +#endif /* FM_QMI_NO_ECC_EXCEPTIONS */ + +#ifdef FM_QMI_NO_SINGLE_ECC_EXCEPTION + if (p_Fm->p_FmStateStruct->revInfo.majorRev >= 6) + if (p_Fm->userSetExceptions & FM_EX_QMI_SINGLE_ECC) + RETURN_ERROR(MAJOR, E_NOT_SUPPORTED, ("exception e_FM_EX_QMI_SINGLE_ECC!")); +#endif /* FM_QMI_NO_SINGLE_ECC_EXCEPTION */ + + return E_OK; +} + + +static void SendIpcIsr(t_Fm *p_Fm, uint32_t macEvent, uint32_t pendingReg) +{ + ASSERT_COND(p_Fm->guestId == NCSW_MASTER_ID); + + if (p_Fm->intrMng[macEvent].guestId == NCSW_MASTER_ID) + p_Fm->intrMng[macEvent].f_Isr(p_Fm->intrMng[macEvent].h_SrcHandle); + + /* If the MAC is running on guest-partition and we have IPC session with it, + we inform him about the event through IPC; otherwise, we ignore the event. */ + else if (p_Fm->h_IpcSessions[p_Fm->intrMng[macEvent].guestId]) + { + t_Error err; + t_FmIpcIsr fmIpcIsr; + t_FmIpcMsg msg; + + memset(&msg, 0, sizeof(msg)); + msg.msgId = FM_GUEST_ISR; + fmIpcIsr.pendingReg = pendingReg; + fmIpcIsr.boolErr = FALSE; + memcpy(msg.msgBody, &fmIpcIsr, sizeof(fmIpcIsr)); + err = XX_IpcSendMessage(p_Fm->h_IpcSessions[p_Fm->intrMng[macEvent].guestId], + (uint8_t*)&msg, + sizeof(msg.msgId) + sizeof(fmIpcIsr), + NULL, + NULL, + NULL, + NULL); + if (err != E_OK) + REPORT_ERROR(MINOR, err, NO_MSG); + } + else + DBG(TRACE, ("FM Guest mode, without IPC - can't call ISR!")); +} + +static void BmiErrEvent(t_Fm *p_Fm) +{ + uint32_t event; + struct fman_bmi_regs *bmi_rg = p_Fm->p_FmBmiRegs; + + + event = fman_get_bmi_err_event(bmi_rg); + + if (event & BMI_ERR_INTR_EN_STORAGE_PROFILE_ECC) + p_Fm->f_Exception(p_Fm->h_App,e_FM_EX_BMI_STORAGE_PROFILE_ECC); + if (event & BMI_ERR_INTR_EN_LIST_RAM_ECC) + p_Fm->f_Exception(p_Fm->h_App,e_FM_EX_BMI_LIST_RAM_ECC); + if (event & BMI_ERR_INTR_EN_STATISTICS_RAM_ECC) + p_Fm->f_Exception(p_Fm->h_App,e_FM_EX_BMI_STATISTICS_RAM_ECC); + if (event & BMI_ERR_INTR_EN_DISPATCH_RAM_ECC) + p_Fm->f_Exception(p_Fm->h_App,e_FM_EX_BMI_DISPATCH_RAM_ECC); +} + +static void QmiErrEvent(t_Fm *p_Fm) +{ + uint32_t event; + struct fman_qmi_regs *qmi_rg = p_Fm->p_FmQmiRegs; + + event = fman_get_qmi_err_event(qmi_rg); + + if (event & QMI_ERR_INTR_EN_DOUBLE_ECC) + p_Fm->f_Exception(p_Fm->h_App,e_FM_EX_QMI_DOUBLE_ECC); + if (event & QMI_ERR_INTR_EN_DEQ_FROM_DEF) + p_Fm->f_Exception(p_Fm->h_App,e_FM_EX_QMI_DEQ_FROM_UNKNOWN_PORTID); +} + +static void DmaErrEvent(t_Fm *p_Fm) +{ + uint32_t status, com_id; + uint8_t tnum; + uint8_t hardwarePortId; + uint8_t relativePortId; + uint16_t liodn; + struct fman_dma_regs *dma_rg = p_Fm->p_FmDmaRegs; + + status = fman_get_dma_err_event(dma_rg); + + if (status & DMA_STATUS_BUS_ERR) + { + com_id = fman_get_dma_com_id(dma_rg); + hardwarePortId = (uint8_t)(((com_id & DMA_TRANSFER_PORTID_MASK) >> DMA_TRANSFER_PORTID_SHIFT)); + ASSERT_COND(IN_RANGE(1, hardwarePortId, 63)); + HW_PORT_ID_TO_SW_PORT_ID(relativePortId, hardwarePortId); + tnum = (uint8_t)((com_id & DMA_TRANSFER_TNUM_MASK) >> DMA_TRANSFER_TNUM_SHIFT); + liodn = (uint16_t)(com_id & DMA_TRANSFER_LIODN_MASK); + ASSERT_COND(p_Fm->p_FmStateStruct->portsTypes[hardwarePortId] != e_FM_PORT_TYPE_DUMMY); + p_Fm->f_BusError(p_Fm->h_App, + p_Fm->p_FmStateStruct->portsTypes[hardwarePortId], + relativePortId, + fman_get_dma_addr(dma_rg), + tnum, + liodn); + } + if (status & DMA_STATUS_FM_SPDAT_ECC) + p_Fm->f_Exception(p_Fm->h_App, e_FM_EX_DMA_SINGLE_PORT_ECC); + if (status & DMA_STATUS_READ_ECC) + p_Fm->f_Exception(p_Fm->h_App, e_FM_EX_DMA_READ_ECC); + if (status & DMA_STATUS_SYSTEM_WRITE_ECC) + p_Fm->f_Exception(p_Fm->h_App, e_FM_EX_DMA_SYSTEM_WRITE_ECC); + if (status & DMA_STATUS_FM_WRITE_ECC) + p_Fm->f_Exception(p_Fm->h_App, e_FM_EX_DMA_FM_WRITE_ECC); + } + +static void FpmErrEvent(t_Fm *p_Fm) +{ + uint32_t event; + struct fman_fpm_regs *fpm_rg = p_Fm->p_FmFpmRegs; + + event = fman_get_fpm_err_event(fpm_rg); + + if ((event & FPM_EV_MASK_DOUBLE_ECC) && (event & FPM_EV_MASK_DOUBLE_ECC_EN)) + p_Fm->f_Exception(p_Fm->h_App,e_FM_EX_FPM_DOUBLE_ECC); + if ((event & FPM_EV_MASK_STALL) && (event & FPM_EV_MASK_STALL_EN)) + p_Fm->f_Exception(p_Fm->h_App,e_FM_EX_FPM_STALL_ON_TASKS); + if ((event & FPM_EV_MASK_SINGLE_ECC) && (event & FPM_EV_MASK_SINGLE_ECC_EN)) + p_Fm->f_Exception(p_Fm->h_App,e_FM_EX_FPM_SINGLE_ECC); +} + +static void MuramErrIntr(t_Fm *p_Fm) +{ + uint32_t event; + struct fman_fpm_regs *fpm_rg = p_Fm->p_FmFpmRegs; + + event = fman_get_muram_err_event(fpm_rg); + + if (event & FPM_RAM_MURAM_ECC) + p_Fm->f_Exception(p_Fm->h_App, e_FM_EX_MURAM_ECC); +} + +static void IramErrIntr(t_Fm *p_Fm) +{ + uint32_t event; + struct fman_fpm_regs *fpm_rg = p_Fm->p_FmFpmRegs; + + event = fman_get_iram_err_event(fpm_rg); + + if (event & FPM_RAM_IRAM_ECC) + p_Fm->f_Exception(p_Fm->h_App, e_FM_EX_IRAM_ECC); +} + +static void QmiEvent(t_Fm *p_Fm) +{ + uint32_t event; + struct fman_qmi_regs *qmi_rg = p_Fm->p_FmQmiRegs; + + event = fman_get_qmi_event(qmi_rg); + + if (event & QMI_INTR_EN_SINGLE_ECC) + p_Fm->f_Exception(p_Fm->h_App,e_FM_EX_QMI_SINGLE_ECC); +} + +static void UnimplementedIsr(t_Handle h_Arg) +{ + UNUSED(h_Arg); + + REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Unimplemented ISR!")); +} + +static void UnimplementedFmanCtrlIsr(t_Handle h_Arg, uint32_t event) +{ + UNUSED(h_Arg); UNUSED(event); + + REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Unimplemented FmCtl ISR!")); +} + +static void EnableTimeStamp(t_Fm *p_Fm) +{ + struct fman_fpm_regs *fpm_rg = p_Fm->p_FmFpmRegs; + + ASSERT_COND(p_Fm->p_FmStateStruct); + ASSERT_COND(p_Fm->p_FmStateStruct->count1MicroBit); + + fman_enable_time_stamp(fpm_rg, p_Fm->p_FmStateStruct->count1MicroBit, p_Fm->p_FmStateStruct->fmClkFreq); + + p_Fm->p_FmStateStruct->enabledTimeStamp = TRUE; +} + +static t_Error ClearIRam(t_Fm *p_Fm) +{ + t_FMIramRegs *p_Iram; + int i; + int iram_size; + + ASSERT_COND(p_Fm); + p_Iram = (t_FMIramRegs *)UINT_TO_PTR(p_Fm->baseAddr + FM_MM_IMEM); + iram_size = FM_IRAM_SIZE(p_Fm->p_FmStateStruct->revInfo.majorRev,p_Fm->p_FmStateStruct->revInfo.minorRev); + + /* Enable the auto-increment */ + WRITE_UINT32(p_Iram->iadd, IRAM_IADD_AIE); + while (GET_UINT32(p_Iram->iadd) != IRAM_IADD_AIE) ; + + for (i=0; i < (iram_size/4); i++) + WRITE_UINT32(p_Iram->idata, 0xffffffff); + + WRITE_UINT32(p_Iram->iadd, iram_size - 4); + CORE_MemoryBarrier(); + while (GET_UINT32(p_Iram->idata) != 0xffffffff) ; + + return E_OK; +} + +static t_Error LoadFmanCtrlCode(t_Fm *p_Fm) +{ + t_FMIramRegs *p_Iram; + int i; + uint32_t tmp; + uint8_t compTo16; + + ASSERT_COND(p_Fm); + p_Iram = (t_FMIramRegs *)UINT_TO_PTR(p_Fm->baseAddr + FM_MM_IMEM); + + /* Enable the auto-increment */ + WRITE_UINT32(p_Iram->iadd, IRAM_IADD_AIE); + while (GET_UINT32(p_Iram->iadd) != IRAM_IADD_AIE) ; + + for (i=0; i < (p_Fm->firmware.size / 4); i++) + WRITE_UINT32(p_Iram->idata, p_Fm->firmware.p_Code[i]); + + compTo16 = (uint8_t)(p_Fm->firmware.size % 16); + if (compTo16) + for (i=0; i < ((16-compTo16) / 4); i++) + WRITE_UINT32(p_Iram->idata, 0xffffffff); + + WRITE_UINT32(p_Iram->iadd,p_Fm->firmware.size-4); + while (GET_UINT32(p_Iram->iadd) != (p_Fm->firmware.size-4)) ; + + /* verify that writing has completed */ + while (GET_UINT32(p_Iram->idata) != p_Fm->firmware.p_Code[(p_Fm->firmware.size / 4)-1]) ; + + if (p_Fm->fwVerify) + { + WRITE_UINT32(p_Iram->iadd, IRAM_IADD_AIE); + while (GET_UINT32(p_Iram->iadd) != IRAM_IADD_AIE) ; + for (i=0; i < (p_Fm->firmware.size / 4); i++) + { + tmp = GET_UINT32(p_Iram->idata); + if (tmp != p_Fm->firmware.p_Code[i]) + RETURN_ERROR(MAJOR, E_WRITE_FAILED, + ("UCode write error : write 0x%x, read 0x%x", + p_Fm->firmware.p_Code[i],tmp)); + } + WRITE_UINT32(p_Iram->iadd, 0x0); + } + + /* Enable patch from IRAM */ + WRITE_UINT32(p_Iram->iready, IRAM_READY); + XX_UDelay(1000); + + DBG(INFO, ("FMan-Controller code (ver %d.%d.%d) loaded to IRAM.", + ((uint16_t *)p_Fm->firmware.p_Code)[2], + ((uint8_t *)p_Fm->firmware.p_Code)[6], + ((uint8_t *)p_Fm->firmware.p_Code)[7])); + + return E_OK; +} + +#ifdef FM_UCODE_NOT_RESET_ERRATA_BUGZILLA6173 +static t_Error FwNotResetErratumBugzilla6173WA(t_Fm *p_Fm) +{ + t_FMIramRegs *p_Iram = (t_FMIramRegs *)UINT_TO_PTR(p_Fm->baseAddr + FM_MM_IMEM); + uint32_t tmpReg; + uint32_t savedSpliodn[63]; + + /* write to IRAM first location the debug instruction */ + WRITE_UINT32(p_Iram->iadd, 0); + while (GET_UINT32(p_Iram->iadd) != 0) ; + WRITE_UINT32(p_Iram->idata, FM_FW_DEBUG_INSTRUCTION); + + WRITE_UINT32(p_Iram->iadd, 0); + while (GET_UINT32(p_Iram->iadd) != 0) ; + while (GET_UINT32(p_Iram->idata) != FM_FW_DEBUG_INSTRUCTION) ; + + /* Enable patch from IRAM */ + WRITE_UINT32(p_Iram->iready, IRAM_READY); + CORE_MemoryBarrier(); + XX_UDelay(100); + IO2MemCpy32((uint8_t *)savedSpliodn, + (uint8_t *)p_Fm->p_FmBmiRegs->fmbm_spliodn, + 63*sizeof(uint32_t)); + + /* reset FMAN */ + WRITE_UINT32(p_Fm->p_FmFpmRegs->fm_rstc, FPM_RSTC_FM_RESET); + CORE_MemoryBarrier(); + XX_UDelay(100); + + /* verify breakpoint debug status register */ + tmpReg = GET_UINT32(*(uint32_t *)UINT_TO_PTR(p_Fm->baseAddr + FM_DEBUG_STATUS_REGISTER_OFFSET)); + if (!tmpReg) + REPORT_ERROR(MAJOR, E_INVALID_STATE, ("Invalid debug status register value is '0'")); + + /*************************************/ + /* Load FMan-Controller code to IRAM */ + /*************************************/ + ClearIRam(p_Fm); + if (p_Fm->firmware.p_Code && + (LoadFmanCtrlCode(p_Fm) != E_OK)) + RETURN_ERROR(MAJOR, E_INVALID_STATE, NO_MSG); + XX_UDelay(100); + + /* reset FMAN again to start the microcode */ + WRITE_UINT32(p_Fm->p_FmFpmRegs->fm_rstc, FPM_RSTC_FM_RESET); + CORE_MemoryBarrier(); + XX_UDelay(100); + Mem2IOCpy32((uint8_t *)p_Fm->p_FmBmiRegs->fmbm_spliodn, + (uint8_t *)savedSpliodn, + 63*sizeof(uint32_t)); + + if (fman_is_qmi_halt_not_busy_state(p_Fm->p_FmQmiRegs)) + { + fman_resume(p_Fm->p_FmFpmRegs); + CORE_MemoryBarrier(); + XX_UDelay(100); + } + + return E_OK; +} +#endif /* FM_UCODE_NOT_RESET_ERRATA_BUGZILLA6173 */ + +static void GuestErrorIsr(t_Fm *p_Fm, uint32_t pending) +{ +#define FM_G_CALL_1G_MAC_ERR_ISR(_id) \ +do { \ + p_Fm->intrMng[(e_FmInterModuleEvent)(e_FM_EV_ERR_1G_MAC0+_id)].f_Isr(p_Fm->intrMng[(e_FmInterModuleEvent)(e_FM_EV_ERR_1G_MAC0+_id)].h_SrcHandle);\ +} while (0) +#define FM_G_CALL_10G_MAC_ERR_ISR(_id) \ +do { \ + p_Fm->intrMng[(e_FmInterModuleEvent)(e_FM_EV_ERR_10G_MAC0+_id)].f_Isr(p_Fm->intrMng[(e_FmInterModuleEvent)(e_FM_EV_ERR_10G_MAC0+_id)].h_SrcHandle);\ +} while (0) + + /* error interrupts */ + if (pending & ERR_INTR_EN_1G_MAC0) + FM_G_CALL_1G_MAC_ERR_ISR(0); + if (pending & ERR_INTR_EN_1G_MAC1) + FM_G_CALL_1G_MAC_ERR_ISR(1); + if (pending & ERR_INTR_EN_1G_MAC2) + FM_G_CALL_1G_MAC_ERR_ISR(2); + if (pending & ERR_INTR_EN_1G_MAC3) + FM_G_CALL_1G_MAC_ERR_ISR(3); + if (pending & ERR_INTR_EN_1G_MAC4) + FM_G_CALL_1G_MAC_ERR_ISR(4); + if (pending & ERR_INTR_EN_1G_MAC5) + FM_G_CALL_1G_MAC_ERR_ISR(5); + if (pending & ERR_INTR_EN_1G_MAC6) + FM_G_CALL_1G_MAC_ERR_ISR(6); + if (pending & ERR_INTR_EN_1G_MAC7) + FM_G_CALL_1G_MAC_ERR_ISR(7); + if (pending & ERR_INTR_EN_10G_MAC0) + FM_G_CALL_10G_MAC_ERR_ISR(0); + if (pending & ERR_INTR_EN_10G_MAC1) + FM_G_CALL_10G_MAC_ERR_ISR(1); +} + +static void GuestEventIsr(t_Fm *p_Fm, uint32_t pending) +{ +#define FM_G_CALL_1G_MAC_ISR(_id) \ +do { \ + p_Fm->intrMng[(e_FmInterModuleEvent)(e_FM_EV_1G_MAC0+_id)].f_Isr(p_Fm->intrMng[(e_FmInterModuleEvent)(e_FM_EV_1G_MAC0+_id)].h_SrcHandle);\ +} while (0) +#define FM_G_CALL_10G_MAC_ISR(_id) \ +do { \ + p_Fm->intrMng[(e_FmInterModuleEvent)(e_FM_EV_10G_MAC0+_id)].f_Isr(p_Fm->intrMng[(e_FmInterModuleEvent)(e_FM_EV_10G_MAC0+_id)].h_SrcHandle);\ +} while (0) + + if (pending & INTR_EN_1G_MAC0) + FM_G_CALL_1G_MAC_ISR(0); + if (pending & INTR_EN_1G_MAC1) + FM_G_CALL_1G_MAC_ISR(1); + if (pending & INTR_EN_1G_MAC2) + FM_G_CALL_1G_MAC_ISR(2); + if (pending & INTR_EN_1G_MAC3) + FM_G_CALL_1G_MAC_ISR(3); + if (pending & INTR_EN_1G_MAC4) + FM_G_CALL_1G_MAC_ISR(4); + if (pending & INTR_EN_1G_MAC5) + FM_G_CALL_1G_MAC_ISR(5); + if (pending & INTR_EN_1G_MAC6) + FM_G_CALL_1G_MAC_ISR(6); + if (pending & INTR_EN_1G_MAC7) + FM_G_CALL_1G_MAC_ISR(7); + if (pending & INTR_EN_10G_MAC0) + FM_G_CALL_10G_MAC_ISR(0); + if (pending & INTR_EN_10G_MAC1) + FM_G_CALL_10G_MAC_ISR(1); +#ifdef CONFIG_FSL_SDK_FMAN_RTC_API + if (pending & INTR_EN_TMR) + p_Fm->intrMng[e_FM_EV_TMR].f_Isr(p_Fm->intrMng[e_FM_EV_TMR].h_SrcHandle); +#endif +} + +#if (DPAA_VERSION >= 11) +static t_Error SetVSPWindow(t_Handle h_Fm, + uint8_t hardwarePortId, + uint8_t baseStorageProfile, + uint8_t log2NumOfProfiles) +{ + t_Fm *p_Fm = (t_Fm *)h_Fm; + + ASSERT_COND(h_Fm); + ASSERT_COND(IN_RANGE(1, hardwarePortId, 63)); + + if ((p_Fm->guestId != NCSW_MASTER_ID) && + !p_Fm->p_FmBmiRegs && + p_Fm->h_IpcSessions[0]) + { + t_FmIpcVspSetPortWindow fmIpcVspSetPortWindow; + t_FmIpcMsg msg; + t_Error err = E_OK; + + memset(&msg, 0, sizeof(msg)); + memset(&fmIpcVspSetPortWindow, 0, sizeof(t_FmIpcVspSetPortWindow)); + fmIpcVspSetPortWindow.hardwarePortId = hardwarePortId; + fmIpcVspSetPortWindow.baseStorageProfile = baseStorageProfile; + fmIpcVspSetPortWindow.log2NumOfProfiles = log2NumOfProfiles; + msg.msgId = FM_VSP_SET_PORT_WINDOW; + memcpy(msg.msgBody, &fmIpcVspSetPortWindow, sizeof(t_FmIpcVspSetPortWindow)); + + err = XX_IpcSendMessage(p_Fm->h_IpcSessions[0], + (uint8_t*)&msg, + sizeof(msg.msgId), + NULL, + NULL, + NULL, + NULL); + if (err != E_OK) + RETURN_ERROR(MINOR, err, NO_MSG); + return E_OK; + } + else if (!p_Fm->p_FmBmiRegs) + RETURN_ERROR(MINOR, E_NOT_SUPPORTED, + ("Either IPC or 'baseAddress' is required!")); + + fman_set_vsp_window(p_Fm->p_FmBmiRegs, + hardwarePortId, + baseStorageProfile, + log2NumOfProfiles); + + return E_OK; +} + +static uint8_t AllocVSPsForPartition(t_Handle h_Fm, uint8_t base, uint8_t numOfProfiles, uint8_t guestId) +{ + t_Fm *p_Fm = (t_Fm *)h_Fm; + uint8_t profilesFound = 0; + int i = 0; + uint32_t intFlags; + + if (!numOfProfiles) + return E_OK; + + if ((numOfProfiles > FM_VSP_MAX_NUM_OF_ENTRIES) || + (base + numOfProfiles > FM_VSP_MAX_NUM_OF_ENTRIES)) + return (uint8_t)ILLEGAL_BASE; + + if (p_Fm->h_IpcSessions[0]) + { + t_FmIpcResourceAllocParams ipcAllocParams; + t_FmIpcMsg msg; + t_FmIpcReply reply; + t_Error err; + uint32_t replyLength; + + memset(&msg, 0, sizeof(msg)); + memset(&reply, 0, sizeof(reply)); + memset(&ipcAllocParams, 0, sizeof(t_FmIpcResourceAllocParams)); + ipcAllocParams.guestId = p_Fm->guestId; + ipcAllocParams.num = p_Fm->partNumOfVSPs; + ipcAllocParams.base = p_Fm->partVSPBase; + msg.msgId = FM_VSP_ALLOC; + memcpy(msg.msgBody, &ipcAllocParams, sizeof(t_FmIpcResourceAllocParams)); + replyLength = sizeof(uint32_t) + sizeof(uint8_t); + err = XX_IpcSendMessage(p_Fm->h_IpcSessions[0], + (uint8_t*)&msg, + sizeof(msg.msgId) + sizeof(t_FmIpcResourceAllocParams), + (uint8_t*)&reply, + &replyLength, + NULL, + NULL); + if ((err != E_OK) || + (replyLength != (sizeof(uint32_t) + sizeof(uint8_t)))) + RETURN_ERROR(MAJOR, err, NO_MSG); + else + memcpy((uint8_t*)&p_Fm->partVSPBase, reply.replyBody, sizeof(uint8_t)); + if (p_Fm->partVSPBase == (uint8_t)(ILLEGAL_BASE)) + RETURN_ERROR(MAJOR, err, NO_MSG); + } + if (p_Fm->guestId != NCSW_MASTER_ID) + { + DBG(WARNING, ("FM Guest mode, without IPC - can't validate VSP range!")); + return (uint8_t)ILLEGAL_BASE; + } + + intFlags = XX_LockIntrSpinlock(p_Fm->h_Spinlock); + for (i = base; i < base + numOfProfiles; i++) + if (p_Fm->p_FmSp->profiles[i].profilesMng.ownerId == (uint8_t)ILLEGAL_BASE) + profilesFound++; + else + break; + + if (profilesFound == numOfProfiles) + for (i = base; i<base + numOfProfiles; i++) + p_Fm->p_FmSp->profiles[i].profilesMng.ownerId = guestId; + else + { + XX_UnlockIntrSpinlock(p_Fm->h_Spinlock, intFlags); + return (uint8_t)ILLEGAL_BASE; + } + XX_UnlockIntrSpinlock(p_Fm->h_Spinlock, intFlags); + + return base; +} + +static void FreeVSPsForPartition(t_Handle h_Fm, uint8_t base, uint8_t numOfProfiles, uint8_t guestId) +{ + t_Fm *p_Fm = (t_Fm *)h_Fm; + int i = 0; + + ASSERT_COND(p_Fm); + + if (p_Fm->h_IpcSessions[0]) + { + t_FmIpcResourceAllocParams ipcAllocParams; + t_FmIpcMsg msg; + t_FmIpcReply reply; + uint32_t replyLength; + t_Error err; + + memset(&msg, 0, sizeof(msg)); + memset(&reply, 0, sizeof(reply)); + memset(&ipcAllocParams, 0, sizeof(t_FmIpcResourceAllocParams)); + ipcAllocParams.guestId = p_Fm->guestId; + ipcAllocParams.num = p_Fm->partNumOfVSPs; + ipcAllocParams.base = p_Fm->partVSPBase; + msg.msgId = FM_VSP_FREE; + memcpy(msg.msgBody, &ipcAllocParams, sizeof(t_FmIpcResourceAllocParams)); + replyLength = sizeof(uint32_t) + sizeof(uint8_t); + err = XX_IpcSendMessage(p_Fm->h_IpcSessions[0], + (uint8_t*)&msg, + sizeof(msg.msgId) + sizeof(t_FmIpcResourceAllocParams), + (uint8_t*)&reply, + &replyLength, + NULL, + NULL); + if (err != E_OK) + REPORT_ERROR(MAJOR, err, NO_MSG); + return; + } + if (p_Fm->guestId != NCSW_MASTER_ID) + { + DBG(WARNING, ("FM Guest mode, without IPC - can't validate VSP range!")); + return; + } + + ASSERT_COND(p_Fm->p_FmSp); + + for (i=base; i<numOfProfiles; i++) + { + if (p_Fm->p_FmSp->profiles[i].profilesMng.ownerId == guestId) + p_Fm->p_FmSp->profiles[i].profilesMng.ownerId = (uint8_t)ILLEGAL_BASE; + else + DBG(WARNING, ("Request for freeing storage profile window which wasn't allocated to this partition")); + } +} +#endif /* (DPAA_VERSION >= 11) */ + +static t_Error FmGuestHandleIpcMsgCB(t_Handle h_Fm, + uint8_t *p_Msg, + uint32_t msgLength, + uint8_t *p_Reply, + uint32_t *p_ReplyLength) +{ + t_Fm *p_Fm = (t_Fm*)h_Fm; + t_FmIpcMsg *p_IpcMsg = (t_FmIpcMsg*)p_Msg; + + UNUSED(p_Reply); + SANITY_CHECK_RETURN_ERROR(p_Fm, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR((msgLength > sizeof(uint32_t)), E_INVALID_VALUE); + +#ifdef DISABLE_SANITY_CHECKS + UNUSED(msgLength); +#endif /* DISABLE_SANITY_CHECKS */ + + ASSERT_COND(p_Msg); + + *p_ReplyLength = 0; + + switch (p_IpcMsg->msgId) + { + case (FM_GUEST_ISR): + { + t_FmIpcIsr ipcIsr; + + memcpy((uint8_t*)&ipcIsr, p_IpcMsg->msgBody, sizeof(t_FmIpcIsr)); + if (ipcIsr.boolErr) + GuestErrorIsr(p_Fm, ipcIsr.pendingReg); + else + GuestEventIsr(p_Fm, ipcIsr.pendingReg); + break; + } + default: + *p_ReplyLength = 0; + RETURN_ERROR(MINOR, E_INVALID_SELECTION, ("command not found!!!")); + } + return E_OK; +} + +static t_Error FmHandleIpcMsgCB(t_Handle h_Fm, + uint8_t *p_Msg, + uint32_t msgLength, + uint8_t *p_Reply, + uint32_t *p_ReplyLength) +{ + t_Error err; + t_Fm *p_Fm = (t_Fm*)h_Fm; + t_FmIpcMsg *p_IpcMsg = (t_FmIpcMsg*)p_Msg; + t_FmIpcReply *p_IpcReply = (t_FmIpcReply*)p_Reply; + + SANITY_CHECK_RETURN_ERROR(p_Fm, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR((msgLength >= sizeof(uint32_t)), E_INVALID_VALUE); + +#ifdef DISABLE_SANITY_CHECKS + UNUSED(msgLength); +#endif /* DISABLE_SANITY_CHECKS */ + + ASSERT_COND(p_IpcMsg); + + memset(p_IpcReply, 0, (sizeof(uint8_t) * FM_IPC_MAX_REPLY_SIZE)); + *p_ReplyLength = 0; + + switch (p_IpcMsg->msgId) + { + case (FM_GET_SET_PORT_PARAMS): + { + t_FmIpcPortInInitParams ipcInitParams; + t_FmInterModulePortInitParams initParams; + t_FmIpcPortOutInitParams ipcOutInitParams; + + memcpy((uint8_t*)&ipcInitParams, p_IpcMsg->msgBody, sizeof(t_FmIpcPortInInitParams)); + initParams.hardwarePortId = ipcInitParams.hardwarePortId; + initParams.portType = (e_FmPortType)ipcInitParams.enumPortType; + initParams.independentMode = (bool)(ipcInitParams.boolIndependentMode); + initParams.liodnOffset = ipcInitParams.liodnOffset; + initParams.numOfTasks = ipcInitParams.numOfTasks; + initParams.numOfExtraTasks = ipcInitParams.numOfExtraTasks; + initParams.numOfOpenDmas = ipcInitParams.numOfOpenDmas; + initParams.numOfExtraOpenDmas = ipcInitParams.numOfExtraOpenDmas; + initParams.sizeOfFifo = ipcInitParams.sizeOfFifo; + initParams.extraSizeOfFifo = ipcInitParams.extraSizeOfFifo; + initParams.deqPipelineDepth = ipcInitParams.deqPipelineDepth; + initParams.maxFrameLength = ipcInitParams.maxFrameLength; + initParams.liodnBase = ipcInitParams.liodnBase; + + p_IpcReply->error = (uint32_t)FmGetSetPortParams(h_Fm, &initParams); + + ipcOutInitParams.ipcPhysAddr.high = initParams.fmMuramPhysBaseAddr.high; + ipcOutInitParams.ipcPhysAddr.low = initParams.fmMuramPhysBaseAddr.low; + ipcOutInitParams.sizeOfFifo = initParams.sizeOfFifo; + ipcOutInitParams.extraSizeOfFifo = initParams.extraSizeOfFifo; + ipcOutInitParams.numOfTasks = initParams.numOfTasks; + ipcOutInitParams.numOfExtraTasks = initParams.numOfExtraTasks; + ipcOutInitParams.numOfOpenDmas = initParams.numOfOpenDmas; + ipcOutInitParams.numOfExtraOpenDmas = initParams.numOfExtraOpenDmas; + memcpy(p_IpcReply->replyBody, (uint8_t*)&ipcOutInitParams, sizeof(ipcOutInitParams)); + *p_ReplyLength = sizeof(uint32_t) + sizeof(t_FmIpcPortOutInitParams); + break; + } + case (FM_SET_SIZE_OF_FIFO): + { + t_FmIpcPortRsrcParams ipcPortRsrcParams; + + memcpy((uint8_t*)&ipcPortRsrcParams, p_IpcMsg->msgBody, sizeof(t_FmIpcPortRsrcParams)); + p_IpcReply->error = (uint32_t)FmSetSizeOfFifo(h_Fm, + ipcPortRsrcParams.hardwarePortId, + &ipcPortRsrcParams.val, + &ipcPortRsrcParams.extra, + (bool)ipcPortRsrcParams.boolInitialConfig); + *p_ReplyLength = sizeof(uint32_t); + break; + } + case (FM_SET_NUM_OF_TASKS): + { + t_FmIpcPortRsrcParams ipcPortRsrcParams; + + memcpy((uint8_t*)&ipcPortRsrcParams, p_IpcMsg->msgBody, sizeof(t_FmIpcPortRsrcParams)); + p_IpcReply->error = (uint32_t)FmSetNumOfTasks(h_Fm, ipcPortRsrcParams.hardwarePortId, + (uint8_t*)&ipcPortRsrcParams.val, + (uint8_t*)&ipcPortRsrcParams.extra, + (bool)ipcPortRsrcParams.boolInitialConfig); + *p_ReplyLength = sizeof(uint32_t); + break; + } + case (FM_SET_NUM_OF_OPEN_DMAS): + { + t_FmIpcPortRsrcParams ipcPortRsrcParams; + + memcpy((uint8_t*)&ipcPortRsrcParams, p_IpcMsg->msgBody, sizeof(t_FmIpcPortRsrcParams)); + p_IpcReply->error = (uint32_t)FmSetNumOfOpenDmas(h_Fm, ipcPortRsrcParams.hardwarePortId, + (uint8_t*)&ipcPortRsrcParams.val, + (uint8_t*)&ipcPortRsrcParams.extra, + (bool)ipcPortRsrcParams.boolInitialConfig); + *p_ReplyLength = sizeof(uint32_t); + break; + } + case (FM_RESUME_STALLED_PORT): + *p_ReplyLength = sizeof(uint32_t); + p_IpcReply->error = (uint32_t)FmResumeStalledPort(h_Fm, p_IpcMsg->msgBody[0]); + break; + case (FM_MASTER_IS_ALIVE): + { + uint8_t guestId = p_IpcMsg->msgBody[0]; + /* build the FM master partition IPC address */ + memset(p_Fm->fmIpcHandlerModuleName[guestId], 0, (sizeof(char)) * MODULE_NAME_SIZE); + if (Sprint (p_Fm->fmIpcHandlerModuleName[guestId], "FM_%d_%d",p_Fm->p_FmStateStruct->fmId, guestId) != (guestId<10 ? 6:7)) + RETURN_ERROR(MAJOR, E_INVALID_STATE, ("Sprint failed")); + p_Fm->h_IpcSessions[guestId] = XX_IpcInitSession(p_Fm->fmIpcHandlerModuleName[guestId], p_Fm->fmModuleName); + if (p_Fm->h_IpcSessions[guestId] == NULL) + RETURN_ERROR(MAJOR, E_NOT_AVAILABLE, ("FM Master IPC session for guest %d", guestId)); + *(uint8_t*)(p_IpcReply->replyBody) = 1; + *p_ReplyLength = sizeof(uint32_t) + sizeof(uint8_t); + break; + } + case (FM_IS_PORT_STALLED): + { + bool tmp; + + p_IpcReply->error = (uint32_t)FmIsPortStalled(h_Fm, p_IpcMsg->msgBody[0], &tmp); + *(uint8_t*)(p_IpcReply->replyBody) = (uint8_t)tmp; + *p_ReplyLength = sizeof(uint32_t) + sizeof(uint8_t); + break; + } + case (FM_RESET_MAC): + { + t_FmIpcMacParams ipcMacParams; + + memcpy((uint8_t*)&ipcMacParams, p_IpcMsg->msgBody, sizeof(t_FmIpcMacParams)); + p_IpcReply->error = (uint32_t)FmResetMac(p_Fm, + (e_FmMacType)(ipcMacParams.enumType), + ipcMacParams.id); + *p_ReplyLength = sizeof(uint32_t); + break; + } + case (FM_SET_MAC_MAX_FRAME): + { + t_FmIpcMacMaxFrameParams ipcMacMaxFrameParams; + + memcpy((uint8_t*)&ipcMacMaxFrameParams, p_IpcMsg->msgBody, sizeof(t_FmIpcMacMaxFrameParams)); + err = FmSetMacMaxFrame(p_Fm, + (e_FmMacType)(ipcMacMaxFrameParams.macParams.enumType), + ipcMacMaxFrameParams.macParams.id, + ipcMacMaxFrameParams.maxFrameLength); + if (err != E_OK) + REPORT_ERROR(MINOR, err, NO_MSG); + break; + } +#if (DPAA_VERSION >= 11) + case (FM_VSP_ALLOC) : + { + t_FmIpcResourceAllocParams ipcAllocParams; + uint8_t vspBase; + memcpy(&ipcAllocParams, p_IpcMsg->msgBody, sizeof(t_FmIpcResourceAllocParams)); + vspBase = AllocVSPsForPartition(h_Fm, (uint8_t)ipcAllocParams.base, (uint8_t)ipcAllocParams.num, ipcAllocParams.guestId); + memcpy(p_IpcReply->replyBody, (uint8_t*)&vspBase, sizeof(uint8_t)); + *p_ReplyLength = sizeof(uint32_t) + sizeof(uint8_t); + break; + } + case (FM_VSP_FREE) : + { + t_FmIpcResourceAllocParams ipcAllocParams; + memcpy(&ipcAllocParams, p_IpcMsg->msgBody, sizeof(t_FmIpcResourceAllocParams)); + FreeVSPsForPartition(h_Fm, (uint8_t)ipcAllocParams.base, (uint8_t)ipcAllocParams.num, ipcAllocParams.guestId); + break; + } + case (FM_VSP_SET_PORT_WINDOW) : + { + t_FmIpcVspSetPortWindow ipcVspSetPortWindow; + memcpy(&ipcVspSetPortWindow, p_IpcMsg->msgBody, sizeof(t_FmIpcVspSetPortWindow)); + err = SetVSPWindow(h_Fm, + ipcVspSetPortWindow.hardwarePortId, + ipcVspSetPortWindow.baseStorageProfile, + ipcVspSetPortWindow.log2NumOfProfiles); + return err; + } + case (FM_SET_CONG_GRP_PFC_PRIO) : + { + t_FmIpcSetCongestionGroupPfcPriority fmIpcSetCongestionGroupPfcPriority; + memcpy(&fmIpcSetCongestionGroupPfcPriority, p_IpcMsg->msgBody, sizeof(t_FmIpcSetCongestionGroupPfcPriority)); + err = FmSetCongestionGroupPFCpriority(h_Fm, + fmIpcSetCongestionGroupPfcPriority.congestionGroupId, + fmIpcSetCongestionGroupPfcPriority.priorityBitMap); + return err; + } +#endif /* (DPAA_VERSION >= 11) */ + + case (FM_FREE_PORT): + { + t_FmInterModulePortFreeParams portParams; + t_FmIpcPortFreeParams ipcPortParams; + + memcpy((uint8_t*)&ipcPortParams, p_IpcMsg->msgBody, sizeof(t_FmIpcPortFreeParams)); + portParams.hardwarePortId = ipcPortParams.hardwarePortId; + portParams.portType = (e_FmPortType)(ipcPortParams.enumPortType); + portParams.deqPipelineDepth = ipcPortParams.deqPipelineDepth; + FmFreePortParams(h_Fm, &portParams); + break; + } + case (FM_REGISTER_INTR): + { + t_FmIpcRegisterIntr ipcRegIntr; + + memcpy((uint8_t*)&ipcRegIntr, p_IpcMsg->msgBody, sizeof(ipcRegIntr)); + p_Fm->intrMng[ipcRegIntr.event].guestId = ipcRegIntr.guestId; + break; + } + case (FM_GET_PARAMS): + { + t_FmIpcParams ipcParams; + + /* Get clock frequency */ + ipcParams.fmClkFreq = p_Fm->p_FmStateStruct->fmClkFreq; + ipcParams.fmMacClkFreq = p_Fm->p_FmStateStruct->fmMacClkFreq; + + fman_get_revision(p_Fm->p_FmFpmRegs,&ipcParams.majorRev,&ipcParams.minorRev); + + memcpy(p_IpcReply->replyBody, (uint8_t*)&ipcParams, sizeof(t_FmIpcParams)); + *p_ReplyLength = sizeof(uint32_t) + sizeof(t_FmIpcParams); + break; + } + case (FM_GET_FMAN_CTRL_CODE_REV): + { + t_FmCtrlCodeRevisionInfo fmanCtrlRevInfo; + t_FmIpcFmanCtrlCodeRevisionInfo ipcRevInfo; + + p_IpcReply->error = (uint32_t)FM_GetFmanCtrlCodeRevision(h_Fm, &fmanCtrlRevInfo); + ipcRevInfo.packageRev = fmanCtrlRevInfo.packageRev; + ipcRevInfo.majorRev = fmanCtrlRevInfo.majorRev; + ipcRevInfo.minorRev = fmanCtrlRevInfo.minorRev; + memcpy(p_IpcReply->replyBody, (uint8_t*)&ipcRevInfo, sizeof(t_FmIpcFmanCtrlCodeRevisionInfo)); + *p_ReplyLength = sizeof(uint32_t) + sizeof(t_FmIpcFmanCtrlCodeRevisionInfo); + break; + } + + case (FM_DMA_STAT): + { + t_FmDmaStatus dmaStatus; + t_FmIpcDmaStatus ipcDmaStatus; + + FM_GetDmaStatus(h_Fm, &dmaStatus); + ipcDmaStatus.boolCmqNotEmpty = (uint8_t)dmaStatus.cmqNotEmpty; + ipcDmaStatus.boolBusError = (uint8_t)dmaStatus.busError; + ipcDmaStatus.boolReadBufEccError = (uint8_t)dmaStatus.readBufEccError; + ipcDmaStatus.boolWriteBufEccSysError = (uint8_t)dmaStatus.writeBufEccSysError; + ipcDmaStatus.boolWriteBufEccFmError = (uint8_t)dmaStatus.writeBufEccFmError; + ipcDmaStatus.boolSinglePortEccError = (uint8_t)dmaStatus.singlePortEccError; + memcpy(p_IpcReply->replyBody, (uint8_t*)&ipcDmaStatus, sizeof(t_FmIpcDmaStatus)); + *p_ReplyLength = sizeof(uint32_t) + sizeof(t_FmIpcDmaStatus); + break; + } + case (FM_ALLOC_FMAN_CTRL_EVENT_REG): + p_IpcReply->error = (uint32_t)FmAllocFmanCtrlEventReg(h_Fm, (uint8_t*)p_IpcReply->replyBody); + *p_ReplyLength = sizeof(uint32_t) + sizeof(uint8_t); + break; + case (FM_FREE_FMAN_CTRL_EVENT_REG): + FmFreeFmanCtrlEventReg(h_Fm, p_IpcMsg->msgBody[0]); + break; + case (FM_GET_TIMESTAMP_SCALE): + { + uint32_t timeStamp = FmGetTimeStampScale(h_Fm); + + memcpy(p_IpcReply->replyBody, (uint8_t*)&timeStamp, sizeof(uint32_t)); + *p_ReplyLength = sizeof(uint32_t) + sizeof(uint32_t); + break; + } + case (FM_GET_COUNTER): + { + e_FmCounters inCounter; + uint32_t outCounter; + + memcpy((uint8_t*)&inCounter, p_IpcMsg->msgBody, sizeof(uint32_t)); + outCounter = FM_GetCounter(h_Fm, inCounter); + memcpy(p_IpcReply->replyBody, (uint8_t*)&outCounter, sizeof(uint32_t)); + *p_ReplyLength = sizeof(uint32_t) + sizeof(uint32_t); + break; + } + case (FM_SET_FMAN_CTRL_EVENTS_ENABLE): + { + t_FmIpcFmanEvents ipcFmanEvents; + + memcpy((uint8_t*)&ipcFmanEvents, p_IpcMsg->msgBody, sizeof(t_FmIpcFmanEvents)); + FmSetFmanCtrlIntr(h_Fm, + ipcFmanEvents.eventRegId, + ipcFmanEvents.enableEvents); + break; + } + case (FM_GET_FMAN_CTRL_EVENTS_ENABLE): + { + uint32_t tmp = FmGetFmanCtrlIntr(h_Fm, p_IpcMsg->msgBody[0]); + + memcpy(p_IpcReply->replyBody, (uint8_t*)&tmp, sizeof(uint32_t)); + *p_ReplyLength = sizeof(uint32_t) + sizeof(uint32_t); + break; + } + case (FM_GET_PHYS_MURAM_BASE): + { + t_FmPhysAddr physAddr; + t_FmIpcPhysAddr ipcPhysAddr; + + FmGetPhysicalMuramBase(h_Fm, &physAddr); + ipcPhysAddr.high = physAddr.high; + ipcPhysAddr.low = physAddr.low; + memcpy(p_IpcReply->replyBody, (uint8_t*)&ipcPhysAddr, sizeof(t_FmIpcPhysAddr)); + *p_ReplyLength = sizeof(uint32_t) + sizeof(t_FmIpcPhysAddr); + break; + } + case (FM_ENABLE_RAM_ECC): + { + if (((err = FM_EnableRamsEcc(h_Fm)) != E_OK) || + ((err = FM_SetException(h_Fm, e_FM_EX_IRAM_ECC, TRUE)) != E_OK) || + ((err = FM_SetException(h_Fm, e_FM_EX_MURAM_ECC, TRUE)) != E_OK)) +#if (!(defined(DEBUG_ERRORS)) || (DEBUG_ERRORS == 0)) + UNUSED(err); +#else + REPORT_ERROR(MINOR, err, NO_MSG); +#endif /* (!(defined(DEBUG_ERRORS)) || (DEBUG_ERRORS == 0)) */ + break; + } + case (FM_DISABLE_RAM_ECC): + { + + if (((err = FM_SetException(h_Fm, e_FM_EX_IRAM_ECC, FALSE)) != E_OK) || + ((err = FM_SetException(h_Fm, e_FM_EX_MURAM_ECC, FALSE)) != E_OK) || + ((err = FM_DisableRamsEcc(h_Fm)) != E_OK)) +#if (!(defined(DEBUG_ERRORS)) || (DEBUG_ERRORS == 0)) + UNUSED(err); +#else + REPORT_ERROR(MINOR, err, NO_MSG); +#endif /* (!(defined(DEBUG_ERRORS)) || (DEBUG_ERRORS == 0)) */ + break; + } + case (FM_SET_NUM_OF_FMAN_CTRL): + { + t_FmIpcPortNumOfFmanCtrls ipcPortNumOfFmanCtrls; + + memcpy((uint8_t*)&ipcPortNumOfFmanCtrls, p_IpcMsg->msgBody, sizeof(t_FmIpcPortNumOfFmanCtrls)); + err = FmSetNumOfRiscsPerPort(h_Fm, + ipcPortNumOfFmanCtrls.hardwarePortId, + ipcPortNumOfFmanCtrls.numOfFmanCtrls, + ipcPortNumOfFmanCtrls.orFmanCtrl); + if (err != E_OK) + REPORT_ERROR(MINOR, err, NO_MSG); + break; + } +#ifdef FM_TX_ECC_FRMS_ERRATA_10GMAC_A004 + case (FM_10G_TX_ECC_WA): + p_IpcReply->error = (uint32_t)Fm10GTxEccWorkaround(h_Fm, p_IpcMsg->msgBody[0]); + *p_ReplyLength = sizeof(uint32_t); + break; +#endif /* FM_TX_ECC_FRMS_ERRATA_10GMAC_A004 */ + default: + *p_ReplyLength = 0; + RETURN_ERROR(MINOR, E_INVALID_SELECTION, ("command not found!!!")); + } + return E_OK; +} + + +/****************************************/ +/* Inter-Module functions */ +/****************************************/ +#ifdef FM_TX_ECC_FRMS_ERRATA_10GMAC_A004 +t_Error Fm10GTxEccWorkaround(t_Handle h_Fm, uint8_t macId) +{ + t_Fm *p_Fm = (t_Fm*)h_Fm; + t_Error err = E_OK; + t_FmIpcMsg msg; + t_FmIpcReply reply; + uint32_t replyLength; + uint8_t rxHardwarePortId, txHardwarePortId; + struct fman_fpm_regs *fpm_rg = p_Fm->p_FmFpmRegs; + + if (p_Fm->guestId != NCSW_MASTER_ID) + { + memset(&msg, 0, sizeof(msg)); + memset(&reply, 0, sizeof(reply)); + msg.msgId = FM_10G_TX_ECC_WA; + msg.msgBody[0] = macId; + replyLength = sizeof(uint32_t); + if ((err = XX_IpcSendMessage(p_Fm->h_IpcSessions[0], + (uint8_t*)&msg, + sizeof(msg.msgId)+sizeof(macId), + (uint8_t*)&reply, + &replyLength, + NULL, + NULL)) != E_OK) + RETURN_ERROR(MINOR, err, NO_MSG); + if (replyLength != sizeof(uint32_t)) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("IPC reply length mismatch")); + return (t_Error)(reply.error); + } + + SANITY_CHECK_RETURN_ERROR((macId == 0), E_NOT_SUPPORTED); + SANITY_CHECK_RETURN_ERROR(IsFmanCtrlCodeLoaded(p_Fm), E_INVALID_STATE); + + rxHardwarePortId = SwPortIdToHwPortId(e_FM_PORT_TYPE_RX_10G, + macId, + p_Fm->p_FmStateStruct->revInfo.majorRev, + p_Fm->p_FmStateStruct->revInfo.minorRev); + txHardwarePortId = SwPortIdToHwPortId(e_FM_PORT_TYPE_TX_10G, + macId, + p_Fm->p_FmStateStruct->revInfo.majorRev, + p_Fm->p_FmStateStruct->revInfo.minorRev); + if ((p_Fm->p_FmStateStruct->portsTypes[rxHardwarePortId] != e_FM_PORT_TYPE_DUMMY) || + (p_Fm->p_FmStateStruct->portsTypes[txHardwarePortId] != e_FM_PORT_TYPE_DUMMY)) + RETURN_ERROR(MAJOR, E_INVALID_STATE, + ("MAC should be initialized prior to Rx and Tx ports!")); + + return fman_set_erratum_10gmac_a004_wa(fpm_rg); +} +#endif /* FM_TX_ECC_FRMS_ERRATA_10GMAC_A004 */ + +uint16_t FmGetTnumAgingPeriod(t_Handle h_Fm) +{ + t_Fm *p_Fm = (t_Fm *)h_Fm; + + SANITY_CHECK_RETURN_VALUE(p_Fm, E_INVALID_HANDLE, 0); + SANITY_CHECK_RETURN_VALUE(!p_Fm->p_FmDriverParam, E_INVALID_STATE, 0); + + return p_Fm->tnumAgingPeriod; +} + +t_Error FmSetPortPreFetchConfiguration(t_Handle h_Fm, + uint8_t portNum, + bool preFetchConfigured) +{ + t_Fm *p_Fm = (t_Fm*)h_Fm; + + SANITY_CHECK_RETURN_ERROR(p_Fm, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(!p_Fm->p_FmDriverParam, E_INVALID_STATE); + + p_Fm->portsPreFetchConfigured[portNum] = TRUE; + p_Fm->portsPreFetchValue[portNum] = preFetchConfigured; + + return E_OK; +} + +t_Error FmGetPortPreFetchConfiguration(t_Handle h_Fm, + uint8_t portNum, + bool *p_PortConfigured, + bool *p_PreFetchConfigured) +{ + t_Fm *p_Fm = (t_Fm*)h_Fm; + + SANITY_CHECK_RETURN_ERROR(p_Fm, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(!p_Fm->p_FmDriverParam, E_INVALID_STATE); + + /* If the prefetch wasn't configured yet (not enable or disabled) + we return the value TRUE as it was already configured */ + if (!p_Fm->portsPreFetchConfigured[portNum]) + { + *p_PortConfigured = FALSE; + *p_PreFetchConfigured = FALSE; + } + else + { + *p_PortConfigured = TRUE; + *p_PreFetchConfigured = (p_Fm->portsPreFetchConfigured[portNum]); + } + + return E_OK; +} + +t_Error FmSetCongestionGroupPFCpriority(t_Handle h_Fm, + uint32_t congestionGroupId, + uint8_t priorityBitMap) +{ + t_Fm *p_Fm = (t_Fm *)h_Fm; + uint32_t regNum; + + ASSERT_COND(h_Fm); + + if (congestionGroupId > FM_PORT_NUM_OF_CONGESTION_GRPS) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, + ("Congestion group ID bigger than %d", + FM_PORT_NUM_OF_CONGESTION_GRPS)); + + if (p_Fm->guestId == NCSW_MASTER_ID) + { + ASSERT_COND(p_Fm->baseAddr); + regNum = (FM_PORT_NUM_OF_CONGESTION_GRPS - 1 - congestionGroupId) / 4; + fman_set_congestion_group_pfc_priority((uint32_t *)((p_Fm->baseAddr+FM_MM_CGP)), + congestionGroupId, + priorityBitMap, + regNum); + } + else if (p_Fm->h_IpcSessions[0]) + { + t_Error err; + t_FmIpcMsg msg; + t_FmIpcSetCongestionGroupPfcPriority fmIpcSetCongestionGroupPfcPriority; + + memset(&msg, 0, sizeof(msg)); + memset(&fmIpcSetCongestionGroupPfcPriority, 0, sizeof(t_FmIpcSetCongestionGroupPfcPriority)); + fmIpcSetCongestionGroupPfcPriority.congestionGroupId = congestionGroupId; + fmIpcSetCongestionGroupPfcPriority.priorityBitMap = priorityBitMap; + + msg.msgId = FM_SET_CONG_GRP_PFC_PRIO; + memcpy(msg.msgBody, &fmIpcSetCongestionGroupPfcPriority, sizeof(t_FmIpcSetCongestionGroupPfcPriority)); + + err = XX_IpcSendMessage(p_Fm->h_IpcSessions[0], + (uint8_t*)&msg, + sizeof(msg.msgId), + NULL, + NULL, + NULL, + NULL); + if (err != E_OK) + RETURN_ERROR(MINOR, err, NO_MSG); + } + else + RETURN_ERROR(MAJOR, E_INVALID_STATE, ("guest without IPC!")); + + return E_OK; +} + +uintptr_t FmGetPcdPrsBaseAddr(t_Handle h_Fm) +{ + t_Fm *p_Fm = (t_Fm*)h_Fm; + + SANITY_CHECK_RETURN_VALUE(p_Fm, E_INVALID_HANDLE, 0); + + if (!p_Fm->baseAddr) + { + REPORT_ERROR(MAJOR, E_INVALID_STATE, + ("No base-addr; probably Guest with IPC!")); + return 0; + } + + return (p_Fm->baseAddr + FM_MM_PRS); +} + +uintptr_t FmGetPcdKgBaseAddr(t_Handle h_Fm) +{ + t_Fm *p_Fm = (t_Fm*)h_Fm; + + SANITY_CHECK_RETURN_VALUE(p_Fm, E_INVALID_HANDLE, 0); + + if (!p_Fm->baseAddr) + { + REPORT_ERROR(MAJOR, E_INVALID_STATE, + ("No base-addr; probably Guest with IPC!")); + return 0; + } + + return (p_Fm->baseAddr + FM_MM_KG); +} + +uintptr_t FmGetPcdPlcrBaseAddr(t_Handle h_Fm) +{ + t_Fm *p_Fm = (t_Fm*)h_Fm; + + SANITY_CHECK_RETURN_VALUE(p_Fm, E_INVALID_HANDLE, 0); + + if (!p_Fm->baseAddr) + { + REPORT_ERROR(MAJOR, E_INVALID_STATE, + ("No base-addr; probably Guest with IPC!")); + return 0; + } + + return (p_Fm->baseAddr + FM_MM_PLCR); +} + +#if (DPAA_VERSION >= 11) +uintptr_t FmGetVSPBaseAddr(t_Handle h_Fm) +{ + t_Fm *p_Fm = (t_Fm*)h_Fm; + + SANITY_CHECK_RETURN_VALUE(p_Fm, E_INVALID_HANDLE, 0); + + return p_Fm->vspBaseAddr; +} +#endif /* (DPAA_VERSION >= 11) */ + +t_Handle FmGetMuramHandle(t_Handle h_Fm) +{ + t_Fm *p_Fm = (t_Fm*)h_Fm; + + SANITY_CHECK_RETURN_VALUE(p_Fm, E_INVALID_HANDLE, NULL); + + return (p_Fm->h_FmMuram); +} + +void FmGetPhysicalMuramBase(t_Handle h_Fm, t_FmPhysAddr *p_FmPhysAddr) +{ + t_Fm *p_Fm = (t_Fm*)h_Fm; + + if (p_Fm->fmMuramPhysBaseAddr) + { + /* General FM driver initialization */ + p_FmPhysAddr->low = (uint32_t)p_Fm->fmMuramPhysBaseAddr; + p_FmPhysAddr->high = (uint8_t)((p_Fm->fmMuramPhysBaseAddr & 0x000000ff00000000LL) >> 32); + return; + } + + ASSERT_COND(p_Fm->guestId != NCSW_MASTER_ID); + + if (p_Fm->h_IpcSessions[0]) + { + t_Error err; + t_FmIpcMsg msg; + t_FmIpcReply reply; + uint32_t replyLength; + t_FmIpcPhysAddr ipcPhysAddr; + + memset(&msg, 0, sizeof(msg)); + memset(&reply, 0, sizeof(reply)); + msg.msgId = FM_GET_PHYS_MURAM_BASE; + replyLength = sizeof(uint32_t) + sizeof(t_FmPhysAddr); + err = XX_IpcSendMessage(p_Fm->h_IpcSessions[0], + (uint8_t*)&msg, + sizeof(msg.msgId), + (uint8_t*)&reply, + &replyLength, + NULL, + NULL); + if (err != E_OK) + { + REPORT_ERROR(MINOR, err, NO_MSG); + return; + } + if (replyLength != (sizeof(uint32_t) + sizeof(t_FmPhysAddr))) + { + REPORT_ERROR(MINOR, E_INVALID_VALUE,("IPC reply length mismatch")); + return; + } + memcpy((uint8_t*)&ipcPhysAddr, reply.replyBody, sizeof(t_FmIpcPhysAddr)); + p_FmPhysAddr->high = ipcPhysAddr.high; + p_FmPhysAddr->low = ipcPhysAddr.low; + } + else + REPORT_ERROR(MINOR, E_NOT_SUPPORTED, + ("running in guest-mode without neither IPC nor mapped register!")); +} + +#if (DPAA_VERSION >= 11) +t_Error FmVSPAllocForPort (t_Handle h_Fm, + e_FmPortType portType, + uint8_t portId, + uint8_t numOfVSPs) +{ + t_Fm *p_Fm = (t_Fm *)h_Fm; + t_Error err = E_OK; + uint32_t profilesFound, intFlags; + uint8_t first, i; + uint8_t log2Num; + uint8_t swPortIndex=0, hardwarePortId; + + SANITY_CHECK_RETURN_ERROR(p_Fm, E_INVALID_HANDLE); + + if (!numOfVSPs) + return E_OK; + + if (numOfVSPs > FM_VSP_MAX_NUM_OF_ENTRIES) + RETURN_ERROR(MINOR, E_INVALID_VALUE, ("numProfiles can not be bigger than %d.",FM_VSP_MAX_NUM_OF_ENTRIES)); + + if (!POWER_OF_2(numOfVSPs)) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("numProfiles must be a power of 2.")); + + LOG2((uint64_t)numOfVSPs, log2Num); + + if ((log2Num == 0) || (p_Fm->partVSPBase == 0)) + first = 0; + else + first = 1<<log2Num; + + if (first > (p_Fm->partVSPBase + p_Fm->partNumOfVSPs)) + RETURN_ERROR(MINOR, E_INVALID_VALUE, ("can not allocate storage profile port window")); + + if (first < p_Fm->partVSPBase) + while (first < p_Fm->partVSPBase) + first = first + numOfVSPs; + + if ((first + numOfVSPs) > (p_Fm->partVSPBase + p_Fm->partNumOfVSPs)) + RETURN_ERROR(MINOR, E_INVALID_VALUE, ("can not allocate storage profile port window")); + + intFlags = XX_LockIntrSpinlock(p_Fm->h_Spinlock); + profilesFound = 0; + for (i=first; i < p_Fm->partVSPBase + p_Fm->partNumOfVSPs; ) + { + if (!p_Fm->p_FmSp->profiles[i].profilesMng.allocated) + { + profilesFound++; + i++; + if (profilesFound == numOfVSPs) + break; + } + else + { + profilesFound = 0; + /* advance i to the next aligned address */ + first = i = (uint8_t)(first + numOfVSPs); + } + } + if (profilesFound == numOfVSPs) + for (i = first; i<first + numOfVSPs; i++) + p_Fm->p_FmSp->profiles[i].profilesMng.allocated = TRUE; + else + { + XX_UnlockIntrSpinlock(p_Fm->h_Spinlock, intFlags); + RETURN_ERROR(MINOR, E_FULL, ("No profiles.")); + } + + hardwarePortId = SwPortIdToHwPortId(portType, + portId, + p_Fm->p_FmStateStruct->revInfo.majorRev, + p_Fm->p_FmStateStruct->revInfo.minorRev); + HW_PORT_ID_TO_SW_PORT_INDX(swPortIndex, hardwarePortId); + + p_Fm->p_FmSp->portsMapping[swPortIndex].numOfProfiles = numOfVSPs; + p_Fm->p_FmSp->portsMapping[swPortIndex].profilesBase = first; + + if ((err = SetVSPWindow(h_Fm,hardwarePortId, first,log2Num)) != E_OK) + for (i = first; i < first + numOfVSPs; i++) + p_Fm->p_FmSp->profiles[i].profilesMng.allocated = FALSE; + + XX_UnlockIntrSpinlock(p_Fm->h_Spinlock, intFlags); + + return err; +} + +t_Error FmVSPFreeForPort(t_Handle h_Fm, + e_FmPortType portType, + uint8_t portId) +{ + t_Fm *p_Fm = (t_Fm *)h_Fm; + uint8_t swPortIndex=0, hardwarePortId, first, numOfVSPs, i; + uint32_t intFlags; + + SANITY_CHECK_RETURN_ERROR(p_Fm, E_INVALID_HANDLE); + + hardwarePortId = SwPortIdToHwPortId(portType, + portId, + p_Fm->p_FmStateStruct->revInfo.majorRev, + p_Fm->p_FmStateStruct->revInfo.minorRev); + HW_PORT_ID_TO_SW_PORT_INDX(swPortIndex, hardwarePortId); + + numOfVSPs = (uint8_t)p_Fm->p_FmSp->portsMapping[swPortIndex].numOfProfiles; + first = (uint8_t)p_Fm->p_FmSp->portsMapping[swPortIndex].profilesBase; + + intFlags = XX_LockIntrSpinlock(p_Fm->h_Spinlock); + for (i = first; i < first + numOfVSPs; i++) + p_Fm->p_FmSp->profiles[i].profilesMng.allocated = FALSE; + XX_UnlockIntrSpinlock(p_Fm->h_Spinlock, intFlags); + + p_Fm->p_FmSp->portsMapping[swPortIndex].numOfProfiles = 0; + p_Fm->p_FmSp->portsMapping[swPortIndex].profilesBase = 0; + + return E_OK; +} +#endif /* (DPAA_VERSION >= 11) */ + +t_Error FmAllocFmanCtrlEventReg(t_Handle h_Fm, uint8_t *p_EventId) +{ + t_Fm *p_Fm = (t_Fm*)h_Fm; + uint8_t i; + + SANITY_CHECK_RETURN_ERROR(p_Fm, E_INVALID_HANDLE); + + if ((p_Fm->guestId != NCSW_MASTER_ID) && + p_Fm->h_IpcSessions[0]) + { + t_Error err; + t_FmIpcMsg msg; + t_FmIpcReply reply; + uint32_t replyLength; + + memset(&msg, 0, sizeof(msg)); + memset(&reply, 0, sizeof(reply)); + msg.msgId = FM_ALLOC_FMAN_CTRL_EVENT_REG; + replyLength = sizeof(uint32_t) + sizeof(uint8_t); + if ((err = XX_IpcSendMessage(p_Fm->h_IpcSessions[0], + (uint8_t*)&msg, + sizeof(msg.msgId), + (uint8_t*)&reply, + &replyLength, + NULL, + NULL)) != E_OK) + RETURN_ERROR(MAJOR, err, NO_MSG); + + if (replyLength != (sizeof(uint32_t) + sizeof(uint8_t))) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("IPC reply length mismatch")); + + *p_EventId = *(uint8_t*)(reply.replyBody); + + return (t_Error)(reply.error); + } + else if (p_Fm->guestId != NCSW_MASTER_ID) + RETURN_ERROR(MINOR, E_NOT_SUPPORTED, + ("running in guest-mode without IPC!")); + + for (i=0;i<FM_NUM_OF_FMAN_CTRL_EVENT_REGS;i++) + if (!p_Fm->usedEventRegs[i]) + { + p_Fm->usedEventRegs[i] = TRUE; + *p_EventId = i; + break; + } + + if (i==FM_NUM_OF_FMAN_CTRL_EVENT_REGS) + RETURN_ERROR(MAJOR, E_BUSY, ("No resource - FMan controller event register.")); + + return E_OK; +} + +void FmFreeFmanCtrlEventReg(t_Handle h_Fm, uint8_t eventId) +{ + t_Fm *p_Fm = (t_Fm*)h_Fm; + + SANITY_CHECK_RETURN(p_Fm, E_INVALID_HANDLE); + + if ((p_Fm->guestId != NCSW_MASTER_ID) && + p_Fm->h_IpcSessions[0]) + { + t_Error err; + t_FmIpcMsg msg; + + memset(&msg, 0, sizeof(msg)); + msg.msgId = FM_FREE_FMAN_CTRL_EVENT_REG; + msg.msgBody[0] = eventId; + err = XX_IpcSendMessage(p_Fm->h_IpcSessions[0], + (uint8_t*)&msg, + sizeof(msg.msgId)+sizeof(eventId), + NULL, + NULL, + NULL, + NULL); + if (err != E_OK) + REPORT_ERROR(MINOR, err, NO_MSG); + return; + } + else if (p_Fm->guestId != NCSW_MASTER_ID) + { + REPORT_ERROR(MINOR, E_NOT_SUPPORTED, + ("running in guest-mode without IPC!")); + return; + } + + ((t_Fm*)h_Fm)->usedEventRegs[eventId] = FALSE; +} + +void FmSetFmanCtrlIntr(t_Handle h_Fm, uint8_t eventRegId, uint32_t enableEvents) +{ + t_Fm *p_Fm = (t_Fm*)h_Fm; + struct fman_fpm_regs *fpm_rg = p_Fm->p_FmFpmRegs; + + if ((p_Fm->guestId != NCSW_MASTER_ID) && + !p_Fm->p_FmFpmRegs && + p_Fm->h_IpcSessions[0]) + { + t_FmIpcFmanEvents fmanCtrl; + t_Error err; + t_FmIpcMsg msg; + + fmanCtrl.eventRegId = eventRegId; + fmanCtrl.enableEvents = enableEvents; + memset(&msg, 0, sizeof(msg)); + msg.msgId = FM_SET_FMAN_CTRL_EVENTS_ENABLE; + memcpy(msg.msgBody, &fmanCtrl, sizeof(fmanCtrl)); + err = XX_IpcSendMessage(p_Fm->h_IpcSessions[0], + (uint8_t*)&msg, + sizeof(msg.msgId)+sizeof(fmanCtrl), + NULL, + NULL, + NULL, + NULL); + if (err != E_OK) + REPORT_ERROR(MINOR, err, NO_MSG); + return; + } + else if (!p_Fm->p_FmFpmRegs) + { + REPORT_ERROR(MINOR, E_NOT_SUPPORTED, + ("Either IPC or 'baseAddress' is required!")); + return; + } + + ASSERT_COND(eventRegId < FM_NUM_OF_FMAN_CTRL_EVENT_REGS); + fman_set_ctrl_intr(fpm_rg, eventRegId, enableEvents); +} + +uint32_t FmGetFmanCtrlIntr(t_Handle h_Fm, uint8_t eventRegId) +{ + t_Fm *p_Fm = (t_Fm*)h_Fm; + struct fman_fpm_regs *fpm_rg = p_Fm->p_FmFpmRegs; + + if ((p_Fm->guestId != NCSW_MASTER_ID) && + !p_Fm->p_FmFpmRegs && + p_Fm->h_IpcSessions[0]) + { + t_Error err; + t_FmIpcMsg msg; + t_FmIpcReply reply; + uint32_t replyLength, ctrlIntr; + + memset(&msg, 0, sizeof(msg)); + memset(&reply, 0, sizeof(reply)); + msg.msgId = FM_GET_FMAN_CTRL_EVENTS_ENABLE; + msg.msgBody[0] = eventRegId; + replyLength = sizeof(uint32_t) + sizeof(uint32_t); + err = XX_IpcSendMessage(p_Fm->h_IpcSessions[0], + (uint8_t*)&msg, + sizeof(msg.msgId)+sizeof(eventRegId), + (uint8_t*)&reply, + &replyLength, + NULL, + NULL); + if (err != E_OK) + { + REPORT_ERROR(MINOR, err, NO_MSG); + return 0; + } + if (replyLength != (sizeof(uint32_t) + sizeof(uint32_t))) + { + REPORT_ERROR(MINOR, E_INVALID_VALUE, ("IPC reply length mismatch")); + return 0; + } + memcpy((uint8_t*)&ctrlIntr, reply.replyBody, sizeof(uint32_t)); + return ctrlIntr; + } + else if (!p_Fm->p_FmFpmRegs) + { + REPORT_ERROR(MINOR, E_NOT_SUPPORTED, + ("Either IPC or 'baseAddress' is required!")); + return 0; + } + + return fman_get_ctrl_intr(fpm_rg, eventRegId); +} + +void FmRegisterIntr(t_Handle h_Fm, + e_FmEventModules module, + uint8_t modId, + e_FmIntrType intrType, + void (*f_Isr) (t_Handle h_Arg), + t_Handle h_Arg) +{ + t_Fm *p_Fm = (t_Fm*)h_Fm; + int event = 0; + + ASSERT_COND(h_Fm); + + GET_FM_MODULE_EVENT(module, modId, intrType, event); + ASSERT_COND(event < e_FM_EV_DUMMY_LAST); + + /* register in local FM structure */ + p_Fm->intrMng[event].f_Isr = f_Isr; + p_Fm->intrMng[event].h_SrcHandle = h_Arg; + + if ((p_Fm->guestId != NCSW_MASTER_ID) && + p_Fm->h_IpcSessions[0]) + { + t_FmIpcRegisterIntr fmIpcRegisterIntr; + t_Error err; + t_FmIpcMsg msg; + + /* register in Master FM structure */ + fmIpcRegisterIntr.event = (uint32_t)event; + fmIpcRegisterIntr.guestId = p_Fm->guestId; + memset(&msg, 0, sizeof(msg)); + msg.msgId = FM_REGISTER_INTR; + memcpy(msg.msgBody, &fmIpcRegisterIntr, sizeof(fmIpcRegisterIntr)); + err = XX_IpcSendMessage(p_Fm->h_IpcSessions[0], + (uint8_t*)&msg, + sizeof(msg.msgId) + sizeof(fmIpcRegisterIntr), + NULL, + NULL, + NULL, + NULL); + if (err != E_OK) + REPORT_ERROR(MINOR, err, NO_MSG); + } + else if (p_Fm->guestId != NCSW_MASTER_ID) + REPORT_ERROR(MINOR, E_NOT_SUPPORTED, + ("running in guest-mode without IPC!")); +} + +void FmUnregisterIntr(t_Handle h_Fm, + e_FmEventModules module, + uint8_t modId, + e_FmIntrType intrType) +{ + t_Fm *p_Fm = (t_Fm*)h_Fm; + int event = 0; + + ASSERT_COND(h_Fm); + + GET_FM_MODULE_EVENT(module, modId,intrType, event); + ASSERT_COND(event < e_FM_EV_DUMMY_LAST); + + p_Fm->intrMng[event].f_Isr = UnimplementedIsr; + p_Fm->intrMng[event].h_SrcHandle = NULL; +} + +void FmRegisterFmanCtrlIntr(t_Handle h_Fm, uint8_t eventRegId, void (*f_Isr) (t_Handle h_Arg, uint32_t event), t_Handle h_Arg) +{ + t_Fm *p_Fm = (t_Fm*)h_Fm; + + ASSERT_COND(eventRegId<FM_NUM_OF_FMAN_CTRL_EVENT_REGS); + + if (p_Fm->guestId != NCSW_MASTER_ID) + { + REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("FM in guest-mode")); + return; + } + + p_Fm->fmanCtrlIntr[eventRegId].f_Isr = f_Isr; + p_Fm->fmanCtrlIntr[eventRegId].h_SrcHandle = h_Arg; +} + +void FmUnregisterFmanCtrlIntr(t_Handle h_Fm, uint8_t eventRegId) +{ + t_Fm *p_Fm = (t_Fm*)h_Fm; + + ASSERT_COND(eventRegId<FM_NUM_OF_FMAN_CTRL_EVENT_REGS); + + if (p_Fm->guestId != NCSW_MASTER_ID) + { + REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("FM in guest-mode")); + return; + } + + p_Fm->fmanCtrlIntr[eventRegId].f_Isr = UnimplementedFmanCtrlIsr; + p_Fm->fmanCtrlIntr[eventRegId].h_SrcHandle = NULL; +} + +void FmRegisterPcd(t_Handle h_Fm, t_Handle h_FmPcd) +{ + t_Fm *p_Fm = (t_Fm*)h_Fm; + + if (p_Fm->h_Pcd) + REPORT_ERROR(MAJOR, E_ALREADY_EXISTS, ("PCD already set")); + + p_Fm->h_Pcd = h_FmPcd; +} + +void FmUnregisterPcd(t_Handle h_Fm) +{ + t_Fm *p_Fm = (t_Fm*)h_Fm; + + if (!p_Fm->h_Pcd) + REPORT_ERROR(MAJOR, E_NOT_FOUND, ("PCD handle!")); + + p_Fm->h_Pcd = NULL; +} + +t_Handle FmGetPcdHandle(t_Handle h_Fm) +{ + t_Fm *p_Fm = (t_Fm*)h_Fm; + + return p_Fm->h_Pcd; +} + +uint8_t FmGetId(t_Handle h_Fm) +{ + t_Fm *p_Fm = (t_Fm*)h_Fm; + + SANITY_CHECK_RETURN_VALUE(p_Fm, E_INVALID_HANDLE, 0xff); + + return p_Fm->p_FmStateStruct->fmId; +} + +t_Error FmReset(t_Handle h_Fm) +{ + t_Fm *p_Fm = (t_Fm*)h_Fm; + + SANITY_CHECK_RETURN_ERROR(p_Fm, E_INVALID_HANDLE); + + WRITE_UINT32(p_Fm->p_FmFpmRegs->fm_rstc, FPM_RSTC_FM_RESET); + CORE_MemoryBarrier(); + XX_UDelay(100); + + return E_OK; +} + +t_Error FmSetNumOfRiscsPerPort(t_Handle h_Fm, + uint8_t hardwarePortId, + uint8_t numOfFmanCtrls, + t_FmFmanCtrl orFmanCtrl) +{ + + t_Fm *p_Fm = (t_Fm*)h_Fm; + struct fman_fpm_regs *fpm_rg; + + SANITY_CHECK_RETURN_ERROR(p_Fm, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(((numOfFmanCtrls > 0) && (numOfFmanCtrls < 3)) , E_INVALID_HANDLE); + + fpm_rg = p_Fm->p_FmFpmRegs; + if ((p_Fm->guestId != NCSW_MASTER_ID) && + !p_Fm->p_FmFpmRegs && + p_Fm->h_IpcSessions[0]) + { + t_Error err; + t_FmIpcPortNumOfFmanCtrls params; + t_FmIpcMsg msg; + + memset(&msg, 0, sizeof(msg)); + params.hardwarePortId = hardwarePortId; + params.numOfFmanCtrls = numOfFmanCtrls; + params.orFmanCtrl = orFmanCtrl; + msg.msgId = FM_SET_NUM_OF_FMAN_CTRL; + memcpy(msg.msgBody, ¶ms, sizeof(params)); + err = XX_IpcSendMessage(p_Fm->h_IpcSessions[0], + (uint8_t*)&msg, + sizeof(msg.msgId) +sizeof(params), + NULL, + NULL, + NULL, + NULL); + if (err != E_OK) + RETURN_ERROR(MINOR, err, NO_MSG); + return E_OK; + } + else if (!p_Fm->p_FmFpmRegs) + RETURN_ERROR(MINOR, E_NOT_SUPPORTED, + ("Either IPC or 'baseAddress' is required!")); + + fman_set_num_of_riscs_per_port(fpm_rg, hardwarePortId, numOfFmanCtrls, orFmanCtrl); + + return E_OK; +} + +t_Error FmGetSetPortParams(t_Handle h_Fm, t_FmInterModulePortInitParams *p_PortParams) +{ + t_Fm *p_Fm = (t_Fm*)h_Fm; + t_Error err; + uint32_t intFlags; + uint8_t hardwarePortId = p_PortParams->hardwarePortId, macId; + struct fman_rg fman_rg; + + fman_rg.bmi_rg = p_Fm->p_FmBmiRegs; + fman_rg.qmi_rg = p_Fm->p_FmQmiRegs; + fman_rg.fpm_rg = p_Fm->p_FmFpmRegs; + fman_rg.dma_rg = p_Fm->p_FmDmaRegs; + + if (p_Fm->guestId != NCSW_MASTER_ID) + { + t_FmIpcPortInInitParams portInParams; + t_FmIpcPortOutInitParams portOutParams; + t_FmIpcMsg msg; + t_FmIpcReply reply; + uint32_t replyLength; + + portInParams.hardwarePortId = p_PortParams->hardwarePortId; + portInParams.enumPortType = (uint32_t)p_PortParams->portType; + portInParams.boolIndependentMode= (uint8_t)p_PortParams->independentMode; + portInParams.liodnOffset = p_PortParams->liodnOffset; + portInParams.numOfTasks = p_PortParams->numOfTasks; + portInParams.numOfExtraTasks = p_PortParams->numOfExtraTasks; + portInParams.numOfOpenDmas = p_PortParams->numOfOpenDmas; + portInParams.numOfExtraOpenDmas = p_PortParams->numOfExtraOpenDmas; + portInParams.sizeOfFifo = p_PortParams->sizeOfFifo; + portInParams.extraSizeOfFifo = p_PortParams->extraSizeOfFifo; + portInParams.deqPipelineDepth = p_PortParams->deqPipelineDepth; + portInParams.maxFrameLength = p_PortParams->maxFrameLength; + portInParams.liodnBase = p_PortParams->liodnBase; + + memset(&msg, 0, sizeof(msg)); + memset(&reply, 0, sizeof(reply)); + msg.msgId = FM_GET_SET_PORT_PARAMS; + memcpy(msg.msgBody, &portInParams, sizeof(portInParams)); + replyLength = (sizeof(uint32_t) + sizeof(t_FmIpcPortOutInitParams)); + if ((err = XX_IpcSendMessage(p_Fm->h_IpcSessions[0], + (uint8_t*)&msg, + sizeof(msg.msgId) +sizeof(portInParams), + (uint8_t*)&reply, + &replyLength, + NULL, + NULL)) != E_OK) + RETURN_ERROR(MINOR, err, NO_MSG); + if (replyLength != (sizeof(uint32_t) + sizeof(t_FmIpcPortOutInitParams))) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("IPC reply length mismatch")); + memcpy((uint8_t*)&portOutParams, reply.replyBody, sizeof(t_FmIpcPortOutInitParams)); + + p_PortParams->fmMuramPhysBaseAddr.high = portOutParams.ipcPhysAddr.high; + p_PortParams->fmMuramPhysBaseAddr.low = portOutParams.ipcPhysAddr.low; + p_PortParams->numOfTasks = portOutParams.numOfTasks; + p_PortParams->numOfExtraTasks = portOutParams.numOfExtraTasks; + p_PortParams->numOfOpenDmas = portOutParams.numOfOpenDmas; + p_PortParams->numOfExtraOpenDmas = portOutParams.numOfExtraOpenDmas; + p_PortParams->sizeOfFifo = portOutParams.sizeOfFifo; + p_PortParams->extraSizeOfFifo = portOutParams.extraSizeOfFifo; + + return (t_Error)(reply.error); + } + + ASSERT_COND(IN_RANGE(1, hardwarePortId, 63)); + + intFlags = XX_LockIntrSpinlock(p_Fm->h_Spinlock); + if (p_PortParams->independentMode) + { + /* set port parameters */ + p_Fm->independentMode = p_PortParams->independentMode; + /* disable dispatch limit */ + fman_qmi_disable_dispatch_limit(fman_rg.fpm_rg); + } + + if (p_PortParams->portType == e_FM_PORT_TYPE_OH_HOST_COMMAND) + { + if (p_Fm->hcPortInitialized) + { + XX_UnlockIntrSpinlock(p_Fm->h_Spinlock, intFlags); + RETURN_ERROR(MAJOR, E_INVALID_STATE, ("Only one host command port is allowed.")); + } + else + p_Fm->hcPortInitialized = TRUE; + } + p_Fm->p_FmStateStruct->portsTypes[hardwarePortId] = p_PortParams->portType; + + err = FmSetNumOfTasks(p_Fm, hardwarePortId, &p_PortParams->numOfTasks, &p_PortParams->numOfExtraTasks, TRUE); + if (err) + { + XX_UnlockIntrSpinlock(p_Fm->h_Spinlock, intFlags); + RETURN_ERROR(MAJOR, err, NO_MSG); + } + +#ifdef FM_QMI_NO_DEQ_OPTIONS_SUPPORT + if (p_Fm->p_FmStateStruct->revInfo.majorRev != 4) +#endif /* FM_QMI_NO_DEQ_OPTIONS_SUPPORT */ + if ((p_PortParams->portType != e_FM_PORT_TYPE_RX) && + (p_PortParams->portType != e_FM_PORT_TYPE_RX_10G)) + /* for transmit & O/H ports */ + { + uint8_t enqTh; + uint8_t deqTh; + + /* update qmi ENQ/DEQ threshold */ + p_Fm->p_FmStateStruct->accumulatedNumOfDeqTnums += p_PortParams->deqPipelineDepth; + enqTh = fman_get_qmi_enq_th(fman_rg.qmi_rg); + /* if enqTh is too big, we reduce it to the max value that is still OK */ + if (enqTh >= (QMI_MAX_NUM_OF_TNUMS - p_Fm->p_FmStateStruct->accumulatedNumOfDeqTnums)) + { + enqTh = (uint8_t)(QMI_MAX_NUM_OF_TNUMS - p_Fm->p_FmStateStruct->accumulatedNumOfDeqTnums - 1); + fman_set_qmi_enq_th(fman_rg.qmi_rg, enqTh); + } + + deqTh = fman_get_qmi_deq_th(fman_rg.qmi_rg); + /* if deqTh is too small, we enlarge it to the min value that is still OK. + deqTh may not be larger than 63 (QMI_MAX_NUM_OF_TNUMS-1). */ + if ((deqTh <= p_Fm->p_FmStateStruct->accumulatedNumOfDeqTnums) && (deqTh < QMI_MAX_NUM_OF_TNUMS-1)) + { + deqTh = (uint8_t)(p_Fm->p_FmStateStruct->accumulatedNumOfDeqTnums + 1); + fman_set_qmi_deq_th(fman_rg.qmi_rg, deqTh); + } + } + +#ifdef FM_LOW_END_RESTRICTION + if ((hardwarePortId==0x1) || (hardwarePortId==0x29)) + { + if (p_Fm->p_FmStateStruct->lowEndRestriction) + { + XX_UnlockIntrSpinlock(p_Fm->h_Spinlock, intFlags); + RETURN_ERROR(MAJOR, E_NOT_AVAILABLE, ("OP #0 cannot work with Tx Port #1.")); + } + else + p_Fm->p_FmStateStruct->lowEndRestriction = TRUE; + } +#endif /* FM_LOW_END_RESTRICTION */ + + err = FmSetSizeOfFifo(p_Fm, + hardwarePortId, + &p_PortParams->sizeOfFifo, + &p_PortParams->extraSizeOfFifo, + TRUE); + if (err) + { + XX_UnlockIntrSpinlock(p_Fm->h_Spinlock, intFlags); + RETURN_ERROR(MAJOR, err, NO_MSG); + } + + err = FmSetNumOfOpenDmas(p_Fm, + hardwarePortId, + &p_PortParams->numOfOpenDmas, + &p_PortParams->numOfExtraOpenDmas, + TRUE); + if (err) + { + XX_UnlockIntrSpinlock(p_Fm->h_Spinlock, intFlags); + RETURN_ERROR(MAJOR, err, NO_MSG); + } + + fman_set_liodn_per_port(&fman_rg, + hardwarePortId, + p_PortParams->liodnBase, + p_PortParams->liodnOffset); + + if (p_Fm->p_FmStateStruct->revInfo.majorRev < 6) + fman_set_order_restoration_per_port(fman_rg.fpm_rg, + hardwarePortId, + p_PortParams->independentMode, + !!((p_PortParams->portType==e_FM_PORT_TYPE_RX) || (p_PortParams->portType==e_FM_PORT_TYPE_RX_10G))); + + HW_PORT_ID_TO_SW_PORT_ID(macId, hardwarePortId); + +#if defined(FM_MAX_NUM_OF_10G_MACS) && (FM_MAX_NUM_OF_10G_MACS) + if ((p_PortParams->portType == e_FM_PORT_TYPE_TX_10G) || + (p_PortParams->portType == e_FM_PORT_TYPE_RX_10G)) + { + ASSERT_COND(macId < FM_MAX_NUM_OF_10G_MACS); + if (p_PortParams->maxFrameLength >= p_Fm->p_FmStateStruct->macMaxFrameLengths10G[macId]) + p_Fm->p_FmStateStruct->portMaxFrameLengths10G[macId] = p_PortParams->maxFrameLength; + else + RETURN_ERROR(MINOR, E_INVALID_VALUE, ("Port maxFrameLength is smaller than MAC current MTU")); + } + else +#endif /* defined(FM_MAX_NUM_OF_10G_MACS) && ... */ + if ((p_PortParams->portType == e_FM_PORT_TYPE_TX) || + (p_PortParams->portType == e_FM_PORT_TYPE_RX)) + { + ASSERT_COND(macId < FM_MAX_NUM_OF_1G_MACS); + if (p_PortParams->maxFrameLength >= p_Fm->p_FmStateStruct->macMaxFrameLengths1G[macId]) + p_Fm->p_FmStateStruct->portMaxFrameLengths1G[macId] = p_PortParams->maxFrameLength; + else + RETURN_ERROR(MINOR, E_INVALID_VALUE, ("Port maxFrameLength is smaller than MAC current MTU")); + } + + FmGetPhysicalMuramBase(p_Fm, &p_PortParams->fmMuramPhysBaseAddr); + XX_UnlockIntrSpinlock(p_Fm->h_Spinlock, intFlags); + + return E_OK; +} + +void FmFreePortParams(t_Handle h_Fm,t_FmInterModulePortFreeParams *p_PortParams) +{ + t_Fm *p_Fm = (t_Fm*)h_Fm; + uint32_t intFlags; + uint8_t hardwarePortId = p_PortParams->hardwarePortId; + uint8_t numOfTasks, numOfDmas, macId; + uint16_t sizeOfFifo; + t_Error err; + t_FmIpcPortFreeParams portParams; + t_FmIpcMsg msg; + struct fman_qmi_regs *qmi_rg = p_Fm->p_FmQmiRegs; + struct fman_bmi_regs *bmi_rg = p_Fm->p_FmBmiRegs; + + if (p_Fm->guestId != NCSW_MASTER_ID) + { + portParams.hardwarePortId = p_PortParams->hardwarePortId; + portParams.enumPortType = (uint32_t)p_PortParams->portType; + portParams.deqPipelineDepth = p_PortParams->deqPipelineDepth; + memset(&msg, 0, sizeof(msg)); + msg.msgId = FM_FREE_PORT; + memcpy(msg.msgBody, &portParams, sizeof(portParams)); + err = XX_IpcSendMessage(p_Fm->h_IpcSessions[0], + (uint8_t*)&msg, + sizeof(msg.msgId)+sizeof(portParams), + NULL, + NULL, + NULL, + NULL); + if (err != E_OK) + REPORT_ERROR(MINOR, err, NO_MSG); + return; + } + + ASSERT_COND(IN_RANGE(1, hardwarePortId, 63)); + + intFlags = XX_LockIntrSpinlock(p_Fm->h_Spinlock); + + if (p_PortParams->portType == e_FM_PORT_TYPE_OH_HOST_COMMAND) + { + ASSERT_COND(p_Fm->hcPortInitialized); + p_Fm->hcPortInitialized = FALSE; + } + + p_Fm->p_FmStateStruct->portsTypes[hardwarePortId] = e_FM_PORT_TYPE_DUMMY; + + /* free numOfTasks */ + numOfTasks = fman_get_num_of_tasks(bmi_rg, hardwarePortId); + ASSERT_COND(p_Fm->p_FmStateStruct->accumulatedNumOfTasks >= numOfTasks); + p_Fm->p_FmStateStruct->accumulatedNumOfTasks -= numOfTasks; + + /* free numOfOpenDmas */ + numOfDmas = fman_get_num_of_dmas(bmi_rg, hardwarePortId); + ASSERT_COND(p_Fm->p_FmStateStruct->accumulatedNumOfOpenDmas >= numOfDmas); + p_Fm->p_FmStateStruct->accumulatedNumOfOpenDmas -= numOfDmas; + +#ifdef FM_HAS_TOTAL_DMAS + if (p_Fm->p_FmStateStruct->revInfo.majorRev < 6) + { + /* update total num of DMA's with committed number of open DMAS, and max uncommitted pool. */ + fman_set_num_of_open_dmas(bmi_rg, + hardwarePortId, + 1, + 0, + (uint8_t)(p_Fm->p_FmStateStruct->accumulatedNumOfOpenDmas + p_Fm->p_FmStateStruct->extraOpenDmasPoolSize)); + } +#endif /* FM_HAS_TOTAL_DMAS */ + + /* free sizeOfFifo */ + sizeOfFifo = fman_get_size_of_fifo(bmi_rg, hardwarePortId); + ASSERT_COND(p_Fm->p_FmStateStruct->accumulatedFifoSize >= (sizeOfFifo * BMI_FIFO_UNITS)); + p_Fm->p_FmStateStruct->accumulatedFifoSize -= (sizeOfFifo * BMI_FIFO_UNITS); + +#ifdef FM_QMI_NO_DEQ_OPTIONS_SUPPORT + if (p_Fm->p_FmStateStruct->revInfo.majorRev != 4) +#endif /* FM_QMI_NO_DEQ_OPTIONS_SUPPORT */ + if ((p_PortParams->portType != e_FM_PORT_TYPE_RX) && + (p_PortParams->portType != e_FM_PORT_TYPE_RX_10G)) + /* for transmit & O/H ports */ + { + uint8_t enqTh; + uint8_t deqTh; + + /* update qmi ENQ/DEQ threshold */ + p_Fm->p_FmStateStruct->accumulatedNumOfDeqTnums -= p_PortParams->deqPipelineDepth; + + /* p_Fm->p_FmStateStruct->accumulatedNumOfDeqTnums is now smaller, + so we can enlarge enqTh */ + enqTh = (uint8_t)(QMI_MAX_NUM_OF_TNUMS - p_Fm->p_FmStateStruct->accumulatedNumOfDeqTnums - 1); + + /* p_Fm->p_FmStateStruct->accumulatedNumOfDeqTnums is now smaller, + so we can reduce deqTh */ + deqTh = (uint8_t)(p_Fm->p_FmStateStruct->accumulatedNumOfDeqTnums + 1); + + fman_set_qmi_enq_th(qmi_rg, enqTh); + fman_set_qmi_deq_th(qmi_rg, deqTh); + } + + HW_PORT_ID_TO_SW_PORT_ID(macId, hardwarePortId); + +#if defined(FM_MAX_NUM_OF_10G_MACS) && (FM_MAX_NUM_OF_10G_MACS) + if ((p_PortParams->portType == e_FM_PORT_TYPE_TX_10G) || + (p_PortParams->portType == e_FM_PORT_TYPE_RX_10G)) + { + ASSERT_COND(macId < FM_MAX_NUM_OF_10G_MACS); + p_Fm->p_FmStateStruct->portMaxFrameLengths10G[macId] = 0; + } + else +#endif /* defined(FM_MAX_NUM_OF_10G_MACS) && ... */ + if ((p_PortParams->portType == e_FM_PORT_TYPE_TX) || + (p_PortParams->portType == e_FM_PORT_TYPE_RX)) + { + ASSERT_COND(macId < FM_MAX_NUM_OF_1G_MACS); + p_Fm->p_FmStateStruct->portMaxFrameLengths1G[macId] = 0; + } + +#ifdef FM_LOW_END_RESTRICTION + if ((hardwarePortId==0x1) || (hardwarePortId==0x29)) + p_Fm->p_FmStateStruct->lowEndRestriction = FALSE; +#endif /* FM_LOW_END_RESTRICTION */ + XX_UnlockIntrSpinlock(p_Fm->h_Spinlock, intFlags); +} + +t_Error FmIsPortStalled(t_Handle h_Fm, uint8_t hardwarePortId, bool *p_IsStalled) +{ + t_Fm *p_Fm = (t_Fm*)h_Fm; + t_Error err; + t_FmIpcMsg msg; + t_FmIpcReply reply; + uint32_t replyLength; + struct fman_fpm_regs *fpm_rg = p_Fm->p_FmFpmRegs; + + if ((p_Fm->guestId != NCSW_MASTER_ID) && + !p_Fm->baseAddr && + p_Fm->h_IpcSessions[0]) + { + memset(&msg, 0, sizeof(msg)); + memset(&reply, 0, sizeof(reply)); + msg.msgId = FM_IS_PORT_STALLED; + msg.msgBody[0] = hardwarePortId; + replyLength = sizeof(uint32_t) + sizeof(uint8_t); + err = XX_IpcSendMessage(p_Fm->h_IpcSessions[0], + (uint8_t*)&msg, + sizeof(msg.msgId)+sizeof(hardwarePortId), + (uint8_t*)&reply, + &replyLength, + NULL, + NULL); + if (err != E_OK) + RETURN_ERROR(MINOR, err, NO_MSG); + if (replyLength != (sizeof(uint32_t) + sizeof(uint8_t))) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("IPC reply length mismatch")); + + *p_IsStalled = (bool)!!(*(uint8_t*)(reply.replyBody)); + + return (t_Error)(reply.error); + } + else if (!p_Fm->baseAddr) + RETURN_ERROR(MINOR, E_NOT_SUPPORTED, + ("Either IPC or 'baseAddress' is required!")); + + *p_IsStalled = fman_is_port_stalled(fpm_rg, hardwarePortId); + + return E_OK; +} + +t_Error FmResumeStalledPort(t_Handle h_Fm, uint8_t hardwarePortId) +{ + t_Fm *p_Fm = (t_Fm*)h_Fm; + t_Error err; + bool isStalled; + struct fman_fpm_regs *fpm_rg = p_Fm->p_FmFpmRegs; + + if ((p_Fm->guestId != NCSW_MASTER_ID) && + !p_Fm->baseAddr && + p_Fm->h_IpcSessions[0]) + { + t_FmIpcMsg msg; + t_FmIpcReply reply; + uint32_t replyLength; + + memset(&msg, 0, sizeof(msg)); + memset(&reply, 0, sizeof(reply)); + msg.msgId = FM_RESUME_STALLED_PORT; + msg.msgBody[0] = hardwarePortId; + replyLength = sizeof(uint32_t); + err = XX_IpcSendMessage(p_Fm->h_IpcSessions[0], + (uint8_t*)&msg, + sizeof(msg.msgId) + sizeof(hardwarePortId), + (uint8_t*)&reply, + &replyLength, + NULL, + NULL); + if (err != E_OK) + RETURN_ERROR(MINOR, err, NO_MSG); + if (replyLength != sizeof(uint32_t)) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("IPC reply length mismatch")); + return (t_Error)(reply.error); + } + else if (!p_Fm->baseAddr) + RETURN_ERROR(MINOR, E_NOT_SUPPORTED, + ("Either IPC or 'baseAddress' is required!")); + + if (p_Fm->p_FmStateStruct->revInfo.majorRev >= 6) + RETURN_ERROR(MINOR, E_NOT_AVAILABLE, ("Not available for this FM revision!")); + + /* Get port status */ + err = FmIsPortStalled(h_Fm, hardwarePortId, &isStalled); + if (err) + RETURN_ERROR(MAJOR, E_INVALID_STATE, ("Can't get port status")); + if (!isStalled) + return E_OK; + + fman_resume_stalled_port(fpm_rg, hardwarePortId); + + return E_OK; +} + +t_Error FmResetMac(t_Handle h_Fm, e_FmMacType type, uint8_t macId) +{ + t_Fm *p_Fm = (t_Fm*)h_Fm; + t_Error err; + struct fman_fpm_regs *fpm_rg = p_Fm->p_FmFpmRegs; + +#if (DPAA_VERSION >= 11) + if (p_Fm->p_FmStateStruct->revInfo.majorRev >= 6) + RETURN_ERROR(MINOR, E_NOT_SUPPORTED, + ("FMan MAC reset!")); +#endif /*(DPAA_VERSION >= 11)*/ + + if ((p_Fm->guestId != NCSW_MASTER_ID) && + !p_Fm->baseAddr && + p_Fm->h_IpcSessions[0]) + { + t_FmIpcMacParams macParams; + t_FmIpcMsg msg; + t_FmIpcReply reply; + uint32_t replyLength; + + memset(&msg, 0, sizeof(msg)); + memset(&reply, 0, sizeof(reply)); + macParams.id = macId; + macParams.enumType = (uint32_t)type; + msg.msgId = FM_RESET_MAC; + memcpy(msg.msgBody, &macParams, sizeof(macParams)); + replyLength = sizeof(uint32_t); + err = XX_IpcSendMessage(p_Fm->h_IpcSessions[0], + (uint8_t*)&msg, + sizeof(msg.msgId)+sizeof(macParams), + (uint8_t*)&reply, + &replyLength, + NULL, + NULL); + if (err != E_OK) + RETURN_ERROR(MINOR, err, NO_MSG); + if (replyLength != sizeof(uint32_t)) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("IPC reply length mismatch")); + return (t_Error)(reply.error); + } + else if (!p_Fm->baseAddr) + RETURN_ERROR(MINOR, E_NOT_SUPPORTED, + ("Either IPC or 'baseAddress' is required!")); + + err = (t_Error)fman_reset_mac(fpm_rg, macId, !!(type == e_FM_MAC_10G)); + + if (err == -EBUSY) + return ERROR_CODE(E_TIMEOUT); + else if (err) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("Illegal MAC ID")); + + return E_OK; +} + +t_Error FmSetMacMaxFrame(t_Handle h_Fm, e_FmMacType type, uint8_t macId, uint16_t mtu) +{ + t_Fm *p_Fm = (t_Fm*)h_Fm; + + if ((p_Fm->guestId != NCSW_MASTER_ID) && + p_Fm->h_IpcSessions[0]) + { + t_FmIpcMacMaxFrameParams macMaxFrameLengthParams; + t_Error err; + t_FmIpcMsg msg; + + memset(&msg, 0, sizeof(msg)); + macMaxFrameLengthParams.macParams.id = macId; + macMaxFrameLengthParams.macParams.enumType = (uint32_t)type; + macMaxFrameLengthParams.maxFrameLength = (uint16_t)mtu; + msg.msgId = FM_SET_MAC_MAX_FRAME; + memcpy(msg.msgBody, &macMaxFrameLengthParams, sizeof(macMaxFrameLengthParams)); + err = XX_IpcSendMessage(p_Fm->h_IpcSessions[0], + (uint8_t*)&msg, + sizeof(msg.msgId)+sizeof(macMaxFrameLengthParams), + NULL, + NULL, + NULL, + NULL); + if (err != E_OK) + RETURN_ERROR(MINOR, err, NO_MSG); + return E_OK; + } + else if (p_Fm->guestId != NCSW_MASTER_ID) + RETURN_ERROR(MINOR, E_NOT_SUPPORTED, + ("running in guest-mode without IPC!")); + + /* if port is already initialized, check that MaxFrameLength is smaller + * or equal to the port's max */ +#if (defined(FM_MAX_NUM_OF_10G_MACS) && (FM_MAX_NUM_OF_10G_MACS)) + if (type == e_FM_MAC_10G) + { + if ((!p_Fm->p_FmStateStruct->portMaxFrameLengths10G[macId]) + || (p_Fm->p_FmStateStruct->portMaxFrameLengths10G[macId] && + (mtu <= p_Fm->p_FmStateStruct->portMaxFrameLengths10G[macId]))) + p_Fm->p_FmStateStruct->macMaxFrameLengths10G[macId] = mtu; + else + RETURN_ERROR(MINOR, E_INVALID_VALUE, ("MAC maxFrameLength is larger than Port maxFrameLength")); + + } + else +#else + UNUSED(type); +#endif /* (defined(FM_MAX_NUM_OF_10G_MACS) && ... */ + if ((!p_Fm->p_FmStateStruct->portMaxFrameLengths1G[macId]) + || (p_Fm->p_FmStateStruct->portMaxFrameLengths1G[macId] && + (mtu <= p_Fm->p_FmStateStruct->portMaxFrameLengths1G[macId]))) + p_Fm->p_FmStateStruct->macMaxFrameLengths1G[macId] = mtu; + else + RETURN_ERROR(MINOR, E_INVALID_VALUE, ("MAC maxFrameLength is larger than Port maxFrameLength")); + + return E_OK; +} + +uint16_t FmGetClockFreq(t_Handle h_Fm) +{ + t_Fm *p_Fm = (t_Fm*)h_Fm; + + /* for multicore environment: this depends on the + * fact that fmClkFreq was properly initialized at "init". */ + return p_Fm->p_FmStateStruct->fmClkFreq; +} + +uint16_t FmGetMacClockFreq(t_Handle h_Fm) +{ + t_Fm *p_Fm = (t_Fm*)h_Fm; + + return p_Fm->p_FmStateStruct->fmMacClkFreq; +} + +uint32_t FmGetTimeStampScale(t_Handle h_Fm) +{ + t_Fm *p_Fm = (t_Fm*)h_Fm; + + if ((p_Fm->guestId != NCSW_MASTER_ID) && + !p_Fm->baseAddr && + p_Fm->h_IpcSessions[0]) + { + t_Error err; + t_FmIpcMsg msg; + t_FmIpcReply reply; + uint32_t replyLength, timeStamp; + + memset(&msg, 0, sizeof(msg)); + memset(&reply, 0, sizeof(reply)); + msg.msgId = FM_GET_TIMESTAMP_SCALE; + replyLength = sizeof(uint32_t) + sizeof(uint32_t); + if ((err = XX_IpcSendMessage(p_Fm->h_IpcSessions[0], + (uint8_t*)&msg, + sizeof(msg.msgId), + (uint8_t*)&reply, + &replyLength, + NULL, + NULL)) != E_OK) + { + REPORT_ERROR(MAJOR, err, NO_MSG); + return 0; + } + if (replyLength != (sizeof(uint32_t) + sizeof(uint32_t))) + { + REPORT_ERROR(MAJOR, E_INVALID_VALUE, ("IPC reply length mismatch")); + return 0; + } + + memcpy((uint8_t*)&timeStamp, reply.replyBody, sizeof(uint32_t)); + return timeStamp; + } + else if ((p_Fm->guestId != NCSW_MASTER_ID) && + p_Fm->baseAddr) + { + if (!(GET_UINT32(p_Fm->p_FmFpmRegs->fmfp_tsc1) & FPM_TS_CTL_EN)) + { + REPORT_ERROR(MAJOR, E_INVALID_STATE, ("timestamp is not enabled!")); + return 0; + } + } + else if (p_Fm->guestId != NCSW_MASTER_ID) + DBG(WARNING, ("No IPC - can't validate FM if timestamp enabled.")); + + return p_Fm->p_FmStateStruct->count1MicroBit; +} + +t_Error FmEnableRamsEcc(t_Handle h_Fm) +{ + t_Fm *p_Fm = (t_Fm*)h_Fm; + + SANITY_CHECK_RETURN_ERROR(p_Fm, E_INVALID_HANDLE); + + p_Fm->p_FmStateStruct->ramsEccOwners++; + p_Fm->p_FmStateStruct->internalCall = TRUE; + + return FM_EnableRamsEcc(p_Fm); +} + +t_Error FmDisableRamsEcc(t_Handle h_Fm) +{ + t_Fm *p_Fm = (t_Fm*)h_Fm; + + SANITY_CHECK_RETURN_ERROR(p_Fm, E_INVALID_HANDLE); + + ASSERT_COND(p_Fm->p_FmStateStruct->ramsEccOwners); + p_Fm->p_FmStateStruct->ramsEccOwners--; + + if (p_Fm->p_FmStateStruct->ramsEccOwners==0) + { + p_Fm->p_FmStateStruct->internalCall = TRUE; + return FM_DisableRamsEcc(p_Fm); + } + + return E_OK; +} + +uint8_t FmGetGuestId(t_Handle h_Fm) +{ + t_Fm *p_Fm = (t_Fm*)h_Fm; + + return p_Fm->guestId; +} + +bool FmIsMaster(t_Handle h_Fm) +{ + t_Fm *p_Fm = (t_Fm*)h_Fm; + + return (p_Fm->guestId == NCSW_MASTER_ID); +} + +t_Error FmSetSizeOfFifo(t_Handle h_Fm, + uint8_t hardwarePortId, + uint32_t *p_SizeOfFifo, + uint32_t *p_ExtraSizeOfFifo, + bool initialConfig) +{ + t_Fm *p_Fm = (t_Fm*)h_Fm; + t_FmIpcPortRsrcParams rsrcParams; + t_Error err; + struct fman_bmi_regs *bmi_rg = p_Fm->p_FmBmiRegs; + uint32_t sizeOfFifo = *p_SizeOfFifo, extraSizeOfFifo = *p_ExtraSizeOfFifo; + uint16_t currentVal = 0, currentExtraVal = 0; + + if ((p_Fm->guestId != NCSW_MASTER_ID) && + !p_Fm->baseAddr && + p_Fm->h_IpcSessions[0]) + { + t_FmIpcMsg msg; + t_FmIpcReply reply; + uint32_t replyLength; + + rsrcParams.hardwarePortId = hardwarePortId; + rsrcParams.val = sizeOfFifo; + rsrcParams.extra = extraSizeOfFifo; + rsrcParams.boolInitialConfig = (uint8_t)initialConfig; + + memset(&msg, 0, sizeof(msg)); + memset(&reply, 0, sizeof(reply)); + msg.msgId = FM_SET_SIZE_OF_FIFO; + memcpy(msg.msgBody, &rsrcParams, sizeof(rsrcParams)); + replyLength = sizeof(uint32_t); + if ((err = XX_IpcSendMessage(p_Fm->h_IpcSessions[0], + (uint8_t*)&msg, + sizeof(msg.msgId) + sizeof(rsrcParams), + (uint8_t*)&reply, + &replyLength, + NULL, + NULL)) != E_OK) + RETURN_ERROR(MINOR, err, NO_MSG); + if (replyLength != sizeof(uint32_t)) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("IPC reply length mismatch")); + return (t_Error)(reply.error); + } + else if ((p_Fm->guestId != NCSW_MASTER_ID) && + p_Fm->baseAddr) + { + DBG(WARNING, ("No IPC - can't validate FM total-fifo size.")); + fman_set_size_of_fifo(bmi_rg, hardwarePortId, sizeOfFifo, extraSizeOfFifo); + } + else if (p_Fm->guestId != NCSW_MASTER_ID) + RETURN_ERROR(MAJOR, E_NOT_SUPPORTED, + ("running in guest-mode without neither IPC nor mapped register!")); + + if (!initialConfig) + { + /* !initialConfig - runtime change of existing value. + * - read the current FIFO and extra FIFO size */ + currentExtraVal = fman_get_size_of_extra_fifo(bmi_rg, hardwarePortId); + currentVal = fman_get_size_of_fifo(bmi_rg, hardwarePortId); + } + + if (extraSizeOfFifo > currentExtraVal) + { + if (extraSizeOfFifo && !p_Fm->p_FmStateStruct->extraFifoPoolSize) + /* if this is the first time a port requires extraFifoPoolSize, the total extraFifoPoolSize + * must be initialized to 1 buffer per port + */ + p_Fm->p_FmStateStruct->extraFifoPoolSize = FM_MAX_NUM_OF_RX_PORTS*BMI_FIFO_UNITS; + + p_Fm->p_FmStateStruct->extraFifoPoolSize = MAX(p_Fm->p_FmStateStruct->extraFifoPoolSize, extraSizeOfFifo); + } + + /* check that there are enough uncommitted fifo size */ + if ((p_Fm->p_FmStateStruct->accumulatedFifoSize - currentVal + sizeOfFifo) > + (p_Fm->p_FmStateStruct->totalFifoSize - p_Fm->p_FmStateStruct->extraFifoPoolSize)){ + REPORT_ERROR(MAJOR, E_INVALID_VALUE, + ("Port request fifo size + accumulated size > total FIFO size:")); + RETURN_ERROR(MAJOR, E_INVALID_VALUE, + ("port 0x%x requested %d bytes, extra size = %d, accumulated size = %d total size = %d", + hardwarePortId, sizeOfFifo, p_Fm->p_FmStateStruct->extraFifoPoolSize, + p_Fm->p_FmStateStruct->accumulatedFifoSize, + p_Fm->p_FmStateStruct->totalFifoSize)); + } + else + { + /* update accumulated */ + ASSERT_COND(p_Fm->p_FmStateStruct->accumulatedFifoSize >= currentVal); + p_Fm->p_FmStateStruct->accumulatedFifoSize -= currentVal; + p_Fm->p_FmStateStruct->accumulatedFifoSize += sizeOfFifo; + fman_set_size_of_fifo(bmi_rg, hardwarePortId, sizeOfFifo, extraSizeOfFifo); + } + + return E_OK; +} + +t_Error FmSetNumOfTasks(t_Handle h_Fm, + uint8_t hardwarePortId, + uint8_t *p_NumOfTasks, + uint8_t *p_NumOfExtraTasks, + bool initialConfig) +{ + t_Fm *p_Fm = (t_Fm *)h_Fm; + t_Error err; + struct fman_bmi_regs *bmi_rg = p_Fm->p_FmBmiRegs; + uint8_t currentVal = 0, currentExtraVal = 0, numOfTasks = *p_NumOfTasks, numOfExtraTasks = *p_NumOfExtraTasks; + + ASSERT_COND(IN_RANGE(1, hardwarePortId, 63)); + + if ((p_Fm->guestId != NCSW_MASTER_ID) && + !p_Fm->baseAddr && + p_Fm->h_IpcSessions[0]) + { + t_FmIpcPortRsrcParams rsrcParams; + t_FmIpcMsg msg; + t_FmIpcReply reply; + uint32_t replyLength; + + rsrcParams.hardwarePortId = hardwarePortId; + rsrcParams.val = numOfTasks; + rsrcParams.extra = numOfExtraTasks; + rsrcParams.boolInitialConfig = (uint8_t)initialConfig; + + memset(&msg, 0, sizeof(msg)); + memset(&reply, 0, sizeof(reply)); + msg.msgId = FM_SET_NUM_OF_TASKS; + memcpy(msg.msgBody, &rsrcParams, sizeof(rsrcParams)); + replyLength = sizeof(uint32_t); + if ((err = XX_IpcSendMessage(p_Fm->h_IpcSessions[0], + (uint8_t*)&msg, + sizeof(msg.msgId) + sizeof(rsrcParams), + (uint8_t*)&reply, + &replyLength, + NULL, + NULL)) != E_OK) + RETURN_ERROR(MINOR, err, NO_MSG); + if (replyLength != sizeof(uint32_t)) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("IPC reply length mismatch")); + return (t_Error)(reply.error); + } + else if ((p_Fm->guestId != NCSW_MASTER_ID) && + p_Fm->baseAddr) + { + DBG(WARNING, ("No IPC - can't validate FM total-num-of-tasks.")); + fman_set_num_of_tasks(bmi_rg, hardwarePortId, numOfTasks, numOfExtraTasks); + } + else if (p_Fm->guestId != NCSW_MASTER_ID) + RETURN_ERROR(MAJOR, E_NOT_SUPPORTED, + ("running in guest-mode without neither IPC nor mapped register!")); + + if (!initialConfig) + { + /* !initialConfig - runtime change of existing value. + * - read the current number of tasks */ + currentVal = fman_get_num_of_tasks(bmi_rg, hardwarePortId); + currentExtraVal = fman_get_num_extra_tasks(bmi_rg, hardwarePortId); + } + + if (numOfExtraTasks > currentExtraVal) + p_Fm->p_FmStateStruct->extraTasksPoolSize = + (uint8_t)MAX(p_Fm->p_FmStateStruct->extraTasksPoolSize, numOfExtraTasks); + + /* check that there are enough uncommitted tasks */ + if ((p_Fm->p_FmStateStruct->accumulatedNumOfTasks - currentVal + numOfTasks) > + (p_Fm->p_FmStateStruct->totalNumOfTasks - p_Fm->p_FmStateStruct->extraTasksPoolSize)) + RETURN_ERROR(MAJOR, E_NOT_AVAILABLE, + ("Requested numOfTasks and extra tasks pool for fm%d exceed total numOfTasks.", + p_Fm->p_FmStateStruct->fmId)); + else + { + ASSERT_COND(p_Fm->p_FmStateStruct->accumulatedNumOfTasks >= currentVal); + /* update accumulated */ + p_Fm->p_FmStateStruct->accumulatedNumOfTasks -= currentVal; + p_Fm->p_FmStateStruct->accumulatedNumOfTasks += numOfTasks; + fman_set_num_of_tasks(bmi_rg, hardwarePortId, numOfTasks, numOfExtraTasks); + } + + return E_OK; +} + +t_Error FmSetNumOfOpenDmas(t_Handle h_Fm, + uint8_t hardwarePortId, + uint8_t *p_NumOfOpenDmas, + uint8_t *p_NumOfExtraOpenDmas, + bool initialConfig) + +{ + t_Fm *p_Fm = (t_Fm *)h_Fm; + t_Error err; + struct fman_bmi_regs *bmi_rg = p_Fm->p_FmBmiRegs; + uint8_t numOfOpenDmas = *p_NumOfOpenDmas, numOfExtraOpenDmas = *p_NumOfExtraOpenDmas; + uint8_t totalNumDmas = 0, currentVal = 0, currentExtraVal = 0; + + ASSERT_COND(IN_RANGE(1, hardwarePortId, 63)); + + if ((p_Fm->guestId != NCSW_MASTER_ID) && + !p_Fm->baseAddr && + p_Fm->h_IpcSessions[0]) + { + t_FmIpcPortRsrcParams rsrcParams; + t_FmIpcMsg msg; + t_FmIpcReply reply; + uint32_t replyLength; + + rsrcParams.hardwarePortId = hardwarePortId; + rsrcParams.val = numOfOpenDmas; + rsrcParams.extra = numOfExtraOpenDmas; + rsrcParams.boolInitialConfig = (uint8_t)initialConfig; + + memset(&msg, 0, sizeof(msg)); + memset(&reply, 0, sizeof(reply)); + msg.msgId = FM_SET_NUM_OF_OPEN_DMAS; + memcpy(msg.msgBody, &rsrcParams, sizeof(rsrcParams)); + replyLength = sizeof(uint32_t); + if ((err = XX_IpcSendMessage(p_Fm->h_IpcSessions[0], + (uint8_t*)&msg, + sizeof(msg.msgId) + sizeof(rsrcParams), + (uint8_t*)&reply, + &replyLength, + NULL, + NULL)) != E_OK) + RETURN_ERROR(MINOR, err, NO_MSG); + if (replyLength != sizeof(uint32_t)) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("IPC reply length mismatch")); + return (t_Error)(reply.error); + } +#ifdef FM_HAS_TOTAL_DMAS + else if (p_Fm->guestId != NCSW_MASTER_ID) + RETURN_ERROR(MAJOR, E_NOT_SUPPORTED, ("running in guest-mode without IPC!")); +#else + else if ((p_Fm->guestId != NCSW_MASTER_ID) && + p_Fm->baseAddr && + (p_Fm->p_FmStateStruct->revInfo.majorRev >= 6)) + { + /*DBG(WARNING, ("No IPC - can't validate FM total-num-of-dmas."));*/ + + if (!numOfOpenDmas) + { + /* first config without explic it value: Do Nothing - reset value shouldn't be + changed, read register for port save */ + *p_NumOfOpenDmas = fman_get_num_of_dmas(bmi_rg, hardwarePortId); + *p_NumOfExtraOpenDmas = fman_get_num_extra_dmas(bmi_rg, hardwarePortId); + } + else + /* whether it is the first time with explicit value, or runtime "set" - write register */ + fman_set_num_of_open_dmas(bmi_rg, + hardwarePortId, + numOfOpenDmas, + numOfExtraOpenDmas, + p_Fm->p_FmStateStruct->accumulatedNumOfOpenDmas + p_Fm->p_FmStateStruct->extraOpenDmasPoolSize); + } + else if (p_Fm->guestId != NCSW_MASTER_ID) + RETURN_ERROR(MAJOR, E_NOT_SUPPORTED, + ("running in guest-mode without neither IPC nor mapped register!")); +#endif /* FM_HAS_TOTAL_DMAS */ + + if (!initialConfig) + { + /* !initialConfig - runtime change of existing value. + * - read the current number of open Dma's */ + currentExtraVal = fman_get_num_extra_dmas(bmi_rg, hardwarePortId); + currentVal = fman_get_num_of_dmas(bmi_rg, hardwarePortId); + } + +#ifdef FM_NO_GUARANTEED_RESET_VALUES + /* it's illegal to be in a state where this is not the first set and no value is specified */ + ASSERT_COND(initialConfig || numOfOpenDmas); + if (!numOfOpenDmas) + { + /* !numOfOpenDmas - first configuration according to values in regs. + * - read the current number of open Dma's */ + currentExtraVal = fman_get_num_extra_dmas(bmi_rg, hardwarePortId); + currentVal = fman_get_num_of_dmas(bmi_rg, hardwarePortId); + /* This is the first configuration and user did not specify value (!numOfOpenDmas), + * reset values will be used and we just save these values for resource management */ + p_Fm->p_FmStateStruct->extraOpenDmasPoolSize = + (uint8_t)MAX(p_Fm->p_FmStateStruct->extraOpenDmasPoolSize, currentExtraVal); + p_Fm->p_FmStateStruct->accumulatedNumOfOpenDmas += currentVal; + *p_NumOfOpenDmas = currentVal; + *p_NumOfExtraOpenDmas = currentExtraVal; + return E_OK; + } +#endif /* FM_NO_GUARANTEED_RESET_VALUES */ + + if (numOfExtraOpenDmas > currentExtraVal) + p_Fm->p_FmStateStruct->extraOpenDmasPoolSize = + (uint8_t)MAX(p_Fm->p_FmStateStruct->extraOpenDmasPoolSize, numOfExtraOpenDmas); + +#ifdef FM_HAS_TOTAL_DMAS + if ((p_Fm->p_FmStateStruct->revInfo.majorRev < 6) && + (p_Fm->p_FmStateStruct->accumulatedNumOfOpenDmas - currentVal + numOfOpenDmas > + p_Fm->p_FmStateStruct->maxNumOfOpenDmas)) + RETURN_ERROR(MAJOR, E_NOT_AVAILABLE, + ("Requested numOfOpenDmas for fm%d exceeds total numOfOpenDmas.", + p_Fm->p_FmStateStruct->fmId)); +#else + if ((p_Fm->p_FmStateStruct->revInfo.majorRev >= 6) && +#ifdef FM_HEAVY_TRAFFIC_SEQUENCER_HANG_ERRATA_FMAN_A006981 + !((p_Fm->p_FmStateStruct->revInfo.majorRev == 6) && + (p_Fm->p_FmStateStruct->revInfo.minorRev == 0)) && +#endif /* FM_HEAVY_TRAFFIC_SEQUENCER_HANG_ERRATA_FMAN_A006981 */ + (p_Fm->p_FmStateStruct->accumulatedNumOfOpenDmas - currentVal + numOfOpenDmas > DMA_THRESH_MAX_COMMQ + 1)) + RETURN_ERROR(MAJOR, E_NOT_AVAILABLE, + ("Requested numOfOpenDmas for fm%d exceeds DMA Command queue (%d)", + p_Fm->p_FmStateStruct->fmId, DMA_THRESH_MAX_COMMQ+1)); +#endif /* FM_HAS_TOTAL_DMAS */ + else + { + ASSERT_COND(p_Fm->p_FmStateStruct->accumulatedNumOfOpenDmas >= currentVal); + /* update acummulated */ + p_Fm->p_FmStateStruct->accumulatedNumOfOpenDmas -= currentVal; + p_Fm->p_FmStateStruct->accumulatedNumOfOpenDmas += numOfOpenDmas; + +#ifdef FM_HAS_TOTAL_DMAS + if (p_Fm->p_FmStateStruct->revInfo.majorRev < 6) + totalNumDmas = (uint8_t)(p_Fm->p_FmStateStruct->accumulatedNumOfOpenDmas + p_Fm->p_FmStateStruct->extraOpenDmasPoolSize); +#endif /* FM_HAS_TOTAL_DMAS */ + fman_set_num_of_open_dmas(bmi_rg, + hardwarePortId, + numOfOpenDmas, + numOfExtraOpenDmas, + totalNumDmas); + } + + return E_OK; +} + +#if (DPAA_VERSION >= 11) +t_Error FmVSPCheckRelativeProfile(t_Handle h_Fm, + e_FmPortType portType, + uint8_t portId, + uint16_t relativeProfile) +{ + t_Fm *p_Fm; + t_FmSp *p_FmPcdSp; + uint8_t swPortIndex=0, hardwarePortId; + + ASSERT_COND(h_Fm); + p_Fm = (t_Fm*)h_Fm; + + hardwarePortId = SwPortIdToHwPortId(portType, + portId, + p_Fm->p_FmStateStruct->revInfo.majorRev, + p_Fm->p_FmStateStruct->revInfo.minorRev); + ASSERT_COND(hardwarePortId); + HW_PORT_ID_TO_SW_PORT_INDX(swPortIndex, hardwarePortId); + + p_FmPcdSp = p_Fm->p_FmSp; + ASSERT_COND(p_FmPcdSp); + + if (!p_FmPcdSp->portsMapping[swPortIndex].numOfProfiles) + RETURN_ERROR(MAJOR, E_INVALID_STATE , ("Port has no allocated profiles")); + if (relativeProfile >= p_FmPcdSp->portsMapping[swPortIndex].numOfProfiles) + RETURN_ERROR(MAJOR, E_NOT_IN_RANGE , ("Profile id is out of range")); + + return E_OK; +} + +t_Error FmVSPGetAbsoluteProfileId(t_Handle h_Fm, + e_FmPortType portType, + uint8_t portId, + uint16_t relativeProfile, + uint16_t *p_AbsoluteId) +{ + t_Fm *p_Fm; + t_FmSp *p_FmPcdSp; + uint8_t swPortIndex=0, hardwarePortId; + t_Error err; + + ASSERT_COND(h_Fm); + p_Fm = (t_Fm*)h_Fm; + + err = FmVSPCheckRelativeProfile(h_Fm, portType, portId, relativeProfile); + if (err != E_OK) + return err; + + hardwarePortId = SwPortIdToHwPortId(portType, + portId, + p_Fm->p_FmStateStruct->revInfo.majorRev, + p_Fm->p_FmStateStruct->revInfo.minorRev); + ASSERT_COND(hardwarePortId); + HW_PORT_ID_TO_SW_PORT_INDX(swPortIndex, hardwarePortId); + + p_FmPcdSp = p_Fm->p_FmSp; + ASSERT_COND(p_FmPcdSp); + + *p_AbsoluteId = (uint16_t)(p_FmPcdSp->portsMapping[swPortIndex].profilesBase + relativeProfile); + + return E_OK; +} +#endif /* (DPAA_VERSION >= 11) */ + +static t_Error InitFmDma(t_Fm *p_Fm) +{ + t_Error err; + + err = (t_Error)fman_dma_init(p_Fm->p_FmDmaRegs, p_Fm->p_FmDriverParam); + if (err != E_OK) + return err; + + /* Allocate MURAM for CAM */ + p_Fm->camBaseAddr = PTR_TO_UINT(FM_MURAM_AllocMem(p_Fm->h_FmMuram, + (uint32_t)(p_Fm->p_FmDriverParam->dma_cam_num_of_entries*DMA_CAM_SIZEOF_ENTRY), + DMA_CAM_ALIGN)); + if (!p_Fm->camBaseAddr) + RETURN_ERROR(MAJOR, E_NO_MEMORY, ("MURAM alloc for DMA CAM failed")); + + WRITE_BLOCK(UINT_TO_PTR(p_Fm->camBaseAddr), + 0, + (uint32_t)(p_Fm->p_FmDriverParam->dma_cam_num_of_entries*DMA_CAM_SIZEOF_ENTRY)); + + if (p_Fm->p_FmStateStruct->revInfo.majorRev == 2) + { + FM_MURAM_FreeMem(p_Fm->h_FmMuram, UINT_TO_PTR(p_Fm->camBaseAddr)); + + p_Fm->camBaseAddr = PTR_TO_UINT(FM_MURAM_AllocMem(p_Fm->h_FmMuram, + (uint32_t)(p_Fm->p_FmDriverParam->dma_cam_num_of_entries*72 + 128), + 64)); + if (!p_Fm->camBaseAddr) + RETURN_ERROR(MAJOR, E_NO_MEMORY, ("MURAM alloc for DMA CAM failed")); + + WRITE_BLOCK(UINT_TO_PTR(p_Fm->camBaseAddr), + 0, + (uint32_t)(p_Fm->p_FmDriverParam->dma_cam_num_of_entries*72 + 128)); + + switch(p_Fm->p_FmDriverParam->dma_cam_num_of_entries) + { + case (8): + WRITE_UINT32(*(uint32_t*)p_Fm->camBaseAddr, 0xff000000); + break; + case (16): + WRITE_UINT32(*(uint32_t*)p_Fm->camBaseAddr, 0xffff0000); + break; + case (24): + WRITE_UINT32(*(uint32_t*)p_Fm->camBaseAddr, 0xffffff00); + break; + case (32): + WRITE_UINT32(*(uint32_t*)p_Fm->camBaseAddr, 0xffffffff); + break; + default: + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("wrong dma_cam_num_of_entries")); + } + } + + p_Fm->p_FmDriverParam->cam_base_addr = + (uint32_t)(XX_VirtToPhys(UINT_TO_PTR(p_Fm->camBaseAddr)) - p_Fm->fmMuramPhysBaseAddr); + + return E_OK; +} + +static t_Error InitFmFpm(t_Fm *p_Fm) +{ + return (t_Error)fman_fpm_init(p_Fm->p_FmFpmRegs, p_Fm->p_FmDriverParam); +} + +static t_Error InitFmBmi(t_Fm *p_Fm) +{ + return (t_Error)fman_bmi_init(p_Fm->p_FmBmiRegs, p_Fm->p_FmDriverParam); +} + +static t_Error InitFmQmi(t_Fm *p_Fm) +{ + return (t_Error)fman_qmi_init(p_Fm->p_FmQmiRegs, p_Fm->p_FmDriverParam); +} + +static t_Error InitGuestMode(t_Fm *p_Fm) +{ + t_Error err = E_OK; + int i; + t_FmIpcMsg msg; + t_FmIpcReply reply; + uint32_t replyLength; + + ASSERT_COND(p_Fm); + ASSERT_COND(p_Fm->guestId != NCSW_MASTER_ID); + + /* build the FM guest partition IPC address */ + if (Sprint (p_Fm->fmModuleName, "FM_%d_%d",p_Fm->p_FmStateStruct->fmId, p_Fm->guestId) != (p_Fm->guestId<10 ? 6:7)) + RETURN_ERROR(MAJOR, E_INVALID_STATE, ("Sprint failed")); + + /* build the FM master partition IPC address */ + memset(p_Fm->fmIpcHandlerModuleName, 0, (sizeof(char)) * MODULE_NAME_SIZE); + if (Sprint (p_Fm->fmIpcHandlerModuleName[0], "FM_%d_%d",p_Fm->p_FmStateStruct->fmId, NCSW_MASTER_ID) != 6) + RETURN_ERROR(MAJOR, E_INVALID_STATE, ("Sprint failed")); + + for (i=0;i<e_FM_EV_DUMMY_LAST;i++) + p_Fm->intrMng[i].f_Isr = UnimplementedIsr; + + p_Fm->h_IpcSessions[0] = XX_IpcInitSession(p_Fm->fmIpcHandlerModuleName[0], p_Fm->fmModuleName); + if (p_Fm->h_IpcSessions[0]) + { + uint8_t isMasterAlive; + t_FmIpcParams ipcParams; + + err = XX_IpcRegisterMsgHandler(p_Fm->fmModuleName, FmGuestHandleIpcMsgCB, p_Fm, FM_IPC_MAX_REPLY_SIZE); + if (err) + RETURN_ERROR(MAJOR, err, NO_MSG); + + memset(&msg, 0, sizeof(msg)); + memset(&reply, 0, sizeof(reply)); + msg.msgId = FM_MASTER_IS_ALIVE; + msg.msgBody[0] = p_Fm->guestId; + replyLength = sizeof(uint32_t) + sizeof(uint8_t); + do + { + blockingFlag = TRUE; + if ((err = XX_IpcSendMessage(p_Fm->h_IpcSessions[0], + (uint8_t*)&msg, + sizeof(msg.msgId)+sizeof(p_Fm->guestId), + (uint8_t*)&reply, + &replyLength, + IpcMsgCompletionCB, + p_Fm)) != E_OK) + REPORT_ERROR(MINOR, err, NO_MSG); + while (blockingFlag) ; + if (replyLength != (sizeof(uint32_t) + sizeof(uint8_t))) + REPORT_ERROR(MAJOR, E_INVALID_VALUE, ("IPC reply length mismatch")); + isMasterAlive = *(uint8_t*)(reply.replyBody); + } while (!isMasterAlive); + + /* read FM parameters and save */ + memset(&msg, 0, sizeof(msg)); + memset(&reply, 0, sizeof(reply)); + msg.msgId = FM_GET_PARAMS; + replyLength = sizeof(uint32_t) + sizeof(t_FmIpcParams); + if ((err = XX_IpcSendMessage(p_Fm->h_IpcSessions[0], + (uint8_t*)&msg, + sizeof(msg.msgId), + (uint8_t*)&reply, + &replyLength, + NULL, + NULL)) != E_OK) + RETURN_ERROR(MAJOR, err, NO_MSG); + if (replyLength != (sizeof(uint32_t) + sizeof(t_FmIpcParams))) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("IPC reply length mismatch")); + memcpy((uint8_t*)&ipcParams, reply.replyBody, sizeof(t_FmIpcParams)); + + p_Fm->p_FmStateStruct->fmClkFreq = ipcParams.fmClkFreq; + p_Fm->p_FmStateStruct->fmMacClkFreq = ipcParams.fmMacClkFreq; + p_Fm->p_FmStateStruct->revInfo.majorRev = ipcParams.majorRev; + p_Fm->p_FmStateStruct->revInfo.minorRev = ipcParams.minorRev; + } + else + { + DBG(WARNING, ("FM Guest mode - without IPC")); + if (!p_Fm->p_FmStateStruct->fmClkFreq) + RETURN_ERROR(MAJOR, E_INVALID_STATE, ("No fmClkFreq configured for guest without IPC")); + if (p_Fm->baseAddr) + { + fman_get_revision(p_Fm->p_FmFpmRegs, + &p_Fm->p_FmStateStruct->revInfo.majorRev, + &p_Fm->p_FmStateStruct->revInfo.minorRev); + + } + } + +#if (DPAA_VERSION >= 11) + p_Fm->partVSPBase = AllocVSPsForPartition(p_Fm, p_Fm->partVSPBase, p_Fm->partNumOfVSPs, p_Fm->guestId); + if (p_Fm->partVSPBase == (uint8_t)(ILLEGAL_BASE)) + DBG(WARNING, ("partition VSPs allocation is FAILED")); +#endif /* (DPAA_VERSION >= 11) */ + + /* General FM driver initialization */ + if (p_Fm->baseAddr) + p_Fm->fmMuramPhysBaseAddr = + (uint64_t)(XX_VirtToPhys(UINT_TO_PTR(p_Fm->baseAddr + FM_MM_MURAM))); + + XX_Free(p_Fm->p_FmDriverParam); + p_Fm->p_FmDriverParam = NULL; + + if ((p_Fm->guestId == NCSW_MASTER_ID) || + (p_Fm->h_IpcSessions[0])) + { + FM_DisableRamsEcc(p_Fm); + FmMuramClear(p_Fm->h_FmMuram); + FM_EnableRamsEcc(p_Fm); + } + + return E_OK; +} + +static __inline__ enum fman_exceptions FmanExceptionTrans(e_FmExceptions exception) +{ + switch (exception) { + case e_FM_EX_DMA_BUS_ERROR: + return E_FMAN_EX_DMA_BUS_ERROR; + case e_FM_EX_DMA_READ_ECC: + return E_FMAN_EX_DMA_READ_ECC; + case e_FM_EX_DMA_SYSTEM_WRITE_ECC: + return E_FMAN_EX_DMA_SYSTEM_WRITE_ECC; + case e_FM_EX_DMA_FM_WRITE_ECC: + return E_FMAN_EX_DMA_FM_WRITE_ECC; + case e_FM_EX_FPM_STALL_ON_TASKS: + return E_FMAN_EX_FPM_STALL_ON_TASKS; + case e_FM_EX_FPM_SINGLE_ECC: + return E_FMAN_EX_FPM_SINGLE_ECC; + case e_FM_EX_FPM_DOUBLE_ECC: + return E_FMAN_EX_FPM_DOUBLE_ECC; + case e_FM_EX_QMI_SINGLE_ECC: + return E_FMAN_EX_QMI_SINGLE_ECC; + case e_FM_EX_QMI_DOUBLE_ECC: + return E_FMAN_EX_QMI_DOUBLE_ECC; + case e_FM_EX_QMI_DEQ_FROM_UNKNOWN_PORTID: + return E_FMAN_EX_QMI_DEQ_FROM_UNKNOWN_PORTID; + case e_FM_EX_BMI_LIST_RAM_ECC: + return E_FMAN_EX_BMI_LIST_RAM_ECC; + case e_FM_EX_BMI_STORAGE_PROFILE_ECC: + return E_FMAN_EX_BMI_STORAGE_PROFILE_ECC; + case e_FM_EX_BMI_STATISTICS_RAM_ECC: + return E_FMAN_EX_BMI_STATISTICS_RAM_ECC; + case e_FM_EX_BMI_DISPATCH_RAM_ECC: + return E_FMAN_EX_BMI_DISPATCH_RAM_ECC; + case e_FM_EX_IRAM_ECC: + return E_FMAN_EX_IRAM_ECC; + case e_FM_EX_MURAM_ECC: + return E_FMAN_EX_MURAM_ECC; + default: + return E_FMAN_EX_DMA_BUS_ERROR; + } +} + +uint8_t SwPortIdToHwPortId(e_FmPortType type, uint8_t relativePortId, uint8_t majorRev, uint8_t minorRev) +{ + switch (type) + { + case (e_FM_PORT_TYPE_OH_OFFLINE_PARSING): + case (e_FM_PORT_TYPE_OH_HOST_COMMAND): + CHECK_PORT_ID_OH_PORTS(relativePortId); + return (uint8_t)(BASE_OH_PORTID + (relativePortId)); + case (e_FM_PORT_TYPE_RX): + CHECK_PORT_ID_1G_RX_PORTS(relativePortId); + return (uint8_t)(BASE_1G_RX_PORTID + (relativePortId)); + case (e_FM_PORT_TYPE_RX_10G): + /* The 10G port in T1024 (FMan Version 6.4) is the first port. + * This is the reason why the 1G port offset is used. + */ + if (majorRev == 6 && minorRev == 4) + { + CHECK_PORT_ID_1G_RX_PORTS(relativePortId); + return (uint8_t)(BASE_1G_RX_PORTID + (relativePortId)); + } + else + { + CHECK_PORT_ID_10G_RX_PORTS(relativePortId); + return (uint8_t)(BASE_10G_RX_PORTID + (relativePortId)); + } + case (e_FM_PORT_TYPE_TX): + CHECK_PORT_ID_1G_TX_PORTS(relativePortId); + return (uint8_t)(BASE_1G_TX_PORTID + (relativePortId)); + case (e_FM_PORT_TYPE_TX_10G): + /* The 10G port in T1024 (FMan Version 6.4) is the first port. + * This is the reason why the 1G port offset is used. + */ + if (majorRev == 6 && minorRev == 4) + { + CHECK_PORT_ID_1G_TX_PORTS(relativePortId); + return (uint8_t)(BASE_1G_TX_PORTID + (relativePortId)); + } + else + { + CHECK_PORT_ID_10G_TX_PORTS(relativePortId); + return (uint8_t)(BASE_10G_TX_PORTID + (relativePortId)); + } + default: + REPORT_ERROR(MAJOR, E_INVALID_VALUE, ("Illegal port type")); + return 0; + } +} + +#if (defined(DEBUG_ERRORS) && (DEBUG_ERRORS > 0)) +t_Error FmDumpPortRegs (t_Handle h_Fm, uint8_t hardwarePortId) +{ + t_Fm *p_Fm = (t_Fm *)h_Fm; + + DECLARE_DUMP; + + ASSERT_COND(IN_RANGE(1, hardwarePortId, 63)); + + SANITY_CHECK_RETURN_ERROR(p_Fm, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(((p_Fm->guestId == NCSW_MASTER_ID) || + p_Fm->baseAddr), E_INVALID_OPERATION); + + DUMP_TITLE(&p_Fm->p_FmBmiRegs->fmbm_pp[hardwarePortId-1], ("fmbm_pp for port %u", (hardwarePortId))); + DUMP_MEMORY(&p_Fm->p_FmBmiRegs->fmbm_pp[hardwarePortId-1], sizeof(uint32_t)); + + DUMP_TITLE(&p_Fm->p_FmBmiRegs->fmbm_pfs[hardwarePortId-1], ("fmbm_pfs for port %u", (hardwarePortId ))); + DUMP_MEMORY(&p_Fm->p_FmBmiRegs->fmbm_pfs[hardwarePortId-1], sizeof(uint32_t)); + + DUMP_TITLE(&p_Fm->p_FmBmiRegs->fmbm_spliodn[hardwarePortId-1], ("fmbm_spliodn for port %u", (hardwarePortId))); + DUMP_MEMORY(&p_Fm->p_FmBmiRegs->fmbm_spliodn[hardwarePortId-1], sizeof(uint32_t)); + + DUMP_TITLE(&p_Fm->p_FmFpmRegs->fmfp_ps[hardwarePortId], ("fmfp_ps for port %u", (hardwarePortId))); + DUMP_MEMORY(&p_Fm->p_FmFpmRegs->fmfp_ps[hardwarePortId], sizeof(uint32_t)); + + DUMP_TITLE(&p_Fm->p_FmDmaRegs->fmdmplr[hardwarePortId/2], ("fmdmplr for port %u", (hardwarePortId))); + DUMP_MEMORY(&p_Fm->p_FmDmaRegs->fmdmplr[hardwarePortId/2], sizeof(uint32_t)); + + return E_OK; +} +#endif /* (defined(DEBUG_ERRORS) && (DEBUG_ERRORS > 0)) */ + + +/*****************************************************************************/ +/* API Init unit functions */ +/*****************************************************************************/ +t_Handle FM_Config(t_FmParams *p_FmParam) +{ + t_Fm *p_Fm; + uint8_t i; + uintptr_t baseAddr; + + SANITY_CHECK_RETURN_VALUE(p_FmParam, E_NULL_POINTER, NULL); + SANITY_CHECK_RETURN_VALUE(((p_FmParam->firmware.p_Code && p_FmParam->firmware.size) || + (!p_FmParam->firmware.p_Code && !p_FmParam->firmware.size)), + E_INVALID_VALUE, NULL); + + baseAddr = p_FmParam->baseAddr; + + /* Allocate FM structure */ + p_Fm = (t_Fm *) XX_Malloc(sizeof(t_Fm)); + if (!p_Fm) + { + REPORT_ERROR(MAJOR, E_NO_MEMORY, ("FM driver structure")); + return NULL; + } + memset(p_Fm, 0, sizeof(t_Fm)); + + p_Fm->p_FmStateStruct = (t_FmStateStruct *) XX_Malloc(sizeof(t_FmStateStruct)); + if (!p_Fm->p_FmStateStruct) + { + XX_Free(p_Fm); + REPORT_ERROR(MAJOR, E_NO_MEMORY, ("FM Status structure")); + return NULL; + } + memset(p_Fm->p_FmStateStruct, 0, sizeof(t_FmStateStruct)); + + /* Initialize FM parameters which will be kept by the driver */ + p_Fm->p_FmStateStruct->fmId = p_FmParam->fmId; + p_Fm->guestId = p_FmParam->guestId; + + for (i=0; i<FM_MAX_NUM_OF_HW_PORT_IDS; i++) + p_Fm->p_FmStateStruct->portsTypes[i] = e_FM_PORT_TYPE_DUMMY; + + /* Allocate the FM driver's parameters structure */ + p_Fm->p_FmDriverParam = (struct fman_cfg *)XX_Malloc(sizeof(struct fman_cfg)); + if (!p_Fm->p_FmDriverParam) + { + XX_Free(p_Fm->p_FmStateStruct); + XX_Free(p_Fm); + REPORT_ERROR(MAJOR, E_NO_MEMORY, ("FM driver parameters")); + return NULL; + } + memset(p_Fm->p_FmDriverParam, 0, sizeof(struct fman_cfg)); + +#if (DPAA_VERSION >= 11) + p_Fm->p_FmSp = (t_FmSp *)XX_Malloc(sizeof(t_FmSp)); + if (!p_Fm->p_FmSp) + { + XX_Free(p_Fm->p_FmDriverParam); + XX_Free(p_Fm->p_FmStateStruct); + XX_Free(p_Fm); + REPORT_ERROR(MAJOR, E_NO_MEMORY, ("allocation for internal data structure failed")); + return NULL; + } + memset(p_Fm->p_FmSp, 0, sizeof(t_FmSp)); + + for (i=0; i<FM_VSP_MAX_NUM_OF_ENTRIES; i++) + p_Fm->p_FmSp->profiles[i].profilesMng.ownerId = (uint8_t)ILLEGAL_BASE; +#endif /* (DPAA_VERSION >= 11) */ + + /* Initialize FM parameters which will be kept by the driver */ + p_Fm->p_FmStateStruct->fmId = p_FmParam->fmId; + p_Fm->h_FmMuram = p_FmParam->h_FmMuram; + p_Fm->h_App = p_FmParam->h_App; + p_Fm->p_FmStateStruct->fmClkFreq = p_FmParam->fmClkFreq; + p_Fm->p_FmStateStruct->fmMacClkFreq = p_FmParam->fmClkFreq / ((!p_FmParam->fmMacClkRatio)? 2: p_FmParam->fmMacClkRatio); + p_Fm->f_Exception = p_FmParam->f_Exception; + p_Fm->f_BusError = p_FmParam->f_BusError; + p_Fm->p_FmFpmRegs = (struct fman_fpm_regs *)UINT_TO_PTR(baseAddr + FM_MM_FPM); + p_Fm->p_FmBmiRegs = (struct fman_bmi_regs *)UINT_TO_PTR(baseAddr + FM_MM_BMI); + p_Fm->p_FmQmiRegs = (struct fman_qmi_regs *)UINT_TO_PTR(baseAddr + FM_MM_QMI); + p_Fm->p_FmDmaRegs = (struct fman_dma_regs *)UINT_TO_PTR(baseAddr + FM_MM_DMA); + p_Fm->p_FmRegs = (struct fman_regs *)UINT_TO_PTR(baseAddr + FM_MM_BMI); + p_Fm->baseAddr = baseAddr; + p_Fm->p_FmStateStruct->irq = p_FmParam->irq; + p_Fm->p_FmStateStruct->errIrq = p_FmParam->errIrq; + p_Fm->hcPortInitialized = FALSE; + p_Fm->independentMode = FALSE; + + p_Fm->h_Spinlock = XX_InitSpinlock(); + if (!p_Fm->h_Spinlock) + { + XX_Free(p_Fm->p_FmDriverParam); + XX_Free(p_Fm->p_FmStateStruct); + XX_Free(p_Fm); + REPORT_ERROR(MAJOR, E_INVALID_STATE, ("can't allocate spinlock!")); + return NULL; + } + +#if (DPAA_VERSION >= 11) + p_Fm->partVSPBase = p_FmParam->partVSPBase; + p_Fm->partNumOfVSPs = p_FmParam->partNumOfVSPs; + p_Fm->vspBaseAddr = p_FmParam->vspBaseAddr; +#endif /* (DPAA_VERSION >= 11) */ + + fman_defconfig(p_Fm->p_FmDriverParam, + !!(p_Fm->guestId == NCSW_MASTER_ID)); +/* overide macros dependent parameters */ +#ifdef FM_PEDANTIC_DMA + p_Fm->p_FmDriverParam->pedantic_dma = TRUE; + p_Fm->p_FmDriverParam->dma_aid_override = TRUE; +#endif /* FM_PEDANTIC_DMA */ +#ifndef FM_QMI_NO_DEQ_OPTIONS_SUPPORT + p_Fm->p_FmDriverParam->qmi_deq_option_support = TRUE; +#endif /* !FM_QMI_NO_DEQ_OPTIONS_SUPPORT */ + + p_Fm->p_FmStateStruct->ramsEccEnable = FALSE; + p_Fm->p_FmStateStruct->extraFifoPoolSize = 0; + p_Fm->p_FmStateStruct->exceptions = DEFAULT_exceptions; + p_Fm->resetOnInit = DEFAULT_resetOnInit; + p_Fm->f_ResetOnInitOverride = DEFAULT_resetOnInitOverrideCallback; + p_Fm->fwVerify = DEFAULT_VerifyUcode; + p_Fm->firmware.size = p_FmParam->firmware.size; + if (p_Fm->firmware.size) + { + p_Fm->firmware.p_Code = (uint32_t *)XX_Malloc(p_Fm->firmware.size); + if (!p_Fm->firmware.p_Code) + { + XX_FreeSpinlock(p_Fm->h_Spinlock); + XX_Free(p_Fm->p_FmStateStruct); + XX_Free(p_Fm->p_FmDriverParam); + XX_Free(p_Fm); + REPORT_ERROR(MAJOR, E_NO_MEMORY, ("FM firmware code")); + return NULL; + } + memcpy(p_Fm->firmware.p_Code, p_FmParam->firmware.p_Code ,p_Fm->firmware.size); + } + + if (p_Fm->guestId != NCSW_MASTER_ID) + return p_Fm; + + /* read revision */ + /* Chip dependent, will be configured in Init */ + fman_get_revision(p_Fm->p_FmFpmRegs, + &p_Fm->p_FmStateStruct->revInfo.majorRev, + &p_Fm->p_FmStateStruct->revInfo.minorRev); + +#ifdef FM_AID_MODE_NO_TNUM_SW005 + if (p_Fm->p_FmStateStruct->revInfo.majorRev >= 6) + p_Fm->p_FmDriverParam->dma_aid_mode = e_FM_DMA_AID_OUT_PORT_ID; +#endif /* FM_AID_MODE_NO_TNUM_SW005 */ +#ifndef FM_QMI_NO_DEQ_OPTIONS_SUPPORT + if (p_Fm->p_FmStateStruct->revInfo.majorRev != 4) + p_Fm->p_FmDriverParam->qmi_def_tnums_thresh = QMI_DEF_TNUMS_THRESH; +#endif /* FM_QMI_NO_DEQ_OPTIONS_SUPPORT */ + + p_Fm->p_FmStateStruct->totalFifoSize = 0; + p_Fm->p_FmStateStruct->totalNumOfTasks = + DEFAULT_totalNumOfTasks(p_Fm->p_FmStateStruct->revInfo.majorRev, + p_Fm->p_FmStateStruct->revInfo.minorRev); + +#ifdef FM_HAS_TOTAL_DMAS + p_Fm->p_FmStateStruct->maxNumOfOpenDmas = BMI_MAX_NUM_OF_DMAS; +#endif /* FM_HAS_TOTAL_DMAS */ +#if (DPAA_VERSION < 11) + p_Fm->p_FmDriverParam->dma_comm_qtsh_clr_emer = DEFAULT_dmaCommQLow; + p_Fm->p_FmDriverParam->dma_comm_qtsh_asrt_emer = DEFAULT_dmaCommQHigh; + p_Fm->p_FmDriverParam->dma_cam_num_of_entries = DEFAULT_dmaCamNumOfEntries; + p_Fm->p_FmDriverParam->dma_read_buf_tsh_clr_emer = DEFAULT_dmaReadIntBufLow; + p_Fm->p_FmDriverParam->dma_read_buf_tsh_asrt_emer = DEFAULT_dmaReadIntBufHigh; + p_Fm->p_FmDriverParam->dma_write_buf_tsh_clr_emer = DEFAULT_dmaWriteIntBufLow; + p_Fm->p_FmDriverParam->dma_write_buf_tsh_asrt_emer = DEFAULT_dmaWriteIntBufHigh; + p_Fm->p_FmDriverParam->dma_axi_dbg_num_of_beats = DEFAULT_axiDbgNumOfBeats; +#endif /* (DPAA_VERSION < 11) */ +#ifdef FM_NO_TNUM_AGING + p_Fm->p_FmDriverParam->tnum_aging_period = 0; +#endif + p_Fm->tnumAgingPeriod = p_Fm->p_FmDriverParam->tnum_aging_period; + + return p_Fm; +} + +/**************************************************************************//** + @Function FM_Init + + @Description Initializes the FM module + + @Param[in] h_Fm - FM module descriptor + + @Return E_OK on success; Error code otherwise. +*//***************************************************************************/ +t_Error FM_Init(t_Handle h_Fm) +{ + t_Fm *p_Fm = (t_Fm*)h_Fm; + struct fman_cfg *p_FmDriverParam = NULL; + t_Error err = E_OK; + int i; + t_FmRevisionInfo revInfo; + struct fman_rg fman_rg; + + SANITY_CHECK_RETURN_ERROR(p_Fm, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_Fm->p_FmDriverParam, E_INVALID_HANDLE); + + fman_rg.bmi_rg = p_Fm->p_FmBmiRegs; + fman_rg.qmi_rg = p_Fm->p_FmQmiRegs; + fman_rg.fpm_rg = p_Fm->p_FmFpmRegs; + fman_rg.dma_rg = p_Fm->p_FmDmaRegs; + + p_Fm->p_FmStateStruct->count1MicroBit = FM_TIMESTAMP_1_USEC_BIT; + p_Fm->p_FmDriverParam->num_of_fman_ctrl_evnt_regs = FM_NUM_OF_FMAN_CTRL_EVENT_REGS; + + if (p_Fm->guestId != NCSW_MASTER_ID) + return InitGuestMode(p_Fm); + + /* if user didn't configured totalFifoSize - (totalFifoSize=0) we configure default + * according to chip. otherwise, we use user's configuration. + */ + if (p_Fm->p_FmStateStruct->totalFifoSize == 0) + p_Fm->p_FmStateStruct->totalFifoSize = DEFAULT_totalFifoSize(p_Fm->p_FmStateStruct->revInfo.majorRev, + p_Fm->p_FmStateStruct->revInfo.minorRev); + + CHECK_INIT_PARAMETERS(p_Fm, CheckFmParameters); + + p_FmDriverParam = p_Fm->p_FmDriverParam; + + FM_GetRevision(p_Fm, &revInfo); + + /* clear revision-dependent non existing exception */ +#ifdef FM_NO_DISPATCH_RAM_ECC + if ((revInfo.majorRev != 4) && + (revInfo.majorRev < 6)) + p_Fm->p_FmStateStruct->exceptions &= ~FM_EX_BMI_DISPATCH_RAM_ECC; +#endif /* FM_NO_DISPATCH_RAM_ECC */ + +#ifdef FM_QMI_NO_ECC_EXCEPTIONS + if (revInfo.majorRev == 4) + p_Fm->p_FmStateStruct->exceptions &= ~(FM_EX_QMI_SINGLE_ECC | FM_EX_QMI_DOUBLE_ECC); +#endif /* FM_QMI_NO_ECC_EXCEPTIONS */ + +#ifdef FM_QMI_NO_SINGLE_ECC_EXCEPTION + if (revInfo.majorRev >= 6) + p_Fm->p_FmStateStruct->exceptions &= ~FM_EX_QMI_SINGLE_ECC; +#endif /* FM_QMI_NO_SINGLE_ECC_EXCEPTION */ + + FmMuramClear(p_Fm->h_FmMuram); + + /* clear CPG */ + IOMemSet32(UINT_TO_PTR(p_Fm->baseAddr + FM_MM_CGP), 0, FM_PORT_NUM_OF_CONGESTION_GRPS); + + /* add to the default exceptions the user's definitions */ + p_Fm->p_FmStateStruct->exceptions |= p_Fm->userSetExceptions; + + /* Reset the FM if required */ + if (p_Fm->resetOnInit) + { +#ifdef FM_UCODE_NOT_RESET_ERRATA_BUGZILLA6173 + if ((err = FwNotResetErratumBugzilla6173WA(p_Fm)) != E_OK) + RETURN_ERROR(MAJOR, err, NO_MSG); +#else /* not FM_UCODE_NOT_RESET_ERRATA_BUGZILLA6173 */ + + if (p_Fm->f_ResetOnInitOverride) + { + /* Perform user specific FMan reset */ + p_Fm->f_ResetOnInitOverride(h_Fm); + } + else + { + /* Perform FMan reset */ + FmReset(h_Fm); + } + + if (fman_is_qmi_halt_not_busy_state(p_Fm->p_FmQmiRegs)) + { + fman_resume(p_Fm->p_FmFpmRegs); + XX_UDelay(100); + } +#endif /* not FM_UCODE_NOT_RESET_ERRATA_BUGZILLA6173 */ + } + +#ifdef FM_UCODE_NOT_RESET_ERRATA_BUGZILLA6173 + if (!p_Fm->resetOnInit) /* Skip operations done in errata workaround */ + { +#endif /* FM_UCODE_NOT_RESET_ERRATA_BUGZILLA6173 */ + /* Load FMan-Controller code to IRAM */ + + ClearIRam(p_Fm); + + if (p_Fm->firmware.p_Code && (LoadFmanCtrlCode(p_Fm) != E_OK)) + RETURN_ERROR(MAJOR, E_INVALID_STATE, NO_MSG); +#ifdef FM_UCODE_NOT_RESET_ERRATA_BUGZILLA6173 + } +#endif /* FM_UCODE_NOT_RESET_ERRATA_BUGZILLA6173 */ + +#ifdef FM_CAPWAP_SUPPORT + /* save first 256 byte in MURAM */ + p_Fm->resAddr = PTR_TO_UINT(FM_MURAM_AllocMem(p_Fm->h_FmMuram, 256, 0)); + if (!p_Fm->resAddr) + RETURN_ERROR(MAJOR, E_NO_MEMORY, ("MURAM alloc for reserved Area failed")); + + WRITE_BLOCK(UINT_TO_PTR(p_Fm->resAddr), 0, 256); +#endif /* FM_CAPWAP_SUPPORT */ + +#if (DPAA_VERSION >= 11) + p_Fm->partVSPBase = AllocVSPsForPartition(h_Fm, p_Fm->partVSPBase, p_Fm->partNumOfVSPs, p_Fm->guestId); + if (p_Fm->partVSPBase == (uint8_t)(ILLEGAL_BASE)) + DBG(WARNING, ("partition VSPs allocation is FAILED")); +#endif /* (DPAA_VERSION >= 11) */ + + /* General FM driver initialization */ + p_Fm->fmMuramPhysBaseAddr = + (uint64_t)(XX_VirtToPhys(UINT_TO_PTR(p_Fm->baseAddr + FM_MM_MURAM))); + + for (i=0;i<e_FM_EV_DUMMY_LAST;i++) + p_Fm->intrMng[i].f_Isr = UnimplementedIsr; + for (i=0;i<FM_NUM_OF_FMAN_CTRL_EVENT_REGS;i++) + p_Fm->fmanCtrlIntr[i].f_Isr = UnimplementedFmanCtrlIsr; + + p_FmDriverParam->exceptions = p_Fm->p_FmStateStruct->exceptions; + + /**********************/ + /* Init DMA Registers */ + /**********************/ + err = InitFmDma(p_Fm); + if (err != E_OK) + { + FreeInitResources(p_Fm); + RETURN_ERROR(MAJOR, err, NO_MSG); + } + + /**********************/ + /* Init FPM Registers */ + /**********************/ + err = InitFmFpm(p_Fm); + if (err != E_OK) + { + FreeInitResources(p_Fm); + RETURN_ERROR(MAJOR, err, NO_MSG); + } + + /* define common resources */ + /* allocate MURAM for FIFO according to total size */ + p_Fm->fifoBaseAddr = PTR_TO_UINT(FM_MURAM_AllocMem(p_Fm->h_FmMuram, + p_Fm->p_FmStateStruct->totalFifoSize, + BMI_FIFO_ALIGN)); + if (!p_Fm->fifoBaseAddr) + { + FreeInitResources(p_Fm); + RETURN_ERROR(MAJOR, E_NO_MEMORY, ("MURAM alloc for BMI FIFO failed")); + } + + p_FmDriverParam->fifo_base_addr = (uint32_t)(XX_VirtToPhys(UINT_TO_PTR(p_Fm->fifoBaseAddr)) - p_Fm->fmMuramPhysBaseAddr); + p_FmDriverParam->total_fifo_size = p_Fm->p_FmStateStruct->totalFifoSize; + p_FmDriverParam->total_num_of_tasks = p_Fm->p_FmStateStruct->totalNumOfTasks; + p_FmDriverParam->clk_freq = p_Fm->p_FmStateStruct->fmClkFreq; + + /**********************/ + /* Init BMI Registers */ + /**********************/ + err = InitFmBmi(p_Fm); + if (err != E_OK) + { + FreeInitResources(p_Fm); + RETURN_ERROR(MAJOR, err, NO_MSG); + } + + /**********************/ + /* Init QMI Registers */ + /**********************/ + err = InitFmQmi(p_Fm); + if (err != E_OK) + { + FreeInitResources(p_Fm); + RETURN_ERROR(MAJOR, err, NO_MSG); + } + + /* build the FM master partition IPC address */ + if (Sprint (p_Fm->fmModuleName, "FM_%d_%d",p_Fm->p_FmStateStruct->fmId, NCSW_MASTER_ID) != 6) + { + FreeInitResources(p_Fm); + RETURN_ERROR(MAJOR, E_INVALID_STATE, ("Sprint failed")); + } + + err = XX_IpcRegisterMsgHandler(p_Fm->fmModuleName, FmHandleIpcMsgCB, p_Fm, FM_IPC_MAX_REPLY_SIZE); + if (err) + { + FreeInitResources(p_Fm); + RETURN_ERROR(MAJOR, err, NO_MSG); + } + + /* Register the FM interrupts handlers */ + if (p_Fm->p_FmStateStruct->irq != NO_IRQ) + { + XX_SetIntr(p_Fm->p_FmStateStruct->irq, FM_EventIsr, p_Fm); + XX_EnableIntr(p_Fm->p_FmStateStruct->irq); + } + + if (p_Fm->p_FmStateStruct->errIrq != NO_IRQ) + { + XX_SetIntr(p_Fm->p_FmStateStruct->errIrq, (void (*) (t_Handle))FM_ErrorIsr, p_Fm); + XX_EnableIntr(p_Fm->p_FmStateStruct->errIrq); + } + + err = (t_Error)fman_enable(&fman_rg , p_FmDriverParam); + if (err != E_OK) + return err; /* FIXME */ + + EnableTimeStamp(p_Fm); + + if (p_Fm->firmware.p_Code) + { + XX_Free(p_Fm->firmware.p_Code); + p_Fm->firmware.p_Code = NULL; + } + + XX_Free(p_Fm->p_FmDriverParam); + p_Fm->p_FmDriverParam = NULL; + + return E_OK; +} + +/**************************************************************************//** + @Function FM_Free + + @Description Frees all resources that were assigned to FM module. + + Calling this routine invalidates the descriptor. + + @Param[in] h_Fm - FM module descriptor + + @Return E_OK on success; Error code otherwise. +*//***************************************************************************/ +t_Error FM_Free(t_Handle h_Fm) +{ + t_Fm *p_Fm = (t_Fm*)h_Fm; + struct fman_rg fman_rg; + + SANITY_CHECK_RETURN_ERROR(p_Fm, E_INVALID_HANDLE); + + fman_rg.bmi_rg = p_Fm->p_FmBmiRegs; + fman_rg.qmi_rg = p_Fm->p_FmQmiRegs; + fman_rg.fpm_rg = p_Fm->p_FmFpmRegs; + fman_rg.dma_rg = p_Fm->p_FmDmaRegs; + + if (p_Fm->guestId != NCSW_MASTER_ID) + { +#if (DPAA_VERSION >= 11) + FreeVSPsForPartition(h_Fm, p_Fm->partVSPBase, p_Fm->partNumOfVSPs, p_Fm->guestId); + + if (p_Fm->p_FmSp) + { + XX_Free(p_Fm->p_FmSp); + p_Fm->p_FmSp = NULL; + } +#endif /* (DPAA_VERSION >= 11) */ + + if (p_Fm->fmModuleName[0] != 0) + XX_IpcUnregisterMsgHandler(p_Fm->fmModuleName); + + if (!p_Fm->recoveryMode) + XX_Free(p_Fm->p_FmStateStruct); + + XX_Free(p_Fm); + + return E_OK; + } + + fman_free_resources(&fman_rg); + + if ((p_Fm->guestId == NCSW_MASTER_ID) && (p_Fm->fmModuleName[0] != 0)) + XX_IpcUnregisterMsgHandler(p_Fm->fmModuleName); + + if (p_Fm->p_FmStateStruct) + { + if (p_Fm->p_FmStateStruct->irq != NO_IRQ) + { + XX_DisableIntr(p_Fm->p_FmStateStruct->irq); + XX_FreeIntr(p_Fm->p_FmStateStruct->irq); + } + if (p_Fm->p_FmStateStruct->errIrq != NO_IRQ) + { + XX_DisableIntr(p_Fm->p_FmStateStruct->errIrq); + XX_FreeIntr(p_Fm->p_FmStateStruct->errIrq); + } + } + +#if (DPAA_VERSION >= 11) + FreeVSPsForPartition(h_Fm, p_Fm->partVSPBase, p_Fm->partNumOfVSPs, p_Fm->guestId); + + if (p_Fm->p_FmSp) + { + XX_Free(p_Fm->p_FmSp); + p_Fm->p_FmSp = NULL; + } +#endif /* (DPAA_VERSION >= 11) */ + + if (p_Fm->h_Spinlock) + XX_FreeSpinlock(p_Fm->h_Spinlock); + + if (p_Fm->p_FmDriverParam) + { + if (p_Fm->firmware.p_Code) + XX_Free(p_Fm->firmware.p_Code); + XX_Free(p_Fm->p_FmDriverParam); + p_Fm->p_FmDriverParam = NULL; + } + + FreeInitResources(p_Fm); + + if (!p_Fm->recoveryMode && p_Fm->p_FmStateStruct) + XX_Free(p_Fm->p_FmStateStruct); + + XX_Free(p_Fm); + + return E_OK; +} + +/*************************************************/ +/* API Advanced Init unit functions */ +/*************************************************/ + +t_Error FM_ConfigResetOnInit(t_Handle h_Fm, bool enable) +{ + t_Fm *p_Fm = (t_Fm*)h_Fm; + + SANITY_CHECK_RETURN_ERROR(p_Fm, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_Fm->p_FmDriverParam, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR((p_Fm->guestId == NCSW_MASTER_ID), E_NOT_SUPPORTED); + + p_Fm->resetOnInit = enable; + + return E_OK; +} + +t_Error FM_ConfigResetOnInitOverrideCallback(t_Handle h_Fm, t_FmResetOnInitOverrideCallback *f_ResetOnInitOverride) +{ + t_Fm *p_Fm = (t_Fm*)h_Fm; + + SANITY_CHECK_RETURN_ERROR(p_Fm, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_Fm->p_FmDriverParam, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR((p_Fm->guestId == NCSW_MASTER_ID), E_NOT_SUPPORTED); + + p_Fm->f_ResetOnInitOverride = f_ResetOnInitOverride; + + return E_OK; +} + +t_Error FM_ConfigTotalFifoSize(t_Handle h_Fm, uint32_t totalFifoSize) +{ + t_Fm *p_Fm = (t_Fm*)h_Fm; + + SANITY_CHECK_RETURN_ERROR(p_Fm, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_Fm->p_FmDriverParam, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR((p_Fm->guestId == NCSW_MASTER_ID), E_NOT_SUPPORTED); + + p_Fm->p_FmStateStruct->totalFifoSize = totalFifoSize; + + return E_OK; +} + +t_Error FM_ConfigDmaCacheOverride(t_Handle h_Fm, e_FmDmaCacheOverride cacheOverride) +{ + t_Fm *p_Fm = (t_Fm*)h_Fm; + enum fman_dma_cache_override fsl_cache_override; + + SANITY_CHECK_RETURN_ERROR(p_Fm, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_Fm->p_FmDriverParam, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR((p_Fm->guestId == NCSW_MASTER_ID), E_NOT_SUPPORTED); + + FMAN_CACHE_OVERRIDE_TRANS(fsl_cache_override, cacheOverride) + p_Fm->p_FmDriverParam->dma_cache_override = fsl_cache_override; + + return E_OK; +} + +t_Error FM_ConfigDmaAidOverride(t_Handle h_Fm, bool aidOverride) +{ + t_Fm *p_Fm = (t_Fm*)h_Fm; + + SANITY_CHECK_RETURN_ERROR(p_Fm, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_Fm->p_FmDriverParam, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR((p_Fm->guestId == NCSW_MASTER_ID), E_NOT_SUPPORTED); + + p_Fm->p_FmDriverParam->dma_aid_override = aidOverride; + + return E_OK; +} + +t_Error FM_ConfigDmaAidMode(t_Handle h_Fm, e_FmDmaAidMode aidMode) +{ + t_Fm *p_Fm = (t_Fm*)h_Fm; + enum fman_dma_aid_mode fsl_aid_mode; + + SANITY_CHECK_RETURN_ERROR(p_Fm, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_Fm->p_FmDriverParam, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR((p_Fm->guestId == NCSW_MASTER_ID), E_NOT_SUPPORTED); + + FMAN_AID_MODE_TRANS(fsl_aid_mode, aidMode); + p_Fm->p_FmDriverParam->dma_aid_mode = fsl_aid_mode; + + return E_OK; +} + +t_Error FM_ConfigDmaAxiDbgNumOfBeats(t_Handle h_Fm, uint8_t axiDbgNumOfBeats) +{ + t_Fm *p_Fm = (t_Fm*)h_Fm; + + SANITY_CHECK_RETURN_ERROR(p_Fm, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_Fm->p_FmDriverParam, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR((p_Fm->guestId == NCSW_MASTER_ID), E_NOT_SUPPORTED); + +#if (DPAA_VERSION >= 11) + RETURN_ERROR(MINOR, E_NOT_SUPPORTED, ("Not available for this FM revision!")); +#else + p_Fm->p_FmDriverParam->dma_axi_dbg_num_of_beats = axiDbgNumOfBeats; + + return E_OK; +#endif /* (DPAA_VERSION >= 11) */ +} + +t_Error FM_ConfigDmaCamNumOfEntries(t_Handle h_Fm, uint8_t numOfEntries) +{ + t_Fm *p_Fm = (t_Fm*)h_Fm; + + SANITY_CHECK_RETURN_ERROR(p_Fm, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_Fm->p_FmDriverParam, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR((p_Fm->guestId == NCSW_MASTER_ID), E_NOT_SUPPORTED); + + p_Fm->p_FmDriverParam->dma_cam_num_of_entries = numOfEntries; + + return E_OK; +} + +t_Error FM_ConfigDmaDbgCounter(t_Handle h_Fm, e_FmDmaDbgCntMode fmDmaDbgCntMode) +{ + t_Fm *p_Fm = (t_Fm*)h_Fm; + enum fman_dma_dbg_cnt_mode fsl_dma_dbg_cnt; + + SANITY_CHECK_RETURN_ERROR(p_Fm, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_Fm->p_FmDriverParam, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR((p_Fm->guestId == NCSW_MASTER_ID), E_NOT_SUPPORTED); + + FMAN_DMA_DBG_CNT_TRANS(fsl_dma_dbg_cnt, fmDmaDbgCntMode); + p_Fm->p_FmDriverParam->dma_dbg_cnt_mode = fsl_dma_dbg_cnt; + + return E_OK; +} + +t_Error FM_ConfigDmaStopOnBusErr(t_Handle h_Fm, bool stop) +{ + t_Fm *p_Fm = (t_Fm*)h_Fm; + + SANITY_CHECK_RETURN_ERROR(p_Fm, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_Fm->p_FmDriverParam, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR((p_Fm->guestId == NCSW_MASTER_ID), E_NOT_SUPPORTED); + + p_Fm->p_FmDriverParam->dma_stop_on_bus_error = stop; + + return E_OK; +} + +t_Error FM_ConfigDmaEmergency(t_Handle h_Fm, t_FmDmaEmergency *p_Emergency) +{ + t_Fm *p_Fm = (t_Fm*)h_Fm; + enum fman_dma_emergency_level fsl_dma_emer; + + SANITY_CHECK_RETURN_ERROR(p_Fm, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_Fm->p_FmDriverParam, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR((p_Fm->guestId == NCSW_MASTER_ID), E_NOT_SUPPORTED); + + FMAN_DMA_EMER_TRANS(fsl_dma_emer, p_Emergency->emergencyLevel); + p_Fm->p_FmDriverParam->dma_en_emergency = TRUE; + p_Fm->p_FmDriverParam->dma_emergency_bus_select = (uint32_t)p_Emergency->emergencyBusSelect; + p_Fm->p_FmDriverParam->dma_emergency_level = fsl_dma_emer; + + return E_OK; +} + +t_Error FM_ConfigDmaEmergencySmoother(t_Handle h_Fm, uint32_t emergencyCnt) +{ + t_Fm *p_Fm = (t_Fm*)h_Fm; + + SANITY_CHECK_RETURN_ERROR(p_Fm, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_Fm->p_FmDriverParam, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR((p_Fm->guestId == NCSW_MASTER_ID), E_NOT_SUPPORTED); + + p_Fm->p_FmDriverParam->dma_en_emergency_smoother = TRUE; + p_Fm->p_FmDriverParam->dma_emergency_switch_counter = emergencyCnt; + + return E_OK; +} + +t_Error FM_ConfigDmaErr(t_Handle h_Fm, e_FmDmaErr dmaErr) +{ + t_Fm *p_Fm = (t_Fm*)h_Fm; + enum fman_dma_err fsl_dma_err; + + SANITY_CHECK_RETURN_ERROR(p_Fm, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_Fm->p_FmDriverParam, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR((p_Fm->guestId == NCSW_MASTER_ID), E_NOT_SUPPORTED); + + FMAN_DMA_ERR_TRANS(fsl_dma_err, dmaErr); + p_Fm->p_FmDriverParam->dma_err = fsl_dma_err; + + return E_OK; +} + +t_Error FM_ConfigCatastrophicErr(t_Handle h_Fm, e_FmCatastrophicErr catastrophicErr) +{ + t_Fm *p_Fm = (t_Fm*)h_Fm; + enum fman_catastrophic_err fsl_catastrophic_err; + + SANITY_CHECK_RETURN_ERROR(p_Fm, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_Fm->p_FmDriverParam, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR((p_Fm->guestId == NCSW_MASTER_ID), E_NOT_SUPPORTED); + + FMAN_CATASTROPHIC_ERR_TRANS(fsl_catastrophic_err, catastrophicErr); + p_Fm->p_FmDriverParam->catastrophic_err = fsl_catastrophic_err; + + return E_OK; +} + +t_Error FM_ConfigEnableMuramTestMode(t_Handle h_Fm) +{ + t_Fm *p_Fm = (t_Fm*)h_Fm; + + SANITY_CHECK_RETURN_ERROR(p_Fm, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_Fm->p_FmDriverParam, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR((p_Fm->guestId == NCSW_MASTER_ID), E_NOT_SUPPORTED); + + if (p_Fm->p_FmStateStruct->revInfo.majorRev >= 6) + RETURN_ERROR(MINOR, E_NOT_SUPPORTED, ("Not available for this FM revision!")); + + p_Fm->p_FmDriverParam->en_muram_test_mode = TRUE; + + return E_OK; +} + +t_Error FM_ConfigEnableIramTestMode(t_Handle h_Fm) +{ + t_Fm *p_Fm = (t_Fm*)h_Fm; + + SANITY_CHECK_RETURN_ERROR(p_Fm, E_INVALID_HANDLE ); + SANITY_CHECK_RETURN_ERROR(p_Fm->p_FmDriverParam, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR((p_Fm->guestId == NCSW_MASTER_ID), E_NOT_SUPPORTED); + + if (p_Fm->p_FmStateStruct->revInfo.majorRev >= 6) + RETURN_ERROR(MINOR, E_NOT_SUPPORTED, ("Not available for this FM revision!")); + + p_Fm->p_FmDriverParam->en_iram_test_mode = TRUE; + + return E_OK; +} + +t_Error FM_ConfigHaltOnExternalActivation(t_Handle h_Fm, bool enable) +{ + t_Fm *p_Fm = (t_Fm*)h_Fm; + + SANITY_CHECK_RETURN_ERROR(p_Fm, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_Fm->p_FmDriverParam, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR((p_Fm->guestId == NCSW_MASTER_ID), E_NOT_SUPPORTED); + + p_Fm->p_FmDriverParam->halt_on_external_activ = enable; + + return E_OK; +} + +t_Error FM_ConfigHaltOnUnrecoverableEccError(t_Handle h_Fm, bool enable) +{ + t_Fm *p_Fm = (t_Fm*)h_Fm; + + SANITY_CHECK_RETURN_ERROR(p_Fm, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_Fm->p_FmDriverParam, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR((p_Fm->guestId == NCSW_MASTER_ID), E_NOT_SUPPORTED); + + if (p_Fm->p_FmStateStruct->revInfo.majorRev >= 6) + RETURN_ERROR(MINOR, E_NOT_SUPPORTED, ("Not available for this FM revision!")); + + p_Fm->p_FmDriverParam->halt_on_unrecov_ecc_err = enable; + + return E_OK; +} + +t_Error FM_ConfigException(t_Handle h_Fm, e_FmExceptions exception, bool enable) +{ + t_Fm *p_Fm = (t_Fm*)h_Fm; + uint32_t bitMask = 0; + + SANITY_CHECK_RETURN_ERROR(p_Fm, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_Fm->p_FmDriverParam, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR((p_Fm->guestId == NCSW_MASTER_ID), E_NOT_SUPPORTED); + + GET_EXCEPTION_FLAG(bitMask, exception); + if (bitMask) + { + if (enable) + p_Fm->userSetExceptions |= bitMask; + else + p_Fm->p_FmStateStruct->exceptions &= ~bitMask; + } + else + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("Undefined exception")); + + return E_OK; +} + +t_Error FM_ConfigExternalEccRamsEnable(t_Handle h_Fm, bool enable) +{ + t_Fm *p_Fm = (t_Fm*)h_Fm; + + SANITY_CHECK_RETURN_ERROR(p_Fm, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_Fm->p_FmDriverParam, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR((p_Fm->guestId == NCSW_MASTER_ID), E_NOT_SUPPORTED); + + p_Fm->p_FmDriverParam->external_ecc_rams_enable = enable; + + return E_OK; +} + +t_Error FM_ConfigTnumAgingPeriod(t_Handle h_Fm, uint16_t tnumAgingPeriod) +{ + t_Fm *p_Fm = (t_Fm*)h_Fm; + + SANITY_CHECK_RETURN_ERROR(p_Fm, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_Fm->p_FmDriverParam, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR((p_Fm->guestId == NCSW_MASTER_ID), E_NOT_SUPPORTED); + + p_Fm->p_FmDriverParam->tnum_aging_period = tnumAgingPeriod; + p_Fm->tnumAgingPeriod = p_Fm->p_FmDriverParam->tnum_aging_period; + + return E_OK; +} + +/****************************************************/ +/* Hidden-DEBUG Only API */ +/****************************************************/ + +t_Error FM_ConfigThresholds(t_Handle h_Fm, t_FmThresholds *p_FmThresholds) +{ + t_Fm *p_Fm = (t_Fm*)h_Fm; + + SANITY_CHECK_RETURN_ERROR(p_Fm, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_Fm->p_FmDriverParam, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR((p_Fm->guestId == NCSW_MASTER_ID), E_NOT_SUPPORTED); + + p_Fm->p_FmDriverParam->disp_limit_tsh = p_FmThresholds->dispLimit; + p_Fm->p_FmDriverParam->prs_disp_tsh = p_FmThresholds->prsDispTh; + p_Fm->p_FmDriverParam->plcr_disp_tsh = p_FmThresholds->plcrDispTh; + p_Fm->p_FmDriverParam->kg_disp_tsh = p_FmThresholds->kgDispTh; + p_Fm->p_FmDriverParam->bmi_disp_tsh = p_FmThresholds->bmiDispTh; + p_Fm->p_FmDriverParam->qmi_enq_disp_tsh = p_FmThresholds->qmiEnqDispTh; + p_Fm->p_FmDriverParam->qmi_deq_disp_tsh = p_FmThresholds->qmiDeqDispTh; + p_Fm->p_FmDriverParam->fm_ctl1_disp_tsh = p_FmThresholds->fmCtl1DispTh; + p_Fm->p_FmDriverParam->fm_ctl2_disp_tsh = p_FmThresholds->fmCtl2DispTh; + + return E_OK; +} + +t_Error FM_ConfigDmaSosEmergencyThreshold(t_Handle h_Fm, uint32_t dmaSosEmergency) +{ + t_Fm *p_Fm = (t_Fm*)h_Fm; + + SANITY_CHECK_RETURN_ERROR(p_Fm, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_Fm->p_FmDriverParam, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR((p_Fm->guestId == NCSW_MASTER_ID), E_NOT_SUPPORTED); + + p_Fm->p_FmDriverParam->dma_sos_emergency = dmaSosEmergency; + + return E_OK; +} + +t_Error FM_ConfigDmaWriteBufThresholds(t_Handle h_Fm, t_FmDmaThresholds *p_FmDmaThresholds) + +{ + t_Fm *p_Fm = (t_Fm*)h_Fm; + + SANITY_CHECK_RETURN_ERROR(p_Fm, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_Fm->p_FmDriverParam, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR((p_Fm->guestId == NCSW_MASTER_ID), E_NOT_SUPPORTED); + +#if (DPAA_VERSION >= 11) + RETURN_ERROR(MINOR, E_NOT_SUPPORTED, ("Not available for this FM revision!")); +#else + p_Fm->p_FmDriverParam->dma_write_buf_tsh_asrt_emer = p_FmDmaThresholds->assertEmergency; + p_Fm->p_FmDriverParam->dma_write_buf_tsh_clr_emer = p_FmDmaThresholds->clearEmergency; + + return E_OK; +#endif +} + +t_Error FM_ConfigDmaCommQThresholds(t_Handle h_Fm, t_FmDmaThresholds *p_FmDmaThresholds) +{ + t_Fm *p_Fm = (t_Fm*)h_Fm; + + SANITY_CHECK_RETURN_ERROR(p_Fm, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_Fm->p_FmDriverParam, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR((p_Fm->guestId == NCSW_MASTER_ID), E_NOT_SUPPORTED); + + p_Fm->p_FmDriverParam->dma_comm_qtsh_asrt_emer = p_FmDmaThresholds->assertEmergency; + p_Fm->p_FmDriverParam->dma_comm_qtsh_clr_emer = p_FmDmaThresholds->clearEmergency; + + return E_OK; +} + +t_Error FM_ConfigDmaReadBufThresholds(t_Handle h_Fm, t_FmDmaThresholds *p_FmDmaThresholds) +{ + t_Fm *p_Fm = (t_Fm*)h_Fm; + + SANITY_CHECK_RETURN_ERROR(p_Fm, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_Fm->p_FmDriverParam, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR((p_Fm->guestId == NCSW_MASTER_ID), E_NOT_SUPPORTED); + +#if (DPAA_VERSION >= 11) + RETURN_ERROR(MINOR, E_NOT_SUPPORTED, ("Not available for this FM revision!")); +#else + p_Fm->p_FmDriverParam->dma_read_buf_tsh_clr_emer = p_FmDmaThresholds->clearEmergency; + p_Fm->p_FmDriverParam->dma_read_buf_tsh_asrt_emer = p_FmDmaThresholds->assertEmergency; + + return E_OK; +#endif +} + +t_Error FM_ConfigDmaWatchdog(t_Handle h_Fm, uint32_t watchdogValue) +{ + t_Fm *p_Fm = (t_Fm*)h_Fm; + + SANITY_CHECK_RETURN_ERROR(p_Fm, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_Fm->p_FmDriverParam, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR((p_Fm->guestId == NCSW_MASTER_ID), E_NOT_SUPPORTED); + + p_Fm->p_FmDriverParam->dma_watchdog = watchdogValue; + + return E_OK; +} + +t_Error FM_ConfigEnableCounters(t_Handle h_Fm) +{ + t_Fm *p_Fm = (t_Fm*)h_Fm; + + SANITY_CHECK_RETURN_ERROR(p_Fm, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_Fm->p_FmDriverParam, E_INVALID_HANDLE); +UNUSED(p_Fm); + + return E_OK; +} + +t_Error FmGetSetParams(t_Handle h_Fm, t_FmGetSetParams *p_Params) +{ + t_Fm* p_Fm = (t_Fm*)h_Fm; + if (p_Params->setParams.type & UPDATE_FM_CLD) + { + WRITE_UINT32(p_Fm->p_FmFpmRegs->fm_cld, GET_UINT32( + p_Fm->p_FmFpmRegs->fm_cld) | 0x00000800); + } + if (p_Params->setParams.type & CLEAR_IRAM_READY) + { + t_FMIramRegs *p_Iram = (t_FMIramRegs *)UINT_TO_PTR(p_Fm->baseAddr + FM_MM_IMEM); + WRITE_UINT32(p_Iram->iready,GET_UINT32(p_Iram->iready) & ~IRAM_READY); + } + if (p_Params->setParams.type & UPDATE_FPM_EXTC) + WRITE_UINT32(p_Fm->p_FmFpmRegs->fmfp_extc,0x80000000); + if (p_Params->setParams.type & UPDATE_FPM_EXTC_CLEAR) + WRITE_UINT32(p_Fm->p_FmFpmRegs->fmfp_extc,0x00800000); + if (p_Params->setParams.type & UPDATE_FPM_BRKC_SLP) + { + if (p_Params->setParams.sleep) + WRITE_UINT32(p_Fm->p_FmFpmRegs->fmfp_brkc, GET_UINT32( + p_Fm->p_FmFpmRegs->fmfp_brkc) | FPM_BRKC_SLP); + else + WRITE_UINT32(p_Fm->p_FmFpmRegs->fmfp_brkc, GET_UINT32( + p_Fm->p_FmFpmRegs->fmfp_brkc) & ~FPM_BRKC_SLP); + } + if (p_Params->getParams.type & GET_FM_CLD) + p_Params->getParams.fm_cld = GET_UINT32(p_Fm->p_FmFpmRegs->fm_cld); + if (p_Params->getParams.type & GET_FMQM_GS) + p_Params->getParams.fmqm_gs = GET_UINT32(p_Fm->p_FmQmiRegs->fmqm_gs); + if (p_Params->getParams.type & GET_FM_NPI) + p_Params->getParams.fm_npi = GET_UINT32(p_Fm->p_FmFpmRegs->fm_npi); + if (p_Params->getParams.type & GET_FMFP_EXTC) + p_Params->getParams.fmfp_extc = GET_UINT32(p_Fm->p_FmFpmRegs->fmfp_extc); + return E_OK; +} + + +/****************************************************/ +/* API Run-time Control uint functions */ +/****************************************************/ +void FM_EventIsr(t_Handle h_Fm) +{ +#define FM_M_CALL_1G_MAC_ISR(_id) \ + { \ + if (p_Fm->guestId != p_Fm->intrMng[(e_FmInterModuleEvent)(e_FM_EV_1G_MAC0+_id)].guestId) \ + SendIpcIsr(p_Fm, (e_FmInterModuleEvent)(e_FM_EV_1G_MAC0+_id), pending); \ + else \ + p_Fm->intrMng[(e_FmInterModuleEvent)(e_FM_EV_1G_MAC0+_id)].f_Isr(p_Fm->intrMng[(e_FmInterModuleEvent)(e_FM_EV_1G_MAC0+_id)].h_SrcHandle);\ + } +#define FM_M_CALL_10G_MAC_ISR(_id) \ + { \ + if (p_Fm->guestId != p_Fm->intrMng[(e_FmInterModuleEvent)(e_FM_EV_10G_MAC0+_id)].guestId) \ + SendIpcIsr(p_Fm, (e_FmInterModuleEvent)(e_FM_EV_10G_MAC0+_id), pending); \ + else \ + p_Fm->intrMng[(e_FmInterModuleEvent)(e_FM_EV_10G_MAC0+_id)].f_Isr(p_Fm->intrMng[(e_FmInterModuleEvent)(e_FM_EV_10G_MAC0+_id)].h_SrcHandle);\ + } + t_Fm *p_Fm = (t_Fm*)h_Fm; + uint32_t pending, event; + struct fman_fpm_regs *fpm_rg; + + SANITY_CHECK_RETURN(p_Fm, E_INVALID_HANDLE); + SANITY_CHECK_RETURN(!p_Fm->p_FmDriverParam, E_INVALID_HANDLE); + SANITY_CHECK_RETURN((p_Fm->guestId == NCSW_MASTER_ID), E_NOT_SUPPORTED); + + fpm_rg = p_Fm->p_FmFpmRegs; + + /* normal interrupts */ + pending = fman_get_normal_pending(fpm_rg); + if (!pending) + return; + if (pending & INTR_EN_WAKEUP) // this is a wake up from sleep interrupt + { + t_FmGetSetParams fmGetSetParams; + memset(&fmGetSetParams, 0, sizeof (t_FmGetSetParams)); + fmGetSetParams.setParams.type = UPDATE_FPM_BRKC_SLP; + fmGetSetParams.setParams.sleep = 0; + FmGetSetParams(h_Fm, &fmGetSetParams); + } + if (pending & INTR_EN_QMI) + QmiEvent(p_Fm); + if (pending & INTR_EN_PRS) + p_Fm->intrMng[e_FM_EV_PRS].f_Isr(p_Fm->intrMng[e_FM_EV_PRS].h_SrcHandle); + if (pending & INTR_EN_PLCR) + p_Fm->intrMng[e_FM_EV_PLCR].f_Isr(p_Fm->intrMng[e_FM_EV_PLCR].h_SrcHandle); +#ifdef CONFIG_FSL_SDK_FMAN_RTC_API + if (pending & INTR_EN_TMR) + p_Fm->intrMng[e_FM_EV_TMR].f_Isr(p_Fm->intrMng[e_FM_EV_TMR].h_SrcHandle); +#endif + + /* MAC events may belong to different partitions */ + if (pending & INTR_EN_1G_MAC0) + FM_M_CALL_1G_MAC_ISR(0); + if (pending & INTR_EN_1G_MAC1) + FM_M_CALL_1G_MAC_ISR(1); + if (pending & INTR_EN_1G_MAC2) + FM_M_CALL_1G_MAC_ISR(2); + if (pending & INTR_EN_1G_MAC3) + FM_M_CALL_1G_MAC_ISR(3); + if (pending & INTR_EN_1G_MAC4) + FM_M_CALL_1G_MAC_ISR(4); + if (pending & INTR_EN_1G_MAC5) + FM_M_CALL_1G_MAC_ISR(5); + if (pending & INTR_EN_1G_MAC6) + FM_M_CALL_1G_MAC_ISR(6); + if (pending & INTR_EN_1G_MAC7) + FM_M_CALL_1G_MAC_ISR(7); + if (pending & INTR_EN_10G_MAC0) + FM_M_CALL_10G_MAC_ISR(0); + if (pending & INTR_EN_10G_MAC1) + FM_M_CALL_10G_MAC_ISR(1); + + /* IM port events may belong to different partitions */ + if (pending & INTR_EN_REV0) + { + event = fman_get_controller_event(fpm_rg, 0); + if (p_Fm->guestId != p_Fm->intrMng[e_FM_EV_FMAN_CTRL_0].guestId) + /*TODO IPC ISR For Fman Ctrl */ + ASSERT_COND(0); + /* SendIpcIsr(p_Fm, e_FM_EV_FMAN_CTRL_0, pending); */ + else + p_Fm->fmanCtrlIntr[0].f_Isr(p_Fm->fmanCtrlIntr[0].h_SrcHandle, event); + + } + if (pending & INTR_EN_REV1) + { + event = fman_get_controller_event(fpm_rg, 1); + if (p_Fm->guestId != p_Fm->intrMng[e_FM_EV_FMAN_CTRL_1].guestId) + /*TODO IPC ISR For Fman Ctrl */ + ASSERT_COND(0); + /* SendIpcIsr(p_Fm, e_FM_EV_FMAN_CTRL_1, pending); */ + else + p_Fm->fmanCtrlIntr[1].f_Isr(p_Fm->fmanCtrlIntr[1].h_SrcHandle, event); + } + if (pending & INTR_EN_REV2) + { + event = fman_get_controller_event(fpm_rg, 2); + if (p_Fm->guestId != p_Fm->intrMng[e_FM_EV_FMAN_CTRL_2].guestId) + /*TODO IPC ISR For Fman Ctrl */ + ASSERT_COND(0); + /* SendIpcIsr(p_Fm, e_FM_EV_FMAN_CTRL_2, pending); */ + else + p_Fm->fmanCtrlIntr[2].f_Isr(p_Fm->fmanCtrlIntr[2].h_SrcHandle, event); + } + if (pending & INTR_EN_REV3) + { + event = fman_get_controller_event(fpm_rg, 3); + if (p_Fm->guestId != p_Fm->intrMng[e_FM_EV_FMAN_CTRL_3].guestId) + /*TODO IPC ISR For Fman Ctrl */ + ASSERT_COND(0); + /* SendIpcIsr(p_Fm, e_FM_EV_FMAN_CTRL_2, pendin3); */ + else + p_Fm->fmanCtrlIntr[3].f_Isr(p_Fm->fmanCtrlIntr[3].h_SrcHandle, event); + } +#ifdef FM_MACSEC_SUPPORT + if (pending & INTR_EN_MACSEC_MAC0) + { + if (p_Fm->guestId != p_Fm->intrMng[e_FM_EV_MACSEC_MAC0].guestId) + SendIpcIsr(p_Fm, e_FM_EV_MACSEC_MAC0, pending); + else + p_Fm->intrMng[e_FM_EV_MACSEC_MAC0].f_Isr(p_Fm->intrMng[e_FM_EV_MACSEC_MAC0].h_SrcHandle); + } +#endif /* FM_MACSEC_SUPPORT */ +} + +t_Error FM_ErrorIsr(t_Handle h_Fm) +{ +#define FM_M_CALL_1G_MAC_ERR_ISR(_id) \ + { \ + if (p_Fm->guestId != p_Fm->intrMng[(e_FmInterModuleEvent)(e_FM_EV_ERR_1G_MAC0+_id)].guestId) \ + SendIpcIsr(p_Fm, (e_FmInterModuleEvent)(e_FM_EV_ERR_1G_MAC0+_id), pending); \ + else \ + p_Fm->intrMng[(e_FmInterModuleEvent)(e_FM_EV_ERR_1G_MAC0+_id)].f_Isr(p_Fm->intrMng[(e_FmInterModuleEvent)(e_FM_EV_ERR_1G_MAC0+_id)].h_SrcHandle);\ + } +#define FM_M_CALL_10G_MAC_ERR_ISR(_id) \ + { \ + if (p_Fm->guestId != p_Fm->intrMng[(e_FmInterModuleEvent)(e_FM_EV_ERR_10G_MAC0+_id)].guestId) \ + SendIpcIsr(p_Fm, (e_FmInterModuleEvent)(e_FM_EV_ERR_10G_MAC0+_id), pending); \ + else \ + p_Fm->intrMng[(e_FmInterModuleEvent)(e_FM_EV_ERR_10G_MAC0+_id)].f_Isr(p_Fm->intrMng[(e_FmInterModuleEvent)(e_FM_EV_ERR_10G_MAC0+_id)].h_SrcHandle);\ + } + t_Fm *p_Fm = (t_Fm*)h_Fm; + uint32_t pending; + struct fman_fpm_regs *fpm_rg; + + SANITY_CHECK_RETURN_ERROR(h_Fm, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(!p_Fm->p_FmDriverParam, E_INVALID_STATE); + SANITY_CHECK_RETURN_ERROR((p_Fm->guestId == NCSW_MASTER_ID), E_NOT_SUPPORTED); + + fpm_rg = p_Fm->p_FmFpmRegs; + + /* error interrupts */ + pending = fman_get_fpm_error_interrupts(fpm_rg); + if (!pending) + return ERROR_CODE(E_EMPTY); + + if (pending & ERR_INTR_EN_BMI) + BmiErrEvent(p_Fm); + if (pending & ERR_INTR_EN_QMI) + QmiErrEvent(p_Fm); + if (pending & ERR_INTR_EN_FPM) + FpmErrEvent(p_Fm); + if (pending & ERR_INTR_EN_DMA) + DmaErrEvent(p_Fm); + if (pending & ERR_INTR_EN_IRAM) + IramErrIntr(p_Fm); + if (pending & ERR_INTR_EN_MURAM) + MuramErrIntr(p_Fm); + if (pending & ERR_INTR_EN_PRS) + p_Fm->intrMng[e_FM_EV_ERR_PRS].f_Isr(p_Fm->intrMng[e_FM_EV_ERR_PRS].h_SrcHandle); + if (pending & ERR_INTR_EN_PLCR) + p_Fm->intrMng[e_FM_EV_ERR_PLCR].f_Isr(p_Fm->intrMng[e_FM_EV_ERR_PLCR].h_SrcHandle); + if (pending & ERR_INTR_EN_KG) + p_Fm->intrMng[e_FM_EV_ERR_KG].f_Isr(p_Fm->intrMng[e_FM_EV_ERR_KG].h_SrcHandle); + + /* MAC events may belong to different partitions */ + if (pending & ERR_INTR_EN_1G_MAC0) + FM_M_CALL_1G_MAC_ERR_ISR(0); + if (pending & ERR_INTR_EN_1G_MAC1) + FM_M_CALL_1G_MAC_ERR_ISR(1); + if (pending & ERR_INTR_EN_1G_MAC2) + FM_M_CALL_1G_MAC_ERR_ISR(2); + if (pending & ERR_INTR_EN_1G_MAC3) + FM_M_CALL_1G_MAC_ERR_ISR(3); + if (pending & ERR_INTR_EN_1G_MAC4) + FM_M_CALL_1G_MAC_ERR_ISR(4); + if (pending & ERR_INTR_EN_1G_MAC5) + FM_M_CALL_1G_MAC_ERR_ISR(5); + if (pending & ERR_INTR_EN_1G_MAC6) + FM_M_CALL_1G_MAC_ERR_ISR(6); + if (pending & ERR_INTR_EN_1G_MAC7) + FM_M_CALL_1G_MAC_ERR_ISR(7); + if (pending & ERR_INTR_EN_10G_MAC0) + FM_M_CALL_10G_MAC_ERR_ISR(0); + if (pending & ERR_INTR_EN_10G_MAC1) + FM_M_CALL_10G_MAC_ERR_ISR(1); + +#ifdef FM_MACSEC_SUPPORT + if (pending & ERR_INTR_EN_MACSEC_MAC0) + { + if (p_Fm->guestId != p_Fm->intrMng[e_FM_EV_ERR_MACSEC_MAC0].guestId) + SendIpcIsr(p_Fm, e_FM_EV_ERR_MACSEC_MAC0, pending); + else + p_Fm->intrMng[e_FM_EV_ERR_MACSEC_MAC0].f_Isr(p_Fm->intrMng[e_FM_EV_ERR_MACSEC_MAC0].h_SrcHandle); + } +#endif /* FM_MACSEC_SUPPORT */ + + return E_OK; +} + +t_Error FM_SetPortsBandwidth(t_Handle h_Fm, t_FmPortsBandwidthParams *p_PortsBandwidth) +{ + t_Fm *p_Fm = (t_Fm*)h_Fm; + int i; + uint8_t sum; + uint8_t hardwarePortId; + uint8_t weights[64]; + uint8_t weight, maxPercent = 0; + struct fman_bmi_regs *bmi_rg; + + SANITY_CHECK_RETURN_ERROR(p_Fm, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(!p_Fm->p_FmDriverParam, E_INVALID_STATE); + SANITY_CHECK_RETURN_ERROR((p_Fm->guestId == NCSW_MASTER_ID), E_NOT_SUPPORTED); + + bmi_rg = p_Fm->p_FmBmiRegs; + + memset(weights, 0, (sizeof(uint8_t) * 64)); + + /* check that all ports add up to 100% */ + sum = 0; + for (i=0; i < p_PortsBandwidth->numOfPorts; i++) + sum +=p_PortsBandwidth->portsBandwidths[i].bandwidth; + if (sum != 100) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("Sum of ports bandwidth differ from 100%")); + + /* find highest percent */ + for (i=0; i < p_PortsBandwidth->numOfPorts; i++) + { + if (p_PortsBandwidth->portsBandwidths[i].bandwidth > maxPercent) + maxPercent = p_PortsBandwidth->portsBandwidths[i].bandwidth; + } + + ASSERT_COND(maxPercent > 0); /* guaranteed by sum = 100 */ + + /* calculate weight for each port */ + for (i=0; i < p_PortsBandwidth->numOfPorts; i++) + { + weight = (uint8_t)((p_PortsBandwidth->portsBandwidths[i].bandwidth * PORT_MAX_WEIGHT ) / maxPercent); + /* we want even division between 1-to-PORT_MAX_WEIGHT. so if exact division + is not reached, we round up so that: + 0 until maxPercent/PORT_MAX_WEIGHT get "1" + maxPercent/PORT_MAX_WEIGHT+1 until (maxPercent/PORT_MAX_WEIGHT)*2 get "2" + ... + maxPercent - maxPercent/PORT_MAX_WEIGHT until maxPercent get "PORT_MAX_WEIGHT: */ + if ((uint8_t)((p_PortsBandwidth->portsBandwidths[i].bandwidth * PORT_MAX_WEIGHT ) % maxPercent)) + weight++; + + /* find the location of this port within the register */ + hardwarePortId = + SwPortIdToHwPortId(p_PortsBandwidth->portsBandwidths[i].type, + p_PortsBandwidth->portsBandwidths[i].relativePortId, + p_Fm->p_FmStateStruct->revInfo.majorRev, + p_Fm->p_FmStateStruct->revInfo.minorRev); + + ASSERT_COND(IN_RANGE(1, hardwarePortId, 63)); + weights[hardwarePortId] = weight; + } + + fman_set_ports_bandwidth(bmi_rg, weights); + + return E_OK; +} + +t_Error FM_EnableRamsEcc(t_Handle h_Fm) +{ + t_Fm *p_Fm = (t_Fm*)h_Fm; + struct fman_fpm_regs *fpm_rg; + + SANITY_CHECK_RETURN_ERROR(p_Fm, E_INVALID_HANDLE); + + fpm_rg = p_Fm->p_FmFpmRegs; + + if (p_Fm->guestId != NCSW_MASTER_ID) + { + t_FmIpcMsg msg; + t_Error err; + + memset(&msg, 0, sizeof(msg)); + msg.msgId = FM_ENABLE_RAM_ECC; + err = XX_IpcSendMessage(p_Fm->h_IpcSessions[0], + (uint8_t*)&msg, + sizeof(msg.msgId), + NULL, + NULL, + NULL, + NULL); + if (err != E_OK) + RETURN_ERROR(MINOR, err, NO_MSG); + return E_OK; + } + + if (!p_Fm->p_FmStateStruct->internalCall) + p_Fm->p_FmStateStruct->explicitEnable = TRUE; + p_Fm->p_FmStateStruct->internalCall = FALSE; + + if (p_Fm->p_FmStateStruct->ramsEccEnable) + return E_OK; + else + { + fman_enable_rams_ecc(fpm_rg); + p_Fm->p_FmStateStruct->ramsEccEnable = TRUE; + } + + return E_OK; +} + +t_Error FM_DisableRamsEcc(t_Handle h_Fm) +{ + t_Fm *p_Fm = (t_Fm*)h_Fm; + bool explicitDisable = FALSE; + struct fman_fpm_regs *fpm_rg; + + SANITY_CHECK_RETURN_ERROR(p_Fm, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(!p_Fm->p_FmDriverParam, E_INVALID_HANDLE); + + fpm_rg = p_Fm->p_FmFpmRegs; + + if (p_Fm->guestId != NCSW_MASTER_ID) + { + t_Error err; + t_FmIpcMsg msg; + + memset(&msg, 0, sizeof(msg)); + msg.msgId = FM_DISABLE_RAM_ECC; + if ((err = XX_IpcSendMessage(p_Fm->h_IpcSessions[0], + (uint8_t*)&msg, + sizeof(msg.msgId), + NULL, + NULL, + NULL, + NULL)) != E_OK) + RETURN_ERROR(MINOR, err, NO_MSG); + return E_OK; + } + + if (!p_Fm->p_FmStateStruct->internalCall) + explicitDisable = TRUE; + p_Fm->p_FmStateStruct->internalCall = FALSE; + + /* if rams are already disabled, or if rams were explicitly enabled and are + currently called indirectly (not explicitly), ignore this call. */ + if (!p_Fm->p_FmStateStruct->ramsEccEnable || + (p_Fm->p_FmStateStruct->explicitEnable && !explicitDisable)) + return E_OK; + else + { + if (p_Fm->p_FmStateStruct->explicitEnable) + /* This is the case were both explicit are TRUE. + Turn off this flag for cases were following ramsEnable + routines are called */ + p_Fm->p_FmStateStruct->explicitEnable = FALSE; + + fman_enable_rams_ecc(fpm_rg); + p_Fm->p_FmStateStruct->ramsEccEnable = FALSE; + } + + return E_OK; +} + +t_Error FM_SetException(t_Handle h_Fm, e_FmExceptions exception, bool enable) +{ + t_Fm *p_Fm = (t_Fm*)h_Fm; + uint32_t bitMask = 0; + enum fman_exceptions fslException; + struct fman_rg fman_rg; + + SANITY_CHECK_RETURN_ERROR(p_Fm, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(!p_Fm->p_FmDriverParam, E_INVALID_STATE); + + fman_rg.bmi_rg = p_Fm->p_FmBmiRegs; + fman_rg.qmi_rg = p_Fm->p_FmQmiRegs; + fman_rg.fpm_rg = p_Fm->p_FmFpmRegs; + fman_rg.dma_rg = p_Fm->p_FmDmaRegs; + + GET_EXCEPTION_FLAG(bitMask, exception); + if (bitMask) + { + if (enable) + p_Fm->p_FmStateStruct->exceptions |= bitMask; + else + p_Fm->p_FmStateStruct->exceptions &= ~bitMask; + + fslException = FmanExceptionTrans(exception); + + return (t_Error)fman_set_exception(&fman_rg, + fslException, + enable); + } + else + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("Undefined exception")); + + return E_OK; +} + +t_Error FM_GetRevision(t_Handle h_Fm, t_FmRevisionInfo *p_FmRevisionInfo) +{ + t_Fm *p_Fm = (t_Fm*)h_Fm; + + p_FmRevisionInfo->majorRev = p_Fm->p_FmStateStruct->revInfo.majorRev; + p_FmRevisionInfo->minorRev = p_Fm->p_FmStateStruct->revInfo.minorRev; + + return E_OK; +} + +t_Error FM_GetFmanCtrlCodeRevision(t_Handle h_Fm, t_FmCtrlCodeRevisionInfo *p_RevisionInfo) +{ + t_Fm *p_Fm = (t_Fm*)h_Fm; + t_FMIramRegs *p_Iram; + uint32_t revInfo; + + SANITY_CHECK_RETURN_ERROR(p_Fm, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_RevisionInfo, E_NULL_POINTER); + + if ((p_Fm->guestId != NCSW_MASTER_ID) && + p_Fm->h_IpcSessions[0]) + { + t_Error err; + t_FmIpcMsg msg; + t_FmIpcReply reply; + uint32_t replyLength; + t_FmIpcFmanCtrlCodeRevisionInfo ipcRevInfo; + + memset(&msg, 0, sizeof(msg)); + memset(&reply, 0, sizeof(reply)); + msg.msgId = FM_GET_FMAN_CTRL_CODE_REV; + replyLength = sizeof(uint32_t) + sizeof(t_FmCtrlCodeRevisionInfo); + if ((err = XX_IpcSendMessage(p_Fm->h_IpcSessions[0], + (uint8_t*)&msg, + sizeof(msg.msgId), + (uint8_t*)&reply, + &replyLength, + NULL, + NULL)) != E_OK) + RETURN_ERROR(MINOR, err, NO_MSG); + if (replyLength != (sizeof(uint32_t) + sizeof(t_FmCtrlCodeRevisionInfo))) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("IPC reply length mismatch")); + memcpy((uint8_t*)&ipcRevInfo, reply.replyBody, sizeof(t_FmCtrlCodeRevisionInfo)); + p_RevisionInfo->packageRev = ipcRevInfo.packageRev; + p_RevisionInfo->majorRev = ipcRevInfo.majorRev; + p_RevisionInfo->minorRev = ipcRevInfo.minorRev; + return (t_Error)(reply.error); + } + else if (p_Fm->guestId != NCSW_MASTER_ID) + RETURN_ERROR(MINOR, E_NOT_SUPPORTED, + ("running in guest-mode without IPC!")); + + p_Iram = (t_FMIramRegs *)UINT_TO_PTR(p_Fm->baseAddr + FM_MM_IMEM); + WRITE_UINT32(p_Iram->iadd, 0x4); + while (GET_UINT32(p_Iram->iadd) != 0x4) ; + revInfo = GET_UINT32(p_Iram->idata); + p_RevisionInfo->packageRev = (uint16_t)((revInfo & 0xFFFF0000) >> 16); + p_RevisionInfo->majorRev = (uint8_t)((revInfo & 0x0000FF00) >> 8); + p_RevisionInfo->minorRev = (uint8_t)(revInfo & 0x000000FF); + + return E_OK; +} + +uint32_t FM_GetCounter(t_Handle h_Fm, e_FmCounters counter) +{ + t_Fm *p_Fm = (t_Fm*)h_Fm; + t_Error err; + uint32_t counterValue; + struct fman_rg fman_rg; + enum fman_counters fsl_counter; + + SANITY_CHECK_RETURN_VALUE(p_Fm, E_INVALID_HANDLE, 0); + SANITY_CHECK_RETURN_VALUE(!p_Fm->p_FmDriverParam, E_INVALID_STATE, 0); + + fman_rg.bmi_rg = p_Fm->p_FmBmiRegs; + fman_rg.qmi_rg = p_Fm->p_FmQmiRegs; + fman_rg.fpm_rg = p_Fm->p_FmFpmRegs; + fman_rg.dma_rg = p_Fm->p_FmDmaRegs; + + if ((p_Fm->guestId != NCSW_MASTER_ID) && + !p_Fm->baseAddr && + p_Fm->h_IpcSessions[0]) + { + t_FmIpcMsg msg; + t_FmIpcReply reply; + uint32_t replyLength, outCounter; + + memset(&msg, 0, sizeof(msg)); + memset(&reply, 0, sizeof(reply)); + msg.msgId = FM_GET_COUNTER; + memcpy(msg.msgBody, (uint8_t *)&counter, sizeof(uint32_t)); + replyLength = sizeof(uint32_t) + sizeof(uint32_t); + err = XX_IpcSendMessage(p_Fm->h_IpcSessions[0], + (uint8_t*)&msg, + sizeof(msg.msgId) +sizeof(counterValue), + (uint8_t*)&reply, + &replyLength, + NULL, + NULL); + if (err != E_OK) + { + REPORT_ERROR(MAJOR, err, NO_MSG); + return 0; + } + if (replyLength != (sizeof(uint32_t) + sizeof(uint32_t))) + { + REPORT_ERROR(MAJOR, E_INVALID_VALUE, ("IPC reply length mismatch")); + return 0; + } + + memcpy((uint8_t*)&outCounter, reply.replyBody, sizeof(uint32_t)); + return outCounter; + } + else if (!p_Fm->baseAddr) + { + REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Either IPC or 'baseAddress' is required!")); + return 0; + } + + /* When applicable (when there is an 'enable counters' bit, + check that counters are enabled */ + switch (counter) + { + case (e_FM_COUNTERS_DEQ_1): + case (e_FM_COUNTERS_DEQ_2): + /* fall through */ + case (e_FM_COUNTERS_DEQ_3): + if ((p_Fm->p_FmStateStruct->revInfo.majorRev == 4) || + (p_Fm->p_FmStateStruct->revInfo.majorRev >= 6)) + { + REPORT_ERROR(MAJOR, E_NOT_SUPPORTED, ("Requested counter not supported")); + return 0; + } + /* fall through */ + case (e_FM_COUNTERS_ENQ_TOTAL_FRAME): + case (e_FM_COUNTERS_DEQ_TOTAL_FRAME): + case (e_FM_COUNTERS_DEQ_0): + case (e_FM_COUNTERS_DEQ_FROM_DEFAULT): + case (e_FM_COUNTERS_DEQ_FROM_CONTEXT): + case (e_FM_COUNTERS_DEQ_FROM_FD): + /* fall through */ + case (e_FM_COUNTERS_DEQ_CONFIRM): + if (!(GET_UINT32(p_Fm->p_FmQmiRegs->fmqm_gc) & QMI_CFG_EN_COUNTERS)) + { + REPORT_ERROR(MAJOR, E_INVALID_STATE, ("Requested counter was not enabled")); + return 0; + } + break; + default: + break; + } + + FMAN_COUNTERS_TRANS(fsl_counter, counter); + return fman_get_counter(&fman_rg, fsl_counter); +} + +t_Error FM_ModifyCounter(t_Handle h_Fm, e_FmCounters counter, uint32_t val) +{ + t_Fm *p_Fm = (t_Fm*)h_Fm; + struct fman_rg fman_rg; + enum fman_counters fsl_counter; + + SANITY_CHECK_RETURN_ERROR(p_Fm, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(!p_Fm->p_FmDriverParam, E_INVALID_STATE); + + fman_rg.bmi_rg = p_Fm->p_FmBmiRegs; + fman_rg.qmi_rg = p_Fm->p_FmQmiRegs; + fman_rg.fpm_rg = p_Fm->p_FmFpmRegs; + fman_rg.dma_rg = p_Fm->p_FmDmaRegs; + + FMAN_COUNTERS_TRANS(fsl_counter, counter); + return (t_Error)fman_modify_counter(&fman_rg, fsl_counter, val); +} + +void FM_SetDmaEmergency(t_Handle h_Fm, e_FmDmaMuramPort muramPort, bool enable) +{ + t_Fm *p_Fm = (t_Fm*)h_Fm; + struct fman_dma_regs *dma_rg; + + SANITY_CHECK_RETURN(p_Fm, E_INVALID_HANDLE); + SANITY_CHECK_RETURN(!p_Fm->p_FmDriverParam, E_INVALID_STATE); + + dma_rg = p_Fm->p_FmDmaRegs; + + fman_set_dma_emergency(dma_rg, !!(muramPort==e_FM_DMA_MURAM_PORT_WRITE), enable); +} + +void FM_SetDmaExtBusPri(t_Handle h_Fm, e_FmDmaExtBusPri pri) +{ + t_Fm *p_Fm = (t_Fm*)h_Fm; + struct fman_dma_regs *dma_rg; + + SANITY_CHECK_RETURN(p_Fm, E_INVALID_HANDLE); + SANITY_CHECK_RETURN(!p_Fm->p_FmDriverParam, E_INVALID_STATE); + + dma_rg = p_Fm->p_FmDmaRegs; + + fman_set_dma_ext_bus_pri(dma_rg, pri); +} + +void FM_GetDmaStatus(t_Handle h_Fm, t_FmDmaStatus *p_FmDmaStatus) +{ + t_Fm *p_Fm = (t_Fm*)h_Fm; + uint32_t dmaStatus; + struct fman_dma_regs *dma_rg; + + SANITY_CHECK_RETURN(p_Fm, E_INVALID_HANDLE); + SANITY_CHECK_RETURN(!p_Fm->p_FmDriverParam, E_INVALID_STATE); + + dma_rg = p_Fm->p_FmDmaRegs; + + if ((p_Fm->guestId != NCSW_MASTER_ID) && + !p_Fm->baseAddr && + p_Fm->h_IpcSessions[0]) + { + t_FmIpcDmaStatus ipcDmaStatus; + t_FmIpcMsg msg; + t_FmIpcReply reply; + t_Error err; + uint32_t replyLength; + + memset(&msg, 0, sizeof(msg)); + memset(&reply, 0, sizeof(reply)); + msg.msgId = FM_DMA_STAT; + replyLength = sizeof(uint32_t) + sizeof(t_FmIpcDmaStatus); + err = XX_IpcSendMessage(p_Fm->h_IpcSessions[0], + (uint8_t*)&msg, + sizeof(msg.msgId), + (uint8_t*)&reply, + &replyLength, + NULL, + NULL); + if (err != E_OK) + { + REPORT_ERROR(MINOR, err, NO_MSG); + return; + } + if (replyLength != (sizeof(uint32_t) + sizeof(t_FmIpcDmaStatus))) + { + REPORT_ERROR(MAJOR, E_INVALID_VALUE, ("IPC reply length mismatch")); + return; + } + memcpy((uint8_t*)&ipcDmaStatus, reply.replyBody, sizeof(t_FmIpcDmaStatus)); + + p_FmDmaStatus->cmqNotEmpty = (bool)ipcDmaStatus.boolCmqNotEmpty; /**< Command queue is not empty */ + p_FmDmaStatus->busError = (bool)ipcDmaStatus.boolBusError; /**< Bus error occurred */ + p_FmDmaStatus->readBufEccError = (bool)ipcDmaStatus.boolReadBufEccError; /**< Double ECC error on buffer Read */ + p_FmDmaStatus->writeBufEccSysError =(bool)ipcDmaStatus.boolWriteBufEccSysError; /**< Double ECC error on buffer write from system side */ + p_FmDmaStatus->writeBufEccFmError = (bool)ipcDmaStatus.boolWriteBufEccFmError; /**< Double ECC error on buffer write from FM side */ + p_FmDmaStatus->singlePortEccError = (bool)ipcDmaStatus.boolSinglePortEccError; /**< Double ECC error on buffer write from FM side */ + return; + } + else if (!p_Fm->baseAddr) + { + REPORT_ERROR(MINOR, E_NOT_SUPPORTED, + ("Either IPC or 'baseAddress' is required!")); + return; + } + + dmaStatus = fman_get_dma_status(dma_rg); + + p_FmDmaStatus->cmqNotEmpty = (bool)(dmaStatus & DMA_STATUS_CMD_QUEUE_NOT_EMPTY); + p_FmDmaStatus->busError = (bool)(dmaStatus & DMA_STATUS_BUS_ERR); + if (p_Fm->p_FmStateStruct->revInfo.majorRev >= 6) + p_FmDmaStatus->singlePortEccError = (bool)(dmaStatus & DMA_STATUS_FM_SPDAT_ECC); + else + { + p_FmDmaStatus->readBufEccError = (bool)(dmaStatus & DMA_STATUS_READ_ECC); + p_FmDmaStatus->writeBufEccSysError = (bool)(dmaStatus & DMA_STATUS_SYSTEM_WRITE_ECC); + p_FmDmaStatus->writeBufEccFmError = (bool)(dmaStatus & DMA_STATUS_FM_WRITE_ECC); + } +} + +void FM_Resume(t_Handle h_Fm) +{ + t_Fm *p_Fm = (t_Fm*)h_Fm; + struct fman_fpm_regs *fpm_rg; + + SANITY_CHECK_RETURN(p_Fm, E_INVALID_HANDLE); + SANITY_CHECK_RETURN(!p_Fm->p_FmDriverParam, E_INVALID_STATE); + SANITY_CHECK_RETURN((p_Fm->guestId == NCSW_MASTER_ID), E_NOT_SUPPORTED); + + fpm_rg = p_Fm->p_FmFpmRegs; + + fman_resume(fpm_rg); +} + +t_Error FM_GetSpecialOperationCoding(t_Handle h_Fm, + fmSpecialOperations_t spOper, + uint8_t *p_SpOperCoding) +{ + t_Fm *p_Fm = (t_Fm*)h_Fm; + t_FmCtrlCodeRevisionInfo revInfo; + t_Error err; + + SANITY_CHECK_RETURN_ERROR(p_Fm, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(!p_Fm->p_FmDriverParam, E_INVALID_STATE); + SANITY_CHECK_RETURN_ERROR(p_SpOperCoding, E_NULL_POINTER); + + if (!spOper) + { + *p_SpOperCoding = 0; + return E_OK; + } + + if ((err = FM_GetFmanCtrlCodeRevision(p_Fm, &revInfo)) != E_OK) + { + DBG(WARNING, ("FM in guest-mode without IPC, can't validate firmware revision.")); + revInfo.packageRev = IP_OFFLOAD_PACKAGE_NUMBER; + } + else if (!IS_OFFLOAD_PACKAGE(revInfo.packageRev)) + RETURN_ERROR(MINOR, E_NOT_SUPPORTED, ("Fman ctrl code package")); + + switch (spOper) + { + case (FM_SP_OP_CAPWAP_DTLS_DEC): + *p_SpOperCoding = 9; + break; + case (FM_SP_OP_CAPWAP_DTLS_ENC): + *p_SpOperCoding = 10; + break; + case (FM_SP_OP_IPSEC|FM_SP_OP_IPSEC_UPDATE_UDP_LEN|FM_SP_OP_IPSEC_MANIP): + case (FM_SP_OP_IPSEC|FM_SP_OP_IPSEC_UPDATE_UDP_LEN|FM_SP_OP_IPSEC_MANIP|FM_SP_OP_RPD): + *p_SpOperCoding = 5; + break; + case (FM_SP_OP_IPSEC|FM_SP_OP_IPSEC_MANIP): + case (FM_SP_OP_IPSEC|FM_SP_OP_IPSEC_MANIP|FM_SP_OP_RPD): + *p_SpOperCoding = 6; + break; + case (FM_SP_OP_IPSEC|FM_SP_OP_IPSEC_UPDATE_UDP_LEN|FM_SP_OP_RPD): + *p_SpOperCoding = 3; + break; + case (FM_SP_OP_IPSEC|FM_SP_OP_IPSEC_UPDATE_UDP_LEN): + *p_SpOperCoding = 1; + break; + case (FM_SP_OP_IPSEC|FM_SP_OP_IPSEC_UPDATE_UDP_LEN|FM_SP_OP_IPSEC_NO_ETH_HDR): + *p_SpOperCoding = 12; + break; + case (FM_SP_OP_IPSEC|FM_SP_OP_RPD): + *p_SpOperCoding = 4; + break; + case (FM_SP_OP_IPSEC): + *p_SpOperCoding = 2; + break; + case (FM_SP_OP_DCL4C): + *p_SpOperCoding = 7; + break; + case (FM_SP_OP_CLEAR_RPD): + *p_SpOperCoding = 8; + break; + default: + RETURN_ERROR(MINOR, E_INVALID_VALUE, NO_MSG); + } + + return E_OK; +} + +t_Error FM_CtrlMonStart(t_Handle h_Fm) +{ + t_Fm *p_Fm = (t_Fm *)h_Fm; + t_FmTrbRegs *p_MonRegs; + uint8_t i; + + SANITY_CHECK_RETURN_ERROR(p_Fm, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(!p_Fm->p_FmDriverParam, E_INVALID_STATE); + SANITY_CHECK_RETURN_ERROR((p_Fm->guestId == NCSW_MASTER_ID), E_NOT_SUPPORTED); + + WRITE_UINT32(p_Fm->p_FmFpmRegs->fmfp_brkc, + GET_UINT32(p_Fm->p_FmFpmRegs->fmfp_brkc) | FPM_BRKC_RDBG); + + for (i = 0; i < FM_NUM_OF_CTRL; i++) + { + p_MonRegs = (t_FmTrbRegs *)UINT_TO_PTR(p_Fm->baseAddr + FM_MM_TRB(i)); + + /* Reset control registers */ + WRITE_UINT32(p_MonRegs->tcrh, TRB_TCRH_RESET); + WRITE_UINT32(p_MonRegs->tcrl, TRB_TCRL_RESET); + + /* Configure: counter #1 counts all stalls in risc - ldsched stall + counter #2 counts all stalls in risc - other stall*/ + WRITE_UINT32(p_MonRegs->tcrl, TRB_TCRL_RESET | TRB_TCRL_UTIL); + + /* Enable monitoring */ + WRITE_UINT32(p_MonRegs->tcrh, TRB_TCRH_ENABLE_COUNTERS); + } + + return E_OK; +} + +t_Error FM_CtrlMonStop(t_Handle h_Fm) +{ + t_Fm *p_Fm = (t_Fm *)h_Fm; + t_FmTrbRegs *p_MonRegs; + uint8_t i; + + SANITY_CHECK_RETURN_ERROR(p_Fm, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(!p_Fm->p_FmDriverParam, E_INVALID_STATE); + SANITY_CHECK_RETURN_ERROR((p_Fm->guestId == NCSW_MASTER_ID), E_NOT_SUPPORTED); + + for (i = 0; i < FM_NUM_OF_CTRL; i++) + { + p_MonRegs = (t_FmTrbRegs *)UINT_TO_PTR(p_Fm->baseAddr + FM_MM_TRB(i)); + WRITE_UINT32(p_MonRegs->tcrh, TRB_TCRH_DISABLE_COUNTERS); + } + + WRITE_UINT32(p_Fm->p_FmFpmRegs->fmfp_brkc, + GET_UINT32(p_Fm->p_FmFpmRegs->fmfp_brkc) & ~FPM_BRKC_RDBG); + + return E_OK; +} + +t_Error FM_CtrlMonGetCounters(t_Handle h_Fm, uint8_t fmCtrlIndex, t_FmCtrlMon *p_Mon) +{ + t_Fm *p_Fm = (t_Fm *)h_Fm; + t_FmTrbRegs *p_MonRegs; + uint64_t clkCnt, utilValue, effValue; + + SANITY_CHECK_RETURN_ERROR(p_Fm, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(!p_Fm->p_FmDriverParam, E_INVALID_STATE); + SANITY_CHECK_RETURN_ERROR((p_Fm->guestId == NCSW_MASTER_ID), E_NOT_SUPPORTED); + SANITY_CHECK_RETURN_ERROR(p_Mon, E_NULL_POINTER); + + if (fmCtrlIndex >= FM_NUM_OF_CTRL) + RETURN_ERROR(MAJOR, E_INVALID_VALUE, ("FM Controller index")); + + p_MonRegs = (t_FmTrbRegs *)UINT_TO_PTR(p_Fm->baseAddr + FM_MM_TRB(fmCtrlIndex)); + + clkCnt = (uint64_t) + ((uint64_t)GET_UINT32(p_MonRegs->tpcch) << 32 | GET_UINT32(p_MonRegs->tpccl)); + + utilValue = (uint64_t) + ((uint64_t)GET_UINT32(p_MonRegs->tpc1h) << 32 | GET_UINT32(p_MonRegs->tpc1l)); + + effValue = (uint64_t) + ((uint64_t)GET_UINT32(p_MonRegs->tpc2h) << 32 | GET_UINT32(p_MonRegs->tpc2l)); + + p_Mon->percentCnt[0] = (uint8_t)div64_u64((clkCnt - utilValue) * 100, clkCnt); + if (clkCnt != utilValue) + p_Mon->percentCnt[1] = (uint8_t)div64_u64(((clkCnt - utilValue) - effValue) * 100, clkCnt - utilValue); + else + p_Mon->percentCnt[1] = 0; + + return E_OK; +} + +t_Handle FM_GetMuramHandle(t_Handle h_Fm) +{ + t_Fm *p_Fm = (t_Fm*)h_Fm; + + SANITY_CHECK_RETURN_VALUE(p_Fm, E_INVALID_HANDLE, NULL); + + return (p_Fm->h_FmMuram); +} + +/****************************************************/ +/* Hidden-DEBUG Only API */ +/****************************************************/ +t_Error FM_ForceIntr (t_Handle h_Fm, e_FmExceptions exception) +{ + t_Fm *p_Fm = (t_Fm*)h_Fm; + enum fman_exceptions fslException; + struct fman_rg fman_rg; + + SANITY_CHECK_RETURN_ERROR(p_Fm, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(!p_Fm->p_FmDriverParam, E_INVALID_STATE); + + fman_rg.bmi_rg = p_Fm->p_FmBmiRegs; + fman_rg.qmi_rg = p_Fm->p_FmQmiRegs; + fman_rg.fpm_rg = p_Fm->p_FmFpmRegs; + fman_rg.dma_rg = p_Fm->p_FmDmaRegs; + + switch (exception) + { + case e_FM_EX_QMI_DEQ_FROM_UNKNOWN_PORTID: + if (!(p_Fm->p_FmStateStruct->exceptions & FM_EX_QMI_DEQ_FROM_UNKNOWN_PORTID)) + RETURN_ERROR(MINOR, E_NOT_SUPPORTED, ("The selected exception is masked")); + break; + case e_FM_EX_QMI_SINGLE_ECC: + if (p_Fm->p_FmStateStruct->revInfo.majorRev >= 6) + RETURN_ERROR(MAJOR, E_NOT_SUPPORTED, ("e_FM_EX_QMI_SINGLE_ECC not supported on this integration.")); + + if (!(p_Fm->p_FmStateStruct->exceptions & FM_EX_QMI_SINGLE_ECC)) + RETURN_ERROR(MINOR, E_NOT_SUPPORTED, ("The selected exception is masked")); + break; + case e_FM_EX_QMI_DOUBLE_ECC: + if (!(p_Fm->p_FmStateStruct->exceptions & FM_EX_QMI_DOUBLE_ECC)) + RETURN_ERROR(MINOR, E_NOT_SUPPORTED, ("The selected exception is masked")); + break; + case e_FM_EX_BMI_LIST_RAM_ECC: + if (!(p_Fm->p_FmStateStruct->exceptions & FM_EX_BMI_LIST_RAM_ECC)) + RETURN_ERROR(MINOR, E_NOT_SUPPORTED, ("The selected exception is masked")); + break; + case e_FM_EX_BMI_STORAGE_PROFILE_ECC: + if (!(p_Fm->p_FmStateStruct->exceptions & FM_EX_BMI_STORAGE_PROFILE_ECC)) + RETURN_ERROR(MINOR, E_NOT_SUPPORTED, ("The selected exception is masked")); + break; + case e_FM_EX_BMI_STATISTICS_RAM_ECC: + if (!(p_Fm->p_FmStateStruct->exceptions & FM_EX_BMI_STATISTICS_RAM_ECC)) + RETURN_ERROR(MINOR, E_NOT_SUPPORTED, ("The selected exception is masked")); + break; + case e_FM_EX_BMI_DISPATCH_RAM_ECC: + if (!(p_Fm->p_FmStateStruct->exceptions & FM_EX_BMI_DISPATCH_RAM_ECC)) + RETURN_ERROR(MINOR, E_NOT_SUPPORTED, ("The selected exception is masked")); + break; + default: + RETURN_ERROR(MINOR, E_NOT_SUPPORTED, ("The selected exception may not be forced")); + } + + fslException = FmanExceptionTrans(exception); + fman_force_intr (&fman_rg, fslException); + + return E_OK; +} + +t_Handle FmGetPcd(t_Handle h_Fm) +{ + return ((t_Fm*)h_Fm)->h_Pcd; +} +#if (DPAA_VERSION >= 11) +extern void *g_MemacRegs; +void fm_clk_down(void); +uint32_t fman_memac_get_event(void *regs, uint32_t ev_mask); +void FM_ChangeClock(t_Handle h_Fm, int hardwarePortId) +{ + int macId; + uint32_t event, rcr; + t_Fm *p_Fm = (t_Fm*)h_Fm; + rcr = GET_UINT32(p_Fm->p_FmFpmRegs->fm_rcr); + rcr |= 0x04000000; + WRITE_UINT32(p_Fm->p_FmFpmRegs->fm_rcr, rcr); + + HW_PORT_ID_TO_SW_PORT_ID(macId, hardwarePortId); + do + { + event = fman_memac_get_event(g_MemacRegs, 0xFFFFFFFF); + } while ((event & 0x00000020) == 0); + fm_clk_down(); + rcr = GET_UINT32(p_Fm->p_FmFpmRegs->fm_rcr); + rcr &= ~0x04000000; + WRITE_UINT32(p_Fm->p_FmFpmRegs->fm_rcr, rcr); +} +#endif diff --git a/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/fm.h b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/fm.h new file mode 100644 index 000000000000..0bded75dad15 --- /dev/null +++ b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/fm.h @@ -0,0 +1,648 @@ +/* + * Copyright 2008-2012 Freescale Semiconductor Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Freescale Semiconductor nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * + * ALTERNATIVELY, this software may be distributed under the terms of the + * GNU General Public License ("GPL") as published by the Free Software + * Foundation, either version 2 of that License or (at your option) any + * later version. + * + * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + +/****************************************************************************** + @File fm.h + + @Description FM internal structures and definitions. +*//***************************************************************************/ +#ifndef __FM_H +#define __FM_H + +#include "error_ext.h" +#include "std_ext.h" +#include "fm_ext.h" +#include "fm_ipc.h" + +#include "fsl_fman.h" + +#define __ERR_MODULE__ MODULE_FM + +#define FM_MAX_NUM_OF_HW_PORT_IDS 64 +#define FM_MAX_NUM_OF_GUESTS 100 + +/**************************************************************************//** + @Description Exceptions +*//***************************************************************************/ +#define FM_EX_DMA_BUS_ERROR 0x80000000 /**< DMA bus error. */ +#define FM_EX_DMA_READ_ECC 0x40000000 +#define FM_EX_DMA_SYSTEM_WRITE_ECC 0x20000000 +#define FM_EX_DMA_FM_WRITE_ECC 0x10000000 +#define FM_EX_FPM_STALL_ON_TASKS 0x08000000 /**< Stall of tasks on FPM */ +#define FM_EX_FPM_SINGLE_ECC 0x04000000 /**< Single ECC on FPM */ +#define FM_EX_FPM_DOUBLE_ECC 0x02000000 +#define FM_EX_QMI_SINGLE_ECC 0x01000000 /**< Single ECC on FPM */ +#define FM_EX_QMI_DEQ_FROM_UNKNOWN_PORTID 0x00800000 /**< Dequeu from default queue id */ +#define FM_EX_QMI_DOUBLE_ECC 0x00400000 +#define FM_EX_BMI_LIST_RAM_ECC 0x00200000 +#define FM_EX_BMI_STORAGE_PROFILE_ECC 0x00100000 +#define FM_EX_BMI_STATISTICS_RAM_ECC 0x00080000 +#define FM_EX_IRAM_ECC 0x00040000 +#define FM_EX_MURAM_ECC 0x00020000 +#define FM_EX_BMI_DISPATCH_RAM_ECC 0x00010000 +#define FM_EX_DMA_SINGLE_PORT_ECC 0x00008000 + +#define DMA_EMSR_EMSTR_MASK 0x0000FFFF + +#define DMA_THRESH_COMMQ_MASK 0xFF000000 +#define DMA_THRESH_READ_INT_BUF_MASK 0x007F0000 +#define DMA_THRESH_WRITE_INT_BUF_MASK 0x0000007F + +#define GET_EXCEPTION_FLAG(bitMask, exception) \ +switch (exception){ \ + case e_FM_EX_DMA_BUS_ERROR: \ + bitMask = FM_EX_DMA_BUS_ERROR; break; \ + case e_FM_EX_DMA_SINGLE_PORT_ECC: \ + bitMask = FM_EX_DMA_SINGLE_PORT_ECC; break; \ + case e_FM_EX_DMA_READ_ECC: \ + bitMask = FM_EX_DMA_READ_ECC; break; \ + case e_FM_EX_DMA_SYSTEM_WRITE_ECC: \ + bitMask = FM_EX_DMA_SYSTEM_WRITE_ECC; break; \ + case e_FM_EX_DMA_FM_WRITE_ECC: \ + bitMask = FM_EX_DMA_FM_WRITE_ECC; break; \ + case e_FM_EX_FPM_STALL_ON_TASKS: \ + bitMask = FM_EX_FPM_STALL_ON_TASKS; break; \ + case e_FM_EX_FPM_SINGLE_ECC: \ + bitMask = FM_EX_FPM_SINGLE_ECC; break; \ + case e_FM_EX_FPM_DOUBLE_ECC: \ + bitMask = FM_EX_FPM_DOUBLE_ECC; break; \ + case e_FM_EX_QMI_SINGLE_ECC: \ + bitMask = FM_EX_QMI_SINGLE_ECC; break; \ + case e_FM_EX_QMI_DOUBLE_ECC: \ + bitMask = FM_EX_QMI_DOUBLE_ECC; break; \ + case e_FM_EX_QMI_DEQ_FROM_UNKNOWN_PORTID: \ + bitMask = FM_EX_QMI_DEQ_FROM_UNKNOWN_PORTID; break; \ + case e_FM_EX_BMI_LIST_RAM_ECC: \ + bitMask = FM_EX_BMI_LIST_RAM_ECC; break; \ + case e_FM_EX_BMI_STORAGE_PROFILE_ECC: \ + bitMask = FM_EX_BMI_STORAGE_PROFILE_ECC; break; \ + case e_FM_EX_BMI_STATISTICS_RAM_ECC: \ + bitMask = FM_EX_BMI_STATISTICS_RAM_ECC; break; \ + case e_FM_EX_BMI_DISPATCH_RAM_ECC: \ + bitMask = FM_EX_BMI_DISPATCH_RAM_ECC; break; \ + case e_FM_EX_IRAM_ECC: \ + bitMask = FM_EX_IRAM_ECC; break; \ + case e_FM_EX_MURAM_ECC: \ + bitMask = FM_EX_MURAM_ECC; break; \ + default: bitMask = 0;break; \ +} + +#define GET_FM_MODULE_EVENT(_mod, _id, _intrType, _event) \ + switch (_mod) { \ + case e_FM_MOD_PRS: \ + if (_id) _event = e_FM_EV_DUMMY_LAST; \ + else _event = (_intrType == e_FM_INTR_TYPE_ERR) ? e_FM_EV_ERR_PRS : e_FM_EV_PRS; \ + break; \ + case e_FM_MOD_KG: \ + if (_id) _event = e_FM_EV_DUMMY_LAST; \ + else _event = (_intrType == e_FM_INTR_TYPE_ERR) ? e_FM_EV_ERR_KG : e_FM_EV_DUMMY_LAST; \ + break; \ + case e_FM_MOD_PLCR: \ + if (_id) _event = e_FM_EV_DUMMY_LAST; \ + else _event = (_intrType == e_FM_INTR_TYPE_ERR) ? e_FM_EV_ERR_PLCR : e_FM_EV_PLCR; \ + break; \ + case e_FM_MOD_TMR: \ + if (_id) _event = e_FM_EV_DUMMY_LAST; \ + else _event = (_intrType == e_FM_INTR_TYPE_ERR) ? e_FM_EV_DUMMY_LAST : e_FM_EV_TMR; \ + break; \ + case e_FM_MOD_10G_MAC: \ + if (_id >= FM_MAX_NUM_OF_10G_MACS) _event = e_FM_EV_DUMMY_LAST; \ + else _event = (_intrType == e_FM_INTR_TYPE_ERR) ? (e_FM_EV_ERR_10G_MAC0 + _id) : (e_FM_EV_10G_MAC0 + _id); \ + break; \ + case e_FM_MOD_1G_MAC: \ + if (_id >= FM_MAX_NUM_OF_1G_MACS) _event = e_FM_EV_DUMMY_LAST; \ + else _event = (_intrType == e_FM_INTR_TYPE_ERR) ? (e_FM_EV_ERR_1G_MAC0 + _id) : (e_FM_EV_1G_MAC0 + _id); \ + break; \ + case e_FM_MOD_MACSEC: \ + switch (_id){ \ + case (0): _event = (_intrType == e_FM_INTR_TYPE_ERR) ? e_FM_EV_ERR_MACSEC_MAC0:e_FM_EV_MACSEC_MAC0; \ + break; \ + } \ + break; \ + case e_FM_MOD_FMAN_CTRL: \ + if (_intrType == e_FM_INTR_TYPE_ERR) _event = e_FM_EV_DUMMY_LAST; \ + else _event = (e_FM_EV_FMAN_CTRL_0 + _id); \ + break; \ + default: _event = e_FM_EV_DUMMY_LAST; \ + break; \ + } + +#define FMAN_CACHE_OVERRIDE_TRANS(fsl_cache_override, _cache_override) \ + switch (_cache_override){ \ + case e_FM_DMA_NO_CACHE_OR: \ + fsl_cache_override = E_FMAN_DMA_NO_CACHE_OR; break; \ + case e_FM_DMA_NO_STASH_DATA: \ + fsl_cache_override = E_FMAN_DMA_NO_STASH_DATA; break; \ + case e_FM_DMA_MAY_STASH_DATA: \ + fsl_cache_override = E_FMAN_DMA_MAY_STASH_DATA; break; \ + case e_FM_DMA_STASH_DATA: \ + fsl_cache_override = E_FMAN_DMA_STASH_DATA; break; \ + default: \ + fsl_cache_override = E_FMAN_DMA_NO_CACHE_OR; break; \ + } + +#define FMAN_AID_MODE_TRANS(fsl_aid_mode, _aid_mode) \ + switch (_aid_mode){ \ + case e_FM_DMA_AID_OUT_PORT_ID: \ + fsl_aid_mode = E_FMAN_DMA_AID_OUT_PORT_ID; break; \ + case e_FM_DMA_AID_OUT_TNUM: \ + fsl_aid_mode = E_FMAN_DMA_AID_OUT_TNUM; break; \ + default: \ + fsl_aid_mode = E_FMAN_DMA_AID_OUT_PORT_ID; break; \ + } + +#define FMAN_DMA_DBG_CNT_TRANS(fsl_dma_dbg_cnt, _dma_dbg_cnt) \ + switch (_dma_dbg_cnt){ \ + case e_FM_DMA_DBG_NO_CNT: \ + fsl_dma_dbg_cnt = E_FMAN_DMA_DBG_NO_CNT; break; \ + case e_FM_DMA_DBG_CNT_DONE: \ + fsl_dma_dbg_cnt = E_FMAN_DMA_DBG_CNT_DONE; break; \ + case e_FM_DMA_DBG_CNT_COMM_Q_EM: \ + fsl_dma_dbg_cnt = E_FMAN_DMA_DBG_CNT_COMM_Q_EM; break; \ + case e_FM_DMA_DBG_CNT_INT_READ_EM: \ + fsl_dma_dbg_cnt = E_FMAN_DMA_DBG_CNT_INT_READ_EM; break; \ + case e_FM_DMA_DBG_CNT_INT_WRITE_EM: \ + fsl_dma_dbg_cnt = E_FMAN_DMA_DBG_CNT_INT_WRITE_EM ; break; \ + case e_FM_DMA_DBG_CNT_FPM_WAIT: \ + fsl_dma_dbg_cnt = E_FMAN_DMA_DBG_CNT_FPM_WAIT ; break; \ + case e_FM_DMA_DBG_CNT_SIGLE_BIT_ECC: \ + fsl_dma_dbg_cnt = E_FMAN_DMA_DBG_CNT_SIGLE_BIT_ECC ; break; \ + case e_FM_DMA_DBG_CNT_RAW_WAR_PROT: \ + fsl_dma_dbg_cnt = E_FMAN_DMA_DBG_CNT_RAW_WAR_PROT ; break; \ + default: \ + fsl_dma_dbg_cnt = E_FMAN_DMA_DBG_NO_CNT; break; \ + } + +#define FMAN_DMA_EMER_TRANS(fsl_dma_emer, _dma_emer) \ + switch (_dma_emer){ \ + case e_FM_DMA_EM_EBS: \ + fsl_dma_emer = E_FMAN_DMA_EM_EBS; break; \ + case e_FM_DMA_EM_SOS: \ + fsl_dma_emer = E_FMAN_DMA_EM_SOS; break; \ + default: \ + fsl_dma_emer = E_FMAN_DMA_EM_EBS; break; \ + } + +#define FMAN_DMA_ERR_TRANS(fsl_dma_err, _dma_err) \ + switch (_dma_err){ \ + case e_FM_DMA_ERR_CATASTROPHIC: \ + fsl_dma_err = E_FMAN_DMA_ERR_CATASTROPHIC; break; \ + case e_FM_DMA_ERR_REPORT: \ + fsl_dma_err = E_FMAN_DMA_ERR_REPORT; break; \ + default: \ + fsl_dma_err = E_FMAN_DMA_ERR_CATASTROPHIC; break; \ + } + +#define FMAN_CATASTROPHIC_ERR_TRANS(fsl_catastrophic_err, _catastrophic_err) \ + switch (_catastrophic_err){ \ + case e_FM_CATASTROPHIC_ERR_STALL_PORT: \ + fsl_catastrophic_err = E_FMAN_CATAST_ERR_STALL_PORT; break; \ + case e_FM_CATASTROPHIC_ERR_STALL_TASK: \ + fsl_catastrophic_err = E_FMAN_CATAST_ERR_STALL_TASK; break; \ + default: \ + fsl_catastrophic_err = E_FMAN_CATAST_ERR_STALL_PORT; break; \ + } + +#define FMAN_COUNTERS_TRANS(fsl_counters, _counters) \ + switch (_counters){ \ + case e_FM_COUNTERS_ENQ_TOTAL_FRAME: \ + fsl_counters = E_FMAN_COUNTERS_ENQ_TOTAL_FRAME; break; \ + case e_FM_COUNTERS_DEQ_TOTAL_FRAME: \ + fsl_counters = E_FMAN_COUNTERS_DEQ_TOTAL_FRAME; break; \ + case e_FM_COUNTERS_DEQ_0: \ + fsl_counters = E_FMAN_COUNTERS_DEQ_0; break; \ + case e_FM_COUNTERS_DEQ_1: \ + fsl_counters = E_FMAN_COUNTERS_DEQ_1; break; \ + case e_FM_COUNTERS_DEQ_2: \ + fsl_counters = E_FMAN_COUNTERS_DEQ_2; break; \ + case e_FM_COUNTERS_DEQ_3: \ + fsl_counters = E_FMAN_COUNTERS_DEQ_3; break; \ + case e_FM_COUNTERS_DEQ_FROM_DEFAULT: \ + fsl_counters = E_FMAN_COUNTERS_DEQ_FROM_DEFAULT; break; \ + case e_FM_COUNTERS_DEQ_FROM_CONTEXT: \ + fsl_counters = E_FMAN_COUNTERS_DEQ_FROM_CONTEXT; break; \ + case e_FM_COUNTERS_DEQ_FROM_FD: \ + fsl_counters = E_FMAN_COUNTERS_DEQ_FROM_FD; break; \ + case e_FM_COUNTERS_DEQ_CONFIRM: \ + fsl_counters = E_FMAN_COUNTERS_DEQ_CONFIRM; break; \ + default: \ + fsl_counters = E_FMAN_COUNTERS_ENQ_TOTAL_FRAME; break; \ + } + +/**************************************************************************//** + @Description defaults +*//***************************************************************************/ +#define DEFAULT_exceptions (FM_EX_DMA_BUS_ERROR |\ + FM_EX_DMA_READ_ECC |\ + FM_EX_DMA_SYSTEM_WRITE_ECC |\ + FM_EX_DMA_FM_WRITE_ECC |\ + FM_EX_FPM_STALL_ON_TASKS |\ + FM_EX_FPM_SINGLE_ECC |\ + FM_EX_FPM_DOUBLE_ECC |\ + FM_EX_QMI_DEQ_FROM_UNKNOWN_PORTID|\ + FM_EX_BMI_LIST_RAM_ECC |\ + FM_EX_BMI_STORAGE_PROFILE_ECC |\ + FM_EX_BMI_STATISTICS_RAM_ECC |\ + FM_EX_IRAM_ECC |\ + FM_EX_MURAM_ECC |\ + FM_EX_BMI_DISPATCH_RAM_ECC |\ + FM_EX_QMI_DOUBLE_ECC |\ + FM_EX_QMI_SINGLE_ECC) + +#define DEFAULT_eccEnable FALSE +#ifdef FM_PEDANTIC_DMA +#define DEFAULT_aidOverride TRUE +#else +#define DEFAULT_aidOverride FALSE +#endif /* FM_PEDANTIC_DMA */ +#define DEFAULT_aidMode e_FM_DMA_AID_OUT_TNUM +#define DEFAULT_dmaStopOnBusError FALSE +#define DEFAULT_stopAtBusError FALSE +#define DEFAULT_axiDbgNumOfBeats 1 +#define DEFAULT_dmaReadIntBufLow ((DMA_THRESH_MAX_BUF+1)/2) +#define DEFAULT_dmaReadIntBufHigh ((DMA_THRESH_MAX_BUF+1)*3/4) +#define DEFAULT_dmaWriteIntBufLow ((DMA_THRESH_MAX_BUF+1)/2) +#define DEFAULT_dmaWriteIntBufHigh ((DMA_THRESH_MAX_BUF+1)*3/4) +#define DEFAULT_catastrophicErr e_FM_CATASTROPHIC_ERR_STALL_PORT +#define DEFAULT_dmaErr e_FM_DMA_ERR_CATASTROPHIC +#define DEFAULT_resetOnInit FALSE +#define DEFAULT_resetOnInitOverrideCallback NULL +#define DEFAULT_haltOnExternalActivation FALSE /* do not change! if changed, must be disabled for rev1 ! */ +#define DEFAULT_haltOnUnrecoverableEccError FALSE /* do not change! if changed, must be disabled for rev1 ! */ +#define DEFAULT_externalEccRamsEnable FALSE +#define DEFAULT_VerifyUcode FALSE + +#if (DPAA_VERSION < 11) +#define DEFAULT_totalFifoSize(major, minor) \ + (((major == 2) || (major == 5)) ? \ + (100*KILOBYTE) : ((major == 4) ? \ + (49*KILOBYTE) : (122*KILOBYTE))) +#define DEFAULT_totalNumOfTasks(major, minor) \ + BMI_MAX_NUM_OF_TASKS + +#define DEFAULT_dmaCommQLow ((DMA_THRESH_MAX_COMMQ+1)/2) +#define DEFAULT_dmaCommQHigh ((DMA_THRESH_MAX_COMMQ+1)*3/4) +#define DEFAULT_cacheOverride e_FM_DMA_NO_CACHE_OR +#define DEFAULT_dmaCamNumOfEntries 32 +#define DEFAULT_dmaDbgCntMode e_FM_DMA_DBG_NO_CNT +#define DEFAULT_dmaEnEmergency FALSE +#define DEFAULT_dmaSosEmergency 0 +#define DEFAULT_dmaWatchdog 0 /* disabled */ +#define DEFAULT_dmaEnEmergencySmoother FALSE +#define DEFAULT_dmaEmergencySwitchCounter 0 + +#define DEFAULT_dispLimit 0 +#define DEFAULT_prsDispTh 16 +#define DEFAULT_plcrDispTh 16 +#define DEFAULT_kgDispTh 16 +#define DEFAULT_bmiDispTh 16 +#define DEFAULT_qmiEnqDispTh 16 +#define DEFAULT_qmiDeqDispTh 16 +#define DEFAULT_fmCtl1DispTh 16 +#define DEFAULT_fmCtl2DispTh 16 + +#else /* (DPAA_VERSION < 11) */ +/* Defaults are registers' reset values */ +#define DEFAULT_totalFifoSize(major, minor) \ + (((major == 6) && ((minor == 1) || (minor == 4))) ? \ + (156*KILOBYTE) : (295*KILOBYTE)) + +/* According to the default value of FMBM_CFG2[TNTSKS] */ +#define DEFAULT_totalNumOfTasks(major, minor) \ + (((major == 6) && ((minor == 1) || (minor == 4))) ? 59 : 124) + +#define DEFAULT_dmaCommQLow 0x2A +#define DEFAULT_dmaCommQHigh 0x3F +#define DEFAULT_cacheOverride e_FM_DMA_NO_CACHE_OR +#define DEFAULT_dmaCamNumOfEntries 64 +#define DEFAULT_dmaDbgCntMode e_FM_DMA_DBG_NO_CNT +#define DEFAULT_dmaEnEmergency FALSE +#define DEFAULT_dmaSosEmergency 0 +#define DEFAULT_dmaWatchdog 0 /* disabled */ +#define DEFAULT_dmaEnEmergencySmoother FALSE +#define DEFAULT_dmaEmergencySwitchCounter 0 + +#define DEFAULT_dispLimit 0 +#define DEFAULT_prsDispTh 16 +#define DEFAULT_plcrDispTh 16 +#define DEFAULT_kgDispTh 16 +#define DEFAULT_bmiDispTh 16 +#define DEFAULT_qmiEnqDispTh 16 +#define DEFAULT_qmiDeqDispTh 16 +#define DEFAULT_fmCtl1DispTh 16 +#define DEFAULT_fmCtl2DispTh 16 +#endif /* (DPAA_VERSION < 11) */ + +#define FM_TIMESTAMP_1_USEC_BIT 8 + +/**************************************************************************//** + @Collection Defines used for enabling/disabling FM interrupts + @{ +*//***************************************************************************/ +#define ERR_INTR_EN_DMA 0x00010000 +#define ERR_INTR_EN_FPM 0x80000000 +#define ERR_INTR_EN_BMI 0x00800000 +#define ERR_INTR_EN_QMI 0x00400000 +#define ERR_INTR_EN_PRS 0x00200000 +#define ERR_INTR_EN_KG 0x00100000 +#define ERR_INTR_EN_PLCR 0x00080000 +#define ERR_INTR_EN_MURAM 0x00040000 +#define ERR_INTR_EN_IRAM 0x00020000 +#define ERR_INTR_EN_10G_MAC0 0x00008000 +#define ERR_INTR_EN_10G_MAC1 0x00000040 +#define ERR_INTR_EN_1G_MAC0 0x00004000 +#define ERR_INTR_EN_1G_MAC1 0x00002000 +#define ERR_INTR_EN_1G_MAC2 0x00001000 +#define ERR_INTR_EN_1G_MAC3 0x00000800 +#define ERR_INTR_EN_1G_MAC4 0x00000400 +#define ERR_INTR_EN_1G_MAC5 0x00000200 +#define ERR_INTR_EN_1G_MAC6 0x00000100 +#define ERR_INTR_EN_1G_MAC7 0x00000080 +#define ERR_INTR_EN_MACSEC_MAC0 0x00000001 + +#define INTR_EN_QMI 0x40000000 +#define INTR_EN_PRS 0x20000000 +#define INTR_EN_WAKEUP 0x10000000 +#define INTR_EN_PLCR 0x08000000 +#define INTR_EN_1G_MAC0 0x00080000 +#define INTR_EN_1G_MAC1 0x00040000 +#define INTR_EN_1G_MAC2 0x00020000 +#define INTR_EN_1G_MAC3 0x00010000 +#define INTR_EN_1G_MAC4 0x00000040 +#define INTR_EN_1G_MAC5 0x00000020 +#define INTR_EN_1G_MAC6 0x00000008 +#define INTR_EN_1G_MAC7 0x00000002 +#define INTR_EN_10G_MAC0 0x00200000 +#define INTR_EN_10G_MAC1 0x00100000 +#define INTR_EN_REV0 0x00008000 +#define INTR_EN_REV1 0x00004000 +#define INTR_EN_REV2 0x00002000 +#define INTR_EN_REV3 0x00001000 +#define INTR_EN_BRK 0x00000080 +#define INTR_EN_TMR 0x01000000 +#define INTR_EN_MACSEC_MAC0 0x00000001 +/* @} */ + +/**************************************************************************//** + @Description Memory Mapped Registers +*//***************************************************************************/ + +#if defined(__MWERKS__) && !defined(__GNUC__) +#pragma pack(push,1) +#endif /* defined(__MWERKS__) && ... */ + +typedef struct +{ + volatile uint32_t iadd; /**< FM IRAM instruction address register */ + volatile uint32_t idata; /**< FM IRAM instruction data register */ + volatile uint32_t itcfg; /**< FM IRAM timing config register */ + volatile uint32_t iready; /**< FM IRAM ready register */ + volatile uint32_t res[0x1FFFC]; +} t_FMIramRegs; + +/* Trace buffer registers - + each FM Controller has its own trace buffer residing at FM_MM_TRB(fmCtrlIndex) offset */ +typedef struct t_FmTrbRegs +{ + volatile uint32_t tcrh; + volatile uint32_t tcrl; + volatile uint32_t tesr; + volatile uint32_t tecr0h; + volatile uint32_t tecr0l; + volatile uint32_t terf0h; + volatile uint32_t terf0l; + volatile uint32_t tecr1h; + volatile uint32_t tecr1l; + volatile uint32_t terf1h; + volatile uint32_t terf1l; + volatile uint32_t tpcch; + volatile uint32_t tpccl; + volatile uint32_t tpc1h; + volatile uint32_t tpc1l; + volatile uint32_t tpc2h; + volatile uint32_t tpc2l; + volatile uint32_t twdimr; + volatile uint32_t twicvr; + volatile uint32_t tar; + volatile uint32_t tdr; + volatile uint32_t tsnum1; + volatile uint32_t tsnum2; + volatile uint32_t tsnum3; + volatile uint32_t tsnum4; +} t_FmTrbRegs; + +#if defined(__MWERKS__) && !defined(__GNUC__) +#pragma pack(pop) +#endif /* defined(__MWERKS__) && ... */ + +/**************************************************************************//** + @Description General defines +*//***************************************************************************/ +#define FM_DEBUG_STATUS_REGISTER_OFFSET 0x000d1084UL +#define FM_FW_DEBUG_INSTRUCTION 0x6ffff805UL + +/**************************************************************************//** + @Description FPM defines +*//***************************************************************************/ +/* masks */ +#define FPM_BRKC_RDBG 0x00000200 +#define FPM_BRKC_SLP 0x00000800 +/**************************************************************************//** + @Description BMI defines +*//***************************************************************************/ +/* masks */ +#define BMI_INIT_START 0x80000000 +#define BMI_ERR_INTR_EN_STORAGE_PROFILE_ECC 0x80000000 +#define BMI_ERR_INTR_EN_LIST_RAM_ECC 0x40000000 +#define BMI_ERR_INTR_EN_STATISTICS_RAM_ECC 0x20000000 +#define BMI_ERR_INTR_EN_DISPATCH_RAM_ECC 0x10000000 +/**************************************************************************//** + @Description QMI defines +*//***************************************************************************/ +/* masks */ +#define QMI_ERR_INTR_EN_DOUBLE_ECC 0x80000000 +#define QMI_ERR_INTR_EN_DEQ_FROM_DEF 0x40000000 +#define QMI_INTR_EN_SINGLE_ECC 0x80000000 + +/**************************************************************************//** + @Description IRAM defines +*//***************************************************************************/ +/* masks */ +#define IRAM_IADD_AIE 0x80000000 +#define IRAM_READY 0x80000000 + +/**************************************************************************//** + @Description TRB defines +*//***************************************************************************/ +/* masks */ +#define TRB_TCRH_RESET 0x04000000 +#define TRB_TCRH_ENABLE_COUNTERS 0x84008000 +#define TRB_TCRH_DISABLE_COUNTERS 0x8400C000 +#define TRB_TCRL_RESET 0x20000000 +#define TRB_TCRL_UTIL 0x00000460 +typedef struct { + void (*f_Isr) (t_Handle h_Arg, uint32_t event); + t_Handle h_SrcHandle; +} t_FmanCtrlIntrSrc; + + +typedef void (t_FmanCtrlIsr)( t_Handle h_Fm, uint32_t event); + +typedef struct +{ +/***************************/ +/* Master/Guest parameters */ +/***************************/ + uint8_t fmId; + e_FmPortType portsTypes[FM_MAX_NUM_OF_HW_PORT_IDS]; + uint16_t fmClkFreq; + uint16_t fmMacClkFreq; + t_FmRevisionInfo revInfo; +/**************************/ +/* Master Only parameters */ +/**************************/ + bool enabledTimeStamp; + uint8_t count1MicroBit; + uint8_t totalNumOfTasks; + uint32_t totalFifoSize; + uint8_t maxNumOfOpenDmas; + uint8_t accumulatedNumOfTasks; + uint32_t accumulatedFifoSize; + uint8_t accumulatedNumOfOpenDmas; + uint8_t accumulatedNumOfDeqTnums; +#ifdef FM_LOW_END_RESTRICTION + bool lowEndRestriction; +#endif /* FM_LOW_END_RESTRICTION */ + uint32_t exceptions; + int irq; + int errIrq; + bool ramsEccEnable; + bool explicitEnable; + bool internalCall; + uint8_t ramsEccOwners; + uint32_t extraFifoPoolSize; + uint8_t extraTasksPoolSize; + uint8_t extraOpenDmasPoolSize; +#if defined(FM_MAX_NUM_OF_10G_MACS) && (FM_MAX_NUM_OF_10G_MACS) + uint16_t portMaxFrameLengths10G[FM_MAX_NUM_OF_10G_MACS]; + uint16_t macMaxFrameLengths10G[FM_MAX_NUM_OF_10G_MACS]; +#endif /* defined(FM_MAX_NUM_OF_10G_MACS) && ... */ + uint16_t portMaxFrameLengths1G[FM_MAX_NUM_OF_1G_MACS]; + uint16_t macMaxFrameLengths1G[FM_MAX_NUM_OF_1G_MACS]; +} t_FmStateStruct; + +#if (DPAA_VERSION >= 11) +typedef struct t_FmMapParam { + uint16_t profilesBase; + uint16_t numOfProfiles; + t_Handle h_FmPort; +} t_FmMapParam; + +typedef struct t_FmAllocMng { + bool allocated; + uint8_t ownerId; /* guestId for KG in multi-partition only, + portId for PLCR in any environment */ +} t_FmAllocMng; + +typedef struct t_FmPcdSpEntry { + bool valid; + t_FmAllocMng profilesMng; +} t_FmPcdSpEntry; + +typedef struct t_FmSp { + void *p_FmPcdStoragePrflRegs; + t_FmPcdSpEntry profiles[FM_VSP_MAX_NUM_OF_ENTRIES]; + t_FmMapParam portsMapping[FM_MAX_NUM_OF_PORTS]; +} t_FmSp; +#endif /* (DPAA_VERSION >= 11) */ + +typedef struct t_Fm +{ +/***************************/ +/* Master/Guest parameters */ +/***************************/ +/* locals for recovery */ + uintptr_t baseAddr; + +/* un-needed for recovery */ + t_Handle h_Pcd; + char fmModuleName[MODULE_NAME_SIZE]; + char fmIpcHandlerModuleName[FM_MAX_NUM_OF_GUESTS][MODULE_NAME_SIZE]; + t_Handle h_IpcSessions[FM_MAX_NUM_OF_GUESTS]; + t_FmIntrSrc intrMng[e_FM_EV_DUMMY_LAST]; /* FM exceptions user callback */ + uint8_t guestId; +/**************************/ +/* Master Only parameters */ +/**************************/ +/* locals for recovery */ + struct fman_fpm_regs *p_FmFpmRegs; + struct fman_bmi_regs *p_FmBmiRegs; + struct fman_qmi_regs *p_FmQmiRegs; + struct fman_dma_regs *p_FmDmaRegs; + struct fman_regs *p_FmRegs; + t_FmExceptionsCallback *f_Exception; + t_FmBusErrorCallback *f_BusError; + t_Handle h_App; /* Application handle */ + t_Handle h_Spinlock; + bool recoveryMode; + t_FmStateStruct *p_FmStateStruct; + uint16_t tnumAgingPeriod; +#if (DPAA_VERSION >= 11) + t_FmSp *p_FmSp; + uint8_t partNumOfVSPs; + uint8_t partVSPBase; + uintptr_t vspBaseAddr; +#endif /* (DPAA_VERSION >= 11) */ + bool portsPreFetchConfigured[FM_MAX_NUM_OF_HW_PORT_IDS]; /* Prefetch configration per Tx-port */ + bool portsPreFetchValue[FM_MAX_NUM_OF_HW_PORT_IDS]; /* Prefetch configration per Tx-port */ + +/* un-needed for recovery */ + struct fman_cfg *p_FmDriverParam; + t_Handle h_FmMuram; + uint64_t fmMuramPhysBaseAddr; + bool independentMode; + bool hcPortInitialized; + uintptr_t camBaseAddr; /* save for freeing */ + uintptr_t resAddr; + uintptr_t fifoBaseAddr; /* save for freeing */ + t_FmanCtrlIntrSrc fmanCtrlIntr[FM_NUM_OF_FMAN_CTRL_EVENT_REGS]; /* FM exceptions user callback */ + bool usedEventRegs[FM_NUM_OF_FMAN_CTRL_EVENT_REGS]; + t_FmFirmwareParams firmware; + bool fwVerify; + bool resetOnInit; + t_FmResetOnInitOverrideCallback *f_ResetOnInitOverride; + uint32_t userSetExceptions; +} t_Fm; + + +#endif /* __FM_H */ diff --git a/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/fm_ipc.h b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/fm_ipc.h new file mode 100644 index 000000000000..7ce36a767e25 --- /dev/null +++ b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/fm_ipc.h @@ -0,0 +1,465 @@ +/* + * Copyright 2008-2012 Freescale Semiconductor Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Freescale Semiconductor nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * + * ALTERNATIVELY, this software may be distributed under the terms of the + * GNU General Public License ("GPL") as published by the Free Software + * Foundation, either version 2 of that License or (at your option) any + * later version. + * + * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + +/**************************************************************************//** + @File fm_ipc.h + + @Description FM Inter-Partition prototypes, structures and definitions. +*//***************************************************************************/ +#ifndef __FM_IPC_H +#define __FM_IPC_H + +#include "error_ext.h" +#include "std_ext.h" + + +/**************************************************************************//** + @Group FM_grp Frame Manager API + + @Description FM API functions, definitions and enums + + @{ +*//***************************************************************************/ + +/**************************************************************************//** + @Group FM_IPC_grp FM Inter-Partition messaging Unit + + @Description FM Inter-Partition messaging unit API definitions and enums. + + @{ +*//***************************************************************************/ + +#if defined(__MWERKS__) && !defined(__GNUC__) +#pragma pack(push,1) +#endif /* defined(__MWERKS__) && ... */ + +/**************************************************************************//** + @Description enum for defining MAC types +*//***************************************************************************/ + +/**************************************************************************//** + @Description A structure of parameters for specifying a MAC. +*//***************************************************************************/ +typedef _Packed struct +{ + uint8_t id; + uint32_t enumType; +} _PackedType t_FmIpcMacParams; + +/**************************************************************************//** + @Description A structure of parameters for specifying a MAC. +*//***************************************************************************/ +typedef _Packed struct +{ + t_FmIpcMacParams macParams; + uint16_t maxFrameLength; +} _PackedType t_FmIpcMacMaxFrameParams; + +/**************************************************************************//** + @Description FM physical Address +*//***************************************************************************/ +typedef _Packed struct t_FmIpcPhysAddr +{ + volatile uint8_t high; + volatile uint32_t low; +} _PackedType t_FmIpcPhysAddr; + + +typedef _Packed struct t_FmIpcPortOutInitParams { + uint8_t numOfTasks; /**< OUT */ + uint8_t numOfExtraTasks; /**< OUT */ + uint8_t numOfOpenDmas; /**< OUT */ + uint8_t numOfExtraOpenDmas; /**< OUT */ + uint32_t sizeOfFifo; /**< OUT */ + uint32_t extraSizeOfFifo; /**< OUT */ + t_FmIpcPhysAddr ipcPhysAddr; /**< OUT */ +} _PackedType t_FmIpcPortOutInitParams; + +/**************************************************************************//** + @Description Structure for IPC communication during FM_PORT_Init. +*//***************************************************************************/ +typedef _Packed struct t_FmIpcPortInInitParams { + uint8_t hardwarePortId; /**< IN. port Id */ + uint32_t enumPortType; /**< IN. Port type */ + uint8_t boolIndependentMode;/**< IN. TRUE if FM Port operates in independent mode */ + uint16_t liodnOffset; /**< IN. Port's requested resource */ + uint8_t numOfTasks; /**< IN. Port's requested resource */ + uint8_t numOfExtraTasks; /**< IN. Port's requested resource */ + uint8_t numOfOpenDmas; /**< IN. Port's requested resource */ + uint8_t numOfExtraOpenDmas; /**< IN. Port's requested resource */ + uint32_t sizeOfFifo; /**< IN. Port's requested resource */ + uint32_t extraSizeOfFifo; /**< IN. Port's requested resource */ + uint8_t deqPipelineDepth; /**< IN. Port's requested resource */ + uint16_t maxFrameLength; /**< IN. Port's max frame length. */ + uint16_t liodnBase; /**< IN. Irrelevant for P4080 rev 1. + LIODN base for this port, to be + used together with LIODN offset. */ +} _PackedType t_FmIpcPortInInitParams; + + +/**************************************************************************//** + @Description Structure for IPC communication between port and FM + regarding tasks and open DMA resources management. +*//***************************************************************************/ +typedef _Packed struct t_FmIpcPortRsrcParams { + uint8_t hardwarePortId; /**< IN. port Id */ + uint32_t val; /**< IN. Port's requested resource */ + uint32_t extra; /**< IN. Port's requested resource */ + uint8_t boolInitialConfig; +} _PackedType t_FmIpcPortRsrcParams; + + +/**************************************************************************//** + @Description Structure for IPC communication between port and FM + regarding tasks and open DMA resources management. +*//***************************************************************************/ +typedef _Packed struct t_FmIpcPortFifoParams { + t_FmIpcPortRsrcParams rsrcParams; + uint32_t enumPortType; + uint8_t boolIndependentMode; + uint8_t deqPipelineDepth; + uint8_t numOfPools; + uint16_t secondLargestBufSize; + uint16_t largestBufSize; + uint8_t boolInitialConfig; +} _PackedType t_FmIpcPortFifoParams; + +/**************************************************************************//** + @Description Structure for port-FM communication during FM_PORT_Free. +*//***************************************************************************/ +typedef _Packed struct t_FmIpcPortFreeParams { + uint8_t hardwarePortId; /**< IN. port Id */ + uint32_t enumPortType; /**< IN. Port type */ + uint8_t deqPipelineDepth; /**< IN. Port's requested resource */ +} _PackedType t_FmIpcPortFreeParams; + +/**************************************************************************//** + @Description Structure for defining DMA status +*//***************************************************************************/ +typedef _Packed struct t_FmIpcDmaStatus { + uint8_t boolCmqNotEmpty; /**< Command queue is not empty */ + uint8_t boolBusError; /**< Bus error occurred */ + uint8_t boolReadBufEccError; /**< Double ECC error on buffer Read */ + uint8_t boolWriteBufEccSysError; /**< Double ECC error on buffer write from system side */ + uint8_t boolWriteBufEccFmError; /**< Double ECC error on buffer write from FM side */ + uint8_t boolSinglePortEccError; /**< Single port ECC error from FM side */ +} _PackedType t_FmIpcDmaStatus; + +typedef _Packed struct t_FmIpcRegisterIntr +{ + uint8_t guestId; /* IN */ + uint32_t event; /* IN */ +} _PackedType t_FmIpcRegisterIntr; + +typedef _Packed struct t_FmIpcIsr +{ + uint8_t boolErr; /* IN */ + uint32_t pendingReg; /* IN */ +} _PackedType t_FmIpcIsr; + +/**************************************************************************//** + @Description structure for returning FM parameters +*//***************************************************************************/ +typedef _Packed struct t_FmIpcParams { + uint16_t fmClkFreq; /**< OUT: FM Clock frequency */ + uint16_t fmMacClkFreq; /**< OUT: FM MAC clock frequence */ + uint8_t majorRev; /**< OUT: FM Major revision */ + uint8_t minorRev; /**< OUT: FM Minor revision */ +} _PackedType t_FmIpcParams; + + +/**************************************************************************//** + @Description structure for returning Fman Ctrl Code revision information +*//***************************************************************************/ +typedef _Packed struct t_FmIpcFmanCtrlCodeRevisionInfo { + uint16_t packageRev; /**< OUT: Package revision */ + uint8_t majorRev; /**< OUT: Major revision */ + uint8_t minorRev; /**< OUT: Minor revision */ +} _PackedType t_FmIpcFmanCtrlCodeRevisionInfo; + +/**************************************************************************//** + @Description Structure for defining Fm number of Fman controlers +*//***************************************************************************/ +typedef _Packed struct t_FmIpcPortNumOfFmanCtrls { + uint8_t hardwarePortId; /**< IN. port Id */ + uint8_t numOfFmanCtrls; /**< IN. Port type */ + t_FmFmanCtrl orFmanCtrl; /**< IN. fman controller for order restoration*/ +} t_FmIpcPortNumOfFmanCtrls; + +/**************************************************************************//** + @Description structure for setting Fman contriller events +*//***************************************************************************/ +typedef _Packed struct t_FmIpcFmanEvents { + uint8_t eventRegId; /**< IN: Fman controller event register id */ + uint32_t enableEvents; /**< IN/OUT: required enabled events mask */ +} _PackedType t_FmIpcFmanEvents; + +typedef _Packed struct t_FmIpcResourceAllocParams { + uint8_t guestId; + uint16_t base; + uint16_t num; +}_PackedType t_FmIpcResourceAllocParams; + +typedef _Packed struct t_FmIpcVspSetPortWindow { + uint8_t hardwarePortId; + uint8_t baseStorageProfile; + uint8_t log2NumOfProfiles; +}_PackedType t_FmIpcVspSetPortWindow; + +typedef _Packed struct t_FmIpcSetCongestionGroupPfcPriority { + uint32_t congestionGroupId; + uint8_t priorityBitMap; +}_PackedType t_FmIpcSetCongestionGroupPfcPriority; + +#define FM_IPC_MAX_REPLY_BODY_SIZE 20 +#define FM_IPC_MAX_REPLY_SIZE (FM_IPC_MAX_REPLY_BODY_SIZE + sizeof(uint32_t)) +#define FM_IPC_MAX_MSG_SIZE 30 + +typedef _Packed struct t_FmIpcMsg +{ + uint32_t msgId; + uint8_t msgBody[FM_IPC_MAX_MSG_SIZE]; +} _PackedType t_FmIpcMsg; + +typedef _Packed struct t_FmIpcReply +{ + uint32_t error; + uint8_t replyBody[FM_IPC_MAX_REPLY_BODY_SIZE]; +} _PackedType t_FmIpcReply; + +#if defined(__MWERKS__) && !defined(__GNUC__) +#pragma pack(pop) +#endif /* defined(__MWERKS__) && ... */ + + +/***************************************************************************/ +/************************ FRONT-END-TO-BACK-END*****************************/ +/***************************************************************************/ + +/**************************************************************************//** + @Function FM_GET_TIMESTAMP_SCALE + + @Description Used by FM front-end. + + @Param[out] uint32_t Pointer +*//***************************************************************************/ +#define FM_GET_TIMESTAMP_SCALE 1 + +/**************************************************************************//** + @Function FM_GET_COUNTER + + @Description Used by FM front-end. + + @Param[in/out] t_FmIpcGetCounter Pointer +*//***************************************************************************/ +#define FM_GET_COUNTER 2 + +/**************************************************************************//** + @Function FM_GET_SET_PORT_PARAMS + + @Description Used by FM front-end for the PORT module in order to set and get + parameters in/from master FM module on FM PORT initialization time. + + @Param[in/out] t_FmIcPortInitParams Pointer +*//***************************************************************************/ +#define FM_GET_SET_PORT_PARAMS 4 + +/**************************************************************************//** + @Function FM_FREE_PORT + + @Description Used by FM front-end for the PORT module when a port is freed + to free all FM PORT resources. + + @Param[in] uint8_t Pointer +*//***************************************************************************/ +#define FM_FREE_PORT 5 + +/**************************************************************************//** + @Function FM_RESET_MAC + + @Description Used by front-end for the MAC module to reset the MAC registers + + @Param[in] t_FmIpcMacParams Pointer . +*//***************************************************************************/ +#define FM_RESET_MAC 6 + +/**************************************************************************//** + @Function FM_RESUME_STALLED_PORT + + @Description Used by FM front-end for the PORT module in order to + release a stalled FM Port. + + @Param[in] uint8_t Pointer +*//***************************************************************************/ +#define FM_RESUME_STALLED_PORT 7 + +/**************************************************************************//** + @Function FM_IS_PORT_STALLED + + @Description Used by FM front-end for the PORT module in order to check whether + an FM port is stalled. + + @Param[in/out] t_FmIcPortIsStalled Pointer +*//***************************************************************************/ +#define FM_IS_PORT_STALLED 8 + +/**************************************************************************//** + @Function FM_GET_PARAMS + + @Description Used by FM front-end for the PORT module in order to dump + return FM parameters. + + @Param[in] uint8_t Pointer +*//***************************************************************************/ +#define FM_GET_PARAMS 10 + +/**************************************************************************//** + @Function FM_REGISTER_INTR + + @Description Used by FM front-end to register an interrupt handler to + be called upon interrupt for guest. + + @Param[out] t_FmIpcRegisterIntr Pointer +*//***************************************************************************/ +#define FM_REGISTER_INTR 11 + +/**************************************************************************//** + @Function FM_DMA_STAT + + @Description Used by FM front-end to read the FM DMA status. + + @Param[out] t_FmIpcDmaStatus Pointer +*//***************************************************************************/ +#define FM_DMA_STAT 13 + +/**************************************************************************//** + @Function FM_ALLOC_FMAN_CTRL_EVENT_REG + + @Description Used by FM front-end to allocate event register. + + @Param[out] Event register id Pointer +*//***************************************************************************/ +#define FM_ALLOC_FMAN_CTRL_EVENT_REG 14 + +/**************************************************************************//** + @Function FM_FREE_FMAN_CTRL_EVENT_REG + + @Description Used by FM front-end to free locate event register. + + @Param[in] uint8_t Pointer - Event register id +*//***************************************************************************/ +#define FM_FREE_FMAN_CTRL_EVENT_REG 15 + +/**************************************************************************//** + @Function FM_SET_FMAN_CTRL_EVENTS_ENABLE + + @Description Used by FM front-end to enable events in the FPM + Fman controller event register. + + @Param[in] t_FmIpcFmanEvents Pointer +*//***************************************************************************/ +#define FM_SET_FMAN_CTRL_EVENTS_ENABLE 16 + +/**************************************************************************//** + @Function FM_SET_FMAN_CTRL_EVENTS_ENABLE + + @Description Used by FM front-end to enable events in the FPM + Fman controller event register. + + @Param[in/out] t_FmIpcFmanEvents Pointer +*//***************************************************************************/ +#define FM_GET_FMAN_CTRL_EVENTS_ENABLE 17 + +/**************************************************************************//** + @Function FM_SET_MAC_MAX_FRAME + + @Description Used by FM front-end to set MAC's MTU/RTU's in + back-end. + + @Param[in/out] t_FmIpcMacMaxFrameParams Pointer +*//***************************************************************************/ +#define FM_SET_MAC_MAX_FRAME 18 + +/**************************************************************************//** + @Function FM_GET_PHYS_MURAM_BASE + + @Description Used by FM front-end in order to get MURAM base address + + @Param[in/out] t_FmIpcPhysAddr Pointer +*//***************************************************************************/ +#define FM_GET_PHYS_MURAM_BASE 19 + +/**************************************************************************//** + @Function FM_MASTER_IS_ALIVE + + @Description Used by FM front-end in order to verify Master is up + + @Param[in/out] bool +*//***************************************************************************/ +#define FM_MASTER_IS_ALIVE 20 + +#define FM_ENABLE_RAM_ECC 21 +#define FM_DISABLE_RAM_ECC 22 +#define FM_SET_NUM_OF_FMAN_CTRL 23 +#define FM_SET_SIZE_OF_FIFO 24 +#define FM_SET_NUM_OF_TASKS 25 +#define FM_SET_NUM_OF_OPEN_DMAS 26 +#define FM_VSP_ALLOC 27 +#define FM_VSP_FREE 28 +#define FM_VSP_SET_PORT_WINDOW 29 +#define FM_GET_FMAN_CTRL_CODE_REV 30 +#define FM_SET_CONG_GRP_PFC_PRIO 31 +#ifdef FM_TX_ECC_FRMS_ERRATA_10GMAC_A004 +#define FM_10G_TX_ECC_WA 100 +#endif /* FM_TX_ECC_FRMS_ERRATA_10GMAC_A004 */ + +/***************************************************************************/ +/************************ BACK-END-TO-FRONT-END*****************************/ +/***************************************************************************/ + +/**************************************************************************//** + @Function FM_GUEST_ISR + + @Description Used by FM back-end to report an interrupt to the front-end. + + @Param[out] t_FmIpcIsr Pointer +*//***************************************************************************/ +#define FM_GUEST_ISR 1 + + + +/** @} */ /* end of FM_IPC_grp group */ +/** @} */ /* end of FM_grp group */ + + +#endif /* __FM_IPC_H */ diff --git a/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/fm_muram.c b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/fm_muram.c new file mode 100644 index 000000000000..0bc67cb74b99 --- /dev/null +++ b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/fm_muram.c @@ -0,0 +1,174 @@ +/* + * Copyright 2008-2012 Freescale Semiconductor Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Freescale Semiconductor nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * + * ALTERNATIVELY, this software may be distributed under the terms of the + * GNU General Public License ("GPL") as published by the Free Software + * Foundation, either version 2 of that License or (at your option) any + * later version. + * + * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + +/****************************************************************************** + @File FM_muram.c + + @Description FM MURAM ... +*//***************************************************************************/ +#include "error_ext.h" +#include "std_ext.h" +#include "mm_ext.h" +#include "string_ext.h" +#include "sprint_ext.h" +#include "fm_muram_ext.h" +#include "fm_common.h" + +#define __ERR_MODULE__ MODULE_FM_MURAM + + +typedef struct +{ + t_Handle h_Mem; + uintptr_t baseAddr; + uint32_t size; +} t_FmMuram; + + +void FmMuramClear(t_Handle h_FmMuram) +{ + t_FmMuram *p_FmMuram = ( t_FmMuram *)h_FmMuram; + + SANITY_CHECK_RETURN(h_FmMuram, E_INVALID_HANDLE); + IOMemSet32(UINT_TO_PTR(p_FmMuram->baseAddr), 0, p_FmMuram->size); +} + + +t_Handle FM_MURAM_ConfigAndInit(uintptr_t baseAddress, uint32_t size) +{ + t_Handle h_Mem; + t_FmMuram *p_FmMuram; + + if (!baseAddress) + { + REPORT_ERROR(MAJOR, E_INVALID_VALUE, ("baseAddress 0 is not supported")); + return NULL; + } + + if (baseAddress%4) + { + REPORT_ERROR(MAJOR, E_INVALID_VALUE, ("baseAddress not 4 bytes aligned!")); + return NULL; + } + + /* Allocate FM MURAM structure */ + p_FmMuram = (t_FmMuram *) XX_Malloc(sizeof(t_FmMuram)); + if (!p_FmMuram) + { + REPORT_ERROR(MAJOR, E_NO_MEMORY, ("FM MURAM driver structure")); + return NULL; + } + memset(p_FmMuram, 0, sizeof(t_FmMuram)); + + + if ((MM_Init(&h_Mem, baseAddress, size) != E_OK) || (!h_Mem)) + { + XX_Free(p_FmMuram); + REPORT_ERROR(MAJOR, E_INVALID_HANDLE, ("FM-MURAM partition!!!")); + return NULL; + } + + /* Initialize FM MURAM parameters which will be kept by the driver */ + p_FmMuram->baseAddr = baseAddress; + p_FmMuram->size = size; + p_FmMuram->h_Mem = h_Mem; + + return p_FmMuram; +} + +t_Error FM_MURAM_Free(t_Handle h_FmMuram) +{ + t_FmMuram *p_FmMuram = ( t_FmMuram *)h_FmMuram; + + if (p_FmMuram->h_Mem) + MM_Free(p_FmMuram->h_Mem); + + XX_Free(h_FmMuram); + + return E_OK; +} + +void * FM_MURAM_AllocMem(t_Handle h_FmMuram, uint32_t size, uint32_t align) +{ + t_FmMuram *p_FmMuram = ( t_FmMuram *)h_FmMuram; + uintptr_t addr; + + SANITY_CHECK_RETURN_VALUE(h_FmMuram, E_INVALID_HANDLE, NULL); + SANITY_CHECK_RETURN_VALUE(p_FmMuram->h_Mem, E_INVALID_HANDLE, NULL); + + addr = (uintptr_t)MM_Get(p_FmMuram->h_Mem, size, align ,"FM MURAM"); + + if (addr == ILLEGAL_BASE) + return NULL; + + return UINT_TO_PTR(addr); +} + +void * FM_MURAM_AllocMemForce(t_Handle h_FmMuram, uint64_t base, uint32_t size) +{ + t_FmMuram *p_FmMuram = ( t_FmMuram *)h_FmMuram; + uintptr_t addr; + + SANITY_CHECK_RETURN_VALUE(h_FmMuram, E_INVALID_HANDLE, NULL); + SANITY_CHECK_RETURN_VALUE(p_FmMuram->h_Mem, E_INVALID_HANDLE, NULL); + + addr = (uintptr_t)MM_GetForce(p_FmMuram->h_Mem, base, size, "FM MURAM"); + + if (addr == ILLEGAL_BASE) + return NULL; + + return UINT_TO_PTR(addr); +} + +t_Error FM_MURAM_FreeMem(t_Handle h_FmMuram, void *ptr) +{ + t_FmMuram *p_FmMuram = ( t_FmMuram *)h_FmMuram; + + SANITY_CHECK_RETURN_ERROR(h_FmMuram, E_INVALID_HANDLE); + SANITY_CHECK_RETURN_ERROR(p_FmMuram->h_Mem, E_INVALID_HANDLE); + + if (MM_Put(p_FmMuram->h_Mem, PTR_TO_UINT(ptr)) == 0) + RETURN_ERROR(MINOR, E_INVALID_ADDRESS, ("memory pointer!!!")); + + return E_OK; +} + +uint64_t FM_MURAM_GetFreeMemSize(t_Handle h_FmMuram) +{ + t_FmMuram *p_FmMuram = ( t_FmMuram *)h_FmMuram; + + SANITY_CHECK_RETURN_VALUE(h_FmMuram, E_INVALID_HANDLE, 0); + SANITY_CHECK_RETURN_VALUE(p_FmMuram->h_Mem, E_INVALID_HANDLE, 0); + + return MM_GetFreeMemSize(p_FmMuram->h_Mem); +} diff --git a/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/fman.c b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/fman.c new file mode 100755 index 000000000000..76d229342ca9 --- /dev/null +++ b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/fman.c @@ -0,0 +1,1400 @@ +/* + * Copyright 2008-2012 Freescale Semiconductor Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Freescale Semiconductor nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * + * ALTERNATIVELY, this software may be distributed under the terms of the + * GNU General Public License ("GPL") as published by the Free Software + * Foundation, either version 2 of that License or (at your option) any + * later version. + * + * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + +#include "std_ext.h" +#include "error_ext.h" +#include <linux/math64.h> +#include "fsl_fman.h" +#include "dpaa_integration_ext.h" + +uint32_t fman_get_bmi_err_event(struct fman_bmi_regs *bmi_rg) +{ + uint32_t event, mask, force; + + event = ioread32be(&bmi_rg->fmbm_ievr); + mask = ioread32be(&bmi_rg->fmbm_ier); + event &= mask; + /* clear the forced events */ + force = ioread32be(&bmi_rg->fmbm_ifr); + if (force & event) + iowrite32be(force & ~event, &bmi_rg->fmbm_ifr); + /* clear the acknowledged events */ + iowrite32be(event, &bmi_rg->fmbm_ievr); + return event; +} + +uint32_t fman_get_qmi_err_event(struct fman_qmi_regs *qmi_rg) +{ + uint32_t event, mask, force; + + event = ioread32be(&qmi_rg->fmqm_eie); + mask = ioread32be(&qmi_rg->fmqm_eien); + event &= mask; + + /* clear the forced events */ + force = ioread32be(&qmi_rg->fmqm_eif); + if (force & event) + iowrite32be(force & ~event, &qmi_rg->fmqm_eif); + /* clear the acknowledged events */ + iowrite32be(event, &qmi_rg->fmqm_eie); + return event; +} + +uint32_t fman_get_dma_com_id(struct fman_dma_regs *dma_rg) +{ + return ioread32be(&dma_rg->fmdmtcid); +} + +uint64_t fman_get_dma_addr(struct fman_dma_regs *dma_rg) +{ + uint64_t addr; + + addr = (uint64_t)ioread32be(&dma_rg->fmdmtal); + addr |= ((uint64_t)(ioread32be(&dma_rg->fmdmtah)) << 32); + + return addr; +} + +uint32_t fman_get_dma_err_event(struct fman_dma_regs *dma_rg) +{ + uint32_t status, mask; + + status = ioread32be(&dma_rg->fmdmsr); + mask = ioread32be(&dma_rg->fmdmmr); + + /* clear DMA_STATUS_BUS_ERR if mask has no DMA_MODE_BER */ + if ((mask & DMA_MODE_BER) != DMA_MODE_BER) + status &= ~DMA_STATUS_BUS_ERR; + + /* clear relevant bits if mask has no DMA_MODE_ECC */ + if ((mask & DMA_MODE_ECC) != DMA_MODE_ECC) + status &= ~(DMA_STATUS_FM_SPDAT_ECC | + DMA_STATUS_READ_ECC | + DMA_STATUS_SYSTEM_WRITE_ECC | + DMA_STATUS_FM_WRITE_ECC); + + /* clear set events */ + iowrite32be(status, &dma_rg->fmdmsr); + + return status; +} + +uint32_t fman_get_fpm_err_event(struct fman_fpm_regs *fpm_rg) +{ + uint32_t event; + + event = ioread32be(&fpm_rg->fmfp_ee); + /* clear the all occurred events */ + iowrite32be(event, &fpm_rg->fmfp_ee); + return event; +} + +uint32_t fman_get_muram_err_event(struct fman_fpm_regs *fpm_rg) +{ + uint32_t event, mask; + + event = ioread32be(&fpm_rg->fm_rcr); + mask = ioread32be(&fpm_rg->fm_rie); + + /* clear MURAM event bit (do not clear IRAM event) */ + iowrite32be(event & ~FPM_RAM_IRAM_ECC, &fpm_rg->fm_rcr); + + if ((mask & FPM_MURAM_ECC_ERR_EX_EN)) + return event; + else + return 0; +} + +uint32_t fman_get_iram_err_event(struct fman_fpm_regs *fpm_rg) +{ + uint32_t event, mask; + + event = ioread32be(&fpm_rg->fm_rcr) ; + mask = ioread32be(&fpm_rg->fm_rie); + /* clear IRAM event bit (do not clear MURAM event) */ + iowrite32be(event & ~FPM_RAM_MURAM_ECC, + &fpm_rg->fm_rcr); + + if ((mask & FPM_IRAM_ECC_ERR_EX_EN)) + return event; + else + return 0; +} + +uint32_t fman_get_qmi_event(struct fman_qmi_regs *qmi_rg) +{ + uint32_t event, mask, force; + + event = ioread32be(&qmi_rg->fmqm_ie); + mask = ioread32be(&qmi_rg->fmqm_ien); + event &= mask; + /* clear the forced events */ + force = ioread32be(&qmi_rg->fmqm_if); + if (force & event) + iowrite32be(force & ~event, &qmi_rg->fmqm_if); + /* clear the acknowledged events */ + iowrite32be(event, &qmi_rg->fmqm_ie); + return event; +} + +void fman_enable_time_stamp(struct fman_fpm_regs *fpm_rg, + uint8_t count1ubit, + uint16_t fm_clk_freq) +{ + uint32_t tmp; + uint64_t frac; + uint32_t intgr; + uint32_t ts_freq = (uint32_t)(1 << count1ubit); /* in Mhz */ + + /* configure timestamp so that bit 8 will count 1 microsecond + * Find effective count rate at TIMESTAMP least significant bits: + * Effective_Count_Rate = 1MHz x 2^8 = 256MHz + * Find frequency ratio between effective count rate and the clock: + * Effective_Count_Rate / CLK e.g. for 600 MHz clock: + * 256/600 = 0.4266666... */ + + intgr = ts_freq / fm_clk_freq; + /* we multiply by 2^16 to keep the fraction of the division + * we do not div back, since we write this value as a fraction + * see spec */ + + frac = ((uint64_t)ts_freq << 16) - ((uint64_t)intgr << 16) * fm_clk_freq; + /* we check remainder of the division in order to round up if not int */ + if (do_div(frac, fm_clk_freq)) + frac++; + + tmp = (intgr << FPM_TS_INT_SHIFT) | (uint16_t)frac; + iowrite32be(tmp, &fpm_rg->fmfp_tsc2); + + /* enable timestamp with original clock */ + iowrite32be(FPM_TS_CTL_EN, &fpm_rg->fmfp_tsc1); +} + +uint32_t fman_get_fpm_error_interrupts(struct fman_fpm_regs *fpm_rg) +{ + return ioread32be(&fpm_rg->fm_epi); +} + + +int fman_set_erratum_10gmac_a004_wa(struct fman_fpm_regs *fpm_rg) +{ + int timeout = 100; + + iowrite32be(0x40000000, &fpm_rg->fmfp_extc); + + while ((ioread32be(&fpm_rg->fmfp_extc) & 0x40000000) && --timeout) + udelay(10); + + if (!timeout) + return -EBUSY; + return 0; +} + +void fman_set_ctrl_intr(struct fman_fpm_regs *fpm_rg, + uint8_t event_reg_id, + uint32_t enable_events) +{ + iowrite32be(enable_events, &fpm_rg->fmfp_cee[event_reg_id]); +} + +uint32_t fman_get_ctrl_intr(struct fman_fpm_regs *fpm_rg, uint8_t event_reg_id) +{ + return ioread32be(&fpm_rg->fmfp_cee[event_reg_id]); +} + +void fman_set_num_of_riscs_per_port(struct fman_fpm_regs *fpm_rg, + uint8_t port_id, + uint8_t num_fman_ctrls, + uint32_t or_fman_ctrl) +{ + uint32_t tmp = 0; + + tmp = (uint32_t)(port_id << FPM_PORT_FM_CTL_PORTID_SHIFT); + /*TODO - maybe to put CTL# according to another criteria*/ + if (num_fman_ctrls == 2) + tmp = FPM_PRT_FM_CTL2 | FPM_PRT_FM_CTL1; + /* order restoration */ + tmp |= (or_fman_ctrl << FPM_PRC_ORA_FM_CTL_SEL_SHIFT) | or_fman_ctrl; + + iowrite32be(tmp, &fpm_rg->fmfp_prc); +} + +void fman_set_order_restoration_per_port(struct fman_fpm_regs *fpm_rg, + uint8_t port_id, + bool independent_mode, + bool is_rx_port) +{ + uint32_t tmp = 0; + + tmp = (uint32_t)(port_id << FPM_PORT_FM_CTL_PORTID_SHIFT); + if (independent_mode) { + if (is_rx_port) + tmp |= (FPM_PRT_FM_CTL1 << + FPM_PRC_ORA_FM_CTL_SEL_SHIFT) | FPM_PRT_FM_CTL1; + else + tmp |= (FPM_PRT_FM_CTL2 << + FPM_PRC_ORA_FM_CTL_SEL_SHIFT) | FPM_PRT_FM_CTL2; + } else { + tmp |= (FPM_PRT_FM_CTL2|FPM_PRT_FM_CTL1); + + /* order restoration */ + if (port_id % 2) + tmp |= (FPM_PRT_FM_CTL1 << + FPM_PRC_ORA_FM_CTL_SEL_SHIFT); + else + tmp |= (FPM_PRT_FM_CTL2 << + FPM_PRC_ORA_FM_CTL_SEL_SHIFT); + } + iowrite32be(tmp, &fpm_rg->fmfp_prc); +} + +uint8_t fman_get_qmi_deq_th(struct fman_qmi_regs *qmi_rg) +{ + return (uint8_t)ioread32be(&qmi_rg->fmqm_gc); +} + +uint8_t fman_get_qmi_enq_th(struct fman_qmi_regs *qmi_rg) +{ + return (uint8_t)(ioread32be(&qmi_rg->fmqm_gc) >> 8); +} + +void fman_set_qmi_enq_th(struct fman_qmi_regs *qmi_rg, uint8_t val) +{ + uint32_t tmp_reg; + + tmp_reg = ioread32be(&qmi_rg->fmqm_gc); + tmp_reg &= ~QMI_CFG_ENQ_MASK; + tmp_reg |= ((uint32_t)val << 8); + iowrite32be(tmp_reg, &qmi_rg->fmqm_gc); +} + +void fman_set_qmi_deq_th(struct fman_qmi_regs *qmi_rg, uint8_t val) +{ + uint32_t tmp_reg; + + tmp_reg = ioread32be(&qmi_rg->fmqm_gc); + tmp_reg &= ~QMI_CFG_DEQ_MASK; + tmp_reg |= (uint32_t)val; + iowrite32be(tmp_reg, &qmi_rg->fmqm_gc); +} + +void fman_qmi_disable_dispatch_limit(struct fman_fpm_regs *fpm_rg) +{ + iowrite32be(0, &fpm_rg->fmfp_mxd); +} + +void fman_set_liodn_per_port(struct fman_rg *fman_rg, uint8_t port_id, + uint16_t liodn_base, + uint16_t liodn_ofst) +{ + uint32_t tmp; + + if ((port_id > 63) || (port_id < 1)) + return; + + /* set LIODN base for this port */ + tmp = ioread32be(&fman_rg->dma_rg->fmdmplr[port_id / 2]); + if (port_id % 2) { + tmp &= ~FM_LIODN_BASE_MASK; + tmp |= (uint32_t)liodn_base; + } else { + tmp &= ~(FM_LIODN_BASE_MASK << DMA_LIODN_SHIFT); + tmp |= (uint32_t)liodn_base << DMA_LIODN_SHIFT; + } + iowrite32be(tmp, &fman_rg->dma_rg->fmdmplr[port_id / 2]); + iowrite32be((uint32_t)liodn_ofst, + &fman_rg->bmi_rg->fmbm_spliodn[port_id - 1]); +} + +bool fman_is_port_stalled(struct fman_fpm_regs *fpm_rg, uint8_t port_id) +{ + return (bool)!!(ioread32be(&fpm_rg->fmfp_ps[port_id]) & FPM_PS_STALLED); +} + +void fman_resume_stalled_port(struct fman_fpm_regs *fpm_rg, uint8_t port_id) +{ + uint32_t tmp; + + tmp = (uint32_t)((port_id << FPM_PORT_FM_CTL_PORTID_SHIFT) | + FPM_PRC_REALSE_STALLED); + iowrite32be(tmp, &fpm_rg->fmfp_prc); +} + +int fman_reset_mac(struct fman_fpm_regs *fpm_rg, uint8_t mac_id, bool is_10g) +{ + uint32_t msk, timeout = 100; + + /* Get the relevant bit mask */ + if (is_10g) { + switch (mac_id) { + case(0): + msk = FPM_RSTC_10G0_RESET; + break; + case(1): + msk = FPM_RSTC_10G1_RESET; + break; + default: + return -EINVAL; + } + } else { + switch (mac_id) { + case(0): + msk = FPM_RSTC_1G0_RESET; + break; + case(1): + msk = FPM_RSTC_1G1_RESET; + break; + case(2): + msk = FPM_RSTC_1G2_RESET; + break; + case(3): + msk = FPM_RSTC_1G3_RESET; + break; + case(4): + msk = FPM_RSTC_1G4_RESET; + break; + case (5): + msk = FPM_RSTC_1G5_RESET; + break; + case (6): + msk = FPM_RSTC_1G6_RESET; + break; + case (7): + msk = FPM_RSTC_1G7_RESET; + break; + default: + return -EINVAL; + } + } + /* reset */ + iowrite32be(msk, &fpm_rg->fm_rstc); + while ((ioread32be(&fpm_rg->fm_rstc) & msk) && --timeout) + udelay(10); + + if (!timeout) + return -EBUSY; + return 0; +} + +uint16_t fman_get_size_of_fifo(struct fman_bmi_regs *bmi_rg, uint8_t port_id) +{ + uint32_t tmp_reg; + + if ((port_id > 63) || (port_id < 1)) + return 0; + + tmp_reg = ioread32be(&bmi_rg->fmbm_pfs[port_id - 1]); + return (uint16_t)((tmp_reg & BMI_FIFO_SIZE_MASK) + 1); +} + +uint32_t fman_get_total_fifo_size(struct fman_bmi_regs *bmi_rg) +{ + uint32_t reg, res; + + reg = ioread32be(&bmi_rg->fmbm_cfg1); + res = (reg >> BMI_CFG1_FIFO_SIZE_SHIFT) & 0x3ff; + return res * FMAN_BMI_FIFO_UNITS; +} + +uint16_t fman_get_size_of_extra_fifo(struct fman_bmi_regs *bmi_rg, + uint8_t port_id) +{ + uint32_t tmp_reg; + + if ((port_id > 63) || (port_id < 1)) + return 0; + + tmp_reg = ioread32be(&bmi_rg->fmbm_pfs[port_id-1]); + return (uint16_t)((tmp_reg & BMI_EXTRA_FIFO_SIZE_MASK) >> + BMI_EXTRA_FIFO_SIZE_SHIFT); +} + +void fman_set_size_of_fifo(struct fman_bmi_regs *bmi_rg, + uint8_t port_id, + uint32_t sz_fifo, + uint32_t extra_sz_fifo) +{ + uint32_t tmp; + + if ((port_id > 63) || (port_id < 1)) + return; + + /* calculate reg */ + tmp = (uint32_t)((sz_fifo / FMAN_BMI_FIFO_UNITS - 1) | + ((extra_sz_fifo / FMAN_BMI_FIFO_UNITS) << + BMI_EXTRA_FIFO_SIZE_SHIFT)); + iowrite32be(tmp, &bmi_rg->fmbm_pfs[port_id - 1]); +} + +uint8_t fman_get_num_of_tasks(struct fman_bmi_regs *bmi_rg, uint8_t port_id) +{ + uint32_t tmp; + + if ((port_id > 63) || (port_id < 1)) + return 0; + + tmp = ioread32be(&bmi_rg->fmbm_pp[port_id - 1]); + return (uint8_t)(((tmp & BMI_NUM_OF_TASKS_MASK) >> + BMI_NUM_OF_TASKS_SHIFT) + 1); +} + +uint8_t fman_get_num_extra_tasks(struct fman_bmi_regs *bmi_rg, uint8_t port_id) +{ + uint32_t tmp; + + if ((port_id > 63) || (port_id < 1)) + return 0; + + tmp = ioread32be(&bmi_rg->fmbm_pp[port_id - 1]); + return (uint8_t)((tmp & BMI_NUM_OF_EXTRA_TASKS_MASK) >> + BMI_EXTRA_NUM_OF_TASKS_SHIFT); +} + +void fman_set_num_of_tasks(struct fman_bmi_regs *bmi_rg, + uint8_t port_id, + uint8_t num_tasks, + uint8_t num_extra_tasks) +{ + uint32_t tmp; + + if ((port_id > 63) || (port_id < 1)) + return; + + /* calculate reg */ + tmp = ioread32be(&bmi_rg->fmbm_pp[port_id - 1]) & + ~(BMI_NUM_OF_TASKS_MASK | BMI_NUM_OF_EXTRA_TASKS_MASK); + tmp |= (uint32_t)(((num_tasks - 1) << BMI_NUM_OF_TASKS_SHIFT) | + (num_extra_tasks << BMI_EXTRA_NUM_OF_TASKS_SHIFT)); + iowrite32be(tmp, &bmi_rg->fmbm_pp[port_id - 1]); +} + +uint8_t fman_get_num_of_dmas(struct fman_bmi_regs *bmi_rg, uint8_t port_id) +{ + uint32_t tmp; + + if ((port_id > 63) || (port_id < 1)) + return 0; + + tmp = ioread32be(&bmi_rg->fmbm_pp[port_id - 1]); + return (uint8_t)(((tmp & BMI_NUM_OF_DMAS_MASK) >> + BMI_NUM_OF_DMAS_SHIFT) + 1); +} + +uint8_t fman_get_num_extra_dmas(struct fman_bmi_regs *bmi_rg, uint8_t port_id) +{ + uint32_t tmp; + + if ((port_id > 63) || (port_id < 1)) + return 0; + + tmp = ioread32be(&bmi_rg->fmbm_pp[port_id - 1]); + return (uint8_t)((tmp & BMI_NUM_OF_EXTRA_DMAS_MASK) >> + BMI_EXTRA_NUM_OF_DMAS_SHIFT); +} + +void fman_set_num_of_open_dmas(struct fman_bmi_regs *bmi_rg, + uint8_t port_id, + uint8_t num_open_dmas, + uint8_t num_extra_open_dmas, + uint8_t total_num_dmas) +{ + uint32_t tmp = 0; + + if ((port_id > 63) || (port_id < 1)) + return; + + /* calculate reg */ + tmp = ioread32be(&bmi_rg->fmbm_pp[port_id - 1]) & + ~(BMI_NUM_OF_DMAS_MASK | BMI_NUM_OF_EXTRA_DMAS_MASK); + tmp |= (uint32_t)(((num_open_dmas-1) << BMI_NUM_OF_DMAS_SHIFT) | + (num_extra_open_dmas << BMI_EXTRA_NUM_OF_DMAS_SHIFT)); + iowrite32be(tmp, &bmi_rg->fmbm_pp[port_id - 1]); + + /* update total num of DMA's with committed number of open DMAS, + * and max uncommitted pool. */ + if (total_num_dmas) + { + tmp = ioread32be(&bmi_rg->fmbm_cfg2) & ~BMI_CFG2_DMAS_MASK; + tmp |= (uint32_t)(total_num_dmas - 1) << BMI_CFG2_DMAS_SHIFT; + iowrite32be(tmp, &bmi_rg->fmbm_cfg2); + } +} + +void fman_set_vsp_window(struct fman_bmi_regs *bmi_rg, + uint8_t port_id, + uint8_t base_storage_profile, + uint8_t log2_num_of_profiles) +{ + uint32_t tmp = 0; + if ((port_id > 63) || (port_id < 1)) + return; + + tmp = ioread32be(&bmi_rg->fmbm_spliodn[port_id-1]); + tmp |= (uint32_t)((uint32_t)base_storage_profile & 0x3f) << 16; + tmp |= (uint32_t)log2_num_of_profiles << 28; + iowrite32be(tmp, &bmi_rg->fmbm_spliodn[port_id-1]); +} + +void fman_set_congestion_group_pfc_priority(uint32_t *cpg_rg, + uint32_t congestion_group_id, + uint8_t priority_bit_map, + uint32_t reg_num) +{ + uint32_t offset, tmp = 0; + + offset = (congestion_group_id%4)*8; + + tmp = ioread32be(&cpg_rg[reg_num]); + tmp &= ~(0xFF<<offset); + tmp |= (uint32_t)priority_bit_map << offset; + + iowrite32be(tmp,&cpg_rg[reg_num]); +} + +/*****************************************************************************/ +/* API Init unit functions */ +/*****************************************************************************/ +void fman_defconfig(struct fman_cfg *cfg, bool is_master) +{ + memset(cfg, 0, sizeof(struct fman_cfg)); + + cfg->catastrophic_err = DEFAULT_CATASTROPHIC_ERR; + cfg->dma_err = DEFAULT_DMA_ERR; + cfg->halt_on_external_activ = DEFAULT_HALT_ON_EXTERNAL_ACTIVATION; + cfg->halt_on_unrecov_ecc_err = DEFAULT_HALT_ON_UNRECOVERABLE_ECC_ERROR; + cfg->en_iram_test_mode = FALSE; + cfg->en_muram_test_mode = FALSE; + cfg->external_ecc_rams_enable = DEFAULT_EXTERNAL_ECC_RAMS_ENABLE; + + if (!is_master) + return; + + cfg->dma_aid_override = DEFAULT_AID_OVERRIDE; + cfg->dma_aid_mode = DEFAULT_AID_MODE; + cfg->dma_comm_qtsh_clr_emer = DEFAULT_DMA_COMM_Q_LOW; + cfg->dma_comm_qtsh_asrt_emer = DEFAULT_DMA_COMM_Q_HIGH; + cfg->dma_cache_override = DEFAULT_CACHE_OVERRIDE; + cfg->dma_cam_num_of_entries = DEFAULT_DMA_CAM_NUM_OF_ENTRIES; + cfg->dma_dbg_cnt_mode = DEFAULT_DMA_DBG_CNT_MODE; + cfg->dma_en_emergency = DEFAULT_DMA_EN_EMERGENCY; + cfg->dma_sos_emergency = DEFAULT_DMA_SOS_EMERGENCY; + cfg->dma_watchdog = DEFAULT_DMA_WATCHDOG; + cfg->dma_en_emergency_smoother = DEFAULT_DMA_EN_EMERGENCY_SMOOTHER; + cfg->dma_emergency_switch_counter = DEFAULT_DMA_EMERGENCY_SWITCH_COUNTER; + cfg->disp_limit_tsh = DEFAULT_DISP_LIMIT; + cfg->prs_disp_tsh = DEFAULT_PRS_DISP_TH; + cfg->plcr_disp_tsh = DEFAULT_PLCR_DISP_TH; + cfg->kg_disp_tsh = DEFAULT_KG_DISP_TH; + cfg->bmi_disp_tsh = DEFAULT_BMI_DISP_TH; + cfg->qmi_enq_disp_tsh = DEFAULT_QMI_ENQ_DISP_TH; + cfg->qmi_deq_disp_tsh = DEFAULT_QMI_DEQ_DISP_TH; + cfg->fm_ctl1_disp_tsh = DEFAULT_FM_CTL1_DISP_TH; + cfg->fm_ctl2_disp_tsh = DEFAULT_FM_CTL2_DISP_TH; + + cfg->pedantic_dma = FALSE; + cfg->tnum_aging_period = DEFAULT_TNUM_AGING_PERIOD; + cfg->dma_stop_on_bus_error = FALSE; + cfg->qmi_deq_option_support = FALSE; +} + +void fman_regconfig(struct fman_rg *fman_rg, struct fman_cfg *cfg) +{ + uint32_t tmp_reg; + + /* read the values from the registers as they are initialized by the HW with + * the required values. + */ + tmp_reg = ioread32be(&fman_rg->bmi_rg->fmbm_cfg1); + cfg->total_fifo_size = + (((tmp_reg & BMI_TOTAL_FIFO_SIZE_MASK) >> BMI_CFG1_FIFO_SIZE_SHIFT) + 1) * FMAN_BMI_FIFO_UNITS; + + tmp_reg = ioread32be(&fman_rg->bmi_rg->fmbm_cfg2); + cfg->total_num_of_tasks = + (uint8_t)(((tmp_reg & BMI_TOTAL_NUM_OF_TASKS_MASK) >> BMI_CFG2_TASKS_SHIFT) + 1); + + tmp_reg = ioread32be(&fman_rg->dma_rg->fmdmtr); + cfg->dma_comm_qtsh_asrt_emer = (uint8_t)(tmp_reg >> DMA_THRESH_COMMQ_SHIFT); + + tmp_reg = ioread32be(&fman_rg->dma_rg->fmdmhy); + cfg->dma_comm_qtsh_clr_emer = (uint8_t)(tmp_reg >> DMA_THRESH_COMMQ_SHIFT); + + tmp_reg = ioread32be(&fman_rg->dma_rg->fmdmmr); + cfg->dma_cache_override = (enum fman_dma_cache_override)((tmp_reg & DMA_MODE_CACHE_OR_MASK) >> DMA_MODE_CACHE_OR_SHIFT); + cfg->dma_cam_num_of_entries = (uint8_t)((((tmp_reg & DMA_MODE_CEN_MASK) >> DMA_MODE_CEN_SHIFT) +1)*DMA_CAM_UNITS); + cfg->dma_aid_override = (bool)((tmp_reg & DMA_MODE_AID_OR)? TRUE:FALSE); + cfg->dma_dbg_cnt_mode = (enum fman_dma_dbg_cnt_mode)((tmp_reg & DMA_MODE_DBG_MASK) >> DMA_MODE_DBG_SHIFT); + cfg->dma_en_emergency = (bool)((tmp_reg & DMA_MODE_EB)? TRUE : FALSE); + + tmp_reg = ioread32be(&fman_rg->fpm_rg->fmfp_mxd); + cfg->disp_limit_tsh = (uint8_t)((tmp_reg & FPM_DISP_LIMIT_MASK) >> FPM_DISP_LIMIT_SHIFT); + + tmp_reg = ioread32be(&fman_rg->fpm_rg->fmfp_dist1); + cfg->prs_disp_tsh = (uint8_t)((tmp_reg & FPM_THR1_PRS_MASK ) >> FPM_THR1_PRS_SHIFT); + cfg->plcr_disp_tsh = (uint8_t)((tmp_reg & FPM_THR1_KG_MASK ) >> FPM_THR1_KG_SHIFT); + cfg->kg_disp_tsh = (uint8_t)((tmp_reg & FPM_THR1_PLCR_MASK ) >> FPM_THR1_PLCR_SHIFT); + cfg->bmi_disp_tsh = (uint8_t)((tmp_reg & FPM_THR1_BMI_MASK ) >> FPM_THR1_BMI_SHIFT); + + tmp_reg = ioread32be(&fman_rg->fpm_rg->fmfp_dist2); + cfg->qmi_enq_disp_tsh = (uint8_t)((tmp_reg & FPM_THR2_QMI_ENQ_MASK ) >> FPM_THR2_QMI_ENQ_SHIFT); + cfg->qmi_deq_disp_tsh = (uint8_t)((tmp_reg & FPM_THR2_QMI_DEQ_MASK ) >> FPM_THR2_QMI_DEQ_SHIFT); + cfg->fm_ctl1_disp_tsh = (uint8_t)((tmp_reg & FPM_THR2_FM_CTL1_MASK ) >> FPM_THR2_FM_CTL1_SHIFT); + cfg->fm_ctl2_disp_tsh = (uint8_t)((tmp_reg & FPM_THR2_FM_CTL2_MASK ) >> FPM_THR2_FM_CTL2_SHIFT); + + tmp_reg = ioread32be(&fman_rg->dma_rg->fmdmsetr); + cfg->dma_sos_emergency = tmp_reg; + + tmp_reg = ioread32be(&fman_rg->dma_rg->fmdmwcr); + cfg->dma_watchdog = tmp_reg/cfg->clk_freq; + + tmp_reg = ioread32be(&fman_rg->dma_rg->fmdmemsr); + cfg->dma_en_emergency_smoother = (bool)((tmp_reg & DMA_EMSR_EMSTR_MASK)? TRUE : FALSE); + cfg->dma_emergency_switch_counter = (tmp_reg & DMA_EMSR_EMSTR_MASK); +} + +void fman_reset(struct fman_fpm_regs *fpm_rg) +{ + iowrite32be(FPM_RSTC_FM_RESET, &fpm_rg->fm_rstc); +} + +/**************************************************************************//** + @Function FM_Init + + @Description Initializes the FM module + + @Param[in] h_Fm - FM module descriptor + + @Return E_OK on success; Error code otherwise. +*//***************************************************************************/ +int fman_dma_init(struct fman_dma_regs *dma_rg, struct fman_cfg *cfg) +{ + uint32_t tmp_reg; + + /**********************/ + /* Init DMA Registers */ + /**********************/ + /* clear status reg events */ + /* oren - check!!! */ + tmp_reg = (DMA_STATUS_BUS_ERR | DMA_STATUS_READ_ECC | + DMA_STATUS_SYSTEM_WRITE_ECC | DMA_STATUS_FM_WRITE_ECC); + iowrite32be(ioread32be(&dma_rg->fmdmsr) | tmp_reg, + &dma_rg->fmdmsr); + + /* configure mode register */ + tmp_reg = 0; + tmp_reg |= cfg->dma_cache_override << DMA_MODE_CACHE_OR_SHIFT; + if (cfg->dma_aid_override) + tmp_reg |= DMA_MODE_AID_OR; + if (cfg->exceptions & FMAN_EX_DMA_BUS_ERROR) + tmp_reg |= DMA_MODE_BER; + if ((cfg->exceptions & FMAN_EX_DMA_SYSTEM_WRITE_ECC) | + (cfg->exceptions & FMAN_EX_DMA_READ_ECC) | + (cfg->exceptions & FMAN_EX_DMA_FM_WRITE_ECC)) + tmp_reg |= DMA_MODE_ECC; + if (cfg->dma_stop_on_bus_error) + tmp_reg |= DMA_MODE_SBER; + if(cfg->dma_axi_dbg_num_of_beats) + tmp_reg |= (uint32_t)(DMA_MODE_AXI_DBG_MASK & + ((cfg->dma_axi_dbg_num_of_beats - 1) << DMA_MODE_AXI_DBG_SHIFT)); + + if (cfg->dma_en_emergency) { + tmp_reg |= cfg->dma_emergency_bus_select; + tmp_reg |= cfg->dma_emergency_level << DMA_MODE_EMER_LVL_SHIFT; + if (cfg->dma_en_emergency_smoother) + iowrite32be(cfg->dma_emergency_switch_counter, + &dma_rg->fmdmemsr); + } + tmp_reg |= ((cfg->dma_cam_num_of_entries / DMA_CAM_UNITS) - 1) << + DMA_MODE_CEN_SHIFT; + tmp_reg |= DMA_MODE_SECURE_PROT; + tmp_reg |= cfg->dma_dbg_cnt_mode << DMA_MODE_DBG_SHIFT; + tmp_reg |= cfg->dma_aid_mode << DMA_MODE_AID_MODE_SHIFT; + + if (cfg->pedantic_dma) + tmp_reg |= DMA_MODE_EMER_READ; + + iowrite32be(tmp_reg, &dma_rg->fmdmmr); + + /* configure thresholds register */ + tmp_reg = ((uint32_t)cfg->dma_comm_qtsh_asrt_emer << + DMA_THRESH_COMMQ_SHIFT) | + ((uint32_t)cfg->dma_read_buf_tsh_asrt_emer << + DMA_THRESH_READ_INT_BUF_SHIFT) | + ((uint32_t)cfg->dma_write_buf_tsh_asrt_emer); + + iowrite32be(tmp_reg, &dma_rg->fmdmtr); + + /* configure hysteresis register */ + tmp_reg = ((uint32_t)cfg->dma_comm_qtsh_clr_emer << + DMA_THRESH_COMMQ_SHIFT) | + ((uint32_t)cfg->dma_read_buf_tsh_clr_emer << + DMA_THRESH_READ_INT_BUF_SHIFT) | + ((uint32_t)cfg->dma_write_buf_tsh_clr_emer); + + iowrite32be(tmp_reg, &dma_rg->fmdmhy); + + /* configure emergency threshold */ + iowrite32be(cfg->dma_sos_emergency, &dma_rg->fmdmsetr); + + /* configure Watchdog */ + iowrite32be((cfg->dma_watchdog * cfg->clk_freq), + &dma_rg->fmdmwcr); + + iowrite32be(cfg->cam_base_addr, &dma_rg->fmdmebcr); + + return 0; +} + +int fman_fpm_init(struct fman_fpm_regs *fpm_rg, struct fman_cfg *cfg) +{ + uint32_t tmp_reg; + int i; + + /**********************/ + /* Init FPM Registers */ + /**********************/ + tmp_reg = (uint32_t)(cfg->disp_limit_tsh << FPM_DISP_LIMIT_SHIFT); + iowrite32be(tmp_reg, &fpm_rg->fmfp_mxd); + + tmp_reg = (((uint32_t)cfg->prs_disp_tsh << FPM_THR1_PRS_SHIFT) | + ((uint32_t)cfg->kg_disp_tsh << FPM_THR1_KG_SHIFT) | + ((uint32_t)cfg->plcr_disp_tsh << FPM_THR1_PLCR_SHIFT) | + ((uint32_t)cfg->bmi_disp_tsh << FPM_THR1_BMI_SHIFT)); + iowrite32be(tmp_reg, &fpm_rg->fmfp_dist1); + + tmp_reg = (((uint32_t)cfg->qmi_enq_disp_tsh << FPM_THR2_QMI_ENQ_SHIFT) | + ((uint32_t)cfg->qmi_deq_disp_tsh << FPM_THR2_QMI_DEQ_SHIFT) | + ((uint32_t)cfg->fm_ctl1_disp_tsh << FPM_THR2_FM_CTL1_SHIFT) | + ((uint32_t)cfg->fm_ctl2_disp_tsh << FPM_THR2_FM_CTL2_SHIFT)); + iowrite32be(tmp_reg, &fpm_rg->fmfp_dist2); + + /* define exceptions and error behavior */ + tmp_reg = 0; + /* Clear events */ + tmp_reg |= (FPM_EV_MASK_STALL | FPM_EV_MASK_DOUBLE_ECC | + FPM_EV_MASK_SINGLE_ECC); + /* enable interrupts */ + if (cfg->exceptions & FMAN_EX_FPM_STALL_ON_TASKS) + tmp_reg |= FPM_EV_MASK_STALL_EN; + if (cfg->exceptions & FMAN_EX_FPM_SINGLE_ECC) + tmp_reg |= FPM_EV_MASK_SINGLE_ECC_EN; + if (cfg->exceptions & FMAN_EX_FPM_DOUBLE_ECC) + tmp_reg |= FPM_EV_MASK_DOUBLE_ECC_EN; + tmp_reg |= (cfg->catastrophic_err << FPM_EV_MASK_CAT_ERR_SHIFT); + tmp_reg |= (cfg->dma_err << FPM_EV_MASK_DMA_ERR_SHIFT); + if (!cfg->halt_on_external_activ) + tmp_reg |= FPM_EV_MASK_EXTERNAL_HALT; + if (!cfg->halt_on_unrecov_ecc_err) + tmp_reg |= FPM_EV_MASK_ECC_ERR_HALT; + iowrite32be(tmp_reg, &fpm_rg->fmfp_ee); + + /* clear all fmCtls event registers */ + for (i = 0; i < cfg->num_of_fman_ctrl_evnt_regs; i++) + iowrite32be(0xFFFFFFFF, &fpm_rg->fmfp_cev[i]); + + /* RAM ECC - enable and clear events*/ + /* first we need to clear all parser memory, + * as it is uninitialized and may cause ECC errors */ + /* event bits */ + tmp_reg = (FPM_RAM_MURAM_ECC | FPM_RAM_IRAM_ECC); + /* Rams enable not effected by RCR bit, but by a COP configuration */ + if (cfg->external_ecc_rams_enable) + tmp_reg |= FPM_RAM_RAMS_ECC_EN_SRC_SEL; + + /* enable test mode */ + if (cfg->en_muram_test_mode) + tmp_reg |= FPM_RAM_MURAM_TEST_ECC; + if (cfg->en_iram_test_mode) + tmp_reg |= FPM_RAM_IRAM_TEST_ECC; + iowrite32be(tmp_reg, &fpm_rg->fm_rcr); + + tmp_reg = 0; + if (cfg->exceptions & FMAN_EX_IRAM_ECC) { + tmp_reg |= FPM_IRAM_ECC_ERR_EX_EN; + fman_enable_rams_ecc(fpm_rg); + } + if (cfg->exceptions & FMAN_EX_NURAM_ECC) { + tmp_reg |= FPM_MURAM_ECC_ERR_EX_EN; + fman_enable_rams_ecc(fpm_rg); + } + iowrite32be(tmp_reg, &fpm_rg->fm_rie); + + return 0; +} + +int fman_bmi_init(struct fman_bmi_regs *bmi_rg, struct fman_cfg *cfg) +{ + uint32_t tmp_reg; + + /**********************/ + /* Init BMI Registers */ + /**********************/ + + /* define common resources */ + tmp_reg = cfg->fifo_base_addr; + tmp_reg = tmp_reg / BMI_FIFO_ALIGN; + + tmp_reg |= ((cfg->total_fifo_size / FMAN_BMI_FIFO_UNITS - 1) << + BMI_CFG1_FIFO_SIZE_SHIFT); + iowrite32be(tmp_reg, &bmi_rg->fmbm_cfg1); + + tmp_reg = ((uint32_t)(cfg->total_num_of_tasks - 1) << + BMI_CFG2_TASKS_SHIFT); + /* num of DMA's will be dynamically updated when each port is set */ + iowrite32be(tmp_reg, &bmi_rg->fmbm_cfg2); + + /* define unmaskable exceptions, enable and clear events */ + tmp_reg = 0; + iowrite32be(BMI_ERR_INTR_EN_LIST_RAM_ECC | + BMI_ERR_INTR_EN_STORAGE_PROFILE_ECC | + BMI_ERR_INTR_EN_STATISTICS_RAM_ECC | + BMI_ERR_INTR_EN_DISPATCH_RAM_ECC, + &bmi_rg->fmbm_ievr); + + if (cfg->exceptions & FMAN_EX_BMI_LIST_RAM_ECC) + tmp_reg |= BMI_ERR_INTR_EN_LIST_RAM_ECC; + if (cfg->exceptions & FMAN_EX_BMI_PIPELINE_ECC) + tmp_reg |= BMI_ERR_INTR_EN_STORAGE_PROFILE_ECC; + if (cfg->exceptions & FMAN_EX_BMI_STATISTICS_RAM_ECC) + tmp_reg |= BMI_ERR_INTR_EN_STATISTICS_RAM_ECC; + if (cfg->exceptions & FMAN_EX_BMI_DISPATCH_RAM_ECC) + tmp_reg |= BMI_ERR_INTR_EN_DISPATCH_RAM_ECC; + iowrite32be(tmp_reg, &bmi_rg->fmbm_ier); + + return 0; +} + +int fman_qmi_init(struct fman_qmi_regs *qmi_rg, struct fman_cfg *cfg) +{ + uint32_t tmp_reg; + uint16_t period_in_fm_clocks; + uint8_t remainder; + /**********************/ + /* Init QMI Registers */ + /**********************/ + /* Clear error interrupt events */ + + iowrite32be(QMI_ERR_INTR_EN_DOUBLE_ECC | QMI_ERR_INTR_EN_DEQ_FROM_DEF, + &qmi_rg->fmqm_eie); + tmp_reg = 0; + if (cfg->exceptions & FMAN_EX_QMI_DEQ_FROM_UNKNOWN_PORTID) + tmp_reg |= QMI_ERR_INTR_EN_DEQ_FROM_DEF; + if (cfg->exceptions & FMAN_EX_QMI_DOUBLE_ECC) + tmp_reg |= QMI_ERR_INTR_EN_DOUBLE_ECC; + /* enable events */ + iowrite32be(tmp_reg, &qmi_rg->fmqm_eien); + + if (cfg->tnum_aging_period) { + /* tnum_aging_period is in units of usec, p_FmClockFreq in Mhz */ + period_in_fm_clocks = (uint16_t) + (cfg->tnum_aging_period * cfg->clk_freq); + /* period_in_fm_clocks must be a 64 multiply */ + remainder = (uint8_t)(period_in_fm_clocks % 64); + if (remainder) + tmp_reg = (uint32_t)((period_in_fm_clocks / 64) + 1); + else{ + tmp_reg = (uint32_t)(period_in_fm_clocks / 64); + if (!tmp_reg) + tmp_reg = 1; + } + tmp_reg <<= QMI_TAPC_TAP; + iowrite32be(tmp_reg, &qmi_rg->fmqm_tapc); + } + tmp_reg = 0; + /* Clear interrupt events */ + iowrite32be(QMI_INTR_EN_SINGLE_ECC, &qmi_rg->fmqm_ie); + if (cfg->exceptions & FMAN_EX_QMI_SINGLE_ECC) + tmp_reg |= QMI_INTR_EN_SINGLE_ECC; + /* enable events */ + iowrite32be(tmp_reg, &qmi_rg->fmqm_ien); + + return 0; +} + +int fman_enable(struct fman_rg *fman_rg, struct fman_cfg *cfg) +{ + uint32_t cfg_reg = 0; + + /**********************/ + /* Enable all modules */ + /**********************/ + /* clear & enable global counters - calculate reg and save for later, + because it's the same reg for QMI enable */ + cfg_reg = QMI_CFG_EN_COUNTERS; + if (cfg->qmi_deq_option_support) + cfg_reg |= (uint32_t)(((cfg->qmi_def_tnums_thresh) << 8) | + (uint32_t)cfg->qmi_def_tnums_thresh); + + iowrite32be(BMI_INIT_START, &fman_rg->bmi_rg->fmbm_init); + iowrite32be(cfg_reg | QMI_CFG_ENQ_EN | QMI_CFG_DEQ_EN, + &fman_rg->qmi_rg->fmqm_gc); + + return 0; +} + +void fman_free_resources(struct fman_rg *fman_rg) +{ + /* disable BMI and QMI */ + iowrite32be(0, &fman_rg->bmi_rg->fmbm_init); + iowrite32be(0, &fman_rg->qmi_rg->fmqm_gc); + + /* release BMI resources */ + iowrite32be(0, &fman_rg->bmi_rg->fmbm_cfg2); + iowrite32be(0, &fman_rg->bmi_rg->fmbm_cfg1); + + /* disable ECC */ + iowrite32be(0, &fman_rg->fpm_rg->fm_rcr); +} + +/****************************************************/ +/* API Run-time Control uint functions */ +/****************************************************/ +uint32_t fman_get_normal_pending(struct fman_fpm_regs *fpm_rg) +{ + return ioread32be(&fpm_rg->fm_npi); +} + +uint32_t fman_get_controller_event(struct fman_fpm_regs *fpm_rg, uint8_t reg_id) +{ + uint32_t event; + + event = ioread32be(&fpm_rg->fmfp_fcev[reg_id]) & + ioread32be(&fpm_rg->fmfp_cee[reg_id]); + iowrite32be(event, &fpm_rg->fmfp_cev[reg_id]); + + return event; +} + +uint32_t fman_get_error_pending(struct fman_fpm_regs *fpm_rg) +{ + return ioread32be(&fpm_rg->fm_epi); +} + +void fman_set_ports_bandwidth(struct fman_bmi_regs *bmi_rg, uint8_t *weights) +{ + int i; + uint8_t shift; + uint32_t tmp = 0; + + for (i = 0; i < 64; i++) { + if (weights[i] > 1) { /* no need to write 1 since it is 0 */ + /* Add this port to tmp_reg */ + /* (each 8 ports result in one register)*/ + shift = (uint8_t)(32 - 4 * ((i % 8) + 1)); + tmp |= ((weights[i] - 1) << shift); + } + if (i % 8 == 7) { /* last in this set */ + iowrite32be(tmp, &bmi_rg->fmbm_arb[i / 8]); + tmp = 0; + } + } +} + +void fman_enable_rams_ecc(struct fman_fpm_regs *fpm_rg) +{ + uint32_t tmp; + + tmp = ioread32be(&fpm_rg->fm_rcr); + if (tmp & FPM_RAM_RAMS_ECC_EN_SRC_SEL) + iowrite32be(tmp | FPM_RAM_IRAM_ECC_EN, + &fpm_rg->fm_rcr); + else + iowrite32be(tmp | FPM_RAM_RAMS_ECC_EN | + FPM_RAM_IRAM_ECC_EN, + &fpm_rg->fm_rcr); +} + +void fman_disable_rams_ecc(struct fman_fpm_regs *fpm_rg) +{ + uint32_t tmp; + + tmp = ioread32be(&fpm_rg->fm_rcr); + if (tmp & FPM_RAM_RAMS_ECC_EN_SRC_SEL) + iowrite32be(tmp & ~FPM_RAM_IRAM_ECC_EN, + &fpm_rg->fm_rcr); + else + iowrite32be(tmp & ~(FPM_RAM_RAMS_ECC_EN | FPM_RAM_IRAM_ECC_EN), + &fpm_rg->fm_rcr); +} + +int fman_set_exception(struct fman_rg *fman_rg, + enum fman_exceptions exception, + bool enable) +{ + uint32_t tmp; + + switch (exception) { + case(E_FMAN_EX_DMA_BUS_ERROR): + tmp = ioread32be(&fman_rg->dma_rg->fmdmmr); + if (enable) + tmp |= DMA_MODE_BER; + else + tmp &= ~DMA_MODE_BER; + /* disable bus error */ + iowrite32be(tmp, &fman_rg->dma_rg->fmdmmr); + break; + case(E_FMAN_EX_DMA_READ_ECC): + case(E_FMAN_EX_DMA_SYSTEM_WRITE_ECC): + case(E_FMAN_EX_DMA_FM_WRITE_ECC): + tmp = ioread32be(&fman_rg->dma_rg->fmdmmr); + if (enable) + tmp |= DMA_MODE_ECC; + else + tmp &= ~DMA_MODE_ECC; + iowrite32be(tmp, &fman_rg->dma_rg->fmdmmr); + break; + case(E_FMAN_EX_FPM_STALL_ON_TASKS): + tmp = ioread32be(&fman_rg->fpm_rg->fmfp_ee); + if (enable) + tmp |= FPM_EV_MASK_STALL_EN; + else + tmp &= ~FPM_EV_MASK_STALL_EN; + iowrite32be(tmp, &fman_rg->fpm_rg->fmfp_ee); + break; + case(E_FMAN_EX_FPM_SINGLE_ECC): + tmp = ioread32be(&fman_rg->fpm_rg->fmfp_ee); + if (enable) + tmp |= FPM_EV_MASK_SINGLE_ECC_EN; + else + tmp &= ~FPM_EV_MASK_SINGLE_ECC_EN; + iowrite32be(tmp, &fman_rg->fpm_rg->fmfp_ee); + break; + case(E_FMAN_EX_FPM_DOUBLE_ECC): + tmp = ioread32be(&fman_rg->fpm_rg->fmfp_ee); + if (enable) + tmp |= FPM_EV_MASK_DOUBLE_ECC_EN; + else + tmp &= ~FPM_EV_MASK_DOUBLE_ECC_EN; + iowrite32be(tmp, &fman_rg->fpm_rg->fmfp_ee); + break; + case(E_FMAN_EX_QMI_SINGLE_ECC): + tmp = ioread32be(&fman_rg->qmi_rg->fmqm_ien); + if (enable) + tmp |= QMI_INTR_EN_SINGLE_ECC; + else + tmp &= ~QMI_INTR_EN_SINGLE_ECC; + iowrite32be(tmp, &fman_rg->qmi_rg->fmqm_ien); + break; + case(E_FMAN_EX_QMI_DOUBLE_ECC): + tmp = ioread32be(&fman_rg->qmi_rg->fmqm_eien); + if (enable) + tmp |= QMI_ERR_INTR_EN_DOUBLE_ECC; + else + tmp &= ~QMI_ERR_INTR_EN_DOUBLE_ECC; + iowrite32be(tmp, &fman_rg->qmi_rg->fmqm_eien); + break; + case(E_FMAN_EX_QMI_DEQ_FROM_UNKNOWN_PORTID): + tmp = ioread32be(&fman_rg->qmi_rg->fmqm_eien); + if (enable) + tmp |= QMI_ERR_INTR_EN_DEQ_FROM_DEF; + else + tmp &= ~QMI_ERR_INTR_EN_DEQ_FROM_DEF; + iowrite32be(tmp, &fman_rg->qmi_rg->fmqm_eien); + break; + case(E_FMAN_EX_BMI_LIST_RAM_ECC): + tmp = ioread32be(&fman_rg->bmi_rg->fmbm_ier); + if (enable) + tmp |= BMI_ERR_INTR_EN_LIST_RAM_ECC; + else + tmp &= ~BMI_ERR_INTR_EN_LIST_RAM_ECC; + iowrite32be(tmp, &fman_rg->bmi_rg->fmbm_ier); + break; + case(E_FMAN_EX_BMI_STORAGE_PROFILE_ECC): + tmp = ioread32be(&fman_rg->bmi_rg->fmbm_ier); + if (enable) + tmp |= BMI_ERR_INTR_EN_STORAGE_PROFILE_ECC; + else + tmp &= ~BMI_ERR_INTR_EN_STORAGE_PROFILE_ECC; + iowrite32be(tmp, &fman_rg->bmi_rg->fmbm_ier); + break; + case(E_FMAN_EX_BMI_STATISTICS_RAM_ECC): + tmp = ioread32be(&fman_rg->bmi_rg->fmbm_ier); + if (enable) + tmp |= BMI_ERR_INTR_EN_STATISTICS_RAM_ECC; + else + tmp &= ~BMI_ERR_INTR_EN_STATISTICS_RAM_ECC; + iowrite32be(tmp, &fman_rg->bmi_rg->fmbm_ier); + break; + case(E_FMAN_EX_BMI_DISPATCH_RAM_ECC): + tmp = ioread32be(&fman_rg->bmi_rg->fmbm_ier); + if (enable) + tmp |= BMI_ERR_INTR_EN_DISPATCH_RAM_ECC; + else + tmp &= ~BMI_ERR_INTR_EN_DISPATCH_RAM_ECC; + iowrite32be(tmp, &fman_rg->bmi_rg->fmbm_ier); + break; + case(E_FMAN_EX_IRAM_ECC): + tmp = ioread32be(&fman_rg->fpm_rg->fm_rie); + if (enable) { + /* enable ECC if not enabled */ + fman_enable_rams_ecc(fman_rg->fpm_rg); + /* enable ECC interrupts */ + tmp |= FPM_IRAM_ECC_ERR_EX_EN; + } else { + /* ECC mechanism may be disabled, + * depending on driver status */ + fman_disable_rams_ecc(fman_rg->fpm_rg); + tmp &= ~FPM_IRAM_ECC_ERR_EX_EN; + } + iowrite32be(tmp, &fman_rg->fpm_rg->fm_rie); + break; + case(E_FMAN_EX_MURAM_ECC): + tmp = ioread32be(&fman_rg->fpm_rg->fm_rie); + if (enable) { + /* enable ECC if not enabled */ + fman_enable_rams_ecc(fman_rg->fpm_rg); + /* enable ECC interrupts */ + tmp |= FPM_MURAM_ECC_ERR_EX_EN; + } else { + /* ECC mechanism may be disabled, + * depending on driver status */ + fman_disable_rams_ecc(fman_rg->fpm_rg); + tmp &= ~FPM_MURAM_ECC_ERR_EX_EN; + } + iowrite32be(tmp, &fman_rg->fpm_rg->fm_rie); + break; + default: + return -EINVAL; + } + return 0; +} + +void fman_get_revision(struct fman_fpm_regs *fpm_rg, + uint8_t *major, + uint8_t *minor) +{ + uint32_t tmp; + + tmp = ioread32be(&fpm_rg->fm_ip_rev_1); + *major = (uint8_t)((tmp & FPM_REV1_MAJOR_MASK) >> FPM_REV1_MAJOR_SHIFT); + *minor = (uint8_t)((tmp & FPM_REV1_MINOR_MASK) >> FPM_REV1_MINOR_SHIFT); + +} + +uint32_t fman_get_counter(struct fman_rg *fman_rg, + enum fman_counters reg_name) +{ + uint32_t ret_val; + + switch (reg_name) { + case(E_FMAN_COUNTERS_ENQ_TOTAL_FRAME): + ret_val = ioread32be(&fman_rg->qmi_rg->fmqm_etfc); + break; + case(E_FMAN_COUNTERS_DEQ_TOTAL_FRAME): + ret_val = ioread32be(&fman_rg->qmi_rg->fmqm_dtfc); + break; + case(E_FMAN_COUNTERS_DEQ_0): + ret_val = ioread32be(&fman_rg->qmi_rg->fmqm_dc0); + break; + case(E_FMAN_COUNTERS_DEQ_1): + ret_val = ioread32be(&fman_rg->qmi_rg->fmqm_dc1); + break; + case(E_FMAN_COUNTERS_DEQ_2): + ret_val = ioread32be(&fman_rg->qmi_rg->fmqm_dc2); + break; + case(E_FMAN_COUNTERS_DEQ_3): + ret_val = ioread32be(&fman_rg->qmi_rg->fmqm_dc3); + break; + case(E_FMAN_COUNTERS_DEQ_FROM_DEFAULT): + ret_val = ioread32be(&fman_rg->qmi_rg->fmqm_dfdc); + break; + case(E_FMAN_COUNTERS_DEQ_FROM_CONTEXT): + ret_val = ioread32be(&fman_rg->qmi_rg->fmqm_dfcc); + break; + case(E_FMAN_COUNTERS_DEQ_FROM_FD): + ret_val = ioread32be(&fman_rg->qmi_rg->fmqm_dffc); + break; + case(E_FMAN_COUNTERS_DEQ_CONFIRM): + ret_val = ioread32be(&fman_rg->qmi_rg->fmqm_dcc); + break; + default: + ret_val = 0; + } + return ret_val; +} + +int fman_modify_counter(struct fman_rg *fman_rg, + enum fman_counters reg_name, + uint32_t val) +{ + /* When applicable (when there is an 'enable counters' bit, + * check that counters are enabled */ + switch (reg_name) { + case(E_FMAN_COUNTERS_ENQ_TOTAL_FRAME): + case(E_FMAN_COUNTERS_DEQ_TOTAL_FRAME): + case(E_FMAN_COUNTERS_DEQ_0): + case(E_FMAN_COUNTERS_DEQ_1): + case(E_FMAN_COUNTERS_DEQ_2): + case(E_FMAN_COUNTERS_DEQ_3): + case(E_FMAN_COUNTERS_DEQ_FROM_DEFAULT): + case(E_FMAN_COUNTERS_DEQ_FROM_CONTEXT): + case(E_FMAN_COUNTERS_DEQ_FROM_FD): + case(E_FMAN_COUNTERS_DEQ_CONFIRM): + if (!(ioread32be(&fman_rg->qmi_rg->fmqm_gc) & + QMI_CFG_EN_COUNTERS)) + return -EINVAL; + break; + default: + break; + } + /* Set counter */ + switch (reg_name) { + case(E_FMAN_COUNTERS_ENQ_TOTAL_FRAME): + iowrite32be(val, &fman_rg->qmi_rg->fmqm_etfc); + break; + case(E_FMAN_COUNTERS_DEQ_TOTAL_FRAME): + iowrite32be(val, &fman_rg->qmi_rg->fmqm_dtfc); + break; + case(E_FMAN_COUNTERS_DEQ_0): + iowrite32be(val, &fman_rg->qmi_rg->fmqm_dc0); + break; + case(E_FMAN_COUNTERS_DEQ_1): + iowrite32be(val, &fman_rg->qmi_rg->fmqm_dc1); + break; + case(E_FMAN_COUNTERS_DEQ_2): + iowrite32be(val, &fman_rg->qmi_rg->fmqm_dc2); + break; + case(E_FMAN_COUNTERS_DEQ_3): + iowrite32be(val, &fman_rg->qmi_rg->fmqm_dc3); + break; + case(E_FMAN_COUNTERS_DEQ_FROM_DEFAULT): + iowrite32be(val, &fman_rg->qmi_rg->fmqm_dfdc); + break; + case(E_FMAN_COUNTERS_DEQ_FROM_CONTEXT): + iowrite32be(val, &fman_rg->qmi_rg->fmqm_dfcc); + break; + case(E_FMAN_COUNTERS_DEQ_FROM_FD): + iowrite32be(val, &fman_rg->qmi_rg->fmqm_dffc); + break; + case(E_FMAN_COUNTERS_DEQ_CONFIRM): + iowrite32be(val, &fman_rg->qmi_rg->fmqm_dcc); + break; + case(E_FMAN_COUNTERS_SEMAPHOR_ENTRY_FULL_REJECT): + iowrite32be(val, &fman_rg->dma_rg->fmdmsefrc); + break; + case(E_FMAN_COUNTERS_SEMAPHOR_QUEUE_FULL_REJECT): + iowrite32be(val, &fman_rg->dma_rg->fmdmsqfrc); + break; + case(E_FMAN_COUNTERS_SEMAPHOR_SYNC_REJECT): + iowrite32be(val, &fman_rg->dma_rg->fmdmssrc); + break; + default: + break; + } + return 0; +} + +void fman_set_dma_emergency(struct fman_dma_regs *dma_rg, + bool is_write, + bool enable) +{ + uint32_t msk; + + msk = (uint32_t)(is_write ? DMA_MODE_EMER_WRITE : DMA_MODE_EMER_READ); + + if (enable) + iowrite32be(ioread32be(&dma_rg->fmdmmr) | msk, + &dma_rg->fmdmmr); + else /* disable */ + iowrite32be(ioread32be(&dma_rg->fmdmmr) & ~msk, + &dma_rg->fmdmmr); +} + +void fman_set_dma_ext_bus_pri(struct fman_dma_regs *dma_rg, uint32_t pri) +{ + uint32_t tmp; + + tmp = ioread32be(&dma_rg->fmdmmr) | + (pri << DMA_MODE_BUS_PRI_SHIFT); + + iowrite32be(tmp, &dma_rg->fmdmmr); +} + +uint32_t fman_get_dma_status(struct fman_dma_regs *dma_rg) +{ + return ioread32be(&dma_rg->fmdmsr); +} + +void fman_force_intr(struct fman_rg *fman_rg, + enum fman_exceptions exception) +{ + switch (exception) { + case E_FMAN_EX_QMI_DEQ_FROM_UNKNOWN_PORTID: + iowrite32be(QMI_ERR_INTR_EN_DEQ_FROM_DEF, + &fman_rg->qmi_rg->fmqm_eif); + break; + case E_FMAN_EX_QMI_SINGLE_ECC: + iowrite32be(QMI_INTR_EN_SINGLE_ECC, + &fman_rg->qmi_rg->fmqm_if); + break; + case E_FMAN_EX_QMI_DOUBLE_ECC: + iowrite32be(QMI_ERR_INTR_EN_DOUBLE_ECC, + &fman_rg->qmi_rg->fmqm_eif); + break; + case E_FMAN_EX_BMI_LIST_RAM_ECC: + iowrite32be(BMI_ERR_INTR_EN_LIST_RAM_ECC, + &fman_rg->bmi_rg->fmbm_ifr); + break; + case E_FMAN_EX_BMI_STORAGE_PROFILE_ECC: + iowrite32be(BMI_ERR_INTR_EN_STORAGE_PROFILE_ECC, + &fman_rg->bmi_rg->fmbm_ifr); + break; + case E_FMAN_EX_BMI_STATISTICS_RAM_ECC: + iowrite32be(BMI_ERR_INTR_EN_STATISTICS_RAM_ECC, + &fman_rg->bmi_rg->fmbm_ifr); + break; + case E_FMAN_EX_BMI_DISPATCH_RAM_ECC: + iowrite32be(BMI_ERR_INTR_EN_DISPATCH_RAM_ECC, + &fman_rg->bmi_rg->fmbm_ifr); + break; + default: + break; + } +} + +bool fman_is_qmi_halt_not_busy_state(struct fman_qmi_regs *qmi_rg) +{ + return (bool)!!(ioread32be(&qmi_rg->fmqm_gs) & QMI_GS_HALT_NOT_BUSY); +} +void fman_resume(struct fman_fpm_regs *fpm_rg) +{ + uint32_t tmp; + + tmp = ioread32be(&fpm_rg->fmfp_ee); + /* clear tmp_reg event bits in order not to clear standing events */ + tmp &= ~(FPM_EV_MASK_DOUBLE_ECC | + FPM_EV_MASK_STALL | + FPM_EV_MASK_SINGLE_ECC); + tmp |= FPM_EV_MASK_RELEASE_FM; + + iowrite32be(tmp, &fpm_rg->fmfp_ee); +} diff --git a/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/inc/fm_common.h b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/inc/fm_common.h new file mode 100644 index 000000000000..204840c9df39 --- /dev/null +++ b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/inc/fm_common.h @@ -0,0 +1,1214 @@ +/* + * Copyright 2008-2012 Freescale Semiconductor Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Freescale Semiconductor nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * + * ALTERNATIVELY, this software may be distributed under the terms of the + * GNU General Public License ("GPL") as published by the Free Software + * Foundation, either version 2 of that License or (at your option) any + * later version. + * + * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + +/****************************************************************************** + @File fm_common.h + + @Description FM internal structures and definitions. +*//***************************************************************************/ +#ifndef __FM_COMMON_H +#define __FM_COMMON_H + +#include "error_ext.h" +#include "std_ext.h" +#include "fm_pcd_ext.h" +#include "fm_ext.h" +#include "fm_port_ext.h" + + +#define e_FM_PORT_TYPE_OH_HOST_COMMAND e_FM_PORT_TYPE_DUMMY + +#define CLS_PLAN_NUM_PER_GRP 8 + +#define IP_OFFLOAD_PACKAGE_NUMBER 106 +#define CAPWAP_OFFLOAD_PACKAGE_NUMBER 108 +#define IS_OFFLOAD_PACKAGE(num) ((num == IP_OFFLOAD_PACKAGE_NUMBER) || (num == CAPWAP_OFFLOAD_PACKAGE_NUMBER)) + + + +/**************************************************************************//** + @Description Modules registers offsets +*//***************************************************************************/ +#define FM_MM_MURAM 0x00000000 +#define FM_MM_BMI 0x00080000 +#define FM_MM_QMI 0x00080400 +#define FM_MM_PRS 0x000c7000 +#define FM_MM_KG 0x000C1000 +#define FM_MM_DMA 0x000C2000 +#define FM_MM_FPM 0x000C3000 +#define FM_MM_PLCR 0x000C0000 +#define FM_MM_IMEM 0x000C4000 +#define FM_MM_CGP 0x000DB000 +#define FM_MM_TRB(i) (0x000D0200 + 0x400 * (i)) +#if (DPAA_VERSION >= 11) +#define FM_MM_SP 0x000dc000 +#endif /* (DPAA_VERSION >= 11) */ + + +/**************************************************************************//** + @Description Enum for inter-module interrupts registration +*//***************************************************************************/ +typedef enum e_FmEventModules{ + e_FM_MOD_PRS, /**< Parser event */ + e_FM_MOD_KG, /**< Keygen event */ + e_FM_MOD_PLCR, /**< Policer event */ + e_FM_MOD_10G_MAC, /**< 10G MAC event */ + e_FM_MOD_1G_MAC, /**< 1G MAC event */ + e_FM_MOD_TMR, /**< Timer event */ + e_FM_MOD_FMAN_CTRL, /**< FMAN Controller Timer event */ + e_FM_MOD_MACSEC, + e_FM_MOD_DUMMY_LAST +} e_FmEventModules; + +/**************************************************************************//** + @Description Enum for interrupts types +*//***************************************************************************/ +typedef enum e_FmIntrType { + e_FM_INTR_TYPE_ERR, + e_FM_INTR_TYPE_NORMAL +} e_FmIntrType; + +/**************************************************************************//** + @Description Enum for inter-module interrupts registration +*//***************************************************************************/ +typedef enum e_FmInterModuleEvent +{ + e_FM_EV_PRS = 0, /**< Parser event */ + e_FM_EV_ERR_PRS, /**< Parser error event */ + e_FM_EV_KG, /**< Keygen event */ + e_FM_EV_ERR_KG, /**< Keygen error event */ + e_FM_EV_PLCR, /**< Policer event */ + e_FM_EV_ERR_PLCR, /**< Policer error event */ + e_FM_EV_ERR_10G_MAC0, /**< 10G MAC 0 error event */ + e_FM_EV_ERR_10G_MAC1, /**< 10G MAC 1 error event */ + e_FM_EV_ERR_1G_MAC0, /**< 1G MAC 0 error event */ + e_FM_EV_ERR_1G_MAC1, /**< 1G MAC 1 error event */ + e_FM_EV_ERR_1G_MAC2, /**< 1G MAC 2 error event */ + e_FM_EV_ERR_1G_MAC3, /**< 1G MAC 3 error event */ + e_FM_EV_ERR_1G_MAC4, /**< 1G MAC 4 error event */ + e_FM_EV_ERR_1G_MAC5, /**< 1G MAC 5 error event */ + e_FM_EV_ERR_1G_MAC6, /**< 1G MAC 6 error event */ + e_FM_EV_ERR_1G_MAC7, /**< 1G MAC 7 error event */ + e_FM_EV_ERR_MACSEC_MAC0, + e_FM_EV_TMR, /**< Timer event */ + e_FM_EV_10G_MAC0, /**< 10G MAC 0 event (Magic packet detection)*/ + e_FM_EV_10G_MAC1, /**< 10G MAC 1 event (Magic packet detection)*/ + e_FM_EV_1G_MAC0, /**< 1G MAC 0 event (Magic packet detection)*/ + e_FM_EV_1G_MAC1, /**< 1G MAC 1 event (Magic packet detection)*/ + e_FM_EV_1G_MAC2, /**< 1G MAC 2 (Magic packet detection)*/ + e_FM_EV_1G_MAC3, /**< 1G MAC 3 (Magic packet detection)*/ + e_FM_EV_1G_MAC4, /**< 1G MAC 4 (Magic packet detection)*/ + e_FM_EV_1G_MAC5, /**< 1G MAC 5 (Magic packet detection)*/ + e_FM_EV_1G_MAC6, /**< 1G MAC 6 (Magic packet detection)*/ + e_FM_EV_1G_MAC7, /**< 1G MAC 7 (Magic packet detection)*/ + e_FM_EV_MACSEC_MAC0, /**< MACSEC MAC 0 event */ + e_FM_EV_FMAN_CTRL_0, /**< Fman controller event 0 */ + e_FM_EV_FMAN_CTRL_1, /**< Fman controller event 1 */ + e_FM_EV_FMAN_CTRL_2, /**< Fman controller event 2 */ + e_FM_EV_FMAN_CTRL_3, /**< Fman controller event 3 */ + e_FM_EV_DUMMY_LAST +} e_FmInterModuleEvent; + + +#if defined(__MWERKS__) && !defined(__GNUC__) +#pragma pack(push,1) +#endif /* defined(__MWERKS__) && ... */ + +/**************************************************************************//** + @Description PCD KG scheme registers +*//***************************************************************************/ +typedef _Packed struct t_FmPcdPlcrProfileRegs { + volatile uint32_t fmpl_pemode; /* 0x090 FMPL_PEMODE - FM Policer Profile Entry Mode*/ + volatile uint32_t fmpl_pegnia; /* 0x094 FMPL_PEGNIA - FM Policer Profile Entry GREEN Next Invoked Action*/ + volatile uint32_t fmpl_peynia; /* 0x098 FMPL_PEYNIA - FM Policer Profile Entry YELLOW Next Invoked Action*/ + volatile uint32_t fmpl_pernia; /* 0x09C FMPL_PERNIA - FM Policer Profile Entry RED Next Invoked Action*/ + volatile uint32_t fmpl_pecir; /* 0x0A0 FMPL_PECIR - FM Policer Profile Entry Committed Information Rate*/ + volatile uint32_t fmpl_pecbs; /* 0x0A4 FMPL_PECBS - FM Policer Profile Entry Committed Burst Size*/ + volatile uint32_t fmpl_pepepir_eir; /* 0x0A8 FMPL_PEPIR_EIR - FM Policer Profile Entry Peak/Excess Information Rate*/ + volatile uint32_t fmpl_pepbs_ebs; /* 0x0AC FMPL_PEPBS_EBS - FM Policer Profile Entry Peak/Excess Information Rate*/ + volatile uint32_t fmpl_pelts; /* 0x0B0 FMPL_PELTS - FM Policer Profile Entry Last TimeStamp*/ + volatile uint32_t fmpl_pects; /* 0x0B4 FMPL_PECTS - FM Policer Profile Entry Committed Token Status*/ + volatile uint32_t fmpl_pepts_ets; /* 0x0B8 FMPL_PEPTS_ETS - FM Policer Profile Entry Peak/Excess Token Status*/ + volatile uint32_t fmpl_pegpc; /* 0x0BC FMPL_PEGPC - FM Policer Profile Entry GREEN Packet Counter*/ + volatile uint32_t fmpl_peypc; /* 0x0C0 FMPL_PEYPC - FM Policer Profile Entry YELLOW Packet Counter*/ + volatile uint32_t fmpl_perpc; /* 0x0C4 FMPL_PERPC - FM Policer Profile Entry RED Packet Counter */ + volatile uint32_t fmpl_perypc; /* 0x0C8 FMPL_PERYPC - FM Policer Profile Entry Recolored YELLOW Packet Counter*/ + volatile uint32_t fmpl_perrpc; /* 0x0CC FMPL_PERRPC - FM Policer Profile Entry Recolored RED Packet Counter*/ + volatile uint32_t fmpl_res1[12]; /* 0x0D0-0x0FF Reserved */ +} _PackedType t_FmPcdPlcrProfileRegs; + + +typedef _Packed struct t_FmPcdCcCapwapReassmTimeoutParams { + volatile uint32_t portIdAndCapwapReassmTbl; + volatile uint32_t fqidForTimeOutFrames; + volatile uint32_t timeoutRequestTime; +}_PackedType t_FmPcdCcCapwapReassmTimeoutParams; + +/**************************************************************************//** + @Description PCD CTRL Parameters Page +*//***************************************************************************/ +typedef _Packed struct t_FmPcdCtrlParamsPage { + volatile uint8_t reserved0[16]; + volatile uint32_t iprIpv4Nia; + volatile uint32_t iprIpv6Nia; + volatile uint8_t reserved1[24]; + volatile uint32_t ipfOptionsCounter; + volatile uint8_t reserved2[12]; + volatile uint32_t misc; + volatile uint32_t errorsDiscardMask; + volatile uint32_t discardMask; + volatile uint8_t reserved3[4]; + volatile uint32_t postBmiFetchNia; + volatile uint8_t reserved4[172]; +} _PackedType t_FmPcdCtrlParamsPage; + + + +#if defined(__MWERKS__) && !defined(__GNUC__) +#pragma pack(pop) +#endif /* defined(__MWERKS__) && ... */ + + +/*for UNDER_CONSTRUCTION_FM_RMU_USE_SEC its defined in fm_ext.h*/ +typedef uint32_t t_FmFmanCtrl; + +#define FPM_PORT_FM_CTL1 0x00000001 +#define FPM_PORT_FM_CTL2 0x00000002 + + + +typedef struct t_FmPcdCcFragScratchPoolCmdParams { + uint32_t numOfBuffers; + uint8_t bufferPoolId; +} t_FmPcdCcFragScratchPoolCmdParams; + +typedef struct t_FmPcdCcReassmTimeoutParams { + bool activate; + uint8_t tsbs; + uint32_t iprcpt; +} t_FmPcdCcReassmTimeoutParams; + +typedef struct { + uint8_t baseEntry; + uint16_t numOfClsPlanEntries; + uint32_t vectors[FM_PCD_MAX_NUM_OF_CLS_PLANS]; +} t_FmPcdKgInterModuleClsPlanSet; + +/**************************************************************************//** + @Description Structure for binding a port to keygen schemes. +*//***************************************************************************/ +typedef struct t_FmPcdKgInterModuleBindPortToSchemes { + uint8_t hardwarePortId; + uint8_t netEnvId; + bool useClsPlan; /**< TRUE if this port uses the clsPlan mechanism */ + uint8_t numOfSchemes; + uint8_t schemesIds[FM_PCD_KG_NUM_OF_SCHEMES]; +} t_FmPcdKgInterModuleBindPortToSchemes; + +typedef struct { + uint32_t nextCcNodeInfo; + t_List node; +} t_CcNodeInfo; + +typedef struct +{ + t_Handle h_CcNode; + uint16_t index; + t_List node; +}t_CcNodeInformation; +#define CC_NODE_F_OBJECT(ptr) LIST_OBJECT(ptr, t_CcNodeInformation, node) + +typedef enum e_ModifyState +{ + e_MODIFY_STATE_ADD = 0, + e_MODIFY_STATE_REMOVE, + e_MODIFY_STATE_CHANGE +} e_ModifyState; + +typedef struct +{ + t_Handle h_Manip; + t_List node; +}t_ManipInfo; +#define CC_NEXT_NODE_F_OBJECT(ptr) LIST_OBJECT(ptr, t_CcNodeInfo, node) + +typedef struct { + uint32_t type; + uint8_t prOffset; + uint16_t dataOffset; + uint8_t internalBufferOffset; + uint8_t numOfTasks; + uint8_t numOfExtraTasks; + uint8_t hardwarePortId; + t_FmRevisionInfo revInfo; + uint32_t nia; + uint32_t discardMask; +} t_GetCcParams; + +typedef struct { + uint32_t type; + int psoSize; + uint32_t nia; + t_FmFmanCtrl orFmanCtrl; + bool overwrite; + uint8_t ofpDpde; +} t_SetCcParams; + +typedef struct { + t_GetCcParams getCcParams; + t_SetCcParams setCcParams; +} t_FmPortGetSetCcParams; + +typedef struct { + uint32_t type; + bool sleep; +} t_FmSetParams; + +typedef struct { + uint32_t type; + uint32_t fmqm_gs; + uint32_t fm_npi; + uint32_t fm_cld; + uint32_t fmfp_extc; +} t_FmGetParams; + +typedef struct { + t_FmSetParams setParams; + t_FmGetParams getParams; +} t_FmGetSetParams; + +t_Error FmGetSetParams(t_Handle h_Fm, t_FmGetSetParams *p_Params); + +static __inline__ bool TRY_LOCK(t_Handle h_Spinlock, volatile bool *p_Flag) +{ + uint32_t intFlags; + if (h_Spinlock) + intFlags = XX_LockIntrSpinlock(h_Spinlock); + else + intFlags = XX_DisableAllIntr(); + + if (*p_Flag) + { + if (h_Spinlock) + XX_UnlockIntrSpinlock(h_Spinlock, intFlags); + else + XX_RestoreAllIntr(intFlags); + return FALSE; + } + *p_Flag = TRUE; + + if (h_Spinlock) + XX_UnlockIntrSpinlock(h_Spinlock, intFlags); + else + XX_RestoreAllIntr(intFlags); + + return TRUE; +} + +#define RELEASE_LOCK(_flag) _flag = FALSE; + +/**************************************************************************//** + @Collection Defines used for manipulation CC and BMI + @{ +*//***************************************************************************/ +#define INTERNAL_CONTEXT_OFFSET 0x80000000 +#define OFFSET_OF_PR 0x40000000 +#define MANIP_EXTRA_SPACE 0x20000000 +#define NUM_OF_TASKS 0x10000000 +#define OFFSET_OF_DATA 0x08000000 +#define HW_PORT_ID 0x04000000 +#define FM_REV 0x02000000 +#define GET_NIA_FPNE 0x01000000 +#define GET_NIA_PNDN 0x00800000 +#define NUM_OF_EXTRA_TASKS 0x00400000 +#define DISCARD_MASK 0x00200000 + +#define UPDATE_NIA_PNEN 0x80000000 +#define UPDATE_PSO 0x40000000 +#define UPDATE_NIA_PNDN 0x20000000 +#define UPDATE_FMFP_PRC_WITH_ONE_RISC_ONLY 0x10000000 +#define UPDATE_OFP_DPTE 0x08000000 +#define UPDATE_NIA_FENE 0x04000000 +#define UPDATE_NIA_CMNE 0x02000000 +#define UPDATE_NIA_FPNE 0x01000000 +/* @} */ + +/**************************************************************************//** + @Collection Defines used for manipulation CC and CC + @{ +*//***************************************************************************/ +#define UPDATE_NIA_ENQ_WITHOUT_DMA 0x80000000 +#define UPDATE_CC_WITH_TREE 0x40000000 +#define UPDATE_CC_WITH_DELETE_TREE 0x20000000 +#define UPDATE_KG_NIA_CC_WA 0x10000000 +#define UPDATE_KG_OPT_MODE 0x08000000 +#define UPDATE_KG_NIA 0x04000000 +#define UPDATE_CC_SHADOW_CLEAR 0x02000000 +/* @} */ + +#define UPDATE_FPM_BRKC_SLP 0x80000000 +#define UPDATE_FPM_EXTC 0x40000000 +#define UPDATE_FPM_EXTC_CLEAR 0x20000000 +#define GET_FMQM_GS 0x10000000 +#define GET_FM_NPI 0x08000000 +#define GET_FMFP_EXTC 0x04000000 +#define CLEAR_IRAM_READY 0x02000000 +#define UPDATE_FM_CLD 0x01000000 +#define GET_FM_CLD 0x00800000 +#define FM_MAX_NUM_OF_PORTS (FM_MAX_NUM_OF_OH_PORTS + \ + FM_MAX_NUM_OF_1G_RX_PORTS + \ + FM_MAX_NUM_OF_10G_RX_PORTS + \ + FM_MAX_NUM_OF_1G_TX_PORTS + \ + FM_MAX_NUM_OF_10G_TX_PORTS) + +#define MODULE_NAME_SIZE 30 +#define DUMMY_PORT_ID 0 + +#define FM_LIODN_OFFSET_MASK 0x3FF + +/**************************************************************************//** + @Description NIA Description +*//***************************************************************************/ +#define NIA_ENG_MASK 0x007C0000 +#define NIA_AC_MASK 0x0003ffff + +#define NIA_ORDER_RESTOR 0x00800000 +#define NIA_ENG_FM_CTL 0x00000000 +#define NIA_ENG_PRS 0x00440000 +#define NIA_ENG_KG 0x00480000 +#define NIA_ENG_PLCR 0x004C0000 +#define NIA_ENG_BMI 0x00500000 +#define NIA_ENG_QMI_ENQ 0x00540000 +#define NIA_ENG_QMI_DEQ 0x00580000 + +#define NIA_FM_CTL_AC_CC 0x00000006 +#define NIA_FM_CTL_AC_HC 0x0000000C +#define NIA_FM_CTL_AC_IND_MODE_TX 0x00000008 +#define NIA_FM_CTL_AC_IND_MODE_RX 0x0000000A +#define NIA_FM_CTL_AC_POP_TO_N_STEP 0x0000000e +#define NIA_FM_CTL_AC_PRE_BMI_FETCH_HEADER 0x00000010 +#define NIA_FM_CTL_AC_PRE_BMI_FETCH_FULL_FRAME 0x00000018 +#define NIA_FM_CTL_AC_POST_BMI_FETCH 0x00000012 +#define NIA_FM_CTL_AC_PRE_BMI_ENQ_FRAME 0x0000001A +#define NIA_FM_CTL_AC_PRE_BMI_DISCARD_FRAME 0x0000001E +#define NIA_FM_CTL_AC_POST_BMI_ENQ_ORR 0x00000014 +#define NIA_FM_CTL_AC_POST_BMI_ENQ 0x00000022 +#define NIA_FM_CTL_AC_PRE_CC 0x00000020 +#define NIA_FM_CTL_AC_POST_TX 0x00000024 +/* V3 only */ +#define NIA_FM_CTL_AC_NO_IPACC_PRE_BMI_ENQ_FRAME 0x00000028 +#define NIA_FM_CTL_AC_NO_IPACC_PRE_BMI_DISCARD_FRAME 0x0000002A +#define NIA_FM_CTL_AC_NO_IPACC_POP_TO_N_STEP 0x0000002C + +#define NIA_BMI_AC_ENQ_FRAME 0x00000002 +#define NIA_BMI_AC_TX_RELEASE 0x000002C0 +#define NIA_BMI_AC_RELEASE 0x000000C0 +#define NIA_BMI_AC_DISCARD 0x000000C1 +#define NIA_BMI_AC_TX 0x00000274 +#define NIA_BMI_AC_FETCH 0x00000208 +#define NIA_BMI_AC_MASK 0x000003FF + +#define NIA_KG_DIRECT 0x00000100 +#define NIA_KG_CC_EN 0x00000200 +#define NIA_PLCR_ABSOLUTE 0x00008000 + +#define NIA_BMI_AC_ENQ_FRAME_WITHOUT_DMA 0x00000202 + +#if defined(FM_OP_NO_VSP_NO_RELEASE_ERRATA_FMAN_A006675) || defined(FM_ERROR_VSP_NO_MATCH_SW006) +#define GET_NIA_BMI_AC_ENQ_FRAME(h_FmPcd) \ + (uint32_t)((FmPcdIsAdvancedOffloadSupported(h_FmPcd)) ? \ + (NIA_ENG_FM_CTL | NIA_FM_CTL_AC_PRE_BMI_ENQ_FRAME) : \ + (NIA_ENG_FM_CTL | NIA_FM_CTL_AC_NO_IPACC_PRE_BMI_ENQ_FRAME)) +#define GET_NIA_BMI_AC_DISCARD_FRAME(h_FmPcd) \ + (uint32_t)((FmPcdIsAdvancedOffloadSupported(h_FmPcd)) ? \ + (NIA_ENG_FM_CTL | NIA_FM_CTL_AC_PRE_BMI_DISCARD_FRAME) : \ + (NIA_ENG_FM_CTL | NIA_FM_CTL_AC_NO_IPACC_PRE_BMI_DISCARD_FRAME)) +#define GET_NO_PCD_NIA_BMI_AC_ENQ_FRAME() \ + (NIA_ENG_FM_CTL | NIA_FM_CTL_AC_NO_IPACC_PRE_BMI_ENQ_FRAME) +#else +#define GET_NIA_BMI_AC_ENQ_FRAME(h_FmPcd) \ + (uint32_t)((FmPcdIsAdvancedOffloadSupported(h_FmPcd)) ? \ + (NIA_ENG_FM_CTL | NIA_FM_CTL_AC_PRE_BMI_ENQ_FRAME) : \ + (NIA_ENG_BMI | NIA_BMI_AC_ENQ_FRAME)) +#define GET_NIA_BMI_AC_DISCARD_FRAME(h_FmPcd) \ + (uint32_t)((FmPcdIsAdvancedOffloadSupported(h_FmPcd)) ? \ + (NIA_ENG_FM_CTL | NIA_FM_CTL_AC_PRE_BMI_DISCARD_FRAME) : \ + (NIA_ENG_BMI | NIA_BMI_AC_DISCARD)) +#define GET_NO_PCD_NIA_BMI_AC_ENQ_FRAME() \ + (NIA_ENG_BMI | NIA_BMI_AC_ENQ_FRAME) +#endif /* defined(FM_OP_NO_VSP_NO_RELEASE_ERRATA_FMAN_A006675) || ... */ + +/**************************************************************************//** + @Description CTRL Parameters Page defines +*//***************************************************************************/ +#define FM_CTL_PARAMS_PAGE_OP_FIX_EN 0x80000000 +#define FM_CTL_PARAMS_PAGE_OFFLOAD_SUPPORT_EN 0x40000000 +#define FM_CTL_PARAMS_PAGE_ALWAYS_ON 0x00000100 + +#define FM_CTL_PARAMS_PAGE_ERROR_VSP_MASK 0x0000003f + +/**************************************************************************//** + @Description Port Id defines +*//***************************************************************************/ +#if (DPAA_VERSION == 10) +#define BASE_OH_PORTID 1 +#else +#define BASE_OH_PORTID 2 +#endif /* (DPAA_VERSION == 10) */ +#define BASE_1G_RX_PORTID 8 +#define BASE_10G_RX_PORTID 0x10 +#define BASE_1G_TX_PORTID 0x28 +#define BASE_10G_TX_PORTID 0x30 + +#define FM_PCD_PORT_OH_BASE_INDX 0 +#define FM_PCD_PORT_1G_RX_BASE_INDX (FM_PCD_PORT_OH_BASE_INDX+FM_MAX_NUM_OF_OH_PORTS) +#define FM_PCD_PORT_10G_RX_BASE_INDX (FM_PCD_PORT_1G_RX_BASE_INDX+FM_MAX_NUM_OF_1G_RX_PORTS) +#define FM_PCD_PORT_1G_TX_BASE_INDX (FM_PCD_PORT_10G_RX_BASE_INDX+FM_MAX_NUM_OF_10G_RX_PORTS) +#define FM_PCD_PORT_10G_TX_BASE_INDX (FM_PCD_PORT_1G_TX_BASE_INDX+FM_MAX_NUM_OF_1G_TX_PORTS) + +#if (FM_MAX_NUM_OF_OH_PORTS > 0) +#define CHECK_PORT_ID_OH_PORTS(_relativePortId) \ + if ((_relativePortId) >= FM_MAX_NUM_OF_OH_PORTS) \ + REPORT_ERROR(MAJOR, E_INVALID_VALUE, ("Illegal OH_PORT port id")) +#else +#define CHECK_PORT_ID_OH_PORTS(_relativePortId) \ + REPORT_ERROR(MAJOR, E_INVALID_VALUE, ("Illegal OH_PORT port id")) +#endif +#if (FM_MAX_NUM_OF_1G_RX_PORTS > 0) +#define CHECK_PORT_ID_1G_RX_PORTS(_relativePortId) \ + if ((_relativePortId) >= FM_MAX_NUM_OF_1G_RX_PORTS) \ + REPORT_ERROR(MAJOR, E_INVALID_VALUE, ("Illegal 1G_RX_PORT port id")) +#else +#define CHECK_PORT_ID_1G_RX_PORTS(_relativePortId) \ + REPORT_ERROR(MAJOR, E_INVALID_VALUE, ("Illegal 1G_RX_PORT port id")) +#endif +#if (FM_MAX_NUM_OF_10G_RX_PORTS > 0) +#define CHECK_PORT_ID_10G_RX_PORTS(_relativePortId) \ + if ((_relativePortId) >= FM_MAX_NUM_OF_10G_RX_PORTS) \ + REPORT_ERROR(MAJOR, E_INVALID_VALUE, ("Illegal 10G_RX_PORT port id")) +#else +#define CHECK_PORT_ID_10G_RX_PORTS(_relativePortId) \ + REPORT_ERROR(MAJOR, E_INVALID_VALUE, ("Illegal 10G_RX_PORT port id")) +#endif +#if (FM_MAX_NUM_OF_1G_TX_PORTS > 0) +#define CHECK_PORT_ID_1G_TX_PORTS(_relativePortId) \ + if ((_relativePortId) >= FM_MAX_NUM_OF_1G_TX_PORTS) \ + REPORT_ERROR(MAJOR, E_INVALID_VALUE, ("Illegal 1G_TX_PORT port id")) +#else +#define CHECK_PORT_ID_1G_TX_PORTS(_relativePortId) \ + REPORT_ERROR(MAJOR, E_INVALID_VALUE, ("Illegal 1G_TX_PORT port id")) +#endif +#if (FM_MAX_NUM_OF_10G_TX_PORTS > 0) +#define CHECK_PORT_ID_10G_TX_PORTS(_relativePortId) \ + if ((_relativePortId) >= FM_MAX_NUM_OF_10G_TX_PORTS) \ + REPORT_ERROR(MAJOR, E_INVALID_VALUE, ("Illegal 10G_TX_PORT port id")) +#else +#define CHECK_PORT_ID_10G_TX_PORTS(_relativePortId) \ + REPORT_ERROR(MAJOR, E_INVALID_VALUE, ("Illegal 10G_TX_PORT port id")) +#endif + +uint8_t SwPortIdToHwPortId(e_FmPortType type, uint8_t relativePortId, uint8_t majorRev, uint8_t minorRev); + +#define HW_PORT_ID_TO_SW_PORT_ID(_relativePortId, hardwarePortId) \ +{ if (((hardwarePortId) >= BASE_OH_PORTID) && \ + ((hardwarePortId) < BASE_OH_PORTID+FM_MAX_NUM_OF_OH_PORTS)) \ + _relativePortId = (uint8_t)((hardwarePortId)-BASE_OH_PORTID); \ + else if (((hardwarePortId) >= BASE_10G_TX_PORTID) && \ + ((hardwarePortId) < BASE_10G_TX_PORTID+FM_MAX_NUM_OF_10G_TX_PORTS)) \ + _relativePortId = (uint8_t)((hardwarePortId)-BASE_10G_TX_PORTID); \ + else if (((hardwarePortId) >= BASE_1G_TX_PORTID) && \ + ((hardwarePortId) < BASE_1G_TX_PORTID+FM_MAX_NUM_OF_1G_TX_PORTS)) \ + _relativePortId = (uint8_t)((hardwarePortId)-BASE_1G_TX_PORTID); \ + else if (((hardwarePortId) >= BASE_10G_RX_PORTID) && \ + ((hardwarePortId) < BASE_10G_RX_PORTID+FM_MAX_NUM_OF_10G_RX_PORTS)) \ + _relativePortId = (uint8_t)((hardwarePortId)-BASE_10G_RX_PORTID); \ + else if (((hardwarePortId) >= BASE_1G_RX_PORTID) && \ + ((hardwarePortId) < BASE_1G_RX_PORTID+FM_MAX_NUM_OF_1G_RX_PORTS)) \ + _relativePortId = (uint8_t)((hardwarePortId)-BASE_1G_RX_PORTID); \ + else { \ + _relativePortId = (uint8_t)DUMMY_PORT_ID; \ + ASSERT_COND(TRUE); \ + } \ +} + +#define HW_PORT_ID_TO_SW_PORT_INDX(swPortIndex, hardwarePortId) \ +do { \ + if (((hardwarePortId) >= BASE_OH_PORTID) && ((hardwarePortId) < BASE_OH_PORTID+FM_MAX_NUM_OF_OH_PORTS)) \ + swPortIndex = (uint8_t)((hardwarePortId)-BASE_OH_PORTID+FM_PCD_PORT_OH_BASE_INDX); \ + else if (((hardwarePortId) >= BASE_1G_RX_PORTID) && \ + ((hardwarePortId) < BASE_1G_RX_PORTID+FM_MAX_NUM_OF_1G_RX_PORTS)) \ + swPortIndex = (uint8_t)((hardwarePortId)-BASE_1G_RX_PORTID+FM_PCD_PORT_1G_RX_BASE_INDX); \ + else if (((hardwarePortId) >= BASE_10G_RX_PORTID) && \ + ((hardwarePortId) < BASE_10G_RX_PORTID+FM_MAX_NUM_OF_10G_RX_PORTS)) \ + swPortIndex = (uint8_t)((hardwarePortId)-BASE_10G_RX_PORTID+FM_PCD_PORT_10G_RX_BASE_INDX); \ + else if (((hardwarePortId) >= BASE_1G_TX_PORTID) && \ + ((hardwarePortId) < BASE_1G_TX_PORTID+FM_MAX_NUM_OF_1G_TX_PORTS)) \ + swPortIndex = (uint8_t)((hardwarePortId)-BASE_1G_TX_PORTID+FM_PCD_PORT_1G_TX_BASE_INDX); \ + else if (((hardwarePortId) >= BASE_10G_TX_PORTID) && \ + ((hardwarePortId) < BASE_10G_TX_PORTID+FM_MAX_NUM_OF_10G_TX_PORTS)) \ + swPortIndex = (uint8_t)((hardwarePortId)-BASE_10G_TX_PORTID+FM_PCD_PORT_10G_TX_BASE_INDX); \ + else ASSERT_COND(FALSE); \ +} while (0) + +#define SW_PORT_INDX_TO_HW_PORT_ID(hardwarePortId, swPortIndex) \ +do { \ + if (((swPortIndex) >= FM_PCD_PORT_OH_BASE_INDX) && ((swPortIndex) < FM_PCD_PORT_1G_RX_BASE_INDX)) \ + hardwarePortId = (uint8_t)((swPortIndex)-FM_PCD_PORT_OH_BASE_INDX+BASE_OH_PORTID); \ + else if (((swPortIndex) >= FM_PCD_PORT_1G_RX_BASE_INDX) && ((swPortIndex) < FM_PCD_PORT_10G_RX_BASE_INDX)) \ + hardwarePortId = (uint8_t)((swPortIndex)-FM_PCD_PORT_1G_RX_BASE_INDX+BASE_1G_RX_PORTID); \ + else if (((swPortIndex) >= FM_PCD_PORT_10G_RX_BASE_INDX) && ((swPortIndex) < FM_MAX_NUM_OF_PORTS)) \ + hardwarePortId = (uint8_t)((swPortIndex)-FM_PCD_PORT_10G_RX_BASE_INDX+BASE_10G_RX_PORTID); \ + else if (((swPortIndex) >= FM_PCD_PORT_1G_TX_BASE_INDX) && ((swPortIndex) < FM_PCD_PORT_10G_TX_BASE_INDX)) \ + hardwarePortId = (uint8_t)((swPortIndex)-FM_PCD_PORT_1G_TX_BASE_INDX+BASE_1G_TX_PORTID); \ + else if (((swPortIndex) >= FM_PCD_PORT_10G_TX_BASE_INDX) && ((swPortIndex) < FM_MAX_NUM_OF_PORTS)) \ + hardwarePortId = (uint8_t)((swPortIndex)-FM_PCD_PORT_10G_TX_BASE_INDX+BASE_10G_TX_PORTID); \ + else ASSERT_COND(FALSE); \ +} while (0) + +#define BMI_MAX_FIFO_SIZE (FM_MURAM_SIZE) +#define BMI_FIFO_UNITS 0x100 + +typedef struct { + void (*f_Isr) (t_Handle h_Arg); + t_Handle h_SrcHandle; + uint8_t guestId; +} t_FmIntrSrc; + +#define ILLEGAL_HDR_NUM 0xFF +#define NO_HDR_NUM FM_PCD_PRS_NUM_OF_HDRS + +#define IS_PRIVATE_HEADER(hdr) (((hdr) == HEADER_TYPE_USER_DEFINED_SHIM1) || \ + ((hdr) == HEADER_TYPE_USER_DEFINED_SHIM2)) +#define IS_SPECIAL_HEADER(hdr) ((hdr) == HEADER_TYPE_MACSEC) + +static __inline__ uint8_t GetPrsHdrNum(e_NetHeaderType hdr) +{ + switch (hdr) + { case (HEADER_TYPE_ETH): return 0; + case (HEADER_TYPE_LLC_SNAP): return 1; + case (HEADER_TYPE_VLAN): return 2; + case (HEADER_TYPE_PPPoE): return 3; + case (HEADER_TYPE_PPP): return 3; + case (HEADER_TYPE_MPLS): return 4; + case (HEADER_TYPE_IPv4): return 5; + case (HEADER_TYPE_IPv6): return 6; + case (HEADER_TYPE_GRE): return 7; + case (HEADER_TYPE_MINENCAP): return 8; + case (HEADER_TYPE_USER_DEFINED_L3): return 9; + case (HEADER_TYPE_TCP): return 10; + case (HEADER_TYPE_UDP): return 11; + case (HEADER_TYPE_IPSEC_AH): + case (HEADER_TYPE_IPSEC_ESP): return 12; + case (HEADER_TYPE_SCTP): return 13; + case (HEADER_TYPE_DCCP): return 14; + case (HEADER_TYPE_USER_DEFINED_L4): return 15; + case (HEADER_TYPE_USER_DEFINED_SHIM1): + case (HEADER_TYPE_USER_DEFINED_SHIM2): + case (HEADER_TYPE_MACSEC): return NO_HDR_NUM; + default: + return ILLEGAL_HDR_NUM; + } +} + +#define FM_PCD_MAX_NUM_OF_OPTIONS(clsPlanEntries) ((clsPlanEntries==256)? 8:((clsPlanEntries==128)? 7: ((clsPlanEntries==64)? 6: ((clsPlanEntries==32)? 5:0)))) + + +/**************************************************************************//** + @Description A structure for initializing a keygen classification plan group +*//***************************************************************************/ +typedef struct t_FmPcdKgInterModuleClsPlanGrpParams { + uint8_t netEnvId; /* IN */ + bool grpExists; /* OUT (unused in FmPcdKgBuildClsPlanGrp)*/ + uint8_t clsPlanGrpId; /* OUT */ + bool emptyClsPlanGrp; /* OUT */ + uint8_t numOfOptions; /* OUT in FmPcdGetSetClsPlanGrpParams IN in FmPcdKgBuildClsPlanGrp*/ + protocolOpt_t options[FM_PCD_MAX_NUM_OF_OPTIONS(FM_PCD_MAX_NUM_OF_CLS_PLANS)]; + /* OUT in FmPcdGetSetClsPlanGrpParams IN in FmPcdKgBuildClsPlanGrp*/ + uint32_t optVectors[FM_PCD_MAX_NUM_OF_OPTIONS(FM_PCD_MAX_NUM_OF_CLS_PLANS)]; + /* OUT in FmPcdGetSetClsPlanGrpParams IN in FmPcdKgBuildClsPlanGrp*/ +} t_FmPcdKgInterModuleClsPlanGrpParams; + +typedef struct t_FmPcdLock { + t_Handle h_Spinlock; + volatile bool flag; + t_List node; +} t_FmPcdLock; +#define FM_PCD_LOCK_OBJ(ptr) LIST_OBJECT(ptr, t_FmPcdLock, node) + + +typedef t_Error (t_FmPortGetSetCcParamsCallback) (t_Handle h_FmPort, + t_FmPortGetSetCcParams *p_FmPortGetSetCcParams); + + +/***********************************************************************/ +/* Common API for FM-PCD module */ +/***********************************************************************/ +t_Handle FmPcdGetHcHandle(t_Handle h_FmPcd); +uint32_t FmPcdGetSwPrsOffset(t_Handle h_FmPcd, e_NetHeaderType hdr, uint8_t indexPerHdr); +uint32_t FmPcdGetLcv(t_Handle h_FmPcd, uint32_t netEnvId, uint8_t hdrNum); +uint32_t FmPcdGetMacsecLcv(t_Handle h_FmPcd, uint32_t netEnvId); +void FmPcdIncNetEnvOwners(t_Handle h_FmPcd, uint8_t netEnvId); +void FmPcdDecNetEnvOwners(t_Handle h_FmPcd, uint8_t netEnvId); +uint8_t FmPcdGetNetEnvId(t_Handle h_NetEnv); +void FmPcdPortRegister(t_Handle h_FmPcd, t_Handle h_FmPort, uint8_t hardwarePortId); +uint32_t FmPcdLock(t_Handle h_FmPcd); +void FmPcdUnlock(t_Handle h_FmPcd, uint32_t intFlags); +bool FmPcdNetEnvIsHdrExist(t_Handle h_FmPcd, uint8_t netEnvId, e_NetHeaderType hdr); +t_Error FmPcdFragHcScratchPoolInit(t_Handle h_FmPcd, uint8_t scratchBpid); +t_Error FmPcdRegisterReassmPort(t_Handle h_FmPcd, t_Handle h_IpReasmCommonPramTbl); +t_Error FmPcdUnregisterReassmPort(t_Handle h_FmPcd, t_Handle h_IpReasmCommonPramTbl); +bool FmPcdIsAdvancedOffloadSupported(t_Handle h_FmPcd); +bool FmPcdLockTryLockAll(t_Handle h_FmPcd); +void FmPcdLockUnlockAll(t_Handle h_FmPcd); +t_Error FmPcdHcSync(t_Handle h_FmPcd); +t_Handle FmGetPcd(t_Handle h_Fm); +/***********************************************************************/ +/* Common API for FM-PCD KG module */ +/***********************************************************************/ +uint8_t FmPcdKgGetClsPlanGrpBase(t_Handle h_FmPcd, uint8_t clsPlanGrp); +uint16_t FmPcdKgGetClsPlanGrpSize(t_Handle h_FmPcd, uint8_t clsPlanGrp); +t_Error FmPcdKgBuildClsPlanGrp(t_Handle h_FmPcd, t_FmPcdKgInterModuleClsPlanGrpParams *p_Grp, t_FmPcdKgInterModuleClsPlanSet *p_ClsPlanSet); + +uint8_t FmPcdKgGetSchemeId(t_Handle h_Scheme); +#if (DPAA_VERSION >= 11) +bool FmPcdKgGetVspe(t_Handle h_Scheme); +#endif /* (DPAA_VERSION >= 11) */ +uint8_t FmPcdKgGetRelativeSchemeId(t_Handle h_FmPcd, uint8_t schemeId); +void FmPcdKgDestroyClsPlanGrp(t_Handle h_FmPcd, uint8_t grpId); +t_Error FmPcdKgCheckInvalidateSchemeSw(t_Handle h_Scheme); +t_Error FmPcdKgBuildBindPortToSchemes(t_Handle h_FmPcd , t_FmPcdKgInterModuleBindPortToSchemes *p_BindPortToSchemes, uint32_t *p_SpReg, bool add); +bool FmPcdKgHwSchemeIsValid(uint32_t schemeModeReg); +uint32_t FmPcdKgBuildWriteSchemeActionReg(uint8_t schemeId, bool updateCounter); +uint32_t FmPcdKgBuildReadSchemeActionReg(uint8_t schemeId); +uint32_t FmPcdKgBuildWriteClsPlanBlockActionReg(uint8_t grpId); +uint32_t FmPcdKgBuildWritePortSchemeBindActionReg(uint8_t hardwarePortId); +uint32_t FmPcdKgBuildReadPortSchemeBindActionReg(uint8_t hardwarePortId); +uint32_t FmPcdKgBuildWritePortClsPlanBindActionReg(uint8_t hardwarePortId); +bool FmPcdKgIsSchemeValidSw(t_Handle h_Scheme); + +t_Error FmPcdKgBindPortToSchemes(t_Handle h_FmPcd , t_FmPcdKgInterModuleBindPortToSchemes *p_SchemeBind); +t_Error FmPcdKgUnbindPortToSchemes(t_Handle h_FmPcd , t_FmPcdKgInterModuleBindPortToSchemes *p_SchemeBind); +uint32_t FmPcdKgGetRequiredAction(t_Handle h_FmPcd, uint8_t schemeId); +uint32_t FmPcdKgGetRequiredActionFlag(t_Handle h_FmPcd, uint8_t schemeId); +e_FmPcdDoneAction FmPcdKgGetDoneAction(t_Handle h_FmPcd, uint8_t schemeId); +e_FmPcdEngine FmPcdKgGetNextEngine(t_Handle h_FmPcd, uint8_t schemeId); +void FmPcdKgUpdateRequiredAction(t_Handle h_Scheme, uint32_t requiredAction); +bool FmPcdKgIsDirectPlcr(t_Handle h_FmPcd, uint8_t schemeId); +bool FmPcdKgIsDistrOnPlcrProfile(t_Handle h_FmPcd, uint8_t schemeId); +uint16_t FmPcdKgGetRelativeProfileId(t_Handle h_FmPcd, uint8_t schemeId); +t_Handle FmPcdKgGetSchemeHandle(t_Handle h_FmPcd, uint8_t relativeSchemeId); +bool FmPcdKgIsSchemeHasOwners(t_Handle h_Scheme); +t_Error FmPcdKgCcGetSetParams(t_Handle h_FmPcd, t_Handle h_Scheme, uint32_t requiredAction, uint32_t value); +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_Error FmPcdKgDeleteOrUnbindPortToClsPlanGrp(t_Handle h_FmPcd, uint8_t hardwarePortId, uint8_t clsPlanGrpId); + +/***********************************************************************/ +/* Common API for FM-PCD parser module */ +/***********************************************************************/ +t_Error FmPcdPrsIncludePortInStatistics(t_Handle p_FmPcd, uint8_t hardwarePortId, bool include); + +/***********************************************************************/ +/* Common API for FM-PCD policer module */ +/***********************************************************************/ +t_Error FmPcdPlcrAllocProfiles(t_Handle h_FmPcd, uint8_t hardwarePortId, uint16_t numOfProfiles); +t_Error FmPcdPlcrFreeProfiles(t_Handle h_FmPcd, uint8_t hardwarePortId); +bool FmPcdPlcrIsProfileValid(t_Handle h_FmPcd, uint16_t absoluteProfileId); +uint16_t FmPcdPlcrGetPortProfilesBase(t_Handle h_FmPcd, uint8_t hardwarePortId); +uint16_t FmPcdPlcrGetPortNumOfProfiles(t_Handle h_FmPcd, uint8_t hardwarePortId); +uint32_t FmPcdPlcrBuildWritePlcrActionRegs(uint16_t absoluteProfileId); +uint32_t FmPcdPlcrBuildCounterProfileReg(e_FmPcdPlcrProfileCounters counter); +uint32_t FmPcdPlcrBuildWritePlcrActionReg(uint16_t absoluteProfileId); +uint32_t FmPcdPlcrBuildReadPlcrActionReg(uint16_t absoluteProfileId); +uint16_t FmPcdPlcrProfileGetAbsoluteId(t_Handle h_Profile); +t_Error FmPcdPlcrGetAbsoluteIdByProfileParams(t_Handle h_FmPcd, + e_FmPcdProfileTypeSelection profileType, + t_Handle h_FmPort, + uint16_t relativeProfile, + uint16_t *p_AbsoluteId); +void FmPcdPlcrInvalidateProfileSw(t_Handle h_FmPcd, uint16_t absoluteProfileId); +void FmPcdPlcrValidateProfileSw(t_Handle h_FmPcd, uint16_t absoluteProfileId); +bool FmPcdPlcrHwProfileIsValid(uint32_t profileModeReg); +uint32_t FmPcdPlcrGetRequiredAction(t_Handle h_FmPcd, uint16_t absoluteProfileId); +uint32_t FmPcdPlcrGetRequiredActionFlag(t_Handle h_FmPcd, uint16_t absoluteProfileId); +uint32_t FmPcdPlcrBuildNiaProfileReg(bool green, bool yellow, bool red); +void FmPcdPlcrUpdateRequiredAction(t_Handle h_FmPcd, uint16_t absoluteProfileId, uint32_t requiredAction); +t_Error FmPcdPlcrCcGetSetParams(t_Handle h_FmPcd, uint16_t profileIndx,uint32_t requiredAction); + +/***********************************************************************/ +/* Common API for FM-PCD CC module */ +/***********************************************************************/ +uint8_t FmPcdCcGetParseCode(t_Handle h_CcNode); +uint8_t FmPcdCcGetOffset(t_Handle h_CcNode); +t_Error FmPcdCcRemoveKey(t_Handle h_FmPcd, t_Handle h_FmPcdCcNode, uint16_t keyIndex); +t_Error FmPcdCcAddKey(t_Handle h_FmPcd, t_Handle h_CcNode, uint16_t keyIndex, uint8_t keySize, t_FmPcdCcKeyParams *p_FmPCdCcKeyParams); +t_Error FmPcdCcModifyKey(t_Handle h_FmPcd, t_Handle h_CcNode, uint16_t keyIndex, uint8_t keySize, uint8_t *p_Key, uint8_t *p_Mask); +t_Error FmPcdCcModifyKeyAndNextEngine(t_Handle h_FmPcd, t_Handle h_FmPcdCcNode, uint16_t keyIndex, uint8_t keySize, t_FmPcdCcKeyParams *p_FmPcdCcKeyParams); +t_Error FmPcdCcModifyMissNextEngineParamNode(t_Handle h_FmPcd,t_Handle h_FmPcdCcNode, t_FmPcdCcNextEngineParams *p_FmPcdCcNextEngineParams); +t_Error FmPcdCcModifyNextEngineParamTree(t_Handle h_FmPcd, t_Handle h_FmPcdCcTree, uint8_t grpId, uint8_t index, t_FmPcdCcNextEngineParams *p_FmPcdCcNextEngineParams); +uint32_t FmPcdCcGetNodeAddrOffsetFromNodeInfo(t_Handle h_FmPcd, t_Handle h_Pointer); +t_Handle FmPcdCcTreeGetSavedManipParams(t_Handle h_FmTree); +void FmPcdCcTreeSetSavedManipParams(t_Handle h_FmTree, t_Handle h_SavedManipParams); +t_Error FmPcdCcTreeAddIPR(t_Handle h_FmPcd, t_Handle h_FmTree, t_Handle h_NetEnv, t_Handle h_ReassemblyManip, bool schemes); +t_Error FmPcdCcTreeAddCPR(t_Handle h_FmPcd, t_Handle h_FmTree, t_Handle h_NetEnv, t_Handle h_ReassemblyManip, bool schemes); +t_Error FmPcdCcBindTree(t_Handle h_FmPcd, t_Handle h_PcdParams, t_Handle h_CcTree, uint32_t *p_Offset,t_Handle h_FmPort); +t_Error FmPcdCcUnbindTree(t_Handle h_FmPcd, t_Handle h_CcTree); + +/***********************************************************************/ +/* Common API for FM-PCD Manip module */ +/***********************************************************************/ +t_Error FmPcdManipUpdate(t_Handle h_FmPcd, t_Handle h_PcdParams, t_Handle h_FmPort, t_Handle h_Manip, t_Handle h_Ad, bool validate, int level, t_Handle h_FmTree, bool modify); + +/***********************************************************************/ +/* Common API for FM-Port module */ +/***********************************************************************/ +#if (DPAA_VERSION >= 11) +typedef enum e_FmPortGprFuncType +{ + e_FM_PORT_GPR_EMPTY = 0, + e_FM_PORT_GPR_MURAM_PAGE +} e_FmPortGprFuncType; + +t_Error FmPortSetGprFunc(t_Handle h_FmPort, e_FmPortGprFuncType gprFunc, void **p_Value); +#endif /* DPAA_VERSION >= 11) */ +t_Error FmGetSetParams(t_Handle h_Fm, t_FmGetSetParams *p_FmGetSetParams); +t_Error FmPortGetSetCcParams(t_Handle h_FmPort, t_FmPortGetSetCcParams *p_FmPortGetSetCcParams); +uint8_t FmPortGetNetEnvId(t_Handle h_FmPort); +uint8_t FmPortGetHardwarePortId(t_Handle h_FmPort); +uint32_t FmPortGetPcdEngines(t_Handle h_FmPort); +void FmPortPcdKgSwUnbindClsPlanGrp (t_Handle h_FmPort); + + +#if (DPAA_VERSION >= 11) +t_Error FmPcdFrmReplicUpdate(t_Handle h_FmPcd, t_Handle h_FmPort, t_Handle h_FrmReplic); +#endif /* (DPAA_VERSION >= 11) */ + +/**************************************************************************//** + @Function FmRegisterIntr + + @Description Used to register an inter-module event handler to be processed by FM + + @Param[in] h_Fm A handle to an FM Module. + @Param[in] mod The module that causes the event + @Param[in] modId Module id - if more than 1 instansiation of this + mode exists,0 otherwise. + @Param[in] intrType Interrupt type (error/normal) selection. + @Param[in] f_Isr The interrupt service routine. + @Param[in] h_Arg Argument to be passed to f_Isr. + + @Return None. +*//***************************************************************************/ +void FmRegisterIntr(t_Handle h_Fm, + e_FmEventModules mod, + uint8_t modId, + e_FmIntrType intrType, + void (*f_Isr) (t_Handle h_Arg), + t_Handle h_Arg); + +/**************************************************************************//** + @Function FmUnregisterIntr + + @Description Used to un-register an inter-module event handler that was processed by FM + + @Param[in] h_Fm A handle to an FM Module. + @Param[in] mod The module that causes the event + @Param[in] modId Module id - if more than 1 instansiation of this + mode exists,0 otherwise. + @Param[in] intrType Interrupt type (error/normal) selection. + + @Return None. +*//***************************************************************************/ +void FmUnregisterIntr(t_Handle h_Fm, + e_FmEventModules mod, + uint8_t modId, + e_FmIntrType intrType); + +/**************************************************************************//** + @Function FmRegisterFmCtlIntr + + @Description Used to register to one of the fmCtl events in the FM module + + @Param[in] h_Fm A handle to an FM Module. + @Param[in] eventRegId FmCtl event id (0-7). + @Param[in] f_Isr The interrupt service routine. + + @Return E_OK on success; Error code otherwise. + + @Cautions Allowed only following FM_Init(). +*//***************************************************************************/ +void FmRegisterFmCtlIntr(t_Handle h_Fm, uint8_t eventRegId, void (*f_Isr) (t_Handle h_Fm, uint32_t event)); + + +/**************************************************************************//** + @Description enum for defining MAC types +*//***************************************************************************/ +typedef enum e_FmMacType { + e_FM_MAC_10G = 0, /**< 10G MAC */ + e_FM_MAC_1G /**< 1G MAC */ +} e_FmMacType; + +/**************************************************************************//** + @Description Structure for port-FM communication during FM_PORT_Init. + Fields commented 'IN' are passed by the port module to be used + by the FM module. + Fields commented 'OUT' will be filled by FM before returning to port. + Some fields are optional (depending on configuration) and + will be analized by the port and FM modules accordingly. +*//***************************************************************************/ +typedef struct t_FmInterModulePortInitParams { + uint8_t hardwarePortId; /**< IN. port Id */ + e_FmPortType portType; /**< IN. Port type */ + bool independentMode; /**< IN. TRUE if FM Port operates in independent mode */ + uint16_t liodnOffset; /**< IN. Port's requested resource */ + uint8_t numOfTasks; /**< IN. Port's requested resource */ + uint8_t numOfExtraTasks; /**< IN. Port's requested resource */ + uint8_t numOfOpenDmas; /**< IN. Port's requested resource */ + uint8_t numOfExtraOpenDmas; /**< IN. Port's requested resource */ + uint32_t sizeOfFifo; /**< IN. Port's requested resource */ + uint32_t extraSizeOfFifo; /**< IN. Port's requested resource */ + uint8_t deqPipelineDepth; /**< IN. Port's requested resource */ + uint16_t maxFrameLength; /**< IN. Port's max frame length. */ + uint16_t liodnBase; /**< IN. Irrelevant for P4080 rev 1. + LIODN base for this port, to be + used together with LIODN offset. */ + t_FmPhysAddr fmMuramPhysBaseAddr;/**< OUT. FM-MURAM physical address*/ +} t_FmInterModulePortInitParams; + +/**************************************************************************//** + @Description Structure for port-FM communication during FM_PORT_Free. +*//***************************************************************************/ +typedef struct t_FmInterModulePortFreeParams { + uint8_t hardwarePortId; /**< IN. port Id */ + e_FmPortType portType; /**< IN. Port type */ + uint8_t deqPipelineDepth; /**< IN. Port's requested resource */ +} t_FmInterModulePortFreeParams; + +/**************************************************************************//** + @Function FmGetPcdPrsBaseAddr + + @Description Get the base address of the Parser from the FM module + + @Param[in] h_Fm A handle to an FM Module. + + @Return Base address. +*//***************************************************************************/ +uintptr_t FmGetPcdPrsBaseAddr(t_Handle h_Fm); + +/**************************************************************************//** + @Function FmGetPcdKgBaseAddr + + @Description Get the base address of the Keygen from the FM module + + @Param[in] h_Fm A handle to an FM Module. + + @Return Base address. +*//***************************************************************************/ +uintptr_t FmGetPcdKgBaseAddr(t_Handle h_Fm); + +/**************************************************************************//** + @Function FmGetPcdPlcrBaseAddr + + @Description Get the base address of the Policer from the FM module + + @Param[in] h_Fm A handle to an FM Module. + + @Return Base address. +*//***************************************************************************/ +uintptr_t FmGetPcdPlcrBaseAddr(t_Handle h_Fm); + +/**************************************************************************//** + @Function FmGetMuramHandle + + @Description Get the handle of the MURAM from the FM module + + @Param[in] h_Fm A handle to an FM Module. + + @Return MURAM module handle. +*//***************************************************************************/ +t_Handle FmGetMuramHandle(t_Handle h_Fm); + +/**************************************************************************//** + @Function FmGetPhysicalMuramBase + + @Description Get the physical base address of the MURAM from the FM module + + @Param[in] h_Fm A handle to an FM Module. + @Param[in] fmPhysAddr Physical MURAM base + + @Return Physical base address. +*//***************************************************************************/ +void FmGetPhysicalMuramBase(t_Handle h_Fm, t_FmPhysAddr *fmPhysAddr); + +/**************************************************************************//** + @Function FmGetTimeStampScale + + @Description Used internally by other modules in order to get the timeStamp + period as requested by the application. + + This function returns bit number that is incremented every 1 usec. + To calculate timestamp period in nsec, use + 1000 / (1 << FmGetTimeStampScale()). + + @Param[in] h_Fm A handle to an FM Module. + + @Return Bit that counts 1 usec. + + @Cautions Allowed only following FM_Init(). +*//***************************************************************************/ +uint32_t FmGetTimeStampScale(t_Handle h_Fm); + +/**************************************************************************//** + @Function FmResumeStalledPort + + @Description Used internally by FM port to release a stalled port. + + @Param[in] h_Fm A handle to an FM Module. + @Param[in] hardwarePortId HW port id. + + @Return E_OK on success; Error code otherwise. + + @Cautions Allowed only following FM_Init(). +*//***************************************************************************/ +t_Error FmResumeStalledPort(t_Handle h_Fm, uint8_t hardwarePortId); + +/**************************************************************************//** + @Function FmIsPortStalled + + @Description Used internally by FM port to read the port's status. + + @Param[in] h_Fm A handle to an FM Module. + @Param[in] hardwarePortId HW port id. + @Param[in] p_IsStalled A pointer to the boolean port stalled state + + @Return E_OK on success; Error code otherwise. + + @Cautions Allowed only following FM_Init(). +*//***************************************************************************/ +t_Error FmIsPortStalled(t_Handle h_Fm, uint8_t hardwarePortId, bool *p_IsStalled); + +/**************************************************************************//** + @Function FmResetMac + + @Description Used by MAC driver to reset the MAC registers + + @Param[in] h_Fm A handle to an FM Module. + @Param[in] type MAC type. + @Param[in] macId MAC id - according to type. + + @Return E_OK on success; Error code otherwise. + + @Cautions Allowed only following FM_Init(). +*//***************************************************************************/ +t_Error FmResetMac(t_Handle h_Fm, e_FmMacType type, uint8_t macId); + +/**************************************************************************//** + @Function FmGetClockFreq + + @Description Used by MAC driver to get the FM clock frequency + + @Param[in] h_Fm A handle to an FM Module. + + @Return clock-freq on success; 0 otherwise. + + @Cautions Allowed only following FM_Init(). +*//***************************************************************************/ +uint16_t FmGetClockFreq(t_Handle h_Fm); + +/**************************************************************************//** + @Function FmGetMacClockFreq + + @Description Used by MAC driver to get the MAC clock frequency + + @Param[in] h_Fm A handle to an FM Module. + + @Return clock-freq on success; 0 otherwise. + + @Cautions Allowed only following FM_Init(). +*//***************************************************************************/ +uint16_t FmGetMacClockFreq(t_Handle h_Fm); + +/**************************************************************************//** + @Function FmGetId + + @Description Used by PCD driver to read rhe FM id + + @Param[in] h_Fm A handle to an FM Module. + + @Return E_OK on success; Error code otherwise. + + @Cautions Allowed only following FM_Init(). +*//***************************************************************************/ +uint8_t FmGetId(t_Handle h_Fm); + +/**************************************************************************//** + @Function FmReset + + @Description Used to reset the FM + + @Param[in] h_Fm A handle to an FM Module. + + @Return E_OK on success; Error code otherwise. +*//***************************************************************************/ +t_Error FmReset(t_Handle h_Fm); + +/**************************************************************************//** + @Function FmGetSetPortParams + + @Description Used by FM-PORT driver to pass and receive parameters between + PORT and FM modules. + + @Param[in] h_Fm A handle to an FM Module. + @Param[in,out] p_PortParams A structure of FM Port parameters. + + @Return E_OK on success; Error code otherwise. + + @Cautions Allowed only following FM_Init(). +*//***************************************************************************/ +t_Error FmGetSetPortParams(t_Handle h_Fm,t_FmInterModulePortInitParams *p_PortParams); + +/**************************************************************************//** + @Function FmFreePortParams + + @Description Used by FM-PORT driver to free port's resources within the FM. + + @Param[in] h_Fm A handle to an FM Module. + @Param[in,out] p_PortParams A structure of FM Port parameters. + + @Return None. + + @Cautions Allowed only following FM_Init(). +*//***************************************************************************/ +void FmFreePortParams(t_Handle h_Fm,t_FmInterModulePortFreeParams *p_PortParams); + +/**************************************************************************//** + @Function FmSetNumOfRiscsPerPort + + @Description Used by FM-PORT driver to pass parameter between + PORT and FM modules for working with number of RISC.. + + @Param[in] h_Fm A handle to an FM Module. + @Param[in] hardwarePortId hardware port Id. + @Param[in] numOfFmanCtrls number of Fman Controllers. + @Param[in] orFmanCtrl Fman Controller for order restoration. + + @Return None. + + @Cautions Allowed only following FM_Init(). +*//***************************************************************************/ +t_Error FmSetNumOfRiscsPerPort(t_Handle h_Fm, uint8_t hardwarePortId, uint8_t numOfFmanCtrls, t_FmFmanCtrl orFmanCtrl); + +#if (defined(DEBUG_ERRORS) && (DEBUG_ERRORS > 0)) +/**************************************************************************//* + @Function FmDumpPortRegs + + @Description Dumps FM port registers which are part of FM common registers + + @Param[in] h_Fm A handle to an FM Module. + @Param[in] hardwarePortId HW port id. + + @Return E_OK on success; Error code otherwise. + + @Cautions Allowed only FM_Init(). +*//***************************************************************************/ +t_Error FmDumpPortRegs(t_Handle h_Fm,uint8_t hardwarePortId); +#endif /* (defined(DEBUG_ERRORS) && ... */ + +void FmRegisterPcd(t_Handle h_Fm, t_Handle h_FmPcd); +void FmUnregisterPcd(t_Handle h_Fm); +t_Handle FmGetPcdHandle(t_Handle h_Fm); +t_Error FmEnableRamsEcc(t_Handle h_Fm); +t_Error FmDisableRamsEcc(t_Handle h_Fm); +void FmGetRevision(t_Handle h_Fm, t_FmRevisionInfo *p_FmRevisionInfo); +t_Error FmAllocFmanCtrlEventReg(t_Handle h_Fm, uint8_t *p_EventId); +void FmFreeFmanCtrlEventReg(t_Handle h_Fm, uint8_t eventId); +void FmSetFmanCtrlIntr(t_Handle h_Fm, uint8_t eventRegId, uint32_t enableEvents); +uint32_t FmGetFmanCtrlIntr(t_Handle h_Fm, uint8_t eventRegId); +void FmRegisterFmanCtrlIntr(t_Handle h_Fm, uint8_t eventRegId, void (*f_Isr) (t_Handle h_Fm, uint32_t event), t_Handle h_Arg); +void FmUnregisterFmanCtrlIntr(t_Handle h_Fm, uint8_t eventRegId); +t_Error FmSetMacMaxFrame(t_Handle h_Fm, e_FmMacType type, uint8_t macId, uint16_t mtu); +bool FmIsMaster(t_Handle h_Fm); +uint8_t FmGetGuestId(t_Handle h_Fm); +uint16_t FmGetTnumAgingPeriod(t_Handle h_Fm); +t_Error FmSetPortPreFetchConfiguration(t_Handle h_Fm, uint8_t portNum, bool preFetchConfigured); +t_Error FmGetPortPreFetchConfiguration(t_Handle h_Fm, uint8_t portNum, bool *p_PortConfigured, bool *p_PreFetchConfigured); + + +#ifdef FM_TX_ECC_FRMS_ERRATA_10GMAC_A004 +t_Error Fm10GTxEccWorkaround(t_Handle h_Fm, uint8_t macId); +#endif /* FM_TX_ECC_FRMS_ERRATA_10GMAC_A004 */ + +void FmMuramClear(t_Handle h_FmMuram); +t_Error FmSetNumOfOpenDmas(t_Handle h_Fm, + uint8_t hardwarePortId, + uint8_t *p_NumOfOpenDmas, + uint8_t *p_NumOfExtraOpenDmas, + bool initialConfig); +t_Error FmSetNumOfTasks(t_Handle h_Fm, + uint8_t hardwarePortId, + uint8_t *p_NumOfTasks, + uint8_t *p_NumOfExtraTasks, + bool initialConfig); +t_Error FmSetSizeOfFifo(t_Handle h_Fm, + uint8_t hardwarePortId, + uint32_t *p_SizeOfFifo, + uint32_t *p_ExtraSizeOfFifo, + bool initialConfig); + +t_Error FmSetCongestionGroupPFCpriority(t_Handle h_Fm, + uint32_t congestionGroupId, + uint8_t priorityBitMap); + +#if (DPAA_VERSION >= 11) +t_Error FmVSPAllocForPort(t_Handle h_Fm, + e_FmPortType portType, + uint8_t portId, + uint8_t numOfStorageProfiles); + +t_Error FmVSPFreeForPort(t_Handle h_Fm, + e_FmPortType portType, + uint8_t portId); + +t_Error FmVSPGetAbsoluteProfileId(t_Handle h_Fm, + e_FmPortType portType, + uint8_t portId, + uint16_t relativeProfile, + uint16_t *p_AbsoluteId); +t_Error FmVSPCheckRelativeProfile(t_Handle h_Fm, + e_FmPortType portType, + uint8_t portId, + uint16_t relativeProfile); + +uintptr_t FmGetVSPBaseAddr(t_Handle h_Fm); +#endif /* (DPAA_VERSION >= 11) */ + + +#endif /* __FM_COMMON_H */ diff --git a/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/inc/fm_hc.h b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/inc/fm_hc.h new file mode 100644 index 000000000000..492aa8a3aa78 --- /dev/null +++ b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/inc/fm_hc.h @@ -0,0 +1,93 @@ +/* + * Copyright 2008-2012 Freescale Semiconductor Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Freescale Semiconductor nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * + * ALTERNATIVELY, this software may be distributed under the terms of the + * GNU General Public License ("GPL") as published by the Free Software + * Foundation, either version 2 of that License or (at your option) any + * later version. + * + * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + +#ifndef __FM_HC_H +#define __FM_HC_H + +#include "std_ext.h" +#include "error_ext.h" +#include "fsl_fman_kg.h" + +#define __ERR_MODULE__ MODULE_FM_PCD + + +typedef struct t_FmHcParams { + t_Handle h_Fm; + t_Handle h_FmPcd; + t_FmPcdHcParams params; +} t_FmHcParams; + + +t_Handle FmHcConfigAndInit(t_FmHcParams *p_FmHcParams); +void FmHcFree(t_Handle h_FmHc); +t_Error FmHcSetFramesDataMemory(t_Handle h_FmHc, + uint8_t memId); +t_Error FmHcDumpRegs(t_Handle h_FmHc); + +void FmHcTxConf(t_Handle h_FmHc, t_DpaaFD *p_Fd); + +t_Error FmHcPcdKgSetScheme(t_Handle h_FmHc, + t_Handle h_Scheme, + struct fman_kg_scheme_regs *p_SchemeRegs, + bool updateCounter); +t_Error FmHcPcdKgDeleteScheme(t_Handle h_FmHc, t_Handle h_Scheme); +t_Error FmHcPcdCcCapwapTimeoutReassm(t_Handle h_FmHc, t_FmPcdCcCapwapReassmTimeoutParams *p_CcCapwapReassmTimeoutParams ); +t_Error FmHcPcdCcIpFragScratchPollCmd(t_Handle h_FmHc, bool fill, t_FmPcdCcFragScratchPoolCmdParams *p_FmPcdCcFragScratchPoolCmdParams); +t_Error FmHcPcdCcTimeoutReassm(t_Handle h_FmHc, t_FmPcdCcReassmTimeoutParams *p_CcReassmTimeoutParams, uint8_t *p_Result); +t_Error FmHcPcdKgSetClsPlan(t_Handle h_FmHc, t_FmPcdKgInterModuleClsPlanSet *p_Set); +t_Error FmHcPcdKgDeleteClsPlan(t_Handle h_FmHc, uint8_t clsPlanGrpId); + +t_Error FmHcPcdKgSetSchemeCounter(t_Handle h_FmHc, t_Handle h_Scheme, uint32_t value); +uint32_t FmHcPcdKgGetSchemeCounter(t_Handle h_FmHc, t_Handle h_Scheme); + +t_Error FmHcPcdCcDoDynamicChange(t_Handle h_FmHc, uint32_t oldAdAddrOffset, uint32_t newAdAddrOffset); + +t_Error FmHcPcdPlcrSetProfile(t_Handle h_FmHc, t_Handle h_Profile, t_FmPcdPlcrProfileRegs *p_PlcrRegs); +t_Error FmHcPcdPlcrDeleteProfile(t_Handle h_FmHc, t_Handle h_Profile); + +t_Error FmHcPcdPlcrSetProfileCounter(t_Handle h_FmHc, t_Handle h_Profile, e_FmPcdPlcrProfileCounters counter, uint32_t value); +uint32_t FmHcPcdPlcrGetProfileCounter(t_Handle h_FmHc, t_Handle h_Profile, e_FmPcdPlcrProfileCounters counter); + +t_Error FmHcKgWriteSp(t_Handle h_FmHc, uint8_t hardwarePortId, uint32_t spReg, bool add); +t_Error FmHcKgWriteCpp(t_Handle h_FmHc, uint8_t hardwarePortId, uint32_t cppReg); + +t_Error FmHcPcdKgCcGetSetParams(t_Handle h_FmHc, t_Handle h_Scheme, uint32_t requiredAction, uint32_t value); +t_Error FmHcPcdPlcrCcGetSetParams(t_Handle h_FmHc,uint16_t absoluteProfileId, uint32_t requiredAction); + +t_Error FmHcPcdSync(t_Handle h_FmHc); +t_Handle FmHcGetPort(t_Handle h_FmHc); + + + + +#endif /* __FM_HC_H */ diff --git a/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/inc/fm_sp_common.h b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/inc/fm_sp_common.h new file mode 100644 index 000000000000..f9dd384bb685 --- /dev/null +++ b/drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/inc/fm_sp_common.h @@ -0,0 +1,117 @@ +/* + * Copyright 2008-2012 Freescale Semiconductor Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Freescale Semiconductor nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * + * ALTERNATIVELY, this software may be distributed under the terms of the + * GNU General Public License ("GPL") as published by the Free Software + * Foundation, either version 2 of that License or (at your option) any + * later version. + * + * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + +/****************************************************************************** + @File fm_sp_common.h + + @Description FM SP ... +*//***************************************************************************/ +#ifndef __FM_SP_COMMON_H +#define __FM_SP_COMMON_H + +#include "std_ext.h" +#include "error_ext.h" +#include "list_ext.h" + +#include "fm_ext.h" +#include "fm_pcd_ext.h" +#include "fsl_fman.h" + +/**************************************************************************//** + @Description defaults +*//***************************************************************************/ +#define DEFAULT_FM_SP_bufferPrefixContent_privDataSize 0 +#define DEFAULT_FM_SP_bufferPrefixContent_passPrsResult FALSE +#define DEFAULT_FM_SP_bufferPrefixContent_passTimeStamp FALSE +#define DEFAULT_FM_SP_bufferPrefixContent_allOtherPCDInfo FALSE +#define DEFAULT_FM_SP_bufferPrefixContent_dataAlign 64 + +/**************************************************************************//** + @Description structure for defining internal context copying +*//***************************************************************************/ +typedef struct +{ + uint16_t extBufOffset; /**< Offset in External buffer to which internal + context is copied to (Rx) or taken from (Tx, Op). */ + uint8_t intContextOffset; /**< Offset within internal context to copy from + (Rx) or to copy to (Tx, Op). */ + uint16_t size; /**< Internal offset size to be copied */ +} t_FmSpIntContextDataCopy; + +/**************************************************************************//** + @Description struct for defining external buffer margins +*//***************************************************************************/ +typedef struct { + uint16_t startMargins; /**< Number of bytes to be left at the beginning + of the external buffer (must be divisible by 16) */ + uint16_t endMargins; /**< number of bytes to be left at the end + of the external buffer(must be divisible by 16) */ +} t_FmSpBufMargins; + +typedef struct { + uint32_t dataOffset; + uint32_t prsResultOffset; + uint32_t timeStampOffset; + uint32_t hashResultOffset; + uint32_t pcdInfoOffset; + uint32_t manipOffset; +} t_FmSpBufferOffsets; + + +t_Error FmSpBuildBufferStructure(t_FmSpIntContextDataCopy *p_FmPortIntContextDataCopy, + t_FmBufferPrefixContent *p_BufferPrefixContent, + t_FmSpBufMargins *p_FmPortBufMargins, + t_FmSpBufferOffsets *p_FmPortBufferOffsets, + uint8_t *internalBufferOffset); + +t_Error FmSpCheckIntContextParams(t_FmSpIntContextDataCopy *p_FmSpIntContextDataCopy); +t_Error FmSpCheckBufPoolsParams(t_FmExtPools *p_FmExtPools, + t_FmBackupBmPools *p_FmBackupBmPools, + t_FmBufPoolDepletion *p_FmBufPoolDepletion); +t_Error FmSpCheckBufMargins(t_FmSpBufMargins *p_FmSpBufMargins); +void FmSpSetBufPoolsInAscOrderOfBufSizes(t_FmExtPools *p_FmExtPools, uint8_t *orderedArray, uint16_t *sizesArray); + +t_Error FmPcdSpAllocProfiles(t_Handle h_FmPcd, + uint8_t hardwarePortId, + uint16_t numOfStorageProfiles, + uint16_t *base, + uint8_t *log2Num); +t_Error FmPcdSpGetAbsoluteProfileId(t_Handle h_FmPcd, + t_Handle h_FmPort, + uint16_t relativeProfile, + uint16_t *p_AbsoluteId); +void SpInvalidateProfileSw(t_Handle h_FmPcd, uint16_t absoluteProfileId); +void SpValidateProfileSw(t_Handle h_FmPcd, uint16_t absoluteProfileId); + + +#endif /* __FM_SP_COMMON_H */ |