/******************************************************************************** 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 */ 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 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]); } }