162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Header Parser helpers for Marvell PPv2 Network Controller
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Copyright (C) 2014 Marvell
662306a36Sopenharmony_ci *
762306a36Sopenharmony_ci * Marcin Wojtas <mw@semihalf.com>
862306a36Sopenharmony_ci */
962306a36Sopenharmony_ci
1062306a36Sopenharmony_ci#include <linux/kernel.h>
1162306a36Sopenharmony_ci#include <linux/netdevice.h>
1262306a36Sopenharmony_ci#include <linux/etherdevice.h>
1362306a36Sopenharmony_ci#include <linux/platform_device.h>
1462306a36Sopenharmony_ci#include <uapi/linux/ppp_defs.h>
1562306a36Sopenharmony_ci#include <net/ip.h>
1662306a36Sopenharmony_ci#include <net/ipv6.h>
1762306a36Sopenharmony_ci
1862306a36Sopenharmony_ci#include "mvpp2.h"
1962306a36Sopenharmony_ci#include "mvpp2_prs.h"
2062306a36Sopenharmony_ci
2162306a36Sopenharmony_ci/* Update parser tcam and sram hw entries */
2262306a36Sopenharmony_cistatic int mvpp2_prs_hw_write(struct mvpp2 *priv, struct mvpp2_prs_entry *pe)
2362306a36Sopenharmony_ci{
2462306a36Sopenharmony_ci	int i;
2562306a36Sopenharmony_ci
2662306a36Sopenharmony_ci	if (pe->index > MVPP2_PRS_TCAM_SRAM_SIZE - 1)
2762306a36Sopenharmony_ci		return -EINVAL;
2862306a36Sopenharmony_ci
2962306a36Sopenharmony_ci	/* Clear entry invalidation bit */
3062306a36Sopenharmony_ci	pe->tcam[MVPP2_PRS_TCAM_INV_WORD] &= ~MVPP2_PRS_TCAM_INV_MASK;
3162306a36Sopenharmony_ci
3262306a36Sopenharmony_ci	/* Write sram index - indirect access */
3362306a36Sopenharmony_ci	mvpp2_write(priv, MVPP2_PRS_SRAM_IDX_REG, pe->index);
3462306a36Sopenharmony_ci	for (i = 0; i < MVPP2_PRS_SRAM_WORDS; i++)
3562306a36Sopenharmony_ci		mvpp2_write(priv, MVPP2_PRS_SRAM_DATA_REG(i), pe->sram[i]);
3662306a36Sopenharmony_ci
3762306a36Sopenharmony_ci	/* Write tcam index - indirect access */
3862306a36Sopenharmony_ci	mvpp2_write(priv, MVPP2_PRS_TCAM_IDX_REG, pe->index);
3962306a36Sopenharmony_ci	for (i = 0; i < MVPP2_PRS_TCAM_WORDS; i++)
4062306a36Sopenharmony_ci		mvpp2_write(priv, MVPP2_PRS_TCAM_DATA_REG(i), pe->tcam[i]);
4162306a36Sopenharmony_ci
4262306a36Sopenharmony_ci	return 0;
4362306a36Sopenharmony_ci}
4462306a36Sopenharmony_ci
4562306a36Sopenharmony_ci/* Initialize tcam entry from hw */
4662306a36Sopenharmony_ciint mvpp2_prs_init_from_hw(struct mvpp2 *priv, struct mvpp2_prs_entry *pe,
4762306a36Sopenharmony_ci			   int tid)
4862306a36Sopenharmony_ci{
4962306a36Sopenharmony_ci	int i;
5062306a36Sopenharmony_ci
5162306a36Sopenharmony_ci	if (tid > MVPP2_PRS_TCAM_SRAM_SIZE - 1)
5262306a36Sopenharmony_ci		return -EINVAL;
5362306a36Sopenharmony_ci
5462306a36Sopenharmony_ci	memset(pe, 0, sizeof(*pe));
5562306a36Sopenharmony_ci	pe->index = tid;
5662306a36Sopenharmony_ci
5762306a36Sopenharmony_ci	/* Write tcam index - indirect access */
5862306a36Sopenharmony_ci	mvpp2_write(priv, MVPP2_PRS_TCAM_IDX_REG, pe->index);
5962306a36Sopenharmony_ci
6062306a36Sopenharmony_ci	pe->tcam[MVPP2_PRS_TCAM_INV_WORD] = mvpp2_read(priv,
6162306a36Sopenharmony_ci			      MVPP2_PRS_TCAM_DATA_REG(MVPP2_PRS_TCAM_INV_WORD));
6262306a36Sopenharmony_ci	if (pe->tcam[MVPP2_PRS_TCAM_INV_WORD] & MVPP2_PRS_TCAM_INV_MASK)
6362306a36Sopenharmony_ci		return MVPP2_PRS_TCAM_ENTRY_INVALID;
6462306a36Sopenharmony_ci
6562306a36Sopenharmony_ci	for (i = 0; i < MVPP2_PRS_TCAM_WORDS; i++)
6662306a36Sopenharmony_ci		pe->tcam[i] = mvpp2_read(priv, MVPP2_PRS_TCAM_DATA_REG(i));
6762306a36Sopenharmony_ci
6862306a36Sopenharmony_ci	/* Write sram index - indirect access */
6962306a36Sopenharmony_ci	mvpp2_write(priv, MVPP2_PRS_SRAM_IDX_REG, pe->index);
7062306a36Sopenharmony_ci	for (i = 0; i < MVPP2_PRS_SRAM_WORDS; i++)
7162306a36Sopenharmony_ci		pe->sram[i] = mvpp2_read(priv, MVPP2_PRS_SRAM_DATA_REG(i));
7262306a36Sopenharmony_ci
7362306a36Sopenharmony_ci	return 0;
7462306a36Sopenharmony_ci}
7562306a36Sopenharmony_ci
7662306a36Sopenharmony_ci/* Invalidate tcam hw entry */
7762306a36Sopenharmony_cistatic void mvpp2_prs_hw_inv(struct mvpp2 *priv, int index)
7862306a36Sopenharmony_ci{
7962306a36Sopenharmony_ci	/* Write index - indirect access */
8062306a36Sopenharmony_ci	mvpp2_write(priv, MVPP2_PRS_TCAM_IDX_REG, index);
8162306a36Sopenharmony_ci	mvpp2_write(priv, MVPP2_PRS_TCAM_DATA_REG(MVPP2_PRS_TCAM_INV_WORD),
8262306a36Sopenharmony_ci		    MVPP2_PRS_TCAM_INV_MASK);
8362306a36Sopenharmony_ci}
8462306a36Sopenharmony_ci
8562306a36Sopenharmony_ci/* Enable shadow table entry and set its lookup ID */
8662306a36Sopenharmony_cistatic void mvpp2_prs_shadow_set(struct mvpp2 *priv, int index, int lu)
8762306a36Sopenharmony_ci{
8862306a36Sopenharmony_ci	priv->prs_shadow[index].valid = true;
8962306a36Sopenharmony_ci	priv->prs_shadow[index].lu = lu;
9062306a36Sopenharmony_ci}
9162306a36Sopenharmony_ci
9262306a36Sopenharmony_ci/* Update ri fields in shadow table entry */
9362306a36Sopenharmony_cistatic void mvpp2_prs_shadow_ri_set(struct mvpp2 *priv, int index,
9462306a36Sopenharmony_ci				    unsigned int ri, unsigned int ri_mask)
9562306a36Sopenharmony_ci{
9662306a36Sopenharmony_ci	priv->prs_shadow[index].ri_mask = ri_mask;
9762306a36Sopenharmony_ci	priv->prs_shadow[index].ri = ri;
9862306a36Sopenharmony_ci}
9962306a36Sopenharmony_ci
10062306a36Sopenharmony_ci/* Update lookup field in tcam sw entry */
10162306a36Sopenharmony_cistatic void mvpp2_prs_tcam_lu_set(struct mvpp2_prs_entry *pe, unsigned int lu)
10262306a36Sopenharmony_ci{
10362306a36Sopenharmony_ci	pe->tcam[MVPP2_PRS_TCAM_LU_WORD] &= ~MVPP2_PRS_TCAM_LU(MVPP2_PRS_LU_MASK);
10462306a36Sopenharmony_ci	pe->tcam[MVPP2_PRS_TCAM_LU_WORD] &= ~MVPP2_PRS_TCAM_LU_EN(MVPP2_PRS_LU_MASK);
10562306a36Sopenharmony_ci	pe->tcam[MVPP2_PRS_TCAM_LU_WORD] |= MVPP2_PRS_TCAM_LU(lu & MVPP2_PRS_LU_MASK);
10662306a36Sopenharmony_ci	pe->tcam[MVPP2_PRS_TCAM_LU_WORD] |= MVPP2_PRS_TCAM_LU_EN(MVPP2_PRS_LU_MASK);
10762306a36Sopenharmony_ci}
10862306a36Sopenharmony_ci
10962306a36Sopenharmony_ci/* Update mask for single port in tcam sw entry */
11062306a36Sopenharmony_cistatic void mvpp2_prs_tcam_port_set(struct mvpp2_prs_entry *pe,
11162306a36Sopenharmony_ci				    unsigned int port, bool add)
11262306a36Sopenharmony_ci{
11362306a36Sopenharmony_ci	if (add)
11462306a36Sopenharmony_ci		pe->tcam[MVPP2_PRS_TCAM_PORT_WORD] &= ~MVPP2_PRS_TCAM_PORT_EN(BIT(port));
11562306a36Sopenharmony_ci	else
11662306a36Sopenharmony_ci		pe->tcam[MVPP2_PRS_TCAM_PORT_WORD] |= MVPP2_PRS_TCAM_PORT_EN(BIT(port));
11762306a36Sopenharmony_ci}
11862306a36Sopenharmony_ci
11962306a36Sopenharmony_ci/* Update port map in tcam sw entry */
12062306a36Sopenharmony_cistatic void mvpp2_prs_tcam_port_map_set(struct mvpp2_prs_entry *pe,
12162306a36Sopenharmony_ci					unsigned int ports)
12262306a36Sopenharmony_ci{
12362306a36Sopenharmony_ci	pe->tcam[MVPP2_PRS_TCAM_PORT_WORD] &= ~MVPP2_PRS_TCAM_PORT(MVPP2_PRS_PORT_MASK);
12462306a36Sopenharmony_ci	pe->tcam[MVPP2_PRS_TCAM_PORT_WORD] &= ~MVPP2_PRS_TCAM_PORT_EN(MVPP2_PRS_PORT_MASK);
12562306a36Sopenharmony_ci	pe->tcam[MVPP2_PRS_TCAM_PORT_WORD] |= MVPP2_PRS_TCAM_PORT_EN(~ports & MVPP2_PRS_PORT_MASK);
12662306a36Sopenharmony_ci}
12762306a36Sopenharmony_ci
12862306a36Sopenharmony_ci/* Obtain port map from tcam sw entry */
12962306a36Sopenharmony_ciunsigned int mvpp2_prs_tcam_port_map_get(struct mvpp2_prs_entry *pe)
13062306a36Sopenharmony_ci{
13162306a36Sopenharmony_ci	return (~pe->tcam[MVPP2_PRS_TCAM_PORT_WORD] >> 24) & MVPP2_PRS_PORT_MASK;
13262306a36Sopenharmony_ci}
13362306a36Sopenharmony_ci
13462306a36Sopenharmony_ci/* Set byte of data and its enable bits in tcam sw entry */
13562306a36Sopenharmony_cistatic void mvpp2_prs_tcam_data_byte_set(struct mvpp2_prs_entry *pe,
13662306a36Sopenharmony_ci					 unsigned int offs, unsigned char byte,
13762306a36Sopenharmony_ci					 unsigned char enable)
13862306a36Sopenharmony_ci{
13962306a36Sopenharmony_ci	int pos = MVPP2_PRS_BYTE_IN_WORD(offs) * BITS_PER_BYTE;
14062306a36Sopenharmony_ci
14162306a36Sopenharmony_ci	pe->tcam[MVPP2_PRS_BYTE_TO_WORD(offs)] &= ~(0xff << pos);
14262306a36Sopenharmony_ci	pe->tcam[MVPP2_PRS_BYTE_TO_WORD(offs)] &= ~(MVPP2_PRS_TCAM_EN(0xff) << pos);
14362306a36Sopenharmony_ci	pe->tcam[MVPP2_PRS_BYTE_TO_WORD(offs)] |= byte << pos;
14462306a36Sopenharmony_ci	pe->tcam[MVPP2_PRS_BYTE_TO_WORD(offs)] |= MVPP2_PRS_TCAM_EN(enable << pos);
14562306a36Sopenharmony_ci}
14662306a36Sopenharmony_ci
14762306a36Sopenharmony_ci/* Get byte of data and its enable bits from tcam sw entry */
14862306a36Sopenharmony_civoid mvpp2_prs_tcam_data_byte_get(struct mvpp2_prs_entry *pe,
14962306a36Sopenharmony_ci				  unsigned int offs, unsigned char *byte,
15062306a36Sopenharmony_ci				  unsigned char *enable)
15162306a36Sopenharmony_ci{
15262306a36Sopenharmony_ci	int pos = MVPP2_PRS_BYTE_IN_WORD(offs) * BITS_PER_BYTE;
15362306a36Sopenharmony_ci
15462306a36Sopenharmony_ci	*byte = (pe->tcam[MVPP2_PRS_BYTE_TO_WORD(offs)] >> pos) & 0xff;
15562306a36Sopenharmony_ci	*enable = (pe->tcam[MVPP2_PRS_BYTE_TO_WORD(offs)] >> (pos + 16)) & 0xff;
15662306a36Sopenharmony_ci}
15762306a36Sopenharmony_ci
15862306a36Sopenharmony_ci/* Compare tcam data bytes with a pattern */
15962306a36Sopenharmony_cistatic bool mvpp2_prs_tcam_data_cmp(struct mvpp2_prs_entry *pe, int offs,
16062306a36Sopenharmony_ci				    u16 data)
16162306a36Sopenharmony_ci{
16262306a36Sopenharmony_ci	u16 tcam_data;
16362306a36Sopenharmony_ci
16462306a36Sopenharmony_ci	tcam_data = pe->tcam[MVPP2_PRS_BYTE_TO_WORD(offs)] & 0xffff;
16562306a36Sopenharmony_ci	return tcam_data == data;
16662306a36Sopenharmony_ci}
16762306a36Sopenharmony_ci
16862306a36Sopenharmony_ci/* Update ai bits in tcam sw entry */
16962306a36Sopenharmony_cistatic void mvpp2_prs_tcam_ai_update(struct mvpp2_prs_entry *pe,
17062306a36Sopenharmony_ci				     unsigned int bits, unsigned int enable)
17162306a36Sopenharmony_ci{
17262306a36Sopenharmony_ci	int i;
17362306a36Sopenharmony_ci
17462306a36Sopenharmony_ci	for (i = 0; i < MVPP2_PRS_AI_BITS; i++) {
17562306a36Sopenharmony_ci		if (!(enable & BIT(i)))
17662306a36Sopenharmony_ci			continue;
17762306a36Sopenharmony_ci
17862306a36Sopenharmony_ci		if (bits & BIT(i))
17962306a36Sopenharmony_ci			pe->tcam[MVPP2_PRS_TCAM_AI_WORD] |= BIT(i);
18062306a36Sopenharmony_ci		else
18162306a36Sopenharmony_ci			pe->tcam[MVPP2_PRS_TCAM_AI_WORD] &= ~BIT(i);
18262306a36Sopenharmony_ci	}
18362306a36Sopenharmony_ci
18462306a36Sopenharmony_ci	pe->tcam[MVPP2_PRS_TCAM_AI_WORD] |= MVPP2_PRS_TCAM_AI_EN(enable);
18562306a36Sopenharmony_ci}
18662306a36Sopenharmony_ci
18762306a36Sopenharmony_ci/* Get ai bits from tcam sw entry */
18862306a36Sopenharmony_cistatic int mvpp2_prs_tcam_ai_get(struct mvpp2_prs_entry *pe)
18962306a36Sopenharmony_ci{
19062306a36Sopenharmony_ci	return pe->tcam[MVPP2_PRS_TCAM_AI_WORD] & MVPP2_PRS_AI_MASK;
19162306a36Sopenharmony_ci}
19262306a36Sopenharmony_ci
19362306a36Sopenharmony_ci/* Set ethertype in tcam sw entry */
19462306a36Sopenharmony_cistatic void mvpp2_prs_match_etype(struct mvpp2_prs_entry *pe, int offset,
19562306a36Sopenharmony_ci				  unsigned short ethertype)
19662306a36Sopenharmony_ci{
19762306a36Sopenharmony_ci	mvpp2_prs_tcam_data_byte_set(pe, offset + 0, ethertype >> 8, 0xff);
19862306a36Sopenharmony_ci	mvpp2_prs_tcam_data_byte_set(pe, offset + 1, ethertype & 0xff, 0xff);
19962306a36Sopenharmony_ci}
20062306a36Sopenharmony_ci
20162306a36Sopenharmony_ci/* Set vid in tcam sw entry */
20262306a36Sopenharmony_cistatic void mvpp2_prs_match_vid(struct mvpp2_prs_entry *pe, int offset,
20362306a36Sopenharmony_ci				unsigned short vid)
20462306a36Sopenharmony_ci{
20562306a36Sopenharmony_ci	mvpp2_prs_tcam_data_byte_set(pe, offset + 0, (vid & 0xf00) >> 8, 0xf);
20662306a36Sopenharmony_ci	mvpp2_prs_tcam_data_byte_set(pe, offset + 1, vid & 0xff, 0xff);
20762306a36Sopenharmony_ci}
20862306a36Sopenharmony_ci
20962306a36Sopenharmony_ci/* Set bits in sram sw entry */
21062306a36Sopenharmony_cistatic void mvpp2_prs_sram_bits_set(struct mvpp2_prs_entry *pe, int bit_num,
21162306a36Sopenharmony_ci				    u32 val)
21262306a36Sopenharmony_ci{
21362306a36Sopenharmony_ci	pe->sram[MVPP2_BIT_TO_WORD(bit_num)] |= (val << (MVPP2_BIT_IN_WORD(bit_num)));
21462306a36Sopenharmony_ci}
21562306a36Sopenharmony_ci
21662306a36Sopenharmony_ci/* Clear bits in sram sw entry */
21762306a36Sopenharmony_cistatic void mvpp2_prs_sram_bits_clear(struct mvpp2_prs_entry *pe, int bit_num,
21862306a36Sopenharmony_ci				      u32 val)
21962306a36Sopenharmony_ci{
22062306a36Sopenharmony_ci	pe->sram[MVPP2_BIT_TO_WORD(bit_num)] &= ~(val << (MVPP2_BIT_IN_WORD(bit_num)));
22162306a36Sopenharmony_ci}
22262306a36Sopenharmony_ci
22362306a36Sopenharmony_ci/* Update ri bits in sram sw entry */
22462306a36Sopenharmony_cistatic void mvpp2_prs_sram_ri_update(struct mvpp2_prs_entry *pe,
22562306a36Sopenharmony_ci				     unsigned int bits, unsigned int mask)
22662306a36Sopenharmony_ci{
22762306a36Sopenharmony_ci	unsigned int i;
22862306a36Sopenharmony_ci
22962306a36Sopenharmony_ci	for (i = 0; i < MVPP2_PRS_SRAM_RI_CTRL_BITS; i++) {
23062306a36Sopenharmony_ci		if (!(mask & BIT(i)))
23162306a36Sopenharmony_ci			continue;
23262306a36Sopenharmony_ci
23362306a36Sopenharmony_ci		if (bits & BIT(i))
23462306a36Sopenharmony_ci			mvpp2_prs_sram_bits_set(pe, MVPP2_PRS_SRAM_RI_OFFS + i,
23562306a36Sopenharmony_ci						1);
23662306a36Sopenharmony_ci		else
23762306a36Sopenharmony_ci			mvpp2_prs_sram_bits_clear(pe,
23862306a36Sopenharmony_ci						  MVPP2_PRS_SRAM_RI_OFFS + i,
23962306a36Sopenharmony_ci						  1);
24062306a36Sopenharmony_ci
24162306a36Sopenharmony_ci		mvpp2_prs_sram_bits_set(pe, MVPP2_PRS_SRAM_RI_CTRL_OFFS + i, 1);
24262306a36Sopenharmony_ci	}
24362306a36Sopenharmony_ci}
24462306a36Sopenharmony_ci
24562306a36Sopenharmony_ci/* Obtain ri bits from sram sw entry */
24662306a36Sopenharmony_cistatic int mvpp2_prs_sram_ri_get(struct mvpp2_prs_entry *pe)
24762306a36Sopenharmony_ci{
24862306a36Sopenharmony_ci	return pe->sram[MVPP2_PRS_SRAM_RI_WORD];
24962306a36Sopenharmony_ci}
25062306a36Sopenharmony_ci
25162306a36Sopenharmony_ci/* Update ai bits in sram sw entry */
25262306a36Sopenharmony_cistatic void mvpp2_prs_sram_ai_update(struct mvpp2_prs_entry *pe,
25362306a36Sopenharmony_ci				     unsigned int bits, unsigned int mask)
25462306a36Sopenharmony_ci{
25562306a36Sopenharmony_ci	unsigned int i;
25662306a36Sopenharmony_ci
25762306a36Sopenharmony_ci	for (i = 0; i < MVPP2_PRS_SRAM_AI_CTRL_BITS; i++) {
25862306a36Sopenharmony_ci		if (!(mask & BIT(i)))
25962306a36Sopenharmony_ci			continue;
26062306a36Sopenharmony_ci
26162306a36Sopenharmony_ci		if (bits & BIT(i))
26262306a36Sopenharmony_ci			mvpp2_prs_sram_bits_set(pe, MVPP2_PRS_SRAM_AI_OFFS + i,
26362306a36Sopenharmony_ci						1);
26462306a36Sopenharmony_ci		else
26562306a36Sopenharmony_ci			mvpp2_prs_sram_bits_clear(pe,
26662306a36Sopenharmony_ci						  MVPP2_PRS_SRAM_AI_OFFS + i,
26762306a36Sopenharmony_ci						  1);
26862306a36Sopenharmony_ci
26962306a36Sopenharmony_ci		mvpp2_prs_sram_bits_set(pe, MVPP2_PRS_SRAM_AI_CTRL_OFFS + i, 1);
27062306a36Sopenharmony_ci	}
27162306a36Sopenharmony_ci}
27262306a36Sopenharmony_ci
27362306a36Sopenharmony_ci/* Read ai bits from sram sw entry */
27462306a36Sopenharmony_cistatic int mvpp2_prs_sram_ai_get(struct mvpp2_prs_entry *pe)
27562306a36Sopenharmony_ci{
27662306a36Sopenharmony_ci	u8 bits;
27762306a36Sopenharmony_ci	/* ai is stored on bits 90->97; so it spreads across two u32 */
27862306a36Sopenharmony_ci	int ai_off = MVPP2_BIT_TO_WORD(MVPP2_PRS_SRAM_AI_OFFS);
27962306a36Sopenharmony_ci	int ai_shift = MVPP2_BIT_IN_WORD(MVPP2_PRS_SRAM_AI_OFFS);
28062306a36Sopenharmony_ci
28162306a36Sopenharmony_ci	bits = (pe->sram[ai_off] >> ai_shift) |
28262306a36Sopenharmony_ci	       (pe->sram[ai_off + 1] << (32 - ai_shift));
28362306a36Sopenharmony_ci
28462306a36Sopenharmony_ci	return bits;
28562306a36Sopenharmony_ci}
28662306a36Sopenharmony_ci
28762306a36Sopenharmony_ci/* In sram sw entry set lookup ID field of the tcam key to be used in the next
28862306a36Sopenharmony_ci * lookup interation
28962306a36Sopenharmony_ci */
29062306a36Sopenharmony_cistatic void mvpp2_prs_sram_next_lu_set(struct mvpp2_prs_entry *pe,
29162306a36Sopenharmony_ci				       unsigned int lu)
29262306a36Sopenharmony_ci{
29362306a36Sopenharmony_ci	int sram_next_off = MVPP2_PRS_SRAM_NEXT_LU_OFFS;
29462306a36Sopenharmony_ci
29562306a36Sopenharmony_ci	mvpp2_prs_sram_bits_clear(pe, sram_next_off,
29662306a36Sopenharmony_ci				  MVPP2_PRS_SRAM_NEXT_LU_MASK);
29762306a36Sopenharmony_ci	mvpp2_prs_sram_bits_set(pe, sram_next_off, lu);
29862306a36Sopenharmony_ci}
29962306a36Sopenharmony_ci
30062306a36Sopenharmony_ci/* In the sram sw entry set sign and value of the next lookup offset
30162306a36Sopenharmony_ci * and the offset value generated to the classifier
30262306a36Sopenharmony_ci */
30362306a36Sopenharmony_cistatic void mvpp2_prs_sram_shift_set(struct mvpp2_prs_entry *pe, int shift,
30462306a36Sopenharmony_ci				     unsigned int op)
30562306a36Sopenharmony_ci{
30662306a36Sopenharmony_ci	/* Set sign */
30762306a36Sopenharmony_ci	if (shift < 0) {
30862306a36Sopenharmony_ci		mvpp2_prs_sram_bits_set(pe, MVPP2_PRS_SRAM_SHIFT_SIGN_BIT, 1);
30962306a36Sopenharmony_ci		shift = 0 - shift;
31062306a36Sopenharmony_ci	} else {
31162306a36Sopenharmony_ci		mvpp2_prs_sram_bits_clear(pe, MVPP2_PRS_SRAM_SHIFT_SIGN_BIT, 1);
31262306a36Sopenharmony_ci	}
31362306a36Sopenharmony_ci
31462306a36Sopenharmony_ci	/* Set value */
31562306a36Sopenharmony_ci	pe->sram[MVPP2_BIT_TO_WORD(MVPP2_PRS_SRAM_SHIFT_OFFS)] |=
31662306a36Sopenharmony_ci		shift & MVPP2_PRS_SRAM_SHIFT_MASK;
31762306a36Sopenharmony_ci
31862306a36Sopenharmony_ci	/* Reset and set operation */
31962306a36Sopenharmony_ci	mvpp2_prs_sram_bits_clear(pe, MVPP2_PRS_SRAM_OP_SEL_SHIFT_OFFS,
32062306a36Sopenharmony_ci				  MVPP2_PRS_SRAM_OP_SEL_SHIFT_MASK);
32162306a36Sopenharmony_ci	mvpp2_prs_sram_bits_set(pe, MVPP2_PRS_SRAM_OP_SEL_SHIFT_OFFS, op);
32262306a36Sopenharmony_ci
32362306a36Sopenharmony_ci	/* Set base offset as current */
32462306a36Sopenharmony_ci	mvpp2_prs_sram_bits_clear(pe, MVPP2_PRS_SRAM_OP_SEL_BASE_OFFS, 1);
32562306a36Sopenharmony_ci}
32662306a36Sopenharmony_ci
32762306a36Sopenharmony_ci/* In the sram sw entry set sign and value of the user defined offset
32862306a36Sopenharmony_ci * generated to the classifier
32962306a36Sopenharmony_ci */
33062306a36Sopenharmony_cistatic void mvpp2_prs_sram_offset_set(struct mvpp2_prs_entry *pe,
33162306a36Sopenharmony_ci				      unsigned int type, int offset,
33262306a36Sopenharmony_ci				      unsigned int op)
33362306a36Sopenharmony_ci{
33462306a36Sopenharmony_ci	/* Set sign */
33562306a36Sopenharmony_ci	if (offset < 0) {
33662306a36Sopenharmony_ci		mvpp2_prs_sram_bits_set(pe, MVPP2_PRS_SRAM_UDF_SIGN_BIT, 1);
33762306a36Sopenharmony_ci		offset = 0 - offset;
33862306a36Sopenharmony_ci	} else {
33962306a36Sopenharmony_ci		mvpp2_prs_sram_bits_clear(pe, MVPP2_PRS_SRAM_UDF_SIGN_BIT, 1);
34062306a36Sopenharmony_ci	}
34162306a36Sopenharmony_ci
34262306a36Sopenharmony_ci	/* Set value */
34362306a36Sopenharmony_ci	mvpp2_prs_sram_bits_clear(pe, MVPP2_PRS_SRAM_UDF_OFFS,
34462306a36Sopenharmony_ci				  MVPP2_PRS_SRAM_UDF_MASK);
34562306a36Sopenharmony_ci	mvpp2_prs_sram_bits_set(pe, MVPP2_PRS_SRAM_UDF_OFFS,
34662306a36Sopenharmony_ci				offset & MVPP2_PRS_SRAM_UDF_MASK);
34762306a36Sopenharmony_ci
34862306a36Sopenharmony_ci	/* Set offset type */
34962306a36Sopenharmony_ci	mvpp2_prs_sram_bits_clear(pe, MVPP2_PRS_SRAM_UDF_TYPE_OFFS,
35062306a36Sopenharmony_ci				  MVPP2_PRS_SRAM_UDF_TYPE_MASK);
35162306a36Sopenharmony_ci	mvpp2_prs_sram_bits_set(pe, MVPP2_PRS_SRAM_UDF_TYPE_OFFS, type);
35262306a36Sopenharmony_ci
35362306a36Sopenharmony_ci	/* Set offset operation */
35462306a36Sopenharmony_ci	mvpp2_prs_sram_bits_clear(pe, MVPP2_PRS_SRAM_OP_SEL_UDF_OFFS,
35562306a36Sopenharmony_ci				  MVPP2_PRS_SRAM_OP_SEL_UDF_MASK);
35662306a36Sopenharmony_ci	mvpp2_prs_sram_bits_set(pe, MVPP2_PRS_SRAM_OP_SEL_UDF_OFFS,
35762306a36Sopenharmony_ci				op & MVPP2_PRS_SRAM_OP_SEL_UDF_MASK);
35862306a36Sopenharmony_ci
35962306a36Sopenharmony_ci	/* Set base offset as current */
36062306a36Sopenharmony_ci	mvpp2_prs_sram_bits_clear(pe, MVPP2_PRS_SRAM_OP_SEL_BASE_OFFS, 1);
36162306a36Sopenharmony_ci}
36262306a36Sopenharmony_ci
36362306a36Sopenharmony_ci/* Find parser flow entry */
36462306a36Sopenharmony_cistatic int mvpp2_prs_flow_find(struct mvpp2 *priv, int flow)
36562306a36Sopenharmony_ci{
36662306a36Sopenharmony_ci	struct mvpp2_prs_entry pe;
36762306a36Sopenharmony_ci	int tid;
36862306a36Sopenharmony_ci
36962306a36Sopenharmony_ci	/* Go through the all entires with MVPP2_PRS_LU_FLOWS */
37062306a36Sopenharmony_ci	for (tid = MVPP2_PRS_TCAM_SRAM_SIZE - 1; tid >= 0; tid--) {
37162306a36Sopenharmony_ci		u8 bits;
37262306a36Sopenharmony_ci
37362306a36Sopenharmony_ci		if (!priv->prs_shadow[tid].valid ||
37462306a36Sopenharmony_ci		    priv->prs_shadow[tid].lu != MVPP2_PRS_LU_FLOWS)
37562306a36Sopenharmony_ci			continue;
37662306a36Sopenharmony_ci
37762306a36Sopenharmony_ci		mvpp2_prs_init_from_hw(priv, &pe, tid);
37862306a36Sopenharmony_ci		bits = mvpp2_prs_sram_ai_get(&pe);
37962306a36Sopenharmony_ci
38062306a36Sopenharmony_ci		/* Sram store classification lookup ID in AI bits [5:0] */
38162306a36Sopenharmony_ci		if ((bits & MVPP2_PRS_FLOW_ID_MASK) == flow)
38262306a36Sopenharmony_ci			return tid;
38362306a36Sopenharmony_ci	}
38462306a36Sopenharmony_ci
38562306a36Sopenharmony_ci	return -ENOENT;
38662306a36Sopenharmony_ci}
38762306a36Sopenharmony_ci
38862306a36Sopenharmony_ci/* Return first free tcam index, seeking from start to end */
38962306a36Sopenharmony_cistatic int mvpp2_prs_tcam_first_free(struct mvpp2 *priv, unsigned char start,
39062306a36Sopenharmony_ci				     unsigned char end)
39162306a36Sopenharmony_ci{
39262306a36Sopenharmony_ci	int tid;
39362306a36Sopenharmony_ci
39462306a36Sopenharmony_ci	if (start > end)
39562306a36Sopenharmony_ci		swap(start, end);
39662306a36Sopenharmony_ci
39762306a36Sopenharmony_ci	for (tid = start; tid <= end; tid++) {
39862306a36Sopenharmony_ci		if (!priv->prs_shadow[tid].valid)
39962306a36Sopenharmony_ci			return tid;
40062306a36Sopenharmony_ci	}
40162306a36Sopenharmony_ci
40262306a36Sopenharmony_ci	return -EINVAL;
40362306a36Sopenharmony_ci}
40462306a36Sopenharmony_ci
40562306a36Sopenharmony_ci/* Drop flow control pause frames */
40662306a36Sopenharmony_cistatic void mvpp2_prs_drop_fc(struct mvpp2 *priv)
40762306a36Sopenharmony_ci{
40862306a36Sopenharmony_ci	unsigned char da[ETH_ALEN] = { 0x01, 0x80, 0xC2, 0x00, 0x00, 0x01 };
40962306a36Sopenharmony_ci	struct mvpp2_prs_entry pe;
41062306a36Sopenharmony_ci	unsigned int len;
41162306a36Sopenharmony_ci
41262306a36Sopenharmony_ci	memset(&pe, 0, sizeof(pe));
41362306a36Sopenharmony_ci
41462306a36Sopenharmony_ci	/* For all ports - drop flow control frames */
41562306a36Sopenharmony_ci	pe.index = MVPP2_PE_FC_DROP;
41662306a36Sopenharmony_ci	mvpp2_prs_tcam_lu_set(&pe, MVPP2_PRS_LU_MAC);
41762306a36Sopenharmony_ci
41862306a36Sopenharmony_ci	/* Set match on DA */
41962306a36Sopenharmony_ci	len = ETH_ALEN;
42062306a36Sopenharmony_ci	while (len--)
42162306a36Sopenharmony_ci		mvpp2_prs_tcam_data_byte_set(&pe, len, da[len], 0xff);
42262306a36Sopenharmony_ci
42362306a36Sopenharmony_ci	mvpp2_prs_sram_ri_update(&pe, MVPP2_PRS_RI_DROP_MASK,
42462306a36Sopenharmony_ci				 MVPP2_PRS_RI_DROP_MASK);
42562306a36Sopenharmony_ci
42662306a36Sopenharmony_ci	mvpp2_prs_sram_bits_set(&pe, MVPP2_PRS_SRAM_LU_GEN_BIT, 1);
42762306a36Sopenharmony_ci	mvpp2_prs_sram_next_lu_set(&pe, MVPP2_PRS_LU_FLOWS);
42862306a36Sopenharmony_ci
42962306a36Sopenharmony_ci	/* Mask all ports */
43062306a36Sopenharmony_ci	mvpp2_prs_tcam_port_map_set(&pe, MVPP2_PRS_PORT_MASK);
43162306a36Sopenharmony_ci
43262306a36Sopenharmony_ci	/* Update shadow table and hw entry */
43362306a36Sopenharmony_ci	mvpp2_prs_shadow_set(priv, pe.index, MVPP2_PRS_LU_MAC);
43462306a36Sopenharmony_ci	mvpp2_prs_hw_write(priv, &pe);
43562306a36Sopenharmony_ci}
43662306a36Sopenharmony_ci
43762306a36Sopenharmony_ci/* Enable/disable dropping all mac da's */
43862306a36Sopenharmony_cistatic void mvpp2_prs_mac_drop_all_set(struct mvpp2 *priv, int port, bool add)
43962306a36Sopenharmony_ci{
44062306a36Sopenharmony_ci	struct mvpp2_prs_entry pe;
44162306a36Sopenharmony_ci
44262306a36Sopenharmony_ci	if (priv->prs_shadow[MVPP2_PE_DROP_ALL].valid) {
44362306a36Sopenharmony_ci		/* Entry exist - update port only */
44462306a36Sopenharmony_ci		mvpp2_prs_init_from_hw(priv, &pe, MVPP2_PE_DROP_ALL);
44562306a36Sopenharmony_ci	} else {
44662306a36Sopenharmony_ci		/* Entry doesn't exist - create new */
44762306a36Sopenharmony_ci		memset(&pe, 0, sizeof(pe));
44862306a36Sopenharmony_ci		mvpp2_prs_tcam_lu_set(&pe, MVPP2_PRS_LU_MAC);
44962306a36Sopenharmony_ci		pe.index = MVPP2_PE_DROP_ALL;
45062306a36Sopenharmony_ci
45162306a36Sopenharmony_ci		/* Non-promiscuous mode for all ports - DROP unknown packets */
45262306a36Sopenharmony_ci		mvpp2_prs_sram_ri_update(&pe, MVPP2_PRS_RI_DROP_MASK,
45362306a36Sopenharmony_ci					 MVPP2_PRS_RI_DROP_MASK);
45462306a36Sopenharmony_ci
45562306a36Sopenharmony_ci		mvpp2_prs_sram_bits_set(&pe, MVPP2_PRS_SRAM_LU_GEN_BIT, 1);
45662306a36Sopenharmony_ci		mvpp2_prs_sram_next_lu_set(&pe, MVPP2_PRS_LU_FLOWS);
45762306a36Sopenharmony_ci
45862306a36Sopenharmony_ci		/* Update shadow table */
45962306a36Sopenharmony_ci		mvpp2_prs_shadow_set(priv, pe.index, MVPP2_PRS_LU_MAC);
46062306a36Sopenharmony_ci
46162306a36Sopenharmony_ci		/* Mask all ports */
46262306a36Sopenharmony_ci		mvpp2_prs_tcam_port_map_set(&pe, 0);
46362306a36Sopenharmony_ci	}
46462306a36Sopenharmony_ci
46562306a36Sopenharmony_ci	/* Update port mask */
46662306a36Sopenharmony_ci	mvpp2_prs_tcam_port_set(&pe, port, add);
46762306a36Sopenharmony_ci
46862306a36Sopenharmony_ci	mvpp2_prs_hw_write(priv, &pe);
46962306a36Sopenharmony_ci}
47062306a36Sopenharmony_ci
47162306a36Sopenharmony_ci/* Set port to unicast or multicast promiscuous mode */
47262306a36Sopenharmony_civoid mvpp2_prs_mac_promisc_set(struct mvpp2 *priv, int port,
47362306a36Sopenharmony_ci			       enum mvpp2_prs_l2_cast l2_cast, bool add)
47462306a36Sopenharmony_ci{
47562306a36Sopenharmony_ci	struct mvpp2_prs_entry pe;
47662306a36Sopenharmony_ci	unsigned char cast_match;
47762306a36Sopenharmony_ci	unsigned int ri;
47862306a36Sopenharmony_ci	int tid;
47962306a36Sopenharmony_ci
48062306a36Sopenharmony_ci	if (l2_cast == MVPP2_PRS_L2_UNI_CAST) {
48162306a36Sopenharmony_ci		cast_match = MVPP2_PRS_UCAST_VAL;
48262306a36Sopenharmony_ci		tid = MVPP2_PE_MAC_UC_PROMISCUOUS;
48362306a36Sopenharmony_ci		ri = MVPP2_PRS_RI_L2_UCAST;
48462306a36Sopenharmony_ci	} else {
48562306a36Sopenharmony_ci		cast_match = MVPP2_PRS_MCAST_VAL;
48662306a36Sopenharmony_ci		tid = MVPP2_PE_MAC_MC_PROMISCUOUS;
48762306a36Sopenharmony_ci		ri = MVPP2_PRS_RI_L2_MCAST;
48862306a36Sopenharmony_ci	}
48962306a36Sopenharmony_ci
49062306a36Sopenharmony_ci	/* promiscuous mode - Accept unknown unicast or multicast packets */
49162306a36Sopenharmony_ci	if (priv->prs_shadow[tid].valid) {
49262306a36Sopenharmony_ci		mvpp2_prs_init_from_hw(priv, &pe, tid);
49362306a36Sopenharmony_ci	} else {
49462306a36Sopenharmony_ci		memset(&pe, 0, sizeof(pe));
49562306a36Sopenharmony_ci		mvpp2_prs_tcam_lu_set(&pe, MVPP2_PRS_LU_MAC);
49662306a36Sopenharmony_ci		pe.index = tid;
49762306a36Sopenharmony_ci
49862306a36Sopenharmony_ci		/* Continue - set next lookup */
49962306a36Sopenharmony_ci		mvpp2_prs_sram_next_lu_set(&pe, MVPP2_PRS_LU_DSA);
50062306a36Sopenharmony_ci
50162306a36Sopenharmony_ci		/* Set result info bits */
50262306a36Sopenharmony_ci		mvpp2_prs_sram_ri_update(&pe, ri, MVPP2_PRS_RI_L2_CAST_MASK);
50362306a36Sopenharmony_ci
50462306a36Sopenharmony_ci		/* Match UC or MC addresses */
50562306a36Sopenharmony_ci		mvpp2_prs_tcam_data_byte_set(&pe, 0, cast_match,
50662306a36Sopenharmony_ci					     MVPP2_PRS_CAST_MASK);
50762306a36Sopenharmony_ci
50862306a36Sopenharmony_ci		/* Shift to ethertype */
50962306a36Sopenharmony_ci		mvpp2_prs_sram_shift_set(&pe, 2 * ETH_ALEN,
51062306a36Sopenharmony_ci					 MVPP2_PRS_SRAM_OP_SEL_SHIFT_ADD);
51162306a36Sopenharmony_ci
51262306a36Sopenharmony_ci		/* Mask all ports */
51362306a36Sopenharmony_ci		mvpp2_prs_tcam_port_map_set(&pe, 0);
51462306a36Sopenharmony_ci
51562306a36Sopenharmony_ci		/* Update shadow table */
51662306a36Sopenharmony_ci		mvpp2_prs_shadow_set(priv, pe.index, MVPP2_PRS_LU_MAC);
51762306a36Sopenharmony_ci	}
51862306a36Sopenharmony_ci
51962306a36Sopenharmony_ci	/* Update port mask */
52062306a36Sopenharmony_ci	mvpp2_prs_tcam_port_set(&pe, port, add);
52162306a36Sopenharmony_ci
52262306a36Sopenharmony_ci	mvpp2_prs_hw_write(priv, &pe);
52362306a36Sopenharmony_ci}
52462306a36Sopenharmony_ci
52562306a36Sopenharmony_ci/* Set entry for dsa packets */
52662306a36Sopenharmony_cistatic void mvpp2_prs_dsa_tag_set(struct mvpp2 *priv, int port, bool add,
52762306a36Sopenharmony_ci				  bool tagged, bool extend)
52862306a36Sopenharmony_ci{
52962306a36Sopenharmony_ci	struct mvpp2_prs_entry pe;
53062306a36Sopenharmony_ci	int tid, shift;
53162306a36Sopenharmony_ci
53262306a36Sopenharmony_ci	if (extend) {
53362306a36Sopenharmony_ci		tid = tagged ? MVPP2_PE_EDSA_TAGGED : MVPP2_PE_EDSA_UNTAGGED;
53462306a36Sopenharmony_ci		shift = 8;
53562306a36Sopenharmony_ci	} else {
53662306a36Sopenharmony_ci		tid = tagged ? MVPP2_PE_DSA_TAGGED : MVPP2_PE_DSA_UNTAGGED;
53762306a36Sopenharmony_ci		shift = 4;
53862306a36Sopenharmony_ci	}
53962306a36Sopenharmony_ci
54062306a36Sopenharmony_ci	if (priv->prs_shadow[tid].valid) {
54162306a36Sopenharmony_ci		/* Entry exist - update port only */
54262306a36Sopenharmony_ci		mvpp2_prs_init_from_hw(priv, &pe, tid);
54362306a36Sopenharmony_ci	} else {
54462306a36Sopenharmony_ci		/* Entry doesn't exist - create new */
54562306a36Sopenharmony_ci		memset(&pe, 0, sizeof(pe));
54662306a36Sopenharmony_ci		mvpp2_prs_tcam_lu_set(&pe, MVPP2_PRS_LU_DSA);
54762306a36Sopenharmony_ci		pe.index = tid;
54862306a36Sopenharmony_ci
54962306a36Sopenharmony_ci		/* Update shadow table */
55062306a36Sopenharmony_ci		mvpp2_prs_shadow_set(priv, pe.index, MVPP2_PRS_LU_DSA);
55162306a36Sopenharmony_ci
55262306a36Sopenharmony_ci		if (tagged) {
55362306a36Sopenharmony_ci			/* Set tagged bit in DSA tag */
55462306a36Sopenharmony_ci			mvpp2_prs_tcam_data_byte_set(&pe, 0,
55562306a36Sopenharmony_ci					     MVPP2_PRS_TCAM_DSA_TAGGED_BIT,
55662306a36Sopenharmony_ci					     MVPP2_PRS_TCAM_DSA_TAGGED_BIT);
55762306a36Sopenharmony_ci
55862306a36Sopenharmony_ci			/* Set ai bits for next iteration */
55962306a36Sopenharmony_ci			if (extend)
56062306a36Sopenharmony_ci				mvpp2_prs_sram_ai_update(&pe, 1,
56162306a36Sopenharmony_ci							MVPP2_PRS_SRAM_AI_MASK);
56262306a36Sopenharmony_ci			else
56362306a36Sopenharmony_ci				mvpp2_prs_sram_ai_update(&pe, 0,
56462306a36Sopenharmony_ci							MVPP2_PRS_SRAM_AI_MASK);
56562306a36Sopenharmony_ci
56662306a36Sopenharmony_ci			/* Set result info bits to 'single vlan' */
56762306a36Sopenharmony_ci			mvpp2_prs_sram_ri_update(&pe, MVPP2_PRS_RI_VLAN_SINGLE,
56862306a36Sopenharmony_ci						 MVPP2_PRS_RI_VLAN_MASK);
56962306a36Sopenharmony_ci			/* If packet is tagged continue check vid filtering */
57062306a36Sopenharmony_ci			mvpp2_prs_sram_next_lu_set(&pe, MVPP2_PRS_LU_VID);
57162306a36Sopenharmony_ci		} else {
57262306a36Sopenharmony_ci			/* Shift 4 bytes for DSA tag or 8 bytes for EDSA tag*/
57362306a36Sopenharmony_ci			mvpp2_prs_sram_shift_set(&pe, shift,
57462306a36Sopenharmony_ci					MVPP2_PRS_SRAM_OP_SEL_SHIFT_ADD);
57562306a36Sopenharmony_ci
57662306a36Sopenharmony_ci			/* Set result info bits to 'no vlans' */
57762306a36Sopenharmony_ci			mvpp2_prs_sram_ri_update(&pe, MVPP2_PRS_RI_VLAN_NONE,
57862306a36Sopenharmony_ci						 MVPP2_PRS_RI_VLAN_MASK);
57962306a36Sopenharmony_ci			mvpp2_prs_sram_next_lu_set(&pe, MVPP2_PRS_LU_L2);
58062306a36Sopenharmony_ci		}
58162306a36Sopenharmony_ci
58262306a36Sopenharmony_ci		/* Mask all ports */
58362306a36Sopenharmony_ci		mvpp2_prs_tcam_port_map_set(&pe, 0);
58462306a36Sopenharmony_ci	}
58562306a36Sopenharmony_ci
58662306a36Sopenharmony_ci	/* Update port mask */
58762306a36Sopenharmony_ci	mvpp2_prs_tcam_port_set(&pe, port, add);
58862306a36Sopenharmony_ci
58962306a36Sopenharmony_ci	mvpp2_prs_hw_write(priv, &pe);
59062306a36Sopenharmony_ci}
59162306a36Sopenharmony_ci
59262306a36Sopenharmony_ci/* Set entry for dsa ethertype */
59362306a36Sopenharmony_cistatic void mvpp2_prs_dsa_tag_ethertype_set(struct mvpp2 *priv, int port,
59462306a36Sopenharmony_ci					    bool add, bool tagged, bool extend)
59562306a36Sopenharmony_ci{
59662306a36Sopenharmony_ci	struct mvpp2_prs_entry pe;
59762306a36Sopenharmony_ci	int tid, shift, port_mask;
59862306a36Sopenharmony_ci
59962306a36Sopenharmony_ci	if (extend) {
60062306a36Sopenharmony_ci		tid = tagged ? MVPP2_PE_ETYPE_EDSA_TAGGED :
60162306a36Sopenharmony_ci		      MVPP2_PE_ETYPE_EDSA_UNTAGGED;
60262306a36Sopenharmony_ci		port_mask = 0;
60362306a36Sopenharmony_ci		shift = 8;
60462306a36Sopenharmony_ci	} else {
60562306a36Sopenharmony_ci		tid = tagged ? MVPP2_PE_ETYPE_DSA_TAGGED :
60662306a36Sopenharmony_ci		      MVPP2_PE_ETYPE_DSA_UNTAGGED;
60762306a36Sopenharmony_ci		port_mask = MVPP2_PRS_PORT_MASK;
60862306a36Sopenharmony_ci		shift = 4;
60962306a36Sopenharmony_ci	}
61062306a36Sopenharmony_ci
61162306a36Sopenharmony_ci	if (priv->prs_shadow[tid].valid) {
61262306a36Sopenharmony_ci		/* Entry exist - update port only */
61362306a36Sopenharmony_ci		mvpp2_prs_init_from_hw(priv, &pe, tid);
61462306a36Sopenharmony_ci	} else {
61562306a36Sopenharmony_ci		/* Entry doesn't exist - create new */
61662306a36Sopenharmony_ci		memset(&pe, 0, sizeof(pe));
61762306a36Sopenharmony_ci		mvpp2_prs_tcam_lu_set(&pe, MVPP2_PRS_LU_DSA);
61862306a36Sopenharmony_ci		pe.index = tid;
61962306a36Sopenharmony_ci
62062306a36Sopenharmony_ci		/* Set ethertype */
62162306a36Sopenharmony_ci		mvpp2_prs_match_etype(&pe, 0, ETH_P_EDSA);
62262306a36Sopenharmony_ci		mvpp2_prs_match_etype(&pe, 2, 0);
62362306a36Sopenharmony_ci
62462306a36Sopenharmony_ci		mvpp2_prs_sram_ri_update(&pe, MVPP2_PRS_RI_DSA_MASK,
62562306a36Sopenharmony_ci					 MVPP2_PRS_RI_DSA_MASK);
62662306a36Sopenharmony_ci		/* Shift ethertype + 2 byte reserved + tag*/
62762306a36Sopenharmony_ci		mvpp2_prs_sram_shift_set(&pe, 2 + MVPP2_ETH_TYPE_LEN + shift,
62862306a36Sopenharmony_ci					 MVPP2_PRS_SRAM_OP_SEL_SHIFT_ADD);
62962306a36Sopenharmony_ci
63062306a36Sopenharmony_ci		/* Update shadow table */
63162306a36Sopenharmony_ci		mvpp2_prs_shadow_set(priv, pe.index, MVPP2_PRS_LU_DSA);
63262306a36Sopenharmony_ci
63362306a36Sopenharmony_ci		if (tagged) {
63462306a36Sopenharmony_ci			/* Set tagged bit in DSA tag */
63562306a36Sopenharmony_ci			mvpp2_prs_tcam_data_byte_set(&pe,
63662306a36Sopenharmony_ci						     MVPP2_ETH_TYPE_LEN + 2 + 3,
63762306a36Sopenharmony_ci						 MVPP2_PRS_TCAM_DSA_TAGGED_BIT,
63862306a36Sopenharmony_ci						 MVPP2_PRS_TCAM_DSA_TAGGED_BIT);
63962306a36Sopenharmony_ci			/* Clear all ai bits for next iteration */
64062306a36Sopenharmony_ci			mvpp2_prs_sram_ai_update(&pe, 0,
64162306a36Sopenharmony_ci						 MVPP2_PRS_SRAM_AI_MASK);
64262306a36Sopenharmony_ci			/* If packet is tagged continue check vlans */
64362306a36Sopenharmony_ci			mvpp2_prs_sram_next_lu_set(&pe, MVPP2_PRS_LU_VLAN);
64462306a36Sopenharmony_ci		} else {
64562306a36Sopenharmony_ci			/* Set result info bits to 'no vlans' */
64662306a36Sopenharmony_ci			mvpp2_prs_sram_ri_update(&pe, MVPP2_PRS_RI_VLAN_NONE,
64762306a36Sopenharmony_ci						 MVPP2_PRS_RI_VLAN_MASK);
64862306a36Sopenharmony_ci			mvpp2_prs_sram_next_lu_set(&pe, MVPP2_PRS_LU_L2);
64962306a36Sopenharmony_ci		}
65062306a36Sopenharmony_ci		/* Mask/unmask all ports, depending on dsa type */
65162306a36Sopenharmony_ci		mvpp2_prs_tcam_port_map_set(&pe, port_mask);
65262306a36Sopenharmony_ci	}
65362306a36Sopenharmony_ci
65462306a36Sopenharmony_ci	/* Update port mask */
65562306a36Sopenharmony_ci	mvpp2_prs_tcam_port_set(&pe, port, add);
65662306a36Sopenharmony_ci
65762306a36Sopenharmony_ci	mvpp2_prs_hw_write(priv, &pe);
65862306a36Sopenharmony_ci}
65962306a36Sopenharmony_ci
66062306a36Sopenharmony_ci/* Search for existing single/triple vlan entry */
66162306a36Sopenharmony_cistatic int mvpp2_prs_vlan_find(struct mvpp2 *priv, unsigned short tpid, int ai)
66262306a36Sopenharmony_ci{
66362306a36Sopenharmony_ci	struct mvpp2_prs_entry pe;
66462306a36Sopenharmony_ci	int tid;
66562306a36Sopenharmony_ci
66662306a36Sopenharmony_ci	/* Go through the all entries with MVPP2_PRS_LU_VLAN */
66762306a36Sopenharmony_ci	for (tid = MVPP2_PE_FIRST_FREE_TID;
66862306a36Sopenharmony_ci	     tid <= MVPP2_PE_LAST_FREE_TID; tid++) {
66962306a36Sopenharmony_ci		unsigned int ri_bits, ai_bits;
67062306a36Sopenharmony_ci		bool match;
67162306a36Sopenharmony_ci
67262306a36Sopenharmony_ci		if (!priv->prs_shadow[tid].valid ||
67362306a36Sopenharmony_ci		    priv->prs_shadow[tid].lu != MVPP2_PRS_LU_VLAN)
67462306a36Sopenharmony_ci			continue;
67562306a36Sopenharmony_ci
67662306a36Sopenharmony_ci		mvpp2_prs_init_from_hw(priv, &pe, tid);
67762306a36Sopenharmony_ci		match = mvpp2_prs_tcam_data_cmp(&pe, 0, tpid);
67862306a36Sopenharmony_ci		if (!match)
67962306a36Sopenharmony_ci			continue;
68062306a36Sopenharmony_ci
68162306a36Sopenharmony_ci		/* Get vlan type */
68262306a36Sopenharmony_ci		ri_bits = mvpp2_prs_sram_ri_get(&pe);
68362306a36Sopenharmony_ci		ri_bits &= MVPP2_PRS_RI_VLAN_MASK;
68462306a36Sopenharmony_ci
68562306a36Sopenharmony_ci		/* Get current ai value from tcam */
68662306a36Sopenharmony_ci		ai_bits = mvpp2_prs_tcam_ai_get(&pe);
68762306a36Sopenharmony_ci		/* Clear double vlan bit */
68862306a36Sopenharmony_ci		ai_bits &= ~MVPP2_PRS_DBL_VLAN_AI_BIT;
68962306a36Sopenharmony_ci
69062306a36Sopenharmony_ci		if (ai != ai_bits)
69162306a36Sopenharmony_ci			continue;
69262306a36Sopenharmony_ci
69362306a36Sopenharmony_ci		if (ri_bits == MVPP2_PRS_RI_VLAN_SINGLE ||
69462306a36Sopenharmony_ci		    ri_bits == MVPP2_PRS_RI_VLAN_TRIPLE)
69562306a36Sopenharmony_ci			return tid;
69662306a36Sopenharmony_ci	}
69762306a36Sopenharmony_ci
69862306a36Sopenharmony_ci	return -ENOENT;
69962306a36Sopenharmony_ci}
70062306a36Sopenharmony_ci
70162306a36Sopenharmony_ci/* Add/update single/triple vlan entry */
70262306a36Sopenharmony_cistatic int mvpp2_prs_vlan_add(struct mvpp2 *priv, unsigned short tpid, int ai,
70362306a36Sopenharmony_ci			      unsigned int port_map)
70462306a36Sopenharmony_ci{
70562306a36Sopenharmony_ci	struct mvpp2_prs_entry pe;
70662306a36Sopenharmony_ci	int tid_aux, tid;
70762306a36Sopenharmony_ci	int ret = 0;
70862306a36Sopenharmony_ci
70962306a36Sopenharmony_ci	memset(&pe, 0, sizeof(pe));
71062306a36Sopenharmony_ci
71162306a36Sopenharmony_ci	tid = mvpp2_prs_vlan_find(priv, tpid, ai);
71262306a36Sopenharmony_ci
71362306a36Sopenharmony_ci	if (tid < 0) {
71462306a36Sopenharmony_ci		/* Create new tcam entry */
71562306a36Sopenharmony_ci		tid = mvpp2_prs_tcam_first_free(priv, MVPP2_PE_LAST_FREE_TID,
71662306a36Sopenharmony_ci						MVPP2_PE_FIRST_FREE_TID);
71762306a36Sopenharmony_ci		if (tid < 0)
71862306a36Sopenharmony_ci			return tid;
71962306a36Sopenharmony_ci
72062306a36Sopenharmony_ci		/* Get last double vlan tid */
72162306a36Sopenharmony_ci		for (tid_aux = MVPP2_PE_LAST_FREE_TID;
72262306a36Sopenharmony_ci		     tid_aux >= MVPP2_PE_FIRST_FREE_TID; tid_aux--) {
72362306a36Sopenharmony_ci			unsigned int ri_bits;
72462306a36Sopenharmony_ci
72562306a36Sopenharmony_ci			if (!priv->prs_shadow[tid_aux].valid ||
72662306a36Sopenharmony_ci			    priv->prs_shadow[tid_aux].lu != MVPP2_PRS_LU_VLAN)
72762306a36Sopenharmony_ci				continue;
72862306a36Sopenharmony_ci
72962306a36Sopenharmony_ci			mvpp2_prs_init_from_hw(priv, &pe, tid_aux);
73062306a36Sopenharmony_ci			ri_bits = mvpp2_prs_sram_ri_get(&pe);
73162306a36Sopenharmony_ci			if ((ri_bits & MVPP2_PRS_RI_VLAN_MASK) ==
73262306a36Sopenharmony_ci			    MVPP2_PRS_RI_VLAN_DOUBLE)
73362306a36Sopenharmony_ci				break;
73462306a36Sopenharmony_ci		}
73562306a36Sopenharmony_ci
73662306a36Sopenharmony_ci		if (tid <= tid_aux)
73762306a36Sopenharmony_ci			return -EINVAL;
73862306a36Sopenharmony_ci
73962306a36Sopenharmony_ci		memset(&pe, 0, sizeof(pe));
74062306a36Sopenharmony_ci		pe.index = tid;
74162306a36Sopenharmony_ci		mvpp2_prs_tcam_lu_set(&pe, MVPP2_PRS_LU_VLAN);
74262306a36Sopenharmony_ci
74362306a36Sopenharmony_ci		mvpp2_prs_match_etype(&pe, 0, tpid);
74462306a36Sopenharmony_ci
74562306a36Sopenharmony_ci		/* VLAN tag detected, proceed with VID filtering */
74662306a36Sopenharmony_ci		mvpp2_prs_sram_next_lu_set(&pe, MVPP2_PRS_LU_VID);
74762306a36Sopenharmony_ci
74862306a36Sopenharmony_ci		/* Clear all ai bits for next iteration */
74962306a36Sopenharmony_ci		mvpp2_prs_sram_ai_update(&pe, 0, MVPP2_PRS_SRAM_AI_MASK);
75062306a36Sopenharmony_ci
75162306a36Sopenharmony_ci		if (ai == MVPP2_PRS_SINGLE_VLAN_AI) {
75262306a36Sopenharmony_ci			mvpp2_prs_sram_ri_update(&pe, MVPP2_PRS_RI_VLAN_SINGLE,
75362306a36Sopenharmony_ci						 MVPP2_PRS_RI_VLAN_MASK);
75462306a36Sopenharmony_ci		} else {
75562306a36Sopenharmony_ci			ai |= MVPP2_PRS_DBL_VLAN_AI_BIT;
75662306a36Sopenharmony_ci			mvpp2_prs_sram_ri_update(&pe, MVPP2_PRS_RI_VLAN_TRIPLE,
75762306a36Sopenharmony_ci						 MVPP2_PRS_RI_VLAN_MASK);
75862306a36Sopenharmony_ci		}
75962306a36Sopenharmony_ci		mvpp2_prs_tcam_ai_update(&pe, ai, MVPP2_PRS_SRAM_AI_MASK);
76062306a36Sopenharmony_ci
76162306a36Sopenharmony_ci		mvpp2_prs_shadow_set(priv, pe.index, MVPP2_PRS_LU_VLAN);
76262306a36Sopenharmony_ci	} else {
76362306a36Sopenharmony_ci		mvpp2_prs_init_from_hw(priv, &pe, tid);
76462306a36Sopenharmony_ci	}
76562306a36Sopenharmony_ci	/* Update ports' mask */
76662306a36Sopenharmony_ci	mvpp2_prs_tcam_port_map_set(&pe, port_map);
76762306a36Sopenharmony_ci
76862306a36Sopenharmony_ci	mvpp2_prs_hw_write(priv, &pe);
76962306a36Sopenharmony_ci
77062306a36Sopenharmony_ci	return ret;
77162306a36Sopenharmony_ci}
77262306a36Sopenharmony_ci
77362306a36Sopenharmony_ci/* Get first free double vlan ai number */
77462306a36Sopenharmony_cistatic int mvpp2_prs_double_vlan_ai_free_get(struct mvpp2 *priv)
77562306a36Sopenharmony_ci{
77662306a36Sopenharmony_ci	int i;
77762306a36Sopenharmony_ci
77862306a36Sopenharmony_ci	for (i = 1; i < MVPP2_PRS_DBL_VLANS_MAX; i++) {
77962306a36Sopenharmony_ci		if (!priv->prs_double_vlans[i])
78062306a36Sopenharmony_ci			return i;
78162306a36Sopenharmony_ci	}
78262306a36Sopenharmony_ci
78362306a36Sopenharmony_ci	return -EINVAL;
78462306a36Sopenharmony_ci}
78562306a36Sopenharmony_ci
78662306a36Sopenharmony_ci/* Search for existing double vlan entry */
78762306a36Sopenharmony_cistatic int mvpp2_prs_double_vlan_find(struct mvpp2 *priv, unsigned short tpid1,
78862306a36Sopenharmony_ci				      unsigned short tpid2)
78962306a36Sopenharmony_ci{
79062306a36Sopenharmony_ci	struct mvpp2_prs_entry pe;
79162306a36Sopenharmony_ci	int tid;
79262306a36Sopenharmony_ci
79362306a36Sopenharmony_ci	/* Go through the all entries with MVPP2_PRS_LU_VLAN */
79462306a36Sopenharmony_ci	for (tid = MVPP2_PE_FIRST_FREE_TID;
79562306a36Sopenharmony_ci	     tid <= MVPP2_PE_LAST_FREE_TID; tid++) {
79662306a36Sopenharmony_ci		unsigned int ri_mask;
79762306a36Sopenharmony_ci		bool match;
79862306a36Sopenharmony_ci
79962306a36Sopenharmony_ci		if (!priv->prs_shadow[tid].valid ||
80062306a36Sopenharmony_ci		    priv->prs_shadow[tid].lu != MVPP2_PRS_LU_VLAN)
80162306a36Sopenharmony_ci			continue;
80262306a36Sopenharmony_ci
80362306a36Sopenharmony_ci		mvpp2_prs_init_from_hw(priv, &pe, tid);
80462306a36Sopenharmony_ci
80562306a36Sopenharmony_ci		match = mvpp2_prs_tcam_data_cmp(&pe, 0, tpid1) &&
80662306a36Sopenharmony_ci			mvpp2_prs_tcam_data_cmp(&pe, 4, tpid2);
80762306a36Sopenharmony_ci
80862306a36Sopenharmony_ci		if (!match)
80962306a36Sopenharmony_ci			continue;
81062306a36Sopenharmony_ci
81162306a36Sopenharmony_ci		ri_mask = mvpp2_prs_sram_ri_get(&pe) & MVPP2_PRS_RI_VLAN_MASK;
81262306a36Sopenharmony_ci		if (ri_mask == MVPP2_PRS_RI_VLAN_DOUBLE)
81362306a36Sopenharmony_ci			return tid;
81462306a36Sopenharmony_ci	}
81562306a36Sopenharmony_ci
81662306a36Sopenharmony_ci	return -ENOENT;
81762306a36Sopenharmony_ci}
81862306a36Sopenharmony_ci
81962306a36Sopenharmony_ci/* Add or update double vlan entry */
82062306a36Sopenharmony_cistatic int mvpp2_prs_double_vlan_add(struct mvpp2 *priv, unsigned short tpid1,
82162306a36Sopenharmony_ci				     unsigned short tpid2,
82262306a36Sopenharmony_ci				     unsigned int port_map)
82362306a36Sopenharmony_ci{
82462306a36Sopenharmony_ci	int tid_aux, tid, ai, ret = 0;
82562306a36Sopenharmony_ci	struct mvpp2_prs_entry pe;
82662306a36Sopenharmony_ci
82762306a36Sopenharmony_ci	memset(&pe, 0, sizeof(pe));
82862306a36Sopenharmony_ci
82962306a36Sopenharmony_ci	tid = mvpp2_prs_double_vlan_find(priv, tpid1, tpid2);
83062306a36Sopenharmony_ci
83162306a36Sopenharmony_ci	if (tid < 0) {
83262306a36Sopenharmony_ci		/* Create new tcam entry */
83362306a36Sopenharmony_ci		tid = mvpp2_prs_tcam_first_free(priv, MVPP2_PE_FIRST_FREE_TID,
83462306a36Sopenharmony_ci				MVPP2_PE_LAST_FREE_TID);
83562306a36Sopenharmony_ci		if (tid < 0)
83662306a36Sopenharmony_ci			return tid;
83762306a36Sopenharmony_ci
83862306a36Sopenharmony_ci		/* Set ai value for new double vlan entry */
83962306a36Sopenharmony_ci		ai = mvpp2_prs_double_vlan_ai_free_get(priv);
84062306a36Sopenharmony_ci		if (ai < 0)
84162306a36Sopenharmony_ci			return ai;
84262306a36Sopenharmony_ci
84362306a36Sopenharmony_ci		/* Get first single/triple vlan tid */
84462306a36Sopenharmony_ci		for (tid_aux = MVPP2_PE_FIRST_FREE_TID;
84562306a36Sopenharmony_ci		     tid_aux <= MVPP2_PE_LAST_FREE_TID; tid_aux++) {
84662306a36Sopenharmony_ci			unsigned int ri_bits;
84762306a36Sopenharmony_ci
84862306a36Sopenharmony_ci			if (!priv->prs_shadow[tid_aux].valid ||
84962306a36Sopenharmony_ci			    priv->prs_shadow[tid_aux].lu != MVPP2_PRS_LU_VLAN)
85062306a36Sopenharmony_ci				continue;
85162306a36Sopenharmony_ci
85262306a36Sopenharmony_ci			mvpp2_prs_init_from_hw(priv, &pe, tid_aux);
85362306a36Sopenharmony_ci			ri_bits = mvpp2_prs_sram_ri_get(&pe);
85462306a36Sopenharmony_ci			ri_bits &= MVPP2_PRS_RI_VLAN_MASK;
85562306a36Sopenharmony_ci			if (ri_bits == MVPP2_PRS_RI_VLAN_SINGLE ||
85662306a36Sopenharmony_ci			    ri_bits == MVPP2_PRS_RI_VLAN_TRIPLE)
85762306a36Sopenharmony_ci				break;
85862306a36Sopenharmony_ci		}
85962306a36Sopenharmony_ci
86062306a36Sopenharmony_ci		if (tid >= tid_aux)
86162306a36Sopenharmony_ci			return -ERANGE;
86262306a36Sopenharmony_ci
86362306a36Sopenharmony_ci		memset(&pe, 0, sizeof(pe));
86462306a36Sopenharmony_ci		mvpp2_prs_tcam_lu_set(&pe, MVPP2_PRS_LU_VLAN);
86562306a36Sopenharmony_ci		pe.index = tid;
86662306a36Sopenharmony_ci
86762306a36Sopenharmony_ci		priv->prs_double_vlans[ai] = true;
86862306a36Sopenharmony_ci
86962306a36Sopenharmony_ci		mvpp2_prs_match_etype(&pe, 0, tpid1);
87062306a36Sopenharmony_ci		mvpp2_prs_match_etype(&pe, 4, tpid2);
87162306a36Sopenharmony_ci
87262306a36Sopenharmony_ci		mvpp2_prs_sram_next_lu_set(&pe, MVPP2_PRS_LU_VLAN);
87362306a36Sopenharmony_ci		/* Shift 4 bytes - skip outer vlan tag */
87462306a36Sopenharmony_ci		mvpp2_prs_sram_shift_set(&pe, MVPP2_VLAN_TAG_LEN,
87562306a36Sopenharmony_ci					 MVPP2_PRS_SRAM_OP_SEL_SHIFT_ADD);
87662306a36Sopenharmony_ci		mvpp2_prs_sram_ri_update(&pe, MVPP2_PRS_RI_VLAN_DOUBLE,
87762306a36Sopenharmony_ci					 MVPP2_PRS_RI_VLAN_MASK);
87862306a36Sopenharmony_ci		mvpp2_prs_sram_ai_update(&pe, ai | MVPP2_PRS_DBL_VLAN_AI_BIT,
87962306a36Sopenharmony_ci					 MVPP2_PRS_SRAM_AI_MASK);
88062306a36Sopenharmony_ci
88162306a36Sopenharmony_ci		mvpp2_prs_shadow_set(priv, pe.index, MVPP2_PRS_LU_VLAN);
88262306a36Sopenharmony_ci	} else {
88362306a36Sopenharmony_ci		mvpp2_prs_init_from_hw(priv, &pe, tid);
88462306a36Sopenharmony_ci	}
88562306a36Sopenharmony_ci
88662306a36Sopenharmony_ci	/* Update ports' mask */
88762306a36Sopenharmony_ci	mvpp2_prs_tcam_port_map_set(&pe, port_map);
88862306a36Sopenharmony_ci	mvpp2_prs_hw_write(priv, &pe);
88962306a36Sopenharmony_ci
89062306a36Sopenharmony_ci	return ret;
89162306a36Sopenharmony_ci}
89262306a36Sopenharmony_ci
89362306a36Sopenharmony_ci/* IPv4 header parsing for fragmentation and L4 offset */
89462306a36Sopenharmony_cistatic int mvpp2_prs_ip4_proto(struct mvpp2 *priv, unsigned short proto,
89562306a36Sopenharmony_ci			       unsigned int ri, unsigned int ri_mask)
89662306a36Sopenharmony_ci{
89762306a36Sopenharmony_ci	struct mvpp2_prs_entry pe;
89862306a36Sopenharmony_ci	int tid;
89962306a36Sopenharmony_ci
90062306a36Sopenharmony_ci	if ((proto != IPPROTO_TCP) && (proto != IPPROTO_UDP) &&
90162306a36Sopenharmony_ci	    (proto != IPPROTO_IGMP))
90262306a36Sopenharmony_ci		return -EINVAL;
90362306a36Sopenharmony_ci
90462306a36Sopenharmony_ci	/* Not fragmented packet */
90562306a36Sopenharmony_ci	tid = mvpp2_prs_tcam_first_free(priv, MVPP2_PE_FIRST_FREE_TID,
90662306a36Sopenharmony_ci					MVPP2_PE_LAST_FREE_TID);
90762306a36Sopenharmony_ci	if (tid < 0)
90862306a36Sopenharmony_ci		return tid;
90962306a36Sopenharmony_ci
91062306a36Sopenharmony_ci	memset(&pe, 0, sizeof(pe));
91162306a36Sopenharmony_ci	mvpp2_prs_tcam_lu_set(&pe, MVPP2_PRS_LU_IP4);
91262306a36Sopenharmony_ci	pe.index = tid;
91362306a36Sopenharmony_ci
91462306a36Sopenharmony_ci	/* Finished: go to flowid generation */
91562306a36Sopenharmony_ci	mvpp2_prs_sram_next_lu_set(&pe, MVPP2_PRS_LU_FLOWS);
91662306a36Sopenharmony_ci	mvpp2_prs_sram_bits_set(&pe, MVPP2_PRS_SRAM_LU_GEN_BIT, 1);
91762306a36Sopenharmony_ci
91862306a36Sopenharmony_ci	/* Set L3 offset */
91962306a36Sopenharmony_ci	mvpp2_prs_sram_offset_set(&pe, MVPP2_PRS_SRAM_UDF_TYPE_L3, -4,
92062306a36Sopenharmony_ci				  MVPP2_PRS_SRAM_OP_SEL_UDF_ADD);
92162306a36Sopenharmony_ci	mvpp2_prs_sram_ai_update(&pe, 0, MVPP2_PRS_IPV4_DIP_AI_BIT);
92262306a36Sopenharmony_ci	mvpp2_prs_sram_ri_update(&pe, ri, ri_mask | MVPP2_PRS_RI_IP_FRAG_MASK);
92362306a36Sopenharmony_ci
92462306a36Sopenharmony_ci	mvpp2_prs_tcam_data_byte_set(&pe, 2, 0x00,
92562306a36Sopenharmony_ci				     MVPP2_PRS_TCAM_PROTO_MASK_L);
92662306a36Sopenharmony_ci	mvpp2_prs_tcam_data_byte_set(&pe, 3, 0x00,
92762306a36Sopenharmony_ci				     MVPP2_PRS_TCAM_PROTO_MASK);
92862306a36Sopenharmony_ci
92962306a36Sopenharmony_ci	mvpp2_prs_tcam_data_byte_set(&pe, 5, proto, MVPP2_PRS_TCAM_PROTO_MASK);
93062306a36Sopenharmony_ci	mvpp2_prs_tcam_ai_update(&pe, MVPP2_PRS_IPV4_DIP_AI_BIT,
93162306a36Sopenharmony_ci				 MVPP2_PRS_IPV4_DIP_AI_BIT);
93262306a36Sopenharmony_ci	/* Unmask all ports */
93362306a36Sopenharmony_ci	mvpp2_prs_tcam_port_map_set(&pe, MVPP2_PRS_PORT_MASK);
93462306a36Sopenharmony_ci
93562306a36Sopenharmony_ci	/* Update shadow table and hw entry */
93662306a36Sopenharmony_ci	mvpp2_prs_shadow_set(priv, pe.index, MVPP2_PRS_LU_IP4);
93762306a36Sopenharmony_ci	mvpp2_prs_hw_write(priv, &pe);
93862306a36Sopenharmony_ci
93962306a36Sopenharmony_ci	/* Fragmented packet */
94062306a36Sopenharmony_ci	tid = mvpp2_prs_tcam_first_free(priv, MVPP2_PE_FIRST_FREE_TID,
94162306a36Sopenharmony_ci					MVPP2_PE_LAST_FREE_TID);
94262306a36Sopenharmony_ci	if (tid < 0)
94362306a36Sopenharmony_ci		return tid;
94462306a36Sopenharmony_ci
94562306a36Sopenharmony_ci	pe.index = tid;
94662306a36Sopenharmony_ci	/* Clear ri before updating */
94762306a36Sopenharmony_ci	pe.sram[MVPP2_PRS_SRAM_RI_WORD] = 0x0;
94862306a36Sopenharmony_ci	pe.sram[MVPP2_PRS_SRAM_RI_CTRL_WORD] = 0x0;
94962306a36Sopenharmony_ci	mvpp2_prs_sram_ri_update(&pe, ri, ri_mask);
95062306a36Sopenharmony_ci
95162306a36Sopenharmony_ci	mvpp2_prs_sram_ri_update(&pe, ri | MVPP2_PRS_RI_IP_FRAG_TRUE,
95262306a36Sopenharmony_ci				 ri_mask | MVPP2_PRS_RI_IP_FRAG_MASK);
95362306a36Sopenharmony_ci
95462306a36Sopenharmony_ci	mvpp2_prs_tcam_data_byte_set(&pe, 2, 0x00, 0x0);
95562306a36Sopenharmony_ci	mvpp2_prs_tcam_data_byte_set(&pe, 3, 0x00, 0x0);
95662306a36Sopenharmony_ci
95762306a36Sopenharmony_ci	/* Update shadow table and hw entry */
95862306a36Sopenharmony_ci	mvpp2_prs_shadow_set(priv, pe.index, MVPP2_PRS_LU_IP4);
95962306a36Sopenharmony_ci	mvpp2_prs_hw_write(priv, &pe);
96062306a36Sopenharmony_ci
96162306a36Sopenharmony_ci	return 0;
96262306a36Sopenharmony_ci}
96362306a36Sopenharmony_ci
96462306a36Sopenharmony_ci/* IPv4 L3 multicast or broadcast */
96562306a36Sopenharmony_cistatic int mvpp2_prs_ip4_cast(struct mvpp2 *priv, unsigned short l3_cast)
96662306a36Sopenharmony_ci{
96762306a36Sopenharmony_ci	struct mvpp2_prs_entry pe;
96862306a36Sopenharmony_ci	int mask, tid;
96962306a36Sopenharmony_ci
97062306a36Sopenharmony_ci	tid = mvpp2_prs_tcam_first_free(priv, MVPP2_PE_FIRST_FREE_TID,
97162306a36Sopenharmony_ci					MVPP2_PE_LAST_FREE_TID);
97262306a36Sopenharmony_ci	if (tid < 0)
97362306a36Sopenharmony_ci		return tid;
97462306a36Sopenharmony_ci
97562306a36Sopenharmony_ci	memset(&pe, 0, sizeof(pe));
97662306a36Sopenharmony_ci	mvpp2_prs_tcam_lu_set(&pe, MVPP2_PRS_LU_IP4);
97762306a36Sopenharmony_ci	pe.index = tid;
97862306a36Sopenharmony_ci
97962306a36Sopenharmony_ci	switch (l3_cast) {
98062306a36Sopenharmony_ci	case MVPP2_PRS_L3_MULTI_CAST:
98162306a36Sopenharmony_ci		mvpp2_prs_tcam_data_byte_set(&pe, 0, MVPP2_PRS_IPV4_MC,
98262306a36Sopenharmony_ci					     MVPP2_PRS_IPV4_MC_MASK);
98362306a36Sopenharmony_ci		mvpp2_prs_sram_ri_update(&pe, MVPP2_PRS_RI_L3_MCAST,
98462306a36Sopenharmony_ci					 MVPP2_PRS_RI_L3_ADDR_MASK);
98562306a36Sopenharmony_ci		break;
98662306a36Sopenharmony_ci	case  MVPP2_PRS_L3_BROAD_CAST:
98762306a36Sopenharmony_ci		mask = MVPP2_PRS_IPV4_BC_MASK;
98862306a36Sopenharmony_ci		mvpp2_prs_tcam_data_byte_set(&pe, 0, mask, mask);
98962306a36Sopenharmony_ci		mvpp2_prs_tcam_data_byte_set(&pe, 1, mask, mask);
99062306a36Sopenharmony_ci		mvpp2_prs_tcam_data_byte_set(&pe, 2, mask, mask);
99162306a36Sopenharmony_ci		mvpp2_prs_tcam_data_byte_set(&pe, 3, mask, mask);
99262306a36Sopenharmony_ci		mvpp2_prs_sram_ri_update(&pe, MVPP2_PRS_RI_L3_BCAST,
99362306a36Sopenharmony_ci					 MVPP2_PRS_RI_L3_ADDR_MASK);
99462306a36Sopenharmony_ci		break;
99562306a36Sopenharmony_ci	default:
99662306a36Sopenharmony_ci		return -EINVAL;
99762306a36Sopenharmony_ci	}
99862306a36Sopenharmony_ci
99962306a36Sopenharmony_ci	/* Go again to ipv4 */
100062306a36Sopenharmony_ci	mvpp2_prs_sram_next_lu_set(&pe, MVPP2_PRS_LU_IP4);
100162306a36Sopenharmony_ci
100262306a36Sopenharmony_ci	mvpp2_prs_sram_ai_update(&pe, MVPP2_PRS_IPV4_DIP_AI_BIT,
100362306a36Sopenharmony_ci				 MVPP2_PRS_IPV4_DIP_AI_BIT);
100462306a36Sopenharmony_ci
100562306a36Sopenharmony_ci	/* Shift back to IPv4 proto */
100662306a36Sopenharmony_ci	mvpp2_prs_sram_shift_set(&pe, -12, MVPP2_PRS_SRAM_OP_SEL_SHIFT_ADD);
100762306a36Sopenharmony_ci
100862306a36Sopenharmony_ci	mvpp2_prs_tcam_ai_update(&pe, 0, MVPP2_PRS_IPV4_DIP_AI_BIT);
100962306a36Sopenharmony_ci
101062306a36Sopenharmony_ci	/* Unmask all ports */
101162306a36Sopenharmony_ci	mvpp2_prs_tcam_port_map_set(&pe, MVPP2_PRS_PORT_MASK);
101262306a36Sopenharmony_ci
101362306a36Sopenharmony_ci	/* Update shadow table and hw entry */
101462306a36Sopenharmony_ci	mvpp2_prs_shadow_set(priv, pe.index, MVPP2_PRS_LU_IP4);
101562306a36Sopenharmony_ci	mvpp2_prs_hw_write(priv, &pe);
101662306a36Sopenharmony_ci
101762306a36Sopenharmony_ci	return 0;
101862306a36Sopenharmony_ci}
101962306a36Sopenharmony_ci
102062306a36Sopenharmony_ci/* Set entries for protocols over IPv6  */
102162306a36Sopenharmony_cistatic int mvpp2_prs_ip6_proto(struct mvpp2 *priv, unsigned short proto,
102262306a36Sopenharmony_ci			       unsigned int ri, unsigned int ri_mask)
102362306a36Sopenharmony_ci{
102462306a36Sopenharmony_ci	struct mvpp2_prs_entry pe;
102562306a36Sopenharmony_ci	int tid;
102662306a36Sopenharmony_ci
102762306a36Sopenharmony_ci	if ((proto != IPPROTO_TCP) && (proto != IPPROTO_UDP) &&
102862306a36Sopenharmony_ci	    (proto != IPPROTO_ICMPV6) && (proto != IPPROTO_IPIP))
102962306a36Sopenharmony_ci		return -EINVAL;
103062306a36Sopenharmony_ci
103162306a36Sopenharmony_ci	tid = mvpp2_prs_tcam_first_free(priv, MVPP2_PE_FIRST_FREE_TID,
103262306a36Sopenharmony_ci					MVPP2_PE_LAST_FREE_TID);
103362306a36Sopenharmony_ci	if (tid < 0)
103462306a36Sopenharmony_ci		return tid;
103562306a36Sopenharmony_ci
103662306a36Sopenharmony_ci	memset(&pe, 0, sizeof(pe));
103762306a36Sopenharmony_ci	mvpp2_prs_tcam_lu_set(&pe, MVPP2_PRS_LU_IP6);
103862306a36Sopenharmony_ci	pe.index = tid;
103962306a36Sopenharmony_ci
104062306a36Sopenharmony_ci	/* Finished: go to flowid generation */
104162306a36Sopenharmony_ci	mvpp2_prs_sram_next_lu_set(&pe, MVPP2_PRS_LU_FLOWS);
104262306a36Sopenharmony_ci	mvpp2_prs_sram_bits_set(&pe, MVPP2_PRS_SRAM_LU_GEN_BIT, 1);
104362306a36Sopenharmony_ci	mvpp2_prs_sram_ri_update(&pe, ri, ri_mask);
104462306a36Sopenharmony_ci	mvpp2_prs_sram_offset_set(&pe, MVPP2_PRS_SRAM_UDF_TYPE_L4,
104562306a36Sopenharmony_ci				  sizeof(struct ipv6hdr) - 6,
104662306a36Sopenharmony_ci				  MVPP2_PRS_SRAM_OP_SEL_UDF_ADD);
104762306a36Sopenharmony_ci
104862306a36Sopenharmony_ci	mvpp2_prs_tcam_data_byte_set(&pe, 0, proto, MVPP2_PRS_TCAM_PROTO_MASK);
104962306a36Sopenharmony_ci	mvpp2_prs_tcam_ai_update(&pe, MVPP2_PRS_IPV6_NO_EXT_AI_BIT,
105062306a36Sopenharmony_ci				 MVPP2_PRS_IPV6_NO_EXT_AI_BIT);
105162306a36Sopenharmony_ci	/* Unmask all ports */
105262306a36Sopenharmony_ci	mvpp2_prs_tcam_port_map_set(&pe, MVPP2_PRS_PORT_MASK);
105362306a36Sopenharmony_ci
105462306a36Sopenharmony_ci	/* Write HW */
105562306a36Sopenharmony_ci	mvpp2_prs_shadow_set(priv, pe.index, MVPP2_PRS_LU_IP6);
105662306a36Sopenharmony_ci	mvpp2_prs_hw_write(priv, &pe);
105762306a36Sopenharmony_ci
105862306a36Sopenharmony_ci	return 0;
105962306a36Sopenharmony_ci}
106062306a36Sopenharmony_ci
106162306a36Sopenharmony_ci/* IPv6 L3 multicast entry */
106262306a36Sopenharmony_cistatic int mvpp2_prs_ip6_cast(struct mvpp2 *priv, unsigned short l3_cast)
106362306a36Sopenharmony_ci{
106462306a36Sopenharmony_ci	struct mvpp2_prs_entry pe;
106562306a36Sopenharmony_ci	int tid;
106662306a36Sopenharmony_ci
106762306a36Sopenharmony_ci	if (l3_cast != MVPP2_PRS_L3_MULTI_CAST)
106862306a36Sopenharmony_ci		return -EINVAL;
106962306a36Sopenharmony_ci
107062306a36Sopenharmony_ci	tid = mvpp2_prs_tcam_first_free(priv, MVPP2_PE_FIRST_FREE_TID,
107162306a36Sopenharmony_ci					MVPP2_PE_LAST_FREE_TID);
107262306a36Sopenharmony_ci	if (tid < 0)
107362306a36Sopenharmony_ci		return tid;
107462306a36Sopenharmony_ci
107562306a36Sopenharmony_ci	memset(&pe, 0, sizeof(pe));
107662306a36Sopenharmony_ci	mvpp2_prs_tcam_lu_set(&pe, MVPP2_PRS_LU_IP6);
107762306a36Sopenharmony_ci	pe.index = tid;
107862306a36Sopenharmony_ci
107962306a36Sopenharmony_ci	/* Finished: go to flowid generation */
108062306a36Sopenharmony_ci	mvpp2_prs_sram_next_lu_set(&pe, MVPP2_PRS_LU_IP6);
108162306a36Sopenharmony_ci	mvpp2_prs_sram_ri_update(&pe, MVPP2_PRS_RI_L3_MCAST,
108262306a36Sopenharmony_ci				 MVPP2_PRS_RI_L3_ADDR_MASK);
108362306a36Sopenharmony_ci	mvpp2_prs_sram_ai_update(&pe, MVPP2_PRS_IPV6_NO_EXT_AI_BIT,
108462306a36Sopenharmony_ci				 MVPP2_PRS_IPV6_NO_EXT_AI_BIT);
108562306a36Sopenharmony_ci	/* Shift back to IPv6 NH */
108662306a36Sopenharmony_ci	mvpp2_prs_sram_shift_set(&pe, -18, MVPP2_PRS_SRAM_OP_SEL_SHIFT_ADD);
108762306a36Sopenharmony_ci
108862306a36Sopenharmony_ci	mvpp2_prs_tcam_data_byte_set(&pe, 0, MVPP2_PRS_IPV6_MC,
108962306a36Sopenharmony_ci				     MVPP2_PRS_IPV6_MC_MASK);
109062306a36Sopenharmony_ci	mvpp2_prs_tcam_ai_update(&pe, 0, MVPP2_PRS_IPV6_NO_EXT_AI_BIT);
109162306a36Sopenharmony_ci	/* Unmask all ports */
109262306a36Sopenharmony_ci	mvpp2_prs_tcam_port_map_set(&pe, MVPP2_PRS_PORT_MASK);
109362306a36Sopenharmony_ci
109462306a36Sopenharmony_ci	/* Update shadow table and hw entry */
109562306a36Sopenharmony_ci	mvpp2_prs_shadow_set(priv, pe.index, MVPP2_PRS_LU_IP6);
109662306a36Sopenharmony_ci	mvpp2_prs_hw_write(priv, &pe);
109762306a36Sopenharmony_ci
109862306a36Sopenharmony_ci	return 0;
109962306a36Sopenharmony_ci}
110062306a36Sopenharmony_ci
110162306a36Sopenharmony_ci/* Parser per-port initialization */
110262306a36Sopenharmony_cistatic void mvpp2_prs_hw_port_init(struct mvpp2 *priv, int port, int lu_first,
110362306a36Sopenharmony_ci				   int lu_max, int offset)
110462306a36Sopenharmony_ci{
110562306a36Sopenharmony_ci	u32 val;
110662306a36Sopenharmony_ci
110762306a36Sopenharmony_ci	/* Set lookup ID */
110862306a36Sopenharmony_ci	val = mvpp2_read(priv, MVPP2_PRS_INIT_LOOKUP_REG);
110962306a36Sopenharmony_ci	val &= ~MVPP2_PRS_PORT_LU_MASK(port);
111062306a36Sopenharmony_ci	val |=  MVPP2_PRS_PORT_LU_VAL(port, lu_first);
111162306a36Sopenharmony_ci	mvpp2_write(priv, MVPP2_PRS_INIT_LOOKUP_REG, val);
111262306a36Sopenharmony_ci
111362306a36Sopenharmony_ci	/* Set maximum number of loops for packet received from port */
111462306a36Sopenharmony_ci	val = mvpp2_read(priv, MVPP2_PRS_MAX_LOOP_REG(port));
111562306a36Sopenharmony_ci	val &= ~MVPP2_PRS_MAX_LOOP_MASK(port);
111662306a36Sopenharmony_ci	val |= MVPP2_PRS_MAX_LOOP_VAL(port, lu_max);
111762306a36Sopenharmony_ci	mvpp2_write(priv, MVPP2_PRS_MAX_LOOP_REG(port), val);
111862306a36Sopenharmony_ci
111962306a36Sopenharmony_ci	/* Set initial offset for packet header extraction for the first
112062306a36Sopenharmony_ci	 * searching loop
112162306a36Sopenharmony_ci	 */
112262306a36Sopenharmony_ci	val = mvpp2_read(priv, MVPP2_PRS_INIT_OFFS_REG(port));
112362306a36Sopenharmony_ci	val &= ~MVPP2_PRS_INIT_OFF_MASK(port);
112462306a36Sopenharmony_ci	val |= MVPP2_PRS_INIT_OFF_VAL(port, offset);
112562306a36Sopenharmony_ci	mvpp2_write(priv, MVPP2_PRS_INIT_OFFS_REG(port), val);
112662306a36Sopenharmony_ci}
112762306a36Sopenharmony_ci
112862306a36Sopenharmony_ci/* Default flow entries initialization for all ports */
112962306a36Sopenharmony_cistatic void mvpp2_prs_def_flow_init(struct mvpp2 *priv)
113062306a36Sopenharmony_ci{
113162306a36Sopenharmony_ci	struct mvpp2_prs_entry pe;
113262306a36Sopenharmony_ci	int port;
113362306a36Sopenharmony_ci
113462306a36Sopenharmony_ci	for (port = 0; port < MVPP2_MAX_PORTS; port++) {
113562306a36Sopenharmony_ci		memset(&pe, 0, sizeof(pe));
113662306a36Sopenharmony_ci		mvpp2_prs_tcam_lu_set(&pe, MVPP2_PRS_LU_FLOWS);
113762306a36Sopenharmony_ci		pe.index = MVPP2_PE_FIRST_DEFAULT_FLOW - port;
113862306a36Sopenharmony_ci
113962306a36Sopenharmony_ci		/* Mask all ports */
114062306a36Sopenharmony_ci		mvpp2_prs_tcam_port_map_set(&pe, 0);
114162306a36Sopenharmony_ci
114262306a36Sopenharmony_ci		/* Set flow ID*/
114362306a36Sopenharmony_ci		mvpp2_prs_sram_ai_update(&pe, port, MVPP2_PRS_FLOW_ID_MASK);
114462306a36Sopenharmony_ci		mvpp2_prs_sram_bits_set(&pe, MVPP2_PRS_SRAM_LU_DONE_BIT, 1);
114562306a36Sopenharmony_ci
114662306a36Sopenharmony_ci		/* Update shadow table and hw entry */
114762306a36Sopenharmony_ci		mvpp2_prs_shadow_set(priv, pe.index, MVPP2_PRS_LU_FLOWS);
114862306a36Sopenharmony_ci		mvpp2_prs_hw_write(priv, &pe);
114962306a36Sopenharmony_ci	}
115062306a36Sopenharmony_ci}
115162306a36Sopenharmony_ci
115262306a36Sopenharmony_ci/* Set default entry for Marvell Header field */
115362306a36Sopenharmony_cistatic void mvpp2_prs_mh_init(struct mvpp2 *priv)
115462306a36Sopenharmony_ci{
115562306a36Sopenharmony_ci	struct mvpp2_prs_entry pe;
115662306a36Sopenharmony_ci
115762306a36Sopenharmony_ci	memset(&pe, 0, sizeof(pe));
115862306a36Sopenharmony_ci
115962306a36Sopenharmony_ci	pe.index = MVPP2_PE_MH_DEFAULT;
116062306a36Sopenharmony_ci	mvpp2_prs_tcam_lu_set(&pe, MVPP2_PRS_LU_MH);
116162306a36Sopenharmony_ci	mvpp2_prs_sram_shift_set(&pe, MVPP2_MH_SIZE,
116262306a36Sopenharmony_ci				 MVPP2_PRS_SRAM_OP_SEL_SHIFT_ADD);
116362306a36Sopenharmony_ci	mvpp2_prs_sram_next_lu_set(&pe, MVPP2_PRS_LU_MAC);
116462306a36Sopenharmony_ci
116562306a36Sopenharmony_ci	/* Unmask all ports */
116662306a36Sopenharmony_ci	mvpp2_prs_tcam_port_map_set(&pe, MVPP2_PRS_PORT_MASK);
116762306a36Sopenharmony_ci
116862306a36Sopenharmony_ci	/* Update shadow table and hw entry */
116962306a36Sopenharmony_ci	mvpp2_prs_shadow_set(priv, pe.index, MVPP2_PRS_LU_MH);
117062306a36Sopenharmony_ci	mvpp2_prs_hw_write(priv, &pe);
117162306a36Sopenharmony_ci
117262306a36Sopenharmony_ci	/* Set MH entry that skip parser */
117362306a36Sopenharmony_ci	pe.index = MVPP2_PE_MH_SKIP_PRS;
117462306a36Sopenharmony_ci	mvpp2_prs_tcam_lu_set(&pe, MVPP2_PRS_LU_MH);
117562306a36Sopenharmony_ci	mvpp2_prs_sram_shift_set(&pe, MVPP2_MH_SIZE,
117662306a36Sopenharmony_ci				 MVPP2_PRS_SRAM_OP_SEL_SHIFT_ADD);
117762306a36Sopenharmony_ci	mvpp2_prs_sram_bits_set(&pe, MVPP2_PRS_SRAM_LU_GEN_BIT, 1);
117862306a36Sopenharmony_ci	mvpp2_prs_sram_next_lu_set(&pe, MVPP2_PRS_LU_FLOWS);
117962306a36Sopenharmony_ci
118062306a36Sopenharmony_ci	/* Mask all ports */
118162306a36Sopenharmony_ci	mvpp2_prs_tcam_port_map_set(&pe, 0);
118262306a36Sopenharmony_ci
118362306a36Sopenharmony_ci	/* Update shadow table and hw entry */
118462306a36Sopenharmony_ci	mvpp2_prs_shadow_set(priv, pe.index, MVPP2_PRS_LU_MH);
118562306a36Sopenharmony_ci	mvpp2_prs_hw_write(priv, &pe);
118662306a36Sopenharmony_ci}
118762306a36Sopenharmony_ci
118862306a36Sopenharmony_ci/* Set default entires (place holder) for promiscuous, non-promiscuous and
118962306a36Sopenharmony_ci * multicast MAC addresses
119062306a36Sopenharmony_ci */
119162306a36Sopenharmony_cistatic void mvpp2_prs_mac_init(struct mvpp2 *priv)
119262306a36Sopenharmony_ci{
119362306a36Sopenharmony_ci	struct mvpp2_prs_entry pe;
119462306a36Sopenharmony_ci
119562306a36Sopenharmony_ci	memset(&pe, 0, sizeof(pe));
119662306a36Sopenharmony_ci
119762306a36Sopenharmony_ci	/* Non-promiscuous mode for all ports - DROP unknown packets */
119862306a36Sopenharmony_ci	pe.index = MVPP2_PE_MAC_NON_PROMISCUOUS;
119962306a36Sopenharmony_ci	mvpp2_prs_tcam_lu_set(&pe, MVPP2_PRS_LU_MAC);
120062306a36Sopenharmony_ci
120162306a36Sopenharmony_ci	mvpp2_prs_sram_ri_update(&pe, MVPP2_PRS_RI_DROP_MASK,
120262306a36Sopenharmony_ci				 MVPP2_PRS_RI_DROP_MASK);
120362306a36Sopenharmony_ci	mvpp2_prs_sram_bits_set(&pe, MVPP2_PRS_SRAM_LU_GEN_BIT, 1);
120462306a36Sopenharmony_ci	mvpp2_prs_sram_next_lu_set(&pe, MVPP2_PRS_LU_FLOWS);
120562306a36Sopenharmony_ci
120662306a36Sopenharmony_ci	/* Unmask all ports */
120762306a36Sopenharmony_ci	mvpp2_prs_tcam_port_map_set(&pe, MVPP2_PRS_PORT_MASK);
120862306a36Sopenharmony_ci
120962306a36Sopenharmony_ci	/* Update shadow table and hw entry */
121062306a36Sopenharmony_ci	mvpp2_prs_shadow_set(priv, pe.index, MVPP2_PRS_LU_MAC);
121162306a36Sopenharmony_ci	mvpp2_prs_hw_write(priv, &pe);
121262306a36Sopenharmony_ci
121362306a36Sopenharmony_ci	/* Create dummy entries for drop all and promiscuous modes */
121462306a36Sopenharmony_ci	mvpp2_prs_drop_fc(priv);
121562306a36Sopenharmony_ci	mvpp2_prs_mac_drop_all_set(priv, 0, false);
121662306a36Sopenharmony_ci	mvpp2_prs_mac_promisc_set(priv, 0, MVPP2_PRS_L2_UNI_CAST, false);
121762306a36Sopenharmony_ci	mvpp2_prs_mac_promisc_set(priv, 0, MVPP2_PRS_L2_MULTI_CAST, false);
121862306a36Sopenharmony_ci}
121962306a36Sopenharmony_ci
122062306a36Sopenharmony_ci/* Set default entries for various types of dsa packets */
122162306a36Sopenharmony_cistatic void mvpp2_prs_dsa_init(struct mvpp2 *priv)
122262306a36Sopenharmony_ci{
122362306a36Sopenharmony_ci	struct mvpp2_prs_entry pe;
122462306a36Sopenharmony_ci
122562306a36Sopenharmony_ci	/* None tagged EDSA entry - place holder */
122662306a36Sopenharmony_ci	mvpp2_prs_dsa_tag_set(priv, 0, false, MVPP2_PRS_UNTAGGED,
122762306a36Sopenharmony_ci			      MVPP2_PRS_EDSA);
122862306a36Sopenharmony_ci
122962306a36Sopenharmony_ci	/* Tagged EDSA entry - place holder */
123062306a36Sopenharmony_ci	mvpp2_prs_dsa_tag_set(priv, 0, false, MVPP2_PRS_TAGGED, MVPP2_PRS_EDSA);
123162306a36Sopenharmony_ci
123262306a36Sopenharmony_ci	/* None tagged DSA entry - place holder */
123362306a36Sopenharmony_ci	mvpp2_prs_dsa_tag_set(priv, 0, false, MVPP2_PRS_UNTAGGED,
123462306a36Sopenharmony_ci			      MVPP2_PRS_DSA);
123562306a36Sopenharmony_ci
123662306a36Sopenharmony_ci	/* Tagged DSA entry - place holder */
123762306a36Sopenharmony_ci	mvpp2_prs_dsa_tag_set(priv, 0, false, MVPP2_PRS_TAGGED, MVPP2_PRS_DSA);
123862306a36Sopenharmony_ci
123962306a36Sopenharmony_ci	/* None tagged EDSA ethertype entry - place holder*/
124062306a36Sopenharmony_ci	mvpp2_prs_dsa_tag_ethertype_set(priv, 0, false,
124162306a36Sopenharmony_ci					MVPP2_PRS_UNTAGGED, MVPP2_PRS_EDSA);
124262306a36Sopenharmony_ci
124362306a36Sopenharmony_ci	/* Tagged EDSA ethertype entry - place holder*/
124462306a36Sopenharmony_ci	mvpp2_prs_dsa_tag_ethertype_set(priv, 0, false,
124562306a36Sopenharmony_ci					MVPP2_PRS_TAGGED, MVPP2_PRS_EDSA);
124662306a36Sopenharmony_ci
124762306a36Sopenharmony_ci	/* None tagged DSA ethertype entry */
124862306a36Sopenharmony_ci	mvpp2_prs_dsa_tag_ethertype_set(priv, 0, true,
124962306a36Sopenharmony_ci					MVPP2_PRS_UNTAGGED, MVPP2_PRS_DSA);
125062306a36Sopenharmony_ci
125162306a36Sopenharmony_ci	/* Tagged DSA ethertype entry */
125262306a36Sopenharmony_ci	mvpp2_prs_dsa_tag_ethertype_set(priv, 0, true,
125362306a36Sopenharmony_ci					MVPP2_PRS_TAGGED, MVPP2_PRS_DSA);
125462306a36Sopenharmony_ci
125562306a36Sopenharmony_ci	/* Set default entry, in case DSA or EDSA tag not found */
125662306a36Sopenharmony_ci	memset(&pe, 0, sizeof(pe));
125762306a36Sopenharmony_ci	mvpp2_prs_tcam_lu_set(&pe, MVPP2_PRS_LU_DSA);
125862306a36Sopenharmony_ci	pe.index = MVPP2_PE_DSA_DEFAULT;
125962306a36Sopenharmony_ci	mvpp2_prs_sram_next_lu_set(&pe, MVPP2_PRS_LU_VLAN);
126062306a36Sopenharmony_ci
126162306a36Sopenharmony_ci	/* Shift 0 bytes */
126262306a36Sopenharmony_ci	mvpp2_prs_sram_shift_set(&pe, 0, MVPP2_PRS_SRAM_OP_SEL_SHIFT_ADD);
126362306a36Sopenharmony_ci	mvpp2_prs_shadow_set(priv, pe.index, MVPP2_PRS_LU_MAC);
126462306a36Sopenharmony_ci
126562306a36Sopenharmony_ci	/* Clear all sram ai bits for next iteration */
126662306a36Sopenharmony_ci	mvpp2_prs_sram_ai_update(&pe, 0, MVPP2_PRS_SRAM_AI_MASK);
126762306a36Sopenharmony_ci
126862306a36Sopenharmony_ci	/* Unmask all ports */
126962306a36Sopenharmony_ci	mvpp2_prs_tcam_port_map_set(&pe, MVPP2_PRS_PORT_MASK);
127062306a36Sopenharmony_ci
127162306a36Sopenharmony_ci	mvpp2_prs_hw_write(priv, &pe);
127262306a36Sopenharmony_ci}
127362306a36Sopenharmony_ci
127462306a36Sopenharmony_ci/* Initialize parser entries for VID filtering */
127562306a36Sopenharmony_cistatic void mvpp2_prs_vid_init(struct mvpp2 *priv)
127662306a36Sopenharmony_ci{
127762306a36Sopenharmony_ci	struct mvpp2_prs_entry pe;
127862306a36Sopenharmony_ci
127962306a36Sopenharmony_ci	memset(&pe, 0, sizeof(pe));
128062306a36Sopenharmony_ci
128162306a36Sopenharmony_ci	/* Set default vid entry */
128262306a36Sopenharmony_ci	pe.index = MVPP2_PE_VID_FLTR_DEFAULT;
128362306a36Sopenharmony_ci	mvpp2_prs_tcam_lu_set(&pe, MVPP2_PRS_LU_VID);
128462306a36Sopenharmony_ci
128562306a36Sopenharmony_ci	mvpp2_prs_tcam_ai_update(&pe, 0, MVPP2_PRS_EDSA_VID_AI_BIT);
128662306a36Sopenharmony_ci
128762306a36Sopenharmony_ci	/* Skip VLAN header - Set offset to 4 bytes */
128862306a36Sopenharmony_ci	mvpp2_prs_sram_shift_set(&pe, MVPP2_VLAN_TAG_LEN,
128962306a36Sopenharmony_ci				 MVPP2_PRS_SRAM_OP_SEL_SHIFT_ADD);
129062306a36Sopenharmony_ci
129162306a36Sopenharmony_ci	/* Clear all ai bits for next iteration */
129262306a36Sopenharmony_ci	mvpp2_prs_sram_ai_update(&pe, 0, MVPP2_PRS_SRAM_AI_MASK);
129362306a36Sopenharmony_ci
129462306a36Sopenharmony_ci	mvpp2_prs_sram_next_lu_set(&pe, MVPP2_PRS_LU_L2);
129562306a36Sopenharmony_ci
129662306a36Sopenharmony_ci	/* Unmask all ports */
129762306a36Sopenharmony_ci	mvpp2_prs_tcam_port_map_set(&pe, MVPP2_PRS_PORT_MASK);
129862306a36Sopenharmony_ci
129962306a36Sopenharmony_ci	/* Update shadow table and hw entry */
130062306a36Sopenharmony_ci	mvpp2_prs_shadow_set(priv, pe.index, MVPP2_PRS_LU_VID);
130162306a36Sopenharmony_ci	mvpp2_prs_hw_write(priv, &pe);
130262306a36Sopenharmony_ci
130362306a36Sopenharmony_ci	/* Set default vid entry for extended DSA*/
130462306a36Sopenharmony_ci	memset(&pe, 0, sizeof(pe));
130562306a36Sopenharmony_ci
130662306a36Sopenharmony_ci	/* Set default vid entry */
130762306a36Sopenharmony_ci	pe.index = MVPP2_PE_VID_EDSA_FLTR_DEFAULT;
130862306a36Sopenharmony_ci	mvpp2_prs_tcam_lu_set(&pe, MVPP2_PRS_LU_VID);
130962306a36Sopenharmony_ci
131062306a36Sopenharmony_ci	mvpp2_prs_tcam_ai_update(&pe, MVPP2_PRS_EDSA_VID_AI_BIT,
131162306a36Sopenharmony_ci				 MVPP2_PRS_EDSA_VID_AI_BIT);
131262306a36Sopenharmony_ci
131362306a36Sopenharmony_ci	/* Skip VLAN header - Set offset to 8 bytes */
131462306a36Sopenharmony_ci	mvpp2_prs_sram_shift_set(&pe, MVPP2_VLAN_TAG_EDSA_LEN,
131562306a36Sopenharmony_ci				 MVPP2_PRS_SRAM_OP_SEL_SHIFT_ADD);
131662306a36Sopenharmony_ci
131762306a36Sopenharmony_ci	/* Clear all ai bits for next iteration */
131862306a36Sopenharmony_ci	mvpp2_prs_sram_ai_update(&pe, 0, MVPP2_PRS_SRAM_AI_MASK);
131962306a36Sopenharmony_ci
132062306a36Sopenharmony_ci	mvpp2_prs_sram_next_lu_set(&pe, MVPP2_PRS_LU_L2);
132162306a36Sopenharmony_ci
132262306a36Sopenharmony_ci	/* Unmask all ports */
132362306a36Sopenharmony_ci	mvpp2_prs_tcam_port_map_set(&pe, MVPP2_PRS_PORT_MASK);
132462306a36Sopenharmony_ci
132562306a36Sopenharmony_ci	/* Update shadow table and hw entry */
132662306a36Sopenharmony_ci	mvpp2_prs_shadow_set(priv, pe.index, MVPP2_PRS_LU_VID);
132762306a36Sopenharmony_ci	mvpp2_prs_hw_write(priv, &pe);
132862306a36Sopenharmony_ci}
132962306a36Sopenharmony_ci
133062306a36Sopenharmony_ci/* Match basic ethertypes */
133162306a36Sopenharmony_cistatic int mvpp2_prs_etype_init(struct mvpp2 *priv)
133262306a36Sopenharmony_ci{
133362306a36Sopenharmony_ci	struct mvpp2_prs_entry pe;
133462306a36Sopenharmony_ci	int tid, ihl;
133562306a36Sopenharmony_ci
133662306a36Sopenharmony_ci	/* Ethertype: PPPoE */
133762306a36Sopenharmony_ci	tid = mvpp2_prs_tcam_first_free(priv, MVPP2_PE_FIRST_FREE_TID,
133862306a36Sopenharmony_ci					MVPP2_PE_LAST_FREE_TID);
133962306a36Sopenharmony_ci	if (tid < 0)
134062306a36Sopenharmony_ci		return tid;
134162306a36Sopenharmony_ci
134262306a36Sopenharmony_ci	memset(&pe, 0, sizeof(pe));
134362306a36Sopenharmony_ci	mvpp2_prs_tcam_lu_set(&pe, MVPP2_PRS_LU_L2);
134462306a36Sopenharmony_ci	pe.index = tid;
134562306a36Sopenharmony_ci
134662306a36Sopenharmony_ci	mvpp2_prs_match_etype(&pe, 0, ETH_P_PPP_SES);
134762306a36Sopenharmony_ci
134862306a36Sopenharmony_ci	mvpp2_prs_sram_shift_set(&pe, MVPP2_PPPOE_HDR_SIZE,
134962306a36Sopenharmony_ci				 MVPP2_PRS_SRAM_OP_SEL_SHIFT_ADD);
135062306a36Sopenharmony_ci	mvpp2_prs_sram_next_lu_set(&pe, MVPP2_PRS_LU_PPPOE);
135162306a36Sopenharmony_ci	mvpp2_prs_sram_ri_update(&pe, MVPP2_PRS_RI_PPPOE_MASK,
135262306a36Sopenharmony_ci				 MVPP2_PRS_RI_PPPOE_MASK);
135362306a36Sopenharmony_ci
135462306a36Sopenharmony_ci	/* Update shadow table and hw entry */
135562306a36Sopenharmony_ci	mvpp2_prs_shadow_set(priv, pe.index, MVPP2_PRS_LU_L2);
135662306a36Sopenharmony_ci	priv->prs_shadow[pe.index].udf = MVPP2_PRS_UDF_L2_DEF;
135762306a36Sopenharmony_ci	priv->prs_shadow[pe.index].finish = false;
135862306a36Sopenharmony_ci	mvpp2_prs_shadow_ri_set(priv, pe.index, MVPP2_PRS_RI_PPPOE_MASK,
135962306a36Sopenharmony_ci				MVPP2_PRS_RI_PPPOE_MASK);
136062306a36Sopenharmony_ci	mvpp2_prs_hw_write(priv, &pe);
136162306a36Sopenharmony_ci
136262306a36Sopenharmony_ci	/* Ethertype: ARP */
136362306a36Sopenharmony_ci	tid = mvpp2_prs_tcam_first_free(priv, MVPP2_PE_FIRST_FREE_TID,
136462306a36Sopenharmony_ci					MVPP2_PE_LAST_FREE_TID);
136562306a36Sopenharmony_ci	if (tid < 0)
136662306a36Sopenharmony_ci		return tid;
136762306a36Sopenharmony_ci
136862306a36Sopenharmony_ci	memset(&pe, 0, sizeof(pe));
136962306a36Sopenharmony_ci	mvpp2_prs_tcam_lu_set(&pe, MVPP2_PRS_LU_L2);
137062306a36Sopenharmony_ci	pe.index = tid;
137162306a36Sopenharmony_ci
137262306a36Sopenharmony_ci	mvpp2_prs_match_etype(&pe, 0, ETH_P_ARP);
137362306a36Sopenharmony_ci
137462306a36Sopenharmony_ci	/* Generate flow in the next iteration*/
137562306a36Sopenharmony_ci	mvpp2_prs_sram_next_lu_set(&pe, MVPP2_PRS_LU_FLOWS);
137662306a36Sopenharmony_ci	mvpp2_prs_sram_bits_set(&pe, MVPP2_PRS_SRAM_LU_GEN_BIT, 1);
137762306a36Sopenharmony_ci	mvpp2_prs_sram_ri_update(&pe, MVPP2_PRS_RI_L3_ARP,
137862306a36Sopenharmony_ci				 MVPP2_PRS_RI_L3_PROTO_MASK);
137962306a36Sopenharmony_ci	/* Set L3 offset */
138062306a36Sopenharmony_ci	mvpp2_prs_sram_offset_set(&pe, MVPP2_PRS_SRAM_UDF_TYPE_L3,
138162306a36Sopenharmony_ci				  MVPP2_ETH_TYPE_LEN,
138262306a36Sopenharmony_ci				  MVPP2_PRS_SRAM_OP_SEL_UDF_ADD);
138362306a36Sopenharmony_ci
138462306a36Sopenharmony_ci	/* Update shadow table and hw entry */
138562306a36Sopenharmony_ci	mvpp2_prs_shadow_set(priv, pe.index, MVPP2_PRS_LU_L2);
138662306a36Sopenharmony_ci	priv->prs_shadow[pe.index].udf = MVPP2_PRS_UDF_L2_DEF;
138762306a36Sopenharmony_ci	priv->prs_shadow[pe.index].finish = true;
138862306a36Sopenharmony_ci	mvpp2_prs_shadow_ri_set(priv, pe.index, MVPP2_PRS_RI_L3_ARP,
138962306a36Sopenharmony_ci				MVPP2_PRS_RI_L3_PROTO_MASK);
139062306a36Sopenharmony_ci	mvpp2_prs_hw_write(priv, &pe);
139162306a36Sopenharmony_ci
139262306a36Sopenharmony_ci	/* Ethertype: LBTD */
139362306a36Sopenharmony_ci	tid = mvpp2_prs_tcam_first_free(priv, MVPP2_PE_FIRST_FREE_TID,
139462306a36Sopenharmony_ci					MVPP2_PE_LAST_FREE_TID);
139562306a36Sopenharmony_ci	if (tid < 0)
139662306a36Sopenharmony_ci		return tid;
139762306a36Sopenharmony_ci
139862306a36Sopenharmony_ci	memset(&pe, 0, sizeof(pe));
139962306a36Sopenharmony_ci	mvpp2_prs_tcam_lu_set(&pe, MVPP2_PRS_LU_L2);
140062306a36Sopenharmony_ci	pe.index = tid;
140162306a36Sopenharmony_ci
140262306a36Sopenharmony_ci	mvpp2_prs_match_etype(&pe, 0, MVPP2_IP_LBDT_TYPE);
140362306a36Sopenharmony_ci
140462306a36Sopenharmony_ci	/* Generate flow in the next iteration*/
140562306a36Sopenharmony_ci	mvpp2_prs_sram_next_lu_set(&pe, MVPP2_PRS_LU_FLOWS);
140662306a36Sopenharmony_ci	mvpp2_prs_sram_bits_set(&pe, MVPP2_PRS_SRAM_LU_GEN_BIT, 1);
140762306a36Sopenharmony_ci	mvpp2_prs_sram_ri_update(&pe, MVPP2_PRS_RI_CPU_CODE_RX_SPEC |
140862306a36Sopenharmony_ci				 MVPP2_PRS_RI_UDF3_RX_SPECIAL,
140962306a36Sopenharmony_ci				 MVPP2_PRS_RI_CPU_CODE_MASK |
141062306a36Sopenharmony_ci				 MVPP2_PRS_RI_UDF3_MASK);
141162306a36Sopenharmony_ci	/* Set L3 offset */
141262306a36Sopenharmony_ci	mvpp2_prs_sram_offset_set(&pe, MVPP2_PRS_SRAM_UDF_TYPE_L3,
141362306a36Sopenharmony_ci				  MVPP2_ETH_TYPE_LEN,
141462306a36Sopenharmony_ci				  MVPP2_PRS_SRAM_OP_SEL_UDF_ADD);
141562306a36Sopenharmony_ci
141662306a36Sopenharmony_ci	/* Update shadow table and hw entry */
141762306a36Sopenharmony_ci	mvpp2_prs_shadow_set(priv, pe.index, MVPP2_PRS_LU_L2);
141862306a36Sopenharmony_ci	priv->prs_shadow[pe.index].udf = MVPP2_PRS_UDF_L2_DEF;
141962306a36Sopenharmony_ci	priv->prs_shadow[pe.index].finish = true;
142062306a36Sopenharmony_ci	mvpp2_prs_shadow_ri_set(priv, pe.index, MVPP2_PRS_RI_CPU_CODE_RX_SPEC |
142162306a36Sopenharmony_ci				MVPP2_PRS_RI_UDF3_RX_SPECIAL,
142262306a36Sopenharmony_ci				MVPP2_PRS_RI_CPU_CODE_MASK |
142362306a36Sopenharmony_ci				MVPP2_PRS_RI_UDF3_MASK);
142462306a36Sopenharmony_ci	mvpp2_prs_hw_write(priv, &pe);
142562306a36Sopenharmony_ci
142662306a36Sopenharmony_ci	/* Ethertype: IPv4 with header length >= 5 */
142762306a36Sopenharmony_ci	for (ihl = MVPP2_PRS_IPV4_IHL_MIN; ihl <= MVPP2_PRS_IPV4_IHL_MAX; ihl++) {
142862306a36Sopenharmony_ci		tid = mvpp2_prs_tcam_first_free(priv, MVPP2_PE_FIRST_FREE_TID,
142962306a36Sopenharmony_ci						MVPP2_PE_LAST_FREE_TID);
143062306a36Sopenharmony_ci		if (tid < 0)
143162306a36Sopenharmony_ci			return tid;
143262306a36Sopenharmony_ci
143362306a36Sopenharmony_ci		memset(&pe, 0, sizeof(pe));
143462306a36Sopenharmony_ci		mvpp2_prs_tcam_lu_set(&pe, MVPP2_PRS_LU_L2);
143562306a36Sopenharmony_ci		pe.index = tid;
143662306a36Sopenharmony_ci
143762306a36Sopenharmony_ci		mvpp2_prs_match_etype(&pe, 0, ETH_P_IP);
143862306a36Sopenharmony_ci		mvpp2_prs_tcam_data_byte_set(&pe, MVPP2_ETH_TYPE_LEN,
143962306a36Sopenharmony_ci					     MVPP2_PRS_IPV4_HEAD | ihl,
144062306a36Sopenharmony_ci					     MVPP2_PRS_IPV4_HEAD_MASK |
144162306a36Sopenharmony_ci					     MVPP2_PRS_IPV4_IHL_MASK);
144262306a36Sopenharmony_ci
144362306a36Sopenharmony_ci		mvpp2_prs_sram_next_lu_set(&pe, MVPP2_PRS_LU_IP4);
144462306a36Sopenharmony_ci		mvpp2_prs_sram_ri_update(&pe, MVPP2_PRS_RI_L3_IP4,
144562306a36Sopenharmony_ci					 MVPP2_PRS_RI_L3_PROTO_MASK);
144662306a36Sopenharmony_ci		/* goto ipv4 dst-address (skip eth_type + IP-header-size - 4) */
144762306a36Sopenharmony_ci		mvpp2_prs_sram_shift_set(&pe, MVPP2_ETH_TYPE_LEN +
144862306a36Sopenharmony_ci					 sizeof(struct iphdr) - 4,
144962306a36Sopenharmony_ci					 MVPP2_PRS_SRAM_OP_SEL_SHIFT_ADD);
145062306a36Sopenharmony_ci		/* Set L4 offset */
145162306a36Sopenharmony_ci		mvpp2_prs_sram_offset_set(&pe, MVPP2_PRS_SRAM_UDF_TYPE_L4,
145262306a36Sopenharmony_ci					  MVPP2_ETH_TYPE_LEN + (ihl * 4),
145362306a36Sopenharmony_ci					  MVPP2_PRS_SRAM_OP_SEL_UDF_ADD);
145462306a36Sopenharmony_ci
145562306a36Sopenharmony_ci		/* Update shadow table and hw entry */
145662306a36Sopenharmony_ci		mvpp2_prs_shadow_set(priv, pe.index, MVPP2_PRS_LU_L2);
145762306a36Sopenharmony_ci		priv->prs_shadow[pe.index].udf = MVPP2_PRS_UDF_L2_DEF;
145862306a36Sopenharmony_ci		priv->prs_shadow[pe.index].finish = false;
145962306a36Sopenharmony_ci		mvpp2_prs_shadow_ri_set(priv, pe.index, MVPP2_PRS_RI_L3_IP4,
146062306a36Sopenharmony_ci					MVPP2_PRS_RI_L3_PROTO_MASK);
146162306a36Sopenharmony_ci		mvpp2_prs_hw_write(priv, &pe);
146262306a36Sopenharmony_ci	}
146362306a36Sopenharmony_ci
146462306a36Sopenharmony_ci	/* Ethertype: IPv6 without options */
146562306a36Sopenharmony_ci	tid = mvpp2_prs_tcam_first_free(priv, MVPP2_PE_FIRST_FREE_TID,
146662306a36Sopenharmony_ci					MVPP2_PE_LAST_FREE_TID);
146762306a36Sopenharmony_ci	if (tid < 0)
146862306a36Sopenharmony_ci		return tid;
146962306a36Sopenharmony_ci
147062306a36Sopenharmony_ci	memset(&pe, 0, sizeof(pe));
147162306a36Sopenharmony_ci	mvpp2_prs_tcam_lu_set(&pe, MVPP2_PRS_LU_L2);
147262306a36Sopenharmony_ci	pe.index = tid;
147362306a36Sopenharmony_ci
147462306a36Sopenharmony_ci	mvpp2_prs_match_etype(&pe, 0, ETH_P_IPV6);
147562306a36Sopenharmony_ci
147662306a36Sopenharmony_ci	/* Skip DIP of IPV6 header */
147762306a36Sopenharmony_ci	mvpp2_prs_sram_shift_set(&pe, MVPP2_ETH_TYPE_LEN + 8 +
147862306a36Sopenharmony_ci				 MVPP2_MAX_L3_ADDR_SIZE,
147962306a36Sopenharmony_ci				 MVPP2_PRS_SRAM_OP_SEL_SHIFT_ADD);
148062306a36Sopenharmony_ci	mvpp2_prs_sram_next_lu_set(&pe, MVPP2_PRS_LU_IP6);
148162306a36Sopenharmony_ci	mvpp2_prs_sram_ri_update(&pe, MVPP2_PRS_RI_L3_IP6,
148262306a36Sopenharmony_ci				 MVPP2_PRS_RI_L3_PROTO_MASK);
148362306a36Sopenharmony_ci	/* Set L3 offset */
148462306a36Sopenharmony_ci	mvpp2_prs_sram_offset_set(&pe, MVPP2_PRS_SRAM_UDF_TYPE_L3,
148562306a36Sopenharmony_ci				  MVPP2_ETH_TYPE_LEN,
148662306a36Sopenharmony_ci				  MVPP2_PRS_SRAM_OP_SEL_UDF_ADD);
148762306a36Sopenharmony_ci
148862306a36Sopenharmony_ci	mvpp2_prs_shadow_set(priv, pe.index, MVPP2_PRS_LU_L2);
148962306a36Sopenharmony_ci	priv->prs_shadow[pe.index].udf = MVPP2_PRS_UDF_L2_DEF;
149062306a36Sopenharmony_ci	priv->prs_shadow[pe.index].finish = false;
149162306a36Sopenharmony_ci	mvpp2_prs_shadow_ri_set(priv, pe.index, MVPP2_PRS_RI_L3_IP6,
149262306a36Sopenharmony_ci				MVPP2_PRS_RI_L3_PROTO_MASK);
149362306a36Sopenharmony_ci	mvpp2_prs_hw_write(priv, &pe);
149462306a36Sopenharmony_ci
149562306a36Sopenharmony_ci	/* Default entry for MVPP2_PRS_LU_L2 - Unknown ethtype */
149662306a36Sopenharmony_ci	memset(&pe, 0, sizeof(struct mvpp2_prs_entry));
149762306a36Sopenharmony_ci	mvpp2_prs_tcam_lu_set(&pe, MVPP2_PRS_LU_L2);
149862306a36Sopenharmony_ci	pe.index = MVPP2_PE_ETH_TYPE_UN;
149962306a36Sopenharmony_ci
150062306a36Sopenharmony_ci	/* Unmask all ports */
150162306a36Sopenharmony_ci	mvpp2_prs_tcam_port_map_set(&pe, MVPP2_PRS_PORT_MASK);
150262306a36Sopenharmony_ci
150362306a36Sopenharmony_ci	/* Generate flow in the next iteration*/
150462306a36Sopenharmony_ci	mvpp2_prs_sram_bits_set(&pe, MVPP2_PRS_SRAM_LU_GEN_BIT, 1);
150562306a36Sopenharmony_ci	mvpp2_prs_sram_next_lu_set(&pe, MVPP2_PRS_LU_FLOWS);
150662306a36Sopenharmony_ci	mvpp2_prs_sram_ri_update(&pe, MVPP2_PRS_RI_L3_UN,
150762306a36Sopenharmony_ci				 MVPP2_PRS_RI_L3_PROTO_MASK);
150862306a36Sopenharmony_ci	/* Set L3 offset even it's unknown L3 */
150962306a36Sopenharmony_ci	mvpp2_prs_sram_offset_set(&pe, MVPP2_PRS_SRAM_UDF_TYPE_L3,
151062306a36Sopenharmony_ci				  MVPP2_ETH_TYPE_LEN,
151162306a36Sopenharmony_ci				  MVPP2_PRS_SRAM_OP_SEL_UDF_ADD);
151262306a36Sopenharmony_ci
151362306a36Sopenharmony_ci	/* Update shadow table and hw entry */
151462306a36Sopenharmony_ci	mvpp2_prs_shadow_set(priv, pe.index, MVPP2_PRS_LU_L2);
151562306a36Sopenharmony_ci	priv->prs_shadow[pe.index].udf = MVPP2_PRS_UDF_L2_DEF;
151662306a36Sopenharmony_ci	priv->prs_shadow[pe.index].finish = true;
151762306a36Sopenharmony_ci	mvpp2_prs_shadow_ri_set(priv, pe.index, MVPP2_PRS_RI_L3_UN,
151862306a36Sopenharmony_ci				MVPP2_PRS_RI_L3_PROTO_MASK);
151962306a36Sopenharmony_ci	mvpp2_prs_hw_write(priv, &pe);
152062306a36Sopenharmony_ci
152162306a36Sopenharmony_ci	return 0;
152262306a36Sopenharmony_ci}
152362306a36Sopenharmony_ci
152462306a36Sopenharmony_ci/* Configure vlan entries and detect up to 2 successive VLAN tags.
152562306a36Sopenharmony_ci * Possible options:
152662306a36Sopenharmony_ci * 0x8100, 0x88A8
152762306a36Sopenharmony_ci * 0x8100, 0x8100
152862306a36Sopenharmony_ci * 0x8100
152962306a36Sopenharmony_ci * 0x88A8
153062306a36Sopenharmony_ci */
153162306a36Sopenharmony_cistatic int mvpp2_prs_vlan_init(struct platform_device *pdev, struct mvpp2 *priv)
153262306a36Sopenharmony_ci{
153362306a36Sopenharmony_ci	struct mvpp2_prs_entry pe;
153462306a36Sopenharmony_ci	int err;
153562306a36Sopenharmony_ci
153662306a36Sopenharmony_ci	priv->prs_double_vlans = devm_kcalloc(&pdev->dev, sizeof(bool),
153762306a36Sopenharmony_ci					      MVPP2_PRS_DBL_VLANS_MAX,
153862306a36Sopenharmony_ci					      GFP_KERNEL);
153962306a36Sopenharmony_ci	if (!priv->prs_double_vlans)
154062306a36Sopenharmony_ci		return -ENOMEM;
154162306a36Sopenharmony_ci
154262306a36Sopenharmony_ci	/* Double VLAN: 0x88A8, 0x8100 */
154362306a36Sopenharmony_ci	err = mvpp2_prs_double_vlan_add(priv, ETH_P_8021AD, ETH_P_8021Q,
154462306a36Sopenharmony_ci					MVPP2_PRS_PORT_MASK);
154562306a36Sopenharmony_ci	if (err)
154662306a36Sopenharmony_ci		return err;
154762306a36Sopenharmony_ci
154862306a36Sopenharmony_ci	/* Double VLAN: 0x8100, 0x8100 */
154962306a36Sopenharmony_ci	err = mvpp2_prs_double_vlan_add(priv, ETH_P_8021Q, ETH_P_8021Q,
155062306a36Sopenharmony_ci					MVPP2_PRS_PORT_MASK);
155162306a36Sopenharmony_ci	if (err)
155262306a36Sopenharmony_ci		return err;
155362306a36Sopenharmony_ci
155462306a36Sopenharmony_ci	/* Single VLAN: 0x88a8 */
155562306a36Sopenharmony_ci	err = mvpp2_prs_vlan_add(priv, ETH_P_8021AD, MVPP2_PRS_SINGLE_VLAN_AI,
155662306a36Sopenharmony_ci				 MVPP2_PRS_PORT_MASK);
155762306a36Sopenharmony_ci	if (err)
155862306a36Sopenharmony_ci		return err;
155962306a36Sopenharmony_ci
156062306a36Sopenharmony_ci	/* Single VLAN: 0x8100 */
156162306a36Sopenharmony_ci	err = mvpp2_prs_vlan_add(priv, ETH_P_8021Q, MVPP2_PRS_SINGLE_VLAN_AI,
156262306a36Sopenharmony_ci				 MVPP2_PRS_PORT_MASK);
156362306a36Sopenharmony_ci	if (err)
156462306a36Sopenharmony_ci		return err;
156562306a36Sopenharmony_ci
156662306a36Sopenharmony_ci	/* Set default double vlan entry */
156762306a36Sopenharmony_ci	memset(&pe, 0, sizeof(pe));
156862306a36Sopenharmony_ci	mvpp2_prs_tcam_lu_set(&pe, MVPP2_PRS_LU_VLAN);
156962306a36Sopenharmony_ci	pe.index = MVPP2_PE_VLAN_DBL;
157062306a36Sopenharmony_ci
157162306a36Sopenharmony_ci	mvpp2_prs_sram_next_lu_set(&pe, MVPP2_PRS_LU_VID);
157262306a36Sopenharmony_ci
157362306a36Sopenharmony_ci	/* Clear ai for next iterations */
157462306a36Sopenharmony_ci	mvpp2_prs_sram_ai_update(&pe, 0, MVPP2_PRS_SRAM_AI_MASK);
157562306a36Sopenharmony_ci	mvpp2_prs_sram_ri_update(&pe, MVPP2_PRS_RI_VLAN_DOUBLE,
157662306a36Sopenharmony_ci				 MVPP2_PRS_RI_VLAN_MASK);
157762306a36Sopenharmony_ci
157862306a36Sopenharmony_ci	mvpp2_prs_tcam_ai_update(&pe, MVPP2_PRS_DBL_VLAN_AI_BIT,
157962306a36Sopenharmony_ci				 MVPP2_PRS_DBL_VLAN_AI_BIT);
158062306a36Sopenharmony_ci	/* Unmask all ports */
158162306a36Sopenharmony_ci	mvpp2_prs_tcam_port_map_set(&pe, MVPP2_PRS_PORT_MASK);
158262306a36Sopenharmony_ci
158362306a36Sopenharmony_ci	/* Update shadow table and hw entry */
158462306a36Sopenharmony_ci	mvpp2_prs_shadow_set(priv, pe.index, MVPP2_PRS_LU_VLAN);
158562306a36Sopenharmony_ci	mvpp2_prs_hw_write(priv, &pe);
158662306a36Sopenharmony_ci
158762306a36Sopenharmony_ci	/* Set default vlan none entry */
158862306a36Sopenharmony_ci	memset(&pe, 0, sizeof(pe));
158962306a36Sopenharmony_ci	mvpp2_prs_tcam_lu_set(&pe, MVPP2_PRS_LU_VLAN);
159062306a36Sopenharmony_ci	pe.index = MVPP2_PE_VLAN_NONE;
159162306a36Sopenharmony_ci
159262306a36Sopenharmony_ci	mvpp2_prs_sram_next_lu_set(&pe, MVPP2_PRS_LU_L2);
159362306a36Sopenharmony_ci	mvpp2_prs_sram_ri_update(&pe, MVPP2_PRS_RI_VLAN_NONE,
159462306a36Sopenharmony_ci				 MVPP2_PRS_RI_VLAN_MASK);
159562306a36Sopenharmony_ci
159662306a36Sopenharmony_ci	/* Unmask all ports */
159762306a36Sopenharmony_ci	mvpp2_prs_tcam_port_map_set(&pe, MVPP2_PRS_PORT_MASK);
159862306a36Sopenharmony_ci
159962306a36Sopenharmony_ci	/* Update shadow table and hw entry */
160062306a36Sopenharmony_ci	mvpp2_prs_shadow_set(priv, pe.index, MVPP2_PRS_LU_VLAN);
160162306a36Sopenharmony_ci	mvpp2_prs_hw_write(priv, &pe);
160262306a36Sopenharmony_ci
160362306a36Sopenharmony_ci	return 0;
160462306a36Sopenharmony_ci}
160562306a36Sopenharmony_ci
160662306a36Sopenharmony_ci/* Set entries for PPPoE ethertype */
160762306a36Sopenharmony_cistatic int mvpp2_prs_pppoe_init(struct mvpp2 *priv)
160862306a36Sopenharmony_ci{
160962306a36Sopenharmony_ci	struct mvpp2_prs_entry pe;
161062306a36Sopenharmony_ci	int tid, ihl;
161162306a36Sopenharmony_ci
161262306a36Sopenharmony_ci	/* IPv4 over PPPoE with header length >= 5 */
161362306a36Sopenharmony_ci	for (ihl = MVPP2_PRS_IPV4_IHL_MIN; ihl <= MVPP2_PRS_IPV4_IHL_MAX; ihl++) {
161462306a36Sopenharmony_ci		tid = mvpp2_prs_tcam_first_free(priv, MVPP2_PE_FIRST_FREE_TID,
161562306a36Sopenharmony_ci						MVPP2_PE_LAST_FREE_TID);
161662306a36Sopenharmony_ci		if (tid < 0)
161762306a36Sopenharmony_ci			return tid;
161862306a36Sopenharmony_ci
161962306a36Sopenharmony_ci		memset(&pe, 0, sizeof(pe));
162062306a36Sopenharmony_ci		mvpp2_prs_tcam_lu_set(&pe, MVPP2_PRS_LU_PPPOE);
162162306a36Sopenharmony_ci		pe.index = tid;
162262306a36Sopenharmony_ci
162362306a36Sopenharmony_ci		mvpp2_prs_match_etype(&pe, 0, PPP_IP);
162462306a36Sopenharmony_ci		mvpp2_prs_tcam_data_byte_set(&pe, MVPP2_ETH_TYPE_LEN,
162562306a36Sopenharmony_ci					     MVPP2_PRS_IPV4_HEAD | ihl,
162662306a36Sopenharmony_ci					     MVPP2_PRS_IPV4_HEAD_MASK |
162762306a36Sopenharmony_ci					     MVPP2_PRS_IPV4_IHL_MASK);
162862306a36Sopenharmony_ci
162962306a36Sopenharmony_ci		mvpp2_prs_sram_next_lu_set(&pe, MVPP2_PRS_LU_IP4);
163062306a36Sopenharmony_ci		mvpp2_prs_sram_ri_update(&pe, MVPP2_PRS_RI_L3_IP4,
163162306a36Sopenharmony_ci					 MVPP2_PRS_RI_L3_PROTO_MASK);
163262306a36Sopenharmony_ci		/* goto ipv4 dst-address (skip eth_type + IP-header-size - 4) */
163362306a36Sopenharmony_ci		mvpp2_prs_sram_shift_set(&pe, MVPP2_ETH_TYPE_LEN +
163462306a36Sopenharmony_ci					 sizeof(struct iphdr) - 4,
163562306a36Sopenharmony_ci					 MVPP2_PRS_SRAM_OP_SEL_SHIFT_ADD);
163662306a36Sopenharmony_ci		/* Set L3 offset */
163762306a36Sopenharmony_ci		mvpp2_prs_sram_offset_set(&pe, MVPP2_PRS_SRAM_UDF_TYPE_L3,
163862306a36Sopenharmony_ci					  MVPP2_ETH_TYPE_LEN,
163962306a36Sopenharmony_ci					  MVPP2_PRS_SRAM_OP_SEL_UDF_ADD);
164062306a36Sopenharmony_ci		/* Set L4 offset */
164162306a36Sopenharmony_ci		mvpp2_prs_sram_offset_set(&pe, MVPP2_PRS_SRAM_UDF_TYPE_L4,
164262306a36Sopenharmony_ci					  MVPP2_ETH_TYPE_LEN + (ihl * 4),
164362306a36Sopenharmony_ci					  MVPP2_PRS_SRAM_OP_SEL_UDF_ADD);
164462306a36Sopenharmony_ci
164562306a36Sopenharmony_ci		/* Update shadow table and hw entry */
164662306a36Sopenharmony_ci		mvpp2_prs_shadow_set(priv, pe.index, MVPP2_PRS_LU_PPPOE);
164762306a36Sopenharmony_ci		mvpp2_prs_hw_write(priv, &pe);
164862306a36Sopenharmony_ci	}
164962306a36Sopenharmony_ci
165062306a36Sopenharmony_ci	/* IPv6 over PPPoE */
165162306a36Sopenharmony_ci	tid = mvpp2_prs_tcam_first_free(priv, MVPP2_PE_FIRST_FREE_TID,
165262306a36Sopenharmony_ci					MVPP2_PE_LAST_FREE_TID);
165362306a36Sopenharmony_ci	if (tid < 0)
165462306a36Sopenharmony_ci		return tid;
165562306a36Sopenharmony_ci
165662306a36Sopenharmony_ci	memset(&pe, 0, sizeof(pe));
165762306a36Sopenharmony_ci	mvpp2_prs_tcam_lu_set(&pe, MVPP2_PRS_LU_PPPOE);
165862306a36Sopenharmony_ci	pe.index = tid;
165962306a36Sopenharmony_ci
166062306a36Sopenharmony_ci	mvpp2_prs_match_etype(&pe, 0, PPP_IPV6);
166162306a36Sopenharmony_ci
166262306a36Sopenharmony_ci	mvpp2_prs_sram_next_lu_set(&pe, MVPP2_PRS_LU_IP6);
166362306a36Sopenharmony_ci	mvpp2_prs_sram_ri_update(&pe, MVPP2_PRS_RI_L3_IP6,
166462306a36Sopenharmony_ci				 MVPP2_PRS_RI_L3_PROTO_MASK);
166562306a36Sopenharmony_ci	/* Jump to DIP of IPV6 header */
166662306a36Sopenharmony_ci	mvpp2_prs_sram_shift_set(&pe, MVPP2_ETH_TYPE_LEN + 8 +
166762306a36Sopenharmony_ci				 MVPP2_MAX_L3_ADDR_SIZE,
166862306a36Sopenharmony_ci				 MVPP2_PRS_SRAM_OP_SEL_SHIFT_ADD);
166962306a36Sopenharmony_ci	/* Set L3 offset */
167062306a36Sopenharmony_ci	mvpp2_prs_sram_offset_set(&pe, MVPP2_PRS_SRAM_UDF_TYPE_L3,
167162306a36Sopenharmony_ci				  MVPP2_ETH_TYPE_LEN,
167262306a36Sopenharmony_ci				  MVPP2_PRS_SRAM_OP_SEL_UDF_ADD);
167362306a36Sopenharmony_ci
167462306a36Sopenharmony_ci	/* Update shadow table and hw entry */
167562306a36Sopenharmony_ci	mvpp2_prs_shadow_set(priv, pe.index, MVPP2_PRS_LU_PPPOE);
167662306a36Sopenharmony_ci	mvpp2_prs_hw_write(priv, &pe);
167762306a36Sopenharmony_ci
167862306a36Sopenharmony_ci	/* Non-IP over PPPoE */
167962306a36Sopenharmony_ci	tid = mvpp2_prs_tcam_first_free(priv, MVPP2_PE_FIRST_FREE_TID,
168062306a36Sopenharmony_ci					MVPP2_PE_LAST_FREE_TID);
168162306a36Sopenharmony_ci	if (tid < 0)
168262306a36Sopenharmony_ci		return tid;
168362306a36Sopenharmony_ci
168462306a36Sopenharmony_ci	memset(&pe, 0, sizeof(pe));
168562306a36Sopenharmony_ci	mvpp2_prs_tcam_lu_set(&pe, MVPP2_PRS_LU_PPPOE);
168662306a36Sopenharmony_ci	pe.index = tid;
168762306a36Sopenharmony_ci
168862306a36Sopenharmony_ci	mvpp2_prs_sram_ri_update(&pe, MVPP2_PRS_RI_L3_UN,
168962306a36Sopenharmony_ci				 MVPP2_PRS_RI_L3_PROTO_MASK);
169062306a36Sopenharmony_ci
169162306a36Sopenharmony_ci	/* Finished: go to flowid generation */
169262306a36Sopenharmony_ci	mvpp2_prs_sram_next_lu_set(&pe, MVPP2_PRS_LU_FLOWS);
169362306a36Sopenharmony_ci	mvpp2_prs_sram_bits_set(&pe, MVPP2_PRS_SRAM_LU_GEN_BIT, 1);
169462306a36Sopenharmony_ci	/* Set L3 offset even if it's unknown L3 */
169562306a36Sopenharmony_ci	mvpp2_prs_sram_offset_set(&pe, MVPP2_PRS_SRAM_UDF_TYPE_L3,
169662306a36Sopenharmony_ci				  MVPP2_ETH_TYPE_LEN,
169762306a36Sopenharmony_ci				  MVPP2_PRS_SRAM_OP_SEL_UDF_ADD);
169862306a36Sopenharmony_ci
169962306a36Sopenharmony_ci	/* Update shadow table and hw entry */
170062306a36Sopenharmony_ci	mvpp2_prs_shadow_set(priv, pe.index, MVPP2_PRS_LU_PPPOE);
170162306a36Sopenharmony_ci	mvpp2_prs_hw_write(priv, &pe);
170262306a36Sopenharmony_ci
170362306a36Sopenharmony_ci	return 0;
170462306a36Sopenharmony_ci}
170562306a36Sopenharmony_ci
170662306a36Sopenharmony_ci/* Initialize entries for IPv4 */
170762306a36Sopenharmony_cistatic int mvpp2_prs_ip4_init(struct mvpp2 *priv)
170862306a36Sopenharmony_ci{
170962306a36Sopenharmony_ci	struct mvpp2_prs_entry pe;
171062306a36Sopenharmony_ci	int err;
171162306a36Sopenharmony_ci
171262306a36Sopenharmony_ci	/* Set entries for TCP, UDP and IGMP over IPv4 */
171362306a36Sopenharmony_ci	err = mvpp2_prs_ip4_proto(priv, IPPROTO_TCP, MVPP2_PRS_RI_L4_TCP,
171462306a36Sopenharmony_ci				  MVPP2_PRS_RI_L4_PROTO_MASK);
171562306a36Sopenharmony_ci	if (err)
171662306a36Sopenharmony_ci		return err;
171762306a36Sopenharmony_ci
171862306a36Sopenharmony_ci	err = mvpp2_prs_ip4_proto(priv, IPPROTO_UDP, MVPP2_PRS_RI_L4_UDP,
171962306a36Sopenharmony_ci				  MVPP2_PRS_RI_L4_PROTO_MASK);
172062306a36Sopenharmony_ci	if (err)
172162306a36Sopenharmony_ci		return err;
172262306a36Sopenharmony_ci
172362306a36Sopenharmony_ci	err = mvpp2_prs_ip4_proto(priv, IPPROTO_IGMP,
172462306a36Sopenharmony_ci				  MVPP2_PRS_RI_CPU_CODE_RX_SPEC |
172562306a36Sopenharmony_ci				  MVPP2_PRS_RI_UDF3_RX_SPECIAL,
172662306a36Sopenharmony_ci				  MVPP2_PRS_RI_CPU_CODE_MASK |
172762306a36Sopenharmony_ci				  MVPP2_PRS_RI_UDF3_MASK);
172862306a36Sopenharmony_ci	if (err)
172962306a36Sopenharmony_ci		return err;
173062306a36Sopenharmony_ci
173162306a36Sopenharmony_ci	/* IPv4 Broadcast */
173262306a36Sopenharmony_ci	err = mvpp2_prs_ip4_cast(priv, MVPP2_PRS_L3_BROAD_CAST);
173362306a36Sopenharmony_ci	if (err)
173462306a36Sopenharmony_ci		return err;
173562306a36Sopenharmony_ci
173662306a36Sopenharmony_ci	/* IPv4 Multicast */
173762306a36Sopenharmony_ci	err = mvpp2_prs_ip4_cast(priv, MVPP2_PRS_L3_MULTI_CAST);
173862306a36Sopenharmony_ci	if (err)
173962306a36Sopenharmony_ci		return err;
174062306a36Sopenharmony_ci
174162306a36Sopenharmony_ci	/* Default IPv4 entry for unknown protocols */
174262306a36Sopenharmony_ci	memset(&pe, 0, sizeof(pe));
174362306a36Sopenharmony_ci	mvpp2_prs_tcam_lu_set(&pe, MVPP2_PRS_LU_IP4);
174462306a36Sopenharmony_ci	pe.index = MVPP2_PE_IP4_PROTO_UN;
174562306a36Sopenharmony_ci
174662306a36Sopenharmony_ci	/* Finished: go to flowid generation */
174762306a36Sopenharmony_ci	mvpp2_prs_sram_next_lu_set(&pe, MVPP2_PRS_LU_FLOWS);
174862306a36Sopenharmony_ci	mvpp2_prs_sram_bits_set(&pe, MVPP2_PRS_SRAM_LU_GEN_BIT, 1);
174962306a36Sopenharmony_ci
175062306a36Sopenharmony_ci	/* Set L3 offset */
175162306a36Sopenharmony_ci	mvpp2_prs_sram_offset_set(&pe, MVPP2_PRS_SRAM_UDF_TYPE_L3, -4,
175262306a36Sopenharmony_ci				  MVPP2_PRS_SRAM_OP_SEL_UDF_ADD);
175362306a36Sopenharmony_ci	mvpp2_prs_sram_ai_update(&pe, 0, MVPP2_PRS_IPV4_DIP_AI_BIT);
175462306a36Sopenharmony_ci	mvpp2_prs_sram_ri_update(&pe, MVPP2_PRS_RI_L4_OTHER,
175562306a36Sopenharmony_ci				 MVPP2_PRS_RI_L4_PROTO_MASK);
175662306a36Sopenharmony_ci
175762306a36Sopenharmony_ci	mvpp2_prs_tcam_ai_update(&pe, MVPP2_PRS_IPV4_DIP_AI_BIT,
175862306a36Sopenharmony_ci				 MVPP2_PRS_IPV4_DIP_AI_BIT);
175962306a36Sopenharmony_ci	/* Unmask all ports */
176062306a36Sopenharmony_ci	mvpp2_prs_tcam_port_map_set(&pe, MVPP2_PRS_PORT_MASK);
176162306a36Sopenharmony_ci
176262306a36Sopenharmony_ci	/* Update shadow table and hw entry */
176362306a36Sopenharmony_ci	mvpp2_prs_shadow_set(priv, pe.index, MVPP2_PRS_LU_IP4);
176462306a36Sopenharmony_ci	mvpp2_prs_hw_write(priv, &pe);
176562306a36Sopenharmony_ci
176662306a36Sopenharmony_ci	/* Default IPv4 entry for unicast address */
176762306a36Sopenharmony_ci	memset(&pe, 0, sizeof(pe));
176862306a36Sopenharmony_ci	mvpp2_prs_tcam_lu_set(&pe, MVPP2_PRS_LU_IP4);
176962306a36Sopenharmony_ci	pe.index = MVPP2_PE_IP4_ADDR_UN;
177062306a36Sopenharmony_ci
177162306a36Sopenharmony_ci	/* Go again to ipv4 */
177262306a36Sopenharmony_ci	mvpp2_prs_sram_next_lu_set(&pe, MVPP2_PRS_LU_IP4);
177362306a36Sopenharmony_ci
177462306a36Sopenharmony_ci	mvpp2_prs_sram_ai_update(&pe, MVPP2_PRS_IPV4_DIP_AI_BIT,
177562306a36Sopenharmony_ci				 MVPP2_PRS_IPV4_DIP_AI_BIT);
177662306a36Sopenharmony_ci
177762306a36Sopenharmony_ci	/* Shift back to IPv4 proto */
177862306a36Sopenharmony_ci	mvpp2_prs_sram_shift_set(&pe, -12, MVPP2_PRS_SRAM_OP_SEL_SHIFT_ADD);
177962306a36Sopenharmony_ci
178062306a36Sopenharmony_ci	mvpp2_prs_sram_ri_update(&pe, MVPP2_PRS_RI_L3_UCAST,
178162306a36Sopenharmony_ci				 MVPP2_PRS_RI_L3_ADDR_MASK);
178262306a36Sopenharmony_ci	mvpp2_prs_tcam_ai_update(&pe, 0, MVPP2_PRS_IPV4_DIP_AI_BIT);
178362306a36Sopenharmony_ci
178462306a36Sopenharmony_ci	/* Unmask all ports */
178562306a36Sopenharmony_ci	mvpp2_prs_tcam_port_map_set(&pe, MVPP2_PRS_PORT_MASK);
178662306a36Sopenharmony_ci
178762306a36Sopenharmony_ci	/* Update shadow table and hw entry */
178862306a36Sopenharmony_ci	mvpp2_prs_shadow_set(priv, pe.index, MVPP2_PRS_LU_IP4);
178962306a36Sopenharmony_ci	mvpp2_prs_hw_write(priv, &pe);
179062306a36Sopenharmony_ci
179162306a36Sopenharmony_ci	return 0;
179262306a36Sopenharmony_ci}
179362306a36Sopenharmony_ci
179462306a36Sopenharmony_ci/* Initialize entries for IPv6 */
179562306a36Sopenharmony_cistatic int mvpp2_prs_ip6_init(struct mvpp2 *priv)
179662306a36Sopenharmony_ci{
179762306a36Sopenharmony_ci	struct mvpp2_prs_entry pe;
179862306a36Sopenharmony_ci	int tid, err;
179962306a36Sopenharmony_ci
180062306a36Sopenharmony_ci	/* Set entries for TCP, UDP and ICMP over IPv6 */
180162306a36Sopenharmony_ci	err = mvpp2_prs_ip6_proto(priv, IPPROTO_TCP,
180262306a36Sopenharmony_ci				  MVPP2_PRS_RI_L4_TCP,
180362306a36Sopenharmony_ci				  MVPP2_PRS_RI_L4_PROTO_MASK);
180462306a36Sopenharmony_ci	if (err)
180562306a36Sopenharmony_ci		return err;
180662306a36Sopenharmony_ci
180762306a36Sopenharmony_ci	err = mvpp2_prs_ip6_proto(priv, IPPROTO_UDP,
180862306a36Sopenharmony_ci				  MVPP2_PRS_RI_L4_UDP,
180962306a36Sopenharmony_ci				  MVPP2_PRS_RI_L4_PROTO_MASK);
181062306a36Sopenharmony_ci	if (err)
181162306a36Sopenharmony_ci		return err;
181262306a36Sopenharmony_ci
181362306a36Sopenharmony_ci	err = mvpp2_prs_ip6_proto(priv, IPPROTO_ICMPV6,
181462306a36Sopenharmony_ci				  MVPP2_PRS_RI_CPU_CODE_RX_SPEC |
181562306a36Sopenharmony_ci				  MVPP2_PRS_RI_UDF3_RX_SPECIAL,
181662306a36Sopenharmony_ci				  MVPP2_PRS_RI_CPU_CODE_MASK |
181762306a36Sopenharmony_ci				  MVPP2_PRS_RI_UDF3_MASK);
181862306a36Sopenharmony_ci	if (err)
181962306a36Sopenharmony_ci		return err;
182062306a36Sopenharmony_ci
182162306a36Sopenharmony_ci	/* IPv4 is the last header. This is similar case as 6-TCP or 17-UDP */
182262306a36Sopenharmony_ci	/* Result Info: UDF7=1, DS lite */
182362306a36Sopenharmony_ci	err = mvpp2_prs_ip6_proto(priv, IPPROTO_IPIP,
182462306a36Sopenharmony_ci				  MVPP2_PRS_RI_UDF7_IP6_LITE,
182562306a36Sopenharmony_ci				  MVPP2_PRS_RI_UDF7_MASK);
182662306a36Sopenharmony_ci	if (err)
182762306a36Sopenharmony_ci		return err;
182862306a36Sopenharmony_ci
182962306a36Sopenharmony_ci	/* IPv6 multicast */
183062306a36Sopenharmony_ci	err = mvpp2_prs_ip6_cast(priv, MVPP2_PRS_L3_MULTI_CAST);
183162306a36Sopenharmony_ci	if (err)
183262306a36Sopenharmony_ci		return err;
183362306a36Sopenharmony_ci
183462306a36Sopenharmony_ci	/* Entry for checking hop limit */
183562306a36Sopenharmony_ci	tid = mvpp2_prs_tcam_first_free(priv, MVPP2_PE_FIRST_FREE_TID,
183662306a36Sopenharmony_ci					MVPP2_PE_LAST_FREE_TID);
183762306a36Sopenharmony_ci	if (tid < 0)
183862306a36Sopenharmony_ci		return tid;
183962306a36Sopenharmony_ci
184062306a36Sopenharmony_ci	memset(&pe, 0, sizeof(pe));
184162306a36Sopenharmony_ci	mvpp2_prs_tcam_lu_set(&pe, MVPP2_PRS_LU_IP6);
184262306a36Sopenharmony_ci	pe.index = tid;
184362306a36Sopenharmony_ci
184462306a36Sopenharmony_ci	/* Finished: go to flowid generation */
184562306a36Sopenharmony_ci	mvpp2_prs_sram_next_lu_set(&pe, MVPP2_PRS_LU_FLOWS);
184662306a36Sopenharmony_ci	mvpp2_prs_sram_bits_set(&pe, MVPP2_PRS_SRAM_LU_GEN_BIT, 1);
184762306a36Sopenharmony_ci	mvpp2_prs_sram_ri_update(&pe, MVPP2_PRS_RI_L3_UN |
184862306a36Sopenharmony_ci				 MVPP2_PRS_RI_DROP_MASK,
184962306a36Sopenharmony_ci				 MVPP2_PRS_RI_L3_PROTO_MASK |
185062306a36Sopenharmony_ci				 MVPP2_PRS_RI_DROP_MASK);
185162306a36Sopenharmony_ci
185262306a36Sopenharmony_ci	mvpp2_prs_tcam_data_byte_set(&pe, 1, 0x00, MVPP2_PRS_IPV6_HOP_MASK);
185362306a36Sopenharmony_ci	mvpp2_prs_tcam_ai_update(&pe, MVPP2_PRS_IPV6_NO_EXT_AI_BIT,
185462306a36Sopenharmony_ci				 MVPP2_PRS_IPV6_NO_EXT_AI_BIT);
185562306a36Sopenharmony_ci
185662306a36Sopenharmony_ci	/* Update shadow table and hw entry */
185762306a36Sopenharmony_ci	mvpp2_prs_shadow_set(priv, pe.index, MVPP2_PRS_LU_IP4);
185862306a36Sopenharmony_ci	mvpp2_prs_hw_write(priv, &pe);
185962306a36Sopenharmony_ci
186062306a36Sopenharmony_ci	/* Default IPv6 entry for unknown protocols */
186162306a36Sopenharmony_ci	memset(&pe, 0, sizeof(pe));
186262306a36Sopenharmony_ci	mvpp2_prs_tcam_lu_set(&pe, MVPP2_PRS_LU_IP6);
186362306a36Sopenharmony_ci	pe.index = MVPP2_PE_IP6_PROTO_UN;
186462306a36Sopenharmony_ci
186562306a36Sopenharmony_ci	/* Finished: go to flowid generation */
186662306a36Sopenharmony_ci	mvpp2_prs_sram_next_lu_set(&pe, MVPP2_PRS_LU_FLOWS);
186762306a36Sopenharmony_ci	mvpp2_prs_sram_bits_set(&pe, MVPP2_PRS_SRAM_LU_GEN_BIT, 1);
186862306a36Sopenharmony_ci	mvpp2_prs_sram_ri_update(&pe, MVPP2_PRS_RI_L4_OTHER,
186962306a36Sopenharmony_ci				 MVPP2_PRS_RI_L4_PROTO_MASK);
187062306a36Sopenharmony_ci	/* Set L4 offset relatively to our current place */
187162306a36Sopenharmony_ci	mvpp2_prs_sram_offset_set(&pe, MVPP2_PRS_SRAM_UDF_TYPE_L4,
187262306a36Sopenharmony_ci				  sizeof(struct ipv6hdr) - 4,
187362306a36Sopenharmony_ci				  MVPP2_PRS_SRAM_OP_SEL_UDF_ADD);
187462306a36Sopenharmony_ci
187562306a36Sopenharmony_ci	mvpp2_prs_tcam_ai_update(&pe, MVPP2_PRS_IPV6_NO_EXT_AI_BIT,
187662306a36Sopenharmony_ci				 MVPP2_PRS_IPV6_NO_EXT_AI_BIT);
187762306a36Sopenharmony_ci	/* Unmask all ports */
187862306a36Sopenharmony_ci	mvpp2_prs_tcam_port_map_set(&pe, MVPP2_PRS_PORT_MASK);
187962306a36Sopenharmony_ci
188062306a36Sopenharmony_ci	/* Update shadow table and hw entry */
188162306a36Sopenharmony_ci	mvpp2_prs_shadow_set(priv, pe.index, MVPP2_PRS_LU_IP4);
188262306a36Sopenharmony_ci	mvpp2_prs_hw_write(priv, &pe);
188362306a36Sopenharmony_ci
188462306a36Sopenharmony_ci	/* Default IPv6 entry for unknown ext protocols */
188562306a36Sopenharmony_ci	memset(&pe, 0, sizeof(struct mvpp2_prs_entry));
188662306a36Sopenharmony_ci	mvpp2_prs_tcam_lu_set(&pe, MVPP2_PRS_LU_IP6);
188762306a36Sopenharmony_ci	pe.index = MVPP2_PE_IP6_EXT_PROTO_UN;
188862306a36Sopenharmony_ci
188962306a36Sopenharmony_ci	/* Finished: go to flowid generation */
189062306a36Sopenharmony_ci	mvpp2_prs_sram_next_lu_set(&pe, MVPP2_PRS_LU_FLOWS);
189162306a36Sopenharmony_ci	mvpp2_prs_sram_bits_set(&pe, MVPP2_PRS_SRAM_LU_GEN_BIT, 1);
189262306a36Sopenharmony_ci	mvpp2_prs_sram_ri_update(&pe, MVPP2_PRS_RI_L4_OTHER,
189362306a36Sopenharmony_ci				 MVPP2_PRS_RI_L4_PROTO_MASK);
189462306a36Sopenharmony_ci
189562306a36Sopenharmony_ci	mvpp2_prs_tcam_ai_update(&pe, MVPP2_PRS_IPV6_EXT_AI_BIT,
189662306a36Sopenharmony_ci				 MVPP2_PRS_IPV6_EXT_AI_BIT);
189762306a36Sopenharmony_ci	/* Unmask all ports */
189862306a36Sopenharmony_ci	mvpp2_prs_tcam_port_map_set(&pe, MVPP2_PRS_PORT_MASK);
189962306a36Sopenharmony_ci
190062306a36Sopenharmony_ci	/* Update shadow table and hw entry */
190162306a36Sopenharmony_ci	mvpp2_prs_shadow_set(priv, pe.index, MVPP2_PRS_LU_IP4);
190262306a36Sopenharmony_ci	mvpp2_prs_hw_write(priv, &pe);
190362306a36Sopenharmony_ci
190462306a36Sopenharmony_ci	/* Default IPv6 entry for unicast address */
190562306a36Sopenharmony_ci	memset(&pe, 0, sizeof(struct mvpp2_prs_entry));
190662306a36Sopenharmony_ci	mvpp2_prs_tcam_lu_set(&pe, MVPP2_PRS_LU_IP6);
190762306a36Sopenharmony_ci	pe.index = MVPP2_PE_IP6_ADDR_UN;
190862306a36Sopenharmony_ci
190962306a36Sopenharmony_ci	/* Finished: go to IPv6 again */
191062306a36Sopenharmony_ci	mvpp2_prs_sram_next_lu_set(&pe, MVPP2_PRS_LU_IP6);
191162306a36Sopenharmony_ci	mvpp2_prs_sram_ri_update(&pe, MVPP2_PRS_RI_L3_UCAST,
191262306a36Sopenharmony_ci				 MVPP2_PRS_RI_L3_ADDR_MASK);
191362306a36Sopenharmony_ci	mvpp2_prs_sram_ai_update(&pe, MVPP2_PRS_IPV6_NO_EXT_AI_BIT,
191462306a36Sopenharmony_ci				 MVPP2_PRS_IPV6_NO_EXT_AI_BIT);
191562306a36Sopenharmony_ci	/* Shift back to IPV6 NH */
191662306a36Sopenharmony_ci	mvpp2_prs_sram_shift_set(&pe, -18, MVPP2_PRS_SRAM_OP_SEL_SHIFT_ADD);
191762306a36Sopenharmony_ci
191862306a36Sopenharmony_ci	mvpp2_prs_tcam_ai_update(&pe, 0, MVPP2_PRS_IPV6_NO_EXT_AI_BIT);
191962306a36Sopenharmony_ci	/* Unmask all ports */
192062306a36Sopenharmony_ci	mvpp2_prs_tcam_port_map_set(&pe, MVPP2_PRS_PORT_MASK);
192162306a36Sopenharmony_ci
192262306a36Sopenharmony_ci	/* Update shadow table and hw entry */
192362306a36Sopenharmony_ci	mvpp2_prs_shadow_set(priv, pe.index, MVPP2_PRS_LU_IP6);
192462306a36Sopenharmony_ci	mvpp2_prs_hw_write(priv, &pe);
192562306a36Sopenharmony_ci
192662306a36Sopenharmony_ci	return 0;
192762306a36Sopenharmony_ci}
192862306a36Sopenharmony_ci
192962306a36Sopenharmony_ci/* Find tcam entry with matched pair <vid,port> */
193062306a36Sopenharmony_cistatic int mvpp2_prs_vid_range_find(struct mvpp2_port *port, u16 vid, u16 mask)
193162306a36Sopenharmony_ci{
193262306a36Sopenharmony_ci	unsigned char byte[2], enable[2];
193362306a36Sopenharmony_ci	struct mvpp2_prs_entry pe;
193462306a36Sopenharmony_ci	u16 rvid, rmask;
193562306a36Sopenharmony_ci	int tid;
193662306a36Sopenharmony_ci
193762306a36Sopenharmony_ci	/* Go through the all entries with MVPP2_PRS_LU_VID */
193862306a36Sopenharmony_ci	for (tid = MVPP2_PRS_VID_PORT_FIRST(port->id);
193962306a36Sopenharmony_ci	     tid <= MVPP2_PRS_VID_PORT_LAST(port->id); tid++) {
194062306a36Sopenharmony_ci		if (!port->priv->prs_shadow[tid].valid ||
194162306a36Sopenharmony_ci		    port->priv->prs_shadow[tid].lu != MVPP2_PRS_LU_VID)
194262306a36Sopenharmony_ci			continue;
194362306a36Sopenharmony_ci
194462306a36Sopenharmony_ci		mvpp2_prs_init_from_hw(port->priv, &pe, tid);
194562306a36Sopenharmony_ci
194662306a36Sopenharmony_ci		mvpp2_prs_tcam_data_byte_get(&pe, 2, &byte[0], &enable[0]);
194762306a36Sopenharmony_ci		mvpp2_prs_tcam_data_byte_get(&pe, 3, &byte[1], &enable[1]);
194862306a36Sopenharmony_ci
194962306a36Sopenharmony_ci		rvid = ((byte[0] & 0xf) << 8) + byte[1];
195062306a36Sopenharmony_ci		rmask = ((enable[0] & 0xf) << 8) + enable[1];
195162306a36Sopenharmony_ci
195262306a36Sopenharmony_ci		if (rvid != vid || rmask != mask)
195362306a36Sopenharmony_ci			continue;
195462306a36Sopenharmony_ci
195562306a36Sopenharmony_ci		return tid;
195662306a36Sopenharmony_ci	}
195762306a36Sopenharmony_ci
195862306a36Sopenharmony_ci	return -ENOENT;
195962306a36Sopenharmony_ci}
196062306a36Sopenharmony_ci
196162306a36Sopenharmony_ci/* Write parser entry for VID filtering */
196262306a36Sopenharmony_ciint mvpp2_prs_vid_entry_add(struct mvpp2_port *port, u16 vid)
196362306a36Sopenharmony_ci{
196462306a36Sopenharmony_ci	unsigned int vid_start = MVPP2_PE_VID_FILT_RANGE_START +
196562306a36Sopenharmony_ci				 port->id * MVPP2_PRS_VLAN_FILT_MAX;
196662306a36Sopenharmony_ci	unsigned int mask = 0xfff, reg_val, shift;
196762306a36Sopenharmony_ci	struct mvpp2 *priv = port->priv;
196862306a36Sopenharmony_ci	struct mvpp2_prs_entry pe;
196962306a36Sopenharmony_ci	int tid;
197062306a36Sopenharmony_ci
197162306a36Sopenharmony_ci	memset(&pe, 0, sizeof(pe));
197262306a36Sopenharmony_ci
197362306a36Sopenharmony_ci	/* Scan TCAM and see if entry with this <vid,port> already exist */
197462306a36Sopenharmony_ci	tid = mvpp2_prs_vid_range_find(port, vid, mask);
197562306a36Sopenharmony_ci
197662306a36Sopenharmony_ci	reg_val = mvpp2_read(priv, MVPP2_MH_REG(port->id));
197762306a36Sopenharmony_ci	if (reg_val & MVPP2_DSA_EXTENDED)
197862306a36Sopenharmony_ci		shift = MVPP2_VLAN_TAG_EDSA_LEN;
197962306a36Sopenharmony_ci	else
198062306a36Sopenharmony_ci		shift = MVPP2_VLAN_TAG_LEN;
198162306a36Sopenharmony_ci
198262306a36Sopenharmony_ci	/* No such entry */
198362306a36Sopenharmony_ci	if (tid < 0) {
198462306a36Sopenharmony_ci
198562306a36Sopenharmony_ci		/* Go through all entries from first to last in vlan range */
198662306a36Sopenharmony_ci		tid = mvpp2_prs_tcam_first_free(priv, vid_start,
198762306a36Sopenharmony_ci						vid_start +
198862306a36Sopenharmony_ci						MVPP2_PRS_VLAN_FILT_MAX_ENTRY);
198962306a36Sopenharmony_ci
199062306a36Sopenharmony_ci		/* There isn't room for a new VID filter */
199162306a36Sopenharmony_ci		if (tid < 0)
199262306a36Sopenharmony_ci			return tid;
199362306a36Sopenharmony_ci
199462306a36Sopenharmony_ci		mvpp2_prs_tcam_lu_set(&pe, MVPP2_PRS_LU_VID);
199562306a36Sopenharmony_ci		pe.index = tid;
199662306a36Sopenharmony_ci
199762306a36Sopenharmony_ci		/* Mask all ports */
199862306a36Sopenharmony_ci		mvpp2_prs_tcam_port_map_set(&pe, 0);
199962306a36Sopenharmony_ci	} else {
200062306a36Sopenharmony_ci		mvpp2_prs_init_from_hw(priv, &pe, tid);
200162306a36Sopenharmony_ci	}
200262306a36Sopenharmony_ci
200362306a36Sopenharmony_ci	/* Enable the current port */
200462306a36Sopenharmony_ci	mvpp2_prs_tcam_port_set(&pe, port->id, true);
200562306a36Sopenharmony_ci
200662306a36Sopenharmony_ci	/* Continue - set next lookup */
200762306a36Sopenharmony_ci	mvpp2_prs_sram_next_lu_set(&pe, MVPP2_PRS_LU_L2);
200862306a36Sopenharmony_ci
200962306a36Sopenharmony_ci	/* Skip VLAN header - Set offset to 4 or 8 bytes */
201062306a36Sopenharmony_ci	mvpp2_prs_sram_shift_set(&pe, shift, MVPP2_PRS_SRAM_OP_SEL_SHIFT_ADD);
201162306a36Sopenharmony_ci
201262306a36Sopenharmony_ci	/* Set match on VID */
201362306a36Sopenharmony_ci	mvpp2_prs_match_vid(&pe, MVPP2_PRS_VID_TCAM_BYTE, vid);
201462306a36Sopenharmony_ci
201562306a36Sopenharmony_ci	/* Clear all ai bits for next iteration */
201662306a36Sopenharmony_ci	mvpp2_prs_sram_ai_update(&pe, 0, MVPP2_PRS_SRAM_AI_MASK);
201762306a36Sopenharmony_ci
201862306a36Sopenharmony_ci	/* Update shadow table */
201962306a36Sopenharmony_ci	mvpp2_prs_shadow_set(priv, pe.index, MVPP2_PRS_LU_VID);
202062306a36Sopenharmony_ci	mvpp2_prs_hw_write(priv, &pe);
202162306a36Sopenharmony_ci
202262306a36Sopenharmony_ci	return 0;
202362306a36Sopenharmony_ci}
202462306a36Sopenharmony_ci
202562306a36Sopenharmony_ci/* Write parser entry for VID filtering */
202662306a36Sopenharmony_civoid mvpp2_prs_vid_entry_remove(struct mvpp2_port *port, u16 vid)
202762306a36Sopenharmony_ci{
202862306a36Sopenharmony_ci	struct mvpp2 *priv = port->priv;
202962306a36Sopenharmony_ci	int tid;
203062306a36Sopenharmony_ci
203162306a36Sopenharmony_ci	/* Scan TCAM and see if entry with this <vid,port> already exist */
203262306a36Sopenharmony_ci	tid = mvpp2_prs_vid_range_find(port, vid, 0xfff);
203362306a36Sopenharmony_ci
203462306a36Sopenharmony_ci	/* No such entry */
203562306a36Sopenharmony_ci	if (tid < 0)
203662306a36Sopenharmony_ci		return;
203762306a36Sopenharmony_ci
203862306a36Sopenharmony_ci	mvpp2_prs_hw_inv(priv, tid);
203962306a36Sopenharmony_ci	priv->prs_shadow[tid].valid = false;
204062306a36Sopenharmony_ci}
204162306a36Sopenharmony_ci
204262306a36Sopenharmony_ci/* Remove all existing VID filters on this port */
204362306a36Sopenharmony_civoid mvpp2_prs_vid_remove_all(struct mvpp2_port *port)
204462306a36Sopenharmony_ci{
204562306a36Sopenharmony_ci	struct mvpp2 *priv = port->priv;
204662306a36Sopenharmony_ci	int tid;
204762306a36Sopenharmony_ci
204862306a36Sopenharmony_ci	for (tid = MVPP2_PRS_VID_PORT_FIRST(port->id);
204962306a36Sopenharmony_ci	     tid <= MVPP2_PRS_VID_PORT_LAST(port->id); tid++) {
205062306a36Sopenharmony_ci		if (priv->prs_shadow[tid].valid) {
205162306a36Sopenharmony_ci			mvpp2_prs_hw_inv(priv, tid);
205262306a36Sopenharmony_ci			priv->prs_shadow[tid].valid = false;
205362306a36Sopenharmony_ci		}
205462306a36Sopenharmony_ci	}
205562306a36Sopenharmony_ci}
205662306a36Sopenharmony_ci
205762306a36Sopenharmony_ci/* Remove VID filering entry for this port */
205862306a36Sopenharmony_civoid mvpp2_prs_vid_disable_filtering(struct mvpp2_port *port)
205962306a36Sopenharmony_ci{
206062306a36Sopenharmony_ci	unsigned int tid = MVPP2_PRS_VID_PORT_DFLT(port->id);
206162306a36Sopenharmony_ci	struct mvpp2 *priv = port->priv;
206262306a36Sopenharmony_ci
206362306a36Sopenharmony_ci	/* Invalidate the guard entry */
206462306a36Sopenharmony_ci	mvpp2_prs_hw_inv(priv, tid);
206562306a36Sopenharmony_ci
206662306a36Sopenharmony_ci	priv->prs_shadow[tid].valid = false;
206762306a36Sopenharmony_ci}
206862306a36Sopenharmony_ci
206962306a36Sopenharmony_ci/* Add guard entry that drops packets when no VID is matched on this port */
207062306a36Sopenharmony_civoid mvpp2_prs_vid_enable_filtering(struct mvpp2_port *port)
207162306a36Sopenharmony_ci{
207262306a36Sopenharmony_ci	unsigned int tid = MVPP2_PRS_VID_PORT_DFLT(port->id);
207362306a36Sopenharmony_ci	struct mvpp2 *priv = port->priv;
207462306a36Sopenharmony_ci	unsigned int reg_val, shift;
207562306a36Sopenharmony_ci	struct mvpp2_prs_entry pe;
207662306a36Sopenharmony_ci
207762306a36Sopenharmony_ci	if (priv->prs_shadow[tid].valid)
207862306a36Sopenharmony_ci		return;
207962306a36Sopenharmony_ci
208062306a36Sopenharmony_ci	memset(&pe, 0, sizeof(pe));
208162306a36Sopenharmony_ci
208262306a36Sopenharmony_ci	pe.index = tid;
208362306a36Sopenharmony_ci
208462306a36Sopenharmony_ci	reg_val = mvpp2_read(priv, MVPP2_MH_REG(port->id));
208562306a36Sopenharmony_ci	if (reg_val & MVPP2_DSA_EXTENDED)
208662306a36Sopenharmony_ci		shift = MVPP2_VLAN_TAG_EDSA_LEN;
208762306a36Sopenharmony_ci	else
208862306a36Sopenharmony_ci		shift = MVPP2_VLAN_TAG_LEN;
208962306a36Sopenharmony_ci
209062306a36Sopenharmony_ci	mvpp2_prs_tcam_lu_set(&pe, MVPP2_PRS_LU_VID);
209162306a36Sopenharmony_ci
209262306a36Sopenharmony_ci	/* Mask all ports */
209362306a36Sopenharmony_ci	mvpp2_prs_tcam_port_map_set(&pe, 0);
209462306a36Sopenharmony_ci
209562306a36Sopenharmony_ci	/* Update port mask */
209662306a36Sopenharmony_ci	mvpp2_prs_tcam_port_set(&pe, port->id, true);
209762306a36Sopenharmony_ci
209862306a36Sopenharmony_ci	/* Continue - set next lookup */
209962306a36Sopenharmony_ci	mvpp2_prs_sram_next_lu_set(&pe, MVPP2_PRS_LU_L2);
210062306a36Sopenharmony_ci
210162306a36Sopenharmony_ci	/* Skip VLAN header - Set offset to 4 or 8 bytes */
210262306a36Sopenharmony_ci	mvpp2_prs_sram_shift_set(&pe, shift, MVPP2_PRS_SRAM_OP_SEL_SHIFT_ADD);
210362306a36Sopenharmony_ci
210462306a36Sopenharmony_ci	/* Drop VLAN packets that don't belong to any VIDs on this port */
210562306a36Sopenharmony_ci	mvpp2_prs_sram_ri_update(&pe, MVPP2_PRS_RI_DROP_MASK,
210662306a36Sopenharmony_ci				 MVPP2_PRS_RI_DROP_MASK);
210762306a36Sopenharmony_ci
210862306a36Sopenharmony_ci	/* Clear all ai bits for next iteration */
210962306a36Sopenharmony_ci	mvpp2_prs_sram_ai_update(&pe, 0, MVPP2_PRS_SRAM_AI_MASK);
211062306a36Sopenharmony_ci
211162306a36Sopenharmony_ci	/* Update shadow table */
211262306a36Sopenharmony_ci	mvpp2_prs_shadow_set(priv, pe.index, MVPP2_PRS_LU_VID);
211362306a36Sopenharmony_ci	mvpp2_prs_hw_write(priv, &pe);
211462306a36Sopenharmony_ci}
211562306a36Sopenharmony_ci
211662306a36Sopenharmony_ci/* Parser default initialization */
211762306a36Sopenharmony_ciint mvpp2_prs_default_init(struct platform_device *pdev, struct mvpp2 *priv)
211862306a36Sopenharmony_ci{
211962306a36Sopenharmony_ci	int err, index, i;
212062306a36Sopenharmony_ci
212162306a36Sopenharmony_ci	/* Enable tcam table */
212262306a36Sopenharmony_ci	mvpp2_write(priv, MVPP2_PRS_TCAM_CTRL_REG, MVPP2_PRS_TCAM_EN_MASK);
212362306a36Sopenharmony_ci
212462306a36Sopenharmony_ci	/* Clear all tcam and sram entries */
212562306a36Sopenharmony_ci	for (index = 0; index < MVPP2_PRS_TCAM_SRAM_SIZE; index++) {
212662306a36Sopenharmony_ci		mvpp2_write(priv, MVPP2_PRS_TCAM_IDX_REG, index);
212762306a36Sopenharmony_ci		for (i = 0; i < MVPP2_PRS_TCAM_WORDS; i++)
212862306a36Sopenharmony_ci			mvpp2_write(priv, MVPP2_PRS_TCAM_DATA_REG(i), 0);
212962306a36Sopenharmony_ci
213062306a36Sopenharmony_ci		mvpp2_write(priv, MVPP2_PRS_SRAM_IDX_REG, index);
213162306a36Sopenharmony_ci		for (i = 0; i < MVPP2_PRS_SRAM_WORDS; i++)
213262306a36Sopenharmony_ci			mvpp2_write(priv, MVPP2_PRS_SRAM_DATA_REG(i), 0);
213362306a36Sopenharmony_ci	}
213462306a36Sopenharmony_ci
213562306a36Sopenharmony_ci	/* Invalidate all tcam entries */
213662306a36Sopenharmony_ci	for (index = 0; index < MVPP2_PRS_TCAM_SRAM_SIZE; index++)
213762306a36Sopenharmony_ci		mvpp2_prs_hw_inv(priv, index);
213862306a36Sopenharmony_ci
213962306a36Sopenharmony_ci	priv->prs_shadow = devm_kcalloc(&pdev->dev, MVPP2_PRS_TCAM_SRAM_SIZE,
214062306a36Sopenharmony_ci					sizeof(*priv->prs_shadow),
214162306a36Sopenharmony_ci					GFP_KERNEL);
214262306a36Sopenharmony_ci	if (!priv->prs_shadow)
214362306a36Sopenharmony_ci		return -ENOMEM;
214462306a36Sopenharmony_ci
214562306a36Sopenharmony_ci	/* Always start from lookup = 0 */
214662306a36Sopenharmony_ci	for (index = 0; index < MVPP2_MAX_PORTS; index++)
214762306a36Sopenharmony_ci		mvpp2_prs_hw_port_init(priv, index, MVPP2_PRS_LU_MH,
214862306a36Sopenharmony_ci				       MVPP2_PRS_PORT_LU_MAX, 0);
214962306a36Sopenharmony_ci
215062306a36Sopenharmony_ci	mvpp2_prs_def_flow_init(priv);
215162306a36Sopenharmony_ci
215262306a36Sopenharmony_ci	mvpp2_prs_mh_init(priv);
215362306a36Sopenharmony_ci
215462306a36Sopenharmony_ci	mvpp2_prs_mac_init(priv);
215562306a36Sopenharmony_ci
215662306a36Sopenharmony_ci	mvpp2_prs_dsa_init(priv);
215762306a36Sopenharmony_ci
215862306a36Sopenharmony_ci	mvpp2_prs_vid_init(priv);
215962306a36Sopenharmony_ci
216062306a36Sopenharmony_ci	err = mvpp2_prs_etype_init(priv);
216162306a36Sopenharmony_ci	if (err)
216262306a36Sopenharmony_ci		return err;
216362306a36Sopenharmony_ci
216462306a36Sopenharmony_ci	err = mvpp2_prs_vlan_init(pdev, priv);
216562306a36Sopenharmony_ci	if (err)
216662306a36Sopenharmony_ci		return err;
216762306a36Sopenharmony_ci
216862306a36Sopenharmony_ci	err = mvpp2_prs_pppoe_init(priv);
216962306a36Sopenharmony_ci	if (err)
217062306a36Sopenharmony_ci		return err;
217162306a36Sopenharmony_ci
217262306a36Sopenharmony_ci	err = mvpp2_prs_ip6_init(priv);
217362306a36Sopenharmony_ci	if (err)
217462306a36Sopenharmony_ci		return err;
217562306a36Sopenharmony_ci
217662306a36Sopenharmony_ci	err = mvpp2_prs_ip4_init(priv);
217762306a36Sopenharmony_ci	if (err)
217862306a36Sopenharmony_ci		return err;
217962306a36Sopenharmony_ci
218062306a36Sopenharmony_ci	return 0;
218162306a36Sopenharmony_ci}
218262306a36Sopenharmony_ci
218362306a36Sopenharmony_ci/* Compare MAC DA with tcam entry data */
218462306a36Sopenharmony_cistatic bool mvpp2_prs_mac_range_equals(struct mvpp2_prs_entry *pe,
218562306a36Sopenharmony_ci				       const u8 *da, unsigned char *mask)
218662306a36Sopenharmony_ci{
218762306a36Sopenharmony_ci	unsigned char tcam_byte, tcam_mask;
218862306a36Sopenharmony_ci	int index;
218962306a36Sopenharmony_ci
219062306a36Sopenharmony_ci	for (index = 0; index < ETH_ALEN; index++) {
219162306a36Sopenharmony_ci		mvpp2_prs_tcam_data_byte_get(pe, index, &tcam_byte, &tcam_mask);
219262306a36Sopenharmony_ci		if (tcam_mask != mask[index])
219362306a36Sopenharmony_ci			return false;
219462306a36Sopenharmony_ci
219562306a36Sopenharmony_ci		if ((tcam_mask & tcam_byte) != (da[index] & mask[index]))
219662306a36Sopenharmony_ci			return false;
219762306a36Sopenharmony_ci	}
219862306a36Sopenharmony_ci
219962306a36Sopenharmony_ci	return true;
220062306a36Sopenharmony_ci}
220162306a36Sopenharmony_ci
220262306a36Sopenharmony_ci/* Find tcam entry with matched pair <MAC DA, port> */
220362306a36Sopenharmony_cistatic int
220462306a36Sopenharmony_cimvpp2_prs_mac_da_range_find(struct mvpp2 *priv, int pmap, const u8 *da,
220562306a36Sopenharmony_ci			    unsigned char *mask, int udf_type)
220662306a36Sopenharmony_ci{
220762306a36Sopenharmony_ci	struct mvpp2_prs_entry pe;
220862306a36Sopenharmony_ci	int tid;
220962306a36Sopenharmony_ci
221062306a36Sopenharmony_ci	/* Go through the all entires with MVPP2_PRS_LU_MAC */
221162306a36Sopenharmony_ci	for (tid = MVPP2_PE_MAC_RANGE_START;
221262306a36Sopenharmony_ci	     tid <= MVPP2_PE_MAC_RANGE_END; tid++) {
221362306a36Sopenharmony_ci		unsigned int entry_pmap;
221462306a36Sopenharmony_ci
221562306a36Sopenharmony_ci		if (!priv->prs_shadow[tid].valid ||
221662306a36Sopenharmony_ci		    (priv->prs_shadow[tid].lu != MVPP2_PRS_LU_MAC) ||
221762306a36Sopenharmony_ci		    (priv->prs_shadow[tid].udf != udf_type))
221862306a36Sopenharmony_ci			continue;
221962306a36Sopenharmony_ci
222062306a36Sopenharmony_ci		mvpp2_prs_init_from_hw(priv, &pe, tid);
222162306a36Sopenharmony_ci		entry_pmap = mvpp2_prs_tcam_port_map_get(&pe);
222262306a36Sopenharmony_ci
222362306a36Sopenharmony_ci		if (mvpp2_prs_mac_range_equals(&pe, da, mask) &&
222462306a36Sopenharmony_ci		    entry_pmap == pmap)
222562306a36Sopenharmony_ci			return tid;
222662306a36Sopenharmony_ci	}
222762306a36Sopenharmony_ci
222862306a36Sopenharmony_ci	return -ENOENT;
222962306a36Sopenharmony_ci}
223062306a36Sopenharmony_ci
223162306a36Sopenharmony_ci/* Update parser's mac da entry */
223262306a36Sopenharmony_ciint mvpp2_prs_mac_da_accept(struct mvpp2_port *port, const u8 *da, bool add)
223362306a36Sopenharmony_ci{
223462306a36Sopenharmony_ci	unsigned char mask[ETH_ALEN] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
223562306a36Sopenharmony_ci	struct mvpp2 *priv = port->priv;
223662306a36Sopenharmony_ci	unsigned int pmap, len, ri;
223762306a36Sopenharmony_ci	struct mvpp2_prs_entry pe;
223862306a36Sopenharmony_ci	int tid;
223962306a36Sopenharmony_ci
224062306a36Sopenharmony_ci	memset(&pe, 0, sizeof(pe));
224162306a36Sopenharmony_ci
224262306a36Sopenharmony_ci	/* Scan TCAM and see if entry with this <MAC DA, port> already exist */
224362306a36Sopenharmony_ci	tid = mvpp2_prs_mac_da_range_find(priv, BIT(port->id), da, mask,
224462306a36Sopenharmony_ci					  MVPP2_PRS_UDF_MAC_DEF);
224562306a36Sopenharmony_ci
224662306a36Sopenharmony_ci	/* No such entry */
224762306a36Sopenharmony_ci	if (tid < 0) {
224862306a36Sopenharmony_ci		if (!add)
224962306a36Sopenharmony_ci			return 0;
225062306a36Sopenharmony_ci
225162306a36Sopenharmony_ci		/* Create new TCAM entry */
225262306a36Sopenharmony_ci		/* Go through the all entries from first to last */
225362306a36Sopenharmony_ci		tid = mvpp2_prs_tcam_first_free(priv,
225462306a36Sopenharmony_ci						MVPP2_PE_MAC_RANGE_START,
225562306a36Sopenharmony_ci						MVPP2_PE_MAC_RANGE_END);
225662306a36Sopenharmony_ci		if (tid < 0)
225762306a36Sopenharmony_ci			return tid;
225862306a36Sopenharmony_ci
225962306a36Sopenharmony_ci		pe.index = tid;
226062306a36Sopenharmony_ci
226162306a36Sopenharmony_ci		/* Mask all ports */
226262306a36Sopenharmony_ci		mvpp2_prs_tcam_port_map_set(&pe, 0);
226362306a36Sopenharmony_ci	} else {
226462306a36Sopenharmony_ci		mvpp2_prs_init_from_hw(priv, &pe, tid);
226562306a36Sopenharmony_ci	}
226662306a36Sopenharmony_ci
226762306a36Sopenharmony_ci	mvpp2_prs_tcam_lu_set(&pe, MVPP2_PRS_LU_MAC);
226862306a36Sopenharmony_ci
226962306a36Sopenharmony_ci	/* Update port mask */
227062306a36Sopenharmony_ci	mvpp2_prs_tcam_port_set(&pe, port->id, add);
227162306a36Sopenharmony_ci
227262306a36Sopenharmony_ci	/* Invalidate the entry if no ports are left enabled */
227362306a36Sopenharmony_ci	pmap = mvpp2_prs_tcam_port_map_get(&pe);
227462306a36Sopenharmony_ci	if (pmap == 0) {
227562306a36Sopenharmony_ci		if (add)
227662306a36Sopenharmony_ci			return -EINVAL;
227762306a36Sopenharmony_ci
227862306a36Sopenharmony_ci		mvpp2_prs_hw_inv(priv, pe.index);
227962306a36Sopenharmony_ci		priv->prs_shadow[pe.index].valid = false;
228062306a36Sopenharmony_ci		return 0;
228162306a36Sopenharmony_ci	}
228262306a36Sopenharmony_ci
228362306a36Sopenharmony_ci	/* Continue - set next lookup */
228462306a36Sopenharmony_ci	mvpp2_prs_sram_next_lu_set(&pe, MVPP2_PRS_LU_DSA);
228562306a36Sopenharmony_ci
228662306a36Sopenharmony_ci	/* Set match on DA */
228762306a36Sopenharmony_ci	len = ETH_ALEN;
228862306a36Sopenharmony_ci	while (len--)
228962306a36Sopenharmony_ci		mvpp2_prs_tcam_data_byte_set(&pe, len, da[len], 0xff);
229062306a36Sopenharmony_ci
229162306a36Sopenharmony_ci	/* Set result info bits */
229262306a36Sopenharmony_ci	if (is_broadcast_ether_addr(da)) {
229362306a36Sopenharmony_ci		ri = MVPP2_PRS_RI_L2_BCAST;
229462306a36Sopenharmony_ci	} else if (is_multicast_ether_addr(da)) {
229562306a36Sopenharmony_ci		ri = MVPP2_PRS_RI_L2_MCAST;
229662306a36Sopenharmony_ci	} else {
229762306a36Sopenharmony_ci		ri = MVPP2_PRS_RI_L2_UCAST;
229862306a36Sopenharmony_ci
229962306a36Sopenharmony_ci		if (ether_addr_equal(da, port->dev->dev_addr))
230062306a36Sopenharmony_ci			ri |= MVPP2_PRS_RI_MAC_ME_MASK;
230162306a36Sopenharmony_ci	}
230262306a36Sopenharmony_ci
230362306a36Sopenharmony_ci	mvpp2_prs_sram_ri_update(&pe, ri, MVPP2_PRS_RI_L2_CAST_MASK |
230462306a36Sopenharmony_ci				 MVPP2_PRS_RI_MAC_ME_MASK);
230562306a36Sopenharmony_ci	mvpp2_prs_shadow_ri_set(priv, pe.index, ri, MVPP2_PRS_RI_L2_CAST_MASK |
230662306a36Sopenharmony_ci				MVPP2_PRS_RI_MAC_ME_MASK);
230762306a36Sopenharmony_ci
230862306a36Sopenharmony_ci	/* Shift to ethertype */
230962306a36Sopenharmony_ci	mvpp2_prs_sram_shift_set(&pe, 2 * ETH_ALEN,
231062306a36Sopenharmony_ci				 MVPP2_PRS_SRAM_OP_SEL_SHIFT_ADD);
231162306a36Sopenharmony_ci
231262306a36Sopenharmony_ci	/* Update shadow table and hw entry */
231362306a36Sopenharmony_ci	priv->prs_shadow[pe.index].udf = MVPP2_PRS_UDF_MAC_DEF;
231462306a36Sopenharmony_ci	mvpp2_prs_shadow_set(priv, pe.index, MVPP2_PRS_LU_MAC);
231562306a36Sopenharmony_ci	mvpp2_prs_hw_write(priv, &pe);
231662306a36Sopenharmony_ci
231762306a36Sopenharmony_ci	return 0;
231862306a36Sopenharmony_ci}
231962306a36Sopenharmony_ci
232062306a36Sopenharmony_ciint mvpp2_prs_update_mac_da(struct net_device *dev, const u8 *da)
232162306a36Sopenharmony_ci{
232262306a36Sopenharmony_ci	struct mvpp2_port *port = netdev_priv(dev);
232362306a36Sopenharmony_ci	int err;
232462306a36Sopenharmony_ci
232562306a36Sopenharmony_ci	/* Remove old parser entry */
232662306a36Sopenharmony_ci	err = mvpp2_prs_mac_da_accept(port, dev->dev_addr, false);
232762306a36Sopenharmony_ci	if (err)
232862306a36Sopenharmony_ci		return err;
232962306a36Sopenharmony_ci
233062306a36Sopenharmony_ci	/* Add new parser entry */
233162306a36Sopenharmony_ci	err = mvpp2_prs_mac_da_accept(port, da, true);
233262306a36Sopenharmony_ci	if (err)
233362306a36Sopenharmony_ci		return err;
233462306a36Sopenharmony_ci
233562306a36Sopenharmony_ci	/* Set addr in the device */
233662306a36Sopenharmony_ci	eth_hw_addr_set(dev, da);
233762306a36Sopenharmony_ci
233862306a36Sopenharmony_ci	return 0;
233962306a36Sopenharmony_ci}
234062306a36Sopenharmony_ci
234162306a36Sopenharmony_civoid mvpp2_prs_mac_del_all(struct mvpp2_port *port)
234262306a36Sopenharmony_ci{
234362306a36Sopenharmony_ci	struct mvpp2 *priv = port->priv;
234462306a36Sopenharmony_ci	struct mvpp2_prs_entry pe;
234562306a36Sopenharmony_ci	unsigned long pmap;
234662306a36Sopenharmony_ci	int index, tid;
234762306a36Sopenharmony_ci
234862306a36Sopenharmony_ci	for (tid = MVPP2_PE_MAC_RANGE_START;
234962306a36Sopenharmony_ci	     tid <= MVPP2_PE_MAC_RANGE_END; tid++) {
235062306a36Sopenharmony_ci		unsigned char da[ETH_ALEN], da_mask[ETH_ALEN];
235162306a36Sopenharmony_ci
235262306a36Sopenharmony_ci		if (!priv->prs_shadow[tid].valid ||
235362306a36Sopenharmony_ci		    (priv->prs_shadow[tid].lu != MVPP2_PRS_LU_MAC) ||
235462306a36Sopenharmony_ci		    (priv->prs_shadow[tid].udf != MVPP2_PRS_UDF_MAC_DEF))
235562306a36Sopenharmony_ci			continue;
235662306a36Sopenharmony_ci
235762306a36Sopenharmony_ci		mvpp2_prs_init_from_hw(priv, &pe, tid);
235862306a36Sopenharmony_ci
235962306a36Sopenharmony_ci		pmap = mvpp2_prs_tcam_port_map_get(&pe);
236062306a36Sopenharmony_ci
236162306a36Sopenharmony_ci		/* We only want entries active on this port */
236262306a36Sopenharmony_ci		if (!test_bit(port->id, &pmap))
236362306a36Sopenharmony_ci			continue;
236462306a36Sopenharmony_ci
236562306a36Sopenharmony_ci		/* Read mac addr from entry */
236662306a36Sopenharmony_ci		for (index = 0; index < ETH_ALEN; index++)
236762306a36Sopenharmony_ci			mvpp2_prs_tcam_data_byte_get(&pe, index, &da[index],
236862306a36Sopenharmony_ci						     &da_mask[index]);
236962306a36Sopenharmony_ci
237062306a36Sopenharmony_ci		/* Special cases : Don't remove broadcast and port's own
237162306a36Sopenharmony_ci		 * address
237262306a36Sopenharmony_ci		 */
237362306a36Sopenharmony_ci		if (is_broadcast_ether_addr(da) ||
237462306a36Sopenharmony_ci		    ether_addr_equal(da, port->dev->dev_addr))
237562306a36Sopenharmony_ci			continue;
237662306a36Sopenharmony_ci
237762306a36Sopenharmony_ci		/* Remove entry from TCAM */
237862306a36Sopenharmony_ci		mvpp2_prs_mac_da_accept(port, da, false);
237962306a36Sopenharmony_ci	}
238062306a36Sopenharmony_ci}
238162306a36Sopenharmony_ci
238262306a36Sopenharmony_ciint mvpp2_prs_tag_mode_set(struct mvpp2 *priv, int port, int type)
238362306a36Sopenharmony_ci{
238462306a36Sopenharmony_ci	switch (type) {
238562306a36Sopenharmony_ci	case MVPP2_TAG_TYPE_EDSA:
238662306a36Sopenharmony_ci		/* Add port to EDSA entries */
238762306a36Sopenharmony_ci		mvpp2_prs_dsa_tag_set(priv, port, true,
238862306a36Sopenharmony_ci				      MVPP2_PRS_TAGGED, MVPP2_PRS_EDSA);
238962306a36Sopenharmony_ci		mvpp2_prs_dsa_tag_set(priv, port, true,
239062306a36Sopenharmony_ci				      MVPP2_PRS_UNTAGGED, MVPP2_PRS_EDSA);
239162306a36Sopenharmony_ci		/* Remove port from DSA entries */
239262306a36Sopenharmony_ci		mvpp2_prs_dsa_tag_set(priv, port, false,
239362306a36Sopenharmony_ci				      MVPP2_PRS_TAGGED, MVPP2_PRS_DSA);
239462306a36Sopenharmony_ci		mvpp2_prs_dsa_tag_set(priv, port, false,
239562306a36Sopenharmony_ci				      MVPP2_PRS_UNTAGGED, MVPP2_PRS_DSA);
239662306a36Sopenharmony_ci		break;
239762306a36Sopenharmony_ci
239862306a36Sopenharmony_ci	case MVPP2_TAG_TYPE_DSA:
239962306a36Sopenharmony_ci		/* Add port to DSA entries */
240062306a36Sopenharmony_ci		mvpp2_prs_dsa_tag_set(priv, port, true,
240162306a36Sopenharmony_ci				      MVPP2_PRS_TAGGED, MVPP2_PRS_DSA);
240262306a36Sopenharmony_ci		mvpp2_prs_dsa_tag_set(priv, port, true,
240362306a36Sopenharmony_ci				      MVPP2_PRS_UNTAGGED, MVPP2_PRS_DSA);
240462306a36Sopenharmony_ci		/* Remove port from EDSA entries */
240562306a36Sopenharmony_ci		mvpp2_prs_dsa_tag_set(priv, port, false,
240662306a36Sopenharmony_ci				      MVPP2_PRS_TAGGED, MVPP2_PRS_EDSA);
240762306a36Sopenharmony_ci		mvpp2_prs_dsa_tag_set(priv, port, false,
240862306a36Sopenharmony_ci				      MVPP2_PRS_UNTAGGED, MVPP2_PRS_EDSA);
240962306a36Sopenharmony_ci		break;
241062306a36Sopenharmony_ci
241162306a36Sopenharmony_ci	case MVPP2_TAG_TYPE_MH:
241262306a36Sopenharmony_ci	case MVPP2_TAG_TYPE_NONE:
241362306a36Sopenharmony_ci		/* Remove port form EDSA and DSA entries */
241462306a36Sopenharmony_ci		mvpp2_prs_dsa_tag_set(priv, port, false,
241562306a36Sopenharmony_ci				      MVPP2_PRS_TAGGED, MVPP2_PRS_DSA);
241662306a36Sopenharmony_ci		mvpp2_prs_dsa_tag_set(priv, port, false,
241762306a36Sopenharmony_ci				      MVPP2_PRS_UNTAGGED, MVPP2_PRS_DSA);
241862306a36Sopenharmony_ci		mvpp2_prs_dsa_tag_set(priv, port, false,
241962306a36Sopenharmony_ci				      MVPP2_PRS_TAGGED, MVPP2_PRS_EDSA);
242062306a36Sopenharmony_ci		mvpp2_prs_dsa_tag_set(priv, port, false,
242162306a36Sopenharmony_ci				      MVPP2_PRS_UNTAGGED, MVPP2_PRS_EDSA);
242262306a36Sopenharmony_ci		break;
242362306a36Sopenharmony_ci
242462306a36Sopenharmony_ci	default:
242562306a36Sopenharmony_ci		if ((type < 0) || (type > MVPP2_TAG_TYPE_EDSA))
242662306a36Sopenharmony_ci			return -EINVAL;
242762306a36Sopenharmony_ci	}
242862306a36Sopenharmony_ci
242962306a36Sopenharmony_ci	return 0;
243062306a36Sopenharmony_ci}
243162306a36Sopenharmony_ci
243262306a36Sopenharmony_ciint mvpp2_prs_add_flow(struct mvpp2 *priv, int flow, u32 ri, u32 ri_mask)
243362306a36Sopenharmony_ci{
243462306a36Sopenharmony_ci	struct mvpp2_prs_entry pe;
243562306a36Sopenharmony_ci	u8 *ri_byte, *ri_byte_mask;
243662306a36Sopenharmony_ci	int tid, i;
243762306a36Sopenharmony_ci
243862306a36Sopenharmony_ci	memset(&pe, 0, sizeof(pe));
243962306a36Sopenharmony_ci
244062306a36Sopenharmony_ci	tid = mvpp2_prs_tcam_first_free(priv,
244162306a36Sopenharmony_ci					MVPP2_PE_LAST_FREE_TID,
244262306a36Sopenharmony_ci					MVPP2_PE_FIRST_FREE_TID);
244362306a36Sopenharmony_ci	if (tid < 0)
244462306a36Sopenharmony_ci		return tid;
244562306a36Sopenharmony_ci
244662306a36Sopenharmony_ci	pe.index = tid;
244762306a36Sopenharmony_ci
244862306a36Sopenharmony_ci	ri_byte = (u8 *)&ri;
244962306a36Sopenharmony_ci	ri_byte_mask = (u8 *)&ri_mask;
245062306a36Sopenharmony_ci
245162306a36Sopenharmony_ci	mvpp2_prs_sram_ai_update(&pe, flow, MVPP2_PRS_FLOW_ID_MASK);
245262306a36Sopenharmony_ci	mvpp2_prs_sram_bits_set(&pe, MVPP2_PRS_SRAM_LU_DONE_BIT, 1);
245362306a36Sopenharmony_ci
245462306a36Sopenharmony_ci	for (i = 0; i < 4; i++) {
245562306a36Sopenharmony_ci		mvpp2_prs_tcam_data_byte_set(&pe, i, ri_byte[i],
245662306a36Sopenharmony_ci					     ri_byte_mask[i]);
245762306a36Sopenharmony_ci	}
245862306a36Sopenharmony_ci
245962306a36Sopenharmony_ci	mvpp2_prs_shadow_set(priv, pe.index, MVPP2_PRS_LU_FLOWS);
246062306a36Sopenharmony_ci	mvpp2_prs_tcam_lu_set(&pe, MVPP2_PRS_LU_FLOWS);
246162306a36Sopenharmony_ci	mvpp2_prs_tcam_port_map_set(&pe, MVPP2_PRS_PORT_MASK);
246262306a36Sopenharmony_ci	mvpp2_prs_hw_write(priv, &pe);
246362306a36Sopenharmony_ci
246462306a36Sopenharmony_ci	return 0;
246562306a36Sopenharmony_ci}
246662306a36Sopenharmony_ci
246762306a36Sopenharmony_ci/* Set prs flow for the port */
246862306a36Sopenharmony_ciint mvpp2_prs_def_flow(struct mvpp2_port *port)
246962306a36Sopenharmony_ci{
247062306a36Sopenharmony_ci	struct mvpp2_prs_entry pe;
247162306a36Sopenharmony_ci	int tid;
247262306a36Sopenharmony_ci
247362306a36Sopenharmony_ci	memset(&pe, 0, sizeof(pe));
247462306a36Sopenharmony_ci
247562306a36Sopenharmony_ci	tid = mvpp2_prs_flow_find(port->priv, port->id);
247662306a36Sopenharmony_ci
247762306a36Sopenharmony_ci	/* Such entry not exist */
247862306a36Sopenharmony_ci	if (tid < 0) {
247962306a36Sopenharmony_ci		/* Go through the all entires from last to first */
248062306a36Sopenharmony_ci		tid = mvpp2_prs_tcam_first_free(port->priv,
248162306a36Sopenharmony_ci						MVPP2_PE_LAST_FREE_TID,
248262306a36Sopenharmony_ci					       MVPP2_PE_FIRST_FREE_TID);
248362306a36Sopenharmony_ci		if (tid < 0)
248462306a36Sopenharmony_ci			return tid;
248562306a36Sopenharmony_ci
248662306a36Sopenharmony_ci		pe.index = tid;
248762306a36Sopenharmony_ci
248862306a36Sopenharmony_ci		/* Set flow ID*/
248962306a36Sopenharmony_ci		mvpp2_prs_sram_ai_update(&pe, port->id, MVPP2_PRS_FLOW_ID_MASK);
249062306a36Sopenharmony_ci		mvpp2_prs_sram_bits_set(&pe, MVPP2_PRS_SRAM_LU_DONE_BIT, 1);
249162306a36Sopenharmony_ci
249262306a36Sopenharmony_ci		/* Update shadow table */
249362306a36Sopenharmony_ci		mvpp2_prs_shadow_set(port->priv, pe.index, MVPP2_PRS_LU_FLOWS);
249462306a36Sopenharmony_ci	} else {
249562306a36Sopenharmony_ci		mvpp2_prs_init_from_hw(port->priv, &pe, tid);
249662306a36Sopenharmony_ci	}
249762306a36Sopenharmony_ci
249862306a36Sopenharmony_ci	mvpp2_prs_tcam_lu_set(&pe, MVPP2_PRS_LU_FLOWS);
249962306a36Sopenharmony_ci	mvpp2_prs_tcam_port_map_set(&pe, (1 << port->id));
250062306a36Sopenharmony_ci	mvpp2_prs_hw_write(port->priv, &pe);
250162306a36Sopenharmony_ci
250262306a36Sopenharmony_ci	return 0;
250362306a36Sopenharmony_ci}
250462306a36Sopenharmony_ci
250562306a36Sopenharmony_ciint mvpp2_prs_hits(struct mvpp2 *priv, int index)
250662306a36Sopenharmony_ci{
250762306a36Sopenharmony_ci	u32 val;
250862306a36Sopenharmony_ci
250962306a36Sopenharmony_ci	if (index > MVPP2_PRS_TCAM_SRAM_SIZE)
251062306a36Sopenharmony_ci		return -EINVAL;
251162306a36Sopenharmony_ci
251262306a36Sopenharmony_ci	mvpp2_write(priv, MVPP2_PRS_TCAM_HIT_IDX_REG, index);
251362306a36Sopenharmony_ci
251462306a36Sopenharmony_ci	val = mvpp2_read(priv, MVPP2_PRS_TCAM_HIT_CNT_REG);
251562306a36Sopenharmony_ci
251662306a36Sopenharmony_ci	val &= MVPP2_PRS_TCAM_HIT_CNT_MASK;
251762306a36Sopenharmony_ci
251862306a36Sopenharmony_ci	return val;
251962306a36Sopenharmony_ci}
2520