18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * Header Parser helpers for Marvell PPv2 Network Controller
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * Copyright (C) 2014 Marvell
68c2ecf20Sopenharmony_ci *
78c2ecf20Sopenharmony_ci * Marcin Wojtas <mw@semihalf.com>
88c2ecf20Sopenharmony_ci */
98c2ecf20Sopenharmony_ci
108c2ecf20Sopenharmony_ci#include <linux/kernel.h>
118c2ecf20Sopenharmony_ci#include <linux/netdevice.h>
128c2ecf20Sopenharmony_ci#include <linux/etherdevice.h>
138c2ecf20Sopenharmony_ci#include <linux/platform_device.h>
148c2ecf20Sopenharmony_ci#include <uapi/linux/ppp_defs.h>
158c2ecf20Sopenharmony_ci#include <net/ip.h>
168c2ecf20Sopenharmony_ci#include <net/ipv6.h>
178c2ecf20Sopenharmony_ci
188c2ecf20Sopenharmony_ci#include "mvpp2.h"
198c2ecf20Sopenharmony_ci#include "mvpp2_prs.h"
208c2ecf20Sopenharmony_ci
218c2ecf20Sopenharmony_ci/* Update parser tcam and sram hw entries */
228c2ecf20Sopenharmony_cistatic int mvpp2_prs_hw_write(struct mvpp2 *priv, struct mvpp2_prs_entry *pe)
238c2ecf20Sopenharmony_ci{
248c2ecf20Sopenharmony_ci	int i;
258c2ecf20Sopenharmony_ci
268c2ecf20Sopenharmony_ci	if (pe->index > MVPP2_PRS_TCAM_SRAM_SIZE - 1)
278c2ecf20Sopenharmony_ci		return -EINVAL;
288c2ecf20Sopenharmony_ci
298c2ecf20Sopenharmony_ci	/* Clear entry invalidation bit */
308c2ecf20Sopenharmony_ci	pe->tcam[MVPP2_PRS_TCAM_INV_WORD] &= ~MVPP2_PRS_TCAM_INV_MASK;
318c2ecf20Sopenharmony_ci
328c2ecf20Sopenharmony_ci	/* Write sram index - indirect access */
338c2ecf20Sopenharmony_ci	mvpp2_write(priv, MVPP2_PRS_SRAM_IDX_REG, pe->index);
348c2ecf20Sopenharmony_ci	for (i = 0; i < MVPP2_PRS_SRAM_WORDS; i++)
358c2ecf20Sopenharmony_ci		mvpp2_write(priv, MVPP2_PRS_SRAM_DATA_REG(i), pe->sram[i]);
368c2ecf20Sopenharmony_ci
378c2ecf20Sopenharmony_ci	/* Write tcam index - indirect access */
388c2ecf20Sopenharmony_ci	mvpp2_write(priv, MVPP2_PRS_TCAM_IDX_REG, pe->index);
398c2ecf20Sopenharmony_ci	for (i = 0; i < MVPP2_PRS_TCAM_WORDS; i++)
408c2ecf20Sopenharmony_ci		mvpp2_write(priv, MVPP2_PRS_TCAM_DATA_REG(i), pe->tcam[i]);
418c2ecf20Sopenharmony_ci
428c2ecf20Sopenharmony_ci	return 0;
438c2ecf20Sopenharmony_ci}
448c2ecf20Sopenharmony_ci
458c2ecf20Sopenharmony_ci/* Initialize tcam entry from hw */
468c2ecf20Sopenharmony_ciint mvpp2_prs_init_from_hw(struct mvpp2 *priv, struct mvpp2_prs_entry *pe,
478c2ecf20Sopenharmony_ci			   int tid)
488c2ecf20Sopenharmony_ci{
498c2ecf20Sopenharmony_ci	int i;
508c2ecf20Sopenharmony_ci
518c2ecf20Sopenharmony_ci	if (tid > MVPP2_PRS_TCAM_SRAM_SIZE - 1)
528c2ecf20Sopenharmony_ci		return -EINVAL;
538c2ecf20Sopenharmony_ci
548c2ecf20Sopenharmony_ci	memset(pe, 0, sizeof(*pe));
558c2ecf20Sopenharmony_ci	pe->index = tid;
568c2ecf20Sopenharmony_ci
578c2ecf20Sopenharmony_ci	/* Write tcam index - indirect access */
588c2ecf20Sopenharmony_ci	mvpp2_write(priv, MVPP2_PRS_TCAM_IDX_REG, pe->index);
598c2ecf20Sopenharmony_ci
608c2ecf20Sopenharmony_ci	pe->tcam[MVPP2_PRS_TCAM_INV_WORD] = mvpp2_read(priv,
618c2ecf20Sopenharmony_ci			      MVPP2_PRS_TCAM_DATA_REG(MVPP2_PRS_TCAM_INV_WORD));
628c2ecf20Sopenharmony_ci	if (pe->tcam[MVPP2_PRS_TCAM_INV_WORD] & MVPP2_PRS_TCAM_INV_MASK)
638c2ecf20Sopenharmony_ci		return MVPP2_PRS_TCAM_ENTRY_INVALID;
648c2ecf20Sopenharmony_ci
658c2ecf20Sopenharmony_ci	for (i = 0; i < MVPP2_PRS_TCAM_WORDS; i++)
668c2ecf20Sopenharmony_ci		pe->tcam[i] = mvpp2_read(priv, MVPP2_PRS_TCAM_DATA_REG(i));
678c2ecf20Sopenharmony_ci
688c2ecf20Sopenharmony_ci	/* Write sram index - indirect access */
698c2ecf20Sopenharmony_ci	mvpp2_write(priv, MVPP2_PRS_SRAM_IDX_REG, pe->index);
708c2ecf20Sopenharmony_ci	for (i = 0; i < MVPP2_PRS_SRAM_WORDS; i++)
718c2ecf20Sopenharmony_ci		pe->sram[i] = mvpp2_read(priv, MVPP2_PRS_SRAM_DATA_REG(i));
728c2ecf20Sopenharmony_ci
738c2ecf20Sopenharmony_ci	return 0;
748c2ecf20Sopenharmony_ci}
758c2ecf20Sopenharmony_ci
768c2ecf20Sopenharmony_ci/* Invalidate tcam hw entry */
778c2ecf20Sopenharmony_cistatic void mvpp2_prs_hw_inv(struct mvpp2 *priv, int index)
788c2ecf20Sopenharmony_ci{
798c2ecf20Sopenharmony_ci	/* Write index - indirect access */
808c2ecf20Sopenharmony_ci	mvpp2_write(priv, MVPP2_PRS_TCAM_IDX_REG, index);
818c2ecf20Sopenharmony_ci	mvpp2_write(priv, MVPP2_PRS_TCAM_DATA_REG(MVPP2_PRS_TCAM_INV_WORD),
828c2ecf20Sopenharmony_ci		    MVPP2_PRS_TCAM_INV_MASK);
838c2ecf20Sopenharmony_ci}
848c2ecf20Sopenharmony_ci
858c2ecf20Sopenharmony_ci/* Enable shadow table entry and set its lookup ID */
868c2ecf20Sopenharmony_cistatic void mvpp2_prs_shadow_set(struct mvpp2 *priv, int index, int lu)
878c2ecf20Sopenharmony_ci{
888c2ecf20Sopenharmony_ci	priv->prs_shadow[index].valid = true;
898c2ecf20Sopenharmony_ci	priv->prs_shadow[index].lu = lu;
908c2ecf20Sopenharmony_ci}
918c2ecf20Sopenharmony_ci
928c2ecf20Sopenharmony_ci/* Update ri fields in shadow table entry */
938c2ecf20Sopenharmony_cistatic void mvpp2_prs_shadow_ri_set(struct mvpp2 *priv, int index,
948c2ecf20Sopenharmony_ci				    unsigned int ri, unsigned int ri_mask)
958c2ecf20Sopenharmony_ci{
968c2ecf20Sopenharmony_ci	priv->prs_shadow[index].ri_mask = ri_mask;
978c2ecf20Sopenharmony_ci	priv->prs_shadow[index].ri = ri;
988c2ecf20Sopenharmony_ci}
998c2ecf20Sopenharmony_ci
1008c2ecf20Sopenharmony_ci/* Update lookup field in tcam sw entry */
1018c2ecf20Sopenharmony_cistatic void mvpp2_prs_tcam_lu_set(struct mvpp2_prs_entry *pe, unsigned int lu)
1028c2ecf20Sopenharmony_ci{
1038c2ecf20Sopenharmony_ci	pe->tcam[MVPP2_PRS_TCAM_LU_WORD] &= ~MVPP2_PRS_TCAM_LU(MVPP2_PRS_LU_MASK);
1048c2ecf20Sopenharmony_ci	pe->tcam[MVPP2_PRS_TCAM_LU_WORD] &= ~MVPP2_PRS_TCAM_LU_EN(MVPP2_PRS_LU_MASK);
1058c2ecf20Sopenharmony_ci	pe->tcam[MVPP2_PRS_TCAM_LU_WORD] |= MVPP2_PRS_TCAM_LU(lu & MVPP2_PRS_LU_MASK);
1068c2ecf20Sopenharmony_ci	pe->tcam[MVPP2_PRS_TCAM_LU_WORD] |= MVPP2_PRS_TCAM_LU_EN(MVPP2_PRS_LU_MASK);
1078c2ecf20Sopenharmony_ci}
1088c2ecf20Sopenharmony_ci
1098c2ecf20Sopenharmony_ci/* Update mask for single port in tcam sw entry */
1108c2ecf20Sopenharmony_cistatic void mvpp2_prs_tcam_port_set(struct mvpp2_prs_entry *pe,
1118c2ecf20Sopenharmony_ci				    unsigned int port, bool add)
1128c2ecf20Sopenharmony_ci{
1138c2ecf20Sopenharmony_ci	if (add)
1148c2ecf20Sopenharmony_ci		pe->tcam[MVPP2_PRS_TCAM_PORT_WORD] &= ~MVPP2_PRS_TCAM_PORT_EN(BIT(port));
1158c2ecf20Sopenharmony_ci	else
1168c2ecf20Sopenharmony_ci		pe->tcam[MVPP2_PRS_TCAM_PORT_WORD] |= MVPP2_PRS_TCAM_PORT_EN(BIT(port));
1178c2ecf20Sopenharmony_ci}
1188c2ecf20Sopenharmony_ci
1198c2ecf20Sopenharmony_ci/* Update port map in tcam sw entry */
1208c2ecf20Sopenharmony_cistatic void mvpp2_prs_tcam_port_map_set(struct mvpp2_prs_entry *pe,
1218c2ecf20Sopenharmony_ci					unsigned int ports)
1228c2ecf20Sopenharmony_ci{
1238c2ecf20Sopenharmony_ci	pe->tcam[MVPP2_PRS_TCAM_PORT_WORD] &= ~MVPP2_PRS_TCAM_PORT(MVPP2_PRS_PORT_MASK);
1248c2ecf20Sopenharmony_ci	pe->tcam[MVPP2_PRS_TCAM_PORT_WORD] &= ~MVPP2_PRS_TCAM_PORT_EN(MVPP2_PRS_PORT_MASK);
1258c2ecf20Sopenharmony_ci	pe->tcam[MVPP2_PRS_TCAM_PORT_WORD] |= MVPP2_PRS_TCAM_PORT_EN(~ports & MVPP2_PRS_PORT_MASK);
1268c2ecf20Sopenharmony_ci}
1278c2ecf20Sopenharmony_ci
1288c2ecf20Sopenharmony_ci/* Obtain port map from tcam sw entry */
1298c2ecf20Sopenharmony_ciunsigned int mvpp2_prs_tcam_port_map_get(struct mvpp2_prs_entry *pe)
1308c2ecf20Sopenharmony_ci{
1318c2ecf20Sopenharmony_ci	return (~pe->tcam[MVPP2_PRS_TCAM_PORT_WORD] >> 24) & MVPP2_PRS_PORT_MASK;
1328c2ecf20Sopenharmony_ci}
1338c2ecf20Sopenharmony_ci
1348c2ecf20Sopenharmony_ci/* Set byte of data and its enable bits in tcam sw entry */
1358c2ecf20Sopenharmony_cistatic void mvpp2_prs_tcam_data_byte_set(struct mvpp2_prs_entry *pe,
1368c2ecf20Sopenharmony_ci					 unsigned int offs, unsigned char byte,
1378c2ecf20Sopenharmony_ci					 unsigned char enable)
1388c2ecf20Sopenharmony_ci{
1398c2ecf20Sopenharmony_ci	int pos = MVPP2_PRS_BYTE_IN_WORD(offs) * BITS_PER_BYTE;
1408c2ecf20Sopenharmony_ci
1418c2ecf20Sopenharmony_ci	pe->tcam[MVPP2_PRS_BYTE_TO_WORD(offs)] &= ~(0xff << pos);
1428c2ecf20Sopenharmony_ci	pe->tcam[MVPP2_PRS_BYTE_TO_WORD(offs)] &= ~(MVPP2_PRS_TCAM_EN(0xff) << pos);
1438c2ecf20Sopenharmony_ci	pe->tcam[MVPP2_PRS_BYTE_TO_WORD(offs)] |= byte << pos;
1448c2ecf20Sopenharmony_ci	pe->tcam[MVPP2_PRS_BYTE_TO_WORD(offs)] |= MVPP2_PRS_TCAM_EN(enable << pos);
1458c2ecf20Sopenharmony_ci}
1468c2ecf20Sopenharmony_ci
1478c2ecf20Sopenharmony_ci/* Get byte of data and its enable bits from tcam sw entry */
1488c2ecf20Sopenharmony_civoid mvpp2_prs_tcam_data_byte_get(struct mvpp2_prs_entry *pe,
1498c2ecf20Sopenharmony_ci				  unsigned int offs, unsigned char *byte,
1508c2ecf20Sopenharmony_ci				  unsigned char *enable)
1518c2ecf20Sopenharmony_ci{
1528c2ecf20Sopenharmony_ci	int pos = MVPP2_PRS_BYTE_IN_WORD(offs) * BITS_PER_BYTE;
1538c2ecf20Sopenharmony_ci
1548c2ecf20Sopenharmony_ci	*byte = (pe->tcam[MVPP2_PRS_BYTE_TO_WORD(offs)] >> pos) & 0xff;
1558c2ecf20Sopenharmony_ci	*enable = (pe->tcam[MVPP2_PRS_BYTE_TO_WORD(offs)] >> (pos + 16)) & 0xff;
1568c2ecf20Sopenharmony_ci}
1578c2ecf20Sopenharmony_ci
1588c2ecf20Sopenharmony_ci/* Compare tcam data bytes with a pattern */
1598c2ecf20Sopenharmony_cistatic bool mvpp2_prs_tcam_data_cmp(struct mvpp2_prs_entry *pe, int offs,
1608c2ecf20Sopenharmony_ci				    u16 data)
1618c2ecf20Sopenharmony_ci{
1628c2ecf20Sopenharmony_ci	u16 tcam_data;
1638c2ecf20Sopenharmony_ci
1648c2ecf20Sopenharmony_ci	tcam_data = pe->tcam[MVPP2_PRS_BYTE_TO_WORD(offs)] & 0xffff;
1658c2ecf20Sopenharmony_ci	return tcam_data == data;
1668c2ecf20Sopenharmony_ci}
1678c2ecf20Sopenharmony_ci
1688c2ecf20Sopenharmony_ci/* Update ai bits in tcam sw entry */
1698c2ecf20Sopenharmony_cistatic void mvpp2_prs_tcam_ai_update(struct mvpp2_prs_entry *pe,
1708c2ecf20Sopenharmony_ci				     unsigned int bits, unsigned int enable)
1718c2ecf20Sopenharmony_ci{
1728c2ecf20Sopenharmony_ci	int i;
1738c2ecf20Sopenharmony_ci
1748c2ecf20Sopenharmony_ci	for (i = 0; i < MVPP2_PRS_AI_BITS; i++) {
1758c2ecf20Sopenharmony_ci		if (!(enable & BIT(i)))
1768c2ecf20Sopenharmony_ci			continue;
1778c2ecf20Sopenharmony_ci
1788c2ecf20Sopenharmony_ci		if (bits & BIT(i))
1798c2ecf20Sopenharmony_ci			pe->tcam[MVPP2_PRS_TCAM_AI_WORD] |= BIT(i);
1808c2ecf20Sopenharmony_ci		else
1818c2ecf20Sopenharmony_ci			pe->tcam[MVPP2_PRS_TCAM_AI_WORD] &= ~BIT(i);
1828c2ecf20Sopenharmony_ci	}
1838c2ecf20Sopenharmony_ci
1848c2ecf20Sopenharmony_ci	pe->tcam[MVPP2_PRS_TCAM_AI_WORD] |= MVPP2_PRS_TCAM_AI_EN(enable);
1858c2ecf20Sopenharmony_ci}
1868c2ecf20Sopenharmony_ci
1878c2ecf20Sopenharmony_ci/* Get ai bits from tcam sw entry */
1888c2ecf20Sopenharmony_cistatic int mvpp2_prs_tcam_ai_get(struct mvpp2_prs_entry *pe)
1898c2ecf20Sopenharmony_ci{
1908c2ecf20Sopenharmony_ci	return pe->tcam[MVPP2_PRS_TCAM_AI_WORD] & MVPP2_PRS_AI_MASK;
1918c2ecf20Sopenharmony_ci}
1928c2ecf20Sopenharmony_ci
1938c2ecf20Sopenharmony_ci/* Set ethertype in tcam sw entry */
1948c2ecf20Sopenharmony_cistatic void mvpp2_prs_match_etype(struct mvpp2_prs_entry *pe, int offset,
1958c2ecf20Sopenharmony_ci				  unsigned short ethertype)
1968c2ecf20Sopenharmony_ci{
1978c2ecf20Sopenharmony_ci	mvpp2_prs_tcam_data_byte_set(pe, offset + 0, ethertype >> 8, 0xff);
1988c2ecf20Sopenharmony_ci	mvpp2_prs_tcam_data_byte_set(pe, offset + 1, ethertype & 0xff, 0xff);
1998c2ecf20Sopenharmony_ci}
2008c2ecf20Sopenharmony_ci
2018c2ecf20Sopenharmony_ci/* Set vid in tcam sw entry */
2028c2ecf20Sopenharmony_cistatic void mvpp2_prs_match_vid(struct mvpp2_prs_entry *pe, int offset,
2038c2ecf20Sopenharmony_ci				unsigned short vid)
2048c2ecf20Sopenharmony_ci{
2058c2ecf20Sopenharmony_ci	mvpp2_prs_tcam_data_byte_set(pe, offset + 0, (vid & 0xf00) >> 8, 0xf);
2068c2ecf20Sopenharmony_ci	mvpp2_prs_tcam_data_byte_set(pe, offset + 1, vid & 0xff, 0xff);
2078c2ecf20Sopenharmony_ci}
2088c2ecf20Sopenharmony_ci
2098c2ecf20Sopenharmony_ci/* Set bits in sram sw entry */
2108c2ecf20Sopenharmony_cistatic void mvpp2_prs_sram_bits_set(struct mvpp2_prs_entry *pe, int bit_num,
2118c2ecf20Sopenharmony_ci				    u32 val)
2128c2ecf20Sopenharmony_ci{
2138c2ecf20Sopenharmony_ci	pe->sram[MVPP2_BIT_TO_WORD(bit_num)] |= (val << (MVPP2_BIT_IN_WORD(bit_num)));
2148c2ecf20Sopenharmony_ci}
2158c2ecf20Sopenharmony_ci
2168c2ecf20Sopenharmony_ci/* Clear bits in sram sw entry */
2178c2ecf20Sopenharmony_cistatic void mvpp2_prs_sram_bits_clear(struct mvpp2_prs_entry *pe, int bit_num,
2188c2ecf20Sopenharmony_ci				      u32 val)
2198c2ecf20Sopenharmony_ci{
2208c2ecf20Sopenharmony_ci	pe->sram[MVPP2_BIT_TO_WORD(bit_num)] &= ~(val << (MVPP2_BIT_IN_WORD(bit_num)));
2218c2ecf20Sopenharmony_ci}
2228c2ecf20Sopenharmony_ci
2238c2ecf20Sopenharmony_ci/* Update ri bits in sram sw entry */
2248c2ecf20Sopenharmony_cistatic void mvpp2_prs_sram_ri_update(struct mvpp2_prs_entry *pe,
2258c2ecf20Sopenharmony_ci				     unsigned int bits, unsigned int mask)
2268c2ecf20Sopenharmony_ci{
2278c2ecf20Sopenharmony_ci	unsigned int i;
2288c2ecf20Sopenharmony_ci
2298c2ecf20Sopenharmony_ci	for (i = 0; i < MVPP2_PRS_SRAM_RI_CTRL_BITS; i++) {
2308c2ecf20Sopenharmony_ci		if (!(mask & BIT(i)))
2318c2ecf20Sopenharmony_ci			continue;
2328c2ecf20Sopenharmony_ci
2338c2ecf20Sopenharmony_ci		if (bits & BIT(i))
2348c2ecf20Sopenharmony_ci			mvpp2_prs_sram_bits_set(pe, MVPP2_PRS_SRAM_RI_OFFS + i,
2358c2ecf20Sopenharmony_ci						1);
2368c2ecf20Sopenharmony_ci		else
2378c2ecf20Sopenharmony_ci			mvpp2_prs_sram_bits_clear(pe,
2388c2ecf20Sopenharmony_ci						  MVPP2_PRS_SRAM_RI_OFFS + i,
2398c2ecf20Sopenharmony_ci						  1);
2408c2ecf20Sopenharmony_ci
2418c2ecf20Sopenharmony_ci		mvpp2_prs_sram_bits_set(pe, MVPP2_PRS_SRAM_RI_CTRL_OFFS + i, 1);
2428c2ecf20Sopenharmony_ci	}
2438c2ecf20Sopenharmony_ci}
2448c2ecf20Sopenharmony_ci
2458c2ecf20Sopenharmony_ci/* Obtain ri bits from sram sw entry */
2468c2ecf20Sopenharmony_cistatic int mvpp2_prs_sram_ri_get(struct mvpp2_prs_entry *pe)
2478c2ecf20Sopenharmony_ci{
2488c2ecf20Sopenharmony_ci	return pe->sram[MVPP2_PRS_SRAM_RI_WORD];
2498c2ecf20Sopenharmony_ci}
2508c2ecf20Sopenharmony_ci
2518c2ecf20Sopenharmony_ci/* Update ai bits in sram sw entry */
2528c2ecf20Sopenharmony_cistatic void mvpp2_prs_sram_ai_update(struct mvpp2_prs_entry *pe,
2538c2ecf20Sopenharmony_ci				     unsigned int bits, unsigned int mask)
2548c2ecf20Sopenharmony_ci{
2558c2ecf20Sopenharmony_ci	unsigned int i;
2568c2ecf20Sopenharmony_ci
2578c2ecf20Sopenharmony_ci	for (i = 0; i < MVPP2_PRS_SRAM_AI_CTRL_BITS; i++) {
2588c2ecf20Sopenharmony_ci		if (!(mask & BIT(i)))
2598c2ecf20Sopenharmony_ci			continue;
2608c2ecf20Sopenharmony_ci
2618c2ecf20Sopenharmony_ci		if (bits & BIT(i))
2628c2ecf20Sopenharmony_ci			mvpp2_prs_sram_bits_set(pe, MVPP2_PRS_SRAM_AI_OFFS + i,
2638c2ecf20Sopenharmony_ci						1);
2648c2ecf20Sopenharmony_ci		else
2658c2ecf20Sopenharmony_ci			mvpp2_prs_sram_bits_clear(pe,
2668c2ecf20Sopenharmony_ci						  MVPP2_PRS_SRAM_AI_OFFS + i,
2678c2ecf20Sopenharmony_ci						  1);
2688c2ecf20Sopenharmony_ci
2698c2ecf20Sopenharmony_ci		mvpp2_prs_sram_bits_set(pe, MVPP2_PRS_SRAM_AI_CTRL_OFFS + i, 1);
2708c2ecf20Sopenharmony_ci	}
2718c2ecf20Sopenharmony_ci}
2728c2ecf20Sopenharmony_ci
2738c2ecf20Sopenharmony_ci/* Read ai bits from sram sw entry */
2748c2ecf20Sopenharmony_cistatic int mvpp2_prs_sram_ai_get(struct mvpp2_prs_entry *pe)
2758c2ecf20Sopenharmony_ci{
2768c2ecf20Sopenharmony_ci	u8 bits;
2778c2ecf20Sopenharmony_ci	/* ai is stored on bits 90->97; so it spreads across two u32 */
2788c2ecf20Sopenharmony_ci	int ai_off = MVPP2_BIT_TO_WORD(MVPP2_PRS_SRAM_AI_OFFS);
2798c2ecf20Sopenharmony_ci	int ai_shift = MVPP2_BIT_IN_WORD(MVPP2_PRS_SRAM_AI_OFFS);
2808c2ecf20Sopenharmony_ci
2818c2ecf20Sopenharmony_ci	bits = (pe->sram[ai_off] >> ai_shift) |
2828c2ecf20Sopenharmony_ci	       (pe->sram[ai_off + 1] << (32 - ai_shift));
2838c2ecf20Sopenharmony_ci
2848c2ecf20Sopenharmony_ci	return bits;
2858c2ecf20Sopenharmony_ci}
2868c2ecf20Sopenharmony_ci
2878c2ecf20Sopenharmony_ci/* In sram sw entry set lookup ID field of the tcam key to be used in the next
2888c2ecf20Sopenharmony_ci * lookup interation
2898c2ecf20Sopenharmony_ci */
2908c2ecf20Sopenharmony_cistatic void mvpp2_prs_sram_next_lu_set(struct mvpp2_prs_entry *pe,
2918c2ecf20Sopenharmony_ci				       unsigned int lu)
2928c2ecf20Sopenharmony_ci{
2938c2ecf20Sopenharmony_ci	int sram_next_off = MVPP2_PRS_SRAM_NEXT_LU_OFFS;
2948c2ecf20Sopenharmony_ci
2958c2ecf20Sopenharmony_ci	mvpp2_prs_sram_bits_clear(pe, sram_next_off,
2968c2ecf20Sopenharmony_ci				  MVPP2_PRS_SRAM_NEXT_LU_MASK);
2978c2ecf20Sopenharmony_ci	mvpp2_prs_sram_bits_set(pe, sram_next_off, lu);
2988c2ecf20Sopenharmony_ci}
2998c2ecf20Sopenharmony_ci
3008c2ecf20Sopenharmony_ci/* In the sram sw entry set sign and value of the next lookup offset
3018c2ecf20Sopenharmony_ci * and the offset value generated to the classifier
3028c2ecf20Sopenharmony_ci */
3038c2ecf20Sopenharmony_cistatic void mvpp2_prs_sram_shift_set(struct mvpp2_prs_entry *pe, int shift,
3048c2ecf20Sopenharmony_ci				     unsigned int op)
3058c2ecf20Sopenharmony_ci{
3068c2ecf20Sopenharmony_ci	/* Set sign */
3078c2ecf20Sopenharmony_ci	if (shift < 0) {
3088c2ecf20Sopenharmony_ci		mvpp2_prs_sram_bits_set(pe, MVPP2_PRS_SRAM_SHIFT_SIGN_BIT, 1);
3098c2ecf20Sopenharmony_ci		shift = 0 - shift;
3108c2ecf20Sopenharmony_ci	} else {
3118c2ecf20Sopenharmony_ci		mvpp2_prs_sram_bits_clear(pe, MVPP2_PRS_SRAM_SHIFT_SIGN_BIT, 1);
3128c2ecf20Sopenharmony_ci	}
3138c2ecf20Sopenharmony_ci
3148c2ecf20Sopenharmony_ci	/* Set value */
3158c2ecf20Sopenharmony_ci	pe->sram[MVPP2_BIT_TO_WORD(MVPP2_PRS_SRAM_SHIFT_OFFS)] |=
3168c2ecf20Sopenharmony_ci		shift & MVPP2_PRS_SRAM_SHIFT_MASK;
3178c2ecf20Sopenharmony_ci
3188c2ecf20Sopenharmony_ci	/* Reset and set operation */
3198c2ecf20Sopenharmony_ci	mvpp2_prs_sram_bits_clear(pe, MVPP2_PRS_SRAM_OP_SEL_SHIFT_OFFS,
3208c2ecf20Sopenharmony_ci				  MVPP2_PRS_SRAM_OP_SEL_SHIFT_MASK);
3218c2ecf20Sopenharmony_ci	mvpp2_prs_sram_bits_set(pe, MVPP2_PRS_SRAM_OP_SEL_SHIFT_OFFS, op);
3228c2ecf20Sopenharmony_ci
3238c2ecf20Sopenharmony_ci	/* Set base offset as current */
3248c2ecf20Sopenharmony_ci	mvpp2_prs_sram_bits_clear(pe, MVPP2_PRS_SRAM_OP_SEL_BASE_OFFS, 1);
3258c2ecf20Sopenharmony_ci}
3268c2ecf20Sopenharmony_ci
3278c2ecf20Sopenharmony_ci/* In the sram sw entry set sign and value of the user defined offset
3288c2ecf20Sopenharmony_ci * generated to the classifier
3298c2ecf20Sopenharmony_ci */
3308c2ecf20Sopenharmony_cistatic void mvpp2_prs_sram_offset_set(struct mvpp2_prs_entry *pe,
3318c2ecf20Sopenharmony_ci				      unsigned int type, int offset,
3328c2ecf20Sopenharmony_ci				      unsigned int op)
3338c2ecf20Sopenharmony_ci{
3348c2ecf20Sopenharmony_ci	/* Set sign */
3358c2ecf20Sopenharmony_ci	if (offset < 0) {
3368c2ecf20Sopenharmony_ci		mvpp2_prs_sram_bits_set(pe, MVPP2_PRS_SRAM_UDF_SIGN_BIT, 1);
3378c2ecf20Sopenharmony_ci		offset = 0 - offset;
3388c2ecf20Sopenharmony_ci	} else {
3398c2ecf20Sopenharmony_ci		mvpp2_prs_sram_bits_clear(pe, MVPP2_PRS_SRAM_UDF_SIGN_BIT, 1);
3408c2ecf20Sopenharmony_ci	}
3418c2ecf20Sopenharmony_ci
3428c2ecf20Sopenharmony_ci	/* Set value */
3438c2ecf20Sopenharmony_ci	mvpp2_prs_sram_bits_clear(pe, MVPP2_PRS_SRAM_UDF_OFFS,
3448c2ecf20Sopenharmony_ci				  MVPP2_PRS_SRAM_UDF_MASK);
3458c2ecf20Sopenharmony_ci	mvpp2_prs_sram_bits_set(pe, MVPP2_PRS_SRAM_UDF_OFFS,
3468c2ecf20Sopenharmony_ci				offset & MVPP2_PRS_SRAM_UDF_MASK);
3478c2ecf20Sopenharmony_ci
3488c2ecf20Sopenharmony_ci	/* Set offset type */
3498c2ecf20Sopenharmony_ci	mvpp2_prs_sram_bits_clear(pe, MVPP2_PRS_SRAM_UDF_TYPE_OFFS,
3508c2ecf20Sopenharmony_ci				  MVPP2_PRS_SRAM_UDF_TYPE_MASK);
3518c2ecf20Sopenharmony_ci	mvpp2_prs_sram_bits_set(pe, MVPP2_PRS_SRAM_UDF_TYPE_OFFS, type);
3528c2ecf20Sopenharmony_ci
3538c2ecf20Sopenharmony_ci	/* Set offset operation */
3548c2ecf20Sopenharmony_ci	mvpp2_prs_sram_bits_clear(pe, MVPP2_PRS_SRAM_OP_SEL_UDF_OFFS,
3558c2ecf20Sopenharmony_ci				  MVPP2_PRS_SRAM_OP_SEL_UDF_MASK);
3568c2ecf20Sopenharmony_ci	mvpp2_prs_sram_bits_set(pe, MVPP2_PRS_SRAM_OP_SEL_UDF_OFFS,
3578c2ecf20Sopenharmony_ci				op & MVPP2_PRS_SRAM_OP_SEL_UDF_MASK);
3588c2ecf20Sopenharmony_ci
3598c2ecf20Sopenharmony_ci	/* Set base offset as current */
3608c2ecf20Sopenharmony_ci	mvpp2_prs_sram_bits_clear(pe, MVPP2_PRS_SRAM_OP_SEL_BASE_OFFS, 1);
3618c2ecf20Sopenharmony_ci}
3628c2ecf20Sopenharmony_ci
3638c2ecf20Sopenharmony_ci/* Find parser flow entry */
3648c2ecf20Sopenharmony_cistatic int mvpp2_prs_flow_find(struct mvpp2 *priv, int flow)
3658c2ecf20Sopenharmony_ci{
3668c2ecf20Sopenharmony_ci	struct mvpp2_prs_entry pe;
3678c2ecf20Sopenharmony_ci	int tid;
3688c2ecf20Sopenharmony_ci
3698c2ecf20Sopenharmony_ci	/* Go through the all entires with MVPP2_PRS_LU_FLOWS */
3708c2ecf20Sopenharmony_ci	for (tid = MVPP2_PRS_TCAM_SRAM_SIZE - 1; tid >= 0; tid--) {
3718c2ecf20Sopenharmony_ci		u8 bits;
3728c2ecf20Sopenharmony_ci
3738c2ecf20Sopenharmony_ci		if (!priv->prs_shadow[tid].valid ||
3748c2ecf20Sopenharmony_ci		    priv->prs_shadow[tid].lu != MVPP2_PRS_LU_FLOWS)
3758c2ecf20Sopenharmony_ci			continue;
3768c2ecf20Sopenharmony_ci
3778c2ecf20Sopenharmony_ci		mvpp2_prs_init_from_hw(priv, &pe, tid);
3788c2ecf20Sopenharmony_ci		bits = mvpp2_prs_sram_ai_get(&pe);
3798c2ecf20Sopenharmony_ci
3808c2ecf20Sopenharmony_ci		/* Sram store classification lookup ID in AI bits [5:0] */
3818c2ecf20Sopenharmony_ci		if ((bits & MVPP2_PRS_FLOW_ID_MASK) == flow)
3828c2ecf20Sopenharmony_ci			return tid;
3838c2ecf20Sopenharmony_ci	}
3848c2ecf20Sopenharmony_ci
3858c2ecf20Sopenharmony_ci	return -ENOENT;
3868c2ecf20Sopenharmony_ci}
3878c2ecf20Sopenharmony_ci
3888c2ecf20Sopenharmony_ci/* Return first free tcam index, seeking from start to end */
3898c2ecf20Sopenharmony_cistatic int mvpp2_prs_tcam_first_free(struct mvpp2 *priv, unsigned char start,
3908c2ecf20Sopenharmony_ci				     unsigned char end)
3918c2ecf20Sopenharmony_ci{
3928c2ecf20Sopenharmony_ci	int tid;
3938c2ecf20Sopenharmony_ci
3948c2ecf20Sopenharmony_ci	if (start > end)
3958c2ecf20Sopenharmony_ci		swap(start, end);
3968c2ecf20Sopenharmony_ci
3978c2ecf20Sopenharmony_ci	if (end >= MVPP2_PRS_TCAM_SRAM_SIZE)
3988c2ecf20Sopenharmony_ci		end = MVPP2_PRS_TCAM_SRAM_SIZE - 1;
3998c2ecf20Sopenharmony_ci
4008c2ecf20Sopenharmony_ci	for (tid = start; tid <= end; tid++) {
4018c2ecf20Sopenharmony_ci		if (!priv->prs_shadow[tid].valid)
4028c2ecf20Sopenharmony_ci			return tid;
4038c2ecf20Sopenharmony_ci	}
4048c2ecf20Sopenharmony_ci
4058c2ecf20Sopenharmony_ci	return -EINVAL;
4068c2ecf20Sopenharmony_ci}
4078c2ecf20Sopenharmony_ci
4088c2ecf20Sopenharmony_ci/* Drop flow control pause frames */
4098c2ecf20Sopenharmony_cistatic void mvpp2_prs_drop_fc(struct mvpp2 *priv)
4108c2ecf20Sopenharmony_ci{
4118c2ecf20Sopenharmony_ci	unsigned char da[ETH_ALEN] = { 0x01, 0x80, 0xC2, 0x00, 0x00, 0x01 };
4128c2ecf20Sopenharmony_ci	struct mvpp2_prs_entry pe;
4138c2ecf20Sopenharmony_ci	unsigned int len;
4148c2ecf20Sopenharmony_ci
4158c2ecf20Sopenharmony_ci	memset(&pe, 0, sizeof(pe));
4168c2ecf20Sopenharmony_ci
4178c2ecf20Sopenharmony_ci	/* For all ports - drop flow control frames */
4188c2ecf20Sopenharmony_ci	pe.index = MVPP2_PE_FC_DROP;
4198c2ecf20Sopenharmony_ci	mvpp2_prs_tcam_lu_set(&pe, MVPP2_PRS_LU_MAC);
4208c2ecf20Sopenharmony_ci
4218c2ecf20Sopenharmony_ci	/* Set match on DA */
4228c2ecf20Sopenharmony_ci	len = ETH_ALEN;
4238c2ecf20Sopenharmony_ci	while (len--)
4248c2ecf20Sopenharmony_ci		mvpp2_prs_tcam_data_byte_set(&pe, len, da[len], 0xff);
4258c2ecf20Sopenharmony_ci
4268c2ecf20Sopenharmony_ci	mvpp2_prs_sram_ri_update(&pe, MVPP2_PRS_RI_DROP_MASK,
4278c2ecf20Sopenharmony_ci				 MVPP2_PRS_RI_DROP_MASK);
4288c2ecf20Sopenharmony_ci
4298c2ecf20Sopenharmony_ci	mvpp2_prs_sram_bits_set(&pe, MVPP2_PRS_SRAM_LU_GEN_BIT, 1);
4308c2ecf20Sopenharmony_ci	mvpp2_prs_sram_next_lu_set(&pe, MVPP2_PRS_LU_FLOWS);
4318c2ecf20Sopenharmony_ci
4328c2ecf20Sopenharmony_ci	/* Mask all ports */
4338c2ecf20Sopenharmony_ci	mvpp2_prs_tcam_port_map_set(&pe, MVPP2_PRS_PORT_MASK);
4348c2ecf20Sopenharmony_ci
4358c2ecf20Sopenharmony_ci	/* Update shadow table and hw entry */
4368c2ecf20Sopenharmony_ci	mvpp2_prs_shadow_set(priv, pe.index, MVPP2_PRS_LU_MAC);
4378c2ecf20Sopenharmony_ci	mvpp2_prs_hw_write(priv, &pe);
4388c2ecf20Sopenharmony_ci}
4398c2ecf20Sopenharmony_ci
4408c2ecf20Sopenharmony_ci/* Enable/disable dropping all mac da's */
4418c2ecf20Sopenharmony_cistatic void mvpp2_prs_mac_drop_all_set(struct mvpp2 *priv, int port, bool add)
4428c2ecf20Sopenharmony_ci{
4438c2ecf20Sopenharmony_ci	struct mvpp2_prs_entry pe;
4448c2ecf20Sopenharmony_ci
4458c2ecf20Sopenharmony_ci	if (priv->prs_shadow[MVPP2_PE_DROP_ALL].valid) {
4468c2ecf20Sopenharmony_ci		/* Entry exist - update port only */
4478c2ecf20Sopenharmony_ci		mvpp2_prs_init_from_hw(priv, &pe, MVPP2_PE_DROP_ALL);
4488c2ecf20Sopenharmony_ci	} else {
4498c2ecf20Sopenharmony_ci		/* Entry doesn't exist - create new */
4508c2ecf20Sopenharmony_ci		memset(&pe, 0, sizeof(pe));
4518c2ecf20Sopenharmony_ci		mvpp2_prs_tcam_lu_set(&pe, MVPP2_PRS_LU_MAC);
4528c2ecf20Sopenharmony_ci		pe.index = MVPP2_PE_DROP_ALL;
4538c2ecf20Sopenharmony_ci
4548c2ecf20Sopenharmony_ci		/* Non-promiscuous mode for all ports - DROP unknown packets */
4558c2ecf20Sopenharmony_ci		mvpp2_prs_sram_ri_update(&pe, MVPP2_PRS_RI_DROP_MASK,
4568c2ecf20Sopenharmony_ci					 MVPP2_PRS_RI_DROP_MASK);
4578c2ecf20Sopenharmony_ci
4588c2ecf20Sopenharmony_ci		mvpp2_prs_sram_bits_set(&pe, MVPP2_PRS_SRAM_LU_GEN_BIT, 1);
4598c2ecf20Sopenharmony_ci		mvpp2_prs_sram_next_lu_set(&pe, MVPP2_PRS_LU_FLOWS);
4608c2ecf20Sopenharmony_ci
4618c2ecf20Sopenharmony_ci		/* Update shadow table */
4628c2ecf20Sopenharmony_ci		mvpp2_prs_shadow_set(priv, pe.index, MVPP2_PRS_LU_MAC);
4638c2ecf20Sopenharmony_ci
4648c2ecf20Sopenharmony_ci		/* Mask all ports */
4658c2ecf20Sopenharmony_ci		mvpp2_prs_tcam_port_map_set(&pe, 0);
4668c2ecf20Sopenharmony_ci	}
4678c2ecf20Sopenharmony_ci
4688c2ecf20Sopenharmony_ci	/* Update port mask */
4698c2ecf20Sopenharmony_ci	mvpp2_prs_tcam_port_set(&pe, port, add);
4708c2ecf20Sopenharmony_ci
4718c2ecf20Sopenharmony_ci	mvpp2_prs_hw_write(priv, &pe);
4728c2ecf20Sopenharmony_ci}
4738c2ecf20Sopenharmony_ci
4748c2ecf20Sopenharmony_ci/* Set port to unicast or multicast promiscuous mode */
4758c2ecf20Sopenharmony_civoid mvpp2_prs_mac_promisc_set(struct mvpp2 *priv, int port,
4768c2ecf20Sopenharmony_ci			       enum mvpp2_prs_l2_cast l2_cast, bool add)
4778c2ecf20Sopenharmony_ci{
4788c2ecf20Sopenharmony_ci	struct mvpp2_prs_entry pe;
4798c2ecf20Sopenharmony_ci	unsigned char cast_match;
4808c2ecf20Sopenharmony_ci	unsigned int ri;
4818c2ecf20Sopenharmony_ci	int tid;
4828c2ecf20Sopenharmony_ci
4838c2ecf20Sopenharmony_ci	if (l2_cast == MVPP2_PRS_L2_UNI_CAST) {
4848c2ecf20Sopenharmony_ci		cast_match = MVPP2_PRS_UCAST_VAL;
4858c2ecf20Sopenharmony_ci		tid = MVPP2_PE_MAC_UC_PROMISCUOUS;
4868c2ecf20Sopenharmony_ci		ri = MVPP2_PRS_RI_L2_UCAST;
4878c2ecf20Sopenharmony_ci	} else {
4888c2ecf20Sopenharmony_ci		cast_match = MVPP2_PRS_MCAST_VAL;
4898c2ecf20Sopenharmony_ci		tid = MVPP2_PE_MAC_MC_PROMISCUOUS;
4908c2ecf20Sopenharmony_ci		ri = MVPP2_PRS_RI_L2_MCAST;
4918c2ecf20Sopenharmony_ci	}
4928c2ecf20Sopenharmony_ci
4938c2ecf20Sopenharmony_ci	/* promiscuous mode - Accept unknown unicast or multicast packets */
4948c2ecf20Sopenharmony_ci	if (priv->prs_shadow[tid].valid) {
4958c2ecf20Sopenharmony_ci		mvpp2_prs_init_from_hw(priv, &pe, tid);
4968c2ecf20Sopenharmony_ci	} else {
4978c2ecf20Sopenharmony_ci		memset(&pe, 0, sizeof(pe));
4988c2ecf20Sopenharmony_ci		mvpp2_prs_tcam_lu_set(&pe, MVPP2_PRS_LU_MAC);
4998c2ecf20Sopenharmony_ci		pe.index = tid;
5008c2ecf20Sopenharmony_ci
5018c2ecf20Sopenharmony_ci		/* Continue - set next lookup */
5028c2ecf20Sopenharmony_ci		mvpp2_prs_sram_next_lu_set(&pe, MVPP2_PRS_LU_DSA);
5038c2ecf20Sopenharmony_ci
5048c2ecf20Sopenharmony_ci		/* Set result info bits */
5058c2ecf20Sopenharmony_ci		mvpp2_prs_sram_ri_update(&pe, ri, MVPP2_PRS_RI_L2_CAST_MASK);
5068c2ecf20Sopenharmony_ci
5078c2ecf20Sopenharmony_ci		/* Match UC or MC addresses */
5088c2ecf20Sopenharmony_ci		mvpp2_prs_tcam_data_byte_set(&pe, 0, cast_match,
5098c2ecf20Sopenharmony_ci					     MVPP2_PRS_CAST_MASK);
5108c2ecf20Sopenharmony_ci
5118c2ecf20Sopenharmony_ci		/* Shift to ethertype */
5128c2ecf20Sopenharmony_ci		mvpp2_prs_sram_shift_set(&pe, 2 * ETH_ALEN,
5138c2ecf20Sopenharmony_ci					 MVPP2_PRS_SRAM_OP_SEL_SHIFT_ADD);
5148c2ecf20Sopenharmony_ci
5158c2ecf20Sopenharmony_ci		/* Mask all ports */
5168c2ecf20Sopenharmony_ci		mvpp2_prs_tcam_port_map_set(&pe, 0);
5178c2ecf20Sopenharmony_ci
5188c2ecf20Sopenharmony_ci		/* Update shadow table */
5198c2ecf20Sopenharmony_ci		mvpp2_prs_shadow_set(priv, pe.index, MVPP2_PRS_LU_MAC);
5208c2ecf20Sopenharmony_ci	}
5218c2ecf20Sopenharmony_ci
5228c2ecf20Sopenharmony_ci	/* Update port mask */
5238c2ecf20Sopenharmony_ci	mvpp2_prs_tcam_port_set(&pe, port, add);
5248c2ecf20Sopenharmony_ci
5258c2ecf20Sopenharmony_ci	mvpp2_prs_hw_write(priv, &pe);
5268c2ecf20Sopenharmony_ci}
5278c2ecf20Sopenharmony_ci
5288c2ecf20Sopenharmony_ci/* Set entry for dsa packets */
5298c2ecf20Sopenharmony_cistatic void mvpp2_prs_dsa_tag_set(struct mvpp2 *priv, int port, bool add,
5308c2ecf20Sopenharmony_ci				  bool tagged, bool extend)
5318c2ecf20Sopenharmony_ci{
5328c2ecf20Sopenharmony_ci	struct mvpp2_prs_entry pe;
5338c2ecf20Sopenharmony_ci	int tid, shift;
5348c2ecf20Sopenharmony_ci
5358c2ecf20Sopenharmony_ci	if (extend) {
5368c2ecf20Sopenharmony_ci		tid = tagged ? MVPP2_PE_EDSA_TAGGED : MVPP2_PE_EDSA_UNTAGGED;
5378c2ecf20Sopenharmony_ci		shift = 8;
5388c2ecf20Sopenharmony_ci	} else {
5398c2ecf20Sopenharmony_ci		tid = tagged ? MVPP2_PE_DSA_TAGGED : MVPP2_PE_DSA_UNTAGGED;
5408c2ecf20Sopenharmony_ci		shift = 4;
5418c2ecf20Sopenharmony_ci	}
5428c2ecf20Sopenharmony_ci
5438c2ecf20Sopenharmony_ci	if (priv->prs_shadow[tid].valid) {
5448c2ecf20Sopenharmony_ci		/* Entry exist - update port only */
5458c2ecf20Sopenharmony_ci		mvpp2_prs_init_from_hw(priv, &pe, tid);
5468c2ecf20Sopenharmony_ci	} else {
5478c2ecf20Sopenharmony_ci		/* Entry doesn't exist - create new */
5488c2ecf20Sopenharmony_ci		memset(&pe, 0, sizeof(pe));
5498c2ecf20Sopenharmony_ci		mvpp2_prs_tcam_lu_set(&pe, MVPP2_PRS_LU_DSA);
5508c2ecf20Sopenharmony_ci		pe.index = tid;
5518c2ecf20Sopenharmony_ci
5528c2ecf20Sopenharmony_ci		/* Update shadow table */
5538c2ecf20Sopenharmony_ci		mvpp2_prs_shadow_set(priv, pe.index, MVPP2_PRS_LU_DSA);
5548c2ecf20Sopenharmony_ci
5558c2ecf20Sopenharmony_ci		if (tagged) {
5568c2ecf20Sopenharmony_ci			/* Set tagged bit in DSA tag */
5578c2ecf20Sopenharmony_ci			mvpp2_prs_tcam_data_byte_set(&pe, 0,
5588c2ecf20Sopenharmony_ci					     MVPP2_PRS_TCAM_DSA_TAGGED_BIT,
5598c2ecf20Sopenharmony_ci					     MVPP2_PRS_TCAM_DSA_TAGGED_BIT);
5608c2ecf20Sopenharmony_ci
5618c2ecf20Sopenharmony_ci			/* Set ai bits for next iteration */
5628c2ecf20Sopenharmony_ci			if (extend)
5638c2ecf20Sopenharmony_ci				mvpp2_prs_sram_ai_update(&pe, 1,
5648c2ecf20Sopenharmony_ci							MVPP2_PRS_SRAM_AI_MASK);
5658c2ecf20Sopenharmony_ci			else
5668c2ecf20Sopenharmony_ci				mvpp2_prs_sram_ai_update(&pe, 0,
5678c2ecf20Sopenharmony_ci							MVPP2_PRS_SRAM_AI_MASK);
5688c2ecf20Sopenharmony_ci
5698c2ecf20Sopenharmony_ci			/* Set result info bits to 'single vlan' */
5708c2ecf20Sopenharmony_ci			mvpp2_prs_sram_ri_update(&pe, MVPP2_PRS_RI_VLAN_SINGLE,
5718c2ecf20Sopenharmony_ci						 MVPP2_PRS_RI_VLAN_MASK);
5728c2ecf20Sopenharmony_ci			/* If packet is tagged continue check vid filtering */
5738c2ecf20Sopenharmony_ci			mvpp2_prs_sram_next_lu_set(&pe, MVPP2_PRS_LU_VID);
5748c2ecf20Sopenharmony_ci		} else {
5758c2ecf20Sopenharmony_ci			/* Shift 4 bytes for DSA tag or 8 bytes for EDSA tag*/
5768c2ecf20Sopenharmony_ci			mvpp2_prs_sram_shift_set(&pe, shift,
5778c2ecf20Sopenharmony_ci					MVPP2_PRS_SRAM_OP_SEL_SHIFT_ADD);
5788c2ecf20Sopenharmony_ci
5798c2ecf20Sopenharmony_ci			/* Set result info bits to 'no vlans' */
5808c2ecf20Sopenharmony_ci			mvpp2_prs_sram_ri_update(&pe, MVPP2_PRS_RI_VLAN_NONE,
5818c2ecf20Sopenharmony_ci						 MVPP2_PRS_RI_VLAN_MASK);
5828c2ecf20Sopenharmony_ci			mvpp2_prs_sram_next_lu_set(&pe, MVPP2_PRS_LU_L2);
5838c2ecf20Sopenharmony_ci		}
5848c2ecf20Sopenharmony_ci
5858c2ecf20Sopenharmony_ci		/* Mask all ports */
5868c2ecf20Sopenharmony_ci		mvpp2_prs_tcam_port_map_set(&pe, 0);
5878c2ecf20Sopenharmony_ci	}
5888c2ecf20Sopenharmony_ci
5898c2ecf20Sopenharmony_ci	/* Update port mask */
5908c2ecf20Sopenharmony_ci	mvpp2_prs_tcam_port_set(&pe, port, add);
5918c2ecf20Sopenharmony_ci
5928c2ecf20Sopenharmony_ci	mvpp2_prs_hw_write(priv, &pe);
5938c2ecf20Sopenharmony_ci}
5948c2ecf20Sopenharmony_ci
5958c2ecf20Sopenharmony_ci/* Set entry for dsa ethertype */
5968c2ecf20Sopenharmony_cistatic void mvpp2_prs_dsa_tag_ethertype_set(struct mvpp2 *priv, int port,
5978c2ecf20Sopenharmony_ci					    bool add, bool tagged, bool extend)
5988c2ecf20Sopenharmony_ci{
5998c2ecf20Sopenharmony_ci	struct mvpp2_prs_entry pe;
6008c2ecf20Sopenharmony_ci	int tid, shift, port_mask;
6018c2ecf20Sopenharmony_ci
6028c2ecf20Sopenharmony_ci	if (extend) {
6038c2ecf20Sopenharmony_ci		tid = tagged ? MVPP2_PE_ETYPE_EDSA_TAGGED :
6048c2ecf20Sopenharmony_ci		      MVPP2_PE_ETYPE_EDSA_UNTAGGED;
6058c2ecf20Sopenharmony_ci		port_mask = 0;
6068c2ecf20Sopenharmony_ci		shift = 8;
6078c2ecf20Sopenharmony_ci	} else {
6088c2ecf20Sopenharmony_ci		tid = tagged ? MVPP2_PE_ETYPE_DSA_TAGGED :
6098c2ecf20Sopenharmony_ci		      MVPP2_PE_ETYPE_DSA_UNTAGGED;
6108c2ecf20Sopenharmony_ci		port_mask = MVPP2_PRS_PORT_MASK;
6118c2ecf20Sopenharmony_ci		shift = 4;
6128c2ecf20Sopenharmony_ci	}
6138c2ecf20Sopenharmony_ci
6148c2ecf20Sopenharmony_ci	if (priv->prs_shadow[tid].valid) {
6158c2ecf20Sopenharmony_ci		/* Entry exist - update port only */
6168c2ecf20Sopenharmony_ci		mvpp2_prs_init_from_hw(priv, &pe, tid);
6178c2ecf20Sopenharmony_ci	} else {
6188c2ecf20Sopenharmony_ci		/* Entry doesn't exist - create new */
6198c2ecf20Sopenharmony_ci		memset(&pe, 0, sizeof(pe));
6208c2ecf20Sopenharmony_ci		mvpp2_prs_tcam_lu_set(&pe, MVPP2_PRS_LU_DSA);
6218c2ecf20Sopenharmony_ci		pe.index = tid;
6228c2ecf20Sopenharmony_ci
6238c2ecf20Sopenharmony_ci		/* Set ethertype */
6248c2ecf20Sopenharmony_ci		mvpp2_prs_match_etype(&pe, 0, ETH_P_EDSA);
6258c2ecf20Sopenharmony_ci		mvpp2_prs_match_etype(&pe, 2, 0);
6268c2ecf20Sopenharmony_ci
6278c2ecf20Sopenharmony_ci		mvpp2_prs_sram_ri_update(&pe, MVPP2_PRS_RI_DSA_MASK,
6288c2ecf20Sopenharmony_ci					 MVPP2_PRS_RI_DSA_MASK);
6298c2ecf20Sopenharmony_ci		/* Shift ethertype + 2 byte reserved + tag*/
6308c2ecf20Sopenharmony_ci		mvpp2_prs_sram_shift_set(&pe, 2 + MVPP2_ETH_TYPE_LEN + shift,
6318c2ecf20Sopenharmony_ci					 MVPP2_PRS_SRAM_OP_SEL_SHIFT_ADD);
6328c2ecf20Sopenharmony_ci
6338c2ecf20Sopenharmony_ci		/* Update shadow table */
6348c2ecf20Sopenharmony_ci		mvpp2_prs_shadow_set(priv, pe.index, MVPP2_PRS_LU_DSA);
6358c2ecf20Sopenharmony_ci
6368c2ecf20Sopenharmony_ci		if (tagged) {
6378c2ecf20Sopenharmony_ci			/* Set tagged bit in DSA tag */
6388c2ecf20Sopenharmony_ci			mvpp2_prs_tcam_data_byte_set(&pe,
6398c2ecf20Sopenharmony_ci						     MVPP2_ETH_TYPE_LEN + 2 + 3,
6408c2ecf20Sopenharmony_ci						 MVPP2_PRS_TCAM_DSA_TAGGED_BIT,
6418c2ecf20Sopenharmony_ci						 MVPP2_PRS_TCAM_DSA_TAGGED_BIT);
6428c2ecf20Sopenharmony_ci			/* Clear all ai bits for next iteration */
6438c2ecf20Sopenharmony_ci			mvpp2_prs_sram_ai_update(&pe, 0,
6448c2ecf20Sopenharmony_ci						 MVPP2_PRS_SRAM_AI_MASK);
6458c2ecf20Sopenharmony_ci			/* If packet is tagged continue check vlans */
6468c2ecf20Sopenharmony_ci			mvpp2_prs_sram_next_lu_set(&pe, MVPP2_PRS_LU_VLAN);
6478c2ecf20Sopenharmony_ci		} else {
6488c2ecf20Sopenharmony_ci			/* Set result info bits to 'no vlans' */
6498c2ecf20Sopenharmony_ci			mvpp2_prs_sram_ri_update(&pe, MVPP2_PRS_RI_VLAN_NONE,
6508c2ecf20Sopenharmony_ci						 MVPP2_PRS_RI_VLAN_MASK);
6518c2ecf20Sopenharmony_ci			mvpp2_prs_sram_next_lu_set(&pe, MVPP2_PRS_LU_L2);
6528c2ecf20Sopenharmony_ci		}
6538c2ecf20Sopenharmony_ci		/* Mask/unmask all ports, depending on dsa type */
6548c2ecf20Sopenharmony_ci		mvpp2_prs_tcam_port_map_set(&pe, port_mask);
6558c2ecf20Sopenharmony_ci	}
6568c2ecf20Sopenharmony_ci
6578c2ecf20Sopenharmony_ci	/* Update port mask */
6588c2ecf20Sopenharmony_ci	mvpp2_prs_tcam_port_set(&pe, port, add);
6598c2ecf20Sopenharmony_ci
6608c2ecf20Sopenharmony_ci	mvpp2_prs_hw_write(priv, &pe);
6618c2ecf20Sopenharmony_ci}
6628c2ecf20Sopenharmony_ci
6638c2ecf20Sopenharmony_ci/* Search for existing single/triple vlan entry */
6648c2ecf20Sopenharmony_cistatic int mvpp2_prs_vlan_find(struct mvpp2 *priv, unsigned short tpid, int ai)
6658c2ecf20Sopenharmony_ci{
6668c2ecf20Sopenharmony_ci	struct mvpp2_prs_entry pe;
6678c2ecf20Sopenharmony_ci	int tid;
6688c2ecf20Sopenharmony_ci
6698c2ecf20Sopenharmony_ci	/* Go through the all entries with MVPP2_PRS_LU_VLAN */
6708c2ecf20Sopenharmony_ci	for (tid = MVPP2_PE_FIRST_FREE_TID;
6718c2ecf20Sopenharmony_ci	     tid <= MVPP2_PE_LAST_FREE_TID; tid++) {
6728c2ecf20Sopenharmony_ci		unsigned int ri_bits, ai_bits;
6738c2ecf20Sopenharmony_ci		bool match;
6748c2ecf20Sopenharmony_ci
6758c2ecf20Sopenharmony_ci		if (!priv->prs_shadow[tid].valid ||
6768c2ecf20Sopenharmony_ci		    priv->prs_shadow[tid].lu != MVPP2_PRS_LU_VLAN)
6778c2ecf20Sopenharmony_ci			continue;
6788c2ecf20Sopenharmony_ci
6798c2ecf20Sopenharmony_ci		mvpp2_prs_init_from_hw(priv, &pe, tid);
6808c2ecf20Sopenharmony_ci		match = mvpp2_prs_tcam_data_cmp(&pe, 0, tpid);
6818c2ecf20Sopenharmony_ci		if (!match)
6828c2ecf20Sopenharmony_ci			continue;
6838c2ecf20Sopenharmony_ci
6848c2ecf20Sopenharmony_ci		/* Get vlan type */
6858c2ecf20Sopenharmony_ci		ri_bits = mvpp2_prs_sram_ri_get(&pe);
6868c2ecf20Sopenharmony_ci		ri_bits &= MVPP2_PRS_RI_VLAN_MASK;
6878c2ecf20Sopenharmony_ci
6888c2ecf20Sopenharmony_ci		/* Get current ai value from tcam */
6898c2ecf20Sopenharmony_ci		ai_bits = mvpp2_prs_tcam_ai_get(&pe);
6908c2ecf20Sopenharmony_ci		/* Clear double vlan bit */
6918c2ecf20Sopenharmony_ci		ai_bits &= ~MVPP2_PRS_DBL_VLAN_AI_BIT;
6928c2ecf20Sopenharmony_ci
6938c2ecf20Sopenharmony_ci		if (ai != ai_bits)
6948c2ecf20Sopenharmony_ci			continue;
6958c2ecf20Sopenharmony_ci
6968c2ecf20Sopenharmony_ci		if (ri_bits == MVPP2_PRS_RI_VLAN_SINGLE ||
6978c2ecf20Sopenharmony_ci		    ri_bits == MVPP2_PRS_RI_VLAN_TRIPLE)
6988c2ecf20Sopenharmony_ci			return tid;
6998c2ecf20Sopenharmony_ci	}
7008c2ecf20Sopenharmony_ci
7018c2ecf20Sopenharmony_ci	return -ENOENT;
7028c2ecf20Sopenharmony_ci}
7038c2ecf20Sopenharmony_ci
7048c2ecf20Sopenharmony_ci/* Add/update single/triple vlan entry */
7058c2ecf20Sopenharmony_cistatic int mvpp2_prs_vlan_add(struct mvpp2 *priv, unsigned short tpid, int ai,
7068c2ecf20Sopenharmony_ci			      unsigned int port_map)
7078c2ecf20Sopenharmony_ci{
7088c2ecf20Sopenharmony_ci	struct mvpp2_prs_entry pe;
7098c2ecf20Sopenharmony_ci	int tid_aux, tid;
7108c2ecf20Sopenharmony_ci	int ret = 0;
7118c2ecf20Sopenharmony_ci
7128c2ecf20Sopenharmony_ci	memset(&pe, 0, sizeof(pe));
7138c2ecf20Sopenharmony_ci
7148c2ecf20Sopenharmony_ci	tid = mvpp2_prs_vlan_find(priv, tpid, ai);
7158c2ecf20Sopenharmony_ci
7168c2ecf20Sopenharmony_ci	if (tid < 0) {
7178c2ecf20Sopenharmony_ci		/* Create new tcam entry */
7188c2ecf20Sopenharmony_ci		tid = mvpp2_prs_tcam_first_free(priv, MVPP2_PE_LAST_FREE_TID,
7198c2ecf20Sopenharmony_ci						MVPP2_PE_FIRST_FREE_TID);
7208c2ecf20Sopenharmony_ci		if (tid < 0)
7218c2ecf20Sopenharmony_ci			return tid;
7228c2ecf20Sopenharmony_ci
7238c2ecf20Sopenharmony_ci		/* Get last double vlan tid */
7248c2ecf20Sopenharmony_ci		for (tid_aux = MVPP2_PE_LAST_FREE_TID;
7258c2ecf20Sopenharmony_ci		     tid_aux >= MVPP2_PE_FIRST_FREE_TID; tid_aux--) {
7268c2ecf20Sopenharmony_ci			unsigned int ri_bits;
7278c2ecf20Sopenharmony_ci
7288c2ecf20Sopenharmony_ci			if (!priv->prs_shadow[tid_aux].valid ||
7298c2ecf20Sopenharmony_ci			    priv->prs_shadow[tid_aux].lu != MVPP2_PRS_LU_VLAN)
7308c2ecf20Sopenharmony_ci				continue;
7318c2ecf20Sopenharmony_ci
7328c2ecf20Sopenharmony_ci			mvpp2_prs_init_from_hw(priv, &pe, tid_aux);
7338c2ecf20Sopenharmony_ci			ri_bits = mvpp2_prs_sram_ri_get(&pe);
7348c2ecf20Sopenharmony_ci			if ((ri_bits & MVPP2_PRS_RI_VLAN_MASK) ==
7358c2ecf20Sopenharmony_ci			    MVPP2_PRS_RI_VLAN_DOUBLE)
7368c2ecf20Sopenharmony_ci				break;
7378c2ecf20Sopenharmony_ci		}
7388c2ecf20Sopenharmony_ci
7398c2ecf20Sopenharmony_ci		if (tid <= tid_aux)
7408c2ecf20Sopenharmony_ci			return -EINVAL;
7418c2ecf20Sopenharmony_ci
7428c2ecf20Sopenharmony_ci		memset(&pe, 0, sizeof(pe));
7438c2ecf20Sopenharmony_ci		pe.index = tid;
7448c2ecf20Sopenharmony_ci		mvpp2_prs_tcam_lu_set(&pe, MVPP2_PRS_LU_VLAN);
7458c2ecf20Sopenharmony_ci
7468c2ecf20Sopenharmony_ci		mvpp2_prs_match_etype(&pe, 0, tpid);
7478c2ecf20Sopenharmony_ci
7488c2ecf20Sopenharmony_ci		/* VLAN tag detected, proceed with VID filtering */
7498c2ecf20Sopenharmony_ci		mvpp2_prs_sram_next_lu_set(&pe, MVPP2_PRS_LU_VID);
7508c2ecf20Sopenharmony_ci
7518c2ecf20Sopenharmony_ci		/* Clear all ai bits for next iteration */
7528c2ecf20Sopenharmony_ci		mvpp2_prs_sram_ai_update(&pe, 0, MVPP2_PRS_SRAM_AI_MASK);
7538c2ecf20Sopenharmony_ci
7548c2ecf20Sopenharmony_ci		if (ai == MVPP2_PRS_SINGLE_VLAN_AI) {
7558c2ecf20Sopenharmony_ci			mvpp2_prs_sram_ri_update(&pe, MVPP2_PRS_RI_VLAN_SINGLE,
7568c2ecf20Sopenharmony_ci						 MVPP2_PRS_RI_VLAN_MASK);
7578c2ecf20Sopenharmony_ci		} else {
7588c2ecf20Sopenharmony_ci			ai |= MVPP2_PRS_DBL_VLAN_AI_BIT;
7598c2ecf20Sopenharmony_ci			mvpp2_prs_sram_ri_update(&pe, MVPP2_PRS_RI_VLAN_TRIPLE,
7608c2ecf20Sopenharmony_ci						 MVPP2_PRS_RI_VLAN_MASK);
7618c2ecf20Sopenharmony_ci		}
7628c2ecf20Sopenharmony_ci		mvpp2_prs_tcam_ai_update(&pe, ai, MVPP2_PRS_SRAM_AI_MASK);
7638c2ecf20Sopenharmony_ci
7648c2ecf20Sopenharmony_ci		mvpp2_prs_shadow_set(priv, pe.index, MVPP2_PRS_LU_VLAN);
7658c2ecf20Sopenharmony_ci	} else {
7668c2ecf20Sopenharmony_ci		mvpp2_prs_init_from_hw(priv, &pe, tid);
7678c2ecf20Sopenharmony_ci	}
7688c2ecf20Sopenharmony_ci	/* Update ports' mask */
7698c2ecf20Sopenharmony_ci	mvpp2_prs_tcam_port_map_set(&pe, port_map);
7708c2ecf20Sopenharmony_ci
7718c2ecf20Sopenharmony_ci	mvpp2_prs_hw_write(priv, &pe);
7728c2ecf20Sopenharmony_ci
7738c2ecf20Sopenharmony_ci	return ret;
7748c2ecf20Sopenharmony_ci}
7758c2ecf20Sopenharmony_ci
7768c2ecf20Sopenharmony_ci/* Get first free double vlan ai number */
7778c2ecf20Sopenharmony_cistatic int mvpp2_prs_double_vlan_ai_free_get(struct mvpp2 *priv)
7788c2ecf20Sopenharmony_ci{
7798c2ecf20Sopenharmony_ci	int i;
7808c2ecf20Sopenharmony_ci
7818c2ecf20Sopenharmony_ci	for (i = 1; i < MVPP2_PRS_DBL_VLANS_MAX; i++) {
7828c2ecf20Sopenharmony_ci		if (!priv->prs_double_vlans[i])
7838c2ecf20Sopenharmony_ci			return i;
7848c2ecf20Sopenharmony_ci	}
7858c2ecf20Sopenharmony_ci
7868c2ecf20Sopenharmony_ci	return -EINVAL;
7878c2ecf20Sopenharmony_ci}
7888c2ecf20Sopenharmony_ci
7898c2ecf20Sopenharmony_ci/* Search for existing double vlan entry */
7908c2ecf20Sopenharmony_cistatic int mvpp2_prs_double_vlan_find(struct mvpp2 *priv, unsigned short tpid1,
7918c2ecf20Sopenharmony_ci				      unsigned short tpid2)
7928c2ecf20Sopenharmony_ci{
7938c2ecf20Sopenharmony_ci	struct mvpp2_prs_entry pe;
7948c2ecf20Sopenharmony_ci	int tid;
7958c2ecf20Sopenharmony_ci
7968c2ecf20Sopenharmony_ci	/* Go through the all entries with MVPP2_PRS_LU_VLAN */
7978c2ecf20Sopenharmony_ci	for (tid = MVPP2_PE_FIRST_FREE_TID;
7988c2ecf20Sopenharmony_ci	     tid <= MVPP2_PE_LAST_FREE_TID; tid++) {
7998c2ecf20Sopenharmony_ci		unsigned int ri_mask;
8008c2ecf20Sopenharmony_ci		bool match;
8018c2ecf20Sopenharmony_ci
8028c2ecf20Sopenharmony_ci		if (!priv->prs_shadow[tid].valid ||
8038c2ecf20Sopenharmony_ci		    priv->prs_shadow[tid].lu != MVPP2_PRS_LU_VLAN)
8048c2ecf20Sopenharmony_ci			continue;
8058c2ecf20Sopenharmony_ci
8068c2ecf20Sopenharmony_ci		mvpp2_prs_init_from_hw(priv, &pe, tid);
8078c2ecf20Sopenharmony_ci
8088c2ecf20Sopenharmony_ci		match = mvpp2_prs_tcam_data_cmp(&pe, 0, tpid1) &&
8098c2ecf20Sopenharmony_ci			mvpp2_prs_tcam_data_cmp(&pe, 4, tpid2);
8108c2ecf20Sopenharmony_ci
8118c2ecf20Sopenharmony_ci		if (!match)
8128c2ecf20Sopenharmony_ci			continue;
8138c2ecf20Sopenharmony_ci
8148c2ecf20Sopenharmony_ci		ri_mask = mvpp2_prs_sram_ri_get(&pe) & MVPP2_PRS_RI_VLAN_MASK;
8158c2ecf20Sopenharmony_ci		if (ri_mask == MVPP2_PRS_RI_VLAN_DOUBLE)
8168c2ecf20Sopenharmony_ci			return tid;
8178c2ecf20Sopenharmony_ci	}
8188c2ecf20Sopenharmony_ci
8198c2ecf20Sopenharmony_ci	return -ENOENT;
8208c2ecf20Sopenharmony_ci}
8218c2ecf20Sopenharmony_ci
8228c2ecf20Sopenharmony_ci/* Add or update double vlan entry */
8238c2ecf20Sopenharmony_cistatic int mvpp2_prs_double_vlan_add(struct mvpp2 *priv, unsigned short tpid1,
8248c2ecf20Sopenharmony_ci				     unsigned short tpid2,
8258c2ecf20Sopenharmony_ci				     unsigned int port_map)
8268c2ecf20Sopenharmony_ci{
8278c2ecf20Sopenharmony_ci	int tid_aux, tid, ai, ret = 0;
8288c2ecf20Sopenharmony_ci	struct mvpp2_prs_entry pe;
8298c2ecf20Sopenharmony_ci
8308c2ecf20Sopenharmony_ci	memset(&pe, 0, sizeof(pe));
8318c2ecf20Sopenharmony_ci
8328c2ecf20Sopenharmony_ci	tid = mvpp2_prs_double_vlan_find(priv, tpid1, tpid2);
8338c2ecf20Sopenharmony_ci
8348c2ecf20Sopenharmony_ci	if (tid < 0) {
8358c2ecf20Sopenharmony_ci		/* Create new tcam entry */
8368c2ecf20Sopenharmony_ci		tid = mvpp2_prs_tcam_first_free(priv, MVPP2_PE_FIRST_FREE_TID,
8378c2ecf20Sopenharmony_ci				MVPP2_PE_LAST_FREE_TID);
8388c2ecf20Sopenharmony_ci		if (tid < 0)
8398c2ecf20Sopenharmony_ci			return tid;
8408c2ecf20Sopenharmony_ci
8418c2ecf20Sopenharmony_ci		/* Set ai value for new double vlan entry */
8428c2ecf20Sopenharmony_ci		ai = mvpp2_prs_double_vlan_ai_free_get(priv);
8438c2ecf20Sopenharmony_ci		if (ai < 0)
8448c2ecf20Sopenharmony_ci			return ai;
8458c2ecf20Sopenharmony_ci
8468c2ecf20Sopenharmony_ci		/* Get first single/triple vlan tid */
8478c2ecf20Sopenharmony_ci		for (tid_aux = MVPP2_PE_FIRST_FREE_TID;
8488c2ecf20Sopenharmony_ci		     tid_aux <= MVPP2_PE_LAST_FREE_TID; tid_aux++) {
8498c2ecf20Sopenharmony_ci			unsigned int ri_bits;
8508c2ecf20Sopenharmony_ci
8518c2ecf20Sopenharmony_ci			if (!priv->prs_shadow[tid_aux].valid ||
8528c2ecf20Sopenharmony_ci			    priv->prs_shadow[tid_aux].lu != MVPP2_PRS_LU_VLAN)
8538c2ecf20Sopenharmony_ci				continue;
8548c2ecf20Sopenharmony_ci
8558c2ecf20Sopenharmony_ci			mvpp2_prs_init_from_hw(priv, &pe, tid_aux);
8568c2ecf20Sopenharmony_ci			ri_bits = mvpp2_prs_sram_ri_get(&pe);
8578c2ecf20Sopenharmony_ci			ri_bits &= MVPP2_PRS_RI_VLAN_MASK;
8588c2ecf20Sopenharmony_ci			if (ri_bits == MVPP2_PRS_RI_VLAN_SINGLE ||
8598c2ecf20Sopenharmony_ci			    ri_bits == MVPP2_PRS_RI_VLAN_TRIPLE)
8608c2ecf20Sopenharmony_ci				break;
8618c2ecf20Sopenharmony_ci		}
8628c2ecf20Sopenharmony_ci
8638c2ecf20Sopenharmony_ci		if (tid >= tid_aux)
8648c2ecf20Sopenharmony_ci			return -ERANGE;
8658c2ecf20Sopenharmony_ci
8668c2ecf20Sopenharmony_ci		memset(&pe, 0, sizeof(pe));
8678c2ecf20Sopenharmony_ci		mvpp2_prs_tcam_lu_set(&pe, MVPP2_PRS_LU_VLAN);
8688c2ecf20Sopenharmony_ci		pe.index = tid;
8698c2ecf20Sopenharmony_ci
8708c2ecf20Sopenharmony_ci		priv->prs_double_vlans[ai] = true;
8718c2ecf20Sopenharmony_ci
8728c2ecf20Sopenharmony_ci		mvpp2_prs_match_etype(&pe, 0, tpid1);
8738c2ecf20Sopenharmony_ci		mvpp2_prs_match_etype(&pe, 4, tpid2);
8748c2ecf20Sopenharmony_ci
8758c2ecf20Sopenharmony_ci		mvpp2_prs_sram_next_lu_set(&pe, MVPP2_PRS_LU_VLAN);
8768c2ecf20Sopenharmony_ci		/* Shift 4 bytes - skip outer vlan tag */
8778c2ecf20Sopenharmony_ci		mvpp2_prs_sram_shift_set(&pe, MVPP2_VLAN_TAG_LEN,
8788c2ecf20Sopenharmony_ci					 MVPP2_PRS_SRAM_OP_SEL_SHIFT_ADD);
8798c2ecf20Sopenharmony_ci		mvpp2_prs_sram_ri_update(&pe, MVPP2_PRS_RI_VLAN_DOUBLE,
8808c2ecf20Sopenharmony_ci					 MVPP2_PRS_RI_VLAN_MASK);
8818c2ecf20Sopenharmony_ci		mvpp2_prs_sram_ai_update(&pe, ai | MVPP2_PRS_DBL_VLAN_AI_BIT,
8828c2ecf20Sopenharmony_ci					 MVPP2_PRS_SRAM_AI_MASK);
8838c2ecf20Sopenharmony_ci
8848c2ecf20Sopenharmony_ci		mvpp2_prs_shadow_set(priv, pe.index, MVPP2_PRS_LU_VLAN);
8858c2ecf20Sopenharmony_ci	} else {
8868c2ecf20Sopenharmony_ci		mvpp2_prs_init_from_hw(priv, &pe, tid);
8878c2ecf20Sopenharmony_ci	}
8888c2ecf20Sopenharmony_ci
8898c2ecf20Sopenharmony_ci	/* Update ports' mask */
8908c2ecf20Sopenharmony_ci	mvpp2_prs_tcam_port_map_set(&pe, port_map);
8918c2ecf20Sopenharmony_ci	mvpp2_prs_hw_write(priv, &pe);
8928c2ecf20Sopenharmony_ci
8938c2ecf20Sopenharmony_ci	return ret;
8948c2ecf20Sopenharmony_ci}
8958c2ecf20Sopenharmony_ci
8968c2ecf20Sopenharmony_ci/* IPv4 header parsing for fragmentation and L4 offset */
8978c2ecf20Sopenharmony_cistatic int mvpp2_prs_ip4_proto(struct mvpp2 *priv, unsigned short proto,
8988c2ecf20Sopenharmony_ci			       unsigned int ri, unsigned int ri_mask)
8998c2ecf20Sopenharmony_ci{
9008c2ecf20Sopenharmony_ci	struct mvpp2_prs_entry pe;
9018c2ecf20Sopenharmony_ci	int tid;
9028c2ecf20Sopenharmony_ci
9038c2ecf20Sopenharmony_ci	if ((proto != IPPROTO_TCP) && (proto != IPPROTO_UDP) &&
9048c2ecf20Sopenharmony_ci	    (proto != IPPROTO_IGMP))
9058c2ecf20Sopenharmony_ci		return -EINVAL;
9068c2ecf20Sopenharmony_ci
9078c2ecf20Sopenharmony_ci	/* Not fragmented packet */
9088c2ecf20Sopenharmony_ci	tid = mvpp2_prs_tcam_first_free(priv, MVPP2_PE_FIRST_FREE_TID,
9098c2ecf20Sopenharmony_ci					MVPP2_PE_LAST_FREE_TID);
9108c2ecf20Sopenharmony_ci	if (tid < 0)
9118c2ecf20Sopenharmony_ci		return tid;
9128c2ecf20Sopenharmony_ci
9138c2ecf20Sopenharmony_ci	memset(&pe, 0, sizeof(pe));
9148c2ecf20Sopenharmony_ci	mvpp2_prs_tcam_lu_set(&pe, MVPP2_PRS_LU_IP4);
9158c2ecf20Sopenharmony_ci	pe.index = tid;
9168c2ecf20Sopenharmony_ci
9178c2ecf20Sopenharmony_ci	/* Set next lu to IPv4 */
9188c2ecf20Sopenharmony_ci	mvpp2_prs_sram_next_lu_set(&pe, MVPP2_PRS_LU_IP4);
9198c2ecf20Sopenharmony_ci	mvpp2_prs_sram_shift_set(&pe, 12, MVPP2_PRS_SRAM_OP_SEL_SHIFT_ADD);
9208c2ecf20Sopenharmony_ci	/* Set L4 offset */
9218c2ecf20Sopenharmony_ci	mvpp2_prs_sram_offset_set(&pe, MVPP2_PRS_SRAM_UDF_TYPE_L4,
9228c2ecf20Sopenharmony_ci				  sizeof(struct iphdr) - 4,
9238c2ecf20Sopenharmony_ci				  MVPP2_PRS_SRAM_OP_SEL_UDF_ADD);
9248c2ecf20Sopenharmony_ci	mvpp2_prs_sram_ai_update(&pe, MVPP2_PRS_IPV4_DIP_AI_BIT,
9258c2ecf20Sopenharmony_ci				 MVPP2_PRS_IPV4_DIP_AI_BIT);
9268c2ecf20Sopenharmony_ci	mvpp2_prs_sram_ri_update(&pe, ri, ri_mask | MVPP2_PRS_RI_IP_FRAG_MASK);
9278c2ecf20Sopenharmony_ci
9288c2ecf20Sopenharmony_ci	mvpp2_prs_tcam_data_byte_set(&pe, 2, 0x00,
9298c2ecf20Sopenharmony_ci				     MVPP2_PRS_TCAM_PROTO_MASK_L);
9308c2ecf20Sopenharmony_ci	mvpp2_prs_tcam_data_byte_set(&pe, 3, 0x00,
9318c2ecf20Sopenharmony_ci				     MVPP2_PRS_TCAM_PROTO_MASK);
9328c2ecf20Sopenharmony_ci
9338c2ecf20Sopenharmony_ci	mvpp2_prs_tcam_data_byte_set(&pe, 5, proto, MVPP2_PRS_TCAM_PROTO_MASK);
9348c2ecf20Sopenharmony_ci	mvpp2_prs_tcam_ai_update(&pe, 0, MVPP2_PRS_IPV4_DIP_AI_BIT);
9358c2ecf20Sopenharmony_ci	/* Unmask all ports */
9368c2ecf20Sopenharmony_ci	mvpp2_prs_tcam_port_map_set(&pe, MVPP2_PRS_PORT_MASK);
9378c2ecf20Sopenharmony_ci
9388c2ecf20Sopenharmony_ci	/* Update shadow table and hw entry */
9398c2ecf20Sopenharmony_ci	mvpp2_prs_shadow_set(priv, pe.index, MVPP2_PRS_LU_IP4);
9408c2ecf20Sopenharmony_ci	mvpp2_prs_hw_write(priv, &pe);
9418c2ecf20Sopenharmony_ci
9428c2ecf20Sopenharmony_ci	/* Fragmented packet */
9438c2ecf20Sopenharmony_ci	tid = mvpp2_prs_tcam_first_free(priv, MVPP2_PE_FIRST_FREE_TID,
9448c2ecf20Sopenharmony_ci					MVPP2_PE_LAST_FREE_TID);
9458c2ecf20Sopenharmony_ci	if (tid < 0)
9468c2ecf20Sopenharmony_ci		return tid;
9478c2ecf20Sopenharmony_ci
9488c2ecf20Sopenharmony_ci	pe.index = tid;
9498c2ecf20Sopenharmony_ci	/* Clear ri before updating */
9508c2ecf20Sopenharmony_ci	pe.sram[MVPP2_PRS_SRAM_RI_WORD] = 0x0;
9518c2ecf20Sopenharmony_ci	pe.sram[MVPP2_PRS_SRAM_RI_CTRL_WORD] = 0x0;
9528c2ecf20Sopenharmony_ci	mvpp2_prs_sram_ri_update(&pe, ri, ri_mask);
9538c2ecf20Sopenharmony_ci
9548c2ecf20Sopenharmony_ci	mvpp2_prs_sram_ri_update(&pe, ri | MVPP2_PRS_RI_IP_FRAG_TRUE,
9558c2ecf20Sopenharmony_ci				 ri_mask | MVPP2_PRS_RI_IP_FRAG_MASK);
9568c2ecf20Sopenharmony_ci
9578c2ecf20Sopenharmony_ci	mvpp2_prs_tcam_data_byte_set(&pe, 2, 0x00, 0x0);
9588c2ecf20Sopenharmony_ci	mvpp2_prs_tcam_data_byte_set(&pe, 3, 0x00, 0x0);
9598c2ecf20Sopenharmony_ci
9608c2ecf20Sopenharmony_ci	/* Update shadow table and hw entry */
9618c2ecf20Sopenharmony_ci	mvpp2_prs_shadow_set(priv, pe.index, MVPP2_PRS_LU_IP4);
9628c2ecf20Sopenharmony_ci	mvpp2_prs_hw_write(priv, &pe);
9638c2ecf20Sopenharmony_ci
9648c2ecf20Sopenharmony_ci	return 0;
9658c2ecf20Sopenharmony_ci}
9668c2ecf20Sopenharmony_ci
9678c2ecf20Sopenharmony_ci/* IPv4 L3 multicast or broadcast */
9688c2ecf20Sopenharmony_cistatic int mvpp2_prs_ip4_cast(struct mvpp2 *priv, unsigned short l3_cast)
9698c2ecf20Sopenharmony_ci{
9708c2ecf20Sopenharmony_ci	struct mvpp2_prs_entry pe;
9718c2ecf20Sopenharmony_ci	int mask, tid;
9728c2ecf20Sopenharmony_ci
9738c2ecf20Sopenharmony_ci	tid = mvpp2_prs_tcam_first_free(priv, MVPP2_PE_FIRST_FREE_TID,
9748c2ecf20Sopenharmony_ci					MVPP2_PE_LAST_FREE_TID);
9758c2ecf20Sopenharmony_ci	if (tid < 0)
9768c2ecf20Sopenharmony_ci		return tid;
9778c2ecf20Sopenharmony_ci
9788c2ecf20Sopenharmony_ci	memset(&pe, 0, sizeof(pe));
9798c2ecf20Sopenharmony_ci	mvpp2_prs_tcam_lu_set(&pe, MVPP2_PRS_LU_IP4);
9808c2ecf20Sopenharmony_ci	pe.index = tid;
9818c2ecf20Sopenharmony_ci
9828c2ecf20Sopenharmony_ci	switch (l3_cast) {
9838c2ecf20Sopenharmony_ci	case MVPP2_PRS_L3_MULTI_CAST:
9848c2ecf20Sopenharmony_ci		mvpp2_prs_tcam_data_byte_set(&pe, 0, MVPP2_PRS_IPV4_MC,
9858c2ecf20Sopenharmony_ci					     MVPP2_PRS_IPV4_MC_MASK);
9868c2ecf20Sopenharmony_ci		mvpp2_prs_sram_ri_update(&pe, MVPP2_PRS_RI_L3_MCAST,
9878c2ecf20Sopenharmony_ci					 MVPP2_PRS_RI_L3_ADDR_MASK);
9888c2ecf20Sopenharmony_ci		break;
9898c2ecf20Sopenharmony_ci	case  MVPP2_PRS_L3_BROAD_CAST:
9908c2ecf20Sopenharmony_ci		mask = MVPP2_PRS_IPV4_BC_MASK;
9918c2ecf20Sopenharmony_ci		mvpp2_prs_tcam_data_byte_set(&pe, 0, mask, mask);
9928c2ecf20Sopenharmony_ci		mvpp2_prs_tcam_data_byte_set(&pe, 1, mask, mask);
9938c2ecf20Sopenharmony_ci		mvpp2_prs_tcam_data_byte_set(&pe, 2, mask, mask);
9948c2ecf20Sopenharmony_ci		mvpp2_prs_tcam_data_byte_set(&pe, 3, mask, mask);
9958c2ecf20Sopenharmony_ci		mvpp2_prs_sram_ri_update(&pe, MVPP2_PRS_RI_L3_BCAST,
9968c2ecf20Sopenharmony_ci					 MVPP2_PRS_RI_L3_ADDR_MASK);
9978c2ecf20Sopenharmony_ci		break;
9988c2ecf20Sopenharmony_ci	default:
9998c2ecf20Sopenharmony_ci		return -EINVAL;
10008c2ecf20Sopenharmony_ci	}
10018c2ecf20Sopenharmony_ci
10028c2ecf20Sopenharmony_ci	/* Finished: go to flowid generation */
10038c2ecf20Sopenharmony_ci	mvpp2_prs_sram_next_lu_set(&pe, MVPP2_PRS_LU_FLOWS);
10048c2ecf20Sopenharmony_ci	mvpp2_prs_sram_bits_set(&pe, MVPP2_PRS_SRAM_LU_GEN_BIT, 1);
10058c2ecf20Sopenharmony_ci
10068c2ecf20Sopenharmony_ci	mvpp2_prs_tcam_ai_update(&pe, MVPP2_PRS_IPV4_DIP_AI_BIT,
10078c2ecf20Sopenharmony_ci				 MVPP2_PRS_IPV4_DIP_AI_BIT);
10088c2ecf20Sopenharmony_ci	/* Unmask all ports */
10098c2ecf20Sopenharmony_ci	mvpp2_prs_tcam_port_map_set(&pe, MVPP2_PRS_PORT_MASK);
10108c2ecf20Sopenharmony_ci
10118c2ecf20Sopenharmony_ci	/* Update shadow table and hw entry */
10128c2ecf20Sopenharmony_ci	mvpp2_prs_shadow_set(priv, pe.index, MVPP2_PRS_LU_IP4);
10138c2ecf20Sopenharmony_ci	mvpp2_prs_hw_write(priv, &pe);
10148c2ecf20Sopenharmony_ci
10158c2ecf20Sopenharmony_ci	return 0;
10168c2ecf20Sopenharmony_ci}
10178c2ecf20Sopenharmony_ci
10188c2ecf20Sopenharmony_ci/* Set entries for protocols over IPv6  */
10198c2ecf20Sopenharmony_cistatic int mvpp2_prs_ip6_proto(struct mvpp2 *priv, unsigned short proto,
10208c2ecf20Sopenharmony_ci			       unsigned int ri, unsigned int ri_mask)
10218c2ecf20Sopenharmony_ci{
10228c2ecf20Sopenharmony_ci	struct mvpp2_prs_entry pe;
10238c2ecf20Sopenharmony_ci	int tid;
10248c2ecf20Sopenharmony_ci
10258c2ecf20Sopenharmony_ci	if ((proto != IPPROTO_TCP) && (proto != IPPROTO_UDP) &&
10268c2ecf20Sopenharmony_ci	    (proto != IPPROTO_ICMPV6) && (proto != IPPROTO_IPIP))
10278c2ecf20Sopenharmony_ci		return -EINVAL;
10288c2ecf20Sopenharmony_ci
10298c2ecf20Sopenharmony_ci	tid = mvpp2_prs_tcam_first_free(priv, MVPP2_PE_FIRST_FREE_TID,
10308c2ecf20Sopenharmony_ci					MVPP2_PE_LAST_FREE_TID);
10318c2ecf20Sopenharmony_ci	if (tid < 0)
10328c2ecf20Sopenharmony_ci		return tid;
10338c2ecf20Sopenharmony_ci
10348c2ecf20Sopenharmony_ci	memset(&pe, 0, sizeof(pe));
10358c2ecf20Sopenharmony_ci	mvpp2_prs_tcam_lu_set(&pe, MVPP2_PRS_LU_IP6);
10368c2ecf20Sopenharmony_ci	pe.index = tid;
10378c2ecf20Sopenharmony_ci
10388c2ecf20Sopenharmony_ci	/* Finished: go to flowid generation */
10398c2ecf20Sopenharmony_ci	mvpp2_prs_sram_next_lu_set(&pe, MVPP2_PRS_LU_FLOWS);
10408c2ecf20Sopenharmony_ci	mvpp2_prs_sram_bits_set(&pe, MVPP2_PRS_SRAM_LU_GEN_BIT, 1);
10418c2ecf20Sopenharmony_ci	mvpp2_prs_sram_ri_update(&pe, ri, ri_mask);
10428c2ecf20Sopenharmony_ci	mvpp2_prs_sram_offset_set(&pe, MVPP2_PRS_SRAM_UDF_TYPE_L4,
10438c2ecf20Sopenharmony_ci				  sizeof(struct ipv6hdr) - 6,
10448c2ecf20Sopenharmony_ci				  MVPP2_PRS_SRAM_OP_SEL_UDF_ADD);
10458c2ecf20Sopenharmony_ci
10468c2ecf20Sopenharmony_ci	mvpp2_prs_tcam_data_byte_set(&pe, 0, proto, MVPP2_PRS_TCAM_PROTO_MASK);
10478c2ecf20Sopenharmony_ci	mvpp2_prs_tcam_ai_update(&pe, MVPP2_PRS_IPV6_NO_EXT_AI_BIT,
10488c2ecf20Sopenharmony_ci				 MVPP2_PRS_IPV6_NO_EXT_AI_BIT);
10498c2ecf20Sopenharmony_ci	/* Unmask all ports */
10508c2ecf20Sopenharmony_ci	mvpp2_prs_tcam_port_map_set(&pe, MVPP2_PRS_PORT_MASK);
10518c2ecf20Sopenharmony_ci
10528c2ecf20Sopenharmony_ci	/* Write HW */
10538c2ecf20Sopenharmony_ci	mvpp2_prs_shadow_set(priv, pe.index, MVPP2_PRS_LU_IP6);
10548c2ecf20Sopenharmony_ci	mvpp2_prs_hw_write(priv, &pe);
10558c2ecf20Sopenharmony_ci
10568c2ecf20Sopenharmony_ci	return 0;
10578c2ecf20Sopenharmony_ci}
10588c2ecf20Sopenharmony_ci
10598c2ecf20Sopenharmony_ci/* IPv6 L3 multicast entry */
10608c2ecf20Sopenharmony_cistatic int mvpp2_prs_ip6_cast(struct mvpp2 *priv, unsigned short l3_cast)
10618c2ecf20Sopenharmony_ci{
10628c2ecf20Sopenharmony_ci	struct mvpp2_prs_entry pe;
10638c2ecf20Sopenharmony_ci	int tid;
10648c2ecf20Sopenharmony_ci
10658c2ecf20Sopenharmony_ci	if (l3_cast != MVPP2_PRS_L3_MULTI_CAST)
10668c2ecf20Sopenharmony_ci		return -EINVAL;
10678c2ecf20Sopenharmony_ci
10688c2ecf20Sopenharmony_ci	tid = mvpp2_prs_tcam_first_free(priv, MVPP2_PE_FIRST_FREE_TID,
10698c2ecf20Sopenharmony_ci					MVPP2_PE_LAST_FREE_TID);
10708c2ecf20Sopenharmony_ci	if (tid < 0)
10718c2ecf20Sopenharmony_ci		return tid;
10728c2ecf20Sopenharmony_ci
10738c2ecf20Sopenharmony_ci	memset(&pe, 0, sizeof(pe));
10748c2ecf20Sopenharmony_ci	mvpp2_prs_tcam_lu_set(&pe, MVPP2_PRS_LU_IP6);
10758c2ecf20Sopenharmony_ci	pe.index = tid;
10768c2ecf20Sopenharmony_ci
10778c2ecf20Sopenharmony_ci	/* Finished: go to flowid generation */
10788c2ecf20Sopenharmony_ci	mvpp2_prs_sram_next_lu_set(&pe, MVPP2_PRS_LU_IP6);
10798c2ecf20Sopenharmony_ci	mvpp2_prs_sram_ri_update(&pe, MVPP2_PRS_RI_L3_MCAST,
10808c2ecf20Sopenharmony_ci				 MVPP2_PRS_RI_L3_ADDR_MASK);
10818c2ecf20Sopenharmony_ci	mvpp2_prs_sram_ai_update(&pe, MVPP2_PRS_IPV6_NO_EXT_AI_BIT,
10828c2ecf20Sopenharmony_ci				 MVPP2_PRS_IPV6_NO_EXT_AI_BIT);
10838c2ecf20Sopenharmony_ci	/* Shift back to IPv6 NH */
10848c2ecf20Sopenharmony_ci	mvpp2_prs_sram_shift_set(&pe, -18, MVPP2_PRS_SRAM_OP_SEL_SHIFT_ADD);
10858c2ecf20Sopenharmony_ci
10868c2ecf20Sopenharmony_ci	mvpp2_prs_tcam_data_byte_set(&pe, 0, MVPP2_PRS_IPV6_MC,
10878c2ecf20Sopenharmony_ci				     MVPP2_PRS_IPV6_MC_MASK);
10888c2ecf20Sopenharmony_ci	mvpp2_prs_tcam_ai_update(&pe, 0, MVPP2_PRS_IPV6_NO_EXT_AI_BIT);
10898c2ecf20Sopenharmony_ci	/* Unmask all ports */
10908c2ecf20Sopenharmony_ci	mvpp2_prs_tcam_port_map_set(&pe, MVPP2_PRS_PORT_MASK);
10918c2ecf20Sopenharmony_ci
10928c2ecf20Sopenharmony_ci	/* Update shadow table and hw entry */
10938c2ecf20Sopenharmony_ci	mvpp2_prs_shadow_set(priv, pe.index, MVPP2_PRS_LU_IP6);
10948c2ecf20Sopenharmony_ci	mvpp2_prs_hw_write(priv, &pe);
10958c2ecf20Sopenharmony_ci
10968c2ecf20Sopenharmony_ci	return 0;
10978c2ecf20Sopenharmony_ci}
10988c2ecf20Sopenharmony_ci
10998c2ecf20Sopenharmony_ci/* Parser per-port initialization */
11008c2ecf20Sopenharmony_cistatic void mvpp2_prs_hw_port_init(struct mvpp2 *priv, int port, int lu_first,
11018c2ecf20Sopenharmony_ci				   int lu_max, int offset)
11028c2ecf20Sopenharmony_ci{
11038c2ecf20Sopenharmony_ci	u32 val;
11048c2ecf20Sopenharmony_ci
11058c2ecf20Sopenharmony_ci	/* Set lookup ID */
11068c2ecf20Sopenharmony_ci	val = mvpp2_read(priv, MVPP2_PRS_INIT_LOOKUP_REG);
11078c2ecf20Sopenharmony_ci	val &= ~MVPP2_PRS_PORT_LU_MASK(port);
11088c2ecf20Sopenharmony_ci	val |=  MVPP2_PRS_PORT_LU_VAL(port, lu_first);
11098c2ecf20Sopenharmony_ci	mvpp2_write(priv, MVPP2_PRS_INIT_LOOKUP_REG, val);
11108c2ecf20Sopenharmony_ci
11118c2ecf20Sopenharmony_ci	/* Set maximum number of loops for packet received from port */
11128c2ecf20Sopenharmony_ci	val = mvpp2_read(priv, MVPP2_PRS_MAX_LOOP_REG(port));
11138c2ecf20Sopenharmony_ci	val &= ~MVPP2_PRS_MAX_LOOP_MASK(port);
11148c2ecf20Sopenharmony_ci	val |= MVPP2_PRS_MAX_LOOP_VAL(port, lu_max);
11158c2ecf20Sopenharmony_ci	mvpp2_write(priv, MVPP2_PRS_MAX_LOOP_REG(port), val);
11168c2ecf20Sopenharmony_ci
11178c2ecf20Sopenharmony_ci	/* Set initial offset for packet header extraction for the first
11188c2ecf20Sopenharmony_ci	 * searching loop
11198c2ecf20Sopenharmony_ci	 */
11208c2ecf20Sopenharmony_ci	val = mvpp2_read(priv, MVPP2_PRS_INIT_OFFS_REG(port));
11218c2ecf20Sopenharmony_ci	val &= ~MVPP2_PRS_INIT_OFF_MASK(port);
11228c2ecf20Sopenharmony_ci	val |= MVPP2_PRS_INIT_OFF_VAL(port, offset);
11238c2ecf20Sopenharmony_ci	mvpp2_write(priv, MVPP2_PRS_INIT_OFFS_REG(port), val);
11248c2ecf20Sopenharmony_ci}
11258c2ecf20Sopenharmony_ci
11268c2ecf20Sopenharmony_ci/* Default flow entries initialization for all ports */
11278c2ecf20Sopenharmony_cistatic void mvpp2_prs_def_flow_init(struct mvpp2 *priv)
11288c2ecf20Sopenharmony_ci{
11298c2ecf20Sopenharmony_ci	struct mvpp2_prs_entry pe;
11308c2ecf20Sopenharmony_ci	int port;
11318c2ecf20Sopenharmony_ci
11328c2ecf20Sopenharmony_ci	for (port = 0; port < MVPP2_MAX_PORTS; port++) {
11338c2ecf20Sopenharmony_ci		memset(&pe, 0, sizeof(pe));
11348c2ecf20Sopenharmony_ci		mvpp2_prs_tcam_lu_set(&pe, MVPP2_PRS_LU_FLOWS);
11358c2ecf20Sopenharmony_ci		pe.index = MVPP2_PE_FIRST_DEFAULT_FLOW - port;
11368c2ecf20Sopenharmony_ci
11378c2ecf20Sopenharmony_ci		/* Mask all ports */
11388c2ecf20Sopenharmony_ci		mvpp2_prs_tcam_port_map_set(&pe, 0);
11398c2ecf20Sopenharmony_ci
11408c2ecf20Sopenharmony_ci		/* Set flow ID*/
11418c2ecf20Sopenharmony_ci		mvpp2_prs_sram_ai_update(&pe, port, MVPP2_PRS_FLOW_ID_MASK);
11428c2ecf20Sopenharmony_ci		mvpp2_prs_sram_bits_set(&pe, MVPP2_PRS_SRAM_LU_DONE_BIT, 1);
11438c2ecf20Sopenharmony_ci
11448c2ecf20Sopenharmony_ci		/* Update shadow table and hw entry */
11458c2ecf20Sopenharmony_ci		mvpp2_prs_shadow_set(priv, pe.index, MVPP2_PRS_LU_FLOWS);
11468c2ecf20Sopenharmony_ci		mvpp2_prs_hw_write(priv, &pe);
11478c2ecf20Sopenharmony_ci	}
11488c2ecf20Sopenharmony_ci}
11498c2ecf20Sopenharmony_ci
11508c2ecf20Sopenharmony_ci/* Set default entry for Marvell Header field */
11518c2ecf20Sopenharmony_cistatic void mvpp2_prs_mh_init(struct mvpp2 *priv)
11528c2ecf20Sopenharmony_ci{
11538c2ecf20Sopenharmony_ci	struct mvpp2_prs_entry pe;
11548c2ecf20Sopenharmony_ci
11558c2ecf20Sopenharmony_ci	memset(&pe, 0, sizeof(pe));
11568c2ecf20Sopenharmony_ci
11578c2ecf20Sopenharmony_ci	pe.index = MVPP2_PE_MH_DEFAULT;
11588c2ecf20Sopenharmony_ci	mvpp2_prs_tcam_lu_set(&pe, MVPP2_PRS_LU_MH);
11598c2ecf20Sopenharmony_ci	mvpp2_prs_sram_shift_set(&pe, MVPP2_MH_SIZE,
11608c2ecf20Sopenharmony_ci				 MVPP2_PRS_SRAM_OP_SEL_SHIFT_ADD);
11618c2ecf20Sopenharmony_ci	mvpp2_prs_sram_next_lu_set(&pe, MVPP2_PRS_LU_MAC);
11628c2ecf20Sopenharmony_ci
11638c2ecf20Sopenharmony_ci	/* Unmask all ports */
11648c2ecf20Sopenharmony_ci	mvpp2_prs_tcam_port_map_set(&pe, MVPP2_PRS_PORT_MASK);
11658c2ecf20Sopenharmony_ci
11668c2ecf20Sopenharmony_ci	/* Update shadow table and hw entry */
11678c2ecf20Sopenharmony_ci	mvpp2_prs_shadow_set(priv, pe.index, MVPP2_PRS_LU_MH);
11688c2ecf20Sopenharmony_ci	mvpp2_prs_hw_write(priv, &pe);
11698c2ecf20Sopenharmony_ci}
11708c2ecf20Sopenharmony_ci
11718c2ecf20Sopenharmony_ci/* Set default entires (place holder) for promiscuous, non-promiscuous and
11728c2ecf20Sopenharmony_ci * multicast MAC addresses
11738c2ecf20Sopenharmony_ci */
11748c2ecf20Sopenharmony_cistatic void mvpp2_prs_mac_init(struct mvpp2 *priv)
11758c2ecf20Sopenharmony_ci{
11768c2ecf20Sopenharmony_ci	struct mvpp2_prs_entry pe;
11778c2ecf20Sopenharmony_ci
11788c2ecf20Sopenharmony_ci	memset(&pe, 0, sizeof(pe));
11798c2ecf20Sopenharmony_ci
11808c2ecf20Sopenharmony_ci	/* Non-promiscuous mode for all ports - DROP unknown packets */
11818c2ecf20Sopenharmony_ci	pe.index = MVPP2_PE_MAC_NON_PROMISCUOUS;
11828c2ecf20Sopenharmony_ci	mvpp2_prs_tcam_lu_set(&pe, MVPP2_PRS_LU_MAC);
11838c2ecf20Sopenharmony_ci
11848c2ecf20Sopenharmony_ci	mvpp2_prs_sram_ri_update(&pe, MVPP2_PRS_RI_DROP_MASK,
11858c2ecf20Sopenharmony_ci				 MVPP2_PRS_RI_DROP_MASK);
11868c2ecf20Sopenharmony_ci	mvpp2_prs_sram_bits_set(&pe, MVPP2_PRS_SRAM_LU_GEN_BIT, 1);
11878c2ecf20Sopenharmony_ci	mvpp2_prs_sram_next_lu_set(&pe, MVPP2_PRS_LU_FLOWS);
11888c2ecf20Sopenharmony_ci
11898c2ecf20Sopenharmony_ci	/* Unmask all ports */
11908c2ecf20Sopenharmony_ci	mvpp2_prs_tcam_port_map_set(&pe, MVPP2_PRS_PORT_MASK);
11918c2ecf20Sopenharmony_ci
11928c2ecf20Sopenharmony_ci	/* Update shadow table and hw entry */
11938c2ecf20Sopenharmony_ci	mvpp2_prs_shadow_set(priv, pe.index, MVPP2_PRS_LU_MAC);
11948c2ecf20Sopenharmony_ci	mvpp2_prs_hw_write(priv, &pe);
11958c2ecf20Sopenharmony_ci
11968c2ecf20Sopenharmony_ci	/* Create dummy entries for drop all and promiscuous modes */
11978c2ecf20Sopenharmony_ci	mvpp2_prs_drop_fc(priv);
11988c2ecf20Sopenharmony_ci	mvpp2_prs_mac_drop_all_set(priv, 0, false);
11998c2ecf20Sopenharmony_ci	mvpp2_prs_mac_promisc_set(priv, 0, MVPP2_PRS_L2_UNI_CAST, false);
12008c2ecf20Sopenharmony_ci	mvpp2_prs_mac_promisc_set(priv, 0, MVPP2_PRS_L2_MULTI_CAST, false);
12018c2ecf20Sopenharmony_ci}
12028c2ecf20Sopenharmony_ci
12038c2ecf20Sopenharmony_ci/* Set default entries for various types of dsa packets */
12048c2ecf20Sopenharmony_cistatic void mvpp2_prs_dsa_init(struct mvpp2 *priv)
12058c2ecf20Sopenharmony_ci{
12068c2ecf20Sopenharmony_ci	struct mvpp2_prs_entry pe;
12078c2ecf20Sopenharmony_ci
12088c2ecf20Sopenharmony_ci	/* None tagged EDSA entry - place holder */
12098c2ecf20Sopenharmony_ci	mvpp2_prs_dsa_tag_set(priv, 0, false, MVPP2_PRS_UNTAGGED,
12108c2ecf20Sopenharmony_ci			      MVPP2_PRS_EDSA);
12118c2ecf20Sopenharmony_ci
12128c2ecf20Sopenharmony_ci	/* Tagged EDSA entry - place holder */
12138c2ecf20Sopenharmony_ci	mvpp2_prs_dsa_tag_set(priv, 0, false, MVPP2_PRS_TAGGED, MVPP2_PRS_EDSA);
12148c2ecf20Sopenharmony_ci
12158c2ecf20Sopenharmony_ci	/* None tagged DSA entry - place holder */
12168c2ecf20Sopenharmony_ci	mvpp2_prs_dsa_tag_set(priv, 0, false, MVPP2_PRS_UNTAGGED,
12178c2ecf20Sopenharmony_ci			      MVPP2_PRS_DSA);
12188c2ecf20Sopenharmony_ci
12198c2ecf20Sopenharmony_ci	/* Tagged DSA entry - place holder */
12208c2ecf20Sopenharmony_ci	mvpp2_prs_dsa_tag_set(priv, 0, false, MVPP2_PRS_TAGGED, MVPP2_PRS_DSA);
12218c2ecf20Sopenharmony_ci
12228c2ecf20Sopenharmony_ci	/* None tagged EDSA ethertype entry - place holder*/
12238c2ecf20Sopenharmony_ci	mvpp2_prs_dsa_tag_ethertype_set(priv, 0, false,
12248c2ecf20Sopenharmony_ci					MVPP2_PRS_UNTAGGED, MVPP2_PRS_EDSA);
12258c2ecf20Sopenharmony_ci
12268c2ecf20Sopenharmony_ci	/* Tagged EDSA ethertype entry - place holder*/
12278c2ecf20Sopenharmony_ci	mvpp2_prs_dsa_tag_ethertype_set(priv, 0, false,
12288c2ecf20Sopenharmony_ci					MVPP2_PRS_TAGGED, MVPP2_PRS_EDSA);
12298c2ecf20Sopenharmony_ci
12308c2ecf20Sopenharmony_ci	/* None tagged DSA ethertype entry */
12318c2ecf20Sopenharmony_ci	mvpp2_prs_dsa_tag_ethertype_set(priv, 0, true,
12328c2ecf20Sopenharmony_ci					MVPP2_PRS_UNTAGGED, MVPP2_PRS_DSA);
12338c2ecf20Sopenharmony_ci
12348c2ecf20Sopenharmony_ci	/* Tagged DSA ethertype entry */
12358c2ecf20Sopenharmony_ci	mvpp2_prs_dsa_tag_ethertype_set(priv, 0, true,
12368c2ecf20Sopenharmony_ci					MVPP2_PRS_TAGGED, MVPP2_PRS_DSA);
12378c2ecf20Sopenharmony_ci
12388c2ecf20Sopenharmony_ci	/* Set default entry, in case DSA or EDSA tag not found */
12398c2ecf20Sopenharmony_ci	memset(&pe, 0, sizeof(pe));
12408c2ecf20Sopenharmony_ci	mvpp2_prs_tcam_lu_set(&pe, MVPP2_PRS_LU_DSA);
12418c2ecf20Sopenharmony_ci	pe.index = MVPP2_PE_DSA_DEFAULT;
12428c2ecf20Sopenharmony_ci	mvpp2_prs_sram_next_lu_set(&pe, MVPP2_PRS_LU_VLAN);
12438c2ecf20Sopenharmony_ci
12448c2ecf20Sopenharmony_ci	/* Shift 0 bytes */
12458c2ecf20Sopenharmony_ci	mvpp2_prs_sram_shift_set(&pe, 0, MVPP2_PRS_SRAM_OP_SEL_SHIFT_ADD);
12468c2ecf20Sopenharmony_ci	mvpp2_prs_shadow_set(priv, pe.index, MVPP2_PRS_LU_MAC);
12478c2ecf20Sopenharmony_ci
12488c2ecf20Sopenharmony_ci	/* Clear all sram ai bits for next iteration */
12498c2ecf20Sopenharmony_ci	mvpp2_prs_sram_ai_update(&pe, 0, MVPP2_PRS_SRAM_AI_MASK);
12508c2ecf20Sopenharmony_ci
12518c2ecf20Sopenharmony_ci	/* Unmask all ports */
12528c2ecf20Sopenharmony_ci	mvpp2_prs_tcam_port_map_set(&pe, MVPP2_PRS_PORT_MASK);
12538c2ecf20Sopenharmony_ci
12548c2ecf20Sopenharmony_ci	mvpp2_prs_hw_write(priv, &pe);
12558c2ecf20Sopenharmony_ci}
12568c2ecf20Sopenharmony_ci
12578c2ecf20Sopenharmony_ci/* Initialize parser entries for VID filtering */
12588c2ecf20Sopenharmony_cistatic void mvpp2_prs_vid_init(struct mvpp2 *priv)
12598c2ecf20Sopenharmony_ci{
12608c2ecf20Sopenharmony_ci	struct mvpp2_prs_entry pe;
12618c2ecf20Sopenharmony_ci
12628c2ecf20Sopenharmony_ci	memset(&pe, 0, sizeof(pe));
12638c2ecf20Sopenharmony_ci
12648c2ecf20Sopenharmony_ci	/* Set default vid entry */
12658c2ecf20Sopenharmony_ci	pe.index = MVPP2_PE_VID_FLTR_DEFAULT;
12668c2ecf20Sopenharmony_ci	mvpp2_prs_tcam_lu_set(&pe, MVPP2_PRS_LU_VID);
12678c2ecf20Sopenharmony_ci
12688c2ecf20Sopenharmony_ci	mvpp2_prs_tcam_ai_update(&pe, 0, MVPP2_PRS_EDSA_VID_AI_BIT);
12698c2ecf20Sopenharmony_ci
12708c2ecf20Sopenharmony_ci	/* Skip VLAN header - Set offset to 4 bytes */
12718c2ecf20Sopenharmony_ci	mvpp2_prs_sram_shift_set(&pe, MVPP2_VLAN_TAG_LEN,
12728c2ecf20Sopenharmony_ci				 MVPP2_PRS_SRAM_OP_SEL_SHIFT_ADD);
12738c2ecf20Sopenharmony_ci
12748c2ecf20Sopenharmony_ci	/* Clear all ai bits for next iteration */
12758c2ecf20Sopenharmony_ci	mvpp2_prs_sram_ai_update(&pe, 0, MVPP2_PRS_SRAM_AI_MASK);
12768c2ecf20Sopenharmony_ci
12778c2ecf20Sopenharmony_ci	mvpp2_prs_sram_next_lu_set(&pe, MVPP2_PRS_LU_L2);
12788c2ecf20Sopenharmony_ci
12798c2ecf20Sopenharmony_ci	/* Unmask all ports */
12808c2ecf20Sopenharmony_ci	mvpp2_prs_tcam_port_map_set(&pe, MVPP2_PRS_PORT_MASK);
12818c2ecf20Sopenharmony_ci
12828c2ecf20Sopenharmony_ci	/* Update shadow table and hw entry */
12838c2ecf20Sopenharmony_ci	mvpp2_prs_shadow_set(priv, pe.index, MVPP2_PRS_LU_VID);
12848c2ecf20Sopenharmony_ci	mvpp2_prs_hw_write(priv, &pe);
12858c2ecf20Sopenharmony_ci
12868c2ecf20Sopenharmony_ci	/* Set default vid entry for extended DSA*/
12878c2ecf20Sopenharmony_ci	memset(&pe, 0, sizeof(pe));
12888c2ecf20Sopenharmony_ci
12898c2ecf20Sopenharmony_ci	/* Set default vid entry */
12908c2ecf20Sopenharmony_ci	pe.index = MVPP2_PE_VID_EDSA_FLTR_DEFAULT;
12918c2ecf20Sopenharmony_ci	mvpp2_prs_tcam_lu_set(&pe, MVPP2_PRS_LU_VID);
12928c2ecf20Sopenharmony_ci
12938c2ecf20Sopenharmony_ci	mvpp2_prs_tcam_ai_update(&pe, MVPP2_PRS_EDSA_VID_AI_BIT,
12948c2ecf20Sopenharmony_ci				 MVPP2_PRS_EDSA_VID_AI_BIT);
12958c2ecf20Sopenharmony_ci
12968c2ecf20Sopenharmony_ci	/* Skip VLAN header - Set offset to 8 bytes */
12978c2ecf20Sopenharmony_ci	mvpp2_prs_sram_shift_set(&pe, MVPP2_VLAN_TAG_EDSA_LEN,
12988c2ecf20Sopenharmony_ci				 MVPP2_PRS_SRAM_OP_SEL_SHIFT_ADD);
12998c2ecf20Sopenharmony_ci
13008c2ecf20Sopenharmony_ci	/* Clear all ai bits for next iteration */
13018c2ecf20Sopenharmony_ci	mvpp2_prs_sram_ai_update(&pe, 0, MVPP2_PRS_SRAM_AI_MASK);
13028c2ecf20Sopenharmony_ci
13038c2ecf20Sopenharmony_ci	mvpp2_prs_sram_next_lu_set(&pe, MVPP2_PRS_LU_L2);
13048c2ecf20Sopenharmony_ci
13058c2ecf20Sopenharmony_ci	/* Unmask all ports */
13068c2ecf20Sopenharmony_ci	mvpp2_prs_tcam_port_map_set(&pe, MVPP2_PRS_PORT_MASK);
13078c2ecf20Sopenharmony_ci
13088c2ecf20Sopenharmony_ci	/* Update shadow table and hw entry */
13098c2ecf20Sopenharmony_ci	mvpp2_prs_shadow_set(priv, pe.index, MVPP2_PRS_LU_VID);
13108c2ecf20Sopenharmony_ci	mvpp2_prs_hw_write(priv, &pe);
13118c2ecf20Sopenharmony_ci}
13128c2ecf20Sopenharmony_ci
13138c2ecf20Sopenharmony_ci/* Match basic ethertypes */
13148c2ecf20Sopenharmony_cistatic int mvpp2_prs_etype_init(struct mvpp2 *priv)
13158c2ecf20Sopenharmony_ci{
13168c2ecf20Sopenharmony_ci	struct mvpp2_prs_entry pe;
13178c2ecf20Sopenharmony_ci	int tid;
13188c2ecf20Sopenharmony_ci
13198c2ecf20Sopenharmony_ci	/* Ethertype: PPPoE */
13208c2ecf20Sopenharmony_ci	tid = mvpp2_prs_tcam_first_free(priv, MVPP2_PE_FIRST_FREE_TID,
13218c2ecf20Sopenharmony_ci					MVPP2_PE_LAST_FREE_TID);
13228c2ecf20Sopenharmony_ci	if (tid < 0)
13238c2ecf20Sopenharmony_ci		return tid;
13248c2ecf20Sopenharmony_ci
13258c2ecf20Sopenharmony_ci	memset(&pe, 0, sizeof(pe));
13268c2ecf20Sopenharmony_ci	mvpp2_prs_tcam_lu_set(&pe, MVPP2_PRS_LU_L2);
13278c2ecf20Sopenharmony_ci	pe.index = tid;
13288c2ecf20Sopenharmony_ci
13298c2ecf20Sopenharmony_ci	mvpp2_prs_match_etype(&pe, 0, ETH_P_PPP_SES);
13308c2ecf20Sopenharmony_ci
13318c2ecf20Sopenharmony_ci	mvpp2_prs_sram_shift_set(&pe, MVPP2_PPPOE_HDR_SIZE,
13328c2ecf20Sopenharmony_ci				 MVPP2_PRS_SRAM_OP_SEL_SHIFT_ADD);
13338c2ecf20Sopenharmony_ci	mvpp2_prs_sram_next_lu_set(&pe, MVPP2_PRS_LU_PPPOE);
13348c2ecf20Sopenharmony_ci	mvpp2_prs_sram_ri_update(&pe, MVPP2_PRS_RI_PPPOE_MASK,
13358c2ecf20Sopenharmony_ci				 MVPP2_PRS_RI_PPPOE_MASK);
13368c2ecf20Sopenharmony_ci
13378c2ecf20Sopenharmony_ci	/* Update shadow table and hw entry */
13388c2ecf20Sopenharmony_ci	mvpp2_prs_shadow_set(priv, pe.index, MVPP2_PRS_LU_L2);
13398c2ecf20Sopenharmony_ci	priv->prs_shadow[pe.index].udf = MVPP2_PRS_UDF_L2_DEF;
13408c2ecf20Sopenharmony_ci	priv->prs_shadow[pe.index].finish = false;
13418c2ecf20Sopenharmony_ci	mvpp2_prs_shadow_ri_set(priv, pe.index, MVPP2_PRS_RI_PPPOE_MASK,
13428c2ecf20Sopenharmony_ci				MVPP2_PRS_RI_PPPOE_MASK);
13438c2ecf20Sopenharmony_ci	mvpp2_prs_hw_write(priv, &pe);
13448c2ecf20Sopenharmony_ci
13458c2ecf20Sopenharmony_ci	/* Ethertype: ARP */
13468c2ecf20Sopenharmony_ci	tid = mvpp2_prs_tcam_first_free(priv, MVPP2_PE_FIRST_FREE_TID,
13478c2ecf20Sopenharmony_ci					MVPP2_PE_LAST_FREE_TID);
13488c2ecf20Sopenharmony_ci	if (tid < 0)
13498c2ecf20Sopenharmony_ci		return tid;
13508c2ecf20Sopenharmony_ci
13518c2ecf20Sopenharmony_ci	memset(&pe, 0, sizeof(pe));
13528c2ecf20Sopenharmony_ci	mvpp2_prs_tcam_lu_set(&pe, MVPP2_PRS_LU_L2);
13538c2ecf20Sopenharmony_ci	pe.index = tid;
13548c2ecf20Sopenharmony_ci
13558c2ecf20Sopenharmony_ci	mvpp2_prs_match_etype(&pe, 0, ETH_P_ARP);
13568c2ecf20Sopenharmony_ci
13578c2ecf20Sopenharmony_ci	/* Generate flow in the next iteration*/
13588c2ecf20Sopenharmony_ci	mvpp2_prs_sram_next_lu_set(&pe, MVPP2_PRS_LU_FLOWS);
13598c2ecf20Sopenharmony_ci	mvpp2_prs_sram_bits_set(&pe, MVPP2_PRS_SRAM_LU_GEN_BIT, 1);
13608c2ecf20Sopenharmony_ci	mvpp2_prs_sram_ri_update(&pe, MVPP2_PRS_RI_L3_ARP,
13618c2ecf20Sopenharmony_ci				 MVPP2_PRS_RI_L3_PROTO_MASK);
13628c2ecf20Sopenharmony_ci	/* Set L3 offset */
13638c2ecf20Sopenharmony_ci	mvpp2_prs_sram_offset_set(&pe, MVPP2_PRS_SRAM_UDF_TYPE_L3,
13648c2ecf20Sopenharmony_ci				  MVPP2_ETH_TYPE_LEN,
13658c2ecf20Sopenharmony_ci				  MVPP2_PRS_SRAM_OP_SEL_UDF_ADD);
13668c2ecf20Sopenharmony_ci
13678c2ecf20Sopenharmony_ci	/* Update shadow table and hw entry */
13688c2ecf20Sopenharmony_ci	mvpp2_prs_shadow_set(priv, pe.index, MVPP2_PRS_LU_L2);
13698c2ecf20Sopenharmony_ci	priv->prs_shadow[pe.index].udf = MVPP2_PRS_UDF_L2_DEF;
13708c2ecf20Sopenharmony_ci	priv->prs_shadow[pe.index].finish = true;
13718c2ecf20Sopenharmony_ci	mvpp2_prs_shadow_ri_set(priv, pe.index, MVPP2_PRS_RI_L3_ARP,
13728c2ecf20Sopenharmony_ci				MVPP2_PRS_RI_L3_PROTO_MASK);
13738c2ecf20Sopenharmony_ci	mvpp2_prs_hw_write(priv, &pe);
13748c2ecf20Sopenharmony_ci
13758c2ecf20Sopenharmony_ci	/* Ethertype: LBTD */
13768c2ecf20Sopenharmony_ci	tid = mvpp2_prs_tcam_first_free(priv, MVPP2_PE_FIRST_FREE_TID,
13778c2ecf20Sopenharmony_ci					MVPP2_PE_LAST_FREE_TID);
13788c2ecf20Sopenharmony_ci	if (tid < 0)
13798c2ecf20Sopenharmony_ci		return tid;
13808c2ecf20Sopenharmony_ci
13818c2ecf20Sopenharmony_ci	memset(&pe, 0, sizeof(pe));
13828c2ecf20Sopenharmony_ci	mvpp2_prs_tcam_lu_set(&pe, MVPP2_PRS_LU_L2);
13838c2ecf20Sopenharmony_ci	pe.index = tid;
13848c2ecf20Sopenharmony_ci
13858c2ecf20Sopenharmony_ci	mvpp2_prs_match_etype(&pe, 0, MVPP2_IP_LBDT_TYPE);
13868c2ecf20Sopenharmony_ci
13878c2ecf20Sopenharmony_ci	/* Generate flow in the next iteration*/
13888c2ecf20Sopenharmony_ci	mvpp2_prs_sram_next_lu_set(&pe, MVPP2_PRS_LU_FLOWS);
13898c2ecf20Sopenharmony_ci	mvpp2_prs_sram_bits_set(&pe, MVPP2_PRS_SRAM_LU_GEN_BIT, 1);
13908c2ecf20Sopenharmony_ci	mvpp2_prs_sram_ri_update(&pe, MVPP2_PRS_RI_CPU_CODE_RX_SPEC |
13918c2ecf20Sopenharmony_ci				 MVPP2_PRS_RI_UDF3_RX_SPECIAL,
13928c2ecf20Sopenharmony_ci				 MVPP2_PRS_RI_CPU_CODE_MASK |
13938c2ecf20Sopenharmony_ci				 MVPP2_PRS_RI_UDF3_MASK);
13948c2ecf20Sopenharmony_ci	/* Set L3 offset */
13958c2ecf20Sopenharmony_ci	mvpp2_prs_sram_offset_set(&pe, MVPP2_PRS_SRAM_UDF_TYPE_L3,
13968c2ecf20Sopenharmony_ci				  MVPP2_ETH_TYPE_LEN,
13978c2ecf20Sopenharmony_ci				  MVPP2_PRS_SRAM_OP_SEL_UDF_ADD);
13988c2ecf20Sopenharmony_ci
13998c2ecf20Sopenharmony_ci	/* Update shadow table and hw entry */
14008c2ecf20Sopenharmony_ci	mvpp2_prs_shadow_set(priv, pe.index, MVPP2_PRS_LU_L2);
14018c2ecf20Sopenharmony_ci	priv->prs_shadow[pe.index].udf = MVPP2_PRS_UDF_L2_DEF;
14028c2ecf20Sopenharmony_ci	priv->prs_shadow[pe.index].finish = true;
14038c2ecf20Sopenharmony_ci	mvpp2_prs_shadow_ri_set(priv, pe.index, MVPP2_PRS_RI_CPU_CODE_RX_SPEC |
14048c2ecf20Sopenharmony_ci				MVPP2_PRS_RI_UDF3_RX_SPECIAL,
14058c2ecf20Sopenharmony_ci				MVPP2_PRS_RI_CPU_CODE_MASK |
14068c2ecf20Sopenharmony_ci				MVPP2_PRS_RI_UDF3_MASK);
14078c2ecf20Sopenharmony_ci	mvpp2_prs_hw_write(priv, &pe);
14088c2ecf20Sopenharmony_ci
14098c2ecf20Sopenharmony_ci	/* Ethertype: IPv4 without options */
14108c2ecf20Sopenharmony_ci	tid = mvpp2_prs_tcam_first_free(priv, MVPP2_PE_FIRST_FREE_TID,
14118c2ecf20Sopenharmony_ci					MVPP2_PE_LAST_FREE_TID);
14128c2ecf20Sopenharmony_ci	if (tid < 0)
14138c2ecf20Sopenharmony_ci		return tid;
14148c2ecf20Sopenharmony_ci
14158c2ecf20Sopenharmony_ci	memset(&pe, 0, sizeof(pe));
14168c2ecf20Sopenharmony_ci	mvpp2_prs_tcam_lu_set(&pe, MVPP2_PRS_LU_L2);
14178c2ecf20Sopenharmony_ci	pe.index = tid;
14188c2ecf20Sopenharmony_ci
14198c2ecf20Sopenharmony_ci	mvpp2_prs_match_etype(&pe, 0, ETH_P_IP);
14208c2ecf20Sopenharmony_ci	mvpp2_prs_tcam_data_byte_set(&pe, MVPP2_ETH_TYPE_LEN,
14218c2ecf20Sopenharmony_ci				     MVPP2_PRS_IPV4_HEAD | MVPP2_PRS_IPV4_IHL,
14228c2ecf20Sopenharmony_ci				     MVPP2_PRS_IPV4_HEAD_MASK |
14238c2ecf20Sopenharmony_ci				     MVPP2_PRS_IPV4_IHL_MASK);
14248c2ecf20Sopenharmony_ci
14258c2ecf20Sopenharmony_ci	mvpp2_prs_sram_next_lu_set(&pe, MVPP2_PRS_LU_IP4);
14268c2ecf20Sopenharmony_ci	mvpp2_prs_sram_ri_update(&pe, MVPP2_PRS_RI_L3_IP4,
14278c2ecf20Sopenharmony_ci				 MVPP2_PRS_RI_L3_PROTO_MASK);
14288c2ecf20Sopenharmony_ci	/* Skip eth_type + 4 bytes of IP header */
14298c2ecf20Sopenharmony_ci	mvpp2_prs_sram_shift_set(&pe, MVPP2_ETH_TYPE_LEN + 4,
14308c2ecf20Sopenharmony_ci				 MVPP2_PRS_SRAM_OP_SEL_SHIFT_ADD);
14318c2ecf20Sopenharmony_ci	/* Set L3 offset */
14328c2ecf20Sopenharmony_ci	mvpp2_prs_sram_offset_set(&pe, MVPP2_PRS_SRAM_UDF_TYPE_L3,
14338c2ecf20Sopenharmony_ci				  MVPP2_ETH_TYPE_LEN,
14348c2ecf20Sopenharmony_ci				  MVPP2_PRS_SRAM_OP_SEL_UDF_ADD);
14358c2ecf20Sopenharmony_ci
14368c2ecf20Sopenharmony_ci	/* Update shadow table and hw entry */
14378c2ecf20Sopenharmony_ci	mvpp2_prs_shadow_set(priv, pe.index, MVPP2_PRS_LU_L2);
14388c2ecf20Sopenharmony_ci	priv->prs_shadow[pe.index].udf = MVPP2_PRS_UDF_L2_DEF;
14398c2ecf20Sopenharmony_ci	priv->prs_shadow[pe.index].finish = false;
14408c2ecf20Sopenharmony_ci	mvpp2_prs_shadow_ri_set(priv, pe.index, MVPP2_PRS_RI_L3_IP4,
14418c2ecf20Sopenharmony_ci				MVPP2_PRS_RI_L3_PROTO_MASK);
14428c2ecf20Sopenharmony_ci	mvpp2_prs_hw_write(priv, &pe);
14438c2ecf20Sopenharmony_ci
14448c2ecf20Sopenharmony_ci	/* Ethertype: IPv4 with options */
14458c2ecf20Sopenharmony_ci	tid = mvpp2_prs_tcam_first_free(priv, MVPP2_PE_FIRST_FREE_TID,
14468c2ecf20Sopenharmony_ci					MVPP2_PE_LAST_FREE_TID);
14478c2ecf20Sopenharmony_ci	if (tid < 0)
14488c2ecf20Sopenharmony_ci		return tid;
14498c2ecf20Sopenharmony_ci
14508c2ecf20Sopenharmony_ci	pe.index = tid;
14518c2ecf20Sopenharmony_ci
14528c2ecf20Sopenharmony_ci	mvpp2_prs_tcam_data_byte_set(&pe, MVPP2_ETH_TYPE_LEN,
14538c2ecf20Sopenharmony_ci				     MVPP2_PRS_IPV4_HEAD,
14548c2ecf20Sopenharmony_ci				     MVPP2_PRS_IPV4_HEAD_MASK);
14558c2ecf20Sopenharmony_ci
14568c2ecf20Sopenharmony_ci	/* Clear ri before updating */
14578c2ecf20Sopenharmony_ci	pe.sram[MVPP2_PRS_SRAM_RI_WORD] = 0x0;
14588c2ecf20Sopenharmony_ci	pe.sram[MVPP2_PRS_SRAM_RI_CTRL_WORD] = 0x0;
14598c2ecf20Sopenharmony_ci	mvpp2_prs_sram_ri_update(&pe, MVPP2_PRS_RI_L3_IP4_OPT,
14608c2ecf20Sopenharmony_ci				 MVPP2_PRS_RI_L3_PROTO_MASK);
14618c2ecf20Sopenharmony_ci
14628c2ecf20Sopenharmony_ci	/* Update shadow table and hw entry */
14638c2ecf20Sopenharmony_ci	mvpp2_prs_shadow_set(priv, pe.index, MVPP2_PRS_LU_L2);
14648c2ecf20Sopenharmony_ci	priv->prs_shadow[pe.index].udf = MVPP2_PRS_UDF_L2_DEF;
14658c2ecf20Sopenharmony_ci	priv->prs_shadow[pe.index].finish = false;
14668c2ecf20Sopenharmony_ci	mvpp2_prs_shadow_ri_set(priv, pe.index, MVPP2_PRS_RI_L3_IP4_OPT,
14678c2ecf20Sopenharmony_ci				MVPP2_PRS_RI_L3_PROTO_MASK);
14688c2ecf20Sopenharmony_ci	mvpp2_prs_hw_write(priv, &pe);
14698c2ecf20Sopenharmony_ci
14708c2ecf20Sopenharmony_ci	/* Ethertype: IPv6 without options */
14718c2ecf20Sopenharmony_ci	tid = mvpp2_prs_tcam_first_free(priv, MVPP2_PE_FIRST_FREE_TID,
14728c2ecf20Sopenharmony_ci					MVPP2_PE_LAST_FREE_TID);
14738c2ecf20Sopenharmony_ci	if (tid < 0)
14748c2ecf20Sopenharmony_ci		return tid;
14758c2ecf20Sopenharmony_ci
14768c2ecf20Sopenharmony_ci	memset(&pe, 0, sizeof(pe));
14778c2ecf20Sopenharmony_ci	mvpp2_prs_tcam_lu_set(&pe, MVPP2_PRS_LU_L2);
14788c2ecf20Sopenharmony_ci	pe.index = tid;
14798c2ecf20Sopenharmony_ci
14808c2ecf20Sopenharmony_ci	mvpp2_prs_match_etype(&pe, 0, ETH_P_IPV6);
14818c2ecf20Sopenharmony_ci
14828c2ecf20Sopenharmony_ci	/* Skip DIP of IPV6 header */
14838c2ecf20Sopenharmony_ci	mvpp2_prs_sram_shift_set(&pe, MVPP2_ETH_TYPE_LEN + 8 +
14848c2ecf20Sopenharmony_ci				 MVPP2_MAX_L3_ADDR_SIZE,
14858c2ecf20Sopenharmony_ci				 MVPP2_PRS_SRAM_OP_SEL_SHIFT_ADD);
14868c2ecf20Sopenharmony_ci	mvpp2_prs_sram_next_lu_set(&pe, MVPP2_PRS_LU_IP6);
14878c2ecf20Sopenharmony_ci	mvpp2_prs_sram_ri_update(&pe, MVPP2_PRS_RI_L3_IP6,
14888c2ecf20Sopenharmony_ci				 MVPP2_PRS_RI_L3_PROTO_MASK);
14898c2ecf20Sopenharmony_ci	/* Set L3 offset */
14908c2ecf20Sopenharmony_ci	mvpp2_prs_sram_offset_set(&pe, MVPP2_PRS_SRAM_UDF_TYPE_L3,
14918c2ecf20Sopenharmony_ci				  MVPP2_ETH_TYPE_LEN,
14928c2ecf20Sopenharmony_ci				  MVPP2_PRS_SRAM_OP_SEL_UDF_ADD);
14938c2ecf20Sopenharmony_ci
14948c2ecf20Sopenharmony_ci	mvpp2_prs_shadow_set(priv, pe.index, MVPP2_PRS_LU_L2);
14958c2ecf20Sopenharmony_ci	priv->prs_shadow[pe.index].udf = MVPP2_PRS_UDF_L2_DEF;
14968c2ecf20Sopenharmony_ci	priv->prs_shadow[pe.index].finish = false;
14978c2ecf20Sopenharmony_ci	mvpp2_prs_shadow_ri_set(priv, pe.index, MVPP2_PRS_RI_L3_IP6,
14988c2ecf20Sopenharmony_ci				MVPP2_PRS_RI_L3_PROTO_MASK);
14998c2ecf20Sopenharmony_ci	mvpp2_prs_hw_write(priv, &pe);
15008c2ecf20Sopenharmony_ci
15018c2ecf20Sopenharmony_ci	/* Default entry for MVPP2_PRS_LU_L2 - Unknown ethtype */
15028c2ecf20Sopenharmony_ci	memset(&pe, 0, sizeof(struct mvpp2_prs_entry));
15038c2ecf20Sopenharmony_ci	mvpp2_prs_tcam_lu_set(&pe, MVPP2_PRS_LU_L2);
15048c2ecf20Sopenharmony_ci	pe.index = MVPP2_PE_ETH_TYPE_UN;
15058c2ecf20Sopenharmony_ci
15068c2ecf20Sopenharmony_ci	/* Unmask all ports */
15078c2ecf20Sopenharmony_ci	mvpp2_prs_tcam_port_map_set(&pe, MVPP2_PRS_PORT_MASK);
15088c2ecf20Sopenharmony_ci
15098c2ecf20Sopenharmony_ci	/* Generate flow in the next iteration*/
15108c2ecf20Sopenharmony_ci	mvpp2_prs_sram_bits_set(&pe, MVPP2_PRS_SRAM_LU_GEN_BIT, 1);
15118c2ecf20Sopenharmony_ci	mvpp2_prs_sram_next_lu_set(&pe, MVPP2_PRS_LU_FLOWS);
15128c2ecf20Sopenharmony_ci	mvpp2_prs_sram_ri_update(&pe, MVPP2_PRS_RI_L3_UN,
15138c2ecf20Sopenharmony_ci				 MVPP2_PRS_RI_L3_PROTO_MASK);
15148c2ecf20Sopenharmony_ci	/* Set L3 offset even it's unknown L3 */
15158c2ecf20Sopenharmony_ci	mvpp2_prs_sram_offset_set(&pe, MVPP2_PRS_SRAM_UDF_TYPE_L3,
15168c2ecf20Sopenharmony_ci				  MVPP2_ETH_TYPE_LEN,
15178c2ecf20Sopenharmony_ci				  MVPP2_PRS_SRAM_OP_SEL_UDF_ADD);
15188c2ecf20Sopenharmony_ci
15198c2ecf20Sopenharmony_ci	/* Update shadow table and hw entry */
15208c2ecf20Sopenharmony_ci	mvpp2_prs_shadow_set(priv, pe.index, MVPP2_PRS_LU_L2);
15218c2ecf20Sopenharmony_ci	priv->prs_shadow[pe.index].udf = MVPP2_PRS_UDF_L2_DEF;
15228c2ecf20Sopenharmony_ci	priv->prs_shadow[pe.index].finish = true;
15238c2ecf20Sopenharmony_ci	mvpp2_prs_shadow_ri_set(priv, pe.index, MVPP2_PRS_RI_L3_UN,
15248c2ecf20Sopenharmony_ci				MVPP2_PRS_RI_L3_PROTO_MASK);
15258c2ecf20Sopenharmony_ci	mvpp2_prs_hw_write(priv, &pe);
15268c2ecf20Sopenharmony_ci
15278c2ecf20Sopenharmony_ci	return 0;
15288c2ecf20Sopenharmony_ci}
15298c2ecf20Sopenharmony_ci
15308c2ecf20Sopenharmony_ci/* Configure vlan entries and detect up to 2 successive VLAN tags.
15318c2ecf20Sopenharmony_ci * Possible options:
15328c2ecf20Sopenharmony_ci * 0x8100, 0x88A8
15338c2ecf20Sopenharmony_ci * 0x8100, 0x8100
15348c2ecf20Sopenharmony_ci * 0x8100
15358c2ecf20Sopenharmony_ci * 0x88A8
15368c2ecf20Sopenharmony_ci */
15378c2ecf20Sopenharmony_cistatic int mvpp2_prs_vlan_init(struct platform_device *pdev, struct mvpp2 *priv)
15388c2ecf20Sopenharmony_ci{
15398c2ecf20Sopenharmony_ci	struct mvpp2_prs_entry pe;
15408c2ecf20Sopenharmony_ci	int err;
15418c2ecf20Sopenharmony_ci
15428c2ecf20Sopenharmony_ci	priv->prs_double_vlans = devm_kcalloc(&pdev->dev, sizeof(bool),
15438c2ecf20Sopenharmony_ci					      MVPP2_PRS_DBL_VLANS_MAX,
15448c2ecf20Sopenharmony_ci					      GFP_KERNEL);
15458c2ecf20Sopenharmony_ci	if (!priv->prs_double_vlans)
15468c2ecf20Sopenharmony_ci		return -ENOMEM;
15478c2ecf20Sopenharmony_ci
15488c2ecf20Sopenharmony_ci	/* Double VLAN: 0x8100, 0x88A8 */
15498c2ecf20Sopenharmony_ci	err = mvpp2_prs_double_vlan_add(priv, ETH_P_8021Q, ETH_P_8021AD,
15508c2ecf20Sopenharmony_ci					MVPP2_PRS_PORT_MASK);
15518c2ecf20Sopenharmony_ci	if (err)
15528c2ecf20Sopenharmony_ci		return err;
15538c2ecf20Sopenharmony_ci
15548c2ecf20Sopenharmony_ci	/* Double VLAN: 0x8100, 0x8100 */
15558c2ecf20Sopenharmony_ci	err = mvpp2_prs_double_vlan_add(priv, ETH_P_8021Q, ETH_P_8021Q,
15568c2ecf20Sopenharmony_ci					MVPP2_PRS_PORT_MASK);
15578c2ecf20Sopenharmony_ci	if (err)
15588c2ecf20Sopenharmony_ci		return err;
15598c2ecf20Sopenharmony_ci
15608c2ecf20Sopenharmony_ci	/* Single VLAN: 0x88a8 */
15618c2ecf20Sopenharmony_ci	err = mvpp2_prs_vlan_add(priv, ETH_P_8021AD, MVPP2_PRS_SINGLE_VLAN_AI,
15628c2ecf20Sopenharmony_ci				 MVPP2_PRS_PORT_MASK);
15638c2ecf20Sopenharmony_ci	if (err)
15648c2ecf20Sopenharmony_ci		return err;
15658c2ecf20Sopenharmony_ci
15668c2ecf20Sopenharmony_ci	/* Single VLAN: 0x8100 */
15678c2ecf20Sopenharmony_ci	err = mvpp2_prs_vlan_add(priv, ETH_P_8021Q, MVPP2_PRS_SINGLE_VLAN_AI,
15688c2ecf20Sopenharmony_ci				 MVPP2_PRS_PORT_MASK);
15698c2ecf20Sopenharmony_ci	if (err)
15708c2ecf20Sopenharmony_ci		return err;
15718c2ecf20Sopenharmony_ci
15728c2ecf20Sopenharmony_ci	/* Set default double vlan entry */
15738c2ecf20Sopenharmony_ci	memset(&pe, 0, sizeof(pe));
15748c2ecf20Sopenharmony_ci	mvpp2_prs_tcam_lu_set(&pe, MVPP2_PRS_LU_VLAN);
15758c2ecf20Sopenharmony_ci	pe.index = MVPP2_PE_VLAN_DBL;
15768c2ecf20Sopenharmony_ci
15778c2ecf20Sopenharmony_ci	mvpp2_prs_sram_next_lu_set(&pe, MVPP2_PRS_LU_VID);
15788c2ecf20Sopenharmony_ci
15798c2ecf20Sopenharmony_ci	/* Clear ai for next iterations */
15808c2ecf20Sopenharmony_ci	mvpp2_prs_sram_ai_update(&pe, 0, MVPP2_PRS_SRAM_AI_MASK);
15818c2ecf20Sopenharmony_ci	mvpp2_prs_sram_ri_update(&pe, MVPP2_PRS_RI_VLAN_DOUBLE,
15828c2ecf20Sopenharmony_ci				 MVPP2_PRS_RI_VLAN_MASK);
15838c2ecf20Sopenharmony_ci
15848c2ecf20Sopenharmony_ci	mvpp2_prs_tcam_ai_update(&pe, MVPP2_PRS_DBL_VLAN_AI_BIT,
15858c2ecf20Sopenharmony_ci				 MVPP2_PRS_DBL_VLAN_AI_BIT);
15868c2ecf20Sopenharmony_ci	/* Unmask all ports */
15878c2ecf20Sopenharmony_ci	mvpp2_prs_tcam_port_map_set(&pe, MVPP2_PRS_PORT_MASK);
15888c2ecf20Sopenharmony_ci
15898c2ecf20Sopenharmony_ci	/* Update shadow table and hw entry */
15908c2ecf20Sopenharmony_ci	mvpp2_prs_shadow_set(priv, pe.index, MVPP2_PRS_LU_VLAN);
15918c2ecf20Sopenharmony_ci	mvpp2_prs_hw_write(priv, &pe);
15928c2ecf20Sopenharmony_ci
15938c2ecf20Sopenharmony_ci	/* Set default vlan none entry */
15948c2ecf20Sopenharmony_ci	memset(&pe, 0, sizeof(pe));
15958c2ecf20Sopenharmony_ci	mvpp2_prs_tcam_lu_set(&pe, MVPP2_PRS_LU_VLAN);
15968c2ecf20Sopenharmony_ci	pe.index = MVPP2_PE_VLAN_NONE;
15978c2ecf20Sopenharmony_ci
15988c2ecf20Sopenharmony_ci	mvpp2_prs_sram_next_lu_set(&pe, MVPP2_PRS_LU_L2);
15998c2ecf20Sopenharmony_ci	mvpp2_prs_sram_ri_update(&pe, MVPP2_PRS_RI_VLAN_NONE,
16008c2ecf20Sopenharmony_ci				 MVPP2_PRS_RI_VLAN_MASK);
16018c2ecf20Sopenharmony_ci
16028c2ecf20Sopenharmony_ci	/* Unmask all ports */
16038c2ecf20Sopenharmony_ci	mvpp2_prs_tcam_port_map_set(&pe, MVPP2_PRS_PORT_MASK);
16048c2ecf20Sopenharmony_ci
16058c2ecf20Sopenharmony_ci	/* Update shadow table and hw entry */
16068c2ecf20Sopenharmony_ci	mvpp2_prs_shadow_set(priv, pe.index, MVPP2_PRS_LU_VLAN);
16078c2ecf20Sopenharmony_ci	mvpp2_prs_hw_write(priv, &pe);
16088c2ecf20Sopenharmony_ci
16098c2ecf20Sopenharmony_ci	return 0;
16108c2ecf20Sopenharmony_ci}
16118c2ecf20Sopenharmony_ci
16128c2ecf20Sopenharmony_ci/* Set entries for PPPoE ethertype */
16138c2ecf20Sopenharmony_cistatic int mvpp2_prs_pppoe_init(struct mvpp2 *priv)
16148c2ecf20Sopenharmony_ci{
16158c2ecf20Sopenharmony_ci	struct mvpp2_prs_entry pe;
16168c2ecf20Sopenharmony_ci	int tid;
16178c2ecf20Sopenharmony_ci
16188c2ecf20Sopenharmony_ci	/* IPv4 over PPPoE with options */
16198c2ecf20Sopenharmony_ci	tid = mvpp2_prs_tcam_first_free(priv, MVPP2_PE_FIRST_FREE_TID,
16208c2ecf20Sopenharmony_ci					MVPP2_PE_LAST_FREE_TID);
16218c2ecf20Sopenharmony_ci	if (tid < 0)
16228c2ecf20Sopenharmony_ci		return tid;
16238c2ecf20Sopenharmony_ci
16248c2ecf20Sopenharmony_ci	memset(&pe, 0, sizeof(pe));
16258c2ecf20Sopenharmony_ci	mvpp2_prs_tcam_lu_set(&pe, MVPP2_PRS_LU_PPPOE);
16268c2ecf20Sopenharmony_ci	pe.index = tid;
16278c2ecf20Sopenharmony_ci
16288c2ecf20Sopenharmony_ci	mvpp2_prs_match_etype(&pe, 0, PPP_IP);
16298c2ecf20Sopenharmony_ci
16308c2ecf20Sopenharmony_ci	mvpp2_prs_sram_next_lu_set(&pe, MVPP2_PRS_LU_IP4);
16318c2ecf20Sopenharmony_ci	mvpp2_prs_sram_ri_update(&pe, MVPP2_PRS_RI_L3_IP4_OPT,
16328c2ecf20Sopenharmony_ci				 MVPP2_PRS_RI_L3_PROTO_MASK);
16338c2ecf20Sopenharmony_ci	/* Skip eth_type + 4 bytes of IP header */
16348c2ecf20Sopenharmony_ci	mvpp2_prs_sram_shift_set(&pe, MVPP2_ETH_TYPE_LEN + 4,
16358c2ecf20Sopenharmony_ci				 MVPP2_PRS_SRAM_OP_SEL_SHIFT_ADD);
16368c2ecf20Sopenharmony_ci	/* Set L3 offset */
16378c2ecf20Sopenharmony_ci	mvpp2_prs_sram_offset_set(&pe, MVPP2_PRS_SRAM_UDF_TYPE_L3,
16388c2ecf20Sopenharmony_ci				  MVPP2_ETH_TYPE_LEN,
16398c2ecf20Sopenharmony_ci				  MVPP2_PRS_SRAM_OP_SEL_UDF_ADD);
16408c2ecf20Sopenharmony_ci
16418c2ecf20Sopenharmony_ci	/* Update shadow table and hw entry */
16428c2ecf20Sopenharmony_ci	mvpp2_prs_shadow_set(priv, pe.index, MVPP2_PRS_LU_PPPOE);
16438c2ecf20Sopenharmony_ci	mvpp2_prs_hw_write(priv, &pe);
16448c2ecf20Sopenharmony_ci
16458c2ecf20Sopenharmony_ci	/* IPv4 over PPPoE without options */
16468c2ecf20Sopenharmony_ci	tid = mvpp2_prs_tcam_first_free(priv, MVPP2_PE_FIRST_FREE_TID,
16478c2ecf20Sopenharmony_ci					MVPP2_PE_LAST_FREE_TID);
16488c2ecf20Sopenharmony_ci	if (tid < 0)
16498c2ecf20Sopenharmony_ci		return tid;
16508c2ecf20Sopenharmony_ci
16518c2ecf20Sopenharmony_ci	pe.index = tid;
16528c2ecf20Sopenharmony_ci
16538c2ecf20Sopenharmony_ci	mvpp2_prs_tcam_data_byte_set(&pe, MVPP2_ETH_TYPE_LEN,
16548c2ecf20Sopenharmony_ci				     MVPP2_PRS_IPV4_HEAD | MVPP2_PRS_IPV4_IHL,
16558c2ecf20Sopenharmony_ci				     MVPP2_PRS_IPV4_HEAD_MASK |
16568c2ecf20Sopenharmony_ci				     MVPP2_PRS_IPV4_IHL_MASK);
16578c2ecf20Sopenharmony_ci
16588c2ecf20Sopenharmony_ci	/* Clear ri before updating */
16598c2ecf20Sopenharmony_ci	pe.sram[MVPP2_PRS_SRAM_RI_WORD] = 0x0;
16608c2ecf20Sopenharmony_ci	pe.sram[MVPP2_PRS_SRAM_RI_CTRL_WORD] = 0x0;
16618c2ecf20Sopenharmony_ci	mvpp2_prs_sram_ri_update(&pe, MVPP2_PRS_RI_L3_IP4,
16628c2ecf20Sopenharmony_ci				 MVPP2_PRS_RI_L3_PROTO_MASK);
16638c2ecf20Sopenharmony_ci
16648c2ecf20Sopenharmony_ci	/* Update shadow table and hw entry */
16658c2ecf20Sopenharmony_ci	mvpp2_prs_shadow_set(priv, pe.index, MVPP2_PRS_LU_PPPOE);
16668c2ecf20Sopenharmony_ci	mvpp2_prs_hw_write(priv, &pe);
16678c2ecf20Sopenharmony_ci
16688c2ecf20Sopenharmony_ci	/* IPv6 over PPPoE */
16698c2ecf20Sopenharmony_ci	tid = mvpp2_prs_tcam_first_free(priv, MVPP2_PE_FIRST_FREE_TID,
16708c2ecf20Sopenharmony_ci					MVPP2_PE_LAST_FREE_TID);
16718c2ecf20Sopenharmony_ci	if (tid < 0)
16728c2ecf20Sopenharmony_ci		return tid;
16738c2ecf20Sopenharmony_ci
16748c2ecf20Sopenharmony_ci	memset(&pe, 0, sizeof(pe));
16758c2ecf20Sopenharmony_ci	mvpp2_prs_tcam_lu_set(&pe, MVPP2_PRS_LU_PPPOE);
16768c2ecf20Sopenharmony_ci	pe.index = tid;
16778c2ecf20Sopenharmony_ci
16788c2ecf20Sopenharmony_ci	mvpp2_prs_match_etype(&pe, 0, PPP_IPV6);
16798c2ecf20Sopenharmony_ci
16808c2ecf20Sopenharmony_ci	mvpp2_prs_sram_next_lu_set(&pe, MVPP2_PRS_LU_IP6);
16818c2ecf20Sopenharmony_ci	mvpp2_prs_sram_ri_update(&pe, MVPP2_PRS_RI_L3_IP6,
16828c2ecf20Sopenharmony_ci				 MVPP2_PRS_RI_L3_PROTO_MASK);
16838c2ecf20Sopenharmony_ci	/* Jump to DIP of IPV6 header */
16848c2ecf20Sopenharmony_ci	mvpp2_prs_sram_shift_set(&pe, MVPP2_ETH_TYPE_LEN + 8 +
16858c2ecf20Sopenharmony_ci				 MVPP2_MAX_L3_ADDR_SIZE,
16868c2ecf20Sopenharmony_ci				 MVPP2_PRS_SRAM_OP_SEL_SHIFT_ADD);
16878c2ecf20Sopenharmony_ci	/* Set L3 offset */
16888c2ecf20Sopenharmony_ci	mvpp2_prs_sram_offset_set(&pe, MVPP2_PRS_SRAM_UDF_TYPE_L3,
16898c2ecf20Sopenharmony_ci				  MVPP2_ETH_TYPE_LEN,
16908c2ecf20Sopenharmony_ci				  MVPP2_PRS_SRAM_OP_SEL_UDF_ADD);
16918c2ecf20Sopenharmony_ci
16928c2ecf20Sopenharmony_ci	/* Update shadow table and hw entry */
16938c2ecf20Sopenharmony_ci	mvpp2_prs_shadow_set(priv, pe.index, MVPP2_PRS_LU_PPPOE);
16948c2ecf20Sopenharmony_ci	mvpp2_prs_hw_write(priv, &pe);
16958c2ecf20Sopenharmony_ci
16968c2ecf20Sopenharmony_ci	/* Non-IP over PPPoE */
16978c2ecf20Sopenharmony_ci	tid = mvpp2_prs_tcam_first_free(priv, MVPP2_PE_FIRST_FREE_TID,
16988c2ecf20Sopenharmony_ci					MVPP2_PE_LAST_FREE_TID);
16998c2ecf20Sopenharmony_ci	if (tid < 0)
17008c2ecf20Sopenharmony_ci		return tid;
17018c2ecf20Sopenharmony_ci
17028c2ecf20Sopenharmony_ci	memset(&pe, 0, sizeof(pe));
17038c2ecf20Sopenharmony_ci	mvpp2_prs_tcam_lu_set(&pe, MVPP2_PRS_LU_PPPOE);
17048c2ecf20Sopenharmony_ci	pe.index = tid;
17058c2ecf20Sopenharmony_ci
17068c2ecf20Sopenharmony_ci	mvpp2_prs_sram_ri_update(&pe, MVPP2_PRS_RI_L3_UN,
17078c2ecf20Sopenharmony_ci				 MVPP2_PRS_RI_L3_PROTO_MASK);
17088c2ecf20Sopenharmony_ci
17098c2ecf20Sopenharmony_ci	/* Finished: go to flowid generation */
17108c2ecf20Sopenharmony_ci	mvpp2_prs_sram_next_lu_set(&pe, MVPP2_PRS_LU_FLOWS);
17118c2ecf20Sopenharmony_ci	mvpp2_prs_sram_bits_set(&pe, MVPP2_PRS_SRAM_LU_GEN_BIT, 1);
17128c2ecf20Sopenharmony_ci	/* Set L3 offset even if it's unknown L3 */
17138c2ecf20Sopenharmony_ci	mvpp2_prs_sram_offset_set(&pe, MVPP2_PRS_SRAM_UDF_TYPE_L3,
17148c2ecf20Sopenharmony_ci				  MVPP2_ETH_TYPE_LEN,
17158c2ecf20Sopenharmony_ci				  MVPP2_PRS_SRAM_OP_SEL_UDF_ADD);
17168c2ecf20Sopenharmony_ci
17178c2ecf20Sopenharmony_ci	/* Update shadow table and hw entry */
17188c2ecf20Sopenharmony_ci	mvpp2_prs_shadow_set(priv, pe.index, MVPP2_PRS_LU_PPPOE);
17198c2ecf20Sopenharmony_ci	mvpp2_prs_hw_write(priv, &pe);
17208c2ecf20Sopenharmony_ci
17218c2ecf20Sopenharmony_ci	return 0;
17228c2ecf20Sopenharmony_ci}
17238c2ecf20Sopenharmony_ci
17248c2ecf20Sopenharmony_ci/* Initialize entries for IPv4 */
17258c2ecf20Sopenharmony_cistatic int mvpp2_prs_ip4_init(struct mvpp2 *priv)
17268c2ecf20Sopenharmony_ci{
17278c2ecf20Sopenharmony_ci	struct mvpp2_prs_entry pe;
17288c2ecf20Sopenharmony_ci	int err;
17298c2ecf20Sopenharmony_ci
17308c2ecf20Sopenharmony_ci	/* Set entries for TCP, UDP and IGMP over IPv4 */
17318c2ecf20Sopenharmony_ci	err = mvpp2_prs_ip4_proto(priv, IPPROTO_TCP, MVPP2_PRS_RI_L4_TCP,
17328c2ecf20Sopenharmony_ci				  MVPP2_PRS_RI_L4_PROTO_MASK);
17338c2ecf20Sopenharmony_ci	if (err)
17348c2ecf20Sopenharmony_ci		return err;
17358c2ecf20Sopenharmony_ci
17368c2ecf20Sopenharmony_ci	err = mvpp2_prs_ip4_proto(priv, IPPROTO_UDP, MVPP2_PRS_RI_L4_UDP,
17378c2ecf20Sopenharmony_ci				  MVPP2_PRS_RI_L4_PROTO_MASK);
17388c2ecf20Sopenharmony_ci	if (err)
17398c2ecf20Sopenharmony_ci		return err;
17408c2ecf20Sopenharmony_ci
17418c2ecf20Sopenharmony_ci	err = mvpp2_prs_ip4_proto(priv, IPPROTO_IGMP,
17428c2ecf20Sopenharmony_ci				  MVPP2_PRS_RI_CPU_CODE_RX_SPEC |
17438c2ecf20Sopenharmony_ci				  MVPP2_PRS_RI_UDF3_RX_SPECIAL,
17448c2ecf20Sopenharmony_ci				  MVPP2_PRS_RI_CPU_CODE_MASK |
17458c2ecf20Sopenharmony_ci				  MVPP2_PRS_RI_UDF3_MASK);
17468c2ecf20Sopenharmony_ci	if (err)
17478c2ecf20Sopenharmony_ci		return err;
17488c2ecf20Sopenharmony_ci
17498c2ecf20Sopenharmony_ci	/* IPv4 Broadcast */
17508c2ecf20Sopenharmony_ci	err = mvpp2_prs_ip4_cast(priv, MVPP2_PRS_L3_BROAD_CAST);
17518c2ecf20Sopenharmony_ci	if (err)
17528c2ecf20Sopenharmony_ci		return err;
17538c2ecf20Sopenharmony_ci
17548c2ecf20Sopenharmony_ci	/* IPv4 Multicast */
17558c2ecf20Sopenharmony_ci	err = mvpp2_prs_ip4_cast(priv, MVPP2_PRS_L3_MULTI_CAST);
17568c2ecf20Sopenharmony_ci	if (err)
17578c2ecf20Sopenharmony_ci		return err;
17588c2ecf20Sopenharmony_ci
17598c2ecf20Sopenharmony_ci	/* Default IPv4 entry for unknown protocols */
17608c2ecf20Sopenharmony_ci	memset(&pe, 0, sizeof(pe));
17618c2ecf20Sopenharmony_ci	mvpp2_prs_tcam_lu_set(&pe, MVPP2_PRS_LU_IP4);
17628c2ecf20Sopenharmony_ci	pe.index = MVPP2_PE_IP4_PROTO_UN;
17638c2ecf20Sopenharmony_ci
17648c2ecf20Sopenharmony_ci	/* Set next lu to IPv4 */
17658c2ecf20Sopenharmony_ci	mvpp2_prs_sram_next_lu_set(&pe, MVPP2_PRS_LU_IP4);
17668c2ecf20Sopenharmony_ci	mvpp2_prs_sram_shift_set(&pe, 12, MVPP2_PRS_SRAM_OP_SEL_SHIFT_ADD);
17678c2ecf20Sopenharmony_ci	/* Set L4 offset */
17688c2ecf20Sopenharmony_ci	mvpp2_prs_sram_offset_set(&pe, MVPP2_PRS_SRAM_UDF_TYPE_L4,
17698c2ecf20Sopenharmony_ci				  sizeof(struct iphdr) - 4,
17708c2ecf20Sopenharmony_ci				  MVPP2_PRS_SRAM_OP_SEL_UDF_ADD);
17718c2ecf20Sopenharmony_ci	mvpp2_prs_sram_ai_update(&pe, MVPP2_PRS_IPV4_DIP_AI_BIT,
17728c2ecf20Sopenharmony_ci				 MVPP2_PRS_IPV4_DIP_AI_BIT);
17738c2ecf20Sopenharmony_ci	mvpp2_prs_sram_ri_update(&pe, MVPP2_PRS_RI_L4_OTHER,
17748c2ecf20Sopenharmony_ci				 MVPP2_PRS_RI_L4_PROTO_MASK);
17758c2ecf20Sopenharmony_ci
17768c2ecf20Sopenharmony_ci	mvpp2_prs_tcam_ai_update(&pe, 0, MVPP2_PRS_IPV4_DIP_AI_BIT);
17778c2ecf20Sopenharmony_ci	/* Unmask all ports */
17788c2ecf20Sopenharmony_ci	mvpp2_prs_tcam_port_map_set(&pe, MVPP2_PRS_PORT_MASK);
17798c2ecf20Sopenharmony_ci
17808c2ecf20Sopenharmony_ci	/* Update shadow table and hw entry */
17818c2ecf20Sopenharmony_ci	mvpp2_prs_shadow_set(priv, pe.index, MVPP2_PRS_LU_IP4);
17828c2ecf20Sopenharmony_ci	mvpp2_prs_hw_write(priv, &pe);
17838c2ecf20Sopenharmony_ci
17848c2ecf20Sopenharmony_ci	/* Default IPv4 entry for unicast address */
17858c2ecf20Sopenharmony_ci	memset(&pe, 0, sizeof(pe));
17868c2ecf20Sopenharmony_ci	mvpp2_prs_tcam_lu_set(&pe, MVPP2_PRS_LU_IP4);
17878c2ecf20Sopenharmony_ci	pe.index = MVPP2_PE_IP4_ADDR_UN;
17888c2ecf20Sopenharmony_ci
17898c2ecf20Sopenharmony_ci	/* Finished: go to flowid generation */
17908c2ecf20Sopenharmony_ci	mvpp2_prs_sram_next_lu_set(&pe, MVPP2_PRS_LU_FLOWS);
17918c2ecf20Sopenharmony_ci	mvpp2_prs_sram_bits_set(&pe, MVPP2_PRS_SRAM_LU_GEN_BIT, 1);
17928c2ecf20Sopenharmony_ci	mvpp2_prs_sram_ri_update(&pe, MVPP2_PRS_RI_L3_UCAST,
17938c2ecf20Sopenharmony_ci				 MVPP2_PRS_RI_L3_ADDR_MASK);
17948c2ecf20Sopenharmony_ci
17958c2ecf20Sopenharmony_ci	mvpp2_prs_tcam_ai_update(&pe, MVPP2_PRS_IPV4_DIP_AI_BIT,
17968c2ecf20Sopenharmony_ci				 MVPP2_PRS_IPV4_DIP_AI_BIT);
17978c2ecf20Sopenharmony_ci	/* Unmask all ports */
17988c2ecf20Sopenharmony_ci	mvpp2_prs_tcam_port_map_set(&pe, MVPP2_PRS_PORT_MASK);
17998c2ecf20Sopenharmony_ci
18008c2ecf20Sopenharmony_ci	/* Update shadow table and hw entry */
18018c2ecf20Sopenharmony_ci	mvpp2_prs_shadow_set(priv, pe.index, MVPP2_PRS_LU_IP4);
18028c2ecf20Sopenharmony_ci	mvpp2_prs_hw_write(priv, &pe);
18038c2ecf20Sopenharmony_ci
18048c2ecf20Sopenharmony_ci	return 0;
18058c2ecf20Sopenharmony_ci}
18068c2ecf20Sopenharmony_ci
18078c2ecf20Sopenharmony_ci/* Initialize entries for IPv6 */
18088c2ecf20Sopenharmony_cistatic int mvpp2_prs_ip6_init(struct mvpp2 *priv)
18098c2ecf20Sopenharmony_ci{
18108c2ecf20Sopenharmony_ci	struct mvpp2_prs_entry pe;
18118c2ecf20Sopenharmony_ci	int tid, err;
18128c2ecf20Sopenharmony_ci
18138c2ecf20Sopenharmony_ci	/* Set entries for TCP, UDP and ICMP over IPv6 */
18148c2ecf20Sopenharmony_ci	err = mvpp2_prs_ip6_proto(priv, IPPROTO_TCP,
18158c2ecf20Sopenharmony_ci				  MVPP2_PRS_RI_L4_TCP,
18168c2ecf20Sopenharmony_ci				  MVPP2_PRS_RI_L4_PROTO_MASK);
18178c2ecf20Sopenharmony_ci	if (err)
18188c2ecf20Sopenharmony_ci		return err;
18198c2ecf20Sopenharmony_ci
18208c2ecf20Sopenharmony_ci	err = mvpp2_prs_ip6_proto(priv, IPPROTO_UDP,
18218c2ecf20Sopenharmony_ci				  MVPP2_PRS_RI_L4_UDP,
18228c2ecf20Sopenharmony_ci				  MVPP2_PRS_RI_L4_PROTO_MASK);
18238c2ecf20Sopenharmony_ci	if (err)
18248c2ecf20Sopenharmony_ci		return err;
18258c2ecf20Sopenharmony_ci
18268c2ecf20Sopenharmony_ci	err = mvpp2_prs_ip6_proto(priv, IPPROTO_ICMPV6,
18278c2ecf20Sopenharmony_ci				  MVPP2_PRS_RI_CPU_CODE_RX_SPEC |
18288c2ecf20Sopenharmony_ci				  MVPP2_PRS_RI_UDF3_RX_SPECIAL,
18298c2ecf20Sopenharmony_ci				  MVPP2_PRS_RI_CPU_CODE_MASK |
18308c2ecf20Sopenharmony_ci				  MVPP2_PRS_RI_UDF3_MASK);
18318c2ecf20Sopenharmony_ci	if (err)
18328c2ecf20Sopenharmony_ci		return err;
18338c2ecf20Sopenharmony_ci
18348c2ecf20Sopenharmony_ci	/* IPv4 is the last header. This is similar case as 6-TCP or 17-UDP */
18358c2ecf20Sopenharmony_ci	/* Result Info: UDF7=1, DS lite */
18368c2ecf20Sopenharmony_ci	err = mvpp2_prs_ip6_proto(priv, IPPROTO_IPIP,
18378c2ecf20Sopenharmony_ci				  MVPP2_PRS_RI_UDF7_IP6_LITE,
18388c2ecf20Sopenharmony_ci				  MVPP2_PRS_RI_UDF7_MASK);
18398c2ecf20Sopenharmony_ci	if (err)
18408c2ecf20Sopenharmony_ci		return err;
18418c2ecf20Sopenharmony_ci
18428c2ecf20Sopenharmony_ci	/* IPv6 multicast */
18438c2ecf20Sopenharmony_ci	err = mvpp2_prs_ip6_cast(priv, MVPP2_PRS_L3_MULTI_CAST);
18448c2ecf20Sopenharmony_ci	if (err)
18458c2ecf20Sopenharmony_ci		return err;
18468c2ecf20Sopenharmony_ci
18478c2ecf20Sopenharmony_ci	/* Entry for checking hop limit */
18488c2ecf20Sopenharmony_ci	tid = mvpp2_prs_tcam_first_free(priv, MVPP2_PE_FIRST_FREE_TID,
18498c2ecf20Sopenharmony_ci					MVPP2_PE_LAST_FREE_TID);
18508c2ecf20Sopenharmony_ci	if (tid < 0)
18518c2ecf20Sopenharmony_ci		return tid;
18528c2ecf20Sopenharmony_ci
18538c2ecf20Sopenharmony_ci	memset(&pe, 0, sizeof(pe));
18548c2ecf20Sopenharmony_ci	mvpp2_prs_tcam_lu_set(&pe, MVPP2_PRS_LU_IP6);
18558c2ecf20Sopenharmony_ci	pe.index = tid;
18568c2ecf20Sopenharmony_ci
18578c2ecf20Sopenharmony_ci	/* Finished: go to flowid generation */
18588c2ecf20Sopenharmony_ci	mvpp2_prs_sram_next_lu_set(&pe, MVPP2_PRS_LU_FLOWS);
18598c2ecf20Sopenharmony_ci	mvpp2_prs_sram_bits_set(&pe, MVPP2_PRS_SRAM_LU_GEN_BIT, 1);
18608c2ecf20Sopenharmony_ci	mvpp2_prs_sram_ri_update(&pe, MVPP2_PRS_RI_L3_UN |
18618c2ecf20Sopenharmony_ci				 MVPP2_PRS_RI_DROP_MASK,
18628c2ecf20Sopenharmony_ci				 MVPP2_PRS_RI_L3_PROTO_MASK |
18638c2ecf20Sopenharmony_ci				 MVPP2_PRS_RI_DROP_MASK);
18648c2ecf20Sopenharmony_ci
18658c2ecf20Sopenharmony_ci	mvpp2_prs_tcam_data_byte_set(&pe, 1, 0x00, MVPP2_PRS_IPV6_HOP_MASK);
18668c2ecf20Sopenharmony_ci	mvpp2_prs_tcam_ai_update(&pe, MVPP2_PRS_IPV6_NO_EXT_AI_BIT,
18678c2ecf20Sopenharmony_ci				 MVPP2_PRS_IPV6_NO_EXT_AI_BIT);
18688c2ecf20Sopenharmony_ci
18698c2ecf20Sopenharmony_ci	/* Update shadow table and hw entry */
18708c2ecf20Sopenharmony_ci	mvpp2_prs_shadow_set(priv, pe.index, MVPP2_PRS_LU_IP4);
18718c2ecf20Sopenharmony_ci	mvpp2_prs_hw_write(priv, &pe);
18728c2ecf20Sopenharmony_ci
18738c2ecf20Sopenharmony_ci	/* Default IPv6 entry for unknown protocols */
18748c2ecf20Sopenharmony_ci	memset(&pe, 0, sizeof(pe));
18758c2ecf20Sopenharmony_ci	mvpp2_prs_tcam_lu_set(&pe, MVPP2_PRS_LU_IP6);
18768c2ecf20Sopenharmony_ci	pe.index = MVPP2_PE_IP6_PROTO_UN;
18778c2ecf20Sopenharmony_ci
18788c2ecf20Sopenharmony_ci	/* Finished: go to flowid generation */
18798c2ecf20Sopenharmony_ci	mvpp2_prs_sram_next_lu_set(&pe, MVPP2_PRS_LU_FLOWS);
18808c2ecf20Sopenharmony_ci	mvpp2_prs_sram_bits_set(&pe, MVPP2_PRS_SRAM_LU_GEN_BIT, 1);
18818c2ecf20Sopenharmony_ci	mvpp2_prs_sram_ri_update(&pe, MVPP2_PRS_RI_L4_OTHER,
18828c2ecf20Sopenharmony_ci				 MVPP2_PRS_RI_L4_PROTO_MASK);
18838c2ecf20Sopenharmony_ci	/* Set L4 offset relatively to our current place */
18848c2ecf20Sopenharmony_ci	mvpp2_prs_sram_offset_set(&pe, MVPP2_PRS_SRAM_UDF_TYPE_L4,
18858c2ecf20Sopenharmony_ci				  sizeof(struct ipv6hdr) - 4,
18868c2ecf20Sopenharmony_ci				  MVPP2_PRS_SRAM_OP_SEL_UDF_ADD);
18878c2ecf20Sopenharmony_ci
18888c2ecf20Sopenharmony_ci	mvpp2_prs_tcam_ai_update(&pe, MVPP2_PRS_IPV6_NO_EXT_AI_BIT,
18898c2ecf20Sopenharmony_ci				 MVPP2_PRS_IPV6_NO_EXT_AI_BIT);
18908c2ecf20Sopenharmony_ci	/* Unmask all ports */
18918c2ecf20Sopenharmony_ci	mvpp2_prs_tcam_port_map_set(&pe, MVPP2_PRS_PORT_MASK);
18928c2ecf20Sopenharmony_ci
18938c2ecf20Sopenharmony_ci	/* Update shadow table and hw entry */
18948c2ecf20Sopenharmony_ci	mvpp2_prs_shadow_set(priv, pe.index, MVPP2_PRS_LU_IP4);
18958c2ecf20Sopenharmony_ci	mvpp2_prs_hw_write(priv, &pe);
18968c2ecf20Sopenharmony_ci
18978c2ecf20Sopenharmony_ci	/* Default IPv6 entry for unknown ext protocols */
18988c2ecf20Sopenharmony_ci	memset(&pe, 0, sizeof(struct mvpp2_prs_entry));
18998c2ecf20Sopenharmony_ci	mvpp2_prs_tcam_lu_set(&pe, MVPP2_PRS_LU_IP6);
19008c2ecf20Sopenharmony_ci	pe.index = MVPP2_PE_IP6_EXT_PROTO_UN;
19018c2ecf20Sopenharmony_ci
19028c2ecf20Sopenharmony_ci	/* Finished: go to flowid generation */
19038c2ecf20Sopenharmony_ci	mvpp2_prs_sram_next_lu_set(&pe, MVPP2_PRS_LU_FLOWS);
19048c2ecf20Sopenharmony_ci	mvpp2_prs_sram_bits_set(&pe, MVPP2_PRS_SRAM_LU_GEN_BIT, 1);
19058c2ecf20Sopenharmony_ci	mvpp2_prs_sram_ri_update(&pe, MVPP2_PRS_RI_L4_OTHER,
19068c2ecf20Sopenharmony_ci				 MVPP2_PRS_RI_L4_PROTO_MASK);
19078c2ecf20Sopenharmony_ci
19088c2ecf20Sopenharmony_ci	mvpp2_prs_tcam_ai_update(&pe, MVPP2_PRS_IPV6_EXT_AI_BIT,
19098c2ecf20Sopenharmony_ci				 MVPP2_PRS_IPV6_EXT_AI_BIT);
19108c2ecf20Sopenharmony_ci	/* Unmask all ports */
19118c2ecf20Sopenharmony_ci	mvpp2_prs_tcam_port_map_set(&pe, MVPP2_PRS_PORT_MASK);
19128c2ecf20Sopenharmony_ci
19138c2ecf20Sopenharmony_ci	/* Update shadow table and hw entry */
19148c2ecf20Sopenharmony_ci	mvpp2_prs_shadow_set(priv, pe.index, MVPP2_PRS_LU_IP4);
19158c2ecf20Sopenharmony_ci	mvpp2_prs_hw_write(priv, &pe);
19168c2ecf20Sopenharmony_ci
19178c2ecf20Sopenharmony_ci	/* Default IPv6 entry for unicast address */
19188c2ecf20Sopenharmony_ci	memset(&pe, 0, sizeof(struct mvpp2_prs_entry));
19198c2ecf20Sopenharmony_ci	mvpp2_prs_tcam_lu_set(&pe, MVPP2_PRS_LU_IP6);
19208c2ecf20Sopenharmony_ci	pe.index = MVPP2_PE_IP6_ADDR_UN;
19218c2ecf20Sopenharmony_ci
19228c2ecf20Sopenharmony_ci	/* Finished: go to IPv6 again */
19238c2ecf20Sopenharmony_ci	mvpp2_prs_sram_next_lu_set(&pe, MVPP2_PRS_LU_IP6);
19248c2ecf20Sopenharmony_ci	mvpp2_prs_sram_ri_update(&pe, MVPP2_PRS_RI_L3_UCAST,
19258c2ecf20Sopenharmony_ci				 MVPP2_PRS_RI_L3_ADDR_MASK);
19268c2ecf20Sopenharmony_ci	mvpp2_prs_sram_ai_update(&pe, MVPP2_PRS_IPV6_NO_EXT_AI_BIT,
19278c2ecf20Sopenharmony_ci				 MVPP2_PRS_IPV6_NO_EXT_AI_BIT);
19288c2ecf20Sopenharmony_ci	/* Shift back to IPV6 NH */
19298c2ecf20Sopenharmony_ci	mvpp2_prs_sram_shift_set(&pe, -18, MVPP2_PRS_SRAM_OP_SEL_SHIFT_ADD);
19308c2ecf20Sopenharmony_ci
19318c2ecf20Sopenharmony_ci	mvpp2_prs_tcam_ai_update(&pe, 0, MVPP2_PRS_IPV6_NO_EXT_AI_BIT);
19328c2ecf20Sopenharmony_ci	/* Unmask all ports */
19338c2ecf20Sopenharmony_ci	mvpp2_prs_tcam_port_map_set(&pe, MVPP2_PRS_PORT_MASK);
19348c2ecf20Sopenharmony_ci
19358c2ecf20Sopenharmony_ci	/* Update shadow table and hw entry */
19368c2ecf20Sopenharmony_ci	mvpp2_prs_shadow_set(priv, pe.index, MVPP2_PRS_LU_IP6);
19378c2ecf20Sopenharmony_ci	mvpp2_prs_hw_write(priv, &pe);
19388c2ecf20Sopenharmony_ci
19398c2ecf20Sopenharmony_ci	return 0;
19408c2ecf20Sopenharmony_ci}
19418c2ecf20Sopenharmony_ci
19428c2ecf20Sopenharmony_ci/* Find tcam entry with matched pair <vid,port> */
19438c2ecf20Sopenharmony_cistatic int mvpp2_prs_vid_range_find(struct mvpp2_port *port, u16 vid, u16 mask)
19448c2ecf20Sopenharmony_ci{
19458c2ecf20Sopenharmony_ci	unsigned char byte[2], enable[2];
19468c2ecf20Sopenharmony_ci	struct mvpp2_prs_entry pe;
19478c2ecf20Sopenharmony_ci	u16 rvid, rmask;
19488c2ecf20Sopenharmony_ci	int tid;
19498c2ecf20Sopenharmony_ci
19508c2ecf20Sopenharmony_ci	/* Go through the all entries with MVPP2_PRS_LU_VID */
19518c2ecf20Sopenharmony_ci	for (tid = MVPP2_PRS_VID_PORT_FIRST(port->id);
19528c2ecf20Sopenharmony_ci	     tid <= MVPP2_PRS_VID_PORT_LAST(port->id); tid++) {
19538c2ecf20Sopenharmony_ci		if (!port->priv->prs_shadow[tid].valid ||
19548c2ecf20Sopenharmony_ci		    port->priv->prs_shadow[tid].lu != MVPP2_PRS_LU_VID)
19558c2ecf20Sopenharmony_ci			continue;
19568c2ecf20Sopenharmony_ci
19578c2ecf20Sopenharmony_ci		mvpp2_prs_init_from_hw(port->priv, &pe, tid);
19588c2ecf20Sopenharmony_ci
19598c2ecf20Sopenharmony_ci		mvpp2_prs_tcam_data_byte_get(&pe, 2, &byte[0], &enable[0]);
19608c2ecf20Sopenharmony_ci		mvpp2_prs_tcam_data_byte_get(&pe, 3, &byte[1], &enable[1]);
19618c2ecf20Sopenharmony_ci
19628c2ecf20Sopenharmony_ci		rvid = ((byte[0] & 0xf) << 8) + byte[1];
19638c2ecf20Sopenharmony_ci		rmask = ((enable[0] & 0xf) << 8) + enable[1];
19648c2ecf20Sopenharmony_ci
19658c2ecf20Sopenharmony_ci		if (rvid != vid || rmask != mask)
19668c2ecf20Sopenharmony_ci			continue;
19678c2ecf20Sopenharmony_ci
19688c2ecf20Sopenharmony_ci		return tid;
19698c2ecf20Sopenharmony_ci	}
19708c2ecf20Sopenharmony_ci
19718c2ecf20Sopenharmony_ci	return -ENOENT;
19728c2ecf20Sopenharmony_ci}
19738c2ecf20Sopenharmony_ci
19748c2ecf20Sopenharmony_ci/* Write parser entry for VID filtering */
19758c2ecf20Sopenharmony_ciint mvpp2_prs_vid_entry_add(struct mvpp2_port *port, u16 vid)
19768c2ecf20Sopenharmony_ci{
19778c2ecf20Sopenharmony_ci	unsigned int vid_start = MVPP2_PE_VID_FILT_RANGE_START +
19788c2ecf20Sopenharmony_ci				 port->id * MVPP2_PRS_VLAN_FILT_MAX;
19798c2ecf20Sopenharmony_ci	unsigned int mask = 0xfff, reg_val, shift;
19808c2ecf20Sopenharmony_ci	struct mvpp2 *priv = port->priv;
19818c2ecf20Sopenharmony_ci	struct mvpp2_prs_entry pe;
19828c2ecf20Sopenharmony_ci	int tid;
19838c2ecf20Sopenharmony_ci
19848c2ecf20Sopenharmony_ci	memset(&pe, 0, sizeof(pe));
19858c2ecf20Sopenharmony_ci
19868c2ecf20Sopenharmony_ci	/* Scan TCAM and see if entry with this <vid,port> already exist */
19878c2ecf20Sopenharmony_ci	tid = mvpp2_prs_vid_range_find(port, vid, mask);
19888c2ecf20Sopenharmony_ci
19898c2ecf20Sopenharmony_ci	reg_val = mvpp2_read(priv, MVPP2_MH_REG(port->id));
19908c2ecf20Sopenharmony_ci	if (reg_val & MVPP2_DSA_EXTENDED)
19918c2ecf20Sopenharmony_ci		shift = MVPP2_VLAN_TAG_EDSA_LEN;
19928c2ecf20Sopenharmony_ci	else
19938c2ecf20Sopenharmony_ci		shift = MVPP2_VLAN_TAG_LEN;
19948c2ecf20Sopenharmony_ci
19958c2ecf20Sopenharmony_ci	/* No such entry */
19968c2ecf20Sopenharmony_ci	if (tid < 0) {
19978c2ecf20Sopenharmony_ci
19988c2ecf20Sopenharmony_ci		/* Go through all entries from first to last in vlan range */
19998c2ecf20Sopenharmony_ci		tid = mvpp2_prs_tcam_first_free(priv, vid_start,
20008c2ecf20Sopenharmony_ci						vid_start +
20018c2ecf20Sopenharmony_ci						MVPP2_PRS_VLAN_FILT_MAX_ENTRY);
20028c2ecf20Sopenharmony_ci
20038c2ecf20Sopenharmony_ci		/* There isn't room for a new VID filter */
20048c2ecf20Sopenharmony_ci		if (tid < 0)
20058c2ecf20Sopenharmony_ci			return tid;
20068c2ecf20Sopenharmony_ci
20078c2ecf20Sopenharmony_ci		mvpp2_prs_tcam_lu_set(&pe, MVPP2_PRS_LU_VID);
20088c2ecf20Sopenharmony_ci		pe.index = tid;
20098c2ecf20Sopenharmony_ci
20108c2ecf20Sopenharmony_ci		/* Mask all ports */
20118c2ecf20Sopenharmony_ci		mvpp2_prs_tcam_port_map_set(&pe, 0);
20128c2ecf20Sopenharmony_ci	} else {
20138c2ecf20Sopenharmony_ci		mvpp2_prs_init_from_hw(priv, &pe, tid);
20148c2ecf20Sopenharmony_ci	}
20158c2ecf20Sopenharmony_ci
20168c2ecf20Sopenharmony_ci	/* Enable the current port */
20178c2ecf20Sopenharmony_ci	mvpp2_prs_tcam_port_set(&pe, port->id, true);
20188c2ecf20Sopenharmony_ci
20198c2ecf20Sopenharmony_ci	/* Continue - set next lookup */
20208c2ecf20Sopenharmony_ci	mvpp2_prs_sram_next_lu_set(&pe, MVPP2_PRS_LU_L2);
20218c2ecf20Sopenharmony_ci
20228c2ecf20Sopenharmony_ci	/* Skip VLAN header - Set offset to 4 or 8 bytes */
20238c2ecf20Sopenharmony_ci	mvpp2_prs_sram_shift_set(&pe, shift, MVPP2_PRS_SRAM_OP_SEL_SHIFT_ADD);
20248c2ecf20Sopenharmony_ci
20258c2ecf20Sopenharmony_ci	/* Set match on VID */
20268c2ecf20Sopenharmony_ci	mvpp2_prs_match_vid(&pe, MVPP2_PRS_VID_TCAM_BYTE, vid);
20278c2ecf20Sopenharmony_ci
20288c2ecf20Sopenharmony_ci	/* Clear all ai bits for next iteration */
20298c2ecf20Sopenharmony_ci	mvpp2_prs_sram_ai_update(&pe, 0, MVPP2_PRS_SRAM_AI_MASK);
20308c2ecf20Sopenharmony_ci
20318c2ecf20Sopenharmony_ci	/* Update shadow table */
20328c2ecf20Sopenharmony_ci	mvpp2_prs_shadow_set(priv, pe.index, MVPP2_PRS_LU_VID);
20338c2ecf20Sopenharmony_ci	mvpp2_prs_hw_write(priv, &pe);
20348c2ecf20Sopenharmony_ci
20358c2ecf20Sopenharmony_ci	return 0;
20368c2ecf20Sopenharmony_ci}
20378c2ecf20Sopenharmony_ci
20388c2ecf20Sopenharmony_ci/* Write parser entry for VID filtering */
20398c2ecf20Sopenharmony_civoid mvpp2_prs_vid_entry_remove(struct mvpp2_port *port, u16 vid)
20408c2ecf20Sopenharmony_ci{
20418c2ecf20Sopenharmony_ci	struct mvpp2 *priv = port->priv;
20428c2ecf20Sopenharmony_ci	int tid;
20438c2ecf20Sopenharmony_ci
20448c2ecf20Sopenharmony_ci	/* Scan TCAM and see if entry with this <vid,port> already exist */
20458c2ecf20Sopenharmony_ci	tid = mvpp2_prs_vid_range_find(port, vid, 0xfff);
20468c2ecf20Sopenharmony_ci
20478c2ecf20Sopenharmony_ci	/* No such entry */
20488c2ecf20Sopenharmony_ci	if (tid < 0)
20498c2ecf20Sopenharmony_ci		return;
20508c2ecf20Sopenharmony_ci
20518c2ecf20Sopenharmony_ci	mvpp2_prs_hw_inv(priv, tid);
20528c2ecf20Sopenharmony_ci	priv->prs_shadow[tid].valid = false;
20538c2ecf20Sopenharmony_ci}
20548c2ecf20Sopenharmony_ci
20558c2ecf20Sopenharmony_ci/* Remove all existing VID filters on this port */
20568c2ecf20Sopenharmony_civoid mvpp2_prs_vid_remove_all(struct mvpp2_port *port)
20578c2ecf20Sopenharmony_ci{
20588c2ecf20Sopenharmony_ci	struct mvpp2 *priv = port->priv;
20598c2ecf20Sopenharmony_ci	int tid;
20608c2ecf20Sopenharmony_ci
20618c2ecf20Sopenharmony_ci	for (tid = MVPP2_PRS_VID_PORT_FIRST(port->id);
20628c2ecf20Sopenharmony_ci	     tid <= MVPP2_PRS_VID_PORT_LAST(port->id); tid++) {
20638c2ecf20Sopenharmony_ci		if (priv->prs_shadow[tid].valid) {
20648c2ecf20Sopenharmony_ci			mvpp2_prs_hw_inv(priv, tid);
20658c2ecf20Sopenharmony_ci			priv->prs_shadow[tid].valid = false;
20668c2ecf20Sopenharmony_ci		}
20678c2ecf20Sopenharmony_ci	}
20688c2ecf20Sopenharmony_ci}
20698c2ecf20Sopenharmony_ci
20708c2ecf20Sopenharmony_ci/* Remove VID filering entry for this port */
20718c2ecf20Sopenharmony_civoid mvpp2_prs_vid_disable_filtering(struct mvpp2_port *port)
20728c2ecf20Sopenharmony_ci{
20738c2ecf20Sopenharmony_ci	unsigned int tid = MVPP2_PRS_VID_PORT_DFLT(port->id);
20748c2ecf20Sopenharmony_ci	struct mvpp2 *priv = port->priv;
20758c2ecf20Sopenharmony_ci
20768c2ecf20Sopenharmony_ci	/* Invalidate the guard entry */
20778c2ecf20Sopenharmony_ci	mvpp2_prs_hw_inv(priv, tid);
20788c2ecf20Sopenharmony_ci
20798c2ecf20Sopenharmony_ci	priv->prs_shadow[tid].valid = false;
20808c2ecf20Sopenharmony_ci}
20818c2ecf20Sopenharmony_ci
20828c2ecf20Sopenharmony_ci/* Add guard entry that drops packets when no VID is matched on this port */
20838c2ecf20Sopenharmony_civoid mvpp2_prs_vid_enable_filtering(struct mvpp2_port *port)
20848c2ecf20Sopenharmony_ci{
20858c2ecf20Sopenharmony_ci	unsigned int tid = MVPP2_PRS_VID_PORT_DFLT(port->id);
20868c2ecf20Sopenharmony_ci	struct mvpp2 *priv = port->priv;
20878c2ecf20Sopenharmony_ci	unsigned int reg_val, shift;
20888c2ecf20Sopenharmony_ci	struct mvpp2_prs_entry pe;
20898c2ecf20Sopenharmony_ci
20908c2ecf20Sopenharmony_ci	if (priv->prs_shadow[tid].valid)
20918c2ecf20Sopenharmony_ci		return;
20928c2ecf20Sopenharmony_ci
20938c2ecf20Sopenharmony_ci	memset(&pe, 0, sizeof(pe));
20948c2ecf20Sopenharmony_ci
20958c2ecf20Sopenharmony_ci	pe.index = tid;
20968c2ecf20Sopenharmony_ci
20978c2ecf20Sopenharmony_ci	reg_val = mvpp2_read(priv, MVPP2_MH_REG(port->id));
20988c2ecf20Sopenharmony_ci	if (reg_val & MVPP2_DSA_EXTENDED)
20998c2ecf20Sopenharmony_ci		shift = MVPP2_VLAN_TAG_EDSA_LEN;
21008c2ecf20Sopenharmony_ci	else
21018c2ecf20Sopenharmony_ci		shift = MVPP2_VLAN_TAG_LEN;
21028c2ecf20Sopenharmony_ci
21038c2ecf20Sopenharmony_ci	mvpp2_prs_tcam_lu_set(&pe, MVPP2_PRS_LU_VID);
21048c2ecf20Sopenharmony_ci
21058c2ecf20Sopenharmony_ci	/* Mask all ports */
21068c2ecf20Sopenharmony_ci	mvpp2_prs_tcam_port_map_set(&pe, 0);
21078c2ecf20Sopenharmony_ci
21088c2ecf20Sopenharmony_ci	/* Update port mask */
21098c2ecf20Sopenharmony_ci	mvpp2_prs_tcam_port_set(&pe, port->id, true);
21108c2ecf20Sopenharmony_ci
21118c2ecf20Sopenharmony_ci	/* Continue - set next lookup */
21128c2ecf20Sopenharmony_ci	mvpp2_prs_sram_next_lu_set(&pe, MVPP2_PRS_LU_L2);
21138c2ecf20Sopenharmony_ci
21148c2ecf20Sopenharmony_ci	/* Skip VLAN header - Set offset to 4 or 8 bytes */
21158c2ecf20Sopenharmony_ci	mvpp2_prs_sram_shift_set(&pe, shift, MVPP2_PRS_SRAM_OP_SEL_SHIFT_ADD);
21168c2ecf20Sopenharmony_ci
21178c2ecf20Sopenharmony_ci	/* Drop VLAN packets that don't belong to any VIDs on this port */
21188c2ecf20Sopenharmony_ci	mvpp2_prs_sram_ri_update(&pe, MVPP2_PRS_RI_DROP_MASK,
21198c2ecf20Sopenharmony_ci				 MVPP2_PRS_RI_DROP_MASK);
21208c2ecf20Sopenharmony_ci
21218c2ecf20Sopenharmony_ci	/* Clear all ai bits for next iteration */
21228c2ecf20Sopenharmony_ci	mvpp2_prs_sram_ai_update(&pe, 0, MVPP2_PRS_SRAM_AI_MASK);
21238c2ecf20Sopenharmony_ci
21248c2ecf20Sopenharmony_ci	/* Update shadow table */
21258c2ecf20Sopenharmony_ci	mvpp2_prs_shadow_set(priv, pe.index, MVPP2_PRS_LU_VID);
21268c2ecf20Sopenharmony_ci	mvpp2_prs_hw_write(priv, &pe);
21278c2ecf20Sopenharmony_ci}
21288c2ecf20Sopenharmony_ci
21298c2ecf20Sopenharmony_ci/* Parser default initialization */
21308c2ecf20Sopenharmony_ciint mvpp2_prs_default_init(struct platform_device *pdev, struct mvpp2 *priv)
21318c2ecf20Sopenharmony_ci{
21328c2ecf20Sopenharmony_ci	int err, index, i;
21338c2ecf20Sopenharmony_ci
21348c2ecf20Sopenharmony_ci	/* Enable tcam table */
21358c2ecf20Sopenharmony_ci	mvpp2_write(priv, MVPP2_PRS_TCAM_CTRL_REG, MVPP2_PRS_TCAM_EN_MASK);
21368c2ecf20Sopenharmony_ci
21378c2ecf20Sopenharmony_ci	/* Clear all tcam and sram entries */
21388c2ecf20Sopenharmony_ci	for (index = 0; index < MVPP2_PRS_TCAM_SRAM_SIZE; index++) {
21398c2ecf20Sopenharmony_ci		mvpp2_write(priv, MVPP2_PRS_TCAM_IDX_REG, index);
21408c2ecf20Sopenharmony_ci		for (i = 0; i < MVPP2_PRS_TCAM_WORDS; i++)
21418c2ecf20Sopenharmony_ci			mvpp2_write(priv, MVPP2_PRS_TCAM_DATA_REG(i), 0);
21428c2ecf20Sopenharmony_ci
21438c2ecf20Sopenharmony_ci		mvpp2_write(priv, MVPP2_PRS_SRAM_IDX_REG, index);
21448c2ecf20Sopenharmony_ci		for (i = 0; i < MVPP2_PRS_SRAM_WORDS; i++)
21458c2ecf20Sopenharmony_ci			mvpp2_write(priv, MVPP2_PRS_SRAM_DATA_REG(i), 0);
21468c2ecf20Sopenharmony_ci	}
21478c2ecf20Sopenharmony_ci
21488c2ecf20Sopenharmony_ci	/* Invalidate all tcam entries */
21498c2ecf20Sopenharmony_ci	for (index = 0; index < MVPP2_PRS_TCAM_SRAM_SIZE; index++)
21508c2ecf20Sopenharmony_ci		mvpp2_prs_hw_inv(priv, index);
21518c2ecf20Sopenharmony_ci
21528c2ecf20Sopenharmony_ci	priv->prs_shadow = devm_kcalloc(&pdev->dev, MVPP2_PRS_TCAM_SRAM_SIZE,
21538c2ecf20Sopenharmony_ci					sizeof(*priv->prs_shadow),
21548c2ecf20Sopenharmony_ci					GFP_KERNEL);
21558c2ecf20Sopenharmony_ci	if (!priv->prs_shadow)
21568c2ecf20Sopenharmony_ci		return -ENOMEM;
21578c2ecf20Sopenharmony_ci
21588c2ecf20Sopenharmony_ci	/* Always start from lookup = 0 */
21598c2ecf20Sopenharmony_ci	for (index = 0; index < MVPP2_MAX_PORTS; index++)
21608c2ecf20Sopenharmony_ci		mvpp2_prs_hw_port_init(priv, index, MVPP2_PRS_LU_MH,
21618c2ecf20Sopenharmony_ci				       MVPP2_PRS_PORT_LU_MAX, 0);
21628c2ecf20Sopenharmony_ci
21638c2ecf20Sopenharmony_ci	mvpp2_prs_def_flow_init(priv);
21648c2ecf20Sopenharmony_ci
21658c2ecf20Sopenharmony_ci	mvpp2_prs_mh_init(priv);
21668c2ecf20Sopenharmony_ci
21678c2ecf20Sopenharmony_ci	mvpp2_prs_mac_init(priv);
21688c2ecf20Sopenharmony_ci
21698c2ecf20Sopenharmony_ci	mvpp2_prs_dsa_init(priv);
21708c2ecf20Sopenharmony_ci
21718c2ecf20Sopenharmony_ci	mvpp2_prs_vid_init(priv);
21728c2ecf20Sopenharmony_ci
21738c2ecf20Sopenharmony_ci	err = mvpp2_prs_etype_init(priv);
21748c2ecf20Sopenharmony_ci	if (err)
21758c2ecf20Sopenharmony_ci		return err;
21768c2ecf20Sopenharmony_ci
21778c2ecf20Sopenharmony_ci	err = mvpp2_prs_vlan_init(pdev, priv);
21788c2ecf20Sopenharmony_ci	if (err)
21798c2ecf20Sopenharmony_ci		return err;
21808c2ecf20Sopenharmony_ci
21818c2ecf20Sopenharmony_ci	err = mvpp2_prs_pppoe_init(priv);
21828c2ecf20Sopenharmony_ci	if (err)
21838c2ecf20Sopenharmony_ci		return err;
21848c2ecf20Sopenharmony_ci
21858c2ecf20Sopenharmony_ci	err = mvpp2_prs_ip6_init(priv);
21868c2ecf20Sopenharmony_ci	if (err)
21878c2ecf20Sopenharmony_ci		return err;
21888c2ecf20Sopenharmony_ci
21898c2ecf20Sopenharmony_ci	err = mvpp2_prs_ip4_init(priv);
21908c2ecf20Sopenharmony_ci	if (err)
21918c2ecf20Sopenharmony_ci		return err;
21928c2ecf20Sopenharmony_ci
21938c2ecf20Sopenharmony_ci	return 0;
21948c2ecf20Sopenharmony_ci}
21958c2ecf20Sopenharmony_ci
21968c2ecf20Sopenharmony_ci/* Compare MAC DA with tcam entry data */
21978c2ecf20Sopenharmony_cistatic bool mvpp2_prs_mac_range_equals(struct mvpp2_prs_entry *pe,
21988c2ecf20Sopenharmony_ci				       const u8 *da, unsigned char *mask)
21998c2ecf20Sopenharmony_ci{
22008c2ecf20Sopenharmony_ci	unsigned char tcam_byte, tcam_mask;
22018c2ecf20Sopenharmony_ci	int index;
22028c2ecf20Sopenharmony_ci
22038c2ecf20Sopenharmony_ci	for (index = 0; index < ETH_ALEN; index++) {
22048c2ecf20Sopenharmony_ci		mvpp2_prs_tcam_data_byte_get(pe, index, &tcam_byte, &tcam_mask);
22058c2ecf20Sopenharmony_ci		if (tcam_mask != mask[index])
22068c2ecf20Sopenharmony_ci			return false;
22078c2ecf20Sopenharmony_ci
22088c2ecf20Sopenharmony_ci		if ((tcam_mask & tcam_byte) != (da[index] & mask[index]))
22098c2ecf20Sopenharmony_ci			return false;
22108c2ecf20Sopenharmony_ci	}
22118c2ecf20Sopenharmony_ci
22128c2ecf20Sopenharmony_ci	return true;
22138c2ecf20Sopenharmony_ci}
22148c2ecf20Sopenharmony_ci
22158c2ecf20Sopenharmony_ci/* Find tcam entry with matched pair <MAC DA, port> */
22168c2ecf20Sopenharmony_cistatic int
22178c2ecf20Sopenharmony_cimvpp2_prs_mac_da_range_find(struct mvpp2 *priv, int pmap, const u8 *da,
22188c2ecf20Sopenharmony_ci			    unsigned char *mask, int udf_type)
22198c2ecf20Sopenharmony_ci{
22208c2ecf20Sopenharmony_ci	struct mvpp2_prs_entry pe;
22218c2ecf20Sopenharmony_ci	int tid;
22228c2ecf20Sopenharmony_ci
22238c2ecf20Sopenharmony_ci	/* Go through the all entires with MVPP2_PRS_LU_MAC */
22248c2ecf20Sopenharmony_ci	for (tid = MVPP2_PE_MAC_RANGE_START;
22258c2ecf20Sopenharmony_ci	     tid <= MVPP2_PE_MAC_RANGE_END; tid++) {
22268c2ecf20Sopenharmony_ci		unsigned int entry_pmap;
22278c2ecf20Sopenharmony_ci
22288c2ecf20Sopenharmony_ci		if (!priv->prs_shadow[tid].valid ||
22298c2ecf20Sopenharmony_ci		    (priv->prs_shadow[tid].lu != MVPP2_PRS_LU_MAC) ||
22308c2ecf20Sopenharmony_ci		    (priv->prs_shadow[tid].udf != udf_type))
22318c2ecf20Sopenharmony_ci			continue;
22328c2ecf20Sopenharmony_ci
22338c2ecf20Sopenharmony_ci		mvpp2_prs_init_from_hw(priv, &pe, tid);
22348c2ecf20Sopenharmony_ci		entry_pmap = mvpp2_prs_tcam_port_map_get(&pe);
22358c2ecf20Sopenharmony_ci
22368c2ecf20Sopenharmony_ci		if (mvpp2_prs_mac_range_equals(&pe, da, mask) &&
22378c2ecf20Sopenharmony_ci		    entry_pmap == pmap)
22388c2ecf20Sopenharmony_ci			return tid;
22398c2ecf20Sopenharmony_ci	}
22408c2ecf20Sopenharmony_ci
22418c2ecf20Sopenharmony_ci	return -ENOENT;
22428c2ecf20Sopenharmony_ci}
22438c2ecf20Sopenharmony_ci
22448c2ecf20Sopenharmony_ci/* Update parser's mac da entry */
22458c2ecf20Sopenharmony_ciint mvpp2_prs_mac_da_accept(struct mvpp2_port *port, const u8 *da, bool add)
22468c2ecf20Sopenharmony_ci{
22478c2ecf20Sopenharmony_ci	unsigned char mask[ETH_ALEN] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
22488c2ecf20Sopenharmony_ci	struct mvpp2 *priv = port->priv;
22498c2ecf20Sopenharmony_ci	unsigned int pmap, len, ri;
22508c2ecf20Sopenharmony_ci	struct mvpp2_prs_entry pe;
22518c2ecf20Sopenharmony_ci	int tid;
22528c2ecf20Sopenharmony_ci
22538c2ecf20Sopenharmony_ci	memset(&pe, 0, sizeof(pe));
22548c2ecf20Sopenharmony_ci
22558c2ecf20Sopenharmony_ci	/* Scan TCAM and see if entry with this <MAC DA, port> already exist */
22568c2ecf20Sopenharmony_ci	tid = mvpp2_prs_mac_da_range_find(priv, BIT(port->id), da, mask,
22578c2ecf20Sopenharmony_ci					  MVPP2_PRS_UDF_MAC_DEF);
22588c2ecf20Sopenharmony_ci
22598c2ecf20Sopenharmony_ci	/* No such entry */
22608c2ecf20Sopenharmony_ci	if (tid < 0) {
22618c2ecf20Sopenharmony_ci		if (!add)
22628c2ecf20Sopenharmony_ci			return 0;
22638c2ecf20Sopenharmony_ci
22648c2ecf20Sopenharmony_ci		/* Create new TCAM entry */
22658c2ecf20Sopenharmony_ci		/* Go through the all entries from first to last */
22668c2ecf20Sopenharmony_ci		tid = mvpp2_prs_tcam_first_free(priv,
22678c2ecf20Sopenharmony_ci						MVPP2_PE_MAC_RANGE_START,
22688c2ecf20Sopenharmony_ci						MVPP2_PE_MAC_RANGE_END);
22698c2ecf20Sopenharmony_ci		if (tid < 0)
22708c2ecf20Sopenharmony_ci			return tid;
22718c2ecf20Sopenharmony_ci
22728c2ecf20Sopenharmony_ci		pe.index = tid;
22738c2ecf20Sopenharmony_ci
22748c2ecf20Sopenharmony_ci		/* Mask all ports */
22758c2ecf20Sopenharmony_ci		mvpp2_prs_tcam_port_map_set(&pe, 0);
22768c2ecf20Sopenharmony_ci	} else {
22778c2ecf20Sopenharmony_ci		mvpp2_prs_init_from_hw(priv, &pe, tid);
22788c2ecf20Sopenharmony_ci	}
22798c2ecf20Sopenharmony_ci
22808c2ecf20Sopenharmony_ci	mvpp2_prs_tcam_lu_set(&pe, MVPP2_PRS_LU_MAC);
22818c2ecf20Sopenharmony_ci
22828c2ecf20Sopenharmony_ci	/* Update port mask */
22838c2ecf20Sopenharmony_ci	mvpp2_prs_tcam_port_set(&pe, port->id, add);
22848c2ecf20Sopenharmony_ci
22858c2ecf20Sopenharmony_ci	/* Invalidate the entry if no ports are left enabled */
22868c2ecf20Sopenharmony_ci	pmap = mvpp2_prs_tcam_port_map_get(&pe);
22878c2ecf20Sopenharmony_ci	if (pmap == 0) {
22888c2ecf20Sopenharmony_ci		if (add)
22898c2ecf20Sopenharmony_ci			return -EINVAL;
22908c2ecf20Sopenharmony_ci
22918c2ecf20Sopenharmony_ci		mvpp2_prs_hw_inv(priv, pe.index);
22928c2ecf20Sopenharmony_ci		priv->prs_shadow[pe.index].valid = false;
22938c2ecf20Sopenharmony_ci		return 0;
22948c2ecf20Sopenharmony_ci	}
22958c2ecf20Sopenharmony_ci
22968c2ecf20Sopenharmony_ci	/* Continue - set next lookup */
22978c2ecf20Sopenharmony_ci	mvpp2_prs_sram_next_lu_set(&pe, MVPP2_PRS_LU_DSA);
22988c2ecf20Sopenharmony_ci
22998c2ecf20Sopenharmony_ci	/* Set match on DA */
23008c2ecf20Sopenharmony_ci	len = ETH_ALEN;
23018c2ecf20Sopenharmony_ci	while (len--)
23028c2ecf20Sopenharmony_ci		mvpp2_prs_tcam_data_byte_set(&pe, len, da[len], 0xff);
23038c2ecf20Sopenharmony_ci
23048c2ecf20Sopenharmony_ci	/* Set result info bits */
23058c2ecf20Sopenharmony_ci	if (is_broadcast_ether_addr(da)) {
23068c2ecf20Sopenharmony_ci		ri = MVPP2_PRS_RI_L2_BCAST;
23078c2ecf20Sopenharmony_ci	} else if (is_multicast_ether_addr(da)) {
23088c2ecf20Sopenharmony_ci		ri = MVPP2_PRS_RI_L2_MCAST;
23098c2ecf20Sopenharmony_ci	} else {
23108c2ecf20Sopenharmony_ci		ri = MVPP2_PRS_RI_L2_UCAST;
23118c2ecf20Sopenharmony_ci
23128c2ecf20Sopenharmony_ci		if (ether_addr_equal(da, port->dev->dev_addr))
23138c2ecf20Sopenharmony_ci			ri |= MVPP2_PRS_RI_MAC_ME_MASK;
23148c2ecf20Sopenharmony_ci	}
23158c2ecf20Sopenharmony_ci
23168c2ecf20Sopenharmony_ci	mvpp2_prs_sram_ri_update(&pe, ri, MVPP2_PRS_RI_L2_CAST_MASK |
23178c2ecf20Sopenharmony_ci				 MVPP2_PRS_RI_MAC_ME_MASK);
23188c2ecf20Sopenharmony_ci	mvpp2_prs_shadow_ri_set(priv, pe.index, ri, MVPP2_PRS_RI_L2_CAST_MASK |
23198c2ecf20Sopenharmony_ci				MVPP2_PRS_RI_MAC_ME_MASK);
23208c2ecf20Sopenharmony_ci
23218c2ecf20Sopenharmony_ci	/* Shift to ethertype */
23228c2ecf20Sopenharmony_ci	mvpp2_prs_sram_shift_set(&pe, 2 * ETH_ALEN,
23238c2ecf20Sopenharmony_ci				 MVPP2_PRS_SRAM_OP_SEL_SHIFT_ADD);
23248c2ecf20Sopenharmony_ci
23258c2ecf20Sopenharmony_ci	/* Update shadow table and hw entry */
23268c2ecf20Sopenharmony_ci	priv->prs_shadow[pe.index].udf = MVPP2_PRS_UDF_MAC_DEF;
23278c2ecf20Sopenharmony_ci	mvpp2_prs_shadow_set(priv, pe.index, MVPP2_PRS_LU_MAC);
23288c2ecf20Sopenharmony_ci	mvpp2_prs_hw_write(priv, &pe);
23298c2ecf20Sopenharmony_ci
23308c2ecf20Sopenharmony_ci	return 0;
23318c2ecf20Sopenharmony_ci}
23328c2ecf20Sopenharmony_ci
23338c2ecf20Sopenharmony_ciint mvpp2_prs_update_mac_da(struct net_device *dev, const u8 *da)
23348c2ecf20Sopenharmony_ci{
23358c2ecf20Sopenharmony_ci	struct mvpp2_port *port = netdev_priv(dev);
23368c2ecf20Sopenharmony_ci	int err;
23378c2ecf20Sopenharmony_ci
23388c2ecf20Sopenharmony_ci	/* Remove old parser entry */
23398c2ecf20Sopenharmony_ci	err = mvpp2_prs_mac_da_accept(port, dev->dev_addr, false);
23408c2ecf20Sopenharmony_ci	if (err)
23418c2ecf20Sopenharmony_ci		return err;
23428c2ecf20Sopenharmony_ci
23438c2ecf20Sopenharmony_ci	/* Add new parser entry */
23448c2ecf20Sopenharmony_ci	err = mvpp2_prs_mac_da_accept(port, da, true);
23458c2ecf20Sopenharmony_ci	if (err)
23468c2ecf20Sopenharmony_ci		return err;
23478c2ecf20Sopenharmony_ci
23488c2ecf20Sopenharmony_ci	/* Set addr in the device */
23498c2ecf20Sopenharmony_ci	ether_addr_copy(dev->dev_addr, da);
23508c2ecf20Sopenharmony_ci
23518c2ecf20Sopenharmony_ci	return 0;
23528c2ecf20Sopenharmony_ci}
23538c2ecf20Sopenharmony_ci
23548c2ecf20Sopenharmony_civoid mvpp2_prs_mac_del_all(struct mvpp2_port *port)
23558c2ecf20Sopenharmony_ci{
23568c2ecf20Sopenharmony_ci	struct mvpp2 *priv = port->priv;
23578c2ecf20Sopenharmony_ci	struct mvpp2_prs_entry pe;
23588c2ecf20Sopenharmony_ci	unsigned long pmap;
23598c2ecf20Sopenharmony_ci	int index, tid;
23608c2ecf20Sopenharmony_ci
23618c2ecf20Sopenharmony_ci	for (tid = MVPP2_PE_MAC_RANGE_START;
23628c2ecf20Sopenharmony_ci	     tid <= MVPP2_PE_MAC_RANGE_END; tid++) {
23638c2ecf20Sopenharmony_ci		unsigned char da[ETH_ALEN], da_mask[ETH_ALEN];
23648c2ecf20Sopenharmony_ci
23658c2ecf20Sopenharmony_ci		if (!priv->prs_shadow[tid].valid ||
23668c2ecf20Sopenharmony_ci		    (priv->prs_shadow[tid].lu != MVPP2_PRS_LU_MAC) ||
23678c2ecf20Sopenharmony_ci		    (priv->prs_shadow[tid].udf != MVPP2_PRS_UDF_MAC_DEF))
23688c2ecf20Sopenharmony_ci			continue;
23698c2ecf20Sopenharmony_ci
23708c2ecf20Sopenharmony_ci		mvpp2_prs_init_from_hw(priv, &pe, tid);
23718c2ecf20Sopenharmony_ci
23728c2ecf20Sopenharmony_ci		pmap = mvpp2_prs_tcam_port_map_get(&pe);
23738c2ecf20Sopenharmony_ci
23748c2ecf20Sopenharmony_ci		/* We only want entries active on this port */
23758c2ecf20Sopenharmony_ci		if (!test_bit(port->id, &pmap))
23768c2ecf20Sopenharmony_ci			continue;
23778c2ecf20Sopenharmony_ci
23788c2ecf20Sopenharmony_ci		/* Read mac addr from entry */
23798c2ecf20Sopenharmony_ci		for (index = 0; index < ETH_ALEN; index++)
23808c2ecf20Sopenharmony_ci			mvpp2_prs_tcam_data_byte_get(&pe, index, &da[index],
23818c2ecf20Sopenharmony_ci						     &da_mask[index]);
23828c2ecf20Sopenharmony_ci
23838c2ecf20Sopenharmony_ci		/* Special cases : Don't remove broadcast and port's own
23848c2ecf20Sopenharmony_ci		 * address
23858c2ecf20Sopenharmony_ci		 */
23868c2ecf20Sopenharmony_ci		if (is_broadcast_ether_addr(da) ||
23878c2ecf20Sopenharmony_ci		    ether_addr_equal(da, port->dev->dev_addr))
23888c2ecf20Sopenharmony_ci			continue;
23898c2ecf20Sopenharmony_ci
23908c2ecf20Sopenharmony_ci		/* Remove entry from TCAM */
23918c2ecf20Sopenharmony_ci		mvpp2_prs_mac_da_accept(port, da, false);
23928c2ecf20Sopenharmony_ci	}
23938c2ecf20Sopenharmony_ci}
23948c2ecf20Sopenharmony_ci
23958c2ecf20Sopenharmony_ciint mvpp2_prs_tag_mode_set(struct mvpp2 *priv, int port, int type)
23968c2ecf20Sopenharmony_ci{
23978c2ecf20Sopenharmony_ci	switch (type) {
23988c2ecf20Sopenharmony_ci	case MVPP2_TAG_TYPE_EDSA:
23998c2ecf20Sopenharmony_ci		/* Add port to EDSA entries */
24008c2ecf20Sopenharmony_ci		mvpp2_prs_dsa_tag_set(priv, port, true,
24018c2ecf20Sopenharmony_ci				      MVPP2_PRS_TAGGED, MVPP2_PRS_EDSA);
24028c2ecf20Sopenharmony_ci		mvpp2_prs_dsa_tag_set(priv, port, true,
24038c2ecf20Sopenharmony_ci				      MVPP2_PRS_UNTAGGED, MVPP2_PRS_EDSA);
24048c2ecf20Sopenharmony_ci		/* Remove port from DSA entries */
24058c2ecf20Sopenharmony_ci		mvpp2_prs_dsa_tag_set(priv, port, false,
24068c2ecf20Sopenharmony_ci				      MVPP2_PRS_TAGGED, MVPP2_PRS_DSA);
24078c2ecf20Sopenharmony_ci		mvpp2_prs_dsa_tag_set(priv, port, false,
24088c2ecf20Sopenharmony_ci				      MVPP2_PRS_UNTAGGED, MVPP2_PRS_DSA);
24098c2ecf20Sopenharmony_ci		break;
24108c2ecf20Sopenharmony_ci
24118c2ecf20Sopenharmony_ci	case MVPP2_TAG_TYPE_DSA:
24128c2ecf20Sopenharmony_ci		/* Add port to DSA entries */
24138c2ecf20Sopenharmony_ci		mvpp2_prs_dsa_tag_set(priv, port, true,
24148c2ecf20Sopenharmony_ci				      MVPP2_PRS_TAGGED, MVPP2_PRS_DSA);
24158c2ecf20Sopenharmony_ci		mvpp2_prs_dsa_tag_set(priv, port, true,
24168c2ecf20Sopenharmony_ci				      MVPP2_PRS_UNTAGGED, MVPP2_PRS_DSA);
24178c2ecf20Sopenharmony_ci		/* Remove port from EDSA entries */
24188c2ecf20Sopenharmony_ci		mvpp2_prs_dsa_tag_set(priv, port, false,
24198c2ecf20Sopenharmony_ci				      MVPP2_PRS_TAGGED, MVPP2_PRS_EDSA);
24208c2ecf20Sopenharmony_ci		mvpp2_prs_dsa_tag_set(priv, port, false,
24218c2ecf20Sopenharmony_ci				      MVPP2_PRS_UNTAGGED, MVPP2_PRS_EDSA);
24228c2ecf20Sopenharmony_ci		break;
24238c2ecf20Sopenharmony_ci
24248c2ecf20Sopenharmony_ci	case MVPP2_TAG_TYPE_MH:
24258c2ecf20Sopenharmony_ci	case MVPP2_TAG_TYPE_NONE:
24268c2ecf20Sopenharmony_ci		/* Remove port form EDSA and DSA entries */
24278c2ecf20Sopenharmony_ci		mvpp2_prs_dsa_tag_set(priv, port, false,
24288c2ecf20Sopenharmony_ci				      MVPP2_PRS_TAGGED, MVPP2_PRS_DSA);
24298c2ecf20Sopenharmony_ci		mvpp2_prs_dsa_tag_set(priv, port, false,
24308c2ecf20Sopenharmony_ci				      MVPP2_PRS_UNTAGGED, MVPP2_PRS_DSA);
24318c2ecf20Sopenharmony_ci		mvpp2_prs_dsa_tag_set(priv, port, false,
24328c2ecf20Sopenharmony_ci				      MVPP2_PRS_TAGGED, MVPP2_PRS_EDSA);
24338c2ecf20Sopenharmony_ci		mvpp2_prs_dsa_tag_set(priv, port, false,
24348c2ecf20Sopenharmony_ci				      MVPP2_PRS_UNTAGGED, MVPP2_PRS_EDSA);
24358c2ecf20Sopenharmony_ci		break;
24368c2ecf20Sopenharmony_ci
24378c2ecf20Sopenharmony_ci	default:
24388c2ecf20Sopenharmony_ci		if ((type < 0) || (type > MVPP2_TAG_TYPE_EDSA))
24398c2ecf20Sopenharmony_ci			return -EINVAL;
24408c2ecf20Sopenharmony_ci	}
24418c2ecf20Sopenharmony_ci
24428c2ecf20Sopenharmony_ci	return 0;
24438c2ecf20Sopenharmony_ci}
24448c2ecf20Sopenharmony_ci
24458c2ecf20Sopenharmony_ciint mvpp2_prs_add_flow(struct mvpp2 *priv, int flow, u32 ri, u32 ri_mask)
24468c2ecf20Sopenharmony_ci{
24478c2ecf20Sopenharmony_ci	struct mvpp2_prs_entry pe;
24488c2ecf20Sopenharmony_ci	u8 *ri_byte, *ri_byte_mask;
24498c2ecf20Sopenharmony_ci	int tid, i;
24508c2ecf20Sopenharmony_ci
24518c2ecf20Sopenharmony_ci	memset(&pe, 0, sizeof(pe));
24528c2ecf20Sopenharmony_ci
24538c2ecf20Sopenharmony_ci	tid = mvpp2_prs_tcam_first_free(priv,
24548c2ecf20Sopenharmony_ci					MVPP2_PE_LAST_FREE_TID,
24558c2ecf20Sopenharmony_ci					MVPP2_PE_FIRST_FREE_TID);
24568c2ecf20Sopenharmony_ci	if (tid < 0)
24578c2ecf20Sopenharmony_ci		return tid;
24588c2ecf20Sopenharmony_ci
24598c2ecf20Sopenharmony_ci	pe.index = tid;
24608c2ecf20Sopenharmony_ci
24618c2ecf20Sopenharmony_ci	ri_byte = (u8 *)&ri;
24628c2ecf20Sopenharmony_ci	ri_byte_mask = (u8 *)&ri_mask;
24638c2ecf20Sopenharmony_ci
24648c2ecf20Sopenharmony_ci	mvpp2_prs_sram_ai_update(&pe, flow, MVPP2_PRS_FLOW_ID_MASK);
24658c2ecf20Sopenharmony_ci	mvpp2_prs_sram_bits_set(&pe, MVPP2_PRS_SRAM_LU_DONE_BIT, 1);
24668c2ecf20Sopenharmony_ci
24678c2ecf20Sopenharmony_ci	for (i = 0; i < 4; i++) {
24688c2ecf20Sopenharmony_ci		mvpp2_prs_tcam_data_byte_set(&pe, i, ri_byte[i],
24698c2ecf20Sopenharmony_ci					     ri_byte_mask[i]);
24708c2ecf20Sopenharmony_ci	}
24718c2ecf20Sopenharmony_ci
24728c2ecf20Sopenharmony_ci	mvpp2_prs_shadow_set(priv, pe.index, MVPP2_PRS_LU_FLOWS);
24738c2ecf20Sopenharmony_ci	mvpp2_prs_tcam_lu_set(&pe, MVPP2_PRS_LU_FLOWS);
24748c2ecf20Sopenharmony_ci	mvpp2_prs_tcam_port_map_set(&pe, MVPP2_PRS_PORT_MASK);
24758c2ecf20Sopenharmony_ci	mvpp2_prs_hw_write(priv, &pe);
24768c2ecf20Sopenharmony_ci
24778c2ecf20Sopenharmony_ci	return 0;
24788c2ecf20Sopenharmony_ci}
24798c2ecf20Sopenharmony_ci
24808c2ecf20Sopenharmony_ci/* Set prs flow for the port */
24818c2ecf20Sopenharmony_ciint mvpp2_prs_def_flow(struct mvpp2_port *port)
24828c2ecf20Sopenharmony_ci{
24838c2ecf20Sopenharmony_ci	struct mvpp2_prs_entry pe;
24848c2ecf20Sopenharmony_ci	int tid;
24858c2ecf20Sopenharmony_ci
24868c2ecf20Sopenharmony_ci	memset(&pe, 0, sizeof(pe));
24878c2ecf20Sopenharmony_ci
24888c2ecf20Sopenharmony_ci	tid = mvpp2_prs_flow_find(port->priv, port->id);
24898c2ecf20Sopenharmony_ci
24908c2ecf20Sopenharmony_ci	/* Such entry not exist */
24918c2ecf20Sopenharmony_ci	if (tid < 0) {
24928c2ecf20Sopenharmony_ci		/* Go through the all entires from last to first */
24938c2ecf20Sopenharmony_ci		tid = mvpp2_prs_tcam_first_free(port->priv,
24948c2ecf20Sopenharmony_ci						MVPP2_PE_LAST_FREE_TID,
24958c2ecf20Sopenharmony_ci					       MVPP2_PE_FIRST_FREE_TID);
24968c2ecf20Sopenharmony_ci		if (tid < 0)
24978c2ecf20Sopenharmony_ci			return tid;
24988c2ecf20Sopenharmony_ci
24998c2ecf20Sopenharmony_ci		pe.index = tid;
25008c2ecf20Sopenharmony_ci
25018c2ecf20Sopenharmony_ci		/* Set flow ID*/
25028c2ecf20Sopenharmony_ci		mvpp2_prs_sram_ai_update(&pe, port->id, MVPP2_PRS_FLOW_ID_MASK);
25038c2ecf20Sopenharmony_ci		mvpp2_prs_sram_bits_set(&pe, MVPP2_PRS_SRAM_LU_DONE_BIT, 1);
25048c2ecf20Sopenharmony_ci
25058c2ecf20Sopenharmony_ci		/* Update shadow table */
25068c2ecf20Sopenharmony_ci		mvpp2_prs_shadow_set(port->priv, pe.index, MVPP2_PRS_LU_FLOWS);
25078c2ecf20Sopenharmony_ci	} else {
25088c2ecf20Sopenharmony_ci		mvpp2_prs_init_from_hw(port->priv, &pe, tid);
25098c2ecf20Sopenharmony_ci	}
25108c2ecf20Sopenharmony_ci
25118c2ecf20Sopenharmony_ci	mvpp2_prs_tcam_lu_set(&pe, MVPP2_PRS_LU_FLOWS);
25128c2ecf20Sopenharmony_ci	mvpp2_prs_tcam_port_map_set(&pe, (1 << port->id));
25138c2ecf20Sopenharmony_ci	mvpp2_prs_hw_write(port->priv, &pe);
25148c2ecf20Sopenharmony_ci
25158c2ecf20Sopenharmony_ci	return 0;
25168c2ecf20Sopenharmony_ci}
25178c2ecf20Sopenharmony_ci
25188c2ecf20Sopenharmony_ciint mvpp2_prs_hits(struct mvpp2 *priv, int index)
25198c2ecf20Sopenharmony_ci{
25208c2ecf20Sopenharmony_ci	u32 val;
25218c2ecf20Sopenharmony_ci
25228c2ecf20Sopenharmony_ci	if (index > MVPP2_PRS_TCAM_SRAM_SIZE)
25238c2ecf20Sopenharmony_ci		return -EINVAL;
25248c2ecf20Sopenharmony_ci
25258c2ecf20Sopenharmony_ci	mvpp2_write(priv, MVPP2_PRS_TCAM_HIT_IDX_REG, index);
25268c2ecf20Sopenharmony_ci
25278c2ecf20Sopenharmony_ci	val = mvpp2_read(priv, MVPP2_PRS_TCAM_HIT_CNT_REG);
25288c2ecf20Sopenharmony_ci
25298c2ecf20Sopenharmony_ci	val &= MVPP2_PRS_TCAM_HIT_CNT_MASK;
25308c2ecf20Sopenharmony_ci
25318c2ecf20Sopenharmony_ci	return val;
25328c2ecf20Sopenharmony_ci}
2533