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