net/ice/base: fix mask for checking protocol header
[dpdk.git] / drivers / net / ice / base / ice_flow.c
index 1530a72..682f26c 100644 (file)
@@ -19,6 +19,8 @@
 #define ICE_FLOW_FLD_SZ_ICMP_CODE      1
 #define ICE_FLOW_FLD_SZ_ARP_OPER       2
 #define ICE_FLOW_FLD_SZ_GRE_KEYID      4
+#define ICE_FLOW_FLD_SZ_GTP_TEID       4
+#define ICE_FLOW_FLD_SZ_PPPOE_SESS_ID   2
 
 /* Protocol header fields are extracted at the word boundaries as word-sized
  * values. Specify the displacement value of some non-word-aligned fields needed
@@ -115,6 +117,23 @@ struct ice_flow_field_info ice_flds_info[ICE_FLOW_FIELD_IDX_MAX] = {
        /* GRE */
        /* ICE_FLOW_FIELD_IDX_GRE_KEYID */
        ICE_FLOW_FLD_INFO(ICE_FLOW_SEG_HDR_GRE, 12, ICE_FLOW_FLD_SZ_GRE_KEYID),
+       /* GTP */
+       /* ICE_FLOW_FIELD_IDX_GTPC_TEID */
+       ICE_FLOW_FLD_INFO(ICE_FLOW_SEG_HDR_GTPC_TEID, 12,
+                         ICE_FLOW_FLD_SZ_GTP_TEID),
+       /* ICE_FLOW_FIELD_IDX_GTPU_IP_TEID */
+       ICE_FLOW_FLD_INFO(ICE_FLOW_SEG_HDR_GTPU_IP, 12,
+                         ICE_FLOW_FLD_SZ_GTP_TEID),
+       /* ICE_FLOW_FIELD_IDX_GTPU_UP_TEID */
+       ICE_FLOW_FLD_INFO(ICE_FLOW_SEG_HDR_GTPU_UP, 12,
+                         ICE_FLOW_FLD_SZ_GTP_TEID),
+       /* ICE_FLOW_FIELD_IDX_GTPU_DWN_TEID */
+       ICE_FLOW_FLD_INFO(ICE_FLOW_SEG_HDR_GTPU_DWN, 12,
+                         ICE_FLOW_FLD_SZ_GTP_TEID),
+       /* PPPOE */
+       /* ICE_FLOW_FIELD_IDX_PPPOE_SESS_ID */
+       ICE_FLOW_FLD_INFO(ICE_FLOW_SEG_HDR_PPPOE, 2,
+                         ICE_FLOW_FLD_SZ_PPPOE_SESS_ID),
 };
 
 /* Bitmaps indicating relevant packet types for a particular protocol header
@@ -124,7 +143,7 @@ struct ice_flow_field_info ice_flds_info[ICE_FLOW_FIELD_IDX_MAX] = {
 static const u32 ice_ptypes_mac_ofos[] = {
        0xFDC00CC6, 0xBFBF7F7E, 0xF7EFDFDF, 0xFEFDFDFB,
        0x03BF7F7E, 0x00000000, 0x00000000, 0x00000000,
-       0x000B0F0F, 0x00000000, 0x00000000, 0x00000000,
+       0x000B0F0F, 0x00003000, 0x00000000, 0x00000000,
        0x00000000, 0x00000000, 0x00000000, 0x00000000,
        0x00000000, 0x00000000, 0x00000000, 0x00000000,
        0x00000000, 0x00000000, 0x00000000, 0x00000000,
@@ -148,7 +167,7 @@ static const u32 ice_ptypes_macvlan_il[] = {
 static const u32 ice_ptypes_ipv4_ofos[] = {
        0xFDC00000, 0xBFBF7F7E, 0x00EFDFDF, 0x00000000,
        0x00000000, 0x00000000, 0x00000000, 0x00000000,
-       0x0003000F, 0x00000000, 0x00000000, 0x00000000,
+       0x0003000F, 0x000FC000, 0x00000000, 0x00000000,
        0x00000000, 0x00000000, 0x00000000, 0x00000000,
        0x00000000, 0x00000000, 0x00000000, 0x00000000,
        0x00000000, 0x00000000, 0x00000000, 0x00000000,
@@ -160,7 +179,7 @@ static const u32 ice_ptypes_ipv4_ofos[] = {
 static const u32 ice_ptypes_ipv4_il[] = {
        0xE0000000, 0xB807700E, 0x8001DC03, 0xE01DC03B,
        0x0007700E, 0x00000000, 0x00000000, 0x00000000,
-       0x00000000, 0x00000000, 0x00000000, 0x00000000,
+       0x00000000, 0x00000000, 0x000FF800, 0x00000000,
        0x00000000, 0x00000000, 0x00000000, 0x00000000,
        0x00000000, 0x00000000, 0x00000000, 0x00000000,
        0x00000000, 0x00000000, 0x00000000, 0x00000000,
@@ -172,7 +191,7 @@ static const u32 ice_ptypes_ipv4_il[] = {
 static const u32 ice_ptypes_ipv6_ofos[] = {
        0x00000000, 0x00000000, 0xF7000000, 0xFEFDFDFB,
        0x03BF7F7E, 0x00000000, 0x00000000, 0x00000000,
-       0x00080F00, 0x00000000, 0x00000000, 0x00000000,
+       0x00080F00, 0x03F00000, 0x00000000, 0x00000000,
        0x00000000, 0x00000000, 0x00000000, 0x00000000,
        0x00000000, 0x00000000, 0x00000000, 0x00000000,
        0x00000000, 0x00000000, 0x00000000, 0x00000000,
@@ -184,7 +203,7 @@ static const u32 ice_ptypes_ipv6_ofos[] = {
 static const u32 ice_ptypes_ipv6_il[] = {
        0x00000000, 0x03B80770, 0x00EE01DC, 0x0EE00000,
        0x03B80770, 0x00000000, 0x00000000, 0x00000000,
-       0x00000000, 0x00000000, 0x00000000, 0x00000000,
+       0x00000000, 0x00000000, 0x7FE00000, 0x00000000,
        0x00000000, 0x00000000, 0x00000000, 0x00000000,
        0x00000000, 0x00000000, 0x00000000, 0x00000000,
        0x00000000, 0x00000000, 0x00000000, 0x00000000,
@@ -210,7 +229,7 @@ static const u32 ice_ptypes_arp_of[] = {
 static const u32 ice_ptypes_udp_il[] = {
        0x81000000, 0x20204040, 0x04081010, 0x80810102,
        0x00204040, 0x00000000, 0x00000000, 0x00000000,
-       0x00000000, 0x00000000, 0x00000000, 0x00000000,
+       0x00000000, 0x00410000, 0x10842000, 0x00000000,
        0x00000000, 0x00000000, 0x00000000, 0x00000000,
        0x00000000, 0x00000000, 0x00000000, 0x00000000,
        0x00000000, 0x00000000, 0x00000000, 0x00000000,
@@ -222,7 +241,7 @@ static const u32 ice_ptypes_udp_il[] = {
 static const u32 ice_ptypes_tcp_il[] = {
        0x04000000, 0x80810102, 0x10204040, 0x42040408,
        0x00810102, 0x00000000, 0x00000000, 0x00000000,
-       0x00000000, 0x00000000, 0x00000000, 0x00000000,
+       0x00000000, 0x00820000, 0x21084000, 0x00000000,
        0x00000000, 0x00000000, 0x00000000, 0x00000000,
        0x00000000, 0x00000000, 0x00000000, 0x00000000,
        0x00000000, 0x00000000, 0x00000000, 0x00000000,
@@ -258,7 +277,7 @@ static const u32 ice_ptypes_icmp_of[] = {
 static const u32 ice_ptypes_icmp_il[] = {
        0x00000000, 0x02040408, 0x40810102, 0x08101020,
        0x02040408, 0x00000000, 0x00000000, 0x00000000,
-       0x00000000, 0x00000000, 0x00000000, 0x00000000,
+       0x00000000, 0x00000000, 0x42108000, 0x00000000,
        0x00000000, 0x00000000, 0x00000000, 0x00000000,
        0x00000000, 0x00000000, 0x00000000, 0x00000000,
        0x00000000, 0x00000000, 0x00000000, 0x00000000,
@@ -290,6 +309,54 @@ static const u32 ice_ptypes_mac_il[] = {
        0x00000000, 0x00000000, 0x00000000, 0x00000000,
 };
 
+/* Packet types for GTPC */
+static const u32 ice_ptypes_gtpc[] = {
+       0x00000000, 0x00000000, 0x00000000, 0x00000000,
+       0x00000000, 0x00000000, 0x00000000, 0x00000000,
+       0x00000000, 0x00000000, 0x00000180, 0x00000000,
+       0x00000000, 0x00000000, 0x00000000, 0x00000000,
+       0x00000000, 0x00000000, 0x00000000, 0x00000000,
+       0x00000000, 0x00000000, 0x00000000, 0x00000000,
+       0x00000000, 0x00000000, 0x00000000, 0x00000000,
+       0x00000000, 0x00000000, 0x00000000, 0x00000000,
+};
+
+/* Packet types for GTPC with TEID */
+static const u32 ice_ptypes_gtpc_tid[] = {
+       0x00000000, 0x00000000, 0x00000000, 0x00000000,
+       0x00000000, 0x00000000, 0x00000000, 0x00000000,
+       0x00000000, 0x00000000, 0x00000060, 0x00000000,
+       0x00000000, 0x00000000, 0x00000000, 0x00000000,
+       0x00000000, 0x00000000, 0x00000000, 0x00000000,
+       0x00000000, 0x00000000, 0x00000000, 0x00000000,
+       0x00000000, 0x00000000, 0x00000000, 0x00000000,
+       0x00000000, 0x00000000, 0x00000000, 0x00000000,
+};
+
+/* Packet types for GTPU */
+static const u32 ice_ptypes_gtpu[] = {
+       0x00000000, 0x00000000, 0x00000000, 0x00000000,
+       0x00000000, 0x00000000, 0x00000000, 0x00000000,
+       0x00000000, 0x00000000, 0x7FFFF800, 0x00000000,
+       0x00000000, 0x00000000, 0x00000000, 0x00000000,
+       0x00000000, 0x00000000, 0x00000000, 0x00000000,
+       0x00000000, 0x00000000, 0x00000000, 0x00000000,
+       0x00000000, 0x00000000, 0x00000000, 0x00000000,
+       0x00000000, 0x00000000, 0x00000000, 0x00000000,
+};
+
+/* Packet types for pppoe */
+static const u32 ice_ptypes_pppoe[] = {
+       0x00000000, 0x00000000, 0x00000000, 0x00000000,
+       0x00000000, 0x00000000, 0x00000000, 0x00000000,
+       0x00000000, 0x03FFF000, 0x00000000, 0x00000000,
+       0x00000000, 0x00000000, 0x00000000, 0x00000000,
+       0x00000000, 0x00000000, 0x00000000, 0x00000000,
+       0x00000000, 0x00000000, 0x00000000, 0x00000000,
+       0x00000000, 0x00000000, 0x00000000, 0x00000000,
+       0x00000000, 0x00000000, 0x00000000, 0x00000000,
+};
+
 /* Manage parameters and info. used during the creation of a flow profile */
 struct ice_flow_prof_params {
        enum ice_block blk;
@@ -305,19 +372,15 @@ struct ice_flow_prof_params {
        ice_declare_bitmap(ptypes, ICE_FLOW_PTYPE_MAX);
 };
 
-/**
- * ice_is_pow2 - check if integer value is a power of 2
- * @val: unsigned integer to be validated
- */
-static bool ice_is_pow2(u64 val)
-{
-       return (val && !(val & (val - 1)));
-}
+#define ICE_FLOW_RSS_HDRS_INNER_MASK \
+       (ICE_FLOW_SEG_HDR_PPPOE | ICE_FLOW_SEG_HDR_GTPC | \
+        ICE_FLOW_SEG_HDR_GTPC_TEID | ICE_FLOW_SEG_HDR_GTPU)
 
 #define ICE_FLOW_SEG_HDRS_L2_MASK      \
        (ICE_FLOW_SEG_HDR_ETH | ICE_FLOW_SEG_HDR_VLAN)
 #define ICE_FLOW_SEG_HDRS_L3_MASK      \
-       (ICE_FLOW_SEG_HDR_IPV4 | ICE_FLOW_SEG_HDR_IPV6 | ICE_FLOW_SEG_HDR_ARP)
+       (ICE_FLOW_SEG_HDR_IPV4 | ICE_FLOW_SEG_HDR_IPV6 | \
+        ICE_FLOW_SEG_HDR_ARP)
 #define ICE_FLOW_SEG_HDRS_L4_MASK      \
        (ICE_FLOW_SEG_HDR_ICMP | ICE_FLOW_SEG_HDR_TCP | ICE_FLOW_SEG_HDR_UDP | \
         ICE_FLOW_SEG_HDR_SCTP)
@@ -330,16 +393,9 @@ static bool ice_is_pow2(u64 val)
 static enum ice_status
 ice_flow_val_hdrs(struct ice_flow_seg_info *segs, u8 segs_cnt)
 {
-       const u32 masks = (ICE_FLOW_SEG_HDRS_L2_MASK |
-                          ICE_FLOW_SEG_HDRS_L3_MASK |
-                          ICE_FLOW_SEG_HDRS_L4_MASK);
        u8 i;
 
        for (i = 0; i < segs_cnt; i++) {
-               /* No header specified */
-               if (!(segs[i].hdrs & masks) || (segs[i].hdrs & ~masks))
-                       return ICE_ERR_PARAM;
-
                /* Multiple L3 headers */
                if (segs[i].hdrs & ICE_FLOW_SEG_HDRS_L3_MASK &&
                    !ice_is_pow2(segs[i].hdrs & ICE_FLOW_SEG_HDRS_L3_MASK))
@@ -431,21 +487,24 @@ ice_flow_proc_seg_hdrs(struct ice_flow_prof_params *params)
                                (const ice_bitmap_t *)ice_ptypes_mac_il;
                        ice_and_bitmap(params->ptypes, params->ptypes, src,
                                       ICE_FLOW_PTYPE_MAX);
-                       hdrs &= ~ICE_FLOW_SEG_HDR_ETH;
                }
 
                if (i && hdrs & ICE_FLOW_SEG_HDR_VLAN) {
                        src = (const ice_bitmap_t *)ice_ptypes_macvlan_il;
                        ice_and_bitmap(params->ptypes, params->ptypes, src,
                                       ICE_FLOW_PTYPE_MAX);
-                       hdrs &= ~ICE_FLOW_SEG_HDR_VLAN;
                }
 
                if (!i && hdrs & ICE_FLOW_SEG_HDR_ARP) {
                        ice_and_bitmap(params->ptypes, params->ptypes,
                                       (const ice_bitmap_t *)ice_ptypes_arp_of,
                                       ICE_FLOW_PTYPE_MAX);
-                       hdrs &= ~ICE_FLOW_SEG_HDR_ARP;
+               }
+
+               if (hdrs & ICE_FLOW_SEG_HDR_PPPOE) {
+                       src = (const ice_bitmap_t *)ice_ptypes_pppoe;
+                       ice_and_bitmap(params->ptypes, params->ptypes, src,
+                                      ICE_FLOW_PTYPE_MAX);
                }
 
                if (hdrs & ICE_FLOW_SEG_HDR_IPV4) {
@@ -453,13 +512,11 @@ ice_flow_proc_seg_hdrs(struct ice_flow_prof_params *params)
                                (const ice_bitmap_t *)ice_ptypes_ipv4_il;
                        ice_and_bitmap(params->ptypes, params->ptypes, src,
                                       ICE_FLOW_PTYPE_MAX);
-                       hdrs &= ~ICE_FLOW_SEG_HDR_IPV4;
                } else if (hdrs & ICE_FLOW_SEG_HDR_IPV6) {
                        src = !i ? (const ice_bitmap_t *)ice_ptypes_ipv6_ofos :
                                (const ice_bitmap_t *)ice_ptypes_ipv6_il;
                        ice_and_bitmap(params->ptypes, params->ptypes, src,
                                       ICE_FLOW_PTYPE_MAX);
-                       hdrs &= ~ICE_FLOW_SEG_HDR_IPV6;
                }
 
                if (hdrs & ICE_FLOW_SEG_HDR_ICMP) {
@@ -467,29 +524,42 @@ ice_flow_proc_seg_hdrs(struct ice_flow_prof_params *params)
                                (const ice_bitmap_t *)ice_ptypes_icmp_il;
                        ice_and_bitmap(params->ptypes, params->ptypes, src,
                                       ICE_FLOW_PTYPE_MAX);
-                       hdrs &= ~ICE_FLOW_SEG_HDR_ICMP;
                } else if (hdrs & ICE_FLOW_SEG_HDR_UDP) {
                        src = (const ice_bitmap_t *)ice_ptypes_udp_il;
                        ice_and_bitmap(params->ptypes, params->ptypes, src,
                                       ICE_FLOW_PTYPE_MAX);
-                       hdrs &= ~ICE_FLOW_SEG_HDR_UDP;
                } else if (hdrs & ICE_FLOW_SEG_HDR_TCP) {
                        ice_and_bitmap(params->ptypes, params->ptypes,
                                       (const ice_bitmap_t *)ice_ptypes_tcp_il,
                                       ICE_FLOW_PTYPE_MAX);
-                       hdrs &= ~ICE_FLOW_SEG_HDR_TCP;
                } else if (hdrs & ICE_FLOW_SEG_HDR_SCTP) {
                        src = (const ice_bitmap_t *)ice_ptypes_sctp_il;
                        ice_and_bitmap(params->ptypes, params->ptypes, src,
                                       ICE_FLOW_PTYPE_MAX);
-                       hdrs &= ~ICE_FLOW_SEG_HDR_SCTP;
                } else if (hdrs & ICE_FLOW_SEG_HDR_GRE) {
                        if (!i) {
                                src = (const ice_bitmap_t *)ice_ptypes_gre_of;
                                ice_and_bitmap(params->ptypes, params->ptypes,
                                               src, ICE_FLOW_PTYPE_MAX);
                        }
-                       hdrs &= ~ICE_FLOW_SEG_HDR_GRE;
+               } else if (hdrs & ICE_FLOW_SEG_HDR_GTPC) {
+                       if (!i) {
+                               src = (const ice_bitmap_t *)ice_ptypes_gtpc;
+                               ice_and_bitmap(params->ptypes, params->ptypes,
+                                              src, ICE_FLOW_PTYPE_MAX);
+                       }
+               } else if (hdrs & ICE_FLOW_SEG_HDR_GTPC_TEID) {
+                       if (!i) {
+                               src = (const ice_bitmap_t *)ice_ptypes_gtpc_tid;
+                               ice_and_bitmap(params->ptypes, params->ptypes,
+                                              src, ICE_FLOW_PTYPE_MAX);
+                       }
+               } else if (hdrs & ICE_FLOW_SEG_HDR_GTPU) {
+                       if (!i) {
+                               src = (const ice_bitmap_t *)ice_ptypes_gtpu;
+                               ice_and_bitmap(params->ptypes, params->ptypes,
+                                              src, ICE_FLOW_PTYPE_MAX);
+                       }
                }
        }
 
@@ -500,7 +570,7 @@ ice_flow_proc_seg_hdrs(struct ice_flow_prof_params *params)
  * ice_flow_xtract_pkt_flags - Create an extr sequence entry for packet flags
  * @hw: pointer to the HW struct
  * @params: information about the flow to be processed
- * @flags: The value of pkt_flags[x:x] in RX/TX MDID metadata.
+ * @flags: The value of pkt_flags[x:x] in Rx/Tx MDID metadata.
  *
  * This function will allocate an extraction sequence entries for a DWORD size
  * chunk of the packet flags.
@@ -613,12 +683,22 @@ ice_flow_xtract_fld(struct ice_hw *hw, struct ice_flow_prof_params *params,
                break;
        case ICE_FLOW_FIELD_IDX_UDP_SRC_PORT:
        case ICE_FLOW_FIELD_IDX_UDP_DST_PORT:
-               prot_id = seg == 0 ? ICE_PROT_UDP_IL_OR_S : ICE_PROT_UDP_OF;
+               prot_id = ICE_PROT_UDP_IL_OR_S;
                break;
        case ICE_FLOW_FIELD_IDX_SCTP_SRC_PORT:
        case ICE_FLOW_FIELD_IDX_SCTP_DST_PORT:
                prot_id = ICE_PROT_SCTP_IL;
                break;
+       case ICE_FLOW_FIELD_IDX_GTPC_TEID:
+       case ICE_FLOW_FIELD_IDX_GTPU_IP_TEID:
+       case ICE_FLOW_FIELD_IDX_GTPU_UP_TEID:
+       case ICE_FLOW_FIELD_IDX_GTPU_DWN_TEID:
+               /* GTP is accessed through UDP OF protocol */
+               prot_id = ICE_PROT_UDP_OF;
+               break;
+       case ICE_FLOW_FIELD_IDX_PPPOE_SESS_ID:
+               prot_id = ICE_PROT_PPPOE;
+               break;
        case ICE_FLOW_FIELD_IDX_ARP_SIP:
        case ICE_FLOW_FIELD_IDX_ARP_DIP:
        case ICE_FLOW_FIELD_IDX_ARP_SHA:
@@ -873,8 +953,9 @@ ice_flow_find_prof_conds(struct ice_hw *hw, enum ice_block blk,
                         enum ice_flow_dir dir, struct ice_flow_seg_info *segs,
                         u8 segs_cnt, u16 vsi_handle, u32 conds)
 {
-       struct ice_flow_prof *p;
+       struct ice_flow_prof *p, *prof = NULL;
 
+       ice_acquire_lock(&hw->fl_profs_locks[blk]);
        LIST_FOR_EACH_ENTRY(p, &hw->fl_profs[blk], ice_flow_prof, l_entry) {
                if ((p->dir == dir || conds & ICE_FLOW_FIND_PROF_NOT_CHK_DIR) &&
                    segs_cnt && segs_cnt == p->segs_cnt) {
@@ -896,12 +977,15 @@ ice_flow_find_prof_conds(struct ice_hw *hw, enum ice_block blk,
                                        break;
 
                        /* A match is found if all segments are matched */
-                       if (i == segs_cnt)
-                               return p;
+                       if (i == segs_cnt) {
+                               prof = p;
+                               break;
+                       }
                }
        }
+       ice_release_lock(&hw->fl_profs_locks[blk]);
 
-       return NULL;
+       return prof;
 }
 
 /**
@@ -918,10 +1002,8 @@ ice_flow_find_prof(struct ice_hw *hw, enum ice_block blk, enum ice_flow_dir dir,
 {
        struct ice_flow_prof *p;
 
-       ice_acquire_lock(&hw->fl_profs_locks[blk]);
        p = ice_flow_find_prof_conds(hw, blk, dir, segs, segs_cnt,
                                     ICE_MAX_VSI, ICE_FLOW_FIND_PROF_CHK_FLDS);
-       ice_release_lock(&hw->fl_profs_locks[blk]);
 
        return p ? p->id : ICE_FLOW_PROF_ID_INVAL;
 }
@@ -1421,9 +1503,12 @@ ice_flow_add_entry(struct ice_hw *hw, enum ice_block blk, u64 prof_id,
                goto out;
        }
 
-       ice_acquire_lock(&prof->entries_lock);
-       LIST_ADD(&e->l_entry, &prof->entries);
-       ice_release_lock(&prof->entries_lock);
+       if (blk != ICE_BLK_ACL) {
+               /* ACL will handle the entry management */
+               ice_acquire_lock(&prof->entries_lock);
+               LIST_ADD(&e->l_entry, &prof->entries);
+               ice_release_lock(&prof->entries_lock);
+       }
 
        *entry_h = ICE_FLOW_ENTRY_HNDL(e);
 
@@ -1600,6 +1685,9 @@ ice_flow_add_fld_raw(struct ice_flow_seg_info *seg, u16 off, u8 len,
        seg->raws_cnt++;
 }
 
+#define ICE_FLOW_RSS_SEG_HDR_L2_MASKS \
+(ICE_FLOW_SEG_HDR_ETH | ICE_FLOW_SEG_HDR_VLAN)
+
 #define ICE_FLOW_RSS_SEG_HDR_L3_MASKS \
        (ICE_FLOW_SEG_HDR_IPV4 | ICE_FLOW_SEG_HDR_IPV6)
 
@@ -1608,7 +1696,8 @@ ice_flow_add_fld_raw(struct ice_flow_seg_info *seg, u16 off, u8 len,
         ICE_FLOW_SEG_HDR_SCTP)
 
 #define ICE_FLOW_RSS_SEG_HDR_VAL_MASKS \
-       (ICE_FLOW_RSS_SEG_HDR_L3_MASKS | \
+       (ICE_FLOW_RSS_SEG_HDR_L2_MASKS | \
+        ICE_FLOW_RSS_SEG_HDR_L3_MASKS | \
         ICE_FLOW_RSS_SEG_HDR_L4_MASKS)
 
 /**
@@ -1641,11 +1730,12 @@ ice_flow_set_rss_seg_info(struct ice_flow_seg_info *segs, u64 hash_fields,
        }
        ICE_FLOW_SET_HDRS(segs, flow_hdr);
 
-       if (segs->hdrs & ~ICE_FLOW_RSS_SEG_HDR_VAL_MASKS)
+       if (segs->hdrs & ~ICE_FLOW_RSS_SEG_HDR_VAL_MASKS &
+           ~ICE_FLOW_RSS_HDRS_INNER_MASK)
                return ICE_ERR_PARAM;
 
        val = (u64)(segs->hdrs & ICE_FLOW_RSS_SEG_HDR_L3_MASKS);
-       if (!ice_is_pow2(val))
+       if (val && !ice_is_pow2(val))
                return ICE_ERR_CFG;
 
        val = (u64)(segs->hdrs & ICE_FLOW_RSS_SEG_HDR_L4_MASKS);
@@ -1793,11 +1883,22 @@ ice_add_rss_list(struct ice_hw *hw, u16 vsi_handle, struct ice_flow_prof *prof)
 #define ICE_FLOW_PROF_HASH_S   0
 #define ICE_FLOW_PROF_HASH_M   (0xFFFFFFFFULL << ICE_FLOW_PROF_HASH_S)
 #define ICE_FLOW_PROF_HDR_S    32
-#define ICE_FLOW_PROF_HDR_M    (0xFFFFFFFFULL << ICE_FLOW_PROF_HDR_S)
+#define ICE_FLOW_PROF_HDR_M    (0x3FFFFFFFULL << ICE_FLOW_PROF_HDR_S)
+#define ICE_FLOW_PROF_ENCAP_S  63
+#define ICE_FLOW_PROF_ENCAP_M  (BIT_ULL(ICE_FLOW_PROF_ENCAP_S))
 
-#define ICE_FLOW_GEN_PROFID(hash, hdr) \
+#define ICE_RSS_OUTER_HEADERS  1
+#define ICE_RSS_INNER_HEADERS  2
+
+/* Flow profile ID format:
+ * [0:31] - Packet match fields
+ * [32:62] - Protocol header
+ * [63] - Encapsulation flag, 0 if non-tunneled, 1 if tunneled
+ */
+#define ICE_FLOW_GEN_PROFID(hash, hdr, segs_cnt) \
        (u64)(((u64)(hash) & ICE_FLOW_PROF_HASH_M) | \
-             (((u64)(hdr) << ICE_FLOW_PROF_HDR_S) & ICE_FLOW_PROF_HDR_M))
+             (((u64)(hdr) << ICE_FLOW_PROF_HDR_S) & ICE_FLOW_PROF_HDR_M) | \
+             ((u8)((segs_cnt) - 1) ? ICE_FLOW_PROF_ENCAP_M : 0))
 
 /**
  * ice_add_rss_cfg_sync - add an RSS configuration
@@ -1805,24 +1906,30 @@ ice_add_rss_list(struct ice_hw *hw, u16 vsi_handle, struct ice_flow_prof *prof)
  * @vsi_handle: software VSI handle
  * @hashed_flds: hash bit fields (ICE_FLOW_HASH_*) to configure
  * @addl_hdrs: protocol header fields
+ * @segs_cnt: packet segment count
  *
  * Assumption: lock has already been acquired for RSS list
  */
 static enum ice_status
 ice_add_rss_cfg_sync(struct ice_hw *hw, u16 vsi_handle, u64 hashed_flds,
-                    u32 addl_hdrs)
+                    u32 addl_hdrs, u8 segs_cnt)
 {
        const enum ice_block blk = ICE_BLK_RSS;
        struct ice_flow_prof *prof = NULL;
        struct ice_flow_seg_info *segs;
        enum ice_status status = ICE_SUCCESS;
 
-       segs = (struct ice_flow_seg_info *)ice_malloc(hw, sizeof(*segs));
+       if (!segs_cnt || segs_cnt > ICE_FLOW_SEG_MAX)
+               return ICE_ERR_PARAM;
+
+       segs = (struct ice_flow_seg_info *)ice_calloc(hw, segs_cnt,
+                                                     sizeof(*segs));
        if (!segs)
                return ICE_ERR_NO_MEMORY;
 
        /* Construct the packet segment info from the hashed fields */
-       status = ice_flow_set_rss_seg_info(segs, hashed_flds, addl_hdrs);
+       status = ice_flow_set_rss_seg_info(&segs[segs_cnt - 1], hashed_flds,
+                                          addl_hdrs);
        if (status)
                goto exit;
 
@@ -1830,7 +1937,7 @@ ice_add_rss_cfg_sync(struct ice_hw *hw, u16 vsi_handle, u64 hashed_flds,
         * and has the input VSI associated to it. If found, no further
         * operations required and exit.
         */
-       prof = ice_flow_find_prof_conds(hw, blk, ICE_FLOW_RX, segs, 1,
+       prof = ice_flow_find_prof_conds(hw, blk, ICE_FLOW_RX, segs, segs_cnt,
                                        vsi_handle,
                                        ICE_FLOW_FIND_PROF_CHK_FLDS |
                                        ICE_FLOW_FIND_PROF_CHK_VSI);
@@ -1842,7 +1949,7 @@ ice_add_rss_cfg_sync(struct ice_hw *hw, u16 vsi_handle, u64 hashed_flds,
         * this profile. The VSI will be added to a new profile created with
         * the protocol header and new hash field configuration.
         */
-       prof = ice_flow_find_prof_conds(hw, blk, ICE_FLOW_RX, segs, 1,
+       prof = ice_flow_find_prof_conds(hw, blk, ICE_FLOW_RX, segs, segs_cnt,
                                        vsi_handle, ICE_FLOW_FIND_PROF_CHK_VSI);
        if (prof) {
                status = ice_flow_disassoc_prof(hw, blk, prof, vsi_handle);
@@ -1853,7 +1960,7 @@ ice_add_rss_cfg_sync(struct ice_hw *hw, u16 vsi_handle, u64 hashed_flds,
 
                /* Remove profile if it has no VSIs associated */
                if (!ice_is_any_bit_set(prof->vsis, ICE_MAX_VSI)) {
-                       status = ice_flow_rem_prof_sync(hw, blk, prof);
+                       status = ice_flow_rem_prof(hw, blk, prof->id);
                        if (status)
                                goto exit;
                }
@@ -1862,7 +1969,7 @@ ice_add_rss_cfg_sync(struct ice_hw *hw, u16 vsi_handle, u64 hashed_flds,
        /* Search for a profile that has same match fields only. If this
         * exists then associate the VSI to this profile.
         */
-       prof = ice_flow_find_prof_conds(hw, blk, ICE_FLOW_RX, segs, 1,
+       prof = ice_flow_find_prof_conds(hw, blk, ICE_FLOW_RX, segs, segs_cnt,
                                        vsi_handle,
                                        ICE_FLOW_FIND_PROF_CHK_FLDS);
        if (prof) {
@@ -1876,8 +1983,10 @@ ice_add_rss_cfg_sync(struct ice_hw *hw, u16 vsi_handle, u64 hashed_flds,
         * segment information.
         */
        status = ice_flow_add_prof(hw, blk, ICE_FLOW_RX,
-                                  ICE_FLOW_GEN_PROFID(hashed_flds, segs->hdrs),
-                                  segs, 1, NULL, 0, &prof);
+                                  ICE_FLOW_GEN_PROFID(hashed_flds,
+                                                      segs[segs_cnt - 1].hdrs,
+                                                      segs_cnt),
+                                  segs, segs_cnt, NULL, 0, &prof);
        if (status)
                goto exit;
 
@@ -1886,7 +1995,7 @@ ice_add_rss_cfg_sync(struct ice_hw *hw, u16 vsi_handle, u64 hashed_flds,
         * be removed.
         */
        if (status) {
-               ice_flow_rem_prof_sync(hw, blk, prof);
+               ice_flow_rem_prof(hw, blk, prof->id);
                goto exit;
        }
 
@@ -1919,7 +2028,11 @@ ice_add_rss_cfg(struct ice_hw *hw, u16 vsi_handle, u64 hashed_flds,
                return ICE_ERR_PARAM;
 
        ice_acquire_lock(&hw->rss_locks);
-       status = ice_add_rss_cfg_sync(hw, vsi_handle, hashed_flds, addl_hdrs);
+       status = ice_add_rss_cfg_sync(hw, vsi_handle, hashed_flds, addl_hdrs,
+                                     ICE_RSS_OUTER_HEADERS);
+       if (!status)
+               status = ice_add_rss_cfg_sync(hw, vsi_handle, hashed_flds,
+                                             addl_hdrs, ICE_RSS_INNER_HEADERS);
        ice_release_lock(&hw->rss_locks);
 
        return status;
@@ -1931,12 +2044,13 @@ ice_add_rss_cfg(struct ice_hw *hw, u16 vsi_handle, u64 hashed_flds,
  * @vsi_handle: software VSI handle
  * @hashed_flds: Packet hash types (ICE_FLOW_HASH_*) to remove
  * @addl_hdrs: Protocol header fields within a packet segment
+ * @segs_cnt: packet segment count
  *
  * Assumption: lock has already been acquired for RSS list
  */
 static enum ice_status
 ice_rem_rss_cfg_sync(struct ice_hw *hw, u16 vsi_handle, u64 hashed_flds,
-                    u32 addl_hdrs)
+                    u32 addl_hdrs, u8 segs_cnt)
 {
        const enum ice_block blk = ICE_BLK_RSS;
        struct ice_flow_seg_info *segs;
@@ -1952,7 +2066,7 @@ ice_rem_rss_cfg_sync(struct ice_hw *hw, u16 vsi_handle, u64 hashed_flds,
        if (status)
                goto out;
 
-       prof = ice_flow_find_prof_conds(hw, blk, ICE_FLOW_RX, segs, 1,
+       prof = ice_flow_find_prof_conds(hw, blk, ICE_FLOW_RX, segs, segs_cnt,
                                        vsi_handle,
                                        ICE_FLOW_FIND_PROF_CHK_FLDS);
        if (!prof) {
@@ -1970,13 +2084,47 @@ ice_rem_rss_cfg_sync(struct ice_hw *hw, u16 vsi_handle, u64 hashed_flds,
        ice_rem_rss_list(hw, vsi_handle, prof);
 
        if (!ice_is_any_bit_set(prof->vsis, ICE_MAX_VSI))
-               status = ice_flow_rem_prof_sync(hw, blk, prof);
+               status = ice_flow_rem_prof(hw, blk, prof->id);
 
 out:
        ice_free(hw, segs);
        return status;
 }
 
+/**
+ * ice_rem_rss_cfg - remove an existing RSS config with matching hashed fields
+ * @hw: pointer to the hardware structure
+ * @vsi_handle: software VSI handle
+ * @hashed_flds: Packet hash types (ICE_FLOW_HASH_*) to remove
+ * @addl_hdrs: Protocol header fields within a packet segment
+ *
+ * This function will lookup the flow profile based on the input
+ * hash field bitmap, iterate through the profile entry list of
+ * that profile and find entry associated with input VSI to be
+ * removed. Calls are made to underlying flow apis which will in
+ * turn build or update buffers for RSS XLT1 section.
+ */
+enum ice_status
+ice_rem_rss_cfg(struct ice_hw *hw, u16 vsi_handle, u64 hashed_flds,
+               u32 addl_hdrs)
+{
+       enum ice_status status;
+
+       if (hashed_flds == ICE_HASH_INVALID ||
+           !ice_is_vsi_valid(hw, vsi_handle))
+               return ICE_ERR_PARAM;
+
+       ice_acquire_lock(&hw->rss_locks);
+       status = ice_rem_rss_cfg_sync(hw, vsi_handle, hashed_flds, addl_hdrs,
+                                     ICE_RSS_OUTER_HEADERS);
+       if (!status)
+               status = ice_rem_rss_cfg_sync(hw, vsi_handle, hashed_flds,
+                                             addl_hdrs, ICE_RSS_INNER_HEADERS);
+       ice_release_lock(&hw->rss_locks);
+
+       return status;
+}
+
 /* Mapping of AVF hash bit fields to an L3-L4 hash combination.
  * As the ice_flow_avf_hdr_field represent individual bit shifts in a hash,
  * convert its values to their appropriate flow L3, L4 values.
@@ -2105,36 +2253,6 @@ ice_add_avf_rss_cfg(struct ice_hw *hw, u16 vsi_handle, u64 avf_hash)
        return status;
 }
 
-/**
- * ice_rem_rss_cfg - remove an existing RSS config with matching hashed fields
- * @hw: pointer to the hardware structure
- * @vsi_handle: software VSI handle
- * @hashed_flds: Packet hash types (ICE_FLOW_HASH_*) to remove
- * @addl_hdrs: Protocol header fields within a packet segment
- *
- * This function will lookup the flow profile based on the input
- * hash field bitmap, iterate through the profile entry list of
- * that profile and find entry associated with input VSI to be
- * removed. Calls are made to underlying flow apis which will in
- * turn build or update buffers for RSS XLT1 section.
- */
-enum ice_status
-ice_rem_rss_cfg(struct ice_hw *hw, u16 vsi_handle, u64 hashed_flds,
-               u32 addl_hdrs)
-{
-       enum ice_status status;
-
-       if (hashed_flds == ICE_HASH_INVALID ||
-           !ice_is_vsi_valid(hw, vsi_handle))
-               return ICE_ERR_PARAM;
-
-       ice_acquire_lock(&hw->rss_locks);
-       status = ice_rem_rss_cfg_sync(hw, vsi_handle, hashed_flds, addl_hdrs);
-       ice_release_lock(&hw->rss_locks);
-
-       return status;
-}
-
 /**
  * ice_replay_rss_cfg - replay RSS configurations associated with VSI
  * @hw: pointer to the hardware structure
@@ -2154,7 +2272,14 @@ enum ice_status ice_replay_rss_cfg(struct ice_hw *hw, u16 vsi_handle)
                if (ice_is_bit_set(r->vsis, vsi_handle)) {
                        status = ice_add_rss_cfg_sync(hw, vsi_handle,
                                                      r->hashed_flds,
-                                                     r->packet_hdr);
+                                                     r->packet_hdr,
+                                                     ICE_RSS_OUTER_HEADERS);
+                       if (status)
+                               break;
+                       status = ice_add_rss_cfg_sync(hw, vsi_handle,
+                                                     r->hashed_flds,
+                                                     r->packet_hdr,
+                                                     ICE_RSS_INNER_HEADERS);
                        if (status)
                                break;
                }