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