diff options
Diffstat (limited to 'drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Pcd/fm_plcr.c')
-rw-r--r-- | drivers/net/ethernet/freescale/sdk_fman/Peripherals/FM/Pcd/fm_plcr.c | 1847 |
1 files changed, 1847 insertions, 0 deletions
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 0000000..e375330 --- /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; +} |