18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
28c2ecf20Sopenharmony_ci/* Copyright (c) 2019, Intel Corporation. */
38c2ecf20Sopenharmony_ci
48c2ecf20Sopenharmony_ci#include "ice_common.h"
58c2ecf20Sopenharmony_ci#include "ice_flow.h"
68c2ecf20Sopenharmony_ci
78c2ecf20Sopenharmony_ci/* Describe properties of a protocol header field */
88c2ecf20Sopenharmony_cistruct ice_flow_field_info {
98c2ecf20Sopenharmony_ci	enum ice_flow_seg_hdr hdr;
108c2ecf20Sopenharmony_ci	s16 off;	/* Offset from start of a protocol header, in bits */
118c2ecf20Sopenharmony_ci	u16 size;	/* Size of fields in bits */
128c2ecf20Sopenharmony_ci};
138c2ecf20Sopenharmony_ci
148c2ecf20Sopenharmony_ci#define ICE_FLOW_FLD_INFO(_hdr, _offset_bytes, _size_bytes) { \
158c2ecf20Sopenharmony_ci	.hdr = _hdr, \
168c2ecf20Sopenharmony_ci	.off = (_offset_bytes) * BITS_PER_BYTE, \
178c2ecf20Sopenharmony_ci	.size = (_size_bytes) * BITS_PER_BYTE, \
188c2ecf20Sopenharmony_ci}
198c2ecf20Sopenharmony_ci
208c2ecf20Sopenharmony_ci/* Table containing properties of supported protocol header fields */
218c2ecf20Sopenharmony_cistatic const
228c2ecf20Sopenharmony_cistruct ice_flow_field_info ice_flds_info[ICE_FLOW_FIELD_IDX_MAX] = {
238c2ecf20Sopenharmony_ci	/* IPv4 / IPv6 */
248c2ecf20Sopenharmony_ci	/* ICE_FLOW_FIELD_IDX_IPV4_SA */
258c2ecf20Sopenharmony_ci	ICE_FLOW_FLD_INFO(ICE_FLOW_SEG_HDR_IPV4, 12, sizeof(struct in_addr)),
268c2ecf20Sopenharmony_ci	/* ICE_FLOW_FIELD_IDX_IPV4_DA */
278c2ecf20Sopenharmony_ci	ICE_FLOW_FLD_INFO(ICE_FLOW_SEG_HDR_IPV4, 16, sizeof(struct in_addr)),
288c2ecf20Sopenharmony_ci	/* ICE_FLOW_FIELD_IDX_IPV6_SA */
298c2ecf20Sopenharmony_ci	ICE_FLOW_FLD_INFO(ICE_FLOW_SEG_HDR_IPV6, 8, sizeof(struct in6_addr)),
308c2ecf20Sopenharmony_ci	/* ICE_FLOW_FIELD_IDX_IPV6_DA */
318c2ecf20Sopenharmony_ci	ICE_FLOW_FLD_INFO(ICE_FLOW_SEG_HDR_IPV6, 24, sizeof(struct in6_addr)),
328c2ecf20Sopenharmony_ci	/* Transport */
338c2ecf20Sopenharmony_ci	/* ICE_FLOW_FIELD_IDX_TCP_SRC_PORT */
348c2ecf20Sopenharmony_ci	ICE_FLOW_FLD_INFO(ICE_FLOW_SEG_HDR_TCP, 0, sizeof(__be16)),
358c2ecf20Sopenharmony_ci	/* ICE_FLOW_FIELD_IDX_TCP_DST_PORT */
368c2ecf20Sopenharmony_ci	ICE_FLOW_FLD_INFO(ICE_FLOW_SEG_HDR_TCP, 2, sizeof(__be16)),
378c2ecf20Sopenharmony_ci	/* ICE_FLOW_FIELD_IDX_UDP_SRC_PORT */
388c2ecf20Sopenharmony_ci	ICE_FLOW_FLD_INFO(ICE_FLOW_SEG_HDR_UDP, 0, sizeof(__be16)),
398c2ecf20Sopenharmony_ci	/* ICE_FLOW_FIELD_IDX_UDP_DST_PORT */
408c2ecf20Sopenharmony_ci	ICE_FLOW_FLD_INFO(ICE_FLOW_SEG_HDR_UDP, 2, sizeof(__be16)),
418c2ecf20Sopenharmony_ci	/* ICE_FLOW_FIELD_IDX_SCTP_SRC_PORT */
428c2ecf20Sopenharmony_ci	ICE_FLOW_FLD_INFO(ICE_FLOW_SEG_HDR_SCTP, 0, sizeof(__be16)),
438c2ecf20Sopenharmony_ci	/* ICE_FLOW_FIELD_IDX_SCTP_DST_PORT */
448c2ecf20Sopenharmony_ci	ICE_FLOW_FLD_INFO(ICE_FLOW_SEG_HDR_SCTP, 2, sizeof(__be16)),
458c2ecf20Sopenharmony_ci	/* GRE */
468c2ecf20Sopenharmony_ci	/* ICE_FLOW_FIELD_IDX_GRE_KEYID */
478c2ecf20Sopenharmony_ci	ICE_FLOW_FLD_INFO(ICE_FLOW_SEG_HDR_GRE, 12,
488c2ecf20Sopenharmony_ci			  sizeof_field(struct gre_full_hdr, key)),
498c2ecf20Sopenharmony_ci};
508c2ecf20Sopenharmony_ci
518c2ecf20Sopenharmony_ci/* Bitmaps indicating relevant packet types for a particular protocol header
528c2ecf20Sopenharmony_ci *
538c2ecf20Sopenharmony_ci * Packet types for packets with an Outer/First/Single IPv4 header
548c2ecf20Sopenharmony_ci */
558c2ecf20Sopenharmony_cistatic const u32 ice_ptypes_ipv4_ofos[] = {
568c2ecf20Sopenharmony_ci	0x1DC00000, 0x04000800, 0x00000000, 0x00000000,
578c2ecf20Sopenharmony_ci	0x00000000, 0x00000000, 0x00000000, 0x00000000,
588c2ecf20Sopenharmony_ci	0x00000000, 0x00000000, 0x00000000, 0x00000000,
598c2ecf20Sopenharmony_ci	0x00000000, 0x00000000, 0x00000000, 0x00000000,
608c2ecf20Sopenharmony_ci	0x00000000, 0x00000000, 0x00000000, 0x00000000,
618c2ecf20Sopenharmony_ci	0x00000000, 0x00000000, 0x00000000, 0x00000000,
628c2ecf20Sopenharmony_ci	0x00000000, 0x00000000, 0x00000000, 0x00000000,
638c2ecf20Sopenharmony_ci	0x00000000, 0x00000000, 0x00000000, 0x00000000,
648c2ecf20Sopenharmony_ci};
658c2ecf20Sopenharmony_ci
668c2ecf20Sopenharmony_ci/* Packet types for packets with an Innermost/Last IPv4 header */
678c2ecf20Sopenharmony_cistatic const u32 ice_ptypes_ipv4_il[] = {
688c2ecf20Sopenharmony_ci	0xE0000000, 0xB807700E, 0x80000003, 0xE01DC03B,
698c2ecf20Sopenharmony_ci	0x0000000E, 0x00000000, 0x00000000, 0x00000000,
708c2ecf20Sopenharmony_ci	0x00000000, 0x00000000, 0x00000000, 0x00000000,
718c2ecf20Sopenharmony_ci	0x00000000, 0x00000000, 0x00000000, 0x00000000,
728c2ecf20Sopenharmony_ci	0x00000000, 0x00000000, 0x00000000, 0x00000000,
738c2ecf20Sopenharmony_ci	0x00000000, 0x00000000, 0x00000000, 0x00000000,
748c2ecf20Sopenharmony_ci	0x00000000, 0x00000000, 0x00000000, 0x00000000,
758c2ecf20Sopenharmony_ci	0x00000000, 0x00000000, 0x00000000, 0x00000000,
768c2ecf20Sopenharmony_ci};
778c2ecf20Sopenharmony_ci
788c2ecf20Sopenharmony_ci/* Packet types for packets with an Outer/First/Single IPv6 header */
798c2ecf20Sopenharmony_cistatic const u32 ice_ptypes_ipv6_ofos[] = {
808c2ecf20Sopenharmony_ci	0x00000000, 0x00000000, 0x77000000, 0x10002000,
818c2ecf20Sopenharmony_ci	0x00000000, 0x00000000, 0x00000000, 0x00000000,
828c2ecf20Sopenharmony_ci	0x00000000, 0x00000000, 0x00000000, 0x00000000,
838c2ecf20Sopenharmony_ci	0x00000000, 0x00000000, 0x00000000, 0x00000000,
848c2ecf20Sopenharmony_ci	0x00000000, 0x00000000, 0x00000000, 0x00000000,
858c2ecf20Sopenharmony_ci	0x00000000, 0x00000000, 0x00000000, 0x00000000,
868c2ecf20Sopenharmony_ci	0x00000000, 0x00000000, 0x00000000, 0x00000000,
878c2ecf20Sopenharmony_ci	0x00000000, 0x00000000, 0x00000000, 0x00000000,
888c2ecf20Sopenharmony_ci};
898c2ecf20Sopenharmony_ci
908c2ecf20Sopenharmony_ci/* Packet types for packets with an Innermost/Last IPv6 header */
918c2ecf20Sopenharmony_cistatic const u32 ice_ptypes_ipv6_il[] = {
928c2ecf20Sopenharmony_ci	0x00000000, 0x03B80770, 0x000001DC, 0x0EE00000,
938c2ecf20Sopenharmony_ci	0x00000770, 0x00000000, 0x00000000, 0x00000000,
948c2ecf20Sopenharmony_ci	0x00000000, 0x00000000, 0x00000000, 0x00000000,
958c2ecf20Sopenharmony_ci	0x00000000, 0x00000000, 0x00000000, 0x00000000,
968c2ecf20Sopenharmony_ci	0x00000000, 0x00000000, 0x00000000, 0x00000000,
978c2ecf20Sopenharmony_ci	0x00000000, 0x00000000, 0x00000000, 0x00000000,
988c2ecf20Sopenharmony_ci	0x00000000, 0x00000000, 0x00000000, 0x00000000,
998c2ecf20Sopenharmony_ci	0x00000000, 0x00000000, 0x00000000, 0x00000000,
1008c2ecf20Sopenharmony_ci};
1018c2ecf20Sopenharmony_ci
1028c2ecf20Sopenharmony_ci/* Packet types for packets with an Outer/First/Single IPv4 header - no L4 */
1038c2ecf20Sopenharmony_cistatic const u32 ice_ipv4_ofos_no_l4[] = {
1048c2ecf20Sopenharmony_ci	0x10C00000, 0x04000800, 0x00000000, 0x00000000,
1058c2ecf20Sopenharmony_ci	0x00000000, 0x00000000, 0x00000000, 0x00000000,
1068c2ecf20Sopenharmony_ci	0x00000000, 0x00000000, 0x00000000, 0x00000000,
1078c2ecf20Sopenharmony_ci	0x00000000, 0x00000000, 0x00000000, 0x00000000,
1088c2ecf20Sopenharmony_ci	0x00000000, 0x00000000, 0x00000000, 0x00000000,
1098c2ecf20Sopenharmony_ci	0x00000000, 0x00000000, 0x00000000, 0x00000000,
1108c2ecf20Sopenharmony_ci	0x00000000, 0x00000000, 0x00000000, 0x00000000,
1118c2ecf20Sopenharmony_ci	0x00000000, 0x00000000, 0x00000000, 0x00000000,
1128c2ecf20Sopenharmony_ci};
1138c2ecf20Sopenharmony_ci
1148c2ecf20Sopenharmony_ci/* Packet types for packets with an Innermost/Last IPv4 header - no L4 */
1158c2ecf20Sopenharmony_cistatic const u32 ice_ipv4_il_no_l4[] = {
1168c2ecf20Sopenharmony_ci	0x60000000, 0x18043008, 0x80000002, 0x6010c021,
1178c2ecf20Sopenharmony_ci	0x00000008, 0x00000000, 0x00000000, 0x00000000,
1188c2ecf20Sopenharmony_ci	0x00000000, 0x00000000, 0x00000000, 0x00000000,
1198c2ecf20Sopenharmony_ci	0x00000000, 0x00000000, 0x00000000, 0x00000000,
1208c2ecf20Sopenharmony_ci	0x00000000, 0x00000000, 0x00000000, 0x00000000,
1218c2ecf20Sopenharmony_ci	0x00000000, 0x00000000, 0x00000000, 0x00000000,
1228c2ecf20Sopenharmony_ci	0x00000000, 0x00000000, 0x00000000, 0x00000000,
1238c2ecf20Sopenharmony_ci	0x00000000, 0x00000000, 0x00000000, 0x00000000,
1248c2ecf20Sopenharmony_ci};
1258c2ecf20Sopenharmony_ci
1268c2ecf20Sopenharmony_ci/* Packet types for packets with an Outer/First/Single IPv6 header - no L4 */
1278c2ecf20Sopenharmony_cistatic const u32 ice_ipv6_ofos_no_l4[] = {
1288c2ecf20Sopenharmony_ci	0x00000000, 0x00000000, 0x43000000, 0x10002000,
1298c2ecf20Sopenharmony_ci	0x00000000, 0x00000000, 0x00000000, 0x00000000,
1308c2ecf20Sopenharmony_ci	0x00000000, 0x00000000, 0x00000000, 0x00000000,
1318c2ecf20Sopenharmony_ci	0x00000000, 0x00000000, 0x00000000, 0x00000000,
1328c2ecf20Sopenharmony_ci	0x00000000, 0x00000000, 0x00000000, 0x00000000,
1338c2ecf20Sopenharmony_ci	0x00000000, 0x00000000, 0x00000000, 0x00000000,
1348c2ecf20Sopenharmony_ci	0x00000000, 0x00000000, 0x00000000, 0x00000000,
1358c2ecf20Sopenharmony_ci	0x00000000, 0x00000000, 0x00000000, 0x00000000,
1368c2ecf20Sopenharmony_ci};
1378c2ecf20Sopenharmony_ci
1388c2ecf20Sopenharmony_ci/* Packet types for packets with an Innermost/Last IPv6 header - no L4 */
1398c2ecf20Sopenharmony_cistatic const u32 ice_ipv6_il_no_l4[] = {
1408c2ecf20Sopenharmony_ci	0x00000000, 0x02180430, 0x0000010c, 0x086010c0,
1418c2ecf20Sopenharmony_ci	0x00000430, 0x00000000, 0x00000000, 0x00000000,
1428c2ecf20Sopenharmony_ci	0x00000000, 0x00000000, 0x00000000, 0x00000000,
1438c2ecf20Sopenharmony_ci	0x00000000, 0x00000000, 0x00000000, 0x00000000,
1448c2ecf20Sopenharmony_ci	0x00000000, 0x00000000, 0x00000000, 0x00000000,
1458c2ecf20Sopenharmony_ci	0x00000000, 0x00000000, 0x00000000, 0x00000000,
1468c2ecf20Sopenharmony_ci	0x00000000, 0x00000000, 0x00000000, 0x00000000,
1478c2ecf20Sopenharmony_ci	0x00000000, 0x00000000, 0x00000000, 0x00000000,
1488c2ecf20Sopenharmony_ci};
1498c2ecf20Sopenharmony_ci
1508c2ecf20Sopenharmony_ci/* UDP Packet types for non-tunneled packets or tunneled
1518c2ecf20Sopenharmony_ci * packets with inner UDP.
1528c2ecf20Sopenharmony_ci */
1538c2ecf20Sopenharmony_cistatic const u32 ice_ptypes_udp_il[] = {
1548c2ecf20Sopenharmony_ci	0x81000000, 0x20204040, 0x04000010, 0x80810102,
1558c2ecf20Sopenharmony_ci	0x00000040, 0x00000000, 0x00000000, 0x00000000,
1568c2ecf20Sopenharmony_ci	0x00000000, 0x00000000, 0x00000000, 0x00000000,
1578c2ecf20Sopenharmony_ci	0x00000000, 0x00000000, 0x00000000, 0x00000000,
1588c2ecf20Sopenharmony_ci	0x00000000, 0x00000000, 0x00000000, 0x00000000,
1598c2ecf20Sopenharmony_ci	0x00000000, 0x00000000, 0x00000000, 0x00000000,
1608c2ecf20Sopenharmony_ci	0x00000000, 0x00000000, 0x00000000, 0x00000000,
1618c2ecf20Sopenharmony_ci	0x00000000, 0x00000000, 0x00000000, 0x00000000,
1628c2ecf20Sopenharmony_ci};
1638c2ecf20Sopenharmony_ci
1648c2ecf20Sopenharmony_ci/* Packet types for packets with an Innermost/Last TCP header */
1658c2ecf20Sopenharmony_cistatic const u32 ice_ptypes_tcp_il[] = {
1668c2ecf20Sopenharmony_ci	0x04000000, 0x80810102, 0x10000040, 0x02040408,
1678c2ecf20Sopenharmony_ci	0x00000102, 0x00000000, 0x00000000, 0x00000000,
1688c2ecf20Sopenharmony_ci	0x00000000, 0x00000000, 0x00000000, 0x00000000,
1698c2ecf20Sopenharmony_ci	0x00000000, 0x00000000, 0x00000000, 0x00000000,
1708c2ecf20Sopenharmony_ci	0x00000000, 0x00000000, 0x00000000, 0x00000000,
1718c2ecf20Sopenharmony_ci	0x00000000, 0x00000000, 0x00000000, 0x00000000,
1728c2ecf20Sopenharmony_ci	0x00000000, 0x00000000, 0x00000000, 0x00000000,
1738c2ecf20Sopenharmony_ci	0x00000000, 0x00000000, 0x00000000, 0x00000000,
1748c2ecf20Sopenharmony_ci};
1758c2ecf20Sopenharmony_ci
1768c2ecf20Sopenharmony_ci/* Packet types for packets with an Innermost/Last SCTP header */
1778c2ecf20Sopenharmony_cistatic const u32 ice_ptypes_sctp_il[] = {
1788c2ecf20Sopenharmony_ci	0x08000000, 0x01020204, 0x20000081, 0x04080810,
1798c2ecf20Sopenharmony_ci	0x00000204, 0x00000000, 0x00000000, 0x00000000,
1808c2ecf20Sopenharmony_ci	0x00000000, 0x00000000, 0x00000000, 0x00000000,
1818c2ecf20Sopenharmony_ci	0x00000000, 0x00000000, 0x00000000, 0x00000000,
1828c2ecf20Sopenharmony_ci	0x00000000, 0x00000000, 0x00000000, 0x00000000,
1838c2ecf20Sopenharmony_ci	0x00000000, 0x00000000, 0x00000000, 0x00000000,
1848c2ecf20Sopenharmony_ci	0x00000000, 0x00000000, 0x00000000, 0x00000000,
1858c2ecf20Sopenharmony_ci	0x00000000, 0x00000000, 0x00000000, 0x00000000,
1868c2ecf20Sopenharmony_ci};
1878c2ecf20Sopenharmony_ci
1888c2ecf20Sopenharmony_ci/* Packet types for packets with an Outermost/First GRE header */
1898c2ecf20Sopenharmony_cistatic const u32 ice_ptypes_gre_of[] = {
1908c2ecf20Sopenharmony_ci	0x00000000, 0xBFBF7800, 0x000001DF, 0xFEFDE000,
1918c2ecf20Sopenharmony_ci	0x0000017E, 0x00000000, 0x00000000, 0x00000000,
1928c2ecf20Sopenharmony_ci	0x00000000, 0x00000000, 0x00000000, 0x00000000,
1938c2ecf20Sopenharmony_ci	0x00000000, 0x00000000, 0x00000000, 0x00000000,
1948c2ecf20Sopenharmony_ci	0x00000000, 0x00000000, 0x00000000, 0x00000000,
1958c2ecf20Sopenharmony_ci	0x00000000, 0x00000000, 0x00000000, 0x00000000,
1968c2ecf20Sopenharmony_ci	0x00000000, 0x00000000, 0x00000000, 0x00000000,
1978c2ecf20Sopenharmony_ci	0x00000000, 0x00000000, 0x00000000, 0x00000000,
1988c2ecf20Sopenharmony_ci};
1998c2ecf20Sopenharmony_ci
2008c2ecf20Sopenharmony_ci/* Manage parameters and info. used during the creation of a flow profile */
2018c2ecf20Sopenharmony_cistruct ice_flow_prof_params {
2028c2ecf20Sopenharmony_ci	enum ice_block blk;
2038c2ecf20Sopenharmony_ci	u16 entry_length; /* # of bytes formatted entry will require */
2048c2ecf20Sopenharmony_ci	u8 es_cnt;
2058c2ecf20Sopenharmony_ci	struct ice_flow_prof *prof;
2068c2ecf20Sopenharmony_ci
2078c2ecf20Sopenharmony_ci	/* For ACL, the es[0] will have the data of ICE_RX_MDID_PKT_FLAGS_15_0
2088c2ecf20Sopenharmony_ci	 * This will give us the direction flags.
2098c2ecf20Sopenharmony_ci	 */
2108c2ecf20Sopenharmony_ci	struct ice_fv_word es[ICE_MAX_FV_WORDS];
2118c2ecf20Sopenharmony_ci	DECLARE_BITMAP(ptypes, ICE_FLOW_PTYPE_MAX);
2128c2ecf20Sopenharmony_ci};
2138c2ecf20Sopenharmony_ci
2148c2ecf20Sopenharmony_ci#define ICE_FLOW_SEG_HDRS_L3_MASK	\
2158c2ecf20Sopenharmony_ci	(ICE_FLOW_SEG_HDR_IPV4 | ICE_FLOW_SEG_HDR_IPV6)
2168c2ecf20Sopenharmony_ci#define ICE_FLOW_SEG_HDRS_L4_MASK	\
2178c2ecf20Sopenharmony_ci	(ICE_FLOW_SEG_HDR_TCP | ICE_FLOW_SEG_HDR_UDP | ICE_FLOW_SEG_HDR_SCTP)
2188c2ecf20Sopenharmony_ci
2198c2ecf20Sopenharmony_ci/**
2208c2ecf20Sopenharmony_ci * ice_flow_val_hdrs - validates packet segments for valid protocol headers
2218c2ecf20Sopenharmony_ci * @segs: array of one or more packet segments that describe the flow
2228c2ecf20Sopenharmony_ci * @segs_cnt: number of packet segments provided
2238c2ecf20Sopenharmony_ci */
2248c2ecf20Sopenharmony_cistatic enum ice_status
2258c2ecf20Sopenharmony_ciice_flow_val_hdrs(struct ice_flow_seg_info *segs, u8 segs_cnt)
2268c2ecf20Sopenharmony_ci{
2278c2ecf20Sopenharmony_ci	u8 i;
2288c2ecf20Sopenharmony_ci
2298c2ecf20Sopenharmony_ci	for (i = 0; i < segs_cnt; i++) {
2308c2ecf20Sopenharmony_ci		/* Multiple L3 headers */
2318c2ecf20Sopenharmony_ci		if (segs[i].hdrs & ICE_FLOW_SEG_HDRS_L3_MASK &&
2328c2ecf20Sopenharmony_ci		    !is_power_of_2(segs[i].hdrs & ICE_FLOW_SEG_HDRS_L3_MASK))
2338c2ecf20Sopenharmony_ci			return ICE_ERR_PARAM;
2348c2ecf20Sopenharmony_ci
2358c2ecf20Sopenharmony_ci		/* Multiple L4 headers */
2368c2ecf20Sopenharmony_ci		if (segs[i].hdrs & ICE_FLOW_SEG_HDRS_L4_MASK &&
2378c2ecf20Sopenharmony_ci		    !is_power_of_2(segs[i].hdrs & ICE_FLOW_SEG_HDRS_L4_MASK))
2388c2ecf20Sopenharmony_ci			return ICE_ERR_PARAM;
2398c2ecf20Sopenharmony_ci	}
2408c2ecf20Sopenharmony_ci
2418c2ecf20Sopenharmony_ci	return 0;
2428c2ecf20Sopenharmony_ci}
2438c2ecf20Sopenharmony_ci
2448c2ecf20Sopenharmony_ci/* Sizes of fixed known protocol headers without header options */
2458c2ecf20Sopenharmony_ci#define ICE_FLOW_PROT_HDR_SZ_MAC	14
2468c2ecf20Sopenharmony_ci#define ICE_FLOW_PROT_HDR_SZ_IPV4	20
2478c2ecf20Sopenharmony_ci#define ICE_FLOW_PROT_HDR_SZ_IPV6	40
2488c2ecf20Sopenharmony_ci#define ICE_FLOW_PROT_HDR_SZ_TCP	20
2498c2ecf20Sopenharmony_ci#define ICE_FLOW_PROT_HDR_SZ_UDP	8
2508c2ecf20Sopenharmony_ci#define ICE_FLOW_PROT_HDR_SZ_SCTP	12
2518c2ecf20Sopenharmony_ci
2528c2ecf20Sopenharmony_ci/**
2538c2ecf20Sopenharmony_ci * ice_flow_calc_seg_sz - calculates size of a packet segment based on headers
2548c2ecf20Sopenharmony_ci * @params: information about the flow to be processed
2558c2ecf20Sopenharmony_ci * @seg: index of packet segment whose header size is to be determined
2568c2ecf20Sopenharmony_ci */
2578c2ecf20Sopenharmony_cistatic u16 ice_flow_calc_seg_sz(struct ice_flow_prof_params *params, u8 seg)
2588c2ecf20Sopenharmony_ci{
2598c2ecf20Sopenharmony_ci	u16 sz = ICE_FLOW_PROT_HDR_SZ_MAC;
2608c2ecf20Sopenharmony_ci
2618c2ecf20Sopenharmony_ci	/* L3 headers */
2628c2ecf20Sopenharmony_ci	if (params->prof->segs[seg].hdrs & ICE_FLOW_SEG_HDR_IPV4)
2638c2ecf20Sopenharmony_ci		sz += ICE_FLOW_PROT_HDR_SZ_IPV4;
2648c2ecf20Sopenharmony_ci	else if (params->prof->segs[seg].hdrs & ICE_FLOW_SEG_HDR_IPV6)
2658c2ecf20Sopenharmony_ci		sz += ICE_FLOW_PROT_HDR_SZ_IPV6;
2668c2ecf20Sopenharmony_ci
2678c2ecf20Sopenharmony_ci	/* L4 headers */
2688c2ecf20Sopenharmony_ci	if (params->prof->segs[seg].hdrs & ICE_FLOW_SEG_HDR_TCP)
2698c2ecf20Sopenharmony_ci		sz += ICE_FLOW_PROT_HDR_SZ_TCP;
2708c2ecf20Sopenharmony_ci	else if (params->prof->segs[seg].hdrs & ICE_FLOW_SEG_HDR_UDP)
2718c2ecf20Sopenharmony_ci		sz += ICE_FLOW_PROT_HDR_SZ_UDP;
2728c2ecf20Sopenharmony_ci	else if (params->prof->segs[seg].hdrs & ICE_FLOW_SEG_HDR_SCTP)
2738c2ecf20Sopenharmony_ci		sz += ICE_FLOW_PROT_HDR_SZ_SCTP;
2748c2ecf20Sopenharmony_ci
2758c2ecf20Sopenharmony_ci	return sz;
2768c2ecf20Sopenharmony_ci}
2778c2ecf20Sopenharmony_ci
2788c2ecf20Sopenharmony_ci/**
2798c2ecf20Sopenharmony_ci * ice_flow_proc_seg_hdrs - process protocol headers present in pkt segments
2808c2ecf20Sopenharmony_ci * @params: information about the flow to be processed
2818c2ecf20Sopenharmony_ci *
2828c2ecf20Sopenharmony_ci * This function identifies the packet types associated with the protocol
2838c2ecf20Sopenharmony_ci * headers being present in packet segments of the specified flow profile.
2848c2ecf20Sopenharmony_ci */
2858c2ecf20Sopenharmony_cistatic enum ice_status
2868c2ecf20Sopenharmony_ciice_flow_proc_seg_hdrs(struct ice_flow_prof_params *params)
2878c2ecf20Sopenharmony_ci{
2888c2ecf20Sopenharmony_ci	struct ice_flow_prof *prof;
2898c2ecf20Sopenharmony_ci	u8 i;
2908c2ecf20Sopenharmony_ci
2918c2ecf20Sopenharmony_ci	memset(params->ptypes, 0xff, sizeof(params->ptypes));
2928c2ecf20Sopenharmony_ci
2938c2ecf20Sopenharmony_ci	prof = params->prof;
2948c2ecf20Sopenharmony_ci
2958c2ecf20Sopenharmony_ci	for (i = 0; i < params->prof->segs_cnt; i++) {
2968c2ecf20Sopenharmony_ci		const unsigned long *src;
2978c2ecf20Sopenharmony_ci		u32 hdrs;
2988c2ecf20Sopenharmony_ci
2998c2ecf20Sopenharmony_ci		hdrs = prof->segs[i].hdrs;
3008c2ecf20Sopenharmony_ci
3018c2ecf20Sopenharmony_ci		if ((hdrs & ICE_FLOW_SEG_HDR_IPV4) &&
3028c2ecf20Sopenharmony_ci		    !(hdrs & ICE_FLOW_SEG_HDRS_L4_MASK)) {
3038c2ecf20Sopenharmony_ci			src = !i ? (const unsigned long *)ice_ipv4_ofos_no_l4 :
3048c2ecf20Sopenharmony_ci				(const unsigned long *)ice_ipv4_il_no_l4;
3058c2ecf20Sopenharmony_ci			bitmap_and(params->ptypes, params->ptypes, src,
3068c2ecf20Sopenharmony_ci				   ICE_FLOW_PTYPE_MAX);
3078c2ecf20Sopenharmony_ci		} else if (hdrs & ICE_FLOW_SEG_HDR_IPV4) {
3088c2ecf20Sopenharmony_ci			src = !i ? (const unsigned long *)ice_ptypes_ipv4_ofos :
3098c2ecf20Sopenharmony_ci				(const unsigned long *)ice_ptypes_ipv4_il;
3108c2ecf20Sopenharmony_ci			bitmap_and(params->ptypes, params->ptypes, src,
3118c2ecf20Sopenharmony_ci				   ICE_FLOW_PTYPE_MAX);
3128c2ecf20Sopenharmony_ci		} else if ((hdrs & ICE_FLOW_SEG_HDR_IPV6) &&
3138c2ecf20Sopenharmony_ci			   !(hdrs & ICE_FLOW_SEG_HDRS_L4_MASK)) {
3148c2ecf20Sopenharmony_ci			src = !i ? (const unsigned long *)ice_ipv6_ofos_no_l4 :
3158c2ecf20Sopenharmony_ci				(const unsigned long *)ice_ipv6_il_no_l4;
3168c2ecf20Sopenharmony_ci			bitmap_and(params->ptypes, params->ptypes, src,
3178c2ecf20Sopenharmony_ci				   ICE_FLOW_PTYPE_MAX);
3188c2ecf20Sopenharmony_ci		} else if (hdrs & ICE_FLOW_SEG_HDR_IPV6) {
3198c2ecf20Sopenharmony_ci			src = !i ? (const unsigned long *)ice_ptypes_ipv6_ofos :
3208c2ecf20Sopenharmony_ci				(const unsigned long *)ice_ptypes_ipv6_il;
3218c2ecf20Sopenharmony_ci			bitmap_and(params->ptypes, params->ptypes, src,
3228c2ecf20Sopenharmony_ci				   ICE_FLOW_PTYPE_MAX);
3238c2ecf20Sopenharmony_ci		}
3248c2ecf20Sopenharmony_ci
3258c2ecf20Sopenharmony_ci		if (hdrs & ICE_FLOW_SEG_HDR_UDP) {
3268c2ecf20Sopenharmony_ci			src = (const unsigned long *)ice_ptypes_udp_il;
3278c2ecf20Sopenharmony_ci			bitmap_and(params->ptypes, params->ptypes, src,
3288c2ecf20Sopenharmony_ci				   ICE_FLOW_PTYPE_MAX);
3298c2ecf20Sopenharmony_ci		} else if (hdrs & ICE_FLOW_SEG_HDR_TCP) {
3308c2ecf20Sopenharmony_ci			bitmap_and(params->ptypes, params->ptypes,
3318c2ecf20Sopenharmony_ci				   (const unsigned long *)ice_ptypes_tcp_il,
3328c2ecf20Sopenharmony_ci				   ICE_FLOW_PTYPE_MAX);
3338c2ecf20Sopenharmony_ci		} else if (hdrs & ICE_FLOW_SEG_HDR_SCTP) {
3348c2ecf20Sopenharmony_ci			src = (const unsigned long *)ice_ptypes_sctp_il;
3358c2ecf20Sopenharmony_ci			bitmap_and(params->ptypes, params->ptypes, src,
3368c2ecf20Sopenharmony_ci				   ICE_FLOW_PTYPE_MAX);
3378c2ecf20Sopenharmony_ci		} else if (hdrs & ICE_FLOW_SEG_HDR_GRE) {
3388c2ecf20Sopenharmony_ci			if (!i) {
3398c2ecf20Sopenharmony_ci				src = (const unsigned long *)ice_ptypes_gre_of;
3408c2ecf20Sopenharmony_ci				bitmap_and(params->ptypes, params->ptypes,
3418c2ecf20Sopenharmony_ci					   src, ICE_FLOW_PTYPE_MAX);
3428c2ecf20Sopenharmony_ci			}
3438c2ecf20Sopenharmony_ci		}
3448c2ecf20Sopenharmony_ci	}
3458c2ecf20Sopenharmony_ci
3468c2ecf20Sopenharmony_ci	return 0;
3478c2ecf20Sopenharmony_ci}
3488c2ecf20Sopenharmony_ci
3498c2ecf20Sopenharmony_ci/**
3508c2ecf20Sopenharmony_ci * ice_flow_xtract_fld - Create an extraction sequence entry for the given field
3518c2ecf20Sopenharmony_ci * @hw: pointer to the HW struct
3528c2ecf20Sopenharmony_ci * @params: information about the flow to be processed
3538c2ecf20Sopenharmony_ci * @seg: packet segment index of the field to be extracted
3548c2ecf20Sopenharmony_ci * @fld: ID of field to be extracted
3558c2ecf20Sopenharmony_ci *
3568c2ecf20Sopenharmony_ci * This function determines the protocol ID, offset, and size of the given
3578c2ecf20Sopenharmony_ci * field. It then allocates one or more extraction sequence entries for the
3588c2ecf20Sopenharmony_ci * given field, and fill the entries with protocol ID and offset information.
3598c2ecf20Sopenharmony_ci */
3608c2ecf20Sopenharmony_cistatic enum ice_status
3618c2ecf20Sopenharmony_ciice_flow_xtract_fld(struct ice_hw *hw, struct ice_flow_prof_params *params,
3628c2ecf20Sopenharmony_ci		    u8 seg, enum ice_flow_field fld)
3638c2ecf20Sopenharmony_ci{
3648c2ecf20Sopenharmony_ci	enum ice_prot_id prot_id = ICE_PROT_ID_INVAL;
3658c2ecf20Sopenharmony_ci	u8 fv_words = hw->blk[params->blk].es.fvw;
3668c2ecf20Sopenharmony_ci	struct ice_flow_fld_info *flds;
3678c2ecf20Sopenharmony_ci	u16 cnt, ese_bits, i;
3688c2ecf20Sopenharmony_ci	u16 off;
3698c2ecf20Sopenharmony_ci
3708c2ecf20Sopenharmony_ci	flds = params->prof->segs[seg].fields;
3718c2ecf20Sopenharmony_ci
3728c2ecf20Sopenharmony_ci	switch (fld) {
3738c2ecf20Sopenharmony_ci	case ICE_FLOW_FIELD_IDX_IPV4_SA:
3748c2ecf20Sopenharmony_ci	case ICE_FLOW_FIELD_IDX_IPV4_DA:
3758c2ecf20Sopenharmony_ci		prot_id = seg == 0 ? ICE_PROT_IPV4_OF_OR_S : ICE_PROT_IPV4_IL;
3768c2ecf20Sopenharmony_ci		break;
3778c2ecf20Sopenharmony_ci	case ICE_FLOW_FIELD_IDX_IPV6_SA:
3788c2ecf20Sopenharmony_ci	case ICE_FLOW_FIELD_IDX_IPV6_DA:
3798c2ecf20Sopenharmony_ci		prot_id = seg == 0 ? ICE_PROT_IPV6_OF_OR_S : ICE_PROT_IPV6_IL;
3808c2ecf20Sopenharmony_ci		break;
3818c2ecf20Sopenharmony_ci	case ICE_FLOW_FIELD_IDX_TCP_SRC_PORT:
3828c2ecf20Sopenharmony_ci	case ICE_FLOW_FIELD_IDX_TCP_DST_PORT:
3838c2ecf20Sopenharmony_ci		prot_id = ICE_PROT_TCP_IL;
3848c2ecf20Sopenharmony_ci		break;
3858c2ecf20Sopenharmony_ci	case ICE_FLOW_FIELD_IDX_UDP_SRC_PORT:
3868c2ecf20Sopenharmony_ci	case ICE_FLOW_FIELD_IDX_UDP_DST_PORT:
3878c2ecf20Sopenharmony_ci		prot_id = ICE_PROT_UDP_IL_OR_S;
3888c2ecf20Sopenharmony_ci		break;
3898c2ecf20Sopenharmony_ci	case ICE_FLOW_FIELD_IDX_SCTP_SRC_PORT:
3908c2ecf20Sopenharmony_ci	case ICE_FLOW_FIELD_IDX_SCTP_DST_PORT:
3918c2ecf20Sopenharmony_ci		prot_id = ICE_PROT_SCTP_IL;
3928c2ecf20Sopenharmony_ci		break;
3938c2ecf20Sopenharmony_ci	case ICE_FLOW_FIELD_IDX_GRE_KEYID:
3948c2ecf20Sopenharmony_ci		prot_id = ICE_PROT_GRE_OF;
3958c2ecf20Sopenharmony_ci		break;
3968c2ecf20Sopenharmony_ci	default:
3978c2ecf20Sopenharmony_ci		return ICE_ERR_NOT_IMPL;
3988c2ecf20Sopenharmony_ci	}
3998c2ecf20Sopenharmony_ci
4008c2ecf20Sopenharmony_ci	/* Each extraction sequence entry is a word in size, and extracts a
4018c2ecf20Sopenharmony_ci	 * word-aligned offset from a protocol header.
4028c2ecf20Sopenharmony_ci	 */
4038c2ecf20Sopenharmony_ci	ese_bits = ICE_FLOW_FV_EXTRACT_SZ * BITS_PER_BYTE;
4048c2ecf20Sopenharmony_ci
4058c2ecf20Sopenharmony_ci	flds[fld].xtrct.prot_id = prot_id;
4068c2ecf20Sopenharmony_ci	flds[fld].xtrct.off = (ice_flds_info[fld].off / ese_bits) *
4078c2ecf20Sopenharmony_ci		ICE_FLOW_FV_EXTRACT_SZ;
4088c2ecf20Sopenharmony_ci	flds[fld].xtrct.disp = (u8)(ice_flds_info[fld].off % ese_bits);
4098c2ecf20Sopenharmony_ci	flds[fld].xtrct.idx = params->es_cnt;
4108c2ecf20Sopenharmony_ci
4118c2ecf20Sopenharmony_ci	/* Adjust the next field-entry index after accommodating the number of
4128c2ecf20Sopenharmony_ci	 * entries this field consumes
4138c2ecf20Sopenharmony_ci	 */
4148c2ecf20Sopenharmony_ci	cnt = DIV_ROUND_UP(flds[fld].xtrct.disp + ice_flds_info[fld].size,
4158c2ecf20Sopenharmony_ci			   ese_bits);
4168c2ecf20Sopenharmony_ci
4178c2ecf20Sopenharmony_ci	/* Fill in the extraction sequence entries needed for this field */
4188c2ecf20Sopenharmony_ci	off = flds[fld].xtrct.off;
4198c2ecf20Sopenharmony_ci	for (i = 0; i < cnt; i++) {
4208c2ecf20Sopenharmony_ci		u8 idx;
4218c2ecf20Sopenharmony_ci
4228c2ecf20Sopenharmony_ci		/* Make sure the number of extraction sequence required
4238c2ecf20Sopenharmony_ci		 * does not exceed the block's capability
4248c2ecf20Sopenharmony_ci		 */
4258c2ecf20Sopenharmony_ci		if (params->es_cnt >= fv_words)
4268c2ecf20Sopenharmony_ci			return ICE_ERR_MAX_LIMIT;
4278c2ecf20Sopenharmony_ci
4288c2ecf20Sopenharmony_ci		/* some blocks require a reversed field vector layout */
4298c2ecf20Sopenharmony_ci		if (hw->blk[params->blk].es.reverse)
4308c2ecf20Sopenharmony_ci			idx = fv_words - params->es_cnt - 1;
4318c2ecf20Sopenharmony_ci		else
4328c2ecf20Sopenharmony_ci			idx = params->es_cnt;
4338c2ecf20Sopenharmony_ci
4348c2ecf20Sopenharmony_ci		params->es[idx].prot_id = prot_id;
4358c2ecf20Sopenharmony_ci		params->es[idx].off = off;
4368c2ecf20Sopenharmony_ci		params->es_cnt++;
4378c2ecf20Sopenharmony_ci
4388c2ecf20Sopenharmony_ci		off += ICE_FLOW_FV_EXTRACT_SZ;
4398c2ecf20Sopenharmony_ci	}
4408c2ecf20Sopenharmony_ci
4418c2ecf20Sopenharmony_ci	return 0;
4428c2ecf20Sopenharmony_ci}
4438c2ecf20Sopenharmony_ci
4448c2ecf20Sopenharmony_ci/**
4458c2ecf20Sopenharmony_ci * ice_flow_xtract_raws - Create extract sequence entries for raw bytes
4468c2ecf20Sopenharmony_ci * @hw: pointer to the HW struct
4478c2ecf20Sopenharmony_ci * @params: information about the flow to be processed
4488c2ecf20Sopenharmony_ci * @seg: index of packet segment whose raw fields are to be extracted
4498c2ecf20Sopenharmony_ci */
4508c2ecf20Sopenharmony_cistatic enum ice_status
4518c2ecf20Sopenharmony_ciice_flow_xtract_raws(struct ice_hw *hw, struct ice_flow_prof_params *params,
4528c2ecf20Sopenharmony_ci		     u8 seg)
4538c2ecf20Sopenharmony_ci{
4548c2ecf20Sopenharmony_ci	u16 fv_words;
4558c2ecf20Sopenharmony_ci	u16 hdrs_sz;
4568c2ecf20Sopenharmony_ci	u8 i;
4578c2ecf20Sopenharmony_ci
4588c2ecf20Sopenharmony_ci	if (!params->prof->segs[seg].raws_cnt)
4598c2ecf20Sopenharmony_ci		return 0;
4608c2ecf20Sopenharmony_ci
4618c2ecf20Sopenharmony_ci	if (params->prof->segs[seg].raws_cnt >
4628c2ecf20Sopenharmony_ci	    ARRAY_SIZE(params->prof->segs[seg].raws))
4638c2ecf20Sopenharmony_ci		return ICE_ERR_MAX_LIMIT;
4648c2ecf20Sopenharmony_ci
4658c2ecf20Sopenharmony_ci	/* Offsets within the segment headers are not supported */
4668c2ecf20Sopenharmony_ci	hdrs_sz = ice_flow_calc_seg_sz(params, seg);
4678c2ecf20Sopenharmony_ci	if (!hdrs_sz)
4688c2ecf20Sopenharmony_ci		return ICE_ERR_PARAM;
4698c2ecf20Sopenharmony_ci
4708c2ecf20Sopenharmony_ci	fv_words = hw->blk[params->blk].es.fvw;
4718c2ecf20Sopenharmony_ci
4728c2ecf20Sopenharmony_ci	for (i = 0; i < params->prof->segs[seg].raws_cnt; i++) {
4738c2ecf20Sopenharmony_ci		struct ice_flow_seg_fld_raw *raw;
4748c2ecf20Sopenharmony_ci		u16 off, cnt, j;
4758c2ecf20Sopenharmony_ci
4768c2ecf20Sopenharmony_ci		raw = &params->prof->segs[seg].raws[i];
4778c2ecf20Sopenharmony_ci
4788c2ecf20Sopenharmony_ci		/* Storing extraction information */
4798c2ecf20Sopenharmony_ci		raw->info.xtrct.prot_id = ICE_PROT_MAC_OF_OR_S;
4808c2ecf20Sopenharmony_ci		raw->info.xtrct.off = (raw->off / ICE_FLOW_FV_EXTRACT_SZ) *
4818c2ecf20Sopenharmony_ci			ICE_FLOW_FV_EXTRACT_SZ;
4828c2ecf20Sopenharmony_ci		raw->info.xtrct.disp = (raw->off % ICE_FLOW_FV_EXTRACT_SZ) *
4838c2ecf20Sopenharmony_ci			BITS_PER_BYTE;
4848c2ecf20Sopenharmony_ci		raw->info.xtrct.idx = params->es_cnt;
4858c2ecf20Sopenharmony_ci
4868c2ecf20Sopenharmony_ci		/* Determine the number of field vector entries this raw field
4878c2ecf20Sopenharmony_ci		 * consumes.
4888c2ecf20Sopenharmony_ci		 */
4898c2ecf20Sopenharmony_ci		cnt = DIV_ROUND_UP(raw->info.xtrct.disp +
4908c2ecf20Sopenharmony_ci				   (raw->info.src.last * BITS_PER_BYTE),
4918c2ecf20Sopenharmony_ci				   (ICE_FLOW_FV_EXTRACT_SZ * BITS_PER_BYTE));
4928c2ecf20Sopenharmony_ci		off = raw->info.xtrct.off;
4938c2ecf20Sopenharmony_ci		for (j = 0; j < cnt; j++) {
4948c2ecf20Sopenharmony_ci			u16 idx;
4958c2ecf20Sopenharmony_ci
4968c2ecf20Sopenharmony_ci			/* Make sure the number of extraction sequence required
4978c2ecf20Sopenharmony_ci			 * does not exceed the block's capability
4988c2ecf20Sopenharmony_ci			 */
4998c2ecf20Sopenharmony_ci			if (params->es_cnt >= hw->blk[params->blk].es.count ||
5008c2ecf20Sopenharmony_ci			    params->es_cnt >= ICE_MAX_FV_WORDS)
5018c2ecf20Sopenharmony_ci				return ICE_ERR_MAX_LIMIT;
5028c2ecf20Sopenharmony_ci
5038c2ecf20Sopenharmony_ci			/* some blocks require a reversed field vector layout */
5048c2ecf20Sopenharmony_ci			if (hw->blk[params->blk].es.reverse)
5058c2ecf20Sopenharmony_ci				idx = fv_words - params->es_cnt - 1;
5068c2ecf20Sopenharmony_ci			else
5078c2ecf20Sopenharmony_ci				idx = params->es_cnt;
5088c2ecf20Sopenharmony_ci
5098c2ecf20Sopenharmony_ci			params->es[idx].prot_id = raw->info.xtrct.prot_id;
5108c2ecf20Sopenharmony_ci			params->es[idx].off = off;
5118c2ecf20Sopenharmony_ci			params->es_cnt++;
5128c2ecf20Sopenharmony_ci			off += ICE_FLOW_FV_EXTRACT_SZ;
5138c2ecf20Sopenharmony_ci		}
5148c2ecf20Sopenharmony_ci	}
5158c2ecf20Sopenharmony_ci
5168c2ecf20Sopenharmony_ci	return 0;
5178c2ecf20Sopenharmony_ci}
5188c2ecf20Sopenharmony_ci
5198c2ecf20Sopenharmony_ci/**
5208c2ecf20Sopenharmony_ci * ice_flow_create_xtrct_seq - Create an extraction sequence for given segments
5218c2ecf20Sopenharmony_ci * @hw: pointer to the HW struct
5228c2ecf20Sopenharmony_ci * @params: information about the flow to be processed
5238c2ecf20Sopenharmony_ci *
5248c2ecf20Sopenharmony_ci * This function iterates through all matched fields in the given segments, and
5258c2ecf20Sopenharmony_ci * creates an extraction sequence for the fields.
5268c2ecf20Sopenharmony_ci */
5278c2ecf20Sopenharmony_cistatic enum ice_status
5288c2ecf20Sopenharmony_ciice_flow_create_xtrct_seq(struct ice_hw *hw,
5298c2ecf20Sopenharmony_ci			  struct ice_flow_prof_params *params)
5308c2ecf20Sopenharmony_ci{
5318c2ecf20Sopenharmony_ci	struct ice_flow_prof *prof = params->prof;
5328c2ecf20Sopenharmony_ci	enum ice_status status = 0;
5338c2ecf20Sopenharmony_ci	u8 i;
5348c2ecf20Sopenharmony_ci
5358c2ecf20Sopenharmony_ci	for (i = 0; i < prof->segs_cnt; i++) {
5368c2ecf20Sopenharmony_ci		u8 j;
5378c2ecf20Sopenharmony_ci
5388c2ecf20Sopenharmony_ci		for_each_set_bit(j, (unsigned long *)&prof->segs[i].match,
5398c2ecf20Sopenharmony_ci				 ICE_FLOW_FIELD_IDX_MAX) {
5408c2ecf20Sopenharmony_ci			status = ice_flow_xtract_fld(hw, params, i,
5418c2ecf20Sopenharmony_ci						     (enum ice_flow_field)j);
5428c2ecf20Sopenharmony_ci			if (status)
5438c2ecf20Sopenharmony_ci				return status;
5448c2ecf20Sopenharmony_ci		}
5458c2ecf20Sopenharmony_ci
5468c2ecf20Sopenharmony_ci		/* Process raw matching bytes */
5478c2ecf20Sopenharmony_ci		status = ice_flow_xtract_raws(hw, params, i);
5488c2ecf20Sopenharmony_ci		if (status)
5498c2ecf20Sopenharmony_ci			return status;
5508c2ecf20Sopenharmony_ci	}
5518c2ecf20Sopenharmony_ci
5528c2ecf20Sopenharmony_ci	return status;
5538c2ecf20Sopenharmony_ci}
5548c2ecf20Sopenharmony_ci
5558c2ecf20Sopenharmony_ci/**
5568c2ecf20Sopenharmony_ci * ice_flow_proc_segs - process all packet segments associated with a profile
5578c2ecf20Sopenharmony_ci * @hw: pointer to the HW struct
5588c2ecf20Sopenharmony_ci * @params: information about the flow to be processed
5598c2ecf20Sopenharmony_ci */
5608c2ecf20Sopenharmony_cistatic enum ice_status
5618c2ecf20Sopenharmony_ciice_flow_proc_segs(struct ice_hw *hw, struct ice_flow_prof_params *params)
5628c2ecf20Sopenharmony_ci{
5638c2ecf20Sopenharmony_ci	enum ice_status status;
5648c2ecf20Sopenharmony_ci
5658c2ecf20Sopenharmony_ci	status = ice_flow_proc_seg_hdrs(params);
5668c2ecf20Sopenharmony_ci	if (status)
5678c2ecf20Sopenharmony_ci		return status;
5688c2ecf20Sopenharmony_ci
5698c2ecf20Sopenharmony_ci	status = ice_flow_create_xtrct_seq(hw, params);
5708c2ecf20Sopenharmony_ci	if (status)
5718c2ecf20Sopenharmony_ci		return status;
5728c2ecf20Sopenharmony_ci
5738c2ecf20Sopenharmony_ci	switch (params->blk) {
5748c2ecf20Sopenharmony_ci	case ICE_BLK_FD:
5758c2ecf20Sopenharmony_ci	case ICE_BLK_RSS:
5768c2ecf20Sopenharmony_ci		status = 0;
5778c2ecf20Sopenharmony_ci		break;
5788c2ecf20Sopenharmony_ci	default:
5798c2ecf20Sopenharmony_ci		return ICE_ERR_NOT_IMPL;
5808c2ecf20Sopenharmony_ci	}
5818c2ecf20Sopenharmony_ci
5828c2ecf20Sopenharmony_ci	return status;
5838c2ecf20Sopenharmony_ci}
5848c2ecf20Sopenharmony_ci
5858c2ecf20Sopenharmony_ci#define ICE_FLOW_FIND_PROF_CHK_FLDS	0x00000001
5868c2ecf20Sopenharmony_ci#define ICE_FLOW_FIND_PROF_CHK_VSI	0x00000002
5878c2ecf20Sopenharmony_ci#define ICE_FLOW_FIND_PROF_NOT_CHK_DIR	0x00000004
5888c2ecf20Sopenharmony_ci
5898c2ecf20Sopenharmony_ci/**
5908c2ecf20Sopenharmony_ci * ice_flow_find_prof_conds - Find a profile matching headers and conditions
5918c2ecf20Sopenharmony_ci * @hw: pointer to the HW struct
5928c2ecf20Sopenharmony_ci * @blk: classification stage
5938c2ecf20Sopenharmony_ci * @dir: flow direction
5948c2ecf20Sopenharmony_ci * @segs: array of one or more packet segments that describe the flow
5958c2ecf20Sopenharmony_ci * @segs_cnt: number of packet segments provided
5968c2ecf20Sopenharmony_ci * @vsi_handle: software VSI handle to check VSI (ICE_FLOW_FIND_PROF_CHK_VSI)
5978c2ecf20Sopenharmony_ci * @conds: additional conditions to be checked (ICE_FLOW_FIND_PROF_CHK_*)
5988c2ecf20Sopenharmony_ci */
5998c2ecf20Sopenharmony_cistatic struct ice_flow_prof *
6008c2ecf20Sopenharmony_ciice_flow_find_prof_conds(struct ice_hw *hw, enum ice_block blk,
6018c2ecf20Sopenharmony_ci			 enum ice_flow_dir dir, struct ice_flow_seg_info *segs,
6028c2ecf20Sopenharmony_ci			 u8 segs_cnt, u16 vsi_handle, u32 conds)
6038c2ecf20Sopenharmony_ci{
6048c2ecf20Sopenharmony_ci	struct ice_flow_prof *p, *prof = NULL;
6058c2ecf20Sopenharmony_ci
6068c2ecf20Sopenharmony_ci	mutex_lock(&hw->fl_profs_locks[blk]);
6078c2ecf20Sopenharmony_ci	list_for_each_entry(p, &hw->fl_profs[blk], l_entry)
6088c2ecf20Sopenharmony_ci		if ((p->dir == dir || conds & ICE_FLOW_FIND_PROF_NOT_CHK_DIR) &&
6098c2ecf20Sopenharmony_ci		    segs_cnt && segs_cnt == p->segs_cnt) {
6108c2ecf20Sopenharmony_ci			u8 i;
6118c2ecf20Sopenharmony_ci
6128c2ecf20Sopenharmony_ci			/* Check for profile-VSI association if specified */
6138c2ecf20Sopenharmony_ci			if ((conds & ICE_FLOW_FIND_PROF_CHK_VSI) &&
6148c2ecf20Sopenharmony_ci			    ice_is_vsi_valid(hw, vsi_handle) &&
6158c2ecf20Sopenharmony_ci			    !test_bit(vsi_handle, p->vsis))
6168c2ecf20Sopenharmony_ci				continue;
6178c2ecf20Sopenharmony_ci
6188c2ecf20Sopenharmony_ci			/* Protocol headers must be checked. Matched fields are
6198c2ecf20Sopenharmony_ci			 * checked if specified.
6208c2ecf20Sopenharmony_ci			 */
6218c2ecf20Sopenharmony_ci			for (i = 0; i < segs_cnt; i++)
6228c2ecf20Sopenharmony_ci				if (segs[i].hdrs != p->segs[i].hdrs ||
6238c2ecf20Sopenharmony_ci				    ((conds & ICE_FLOW_FIND_PROF_CHK_FLDS) &&
6248c2ecf20Sopenharmony_ci				     segs[i].match != p->segs[i].match))
6258c2ecf20Sopenharmony_ci					break;
6268c2ecf20Sopenharmony_ci
6278c2ecf20Sopenharmony_ci			/* A match is found if all segments are matched */
6288c2ecf20Sopenharmony_ci			if (i == segs_cnt) {
6298c2ecf20Sopenharmony_ci				prof = p;
6308c2ecf20Sopenharmony_ci				break;
6318c2ecf20Sopenharmony_ci			}
6328c2ecf20Sopenharmony_ci		}
6338c2ecf20Sopenharmony_ci	mutex_unlock(&hw->fl_profs_locks[blk]);
6348c2ecf20Sopenharmony_ci
6358c2ecf20Sopenharmony_ci	return prof;
6368c2ecf20Sopenharmony_ci}
6378c2ecf20Sopenharmony_ci
6388c2ecf20Sopenharmony_ci/**
6398c2ecf20Sopenharmony_ci * ice_flow_find_prof_id - Look up a profile with given profile ID
6408c2ecf20Sopenharmony_ci * @hw: pointer to the HW struct
6418c2ecf20Sopenharmony_ci * @blk: classification stage
6428c2ecf20Sopenharmony_ci * @prof_id: unique ID to identify this flow profile
6438c2ecf20Sopenharmony_ci */
6448c2ecf20Sopenharmony_cistatic struct ice_flow_prof *
6458c2ecf20Sopenharmony_ciice_flow_find_prof_id(struct ice_hw *hw, enum ice_block blk, u64 prof_id)
6468c2ecf20Sopenharmony_ci{
6478c2ecf20Sopenharmony_ci	struct ice_flow_prof *p;
6488c2ecf20Sopenharmony_ci
6498c2ecf20Sopenharmony_ci	list_for_each_entry(p, &hw->fl_profs[blk], l_entry)
6508c2ecf20Sopenharmony_ci		if (p->id == prof_id)
6518c2ecf20Sopenharmony_ci			return p;
6528c2ecf20Sopenharmony_ci
6538c2ecf20Sopenharmony_ci	return NULL;
6548c2ecf20Sopenharmony_ci}
6558c2ecf20Sopenharmony_ci
6568c2ecf20Sopenharmony_ci/**
6578c2ecf20Sopenharmony_ci * ice_dealloc_flow_entry - Deallocate flow entry memory
6588c2ecf20Sopenharmony_ci * @hw: pointer to the HW struct
6598c2ecf20Sopenharmony_ci * @entry: flow entry to be removed
6608c2ecf20Sopenharmony_ci */
6618c2ecf20Sopenharmony_cistatic void
6628c2ecf20Sopenharmony_ciice_dealloc_flow_entry(struct ice_hw *hw, struct ice_flow_entry *entry)
6638c2ecf20Sopenharmony_ci{
6648c2ecf20Sopenharmony_ci	if (!entry)
6658c2ecf20Sopenharmony_ci		return;
6668c2ecf20Sopenharmony_ci
6678c2ecf20Sopenharmony_ci	if (entry->entry)
6688c2ecf20Sopenharmony_ci		devm_kfree(ice_hw_to_dev(hw), entry->entry);
6698c2ecf20Sopenharmony_ci
6708c2ecf20Sopenharmony_ci	devm_kfree(ice_hw_to_dev(hw), entry);
6718c2ecf20Sopenharmony_ci}
6728c2ecf20Sopenharmony_ci
6738c2ecf20Sopenharmony_ci/**
6748c2ecf20Sopenharmony_ci * ice_flow_rem_entry_sync - Remove a flow entry
6758c2ecf20Sopenharmony_ci * @hw: pointer to the HW struct
6768c2ecf20Sopenharmony_ci * @blk: classification stage
6778c2ecf20Sopenharmony_ci * @entry: flow entry to be removed
6788c2ecf20Sopenharmony_ci */
6798c2ecf20Sopenharmony_cistatic enum ice_status
6808c2ecf20Sopenharmony_ciice_flow_rem_entry_sync(struct ice_hw *hw, enum ice_block __always_unused blk,
6818c2ecf20Sopenharmony_ci			struct ice_flow_entry *entry)
6828c2ecf20Sopenharmony_ci{
6838c2ecf20Sopenharmony_ci	if (!entry)
6848c2ecf20Sopenharmony_ci		return ICE_ERR_BAD_PTR;
6858c2ecf20Sopenharmony_ci
6868c2ecf20Sopenharmony_ci	list_del(&entry->l_entry);
6878c2ecf20Sopenharmony_ci
6888c2ecf20Sopenharmony_ci	ice_dealloc_flow_entry(hw, entry);
6898c2ecf20Sopenharmony_ci
6908c2ecf20Sopenharmony_ci	return 0;
6918c2ecf20Sopenharmony_ci}
6928c2ecf20Sopenharmony_ci
6938c2ecf20Sopenharmony_ci/**
6948c2ecf20Sopenharmony_ci * ice_flow_add_prof_sync - Add a flow profile for packet segments and fields
6958c2ecf20Sopenharmony_ci * @hw: pointer to the HW struct
6968c2ecf20Sopenharmony_ci * @blk: classification stage
6978c2ecf20Sopenharmony_ci * @dir: flow direction
6988c2ecf20Sopenharmony_ci * @prof_id: unique ID to identify this flow profile
6998c2ecf20Sopenharmony_ci * @segs: array of one or more packet segments that describe the flow
7008c2ecf20Sopenharmony_ci * @segs_cnt: number of packet segments provided
7018c2ecf20Sopenharmony_ci * @prof: stores the returned flow profile added
7028c2ecf20Sopenharmony_ci *
7038c2ecf20Sopenharmony_ci * Assumption: the caller has acquired the lock to the profile list
7048c2ecf20Sopenharmony_ci */
7058c2ecf20Sopenharmony_cistatic enum ice_status
7068c2ecf20Sopenharmony_ciice_flow_add_prof_sync(struct ice_hw *hw, enum ice_block blk,
7078c2ecf20Sopenharmony_ci		       enum ice_flow_dir dir, u64 prof_id,
7088c2ecf20Sopenharmony_ci		       struct ice_flow_seg_info *segs, u8 segs_cnt,
7098c2ecf20Sopenharmony_ci		       struct ice_flow_prof **prof)
7108c2ecf20Sopenharmony_ci{
7118c2ecf20Sopenharmony_ci	struct ice_flow_prof_params params;
7128c2ecf20Sopenharmony_ci	enum ice_status status;
7138c2ecf20Sopenharmony_ci	u8 i;
7148c2ecf20Sopenharmony_ci
7158c2ecf20Sopenharmony_ci	if (!prof)
7168c2ecf20Sopenharmony_ci		return ICE_ERR_BAD_PTR;
7178c2ecf20Sopenharmony_ci
7188c2ecf20Sopenharmony_ci	memset(&params, 0, sizeof(params));
7198c2ecf20Sopenharmony_ci	params.prof = devm_kzalloc(ice_hw_to_dev(hw), sizeof(*params.prof),
7208c2ecf20Sopenharmony_ci				   GFP_KERNEL);
7218c2ecf20Sopenharmony_ci	if (!params.prof)
7228c2ecf20Sopenharmony_ci		return ICE_ERR_NO_MEMORY;
7238c2ecf20Sopenharmony_ci
7248c2ecf20Sopenharmony_ci	/* initialize extraction sequence to all invalid (0xff) */
7258c2ecf20Sopenharmony_ci	for (i = 0; i < ICE_MAX_FV_WORDS; i++) {
7268c2ecf20Sopenharmony_ci		params.es[i].prot_id = ICE_PROT_INVALID;
7278c2ecf20Sopenharmony_ci		params.es[i].off = ICE_FV_OFFSET_INVAL;
7288c2ecf20Sopenharmony_ci	}
7298c2ecf20Sopenharmony_ci
7308c2ecf20Sopenharmony_ci	params.blk = blk;
7318c2ecf20Sopenharmony_ci	params.prof->id = prof_id;
7328c2ecf20Sopenharmony_ci	params.prof->dir = dir;
7338c2ecf20Sopenharmony_ci	params.prof->segs_cnt = segs_cnt;
7348c2ecf20Sopenharmony_ci
7358c2ecf20Sopenharmony_ci	/* Make a copy of the segments that need to be persistent in the flow
7368c2ecf20Sopenharmony_ci	 * profile instance
7378c2ecf20Sopenharmony_ci	 */
7388c2ecf20Sopenharmony_ci	for (i = 0; i < segs_cnt; i++)
7398c2ecf20Sopenharmony_ci		memcpy(&params.prof->segs[i], &segs[i], sizeof(*segs));
7408c2ecf20Sopenharmony_ci
7418c2ecf20Sopenharmony_ci	status = ice_flow_proc_segs(hw, &params);
7428c2ecf20Sopenharmony_ci	if (status) {
7438c2ecf20Sopenharmony_ci		ice_debug(hw, ICE_DBG_FLOW,
7448c2ecf20Sopenharmony_ci			  "Error processing a flow's packet segments\n");
7458c2ecf20Sopenharmony_ci		goto out;
7468c2ecf20Sopenharmony_ci	}
7478c2ecf20Sopenharmony_ci
7488c2ecf20Sopenharmony_ci	/* Add a HW profile for this flow profile */
7498c2ecf20Sopenharmony_ci	status = ice_add_prof(hw, blk, prof_id, (u8 *)params.ptypes, params.es);
7508c2ecf20Sopenharmony_ci	if (status) {
7518c2ecf20Sopenharmony_ci		ice_debug(hw, ICE_DBG_FLOW, "Error adding a HW flow profile\n");
7528c2ecf20Sopenharmony_ci		goto out;
7538c2ecf20Sopenharmony_ci	}
7548c2ecf20Sopenharmony_ci
7558c2ecf20Sopenharmony_ci	INIT_LIST_HEAD(&params.prof->entries);
7568c2ecf20Sopenharmony_ci	mutex_init(&params.prof->entries_lock);
7578c2ecf20Sopenharmony_ci	*prof = params.prof;
7588c2ecf20Sopenharmony_ci
7598c2ecf20Sopenharmony_ciout:
7608c2ecf20Sopenharmony_ci	if (status)
7618c2ecf20Sopenharmony_ci		devm_kfree(ice_hw_to_dev(hw), params.prof);
7628c2ecf20Sopenharmony_ci
7638c2ecf20Sopenharmony_ci	return status;
7648c2ecf20Sopenharmony_ci}
7658c2ecf20Sopenharmony_ci
7668c2ecf20Sopenharmony_ci/**
7678c2ecf20Sopenharmony_ci * ice_flow_rem_prof_sync - remove a flow profile
7688c2ecf20Sopenharmony_ci * @hw: pointer to the hardware structure
7698c2ecf20Sopenharmony_ci * @blk: classification stage
7708c2ecf20Sopenharmony_ci * @prof: pointer to flow profile to remove
7718c2ecf20Sopenharmony_ci *
7728c2ecf20Sopenharmony_ci * Assumption: the caller has acquired the lock to the profile list
7738c2ecf20Sopenharmony_ci */
7748c2ecf20Sopenharmony_cistatic enum ice_status
7758c2ecf20Sopenharmony_ciice_flow_rem_prof_sync(struct ice_hw *hw, enum ice_block blk,
7768c2ecf20Sopenharmony_ci		       struct ice_flow_prof *prof)
7778c2ecf20Sopenharmony_ci{
7788c2ecf20Sopenharmony_ci	enum ice_status status;
7798c2ecf20Sopenharmony_ci
7808c2ecf20Sopenharmony_ci	/* Remove all remaining flow entries before removing the flow profile */
7818c2ecf20Sopenharmony_ci	if (!list_empty(&prof->entries)) {
7828c2ecf20Sopenharmony_ci		struct ice_flow_entry *e, *t;
7838c2ecf20Sopenharmony_ci
7848c2ecf20Sopenharmony_ci		mutex_lock(&prof->entries_lock);
7858c2ecf20Sopenharmony_ci
7868c2ecf20Sopenharmony_ci		list_for_each_entry_safe(e, t, &prof->entries, l_entry) {
7878c2ecf20Sopenharmony_ci			status = ice_flow_rem_entry_sync(hw, blk, e);
7888c2ecf20Sopenharmony_ci			if (status)
7898c2ecf20Sopenharmony_ci				break;
7908c2ecf20Sopenharmony_ci		}
7918c2ecf20Sopenharmony_ci
7928c2ecf20Sopenharmony_ci		mutex_unlock(&prof->entries_lock);
7938c2ecf20Sopenharmony_ci	}
7948c2ecf20Sopenharmony_ci
7958c2ecf20Sopenharmony_ci	/* Remove all hardware profiles associated with this flow profile */
7968c2ecf20Sopenharmony_ci	status = ice_rem_prof(hw, blk, prof->id);
7978c2ecf20Sopenharmony_ci	if (!status) {
7988c2ecf20Sopenharmony_ci		list_del(&prof->l_entry);
7998c2ecf20Sopenharmony_ci		mutex_destroy(&prof->entries_lock);
8008c2ecf20Sopenharmony_ci		devm_kfree(ice_hw_to_dev(hw), prof);
8018c2ecf20Sopenharmony_ci	}
8028c2ecf20Sopenharmony_ci
8038c2ecf20Sopenharmony_ci	return status;
8048c2ecf20Sopenharmony_ci}
8058c2ecf20Sopenharmony_ci
8068c2ecf20Sopenharmony_ci/**
8078c2ecf20Sopenharmony_ci * ice_flow_assoc_prof - associate a VSI with a flow profile
8088c2ecf20Sopenharmony_ci * @hw: pointer to the hardware structure
8098c2ecf20Sopenharmony_ci * @blk: classification stage
8108c2ecf20Sopenharmony_ci * @prof: pointer to flow profile
8118c2ecf20Sopenharmony_ci * @vsi_handle: software VSI handle
8128c2ecf20Sopenharmony_ci *
8138c2ecf20Sopenharmony_ci * Assumption: the caller has acquired the lock to the profile list
8148c2ecf20Sopenharmony_ci * and the software VSI handle has been validated
8158c2ecf20Sopenharmony_ci */
8168c2ecf20Sopenharmony_cistatic enum ice_status
8178c2ecf20Sopenharmony_ciice_flow_assoc_prof(struct ice_hw *hw, enum ice_block blk,
8188c2ecf20Sopenharmony_ci		    struct ice_flow_prof *prof, u16 vsi_handle)
8198c2ecf20Sopenharmony_ci{
8208c2ecf20Sopenharmony_ci	enum ice_status status = 0;
8218c2ecf20Sopenharmony_ci
8228c2ecf20Sopenharmony_ci	if (!test_bit(vsi_handle, prof->vsis)) {
8238c2ecf20Sopenharmony_ci		status = ice_add_prof_id_flow(hw, blk,
8248c2ecf20Sopenharmony_ci					      ice_get_hw_vsi_num(hw,
8258c2ecf20Sopenharmony_ci								 vsi_handle),
8268c2ecf20Sopenharmony_ci					      prof->id);
8278c2ecf20Sopenharmony_ci		if (!status)
8288c2ecf20Sopenharmony_ci			set_bit(vsi_handle, prof->vsis);
8298c2ecf20Sopenharmony_ci		else
8308c2ecf20Sopenharmony_ci			ice_debug(hw, ICE_DBG_FLOW,
8318c2ecf20Sopenharmony_ci				  "HW profile add failed, %d\n",
8328c2ecf20Sopenharmony_ci				  status);
8338c2ecf20Sopenharmony_ci	}
8348c2ecf20Sopenharmony_ci
8358c2ecf20Sopenharmony_ci	return status;
8368c2ecf20Sopenharmony_ci}
8378c2ecf20Sopenharmony_ci
8388c2ecf20Sopenharmony_ci/**
8398c2ecf20Sopenharmony_ci * ice_flow_disassoc_prof - disassociate a VSI from a flow profile
8408c2ecf20Sopenharmony_ci * @hw: pointer to the hardware structure
8418c2ecf20Sopenharmony_ci * @blk: classification stage
8428c2ecf20Sopenharmony_ci * @prof: pointer to flow profile
8438c2ecf20Sopenharmony_ci * @vsi_handle: software VSI handle
8448c2ecf20Sopenharmony_ci *
8458c2ecf20Sopenharmony_ci * Assumption: the caller has acquired the lock to the profile list
8468c2ecf20Sopenharmony_ci * and the software VSI handle has been validated
8478c2ecf20Sopenharmony_ci */
8488c2ecf20Sopenharmony_cistatic enum ice_status
8498c2ecf20Sopenharmony_ciice_flow_disassoc_prof(struct ice_hw *hw, enum ice_block blk,
8508c2ecf20Sopenharmony_ci		       struct ice_flow_prof *prof, u16 vsi_handle)
8518c2ecf20Sopenharmony_ci{
8528c2ecf20Sopenharmony_ci	enum ice_status status = 0;
8538c2ecf20Sopenharmony_ci
8548c2ecf20Sopenharmony_ci	if (test_bit(vsi_handle, prof->vsis)) {
8558c2ecf20Sopenharmony_ci		status = ice_rem_prof_id_flow(hw, blk,
8568c2ecf20Sopenharmony_ci					      ice_get_hw_vsi_num(hw,
8578c2ecf20Sopenharmony_ci								 vsi_handle),
8588c2ecf20Sopenharmony_ci					      prof->id);
8598c2ecf20Sopenharmony_ci		if (!status)
8608c2ecf20Sopenharmony_ci			clear_bit(vsi_handle, prof->vsis);
8618c2ecf20Sopenharmony_ci		else
8628c2ecf20Sopenharmony_ci			ice_debug(hw, ICE_DBG_FLOW,
8638c2ecf20Sopenharmony_ci				  "HW profile remove failed, %d\n",
8648c2ecf20Sopenharmony_ci				  status);
8658c2ecf20Sopenharmony_ci	}
8668c2ecf20Sopenharmony_ci
8678c2ecf20Sopenharmony_ci	return status;
8688c2ecf20Sopenharmony_ci}
8698c2ecf20Sopenharmony_ci
8708c2ecf20Sopenharmony_ci/**
8718c2ecf20Sopenharmony_ci * ice_flow_add_prof - Add a flow profile for packet segments and matched fields
8728c2ecf20Sopenharmony_ci * @hw: pointer to the HW struct
8738c2ecf20Sopenharmony_ci * @blk: classification stage
8748c2ecf20Sopenharmony_ci * @dir: flow direction
8758c2ecf20Sopenharmony_ci * @prof_id: unique ID to identify this flow profile
8768c2ecf20Sopenharmony_ci * @segs: array of one or more packet segments that describe the flow
8778c2ecf20Sopenharmony_ci * @segs_cnt: number of packet segments provided
8788c2ecf20Sopenharmony_ci * @prof: stores the returned flow profile added
8798c2ecf20Sopenharmony_ci */
8808c2ecf20Sopenharmony_cienum ice_status
8818c2ecf20Sopenharmony_ciice_flow_add_prof(struct ice_hw *hw, enum ice_block blk, enum ice_flow_dir dir,
8828c2ecf20Sopenharmony_ci		  u64 prof_id, struct ice_flow_seg_info *segs, u8 segs_cnt,
8838c2ecf20Sopenharmony_ci		  struct ice_flow_prof **prof)
8848c2ecf20Sopenharmony_ci{
8858c2ecf20Sopenharmony_ci	enum ice_status status;
8868c2ecf20Sopenharmony_ci
8878c2ecf20Sopenharmony_ci	if (segs_cnt > ICE_FLOW_SEG_MAX)
8888c2ecf20Sopenharmony_ci		return ICE_ERR_MAX_LIMIT;
8898c2ecf20Sopenharmony_ci
8908c2ecf20Sopenharmony_ci	if (!segs_cnt)
8918c2ecf20Sopenharmony_ci		return ICE_ERR_PARAM;
8928c2ecf20Sopenharmony_ci
8938c2ecf20Sopenharmony_ci	if (!segs)
8948c2ecf20Sopenharmony_ci		return ICE_ERR_BAD_PTR;
8958c2ecf20Sopenharmony_ci
8968c2ecf20Sopenharmony_ci	status = ice_flow_val_hdrs(segs, segs_cnt);
8978c2ecf20Sopenharmony_ci	if (status)
8988c2ecf20Sopenharmony_ci		return status;
8998c2ecf20Sopenharmony_ci
9008c2ecf20Sopenharmony_ci	mutex_lock(&hw->fl_profs_locks[blk]);
9018c2ecf20Sopenharmony_ci
9028c2ecf20Sopenharmony_ci	status = ice_flow_add_prof_sync(hw, blk, dir, prof_id, segs, segs_cnt,
9038c2ecf20Sopenharmony_ci					prof);
9048c2ecf20Sopenharmony_ci	if (!status)
9058c2ecf20Sopenharmony_ci		list_add(&(*prof)->l_entry, &hw->fl_profs[blk]);
9068c2ecf20Sopenharmony_ci
9078c2ecf20Sopenharmony_ci	mutex_unlock(&hw->fl_profs_locks[blk]);
9088c2ecf20Sopenharmony_ci
9098c2ecf20Sopenharmony_ci	return status;
9108c2ecf20Sopenharmony_ci}
9118c2ecf20Sopenharmony_ci
9128c2ecf20Sopenharmony_ci/**
9138c2ecf20Sopenharmony_ci * ice_flow_rem_prof - Remove a flow profile and all entries associated with it
9148c2ecf20Sopenharmony_ci * @hw: pointer to the HW struct
9158c2ecf20Sopenharmony_ci * @blk: the block for which the flow profile is to be removed
9168c2ecf20Sopenharmony_ci * @prof_id: unique ID of the flow profile to be removed
9178c2ecf20Sopenharmony_ci */
9188c2ecf20Sopenharmony_cienum ice_status
9198c2ecf20Sopenharmony_ciice_flow_rem_prof(struct ice_hw *hw, enum ice_block blk, u64 prof_id)
9208c2ecf20Sopenharmony_ci{
9218c2ecf20Sopenharmony_ci	struct ice_flow_prof *prof;
9228c2ecf20Sopenharmony_ci	enum ice_status status;
9238c2ecf20Sopenharmony_ci
9248c2ecf20Sopenharmony_ci	mutex_lock(&hw->fl_profs_locks[blk]);
9258c2ecf20Sopenharmony_ci
9268c2ecf20Sopenharmony_ci	prof = ice_flow_find_prof_id(hw, blk, prof_id);
9278c2ecf20Sopenharmony_ci	if (!prof) {
9288c2ecf20Sopenharmony_ci		status = ICE_ERR_DOES_NOT_EXIST;
9298c2ecf20Sopenharmony_ci		goto out;
9308c2ecf20Sopenharmony_ci	}
9318c2ecf20Sopenharmony_ci
9328c2ecf20Sopenharmony_ci	/* prof becomes invalid after the call */
9338c2ecf20Sopenharmony_ci	status = ice_flow_rem_prof_sync(hw, blk, prof);
9348c2ecf20Sopenharmony_ci
9358c2ecf20Sopenharmony_ciout:
9368c2ecf20Sopenharmony_ci	mutex_unlock(&hw->fl_profs_locks[blk]);
9378c2ecf20Sopenharmony_ci
9388c2ecf20Sopenharmony_ci	return status;
9398c2ecf20Sopenharmony_ci}
9408c2ecf20Sopenharmony_ci
9418c2ecf20Sopenharmony_ci/**
9428c2ecf20Sopenharmony_ci * ice_flow_add_entry - Add a flow entry
9438c2ecf20Sopenharmony_ci * @hw: pointer to the HW struct
9448c2ecf20Sopenharmony_ci * @blk: classification stage
9458c2ecf20Sopenharmony_ci * @prof_id: ID of the profile to add a new flow entry to
9468c2ecf20Sopenharmony_ci * @entry_id: unique ID to identify this flow entry
9478c2ecf20Sopenharmony_ci * @vsi_handle: software VSI handle for the flow entry
9488c2ecf20Sopenharmony_ci * @prio: priority of the flow entry
9498c2ecf20Sopenharmony_ci * @data: pointer to a data buffer containing flow entry's match values/masks
9508c2ecf20Sopenharmony_ci * @entry_h: pointer to buffer that receives the new flow entry's handle
9518c2ecf20Sopenharmony_ci */
9528c2ecf20Sopenharmony_cienum ice_status
9538c2ecf20Sopenharmony_ciice_flow_add_entry(struct ice_hw *hw, enum ice_block blk, u64 prof_id,
9548c2ecf20Sopenharmony_ci		   u64 entry_id, u16 vsi_handle, enum ice_flow_priority prio,
9558c2ecf20Sopenharmony_ci		   void *data, u64 *entry_h)
9568c2ecf20Sopenharmony_ci{
9578c2ecf20Sopenharmony_ci	struct ice_flow_entry *e = NULL;
9588c2ecf20Sopenharmony_ci	struct ice_flow_prof *prof;
9598c2ecf20Sopenharmony_ci	enum ice_status status;
9608c2ecf20Sopenharmony_ci
9618c2ecf20Sopenharmony_ci	/* No flow entry data is expected for RSS */
9628c2ecf20Sopenharmony_ci	if (!entry_h || (!data && blk != ICE_BLK_RSS))
9638c2ecf20Sopenharmony_ci		return ICE_ERR_BAD_PTR;
9648c2ecf20Sopenharmony_ci
9658c2ecf20Sopenharmony_ci	if (!ice_is_vsi_valid(hw, vsi_handle))
9668c2ecf20Sopenharmony_ci		return ICE_ERR_PARAM;
9678c2ecf20Sopenharmony_ci
9688c2ecf20Sopenharmony_ci	mutex_lock(&hw->fl_profs_locks[blk]);
9698c2ecf20Sopenharmony_ci
9708c2ecf20Sopenharmony_ci	prof = ice_flow_find_prof_id(hw, blk, prof_id);
9718c2ecf20Sopenharmony_ci	if (!prof) {
9728c2ecf20Sopenharmony_ci		status = ICE_ERR_DOES_NOT_EXIST;
9738c2ecf20Sopenharmony_ci	} else {
9748c2ecf20Sopenharmony_ci		/* Allocate memory for the entry being added and associate
9758c2ecf20Sopenharmony_ci		 * the VSI to the found flow profile
9768c2ecf20Sopenharmony_ci		 */
9778c2ecf20Sopenharmony_ci		e = devm_kzalloc(ice_hw_to_dev(hw), sizeof(*e), GFP_KERNEL);
9788c2ecf20Sopenharmony_ci		if (!e)
9798c2ecf20Sopenharmony_ci			status = ICE_ERR_NO_MEMORY;
9808c2ecf20Sopenharmony_ci		else
9818c2ecf20Sopenharmony_ci			status = ice_flow_assoc_prof(hw, blk, prof, vsi_handle);
9828c2ecf20Sopenharmony_ci	}
9838c2ecf20Sopenharmony_ci
9848c2ecf20Sopenharmony_ci	mutex_unlock(&hw->fl_profs_locks[blk]);
9858c2ecf20Sopenharmony_ci	if (status)
9868c2ecf20Sopenharmony_ci		goto out;
9878c2ecf20Sopenharmony_ci
9888c2ecf20Sopenharmony_ci	e->id = entry_id;
9898c2ecf20Sopenharmony_ci	e->vsi_handle = vsi_handle;
9908c2ecf20Sopenharmony_ci	e->prof = prof;
9918c2ecf20Sopenharmony_ci	e->priority = prio;
9928c2ecf20Sopenharmony_ci
9938c2ecf20Sopenharmony_ci	switch (blk) {
9948c2ecf20Sopenharmony_ci	case ICE_BLK_FD:
9958c2ecf20Sopenharmony_ci	case ICE_BLK_RSS:
9968c2ecf20Sopenharmony_ci		break;
9978c2ecf20Sopenharmony_ci	default:
9988c2ecf20Sopenharmony_ci		status = ICE_ERR_NOT_IMPL;
9998c2ecf20Sopenharmony_ci		goto out;
10008c2ecf20Sopenharmony_ci	}
10018c2ecf20Sopenharmony_ci
10028c2ecf20Sopenharmony_ci	mutex_lock(&prof->entries_lock);
10038c2ecf20Sopenharmony_ci	list_add(&e->l_entry, &prof->entries);
10048c2ecf20Sopenharmony_ci	mutex_unlock(&prof->entries_lock);
10058c2ecf20Sopenharmony_ci
10068c2ecf20Sopenharmony_ci	*entry_h = ICE_FLOW_ENTRY_HNDL(e);
10078c2ecf20Sopenharmony_ci
10088c2ecf20Sopenharmony_ciout:
10098c2ecf20Sopenharmony_ci	if (status && e) {
10108c2ecf20Sopenharmony_ci		if (e->entry)
10118c2ecf20Sopenharmony_ci			devm_kfree(ice_hw_to_dev(hw), e->entry);
10128c2ecf20Sopenharmony_ci		devm_kfree(ice_hw_to_dev(hw), e);
10138c2ecf20Sopenharmony_ci	}
10148c2ecf20Sopenharmony_ci
10158c2ecf20Sopenharmony_ci	return status;
10168c2ecf20Sopenharmony_ci}
10178c2ecf20Sopenharmony_ci
10188c2ecf20Sopenharmony_ci/**
10198c2ecf20Sopenharmony_ci * ice_flow_rem_entry - Remove a flow entry
10208c2ecf20Sopenharmony_ci * @hw: pointer to the HW struct
10218c2ecf20Sopenharmony_ci * @blk: classification stage
10228c2ecf20Sopenharmony_ci * @entry_h: handle to the flow entry to be removed
10238c2ecf20Sopenharmony_ci */
10248c2ecf20Sopenharmony_cienum ice_status ice_flow_rem_entry(struct ice_hw *hw, enum ice_block blk,
10258c2ecf20Sopenharmony_ci				   u64 entry_h)
10268c2ecf20Sopenharmony_ci{
10278c2ecf20Sopenharmony_ci	struct ice_flow_entry *entry;
10288c2ecf20Sopenharmony_ci	struct ice_flow_prof *prof;
10298c2ecf20Sopenharmony_ci	enum ice_status status = 0;
10308c2ecf20Sopenharmony_ci
10318c2ecf20Sopenharmony_ci	if (entry_h == ICE_FLOW_ENTRY_HANDLE_INVAL)
10328c2ecf20Sopenharmony_ci		return ICE_ERR_PARAM;
10338c2ecf20Sopenharmony_ci
10348c2ecf20Sopenharmony_ci	entry = ICE_FLOW_ENTRY_PTR(entry_h);
10358c2ecf20Sopenharmony_ci
10368c2ecf20Sopenharmony_ci	/* Retain the pointer to the flow profile as the entry will be freed */
10378c2ecf20Sopenharmony_ci	prof = entry->prof;
10388c2ecf20Sopenharmony_ci
10398c2ecf20Sopenharmony_ci	if (prof) {
10408c2ecf20Sopenharmony_ci		mutex_lock(&prof->entries_lock);
10418c2ecf20Sopenharmony_ci		status = ice_flow_rem_entry_sync(hw, blk, entry);
10428c2ecf20Sopenharmony_ci		mutex_unlock(&prof->entries_lock);
10438c2ecf20Sopenharmony_ci	}
10448c2ecf20Sopenharmony_ci
10458c2ecf20Sopenharmony_ci	return status;
10468c2ecf20Sopenharmony_ci}
10478c2ecf20Sopenharmony_ci
10488c2ecf20Sopenharmony_ci/**
10498c2ecf20Sopenharmony_ci * ice_flow_set_fld_ext - specifies locations of field from entry's input buffer
10508c2ecf20Sopenharmony_ci * @seg: packet segment the field being set belongs to
10518c2ecf20Sopenharmony_ci * @fld: field to be set
10528c2ecf20Sopenharmony_ci * @field_type: type of the field
10538c2ecf20Sopenharmony_ci * @val_loc: if not ICE_FLOW_FLD_OFF_INVAL, location of the value to match from
10548c2ecf20Sopenharmony_ci *           entry's input buffer
10558c2ecf20Sopenharmony_ci * @mask_loc: if not ICE_FLOW_FLD_OFF_INVAL, location of mask value from entry's
10568c2ecf20Sopenharmony_ci *            input buffer
10578c2ecf20Sopenharmony_ci * @last_loc: if not ICE_FLOW_FLD_OFF_INVAL, location of last/upper value from
10588c2ecf20Sopenharmony_ci *            entry's input buffer
10598c2ecf20Sopenharmony_ci *
10608c2ecf20Sopenharmony_ci * This helper function stores information of a field being matched, including
10618c2ecf20Sopenharmony_ci * the type of the field and the locations of the value to match, the mask, and
10628c2ecf20Sopenharmony_ci * the upper-bound value in the start of the input buffer for a flow entry.
10638c2ecf20Sopenharmony_ci * This function should only be used for fixed-size data structures.
10648c2ecf20Sopenharmony_ci *
10658c2ecf20Sopenharmony_ci * This function also opportunistically determines the protocol headers to be
10668c2ecf20Sopenharmony_ci * present based on the fields being set. Some fields cannot be used alone to
10678c2ecf20Sopenharmony_ci * determine the protocol headers present. Sometimes, fields for particular
10688c2ecf20Sopenharmony_ci * protocol headers are not matched. In those cases, the protocol headers
10698c2ecf20Sopenharmony_ci * must be explicitly set.
10708c2ecf20Sopenharmony_ci */
10718c2ecf20Sopenharmony_cistatic void
10728c2ecf20Sopenharmony_ciice_flow_set_fld_ext(struct ice_flow_seg_info *seg, enum ice_flow_field fld,
10738c2ecf20Sopenharmony_ci		     enum ice_flow_fld_match_type field_type, u16 val_loc,
10748c2ecf20Sopenharmony_ci		     u16 mask_loc, u16 last_loc)
10758c2ecf20Sopenharmony_ci{
10768c2ecf20Sopenharmony_ci	u64 bit = BIT_ULL(fld);
10778c2ecf20Sopenharmony_ci
10788c2ecf20Sopenharmony_ci	seg->match |= bit;
10798c2ecf20Sopenharmony_ci	if (field_type == ICE_FLOW_FLD_TYPE_RANGE)
10808c2ecf20Sopenharmony_ci		seg->range |= bit;
10818c2ecf20Sopenharmony_ci
10828c2ecf20Sopenharmony_ci	seg->fields[fld].type = field_type;
10838c2ecf20Sopenharmony_ci	seg->fields[fld].src.val = val_loc;
10848c2ecf20Sopenharmony_ci	seg->fields[fld].src.mask = mask_loc;
10858c2ecf20Sopenharmony_ci	seg->fields[fld].src.last = last_loc;
10868c2ecf20Sopenharmony_ci
10878c2ecf20Sopenharmony_ci	ICE_FLOW_SET_HDRS(seg, ice_flds_info[fld].hdr);
10888c2ecf20Sopenharmony_ci}
10898c2ecf20Sopenharmony_ci
10908c2ecf20Sopenharmony_ci/**
10918c2ecf20Sopenharmony_ci * ice_flow_set_fld - specifies locations of field from entry's input buffer
10928c2ecf20Sopenharmony_ci * @seg: packet segment the field being set belongs to
10938c2ecf20Sopenharmony_ci * @fld: field to be set
10948c2ecf20Sopenharmony_ci * @val_loc: if not ICE_FLOW_FLD_OFF_INVAL, location of the value to match from
10958c2ecf20Sopenharmony_ci *           entry's input buffer
10968c2ecf20Sopenharmony_ci * @mask_loc: if not ICE_FLOW_FLD_OFF_INVAL, location of mask value from entry's
10978c2ecf20Sopenharmony_ci *            input buffer
10988c2ecf20Sopenharmony_ci * @last_loc: if not ICE_FLOW_FLD_OFF_INVAL, location of last/upper value from
10998c2ecf20Sopenharmony_ci *            entry's input buffer
11008c2ecf20Sopenharmony_ci * @range: indicate if field being matched is to be in a range
11018c2ecf20Sopenharmony_ci *
11028c2ecf20Sopenharmony_ci * This function specifies the locations, in the form of byte offsets from the
11038c2ecf20Sopenharmony_ci * start of the input buffer for a flow entry, from where the value to match,
11048c2ecf20Sopenharmony_ci * the mask value, and upper value can be extracted. These locations are then
11058c2ecf20Sopenharmony_ci * stored in the flow profile. When adding a flow entry associated with the
11068c2ecf20Sopenharmony_ci * flow profile, these locations will be used to quickly extract the values and
11078c2ecf20Sopenharmony_ci * create the content of a match entry. This function should only be used for
11088c2ecf20Sopenharmony_ci * fixed-size data structures.
11098c2ecf20Sopenharmony_ci */
11108c2ecf20Sopenharmony_civoid
11118c2ecf20Sopenharmony_ciice_flow_set_fld(struct ice_flow_seg_info *seg, enum ice_flow_field fld,
11128c2ecf20Sopenharmony_ci		 u16 val_loc, u16 mask_loc, u16 last_loc, bool range)
11138c2ecf20Sopenharmony_ci{
11148c2ecf20Sopenharmony_ci	enum ice_flow_fld_match_type t = range ?
11158c2ecf20Sopenharmony_ci		ICE_FLOW_FLD_TYPE_RANGE : ICE_FLOW_FLD_TYPE_REG;
11168c2ecf20Sopenharmony_ci
11178c2ecf20Sopenharmony_ci	ice_flow_set_fld_ext(seg, fld, t, val_loc, mask_loc, last_loc);
11188c2ecf20Sopenharmony_ci}
11198c2ecf20Sopenharmony_ci
11208c2ecf20Sopenharmony_ci/**
11218c2ecf20Sopenharmony_ci * ice_flow_add_fld_raw - sets locations of a raw field from entry's input buf
11228c2ecf20Sopenharmony_ci * @seg: packet segment the field being set belongs to
11238c2ecf20Sopenharmony_ci * @off: offset of the raw field from the beginning of the segment in bytes
11248c2ecf20Sopenharmony_ci * @len: length of the raw pattern to be matched
11258c2ecf20Sopenharmony_ci * @val_loc: location of the value to match from entry's input buffer
11268c2ecf20Sopenharmony_ci * @mask_loc: location of mask value from entry's input buffer
11278c2ecf20Sopenharmony_ci *
11288c2ecf20Sopenharmony_ci * This function specifies the offset of the raw field to be match from the
11298c2ecf20Sopenharmony_ci * beginning of the specified packet segment, and the locations, in the form of
11308c2ecf20Sopenharmony_ci * byte offsets from the start of the input buffer for a flow entry, from where
11318c2ecf20Sopenharmony_ci * the value to match and the mask value to be extracted. These locations are
11328c2ecf20Sopenharmony_ci * then stored in the flow profile. When adding flow entries to the associated
11338c2ecf20Sopenharmony_ci * flow profile, these locations can be used to quickly extract the values to
11348c2ecf20Sopenharmony_ci * create the content of a match entry. This function should only be used for
11358c2ecf20Sopenharmony_ci * fixed-size data structures.
11368c2ecf20Sopenharmony_ci */
11378c2ecf20Sopenharmony_civoid
11388c2ecf20Sopenharmony_ciice_flow_add_fld_raw(struct ice_flow_seg_info *seg, u16 off, u8 len,
11398c2ecf20Sopenharmony_ci		     u16 val_loc, u16 mask_loc)
11408c2ecf20Sopenharmony_ci{
11418c2ecf20Sopenharmony_ci	if (seg->raws_cnt < ICE_FLOW_SEG_RAW_FLD_MAX) {
11428c2ecf20Sopenharmony_ci		seg->raws[seg->raws_cnt].off = off;
11438c2ecf20Sopenharmony_ci		seg->raws[seg->raws_cnt].info.type = ICE_FLOW_FLD_TYPE_SIZE;
11448c2ecf20Sopenharmony_ci		seg->raws[seg->raws_cnt].info.src.val = val_loc;
11458c2ecf20Sopenharmony_ci		seg->raws[seg->raws_cnt].info.src.mask = mask_loc;
11468c2ecf20Sopenharmony_ci		/* The "last" field is used to store the length of the field */
11478c2ecf20Sopenharmony_ci		seg->raws[seg->raws_cnt].info.src.last = len;
11488c2ecf20Sopenharmony_ci	}
11498c2ecf20Sopenharmony_ci
11508c2ecf20Sopenharmony_ci	/* Overflows of "raws" will be handled as an error condition later in
11518c2ecf20Sopenharmony_ci	 * the flow when this information is processed.
11528c2ecf20Sopenharmony_ci	 */
11538c2ecf20Sopenharmony_ci	seg->raws_cnt++;
11548c2ecf20Sopenharmony_ci}
11558c2ecf20Sopenharmony_ci
11568c2ecf20Sopenharmony_ci#define ICE_FLOW_RSS_SEG_HDR_L3_MASKS \
11578c2ecf20Sopenharmony_ci	(ICE_FLOW_SEG_HDR_IPV4 | ICE_FLOW_SEG_HDR_IPV6)
11588c2ecf20Sopenharmony_ci
11598c2ecf20Sopenharmony_ci#define ICE_FLOW_RSS_SEG_HDR_L4_MASKS \
11608c2ecf20Sopenharmony_ci	(ICE_FLOW_SEG_HDR_TCP | ICE_FLOW_SEG_HDR_UDP | ICE_FLOW_SEG_HDR_SCTP)
11618c2ecf20Sopenharmony_ci
11628c2ecf20Sopenharmony_ci#define ICE_FLOW_RSS_SEG_HDR_VAL_MASKS \
11638c2ecf20Sopenharmony_ci	(ICE_FLOW_RSS_SEG_HDR_L3_MASKS | \
11648c2ecf20Sopenharmony_ci	 ICE_FLOW_RSS_SEG_HDR_L4_MASKS)
11658c2ecf20Sopenharmony_ci
11668c2ecf20Sopenharmony_ci/**
11678c2ecf20Sopenharmony_ci * ice_flow_set_rss_seg_info - setup packet segments for RSS
11688c2ecf20Sopenharmony_ci * @segs: pointer to the flow field segment(s)
11698c2ecf20Sopenharmony_ci * @hash_fields: fields to be hashed on for the segment(s)
11708c2ecf20Sopenharmony_ci * @flow_hdr: protocol header fields within a packet segment
11718c2ecf20Sopenharmony_ci *
11728c2ecf20Sopenharmony_ci * Helper function to extract fields from hash bitmap and use flow
11738c2ecf20Sopenharmony_ci * header value to set flow field segment for further use in flow
11748c2ecf20Sopenharmony_ci * profile entry or removal.
11758c2ecf20Sopenharmony_ci */
11768c2ecf20Sopenharmony_cistatic enum ice_status
11778c2ecf20Sopenharmony_ciice_flow_set_rss_seg_info(struct ice_flow_seg_info *segs, u64 hash_fields,
11788c2ecf20Sopenharmony_ci			  u32 flow_hdr)
11798c2ecf20Sopenharmony_ci{
11808c2ecf20Sopenharmony_ci	u64 val;
11818c2ecf20Sopenharmony_ci	u8 i;
11828c2ecf20Sopenharmony_ci
11838c2ecf20Sopenharmony_ci	for_each_set_bit(i, (unsigned long *)&hash_fields,
11848c2ecf20Sopenharmony_ci			 ICE_FLOW_FIELD_IDX_MAX)
11858c2ecf20Sopenharmony_ci		ice_flow_set_fld(segs, (enum ice_flow_field)i,
11868c2ecf20Sopenharmony_ci				 ICE_FLOW_FLD_OFF_INVAL, ICE_FLOW_FLD_OFF_INVAL,
11878c2ecf20Sopenharmony_ci				 ICE_FLOW_FLD_OFF_INVAL, false);
11888c2ecf20Sopenharmony_ci
11898c2ecf20Sopenharmony_ci	ICE_FLOW_SET_HDRS(segs, flow_hdr);
11908c2ecf20Sopenharmony_ci
11918c2ecf20Sopenharmony_ci	if (segs->hdrs & ~ICE_FLOW_RSS_SEG_HDR_VAL_MASKS)
11928c2ecf20Sopenharmony_ci		return ICE_ERR_PARAM;
11938c2ecf20Sopenharmony_ci
11948c2ecf20Sopenharmony_ci	val = (u64)(segs->hdrs & ICE_FLOW_RSS_SEG_HDR_L3_MASKS);
11958c2ecf20Sopenharmony_ci	if (val && !is_power_of_2(val))
11968c2ecf20Sopenharmony_ci		return ICE_ERR_CFG;
11978c2ecf20Sopenharmony_ci
11988c2ecf20Sopenharmony_ci	val = (u64)(segs->hdrs & ICE_FLOW_RSS_SEG_HDR_L4_MASKS);
11998c2ecf20Sopenharmony_ci	if (val && !is_power_of_2(val))
12008c2ecf20Sopenharmony_ci		return ICE_ERR_CFG;
12018c2ecf20Sopenharmony_ci
12028c2ecf20Sopenharmony_ci	return 0;
12038c2ecf20Sopenharmony_ci}
12048c2ecf20Sopenharmony_ci
12058c2ecf20Sopenharmony_ci/**
12068c2ecf20Sopenharmony_ci * ice_rem_vsi_rss_list - remove VSI from RSS list
12078c2ecf20Sopenharmony_ci * @hw: pointer to the hardware structure
12088c2ecf20Sopenharmony_ci * @vsi_handle: software VSI handle
12098c2ecf20Sopenharmony_ci *
12108c2ecf20Sopenharmony_ci * Remove the VSI from all RSS configurations in the list.
12118c2ecf20Sopenharmony_ci */
12128c2ecf20Sopenharmony_civoid ice_rem_vsi_rss_list(struct ice_hw *hw, u16 vsi_handle)
12138c2ecf20Sopenharmony_ci{
12148c2ecf20Sopenharmony_ci	struct ice_rss_cfg *r, *tmp;
12158c2ecf20Sopenharmony_ci
12168c2ecf20Sopenharmony_ci	if (list_empty(&hw->rss_list_head))
12178c2ecf20Sopenharmony_ci		return;
12188c2ecf20Sopenharmony_ci
12198c2ecf20Sopenharmony_ci	mutex_lock(&hw->rss_locks);
12208c2ecf20Sopenharmony_ci	list_for_each_entry_safe(r, tmp, &hw->rss_list_head, l_entry)
12218c2ecf20Sopenharmony_ci		if (test_and_clear_bit(vsi_handle, r->vsis))
12228c2ecf20Sopenharmony_ci			if (bitmap_empty(r->vsis, ICE_MAX_VSI)) {
12238c2ecf20Sopenharmony_ci				list_del(&r->l_entry);
12248c2ecf20Sopenharmony_ci				devm_kfree(ice_hw_to_dev(hw), r);
12258c2ecf20Sopenharmony_ci			}
12268c2ecf20Sopenharmony_ci	mutex_unlock(&hw->rss_locks);
12278c2ecf20Sopenharmony_ci}
12288c2ecf20Sopenharmony_ci
12298c2ecf20Sopenharmony_ci/**
12308c2ecf20Sopenharmony_ci * ice_rem_vsi_rss_cfg - remove RSS configurations associated with VSI
12318c2ecf20Sopenharmony_ci * @hw: pointer to the hardware structure
12328c2ecf20Sopenharmony_ci * @vsi_handle: software VSI handle
12338c2ecf20Sopenharmony_ci *
12348c2ecf20Sopenharmony_ci * This function will iterate through all flow profiles and disassociate
12358c2ecf20Sopenharmony_ci * the VSI from that profile. If the flow profile has no VSIs it will
12368c2ecf20Sopenharmony_ci * be removed.
12378c2ecf20Sopenharmony_ci */
12388c2ecf20Sopenharmony_cienum ice_status ice_rem_vsi_rss_cfg(struct ice_hw *hw, u16 vsi_handle)
12398c2ecf20Sopenharmony_ci{
12408c2ecf20Sopenharmony_ci	const enum ice_block blk = ICE_BLK_RSS;
12418c2ecf20Sopenharmony_ci	struct ice_flow_prof *p, *t;
12428c2ecf20Sopenharmony_ci	enum ice_status status = 0;
12438c2ecf20Sopenharmony_ci
12448c2ecf20Sopenharmony_ci	if (!ice_is_vsi_valid(hw, vsi_handle))
12458c2ecf20Sopenharmony_ci		return ICE_ERR_PARAM;
12468c2ecf20Sopenharmony_ci
12478c2ecf20Sopenharmony_ci	if (list_empty(&hw->fl_profs[blk]))
12488c2ecf20Sopenharmony_ci		return 0;
12498c2ecf20Sopenharmony_ci
12508c2ecf20Sopenharmony_ci	mutex_lock(&hw->rss_locks);
12518c2ecf20Sopenharmony_ci	list_for_each_entry_safe(p, t, &hw->fl_profs[blk], l_entry)
12528c2ecf20Sopenharmony_ci		if (test_bit(vsi_handle, p->vsis)) {
12538c2ecf20Sopenharmony_ci			status = ice_flow_disassoc_prof(hw, blk, p, vsi_handle);
12548c2ecf20Sopenharmony_ci			if (status)
12558c2ecf20Sopenharmony_ci				break;
12568c2ecf20Sopenharmony_ci
12578c2ecf20Sopenharmony_ci			if (bitmap_empty(p->vsis, ICE_MAX_VSI)) {
12588c2ecf20Sopenharmony_ci				status = ice_flow_rem_prof(hw, blk, p->id);
12598c2ecf20Sopenharmony_ci				if (status)
12608c2ecf20Sopenharmony_ci					break;
12618c2ecf20Sopenharmony_ci			}
12628c2ecf20Sopenharmony_ci		}
12638c2ecf20Sopenharmony_ci	mutex_unlock(&hw->rss_locks);
12648c2ecf20Sopenharmony_ci
12658c2ecf20Sopenharmony_ci	return status;
12668c2ecf20Sopenharmony_ci}
12678c2ecf20Sopenharmony_ci
12688c2ecf20Sopenharmony_ci/**
12698c2ecf20Sopenharmony_ci * ice_rem_rss_list - remove RSS configuration from list
12708c2ecf20Sopenharmony_ci * @hw: pointer to the hardware structure
12718c2ecf20Sopenharmony_ci * @vsi_handle: software VSI handle
12728c2ecf20Sopenharmony_ci * @prof: pointer to flow profile
12738c2ecf20Sopenharmony_ci *
12748c2ecf20Sopenharmony_ci * Assumption: lock has already been acquired for RSS list
12758c2ecf20Sopenharmony_ci */
12768c2ecf20Sopenharmony_cistatic void
12778c2ecf20Sopenharmony_ciice_rem_rss_list(struct ice_hw *hw, u16 vsi_handle, struct ice_flow_prof *prof)
12788c2ecf20Sopenharmony_ci{
12798c2ecf20Sopenharmony_ci	struct ice_rss_cfg *r, *tmp;
12808c2ecf20Sopenharmony_ci
12818c2ecf20Sopenharmony_ci	/* Search for RSS hash fields associated to the VSI that match the
12828c2ecf20Sopenharmony_ci	 * hash configurations associated to the flow profile. If found
12838c2ecf20Sopenharmony_ci	 * remove from the RSS entry list of the VSI context and delete entry.
12848c2ecf20Sopenharmony_ci	 */
12858c2ecf20Sopenharmony_ci	list_for_each_entry_safe(r, tmp, &hw->rss_list_head, l_entry)
12868c2ecf20Sopenharmony_ci		if (r->hashed_flds == prof->segs[prof->segs_cnt - 1].match &&
12878c2ecf20Sopenharmony_ci		    r->packet_hdr == prof->segs[prof->segs_cnt - 1].hdrs) {
12888c2ecf20Sopenharmony_ci			clear_bit(vsi_handle, r->vsis);
12898c2ecf20Sopenharmony_ci			if (bitmap_empty(r->vsis, ICE_MAX_VSI)) {
12908c2ecf20Sopenharmony_ci				list_del(&r->l_entry);
12918c2ecf20Sopenharmony_ci				devm_kfree(ice_hw_to_dev(hw), r);
12928c2ecf20Sopenharmony_ci			}
12938c2ecf20Sopenharmony_ci			return;
12948c2ecf20Sopenharmony_ci		}
12958c2ecf20Sopenharmony_ci}
12968c2ecf20Sopenharmony_ci
12978c2ecf20Sopenharmony_ci/**
12988c2ecf20Sopenharmony_ci * ice_add_rss_list - add RSS configuration to list
12998c2ecf20Sopenharmony_ci * @hw: pointer to the hardware structure
13008c2ecf20Sopenharmony_ci * @vsi_handle: software VSI handle
13018c2ecf20Sopenharmony_ci * @prof: pointer to flow profile
13028c2ecf20Sopenharmony_ci *
13038c2ecf20Sopenharmony_ci * Assumption: lock has already been acquired for RSS list
13048c2ecf20Sopenharmony_ci */
13058c2ecf20Sopenharmony_cistatic enum ice_status
13068c2ecf20Sopenharmony_ciice_add_rss_list(struct ice_hw *hw, u16 vsi_handle, struct ice_flow_prof *prof)
13078c2ecf20Sopenharmony_ci{
13088c2ecf20Sopenharmony_ci	struct ice_rss_cfg *r, *rss_cfg;
13098c2ecf20Sopenharmony_ci
13108c2ecf20Sopenharmony_ci	list_for_each_entry(r, &hw->rss_list_head, l_entry)
13118c2ecf20Sopenharmony_ci		if (r->hashed_flds == prof->segs[prof->segs_cnt - 1].match &&
13128c2ecf20Sopenharmony_ci		    r->packet_hdr == prof->segs[prof->segs_cnt - 1].hdrs) {
13138c2ecf20Sopenharmony_ci			set_bit(vsi_handle, r->vsis);
13148c2ecf20Sopenharmony_ci			return 0;
13158c2ecf20Sopenharmony_ci		}
13168c2ecf20Sopenharmony_ci
13178c2ecf20Sopenharmony_ci	rss_cfg = devm_kzalloc(ice_hw_to_dev(hw), sizeof(*rss_cfg),
13188c2ecf20Sopenharmony_ci			       GFP_KERNEL);
13198c2ecf20Sopenharmony_ci	if (!rss_cfg)
13208c2ecf20Sopenharmony_ci		return ICE_ERR_NO_MEMORY;
13218c2ecf20Sopenharmony_ci
13228c2ecf20Sopenharmony_ci	rss_cfg->hashed_flds = prof->segs[prof->segs_cnt - 1].match;
13238c2ecf20Sopenharmony_ci	rss_cfg->packet_hdr = prof->segs[prof->segs_cnt - 1].hdrs;
13248c2ecf20Sopenharmony_ci	set_bit(vsi_handle, rss_cfg->vsis);
13258c2ecf20Sopenharmony_ci
13268c2ecf20Sopenharmony_ci	list_add_tail(&rss_cfg->l_entry, &hw->rss_list_head);
13278c2ecf20Sopenharmony_ci
13288c2ecf20Sopenharmony_ci	return 0;
13298c2ecf20Sopenharmony_ci}
13308c2ecf20Sopenharmony_ci
13318c2ecf20Sopenharmony_ci#define ICE_FLOW_PROF_HASH_S	0
13328c2ecf20Sopenharmony_ci#define ICE_FLOW_PROF_HASH_M	(0xFFFFFFFFULL << ICE_FLOW_PROF_HASH_S)
13338c2ecf20Sopenharmony_ci#define ICE_FLOW_PROF_HDR_S	32
13348c2ecf20Sopenharmony_ci#define ICE_FLOW_PROF_HDR_M	(0x3FFFFFFFULL << ICE_FLOW_PROF_HDR_S)
13358c2ecf20Sopenharmony_ci#define ICE_FLOW_PROF_ENCAP_S	63
13368c2ecf20Sopenharmony_ci#define ICE_FLOW_PROF_ENCAP_M	(BIT_ULL(ICE_FLOW_PROF_ENCAP_S))
13378c2ecf20Sopenharmony_ci
13388c2ecf20Sopenharmony_ci#define ICE_RSS_OUTER_HEADERS	1
13398c2ecf20Sopenharmony_ci#define ICE_RSS_INNER_HEADERS	2
13408c2ecf20Sopenharmony_ci
13418c2ecf20Sopenharmony_ci/* Flow profile ID format:
13428c2ecf20Sopenharmony_ci * [0:31] - Packet match fields
13438c2ecf20Sopenharmony_ci * [32:62] - Protocol header
13448c2ecf20Sopenharmony_ci * [63] - Encapsulation flag, 0 if non-tunneled, 1 if tunneled
13458c2ecf20Sopenharmony_ci */
13468c2ecf20Sopenharmony_ci#define ICE_FLOW_GEN_PROFID(hash, hdr, segs_cnt) \
13478c2ecf20Sopenharmony_ci	(u64)(((u64)(hash) & ICE_FLOW_PROF_HASH_M) | \
13488c2ecf20Sopenharmony_ci	      (((u64)(hdr) << ICE_FLOW_PROF_HDR_S) & ICE_FLOW_PROF_HDR_M) | \
13498c2ecf20Sopenharmony_ci	      ((u8)((segs_cnt) - 1) ? ICE_FLOW_PROF_ENCAP_M : 0))
13508c2ecf20Sopenharmony_ci
13518c2ecf20Sopenharmony_ci/**
13528c2ecf20Sopenharmony_ci * ice_add_rss_cfg_sync - add an RSS configuration
13538c2ecf20Sopenharmony_ci * @hw: pointer to the hardware structure
13548c2ecf20Sopenharmony_ci * @vsi_handle: software VSI handle
13558c2ecf20Sopenharmony_ci * @hashed_flds: hash bit fields (ICE_FLOW_HASH_*) to configure
13568c2ecf20Sopenharmony_ci * @addl_hdrs: protocol header fields
13578c2ecf20Sopenharmony_ci * @segs_cnt: packet segment count
13588c2ecf20Sopenharmony_ci *
13598c2ecf20Sopenharmony_ci * Assumption: lock has already been acquired for RSS list
13608c2ecf20Sopenharmony_ci */
13618c2ecf20Sopenharmony_cistatic enum ice_status
13628c2ecf20Sopenharmony_ciice_add_rss_cfg_sync(struct ice_hw *hw, u16 vsi_handle, u64 hashed_flds,
13638c2ecf20Sopenharmony_ci		     u32 addl_hdrs, u8 segs_cnt)
13648c2ecf20Sopenharmony_ci{
13658c2ecf20Sopenharmony_ci	const enum ice_block blk = ICE_BLK_RSS;
13668c2ecf20Sopenharmony_ci	struct ice_flow_prof *prof = NULL;
13678c2ecf20Sopenharmony_ci	struct ice_flow_seg_info *segs;
13688c2ecf20Sopenharmony_ci	enum ice_status status;
13698c2ecf20Sopenharmony_ci
13708c2ecf20Sopenharmony_ci	if (!segs_cnt || segs_cnt > ICE_FLOW_SEG_MAX)
13718c2ecf20Sopenharmony_ci		return ICE_ERR_PARAM;
13728c2ecf20Sopenharmony_ci
13738c2ecf20Sopenharmony_ci	segs = kcalloc(segs_cnt, sizeof(*segs), GFP_KERNEL);
13748c2ecf20Sopenharmony_ci	if (!segs)
13758c2ecf20Sopenharmony_ci		return ICE_ERR_NO_MEMORY;
13768c2ecf20Sopenharmony_ci
13778c2ecf20Sopenharmony_ci	/* Construct the packet segment info from the hashed fields */
13788c2ecf20Sopenharmony_ci	status = ice_flow_set_rss_seg_info(&segs[segs_cnt - 1], hashed_flds,
13798c2ecf20Sopenharmony_ci					   addl_hdrs);
13808c2ecf20Sopenharmony_ci	if (status)
13818c2ecf20Sopenharmony_ci		goto exit;
13828c2ecf20Sopenharmony_ci
13838c2ecf20Sopenharmony_ci	/* Search for a flow profile that has matching headers, hash fields
13848c2ecf20Sopenharmony_ci	 * and has the input VSI associated to it. If found, no further
13858c2ecf20Sopenharmony_ci	 * operations required and exit.
13868c2ecf20Sopenharmony_ci	 */
13878c2ecf20Sopenharmony_ci	prof = ice_flow_find_prof_conds(hw, blk, ICE_FLOW_RX, segs, segs_cnt,
13888c2ecf20Sopenharmony_ci					vsi_handle,
13898c2ecf20Sopenharmony_ci					ICE_FLOW_FIND_PROF_CHK_FLDS |
13908c2ecf20Sopenharmony_ci					ICE_FLOW_FIND_PROF_CHK_VSI);
13918c2ecf20Sopenharmony_ci	if (prof)
13928c2ecf20Sopenharmony_ci		goto exit;
13938c2ecf20Sopenharmony_ci
13948c2ecf20Sopenharmony_ci	/* Check if a flow profile exists with the same protocol headers and
13958c2ecf20Sopenharmony_ci	 * associated with the input VSI. If so disassociate the VSI from
13968c2ecf20Sopenharmony_ci	 * this profile. The VSI will be added to a new profile created with
13978c2ecf20Sopenharmony_ci	 * the protocol header and new hash field configuration.
13988c2ecf20Sopenharmony_ci	 */
13998c2ecf20Sopenharmony_ci	prof = ice_flow_find_prof_conds(hw, blk, ICE_FLOW_RX, segs, segs_cnt,
14008c2ecf20Sopenharmony_ci					vsi_handle, ICE_FLOW_FIND_PROF_CHK_VSI);
14018c2ecf20Sopenharmony_ci	if (prof) {
14028c2ecf20Sopenharmony_ci		status = ice_flow_disassoc_prof(hw, blk, prof, vsi_handle);
14038c2ecf20Sopenharmony_ci		if (!status)
14048c2ecf20Sopenharmony_ci			ice_rem_rss_list(hw, vsi_handle, prof);
14058c2ecf20Sopenharmony_ci		else
14068c2ecf20Sopenharmony_ci			goto exit;
14078c2ecf20Sopenharmony_ci
14088c2ecf20Sopenharmony_ci		/* Remove profile if it has no VSIs associated */
14098c2ecf20Sopenharmony_ci		if (bitmap_empty(prof->vsis, ICE_MAX_VSI)) {
14108c2ecf20Sopenharmony_ci			status = ice_flow_rem_prof(hw, blk, prof->id);
14118c2ecf20Sopenharmony_ci			if (status)
14128c2ecf20Sopenharmony_ci				goto exit;
14138c2ecf20Sopenharmony_ci		}
14148c2ecf20Sopenharmony_ci	}
14158c2ecf20Sopenharmony_ci
14168c2ecf20Sopenharmony_ci	/* Search for a profile that has same match fields only. If this
14178c2ecf20Sopenharmony_ci	 * exists then associate the VSI to this profile.
14188c2ecf20Sopenharmony_ci	 */
14198c2ecf20Sopenharmony_ci	prof = ice_flow_find_prof_conds(hw, blk, ICE_FLOW_RX, segs, segs_cnt,
14208c2ecf20Sopenharmony_ci					vsi_handle,
14218c2ecf20Sopenharmony_ci					ICE_FLOW_FIND_PROF_CHK_FLDS);
14228c2ecf20Sopenharmony_ci	if (prof) {
14238c2ecf20Sopenharmony_ci		status = ice_flow_assoc_prof(hw, blk, prof, vsi_handle);
14248c2ecf20Sopenharmony_ci		if (!status)
14258c2ecf20Sopenharmony_ci			status = ice_add_rss_list(hw, vsi_handle, prof);
14268c2ecf20Sopenharmony_ci		goto exit;
14278c2ecf20Sopenharmony_ci	}
14288c2ecf20Sopenharmony_ci
14298c2ecf20Sopenharmony_ci	/* Create a new flow profile with generated profile and packet
14308c2ecf20Sopenharmony_ci	 * segment information.
14318c2ecf20Sopenharmony_ci	 */
14328c2ecf20Sopenharmony_ci	status = ice_flow_add_prof(hw, blk, ICE_FLOW_RX,
14338c2ecf20Sopenharmony_ci				   ICE_FLOW_GEN_PROFID(hashed_flds,
14348c2ecf20Sopenharmony_ci						       segs[segs_cnt - 1].hdrs,
14358c2ecf20Sopenharmony_ci						       segs_cnt),
14368c2ecf20Sopenharmony_ci				   segs, segs_cnt, &prof);
14378c2ecf20Sopenharmony_ci	if (status)
14388c2ecf20Sopenharmony_ci		goto exit;
14398c2ecf20Sopenharmony_ci
14408c2ecf20Sopenharmony_ci	status = ice_flow_assoc_prof(hw, blk, prof, vsi_handle);
14418c2ecf20Sopenharmony_ci	/* If association to a new flow profile failed then this profile can
14428c2ecf20Sopenharmony_ci	 * be removed.
14438c2ecf20Sopenharmony_ci	 */
14448c2ecf20Sopenharmony_ci	if (status) {
14458c2ecf20Sopenharmony_ci		ice_flow_rem_prof(hw, blk, prof->id);
14468c2ecf20Sopenharmony_ci		goto exit;
14478c2ecf20Sopenharmony_ci	}
14488c2ecf20Sopenharmony_ci
14498c2ecf20Sopenharmony_ci	status = ice_add_rss_list(hw, vsi_handle, prof);
14508c2ecf20Sopenharmony_ci
14518c2ecf20Sopenharmony_ciexit:
14528c2ecf20Sopenharmony_ci	kfree(segs);
14538c2ecf20Sopenharmony_ci	return status;
14548c2ecf20Sopenharmony_ci}
14558c2ecf20Sopenharmony_ci
14568c2ecf20Sopenharmony_ci/**
14578c2ecf20Sopenharmony_ci * ice_add_rss_cfg - add an RSS configuration with specified hashed fields
14588c2ecf20Sopenharmony_ci * @hw: pointer to the hardware structure
14598c2ecf20Sopenharmony_ci * @vsi_handle: software VSI handle
14608c2ecf20Sopenharmony_ci * @hashed_flds: hash bit fields (ICE_FLOW_HASH_*) to configure
14618c2ecf20Sopenharmony_ci * @addl_hdrs: protocol header fields
14628c2ecf20Sopenharmony_ci *
14638c2ecf20Sopenharmony_ci * This function will generate a flow profile based on fields associated with
14648c2ecf20Sopenharmony_ci * the input fields to hash on, the flow type and use the VSI number to add
14658c2ecf20Sopenharmony_ci * a flow entry to the profile.
14668c2ecf20Sopenharmony_ci */
14678c2ecf20Sopenharmony_cienum ice_status
14688c2ecf20Sopenharmony_ciice_add_rss_cfg(struct ice_hw *hw, u16 vsi_handle, u64 hashed_flds,
14698c2ecf20Sopenharmony_ci		u32 addl_hdrs)
14708c2ecf20Sopenharmony_ci{
14718c2ecf20Sopenharmony_ci	enum ice_status status;
14728c2ecf20Sopenharmony_ci
14738c2ecf20Sopenharmony_ci	if (hashed_flds == ICE_HASH_INVALID ||
14748c2ecf20Sopenharmony_ci	    !ice_is_vsi_valid(hw, vsi_handle))
14758c2ecf20Sopenharmony_ci		return ICE_ERR_PARAM;
14768c2ecf20Sopenharmony_ci
14778c2ecf20Sopenharmony_ci	mutex_lock(&hw->rss_locks);
14788c2ecf20Sopenharmony_ci	status = ice_add_rss_cfg_sync(hw, vsi_handle, hashed_flds, addl_hdrs,
14798c2ecf20Sopenharmony_ci				      ICE_RSS_OUTER_HEADERS);
14808c2ecf20Sopenharmony_ci	if (!status)
14818c2ecf20Sopenharmony_ci		status = ice_add_rss_cfg_sync(hw, vsi_handle, hashed_flds,
14828c2ecf20Sopenharmony_ci					      addl_hdrs, ICE_RSS_INNER_HEADERS);
14838c2ecf20Sopenharmony_ci	mutex_unlock(&hw->rss_locks);
14848c2ecf20Sopenharmony_ci
14858c2ecf20Sopenharmony_ci	return status;
14868c2ecf20Sopenharmony_ci}
14878c2ecf20Sopenharmony_ci
14888c2ecf20Sopenharmony_ci/* Mapping of AVF hash bit fields to an L3-L4 hash combination.
14898c2ecf20Sopenharmony_ci * As the ice_flow_avf_hdr_field represent individual bit shifts in a hash,
14908c2ecf20Sopenharmony_ci * convert its values to their appropriate flow L3, L4 values.
14918c2ecf20Sopenharmony_ci */
14928c2ecf20Sopenharmony_ci#define ICE_FLOW_AVF_RSS_IPV4_MASKS \
14938c2ecf20Sopenharmony_ci	(BIT_ULL(ICE_AVF_FLOW_FIELD_IPV4_OTHER) | \
14948c2ecf20Sopenharmony_ci	 BIT_ULL(ICE_AVF_FLOW_FIELD_FRAG_IPV4))
14958c2ecf20Sopenharmony_ci#define ICE_FLOW_AVF_RSS_TCP_IPV4_MASKS \
14968c2ecf20Sopenharmony_ci	(BIT_ULL(ICE_AVF_FLOW_FIELD_IPV4_TCP_SYN_NO_ACK) | \
14978c2ecf20Sopenharmony_ci	 BIT_ULL(ICE_AVF_FLOW_FIELD_IPV4_TCP))
14988c2ecf20Sopenharmony_ci#define ICE_FLOW_AVF_RSS_UDP_IPV4_MASKS \
14998c2ecf20Sopenharmony_ci	(BIT_ULL(ICE_AVF_FLOW_FIELD_UNICAST_IPV4_UDP) | \
15008c2ecf20Sopenharmony_ci	 BIT_ULL(ICE_AVF_FLOW_FIELD_MULTICAST_IPV4_UDP) | \
15018c2ecf20Sopenharmony_ci	 BIT_ULL(ICE_AVF_FLOW_FIELD_IPV4_UDP))
15028c2ecf20Sopenharmony_ci#define ICE_FLOW_AVF_RSS_ALL_IPV4_MASKS \
15038c2ecf20Sopenharmony_ci	(ICE_FLOW_AVF_RSS_TCP_IPV4_MASKS | ICE_FLOW_AVF_RSS_UDP_IPV4_MASKS | \
15048c2ecf20Sopenharmony_ci	 ICE_FLOW_AVF_RSS_IPV4_MASKS | BIT_ULL(ICE_AVF_FLOW_FIELD_IPV4_SCTP))
15058c2ecf20Sopenharmony_ci
15068c2ecf20Sopenharmony_ci#define ICE_FLOW_AVF_RSS_IPV6_MASKS \
15078c2ecf20Sopenharmony_ci	(BIT_ULL(ICE_AVF_FLOW_FIELD_IPV6_OTHER) | \
15088c2ecf20Sopenharmony_ci	 BIT_ULL(ICE_AVF_FLOW_FIELD_FRAG_IPV6))
15098c2ecf20Sopenharmony_ci#define ICE_FLOW_AVF_RSS_UDP_IPV6_MASKS \
15108c2ecf20Sopenharmony_ci	(BIT_ULL(ICE_AVF_FLOW_FIELD_UNICAST_IPV6_UDP) | \
15118c2ecf20Sopenharmony_ci	 BIT_ULL(ICE_AVF_FLOW_FIELD_MULTICAST_IPV6_UDP) | \
15128c2ecf20Sopenharmony_ci	 BIT_ULL(ICE_AVF_FLOW_FIELD_IPV6_UDP))
15138c2ecf20Sopenharmony_ci#define ICE_FLOW_AVF_RSS_TCP_IPV6_MASKS \
15148c2ecf20Sopenharmony_ci	(BIT_ULL(ICE_AVF_FLOW_FIELD_IPV6_TCP_SYN_NO_ACK) | \
15158c2ecf20Sopenharmony_ci	 BIT_ULL(ICE_AVF_FLOW_FIELD_IPV6_TCP))
15168c2ecf20Sopenharmony_ci#define ICE_FLOW_AVF_RSS_ALL_IPV6_MASKS \
15178c2ecf20Sopenharmony_ci	(ICE_FLOW_AVF_RSS_TCP_IPV6_MASKS | ICE_FLOW_AVF_RSS_UDP_IPV6_MASKS | \
15188c2ecf20Sopenharmony_ci	 ICE_FLOW_AVF_RSS_IPV6_MASKS | BIT_ULL(ICE_AVF_FLOW_FIELD_IPV6_SCTP))
15198c2ecf20Sopenharmony_ci
15208c2ecf20Sopenharmony_ci/**
15218c2ecf20Sopenharmony_ci * ice_add_avf_rss_cfg - add an RSS configuration for AVF driver
15228c2ecf20Sopenharmony_ci * @hw: pointer to the hardware structure
15238c2ecf20Sopenharmony_ci * @vsi_handle: software VSI handle
15248c2ecf20Sopenharmony_ci * @avf_hash: hash bit fields (ICE_AVF_FLOW_FIELD_*) to configure
15258c2ecf20Sopenharmony_ci *
15268c2ecf20Sopenharmony_ci * This function will take the hash bitmap provided by the AVF driver via a
15278c2ecf20Sopenharmony_ci * message, convert it to ICE-compatible values, and configure RSS flow
15288c2ecf20Sopenharmony_ci * profiles.
15298c2ecf20Sopenharmony_ci */
15308c2ecf20Sopenharmony_cienum ice_status
15318c2ecf20Sopenharmony_ciice_add_avf_rss_cfg(struct ice_hw *hw, u16 vsi_handle, u64 avf_hash)
15328c2ecf20Sopenharmony_ci{
15338c2ecf20Sopenharmony_ci	enum ice_status status = 0;
15348c2ecf20Sopenharmony_ci	u64 hash_flds;
15358c2ecf20Sopenharmony_ci
15368c2ecf20Sopenharmony_ci	if (avf_hash == ICE_AVF_FLOW_FIELD_INVALID ||
15378c2ecf20Sopenharmony_ci	    !ice_is_vsi_valid(hw, vsi_handle))
15388c2ecf20Sopenharmony_ci		return ICE_ERR_PARAM;
15398c2ecf20Sopenharmony_ci
15408c2ecf20Sopenharmony_ci	/* Make sure no unsupported bits are specified */
15418c2ecf20Sopenharmony_ci	if (avf_hash & ~(ICE_FLOW_AVF_RSS_ALL_IPV4_MASKS |
15428c2ecf20Sopenharmony_ci			 ICE_FLOW_AVF_RSS_ALL_IPV6_MASKS))
15438c2ecf20Sopenharmony_ci		return ICE_ERR_CFG;
15448c2ecf20Sopenharmony_ci
15458c2ecf20Sopenharmony_ci	hash_flds = avf_hash;
15468c2ecf20Sopenharmony_ci
15478c2ecf20Sopenharmony_ci	/* Always create an L3 RSS configuration for any L4 RSS configuration */
15488c2ecf20Sopenharmony_ci	if (hash_flds & ICE_FLOW_AVF_RSS_ALL_IPV4_MASKS)
15498c2ecf20Sopenharmony_ci		hash_flds |= ICE_FLOW_AVF_RSS_IPV4_MASKS;
15508c2ecf20Sopenharmony_ci
15518c2ecf20Sopenharmony_ci	if (hash_flds & ICE_FLOW_AVF_RSS_ALL_IPV6_MASKS)
15528c2ecf20Sopenharmony_ci		hash_flds |= ICE_FLOW_AVF_RSS_IPV6_MASKS;
15538c2ecf20Sopenharmony_ci
15548c2ecf20Sopenharmony_ci	/* Create the corresponding RSS configuration for each valid hash bit */
15558c2ecf20Sopenharmony_ci	while (hash_flds) {
15568c2ecf20Sopenharmony_ci		u64 rss_hash = ICE_HASH_INVALID;
15578c2ecf20Sopenharmony_ci
15588c2ecf20Sopenharmony_ci		if (hash_flds & ICE_FLOW_AVF_RSS_ALL_IPV4_MASKS) {
15598c2ecf20Sopenharmony_ci			if (hash_flds & ICE_FLOW_AVF_RSS_IPV4_MASKS) {
15608c2ecf20Sopenharmony_ci				rss_hash = ICE_FLOW_HASH_IPV4;
15618c2ecf20Sopenharmony_ci				hash_flds &= ~ICE_FLOW_AVF_RSS_IPV4_MASKS;
15628c2ecf20Sopenharmony_ci			} else if (hash_flds &
15638c2ecf20Sopenharmony_ci				   ICE_FLOW_AVF_RSS_TCP_IPV4_MASKS) {
15648c2ecf20Sopenharmony_ci				rss_hash = ICE_FLOW_HASH_IPV4 |
15658c2ecf20Sopenharmony_ci					ICE_FLOW_HASH_TCP_PORT;
15668c2ecf20Sopenharmony_ci				hash_flds &= ~ICE_FLOW_AVF_RSS_TCP_IPV4_MASKS;
15678c2ecf20Sopenharmony_ci			} else if (hash_flds &
15688c2ecf20Sopenharmony_ci				   ICE_FLOW_AVF_RSS_UDP_IPV4_MASKS) {
15698c2ecf20Sopenharmony_ci				rss_hash = ICE_FLOW_HASH_IPV4 |
15708c2ecf20Sopenharmony_ci					ICE_FLOW_HASH_UDP_PORT;
15718c2ecf20Sopenharmony_ci				hash_flds &= ~ICE_FLOW_AVF_RSS_UDP_IPV4_MASKS;
15728c2ecf20Sopenharmony_ci			} else if (hash_flds &
15738c2ecf20Sopenharmony_ci				   BIT_ULL(ICE_AVF_FLOW_FIELD_IPV4_SCTP)) {
15748c2ecf20Sopenharmony_ci				rss_hash = ICE_FLOW_HASH_IPV4 |
15758c2ecf20Sopenharmony_ci					ICE_FLOW_HASH_SCTP_PORT;
15768c2ecf20Sopenharmony_ci				hash_flds &=
15778c2ecf20Sopenharmony_ci					~BIT_ULL(ICE_AVF_FLOW_FIELD_IPV4_SCTP);
15788c2ecf20Sopenharmony_ci			}
15798c2ecf20Sopenharmony_ci		} else if (hash_flds & ICE_FLOW_AVF_RSS_ALL_IPV6_MASKS) {
15808c2ecf20Sopenharmony_ci			if (hash_flds & ICE_FLOW_AVF_RSS_IPV6_MASKS) {
15818c2ecf20Sopenharmony_ci				rss_hash = ICE_FLOW_HASH_IPV6;
15828c2ecf20Sopenharmony_ci				hash_flds &= ~ICE_FLOW_AVF_RSS_IPV6_MASKS;
15838c2ecf20Sopenharmony_ci			} else if (hash_flds &
15848c2ecf20Sopenharmony_ci				   ICE_FLOW_AVF_RSS_TCP_IPV6_MASKS) {
15858c2ecf20Sopenharmony_ci				rss_hash = ICE_FLOW_HASH_IPV6 |
15868c2ecf20Sopenharmony_ci					ICE_FLOW_HASH_TCP_PORT;
15878c2ecf20Sopenharmony_ci				hash_flds &= ~ICE_FLOW_AVF_RSS_TCP_IPV6_MASKS;
15888c2ecf20Sopenharmony_ci			} else if (hash_flds &
15898c2ecf20Sopenharmony_ci				   ICE_FLOW_AVF_RSS_UDP_IPV6_MASKS) {
15908c2ecf20Sopenharmony_ci				rss_hash = ICE_FLOW_HASH_IPV6 |
15918c2ecf20Sopenharmony_ci					ICE_FLOW_HASH_UDP_PORT;
15928c2ecf20Sopenharmony_ci				hash_flds &= ~ICE_FLOW_AVF_RSS_UDP_IPV6_MASKS;
15938c2ecf20Sopenharmony_ci			} else if (hash_flds &
15948c2ecf20Sopenharmony_ci				   BIT_ULL(ICE_AVF_FLOW_FIELD_IPV6_SCTP)) {
15958c2ecf20Sopenharmony_ci				rss_hash = ICE_FLOW_HASH_IPV6 |
15968c2ecf20Sopenharmony_ci					ICE_FLOW_HASH_SCTP_PORT;
15978c2ecf20Sopenharmony_ci				hash_flds &=
15988c2ecf20Sopenharmony_ci					~BIT_ULL(ICE_AVF_FLOW_FIELD_IPV6_SCTP);
15998c2ecf20Sopenharmony_ci			}
16008c2ecf20Sopenharmony_ci		}
16018c2ecf20Sopenharmony_ci
16028c2ecf20Sopenharmony_ci		if (rss_hash == ICE_HASH_INVALID)
16038c2ecf20Sopenharmony_ci			return ICE_ERR_OUT_OF_RANGE;
16048c2ecf20Sopenharmony_ci
16058c2ecf20Sopenharmony_ci		status = ice_add_rss_cfg(hw, vsi_handle, rss_hash,
16068c2ecf20Sopenharmony_ci					 ICE_FLOW_SEG_HDR_NONE);
16078c2ecf20Sopenharmony_ci		if (status)
16088c2ecf20Sopenharmony_ci			break;
16098c2ecf20Sopenharmony_ci	}
16108c2ecf20Sopenharmony_ci
16118c2ecf20Sopenharmony_ci	return status;
16128c2ecf20Sopenharmony_ci}
16138c2ecf20Sopenharmony_ci
16148c2ecf20Sopenharmony_ci/**
16158c2ecf20Sopenharmony_ci * ice_replay_rss_cfg - replay RSS configurations associated with VSI
16168c2ecf20Sopenharmony_ci * @hw: pointer to the hardware structure
16178c2ecf20Sopenharmony_ci * @vsi_handle: software VSI handle
16188c2ecf20Sopenharmony_ci */
16198c2ecf20Sopenharmony_cienum ice_status ice_replay_rss_cfg(struct ice_hw *hw, u16 vsi_handle)
16208c2ecf20Sopenharmony_ci{
16218c2ecf20Sopenharmony_ci	enum ice_status status = 0;
16228c2ecf20Sopenharmony_ci	struct ice_rss_cfg *r;
16238c2ecf20Sopenharmony_ci
16248c2ecf20Sopenharmony_ci	if (!ice_is_vsi_valid(hw, vsi_handle))
16258c2ecf20Sopenharmony_ci		return ICE_ERR_PARAM;
16268c2ecf20Sopenharmony_ci
16278c2ecf20Sopenharmony_ci	mutex_lock(&hw->rss_locks);
16288c2ecf20Sopenharmony_ci	list_for_each_entry(r, &hw->rss_list_head, l_entry) {
16298c2ecf20Sopenharmony_ci		if (test_bit(vsi_handle, r->vsis)) {
16308c2ecf20Sopenharmony_ci			status = ice_add_rss_cfg_sync(hw, vsi_handle,
16318c2ecf20Sopenharmony_ci						      r->hashed_flds,
16328c2ecf20Sopenharmony_ci						      r->packet_hdr,
16338c2ecf20Sopenharmony_ci						      ICE_RSS_OUTER_HEADERS);
16348c2ecf20Sopenharmony_ci			if (status)
16358c2ecf20Sopenharmony_ci				break;
16368c2ecf20Sopenharmony_ci			status = ice_add_rss_cfg_sync(hw, vsi_handle,
16378c2ecf20Sopenharmony_ci						      r->hashed_flds,
16388c2ecf20Sopenharmony_ci						      r->packet_hdr,
16398c2ecf20Sopenharmony_ci						      ICE_RSS_INNER_HEADERS);
16408c2ecf20Sopenharmony_ci			if (status)
16418c2ecf20Sopenharmony_ci				break;
16428c2ecf20Sopenharmony_ci		}
16438c2ecf20Sopenharmony_ci	}
16448c2ecf20Sopenharmony_ci	mutex_unlock(&hw->rss_locks);
16458c2ecf20Sopenharmony_ci
16468c2ecf20Sopenharmony_ci	return status;
16478c2ecf20Sopenharmony_ci}
16488c2ecf20Sopenharmony_ci
16498c2ecf20Sopenharmony_ci/**
16508c2ecf20Sopenharmony_ci * ice_get_rss_cfg - returns hashed fields for the given header types
16518c2ecf20Sopenharmony_ci * @hw: pointer to the hardware structure
16528c2ecf20Sopenharmony_ci * @vsi_handle: software VSI handle
16538c2ecf20Sopenharmony_ci * @hdrs: protocol header type
16548c2ecf20Sopenharmony_ci *
16558c2ecf20Sopenharmony_ci * This function will return the match fields of the first instance of flow
16568c2ecf20Sopenharmony_ci * profile having the given header types and containing input VSI
16578c2ecf20Sopenharmony_ci */
16588c2ecf20Sopenharmony_ciu64 ice_get_rss_cfg(struct ice_hw *hw, u16 vsi_handle, u32 hdrs)
16598c2ecf20Sopenharmony_ci{
16608c2ecf20Sopenharmony_ci	u64 rss_hash = ICE_HASH_INVALID;
16618c2ecf20Sopenharmony_ci	struct ice_rss_cfg *r;
16628c2ecf20Sopenharmony_ci
16638c2ecf20Sopenharmony_ci	/* verify if the protocol header is non zero and VSI is valid */
16648c2ecf20Sopenharmony_ci	if (hdrs == ICE_FLOW_SEG_HDR_NONE || !ice_is_vsi_valid(hw, vsi_handle))
16658c2ecf20Sopenharmony_ci		return ICE_HASH_INVALID;
16668c2ecf20Sopenharmony_ci
16678c2ecf20Sopenharmony_ci	mutex_lock(&hw->rss_locks);
16688c2ecf20Sopenharmony_ci	list_for_each_entry(r, &hw->rss_list_head, l_entry)
16698c2ecf20Sopenharmony_ci		if (test_bit(vsi_handle, r->vsis) &&
16708c2ecf20Sopenharmony_ci		    r->packet_hdr == hdrs) {
16718c2ecf20Sopenharmony_ci			rss_hash = r->hashed_flds;
16728c2ecf20Sopenharmony_ci			break;
16738c2ecf20Sopenharmony_ci		}
16748c2ecf20Sopenharmony_ci	mutex_unlock(&hw->rss_locks);
16758c2ecf20Sopenharmony_ci
16768c2ecf20Sopenharmony_ci	return rss_hash;
16778c2ecf20Sopenharmony_ci}
1678