mirror of https://github.com/F-Stack/f-stack.git
1848 lines
72 KiB
C
1848 lines
72 KiB
C
/*
|
|
* 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 = (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 = (((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;
|
|
}
|