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 
10231ad4e4eSTony Nguyen /* UDP Packet types for non-tunneled packets or tunneled
10331ad4e4eSTony Nguyen  * packets with inner UDP.
10431ad4e4eSTony Nguyen  */
10531ad4e4eSTony Nguyen static const u32 ice_ptypes_udp_il[] = {
10631ad4e4eSTony Nguyen 	0x81000000, 0x20204040, 0x04000010, 0x80810102,
10731ad4e4eSTony Nguyen 	0x00000040, 0x00000000, 0x00000000, 0x00000000,
10831ad4e4eSTony Nguyen 	0x00000000, 0x00000000, 0x00000000, 0x00000000,
10931ad4e4eSTony Nguyen 	0x00000000, 0x00000000, 0x00000000, 0x00000000,
11031ad4e4eSTony Nguyen 	0x00000000, 0x00000000, 0x00000000, 0x00000000,
11131ad4e4eSTony Nguyen 	0x00000000, 0x00000000, 0x00000000, 0x00000000,
11231ad4e4eSTony Nguyen 	0x00000000, 0x00000000, 0x00000000, 0x00000000,
11331ad4e4eSTony Nguyen 	0x00000000, 0x00000000, 0x00000000, 0x00000000,
11431ad4e4eSTony Nguyen };
11531ad4e4eSTony Nguyen 
11631ad4e4eSTony Nguyen /* Packet types for packets with an Innermost/Last TCP header */
11731ad4e4eSTony Nguyen static const u32 ice_ptypes_tcp_il[] = {
11831ad4e4eSTony Nguyen 	0x04000000, 0x80810102, 0x10000040, 0x02040408,
11931ad4e4eSTony Nguyen 	0x00000102, 0x00000000, 0x00000000, 0x00000000,
12031ad4e4eSTony Nguyen 	0x00000000, 0x00000000, 0x00000000, 0x00000000,
12131ad4e4eSTony Nguyen 	0x00000000, 0x00000000, 0x00000000, 0x00000000,
12231ad4e4eSTony Nguyen 	0x00000000, 0x00000000, 0x00000000, 0x00000000,
12331ad4e4eSTony Nguyen 	0x00000000, 0x00000000, 0x00000000, 0x00000000,
12431ad4e4eSTony Nguyen 	0x00000000, 0x00000000, 0x00000000, 0x00000000,
12531ad4e4eSTony Nguyen 	0x00000000, 0x00000000, 0x00000000, 0x00000000,
12631ad4e4eSTony Nguyen };
12731ad4e4eSTony Nguyen 
12831ad4e4eSTony Nguyen /* Packet types for packets with an Innermost/Last SCTP header */
12931ad4e4eSTony Nguyen static const u32 ice_ptypes_sctp_il[] = {
13031ad4e4eSTony Nguyen 	0x08000000, 0x01020204, 0x20000081, 0x04080810,
13131ad4e4eSTony Nguyen 	0x00000204, 0x00000000, 0x00000000, 0x00000000,
13231ad4e4eSTony Nguyen 	0x00000000, 0x00000000, 0x00000000, 0x00000000,
13331ad4e4eSTony Nguyen 	0x00000000, 0x00000000, 0x00000000, 0x00000000,
13431ad4e4eSTony Nguyen 	0x00000000, 0x00000000, 0x00000000, 0x00000000,
13531ad4e4eSTony Nguyen 	0x00000000, 0x00000000, 0x00000000, 0x00000000,
13631ad4e4eSTony Nguyen 	0x00000000, 0x00000000, 0x00000000, 0x00000000,
13731ad4e4eSTony Nguyen 	0x00000000, 0x00000000, 0x00000000, 0x00000000,
13831ad4e4eSTony Nguyen };
13931ad4e4eSTony Nguyen 
140a4e82a81STony Nguyen /* Packet types for packets with an Outermost/First GRE header */
141a4e82a81STony Nguyen static const u32 ice_ptypes_gre_of[] = {
142a4e82a81STony Nguyen 	0x00000000, 0xBFBF7800, 0x000001DF, 0xFEFDE000,
143a4e82a81STony Nguyen 	0x0000017E, 0x00000000, 0x00000000, 0x00000000,
144a4e82a81STony Nguyen 	0x00000000, 0x00000000, 0x00000000, 0x00000000,
145a4e82a81STony Nguyen 	0x00000000, 0x00000000, 0x00000000, 0x00000000,
146a4e82a81STony Nguyen 	0x00000000, 0x00000000, 0x00000000, 0x00000000,
147a4e82a81STony Nguyen 	0x00000000, 0x00000000, 0x00000000, 0x00000000,
148a4e82a81STony Nguyen 	0x00000000, 0x00000000, 0x00000000, 0x00000000,
149a4e82a81STony Nguyen 	0x00000000, 0x00000000, 0x00000000, 0x00000000,
150a4e82a81STony Nguyen };
151a4e82a81STony Nguyen 
15231ad4e4eSTony Nguyen /* Manage parameters and info. used during the creation of a flow profile */
15331ad4e4eSTony Nguyen struct ice_flow_prof_params {
15431ad4e4eSTony Nguyen 	enum ice_block blk;
15531ad4e4eSTony Nguyen 	u16 entry_length; /* # of bytes formatted entry will require */
15631ad4e4eSTony Nguyen 	u8 es_cnt;
15731ad4e4eSTony Nguyen 	struct ice_flow_prof *prof;
15831ad4e4eSTony Nguyen 
15931ad4e4eSTony Nguyen 	/* For ACL, the es[0] will have the data of ICE_RX_MDID_PKT_FLAGS_15_0
16031ad4e4eSTony Nguyen 	 * This will give us the direction flags.
16131ad4e4eSTony Nguyen 	 */
16231ad4e4eSTony Nguyen 	struct ice_fv_word es[ICE_MAX_FV_WORDS];
16331ad4e4eSTony Nguyen 	DECLARE_BITMAP(ptypes, ICE_FLOW_PTYPE_MAX);
16431ad4e4eSTony Nguyen };
16531ad4e4eSTony Nguyen 
16631ad4e4eSTony Nguyen #define ICE_FLOW_SEG_HDRS_L3_MASK	\
16731ad4e4eSTony Nguyen 	(ICE_FLOW_SEG_HDR_IPV4 | ICE_FLOW_SEG_HDR_IPV6)
16831ad4e4eSTony Nguyen #define ICE_FLOW_SEG_HDRS_L4_MASK	\
16931ad4e4eSTony Nguyen 	(ICE_FLOW_SEG_HDR_TCP | ICE_FLOW_SEG_HDR_UDP | ICE_FLOW_SEG_HDR_SCTP)
17031ad4e4eSTony Nguyen 
17131ad4e4eSTony Nguyen /**
17231ad4e4eSTony Nguyen  * ice_flow_val_hdrs - validates packet segments for valid protocol headers
17331ad4e4eSTony Nguyen  * @segs: array of one or more packet segments that describe the flow
17431ad4e4eSTony Nguyen  * @segs_cnt: number of packet segments provided
17531ad4e4eSTony Nguyen  */
17631ad4e4eSTony Nguyen static enum ice_status
17731ad4e4eSTony Nguyen ice_flow_val_hdrs(struct ice_flow_seg_info *segs, u8 segs_cnt)
17831ad4e4eSTony Nguyen {
17931ad4e4eSTony Nguyen 	u8 i;
18031ad4e4eSTony Nguyen 
18131ad4e4eSTony Nguyen 	for (i = 0; i < segs_cnt; i++) {
18231ad4e4eSTony Nguyen 		/* Multiple L3 headers */
18331ad4e4eSTony Nguyen 		if (segs[i].hdrs & ICE_FLOW_SEG_HDRS_L3_MASK &&
18431ad4e4eSTony Nguyen 		    !is_power_of_2(segs[i].hdrs & ICE_FLOW_SEG_HDRS_L3_MASK))
18531ad4e4eSTony Nguyen 			return ICE_ERR_PARAM;
18631ad4e4eSTony Nguyen 
18731ad4e4eSTony Nguyen 		/* Multiple L4 headers */
18831ad4e4eSTony Nguyen 		if (segs[i].hdrs & ICE_FLOW_SEG_HDRS_L4_MASK &&
18931ad4e4eSTony Nguyen 		    !is_power_of_2(segs[i].hdrs & ICE_FLOW_SEG_HDRS_L4_MASK))
19031ad4e4eSTony Nguyen 			return ICE_ERR_PARAM;
19131ad4e4eSTony Nguyen 	}
19231ad4e4eSTony Nguyen 
19331ad4e4eSTony Nguyen 	return 0;
19431ad4e4eSTony Nguyen }
19531ad4e4eSTony Nguyen 
19631ad4e4eSTony Nguyen /**
19731ad4e4eSTony Nguyen  * ice_flow_proc_seg_hdrs - process protocol headers present in pkt segments
19831ad4e4eSTony Nguyen  * @params: information about the flow to be processed
19931ad4e4eSTony Nguyen  *
20031ad4e4eSTony Nguyen  * This function identifies the packet types associated with the protocol
20131ad4e4eSTony Nguyen  * headers being present in packet segments of the specified flow profile.
20231ad4e4eSTony Nguyen  */
20331ad4e4eSTony Nguyen static enum ice_status
20431ad4e4eSTony Nguyen ice_flow_proc_seg_hdrs(struct ice_flow_prof_params *params)
20531ad4e4eSTony Nguyen {
20631ad4e4eSTony Nguyen 	struct ice_flow_prof *prof;
20731ad4e4eSTony Nguyen 	u8 i;
20831ad4e4eSTony Nguyen 
20931ad4e4eSTony Nguyen 	memset(params->ptypes, 0xff, sizeof(params->ptypes));
21031ad4e4eSTony Nguyen 
21131ad4e4eSTony Nguyen 	prof = params->prof;
21231ad4e4eSTony Nguyen 
21331ad4e4eSTony Nguyen 	for (i = 0; i < params->prof->segs_cnt; i++) {
21431ad4e4eSTony Nguyen 		const unsigned long *src;
21531ad4e4eSTony Nguyen 		u32 hdrs;
21631ad4e4eSTony Nguyen 
21731ad4e4eSTony Nguyen 		hdrs = prof->segs[i].hdrs;
21831ad4e4eSTony Nguyen 
21931ad4e4eSTony Nguyen 		if (hdrs & ICE_FLOW_SEG_HDR_IPV4) {
22031ad4e4eSTony Nguyen 			src = !i ? (const unsigned long *)ice_ptypes_ipv4_ofos :
22131ad4e4eSTony Nguyen 				(const unsigned long *)ice_ptypes_ipv4_il;
22231ad4e4eSTony Nguyen 			bitmap_and(params->ptypes, params->ptypes, src,
22331ad4e4eSTony Nguyen 				   ICE_FLOW_PTYPE_MAX);
22431ad4e4eSTony Nguyen 		} else if (hdrs & ICE_FLOW_SEG_HDR_IPV6) {
22531ad4e4eSTony Nguyen 			src = !i ? (const unsigned long *)ice_ptypes_ipv6_ofos :
22631ad4e4eSTony Nguyen 				(const unsigned long *)ice_ptypes_ipv6_il;
22731ad4e4eSTony Nguyen 			bitmap_and(params->ptypes, params->ptypes, src,
22831ad4e4eSTony Nguyen 				   ICE_FLOW_PTYPE_MAX);
22931ad4e4eSTony Nguyen 		}
23031ad4e4eSTony Nguyen 
23131ad4e4eSTony Nguyen 		if (hdrs & ICE_FLOW_SEG_HDR_UDP) {
23231ad4e4eSTony Nguyen 			src = (const unsigned long *)ice_ptypes_udp_il;
23331ad4e4eSTony Nguyen 			bitmap_and(params->ptypes, params->ptypes, src,
23431ad4e4eSTony Nguyen 				   ICE_FLOW_PTYPE_MAX);
23531ad4e4eSTony Nguyen 		} else if (hdrs & ICE_FLOW_SEG_HDR_TCP) {
23631ad4e4eSTony Nguyen 			bitmap_and(params->ptypes, params->ptypes,
23731ad4e4eSTony Nguyen 				   (const unsigned long *)ice_ptypes_tcp_il,
23831ad4e4eSTony Nguyen 				   ICE_FLOW_PTYPE_MAX);
23931ad4e4eSTony Nguyen 		} else if (hdrs & ICE_FLOW_SEG_HDR_SCTP) {
24031ad4e4eSTony Nguyen 			src = (const unsigned long *)ice_ptypes_sctp_il;
24131ad4e4eSTony Nguyen 			bitmap_and(params->ptypes, params->ptypes, src,
24231ad4e4eSTony Nguyen 				   ICE_FLOW_PTYPE_MAX);
243a4e82a81STony Nguyen 		} else if (hdrs & ICE_FLOW_SEG_HDR_GRE) {
244a4e82a81STony Nguyen 			if (!i) {
245a4e82a81STony Nguyen 				src = (const unsigned long *)ice_ptypes_gre_of;
246a4e82a81STony Nguyen 				bitmap_and(params->ptypes, params->ptypes,
247a4e82a81STony Nguyen 					   src, ICE_FLOW_PTYPE_MAX);
248a4e82a81STony Nguyen 			}
24931ad4e4eSTony Nguyen 		}
25031ad4e4eSTony Nguyen 	}
25131ad4e4eSTony Nguyen 
25231ad4e4eSTony Nguyen 	return 0;
25331ad4e4eSTony Nguyen }
25431ad4e4eSTony Nguyen 
25531ad4e4eSTony Nguyen /**
25631ad4e4eSTony Nguyen  * ice_flow_xtract_fld - Create an extraction sequence entry for the given field
25731ad4e4eSTony Nguyen  * @hw: pointer to the HW struct
25831ad4e4eSTony Nguyen  * @params: information about the flow to be processed
25931ad4e4eSTony Nguyen  * @seg: packet segment index of the field to be extracted
26031ad4e4eSTony Nguyen  * @fld: ID of field to be extracted
26131ad4e4eSTony Nguyen  *
26231ad4e4eSTony Nguyen  * This function determines the protocol ID, offset, and size of the given
26331ad4e4eSTony Nguyen  * field. It then allocates one or more extraction sequence entries for the
26431ad4e4eSTony Nguyen  * given field, and fill the entries with protocol ID and offset information.
26531ad4e4eSTony Nguyen  */
26631ad4e4eSTony Nguyen static enum ice_status
26731ad4e4eSTony Nguyen ice_flow_xtract_fld(struct ice_hw *hw, struct ice_flow_prof_params *params,
26831ad4e4eSTony Nguyen 		    u8 seg, enum ice_flow_field fld)
26931ad4e4eSTony Nguyen {
27031ad4e4eSTony Nguyen 	enum ice_prot_id prot_id = ICE_PROT_ID_INVAL;
27131ad4e4eSTony Nguyen 	u8 fv_words = hw->blk[params->blk].es.fvw;
27231ad4e4eSTony Nguyen 	struct ice_flow_fld_info *flds;
27331ad4e4eSTony Nguyen 	u16 cnt, ese_bits, i;
27431ad4e4eSTony Nguyen 	u16 off;
27531ad4e4eSTony Nguyen 
27631ad4e4eSTony Nguyen 	flds = params->prof->segs[seg].fields;
27731ad4e4eSTony Nguyen 
27831ad4e4eSTony Nguyen 	switch (fld) {
27931ad4e4eSTony Nguyen 	case ICE_FLOW_FIELD_IDX_IPV4_SA:
28031ad4e4eSTony Nguyen 	case ICE_FLOW_FIELD_IDX_IPV4_DA:
28131ad4e4eSTony Nguyen 		prot_id = seg == 0 ? ICE_PROT_IPV4_OF_OR_S : ICE_PROT_IPV4_IL;
28231ad4e4eSTony Nguyen 		break;
28331ad4e4eSTony Nguyen 	case ICE_FLOW_FIELD_IDX_IPV6_SA:
28431ad4e4eSTony Nguyen 	case ICE_FLOW_FIELD_IDX_IPV6_DA:
28531ad4e4eSTony Nguyen 		prot_id = seg == 0 ? ICE_PROT_IPV6_OF_OR_S : ICE_PROT_IPV6_IL;
28631ad4e4eSTony Nguyen 		break;
28731ad4e4eSTony Nguyen 	case ICE_FLOW_FIELD_IDX_TCP_SRC_PORT:
28831ad4e4eSTony Nguyen 	case ICE_FLOW_FIELD_IDX_TCP_DST_PORT:
28931ad4e4eSTony Nguyen 		prot_id = ICE_PROT_TCP_IL;
29031ad4e4eSTony Nguyen 		break;
29131ad4e4eSTony Nguyen 	case ICE_FLOW_FIELD_IDX_UDP_SRC_PORT:
29231ad4e4eSTony Nguyen 	case ICE_FLOW_FIELD_IDX_UDP_DST_PORT:
29331ad4e4eSTony Nguyen 		prot_id = ICE_PROT_UDP_IL_OR_S;
29431ad4e4eSTony Nguyen 		break;
2951c01c8c6SMd Fahad Iqbal Polash 	case ICE_FLOW_FIELD_IDX_SCTP_SRC_PORT:
2961c01c8c6SMd Fahad Iqbal Polash 	case ICE_FLOW_FIELD_IDX_SCTP_DST_PORT:
2971c01c8c6SMd Fahad Iqbal Polash 		prot_id = ICE_PROT_SCTP_IL;
2981c01c8c6SMd Fahad Iqbal Polash 		break;
299a4e82a81STony Nguyen 	case ICE_FLOW_FIELD_IDX_GRE_KEYID:
300a4e82a81STony Nguyen 		prot_id = ICE_PROT_GRE_OF;
301a4e82a81STony Nguyen 		break;
30231ad4e4eSTony Nguyen 	default:
30331ad4e4eSTony Nguyen 		return ICE_ERR_NOT_IMPL;
30431ad4e4eSTony Nguyen 	}
30531ad4e4eSTony Nguyen 
30631ad4e4eSTony Nguyen 	/* Each extraction sequence entry is a word in size, and extracts a
30731ad4e4eSTony Nguyen 	 * word-aligned offset from a protocol header.
30831ad4e4eSTony Nguyen 	 */
30931ad4e4eSTony Nguyen 	ese_bits = ICE_FLOW_FV_EXTRACT_SZ * BITS_PER_BYTE;
31031ad4e4eSTony Nguyen 
31131ad4e4eSTony Nguyen 	flds[fld].xtrct.prot_id = prot_id;
31231ad4e4eSTony Nguyen 	flds[fld].xtrct.off = (ice_flds_info[fld].off / ese_bits) *
31331ad4e4eSTony Nguyen 		ICE_FLOW_FV_EXTRACT_SZ;
31431ad4e4eSTony Nguyen 	flds[fld].xtrct.disp = (u8)(ice_flds_info[fld].off % ese_bits);
31531ad4e4eSTony Nguyen 	flds[fld].xtrct.idx = params->es_cnt;
31631ad4e4eSTony Nguyen 
31731ad4e4eSTony Nguyen 	/* Adjust the next field-entry index after accommodating the number of
31831ad4e4eSTony Nguyen 	 * entries this field consumes
31931ad4e4eSTony Nguyen 	 */
32031ad4e4eSTony Nguyen 	cnt = DIV_ROUND_UP(flds[fld].xtrct.disp + ice_flds_info[fld].size,
32131ad4e4eSTony Nguyen 			   ese_bits);
32231ad4e4eSTony Nguyen 
32331ad4e4eSTony Nguyen 	/* Fill in the extraction sequence entries needed for this field */
32431ad4e4eSTony Nguyen 	off = flds[fld].xtrct.off;
32531ad4e4eSTony Nguyen 	for (i = 0; i < cnt; i++) {
32631ad4e4eSTony Nguyen 		u8 idx;
32731ad4e4eSTony Nguyen 
32831ad4e4eSTony Nguyen 		/* Make sure the number of extraction sequence required
32931ad4e4eSTony Nguyen 		 * does not exceed the block's capability
33031ad4e4eSTony Nguyen 		 */
33131ad4e4eSTony Nguyen 		if (params->es_cnt >= fv_words)
33231ad4e4eSTony Nguyen 			return ICE_ERR_MAX_LIMIT;
33331ad4e4eSTony Nguyen 
33431ad4e4eSTony Nguyen 		/* some blocks require a reversed field vector layout */
33531ad4e4eSTony Nguyen 		if (hw->blk[params->blk].es.reverse)
33631ad4e4eSTony Nguyen 			idx = fv_words - params->es_cnt - 1;
33731ad4e4eSTony Nguyen 		else
33831ad4e4eSTony Nguyen 			idx = params->es_cnt;
33931ad4e4eSTony Nguyen 
34031ad4e4eSTony Nguyen 		params->es[idx].prot_id = prot_id;
34131ad4e4eSTony Nguyen 		params->es[idx].off = off;
34231ad4e4eSTony Nguyen 		params->es_cnt++;
34331ad4e4eSTony Nguyen 
34431ad4e4eSTony Nguyen 		off += ICE_FLOW_FV_EXTRACT_SZ;
34531ad4e4eSTony Nguyen 	}
34631ad4e4eSTony Nguyen 
34731ad4e4eSTony Nguyen 	return 0;
34831ad4e4eSTony Nguyen }
34931ad4e4eSTony Nguyen 
35031ad4e4eSTony Nguyen /**
35131ad4e4eSTony Nguyen  * ice_flow_create_xtrct_seq - Create an extraction sequence for given segments
35231ad4e4eSTony Nguyen  * @hw: pointer to the HW struct
35331ad4e4eSTony Nguyen  * @params: information about the flow to be processed
35431ad4e4eSTony Nguyen  *
35531ad4e4eSTony Nguyen  * This function iterates through all matched fields in the given segments, and
35631ad4e4eSTony Nguyen  * creates an extraction sequence for the fields.
35731ad4e4eSTony Nguyen  */
35831ad4e4eSTony Nguyen static enum ice_status
35931ad4e4eSTony Nguyen ice_flow_create_xtrct_seq(struct ice_hw *hw,
36031ad4e4eSTony Nguyen 			  struct ice_flow_prof_params *params)
36131ad4e4eSTony Nguyen {
36231ad4e4eSTony Nguyen 	struct ice_flow_prof *prof = params->prof;
36331ad4e4eSTony Nguyen 	enum ice_status status = 0;
36431ad4e4eSTony Nguyen 	u8 i;
36531ad4e4eSTony Nguyen 
36631ad4e4eSTony Nguyen 	for (i = 0; i < prof->segs_cnt; i++) {
36731ad4e4eSTony Nguyen 		u8 j;
36831ad4e4eSTony Nguyen 
36931ad4e4eSTony Nguyen 		for_each_set_bit(j, (unsigned long *)&prof->segs[i].match,
37031ad4e4eSTony Nguyen 				 ICE_FLOW_FIELD_IDX_MAX) {
37131ad4e4eSTony Nguyen 			status = ice_flow_xtract_fld(hw, params, i,
37231ad4e4eSTony Nguyen 						     (enum ice_flow_field)j);
37331ad4e4eSTony Nguyen 			if (status)
37431ad4e4eSTony Nguyen 				return status;
37531ad4e4eSTony Nguyen 		}
37631ad4e4eSTony Nguyen 	}
37731ad4e4eSTony Nguyen 
37831ad4e4eSTony Nguyen 	return status;
37931ad4e4eSTony Nguyen }
38031ad4e4eSTony Nguyen 
38131ad4e4eSTony Nguyen /**
38231ad4e4eSTony Nguyen  * ice_flow_proc_segs - process all packet segments associated with a profile
38331ad4e4eSTony Nguyen  * @hw: pointer to the HW struct
38431ad4e4eSTony Nguyen  * @params: information about the flow to be processed
38531ad4e4eSTony Nguyen  */
38631ad4e4eSTony Nguyen static enum ice_status
38731ad4e4eSTony Nguyen ice_flow_proc_segs(struct ice_hw *hw, struct ice_flow_prof_params *params)
38831ad4e4eSTony Nguyen {
38931ad4e4eSTony Nguyen 	enum ice_status status;
39031ad4e4eSTony Nguyen 
39131ad4e4eSTony Nguyen 	status = ice_flow_proc_seg_hdrs(params);
39231ad4e4eSTony Nguyen 	if (status)
39331ad4e4eSTony Nguyen 		return status;
39431ad4e4eSTony Nguyen 
39531ad4e4eSTony Nguyen 	status = ice_flow_create_xtrct_seq(hw, params);
39631ad4e4eSTony Nguyen 	if (status)
39731ad4e4eSTony Nguyen 		return status;
39831ad4e4eSTony Nguyen 
39931ad4e4eSTony Nguyen 	switch (params->blk) {
400148beb61SHenry Tieman 	case ICE_BLK_FD:
40131ad4e4eSTony Nguyen 	case ICE_BLK_RSS:
40231ad4e4eSTony Nguyen 		status = 0;
40331ad4e4eSTony Nguyen 		break;
40431ad4e4eSTony Nguyen 	default:
40531ad4e4eSTony Nguyen 		return ICE_ERR_NOT_IMPL;
40631ad4e4eSTony Nguyen 	}
40731ad4e4eSTony Nguyen 
40831ad4e4eSTony Nguyen 	return status;
40931ad4e4eSTony Nguyen }
41031ad4e4eSTony Nguyen 
4112c61054cSTony Nguyen #define ICE_FLOW_FIND_PROF_CHK_FLDS	0x00000001
4122c61054cSTony Nguyen #define ICE_FLOW_FIND_PROF_CHK_VSI	0x00000002
4132c61054cSTony Nguyen #define ICE_FLOW_FIND_PROF_NOT_CHK_DIR	0x00000004
4142c61054cSTony Nguyen 
4152c61054cSTony Nguyen /**
4162c61054cSTony Nguyen  * ice_flow_find_prof_conds - Find a profile matching headers and conditions
4172c61054cSTony Nguyen  * @hw: pointer to the HW struct
4182c61054cSTony Nguyen  * @blk: classification stage
4192c61054cSTony Nguyen  * @dir: flow direction
4202c61054cSTony Nguyen  * @segs: array of one or more packet segments that describe the flow
4212c61054cSTony Nguyen  * @segs_cnt: number of packet segments provided
4222c61054cSTony Nguyen  * @vsi_handle: software VSI handle to check VSI (ICE_FLOW_FIND_PROF_CHK_VSI)
4232c61054cSTony Nguyen  * @conds: additional conditions to be checked (ICE_FLOW_FIND_PROF_CHK_*)
4242c61054cSTony Nguyen  */
4252c61054cSTony Nguyen static struct ice_flow_prof *
4262c61054cSTony Nguyen ice_flow_find_prof_conds(struct ice_hw *hw, enum ice_block blk,
4272c61054cSTony Nguyen 			 enum ice_flow_dir dir, struct ice_flow_seg_info *segs,
4282c61054cSTony Nguyen 			 u8 segs_cnt, u16 vsi_handle, u32 conds)
4292c61054cSTony Nguyen {
4302c61054cSTony Nguyen 	struct ice_flow_prof *p, *prof = NULL;
4312c61054cSTony Nguyen 
4322c61054cSTony Nguyen 	mutex_lock(&hw->fl_profs_locks[blk]);
4332c61054cSTony Nguyen 	list_for_each_entry(p, &hw->fl_profs[blk], l_entry)
4342c61054cSTony Nguyen 		if ((p->dir == dir || conds & ICE_FLOW_FIND_PROF_NOT_CHK_DIR) &&
4352c61054cSTony Nguyen 		    segs_cnt && segs_cnt == p->segs_cnt) {
4362c61054cSTony Nguyen 			u8 i;
4372c61054cSTony Nguyen 
4382c61054cSTony Nguyen 			/* Check for profile-VSI association if specified */
4392c61054cSTony Nguyen 			if ((conds & ICE_FLOW_FIND_PROF_CHK_VSI) &&
4402c61054cSTony Nguyen 			    ice_is_vsi_valid(hw, vsi_handle) &&
4412c61054cSTony Nguyen 			    !test_bit(vsi_handle, p->vsis))
4422c61054cSTony Nguyen 				continue;
4432c61054cSTony Nguyen 
4442c61054cSTony Nguyen 			/* Protocol headers must be checked. Matched fields are
4452c61054cSTony Nguyen 			 * checked if specified.
4462c61054cSTony Nguyen 			 */
4472c61054cSTony Nguyen 			for (i = 0; i < segs_cnt; i++)
4482c61054cSTony Nguyen 				if (segs[i].hdrs != p->segs[i].hdrs ||
4492c61054cSTony Nguyen 				    ((conds & ICE_FLOW_FIND_PROF_CHK_FLDS) &&
4502c61054cSTony Nguyen 				     segs[i].match != p->segs[i].match))
4512c61054cSTony Nguyen 					break;
4522c61054cSTony Nguyen 
4532c61054cSTony Nguyen 			/* A match is found if all segments are matched */
4542c61054cSTony Nguyen 			if (i == segs_cnt) {
4552c61054cSTony Nguyen 				prof = p;
4562c61054cSTony Nguyen 				break;
4572c61054cSTony Nguyen 			}
4582c61054cSTony Nguyen 		}
4592c61054cSTony Nguyen 	mutex_unlock(&hw->fl_profs_locks[blk]);
4602c61054cSTony Nguyen 
4612c61054cSTony Nguyen 	return prof;
4622c61054cSTony Nguyen }
4632c61054cSTony Nguyen 
4642c61054cSTony Nguyen /**
4652c61054cSTony Nguyen  * ice_flow_find_prof_id - Look up a profile with given profile ID
4662c61054cSTony Nguyen  * @hw: pointer to the HW struct
4672c61054cSTony Nguyen  * @blk: classification stage
4682c61054cSTony Nguyen  * @prof_id: unique ID to identify this flow profile
4692c61054cSTony Nguyen  */
4702c61054cSTony Nguyen static struct ice_flow_prof *
4712c61054cSTony Nguyen ice_flow_find_prof_id(struct ice_hw *hw, enum ice_block blk, u64 prof_id)
4722c61054cSTony Nguyen {
4732c61054cSTony Nguyen 	struct ice_flow_prof *p;
4742c61054cSTony Nguyen 
4752c61054cSTony Nguyen 	list_for_each_entry(p, &hw->fl_profs[blk], l_entry)
4762c61054cSTony Nguyen 		if (p->id == prof_id)
4772c61054cSTony Nguyen 			return p;
4782c61054cSTony Nguyen 
4792c61054cSTony Nguyen 	return NULL;
4802c61054cSTony Nguyen }
4812c61054cSTony Nguyen 
48231ad4e4eSTony Nguyen /**
483148beb61SHenry Tieman  * ice_dealloc_flow_entry - Deallocate flow entry memory
484148beb61SHenry Tieman  * @hw: pointer to the HW struct
485148beb61SHenry Tieman  * @entry: flow entry to be removed
486148beb61SHenry Tieman  */
487148beb61SHenry Tieman static void
488148beb61SHenry Tieman ice_dealloc_flow_entry(struct ice_hw *hw, struct ice_flow_entry *entry)
489148beb61SHenry Tieman {
490148beb61SHenry Tieman 	if (!entry)
491148beb61SHenry Tieman 		return;
492148beb61SHenry Tieman 
493148beb61SHenry Tieman 	if (entry->entry)
494148beb61SHenry Tieman 		devm_kfree(ice_hw_to_dev(hw), entry->entry);
495148beb61SHenry Tieman 
496148beb61SHenry Tieman 	devm_kfree(ice_hw_to_dev(hw), entry);
497148beb61SHenry Tieman }
498148beb61SHenry Tieman 
499148beb61SHenry Tieman /**
500148beb61SHenry Tieman  * ice_flow_rem_entry_sync - Remove a flow entry
501148beb61SHenry Tieman  * @hw: pointer to the HW struct
502148beb61SHenry Tieman  * @blk: classification stage
503148beb61SHenry Tieman  * @entry: flow entry to be removed
504148beb61SHenry Tieman  */
505148beb61SHenry Tieman static enum ice_status
506148beb61SHenry Tieman ice_flow_rem_entry_sync(struct ice_hw *hw, enum ice_block __always_unused blk,
507148beb61SHenry Tieman 			struct ice_flow_entry *entry)
508148beb61SHenry Tieman {
509148beb61SHenry Tieman 	if (!entry)
510148beb61SHenry Tieman 		return ICE_ERR_BAD_PTR;
511148beb61SHenry Tieman 
512148beb61SHenry Tieman 	list_del(&entry->l_entry);
513148beb61SHenry Tieman 
514148beb61SHenry Tieman 	ice_dealloc_flow_entry(hw, entry);
515148beb61SHenry Tieman 
516148beb61SHenry Tieman 	return 0;
517148beb61SHenry Tieman }
518148beb61SHenry Tieman 
519148beb61SHenry Tieman /**
52031ad4e4eSTony Nguyen  * ice_flow_add_prof_sync - Add a flow profile for packet segments and fields
52131ad4e4eSTony Nguyen  * @hw: pointer to the HW struct
52231ad4e4eSTony Nguyen  * @blk: classification stage
52331ad4e4eSTony Nguyen  * @dir: flow direction
52431ad4e4eSTony Nguyen  * @prof_id: unique ID to identify this flow profile
52531ad4e4eSTony Nguyen  * @segs: array of one or more packet segments that describe the flow
52631ad4e4eSTony Nguyen  * @segs_cnt: number of packet segments provided
52731ad4e4eSTony Nguyen  * @prof: stores the returned flow profile added
52831ad4e4eSTony Nguyen  *
52931ad4e4eSTony Nguyen  * Assumption: the caller has acquired the lock to the profile list
53031ad4e4eSTony Nguyen  */
53131ad4e4eSTony Nguyen static enum ice_status
53231ad4e4eSTony Nguyen ice_flow_add_prof_sync(struct ice_hw *hw, enum ice_block blk,
53331ad4e4eSTony Nguyen 		       enum ice_flow_dir dir, u64 prof_id,
53431ad4e4eSTony Nguyen 		       struct ice_flow_seg_info *segs, u8 segs_cnt,
53531ad4e4eSTony Nguyen 		       struct ice_flow_prof **prof)
53631ad4e4eSTony Nguyen {
53731ad4e4eSTony Nguyen 	struct ice_flow_prof_params params;
53831ad4e4eSTony Nguyen 	enum ice_status status;
53931ad4e4eSTony Nguyen 	u8 i;
54031ad4e4eSTony Nguyen 
54131ad4e4eSTony Nguyen 	if (!prof)
54231ad4e4eSTony Nguyen 		return ICE_ERR_BAD_PTR;
54331ad4e4eSTony Nguyen 
54431ad4e4eSTony Nguyen 	memset(&params, 0, sizeof(params));
54531ad4e4eSTony Nguyen 	params.prof = devm_kzalloc(ice_hw_to_dev(hw), sizeof(*params.prof),
54631ad4e4eSTony Nguyen 				   GFP_KERNEL);
54731ad4e4eSTony Nguyen 	if (!params.prof)
54831ad4e4eSTony Nguyen 		return ICE_ERR_NO_MEMORY;
54931ad4e4eSTony Nguyen 
55031ad4e4eSTony Nguyen 	/* initialize extraction sequence to all invalid (0xff) */
55131ad4e4eSTony Nguyen 	for (i = 0; i < ICE_MAX_FV_WORDS; i++) {
55231ad4e4eSTony Nguyen 		params.es[i].prot_id = ICE_PROT_INVALID;
55331ad4e4eSTony Nguyen 		params.es[i].off = ICE_FV_OFFSET_INVAL;
55431ad4e4eSTony Nguyen 	}
55531ad4e4eSTony Nguyen 
55631ad4e4eSTony Nguyen 	params.blk = blk;
55731ad4e4eSTony Nguyen 	params.prof->id = prof_id;
55831ad4e4eSTony Nguyen 	params.prof->dir = dir;
55931ad4e4eSTony Nguyen 	params.prof->segs_cnt = segs_cnt;
56031ad4e4eSTony Nguyen 
56131ad4e4eSTony Nguyen 	/* Make a copy of the segments that need to be persistent in the flow
56231ad4e4eSTony Nguyen 	 * profile instance
56331ad4e4eSTony Nguyen 	 */
56431ad4e4eSTony Nguyen 	for (i = 0; i < segs_cnt; i++)
56531ad4e4eSTony Nguyen 		memcpy(&params.prof->segs[i], &segs[i], sizeof(*segs));
56631ad4e4eSTony Nguyen 
56731ad4e4eSTony Nguyen 	status = ice_flow_proc_segs(hw, &params);
56831ad4e4eSTony Nguyen 	if (status) {
56931ad4e4eSTony Nguyen 		ice_debug(hw, ICE_DBG_FLOW,
57031ad4e4eSTony Nguyen 			  "Error processing a flow's packet segments\n");
57131ad4e4eSTony Nguyen 		goto out;
57231ad4e4eSTony Nguyen 	}
57331ad4e4eSTony Nguyen 
57431ad4e4eSTony Nguyen 	/* Add a HW profile for this flow profile */
57531ad4e4eSTony Nguyen 	status = ice_add_prof(hw, blk, prof_id, (u8 *)params.ptypes, params.es);
57631ad4e4eSTony Nguyen 	if (status) {
57731ad4e4eSTony Nguyen 		ice_debug(hw, ICE_DBG_FLOW, "Error adding a HW flow profile\n");
57831ad4e4eSTony Nguyen 		goto out;
57931ad4e4eSTony Nguyen 	}
58031ad4e4eSTony Nguyen 
58131ad4e4eSTony Nguyen 	INIT_LIST_HEAD(&params.prof->entries);
58231ad4e4eSTony Nguyen 	mutex_init(&params.prof->entries_lock);
58331ad4e4eSTony Nguyen 	*prof = params.prof;
58431ad4e4eSTony Nguyen 
58531ad4e4eSTony Nguyen out:
58631ad4e4eSTony Nguyen 	if (status)
58731ad4e4eSTony Nguyen 		devm_kfree(ice_hw_to_dev(hw), params.prof);
58831ad4e4eSTony Nguyen 
58931ad4e4eSTony Nguyen 	return status;
59031ad4e4eSTony Nguyen }
59131ad4e4eSTony Nguyen 
59231ad4e4eSTony Nguyen /**
5932c61054cSTony Nguyen  * ice_flow_rem_prof_sync - remove a flow profile
5942c61054cSTony Nguyen  * @hw: pointer to the hardware structure
5952c61054cSTony Nguyen  * @blk: classification stage
5962c61054cSTony Nguyen  * @prof: pointer to flow profile to remove
5972c61054cSTony Nguyen  *
5982c61054cSTony Nguyen  * Assumption: the caller has acquired the lock to the profile list
5992c61054cSTony Nguyen  */
6002c61054cSTony Nguyen static enum ice_status
6012c61054cSTony Nguyen ice_flow_rem_prof_sync(struct ice_hw *hw, enum ice_block blk,
6022c61054cSTony Nguyen 		       struct ice_flow_prof *prof)
6032c61054cSTony Nguyen {
6042c61054cSTony Nguyen 	enum ice_status status;
6052c61054cSTony Nguyen 
606148beb61SHenry Tieman 	/* Remove all remaining flow entries before removing the flow profile */
607148beb61SHenry Tieman 	if (!list_empty(&prof->entries)) {
608148beb61SHenry Tieman 		struct ice_flow_entry *e, *t;
609148beb61SHenry Tieman 
610148beb61SHenry Tieman 		mutex_lock(&prof->entries_lock);
611148beb61SHenry Tieman 
612148beb61SHenry Tieman 		list_for_each_entry_safe(e, t, &prof->entries, l_entry) {
613148beb61SHenry Tieman 			status = ice_flow_rem_entry_sync(hw, blk, e);
614148beb61SHenry Tieman 			if (status)
615148beb61SHenry Tieman 				break;
616148beb61SHenry Tieman 		}
617148beb61SHenry Tieman 
618148beb61SHenry Tieman 		mutex_unlock(&prof->entries_lock);
619148beb61SHenry Tieman 	}
620148beb61SHenry Tieman 
6212c61054cSTony Nguyen 	/* Remove all hardware profiles associated with this flow profile */
6222c61054cSTony Nguyen 	status = ice_rem_prof(hw, blk, prof->id);
6232c61054cSTony Nguyen 	if (!status) {
6242c61054cSTony Nguyen 		list_del(&prof->l_entry);
6252c61054cSTony Nguyen 		mutex_destroy(&prof->entries_lock);
6262c61054cSTony Nguyen 		devm_kfree(ice_hw_to_dev(hw), prof);
6272c61054cSTony Nguyen 	}
6282c61054cSTony Nguyen 
6292c61054cSTony Nguyen 	return status;
6302c61054cSTony Nguyen }
6312c61054cSTony Nguyen 
6322c61054cSTony Nguyen /**
633451f2c44STony Nguyen  * ice_flow_assoc_prof - associate a VSI with a flow profile
634451f2c44STony Nguyen  * @hw: pointer to the hardware structure
635451f2c44STony Nguyen  * @blk: classification stage
636451f2c44STony Nguyen  * @prof: pointer to flow profile
637451f2c44STony Nguyen  * @vsi_handle: software VSI handle
638451f2c44STony Nguyen  *
639451f2c44STony Nguyen  * Assumption: the caller has acquired the lock to the profile list
640451f2c44STony Nguyen  * and the software VSI handle has been validated
641451f2c44STony Nguyen  */
642451f2c44STony Nguyen static enum ice_status
643451f2c44STony Nguyen ice_flow_assoc_prof(struct ice_hw *hw, enum ice_block blk,
644451f2c44STony Nguyen 		    struct ice_flow_prof *prof, u16 vsi_handle)
645451f2c44STony Nguyen {
646451f2c44STony Nguyen 	enum ice_status status = 0;
647451f2c44STony Nguyen 
648451f2c44STony Nguyen 	if (!test_bit(vsi_handle, prof->vsis)) {
649451f2c44STony Nguyen 		status = ice_add_prof_id_flow(hw, blk,
650451f2c44STony Nguyen 					      ice_get_hw_vsi_num(hw,
651451f2c44STony Nguyen 								 vsi_handle),
652451f2c44STony Nguyen 					      prof->id);
653451f2c44STony Nguyen 		if (!status)
654451f2c44STony Nguyen 			set_bit(vsi_handle, prof->vsis);
655451f2c44STony Nguyen 		else
656451f2c44STony Nguyen 			ice_debug(hw, ICE_DBG_FLOW,
657451f2c44STony Nguyen 				  "HW profile add failed, %d\n",
658451f2c44STony Nguyen 				  status);
659451f2c44STony Nguyen 	}
660451f2c44STony Nguyen 
661451f2c44STony Nguyen 	return status;
662451f2c44STony Nguyen }
663451f2c44STony Nguyen 
664451f2c44STony Nguyen /**
6652c61054cSTony Nguyen  * ice_flow_disassoc_prof - disassociate a VSI from a flow profile
6662c61054cSTony Nguyen  * @hw: pointer to the hardware structure
6672c61054cSTony Nguyen  * @blk: classification stage
6682c61054cSTony Nguyen  * @prof: pointer to flow profile
6692c61054cSTony Nguyen  * @vsi_handle: software VSI handle
6702c61054cSTony Nguyen  *
6712c61054cSTony Nguyen  * Assumption: the caller has acquired the lock to the profile list
6722c61054cSTony Nguyen  * and the software VSI handle has been validated
6732c61054cSTony Nguyen  */
6742c61054cSTony Nguyen static enum ice_status
6752c61054cSTony Nguyen ice_flow_disassoc_prof(struct ice_hw *hw, enum ice_block blk,
6762c61054cSTony Nguyen 		       struct ice_flow_prof *prof, u16 vsi_handle)
6772c61054cSTony Nguyen {
6782c61054cSTony Nguyen 	enum ice_status status = 0;
6792c61054cSTony Nguyen 
6802c61054cSTony Nguyen 	if (test_bit(vsi_handle, prof->vsis)) {
6812c61054cSTony Nguyen 		status = ice_rem_prof_id_flow(hw, blk,
6822c61054cSTony Nguyen 					      ice_get_hw_vsi_num(hw,
6832c61054cSTony Nguyen 								 vsi_handle),
6842c61054cSTony Nguyen 					      prof->id);
6852c61054cSTony Nguyen 		if (!status)
6862c61054cSTony Nguyen 			clear_bit(vsi_handle, prof->vsis);
6872c61054cSTony Nguyen 		else
6882c61054cSTony Nguyen 			ice_debug(hw, ICE_DBG_FLOW,
6892c61054cSTony Nguyen 				  "HW profile remove failed, %d\n",
6902c61054cSTony Nguyen 				  status);
6912c61054cSTony Nguyen 	}
6922c61054cSTony Nguyen 
6932c61054cSTony Nguyen 	return status;
6942c61054cSTony Nguyen }
6952c61054cSTony Nguyen 
6962c61054cSTony Nguyen /**
69731ad4e4eSTony Nguyen  * ice_flow_add_prof - Add a flow profile for packet segments and matched fields
69831ad4e4eSTony Nguyen  * @hw: pointer to the HW struct
69931ad4e4eSTony Nguyen  * @blk: classification stage
70031ad4e4eSTony Nguyen  * @dir: flow direction
70131ad4e4eSTony Nguyen  * @prof_id: unique ID to identify this flow profile
70231ad4e4eSTony Nguyen  * @segs: array of one or more packet segments that describe the flow
70331ad4e4eSTony Nguyen  * @segs_cnt: number of packet segments provided
704451f2c44STony Nguyen  * @prof: stores the returned flow profile added
70531ad4e4eSTony Nguyen  */
706148beb61SHenry Tieman enum ice_status
70731ad4e4eSTony Nguyen ice_flow_add_prof(struct ice_hw *hw, enum ice_block blk, enum ice_flow_dir dir,
708451f2c44STony Nguyen 		  u64 prof_id, struct ice_flow_seg_info *segs, u8 segs_cnt,
709451f2c44STony Nguyen 		  struct ice_flow_prof **prof)
71031ad4e4eSTony Nguyen {
71131ad4e4eSTony Nguyen 	enum ice_status status;
71231ad4e4eSTony Nguyen 
71331ad4e4eSTony Nguyen 	if (segs_cnt > ICE_FLOW_SEG_MAX)
71431ad4e4eSTony Nguyen 		return ICE_ERR_MAX_LIMIT;
71531ad4e4eSTony Nguyen 
71631ad4e4eSTony Nguyen 	if (!segs_cnt)
71731ad4e4eSTony Nguyen 		return ICE_ERR_PARAM;
71831ad4e4eSTony Nguyen 
71931ad4e4eSTony Nguyen 	if (!segs)
72031ad4e4eSTony Nguyen 		return ICE_ERR_BAD_PTR;
72131ad4e4eSTony Nguyen 
72231ad4e4eSTony Nguyen 	status = ice_flow_val_hdrs(segs, segs_cnt);
72331ad4e4eSTony Nguyen 	if (status)
72431ad4e4eSTony Nguyen 		return status;
72531ad4e4eSTony Nguyen 
72631ad4e4eSTony Nguyen 	mutex_lock(&hw->fl_profs_locks[blk]);
72731ad4e4eSTony Nguyen 
72831ad4e4eSTony Nguyen 	status = ice_flow_add_prof_sync(hw, blk, dir, prof_id, segs, segs_cnt,
729451f2c44STony Nguyen 					prof);
73031ad4e4eSTony Nguyen 	if (!status)
731451f2c44STony Nguyen 		list_add(&(*prof)->l_entry, &hw->fl_profs[blk]);
73231ad4e4eSTony Nguyen 
73331ad4e4eSTony Nguyen 	mutex_unlock(&hw->fl_profs_locks[blk]);
73431ad4e4eSTony Nguyen 
73531ad4e4eSTony Nguyen 	return status;
73631ad4e4eSTony Nguyen }
73731ad4e4eSTony Nguyen 
738c90ed40cSTony Nguyen /**
7392c61054cSTony Nguyen  * ice_flow_rem_prof - Remove a flow profile and all entries associated with it
7402c61054cSTony Nguyen  * @hw: pointer to the HW struct
7412c61054cSTony Nguyen  * @blk: the block for which the flow profile is to be removed
7422c61054cSTony Nguyen  * @prof_id: unique ID of the flow profile to be removed
7432c61054cSTony Nguyen  */
744148beb61SHenry Tieman enum ice_status
7452c61054cSTony Nguyen ice_flow_rem_prof(struct ice_hw *hw, enum ice_block blk, u64 prof_id)
7462c61054cSTony Nguyen {
7472c61054cSTony Nguyen 	struct ice_flow_prof *prof;
7482c61054cSTony Nguyen 	enum ice_status status;
7492c61054cSTony Nguyen 
7502c61054cSTony Nguyen 	mutex_lock(&hw->fl_profs_locks[blk]);
7512c61054cSTony Nguyen 
7522c61054cSTony Nguyen 	prof = ice_flow_find_prof_id(hw, blk, prof_id);
7532c61054cSTony Nguyen 	if (!prof) {
7542c61054cSTony Nguyen 		status = ICE_ERR_DOES_NOT_EXIST;
7552c61054cSTony Nguyen 		goto out;
7562c61054cSTony Nguyen 	}
7572c61054cSTony Nguyen 
7582c61054cSTony Nguyen 	/* prof becomes invalid after the call */
7592c61054cSTony Nguyen 	status = ice_flow_rem_prof_sync(hw, blk, prof);
7602c61054cSTony Nguyen 
7612c61054cSTony Nguyen out:
7622c61054cSTony Nguyen 	mutex_unlock(&hw->fl_profs_locks[blk]);
7632c61054cSTony Nguyen 
7642c61054cSTony Nguyen 	return status;
7652c61054cSTony Nguyen }
7662c61054cSTony Nguyen 
7672c61054cSTony Nguyen /**
768148beb61SHenry Tieman  * ice_flow_add_entry - Add a flow entry
769148beb61SHenry Tieman  * @hw: pointer to the HW struct
770148beb61SHenry Tieman  * @blk: classification stage
771148beb61SHenry Tieman  * @prof_id: ID of the profile to add a new flow entry to
772148beb61SHenry Tieman  * @entry_id: unique ID to identify this flow entry
773148beb61SHenry Tieman  * @vsi_handle: software VSI handle for the flow entry
774148beb61SHenry Tieman  * @prio: priority of the flow entry
775148beb61SHenry Tieman  * @data: pointer to a data buffer containing flow entry's match values/masks
776148beb61SHenry Tieman  * @entry_h: pointer to buffer that receives the new flow entry's handle
777148beb61SHenry Tieman  */
778148beb61SHenry Tieman enum ice_status
779148beb61SHenry Tieman ice_flow_add_entry(struct ice_hw *hw, enum ice_block blk, u64 prof_id,
780148beb61SHenry Tieman 		   u64 entry_id, u16 vsi_handle, enum ice_flow_priority prio,
781148beb61SHenry Tieman 		   void *data, u64 *entry_h)
782148beb61SHenry Tieman {
783148beb61SHenry Tieman 	struct ice_flow_entry *e = NULL;
784148beb61SHenry Tieman 	struct ice_flow_prof *prof;
785148beb61SHenry Tieman 	enum ice_status status;
786148beb61SHenry Tieman 
787148beb61SHenry Tieman 	/* No flow entry data is expected for RSS */
788148beb61SHenry Tieman 	if (!entry_h || (!data && blk != ICE_BLK_RSS))
789148beb61SHenry Tieman 		return ICE_ERR_BAD_PTR;
790148beb61SHenry Tieman 
791148beb61SHenry Tieman 	if (!ice_is_vsi_valid(hw, vsi_handle))
792148beb61SHenry Tieman 		return ICE_ERR_PARAM;
793148beb61SHenry Tieman 
794148beb61SHenry Tieman 	mutex_lock(&hw->fl_profs_locks[blk]);
795148beb61SHenry Tieman 
796148beb61SHenry Tieman 	prof = ice_flow_find_prof_id(hw, blk, prof_id);
797148beb61SHenry Tieman 	if (!prof) {
798148beb61SHenry Tieman 		status = ICE_ERR_DOES_NOT_EXIST;
799148beb61SHenry Tieman 	} else {
800148beb61SHenry Tieman 		/* Allocate memory for the entry being added and associate
801148beb61SHenry Tieman 		 * the VSI to the found flow profile
802148beb61SHenry Tieman 		 */
803148beb61SHenry Tieman 		e = devm_kzalloc(ice_hw_to_dev(hw), sizeof(*e), GFP_KERNEL);
804148beb61SHenry Tieman 		if (!e)
805148beb61SHenry Tieman 			status = ICE_ERR_NO_MEMORY;
806148beb61SHenry Tieman 		else
807148beb61SHenry Tieman 			status = ice_flow_assoc_prof(hw, blk, prof, vsi_handle);
808148beb61SHenry Tieman 	}
809148beb61SHenry Tieman 
810148beb61SHenry Tieman 	mutex_unlock(&hw->fl_profs_locks[blk]);
811148beb61SHenry Tieman 	if (status)
812148beb61SHenry Tieman 		goto out;
813148beb61SHenry Tieman 
814148beb61SHenry Tieman 	e->id = entry_id;
815148beb61SHenry Tieman 	e->vsi_handle = vsi_handle;
816148beb61SHenry Tieman 	e->prof = prof;
817148beb61SHenry Tieman 	e->priority = prio;
818148beb61SHenry Tieman 
819148beb61SHenry Tieman 	switch (blk) {
820148beb61SHenry Tieman 	case ICE_BLK_FD:
821148beb61SHenry Tieman 	case ICE_BLK_RSS:
822148beb61SHenry Tieman 		break;
823148beb61SHenry Tieman 	default:
824148beb61SHenry Tieman 		status = ICE_ERR_NOT_IMPL;
825148beb61SHenry Tieman 		goto out;
826148beb61SHenry Tieman 	}
827148beb61SHenry Tieman 
828148beb61SHenry Tieman 	mutex_lock(&prof->entries_lock);
829148beb61SHenry Tieman 	list_add(&e->l_entry, &prof->entries);
830148beb61SHenry Tieman 	mutex_unlock(&prof->entries_lock);
831148beb61SHenry Tieman 
832148beb61SHenry Tieman 	*entry_h = ICE_FLOW_ENTRY_HNDL(e);
833148beb61SHenry Tieman 
834148beb61SHenry Tieman out:
835148beb61SHenry Tieman 	if (status && e) {
836148beb61SHenry Tieman 		if (e->entry)
837148beb61SHenry Tieman 			devm_kfree(ice_hw_to_dev(hw), e->entry);
838148beb61SHenry Tieman 		devm_kfree(ice_hw_to_dev(hw), e);
839148beb61SHenry Tieman 	}
840148beb61SHenry Tieman 
841148beb61SHenry Tieman 	return status;
842148beb61SHenry Tieman }
843148beb61SHenry Tieman 
844148beb61SHenry Tieman /**
845148beb61SHenry Tieman  * ice_flow_rem_entry - Remove a flow entry
846148beb61SHenry Tieman  * @hw: pointer to the HW struct
847148beb61SHenry Tieman  * @blk: classification stage
848148beb61SHenry Tieman  * @entry_h: handle to the flow entry to be removed
849148beb61SHenry Tieman  */
850148beb61SHenry Tieman enum ice_status ice_flow_rem_entry(struct ice_hw *hw, enum ice_block blk,
851148beb61SHenry Tieman 				   u64 entry_h)
852148beb61SHenry Tieman {
853148beb61SHenry Tieman 	struct ice_flow_entry *entry;
854148beb61SHenry Tieman 	struct ice_flow_prof *prof;
855148beb61SHenry Tieman 	enum ice_status status = 0;
856148beb61SHenry Tieman 
857148beb61SHenry Tieman 	if (entry_h == ICE_FLOW_ENTRY_HANDLE_INVAL)
858148beb61SHenry Tieman 		return ICE_ERR_PARAM;
859148beb61SHenry Tieman 
860148beb61SHenry Tieman 	entry = ICE_FLOW_ENTRY_PTR(entry_h);
861148beb61SHenry Tieman 
862148beb61SHenry Tieman 	/* Retain the pointer to the flow profile as the entry will be freed */
863148beb61SHenry Tieman 	prof = entry->prof;
864148beb61SHenry Tieman 
865148beb61SHenry Tieman 	if (prof) {
866148beb61SHenry Tieman 		mutex_lock(&prof->entries_lock);
867148beb61SHenry Tieman 		status = ice_flow_rem_entry_sync(hw, blk, entry);
868148beb61SHenry Tieman 		mutex_unlock(&prof->entries_lock);
869148beb61SHenry Tieman 	}
870148beb61SHenry Tieman 
871148beb61SHenry Tieman 	return status;
872148beb61SHenry Tieman }
873148beb61SHenry Tieman 
874148beb61SHenry Tieman /**
875c90ed40cSTony Nguyen  * ice_flow_set_fld_ext - specifies locations of field from entry's input buffer
876c90ed40cSTony Nguyen  * @seg: packet segment the field being set belongs to
877c90ed40cSTony Nguyen  * @fld: field to be set
8786dae8aa0SBruce Allan  * @field_type: type of the field
879c90ed40cSTony Nguyen  * @val_loc: if not ICE_FLOW_FLD_OFF_INVAL, location of the value to match from
880c90ed40cSTony Nguyen  *           entry's input buffer
881c90ed40cSTony Nguyen  * @mask_loc: if not ICE_FLOW_FLD_OFF_INVAL, location of mask value from entry's
882c90ed40cSTony Nguyen  *            input buffer
883c90ed40cSTony Nguyen  * @last_loc: if not ICE_FLOW_FLD_OFF_INVAL, location of last/upper value from
884c90ed40cSTony Nguyen  *            entry's input buffer
885c90ed40cSTony Nguyen  *
886c90ed40cSTony Nguyen  * This helper function stores information of a field being matched, including
887c90ed40cSTony Nguyen  * the type of the field and the locations of the value to match, the mask, and
888c90ed40cSTony Nguyen  * and the upper-bound value in the start of the input buffer for a flow entry.
889c90ed40cSTony Nguyen  * This function should only be used for fixed-size data structures.
890c90ed40cSTony Nguyen  *
891c90ed40cSTony Nguyen  * This function also opportunistically determines the protocol headers to be
892c90ed40cSTony Nguyen  * present based on the fields being set. Some fields cannot be used alone to
893c90ed40cSTony Nguyen  * determine the protocol headers present. Sometimes, fields for particular
894c90ed40cSTony Nguyen  * protocol headers are not matched. In those cases, the protocol headers
895c90ed40cSTony Nguyen  * must be explicitly set.
896c90ed40cSTony Nguyen  */
897c90ed40cSTony Nguyen static void
898c90ed40cSTony Nguyen ice_flow_set_fld_ext(struct ice_flow_seg_info *seg, enum ice_flow_field fld,
8996dae8aa0SBruce Allan 		     enum ice_flow_fld_match_type field_type, u16 val_loc,
900c90ed40cSTony Nguyen 		     u16 mask_loc, u16 last_loc)
901c90ed40cSTony Nguyen {
902c90ed40cSTony Nguyen 	u64 bit = BIT_ULL(fld);
903c90ed40cSTony Nguyen 
904c90ed40cSTony Nguyen 	seg->match |= bit;
9056dae8aa0SBruce Allan 	if (field_type == ICE_FLOW_FLD_TYPE_RANGE)
906c90ed40cSTony Nguyen 		seg->range |= bit;
907c90ed40cSTony Nguyen 
9086dae8aa0SBruce Allan 	seg->fields[fld].type = field_type;
909c90ed40cSTony Nguyen 	seg->fields[fld].src.val = val_loc;
910c90ed40cSTony Nguyen 	seg->fields[fld].src.mask = mask_loc;
911c90ed40cSTony Nguyen 	seg->fields[fld].src.last = last_loc;
912c90ed40cSTony Nguyen 
913c90ed40cSTony Nguyen 	ICE_FLOW_SET_HDRS(seg, ice_flds_info[fld].hdr);
914c90ed40cSTony Nguyen }
915c90ed40cSTony Nguyen 
916c90ed40cSTony Nguyen /**
917c90ed40cSTony Nguyen  * ice_flow_set_fld - specifies locations of field from entry's input buffer
918c90ed40cSTony Nguyen  * @seg: packet segment the field being set belongs to
919c90ed40cSTony Nguyen  * @fld: field to be set
920c90ed40cSTony Nguyen  * @val_loc: if not ICE_FLOW_FLD_OFF_INVAL, location of the value to match from
921c90ed40cSTony Nguyen  *           entry's input buffer
922c90ed40cSTony Nguyen  * @mask_loc: if not ICE_FLOW_FLD_OFF_INVAL, location of mask value from entry's
923c90ed40cSTony Nguyen  *            input buffer
924c90ed40cSTony Nguyen  * @last_loc: if not ICE_FLOW_FLD_OFF_INVAL, location of last/upper value from
925c90ed40cSTony Nguyen  *            entry's input buffer
926c90ed40cSTony Nguyen  * @range: indicate if field being matched is to be in a range
927c90ed40cSTony Nguyen  *
928c90ed40cSTony Nguyen  * This function specifies the locations, in the form of byte offsets from the
929c90ed40cSTony Nguyen  * start of the input buffer for a flow entry, from where the value to match,
930c90ed40cSTony Nguyen  * the mask value, and upper value can be extracted. These locations are then
931c90ed40cSTony Nguyen  * stored in the flow profile. When adding a flow entry associated with the
932c90ed40cSTony Nguyen  * flow profile, these locations will be used to quickly extract the values and
933c90ed40cSTony Nguyen  * create the content of a match entry. This function should only be used for
934c90ed40cSTony Nguyen  * fixed-size data structures.
935c90ed40cSTony Nguyen  */
936148beb61SHenry Tieman void
937c90ed40cSTony Nguyen ice_flow_set_fld(struct ice_flow_seg_info *seg, enum ice_flow_field fld,
938c90ed40cSTony Nguyen 		 u16 val_loc, u16 mask_loc, u16 last_loc, bool range)
939c90ed40cSTony Nguyen {
940c90ed40cSTony Nguyen 	enum ice_flow_fld_match_type t = range ?
941c90ed40cSTony Nguyen 		ICE_FLOW_FLD_TYPE_RANGE : ICE_FLOW_FLD_TYPE_REG;
942c90ed40cSTony Nguyen 
943c90ed40cSTony Nguyen 	ice_flow_set_fld_ext(seg, fld, t, val_loc, mask_loc, last_loc);
944c90ed40cSTony Nguyen }
945c90ed40cSTony Nguyen 
946c90ed40cSTony Nguyen #define ICE_FLOW_RSS_SEG_HDR_L3_MASKS \
947c90ed40cSTony Nguyen 	(ICE_FLOW_SEG_HDR_IPV4 | ICE_FLOW_SEG_HDR_IPV6)
948c90ed40cSTony Nguyen 
949c90ed40cSTony Nguyen #define ICE_FLOW_RSS_SEG_HDR_L4_MASKS \
950c90ed40cSTony Nguyen 	(ICE_FLOW_SEG_HDR_TCP | ICE_FLOW_SEG_HDR_UDP | ICE_FLOW_SEG_HDR_SCTP)
951c90ed40cSTony Nguyen 
952c90ed40cSTony Nguyen #define ICE_FLOW_RSS_SEG_HDR_VAL_MASKS \
953c90ed40cSTony Nguyen 	(ICE_FLOW_RSS_SEG_HDR_L3_MASKS | \
954c90ed40cSTony Nguyen 	 ICE_FLOW_RSS_SEG_HDR_L4_MASKS)
955c90ed40cSTony Nguyen 
956c90ed40cSTony Nguyen /**
957c90ed40cSTony Nguyen  * ice_flow_set_rss_seg_info - setup packet segments for RSS
958c90ed40cSTony Nguyen  * @segs: pointer to the flow field segment(s)
959c90ed40cSTony Nguyen  * @hash_fields: fields to be hashed on for the segment(s)
960c90ed40cSTony Nguyen  * @flow_hdr: protocol header fields within a packet segment
961c90ed40cSTony Nguyen  *
962c90ed40cSTony Nguyen  * Helper function to extract fields from hash bitmap and use flow
963c90ed40cSTony Nguyen  * header value to set flow field segment for further use in flow
964c90ed40cSTony Nguyen  * profile entry or removal.
965c90ed40cSTony Nguyen  */
966c90ed40cSTony Nguyen static enum ice_status
967c90ed40cSTony Nguyen ice_flow_set_rss_seg_info(struct ice_flow_seg_info *segs, u64 hash_fields,
968c90ed40cSTony Nguyen 			  u32 flow_hdr)
969c90ed40cSTony Nguyen {
970c90ed40cSTony Nguyen 	u64 val;
971c90ed40cSTony Nguyen 	u8 i;
972c90ed40cSTony Nguyen 
973c90ed40cSTony Nguyen 	for_each_set_bit(i, (unsigned long *)&hash_fields,
974c90ed40cSTony Nguyen 			 ICE_FLOW_FIELD_IDX_MAX)
975c90ed40cSTony Nguyen 		ice_flow_set_fld(segs, (enum ice_flow_field)i,
976c90ed40cSTony Nguyen 				 ICE_FLOW_FLD_OFF_INVAL, ICE_FLOW_FLD_OFF_INVAL,
977c90ed40cSTony Nguyen 				 ICE_FLOW_FLD_OFF_INVAL, false);
978c90ed40cSTony Nguyen 
979c90ed40cSTony Nguyen 	ICE_FLOW_SET_HDRS(segs, flow_hdr);
980c90ed40cSTony Nguyen 
981c90ed40cSTony Nguyen 	if (segs->hdrs & ~ICE_FLOW_RSS_SEG_HDR_VAL_MASKS)
982c90ed40cSTony Nguyen 		return ICE_ERR_PARAM;
983c90ed40cSTony Nguyen 
984c90ed40cSTony Nguyen 	val = (u64)(segs->hdrs & ICE_FLOW_RSS_SEG_HDR_L3_MASKS);
985c90ed40cSTony Nguyen 	if (val && !is_power_of_2(val))
986c90ed40cSTony Nguyen 		return ICE_ERR_CFG;
987c90ed40cSTony Nguyen 
988c90ed40cSTony Nguyen 	val = (u64)(segs->hdrs & ICE_FLOW_RSS_SEG_HDR_L4_MASKS);
989c90ed40cSTony Nguyen 	if (val && !is_power_of_2(val))
990c90ed40cSTony Nguyen 		return ICE_ERR_CFG;
991c90ed40cSTony Nguyen 
992c90ed40cSTony Nguyen 	return 0;
993c90ed40cSTony Nguyen }
994c90ed40cSTony Nguyen 
9952c61054cSTony Nguyen /**
9962c61054cSTony Nguyen  * ice_rem_vsi_rss_list - remove VSI from RSS list
9972c61054cSTony Nguyen  * @hw: pointer to the hardware structure
9982c61054cSTony Nguyen  * @vsi_handle: software VSI handle
9992c61054cSTony Nguyen  *
10002c61054cSTony Nguyen  * Remove the VSI from all RSS configurations in the list.
10012c61054cSTony Nguyen  */
10022c61054cSTony Nguyen void ice_rem_vsi_rss_list(struct ice_hw *hw, u16 vsi_handle)
10032c61054cSTony Nguyen {
10042c61054cSTony Nguyen 	struct ice_rss_cfg *r, *tmp;
10052c61054cSTony Nguyen 
10062c61054cSTony Nguyen 	if (list_empty(&hw->rss_list_head))
10072c61054cSTony Nguyen 		return;
10082c61054cSTony Nguyen 
10092c61054cSTony Nguyen 	mutex_lock(&hw->rss_locks);
10102c61054cSTony Nguyen 	list_for_each_entry_safe(r, tmp, &hw->rss_list_head, l_entry)
10112c61054cSTony Nguyen 		if (test_and_clear_bit(vsi_handle, r->vsis))
10122c61054cSTony Nguyen 			if (bitmap_empty(r->vsis, ICE_MAX_VSI)) {
10132c61054cSTony Nguyen 				list_del(&r->l_entry);
10142c61054cSTony Nguyen 				devm_kfree(ice_hw_to_dev(hw), r);
10152c61054cSTony Nguyen 			}
10162c61054cSTony Nguyen 	mutex_unlock(&hw->rss_locks);
10172c61054cSTony Nguyen }
10182c61054cSTony Nguyen 
10192c61054cSTony Nguyen /**
10202c61054cSTony Nguyen  * ice_rem_vsi_rss_cfg - remove RSS configurations associated with VSI
10212c61054cSTony Nguyen  * @hw: pointer to the hardware structure
10222c61054cSTony Nguyen  * @vsi_handle: software VSI handle
10232c61054cSTony Nguyen  *
10242c61054cSTony Nguyen  * This function will iterate through all flow profiles and disassociate
10252c61054cSTony Nguyen  * the VSI from that profile. If the flow profile has no VSIs it will
10262c61054cSTony Nguyen  * be removed.
10272c61054cSTony Nguyen  */
10282c61054cSTony Nguyen enum ice_status ice_rem_vsi_rss_cfg(struct ice_hw *hw, u16 vsi_handle)
10292c61054cSTony Nguyen {
10302c61054cSTony Nguyen 	const enum ice_block blk = ICE_BLK_RSS;
10312c61054cSTony Nguyen 	struct ice_flow_prof *p, *t;
10322c61054cSTony Nguyen 	enum ice_status status = 0;
10332c61054cSTony Nguyen 
10342c61054cSTony Nguyen 	if (!ice_is_vsi_valid(hw, vsi_handle))
10352c61054cSTony Nguyen 		return ICE_ERR_PARAM;
10362c61054cSTony Nguyen 
10372c61054cSTony Nguyen 	if (list_empty(&hw->fl_profs[blk]))
10382c61054cSTony Nguyen 		return 0;
10392c61054cSTony Nguyen 
10402c61054cSTony Nguyen 	mutex_lock(&hw->fl_profs_locks[blk]);
10412c61054cSTony Nguyen 	list_for_each_entry_safe(p, t, &hw->fl_profs[blk], l_entry)
10422c61054cSTony Nguyen 		if (test_bit(vsi_handle, p->vsis)) {
10432c61054cSTony Nguyen 			status = ice_flow_disassoc_prof(hw, blk, p, vsi_handle);
10442c61054cSTony Nguyen 			if (status)
10452c61054cSTony Nguyen 				break;
10462c61054cSTony Nguyen 
10472c61054cSTony Nguyen 			if (bitmap_empty(p->vsis, ICE_MAX_VSI)) {
10482c61054cSTony Nguyen 				status = ice_flow_rem_prof_sync(hw, blk, p);
10492c61054cSTony Nguyen 				if (status)
10502c61054cSTony Nguyen 					break;
10512c61054cSTony Nguyen 			}
10522c61054cSTony Nguyen 		}
10532c61054cSTony Nguyen 	mutex_unlock(&hw->fl_profs_locks[blk]);
10542c61054cSTony Nguyen 
10552c61054cSTony Nguyen 	return status;
10562c61054cSTony Nguyen }
10572c61054cSTony Nguyen 
10582c61054cSTony Nguyen /**
10592c61054cSTony Nguyen  * ice_rem_rss_list - remove RSS configuration from list
10602c61054cSTony Nguyen  * @hw: pointer to the hardware structure
10612c61054cSTony Nguyen  * @vsi_handle: software VSI handle
10622c61054cSTony Nguyen  * @prof: pointer to flow profile
10632c61054cSTony Nguyen  *
10642c61054cSTony Nguyen  * Assumption: lock has already been acquired for RSS list
10652c61054cSTony Nguyen  */
10662c61054cSTony Nguyen static void
10672c61054cSTony Nguyen ice_rem_rss_list(struct ice_hw *hw, u16 vsi_handle, struct ice_flow_prof *prof)
10682c61054cSTony Nguyen {
10692c61054cSTony Nguyen 	struct ice_rss_cfg *r, *tmp;
10702c61054cSTony Nguyen 
10712c61054cSTony Nguyen 	/* Search for RSS hash fields associated to the VSI that match the
10722c61054cSTony Nguyen 	 * hash configurations associated to the flow profile. If found
10732c61054cSTony Nguyen 	 * remove from the RSS entry list of the VSI context and delete entry.
10742c61054cSTony Nguyen 	 */
10752c61054cSTony Nguyen 	list_for_each_entry_safe(r, tmp, &hw->rss_list_head, l_entry)
10762c61054cSTony Nguyen 		if (r->hashed_flds == prof->segs[prof->segs_cnt - 1].match &&
10772c61054cSTony Nguyen 		    r->packet_hdr == prof->segs[prof->segs_cnt - 1].hdrs) {
10782c61054cSTony Nguyen 			clear_bit(vsi_handle, r->vsis);
10792c61054cSTony Nguyen 			if (bitmap_empty(r->vsis, ICE_MAX_VSI)) {
10802c61054cSTony Nguyen 				list_del(&r->l_entry);
10812c61054cSTony Nguyen 				devm_kfree(ice_hw_to_dev(hw), r);
10822c61054cSTony Nguyen 			}
10832c61054cSTony Nguyen 			return;
10842c61054cSTony Nguyen 		}
10852c61054cSTony Nguyen }
10862c61054cSTony Nguyen 
10872c61054cSTony Nguyen /**
10882c61054cSTony Nguyen  * ice_add_rss_list - add RSS configuration to list
10892c61054cSTony Nguyen  * @hw: pointer to the hardware structure
10902c61054cSTony Nguyen  * @vsi_handle: software VSI handle
10912c61054cSTony Nguyen  * @prof: pointer to flow profile
10922c61054cSTony Nguyen  *
10932c61054cSTony Nguyen  * Assumption: lock has already been acquired for RSS list
10942c61054cSTony Nguyen  */
10952c61054cSTony Nguyen static enum ice_status
10962c61054cSTony Nguyen ice_add_rss_list(struct ice_hw *hw, u16 vsi_handle, struct ice_flow_prof *prof)
10972c61054cSTony Nguyen {
10982c61054cSTony Nguyen 	struct ice_rss_cfg *r, *rss_cfg;
10992c61054cSTony Nguyen 
11002c61054cSTony Nguyen 	list_for_each_entry(r, &hw->rss_list_head, l_entry)
11012c61054cSTony Nguyen 		if (r->hashed_flds == prof->segs[prof->segs_cnt - 1].match &&
11022c61054cSTony Nguyen 		    r->packet_hdr == prof->segs[prof->segs_cnt - 1].hdrs) {
11032c61054cSTony Nguyen 			set_bit(vsi_handle, r->vsis);
11042c61054cSTony Nguyen 			return 0;
11052c61054cSTony Nguyen 		}
11062c61054cSTony Nguyen 
11072c61054cSTony Nguyen 	rss_cfg = devm_kzalloc(ice_hw_to_dev(hw), sizeof(*rss_cfg),
11082c61054cSTony Nguyen 			       GFP_KERNEL);
11092c61054cSTony Nguyen 	if (!rss_cfg)
11102c61054cSTony Nguyen 		return ICE_ERR_NO_MEMORY;
11112c61054cSTony Nguyen 
11122c61054cSTony Nguyen 	rss_cfg->hashed_flds = prof->segs[prof->segs_cnt - 1].match;
11132c61054cSTony Nguyen 	rss_cfg->packet_hdr = prof->segs[prof->segs_cnt - 1].hdrs;
11142c61054cSTony Nguyen 	set_bit(vsi_handle, rss_cfg->vsis);
11152c61054cSTony Nguyen 
11162c61054cSTony Nguyen 	list_add_tail(&rss_cfg->l_entry, &hw->rss_list_head);
11172c61054cSTony Nguyen 
11182c61054cSTony Nguyen 	return 0;
11192c61054cSTony Nguyen }
11202c61054cSTony Nguyen 
112131ad4e4eSTony Nguyen #define ICE_FLOW_PROF_HASH_S	0
112231ad4e4eSTony Nguyen #define ICE_FLOW_PROF_HASH_M	(0xFFFFFFFFULL << ICE_FLOW_PROF_HASH_S)
112331ad4e4eSTony Nguyen #define ICE_FLOW_PROF_HDR_S	32
112431ad4e4eSTony Nguyen #define ICE_FLOW_PROF_HDR_M	(0x3FFFFFFFULL << ICE_FLOW_PROF_HDR_S)
112531ad4e4eSTony Nguyen #define ICE_FLOW_PROF_ENCAP_S	63
112631ad4e4eSTony Nguyen #define ICE_FLOW_PROF_ENCAP_M	(BIT_ULL(ICE_FLOW_PROF_ENCAP_S))
112731ad4e4eSTony Nguyen 
1128c90ed40cSTony Nguyen #define ICE_RSS_OUTER_HEADERS	1
1129a4e82a81STony Nguyen #define ICE_RSS_INNER_HEADERS	2
1130c90ed40cSTony Nguyen 
113131ad4e4eSTony Nguyen /* Flow profile ID format:
113231ad4e4eSTony Nguyen  * [0:31] - Packet match fields
113331ad4e4eSTony Nguyen  * [32:62] - Protocol header
113431ad4e4eSTony Nguyen  * [63] - Encapsulation flag, 0 if non-tunneled, 1 if tunneled
113531ad4e4eSTony Nguyen  */
113631ad4e4eSTony Nguyen #define ICE_FLOW_GEN_PROFID(hash, hdr, segs_cnt) \
113731ad4e4eSTony Nguyen 	(u64)(((u64)(hash) & ICE_FLOW_PROF_HASH_M) | \
113831ad4e4eSTony Nguyen 	      (((u64)(hdr) << ICE_FLOW_PROF_HDR_S) & ICE_FLOW_PROF_HDR_M) | \
113931ad4e4eSTony Nguyen 	      ((u8)((segs_cnt) - 1) ? ICE_FLOW_PROF_ENCAP_M : 0))
114031ad4e4eSTony Nguyen 
1141c90ed40cSTony Nguyen /**
1142c90ed40cSTony Nguyen  * ice_add_rss_cfg_sync - add an RSS configuration
114331ad4e4eSTony Nguyen  * @hw: pointer to the hardware structure
1144451f2c44STony Nguyen  * @vsi_handle: software VSI handle
1145c90ed40cSTony Nguyen  * @hashed_flds: hash bit fields (ICE_FLOW_HASH_*) to configure
1146c90ed40cSTony Nguyen  * @addl_hdrs: protocol header fields
1147c90ed40cSTony Nguyen  * @segs_cnt: packet segment count
1148c90ed40cSTony Nguyen  *
1149c90ed40cSTony Nguyen  * Assumption: lock has already been acquired for RSS list
1150c90ed40cSTony Nguyen  */
1151c90ed40cSTony Nguyen static enum ice_status
1152451f2c44STony Nguyen ice_add_rss_cfg_sync(struct ice_hw *hw, u16 vsi_handle, u64 hashed_flds,
1153451f2c44STony Nguyen 		     u32 addl_hdrs, u8 segs_cnt)
1154c90ed40cSTony Nguyen {
1155451f2c44STony Nguyen 	const enum ice_block blk = ICE_BLK_RSS;
1156451f2c44STony Nguyen 	struct ice_flow_prof *prof = NULL;
1157c90ed40cSTony Nguyen 	struct ice_flow_seg_info *segs;
1158c90ed40cSTony Nguyen 	enum ice_status status;
1159c90ed40cSTony Nguyen 
1160c90ed40cSTony Nguyen 	if (!segs_cnt || segs_cnt > ICE_FLOW_SEG_MAX)
1161c90ed40cSTony Nguyen 		return ICE_ERR_PARAM;
1162c90ed40cSTony Nguyen 
1163c90ed40cSTony Nguyen 	segs = kcalloc(segs_cnt, sizeof(*segs), GFP_KERNEL);
1164c90ed40cSTony Nguyen 	if (!segs)
1165c90ed40cSTony Nguyen 		return ICE_ERR_NO_MEMORY;
1166c90ed40cSTony Nguyen 
1167c90ed40cSTony Nguyen 	/* Construct the packet segment info from the hashed fields */
1168c90ed40cSTony Nguyen 	status = ice_flow_set_rss_seg_info(&segs[segs_cnt - 1], hashed_flds,
1169c90ed40cSTony Nguyen 					   addl_hdrs);
117031ad4e4eSTony Nguyen 	if (status)
117131ad4e4eSTony Nguyen 		goto exit;
1172c90ed40cSTony Nguyen 
11732c61054cSTony Nguyen 	/* Search for a flow profile that has matching headers, hash fields
11742c61054cSTony Nguyen 	 * and has the input VSI associated to it. If found, no further
11752c61054cSTony Nguyen 	 * operations required and exit.
11762c61054cSTony Nguyen 	 */
11772c61054cSTony Nguyen 	prof = ice_flow_find_prof_conds(hw, blk, ICE_FLOW_RX, segs, segs_cnt,
11782c61054cSTony Nguyen 					vsi_handle,
11792c61054cSTony Nguyen 					ICE_FLOW_FIND_PROF_CHK_FLDS |
11802c61054cSTony Nguyen 					ICE_FLOW_FIND_PROF_CHK_VSI);
11812c61054cSTony Nguyen 	if (prof)
11822c61054cSTony Nguyen 		goto exit;
11832c61054cSTony Nguyen 
11842c61054cSTony Nguyen 	/* Check if a flow profile exists with the same protocol headers and
11852c61054cSTony Nguyen 	 * associated with the input VSI. If so disassociate the VSI from
11862c61054cSTony Nguyen 	 * this profile. The VSI will be added to a new profile created with
11872c61054cSTony Nguyen 	 * the protocol header and new hash field configuration.
11882c61054cSTony Nguyen 	 */
11892c61054cSTony Nguyen 	prof = ice_flow_find_prof_conds(hw, blk, ICE_FLOW_RX, segs, segs_cnt,
11902c61054cSTony Nguyen 					vsi_handle, ICE_FLOW_FIND_PROF_CHK_VSI);
11912c61054cSTony Nguyen 	if (prof) {
11922c61054cSTony Nguyen 		status = ice_flow_disassoc_prof(hw, blk, prof, vsi_handle);
11932c61054cSTony Nguyen 		if (!status)
11942c61054cSTony Nguyen 			ice_rem_rss_list(hw, vsi_handle, prof);
11952c61054cSTony Nguyen 		else
11962c61054cSTony Nguyen 			goto exit;
11972c61054cSTony Nguyen 
11982c61054cSTony Nguyen 		/* Remove profile if it has no VSIs associated */
11992c61054cSTony Nguyen 		if (bitmap_empty(prof->vsis, ICE_MAX_VSI)) {
12002c61054cSTony Nguyen 			status = ice_flow_rem_prof(hw, blk, prof->id);
12012c61054cSTony Nguyen 			if (status)
12022c61054cSTony Nguyen 				goto exit;
12032c61054cSTony Nguyen 		}
12042c61054cSTony Nguyen 	}
12052c61054cSTony Nguyen 
12062c61054cSTony Nguyen 	/* Search for a profile that has same match fields only. If this
12072c61054cSTony Nguyen 	 * exists then associate the VSI to this profile.
12082c61054cSTony Nguyen 	 */
12092c61054cSTony Nguyen 	prof = ice_flow_find_prof_conds(hw, blk, ICE_FLOW_RX, segs, segs_cnt,
12102c61054cSTony Nguyen 					vsi_handle,
12112c61054cSTony Nguyen 					ICE_FLOW_FIND_PROF_CHK_FLDS);
12122c61054cSTony Nguyen 	if (prof) {
12132c61054cSTony Nguyen 		status = ice_flow_assoc_prof(hw, blk, prof, vsi_handle);
12142c61054cSTony Nguyen 		if (!status)
12152c61054cSTony Nguyen 			status = ice_add_rss_list(hw, vsi_handle, prof);
12162c61054cSTony Nguyen 		goto exit;
12172c61054cSTony Nguyen 	}
12182c61054cSTony Nguyen 
121931ad4e4eSTony Nguyen 	/* Create a new flow profile with generated profile and packet
122031ad4e4eSTony Nguyen 	 * segment information.
122131ad4e4eSTony Nguyen 	 */
1222451f2c44STony Nguyen 	status = ice_flow_add_prof(hw, blk, ICE_FLOW_RX,
122331ad4e4eSTony Nguyen 				   ICE_FLOW_GEN_PROFID(hashed_flds,
122431ad4e4eSTony Nguyen 						       segs[segs_cnt - 1].hdrs,
122531ad4e4eSTony Nguyen 						       segs_cnt),
1226451f2c44STony Nguyen 				   segs, segs_cnt, &prof);
1227451f2c44STony Nguyen 	if (status)
1228451f2c44STony Nguyen 		goto exit;
1229451f2c44STony Nguyen 
1230451f2c44STony Nguyen 	status = ice_flow_assoc_prof(hw, blk, prof, vsi_handle);
12312c61054cSTony Nguyen 	/* If association to a new flow profile failed then this profile can
12322c61054cSTony Nguyen 	 * be removed.
12332c61054cSTony Nguyen 	 */
12342c61054cSTony Nguyen 	if (status) {
12352c61054cSTony Nguyen 		ice_flow_rem_prof(hw, blk, prof->id);
12362c61054cSTony Nguyen 		goto exit;
12372c61054cSTony Nguyen 	}
12382c61054cSTony Nguyen 
12392c61054cSTony Nguyen 	status = ice_add_rss_list(hw, vsi_handle, prof);
124031ad4e4eSTony Nguyen 
124131ad4e4eSTony Nguyen exit:
1242c90ed40cSTony Nguyen 	kfree(segs);
1243c90ed40cSTony Nguyen 	return status;
1244c90ed40cSTony Nguyen }
1245c90ed40cSTony Nguyen 
1246c90ed40cSTony Nguyen /**
1247c90ed40cSTony Nguyen  * ice_add_rss_cfg - add an RSS configuration with specified hashed fields
1248c90ed40cSTony Nguyen  * @hw: pointer to the hardware structure
1249c90ed40cSTony Nguyen  * @vsi_handle: software VSI handle
1250c90ed40cSTony Nguyen  * @hashed_flds: hash bit fields (ICE_FLOW_HASH_*) to configure
1251c90ed40cSTony Nguyen  * @addl_hdrs: protocol header fields
1252c90ed40cSTony Nguyen  *
1253c90ed40cSTony Nguyen  * This function will generate a flow profile based on fields associated with
1254c90ed40cSTony Nguyen  * the input fields to hash on, the flow type and use the VSI number to add
1255c90ed40cSTony Nguyen  * a flow entry to the profile.
1256c90ed40cSTony Nguyen  */
1257c90ed40cSTony Nguyen enum ice_status
1258c90ed40cSTony Nguyen ice_add_rss_cfg(struct ice_hw *hw, u16 vsi_handle, u64 hashed_flds,
1259c90ed40cSTony Nguyen 		u32 addl_hdrs)
1260c90ed40cSTony Nguyen {
1261c90ed40cSTony Nguyen 	enum ice_status status;
1262c90ed40cSTony Nguyen 
1263c90ed40cSTony Nguyen 	if (hashed_flds == ICE_HASH_INVALID ||
1264c90ed40cSTony Nguyen 	    !ice_is_vsi_valid(hw, vsi_handle))
1265c90ed40cSTony Nguyen 		return ICE_ERR_PARAM;
1266c90ed40cSTony Nguyen 
1267c90ed40cSTony Nguyen 	mutex_lock(&hw->rss_locks);
1268451f2c44STony Nguyen 	status = ice_add_rss_cfg_sync(hw, vsi_handle, hashed_flds, addl_hdrs,
1269c90ed40cSTony Nguyen 				      ICE_RSS_OUTER_HEADERS);
1270a4e82a81STony Nguyen 	if (!status)
1271a4e82a81STony Nguyen 		status = ice_add_rss_cfg_sync(hw, vsi_handle, hashed_flds,
1272a4e82a81STony Nguyen 					      addl_hdrs, ICE_RSS_INNER_HEADERS);
1273c90ed40cSTony Nguyen 	mutex_unlock(&hw->rss_locks);
1274c90ed40cSTony Nguyen 
1275c90ed40cSTony Nguyen 	return status;
1276c90ed40cSTony Nguyen }
1277c90ed40cSTony Nguyen 
12781c01c8c6SMd Fahad Iqbal Polash /* Mapping of AVF hash bit fields to an L3-L4 hash combination.
12791c01c8c6SMd Fahad Iqbal Polash  * As the ice_flow_avf_hdr_field represent individual bit shifts in a hash,
12801c01c8c6SMd Fahad Iqbal Polash  * convert its values to their appropriate flow L3, L4 values.
12811c01c8c6SMd Fahad Iqbal Polash  */
12821c01c8c6SMd Fahad Iqbal Polash #define ICE_FLOW_AVF_RSS_IPV4_MASKS \
12831c01c8c6SMd Fahad Iqbal Polash 	(BIT_ULL(ICE_AVF_FLOW_FIELD_IPV4_OTHER) | \
12841c01c8c6SMd Fahad Iqbal Polash 	 BIT_ULL(ICE_AVF_FLOW_FIELD_FRAG_IPV4))
12851c01c8c6SMd Fahad Iqbal Polash #define ICE_FLOW_AVF_RSS_TCP_IPV4_MASKS \
12861c01c8c6SMd Fahad Iqbal Polash 	(BIT_ULL(ICE_AVF_FLOW_FIELD_IPV4_TCP_SYN_NO_ACK) | \
12871c01c8c6SMd Fahad Iqbal Polash 	 BIT_ULL(ICE_AVF_FLOW_FIELD_IPV4_TCP))
12881c01c8c6SMd Fahad Iqbal Polash #define ICE_FLOW_AVF_RSS_UDP_IPV4_MASKS \
12891c01c8c6SMd Fahad Iqbal Polash 	(BIT_ULL(ICE_AVF_FLOW_FIELD_UNICAST_IPV4_UDP) | \
12901c01c8c6SMd Fahad Iqbal Polash 	 BIT_ULL(ICE_AVF_FLOW_FIELD_MULTICAST_IPV4_UDP) | \
12911c01c8c6SMd Fahad Iqbal Polash 	 BIT_ULL(ICE_AVF_FLOW_FIELD_IPV4_UDP))
12921c01c8c6SMd Fahad Iqbal Polash #define ICE_FLOW_AVF_RSS_ALL_IPV4_MASKS \
12931c01c8c6SMd Fahad Iqbal Polash 	(ICE_FLOW_AVF_RSS_TCP_IPV4_MASKS | ICE_FLOW_AVF_RSS_UDP_IPV4_MASKS | \
12941c01c8c6SMd Fahad Iqbal Polash 	 ICE_FLOW_AVF_RSS_IPV4_MASKS | BIT_ULL(ICE_AVF_FLOW_FIELD_IPV4_SCTP))
12951c01c8c6SMd Fahad Iqbal Polash 
12961c01c8c6SMd Fahad Iqbal Polash #define ICE_FLOW_AVF_RSS_IPV6_MASKS \
12971c01c8c6SMd Fahad Iqbal Polash 	(BIT_ULL(ICE_AVF_FLOW_FIELD_IPV6_OTHER) | \
12981c01c8c6SMd Fahad Iqbal Polash 	 BIT_ULL(ICE_AVF_FLOW_FIELD_FRAG_IPV6))
12991c01c8c6SMd Fahad Iqbal Polash #define ICE_FLOW_AVF_RSS_UDP_IPV6_MASKS \
13001c01c8c6SMd Fahad Iqbal Polash 	(BIT_ULL(ICE_AVF_FLOW_FIELD_UNICAST_IPV6_UDP) | \
13011c01c8c6SMd Fahad Iqbal Polash 	 BIT_ULL(ICE_AVF_FLOW_FIELD_MULTICAST_IPV6_UDP) | \
13021c01c8c6SMd Fahad Iqbal Polash 	 BIT_ULL(ICE_AVF_FLOW_FIELD_IPV6_UDP))
13031c01c8c6SMd Fahad Iqbal Polash #define ICE_FLOW_AVF_RSS_TCP_IPV6_MASKS \
13041c01c8c6SMd Fahad Iqbal Polash 	(BIT_ULL(ICE_AVF_FLOW_FIELD_IPV6_TCP_SYN_NO_ACK) | \
13051c01c8c6SMd Fahad Iqbal Polash 	 BIT_ULL(ICE_AVF_FLOW_FIELD_IPV6_TCP))
13061c01c8c6SMd Fahad Iqbal Polash #define ICE_FLOW_AVF_RSS_ALL_IPV6_MASKS \
13071c01c8c6SMd Fahad Iqbal Polash 	(ICE_FLOW_AVF_RSS_TCP_IPV6_MASKS | ICE_FLOW_AVF_RSS_UDP_IPV6_MASKS | \
13081c01c8c6SMd Fahad Iqbal Polash 	 ICE_FLOW_AVF_RSS_IPV6_MASKS | BIT_ULL(ICE_AVF_FLOW_FIELD_IPV6_SCTP))
13091c01c8c6SMd Fahad Iqbal Polash 
13101c01c8c6SMd Fahad Iqbal Polash /**
13111c01c8c6SMd Fahad Iqbal Polash  * ice_add_avf_rss_cfg - add an RSS configuration for AVF driver
13121c01c8c6SMd Fahad Iqbal Polash  * @hw: pointer to the hardware structure
13131c01c8c6SMd Fahad Iqbal Polash  * @vsi_handle: software VSI handle
13141c01c8c6SMd Fahad Iqbal Polash  * @avf_hash: hash bit fields (ICE_AVF_FLOW_FIELD_*) to configure
13151c01c8c6SMd Fahad Iqbal Polash  *
13161c01c8c6SMd Fahad Iqbal Polash  * This function will take the hash bitmap provided by the AVF driver via a
13171c01c8c6SMd Fahad Iqbal Polash  * message, convert it to ICE-compatible values, and configure RSS flow
13181c01c8c6SMd Fahad Iqbal Polash  * profiles.
13191c01c8c6SMd Fahad Iqbal Polash  */
13201c01c8c6SMd Fahad Iqbal Polash enum ice_status
13211c01c8c6SMd Fahad Iqbal Polash ice_add_avf_rss_cfg(struct ice_hw *hw, u16 vsi_handle, u64 avf_hash)
13221c01c8c6SMd Fahad Iqbal Polash {
13231c01c8c6SMd Fahad Iqbal Polash 	enum ice_status status = 0;
13241c01c8c6SMd Fahad Iqbal Polash 	u64 hash_flds;
13251c01c8c6SMd Fahad Iqbal Polash 
13261c01c8c6SMd Fahad Iqbal Polash 	if (avf_hash == ICE_AVF_FLOW_FIELD_INVALID ||
13271c01c8c6SMd Fahad Iqbal Polash 	    !ice_is_vsi_valid(hw, vsi_handle))
13281c01c8c6SMd Fahad Iqbal Polash 		return ICE_ERR_PARAM;
13291c01c8c6SMd Fahad Iqbal Polash 
13301c01c8c6SMd Fahad Iqbal Polash 	/* Make sure no unsupported bits are specified */
13311c01c8c6SMd Fahad Iqbal Polash 	if (avf_hash & ~(ICE_FLOW_AVF_RSS_ALL_IPV4_MASKS |
13321c01c8c6SMd Fahad Iqbal Polash 			 ICE_FLOW_AVF_RSS_ALL_IPV6_MASKS))
13331c01c8c6SMd Fahad Iqbal Polash 		return ICE_ERR_CFG;
13341c01c8c6SMd Fahad Iqbal Polash 
13351c01c8c6SMd Fahad Iqbal Polash 	hash_flds = avf_hash;
13361c01c8c6SMd Fahad Iqbal Polash 
13371c01c8c6SMd Fahad Iqbal Polash 	/* Always create an L3 RSS configuration for any L4 RSS configuration */
13381c01c8c6SMd Fahad Iqbal Polash 	if (hash_flds & ICE_FLOW_AVF_RSS_ALL_IPV4_MASKS)
13391c01c8c6SMd Fahad Iqbal Polash 		hash_flds |= ICE_FLOW_AVF_RSS_IPV4_MASKS;
13401c01c8c6SMd Fahad Iqbal Polash 
13411c01c8c6SMd Fahad Iqbal Polash 	if (hash_flds & ICE_FLOW_AVF_RSS_ALL_IPV6_MASKS)
13421c01c8c6SMd Fahad Iqbal Polash 		hash_flds |= ICE_FLOW_AVF_RSS_IPV6_MASKS;
13431c01c8c6SMd Fahad Iqbal Polash 
13441c01c8c6SMd Fahad Iqbal Polash 	/* Create the corresponding RSS configuration for each valid hash bit */
13451c01c8c6SMd Fahad Iqbal Polash 	while (hash_flds) {
13461c01c8c6SMd Fahad Iqbal Polash 		u64 rss_hash = ICE_HASH_INVALID;
13471c01c8c6SMd Fahad Iqbal Polash 
13481c01c8c6SMd Fahad Iqbal Polash 		if (hash_flds & ICE_FLOW_AVF_RSS_ALL_IPV4_MASKS) {
13491c01c8c6SMd Fahad Iqbal Polash 			if (hash_flds & ICE_FLOW_AVF_RSS_IPV4_MASKS) {
13501c01c8c6SMd Fahad Iqbal Polash 				rss_hash = ICE_FLOW_HASH_IPV4;
13511c01c8c6SMd Fahad Iqbal Polash 				hash_flds &= ~ICE_FLOW_AVF_RSS_IPV4_MASKS;
13521c01c8c6SMd Fahad Iqbal Polash 			} else if (hash_flds &
13531c01c8c6SMd Fahad Iqbal Polash 				   ICE_FLOW_AVF_RSS_TCP_IPV4_MASKS) {
13541c01c8c6SMd Fahad Iqbal Polash 				rss_hash = ICE_FLOW_HASH_IPV4 |
13551c01c8c6SMd Fahad Iqbal Polash 					ICE_FLOW_HASH_TCP_PORT;
13561c01c8c6SMd Fahad Iqbal Polash 				hash_flds &= ~ICE_FLOW_AVF_RSS_TCP_IPV4_MASKS;
13571c01c8c6SMd Fahad Iqbal Polash 			} else if (hash_flds &
13581c01c8c6SMd Fahad Iqbal Polash 				   ICE_FLOW_AVF_RSS_UDP_IPV4_MASKS) {
13591c01c8c6SMd Fahad Iqbal Polash 				rss_hash = ICE_FLOW_HASH_IPV4 |
13601c01c8c6SMd Fahad Iqbal Polash 					ICE_FLOW_HASH_UDP_PORT;
13611c01c8c6SMd Fahad Iqbal Polash 				hash_flds &= ~ICE_FLOW_AVF_RSS_UDP_IPV4_MASKS;
13621c01c8c6SMd Fahad Iqbal Polash 			} else if (hash_flds &
13631c01c8c6SMd Fahad Iqbal Polash 				   BIT_ULL(ICE_AVF_FLOW_FIELD_IPV4_SCTP)) {
13641c01c8c6SMd Fahad Iqbal Polash 				rss_hash = ICE_FLOW_HASH_IPV4 |
13651c01c8c6SMd Fahad Iqbal Polash 					ICE_FLOW_HASH_SCTP_PORT;
13661c01c8c6SMd Fahad Iqbal Polash 				hash_flds &=
13671c01c8c6SMd Fahad Iqbal Polash 					~BIT_ULL(ICE_AVF_FLOW_FIELD_IPV4_SCTP);
13681c01c8c6SMd Fahad Iqbal Polash 			}
13691c01c8c6SMd Fahad Iqbal Polash 		} else if (hash_flds & ICE_FLOW_AVF_RSS_ALL_IPV6_MASKS) {
13701c01c8c6SMd Fahad Iqbal Polash 			if (hash_flds & ICE_FLOW_AVF_RSS_IPV6_MASKS) {
13711c01c8c6SMd Fahad Iqbal Polash 				rss_hash = ICE_FLOW_HASH_IPV6;
13721c01c8c6SMd Fahad Iqbal Polash 				hash_flds &= ~ICE_FLOW_AVF_RSS_IPV6_MASKS;
13731c01c8c6SMd Fahad Iqbal Polash 			} else if (hash_flds &
13741c01c8c6SMd Fahad Iqbal Polash 				   ICE_FLOW_AVF_RSS_TCP_IPV6_MASKS) {
13751c01c8c6SMd Fahad Iqbal Polash 				rss_hash = ICE_FLOW_HASH_IPV6 |
13761c01c8c6SMd Fahad Iqbal Polash 					ICE_FLOW_HASH_TCP_PORT;
13771c01c8c6SMd Fahad Iqbal Polash 				hash_flds &= ~ICE_FLOW_AVF_RSS_TCP_IPV6_MASKS;
13781c01c8c6SMd Fahad Iqbal Polash 			} else if (hash_flds &
13791c01c8c6SMd Fahad Iqbal Polash 				   ICE_FLOW_AVF_RSS_UDP_IPV6_MASKS) {
13801c01c8c6SMd Fahad Iqbal Polash 				rss_hash = ICE_FLOW_HASH_IPV6 |
13811c01c8c6SMd Fahad Iqbal Polash 					ICE_FLOW_HASH_UDP_PORT;
13821c01c8c6SMd Fahad Iqbal Polash 				hash_flds &= ~ICE_FLOW_AVF_RSS_UDP_IPV6_MASKS;
13831c01c8c6SMd Fahad Iqbal Polash 			} else if (hash_flds &
13841c01c8c6SMd Fahad Iqbal Polash 				   BIT_ULL(ICE_AVF_FLOW_FIELD_IPV6_SCTP)) {
13851c01c8c6SMd Fahad Iqbal Polash 				rss_hash = ICE_FLOW_HASH_IPV6 |
13861c01c8c6SMd Fahad Iqbal Polash 					ICE_FLOW_HASH_SCTP_PORT;
13871c01c8c6SMd Fahad Iqbal Polash 				hash_flds &=
13881c01c8c6SMd Fahad Iqbal Polash 					~BIT_ULL(ICE_AVF_FLOW_FIELD_IPV6_SCTP);
13891c01c8c6SMd Fahad Iqbal Polash 			}
13901c01c8c6SMd Fahad Iqbal Polash 		}
13911c01c8c6SMd Fahad Iqbal Polash 
13921c01c8c6SMd Fahad Iqbal Polash 		if (rss_hash == ICE_HASH_INVALID)
13931c01c8c6SMd Fahad Iqbal Polash 			return ICE_ERR_OUT_OF_RANGE;
13941c01c8c6SMd Fahad Iqbal Polash 
13951c01c8c6SMd Fahad Iqbal Polash 		status = ice_add_rss_cfg(hw, vsi_handle, rss_hash,
13961c01c8c6SMd Fahad Iqbal Polash 					 ICE_FLOW_SEG_HDR_NONE);
13971c01c8c6SMd Fahad Iqbal Polash 		if (status)
13981c01c8c6SMd Fahad Iqbal Polash 			break;
13991c01c8c6SMd Fahad Iqbal Polash 	}
14001c01c8c6SMd Fahad Iqbal Polash 
14011c01c8c6SMd Fahad Iqbal Polash 	return status;
14021c01c8c6SMd Fahad Iqbal Polash }
14031c01c8c6SMd Fahad Iqbal Polash 
1404c90ed40cSTony Nguyen /**
1405c90ed40cSTony Nguyen  * ice_replay_rss_cfg - replay RSS configurations associated with VSI
1406c90ed40cSTony Nguyen  * @hw: pointer to the hardware structure
1407c90ed40cSTony Nguyen  * @vsi_handle: software VSI handle
1408c90ed40cSTony Nguyen  */
1409c90ed40cSTony Nguyen enum ice_status ice_replay_rss_cfg(struct ice_hw *hw, u16 vsi_handle)
1410c90ed40cSTony Nguyen {
1411c90ed40cSTony Nguyen 	enum ice_status status = 0;
1412c90ed40cSTony Nguyen 	struct ice_rss_cfg *r;
1413c90ed40cSTony Nguyen 
1414c90ed40cSTony Nguyen 	if (!ice_is_vsi_valid(hw, vsi_handle))
1415c90ed40cSTony Nguyen 		return ICE_ERR_PARAM;
1416c90ed40cSTony Nguyen 
1417c90ed40cSTony Nguyen 	mutex_lock(&hw->rss_locks);
1418c90ed40cSTony Nguyen 	list_for_each_entry(r, &hw->rss_list_head, l_entry) {
1419c90ed40cSTony Nguyen 		if (test_bit(vsi_handle, r->vsis)) {
1420451f2c44STony Nguyen 			status = ice_add_rss_cfg_sync(hw, vsi_handle,
1421451f2c44STony Nguyen 						      r->hashed_flds,
1422c90ed40cSTony Nguyen 						      r->packet_hdr,
1423c90ed40cSTony Nguyen 						      ICE_RSS_OUTER_HEADERS);
1424c90ed40cSTony Nguyen 			if (status)
1425c90ed40cSTony Nguyen 				break;
1426a4e82a81STony Nguyen 			status = ice_add_rss_cfg_sync(hw, vsi_handle,
1427a4e82a81STony Nguyen 						      r->hashed_flds,
1428a4e82a81STony Nguyen 						      r->packet_hdr,
1429a4e82a81STony Nguyen 						      ICE_RSS_INNER_HEADERS);
1430a4e82a81STony Nguyen 			if (status)
1431a4e82a81STony Nguyen 				break;
1432c90ed40cSTony Nguyen 		}
1433c90ed40cSTony Nguyen 	}
1434c90ed40cSTony Nguyen 	mutex_unlock(&hw->rss_locks);
1435c90ed40cSTony Nguyen 
1436c90ed40cSTony Nguyen 	return status;
1437c90ed40cSTony Nguyen }
14386876fb64SMd Fahad Iqbal Polash 
14396876fb64SMd Fahad Iqbal Polash /**
14406876fb64SMd Fahad Iqbal Polash  * ice_get_rss_cfg - returns hashed fields for the given header types
14416876fb64SMd Fahad Iqbal Polash  * @hw: pointer to the hardware structure
14426876fb64SMd Fahad Iqbal Polash  * @vsi_handle: software VSI handle
14436876fb64SMd Fahad Iqbal Polash  * @hdrs: protocol header type
14446876fb64SMd Fahad Iqbal Polash  *
14456876fb64SMd Fahad Iqbal Polash  * This function will return the match fields of the first instance of flow
14466876fb64SMd Fahad Iqbal Polash  * profile having the given header types and containing input VSI
14476876fb64SMd Fahad Iqbal Polash  */
14486876fb64SMd Fahad Iqbal Polash u64 ice_get_rss_cfg(struct ice_hw *hw, u16 vsi_handle, u32 hdrs)
14496876fb64SMd Fahad Iqbal Polash {
14506876fb64SMd Fahad Iqbal Polash 	struct ice_rss_cfg *r, *rss_cfg = NULL;
14516876fb64SMd Fahad Iqbal Polash 
14526876fb64SMd Fahad Iqbal Polash 	/* verify if the protocol header is non zero and VSI is valid */
14536876fb64SMd Fahad Iqbal Polash 	if (hdrs == ICE_FLOW_SEG_HDR_NONE || !ice_is_vsi_valid(hw, vsi_handle))
14546876fb64SMd Fahad Iqbal Polash 		return ICE_HASH_INVALID;
14556876fb64SMd Fahad Iqbal Polash 
14566876fb64SMd Fahad Iqbal Polash 	mutex_lock(&hw->rss_locks);
14576876fb64SMd Fahad Iqbal Polash 	list_for_each_entry(r, &hw->rss_list_head, l_entry)
14586876fb64SMd Fahad Iqbal Polash 		if (test_bit(vsi_handle, r->vsis) &&
14596876fb64SMd Fahad Iqbal Polash 		    r->packet_hdr == hdrs) {
14606876fb64SMd Fahad Iqbal Polash 			rss_cfg = r;
14616876fb64SMd Fahad Iqbal Polash 			break;
14626876fb64SMd Fahad Iqbal Polash 		}
14636876fb64SMd Fahad Iqbal Polash 	mutex_unlock(&hw->rss_locks);
14646876fb64SMd Fahad Iqbal Polash 
14656876fb64SMd Fahad Iqbal Polash 	return rss_cfg ? rss_cfg->hashed_flds : ICE_HASH_INVALID;
14666876fb64SMd Fahad Iqbal Polash }
1467