xref: /openbmc/linux/drivers/net/ethernet/marvell/mvpp2/mvpp2_prs.c (revision 1ac731c529cd4d6adbce134754b51ff7d822b145)
1f1e37e31SAntoine Tenart // SPDX-License-Identifier: GPL-2.0
2db9d7d36SMaxime Chevallier /*
3db9d7d36SMaxime Chevallier  * Header Parser helpers for Marvell PPv2 Network Controller
4db9d7d36SMaxime Chevallier  *
5db9d7d36SMaxime Chevallier  * Copyright (C) 2014 Marvell
6db9d7d36SMaxime Chevallier  *
7db9d7d36SMaxime Chevallier  * Marcin Wojtas <mw@semihalf.com>
8db9d7d36SMaxime Chevallier  */
9db9d7d36SMaxime Chevallier 
10db9d7d36SMaxime Chevallier #include <linux/kernel.h>
11db9d7d36SMaxime Chevallier #include <linux/netdevice.h>
12db9d7d36SMaxime Chevallier #include <linux/etherdevice.h>
13db9d7d36SMaxime Chevallier #include <linux/platform_device.h>
14db9d7d36SMaxime Chevallier #include <uapi/linux/ppp_defs.h>
15db9d7d36SMaxime Chevallier #include <net/ip.h>
16db9d7d36SMaxime Chevallier #include <net/ipv6.h>
17db9d7d36SMaxime Chevallier 
18db9d7d36SMaxime Chevallier #include "mvpp2.h"
19db9d7d36SMaxime Chevallier #include "mvpp2_prs.h"
20db9d7d36SMaxime Chevallier 
21db9d7d36SMaxime Chevallier /* Update parser tcam and sram hw entries */
mvpp2_prs_hw_write(struct mvpp2 * priv,struct mvpp2_prs_entry * pe)22db9d7d36SMaxime Chevallier static int mvpp2_prs_hw_write(struct mvpp2 *priv, struct mvpp2_prs_entry *pe)
23db9d7d36SMaxime Chevallier {
24db9d7d36SMaxime Chevallier 	int i;
25db9d7d36SMaxime Chevallier 
26db9d7d36SMaxime Chevallier 	if (pe->index > MVPP2_PRS_TCAM_SRAM_SIZE - 1)
27db9d7d36SMaxime Chevallier 		return -EINVAL;
28db9d7d36SMaxime Chevallier 
29db9d7d36SMaxime Chevallier 	/* Clear entry invalidation bit */
30bd43d1baSMaxime Chevallier 	pe->tcam[MVPP2_PRS_TCAM_INV_WORD] &= ~MVPP2_PRS_TCAM_INV_MASK;
31db9d7d36SMaxime Chevallier 
32db9d7d36SMaxime Chevallier 	/* Write sram index - indirect access */
33db9d7d36SMaxime Chevallier 	mvpp2_write(priv, MVPP2_PRS_SRAM_IDX_REG, pe->index);
34db9d7d36SMaxime Chevallier 	for (i = 0; i < MVPP2_PRS_SRAM_WORDS; i++)
35bd43d1baSMaxime Chevallier 		mvpp2_write(priv, MVPP2_PRS_SRAM_DATA_REG(i), pe->sram[i]);
36db9d7d36SMaxime Chevallier 
3743f4a20aSStefan Chulski 	/* Write tcam index - indirect access */
3843f4a20aSStefan Chulski 	mvpp2_write(priv, MVPP2_PRS_TCAM_IDX_REG, pe->index);
3943f4a20aSStefan Chulski 	for (i = 0; i < MVPP2_PRS_TCAM_WORDS; i++)
4043f4a20aSStefan Chulski 		mvpp2_write(priv, MVPP2_PRS_TCAM_DATA_REG(i), pe->tcam[i]);
4143f4a20aSStefan Chulski 
42db9d7d36SMaxime Chevallier 	return 0;
43db9d7d36SMaxime Chevallier }
44db9d7d36SMaxime Chevallier 
45db9d7d36SMaxime Chevallier /* Initialize tcam entry from hw */
mvpp2_prs_init_from_hw(struct mvpp2 * priv,struct mvpp2_prs_entry * pe,int tid)4621da57a2SMaxime Chevallier int mvpp2_prs_init_from_hw(struct mvpp2 *priv, struct mvpp2_prs_entry *pe,
4721da57a2SMaxime Chevallier 			   int tid)
48db9d7d36SMaxime Chevallier {
49db9d7d36SMaxime Chevallier 	int i;
50db9d7d36SMaxime Chevallier 
51db9d7d36SMaxime Chevallier 	if (tid > MVPP2_PRS_TCAM_SRAM_SIZE - 1)
52db9d7d36SMaxime Chevallier 		return -EINVAL;
53db9d7d36SMaxime Chevallier 
54db9d7d36SMaxime Chevallier 	memset(pe, 0, sizeof(*pe));
55db9d7d36SMaxime Chevallier 	pe->index = tid;
56db9d7d36SMaxime Chevallier 
57db9d7d36SMaxime Chevallier 	/* Write tcam index - indirect access */
58db9d7d36SMaxime Chevallier 	mvpp2_write(priv, MVPP2_PRS_TCAM_IDX_REG, pe->index);
59db9d7d36SMaxime Chevallier 
60bd43d1baSMaxime Chevallier 	pe->tcam[MVPP2_PRS_TCAM_INV_WORD] = mvpp2_read(priv,
61db9d7d36SMaxime Chevallier 			      MVPP2_PRS_TCAM_DATA_REG(MVPP2_PRS_TCAM_INV_WORD));
62bd43d1baSMaxime Chevallier 	if (pe->tcam[MVPP2_PRS_TCAM_INV_WORD] & MVPP2_PRS_TCAM_INV_MASK)
63db9d7d36SMaxime Chevallier 		return MVPP2_PRS_TCAM_ENTRY_INVALID;
64db9d7d36SMaxime Chevallier 
65db9d7d36SMaxime Chevallier 	for (i = 0; i < MVPP2_PRS_TCAM_WORDS; i++)
66bd43d1baSMaxime Chevallier 		pe->tcam[i] = mvpp2_read(priv, MVPP2_PRS_TCAM_DATA_REG(i));
67db9d7d36SMaxime Chevallier 
68db9d7d36SMaxime Chevallier 	/* Write sram index - indirect access */
69db9d7d36SMaxime Chevallier 	mvpp2_write(priv, MVPP2_PRS_SRAM_IDX_REG, pe->index);
70db9d7d36SMaxime Chevallier 	for (i = 0; i < MVPP2_PRS_SRAM_WORDS; i++)
71bd43d1baSMaxime Chevallier 		pe->sram[i] = mvpp2_read(priv, MVPP2_PRS_SRAM_DATA_REG(i));
72db9d7d36SMaxime Chevallier 
73db9d7d36SMaxime Chevallier 	return 0;
74db9d7d36SMaxime Chevallier }
75db9d7d36SMaxime Chevallier 
76db9d7d36SMaxime Chevallier /* Invalidate tcam hw entry */
mvpp2_prs_hw_inv(struct mvpp2 * priv,int index)77db9d7d36SMaxime Chevallier static void mvpp2_prs_hw_inv(struct mvpp2 *priv, int index)
78db9d7d36SMaxime Chevallier {
79db9d7d36SMaxime Chevallier 	/* Write index - indirect access */
80db9d7d36SMaxime Chevallier 	mvpp2_write(priv, MVPP2_PRS_TCAM_IDX_REG, index);
81db9d7d36SMaxime Chevallier 	mvpp2_write(priv, MVPP2_PRS_TCAM_DATA_REG(MVPP2_PRS_TCAM_INV_WORD),
82db9d7d36SMaxime Chevallier 		    MVPP2_PRS_TCAM_INV_MASK);
83db9d7d36SMaxime Chevallier }
84db9d7d36SMaxime Chevallier 
85db9d7d36SMaxime Chevallier /* Enable shadow table entry and set its lookup ID */
mvpp2_prs_shadow_set(struct mvpp2 * priv,int index,int lu)86db9d7d36SMaxime Chevallier static void mvpp2_prs_shadow_set(struct mvpp2 *priv, int index, int lu)
87db9d7d36SMaxime Chevallier {
88db9d7d36SMaxime Chevallier 	priv->prs_shadow[index].valid = true;
89db9d7d36SMaxime Chevallier 	priv->prs_shadow[index].lu = lu;
90db9d7d36SMaxime Chevallier }
91db9d7d36SMaxime Chevallier 
92db9d7d36SMaxime Chevallier /* Update ri fields in shadow table entry */
mvpp2_prs_shadow_ri_set(struct mvpp2 * priv,int index,unsigned int ri,unsigned int ri_mask)93db9d7d36SMaxime Chevallier static void mvpp2_prs_shadow_ri_set(struct mvpp2 *priv, int index,
94db9d7d36SMaxime Chevallier 				    unsigned int ri, unsigned int ri_mask)
95db9d7d36SMaxime Chevallier {
96db9d7d36SMaxime Chevallier 	priv->prs_shadow[index].ri_mask = ri_mask;
97db9d7d36SMaxime Chevallier 	priv->prs_shadow[index].ri = ri;
98db9d7d36SMaxime Chevallier }
99db9d7d36SMaxime Chevallier 
100db9d7d36SMaxime Chevallier /* Update lookup field in tcam sw entry */
mvpp2_prs_tcam_lu_set(struct mvpp2_prs_entry * pe,unsigned int lu)101db9d7d36SMaxime Chevallier static void mvpp2_prs_tcam_lu_set(struct mvpp2_prs_entry *pe, unsigned int lu)
102db9d7d36SMaxime Chevallier {
103bd43d1baSMaxime Chevallier 	pe->tcam[MVPP2_PRS_TCAM_LU_WORD] &= ~MVPP2_PRS_TCAM_LU(MVPP2_PRS_LU_MASK);
104bd43d1baSMaxime Chevallier 	pe->tcam[MVPP2_PRS_TCAM_LU_WORD] &= ~MVPP2_PRS_TCAM_LU_EN(MVPP2_PRS_LU_MASK);
105bd43d1baSMaxime Chevallier 	pe->tcam[MVPP2_PRS_TCAM_LU_WORD] |= MVPP2_PRS_TCAM_LU(lu & MVPP2_PRS_LU_MASK);
106bd43d1baSMaxime Chevallier 	pe->tcam[MVPP2_PRS_TCAM_LU_WORD] |= MVPP2_PRS_TCAM_LU_EN(MVPP2_PRS_LU_MASK);
107db9d7d36SMaxime Chevallier }
108db9d7d36SMaxime Chevallier 
109db9d7d36SMaxime Chevallier /* Update mask for single port in tcam sw entry */
mvpp2_prs_tcam_port_set(struct mvpp2_prs_entry * pe,unsigned int port,bool add)110db9d7d36SMaxime Chevallier static void mvpp2_prs_tcam_port_set(struct mvpp2_prs_entry *pe,
111db9d7d36SMaxime Chevallier 				    unsigned int port, bool add)
112db9d7d36SMaxime Chevallier {
113db9d7d36SMaxime Chevallier 	if (add)
114bd43d1baSMaxime Chevallier 		pe->tcam[MVPP2_PRS_TCAM_PORT_WORD] &= ~MVPP2_PRS_TCAM_PORT_EN(BIT(port));
115db9d7d36SMaxime Chevallier 	else
116bd43d1baSMaxime Chevallier 		pe->tcam[MVPP2_PRS_TCAM_PORT_WORD] |= MVPP2_PRS_TCAM_PORT_EN(BIT(port));
117db9d7d36SMaxime Chevallier }
118db9d7d36SMaxime Chevallier 
119db9d7d36SMaxime Chevallier /* Update port map in tcam sw entry */
mvpp2_prs_tcam_port_map_set(struct mvpp2_prs_entry * pe,unsigned int ports)120db9d7d36SMaxime Chevallier static void mvpp2_prs_tcam_port_map_set(struct mvpp2_prs_entry *pe,
121db9d7d36SMaxime Chevallier 					unsigned int ports)
122db9d7d36SMaxime Chevallier {
123bd43d1baSMaxime Chevallier 	pe->tcam[MVPP2_PRS_TCAM_PORT_WORD] &= ~MVPP2_PRS_TCAM_PORT(MVPP2_PRS_PORT_MASK);
124bd43d1baSMaxime Chevallier 	pe->tcam[MVPP2_PRS_TCAM_PORT_WORD] &= ~MVPP2_PRS_TCAM_PORT_EN(MVPP2_PRS_PORT_MASK);
125bd43d1baSMaxime Chevallier 	pe->tcam[MVPP2_PRS_TCAM_PORT_WORD] |= MVPP2_PRS_TCAM_PORT_EN(~ports & MVPP2_PRS_PORT_MASK);
126db9d7d36SMaxime Chevallier }
127db9d7d36SMaxime Chevallier 
128db9d7d36SMaxime Chevallier /* Obtain port map from tcam sw entry */
mvpp2_prs_tcam_port_map_get(struct mvpp2_prs_entry * pe)12921da57a2SMaxime Chevallier unsigned int mvpp2_prs_tcam_port_map_get(struct mvpp2_prs_entry *pe)
130db9d7d36SMaxime Chevallier {
131bd43d1baSMaxime Chevallier 	return (~pe->tcam[MVPP2_PRS_TCAM_PORT_WORD] >> 24) & MVPP2_PRS_PORT_MASK;
132db9d7d36SMaxime Chevallier }
133db9d7d36SMaxime Chevallier 
134db9d7d36SMaxime Chevallier /* Set byte of data and its enable bits in tcam sw entry */
mvpp2_prs_tcam_data_byte_set(struct mvpp2_prs_entry * pe,unsigned int offs,unsigned char byte,unsigned char enable)135db9d7d36SMaxime Chevallier static void mvpp2_prs_tcam_data_byte_set(struct mvpp2_prs_entry *pe,
136db9d7d36SMaxime Chevallier 					 unsigned int offs, unsigned char byte,
137db9d7d36SMaxime Chevallier 					 unsigned char enable)
138db9d7d36SMaxime Chevallier {
139bd43d1baSMaxime Chevallier 	int pos = MVPP2_PRS_BYTE_IN_WORD(offs) * BITS_PER_BYTE;
140bd43d1baSMaxime Chevallier 
141bd43d1baSMaxime Chevallier 	pe->tcam[MVPP2_PRS_BYTE_TO_WORD(offs)] &= ~(0xff << pos);
142bd43d1baSMaxime Chevallier 	pe->tcam[MVPP2_PRS_BYTE_TO_WORD(offs)] &= ~(MVPP2_PRS_TCAM_EN(0xff) << pos);
143bd43d1baSMaxime Chevallier 	pe->tcam[MVPP2_PRS_BYTE_TO_WORD(offs)] |= byte << pos;
144bd43d1baSMaxime Chevallier 	pe->tcam[MVPP2_PRS_BYTE_TO_WORD(offs)] |= MVPP2_PRS_TCAM_EN(enable << pos);
145db9d7d36SMaxime Chevallier }
146db9d7d36SMaxime Chevallier 
147db9d7d36SMaxime Chevallier /* Get byte of data and its enable bits from tcam sw entry */
mvpp2_prs_tcam_data_byte_get(struct mvpp2_prs_entry * pe,unsigned int offs,unsigned char * byte,unsigned char * enable)14821da57a2SMaxime Chevallier void mvpp2_prs_tcam_data_byte_get(struct mvpp2_prs_entry *pe,
149db9d7d36SMaxime Chevallier 				  unsigned int offs, unsigned char *byte,
150db9d7d36SMaxime Chevallier 				  unsigned char *enable)
151db9d7d36SMaxime Chevallier {
152bd43d1baSMaxime Chevallier 	int pos = MVPP2_PRS_BYTE_IN_WORD(offs) * BITS_PER_BYTE;
153bd43d1baSMaxime Chevallier 
154bd43d1baSMaxime Chevallier 	*byte = (pe->tcam[MVPP2_PRS_BYTE_TO_WORD(offs)] >> pos) & 0xff;
155bd43d1baSMaxime Chevallier 	*enable = (pe->tcam[MVPP2_PRS_BYTE_TO_WORD(offs)] >> (pos + 16)) & 0xff;
156db9d7d36SMaxime Chevallier }
157db9d7d36SMaxime Chevallier 
158db9d7d36SMaxime Chevallier /* Compare tcam data bytes with a pattern */
mvpp2_prs_tcam_data_cmp(struct mvpp2_prs_entry * pe,int offs,u16 data)159db9d7d36SMaxime Chevallier static bool mvpp2_prs_tcam_data_cmp(struct mvpp2_prs_entry *pe, int offs,
160db9d7d36SMaxime Chevallier 				    u16 data)
161db9d7d36SMaxime Chevallier {
162db9d7d36SMaxime Chevallier 	u16 tcam_data;
163db9d7d36SMaxime Chevallier 
164bd43d1baSMaxime Chevallier 	tcam_data = pe->tcam[MVPP2_PRS_BYTE_TO_WORD(offs)] & 0xffff;
165bd43d1baSMaxime Chevallier 	return tcam_data == data;
166db9d7d36SMaxime Chevallier }
167db9d7d36SMaxime Chevallier 
168db9d7d36SMaxime Chevallier /* Update ai bits in tcam sw entry */
mvpp2_prs_tcam_ai_update(struct mvpp2_prs_entry * pe,unsigned int bits,unsigned int enable)169db9d7d36SMaxime Chevallier static void mvpp2_prs_tcam_ai_update(struct mvpp2_prs_entry *pe,
170db9d7d36SMaxime Chevallier 				     unsigned int bits, unsigned int enable)
171db9d7d36SMaxime Chevallier {
172bd43d1baSMaxime Chevallier 	int i;
173db9d7d36SMaxime Chevallier 
174db9d7d36SMaxime Chevallier 	for (i = 0; i < MVPP2_PRS_AI_BITS; i++) {
175db9d7d36SMaxime Chevallier 		if (!(enable & BIT(i)))
176db9d7d36SMaxime Chevallier 			continue;
177db9d7d36SMaxime Chevallier 
178db9d7d36SMaxime Chevallier 		if (bits & BIT(i))
179bd43d1baSMaxime Chevallier 			pe->tcam[MVPP2_PRS_TCAM_AI_WORD] |= BIT(i);
180db9d7d36SMaxime Chevallier 		else
181bd43d1baSMaxime Chevallier 			pe->tcam[MVPP2_PRS_TCAM_AI_WORD] &= ~BIT(i);
182db9d7d36SMaxime Chevallier 	}
183db9d7d36SMaxime Chevallier 
184bd43d1baSMaxime Chevallier 	pe->tcam[MVPP2_PRS_TCAM_AI_WORD] |= MVPP2_PRS_TCAM_AI_EN(enable);
185db9d7d36SMaxime Chevallier }
186db9d7d36SMaxime Chevallier 
187db9d7d36SMaxime Chevallier /* Get ai bits from tcam sw entry */
mvpp2_prs_tcam_ai_get(struct mvpp2_prs_entry * pe)188db9d7d36SMaxime Chevallier static int mvpp2_prs_tcam_ai_get(struct mvpp2_prs_entry *pe)
189db9d7d36SMaxime Chevallier {
190bd43d1baSMaxime Chevallier 	return pe->tcam[MVPP2_PRS_TCAM_AI_WORD] & MVPP2_PRS_AI_MASK;
191db9d7d36SMaxime Chevallier }
192db9d7d36SMaxime Chevallier 
193db9d7d36SMaxime Chevallier /* Set ethertype in tcam sw entry */
mvpp2_prs_match_etype(struct mvpp2_prs_entry * pe,int offset,unsigned short ethertype)194db9d7d36SMaxime Chevallier static void mvpp2_prs_match_etype(struct mvpp2_prs_entry *pe, int offset,
195db9d7d36SMaxime Chevallier 				  unsigned short ethertype)
196db9d7d36SMaxime Chevallier {
197db9d7d36SMaxime Chevallier 	mvpp2_prs_tcam_data_byte_set(pe, offset + 0, ethertype >> 8, 0xff);
198db9d7d36SMaxime Chevallier 	mvpp2_prs_tcam_data_byte_set(pe, offset + 1, ethertype & 0xff, 0xff);
199db9d7d36SMaxime Chevallier }
200db9d7d36SMaxime Chevallier 
201db9d7d36SMaxime Chevallier /* Set vid in tcam sw entry */
mvpp2_prs_match_vid(struct mvpp2_prs_entry * pe,int offset,unsigned short vid)202db9d7d36SMaxime Chevallier static void mvpp2_prs_match_vid(struct mvpp2_prs_entry *pe, int offset,
203db9d7d36SMaxime Chevallier 				unsigned short vid)
204db9d7d36SMaxime Chevallier {
205db9d7d36SMaxime Chevallier 	mvpp2_prs_tcam_data_byte_set(pe, offset + 0, (vid & 0xf00) >> 8, 0xf);
206db9d7d36SMaxime Chevallier 	mvpp2_prs_tcam_data_byte_set(pe, offset + 1, vid & 0xff, 0xff);
207db9d7d36SMaxime Chevallier }
208db9d7d36SMaxime Chevallier 
209db9d7d36SMaxime Chevallier /* Set bits in sram sw entry */
mvpp2_prs_sram_bits_set(struct mvpp2_prs_entry * pe,int bit_num,u32 val)210db9d7d36SMaxime Chevallier static void mvpp2_prs_sram_bits_set(struct mvpp2_prs_entry *pe, int bit_num,
211bd43d1baSMaxime Chevallier 				    u32 val)
212db9d7d36SMaxime Chevallier {
213bd43d1baSMaxime Chevallier 	pe->sram[MVPP2_BIT_TO_WORD(bit_num)] |= (val << (MVPP2_BIT_IN_WORD(bit_num)));
214db9d7d36SMaxime Chevallier }
215db9d7d36SMaxime Chevallier 
216db9d7d36SMaxime Chevallier /* Clear bits in sram sw entry */
mvpp2_prs_sram_bits_clear(struct mvpp2_prs_entry * pe,int bit_num,u32 val)217db9d7d36SMaxime Chevallier static void mvpp2_prs_sram_bits_clear(struct mvpp2_prs_entry *pe, int bit_num,
218bd43d1baSMaxime Chevallier 				      u32 val)
219db9d7d36SMaxime Chevallier {
220bd43d1baSMaxime Chevallier 	pe->sram[MVPP2_BIT_TO_WORD(bit_num)] &= ~(val << (MVPP2_BIT_IN_WORD(bit_num)));
221db9d7d36SMaxime Chevallier }
222db9d7d36SMaxime Chevallier 
223db9d7d36SMaxime Chevallier /* Update ri bits in sram sw entry */
mvpp2_prs_sram_ri_update(struct mvpp2_prs_entry * pe,unsigned int bits,unsigned int mask)224db9d7d36SMaxime Chevallier static void mvpp2_prs_sram_ri_update(struct mvpp2_prs_entry *pe,
225db9d7d36SMaxime Chevallier 				     unsigned int bits, unsigned int mask)
226db9d7d36SMaxime Chevallier {
227db9d7d36SMaxime Chevallier 	unsigned int i;
228db9d7d36SMaxime Chevallier 
229db9d7d36SMaxime Chevallier 	for (i = 0; i < MVPP2_PRS_SRAM_RI_CTRL_BITS; i++) {
230db9d7d36SMaxime Chevallier 		if (!(mask & BIT(i)))
231db9d7d36SMaxime Chevallier 			continue;
232db9d7d36SMaxime Chevallier 
233db9d7d36SMaxime Chevallier 		if (bits & BIT(i))
234bd43d1baSMaxime Chevallier 			mvpp2_prs_sram_bits_set(pe, MVPP2_PRS_SRAM_RI_OFFS + i,
235bd43d1baSMaxime Chevallier 						1);
236db9d7d36SMaxime Chevallier 		else
237bd43d1baSMaxime Chevallier 			mvpp2_prs_sram_bits_clear(pe,
238bd43d1baSMaxime Chevallier 						  MVPP2_PRS_SRAM_RI_OFFS + i,
239bd43d1baSMaxime Chevallier 						  1);
240db9d7d36SMaxime Chevallier 
241db9d7d36SMaxime Chevallier 		mvpp2_prs_sram_bits_set(pe, MVPP2_PRS_SRAM_RI_CTRL_OFFS + i, 1);
242db9d7d36SMaxime Chevallier 	}
243db9d7d36SMaxime Chevallier }
244db9d7d36SMaxime Chevallier 
245db9d7d36SMaxime Chevallier /* Obtain ri bits from sram sw entry */
mvpp2_prs_sram_ri_get(struct mvpp2_prs_entry * pe)246db9d7d36SMaxime Chevallier static int mvpp2_prs_sram_ri_get(struct mvpp2_prs_entry *pe)
247db9d7d36SMaxime Chevallier {
248bd43d1baSMaxime Chevallier 	return pe->sram[MVPP2_PRS_SRAM_RI_WORD];
249db9d7d36SMaxime Chevallier }
250db9d7d36SMaxime Chevallier 
251db9d7d36SMaxime Chevallier /* Update ai bits in sram sw entry */
mvpp2_prs_sram_ai_update(struct mvpp2_prs_entry * pe,unsigned int bits,unsigned int mask)252db9d7d36SMaxime Chevallier static void mvpp2_prs_sram_ai_update(struct mvpp2_prs_entry *pe,
253db9d7d36SMaxime Chevallier 				     unsigned int bits, unsigned int mask)
254db9d7d36SMaxime Chevallier {
255db9d7d36SMaxime Chevallier 	unsigned int i;
256db9d7d36SMaxime Chevallier 
257db9d7d36SMaxime Chevallier 	for (i = 0; i < MVPP2_PRS_SRAM_AI_CTRL_BITS; i++) {
258db9d7d36SMaxime Chevallier 		if (!(mask & BIT(i)))
259db9d7d36SMaxime Chevallier 			continue;
260db9d7d36SMaxime Chevallier 
261db9d7d36SMaxime Chevallier 		if (bits & BIT(i))
262bd43d1baSMaxime Chevallier 			mvpp2_prs_sram_bits_set(pe, MVPP2_PRS_SRAM_AI_OFFS + i,
263bd43d1baSMaxime Chevallier 						1);
264db9d7d36SMaxime Chevallier 		else
265bd43d1baSMaxime Chevallier 			mvpp2_prs_sram_bits_clear(pe,
266bd43d1baSMaxime Chevallier 						  MVPP2_PRS_SRAM_AI_OFFS + i,
267bd43d1baSMaxime Chevallier 						  1);
268db9d7d36SMaxime Chevallier 
269db9d7d36SMaxime Chevallier 		mvpp2_prs_sram_bits_set(pe, MVPP2_PRS_SRAM_AI_CTRL_OFFS + i, 1);
270db9d7d36SMaxime Chevallier 	}
271db9d7d36SMaxime Chevallier }
272db9d7d36SMaxime Chevallier 
273db9d7d36SMaxime Chevallier /* Read ai bits from sram sw entry */
mvpp2_prs_sram_ai_get(struct mvpp2_prs_entry * pe)274db9d7d36SMaxime Chevallier static int mvpp2_prs_sram_ai_get(struct mvpp2_prs_entry *pe)
275db9d7d36SMaxime Chevallier {
276db9d7d36SMaxime Chevallier 	u8 bits;
277bd43d1baSMaxime Chevallier 	/* ai is stored on bits 90->97; so it spreads across two u32 */
278bd43d1baSMaxime Chevallier 	int ai_off = MVPP2_BIT_TO_WORD(MVPP2_PRS_SRAM_AI_OFFS);
279bd43d1baSMaxime Chevallier 	int ai_shift = MVPP2_BIT_IN_WORD(MVPP2_PRS_SRAM_AI_OFFS);
280db9d7d36SMaxime Chevallier 
281bd43d1baSMaxime Chevallier 	bits = (pe->sram[ai_off] >> ai_shift) |
282bd43d1baSMaxime Chevallier 	       (pe->sram[ai_off + 1] << (32 - ai_shift));
283db9d7d36SMaxime Chevallier 
284db9d7d36SMaxime Chevallier 	return bits;
285db9d7d36SMaxime Chevallier }
286db9d7d36SMaxime Chevallier 
287db9d7d36SMaxime Chevallier /* In sram sw entry set lookup ID field of the tcam key to be used in the next
288db9d7d36SMaxime Chevallier  * lookup interation
289db9d7d36SMaxime Chevallier  */
mvpp2_prs_sram_next_lu_set(struct mvpp2_prs_entry * pe,unsigned int lu)290db9d7d36SMaxime Chevallier static void mvpp2_prs_sram_next_lu_set(struct mvpp2_prs_entry *pe,
291db9d7d36SMaxime Chevallier 				       unsigned int lu)
292db9d7d36SMaxime Chevallier {
293db9d7d36SMaxime Chevallier 	int sram_next_off = MVPP2_PRS_SRAM_NEXT_LU_OFFS;
294db9d7d36SMaxime Chevallier 
295db9d7d36SMaxime Chevallier 	mvpp2_prs_sram_bits_clear(pe, sram_next_off,
296db9d7d36SMaxime Chevallier 				  MVPP2_PRS_SRAM_NEXT_LU_MASK);
297db9d7d36SMaxime Chevallier 	mvpp2_prs_sram_bits_set(pe, sram_next_off, lu);
298db9d7d36SMaxime Chevallier }
299db9d7d36SMaxime Chevallier 
300db9d7d36SMaxime Chevallier /* In the sram sw entry set sign and value of the next lookup offset
301db9d7d36SMaxime Chevallier  * and the offset value generated to the classifier
302db9d7d36SMaxime Chevallier  */
mvpp2_prs_sram_shift_set(struct mvpp2_prs_entry * pe,int shift,unsigned int op)303db9d7d36SMaxime Chevallier static void mvpp2_prs_sram_shift_set(struct mvpp2_prs_entry *pe, int shift,
304db9d7d36SMaxime Chevallier 				     unsigned int op)
305db9d7d36SMaxime Chevallier {
306db9d7d36SMaxime Chevallier 	/* Set sign */
307db9d7d36SMaxime Chevallier 	if (shift < 0) {
308db9d7d36SMaxime Chevallier 		mvpp2_prs_sram_bits_set(pe, MVPP2_PRS_SRAM_SHIFT_SIGN_BIT, 1);
309db9d7d36SMaxime Chevallier 		shift = 0 - shift;
310db9d7d36SMaxime Chevallier 	} else {
311db9d7d36SMaxime Chevallier 		mvpp2_prs_sram_bits_clear(pe, MVPP2_PRS_SRAM_SHIFT_SIGN_BIT, 1);
312db9d7d36SMaxime Chevallier 	}
313db9d7d36SMaxime Chevallier 
314db9d7d36SMaxime Chevallier 	/* Set value */
3158ec3ede5SMaxime Chevallier 	pe->sram[MVPP2_BIT_TO_WORD(MVPP2_PRS_SRAM_SHIFT_OFFS)] |=
3168ec3ede5SMaxime Chevallier 		shift & MVPP2_PRS_SRAM_SHIFT_MASK;
317db9d7d36SMaxime Chevallier 
318db9d7d36SMaxime Chevallier 	/* Reset and set operation */
319db9d7d36SMaxime Chevallier 	mvpp2_prs_sram_bits_clear(pe, MVPP2_PRS_SRAM_OP_SEL_SHIFT_OFFS,
320db9d7d36SMaxime Chevallier 				  MVPP2_PRS_SRAM_OP_SEL_SHIFT_MASK);
321db9d7d36SMaxime Chevallier 	mvpp2_prs_sram_bits_set(pe, MVPP2_PRS_SRAM_OP_SEL_SHIFT_OFFS, op);
322db9d7d36SMaxime Chevallier 
323db9d7d36SMaxime Chevallier 	/* Set base offset as current */
324db9d7d36SMaxime Chevallier 	mvpp2_prs_sram_bits_clear(pe, MVPP2_PRS_SRAM_OP_SEL_BASE_OFFS, 1);
325db9d7d36SMaxime Chevallier }
326db9d7d36SMaxime Chevallier 
327db9d7d36SMaxime Chevallier /* In the sram sw entry set sign and value of the user defined offset
328db9d7d36SMaxime Chevallier  * generated to the classifier
329db9d7d36SMaxime Chevallier  */
mvpp2_prs_sram_offset_set(struct mvpp2_prs_entry * pe,unsigned int type,int offset,unsigned int op)330db9d7d36SMaxime Chevallier static void mvpp2_prs_sram_offset_set(struct mvpp2_prs_entry *pe,
331db9d7d36SMaxime Chevallier 				      unsigned int type, int offset,
332db9d7d36SMaxime Chevallier 				      unsigned int op)
333db9d7d36SMaxime Chevallier {
334db9d7d36SMaxime Chevallier 	/* Set sign */
335db9d7d36SMaxime Chevallier 	if (offset < 0) {
336db9d7d36SMaxime Chevallier 		mvpp2_prs_sram_bits_set(pe, MVPP2_PRS_SRAM_UDF_SIGN_BIT, 1);
337db9d7d36SMaxime Chevallier 		offset = 0 - offset;
338db9d7d36SMaxime Chevallier 	} else {
339db9d7d36SMaxime Chevallier 		mvpp2_prs_sram_bits_clear(pe, MVPP2_PRS_SRAM_UDF_SIGN_BIT, 1);
340db9d7d36SMaxime Chevallier 	}
341db9d7d36SMaxime Chevallier 
342db9d7d36SMaxime Chevallier 	/* Set value */
343db9d7d36SMaxime Chevallier 	mvpp2_prs_sram_bits_clear(pe, MVPP2_PRS_SRAM_UDF_OFFS,
344db9d7d36SMaxime Chevallier 				  MVPP2_PRS_SRAM_UDF_MASK);
345bd43d1baSMaxime Chevallier 	mvpp2_prs_sram_bits_set(pe, MVPP2_PRS_SRAM_UDF_OFFS,
346bd43d1baSMaxime Chevallier 				offset & MVPP2_PRS_SRAM_UDF_MASK);
347db9d7d36SMaxime Chevallier 
348db9d7d36SMaxime Chevallier 	/* Set offset type */
349db9d7d36SMaxime Chevallier 	mvpp2_prs_sram_bits_clear(pe, MVPP2_PRS_SRAM_UDF_TYPE_OFFS,
350db9d7d36SMaxime Chevallier 				  MVPP2_PRS_SRAM_UDF_TYPE_MASK);
351db9d7d36SMaxime Chevallier 	mvpp2_prs_sram_bits_set(pe, MVPP2_PRS_SRAM_UDF_TYPE_OFFS, type);
352db9d7d36SMaxime Chevallier 
353db9d7d36SMaxime Chevallier 	/* Set offset operation */
354db9d7d36SMaxime Chevallier 	mvpp2_prs_sram_bits_clear(pe, MVPP2_PRS_SRAM_OP_SEL_UDF_OFFS,
355db9d7d36SMaxime Chevallier 				  MVPP2_PRS_SRAM_OP_SEL_UDF_MASK);
356bd43d1baSMaxime Chevallier 	mvpp2_prs_sram_bits_set(pe, MVPP2_PRS_SRAM_OP_SEL_UDF_OFFS,
357bd43d1baSMaxime Chevallier 				op & MVPP2_PRS_SRAM_OP_SEL_UDF_MASK);
358db9d7d36SMaxime Chevallier 
359db9d7d36SMaxime Chevallier 	/* Set base offset as current */
360db9d7d36SMaxime Chevallier 	mvpp2_prs_sram_bits_clear(pe, MVPP2_PRS_SRAM_OP_SEL_BASE_OFFS, 1);
361db9d7d36SMaxime Chevallier }
362db9d7d36SMaxime Chevallier 
363db9d7d36SMaxime Chevallier /* Find parser flow entry */
mvpp2_prs_flow_find(struct mvpp2 * priv,int flow)364db9d7d36SMaxime Chevallier static int mvpp2_prs_flow_find(struct mvpp2 *priv, int flow)
365db9d7d36SMaxime Chevallier {
366db9d7d36SMaxime Chevallier 	struct mvpp2_prs_entry pe;
367db9d7d36SMaxime Chevallier 	int tid;
368db9d7d36SMaxime Chevallier 
369db9d7d36SMaxime Chevallier 	/* Go through the all entires with MVPP2_PRS_LU_FLOWS */
370db9d7d36SMaxime Chevallier 	for (tid = MVPP2_PRS_TCAM_SRAM_SIZE - 1; tid >= 0; tid--) {
371db9d7d36SMaxime Chevallier 		u8 bits;
372db9d7d36SMaxime Chevallier 
373db9d7d36SMaxime Chevallier 		if (!priv->prs_shadow[tid].valid ||
374db9d7d36SMaxime Chevallier 		    priv->prs_shadow[tid].lu != MVPP2_PRS_LU_FLOWS)
375db9d7d36SMaxime Chevallier 			continue;
376db9d7d36SMaxime Chevallier 
377db9d7d36SMaxime Chevallier 		mvpp2_prs_init_from_hw(priv, &pe, tid);
378db9d7d36SMaxime Chevallier 		bits = mvpp2_prs_sram_ai_get(&pe);
379db9d7d36SMaxime Chevallier 
380db9d7d36SMaxime Chevallier 		/* Sram store classification lookup ID in AI bits [5:0] */
381db9d7d36SMaxime Chevallier 		if ((bits & MVPP2_PRS_FLOW_ID_MASK) == flow)
382db9d7d36SMaxime Chevallier 			return tid;
383db9d7d36SMaxime Chevallier 	}
384db9d7d36SMaxime Chevallier 
385db9d7d36SMaxime Chevallier 	return -ENOENT;
386db9d7d36SMaxime Chevallier }
387db9d7d36SMaxime Chevallier 
388db9d7d36SMaxime Chevallier /* Return first free tcam index, seeking from start to end */
mvpp2_prs_tcam_first_free(struct mvpp2 * priv,unsigned char start,unsigned char end)389db9d7d36SMaxime Chevallier static int mvpp2_prs_tcam_first_free(struct mvpp2 *priv, unsigned char start,
390db9d7d36SMaxime Chevallier 				     unsigned char end)
391db9d7d36SMaxime Chevallier {
392db9d7d36SMaxime Chevallier 	int tid;
393db9d7d36SMaxime Chevallier 
394db9d7d36SMaxime Chevallier 	if (start > end)
395db9d7d36SMaxime Chevallier 		swap(start, end);
396db9d7d36SMaxime Chevallier 
397db9d7d36SMaxime Chevallier 	for (tid = start; tid <= end; tid++) {
398db9d7d36SMaxime Chevallier 		if (!priv->prs_shadow[tid].valid)
399db9d7d36SMaxime Chevallier 			return tid;
400db9d7d36SMaxime Chevallier 	}
401db9d7d36SMaxime Chevallier 
402db9d7d36SMaxime Chevallier 	return -EINVAL;
403db9d7d36SMaxime Chevallier }
404db9d7d36SMaxime Chevallier 
4053f48fab6SStefan Chulski /* Drop flow control pause frames */
mvpp2_prs_drop_fc(struct mvpp2 * priv)4063f48fab6SStefan Chulski static void mvpp2_prs_drop_fc(struct mvpp2 *priv)
4073f48fab6SStefan Chulski {
4083f48fab6SStefan Chulski 	unsigned char da[ETH_ALEN] = { 0x01, 0x80, 0xC2, 0x00, 0x00, 0x01 };
4093f48fab6SStefan Chulski 	struct mvpp2_prs_entry pe;
4103f48fab6SStefan Chulski 	unsigned int len;
4113f48fab6SStefan Chulski 
4123f48fab6SStefan Chulski 	memset(&pe, 0, sizeof(pe));
4133f48fab6SStefan Chulski 
4143f48fab6SStefan Chulski 	/* For all ports - drop flow control frames */
4153f48fab6SStefan Chulski 	pe.index = MVPP2_PE_FC_DROP;
4163f48fab6SStefan Chulski 	mvpp2_prs_tcam_lu_set(&pe, MVPP2_PRS_LU_MAC);
4173f48fab6SStefan Chulski 
4183f48fab6SStefan Chulski 	/* Set match on DA */
4193f48fab6SStefan Chulski 	len = ETH_ALEN;
4203f48fab6SStefan Chulski 	while (len--)
4213f48fab6SStefan Chulski 		mvpp2_prs_tcam_data_byte_set(&pe, len, da[len], 0xff);
4223f48fab6SStefan Chulski 
4233f48fab6SStefan Chulski 	mvpp2_prs_sram_ri_update(&pe, MVPP2_PRS_RI_DROP_MASK,
4243f48fab6SStefan Chulski 				 MVPP2_PRS_RI_DROP_MASK);
4253f48fab6SStefan Chulski 
4263f48fab6SStefan Chulski 	mvpp2_prs_sram_bits_set(&pe, MVPP2_PRS_SRAM_LU_GEN_BIT, 1);
4273f48fab6SStefan Chulski 	mvpp2_prs_sram_next_lu_set(&pe, MVPP2_PRS_LU_FLOWS);
4283f48fab6SStefan Chulski 
4293f48fab6SStefan Chulski 	/* Mask all ports */
4303f48fab6SStefan Chulski 	mvpp2_prs_tcam_port_map_set(&pe, MVPP2_PRS_PORT_MASK);
4313f48fab6SStefan Chulski 
4323f48fab6SStefan Chulski 	/* Update shadow table and hw entry */
4333f48fab6SStefan Chulski 	mvpp2_prs_shadow_set(priv, pe.index, MVPP2_PRS_LU_MAC);
4343f48fab6SStefan Chulski 	mvpp2_prs_hw_write(priv, &pe);
4353f48fab6SStefan Chulski }
4363f48fab6SStefan Chulski 
437db9d7d36SMaxime Chevallier /* Enable/disable dropping all mac da's */
mvpp2_prs_mac_drop_all_set(struct mvpp2 * priv,int port,bool add)438db9d7d36SMaxime Chevallier static void mvpp2_prs_mac_drop_all_set(struct mvpp2 *priv, int port, bool add)
439db9d7d36SMaxime Chevallier {
440db9d7d36SMaxime Chevallier 	struct mvpp2_prs_entry pe;
441db9d7d36SMaxime Chevallier 
442db9d7d36SMaxime Chevallier 	if (priv->prs_shadow[MVPP2_PE_DROP_ALL].valid) {
443db9d7d36SMaxime Chevallier 		/* Entry exist - update port only */
444db9d7d36SMaxime Chevallier 		mvpp2_prs_init_from_hw(priv, &pe, MVPP2_PE_DROP_ALL);
445db9d7d36SMaxime Chevallier 	} else {
446db9d7d36SMaxime Chevallier 		/* Entry doesn't exist - create new */
447db9d7d36SMaxime Chevallier 		memset(&pe, 0, sizeof(pe));
448db9d7d36SMaxime Chevallier 		mvpp2_prs_tcam_lu_set(&pe, MVPP2_PRS_LU_MAC);
449db9d7d36SMaxime Chevallier 		pe.index = MVPP2_PE_DROP_ALL;
450db9d7d36SMaxime Chevallier 
451db9d7d36SMaxime Chevallier 		/* Non-promiscuous mode for all ports - DROP unknown packets */
452db9d7d36SMaxime Chevallier 		mvpp2_prs_sram_ri_update(&pe, MVPP2_PRS_RI_DROP_MASK,
453db9d7d36SMaxime Chevallier 					 MVPP2_PRS_RI_DROP_MASK);
454db9d7d36SMaxime Chevallier 
455db9d7d36SMaxime Chevallier 		mvpp2_prs_sram_bits_set(&pe, MVPP2_PRS_SRAM_LU_GEN_BIT, 1);
456db9d7d36SMaxime Chevallier 		mvpp2_prs_sram_next_lu_set(&pe, MVPP2_PRS_LU_FLOWS);
457db9d7d36SMaxime Chevallier 
458db9d7d36SMaxime Chevallier 		/* Update shadow table */
459db9d7d36SMaxime Chevallier 		mvpp2_prs_shadow_set(priv, pe.index, MVPP2_PRS_LU_MAC);
460db9d7d36SMaxime Chevallier 
461db9d7d36SMaxime Chevallier 		/* Mask all ports */
462db9d7d36SMaxime Chevallier 		mvpp2_prs_tcam_port_map_set(&pe, 0);
463db9d7d36SMaxime Chevallier 	}
464db9d7d36SMaxime Chevallier 
465db9d7d36SMaxime Chevallier 	/* Update port mask */
466db9d7d36SMaxime Chevallier 	mvpp2_prs_tcam_port_set(&pe, port, add);
467db9d7d36SMaxime Chevallier 
468db9d7d36SMaxime Chevallier 	mvpp2_prs_hw_write(priv, &pe);
469db9d7d36SMaxime Chevallier }
470db9d7d36SMaxime Chevallier 
471db9d7d36SMaxime Chevallier /* Set port to unicast or multicast promiscuous mode */
mvpp2_prs_mac_promisc_set(struct mvpp2 * priv,int port,enum mvpp2_prs_l2_cast l2_cast,bool add)472db9d7d36SMaxime Chevallier void mvpp2_prs_mac_promisc_set(struct mvpp2 *priv, int port,
473db9d7d36SMaxime Chevallier 			       enum mvpp2_prs_l2_cast l2_cast, bool add)
474db9d7d36SMaxime Chevallier {
475db9d7d36SMaxime Chevallier 	struct mvpp2_prs_entry pe;
476db9d7d36SMaxime Chevallier 	unsigned char cast_match;
477db9d7d36SMaxime Chevallier 	unsigned int ri;
478db9d7d36SMaxime Chevallier 	int tid;
479db9d7d36SMaxime Chevallier 
480db9d7d36SMaxime Chevallier 	if (l2_cast == MVPP2_PRS_L2_UNI_CAST) {
481db9d7d36SMaxime Chevallier 		cast_match = MVPP2_PRS_UCAST_VAL;
482db9d7d36SMaxime Chevallier 		tid = MVPP2_PE_MAC_UC_PROMISCUOUS;
483db9d7d36SMaxime Chevallier 		ri = MVPP2_PRS_RI_L2_UCAST;
484db9d7d36SMaxime Chevallier 	} else {
485db9d7d36SMaxime Chevallier 		cast_match = MVPP2_PRS_MCAST_VAL;
486db9d7d36SMaxime Chevallier 		tid = MVPP2_PE_MAC_MC_PROMISCUOUS;
487db9d7d36SMaxime Chevallier 		ri = MVPP2_PRS_RI_L2_MCAST;
488db9d7d36SMaxime Chevallier 	}
489db9d7d36SMaxime Chevallier 
490db9d7d36SMaxime Chevallier 	/* promiscuous mode - Accept unknown unicast or multicast packets */
491db9d7d36SMaxime Chevallier 	if (priv->prs_shadow[tid].valid) {
492db9d7d36SMaxime Chevallier 		mvpp2_prs_init_from_hw(priv, &pe, tid);
493db9d7d36SMaxime Chevallier 	} else {
494db9d7d36SMaxime Chevallier 		memset(&pe, 0, sizeof(pe));
495db9d7d36SMaxime Chevallier 		mvpp2_prs_tcam_lu_set(&pe, MVPP2_PRS_LU_MAC);
496db9d7d36SMaxime Chevallier 		pe.index = tid;
497db9d7d36SMaxime Chevallier 
498db9d7d36SMaxime Chevallier 		/* Continue - set next lookup */
499db9d7d36SMaxime Chevallier 		mvpp2_prs_sram_next_lu_set(&pe, MVPP2_PRS_LU_DSA);
500db9d7d36SMaxime Chevallier 
501db9d7d36SMaxime Chevallier 		/* Set result info bits */
502db9d7d36SMaxime Chevallier 		mvpp2_prs_sram_ri_update(&pe, ri, MVPP2_PRS_RI_L2_CAST_MASK);
503db9d7d36SMaxime Chevallier 
504db9d7d36SMaxime Chevallier 		/* Match UC or MC addresses */
505db9d7d36SMaxime Chevallier 		mvpp2_prs_tcam_data_byte_set(&pe, 0, cast_match,
506db9d7d36SMaxime Chevallier 					     MVPP2_PRS_CAST_MASK);
507db9d7d36SMaxime Chevallier 
508db9d7d36SMaxime Chevallier 		/* Shift to ethertype */
509db9d7d36SMaxime Chevallier 		mvpp2_prs_sram_shift_set(&pe, 2 * ETH_ALEN,
510db9d7d36SMaxime Chevallier 					 MVPP2_PRS_SRAM_OP_SEL_SHIFT_ADD);
511db9d7d36SMaxime Chevallier 
512db9d7d36SMaxime Chevallier 		/* Mask all ports */
513db9d7d36SMaxime Chevallier 		mvpp2_prs_tcam_port_map_set(&pe, 0);
514db9d7d36SMaxime Chevallier 
515db9d7d36SMaxime Chevallier 		/* Update shadow table */
516db9d7d36SMaxime Chevallier 		mvpp2_prs_shadow_set(priv, pe.index, MVPP2_PRS_LU_MAC);
517db9d7d36SMaxime Chevallier 	}
518db9d7d36SMaxime Chevallier 
519db9d7d36SMaxime Chevallier 	/* Update port mask */
520db9d7d36SMaxime Chevallier 	mvpp2_prs_tcam_port_set(&pe, port, add);
521db9d7d36SMaxime Chevallier 
522db9d7d36SMaxime Chevallier 	mvpp2_prs_hw_write(priv, &pe);
523db9d7d36SMaxime Chevallier }
524db9d7d36SMaxime Chevallier 
525db9d7d36SMaxime Chevallier /* Set entry for dsa packets */
mvpp2_prs_dsa_tag_set(struct mvpp2 * priv,int port,bool add,bool tagged,bool extend)526db9d7d36SMaxime Chevallier static void mvpp2_prs_dsa_tag_set(struct mvpp2 *priv, int port, bool add,
527db9d7d36SMaxime Chevallier 				  bool tagged, bool extend)
528db9d7d36SMaxime Chevallier {
529db9d7d36SMaxime Chevallier 	struct mvpp2_prs_entry pe;
530db9d7d36SMaxime Chevallier 	int tid, shift;
531db9d7d36SMaxime Chevallier 
532db9d7d36SMaxime Chevallier 	if (extend) {
533db9d7d36SMaxime Chevallier 		tid = tagged ? MVPP2_PE_EDSA_TAGGED : MVPP2_PE_EDSA_UNTAGGED;
534db9d7d36SMaxime Chevallier 		shift = 8;
535db9d7d36SMaxime Chevallier 	} else {
536db9d7d36SMaxime Chevallier 		tid = tagged ? MVPP2_PE_DSA_TAGGED : MVPP2_PE_DSA_UNTAGGED;
537db9d7d36SMaxime Chevallier 		shift = 4;
538db9d7d36SMaxime Chevallier 	}
539db9d7d36SMaxime Chevallier 
540db9d7d36SMaxime Chevallier 	if (priv->prs_shadow[tid].valid) {
541db9d7d36SMaxime Chevallier 		/* Entry exist - update port only */
542db9d7d36SMaxime Chevallier 		mvpp2_prs_init_from_hw(priv, &pe, tid);
543db9d7d36SMaxime Chevallier 	} else {
544db9d7d36SMaxime Chevallier 		/* Entry doesn't exist - create new */
545db9d7d36SMaxime Chevallier 		memset(&pe, 0, sizeof(pe));
546db9d7d36SMaxime Chevallier 		mvpp2_prs_tcam_lu_set(&pe, MVPP2_PRS_LU_DSA);
547db9d7d36SMaxime Chevallier 		pe.index = tid;
548db9d7d36SMaxime Chevallier 
549db9d7d36SMaxime Chevallier 		/* Update shadow table */
550db9d7d36SMaxime Chevallier 		mvpp2_prs_shadow_set(priv, pe.index, MVPP2_PRS_LU_DSA);
551db9d7d36SMaxime Chevallier 
552db9d7d36SMaxime Chevallier 		if (tagged) {
553db9d7d36SMaxime Chevallier 			/* Set tagged bit in DSA tag */
554db9d7d36SMaxime Chevallier 			mvpp2_prs_tcam_data_byte_set(&pe, 0,
555db9d7d36SMaxime Chevallier 					     MVPP2_PRS_TCAM_DSA_TAGGED_BIT,
556db9d7d36SMaxime Chevallier 					     MVPP2_PRS_TCAM_DSA_TAGGED_BIT);
557db9d7d36SMaxime Chevallier 
558db9d7d36SMaxime Chevallier 			/* Set ai bits for next iteration */
559db9d7d36SMaxime Chevallier 			if (extend)
560db9d7d36SMaxime Chevallier 				mvpp2_prs_sram_ai_update(&pe, 1,
561db9d7d36SMaxime Chevallier 							MVPP2_PRS_SRAM_AI_MASK);
562db9d7d36SMaxime Chevallier 			else
563db9d7d36SMaxime Chevallier 				mvpp2_prs_sram_ai_update(&pe, 0,
564db9d7d36SMaxime Chevallier 							MVPP2_PRS_SRAM_AI_MASK);
565db9d7d36SMaxime Chevallier 
566db9d7d36SMaxime Chevallier 			/* Set result info bits to 'single vlan' */
567db9d7d36SMaxime Chevallier 			mvpp2_prs_sram_ri_update(&pe, MVPP2_PRS_RI_VLAN_SINGLE,
568db9d7d36SMaxime Chevallier 						 MVPP2_PRS_RI_VLAN_MASK);
569db9d7d36SMaxime Chevallier 			/* If packet is tagged continue check vid filtering */
570db9d7d36SMaxime Chevallier 			mvpp2_prs_sram_next_lu_set(&pe, MVPP2_PRS_LU_VID);
571db9d7d36SMaxime Chevallier 		} else {
572db9d7d36SMaxime Chevallier 			/* Shift 4 bytes for DSA tag or 8 bytes for EDSA tag*/
573db9d7d36SMaxime Chevallier 			mvpp2_prs_sram_shift_set(&pe, shift,
574db9d7d36SMaxime Chevallier 					MVPP2_PRS_SRAM_OP_SEL_SHIFT_ADD);
575db9d7d36SMaxime Chevallier 
576db9d7d36SMaxime Chevallier 			/* Set result info bits to 'no vlans' */
577db9d7d36SMaxime Chevallier 			mvpp2_prs_sram_ri_update(&pe, MVPP2_PRS_RI_VLAN_NONE,
578db9d7d36SMaxime Chevallier 						 MVPP2_PRS_RI_VLAN_MASK);
579db9d7d36SMaxime Chevallier 			mvpp2_prs_sram_next_lu_set(&pe, MVPP2_PRS_LU_L2);
580db9d7d36SMaxime Chevallier 		}
581db9d7d36SMaxime Chevallier 
582db9d7d36SMaxime Chevallier 		/* Mask all ports */
583db9d7d36SMaxime Chevallier 		mvpp2_prs_tcam_port_map_set(&pe, 0);
584db9d7d36SMaxime Chevallier 	}
585db9d7d36SMaxime Chevallier 
586db9d7d36SMaxime Chevallier 	/* Update port mask */
587db9d7d36SMaxime Chevallier 	mvpp2_prs_tcam_port_set(&pe, port, add);
588db9d7d36SMaxime Chevallier 
589db9d7d36SMaxime Chevallier 	mvpp2_prs_hw_write(priv, &pe);
590db9d7d36SMaxime Chevallier }
591db9d7d36SMaxime Chevallier 
592db9d7d36SMaxime Chevallier /* Set entry for dsa ethertype */
mvpp2_prs_dsa_tag_ethertype_set(struct mvpp2 * priv,int port,bool add,bool tagged,bool extend)593db9d7d36SMaxime Chevallier static void mvpp2_prs_dsa_tag_ethertype_set(struct mvpp2 *priv, int port,
594db9d7d36SMaxime Chevallier 					    bool add, bool tagged, bool extend)
595db9d7d36SMaxime Chevallier {
596db9d7d36SMaxime Chevallier 	struct mvpp2_prs_entry pe;
597db9d7d36SMaxime Chevallier 	int tid, shift, port_mask;
598db9d7d36SMaxime Chevallier 
599db9d7d36SMaxime Chevallier 	if (extend) {
600db9d7d36SMaxime Chevallier 		tid = tagged ? MVPP2_PE_ETYPE_EDSA_TAGGED :
601db9d7d36SMaxime Chevallier 		      MVPP2_PE_ETYPE_EDSA_UNTAGGED;
602db9d7d36SMaxime Chevallier 		port_mask = 0;
603db9d7d36SMaxime Chevallier 		shift = 8;
604db9d7d36SMaxime Chevallier 	} else {
605db9d7d36SMaxime Chevallier 		tid = tagged ? MVPP2_PE_ETYPE_DSA_TAGGED :
606db9d7d36SMaxime Chevallier 		      MVPP2_PE_ETYPE_DSA_UNTAGGED;
607db9d7d36SMaxime Chevallier 		port_mask = MVPP2_PRS_PORT_MASK;
608db9d7d36SMaxime Chevallier 		shift = 4;
609db9d7d36SMaxime Chevallier 	}
610db9d7d36SMaxime Chevallier 
611db9d7d36SMaxime Chevallier 	if (priv->prs_shadow[tid].valid) {
612db9d7d36SMaxime Chevallier 		/* Entry exist - update port only */
613db9d7d36SMaxime Chevallier 		mvpp2_prs_init_from_hw(priv, &pe, tid);
614db9d7d36SMaxime Chevallier 	} else {
615db9d7d36SMaxime Chevallier 		/* Entry doesn't exist - create new */
616db9d7d36SMaxime Chevallier 		memset(&pe, 0, sizeof(pe));
617db9d7d36SMaxime Chevallier 		mvpp2_prs_tcam_lu_set(&pe, MVPP2_PRS_LU_DSA);
618db9d7d36SMaxime Chevallier 		pe.index = tid;
619db9d7d36SMaxime Chevallier 
620db9d7d36SMaxime Chevallier 		/* Set ethertype */
621db9d7d36SMaxime Chevallier 		mvpp2_prs_match_etype(&pe, 0, ETH_P_EDSA);
622db9d7d36SMaxime Chevallier 		mvpp2_prs_match_etype(&pe, 2, 0);
623db9d7d36SMaxime Chevallier 
624db9d7d36SMaxime Chevallier 		mvpp2_prs_sram_ri_update(&pe, MVPP2_PRS_RI_DSA_MASK,
625db9d7d36SMaxime Chevallier 					 MVPP2_PRS_RI_DSA_MASK);
626db9d7d36SMaxime Chevallier 		/* Shift ethertype + 2 byte reserved + tag*/
627db9d7d36SMaxime Chevallier 		mvpp2_prs_sram_shift_set(&pe, 2 + MVPP2_ETH_TYPE_LEN + shift,
628db9d7d36SMaxime Chevallier 					 MVPP2_PRS_SRAM_OP_SEL_SHIFT_ADD);
629db9d7d36SMaxime Chevallier 
630db9d7d36SMaxime Chevallier 		/* Update shadow table */
631db9d7d36SMaxime Chevallier 		mvpp2_prs_shadow_set(priv, pe.index, MVPP2_PRS_LU_DSA);
632db9d7d36SMaxime Chevallier 
633db9d7d36SMaxime Chevallier 		if (tagged) {
634db9d7d36SMaxime Chevallier 			/* Set tagged bit in DSA tag */
635db9d7d36SMaxime Chevallier 			mvpp2_prs_tcam_data_byte_set(&pe,
636db9d7d36SMaxime Chevallier 						     MVPP2_ETH_TYPE_LEN + 2 + 3,
637db9d7d36SMaxime Chevallier 						 MVPP2_PRS_TCAM_DSA_TAGGED_BIT,
638db9d7d36SMaxime Chevallier 						 MVPP2_PRS_TCAM_DSA_TAGGED_BIT);
639db9d7d36SMaxime Chevallier 			/* Clear all ai bits for next iteration */
640db9d7d36SMaxime Chevallier 			mvpp2_prs_sram_ai_update(&pe, 0,
641db9d7d36SMaxime Chevallier 						 MVPP2_PRS_SRAM_AI_MASK);
642db9d7d36SMaxime Chevallier 			/* If packet is tagged continue check vlans */
643db9d7d36SMaxime Chevallier 			mvpp2_prs_sram_next_lu_set(&pe, MVPP2_PRS_LU_VLAN);
644db9d7d36SMaxime Chevallier 		} else {
645db9d7d36SMaxime Chevallier 			/* Set result info bits to 'no vlans' */
646db9d7d36SMaxime Chevallier 			mvpp2_prs_sram_ri_update(&pe, MVPP2_PRS_RI_VLAN_NONE,
647db9d7d36SMaxime Chevallier 						 MVPP2_PRS_RI_VLAN_MASK);
648db9d7d36SMaxime Chevallier 			mvpp2_prs_sram_next_lu_set(&pe, MVPP2_PRS_LU_L2);
649db9d7d36SMaxime Chevallier 		}
650db9d7d36SMaxime Chevallier 		/* Mask/unmask all ports, depending on dsa type */
651db9d7d36SMaxime Chevallier 		mvpp2_prs_tcam_port_map_set(&pe, port_mask);
652db9d7d36SMaxime Chevallier 	}
653db9d7d36SMaxime Chevallier 
654db9d7d36SMaxime Chevallier 	/* Update port mask */
655db9d7d36SMaxime Chevallier 	mvpp2_prs_tcam_port_set(&pe, port, add);
656db9d7d36SMaxime Chevallier 
657db9d7d36SMaxime Chevallier 	mvpp2_prs_hw_write(priv, &pe);
658db9d7d36SMaxime Chevallier }
659db9d7d36SMaxime Chevallier 
660db9d7d36SMaxime Chevallier /* Search for existing single/triple vlan entry */
mvpp2_prs_vlan_find(struct mvpp2 * priv,unsigned short tpid,int ai)661db9d7d36SMaxime Chevallier static int mvpp2_prs_vlan_find(struct mvpp2 *priv, unsigned short tpid, int ai)
662db9d7d36SMaxime Chevallier {
663db9d7d36SMaxime Chevallier 	struct mvpp2_prs_entry pe;
664db9d7d36SMaxime Chevallier 	int tid;
665db9d7d36SMaxime Chevallier 
666db9d7d36SMaxime Chevallier 	/* Go through the all entries with MVPP2_PRS_LU_VLAN */
667db9d7d36SMaxime Chevallier 	for (tid = MVPP2_PE_FIRST_FREE_TID;
668db9d7d36SMaxime Chevallier 	     tid <= MVPP2_PE_LAST_FREE_TID; tid++) {
669db9d7d36SMaxime Chevallier 		unsigned int ri_bits, ai_bits;
670db9d7d36SMaxime Chevallier 		bool match;
671db9d7d36SMaxime Chevallier 
672db9d7d36SMaxime Chevallier 		if (!priv->prs_shadow[tid].valid ||
673db9d7d36SMaxime Chevallier 		    priv->prs_shadow[tid].lu != MVPP2_PRS_LU_VLAN)
674db9d7d36SMaxime Chevallier 			continue;
675db9d7d36SMaxime Chevallier 
676db9d7d36SMaxime Chevallier 		mvpp2_prs_init_from_hw(priv, &pe, tid);
677432b5942SMaxime Chevallier 		match = mvpp2_prs_tcam_data_cmp(&pe, 0, tpid);
678db9d7d36SMaxime Chevallier 		if (!match)
679db9d7d36SMaxime Chevallier 			continue;
680db9d7d36SMaxime Chevallier 
681db9d7d36SMaxime Chevallier 		/* Get vlan type */
682db9d7d36SMaxime Chevallier 		ri_bits = mvpp2_prs_sram_ri_get(&pe);
683db9d7d36SMaxime Chevallier 		ri_bits &= MVPP2_PRS_RI_VLAN_MASK;
684db9d7d36SMaxime Chevallier 
685db9d7d36SMaxime Chevallier 		/* Get current ai value from tcam */
686db9d7d36SMaxime Chevallier 		ai_bits = mvpp2_prs_tcam_ai_get(&pe);
687db9d7d36SMaxime Chevallier 		/* Clear double vlan bit */
688db9d7d36SMaxime Chevallier 		ai_bits &= ~MVPP2_PRS_DBL_VLAN_AI_BIT;
689db9d7d36SMaxime Chevallier 
690db9d7d36SMaxime Chevallier 		if (ai != ai_bits)
691db9d7d36SMaxime Chevallier 			continue;
692db9d7d36SMaxime Chevallier 
693db9d7d36SMaxime Chevallier 		if (ri_bits == MVPP2_PRS_RI_VLAN_SINGLE ||
694db9d7d36SMaxime Chevallier 		    ri_bits == MVPP2_PRS_RI_VLAN_TRIPLE)
695db9d7d36SMaxime Chevallier 			return tid;
696db9d7d36SMaxime Chevallier 	}
697db9d7d36SMaxime Chevallier 
698db9d7d36SMaxime Chevallier 	return -ENOENT;
699db9d7d36SMaxime Chevallier }
700db9d7d36SMaxime Chevallier 
701db9d7d36SMaxime Chevallier /* Add/update single/triple vlan entry */
mvpp2_prs_vlan_add(struct mvpp2 * priv,unsigned short tpid,int ai,unsigned int port_map)702db9d7d36SMaxime Chevallier static int mvpp2_prs_vlan_add(struct mvpp2 *priv, unsigned short tpid, int ai,
703db9d7d36SMaxime Chevallier 			      unsigned int port_map)
704db9d7d36SMaxime Chevallier {
705db9d7d36SMaxime Chevallier 	struct mvpp2_prs_entry pe;
706db9d7d36SMaxime Chevallier 	int tid_aux, tid;
707db9d7d36SMaxime Chevallier 	int ret = 0;
708db9d7d36SMaxime Chevallier 
709db9d7d36SMaxime Chevallier 	memset(&pe, 0, sizeof(pe));
710db9d7d36SMaxime Chevallier 
711db9d7d36SMaxime Chevallier 	tid = mvpp2_prs_vlan_find(priv, tpid, ai);
712db9d7d36SMaxime Chevallier 
713db9d7d36SMaxime Chevallier 	if (tid < 0) {
714db9d7d36SMaxime Chevallier 		/* Create new tcam entry */
715db9d7d36SMaxime Chevallier 		tid = mvpp2_prs_tcam_first_free(priv, MVPP2_PE_LAST_FREE_TID,
716db9d7d36SMaxime Chevallier 						MVPP2_PE_FIRST_FREE_TID);
717db9d7d36SMaxime Chevallier 		if (tid < 0)
718db9d7d36SMaxime Chevallier 			return tid;
719db9d7d36SMaxime Chevallier 
720db9d7d36SMaxime Chevallier 		/* Get last double vlan tid */
721db9d7d36SMaxime Chevallier 		for (tid_aux = MVPP2_PE_LAST_FREE_TID;
722db9d7d36SMaxime Chevallier 		     tid_aux >= MVPP2_PE_FIRST_FREE_TID; tid_aux--) {
723db9d7d36SMaxime Chevallier 			unsigned int ri_bits;
724db9d7d36SMaxime Chevallier 
725db9d7d36SMaxime Chevallier 			if (!priv->prs_shadow[tid_aux].valid ||
726db9d7d36SMaxime Chevallier 			    priv->prs_shadow[tid_aux].lu != MVPP2_PRS_LU_VLAN)
727db9d7d36SMaxime Chevallier 				continue;
728db9d7d36SMaxime Chevallier 
729db9d7d36SMaxime Chevallier 			mvpp2_prs_init_from_hw(priv, &pe, tid_aux);
730db9d7d36SMaxime Chevallier 			ri_bits = mvpp2_prs_sram_ri_get(&pe);
731db9d7d36SMaxime Chevallier 			if ((ri_bits & MVPP2_PRS_RI_VLAN_MASK) ==
732db9d7d36SMaxime Chevallier 			    MVPP2_PRS_RI_VLAN_DOUBLE)
733db9d7d36SMaxime Chevallier 				break;
734db9d7d36SMaxime Chevallier 		}
735db9d7d36SMaxime Chevallier 
736db9d7d36SMaxime Chevallier 		if (tid <= tid_aux)
737db9d7d36SMaxime Chevallier 			return -EINVAL;
738db9d7d36SMaxime Chevallier 
739db9d7d36SMaxime Chevallier 		memset(&pe, 0, sizeof(pe));
740db9d7d36SMaxime Chevallier 		pe.index = tid;
741db9d7d36SMaxime Chevallier 		mvpp2_prs_tcam_lu_set(&pe, MVPP2_PRS_LU_VLAN);
742db9d7d36SMaxime Chevallier 
743db9d7d36SMaxime Chevallier 		mvpp2_prs_match_etype(&pe, 0, tpid);
744db9d7d36SMaxime Chevallier 
745db9d7d36SMaxime Chevallier 		/* VLAN tag detected, proceed with VID filtering */
746db9d7d36SMaxime Chevallier 		mvpp2_prs_sram_next_lu_set(&pe, MVPP2_PRS_LU_VID);
747db9d7d36SMaxime Chevallier 
748db9d7d36SMaxime Chevallier 		/* Clear all ai bits for next iteration */
749db9d7d36SMaxime Chevallier 		mvpp2_prs_sram_ai_update(&pe, 0, MVPP2_PRS_SRAM_AI_MASK);
750db9d7d36SMaxime Chevallier 
751db9d7d36SMaxime Chevallier 		if (ai == MVPP2_PRS_SINGLE_VLAN_AI) {
752db9d7d36SMaxime Chevallier 			mvpp2_prs_sram_ri_update(&pe, MVPP2_PRS_RI_VLAN_SINGLE,
753db9d7d36SMaxime Chevallier 						 MVPP2_PRS_RI_VLAN_MASK);
754db9d7d36SMaxime Chevallier 		} else {
755db9d7d36SMaxime Chevallier 			ai |= MVPP2_PRS_DBL_VLAN_AI_BIT;
756db9d7d36SMaxime Chevallier 			mvpp2_prs_sram_ri_update(&pe, MVPP2_PRS_RI_VLAN_TRIPLE,
757db9d7d36SMaxime Chevallier 						 MVPP2_PRS_RI_VLAN_MASK);
758db9d7d36SMaxime Chevallier 		}
759db9d7d36SMaxime Chevallier 		mvpp2_prs_tcam_ai_update(&pe, ai, MVPP2_PRS_SRAM_AI_MASK);
760db9d7d36SMaxime Chevallier 
761db9d7d36SMaxime Chevallier 		mvpp2_prs_shadow_set(priv, pe.index, MVPP2_PRS_LU_VLAN);
762db9d7d36SMaxime Chevallier 	} else {
763db9d7d36SMaxime Chevallier 		mvpp2_prs_init_from_hw(priv, &pe, tid);
764db9d7d36SMaxime Chevallier 	}
765db9d7d36SMaxime Chevallier 	/* Update ports' mask */
766db9d7d36SMaxime Chevallier 	mvpp2_prs_tcam_port_map_set(&pe, port_map);
767db9d7d36SMaxime Chevallier 
768db9d7d36SMaxime Chevallier 	mvpp2_prs_hw_write(priv, &pe);
769db9d7d36SMaxime Chevallier 
770db9d7d36SMaxime Chevallier 	return ret;
771db9d7d36SMaxime Chevallier }
772db9d7d36SMaxime Chevallier 
773db9d7d36SMaxime Chevallier /* Get first free double vlan ai number */
mvpp2_prs_double_vlan_ai_free_get(struct mvpp2 * priv)774db9d7d36SMaxime Chevallier static int mvpp2_prs_double_vlan_ai_free_get(struct mvpp2 *priv)
775db9d7d36SMaxime Chevallier {
776db9d7d36SMaxime Chevallier 	int i;
777db9d7d36SMaxime Chevallier 
778db9d7d36SMaxime Chevallier 	for (i = 1; i < MVPP2_PRS_DBL_VLANS_MAX; i++) {
779db9d7d36SMaxime Chevallier 		if (!priv->prs_double_vlans[i])
780db9d7d36SMaxime Chevallier 			return i;
781db9d7d36SMaxime Chevallier 	}
782db9d7d36SMaxime Chevallier 
783db9d7d36SMaxime Chevallier 	return -EINVAL;
784db9d7d36SMaxime Chevallier }
785db9d7d36SMaxime Chevallier 
786db9d7d36SMaxime Chevallier /* Search for existing double vlan entry */
mvpp2_prs_double_vlan_find(struct mvpp2 * priv,unsigned short tpid1,unsigned short tpid2)787db9d7d36SMaxime Chevallier static int mvpp2_prs_double_vlan_find(struct mvpp2 *priv, unsigned short tpid1,
788db9d7d36SMaxime Chevallier 				      unsigned short tpid2)
789db9d7d36SMaxime Chevallier {
790db9d7d36SMaxime Chevallier 	struct mvpp2_prs_entry pe;
791db9d7d36SMaxime Chevallier 	int tid;
792db9d7d36SMaxime Chevallier 
793db9d7d36SMaxime Chevallier 	/* Go through the all entries with MVPP2_PRS_LU_VLAN */
794db9d7d36SMaxime Chevallier 	for (tid = MVPP2_PE_FIRST_FREE_TID;
795db9d7d36SMaxime Chevallier 	     tid <= MVPP2_PE_LAST_FREE_TID; tid++) {
796db9d7d36SMaxime Chevallier 		unsigned int ri_mask;
797db9d7d36SMaxime Chevallier 		bool match;
798db9d7d36SMaxime Chevallier 
799db9d7d36SMaxime Chevallier 		if (!priv->prs_shadow[tid].valid ||
800db9d7d36SMaxime Chevallier 		    priv->prs_shadow[tid].lu != MVPP2_PRS_LU_VLAN)
801db9d7d36SMaxime Chevallier 			continue;
802db9d7d36SMaxime Chevallier 
803db9d7d36SMaxime Chevallier 		mvpp2_prs_init_from_hw(priv, &pe, tid);
804db9d7d36SMaxime Chevallier 
805432b5942SMaxime Chevallier 		match = mvpp2_prs_tcam_data_cmp(&pe, 0, tpid1) &&
806432b5942SMaxime Chevallier 			mvpp2_prs_tcam_data_cmp(&pe, 4, tpid2);
807db9d7d36SMaxime Chevallier 
808db9d7d36SMaxime Chevallier 		if (!match)
809db9d7d36SMaxime Chevallier 			continue;
810db9d7d36SMaxime Chevallier 
811db9d7d36SMaxime Chevallier 		ri_mask = mvpp2_prs_sram_ri_get(&pe) & MVPP2_PRS_RI_VLAN_MASK;
812db9d7d36SMaxime Chevallier 		if (ri_mask == MVPP2_PRS_RI_VLAN_DOUBLE)
813db9d7d36SMaxime Chevallier 			return tid;
814db9d7d36SMaxime Chevallier 	}
815db9d7d36SMaxime Chevallier 
816db9d7d36SMaxime Chevallier 	return -ENOENT;
817db9d7d36SMaxime Chevallier }
818db9d7d36SMaxime Chevallier 
819db9d7d36SMaxime Chevallier /* Add or update double vlan entry */
mvpp2_prs_double_vlan_add(struct mvpp2 * priv,unsigned short tpid1,unsigned short tpid2,unsigned int port_map)820db9d7d36SMaxime Chevallier static int mvpp2_prs_double_vlan_add(struct mvpp2 *priv, unsigned short tpid1,
821db9d7d36SMaxime Chevallier 				     unsigned short tpid2,
822db9d7d36SMaxime Chevallier 				     unsigned int port_map)
823db9d7d36SMaxime Chevallier {
824db9d7d36SMaxime Chevallier 	int tid_aux, tid, ai, ret = 0;
825db9d7d36SMaxime Chevallier 	struct mvpp2_prs_entry pe;
826db9d7d36SMaxime Chevallier 
827db9d7d36SMaxime Chevallier 	memset(&pe, 0, sizeof(pe));
828db9d7d36SMaxime Chevallier 
829db9d7d36SMaxime Chevallier 	tid = mvpp2_prs_double_vlan_find(priv, tpid1, tpid2);
830db9d7d36SMaxime Chevallier 
831db9d7d36SMaxime Chevallier 	if (tid < 0) {
832db9d7d36SMaxime Chevallier 		/* Create new tcam entry */
833db9d7d36SMaxime Chevallier 		tid = mvpp2_prs_tcam_first_free(priv, MVPP2_PE_FIRST_FREE_TID,
834db9d7d36SMaxime Chevallier 				MVPP2_PE_LAST_FREE_TID);
835db9d7d36SMaxime Chevallier 		if (tid < 0)
836db9d7d36SMaxime Chevallier 			return tid;
837db9d7d36SMaxime Chevallier 
838db9d7d36SMaxime Chevallier 		/* Set ai value for new double vlan entry */
839db9d7d36SMaxime Chevallier 		ai = mvpp2_prs_double_vlan_ai_free_get(priv);
840db9d7d36SMaxime Chevallier 		if (ai < 0)
841db9d7d36SMaxime Chevallier 			return ai;
842db9d7d36SMaxime Chevallier 
843db9d7d36SMaxime Chevallier 		/* Get first single/triple vlan tid */
844db9d7d36SMaxime Chevallier 		for (tid_aux = MVPP2_PE_FIRST_FREE_TID;
845db9d7d36SMaxime Chevallier 		     tid_aux <= MVPP2_PE_LAST_FREE_TID; tid_aux++) {
846db9d7d36SMaxime Chevallier 			unsigned int ri_bits;
847db9d7d36SMaxime Chevallier 
848db9d7d36SMaxime Chevallier 			if (!priv->prs_shadow[tid_aux].valid ||
849db9d7d36SMaxime Chevallier 			    priv->prs_shadow[tid_aux].lu != MVPP2_PRS_LU_VLAN)
850db9d7d36SMaxime Chevallier 				continue;
851db9d7d36SMaxime Chevallier 
852db9d7d36SMaxime Chevallier 			mvpp2_prs_init_from_hw(priv, &pe, tid_aux);
853db9d7d36SMaxime Chevallier 			ri_bits = mvpp2_prs_sram_ri_get(&pe);
854db9d7d36SMaxime Chevallier 			ri_bits &= MVPP2_PRS_RI_VLAN_MASK;
855db9d7d36SMaxime Chevallier 			if (ri_bits == MVPP2_PRS_RI_VLAN_SINGLE ||
856db9d7d36SMaxime Chevallier 			    ri_bits == MVPP2_PRS_RI_VLAN_TRIPLE)
857db9d7d36SMaxime Chevallier 				break;
858db9d7d36SMaxime Chevallier 		}
859db9d7d36SMaxime Chevallier 
860db9d7d36SMaxime Chevallier 		if (tid >= tid_aux)
861db9d7d36SMaxime Chevallier 			return -ERANGE;
862db9d7d36SMaxime Chevallier 
863db9d7d36SMaxime Chevallier 		memset(&pe, 0, sizeof(pe));
864db9d7d36SMaxime Chevallier 		mvpp2_prs_tcam_lu_set(&pe, MVPP2_PRS_LU_VLAN);
865db9d7d36SMaxime Chevallier 		pe.index = tid;
866db9d7d36SMaxime Chevallier 
867db9d7d36SMaxime Chevallier 		priv->prs_double_vlans[ai] = true;
868db9d7d36SMaxime Chevallier 
869db9d7d36SMaxime Chevallier 		mvpp2_prs_match_etype(&pe, 0, tpid1);
870db9d7d36SMaxime Chevallier 		mvpp2_prs_match_etype(&pe, 4, tpid2);
871db9d7d36SMaxime Chevallier 
872db9d7d36SMaxime Chevallier 		mvpp2_prs_sram_next_lu_set(&pe, MVPP2_PRS_LU_VLAN);
873db9d7d36SMaxime Chevallier 		/* Shift 4 bytes - skip outer vlan tag */
874db9d7d36SMaxime Chevallier 		mvpp2_prs_sram_shift_set(&pe, MVPP2_VLAN_TAG_LEN,
875db9d7d36SMaxime Chevallier 					 MVPP2_PRS_SRAM_OP_SEL_SHIFT_ADD);
876db9d7d36SMaxime Chevallier 		mvpp2_prs_sram_ri_update(&pe, MVPP2_PRS_RI_VLAN_DOUBLE,
877db9d7d36SMaxime Chevallier 					 MVPP2_PRS_RI_VLAN_MASK);
878db9d7d36SMaxime Chevallier 		mvpp2_prs_sram_ai_update(&pe, ai | MVPP2_PRS_DBL_VLAN_AI_BIT,
879db9d7d36SMaxime Chevallier 					 MVPP2_PRS_SRAM_AI_MASK);
880db9d7d36SMaxime Chevallier 
881db9d7d36SMaxime Chevallier 		mvpp2_prs_shadow_set(priv, pe.index, MVPP2_PRS_LU_VLAN);
882db9d7d36SMaxime Chevallier 	} else {
883db9d7d36SMaxime Chevallier 		mvpp2_prs_init_from_hw(priv, &pe, tid);
884db9d7d36SMaxime Chevallier 	}
885db9d7d36SMaxime Chevallier 
886db9d7d36SMaxime Chevallier 	/* Update ports' mask */
887db9d7d36SMaxime Chevallier 	mvpp2_prs_tcam_port_map_set(&pe, port_map);
888db9d7d36SMaxime Chevallier 	mvpp2_prs_hw_write(priv, &pe);
889db9d7d36SMaxime Chevallier 
890db9d7d36SMaxime Chevallier 	return ret;
891db9d7d36SMaxime Chevallier }
892db9d7d36SMaxime Chevallier 
893db9d7d36SMaxime Chevallier /* IPv4 header parsing for fragmentation and L4 offset */
mvpp2_prs_ip4_proto(struct mvpp2 * priv,unsigned short proto,unsigned int ri,unsigned int ri_mask)894db9d7d36SMaxime Chevallier static int mvpp2_prs_ip4_proto(struct mvpp2 *priv, unsigned short proto,
895db9d7d36SMaxime Chevallier 			       unsigned int ri, unsigned int ri_mask)
896db9d7d36SMaxime Chevallier {
897db9d7d36SMaxime Chevallier 	struct mvpp2_prs_entry pe;
898db9d7d36SMaxime Chevallier 	int tid;
899db9d7d36SMaxime Chevallier 
900db9d7d36SMaxime Chevallier 	if ((proto != IPPROTO_TCP) && (proto != IPPROTO_UDP) &&
901db9d7d36SMaxime Chevallier 	    (proto != IPPROTO_IGMP))
902db9d7d36SMaxime Chevallier 		return -EINVAL;
903db9d7d36SMaxime Chevallier 
904db9d7d36SMaxime Chevallier 	/* Not fragmented packet */
905db9d7d36SMaxime Chevallier 	tid = mvpp2_prs_tcam_first_free(priv, MVPP2_PE_FIRST_FREE_TID,
906db9d7d36SMaxime Chevallier 					MVPP2_PE_LAST_FREE_TID);
907db9d7d36SMaxime Chevallier 	if (tid < 0)
908db9d7d36SMaxime Chevallier 		return tid;
909db9d7d36SMaxime Chevallier 
910db9d7d36SMaxime Chevallier 	memset(&pe, 0, sizeof(pe));
911db9d7d36SMaxime Chevallier 	mvpp2_prs_tcam_lu_set(&pe, MVPP2_PRS_LU_IP4);
912db9d7d36SMaxime Chevallier 	pe.index = tid;
913db9d7d36SMaxime Chevallier 
914c73a4596SStefan Chulski 	/* Finished: go to flowid generation */
915c73a4596SStefan Chulski 	mvpp2_prs_sram_next_lu_set(&pe, MVPP2_PRS_LU_FLOWS);
916c73a4596SStefan Chulski 	mvpp2_prs_sram_bits_set(&pe, MVPP2_PRS_SRAM_LU_GEN_BIT, 1);
917c73a4596SStefan Chulski 
9184ad29b1aSStefan Chulski 	/* Set L3 offset */
9194ad29b1aSStefan Chulski 	mvpp2_prs_sram_offset_set(&pe, MVPP2_PRS_SRAM_UDF_TYPE_L3, -4,
920db9d7d36SMaxime Chevallier 				  MVPP2_PRS_SRAM_OP_SEL_UDF_ADD);
921c73a4596SStefan Chulski 	mvpp2_prs_sram_ai_update(&pe, 0, MVPP2_PRS_IPV4_DIP_AI_BIT);
922db9d7d36SMaxime Chevallier 	mvpp2_prs_sram_ri_update(&pe, ri, ri_mask | MVPP2_PRS_RI_IP_FRAG_MASK);
923db9d7d36SMaxime Chevallier 
924db9d7d36SMaxime Chevallier 	mvpp2_prs_tcam_data_byte_set(&pe, 2, 0x00,
925db9d7d36SMaxime Chevallier 				     MVPP2_PRS_TCAM_PROTO_MASK_L);
926db9d7d36SMaxime Chevallier 	mvpp2_prs_tcam_data_byte_set(&pe, 3, 0x00,
927db9d7d36SMaxime Chevallier 				     MVPP2_PRS_TCAM_PROTO_MASK);
928db9d7d36SMaxime Chevallier 
929db9d7d36SMaxime Chevallier 	mvpp2_prs_tcam_data_byte_set(&pe, 5, proto, MVPP2_PRS_TCAM_PROTO_MASK);
930c73a4596SStefan Chulski 	mvpp2_prs_tcam_ai_update(&pe, MVPP2_PRS_IPV4_DIP_AI_BIT,
931c73a4596SStefan Chulski 				 MVPP2_PRS_IPV4_DIP_AI_BIT);
932db9d7d36SMaxime Chevallier 	/* Unmask all ports */
933db9d7d36SMaxime Chevallier 	mvpp2_prs_tcam_port_map_set(&pe, MVPP2_PRS_PORT_MASK);
934db9d7d36SMaxime Chevallier 
935db9d7d36SMaxime Chevallier 	/* Update shadow table and hw entry */
936db9d7d36SMaxime Chevallier 	mvpp2_prs_shadow_set(priv, pe.index, MVPP2_PRS_LU_IP4);
937db9d7d36SMaxime Chevallier 	mvpp2_prs_hw_write(priv, &pe);
938db9d7d36SMaxime Chevallier 
939db9d7d36SMaxime Chevallier 	/* Fragmented packet */
940db9d7d36SMaxime Chevallier 	tid = mvpp2_prs_tcam_first_free(priv, MVPP2_PE_FIRST_FREE_TID,
941db9d7d36SMaxime Chevallier 					MVPP2_PE_LAST_FREE_TID);
942db9d7d36SMaxime Chevallier 	if (tid < 0)
943db9d7d36SMaxime Chevallier 		return tid;
944db9d7d36SMaxime Chevallier 
945db9d7d36SMaxime Chevallier 	pe.index = tid;
946db9d7d36SMaxime Chevallier 	/* Clear ri before updating */
947bd43d1baSMaxime Chevallier 	pe.sram[MVPP2_PRS_SRAM_RI_WORD] = 0x0;
948bd43d1baSMaxime Chevallier 	pe.sram[MVPP2_PRS_SRAM_RI_CTRL_WORD] = 0x0;
949db9d7d36SMaxime Chevallier 	mvpp2_prs_sram_ri_update(&pe, ri, ri_mask);
950db9d7d36SMaxime Chevallier 
951db9d7d36SMaxime Chevallier 	mvpp2_prs_sram_ri_update(&pe, ri | MVPP2_PRS_RI_IP_FRAG_TRUE,
952db9d7d36SMaxime Chevallier 				 ri_mask | MVPP2_PRS_RI_IP_FRAG_MASK);
953db9d7d36SMaxime Chevallier 
954db9d7d36SMaxime Chevallier 	mvpp2_prs_tcam_data_byte_set(&pe, 2, 0x00, 0x0);
955db9d7d36SMaxime Chevallier 	mvpp2_prs_tcam_data_byte_set(&pe, 3, 0x00, 0x0);
956db9d7d36SMaxime Chevallier 
957db9d7d36SMaxime Chevallier 	/* Update shadow table and hw entry */
958db9d7d36SMaxime Chevallier 	mvpp2_prs_shadow_set(priv, pe.index, MVPP2_PRS_LU_IP4);
959db9d7d36SMaxime Chevallier 	mvpp2_prs_hw_write(priv, &pe);
960db9d7d36SMaxime Chevallier 
961db9d7d36SMaxime Chevallier 	return 0;
962db9d7d36SMaxime Chevallier }
963db9d7d36SMaxime Chevallier 
964db9d7d36SMaxime Chevallier /* IPv4 L3 multicast or broadcast */
mvpp2_prs_ip4_cast(struct mvpp2 * priv,unsigned short l3_cast)965db9d7d36SMaxime Chevallier static int mvpp2_prs_ip4_cast(struct mvpp2 *priv, unsigned short l3_cast)
966db9d7d36SMaxime Chevallier {
967db9d7d36SMaxime Chevallier 	struct mvpp2_prs_entry pe;
968db9d7d36SMaxime Chevallier 	int mask, tid;
969db9d7d36SMaxime Chevallier 
970db9d7d36SMaxime Chevallier 	tid = mvpp2_prs_tcam_first_free(priv, MVPP2_PE_FIRST_FREE_TID,
971db9d7d36SMaxime Chevallier 					MVPP2_PE_LAST_FREE_TID);
972db9d7d36SMaxime Chevallier 	if (tid < 0)
973db9d7d36SMaxime Chevallier 		return tid;
974db9d7d36SMaxime Chevallier 
975db9d7d36SMaxime Chevallier 	memset(&pe, 0, sizeof(pe));
976db9d7d36SMaxime Chevallier 	mvpp2_prs_tcam_lu_set(&pe, MVPP2_PRS_LU_IP4);
977db9d7d36SMaxime Chevallier 	pe.index = tid;
978db9d7d36SMaxime Chevallier 
979db9d7d36SMaxime Chevallier 	switch (l3_cast) {
980db9d7d36SMaxime Chevallier 	case MVPP2_PRS_L3_MULTI_CAST:
981db9d7d36SMaxime Chevallier 		mvpp2_prs_tcam_data_byte_set(&pe, 0, MVPP2_PRS_IPV4_MC,
982db9d7d36SMaxime Chevallier 					     MVPP2_PRS_IPV4_MC_MASK);
983db9d7d36SMaxime Chevallier 		mvpp2_prs_sram_ri_update(&pe, MVPP2_PRS_RI_L3_MCAST,
984db9d7d36SMaxime Chevallier 					 MVPP2_PRS_RI_L3_ADDR_MASK);
985db9d7d36SMaxime Chevallier 		break;
986db9d7d36SMaxime Chevallier 	case  MVPP2_PRS_L3_BROAD_CAST:
987db9d7d36SMaxime Chevallier 		mask = MVPP2_PRS_IPV4_BC_MASK;
988db9d7d36SMaxime Chevallier 		mvpp2_prs_tcam_data_byte_set(&pe, 0, mask, mask);
989db9d7d36SMaxime Chevallier 		mvpp2_prs_tcam_data_byte_set(&pe, 1, mask, mask);
990db9d7d36SMaxime Chevallier 		mvpp2_prs_tcam_data_byte_set(&pe, 2, mask, mask);
991db9d7d36SMaxime Chevallier 		mvpp2_prs_tcam_data_byte_set(&pe, 3, mask, mask);
992db9d7d36SMaxime Chevallier 		mvpp2_prs_sram_ri_update(&pe, MVPP2_PRS_RI_L3_BCAST,
993db9d7d36SMaxime Chevallier 					 MVPP2_PRS_RI_L3_ADDR_MASK);
994db9d7d36SMaxime Chevallier 		break;
995db9d7d36SMaxime Chevallier 	default:
996db9d7d36SMaxime Chevallier 		return -EINVAL;
997db9d7d36SMaxime Chevallier 	}
998db9d7d36SMaxime Chevallier 
999c73a4596SStefan Chulski 	/* Go again to ipv4 */
1000c73a4596SStefan Chulski 	mvpp2_prs_sram_next_lu_set(&pe, MVPP2_PRS_LU_IP4);
1001db9d7d36SMaxime Chevallier 
1002c73a4596SStefan Chulski 	mvpp2_prs_sram_ai_update(&pe, MVPP2_PRS_IPV4_DIP_AI_BIT,
1003db9d7d36SMaxime Chevallier 				 MVPP2_PRS_IPV4_DIP_AI_BIT);
1004c73a4596SStefan Chulski 
1005c73a4596SStefan Chulski 	/* Shift back to IPv4 proto */
1006c73a4596SStefan Chulski 	mvpp2_prs_sram_shift_set(&pe, -12, MVPP2_PRS_SRAM_OP_SEL_SHIFT_ADD);
1007c73a4596SStefan Chulski 
1008c73a4596SStefan Chulski 	mvpp2_prs_tcam_ai_update(&pe, 0, MVPP2_PRS_IPV4_DIP_AI_BIT);
1009c73a4596SStefan Chulski 
1010db9d7d36SMaxime Chevallier 	/* Unmask all ports */
1011db9d7d36SMaxime Chevallier 	mvpp2_prs_tcam_port_map_set(&pe, MVPP2_PRS_PORT_MASK);
1012db9d7d36SMaxime Chevallier 
1013db9d7d36SMaxime Chevallier 	/* Update shadow table and hw entry */
1014db9d7d36SMaxime Chevallier 	mvpp2_prs_shadow_set(priv, pe.index, MVPP2_PRS_LU_IP4);
1015db9d7d36SMaxime Chevallier 	mvpp2_prs_hw_write(priv, &pe);
1016db9d7d36SMaxime Chevallier 
1017db9d7d36SMaxime Chevallier 	return 0;
1018db9d7d36SMaxime Chevallier }
1019db9d7d36SMaxime Chevallier 
1020db9d7d36SMaxime Chevallier /* Set entries for protocols over IPv6  */
mvpp2_prs_ip6_proto(struct mvpp2 * priv,unsigned short proto,unsigned int ri,unsigned int ri_mask)1021db9d7d36SMaxime Chevallier static int mvpp2_prs_ip6_proto(struct mvpp2 *priv, unsigned short proto,
1022db9d7d36SMaxime Chevallier 			       unsigned int ri, unsigned int ri_mask)
1023db9d7d36SMaxime Chevallier {
1024db9d7d36SMaxime Chevallier 	struct mvpp2_prs_entry pe;
1025db9d7d36SMaxime Chevallier 	int tid;
1026db9d7d36SMaxime Chevallier 
1027db9d7d36SMaxime Chevallier 	if ((proto != IPPROTO_TCP) && (proto != IPPROTO_UDP) &&
1028db9d7d36SMaxime Chevallier 	    (proto != IPPROTO_ICMPV6) && (proto != IPPROTO_IPIP))
1029db9d7d36SMaxime Chevallier 		return -EINVAL;
1030db9d7d36SMaxime Chevallier 
1031db9d7d36SMaxime Chevallier 	tid = mvpp2_prs_tcam_first_free(priv, MVPP2_PE_FIRST_FREE_TID,
1032db9d7d36SMaxime Chevallier 					MVPP2_PE_LAST_FREE_TID);
1033db9d7d36SMaxime Chevallier 	if (tid < 0)
1034db9d7d36SMaxime Chevallier 		return tid;
1035db9d7d36SMaxime Chevallier 
1036db9d7d36SMaxime Chevallier 	memset(&pe, 0, sizeof(pe));
1037db9d7d36SMaxime Chevallier 	mvpp2_prs_tcam_lu_set(&pe, MVPP2_PRS_LU_IP6);
1038db9d7d36SMaxime Chevallier 	pe.index = tid;
1039db9d7d36SMaxime Chevallier 
1040db9d7d36SMaxime Chevallier 	/* Finished: go to flowid generation */
1041db9d7d36SMaxime Chevallier 	mvpp2_prs_sram_next_lu_set(&pe, MVPP2_PRS_LU_FLOWS);
1042db9d7d36SMaxime Chevallier 	mvpp2_prs_sram_bits_set(&pe, MVPP2_PRS_SRAM_LU_GEN_BIT, 1);
1043db9d7d36SMaxime Chevallier 	mvpp2_prs_sram_ri_update(&pe, ri, ri_mask);
1044db9d7d36SMaxime Chevallier 	mvpp2_prs_sram_offset_set(&pe, MVPP2_PRS_SRAM_UDF_TYPE_L4,
1045db9d7d36SMaxime Chevallier 				  sizeof(struct ipv6hdr) - 6,
1046db9d7d36SMaxime Chevallier 				  MVPP2_PRS_SRAM_OP_SEL_UDF_ADD);
1047db9d7d36SMaxime Chevallier 
1048db9d7d36SMaxime Chevallier 	mvpp2_prs_tcam_data_byte_set(&pe, 0, proto, MVPP2_PRS_TCAM_PROTO_MASK);
1049db9d7d36SMaxime Chevallier 	mvpp2_prs_tcam_ai_update(&pe, MVPP2_PRS_IPV6_NO_EXT_AI_BIT,
1050db9d7d36SMaxime Chevallier 				 MVPP2_PRS_IPV6_NO_EXT_AI_BIT);
1051db9d7d36SMaxime Chevallier 	/* Unmask all ports */
1052db9d7d36SMaxime Chevallier 	mvpp2_prs_tcam_port_map_set(&pe, MVPP2_PRS_PORT_MASK);
1053db9d7d36SMaxime Chevallier 
1054db9d7d36SMaxime Chevallier 	/* Write HW */
1055db9d7d36SMaxime Chevallier 	mvpp2_prs_shadow_set(priv, pe.index, MVPP2_PRS_LU_IP6);
1056db9d7d36SMaxime Chevallier 	mvpp2_prs_hw_write(priv, &pe);
1057db9d7d36SMaxime Chevallier 
1058db9d7d36SMaxime Chevallier 	return 0;
1059db9d7d36SMaxime Chevallier }
1060db9d7d36SMaxime Chevallier 
1061db9d7d36SMaxime Chevallier /* IPv6 L3 multicast entry */
mvpp2_prs_ip6_cast(struct mvpp2 * priv,unsigned short l3_cast)1062db9d7d36SMaxime Chevallier static int mvpp2_prs_ip6_cast(struct mvpp2 *priv, unsigned short l3_cast)
1063db9d7d36SMaxime Chevallier {
1064db9d7d36SMaxime Chevallier 	struct mvpp2_prs_entry pe;
1065db9d7d36SMaxime Chevallier 	int tid;
1066db9d7d36SMaxime Chevallier 
1067db9d7d36SMaxime Chevallier 	if (l3_cast != MVPP2_PRS_L3_MULTI_CAST)
1068db9d7d36SMaxime Chevallier 		return -EINVAL;
1069db9d7d36SMaxime Chevallier 
1070db9d7d36SMaxime Chevallier 	tid = mvpp2_prs_tcam_first_free(priv, MVPP2_PE_FIRST_FREE_TID,
1071db9d7d36SMaxime Chevallier 					MVPP2_PE_LAST_FREE_TID);
1072db9d7d36SMaxime Chevallier 	if (tid < 0)
1073db9d7d36SMaxime Chevallier 		return tid;
1074db9d7d36SMaxime Chevallier 
1075db9d7d36SMaxime Chevallier 	memset(&pe, 0, sizeof(pe));
1076db9d7d36SMaxime Chevallier 	mvpp2_prs_tcam_lu_set(&pe, MVPP2_PRS_LU_IP6);
1077db9d7d36SMaxime Chevallier 	pe.index = tid;
1078db9d7d36SMaxime Chevallier 
1079db9d7d36SMaxime Chevallier 	/* Finished: go to flowid generation */
1080db9d7d36SMaxime Chevallier 	mvpp2_prs_sram_next_lu_set(&pe, MVPP2_PRS_LU_IP6);
1081db9d7d36SMaxime Chevallier 	mvpp2_prs_sram_ri_update(&pe, MVPP2_PRS_RI_L3_MCAST,
1082db9d7d36SMaxime Chevallier 				 MVPP2_PRS_RI_L3_ADDR_MASK);
1083db9d7d36SMaxime Chevallier 	mvpp2_prs_sram_ai_update(&pe, MVPP2_PRS_IPV6_NO_EXT_AI_BIT,
1084db9d7d36SMaxime Chevallier 				 MVPP2_PRS_IPV6_NO_EXT_AI_BIT);
1085db9d7d36SMaxime Chevallier 	/* Shift back to IPv6 NH */
1086db9d7d36SMaxime Chevallier 	mvpp2_prs_sram_shift_set(&pe, -18, MVPP2_PRS_SRAM_OP_SEL_SHIFT_ADD);
1087db9d7d36SMaxime Chevallier 
1088db9d7d36SMaxime Chevallier 	mvpp2_prs_tcam_data_byte_set(&pe, 0, MVPP2_PRS_IPV6_MC,
1089db9d7d36SMaxime Chevallier 				     MVPP2_PRS_IPV6_MC_MASK);
1090db9d7d36SMaxime Chevallier 	mvpp2_prs_tcam_ai_update(&pe, 0, MVPP2_PRS_IPV6_NO_EXT_AI_BIT);
1091db9d7d36SMaxime Chevallier 	/* Unmask all ports */
1092db9d7d36SMaxime Chevallier 	mvpp2_prs_tcam_port_map_set(&pe, MVPP2_PRS_PORT_MASK);
1093db9d7d36SMaxime Chevallier 
1094db9d7d36SMaxime Chevallier 	/* Update shadow table and hw entry */
1095db9d7d36SMaxime Chevallier 	mvpp2_prs_shadow_set(priv, pe.index, MVPP2_PRS_LU_IP6);
1096db9d7d36SMaxime Chevallier 	mvpp2_prs_hw_write(priv, &pe);
1097db9d7d36SMaxime Chevallier 
1098db9d7d36SMaxime Chevallier 	return 0;
1099db9d7d36SMaxime Chevallier }
1100db9d7d36SMaxime Chevallier 
1101db9d7d36SMaxime Chevallier /* Parser per-port initialization */
mvpp2_prs_hw_port_init(struct mvpp2 * priv,int port,int lu_first,int lu_max,int offset)1102db9d7d36SMaxime Chevallier static void mvpp2_prs_hw_port_init(struct mvpp2 *priv, int port, int lu_first,
1103db9d7d36SMaxime Chevallier 				   int lu_max, int offset)
1104db9d7d36SMaxime Chevallier {
1105db9d7d36SMaxime Chevallier 	u32 val;
1106db9d7d36SMaxime Chevallier 
1107db9d7d36SMaxime Chevallier 	/* Set lookup ID */
1108db9d7d36SMaxime Chevallier 	val = mvpp2_read(priv, MVPP2_PRS_INIT_LOOKUP_REG);
1109db9d7d36SMaxime Chevallier 	val &= ~MVPP2_PRS_PORT_LU_MASK(port);
1110db9d7d36SMaxime Chevallier 	val |=  MVPP2_PRS_PORT_LU_VAL(port, lu_first);
1111db9d7d36SMaxime Chevallier 	mvpp2_write(priv, MVPP2_PRS_INIT_LOOKUP_REG, val);
1112db9d7d36SMaxime Chevallier 
1113db9d7d36SMaxime Chevallier 	/* Set maximum number of loops for packet received from port */
1114db9d7d36SMaxime Chevallier 	val = mvpp2_read(priv, MVPP2_PRS_MAX_LOOP_REG(port));
1115db9d7d36SMaxime Chevallier 	val &= ~MVPP2_PRS_MAX_LOOP_MASK(port);
1116db9d7d36SMaxime Chevallier 	val |= MVPP2_PRS_MAX_LOOP_VAL(port, lu_max);
1117db9d7d36SMaxime Chevallier 	mvpp2_write(priv, MVPP2_PRS_MAX_LOOP_REG(port), val);
1118db9d7d36SMaxime Chevallier 
1119db9d7d36SMaxime Chevallier 	/* Set initial offset for packet header extraction for the first
1120db9d7d36SMaxime Chevallier 	 * searching loop
1121db9d7d36SMaxime Chevallier 	 */
1122db9d7d36SMaxime Chevallier 	val = mvpp2_read(priv, MVPP2_PRS_INIT_OFFS_REG(port));
1123db9d7d36SMaxime Chevallier 	val &= ~MVPP2_PRS_INIT_OFF_MASK(port);
1124db9d7d36SMaxime Chevallier 	val |= MVPP2_PRS_INIT_OFF_VAL(port, offset);
1125db9d7d36SMaxime Chevallier 	mvpp2_write(priv, MVPP2_PRS_INIT_OFFS_REG(port), val);
1126db9d7d36SMaxime Chevallier }
1127db9d7d36SMaxime Chevallier 
1128db9d7d36SMaxime Chevallier /* Default flow entries initialization for all ports */
mvpp2_prs_def_flow_init(struct mvpp2 * priv)1129db9d7d36SMaxime Chevallier static void mvpp2_prs_def_flow_init(struct mvpp2 *priv)
1130db9d7d36SMaxime Chevallier {
1131db9d7d36SMaxime Chevallier 	struct mvpp2_prs_entry pe;
1132db9d7d36SMaxime Chevallier 	int port;
1133db9d7d36SMaxime Chevallier 
1134db9d7d36SMaxime Chevallier 	for (port = 0; port < MVPP2_MAX_PORTS; port++) {
1135db9d7d36SMaxime Chevallier 		memset(&pe, 0, sizeof(pe));
1136db9d7d36SMaxime Chevallier 		mvpp2_prs_tcam_lu_set(&pe, MVPP2_PRS_LU_FLOWS);
1137db9d7d36SMaxime Chevallier 		pe.index = MVPP2_PE_FIRST_DEFAULT_FLOW - port;
1138db9d7d36SMaxime Chevallier 
1139db9d7d36SMaxime Chevallier 		/* Mask all ports */
1140db9d7d36SMaxime Chevallier 		mvpp2_prs_tcam_port_map_set(&pe, 0);
1141db9d7d36SMaxime Chevallier 
1142db9d7d36SMaxime Chevallier 		/* Set flow ID*/
1143db9d7d36SMaxime Chevallier 		mvpp2_prs_sram_ai_update(&pe, port, MVPP2_PRS_FLOW_ID_MASK);
1144db9d7d36SMaxime Chevallier 		mvpp2_prs_sram_bits_set(&pe, MVPP2_PRS_SRAM_LU_DONE_BIT, 1);
1145db9d7d36SMaxime Chevallier 
1146db9d7d36SMaxime Chevallier 		/* Update shadow table and hw entry */
1147db9d7d36SMaxime Chevallier 		mvpp2_prs_shadow_set(priv, pe.index, MVPP2_PRS_LU_FLOWS);
1148db9d7d36SMaxime Chevallier 		mvpp2_prs_hw_write(priv, &pe);
1149db9d7d36SMaxime Chevallier 	}
1150db9d7d36SMaxime Chevallier }
1151db9d7d36SMaxime Chevallier 
1152db9d7d36SMaxime Chevallier /* Set default entry for Marvell Header field */
mvpp2_prs_mh_init(struct mvpp2 * priv)1153db9d7d36SMaxime Chevallier static void mvpp2_prs_mh_init(struct mvpp2 *priv)
1154db9d7d36SMaxime Chevallier {
1155db9d7d36SMaxime Chevallier 	struct mvpp2_prs_entry pe;
1156db9d7d36SMaxime Chevallier 
1157db9d7d36SMaxime Chevallier 	memset(&pe, 0, sizeof(pe));
1158db9d7d36SMaxime Chevallier 
1159db9d7d36SMaxime Chevallier 	pe.index = MVPP2_PE_MH_DEFAULT;
1160db9d7d36SMaxime Chevallier 	mvpp2_prs_tcam_lu_set(&pe, MVPP2_PRS_LU_MH);
1161db9d7d36SMaxime Chevallier 	mvpp2_prs_sram_shift_set(&pe, MVPP2_MH_SIZE,
1162db9d7d36SMaxime Chevallier 				 MVPP2_PRS_SRAM_OP_SEL_SHIFT_ADD);
1163db9d7d36SMaxime Chevallier 	mvpp2_prs_sram_next_lu_set(&pe, MVPP2_PRS_LU_MAC);
1164db9d7d36SMaxime Chevallier 
1165db9d7d36SMaxime Chevallier 	/* Unmask all ports */
1166db9d7d36SMaxime Chevallier 	mvpp2_prs_tcam_port_map_set(&pe, MVPP2_PRS_PORT_MASK);
1167db9d7d36SMaxime Chevallier 
1168db9d7d36SMaxime Chevallier 	/* Update shadow table and hw entry */
1169db9d7d36SMaxime Chevallier 	mvpp2_prs_shadow_set(priv, pe.index, MVPP2_PRS_LU_MH);
1170db9d7d36SMaxime Chevallier 	mvpp2_prs_hw_write(priv, &pe);
1171e4b62cf7SStefan Chulski 
1172e4b62cf7SStefan Chulski 	/* Set MH entry that skip parser */
1173e4b62cf7SStefan Chulski 	pe.index = MVPP2_PE_MH_SKIP_PRS;
1174e4b62cf7SStefan Chulski 	mvpp2_prs_tcam_lu_set(&pe, MVPP2_PRS_LU_MH);
1175e4b62cf7SStefan Chulski 	mvpp2_prs_sram_shift_set(&pe, MVPP2_MH_SIZE,
1176e4b62cf7SStefan Chulski 				 MVPP2_PRS_SRAM_OP_SEL_SHIFT_ADD);
1177e4b62cf7SStefan Chulski 	mvpp2_prs_sram_bits_set(&pe, MVPP2_PRS_SRAM_LU_GEN_BIT, 1);
1178e4b62cf7SStefan Chulski 	mvpp2_prs_sram_next_lu_set(&pe, MVPP2_PRS_LU_FLOWS);
1179e4b62cf7SStefan Chulski 
1180e4b62cf7SStefan Chulski 	/* Mask all ports */
1181e4b62cf7SStefan Chulski 	mvpp2_prs_tcam_port_map_set(&pe, 0);
1182e4b62cf7SStefan Chulski 
1183e4b62cf7SStefan Chulski 	/* Update shadow table and hw entry */
1184e4b62cf7SStefan Chulski 	mvpp2_prs_shadow_set(priv, pe.index, MVPP2_PRS_LU_MH);
1185e4b62cf7SStefan Chulski 	mvpp2_prs_hw_write(priv, &pe);
1186db9d7d36SMaxime Chevallier }
1187db9d7d36SMaxime Chevallier 
1188db9d7d36SMaxime Chevallier /* Set default entires (place holder) for promiscuous, non-promiscuous and
1189db9d7d36SMaxime Chevallier  * multicast MAC addresses
1190db9d7d36SMaxime Chevallier  */
mvpp2_prs_mac_init(struct mvpp2 * priv)1191db9d7d36SMaxime Chevallier static void mvpp2_prs_mac_init(struct mvpp2 *priv)
1192db9d7d36SMaxime Chevallier {
1193db9d7d36SMaxime Chevallier 	struct mvpp2_prs_entry pe;
1194db9d7d36SMaxime Chevallier 
1195db9d7d36SMaxime Chevallier 	memset(&pe, 0, sizeof(pe));
1196db9d7d36SMaxime Chevallier 
1197db9d7d36SMaxime Chevallier 	/* Non-promiscuous mode for all ports - DROP unknown packets */
1198db9d7d36SMaxime Chevallier 	pe.index = MVPP2_PE_MAC_NON_PROMISCUOUS;
1199db9d7d36SMaxime Chevallier 	mvpp2_prs_tcam_lu_set(&pe, MVPP2_PRS_LU_MAC);
1200db9d7d36SMaxime Chevallier 
1201db9d7d36SMaxime Chevallier 	mvpp2_prs_sram_ri_update(&pe, MVPP2_PRS_RI_DROP_MASK,
1202db9d7d36SMaxime Chevallier 				 MVPP2_PRS_RI_DROP_MASK);
1203db9d7d36SMaxime Chevallier 	mvpp2_prs_sram_bits_set(&pe, MVPP2_PRS_SRAM_LU_GEN_BIT, 1);
1204db9d7d36SMaxime Chevallier 	mvpp2_prs_sram_next_lu_set(&pe, MVPP2_PRS_LU_FLOWS);
1205db9d7d36SMaxime Chevallier 
1206db9d7d36SMaxime Chevallier 	/* Unmask all ports */
1207db9d7d36SMaxime Chevallier 	mvpp2_prs_tcam_port_map_set(&pe, MVPP2_PRS_PORT_MASK);
1208db9d7d36SMaxime Chevallier 
1209db9d7d36SMaxime Chevallier 	/* Update shadow table and hw entry */
1210db9d7d36SMaxime Chevallier 	mvpp2_prs_shadow_set(priv, pe.index, MVPP2_PRS_LU_MAC);
1211db9d7d36SMaxime Chevallier 	mvpp2_prs_hw_write(priv, &pe);
1212db9d7d36SMaxime Chevallier 
1213db9d7d36SMaxime Chevallier 	/* Create dummy entries for drop all and promiscuous modes */
12143f48fab6SStefan Chulski 	mvpp2_prs_drop_fc(priv);
1215db9d7d36SMaxime Chevallier 	mvpp2_prs_mac_drop_all_set(priv, 0, false);
1216db9d7d36SMaxime Chevallier 	mvpp2_prs_mac_promisc_set(priv, 0, MVPP2_PRS_L2_UNI_CAST, false);
1217db9d7d36SMaxime Chevallier 	mvpp2_prs_mac_promisc_set(priv, 0, MVPP2_PRS_L2_MULTI_CAST, false);
1218db9d7d36SMaxime Chevallier }
1219db9d7d36SMaxime Chevallier 
1220db9d7d36SMaxime Chevallier /* Set default entries for various types of dsa packets */
mvpp2_prs_dsa_init(struct mvpp2 * priv)1221db9d7d36SMaxime Chevallier static void mvpp2_prs_dsa_init(struct mvpp2 *priv)
1222db9d7d36SMaxime Chevallier {
1223db9d7d36SMaxime Chevallier 	struct mvpp2_prs_entry pe;
1224db9d7d36SMaxime Chevallier 
1225db9d7d36SMaxime Chevallier 	/* None tagged EDSA entry - place holder */
1226db9d7d36SMaxime Chevallier 	mvpp2_prs_dsa_tag_set(priv, 0, false, MVPP2_PRS_UNTAGGED,
1227db9d7d36SMaxime Chevallier 			      MVPP2_PRS_EDSA);
1228db9d7d36SMaxime Chevallier 
1229db9d7d36SMaxime Chevallier 	/* Tagged EDSA entry - place holder */
1230db9d7d36SMaxime Chevallier 	mvpp2_prs_dsa_tag_set(priv, 0, false, MVPP2_PRS_TAGGED, MVPP2_PRS_EDSA);
1231db9d7d36SMaxime Chevallier 
1232db9d7d36SMaxime Chevallier 	/* None tagged DSA entry - place holder */
1233db9d7d36SMaxime Chevallier 	mvpp2_prs_dsa_tag_set(priv, 0, false, MVPP2_PRS_UNTAGGED,
1234db9d7d36SMaxime Chevallier 			      MVPP2_PRS_DSA);
1235db9d7d36SMaxime Chevallier 
1236db9d7d36SMaxime Chevallier 	/* Tagged DSA entry - place holder */
1237db9d7d36SMaxime Chevallier 	mvpp2_prs_dsa_tag_set(priv, 0, false, MVPP2_PRS_TAGGED, MVPP2_PRS_DSA);
1238db9d7d36SMaxime Chevallier 
1239db9d7d36SMaxime Chevallier 	/* None tagged EDSA ethertype entry - place holder*/
1240db9d7d36SMaxime Chevallier 	mvpp2_prs_dsa_tag_ethertype_set(priv, 0, false,
1241db9d7d36SMaxime Chevallier 					MVPP2_PRS_UNTAGGED, MVPP2_PRS_EDSA);
1242db9d7d36SMaxime Chevallier 
1243db9d7d36SMaxime Chevallier 	/* Tagged EDSA ethertype entry - place holder*/
1244db9d7d36SMaxime Chevallier 	mvpp2_prs_dsa_tag_ethertype_set(priv, 0, false,
1245db9d7d36SMaxime Chevallier 					MVPP2_PRS_TAGGED, MVPP2_PRS_EDSA);
1246db9d7d36SMaxime Chevallier 
1247db9d7d36SMaxime Chevallier 	/* None tagged DSA ethertype entry */
1248db9d7d36SMaxime Chevallier 	mvpp2_prs_dsa_tag_ethertype_set(priv, 0, true,
1249db9d7d36SMaxime Chevallier 					MVPP2_PRS_UNTAGGED, MVPP2_PRS_DSA);
1250db9d7d36SMaxime Chevallier 
1251db9d7d36SMaxime Chevallier 	/* Tagged DSA ethertype entry */
1252db9d7d36SMaxime Chevallier 	mvpp2_prs_dsa_tag_ethertype_set(priv, 0, true,
1253db9d7d36SMaxime Chevallier 					MVPP2_PRS_TAGGED, MVPP2_PRS_DSA);
1254db9d7d36SMaxime Chevallier 
1255db9d7d36SMaxime Chevallier 	/* Set default entry, in case DSA or EDSA tag not found */
1256db9d7d36SMaxime Chevallier 	memset(&pe, 0, sizeof(pe));
1257db9d7d36SMaxime Chevallier 	mvpp2_prs_tcam_lu_set(&pe, MVPP2_PRS_LU_DSA);
1258db9d7d36SMaxime Chevallier 	pe.index = MVPP2_PE_DSA_DEFAULT;
1259db9d7d36SMaxime Chevallier 	mvpp2_prs_sram_next_lu_set(&pe, MVPP2_PRS_LU_VLAN);
1260db9d7d36SMaxime Chevallier 
1261db9d7d36SMaxime Chevallier 	/* Shift 0 bytes */
1262db9d7d36SMaxime Chevallier 	mvpp2_prs_sram_shift_set(&pe, 0, MVPP2_PRS_SRAM_OP_SEL_SHIFT_ADD);
1263db9d7d36SMaxime Chevallier 	mvpp2_prs_shadow_set(priv, pe.index, MVPP2_PRS_LU_MAC);
1264db9d7d36SMaxime Chevallier 
1265db9d7d36SMaxime Chevallier 	/* Clear all sram ai bits for next iteration */
1266db9d7d36SMaxime Chevallier 	mvpp2_prs_sram_ai_update(&pe, 0, MVPP2_PRS_SRAM_AI_MASK);
1267db9d7d36SMaxime Chevallier 
1268db9d7d36SMaxime Chevallier 	/* Unmask all ports */
1269db9d7d36SMaxime Chevallier 	mvpp2_prs_tcam_port_map_set(&pe, MVPP2_PRS_PORT_MASK);
1270db9d7d36SMaxime Chevallier 
1271db9d7d36SMaxime Chevallier 	mvpp2_prs_hw_write(priv, &pe);
1272db9d7d36SMaxime Chevallier }
1273db9d7d36SMaxime Chevallier 
1274db9d7d36SMaxime Chevallier /* Initialize parser entries for VID filtering */
mvpp2_prs_vid_init(struct mvpp2 * priv)1275db9d7d36SMaxime Chevallier static void mvpp2_prs_vid_init(struct mvpp2 *priv)
1276db9d7d36SMaxime Chevallier {
1277db9d7d36SMaxime Chevallier 	struct mvpp2_prs_entry pe;
1278db9d7d36SMaxime Chevallier 
1279db9d7d36SMaxime Chevallier 	memset(&pe, 0, sizeof(pe));
1280db9d7d36SMaxime Chevallier 
1281db9d7d36SMaxime Chevallier 	/* Set default vid entry */
1282db9d7d36SMaxime Chevallier 	pe.index = MVPP2_PE_VID_FLTR_DEFAULT;
1283db9d7d36SMaxime Chevallier 	mvpp2_prs_tcam_lu_set(&pe, MVPP2_PRS_LU_VID);
1284db9d7d36SMaxime Chevallier 
1285db9d7d36SMaxime Chevallier 	mvpp2_prs_tcam_ai_update(&pe, 0, MVPP2_PRS_EDSA_VID_AI_BIT);
1286db9d7d36SMaxime Chevallier 
1287db9d7d36SMaxime Chevallier 	/* Skip VLAN header - Set offset to 4 bytes */
1288db9d7d36SMaxime Chevallier 	mvpp2_prs_sram_shift_set(&pe, MVPP2_VLAN_TAG_LEN,
1289db9d7d36SMaxime Chevallier 				 MVPP2_PRS_SRAM_OP_SEL_SHIFT_ADD);
1290db9d7d36SMaxime Chevallier 
1291db9d7d36SMaxime Chevallier 	/* Clear all ai bits for next iteration */
1292db9d7d36SMaxime Chevallier 	mvpp2_prs_sram_ai_update(&pe, 0, MVPP2_PRS_SRAM_AI_MASK);
1293db9d7d36SMaxime Chevallier 
1294db9d7d36SMaxime Chevallier 	mvpp2_prs_sram_next_lu_set(&pe, MVPP2_PRS_LU_L2);
1295db9d7d36SMaxime Chevallier 
1296db9d7d36SMaxime Chevallier 	/* Unmask all ports */
1297db9d7d36SMaxime Chevallier 	mvpp2_prs_tcam_port_map_set(&pe, MVPP2_PRS_PORT_MASK);
1298db9d7d36SMaxime Chevallier 
1299db9d7d36SMaxime Chevallier 	/* Update shadow table and hw entry */
1300db9d7d36SMaxime Chevallier 	mvpp2_prs_shadow_set(priv, pe.index, MVPP2_PRS_LU_VID);
1301db9d7d36SMaxime Chevallier 	mvpp2_prs_hw_write(priv, &pe);
1302db9d7d36SMaxime Chevallier 
1303db9d7d36SMaxime Chevallier 	/* Set default vid entry for extended DSA*/
1304db9d7d36SMaxime Chevallier 	memset(&pe, 0, sizeof(pe));
1305db9d7d36SMaxime Chevallier 
1306db9d7d36SMaxime Chevallier 	/* Set default vid entry */
1307db9d7d36SMaxime Chevallier 	pe.index = MVPP2_PE_VID_EDSA_FLTR_DEFAULT;
1308db9d7d36SMaxime Chevallier 	mvpp2_prs_tcam_lu_set(&pe, MVPP2_PRS_LU_VID);
1309db9d7d36SMaxime Chevallier 
1310db9d7d36SMaxime Chevallier 	mvpp2_prs_tcam_ai_update(&pe, MVPP2_PRS_EDSA_VID_AI_BIT,
1311db9d7d36SMaxime Chevallier 				 MVPP2_PRS_EDSA_VID_AI_BIT);
1312db9d7d36SMaxime Chevallier 
1313db9d7d36SMaxime Chevallier 	/* Skip VLAN header - Set offset to 8 bytes */
1314db9d7d36SMaxime Chevallier 	mvpp2_prs_sram_shift_set(&pe, MVPP2_VLAN_TAG_EDSA_LEN,
1315db9d7d36SMaxime Chevallier 				 MVPP2_PRS_SRAM_OP_SEL_SHIFT_ADD);
1316db9d7d36SMaxime Chevallier 
1317db9d7d36SMaxime Chevallier 	/* Clear all ai bits for next iteration */
1318db9d7d36SMaxime Chevallier 	mvpp2_prs_sram_ai_update(&pe, 0, MVPP2_PRS_SRAM_AI_MASK);
1319db9d7d36SMaxime Chevallier 
1320db9d7d36SMaxime Chevallier 	mvpp2_prs_sram_next_lu_set(&pe, MVPP2_PRS_LU_L2);
1321db9d7d36SMaxime Chevallier 
1322db9d7d36SMaxime Chevallier 	/* Unmask all ports */
1323db9d7d36SMaxime Chevallier 	mvpp2_prs_tcam_port_map_set(&pe, MVPP2_PRS_PORT_MASK);
1324db9d7d36SMaxime Chevallier 
1325db9d7d36SMaxime Chevallier 	/* Update shadow table and hw entry */
1326db9d7d36SMaxime Chevallier 	mvpp2_prs_shadow_set(priv, pe.index, MVPP2_PRS_LU_VID);
1327db9d7d36SMaxime Chevallier 	mvpp2_prs_hw_write(priv, &pe);
1328db9d7d36SMaxime Chevallier }
1329db9d7d36SMaxime Chevallier 
1330db9d7d36SMaxime Chevallier /* Match basic ethertypes */
mvpp2_prs_etype_init(struct mvpp2 * priv)1331db9d7d36SMaxime Chevallier static int mvpp2_prs_etype_init(struct mvpp2 *priv)
1332db9d7d36SMaxime Chevallier {
1333db9d7d36SMaxime Chevallier 	struct mvpp2_prs_entry pe;
13344ad29b1aSStefan Chulski 	int tid, ihl;
1335db9d7d36SMaxime Chevallier 
1336db9d7d36SMaxime Chevallier 	/* Ethertype: PPPoE */
1337db9d7d36SMaxime Chevallier 	tid = mvpp2_prs_tcam_first_free(priv, MVPP2_PE_FIRST_FREE_TID,
1338db9d7d36SMaxime Chevallier 					MVPP2_PE_LAST_FREE_TID);
1339db9d7d36SMaxime Chevallier 	if (tid < 0)
1340db9d7d36SMaxime Chevallier 		return tid;
1341db9d7d36SMaxime Chevallier 
1342db9d7d36SMaxime Chevallier 	memset(&pe, 0, sizeof(pe));
1343db9d7d36SMaxime Chevallier 	mvpp2_prs_tcam_lu_set(&pe, MVPP2_PRS_LU_L2);
1344db9d7d36SMaxime Chevallier 	pe.index = tid;
1345db9d7d36SMaxime Chevallier 
1346db9d7d36SMaxime Chevallier 	mvpp2_prs_match_etype(&pe, 0, ETH_P_PPP_SES);
1347db9d7d36SMaxime Chevallier 
1348db9d7d36SMaxime Chevallier 	mvpp2_prs_sram_shift_set(&pe, MVPP2_PPPOE_HDR_SIZE,
1349db9d7d36SMaxime Chevallier 				 MVPP2_PRS_SRAM_OP_SEL_SHIFT_ADD);
1350db9d7d36SMaxime Chevallier 	mvpp2_prs_sram_next_lu_set(&pe, MVPP2_PRS_LU_PPPOE);
1351db9d7d36SMaxime Chevallier 	mvpp2_prs_sram_ri_update(&pe, MVPP2_PRS_RI_PPPOE_MASK,
1352db9d7d36SMaxime Chevallier 				 MVPP2_PRS_RI_PPPOE_MASK);
1353db9d7d36SMaxime Chevallier 
1354db9d7d36SMaxime Chevallier 	/* Update shadow table and hw entry */
1355db9d7d36SMaxime Chevallier 	mvpp2_prs_shadow_set(priv, pe.index, MVPP2_PRS_LU_L2);
1356db9d7d36SMaxime Chevallier 	priv->prs_shadow[pe.index].udf = MVPP2_PRS_UDF_L2_DEF;
1357db9d7d36SMaxime Chevallier 	priv->prs_shadow[pe.index].finish = false;
1358db9d7d36SMaxime Chevallier 	mvpp2_prs_shadow_ri_set(priv, pe.index, MVPP2_PRS_RI_PPPOE_MASK,
1359db9d7d36SMaxime Chevallier 				MVPP2_PRS_RI_PPPOE_MASK);
1360db9d7d36SMaxime Chevallier 	mvpp2_prs_hw_write(priv, &pe);
1361db9d7d36SMaxime Chevallier 
1362db9d7d36SMaxime Chevallier 	/* Ethertype: ARP */
1363db9d7d36SMaxime Chevallier 	tid = mvpp2_prs_tcam_first_free(priv, MVPP2_PE_FIRST_FREE_TID,
1364db9d7d36SMaxime Chevallier 					MVPP2_PE_LAST_FREE_TID);
1365db9d7d36SMaxime Chevallier 	if (tid < 0)
1366db9d7d36SMaxime Chevallier 		return tid;
1367db9d7d36SMaxime Chevallier 
1368db9d7d36SMaxime Chevallier 	memset(&pe, 0, sizeof(pe));
1369db9d7d36SMaxime Chevallier 	mvpp2_prs_tcam_lu_set(&pe, MVPP2_PRS_LU_L2);
1370db9d7d36SMaxime Chevallier 	pe.index = tid;
1371db9d7d36SMaxime Chevallier 
1372db9d7d36SMaxime Chevallier 	mvpp2_prs_match_etype(&pe, 0, ETH_P_ARP);
1373db9d7d36SMaxime Chevallier 
1374db9d7d36SMaxime Chevallier 	/* Generate flow in the next iteration*/
1375db9d7d36SMaxime Chevallier 	mvpp2_prs_sram_next_lu_set(&pe, MVPP2_PRS_LU_FLOWS);
1376db9d7d36SMaxime Chevallier 	mvpp2_prs_sram_bits_set(&pe, MVPP2_PRS_SRAM_LU_GEN_BIT, 1);
1377db9d7d36SMaxime Chevallier 	mvpp2_prs_sram_ri_update(&pe, MVPP2_PRS_RI_L3_ARP,
1378db9d7d36SMaxime Chevallier 				 MVPP2_PRS_RI_L3_PROTO_MASK);
1379db9d7d36SMaxime Chevallier 	/* Set L3 offset */
1380db9d7d36SMaxime Chevallier 	mvpp2_prs_sram_offset_set(&pe, MVPP2_PRS_SRAM_UDF_TYPE_L3,
1381db9d7d36SMaxime Chevallier 				  MVPP2_ETH_TYPE_LEN,
1382db9d7d36SMaxime Chevallier 				  MVPP2_PRS_SRAM_OP_SEL_UDF_ADD);
1383db9d7d36SMaxime Chevallier 
1384db9d7d36SMaxime Chevallier 	/* Update shadow table and hw entry */
1385db9d7d36SMaxime Chevallier 	mvpp2_prs_shadow_set(priv, pe.index, MVPP2_PRS_LU_L2);
1386db9d7d36SMaxime Chevallier 	priv->prs_shadow[pe.index].udf = MVPP2_PRS_UDF_L2_DEF;
1387db9d7d36SMaxime Chevallier 	priv->prs_shadow[pe.index].finish = true;
1388db9d7d36SMaxime Chevallier 	mvpp2_prs_shadow_ri_set(priv, pe.index, MVPP2_PRS_RI_L3_ARP,
1389db9d7d36SMaxime Chevallier 				MVPP2_PRS_RI_L3_PROTO_MASK);
1390db9d7d36SMaxime Chevallier 	mvpp2_prs_hw_write(priv, &pe);
1391db9d7d36SMaxime Chevallier 
1392db9d7d36SMaxime Chevallier 	/* Ethertype: LBTD */
1393db9d7d36SMaxime Chevallier 	tid = mvpp2_prs_tcam_first_free(priv, MVPP2_PE_FIRST_FREE_TID,
1394db9d7d36SMaxime Chevallier 					MVPP2_PE_LAST_FREE_TID);
1395db9d7d36SMaxime Chevallier 	if (tid < 0)
1396db9d7d36SMaxime Chevallier 		return tid;
1397db9d7d36SMaxime Chevallier 
1398db9d7d36SMaxime Chevallier 	memset(&pe, 0, sizeof(pe));
1399db9d7d36SMaxime Chevallier 	mvpp2_prs_tcam_lu_set(&pe, MVPP2_PRS_LU_L2);
1400db9d7d36SMaxime Chevallier 	pe.index = tid;
1401db9d7d36SMaxime Chevallier 
1402db9d7d36SMaxime Chevallier 	mvpp2_prs_match_etype(&pe, 0, MVPP2_IP_LBDT_TYPE);
1403db9d7d36SMaxime Chevallier 
1404db9d7d36SMaxime Chevallier 	/* Generate flow in the next iteration*/
1405db9d7d36SMaxime Chevallier 	mvpp2_prs_sram_next_lu_set(&pe, MVPP2_PRS_LU_FLOWS);
1406db9d7d36SMaxime Chevallier 	mvpp2_prs_sram_bits_set(&pe, MVPP2_PRS_SRAM_LU_GEN_BIT, 1);
1407db9d7d36SMaxime Chevallier 	mvpp2_prs_sram_ri_update(&pe, MVPP2_PRS_RI_CPU_CODE_RX_SPEC |
1408db9d7d36SMaxime Chevallier 				 MVPP2_PRS_RI_UDF3_RX_SPECIAL,
1409db9d7d36SMaxime Chevallier 				 MVPP2_PRS_RI_CPU_CODE_MASK |
1410db9d7d36SMaxime Chevallier 				 MVPP2_PRS_RI_UDF3_MASK);
1411db9d7d36SMaxime Chevallier 	/* Set L3 offset */
1412db9d7d36SMaxime Chevallier 	mvpp2_prs_sram_offset_set(&pe, MVPP2_PRS_SRAM_UDF_TYPE_L3,
1413db9d7d36SMaxime Chevallier 				  MVPP2_ETH_TYPE_LEN,
1414db9d7d36SMaxime Chevallier 				  MVPP2_PRS_SRAM_OP_SEL_UDF_ADD);
1415db9d7d36SMaxime Chevallier 
1416db9d7d36SMaxime Chevallier 	/* Update shadow table and hw entry */
1417db9d7d36SMaxime Chevallier 	mvpp2_prs_shadow_set(priv, pe.index, MVPP2_PRS_LU_L2);
1418db9d7d36SMaxime Chevallier 	priv->prs_shadow[pe.index].udf = MVPP2_PRS_UDF_L2_DEF;
1419db9d7d36SMaxime Chevallier 	priv->prs_shadow[pe.index].finish = true;
1420db9d7d36SMaxime Chevallier 	mvpp2_prs_shadow_ri_set(priv, pe.index, MVPP2_PRS_RI_CPU_CODE_RX_SPEC |
1421db9d7d36SMaxime Chevallier 				MVPP2_PRS_RI_UDF3_RX_SPECIAL,
1422db9d7d36SMaxime Chevallier 				MVPP2_PRS_RI_CPU_CODE_MASK |
1423db9d7d36SMaxime Chevallier 				MVPP2_PRS_RI_UDF3_MASK);
1424db9d7d36SMaxime Chevallier 	mvpp2_prs_hw_write(priv, &pe);
1425db9d7d36SMaxime Chevallier 
14264ad29b1aSStefan Chulski 	/* Ethertype: IPv4 with header length >= 5 */
14274ad29b1aSStefan Chulski 	for (ihl = MVPP2_PRS_IPV4_IHL_MIN; ihl <= MVPP2_PRS_IPV4_IHL_MAX; ihl++) {
1428db9d7d36SMaxime Chevallier 		tid = mvpp2_prs_tcam_first_free(priv, MVPP2_PE_FIRST_FREE_TID,
1429db9d7d36SMaxime Chevallier 						MVPP2_PE_LAST_FREE_TID);
1430db9d7d36SMaxime Chevallier 		if (tid < 0)
1431db9d7d36SMaxime Chevallier 			return tid;
1432db9d7d36SMaxime Chevallier 
1433db9d7d36SMaxime Chevallier 		memset(&pe, 0, sizeof(pe));
1434db9d7d36SMaxime Chevallier 		mvpp2_prs_tcam_lu_set(&pe, MVPP2_PRS_LU_L2);
1435db9d7d36SMaxime Chevallier 		pe.index = tid;
1436db9d7d36SMaxime Chevallier 
1437db9d7d36SMaxime Chevallier 		mvpp2_prs_match_etype(&pe, 0, ETH_P_IP);
1438db9d7d36SMaxime Chevallier 		mvpp2_prs_tcam_data_byte_set(&pe, MVPP2_ETH_TYPE_LEN,
14394ad29b1aSStefan Chulski 					     MVPP2_PRS_IPV4_HEAD | ihl,
1440db9d7d36SMaxime Chevallier 					     MVPP2_PRS_IPV4_HEAD_MASK |
1441db9d7d36SMaxime Chevallier 					     MVPP2_PRS_IPV4_IHL_MASK);
1442db9d7d36SMaxime Chevallier 
1443db9d7d36SMaxime Chevallier 		mvpp2_prs_sram_next_lu_set(&pe, MVPP2_PRS_LU_IP4);
1444db9d7d36SMaxime Chevallier 		mvpp2_prs_sram_ri_update(&pe, MVPP2_PRS_RI_L3_IP4,
1445db9d7d36SMaxime Chevallier 					 MVPP2_PRS_RI_L3_PROTO_MASK);
14464ad29b1aSStefan Chulski 		/* goto ipv4 dst-address (skip eth_type + IP-header-size - 4) */
1447c73a4596SStefan Chulski 		mvpp2_prs_sram_shift_set(&pe, MVPP2_ETH_TYPE_LEN +
1448c73a4596SStefan Chulski 					 sizeof(struct iphdr) - 4,
1449db9d7d36SMaxime Chevallier 					 MVPP2_PRS_SRAM_OP_SEL_SHIFT_ADD);
14504ad29b1aSStefan Chulski 		/* Set L4 offset */
14514ad29b1aSStefan Chulski 		mvpp2_prs_sram_offset_set(&pe, MVPP2_PRS_SRAM_UDF_TYPE_L4,
14524ad29b1aSStefan Chulski 					  MVPP2_ETH_TYPE_LEN + (ihl * 4),
1453db9d7d36SMaxime Chevallier 					  MVPP2_PRS_SRAM_OP_SEL_UDF_ADD);
1454db9d7d36SMaxime Chevallier 
1455db9d7d36SMaxime Chevallier 		/* Update shadow table and hw entry */
1456db9d7d36SMaxime Chevallier 		mvpp2_prs_shadow_set(priv, pe.index, MVPP2_PRS_LU_L2);
1457db9d7d36SMaxime Chevallier 		priv->prs_shadow[pe.index].udf = MVPP2_PRS_UDF_L2_DEF;
1458db9d7d36SMaxime Chevallier 		priv->prs_shadow[pe.index].finish = false;
1459db9d7d36SMaxime Chevallier 		mvpp2_prs_shadow_ri_set(priv, pe.index, MVPP2_PRS_RI_L3_IP4,
1460db9d7d36SMaxime Chevallier 					MVPP2_PRS_RI_L3_PROTO_MASK);
1461db9d7d36SMaxime Chevallier 		mvpp2_prs_hw_write(priv, &pe);
14624ad29b1aSStefan Chulski 	}
1463db9d7d36SMaxime Chevallier 
1464db9d7d36SMaxime Chevallier 	/* Ethertype: IPv6 without options */
1465db9d7d36SMaxime Chevallier 	tid = mvpp2_prs_tcam_first_free(priv, MVPP2_PE_FIRST_FREE_TID,
1466db9d7d36SMaxime Chevallier 					MVPP2_PE_LAST_FREE_TID);
1467db9d7d36SMaxime Chevallier 	if (tid < 0)
1468db9d7d36SMaxime Chevallier 		return tid;
1469db9d7d36SMaxime Chevallier 
1470db9d7d36SMaxime Chevallier 	memset(&pe, 0, sizeof(pe));
1471db9d7d36SMaxime Chevallier 	mvpp2_prs_tcam_lu_set(&pe, MVPP2_PRS_LU_L2);
1472db9d7d36SMaxime Chevallier 	pe.index = tid;
1473db9d7d36SMaxime Chevallier 
1474db9d7d36SMaxime Chevallier 	mvpp2_prs_match_etype(&pe, 0, ETH_P_IPV6);
1475db9d7d36SMaxime Chevallier 
1476db9d7d36SMaxime Chevallier 	/* Skip DIP of IPV6 header */
1477db9d7d36SMaxime Chevallier 	mvpp2_prs_sram_shift_set(&pe, MVPP2_ETH_TYPE_LEN + 8 +
1478db9d7d36SMaxime Chevallier 				 MVPP2_MAX_L3_ADDR_SIZE,
1479db9d7d36SMaxime Chevallier 				 MVPP2_PRS_SRAM_OP_SEL_SHIFT_ADD);
1480db9d7d36SMaxime Chevallier 	mvpp2_prs_sram_next_lu_set(&pe, MVPP2_PRS_LU_IP6);
1481db9d7d36SMaxime Chevallier 	mvpp2_prs_sram_ri_update(&pe, MVPP2_PRS_RI_L3_IP6,
1482db9d7d36SMaxime Chevallier 				 MVPP2_PRS_RI_L3_PROTO_MASK);
1483db9d7d36SMaxime Chevallier 	/* Set L3 offset */
1484db9d7d36SMaxime Chevallier 	mvpp2_prs_sram_offset_set(&pe, MVPP2_PRS_SRAM_UDF_TYPE_L3,
1485db9d7d36SMaxime Chevallier 				  MVPP2_ETH_TYPE_LEN,
1486db9d7d36SMaxime Chevallier 				  MVPP2_PRS_SRAM_OP_SEL_UDF_ADD);
1487db9d7d36SMaxime Chevallier 
1488db9d7d36SMaxime Chevallier 	mvpp2_prs_shadow_set(priv, pe.index, MVPP2_PRS_LU_L2);
1489db9d7d36SMaxime Chevallier 	priv->prs_shadow[pe.index].udf = MVPP2_PRS_UDF_L2_DEF;
1490db9d7d36SMaxime Chevallier 	priv->prs_shadow[pe.index].finish = false;
1491db9d7d36SMaxime Chevallier 	mvpp2_prs_shadow_ri_set(priv, pe.index, MVPP2_PRS_RI_L3_IP6,
1492db9d7d36SMaxime Chevallier 				MVPP2_PRS_RI_L3_PROTO_MASK);
1493db9d7d36SMaxime Chevallier 	mvpp2_prs_hw_write(priv, &pe);
1494db9d7d36SMaxime Chevallier 
1495db9d7d36SMaxime Chevallier 	/* Default entry for MVPP2_PRS_LU_L2 - Unknown ethtype */
1496db9d7d36SMaxime Chevallier 	memset(&pe, 0, sizeof(struct mvpp2_prs_entry));
1497db9d7d36SMaxime Chevallier 	mvpp2_prs_tcam_lu_set(&pe, MVPP2_PRS_LU_L2);
1498db9d7d36SMaxime Chevallier 	pe.index = MVPP2_PE_ETH_TYPE_UN;
1499db9d7d36SMaxime Chevallier 
1500db9d7d36SMaxime Chevallier 	/* Unmask all ports */
1501db9d7d36SMaxime Chevallier 	mvpp2_prs_tcam_port_map_set(&pe, MVPP2_PRS_PORT_MASK);
1502db9d7d36SMaxime Chevallier 
1503db9d7d36SMaxime Chevallier 	/* Generate flow in the next iteration*/
1504db9d7d36SMaxime Chevallier 	mvpp2_prs_sram_bits_set(&pe, MVPP2_PRS_SRAM_LU_GEN_BIT, 1);
1505db9d7d36SMaxime Chevallier 	mvpp2_prs_sram_next_lu_set(&pe, MVPP2_PRS_LU_FLOWS);
1506db9d7d36SMaxime Chevallier 	mvpp2_prs_sram_ri_update(&pe, MVPP2_PRS_RI_L3_UN,
1507db9d7d36SMaxime Chevallier 				 MVPP2_PRS_RI_L3_PROTO_MASK);
1508db9d7d36SMaxime Chevallier 	/* Set L3 offset even it's unknown L3 */
1509db9d7d36SMaxime Chevallier 	mvpp2_prs_sram_offset_set(&pe, MVPP2_PRS_SRAM_UDF_TYPE_L3,
1510db9d7d36SMaxime Chevallier 				  MVPP2_ETH_TYPE_LEN,
1511db9d7d36SMaxime Chevallier 				  MVPP2_PRS_SRAM_OP_SEL_UDF_ADD);
1512db9d7d36SMaxime Chevallier 
1513db9d7d36SMaxime Chevallier 	/* Update shadow table and hw entry */
1514db9d7d36SMaxime Chevallier 	mvpp2_prs_shadow_set(priv, pe.index, MVPP2_PRS_LU_L2);
1515db9d7d36SMaxime Chevallier 	priv->prs_shadow[pe.index].udf = MVPP2_PRS_UDF_L2_DEF;
1516db9d7d36SMaxime Chevallier 	priv->prs_shadow[pe.index].finish = true;
1517db9d7d36SMaxime Chevallier 	mvpp2_prs_shadow_ri_set(priv, pe.index, MVPP2_PRS_RI_L3_UN,
1518db9d7d36SMaxime Chevallier 				MVPP2_PRS_RI_L3_PROTO_MASK);
1519db9d7d36SMaxime Chevallier 	mvpp2_prs_hw_write(priv, &pe);
1520db9d7d36SMaxime Chevallier 
1521db9d7d36SMaxime Chevallier 	return 0;
1522db9d7d36SMaxime Chevallier }
1523db9d7d36SMaxime Chevallier 
1524db9d7d36SMaxime Chevallier /* Configure vlan entries and detect up to 2 successive VLAN tags.
1525db9d7d36SMaxime Chevallier  * Possible options:
1526db9d7d36SMaxime Chevallier  * 0x8100, 0x88A8
1527db9d7d36SMaxime Chevallier  * 0x8100, 0x8100
1528db9d7d36SMaxime Chevallier  * 0x8100
1529db9d7d36SMaxime Chevallier  * 0x88A8
1530db9d7d36SMaxime Chevallier  */
mvpp2_prs_vlan_init(struct platform_device * pdev,struct mvpp2 * priv)1531db9d7d36SMaxime Chevallier static int mvpp2_prs_vlan_init(struct platform_device *pdev, struct mvpp2 *priv)
1532db9d7d36SMaxime Chevallier {
1533db9d7d36SMaxime Chevallier 	struct mvpp2_prs_entry pe;
1534db9d7d36SMaxime Chevallier 	int err;
1535db9d7d36SMaxime Chevallier 
1536db9d7d36SMaxime Chevallier 	priv->prs_double_vlans = devm_kcalloc(&pdev->dev, sizeof(bool),
1537db9d7d36SMaxime Chevallier 					      MVPP2_PRS_DBL_VLANS_MAX,
1538db9d7d36SMaxime Chevallier 					      GFP_KERNEL);
1539db9d7d36SMaxime Chevallier 	if (!priv->prs_double_vlans)
1540db9d7d36SMaxime Chevallier 		return -ENOMEM;
1541db9d7d36SMaxime Chevallier 
1542a587a848SSven Auhagen 	/* Double VLAN: 0x88A8, 0x8100 */
1543a587a848SSven Auhagen 	err = mvpp2_prs_double_vlan_add(priv, ETH_P_8021AD, ETH_P_8021Q,
1544db9d7d36SMaxime Chevallier 					MVPP2_PRS_PORT_MASK);
1545db9d7d36SMaxime Chevallier 	if (err)
1546db9d7d36SMaxime Chevallier 		return err;
1547db9d7d36SMaxime Chevallier 
1548db9d7d36SMaxime Chevallier 	/* Double VLAN: 0x8100, 0x8100 */
1549db9d7d36SMaxime Chevallier 	err = mvpp2_prs_double_vlan_add(priv, ETH_P_8021Q, ETH_P_8021Q,
1550db9d7d36SMaxime Chevallier 					MVPP2_PRS_PORT_MASK);
1551db9d7d36SMaxime Chevallier 	if (err)
1552db9d7d36SMaxime Chevallier 		return err;
1553db9d7d36SMaxime Chevallier 
1554db9d7d36SMaxime Chevallier 	/* Single VLAN: 0x88a8 */
1555db9d7d36SMaxime Chevallier 	err = mvpp2_prs_vlan_add(priv, ETH_P_8021AD, MVPP2_PRS_SINGLE_VLAN_AI,
1556db9d7d36SMaxime Chevallier 				 MVPP2_PRS_PORT_MASK);
1557db9d7d36SMaxime Chevallier 	if (err)
1558db9d7d36SMaxime Chevallier 		return err;
1559db9d7d36SMaxime Chevallier 
1560db9d7d36SMaxime Chevallier 	/* Single VLAN: 0x8100 */
1561db9d7d36SMaxime Chevallier 	err = mvpp2_prs_vlan_add(priv, ETH_P_8021Q, MVPP2_PRS_SINGLE_VLAN_AI,
1562db9d7d36SMaxime Chevallier 				 MVPP2_PRS_PORT_MASK);
1563db9d7d36SMaxime Chevallier 	if (err)
1564db9d7d36SMaxime Chevallier 		return err;
1565db9d7d36SMaxime Chevallier 
1566db9d7d36SMaxime Chevallier 	/* Set default double vlan entry */
1567db9d7d36SMaxime Chevallier 	memset(&pe, 0, sizeof(pe));
1568db9d7d36SMaxime Chevallier 	mvpp2_prs_tcam_lu_set(&pe, MVPP2_PRS_LU_VLAN);
1569db9d7d36SMaxime Chevallier 	pe.index = MVPP2_PE_VLAN_DBL;
1570db9d7d36SMaxime Chevallier 
1571db9d7d36SMaxime Chevallier 	mvpp2_prs_sram_next_lu_set(&pe, MVPP2_PRS_LU_VID);
1572db9d7d36SMaxime Chevallier 
1573db9d7d36SMaxime Chevallier 	/* Clear ai for next iterations */
1574db9d7d36SMaxime Chevallier 	mvpp2_prs_sram_ai_update(&pe, 0, MVPP2_PRS_SRAM_AI_MASK);
1575db9d7d36SMaxime Chevallier 	mvpp2_prs_sram_ri_update(&pe, MVPP2_PRS_RI_VLAN_DOUBLE,
1576db9d7d36SMaxime Chevallier 				 MVPP2_PRS_RI_VLAN_MASK);
1577db9d7d36SMaxime Chevallier 
1578db9d7d36SMaxime Chevallier 	mvpp2_prs_tcam_ai_update(&pe, MVPP2_PRS_DBL_VLAN_AI_BIT,
1579db9d7d36SMaxime Chevallier 				 MVPP2_PRS_DBL_VLAN_AI_BIT);
1580db9d7d36SMaxime Chevallier 	/* Unmask all ports */
1581db9d7d36SMaxime Chevallier 	mvpp2_prs_tcam_port_map_set(&pe, MVPP2_PRS_PORT_MASK);
1582db9d7d36SMaxime Chevallier 
1583db9d7d36SMaxime Chevallier 	/* Update shadow table and hw entry */
1584db9d7d36SMaxime Chevallier 	mvpp2_prs_shadow_set(priv, pe.index, MVPP2_PRS_LU_VLAN);
1585db9d7d36SMaxime Chevallier 	mvpp2_prs_hw_write(priv, &pe);
1586db9d7d36SMaxime Chevallier 
1587db9d7d36SMaxime Chevallier 	/* Set default vlan none entry */
1588db9d7d36SMaxime Chevallier 	memset(&pe, 0, sizeof(pe));
1589db9d7d36SMaxime Chevallier 	mvpp2_prs_tcam_lu_set(&pe, MVPP2_PRS_LU_VLAN);
1590db9d7d36SMaxime Chevallier 	pe.index = MVPP2_PE_VLAN_NONE;
1591db9d7d36SMaxime Chevallier 
1592db9d7d36SMaxime Chevallier 	mvpp2_prs_sram_next_lu_set(&pe, MVPP2_PRS_LU_L2);
1593db9d7d36SMaxime Chevallier 	mvpp2_prs_sram_ri_update(&pe, MVPP2_PRS_RI_VLAN_NONE,
1594db9d7d36SMaxime Chevallier 				 MVPP2_PRS_RI_VLAN_MASK);
1595db9d7d36SMaxime Chevallier 
1596db9d7d36SMaxime Chevallier 	/* Unmask all ports */
1597db9d7d36SMaxime Chevallier 	mvpp2_prs_tcam_port_map_set(&pe, MVPP2_PRS_PORT_MASK);
1598db9d7d36SMaxime Chevallier 
1599db9d7d36SMaxime Chevallier 	/* Update shadow table and hw entry */
1600db9d7d36SMaxime Chevallier 	mvpp2_prs_shadow_set(priv, pe.index, MVPP2_PRS_LU_VLAN);
1601db9d7d36SMaxime Chevallier 	mvpp2_prs_hw_write(priv, &pe);
1602db9d7d36SMaxime Chevallier 
1603db9d7d36SMaxime Chevallier 	return 0;
1604db9d7d36SMaxime Chevallier }
1605db9d7d36SMaxime Chevallier 
1606db9d7d36SMaxime Chevallier /* Set entries for PPPoE ethertype */
mvpp2_prs_pppoe_init(struct mvpp2 * priv)1607db9d7d36SMaxime Chevallier static int mvpp2_prs_pppoe_init(struct mvpp2 *priv)
1608db9d7d36SMaxime Chevallier {
1609db9d7d36SMaxime Chevallier 	struct mvpp2_prs_entry pe;
1610*031a416cSSven Auhagen 	int tid, ihl;
1611db9d7d36SMaxime Chevallier 
1612*031a416cSSven Auhagen 	/* IPv4 over PPPoE with header length >= 5 */
1613*031a416cSSven Auhagen 	for (ihl = MVPP2_PRS_IPV4_IHL_MIN; ihl <= MVPP2_PRS_IPV4_IHL_MAX; ihl++) {
1614db9d7d36SMaxime Chevallier 		tid = mvpp2_prs_tcam_first_free(priv, MVPP2_PE_FIRST_FREE_TID,
1615db9d7d36SMaxime Chevallier 						MVPP2_PE_LAST_FREE_TID);
1616db9d7d36SMaxime Chevallier 		if (tid < 0)
1617db9d7d36SMaxime Chevallier 			return tid;
1618db9d7d36SMaxime Chevallier 
1619db9d7d36SMaxime Chevallier 		memset(&pe, 0, sizeof(pe));
1620db9d7d36SMaxime Chevallier 		mvpp2_prs_tcam_lu_set(&pe, MVPP2_PRS_LU_PPPOE);
1621db9d7d36SMaxime Chevallier 		pe.index = tid;
1622db9d7d36SMaxime Chevallier 
1623db9d7d36SMaxime Chevallier 		mvpp2_prs_match_etype(&pe, 0, PPP_IP);
1624*031a416cSSven Auhagen 		mvpp2_prs_tcam_data_byte_set(&pe, MVPP2_ETH_TYPE_LEN,
1625*031a416cSSven Auhagen 					     MVPP2_PRS_IPV4_HEAD | ihl,
1626*031a416cSSven Auhagen 					     MVPP2_PRS_IPV4_HEAD_MASK |
1627*031a416cSSven Auhagen 					     MVPP2_PRS_IPV4_IHL_MASK);
1628db9d7d36SMaxime Chevallier 
1629db9d7d36SMaxime Chevallier 		mvpp2_prs_sram_next_lu_set(&pe, MVPP2_PRS_LU_IP4);
1630*031a416cSSven Auhagen 		mvpp2_prs_sram_ri_update(&pe, MVPP2_PRS_RI_L3_IP4,
1631db9d7d36SMaxime Chevallier 					 MVPP2_PRS_RI_L3_PROTO_MASK);
1632*031a416cSSven Auhagen 		/* goto ipv4 dst-address (skip eth_type + IP-header-size - 4) */
1633c73a4596SStefan Chulski 		mvpp2_prs_sram_shift_set(&pe, MVPP2_ETH_TYPE_LEN +
1634c73a4596SStefan Chulski 					 sizeof(struct iphdr) - 4,
1635db9d7d36SMaxime Chevallier 					 MVPP2_PRS_SRAM_OP_SEL_SHIFT_ADD);
1636db9d7d36SMaxime Chevallier 		/* Set L3 offset */
1637db9d7d36SMaxime Chevallier 		mvpp2_prs_sram_offset_set(&pe, MVPP2_PRS_SRAM_UDF_TYPE_L3,
1638db9d7d36SMaxime Chevallier 					  MVPP2_ETH_TYPE_LEN,
1639db9d7d36SMaxime Chevallier 					  MVPP2_PRS_SRAM_OP_SEL_UDF_ADD);
1640*031a416cSSven Auhagen 		/* Set L4 offset */
1641*031a416cSSven Auhagen 		mvpp2_prs_sram_offset_set(&pe, MVPP2_PRS_SRAM_UDF_TYPE_L4,
1642*031a416cSSven Auhagen 					  MVPP2_ETH_TYPE_LEN + (ihl * 4),
1643*031a416cSSven Auhagen 					  MVPP2_PRS_SRAM_OP_SEL_UDF_ADD);
1644db9d7d36SMaxime Chevallier 
1645db9d7d36SMaxime Chevallier 		/* Update shadow table and hw entry */
1646db9d7d36SMaxime Chevallier 		mvpp2_prs_shadow_set(priv, pe.index, MVPP2_PRS_LU_PPPOE);
1647db9d7d36SMaxime Chevallier 		mvpp2_prs_hw_write(priv, &pe);
1648*031a416cSSven Auhagen 	}
1649db9d7d36SMaxime Chevallier 
1650db9d7d36SMaxime Chevallier 	/* IPv6 over PPPoE */
1651db9d7d36SMaxime Chevallier 	tid = mvpp2_prs_tcam_first_free(priv, MVPP2_PE_FIRST_FREE_TID,
1652db9d7d36SMaxime Chevallier 					MVPP2_PE_LAST_FREE_TID);
1653db9d7d36SMaxime Chevallier 	if (tid < 0)
1654db9d7d36SMaxime Chevallier 		return tid;
1655db9d7d36SMaxime Chevallier 
1656db9d7d36SMaxime Chevallier 	memset(&pe, 0, sizeof(pe));
1657db9d7d36SMaxime Chevallier 	mvpp2_prs_tcam_lu_set(&pe, MVPP2_PRS_LU_PPPOE);
1658db9d7d36SMaxime Chevallier 	pe.index = tid;
1659db9d7d36SMaxime Chevallier 
1660db9d7d36SMaxime Chevallier 	mvpp2_prs_match_etype(&pe, 0, PPP_IPV6);
1661db9d7d36SMaxime Chevallier 
1662db9d7d36SMaxime Chevallier 	mvpp2_prs_sram_next_lu_set(&pe, MVPP2_PRS_LU_IP6);
1663db9d7d36SMaxime Chevallier 	mvpp2_prs_sram_ri_update(&pe, MVPP2_PRS_RI_L3_IP6,
1664db9d7d36SMaxime Chevallier 				 MVPP2_PRS_RI_L3_PROTO_MASK);
1665fec6079bSStefan Chulski 	/* Jump to DIP of IPV6 header */
1666fec6079bSStefan Chulski 	mvpp2_prs_sram_shift_set(&pe, MVPP2_ETH_TYPE_LEN + 8 +
1667fec6079bSStefan Chulski 				 MVPP2_MAX_L3_ADDR_SIZE,
1668db9d7d36SMaxime Chevallier 				 MVPP2_PRS_SRAM_OP_SEL_SHIFT_ADD);
1669db9d7d36SMaxime Chevallier 	/* Set L3 offset */
1670db9d7d36SMaxime Chevallier 	mvpp2_prs_sram_offset_set(&pe, MVPP2_PRS_SRAM_UDF_TYPE_L3,
1671db9d7d36SMaxime Chevallier 				  MVPP2_ETH_TYPE_LEN,
1672db9d7d36SMaxime Chevallier 				  MVPP2_PRS_SRAM_OP_SEL_UDF_ADD);
1673db9d7d36SMaxime Chevallier 
1674db9d7d36SMaxime Chevallier 	/* Update shadow table and hw entry */
1675db9d7d36SMaxime Chevallier 	mvpp2_prs_shadow_set(priv, pe.index, MVPP2_PRS_LU_PPPOE);
1676db9d7d36SMaxime Chevallier 	mvpp2_prs_hw_write(priv, &pe);
1677db9d7d36SMaxime Chevallier 
1678db9d7d36SMaxime Chevallier 	/* Non-IP over PPPoE */
1679db9d7d36SMaxime Chevallier 	tid = mvpp2_prs_tcam_first_free(priv, MVPP2_PE_FIRST_FREE_TID,
1680db9d7d36SMaxime Chevallier 					MVPP2_PE_LAST_FREE_TID);
1681db9d7d36SMaxime Chevallier 	if (tid < 0)
1682db9d7d36SMaxime Chevallier 		return tid;
1683db9d7d36SMaxime Chevallier 
1684db9d7d36SMaxime Chevallier 	memset(&pe, 0, sizeof(pe));
1685db9d7d36SMaxime Chevallier 	mvpp2_prs_tcam_lu_set(&pe, MVPP2_PRS_LU_PPPOE);
1686db9d7d36SMaxime Chevallier 	pe.index = tid;
1687db9d7d36SMaxime Chevallier 
1688db9d7d36SMaxime Chevallier 	mvpp2_prs_sram_ri_update(&pe, MVPP2_PRS_RI_L3_UN,
1689db9d7d36SMaxime Chevallier 				 MVPP2_PRS_RI_L3_PROTO_MASK);
1690db9d7d36SMaxime Chevallier 
1691db9d7d36SMaxime Chevallier 	/* Finished: go to flowid generation */
1692db9d7d36SMaxime Chevallier 	mvpp2_prs_sram_next_lu_set(&pe, MVPP2_PRS_LU_FLOWS);
1693db9d7d36SMaxime Chevallier 	mvpp2_prs_sram_bits_set(&pe, MVPP2_PRS_SRAM_LU_GEN_BIT, 1);
1694db9d7d36SMaxime Chevallier 	/* Set L3 offset even if it's unknown L3 */
1695db9d7d36SMaxime Chevallier 	mvpp2_prs_sram_offset_set(&pe, MVPP2_PRS_SRAM_UDF_TYPE_L3,
1696db9d7d36SMaxime Chevallier 				  MVPP2_ETH_TYPE_LEN,
1697db9d7d36SMaxime Chevallier 				  MVPP2_PRS_SRAM_OP_SEL_UDF_ADD);
1698db9d7d36SMaxime Chevallier 
1699db9d7d36SMaxime Chevallier 	/* Update shadow table and hw entry */
1700db9d7d36SMaxime Chevallier 	mvpp2_prs_shadow_set(priv, pe.index, MVPP2_PRS_LU_PPPOE);
1701db9d7d36SMaxime Chevallier 	mvpp2_prs_hw_write(priv, &pe);
1702db9d7d36SMaxime Chevallier 
1703db9d7d36SMaxime Chevallier 	return 0;
1704db9d7d36SMaxime Chevallier }
1705db9d7d36SMaxime Chevallier 
1706db9d7d36SMaxime Chevallier /* Initialize entries for IPv4 */
mvpp2_prs_ip4_init(struct mvpp2 * priv)1707db9d7d36SMaxime Chevallier static int mvpp2_prs_ip4_init(struct mvpp2 *priv)
1708db9d7d36SMaxime Chevallier {
1709db9d7d36SMaxime Chevallier 	struct mvpp2_prs_entry pe;
1710db9d7d36SMaxime Chevallier 	int err;
1711db9d7d36SMaxime Chevallier 
1712db9d7d36SMaxime Chevallier 	/* Set entries for TCP, UDP and IGMP over IPv4 */
1713db9d7d36SMaxime Chevallier 	err = mvpp2_prs_ip4_proto(priv, IPPROTO_TCP, MVPP2_PRS_RI_L4_TCP,
1714db9d7d36SMaxime Chevallier 				  MVPP2_PRS_RI_L4_PROTO_MASK);
1715db9d7d36SMaxime Chevallier 	if (err)
1716db9d7d36SMaxime Chevallier 		return err;
1717db9d7d36SMaxime Chevallier 
1718db9d7d36SMaxime Chevallier 	err = mvpp2_prs_ip4_proto(priv, IPPROTO_UDP, MVPP2_PRS_RI_L4_UDP,
1719db9d7d36SMaxime Chevallier 				  MVPP2_PRS_RI_L4_PROTO_MASK);
1720db9d7d36SMaxime Chevallier 	if (err)
1721db9d7d36SMaxime Chevallier 		return err;
1722db9d7d36SMaxime Chevallier 
1723db9d7d36SMaxime Chevallier 	err = mvpp2_prs_ip4_proto(priv, IPPROTO_IGMP,
1724db9d7d36SMaxime Chevallier 				  MVPP2_PRS_RI_CPU_CODE_RX_SPEC |
1725db9d7d36SMaxime Chevallier 				  MVPP2_PRS_RI_UDF3_RX_SPECIAL,
1726db9d7d36SMaxime Chevallier 				  MVPP2_PRS_RI_CPU_CODE_MASK |
1727db9d7d36SMaxime Chevallier 				  MVPP2_PRS_RI_UDF3_MASK);
1728db9d7d36SMaxime Chevallier 	if (err)
1729db9d7d36SMaxime Chevallier 		return err;
1730db9d7d36SMaxime Chevallier 
1731db9d7d36SMaxime Chevallier 	/* IPv4 Broadcast */
1732db9d7d36SMaxime Chevallier 	err = mvpp2_prs_ip4_cast(priv, MVPP2_PRS_L3_BROAD_CAST);
1733db9d7d36SMaxime Chevallier 	if (err)
1734db9d7d36SMaxime Chevallier 		return err;
1735db9d7d36SMaxime Chevallier 
1736db9d7d36SMaxime Chevallier 	/* IPv4 Multicast */
1737db9d7d36SMaxime Chevallier 	err = mvpp2_prs_ip4_cast(priv, MVPP2_PRS_L3_MULTI_CAST);
1738db9d7d36SMaxime Chevallier 	if (err)
1739db9d7d36SMaxime Chevallier 		return err;
1740db9d7d36SMaxime Chevallier 
1741db9d7d36SMaxime Chevallier 	/* Default IPv4 entry for unknown protocols */
1742db9d7d36SMaxime Chevallier 	memset(&pe, 0, sizeof(pe));
1743db9d7d36SMaxime Chevallier 	mvpp2_prs_tcam_lu_set(&pe, MVPP2_PRS_LU_IP4);
1744db9d7d36SMaxime Chevallier 	pe.index = MVPP2_PE_IP4_PROTO_UN;
1745db9d7d36SMaxime Chevallier 
1746c73a4596SStefan Chulski 	/* Finished: go to flowid generation */
1747c73a4596SStefan Chulski 	mvpp2_prs_sram_next_lu_set(&pe, MVPP2_PRS_LU_FLOWS);
1748c73a4596SStefan Chulski 	mvpp2_prs_sram_bits_set(&pe, MVPP2_PRS_SRAM_LU_GEN_BIT, 1);
1749c73a4596SStefan Chulski 
17504ad29b1aSStefan Chulski 	/* Set L3 offset */
17514ad29b1aSStefan Chulski 	mvpp2_prs_sram_offset_set(&pe, MVPP2_PRS_SRAM_UDF_TYPE_L3, -4,
1752db9d7d36SMaxime Chevallier 				  MVPP2_PRS_SRAM_OP_SEL_UDF_ADD);
1753c73a4596SStefan Chulski 	mvpp2_prs_sram_ai_update(&pe, 0, MVPP2_PRS_IPV4_DIP_AI_BIT);
1754db9d7d36SMaxime Chevallier 	mvpp2_prs_sram_ri_update(&pe, MVPP2_PRS_RI_L4_OTHER,
1755db9d7d36SMaxime Chevallier 				 MVPP2_PRS_RI_L4_PROTO_MASK);
1756db9d7d36SMaxime Chevallier 
1757c73a4596SStefan Chulski 	mvpp2_prs_tcam_ai_update(&pe, MVPP2_PRS_IPV4_DIP_AI_BIT,
1758c73a4596SStefan Chulski 				 MVPP2_PRS_IPV4_DIP_AI_BIT);
1759db9d7d36SMaxime Chevallier 	/* Unmask all ports */
1760db9d7d36SMaxime Chevallier 	mvpp2_prs_tcam_port_map_set(&pe, MVPP2_PRS_PORT_MASK);
1761db9d7d36SMaxime Chevallier 
1762db9d7d36SMaxime Chevallier 	/* Update shadow table and hw entry */
1763db9d7d36SMaxime Chevallier 	mvpp2_prs_shadow_set(priv, pe.index, MVPP2_PRS_LU_IP4);
1764db9d7d36SMaxime Chevallier 	mvpp2_prs_hw_write(priv, &pe);
1765db9d7d36SMaxime Chevallier 
1766db9d7d36SMaxime Chevallier 	/* Default IPv4 entry for unicast address */
1767db9d7d36SMaxime Chevallier 	memset(&pe, 0, sizeof(pe));
1768db9d7d36SMaxime Chevallier 	mvpp2_prs_tcam_lu_set(&pe, MVPP2_PRS_LU_IP4);
1769db9d7d36SMaxime Chevallier 	pe.index = MVPP2_PE_IP4_ADDR_UN;
1770db9d7d36SMaxime Chevallier 
1771c73a4596SStefan Chulski 	/* Go again to ipv4 */
1772c73a4596SStefan Chulski 	mvpp2_prs_sram_next_lu_set(&pe, MVPP2_PRS_LU_IP4);
1773c73a4596SStefan Chulski 
1774c73a4596SStefan Chulski 	mvpp2_prs_sram_ai_update(&pe, MVPP2_PRS_IPV4_DIP_AI_BIT,
1775c73a4596SStefan Chulski 				 MVPP2_PRS_IPV4_DIP_AI_BIT);
1776c73a4596SStefan Chulski 
1777c73a4596SStefan Chulski 	/* Shift back to IPv4 proto */
1778c73a4596SStefan Chulski 	mvpp2_prs_sram_shift_set(&pe, -12, MVPP2_PRS_SRAM_OP_SEL_SHIFT_ADD);
1779c73a4596SStefan Chulski 
1780db9d7d36SMaxime Chevallier 	mvpp2_prs_sram_ri_update(&pe, MVPP2_PRS_RI_L3_UCAST,
1781db9d7d36SMaxime Chevallier 				 MVPP2_PRS_RI_L3_ADDR_MASK);
1782c73a4596SStefan Chulski 	mvpp2_prs_tcam_ai_update(&pe, 0, MVPP2_PRS_IPV4_DIP_AI_BIT);
1783db9d7d36SMaxime Chevallier 
1784db9d7d36SMaxime Chevallier 	/* Unmask all ports */
1785db9d7d36SMaxime Chevallier 	mvpp2_prs_tcam_port_map_set(&pe, MVPP2_PRS_PORT_MASK);
1786db9d7d36SMaxime Chevallier 
1787db9d7d36SMaxime Chevallier 	/* Update shadow table and hw entry */
1788db9d7d36SMaxime Chevallier 	mvpp2_prs_shadow_set(priv, pe.index, MVPP2_PRS_LU_IP4);
1789db9d7d36SMaxime Chevallier 	mvpp2_prs_hw_write(priv, &pe);
1790db9d7d36SMaxime Chevallier 
1791db9d7d36SMaxime Chevallier 	return 0;
1792db9d7d36SMaxime Chevallier }
1793db9d7d36SMaxime Chevallier 
1794db9d7d36SMaxime Chevallier /* Initialize entries for IPv6 */
mvpp2_prs_ip6_init(struct mvpp2 * priv)1795db9d7d36SMaxime Chevallier static int mvpp2_prs_ip6_init(struct mvpp2 *priv)
1796db9d7d36SMaxime Chevallier {
1797db9d7d36SMaxime Chevallier 	struct mvpp2_prs_entry pe;
1798db9d7d36SMaxime Chevallier 	int tid, err;
1799db9d7d36SMaxime Chevallier 
1800db9d7d36SMaxime Chevallier 	/* Set entries for TCP, UDP and ICMP over IPv6 */
1801db9d7d36SMaxime Chevallier 	err = mvpp2_prs_ip6_proto(priv, IPPROTO_TCP,
1802db9d7d36SMaxime Chevallier 				  MVPP2_PRS_RI_L4_TCP,
1803db9d7d36SMaxime Chevallier 				  MVPP2_PRS_RI_L4_PROTO_MASK);
1804db9d7d36SMaxime Chevallier 	if (err)
1805db9d7d36SMaxime Chevallier 		return err;
1806db9d7d36SMaxime Chevallier 
1807db9d7d36SMaxime Chevallier 	err = mvpp2_prs_ip6_proto(priv, IPPROTO_UDP,
1808db9d7d36SMaxime Chevallier 				  MVPP2_PRS_RI_L4_UDP,
1809db9d7d36SMaxime Chevallier 				  MVPP2_PRS_RI_L4_PROTO_MASK);
1810db9d7d36SMaxime Chevallier 	if (err)
1811db9d7d36SMaxime Chevallier 		return err;
1812db9d7d36SMaxime Chevallier 
1813db9d7d36SMaxime Chevallier 	err = mvpp2_prs_ip6_proto(priv, IPPROTO_ICMPV6,
1814db9d7d36SMaxime Chevallier 				  MVPP2_PRS_RI_CPU_CODE_RX_SPEC |
1815db9d7d36SMaxime Chevallier 				  MVPP2_PRS_RI_UDF3_RX_SPECIAL,
1816db9d7d36SMaxime Chevallier 				  MVPP2_PRS_RI_CPU_CODE_MASK |
1817db9d7d36SMaxime Chevallier 				  MVPP2_PRS_RI_UDF3_MASK);
1818db9d7d36SMaxime Chevallier 	if (err)
1819db9d7d36SMaxime Chevallier 		return err;
1820db9d7d36SMaxime Chevallier 
1821db9d7d36SMaxime Chevallier 	/* IPv4 is the last header. This is similar case as 6-TCP or 17-UDP */
1822db9d7d36SMaxime Chevallier 	/* Result Info: UDF7=1, DS lite */
1823db9d7d36SMaxime Chevallier 	err = mvpp2_prs_ip6_proto(priv, IPPROTO_IPIP,
1824db9d7d36SMaxime Chevallier 				  MVPP2_PRS_RI_UDF7_IP6_LITE,
1825db9d7d36SMaxime Chevallier 				  MVPP2_PRS_RI_UDF7_MASK);
1826db9d7d36SMaxime Chevallier 	if (err)
1827db9d7d36SMaxime Chevallier 		return err;
1828db9d7d36SMaxime Chevallier 
1829db9d7d36SMaxime Chevallier 	/* IPv6 multicast */
1830db9d7d36SMaxime Chevallier 	err = mvpp2_prs_ip6_cast(priv, MVPP2_PRS_L3_MULTI_CAST);
1831db9d7d36SMaxime Chevallier 	if (err)
1832db9d7d36SMaxime Chevallier 		return err;
1833db9d7d36SMaxime Chevallier 
1834db9d7d36SMaxime Chevallier 	/* Entry for checking hop limit */
1835db9d7d36SMaxime Chevallier 	tid = mvpp2_prs_tcam_first_free(priv, MVPP2_PE_FIRST_FREE_TID,
1836db9d7d36SMaxime Chevallier 					MVPP2_PE_LAST_FREE_TID);
1837db9d7d36SMaxime Chevallier 	if (tid < 0)
1838db9d7d36SMaxime Chevallier 		return tid;
1839db9d7d36SMaxime Chevallier 
1840db9d7d36SMaxime Chevallier 	memset(&pe, 0, sizeof(pe));
1841db9d7d36SMaxime Chevallier 	mvpp2_prs_tcam_lu_set(&pe, MVPP2_PRS_LU_IP6);
1842db9d7d36SMaxime Chevallier 	pe.index = tid;
1843db9d7d36SMaxime Chevallier 
1844db9d7d36SMaxime Chevallier 	/* Finished: go to flowid generation */
1845db9d7d36SMaxime Chevallier 	mvpp2_prs_sram_next_lu_set(&pe, MVPP2_PRS_LU_FLOWS);
1846db9d7d36SMaxime Chevallier 	mvpp2_prs_sram_bits_set(&pe, MVPP2_PRS_SRAM_LU_GEN_BIT, 1);
1847db9d7d36SMaxime Chevallier 	mvpp2_prs_sram_ri_update(&pe, MVPP2_PRS_RI_L3_UN |
1848db9d7d36SMaxime Chevallier 				 MVPP2_PRS_RI_DROP_MASK,
1849db9d7d36SMaxime Chevallier 				 MVPP2_PRS_RI_L3_PROTO_MASK |
1850db9d7d36SMaxime Chevallier 				 MVPP2_PRS_RI_DROP_MASK);
1851db9d7d36SMaxime Chevallier 
1852db9d7d36SMaxime Chevallier 	mvpp2_prs_tcam_data_byte_set(&pe, 1, 0x00, MVPP2_PRS_IPV6_HOP_MASK);
1853db9d7d36SMaxime Chevallier 	mvpp2_prs_tcam_ai_update(&pe, MVPP2_PRS_IPV6_NO_EXT_AI_BIT,
1854db9d7d36SMaxime Chevallier 				 MVPP2_PRS_IPV6_NO_EXT_AI_BIT);
1855db9d7d36SMaxime Chevallier 
1856db9d7d36SMaxime Chevallier 	/* Update shadow table and hw entry */
1857db9d7d36SMaxime Chevallier 	mvpp2_prs_shadow_set(priv, pe.index, MVPP2_PRS_LU_IP4);
1858db9d7d36SMaxime Chevallier 	mvpp2_prs_hw_write(priv, &pe);
1859db9d7d36SMaxime Chevallier 
1860db9d7d36SMaxime Chevallier 	/* Default IPv6 entry for unknown protocols */
1861db9d7d36SMaxime Chevallier 	memset(&pe, 0, sizeof(pe));
1862db9d7d36SMaxime Chevallier 	mvpp2_prs_tcam_lu_set(&pe, MVPP2_PRS_LU_IP6);
1863db9d7d36SMaxime Chevallier 	pe.index = MVPP2_PE_IP6_PROTO_UN;
1864db9d7d36SMaxime Chevallier 
1865db9d7d36SMaxime Chevallier 	/* Finished: go to flowid generation */
1866db9d7d36SMaxime Chevallier 	mvpp2_prs_sram_next_lu_set(&pe, MVPP2_PRS_LU_FLOWS);
1867db9d7d36SMaxime Chevallier 	mvpp2_prs_sram_bits_set(&pe, MVPP2_PRS_SRAM_LU_GEN_BIT, 1);
1868db9d7d36SMaxime Chevallier 	mvpp2_prs_sram_ri_update(&pe, MVPP2_PRS_RI_L4_OTHER,
1869db9d7d36SMaxime Chevallier 				 MVPP2_PRS_RI_L4_PROTO_MASK);
1870db9d7d36SMaxime Chevallier 	/* Set L4 offset relatively to our current place */
1871db9d7d36SMaxime Chevallier 	mvpp2_prs_sram_offset_set(&pe, MVPP2_PRS_SRAM_UDF_TYPE_L4,
1872db9d7d36SMaxime Chevallier 				  sizeof(struct ipv6hdr) - 4,
1873db9d7d36SMaxime Chevallier 				  MVPP2_PRS_SRAM_OP_SEL_UDF_ADD);
1874db9d7d36SMaxime Chevallier 
1875db9d7d36SMaxime Chevallier 	mvpp2_prs_tcam_ai_update(&pe, MVPP2_PRS_IPV6_NO_EXT_AI_BIT,
1876db9d7d36SMaxime Chevallier 				 MVPP2_PRS_IPV6_NO_EXT_AI_BIT);
1877db9d7d36SMaxime Chevallier 	/* Unmask all ports */
1878db9d7d36SMaxime Chevallier 	mvpp2_prs_tcam_port_map_set(&pe, MVPP2_PRS_PORT_MASK);
1879db9d7d36SMaxime Chevallier 
1880db9d7d36SMaxime Chevallier 	/* Update shadow table and hw entry */
1881db9d7d36SMaxime Chevallier 	mvpp2_prs_shadow_set(priv, pe.index, MVPP2_PRS_LU_IP4);
1882db9d7d36SMaxime Chevallier 	mvpp2_prs_hw_write(priv, &pe);
1883db9d7d36SMaxime Chevallier 
1884db9d7d36SMaxime Chevallier 	/* Default IPv6 entry for unknown ext protocols */
1885db9d7d36SMaxime Chevallier 	memset(&pe, 0, sizeof(struct mvpp2_prs_entry));
1886db9d7d36SMaxime Chevallier 	mvpp2_prs_tcam_lu_set(&pe, MVPP2_PRS_LU_IP6);
1887db9d7d36SMaxime Chevallier 	pe.index = MVPP2_PE_IP6_EXT_PROTO_UN;
1888db9d7d36SMaxime Chevallier 
1889db9d7d36SMaxime Chevallier 	/* Finished: go to flowid generation */
1890db9d7d36SMaxime Chevallier 	mvpp2_prs_sram_next_lu_set(&pe, MVPP2_PRS_LU_FLOWS);
1891db9d7d36SMaxime Chevallier 	mvpp2_prs_sram_bits_set(&pe, MVPP2_PRS_SRAM_LU_GEN_BIT, 1);
1892db9d7d36SMaxime Chevallier 	mvpp2_prs_sram_ri_update(&pe, MVPP2_PRS_RI_L4_OTHER,
1893db9d7d36SMaxime Chevallier 				 MVPP2_PRS_RI_L4_PROTO_MASK);
1894db9d7d36SMaxime Chevallier 
1895db9d7d36SMaxime Chevallier 	mvpp2_prs_tcam_ai_update(&pe, MVPP2_PRS_IPV6_EXT_AI_BIT,
1896db9d7d36SMaxime Chevallier 				 MVPP2_PRS_IPV6_EXT_AI_BIT);
1897db9d7d36SMaxime Chevallier 	/* Unmask all ports */
1898db9d7d36SMaxime Chevallier 	mvpp2_prs_tcam_port_map_set(&pe, MVPP2_PRS_PORT_MASK);
1899db9d7d36SMaxime Chevallier 
1900db9d7d36SMaxime Chevallier 	/* Update shadow table and hw entry */
1901db9d7d36SMaxime Chevallier 	mvpp2_prs_shadow_set(priv, pe.index, MVPP2_PRS_LU_IP4);
1902db9d7d36SMaxime Chevallier 	mvpp2_prs_hw_write(priv, &pe);
1903db9d7d36SMaxime Chevallier 
1904db9d7d36SMaxime Chevallier 	/* Default IPv6 entry for unicast address */
1905db9d7d36SMaxime Chevallier 	memset(&pe, 0, sizeof(struct mvpp2_prs_entry));
1906db9d7d36SMaxime Chevallier 	mvpp2_prs_tcam_lu_set(&pe, MVPP2_PRS_LU_IP6);
1907db9d7d36SMaxime Chevallier 	pe.index = MVPP2_PE_IP6_ADDR_UN;
1908db9d7d36SMaxime Chevallier 
1909db9d7d36SMaxime Chevallier 	/* Finished: go to IPv6 again */
1910db9d7d36SMaxime Chevallier 	mvpp2_prs_sram_next_lu_set(&pe, MVPP2_PRS_LU_IP6);
1911db9d7d36SMaxime Chevallier 	mvpp2_prs_sram_ri_update(&pe, MVPP2_PRS_RI_L3_UCAST,
1912db9d7d36SMaxime Chevallier 				 MVPP2_PRS_RI_L3_ADDR_MASK);
1913db9d7d36SMaxime Chevallier 	mvpp2_prs_sram_ai_update(&pe, MVPP2_PRS_IPV6_NO_EXT_AI_BIT,
1914db9d7d36SMaxime Chevallier 				 MVPP2_PRS_IPV6_NO_EXT_AI_BIT);
1915db9d7d36SMaxime Chevallier 	/* Shift back to IPV6 NH */
1916db9d7d36SMaxime Chevallier 	mvpp2_prs_sram_shift_set(&pe, -18, MVPP2_PRS_SRAM_OP_SEL_SHIFT_ADD);
1917db9d7d36SMaxime Chevallier 
1918db9d7d36SMaxime Chevallier 	mvpp2_prs_tcam_ai_update(&pe, 0, MVPP2_PRS_IPV6_NO_EXT_AI_BIT);
1919db9d7d36SMaxime Chevallier 	/* Unmask all ports */
1920db9d7d36SMaxime Chevallier 	mvpp2_prs_tcam_port_map_set(&pe, MVPP2_PRS_PORT_MASK);
1921db9d7d36SMaxime Chevallier 
1922db9d7d36SMaxime Chevallier 	/* Update shadow table and hw entry */
1923db9d7d36SMaxime Chevallier 	mvpp2_prs_shadow_set(priv, pe.index, MVPP2_PRS_LU_IP6);
1924db9d7d36SMaxime Chevallier 	mvpp2_prs_hw_write(priv, &pe);
1925db9d7d36SMaxime Chevallier 
1926db9d7d36SMaxime Chevallier 	return 0;
1927db9d7d36SMaxime Chevallier }
1928db9d7d36SMaxime Chevallier 
1929db9d7d36SMaxime Chevallier /* Find tcam entry with matched pair <vid,port> */
mvpp2_prs_vid_range_find(struct mvpp2_port * port,u16 vid,u16 mask)193046b0090aSMaxime Chevallier static int mvpp2_prs_vid_range_find(struct mvpp2_port *port, u16 vid, u16 mask)
1931db9d7d36SMaxime Chevallier {
1932db9d7d36SMaxime Chevallier 	unsigned char byte[2], enable[2];
1933db9d7d36SMaxime Chevallier 	struct mvpp2_prs_entry pe;
1934db9d7d36SMaxime Chevallier 	u16 rvid, rmask;
1935db9d7d36SMaxime Chevallier 	int tid;
1936db9d7d36SMaxime Chevallier 
1937db9d7d36SMaxime Chevallier 	/* Go through the all entries with MVPP2_PRS_LU_VID */
193846b0090aSMaxime Chevallier 	for (tid = MVPP2_PRS_VID_PORT_FIRST(port->id);
193946b0090aSMaxime Chevallier 	     tid <= MVPP2_PRS_VID_PORT_LAST(port->id); tid++) {
194046b0090aSMaxime Chevallier 		if (!port->priv->prs_shadow[tid].valid ||
194146b0090aSMaxime Chevallier 		    port->priv->prs_shadow[tid].lu != MVPP2_PRS_LU_VID)
1942db9d7d36SMaxime Chevallier 			continue;
1943db9d7d36SMaxime Chevallier 
194446b0090aSMaxime Chevallier 		mvpp2_prs_init_from_hw(port->priv, &pe, tid);
1945db9d7d36SMaxime Chevallier 
1946db9d7d36SMaxime Chevallier 		mvpp2_prs_tcam_data_byte_get(&pe, 2, &byte[0], &enable[0]);
1947db9d7d36SMaxime Chevallier 		mvpp2_prs_tcam_data_byte_get(&pe, 3, &byte[1], &enable[1]);
1948db9d7d36SMaxime Chevallier 
1949db9d7d36SMaxime Chevallier 		rvid = ((byte[0] & 0xf) << 8) + byte[1];
1950db9d7d36SMaxime Chevallier 		rmask = ((enable[0] & 0xf) << 8) + enable[1];
1951db9d7d36SMaxime Chevallier 
1952db9d7d36SMaxime Chevallier 		if (rvid != vid || rmask != mask)
1953db9d7d36SMaxime Chevallier 			continue;
1954db9d7d36SMaxime Chevallier 
1955db9d7d36SMaxime Chevallier 		return tid;
1956db9d7d36SMaxime Chevallier 	}
1957db9d7d36SMaxime Chevallier 
1958db9d7d36SMaxime Chevallier 	return -ENOENT;
1959db9d7d36SMaxime Chevallier }
1960db9d7d36SMaxime Chevallier 
1961db9d7d36SMaxime Chevallier /* Write parser entry for VID filtering */
mvpp2_prs_vid_entry_add(struct mvpp2_port * port,u16 vid)1962db9d7d36SMaxime Chevallier int mvpp2_prs_vid_entry_add(struct mvpp2_port *port, u16 vid)
1963db9d7d36SMaxime Chevallier {
1964db9d7d36SMaxime Chevallier 	unsigned int vid_start = MVPP2_PE_VID_FILT_RANGE_START +
1965db9d7d36SMaxime Chevallier 				 port->id * MVPP2_PRS_VLAN_FILT_MAX;
1966db9d7d36SMaxime Chevallier 	unsigned int mask = 0xfff, reg_val, shift;
1967db9d7d36SMaxime Chevallier 	struct mvpp2 *priv = port->priv;
1968db9d7d36SMaxime Chevallier 	struct mvpp2_prs_entry pe;
1969db9d7d36SMaxime Chevallier 	int tid;
1970db9d7d36SMaxime Chevallier 
1971db9d7d36SMaxime Chevallier 	memset(&pe, 0, sizeof(pe));
1972db9d7d36SMaxime Chevallier 
1973db9d7d36SMaxime Chevallier 	/* Scan TCAM and see if entry with this <vid,port> already exist */
197446b0090aSMaxime Chevallier 	tid = mvpp2_prs_vid_range_find(port, vid, mask);
1975db9d7d36SMaxime Chevallier 
1976db9d7d36SMaxime Chevallier 	reg_val = mvpp2_read(priv, MVPP2_MH_REG(port->id));
1977db9d7d36SMaxime Chevallier 	if (reg_val & MVPP2_DSA_EXTENDED)
1978db9d7d36SMaxime Chevallier 		shift = MVPP2_VLAN_TAG_EDSA_LEN;
1979db9d7d36SMaxime Chevallier 	else
1980db9d7d36SMaxime Chevallier 		shift = MVPP2_VLAN_TAG_LEN;
1981db9d7d36SMaxime Chevallier 
1982db9d7d36SMaxime Chevallier 	/* No such entry */
1983db9d7d36SMaxime Chevallier 	if (tid < 0) {
1984db9d7d36SMaxime Chevallier 
1985db9d7d36SMaxime Chevallier 		/* Go through all entries from first to last in vlan range */
1986db9d7d36SMaxime Chevallier 		tid = mvpp2_prs_tcam_first_free(priv, vid_start,
1987db9d7d36SMaxime Chevallier 						vid_start +
1988db9d7d36SMaxime Chevallier 						MVPP2_PRS_VLAN_FILT_MAX_ENTRY);
1989db9d7d36SMaxime Chevallier 
1990db9d7d36SMaxime Chevallier 		/* There isn't room for a new VID filter */
1991db9d7d36SMaxime Chevallier 		if (tid < 0)
1992db9d7d36SMaxime Chevallier 			return tid;
1993db9d7d36SMaxime Chevallier 
1994db9d7d36SMaxime Chevallier 		mvpp2_prs_tcam_lu_set(&pe, MVPP2_PRS_LU_VID);
1995db9d7d36SMaxime Chevallier 		pe.index = tid;
1996db9d7d36SMaxime Chevallier 
1997db9d7d36SMaxime Chevallier 		/* Mask all ports */
1998db9d7d36SMaxime Chevallier 		mvpp2_prs_tcam_port_map_set(&pe, 0);
1999db9d7d36SMaxime Chevallier 	} else {
2000db9d7d36SMaxime Chevallier 		mvpp2_prs_init_from_hw(priv, &pe, tid);
2001db9d7d36SMaxime Chevallier 	}
2002db9d7d36SMaxime Chevallier 
2003db9d7d36SMaxime Chevallier 	/* Enable the current port */
2004db9d7d36SMaxime Chevallier 	mvpp2_prs_tcam_port_set(&pe, port->id, true);
2005db9d7d36SMaxime Chevallier 
2006db9d7d36SMaxime Chevallier 	/* Continue - set next lookup */
2007db9d7d36SMaxime Chevallier 	mvpp2_prs_sram_next_lu_set(&pe, MVPP2_PRS_LU_L2);
2008db9d7d36SMaxime Chevallier 
2009db9d7d36SMaxime Chevallier 	/* Skip VLAN header - Set offset to 4 or 8 bytes */
2010db9d7d36SMaxime Chevallier 	mvpp2_prs_sram_shift_set(&pe, shift, MVPP2_PRS_SRAM_OP_SEL_SHIFT_ADD);
2011db9d7d36SMaxime Chevallier 
2012db9d7d36SMaxime Chevallier 	/* Set match on VID */
2013db9d7d36SMaxime Chevallier 	mvpp2_prs_match_vid(&pe, MVPP2_PRS_VID_TCAM_BYTE, vid);
2014db9d7d36SMaxime Chevallier 
2015db9d7d36SMaxime Chevallier 	/* Clear all ai bits for next iteration */
2016db9d7d36SMaxime Chevallier 	mvpp2_prs_sram_ai_update(&pe, 0, MVPP2_PRS_SRAM_AI_MASK);
2017db9d7d36SMaxime Chevallier 
2018db9d7d36SMaxime Chevallier 	/* Update shadow table */
2019db9d7d36SMaxime Chevallier 	mvpp2_prs_shadow_set(priv, pe.index, MVPP2_PRS_LU_VID);
2020db9d7d36SMaxime Chevallier 	mvpp2_prs_hw_write(priv, &pe);
2021db9d7d36SMaxime Chevallier 
2022db9d7d36SMaxime Chevallier 	return 0;
2023db9d7d36SMaxime Chevallier }
2024db9d7d36SMaxime Chevallier 
2025db9d7d36SMaxime Chevallier /* Write parser entry for VID filtering */
mvpp2_prs_vid_entry_remove(struct mvpp2_port * port,u16 vid)2026db9d7d36SMaxime Chevallier void mvpp2_prs_vid_entry_remove(struct mvpp2_port *port, u16 vid)
2027db9d7d36SMaxime Chevallier {
2028db9d7d36SMaxime Chevallier 	struct mvpp2 *priv = port->priv;
2029db9d7d36SMaxime Chevallier 	int tid;
2030db9d7d36SMaxime Chevallier 
2031db9d7d36SMaxime Chevallier 	/* Scan TCAM and see if entry with this <vid,port> already exist */
203246b0090aSMaxime Chevallier 	tid = mvpp2_prs_vid_range_find(port, vid, 0xfff);
2033db9d7d36SMaxime Chevallier 
2034db9d7d36SMaxime Chevallier 	/* No such entry */
2035db9d7d36SMaxime Chevallier 	if (tid < 0)
2036db9d7d36SMaxime Chevallier 		return;
2037db9d7d36SMaxime Chevallier 
2038db9d7d36SMaxime Chevallier 	mvpp2_prs_hw_inv(priv, tid);
2039db9d7d36SMaxime Chevallier 	priv->prs_shadow[tid].valid = false;
2040db9d7d36SMaxime Chevallier }
2041db9d7d36SMaxime Chevallier 
2042db9d7d36SMaxime Chevallier /* Remove all existing VID filters on this port */
mvpp2_prs_vid_remove_all(struct mvpp2_port * port)2043db9d7d36SMaxime Chevallier void mvpp2_prs_vid_remove_all(struct mvpp2_port *port)
2044db9d7d36SMaxime Chevallier {
2045db9d7d36SMaxime Chevallier 	struct mvpp2 *priv = port->priv;
2046db9d7d36SMaxime Chevallier 	int tid;
2047db9d7d36SMaxime Chevallier 
2048db9d7d36SMaxime Chevallier 	for (tid = MVPP2_PRS_VID_PORT_FIRST(port->id);
2049db9d7d36SMaxime Chevallier 	     tid <= MVPP2_PRS_VID_PORT_LAST(port->id); tid++) {
20506b7a3430SMaxime Chevallier 		if (priv->prs_shadow[tid].valid) {
20516b7a3430SMaxime Chevallier 			mvpp2_prs_hw_inv(priv, tid);
20526b7a3430SMaxime Chevallier 			priv->prs_shadow[tid].valid = false;
20536b7a3430SMaxime Chevallier 		}
2054db9d7d36SMaxime Chevallier 	}
2055db9d7d36SMaxime Chevallier }
2056db9d7d36SMaxime Chevallier 
2057db9d7d36SMaxime Chevallier /* Remove VID filering entry for this port */
mvpp2_prs_vid_disable_filtering(struct mvpp2_port * port)2058db9d7d36SMaxime Chevallier void mvpp2_prs_vid_disable_filtering(struct mvpp2_port *port)
2059db9d7d36SMaxime Chevallier {
2060db9d7d36SMaxime Chevallier 	unsigned int tid = MVPP2_PRS_VID_PORT_DFLT(port->id);
2061db9d7d36SMaxime Chevallier 	struct mvpp2 *priv = port->priv;
2062db9d7d36SMaxime Chevallier 
2063db9d7d36SMaxime Chevallier 	/* Invalidate the guard entry */
2064db9d7d36SMaxime Chevallier 	mvpp2_prs_hw_inv(priv, tid);
2065db9d7d36SMaxime Chevallier 
2066db9d7d36SMaxime Chevallier 	priv->prs_shadow[tid].valid = false;
2067db9d7d36SMaxime Chevallier }
2068db9d7d36SMaxime Chevallier 
2069db9d7d36SMaxime Chevallier /* Add guard entry that drops packets when no VID is matched on this port */
mvpp2_prs_vid_enable_filtering(struct mvpp2_port * port)2070db9d7d36SMaxime Chevallier void mvpp2_prs_vid_enable_filtering(struct mvpp2_port *port)
2071db9d7d36SMaxime Chevallier {
2072db9d7d36SMaxime Chevallier 	unsigned int tid = MVPP2_PRS_VID_PORT_DFLT(port->id);
2073db9d7d36SMaxime Chevallier 	struct mvpp2 *priv = port->priv;
2074db9d7d36SMaxime Chevallier 	unsigned int reg_val, shift;
2075db9d7d36SMaxime Chevallier 	struct mvpp2_prs_entry pe;
2076db9d7d36SMaxime Chevallier 
2077db9d7d36SMaxime Chevallier 	if (priv->prs_shadow[tid].valid)
2078db9d7d36SMaxime Chevallier 		return;
2079db9d7d36SMaxime Chevallier 
2080db9d7d36SMaxime Chevallier 	memset(&pe, 0, sizeof(pe));
2081db9d7d36SMaxime Chevallier 
2082db9d7d36SMaxime Chevallier 	pe.index = tid;
2083db9d7d36SMaxime Chevallier 
2084db9d7d36SMaxime Chevallier 	reg_val = mvpp2_read(priv, MVPP2_MH_REG(port->id));
2085db9d7d36SMaxime Chevallier 	if (reg_val & MVPP2_DSA_EXTENDED)
2086db9d7d36SMaxime Chevallier 		shift = MVPP2_VLAN_TAG_EDSA_LEN;
2087db9d7d36SMaxime Chevallier 	else
2088db9d7d36SMaxime Chevallier 		shift = MVPP2_VLAN_TAG_LEN;
2089db9d7d36SMaxime Chevallier 
2090db9d7d36SMaxime Chevallier 	mvpp2_prs_tcam_lu_set(&pe, MVPP2_PRS_LU_VID);
2091db9d7d36SMaxime Chevallier 
2092db9d7d36SMaxime Chevallier 	/* Mask all ports */
2093db9d7d36SMaxime Chevallier 	mvpp2_prs_tcam_port_map_set(&pe, 0);
2094db9d7d36SMaxime Chevallier 
2095db9d7d36SMaxime Chevallier 	/* Update port mask */
2096db9d7d36SMaxime Chevallier 	mvpp2_prs_tcam_port_set(&pe, port->id, true);
2097db9d7d36SMaxime Chevallier 
2098db9d7d36SMaxime Chevallier 	/* Continue - set next lookup */
2099db9d7d36SMaxime Chevallier 	mvpp2_prs_sram_next_lu_set(&pe, MVPP2_PRS_LU_L2);
2100db9d7d36SMaxime Chevallier 
2101db9d7d36SMaxime Chevallier 	/* Skip VLAN header - Set offset to 4 or 8 bytes */
2102db9d7d36SMaxime Chevallier 	mvpp2_prs_sram_shift_set(&pe, shift, MVPP2_PRS_SRAM_OP_SEL_SHIFT_ADD);
2103db9d7d36SMaxime Chevallier 
2104db9d7d36SMaxime Chevallier 	/* Drop VLAN packets that don't belong to any VIDs on this port */
2105db9d7d36SMaxime Chevallier 	mvpp2_prs_sram_ri_update(&pe, MVPP2_PRS_RI_DROP_MASK,
2106db9d7d36SMaxime Chevallier 				 MVPP2_PRS_RI_DROP_MASK);
2107db9d7d36SMaxime Chevallier 
2108db9d7d36SMaxime Chevallier 	/* Clear all ai bits for next iteration */
2109db9d7d36SMaxime Chevallier 	mvpp2_prs_sram_ai_update(&pe, 0, MVPP2_PRS_SRAM_AI_MASK);
2110db9d7d36SMaxime Chevallier 
2111db9d7d36SMaxime Chevallier 	/* Update shadow table */
2112db9d7d36SMaxime Chevallier 	mvpp2_prs_shadow_set(priv, pe.index, MVPP2_PRS_LU_VID);
2113db9d7d36SMaxime Chevallier 	mvpp2_prs_hw_write(priv, &pe);
2114db9d7d36SMaxime Chevallier }
2115db9d7d36SMaxime Chevallier 
2116db9d7d36SMaxime Chevallier /* Parser default initialization */
mvpp2_prs_default_init(struct platform_device * pdev,struct mvpp2 * priv)2117db9d7d36SMaxime Chevallier int mvpp2_prs_default_init(struct platform_device *pdev, struct mvpp2 *priv)
2118db9d7d36SMaxime Chevallier {
2119db9d7d36SMaxime Chevallier 	int err, index, i;
2120db9d7d36SMaxime Chevallier 
2121db9d7d36SMaxime Chevallier 	/* Enable tcam table */
2122db9d7d36SMaxime Chevallier 	mvpp2_write(priv, MVPP2_PRS_TCAM_CTRL_REG, MVPP2_PRS_TCAM_EN_MASK);
2123db9d7d36SMaxime Chevallier 
2124db9d7d36SMaxime Chevallier 	/* Clear all tcam and sram entries */
2125db9d7d36SMaxime Chevallier 	for (index = 0; index < MVPP2_PRS_TCAM_SRAM_SIZE; index++) {
2126db9d7d36SMaxime Chevallier 		mvpp2_write(priv, MVPP2_PRS_TCAM_IDX_REG, index);
2127db9d7d36SMaxime Chevallier 		for (i = 0; i < MVPP2_PRS_TCAM_WORDS; i++)
2128db9d7d36SMaxime Chevallier 			mvpp2_write(priv, MVPP2_PRS_TCAM_DATA_REG(i), 0);
2129db9d7d36SMaxime Chevallier 
2130db9d7d36SMaxime Chevallier 		mvpp2_write(priv, MVPP2_PRS_SRAM_IDX_REG, index);
2131db9d7d36SMaxime Chevallier 		for (i = 0; i < MVPP2_PRS_SRAM_WORDS; i++)
2132db9d7d36SMaxime Chevallier 			mvpp2_write(priv, MVPP2_PRS_SRAM_DATA_REG(i), 0);
2133db9d7d36SMaxime Chevallier 	}
2134db9d7d36SMaxime Chevallier 
2135db9d7d36SMaxime Chevallier 	/* Invalidate all tcam entries */
2136db9d7d36SMaxime Chevallier 	for (index = 0; index < MVPP2_PRS_TCAM_SRAM_SIZE; index++)
2137db9d7d36SMaxime Chevallier 		mvpp2_prs_hw_inv(priv, index);
2138db9d7d36SMaxime Chevallier 
2139db9d7d36SMaxime Chevallier 	priv->prs_shadow = devm_kcalloc(&pdev->dev, MVPP2_PRS_TCAM_SRAM_SIZE,
2140db9d7d36SMaxime Chevallier 					sizeof(*priv->prs_shadow),
2141db9d7d36SMaxime Chevallier 					GFP_KERNEL);
2142db9d7d36SMaxime Chevallier 	if (!priv->prs_shadow)
2143db9d7d36SMaxime Chevallier 		return -ENOMEM;
2144db9d7d36SMaxime Chevallier 
2145db9d7d36SMaxime Chevallier 	/* Always start from lookup = 0 */
2146db9d7d36SMaxime Chevallier 	for (index = 0; index < MVPP2_MAX_PORTS; index++)
2147db9d7d36SMaxime Chevallier 		mvpp2_prs_hw_port_init(priv, index, MVPP2_PRS_LU_MH,
2148db9d7d36SMaxime Chevallier 				       MVPP2_PRS_PORT_LU_MAX, 0);
2149db9d7d36SMaxime Chevallier 
2150db9d7d36SMaxime Chevallier 	mvpp2_prs_def_flow_init(priv);
2151db9d7d36SMaxime Chevallier 
2152db9d7d36SMaxime Chevallier 	mvpp2_prs_mh_init(priv);
2153db9d7d36SMaxime Chevallier 
2154db9d7d36SMaxime Chevallier 	mvpp2_prs_mac_init(priv);
2155db9d7d36SMaxime Chevallier 
2156db9d7d36SMaxime Chevallier 	mvpp2_prs_dsa_init(priv);
2157db9d7d36SMaxime Chevallier 
2158db9d7d36SMaxime Chevallier 	mvpp2_prs_vid_init(priv);
2159db9d7d36SMaxime Chevallier 
2160db9d7d36SMaxime Chevallier 	err = mvpp2_prs_etype_init(priv);
2161db9d7d36SMaxime Chevallier 	if (err)
2162db9d7d36SMaxime Chevallier 		return err;
2163db9d7d36SMaxime Chevallier 
2164db9d7d36SMaxime Chevallier 	err = mvpp2_prs_vlan_init(pdev, priv);
2165db9d7d36SMaxime Chevallier 	if (err)
2166db9d7d36SMaxime Chevallier 		return err;
2167db9d7d36SMaxime Chevallier 
2168db9d7d36SMaxime Chevallier 	err = mvpp2_prs_pppoe_init(priv);
2169db9d7d36SMaxime Chevallier 	if (err)
2170db9d7d36SMaxime Chevallier 		return err;
2171db9d7d36SMaxime Chevallier 
2172db9d7d36SMaxime Chevallier 	err = mvpp2_prs_ip6_init(priv);
2173db9d7d36SMaxime Chevallier 	if (err)
2174db9d7d36SMaxime Chevallier 		return err;
2175db9d7d36SMaxime Chevallier 
2176db9d7d36SMaxime Chevallier 	err = mvpp2_prs_ip4_init(priv);
2177db9d7d36SMaxime Chevallier 	if (err)
2178db9d7d36SMaxime Chevallier 		return err;
2179db9d7d36SMaxime Chevallier 
2180db9d7d36SMaxime Chevallier 	return 0;
2181db9d7d36SMaxime Chevallier }
2182db9d7d36SMaxime Chevallier 
2183db9d7d36SMaxime Chevallier /* Compare MAC DA with tcam entry data */
mvpp2_prs_mac_range_equals(struct mvpp2_prs_entry * pe,const u8 * da,unsigned char * mask)2184db9d7d36SMaxime Chevallier static bool mvpp2_prs_mac_range_equals(struct mvpp2_prs_entry *pe,
2185db9d7d36SMaxime Chevallier 				       const u8 *da, unsigned char *mask)
2186db9d7d36SMaxime Chevallier {
2187db9d7d36SMaxime Chevallier 	unsigned char tcam_byte, tcam_mask;
2188db9d7d36SMaxime Chevallier 	int index;
2189db9d7d36SMaxime Chevallier 
2190db9d7d36SMaxime Chevallier 	for (index = 0; index < ETH_ALEN; index++) {
2191db9d7d36SMaxime Chevallier 		mvpp2_prs_tcam_data_byte_get(pe, index, &tcam_byte, &tcam_mask);
2192db9d7d36SMaxime Chevallier 		if (tcam_mask != mask[index])
2193db9d7d36SMaxime Chevallier 			return false;
2194db9d7d36SMaxime Chevallier 
2195db9d7d36SMaxime Chevallier 		if ((tcam_mask & tcam_byte) != (da[index] & mask[index]))
2196db9d7d36SMaxime Chevallier 			return false;
2197db9d7d36SMaxime Chevallier 	}
2198db9d7d36SMaxime Chevallier 
2199db9d7d36SMaxime Chevallier 	return true;
2200db9d7d36SMaxime Chevallier }
2201db9d7d36SMaxime Chevallier 
2202db9d7d36SMaxime Chevallier /* Find tcam entry with matched pair <MAC DA, port> */
2203db9d7d36SMaxime Chevallier static int
mvpp2_prs_mac_da_range_find(struct mvpp2 * priv,int pmap,const u8 * da,unsigned char * mask,int udf_type)2204db9d7d36SMaxime Chevallier mvpp2_prs_mac_da_range_find(struct mvpp2 *priv, int pmap, const u8 *da,
2205db9d7d36SMaxime Chevallier 			    unsigned char *mask, int udf_type)
2206db9d7d36SMaxime Chevallier {
2207db9d7d36SMaxime Chevallier 	struct mvpp2_prs_entry pe;
2208db9d7d36SMaxime Chevallier 	int tid;
2209db9d7d36SMaxime Chevallier 
2210db9d7d36SMaxime Chevallier 	/* Go through the all entires with MVPP2_PRS_LU_MAC */
2211db9d7d36SMaxime Chevallier 	for (tid = MVPP2_PE_MAC_RANGE_START;
2212db9d7d36SMaxime Chevallier 	     tid <= MVPP2_PE_MAC_RANGE_END; tid++) {
2213db9d7d36SMaxime Chevallier 		unsigned int entry_pmap;
2214db9d7d36SMaxime Chevallier 
2215db9d7d36SMaxime Chevallier 		if (!priv->prs_shadow[tid].valid ||
2216db9d7d36SMaxime Chevallier 		    (priv->prs_shadow[tid].lu != MVPP2_PRS_LU_MAC) ||
2217db9d7d36SMaxime Chevallier 		    (priv->prs_shadow[tid].udf != udf_type))
2218db9d7d36SMaxime Chevallier 			continue;
2219db9d7d36SMaxime Chevallier 
2220db9d7d36SMaxime Chevallier 		mvpp2_prs_init_from_hw(priv, &pe, tid);
2221db9d7d36SMaxime Chevallier 		entry_pmap = mvpp2_prs_tcam_port_map_get(&pe);
2222db9d7d36SMaxime Chevallier 
2223db9d7d36SMaxime Chevallier 		if (mvpp2_prs_mac_range_equals(&pe, da, mask) &&
2224db9d7d36SMaxime Chevallier 		    entry_pmap == pmap)
2225db9d7d36SMaxime Chevallier 			return tid;
2226db9d7d36SMaxime Chevallier 	}
2227db9d7d36SMaxime Chevallier 
2228db9d7d36SMaxime Chevallier 	return -ENOENT;
2229db9d7d36SMaxime Chevallier }
2230db9d7d36SMaxime Chevallier 
2231db9d7d36SMaxime Chevallier /* Update parser's mac da entry */
mvpp2_prs_mac_da_accept(struct mvpp2_port * port,const u8 * da,bool add)2232db9d7d36SMaxime Chevallier int mvpp2_prs_mac_da_accept(struct mvpp2_port *port, const u8 *da, bool add)
2233db9d7d36SMaxime Chevallier {
2234db9d7d36SMaxime Chevallier 	unsigned char mask[ETH_ALEN] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
2235db9d7d36SMaxime Chevallier 	struct mvpp2 *priv = port->priv;
2236db9d7d36SMaxime Chevallier 	unsigned int pmap, len, ri;
2237db9d7d36SMaxime Chevallier 	struct mvpp2_prs_entry pe;
2238db9d7d36SMaxime Chevallier 	int tid;
2239db9d7d36SMaxime Chevallier 
2240db9d7d36SMaxime Chevallier 	memset(&pe, 0, sizeof(pe));
2241db9d7d36SMaxime Chevallier 
2242db9d7d36SMaxime Chevallier 	/* Scan TCAM and see if entry with this <MAC DA, port> already exist */
2243db9d7d36SMaxime Chevallier 	tid = mvpp2_prs_mac_da_range_find(priv, BIT(port->id), da, mask,
2244db9d7d36SMaxime Chevallier 					  MVPP2_PRS_UDF_MAC_DEF);
2245db9d7d36SMaxime Chevallier 
2246db9d7d36SMaxime Chevallier 	/* No such entry */
2247db9d7d36SMaxime Chevallier 	if (tid < 0) {
2248db9d7d36SMaxime Chevallier 		if (!add)
2249db9d7d36SMaxime Chevallier 			return 0;
2250db9d7d36SMaxime Chevallier 
2251db9d7d36SMaxime Chevallier 		/* Create new TCAM entry */
2252db9d7d36SMaxime Chevallier 		/* Go through the all entries from first to last */
2253db9d7d36SMaxime Chevallier 		tid = mvpp2_prs_tcam_first_free(priv,
2254db9d7d36SMaxime Chevallier 						MVPP2_PE_MAC_RANGE_START,
2255db9d7d36SMaxime Chevallier 						MVPP2_PE_MAC_RANGE_END);
2256db9d7d36SMaxime Chevallier 		if (tid < 0)
2257db9d7d36SMaxime Chevallier 			return tid;
2258db9d7d36SMaxime Chevallier 
2259db9d7d36SMaxime Chevallier 		pe.index = tid;
2260db9d7d36SMaxime Chevallier 
2261db9d7d36SMaxime Chevallier 		/* Mask all ports */
2262db9d7d36SMaxime Chevallier 		mvpp2_prs_tcam_port_map_set(&pe, 0);
2263db9d7d36SMaxime Chevallier 	} else {
2264db9d7d36SMaxime Chevallier 		mvpp2_prs_init_from_hw(priv, &pe, tid);
2265db9d7d36SMaxime Chevallier 	}
2266db9d7d36SMaxime Chevallier 
2267db9d7d36SMaxime Chevallier 	mvpp2_prs_tcam_lu_set(&pe, MVPP2_PRS_LU_MAC);
2268db9d7d36SMaxime Chevallier 
2269db9d7d36SMaxime Chevallier 	/* Update port mask */
2270db9d7d36SMaxime Chevallier 	mvpp2_prs_tcam_port_set(&pe, port->id, add);
2271db9d7d36SMaxime Chevallier 
2272db9d7d36SMaxime Chevallier 	/* Invalidate the entry if no ports are left enabled */
2273db9d7d36SMaxime Chevallier 	pmap = mvpp2_prs_tcam_port_map_get(&pe);
2274db9d7d36SMaxime Chevallier 	if (pmap == 0) {
2275db9d7d36SMaxime Chevallier 		if (add)
2276db9d7d36SMaxime Chevallier 			return -EINVAL;
2277db9d7d36SMaxime Chevallier 
2278db9d7d36SMaxime Chevallier 		mvpp2_prs_hw_inv(priv, pe.index);
2279db9d7d36SMaxime Chevallier 		priv->prs_shadow[pe.index].valid = false;
2280db9d7d36SMaxime Chevallier 		return 0;
2281db9d7d36SMaxime Chevallier 	}
2282db9d7d36SMaxime Chevallier 
2283db9d7d36SMaxime Chevallier 	/* Continue - set next lookup */
2284db9d7d36SMaxime Chevallier 	mvpp2_prs_sram_next_lu_set(&pe, MVPP2_PRS_LU_DSA);
2285db9d7d36SMaxime Chevallier 
2286db9d7d36SMaxime Chevallier 	/* Set match on DA */
2287db9d7d36SMaxime Chevallier 	len = ETH_ALEN;
2288db9d7d36SMaxime Chevallier 	while (len--)
2289db9d7d36SMaxime Chevallier 		mvpp2_prs_tcam_data_byte_set(&pe, len, da[len], 0xff);
2290db9d7d36SMaxime Chevallier 
2291db9d7d36SMaxime Chevallier 	/* Set result info bits */
2292db9d7d36SMaxime Chevallier 	if (is_broadcast_ether_addr(da)) {
2293db9d7d36SMaxime Chevallier 		ri = MVPP2_PRS_RI_L2_BCAST;
2294db9d7d36SMaxime Chevallier 	} else if (is_multicast_ether_addr(da)) {
2295db9d7d36SMaxime Chevallier 		ri = MVPP2_PRS_RI_L2_MCAST;
2296db9d7d36SMaxime Chevallier 	} else {
2297db9d7d36SMaxime Chevallier 		ri = MVPP2_PRS_RI_L2_UCAST;
2298db9d7d36SMaxime Chevallier 
2299db9d7d36SMaxime Chevallier 		if (ether_addr_equal(da, port->dev->dev_addr))
2300db9d7d36SMaxime Chevallier 			ri |= MVPP2_PRS_RI_MAC_ME_MASK;
2301db9d7d36SMaxime Chevallier 	}
2302db9d7d36SMaxime Chevallier 
2303db9d7d36SMaxime Chevallier 	mvpp2_prs_sram_ri_update(&pe, ri, MVPP2_PRS_RI_L2_CAST_MASK |
2304db9d7d36SMaxime Chevallier 				 MVPP2_PRS_RI_MAC_ME_MASK);
2305db9d7d36SMaxime Chevallier 	mvpp2_prs_shadow_ri_set(priv, pe.index, ri, MVPP2_PRS_RI_L2_CAST_MASK |
2306db9d7d36SMaxime Chevallier 				MVPP2_PRS_RI_MAC_ME_MASK);
2307db9d7d36SMaxime Chevallier 
2308db9d7d36SMaxime Chevallier 	/* Shift to ethertype */
2309db9d7d36SMaxime Chevallier 	mvpp2_prs_sram_shift_set(&pe, 2 * ETH_ALEN,
2310db9d7d36SMaxime Chevallier 				 MVPP2_PRS_SRAM_OP_SEL_SHIFT_ADD);
2311db9d7d36SMaxime Chevallier 
2312db9d7d36SMaxime Chevallier 	/* Update shadow table and hw entry */
2313db9d7d36SMaxime Chevallier 	priv->prs_shadow[pe.index].udf = MVPP2_PRS_UDF_MAC_DEF;
2314db9d7d36SMaxime Chevallier 	mvpp2_prs_shadow_set(priv, pe.index, MVPP2_PRS_LU_MAC);
2315db9d7d36SMaxime Chevallier 	mvpp2_prs_hw_write(priv, &pe);
2316db9d7d36SMaxime Chevallier 
2317db9d7d36SMaxime Chevallier 	return 0;
2318db9d7d36SMaxime Chevallier }
2319db9d7d36SMaxime Chevallier 
mvpp2_prs_update_mac_da(struct net_device * dev,const u8 * da)2320db9d7d36SMaxime Chevallier int mvpp2_prs_update_mac_da(struct net_device *dev, const u8 *da)
2321db9d7d36SMaxime Chevallier {
2322db9d7d36SMaxime Chevallier 	struct mvpp2_port *port = netdev_priv(dev);
2323db9d7d36SMaxime Chevallier 	int err;
2324db9d7d36SMaxime Chevallier 
2325db9d7d36SMaxime Chevallier 	/* Remove old parser entry */
2326db9d7d36SMaxime Chevallier 	err = mvpp2_prs_mac_da_accept(port, dev->dev_addr, false);
2327db9d7d36SMaxime Chevallier 	if (err)
2328db9d7d36SMaxime Chevallier 		return err;
2329db9d7d36SMaxime Chevallier 
2330db9d7d36SMaxime Chevallier 	/* Add new parser entry */
2331db9d7d36SMaxime Chevallier 	err = mvpp2_prs_mac_da_accept(port, da, true);
2332db9d7d36SMaxime Chevallier 	if (err)
2333db9d7d36SMaxime Chevallier 		return err;
2334db9d7d36SMaxime Chevallier 
2335db9d7d36SMaxime Chevallier 	/* Set addr in the device */
2336f3956ebbSJakub Kicinski 	eth_hw_addr_set(dev, da);
2337db9d7d36SMaxime Chevallier 
2338db9d7d36SMaxime Chevallier 	return 0;
2339db9d7d36SMaxime Chevallier }
2340db9d7d36SMaxime Chevallier 
mvpp2_prs_mac_del_all(struct mvpp2_port * port)2341db9d7d36SMaxime Chevallier void mvpp2_prs_mac_del_all(struct mvpp2_port *port)
2342db9d7d36SMaxime Chevallier {
2343db9d7d36SMaxime Chevallier 	struct mvpp2 *priv = port->priv;
2344db9d7d36SMaxime Chevallier 	struct mvpp2_prs_entry pe;
2345db9d7d36SMaxime Chevallier 	unsigned long pmap;
2346db9d7d36SMaxime Chevallier 	int index, tid;
2347db9d7d36SMaxime Chevallier 
2348db9d7d36SMaxime Chevallier 	for (tid = MVPP2_PE_MAC_RANGE_START;
2349db9d7d36SMaxime Chevallier 	     tid <= MVPP2_PE_MAC_RANGE_END; tid++) {
2350db9d7d36SMaxime Chevallier 		unsigned char da[ETH_ALEN], da_mask[ETH_ALEN];
2351db9d7d36SMaxime Chevallier 
2352db9d7d36SMaxime Chevallier 		if (!priv->prs_shadow[tid].valid ||
2353db9d7d36SMaxime Chevallier 		    (priv->prs_shadow[tid].lu != MVPP2_PRS_LU_MAC) ||
2354db9d7d36SMaxime Chevallier 		    (priv->prs_shadow[tid].udf != MVPP2_PRS_UDF_MAC_DEF))
2355db9d7d36SMaxime Chevallier 			continue;
2356db9d7d36SMaxime Chevallier 
2357db9d7d36SMaxime Chevallier 		mvpp2_prs_init_from_hw(priv, &pe, tid);
2358db9d7d36SMaxime Chevallier 
2359db9d7d36SMaxime Chevallier 		pmap = mvpp2_prs_tcam_port_map_get(&pe);
2360db9d7d36SMaxime Chevallier 
2361db9d7d36SMaxime Chevallier 		/* We only want entries active on this port */
2362db9d7d36SMaxime Chevallier 		if (!test_bit(port->id, &pmap))
2363db9d7d36SMaxime Chevallier 			continue;
2364db9d7d36SMaxime Chevallier 
2365db9d7d36SMaxime Chevallier 		/* Read mac addr from entry */
2366db9d7d36SMaxime Chevallier 		for (index = 0; index < ETH_ALEN; index++)
2367db9d7d36SMaxime Chevallier 			mvpp2_prs_tcam_data_byte_get(&pe, index, &da[index],
2368db9d7d36SMaxime Chevallier 						     &da_mask[index]);
2369db9d7d36SMaxime Chevallier 
2370db9d7d36SMaxime Chevallier 		/* Special cases : Don't remove broadcast and port's own
2371db9d7d36SMaxime Chevallier 		 * address
2372db9d7d36SMaxime Chevallier 		 */
2373db9d7d36SMaxime Chevallier 		if (is_broadcast_ether_addr(da) ||
2374db9d7d36SMaxime Chevallier 		    ether_addr_equal(da, port->dev->dev_addr))
2375db9d7d36SMaxime Chevallier 			continue;
2376db9d7d36SMaxime Chevallier 
2377db9d7d36SMaxime Chevallier 		/* Remove entry from TCAM */
2378db9d7d36SMaxime Chevallier 		mvpp2_prs_mac_da_accept(port, da, false);
2379db9d7d36SMaxime Chevallier 	}
2380db9d7d36SMaxime Chevallier }
2381db9d7d36SMaxime Chevallier 
mvpp2_prs_tag_mode_set(struct mvpp2 * priv,int port,int type)2382db9d7d36SMaxime Chevallier int mvpp2_prs_tag_mode_set(struct mvpp2 *priv, int port, int type)
2383db9d7d36SMaxime Chevallier {
2384db9d7d36SMaxime Chevallier 	switch (type) {
2385db9d7d36SMaxime Chevallier 	case MVPP2_TAG_TYPE_EDSA:
2386db9d7d36SMaxime Chevallier 		/* Add port to EDSA entries */
2387db9d7d36SMaxime Chevallier 		mvpp2_prs_dsa_tag_set(priv, port, true,
2388db9d7d36SMaxime Chevallier 				      MVPP2_PRS_TAGGED, MVPP2_PRS_EDSA);
2389db9d7d36SMaxime Chevallier 		mvpp2_prs_dsa_tag_set(priv, port, true,
2390db9d7d36SMaxime Chevallier 				      MVPP2_PRS_UNTAGGED, MVPP2_PRS_EDSA);
2391db9d7d36SMaxime Chevallier 		/* Remove port from DSA entries */
2392db9d7d36SMaxime Chevallier 		mvpp2_prs_dsa_tag_set(priv, port, false,
2393db9d7d36SMaxime Chevallier 				      MVPP2_PRS_TAGGED, MVPP2_PRS_DSA);
2394db9d7d36SMaxime Chevallier 		mvpp2_prs_dsa_tag_set(priv, port, false,
2395db9d7d36SMaxime Chevallier 				      MVPP2_PRS_UNTAGGED, MVPP2_PRS_DSA);
2396db9d7d36SMaxime Chevallier 		break;
2397db9d7d36SMaxime Chevallier 
2398db9d7d36SMaxime Chevallier 	case MVPP2_TAG_TYPE_DSA:
2399db9d7d36SMaxime Chevallier 		/* Add port to DSA entries */
2400db9d7d36SMaxime Chevallier 		mvpp2_prs_dsa_tag_set(priv, port, true,
2401db9d7d36SMaxime Chevallier 				      MVPP2_PRS_TAGGED, MVPP2_PRS_DSA);
2402db9d7d36SMaxime Chevallier 		mvpp2_prs_dsa_tag_set(priv, port, true,
2403db9d7d36SMaxime Chevallier 				      MVPP2_PRS_UNTAGGED, MVPP2_PRS_DSA);
2404db9d7d36SMaxime Chevallier 		/* Remove port from EDSA entries */
2405db9d7d36SMaxime Chevallier 		mvpp2_prs_dsa_tag_set(priv, port, false,
2406db9d7d36SMaxime Chevallier 				      MVPP2_PRS_TAGGED, MVPP2_PRS_EDSA);
2407db9d7d36SMaxime Chevallier 		mvpp2_prs_dsa_tag_set(priv, port, false,
2408db9d7d36SMaxime Chevallier 				      MVPP2_PRS_UNTAGGED, MVPP2_PRS_EDSA);
2409db9d7d36SMaxime Chevallier 		break;
2410db9d7d36SMaxime Chevallier 
2411db9d7d36SMaxime Chevallier 	case MVPP2_TAG_TYPE_MH:
2412db9d7d36SMaxime Chevallier 	case MVPP2_TAG_TYPE_NONE:
2413db9d7d36SMaxime Chevallier 		/* Remove port form EDSA and DSA entries */
2414db9d7d36SMaxime Chevallier 		mvpp2_prs_dsa_tag_set(priv, port, false,
2415db9d7d36SMaxime Chevallier 				      MVPP2_PRS_TAGGED, MVPP2_PRS_DSA);
2416db9d7d36SMaxime Chevallier 		mvpp2_prs_dsa_tag_set(priv, port, false,
2417db9d7d36SMaxime Chevallier 				      MVPP2_PRS_UNTAGGED, MVPP2_PRS_DSA);
2418db9d7d36SMaxime Chevallier 		mvpp2_prs_dsa_tag_set(priv, port, false,
2419db9d7d36SMaxime Chevallier 				      MVPP2_PRS_TAGGED, MVPP2_PRS_EDSA);
2420db9d7d36SMaxime Chevallier 		mvpp2_prs_dsa_tag_set(priv, port, false,
2421db9d7d36SMaxime Chevallier 				      MVPP2_PRS_UNTAGGED, MVPP2_PRS_EDSA);
2422db9d7d36SMaxime Chevallier 		break;
2423db9d7d36SMaxime Chevallier 
2424db9d7d36SMaxime Chevallier 	default:
2425db9d7d36SMaxime Chevallier 		if ((type < 0) || (type > MVPP2_TAG_TYPE_EDSA))
2426db9d7d36SMaxime Chevallier 			return -EINVAL;
2427db9d7d36SMaxime Chevallier 	}
2428db9d7d36SMaxime Chevallier 
2429db9d7d36SMaxime Chevallier 	return 0;
2430db9d7d36SMaxime Chevallier }
2431db9d7d36SMaxime Chevallier 
mvpp2_prs_add_flow(struct mvpp2 * priv,int flow,u32 ri,u32 ri_mask)2432f9358e12SMaxime Chevallier int mvpp2_prs_add_flow(struct mvpp2 *priv, int flow, u32 ri, u32 ri_mask)
2433f9358e12SMaxime Chevallier {
2434f9358e12SMaxime Chevallier 	struct mvpp2_prs_entry pe;
2435f9358e12SMaxime Chevallier 	u8 *ri_byte, *ri_byte_mask;
2436f9358e12SMaxime Chevallier 	int tid, i;
2437f9358e12SMaxime Chevallier 
2438f9358e12SMaxime Chevallier 	memset(&pe, 0, sizeof(pe));
2439f9358e12SMaxime Chevallier 
2440f9358e12SMaxime Chevallier 	tid = mvpp2_prs_tcam_first_free(priv,
2441f9358e12SMaxime Chevallier 					MVPP2_PE_LAST_FREE_TID,
2442f9358e12SMaxime Chevallier 					MVPP2_PE_FIRST_FREE_TID);
2443f9358e12SMaxime Chevallier 	if (tid < 0)
2444f9358e12SMaxime Chevallier 		return tid;
2445f9358e12SMaxime Chevallier 
2446f9358e12SMaxime Chevallier 	pe.index = tid;
2447f9358e12SMaxime Chevallier 
2448f9358e12SMaxime Chevallier 	ri_byte = (u8 *)&ri;
2449f9358e12SMaxime Chevallier 	ri_byte_mask = (u8 *)&ri_mask;
2450f9358e12SMaxime Chevallier 
2451f9358e12SMaxime Chevallier 	mvpp2_prs_sram_ai_update(&pe, flow, MVPP2_PRS_FLOW_ID_MASK);
2452f9358e12SMaxime Chevallier 	mvpp2_prs_sram_bits_set(&pe, MVPP2_PRS_SRAM_LU_DONE_BIT, 1);
2453f9358e12SMaxime Chevallier 
2454f9358e12SMaxime Chevallier 	for (i = 0; i < 4; i++) {
2455f9358e12SMaxime Chevallier 		mvpp2_prs_tcam_data_byte_set(&pe, i, ri_byte[i],
2456f9358e12SMaxime Chevallier 					     ri_byte_mask[i]);
2457f9358e12SMaxime Chevallier 	}
2458f9358e12SMaxime Chevallier 
2459f9358e12SMaxime Chevallier 	mvpp2_prs_shadow_set(priv, pe.index, MVPP2_PRS_LU_FLOWS);
2460f9358e12SMaxime Chevallier 	mvpp2_prs_tcam_lu_set(&pe, MVPP2_PRS_LU_FLOWS);
2461f9358e12SMaxime Chevallier 	mvpp2_prs_tcam_port_map_set(&pe, MVPP2_PRS_PORT_MASK);
2462f9358e12SMaxime Chevallier 	mvpp2_prs_hw_write(priv, &pe);
2463f9358e12SMaxime Chevallier 
2464f9358e12SMaxime Chevallier 	return 0;
2465f9358e12SMaxime Chevallier }
2466f9358e12SMaxime Chevallier 
2467db9d7d36SMaxime Chevallier /* Set prs flow for the port */
mvpp2_prs_def_flow(struct mvpp2_port * port)2468db9d7d36SMaxime Chevallier int mvpp2_prs_def_flow(struct mvpp2_port *port)
2469db9d7d36SMaxime Chevallier {
2470db9d7d36SMaxime Chevallier 	struct mvpp2_prs_entry pe;
2471db9d7d36SMaxime Chevallier 	int tid;
2472db9d7d36SMaxime Chevallier 
2473db9d7d36SMaxime Chevallier 	memset(&pe, 0, sizeof(pe));
2474db9d7d36SMaxime Chevallier 
2475db9d7d36SMaxime Chevallier 	tid = mvpp2_prs_flow_find(port->priv, port->id);
2476db9d7d36SMaxime Chevallier 
2477db9d7d36SMaxime Chevallier 	/* Such entry not exist */
2478db9d7d36SMaxime Chevallier 	if (tid < 0) {
2479db9d7d36SMaxime Chevallier 		/* Go through the all entires from last to first */
2480db9d7d36SMaxime Chevallier 		tid = mvpp2_prs_tcam_first_free(port->priv,
2481db9d7d36SMaxime Chevallier 						MVPP2_PE_LAST_FREE_TID,
2482db9d7d36SMaxime Chevallier 					       MVPP2_PE_FIRST_FREE_TID);
2483db9d7d36SMaxime Chevallier 		if (tid < 0)
2484db9d7d36SMaxime Chevallier 			return tid;
2485db9d7d36SMaxime Chevallier 
2486db9d7d36SMaxime Chevallier 		pe.index = tid;
2487db9d7d36SMaxime Chevallier 
2488db9d7d36SMaxime Chevallier 		/* Set flow ID*/
2489db9d7d36SMaxime Chevallier 		mvpp2_prs_sram_ai_update(&pe, port->id, MVPP2_PRS_FLOW_ID_MASK);
2490db9d7d36SMaxime Chevallier 		mvpp2_prs_sram_bits_set(&pe, MVPP2_PRS_SRAM_LU_DONE_BIT, 1);
2491db9d7d36SMaxime Chevallier 
2492db9d7d36SMaxime Chevallier 		/* Update shadow table */
2493db9d7d36SMaxime Chevallier 		mvpp2_prs_shadow_set(port->priv, pe.index, MVPP2_PRS_LU_FLOWS);
2494db9d7d36SMaxime Chevallier 	} else {
2495db9d7d36SMaxime Chevallier 		mvpp2_prs_init_from_hw(port->priv, &pe, tid);
2496db9d7d36SMaxime Chevallier 	}
2497db9d7d36SMaxime Chevallier 
2498db9d7d36SMaxime Chevallier 	mvpp2_prs_tcam_lu_set(&pe, MVPP2_PRS_LU_FLOWS);
2499db9d7d36SMaxime Chevallier 	mvpp2_prs_tcam_port_map_set(&pe, (1 << port->id));
2500db9d7d36SMaxime Chevallier 	mvpp2_prs_hw_write(port->priv, &pe);
2501db9d7d36SMaxime Chevallier 
2502db9d7d36SMaxime Chevallier 	return 0;
2503db9d7d36SMaxime Chevallier }
25041203341cSMaxime Chevallier 
mvpp2_prs_hits(struct mvpp2 * priv,int index)25051203341cSMaxime Chevallier int mvpp2_prs_hits(struct mvpp2 *priv, int index)
25061203341cSMaxime Chevallier {
25071203341cSMaxime Chevallier 	u32 val;
25081203341cSMaxime Chevallier 
25091203341cSMaxime Chevallier 	if (index > MVPP2_PRS_TCAM_SRAM_SIZE)
25101203341cSMaxime Chevallier 		return -EINVAL;
25111203341cSMaxime Chevallier 
25121203341cSMaxime Chevallier 	mvpp2_write(priv, MVPP2_PRS_TCAM_HIT_IDX_REG, index);
25131203341cSMaxime Chevallier 
25141203341cSMaxime Chevallier 	val = mvpp2_read(priv, MVPP2_PRS_TCAM_HIT_CNT_REG);
25151203341cSMaxime Chevallier 
25161203341cSMaxime Chevallier 	val &= MVPP2_PRS_TCAM_HIT_CNT_MASK;
25171203341cSMaxime Chevallier 
25181203341cSMaxime Chevallier 	return val;
25191203341cSMaxime Chevallier }
2520