blob: eaa1a52ecdd12956f8aef50c3b7e92877e0e7604 [file] [log] [blame]
/*******************************************************************************
Copyright (C) Marvell International Ltd. and its affiliates
This software file (the "File") is owned and distributed by Marvell
International Ltd. and/or its affiliates ("Marvell") under the following
alternative licensing terms. Once you have made an election to distribute the
File under one of the following license alternatives, please (i) delete this
introductory statement regarding license alternatives, (ii) delete the two
license alternatives that you have not elected to use and (iii) preserve the
Marvell copyright notice above.
********************************************************************************
Marvell Commercial License Option
If you received this File from Marvell and you have entered into a commercial
license agreement (a "Commercial License") with Marvell, the File is licensed
to you under the terms of the applicable Commercial License.
********************************************************************************
Marvell GPL License Option
If you received this File from Marvell, you may opt to use, redistribute and/or
modify this File in accordance with the terms and conditions of the General
Public License Version 2, June 1991 (the "GPL License"), a copy of which is
available along with the File in the license.txt file or by writing to the Free
Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 or
on the worldwide web at http://www.gnu.org/licenses/gpl.txt.
THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE IMPLIED
WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE ARE EXPRESSLY
DISCLAIMED. The GPL License provides additional details about this warranty
disclaimer.
********************************************************************************
Marvell BSD License Option
If you received this File from Marvell, you may opt to use, redistribute and/or
modify this File under the following licensing terms.
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
* Neither the name of Marvell nor the names of its contributors may be
used to endorse or promote products derived from this software without
specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*******************************************************************************/
#include "mvOs.h"
#include "mvCommon.h"
#include "mv802_3.h"
#include "mvPp2Prs.h"
#include "gbe/mvPp2Gbe.h"
#include "mvPp2PrsHw.h"
#include "mvPp2Prs.h"
#define PRS_DBG(X...)
/*-------------------------------------------------------------------------------*/
/* Static varialbes for internal use */
/*-------------------------------------------------------------------------------*/
int etherTypeDsa;
int mvPrsDblVlanAiShadow[DBL_VLAN_SHADOW_SIZE];
static int mvPrsDblVlanAiShadowSet(int index)
{
RANGE_VALIDATE(index, 1, DBL_VLAN_SHADOW_SIZE - 1);
mvPrsDblVlanAiShadow[index] = 1;
return MV_OK;
}
static int mvPrsDblVlanAiShadowClear(int index)
{
RANGE_VALIDATE(index, 1, DBL_VLAN_SHADOW_SIZE - 1);
mvPrsDblVlanAiShadow[index] = 0;
return MV_OK;
}
static int mvPrsDblVlanAiShadowClearAll(void)
{
int i;
for (i = 1; i < DBL_VLAN_SHADOW_SIZE; i++)
mvPrsDblVlanAiShadowClear(i);
return MV_OK;
}
static int mvPrsDblVlanAiFreeGet(void)
{
int i;
/* start from 1, 0 not in used */
for (i = 1; i < DBL_VLAN_SHADOW_SIZE; i++)
if (mvPrsDblVlanAiShadow[i] == 0)
return i;
return MV_PRS_OUT_OF_RAGE;
}
/******************************************************************************
* Common utilities
******************************************************************************/
static MV_BOOL mvPp2PrsEtypeEquals(MV_PP2_PRS_ENTRY *pe, int offset, unsigned short ethertype)
{
unsigned char etype[MV_ETH_TYPE_LEN];
PRS_DBG("%s\n", __func__);
etype[0] = (ethertype >> 8) & 0xFF;
etype[1] = ethertype & 0xFF;
if (mvPp2PrsSwTcamBytesIgnorMaskCmp(pe, offset, MV_ETH_TYPE_LEN, etype) == NOT_EQUALS)
return MV_FALSE;
return MV_TRUE;
}
static void mvPp2PrsMatchEtype(MV_PP2_PRS_ENTRY *pe, int offset, unsigned short ethertype)
{
PRS_DBG("%s\n", __func__);
mvPp2PrsSwTcamByteSet(pe, offset + 0, ethertype >> 8, 0xff);
mvPp2PrsSwTcamByteSet(pe, offset + 1, ethertype & 0xFF, 0xff);
}
#if 0
static void mvPp2PrsMatchMh(MV_PP2_PRS_ENTRY *pe, unsigned short mh)
{
PRS_DBG("%s\n", __func__);
mvPp2PrsSwTcamByteSet(pe, 0, mh >> 8, 0xff);
mvPp2PrsSwTcamByteSet(pe, 1, mh & 0xFF, 0xff);
}
#endif
/******************************************************************************
*
* Marvell header Section
*
******************************************************************************
*/
static MV_BOOL mvPrsMhRangeEquals(MV_PP2_PRS_ENTRY *pe, MV_U8 *mh, MV_U8 *mask)
{
int index;
unsigned char tcamByte, tcamMask;
for (index = 0; index < MV_ETH_MH_SIZE; index++) {
mvPp2PrsSwTcamByteGet(pe, index, &tcamByte, &tcamMask);
if (tcamMask != mask[index])
return MV_FALSE;
if ((tcamMask & tcamByte) != (mh[index] & mask[index]))
return MV_FALSE;
}
return MV_TRUE;
}
static MV_BOOL mvPrsMhRangeIntersec(MV_PP2_PRS_ENTRY *pe, MV_U8 *mh, MV_U8 *mask)
{
int index;
unsigned char tcamByte, tcamMask, commonMask;
for (index = 0; index < MV_ETH_MH_SIZE; index++) {
mvPp2PrsSwTcamByteGet(pe, index, &tcamByte, &tcamMask);
commonMask = mask[index] & tcamMask;
if ((commonMask & tcamByte) != (commonMask & mh[index]))
return MV_FALSE;
}
return MV_TRUE;
}
static MV_BOOL mvPrsMhInRange(MV_PP2_PRS_ENTRY *pe, MV_U8 *mh, MV_U8 *mask)
{
int index;
unsigned char tcamByte, tcamMask;
for (index = 0; index < MV_ETH_MH_SIZE; index++) {
mvPp2PrsSwTcamByteGet(pe, index, &tcamByte, &tcamMask);
if ((tcamByte & mask[index]) != (mh[index] & mask[index]))
return MV_FALSE;
}
return MV_TRUE;
}
static MV_PP2_PRS_ENTRY *mvPrsMhRangeFind(int portMap, unsigned char *mh, unsigned char *mask)
{
MV_PP2_PRS_ENTRY *pe;
int tid;
unsigned int entryPmap;
pe = mvPp2PrsSwAlloc(PRS_LU_MH);
/* Go through the all entires with PRS_LU_MAC */
for (tid = PE_FIRST_FREE_TID; tid <= PE_LAST_FREE_TID; tid++) {
if ((!mvPp2PrsShadowIsValid(tid)) || (mvPp2PrsShadowLu(tid) != PRS_LU_MH))
continue;
pe->index = tid;
mvPp2PrsHwRead(pe);
mvPp2PrsSwTcamPortMapGet(pe, &entryPmap);
if (mvPrsMhRangeEquals(pe, mh, mask) && (entryPmap == (unsigned int)portMap))
return pe;
}
mvPp2PrsSwFree(pe);
return NULL;
}
static int mvPrsMhRangeAccept(int portMap, MV_U8 *mh, MV_U8 *mask, unsigned int ri, unsigned int riMask, MV_BOOL finish)
{
int tid, len;
MV_PP2_PRS_ENTRY *pe = NULL;
/* Scan TCAM and see if entry with this <MH, port> already exist */
pe = mvPrsMhRangeFind(portMap, mh, mask);
if (pe == NULL) {
/* entry not exist */
/* Go through the all entires from first to last */
tid = mvPp2PrsTcamFirstFree(PE_FIRST_FREE_TID, PE_LAST_FREE_TID);
/* Can't add - No free TCAM entries */
if (tid == MV_PRS_OUT_OF_RAGE) {
mvOsPrintf("%s: No free TCAM entiry\n", __func__);
mvPp2PrsSwFree(pe);
return MV_ERROR;
}
pe = mvPp2PrsSwAlloc(PRS_LU_MH);
pe->index = tid;
mvPp2PrsSwTcamPortMapSet(pe, portMap);
/* shift to MAC */
mvPp2PrsSwSramShiftSet(pe, MV_ETH_MH_SIZE, SRAM_OP_SEL_SHIFT_ADD);
mvPp2PrsSwSramNextLuSet(pe, PRS_LU_FLOWS);
mvPp2PrsSwSramFlowidGenSet(pe);
/* set MH range */
len = MV_ETH_MH_SIZE;
while (len--)
mvPp2PrsSwTcamByteSet(pe, len, mh[len], mask[len]);
/* Update mvPrsShadowTbl */
mvPp2PrsShadowSet(pe->index, PRS_LU_MH, "mh-range");
}
/* Set result info bits */
mvPp2PrsSwSramRiUpdate(pe, ri, riMask);
finish ? mvPp2PrsSwSramFlowidGenSet(pe) : mvPp2PrsSwSramFlowidGenClear(pe);
/* Write entry to TCAM */
mvPp2PrsHwWrite(pe);
mvPp2PrsSwFree(pe);
return MV_OK;
}
static int mvPrsMhRangeValid(unsigned int portMap, MV_U8 *mh, MV_U8 *mask)
{
MV_PP2_PRS_ENTRY pe;
unsigned int entryPmap;
int tid;
for (tid = PE_LAST_FREE_TID; tid >= PE_FIRST_FREE_TID; tid--) {
if (!mvPp2PrsShadowIsValid(tid) || (mvPp2PrsShadowLu(tid) != PRS_LU_MH))
continue;
pe.index = tid;
mvPp2PrsHwRead(&pe);
mvPp2PrsSwTcamPortMapGet(&pe, &entryPmap);
if ((mvPrsMhRangeIntersec(&pe, mh, mask)) & !mvPrsMhRangeEquals(&pe, mh, mask)) {
if (entryPmap & portMap) {
mvOsPrintf("%s: operation not supported, range intersection\n", __func__);
mvOsPrintf("%s: user must delete portMap 0x%x from entry %d.\n",
__func__, entryPmap & portMap, tid);
return MV_ERROR;
}
} else if (mvPrsMhRangeEquals(&pe, mh, mask) && (entryPmap != portMap) && (entryPmap & portMap)) {
mvOsPrintf("%s: operation not supported, range intersection\n", __func__);
mvOsPrintf("%s: user must delete portMap 0x%x from entry %d.\n",
__func__, entryPmap & portMap, tid);
return MV_ERROR;
}
}
return MV_OK;
}
int mvPrsMhSet(unsigned int portMap, unsigned short mh, unsigned short mh_mask, unsigned int ri, unsigned int riMask, MV_BOOL finish)
{
MV_PP2_PRS_ENTRY pe;
int tid;
unsigned int entryPmap;
MV_BOOL done = MV_FALSE;
unsigned short n_mh;
unsigned short n_mh_mask;
/* step 1 - validation, ranges intersections are forbidden*/
n_mh = htons(mh);
n_mh_mask = htons(mh_mask);
if (mvPrsMhRangeValid(portMap, (unsigned char *)&n_mh, (unsigned char *)&n_mh_mask))
return MV_ERROR;
/* step 2 - update TCAM */
for (tid = PE_LAST_FREE_TID; tid >= PE_FIRST_FREE_TID; tid--) {
if (!mvPp2PrsShadowIsValid(tid) || !(mvPp2PrsShadowLu(tid) == PRS_LU_MH))
continue;
pe.index = tid;
mvPp2PrsHwRead(&pe);
mvPp2PrsSwTcamPortMapGet(&pe, &entryPmap);
if (mvPrsMhRangeEquals(&pe, (unsigned char *)&n_mh, (unsigned char *)&n_mh_mask) &&
(entryPmap == portMap)) {
/* portMap and range are equals to TCAM entry*/
done = MV_TRUE;
mvPp2PrsSwSramRiUpdate(&pe, ri, riMask);
finish ? mvPp2PrsSwSramFlowidGenSet(&pe) : mvPp2PrsSwSramFlowidGenClear(&pe);
mvPp2PrsHwWrite(&pe);
continue;
}
/* PRS_UDF_MAC_DEF */
if (mvPrsMhInRange(&pe, (unsigned char *)&n_mh, (unsigned char *)&n_mh_mask) && (entryPmap & portMap)) {
mvPp2PrsSwSramRiUpdate(&pe, ri, riMask);
finish ? mvPp2PrsSwSramFlowidGenSet(&pe) : mvPp2PrsSwSramFlowidGenClear(&pe);
mvPp2PrsHwWrite(&pe);
}
}
/* step 3 - Add new range entry */
if (!done)
return mvPrsMhRangeAccept(portMap, (unsigned char *)&n_mh,
(unsigned char *)&n_mh_mask, ri, riMask, finish);
return MV_OK;
}
int mvPrsMhDel(unsigned int portMap, unsigned short mh, unsigned short mh_mask)
{
MV_PP2_PRS_ENTRY pe;
int tid;
unsigned int entryPmap;
MV_BOOL found = MV_FALSE;
unsigned short n_mh;
unsigned short n_mh_mask;
n_mh = htons(mh);
n_mh_mask = htons(mh_mask);
for (tid = PE_LAST_FREE_TID; tid >= PE_FIRST_FREE_TID; tid--) {
if (!mvPp2PrsShadowIsValid(tid) || !(mvPp2PrsShadowLu(tid) == PRS_LU_MH))
continue;
pe.index = tid;
mvPp2PrsHwRead(&pe);
mvPp2PrsSwTcamPortMapGet(&pe, &entryPmap);
/* differents ports */
if (!(entryPmap & portMap))
continue;
if (mvPrsMhRangeEquals(&pe, (unsigned char *)&n_mh, (unsigned char *)&n_mh_mask)) {
found = MV_TRUE;
entryPmap &= ~portMap;
if (!entryPmap) {
/* delete entry */
mvPp2PrsHwInv(pe.index);
mvPp2PrsShadowClear(pe.index);
continue;
}
/* update port map */
mvPp2PrsSwTcamPortMapSet(&pe, entryPmap);
mvPp2PrsHwWrite(&pe);
continue;
}
/* PRS_UDF_MH_RANGE */
if (!found) {
/* range entry not exist */
mvOsPrintf("%s: Error, entry not found\n", __func__);
return MV_ERROR;
}
/* range entry allready found, now fix all relevant default entries*/
if (mvPrsMhInRange(&pe, (unsigned char *)&n_mh, (unsigned char *)&n_mh_mask)) {
mvPp2PrsSwSramFlowidGenClear(&pe);
mvPp2PrsSwSramRiSet(&pe, mvPp2PrsShadowRi(tid), mvPp2PrsShadowRiMask(tid));
mvPp2PrsHwWrite(&pe);
}
}
return MV_OK;
}
/* Set default entry for Marvell header field */
static int mvPp2PrsMhInit(void)
{
MV_PP2_PRS_ENTRY pe;
mvPp2PrsSwClear(&pe);
pe.index = PE_MH_DEFAULT;
mvPp2PrsSwTcamLuSet(&pe, PRS_LU_MH);
mvPp2PrsSwSramShiftSet(&pe, MV_ETH_MH_SIZE, SRAM_OP_SEL_SHIFT_ADD);
mvPp2PrsSwSramNextLuSet(&pe, PRS_LU_MAC);
/* Update mvPrsShadowTbl */
mvPp2PrsShadowSet(pe.index, PRS_LU_MH, "mh-default");
mvPp2PrsSwTcamPortMapSet(&pe, PORT_MASK);
mvPp2PrsHwWrite(&pe);
return MV_OK;
}
/******************************************************************************
*
* MAC Address Section
*
******************************************************************************
*/
char *mvPrsL2InfoStr(unsigned int l2_info)
{
switch (l2_info << RI_L2_CAST_OFFS) {
case RI_L2_UCAST:
return "Ucast";
case RI_L2_MCAST:
return "Mcast";
case RI_L2_BCAST:
return "Bcast";
default:
return "Unknown";
}
return NULL;
}
static MV_BOOL mvPrsMacRangeEquals(MV_PP2_PRS_ENTRY *pe, MV_U8 *da, MV_U8 *mask)
{
int index;
unsigned char tcamByte, tcamMask;
for (index = 0; index < MV_MAC_ADDR_SIZE; index++) {
mvPp2PrsSwTcamByteGet(pe, index, &tcamByte, &tcamMask);
if (tcamMask != mask[index])
return MV_FALSE;
if ((tcamMask & tcamByte) != (da[index] & mask[index]))
return MV_FALSE;
}
return MV_TRUE;
}
static MV_BOOL mvPrsMacRangeIntersec(MV_PP2_PRS_ENTRY *pe, MV_U8 *da, MV_U8 *mask)
{
int index;
unsigned char tcamByte, tcamMask, commonMask;
for (index = 0; index < MV_MAC_ADDR_SIZE; index++) {
mvPp2PrsSwTcamByteGet(pe, index, &tcamByte, &tcamMask);
commonMask = mask[index] & tcamMask;
if ((commonMask & tcamByte) != (commonMask & da[index]))
return MV_FALSE;
}
return MV_TRUE;
}
static MV_BOOL mvPrsMacInRange(MV_PP2_PRS_ENTRY *pe, MV_U8* da, MV_U8* mask)
{
int index;
unsigned char tcamByte, tcamMask;
for (index = 0; index < MV_MAC_ADDR_SIZE; index++) {
mvPp2PrsSwTcamByteGet(pe, index, &tcamByte, &tcamMask);
if ((tcamByte & mask[index]) != (da[index] & mask[index]))
return MV_FALSE;
}
return MV_TRUE;
}
static MV_PP2_PRS_ENTRY *mvPrsMacDaRangeFind(int portMap, unsigned char *da, unsigned char *mask, int udfType)
{
MV_PP2_PRS_ENTRY *pe;
int tid;
unsigned int entryPmap;
pe = mvPp2PrsSwAlloc(PRS_LU_MAC);
/* Go through the all entires with PRS_LU_MAC */
for (tid = PE_FIRST_FREE_TID ; tid <= PE_LAST_FREE_TID; tid++) {
if ((!mvPp2PrsShadowIsValid(tid)) || (mvPp2PrsShadowLu(tid) != PRS_LU_MAC))
continue;
if (mvPp2PrsShadowUdf(tid) != udfType)
continue;
pe->index = tid;
mvPp2PrsHwRead(pe);
mvPp2PrsSwTcamPortMapGet(pe, &entryPmap);
if (mvPrsMacRangeEquals(pe, da, mask) && (entryPmap == portMap))
return pe;
}
mvPp2PrsSwFree(pe);
return NULL;
}
static MV_PP2_PRS_ENTRY *mvPrsMacDaFind(int port, unsigned char *da)
{
unsigned char mask[MV_MAC_ADDR_SIZE];
mask[0] = mask[1] = mask[2] = mask[3] = mask[4] = mask[5] = 0xff;
/* Scan TCAM and see if entry with this <MAC DA, port> already exist */
return mvPrsMacDaRangeFind((1 << port), da, mask, PRS_UDF_MAC_DEF);
}
static int mvPrsMacDaRangeAccept(int portMap, MV_U8 *da, MV_U8 *mask, unsigned int ri, unsigned int riMask, MV_BOOL finish)
{
int tid, len;
MV_PP2_PRS_ENTRY *pe = NULL;
/* Scan TCAM and see if entry with this <MAC DA, port> already exist */
pe = mvPrsMacDaRangeFind(portMap, da, mask, PRS_UDF_MAC_RANGE);
if (pe == NULL) {
/* entry not exist */
/* find last simple mac entry*/
for (tid = PE_LAST_FREE_TID ; tid >= PE_FIRST_FREE_TID; tid--)
if (mvPp2PrsShadowIsValid(tid) && (mvPp2PrsShadowLu(tid) == PRS_LU_MAC) &&
(mvPp2PrsShadowUdf(tid) == PRS_UDF_MAC_DEF))
break;
/* Go through the all entires from first to last */
tid = mvPp2PrsTcamFirstFree(tid + 1, PE_LAST_FREE_TID);
/* Can't add - No free TCAM entries */
if (tid == MV_PRS_OUT_OF_RAGE) {
mvOsPrintf("%s: No free TCAM entiry\n", __func__);
mvPp2PrsSwFree(pe);
return MV_ERROR;
}
pe = mvPp2PrsSwAlloc(PRS_LU_MAC);
pe->index = tid;
mvPp2PrsSwTcamPortMapSet(pe, portMap);
/* shift to ethertype */
mvPp2PrsSwSramShiftSet(pe, 2 * MV_MAC_ADDR_SIZE, SRAM_OP_SEL_SHIFT_ADD);
/* set DA range */
len = MV_MAC_ADDR_SIZE;
while (len--)
mvPp2PrsSwTcamByteSet(pe, len, da[len], mask[len]);
/* Update mvPrsShadowTbl */
mvPp2PrsShadowSet(pe->index, PRS_LU_MAC, "mac-range");
mvPp2PrsShadowUdfSet(pe->index, PRS_UDF_MAC_RANGE);
}
/* Set result info bits */
mvPp2PrsSwSramRiUpdate(pe, ri, riMask);
finish ? mvPp2PrsSwSramFlowidGenSet(pe) : mvPp2PrsSwSramFlowidGenClear(pe);
/* Write entry to TCAM */
mvPp2PrsHwWrite(pe);
mvPp2PrsSwFree(pe);
return MV_OK;
}
/* delete all port's simple (not range) multicast entries */
int mvPrsMcastDelAll(int port)
{
MV_PP2_PRS_ENTRY pe;
int tid, index;
unsigned char da[MV_MAC_ADDR_SIZE], daMask[MV_MAC_ADDR_SIZE];
for (tid = PE_FIRST_FREE_TID ; tid <= PE_LAST_FREE_TID; tid++) {
if (!mvPp2PrsShadowIsValid(tid))
continue;
if (mvPp2PrsShadowLu(tid) != PRS_LU_MAC)
continue;
if (mvPp2PrsShadowUdf(tid) != PRS_UDF_MAC_DEF)
continue;
/* only simple mac entries */
pe.index = tid;
mvPp2PrsHwRead(&pe);
/* read mac addr from entry */
for (index = 0; index < MV_MAC_ADDR_SIZE; index++)
mvPp2PrsSwTcamByteGet(&pe, index, &da[index], &daMask[index]);
if (MV_IS_BROADCAST_MAC(da))
continue;
if (MV_IS_MULTICAST_MAC(da))
/* delete mcast entry */
mvPrsMacDaAccept(port, da, 0);
}
return MV_OK;
}
/* TODO: use mvPrsMacDaRangeAccept */
int mvPrsMacDaAccept(int port, unsigned char *da, int add)
{
MV_PP2_PRS_ENTRY *pe = NULL;
unsigned int len, ports, ri;
int tid;
char name[PRS_TEXT_SIZE];
/* Scan TCAM and see if entry with this <MAC DA, port> already exist */
pe = mvPrsMacDaFind(port, da);
if (pe == NULL) {
/* No such entry */
if (!add) {
/* Can't remove - No such entry */
return MV_ERROR;
}
/* Create new TCAM entry */
/* find last range mac entry*/
for (tid = PE_FIRST_FREE_TID ; tid <= PE_LAST_FREE_TID; tid++)
if (mvPp2PrsShadowIsValid(tid) && (mvPp2PrsShadowLu(tid) == PRS_LU_MAC) &&
(mvPp2PrsShadowUdf(tid) == PRS_UDF_MAC_RANGE))
break;
/* Go through the all entires from first to last */
tid = mvPp2PrsTcamFirstFree(0, tid - 1);
/* Can't add - No free TCAM entries */
if (tid == MV_PRS_OUT_OF_RAGE) {
mvOsPrintf("%s: No free TCAM entiry\n", __func__);
mvPp2PrsSwFree(pe);
return MV_ERROR;
}
pe = mvPp2PrsSwAlloc(PRS_LU_MAC);
pe->index = tid;
mvPp2PrsSwTcamPortMapSet(pe, 0);
}
/* Update port mask */
mvPp2PrsSwTcamPortSet(pe, port, add);
mvPp2PrsSwTcamPortMapGet(pe, &ports);
if (ports == 0) {
if (add) {
mvPp2PrsSwFree(pe);
/* Internal error, port should be set in ports bitmap */
return MV_ERROR;
}
/* No ports - invalidate the entry */
mvPp2PrsHwInv(pe->index);
mvPp2PrsShadowClear(pe->index);
mvPp2PrsSwFree(pe);
return MV_OK;
}
/* Continue - set next lookup */
mvPp2PrsSwSramNextLuSet(pe, PRS_LU_DSA);
/* set match on DA */
len = MV_MAC_ADDR_SIZE;
while (len--)
mvPp2PrsSwTcamByteSet(pe, len, da[len], 0xff);
/* Set result info bits */
if (MV_IS_BROADCAST_MAC(da)) {
ri = RI_L2_BCAST;
mvOsSPrintf(name, "bcast-port-%d", port);
} else if (MV_IS_MULTICAST_MAC(da)) {
ri = RI_L2_MCAST;
mvOsSPrintf(name, "mcast-port-%d", port);
} else {
ri = RI_L2_UCAST | RI_MAC_ME_MASK;
mvOsSPrintf(name, "ucast-port-%d", port);
}
/*mvPp2PrsSwSramRiSetBit(pe, RI_MAC_ME_BIT);*/
mvPp2PrsSwSramRiUpdate(pe, ri, RI_L2_CAST_MASK | RI_MAC_ME_MASK);
mvPp2PrsShadowRiSet(pe->index, ri, RI_L2_CAST_MASK | RI_MAC_ME_MASK);
/* shift to ethertype */
mvPp2PrsSwSramShiftSet(pe, 2 * MV_MAC_ADDR_SIZE, SRAM_OP_SEL_SHIFT_ADD);
/* Write entry to TCAM */
mvPp2PrsHwWrite(pe);
/* Update mvPrsShadowTbl */
mvPp2PrsShadowSet(pe->index, PRS_LU_MAC, name);
mvPp2PrsShadowUdfSet(pe->index, PRS_UDF_MAC_DEF);
mvPp2PrsSwFree(pe);
return MV_OK;
}
static int mvPrsMacDaRangeValid(unsigned int portMap, MV_U8 *da, MV_U8 *mask)
{
MV_PP2_PRS_ENTRY pe;
unsigned int entryPmap;
int tid;
for (tid = PE_LAST_FREE_TID ; tid >= PE_FIRST_FREE_TID; tid--) {
if (!mvPp2PrsShadowIsValid(tid) || (mvPp2PrsShadowLu(tid) != PRS_LU_MAC) ||
(mvPp2PrsShadowUdf(tid) != PRS_UDF_MAC_RANGE))
continue;
pe.index = tid;
mvPp2PrsHwRead(&pe);
mvPp2PrsSwTcamPortMapGet(&pe, &entryPmap);
if ((mvPrsMacRangeIntersec(&pe, da, mask)) && !mvPrsMacRangeEquals(&pe, da, mask)) {
if (entryPmap & portMap) {
mvOsPrintf("%s: operation not supported, range intersection\n", __func__);
mvOsPrintf("%s: user must delete portMap 0x%x from entry %d.\n",
__func__, entryPmap & portMap, tid);
return MV_ERROR;
}
} else if (mvPrsMacRangeEquals(&pe, da, mask) && (entryPmap != portMap) && (entryPmap & portMap)) {
mvOsPrintf("%s: operation not supported, range intersection\n", __func__);
mvOsPrintf("%s: user must delete portMap 0x%x from entry %d.\n",
__func__, entryPmap & portMap, tid);
return MV_ERROR;
}
}
return MV_OK;
}
int mvPrsMacDaRangeSet(unsigned int portMap, MV_U8 *da, MV_U8 *mask, unsigned int ri, unsigned int riMask, MV_BOOL finish)
{
MV_PP2_PRS_ENTRY pe;
int tid;
unsigned int entryPmap;
MV_BOOL done = MV_FALSE;
/* step 1 - validation, ranges intersections are forbidden*/
if (mvPrsMacDaRangeValid(portMap, da, mask))
return MV_ERROR;
/* step 2 - update TCAM */
for (tid = PE_LAST_FREE_TID ; tid >= PE_FIRST_FREE_TID; tid--) {
if (!mvPp2PrsShadowIsValid(tid) || !(mvPp2PrsShadowLu(tid) == PRS_LU_MAC))
continue;
pe.index = tid;
mvPp2PrsHwRead(&pe);
mvPp2PrsSwTcamPortMapGet(&pe, &entryPmap);
if ((mvPp2PrsShadowUdf(tid) == PRS_UDF_MAC_RANGE) &&
mvPrsMacRangeEquals(&pe, da, mask) && (entryPmap == portMap)) {
/* portMap and range are equals to TCAM entry*/
done = MV_TRUE;
mvPp2PrsSwSramRiUpdate(&pe, ri, riMask);
finish ? mvPp2PrsSwSramFlowidGenSet(&pe) : mvPp2PrsSwSramFlowidGenClear(&pe);
mvPp2PrsHwWrite(&pe);
continue;
}
/* PRS_UDF_MAC_DEF */
if (mvPrsMacInRange(&pe, da, mask) && (entryPmap & portMap)) {
mvPp2PrsSwSramRiUpdate(&pe, ri, riMask);
finish ? mvPp2PrsSwSramFlowidGenSet(&pe) : mvPp2PrsSwSramFlowidGenClear(&pe);
mvPp2PrsHwWrite(&pe);
}
}
/* step 3 - Add new range entry */
if (!done)
return mvPrsMacDaRangeAccept(portMap, da, mask, ri, riMask, finish);
return MV_OK;
}
int mvPrsMacDaRangeDel(unsigned int portMap, MV_U8 *da, MV_U8 *mask)
{
MV_PP2_PRS_ENTRY pe;
int tid;
unsigned int entryPmap;
MV_BOOL found = MV_FALSE;
for (tid = PE_LAST_FREE_TID ; tid >= PE_FIRST_FREE_TID; tid--) {
if (!mvPp2PrsShadowIsValid(tid) || !(mvPp2PrsShadowLu(tid) == PRS_LU_MAC))
continue;
pe.index = tid;
mvPp2PrsHwRead(&pe);
mvPp2PrsSwTcamPortMapGet(&pe, &entryPmap);
/* differents ports */
if (!(entryPmap & portMap))
continue;
if ((mvPp2PrsShadowUdf(tid) == PRS_UDF_MAC_RANGE) && (mvPrsMacRangeEquals(&pe, da, mask))) {
found = MV_TRUE;
entryPmap &= ~portMap;
if (!entryPmap) {
/* delete entry */
mvPp2PrsHwInv(pe.index);
mvPp2PrsShadowClear(pe.index);
continue;
}
/* update port map */
mvPp2PrsSwTcamPortMapSet(&pe, entryPmap);
mvPp2PrsHwWrite(&pe);
continue;
}
/* PRS_UDF_MAC_RANGE */
if (!found) {
/* range entry not exist */
mvOsPrintf("%s: Error, entry not found\n", __func__);
return MV_ERROR;
}
/* range entry allready found, now fix all relevant default entries*/
if (mvPrsMacInRange(&pe, da, mask)) {
mvPp2PrsSwSramFlowidGenClear(&pe);
mvPp2PrsSwSramRiSet(&pe, mvPp2PrsShadowRi(tid), mvPp2PrsShadowRiMask(tid));
mvPp2PrsHwWrite(&pe);
}
}
return MV_OK;
}
/* Drop special MAC DA - 6 bytes */
int mvPrsMacDaDrop(int port, unsigned char *da, int add)
{
return MV_OK;
}
int mvPrsMacDropAllSet(int port, int add)
{
MV_PP2_PRS_ENTRY pe;
if (mvPp2PrsShadowIsValid(PE_DROP_ALL)) {
/* Entry exist - update port only */
pe.index = PE_DROP_ALL;
mvPp2PrsHwRead(&pe);
} else {
/* Entry doesn't exist - create new */
mvPp2PrsSwClear(&pe);
mvPp2PrsSwTcamLuSet(&pe, PRS_LU_MAC);
pe.index = PE_DROP_ALL;
/* Non-promiscous mode for all ports - DROP unknown packets */
mvPp2PrsSwSramRiSetBit(&pe, RI_DROP_BIT);
/* mvPp2PrsSwSramLuDoneSet(&pe);*/
mvPp2PrsSwSramFlowidGenSet(&pe);
mvPp2PrsSwSramNextLuSet(&pe, PRS_LU_FLOWS);
/* Update mvPrsShadowTbl */
mvPp2PrsShadowSet(pe.index, PRS_LU_MAC, "drop-all");
mvPp2PrsSwTcamPortMapSet(&pe, 0);
}
mvPp2PrsSwTcamPortSet(&pe, port, add);
mvPp2PrsHwWrite(&pe);
return MV_OK;
}
/* Set port to promiscous mode */
int mvPrsMacPromiscousSet(int port, int add)
{
MV_PP2_PRS_ENTRY pe;
/* Promiscous mode - Accept unknown packets */
if (mvPp2PrsShadowIsValid(PE_MAC_PROMISCOUS)) {
/* Entry exist - update port only */
pe.index = PE_MAC_PROMISCOUS;
mvPp2PrsHwRead(&pe);
} else {
/* Entry doesn't exist - create new */
mvPp2PrsSwClear(&pe);
mvPp2PrsSwTcamLuSet(&pe, PRS_LU_MAC);
pe.index = PE_MAC_PROMISCOUS;
/* Continue - set next lookup */
mvPp2PrsSwSramNextLuSet(&pe, PRS_LU_DSA);
/* Set result info bits */
mvPp2PrsSwSramRiUpdate(&pe, RI_L2_UCAST, RI_L2_CAST_MASK);
/* shift to ethertype */
mvPp2PrsSwSramShiftSet(&pe, 2 * MV_MAC_ADDR_SIZE, SRAM_OP_SEL_SHIFT_ADD);
/* mask all ports */
mvPp2PrsSwTcamPortMapSet(&pe, 0);
/* Update mvPrsShadowTbl */
mvPp2PrsShadowSet(pe.index, PRS_LU_MAC, "promisc");
}
mvPp2PrsSwTcamPortSet(&pe, port, add);
mvPp2PrsHwWrite(&pe);
return MV_OK;
}
/* 0 - reject, 1 - accept */
int mvPrsMacAllMultiSet(int port, int add)
{
MV_PP2_PRS_ENTRY pe;
unsigned int i, idx = 0;
char *rule_str[MAX_MAC_MC] = { "mcast-mac-ip4", "mcast-mac-ip6" };
/* Ethernet multicast address first byte is with 0x01 */
unsigned char da_mc[MAX_MAC_MC] = { 0x01, 0x33 };
for (i = IP4_MAC_MC; i < MAX_MAC_MC; i++) {
if (i == IP4_MAC_MC)
idx = PE_MAC_MC_ALL;
else
idx = PE_MAC_MC_IP6;
/* all multicast */
if (mvPp2PrsShadowIsValid(idx)) {
/* Entry exist - update port only */
pe.index = idx;
mvPp2PrsHwRead(&pe);
} else {
/* Entry doesn't exist - create new */
mvPp2PrsSwClear(&pe);
pe.index = idx;
mvPp2PrsSwTcamLuSet(&pe, PRS_LU_MAC);
/* Continue - set next lookup */
mvPp2PrsSwSramNextLuSet(&pe, PRS_LU_DSA);
/* Set result info bits */
mvPp2PrsSwSramRiUpdate(&pe, RI_L2_MCAST, RI_L2_CAST_MASK);
mvPp2PrsSwTcamByteSet(&pe, 0, da_mc[i], 0xff);
/* shift to ethertype */
mvPp2PrsSwSramShiftSet(&pe, 2 * MV_MAC_ADDR_SIZE, SRAM_OP_SEL_SHIFT_ADD);
/* no ports */
mvPp2PrsSwTcamPortMapSet(&pe, 0);
/* Update mvPrsShadowTbl */
mvPp2PrsShadowSet(pe.index, PRS_LU_MAC, rule_str[i]);
}
mvPp2PrsSwTcamPortSet(&pe, port, add);
mvPp2PrsHwWrite(&pe);
}
return MV_OK;
}
int mvPrsMhRxSpecialSet(int port, unsigned short mh, int add)
{
#if 0 /* this function to be removed in future */
MV_PP2_PRS_ENTRY pe;
if (mvPp2PrsShadowIsValid(PE_RX_SPECIAL)) {
/* Entry exist - update port only */
pe.index = PE_RX_SPECIAL;
mvPp2PrsHwRead(&pe);
} else {
/* Entry doesn't exist - create new */
mvPp2PrsSwClear(&pe);
mvPp2PrsSwTcamLuSet(&pe, PRS_LU_MAC);
pe.index = PE_RX_SPECIAL;
mvPp2PrsSwSramRiUpdate(&pe, RI_CPU_CODE_RX_SPEC, RI_CPU_CODE_MASK);
mvPp2PrsSwSramFlowidGenSet(&pe);
mvPp2PrsSwSramNextLuSet(&pe, PRS_LU_FLOWS);
/* Update mvPrsShadowTbl */
mvPp2PrsShadowSet(pe.index, PRS_LU_MAC, "RX special");
mvPp2PrsSwTcamPortMapSet(&pe, 0);
}
mvPp2PrsMatchMh(&pe, mh);
mvPp2PrsSwTcamPortSet(&pe, port, add);
mvPp2PrsHwWrite(&pe);
#endif
return MV_OK;
}
/* Set default entires (place holder) for promiscous, non-promiscous and all-milticast MAC addresses */
static int mvPp2PrsMacInit(void)
{
MV_PP2_PRS_ENTRY pe;
mvPp2PrsSwClear(&pe);
/* Non-promiscous mode for all ports - DROP unknown packets */
pe.index = PE_MAC_NON_PROMISCOUS;
mvPp2PrsSwTcamLuSet(&pe, PRS_LU_MAC);
mvPp2PrsSwSramRiSetBit(&pe, RI_DROP_BIT);
/* mvPp2PrsSwSramLuDoneSet(&pe);*/
mvPp2PrsSwSramFlowidGenSet(&pe);
mvPp2PrsSwSramNextLuSet(&pe, PRS_LU_FLOWS);
/* Update mvPrsShadowTbl */
mvPp2PrsShadowSet(pe.index, PRS_LU_MAC, "non-promisc");
mvPp2PrsSwTcamPortMapSet(&pe, PORT_MASK);
mvPp2PrsHwWrite(&pe);
/* place holders only - no ports */
mvPrsMacDropAllSet(0, 0);
mvPrsMacPromiscousSet(0, 0);
mvPrsMacAllMultiSet(0, 0);
return MV_OK;
}
/******************************************************************************
*
* DSA Section
*
******************************************************************************
*/
static int mvPp2PrsDsaTagEtherTypeSet(int port, int add, int tagged, int extend)
{
MV_PP2_PRS_ENTRY pe;
char name[PRS_TEXT_SIZE];
int tid, shift, portMask;
/* if packet is tagged continue check vlans */
if (extend) {
if (tagged) {
tid = PE_ETYPE_EDSA_TAGGED;
mvOsSPrintf(name, "Etype-EDSA-tagged");
} else {
tid = PE_ETYPE_EDSA_UNTAGGED;
mvOsSPrintf(name, "Etype-EDSA-untagged");
}
portMask = 0;
shift = 8;
} else {
if (tagged) {
tid = PE_ETYPE_DSA_TAGGED;
mvOsSPrintf(name, "Etype-DSA-tagged");
} else {
tid = PE_ETYPE_DSA_UNTAGGED;
mvOsSPrintf(name, "Etype-DSA-untagged");
}
portMask = PORT_MASK;
shift = 4;
}
if (mvPp2PrsShadowIsValid(tid)) {
/* Entry exist - update port only */
pe.index = tid;
mvPp2PrsHwRead(&pe);
} else {
/* Entry doesn't exist - create new */
mvPp2PrsSwClear(&pe);
mvPp2PrsSwTcamLuSet(&pe, PRS_LU_DSA);
pe.index = tid;
/* set etherType*/
mvPp2PrsMatchEtype(&pe, 0, etherTypeDsa);
mvPp2PrsMatchEtype(&pe, 2, 0);
mvPp2PrsSwSramRiSetBit(&pe, RI_DSA_BIT);
/* shift etherType + 2 byte reserved + tag*/
mvPp2PrsSwSramShiftSet(&pe, 2 + MV_ETH_TYPE_LEN + shift, SRAM_OP_SEL_SHIFT_ADD);
mvPp2PrsShadowSet(pe.index, PRS_LU_DSA, name);
/* set tagged bit in DSA tag */
/* TODO use define */
if (tagged) {
/* set bit 29 in dsa tag */
mvPp2PrsSwTcamByteSet(&pe, MV_ETH_TYPE_LEN + 2 + 3, 0x20, 0x20);
/* Clear all AI bits for next iteration */
mvPp2PrsSwSramAiUpdate(&pe, 0, SRAM_AI_MASK);
/* mark vlan single RI */
mvPp2PrsSwSramRiUpdate(&pe, RI_VLAN_SINGLE, RI_VLAN_MASK);
mvPp2PrsSwSramNextLuSet(&pe, PRS_LU_VLAN);
} else {
/* Set result info bits - No valns ! */
mvPp2PrsSwSramRiUpdate(&pe, RI_VLAN_NONE, RI_VLAN_MASK);
mvPp2PrsSwSramNextLuSet(&pe, PRS_LU_L2);
}
/* all ports enabled */
mvPp2PrsSwTcamPortMapSet(&pe, portMask);
}
mvPp2PrsSwTcamPortSet(&pe, port, add);
mvPp2PrsHwWrite(&pe);
return MV_OK;
}
static int mvPp2PrsDsaTagSet(int port, int add, int tagged, int extend)
{
MV_PP2_PRS_ENTRY pe;
char name[PRS_TEXT_SIZE];
int tid, shift;
/* if packet is tagged continue check vlans */
if (extend) {
if (tagged) {
tid = PE_EDSA_TAGGED;
mvOsSPrintf(name, "EDSA-tagged");
} else {
tid = PE_EDSA_UNTAGGED;
mvOsSPrintf(name, "EDSA-untagged");
}
shift = 8;
} else {
if (tagged) {
tid = PE_DSA_TAGGED;
mvOsSPrintf(name, "DSA-tagged");
} else {
tid = PE_DSA_UNTAGGED;
mvOsSPrintf(name, "DSA-untagged");
}
shift = 4;
}
if (mvPp2PrsShadowIsValid(tid)) {
/* Entry exist - update port only */
pe.index = tid;
mvPp2PrsHwRead(&pe);
} else {
/* Entry doesn't exist - create new */
mvPp2PrsSwClear(&pe);
mvPp2PrsSwTcamLuSet(&pe, PRS_LU_DSA);
pe.index = tid;
/* shift 4 bytes if DSA tag , Skip 8 bytes if extand DSA tag*/
mvPp2PrsSwSramShiftSet(&pe, shift, SRAM_OP_SEL_SHIFT_ADD);
mvPp2PrsShadowSet(pe.index, PRS_LU_DSA, name);
/* set tagged bit in DSA tag */
/* TODO use define */
if (tagged) {
mvPp2PrsSwTcamByteSet(&pe, 0, 0x20, 0x20);
/* Clear all AI bits for next iteration */
mvPp2PrsSwSramAiUpdate(&pe, 0, SRAM_AI_MASK);
/* mark vlan single RI */
mvPp2PrsSwSramRiUpdate(&pe, RI_VLAN_SINGLE, RI_VLAN_MASK);
mvPp2PrsSwSramNextLuSet(&pe, PRS_LU_VLAN);
} else {
/* Set result info bits - No valns ! */
mvPp2PrsSwSramRiUpdate(&pe, RI_VLAN_NONE, RI_VLAN_MASK);
mvPp2PrsSwSramNextLuSet(&pe, PRS_LU_L2);
}
mvPp2PrsSwTcamPortMapSet(&pe, 0);
}
mvPp2PrsSwTcamPortSet(&pe, port, add);
mvPp2PrsHwWrite(&pe);
return MV_OK;
}
static int mvPp2PrsDsaInit(void)
{
MV_PP2_PRS_ENTRY pe;
etherTypeDsa = DSA_ETHER_TYPE;
/* none tagged EDSA entry -place holder */
mvPp2PrsDsaTagSet(0, 0, UNTAGGED, EDSA);
/* tagged EDSA entry -place holder */
mvPp2PrsDsaTagSet(0, 0, TAGGED, EDSA);
/* none tagged DSA entry -place holder */
mvPp2PrsDsaTagSet(0, 0, UNTAGGED, DSA);
/* tagged DSA entry -place holder */
mvPp2PrsDsaTagSet(0, 0, TAGGED, DSA);
/* none tagged EDSA EtherType entry - place holder*/
mvPp2PrsDsaTagEtherTypeSet(0, 0, UNTAGGED, EDSA);
/* tagged EDSA EtherType entry - place holder*/
mvPp2PrsDsaTagEtherTypeSet(0, 0, TAGGED, EDSA);
/* none tagged DSA EtherType entry */
mvPp2PrsDsaTagEtherTypeSet(0, 1, UNTAGGED, DSA);
/* tagged DSA EtherType entry */
mvPp2PrsDsaTagEtherTypeSet(0, 1, TAGGED, DSA);
/* default entry , if DSA or EDSA tag not found */
mvPp2PrsSwClear(&pe);
mvPp2PrsSwTcamLuSet(&pe, PRS_LU_DSA);
pe.index = PE_DSA_DEFAULT;
mvPp2PrsSwSramNextLuSet(&pe, PRS_LU_VLAN);
/* shift 0 bytes */
mvPp2PrsSwSramShiftSet(&pe, 0, SRAM_OP_SEL_SHIFT_ADD);
mvPp2PrsShadowSet(pe.index, PRS_LU_MAC, "default-DSA-tag");
/* Clear all AI bits for next iteration */
mvPp2PrsSwSramAiUpdate(&pe, 0, SRAM_AI_MASK);
/* match for all ports*/
mvPp2PrsSwTcamPortMapSet(&pe, PORT_MASK);
mvPp2PrsHwWrite(&pe);
return MV_OK;
}
int mvPp2PrsEtypeDsaSet(unsigned int eType)
{
int tid;
MV_PP2_PRS_ENTRY pe;
etherTypeDsa = eType;
for (tid = PE_ETYPE_EDSA_TAGGED; tid <= PE_ETYPE_DSA_UNTAGGED; tid++) {
pe.index = tid;
mvPp2PrsHwRead(&pe);
/* overrwite old etherType*/
mvPp2PrsMatchEtype(&pe, 0, etherTypeDsa);
mvPp2PrsHwWrite(&pe);
}
return MV_OK;
}
int mvPp2PrsEtypeDsaModeSet(int port, int extand)
{
POS_RANGE_VALIDATE(port, MV_PP2_MAX_PORTS - 1);
POS_RANGE_VALIDATE(extand, 1);
if (extand) {
mvPp2PrsDsaTagEtherTypeSet(port, 1, UNTAGGED, EDSA);
mvPp2PrsDsaTagEtherTypeSet(port, 1, TAGGED, EDSA);
mvPp2PrsDsaTagEtherTypeSet(port, 0, UNTAGGED, DSA);
mvPp2PrsDsaTagEtherTypeSet(port, 0, TAGGED, DSA);
} else {
mvPp2PrsDsaTagEtherTypeSet(port, 0, UNTAGGED, EDSA);
mvPp2PrsDsaTagEtherTypeSet(port, 0, TAGGED, EDSA);
mvPp2PrsDsaTagEtherTypeSet(port, 1, UNTAGGED, DSA);
mvPp2PrsDsaTagEtherTypeSet(port, 1, TAGGED, DSA);
}
return MV_OK;
}
int mvPp2PrsTagModeSet(int port, int type)
{
POS_RANGE_VALIDATE(port, MV_PP2_MAX_PORTS - 1);
switch (type) {
case MV_TAG_TYPE_EDSA:
/* Add port to EDSA entries */
mvPp2PrsDsaTagSet(port, 1, TAGGED, EDSA);
mvPp2PrsDsaTagSet(port, 1, UNTAGGED, EDSA);
/* remove port from DSA entries */
mvPp2PrsDsaTagSet(port, 0, TAGGED, DSA);
mvPp2PrsDsaTagSet(port, 0, UNTAGGED, DSA);
break;
case MV_TAG_TYPE_DSA:
/* Add port to DSA entries */
mvPp2PrsDsaTagSet(port, 1, TAGGED, DSA);
mvPp2PrsDsaTagSet(port, 1, UNTAGGED, DSA);
/* remove port from EDSA entries */
mvPp2PrsDsaTagSet(port, 0, TAGGED, EDSA);
mvPp2PrsDsaTagSet(port, 0, UNTAGGED, EDSA);
break;
case MV_TAG_TYPE_MH:
case MV_TAG_TYPE_NONE:
/* remove port form EDSA and DSA entries */
mvPp2PrsDsaTagSet(port, 0, TAGGED, DSA);
mvPp2PrsDsaTagSet(port, 0, UNTAGGED, DSA);
mvPp2PrsDsaTagSet(port, 0, TAGGED, EDSA);
mvPp2PrsDsaTagSet(port, 0, UNTAGGED, EDSA);
break;
default:
POS_RANGE_VALIDATE(type, MV_TAG_TYPE_EDSA);
}
return MV_OK;
}
/******************************************************************************
*
* VLAN Section
*
******************************************************************************
*/
char *mvPrsVlanInfoStr(unsigned int vlan_info)
{
switch (vlan_info << RI_VLAN_OFFS) {
case RI_VLAN_NONE:
return "None";
case RI_VLAN_SINGLE:
return "Single";
case RI_VLAN_DOUBLE:
return "Double";
case RI_VLAN_TRIPLE:
return "Triple";
default:
return "Unknown";
}
return NULL;
}
static MV_PP2_PRS_ENTRY *mvPrsVlanFind(unsigned short tpid, int ai)
{
MV_PP2_PRS_ENTRY *pe;
int tid;
unsigned int riBits, aiBits, enable;
unsigned char tpidArr[2];
pe = mvPp2PrsSwAlloc(PRS_LU_VLAN);
#ifdef MV_CPU_LE
tpidArr[0] = ((unsigned char *)&tpid)[1];
tpidArr[1] = ((unsigned char *)&tpid)[0];
#else
tpidArr[0] = ((unsigned char *)&tpid)[0];
tpidArr[1] = ((unsigned char *)&tpid)[1];
#endif
/* Go through the all entires with PRS_LU_MAC */
for (tid = PE_FIRST_FREE_TID ; tid <= PE_LAST_FREE_TID; tid++) {
if ((!mvPp2PrsShadowIsValid(tid)) || (mvPp2PrsShadowLu(tid) != PRS_LU_VLAN))
continue;
pe->index = tid;
mvPp2PrsHwRead(pe);
if (mvPp2PrsSwTcamBytesIgnorMaskCmp(pe, 0, 2, tpidArr) == EQUALS) {
mvPp2PrsSwSramRiGet(pe, &riBits, &enable);
/* get Vlan type */
riBits = (riBits & RI_VLAN_MASK);
/* get current AI value Tcam */
mvPp2PrsSwTcamAiGet(pe, &aiBits, &enable);
/* clear double Vlan Bit */
aiBits &= ~(1 << DBL_VLAN_AI_BIT);
if (ai != aiBits)
continue;
if ((riBits == RI_VLAN_SINGLE) || (riBits == RI_VLAN_TRIPLE))
return pe;
}
}
mvPp2PrsSwFree(pe);
return NULL;
}
int mvPrsVlanExist(unsigned short tpid, int ai)
{
if (NULL == mvPrsVlanFind(tpid, ai))
return 0;
else
return 1;
}
static MV_PP2_PRS_ENTRY *mvPrsDoubleVlanFind(unsigned short tpid1, unsigned short tpid2)
{
MV_PP2_PRS_ENTRY *pe;
int tid;
unsigned int bits, enable;
unsigned char tpidArr1[2];
unsigned char tpidArr2[2];
#ifdef MV_CPU_LE
tpidArr1[0] = ((unsigned char *)&tpid1)[1];
tpidArr1[1] = ((unsigned char *)&tpid1)[0];
tpidArr2[0] = ((unsigned char *)&tpid2)[1];
tpidArr2[1] = ((unsigned char *)&tpid2)[0];
#else /* MV_CPU_LE */
tpidArr1[0] = ((unsigned char *)&tpid1)[0];
tpidArr1[1] = ((unsigned char *)&tpid1)[1];
tpidArr2[0] = ((unsigned char *)&tpid2)[0];
tpidArr2[1] = ((unsigned char *)&tpid2)[1];
#endif
pe = mvPp2PrsSwAlloc(PRS_LU_VLAN);
/* Go through the all entires with PRS_LU_MAC */
for (tid = PE_FIRST_FREE_TID ; tid <= PE_LAST_FREE_TID; tid++) {
if ((!mvPp2PrsShadowIsValid(tid)) || (mvPp2PrsShadowLu(tid) != PRS_LU_VLAN))
continue;
pe->index = tid;
mvPp2PrsHwRead(pe);
if ((mvPp2PrsSwTcamBytesIgnorMaskCmp(pe, 0, 2, tpidArr1) == EQUALS) &&
(mvPp2PrsSwTcamBytesIgnorMaskCmp(pe, 4, 2, tpidArr2) == EQUALS)) {
mvPp2PrsSwSramRiGet(pe, &bits, &enable);
if ((bits & RI_VLAN_MASK) == RI_VLAN_DOUBLE)
return pe;
}
}
mvPp2PrsSwFree(pe);
return NULL;
}
int mvPrsDoubleVlanExist(unsigned short tpid1, unsigned short tpid2)
{
if (NULL == mvPrsDoubleVlanFind(tpid1, tpid2))
return 0;
else
return 1;
}
/* return last double vlan entry */
static int mvPpPrsDoubleVlanLast(void)
{
MV_PP2_PRS_ENTRY pe;
unsigned int bits, enable;
int tid;
for (tid = PE_LAST_FREE_TID; tid >= PE_FIRST_FREE_TID; tid--) {
if ((!mvPp2PrsShadowIsValid(tid)) || (mvPp2PrsShadowLu(tid) != PRS_LU_VLAN))
continue;
pe.index = tid;
mvPp2PrsHwRead(&pe);
mvPp2PrsSwSramRiGet(&pe, &bits, &enable);
if ((bits & RI_VLAN_MASK) == RI_VLAN_DOUBLE)
return tid;
}
return tid;
}
/* return first Single or Triple vlan entry */
static int mvPpPrsVlanFirst(void)
{
MV_PP2_PRS_ENTRY pe;
unsigned int bits, enable;
int tid;
for (tid = PE_FIRST_FREE_TID; tid <= PE_LAST_FREE_TID; tid++) {
if ((!mvPp2PrsShadowIsValid(tid)) || (mvPp2PrsShadowLu(tid) != PRS_LU_VLAN))
continue;
pe.index = tid;
mvPp2PrsHwRead(&pe);
mvPp2PrsSwSramRiGet(&pe, &bits, &enable);
bits &= RI_VLAN_MASK;
if ((bits == RI_VLAN_SINGLE) || (bits == RI_VLAN_TRIPLE))
return tid;
}
return tid;
}
static int mvPp2PrsVlanAdd(unsigned short tpid, int ai, unsigned int portBmp)
{
int lastDouble, tid, status = 0;
MV_PP2_PRS_ENTRY *pe = NULL;
char name[PRS_TEXT_SIZE];
pe = mvPrsVlanFind(tpid, ai);
if (pe == NULL) {
/* Create new TCAM entry */
tid = mvPp2PrsTcamFirstFree(PE_LAST_FREE_TID, PE_FIRST_FREE_TID);
if (tid == MV_PRS_OUT_OF_RAGE) {
mvOsPrintf("%s: No free TCAM entiry\n", __func__);
return MV_ERROR;
}
/* get last double vlan tid */
lastDouble = mvPpPrsDoubleVlanLast();
if (tid <= lastDouble) {
/* double vlan entries overlapping*/
mvOsPrintf("%s:Can't add entry, please remove unnecessary triple or single vlans entries.\n",
__func__);
return MV_ERROR;
}
pe = mvPp2PrsSwAlloc(PRS_LU_VLAN);
pe->index = tid;
mvPp2PrsMatchEtype(pe, 0, tpid);
/* Clear all AI bits for next iteration */
status |= mvPp2PrsSwSramAiUpdate(pe, 0, SRAM_AI_MASK);
/* Continue - set next lookup */
status |= mvPp2PrsSwSramNextLuSet(pe, PRS_LU_L2);
/* shift 4 bytes - skip 1 VLAN tags */
status |= mvPp2PrsSwSramShiftSet(pe, MV_VLAN_HLEN, SRAM_OP_SEL_SHIFT_ADD);
if (ai == SINGLE_VLAN_AI) {
/* single vlan*/
mvOsSPrintf(name, "single-VLAN");
mvPp2PrsSwSramRiUpdate(pe, RI_VLAN_SINGLE, RI_VLAN_MASK);
} else {
/* triple vlan*/
mvOsSPrintf(name, "triple-VLAN-%d", ai);
ai |= (1 << DBL_VLAN_AI_BIT);
mvPp2PrsSwSramRiUpdate(pe, RI_VLAN_TRIPLE, RI_VLAN_MASK);
}
status |= mvPp2PrsSwTcamAiUpdate(pe, ai, SRAM_AI_MASK);
mvPp2PrsShadowSet(pe->index, PRS_LU_VLAN, name);
}
status |= mvPp2PrsSwTcamPortMapSet(pe, portBmp);
if (status == 0)
mvPp2PrsHwWrite(pe);
mvPp2PrsSwFree(pe);
return MV_OK;
}
static int mvPp2PrsVlanDel(unsigned short tpid, int ai)
{
MV_PP2_PRS_ENTRY *pe = NULL;
pe = mvPrsVlanFind(tpid, ai);
if (pe == NULL) {
/* No such entry */
mvOsPrintf("Can't remove - No such entry\n");
return MV_ERROR;
}
/* remove entry */
mvPp2PrsHwInv(pe->index);
mvPp2PrsShadowClear(pe->index);
mvPp2PrsSwFree(pe);
return MV_OK;
}
int mvPp2PrsDoubleVlanAdd(unsigned short tpid1, unsigned short tpid2, unsigned int portBmp)
{
int tid, ai, status = 0;
int firstVlan;
MV_PP2_PRS_ENTRY *pe = NULL;
char name[PRS_TEXT_SIZE];
pe = mvPrsDoubleVlanFind(tpid1, tpid2);
if (pe == NULL) {
/* Create new TCAM entry */
tid = mvPp2PrsTcamFirstFree(PE_FIRST_FREE_TID, PE_LAST_FREE_TID);
if (tid == MV_PRS_OUT_OF_RAGE) {
mvOsPrintf("%s: No free TCAM entiry\n", __func__);
return MV_ERROR;
}
pe = mvPp2PrsSwAlloc(PRS_LU_VLAN);
pe->index = tid;
/* set AI value for new double vlan entry */
ai = mvPrsDblVlanAiFreeGet();
if (ai == MV_PRS_OUT_OF_RAGE) {
mvOsPrintf("%s: Can't add - number of Double vlan rules reached to maximum.\n", __func__);
return MV_ERROR;
}
/* get first single/triple vlan tid */
firstVlan = mvPpPrsVlanFirst();
if (tid >= firstVlan) {
/* double vlan entries overlapping*/
mvOsPrintf("%s:Can't add entry, please remove unnecessary double vlans entries.\n", __func__);
return MV_ERROR;
}
mvPrsDblVlanAiShadowSet(ai);
mvPp2PrsMatchEtype(pe, 0, tpid1);
mvPp2PrsMatchEtype(pe, 4, tpid2);
/* Set AI value in SRAM for double vlan */
status |= mvPp2PrsSwSramAiUpdate(pe, (ai | (1 << DBL_VLAN_AI_BIT)), SRAM_AI_MASK);
/* Continue - set next lookup, */
status |= mvPp2PrsSwSramNextLuSet(pe, PRS_LU_VLAN);
/* Set result info bits */
status |= mvPp2PrsSwSramRiUpdate(pe, RI_VLAN_DOUBLE, RI_VLAN_MASK);
/* shift 8 bytes - skip 2 VLAN tags */
status |= mvPp2PrsSwSramShiftSet(pe, 2 * MV_VLAN_HLEN, SRAM_OP_SEL_SHIFT_ADD);
/* Update mvPrsShadowTbl */
mvOsSPrintf(name, "double-VLAN-%d", ai);
mvPp2PrsShadowSet(pe->index, PRS_LU_VLAN, name);
}
/* set ports bitmap*/
status |= mvPp2PrsSwTcamPortMapSet(pe, portBmp);
if (status == 0)
mvPp2PrsHwWrite(pe);
mvPp2PrsSwFree(pe);
return status;
}
int mvPp2PrsDoubleVlanDel(unsigned short tpid1, unsigned short tpid2)
{
MV_PP2_PRS_ENTRY *pe = NULL;
unsigned int ai, enable;
pe = mvPrsDoubleVlanFind(tpid1, tpid2);
if (pe == NULL) {
/* No such entry */
mvOsPrintf("Can't remove - No such entry\n");
return MV_ERROR;
}
/* TODO - remove all corresponding vlan triples */
mvPp2PrsSwSramAiGet(pe, &ai, &enable);
/* remove double vlan AI sign*/
ai &= ~(1 << DBL_VLAN_AI_BIT);
mvPrsDblVlanAiShadowClear(ai);
/* remove entry */
mvPp2PrsHwInv(pe->index);
mvPp2PrsShadowClear(pe->index);
mvPp2PrsSwFree(pe);
return MV_OK;
}
int mvPp2PrsSingleVlan(unsigned short tpid, unsigned int portBmp, int add)
{
if (add)
return mvPp2PrsVlanAdd(tpid, SINGLE_VLAN_AI, portBmp);
else
return mvPp2PrsVlanDel(tpid, SINGLE_VLAN_AI);
}
int mvPp2PrsDoubleVlan(unsigned short tpid1, unsigned short tpid2, unsigned int portBmp, int add)
{
if (add)
return mvPp2PrsDoubleVlanAdd(tpid1, tpid2, portBmp);
else
return mvPp2PrsDoubleVlanDel(tpid1, tpid2);
}
int mvPp2PrsTripleVlan(unsigned short tpid1, unsigned short tpid2, unsigned short tpid3, unsigned int portBmp, int add)
{
MV_PP2_PRS_ENTRY *pe;
unsigned int ai, aiEnable;
int status;
pe = mvPrsDoubleVlanFind(tpid1, tpid2);
if (!pe) {
if (add)
mvOsPrintf("User must enter first double vlan <0x%x,0x%x> before triple\n", tpid1, tpid2);
else
mvOsPrintf("Can't remove - No such entry\n");
return MV_ERROR;
}
/* get AI value form double VLAN entry */
mvPp2PrsSwSramAiGet(pe, &ai, &aiEnable);
ai &= ~(1 << DBL_VLAN_AI_BIT);
if (add)
status = mvPp2PrsVlanAdd(tpid3, ai, portBmp);
else
status = mvPp2PrsVlanDel(tpid3, ai);
mvPp2PrsSwFree(pe);
return status;
}
/* Detect up to 2 successive VLAN tags:
* Possible options:
* 0x8100, 0x88A8
* 0x8100, 0x8100
* 0x8100
* 0x88A8
*/
static int mvPp2PrsVlanInit(void)
{
MV_PP2_PRS_ENTRY pe;
mvPrsDblVlanAiShadowClearAll();
/* double VLAN: 0x8100, 0x88A8 */
if (mvPp2PrsDoubleVlan(MV_VLAN_TYPE, MV_VLAN_1_TYPE, PORT_MASK, 1))
return MV_ERROR;
/* double VLAN: 0x8100, 0x8100 */
if (mvPp2PrsDoubleVlan(MV_VLAN_TYPE, MV_VLAN_TYPE, PORT_MASK, 1))
return MV_ERROR;
/* single VLAN: 0x88a8 */
if (mvPp2PrsSingleVlan(MV_VLAN_1_TYPE, PORT_MASK, 1))
return MV_ERROR;
/* single VLAN: 0x8100 */
if (mvPp2PrsSingleVlan(MV_VLAN_TYPE, PORT_MASK, 1))
return MV_ERROR;
/*---------------------------------*/
/* Set default double vlan entry */
/*---------------------------------*/
mvPp2PrsSwClear(&pe);
mvPp2PrsSwTcamLuSet(&pe, PRS_LU_VLAN);
pe.index = PE_VLAN_DBL;
/* Continue - set next lookup */
mvPp2PrsSwSramNextLuSet(&pe, PRS_LU_L2);
/* double vlan AI bit */
mvPp2PrsSwTcamAiUpdate(&pe, (1 << DBL_VLAN_AI_BIT), (1 << DBL_VLAN_AI_BIT));
/* clear AI for next iterations */
mvPp2PrsSwSramAiUpdate(&pe, 0, SRAM_AI_MASK);
/* Set result info bits */
mvPp2PrsSwSramRiUpdate(&pe, RI_VLAN_DOUBLE, RI_VLAN_MASK);
mvPp2PrsSwTcamPortMapSet(&pe, PORT_MASK);
mvPp2PrsHwWrite(&pe);
/* Update mvPrsShadowTbl */
mvPp2PrsShadowSet(pe.index, PRS_LU_VLAN, "double-VLAN-accept");
/*---------------------------------*/
/* Set default vlan none entry */
/*---------------------------------*/
mvPp2PrsSwClear(&pe);
mvPp2PrsSwTcamLuSet(&pe, PRS_LU_VLAN);
pe.index = PE_VLAN_NONE;
/* Continue - set next lookup */
mvPp2PrsSwSramNextLuSet(&pe, PRS_LU_L2);
/* Set result info bits */
mvPp2PrsSwSramRiUpdate(&pe, RI_VLAN_NONE, RI_VLAN_MASK);
mvPp2PrsSwTcamPortMapSet(&pe, PORT_MASK);
mvPp2PrsHwWrite(&pe);
/* Update mvPrsShadowTbl */
mvPp2PrsShadowSet(pe.index, PRS_LU_VLAN, "no-VLAN");
return MV_OK;
}
/* remove all vlan entries */
int mvPp2PrsVlanAllDel(void)
{
int tid;
/* clear doublr Vlan shadow */
mvPrsDblVlanAiShadowClearAll();
for (tid = PE_FIRST_FREE_TID ; tid <= PE_LAST_FREE_TID; tid++) {
if (mvPp2PrsShadowIsValid(tid) && (mvPp2PrsShadowLu(tid) == PRS_LU_VLAN)) {
mvPp2PrsHwInv(tid);
mvPp2PrsShadowClear(tid);
}
}
return MV_OK;
}
/******************************************************************************
*
* Ethertype Section
*
******************************************************************************
*/
/*TODO USE this function for all def etypres creation */
static int mvPrsEthTypeCreate(int portMap, unsigned short eth_type, unsigned int ri, unsigned int riMask)
{
int tid;
MV_PP2_PRS_ENTRY *pe;
/* Go through the all entires from first to last */
tid = mvPp2PrsTcamFirstFree(PE_FIRST_FREE_TID, PE_LAST_FREE_TID);
/* Can't add - No free TCAM entries */
if (tid == MV_PRS_OUT_OF_RAGE) {
mvOsPrintf("%s: No free TCAM entiry\n", __func__);
return MV_ERROR;
}
pe = mvPp2PrsSwAlloc(PRS_LU_L2);
pe->index = tid;
mvPp2PrsMatchEtype(pe, 0, eth_type);
mvPp2PrsSwSramRiSet(pe, ri, riMask);
mvPp2PrsSwTcamPortMapSet(pe, portMap);
/* Continue - set next lookup */
mvPp2PrsSwSramNextLuSet(pe, PRS_LU_FLOWS);
mvPp2PrsSwSramFlowidGenSet(pe);
mvPp2PrsHwWrite(pe);
mvPp2PrsShadowSet(pe->index, PRS_LU_L2, "etype-user-define");
mvPp2PrsShadowUdfSet(pe->index, PRS_UDF_L2_USER);
mvPp2PrsShadowRiSet(pe->index, ri, riMask);
mvPp2PrsSwFree(pe);
return MV_OK;
}
static int mvPrsEthTypeValid(unsigned int portMap, unsigned short ethertype)
{
MV_PP2_PRS_ENTRY pe;
unsigned int entryPmap;
int tid;
for (tid = PE_LAST_FREE_TID ; tid >= PE_FIRST_FREE_TID; tid--) {
if (!mvPp2PrsShadowIsValid(tid) || (mvPp2PrsShadowLu(tid) != PRS_LU_L2))
continue;
pe.index = tid;
mvPp2PrsHwRead(&pe);
if (!mvPp2PrsEtypeEquals(&pe, 0, ethertype))
continue;
/* in default entries portmask must be 0xff */
if ((mvPp2PrsShadowUdf(tid) == PRS_UDF_L2_DEF) && (portMap != PORT_MASK)) {
mvOsPrintf("%s: operation not supported.\n", __func__);
mvOsPrintf("%s: ports map must be 0xFF for default ether type\n", __func__);
return MV_ERROR;
} else {
/* port maps cannot intersection in User entries*/
/* PRS_UDF_L2_USER */
mvPp2PrsSwTcamPortMapGet(&pe, &entryPmap);
if ((portMap & entryPmap) && (portMap != entryPmap)) {
mvOsPrintf("%s: operation not supported\n", __func__);
mvOsPrintf("%s: user must delete portMap 0x%x from entry %d.\n",
__func__, entryPmap & portMap, tid);
return MV_ERROR;
}
}
}
return MV_OK;
}
int mvPrsEthTypeSet(int portMap, unsigned short ethertype, unsigned int ri, unsigned int riMask, MV_BOOL finish)
{
MV_PP2_PRS_ENTRY pe;
int tid;
unsigned int entryPmap;
MV_BOOL done = MV_FALSE;
/* step 1 - validation */
if (mvPrsEthTypeValid(portMap, ethertype))
return MV_ERROR;
/* step 2 - update TCAM */
for (tid = PE_FIRST_FREE_TID ; tid <= PE_LAST_FREE_TID; tid++) {
if (!mvPp2PrsShadowIsValid(tid) || (mvPp2PrsShadowLu(tid) != PRS_LU_L2))
continue;
pe.index = tid;
mvPp2PrsHwRead(&pe);
if (!mvPp2PrsEtypeEquals(&pe, 0, ethertype))
continue;
mvPp2PrsSwTcamPortMapGet(&pe, &entryPmap);
if (entryPmap != portMap)
continue;
done = MV_TRUE;
mvPp2PrsSwSramRiUpdate(&pe, ri, riMask);
if ((mvPp2PrsShadowUdf(tid) == PRS_UDF_L2_USER) || finish)
mvPp2PrsSwSramFlowidGenSet(&pe);
mvPp2PrsHwWrite(&pe);
}
/* step 3 - Add new ethertype entry */
if (!done)
return mvPrsEthTypeCreate(portMap, ethertype, ri, riMask);
return MV_OK;
}
int mvPrsEthTypeDel(int portMap, unsigned short ethertype)
{
MV_PP2_PRS_ENTRY pe;
unsigned int entryPmap;
int tid;
for (tid = PE_FIRST_FREE_TID; tid <= PE_LAST_FREE_TID; tid++) {
if (!mvPp2PrsShadowIsValid(tid) || (mvPp2PrsShadowLu(tid) != PRS_LU_L2))
continue;
/* EtherType entry */
pe.index = tid;
mvPp2PrsHwRead(&pe);
if (!mvPp2PrsEtypeEquals(&pe, 0, ethertype))
continue;
if (mvPp2PrsShadowUdf(tid) == PRS_UDF_L2_DEF) {
if (portMap != PORT_MASK) {
mvOsPrintf("%s: ports map must be 0xFF for default ether type\n", __func__);
return MV_ERROR;
}
mvPp2PrsSwSramRiSet(&pe, mvPp2PrsShadowRi(tid), mvPp2PrsShadowRiMask(tid));
if (!mvPp2PrsShadowFin(tid))
mvPp2PrsSwSramFlowidGenClear(&pe);
mvPp2PrsHwWrite(&pe);
continue;
}
/*PRS_UDF_L2_USER */
mvPp2PrsSwTcamPortMapGet(&pe, &entryPmap);
/*mask ports in user entry */
entryPmap &= ~portMap;
if (entryPmap == 0) {
mvPp2PrsHwInv(tid);
mvPp2PrsShadowClear(tid);
continue;
}
mvPp2PrsSwTcamPortMapSet(&pe, entryPmap);
mvPp2PrsHwWrite(&pe);
}
return MV_OK;
}
static int mvPp2PrsEtypePppoe(void)
{
int tid;
MV_PP2_PRS_ENTRY *pe;
PRS_DBG("%s\n", __func__);
/* Go through the all entires from first to last */
tid = mvPp2PrsTcamFirstFree(0, MV_PP2_PRS_TCAM_SIZE - 1);
/* Can't add - No free TCAM entries */
if (tid == MV_PRS_OUT_OF_RAGE) {
mvOsPrintf("%s: No free TCAM entiry\n", __func__);
return MV_ERROR;
}
pe = mvPp2PrsSwAlloc(PRS_LU_L2);
pe->index = tid;
mvPp2PrsMatchEtype(pe, 0, MV_PPPOE_TYPE);
mvPp2PrsSwSramShiftSet(pe, MV_PPPOE_HDR_SIZE, SRAM_OP_SEL_SHIFT_ADD);
mvPp2PrsSwSramNextLuSet(pe, PRS_LU_PPPOE);
mvPp2PrsSwSramRiSetBit(pe, RI_PPPOE_BIT);
mvPp2PrsHwWrite(pe);
/* Update mvPrsShadowTbl */
mvPp2PrsShadowSet(pe->index, PRS_LU_L2, "etype-PPPoE");
mvPp2PrsShadowUdfSet(pe->index, PRS_UDF_L2_DEF);
mvPp2PrsShadowRiSet(pe->index, RI_PPPOE_MASK, RI_PPPOE_MASK);
mvPp2PrsShadowFinSet(pe->index, MV_FALSE);
mvPp2PrsSwFree(pe);
return MV_OK;
}
/* match ip4 and ihl == 5 */
static int mvPp2PrsEtypeIp4(void)
{
int tid;
MV_PP2_PRS_ENTRY *pe;
PRS_DBG("%s\n", __func__);
/* IPv4 without options */
/* Go through the all entires from first to last */
tid = mvPp2PrsTcamFirstFree(0, MV_PP2_PRS_TCAM_SIZE - 1);
/* Can't add - No free TCAM entries */
if (tid == MV_PRS_OUT_OF_RAGE) {
mvOsPrintf("%s: No free TCAM entiry\n", __func__);
return MV_ERROR;
}
pe = mvPp2PrsSwAlloc(PRS_LU_L2);
pe->index = tid;
mvPp2PrsMatchEtype(pe, 0, MV_IP_TYPE);
mvPp2PrsSwTcamByteSet(pe, MV_ETH_TYPE_LEN + 0, 0x45, 0xff);
mvPp2PrsSwSramNextLuSet(pe, PRS_LU_IP4);
mvPp2PrsSwSramRiUpdate(pe, RI_L3_IP4, RI_L3_PROTO_MASK);
/* Skip eth_type + 4 bytes of IP header */
mvPp2PrsSwSramShiftSet(pe, MV_ETH_TYPE_LEN + 4, SRAM_OP_SEL_SHIFT_ADD);
/* set L3 offset */
mvPp2PrsSwSramOffsetSet(pe, SRAM_OFFSET_TYPE_L3, MV_ETH_TYPE_LEN, SRAM_OP_SEL_OFFSET_ADD);
mvPp2PrsHwWrite(pe);
/* Update mvPrsShadowTbl */
mvPp2PrsShadowSet(pe->index, PRS_LU_L2, "etype-ipv4");
mvPp2PrsShadowFinSet(pe->index, MV_FALSE);
mvPp2PrsShadowUdfSet(pe->index, PRS_UDF_L2_DEF);
mvPp2PrsShadowRiSet(pe->index, RI_L3_IP4, RI_L3_PROTO_MASK);
mvPp2PrsSwFree(pe);
/* IPv4 with options */
/* Go through the all entires from first to last */
tid = mvPp2PrsTcamFirstFree(0, MV_PP2_PRS_TCAM_SIZE - 1);
/* Can't add - No free TCAM entries */
if (tid == MV_PRS_OUT_OF_RAGE) {
mvOsPrintf("%s: No free TCAM entiry\n", __func__);
return MV_ERROR;
}
pe = mvPp2PrsSwAlloc(PRS_LU_L2);
pe->index = tid;
mvPp2PrsMatchEtype(pe, 0, MV_IP_TYPE);
mvPp2PrsSwTcamByteSet(pe, MV_ETH_TYPE_LEN + 0, 0x40, 0xf0);
/* Skip eth_type + 4 bytes of IP header */
mvPp2PrsSwSramShiftSet(pe, MV_ETH_TYPE_LEN + 4, SRAM_OP_SEL_SHIFT_ADD);
mvPp2PrsSwSramNextLuSet(pe, PRS_LU_IP4);
mvPp2PrsSwSramRiUpdate(pe, RI_L3_IP4_OPT, RI_L3_PROTO_MASK);
/* set L3 offset */
mvPp2PrsSwSramOffsetSet(pe, SRAM_OFFSET_TYPE_L3, MV_ETH_TYPE_LEN, SRAM_OP_SEL_OFFSET_ADD);
mvPp2PrsHwWrite(pe);
/* Update mvPrsShadowTbl */
mvPp2PrsShadowSet(pe->index, PRS_LU_L2, "etype-ipv4-opt");
mvPp2PrsShadowUdfSet(pe->index, PRS_UDF_L2_DEF);
mvPp2PrsShadowFinSet(pe->index, MV_FALSE);
mvPp2PrsShadowRiSet(pe->index, RI_L3_IP4_OPT, RI_L3_PROTO_MASK);
mvPp2PrsSwFree(pe);
return MV_OK;
}
static int mvPp2PrsEtypeArp(void)
{
int tid;
MV_PP2_PRS_ENTRY *pe;
/* Go through the all entires from first to last */
tid = mvPp2PrsTcamFirstFree(0, MV_PP2_PRS_TCAM_SIZE - 1);
/* Can't add - No free TCAM entries */
if (tid == MV_PRS_OUT_OF_RAGE) {
mvOsPrintf("%s: No free TCAM entiry\n", __func__);
return MV_ERROR;
}
pe = mvPp2PrsSwAlloc(PRS_LU_L2);
pe->index = tid;
mvPp2PrsMatchEtype(pe, 0, MV_IP_ARP_TYPE);
/* generate flow in the next iteration*/
/*mvPp2PrsSwSramAiSetBit(pe, AI_DONE_BIT);*/
mvPp2PrsSwSramNextLuSet(pe, PRS_LU_FLOWS);
mvPp2PrsSwSramFlowidGenSet(pe);
mvPp2PrsSwSramRiUpdate(pe, RI_L3_ARP, RI_L3_PROTO_MASK);
/* set L3 offset */
mvPp2PrsSwSramOffsetSet(pe, SRAM_OFFSET_TYPE_L3, MV_ETH_TYPE_LEN, SRAM_OP_SEL_OFFSET_ADD);
mvPp2PrsHwWrite(pe);
mvPp2PrsShadowSet(pe->index, PRS_LU_L2, "etype-arp");
mvPp2PrsShadowUdfSet(pe->index, PRS_UDF_L2_DEF);
mvPp2PrsShadowFinSet(pe->index, MV_TRUE);
mvPp2PrsShadowRiSet(pe->index, RI_L3_ARP, RI_L3_PROTO_MASK);
mvPp2PrsSwFree(pe);
return MV_OK;
}
static int mvPp2PrsEtypeLbdt(void)
{
int tid;
MV_PP2_PRS_ENTRY *pe;
/* Go through the all entires from first to last */
tid = mvPp2PrsTcamFirstFree(0, MV_PP2_PRS_TCAM_SIZE - 1);
/* Can't add - No free TCAM entries */
if (tid == MV_PRS_OUT_OF_RAGE) {
mvOsPrintf("%s: No free TCAM entiry\n", __func__);
return MV_ERROR;
}
pe = mvPp2PrsSwAlloc(PRS_LU_L2);
pe->index = tid;
mvPp2PrsMatchEtype(pe, 0, MV_IP_LBDT_TYPE);
/* generate flow in the next iteration*/
/*mvPp2PrsSwSramAiSetBit(pe, AI_DONE_BIT);*/
mvPp2PrsSwSramNextLuSet(pe, PRS_LU_FLOWS);
mvPp2PrsSwSramFlowidGenSet(pe);
mvPp2PrsSwSramRiUpdate(pe, RI_CPU_CODE_RX_SPEC | RI_UDF3_RX_SPECIAL, RI_CPU_CODE_MASK | RI_UDF3_MASK);
/* set L3 offset */
mvPp2PrsSwSramOffsetSet(pe, SRAM_OFFSET_TYPE_L3, MV_ETH_TYPE_LEN, SRAM_OP_SEL_OFFSET_ADD);
mvPp2PrsHwWrite(pe);
mvPp2PrsShadowSet(pe->index, PRS_LU_L2, "etype-lbdt");
mvPp2PrsShadowUdfSet(pe->index, PRS_UDF_L2_DEF);
mvPp2PrsShadowFinSet(pe->index, MV_TRUE);
mvPp2PrsShadowRiSet(pe->index, RI_CPU_CODE_RX_SPEC | RI_UDF3_RX_SPECIAL, RI_CPU_CODE_MASK | RI_UDF3_MASK);
mvPp2PrsSwFree(pe);
return MV_OK;
}
/* match ip6 */
static int mvPp2PrsEtypeIp6(void)
{
int tid;
MV_PP2_PRS_ENTRY *pe;
/* Go through the all entires from first to last */
tid = mvPp2PrsTcamFirstFree(0, MV_PP2_PRS_TCAM_SIZE - 1);
/* Can't add - No free TCAM entries */
if (tid == MV_PRS_OUT_OF_RAGE) {
mvOsPrintf("%s: No free TCAM entiry\n", __func__);
return MV_ERROR;
}
pe = mvPp2PrsSwAlloc(PRS_LU_L2);
pe->index = tid;
mvPp2PrsMatchEtype(pe, 0, MV_IP6_TYPE);
/* Skip DIP of IPV6 header */
mvPp2PrsSwSramShiftSet(pe, MV_ETH_TYPE_LEN + 8 + MV_MAX_L3_ADDR_SIZE, SRAM_OP_SEL_SHIFT_ADD);
mvPp2PrsSwSramNextLuSet(pe, PRS_LU_IP6);
/*
there is no support in extension yet
*/
mvPp2PrsSwSramRiUpdate(pe, RI_L3_IP6, RI_L3_PROTO_MASK);
/* set L3 offset */
mvPp2PrsSwSramOffsetSet(pe, SRAM_OFFSET_TYPE_L3, MV_ETH_TYPE_LEN, SRAM_OP_SEL_OFFSET_ADD);
mvPp2PrsHwWrite(pe);
mvPp2PrsShadowSet(pe->index, PRS_LU_L2, "etype-ipv6");
mvPp2PrsShadowUdfSet(pe->index, PRS_UDF_L2_DEF);
mvPp2PrsShadowFinSet(pe->index, MV_FALSE);
mvPp2PrsShadowRiSet(pe->index, RI_L3_IP6, RI_L3_PROTO_MASK);
mvPp2PrsSwFree(pe);
return MV_OK;
}
/* unknown ethertype */
static int mvPp2PrsEtypeUn(void)
{
MV_PP2_PRS_ENTRY *pe;
/* Default entry for PRS_LU_L2 - Unknown ethtype */
pe = mvPp2PrsSwAlloc(PRS_LU_L2);
pe->index = PE_ETH_TYPE_UN;
/* generate flow in the next iteration*/
mvPp2PrsSwSramFlowidGenSet(pe);
mvPp2PrsSwSramNextLuSet(pe, PRS_LU_FLOWS);
/* Set result info bits */
mvPp2PrsSwSramRiUpdate(pe, RI_L3_UN, RI_L3_PROTO_MASK);
mvPp2PrsSwTcamPortMapSet(pe, PORT_MASK);
/* set L3 offset even it's unknown L3 */
mvPp2PrsSwSramOffsetSet(pe, SRAM_OFFSET_TYPE_L3, MV_ETH_TYPE_LEN, SRAM_OP_SEL_OFFSET_ADD);
mvPp2PrsHwWrite(pe);
/* Update mvPrsShadowTbl */
mvPp2PrsShadowSet(pe->index, PRS_LU_L2, "etype-unknown");
mvPp2PrsShadowUdfSet(pe->index, PRS_UDF_L2_DEF);
mvPp2PrsShadowFinSet(pe->index, MV_TRUE);
mvPp2PrsShadowRiSet(pe->index, RI_L3_UN, RI_L3_PROTO_MASK);
mvPp2PrsSwFree(pe);
return MV_OK;
}
/*
* pnc_etype_init - match basic ethertypes
*/
static int mvPp2PrsEtypeInit(void)
{
int rc;
PRS_DBG("%s\n", __func__);
rc = mvPp2PrsEtypePppoe();
if (rc)
return rc;
rc = mvPp2PrsEtypeArp();
if (rc)
return rc;
rc = mvPp2PrsEtypeLbdt();
if (rc)
return rc;
rc = mvPp2PrsEtypeIp4();
if (rc)
return rc;
rc = mvPp2PrsEtypeIp6();
if (rc)
return rc;
rc = mvPp2PrsEtypeUn();
if (rc)
return rc;
return MV_OK;
}
/******************************************************************************
*
* PPPoE Section
*
******************************************************************************
*/
static int mvPp2PrsIpv6Pppoe(void)
{
int tid;
MV_PP2_PRS_ENTRY *pe;
PRS_DBG("%s\n", __func__);
/* Go through the all entires from first to last */
tid = mvPp2PrsTcamFirstFree(0, MV_PP2_PRS_TCAM_SIZE - 1);
/* Can't add - No free TCAM entries */
if (tid == MV_PRS_OUT_OF_RAGE) {
mvOsPrintf("%s: No free TCAM entiry\n", __func__);
return MV_ERROR;
}
pe = mvPp2PrsSwAlloc(PRS_LU_PPPOE);
pe->index = tid;
mvPp2PrsMatchEtype(pe, 0, MV_IP6_PPP);
/* there is no support in extension yet */
mvPp2PrsSwSramRiUpdate(pe, RI_L3_IP6, RI_L3_PROTO_MASK);
/* Skip DIP of IPV6 header */
mvPp2PrsSwSramShiftSet(pe, MV_ETH_TYPE_LEN + 8 + MV_MAX_L3_ADDR_SIZE, SRAM_OP_SEL_SHIFT_ADD);
/* set L3 offset */
mvPp2PrsSwSramOffsetSet(pe, SRAM_OFFSET_TYPE_L3, MV_ETH_TYPE_LEN, SRAM_OP_SEL_OFFSET_ADD);
mvPp2PrsSwSramNextLuSet(pe, PRS_LU_IP6);
mvPp2PrsHwWrite(pe);
/* Update mvPrsShadowTbl */
mvPp2PrsShadowSet(pe->index, PRS_LU_PPPOE, "Ipv6-over-PPPoE");
mvPp2PrsSwFree(pe);
return MV_OK;
}
static int mvPp2PrsIpv4Pppoe(void)
{
int tid;
MV_PP2_PRS_ENTRY *pe;
PRS_DBG("%s\n", __func__);
/** ipV4 over PPPoE without options **/
/* Go through the all entires from first to last */
tid = mvPp2PrsTcamFirstFree(0, MV_PP2_PRS_TCAM_SIZE - 1);
/* Can't add - No free TCAM entries */
if (tid == MV_PRS_OUT_OF_RAGE) {
mvOsPrintf("%s: No free TCAM entiry\n", __func__);
return MV_ERROR;
}
pe = mvPp2PrsSwAlloc(PRS_LU_PPPOE);
pe->index = tid;
mvPp2PrsMatchEtype(pe, 0, MV_IP_PPP);
mvPp2PrsSwTcamByteSet(pe, MV_ETH_TYPE_LEN + 0, 0x45, 0xff);
mvPp2PrsSwSramRiUpdate(pe, RI_L3_IP4, RI_L3_PROTO_MASK);
/* Skip eth_type + 4 bytes of IP header */
mvPp2PrsSwSramShiftSet(pe, MV_ETH_TYPE_LEN + 4, SRAM_OP_SEL_SHIFT_ADD);
/* set L3 offset */
mvPp2PrsSwSramOffsetSet(pe, SRAM_OFFSET_TYPE_L3, MV_ETH_TYPE_LEN, SRAM_OP_SEL_OFFSET_ADD);
mvPp2PrsSwSramNextLuSet(pe, PRS_LU_IP4);
mvPp2PrsHwWrite(pe);
/* Update mvPrsShadowTbl */
mvPp2PrsShadowSet(pe->index, PRS_LU_PPPOE, "Ipv4-over-PPPoE");
mvPp2PrsSwFree(pe);
/** ipV4 over PPPoE with options **/
/* Go through the all entires from first to last */
tid = mvPp2PrsTcamFirstFree(0, MV_PP2_PRS_TCAM_SIZE - 1);
/* Can't add - No free TCAM entries */
if (tid == MV_PRS_OUT_OF_RAGE) {
mvOsPrintf("%s: No free TCAM entiry\n", __func__);
return MV_ERROR;
}
pe = mvPp2PrsSwAlloc(PRS_LU_PPPOE);
pe->index = tid;
mvPp2PrsMatchEtype(pe, 0, MV_IP_PPP);
mvPp2PrsSwSramRiUpdate(pe, RI_L3_IP4_OPT, RI_L3_PROTO_MASK);
/* Skip eth_type + 4 bytes of IP header */
mvPp2PrsSwSramShiftSet(pe, MV_ETH_TYPE_LEN + 4, SRAM_OP_SEL_SHIFT_ADD);
/* set L3 offset */
mvPp2PrsSwSramOffsetSet(pe, SRAM_OFFSET_TYPE_L3, MV_ETH_TYPE_LEN, SRAM_OP_SEL_OFFSET_ADD);
mvPp2PrsSwSramNextLuSet(pe, PRS_LU_IP4);
mvPp2PrsHwWrite(pe);
/* Update mvPrsShadowTbl */
mvPp2PrsShadowSet(pe->index, PRS_LU_PPPOE, "Ipv4-over-PPPoE-opt");
mvPp2PrsSwFree(pe);
return MV_OK;
}
/* Create entry for non-ip over PPPoE (for PPP LCP, IPCPv4, IPCPv6, etc) */
static int mvPp2PrsNonipPppoe(void)
{
int ret;
int tid;
MV_PP2_PRS_ENTRY *pe;
PRS_DBG("%s\n", __func__);
/** non-Ip over PPPoE **/
/* Go through the all entires from first to last */
tid = mvPp2PrsTcamFirstFree(0, MV_PP2_PRS_TCAM_SIZE - 1);
/* Can't add - No free TCAM entries */
if (tid == MV_PRS_OUT_OF_RAGE) {
mvOsPrintf("%s: No free TCAM entiry\n", __func__);
return MV_ERROR;
}
pe = mvPp2PrsSwAlloc(PRS_LU_PPPOE);
PTR_VALIDATE(pe);
pe->index = tid;
ret = mvPp2PrsSwSramRiUpdate(pe, RI_L3_UN, RI_L3_PROTO_MASK);
RET_VALIDATE(ret);
ret = mvPp2PrsSwSramFlowidGenSet(pe);
RET_VALIDATE(ret);
/* set L3 offset even it's unknown L3 */
ret = mvPp2PrsSwSramOffsetSet(pe, SRAM_OFFSET_TYPE_L3, MV_ETH_TYPE_LEN, SRAM_OP_SEL_OFFSET_ADD);
RET_VALIDATE(ret);
ret = mvPp2PrsSwSramNextLuSet(pe, PRS_LU_FLOWS);
RET_VALIDATE(ret);
ret = mvPp2PrsHwWrite(pe);
RET_VALIDATE(ret);
/* Update mvPrsShadowTbl */
mvPp2PrsShadowSet(pe->index, PRS_LU_PPPOE, "NonIP-over-PPPoE");
mvPp2PrsSwFree(pe);
return MV_OK;
}
/* match etype = PPPOE */
static int mvPp2PrsPppeInit(void)
{
int rc;
rc = mvPp2PrsIpv4Pppoe();
if (rc)
return rc;
rc = mvPp2PrsIpv6Pppoe();
if (rc)
return rc;
rc = mvPp2PrsNonipPppoe();
if (rc)
return rc;
return MV_OK;
}
/******************************************************************************
*
* IPv4 Section
*
******************************************************************************
*/
/* IPv4/TCP header parsing for fragmentation and L4 offset. */
static int mvPp2PrsIp4Proto(unsigned short proto, unsigned int ri, unsigned int riMask)
{
int tid;
MV_PP2_PRS_ENTRY *pe;
PRS_DBG("%s\n", __func__);
/* TCP, Not Fragmented */
tid = mvPp2PrsTcamFirstFree(0, MV_PP2_PRS_TCAM_SIZE - 1);
if (tid == MV_PRS_OUT_OF_RAGE) {
mvOsPrintf("%s: No free TCAM entiry\n", __func__);
return MV_ERROR;
}
pe = mvPp2PrsSwAlloc(PRS_LU_IP4);
pe->index = tid;
mvPp2PrsSwTcamByteSet(pe, 2, 0x00, 0x3f);
mvPp2PrsSwTcamByteSet(pe, 3, 0x00, 0xff);
mvPp2PrsSwTcamPortMapSet(pe, PORT_MASK);
mvPp2PrsSwTcamByteSet(pe, 5, proto, 0xff);
if (proto == MV_IP_PROTO_TCP) {
mvPp2PrsSwSramRiUpdate(pe, ri, riMask);
mvPp2PrsShadowSet(pe->index, PRS_LU_IP4, "ipv4-tcp");
} else if (proto == MV_IP_PROTO_UDP) {
mvPp2PrsSwSramRiUpdate(pe, ri, riMask);
mvPp2PrsShadowSet(pe->index, PRS_LU_IP4, "ipv4-udp");
} else if (proto == MV_IP_PROTO_IGMP) {
mvPp2PrsSwSramRiUpdate(pe, ri, riMask);
mvPp2PrsShadowSet(pe->index, PRS_LU_IP4, "ipv4-igmp");
} else {
mvOsPrintf("%s: IPv4 unsupported protocol %d\n", __func__, proto);
mvPp2PrsSwFree(pe);
return MV_ERROR;
}
/* set L4 offset */
mvPp2PrsSwSramOffsetSet(pe, SRAM_OFFSET_TYPE_L4, sizeof(MV_IP_HEADER) - 4, SRAM_OP_SEL_OFFSET_ADD);
mvPp2PrsSwSramShiftSet(pe, 12, SRAM_OP_SEL_SHIFT_ADD);
/* Next: go to IPV4 */
mvPp2PrsSwSramNextLuSet(pe, PRS_LU_IP4);
/* Set sram AIbits */
mvPp2PrsSwSramAiUpdate(pe, (1 << IPV4_DIP_AI_BIT), (1 << IPV4_DIP_AI_BIT));
mvPp2PrsSwTcamPortMapSet(pe, PORT_MASK);
/* AI bits check */
mvPp2PrsSwTcamAiUpdate(pe, 0, (1 << IPV4_DIP_AI_BIT));
mvPp2PrsHwWrite(pe);
mvPp2PrsSwFree(pe);
/* TCP, Fragmented */
tid = mvPp2PrsTcamFirstFree(0, MV_PP2_PRS_TCAM_SIZE - 1);
if (tid == MV_PRS_OUT_OF_RAGE) {
mvOsPrintf("%s: No free TCAM entiry\n", __func__);
return MV_ERROR;
}
pe = mvPp2PrsSwAlloc(PRS_LU_IP4);
pe->index = tid;
mvPp2PrsSwTcamByteSet(pe, 5, proto, 0xff);
mvPp2PrsSwSramRiSetBit(pe, RI_IP_FRAG_BIT);
if (proto == MV_IP_PROTO_TCP) {
mvPp2PrsSwSramRiUpdate(pe, ri, riMask);
mvPp2PrsShadowSet(pe->index, PRS_LU_IP4, "ipv4-tcp-frag");
} else if (proto == MV_IP_PROTO_UDP) {
mvPp2PrsSwSramRiUpdate(pe, ri, riMask);
mvPp2PrsShadowSet(pe->index, PRS_LU_IP4, "ipv4-udp-frag");
} else if (proto == MV_IP_PROTO_IGMP) {
mvPp2PrsSwSramRiUpdate(pe, ri, riMask);
mvPp2PrsShadowSet(pe->index, PRS_LU_IP4, "ipv4-igmp-frag");
} else {
mvOsPrintf("%s: IPv4 unsupported protocol %d\n", __func__, proto);
mvPp2PrsSwFree(pe);
return MV_ERROR;
}
/* set L4 offset */
mvPp2PrsSwSramOffsetSet(pe, SRAM_OFFSET_TYPE_L4, sizeof(MV_IP_HEADER) - 4, SRAM_OP_SEL_OFFSET_ADD);
mvPp2PrsSwSramShiftSet(pe, 12, SRAM_OP_SEL_SHIFT_ADD);
/* Next: go to IPV4 */
mvPp2PrsSwSramNextLuSet(pe, PRS_LU_IP4);
/* Set sram AIbits */
mvPp2PrsSwSramAiUpdate(pe, (1 << IPV4_DIP_AI_BIT), (1 << IPV4_DIP_AI_BIT));
mvPp2PrsSwTcamPortMapSet(pe, PORT_MASK);
/* AI bits check */
mvPp2PrsSwTcamAiUpdate(pe, 0, (1 << IPV4_DIP_AI_BIT));
mvPp2PrsHwWrite(pe);
mvPp2PrsSwFree(pe);
return MV_OK;
}
/* IPv4 L3 Multicast or borad cast. 1-MC, 2-BC */
static int mvPp2PrsIp4Cast(unsigned short l3_cast)
{
int tid;
MV_PP2_PRS_ENTRY *pe;
PRS_DBG("%s\n", __func__);
if (l3_cast != L3_MULTI_CAST &&
l3_cast != L3_BROAD_CAST) {
mvOsPrintf("%s: Invalid Input\n", __func__);
return MV_ERROR;
}
/* Get free entry */
tid = mvPp2PrsTcamFirstFree(0, MV_PP2_PRS_TCAM_SIZE - 1);
if (tid == MV_PRS_OUT_OF_RAGE) {
mvOsPrintf("%s: No free TCAM entiry\n", __func__);
return MV_ERROR;
}
pe = mvPp2PrsSwAlloc(PRS_LU_IP4);
pe->index = tid;
if (l3_cast == L3_MULTI_CAST) {
mvPp2PrsSwTcamByteSet(pe, 0, 0xE0, 0xE0);
mvPp2PrsSwSramRiUpdate(pe, RI_L3_MCAST, RI_L3_ADDR_MASK);
mvPp2PrsShadowSet(pe->index, PRS_LU_IP4, "ipv4-mc");
} else if (l3_cast == L3_BROAD_CAST) {
mvPp2PrsSwTcamByteSet(pe, 0, 0xFF, 0xFF);
mvPp2PrsSwTcamByteSet(pe, 1, 0xFF, 0xFF);
mvPp2PrsSwTcamByteSet(pe, 2, 0xFF, 0xFF);
mvPp2PrsSwTcamByteSet(pe, 3, 0xFF, 0xFF);
mvPp2PrsSwSramRiUpdate(pe, RI_L3_BCAST, RI_L3_ADDR_MASK);
mvPp2PrsShadowSet(pe->index, PRS_LU_IP4, "ipv4-bc");
}
mvPp2PrsSwTcamAiUpdate(pe, (1 << IPV4_DIP_AI_BIT), (1 << IPV4_DIP_AI_BIT));
mvPp2PrsSwTcamPortMapSet(pe, PORT_MASK);
/* Finished: go to flowid generation */
mvPp2PrsSwSramFlowidGenSet(pe);
mvPp2PrsSwSramNextLuSet(pe, PRS_LU_FLOWS);
mvPp2PrsSwTcamPortMapSet(pe, PORT_MASK);
mvPp2PrsHwWrite(pe);
mvPp2PrsSwFree(pe);
return MV_OK;
}
static int mvPp2PrsIp4Init(void)
{
int rc;
MV_PP2_PRS_ENTRY *pe;
PRS_DBG("%s\n", __func__);
/* Set entries for TCP, UDP and IGMP over IPv4 */
rc = mvPp2PrsIp4Proto(MV_IP_PROTO_TCP, RI_L4_TCP, RI_L4_PROTO_MASK);
if (rc)
return rc;
rc = mvPp2PrsIp4Proto(MV_IP_PROTO_UDP, RI_L4_UDP, RI_L4_PROTO_MASK);
if (rc)
return rc;
/* IPv4 Broadcast */
rc = mvPp2PrsIp4Cast(L3_BROAD_CAST);
if (rc)
return rc;
/* IPv4 Multicast */
rc = mvPp2PrsIp4Cast(L3_MULTI_CAST);
if (rc)
return rc;
rc = mvPp2PrsIp4Proto(MV_IP_PROTO_IGMP, RI_CPU_CODE_RX_SPEC | RI_UDF3_RX_SPECIAL, RI_CPU_CODE_MASK | RI_UDF3_MASK);
if (rc)
return rc;
/* Default IPv4 entry for unknown protocols */
pe = mvPp2PrsSwAlloc(PRS_LU_IP4);
pe->index = PE_IP4_PROTO_UN;
/* Next: go to IPV4 */
mvPp2PrsSwSramNextLuSet(pe, PRS_LU_IP4);
/* Set sram AIbits */
mvPp2PrsSwSramAiUpdate(pe, (1 << IPV4_DIP_AI_BIT), (1 << IPV4_DIP_AI_BIT));
/* Set result info bits */
mvPp2PrsSwSramRiUpdate(pe, RI_L4_OTHER, RI_L4_PROTO_MASK);
mvPp2PrsSwSramOffsetSet(pe, SRAM_OFFSET_TYPE_L4, sizeof(MV_IP_HEADER) - 4, SRAM_OP_SEL_OFFSET_ADD);
mvPp2PrsSwSramShiftSet(pe, 12, SRAM_OP_SEL_SHIFT_ADD);
mvPp2PrsSwTcamPortMapSet(pe, PORT_MASK);
/* AI bits check */
mvPp2PrsSwTcamAiUpdate(pe, 0, (1 << IPV4_DIP_AI_BIT));
mvPp2PrsHwWrite(pe);
/* Update mvPrsShadowTbl */
mvPp2PrsShadowSet(pe->index, PRS_LU_IP4, "ipv4-l4-unknown");
mvPp2PrsSwFree(pe);
/* Default IPv4 entry for unit cast address */
pe = mvPp2PrsSwAlloc(PRS_LU_IP4);
pe->index = PE_IP4_ADDR_UN;
mvPp2PrsSwTcamAiUpdate(pe, (1 << IPV4_DIP_AI_BIT), (1 << IPV4_DIP_AI_BIT));
mvPp2PrsSwTcamPortMapSet(pe, PORT_MASK);
mvPp2PrsSwSramRiUpdate(pe, RI_L3_UCAST, RI_L3_ADDR_MASK);
mvPp2PrsShadowSet(pe->index, PRS_LU_IP4, "ipv4-uc");
/* Finished: go to flowid generation */
mvPp2PrsSwSramFlowidGenSet(pe);
mvPp2PrsSwSramNextLuSet(pe, PRS_LU_FLOWS);
mvPp2PrsSwTcamPortMapSet(pe, PORT_MASK);
mvPp2PrsHwWrite(pe);
mvPp2PrsSwFree(pe);
return MV_OK;
}
/******************************************************************************
*
* IPv6 Section
*
*******************************************************************************/
/* TODO continue from here */
/* IPv6 - detect TCP */
static int mvPp2PrsIp6Proto(unsigned short proto, unsigned int ri, unsigned int riMask, MV_BOOL ip6_ext)
{
int tid;
MV_PP2_PRS_ENTRY *pe;
PRS_DBG("%s\n", __func__);
/* TCP, Not Fragmented */
tid = mvPp2PrsTcamFirstFree(0, MV_PP2_PRS_TCAM_SIZE - 1);
if (tid == MV_PRS_OUT_OF_RAGE) {
mvOsPrintf("%s: No free TCAM entiry\n", __func__);
return MV_ERROR;
}
pe = mvPp2PrsSwAlloc(PRS_LU_IP6);
pe->index = tid;
/* Match Protocol */
mvPp2PrsSwTcamByteSet(pe, 0, proto, 0xff);
/* Set Rule Shadow */
switch (proto) {
/* TCP */
case MV_IP_PROTO_TCP:
mvPp2PrsShadowSet(pe->index, PRS_LU_IP6, (MV_FALSE == ip6_ext) ? "ipv6-tcp" : "ipv6-ext-tcp");
break;
/* UDP */
case MV_IP_PROTO_UDP:
mvPp2PrsShadowSet(pe->index, PRS_LU_IP6, (MV_FALSE == ip6_ext) ? "ipv6-udp" : "ipv6-ext-udp");
break;
/* ICMP */
case MV_IP_PROTO_ICMPV6:
mvPp2PrsShadowSet(pe->index, PRS_LU_IP6, (MV_FALSE == ip6_ext) ? "ipv6-icmp" : "ipv6-ext-icmp");
break;
/* IPv4, for IPv6 DS Lite */
case MV_IP_PROTO_IPIP:
if (ip6_ext != MV_FALSE) {
mvOsPrintf("%s: IPv4 header not a IP6 extension header\n", __func__);
mvPp2PrsSwFree(pe);
return MV_ERROR;
}
mvPp2PrsShadowSet(pe->index, PRS_LU_IP6, "ipv6-lite-ip4");
break;
/* IPV6 Extension Header */
/* Hop-by-Hop Options Header, Dummy protocol for TCP */
case MV_IP_PROTO_NULL:
mvPp2PrsShadowSet(pe->index, PRS_LU_IP6, (MV_FALSE == ip6_ext) ? "ipv6-nh-hh" : "ipv6-ext-nh-hh");
break;
/* Encapsulated IPv6 Header, IPv6-in-IPv4 tunnelling */
case MV_IP_PROTO_IPV6:
mvPp2PrsShadowSet(pe->index, PRS_LU_IP6, (MV_FALSE == ip6_ext) ? "ipv6-nh-eh" : "ipv6-ext-nh-eh");
break;
/* Route header */
case MV_IP_PROTO_RH:
mvPp2PrsShadowSet(pe->index, PRS_LU_IP6, (MV_FALSE == ip6_ext) ? "ipv6-nh-rh" : "ipv6-ext-nh-rh");
break;
/* Fragment Header */
case MV_IP_PROTO_FH:
mvPp2PrsShadowSet(pe->index, PRS_LU_IP6, (MV_FALSE == ip6_ext) ? "ipv6-nh-fh" : "ipv6-ext-nh-fh");
break;
#if 0
/* Encapsulation Security Payload protocol */
case MV_IP_PROTO_ESP:
mvPp2PrsShadowSet(pe->index, PRS_LU_IP6, (MV_FALSE == ip6_ext) ? "ipv6-nh-esp" : "ipv6-ext-nh-esp");
break;
#endif
/* Authentication Header */
case MV_IP_PROTO_AH:
mvPp2PrsShadowSet(pe->index, PRS_LU_IP6, (MV_FALSE == ip6_ext) ? "ipv6-nh-ah" : "ipv6-ext-nh-ah");
break;
/* Destination Options Header */
case MV_IP_PROTO_DH:
mvPp2PrsShadowSet(pe->index, PRS_LU_IP6, (MV_FALSE == ip6_ext) ? "ipv6-nh-dh" : "ipv6-ext-nh-dh");
break;
/* Mobility Header */
case MV_IP_PROTO_MH:
mvPp2PrsShadowSet(pe->index, PRS_LU_IP6, (MV_FALSE == ip6_ext) ? "ipv6-nh-mh" : "ipv6-ext-nh-mh");
break;
default:
mvOsPrintf("%s: IPv6 unsupported protocol %d\n", __func__, proto);
mvPp2PrsSwFree(pe);
return MV_ERROR;
}
/* Set TCAM and SRAM for TCP, UDP and IGMP */
if (proto == MV_IP_PROTO_TCP ||
proto == MV_IP_PROTO_UDP ||
proto == MV_IP_PROTO_ICMPV6 ||
proto == MV_IP_PROTO_IPIP) {
/* Set TCAM AI */
if (MV_FALSE == ip6_ext)
mvPp2PrsSwTcamAiUpdate(pe, (1 << IPV6_NO_EXT_AI_BIT), (1 << IPV6_NO_EXT_AI_BIT));
else
mvPp2PrsSwTcamAiUpdate(pe, (1 << IPV6_EXT_AI_BIT), (1 << IPV6_EXT_AI_BIT));
/* Set result info */
mvPp2PrsSwSramRiUpdate(pe, ri, riMask);
/* set L4 offset relatively to our current place */
if (MV_FALSE == ip6_ext)
mvPp2PrsSwSramOffsetSet(pe, SRAM_OFFSET_TYPE_L4, sizeof(MV_IP6_HEADER) - 6, SRAM_OP_SEL_OFFSET_ADD);
else
mvPp2PrsSwSramOffsetSet(pe, SRAM_OFFSET_TYPE_L4, 0, SRAM_OP_SEL_OFFSET_IP6_ADD);
/* Finished: go to LU Generation */
mvPp2PrsSwSramFlowidGenSet(pe);
mvPp2PrsSwSramNextLuSet(pe, PRS_LU_FLOWS);
} else { /* Set TCAM and SRAM for IPV6 Extension Header */
if (MV_FALSE == ip6_ext) { /* Case 1: xx is first NH of IPv6 */
/* Skip to NH */
mvPp2PrsSwSramShiftSet(pe, 34, SRAM_OP_SEL_SHIFT_ADD);
/* Set AI bit */
mvPp2PrsSwTcamAiUpdate(pe, (1 << IPV6_NO_EXT_AI_BIT), (1 << IPV6_NO_EXT_AI_BIT));
/* update UDF2 */
mvPp2PrsSwSramOffsetSet(pe, SRAM_OFFSET_TYPE_IPV6_PROTO, 0, SRAM_OP_SEL_SHIFT_ADD);
} else { /* Case 2: xx is not first NH of IPv6 */
/* Skip to NH */
mvPp2PrsSwSramShiftSet(pe, 0, SRAM_OP_SEL_SHIFT_IP6_ADD);
/* Set AI bit */
mvPp2PrsSwTcamAiUpdate(pe, (1 << IPV6_EXT_AI_BIT), (1 << IPV6_EXT_AI_BIT));
/* update UDF2 */
mvPp2PrsSwSramOffsetSet(pe, SRAM_OFFSET_TYPE_IPV6_PROTO, 0, SRAM_OP_SEL_SHIFT_IP6_ADD);
}
/* Next LU */
mvPp2PrsSwSramNextLuSet(pe, PRS_LU_IP6);
/* Set sram AIbits */
if (proto == MV_IP_PROTO_AH) {
mvPp2PrsSwSramAiUpdate(pe, (1 << IPV6_EXT_AH_AI_BIT), (1 << IPV6_EXT_AH_AI_BIT));
mvPp2PrsSwSramAiUpdate(pe, 0, (1 << IPV6_EXT_AI_BIT));
mvPp2PrsSwSramAiUpdate(pe, 0, (1 << IPV6_NO_EXT_AI_BIT));
} else {
mvPp2PrsSwSramAiUpdate(pe, 0, (1 << IPV6_EXT_AH_AI_BIT));
mvPp2PrsSwSramAiUpdate(pe, (1 << IPV6_EXT_AI_BIT), (1 << IPV6_EXT_AI_BIT));
mvPp2PrsSwSramAiUpdate(pe, 0, (1 << IPV6_NO_EXT_AI_BIT));
}
/* Set RI, IPv6 Ext */
mvPp2PrsSwSramRiUpdate(pe, RI_L3_IP6_EXT, RI_L3_PROTO_MASK);
}
/* All ports */
mvPp2PrsSwTcamPortMapSet(pe, PORT_MASK);
/* Write HW */
mvPp2PrsHwWrite(pe);
/* Release SW entry */
mvPp2PrsSwFree(pe);
return MV_OK;
}
/* Parse the extension header on AH */
static int mvPp2PrsIp6ProtoAh(unsigned short proto, unsigned int ri, unsigned int riMask)
{
int tid;
MV_PP2_PRS_ENTRY *pe;
PRS_DBG("%s\n", __func__);
/* TCP, Not Fragmented */
tid = mvPp2PrsTcamFirstFree(0, MV_PP2_PRS_TCAM_SIZE - 1);
if (tid == MV_PRS_OUT_OF_RAGE) {
mvOsPrintf("%s: No free TCAM entiry\n", __func__);
return MV_ERROR;
}
pe = mvPp2PrsSwAlloc(PRS_LU_IP6);
pe->index = tid;
/* Match Protocol */
mvPp2PrsSwTcamByteSet(pe, 0, proto, 0xff);
/* Set Rule Shadow */
switch (proto) {
/* TCP */
case MV_IP_PROTO_TCP:
mvPp2PrsShadowSet(pe->index, PRS_LU_IP6, "ipv6-ah-tcp");
break;
/* UDP */
case MV_IP_PROTO_UDP:
mvPp2PrsShadowSet(pe->index, PRS_LU_IP6, "ipv6-ah-udp");
break;
/* ICMP */
case MV_IP_PROTO_ICMPV6:
mvPp2PrsShadowSet(pe->index, PRS_LU_IP6, "ipv6-ah-icmp");
break;
/* IPV6 Extension Header */
/* Hop-by-Hop Options Header, Dummy protocol for TCP */
case MV_IP_PROTO_NULL:
mvPp2PrsShadowSet(pe->index, PRS_LU_IP6, "ipv6-ah-nh-hh");
break;
/* Encapsulated IPv6 Header, IPv6-in-IPv4 tunnelling */
case MV_IP_PROTO_IPV6:
mvPp2PrsShadowSet(pe->index, PRS_LU_IP6, "ipv6-ah-nh-eh");
break;
/* Route header */
case MV_IP_PROTO_RH:
mvPp2PrsShadowSet(pe->index, PRS_LU_IP6, "ipv6-ah-nh-rh");
break;
/* Fragment Header */
case MV_IP_PROTO_FH:
mvPp2PrsShadowSet(pe->index, PRS_LU_IP6, "ipv6-ah-nh-fh");
break;
/* Authentication Header */
case MV_IP_PROTO_AH:
mvPp2PrsShadowSet(pe->index, PRS_LU_IP6, "ipv6-ah-nh-ah");
break;
/* Destination Options Header */
case MV_IP_PROTO_DH:
mvPp2PrsShadowSet(pe->index, PRS_LU_IP6, "ipv6-ah-nh-dh");
break;
/* Mobility Header */
case MV_IP_PROTO_MH:
mvPp2PrsShadowSet(pe->index, PRS_LU_IP6, "ipv6-ah-nh-mh");
break;
default:
mvOsPrintf("%s: IPv6 unsupported extension header %d\n", __func__, proto);
mvPp2PrsSwFree(pe);
return MV_ERROR;
}
/* Set TCAM and SRAM for TCP, UDP and IGMP */
if (proto == MV_IP_PROTO_TCP ||
proto == MV_IP_PROTO_UDP ||
proto == MV_IP_PROTO_ICMPV6) {
/* Set result info */
mvPp2PrsSwSramRiUpdate(pe, ri, riMask);
/* Set sram AIbits */
mvPp2PrsSwSramAiUpdate(pe, (1 << IPV6_EXT_AH_L4_AI_BIT), (1 << IPV6_EXT_AH_L4_AI_BIT));
mvPp2PrsSwSramAiUpdate(pe, 0, (1 << IPV6_EXT_AH_LEN_AI_BIT));
mvPp2PrsSwSramAiUpdate(pe, 0, (1 << IPV6_EXT_AH_AI_BIT));
mvPp2PrsSwSramAiUpdate(pe, 0, (1 << IPV6_EXT_AI_BIT));
mvPp2PrsSwSramAiUpdate(pe, 0, (1 << IPV6_NO_EXT_AI_BIT));
} else {
/* Set sram AIbits */
mvPp2PrsSwSramAiUpdate(pe, 0, (1 << IPV6_EXT_AH_L4_AI_BIT));
mvPp2PrsSwSramAiUpdate(pe, (1 << IPV6_EXT_AH_LEN_AI_BIT), (1 << IPV6_EXT_AH_LEN_AI_BIT));
mvPp2PrsSwSramAiUpdate(pe, 0, (1 << IPV6_EXT_AH_AI_BIT));
mvPp2PrsSwSramAiUpdate(pe, 0, (1 << IPV6_EXT_AI_BIT));
mvPp2PrsSwSramAiUpdate(pe, 0, (1 << IPV6_NO_EXT_AI_BIT));
}
/* Set AI bit */
mvPp2PrsSwTcamAiUpdate(pe, (1 << IPV6_EXT_AH_AI_BIT), (1 << IPV6_EXT_AH_AI_BIT));
/* Next LU */
mvPp2PrsSwSramNextLuSet(pe, PRS_LU_IP6);
/* Set RI, IPv6 Ext */
mvPp2PrsSwSramRiUpdate(pe, RI_L3_IP6_EXT, RI_L3_PROTO_MASK);
/* All ports */
mvPp2PrsSwTcamPortMapSet(pe, PORT_MASK);
/* Write HW */
mvPp2PrsHwWrite(pe);
/* Release SW entry */
mvPp2PrsSwFree(pe);
return MV_OK;
}
/* Parse AH length field */
static int mvPp2PrsIp6AhLen(unsigned char ah_len, MV_BOOL l4_off_set)
{
int tid;
MV_PP2_PRS_ENTRY *pe;
char tmp_buf[15];
PRS_DBG("%s\n", __func__);
/* TCP, Not Fragmented */
tid = mvPp2PrsTcamFirstFree(0, MV_PP2_PRS_TCAM_SIZE - 1);
if (tid == MV_PRS_OUT_OF_RAGE) {
mvOsPrintf("%s: No free TCAM entiry\n", __func__);
return MV_ERROR;
}
pe = mvPp2PrsSwAlloc(PRS_LU_IP6);
pe->index = tid;
/* Match AH Len */
mvPp2PrsSwTcamByteSet(pe, 1, ah_len, 0xff);
/* Set Rule Shadow */
sprintf(tmp_buf, "ipv6-ah-len%d", ah_len);
mvPp2PrsShadowSet(pe->index, PRS_LU_IP6, tmp_buf);
/* Set AI bit */
if (l4_off_set) {
mvPp2PrsSwTcamAiUpdate(pe, (1 << IPV6_EXT_AH_L4_AI_BIT), (1 << IPV6_EXT_AH_L4_AI_BIT));
/* Set L4 offset */
mvPp2PrsSwSramOffsetSet(pe, SRAM_OFFSET_TYPE_L4,
(IPV6_EXT_EXCLUDE_BYTES + ah_len * IPV6_EXT_AH_UNIT_BYTES),
SRAM_OP_SEL_OFFSET_LKP_ADD);
/* Finished: go to LU Generation */
mvPp2PrsSwSramFlowidGenSet(pe);
mvPp2PrsSwSramNextLuSet(pe, PRS_LU_FLOWS);
} else {
mvPp2PrsSwTcamAiUpdate(pe, (1 << IPV6_EXT_AH_LEN_AI_BIT), (1 << IPV6_EXT_AH_LEN_AI_BIT));
/* Set sram AIbits */
mvPp2PrsSwSramAiUpdate(pe, 0, (1 << IPV6_EXT_AH_L4_AI_BIT));
mvPp2PrsSwSramAiUpdate(pe, 0, (1 << IPV6_EXT_AH_LEN_AI_BIT));
mvPp2PrsSwSramAiUpdate(pe, 0, (1 << IPV6_EXT_AH_AI_BIT));
mvPp2PrsSwSramAiUpdate(pe, (1 << IPV6_EXT_AI_BIT), (1 << IPV6_EXT_AI_BIT));
mvPp2PrsSwSramAiUpdate(pe, 0, (1 << IPV6_NO_EXT_AI_BIT));
/* Skip to NH */
mvPp2PrsSwSramShiftSet(pe, (IPV6_EXT_EXCLUDE_BYTES + ah_len * IPV6_EXT_AH_UNIT_BYTES), SRAM_OP_SEL_SHIFT_ADD);
/* Next LU */
mvPp2PrsSwSramNextLuSet(pe, PRS_LU_IP6);
}
/* All ports */
mvPp2PrsSwTcamPortMapSet(pe, PORT_MASK);
/* Write HW */
mvPp2PrsHwWrite(pe);
/* Release SW entry */
mvPp2PrsSwFree(pe);
return MV_OK;
}
/* IPv6 L3 Multicast or borad cast. 1-MC */
static int mvPp2PrsIp6Cast(unsigned short l3_cast)
{
int tid;
MV_PP2_PRS_ENTRY *pe;
PRS_DBG("%s\n", __func__);
if (l3_cast != L3_MULTI_CAST) {
mvOsPrintf("%s: Invalid Input\n", __func__);
return MV_ERROR;
}
/* Get free entry */
tid = mvPp2PrsTcamFirstFree(0, MV_PP2_PRS_TCAM_SIZE - 1);
if (tid == MV_PRS_OUT_OF_RAGE) {
mvOsPrintf("%s: No free TCAM entiry\n", __func__);
return MV_ERROR;
}
pe = mvPp2PrsSwAlloc(PRS_LU_IP6);
pe->index = tid;
mvPp2PrsSwTcamByteSet(pe, 0, 0xFF, 0xFF);
mvPp2PrsSwSramRiUpdate(pe, RI_L3_MCAST, RI_L3_ADDR_MASK);
mvPp2PrsShadowSet(pe->index, PRS_LU_IP6, "ipv6-mc");
mvPp2PrsSwTcamAiUpdate(pe, 0, (1 << IPV6_NO_EXT_AI_BIT));
mvPp2PrsSwTcamPortMapSet(pe, PORT_MASK);
/* Set sram AIbits */
mvPp2PrsSwSramAiUpdate(pe, (1 << IPV6_NO_EXT_AI_BIT), (1 << IPV6_NO_EXT_AI_BIT));
/* Shift back to IPV6 NH */
mvPp2PrsSwSramShiftSet(pe, -18, SRAM_OP_SEL_SHIFT_ADD);
/* Finished: go to flowid generation */
mvPp2PrsSwSramNextLuSet(pe, PRS_LU_IP6);
mvPp2PrsSwTcamPortMapSet(pe, PORT_MASK);
mvPp2PrsHwWrite(pe);
mvPp2PrsSwFree(pe);
return MV_OK;
}
static int mvPp2PrsIp6Init(void)
{
int tid, rc;
MV_PP2_PRS_ENTRY *pe;
PRS_DBG("%s\n", __func__);
pe = mvPp2PrsSwAlloc(PRS_LU_IP6);
/* Check hop limit */
tid = mvPp2PrsTcamFirstFree(0, MV_PP2_PRS_TCAM_SIZE - 1);
if (tid == MV_PRS_OUT_OF_RAGE) {
mvOsPrintf("%s: No free TCAM entiry\n", __func__);
mvPp2PrsSwFree(pe);
return MV_ERROR;
}
pe->index = tid;
mvPp2PrsSwTcamByteSet(pe, 1, 0x00, 0xff);
mvPp2PrsSwSramRiUpdate(pe, (RI_L3_UN | RI_DROP_BIT), (RI_L3_PROTO_MASK | RI_DROP_MASK));
mvPp2PrsSwSramFlowidGenSet(pe);
mvPp2PrsSwSramNextLuSet(pe, PRS_LU_FLOWS);
/* Update TCAM AI */
mvPp2PrsSwTcamAiUpdate(pe, (1 << IPV6_NO_EXT_AI_BIT), (1 << IPV6_NO_EXT_AI_BIT));
mvPp2PrsHwWrite(pe);
/* Update mvPrsShadowTbl */
mvPp2PrsShadowSet(pe->index, PRS_LU_IP4, "ipv6-hop-zero");
mvPp2PrsSwFree(pe);
/* Set entries for TCP and UDP over IPv6 */
rc = mvPp2PrsIp6Proto(MV_IP_PROTO_TCP,
RI_L4_TCP,
RI_L4_PROTO_MASK,
MV_FALSE);
if (rc)
return rc;
rc = mvPp2PrsIp6Proto(MV_IP_PROTO_UDP,
RI_L4_UDP,
RI_L4_PROTO_MASK,
MV_FALSE);
if (rc)
return rc;
/* IPv6 Multicast */
rc = mvPp2PrsIp6Cast(L3_MULTI_CAST);
if (rc)
return rc;
rc = mvPp2PrsIp6Proto(MV_IP_PROTO_ICMPV6,
RI_CPU_CODE_RX_SPEC | RI_UDF3_RX_SPECIAL, RI_CPU_CODE_MASK | RI_UDF3_MASK,
MV_FALSE);
if (rc)
return rc;
/* IPv4 is the last header. This is similar case as 6-TCP or 17-UDP */
/* Result Info: UDF7=1, DS lite */
rc = mvPp2PrsIp6Proto(MV_IP_PROTO_IPIP, RI_UDF7_IP6_LITE, RI_UDF7_MASK, MV_FALSE);
if (rc)
return rc;
/* Default IPv6 entry for unknown protocols */
pe = mvPp2PrsSwAlloc(PRS_LU_IP6);
pe->index = PE_IP6_PROTO_UN;
/* generate flow in the next iteration*/
mvPp2PrsSwSramFlowidGenSet(pe);
mvPp2PrsSwSramNextLuSet(pe, PRS_LU_FLOWS);
/* Set result info bits */
mvPp2PrsSwSramRiUpdate(pe, RI_L4_OTHER, RI_L4_PROTO_MASK);
/* set L4 offset relatively to our current place */
mvPp2PrsSwSramOffsetSet(pe, SRAM_OFFSET_TYPE_L4, sizeof(MV_IP6_HEADER) - 4, SRAM_OP_SEL_OFFSET_ADD);
mvPp2PrsSwTcamPortMapSet(pe, PORT_MASK);
/* AI bits check */
mvPp2PrsSwTcamAiUpdate(pe, (1 << IPV6_NO_EXT_AI_BIT), (1 << IPV6_NO_EXT_AI_BIT));
mvPp2PrsHwWrite(pe);
/* Update mvPrsShadowTbl */
mvPp2PrsShadowSet(pe->index, PRS_LU_IP4, "ipv6-l4-unknown");
mvPp2PrsSwFree(pe);
/* Default IPv6 entry for unknown Ext protocols */
pe = mvPp2PrsSwAlloc(PRS_LU_IP6);
pe->index = PE_IP6_EXT_PROTO_UN;
/* Finished: go to LU Generation */
mvPp2PrsSwSramFlowidGenSet(pe);
mvPp2PrsSwSramNextLuSet(pe, PRS_LU_FLOWS);
/* Set result info bits */
mvPp2PrsSwSramRiUpdate(pe, RI_L4_OTHER, RI_L4_PROTO_MASK);
mvPp2PrsSwTcamPortMapSet(pe, PORT_MASK);
/* AI bits check */
mvPp2PrsSwTcamAiUpdate(pe, (1 << IPV6_EXT_AI_BIT), (1 << IPV6_EXT_AI_BIT));
mvPp2PrsHwWrite(pe);
/* Update mvPrsShadowTbl */
mvPp2PrsShadowSet(pe->index, PRS_LU_IP4, "ipv6-ext-l4-unknown");
mvPp2PrsSwFree(pe);
/* Default IPv6 entry for unit cast address */
pe = mvPp2PrsSwAlloc(PRS_LU_IP6);
pe->index = PE_IP6_ADDR_UN;
mvPp2PrsSwTcamAiUpdate(pe, 0, (1 << IPV6_NO_EXT_AI_BIT));
mvPp2PrsSwTcamPortMapSet(pe, PORT_MASK);
mvPp2PrsSwSramRiUpdate(pe, RI_L3_UCAST, RI_L3_ADDR_MASK);
mvPp2PrsShadowSet(pe->index, PRS_LU_IP6, "ipv6-uc");
/* Finished: go to IPv6 again */
mvPp2PrsSwSramNextLuSet(pe, PRS_LU_IP6);
/* Shift back to IPV6 NH */
mvPp2PrsSwSramShiftSet(pe, -18, SRAM_OP_SEL_SHIFT_ADD);
/* Set sram AIbits */
mvPp2PrsSwSramAiUpdate(pe, (1 << IPV6_NO_EXT_AI_BIT), (1 << IPV6_NO_EXT_AI_BIT));
mvPp2PrsSwTcamPortMapSet(pe, PORT_MASK);
mvPp2PrsHwWrite(pe);
mvPp2PrsSwFree(pe);
return MV_OK;
}
/* Add IPv6 Next Header parse rule set */
int mvPrsIp6NhSet(void)
{
int rc;
unsigned char ah_len = 0;
/* Hop-by-Hop Options Header, Dummy protocol for TCP */
rc = mvPp2PrsIp6Proto(MV_IP_PROTO_NULL, 0, 0, MV_FALSE);
if (rc)
return rc;
rc = mvPp2PrsIp6Proto(MV_IP_PROTO_NULL, 0, 0, MV_TRUE);
if (rc)
return rc;
/* Encapsulated IPv6 Header, IPv6-in-IPv4 tunnelling */
rc = mvPp2PrsIp6Proto(MV_IP_PROTO_IPV6, 0, 0, MV_FALSE);
if (rc)
return rc;
rc = mvPp2PrsIp6Proto(MV_IP_PROTO_IPV6, 0, 0, MV_TRUE);
if (rc)
return rc;
/* Route header */
rc = mvPp2PrsIp6Proto(MV_IP_PROTO_RH, 0, 0, MV_FALSE);
if (rc)
return rc;
rc = mvPp2PrsIp6Proto(MV_IP_PROTO_RH, 0, 0, MV_TRUE);
if (rc)
return rc;
/* Fragment Header */
rc = mvPp2PrsIp6Proto(MV_IP_PROTO_FH, 0, 0, MV_FALSE);
if (rc)
return rc;
rc = mvPp2PrsIp6Proto(MV_IP_PROTO_FH, 0, 0, MV_TRUE);
if (rc)
return rc;
/* Authentication Header */
rc = mvPp2PrsIp6Proto(MV_IP_PROTO_AH, 0, 0, MV_FALSE);
if (rc)
return rc;
rc = mvPp2PrsIp6Proto(MV_IP_PROTO_AH, 0, 0, MV_TRUE);
if (rc)
return rc;
/* Check NH on AH header */
rc = mvPp2PrsIp6ProtoAh(MV_IP_PROTO_NULL, 0, 0);
if (rc)
return rc;
rc = mvPp2PrsIp6ProtoAh(MV_IP_PROTO_IPV6, 0, 0);
if (rc)
return rc;
rc = mvPp2PrsIp6ProtoAh(MV_IP_PROTO_RH, 0, 0);
if (rc)
return rc;
rc = mvPp2PrsIp6ProtoAh(MV_IP_PROTO_FH, 0, 0);
if (rc)
return rc;
rc = mvPp2PrsIp6ProtoAh(MV_IP_PROTO_DH, 0, 0);
if (rc)
return rc;
rc = mvPp2PrsIp6ProtoAh(MV_IP_PROTO_MH, 0, 0);
if (rc)
return rc;
rc = mvPp2PrsIp6ProtoAh(MV_IP_PROTO_TCP, RI_L4_TCP, RI_L4_PROTO_MASK);
if (rc)
return rc;
rc = mvPp2PrsIp6ProtoAh(MV_IP_PROTO_UDP, RI_L4_UDP, RI_L4_PROTO_MASK);
if (rc)
return rc;
rc = mvPp2PrsIp6ProtoAh(MV_IP_PROTO_ICMPV6, RI_CPU_CODE_RX_SPEC | RI_UDF3_RX_SPECIAL, RI_CPU_CODE_MASK | RI_UDF3_MASK);
if (rc)
return rc;
/* Check AH length */
for (ah_len = IP6_AH_LEN_16B; ah_len < IP6_AH_LEN_MAX; ah_len++) {
rc = mvPp2PrsIp6AhLen(ah_len, MV_FALSE);
if (rc)
return rc;
/* Set L4 offset */
rc = mvPp2PrsIp6AhLen(ah_len, MV_TRUE);
if (rc)
return rc;
}
/* Destination Options Header */
rc = mvPp2PrsIp6Proto(MV_IP_PROTO_DH, 0, 0, MV_FALSE);
if (rc)
return rc;
rc = mvPp2PrsIp6Proto(MV_IP_PROTO_DH, 0, 0, MV_TRUE);
if (rc)
return rc;
/* Mobility Header */
rc = mvPp2PrsIp6Proto(MV_IP_PROTO_MH, 0, 0, MV_FALSE);
if (rc)
return rc;
rc = mvPp2PrsIp6Proto(MV_IP_PROTO_MH, 0, 0, MV_TRUE);
if (rc)
return rc;
/* L4 parse */
rc = mvPp2PrsIp6Proto(MV_IP_PROTO_TCP,
RI_L4_TCP,
RI_L4_PROTO_MASK,
MV_TRUE);
if (rc)
return rc;
rc = mvPp2PrsIp6Proto(MV_IP_PROTO_UDP,
RI_L4_UDP,
RI_L4_PROTO_MASK,
MV_TRUE);
if (rc)
return rc;
rc = mvPp2PrsIp6Proto(MV_IP_PROTO_ICMPV6,
RI_CPU_CODE_RX_SPEC | RI_UDF3_RX_SPECIAL, RI_CPU_CODE_MASK | RI_UDF3_MASK,
MV_TRUE);
if (rc)
return rc;
return MV_OK;
}
/*
******************************************************************************
*
* flows
*
******************************************************************************
*/
static MV_PP2_PRS_ENTRY *mvPrsFlowFind(int flow)
{
MV_PP2_PRS_ENTRY *pe;
int tid;
unsigned int bits, enable;
pe = mvPp2PrsSwAlloc(PRS_LU_FLOWS);
/* Go through the all entires with PRS_LU_MAC */
for (tid = MV_PP2_PRS_TCAM_SIZE - 1; tid >= 0; tid--) {
if ((!mvPp2PrsShadowIsValid(tid)) || (mvPp2PrsShadowLu(tid) != PRS_LU_FLOWS))
continue;
pe->index = tid;
mvPp2PrsHwRead(pe);
mvPp2PrsSwSramAiGet(pe, &bits, &enable);
/* sram store classification lookup id in AI bits [5:0] */
if ((bits & FLOWID_MASK) == flow)
return pe;
}
mvPp2PrsSwFree(pe);
return NULL;
}
int mvPrsFlowIdGen(int tid, int flowId, unsigned int res, unsigned int resMask, int portBmp)
{
MV_PP2_PRS_ENTRY *pe;
char name[PRS_TEXT_SIZE];
PRS_DBG("%s\n", __func__);
POS_RANGE_VALIDATE(flowId, FLOWID_MASK);
POS_RANGE_VALIDATE(tid, MV_PP2_PRS_TCAM_SIZE - 1);
/* Default configuration entry - overrwite is forbidden */
if (mvPp2PrsShadowIsValid(tid) && (mvPp2PrsShadowLu(tid) != PRS_LU_FLOWS)) {
mvOsPrintf("%s: Error, Tcam entry is in use\n", __func__);
return MV_ERROR;
}
pe = mvPp2PrsSwAlloc(PRS_LU_FLOWS);
pe->index = tid;
mvPp2PrsSwSramAiUpdate(pe, flowId, FLOWID_MASK);
mvPp2PrsSwSramLuDoneSet(pe);
mvOsSPrintf(name, "flowId-%d", flowId);
/* Update mvPrsShadowTbl */
mvPp2PrsShadowSet(pe->index, PRS_LU_FLOWS, name);
mvPp2PrsSwTcamPortMapSet(pe, portBmp);
/*update result data and mask*/
mvPp2PrsSwTcamWordSet(pe, TCAM_DATA_OFFS, res, resMask);
mvPp2PrsHwWrite(pe);
mvPp2PrsSwFree(pe);
return MV_OK;
}
int mvPrsFlowIdDel(int tid)
{
PRS_DBG("%s\n", __func__);
POS_RANGE_VALIDATE(tid, MV_PP2_PRS_TCAM_SIZE - 1);
/* Only handle valid flow type rule */
if (!mvPp2PrsShadowIsValid(tid) || (mvPp2PrsShadowLu(tid) != PRS_LU_FLOWS)) {
mvOsPrintf("%s: Error, Tcam entry is not use or not flow type\n", __func__);
return MV_ERROR;
}
mvPp2PrsHwInv(tid);
mvPp2PrsShadowClear(tid);
return MV_OK;
}
int mvPrsFlowIdFirstFreeGet(void)
{
int fid;
for (fid = MV_PP2_PRS_FIRST_FLOW_ID; fid <= MV_PP2_PRS_LAST_FLOW_ID; fid++)
if (mvPrsFlowIdGet(fid) == MV_FALSE)
break;
if (fid <= MV_PP2_PRS_LAST_FLOW_ID)
return fid;
return MV_PP2_PRS_INVALID_FLOW_ID;
}
int mvPrsFlowIdLastFreeGet(void)
{
int fid;
for (fid = MV_PP2_PRS_LAST_FLOW_ID; fid >= MV_PP2_PRS_FIRST_FLOW_ID; fid--)
if (mvPrsFlowIdGet(fid) == MV_FALSE)
break;
if (fid >= MV_PP2_PRS_FIRST_FLOW_ID)
return fid;
return MV_PP2_PRS_INVALID_FLOW_ID;
}
int mvPrsFlowIdRelease(int flowId)
{
POS_RANGE_VALIDATE(flowId, FLOWID_MASK);
mvPrsFlowIdClear(flowId);
return MV_OK;
}
int mvPrsDefFlow(int port)
{
MV_PP2_PRS_ENTRY *pe;
int tid, mallocFlag = 0;
char name[PRS_TEXT_SIZE];
PRS_DBG("%s\n", __func__);
POS_RANGE_VALIDATE(port, MV_PP2_MAX_PORTS - 1);
pe = mvPrsFlowFind(FLOWID_DEF(port));
/* Such entry not exist */
if (!pe) {
/* Go through the all entires from last to fires */
tid = mvPp2PrsTcamFirstFree(MV_PP2_PRS_TCAM_SIZE - 1, 0);
if (tid == MV_PRS_OUT_OF_RAGE) {
mvOsPrintf("%s: No free TCAM entiry\n", __func__);
return MV_ERROR;
}
mallocFlag = 1;
pe = mvPp2PrsSwAlloc(PRS_LU_FLOWS);
pe->index = tid;
/* set flowID*/
mvPp2PrsSwSramAiUpdate(pe, FLOWID_DEF(port), FLOWID_MASK);
mvPrsFlowIdSet(FLOWID_DEF(port));
mvPp2PrsSwSramLuDoneSet(pe);
mvOsSPrintf(name, "def-flowId-port-%d", port);
/* Update mvPrsShadowTbl */
mvPp2PrsShadowSet(pe->index, PRS_LU_FLOWS, name);
}
mvPp2PrsSwTcamPortMapSet(pe, (1 << port));
mvPp2PrsHwWrite(pe);
if (mallocFlag)
mvPp2PrsSwFree(pe);
return MV_OK;
}
int mvPrsDefFlowInit(void)
{
MV_PP2_PRS_ENTRY *pe;
int tid;
int port;
char name[PRS_TEXT_SIZE];
PRS_DBG("%s\n", __func__);
for (port = 0; port < MV_PP2_MAX_PORTS; port++) {
/* Go through the all entires from last to fires */
tid = PE_FIRST_DEFAULT_FLOW - port;
if (tid == MV_PRS_OUT_OF_RAGE) {
mvOsPrintf("%s: No free TCAM entiry\n", __func__);
return MV_ERROR;
}
pe = mvPp2PrsSwAlloc(PRS_LU_FLOWS);
pe->index = tid;
mvPp2PrsSwTcamPortMapSet(pe, 0);
/* set flowID*/
mvPp2PrsSwSramAiUpdate(pe, FLOWID_DEF(port), FLOWID_MASK);
mvPrsFlowIdSet(FLOWID_DEF(port));
mvPp2PrsSwSramLuDoneSet(pe);
mvOsSPrintf(name, "def-flowId-port-%d", port);
/* Update mvPrsShadowTbl */
mvPp2PrsShadowSet(pe->index, PRS_LU_FLOWS, name);
mvPp2PrsHwWrite(pe);
mvPp2PrsSwFree(pe);
}
return MV_OK;
}
/******************************************************************************
*
* Paeser Init
*
******************************************************************************
*/
int mvPrsDefaultInit(void)
{
int port, rc;
/*enable tcam table*/
mvPp2PrsSwTcam(1);
/*write zero to all the lines*/
mvPp2PrsHwClearAll();
mvPp2PrsHwInvAll();
mvPp2PrsShadowClearAll();
mvPrsFlowIdClearAll();
/* TODO: Mask & clear all interrupts */
/* Always start from lookup = 0 */
for (port = 0; port < MV_PP2_MAX_PORTS; port++)
mvPp2PrsHwPortInit(port, PRS_LU_MH, MV_PP2_PRS_PORT_LU_MAX, 0);
rc = mvPrsDefFlowInit();
if (rc)
return rc;
rc = mvPp2PrsMhInit();
if (rc)
return rc;
rc = mvPp2PrsMacInit();
if (rc)
return rc;
rc = mvPp2PrsDsaInit();
if (rc)
return rc;
rc = mvPp2PrsEtypeInit();
if (rc)
return rc;
rc = mvPp2PrsVlanInit();
if (rc)
return rc;
rc = mvPp2PrsPppeInit();
if (rc)
return rc;
rc = mvPp2PrsIp4Init();
if (rc)
return rc;
rc = mvPp2PrsIp6Init();
if (rc)
return rc;
return MV_OK;
}