/********************************************************************************
|
Copyright (C) 2016 Marvell International Ltd.
|
|
SPDX-License-Identifier: BSD-2-Clause-Patent
|
|
*******************************************************************************/
|
|
#include "Mvpp2Lib.h"
|
#include "Mvpp2LibHw.h"
|
#include "Pp2Dxe.h"
|
|
/* Parser configuration routines */
|
|
/* Update parser Tcam and Sram hw entries */
|
STATIC
|
INT32
|
Mvpp2PrsHwWrite (
|
IN MVPP2_SHARED *Priv,
|
IN OUT MVPP2_PRS_ENTRY *Pe
|
)
|
{
|
INT32 i;
|
|
if (Pe->Index > MVPP2_PRS_TCAM_SRAM_SIZE - 1) {
|
return MVPP2_EINVAL;
|
}
|
|
/* Clear entry invalidation bit */
|
Pe->Tcam.Word[MVPP2_PRS_TCAM_INV_WORD] &= ~MVPP2_PRS_TCAM_INV_MASK;
|
|
/* Write Tcam Index - indirect access */
|
Mvpp2Write (Priv, MVPP2_PRS_TCAM_IDX_REG, Pe->Index);
|
for (i = 0; i < MVPP2_PRS_TCAM_WORDS; i++) {
|
Mvpp2Write (Priv, MVPP2_PRS_TCAM_DATA_REG(i), Pe->Tcam.Word[i]);
|
}
|
|
/* Write Sram Index - indirect access */
|
Mvpp2Write (Priv, MVPP2_PRS_SRAM_IDX_REG, Pe->Index);
|
for (i = 0; i < MVPP2_PRS_SRAM_WORDS; i++) {
|
Mvpp2Write (Priv, MVPP2_PRS_SRAM_DATA_REG(i), Pe->Sram.Word[i]);
|
}
|
|
return 0;
|
}
|
|
/* Read Tcam entry from hw */
|
STATIC
|
INT32
|
Mvpp2PrsHwRead (
|
IN MVPP2_SHARED *Priv,
|
IN OUT MVPP2_PRS_ENTRY *Pe
|
)
|
{
|
INT32 i;
|
|
if (Pe->Index > MVPP2_PRS_TCAM_SRAM_SIZE - 1) {
|
return MVPP2_EINVAL;
|
}
|
|
/* Write Tcam Index - indirect access */
|
Mvpp2Write (Priv, MVPP2_PRS_TCAM_IDX_REG, Pe->Index);
|
|
Pe->Tcam.Word[MVPP2_PRS_TCAM_INV_WORD] =
|
Mvpp2Read (Priv, MVPP2_PRS_TCAM_DATA_REG(MVPP2_PRS_TCAM_INV_WORD));
|
if (Pe->Tcam.Word[MVPP2_PRS_TCAM_INV_WORD] & MVPP2_PRS_TCAM_INV_MASK) {
|
return MVPP2_PRS_TCAM_ENTRY_INVALID;
|
}
|
|
for (i = 0; i < MVPP2_PRS_TCAM_WORDS; i++) {
|
Pe->Tcam.Word[i] = Mvpp2Read (Priv, MVPP2_PRS_TCAM_DATA_REG(i));
|
}
|
|
/* Write Sram Index - indirect access */
|
Mvpp2Write (Priv, MVPP2_PRS_SRAM_IDX_REG, Pe->Index);
|
for (i = 0; i < MVPP2_PRS_SRAM_WORDS; i++) {
|
Pe->Sram.Word[i] = Mvpp2Read (Priv, MVPP2_PRS_SRAM_DATA_REG(i));
|
}
|
|
return 0;
|
}
|
|
/* Invalidate Tcam hw entry */
|
STATIC
|
VOID
|
Mvpp2PrsHwInv (
|
IN MVPP2_SHARED *Priv,
|
IN INT32 Index
|
)
|
{
|
/* Write Index - indirect access */
|
Mvpp2Write (Priv, MVPP2_PRS_TCAM_IDX_REG, Index);
|
Mvpp2Write (Priv, MVPP2_PRS_TCAM_DATA_REG(MVPP2_PRS_TCAM_INV_WORD),
|
MVPP2_PRS_TCAM_INV_MASK);
|
}
|
|
/* Enable shadow table entry and set its lookup ID */
|
STATIC
|
VOID
|
Mvpp2PrsShadowSet (
|
IN MVPP2_SHARED *Priv,
|
IN INT32 Index,
|
IN INT32 Lu
|
)
|
{
|
Priv->PrsShadow[Index].Valid = TRUE;
|
Priv->PrsShadow[Index].Lu = Lu;
|
}
|
|
/* Update Ri fields in shadow table entry */
|
STATIC
|
VOID
|
Mvpp2PrsShadowRiSet (
|
IN MVPP2_SHARED *Priv,
|
IN INT32 Index,
|
IN UINT32 Ri,
|
IN UINT32 RiMask
|
)
|
{
|
Priv->PrsShadow[Index].RiMask = RiMask;
|
Priv->PrsShadow[Index].Ri = Ri;
|
}
|
|
/* Update lookup field in Tcam sw entry */
|
STATIC
|
VOID
|
Mvpp2PrsTcamLuSet (
|
IN OUT MVPP2_PRS_ENTRY *Pe,
|
IN UINT32 Lu
|
)
|
{
|
INT32 EnableOff = MVPP2_PRS_TCAM_EN_OFFS (MVPP2_PRS_TCAM_LU_BYTE);
|
|
Pe->Tcam.Byte[MVPP2_PRS_TCAM_LU_BYTE] = Lu;
|
Pe->Tcam.Byte[EnableOff] = MVPP2_PRS_LU_MASK;
|
}
|
|
/* Update Mask for single Port in Tcam sw entry */
|
STATIC
|
VOID
|
Mvpp2PrsTcamPortSet (
|
IN OUT MVPP2_PRS_ENTRY *Pe,
|
IN UINT32 PortId,
|
IN BOOLEAN Add
|
)
|
{
|
INT32 EnableOff = MVPP2_PRS_TCAM_EN_OFFS (MVPP2_PRS_TCAM_PORT_BYTE);
|
|
if (Add) {
|
Pe->Tcam.Byte[EnableOff] &= ~(1 << PortId);
|
} else {
|
Pe->Tcam.Byte[EnableOff] |= 1 << PortId;
|
}
|
}
|
|
/* Update Port map in Tcam sw entry */
|
STATIC
|
VOID
|
Mvpp2PrsTcamPortMapSet (
|
IN OUT MVPP2_PRS_ENTRY *Pe,
|
IN UINT32 PortMask
|
)
|
{
|
INT32 EnableOff = MVPP2_PRS_TCAM_EN_OFFS (MVPP2_PRS_TCAM_PORT_BYTE);
|
UINT8 Mask = MVPP2_PRS_PORT_MASK;
|
|
Pe->Tcam.Byte[MVPP2_PRS_TCAM_PORT_BYTE] = 0;
|
Pe->Tcam.Byte[EnableOff] &= ~Mask;
|
Pe->Tcam.Byte[EnableOff] |= ~PortMask & MVPP2_PRS_PORT_MASK;
|
}
|
|
/* Obtain Port map from Tcam sw entry */
|
STATIC
|
UINT32
|
Mvpp2PrsTcamPortMapGet (
|
IN MVPP2_PRS_ENTRY *Pe
|
)
|
{
|
INT32 EnableOff = MVPP2_PRS_TCAM_EN_OFFS (MVPP2_PRS_TCAM_PORT_BYTE);
|
|
return ~(Pe->Tcam.Byte[EnableOff]) & MVPP2_PRS_PORT_MASK;
|
}
|
|
/* Set Byte of data and its enable bits in Tcam sw entry */
|
STATIC
|
VOID
|
Mvpp2PrsTcamDataByteSet (
|
IN OUT MVPP2_PRS_ENTRY *Pe,
|
IN UINT32 Offs,
|
IN UINT8 Byte,
|
IN UINT8 Enable
|
)
|
{
|
Pe->Tcam.Byte[MVPP2_PRS_TCAM_DATA_BYTE(Offs)] = Byte;
|
Pe->Tcam.Byte[MVPP2_PRS_TCAM_DATA_BYTE_EN(Offs)] = Enable;
|
}
|
|
/* Get Byte of data and its enable bits from Tcam sw entry */
|
STATIC
|
VOID
|
Mvpp2PrsTcamDataByteGet (
|
IN MVPP2_PRS_ENTRY *Pe,
|
IN UINT32 Offs,
|
OUT UINT8 *Byte,
|
OUT UINT8 *Enable
|
)
|
{
|
*Byte = Pe->Tcam.Byte[MVPP2_PRS_TCAM_DATA_BYTE(Offs)];
|
*Enable = Pe->Tcam.Byte[MVPP2_PRS_TCAM_DATA_BYTE_EN(Offs)];
|
}
|
|
/* Compare Tcam data bytes with a pattern */
|
STATIC
|
BOOLEAN
|
Mvpp2PrsTcamDataCmp (
|
IN MVPP2_PRS_ENTRY *Pe,
|
IN INT32 Offset,
|
IN UINT16 Data
|
)
|
{
|
INT32 ByteOffset = MVPP2_PRS_TCAM_DATA_BYTE(Offset);
|
UINT16 TcamData;
|
|
TcamData = (Pe->Tcam.Byte[ByteOffset + 1] << 8) | Pe->Tcam.Byte[ByteOffset];
|
if (TcamData != Data) {
|
return FALSE;
|
}
|
|
return TRUE;
|
}
|
|
/* Update ai bits in Tcam sw entry */
|
STATIC
|
VOID
|
Mvpp2PrsTcamAiUpdate (
|
IN OUT MVPP2_PRS_ENTRY *Pe,
|
IN UINT32 Bits,
|
IN UINT32 Enable
|
)
|
{
|
INT32 i, AiIdx = MVPP2_PRS_TCAM_AI_BYTE;
|
|
for (i = 0; i < MVPP2_PRS_AI_BITS; i++) {
|
|
if (!(Enable & BIT (i))) {
|
continue;
|
}
|
|
if (Bits & BIT (i)) {
|
Pe->Tcam.Byte[AiIdx] |= 1 << i;
|
} else {
|
Pe->Tcam.Byte[AiIdx] &= ~(1 << i);
|
}
|
}
|
|
Pe->Tcam.Byte[MVPP2_PRS_TCAM_EN_OFFS (AiIdx)] |= Enable;
|
}
|
|
/* Get ai bits from Tcam sw entry */
|
STATIC
|
INT32
|
Mvpp2PrsTcamAiGet (
|
IN MVPP2_PRS_ENTRY *Pe
|
)
|
{
|
return Pe->Tcam.Byte[MVPP2_PRS_TCAM_AI_BYTE];
|
}
|
|
/* Get word of data and its enable bits from Tcam sw entry */
|
STATIC
|
VOID
|
Mvpp2PrsTcamDataWordGet (
|
IN MVPP2_PRS_ENTRY *Pe,
|
IN UINT32 DataOffset,
|
OUT UINT32 *Word,
|
OUT UINT32 *Enable
|
)
|
{
|
INT32 Index, Position;
|
UINT8 Byte, Mask;
|
|
for (Index = 0; Index < 4; Index++) {
|
Position = (DataOffset * sizeof (INT32)) + Index;
|
Mvpp2PrsTcamDataByteGet (Pe, Position, &Byte, &Mask);
|
((UINT8 *)Word)[Index] = Byte;
|
((UINT8 *)Enable)[Index] = Mask;
|
}
|
}
|
|
/* Set ethertype in Tcam sw entry */
|
STATIC
|
VOID
|
Mvpp2PrsMatchEtype (
|
IN OUT MVPP2_PRS_ENTRY *Pe,
|
IN INT32 Offset,
|
IN UINT16 EtherType
|
)
|
{
|
Mvpp2PrsTcamDataByteSet (Pe, Offset + 0, EtherType >> 8, 0xff);
|
Mvpp2PrsTcamDataByteSet (Pe, Offset + 1, EtherType & 0xff, 0xff);
|
}
|
|
/* Set bits in Sram sw entry */
|
STATIC
|
VOID
|
Mvpp2PrsSramBitsSet (
|
IN OUT MVPP2_PRS_ENTRY *Pe,
|
IN INT32 BitNum,
|
IN INT32 Val
|
)
|
{
|
Pe->Sram.Byte[MVPP2_BIT_TO_BYTE(BitNum)] |= (Val << (BitNum % 8));
|
}
|
|
/* Clear bits in Sram sw entry */
|
STATIC
|
VOID
|
Mvpp2PrsSramBitsClear (
|
IN OUT MVPP2_PRS_ENTRY *Pe,
|
IN INT32 BitNum,
|
IN INT32 Val
|
)
|
{
|
Pe->Sram.Byte[MVPP2_BIT_TO_BYTE(BitNum)] &= ~(Val << (BitNum % 8));
|
}
|
|
/* Update Ri bits in Sram sw entry */
|
STATIC
|
VOID
|
Mvpp2PrsSramRiUpdate (
|
IN OUT MVPP2_PRS_ENTRY *Pe,
|
IN UINT32 bits,
|
IN UINT32 Mask
|
)
|
{
|
UINT32 i;
|
|
for (i = 0; i < MVPP2_PRS_SRAM_RI_CTRL_BITS; i++) {
|
INT32 RiOff = MVPP2_PRS_SRAM_RI_OFFS;
|
|
if (!(Mask & BIT (i))) {
|
continue;
|
}
|
|
if (bits & BIT (i)) {
|
Mvpp2PrsSramBitsSet (Pe, RiOff + i, 1);
|
} else {
|
Mvpp2PrsSramBitsClear (Pe, RiOff + i, 1);
|
}
|
|
Mvpp2PrsSramBitsSet (Pe, MVPP2_PRS_SRAM_RI_CTRL_OFFS + i, 1);
|
}
|
}
|
|
/* Obtain Ri bits from Sram sw entry */
|
STATIC
|
INT32
|
Mvpp2PrsSramRiGet (
|
IN MVPP2_PRS_ENTRY *Pe
|
)
|
{
|
return Pe->Sram.Word[MVPP2_PRS_SRAM_RI_WORD];
|
}
|
|
/* Update ai bits in Sram sw entry */
|
STATIC
|
VOID
|
Mvpp2PrsSramAiUpdate (
|
IN OUT MVPP2_PRS_ENTRY *Pe,
|
IN UINT32 Bits,
|
UINT32 Mask
|
)
|
{
|
UINT32 i;
|
INT32 AiOff = MVPP2_PRS_SRAM_AI_OFFS;
|
|
for (i = 0; i < MVPP2_PRS_SRAM_AI_CTRL_BITS; i++) {
|
|
if (!(Mask & BIT (i))) {
|
continue;
|
}
|
|
if (Bits & BIT (i)) {
|
Mvpp2PrsSramBitsSet (Pe, AiOff + i, 1);
|
} else {
|
Mvpp2PrsSramBitsClear (Pe, AiOff + i, 1);
|
}
|
|
Mvpp2PrsSramBitsSet (Pe, MVPP2_PRS_SRAM_AI_CTRL_OFFS + i, 1);
|
}
|
}
|
|
/* Read ai bits from Sram sw entry */
|
STATIC
|
INT32
|
Mvpp2PrsSramAiGet (
|
IN MVPP2_PRS_ENTRY *Pe
|
)
|
{
|
UINT8 bits;
|
INT32 AiOff = MVPP2_BIT_TO_BYTE(MVPP2_PRS_SRAM_AI_OFFS);
|
INT32 AiEnOff = AiOff + 1;
|
INT32 AiShift = MVPP2_PRS_SRAM_AI_OFFS % 8;
|
|
bits = (Pe->Sram.Byte[AiOff] >> AiShift) |
|
(Pe->Sram.Byte[AiEnOff] << (8 - AiShift));
|
|
return bits;
|
}
|
|
/*
|
* In Sram sw entry set lookup ID field of the
|
* Tcam key to be used in the next lookup iteration
|
*/
|
STATIC
|
VOID
|
Mvpp2PrsSramNextLuSet (
|
IN OUT MVPP2_PRS_ENTRY *Pe,
|
IN UINT32 Lu
|
)
|
{
|
INT32 SramNextOff = MVPP2_PRS_SRAM_NEXT_LU_OFFS;
|
|
Mvpp2PrsSramBitsClear (Pe, SramNextOff, MVPP2_PRS_SRAM_NEXT_LU_MASK);
|
Mvpp2PrsSramBitsSet (Pe, SramNextOff, Lu);
|
}
|
|
/*
|
* In the Sram sw entry set sign and value of the next lookup Offset
|
* and the Offset value generated to the classifier
|
*/
|
STATIC
|
VOID
|
Mvpp2PrsSramShiftSet (
|
IN OUT MVPP2_PRS_ENTRY *Pe,
|
IN INT32 Shift,
|
IN UINT32 Op
|
)
|
{
|
/* Set sign */
|
if (Shift < 0) {
|
Mvpp2PrsSramBitsSet (Pe, MVPP2_PRS_SRAM_SHIFT_SIGN_BIT, 1);
|
Shift = -Shift;
|
} else {
|
Mvpp2PrsSramBitsClear (Pe, MVPP2_PRS_SRAM_SHIFT_SIGN_BIT, 1);
|
}
|
|
/* Set value */
|
Pe->Sram.Byte[MVPP2_BIT_TO_BYTE(MVPP2_PRS_SRAM_SHIFT_OFFS)] = (UINT8)Shift;
|
|
/* Reset and set operation */
|
Mvpp2PrsSramBitsClear (Pe, MVPP2_PRS_SRAM_OP_SEL_SHIFT_OFFS, MVPP2_PRS_SRAM_OP_SEL_SHIFT_MASK);
|
Mvpp2PrsSramBitsSet (Pe, MVPP2_PRS_SRAM_OP_SEL_SHIFT_OFFS, Op);
|
|
/* Set base Offset as current */
|
Mvpp2PrsSramBitsClear (Pe, MVPP2_PRS_SRAM_OP_SEL_BASE_OFFS, 1);
|
}
|
|
/*
|
* In the Sram sw entry set sign and value of the user defined offset
|
* generated for the classifier
|
*/
|
STATIC
|
VOID
|
Mvpp2PrsSramOffsetSet (
|
IN OUT MVPP2_PRS_ENTRY *Pe,
|
IN UINT32 Type,
|
IN INT32 Offset,
|
IN UINT32 Op
|
)
|
{
|
UINT8 UdfByte = MVPP2_BIT_TO_BYTE(MVPP2_PRS_SRAM_UDF_OFFS + MVPP2_PRS_SRAM_UDF_BITS);
|
UINT8 UdfByteOffset = (8 - (MVPP2_PRS_SRAM_UDF_OFFS % 8));
|
UINT8 OpSelUdfByte = MVPP2_BIT_TO_BYTE(MVPP2_PRS_SRAM_OP_SEL_UDF_OFFS + MVPP2_PRS_SRAM_OP_SEL_UDF_BITS);
|
UINT8 OpSelUdfByteOffset = (8 - (MVPP2_PRS_SRAM_OP_SEL_UDF_OFFS % 8));
|
|
/* Set sign */
|
if (Offset < 0) {
|
Mvpp2PrsSramBitsSet (Pe, MVPP2_PRS_SRAM_UDF_SIGN_BIT, 1);
|
Offset = -Offset;
|
} else {
|
Mvpp2PrsSramBitsClear (Pe, MVPP2_PRS_SRAM_UDF_SIGN_BIT, 1);
|
}
|
|
/* Set value */
|
Mvpp2PrsSramBitsClear (Pe, MVPP2_PRS_SRAM_UDF_OFFS, MVPP2_PRS_SRAM_UDF_MASK);
|
Mvpp2PrsSramBitsSet (Pe, MVPP2_PRS_SRAM_UDF_OFFS, Offset);
|
|
Pe->Sram.Byte[UdfByte] &= ~(MVPP2_PRS_SRAM_UDF_MASK >> UdfByteOffset);
|
Pe->Sram.Byte[UdfByte] |= (Offset >> UdfByteOffset);
|
|
/* Set Offset Type */
|
Mvpp2PrsSramBitsClear (Pe, MVPP2_PRS_SRAM_UDF_TYPE_OFFS, MVPP2_PRS_SRAM_UDF_TYPE_MASK);
|
Mvpp2PrsSramBitsSet (Pe, MVPP2_PRS_SRAM_UDF_TYPE_OFFS, Type);
|
|
/* Set Offset operation */
|
Mvpp2PrsSramBitsClear (Pe, MVPP2_PRS_SRAM_OP_SEL_UDF_OFFS, MVPP2_PRS_SRAM_OP_SEL_UDF_MASK);
|
Mvpp2PrsSramBitsSet (Pe, MVPP2_PRS_SRAM_OP_SEL_UDF_OFFS, Op);
|
|
Pe->Sram.Byte[OpSelUdfByte] &= ~(MVPP2_PRS_SRAM_OP_SEL_UDF_MASK >> OpSelUdfByteOffset);
|
Pe->Sram.Byte[OpSelUdfByte] |= (Op >> OpSelUdfByteOffset);
|
|
/* Set base Offset as current */
|
Mvpp2PrsSramBitsClear (Pe, MVPP2_PRS_SRAM_OP_SEL_BASE_OFFS, 1);
|
}
|
|
/* Find parser Flow entry */
|
STATIC
|
MVPP2_PRS_ENTRY *
|
Mvpp2PrsFlowFind (
|
IN MVPP2_SHARED *Priv,
|
IN INT32 Flow
|
)
|
{
|
MVPP2_PRS_ENTRY *Pe;
|
INT32 Tid;
|
UINT32 Word, Enable;
|
|
Pe = Mvpp2Alloc (sizeof (*Pe));
|
if (Pe == NULL) {
|
return NULL;
|
}
|
|
Mvpp2PrsTcamLuSet (Pe, MVPP2_PRS_LU_FLOWS);
|
|
/* Go through the all entires with MVPP2_PRS_LU_FLOWS */
|
for (Tid = MVPP2_PRS_TCAM_SRAM_SIZE - 1; Tid >= 0; Tid--) {
|
UINT8 Bits;
|
|
if (!Priv->PrsShadow[Tid].Valid || Priv->PrsShadow[Tid].Lu != MVPP2_PRS_LU_FLOWS) {
|
continue;
|
}
|
|
Pe->Index = Tid;
|
Mvpp2PrsHwRead (Priv, Pe);
|
|
/*
|
* Check result info, because there maybe
|
* several TCAM lines to generate the same Flow
|
*/
|
Mvpp2PrsTcamDataWordGet (Pe, 0, &Word, &Enable);
|
if ((Word != 0) || (Enable != 0)) {
|
continue;
|
}
|
|
Bits = Mvpp2PrsSramAiGet (Pe);
|
|
/* Sram store classification lookup ID in AI Bits [5:0] */
|
if ((Bits & MVPP2_PRS_FLOW_ID_MASK) == Flow) {
|
return Pe;
|
}
|
}
|
|
Mvpp2Free (Pe);
|
|
return NULL;
|
}
|
|
/* Return first free Tcam Index, seeking from start to end */
|
STATIC
|
INT32
|
Mvpp2PrsTcamFirstFree (
|
IN MVPP2_SHARED *Priv,
|
IN UINT8 Start,
|
IN UINT8 End
|
)
|
{
|
INT32 Tid;
|
|
if (Start > End) {
|
Mvpp2SwapVariables (Start, End);
|
}
|
|
if (End >= MVPP2_PRS_TCAM_SRAM_SIZE) {
|
End = MVPP2_PRS_TCAM_SRAM_SIZE - 1;
|
}
|
|
for (Tid = Start; Tid <= End; Tid++) {
|
if (!Priv->PrsShadow[Tid].Valid) {
|
return Tid;
|
}
|
}
|
|
return MVPP2_EINVAL;
|
}
|
|
/* Enable/disable dropping all mac Da's */
|
STATIC
|
VOID
|
Mvpp2PrsMacDropAllSet (
|
IN MVPP2_SHARED *Priv,
|
IN INT32 PortId,
|
IN BOOLEAN Add
|
)
|
{
|
MVPP2_PRS_ENTRY Pe;
|
|
if (Priv->PrsShadow[MVPP2_PE_DROP_ALL].Valid) {
|
/* Entry exist - update PortId only */
|
Pe.Index = MVPP2_PE_DROP_ALL;
|
Mvpp2PrsHwRead (Priv, &Pe);
|
} else {
|
/* Entry doesn't exist - create new */
|
Mvpp2Memset (&Pe, 0, sizeof (MVPP2_PRS_ENTRY));
|
Mvpp2PrsTcamLuSet (&Pe, MVPP2_PRS_LU_MAC);
|
Pe.Index = MVPP2_PE_DROP_ALL;
|
|
/* Non-promiscuous mode for all Ports - DROP unknown packets */
|
Mvpp2PrsSramRiUpdate (&Pe, MVPP2_PRS_RI_DROP_MASK, MVPP2_PRS_RI_DROP_MASK);
|
|
Mvpp2PrsSramBitsSet (&Pe, MVPP2_PRS_SRAM_LU_GEN_BIT, 1);
|
Mvpp2PrsSramNextLuSet (&Pe, MVPP2_PRS_LU_FLOWS);
|
|
/* Update shadow table */
|
Mvpp2PrsShadowSet (Priv, Pe.Index, MVPP2_PRS_LU_MAC);
|
|
/* Mask all Ports */
|
Mvpp2PrsTcamPortMapSet (&Pe, 0);
|
}
|
|
/* Update PortId Mask */
|
Mvpp2PrsTcamPortSet (&Pe, PortId, Add);
|
|
Mvpp2PrsHwWrite (Priv, &Pe);
|
}
|
|
/* Set port to promiscuous mode */
|
VOID
|
Mvpp2PrsMacPromiscSet (
|
IN MVPP2_SHARED *Priv,
|
IN INT32 PortId,
|
IN BOOLEAN Add
|
)
|
{
|
MVPP2_PRS_ENTRY Pe;
|
|
/* Promiscuous mode - Accept unknown packets */
|
|
if (Priv->PrsShadow[MVPP2_PE_MAC_PROMISCUOUS].Valid) {
|
/* Entry exist - update port only */
|
Pe.Index = MVPP2_PE_MAC_PROMISCUOUS;
|
Mvpp2PrsHwRead (Priv, &Pe);
|
} else {
|
/* Entry doesn't exist - create new */
|
Mvpp2Memset (&Pe, 0, sizeof (MVPP2_PRS_ENTRY));
|
Mvpp2PrsTcamLuSet (&Pe, MVPP2_PRS_LU_MAC);
|
Pe.Index = MVPP2_PE_MAC_PROMISCUOUS;
|
|
/* Continue - set next lookup */
|
Mvpp2PrsSramNextLuSet (&Pe, MVPP2_PRS_LU_DSA);
|
|
/* Set result info bits */
|
Mvpp2PrsSramRiUpdate (&Pe, MVPP2_PRS_RI_L2_UCAST, MVPP2_PRS_RI_L2_CAST_MASK);
|
|
/* Shift to ethertype with 2 of MAC Address length */
|
Mvpp2PrsSramShiftSet (&Pe, 2 * MV_ETH_ALEN, MVPP2_PRS_SRAM_OP_SEL_SHIFT_ADD);
|
|
/* Mask all Ports */
|
Mvpp2PrsTcamPortMapSet (&Pe, 0);
|
|
/* Update shadow table */
|
Mvpp2PrsShadowSet (Priv, Pe.Index, MVPP2_PRS_LU_MAC);
|
}
|
|
/* Update port Mask */
|
Mvpp2PrsTcamPortSet (&Pe, PortId, Add);
|
|
Mvpp2PrsHwWrite (Priv, &Pe);
|
}
|
|
/* Accept multicast */
|
VOID
|
Mvpp2PrsMacMultiSet (
|
IN MVPP2_SHARED *Priv,
|
IN INT32 PortId,
|
IN INT32 Index,
|
IN BOOLEAN Add
|
)
|
{
|
MVPP2_PRS_ENTRY Pe;
|
UINT8 DaMc;
|
|
/*
|
* Ethernet multicast Address first Byte is
|
* 0x01 for IPv4 and 0x33 for IPv6
|
*/
|
DaMc = (Index == MVPP2_PE_MAC_MC_ALL) ? 0x01 : 0x33;
|
|
if (Priv->PrsShadow[Index].Valid) {
|
/* Entry exist - update port only */
|
Pe.Index = Index;
|
Mvpp2PrsHwRead (Priv, &Pe);
|
} else {
|
/* Entry doesn't exist - create new */
|
Mvpp2Memset (&Pe, 0, sizeof (MVPP2_PRS_ENTRY));
|
Mvpp2PrsTcamLuSet (&Pe, MVPP2_PRS_LU_MAC);
|
Pe.Index = Index;
|
|
/* Continue - set next lookup */
|
Mvpp2PrsSramNextLuSet (&Pe, MVPP2_PRS_LU_DSA);
|
|
/* Set result info bits */
|
Mvpp2PrsSramRiUpdate (&Pe, MVPP2_PRS_RI_L2_MCAST, MVPP2_PRS_RI_L2_CAST_MASK);
|
|
/* Update Tcam entry data first Byte */
|
Mvpp2PrsTcamDataByteSet (&Pe, 0, DaMc, 0xff);
|
|
/* Shift to ethertype */
|
Mvpp2PrsSramShiftSet (&Pe, 2 * MV_ETH_ALEN, MVPP2_PRS_SRAM_OP_SEL_SHIFT_ADD);
|
|
/* Mask all ports */
|
Mvpp2PrsTcamPortMapSet (&Pe, 0);
|
|
/* Update shadow table */
|
Mvpp2PrsShadowSet (Priv, Pe.Index, MVPP2_PRS_LU_MAC);
|
}
|
|
/* Update port Mask */
|
Mvpp2PrsTcamPortSet (&Pe, PortId, Add);
|
|
Mvpp2PrsHwWrite (Priv, &Pe);
|
}
|
|
/* Set entry for dsa packets */
|
STATIC
|
VOID
|
Mvpp2PrsDsaTagSet (
|
IN MVPP2_SHARED *Priv,
|
IN INT32 PortId,
|
IN BOOLEAN Add,
|
IN BOOLEAN Tagged,
|
IN BOOLEAN Extend
|
)
|
{
|
MVPP2_PRS_ENTRY Pe;
|
INT32 Tid, Shift;
|
|
if (Extend) {
|
Tid = Tagged ? MVPP2_PE_EDSA_TAGGED : MVPP2_PE_EDSA_UNTAGGED;
|
Shift = 8;
|
} else {
|
Tid = Tagged ? MVPP2_PE_DSA_TAGGED : MVPP2_PE_DSA_UNTAGGED;
|
Shift = 4;
|
}
|
|
if (Priv->PrsShadow[Tid].Valid) {
|
/* Entry exist - update port only */
|
Pe.Index = Tid;
|
Mvpp2PrsHwRead (Priv, &Pe);
|
} else {
|
/* Entry doesn't exist - create new */
|
Mvpp2Memset (&Pe, 0, sizeof (MVPP2_PRS_ENTRY));
|
Mvpp2PrsTcamLuSet (&Pe, MVPP2_PRS_LU_DSA);
|
Pe.Index = Tid;
|
|
/* Shift 4 bytes if DSA tag or 8 bytes in case of EDSA tag*/
|
Mvpp2PrsSramShiftSet (&Pe, Shift, MVPP2_PRS_SRAM_OP_SEL_SHIFT_ADD);
|
|
/* Update shadow table */
|
Mvpp2PrsShadowSet (Priv, Pe.Index, MVPP2_PRS_LU_DSA);
|
|
if (Tagged) {
|
/* Set Tagged bit in DSA tag */
|
Mvpp2PrsTcamDataByteSet (&Pe, 0, MVPP2_PRS_TCAM_DSA_TAGGED_BIT, MVPP2_PRS_TCAM_DSA_TAGGED_BIT);
|
|
/* Clear all ai bits for next iteration */
|
Mvpp2PrsSramAiUpdate (&Pe, 0, MVPP2_PRS_SRAM_AI_MASK);
|
|
/* If packet is Tagged continue check vlans */
|
Mvpp2PrsSramNextLuSet (&Pe, MVPP2_PRS_LU_VLAN);
|
} else {
|
/* Set result info bits to 'no vlans' */
|
Mvpp2PrsSramRiUpdate (&Pe, MVPP2_PRS_RI_VLAN_NONE, MVPP2_PRS_RI_VLAN_MASK);
|
Mvpp2PrsSramNextLuSet (&Pe, MVPP2_PRS_LU_L2);
|
}
|
|
/* Mask all Ports */
|
Mvpp2PrsTcamPortMapSet (&Pe, 0);
|
}
|
|
/* Update port Mask */
|
Mvpp2PrsTcamPortSet (&Pe, PortId, Add);
|
|
Mvpp2PrsHwWrite (Priv, &Pe);
|
}
|
|
/* Set entry for dsa ethertype */
|
STATIC
|
VOID
|
Mvpp2PrsDsaTagEthertypeSet (
|
IN MVPP2_SHARED *Priv,
|
IN INT32 PortId,
|
IN BOOLEAN Add,
|
IN BOOLEAN Tagged,
|
IN BOOLEAN Extend
|
)
|
{
|
MVPP2_PRS_ENTRY Pe;
|
INT32 Tid, Shift, PortMask;
|
|
if (Extend) {
|
Tid = Tagged ? MVPP2_PE_ETYPE_EDSA_TAGGED : MVPP2_PE_ETYPE_EDSA_UNTAGGED;
|
PortMask = 0;
|
Shift = 8;
|
} else {
|
Tid = Tagged ? MVPP2_PE_ETYPE_DSA_TAGGED : MVPP2_PE_ETYPE_DSA_UNTAGGED;
|
PortMask = MVPP2_PRS_PORT_MASK;
|
Shift = 4;
|
}
|
|
if (Priv->PrsShadow[Tid].Valid) {
|
/* Entry exist - update PortId only */
|
Pe.Index = Tid;
|
Mvpp2PrsHwRead (Priv, &Pe);
|
} else {
|
/* Entry doesn't exist - create new */
|
Mvpp2Memset (&Pe, 0, sizeof (MVPP2_PRS_ENTRY));
|
Mvpp2PrsTcamLuSet (&Pe, MVPP2_PRS_LU_DSA);
|
Pe.Index = Tid;
|
|
/*
|
* Set ethertype at offset 0 for DSA and
|
* clear it at offset 2 - obtained from Marvell.
|
*/
|
Mvpp2PrsMatchEtype (&Pe, 0, MV_ETH_P_EDSA);
|
Mvpp2PrsMatchEtype (&Pe, 2, 0);
|
|
Mvpp2PrsSramRiUpdate (&Pe, MVPP2_PRS_RI_DSA_MASK,
|
MVPP2_PRS_RI_DSA_MASK);
|
|
/* Shift ethertype + 2 Byte reserved + tag */
|
Mvpp2PrsSramShiftSet (&Pe, 2 + MVPP2_ETH_TYPE_LEN + Shift,
|
MVPP2_PRS_SRAM_OP_SEL_SHIFT_ADD);
|
|
/* Update shadow table */
|
Mvpp2PrsShadowSet (Priv, Pe.Index, MVPP2_PRS_LU_DSA);
|
|
if (Tagged) {
|
/* Set Tagged bit in DSA tag */
|
Mvpp2PrsTcamDataByteSet (
|
&Pe,
|
MVPP2_ETH_TYPE_LEN + 2 + 3,
|
MVPP2_PRS_TCAM_DSA_TAGGED_BIT,
|
MVPP2_PRS_TCAM_DSA_TAGGED_BIT
|
);
|
|
/* Clear all ai bits for next iteration */
|
Mvpp2PrsSramAiUpdate (&Pe, 0, MVPP2_PRS_SRAM_AI_MASK);
|
|
/* If packet is Tagged continue check vlans */
|
Mvpp2PrsSramNextLuSet (&Pe, MVPP2_PRS_LU_VLAN);
|
} else {
|
/* Set result info bits to 'no vlans' */
|
Mvpp2PrsSramRiUpdate (&Pe, MVPP2_PRS_RI_VLAN_NONE, MVPP2_PRS_RI_VLAN_MASK);
|
Mvpp2PrsSramNextLuSet (&Pe, MVPP2_PRS_LU_L2);
|
}
|
|
/* Mask/unmask all ports, depending on dsa type */
|
Mvpp2PrsTcamPortMapSet (&Pe, PortMask);
|
}
|
|
/* Update port Mask */
|
Mvpp2PrsTcamPortSet (&Pe, PortId, Add);
|
|
Mvpp2PrsHwWrite (Priv, &Pe);
|
}
|
|
/* Search for existing single/triple vlan entry */
|
STATIC
|
MVPP2_PRS_ENTRY *
|
Mvpp2PrsVlanFind (
|
IN MVPP2_SHARED *Priv,
|
IN UINT16 Tpid,
|
IN INT32 Ai
|
)
|
{
|
MVPP2_PRS_ENTRY *Pe;
|
INT32 Tid;
|
|
Pe = Mvpp2Alloc (sizeof (*Pe));
|
if (Pe == NULL) {
|
return NULL;
|
}
|
|
Mvpp2PrsTcamLuSet (Pe, MVPP2_PRS_LU_VLAN);
|
|
/* Go through the all entries with MVPP2_PRS_LU_VLAN */
|
for (Tid = MVPP2_PE_FIRST_FREE_TID; Tid <= MVPP2_PE_LAST_FREE_TID; Tid++) {
|
UINT32 RiBits, AiBits;
|
BOOLEAN match;
|
|
if (!Priv->PrsShadow[Tid].Valid || Priv->PrsShadow[Tid].Lu != MVPP2_PRS_LU_VLAN) {
|
continue;
|
}
|
|
Pe->Index = Tid;
|
|
Mvpp2PrsHwRead (Priv, Pe);
|
match = Mvpp2PrsTcamDataCmp (Pe, 0, Mvpp2SwapBytes16 (Tpid));
|
if (!match) {
|
continue;
|
}
|
|
/* Get vlan type */
|
RiBits = Mvpp2PrsSramRiGet (Pe);
|
RiBits &= MVPP2_PRS_RI_VLAN_MASK;
|
|
/* Get current Ai value from Tcam */
|
AiBits = Mvpp2PrsTcamAiGet (Pe);
|
|
/* Clear double vlan bit */
|
AiBits &= ~MVPP2_PRS_DBL_VLAN_AI_BIT;
|
|
if (Ai != AiBits) {
|
continue;
|
}
|
|
if (RiBits == MVPP2_PRS_RI_VLAN_SINGLE || RiBits == MVPP2_PRS_RI_VLAN_TRIPLE) {
|
return Pe;
|
}
|
}
|
|
Mvpp2Free (Pe);
|
|
return NULL;
|
}
|
|
/* Add/update single/triple vlan entry */
|
INT32
|
Mvpp2PrsVlanAdd (
|
IN MVPP2_SHARED *Priv,
|
IN UINT16 Tpid,
|
IN INT32 Ai,
|
IN UINT32 PortMap
|
)
|
{
|
MVPP2_PRS_ENTRY *Pe;
|
INT32 TidAux, Tid;
|
INT32 Ret = 0;
|
|
Pe = Mvpp2PrsVlanFind (Priv, Tpid, Ai);
|
|
if (!Pe) {
|
/* Create new Tcam entry */
|
Tid = Mvpp2PrsTcamFirstFree (Priv, MVPP2_PE_LAST_FREE_TID, MVPP2_PE_FIRST_FREE_TID);
|
if (Tid < 0) {
|
return Tid;
|
}
|
|
Pe = Mvpp2Alloc (sizeof (*Pe));
|
if (Pe == NULL) {
|
return MVPP2_ENOMEM;
|
}
|
|
/* Get last double vlan Tid */
|
for (TidAux = MVPP2_PE_LAST_FREE_TID; TidAux >= MVPP2_PE_FIRST_FREE_TID; TidAux--) {
|
UINT32 RiBits;
|
|
if (!Priv->PrsShadow[TidAux].Valid || Priv->PrsShadow[TidAux].Lu != MVPP2_PRS_LU_VLAN) {
|
continue;
|
}
|
|
Pe->Index = TidAux;
|
Mvpp2PrsHwRead (Priv, Pe);
|
RiBits = Mvpp2PrsSramRiGet (Pe);
|
if ((RiBits & MVPP2_PRS_RI_VLAN_MASK) == MVPP2_PRS_RI_VLAN_DOUBLE) {
|
break;
|
}
|
}
|
|
if (Tid <= TidAux) {
|
Ret = MVPP2_EINVAL;
|
goto error;
|
}
|
|
Mvpp2Memset (Pe, 0 , sizeof (MVPP2_PRS_ENTRY));
|
Mvpp2PrsTcamLuSet (Pe, MVPP2_PRS_LU_VLAN);
|
Pe->Index = Tid;
|
|
/* Set VLAN type's offset to 0 bytes - obtained from Marvell */
|
Mvpp2PrsMatchEtype (Pe, 0, Tpid);
|
|
Mvpp2PrsSramNextLuSet (Pe, MVPP2_PRS_LU_L2);
|
|
/* Shift 4 bytes - skip 1 vlan tag */
|
Mvpp2PrsSramShiftSet (Pe, MVPP2_VLAN_TAG_LEN,
|
MVPP2_PRS_SRAM_OP_SEL_SHIFT_ADD);
|
|
/* Clear all Ai bits for next iteration */
|
Mvpp2PrsSramAiUpdate (Pe, 0, MVPP2_PRS_SRAM_AI_MASK);
|
|
if (Ai == MVPP2_PRS_SINGLE_VLAN_AI) {
|
Mvpp2PrsSramRiUpdate (Pe, MVPP2_PRS_RI_VLAN_SINGLE, MVPP2_PRS_RI_VLAN_MASK);
|
} else {
|
Ai |= MVPP2_PRS_DBL_VLAN_AI_BIT;
|
Mvpp2PrsSramRiUpdate (Pe, MVPP2_PRS_RI_VLAN_TRIPLE, MVPP2_PRS_RI_VLAN_MASK);
|
}
|
|
Mvpp2PrsTcamAiUpdate (Pe, Ai, MVPP2_PRS_SRAM_AI_MASK);
|
|
Mvpp2PrsShadowSet (Priv, Pe->Index, MVPP2_PRS_LU_VLAN);
|
}
|
|
/* Update Ports' Mask */
|
Mvpp2PrsTcamPortMapSet (Pe, PortMap);
|
Mvpp2PrsHwWrite (Priv, Pe);
|
|
error:
|
Mvpp2Free (Pe);
|
|
return Ret;
|
}
|
|
/* Get first free double vlan ai number */
|
INT32
|
Mvpp2PrsDoubleVlanAiFreeGet (
|
IN MVPP2_SHARED *Priv
|
)
|
{
|
INT32 i;
|
|
for (i = 1; i < MVPP2_PRS_DBL_VLANS_MAX; i++) {
|
if (!Priv->PrsDoubleVlans[i]) {
|
return i;
|
}
|
}
|
|
return MVPP2_EINVAL;
|
}
|
|
/* Search for existing double vlan entry */
|
MVPP2_PRS_ENTRY *Mvpp2PrsDoubleVlanFind (
|
IN MVPP2_SHARED *Priv,
|
IN UINT16 Tpid1,
|
IN UINT16 Tpid2
|
)
|
{
|
MVPP2_PRS_ENTRY *Pe;
|
INT32 Tid;
|
|
Pe = Mvpp2Alloc (sizeof (*Pe));
|
if (Pe == NULL) {
|
return NULL;
|
}
|
|
Mvpp2PrsTcamLuSet (Pe, MVPP2_PRS_LU_VLAN);
|
|
/* Go through the all entries with MVPP2_PRS_LU_VLAN */
|
for (Tid = MVPP2_PE_FIRST_FREE_TID; Tid <= MVPP2_PE_LAST_FREE_TID; Tid++) {
|
UINT32 RiMask;
|
BOOLEAN match;
|
|
if (!Priv->PrsShadow[Tid].Valid || Priv->PrsShadow[Tid].Lu != MVPP2_PRS_LU_VLAN) {
|
continue;
|
}
|
|
Pe->Index = Tid;
|
Mvpp2PrsHwRead (Priv, Pe);
|
|
match = Mvpp2PrsTcamDataCmp (Pe, 0, Mvpp2SwapBytes16 (Tpid1)) &&
|
Mvpp2PrsTcamDataCmp (Pe, 4, Mvpp2SwapBytes16 (Tpid2));
|
|
if (!match) {
|
continue;
|
}
|
|
RiMask = Mvpp2PrsSramRiGet (Pe) & MVPP2_PRS_RI_VLAN_MASK;
|
if (RiMask == MVPP2_PRS_RI_VLAN_DOUBLE) {
|
return Pe;
|
}
|
}
|
|
Mvpp2Free (Pe);
|
|
return NULL;
|
}
|
|
/* Add or update double vlan entry */
|
INT32
|
Mvpp2PrsDoubleVlanAdd (
|
IN MVPP2_SHARED *Priv,
|
IN UINT16 Tpid1,
|
IN UINT16 Tpid2,
|
IN UINT32 PortMap
|
)
|
{
|
MVPP2_PRS_ENTRY *Pe;
|
INT32 TidAux, Tid, Ai, Ret = 0;
|
|
Pe = Mvpp2PrsDoubleVlanFind (Priv, Tpid1, Tpid2);
|
|
if (!Pe) {
|
/* Create new Tcam entry */
|
Tid = Mvpp2PrsTcamFirstFree (Priv, MVPP2_PE_FIRST_FREE_TID, MVPP2_PE_LAST_FREE_TID);
|
if (Tid < 0) {
|
return Tid;
|
}
|
|
Pe = Mvpp2Alloc (sizeof (*Pe));
|
if (Pe == NULL) {
|
return MVPP2_ENOMEM;
|
}
|
|
/* Set Ai value for new double vlan entry */
|
Ai = Mvpp2PrsDoubleVlanAiFreeGet (Priv);
|
if (Ai < 0) {
|
Ret = Ai;
|
goto error;
|
}
|
|
/* Get first single/triple vlan Tid */
|
for (TidAux = MVPP2_PE_FIRST_FREE_TID; TidAux <= MVPP2_PE_LAST_FREE_TID; TidAux++) {
|
UINT32 RiBits;
|
|
if (!Priv->PrsShadow[TidAux].Valid || Priv->PrsShadow[TidAux].Lu != MVPP2_PRS_LU_VLAN) {
|
continue;
|
}
|
|
Pe->Index = TidAux;
|
Mvpp2PrsHwRead (Priv, Pe);
|
RiBits = Mvpp2PrsSramRiGet (Pe);
|
RiBits &= MVPP2_PRS_RI_VLAN_MASK;
|
|
if (RiBits == MVPP2_PRS_RI_VLAN_SINGLE || RiBits == MVPP2_PRS_RI_VLAN_TRIPLE) {
|
break;
|
}
|
}
|
|
if (Tid >= TidAux) {
|
Ret = MVPP2_ERANGE;
|
goto error;
|
}
|
|
Mvpp2Memset (Pe, 0, sizeof (MVPP2_PRS_ENTRY));
|
Mvpp2PrsTcamLuSet (Pe, MVPP2_PRS_LU_VLAN);
|
Pe->Index = Tid;
|
|
Priv->PrsDoubleVlans[Ai] = TRUE;
|
|
/* Set both VLAN types' offsets to 0 and 4 bytes - obtained from Marvell */
|
Mvpp2PrsMatchEtype (Pe, 0, Tpid1);
|
Mvpp2PrsMatchEtype (Pe, 4, Tpid2);
|
|
Mvpp2PrsSramNextLuSet (Pe, MVPP2_PRS_LU_VLAN);
|
|
/* Shift 8 bytes - skip 2 vlan tags */
|
Mvpp2PrsSramShiftSet (Pe, 2 * MVPP2_VLAN_TAG_LEN, MVPP2_PRS_SRAM_OP_SEL_SHIFT_ADD);
|
Mvpp2PrsSramRiUpdate (Pe, MVPP2_PRS_RI_VLAN_DOUBLE, MVPP2_PRS_RI_VLAN_MASK);
|
Mvpp2PrsSramAiUpdate (Pe, Ai | MVPP2_PRS_DBL_VLAN_AI_BIT, MVPP2_PRS_SRAM_AI_MASK);
|
|
Mvpp2PrsShadowSet (Priv, Pe->Index, MVPP2_PRS_LU_VLAN);
|
}
|
|
/* Update Ports' Mask */
|
Mvpp2PrsTcamPortMapSet (Pe, PortMap);
|
Mvpp2PrsHwWrite (Priv, Pe);
|
|
error:
|
Mvpp2Free (Pe);
|
return Ret;
|
}
|
|
/* IPv4 header parsing for fragmentation and L4 Offset */
|
STATIC
|
INT32
|
Mvpp2PrsIp4Proto (
|
IN MVPP2_SHARED *Priv,
|
IN UINT16 Proto,
|
IN UINT32 Ri,
|
IN UINT32 RiMask
|
)
|
{
|
MVPP2_PRS_ENTRY Pe;
|
INT32 Tid;
|
|
if ((Proto != MV_IPPR_TCP) && (Proto != MV_IPPR_UDP) && (Proto != MV_IPPR_IGMP)) {
|
return MVPP2_EINVAL;
|
}
|
|
/* Fragmented packet */
|
Tid = Mvpp2PrsTcamFirstFree (Priv, MVPP2_PE_FIRST_FREE_TID, MVPP2_PE_LAST_FREE_TID);
|
if (Tid < 0) {
|
return Tid;
|
}
|
|
Mvpp2Memset (&Pe, 0, sizeof (MVPP2_PRS_ENTRY));
|
Mvpp2PrsTcamLuSet (&Pe, MVPP2_PRS_LU_IP4);
|
Pe.Index = Tid;
|
|
/* Set next Lu to IPv4 - 12 bytes shift */
|
Mvpp2PrsSramNextLuSet (&Pe, MVPP2_PRS_LU_IP4);
|
Mvpp2PrsSramShiftSet (&Pe, 12, MVPP2_PRS_SRAM_OP_SEL_SHIFT_ADD);
|
|
/* Set L4 offset 4 bytes relative IPv4 header size (current position) */
|
Mvpp2PrsSramOffsetSet (
|
&Pe,
|
MVPP2_PRS_SRAM_UDF_TYPE_L4,
|
sizeof (Mvpp2Iphdr) - 4,
|
MVPP2_PRS_SRAM_OP_SEL_UDF_ADD
|
);
|
|
Mvpp2PrsSramAiUpdate (&Pe, MVPP2_PRS_IPV4_DIP_AI_BIT, MVPP2_PRS_IPV4_DIP_AI_BIT);
|
Mvpp2PrsSramRiUpdate (&Pe, Ri | MVPP2_PRS_RI_IP_FRAG_MASK, RiMask | MVPP2_PRS_RI_IP_FRAG_MASK);
|
|
Mvpp2PrsTcamDataByteSet (&Pe, 5, Proto, MVPP2_PRS_TCAM_PROTO_MASK);
|
Mvpp2PrsTcamAiUpdate (&Pe, 0, MVPP2_PRS_IPV4_DIP_AI_BIT);
|
|
/* Unmask all Ports */
|
Mvpp2PrsTcamPortMapSet (&Pe, MVPP2_PRS_PORT_MASK);
|
|
/* Update shadow table and hw entry */
|
Mvpp2PrsShadowSet (Priv, Pe.Index, MVPP2_PRS_LU_IP4);
|
Mvpp2PrsHwWrite (Priv, &Pe);
|
|
/* Not fragmented packet */
|
Tid = Mvpp2PrsTcamFirstFree (Priv, MVPP2_PE_FIRST_FREE_TID, MVPP2_PE_LAST_FREE_TID);
|
if (Tid < 0) {
|
return Tid;
|
}
|
|
Pe.Index = Tid;
|
|
/* Clear Ri before updating */
|
Pe.Sram.Word[MVPP2_PRS_SRAM_RI_WORD] = 0x0;
|
Pe.Sram.Word[MVPP2_PRS_SRAM_RI_CTRL_WORD] = 0x0;
|
Mvpp2PrsSramRiUpdate (&Pe, Ri, RiMask);
|
|
Mvpp2PrsTcamDataByteSet (&Pe, 2, 0x00, MVPP2_PRS_TCAM_PROTO_MASK_L);
|
Mvpp2PrsTcamDataByteSet (&Pe, 3, 0x00, MVPP2_PRS_TCAM_PROTO_MASK);
|
|
/* Update shadow table and hw entry */
|
Mvpp2PrsShadowSet (Priv, Pe.Index, MVPP2_PRS_LU_IP4);
|
Mvpp2PrsHwWrite (Priv, &Pe);
|
|
return 0;
|
}
|
|
/* IPv4 L3 multicast or broadcast */
|
STATIC
|
INT32
|
Mvpp2PrsIp4Cast (
|
IN MVPP2_SHARED *Priv,
|
IN UINT16 L3Cast
|
)
|
{
|
MVPP2_PRS_ENTRY Pe;
|
INT32 Mask, Tid;
|
|
Tid = Mvpp2PrsTcamFirstFree (Priv, MVPP2_PE_FIRST_FREE_TID, MVPP2_PE_LAST_FREE_TID);
|
if (Tid < 0) {
|
return Tid;
|
}
|
|
Mvpp2Memset (&Pe, 0, sizeof (MVPP2_PRS_ENTRY));
|
Mvpp2PrsTcamLuSet (&Pe, MVPP2_PRS_LU_IP4);
|
Pe.Index = Tid;
|
|
switch (L3Cast) {
|
case MVPP2_PRS_L3_MULTI_CAST:
|
Mvpp2PrsTcamDataByteSet (&Pe, 0, MVPP2_PRS_IPV4_MC, MVPP2_PRS_IPV4_MC_MASK);
|
Mvpp2PrsSramRiUpdate (&Pe, MVPP2_PRS_RI_L3_MCAST, MVPP2_PRS_RI_L3_ADDR_MASK);
|
break;
|
case MVPP2_PRS_L3_BROAD_CAST:
|
Mask = MVPP2_PRS_IPV4_BC_MASK;
|
Mvpp2PrsTcamDataByteSet (&Pe, 0, Mask, Mask);
|
Mvpp2PrsTcamDataByteSet (&Pe, 1, Mask, Mask);
|
Mvpp2PrsTcamDataByteSet (&Pe, 2, Mask, Mask);
|
Mvpp2PrsTcamDataByteSet (&Pe, 3, Mask, Mask);
|
Mvpp2PrsSramRiUpdate (&Pe, MVPP2_PRS_RI_L3_BCAST, MVPP2_PRS_RI_L3_ADDR_MASK);
|
break;
|
default:
|
return MVPP2_EINVAL;
|
}
|
|
/* Finished: go to Flowid generation */
|
Mvpp2PrsSramNextLuSet (&Pe, MVPP2_PRS_LU_FLOWS);
|
Mvpp2PrsSramBitsSet (&Pe, MVPP2_PRS_SRAM_LU_GEN_BIT, 1);
|
|
Mvpp2PrsTcamAiUpdate (&Pe, MVPP2_PRS_IPV4_DIP_AI_BIT, MVPP2_PRS_IPV4_DIP_AI_BIT);
|
|
/* Unmask all Ports */
|
Mvpp2PrsTcamPortMapSet (&Pe, MVPP2_PRS_PORT_MASK);
|
|
/* Update shadow table and hw entry */
|
Mvpp2PrsShadowSet (Priv, Pe.Index, MVPP2_PRS_LU_IP4);
|
Mvpp2PrsHwWrite (Priv, &Pe);
|
|
return 0;
|
}
|
|
/* Set entries for protocols over IPv6 */
|
STATIC
|
INT32
|
Mvpp2PrsIp6Proto (
|
IN MVPP2_SHARED *Priv,
|
IN UINT16 Proto,
|
IN UINT32 Ri,
|
IN UINT32 RiMask
|
)
|
{
|
MVPP2_PRS_ENTRY Pe;
|
INT32 Tid;
|
|
if ((Proto != MV_IPPR_TCP) && (Proto != MV_IPPR_UDP) &&
|
(Proto != MV_IPPR_ICMPV6) && (Proto != MV_IPPR_IPIP))
|
{
|
return MVPP2_EINVAL;
|
}
|
|
Tid = Mvpp2PrsTcamFirstFree (Priv, MVPP2_PE_FIRST_FREE_TID, MVPP2_PE_LAST_FREE_TID);
|
if (Tid < 0) {
|
return Tid;
|
}
|
|
Mvpp2Memset (&Pe, 0, sizeof (MVPP2_PRS_ENTRY));
|
Mvpp2PrsTcamLuSet (&Pe, MVPP2_PRS_LU_IP6);
|
Pe.Index = Tid;
|
|
/* Finished: go to Flowid generation */
|
Mvpp2PrsSramNextLuSet (&Pe, MVPP2_PRS_LU_FLOWS);
|
Mvpp2PrsSramBitsSet (&Pe, MVPP2_PRS_SRAM_LU_GEN_BIT, 1);
|
Mvpp2PrsSramRiUpdate (&Pe, Ri, RiMask);
|
|
/* Set offset for protocol 6 bytes relative to IPv6 header size */
|
Mvpp2PrsSramOffsetSet (
|
&Pe,
|
MVPP2_PRS_SRAM_UDF_TYPE_L4,
|
sizeof (Mvpp2Ipv6hdr) - 6,
|
MVPP2_PRS_SRAM_OP_SEL_UDF_ADD
|
);
|
|
Mvpp2PrsTcamDataByteSet (&Pe, 0, Proto, MVPP2_PRS_TCAM_PROTO_MASK);
|
Mvpp2PrsTcamAiUpdate (&Pe, MVPP2_PRS_IPV6_NO_EXT_AI_BIT, MVPP2_PRS_IPV6_NO_EXT_AI_BIT);
|
|
/* Unmask all Ports */
|
Mvpp2PrsTcamPortMapSet (&Pe, MVPP2_PRS_PORT_MASK);
|
|
/* Write HW */
|
Mvpp2PrsShadowSet (Priv, Pe.Index, MVPP2_PRS_LU_IP6);
|
Mvpp2PrsHwWrite (Priv, &Pe);
|
|
return 0;
|
}
|
|
/* IPv6 L3 multicast entry */
|
STATIC
|
INT32
|
Mvpp2PrsIp6Cast (
|
IN MVPP2_SHARED *Priv,
|
IN UINT16 L3Cast
|
)
|
{
|
MVPP2_PRS_ENTRY Pe;
|
INT32 Tid;
|
|
if (L3Cast != MVPP2_PRS_L3_MULTI_CAST) {
|
return MVPP2_EINVAL;
|
}
|
|
Tid = Mvpp2PrsTcamFirstFree (Priv, MVPP2_PE_FIRST_FREE_TID, MVPP2_PE_LAST_FREE_TID);
|
if (Tid < 0) {
|
return Tid;
|
}
|
|
Mvpp2Memset (&Pe, 0, sizeof (MVPP2_PRS_ENTRY));
|
Mvpp2PrsTcamLuSet (&Pe, MVPP2_PRS_LU_IP6);
|
Pe.Index = Tid;
|
|
/* Finished: go to Flowid generation */
|
Mvpp2PrsSramNextLuSet (&Pe, MVPP2_PRS_LU_IP6);
|
Mvpp2PrsSramRiUpdate (&Pe, MVPP2_PRS_RI_L3_MCAST, MVPP2_PRS_RI_L3_ADDR_MASK);
|
Mvpp2PrsSramAiUpdate (&Pe, MVPP2_PRS_IPV6_NO_EXT_AI_BIT, MVPP2_PRS_IPV6_NO_EXT_AI_BIT);
|
|
/* Shift back to IPv6 by 18 bytes - byte count provided by Marvell */
|
Mvpp2PrsSramShiftSet (&Pe, -18, MVPP2_PRS_SRAM_OP_SEL_SHIFT_ADD);
|
|
Mvpp2PrsTcamDataByteSet (&Pe, 0, MVPP2_PRS_IPV6_MC, MVPP2_PRS_IPV6_MC_MASK);
|
Mvpp2PrsTcamAiUpdate (&Pe, 0, MVPP2_PRS_IPV6_NO_EXT_AI_BIT);
|
|
/* Unmask all Ports */
|
Mvpp2PrsTcamPortMapSet (&Pe, MVPP2_PRS_PORT_MASK);
|
|
/* Update shadow table and hw entry */
|
Mvpp2PrsShadowSet (Priv, Pe.Index, MVPP2_PRS_LU_IP6);
|
Mvpp2PrsHwWrite (Priv, &Pe);
|
|
return 0;
|
}
|
|
/* Parser per-Port initialization */
|
STATIC
|
VOID
|
Mvpp2PrsHwPortInit (
|
IN MVPP2_SHARED *Priv,
|
IN INT32 PortId,
|
IN INT32 LuFirst,
|
IN INT32 LuMax,
|
IN INT32 Offset
|
)
|
{
|
UINT32 Val;
|
|
/* Set lookup ID */
|
Val = Mvpp2Read (Priv, MVPP2_PRS_INIT_LOOKUP_REG);
|
Val &= ~MVPP2_PRS_PORT_LU_MASK (PortId);
|
Val |= MVPP2_PRS_PORT_LU_VAL (PortId, LuFirst);
|
Mvpp2Write (Priv, MVPP2_PRS_INIT_LOOKUP_REG, Val);
|
|
/* Set maximum number of loops for packet received from PortId */
|
Val = Mvpp2Read (Priv, MVPP2_PRS_MAX_LOOP_REG(PortId));
|
Val &= ~MVPP2_PRS_MAX_LOOP_MASK (PortId);
|
Val |= MVPP2_PRS_MAX_LOOP_VAL (PortId, LuMax);
|
Mvpp2Write (Priv, MVPP2_PRS_MAX_LOOP_REG(PortId), Val);
|
|
/*
|
* Set initial Offset for packet header extraction for the first
|
* searching loop
|
*/
|
Val = Mvpp2Read (Priv, MVPP2_PRS_INIT_OFFS_REG(PortId));
|
Val &= ~MVPP2_PRS_INIT_OFF_MASK (PortId);
|
Val |= MVPP2_PRS_INIT_OFF_VAL (PortId, Offset);
|
Mvpp2Write (Priv, MVPP2_PRS_INIT_OFFS_REG(PortId), Val);
|
}
|
|
/* Default Flow entries initialization for all Ports */
|
STATIC
|
VOID
|
Mvpp2PrsDefFlowInit (
|
IN MVPP2_SHARED *Priv
|
)
|
{
|
MVPP2_PRS_ENTRY Pe;
|
INT32 PortId;
|
|
for (PortId = 0; PortId < MVPP2_MAX_PORTS; PortId++) {
|
Mvpp2Memset (&Pe, 0, sizeof (MVPP2_PRS_ENTRY));
|
Mvpp2PrsTcamLuSet (&Pe, MVPP2_PRS_LU_FLOWS);
|
Pe.Index = MVPP2_PE_FIRST_DEFAULT_FLOW - PortId;
|
|
/* Mask all Ports */
|
Mvpp2PrsTcamPortMapSet (&Pe, 0);
|
|
/* Set Flow ID*/
|
Mvpp2PrsSramAiUpdate (&Pe, PortId, MVPP2_PRS_FLOW_ID_MASK);
|
Mvpp2PrsSramBitsSet (&Pe, MVPP2_PRS_SRAM_LU_DONE_BIT, 1);
|
|
/* Update shadow table and hw entry */
|
Mvpp2PrsShadowSet (Priv, Pe.Index, MVPP2_PRS_LU_FLOWS);
|
Mvpp2PrsHwWrite (Priv, &Pe);
|
}
|
}
|
|
/* Set default entry for Marvell Header field */
|
STATIC
|
VOID
|
Mvpp2PrsMhInit (
|
IN MVPP2_SHARED *Priv
|
)
|
{
|
MVPP2_PRS_ENTRY Pe;
|
|
Mvpp2Memset (&Pe, 0, sizeof (MVPP2_PRS_ENTRY));
|
|
Pe.Index = MVPP2_PE_MH_DEFAULT;
|
Mvpp2PrsTcamLuSet (&Pe, MVPP2_PRS_LU_MH);
|
Mvpp2PrsSramShiftSet (&Pe, MVPP2_MH_SIZE, MVPP2_PRS_SRAM_OP_SEL_SHIFT_ADD);
|
Mvpp2PrsSramNextLuSet (&Pe, MVPP2_PRS_LU_MAC);
|
|
/* Unmask all Ports */
|
Mvpp2PrsTcamPortMapSet (&Pe, MVPP2_PRS_PORT_MASK);
|
|
/* Update shadow table and hw entry */
|
Mvpp2PrsShadowSet (Priv, Pe.Index, MVPP2_PRS_LU_MH);
|
Mvpp2PrsHwWrite (Priv, &Pe);
|
}
|
|
/*
|
* Set default entires (place holder) for promiscuous, non-promiscuous and
|
* multicast MAC Addresses
|
*/
|
STATIC
|
VOID
|
Mvpp2PrsMacInit (
|
IN MVPP2_SHARED *Priv
|
)
|
{
|
MVPP2_PRS_ENTRY Pe;
|
|
Mvpp2Memset (&Pe, 0, sizeof (MVPP2_PRS_ENTRY));
|
|
/* Non-promiscuous mode for all Ports - DROP unknown packets */
|
Pe.Index = MVPP2_PE_MAC_NON_PROMISCUOUS;
|
Mvpp2PrsTcamLuSet (&Pe, MVPP2_PRS_LU_MAC);
|
|
Mvpp2PrsSramRiUpdate (&Pe, MVPP2_PRS_RI_DROP_MASK, MVPP2_PRS_RI_DROP_MASK);
|
Mvpp2PrsSramBitsSet (&Pe, MVPP2_PRS_SRAM_LU_GEN_BIT, 1);
|
Mvpp2PrsSramNextLuSet (&Pe, MVPP2_PRS_LU_FLOWS);
|
|
/* Unmask all Ports */
|
Mvpp2PrsTcamPortMapSet (&Pe, MVPP2_PRS_PORT_MASK);
|
|
/* Update shadow table and hw entry */
|
Mvpp2PrsShadowSet (Priv, Pe.Index, MVPP2_PRS_LU_MAC);
|
Mvpp2PrsHwWrite (Priv, &Pe);
|
|
/* Place holders only - no Ports */
|
Mvpp2PrsMacDropAllSet (Priv, 0, FALSE);
|
Mvpp2PrsMacPromiscSet (Priv, 0, FALSE);
|
Mvpp2PrsMacMultiSet (Priv, MVPP2_PE_MAC_MC_ALL, 0, FALSE);
|
Mvpp2PrsMacMultiSet (Priv, MVPP2_PE_MAC_MC_IP6, 0, FALSE);
|
}
|
|
/* Set default entries for various types of dsa packets */
|
STATIC
|
VOID
|
Mvpp2PrsDsaInit (
|
IN MVPP2_SHARED *Priv
|
)
|
{
|
MVPP2_PRS_ENTRY Pe;
|
|
/* None tagged EDSA entry - place holder */
|
Mvpp2PrsDsaTagSet (Priv, 0, FALSE, MVPP2_PRS_UNTAGGED, MVPP2_PRS_EDSA);
|
|
/* Tagged EDSA entry - place holder */
|
Mvpp2PrsDsaTagSet (Priv, 0, FALSE, MVPP2_PRS_TAGGED, MVPP2_PRS_EDSA);
|
|
/* None tagged DSA entry - place holder */
|
Mvpp2PrsDsaTagSet (Priv, 0, FALSE, MVPP2_PRS_UNTAGGED, MVPP2_PRS_DSA);
|
|
/* Tagged DSA entry - place holder */
|
Mvpp2PrsDsaTagSet (Priv, 0, FALSE, MVPP2_PRS_TAGGED, MVPP2_PRS_DSA);
|
|
/* None tagged EDSA ethertype entry - place holder*/
|
Mvpp2PrsDsaTagEthertypeSet (Priv, 0, FALSE, MVPP2_PRS_UNTAGGED, MVPP2_PRS_EDSA);
|
|
/* Tagged EDSA ethertype entry - place holder*/
|
Mvpp2PrsDsaTagEthertypeSet (Priv, 0, FALSE, MVPP2_PRS_TAGGED, MVPP2_PRS_EDSA);
|
|
/* None tagged DSA ethertype entry */
|
Mvpp2PrsDsaTagEthertypeSet (Priv, 0, TRUE, MVPP2_PRS_UNTAGGED, MVPP2_PRS_DSA);
|
|
/* Tagged DSA ethertype entry */
|
Mvpp2PrsDsaTagEthertypeSet (Priv, 0, TRUE, MVPP2_PRS_TAGGED, MVPP2_PRS_DSA);
|
|
/* Set default entry, in case DSA or EDSA tag not found */
|
Mvpp2Memset (&Pe, 0, sizeof (MVPP2_PRS_ENTRY));
|
Mvpp2PrsTcamLuSet (&Pe, MVPP2_PRS_LU_DSA);
|
Pe.Index = MVPP2_PE_DSA_DEFAULT;
|
Mvpp2PrsSramNextLuSet (&Pe, MVPP2_PRS_LU_VLAN);
|
|
/* Shift 0 bytes */
|
Mvpp2PrsSramShiftSet (&Pe, 0, MVPP2_PRS_SRAM_OP_SEL_SHIFT_ADD);
|
Mvpp2PrsShadowSet (Priv, Pe.Index, MVPP2_PRS_LU_MAC);
|
|
/* Clear all Sram ai bits for next iteration */
|
Mvpp2PrsSramAiUpdate (&Pe, 0, MVPP2_PRS_SRAM_AI_MASK);
|
|
/* Unmask all Ports */
|
Mvpp2PrsTcamPortMapSet (&Pe, MVPP2_PRS_PORT_MASK);
|
|
Mvpp2PrsHwWrite (Priv, &Pe);
|
}
|
|
/* Match basic ethertypes */
|
STATIC
|
INT32
|
Mvpp2PrsEtypeInit (
|
IN MVPP2_SHARED *Priv
|
)
|
{
|
MVPP2_PRS_ENTRY Pe;
|
INT32 Tid;
|
|
/* Ethertype: PPPoE */
|
Tid = Mvpp2PrsTcamFirstFree (Priv, MVPP2_PE_FIRST_FREE_TID, MVPP2_PE_LAST_FREE_TID);
|
if (Tid < 0) {
|
return Tid;
|
}
|
|
Mvpp2Memset (&Pe, 0, sizeof (MVPP2_PRS_ENTRY));
|
Mvpp2PrsTcamLuSet (&Pe, MVPP2_PRS_LU_L2);
|
Pe.Index = Tid;
|
|
/* Set PPPoE type offset to 0 - obtained from Marvell */
|
Mvpp2PrsMatchEtype (&Pe, 0, MV_ETH_P_PPP_SES);
|
|
Mvpp2PrsSramShiftSet (&Pe, MVPP2_PPPOE_HDR_SIZE, MVPP2_PRS_SRAM_OP_SEL_SHIFT_ADD);
|
Mvpp2PrsSramNextLuSet (&Pe, MVPP2_PRS_LU_PPPOE);
|
Mvpp2PrsSramRiUpdate (&Pe, MVPP2_PRS_RI_PPPOE_MASK, MVPP2_PRS_RI_PPPOE_MASK);
|
|
/* Update shadow table and hw entry */
|
Mvpp2PrsShadowSet (Priv, Pe.Index, MVPP2_PRS_LU_L2);
|
Priv->PrsShadow[Pe.Index].Udf = MVPP2_PRS_UDF_L2_DEF;
|
Priv->PrsShadow[Pe.Index].Finish = FALSE;
|
Mvpp2PrsShadowRiSet (Priv, Pe.Index, MVPP2_PRS_RI_PPPOE_MASK, MVPP2_PRS_RI_PPPOE_MASK);
|
Mvpp2PrsHwWrite (Priv, &Pe);
|
|
/* Ethertype: ARP */
|
Tid = Mvpp2PrsTcamFirstFree (Priv, MVPP2_PE_FIRST_FREE_TID, MVPP2_PE_LAST_FREE_TID);
|
if (Tid < 0) {
|
return Tid;
|
}
|
|
Mvpp2Memset (&Pe, 0, sizeof (MVPP2_PRS_ENTRY));
|
Mvpp2PrsTcamLuSet (&Pe, MVPP2_PRS_LU_L2);
|
Pe.Index = Tid;
|
|
/* Set ARP type offset to 0 - obtained from Marvell */
|
Mvpp2PrsMatchEtype (&Pe, 0, MV_ETH_P_ARP);
|
|
/* Generate Flow in the next iteration*/
|
Mvpp2PrsSramNextLuSet (&Pe, MVPP2_PRS_LU_FLOWS);
|
Mvpp2PrsSramBitsSet (&Pe, MVPP2_PRS_SRAM_LU_GEN_BIT, 1);
|
Mvpp2PrsSramRiUpdate (&Pe, MVPP2_PRS_RI_L3_ARP, MVPP2_PRS_RI_L3_PROTO_MASK);
|
|
/* Set L3 Offset */
|
Mvpp2PrsSramOffsetSet (&Pe, MVPP2_PRS_SRAM_UDF_TYPE_L3, MVPP2_ETH_TYPE_LEN, MVPP2_PRS_SRAM_OP_SEL_UDF_ADD);
|
|
/* Update shadow table and hw entry */
|
Mvpp2PrsShadowSet (Priv, Pe.Index, MVPP2_PRS_LU_L2);
|
Priv->PrsShadow[Pe.Index].Udf = MVPP2_PRS_UDF_L2_DEF;
|
Priv->PrsShadow[Pe.Index].Finish = TRUE;
|
Mvpp2PrsShadowRiSet (Priv, Pe.Index, MVPP2_PRS_RI_L3_ARP, MVPP2_PRS_RI_L3_PROTO_MASK);
|
Mvpp2PrsHwWrite (Priv, &Pe);
|
|
/* Ethertype: LBTD */
|
Tid = Mvpp2PrsTcamFirstFree (Priv, MVPP2_PE_FIRST_FREE_TID, MVPP2_PE_LAST_FREE_TID);
|
if (Tid < 0) {
|
return Tid;
|
}
|
|
Mvpp2Memset (&Pe, 0, sizeof (MVPP2_PRS_ENTRY));
|
Mvpp2PrsTcamLuSet (&Pe, MVPP2_PRS_LU_L2);
|
Pe.Index = Tid;
|
|
/* Set LBTD type offset to 0 - obtained from Marvell */
|
Mvpp2PrsMatchEtype (&Pe, 0, MVPP2_IP_LBDT_TYPE);
|
|
/* Generate Flow in the next iteration*/
|
Mvpp2PrsSramNextLuSet (&Pe, MVPP2_PRS_LU_FLOWS);
|
Mvpp2PrsSramBitsSet (&Pe, MVPP2_PRS_SRAM_LU_GEN_BIT, 1);
|
Mvpp2PrsSramRiUpdate (
|
&Pe,
|
MVPP2_PRS_RI_CPU_CODE_RX_SPEC | MVPP2_PRS_RI_UDF3_RX_SPECIAL,
|
MVPP2_PRS_RI_CPU_CODE_MASK | MVPP2_PRS_RI_UDF3_MASK
|
);
|
|
/* Set L3 Offset */
|
Mvpp2PrsSramOffsetSet (&Pe, MVPP2_PRS_SRAM_UDF_TYPE_L3, MVPP2_ETH_TYPE_LEN, MVPP2_PRS_SRAM_OP_SEL_UDF_ADD);
|
|
/* Update shadow table and hw entry */
|
Mvpp2PrsShadowSet (Priv, Pe.Index, MVPP2_PRS_LU_L2);
|
Priv->PrsShadow[Pe.Index].Udf = MVPP2_PRS_UDF_L2_DEF;
|
Priv->PrsShadow[Pe.Index].Finish = TRUE;
|
Mvpp2PrsShadowRiSet (
|
Priv,
|
Pe.Index,
|
MVPP2_PRS_RI_CPU_CODE_RX_SPEC | MVPP2_PRS_RI_UDF3_RX_SPECIAL,
|
MVPP2_PRS_RI_CPU_CODE_MASK | MVPP2_PRS_RI_UDF3_MASK
|
);
|
|
Mvpp2PrsHwWrite (Priv, &Pe);
|
|
/* Ethertype: IPv4 without options */
|
Tid = Mvpp2PrsTcamFirstFree (Priv, MVPP2_PE_FIRST_FREE_TID, MVPP2_PE_LAST_FREE_TID);
|
if (Tid < 0) {
|
return Tid;
|
}
|
|
Mvpp2Memset (&Pe, 0, sizeof (MVPP2_PRS_ENTRY));
|
Mvpp2PrsTcamLuSet (&Pe, MVPP2_PRS_LU_L2);
|
Pe.Index = Tid;
|
|
/* Set IPv4 type offset to 0 - obtained from Marvell */
|
Mvpp2PrsMatchEtype (&Pe, 0, MV_ETH_P_IP);
|
Mvpp2PrsTcamDataByteSet (
|
&Pe,
|
MVPP2_ETH_TYPE_LEN,
|
MVPP2_PRS_IPV4_HEAD | MVPP2_PRS_IPV4_IHL,
|
MVPP2_PRS_IPV4_HEAD_MASK | MVPP2_PRS_IPV4_IHL_MASK
|
);
|
|
Mvpp2PrsSramNextLuSet (&Pe, MVPP2_PRS_LU_IP4);
|
Mvpp2PrsSramRiUpdate (&Pe, MVPP2_PRS_RI_L3_IP4, MVPP2_PRS_RI_L3_PROTO_MASK);
|
|
/* Skip EthType + 4 bytes of IP header */
|
Mvpp2PrsSramShiftSet (&Pe, MVPP2_ETH_TYPE_LEN + 4, MVPP2_PRS_SRAM_OP_SEL_SHIFT_ADD);
|
|
/* Set L3 Offset */
|
Mvpp2PrsSramOffsetSet (&Pe, MVPP2_PRS_SRAM_UDF_TYPE_L3, MVPP2_ETH_TYPE_LEN, MVPP2_PRS_SRAM_OP_SEL_UDF_ADD);
|
|
/* Update shadow table and hw entry */
|
Mvpp2PrsShadowSet (Priv, Pe.Index, MVPP2_PRS_LU_L2);
|
Priv->PrsShadow[Pe.Index].Udf = MVPP2_PRS_UDF_L2_DEF;
|
Priv->PrsShadow[Pe.Index].Finish = FALSE;
|
Mvpp2PrsShadowRiSet (Priv, Pe.Index, MVPP2_PRS_RI_L3_IP4, MVPP2_PRS_RI_L3_PROTO_MASK);
|
Mvpp2PrsHwWrite (Priv, &Pe);
|
|
/* Ethertype: IPv4 with options */
|
Tid = Mvpp2PrsTcamFirstFree (Priv, MVPP2_PE_FIRST_FREE_TID, MVPP2_PE_LAST_FREE_TID);
|
if (Tid < 0) {
|
return Tid;
|
}
|
|
Pe.Index = Tid;
|
|
/* Clear Tcam data before updating */
|
Pe.Tcam.Byte[MVPP2_PRS_TCAM_DATA_BYTE(MVPP2_ETH_TYPE_LEN)] = 0x0;
|
Pe.Tcam.Byte[MVPP2_PRS_TCAM_DATA_BYTE_EN(MVPP2_ETH_TYPE_LEN)] = 0x0;
|
|
Mvpp2PrsTcamDataByteSet (&Pe, MVPP2_ETH_TYPE_LEN, MVPP2_PRS_IPV4_HEAD, MVPP2_PRS_IPV4_HEAD_MASK);
|
|
/* Clear Ri before updating */
|
Pe.Sram.Word[MVPP2_PRS_SRAM_RI_WORD] = 0x0;
|
Pe.Sram.Word[MVPP2_PRS_SRAM_RI_CTRL_WORD] = 0x0;
|
Mvpp2PrsSramRiUpdate (&Pe, MVPP2_PRS_RI_L3_IP4_OPT, MVPP2_PRS_RI_L3_PROTO_MASK);
|
|
/* Update shadow table and hw entry */
|
Mvpp2PrsShadowSet (Priv, Pe.Index, MVPP2_PRS_LU_L2);
|
Priv->PrsShadow[Pe.Index].Udf = MVPP2_PRS_UDF_L2_DEF;
|
Priv->PrsShadow[Pe.Index].Finish = FALSE;
|
Mvpp2PrsShadowRiSet (Priv, Pe.Index, MVPP2_PRS_RI_L3_IP4_OPT, MVPP2_PRS_RI_L3_PROTO_MASK);
|
Mvpp2PrsHwWrite (Priv, &Pe);
|
|
/* Ethertype: IPv6 without options */
|
Tid = Mvpp2PrsTcamFirstFree (Priv, MVPP2_PE_FIRST_FREE_TID, MVPP2_PE_LAST_FREE_TID);
|
if (Tid < 0) {
|
return Tid;
|
}
|
|
Mvpp2Memset (&Pe, 0, sizeof (MVPP2_PRS_ENTRY));
|
Mvpp2PrsTcamLuSet (&Pe, MVPP2_PRS_LU_L2);
|
Pe.Index = Tid;
|
|
/* Set IPv6 type offset to 0 - obtained from Marvell */
|
Mvpp2PrsMatchEtype (&Pe, 0, MV_ETH_P_IPV6);
|
|
/* Skip DIP of IPV6 header - value provided by Marvell */
|
Mvpp2PrsSramShiftSet (&Pe, MVPP2_ETH_TYPE_LEN + 8 + MVPP2_MAX_L3_ADDR_SIZE, MVPP2_PRS_SRAM_OP_SEL_SHIFT_ADD);
|
Mvpp2PrsSramNextLuSet (&Pe, MVPP2_PRS_LU_IP6);
|
Mvpp2PrsSramRiUpdate (&Pe, MVPP2_PRS_RI_L3_IP6, MVPP2_PRS_RI_L3_PROTO_MASK);
|
|
/* Set L3 Offset */
|
Mvpp2PrsSramOffsetSet (&Pe, MVPP2_PRS_SRAM_UDF_TYPE_L3, MVPP2_ETH_TYPE_LEN, MVPP2_PRS_SRAM_OP_SEL_UDF_ADD);
|
|
/* Update shadow table and hw entry */
|
Mvpp2PrsShadowSet (Priv, Pe.Index, MVPP2_PRS_LU_L2);
|
Priv->PrsShadow[Pe.Index].Udf = MVPP2_PRS_UDF_L2_DEF;
|
Priv->PrsShadow[Pe.Index].Finish = FALSE;
|
Mvpp2PrsShadowRiSet (Priv, Pe.Index, MVPP2_PRS_RI_L3_IP6, MVPP2_PRS_RI_L3_PROTO_MASK);
|
Mvpp2PrsHwWrite (Priv, &Pe);
|
|
/* Default entry for MVPP2_PRS_LU_L2 - Unknown ethtype */
|
Mvpp2Memset (&Pe, 0, sizeof (MVPP2_PRS_ENTRY));
|
Mvpp2PrsTcamLuSet (&Pe, MVPP2_PRS_LU_L2);
|
Pe.Index = MVPP2_PE_ETH_TYPE_UN;
|
|
/* Unmask all Ports */
|
Mvpp2PrsTcamPortMapSet (&Pe, MVPP2_PRS_PORT_MASK);
|
|
/* Generate Flow in the next iteration*/
|
Mvpp2PrsSramBitsSet (&Pe, MVPP2_PRS_SRAM_LU_GEN_BIT, 1);
|
Mvpp2PrsSramNextLuSet (&Pe, MVPP2_PRS_LU_FLOWS);
|
Mvpp2PrsSramRiUpdate (&Pe, MVPP2_PRS_RI_L3_UN, MVPP2_PRS_RI_L3_PROTO_MASK);
|
|
/* Set L3 Offset even it's unknown L3 */
|
Mvpp2PrsSramOffsetSet (&Pe, MVPP2_PRS_SRAM_UDF_TYPE_L3, MVPP2_ETH_TYPE_LEN, MVPP2_PRS_SRAM_OP_SEL_UDF_ADD);
|
|
/* Update shadow table and hw entry */
|
Mvpp2PrsShadowSet (Priv, Pe.Index, MVPP2_PRS_LU_L2);
|
Priv->PrsShadow[Pe.Index].Udf = MVPP2_PRS_UDF_L2_DEF;
|
Priv->PrsShadow[Pe.Index].Finish = TRUE;
|
Mvpp2PrsShadowRiSet (Priv, Pe.Index, MVPP2_PRS_RI_L3_UN, MVPP2_PRS_RI_L3_PROTO_MASK);
|
Mvpp2PrsHwWrite (Priv, &Pe);
|
|
return 0;
|
}
|
|
/*
|
* Configure vlan entries and detect up to 2 successive VLAN tags.
|
* Possible options:
|
* 0x8100, 0x88A8
|
* 0x8100, 0x8100
|
* 0x8100, 0x88A8
|
*/
|
STATIC
|
INT32
|
Mvpp2PrsVlanInit (
|
IN MVPP2_SHARED *Priv
|
)
|
{
|
MVPP2_PRS_ENTRY Pe;
|
INT32 Err;
|
|
/* Double VLAN: 0x8100, 0x88A8 */
|
Err = Mvpp2PrsDoubleVlanAdd (Priv, MV_ETH_P_8021Q, MV_ETH_P_8021AD, MVPP2_PRS_PORT_MASK);
|
if (Err != 0) {
|
return Err;
|
}
|
|
/* Double VLAN: 0x8100, 0x8100 */
|
Err = Mvpp2PrsDoubleVlanAdd (Priv, MV_ETH_P_8021Q, MV_ETH_P_8021Q, MVPP2_PRS_PORT_MASK);
|
if (Err != 0) {
|
return Err;
|
}
|
|
/* Single VLAN: 0x88a8 */
|
Err = Mvpp2PrsVlanAdd (Priv, MV_ETH_P_8021AD, MVPP2_PRS_SINGLE_VLAN_AI, MVPP2_PRS_PORT_MASK);
|
if (Err != 0) {
|
return Err;
|
}
|
|
/* Single VLAN: 0x8100 */
|
Err = Mvpp2PrsVlanAdd (Priv, MV_ETH_P_8021Q, MVPP2_PRS_SINGLE_VLAN_AI, MVPP2_PRS_PORT_MASK);
|
if (Err != 0) {
|
return Err;
|
}
|
|
/* Set default double vlan entry */
|
Mvpp2Memset (&Pe, 0, sizeof (MVPP2_PRS_ENTRY));
|
Mvpp2PrsTcamLuSet (&Pe, MVPP2_PRS_LU_VLAN);
|
Pe.Index = MVPP2_PE_VLAN_DBL;
|
|
Mvpp2PrsSramNextLuSet (&Pe, MVPP2_PRS_LU_L2);
|
|
/* Clear ai for next iterations */
|
Mvpp2PrsSramAiUpdate (&Pe, 0, MVPP2_PRS_SRAM_AI_MASK);
|
Mvpp2PrsSramRiUpdate (&Pe, MVPP2_PRS_RI_VLAN_DOUBLE, MVPP2_PRS_RI_VLAN_MASK);
|
|
Mvpp2PrsTcamAiUpdate (&Pe, MVPP2_PRS_DBL_VLAN_AI_BIT, MVPP2_PRS_DBL_VLAN_AI_BIT);
|
|
/* Unmask all Ports */
|
Mvpp2PrsTcamPortMapSet (&Pe, MVPP2_PRS_PORT_MASK);
|
|
/* Update shadow table and hw entry */
|
Mvpp2PrsShadowSet (Priv, Pe.Index, MVPP2_PRS_LU_VLAN);
|
Mvpp2PrsHwWrite (Priv, &Pe);
|
|
/* Set default vlan none entry */
|
Mvpp2Memset (&Pe, 0, sizeof (MVPP2_PRS_ENTRY));
|
Mvpp2PrsTcamLuSet (&Pe, MVPP2_PRS_LU_VLAN);
|
Pe.Index = MVPP2_PE_VLAN_NONE;
|
|
Mvpp2PrsSramNextLuSet (&Pe, MVPP2_PRS_LU_L2);
|
Mvpp2PrsSramRiUpdate (&Pe, MVPP2_PRS_RI_VLAN_NONE, MVPP2_PRS_RI_VLAN_MASK);
|
|
/* Unmask all Ports */
|
Mvpp2PrsTcamPortMapSet (&Pe, MVPP2_PRS_PORT_MASK);
|
|
/* Update shadow table and hw entry */
|
Mvpp2PrsShadowSet (Priv, Pe.Index, MVPP2_PRS_LU_VLAN);
|
Mvpp2PrsHwWrite (Priv, &Pe);
|
|
return 0;
|
}
|
|
/* Set entries for PPPoE ethertype */
|
STATIC
|
INT32
|
Mvpp2PrsPppoeInit (
|
IN MVPP2_SHARED *Priv
|
)
|
{
|
MVPP2_PRS_ENTRY Pe;
|
INT32 Tid;
|
|
/* IPv4 over PPPoE with options */
|
Tid = Mvpp2PrsTcamFirstFree (Priv, MVPP2_PE_FIRST_FREE_TID, MVPP2_PE_LAST_FREE_TID);
|
if (Tid < 0) {
|
return Tid;
|
}
|
|
Mvpp2Memset (&Pe, 0, sizeof (MVPP2_PRS_ENTRY));
|
Mvpp2PrsTcamLuSet (&Pe, MVPP2_PRS_LU_PPPOE);
|
Pe.Index = Tid;
|
|
/* Set IPv4 over PPPoE type offset to 0 - obtained from Marvell */
|
Mvpp2PrsMatchEtype (&Pe, 0, MV_PPP_IP);
|
|
Mvpp2PrsSramNextLuSet (&Pe, MVPP2_PRS_LU_IP4);
|
Mvpp2PrsSramRiUpdate (&Pe, MVPP2_PRS_RI_L3_IP4_OPT, MVPP2_PRS_RI_L3_PROTO_MASK);
|
|
/* Skip EthType + 4 bytes of IP header */
|
Mvpp2PrsSramShiftSet (&Pe, MVPP2_ETH_TYPE_LEN + 4, MVPP2_PRS_SRAM_OP_SEL_SHIFT_ADD);
|
|
/* Set L3 Offset */
|
Mvpp2PrsSramOffsetSet (&Pe, MVPP2_PRS_SRAM_UDF_TYPE_L3, MVPP2_ETH_TYPE_LEN, MVPP2_PRS_SRAM_OP_SEL_UDF_ADD);
|
|
/* Update shadow table and hw entry */
|
Mvpp2PrsShadowSet (Priv, Pe.Index, MVPP2_PRS_LU_PPPOE);
|
Mvpp2PrsHwWrite (Priv, &Pe);
|
|
/* IPv4 over PPPoE without options */
|
Tid = Mvpp2PrsTcamFirstFree (Priv, MVPP2_PE_FIRST_FREE_TID, MVPP2_PE_LAST_FREE_TID);
|
if (Tid < 0) {
|
return Tid;
|
}
|
|
Pe.Index = Tid;
|
|
Mvpp2PrsTcamDataByteSet (
|
&Pe,
|
MVPP2_ETH_TYPE_LEN,
|
MVPP2_PRS_IPV4_HEAD | MVPP2_PRS_IPV4_IHL,
|
MVPP2_PRS_IPV4_HEAD_MASK | MVPP2_PRS_IPV4_IHL_MASK
|
);
|
|
/* Clear Ri before updating */
|
Pe.Sram.Word[MVPP2_PRS_SRAM_RI_WORD] = 0x0;
|
Pe.Sram.Word[MVPP2_PRS_SRAM_RI_CTRL_WORD] = 0x0;
|
Mvpp2PrsSramRiUpdate (&Pe, MVPP2_PRS_RI_L3_IP4, MVPP2_PRS_RI_L3_PROTO_MASK);
|
|
/* Update shadow table and hw entry */
|
Mvpp2PrsShadowSet (Priv, Pe.Index, MVPP2_PRS_LU_PPPOE);
|
Mvpp2PrsHwWrite (Priv, &Pe);
|
|
/* IPv6 over PPPoE */
|
Tid = Mvpp2PrsTcamFirstFree (Priv, MVPP2_PE_FIRST_FREE_TID, MVPP2_PE_LAST_FREE_TID);
|
if (Tid < 0) {
|
return Tid;
|
}
|
|
Mvpp2Memset (&Pe, 0, sizeof (MVPP2_PRS_ENTRY));
|
Mvpp2PrsTcamLuSet (&Pe, MVPP2_PRS_LU_PPPOE);
|
Pe.Index = Tid;
|
|
/* Set IPv6 over PPPoE type offset to 0 - obtained from Marvell */
|
Mvpp2PrsMatchEtype (&Pe, 0, MV_PPP_IPV6);
|
|
Mvpp2PrsSramNextLuSet (&Pe, MVPP2_PRS_LU_IP6);
|
Mvpp2PrsSramRiUpdate (&Pe, MVPP2_PRS_RI_L3_IP6, MVPP2_PRS_RI_L3_PROTO_MASK);
|
|
/* Skip EthType + 4 bytes of IPv6 header */
|
Mvpp2PrsSramShiftSet (&Pe, MVPP2_ETH_TYPE_LEN + 4, MVPP2_PRS_SRAM_OP_SEL_SHIFT_ADD);
|
|
/* Set L3 Offset */
|
Mvpp2PrsSramOffsetSet (&Pe, MVPP2_PRS_SRAM_UDF_TYPE_L3, MVPP2_ETH_TYPE_LEN, MVPP2_PRS_SRAM_OP_SEL_UDF_ADD);
|
|
/* Update shadow table and hw entry */
|
Mvpp2PrsShadowSet (Priv, Pe.Index, MVPP2_PRS_LU_PPPOE);
|
Mvpp2PrsHwWrite (Priv, &Pe);
|
|
/* Non-IP over PPPoE */
|
Tid = Mvpp2PrsTcamFirstFree (Priv, MVPP2_PE_FIRST_FREE_TID, MVPP2_PE_LAST_FREE_TID);
|
if (Tid < 0) {
|
return Tid;
|
}
|
|
Mvpp2Memset (&Pe, 0, sizeof (MVPP2_PRS_ENTRY));
|
Mvpp2PrsTcamLuSet (&Pe, MVPP2_PRS_LU_PPPOE);
|
Pe.Index = Tid;
|
|
Mvpp2PrsSramRiUpdate (&Pe, MVPP2_PRS_RI_L3_UN, MVPP2_PRS_RI_L3_PROTO_MASK);
|
|
/* Finished: go to Flowid generation */
|
Mvpp2PrsSramNextLuSet (&Pe, MVPP2_PRS_LU_FLOWS);
|
Mvpp2PrsSramBitsSet (&Pe, MVPP2_PRS_SRAM_LU_GEN_BIT, 1);
|
|
/* Set L3 Offset even if it's unknown L3 */
|
Mvpp2PrsSramOffsetSet (&Pe, MVPP2_PRS_SRAM_UDF_TYPE_L3, MVPP2_ETH_TYPE_LEN, MVPP2_PRS_SRAM_OP_SEL_UDF_ADD);
|
|
/* Update shadow table and hw entry */
|
Mvpp2PrsShadowSet (Priv, Pe.Index, MVPP2_PRS_LU_PPPOE);
|
Mvpp2PrsHwWrite (Priv, &Pe);
|
|
return 0;
|
}
|
|
/* Initialize entries for IPv4 */
|
STATIC
|
INT32
|
Mvpp2PrsIp4Init (
|
IN MVPP2_SHARED *Priv
|
)
|
{
|
MVPP2_PRS_ENTRY Pe;
|
INT32 Err;
|
|
/* Set entries for TCP, UDP and IGMP over IPv4 */
|
Err = Mvpp2PrsIp4Proto (Priv, MV_IPPR_TCP, MVPP2_PRS_RI_L4_TCP, MVPP2_PRS_RI_L4_PROTO_MASK);
|
if (Err != 0) {
|
return Err;
|
}
|
|
Err = Mvpp2PrsIp4Proto (Priv, MV_IPPR_UDP, MVPP2_PRS_RI_L4_UDP, MVPP2_PRS_RI_L4_PROTO_MASK);
|
if (Err != 0) {
|
return Err;
|
}
|
|
Err = Mvpp2PrsIp4Proto (
|
Priv,
|
MV_IPPR_IGMP,
|
MVPP2_PRS_RI_CPU_CODE_RX_SPEC | MVPP2_PRS_RI_UDF3_RX_SPECIAL,
|
MVPP2_PRS_RI_CPU_CODE_MASK | MVPP2_PRS_RI_UDF3_MASK
|
);
|
|
if (Err != 0) {
|
return Err;
|
}
|
|
/* IPv4 Broadcast */
|
Err = Mvpp2PrsIp4Cast (Priv, MVPP2_PRS_L3_BROAD_CAST);
|
if (Err != 0) {
|
return Err;
|
}
|
|
/* IPv4 Multicast */
|
Err = Mvpp2PrsIp4Cast (Priv, MVPP2_PRS_L3_MULTI_CAST);
|
if (Err != 0) {
|
return Err;
|
}
|
|
/* Default IPv4 entry for unknown protocols */
|
Mvpp2Memset (&Pe, 0, sizeof (MVPP2_PRS_ENTRY));
|
Mvpp2PrsTcamLuSet (&Pe, MVPP2_PRS_LU_IP4);
|
Pe.Index = MVPP2_PE_IP4_PROTO_UN;
|
|
/* Set next Lu to IPv4 and shift by 12 bytes - obtained from Marvell*/
|
Mvpp2PrsSramNextLuSet (&Pe, MVPP2_PRS_LU_IP4);
|
Mvpp2PrsSramShiftSet (&Pe, 12, MVPP2_PRS_SRAM_OP_SEL_SHIFT_ADD);
|
|
/* Set L4 offset 4 bytes relative IPv4 header size (current position) */
|
Mvpp2PrsSramOffsetSet (
|
&Pe,
|
MVPP2_PRS_SRAM_UDF_TYPE_L4,
|
sizeof (Mvpp2Iphdr) - 4,
|
MVPP2_PRS_SRAM_OP_SEL_UDF_ADD
|
);
|
|
Mvpp2PrsSramAiUpdate (&Pe, MVPP2_PRS_IPV4_DIP_AI_BIT, MVPP2_PRS_IPV4_DIP_AI_BIT);
|
Mvpp2PrsSramRiUpdate (&Pe, MVPP2_PRS_RI_L4_OTHER, MVPP2_PRS_RI_L4_PROTO_MASK);
|
|
Mvpp2PrsTcamAiUpdate (&Pe, 0, MVPP2_PRS_IPV4_DIP_AI_BIT);
|
|
/* Unmask all Ports */
|
Mvpp2PrsTcamPortMapSet (&Pe, MVPP2_PRS_PORT_MASK);
|
|
/* Update shadow table and hw entry */
|
Mvpp2PrsShadowSet (Priv, Pe.Index, MVPP2_PRS_LU_IP4);
|
Mvpp2PrsHwWrite (Priv, &Pe);
|
|
/* Default IPv4 entry for unicast Address */
|
Mvpp2Memset (&Pe, 0, sizeof (MVPP2_PRS_ENTRY));
|
Mvpp2PrsTcamLuSet (&Pe, MVPP2_PRS_LU_IP4);
|
Pe.Index = MVPP2_PE_IP4_ADDR_UN;
|
|
/* Finished: go to Flowid generation */
|
Mvpp2PrsSramNextLuSet (&Pe, MVPP2_PRS_LU_FLOWS);
|
Mvpp2PrsSramBitsSet (&Pe, MVPP2_PRS_SRAM_LU_GEN_BIT, 1);
|
Mvpp2PrsSramRiUpdate (&Pe, MVPP2_PRS_RI_L3_UCAST, MVPP2_PRS_RI_L3_ADDR_MASK);
|
|
Mvpp2PrsTcamAiUpdate (&Pe, MVPP2_PRS_IPV4_DIP_AI_BIT, MVPP2_PRS_IPV4_DIP_AI_BIT);
|
|
/* Unmask all Ports */
|
Mvpp2PrsTcamPortMapSet (&Pe, MVPP2_PRS_PORT_MASK);
|
|
/* Update shadow table and hw entry */
|
Mvpp2PrsShadowSet (Priv, Pe.Index, MVPP2_PRS_LU_IP4);
|
Mvpp2PrsHwWrite (Priv, &Pe);
|
|
return 0;
|
}
|
|
/* Initialize entries for IPv6 */
|
STATIC
|
INT32
|
Mvpp2PrsIp6Init (
|
IN MVPP2_SHARED *Priv
|
)
|
{
|
MVPP2_PRS_ENTRY Pe;
|
INT32 Tid, Err;
|
|
/* Set entries for TCP, UDP and ICMP over IPv6 */
|
Err = Mvpp2PrsIp6Proto (Priv, MV_IPPR_TCP, MVPP2_PRS_RI_L4_TCP, MVPP2_PRS_RI_L4_PROTO_MASK);
|
if (Err != 0) {
|
return Err;
|
}
|
|
Err = Mvpp2PrsIp6Proto (Priv, MV_IPPR_UDP, MVPP2_PRS_RI_L4_UDP, MVPP2_PRS_RI_L4_PROTO_MASK);
|
if (Err != 0) {
|
return Err;
|
}
|
|
Err = Mvpp2PrsIp6Proto (
|
Priv,
|
MV_IPPR_ICMPV6,
|
MVPP2_PRS_RI_CPU_CODE_RX_SPEC | MVPP2_PRS_RI_UDF3_RX_SPECIAL,
|
MVPP2_PRS_RI_CPU_CODE_MASK | MVPP2_PRS_RI_UDF3_MASK
|
);
|
|
if (Err != 0) {
|
return Err;
|
}
|
|
/*
|
* IPv4 is the last header. This is similar case as 6-TCP or 17-UDP
|
* Result Info: UDF7=1, DS lite
|
*/
|
Err = Mvpp2PrsIp6Proto (Priv, MV_IPPR_IPIP, MVPP2_PRS_RI_UDF7_IP6_LITE, MVPP2_PRS_RI_UDF7_MASK);
|
if (Err != 0) {
|
return Err;
|
}
|
|
/* IPv6 multicast */
|
Err = Mvpp2PrsIp6Cast (Priv, MVPP2_PRS_L3_MULTI_CAST);
|
if (Err != 0) {
|
return Err;
|
}
|
|
/* Entry for checking hop limit */
|
Tid = Mvpp2PrsTcamFirstFree (Priv, MVPP2_PE_FIRST_FREE_TID, MVPP2_PE_LAST_FREE_TID);
|
if (Tid < 0) {
|
return Tid;
|
}
|
|
Mvpp2Memset (&Pe, 0, sizeof (MVPP2_PRS_ENTRY));
|
Mvpp2PrsTcamLuSet (&Pe, MVPP2_PRS_LU_IP6);
|
Pe.Index = Tid;
|
|
/* Finished: go to Flowid generation */
|
Mvpp2PrsSramNextLuSet (&Pe, MVPP2_PRS_LU_FLOWS);
|
Mvpp2PrsSramBitsSet (&Pe, MVPP2_PRS_SRAM_LU_GEN_BIT, 1);
|
Mvpp2PrsSramRiUpdate (
|
&Pe,
|
MVPP2_PRS_RI_L3_UN | MVPP2_PRS_RI_DROP_MASK,
|
MVPP2_PRS_RI_L3_PROTO_MASK | MVPP2_PRS_RI_DROP_MASK
|
);
|
|
Mvpp2PrsTcamDataByteSet (&Pe, 1, 0x00, MVPP2_PRS_IPV6_HOP_MASK);
|
Mvpp2PrsTcamAiUpdate (&Pe, MVPP2_PRS_IPV6_NO_EXT_AI_BIT, MVPP2_PRS_IPV6_NO_EXT_AI_BIT);
|
|
/* Update shadow table and hw entry */
|
Mvpp2PrsShadowSet (Priv, Pe.Index, MVPP2_PRS_LU_IP4);
|
Mvpp2PrsHwWrite (Priv, &Pe);
|
|
/* Default IPv6 entry for unknown protocols */
|
Mvpp2Memset (&Pe, 0, sizeof (MVPP2_PRS_ENTRY));
|
Mvpp2PrsTcamLuSet (&Pe, MVPP2_PRS_LU_IP6);
|
Pe.Index = MVPP2_PE_IP6_PROTO_UN;
|
|
/* Finished: go to Flowid generation */
|
Mvpp2PrsSramNextLuSet (&Pe, MVPP2_PRS_LU_FLOWS);
|
Mvpp2PrsSramBitsSet (&Pe, MVPP2_PRS_SRAM_LU_GEN_BIT, 1);
|
Mvpp2PrsSramRiUpdate (&Pe, MVPP2_PRS_RI_L4_OTHER, MVPP2_PRS_RI_L4_PROTO_MASK);
|
|
/* Set L4 offset 6 bytes relative IPv6 header size (current position) */
|
Mvpp2PrsSramOffsetSet (
|
&Pe,
|
MVPP2_PRS_SRAM_UDF_TYPE_L4,
|
sizeof (Mvpp2Ipv6hdr) - 6,
|
MVPP2_PRS_SRAM_OP_SEL_UDF_ADD
|
);
|
|
Mvpp2PrsTcamAiUpdate (&Pe, MVPP2_PRS_IPV6_NO_EXT_AI_BIT, MVPP2_PRS_IPV6_NO_EXT_AI_BIT);
|
|
/* Unmask all Ports */
|
Mvpp2PrsTcamPortMapSet (&Pe, MVPP2_PRS_PORT_MASK);
|
|
/* Update shadow table and hw entry */
|
Mvpp2PrsShadowSet (Priv, Pe.Index, MVPP2_PRS_LU_IP4);
|
Mvpp2PrsHwWrite (Priv, &Pe);
|
|
/* Default IPv6 entry for unknown ext protocols */
|
Mvpp2Memset (&Pe, 0, sizeof (MVPP2_PRS_ENTRY));
|
Mvpp2PrsTcamLuSet (&Pe, MVPP2_PRS_LU_IP6);
|
Pe.Index = MVPP2_PE_IP6_EXT_PROTO_UN;
|
|
/* Finished: go to Flowid generation */
|
Mvpp2PrsSramNextLuSet (&Pe, MVPP2_PRS_LU_FLOWS);
|
Mvpp2PrsSramBitsSet (&Pe, MVPP2_PRS_SRAM_LU_GEN_BIT, 1);
|
Mvpp2PrsSramRiUpdate (&Pe, MVPP2_PRS_RI_L4_OTHER, MVPP2_PRS_RI_L4_PROTO_MASK);
|
|
Mvpp2PrsTcamAiUpdate (&Pe, MVPP2_PRS_IPV6_EXT_AI_BIT, MVPP2_PRS_IPV6_EXT_AI_BIT);
|
|
/* Unmask all Ports */
|
Mvpp2PrsTcamPortMapSet (&Pe, MVPP2_PRS_PORT_MASK);
|
|
/* Update shadow table and hw entry */
|
Mvpp2PrsShadowSet (Priv, Pe.Index, MVPP2_PRS_LU_IP4);
|
Mvpp2PrsHwWrite (Priv, &Pe);
|
|
/* Default IPv6 entry for unicast Address */
|
Mvpp2Memset (&Pe, 0, sizeof (MVPP2_PRS_ENTRY));
|
Mvpp2PrsTcamLuSet (&Pe, MVPP2_PRS_LU_IP6);
|
Pe.Index = MVPP2_PE_IP6_ADDR_UN;
|
|
/* Finished: go to IPv6 again */
|
Mvpp2PrsSramNextLuSet (&Pe, MVPP2_PRS_LU_IP6);
|
Mvpp2PrsSramRiUpdate (&Pe, MVPP2_PRS_RI_L3_UCAST, MVPP2_PRS_RI_L3_ADDR_MASK);
|
Mvpp2PrsSramAiUpdate (&Pe, MVPP2_PRS_IPV6_NO_EXT_AI_BIT, MVPP2_PRS_IPV6_NO_EXT_AI_BIT);
|
|
/* Shift back to IPv6 by 18 bytes - byte count provided by Marvell */
|
Mvpp2PrsSramShiftSet (&Pe, -18, MVPP2_PRS_SRAM_OP_SEL_SHIFT_ADD);
|
Mvpp2PrsTcamAiUpdate (&Pe, 0, MVPP2_PRS_IPV6_NO_EXT_AI_BIT);
|
|
/* Unmask all Ports */
|
Mvpp2PrsTcamPortMapSet (&Pe, MVPP2_PRS_PORT_MASK);
|
|
/* Update shadow table and hw entry */
|
Mvpp2PrsShadowSet (Priv, Pe.Index, MVPP2_PRS_LU_IP6);
|
Mvpp2PrsHwWrite (Priv, &Pe);
|
|
return 0;
|
}
|
|
/* Parser default initialization */
|
INT32
|
Mvpp2PrsDefaultInit (
|
IN MVPP2_SHARED *Priv
|
)
|
{
|
INT32 Err, Index, i;
|
|
/* Enable Tcam table */
|
Mvpp2Write (Priv, MVPP2_PRS_TCAM_CTRL_REG, MVPP2_PRS_TCAM_EN_MASK);
|
|
/* Clear all Tcam and Sram entries */
|
for (Index = 0; Index < MVPP2_PRS_TCAM_SRAM_SIZE; Index++) {
|
Mvpp2Write (Priv, MVPP2_PRS_TCAM_IDX_REG, Index);
|
for (i = 0; i < MVPP2_PRS_TCAM_WORDS; i++) {
|
Mvpp2Write (Priv, MVPP2_PRS_TCAM_DATA_REG(i), 0);
|
}
|
|
Mvpp2Write (Priv, MVPP2_PRS_SRAM_IDX_REG, Index);
|
for (i = 0; i < MVPP2_PRS_SRAM_WORDS; i++) {
|
Mvpp2Write (Priv, MVPP2_PRS_SRAM_DATA_REG(i), 0);
|
}
|
}
|
|
/* Invalidate all Tcam entries */
|
for (Index = 0; Index < MVPP2_PRS_TCAM_SRAM_SIZE; Index++) {
|
Mvpp2PrsHwInv (Priv, Index);
|
}
|
|
/* Always start from lookup = 0 */
|
for (Index = 0; Index < MVPP2_MAX_PORTS; Index++) {
|
Mvpp2PrsHwPortInit (Priv, Index, MVPP2_PRS_LU_MH, MVPP2_PRS_PORT_LU_MAX, 0);
|
}
|
|
Mvpp2PrsDefFlowInit (Priv);
|
|
Mvpp2PrsMhInit (Priv);
|
|
Mvpp2PrsMacInit (Priv);
|
|
Mvpp2PrsDsaInit (Priv);
|
|
Err = Mvpp2PrsEtypeInit (Priv);
|
if (Err != 0) {
|
return Err;
|
}
|
|
Err = Mvpp2PrsVlanInit (Priv);
|
if (Err != 0) {
|
return Err;
|
}
|
|
Err = Mvpp2PrsPppoeInit (Priv);
|
if (Err != 0) {
|
return Err;
|
}
|
|
Err = Mvpp2PrsIp6Init (Priv);
|
if (Err != 0) {
|
return Err;
|
}
|
|
Err = Mvpp2PrsIp4Init (Priv);
|
if (Err != 0) {
|
return Err;
|
}
|
|
return 0;
|
}
|
|
/* Compare MAC DA with Tcam entry data */
|
STATIC
|
BOOLEAN
|
Mvpp2PrsMacRangeEquals (
|
IN MVPP2_PRS_ENTRY *Pe,
|
IN const UINT8 *Da,
|
IN UINT8 *Mask
|
)
|
{
|
UINT8 TcamByte, TcamMask;
|
INT32 Index;
|
|
for (Index = 0; Index < MV_ETH_ALEN; Index++) {
|
Mvpp2PrsTcamDataByteGet (Pe, Index, &TcamByte, &TcamMask);
|
if (TcamMask != Mask[Index]) {
|
return FALSE;
|
}
|
|
if ((TcamMask & TcamByte) != (Da[Index] & Mask[Index])) {
|
return FALSE;
|
}
|
}
|
|
return TRUE;
|
}
|
|
/* Find Tcam entry with matched pair <MAC DA, Port> */
|
STATIC
|
MVPP2_PRS_ENTRY *
|
Mvpp2PrsMacDaRangeFind (
|
IN MVPP2_SHARED *Priv,
|
IN INT32 Pmap,
|
IN const UINT8 *Da,
|
IN UINT8 *Mask,
|
IN INT32 UdfType
|
)
|
{
|
MVPP2_PRS_ENTRY *Pe;
|
INT32 Tid;
|
|
Pe = Mvpp2Alloc (sizeof (*Pe));
|
if (Pe == NULL) {
|
return NULL;
|
}
|
Mvpp2PrsTcamLuSet (Pe, MVPP2_PRS_LU_MAC);
|
|
/* Go through the all entires with MVPP2_PRS_LU_MAC */
|
for (Tid = MVPP2_PE_FIRST_FREE_TID; Tid <= MVPP2_PE_LAST_FREE_TID; Tid++) {
|
UINT32 EntryPmap;
|
|
if (!Priv->PrsShadow[Tid].Valid ||
|
(Priv->PrsShadow[Tid].Lu != MVPP2_PRS_LU_MAC) ||
|
(Priv->PrsShadow[Tid].Udf != UdfType))
|
{
|
continue;
|
}
|
|
Pe->Index = Tid;
|
Mvpp2PrsHwRead (Priv, Pe);
|
EntryPmap = Mvpp2PrsTcamPortMapGet (Pe);
|
|
if (Mvpp2PrsMacRangeEquals (Pe, Da, Mask) && EntryPmap == Pmap) {
|
return Pe;
|
}
|
}
|
|
Mvpp2Free (Pe);
|
|
return NULL;
|
}
|
|
/* Update parser's mac Da entry */
|
INT32
|
Mvpp2PrsMacDaAccept (
|
IN MVPP2_SHARED *Priv,
|
IN INT32 PortId,
|
IN const UINT8 *Da,
|
IN BOOLEAN Add
|
)
|
{
|
MVPP2_PRS_ENTRY *Pe;
|
UINT32 Pmap, Len, Ri;
|
UINT8 Mask[MV_ETH_ALEN] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
|
INT32 Tid;
|
|
/* Scan TCAM and see if entry with this <MAC DA, PortId> already exist */
|
Pe = Mvpp2PrsMacDaRangeFind (Priv, (1 << PortId), Da, Mask, MVPP2_PRS_UDF_MAC_DEF);
|
|
/* No such entry */
|
if (Pe == NULL) {
|
if (!Add) {
|
return 0;
|
}
|
|
/* Create new TCAM entry */
|
/* Find first range mac entry*/
|
for (Tid = MVPP2_PE_FIRST_FREE_TID; Tid <= MVPP2_PE_LAST_FREE_TID; Tid++) {
|
if (Priv->PrsShadow[Tid].Valid &&
|
(Priv->PrsShadow[Tid].Lu == MVPP2_PRS_LU_MAC) &&
|
(Priv->PrsShadow[Tid].Udf == MVPP2_PRS_UDF_MAC_RANGE))
|
{
|
break;
|
}
|
}
|
|
|
/* Go through the all entries from first to last */
|
Tid = Mvpp2PrsTcamFirstFree (Priv, MVPP2_PE_FIRST_FREE_TID, Tid - 1);
|
if (Tid < 0) {
|
return Tid;
|
}
|
|
Pe = Mvpp2Alloc (sizeof (*Pe));
|
if (Pe == NULL) {
|
return -1;
|
}
|
|
Mvpp2PrsTcamLuSet (Pe, MVPP2_PRS_LU_MAC);
|
Pe->Index = Tid;
|
|
/* Mask all Ports */
|
Mvpp2PrsTcamPortMapSet (Pe, 0);
|
}
|
|
/* Update PortId Mask */
|
Mvpp2PrsTcamPortSet (Pe, PortId, Add);
|
|
/* Invalidate the entry if no Ports are left enabled */
|
Pmap = Mvpp2PrsTcamPortMapGet (Pe);
|
if (Pmap == 0) {
|
if (Add) {
|
Mvpp2Free (Pe);
|
return -1;
|
}
|
|
Mvpp2PrsHwInv (Priv, Pe->Index);
|
Priv->PrsShadow[Pe->Index].Valid = FALSE;
|
|
Mvpp2Free (Pe);
|
|
return 0;
|
}
|
|
/* Continue - set next lookup */
|
Mvpp2PrsSramNextLuSet (Pe, MVPP2_PRS_LU_DSA);
|
|
/* Set match on DA */
|
Len = MV_ETH_ALEN;
|
while (Len--) {
|
Mvpp2PrsTcamDataByteSet (Pe, Len, Da[Len], 0xff);
|
}
|
|
/* Set result info bits */
|
if (Mvpp2IsBroadcastEtherAddr (Da)) {
|
Ri = MVPP2_PRS_RI_L2_BCAST;
|
} else if (Mvpp2IsMulticastEtherAddr (Da)) {
|
Ri = MVPP2_PRS_RI_L2_MCAST;
|
} else {
|
Ri = MVPP2_PRS_RI_L2_UCAST | MVPP2_PRS_RI_MAC_ME_MASK;
|
}
|
|
Mvpp2PrsSramRiUpdate (Pe, Ri, MVPP2_PRS_RI_L2_CAST_MASK | MVPP2_PRS_RI_MAC_ME_MASK);
|
Mvpp2PrsShadowRiSet (Priv, Pe->Index, Ri, MVPP2_PRS_RI_L2_CAST_MASK | MVPP2_PRS_RI_MAC_ME_MASK);
|
|
/* Shift to ethertype */
|
Mvpp2PrsSramShiftSet (Pe, 2 * MV_ETH_ALEN, MVPP2_PRS_SRAM_OP_SEL_SHIFT_ADD);
|
|
/* Update shadow table and hw entry */
|
Priv->PrsShadow[Pe->Index].Udf = MVPP2_PRS_UDF_MAC_DEF;
|
Mvpp2PrsShadowSet (Priv, Pe->Index, MVPP2_PRS_LU_MAC);
|
Mvpp2PrsHwWrite (Priv, Pe);
|
|
Mvpp2Free (Pe);
|
|
return 0;
|
}
|
|
/* Delete all Port's multicast simple (not range) entries */
|
VOID
|
Mvpp2PrsMcastDelAll (
|
IN MVPP2_SHARED *Priv,
|
IN INT32 PortId
|
)
|
{
|
MVPP2_PRS_ENTRY Pe;
|
INT32 Index, Tid;
|
|
for (Tid = MVPP2_PE_FIRST_FREE_TID; Tid <= MVPP2_PE_LAST_FREE_TID; Tid++) {
|
UINT8 Da[MV_ETH_ALEN], DaMask[MV_ETH_ALEN];
|
|
if (!Priv->PrsShadow[Tid].Valid ||
|
(Priv->PrsShadow[Tid].Lu != MVPP2_PRS_LU_MAC) ||
|
(Priv->PrsShadow[Tid].Udf != MVPP2_PRS_UDF_MAC_DEF))
|
{
|
continue;
|
}
|
|
/* Only simple mac entries */
|
Pe.Index = Tid;
|
Mvpp2PrsHwRead (Priv, &Pe);
|
|
/* Read mac Addr from entry */
|
for (Index = 0; Index < MV_ETH_ALEN; Index++) {
|
Mvpp2PrsTcamDataByteGet (&Pe, Index, &Da[Index], &DaMask[Index]);
|
}
|
|
if (Mvpp2IsMulticastEtherAddr (Da) && !Mvpp2IsBroadcastEtherAddr (Da)) {
|
/* Delete this entry */
|
Mvpp2PrsMacDaAccept (Priv, PortId, Da, FALSE);
|
}
|
}
|
}
|
|
INT32
|
Mvpp2PrsTagModeSet (
|
IN MVPP2_SHARED *Priv,
|
IN INT32 PortId,
|
IN INT32 Type
|
)
|
{
|
switch (Type) {
|
case MVPP2_TAG_TYPE_EDSA:
|
/* Add PortId to EDSA entries */
|
Mvpp2PrsDsaTagSet (Priv, PortId, TRUE, MVPP2_PRS_TAGGED, MVPP2_PRS_EDSA);
|
Mvpp2PrsDsaTagSet (Priv, PortId, TRUE, MVPP2_PRS_UNTAGGED, MVPP2_PRS_EDSA);
|
/* Remove PortId from DSA entries */
|
Mvpp2PrsDsaTagSet (Priv, PortId, FALSE, MVPP2_PRS_TAGGED, MVPP2_PRS_DSA);
|
Mvpp2PrsDsaTagSet (Priv, PortId, FALSE, MVPP2_PRS_UNTAGGED, MVPP2_PRS_DSA);
|
break;
|
case MVPP2_TAG_TYPE_DSA:
|
/* Add PortId to DSA entries */
|
Mvpp2PrsDsaTagSet (Priv, PortId, TRUE, MVPP2_PRS_TAGGED, MVPP2_PRS_DSA);
|
Mvpp2PrsDsaTagSet (Priv, PortId, TRUE, MVPP2_PRS_UNTAGGED, MVPP2_PRS_DSA);
|
|
/* Remove PortId from EDSA entries */
|
Mvpp2PrsDsaTagSet (Priv, PortId, FALSE, MVPP2_PRS_TAGGED, MVPP2_PRS_EDSA);
|
Mvpp2PrsDsaTagSet (Priv, PortId, FALSE, MVPP2_PRS_UNTAGGED, MVPP2_PRS_EDSA);
|
break;
|
case MVPP2_TAG_TYPE_MH:
|
case MVPP2_TAG_TYPE_NONE:
|
/* Remove PortId form EDSA and DSA entries */
|
Mvpp2PrsDsaTagSet (Priv, PortId, FALSE, MVPP2_PRS_TAGGED, MVPP2_PRS_DSA);
|
Mvpp2PrsDsaTagSet (Priv, PortId, FALSE, MVPP2_PRS_UNTAGGED, MVPP2_PRS_DSA);
|
Mvpp2PrsDsaTagSet (Priv, PortId, FALSE, MVPP2_PRS_TAGGED, MVPP2_PRS_EDSA);
|
Mvpp2PrsDsaTagSet (Priv, PortId, FALSE, MVPP2_PRS_UNTAGGED, MVPP2_PRS_EDSA);
|
break;
|
default:
|
if ((Type < 0) || (Type > MVPP2_TAG_TYPE_EDSA)) {
|
return MVPP2_EINVAL;
|
}
|
}
|
|
return 0;
|
}
|
|
/* Set prs Flow for the Port */
|
INT32
|
Mvpp2PrsDefFlow (
|
IN PP2DXE_PORT *Port
|
)
|
{
|
MVPP2_PRS_ENTRY *Pe;
|
INT32 Tid;
|
|
Pe = Mvpp2PrsFlowFind (Port->Priv, Port->Id);
|
|
/* Such entry not exist */
|
if (Pe == NULL) {
|
/* Go through the all entires from last to first */
|
Tid = Mvpp2PrsTcamFirstFree (Port->Priv, MVPP2_PE_LAST_FREE_TID, MVPP2_PE_FIRST_FREE_TID);
|
if (Tid < 0) {
|
return Tid;
|
}
|
|
Pe = Mvpp2Alloc (sizeof (*Pe));
|
if (Pe == NULL) {
|
return MVPP2_ENOMEM;
|
}
|
|
Mvpp2PrsTcamLuSet (Pe, MVPP2_PRS_LU_FLOWS);
|
Pe->Index = Tid;
|
|
/* Set Flow ID*/
|
Mvpp2PrsSramAiUpdate (Pe, Port->Id, MVPP2_PRS_FLOW_ID_MASK);
|
Mvpp2PrsSramBitsSet (Pe, MVPP2_PRS_SRAM_LU_DONE_BIT, 1);
|
|
/* Update shadow table */
|
Mvpp2PrsShadowSet (Port->Priv, Pe->Index, MVPP2_PRS_LU_FLOWS);
|
}
|
|
Mvpp2PrsTcamPortMapSet (Pe, (1 << Port->Id));
|
Mvpp2PrsHwWrite (Port->Priv, Pe);
|
Mvpp2Free (Pe);
|
|
return 0;
|
}
|
|
/* Classifier configuration routines */
|
|
/* Update classification Flow table RegValisters */
|
STATIC
|
VOID
|
Mvpp2ClsFlowWrite (
|
IN MVPP2_SHARED *Priv,
|
IN MVPP2_CLS_FLOW_ENTRY *Fe
|
)
|
{
|
Mvpp2Write (Priv, MVPP2_CLS_FLOW_INDEX_REG, Fe->Index);
|
Mvpp2Write (Priv, MVPP2_CLS_FLOW_TBL0_REG, Fe->Data[0]);
|
Mvpp2Write (Priv, MVPP2_CLS_FLOW_TBL1_REG, Fe->Data[1]);
|
Mvpp2Write (Priv, MVPP2_CLS_FLOW_TBL2_REG, Fe->Data[2]);
|
}
|
|
/* Update classification lookup table RegValister */
|
VOID
|
Mvpp2ClsLookupWrite (
|
IN MVPP2_SHARED *Priv,
|
IN OUT MVPP2_CLS_LOOKUP_ENTRY *Le
|
)
|
{
|
UINT32 Val;
|
|
Val = (Le->Way << MVPP2_CLS_LKP_INDEX_WAY_OFFS) | Le->Lkpid;
|
Mvpp2Write (Priv, MVPP2_CLS_LKP_INDEX_REG, Val);
|
Mvpp2Write (Priv, MVPP2_CLS_LKP_TBL_REG, Le->Data);
|
}
|
|
/* Classifier default initialization */
|
VOID
|
Mvpp2ClsInit (
|
IN MVPP2_SHARED *Priv
|
)
|
{
|
MVPP2_CLS_LOOKUP_ENTRY Le;
|
MVPP2_CLS_FLOW_ENTRY Fe;
|
INT32 Index;
|
|
/* Enable classifier */
|
Mvpp2Write (Priv, MVPP2_CLS_MODE_REG, MVPP2_CLS_MODE_ACTIVE_MASK);
|
|
/* Clear classifier Flow table */
|
Mvpp2Memset (&Fe.Data, 0, MVPP2_CLS_FLOWS_TBL_DATA_WORDS);
|
for (Index = 0; Index < MVPP2_CLS_FLOWS_TBL_SIZE; Index++) {
|
Fe.Index = Index;
|
Mvpp2ClsFlowWrite (Priv, &Fe);
|
}
|
|
/* Clear classifier lookup table */
|
Le.Data = 0;
|
for (Index = 0; Index < MVPP2_CLS_LKP_TBL_SIZE; Index++) {
|
Le.Lkpid = Index;
|
Le.Way = 0;
|
Mvpp2ClsLookupWrite (Priv, &Le);
|
|
Le.Way = 1;
|
Mvpp2ClsLookupWrite (Priv, &Le);
|
}
|
}
|
|
VOID
|
Mvpp2ClsPortConfig (
|
IN PP2DXE_PORT *Port
|
)
|
{
|
MVPP2_CLS_LOOKUP_ENTRY Le;
|
UINT32 Val;
|
|
/* Set way for the Port */
|
Val = Mvpp2Read (Port->Priv, MVPP2_CLS_PORT_WAY_REG);
|
Val &= ~MVPP2_CLS_PORT_WAY_MASK (Port->Id);
|
Mvpp2Write (Port->Priv, MVPP2_CLS_PORT_WAY_REG, Val);
|
|
/*
|
* Pick the entry to be accessed in lookup ID decoding table
|
* according to the way and lkpid.
|
*/
|
Le.Lkpid = Port->Id;
|
Le.Way = 0;
|
Le.Data = 0;
|
|
/* Set initial CPU Queue for receiving packets */
|
Le.Data &= ~MVPP2_CLS_LKP_TBL_RXQ_MASK;
|
Le.Data |= Port->FirstRxq;
|
|
/* Disable classification engines */
|
Le.Data &= ~MVPP2_CLS_LKP_TBL_LOOKUP_EN_MASK;
|
|
/* Update lookup ID table entry */
|
Mvpp2ClsLookupWrite (Port->Priv, &Le);
|
}
|
|
/* Set CPU Queue number for oversize packets */
|
VOID
|
Mvpp2ClsOversizeRxqSet (
|
IN PP2DXE_PORT *Port
|
)
|
{
|
|
Mvpp2Write (
|
Port->Priv,
|
MVPP2_CLS_OVERSIZE_RXQ_LOW_REG(Port->Id),
|
Port->FirstRxq & MVPP2_CLS_OVERSIZE_RXQ_LOW_MASK
|
);
|
}
|
|
/* BM helper routines */
|
|
VOID
|
Mvpp2BmPoolHwCreate (
|
IN MVPP2_SHARED *Priv,
|
IN MVPP2_BMS_POOL *BmPool,
|
IN INT32 Size
|
)
|
{
|
BmPool->Size = Size;
|
|
Mvpp2Write (Priv, MVPP2_BM_POOL_BASE_REG(BmPool->Id), Lower32Bits (BmPool->PhysAddr));
|
Mvpp2Write (Priv, MVPP22_BM_POOL_BASE_HIGH_REG, (Upper32Bits (BmPool->PhysAddr) & MVPP22_BM_POOL_BASE_HIGH_REG));
|
Mvpp2Write (Priv, MVPP2_BM_POOL_SIZE_REG(BmPool->Id), BmPool->Size);
|
}
|
|
/* Set Pool buffer Size */
|
VOID
|
Mvpp2BmPoolBufsizeSet (
|
IN MVPP2_SHARED *Priv,
|
IN MVPP2_BMS_POOL *BmPool,
|
IN INT32 BufSize
|
)
|
{
|
UINT32 Val;
|
|
BmPool->BufSize = BufSize;
|
|
Val = MVPP2_ALIGN (BufSize, 1 << MVPP2_POOL_BUF_SIZE_OFFSET);
|
Mvpp2Write (Priv, MVPP2_POOL_BUF_SIZE_REG(BmPool->Id), Val);
|
}
|
|
VOID
|
Mvpp2BmStop (
|
IN MVPP2_SHARED *Priv,
|
IN INT32 Pool
|
)
|
{
|
UINT32 Val, i;
|
|
for (i = 0; i < MVPP2_BM_SIZE; i++) {
|
Mvpp2Read (Priv, MVPP2_BM_PHY_ALLOC_REG(Pool));
|
}
|
|
Val = Mvpp2Read (Priv, MVPP2_BM_POOL_CTRL_REG(Pool));
|
Val |= MVPP2_BM_STOP_MASK;
|
Mvpp2Write (Priv, MVPP2_BM_POOL_CTRL_REG(Pool), Val);
|
}
|
|
VOID
|
Mvpp2BmIrqClear (
|
IN MVPP2_SHARED *Priv,
|
IN INT32 Pool
|
)
|
{
|
/* Mask BM all interrupts */
|
Mvpp2Write (Priv, MVPP2_BM_INTR_MASK_REG(Pool), 0);
|
|
/* Clear BM cause RegValister */
|
Mvpp2Write (Priv, MVPP2_BM_INTR_CAUSE_REG(Pool), 0);
|
}
|
|
/* Attach long Pool to Rxq */
|
VOID
|
Mvpp2RxqLongPoolSet (
|
IN PP2DXE_PORT *Port,
|
IN INT32 Lrxq,
|
IN INT32 LongPool
|
)
|
{
|
UINT32 Val;
|
INT32 Prxq;
|
|
/* Get Queue physical ID */
|
Prxq = Port->Rxqs[Lrxq].Id;
|
|
Val = Mvpp2Read (Port->Priv, MVPP2_RXQ_CONFIG_REG(Prxq));
|
Val &= ~MVPP2_RXQ_POOL_LONG_MASK;
|
Val |= ((LongPool << MVPP2_RXQ_POOL_LONG_OFFS) & MVPP2_RXQ_POOL_LONG_MASK);
|
|
Mvpp2Write (Port->Priv, MVPP2_RXQ_CONFIG_REG(Prxq), Val);
|
}
|
|
/* Attach short Pool to Rxq */
|
VOID
|
Mvpp2RxqShortPoolSet (
|
IN PP2DXE_PORT *Port,
|
IN INT32 Lrxq,
|
IN INT32 ShortPool
|
)
|
{
|
UINT32 Val;
|
INT32 Prxq;
|
|
/* Get Queue physical ID */
|
Prxq = Port->Rxqs[Lrxq].Id;
|
|
Val = Mvpp2Read (Port->Priv, MVPP2_RXQ_CONFIG_REG(Prxq));
|
Val &= ~MVPP2_RXQ_POOL_SHORT_MASK;
|
Val |= ((ShortPool << MVPP2_RXQ_POOL_SHORT_OFFS) & MVPP2_RXQ_POOL_SHORT_MASK);
|
|
Mvpp2Write (Port->Priv, MVPP2_RXQ_CONFIG_REG(Prxq), Val);
|
}
|
|
/* Release multicast buffer */
|
VOID
|
Mvpp2BmPoolMcPut (
|
IN PP2DXE_PORT *Port,
|
IN INT32 Pool,
|
IN UINT32 BufPhysAddr,
|
IN UINT32 BufVirtAddr,
|
IN INT32 McId
|
)
|
{
|
UINT32 Val = 0;
|
|
Val |= (McId & MVPP2_BM_MC_ID_MASK);
|
Mvpp2Write (Port->Priv, MVPP2_BM_MC_RLS_REG, Val);
|
|
Mvpp2BmPoolPut (Port->Priv, Pool, BufPhysAddr | MVPP2_BM_PHY_RLS_MC_BUFF_MASK, BufVirtAddr);
|
}
|
|
/* Refill BM Pool */
|
VOID
|
Mvpp2PoolRefill (
|
IN PP2DXE_PORT *Port,
|
IN UINT32 Bm,
|
IN UINT32 PhysAddr,
|
IN UINT32 cookie
|
)
|
{
|
INT32 Pool = Mvpp2BmCookiePoolGet (Bm);
|
|
Mvpp2BmPoolPut (Port->Priv, Pool, PhysAddr, cookie);
|
}
|
|
INTN
|
Mvpp2BmPoolCtrl (
|
IN MVPP2_SHARED *Priv,
|
IN INTN Pool,
|
IN enum Mvpp2Command Cmd
|
)
|
{
|
UINT32 RegVal = 0;
|
RegVal = Mvpp2Read (Priv, MVPP2_BM_POOL_CTRL_REG(Pool));
|
|
switch (Cmd) {
|
case MVPP2_START:
|
RegVal |= MVPP2_BM_START_MASK;
|
break;
|
|
case MVPP2_STOP:
|
RegVal |= MVPP2_BM_STOP_MASK;
|
break;
|
|
default:
|
return -1;
|
}
|
Mvpp2Write (Priv, MVPP2_BM_POOL_CTRL_REG(Pool), RegVal);
|
|
return 0;
|
}
|
|
/* Mask the current CPU's Rx/Tx interrupts */
|
VOID
|
Mvpp2InterruptsMask (
|
IN VOID *arg
|
)
|
{
|
PP2DXE_PORT *Port = arg;
|
|
Mvpp2Write (Port->Priv, MVPP2_ISR_RX_TX_MASK_REG(Port->Id), 0);
|
}
|
|
/* Unmask the current CPU's Rx/Tx interrupts */
|
VOID
|
Mvpp2InterruptsUnmask (
|
IN VOID *arg
|
)
|
{
|
PP2DXE_PORT *Port = arg;
|
|
Mvpp2Write (
|
Port->Priv,
|
MVPP2_ISR_RX_TX_MASK_REG(Port->Id),
|
(MVPP2_CAUSE_MISC_SUM_MASK | MVPP2_CAUSE_RXQ_OCCUP_DESC_ALL_MASK)
|
);
|
}
|
|
/* MAC configuration routines */
|
|
STATIC
|
VOID
|
Mvpp2PortMiiSet (
|
IN PP2DXE_PORT *Port
|
)
|
{
|
UINT32 Val;
|
|
Val = Mvpp2GmacRead (Port, MVPP2_GMAC_CTRL_2_REG);
|
|
switch (Port->PhyInterface) {
|
case MV_MODE_SGMII:
|
Val |= MVPP2_GMAC_INBAND_AN_MASK;
|
break;
|
case MV_MODE_RGMII:
|
Val |= MVPP2_GMAC_PORT_RGMII_MASK;
|
default:
|
Val &= ~MVPP2_GMAC_PCS_ENABLE_MASK;
|
}
|
|
Mvpp2GmacWrite (Port, MVPP2_GMAC_CTRL_2_REG, Val);
|
}
|
|
STATIC
|
VOID Mvpp2PortFcAdvEnable (
|
IN PP2DXE_PORT *Port
|
)
|
{
|
UINT32 Val;
|
|
Val = Mvpp2GmacRead (Port, MVPP2_GMAC_AUTONEG_CONFIG);
|
Val |= MVPP2_GMAC_FC_ADV_EN;
|
Mvpp2GmacWrite (Port, MVPP2_GMAC_AUTONEG_CONFIG, Val);
|
}
|
|
VOID
|
Mvpp2PortEnable (
|
IN PP2DXE_PORT *Port
|
)
|
{
|
UINT32 Val;
|
|
Val = Mvpp2GmacRead (Port, MVPP2_GMAC_CTRL_0_REG);
|
Val |= MVPP2_GMAC_PORT_EN_MASK;
|
Val |= MVPP2_GMAC_MIB_CNTR_EN_MASK;
|
Mvpp2GmacWrite (Port, MVPP2_GMAC_CTRL_0_REG, Val);
|
}
|
|
VOID
|
Mvpp2PortDisable (
|
IN PP2DXE_PORT *Port
|
)
|
{
|
UINT32 Val;
|
|
Val = Mvpp2GmacRead (Port, MVPP2_GMAC_CTRL_0_REG);
|
Val &= ~(MVPP2_GMAC_PORT_EN_MASK);
|
Mvpp2GmacWrite (Port, MVPP2_GMAC_CTRL_0_REG, Val);
|
}
|
|
/* Set IEEE 802.3x Flow Control Xon Packet Transmission Mode */
|
STATIC
|
VOID
|
Mvpp2PortPeriodicXonDisable (
|
IN PP2DXE_PORT *Port
|
)
|
{
|
UINT32 Val;
|
|
Val = Mvpp2GmacRead (Port, MVPP2_GMAC_CTRL_1_REG) & ~MVPP2_GMAC_PERIODIC_XON_EN_MASK;
|
Mvpp2GmacWrite (Port, MVPP2_GMAC_CTRL_1_REG, Val);
|
}
|
|
/* Configure loopback Port */
|
STATIC
|
VOID
|
Mvpp2PortReset (
|
IN PP2DXE_PORT *Port
|
)
|
{
|
UINT32 Val;
|
|
Val = Mvpp2GmacRead (Port, MVPP2_GMAC_CTRL_2_REG) & ~MVPP2_GMAC_PORT_RESET_MASK;
|
Mvpp2GmacWrite (Port, MVPP2_GMAC_CTRL_2_REG, Val);
|
|
while (Mvpp2GmacRead (Port, MVPP2_GMAC_CTRL_2_REG) & MVPP2_GMAC_PORT_RESET_MASK) {
|
continue;
|
}
|
}
|
|
/* Set defaults to the MVPP2 Port */
|
VOID
|
Mvpp2DefaultsSet (
|
IN PP2DXE_PORT *Port
|
)
|
{
|
INT32 TxPortNum, Val, Queue, pTxq;
|
|
/* Disable Legacy WRR, Disable EJP, Release from Reset */
|
TxPortNum = Mvpp2EgressPort (Port);
|
Mvpp2Write (Port->Priv, MVPP2_TXP_SCHED_PORT_INDEX_REG, TxPortNum);
|
Mvpp2Write (Port->Priv, MVPP2_TXP_SCHED_CMD_1_REG, 0);
|
|
/* Close bandwidth for all Queues */
|
for (Queue = 0; Queue < MVPP2_MAX_TXQ; Queue++) {
|
pTxq = Mvpp2TxqPhys (Port->Id, Queue);
|
Mvpp2Write (Port->Priv, MVPP2_TXQ_SCHED_TOKEN_CNTR_REG(pTxq), 0);
|
}
|
|
|
/* Set refill period to 1 Usec, refill tokens and bucket Size to maximum */
|
Mvpp2Write (Port->Priv, MVPP2_TXP_SCHED_PERIOD_REG, Port->Priv->Tclk / MVPP2_USEC_PER_SEC);
|
Val = Mvpp2Read (Port->Priv, MVPP2_TXP_SCHED_REFILL_REG);
|
Val &= ~MVPP2_TXP_REFILL_PERIOD_ALL_MASK;
|
Val |= MVPP2_TXP_REFILL_PERIOD_MASK (1);
|
Val |= MVPP2_TXP_REFILL_TOKENS_ALL_MASK;
|
Mvpp2Write (Port->Priv, MVPP2_TXP_SCHED_REFILL_REG, Val);
|
Val = MVPP2_TXP_TOKEN_SIZE_MAX;
|
Mvpp2Write (Port->Priv, MVPP2_TXP_SCHED_TOKEN_SIZE_REG, Val);
|
|
/* Set MaximumLowLatencyPacketSize value to 256 */
|
Mvpp2Write (
|
Port->Priv,
|
MVPP2_RX_CTRL_REG(Port->Id),
|
MVPP2_RX_USE_PSEUDO_FOR_CSUM_MASK | MVPP2_RX_LOW_LATENCY_PKT_SIZE (256)
|
);
|
|
/* Mask all interrupts to all present cpus */
|
Mvpp2InterruptsDisable (Port, 0x1);
|
}
|
|
/* Enable/disable receiving packets */
|
VOID
|
Mvpp2IngressEnable (
|
IN PP2DXE_PORT *Port
|
)
|
{
|
UINT32 Val;
|
INT32 Lrxq, Queue;
|
|
for (Lrxq = 0; Lrxq < RxqNumber; Lrxq++) {
|
Queue = Port->Rxqs[Lrxq].Id;
|
Val = Mvpp2Read (Port->Priv, MVPP2_RXQ_CONFIG_REG(Queue));
|
Val &= ~MVPP2_RXQ_DISABLE_MASK;
|
Mvpp2Write (Port->Priv, MVPP2_RXQ_CONFIG_REG(Queue), Val);
|
}
|
}
|
|
VOID
|
Mvpp2IngressDisable (
|
IN PP2DXE_PORT *Port
|
)
|
{
|
UINT32 Val;
|
INT32 Lrxq, Queue;
|
|
for (Lrxq = 0; Lrxq < RxqNumber; Lrxq++) {
|
Queue = Port->Rxqs[Lrxq].Id;
|
Val = Mvpp2Read (Port->Priv, MVPP2_RXQ_CONFIG_REG(Queue));
|
Val |= MVPP2_RXQ_DISABLE_MASK;
|
Mvpp2Write (Port->Priv, MVPP2_RXQ_CONFIG_REG(Queue), Val);
|
}
|
}
|
|
/* Enable transmit via physical egress Queue - HW starts take descriptors from DRAM */
|
VOID
|
Mvpp2EgressEnable (
|
IN PP2DXE_PORT *Port
|
)
|
{
|
UINT32 qmap;
|
INT32 Queue;
|
INT32 TxPortNum = Mvpp2EgressPort (Port);
|
|
/* Enable all initialized TXs. */
|
qmap = 0;
|
for (Queue = 0; Queue < TxqNumber; Queue++) {
|
MVPP2_TX_QUEUE *Txq = &Port->Txqs[Queue];
|
|
if (Txq->Descs != NULL) {
|
qmap |= (1 << Queue);
|
}
|
}
|
|
Mvpp2Write (Port->Priv, MVPP2_TXP_SCHED_PORT_INDEX_REG, TxPortNum);
|
Mvpp2Write (Port->Priv, MVPP2_TXP_SCHED_Q_CMD_REG, qmap);
|
}
|
|
/* Disable transmit via physical egress Queue - HW doesn't take descriptors from DRAM */
|
VOID
|
Mvpp2EgressDisable (
|
IN PP2DXE_PORT *Port
|
)
|
{
|
UINT32 RegData;
|
INT32 Delay;
|
INT32 TxPortNum = Mvpp2EgressPort (Port);
|
|
/* Issue stop command for active channels only */
|
Mvpp2Write (Port->Priv, MVPP2_TXP_SCHED_PORT_INDEX_REG, TxPortNum);
|
RegData = (Mvpp2Read (Port->Priv, MVPP2_TXP_SCHED_Q_CMD_REG)) & MVPP2_TXP_SCHED_ENQ_MASK;
|
if (RegData != 0) {
|
Mvpp2Write (Port->Priv, MVPP2_TXP_SCHED_Q_CMD_REG, (RegData << MVPP2_TXP_SCHED_DISQ_OFFSET));
|
}
|
|
/* Wait for all Tx activity to terminate. */
|
Delay = 0;
|
do {
|
if (Delay >= MVPP2_TX_DISABLE_TIMEOUT_MSEC) {
|
Mvpp2Printf ("Tx stop timed out, status=0x%08x\n", RegData);
|
break;
|
}
|
Mvpp2Mdelay (1);
|
Delay++;
|
|
/* Check Port TX Command RegValister that all Tx Queues are stopped */
|
RegData = Mvpp2Read (Port->Priv, MVPP2_TXP_SCHED_Q_CMD_REG);
|
} while (RegData & MVPP2_TXP_SCHED_ENQ_MASK);
|
}
|
|
/* Rx descriptors helper methods */
|
|
/* Set rx Queue Offset */
|
STATIC
|
VOID
|
Mvpp2RxqOffsetSet (
|
IN PP2DXE_PORT *Port,
|
IN INT32 Prxq,
|
IN INT32 Offset
|
)
|
{
|
UINT32 Val;
|
|
/* Convert Offset from bytes to units of 32 bytes */
|
Offset = Offset >> 5;
|
|
/* Clear previous value */
|
Val = Mvpp2Read (Port->Priv, MVPP2_RXQ_CONFIG_REG(Prxq));
|
Val &= ~MVPP2_RXQ_PACKET_OFFSET_MASK;
|
|
/* Update packet Offset in received buffer */
|
Val |= ((Offset << MVPP2_RXQ_PACKET_OFFSET_OFFS) & MVPP2_RXQ_PACKET_OFFSET_MASK);
|
Mvpp2Write (Port->Priv, MVPP2_RXQ_CONFIG_REG(Prxq), Val);
|
}
|
|
/* Obtain BM cookie information from descriptor */
|
UINT32
|
Mvpp2BmCookieBuild (
|
IN MVPP2_RX_DESC *RxDesc,
|
IN INT32 Cpu
|
)
|
{
|
INT32 Pool;
|
UINT32 ret;
|
|
Pool = (RxDesc->status & MVPP2_RXD_BM_POOL_ID_MASK) >> MVPP2_RXD_BM_POOL_ID_OFFS;
|
|
ret = ((Pool & 0xFF) << MVPP2_BM_COOKIE_POOL_OFFS) | ((Cpu & 0xFF) << MVPP2_BM_COOKIE_CPU_OFFS);
|
|
return ret;
|
}
|
|
/* Tx descriptors helper methods */
|
|
INT32
|
Mvpp2TxqDrainSet (
|
IN PP2DXE_PORT *Port,
|
IN INT32 Txq,
|
IN BOOLEAN En
|
)
|
{
|
UINT32 RegVal;
|
INT32 pTxq = Mvpp2TxqPhys (Port->Id, Txq);
|
|
Mvpp2Write (Port->Priv, MVPP2_TXQ_NUM_REG, pTxq);
|
RegVal = Mvpp2Read (Port->Priv, MVPP2_TXQ_PREF_BUF_REG);
|
|
if (En) {
|
RegVal |= MVPP2_TXQ_DRAIN_EN_MASK;
|
} else {
|
RegVal &= ~MVPP2_TXQ_DRAIN_EN_MASK;
|
}
|
|
Mvpp2Write (Port->Priv, MVPP2_TXQ_PREF_BUF_REG, RegVal);
|
|
return 0;
|
}
|
|
/* Get number of Tx descriptors waiting to be transmitted by HW */
|
INT32
|
Mvpp2TxqPendDescNumGet (
|
IN PP2DXE_PORT *Port,
|
IN MVPP2_TX_QUEUE *Txq
|
)
|
{
|
UINT32 Val;
|
|
Mvpp2Write (Port->Priv, MVPP2_TXQ_NUM_REG, Txq->Id);
|
Val = Mvpp2Read (Port->Priv, MVPP2_TXQ_PENDING_REG);
|
|
return Val & MVPP2_TXQ_PENDING_MASK;
|
}
|
|
/* Get number of occupied aggRegValated Tx descriptors */
|
UINT32
|
Mvpp2AggrTxqPendDescNumGet (
|
IN MVPP2_SHARED *Priv,
|
IN INT32 Cpu
|
)
|
{
|
UINT32 RegVal;
|
|
RegVal = Mvpp2Read (Priv, MVPP2_AGGR_TXQ_STATUS_REG(Cpu));
|
|
return RegVal & MVPP2_AGGR_TXQ_PENDING_MASK;
|
}
|
|
/* Get pointer to next Tx descriptor to be processed (send) by HW */
|
MVPP2_TX_DESC *
|
Mvpp2TxqNextDescGet (
|
MVPP2_TX_QUEUE *Txq
|
)
|
{
|
INT32 TxDesc = Txq->NextDescToProc;
|
|
Txq->NextDescToProc = MVPP2_QUEUE_NEXT_DESC (Txq, TxDesc);
|
|
return Txq->Descs + TxDesc;
|
}
|
|
/* Update HW with number of aggRegValated Tx descriptors to be sent */
|
VOID
|
Mvpp2AggrTxqPendDescAdd (
|
IN PP2DXE_PORT *Port,
|
IN INT32 Pending
|
)
|
{
|
/* AggRegValated access - relevant TXQ number is written in TX desc */
|
Mvpp2Write (Port->Priv, MVPP2_AGGR_TXQ_UPDATE_REG, Pending);
|
}
|
|
/*
|
* Check if there are enough free descriptors in aggRegValated Txq.
|
* If not, update the number of occupied descriptors and repeat the check.
|
*/
|
INT32
|
Mvpp2AggrDescNumCheck (
|
IN MVPP2_SHARED *Priv,
|
IN MVPP2_TX_QUEUE *AggrTxq,
|
IN INT32 Num,
|
IN INT32 Cpu
|
)
|
{
|
UINT32 Val;
|
|
if ((AggrTxq->count + Num) > AggrTxq->Size) {
|
/* Update number of occupied aggRegValated Tx descriptors */
|
Val = Mvpp2Read (Priv, MVPP2_AGGR_TXQ_STATUS_REG(Cpu));
|
AggrTxq->count = Val & MVPP2_AGGR_TXQ_PENDING_MASK;
|
}
|
|
if ((AggrTxq->count + Num) > AggrTxq->Size) {
|
return MVPP2_ENOMEM;
|
}
|
|
return 0;
|
}
|
|
/* Reserved Tx descriptors allocation request */
|
INT32
|
Mvpp2TxqAllocReservedDesc (
|
IN MVPP2_SHARED *Priv,
|
IN MVPP2_TX_QUEUE *Txq,
|
IN INT32 Num
|
)
|
{
|
UINT32 Val;
|
|
Val = (Txq->Id << MVPP2_TXQ_RSVD_REQ_Q_OFFSET) | Num;
|
Mvpp2Write (Priv, MVPP2_TXQ_RSVD_REQ_REG, Val);
|
|
Val = Mvpp2Read (Priv, MVPP2_TXQ_RSVD_RSLT_REG);
|
|
return Val & MVPP2_TXQ_RSVD_RSLT_MASK;
|
}
|
|
/*
|
* Release the last allocated Tx descriptor. Useful to handle DMA
|
* mapping failures in the Tx path.
|
*/
|
VOID
|
Mvpp2TxqDescPut (
|
IN MVPP2_TX_QUEUE *Txq
|
)
|
{
|
if (Txq->NextDescToProc == 0) {
|
Txq->NextDescToProc = Txq->LastDesc - 1;
|
} else {
|
Txq->NextDescToProc--;
|
}
|
}
|
|
/* Set Tx descriptors fields relevant for CSUM calculation */
|
UINT32
|
Mvpp2TxqDescCsum (
|
IN INT32 L3Offs,
|
IN INT32 L3Proto,
|
IN INT32 IpHdrLen,
|
IN INT32 L4Proto
|
)
|
{
|
UINT32 command;
|
|
/*
|
* Fields: L3_Offset, IP_hdrlen, L3_type, G_IPV4Chk,
|
* G_L4_chk, L4_type required only for checksum calculation
|
*/
|
command = (L3Offs << MVPP2_TXD_L3_OFF_SHIFT);
|
command |= (IpHdrLen << MVPP2_TXD_IP_HLEN_SHIFT);
|
command |= MVPP2_TXD_IP_CSUM_DISABLE;
|
|
if (L3Proto == Mvpp2SwapBytes16 (MV_ETH_P_IP)) {
|
command &= ~MVPP2_TXD_IP_CSUM_DISABLE; /* enable IPv4 csum */
|
command &= ~MVPP2_TXD_L3_IP6; /* enable IPv4 */
|
} else {
|
command |= MVPP2_TXD_L3_IP6; /* enable IPv6 */
|
}
|
|
if (L4Proto == MV_IPPR_TCP) {
|
command &= ~MVPP2_TXD_L4_UDP; /* enable TCP */
|
command &= ~MVPP2_TXD_L4_CSUM_FRAG; /* generate L4 csum */
|
} else if (L4Proto == MV_IPPR_UDP) {
|
command |= MVPP2_TXD_L4_UDP; /* enable UDP */
|
command &= ~MVPP2_TXD_L4_CSUM_FRAG; /* generate L4 csum */
|
} else {
|
command |= MVPP2_TXD_L4_CSUM_NOT;
|
}
|
|
return command;
|
}
|
|
/* Clear counter of sent packets */
|
VOID
|
Mvpp2TxqSentCounterClear (
|
IN OUT VOID *arg
|
)
|
{
|
PP2DXE_PORT *Port = arg;
|
INT32 Queue;
|
|
for (Queue = 0; Queue < TxqNumber; Queue++) {
|
INT32 Id = Port->Txqs[Queue].Id;
|
|
Mvpp2Read (Port->Priv, MVPP2_TXQ_SENT_REG(Id));
|
}
|
}
|
|
/* Change maximum receive Size of the Port */
|
VOID
|
Mvpp2GmacMaxRxSizeSet (
|
IN PP2DXE_PORT *Port
|
)
|
{
|
UINT32 Val;
|
|
Val = Mvpp2GmacRead (Port, MVPP2_GMAC_CTRL_0_REG);
|
Val &= ~MVPP2_GMAC_MAX_RX_SIZE_MASK;
|
Val |= (((Port->PktSize - MVPP2_MH_SIZE) / 2) << MVPP2_GMAC_MAX_RX_SIZE_OFFS);
|
Mvpp2GmacWrite (Port, MVPP2_GMAC_CTRL_0_REG, Val);
|
}
|
|
/* Set max sizes for Tx Queues */
|
VOID
|
Mvpp2TxpMaxTxSizeSet (
|
IN PP2DXE_PORT *Port
|
)
|
{
|
UINT32 Val, Size, mtu;
|
INT32 Txq, TxPortNum;
|
|
mtu = Port->PktSize * 8;
|
if (mtu > MVPP2_TXP_MTU_MAX) {
|
mtu = MVPP2_TXP_MTU_MAX;
|
}
|
|
/* WA for wrong Token bucket update: Set MTU value = 3*real MTU value */
|
mtu = 3 * mtu;
|
|
/* Indirect access to RegValisters */
|
TxPortNum = Mvpp2EgressPort (Port);
|
Mvpp2Write (Port->Priv, MVPP2_TXP_SCHED_PORT_INDEX_REG, TxPortNum);
|
|
/* Set MTU */
|
Val = Mvpp2Read (Port->Priv, MVPP2_TXP_SCHED_MTU_REG);
|
Val &= ~MVPP2_TXP_MTU_MAX;
|
Val |= mtu;
|
Mvpp2Write (Port->Priv, MVPP2_TXP_SCHED_MTU_REG, Val);
|
|
/* TXP token Size and all TXQs token Size must be larger that MTU */
|
Val = Mvpp2Read (Port->Priv, MVPP2_TXP_SCHED_TOKEN_SIZE_REG);
|
Size = Val & MVPP2_TXP_TOKEN_SIZE_MAX;
|
if (Size < mtu) {
|
Size = mtu;
|
Val &= ~MVPP2_TXP_TOKEN_SIZE_MAX;
|
Val |= Size;
|
Mvpp2Write (Port->Priv, MVPP2_TXP_SCHED_TOKEN_SIZE_REG, Val);
|
}
|
|
for (Txq = 0; Txq < TxqNumber; Txq++) {
|
Val = Mvpp2Read (Port->Priv, MVPP2_TXQ_SCHED_TOKEN_SIZE_REG(Txq));
|
Size = Val & MVPP2_TXQ_TOKEN_SIZE_MAX;
|
|
if (Size < mtu) {
|
Size = mtu;
|
Val &= ~MVPP2_TXQ_TOKEN_SIZE_MAX;
|
Val |= Size;
|
Mvpp2Write (Port->Priv, MVPP2_TXQ_SCHED_TOKEN_SIZE_REG(Txq), Val);
|
}
|
}
|
}
|
|
/*
|
* Set the number of packets that will be received before Rx interrupt
|
* will be generated by HW.
|
*/
|
VOID
|
Mvpp2RxPktsCoalSet (
|
IN PP2DXE_PORT *Port,
|
IN OUT MVPP2_RX_QUEUE *Rxq,
|
IN UINT32 Pkts
|
)
|
{
|
UINT32 Val;
|
|
Val = (Pkts & MVPP2_OCCUPIED_THRESH_MASK);
|
Mvpp2Write (Port->Priv, MVPP2_RXQ_NUM_REG, Rxq->Id);
|
Mvpp2Write (Port->Priv, MVPP2_RXQ_THRESH_REG, Val);
|
|
Rxq->PktsCoal = Pkts;
|
}
|
|
/* Set the time Delay in Usec before Rx INT32errupt */
|
VOID
|
Mvpp2RxTimeCoalSet (
|
IN PP2DXE_PORT *Port,
|
IN OUT MVPP2_RX_QUEUE *Rxq,
|
IN UINT32 Usec
|
)
|
{
|
UINT32 Val;
|
|
Val = (Port->Priv->Tclk / MVPP2_USEC_PER_SEC) * Usec;
|
Mvpp2Write (Port->Priv, MVPP2_ISR_RX_THRESHOLD_REG(Rxq->Id), Val);
|
|
Rxq->TimeCoal = Usec;
|
}
|
|
/* Rx/Tx Queue initialization/cleanup methods */
|
|
/* Configure RXQ's */
|
VOID
|
Mvpp2RxqHwInit (
|
IN PP2DXE_PORT *Port,
|
IN OUT MVPP2_RX_QUEUE *Rxq
|
)
|
{
|
Rxq->LastDesc = Rxq->Size - 1;
|
|
/* Zero occupied and non-occupied counters - direct access */
|
Mvpp2Write (Port->Priv, MVPP2_RXQ_STATUS_REG(Rxq->Id), 0);
|
|
/* Set Rx descriptors Queue starting Address - indirect access */
|
Mvpp2Write (Port->Priv, MVPP2_RXQ_NUM_REG, Rxq->Id);
|
Mvpp2Write (Port->Priv, MVPP2_RXQ_DESC_ADDR_REG, Rxq->DescsPhys >> MVPP22_DESC_ADDR_SHIFT);
|
Mvpp2Write (Port->Priv, MVPP2_RXQ_DESC_SIZE_REG, Rxq->Size);
|
Mvpp2Write (Port->Priv, MVPP2_RXQ_INDEX_REG, 0);
|
|
/* Set Offset */
|
Mvpp2RxqOffsetSet (Port, Rxq->Id, MVPP2_RXQ_OFFSET);
|
|
/* Set coalescing pkts and time */
|
Mvpp2RxPktsCoalSet (Port, Rxq, MVPP2_RX_COAL_PKTS);
|
Mvpp2RxTimeCoalSet (Port, Rxq, Rxq->TimeCoal);
|
|
/* Add number of descriptors ready for receiving packets */
|
Mvpp2RxqStatusUpdate (Port, Rxq->Id, 0, Rxq->Size);
|
}
|
|
/* Push packets received by the RXQ to BM Pool */
|
VOID
|
Mvpp2RxqDropPkts (
|
IN PP2DXE_PORT *Port,
|
IN OUT MVPP2_RX_QUEUE *Rxq,
|
IN INT32 Cpu
|
)
|
{
|
INT32 RxReceived;
|
|
RxReceived = Mvpp2RxqReceived (Port, Rxq->Id);
|
if (!RxReceived) {
|
return;
|
}
|
|
Mvpp2RxqStatusUpdate (Port, Rxq->Id, RxReceived, RxReceived);
|
}
|
|
VOID
|
Mvpp2RxqHwDeinit (
|
IN PP2DXE_PORT *Port,
|
IN OUT MVPP2_RX_QUEUE *Rxq
|
)
|
{
|
Rxq->Descs = NULL;
|
Rxq->LastDesc = 0;
|
Rxq->NextDescToProc = 0;
|
Rxq->DescsPhys = 0;
|
|
/*
|
* Clear Rx descriptors Queue starting Address and Size;
|
* free descriptor number
|
*/
|
Mvpp2Write (Port->Priv, MVPP2_RXQ_STATUS_REG(Rxq->Id), 0);
|
Mvpp2Write (Port->Priv, MVPP2_RXQ_NUM_REG, Rxq->Id);
|
Mvpp2Write (Port->Priv, MVPP2_RXQ_DESC_ADDR_REG, 0);
|
Mvpp2Write (Port->Priv, MVPP2_RXQ_DESC_SIZE_REG, 0);
|
}
|
|
/* Configure TXQ's */
|
VOID
|
Mvpp2TxqHwInit (
|
IN PP2DXE_PORT *Port,
|
IN OUT MVPP2_TX_QUEUE *Txq
|
)
|
{
|
INT32 Desc, DescPerTxq, TxPortNum;
|
UINT32 Val;
|
|
Txq->LastDesc = Txq->Size - 1;
|
|
/* Set Tx descriptors Queue starting Address - indirect access */
|
Mvpp2Write (Port->Priv, MVPP2_TXQ_NUM_REG, Txq->Id);
|
Mvpp2Write (Port->Priv, MVPP2_TXQ_DESC_ADDR_REG, Txq->DescsPhys);
|
Mvpp2Write (Port->Priv, MVPP2_TXQ_DESC_SIZE_REG, Txq->Size & MVPP2_TXQ_DESC_SIZE_MASK);
|
Mvpp2Write (Port->Priv, MVPP2_TXQ_INDEX_REG, 0);
|
Mvpp2Write (Port->Priv, MVPP2_TXQ_RSVD_CLR_REG, Txq->Id << MVPP2_TXQ_RSVD_CLR_OFFSET);
|
Val = Mvpp2Read (Port->Priv, MVPP2_TXQ_PENDING_REG);
|
Val &= ~MVPP2_TXQ_PENDING_MASK;
|
Mvpp2Write (Port->Priv, MVPP2_TXQ_PENDING_REG, Val);
|
|
/*
|
* Calculate base Address in prefetch buffer. We reserve 16 descriptors
|
* for each existing TXQ.
|
* TCONTS for PON Port must be continuous from 0 to MVPP2_MAX_TCONT
|
* GBE Ports assumed to be continious from 0 to MVPP2_MAX_PORTS
|
*/
|
DescPerTxq = 16;
|
Desc = (Port->Id * MVPP2_MAX_TXQ * DescPerTxq) + (Txq->LogId * DescPerTxq);
|
|
Mvpp2Write (
|
Port->Priv,
|
MVPP2_TXQ_PREF_BUF_REG,
|
MVPP2_PREF_BUF_PTR (Desc) | MVPP2_PREF_BUF_SIZE_16 | MVPP2_PREF_BUF_THRESH (DescPerTxq/2)
|
);
|
|
/* WRR / EJP configuration - indirect access */
|
TxPortNum = Mvpp2EgressPort (Port);
|
Mvpp2Write (Port->Priv, MVPP2_TXP_SCHED_PORT_INDEX_REG, TxPortNum);
|
|
Val = Mvpp2Read (Port->Priv, MVPP2_TXQ_SCHED_REFILL_REG(Txq->LogId));
|
Val &= ~MVPP2_TXQ_REFILL_PERIOD_ALL_MASK;
|
Val |= MVPP2_TXQ_REFILL_PERIOD_MASK (1);
|
Val |= MVPP2_TXQ_REFILL_TOKENS_ALL_MASK;
|
Mvpp2Write (Port->Priv, MVPP2_TXQ_SCHED_REFILL_REG(Txq->LogId), Val);
|
|
Val = MVPP2_TXQ_TOKEN_SIZE_MAX;
|
Mvpp2Write (Port->Priv, MVPP2_TXQ_SCHED_TOKEN_SIZE_REG(Txq->LogId), Val);
|
}
|
|
VOID
|
Mvpp2TxqHwDeinit (
|
IN PP2DXE_PORT *Port,
|
IN OUT MVPP2_TX_QUEUE *Txq
|
)
|
{
|
Txq->Descs = NULL;
|
Txq->LastDesc = 0;
|
Txq->NextDescToProc = 0;
|
Txq->DescsPhys = 0;
|
|
/* Set minimum bandwidth for disabled TXQs */
|
Mvpp2Write (Port->Priv, MVPP2_TXQ_SCHED_TOKEN_CNTR_REG(Txq->Id), 0);
|
|
/* Set Tx descriptors Queue starting Address and Size */
|
Mvpp2Write (Port->Priv, MVPP2_TXQ_NUM_REG, Txq->Id);
|
Mvpp2Write (Port->Priv, MVPP2_TXQ_DESC_ADDR_REG, 0);
|
Mvpp2Write (Port->Priv, MVPP2_TXQ_DESC_SIZE_REG, 0);
|
}
|
|
/* Allocate and initialize descriptors for aggr TXQ */
|
VOID
|
Mvpp2AggrTxqHwInit (
|
IN OUT MVPP2_TX_QUEUE *AggrTxq,
|
IN INT32 DescNum,
|
IN INT32 Cpu,
|
IN MVPP2_SHARED *Priv
|
)
|
{
|
AggrTxq->LastDesc = AggrTxq->Size - 1;
|
|
/* Aggr TXQ no Reset WA */
|
AggrTxq->NextDescToProc = Mvpp2Read (Priv, MVPP2_AGGR_TXQ_INDEX_REG(Cpu));
|
|
/* Set Tx descriptors Queue starting Address (indirect access) */
|
Mvpp2Write (Priv, MVPP2_AGGR_TXQ_DESC_ADDR_REG(Cpu), AggrTxq->DescsPhys >> MVPP22_DESC_ADDR_SHIFT);
|
Mvpp2Write (Priv, MVPP2_AGGR_TXQ_DESC_SIZE_REG(Cpu), DescNum & MVPP2_AGGR_TXQ_DESC_SIZE_MASK);
|
}
|
|
/* Enable gmac */
|
VOID
|
Mvpp2PortPowerUp (
|
IN PP2DXE_PORT *Port
|
)
|
{
|
Mvpp2PortMiiSet (Port);
|
Mvpp2PortPeriodicXonDisable (Port);
|
Mvpp2PortFcAdvEnable (Port);
|
Mvpp2PortReset (Port);
|
}
|
|
/* Initialize Rx FIFO's */
|
VOID
|
Mvpp2RxFifoInit (
|
IN MVPP2_SHARED *Priv
|
)
|
{
|
INT32 PortId;
|
|
for (PortId = 0; PortId < MVPP2_MAX_PORTS; PortId++) {
|
Mvpp2Write (Priv, MVPP2_RX_DATA_FIFO_SIZE_REG(PortId), MVPP2_RX_FIFO_PORT_DATA_SIZE);
|
Mvpp2Write (Priv, MVPP2_RX_ATTR_FIFO_SIZE_REG(PortId), MVPP2_RX_FIFO_PORT_ATTR_SIZE);
|
}
|
|
Mvpp2Write (Priv, MVPP2_RX_MIN_PKT_SIZE_REG, MVPP2_RX_FIFO_PORT_MIN_PKT);
|
Mvpp2Write (Priv, MVPP2_RX_FIFO_INIT_REG, 0x1);
|
}
|
|
VOID
|
MvGop110NetcActivePort (
|
IN PP2DXE_PORT *Port,
|
IN UINT32 PortId,
|
IN UINT32 Val
|
)
|
{
|
UINT32 RegVal;
|
|
RegVal = Mvpp2Rfu1Read (Port->Priv, MV_NETCOMP_PORTS_CONTROL_1);
|
RegVal &= ~(NETC_PORTS_ACTIVE_MASK (PortId));
|
|
Val <<= NETC_PORTS_ACTIVE_OFFSET (PortId);
|
Val &= NETC_PORTS_ACTIVE_MASK (PortId);
|
|
RegVal |= Val;
|
|
Mvpp2Rfu1Write (Port->Priv, MV_NETCOMP_PORTS_CONTROL_1, RegVal);
|
}
|
|
STATIC
|
VOID
|
MvGop110NetcXauiEnable (
|
IN PP2DXE_PORT *Port,
|
IN UINT32 PortId,
|
IN UINT32 Val
|
)
|
{
|
UINT32 RegVal;
|
|
RegVal = Mvpp2Rfu1Read (Port->Priv, SD1_CONTROL_1_REG);
|
RegVal &= ~SD1_CONTROL_XAUI_EN_MASK;
|
|
Val <<= SD1_CONTROL_XAUI_EN_OFFSET;
|
Val &= SD1_CONTROL_XAUI_EN_MASK;
|
|
RegVal |= Val;
|
|
Mvpp2Rfu1Write (Port->Priv, SD1_CONTROL_1_REG, RegVal);
|
}
|
|
STATIC
|
VOID
|
MvGop110NetcRxaui0Enable (
|
IN PP2DXE_PORT *Port,
|
IN UINT32 PortId,
|
IN UINT32 Val
|
)
|
{
|
UINT32 RegVal;
|
|
RegVal = Mvpp2Rfu1Read (Port->Priv, SD1_CONTROL_1_REG);
|
RegVal &= ~SD1_CONTROL_RXAUI0_L23_EN_MASK;
|
|
Val <<= SD1_CONTROL_RXAUI0_L23_EN_OFFSET;
|
Val &= SD1_CONTROL_RXAUI0_L23_EN_MASK;
|
|
RegVal |= Val;
|
|
Mvpp2Rfu1Write (Port->Priv, SD1_CONTROL_1_REG, RegVal);
|
}
|
|
STATIC
|
VOID
|
MvGop110NetcRxaui1Enable (
|
IN PP2DXE_PORT *Port,
|
IN UINT32 PortId,
|
IN UINT32 Val
|
)
|
{
|
UINT32 RegVal;
|
|
RegVal = Mvpp2Rfu1Read (Port->Priv, SD1_CONTROL_1_REG);
|
RegVal &= ~SD1_CONTROL_RXAUI1_L45_EN_MASK;
|
|
Val <<= SD1_CONTROL_RXAUI1_L45_EN_OFFSET;
|
Val &= SD1_CONTROL_RXAUI1_L45_EN_MASK;
|
|
RegVal |= Val;
|
|
Mvpp2Rfu1Write (Port->Priv, SD1_CONTROL_1_REG, RegVal);
|
}
|
|
STATIC
|
VOID
|
MvGop110NetcMiiMode (
|
IN PP2DXE_PORT *Port,
|
IN UINT32 PortId,
|
IN UINT32 Val
|
)
|
{
|
UINT32 RegVal;
|
|
RegVal = Mvpp2Rfu1Read (Port->Priv, MV_NETCOMP_CONTROL_0);
|
RegVal &= ~NETC_GBE_PORT1_MII_MODE_MASK;
|
|
Val <<= NETC_GBE_PORT1_MII_MODE_OFFSET;
|
Val &= NETC_GBE_PORT1_MII_MODE_MASK;
|
|
RegVal |= Val;
|
|
Mvpp2Rfu1Write (Port->Priv, MV_NETCOMP_CONTROL_0, RegVal);
|
}
|
|
STATIC
|
VOID
|
MvGop110NetcGopReset (
|
IN PP2DXE_PORT *Port,
|
IN UINT32 Val
|
)
|
{
|
UINT32 RegVal;
|
|
RegVal = Mvpp2Rfu1Read (Port->Priv, MV_GOP_SOFT_RESET_1_REG);
|
RegVal &= ~NETC_GOP_SOFT_RESET_MASK;
|
|
Val <<= NETC_GOP_SOFT_RESET_OFFSET;
|
Val &= NETC_GOP_SOFT_RESET_MASK;
|
|
RegVal |= Val;
|
|
Mvpp2Rfu1Write (Port->Priv, MV_GOP_SOFT_RESET_1_REG, RegVal);
|
}
|
|
STATIC
|
VOID
|
MvGop110NetcGopClockLogicSet (
|
IN PP2DXE_PORT *Port,
|
IN UINT32 Val
|
)
|
{
|
UINT32 RegVal;
|
|
RegVal = Mvpp2Rfu1Read (Port->Priv, MV_NETCOMP_PORTS_CONTROL_0);
|
RegVal &= ~NETC_CLK_DIV_PHASE_MASK;
|
|
Val <<= NETC_CLK_DIV_PHASE_OFFSET;
|
Val &= NETC_CLK_DIV_PHASE_MASK;
|
|
RegVal |= Val;
|
|
Mvpp2Rfu1Write (Port->Priv, MV_NETCOMP_PORTS_CONTROL_0, RegVal);
|
}
|
|
STATIC
|
VOID
|
MvGop110NetcPortRfReset (
|
IN PP2DXE_PORT *Port,
|
IN UINT32 PortId,
|
IN UINT32 Val
|
)
|
{
|
UINT32 RegVal;
|
|
RegVal = Mvpp2Rfu1Read (Port->Priv, MV_NETCOMP_PORTS_CONTROL_1);
|
RegVal &= ~(NETC_PORT_GIG_RF_RESET_MASK (PortId));
|
|
Val <<= NETC_PORT_GIG_RF_RESET_OFFSET (PortId);
|
Val &= NETC_PORT_GIG_RF_RESET_MASK (PortId);
|
|
RegVal |= Val;
|
|
Mvpp2Rfu1Write (Port->Priv, MV_NETCOMP_PORTS_CONTROL_1, RegVal);
|
}
|
|
STATIC
|
VOID
|
MvGop110NetcGbeSgmiiModeSelect (
|
IN PP2DXE_PORT *Port,
|
IN UINT32 PortId,
|
IN UINT32 Val
|
)
|
{
|
UINT32 RegVal, Mask, Offset;
|
|
if (PortId == 2) {
|
Mask = NETC_GBE_PORT0_SGMII_MODE_MASK;
|
Offset = NETC_GBE_PORT0_SGMII_MODE_OFFSET;
|
} else {
|
Mask = NETC_GBE_PORT1_SGMII_MODE_MASK;
|
Offset = NETC_GBE_PORT1_SGMII_MODE_OFFSET;
|
}
|
RegVal = Mvpp2Rfu1Read (Port->Priv, MV_NETCOMP_CONTROL_0);
|
RegVal &= ~Mask;
|
|
Val <<= Offset;
|
Val &= Mask;
|
|
RegVal |= Val;
|
|
Mvpp2Rfu1Write (Port->Priv, MV_NETCOMP_CONTROL_0, RegVal);
|
}
|
|
STATIC
|
VOID
|
MvGop110NetcBusWidthSelect (
|
IN PP2DXE_PORT *Port,
|
IN UINT32 Val
|
)
|
{
|
UINT32 RegVal;
|
|
RegVal = Mvpp2Rfu1Read (Port->Priv, MV_NETCOMP_PORTS_CONTROL_0);
|
RegVal &= ~NETC_BUS_WIDTH_SELECT_MASK;
|
|
Val <<= NETC_BUS_WIDTH_SELECT_OFFSET;
|
Val &= NETC_BUS_WIDTH_SELECT_MASK;
|
|
RegVal |= Val;
|
|
Mvpp2Rfu1Write (Port->Priv, MV_NETCOMP_PORTS_CONTROL_0, RegVal);
|
}
|
|
STATIC
|
VOID
|
MvGop110NetcSampleStagesTiming (
|
IN PP2DXE_PORT *Port,
|
IN UINT32 Val
|
)
|
{
|
UINT32 RegVal;
|
|
RegVal = Mvpp2Rfu1Read (Port->Priv, MV_NETCOMP_PORTS_CONTROL_0);
|
RegVal &= ~NETC_GIG_RX_DATA_SAMPLE_MASK;
|
|
Val <<= NETC_GIG_RX_DATA_SAMPLE_OFFSET;
|
Val &= NETC_GIG_RX_DATA_SAMPLE_MASK;
|
|
RegVal |= Val;
|
|
Mvpp2Rfu1Write (Port->Priv, MV_NETCOMP_PORTS_CONTROL_0, RegVal);
|
}
|
|
STATIC
|
VOID
|
MvGop110NetcMacToXgmii (
|
IN PP2DXE_PORT *Port,
|
IN UINT32 PortId,
|
IN enum MvNetcPhase Phase
|
)
|
{
|
switch (Phase) {
|
case MV_NETC_FIRST_PHASE:
|
|
/* Set Bus Width to HB mode = 1 */
|
MvGop110NetcBusWidthSelect (Port, 0x1);
|
|
/* Select RGMII mode */
|
MvGop110NetcGbeSgmiiModeSelect (Port, PortId, MV_NETC_GBE_XMII);
|
break;
|
case MV_NETC_SECOND_PHASE:
|
|
/* De-assert the relevant PortId HB Reset */
|
MvGop110NetcPortRfReset (Port, PortId, 0x1);
|
break;
|
}
|
}
|
|
STATIC
|
VOID
|
MvGop110NetcMacToSgmii (
|
IN PP2DXE_PORT *Port,
|
IN UINT32 PortId,
|
IN enum MvNetcPhase Phase
|
)
|
{
|
switch (Phase) {
|
case MV_NETC_FIRST_PHASE:
|
|
/* Set Bus Width to HB mode = 1 */
|
MvGop110NetcBusWidthSelect (Port, 1);
|
|
/* Select SGMII mode */
|
if (PortId >= 1) {
|
MvGop110NetcGbeSgmiiModeSelect (Port, PortId, MV_NETC_GBE_SGMII);
|
}
|
|
/* Configure the sample stages */
|
MvGop110NetcSampleStagesTiming (Port, 0);
|
break;
|
case MV_NETC_SECOND_PHASE:
|
|
/* De-assert the relevant PortId HB Reset */
|
MvGop110NetcPortRfReset (Port, PortId, 1);
|
break;
|
}
|
}
|
|
STATIC
|
VOID
|
MvGop110NetcMacToRxaui (
|
IN PP2DXE_PORT *Port,
|
IN UINT32 PortId,
|
IN enum MvNetcPhase Phase,
|
IN enum MvNetcLanes Lanes
|
)
|
{
|
/* Currently only RXAUI0 supPorted */
|
if (PortId != 0)
|
return;
|
|
switch (Phase) {
|
case MV_NETC_FIRST_PHASE:
|
|
/* RXAUI Serdes/s Clock alignment */
|
if (Lanes == MV_NETC_LANE_23) {
|
MvGop110NetcRxaui0Enable (Port, PortId, 1);
|
} else {
|
MvGop110NetcRxaui1Enable (Port, PortId, 1);
|
}
|
break;
|
case MV_NETC_SECOND_PHASE:
|
|
/* De-assert the relevant PortId HB Reset */
|
MvGop110NetcPortRfReset (Port, PortId, 1);
|
break;
|
}
|
}
|
|
STATIC
|
VOID
|
MvGop110NetcMacToXaui (
|
IN PP2DXE_PORT *Port,
|
IN UINT32 PortId,
|
IN enum MvNetcPhase Phase
|
)
|
{
|
switch (Phase) {
|
case MV_NETC_FIRST_PHASE:
|
|
/* RXAUI Serdes/s Clock alignment */
|
MvGop110NetcXauiEnable (Port, PortId, 1);
|
break;
|
case MV_NETC_SECOND_PHASE:
|
|
/* De-assert the relevant PortId HB Reset */
|
MvGop110NetcPortRfReset (Port, PortId, 1);
|
break;
|
}
|
}
|
|
INT32
|
MvGop110NetcInit (
|
IN PP2DXE_PORT *Port,
|
IN UINT32 NetCompConfig,
|
IN enum MvNetcPhase Phase
|
)
|
{
|
UINT32 c = NetCompConfig;
|
|
if (c & MV_NETC_GE_MAC0_RXAUI_L23) {
|
MvGop110NetcMacToRxaui (Port, 0, Phase, MV_NETC_LANE_23);
|
}
|
|
if (c & MV_NETC_GE_MAC0_RXAUI_L45) {
|
MvGop110NetcMacToRxaui (Port, 0, Phase, MV_NETC_LANE_45);
|
}
|
|
if (c & MV_NETC_GE_MAC0_XAUI) {
|
MvGop110NetcMacToXaui (Port, 0, Phase);
|
}
|
|
if (c & MV_NETC_GE_MAC2_SGMII) {
|
MvGop110NetcMacToSgmii (Port, 2, Phase);
|
} else {
|
MvGop110NetcMacToXgmii (Port, 2, Phase);
|
}
|
|
if (c & MV_NETC_GE_MAC3_SGMII) {
|
MvGop110NetcMacToSgmii (Port, 3, Phase);
|
} else {
|
MvGop110NetcMacToXgmii (Port, 3, Phase);
|
if (c & MV_NETC_GE_MAC3_RGMII) {
|
MvGop110NetcMiiMode (Port, 3, MV_NETC_GBE_RGMII);
|
} else {
|
MvGop110NetcMiiMode (Port, 3, MV_NETC_GBE_MII);
|
}
|
}
|
|
/* Activate gop Ports 0, 2, 3 */
|
MvGop110NetcActivePort (Port, 0, 1);
|
MvGop110NetcActivePort (Port, 2, 1);
|
MvGop110NetcActivePort (Port, 3, 1);
|
|
if (Phase == MV_NETC_SECOND_PHASE) {
|
|
/* Enable the GOP internal clock logic */
|
MvGop110NetcGopClockLogicSet (Port, 1);
|
|
/* De-assert GOP unit Reset */
|
MvGop110NetcGopReset (Port, 1);
|
}
|
|
return 0;
|
}
|
|
UINT32
|
MvpPp2xGop110NetcCfgCreate (
|
IN PP2DXE_PORT *Port
|
)
|
{
|
UINT32 Val = 0;
|
|
if (Port->GopIndex == 0) {
|
if (Port->PhyInterface == MV_MODE_XAUI) {
|
Val |= MV_NETC_GE_MAC0_XAUI;
|
} else if (Port->PhyInterface == MV_MODE_RXAUI) {
|
Val |= MV_NETC_GE_MAC0_RXAUI_L23;
|
}
|
}
|
|
if (Port->GopIndex == 2) {
|
if (Port->PhyInterface == MV_MODE_SGMII) {
|
Val |= MV_NETC_GE_MAC2_SGMII;
|
}
|
}
|
|
if (Port->GopIndex == 3) {
|
if (Port->PhyInterface == MV_MODE_SGMII) {
|
Val |= MV_NETC_GE_MAC3_SGMII;
|
} else if (Port->PhyInterface == MV_MODE_RGMII) {
|
Val |= MV_NETC_GE_MAC3_RGMII;
|
}
|
}
|
|
return Val;
|
}
|
|
/*
|
* Initialize physical Port. Configure the Port mode and
|
* all its elements accordingly.
|
*/
|
INT32
|
MvGop110PortInit (
|
IN PP2DXE_PORT *Port
|
)
|
{
|
|
switch (Port->PhyInterface) {
|
case MV_MODE_RGMII:
|
MvGop110GmacReset (Port, RESET);
|
|
/* Configure PCS */
|
MvGop110GpcsModeCfg (Port, FALSE);
|
MvGop110BypassClkCfg (Port, TRUE);
|
|
/* Configure MAC */
|
MvGop110GmacModeCfg (Port);
|
|
/* PCS unreset */
|
MvGop110GpcsReset (Port, UNRESET);
|
|
/* MAC unreset */
|
MvGop110GmacReset (Port, UNRESET);
|
break;
|
case MV_MODE_SGMII:
|
case MV_MODE_QSGMII:
|
|
/* Configure PCS */
|
MvGop110GpcsModeCfg (Port, TRUE);
|
|
/* Configure MAC */
|
MvGop110GmacModeCfg (Port);
|
|
/* Select proper MAC mode */
|
MvGop110Xlg2GigMacCfg (Port);
|
|
/* PCS unreset */
|
MvGop110GpcsReset (Port, UNRESET);
|
|
/* MAC unreset */
|
MvGop110GmacReset (Port, UNRESET);
|
break;
|
case MV_MODE_SFI:
|
/* Configure PCS */
|
MvGopXpcsModeCfg (Port, MVPP2_SFI_LANE_COUNT);
|
|
MvGopMpcsModeCfg (Port);
|
|
/* Configure MAC */
|
MvGopXlgMacModeCfg (Port);
|
|
/* PCS unreset */
|
MvGopXpcsUnreset (Port);
|
|
/* MAC unreset */
|
MvGopXlgMacUnreset (Port);
|
break;
|
default:
|
return -1;
|
}
|
|
return 0;
|
}
|
|
/* Set the MAC to Reset or exit from Reset */
|
INT32
|
MvGop110GmacReset (
|
IN PP2DXE_PORT *Port,
|
IN enum MvReset ResetCmd
|
)
|
{
|
UINT32 RegAddr;
|
UINT32 Val;
|
|
RegAddr = MVPP2_PORT_CTRL2_REG;
|
|
Val = MvGop110GmacRead (Port, RegAddr);
|
|
if (ResetCmd == RESET) {
|
Val |= MVPP2_PORT_CTRL2_PORTMACRESET_MASK;
|
} else {
|
Val &= ~MVPP2_PORT_CTRL2_PORTMACRESET_MASK;
|
}
|
|
MvGop110GmacWrite (Port, RegAddr, Val);
|
|
return 0;
|
}
|
|
/* Enable/Disable Port to work with Gig PCS */
|
INT32
|
MvGop110GpcsModeCfg (
|
IN PP2DXE_PORT *Port,
|
BOOLEAN En
|
)
|
{
|
UINT32 Val;
|
|
Val = MvGop110GmacRead (Port, MVPP2_PORT_CTRL2_REG);
|
|
if (En) {
|
Val |= MVPP2_PORT_CTRL2_PCS_EN_MASK;
|
} else {
|
Val &= ~MVPP2_PORT_CTRL2_PCS_EN_MASK;
|
}
|
|
MvGop110GmacWrite (Port, MVPP2_PORT_CTRL2_REG, Val);
|
|
return 0;
|
}
|
|
INT32
|
MvGop110BypassClkCfg (
|
IN PP2DXE_PORT *Port,
|
IN BOOLEAN En
|
)
|
{
|
UINT32 Val;
|
|
Val = MvGop110GmacRead (Port, MVPP2_PORT_CTRL2_REG);
|
|
if (En) {
|
Val |= MVPP2_PORT_CTRL2_CLK_125_BYPS_EN_MASK;
|
} else {
|
Val &= ~MVPP2_PORT_CTRL2_CLK_125_BYPS_EN_MASK;
|
}
|
|
MvGop110GmacWrite (Port, MVPP2_PORT_CTRL2_REG, Val);
|
|
return 0;
|
}
|
|
INT32
|
MvGop110GpcsReset (
|
IN PP2DXE_PORT *Port,
|
IN enum MvReset ResetCmd
|
)
|
{
|
UINT32 RegData;
|
|
RegData = MvGop110GmacRead (Port, MVPP2_PORT_CTRL2_REG);
|
|
if (ResetCmd == RESET) {
|
U32_SET_FIELD (
|
RegData,
|
MVPP2_PORT_CTRL2_SGMII_MODE_MASK,
|
0
|
);
|
|
} else {
|
U32_SET_FIELD (
|
RegData,
|
MVPP2_PORT_CTRL2_SGMII_MODE_MASK,
|
1 << MVPP2_PORT_CTRL2_SGMII_MODE_OFFS
|
);
|
|
}
|
|
MvGop110GmacWrite (Port, MVPP2_PORT_CTRL2_REG, RegData);
|
|
return 0;
|
}
|
|
VOID
|
MvGop110Xlg2GigMacCfg (
|
IN PP2DXE_PORT *Port
|
)
|
{
|
UINT32 RegVal;
|
|
/* Relevant only for MAC0 (XLG0 and GMAC0) */
|
if (Port->GopIndex > 0) {
|
return;
|
}
|
|
/* Configure 1Gig MAC mode */
|
RegVal = Mvpp2XlgRead (Port, MV_XLG_PORT_MAC_CTRL3_REG);
|
U32_SET_FIELD (
|
RegVal,
|
MV_XLG_MAC_CTRL3_MACMODESELECT_MASK,
|
(0 << MV_XLG_MAC_CTRL3_MACMODESELECT_OFFS)
|
);
|
|
Mvpp2XlgWrite (Port, MV_XLG_PORT_MAC_CTRL3_REG, RegVal);
|
}
|
|
/* Set the internal mux's to the required MAC in the GOP */
|
INT32
|
MvGop110GmacModeCfg (
|
IN PP2DXE_PORT *Port
|
)
|
{
|
UINT32 RegAddr;
|
UINT32 Val;
|
|
/* Set TX FIFO thresholds */
|
switch (Port->PhyInterface) {
|
case MV_MODE_SGMII:
|
if (Port->Speed == MV_PORT_SPEED_2500) {
|
MvGop110GmacSgmii25Cfg (Port);
|
} else {
|
MvGop110GmacSgmiiCfg (Port);
|
}
|
break;
|
case MV_MODE_RGMII:
|
MvGop110GmacRgmiiCfg (Port);
|
break;
|
case MV_MODE_QSGMII:
|
MvGop110GmacQsgmiiCfg (Port);
|
break;
|
default:
|
return -1;
|
}
|
|
/* Jumbo frame supPort - 0x1400*2= 0x2800 bytes */
|
Val = MvGop110GmacRead (Port, MVPP2_PORT_CTRL0_REG);
|
U32_SET_FIELD (
|
Val,
|
MVPP2_PORT_CTRL0_FRAMESIZELIMIT_MASK,
|
(0x1400 << MVPP2_PORT_CTRL0_FRAMESIZELIMIT_OFFS)
|
);
|
|
MvGop110GmacWrite (Port, MVPP2_PORT_CTRL0_REG, Val);
|
|
/* PeriodicXonEn disable */
|
RegAddr = MVPP2_PORT_CTRL1_REG;
|
Val = MvGop110GmacRead (Port, RegAddr);
|
Val &= ~MVPP2_PORT_CTRL1_EN_PERIODIC_FC_XON_MASK;
|
MvGop110GmacWrite (Port, RegAddr, Val);
|
|
/* Mask all Ports interrupts */
|
MvGop110GmacPortLinkEventMask (Port);
|
|
#if MV_PP2x_INTERRUPT
|
/* Unmask link change interrupt */
|
Val = MvGop110GmacRead (Port, MVPP2_INTERRUPT_MASK_REG);
|
Val |= MVPP2_INTERRUPT_CAUSE_LINK_CHANGE_MASK;
|
Val |= 1; /* Unmask summary bit */
|
MvGop110GmacWrite (Port, MVPP2_INTERRUPT_MASK_REG, Val);
|
#endif
|
|
return 0;
|
}
|
|
VOID
|
MvGop110GmacRgmiiCfg (
|
IN PP2DXE_PORT *Port
|
)
|
{
|
UINT32 Val, thresh, an;
|
|
/* Configure minimal level of the Tx FIFO before the lower part starts to read a packet*/
|
thresh = MV_RGMII_TX_FIFO_MIN_TH;
|
Val = MvGop110GmacRead (Port, MVPP2_PORT_FIFO_CFG_1_REG);
|
U32_SET_FIELD (
|
Val,
|
MVPP2_PORT_FIFO_CFG_1_TX_FIFO_MIN_TH_MASK,
|
(thresh << MVPP2_PORT_FIFO_CFG_1_TX_FIFO_MIN_TH_OFFS)
|
);
|
|
MvGop110GmacWrite (Port, MVPP2_PORT_FIFO_CFG_1_REG, Val);
|
|
/* Disable bypass of sync module */
|
Val = MvGop110GmacRead (Port, MVPP2_PORT_CTRL4_REG);
|
Val |= MVPP2_PORT_CTRL4_SYNC_BYPASS_MASK;
|
|
/* Configure DP clock select according to mode */
|
Val &= ~MVPP2_PORT_CTRL4_DP_CLK_SEL_MASK;
|
Val |= MVPP2_PORT_CTRL4_QSGMII_BYPASS_ACTIVE_MASK;
|
Val |= MVPP2_PORT_CTRL4_EXT_PIN_GMII_SEL_MASK;
|
MvGop110GmacWrite (Port, MVPP2_PORT_CTRL4_REG, Val);
|
|
Val = MvGop110GmacRead (Port, MVPP2_PORT_CTRL2_REG);
|
Val &= ~MVPP2_PORT_CTRL2_DIS_PADING_OFFS;
|
MvGop110GmacWrite (Port, MVPP2_PORT_CTRL2_REG, Val);
|
|
/* Configure GIG MAC to SGMII mode */
|
Val = MvGop110GmacRead (Port, MVPP2_PORT_CTRL0_REG);
|
Val &= ~MVPP2_PORT_CTRL0_PORTTYPE_MASK;
|
MvGop110GmacWrite (Port, MVPP2_PORT_CTRL0_REG, Val);
|
|
/* configure AN 0xb8e8 */
|
an = MVPP2_PORT_AUTO_NEG_CFG_AN_BYPASS_EN_MASK |
|
MVPP2_PORT_AUTO_NEG_CFG_EN_AN_SPEED_MASK |
|
MVPP2_PORT_AUTO_NEG_CFG_EN_FC_AN_MASK |
|
MVPP2_PORT_AUTO_NEG_CFG_EN_FDX_AN_MASK |
|
MVPP2_PORT_AUTO_NEG_CFG_CHOOSE_SAMPLE_TX_CONFIG_MASK;
|
MvGop110GmacWrite (Port, MVPP2_PORT_AUTO_NEG_CFG_REG, an);
|
}
|
|
VOID
|
MvGop110GmacSgmii25Cfg (
|
IN PP2DXE_PORT *Port
|
)
|
{
|
UINT32 Val, thresh, an;
|
|
/*
|
* Configure minimal level of the Tx FIFO before
|
* the lower part starts to read a packet.
|
*/
|
thresh = MV_SGMII2_5_TX_FIFO_MIN_TH;
|
Val = MvGop110GmacRead (Port, MVPP2_PORT_FIFO_CFG_1_REG);
|
U32_SET_FIELD (
|
Val,
|
MVPP2_PORT_FIFO_CFG_1_TX_FIFO_MIN_TH_MASK,
|
(thresh << MVPP2_PORT_FIFO_CFG_1_TX_FIFO_MIN_TH_OFFS)
|
);
|
|
MvGop110GmacWrite (Port, MVPP2_PORT_FIFO_CFG_1_REG, Val);
|
|
/* Disable bypass of sync module */
|
Val = MvGop110GmacRead (Port, MVPP2_PORT_CTRL4_REG);
|
Val |= MVPP2_PORT_CTRL4_SYNC_BYPASS_MASK;
|
|
/* Configure DP clock select according to mode */
|
Val |= MVPP2_PORT_CTRL4_DP_CLK_SEL_MASK;
|
|
/* Configure QSGMII bypass according to mode */
|
Val |= MVPP2_PORT_CTRL4_QSGMII_BYPASS_ACTIVE_MASK;
|
MvGop110GmacWrite (Port, MVPP2_PORT_CTRL4_REG, Val);
|
|
Val = MvGop110GmacRead (Port, MVPP2_PORT_CTRL2_REG);
|
Val |= MVPP2_PORT_CTRL2_DIS_PADING_OFFS;
|
MvGop110GmacWrite (Port, MVPP2_PORT_CTRL2_REG, Val);
|
|
/* Configure GIG MAC to 1000Base-X mode connected to a fiber transceiver */
|
Val = MvGop110GmacRead (Port, MVPP2_PORT_CTRL0_REG);
|
Val |= MVPP2_PORT_CTRL0_PORTTYPE_MASK;
|
MvGop110GmacWrite (Port, MVPP2_PORT_CTRL0_REG, Val);
|
|
/* configure AN 0x9268 */
|
an = MVPP2_PORT_AUTO_NEG_CFG_EN_PCS_AN_MASK |
|
MVPP2_PORT_AUTO_NEG_CFG_AN_BYPASS_EN_MASK |
|
MVPP2_PORT_AUTO_NEG_CFG_SET_MII_SPEED_MASK |
|
MVPP2_PORT_AUTO_NEG_CFG_SET_GMII_SPEED_MASK |
|
MVPP2_PORT_AUTO_NEG_CFG_ADV_PAUSE_MASK |
|
MVPP2_PORT_AUTO_NEG_CFG_SET_FULL_DX_MASK |
|
MVPP2_PORT_AUTO_NEG_CFG_CHOOSE_SAMPLE_TX_CONFIG_MASK;
|
MvGop110GmacWrite (Port, MVPP2_PORT_AUTO_NEG_CFG_REG, an);
|
}
|
|
VOID
|
MvGop110GmacSgmiiCfg (
|
IN PP2DXE_PORT *Port
|
)
|
{
|
UINT32 Val, thresh, an;
|
|
/*
|
* Configure minimal level of the Tx FIFO before
|
* the lower part starts to read a packet.
|
*/
|
thresh = MV_SGMII_TX_FIFO_MIN_TH;
|
Val = MvGop110GmacRead (Port, MVPP2_PORT_FIFO_CFG_1_REG);
|
U32_SET_FIELD (Val, MVPP2_PORT_FIFO_CFG_1_TX_FIFO_MIN_TH_MASK,
|
(thresh << MVPP2_PORT_FIFO_CFG_1_TX_FIFO_MIN_TH_OFFS));
|
MvGop110GmacWrite (Port, MVPP2_PORT_FIFO_CFG_1_REG, Val);
|
|
/* Disable bypass of sync module */
|
Val = MvGop110GmacRead (Port, MVPP2_PORT_CTRL4_REG);
|
Val |= MVPP2_PORT_CTRL4_SYNC_BYPASS_MASK;
|
|
/* Configure DP clock select according to mode */
|
Val &= ~MVPP2_PORT_CTRL4_DP_CLK_SEL_MASK;
|
|
/* Configure QSGMII bypass according to mode */
|
Val |= MVPP2_PORT_CTRL4_QSGMII_BYPASS_ACTIVE_MASK;
|
MvGop110GmacWrite (Port, MVPP2_PORT_CTRL4_REG, Val);
|
|
Val = MvGop110GmacRead (Port, MVPP2_PORT_CTRL2_REG);
|
Val |= MVPP2_PORT_CTRL2_DIS_PADING_OFFS;
|
MvGop110GmacWrite (Port, MVPP2_PORT_CTRL2_REG, Val);
|
|
/* Configure GIG MAC to SGMII mode */
|
Val = MvGop110GmacRead (Port, MVPP2_PORT_CTRL0_REG);
|
Val &= ~MVPP2_PORT_CTRL0_PORTTYPE_MASK;
|
MvGop110GmacWrite (Port, MVPP2_PORT_CTRL0_REG, Val);
|
|
/* Configure AN */
|
an = MVPP2_PORT_AUTO_NEG_CFG_EN_PCS_AN_MASK |
|
MVPP2_PORT_AUTO_NEG_CFG_AN_BYPASS_EN_MASK |
|
MVPP2_PORT_AUTO_NEG_CFG_EN_AN_SPEED_MASK |
|
MVPP2_PORT_AUTO_NEG_CFG_EN_FC_AN_MASK |
|
MVPP2_PORT_AUTO_NEG_CFG_EN_FDX_AN_MASK |
|
MVPP2_PORT_AUTO_NEG_CFG_CHOOSE_SAMPLE_TX_CONFIG_MASK;
|
MvGop110GmacWrite (Port, MVPP2_PORT_AUTO_NEG_CFG_REG, an);
|
}
|
|
VOID
|
MvGop110GmacQsgmiiCfg (
|
IN PP2DXE_PORT *Port
|
)
|
{
|
UINT32 Val, thresh, an;
|
|
/*
|
* Configure minimal level of the Tx FIFO before
|
* the lower part starts to read a packet.
|
*/
|
thresh = MV_SGMII_TX_FIFO_MIN_TH;
|
Val = MvGop110GmacRead (Port, MVPP2_PORT_FIFO_CFG_1_REG);
|
U32_SET_FIELD (
|
Val,
|
MVPP2_PORT_FIFO_CFG_1_TX_FIFO_MIN_TH_MASK,
|
(thresh << MVPP2_PORT_FIFO_CFG_1_TX_FIFO_MIN_TH_OFFS)
|
);
|
|
MvGop110GmacWrite (Port, MVPP2_PORT_FIFO_CFG_1_REG, Val);
|
|
/* Disable bypass of sync module */
|
Val = MvGop110GmacRead (Port, MVPP2_PORT_CTRL4_REG);
|
Val |= MVPP2_PORT_CTRL4_SYNC_BYPASS_MASK;
|
|
/* Configure DP clock select according to mode */
|
Val &= ~MVPP2_PORT_CTRL4_DP_CLK_SEL_MASK;
|
Val &= ~MVPP2_PORT_CTRL4_EXT_PIN_GMII_SEL_MASK;
|
|
/* Configure QSGMII bypass according to mode */
|
Val &= ~MVPP2_PORT_CTRL4_QSGMII_BYPASS_ACTIVE_MASK;
|
MvGop110GmacWrite (Port, MVPP2_PORT_CTRL4_REG, Val);
|
|
Val = MvGop110GmacRead (Port, MVPP2_PORT_CTRL2_REG);
|
Val &= ~MVPP2_PORT_CTRL2_DIS_PADING_OFFS;
|
MvGop110GmacWrite (Port, MVPP2_PORT_CTRL2_REG, Val);
|
|
/* Configure GIG MAC to SGMII mode */
|
Val = MvGop110GmacRead (Port, MVPP2_PORT_CTRL0_REG);
|
Val &= ~MVPP2_PORT_CTRL0_PORTTYPE_MASK;
|
MvGop110GmacWrite (Port, MVPP2_PORT_CTRL0_REG, Val);
|
|
/* Configure AN 0xB8EC */
|
an = MVPP2_PORT_AUTO_NEG_CFG_EN_PCS_AN_MASK |
|
MVPP2_PORT_AUTO_NEG_CFG_AN_BYPASS_EN_MASK |
|
MVPP2_PORT_AUTO_NEG_CFG_EN_AN_SPEED_MASK |
|
MVPP2_PORT_AUTO_NEG_CFG_EN_FC_AN_MASK |
|
MVPP2_PORT_AUTO_NEG_CFG_EN_FDX_AN_MASK |
|
MVPP2_PORT_AUTO_NEG_CFG_CHOOSE_SAMPLE_TX_CONFIG_MASK;
|
MvGop110GmacWrite (Port, MVPP2_PORT_AUTO_NEG_CFG_REG, an);
|
}
|
|
INT32
|
Mvpp2SmiPhyAddrCfg (
|
IN PP2DXE_PORT *Port,
|
IN INT32 PortId,
|
IN INT32 Addr
|
)
|
{
|
Mvpp2SmiWrite (Port->Priv, MV_SMI_PHY_ADDRESS_REG(PortId), Addr);
|
|
return 0;
|
}
|
|
/* Set the internal mux's to the required PCS */
|
EFI_STATUS
|
MvGopXpcsModeCfg (
|
IN PP2DXE_PORT *Port,
|
IN INT32 NumOfLanes
|
)
|
{
|
UINT8 LaneCoeff;
|
|
switch (NumOfLanes) {
|
case 1:
|
case 2:
|
case 4:
|
LaneCoeff = NumOfLanes >> 1;
|
default:
|
return EFI_INVALID_PARAMETER;
|
}
|
|
/* Configure XG MAC mode */
|
MmioAndThenOr32 (Port->Priv->XpcsBase + MVPP22_XPCS_GLOBAL_CFG_0_REG,
|
~(MVPP22_XPCS_PCSMODE_MASK | MVPP22_XPCS_LANEACTIVE_MASK),
|
LaneCoeff << MVPP22_XPCS_LANEACTIVE_OFFS);
|
|
return EFI_SUCCESS;
|
}
|
|
VOID
|
MvGopMpcsModeCfg (
|
IN PP2DXE_PORT *Port
|
)
|
{
|
/* Configure MPCS40G COMMON CONTROL */
|
MmioAnd32 (Port->Priv->MpcsBase + MVPP22_MPCS40G_COMMON_CONTROL,
|
~MVPP22_MPCS_FORWARD_ERROR_CORRECTION_MASK);
|
|
/* Configure MPCS CLOCK RESET */
|
MmioAndThenOr32 (Port->Priv->MpcsBase + MVPP22_MPCS_CLOCK_RESET,
|
~(MVPP22_MPCS_CLK_DIVISION_RATIO_MASK | MVPP22_MPCS_CLK_DIV_PHASE_SET_MASK),
|
MVPP22_MPCS_CLK_DIVISION_RATIO_DEFAULT | MVPP22_MPCS_MAC_CLK_RESET_MASK |
|
MVPP22_MPCS_RX_SD_CLK_RESET_MASK | MVPP22_MPCS_TX_SD_CLK_RESET_MASK);
|
}
|
|
/* Set the internal mux's to the required MAC in the GOP */
|
VOID
|
MvGopXlgMacModeCfg (
|
IN PP2DXE_PORT *Port
|
)
|
{
|
/* Configure 10G MAC mode */
|
MmioOr32 (Port->XlgBase + MV_XLG_PORT_MAC_CTRL0_REG, MV_XLG_MAC_CTRL0_RXFCEN_MASK);
|
|
MmioAndThenOr32 (Port->XlgBase + MV_XLG_PORT_MAC_CTRL3_REG,
|
~MV_XLG_MAC_CTRL3_MACMODESELECT_MASK,
|
MV_XLG_MAC_CTRL3_MACMODESELECT_10G);
|
|
MmioAndThenOr32 (Port->XlgBase + MV_XLG_PORT_MAC_CTRL4_REG,
|
~(MV_XLG_MAC_CTRL4_MAC_MODE_DMA_1G_MASK | MV_XLG_MAC_CTRL4_EN_IDLE_CHECK_FOR_LINK_MASK),
|
MV_XLG_MAC_CTRL4_FORWARD_PFC_EN_MASK | MV_XLG_MAC_CTRL4_FORWARD_802_3X_FC_EN_MASK);
|
|
/* Configure frame size limit */
|
MmioAndThenOr32 (Port->XlgBase + MV_XLG_PORT_MAC_CTRL1_REG,
|
~MV_XLG_MAC_CTRL1_FRAMESIZELIMIT_MASK,
|
MV_XLG_MAC_CTRL1_FRAMESIZELIMIT_DEFAULT);
|
|
/* Mask all port's external interrupts */
|
MvGop110XlgPortLinkEventMask (Port);
|
|
/* Unmask link change interrupt - enable automatic status update */
|
MmioOr32 (Port->XlgBase + MV_XLG_INTERRUPT_MASK_REG,
|
MV_XLG_INTERRUPT_LINK_CHANGE_MASK | MV_XLG_SUMMARY_INTERRUPT_MASK);
|
}
|
|
/* Set PCS to exit from reset */
|
VOID
|
MvGopXpcsUnreset (
|
IN PP2DXE_PORT *Port
|
)
|
{
|
MmioOr32 (Port->Priv->XpcsBase + MVPP22_XPCS_GLOBAL_CFG_0_REG, MVPP22_XPCS_PCSRESET);
|
}
|
|
/* Set the MAC to exit from reset */
|
VOID
|
MvGopXlgMacUnreset (
|
IN PP2DXE_PORT *Port
|
)
|
{
|
MmioOr32 (Port->XlgBase + MV_XLG_PORT_MAC_CTRL0_REG, MV_XLG_MAC_CTRL0_MACRESETN_MASK);
|
}
|
|
BOOLEAN
|
MvGop110XlgLinkStatusGet (
|
IN PP2DXE_PORT *Port
|
)
|
{
|
return MmioRead32 (Port->XlgBase + MV_XLG_MAC_PORT_STATUS_REG) & MV_XLG_MAC_PORT_STATUS_LINKSTATUS_MASK;
|
}
|
|
BOOLEAN
|
MvGop110PortIsLinkUp (
|
IN PP2DXE_PORT *Port
|
)
|
{
|
switch (Port->PhyInterface) {
|
case MV_MODE_RGMII:
|
case MV_MODE_SGMII:
|
case MV_MODE_QSGMII:
|
return MvGop110GmacLinkStatusGet (Port);
|
case MV_MODE_SFI:
|
return MvGop110XlgLinkStatusGet (Port);
|
case MV_MODE_XAUI:
|
case MV_MODE_RXAUI:
|
return FALSE;
|
default:
|
return FALSE;
|
}
|
}
|
|
/* Get MAC link status */
|
BOOLEAN
|
MvGop110GmacLinkStatusGet (
|
IN PP2DXE_PORT *Port
|
)
|
{
|
UINT32 RegAddr;
|
UINT32 Val;
|
|
RegAddr = MVPP2_PORT_STATUS0_REG;
|
|
Val = MvGop110GmacRead (Port, RegAddr);
|
|
return (Val & 1) ? TRUE : FALSE;
|
}
|
|
STATIC
|
VOID
|
MvGop110XlgPortEnable (
|
IN PP2DXE_PORT *Port
|
)
|
{
|
/* Enable port and MIB counters update */
|
MmioAndThenOr32 (Port->XlgBase + MV_XLG_PORT_MAC_CTRL0_REG,
|
~MV_XLG_MAC_CTRL0_MIBCNTDIS_MASK,
|
MV_XLG_MAC_CTRL0_PORTEN_MASK);
|
}
|
|
STATIC
|
VOID
|
MvGop110XlgPortDisable (
|
IN PP2DXE_PORT *Port
|
)
|
{
|
/* Mask all port's external interrupts */
|
MvGop110XlgPortLinkEventMask (Port);
|
|
MmioAnd32 (Port->XlgBase + MV_XLG_PORT_MAC_CTRL0_REG, ~MV_XLG_MAC_CTRL0_PORTEN_MASK);
|
}
|
|
VOID
|
MvGop110PortDisable (
|
IN PP2DXE_PORT *Port
|
)
|
{
|
switch (Port->PhyInterface) {
|
case MV_MODE_RGMII:
|
case MV_MODE_SGMII:
|
case MV_MODE_QSGMII:
|
MvGop110GmacPortDisable (Port);
|
break;
|
case MV_MODE_XAUI:
|
case MV_MODE_RXAUI:
|
case MV_MODE_SFI:
|
MvGop110XlgPortDisable (Port);
|
break;
|
default:
|
return;
|
}
|
}
|
|
VOID
|
MvGop110PortEnable (
|
IN PP2DXE_PORT *Port
|
)
|
{
|
switch (Port->PhyInterface) {
|
case MV_MODE_RGMII:
|
case MV_MODE_SGMII:
|
case MV_MODE_QSGMII:
|
MvGop110GmacPortEnable (Port);
|
break;
|
case MV_MODE_XAUI:
|
case MV_MODE_RXAUI:
|
case MV_MODE_SFI:
|
MvGop110XlgPortEnable (Port);
|
break;
|
default:
|
return;
|
}
|
}
|
|
/* Enable Port and MIB counters */
|
VOID
|
MvGop110GmacPortEnable (
|
IN PP2DXE_PORT *Port
|
)
|
{
|
UINT32 RegVal;
|
|
RegVal = MvGop110GmacRead (Port, MVPP2_PORT_CTRL0_REG);
|
RegVal |= MVPP2_PORT_CTRL0_PORTEN_MASK;
|
RegVal |= MVPP2_PORT_CTRL0_COUNT_EN_MASK;
|
|
MvGop110GmacWrite (Port, MVPP2_PORT_CTRL0_REG, RegVal);
|
}
|
|
/* Disable Port */
|
VOID
|
MvGop110GmacPortDisable (
|
IN PP2DXE_PORT *Port
|
)
|
{
|
UINT32 RegVal;
|
|
/* Mask all Ports interrupts */
|
MvGop110GmacPortLinkEventMask (Port);
|
|
RegVal = MvGop110GmacRead (Port, MVPP2_PORT_CTRL0_REG);
|
RegVal &= ~MVPP2_PORT_CTRL0_PORTEN_MASK;
|
|
MvGop110GmacWrite (Port, MVPP2_PORT_CTRL0_REG, RegVal);
|
}
|
|
VOID
|
MvGop110GmacPortLinkEventMask (
|
IN PP2DXE_PORT *Port
|
)
|
{
|
UINT32 RegVal;
|
|
RegVal = MvGop110GmacRead (Port, MV_GMAC_INTERRUPT_SUM_MASK_REG);
|
RegVal &= ~MV_GMAC_INTERRUPT_SUM_CAUSE_LINK_CHANGE_MASK;
|
MvGop110GmacWrite (Port, MV_GMAC_INTERRUPT_SUM_MASK_REG, RegVal);
|
}
|
|
VOID
|
MvGop110XlgPortLinkEventMask (
|
IN PP2DXE_PORT *Port
|
)
|
{
|
MmioAnd32 (Port->XlgBase + MV_XLG_EXTERNAL_INTERRUPT_MASK_REG,
|
~MV_XLG_EXTERNAL_INTERRUPT_LINK_CHANGE_MASK);
|
}
|
|
INT32
|
MvGop110PortEventsMask (
|
IN PP2DXE_PORT *Port
|
)
|
{
|
|
switch (Port->PhyInterface) {
|
case MV_MODE_RGMII:
|
case MV_MODE_SGMII:
|
case MV_MODE_QSGMII:
|
MvGop110GmacPortLinkEventMask (Port);
|
break;
|
case MV_MODE_XAUI:
|
case MV_MODE_RXAUI:
|
case MV_MODE_SFI:
|
MvGop110XlgPortLinkEventMask (Port);
|
break;
|
default:
|
return -1;
|
}
|
|
return 0;
|
}
|
|
/*
|
* Sets "Force Link Pass" and clears "Do Not Force Link Fail" bits.
|
* This function should only be called when the port is disabled.
|
*/
|
VOID
|
MvGop110GmacForceLinkUp (
|
IN PP2DXE_PORT *Port
|
)
|
{
|
UINT32 RegVal;
|
|
RegVal = MvGop110GmacRead (Port, MVPP2_PORT_AUTO_NEG_CFG_REG);
|
|
RegVal |= MVPP2_PORT_AUTO_NEG_CFG_FORCE_LINK_UP_MASK;
|
RegVal &= ~MVPP2_PORT_AUTO_NEG_CFG_FORCE_LINK_DOWN_MASK;
|
|
MvGop110GmacWrite (Port, MVPP2_PORT_AUTO_NEG_CFG_REG, RegVal);
|
}
|
|
INT32
|
MvGop110FlCfg (
|
IN PP2DXE_PORT *Port
|
)
|
{
|
switch (Port->PhyInterface) {
|
case MV_MODE_RGMII:
|
case MV_MODE_SGMII:
|
case MV_MODE_QSGMII:
|
/* Disable AN */
|
MvGop110SpeedDuplexSet (Port, Port->Speed, MV_PORT_DUPLEX_FULL);
|
break;
|
case MV_MODE_XAUI:
|
case MV_MODE_RXAUI:
|
case MV_MODE_SFI:
|
return 0;
|
default:
|
return -1;
|
}
|
|
return 0;
|
}
|
|
/* Set Port Speed and Duplex */
|
INT32
|
MvGop110SpeedDuplexSet (
|
IN PP2DXE_PORT *Port,
|
IN INT32 Speed,
|
IN enum MvPortDuplex Duplex
|
)
|
{
|
switch (Port->PhyInterface) {
|
case MV_MODE_RGMII:
|
case MV_MODE_SGMII:
|
case MV_MODE_QSGMII:
|
MvGop110GmacSpeedDuplexSet (Port, Speed, Duplex);
|
break;
|
case MV_MODE_XAUI:
|
case MV_MODE_RXAUI:
|
case MV_MODE_SFI:
|
break;
|
default:
|
return -1;
|
}
|
|
return 0;
|
}
|
|
/*
|
* Sets Port Speed to Auto Negotiation / 1000 / 100 / 10 Mbps.
|
* Sets Port Duplex to Auto Negotiation / Full / Half Duplex.
|
*/
|
INT32
|
MvGop110GmacSpeedDuplexSet (
|
IN PP2DXE_PORT *Port,
|
IN INT32 Speed,
|
IN enum MvPortDuplex Duplex
|
)
|
{
|
UINT32 RegVal;
|
|
RegVal = Mvpp2GmacRead (Port, MVPP2_PORT_AUTO_NEG_CFG_REG);
|
|
switch (Speed) {
|
case MV_PORT_SPEED_2500:
|
case MV_PORT_SPEED_1000:
|
RegVal &= ~MVPP2_PORT_AUTO_NEG_CFG_EN_AN_SPEED_MASK;
|
RegVal |= MVPP2_PORT_AUTO_NEG_CFG_SET_GMII_SPEED_MASK;
|
/* The 100/10 bit doesn't matter in this case */
|
break;
|
case MV_PORT_SPEED_100:
|
RegVal &= ~MVPP2_PORT_AUTO_NEG_CFG_EN_AN_SPEED_MASK;
|
RegVal &= ~MVPP2_PORT_AUTO_NEG_CFG_SET_GMII_SPEED_MASK;
|
RegVal |= MVPP2_PORT_AUTO_NEG_CFG_SET_MII_SPEED_MASK;
|
break;
|
case MV_PORT_SPEED_10:
|
RegVal &= ~MVPP2_PORT_AUTO_NEG_CFG_EN_AN_SPEED_MASK;
|
RegVal &= ~MVPP2_PORT_AUTO_NEG_CFG_SET_GMII_SPEED_MASK;
|
RegVal &= ~MVPP2_PORT_AUTO_NEG_CFG_SET_MII_SPEED_MASK;
|
break;
|
default:
|
return MVPP2_EINVAL;
|
}
|
|
switch (Duplex) {
|
case MV_PORT_DUPLEX_AN:
|
RegVal |= MVPP2_PORT_AUTO_NEG_CFG_EN_FDX_AN_MASK;
|
/* The other bits don't matter in this case */
|
break;
|
case MV_PORT_DUPLEX_HALF:
|
RegVal &= ~MVPP2_PORT_AUTO_NEG_CFG_EN_FDX_AN_MASK;
|
RegVal &= ~MVPP2_PORT_AUTO_NEG_CFG_SET_FULL_DX_MASK;
|
break;
|
case MV_PORT_DUPLEX_FULL:
|
RegVal &= ~MVPP2_PORT_AUTO_NEG_CFG_EN_FDX_AN_MASK;
|
RegVal |= MVPP2_PORT_AUTO_NEG_CFG_SET_FULL_DX_MASK;
|
break;
|
default:
|
return MVPP2_EINVAL;
|
}
|
|
Mvpp2GmacWrite (Port, MVPP2_PORT_AUTO_NEG_CFG_REG, RegVal);
|
|
return 0;
|
}
|
|
VOID
|
Mvpp2AxiConfig (
|
IN MVPP2_SHARED *Priv
|
)
|
{
|
/* Config AXI Read&Write Normal and Soop mode */
|
Mvpp2Write (Priv, MVPP22_AXI_BM_WR_ATTR_REG, MVPP22_AXI_ATTR_SNOOP_CNTRL_BIT);
|
Mvpp2Write (Priv, MVPP22_AXI_BM_RD_ATTR_REG, MVPP22_AXI_ATTR_SNOOP_CNTRL_BIT);
|
Mvpp2Write (Priv, MVPP22_AXI_AGGRQ_DESCR_RD_ATTR_REG, MVPP22_AXI_ATTR_SNOOP_CNTRL_BIT);
|
Mvpp2Write (Priv, MVPP22_AXI_TXQ_DESCR_WR_ATTR_REG, MVPP22_AXI_ATTR_SNOOP_CNTRL_BIT);
|
Mvpp2Write (Priv, MVPP22_AXI_TXQ_DESCR_RD_ATTR_REG, MVPP22_AXI_ATTR_SNOOP_CNTRL_BIT);
|
Mvpp2Write (Priv, MVPP22_AXI_RXQ_DESCR_WR_ATTR_REG, MVPP22_AXI_ATTR_SNOOP_CNTRL_BIT);
|
Mvpp2Write (Priv, MVPP22_AXI_RX_DATA_WR_ATTR_REG, MVPP22_AXI_ATTR_SNOOP_CNTRL_BIT);
|
Mvpp2Write (Priv, MVPP22_AXI_TX_DATA_RD_ATTR_REG, MVPP22_AXI_ATTR_SNOOP_CNTRL_BIT);
|
}
|
|
/* Cleanup Tx Ports */
|
VOID
|
Mvpp2TxpClean (
|
IN PP2DXE_PORT *Port,
|
IN INT32 Txp,
|
IN MVPP2_TX_QUEUE *Txq
|
)
|
{
|
INT32 Delay, Pending;
|
UINT32 RegVal;
|
|
Mvpp2Write (Port->Priv, MVPP2_TXQ_NUM_REG, Txq->Id);
|
RegVal = Mvpp2Read (Port->Priv, MVPP2_TXQ_PREF_BUF_REG);
|
RegVal |= MVPP2_TXQ_DRAIN_EN_MASK;
|
Mvpp2Write (Port->Priv, MVPP2_TXQ_PREF_BUF_REG, RegVal);
|
|
/*
|
* The Queue has been stopped so wait for all packets
|
* to be transmitted.
|
*/
|
Delay = 0;
|
do {
|
if (Delay >= MVPP2_TX_PENDING_TIMEOUT_MSEC) {
|
Mvpp2Printf ("Port %d: cleaning Queue %d timed out\n", Port->Id, Txq->LogId);
|
break;
|
}
|
Mvpp2Mdelay (1);
|
Delay++;
|
|
Pending = Mvpp2TxqPendDescNumGet (Port, Txq);
|
} while (Pending);
|
|
RegVal &= ~MVPP2_TXQ_DRAIN_EN_MASK;
|
Mvpp2Write (Port->Priv, MVPP2_TXQ_PREF_BUF_REG, RegVal);
|
}
|
|
/* Cleanup all Tx Queues */
|
VOID
|
Mvpp2CleanupTxqs (
|
IN PP2DXE_PORT *Port
|
)
|
{
|
MVPP2_TX_QUEUE *Txq;
|
INT32 Txp, Queue;
|
UINT32 RegVal;
|
|
RegVal = Mvpp2Read (Port->Priv, MVPP2_TX_PORT_FLUSH_REG);
|
|
/* Reset Tx Ports and delete Tx Queues */
|
for (Txp = 0; Txp < Port->TxpNum; Txp++) {
|
RegVal |= MVPP2_TX_PORT_FLUSH_MASK (Port->Id);
|
Mvpp2Write (Port->Priv, MVPP2_TX_PORT_FLUSH_REG, RegVal);
|
|
for (Queue = 0; Queue < TxqNumber; Queue++) {
|
Txq = &Port->Txqs[Txp * TxqNumber + Queue];
|
Mvpp2TxpClean (Port, Txp, Txq);
|
Mvpp2TxqHwDeinit (Port, Txq);
|
}
|
|
RegVal &= ~MVPP2_TX_PORT_FLUSH_MASK (Port->Id);
|
Mvpp2Write (Port->Priv, MVPP2_TX_PORT_FLUSH_REG, RegVal);
|
}
|
}
|
|
/* Cleanup all Rx Queues */
|
VOID
|
Mvpp2CleanupRxqs (
|
IN PP2DXE_PORT *Port
|
)
|
{
|
INT32 Queue;
|
|
for (Queue = 0; Queue < RxqNumber; Queue++) {
|
Mvpp2RxqHwDeinit (Port, &Port->Rxqs[Queue]);
|
}
|
}
|