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 = ¶ms->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(¶ms, 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(¶ms.prof->segs[i], &segs[i], sizeof(*segs)); 7408c2ecf20Sopenharmony_ci 7418c2ecf20Sopenharmony_ci status = ice_flow_proc_segs(hw, ¶ms); 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(¶ms.prof->entries); 7568c2ecf20Sopenharmony_ci mutex_init(¶ms.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