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 */
12c90ed40cSTony Nguyen };
13c90ed40cSTony Nguyen 
14c90ed40cSTony Nguyen #define ICE_FLOW_FLD_INFO(_hdr, _offset_bytes, _size_bytes) { \
15c90ed40cSTony Nguyen 	.hdr = _hdr, \
16c90ed40cSTony Nguyen 	.off = (_offset_bytes) * BITS_PER_BYTE, \
17c90ed40cSTony Nguyen 	.size = (_size_bytes) * BITS_PER_BYTE, \
18c90ed40cSTony Nguyen }
19c90ed40cSTony Nguyen 
20c90ed40cSTony Nguyen /* Table containing properties of supported protocol header fields */
21c90ed40cSTony Nguyen static const
22c90ed40cSTony Nguyen struct ice_flow_field_info ice_flds_info[ICE_FLOW_FIELD_IDX_MAX] = {
23c90ed40cSTony Nguyen 	/* IPv4 / IPv6 */
24c90ed40cSTony Nguyen 	/* ICE_FLOW_FIELD_IDX_IPV4_SA */
25c90ed40cSTony Nguyen 	ICE_FLOW_FLD_INFO(ICE_FLOW_SEG_HDR_IPV4, 12, sizeof(struct in_addr)),
26c90ed40cSTony Nguyen 	/* ICE_FLOW_FIELD_IDX_IPV4_DA */
27c90ed40cSTony Nguyen 	ICE_FLOW_FLD_INFO(ICE_FLOW_SEG_HDR_IPV4, 16, sizeof(struct in_addr)),
28c90ed40cSTony Nguyen 	/* ICE_FLOW_FIELD_IDX_IPV6_SA */
29c90ed40cSTony Nguyen 	ICE_FLOW_FLD_INFO(ICE_FLOW_SEG_HDR_IPV6, 8, sizeof(struct in6_addr)),
30c90ed40cSTony Nguyen 	/* ICE_FLOW_FIELD_IDX_IPV6_DA */
31c90ed40cSTony Nguyen 	ICE_FLOW_FLD_INFO(ICE_FLOW_SEG_HDR_IPV6, 24, sizeof(struct in6_addr)),
32c90ed40cSTony Nguyen 	/* Transport */
33c90ed40cSTony Nguyen 	/* ICE_FLOW_FIELD_IDX_TCP_SRC_PORT */
34c90ed40cSTony Nguyen 	ICE_FLOW_FLD_INFO(ICE_FLOW_SEG_HDR_TCP, 0, sizeof(__be16)),
35c90ed40cSTony Nguyen 	/* ICE_FLOW_FIELD_IDX_TCP_DST_PORT */
36c90ed40cSTony Nguyen 	ICE_FLOW_FLD_INFO(ICE_FLOW_SEG_HDR_TCP, 2, sizeof(__be16)),
37c90ed40cSTony Nguyen 	/* ICE_FLOW_FIELD_IDX_UDP_SRC_PORT */
38c90ed40cSTony Nguyen 	ICE_FLOW_FLD_INFO(ICE_FLOW_SEG_HDR_UDP, 0, sizeof(__be16)),
39c90ed40cSTony Nguyen 	/* ICE_FLOW_FIELD_IDX_UDP_DST_PORT */
40c90ed40cSTony Nguyen 	ICE_FLOW_FLD_INFO(ICE_FLOW_SEG_HDR_UDP, 2, sizeof(__be16)),
411c01c8c6SMd Fahad Iqbal Polash 	/* ICE_FLOW_FIELD_IDX_SCTP_SRC_PORT */
421c01c8c6SMd Fahad Iqbal Polash 	ICE_FLOW_FLD_INFO(ICE_FLOW_SEG_HDR_SCTP, 0, sizeof(__be16)),
431c01c8c6SMd Fahad Iqbal Polash 	/* ICE_FLOW_FIELD_IDX_SCTP_DST_PORT */
441c01c8c6SMd Fahad Iqbal Polash 	ICE_FLOW_FLD_INFO(ICE_FLOW_SEG_HDR_SCTP, 2, sizeof(__be16)),
45a4e82a81STony Nguyen 	/* GRE */
46a4e82a81STony Nguyen 	/* ICE_FLOW_FIELD_IDX_GRE_KEYID */
47a4e82a81STony Nguyen 	ICE_FLOW_FLD_INFO(ICE_FLOW_SEG_HDR_GRE, 12,
48a4e82a81STony Nguyen 			  sizeof_field(struct gre_full_hdr, key)),
49c90ed40cSTony Nguyen };
50c90ed40cSTony Nguyen 
5131ad4e4eSTony Nguyen /* Bitmaps indicating relevant packet types for a particular protocol header
5231ad4e4eSTony Nguyen  *
5331ad4e4eSTony Nguyen  * Packet types for packets with an Outer/First/Single IPv4 header
5431ad4e4eSTony Nguyen  */
5531ad4e4eSTony Nguyen static const u32 ice_ptypes_ipv4_ofos[] = {
5631ad4e4eSTony Nguyen 	0x1DC00000, 0x04000800, 0x00000000, 0x00000000,
5731ad4e4eSTony Nguyen 	0x00000000, 0x00000000, 0x00000000, 0x00000000,
5831ad4e4eSTony Nguyen 	0x00000000, 0x00000000, 0x00000000, 0x00000000,
5931ad4e4eSTony Nguyen 	0x00000000, 0x00000000, 0x00000000, 0x00000000,
6031ad4e4eSTony Nguyen 	0x00000000, 0x00000000, 0x00000000, 0x00000000,
6131ad4e4eSTony Nguyen 	0x00000000, 0x00000000, 0x00000000, 0x00000000,
6231ad4e4eSTony Nguyen 	0x00000000, 0x00000000, 0x00000000, 0x00000000,
6331ad4e4eSTony Nguyen 	0x00000000, 0x00000000, 0x00000000, 0x00000000,
6431ad4e4eSTony Nguyen };
6531ad4e4eSTony Nguyen 
6631ad4e4eSTony Nguyen /* Packet types for packets with an Innermost/Last IPv4 header */
6731ad4e4eSTony Nguyen static const u32 ice_ptypes_ipv4_il[] = {
6831ad4e4eSTony Nguyen 	0xE0000000, 0xB807700E, 0x80000003, 0xE01DC03B,
6931ad4e4eSTony Nguyen 	0x0000000E, 0x00000000, 0x00000000, 0x00000000,
7031ad4e4eSTony Nguyen 	0x00000000, 0x00000000, 0x00000000, 0x00000000,
7131ad4e4eSTony Nguyen 	0x00000000, 0x00000000, 0x00000000, 0x00000000,
7231ad4e4eSTony Nguyen 	0x00000000, 0x00000000, 0x00000000, 0x00000000,
7331ad4e4eSTony Nguyen 	0x00000000, 0x00000000, 0x00000000, 0x00000000,
7431ad4e4eSTony Nguyen 	0x00000000, 0x00000000, 0x00000000, 0x00000000,
7531ad4e4eSTony Nguyen 	0x00000000, 0x00000000, 0x00000000, 0x00000000,
7631ad4e4eSTony Nguyen };
7731ad4e4eSTony Nguyen 
7831ad4e4eSTony Nguyen /* Packet types for packets with an Outer/First/Single IPv6 header */
7931ad4e4eSTony Nguyen static const u32 ice_ptypes_ipv6_ofos[] = {
8031ad4e4eSTony Nguyen 	0x00000000, 0x00000000, 0x77000000, 0x10002000,
8131ad4e4eSTony Nguyen 	0x00000000, 0x00000000, 0x00000000, 0x00000000,
8231ad4e4eSTony Nguyen 	0x00000000, 0x00000000, 0x00000000, 0x00000000,
8331ad4e4eSTony Nguyen 	0x00000000, 0x00000000, 0x00000000, 0x00000000,
8431ad4e4eSTony Nguyen 	0x00000000, 0x00000000, 0x00000000, 0x00000000,
8531ad4e4eSTony Nguyen 	0x00000000, 0x00000000, 0x00000000, 0x00000000,
8631ad4e4eSTony Nguyen 	0x00000000, 0x00000000, 0x00000000, 0x00000000,
8731ad4e4eSTony Nguyen 	0x00000000, 0x00000000, 0x00000000, 0x00000000,
8831ad4e4eSTony Nguyen };
8931ad4e4eSTony Nguyen 
9031ad4e4eSTony Nguyen /* Packet types for packets with an Innermost/Last IPv6 header */
9131ad4e4eSTony Nguyen static const u32 ice_ptypes_ipv6_il[] = {
9231ad4e4eSTony Nguyen 	0x00000000, 0x03B80770, 0x000001DC, 0x0EE00000,
9331ad4e4eSTony Nguyen 	0x00000770, 0x00000000, 0x00000000, 0x00000000,
9431ad4e4eSTony Nguyen 	0x00000000, 0x00000000, 0x00000000, 0x00000000,
9531ad4e4eSTony Nguyen 	0x00000000, 0x00000000, 0x00000000, 0x00000000,
9631ad4e4eSTony Nguyen 	0x00000000, 0x00000000, 0x00000000, 0x00000000,
9731ad4e4eSTony Nguyen 	0x00000000, 0x00000000, 0x00000000, 0x00000000,
9831ad4e4eSTony Nguyen 	0x00000000, 0x00000000, 0x00000000, 0x00000000,
9931ad4e4eSTony Nguyen 	0x00000000, 0x00000000, 0x00000000, 0x00000000,
10031ad4e4eSTony Nguyen };
10131ad4e4eSTony Nguyen 
102051d2b5cSDan Nowlin /* Packet types for packets with an Outer/First/Single IPv4 header - no L4 */
103051d2b5cSDan Nowlin static const u32 ice_ipv4_ofos_no_l4[] = {
104051d2b5cSDan Nowlin 	0x10C00000, 0x04000800, 0x00000000, 0x00000000,
105051d2b5cSDan Nowlin 	0x00000000, 0x00000000, 0x00000000, 0x00000000,
106051d2b5cSDan Nowlin 	0x00000000, 0x00000000, 0x00000000, 0x00000000,
107051d2b5cSDan Nowlin 	0x00000000, 0x00000000, 0x00000000, 0x00000000,
108051d2b5cSDan Nowlin 	0x00000000, 0x00000000, 0x00000000, 0x00000000,
109051d2b5cSDan Nowlin 	0x00000000, 0x00000000, 0x00000000, 0x00000000,
110051d2b5cSDan Nowlin 	0x00000000, 0x00000000, 0x00000000, 0x00000000,
111051d2b5cSDan Nowlin 	0x00000000, 0x00000000, 0x00000000, 0x00000000,
112051d2b5cSDan Nowlin };
113051d2b5cSDan Nowlin 
114051d2b5cSDan Nowlin /* Packet types for packets with an Innermost/Last IPv4 header - no L4 */
115051d2b5cSDan Nowlin static const u32 ice_ipv4_il_no_l4[] = {
116051d2b5cSDan Nowlin 	0x60000000, 0x18043008, 0x80000002, 0x6010c021,
117051d2b5cSDan Nowlin 	0x00000008, 0x00000000, 0x00000000, 0x00000000,
118051d2b5cSDan Nowlin 	0x00000000, 0x00000000, 0x00000000, 0x00000000,
119051d2b5cSDan Nowlin 	0x00000000, 0x00000000, 0x00000000, 0x00000000,
120051d2b5cSDan Nowlin 	0x00000000, 0x00000000, 0x00000000, 0x00000000,
121051d2b5cSDan Nowlin 	0x00000000, 0x00000000, 0x00000000, 0x00000000,
122051d2b5cSDan Nowlin 	0x00000000, 0x00000000, 0x00000000, 0x00000000,
123051d2b5cSDan Nowlin 	0x00000000, 0x00000000, 0x00000000, 0x00000000,
124051d2b5cSDan Nowlin };
125051d2b5cSDan Nowlin 
126051d2b5cSDan Nowlin /* Packet types for packets with an Outer/First/Single IPv6 header - no L4 */
127051d2b5cSDan Nowlin static const u32 ice_ipv6_ofos_no_l4[] = {
128051d2b5cSDan Nowlin 	0x00000000, 0x00000000, 0x43000000, 0x10002000,
129051d2b5cSDan Nowlin 	0x00000000, 0x00000000, 0x00000000, 0x00000000,
130051d2b5cSDan Nowlin 	0x00000000, 0x00000000, 0x00000000, 0x00000000,
131051d2b5cSDan Nowlin 	0x00000000, 0x00000000, 0x00000000, 0x00000000,
132051d2b5cSDan Nowlin 	0x00000000, 0x00000000, 0x00000000, 0x00000000,
133051d2b5cSDan Nowlin 	0x00000000, 0x00000000, 0x00000000, 0x00000000,
134051d2b5cSDan Nowlin 	0x00000000, 0x00000000, 0x00000000, 0x00000000,
135051d2b5cSDan Nowlin 	0x00000000, 0x00000000, 0x00000000, 0x00000000,
136051d2b5cSDan Nowlin };
137051d2b5cSDan Nowlin 
138051d2b5cSDan Nowlin /* Packet types for packets with an Innermost/Last IPv6 header - no L4 */
139051d2b5cSDan Nowlin static const u32 ice_ipv6_il_no_l4[] = {
140051d2b5cSDan Nowlin 	0x00000000, 0x02180430, 0x0000010c, 0x086010c0,
141051d2b5cSDan Nowlin 	0x00000430, 0x00000000, 0x00000000, 0x00000000,
142051d2b5cSDan Nowlin 	0x00000000, 0x00000000, 0x00000000, 0x00000000,
143051d2b5cSDan Nowlin 	0x00000000, 0x00000000, 0x00000000, 0x00000000,
144051d2b5cSDan Nowlin 	0x00000000, 0x00000000, 0x00000000, 0x00000000,
145051d2b5cSDan Nowlin 	0x00000000, 0x00000000, 0x00000000, 0x00000000,
146051d2b5cSDan Nowlin 	0x00000000, 0x00000000, 0x00000000, 0x00000000,
147051d2b5cSDan Nowlin 	0x00000000, 0x00000000, 0x00000000, 0x00000000,
148051d2b5cSDan Nowlin };
149051d2b5cSDan Nowlin 
15031ad4e4eSTony Nguyen /* UDP Packet types for non-tunneled packets or tunneled
15131ad4e4eSTony Nguyen  * packets with inner UDP.
15231ad4e4eSTony Nguyen  */
15331ad4e4eSTony Nguyen static const u32 ice_ptypes_udp_il[] = {
15431ad4e4eSTony Nguyen 	0x81000000, 0x20204040, 0x04000010, 0x80810102,
15531ad4e4eSTony Nguyen 	0x00000040, 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 TCP header */
16531ad4e4eSTony Nguyen static const u32 ice_ptypes_tcp_il[] = {
16631ad4e4eSTony Nguyen 	0x04000000, 0x80810102, 0x10000040, 0x02040408,
16731ad4e4eSTony Nguyen 	0x00000102, 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 
17631ad4e4eSTony Nguyen /* Packet types for packets with an Innermost/Last SCTP header */
17731ad4e4eSTony Nguyen static const u32 ice_ptypes_sctp_il[] = {
17831ad4e4eSTony Nguyen 	0x08000000, 0x01020204, 0x20000081, 0x04080810,
17931ad4e4eSTony Nguyen 	0x00000204, 0x00000000, 0x00000000, 0x00000000,
18031ad4e4eSTony Nguyen 	0x00000000, 0x00000000, 0x00000000, 0x00000000,
18131ad4e4eSTony Nguyen 	0x00000000, 0x00000000, 0x00000000, 0x00000000,
18231ad4e4eSTony Nguyen 	0x00000000, 0x00000000, 0x00000000, 0x00000000,
18331ad4e4eSTony Nguyen 	0x00000000, 0x00000000, 0x00000000, 0x00000000,
18431ad4e4eSTony Nguyen 	0x00000000, 0x00000000, 0x00000000, 0x00000000,
18531ad4e4eSTony Nguyen 	0x00000000, 0x00000000, 0x00000000, 0x00000000,
18631ad4e4eSTony Nguyen };
18731ad4e4eSTony Nguyen 
188a4e82a81STony Nguyen /* Packet types for packets with an Outermost/First GRE header */
189a4e82a81STony Nguyen static const u32 ice_ptypes_gre_of[] = {
190a4e82a81STony Nguyen 	0x00000000, 0xBFBF7800, 0x000001DF, 0xFEFDE000,
191a4e82a81STony Nguyen 	0x0000017E, 0x00000000, 0x00000000, 0x00000000,
192a4e82a81STony Nguyen 	0x00000000, 0x00000000, 0x00000000, 0x00000000,
193a4e82a81STony Nguyen 	0x00000000, 0x00000000, 0x00000000, 0x00000000,
194a4e82a81STony Nguyen 	0x00000000, 0x00000000, 0x00000000, 0x00000000,
195a4e82a81STony Nguyen 	0x00000000, 0x00000000, 0x00000000, 0x00000000,
196a4e82a81STony Nguyen 	0x00000000, 0x00000000, 0x00000000, 0x00000000,
197a4e82a81STony Nguyen 	0x00000000, 0x00000000, 0x00000000, 0x00000000,
198a4e82a81STony Nguyen };
199a4e82a81STony Nguyen 
20031ad4e4eSTony Nguyen /* Manage parameters and info. used during the creation of a flow profile */
20131ad4e4eSTony Nguyen struct ice_flow_prof_params {
20231ad4e4eSTony Nguyen 	enum ice_block blk;
20331ad4e4eSTony Nguyen 	u16 entry_length; /* # of bytes formatted entry will require */
20431ad4e4eSTony Nguyen 	u8 es_cnt;
20531ad4e4eSTony Nguyen 	struct ice_flow_prof *prof;
20631ad4e4eSTony Nguyen 
20731ad4e4eSTony Nguyen 	/* For ACL, the es[0] will have the data of ICE_RX_MDID_PKT_FLAGS_15_0
20831ad4e4eSTony Nguyen 	 * This will give us the direction flags.
20931ad4e4eSTony Nguyen 	 */
21031ad4e4eSTony Nguyen 	struct ice_fv_word es[ICE_MAX_FV_WORDS];
21131ad4e4eSTony Nguyen 	DECLARE_BITMAP(ptypes, ICE_FLOW_PTYPE_MAX);
21231ad4e4eSTony Nguyen };
21331ad4e4eSTony Nguyen 
21431ad4e4eSTony Nguyen #define ICE_FLOW_SEG_HDRS_L3_MASK	\
21531ad4e4eSTony Nguyen 	(ICE_FLOW_SEG_HDR_IPV4 | ICE_FLOW_SEG_HDR_IPV6)
21631ad4e4eSTony Nguyen #define ICE_FLOW_SEG_HDRS_L4_MASK	\
21731ad4e4eSTony Nguyen 	(ICE_FLOW_SEG_HDR_TCP | ICE_FLOW_SEG_HDR_UDP | ICE_FLOW_SEG_HDR_SCTP)
21831ad4e4eSTony Nguyen 
21931ad4e4eSTony Nguyen /**
22031ad4e4eSTony Nguyen  * ice_flow_val_hdrs - validates packet segments for valid protocol headers
22131ad4e4eSTony Nguyen  * @segs: array of one or more packet segments that describe the flow
22231ad4e4eSTony Nguyen  * @segs_cnt: number of packet segments provided
22331ad4e4eSTony Nguyen  */
22431ad4e4eSTony Nguyen static enum ice_status
22531ad4e4eSTony Nguyen ice_flow_val_hdrs(struct ice_flow_seg_info *segs, u8 segs_cnt)
22631ad4e4eSTony Nguyen {
22731ad4e4eSTony Nguyen 	u8 i;
22831ad4e4eSTony Nguyen 
22931ad4e4eSTony Nguyen 	for (i = 0; i < segs_cnt; i++) {
23031ad4e4eSTony Nguyen 		/* Multiple L3 headers */
23131ad4e4eSTony Nguyen 		if (segs[i].hdrs & ICE_FLOW_SEG_HDRS_L3_MASK &&
23231ad4e4eSTony Nguyen 		    !is_power_of_2(segs[i].hdrs & ICE_FLOW_SEG_HDRS_L3_MASK))
23331ad4e4eSTony Nguyen 			return ICE_ERR_PARAM;
23431ad4e4eSTony Nguyen 
23531ad4e4eSTony Nguyen 		/* Multiple L4 headers */
23631ad4e4eSTony Nguyen 		if (segs[i].hdrs & ICE_FLOW_SEG_HDRS_L4_MASK &&
23731ad4e4eSTony Nguyen 		    !is_power_of_2(segs[i].hdrs & ICE_FLOW_SEG_HDRS_L4_MASK))
23831ad4e4eSTony Nguyen 			return ICE_ERR_PARAM;
23931ad4e4eSTony Nguyen 	}
24031ad4e4eSTony Nguyen 
24131ad4e4eSTony Nguyen 	return 0;
24231ad4e4eSTony Nguyen }
24331ad4e4eSTony Nguyen 
2442c57ffcbSHenry Tieman /* Sizes of fixed known protocol headers without header options */
2452c57ffcbSHenry Tieman #define ICE_FLOW_PROT_HDR_SZ_MAC	14
2462c57ffcbSHenry Tieman #define ICE_FLOW_PROT_HDR_SZ_IPV4	20
2472c57ffcbSHenry Tieman #define ICE_FLOW_PROT_HDR_SZ_IPV6	40
2482c57ffcbSHenry Tieman #define ICE_FLOW_PROT_HDR_SZ_TCP	20
2492c57ffcbSHenry Tieman #define ICE_FLOW_PROT_HDR_SZ_UDP	8
2502c57ffcbSHenry Tieman #define ICE_FLOW_PROT_HDR_SZ_SCTP	12
2512c57ffcbSHenry Tieman 
2522c57ffcbSHenry Tieman /**
2532c57ffcbSHenry Tieman  * ice_flow_calc_seg_sz - calculates size of a packet segment based on headers
2542c57ffcbSHenry Tieman  * @params: information about the flow to be processed
2552c57ffcbSHenry Tieman  * @seg: index of packet segment whose header size is to be determined
2562c57ffcbSHenry Tieman  */
2572c57ffcbSHenry Tieman static u16 ice_flow_calc_seg_sz(struct ice_flow_prof_params *params, u8 seg)
2582c57ffcbSHenry Tieman {
2592c57ffcbSHenry Tieman 	u16 sz = ICE_FLOW_PROT_HDR_SZ_MAC;
2602c57ffcbSHenry Tieman 
2612c57ffcbSHenry Tieman 	/* L3 headers */
2622c57ffcbSHenry Tieman 	if (params->prof->segs[seg].hdrs & ICE_FLOW_SEG_HDR_IPV4)
2632c57ffcbSHenry Tieman 		sz += ICE_FLOW_PROT_HDR_SZ_IPV4;
2642c57ffcbSHenry Tieman 	else if (params->prof->segs[seg].hdrs & ICE_FLOW_SEG_HDR_IPV6)
2652c57ffcbSHenry Tieman 		sz += ICE_FLOW_PROT_HDR_SZ_IPV6;
2662c57ffcbSHenry Tieman 
2672c57ffcbSHenry Tieman 	/* L4 headers */
2682c57ffcbSHenry Tieman 	if (params->prof->segs[seg].hdrs & ICE_FLOW_SEG_HDR_TCP)
2692c57ffcbSHenry Tieman 		sz += ICE_FLOW_PROT_HDR_SZ_TCP;
2702c57ffcbSHenry Tieman 	else if (params->prof->segs[seg].hdrs & ICE_FLOW_SEG_HDR_UDP)
2712c57ffcbSHenry Tieman 		sz += ICE_FLOW_PROT_HDR_SZ_UDP;
2722c57ffcbSHenry Tieman 	else if (params->prof->segs[seg].hdrs & ICE_FLOW_SEG_HDR_SCTP)
2732c57ffcbSHenry Tieman 		sz += ICE_FLOW_PROT_HDR_SZ_SCTP;
2742c57ffcbSHenry Tieman 
2752c57ffcbSHenry Tieman 	return sz;
2762c57ffcbSHenry Tieman }
2772c57ffcbSHenry Tieman 
27831ad4e4eSTony Nguyen /**
27931ad4e4eSTony Nguyen  * ice_flow_proc_seg_hdrs - process protocol headers present in pkt segments
28031ad4e4eSTony Nguyen  * @params: information about the flow to be processed
28131ad4e4eSTony Nguyen  *
28231ad4e4eSTony Nguyen  * This function identifies the packet types associated with the protocol
28331ad4e4eSTony Nguyen  * headers being present in packet segments of the specified flow profile.
28431ad4e4eSTony Nguyen  */
28531ad4e4eSTony Nguyen static enum ice_status
28631ad4e4eSTony Nguyen ice_flow_proc_seg_hdrs(struct ice_flow_prof_params *params)
28731ad4e4eSTony Nguyen {
28831ad4e4eSTony Nguyen 	struct ice_flow_prof *prof;
28931ad4e4eSTony Nguyen 	u8 i;
29031ad4e4eSTony Nguyen 
29131ad4e4eSTony Nguyen 	memset(params->ptypes, 0xff, sizeof(params->ptypes));
29231ad4e4eSTony Nguyen 
29331ad4e4eSTony Nguyen 	prof = params->prof;
29431ad4e4eSTony Nguyen 
29531ad4e4eSTony Nguyen 	for (i = 0; i < params->prof->segs_cnt; i++) {
29631ad4e4eSTony Nguyen 		const unsigned long *src;
29731ad4e4eSTony Nguyen 		u32 hdrs;
29831ad4e4eSTony Nguyen 
29931ad4e4eSTony Nguyen 		hdrs = prof->segs[i].hdrs;
30031ad4e4eSTony Nguyen 
301051d2b5cSDan Nowlin 		if ((hdrs & ICE_FLOW_SEG_HDR_IPV4) &&
302051d2b5cSDan Nowlin 		    !(hdrs & ICE_FLOW_SEG_HDRS_L4_MASK)) {
303051d2b5cSDan Nowlin 			src = !i ? (const unsigned long *)ice_ipv4_ofos_no_l4 :
304051d2b5cSDan Nowlin 				(const unsigned long *)ice_ipv4_il_no_l4;
305051d2b5cSDan Nowlin 			bitmap_and(params->ptypes, params->ptypes, src,
306051d2b5cSDan Nowlin 				   ICE_FLOW_PTYPE_MAX);
307051d2b5cSDan Nowlin 		} else if (hdrs & ICE_FLOW_SEG_HDR_IPV4) {
30831ad4e4eSTony Nguyen 			src = !i ? (const unsigned long *)ice_ptypes_ipv4_ofos :
30931ad4e4eSTony Nguyen 				(const unsigned long *)ice_ptypes_ipv4_il;
31031ad4e4eSTony Nguyen 			bitmap_and(params->ptypes, params->ptypes, src,
31131ad4e4eSTony Nguyen 				   ICE_FLOW_PTYPE_MAX);
312051d2b5cSDan Nowlin 		} else if ((hdrs & ICE_FLOW_SEG_HDR_IPV6) &&
313051d2b5cSDan Nowlin 			   !(hdrs & ICE_FLOW_SEG_HDRS_L4_MASK)) {
314051d2b5cSDan Nowlin 			src = !i ? (const unsigned long *)ice_ipv6_ofos_no_l4 :
315051d2b5cSDan Nowlin 				(const unsigned long *)ice_ipv6_il_no_l4;
316051d2b5cSDan Nowlin 			bitmap_and(params->ptypes, params->ptypes, src,
317051d2b5cSDan Nowlin 				   ICE_FLOW_PTYPE_MAX);
31831ad4e4eSTony Nguyen 		} else if (hdrs & ICE_FLOW_SEG_HDR_IPV6) {
31931ad4e4eSTony Nguyen 			src = !i ? (const unsigned long *)ice_ptypes_ipv6_ofos :
32031ad4e4eSTony Nguyen 				(const unsigned long *)ice_ptypes_ipv6_il;
32131ad4e4eSTony Nguyen 			bitmap_and(params->ptypes, params->ptypes, src,
32231ad4e4eSTony Nguyen 				   ICE_FLOW_PTYPE_MAX);
32331ad4e4eSTony Nguyen 		}
32431ad4e4eSTony Nguyen 
32531ad4e4eSTony Nguyen 		if (hdrs & ICE_FLOW_SEG_HDR_UDP) {
32631ad4e4eSTony Nguyen 			src = (const unsigned long *)ice_ptypes_udp_il;
32731ad4e4eSTony Nguyen 			bitmap_and(params->ptypes, params->ptypes, src,
32831ad4e4eSTony Nguyen 				   ICE_FLOW_PTYPE_MAX);
32931ad4e4eSTony Nguyen 		} else if (hdrs & ICE_FLOW_SEG_HDR_TCP) {
33031ad4e4eSTony Nguyen 			bitmap_and(params->ptypes, params->ptypes,
33131ad4e4eSTony Nguyen 				   (const unsigned long *)ice_ptypes_tcp_il,
33231ad4e4eSTony Nguyen 				   ICE_FLOW_PTYPE_MAX);
33331ad4e4eSTony Nguyen 		} else if (hdrs & ICE_FLOW_SEG_HDR_SCTP) {
33431ad4e4eSTony Nguyen 			src = (const unsigned long *)ice_ptypes_sctp_il;
33531ad4e4eSTony Nguyen 			bitmap_and(params->ptypes, params->ptypes, src,
33631ad4e4eSTony Nguyen 				   ICE_FLOW_PTYPE_MAX);
337a4e82a81STony Nguyen 		} else if (hdrs & ICE_FLOW_SEG_HDR_GRE) {
338a4e82a81STony Nguyen 			if (!i) {
339a4e82a81STony Nguyen 				src = (const unsigned long *)ice_ptypes_gre_of;
340a4e82a81STony Nguyen 				bitmap_and(params->ptypes, params->ptypes,
341a4e82a81STony Nguyen 					   src, ICE_FLOW_PTYPE_MAX);
342a4e82a81STony Nguyen 			}
34331ad4e4eSTony Nguyen 		}
34431ad4e4eSTony Nguyen 	}
34531ad4e4eSTony Nguyen 
34631ad4e4eSTony Nguyen 	return 0;
34731ad4e4eSTony Nguyen }
34831ad4e4eSTony Nguyen 
34931ad4e4eSTony Nguyen /**
35031ad4e4eSTony Nguyen  * ice_flow_xtract_fld - Create an extraction sequence entry for the given field
35131ad4e4eSTony Nguyen  * @hw: pointer to the HW struct
35231ad4e4eSTony Nguyen  * @params: information about the flow to be processed
35331ad4e4eSTony Nguyen  * @seg: packet segment index of the field to be extracted
35431ad4e4eSTony Nguyen  * @fld: ID of field to be extracted
35531ad4e4eSTony Nguyen  *
35631ad4e4eSTony Nguyen  * This function determines the protocol ID, offset, and size of the given
35731ad4e4eSTony Nguyen  * field. It then allocates one or more extraction sequence entries for the
35831ad4e4eSTony Nguyen  * given field, and fill the entries with protocol ID and offset information.
35931ad4e4eSTony Nguyen  */
36031ad4e4eSTony Nguyen static enum ice_status
36131ad4e4eSTony Nguyen ice_flow_xtract_fld(struct ice_hw *hw, struct ice_flow_prof_params *params,
36231ad4e4eSTony Nguyen 		    u8 seg, enum ice_flow_field fld)
36331ad4e4eSTony Nguyen {
36431ad4e4eSTony Nguyen 	enum ice_prot_id prot_id = ICE_PROT_ID_INVAL;
36531ad4e4eSTony Nguyen 	u8 fv_words = hw->blk[params->blk].es.fvw;
36631ad4e4eSTony Nguyen 	struct ice_flow_fld_info *flds;
36731ad4e4eSTony Nguyen 	u16 cnt, ese_bits, i;
36831ad4e4eSTony Nguyen 	u16 off;
36931ad4e4eSTony Nguyen 
37031ad4e4eSTony Nguyen 	flds = params->prof->segs[seg].fields;
37131ad4e4eSTony Nguyen 
37231ad4e4eSTony Nguyen 	switch (fld) {
37331ad4e4eSTony Nguyen 	case ICE_FLOW_FIELD_IDX_IPV4_SA:
37431ad4e4eSTony Nguyen 	case ICE_FLOW_FIELD_IDX_IPV4_DA:
37531ad4e4eSTony Nguyen 		prot_id = seg == 0 ? ICE_PROT_IPV4_OF_OR_S : ICE_PROT_IPV4_IL;
37631ad4e4eSTony Nguyen 		break;
37731ad4e4eSTony Nguyen 	case ICE_FLOW_FIELD_IDX_IPV6_SA:
37831ad4e4eSTony Nguyen 	case ICE_FLOW_FIELD_IDX_IPV6_DA:
37931ad4e4eSTony Nguyen 		prot_id = seg == 0 ? ICE_PROT_IPV6_OF_OR_S : ICE_PROT_IPV6_IL;
38031ad4e4eSTony Nguyen 		break;
38131ad4e4eSTony Nguyen 	case ICE_FLOW_FIELD_IDX_TCP_SRC_PORT:
38231ad4e4eSTony Nguyen 	case ICE_FLOW_FIELD_IDX_TCP_DST_PORT:
38331ad4e4eSTony Nguyen 		prot_id = ICE_PROT_TCP_IL;
38431ad4e4eSTony Nguyen 		break;
38531ad4e4eSTony Nguyen 	case ICE_FLOW_FIELD_IDX_UDP_SRC_PORT:
38631ad4e4eSTony Nguyen 	case ICE_FLOW_FIELD_IDX_UDP_DST_PORT:
38731ad4e4eSTony Nguyen 		prot_id = ICE_PROT_UDP_IL_OR_S;
38831ad4e4eSTony Nguyen 		break;
3891c01c8c6SMd Fahad Iqbal Polash 	case ICE_FLOW_FIELD_IDX_SCTP_SRC_PORT:
3901c01c8c6SMd Fahad Iqbal Polash 	case ICE_FLOW_FIELD_IDX_SCTP_DST_PORT:
3911c01c8c6SMd Fahad Iqbal Polash 		prot_id = ICE_PROT_SCTP_IL;
3921c01c8c6SMd Fahad Iqbal Polash 		break;
393a4e82a81STony Nguyen 	case ICE_FLOW_FIELD_IDX_GRE_KEYID:
394a4e82a81STony Nguyen 		prot_id = ICE_PROT_GRE_OF;
395a4e82a81STony Nguyen 		break;
39631ad4e4eSTony Nguyen 	default:
39731ad4e4eSTony Nguyen 		return ICE_ERR_NOT_IMPL;
39831ad4e4eSTony Nguyen 	}
39931ad4e4eSTony Nguyen 
40031ad4e4eSTony Nguyen 	/* Each extraction sequence entry is a word in size, and extracts a
40131ad4e4eSTony Nguyen 	 * word-aligned offset from a protocol header.
40231ad4e4eSTony Nguyen 	 */
40331ad4e4eSTony Nguyen 	ese_bits = ICE_FLOW_FV_EXTRACT_SZ * BITS_PER_BYTE;
40431ad4e4eSTony Nguyen 
40531ad4e4eSTony Nguyen 	flds[fld].xtrct.prot_id = prot_id;
40631ad4e4eSTony Nguyen 	flds[fld].xtrct.off = (ice_flds_info[fld].off / ese_bits) *
40731ad4e4eSTony Nguyen 		ICE_FLOW_FV_EXTRACT_SZ;
40831ad4e4eSTony Nguyen 	flds[fld].xtrct.disp = (u8)(ice_flds_info[fld].off % ese_bits);
40931ad4e4eSTony Nguyen 	flds[fld].xtrct.idx = params->es_cnt;
41031ad4e4eSTony Nguyen 
41131ad4e4eSTony Nguyen 	/* Adjust the next field-entry index after accommodating the number of
41231ad4e4eSTony Nguyen 	 * entries this field consumes
41331ad4e4eSTony Nguyen 	 */
41431ad4e4eSTony Nguyen 	cnt = DIV_ROUND_UP(flds[fld].xtrct.disp + ice_flds_info[fld].size,
41531ad4e4eSTony Nguyen 			   ese_bits);
41631ad4e4eSTony Nguyen 
41731ad4e4eSTony Nguyen 	/* Fill in the extraction sequence entries needed for this field */
41831ad4e4eSTony Nguyen 	off = flds[fld].xtrct.off;
41931ad4e4eSTony Nguyen 	for (i = 0; i < cnt; i++) {
42031ad4e4eSTony Nguyen 		u8 idx;
42131ad4e4eSTony Nguyen 
42231ad4e4eSTony Nguyen 		/* Make sure the number of extraction sequence required
42331ad4e4eSTony Nguyen 		 * does not exceed the block's capability
42431ad4e4eSTony Nguyen 		 */
42531ad4e4eSTony Nguyen 		if (params->es_cnt >= fv_words)
42631ad4e4eSTony Nguyen 			return ICE_ERR_MAX_LIMIT;
42731ad4e4eSTony Nguyen 
42831ad4e4eSTony Nguyen 		/* some blocks require a reversed field vector layout */
42931ad4e4eSTony Nguyen 		if (hw->blk[params->blk].es.reverse)
43031ad4e4eSTony Nguyen 			idx = fv_words - params->es_cnt - 1;
43131ad4e4eSTony Nguyen 		else
43231ad4e4eSTony Nguyen 			idx = params->es_cnt;
43331ad4e4eSTony Nguyen 
43431ad4e4eSTony Nguyen 		params->es[idx].prot_id = prot_id;
43531ad4e4eSTony Nguyen 		params->es[idx].off = off;
43631ad4e4eSTony Nguyen 		params->es_cnt++;
43731ad4e4eSTony Nguyen 
43831ad4e4eSTony Nguyen 		off += ICE_FLOW_FV_EXTRACT_SZ;
43931ad4e4eSTony Nguyen 	}
44031ad4e4eSTony Nguyen 
44131ad4e4eSTony Nguyen 	return 0;
44231ad4e4eSTony Nguyen }
44331ad4e4eSTony Nguyen 
44431ad4e4eSTony Nguyen /**
4452c57ffcbSHenry Tieman  * ice_flow_xtract_raws - Create extract sequence entries for raw bytes
4462c57ffcbSHenry Tieman  * @hw: pointer to the HW struct
4472c57ffcbSHenry Tieman  * @params: information about the flow to be processed
448ac382a09SBruce Allan  * @seg: index of packet segment whose raw fields are to be extracted
4492c57ffcbSHenry Tieman  */
4502c57ffcbSHenry Tieman static enum ice_status
4512c57ffcbSHenry Tieman ice_flow_xtract_raws(struct ice_hw *hw, struct ice_flow_prof_params *params,
4522c57ffcbSHenry Tieman 		     u8 seg)
4532c57ffcbSHenry Tieman {
4542c57ffcbSHenry Tieman 	u16 fv_words;
4552c57ffcbSHenry Tieman 	u16 hdrs_sz;
4562c57ffcbSHenry Tieman 	u8 i;
4572c57ffcbSHenry Tieman 
4582c57ffcbSHenry Tieman 	if (!params->prof->segs[seg].raws_cnt)
4592c57ffcbSHenry Tieman 		return 0;
4602c57ffcbSHenry Tieman 
4612c57ffcbSHenry Tieman 	if (params->prof->segs[seg].raws_cnt >
4622c57ffcbSHenry Tieman 	    ARRAY_SIZE(params->prof->segs[seg].raws))
4632c57ffcbSHenry Tieman 		return ICE_ERR_MAX_LIMIT;
4642c57ffcbSHenry Tieman 
4652c57ffcbSHenry Tieman 	/* Offsets within the segment headers are not supported */
4662c57ffcbSHenry Tieman 	hdrs_sz = ice_flow_calc_seg_sz(params, seg);
4672c57ffcbSHenry Tieman 	if (!hdrs_sz)
4682c57ffcbSHenry Tieman 		return ICE_ERR_PARAM;
4692c57ffcbSHenry Tieman 
4702c57ffcbSHenry Tieman 	fv_words = hw->blk[params->blk].es.fvw;
4712c57ffcbSHenry Tieman 
4722c57ffcbSHenry Tieman 	for (i = 0; i < params->prof->segs[seg].raws_cnt; i++) {
4732c57ffcbSHenry Tieman 		struct ice_flow_seg_fld_raw *raw;
4742c57ffcbSHenry Tieman 		u16 off, cnt, j;
4752c57ffcbSHenry Tieman 
4762c57ffcbSHenry Tieman 		raw = &params->prof->segs[seg].raws[i];
4772c57ffcbSHenry Tieman 
4782c57ffcbSHenry Tieman 		/* Storing extraction information */
4792c57ffcbSHenry Tieman 		raw->info.xtrct.prot_id = ICE_PROT_MAC_OF_OR_S;
4802c57ffcbSHenry Tieman 		raw->info.xtrct.off = (raw->off / ICE_FLOW_FV_EXTRACT_SZ) *
4812c57ffcbSHenry Tieman 			ICE_FLOW_FV_EXTRACT_SZ;
4822c57ffcbSHenry Tieman 		raw->info.xtrct.disp = (raw->off % ICE_FLOW_FV_EXTRACT_SZ) *
4832c57ffcbSHenry Tieman 			BITS_PER_BYTE;
4842c57ffcbSHenry Tieman 		raw->info.xtrct.idx = params->es_cnt;
4852c57ffcbSHenry Tieman 
4862c57ffcbSHenry Tieman 		/* Determine the number of field vector entries this raw field
4872c57ffcbSHenry Tieman 		 * consumes.
4882c57ffcbSHenry Tieman 		 */
4892c57ffcbSHenry Tieman 		cnt = DIV_ROUND_UP(raw->info.xtrct.disp +
4902c57ffcbSHenry Tieman 				   (raw->info.src.last * BITS_PER_BYTE),
4912c57ffcbSHenry Tieman 				   (ICE_FLOW_FV_EXTRACT_SZ * BITS_PER_BYTE));
4922c57ffcbSHenry Tieman 		off = raw->info.xtrct.off;
4932c57ffcbSHenry Tieman 		for (j = 0; j < cnt; j++) {
4942c57ffcbSHenry Tieman 			u16 idx;
4952c57ffcbSHenry Tieman 
4962c57ffcbSHenry Tieman 			/* Make sure the number of extraction sequence required
4972c57ffcbSHenry Tieman 			 * does not exceed the block's capability
4982c57ffcbSHenry Tieman 			 */
4992c57ffcbSHenry Tieman 			if (params->es_cnt >= hw->blk[params->blk].es.count ||
5002c57ffcbSHenry Tieman 			    params->es_cnt >= ICE_MAX_FV_WORDS)
5012c57ffcbSHenry Tieman 				return ICE_ERR_MAX_LIMIT;
5022c57ffcbSHenry Tieman 
5032c57ffcbSHenry Tieman 			/* some blocks require a reversed field vector layout */
5042c57ffcbSHenry Tieman 			if (hw->blk[params->blk].es.reverse)
5052c57ffcbSHenry Tieman 				idx = fv_words - params->es_cnt - 1;
5062c57ffcbSHenry Tieman 			else
5072c57ffcbSHenry Tieman 				idx = params->es_cnt;
5082c57ffcbSHenry Tieman 
5092c57ffcbSHenry Tieman 			params->es[idx].prot_id = raw->info.xtrct.prot_id;
5102c57ffcbSHenry Tieman 			params->es[idx].off = off;
5112c57ffcbSHenry Tieman 			params->es_cnt++;
5122c57ffcbSHenry Tieman 			off += ICE_FLOW_FV_EXTRACT_SZ;
5132c57ffcbSHenry Tieman 		}
5142c57ffcbSHenry Tieman 	}
5152c57ffcbSHenry Tieman 
5162c57ffcbSHenry Tieman 	return 0;
5172c57ffcbSHenry Tieman }
5182c57ffcbSHenry Tieman 
5192c57ffcbSHenry Tieman /**
52031ad4e4eSTony Nguyen  * ice_flow_create_xtrct_seq - Create an extraction sequence for given segments
52131ad4e4eSTony Nguyen  * @hw: pointer to the HW struct
52231ad4e4eSTony Nguyen  * @params: information about the flow to be processed
52331ad4e4eSTony Nguyen  *
52431ad4e4eSTony Nguyen  * This function iterates through all matched fields in the given segments, and
52531ad4e4eSTony Nguyen  * creates an extraction sequence for the fields.
52631ad4e4eSTony Nguyen  */
52731ad4e4eSTony Nguyen static enum ice_status
52831ad4e4eSTony Nguyen ice_flow_create_xtrct_seq(struct ice_hw *hw,
52931ad4e4eSTony Nguyen 			  struct ice_flow_prof_params *params)
53031ad4e4eSTony Nguyen {
53131ad4e4eSTony Nguyen 	struct ice_flow_prof *prof = params->prof;
53231ad4e4eSTony Nguyen 	enum ice_status status = 0;
53331ad4e4eSTony Nguyen 	u8 i;
53431ad4e4eSTony Nguyen 
53531ad4e4eSTony Nguyen 	for (i = 0; i < prof->segs_cnt; i++) {
53631ad4e4eSTony Nguyen 		u8 j;
53731ad4e4eSTony Nguyen 
53831ad4e4eSTony Nguyen 		for_each_set_bit(j, (unsigned long *)&prof->segs[i].match,
53931ad4e4eSTony Nguyen 				 ICE_FLOW_FIELD_IDX_MAX) {
54031ad4e4eSTony Nguyen 			status = ice_flow_xtract_fld(hw, params, i,
54131ad4e4eSTony Nguyen 						     (enum ice_flow_field)j);
54231ad4e4eSTony Nguyen 			if (status)
54331ad4e4eSTony Nguyen 				return status;
54431ad4e4eSTony Nguyen 		}
5452c57ffcbSHenry Tieman 
5462c57ffcbSHenry Tieman 		/* Process raw matching bytes */
5472c57ffcbSHenry Tieman 		status = ice_flow_xtract_raws(hw, params, i);
5482c57ffcbSHenry Tieman 		if (status)
5492c57ffcbSHenry Tieman 			return status;
55031ad4e4eSTony Nguyen 	}
55131ad4e4eSTony Nguyen 
55231ad4e4eSTony Nguyen 	return status;
55331ad4e4eSTony Nguyen }
55431ad4e4eSTony Nguyen 
55531ad4e4eSTony Nguyen /**
55631ad4e4eSTony Nguyen  * ice_flow_proc_segs - process all packet segments associated with a profile
55731ad4e4eSTony Nguyen  * @hw: pointer to the HW struct
55831ad4e4eSTony Nguyen  * @params: information about the flow to be processed
55931ad4e4eSTony Nguyen  */
56031ad4e4eSTony Nguyen static enum ice_status
56131ad4e4eSTony Nguyen ice_flow_proc_segs(struct ice_hw *hw, struct ice_flow_prof_params *params)
56231ad4e4eSTony Nguyen {
56331ad4e4eSTony Nguyen 	enum ice_status status;
56431ad4e4eSTony Nguyen 
56531ad4e4eSTony Nguyen 	status = ice_flow_proc_seg_hdrs(params);
56631ad4e4eSTony Nguyen 	if (status)
56731ad4e4eSTony Nguyen 		return status;
56831ad4e4eSTony Nguyen 
56931ad4e4eSTony Nguyen 	status = ice_flow_create_xtrct_seq(hw, params);
57031ad4e4eSTony Nguyen 	if (status)
57131ad4e4eSTony Nguyen 		return status;
57231ad4e4eSTony Nguyen 
57331ad4e4eSTony Nguyen 	switch (params->blk) {
574148beb61SHenry Tieman 	case ICE_BLK_FD:
57531ad4e4eSTony Nguyen 	case ICE_BLK_RSS:
57631ad4e4eSTony Nguyen 		status = 0;
57731ad4e4eSTony Nguyen 		break;
57831ad4e4eSTony Nguyen 	default:
57931ad4e4eSTony Nguyen 		return ICE_ERR_NOT_IMPL;
58031ad4e4eSTony Nguyen 	}
58131ad4e4eSTony Nguyen 
58231ad4e4eSTony Nguyen 	return status;
58331ad4e4eSTony Nguyen }
58431ad4e4eSTony Nguyen 
5852c61054cSTony Nguyen #define ICE_FLOW_FIND_PROF_CHK_FLDS	0x00000001
5862c61054cSTony Nguyen #define ICE_FLOW_FIND_PROF_CHK_VSI	0x00000002
5872c61054cSTony Nguyen #define ICE_FLOW_FIND_PROF_NOT_CHK_DIR	0x00000004
5882c61054cSTony Nguyen 
5892c61054cSTony Nguyen /**
5902c61054cSTony Nguyen  * ice_flow_find_prof_conds - Find a profile matching headers and conditions
5912c61054cSTony Nguyen  * @hw: pointer to the HW struct
5922c61054cSTony Nguyen  * @blk: classification stage
5932c61054cSTony Nguyen  * @dir: flow direction
5942c61054cSTony Nguyen  * @segs: array of one or more packet segments that describe the flow
5952c61054cSTony Nguyen  * @segs_cnt: number of packet segments provided
5962c61054cSTony Nguyen  * @vsi_handle: software VSI handle to check VSI (ICE_FLOW_FIND_PROF_CHK_VSI)
5972c61054cSTony Nguyen  * @conds: additional conditions to be checked (ICE_FLOW_FIND_PROF_CHK_*)
5982c61054cSTony Nguyen  */
5992c61054cSTony Nguyen static struct ice_flow_prof *
6002c61054cSTony Nguyen ice_flow_find_prof_conds(struct ice_hw *hw, enum ice_block blk,
6012c61054cSTony Nguyen 			 enum ice_flow_dir dir, struct ice_flow_seg_info *segs,
6022c61054cSTony Nguyen 			 u8 segs_cnt, u16 vsi_handle, u32 conds)
6032c61054cSTony Nguyen {
6042c61054cSTony Nguyen 	struct ice_flow_prof *p, *prof = NULL;
6052c61054cSTony Nguyen 
6062c61054cSTony Nguyen 	mutex_lock(&hw->fl_profs_locks[blk]);
6072c61054cSTony Nguyen 	list_for_each_entry(p, &hw->fl_profs[blk], l_entry)
6082c61054cSTony Nguyen 		if ((p->dir == dir || conds & ICE_FLOW_FIND_PROF_NOT_CHK_DIR) &&
6092c61054cSTony Nguyen 		    segs_cnt && segs_cnt == p->segs_cnt) {
6102c61054cSTony Nguyen 			u8 i;
6112c61054cSTony Nguyen 
6122c61054cSTony Nguyen 			/* Check for profile-VSI association if specified */
6132c61054cSTony Nguyen 			if ((conds & ICE_FLOW_FIND_PROF_CHK_VSI) &&
6142c61054cSTony Nguyen 			    ice_is_vsi_valid(hw, vsi_handle) &&
6152c61054cSTony Nguyen 			    !test_bit(vsi_handle, p->vsis))
6162c61054cSTony Nguyen 				continue;
6172c61054cSTony Nguyen 
6182c61054cSTony Nguyen 			/* Protocol headers must be checked. Matched fields are
6192c61054cSTony Nguyen 			 * checked if specified.
6202c61054cSTony Nguyen 			 */
6212c61054cSTony Nguyen 			for (i = 0; i < segs_cnt; i++)
6222c61054cSTony Nguyen 				if (segs[i].hdrs != p->segs[i].hdrs ||
6232c61054cSTony Nguyen 				    ((conds & ICE_FLOW_FIND_PROF_CHK_FLDS) &&
6242c61054cSTony Nguyen 				     segs[i].match != p->segs[i].match))
6252c61054cSTony Nguyen 					break;
6262c61054cSTony Nguyen 
6272c61054cSTony Nguyen 			/* A match is found if all segments are matched */
6282c61054cSTony Nguyen 			if (i == segs_cnt) {
6292c61054cSTony Nguyen 				prof = p;
6302c61054cSTony Nguyen 				break;
6312c61054cSTony Nguyen 			}
6322c61054cSTony Nguyen 		}
6332c61054cSTony Nguyen 	mutex_unlock(&hw->fl_profs_locks[blk]);
6342c61054cSTony Nguyen 
6352c61054cSTony Nguyen 	return prof;
6362c61054cSTony Nguyen }
6372c61054cSTony Nguyen 
6382c61054cSTony Nguyen /**
6392c61054cSTony Nguyen  * ice_flow_find_prof_id - Look up a profile with given profile ID
6402c61054cSTony Nguyen  * @hw: pointer to the HW struct
6412c61054cSTony Nguyen  * @blk: classification stage
6422c61054cSTony Nguyen  * @prof_id: unique ID to identify this flow profile
6432c61054cSTony Nguyen  */
6442c61054cSTony Nguyen static struct ice_flow_prof *
6452c61054cSTony Nguyen ice_flow_find_prof_id(struct ice_hw *hw, enum ice_block blk, u64 prof_id)
6462c61054cSTony Nguyen {
6472c61054cSTony Nguyen 	struct ice_flow_prof *p;
6482c61054cSTony Nguyen 
6492c61054cSTony Nguyen 	list_for_each_entry(p, &hw->fl_profs[blk], l_entry)
6502c61054cSTony Nguyen 		if (p->id == prof_id)
6512c61054cSTony Nguyen 			return p;
6522c61054cSTony Nguyen 
6532c61054cSTony Nguyen 	return NULL;
6542c61054cSTony Nguyen }
6552c61054cSTony Nguyen 
65631ad4e4eSTony Nguyen /**
657148beb61SHenry Tieman  * ice_dealloc_flow_entry - Deallocate flow entry memory
658148beb61SHenry Tieman  * @hw: pointer to the HW struct
659148beb61SHenry Tieman  * @entry: flow entry to be removed
660148beb61SHenry Tieman  */
661148beb61SHenry Tieman static void
662148beb61SHenry Tieman ice_dealloc_flow_entry(struct ice_hw *hw, struct ice_flow_entry *entry)
663148beb61SHenry Tieman {
664148beb61SHenry Tieman 	if (!entry)
665148beb61SHenry Tieman 		return;
666148beb61SHenry Tieman 
667148beb61SHenry Tieman 	if (entry->entry)
668148beb61SHenry Tieman 		devm_kfree(ice_hw_to_dev(hw), entry->entry);
669148beb61SHenry Tieman 
670148beb61SHenry Tieman 	devm_kfree(ice_hw_to_dev(hw), entry);
671148beb61SHenry Tieman }
672148beb61SHenry Tieman 
673148beb61SHenry Tieman /**
674148beb61SHenry Tieman  * ice_flow_rem_entry_sync - Remove a flow entry
675148beb61SHenry Tieman  * @hw: pointer to the HW struct
676148beb61SHenry Tieman  * @blk: classification stage
677148beb61SHenry Tieman  * @entry: flow entry to be removed
678148beb61SHenry Tieman  */
679148beb61SHenry Tieman static enum ice_status
680148beb61SHenry Tieman ice_flow_rem_entry_sync(struct ice_hw *hw, enum ice_block __always_unused blk,
681148beb61SHenry Tieman 			struct ice_flow_entry *entry)
682148beb61SHenry Tieman {
683148beb61SHenry Tieman 	if (!entry)
684148beb61SHenry Tieman 		return ICE_ERR_BAD_PTR;
685148beb61SHenry Tieman 
686148beb61SHenry Tieman 	list_del(&entry->l_entry);
687148beb61SHenry Tieman 
688148beb61SHenry Tieman 	ice_dealloc_flow_entry(hw, entry);
689148beb61SHenry Tieman 
690148beb61SHenry Tieman 	return 0;
691148beb61SHenry Tieman }
692148beb61SHenry Tieman 
693148beb61SHenry Tieman /**
69431ad4e4eSTony Nguyen  * ice_flow_add_prof_sync - Add a flow profile for packet segments and fields
69531ad4e4eSTony Nguyen  * @hw: pointer to the HW struct
69631ad4e4eSTony Nguyen  * @blk: classification stage
69731ad4e4eSTony Nguyen  * @dir: flow direction
69831ad4e4eSTony Nguyen  * @prof_id: unique ID to identify this flow profile
69931ad4e4eSTony Nguyen  * @segs: array of one or more packet segments that describe the flow
70031ad4e4eSTony Nguyen  * @segs_cnt: number of packet segments provided
70131ad4e4eSTony Nguyen  * @prof: stores the returned flow profile added
70231ad4e4eSTony Nguyen  *
70331ad4e4eSTony Nguyen  * Assumption: the caller has acquired the lock to the profile list
70431ad4e4eSTony Nguyen  */
70531ad4e4eSTony Nguyen static enum ice_status
70631ad4e4eSTony Nguyen ice_flow_add_prof_sync(struct ice_hw *hw, enum ice_block blk,
70731ad4e4eSTony Nguyen 		       enum ice_flow_dir dir, u64 prof_id,
70831ad4e4eSTony Nguyen 		       struct ice_flow_seg_info *segs, u8 segs_cnt,
70931ad4e4eSTony Nguyen 		       struct ice_flow_prof **prof)
71031ad4e4eSTony Nguyen {
711*88dcfdb4SBruce Allan 	struct ice_flow_prof_params *params;
71231ad4e4eSTony Nguyen 	enum ice_status status;
71331ad4e4eSTony Nguyen 	u8 i;
71431ad4e4eSTony Nguyen 
71531ad4e4eSTony Nguyen 	if (!prof)
71631ad4e4eSTony Nguyen 		return ICE_ERR_BAD_PTR;
71731ad4e4eSTony Nguyen 
718*88dcfdb4SBruce Allan 	params = kzalloc(sizeof(*params), GFP_KERNEL);
719*88dcfdb4SBruce Allan 	if (!params)
72031ad4e4eSTony Nguyen 		return ICE_ERR_NO_MEMORY;
72131ad4e4eSTony Nguyen 
722*88dcfdb4SBruce Allan 	params->prof = devm_kzalloc(ice_hw_to_dev(hw), sizeof(*params->prof),
723*88dcfdb4SBruce Allan 				    GFP_KERNEL);
724*88dcfdb4SBruce Allan 	if (!params->prof) {
725*88dcfdb4SBruce Allan 		status = ICE_ERR_NO_MEMORY;
726*88dcfdb4SBruce Allan 		goto free_params;
727*88dcfdb4SBruce Allan 	}
728*88dcfdb4SBruce Allan 
72931ad4e4eSTony Nguyen 	/* initialize extraction sequence to all invalid (0xff) */
73031ad4e4eSTony Nguyen 	for (i = 0; i < ICE_MAX_FV_WORDS; i++) {
731*88dcfdb4SBruce Allan 		params->es[i].prot_id = ICE_PROT_INVALID;
732*88dcfdb4SBruce Allan 		params->es[i].off = ICE_FV_OFFSET_INVAL;
73331ad4e4eSTony Nguyen 	}
73431ad4e4eSTony Nguyen 
735*88dcfdb4SBruce Allan 	params->blk = blk;
736*88dcfdb4SBruce Allan 	params->prof->id = prof_id;
737*88dcfdb4SBruce Allan 	params->prof->dir = dir;
738*88dcfdb4SBruce Allan 	params->prof->segs_cnt = segs_cnt;
73931ad4e4eSTony Nguyen 
74031ad4e4eSTony Nguyen 	/* Make a copy of the segments that need to be persistent in the flow
74131ad4e4eSTony Nguyen 	 * profile instance
74231ad4e4eSTony Nguyen 	 */
74331ad4e4eSTony Nguyen 	for (i = 0; i < segs_cnt; i++)
744*88dcfdb4SBruce Allan 		memcpy(&params->prof->segs[i], &segs[i], sizeof(*segs));
74531ad4e4eSTony Nguyen 
746*88dcfdb4SBruce Allan 	status = ice_flow_proc_segs(hw, params);
74731ad4e4eSTony Nguyen 	if (status) {
74831ad4e4eSTony Nguyen 		ice_debug(hw, ICE_DBG_FLOW,
74931ad4e4eSTony Nguyen 			  "Error processing a flow's packet segments\n");
75031ad4e4eSTony Nguyen 		goto out;
75131ad4e4eSTony Nguyen 	}
75231ad4e4eSTony Nguyen 
75331ad4e4eSTony Nguyen 	/* Add a HW profile for this flow profile */
754*88dcfdb4SBruce Allan 	status = ice_add_prof(hw, blk, prof_id, (u8 *)params->ptypes,
755*88dcfdb4SBruce Allan 			      params->es);
75631ad4e4eSTony Nguyen 	if (status) {
75731ad4e4eSTony Nguyen 		ice_debug(hw, ICE_DBG_FLOW, "Error adding a HW flow profile\n");
75831ad4e4eSTony Nguyen 		goto out;
75931ad4e4eSTony Nguyen 	}
76031ad4e4eSTony Nguyen 
761*88dcfdb4SBruce Allan 	INIT_LIST_HEAD(&params->prof->entries);
762*88dcfdb4SBruce Allan 	mutex_init(&params->prof->entries_lock);
763*88dcfdb4SBruce Allan 	*prof = params->prof;
76431ad4e4eSTony Nguyen 
76531ad4e4eSTony Nguyen out:
76631ad4e4eSTony Nguyen 	if (status)
767*88dcfdb4SBruce Allan 		devm_kfree(ice_hw_to_dev(hw), params->prof);
768*88dcfdb4SBruce Allan free_params:
769*88dcfdb4SBruce Allan 	kfree(params);
77031ad4e4eSTony Nguyen 
77131ad4e4eSTony Nguyen 	return status;
77231ad4e4eSTony Nguyen }
77331ad4e4eSTony Nguyen 
77431ad4e4eSTony Nguyen /**
7752c61054cSTony Nguyen  * ice_flow_rem_prof_sync - remove a flow profile
7762c61054cSTony Nguyen  * @hw: pointer to the hardware structure
7772c61054cSTony Nguyen  * @blk: classification stage
7782c61054cSTony Nguyen  * @prof: pointer to flow profile to remove
7792c61054cSTony Nguyen  *
7802c61054cSTony Nguyen  * Assumption: the caller has acquired the lock to the profile list
7812c61054cSTony Nguyen  */
7822c61054cSTony Nguyen static enum ice_status
7832c61054cSTony Nguyen ice_flow_rem_prof_sync(struct ice_hw *hw, enum ice_block blk,
7842c61054cSTony Nguyen 		       struct ice_flow_prof *prof)
7852c61054cSTony Nguyen {
7862c61054cSTony Nguyen 	enum ice_status status;
7872c61054cSTony Nguyen 
788148beb61SHenry Tieman 	/* Remove all remaining flow entries before removing the flow profile */
789148beb61SHenry Tieman 	if (!list_empty(&prof->entries)) {
790148beb61SHenry Tieman 		struct ice_flow_entry *e, *t;
791148beb61SHenry Tieman 
792148beb61SHenry Tieman 		mutex_lock(&prof->entries_lock);
793148beb61SHenry Tieman 
794148beb61SHenry Tieman 		list_for_each_entry_safe(e, t, &prof->entries, l_entry) {
795148beb61SHenry Tieman 			status = ice_flow_rem_entry_sync(hw, blk, e);
796148beb61SHenry Tieman 			if (status)
797148beb61SHenry Tieman 				break;
798148beb61SHenry Tieman 		}
799148beb61SHenry Tieman 
800148beb61SHenry Tieman 		mutex_unlock(&prof->entries_lock);
801148beb61SHenry Tieman 	}
802148beb61SHenry Tieman 
8032c61054cSTony Nguyen 	/* Remove all hardware profiles associated with this flow profile */
8042c61054cSTony Nguyen 	status = ice_rem_prof(hw, blk, prof->id);
8052c61054cSTony Nguyen 	if (!status) {
8062c61054cSTony Nguyen 		list_del(&prof->l_entry);
8072c61054cSTony Nguyen 		mutex_destroy(&prof->entries_lock);
8082c61054cSTony Nguyen 		devm_kfree(ice_hw_to_dev(hw), prof);
8092c61054cSTony Nguyen 	}
8102c61054cSTony Nguyen 
8112c61054cSTony Nguyen 	return status;
8122c61054cSTony Nguyen }
8132c61054cSTony Nguyen 
8142c61054cSTony Nguyen /**
815451f2c44STony Nguyen  * ice_flow_assoc_prof - associate a VSI with a flow profile
816451f2c44STony Nguyen  * @hw: pointer to the hardware structure
817451f2c44STony Nguyen  * @blk: classification stage
818451f2c44STony Nguyen  * @prof: pointer to flow profile
819451f2c44STony Nguyen  * @vsi_handle: software VSI handle
820451f2c44STony Nguyen  *
821451f2c44STony Nguyen  * Assumption: the caller has acquired the lock to the profile list
822451f2c44STony Nguyen  * and the software VSI handle has been validated
823451f2c44STony Nguyen  */
824451f2c44STony Nguyen static enum ice_status
825451f2c44STony Nguyen ice_flow_assoc_prof(struct ice_hw *hw, enum ice_block blk,
826451f2c44STony Nguyen 		    struct ice_flow_prof *prof, u16 vsi_handle)
827451f2c44STony Nguyen {
828451f2c44STony Nguyen 	enum ice_status status = 0;
829451f2c44STony Nguyen 
830451f2c44STony Nguyen 	if (!test_bit(vsi_handle, prof->vsis)) {
831451f2c44STony Nguyen 		status = ice_add_prof_id_flow(hw, blk,
832451f2c44STony Nguyen 					      ice_get_hw_vsi_num(hw,
833451f2c44STony Nguyen 								 vsi_handle),
834451f2c44STony Nguyen 					      prof->id);
835451f2c44STony Nguyen 		if (!status)
836451f2c44STony Nguyen 			set_bit(vsi_handle, prof->vsis);
837451f2c44STony Nguyen 		else
838451f2c44STony Nguyen 			ice_debug(hw, ICE_DBG_FLOW,
839451f2c44STony Nguyen 				  "HW profile add failed, %d\n",
840451f2c44STony Nguyen 				  status);
841451f2c44STony Nguyen 	}
842451f2c44STony Nguyen 
843451f2c44STony Nguyen 	return status;
844451f2c44STony Nguyen }
845451f2c44STony Nguyen 
846451f2c44STony Nguyen /**
8472c61054cSTony Nguyen  * ice_flow_disassoc_prof - disassociate a VSI from a flow profile
8482c61054cSTony Nguyen  * @hw: pointer to the hardware structure
8492c61054cSTony Nguyen  * @blk: classification stage
8502c61054cSTony Nguyen  * @prof: pointer to flow profile
8512c61054cSTony Nguyen  * @vsi_handle: software VSI handle
8522c61054cSTony Nguyen  *
8532c61054cSTony Nguyen  * Assumption: the caller has acquired the lock to the profile list
8542c61054cSTony Nguyen  * and the software VSI handle has been validated
8552c61054cSTony Nguyen  */
8562c61054cSTony Nguyen static enum ice_status
8572c61054cSTony Nguyen ice_flow_disassoc_prof(struct ice_hw *hw, enum ice_block blk,
8582c61054cSTony Nguyen 		       struct ice_flow_prof *prof, u16 vsi_handle)
8592c61054cSTony Nguyen {
8602c61054cSTony Nguyen 	enum ice_status status = 0;
8612c61054cSTony Nguyen 
8622c61054cSTony Nguyen 	if (test_bit(vsi_handle, prof->vsis)) {
8632c61054cSTony Nguyen 		status = ice_rem_prof_id_flow(hw, blk,
8642c61054cSTony Nguyen 					      ice_get_hw_vsi_num(hw,
8652c61054cSTony Nguyen 								 vsi_handle),
8662c61054cSTony Nguyen 					      prof->id);
8672c61054cSTony Nguyen 		if (!status)
8682c61054cSTony Nguyen 			clear_bit(vsi_handle, prof->vsis);
8692c61054cSTony Nguyen 		else
8702c61054cSTony Nguyen 			ice_debug(hw, ICE_DBG_FLOW,
8712c61054cSTony Nguyen 				  "HW profile remove failed, %d\n",
8722c61054cSTony Nguyen 				  status);
8732c61054cSTony Nguyen 	}
8742c61054cSTony Nguyen 
8752c61054cSTony Nguyen 	return status;
8762c61054cSTony Nguyen }
8772c61054cSTony Nguyen 
8782c61054cSTony Nguyen /**
87931ad4e4eSTony Nguyen  * ice_flow_add_prof - Add a flow profile for packet segments and matched fields
88031ad4e4eSTony Nguyen  * @hw: pointer to the HW struct
88131ad4e4eSTony Nguyen  * @blk: classification stage
88231ad4e4eSTony Nguyen  * @dir: flow direction
88331ad4e4eSTony Nguyen  * @prof_id: unique ID to identify this flow profile
88431ad4e4eSTony Nguyen  * @segs: array of one or more packet segments that describe the flow
88531ad4e4eSTony Nguyen  * @segs_cnt: number of packet segments provided
886451f2c44STony Nguyen  * @prof: stores the returned flow profile added
88731ad4e4eSTony Nguyen  */
888148beb61SHenry Tieman enum ice_status
88931ad4e4eSTony Nguyen ice_flow_add_prof(struct ice_hw *hw, enum ice_block blk, enum ice_flow_dir dir,
890451f2c44STony Nguyen 		  u64 prof_id, struct ice_flow_seg_info *segs, u8 segs_cnt,
891451f2c44STony Nguyen 		  struct ice_flow_prof **prof)
89231ad4e4eSTony Nguyen {
89331ad4e4eSTony Nguyen 	enum ice_status status;
89431ad4e4eSTony Nguyen 
89531ad4e4eSTony Nguyen 	if (segs_cnt > ICE_FLOW_SEG_MAX)
89631ad4e4eSTony Nguyen 		return ICE_ERR_MAX_LIMIT;
89731ad4e4eSTony Nguyen 
89831ad4e4eSTony Nguyen 	if (!segs_cnt)
89931ad4e4eSTony Nguyen 		return ICE_ERR_PARAM;
90031ad4e4eSTony Nguyen 
90131ad4e4eSTony Nguyen 	if (!segs)
90231ad4e4eSTony Nguyen 		return ICE_ERR_BAD_PTR;
90331ad4e4eSTony Nguyen 
90431ad4e4eSTony Nguyen 	status = ice_flow_val_hdrs(segs, segs_cnt);
90531ad4e4eSTony Nguyen 	if (status)
90631ad4e4eSTony Nguyen 		return status;
90731ad4e4eSTony Nguyen 
90831ad4e4eSTony Nguyen 	mutex_lock(&hw->fl_profs_locks[blk]);
90931ad4e4eSTony Nguyen 
91031ad4e4eSTony Nguyen 	status = ice_flow_add_prof_sync(hw, blk, dir, prof_id, segs, segs_cnt,
911451f2c44STony Nguyen 					prof);
91231ad4e4eSTony Nguyen 	if (!status)
913451f2c44STony Nguyen 		list_add(&(*prof)->l_entry, &hw->fl_profs[blk]);
91431ad4e4eSTony Nguyen 
91531ad4e4eSTony Nguyen 	mutex_unlock(&hw->fl_profs_locks[blk]);
91631ad4e4eSTony Nguyen 
91731ad4e4eSTony Nguyen 	return status;
91831ad4e4eSTony Nguyen }
91931ad4e4eSTony Nguyen 
920c90ed40cSTony Nguyen /**
9212c61054cSTony Nguyen  * ice_flow_rem_prof - Remove a flow profile and all entries associated with it
9222c61054cSTony Nguyen  * @hw: pointer to the HW struct
9232c61054cSTony Nguyen  * @blk: the block for which the flow profile is to be removed
9242c61054cSTony Nguyen  * @prof_id: unique ID of the flow profile to be removed
9252c61054cSTony Nguyen  */
926148beb61SHenry Tieman enum ice_status
9272c61054cSTony Nguyen ice_flow_rem_prof(struct ice_hw *hw, enum ice_block blk, u64 prof_id)
9282c61054cSTony Nguyen {
9292c61054cSTony Nguyen 	struct ice_flow_prof *prof;
9302c61054cSTony Nguyen 	enum ice_status status;
9312c61054cSTony Nguyen 
9322c61054cSTony Nguyen 	mutex_lock(&hw->fl_profs_locks[blk]);
9332c61054cSTony Nguyen 
9342c61054cSTony Nguyen 	prof = ice_flow_find_prof_id(hw, blk, prof_id);
9352c61054cSTony Nguyen 	if (!prof) {
9362c61054cSTony Nguyen 		status = ICE_ERR_DOES_NOT_EXIST;
9372c61054cSTony Nguyen 		goto out;
9382c61054cSTony Nguyen 	}
9392c61054cSTony Nguyen 
9402c61054cSTony Nguyen 	/* prof becomes invalid after the call */
9412c61054cSTony Nguyen 	status = ice_flow_rem_prof_sync(hw, blk, prof);
9422c61054cSTony Nguyen 
9432c61054cSTony Nguyen out:
9442c61054cSTony Nguyen 	mutex_unlock(&hw->fl_profs_locks[blk]);
9452c61054cSTony Nguyen 
9462c61054cSTony Nguyen 	return status;
9472c61054cSTony Nguyen }
9482c61054cSTony Nguyen 
9492c61054cSTony Nguyen /**
950148beb61SHenry Tieman  * ice_flow_add_entry - Add a flow entry
951148beb61SHenry Tieman  * @hw: pointer to the HW struct
952148beb61SHenry Tieman  * @blk: classification stage
953148beb61SHenry Tieman  * @prof_id: ID of the profile to add a new flow entry to
954148beb61SHenry Tieman  * @entry_id: unique ID to identify this flow entry
955148beb61SHenry Tieman  * @vsi_handle: software VSI handle for the flow entry
956148beb61SHenry Tieman  * @prio: priority of the flow entry
957148beb61SHenry Tieman  * @data: pointer to a data buffer containing flow entry's match values/masks
958148beb61SHenry Tieman  * @entry_h: pointer to buffer that receives the new flow entry's handle
959148beb61SHenry Tieman  */
960148beb61SHenry Tieman enum ice_status
961148beb61SHenry Tieman ice_flow_add_entry(struct ice_hw *hw, enum ice_block blk, u64 prof_id,
962148beb61SHenry Tieman 		   u64 entry_id, u16 vsi_handle, enum ice_flow_priority prio,
963148beb61SHenry Tieman 		   void *data, u64 *entry_h)
964148beb61SHenry Tieman {
965148beb61SHenry Tieman 	struct ice_flow_entry *e = NULL;
966148beb61SHenry Tieman 	struct ice_flow_prof *prof;
967148beb61SHenry Tieman 	enum ice_status status;
968148beb61SHenry Tieman 
969148beb61SHenry Tieman 	/* No flow entry data is expected for RSS */
970148beb61SHenry Tieman 	if (!entry_h || (!data && blk != ICE_BLK_RSS))
971148beb61SHenry Tieman 		return ICE_ERR_BAD_PTR;
972148beb61SHenry Tieman 
973148beb61SHenry Tieman 	if (!ice_is_vsi_valid(hw, vsi_handle))
974148beb61SHenry Tieman 		return ICE_ERR_PARAM;
975148beb61SHenry Tieman 
976148beb61SHenry Tieman 	mutex_lock(&hw->fl_profs_locks[blk]);
977148beb61SHenry Tieman 
978148beb61SHenry Tieman 	prof = ice_flow_find_prof_id(hw, blk, prof_id);
979148beb61SHenry Tieman 	if (!prof) {
980148beb61SHenry Tieman 		status = ICE_ERR_DOES_NOT_EXIST;
981148beb61SHenry Tieman 	} else {
982148beb61SHenry Tieman 		/* Allocate memory for the entry being added and associate
983148beb61SHenry Tieman 		 * the VSI to the found flow profile
984148beb61SHenry Tieman 		 */
985148beb61SHenry Tieman 		e = devm_kzalloc(ice_hw_to_dev(hw), sizeof(*e), GFP_KERNEL);
986148beb61SHenry Tieman 		if (!e)
987148beb61SHenry Tieman 			status = ICE_ERR_NO_MEMORY;
988148beb61SHenry Tieman 		else
989148beb61SHenry Tieman 			status = ice_flow_assoc_prof(hw, blk, prof, vsi_handle);
990148beb61SHenry Tieman 	}
991148beb61SHenry Tieman 
992148beb61SHenry Tieman 	mutex_unlock(&hw->fl_profs_locks[blk]);
993148beb61SHenry Tieman 	if (status)
994148beb61SHenry Tieman 		goto out;
995148beb61SHenry Tieman 
996148beb61SHenry Tieman 	e->id = entry_id;
997148beb61SHenry Tieman 	e->vsi_handle = vsi_handle;
998148beb61SHenry Tieman 	e->prof = prof;
999148beb61SHenry Tieman 	e->priority = prio;
1000148beb61SHenry Tieman 
1001148beb61SHenry Tieman 	switch (blk) {
1002148beb61SHenry Tieman 	case ICE_BLK_FD:
1003148beb61SHenry Tieman 	case ICE_BLK_RSS:
1004148beb61SHenry Tieman 		break;
1005148beb61SHenry Tieman 	default:
1006148beb61SHenry Tieman 		status = ICE_ERR_NOT_IMPL;
1007148beb61SHenry Tieman 		goto out;
1008148beb61SHenry Tieman 	}
1009148beb61SHenry Tieman 
1010148beb61SHenry Tieman 	mutex_lock(&prof->entries_lock);
1011148beb61SHenry Tieman 	list_add(&e->l_entry, &prof->entries);
1012148beb61SHenry Tieman 	mutex_unlock(&prof->entries_lock);
1013148beb61SHenry Tieman 
1014148beb61SHenry Tieman 	*entry_h = ICE_FLOW_ENTRY_HNDL(e);
1015148beb61SHenry Tieman 
1016148beb61SHenry Tieman out:
1017148beb61SHenry Tieman 	if (status && e) {
1018148beb61SHenry Tieman 		if (e->entry)
1019148beb61SHenry Tieman 			devm_kfree(ice_hw_to_dev(hw), e->entry);
1020148beb61SHenry Tieman 		devm_kfree(ice_hw_to_dev(hw), e);
1021148beb61SHenry Tieman 	}
1022148beb61SHenry Tieman 
1023148beb61SHenry Tieman 	return status;
1024148beb61SHenry Tieman }
1025148beb61SHenry Tieman 
1026148beb61SHenry Tieman /**
1027148beb61SHenry Tieman  * ice_flow_rem_entry - Remove a flow entry
1028148beb61SHenry Tieman  * @hw: pointer to the HW struct
1029148beb61SHenry Tieman  * @blk: classification stage
1030148beb61SHenry Tieman  * @entry_h: handle to the flow entry to be removed
1031148beb61SHenry Tieman  */
1032148beb61SHenry Tieman enum ice_status ice_flow_rem_entry(struct ice_hw *hw, enum ice_block blk,
1033148beb61SHenry Tieman 				   u64 entry_h)
1034148beb61SHenry Tieman {
1035148beb61SHenry Tieman 	struct ice_flow_entry *entry;
1036148beb61SHenry Tieman 	struct ice_flow_prof *prof;
1037148beb61SHenry Tieman 	enum ice_status status = 0;
1038148beb61SHenry Tieman 
1039148beb61SHenry Tieman 	if (entry_h == ICE_FLOW_ENTRY_HANDLE_INVAL)
1040148beb61SHenry Tieman 		return ICE_ERR_PARAM;
1041148beb61SHenry Tieman 
1042148beb61SHenry Tieman 	entry = ICE_FLOW_ENTRY_PTR(entry_h);
1043148beb61SHenry Tieman 
1044148beb61SHenry Tieman 	/* Retain the pointer to the flow profile as the entry will be freed */
1045148beb61SHenry Tieman 	prof = entry->prof;
1046148beb61SHenry Tieman 
1047148beb61SHenry Tieman 	if (prof) {
1048148beb61SHenry Tieman 		mutex_lock(&prof->entries_lock);
1049148beb61SHenry Tieman 		status = ice_flow_rem_entry_sync(hw, blk, entry);
1050148beb61SHenry Tieman 		mutex_unlock(&prof->entries_lock);
1051148beb61SHenry Tieman 	}
1052148beb61SHenry Tieman 
1053148beb61SHenry Tieman 	return status;
1054148beb61SHenry Tieman }
1055148beb61SHenry Tieman 
1056148beb61SHenry Tieman /**
1057c90ed40cSTony Nguyen  * ice_flow_set_fld_ext - specifies locations of field from entry's input buffer
1058c90ed40cSTony Nguyen  * @seg: packet segment the field being set belongs to
1059c90ed40cSTony Nguyen  * @fld: field to be set
10606dae8aa0SBruce Allan  * @field_type: type of the field
1061c90ed40cSTony Nguyen  * @val_loc: if not ICE_FLOW_FLD_OFF_INVAL, location of the value to match from
1062c90ed40cSTony Nguyen  *           entry's input buffer
1063c90ed40cSTony Nguyen  * @mask_loc: if not ICE_FLOW_FLD_OFF_INVAL, location of mask value from entry's
1064c90ed40cSTony Nguyen  *            input buffer
1065c90ed40cSTony Nguyen  * @last_loc: if not ICE_FLOW_FLD_OFF_INVAL, location of last/upper value from
1066c90ed40cSTony Nguyen  *            entry's input buffer
1067c90ed40cSTony Nguyen  *
1068c90ed40cSTony Nguyen  * This helper function stores information of a field being matched, including
1069c90ed40cSTony Nguyen  * the type of the field and the locations of the value to match, the mask, and
1070ac382a09SBruce Allan  * the upper-bound value in the start of the input buffer for a flow entry.
1071c90ed40cSTony Nguyen  * This function should only be used for fixed-size data structures.
1072c90ed40cSTony Nguyen  *
1073c90ed40cSTony Nguyen  * This function also opportunistically determines the protocol headers to be
1074c90ed40cSTony Nguyen  * present based on the fields being set. Some fields cannot be used alone to
1075c90ed40cSTony Nguyen  * determine the protocol headers present. Sometimes, fields for particular
1076c90ed40cSTony Nguyen  * protocol headers are not matched. In those cases, the protocol headers
1077c90ed40cSTony Nguyen  * must be explicitly set.
1078c90ed40cSTony Nguyen  */
1079c90ed40cSTony Nguyen static void
1080c90ed40cSTony Nguyen ice_flow_set_fld_ext(struct ice_flow_seg_info *seg, enum ice_flow_field fld,
10816dae8aa0SBruce Allan 		     enum ice_flow_fld_match_type field_type, u16 val_loc,
1082c90ed40cSTony Nguyen 		     u16 mask_loc, u16 last_loc)
1083c90ed40cSTony Nguyen {
1084c90ed40cSTony Nguyen 	u64 bit = BIT_ULL(fld);
1085c90ed40cSTony Nguyen 
1086c90ed40cSTony Nguyen 	seg->match |= bit;
10876dae8aa0SBruce Allan 	if (field_type == ICE_FLOW_FLD_TYPE_RANGE)
1088c90ed40cSTony Nguyen 		seg->range |= bit;
1089c90ed40cSTony Nguyen 
10906dae8aa0SBruce Allan 	seg->fields[fld].type = field_type;
1091c90ed40cSTony Nguyen 	seg->fields[fld].src.val = val_loc;
1092c90ed40cSTony Nguyen 	seg->fields[fld].src.mask = mask_loc;
1093c90ed40cSTony Nguyen 	seg->fields[fld].src.last = last_loc;
1094c90ed40cSTony Nguyen 
1095c90ed40cSTony Nguyen 	ICE_FLOW_SET_HDRS(seg, ice_flds_info[fld].hdr);
1096c90ed40cSTony Nguyen }
1097c90ed40cSTony Nguyen 
1098c90ed40cSTony Nguyen /**
1099c90ed40cSTony Nguyen  * ice_flow_set_fld - specifies locations of field from entry's input buffer
1100c90ed40cSTony Nguyen  * @seg: packet segment the field being set belongs to
1101c90ed40cSTony Nguyen  * @fld: field to be set
1102c90ed40cSTony Nguyen  * @val_loc: if not ICE_FLOW_FLD_OFF_INVAL, location of the value to match from
1103c90ed40cSTony Nguyen  *           entry's input buffer
1104c90ed40cSTony Nguyen  * @mask_loc: if not ICE_FLOW_FLD_OFF_INVAL, location of mask value from entry's
1105c90ed40cSTony Nguyen  *            input buffer
1106c90ed40cSTony Nguyen  * @last_loc: if not ICE_FLOW_FLD_OFF_INVAL, location of last/upper value from
1107c90ed40cSTony Nguyen  *            entry's input buffer
1108c90ed40cSTony Nguyen  * @range: indicate if field being matched is to be in a range
1109c90ed40cSTony Nguyen  *
1110c90ed40cSTony Nguyen  * This function specifies the locations, in the form of byte offsets from the
1111c90ed40cSTony Nguyen  * start of the input buffer for a flow entry, from where the value to match,
1112c90ed40cSTony Nguyen  * the mask value, and upper value can be extracted. These locations are then
1113c90ed40cSTony Nguyen  * stored in the flow profile. When adding a flow entry associated with the
1114c90ed40cSTony Nguyen  * flow profile, these locations will be used to quickly extract the values and
1115c90ed40cSTony Nguyen  * create the content of a match entry. This function should only be used for
1116c90ed40cSTony Nguyen  * fixed-size data structures.
1117c90ed40cSTony Nguyen  */
1118148beb61SHenry Tieman void
1119c90ed40cSTony Nguyen ice_flow_set_fld(struct ice_flow_seg_info *seg, enum ice_flow_field fld,
1120c90ed40cSTony Nguyen 		 u16 val_loc, u16 mask_loc, u16 last_loc, bool range)
1121c90ed40cSTony Nguyen {
1122c90ed40cSTony Nguyen 	enum ice_flow_fld_match_type t = range ?
1123c90ed40cSTony Nguyen 		ICE_FLOW_FLD_TYPE_RANGE : ICE_FLOW_FLD_TYPE_REG;
1124c90ed40cSTony Nguyen 
1125c90ed40cSTony Nguyen 	ice_flow_set_fld_ext(seg, fld, t, val_loc, mask_loc, last_loc);
1126c90ed40cSTony Nguyen }
1127c90ed40cSTony Nguyen 
11282c57ffcbSHenry Tieman /**
11292c57ffcbSHenry Tieman  * ice_flow_add_fld_raw - sets locations of a raw field from entry's input buf
11302c57ffcbSHenry Tieman  * @seg: packet segment the field being set belongs to
11312c57ffcbSHenry Tieman  * @off: offset of the raw field from the beginning of the segment in bytes
11322c57ffcbSHenry Tieman  * @len: length of the raw pattern to be matched
11332c57ffcbSHenry Tieman  * @val_loc: location of the value to match from entry's input buffer
11342c57ffcbSHenry Tieman  * @mask_loc: location of mask value from entry's input buffer
11352c57ffcbSHenry Tieman  *
11362c57ffcbSHenry Tieman  * This function specifies the offset of the raw field to be match from the
11372c57ffcbSHenry Tieman  * beginning of the specified packet segment, and the locations, in the form of
11382c57ffcbSHenry Tieman  * byte offsets from the start of the input buffer for a flow entry, from where
11392c57ffcbSHenry Tieman  * the value to match and the mask value to be extracted. These locations are
11402c57ffcbSHenry Tieman  * then stored in the flow profile. When adding flow entries to the associated
11412c57ffcbSHenry Tieman  * flow profile, these locations can be used to quickly extract the values to
11422c57ffcbSHenry Tieman  * create the content of a match entry. This function should only be used for
11432c57ffcbSHenry Tieman  * fixed-size data structures.
11442c57ffcbSHenry Tieman  */
11452c57ffcbSHenry Tieman void
11462c57ffcbSHenry Tieman ice_flow_add_fld_raw(struct ice_flow_seg_info *seg, u16 off, u8 len,
11472c57ffcbSHenry Tieman 		     u16 val_loc, u16 mask_loc)
11482c57ffcbSHenry Tieman {
11492c57ffcbSHenry Tieman 	if (seg->raws_cnt < ICE_FLOW_SEG_RAW_FLD_MAX) {
11502c57ffcbSHenry Tieman 		seg->raws[seg->raws_cnt].off = off;
11512c57ffcbSHenry Tieman 		seg->raws[seg->raws_cnt].info.type = ICE_FLOW_FLD_TYPE_SIZE;
11522c57ffcbSHenry Tieman 		seg->raws[seg->raws_cnt].info.src.val = val_loc;
11532c57ffcbSHenry Tieman 		seg->raws[seg->raws_cnt].info.src.mask = mask_loc;
11542c57ffcbSHenry Tieman 		/* The "last" field is used to store the length of the field */
11552c57ffcbSHenry Tieman 		seg->raws[seg->raws_cnt].info.src.last = len;
11562c57ffcbSHenry Tieman 	}
11572c57ffcbSHenry Tieman 
11582c57ffcbSHenry Tieman 	/* Overflows of "raws" will be handled as an error condition later in
11592c57ffcbSHenry Tieman 	 * the flow when this information is processed.
11602c57ffcbSHenry Tieman 	 */
11612c57ffcbSHenry Tieman 	seg->raws_cnt++;
11622c57ffcbSHenry Tieman }
11632c57ffcbSHenry Tieman 
1164c90ed40cSTony Nguyen #define ICE_FLOW_RSS_SEG_HDR_L3_MASKS \
1165c90ed40cSTony Nguyen 	(ICE_FLOW_SEG_HDR_IPV4 | ICE_FLOW_SEG_HDR_IPV6)
1166c90ed40cSTony Nguyen 
1167c90ed40cSTony Nguyen #define ICE_FLOW_RSS_SEG_HDR_L4_MASKS \
1168c90ed40cSTony Nguyen 	(ICE_FLOW_SEG_HDR_TCP | ICE_FLOW_SEG_HDR_UDP | ICE_FLOW_SEG_HDR_SCTP)
1169c90ed40cSTony Nguyen 
1170c90ed40cSTony Nguyen #define ICE_FLOW_RSS_SEG_HDR_VAL_MASKS \
1171c90ed40cSTony Nguyen 	(ICE_FLOW_RSS_SEG_HDR_L3_MASKS | \
1172c90ed40cSTony Nguyen 	 ICE_FLOW_RSS_SEG_HDR_L4_MASKS)
1173c90ed40cSTony Nguyen 
1174c90ed40cSTony Nguyen /**
1175c90ed40cSTony Nguyen  * ice_flow_set_rss_seg_info - setup packet segments for RSS
1176c90ed40cSTony Nguyen  * @segs: pointer to the flow field segment(s)
1177c90ed40cSTony Nguyen  * @hash_fields: fields to be hashed on for the segment(s)
1178c90ed40cSTony Nguyen  * @flow_hdr: protocol header fields within a packet segment
1179c90ed40cSTony Nguyen  *
1180c90ed40cSTony Nguyen  * Helper function to extract fields from hash bitmap and use flow
1181c90ed40cSTony Nguyen  * header value to set flow field segment for further use in flow
1182c90ed40cSTony Nguyen  * profile entry or removal.
1183c90ed40cSTony Nguyen  */
1184c90ed40cSTony Nguyen static enum ice_status
1185c90ed40cSTony Nguyen ice_flow_set_rss_seg_info(struct ice_flow_seg_info *segs, u64 hash_fields,
1186c90ed40cSTony Nguyen 			  u32 flow_hdr)
1187c90ed40cSTony Nguyen {
1188c90ed40cSTony Nguyen 	u64 val;
1189c90ed40cSTony Nguyen 	u8 i;
1190c90ed40cSTony Nguyen 
1191c90ed40cSTony Nguyen 	for_each_set_bit(i, (unsigned long *)&hash_fields,
1192c90ed40cSTony Nguyen 			 ICE_FLOW_FIELD_IDX_MAX)
1193c90ed40cSTony Nguyen 		ice_flow_set_fld(segs, (enum ice_flow_field)i,
1194c90ed40cSTony Nguyen 				 ICE_FLOW_FLD_OFF_INVAL, ICE_FLOW_FLD_OFF_INVAL,
1195c90ed40cSTony Nguyen 				 ICE_FLOW_FLD_OFF_INVAL, false);
1196c90ed40cSTony Nguyen 
1197c90ed40cSTony Nguyen 	ICE_FLOW_SET_HDRS(segs, flow_hdr);
1198c90ed40cSTony Nguyen 
1199c90ed40cSTony Nguyen 	if (segs->hdrs & ~ICE_FLOW_RSS_SEG_HDR_VAL_MASKS)
1200c90ed40cSTony Nguyen 		return ICE_ERR_PARAM;
1201c90ed40cSTony Nguyen 
1202c90ed40cSTony Nguyen 	val = (u64)(segs->hdrs & ICE_FLOW_RSS_SEG_HDR_L3_MASKS);
1203c90ed40cSTony Nguyen 	if (val && !is_power_of_2(val))
1204c90ed40cSTony Nguyen 		return ICE_ERR_CFG;
1205c90ed40cSTony Nguyen 
1206c90ed40cSTony Nguyen 	val = (u64)(segs->hdrs & ICE_FLOW_RSS_SEG_HDR_L4_MASKS);
1207c90ed40cSTony Nguyen 	if (val && !is_power_of_2(val))
1208c90ed40cSTony Nguyen 		return ICE_ERR_CFG;
1209c90ed40cSTony Nguyen 
1210c90ed40cSTony Nguyen 	return 0;
1211c90ed40cSTony Nguyen }
1212c90ed40cSTony Nguyen 
12132c61054cSTony Nguyen /**
12142c61054cSTony Nguyen  * ice_rem_vsi_rss_list - remove VSI from RSS list
12152c61054cSTony Nguyen  * @hw: pointer to the hardware structure
12162c61054cSTony Nguyen  * @vsi_handle: software VSI handle
12172c61054cSTony Nguyen  *
12182c61054cSTony Nguyen  * Remove the VSI from all RSS configurations in the list.
12192c61054cSTony Nguyen  */
12202c61054cSTony Nguyen void ice_rem_vsi_rss_list(struct ice_hw *hw, u16 vsi_handle)
12212c61054cSTony Nguyen {
12222c61054cSTony Nguyen 	struct ice_rss_cfg *r, *tmp;
12232c61054cSTony Nguyen 
12242c61054cSTony Nguyen 	if (list_empty(&hw->rss_list_head))
12252c61054cSTony Nguyen 		return;
12262c61054cSTony Nguyen 
12272c61054cSTony Nguyen 	mutex_lock(&hw->rss_locks);
12282c61054cSTony Nguyen 	list_for_each_entry_safe(r, tmp, &hw->rss_list_head, l_entry)
12292c61054cSTony Nguyen 		if (test_and_clear_bit(vsi_handle, r->vsis))
12302c61054cSTony Nguyen 			if (bitmap_empty(r->vsis, ICE_MAX_VSI)) {
12312c61054cSTony Nguyen 				list_del(&r->l_entry);
12322c61054cSTony Nguyen 				devm_kfree(ice_hw_to_dev(hw), r);
12332c61054cSTony Nguyen 			}
12342c61054cSTony Nguyen 	mutex_unlock(&hw->rss_locks);
12352c61054cSTony Nguyen }
12362c61054cSTony Nguyen 
12372c61054cSTony Nguyen /**
12382c61054cSTony Nguyen  * ice_rem_vsi_rss_cfg - remove RSS configurations associated with VSI
12392c61054cSTony Nguyen  * @hw: pointer to the hardware structure
12402c61054cSTony Nguyen  * @vsi_handle: software VSI handle
12412c61054cSTony Nguyen  *
12422c61054cSTony Nguyen  * This function will iterate through all flow profiles and disassociate
12432c61054cSTony Nguyen  * the VSI from that profile. If the flow profile has no VSIs it will
12442c61054cSTony Nguyen  * be removed.
12452c61054cSTony Nguyen  */
12462c61054cSTony Nguyen enum ice_status ice_rem_vsi_rss_cfg(struct ice_hw *hw, u16 vsi_handle)
12472c61054cSTony Nguyen {
12482c61054cSTony Nguyen 	const enum ice_block blk = ICE_BLK_RSS;
12492c61054cSTony Nguyen 	struct ice_flow_prof *p, *t;
12502c61054cSTony Nguyen 	enum ice_status status = 0;
12512c61054cSTony Nguyen 
12522c61054cSTony Nguyen 	if (!ice_is_vsi_valid(hw, vsi_handle))
12532c61054cSTony Nguyen 		return ICE_ERR_PARAM;
12542c61054cSTony Nguyen 
12552c61054cSTony Nguyen 	if (list_empty(&hw->fl_profs[blk]))
12562c61054cSTony Nguyen 		return 0;
12572c61054cSTony Nguyen 
1258cdedbab9SVignesh Sridhar 	mutex_lock(&hw->rss_locks);
12592c61054cSTony Nguyen 	list_for_each_entry_safe(p, t, &hw->fl_profs[blk], l_entry)
12602c61054cSTony Nguyen 		if (test_bit(vsi_handle, p->vsis)) {
12612c61054cSTony Nguyen 			status = ice_flow_disassoc_prof(hw, blk, p, vsi_handle);
12622c61054cSTony Nguyen 			if (status)
12632c61054cSTony Nguyen 				break;
12642c61054cSTony Nguyen 
12652c61054cSTony Nguyen 			if (bitmap_empty(p->vsis, ICE_MAX_VSI)) {
1266cdedbab9SVignesh Sridhar 				status = ice_flow_rem_prof(hw, blk, p->id);
12672c61054cSTony Nguyen 				if (status)
12682c61054cSTony Nguyen 					break;
12692c61054cSTony Nguyen 			}
12702c61054cSTony Nguyen 		}
1271cdedbab9SVignesh Sridhar 	mutex_unlock(&hw->rss_locks);
12722c61054cSTony Nguyen 
12732c61054cSTony Nguyen 	return status;
12742c61054cSTony Nguyen }
12752c61054cSTony Nguyen 
12762c61054cSTony Nguyen /**
12772c61054cSTony Nguyen  * ice_rem_rss_list - remove RSS configuration from list
12782c61054cSTony Nguyen  * @hw: pointer to the hardware structure
12792c61054cSTony Nguyen  * @vsi_handle: software VSI handle
12802c61054cSTony Nguyen  * @prof: pointer to flow profile
12812c61054cSTony Nguyen  *
12822c61054cSTony Nguyen  * Assumption: lock has already been acquired for RSS list
12832c61054cSTony Nguyen  */
12842c61054cSTony Nguyen static void
12852c61054cSTony Nguyen ice_rem_rss_list(struct ice_hw *hw, u16 vsi_handle, struct ice_flow_prof *prof)
12862c61054cSTony Nguyen {
12872c61054cSTony Nguyen 	struct ice_rss_cfg *r, *tmp;
12882c61054cSTony Nguyen 
12892c61054cSTony Nguyen 	/* Search for RSS hash fields associated to the VSI that match the
12902c61054cSTony Nguyen 	 * hash configurations associated to the flow profile. If found
12912c61054cSTony Nguyen 	 * remove from the RSS entry list of the VSI context and delete entry.
12922c61054cSTony Nguyen 	 */
12932c61054cSTony Nguyen 	list_for_each_entry_safe(r, tmp, &hw->rss_list_head, l_entry)
12942c61054cSTony Nguyen 		if (r->hashed_flds == prof->segs[prof->segs_cnt - 1].match &&
12952c61054cSTony Nguyen 		    r->packet_hdr == prof->segs[prof->segs_cnt - 1].hdrs) {
12962c61054cSTony Nguyen 			clear_bit(vsi_handle, r->vsis);
12972c61054cSTony Nguyen 			if (bitmap_empty(r->vsis, ICE_MAX_VSI)) {
12982c61054cSTony Nguyen 				list_del(&r->l_entry);
12992c61054cSTony Nguyen 				devm_kfree(ice_hw_to_dev(hw), r);
13002c61054cSTony Nguyen 			}
13012c61054cSTony Nguyen 			return;
13022c61054cSTony Nguyen 		}
13032c61054cSTony Nguyen }
13042c61054cSTony Nguyen 
13052c61054cSTony Nguyen /**
13062c61054cSTony Nguyen  * ice_add_rss_list - add RSS configuration to list
13072c61054cSTony Nguyen  * @hw: pointer to the hardware structure
13082c61054cSTony Nguyen  * @vsi_handle: software VSI handle
13092c61054cSTony Nguyen  * @prof: pointer to flow profile
13102c61054cSTony Nguyen  *
13112c61054cSTony Nguyen  * Assumption: lock has already been acquired for RSS list
13122c61054cSTony Nguyen  */
13132c61054cSTony Nguyen static enum ice_status
13142c61054cSTony Nguyen ice_add_rss_list(struct ice_hw *hw, u16 vsi_handle, struct ice_flow_prof *prof)
13152c61054cSTony Nguyen {
13162c61054cSTony Nguyen 	struct ice_rss_cfg *r, *rss_cfg;
13172c61054cSTony Nguyen 
13182c61054cSTony Nguyen 	list_for_each_entry(r, &hw->rss_list_head, l_entry)
13192c61054cSTony Nguyen 		if (r->hashed_flds == prof->segs[prof->segs_cnt - 1].match &&
13202c61054cSTony Nguyen 		    r->packet_hdr == prof->segs[prof->segs_cnt - 1].hdrs) {
13212c61054cSTony Nguyen 			set_bit(vsi_handle, r->vsis);
13222c61054cSTony Nguyen 			return 0;
13232c61054cSTony Nguyen 		}
13242c61054cSTony Nguyen 
13252c61054cSTony Nguyen 	rss_cfg = devm_kzalloc(ice_hw_to_dev(hw), sizeof(*rss_cfg),
13262c61054cSTony Nguyen 			       GFP_KERNEL);
13272c61054cSTony Nguyen 	if (!rss_cfg)
13282c61054cSTony Nguyen 		return ICE_ERR_NO_MEMORY;
13292c61054cSTony Nguyen 
13302c61054cSTony Nguyen 	rss_cfg->hashed_flds = prof->segs[prof->segs_cnt - 1].match;
13312c61054cSTony Nguyen 	rss_cfg->packet_hdr = prof->segs[prof->segs_cnt - 1].hdrs;
13322c61054cSTony Nguyen 	set_bit(vsi_handle, rss_cfg->vsis);
13332c61054cSTony Nguyen 
13342c61054cSTony Nguyen 	list_add_tail(&rss_cfg->l_entry, &hw->rss_list_head);
13352c61054cSTony Nguyen 
13362c61054cSTony Nguyen 	return 0;
13372c61054cSTony Nguyen }
13382c61054cSTony Nguyen 
133931ad4e4eSTony Nguyen #define ICE_FLOW_PROF_HASH_S	0
134031ad4e4eSTony Nguyen #define ICE_FLOW_PROF_HASH_M	(0xFFFFFFFFULL << ICE_FLOW_PROF_HASH_S)
134131ad4e4eSTony Nguyen #define ICE_FLOW_PROF_HDR_S	32
134231ad4e4eSTony Nguyen #define ICE_FLOW_PROF_HDR_M	(0x3FFFFFFFULL << ICE_FLOW_PROF_HDR_S)
134331ad4e4eSTony Nguyen #define ICE_FLOW_PROF_ENCAP_S	63
134431ad4e4eSTony Nguyen #define ICE_FLOW_PROF_ENCAP_M	(BIT_ULL(ICE_FLOW_PROF_ENCAP_S))
134531ad4e4eSTony Nguyen 
1346c90ed40cSTony Nguyen #define ICE_RSS_OUTER_HEADERS	1
1347a4e82a81STony Nguyen #define ICE_RSS_INNER_HEADERS	2
1348c90ed40cSTony Nguyen 
134931ad4e4eSTony Nguyen /* Flow profile ID format:
135031ad4e4eSTony Nguyen  * [0:31] - Packet match fields
135131ad4e4eSTony Nguyen  * [32:62] - Protocol header
135231ad4e4eSTony Nguyen  * [63] - Encapsulation flag, 0 if non-tunneled, 1 if tunneled
135331ad4e4eSTony Nguyen  */
135431ad4e4eSTony Nguyen #define ICE_FLOW_GEN_PROFID(hash, hdr, segs_cnt) \
135531ad4e4eSTony Nguyen 	(u64)(((u64)(hash) & ICE_FLOW_PROF_HASH_M) | \
135631ad4e4eSTony Nguyen 	      (((u64)(hdr) << ICE_FLOW_PROF_HDR_S) & ICE_FLOW_PROF_HDR_M) | \
135731ad4e4eSTony Nguyen 	      ((u8)((segs_cnt) - 1) ? ICE_FLOW_PROF_ENCAP_M : 0))
135831ad4e4eSTony Nguyen 
1359c90ed40cSTony Nguyen /**
1360c90ed40cSTony Nguyen  * ice_add_rss_cfg_sync - add an RSS configuration
136131ad4e4eSTony Nguyen  * @hw: pointer to the hardware structure
1362451f2c44STony Nguyen  * @vsi_handle: software VSI handle
1363c90ed40cSTony Nguyen  * @hashed_flds: hash bit fields (ICE_FLOW_HASH_*) to configure
1364c90ed40cSTony Nguyen  * @addl_hdrs: protocol header fields
1365c90ed40cSTony Nguyen  * @segs_cnt: packet segment count
1366c90ed40cSTony Nguyen  *
1367c90ed40cSTony Nguyen  * Assumption: lock has already been acquired for RSS list
1368c90ed40cSTony Nguyen  */
1369c90ed40cSTony Nguyen static enum ice_status
1370451f2c44STony Nguyen ice_add_rss_cfg_sync(struct ice_hw *hw, u16 vsi_handle, u64 hashed_flds,
1371451f2c44STony Nguyen 		     u32 addl_hdrs, u8 segs_cnt)
1372c90ed40cSTony Nguyen {
1373451f2c44STony Nguyen 	const enum ice_block blk = ICE_BLK_RSS;
1374451f2c44STony Nguyen 	struct ice_flow_prof *prof = NULL;
1375c90ed40cSTony Nguyen 	struct ice_flow_seg_info *segs;
1376c90ed40cSTony Nguyen 	enum ice_status status;
1377c90ed40cSTony Nguyen 
1378c90ed40cSTony Nguyen 	if (!segs_cnt || segs_cnt > ICE_FLOW_SEG_MAX)
1379c90ed40cSTony Nguyen 		return ICE_ERR_PARAM;
1380c90ed40cSTony Nguyen 
1381c90ed40cSTony Nguyen 	segs = kcalloc(segs_cnt, sizeof(*segs), GFP_KERNEL);
1382c90ed40cSTony Nguyen 	if (!segs)
1383c90ed40cSTony Nguyen 		return ICE_ERR_NO_MEMORY;
1384c90ed40cSTony Nguyen 
1385c90ed40cSTony Nguyen 	/* Construct the packet segment info from the hashed fields */
1386c90ed40cSTony Nguyen 	status = ice_flow_set_rss_seg_info(&segs[segs_cnt - 1], hashed_flds,
1387c90ed40cSTony Nguyen 					   addl_hdrs);
138831ad4e4eSTony Nguyen 	if (status)
138931ad4e4eSTony Nguyen 		goto exit;
1390c90ed40cSTony Nguyen 
13912c61054cSTony Nguyen 	/* Search for a flow profile that has matching headers, hash fields
13922c61054cSTony Nguyen 	 * and has the input VSI associated to it. If found, no further
13932c61054cSTony Nguyen 	 * operations required and exit.
13942c61054cSTony Nguyen 	 */
13952c61054cSTony Nguyen 	prof = ice_flow_find_prof_conds(hw, blk, ICE_FLOW_RX, segs, segs_cnt,
13962c61054cSTony Nguyen 					vsi_handle,
13972c61054cSTony Nguyen 					ICE_FLOW_FIND_PROF_CHK_FLDS |
13982c61054cSTony Nguyen 					ICE_FLOW_FIND_PROF_CHK_VSI);
13992c61054cSTony Nguyen 	if (prof)
14002c61054cSTony Nguyen 		goto exit;
14012c61054cSTony Nguyen 
14022c61054cSTony Nguyen 	/* Check if a flow profile exists with the same protocol headers and
14032c61054cSTony Nguyen 	 * associated with the input VSI. If so disassociate the VSI from
14042c61054cSTony Nguyen 	 * this profile. The VSI will be added to a new profile created with
14052c61054cSTony Nguyen 	 * the protocol header and new hash field configuration.
14062c61054cSTony Nguyen 	 */
14072c61054cSTony Nguyen 	prof = ice_flow_find_prof_conds(hw, blk, ICE_FLOW_RX, segs, segs_cnt,
14082c61054cSTony Nguyen 					vsi_handle, ICE_FLOW_FIND_PROF_CHK_VSI);
14092c61054cSTony Nguyen 	if (prof) {
14102c61054cSTony Nguyen 		status = ice_flow_disassoc_prof(hw, blk, prof, vsi_handle);
14112c61054cSTony Nguyen 		if (!status)
14122c61054cSTony Nguyen 			ice_rem_rss_list(hw, vsi_handle, prof);
14132c61054cSTony Nguyen 		else
14142c61054cSTony Nguyen 			goto exit;
14152c61054cSTony Nguyen 
14162c61054cSTony Nguyen 		/* Remove profile if it has no VSIs associated */
14172c61054cSTony Nguyen 		if (bitmap_empty(prof->vsis, ICE_MAX_VSI)) {
14182c61054cSTony Nguyen 			status = ice_flow_rem_prof(hw, blk, prof->id);
14192c61054cSTony Nguyen 			if (status)
14202c61054cSTony Nguyen 				goto exit;
14212c61054cSTony Nguyen 		}
14222c61054cSTony Nguyen 	}
14232c61054cSTony Nguyen 
14242c61054cSTony Nguyen 	/* Search for a profile that has same match fields only. If this
14252c61054cSTony Nguyen 	 * exists then associate the VSI to this profile.
14262c61054cSTony Nguyen 	 */
14272c61054cSTony Nguyen 	prof = ice_flow_find_prof_conds(hw, blk, ICE_FLOW_RX, segs, segs_cnt,
14282c61054cSTony Nguyen 					vsi_handle,
14292c61054cSTony Nguyen 					ICE_FLOW_FIND_PROF_CHK_FLDS);
14302c61054cSTony Nguyen 	if (prof) {
14312c61054cSTony Nguyen 		status = ice_flow_assoc_prof(hw, blk, prof, vsi_handle);
14322c61054cSTony Nguyen 		if (!status)
14332c61054cSTony Nguyen 			status = ice_add_rss_list(hw, vsi_handle, prof);
14342c61054cSTony Nguyen 		goto exit;
14352c61054cSTony Nguyen 	}
14362c61054cSTony Nguyen 
143731ad4e4eSTony Nguyen 	/* Create a new flow profile with generated profile and packet
143831ad4e4eSTony Nguyen 	 * segment information.
143931ad4e4eSTony Nguyen 	 */
1440451f2c44STony Nguyen 	status = ice_flow_add_prof(hw, blk, ICE_FLOW_RX,
144131ad4e4eSTony Nguyen 				   ICE_FLOW_GEN_PROFID(hashed_flds,
144231ad4e4eSTony Nguyen 						       segs[segs_cnt - 1].hdrs,
144331ad4e4eSTony Nguyen 						       segs_cnt),
1444451f2c44STony Nguyen 				   segs, segs_cnt, &prof);
1445451f2c44STony Nguyen 	if (status)
1446451f2c44STony Nguyen 		goto exit;
1447451f2c44STony Nguyen 
1448451f2c44STony Nguyen 	status = ice_flow_assoc_prof(hw, blk, prof, vsi_handle);
14492c61054cSTony Nguyen 	/* If association to a new flow profile failed then this profile can
14502c61054cSTony Nguyen 	 * be removed.
14512c61054cSTony Nguyen 	 */
14522c61054cSTony Nguyen 	if (status) {
14532c61054cSTony Nguyen 		ice_flow_rem_prof(hw, blk, prof->id);
14542c61054cSTony Nguyen 		goto exit;
14552c61054cSTony Nguyen 	}
14562c61054cSTony Nguyen 
14572c61054cSTony Nguyen 	status = ice_add_rss_list(hw, vsi_handle, prof);
145831ad4e4eSTony Nguyen 
145931ad4e4eSTony Nguyen exit:
1460c90ed40cSTony Nguyen 	kfree(segs);
1461c90ed40cSTony Nguyen 	return status;
1462c90ed40cSTony Nguyen }
1463c90ed40cSTony Nguyen 
1464c90ed40cSTony Nguyen /**
1465c90ed40cSTony Nguyen  * ice_add_rss_cfg - add an RSS configuration with specified hashed fields
1466c90ed40cSTony Nguyen  * @hw: pointer to the hardware structure
1467c90ed40cSTony Nguyen  * @vsi_handle: software VSI handle
1468c90ed40cSTony Nguyen  * @hashed_flds: hash bit fields (ICE_FLOW_HASH_*) to configure
1469c90ed40cSTony Nguyen  * @addl_hdrs: protocol header fields
1470c90ed40cSTony Nguyen  *
1471c90ed40cSTony Nguyen  * This function will generate a flow profile based on fields associated with
1472c90ed40cSTony Nguyen  * the input fields to hash on, the flow type and use the VSI number to add
1473c90ed40cSTony Nguyen  * a flow entry to the profile.
1474c90ed40cSTony Nguyen  */
1475c90ed40cSTony Nguyen enum ice_status
1476c90ed40cSTony Nguyen ice_add_rss_cfg(struct ice_hw *hw, u16 vsi_handle, u64 hashed_flds,
1477c90ed40cSTony Nguyen 		u32 addl_hdrs)
1478c90ed40cSTony Nguyen {
1479c90ed40cSTony Nguyen 	enum ice_status status;
1480c90ed40cSTony Nguyen 
1481c90ed40cSTony Nguyen 	if (hashed_flds == ICE_HASH_INVALID ||
1482c90ed40cSTony Nguyen 	    !ice_is_vsi_valid(hw, vsi_handle))
1483c90ed40cSTony Nguyen 		return ICE_ERR_PARAM;
1484c90ed40cSTony Nguyen 
1485c90ed40cSTony Nguyen 	mutex_lock(&hw->rss_locks);
1486451f2c44STony Nguyen 	status = ice_add_rss_cfg_sync(hw, vsi_handle, hashed_flds, addl_hdrs,
1487c90ed40cSTony Nguyen 				      ICE_RSS_OUTER_HEADERS);
1488a4e82a81STony Nguyen 	if (!status)
1489a4e82a81STony Nguyen 		status = ice_add_rss_cfg_sync(hw, vsi_handle, hashed_flds,
1490a4e82a81STony Nguyen 					      addl_hdrs, ICE_RSS_INNER_HEADERS);
1491c90ed40cSTony Nguyen 	mutex_unlock(&hw->rss_locks);
1492c90ed40cSTony Nguyen 
1493c90ed40cSTony Nguyen 	return status;
1494c90ed40cSTony Nguyen }
1495c90ed40cSTony Nguyen 
14961c01c8c6SMd Fahad Iqbal Polash /* Mapping of AVF hash bit fields to an L3-L4 hash combination.
14971c01c8c6SMd Fahad Iqbal Polash  * As the ice_flow_avf_hdr_field represent individual bit shifts in a hash,
14981c01c8c6SMd Fahad Iqbal Polash  * convert its values to their appropriate flow L3, L4 values.
14991c01c8c6SMd Fahad Iqbal Polash  */
15001c01c8c6SMd Fahad Iqbal Polash #define ICE_FLOW_AVF_RSS_IPV4_MASKS \
15011c01c8c6SMd Fahad Iqbal Polash 	(BIT_ULL(ICE_AVF_FLOW_FIELD_IPV4_OTHER) | \
15021c01c8c6SMd Fahad Iqbal Polash 	 BIT_ULL(ICE_AVF_FLOW_FIELD_FRAG_IPV4))
15031c01c8c6SMd Fahad Iqbal Polash #define ICE_FLOW_AVF_RSS_TCP_IPV4_MASKS \
15041c01c8c6SMd Fahad Iqbal Polash 	(BIT_ULL(ICE_AVF_FLOW_FIELD_IPV4_TCP_SYN_NO_ACK) | \
15051c01c8c6SMd Fahad Iqbal Polash 	 BIT_ULL(ICE_AVF_FLOW_FIELD_IPV4_TCP))
15061c01c8c6SMd Fahad Iqbal Polash #define ICE_FLOW_AVF_RSS_UDP_IPV4_MASKS \
15071c01c8c6SMd Fahad Iqbal Polash 	(BIT_ULL(ICE_AVF_FLOW_FIELD_UNICAST_IPV4_UDP) | \
15081c01c8c6SMd Fahad Iqbal Polash 	 BIT_ULL(ICE_AVF_FLOW_FIELD_MULTICAST_IPV4_UDP) | \
15091c01c8c6SMd Fahad Iqbal Polash 	 BIT_ULL(ICE_AVF_FLOW_FIELD_IPV4_UDP))
15101c01c8c6SMd Fahad Iqbal Polash #define ICE_FLOW_AVF_RSS_ALL_IPV4_MASKS \
15111c01c8c6SMd Fahad Iqbal Polash 	(ICE_FLOW_AVF_RSS_TCP_IPV4_MASKS | ICE_FLOW_AVF_RSS_UDP_IPV4_MASKS | \
15121c01c8c6SMd Fahad Iqbal Polash 	 ICE_FLOW_AVF_RSS_IPV4_MASKS | BIT_ULL(ICE_AVF_FLOW_FIELD_IPV4_SCTP))
15131c01c8c6SMd Fahad Iqbal Polash 
15141c01c8c6SMd Fahad Iqbal Polash #define ICE_FLOW_AVF_RSS_IPV6_MASKS \
15151c01c8c6SMd Fahad Iqbal Polash 	(BIT_ULL(ICE_AVF_FLOW_FIELD_IPV6_OTHER) | \
15161c01c8c6SMd Fahad Iqbal Polash 	 BIT_ULL(ICE_AVF_FLOW_FIELD_FRAG_IPV6))
15171c01c8c6SMd Fahad Iqbal Polash #define ICE_FLOW_AVF_RSS_UDP_IPV6_MASKS \
15181c01c8c6SMd Fahad Iqbal Polash 	(BIT_ULL(ICE_AVF_FLOW_FIELD_UNICAST_IPV6_UDP) | \
15191c01c8c6SMd Fahad Iqbal Polash 	 BIT_ULL(ICE_AVF_FLOW_FIELD_MULTICAST_IPV6_UDP) | \
15201c01c8c6SMd Fahad Iqbal Polash 	 BIT_ULL(ICE_AVF_FLOW_FIELD_IPV6_UDP))
15211c01c8c6SMd Fahad Iqbal Polash #define ICE_FLOW_AVF_RSS_TCP_IPV6_MASKS \
15221c01c8c6SMd Fahad Iqbal Polash 	(BIT_ULL(ICE_AVF_FLOW_FIELD_IPV6_TCP_SYN_NO_ACK) | \
15231c01c8c6SMd Fahad Iqbal Polash 	 BIT_ULL(ICE_AVF_FLOW_FIELD_IPV6_TCP))
15241c01c8c6SMd Fahad Iqbal Polash #define ICE_FLOW_AVF_RSS_ALL_IPV6_MASKS \
15251c01c8c6SMd Fahad Iqbal Polash 	(ICE_FLOW_AVF_RSS_TCP_IPV6_MASKS | ICE_FLOW_AVF_RSS_UDP_IPV6_MASKS | \
15261c01c8c6SMd Fahad Iqbal Polash 	 ICE_FLOW_AVF_RSS_IPV6_MASKS | BIT_ULL(ICE_AVF_FLOW_FIELD_IPV6_SCTP))
15271c01c8c6SMd Fahad Iqbal Polash 
15281c01c8c6SMd Fahad Iqbal Polash /**
15291c01c8c6SMd Fahad Iqbal Polash  * ice_add_avf_rss_cfg - add an RSS configuration for AVF driver
15301c01c8c6SMd Fahad Iqbal Polash  * @hw: pointer to the hardware structure
15311c01c8c6SMd Fahad Iqbal Polash  * @vsi_handle: software VSI handle
15321c01c8c6SMd Fahad Iqbal Polash  * @avf_hash: hash bit fields (ICE_AVF_FLOW_FIELD_*) to configure
15331c01c8c6SMd Fahad Iqbal Polash  *
15341c01c8c6SMd Fahad Iqbal Polash  * This function will take the hash bitmap provided by the AVF driver via a
15351c01c8c6SMd Fahad Iqbal Polash  * message, convert it to ICE-compatible values, and configure RSS flow
15361c01c8c6SMd Fahad Iqbal Polash  * profiles.
15371c01c8c6SMd Fahad Iqbal Polash  */
15381c01c8c6SMd Fahad Iqbal Polash enum ice_status
15391c01c8c6SMd Fahad Iqbal Polash ice_add_avf_rss_cfg(struct ice_hw *hw, u16 vsi_handle, u64 avf_hash)
15401c01c8c6SMd Fahad Iqbal Polash {
15411c01c8c6SMd Fahad Iqbal Polash 	enum ice_status status = 0;
15421c01c8c6SMd Fahad Iqbal Polash 	u64 hash_flds;
15431c01c8c6SMd Fahad Iqbal Polash 
15441c01c8c6SMd Fahad Iqbal Polash 	if (avf_hash == ICE_AVF_FLOW_FIELD_INVALID ||
15451c01c8c6SMd Fahad Iqbal Polash 	    !ice_is_vsi_valid(hw, vsi_handle))
15461c01c8c6SMd Fahad Iqbal Polash 		return ICE_ERR_PARAM;
15471c01c8c6SMd Fahad Iqbal Polash 
15481c01c8c6SMd Fahad Iqbal Polash 	/* Make sure no unsupported bits are specified */
15491c01c8c6SMd Fahad Iqbal Polash 	if (avf_hash & ~(ICE_FLOW_AVF_RSS_ALL_IPV4_MASKS |
15501c01c8c6SMd Fahad Iqbal Polash 			 ICE_FLOW_AVF_RSS_ALL_IPV6_MASKS))
15511c01c8c6SMd Fahad Iqbal Polash 		return ICE_ERR_CFG;
15521c01c8c6SMd Fahad Iqbal Polash 
15531c01c8c6SMd Fahad Iqbal Polash 	hash_flds = avf_hash;
15541c01c8c6SMd Fahad Iqbal Polash 
15551c01c8c6SMd Fahad Iqbal Polash 	/* Always create an L3 RSS configuration for any L4 RSS configuration */
15561c01c8c6SMd Fahad Iqbal Polash 	if (hash_flds & ICE_FLOW_AVF_RSS_ALL_IPV4_MASKS)
15571c01c8c6SMd Fahad Iqbal Polash 		hash_flds |= ICE_FLOW_AVF_RSS_IPV4_MASKS;
15581c01c8c6SMd Fahad Iqbal Polash 
15591c01c8c6SMd Fahad Iqbal Polash 	if (hash_flds & ICE_FLOW_AVF_RSS_ALL_IPV6_MASKS)
15601c01c8c6SMd Fahad Iqbal Polash 		hash_flds |= ICE_FLOW_AVF_RSS_IPV6_MASKS;
15611c01c8c6SMd Fahad Iqbal Polash 
15621c01c8c6SMd Fahad Iqbal Polash 	/* Create the corresponding RSS configuration for each valid hash bit */
15631c01c8c6SMd Fahad Iqbal Polash 	while (hash_flds) {
15641c01c8c6SMd Fahad Iqbal Polash 		u64 rss_hash = ICE_HASH_INVALID;
15651c01c8c6SMd Fahad Iqbal Polash 
15661c01c8c6SMd Fahad Iqbal Polash 		if (hash_flds & ICE_FLOW_AVF_RSS_ALL_IPV4_MASKS) {
15671c01c8c6SMd Fahad Iqbal Polash 			if (hash_flds & ICE_FLOW_AVF_RSS_IPV4_MASKS) {
15681c01c8c6SMd Fahad Iqbal Polash 				rss_hash = ICE_FLOW_HASH_IPV4;
15691c01c8c6SMd Fahad Iqbal Polash 				hash_flds &= ~ICE_FLOW_AVF_RSS_IPV4_MASKS;
15701c01c8c6SMd Fahad Iqbal Polash 			} else if (hash_flds &
15711c01c8c6SMd Fahad Iqbal Polash 				   ICE_FLOW_AVF_RSS_TCP_IPV4_MASKS) {
15721c01c8c6SMd Fahad Iqbal Polash 				rss_hash = ICE_FLOW_HASH_IPV4 |
15731c01c8c6SMd Fahad Iqbal Polash 					ICE_FLOW_HASH_TCP_PORT;
15741c01c8c6SMd Fahad Iqbal Polash 				hash_flds &= ~ICE_FLOW_AVF_RSS_TCP_IPV4_MASKS;
15751c01c8c6SMd Fahad Iqbal Polash 			} else if (hash_flds &
15761c01c8c6SMd Fahad Iqbal Polash 				   ICE_FLOW_AVF_RSS_UDP_IPV4_MASKS) {
15771c01c8c6SMd Fahad Iqbal Polash 				rss_hash = ICE_FLOW_HASH_IPV4 |
15781c01c8c6SMd Fahad Iqbal Polash 					ICE_FLOW_HASH_UDP_PORT;
15791c01c8c6SMd Fahad Iqbal Polash 				hash_flds &= ~ICE_FLOW_AVF_RSS_UDP_IPV4_MASKS;
15801c01c8c6SMd Fahad Iqbal Polash 			} else if (hash_flds &
15811c01c8c6SMd Fahad Iqbal Polash 				   BIT_ULL(ICE_AVF_FLOW_FIELD_IPV4_SCTP)) {
15821c01c8c6SMd Fahad Iqbal Polash 				rss_hash = ICE_FLOW_HASH_IPV4 |
15831c01c8c6SMd Fahad Iqbal Polash 					ICE_FLOW_HASH_SCTP_PORT;
15841c01c8c6SMd Fahad Iqbal Polash 				hash_flds &=
15851c01c8c6SMd Fahad Iqbal Polash 					~BIT_ULL(ICE_AVF_FLOW_FIELD_IPV4_SCTP);
15861c01c8c6SMd Fahad Iqbal Polash 			}
15871c01c8c6SMd Fahad Iqbal Polash 		} else if (hash_flds & ICE_FLOW_AVF_RSS_ALL_IPV6_MASKS) {
15881c01c8c6SMd Fahad Iqbal Polash 			if (hash_flds & ICE_FLOW_AVF_RSS_IPV6_MASKS) {
15891c01c8c6SMd Fahad Iqbal Polash 				rss_hash = ICE_FLOW_HASH_IPV6;
15901c01c8c6SMd Fahad Iqbal Polash 				hash_flds &= ~ICE_FLOW_AVF_RSS_IPV6_MASKS;
15911c01c8c6SMd Fahad Iqbal Polash 			} else if (hash_flds &
15921c01c8c6SMd Fahad Iqbal Polash 				   ICE_FLOW_AVF_RSS_TCP_IPV6_MASKS) {
15931c01c8c6SMd Fahad Iqbal Polash 				rss_hash = ICE_FLOW_HASH_IPV6 |
15941c01c8c6SMd Fahad Iqbal Polash 					ICE_FLOW_HASH_TCP_PORT;
15951c01c8c6SMd Fahad Iqbal Polash 				hash_flds &= ~ICE_FLOW_AVF_RSS_TCP_IPV6_MASKS;
15961c01c8c6SMd Fahad Iqbal Polash 			} else if (hash_flds &
15971c01c8c6SMd Fahad Iqbal Polash 				   ICE_FLOW_AVF_RSS_UDP_IPV6_MASKS) {
15981c01c8c6SMd Fahad Iqbal Polash 				rss_hash = ICE_FLOW_HASH_IPV6 |
15991c01c8c6SMd Fahad Iqbal Polash 					ICE_FLOW_HASH_UDP_PORT;
16001c01c8c6SMd Fahad Iqbal Polash 				hash_flds &= ~ICE_FLOW_AVF_RSS_UDP_IPV6_MASKS;
16011c01c8c6SMd Fahad Iqbal Polash 			} else if (hash_flds &
16021c01c8c6SMd Fahad Iqbal Polash 				   BIT_ULL(ICE_AVF_FLOW_FIELD_IPV6_SCTP)) {
16031c01c8c6SMd Fahad Iqbal Polash 				rss_hash = ICE_FLOW_HASH_IPV6 |
16041c01c8c6SMd Fahad Iqbal Polash 					ICE_FLOW_HASH_SCTP_PORT;
16051c01c8c6SMd Fahad Iqbal Polash 				hash_flds &=
16061c01c8c6SMd Fahad Iqbal Polash 					~BIT_ULL(ICE_AVF_FLOW_FIELD_IPV6_SCTP);
16071c01c8c6SMd Fahad Iqbal Polash 			}
16081c01c8c6SMd Fahad Iqbal Polash 		}
16091c01c8c6SMd Fahad Iqbal Polash 
16101c01c8c6SMd Fahad Iqbal Polash 		if (rss_hash == ICE_HASH_INVALID)
16111c01c8c6SMd Fahad Iqbal Polash 			return ICE_ERR_OUT_OF_RANGE;
16121c01c8c6SMd Fahad Iqbal Polash 
16131c01c8c6SMd Fahad Iqbal Polash 		status = ice_add_rss_cfg(hw, vsi_handle, rss_hash,
16141c01c8c6SMd Fahad Iqbal Polash 					 ICE_FLOW_SEG_HDR_NONE);
16151c01c8c6SMd Fahad Iqbal Polash 		if (status)
16161c01c8c6SMd Fahad Iqbal Polash 			break;
16171c01c8c6SMd Fahad Iqbal Polash 	}
16181c01c8c6SMd Fahad Iqbal Polash 
16191c01c8c6SMd Fahad Iqbal Polash 	return status;
16201c01c8c6SMd Fahad Iqbal Polash }
16211c01c8c6SMd Fahad Iqbal Polash 
1622c90ed40cSTony Nguyen /**
1623c90ed40cSTony Nguyen  * ice_replay_rss_cfg - replay RSS configurations associated with VSI
1624c90ed40cSTony Nguyen  * @hw: pointer to the hardware structure
1625c90ed40cSTony Nguyen  * @vsi_handle: software VSI handle
1626c90ed40cSTony Nguyen  */
1627c90ed40cSTony Nguyen enum ice_status ice_replay_rss_cfg(struct ice_hw *hw, u16 vsi_handle)
1628c90ed40cSTony Nguyen {
1629c90ed40cSTony Nguyen 	enum ice_status status = 0;
1630c90ed40cSTony Nguyen 	struct ice_rss_cfg *r;
1631c90ed40cSTony Nguyen 
1632c90ed40cSTony Nguyen 	if (!ice_is_vsi_valid(hw, vsi_handle))
1633c90ed40cSTony Nguyen 		return ICE_ERR_PARAM;
1634c90ed40cSTony Nguyen 
1635c90ed40cSTony Nguyen 	mutex_lock(&hw->rss_locks);
1636c90ed40cSTony Nguyen 	list_for_each_entry(r, &hw->rss_list_head, l_entry) {
1637c90ed40cSTony Nguyen 		if (test_bit(vsi_handle, r->vsis)) {
1638451f2c44STony Nguyen 			status = ice_add_rss_cfg_sync(hw, vsi_handle,
1639451f2c44STony Nguyen 						      r->hashed_flds,
1640c90ed40cSTony Nguyen 						      r->packet_hdr,
1641c90ed40cSTony Nguyen 						      ICE_RSS_OUTER_HEADERS);
1642c90ed40cSTony Nguyen 			if (status)
1643c90ed40cSTony Nguyen 				break;
1644a4e82a81STony Nguyen 			status = ice_add_rss_cfg_sync(hw, vsi_handle,
1645a4e82a81STony Nguyen 						      r->hashed_flds,
1646a4e82a81STony Nguyen 						      r->packet_hdr,
1647a4e82a81STony Nguyen 						      ICE_RSS_INNER_HEADERS);
1648a4e82a81STony Nguyen 			if (status)
1649a4e82a81STony Nguyen 				break;
1650c90ed40cSTony Nguyen 		}
1651c90ed40cSTony Nguyen 	}
1652c90ed40cSTony Nguyen 	mutex_unlock(&hw->rss_locks);
1653c90ed40cSTony Nguyen 
1654c90ed40cSTony Nguyen 	return status;
1655c90ed40cSTony Nguyen }
16566876fb64SMd Fahad Iqbal Polash 
16576876fb64SMd Fahad Iqbal Polash /**
16586876fb64SMd Fahad Iqbal Polash  * ice_get_rss_cfg - returns hashed fields for the given header types
16596876fb64SMd Fahad Iqbal Polash  * @hw: pointer to the hardware structure
16606876fb64SMd Fahad Iqbal Polash  * @vsi_handle: software VSI handle
16616876fb64SMd Fahad Iqbal Polash  * @hdrs: protocol header type
16626876fb64SMd Fahad Iqbal Polash  *
16636876fb64SMd Fahad Iqbal Polash  * This function will return the match fields of the first instance of flow
16646876fb64SMd Fahad Iqbal Polash  * profile having the given header types and containing input VSI
16656876fb64SMd Fahad Iqbal Polash  */
16666876fb64SMd Fahad Iqbal Polash u64 ice_get_rss_cfg(struct ice_hw *hw, u16 vsi_handle, u32 hdrs)
16676876fb64SMd Fahad Iqbal Polash {
1668cdedbab9SVignesh Sridhar 	u64 rss_hash = ICE_HASH_INVALID;
1669cdedbab9SVignesh Sridhar 	struct ice_rss_cfg *r;
16706876fb64SMd Fahad Iqbal Polash 
16716876fb64SMd Fahad Iqbal Polash 	/* verify if the protocol header is non zero and VSI is valid */
16726876fb64SMd Fahad Iqbal Polash 	if (hdrs == ICE_FLOW_SEG_HDR_NONE || !ice_is_vsi_valid(hw, vsi_handle))
16736876fb64SMd Fahad Iqbal Polash 		return ICE_HASH_INVALID;
16746876fb64SMd Fahad Iqbal Polash 
16756876fb64SMd Fahad Iqbal Polash 	mutex_lock(&hw->rss_locks);
16766876fb64SMd Fahad Iqbal Polash 	list_for_each_entry(r, &hw->rss_list_head, l_entry)
16776876fb64SMd Fahad Iqbal Polash 		if (test_bit(vsi_handle, r->vsis) &&
16786876fb64SMd Fahad Iqbal Polash 		    r->packet_hdr == hdrs) {
1679cdedbab9SVignesh Sridhar 			rss_hash = r->hashed_flds;
16806876fb64SMd Fahad Iqbal Polash 			break;
16816876fb64SMd Fahad Iqbal Polash 		}
16826876fb64SMd Fahad Iqbal Polash 	mutex_unlock(&hw->rss_locks);
16836876fb64SMd Fahad Iqbal Polash 
1684cdedbab9SVignesh Sridhar 	return rss_hash;
16856876fb64SMd Fahad Iqbal Polash }
1686