1c90ed40cSTony Nguyen // SPDX-License-Identifier: GPL-2.0
2c90ed40cSTony Nguyen /* Copyright (c) 2019, Intel Corporation. */
3c90ed40cSTony Nguyen 
4c90ed40cSTony Nguyen #include "ice_common.h"
5c90ed40cSTony Nguyen #include "ice_flow.h"
6c90ed40cSTony Nguyen 
7c90ed40cSTony Nguyen /* Describe properties of a protocol header field */
8c90ed40cSTony Nguyen struct ice_flow_field_info {
9c90ed40cSTony Nguyen 	enum ice_flow_seg_hdr hdr;
10c90ed40cSTony Nguyen 	s16 off;	/* Offset from start of a protocol header, in bits */
11c90ed40cSTony Nguyen 	u16 size;	/* Size of fields in bits */
12*b199dddbSQi Zhang 	u16 mask;	/* 16-bit mask for field */
13c90ed40cSTony Nguyen };
14c90ed40cSTony Nguyen 
15c90ed40cSTony Nguyen #define ICE_FLOW_FLD_INFO(_hdr, _offset_bytes, _size_bytes) { \
16c90ed40cSTony Nguyen 	.hdr = _hdr, \
17c90ed40cSTony Nguyen 	.off = (_offset_bytes) * BITS_PER_BYTE, \
18c90ed40cSTony Nguyen 	.size = (_size_bytes) * BITS_PER_BYTE, \
19*b199dddbSQi Zhang 	.mask = 0, \
20*b199dddbSQi Zhang }
21*b199dddbSQi Zhang 
22*b199dddbSQi Zhang #define ICE_FLOW_FLD_INFO_MSK(_hdr, _offset_bytes, _size_bytes, _mask) { \
23*b199dddbSQi Zhang 	.hdr = _hdr, \
24*b199dddbSQi Zhang 	.off = (_offset_bytes) * BITS_PER_BYTE, \
25*b199dddbSQi Zhang 	.size = (_size_bytes) * BITS_PER_BYTE, \
26*b199dddbSQi Zhang 	.mask = _mask, \
27c90ed40cSTony Nguyen }
28c90ed40cSTony Nguyen 
29c90ed40cSTony Nguyen /* Table containing properties of supported protocol header fields */
30c90ed40cSTony Nguyen static const
31c90ed40cSTony Nguyen struct ice_flow_field_info ice_flds_info[ICE_FLOW_FIELD_IDX_MAX] = {
32390bd141SQi Zhang 	/* Ether */
33390bd141SQi Zhang 	/* ICE_FLOW_FIELD_IDX_ETH_DA */
34390bd141SQi Zhang 	ICE_FLOW_FLD_INFO(ICE_FLOW_SEG_HDR_ETH, 0, ETH_ALEN),
35390bd141SQi Zhang 	/* ICE_FLOW_FIELD_IDX_ETH_SA */
36390bd141SQi Zhang 	ICE_FLOW_FLD_INFO(ICE_FLOW_SEG_HDR_ETH, ETH_ALEN, ETH_ALEN),
37390bd141SQi Zhang 	/* ICE_FLOW_FIELD_IDX_S_VLAN */
38390bd141SQi Zhang 	ICE_FLOW_FLD_INFO(ICE_FLOW_SEG_HDR_VLAN, 12, sizeof(__be16)),
39390bd141SQi Zhang 	/* ICE_FLOW_FIELD_IDX_C_VLAN */
40390bd141SQi Zhang 	ICE_FLOW_FLD_INFO(ICE_FLOW_SEG_HDR_VLAN, 14, sizeof(__be16)),
41390bd141SQi Zhang 	/* ICE_FLOW_FIELD_IDX_ETH_TYPE */
42390bd141SQi Zhang 	ICE_FLOW_FLD_INFO(ICE_FLOW_SEG_HDR_ETH, 0, sizeof(__be16)),
43c90ed40cSTony Nguyen 	/* IPv4 / IPv6 */
44*b199dddbSQi Zhang 	/* ICE_FLOW_FIELD_IDX_IPV4_DSCP */
45*b199dddbSQi Zhang 	ICE_FLOW_FLD_INFO_MSK(ICE_FLOW_SEG_HDR_IPV4, 0, 1, 0x00fc),
46*b199dddbSQi Zhang 	/* ICE_FLOW_FIELD_IDX_IPV6_DSCP */
47*b199dddbSQi Zhang 	ICE_FLOW_FLD_INFO_MSK(ICE_FLOW_SEG_HDR_IPV6, 0, 1, 0x0ff0),
48*b199dddbSQi Zhang 	/* ICE_FLOW_FIELD_IDX_IPV4_TTL */
49*b199dddbSQi Zhang 	ICE_FLOW_FLD_INFO_MSK(ICE_FLOW_SEG_HDR_NONE, 8, 1, 0xff00),
50*b199dddbSQi Zhang 	/* ICE_FLOW_FIELD_IDX_IPV4_PROT */
51*b199dddbSQi Zhang 	ICE_FLOW_FLD_INFO_MSK(ICE_FLOW_SEG_HDR_NONE, 8, 1, 0x00ff),
52*b199dddbSQi Zhang 	/* ICE_FLOW_FIELD_IDX_IPV6_TTL */
53*b199dddbSQi Zhang 	ICE_FLOW_FLD_INFO_MSK(ICE_FLOW_SEG_HDR_NONE, 6, 1, 0x00ff),
54*b199dddbSQi Zhang 	/* ICE_FLOW_FIELD_IDX_IPV6_PROT */
55*b199dddbSQi Zhang 	ICE_FLOW_FLD_INFO_MSK(ICE_FLOW_SEG_HDR_NONE, 6, 1, 0xff00),
56c90ed40cSTony Nguyen 	/* ICE_FLOW_FIELD_IDX_IPV4_SA */
57c90ed40cSTony Nguyen 	ICE_FLOW_FLD_INFO(ICE_FLOW_SEG_HDR_IPV4, 12, sizeof(struct in_addr)),
58c90ed40cSTony Nguyen 	/* ICE_FLOW_FIELD_IDX_IPV4_DA */
59c90ed40cSTony Nguyen 	ICE_FLOW_FLD_INFO(ICE_FLOW_SEG_HDR_IPV4, 16, sizeof(struct in_addr)),
60c90ed40cSTony Nguyen 	/* ICE_FLOW_FIELD_IDX_IPV6_SA */
61c90ed40cSTony Nguyen 	ICE_FLOW_FLD_INFO(ICE_FLOW_SEG_HDR_IPV6, 8, sizeof(struct in6_addr)),
62c90ed40cSTony Nguyen 	/* ICE_FLOW_FIELD_IDX_IPV6_DA */
63c90ed40cSTony Nguyen 	ICE_FLOW_FLD_INFO(ICE_FLOW_SEG_HDR_IPV6, 24, sizeof(struct in6_addr)),
64c90ed40cSTony Nguyen 	/* Transport */
65c90ed40cSTony Nguyen 	/* ICE_FLOW_FIELD_IDX_TCP_SRC_PORT */
66c90ed40cSTony Nguyen 	ICE_FLOW_FLD_INFO(ICE_FLOW_SEG_HDR_TCP, 0, sizeof(__be16)),
67c90ed40cSTony Nguyen 	/* ICE_FLOW_FIELD_IDX_TCP_DST_PORT */
68c90ed40cSTony Nguyen 	ICE_FLOW_FLD_INFO(ICE_FLOW_SEG_HDR_TCP, 2, sizeof(__be16)),
69c90ed40cSTony Nguyen 	/* ICE_FLOW_FIELD_IDX_UDP_SRC_PORT */
70c90ed40cSTony Nguyen 	ICE_FLOW_FLD_INFO(ICE_FLOW_SEG_HDR_UDP, 0, sizeof(__be16)),
71c90ed40cSTony Nguyen 	/* ICE_FLOW_FIELD_IDX_UDP_DST_PORT */
72c90ed40cSTony Nguyen 	ICE_FLOW_FLD_INFO(ICE_FLOW_SEG_HDR_UDP, 2, sizeof(__be16)),
731c01c8c6SMd Fahad Iqbal Polash 	/* ICE_FLOW_FIELD_IDX_SCTP_SRC_PORT */
741c01c8c6SMd Fahad Iqbal Polash 	ICE_FLOW_FLD_INFO(ICE_FLOW_SEG_HDR_SCTP, 0, sizeof(__be16)),
751c01c8c6SMd Fahad Iqbal Polash 	/* ICE_FLOW_FIELD_IDX_SCTP_DST_PORT */
761c01c8c6SMd Fahad Iqbal Polash 	ICE_FLOW_FLD_INFO(ICE_FLOW_SEG_HDR_SCTP, 2, sizeof(__be16)),
77390bd141SQi Zhang 	/* ICE_FLOW_FIELD_IDX_TCP_FLAGS */
78390bd141SQi Zhang 	ICE_FLOW_FLD_INFO(ICE_FLOW_SEG_HDR_TCP, 13, 1),
79390bd141SQi Zhang 	/* ARP */
80390bd141SQi Zhang 	/* ICE_FLOW_FIELD_IDX_ARP_SIP */
81390bd141SQi Zhang 	ICE_FLOW_FLD_INFO(ICE_FLOW_SEG_HDR_ARP, 14, sizeof(struct in_addr)),
82390bd141SQi Zhang 	/* ICE_FLOW_FIELD_IDX_ARP_DIP */
83390bd141SQi Zhang 	ICE_FLOW_FLD_INFO(ICE_FLOW_SEG_HDR_ARP, 24, sizeof(struct in_addr)),
84390bd141SQi Zhang 	/* ICE_FLOW_FIELD_IDX_ARP_SHA */
85390bd141SQi Zhang 	ICE_FLOW_FLD_INFO(ICE_FLOW_SEG_HDR_ARP, 8, ETH_ALEN),
86390bd141SQi Zhang 	/* ICE_FLOW_FIELD_IDX_ARP_DHA */
87390bd141SQi Zhang 	ICE_FLOW_FLD_INFO(ICE_FLOW_SEG_HDR_ARP, 18, ETH_ALEN),
88390bd141SQi Zhang 	/* ICE_FLOW_FIELD_IDX_ARP_OP */
89390bd141SQi Zhang 	ICE_FLOW_FLD_INFO(ICE_FLOW_SEG_HDR_ARP, 6, sizeof(__be16)),
90390bd141SQi Zhang 	/* ICMP */
91390bd141SQi Zhang 	/* ICE_FLOW_FIELD_IDX_ICMP_TYPE */
92390bd141SQi Zhang 	ICE_FLOW_FLD_INFO(ICE_FLOW_SEG_HDR_ICMP, 0, 1),
93390bd141SQi Zhang 	/* ICE_FLOW_FIELD_IDX_ICMP_CODE */
94390bd141SQi Zhang 	ICE_FLOW_FLD_INFO(ICE_FLOW_SEG_HDR_ICMP, 1, 1),
95a4e82a81STony Nguyen 	/* GRE */
96a4e82a81STony Nguyen 	/* ICE_FLOW_FIELD_IDX_GRE_KEYID */
97a4e82a81STony Nguyen 	ICE_FLOW_FLD_INFO(ICE_FLOW_SEG_HDR_GRE, 12,
98a4e82a81STony Nguyen 			  sizeof_field(struct gre_full_hdr, key)),
99c90ed40cSTony Nguyen };
100c90ed40cSTony Nguyen 
10131ad4e4eSTony Nguyen /* Bitmaps indicating relevant packet types for a particular protocol header
10231ad4e4eSTony Nguyen  *
103390bd141SQi Zhang  * Packet types for packets with an Outer/First/Single MAC header
10431ad4e4eSTony Nguyen  */
105390bd141SQi Zhang static const u32 ice_ptypes_mac_ofos[] = {
106390bd141SQi Zhang 	0xFDC00846, 0xBFBF7F7E, 0xF70001DF, 0xFEFDFDFB,
107390bd141SQi Zhang 	0x0000077E, 0x00000000, 0x00000000, 0x00000000,
108390bd141SQi Zhang 	0x00400000, 0x03FFF000, 0x7FFFFFE0, 0x00000000,
109390bd141SQi Zhang 	0x00000000, 0x00000000, 0x00000000, 0x00000000,
110390bd141SQi Zhang 	0x00000000, 0x00000000, 0x00000000, 0x00000000,
111390bd141SQi Zhang 	0x00000000, 0x00000000, 0x00000000, 0x00000000,
112390bd141SQi Zhang 	0x00000000, 0x00000000, 0x00000000, 0x00000000,
113390bd141SQi Zhang 	0x00000000, 0x00000000, 0x00000000, 0x00000000,
114390bd141SQi Zhang };
115390bd141SQi Zhang 
116390bd141SQi Zhang /* Packet types for packets with an Innermost/Last MAC VLAN header */
117390bd141SQi Zhang static const u32 ice_ptypes_macvlan_il[] = {
118390bd141SQi Zhang 	0x00000000, 0xBC000000, 0x000001DF, 0xF0000000,
119390bd141SQi Zhang 	0x0000077E, 0x00000000, 0x00000000, 0x00000000,
120390bd141SQi Zhang 	0x00000000, 0x00000000, 0x00000000, 0x00000000,
121390bd141SQi Zhang 	0x00000000, 0x00000000, 0x00000000, 0x00000000,
122390bd141SQi Zhang 	0x00000000, 0x00000000, 0x00000000, 0x00000000,
123390bd141SQi Zhang 	0x00000000, 0x00000000, 0x00000000, 0x00000000,
124390bd141SQi Zhang 	0x00000000, 0x00000000, 0x00000000, 0x00000000,
125390bd141SQi Zhang 	0x00000000, 0x00000000, 0x00000000, 0x00000000,
126390bd141SQi Zhang };
127390bd141SQi Zhang 
128390bd141SQi Zhang /* Packet types for packets with an Outer/First/Single IPv4 header */
12931ad4e4eSTony Nguyen static const u32 ice_ptypes_ipv4_ofos[] = {
13031ad4e4eSTony Nguyen 	0x1DC00000, 0x04000800, 0x00000000, 0x00000000,
13131ad4e4eSTony Nguyen 	0x00000000, 0x00000000, 0x00000000, 0x00000000,
13231ad4e4eSTony Nguyen 	0x00000000, 0x00000000, 0x00000000, 0x00000000,
13331ad4e4eSTony Nguyen 	0x00000000, 0x00000000, 0x00000000, 0x00000000,
13431ad4e4eSTony Nguyen 	0x00000000, 0x00000000, 0x00000000, 0x00000000,
13531ad4e4eSTony Nguyen 	0x00000000, 0x00000000, 0x00000000, 0x00000000,
13631ad4e4eSTony Nguyen 	0x00000000, 0x00000000, 0x00000000, 0x00000000,
13731ad4e4eSTony Nguyen 	0x00000000, 0x00000000, 0x00000000, 0x00000000,
13831ad4e4eSTony Nguyen };
13931ad4e4eSTony Nguyen 
14031ad4e4eSTony Nguyen /* Packet types for packets with an Innermost/Last IPv4 header */
14131ad4e4eSTony Nguyen static const u32 ice_ptypes_ipv4_il[] = {
14231ad4e4eSTony Nguyen 	0xE0000000, 0xB807700E, 0x80000003, 0xE01DC03B,
14331ad4e4eSTony Nguyen 	0x0000000E, 0x00000000, 0x00000000, 0x00000000,
14431ad4e4eSTony Nguyen 	0x00000000, 0x00000000, 0x00000000, 0x00000000,
14531ad4e4eSTony Nguyen 	0x00000000, 0x00000000, 0x00000000, 0x00000000,
14631ad4e4eSTony Nguyen 	0x00000000, 0x00000000, 0x00000000, 0x00000000,
14731ad4e4eSTony Nguyen 	0x00000000, 0x00000000, 0x00000000, 0x00000000,
14831ad4e4eSTony Nguyen 	0x00000000, 0x00000000, 0x00000000, 0x00000000,
14931ad4e4eSTony Nguyen 	0x00000000, 0x00000000, 0x00000000, 0x00000000,
15031ad4e4eSTony Nguyen };
15131ad4e4eSTony Nguyen 
15231ad4e4eSTony Nguyen /* Packet types for packets with an Outer/First/Single IPv6 header */
15331ad4e4eSTony Nguyen static const u32 ice_ptypes_ipv6_ofos[] = {
15431ad4e4eSTony Nguyen 	0x00000000, 0x00000000, 0x77000000, 0x10002000,
15531ad4e4eSTony Nguyen 	0x00000000, 0x00000000, 0x00000000, 0x00000000,
15631ad4e4eSTony Nguyen 	0x00000000, 0x00000000, 0x00000000, 0x00000000,
15731ad4e4eSTony Nguyen 	0x00000000, 0x00000000, 0x00000000, 0x00000000,
15831ad4e4eSTony Nguyen 	0x00000000, 0x00000000, 0x00000000, 0x00000000,
15931ad4e4eSTony Nguyen 	0x00000000, 0x00000000, 0x00000000, 0x00000000,
16031ad4e4eSTony Nguyen 	0x00000000, 0x00000000, 0x00000000, 0x00000000,
16131ad4e4eSTony Nguyen 	0x00000000, 0x00000000, 0x00000000, 0x00000000,
16231ad4e4eSTony Nguyen };
16331ad4e4eSTony Nguyen 
16431ad4e4eSTony Nguyen /* Packet types for packets with an Innermost/Last IPv6 header */
16531ad4e4eSTony Nguyen static const u32 ice_ptypes_ipv6_il[] = {
16631ad4e4eSTony Nguyen 	0x00000000, 0x03B80770, 0x000001DC, 0x0EE00000,
16731ad4e4eSTony Nguyen 	0x00000770, 0x00000000, 0x00000000, 0x00000000,
16831ad4e4eSTony Nguyen 	0x00000000, 0x00000000, 0x00000000, 0x00000000,
16931ad4e4eSTony Nguyen 	0x00000000, 0x00000000, 0x00000000, 0x00000000,
17031ad4e4eSTony Nguyen 	0x00000000, 0x00000000, 0x00000000, 0x00000000,
17131ad4e4eSTony Nguyen 	0x00000000, 0x00000000, 0x00000000, 0x00000000,
17231ad4e4eSTony Nguyen 	0x00000000, 0x00000000, 0x00000000, 0x00000000,
17331ad4e4eSTony Nguyen 	0x00000000, 0x00000000, 0x00000000, 0x00000000,
17431ad4e4eSTony Nguyen };
17531ad4e4eSTony Nguyen 
176051d2b5cSDan Nowlin /* Packet types for packets with an Outer/First/Single IPv4 header - no L4 */
177051d2b5cSDan Nowlin static const u32 ice_ipv4_ofos_no_l4[] = {
178051d2b5cSDan Nowlin 	0x10C00000, 0x04000800, 0x00000000, 0x00000000,
179051d2b5cSDan Nowlin 	0x00000000, 0x00000000, 0x00000000, 0x00000000,
180051d2b5cSDan Nowlin 	0x00000000, 0x00000000, 0x00000000, 0x00000000,
181051d2b5cSDan Nowlin 	0x00000000, 0x00000000, 0x00000000, 0x00000000,
182051d2b5cSDan Nowlin 	0x00000000, 0x00000000, 0x00000000, 0x00000000,
183051d2b5cSDan Nowlin 	0x00000000, 0x00000000, 0x00000000, 0x00000000,
184051d2b5cSDan Nowlin 	0x00000000, 0x00000000, 0x00000000, 0x00000000,
185051d2b5cSDan Nowlin 	0x00000000, 0x00000000, 0x00000000, 0x00000000,
186051d2b5cSDan Nowlin };
187051d2b5cSDan Nowlin 
188390bd141SQi Zhang /* Packet types for packets with an Outermost/First ARP header */
189390bd141SQi Zhang static const u32 ice_ptypes_arp_of[] = {
190390bd141SQi Zhang 	0x00000800, 0x00000000, 0x00000000, 0x00000000,
191390bd141SQi Zhang 	0x00000000, 0x00000000, 0x00000000, 0x00000000,
192390bd141SQi Zhang 	0x00000000, 0x00000000, 0x00000000, 0x00000000,
193390bd141SQi Zhang 	0x00000000, 0x00000000, 0x00000000, 0x00000000,
194390bd141SQi Zhang 	0x00000000, 0x00000000, 0x00000000, 0x00000000,
195390bd141SQi Zhang 	0x00000000, 0x00000000, 0x00000000, 0x00000000,
196390bd141SQi Zhang 	0x00000000, 0x00000000, 0x00000000, 0x00000000,
197390bd141SQi Zhang 	0x00000000, 0x00000000, 0x00000000, 0x00000000,
198390bd141SQi Zhang };
199390bd141SQi Zhang 
200051d2b5cSDan Nowlin /* Packet types for packets with an Innermost/Last IPv4 header - no L4 */
201051d2b5cSDan Nowlin static const u32 ice_ipv4_il_no_l4[] = {
202051d2b5cSDan Nowlin 	0x60000000, 0x18043008, 0x80000002, 0x6010c021,
203051d2b5cSDan Nowlin 	0x00000008, 0x00000000, 0x00000000, 0x00000000,
204051d2b5cSDan Nowlin 	0x00000000, 0x00000000, 0x00000000, 0x00000000,
205051d2b5cSDan Nowlin 	0x00000000, 0x00000000, 0x00000000, 0x00000000,
206051d2b5cSDan Nowlin 	0x00000000, 0x00000000, 0x00000000, 0x00000000,
207051d2b5cSDan Nowlin 	0x00000000, 0x00000000, 0x00000000, 0x00000000,
208051d2b5cSDan Nowlin 	0x00000000, 0x00000000, 0x00000000, 0x00000000,
209051d2b5cSDan Nowlin 	0x00000000, 0x00000000, 0x00000000, 0x00000000,
210051d2b5cSDan Nowlin };
211051d2b5cSDan Nowlin 
212051d2b5cSDan Nowlin /* Packet types for packets with an Outer/First/Single IPv6 header - no L4 */
213051d2b5cSDan Nowlin static const u32 ice_ipv6_ofos_no_l4[] = {
214051d2b5cSDan Nowlin 	0x00000000, 0x00000000, 0x43000000, 0x10002000,
215051d2b5cSDan Nowlin 	0x00000000, 0x00000000, 0x00000000, 0x00000000,
216051d2b5cSDan Nowlin 	0x00000000, 0x00000000, 0x00000000, 0x00000000,
217051d2b5cSDan Nowlin 	0x00000000, 0x00000000, 0x00000000, 0x00000000,
218051d2b5cSDan Nowlin 	0x00000000, 0x00000000, 0x00000000, 0x00000000,
219051d2b5cSDan Nowlin 	0x00000000, 0x00000000, 0x00000000, 0x00000000,
220051d2b5cSDan Nowlin 	0x00000000, 0x00000000, 0x00000000, 0x00000000,
221051d2b5cSDan Nowlin 	0x00000000, 0x00000000, 0x00000000, 0x00000000,
222051d2b5cSDan Nowlin };
223051d2b5cSDan Nowlin 
224051d2b5cSDan Nowlin /* Packet types for packets with an Innermost/Last IPv6 header - no L4 */
225051d2b5cSDan Nowlin static const u32 ice_ipv6_il_no_l4[] = {
226051d2b5cSDan Nowlin 	0x00000000, 0x02180430, 0x0000010c, 0x086010c0,
227051d2b5cSDan Nowlin 	0x00000430, 0x00000000, 0x00000000, 0x00000000,
228051d2b5cSDan Nowlin 	0x00000000, 0x00000000, 0x00000000, 0x00000000,
229051d2b5cSDan Nowlin 	0x00000000, 0x00000000, 0x00000000, 0x00000000,
230051d2b5cSDan Nowlin 	0x00000000, 0x00000000, 0x00000000, 0x00000000,
231051d2b5cSDan Nowlin 	0x00000000, 0x00000000, 0x00000000, 0x00000000,
232051d2b5cSDan Nowlin 	0x00000000, 0x00000000, 0x00000000, 0x00000000,
233051d2b5cSDan Nowlin 	0x00000000, 0x00000000, 0x00000000, 0x00000000,
234051d2b5cSDan Nowlin };
235051d2b5cSDan Nowlin 
23631ad4e4eSTony Nguyen /* UDP Packet types for non-tunneled packets or tunneled
23731ad4e4eSTony Nguyen  * packets with inner UDP.
23831ad4e4eSTony Nguyen  */
23931ad4e4eSTony Nguyen static const u32 ice_ptypes_udp_il[] = {
24031ad4e4eSTony Nguyen 	0x81000000, 0x20204040, 0x04000010, 0x80810102,
24131ad4e4eSTony Nguyen 	0x00000040, 0x00000000, 0x00000000, 0x00000000,
24231ad4e4eSTony Nguyen 	0x00000000, 0x00000000, 0x00000000, 0x00000000,
24331ad4e4eSTony Nguyen 	0x00000000, 0x00000000, 0x00000000, 0x00000000,
24431ad4e4eSTony Nguyen 	0x00000000, 0x00000000, 0x00000000, 0x00000000,
24531ad4e4eSTony Nguyen 	0x00000000, 0x00000000, 0x00000000, 0x00000000,
24631ad4e4eSTony Nguyen 	0x00000000, 0x00000000, 0x00000000, 0x00000000,
24731ad4e4eSTony Nguyen 	0x00000000, 0x00000000, 0x00000000, 0x00000000,
24831ad4e4eSTony Nguyen };
24931ad4e4eSTony Nguyen 
25031ad4e4eSTony Nguyen /* Packet types for packets with an Innermost/Last TCP header */
25131ad4e4eSTony Nguyen static const u32 ice_ptypes_tcp_il[] = {
25231ad4e4eSTony Nguyen 	0x04000000, 0x80810102, 0x10000040, 0x02040408,
25331ad4e4eSTony Nguyen 	0x00000102, 0x00000000, 0x00000000, 0x00000000,
25431ad4e4eSTony Nguyen 	0x00000000, 0x00000000, 0x00000000, 0x00000000,
25531ad4e4eSTony Nguyen 	0x00000000, 0x00000000, 0x00000000, 0x00000000,
25631ad4e4eSTony Nguyen 	0x00000000, 0x00000000, 0x00000000, 0x00000000,
25731ad4e4eSTony Nguyen 	0x00000000, 0x00000000, 0x00000000, 0x00000000,
25831ad4e4eSTony Nguyen 	0x00000000, 0x00000000, 0x00000000, 0x00000000,
25931ad4e4eSTony Nguyen 	0x00000000, 0x00000000, 0x00000000, 0x00000000,
26031ad4e4eSTony Nguyen };
26131ad4e4eSTony Nguyen 
26231ad4e4eSTony Nguyen /* Packet types for packets with an Innermost/Last SCTP header */
26331ad4e4eSTony Nguyen static const u32 ice_ptypes_sctp_il[] = {
26431ad4e4eSTony Nguyen 	0x08000000, 0x01020204, 0x20000081, 0x04080810,
26531ad4e4eSTony Nguyen 	0x00000204, 0x00000000, 0x00000000, 0x00000000,
26631ad4e4eSTony Nguyen 	0x00000000, 0x00000000, 0x00000000, 0x00000000,
26731ad4e4eSTony Nguyen 	0x00000000, 0x00000000, 0x00000000, 0x00000000,
26831ad4e4eSTony Nguyen 	0x00000000, 0x00000000, 0x00000000, 0x00000000,
26931ad4e4eSTony Nguyen 	0x00000000, 0x00000000, 0x00000000, 0x00000000,
27031ad4e4eSTony Nguyen 	0x00000000, 0x00000000, 0x00000000, 0x00000000,
271390bd141SQi Zhang };
272390bd141SQi Zhang 
273390bd141SQi Zhang /* Packet types for packets with an Outermost/First ICMP header */
274390bd141SQi Zhang static const u32 ice_ptypes_icmp_of[] = {
275390bd141SQi Zhang 	0x10000000, 0x00000000, 0x00000000, 0x00000000,
276390bd141SQi Zhang 	0x00000000, 0x00000000, 0x00000000, 0x00000000,
277390bd141SQi Zhang 	0x00000000, 0x00000000, 0x00000000, 0x00000000,
278390bd141SQi Zhang 	0x00000000, 0x00000000, 0x00000000, 0x00000000,
279390bd141SQi Zhang 	0x00000000, 0x00000000, 0x00000000, 0x00000000,
280390bd141SQi Zhang 	0x00000000, 0x00000000, 0x00000000, 0x00000000,
281390bd141SQi Zhang 	0x00000000, 0x00000000, 0x00000000, 0x00000000,
282390bd141SQi Zhang 	0x00000000, 0x00000000, 0x00000000, 0x00000000,
283390bd141SQi Zhang };
284390bd141SQi Zhang 
285390bd141SQi Zhang /* Packet types for packets with an Innermost/Last ICMP header */
286390bd141SQi Zhang static const u32 ice_ptypes_icmp_il[] = {
287390bd141SQi Zhang 	0x00000000, 0x02040408, 0x40000102, 0x08101020,
288390bd141SQi Zhang 	0x00000408, 0x00000000, 0x00000000, 0x00000000,
289390bd141SQi Zhang 	0x00000000, 0x00000000, 0x42108000, 0x00000000,
290390bd141SQi Zhang 	0x00000000, 0x00000000, 0x00000000, 0x00000000,
291390bd141SQi Zhang 	0x00000000, 0x00000000, 0x00000000, 0x00000000,
292390bd141SQi Zhang 	0x00000000, 0x00000000, 0x00000000, 0x00000000,
293390bd141SQi Zhang 	0x00000000, 0x00000000, 0x00000000, 0x00000000,
29431ad4e4eSTony Nguyen 	0x00000000, 0x00000000, 0x00000000, 0x00000000,
29531ad4e4eSTony Nguyen };
29631ad4e4eSTony Nguyen 
297a4e82a81STony Nguyen /* Packet types for packets with an Outermost/First GRE header */
298a4e82a81STony Nguyen static const u32 ice_ptypes_gre_of[] = {
299a4e82a81STony Nguyen 	0x00000000, 0xBFBF7800, 0x000001DF, 0xFEFDE000,
300a4e82a81STony Nguyen 	0x0000017E, 0x00000000, 0x00000000, 0x00000000,
301a4e82a81STony Nguyen 	0x00000000, 0x00000000, 0x00000000, 0x00000000,
302a4e82a81STony Nguyen 	0x00000000, 0x00000000, 0x00000000, 0x00000000,
303a4e82a81STony Nguyen 	0x00000000, 0x00000000, 0x00000000, 0x00000000,
304a4e82a81STony Nguyen 	0x00000000, 0x00000000, 0x00000000, 0x00000000,
305a4e82a81STony Nguyen 	0x00000000, 0x00000000, 0x00000000, 0x00000000,
306a4e82a81STony Nguyen 	0x00000000, 0x00000000, 0x00000000, 0x00000000,
307a4e82a81STony Nguyen };
308a4e82a81STony Nguyen 
309390bd141SQi Zhang /* Packet types for packets with an Innermost/Last MAC header */
310390bd141SQi Zhang static const u32 ice_ptypes_mac_il[] = {
311390bd141SQi Zhang 	0x00000000, 0x00000000, 0x00000000, 0x00000000,
312390bd141SQi Zhang 	0x00000000, 0x00000000, 0x00000000, 0x00000000,
313390bd141SQi Zhang 	0x00000000, 0x00000000, 0x00000000, 0x00000000,
314390bd141SQi Zhang 	0x00000000, 0x00000000, 0x00000000, 0x00000000,
315390bd141SQi Zhang 	0x00000000, 0x00000000, 0x00000000, 0x00000000,
316390bd141SQi Zhang 	0x00000000, 0x00000000, 0x00000000, 0x00000000,
317390bd141SQi Zhang 	0x00000000, 0x00000000, 0x00000000, 0x00000000,
318390bd141SQi Zhang 	0x00000000, 0x00000000, 0x00000000, 0x00000000,
319390bd141SQi Zhang };
320390bd141SQi Zhang 
32131ad4e4eSTony Nguyen /* Manage parameters and info. used during the creation of a flow profile */
32231ad4e4eSTony Nguyen struct ice_flow_prof_params {
32331ad4e4eSTony Nguyen 	enum ice_block blk;
32431ad4e4eSTony Nguyen 	u16 entry_length; /* # of bytes formatted entry will require */
32531ad4e4eSTony Nguyen 	u8 es_cnt;
32631ad4e4eSTony Nguyen 	struct ice_flow_prof *prof;
32731ad4e4eSTony Nguyen 
32831ad4e4eSTony Nguyen 	/* For ACL, the es[0] will have the data of ICE_RX_MDID_PKT_FLAGS_15_0
32931ad4e4eSTony Nguyen 	 * This will give us the direction flags.
33031ad4e4eSTony Nguyen 	 */
33131ad4e4eSTony Nguyen 	struct ice_fv_word es[ICE_MAX_FV_WORDS];
332*b199dddbSQi Zhang 
333*b199dddbSQi Zhang 	u16 mask[ICE_MAX_FV_WORDS];
33431ad4e4eSTony Nguyen 	DECLARE_BITMAP(ptypes, ICE_FLOW_PTYPE_MAX);
33531ad4e4eSTony Nguyen };
33631ad4e4eSTony Nguyen 
33731ad4e4eSTony Nguyen #define ICE_FLOW_SEG_HDRS_L3_MASK	\
338390bd141SQi Zhang 	(ICE_FLOW_SEG_HDR_IPV4 | ICE_FLOW_SEG_HDR_IPV6 | ICE_FLOW_SEG_HDR_ARP)
33931ad4e4eSTony Nguyen #define ICE_FLOW_SEG_HDRS_L4_MASK	\
340390bd141SQi Zhang 	(ICE_FLOW_SEG_HDR_ICMP | ICE_FLOW_SEG_HDR_TCP | ICE_FLOW_SEG_HDR_UDP | \
341390bd141SQi Zhang 	 ICE_FLOW_SEG_HDR_SCTP)
34231ad4e4eSTony Nguyen 
34331ad4e4eSTony Nguyen /**
34431ad4e4eSTony Nguyen  * ice_flow_val_hdrs - validates packet segments for valid protocol headers
34531ad4e4eSTony Nguyen  * @segs: array of one or more packet segments that describe the flow
34631ad4e4eSTony Nguyen  * @segs_cnt: number of packet segments provided
34731ad4e4eSTony Nguyen  */
34831ad4e4eSTony Nguyen static enum ice_status
34931ad4e4eSTony Nguyen ice_flow_val_hdrs(struct ice_flow_seg_info *segs, u8 segs_cnt)
35031ad4e4eSTony Nguyen {
35131ad4e4eSTony Nguyen 	u8 i;
35231ad4e4eSTony Nguyen 
35331ad4e4eSTony Nguyen 	for (i = 0; i < segs_cnt; i++) {
35431ad4e4eSTony Nguyen 		/* Multiple L3 headers */
35531ad4e4eSTony Nguyen 		if (segs[i].hdrs & ICE_FLOW_SEG_HDRS_L3_MASK &&
35631ad4e4eSTony Nguyen 		    !is_power_of_2(segs[i].hdrs & ICE_FLOW_SEG_HDRS_L3_MASK))
35731ad4e4eSTony Nguyen 			return ICE_ERR_PARAM;
35831ad4e4eSTony Nguyen 
35931ad4e4eSTony Nguyen 		/* Multiple L4 headers */
36031ad4e4eSTony Nguyen 		if (segs[i].hdrs & ICE_FLOW_SEG_HDRS_L4_MASK &&
36131ad4e4eSTony Nguyen 		    !is_power_of_2(segs[i].hdrs & ICE_FLOW_SEG_HDRS_L4_MASK))
36231ad4e4eSTony Nguyen 			return ICE_ERR_PARAM;
36331ad4e4eSTony Nguyen 	}
36431ad4e4eSTony Nguyen 
36531ad4e4eSTony Nguyen 	return 0;
36631ad4e4eSTony Nguyen }
36731ad4e4eSTony Nguyen 
3682c57ffcbSHenry Tieman /* Sizes of fixed known protocol headers without header options */
3692c57ffcbSHenry Tieman #define ICE_FLOW_PROT_HDR_SZ_MAC	14
370390bd141SQi Zhang #define ICE_FLOW_PROT_HDR_SZ_MAC_VLAN	(ICE_FLOW_PROT_HDR_SZ_MAC + 2)
3712c57ffcbSHenry Tieman #define ICE_FLOW_PROT_HDR_SZ_IPV4	20
3722c57ffcbSHenry Tieman #define ICE_FLOW_PROT_HDR_SZ_IPV6	40
373390bd141SQi Zhang #define ICE_FLOW_PROT_HDR_SZ_ARP	28
374390bd141SQi Zhang #define ICE_FLOW_PROT_HDR_SZ_ICMP	8
3752c57ffcbSHenry Tieman #define ICE_FLOW_PROT_HDR_SZ_TCP	20
3762c57ffcbSHenry Tieman #define ICE_FLOW_PROT_HDR_SZ_UDP	8
3772c57ffcbSHenry Tieman #define ICE_FLOW_PROT_HDR_SZ_SCTP	12
3782c57ffcbSHenry Tieman 
3792c57ffcbSHenry Tieman /**
3802c57ffcbSHenry Tieman  * ice_flow_calc_seg_sz - calculates size of a packet segment based on headers
3812c57ffcbSHenry Tieman  * @params: information about the flow to be processed
3822c57ffcbSHenry Tieman  * @seg: index of packet segment whose header size is to be determined
3832c57ffcbSHenry Tieman  */
3842c57ffcbSHenry Tieman static u16 ice_flow_calc_seg_sz(struct ice_flow_prof_params *params, u8 seg)
3852c57ffcbSHenry Tieman {
386390bd141SQi Zhang 	u16 sz;
387390bd141SQi Zhang 
388390bd141SQi Zhang 	/* L2 headers */
389390bd141SQi Zhang 	sz = (params->prof->segs[seg].hdrs & ICE_FLOW_SEG_HDR_VLAN) ?
390390bd141SQi Zhang 		ICE_FLOW_PROT_HDR_SZ_MAC_VLAN : ICE_FLOW_PROT_HDR_SZ_MAC;
3912c57ffcbSHenry Tieman 
3922c57ffcbSHenry Tieman 	/* L3 headers */
3932c57ffcbSHenry Tieman 	if (params->prof->segs[seg].hdrs & ICE_FLOW_SEG_HDR_IPV4)
3942c57ffcbSHenry Tieman 		sz += ICE_FLOW_PROT_HDR_SZ_IPV4;
3952c57ffcbSHenry Tieman 	else if (params->prof->segs[seg].hdrs & ICE_FLOW_SEG_HDR_IPV6)
3962c57ffcbSHenry Tieman 		sz += ICE_FLOW_PROT_HDR_SZ_IPV6;
397390bd141SQi Zhang 	else if (params->prof->segs[seg].hdrs & ICE_FLOW_SEG_HDR_ARP)
398390bd141SQi Zhang 		sz += ICE_FLOW_PROT_HDR_SZ_ARP;
399390bd141SQi Zhang 	else if (params->prof->segs[seg].hdrs & ICE_FLOW_SEG_HDRS_L4_MASK)
400390bd141SQi Zhang 		/* An L3 header is required if L4 is specified */
401390bd141SQi Zhang 		return 0;
4022c57ffcbSHenry Tieman 
4032c57ffcbSHenry Tieman 	/* L4 headers */
404390bd141SQi Zhang 	if (params->prof->segs[seg].hdrs & ICE_FLOW_SEG_HDR_ICMP)
405390bd141SQi Zhang 		sz += ICE_FLOW_PROT_HDR_SZ_ICMP;
406390bd141SQi Zhang 	else if (params->prof->segs[seg].hdrs & ICE_FLOW_SEG_HDR_TCP)
4072c57ffcbSHenry Tieman 		sz += ICE_FLOW_PROT_HDR_SZ_TCP;
4082c57ffcbSHenry Tieman 	else if (params->prof->segs[seg].hdrs & ICE_FLOW_SEG_HDR_UDP)
4092c57ffcbSHenry Tieman 		sz += ICE_FLOW_PROT_HDR_SZ_UDP;
4102c57ffcbSHenry Tieman 	else if (params->prof->segs[seg].hdrs & ICE_FLOW_SEG_HDR_SCTP)
4112c57ffcbSHenry Tieman 		sz += ICE_FLOW_PROT_HDR_SZ_SCTP;
4122c57ffcbSHenry Tieman 
4132c57ffcbSHenry Tieman 	return sz;
4142c57ffcbSHenry Tieman }
4152c57ffcbSHenry Tieman 
41631ad4e4eSTony Nguyen /**
41731ad4e4eSTony Nguyen  * ice_flow_proc_seg_hdrs - process protocol headers present in pkt segments
41831ad4e4eSTony Nguyen  * @params: information about the flow to be processed
41931ad4e4eSTony Nguyen  *
42031ad4e4eSTony Nguyen  * This function identifies the packet types associated with the protocol
42131ad4e4eSTony Nguyen  * headers being present in packet segments of the specified flow profile.
42231ad4e4eSTony Nguyen  */
42331ad4e4eSTony Nguyen static enum ice_status
42431ad4e4eSTony Nguyen ice_flow_proc_seg_hdrs(struct ice_flow_prof_params *params)
42531ad4e4eSTony Nguyen {
42631ad4e4eSTony Nguyen 	struct ice_flow_prof *prof;
42731ad4e4eSTony Nguyen 	u8 i;
42831ad4e4eSTony Nguyen 
42931ad4e4eSTony Nguyen 	memset(params->ptypes, 0xff, sizeof(params->ptypes));
43031ad4e4eSTony Nguyen 
43131ad4e4eSTony Nguyen 	prof = params->prof;
43231ad4e4eSTony Nguyen 
43331ad4e4eSTony Nguyen 	for (i = 0; i < params->prof->segs_cnt; i++) {
43431ad4e4eSTony Nguyen 		const unsigned long *src;
43531ad4e4eSTony Nguyen 		u32 hdrs;
43631ad4e4eSTony Nguyen 
43731ad4e4eSTony Nguyen 		hdrs = prof->segs[i].hdrs;
43831ad4e4eSTony Nguyen 
439390bd141SQi Zhang 		if (hdrs & ICE_FLOW_SEG_HDR_ETH) {
440390bd141SQi Zhang 			src = !i ? (const unsigned long *)ice_ptypes_mac_ofos :
441390bd141SQi Zhang 				(const unsigned long *)ice_ptypes_mac_il;
442390bd141SQi Zhang 			bitmap_and(params->ptypes, params->ptypes, src,
443390bd141SQi Zhang 				   ICE_FLOW_PTYPE_MAX);
444390bd141SQi Zhang 		}
445390bd141SQi Zhang 
446390bd141SQi Zhang 		if (i && hdrs & ICE_FLOW_SEG_HDR_VLAN) {
447390bd141SQi Zhang 			src = (const unsigned long *)ice_ptypes_macvlan_il;
448390bd141SQi Zhang 			bitmap_and(params->ptypes, params->ptypes, src,
449390bd141SQi Zhang 				   ICE_FLOW_PTYPE_MAX);
450390bd141SQi Zhang 		}
451390bd141SQi Zhang 
452390bd141SQi Zhang 		if (!i && hdrs & ICE_FLOW_SEG_HDR_ARP) {
453390bd141SQi Zhang 			bitmap_and(params->ptypes, params->ptypes,
454390bd141SQi Zhang 				   (const unsigned long *)ice_ptypes_arp_of,
455390bd141SQi Zhang 				   ICE_FLOW_PTYPE_MAX);
456390bd141SQi Zhang 		}
457051d2b5cSDan Nowlin 		if ((hdrs & ICE_FLOW_SEG_HDR_IPV4) &&
458051d2b5cSDan Nowlin 		    !(hdrs & ICE_FLOW_SEG_HDRS_L4_MASK)) {
459051d2b5cSDan Nowlin 			src = !i ? (const unsigned long *)ice_ipv4_ofos_no_l4 :
460051d2b5cSDan Nowlin 				(const unsigned long *)ice_ipv4_il_no_l4;
461051d2b5cSDan Nowlin 			bitmap_and(params->ptypes, params->ptypes, src,
462051d2b5cSDan Nowlin 				   ICE_FLOW_PTYPE_MAX);
463051d2b5cSDan Nowlin 		} else if (hdrs & ICE_FLOW_SEG_HDR_IPV4) {
46431ad4e4eSTony Nguyen 			src = !i ? (const unsigned long *)ice_ptypes_ipv4_ofos :
46531ad4e4eSTony Nguyen 				(const unsigned long *)ice_ptypes_ipv4_il;
46631ad4e4eSTony Nguyen 			bitmap_and(params->ptypes, params->ptypes, src,
46731ad4e4eSTony Nguyen 				   ICE_FLOW_PTYPE_MAX);
468051d2b5cSDan Nowlin 		} else if ((hdrs & ICE_FLOW_SEG_HDR_IPV6) &&
469051d2b5cSDan Nowlin 			   !(hdrs & ICE_FLOW_SEG_HDRS_L4_MASK)) {
470051d2b5cSDan Nowlin 			src = !i ? (const unsigned long *)ice_ipv6_ofos_no_l4 :
471051d2b5cSDan Nowlin 				(const unsigned long *)ice_ipv6_il_no_l4;
472051d2b5cSDan Nowlin 			bitmap_and(params->ptypes, params->ptypes, src,
473051d2b5cSDan Nowlin 				   ICE_FLOW_PTYPE_MAX);
47431ad4e4eSTony Nguyen 		} else if (hdrs & ICE_FLOW_SEG_HDR_IPV6) {
47531ad4e4eSTony Nguyen 			src = !i ? (const unsigned long *)ice_ptypes_ipv6_ofos :
47631ad4e4eSTony Nguyen 				(const unsigned long *)ice_ptypes_ipv6_il;
47731ad4e4eSTony Nguyen 			bitmap_and(params->ptypes, params->ptypes, src,
47831ad4e4eSTony Nguyen 				   ICE_FLOW_PTYPE_MAX);
47931ad4e4eSTony Nguyen 		}
48031ad4e4eSTony Nguyen 
48131ad4e4eSTony Nguyen 		if (hdrs & ICE_FLOW_SEG_HDR_UDP) {
48231ad4e4eSTony Nguyen 			src = (const unsigned long *)ice_ptypes_udp_il;
48331ad4e4eSTony Nguyen 			bitmap_and(params->ptypes, params->ptypes, src,
48431ad4e4eSTony Nguyen 				   ICE_FLOW_PTYPE_MAX);
48531ad4e4eSTony Nguyen 		} else if (hdrs & ICE_FLOW_SEG_HDR_TCP) {
48631ad4e4eSTony Nguyen 			bitmap_and(params->ptypes, params->ptypes,
48731ad4e4eSTony Nguyen 				   (const unsigned long *)ice_ptypes_tcp_il,
48831ad4e4eSTony Nguyen 				   ICE_FLOW_PTYPE_MAX);
48931ad4e4eSTony Nguyen 		} else if (hdrs & ICE_FLOW_SEG_HDR_SCTP) {
49031ad4e4eSTony Nguyen 			src = (const unsigned long *)ice_ptypes_sctp_il;
49131ad4e4eSTony Nguyen 			bitmap_and(params->ptypes, params->ptypes, src,
49231ad4e4eSTony Nguyen 				   ICE_FLOW_PTYPE_MAX);
493390bd141SQi Zhang 		}
494390bd141SQi Zhang 
495390bd141SQi Zhang 		if (hdrs & ICE_FLOW_SEG_HDR_ICMP) {
496390bd141SQi Zhang 			src = !i ? (const unsigned long *)ice_ptypes_icmp_of :
497390bd141SQi Zhang 				(const unsigned long *)ice_ptypes_icmp_il;
498390bd141SQi Zhang 			bitmap_and(params->ptypes, params->ptypes, src,
499390bd141SQi Zhang 				   ICE_FLOW_PTYPE_MAX);
500a4e82a81STony Nguyen 		} else if (hdrs & ICE_FLOW_SEG_HDR_GRE) {
501a4e82a81STony Nguyen 			if (!i) {
502a4e82a81STony Nguyen 				src = (const unsigned long *)ice_ptypes_gre_of;
503a4e82a81STony Nguyen 				bitmap_and(params->ptypes, params->ptypes,
504a4e82a81STony Nguyen 					   src, ICE_FLOW_PTYPE_MAX);
505a4e82a81STony Nguyen 			}
50631ad4e4eSTony Nguyen 		}
50731ad4e4eSTony Nguyen 	}
50831ad4e4eSTony Nguyen 
50931ad4e4eSTony Nguyen 	return 0;
51031ad4e4eSTony Nguyen }
51131ad4e4eSTony Nguyen 
51231ad4e4eSTony Nguyen /**
51331ad4e4eSTony Nguyen  * ice_flow_xtract_fld - Create an extraction sequence entry for the given field
51431ad4e4eSTony Nguyen  * @hw: pointer to the HW struct
51531ad4e4eSTony Nguyen  * @params: information about the flow to be processed
51631ad4e4eSTony Nguyen  * @seg: packet segment index of the field to be extracted
51731ad4e4eSTony Nguyen  * @fld: ID of field to be extracted
518*b199dddbSQi Zhang  * @match: bit field of all fields
51931ad4e4eSTony Nguyen  *
52031ad4e4eSTony Nguyen  * This function determines the protocol ID, offset, and size of the given
52131ad4e4eSTony Nguyen  * field. It then allocates one or more extraction sequence entries for the
52231ad4e4eSTony Nguyen  * given field, and fill the entries with protocol ID and offset information.
52331ad4e4eSTony Nguyen  */
52431ad4e4eSTony Nguyen static enum ice_status
52531ad4e4eSTony Nguyen ice_flow_xtract_fld(struct ice_hw *hw, struct ice_flow_prof_params *params,
526*b199dddbSQi Zhang 		    u8 seg, enum ice_flow_field fld, u64 match)
52731ad4e4eSTony Nguyen {
528*b199dddbSQi Zhang 	enum ice_flow_field sib = ICE_FLOW_FIELD_IDX_MAX;
52931ad4e4eSTony Nguyen 	enum ice_prot_id prot_id = ICE_PROT_ID_INVAL;
53031ad4e4eSTony Nguyen 	u8 fv_words = hw->blk[params->blk].es.fvw;
53131ad4e4eSTony Nguyen 	struct ice_flow_fld_info *flds;
53231ad4e4eSTony Nguyen 	u16 cnt, ese_bits, i;
533*b199dddbSQi Zhang 	u16 sib_mask = 0;
534*b199dddbSQi Zhang 	u16 mask;
53531ad4e4eSTony Nguyen 	u16 off;
53631ad4e4eSTony Nguyen 
53731ad4e4eSTony Nguyen 	flds = params->prof->segs[seg].fields;
53831ad4e4eSTony Nguyen 
53931ad4e4eSTony Nguyen 	switch (fld) {
540390bd141SQi Zhang 	case ICE_FLOW_FIELD_IDX_ETH_DA:
541390bd141SQi Zhang 	case ICE_FLOW_FIELD_IDX_ETH_SA:
542390bd141SQi Zhang 	case ICE_FLOW_FIELD_IDX_S_VLAN:
543390bd141SQi Zhang 	case ICE_FLOW_FIELD_IDX_C_VLAN:
544390bd141SQi Zhang 		prot_id = seg == 0 ? ICE_PROT_MAC_OF_OR_S : ICE_PROT_MAC_IL;
545390bd141SQi Zhang 		break;
546390bd141SQi Zhang 	case ICE_FLOW_FIELD_IDX_ETH_TYPE:
547390bd141SQi Zhang 		prot_id = seg == 0 ? ICE_PROT_ETYPE_OL : ICE_PROT_ETYPE_IL;
548390bd141SQi Zhang 		break;
549*b199dddbSQi Zhang 	case ICE_FLOW_FIELD_IDX_IPV4_DSCP:
550*b199dddbSQi Zhang 		prot_id = seg == 0 ? ICE_PROT_IPV4_OF_OR_S : ICE_PROT_IPV4_IL;
551*b199dddbSQi Zhang 		break;
552*b199dddbSQi Zhang 	case ICE_FLOW_FIELD_IDX_IPV6_DSCP:
553*b199dddbSQi Zhang 		prot_id = seg == 0 ? ICE_PROT_IPV6_OF_OR_S : ICE_PROT_IPV6_IL;
554*b199dddbSQi Zhang 		break;
555*b199dddbSQi Zhang 	case ICE_FLOW_FIELD_IDX_IPV4_TTL:
556*b199dddbSQi Zhang 	case ICE_FLOW_FIELD_IDX_IPV4_PROT:
557*b199dddbSQi Zhang 		prot_id = seg == 0 ? ICE_PROT_IPV4_OF_OR_S : ICE_PROT_IPV4_IL;
558*b199dddbSQi Zhang 
559*b199dddbSQi Zhang 		/* TTL and PROT share the same extraction seq. entry.
560*b199dddbSQi Zhang 		 * Each is considered a sibling to the other in terms of sharing
561*b199dddbSQi Zhang 		 * the same extraction sequence entry.
562*b199dddbSQi Zhang 		 */
563*b199dddbSQi Zhang 		if (fld == ICE_FLOW_FIELD_IDX_IPV4_TTL)
564*b199dddbSQi Zhang 			sib = ICE_FLOW_FIELD_IDX_IPV4_PROT;
565*b199dddbSQi Zhang 		else if (fld == ICE_FLOW_FIELD_IDX_IPV4_PROT)
566*b199dddbSQi Zhang 			sib = ICE_FLOW_FIELD_IDX_IPV4_TTL;
567*b199dddbSQi Zhang 
568*b199dddbSQi Zhang 		/* If the sibling field is also included, that field's
569*b199dddbSQi Zhang 		 * mask needs to be included.
570*b199dddbSQi Zhang 		 */
571*b199dddbSQi Zhang 		if (match & BIT(sib))
572*b199dddbSQi Zhang 			sib_mask = ice_flds_info[sib].mask;
573*b199dddbSQi Zhang 		break;
574*b199dddbSQi Zhang 	case ICE_FLOW_FIELD_IDX_IPV6_TTL:
575*b199dddbSQi Zhang 	case ICE_FLOW_FIELD_IDX_IPV6_PROT:
576*b199dddbSQi Zhang 		prot_id = seg == 0 ? ICE_PROT_IPV6_OF_OR_S : ICE_PROT_IPV6_IL;
577*b199dddbSQi Zhang 
578*b199dddbSQi Zhang 		/* TTL and PROT share the same extraction seq. entry.
579*b199dddbSQi Zhang 		 * Each is considered a sibling to the other in terms of sharing
580*b199dddbSQi Zhang 		 * the same extraction sequence entry.
581*b199dddbSQi Zhang 		 */
582*b199dddbSQi Zhang 		if (fld == ICE_FLOW_FIELD_IDX_IPV6_TTL)
583*b199dddbSQi Zhang 			sib = ICE_FLOW_FIELD_IDX_IPV6_PROT;
584*b199dddbSQi Zhang 		else if (fld == ICE_FLOW_FIELD_IDX_IPV6_PROT)
585*b199dddbSQi Zhang 			sib = ICE_FLOW_FIELD_IDX_IPV6_TTL;
586*b199dddbSQi Zhang 
587*b199dddbSQi Zhang 		/* If the sibling field is also included, that field's
588*b199dddbSQi Zhang 		 * mask needs to be included.
589*b199dddbSQi Zhang 		 */
590*b199dddbSQi Zhang 		if (match & BIT(sib))
591*b199dddbSQi Zhang 			sib_mask = ice_flds_info[sib].mask;
592*b199dddbSQi Zhang 		break;
59331ad4e4eSTony Nguyen 	case ICE_FLOW_FIELD_IDX_IPV4_SA:
59431ad4e4eSTony Nguyen 	case ICE_FLOW_FIELD_IDX_IPV4_DA:
59531ad4e4eSTony Nguyen 		prot_id = seg == 0 ? ICE_PROT_IPV4_OF_OR_S : ICE_PROT_IPV4_IL;
59631ad4e4eSTony Nguyen 		break;
59731ad4e4eSTony Nguyen 	case ICE_FLOW_FIELD_IDX_IPV6_SA:
59831ad4e4eSTony Nguyen 	case ICE_FLOW_FIELD_IDX_IPV6_DA:
59931ad4e4eSTony Nguyen 		prot_id = seg == 0 ? ICE_PROT_IPV6_OF_OR_S : ICE_PROT_IPV6_IL;
60031ad4e4eSTony Nguyen 		break;
60131ad4e4eSTony Nguyen 	case ICE_FLOW_FIELD_IDX_TCP_SRC_PORT:
60231ad4e4eSTony Nguyen 	case ICE_FLOW_FIELD_IDX_TCP_DST_PORT:
603390bd141SQi Zhang 	case ICE_FLOW_FIELD_IDX_TCP_FLAGS:
60431ad4e4eSTony Nguyen 		prot_id = ICE_PROT_TCP_IL;
60531ad4e4eSTony Nguyen 		break;
60631ad4e4eSTony Nguyen 	case ICE_FLOW_FIELD_IDX_UDP_SRC_PORT:
60731ad4e4eSTony Nguyen 	case ICE_FLOW_FIELD_IDX_UDP_DST_PORT:
60831ad4e4eSTony Nguyen 		prot_id = ICE_PROT_UDP_IL_OR_S;
60931ad4e4eSTony Nguyen 		break;
6101c01c8c6SMd Fahad Iqbal Polash 	case ICE_FLOW_FIELD_IDX_SCTP_SRC_PORT:
6111c01c8c6SMd Fahad Iqbal Polash 	case ICE_FLOW_FIELD_IDX_SCTP_DST_PORT:
6121c01c8c6SMd Fahad Iqbal Polash 		prot_id = ICE_PROT_SCTP_IL;
6131c01c8c6SMd Fahad Iqbal Polash 		break;
614390bd141SQi Zhang 	case ICE_FLOW_FIELD_IDX_ARP_SIP:
615390bd141SQi Zhang 	case ICE_FLOW_FIELD_IDX_ARP_DIP:
616390bd141SQi Zhang 	case ICE_FLOW_FIELD_IDX_ARP_SHA:
617390bd141SQi Zhang 	case ICE_FLOW_FIELD_IDX_ARP_DHA:
618390bd141SQi Zhang 	case ICE_FLOW_FIELD_IDX_ARP_OP:
619390bd141SQi Zhang 		prot_id = ICE_PROT_ARP_OF;
620390bd141SQi Zhang 		break;
621390bd141SQi Zhang 	case ICE_FLOW_FIELD_IDX_ICMP_TYPE:
622390bd141SQi Zhang 	case ICE_FLOW_FIELD_IDX_ICMP_CODE:
623390bd141SQi Zhang 		/* ICMP type and code share the same extraction seq. entry */
624390bd141SQi Zhang 		prot_id = (params->prof->segs[seg].hdrs & ICE_FLOW_SEG_HDR_IPV4) ?
625390bd141SQi Zhang 				ICE_PROT_ICMP_IL : ICE_PROT_ICMPV6_IL;
626*b199dddbSQi Zhang 		sib = fld == ICE_FLOW_FIELD_IDX_ICMP_TYPE ?
627*b199dddbSQi Zhang 			ICE_FLOW_FIELD_IDX_ICMP_CODE :
628*b199dddbSQi Zhang 			ICE_FLOW_FIELD_IDX_ICMP_TYPE;
629390bd141SQi Zhang 		break;
630a4e82a81STony Nguyen 	case ICE_FLOW_FIELD_IDX_GRE_KEYID:
631a4e82a81STony Nguyen 		prot_id = ICE_PROT_GRE_OF;
632a4e82a81STony Nguyen 		break;
63331ad4e4eSTony Nguyen 	default:
63431ad4e4eSTony Nguyen 		return ICE_ERR_NOT_IMPL;
63531ad4e4eSTony Nguyen 	}
63631ad4e4eSTony Nguyen 
63731ad4e4eSTony Nguyen 	/* Each extraction sequence entry is a word in size, and extracts a
63831ad4e4eSTony Nguyen 	 * word-aligned offset from a protocol header.
63931ad4e4eSTony Nguyen 	 */
64031ad4e4eSTony Nguyen 	ese_bits = ICE_FLOW_FV_EXTRACT_SZ * BITS_PER_BYTE;
64131ad4e4eSTony Nguyen 
64231ad4e4eSTony Nguyen 	flds[fld].xtrct.prot_id = prot_id;
64331ad4e4eSTony Nguyen 	flds[fld].xtrct.off = (ice_flds_info[fld].off / ese_bits) *
64431ad4e4eSTony Nguyen 		ICE_FLOW_FV_EXTRACT_SZ;
64531ad4e4eSTony Nguyen 	flds[fld].xtrct.disp = (u8)(ice_flds_info[fld].off % ese_bits);
64631ad4e4eSTony Nguyen 	flds[fld].xtrct.idx = params->es_cnt;
647*b199dddbSQi Zhang 	flds[fld].xtrct.mask = ice_flds_info[fld].mask;
64831ad4e4eSTony Nguyen 
64931ad4e4eSTony Nguyen 	/* Adjust the next field-entry index after accommodating the number of
65031ad4e4eSTony Nguyen 	 * entries this field consumes
65131ad4e4eSTony Nguyen 	 */
65231ad4e4eSTony Nguyen 	cnt = DIV_ROUND_UP(flds[fld].xtrct.disp + ice_flds_info[fld].size,
65331ad4e4eSTony Nguyen 			   ese_bits);
65431ad4e4eSTony Nguyen 
65531ad4e4eSTony Nguyen 	/* Fill in the extraction sequence entries needed for this field */
65631ad4e4eSTony Nguyen 	off = flds[fld].xtrct.off;
657*b199dddbSQi Zhang 	mask = flds[fld].xtrct.mask;
65831ad4e4eSTony Nguyen 	for (i = 0; i < cnt; i++) {
659*b199dddbSQi Zhang 		/* Only consume an extraction sequence entry if there is no
660*b199dddbSQi Zhang 		 * sibling field associated with this field or the sibling entry
661*b199dddbSQi Zhang 		 * already extracts the word shared with this field.
662*b199dddbSQi Zhang 		 */
663*b199dddbSQi Zhang 		if (sib == ICE_FLOW_FIELD_IDX_MAX ||
664*b199dddbSQi Zhang 		    flds[sib].xtrct.prot_id == ICE_PROT_ID_INVAL ||
665*b199dddbSQi Zhang 		    flds[sib].xtrct.off != off) {
66631ad4e4eSTony Nguyen 			u8 idx;
66731ad4e4eSTony Nguyen 
66831ad4e4eSTony Nguyen 			/* Make sure the number of extraction sequence required
66931ad4e4eSTony Nguyen 			 * does not exceed the block's capability
67031ad4e4eSTony Nguyen 			 */
67131ad4e4eSTony Nguyen 			if (params->es_cnt >= fv_words)
67231ad4e4eSTony Nguyen 				return ICE_ERR_MAX_LIMIT;
67331ad4e4eSTony Nguyen 
67431ad4e4eSTony Nguyen 			/* some blocks require a reversed field vector layout */
67531ad4e4eSTony Nguyen 			if (hw->blk[params->blk].es.reverse)
67631ad4e4eSTony Nguyen 				idx = fv_words - params->es_cnt - 1;
67731ad4e4eSTony Nguyen 			else
67831ad4e4eSTony Nguyen 				idx = params->es_cnt;
67931ad4e4eSTony Nguyen 
68031ad4e4eSTony Nguyen 			params->es[idx].prot_id = prot_id;
68131ad4e4eSTony Nguyen 			params->es[idx].off = off;
682*b199dddbSQi Zhang 			params->mask[idx] = mask | sib_mask;
68331ad4e4eSTony Nguyen 			params->es_cnt++;
684*b199dddbSQi Zhang 		}
68531ad4e4eSTony Nguyen 
68631ad4e4eSTony Nguyen 		off += ICE_FLOW_FV_EXTRACT_SZ;
68731ad4e4eSTony Nguyen 	}
68831ad4e4eSTony Nguyen 
68931ad4e4eSTony Nguyen 	return 0;
69031ad4e4eSTony Nguyen }
69131ad4e4eSTony Nguyen 
69231ad4e4eSTony Nguyen /**
6932c57ffcbSHenry Tieman  * ice_flow_xtract_raws - Create extract sequence entries for raw bytes
6942c57ffcbSHenry Tieman  * @hw: pointer to the HW struct
6952c57ffcbSHenry Tieman  * @params: information about the flow to be processed
696ac382a09SBruce Allan  * @seg: index of packet segment whose raw fields are to be extracted
6972c57ffcbSHenry Tieman  */
6982c57ffcbSHenry Tieman static enum ice_status
6992c57ffcbSHenry Tieman ice_flow_xtract_raws(struct ice_hw *hw, struct ice_flow_prof_params *params,
7002c57ffcbSHenry Tieman 		     u8 seg)
7012c57ffcbSHenry Tieman {
7022c57ffcbSHenry Tieman 	u16 fv_words;
7032c57ffcbSHenry Tieman 	u16 hdrs_sz;
7042c57ffcbSHenry Tieman 	u8 i;
7052c57ffcbSHenry Tieman 
7062c57ffcbSHenry Tieman 	if (!params->prof->segs[seg].raws_cnt)
7072c57ffcbSHenry Tieman 		return 0;
7082c57ffcbSHenry Tieman 
7092c57ffcbSHenry Tieman 	if (params->prof->segs[seg].raws_cnt >
7102c57ffcbSHenry Tieman 	    ARRAY_SIZE(params->prof->segs[seg].raws))
7112c57ffcbSHenry Tieman 		return ICE_ERR_MAX_LIMIT;
7122c57ffcbSHenry Tieman 
7132c57ffcbSHenry Tieman 	/* Offsets within the segment headers are not supported */
7142c57ffcbSHenry Tieman 	hdrs_sz = ice_flow_calc_seg_sz(params, seg);
7152c57ffcbSHenry Tieman 	if (!hdrs_sz)
7162c57ffcbSHenry Tieman 		return ICE_ERR_PARAM;
7172c57ffcbSHenry Tieman 
7182c57ffcbSHenry Tieman 	fv_words = hw->blk[params->blk].es.fvw;
7192c57ffcbSHenry Tieman 
7202c57ffcbSHenry Tieman 	for (i = 0; i < params->prof->segs[seg].raws_cnt; i++) {
7212c57ffcbSHenry Tieman 		struct ice_flow_seg_fld_raw *raw;
7222c57ffcbSHenry Tieman 		u16 off, cnt, j;
7232c57ffcbSHenry Tieman 
7242c57ffcbSHenry Tieman 		raw = &params->prof->segs[seg].raws[i];
7252c57ffcbSHenry Tieman 
7262c57ffcbSHenry Tieman 		/* Storing extraction information */
7272c57ffcbSHenry Tieman 		raw->info.xtrct.prot_id = ICE_PROT_MAC_OF_OR_S;
7282c57ffcbSHenry Tieman 		raw->info.xtrct.off = (raw->off / ICE_FLOW_FV_EXTRACT_SZ) *
7292c57ffcbSHenry Tieman 			ICE_FLOW_FV_EXTRACT_SZ;
7302c57ffcbSHenry Tieman 		raw->info.xtrct.disp = (raw->off % ICE_FLOW_FV_EXTRACT_SZ) *
7312c57ffcbSHenry Tieman 			BITS_PER_BYTE;
7322c57ffcbSHenry Tieman 		raw->info.xtrct.idx = params->es_cnt;
7332c57ffcbSHenry Tieman 
7342c57ffcbSHenry Tieman 		/* Determine the number of field vector entries this raw field
7352c57ffcbSHenry Tieman 		 * consumes.
7362c57ffcbSHenry Tieman 		 */
7372c57ffcbSHenry Tieman 		cnt = DIV_ROUND_UP(raw->info.xtrct.disp +
7382c57ffcbSHenry Tieman 				   (raw->info.src.last * BITS_PER_BYTE),
7392c57ffcbSHenry Tieman 				   (ICE_FLOW_FV_EXTRACT_SZ * BITS_PER_BYTE));
7402c57ffcbSHenry Tieman 		off = raw->info.xtrct.off;
7412c57ffcbSHenry Tieman 		for (j = 0; j < cnt; j++) {
7422c57ffcbSHenry Tieman 			u16 idx;
7432c57ffcbSHenry Tieman 
7442c57ffcbSHenry Tieman 			/* Make sure the number of extraction sequence required
7452c57ffcbSHenry Tieman 			 * does not exceed the block's capability
7462c57ffcbSHenry Tieman 			 */
7472c57ffcbSHenry Tieman 			if (params->es_cnt >= hw->blk[params->blk].es.count ||
7482c57ffcbSHenry Tieman 			    params->es_cnt >= ICE_MAX_FV_WORDS)
7492c57ffcbSHenry Tieman 				return ICE_ERR_MAX_LIMIT;
7502c57ffcbSHenry Tieman 
7512c57ffcbSHenry Tieman 			/* some blocks require a reversed field vector layout */
7522c57ffcbSHenry Tieman 			if (hw->blk[params->blk].es.reverse)
7532c57ffcbSHenry Tieman 				idx = fv_words - params->es_cnt - 1;
7542c57ffcbSHenry Tieman 			else
7552c57ffcbSHenry Tieman 				idx = params->es_cnt;
7562c57ffcbSHenry Tieman 
7572c57ffcbSHenry Tieman 			params->es[idx].prot_id = raw->info.xtrct.prot_id;
7582c57ffcbSHenry Tieman 			params->es[idx].off = off;
7592c57ffcbSHenry Tieman 			params->es_cnt++;
7602c57ffcbSHenry Tieman 			off += ICE_FLOW_FV_EXTRACT_SZ;
7612c57ffcbSHenry Tieman 		}
7622c57ffcbSHenry Tieman 	}
7632c57ffcbSHenry Tieman 
7642c57ffcbSHenry Tieman 	return 0;
7652c57ffcbSHenry Tieman }
7662c57ffcbSHenry Tieman 
7672c57ffcbSHenry Tieman /**
76831ad4e4eSTony Nguyen  * ice_flow_create_xtrct_seq - Create an extraction sequence for given segments
76931ad4e4eSTony Nguyen  * @hw: pointer to the HW struct
77031ad4e4eSTony Nguyen  * @params: information about the flow to be processed
77131ad4e4eSTony Nguyen  *
77231ad4e4eSTony Nguyen  * This function iterates through all matched fields in the given segments, and
77331ad4e4eSTony Nguyen  * creates an extraction sequence for the fields.
77431ad4e4eSTony Nguyen  */
77531ad4e4eSTony Nguyen static enum ice_status
77631ad4e4eSTony Nguyen ice_flow_create_xtrct_seq(struct ice_hw *hw,
77731ad4e4eSTony Nguyen 			  struct ice_flow_prof_params *params)
77831ad4e4eSTony Nguyen {
77931ad4e4eSTony Nguyen 	struct ice_flow_prof *prof = params->prof;
78031ad4e4eSTony Nguyen 	enum ice_status status = 0;
78131ad4e4eSTony Nguyen 	u8 i;
78231ad4e4eSTony Nguyen 
78331ad4e4eSTony Nguyen 	for (i = 0; i < prof->segs_cnt; i++) {
784*b199dddbSQi Zhang 		u64 match = params->prof->segs[i].match;
785*b199dddbSQi Zhang 		enum ice_flow_field j;
78631ad4e4eSTony Nguyen 
787*b199dddbSQi Zhang 		for_each_set_bit(j, (unsigned long *)&match,
78831ad4e4eSTony Nguyen 				 ICE_FLOW_FIELD_IDX_MAX) {
789*b199dddbSQi Zhang 			status = ice_flow_xtract_fld(hw, params, i, j, match);
79031ad4e4eSTony Nguyen 			if (status)
79131ad4e4eSTony Nguyen 				return status;
792*b199dddbSQi Zhang 			clear_bit(j, (unsigned long *)&match);
79331ad4e4eSTony Nguyen 		}
7942c57ffcbSHenry Tieman 
7952c57ffcbSHenry Tieman 		/* Process raw matching bytes */
7962c57ffcbSHenry Tieman 		status = ice_flow_xtract_raws(hw, params, i);
7972c57ffcbSHenry Tieman 		if (status)
7982c57ffcbSHenry Tieman 			return status;
79931ad4e4eSTony Nguyen 	}
80031ad4e4eSTony Nguyen 
80131ad4e4eSTony Nguyen 	return status;
80231ad4e4eSTony Nguyen }
80331ad4e4eSTony Nguyen 
80431ad4e4eSTony Nguyen /**
80531ad4e4eSTony Nguyen  * ice_flow_proc_segs - process all packet segments associated with a profile
80631ad4e4eSTony Nguyen  * @hw: pointer to the HW struct
80731ad4e4eSTony Nguyen  * @params: information about the flow to be processed
80831ad4e4eSTony Nguyen  */
80931ad4e4eSTony Nguyen static enum ice_status
81031ad4e4eSTony Nguyen ice_flow_proc_segs(struct ice_hw *hw, struct ice_flow_prof_params *params)
81131ad4e4eSTony Nguyen {
81231ad4e4eSTony Nguyen 	enum ice_status status;
81331ad4e4eSTony Nguyen 
81431ad4e4eSTony Nguyen 	status = ice_flow_proc_seg_hdrs(params);
81531ad4e4eSTony Nguyen 	if (status)
81631ad4e4eSTony Nguyen 		return status;
81731ad4e4eSTony Nguyen 
81831ad4e4eSTony Nguyen 	status = ice_flow_create_xtrct_seq(hw, params);
81931ad4e4eSTony Nguyen 	if (status)
82031ad4e4eSTony Nguyen 		return status;
82131ad4e4eSTony Nguyen 
82231ad4e4eSTony Nguyen 	switch (params->blk) {
823148beb61SHenry Tieman 	case ICE_BLK_FD:
82431ad4e4eSTony Nguyen 	case ICE_BLK_RSS:
82531ad4e4eSTony Nguyen 		status = 0;
82631ad4e4eSTony Nguyen 		break;
82731ad4e4eSTony Nguyen 	default:
82831ad4e4eSTony Nguyen 		return ICE_ERR_NOT_IMPL;
82931ad4e4eSTony Nguyen 	}
83031ad4e4eSTony Nguyen 
83131ad4e4eSTony Nguyen 	return status;
83231ad4e4eSTony Nguyen }
83331ad4e4eSTony Nguyen 
8342c61054cSTony Nguyen #define ICE_FLOW_FIND_PROF_CHK_FLDS	0x00000001
8352c61054cSTony Nguyen #define ICE_FLOW_FIND_PROF_CHK_VSI	0x00000002
8362c61054cSTony Nguyen #define ICE_FLOW_FIND_PROF_NOT_CHK_DIR	0x00000004
8372c61054cSTony Nguyen 
8382c61054cSTony Nguyen /**
8392c61054cSTony Nguyen  * ice_flow_find_prof_conds - Find a profile matching headers and conditions
8402c61054cSTony Nguyen  * @hw: pointer to the HW struct
8412c61054cSTony Nguyen  * @blk: classification stage
8422c61054cSTony Nguyen  * @dir: flow direction
8432c61054cSTony Nguyen  * @segs: array of one or more packet segments that describe the flow
8442c61054cSTony Nguyen  * @segs_cnt: number of packet segments provided
8452c61054cSTony Nguyen  * @vsi_handle: software VSI handle to check VSI (ICE_FLOW_FIND_PROF_CHK_VSI)
8462c61054cSTony Nguyen  * @conds: additional conditions to be checked (ICE_FLOW_FIND_PROF_CHK_*)
8472c61054cSTony Nguyen  */
8482c61054cSTony Nguyen static struct ice_flow_prof *
8492c61054cSTony Nguyen ice_flow_find_prof_conds(struct ice_hw *hw, enum ice_block blk,
8502c61054cSTony Nguyen 			 enum ice_flow_dir dir, struct ice_flow_seg_info *segs,
8512c61054cSTony Nguyen 			 u8 segs_cnt, u16 vsi_handle, u32 conds)
8522c61054cSTony Nguyen {
8532c61054cSTony Nguyen 	struct ice_flow_prof *p, *prof = NULL;
8542c61054cSTony Nguyen 
8552c61054cSTony Nguyen 	mutex_lock(&hw->fl_profs_locks[blk]);
8562c61054cSTony Nguyen 	list_for_each_entry(p, &hw->fl_profs[blk], l_entry)
8572c61054cSTony Nguyen 		if ((p->dir == dir || conds & ICE_FLOW_FIND_PROF_NOT_CHK_DIR) &&
8582c61054cSTony Nguyen 		    segs_cnt && segs_cnt == p->segs_cnt) {
8592c61054cSTony Nguyen 			u8 i;
8602c61054cSTony Nguyen 
8612c61054cSTony Nguyen 			/* Check for profile-VSI association if specified */
8622c61054cSTony Nguyen 			if ((conds & ICE_FLOW_FIND_PROF_CHK_VSI) &&
8632c61054cSTony Nguyen 			    ice_is_vsi_valid(hw, vsi_handle) &&
8642c61054cSTony Nguyen 			    !test_bit(vsi_handle, p->vsis))
8652c61054cSTony Nguyen 				continue;
8662c61054cSTony Nguyen 
8672c61054cSTony Nguyen 			/* Protocol headers must be checked. Matched fields are
8682c61054cSTony Nguyen 			 * checked if specified.
8692c61054cSTony Nguyen 			 */
8702c61054cSTony Nguyen 			for (i = 0; i < segs_cnt; i++)
8712c61054cSTony Nguyen 				if (segs[i].hdrs != p->segs[i].hdrs ||
8722c61054cSTony Nguyen 				    ((conds & ICE_FLOW_FIND_PROF_CHK_FLDS) &&
8732c61054cSTony Nguyen 				     segs[i].match != p->segs[i].match))
8742c61054cSTony Nguyen 					break;
8752c61054cSTony Nguyen 
8762c61054cSTony Nguyen 			/* A match is found if all segments are matched */
8772c61054cSTony Nguyen 			if (i == segs_cnt) {
8782c61054cSTony Nguyen 				prof = p;
8792c61054cSTony Nguyen 				break;
8802c61054cSTony Nguyen 			}
8812c61054cSTony Nguyen 		}
8822c61054cSTony Nguyen 	mutex_unlock(&hw->fl_profs_locks[blk]);
8832c61054cSTony Nguyen 
8842c61054cSTony Nguyen 	return prof;
8852c61054cSTony Nguyen }
8862c61054cSTony Nguyen 
8872c61054cSTony Nguyen /**
8882c61054cSTony Nguyen  * ice_flow_find_prof_id - Look up a profile with given profile ID
8892c61054cSTony Nguyen  * @hw: pointer to the HW struct
8902c61054cSTony Nguyen  * @blk: classification stage
8912c61054cSTony Nguyen  * @prof_id: unique ID to identify this flow profile
8922c61054cSTony Nguyen  */
8932c61054cSTony Nguyen static struct ice_flow_prof *
8942c61054cSTony Nguyen ice_flow_find_prof_id(struct ice_hw *hw, enum ice_block blk, u64 prof_id)
8952c61054cSTony Nguyen {
8962c61054cSTony Nguyen 	struct ice_flow_prof *p;
8972c61054cSTony Nguyen 
8982c61054cSTony Nguyen 	list_for_each_entry(p, &hw->fl_profs[blk], l_entry)
8992c61054cSTony Nguyen 		if (p->id == prof_id)
9002c61054cSTony Nguyen 			return p;
9012c61054cSTony Nguyen 
9022c61054cSTony Nguyen 	return NULL;
9032c61054cSTony Nguyen }
9042c61054cSTony Nguyen 
90531ad4e4eSTony Nguyen /**
906148beb61SHenry Tieman  * ice_dealloc_flow_entry - Deallocate flow entry memory
907148beb61SHenry Tieman  * @hw: pointer to the HW struct
908148beb61SHenry Tieman  * @entry: flow entry to be removed
909148beb61SHenry Tieman  */
910148beb61SHenry Tieman static void
911148beb61SHenry Tieman ice_dealloc_flow_entry(struct ice_hw *hw, struct ice_flow_entry *entry)
912148beb61SHenry Tieman {
913148beb61SHenry Tieman 	if (!entry)
914148beb61SHenry Tieman 		return;
915148beb61SHenry Tieman 
916148beb61SHenry Tieman 	if (entry->entry)
917148beb61SHenry Tieman 		devm_kfree(ice_hw_to_dev(hw), entry->entry);
918148beb61SHenry Tieman 
919148beb61SHenry Tieman 	devm_kfree(ice_hw_to_dev(hw), entry);
920148beb61SHenry Tieman }
921148beb61SHenry Tieman 
922148beb61SHenry Tieman /**
923148beb61SHenry Tieman  * ice_flow_rem_entry_sync - Remove a flow entry
924148beb61SHenry Tieman  * @hw: pointer to the HW struct
925148beb61SHenry Tieman  * @blk: classification stage
926148beb61SHenry Tieman  * @entry: flow entry to be removed
927148beb61SHenry Tieman  */
928148beb61SHenry Tieman static enum ice_status
929148beb61SHenry Tieman ice_flow_rem_entry_sync(struct ice_hw *hw, enum ice_block __always_unused blk,
930148beb61SHenry Tieman 			struct ice_flow_entry *entry)
931148beb61SHenry Tieman {
932148beb61SHenry Tieman 	if (!entry)
933148beb61SHenry Tieman 		return ICE_ERR_BAD_PTR;
934148beb61SHenry Tieman 
935148beb61SHenry Tieman 	list_del(&entry->l_entry);
936148beb61SHenry Tieman 
937148beb61SHenry Tieman 	ice_dealloc_flow_entry(hw, entry);
938148beb61SHenry Tieman 
939148beb61SHenry Tieman 	return 0;
940148beb61SHenry Tieman }
941148beb61SHenry Tieman 
942148beb61SHenry Tieman /**
94331ad4e4eSTony Nguyen  * ice_flow_add_prof_sync - Add a flow profile for packet segments and fields
94431ad4e4eSTony Nguyen  * @hw: pointer to the HW struct
94531ad4e4eSTony Nguyen  * @blk: classification stage
94631ad4e4eSTony Nguyen  * @dir: flow direction
94731ad4e4eSTony Nguyen  * @prof_id: unique ID to identify this flow profile
94831ad4e4eSTony Nguyen  * @segs: array of one or more packet segments that describe the flow
94931ad4e4eSTony Nguyen  * @segs_cnt: number of packet segments provided
95031ad4e4eSTony Nguyen  * @prof: stores the returned flow profile added
95131ad4e4eSTony Nguyen  *
95231ad4e4eSTony Nguyen  * Assumption: the caller has acquired the lock to the profile list
95331ad4e4eSTony Nguyen  */
95431ad4e4eSTony Nguyen static enum ice_status
95531ad4e4eSTony Nguyen ice_flow_add_prof_sync(struct ice_hw *hw, enum ice_block blk,
95631ad4e4eSTony Nguyen 		       enum ice_flow_dir dir, u64 prof_id,
95731ad4e4eSTony Nguyen 		       struct ice_flow_seg_info *segs, u8 segs_cnt,
95831ad4e4eSTony Nguyen 		       struct ice_flow_prof **prof)
95931ad4e4eSTony Nguyen {
96088dcfdb4SBruce Allan 	struct ice_flow_prof_params *params;
96131ad4e4eSTony Nguyen 	enum ice_status status;
96231ad4e4eSTony Nguyen 	u8 i;
96331ad4e4eSTony Nguyen 
96431ad4e4eSTony Nguyen 	if (!prof)
96531ad4e4eSTony Nguyen 		return ICE_ERR_BAD_PTR;
96631ad4e4eSTony Nguyen 
96788dcfdb4SBruce Allan 	params = kzalloc(sizeof(*params), GFP_KERNEL);
96888dcfdb4SBruce Allan 	if (!params)
96931ad4e4eSTony Nguyen 		return ICE_ERR_NO_MEMORY;
97031ad4e4eSTony Nguyen 
97188dcfdb4SBruce Allan 	params->prof = devm_kzalloc(ice_hw_to_dev(hw), sizeof(*params->prof),
97288dcfdb4SBruce Allan 				    GFP_KERNEL);
97388dcfdb4SBruce Allan 	if (!params->prof) {
97488dcfdb4SBruce Allan 		status = ICE_ERR_NO_MEMORY;
97588dcfdb4SBruce Allan 		goto free_params;
97688dcfdb4SBruce Allan 	}
97788dcfdb4SBruce Allan 
97831ad4e4eSTony Nguyen 	/* initialize extraction sequence to all invalid (0xff) */
97931ad4e4eSTony Nguyen 	for (i = 0; i < ICE_MAX_FV_WORDS; i++) {
98088dcfdb4SBruce Allan 		params->es[i].prot_id = ICE_PROT_INVALID;
98188dcfdb4SBruce Allan 		params->es[i].off = ICE_FV_OFFSET_INVAL;
98231ad4e4eSTony Nguyen 	}
98331ad4e4eSTony Nguyen 
98488dcfdb4SBruce Allan 	params->blk = blk;
98588dcfdb4SBruce Allan 	params->prof->id = prof_id;
98688dcfdb4SBruce Allan 	params->prof->dir = dir;
98788dcfdb4SBruce Allan 	params->prof->segs_cnt = segs_cnt;
98831ad4e4eSTony Nguyen 
98931ad4e4eSTony Nguyen 	/* Make a copy of the segments that need to be persistent in the flow
99031ad4e4eSTony Nguyen 	 * profile instance
99131ad4e4eSTony Nguyen 	 */
99231ad4e4eSTony Nguyen 	for (i = 0; i < segs_cnt; i++)
99388dcfdb4SBruce Allan 		memcpy(&params->prof->segs[i], &segs[i], sizeof(*segs));
99431ad4e4eSTony Nguyen 
99588dcfdb4SBruce Allan 	status = ice_flow_proc_segs(hw, params);
99631ad4e4eSTony Nguyen 	if (status) {
9979228d8b2SJacob Keller 		ice_debug(hw, ICE_DBG_FLOW, "Error processing a flow's packet segments\n");
99831ad4e4eSTony Nguyen 		goto out;
99931ad4e4eSTony Nguyen 	}
100031ad4e4eSTony Nguyen 
100131ad4e4eSTony Nguyen 	/* Add a HW profile for this flow profile */
100288dcfdb4SBruce Allan 	status = ice_add_prof(hw, blk, prof_id, (u8 *)params->ptypes,
1003*b199dddbSQi Zhang 			      params->es, params->mask);
100431ad4e4eSTony Nguyen 	if (status) {
100531ad4e4eSTony Nguyen 		ice_debug(hw, ICE_DBG_FLOW, "Error adding a HW flow profile\n");
100631ad4e4eSTony Nguyen 		goto out;
100731ad4e4eSTony Nguyen 	}
100831ad4e4eSTony Nguyen 
100988dcfdb4SBruce Allan 	INIT_LIST_HEAD(&params->prof->entries);
101088dcfdb4SBruce Allan 	mutex_init(&params->prof->entries_lock);
101188dcfdb4SBruce Allan 	*prof = params->prof;
101231ad4e4eSTony Nguyen 
101331ad4e4eSTony Nguyen out:
101431ad4e4eSTony Nguyen 	if (status)
101588dcfdb4SBruce Allan 		devm_kfree(ice_hw_to_dev(hw), params->prof);
101688dcfdb4SBruce Allan free_params:
101788dcfdb4SBruce Allan 	kfree(params);
101831ad4e4eSTony Nguyen 
101931ad4e4eSTony Nguyen 	return status;
102031ad4e4eSTony Nguyen }
102131ad4e4eSTony Nguyen 
102231ad4e4eSTony Nguyen /**
10232c61054cSTony Nguyen  * ice_flow_rem_prof_sync - remove a flow profile
10242c61054cSTony Nguyen  * @hw: pointer to the hardware structure
10252c61054cSTony Nguyen  * @blk: classification stage
10262c61054cSTony Nguyen  * @prof: pointer to flow profile to remove
10272c61054cSTony Nguyen  *
10282c61054cSTony Nguyen  * Assumption: the caller has acquired the lock to the profile list
10292c61054cSTony Nguyen  */
10302c61054cSTony Nguyen static enum ice_status
10312c61054cSTony Nguyen ice_flow_rem_prof_sync(struct ice_hw *hw, enum ice_block blk,
10322c61054cSTony Nguyen 		       struct ice_flow_prof *prof)
10332c61054cSTony Nguyen {
10342c61054cSTony Nguyen 	enum ice_status status;
10352c61054cSTony Nguyen 
1036148beb61SHenry Tieman 	/* Remove all remaining flow entries before removing the flow profile */
1037148beb61SHenry Tieman 	if (!list_empty(&prof->entries)) {
1038148beb61SHenry Tieman 		struct ice_flow_entry *e, *t;
1039148beb61SHenry Tieman 
1040148beb61SHenry Tieman 		mutex_lock(&prof->entries_lock);
1041148beb61SHenry Tieman 
1042148beb61SHenry Tieman 		list_for_each_entry_safe(e, t, &prof->entries, l_entry) {
1043148beb61SHenry Tieman 			status = ice_flow_rem_entry_sync(hw, blk, e);
1044148beb61SHenry Tieman 			if (status)
1045148beb61SHenry Tieman 				break;
1046148beb61SHenry Tieman 		}
1047148beb61SHenry Tieman 
1048148beb61SHenry Tieman 		mutex_unlock(&prof->entries_lock);
1049148beb61SHenry Tieman 	}
1050148beb61SHenry Tieman 
10512c61054cSTony Nguyen 	/* Remove all hardware profiles associated with this flow profile */
10522c61054cSTony Nguyen 	status = ice_rem_prof(hw, blk, prof->id);
10532c61054cSTony Nguyen 	if (!status) {
10542c61054cSTony Nguyen 		list_del(&prof->l_entry);
10552c61054cSTony Nguyen 		mutex_destroy(&prof->entries_lock);
10562c61054cSTony Nguyen 		devm_kfree(ice_hw_to_dev(hw), prof);
10572c61054cSTony Nguyen 	}
10582c61054cSTony Nguyen 
10592c61054cSTony Nguyen 	return status;
10602c61054cSTony Nguyen }
10612c61054cSTony Nguyen 
10622c61054cSTony Nguyen /**
1063451f2c44STony Nguyen  * ice_flow_assoc_prof - associate a VSI with a flow profile
1064451f2c44STony Nguyen  * @hw: pointer to the hardware structure
1065451f2c44STony Nguyen  * @blk: classification stage
1066451f2c44STony Nguyen  * @prof: pointer to flow profile
1067451f2c44STony Nguyen  * @vsi_handle: software VSI handle
1068451f2c44STony Nguyen  *
1069451f2c44STony Nguyen  * Assumption: the caller has acquired the lock to the profile list
1070451f2c44STony Nguyen  * and the software VSI handle has been validated
1071451f2c44STony Nguyen  */
1072451f2c44STony Nguyen static enum ice_status
1073451f2c44STony Nguyen ice_flow_assoc_prof(struct ice_hw *hw, enum ice_block blk,
1074451f2c44STony Nguyen 		    struct ice_flow_prof *prof, u16 vsi_handle)
1075451f2c44STony Nguyen {
1076451f2c44STony Nguyen 	enum ice_status status = 0;
1077451f2c44STony Nguyen 
1078451f2c44STony Nguyen 	if (!test_bit(vsi_handle, prof->vsis)) {
1079451f2c44STony Nguyen 		status = ice_add_prof_id_flow(hw, blk,
1080451f2c44STony Nguyen 					      ice_get_hw_vsi_num(hw,
1081451f2c44STony Nguyen 								 vsi_handle),
1082451f2c44STony Nguyen 					      prof->id);
1083451f2c44STony Nguyen 		if (!status)
1084451f2c44STony Nguyen 			set_bit(vsi_handle, prof->vsis);
1085451f2c44STony Nguyen 		else
10869228d8b2SJacob Keller 			ice_debug(hw, ICE_DBG_FLOW, "HW profile add failed, %d\n",
1087451f2c44STony Nguyen 				  status);
1088451f2c44STony Nguyen 	}
1089451f2c44STony Nguyen 
1090451f2c44STony Nguyen 	return status;
1091451f2c44STony Nguyen }
1092451f2c44STony Nguyen 
1093451f2c44STony Nguyen /**
10942c61054cSTony Nguyen  * ice_flow_disassoc_prof - disassociate a VSI from a flow profile
10952c61054cSTony Nguyen  * @hw: pointer to the hardware structure
10962c61054cSTony Nguyen  * @blk: classification stage
10972c61054cSTony Nguyen  * @prof: pointer to flow profile
10982c61054cSTony Nguyen  * @vsi_handle: software VSI handle
10992c61054cSTony Nguyen  *
11002c61054cSTony Nguyen  * Assumption: the caller has acquired the lock to the profile list
11012c61054cSTony Nguyen  * and the software VSI handle has been validated
11022c61054cSTony Nguyen  */
11032c61054cSTony Nguyen static enum ice_status
11042c61054cSTony Nguyen ice_flow_disassoc_prof(struct ice_hw *hw, enum ice_block blk,
11052c61054cSTony Nguyen 		       struct ice_flow_prof *prof, u16 vsi_handle)
11062c61054cSTony Nguyen {
11072c61054cSTony Nguyen 	enum ice_status status = 0;
11082c61054cSTony Nguyen 
11092c61054cSTony Nguyen 	if (test_bit(vsi_handle, prof->vsis)) {
11102c61054cSTony Nguyen 		status = ice_rem_prof_id_flow(hw, blk,
11112c61054cSTony Nguyen 					      ice_get_hw_vsi_num(hw,
11122c61054cSTony Nguyen 								 vsi_handle),
11132c61054cSTony Nguyen 					      prof->id);
11142c61054cSTony Nguyen 		if (!status)
11152c61054cSTony Nguyen 			clear_bit(vsi_handle, prof->vsis);
11162c61054cSTony Nguyen 		else
11179228d8b2SJacob Keller 			ice_debug(hw, ICE_DBG_FLOW, "HW profile remove failed, %d\n",
11182c61054cSTony Nguyen 				  status);
11192c61054cSTony Nguyen 	}
11202c61054cSTony Nguyen 
11212c61054cSTony Nguyen 	return status;
11222c61054cSTony Nguyen }
11232c61054cSTony Nguyen 
11242c61054cSTony Nguyen /**
112531ad4e4eSTony Nguyen  * ice_flow_add_prof - Add a flow profile for packet segments and matched fields
112631ad4e4eSTony Nguyen  * @hw: pointer to the HW struct
112731ad4e4eSTony Nguyen  * @blk: classification stage
112831ad4e4eSTony Nguyen  * @dir: flow direction
112931ad4e4eSTony Nguyen  * @prof_id: unique ID to identify this flow profile
113031ad4e4eSTony Nguyen  * @segs: array of one or more packet segments that describe the flow
113131ad4e4eSTony Nguyen  * @segs_cnt: number of packet segments provided
1132451f2c44STony Nguyen  * @prof: stores the returned flow profile added
113331ad4e4eSTony Nguyen  */
1134148beb61SHenry Tieman enum ice_status
113531ad4e4eSTony Nguyen ice_flow_add_prof(struct ice_hw *hw, enum ice_block blk, enum ice_flow_dir dir,
1136451f2c44STony Nguyen 		  u64 prof_id, struct ice_flow_seg_info *segs, u8 segs_cnt,
1137451f2c44STony Nguyen 		  struct ice_flow_prof **prof)
113831ad4e4eSTony Nguyen {
113931ad4e4eSTony Nguyen 	enum ice_status status;
114031ad4e4eSTony Nguyen 
114131ad4e4eSTony Nguyen 	if (segs_cnt > ICE_FLOW_SEG_MAX)
114231ad4e4eSTony Nguyen 		return ICE_ERR_MAX_LIMIT;
114331ad4e4eSTony Nguyen 
114431ad4e4eSTony Nguyen 	if (!segs_cnt)
114531ad4e4eSTony Nguyen 		return ICE_ERR_PARAM;
114631ad4e4eSTony Nguyen 
114731ad4e4eSTony Nguyen 	if (!segs)
114831ad4e4eSTony Nguyen 		return ICE_ERR_BAD_PTR;
114931ad4e4eSTony Nguyen 
115031ad4e4eSTony Nguyen 	status = ice_flow_val_hdrs(segs, segs_cnt);
115131ad4e4eSTony Nguyen 	if (status)
115231ad4e4eSTony Nguyen 		return status;
115331ad4e4eSTony Nguyen 
115431ad4e4eSTony Nguyen 	mutex_lock(&hw->fl_profs_locks[blk]);
115531ad4e4eSTony Nguyen 
115631ad4e4eSTony Nguyen 	status = ice_flow_add_prof_sync(hw, blk, dir, prof_id, segs, segs_cnt,
1157451f2c44STony Nguyen 					prof);
115831ad4e4eSTony Nguyen 	if (!status)
1159451f2c44STony Nguyen 		list_add(&(*prof)->l_entry, &hw->fl_profs[blk]);
116031ad4e4eSTony Nguyen 
116131ad4e4eSTony Nguyen 	mutex_unlock(&hw->fl_profs_locks[blk]);
116231ad4e4eSTony Nguyen 
116331ad4e4eSTony Nguyen 	return status;
116431ad4e4eSTony Nguyen }
116531ad4e4eSTony Nguyen 
1166c90ed40cSTony Nguyen /**
11672c61054cSTony Nguyen  * ice_flow_rem_prof - Remove a flow profile and all entries associated with it
11682c61054cSTony Nguyen  * @hw: pointer to the HW struct
11692c61054cSTony Nguyen  * @blk: the block for which the flow profile is to be removed
11702c61054cSTony Nguyen  * @prof_id: unique ID of the flow profile to be removed
11712c61054cSTony Nguyen  */
1172148beb61SHenry Tieman enum ice_status
11732c61054cSTony Nguyen ice_flow_rem_prof(struct ice_hw *hw, enum ice_block blk, u64 prof_id)
11742c61054cSTony Nguyen {
11752c61054cSTony Nguyen 	struct ice_flow_prof *prof;
11762c61054cSTony Nguyen 	enum ice_status status;
11772c61054cSTony Nguyen 
11782c61054cSTony Nguyen 	mutex_lock(&hw->fl_profs_locks[blk]);
11792c61054cSTony Nguyen 
11802c61054cSTony Nguyen 	prof = ice_flow_find_prof_id(hw, blk, prof_id);
11812c61054cSTony Nguyen 	if (!prof) {
11822c61054cSTony Nguyen 		status = ICE_ERR_DOES_NOT_EXIST;
11832c61054cSTony Nguyen 		goto out;
11842c61054cSTony Nguyen 	}
11852c61054cSTony Nguyen 
11862c61054cSTony Nguyen 	/* prof becomes invalid after the call */
11872c61054cSTony Nguyen 	status = ice_flow_rem_prof_sync(hw, blk, prof);
11882c61054cSTony Nguyen 
11892c61054cSTony Nguyen out:
11902c61054cSTony Nguyen 	mutex_unlock(&hw->fl_profs_locks[blk]);
11912c61054cSTony Nguyen 
11922c61054cSTony Nguyen 	return status;
11932c61054cSTony Nguyen }
11942c61054cSTony Nguyen 
11952c61054cSTony Nguyen /**
1196148beb61SHenry Tieman  * ice_flow_add_entry - Add a flow entry
1197148beb61SHenry Tieman  * @hw: pointer to the HW struct
1198148beb61SHenry Tieman  * @blk: classification stage
1199148beb61SHenry Tieman  * @prof_id: ID of the profile to add a new flow entry to
1200148beb61SHenry Tieman  * @entry_id: unique ID to identify this flow entry
1201148beb61SHenry Tieman  * @vsi_handle: software VSI handle for the flow entry
1202148beb61SHenry Tieman  * @prio: priority of the flow entry
1203148beb61SHenry Tieman  * @data: pointer to a data buffer containing flow entry's match values/masks
1204148beb61SHenry Tieman  * @entry_h: pointer to buffer that receives the new flow entry's handle
1205148beb61SHenry Tieman  */
1206148beb61SHenry Tieman enum ice_status
1207148beb61SHenry Tieman ice_flow_add_entry(struct ice_hw *hw, enum ice_block blk, u64 prof_id,
1208148beb61SHenry Tieman 		   u64 entry_id, u16 vsi_handle, enum ice_flow_priority prio,
1209148beb61SHenry Tieman 		   void *data, u64 *entry_h)
1210148beb61SHenry Tieman {
1211148beb61SHenry Tieman 	struct ice_flow_entry *e = NULL;
1212148beb61SHenry Tieman 	struct ice_flow_prof *prof;
1213148beb61SHenry Tieman 	enum ice_status status;
1214148beb61SHenry Tieman 
1215148beb61SHenry Tieman 	/* No flow entry data is expected for RSS */
1216148beb61SHenry Tieman 	if (!entry_h || (!data && blk != ICE_BLK_RSS))
1217148beb61SHenry Tieman 		return ICE_ERR_BAD_PTR;
1218148beb61SHenry Tieman 
1219148beb61SHenry Tieman 	if (!ice_is_vsi_valid(hw, vsi_handle))
1220148beb61SHenry Tieman 		return ICE_ERR_PARAM;
1221148beb61SHenry Tieman 
1222148beb61SHenry Tieman 	mutex_lock(&hw->fl_profs_locks[blk]);
1223148beb61SHenry Tieman 
1224148beb61SHenry Tieman 	prof = ice_flow_find_prof_id(hw, blk, prof_id);
1225148beb61SHenry Tieman 	if (!prof) {
1226148beb61SHenry Tieman 		status = ICE_ERR_DOES_NOT_EXIST;
1227148beb61SHenry Tieman 	} else {
1228148beb61SHenry Tieman 		/* Allocate memory for the entry being added and associate
1229148beb61SHenry Tieman 		 * the VSI to the found flow profile
1230148beb61SHenry Tieman 		 */
1231148beb61SHenry Tieman 		e = devm_kzalloc(ice_hw_to_dev(hw), sizeof(*e), GFP_KERNEL);
1232148beb61SHenry Tieman 		if (!e)
1233148beb61SHenry Tieman 			status = ICE_ERR_NO_MEMORY;
1234148beb61SHenry Tieman 		else
1235148beb61SHenry Tieman 			status = ice_flow_assoc_prof(hw, blk, prof, vsi_handle);
1236148beb61SHenry Tieman 	}
1237148beb61SHenry Tieman 
1238148beb61SHenry Tieman 	mutex_unlock(&hw->fl_profs_locks[blk]);
1239148beb61SHenry Tieman 	if (status)
1240148beb61SHenry Tieman 		goto out;
1241148beb61SHenry Tieman 
1242148beb61SHenry Tieman 	e->id = entry_id;
1243148beb61SHenry Tieman 	e->vsi_handle = vsi_handle;
1244148beb61SHenry Tieman 	e->prof = prof;
1245148beb61SHenry Tieman 	e->priority = prio;
1246148beb61SHenry Tieman 
1247148beb61SHenry Tieman 	switch (blk) {
1248148beb61SHenry Tieman 	case ICE_BLK_FD:
1249148beb61SHenry Tieman 	case ICE_BLK_RSS:
1250148beb61SHenry Tieman 		break;
1251148beb61SHenry Tieman 	default:
1252148beb61SHenry Tieman 		status = ICE_ERR_NOT_IMPL;
1253148beb61SHenry Tieman 		goto out;
1254148beb61SHenry Tieman 	}
1255148beb61SHenry Tieman 
1256148beb61SHenry Tieman 	mutex_lock(&prof->entries_lock);
1257148beb61SHenry Tieman 	list_add(&e->l_entry, &prof->entries);
1258148beb61SHenry Tieman 	mutex_unlock(&prof->entries_lock);
1259148beb61SHenry Tieman 
1260148beb61SHenry Tieman 	*entry_h = ICE_FLOW_ENTRY_HNDL(e);
1261148beb61SHenry Tieman 
1262148beb61SHenry Tieman out:
1263148beb61SHenry Tieman 	if (status && e) {
1264148beb61SHenry Tieman 		if (e->entry)
1265148beb61SHenry Tieman 			devm_kfree(ice_hw_to_dev(hw), e->entry);
1266148beb61SHenry Tieman 		devm_kfree(ice_hw_to_dev(hw), e);
1267148beb61SHenry Tieman 	}
1268148beb61SHenry Tieman 
1269148beb61SHenry Tieman 	return status;
1270148beb61SHenry Tieman }
1271148beb61SHenry Tieman 
1272148beb61SHenry Tieman /**
1273148beb61SHenry Tieman  * ice_flow_rem_entry - Remove a flow entry
1274148beb61SHenry Tieman  * @hw: pointer to the HW struct
1275148beb61SHenry Tieman  * @blk: classification stage
1276148beb61SHenry Tieman  * @entry_h: handle to the flow entry to be removed
1277148beb61SHenry Tieman  */
1278148beb61SHenry Tieman enum ice_status ice_flow_rem_entry(struct ice_hw *hw, enum ice_block blk,
1279148beb61SHenry Tieman 				   u64 entry_h)
1280148beb61SHenry Tieman {
1281148beb61SHenry Tieman 	struct ice_flow_entry *entry;
1282148beb61SHenry Tieman 	struct ice_flow_prof *prof;
1283148beb61SHenry Tieman 	enum ice_status status = 0;
1284148beb61SHenry Tieman 
1285148beb61SHenry Tieman 	if (entry_h == ICE_FLOW_ENTRY_HANDLE_INVAL)
1286148beb61SHenry Tieman 		return ICE_ERR_PARAM;
1287148beb61SHenry Tieman 
1288148beb61SHenry Tieman 	entry = ICE_FLOW_ENTRY_PTR(entry_h);
1289148beb61SHenry Tieman 
1290148beb61SHenry Tieman 	/* Retain the pointer to the flow profile as the entry will be freed */
1291148beb61SHenry Tieman 	prof = entry->prof;
1292148beb61SHenry Tieman 
1293148beb61SHenry Tieman 	if (prof) {
1294148beb61SHenry Tieman 		mutex_lock(&prof->entries_lock);
1295148beb61SHenry Tieman 		status = ice_flow_rem_entry_sync(hw, blk, entry);
1296148beb61SHenry Tieman 		mutex_unlock(&prof->entries_lock);
1297148beb61SHenry Tieman 	}
1298148beb61SHenry Tieman 
1299148beb61SHenry Tieman 	return status;
1300148beb61SHenry Tieman }
1301148beb61SHenry Tieman 
1302148beb61SHenry Tieman /**
1303c90ed40cSTony Nguyen  * ice_flow_set_fld_ext - specifies locations of field from entry's input buffer
1304c90ed40cSTony Nguyen  * @seg: packet segment the field being set belongs to
1305c90ed40cSTony Nguyen  * @fld: field to be set
13066dae8aa0SBruce Allan  * @field_type: type of the field
1307c90ed40cSTony Nguyen  * @val_loc: if not ICE_FLOW_FLD_OFF_INVAL, location of the value to match from
1308c90ed40cSTony Nguyen  *           entry's input buffer
1309c90ed40cSTony Nguyen  * @mask_loc: if not ICE_FLOW_FLD_OFF_INVAL, location of mask value from entry's
1310c90ed40cSTony Nguyen  *            input buffer
1311c90ed40cSTony Nguyen  * @last_loc: if not ICE_FLOW_FLD_OFF_INVAL, location of last/upper value from
1312c90ed40cSTony Nguyen  *            entry's input buffer
1313c90ed40cSTony Nguyen  *
1314c90ed40cSTony Nguyen  * This helper function stores information of a field being matched, including
1315c90ed40cSTony Nguyen  * the type of the field and the locations of the value to match, the mask, and
1316ac382a09SBruce Allan  * the upper-bound value in the start of the input buffer for a flow entry.
1317c90ed40cSTony Nguyen  * This function should only be used for fixed-size data structures.
1318c90ed40cSTony Nguyen  *
1319c90ed40cSTony Nguyen  * This function also opportunistically determines the protocol headers to be
1320c90ed40cSTony Nguyen  * present based on the fields being set. Some fields cannot be used alone to
1321c90ed40cSTony Nguyen  * determine the protocol headers present. Sometimes, fields for particular
1322c90ed40cSTony Nguyen  * protocol headers are not matched. In those cases, the protocol headers
1323c90ed40cSTony Nguyen  * must be explicitly set.
1324c90ed40cSTony Nguyen  */
1325c90ed40cSTony Nguyen static void
1326c90ed40cSTony Nguyen ice_flow_set_fld_ext(struct ice_flow_seg_info *seg, enum ice_flow_field fld,
13276dae8aa0SBruce Allan 		     enum ice_flow_fld_match_type field_type, u16 val_loc,
1328c90ed40cSTony Nguyen 		     u16 mask_loc, u16 last_loc)
1329c90ed40cSTony Nguyen {
1330c90ed40cSTony Nguyen 	u64 bit = BIT_ULL(fld);
1331c90ed40cSTony Nguyen 
1332c90ed40cSTony Nguyen 	seg->match |= bit;
13336dae8aa0SBruce Allan 	if (field_type == ICE_FLOW_FLD_TYPE_RANGE)
1334c90ed40cSTony Nguyen 		seg->range |= bit;
1335c90ed40cSTony Nguyen 
13366dae8aa0SBruce Allan 	seg->fields[fld].type = field_type;
1337c90ed40cSTony Nguyen 	seg->fields[fld].src.val = val_loc;
1338c90ed40cSTony Nguyen 	seg->fields[fld].src.mask = mask_loc;
1339c90ed40cSTony Nguyen 	seg->fields[fld].src.last = last_loc;
1340c90ed40cSTony Nguyen 
1341c90ed40cSTony Nguyen 	ICE_FLOW_SET_HDRS(seg, ice_flds_info[fld].hdr);
1342c90ed40cSTony Nguyen }
1343c90ed40cSTony Nguyen 
1344c90ed40cSTony Nguyen /**
1345c90ed40cSTony Nguyen  * ice_flow_set_fld - specifies locations of field from entry's input buffer
1346c90ed40cSTony Nguyen  * @seg: packet segment the field being set belongs to
1347c90ed40cSTony Nguyen  * @fld: field to be set
1348c90ed40cSTony Nguyen  * @val_loc: if not ICE_FLOW_FLD_OFF_INVAL, location of the value to match from
1349c90ed40cSTony Nguyen  *           entry's input buffer
1350c90ed40cSTony Nguyen  * @mask_loc: if not ICE_FLOW_FLD_OFF_INVAL, location of mask value from entry's
1351c90ed40cSTony Nguyen  *            input buffer
1352c90ed40cSTony Nguyen  * @last_loc: if not ICE_FLOW_FLD_OFF_INVAL, location of last/upper value from
1353c90ed40cSTony Nguyen  *            entry's input buffer
1354c90ed40cSTony Nguyen  * @range: indicate if field being matched is to be in a range
1355c90ed40cSTony Nguyen  *
1356c90ed40cSTony Nguyen  * This function specifies the locations, in the form of byte offsets from the
1357c90ed40cSTony Nguyen  * start of the input buffer for a flow entry, from where the value to match,
1358c90ed40cSTony Nguyen  * the mask value, and upper value can be extracted. These locations are then
1359c90ed40cSTony Nguyen  * stored in the flow profile. When adding a flow entry associated with the
1360c90ed40cSTony Nguyen  * flow profile, these locations will be used to quickly extract the values and
1361c90ed40cSTony Nguyen  * create the content of a match entry. This function should only be used for
1362c90ed40cSTony Nguyen  * fixed-size data structures.
1363c90ed40cSTony Nguyen  */
1364148beb61SHenry Tieman void
1365c90ed40cSTony Nguyen ice_flow_set_fld(struct ice_flow_seg_info *seg, enum ice_flow_field fld,
1366c90ed40cSTony Nguyen 		 u16 val_loc, u16 mask_loc, u16 last_loc, bool range)
1367c90ed40cSTony Nguyen {
1368c90ed40cSTony Nguyen 	enum ice_flow_fld_match_type t = range ?
1369c90ed40cSTony Nguyen 		ICE_FLOW_FLD_TYPE_RANGE : ICE_FLOW_FLD_TYPE_REG;
1370c90ed40cSTony Nguyen 
1371c90ed40cSTony Nguyen 	ice_flow_set_fld_ext(seg, fld, t, val_loc, mask_loc, last_loc);
1372c90ed40cSTony Nguyen }
1373c90ed40cSTony Nguyen 
13742c57ffcbSHenry Tieman /**
13752c57ffcbSHenry Tieman  * ice_flow_add_fld_raw - sets locations of a raw field from entry's input buf
13762c57ffcbSHenry Tieman  * @seg: packet segment the field being set belongs to
13772c57ffcbSHenry Tieman  * @off: offset of the raw field from the beginning of the segment in bytes
13782c57ffcbSHenry Tieman  * @len: length of the raw pattern to be matched
13792c57ffcbSHenry Tieman  * @val_loc: location of the value to match from entry's input buffer
13802c57ffcbSHenry Tieman  * @mask_loc: location of mask value from entry's input buffer
13812c57ffcbSHenry Tieman  *
13822c57ffcbSHenry Tieman  * This function specifies the offset of the raw field to be match from the
13832c57ffcbSHenry Tieman  * beginning of the specified packet segment, and the locations, in the form of
13842c57ffcbSHenry Tieman  * byte offsets from the start of the input buffer for a flow entry, from where
13852c57ffcbSHenry Tieman  * the value to match and the mask value to be extracted. These locations are
13862c57ffcbSHenry Tieman  * then stored in the flow profile. When adding flow entries to the associated
13872c57ffcbSHenry Tieman  * flow profile, these locations can be used to quickly extract the values to
13882c57ffcbSHenry Tieman  * create the content of a match entry. This function should only be used for
13892c57ffcbSHenry Tieman  * fixed-size data structures.
13902c57ffcbSHenry Tieman  */
13912c57ffcbSHenry Tieman void
13922c57ffcbSHenry Tieman ice_flow_add_fld_raw(struct ice_flow_seg_info *seg, u16 off, u8 len,
13932c57ffcbSHenry Tieman 		     u16 val_loc, u16 mask_loc)
13942c57ffcbSHenry Tieman {
13952c57ffcbSHenry Tieman 	if (seg->raws_cnt < ICE_FLOW_SEG_RAW_FLD_MAX) {
13962c57ffcbSHenry Tieman 		seg->raws[seg->raws_cnt].off = off;
13972c57ffcbSHenry Tieman 		seg->raws[seg->raws_cnt].info.type = ICE_FLOW_FLD_TYPE_SIZE;
13982c57ffcbSHenry Tieman 		seg->raws[seg->raws_cnt].info.src.val = val_loc;
13992c57ffcbSHenry Tieman 		seg->raws[seg->raws_cnt].info.src.mask = mask_loc;
14002c57ffcbSHenry Tieman 		/* The "last" field is used to store the length of the field */
14012c57ffcbSHenry Tieman 		seg->raws[seg->raws_cnt].info.src.last = len;
14022c57ffcbSHenry Tieman 	}
14032c57ffcbSHenry Tieman 
14042c57ffcbSHenry Tieman 	/* Overflows of "raws" will be handled as an error condition later in
14052c57ffcbSHenry Tieman 	 * the flow when this information is processed.
14062c57ffcbSHenry Tieman 	 */
14072c57ffcbSHenry Tieman 	seg->raws_cnt++;
14082c57ffcbSHenry Tieman }
14092c57ffcbSHenry Tieman 
1410390bd141SQi Zhang #define ICE_FLOW_RSS_SEG_HDR_L2_MASKS \
1411390bd141SQi Zhang 	(ICE_FLOW_SEG_HDR_ETH | ICE_FLOW_SEG_HDR_VLAN)
1412390bd141SQi Zhang 
1413c90ed40cSTony Nguyen #define ICE_FLOW_RSS_SEG_HDR_L3_MASKS \
1414c90ed40cSTony Nguyen 	(ICE_FLOW_SEG_HDR_IPV4 | ICE_FLOW_SEG_HDR_IPV6)
1415c90ed40cSTony Nguyen 
1416c90ed40cSTony Nguyen #define ICE_FLOW_RSS_SEG_HDR_L4_MASKS \
1417c90ed40cSTony Nguyen 	(ICE_FLOW_SEG_HDR_TCP | ICE_FLOW_SEG_HDR_UDP | ICE_FLOW_SEG_HDR_SCTP)
1418c90ed40cSTony Nguyen 
1419c90ed40cSTony Nguyen #define ICE_FLOW_RSS_SEG_HDR_VAL_MASKS \
1420390bd141SQi Zhang 	(ICE_FLOW_RSS_SEG_HDR_L2_MASKS | \
1421390bd141SQi Zhang 	 ICE_FLOW_RSS_SEG_HDR_L3_MASKS | \
1422c90ed40cSTony Nguyen 	 ICE_FLOW_RSS_SEG_HDR_L4_MASKS)
1423c90ed40cSTony Nguyen 
1424c90ed40cSTony Nguyen /**
1425c90ed40cSTony Nguyen  * ice_flow_set_rss_seg_info - setup packet segments for RSS
1426c90ed40cSTony Nguyen  * @segs: pointer to the flow field segment(s)
1427c90ed40cSTony Nguyen  * @hash_fields: fields to be hashed on for the segment(s)
1428c90ed40cSTony Nguyen  * @flow_hdr: protocol header fields within a packet segment
1429c90ed40cSTony Nguyen  *
1430c90ed40cSTony Nguyen  * Helper function to extract fields from hash bitmap and use flow
1431c90ed40cSTony Nguyen  * header value to set flow field segment for further use in flow
1432c90ed40cSTony Nguyen  * profile entry or removal.
1433c90ed40cSTony Nguyen  */
1434c90ed40cSTony Nguyen static enum ice_status
1435c90ed40cSTony Nguyen ice_flow_set_rss_seg_info(struct ice_flow_seg_info *segs, u64 hash_fields,
1436c90ed40cSTony Nguyen 			  u32 flow_hdr)
1437c90ed40cSTony Nguyen {
1438c90ed40cSTony Nguyen 	u64 val;
1439c90ed40cSTony Nguyen 	u8 i;
1440c90ed40cSTony Nguyen 
1441c90ed40cSTony Nguyen 	for_each_set_bit(i, (unsigned long *)&hash_fields,
1442c90ed40cSTony Nguyen 			 ICE_FLOW_FIELD_IDX_MAX)
1443c90ed40cSTony Nguyen 		ice_flow_set_fld(segs, (enum ice_flow_field)i,
1444c90ed40cSTony Nguyen 				 ICE_FLOW_FLD_OFF_INVAL, ICE_FLOW_FLD_OFF_INVAL,
1445c90ed40cSTony Nguyen 				 ICE_FLOW_FLD_OFF_INVAL, false);
1446c90ed40cSTony Nguyen 
1447c90ed40cSTony Nguyen 	ICE_FLOW_SET_HDRS(segs, flow_hdr);
1448c90ed40cSTony Nguyen 
1449c90ed40cSTony Nguyen 	if (segs->hdrs & ~ICE_FLOW_RSS_SEG_HDR_VAL_MASKS)
1450c90ed40cSTony Nguyen 		return ICE_ERR_PARAM;
1451c90ed40cSTony Nguyen 
1452c90ed40cSTony Nguyen 	val = (u64)(segs->hdrs & ICE_FLOW_RSS_SEG_HDR_L3_MASKS);
1453c90ed40cSTony Nguyen 	if (val && !is_power_of_2(val))
1454c90ed40cSTony Nguyen 		return ICE_ERR_CFG;
1455c90ed40cSTony Nguyen 
1456c90ed40cSTony Nguyen 	val = (u64)(segs->hdrs & ICE_FLOW_RSS_SEG_HDR_L4_MASKS);
1457c90ed40cSTony Nguyen 	if (val && !is_power_of_2(val))
1458c90ed40cSTony Nguyen 		return ICE_ERR_CFG;
1459c90ed40cSTony Nguyen 
1460c90ed40cSTony Nguyen 	return 0;
1461c90ed40cSTony Nguyen }
1462c90ed40cSTony Nguyen 
14632c61054cSTony Nguyen /**
14642c61054cSTony Nguyen  * ice_rem_vsi_rss_list - remove VSI from RSS list
14652c61054cSTony Nguyen  * @hw: pointer to the hardware structure
14662c61054cSTony Nguyen  * @vsi_handle: software VSI handle
14672c61054cSTony Nguyen  *
14682c61054cSTony Nguyen  * Remove the VSI from all RSS configurations in the list.
14692c61054cSTony Nguyen  */
14702c61054cSTony Nguyen void ice_rem_vsi_rss_list(struct ice_hw *hw, u16 vsi_handle)
14712c61054cSTony Nguyen {
14722c61054cSTony Nguyen 	struct ice_rss_cfg *r, *tmp;
14732c61054cSTony Nguyen 
14742c61054cSTony Nguyen 	if (list_empty(&hw->rss_list_head))
14752c61054cSTony Nguyen 		return;
14762c61054cSTony Nguyen 
14772c61054cSTony Nguyen 	mutex_lock(&hw->rss_locks);
14782c61054cSTony Nguyen 	list_for_each_entry_safe(r, tmp, &hw->rss_list_head, l_entry)
14792c61054cSTony Nguyen 		if (test_and_clear_bit(vsi_handle, r->vsis))
14802c61054cSTony Nguyen 			if (bitmap_empty(r->vsis, ICE_MAX_VSI)) {
14812c61054cSTony Nguyen 				list_del(&r->l_entry);
14822c61054cSTony Nguyen 				devm_kfree(ice_hw_to_dev(hw), r);
14832c61054cSTony Nguyen 			}
14842c61054cSTony Nguyen 	mutex_unlock(&hw->rss_locks);
14852c61054cSTony Nguyen }
14862c61054cSTony Nguyen 
14872c61054cSTony Nguyen /**
14882c61054cSTony Nguyen  * ice_rem_vsi_rss_cfg - remove RSS configurations associated with VSI
14892c61054cSTony Nguyen  * @hw: pointer to the hardware structure
14902c61054cSTony Nguyen  * @vsi_handle: software VSI handle
14912c61054cSTony Nguyen  *
14922c61054cSTony Nguyen  * This function will iterate through all flow profiles and disassociate
14932c61054cSTony Nguyen  * the VSI from that profile. If the flow profile has no VSIs it will
14942c61054cSTony Nguyen  * be removed.
14952c61054cSTony Nguyen  */
14962c61054cSTony Nguyen enum ice_status ice_rem_vsi_rss_cfg(struct ice_hw *hw, u16 vsi_handle)
14972c61054cSTony Nguyen {
14982c61054cSTony Nguyen 	const enum ice_block blk = ICE_BLK_RSS;
14992c61054cSTony Nguyen 	struct ice_flow_prof *p, *t;
15002c61054cSTony Nguyen 	enum ice_status status = 0;
15012c61054cSTony Nguyen 
15022c61054cSTony Nguyen 	if (!ice_is_vsi_valid(hw, vsi_handle))
15032c61054cSTony Nguyen 		return ICE_ERR_PARAM;
15042c61054cSTony Nguyen 
15052c61054cSTony Nguyen 	if (list_empty(&hw->fl_profs[blk]))
15062c61054cSTony Nguyen 		return 0;
15072c61054cSTony Nguyen 
1508cdedbab9SVignesh Sridhar 	mutex_lock(&hw->rss_locks);
15092c61054cSTony Nguyen 	list_for_each_entry_safe(p, t, &hw->fl_profs[blk], l_entry)
15102c61054cSTony Nguyen 		if (test_bit(vsi_handle, p->vsis)) {
15112c61054cSTony Nguyen 			status = ice_flow_disassoc_prof(hw, blk, p, vsi_handle);
15122c61054cSTony Nguyen 			if (status)
15132c61054cSTony Nguyen 				break;
15142c61054cSTony Nguyen 
15152c61054cSTony Nguyen 			if (bitmap_empty(p->vsis, ICE_MAX_VSI)) {
1516cdedbab9SVignesh Sridhar 				status = ice_flow_rem_prof(hw, blk, p->id);
15172c61054cSTony Nguyen 				if (status)
15182c61054cSTony Nguyen 					break;
15192c61054cSTony Nguyen 			}
15202c61054cSTony Nguyen 		}
1521cdedbab9SVignesh Sridhar 	mutex_unlock(&hw->rss_locks);
15222c61054cSTony Nguyen 
15232c61054cSTony Nguyen 	return status;
15242c61054cSTony Nguyen }
15252c61054cSTony Nguyen 
15262c61054cSTony Nguyen /**
15272c61054cSTony Nguyen  * ice_rem_rss_list - remove RSS configuration from list
15282c61054cSTony Nguyen  * @hw: pointer to the hardware structure
15292c61054cSTony Nguyen  * @vsi_handle: software VSI handle
15302c61054cSTony Nguyen  * @prof: pointer to flow profile
15312c61054cSTony Nguyen  *
15322c61054cSTony Nguyen  * Assumption: lock has already been acquired for RSS list
15332c61054cSTony Nguyen  */
15342c61054cSTony Nguyen static void
15352c61054cSTony Nguyen ice_rem_rss_list(struct ice_hw *hw, u16 vsi_handle, struct ice_flow_prof *prof)
15362c61054cSTony Nguyen {
15372c61054cSTony Nguyen 	struct ice_rss_cfg *r, *tmp;
15382c61054cSTony Nguyen 
15392c61054cSTony Nguyen 	/* Search for RSS hash fields associated to the VSI that match the
15402c61054cSTony Nguyen 	 * hash configurations associated to the flow profile. If found
15412c61054cSTony Nguyen 	 * remove from the RSS entry list of the VSI context and delete entry.
15422c61054cSTony Nguyen 	 */
15432c61054cSTony Nguyen 	list_for_each_entry_safe(r, tmp, &hw->rss_list_head, l_entry)
15442c61054cSTony Nguyen 		if (r->hashed_flds == prof->segs[prof->segs_cnt - 1].match &&
15452c61054cSTony Nguyen 		    r->packet_hdr == prof->segs[prof->segs_cnt - 1].hdrs) {
15462c61054cSTony Nguyen 			clear_bit(vsi_handle, r->vsis);
15472c61054cSTony Nguyen 			if (bitmap_empty(r->vsis, ICE_MAX_VSI)) {
15482c61054cSTony Nguyen 				list_del(&r->l_entry);
15492c61054cSTony Nguyen 				devm_kfree(ice_hw_to_dev(hw), r);
15502c61054cSTony Nguyen 			}
15512c61054cSTony Nguyen 			return;
15522c61054cSTony Nguyen 		}
15532c61054cSTony Nguyen }
15542c61054cSTony Nguyen 
15552c61054cSTony Nguyen /**
15562c61054cSTony Nguyen  * ice_add_rss_list - add RSS configuration to list
15572c61054cSTony Nguyen  * @hw: pointer to the hardware structure
15582c61054cSTony Nguyen  * @vsi_handle: software VSI handle
15592c61054cSTony Nguyen  * @prof: pointer to flow profile
15602c61054cSTony Nguyen  *
15612c61054cSTony Nguyen  * Assumption: lock has already been acquired for RSS list
15622c61054cSTony Nguyen  */
15632c61054cSTony Nguyen static enum ice_status
15642c61054cSTony Nguyen ice_add_rss_list(struct ice_hw *hw, u16 vsi_handle, struct ice_flow_prof *prof)
15652c61054cSTony Nguyen {
15662c61054cSTony Nguyen 	struct ice_rss_cfg *r, *rss_cfg;
15672c61054cSTony Nguyen 
15682c61054cSTony Nguyen 	list_for_each_entry(r, &hw->rss_list_head, l_entry)
15692c61054cSTony Nguyen 		if (r->hashed_flds == prof->segs[prof->segs_cnt - 1].match &&
15702c61054cSTony Nguyen 		    r->packet_hdr == prof->segs[prof->segs_cnt - 1].hdrs) {
15712c61054cSTony Nguyen 			set_bit(vsi_handle, r->vsis);
15722c61054cSTony Nguyen 			return 0;
15732c61054cSTony Nguyen 		}
15742c61054cSTony Nguyen 
15752c61054cSTony Nguyen 	rss_cfg = devm_kzalloc(ice_hw_to_dev(hw), sizeof(*rss_cfg),
15762c61054cSTony Nguyen 			       GFP_KERNEL);
15772c61054cSTony Nguyen 	if (!rss_cfg)
15782c61054cSTony Nguyen 		return ICE_ERR_NO_MEMORY;
15792c61054cSTony Nguyen 
15802c61054cSTony Nguyen 	rss_cfg->hashed_flds = prof->segs[prof->segs_cnt - 1].match;
15812c61054cSTony Nguyen 	rss_cfg->packet_hdr = prof->segs[prof->segs_cnt - 1].hdrs;
15822c61054cSTony Nguyen 	set_bit(vsi_handle, rss_cfg->vsis);
15832c61054cSTony Nguyen 
15842c61054cSTony Nguyen 	list_add_tail(&rss_cfg->l_entry, &hw->rss_list_head);
15852c61054cSTony Nguyen 
15862c61054cSTony Nguyen 	return 0;
15872c61054cSTony Nguyen }
15882c61054cSTony Nguyen 
158931ad4e4eSTony Nguyen #define ICE_FLOW_PROF_HASH_S	0
159031ad4e4eSTony Nguyen #define ICE_FLOW_PROF_HASH_M	(0xFFFFFFFFULL << ICE_FLOW_PROF_HASH_S)
159131ad4e4eSTony Nguyen #define ICE_FLOW_PROF_HDR_S	32
159231ad4e4eSTony Nguyen #define ICE_FLOW_PROF_HDR_M	(0x3FFFFFFFULL << ICE_FLOW_PROF_HDR_S)
159331ad4e4eSTony Nguyen #define ICE_FLOW_PROF_ENCAP_S	63
159431ad4e4eSTony Nguyen #define ICE_FLOW_PROF_ENCAP_M	(BIT_ULL(ICE_FLOW_PROF_ENCAP_S))
159531ad4e4eSTony Nguyen 
1596c90ed40cSTony Nguyen #define ICE_RSS_OUTER_HEADERS	1
1597a4e82a81STony Nguyen #define ICE_RSS_INNER_HEADERS	2
1598c90ed40cSTony Nguyen 
159931ad4e4eSTony Nguyen /* Flow profile ID format:
160031ad4e4eSTony Nguyen  * [0:31] - Packet match fields
160131ad4e4eSTony Nguyen  * [32:62] - Protocol header
160231ad4e4eSTony Nguyen  * [63] - Encapsulation flag, 0 if non-tunneled, 1 if tunneled
160331ad4e4eSTony Nguyen  */
160431ad4e4eSTony Nguyen #define ICE_FLOW_GEN_PROFID(hash, hdr, segs_cnt) \
160531ad4e4eSTony Nguyen 	(u64)(((u64)(hash) & ICE_FLOW_PROF_HASH_M) | \
160631ad4e4eSTony Nguyen 	      (((u64)(hdr) << ICE_FLOW_PROF_HDR_S) & ICE_FLOW_PROF_HDR_M) | \
160731ad4e4eSTony Nguyen 	      ((u8)((segs_cnt) - 1) ? ICE_FLOW_PROF_ENCAP_M : 0))
160831ad4e4eSTony Nguyen 
1609c90ed40cSTony Nguyen /**
1610c90ed40cSTony Nguyen  * ice_add_rss_cfg_sync - add an RSS configuration
161131ad4e4eSTony Nguyen  * @hw: pointer to the hardware structure
1612451f2c44STony Nguyen  * @vsi_handle: software VSI handle
1613c90ed40cSTony Nguyen  * @hashed_flds: hash bit fields (ICE_FLOW_HASH_*) to configure
1614c90ed40cSTony Nguyen  * @addl_hdrs: protocol header fields
1615c90ed40cSTony Nguyen  * @segs_cnt: packet segment count
1616c90ed40cSTony Nguyen  *
1617c90ed40cSTony Nguyen  * Assumption: lock has already been acquired for RSS list
1618c90ed40cSTony Nguyen  */
1619c90ed40cSTony Nguyen static enum ice_status
1620451f2c44STony Nguyen ice_add_rss_cfg_sync(struct ice_hw *hw, u16 vsi_handle, u64 hashed_flds,
1621451f2c44STony Nguyen 		     u32 addl_hdrs, u8 segs_cnt)
1622c90ed40cSTony Nguyen {
1623451f2c44STony Nguyen 	const enum ice_block blk = ICE_BLK_RSS;
1624451f2c44STony Nguyen 	struct ice_flow_prof *prof = NULL;
1625c90ed40cSTony Nguyen 	struct ice_flow_seg_info *segs;
1626c90ed40cSTony Nguyen 	enum ice_status status;
1627c90ed40cSTony Nguyen 
1628c90ed40cSTony Nguyen 	if (!segs_cnt || segs_cnt > ICE_FLOW_SEG_MAX)
1629c90ed40cSTony Nguyen 		return ICE_ERR_PARAM;
1630c90ed40cSTony Nguyen 
1631c90ed40cSTony Nguyen 	segs = kcalloc(segs_cnt, sizeof(*segs), GFP_KERNEL);
1632c90ed40cSTony Nguyen 	if (!segs)
1633c90ed40cSTony Nguyen 		return ICE_ERR_NO_MEMORY;
1634c90ed40cSTony Nguyen 
1635c90ed40cSTony Nguyen 	/* Construct the packet segment info from the hashed fields */
1636c90ed40cSTony Nguyen 	status = ice_flow_set_rss_seg_info(&segs[segs_cnt - 1], hashed_flds,
1637c90ed40cSTony Nguyen 					   addl_hdrs);
163831ad4e4eSTony Nguyen 	if (status)
163931ad4e4eSTony Nguyen 		goto exit;
1640c90ed40cSTony Nguyen 
16412c61054cSTony Nguyen 	/* Search for a flow profile that has matching headers, hash fields
16422c61054cSTony Nguyen 	 * and has the input VSI associated to it. If found, no further
16432c61054cSTony Nguyen 	 * operations required and exit.
16442c61054cSTony Nguyen 	 */
16452c61054cSTony Nguyen 	prof = ice_flow_find_prof_conds(hw, blk, ICE_FLOW_RX, segs, segs_cnt,
16462c61054cSTony Nguyen 					vsi_handle,
16472c61054cSTony Nguyen 					ICE_FLOW_FIND_PROF_CHK_FLDS |
16482c61054cSTony Nguyen 					ICE_FLOW_FIND_PROF_CHK_VSI);
16492c61054cSTony Nguyen 	if (prof)
16502c61054cSTony Nguyen 		goto exit;
16512c61054cSTony Nguyen 
16522c61054cSTony Nguyen 	/* Check if a flow profile exists with the same protocol headers and
16532c61054cSTony Nguyen 	 * associated with the input VSI. If so disassociate the VSI from
16542c61054cSTony Nguyen 	 * this profile. The VSI will be added to a new profile created with
16552c61054cSTony Nguyen 	 * the protocol header and new hash field configuration.
16562c61054cSTony Nguyen 	 */
16572c61054cSTony Nguyen 	prof = ice_flow_find_prof_conds(hw, blk, ICE_FLOW_RX, segs, segs_cnt,
16582c61054cSTony Nguyen 					vsi_handle, ICE_FLOW_FIND_PROF_CHK_VSI);
16592c61054cSTony Nguyen 	if (prof) {
16602c61054cSTony Nguyen 		status = ice_flow_disassoc_prof(hw, blk, prof, vsi_handle);
16612c61054cSTony Nguyen 		if (!status)
16622c61054cSTony Nguyen 			ice_rem_rss_list(hw, vsi_handle, prof);
16632c61054cSTony Nguyen 		else
16642c61054cSTony Nguyen 			goto exit;
16652c61054cSTony Nguyen 
16662c61054cSTony Nguyen 		/* Remove profile if it has no VSIs associated */
16672c61054cSTony Nguyen 		if (bitmap_empty(prof->vsis, ICE_MAX_VSI)) {
16682c61054cSTony Nguyen 			status = ice_flow_rem_prof(hw, blk, prof->id);
16692c61054cSTony Nguyen 			if (status)
16702c61054cSTony Nguyen 				goto exit;
16712c61054cSTony Nguyen 		}
16722c61054cSTony Nguyen 	}
16732c61054cSTony Nguyen 
16742c61054cSTony Nguyen 	/* Search for a profile that has same match fields only. If this
16752c61054cSTony Nguyen 	 * exists then associate the VSI to this profile.
16762c61054cSTony Nguyen 	 */
16772c61054cSTony Nguyen 	prof = ice_flow_find_prof_conds(hw, blk, ICE_FLOW_RX, segs, segs_cnt,
16782c61054cSTony Nguyen 					vsi_handle,
16792c61054cSTony Nguyen 					ICE_FLOW_FIND_PROF_CHK_FLDS);
16802c61054cSTony Nguyen 	if (prof) {
16812c61054cSTony Nguyen 		status = ice_flow_assoc_prof(hw, blk, prof, vsi_handle);
16822c61054cSTony Nguyen 		if (!status)
16832c61054cSTony Nguyen 			status = ice_add_rss_list(hw, vsi_handle, prof);
16842c61054cSTony Nguyen 		goto exit;
16852c61054cSTony Nguyen 	}
16862c61054cSTony Nguyen 
168731ad4e4eSTony Nguyen 	/* Create a new flow profile with generated profile and packet
168831ad4e4eSTony Nguyen 	 * segment information.
168931ad4e4eSTony Nguyen 	 */
1690451f2c44STony Nguyen 	status = ice_flow_add_prof(hw, blk, ICE_FLOW_RX,
169131ad4e4eSTony Nguyen 				   ICE_FLOW_GEN_PROFID(hashed_flds,
169231ad4e4eSTony Nguyen 						       segs[segs_cnt - 1].hdrs,
169331ad4e4eSTony Nguyen 						       segs_cnt),
1694451f2c44STony Nguyen 				   segs, segs_cnt, &prof);
1695451f2c44STony Nguyen 	if (status)
1696451f2c44STony Nguyen 		goto exit;
1697451f2c44STony Nguyen 
1698451f2c44STony Nguyen 	status = ice_flow_assoc_prof(hw, blk, prof, vsi_handle);
16992c61054cSTony Nguyen 	/* If association to a new flow profile failed then this profile can
17002c61054cSTony Nguyen 	 * be removed.
17012c61054cSTony Nguyen 	 */
17022c61054cSTony Nguyen 	if (status) {
17032c61054cSTony Nguyen 		ice_flow_rem_prof(hw, blk, prof->id);
17042c61054cSTony Nguyen 		goto exit;
17052c61054cSTony Nguyen 	}
17062c61054cSTony Nguyen 
17072c61054cSTony Nguyen 	status = ice_add_rss_list(hw, vsi_handle, prof);
170831ad4e4eSTony Nguyen 
170931ad4e4eSTony Nguyen exit:
1710c90ed40cSTony Nguyen 	kfree(segs);
1711c90ed40cSTony Nguyen 	return status;
1712c90ed40cSTony Nguyen }
1713c90ed40cSTony Nguyen 
1714c90ed40cSTony Nguyen /**
1715c90ed40cSTony Nguyen  * ice_add_rss_cfg - add an RSS configuration with specified hashed fields
1716c90ed40cSTony Nguyen  * @hw: pointer to the hardware structure
1717c90ed40cSTony Nguyen  * @vsi_handle: software VSI handle
1718c90ed40cSTony Nguyen  * @hashed_flds: hash bit fields (ICE_FLOW_HASH_*) to configure
1719c90ed40cSTony Nguyen  * @addl_hdrs: protocol header fields
1720c90ed40cSTony Nguyen  *
1721c90ed40cSTony Nguyen  * This function will generate a flow profile based on fields associated with
1722c90ed40cSTony Nguyen  * the input fields to hash on, the flow type and use the VSI number to add
1723c90ed40cSTony Nguyen  * a flow entry to the profile.
1724c90ed40cSTony Nguyen  */
1725c90ed40cSTony Nguyen enum ice_status
1726c90ed40cSTony Nguyen ice_add_rss_cfg(struct ice_hw *hw, u16 vsi_handle, u64 hashed_flds,
1727c90ed40cSTony Nguyen 		u32 addl_hdrs)
1728c90ed40cSTony Nguyen {
1729c90ed40cSTony Nguyen 	enum ice_status status;
1730c90ed40cSTony Nguyen 
1731c90ed40cSTony Nguyen 	if (hashed_flds == ICE_HASH_INVALID ||
1732c90ed40cSTony Nguyen 	    !ice_is_vsi_valid(hw, vsi_handle))
1733c90ed40cSTony Nguyen 		return ICE_ERR_PARAM;
1734c90ed40cSTony Nguyen 
1735c90ed40cSTony Nguyen 	mutex_lock(&hw->rss_locks);
1736451f2c44STony Nguyen 	status = ice_add_rss_cfg_sync(hw, vsi_handle, hashed_flds, addl_hdrs,
1737c90ed40cSTony Nguyen 				      ICE_RSS_OUTER_HEADERS);
1738a4e82a81STony Nguyen 	if (!status)
1739a4e82a81STony Nguyen 		status = ice_add_rss_cfg_sync(hw, vsi_handle, hashed_flds,
1740a4e82a81STony Nguyen 					      addl_hdrs, ICE_RSS_INNER_HEADERS);
1741c90ed40cSTony Nguyen 	mutex_unlock(&hw->rss_locks);
1742c90ed40cSTony Nguyen 
1743c90ed40cSTony Nguyen 	return status;
1744c90ed40cSTony Nguyen }
1745c90ed40cSTony Nguyen 
17461c01c8c6SMd Fahad Iqbal Polash /* Mapping of AVF hash bit fields to an L3-L4 hash combination.
17471c01c8c6SMd Fahad Iqbal Polash  * As the ice_flow_avf_hdr_field represent individual bit shifts in a hash,
17481c01c8c6SMd Fahad Iqbal Polash  * convert its values to their appropriate flow L3, L4 values.
17491c01c8c6SMd Fahad Iqbal Polash  */
17501c01c8c6SMd Fahad Iqbal Polash #define ICE_FLOW_AVF_RSS_IPV4_MASKS \
17511c01c8c6SMd Fahad Iqbal Polash 	(BIT_ULL(ICE_AVF_FLOW_FIELD_IPV4_OTHER) | \
17521c01c8c6SMd Fahad Iqbal Polash 	 BIT_ULL(ICE_AVF_FLOW_FIELD_FRAG_IPV4))
17531c01c8c6SMd Fahad Iqbal Polash #define ICE_FLOW_AVF_RSS_TCP_IPV4_MASKS \
17541c01c8c6SMd Fahad Iqbal Polash 	(BIT_ULL(ICE_AVF_FLOW_FIELD_IPV4_TCP_SYN_NO_ACK) | \
17551c01c8c6SMd Fahad Iqbal Polash 	 BIT_ULL(ICE_AVF_FLOW_FIELD_IPV4_TCP))
17561c01c8c6SMd Fahad Iqbal Polash #define ICE_FLOW_AVF_RSS_UDP_IPV4_MASKS \
17571c01c8c6SMd Fahad Iqbal Polash 	(BIT_ULL(ICE_AVF_FLOW_FIELD_UNICAST_IPV4_UDP) | \
17581c01c8c6SMd Fahad Iqbal Polash 	 BIT_ULL(ICE_AVF_FLOW_FIELD_MULTICAST_IPV4_UDP) | \
17591c01c8c6SMd Fahad Iqbal Polash 	 BIT_ULL(ICE_AVF_FLOW_FIELD_IPV4_UDP))
17601c01c8c6SMd Fahad Iqbal Polash #define ICE_FLOW_AVF_RSS_ALL_IPV4_MASKS \
17611c01c8c6SMd Fahad Iqbal Polash 	(ICE_FLOW_AVF_RSS_TCP_IPV4_MASKS | ICE_FLOW_AVF_RSS_UDP_IPV4_MASKS | \
17621c01c8c6SMd Fahad Iqbal Polash 	 ICE_FLOW_AVF_RSS_IPV4_MASKS | BIT_ULL(ICE_AVF_FLOW_FIELD_IPV4_SCTP))
17631c01c8c6SMd Fahad Iqbal Polash 
17641c01c8c6SMd Fahad Iqbal Polash #define ICE_FLOW_AVF_RSS_IPV6_MASKS \
17651c01c8c6SMd Fahad Iqbal Polash 	(BIT_ULL(ICE_AVF_FLOW_FIELD_IPV6_OTHER) | \
17661c01c8c6SMd Fahad Iqbal Polash 	 BIT_ULL(ICE_AVF_FLOW_FIELD_FRAG_IPV6))
17671c01c8c6SMd Fahad Iqbal Polash #define ICE_FLOW_AVF_RSS_UDP_IPV6_MASKS \
17681c01c8c6SMd Fahad Iqbal Polash 	(BIT_ULL(ICE_AVF_FLOW_FIELD_UNICAST_IPV6_UDP) | \
17691c01c8c6SMd Fahad Iqbal Polash 	 BIT_ULL(ICE_AVF_FLOW_FIELD_MULTICAST_IPV6_UDP) | \
17701c01c8c6SMd Fahad Iqbal Polash 	 BIT_ULL(ICE_AVF_FLOW_FIELD_IPV6_UDP))
17711c01c8c6SMd Fahad Iqbal Polash #define ICE_FLOW_AVF_RSS_TCP_IPV6_MASKS \
17721c01c8c6SMd Fahad Iqbal Polash 	(BIT_ULL(ICE_AVF_FLOW_FIELD_IPV6_TCP_SYN_NO_ACK) | \
17731c01c8c6SMd Fahad Iqbal Polash 	 BIT_ULL(ICE_AVF_FLOW_FIELD_IPV6_TCP))
17741c01c8c6SMd Fahad Iqbal Polash #define ICE_FLOW_AVF_RSS_ALL_IPV6_MASKS \
17751c01c8c6SMd Fahad Iqbal Polash 	(ICE_FLOW_AVF_RSS_TCP_IPV6_MASKS | ICE_FLOW_AVF_RSS_UDP_IPV6_MASKS | \
17761c01c8c6SMd Fahad Iqbal Polash 	 ICE_FLOW_AVF_RSS_IPV6_MASKS | BIT_ULL(ICE_AVF_FLOW_FIELD_IPV6_SCTP))
17771c01c8c6SMd Fahad Iqbal Polash 
17781c01c8c6SMd Fahad Iqbal Polash /**
17791c01c8c6SMd Fahad Iqbal Polash  * ice_add_avf_rss_cfg - add an RSS configuration for AVF driver
17801c01c8c6SMd Fahad Iqbal Polash  * @hw: pointer to the hardware structure
17811c01c8c6SMd Fahad Iqbal Polash  * @vsi_handle: software VSI handle
17821c01c8c6SMd Fahad Iqbal Polash  * @avf_hash: hash bit fields (ICE_AVF_FLOW_FIELD_*) to configure
17831c01c8c6SMd Fahad Iqbal Polash  *
17841c01c8c6SMd Fahad Iqbal Polash  * This function will take the hash bitmap provided by the AVF driver via a
17851c01c8c6SMd Fahad Iqbal Polash  * message, convert it to ICE-compatible values, and configure RSS flow
17861c01c8c6SMd Fahad Iqbal Polash  * profiles.
17871c01c8c6SMd Fahad Iqbal Polash  */
17881c01c8c6SMd Fahad Iqbal Polash enum ice_status
17891c01c8c6SMd Fahad Iqbal Polash ice_add_avf_rss_cfg(struct ice_hw *hw, u16 vsi_handle, u64 avf_hash)
17901c01c8c6SMd Fahad Iqbal Polash {
17911c01c8c6SMd Fahad Iqbal Polash 	enum ice_status status = 0;
17921c01c8c6SMd Fahad Iqbal Polash 	u64 hash_flds;
17931c01c8c6SMd Fahad Iqbal Polash 
17941c01c8c6SMd Fahad Iqbal Polash 	if (avf_hash == ICE_AVF_FLOW_FIELD_INVALID ||
17951c01c8c6SMd Fahad Iqbal Polash 	    !ice_is_vsi_valid(hw, vsi_handle))
17961c01c8c6SMd Fahad Iqbal Polash 		return ICE_ERR_PARAM;
17971c01c8c6SMd Fahad Iqbal Polash 
17981c01c8c6SMd Fahad Iqbal Polash 	/* Make sure no unsupported bits are specified */
17991c01c8c6SMd Fahad Iqbal Polash 	if (avf_hash & ~(ICE_FLOW_AVF_RSS_ALL_IPV4_MASKS |
18001c01c8c6SMd Fahad Iqbal Polash 			 ICE_FLOW_AVF_RSS_ALL_IPV6_MASKS))
18011c01c8c6SMd Fahad Iqbal Polash 		return ICE_ERR_CFG;
18021c01c8c6SMd Fahad Iqbal Polash 
18031c01c8c6SMd Fahad Iqbal Polash 	hash_flds = avf_hash;
18041c01c8c6SMd Fahad Iqbal Polash 
18051c01c8c6SMd Fahad Iqbal Polash 	/* Always create an L3 RSS configuration for any L4 RSS configuration */
18061c01c8c6SMd Fahad Iqbal Polash 	if (hash_flds & ICE_FLOW_AVF_RSS_ALL_IPV4_MASKS)
18071c01c8c6SMd Fahad Iqbal Polash 		hash_flds |= ICE_FLOW_AVF_RSS_IPV4_MASKS;
18081c01c8c6SMd Fahad Iqbal Polash 
18091c01c8c6SMd Fahad Iqbal Polash 	if (hash_flds & ICE_FLOW_AVF_RSS_ALL_IPV6_MASKS)
18101c01c8c6SMd Fahad Iqbal Polash 		hash_flds |= ICE_FLOW_AVF_RSS_IPV6_MASKS;
18111c01c8c6SMd Fahad Iqbal Polash 
18121c01c8c6SMd Fahad Iqbal Polash 	/* Create the corresponding RSS configuration for each valid hash bit */
18131c01c8c6SMd Fahad Iqbal Polash 	while (hash_flds) {
18141c01c8c6SMd Fahad Iqbal Polash 		u64 rss_hash = ICE_HASH_INVALID;
18151c01c8c6SMd Fahad Iqbal Polash 
18161c01c8c6SMd Fahad Iqbal Polash 		if (hash_flds & ICE_FLOW_AVF_RSS_ALL_IPV4_MASKS) {
18171c01c8c6SMd Fahad Iqbal Polash 			if (hash_flds & ICE_FLOW_AVF_RSS_IPV4_MASKS) {
18181c01c8c6SMd Fahad Iqbal Polash 				rss_hash = ICE_FLOW_HASH_IPV4;
18191c01c8c6SMd Fahad Iqbal Polash 				hash_flds &= ~ICE_FLOW_AVF_RSS_IPV4_MASKS;
18201c01c8c6SMd Fahad Iqbal Polash 			} else if (hash_flds &
18211c01c8c6SMd Fahad Iqbal Polash 				   ICE_FLOW_AVF_RSS_TCP_IPV4_MASKS) {
18221c01c8c6SMd Fahad Iqbal Polash 				rss_hash = ICE_FLOW_HASH_IPV4 |
18231c01c8c6SMd Fahad Iqbal Polash 					ICE_FLOW_HASH_TCP_PORT;
18241c01c8c6SMd Fahad Iqbal Polash 				hash_flds &= ~ICE_FLOW_AVF_RSS_TCP_IPV4_MASKS;
18251c01c8c6SMd Fahad Iqbal Polash 			} else if (hash_flds &
18261c01c8c6SMd Fahad Iqbal Polash 				   ICE_FLOW_AVF_RSS_UDP_IPV4_MASKS) {
18271c01c8c6SMd Fahad Iqbal Polash 				rss_hash = ICE_FLOW_HASH_IPV4 |
18281c01c8c6SMd Fahad Iqbal Polash 					ICE_FLOW_HASH_UDP_PORT;
18291c01c8c6SMd Fahad Iqbal Polash 				hash_flds &= ~ICE_FLOW_AVF_RSS_UDP_IPV4_MASKS;
18301c01c8c6SMd Fahad Iqbal Polash 			} else if (hash_flds &
18311c01c8c6SMd Fahad Iqbal Polash 				   BIT_ULL(ICE_AVF_FLOW_FIELD_IPV4_SCTP)) {
18321c01c8c6SMd Fahad Iqbal Polash 				rss_hash = ICE_FLOW_HASH_IPV4 |
18331c01c8c6SMd Fahad Iqbal Polash 					ICE_FLOW_HASH_SCTP_PORT;
18341c01c8c6SMd Fahad Iqbal Polash 				hash_flds &=
18351c01c8c6SMd Fahad Iqbal Polash 					~BIT_ULL(ICE_AVF_FLOW_FIELD_IPV4_SCTP);
18361c01c8c6SMd Fahad Iqbal Polash 			}
18371c01c8c6SMd Fahad Iqbal Polash 		} else if (hash_flds & ICE_FLOW_AVF_RSS_ALL_IPV6_MASKS) {
18381c01c8c6SMd Fahad Iqbal Polash 			if (hash_flds & ICE_FLOW_AVF_RSS_IPV6_MASKS) {
18391c01c8c6SMd Fahad Iqbal Polash 				rss_hash = ICE_FLOW_HASH_IPV6;
18401c01c8c6SMd Fahad Iqbal Polash 				hash_flds &= ~ICE_FLOW_AVF_RSS_IPV6_MASKS;
18411c01c8c6SMd Fahad Iqbal Polash 			} else if (hash_flds &
18421c01c8c6SMd Fahad Iqbal Polash 				   ICE_FLOW_AVF_RSS_TCP_IPV6_MASKS) {
18431c01c8c6SMd Fahad Iqbal Polash 				rss_hash = ICE_FLOW_HASH_IPV6 |
18441c01c8c6SMd Fahad Iqbal Polash 					ICE_FLOW_HASH_TCP_PORT;
18451c01c8c6SMd Fahad Iqbal Polash 				hash_flds &= ~ICE_FLOW_AVF_RSS_TCP_IPV6_MASKS;
18461c01c8c6SMd Fahad Iqbal Polash 			} else if (hash_flds &
18471c01c8c6SMd Fahad Iqbal Polash 				   ICE_FLOW_AVF_RSS_UDP_IPV6_MASKS) {
18481c01c8c6SMd Fahad Iqbal Polash 				rss_hash = ICE_FLOW_HASH_IPV6 |
18491c01c8c6SMd Fahad Iqbal Polash 					ICE_FLOW_HASH_UDP_PORT;
18501c01c8c6SMd Fahad Iqbal Polash 				hash_flds &= ~ICE_FLOW_AVF_RSS_UDP_IPV6_MASKS;
18511c01c8c6SMd Fahad Iqbal Polash 			} else if (hash_flds &
18521c01c8c6SMd Fahad Iqbal Polash 				   BIT_ULL(ICE_AVF_FLOW_FIELD_IPV6_SCTP)) {
18531c01c8c6SMd Fahad Iqbal Polash 				rss_hash = ICE_FLOW_HASH_IPV6 |
18541c01c8c6SMd Fahad Iqbal Polash 					ICE_FLOW_HASH_SCTP_PORT;
18551c01c8c6SMd Fahad Iqbal Polash 				hash_flds &=
18561c01c8c6SMd Fahad Iqbal Polash 					~BIT_ULL(ICE_AVF_FLOW_FIELD_IPV6_SCTP);
18571c01c8c6SMd Fahad Iqbal Polash 			}
18581c01c8c6SMd Fahad Iqbal Polash 		}
18591c01c8c6SMd Fahad Iqbal Polash 
18601c01c8c6SMd Fahad Iqbal Polash 		if (rss_hash == ICE_HASH_INVALID)
18611c01c8c6SMd Fahad Iqbal Polash 			return ICE_ERR_OUT_OF_RANGE;
18621c01c8c6SMd Fahad Iqbal Polash 
18631c01c8c6SMd Fahad Iqbal Polash 		status = ice_add_rss_cfg(hw, vsi_handle, rss_hash,
18641c01c8c6SMd Fahad Iqbal Polash 					 ICE_FLOW_SEG_HDR_NONE);
18651c01c8c6SMd Fahad Iqbal Polash 		if (status)
18661c01c8c6SMd Fahad Iqbal Polash 			break;
18671c01c8c6SMd Fahad Iqbal Polash 	}
18681c01c8c6SMd Fahad Iqbal Polash 
18691c01c8c6SMd Fahad Iqbal Polash 	return status;
18701c01c8c6SMd Fahad Iqbal Polash }
18711c01c8c6SMd Fahad Iqbal Polash 
1872c90ed40cSTony Nguyen /**
1873c90ed40cSTony Nguyen  * ice_replay_rss_cfg - replay RSS configurations associated with VSI
1874c90ed40cSTony Nguyen  * @hw: pointer to the hardware structure
1875c90ed40cSTony Nguyen  * @vsi_handle: software VSI handle
1876c90ed40cSTony Nguyen  */
1877c90ed40cSTony Nguyen enum ice_status ice_replay_rss_cfg(struct ice_hw *hw, u16 vsi_handle)
1878c90ed40cSTony Nguyen {
1879c90ed40cSTony Nguyen 	enum ice_status status = 0;
1880c90ed40cSTony Nguyen 	struct ice_rss_cfg *r;
1881c90ed40cSTony Nguyen 
1882c90ed40cSTony Nguyen 	if (!ice_is_vsi_valid(hw, vsi_handle))
1883c90ed40cSTony Nguyen 		return ICE_ERR_PARAM;
1884c90ed40cSTony Nguyen 
1885c90ed40cSTony Nguyen 	mutex_lock(&hw->rss_locks);
1886c90ed40cSTony Nguyen 	list_for_each_entry(r, &hw->rss_list_head, l_entry) {
1887c90ed40cSTony Nguyen 		if (test_bit(vsi_handle, r->vsis)) {
1888451f2c44STony Nguyen 			status = ice_add_rss_cfg_sync(hw, vsi_handle,
1889451f2c44STony Nguyen 						      r->hashed_flds,
1890c90ed40cSTony Nguyen 						      r->packet_hdr,
1891c90ed40cSTony Nguyen 						      ICE_RSS_OUTER_HEADERS);
1892c90ed40cSTony Nguyen 			if (status)
1893c90ed40cSTony Nguyen 				break;
1894a4e82a81STony Nguyen 			status = ice_add_rss_cfg_sync(hw, vsi_handle,
1895a4e82a81STony Nguyen 						      r->hashed_flds,
1896a4e82a81STony Nguyen 						      r->packet_hdr,
1897a4e82a81STony Nguyen 						      ICE_RSS_INNER_HEADERS);
1898a4e82a81STony Nguyen 			if (status)
1899a4e82a81STony Nguyen 				break;
1900c90ed40cSTony Nguyen 		}
1901c90ed40cSTony Nguyen 	}
1902c90ed40cSTony Nguyen 	mutex_unlock(&hw->rss_locks);
1903c90ed40cSTony Nguyen 
1904c90ed40cSTony Nguyen 	return status;
1905c90ed40cSTony Nguyen }
19066876fb64SMd Fahad Iqbal Polash 
19076876fb64SMd Fahad Iqbal Polash /**
19086876fb64SMd Fahad Iqbal Polash  * ice_get_rss_cfg - returns hashed fields for the given header types
19096876fb64SMd Fahad Iqbal Polash  * @hw: pointer to the hardware structure
19106876fb64SMd Fahad Iqbal Polash  * @vsi_handle: software VSI handle
19116876fb64SMd Fahad Iqbal Polash  * @hdrs: protocol header type
19126876fb64SMd Fahad Iqbal Polash  *
19136876fb64SMd Fahad Iqbal Polash  * This function will return the match fields of the first instance of flow
19146876fb64SMd Fahad Iqbal Polash  * profile having the given header types and containing input VSI
19156876fb64SMd Fahad Iqbal Polash  */
19166876fb64SMd Fahad Iqbal Polash u64 ice_get_rss_cfg(struct ice_hw *hw, u16 vsi_handle, u32 hdrs)
19176876fb64SMd Fahad Iqbal Polash {
1918cdedbab9SVignesh Sridhar 	u64 rss_hash = ICE_HASH_INVALID;
1919cdedbab9SVignesh Sridhar 	struct ice_rss_cfg *r;
19206876fb64SMd Fahad Iqbal Polash 
19216876fb64SMd Fahad Iqbal Polash 	/* verify if the protocol header is non zero and VSI is valid */
19226876fb64SMd Fahad Iqbal Polash 	if (hdrs == ICE_FLOW_SEG_HDR_NONE || !ice_is_vsi_valid(hw, vsi_handle))
19236876fb64SMd Fahad Iqbal Polash 		return ICE_HASH_INVALID;
19246876fb64SMd Fahad Iqbal Polash 
19256876fb64SMd Fahad Iqbal Polash 	mutex_lock(&hw->rss_locks);
19266876fb64SMd Fahad Iqbal Polash 	list_for_each_entry(r, &hw->rss_list_head, l_entry)
19276876fb64SMd Fahad Iqbal Polash 		if (test_bit(vsi_handle, r->vsis) &&
19286876fb64SMd Fahad Iqbal Polash 		    r->packet_hdr == hdrs) {
1929cdedbab9SVignesh Sridhar 			rss_hash = r->hashed_flds;
19306876fb64SMd Fahad Iqbal Polash 			break;
19316876fb64SMd Fahad Iqbal Polash 		}
19326876fb64SMd Fahad Iqbal Polash 	mutex_unlock(&hw->rss_locks);
19336876fb64SMd Fahad Iqbal Polash 
1934cdedbab9SVignesh Sridhar 	return rss_hash;
19356876fb64SMd Fahad Iqbal Polash }
1936