net/sfc: check actual all multicast unknown unicast filters
[dpdk.git] / drivers / net / ice / base / ice_flex_pipe.c
index 8f8cab8..de14d9d 100644 (file)
@@ -1,5 +1,5 @@
 /* SPDX-License-Identifier: BSD-3-Clause
- * Copyright(c) 2001-2019
+ * Copyright(c) 2001-2020
  */
 
 #include "ice_common.h"
@@ -470,6 +470,7 @@ static void ice_init_pkg_hints(struct ice_hw *hw, struct ice_seg *ice_seg)
        int i;
 
        ice_memset(&hw->tnl, 0, sizeof(hw->tnl), ICE_NONDMA_MEM);
+       ice_memset(&state, 0, sizeof(state), ICE_NONDMA_MEM);
 
        if (!ice_seg)
                return;
@@ -609,7 +610,7 @@ ice_gen_key_word(u8 val, u8 valid, u8 dont_care, u8 nvr_mtch, u8 *key,
 static bool ice_bits_max_set(const u8 *mask, u16 size, u16 max)
 {
        u16 count = 0;
-       u16 i, j;
+       u16 i;
 
        /* check each byte */
        for (i = 0; i < size; i++) {
@@ -625,11 +626,9 @@ static bool ice_bits_max_set(const u8 *mask, u16 size, u16 max)
                        return false;
 
                /* count the bits in this byte, checking threshold */
-               for (j = 0; j < BITS_PER_BYTE; j++) {
-                       count += (mask[i] & (0x1 << j)) ? 1 : 0;
-                       if (count > max)
-                               return false;
-               }
+               count += ice_hweight8(mask[i]);
+               if (count > max)
+                       return false;
        }
 
        return true;
@@ -877,8 +876,9 @@ ice_find_seg_in_pkg(struct ice_hw *hw, u32 seg_type,
 
        ice_debug(hw, ICE_DBG_TRACE, "%s\n", __func__);
        ice_debug(hw, ICE_DBG_PKG, "Package format version: %d.%d.%d.%d\n",
-                 pkg_hdr->format_ver.major, pkg_hdr->format_ver.minor,
-                 pkg_hdr->format_ver.update, pkg_hdr->format_ver.draft);
+                 pkg_hdr->pkg_format_ver.major, pkg_hdr->pkg_format_ver.minor,
+                 pkg_hdr->pkg_format_ver.update,
+                 pkg_hdr->pkg_format_ver.draft);
 
        /* Search all package segments for the requested segment type */
        for (i = 0; i < LE32_TO_CPU(pkg_hdr->seg_count); i++) {
@@ -913,9 +913,8 @@ ice_update_pkg(struct ice_hw *hw, struct ice_buf *bufs, u32 count)
                return status;
 
        for (i = 0; i < count; i++) {
-               bool last = ((i + 1) == count);
-
                struct ice_buf_hdr *bh = (struct ice_buf_hdr *)(bufs + i);
+               bool last = ((i + 1) == count);
 
                status = ice_aq_update_pkg(hw, bh, LE16_TO_CPU(bh->data_end),
                                           last, &offset, &info, NULL);
@@ -1050,13 +1049,15 @@ ice_download_pkg(struct ice_hw *hw, struct ice_seg *ice_seg)
        struct ice_buf_table *ice_buf_tbl;
 
        ice_debug(hw, ICE_DBG_TRACE, "%s\n", __func__);
-       ice_debug(hw, ICE_DBG_PKG, "Segment version: %d.%d.%d.%d\n",
-                 ice_seg->hdr.seg_ver.major, ice_seg->hdr.seg_ver.minor,
-                 ice_seg->hdr.seg_ver.update, ice_seg->hdr.seg_ver.draft);
+       ice_debug(hw, ICE_DBG_PKG, "Segment format version: %d.%d.%d.%d\n",
+                 ice_seg->hdr.seg_format_ver.major,
+                 ice_seg->hdr.seg_format_ver.minor,
+                 ice_seg->hdr.seg_format_ver.update,
+                 ice_seg->hdr.seg_format_ver.draft);
 
        ice_debug(hw, ICE_DBG_PKG, "Seg: type 0x%X, size %d, name %s\n",
                  LE32_TO_CPU(ice_seg->hdr.seg_type),
-                 LE32_TO_CPU(ice_seg->hdr.seg_size), ice_seg->hdr.seg_name);
+                 LE32_TO_CPU(ice_seg->hdr.seg_size), ice_seg->hdr.seg_id);
 
        ice_buf_tbl = ice_find_buf_table(ice_seg);
 
@@ -1103,14 +1104,16 @@ ice_init_pkg_info(struct ice_hw *hw, struct ice_pkg_hdr *pkg_hdr)
 
        seg_hdr = ice_find_seg_in_pkg(hw, SEGMENT_TYPE_ICE, pkg_hdr);
        if (seg_hdr) {
-               hw->ice_pkg_ver = seg_hdr->seg_ver;
-               ice_memcpy(hw->ice_pkg_name, seg_hdr->seg_name,
+               hw->ice_pkg_ver = seg_hdr->seg_format_ver;
+               ice_memcpy(hw->ice_pkg_name, seg_hdr->seg_id,
                           sizeof(hw->ice_pkg_name), ICE_NONDMA_TO_NONDMA);
 
-               ice_debug(hw, ICE_DBG_PKG, "Ice Pkg: %d.%d.%d.%d, %s\n",
-                         seg_hdr->seg_ver.major, seg_hdr->seg_ver.minor,
-                         seg_hdr->seg_ver.update, seg_hdr->seg_ver.draft,
-                         seg_hdr->seg_name);
+               ice_debug(hw, ICE_DBG_PKG, "Ice Seg: %d.%d.%d.%d, %s\n",
+                         seg_hdr->seg_format_ver.major,
+                         seg_hdr->seg_format_ver.minor,
+                         seg_hdr->seg_format_ver.update,
+                         seg_hdr->seg_format_ver.draft,
+                         seg_hdr->seg_id);
        } else {
                ice_debug(hw, ICE_DBG_INIT,
                          "Did not find ice segment in driver package\n");
@@ -1135,8 +1138,7 @@ static enum ice_status ice_get_pkg_info(struct ice_hw *hw)
 
        ice_debug(hw, ICE_DBG_TRACE, "%s\n", __func__);
 
-       size = sizeof(*pkg_info) + (sizeof(pkg_info->pkg_info[0]) *
-                                   (ICE_PKG_CNT - 1));
+       size = ice_struct_size(pkg_info, pkg_info, ICE_PKG_CNT - 1);
        pkg_info = (struct ice_aqc_get_pkg_info_resp *)ice_malloc(hw, size);
        if (!pkg_info)
                return ICE_ERR_NO_MEMORY;
@@ -1153,9 +1155,11 @@ static enum ice_status ice_get_pkg_info(struct ice_hw *hw)
                if (pkg_info->pkg_info[i].is_active) {
                        flags[place++] = 'A';
                        hw->active_pkg_ver = pkg_info->pkg_info[i].ver;
+                       hw->active_track_id =
+                               LE32_TO_CPU(pkg_info->pkg_info[i].track_id);
                        ice_memcpy(hw->active_pkg_name,
                                   pkg_info->pkg_info[i].name,
-                                  sizeof(hw->active_pkg_name),
+                                  sizeof(pkg_info->pkg_info[i].name),
                                   ICE_NONDMA_TO_NONDMA);
                        hw->active_pkg_in_nvm = pkg_info->pkg_info[i].is_in_nvm;
                }
@@ -1196,10 +1200,10 @@ static enum ice_status ice_verify_pkg(struct ice_pkg_hdr *pkg, u32 len)
        if (len < sizeof(*pkg))
                return ICE_ERR_BUF_TOO_SHORT;
 
-       if (pkg->format_ver.major != ICE_PKG_FMT_VER_MAJ ||
-           pkg->format_ver.minor != ICE_PKG_FMT_VER_MNR ||
-           pkg->format_ver.update != ICE_PKG_FMT_VER_UPD ||
-           pkg->format_ver.draft != ICE_PKG_FMT_VER_DFT)
+       if (pkg->pkg_format_ver.major != ICE_PKG_FMT_VER_MAJ ||
+           pkg->pkg_format_ver.minor != ICE_PKG_FMT_VER_MNR ||
+           pkg->pkg_format_ver.update != ICE_PKG_FMT_VER_UPD ||
+           pkg->pkg_format_ver.draft != ICE_PKG_FMT_VER_DFT)
                return ICE_ERR_CFG;
 
        /* pkg must have at least one segment */
@@ -1208,7 +1212,7 @@ static enum ice_status ice_verify_pkg(struct ice_pkg_hdr *pkg, u32 len)
                return ICE_ERR_CFG;
 
        /* make sure segment array fits in package length */
-       if (len < sizeof(*pkg) + ((seg_count - 1) * sizeof(pkg->seg_offset)))
+       if (len < ice_struct_size(pkg, seg_offset, seg_count - 1))
                return ICE_ERR_BUF_TOO_SHORT;
 
        /* all segments must fit within length */
@@ -1256,6 +1260,8 @@ static void ice_init_pkg_regs(struct ice_hw *hw)
 #define ICE_SW_BLK_INP_MASK_L 0xFFFFFFFF
 #define ICE_SW_BLK_INP_MASK_H 0x0000FFFF
 #define ICE_SW_BLK_IDX 0
+       if (hw->dcf_enabled)
+               return;
 
        /* setup Switch block input mask, which is 48-bits in two parts */
        wr32(hw, GL_PREEXT_L2_PMASK0(ICE_SW_BLK_IDX), ICE_SW_BLK_INP_MASK_L);
@@ -1280,6 +1286,70 @@ static enum ice_status ice_chk_pkg_version(struct ice_pkg_ver *pkg_ver)
        return ICE_SUCCESS;
 }
 
+/**
+ * ice_chk_pkg_compat
+ * @hw: pointer to the hardware structure
+ * @ospkg: pointer to the package hdr
+ * @seg: pointer to the package segment hdr
+ *
+ * This function checks the package version compatibility with driver and NVM
+ */
+static enum ice_status
+ice_chk_pkg_compat(struct ice_hw *hw, struct ice_pkg_hdr *ospkg,
+                  struct ice_seg **seg)
+{
+       struct ice_aqc_get_pkg_info_resp *pkg;
+       enum ice_status status;
+       u16 size;
+       u32 i;
+
+       ice_debug(hw, ICE_DBG_TRACE, "%s\n", __func__);
+
+       /* Check package version compatibility */
+       status = ice_chk_pkg_version(&hw->pkg_ver);
+       if (status) {
+               ice_debug(hw, ICE_DBG_INIT, "Package version check failed.\n");
+               return status;
+       }
+
+       /* find ICE segment in given package */
+       *seg = (struct ice_seg *)ice_find_seg_in_pkg(hw, SEGMENT_TYPE_ICE,
+                                                    ospkg);
+       if (!*seg) {
+               ice_debug(hw, ICE_DBG_INIT, "no ice segment in package.\n");
+               return ICE_ERR_CFG;
+       }
+
+       /* Check if FW is compatible with the OS package */
+       size = ice_struct_size(pkg, pkg_info, ICE_PKG_CNT - 1);
+       pkg = (struct ice_aqc_get_pkg_info_resp *)ice_malloc(hw, size);
+       if (!pkg)
+               return ICE_ERR_NO_MEMORY;
+
+       status = ice_aq_get_pkg_info_list(hw, pkg, size, NULL);
+       if (status)
+               goto fw_ddp_compat_free_alloc;
+
+       for (i = 0; i < LE32_TO_CPU(pkg->count); i++) {
+               /* loop till we find the NVM package */
+               if (!pkg->pkg_info[i].is_in_nvm)
+                       continue;
+               if ((*seg)->hdr.seg_format_ver.major !=
+                       pkg->pkg_info[i].ver.major ||
+                   (*seg)->hdr.seg_format_ver.minor >
+                       pkg->pkg_info[i].ver.minor) {
+                       status = ICE_ERR_FW_DDP_MISMATCH;
+                       ice_debug(hw, ICE_DBG_INIT,
+                                 "OS package is not compatible with NVM.\n");
+               }
+               /* done processing NVM package so break */
+               break;
+       }
+fw_ddp_compat_free_alloc:
+       ice_free(hw, pkg);
+       return status;
+}
+
 /**
  * ice_init_pkg - initialize/download package
  * @hw: pointer to the hardware structure
@@ -1330,17 +1400,10 @@ enum ice_status ice_init_pkg(struct ice_hw *hw, u8 *buf, u32 len)
        /* before downloading the package, check package version for
         * compatibility with driver
         */
-       status = ice_chk_pkg_version(&hw->pkg_ver);
+       status = ice_chk_pkg_compat(hw, pkg, &seg);
        if (status)
                return status;
 
-       /* find segment in given package */
-       seg = (struct ice_seg *)ice_find_seg_in_pkg(hw, SEGMENT_TYPE_ICE, pkg);
-       if (!seg) {
-               ice_debug(hw, ICE_DBG_INIT, "no ice segment in package.\n");
-               return ICE_ERR_CFG;
-       }
-
        /* initialize package hints and then download package */
        ice_init_pkg_hints(hw, seg);
        status = ice_download_pkg(hw, seg);
@@ -1438,8 +1501,8 @@ static struct ice_buf_build *ice_pkg_buf_alloc(struct ice_hw *hw)
                return NULL;
 
        buf = (struct ice_buf_hdr *)bld;
-       buf->data_end = CPU_TO_LE16(sizeof(*buf) -
-                                   sizeof(buf->section_entry[0]));
+       buf->data_end = CPU_TO_LE16(offsetof(struct ice_buf_hdr,
+                                            section_entry));
        return bld;
 }
 
@@ -1506,18 +1569,20 @@ ice_get_sw_prof_type(struct ice_hw *hw, struct ice_fv *fv)
 /**
  * ice_get_sw_fv_bitmap - Get switch field vector bitmap based on profile type
  * @hw: pointer to hardware structure
- * @type: type of profiles requested
+ * @req_profs: type of profiles requested
  * @bm: pointer to memory for returning the bitmap of field vectors
  */
 void
-ice_get_sw_fv_bitmap(struct ice_hw *hw, enum ice_prof_type type,
+ice_get_sw_fv_bitmap(struct ice_hw *hw, enum ice_prof_type req_profs,
                     ice_bitmap_t *bm)
 {
        struct ice_pkg_enum state;
        struct ice_seg *ice_seg;
        struct ice_fv *fv;
 
-       if (type == ICE_PROF_ALL) {
+       ice_memset(&state, 0, sizeof(state), ICE_NONDMA_MEM);
+
+       if (req_profs == ICE_PROF_ALL) {
                u16 i;
 
                for (i = 0; i < ICE_MAX_NUM_PROFILES; i++)
@@ -1541,7 +1606,7 @@ ice_get_sw_fv_bitmap(struct ice_hw *hw, enum ice_prof_type type,
                        /* Determine field vector type */
                        prof_type = ice_get_sw_prof_type(hw, fv);
 
-                       if (type & prof_type)
+                       if (req_profs & prof_type)
                                ice_set_bit((u16)offset, bm);
                }
        } while (fv);
@@ -1563,7 +1628,7 @@ ice_get_sw_fv_bitmap(struct ice_hw *hw, enum ice_prof_type type,
  * allocated for every list entry.
  */
 enum ice_status
-ice_get_sw_fv_list(struct ice_hw *hw, u16 *prot_ids, u8 ids_cnt,
+ice_get_sw_fv_list(struct ice_hw *hw, u8 *prot_ids, u16 ids_cnt,
                   ice_bitmap_t *bm, struct LIST_HEAD_TYPE *fv_list)
 {
        struct ice_sw_fv_list_entry *fvl;
@@ -1573,12 +1638,14 @@ ice_get_sw_fv_list(struct ice_hw *hw, u16 *prot_ids, u8 ids_cnt,
        struct ice_fv *fv;
        u32 offset;
 
+       ice_memset(&state, 0, sizeof(state), ICE_NONDMA_MEM);
+
        if (!ids_cnt || !hw->seg)
                return ICE_ERR_PARAM;
 
        ice_seg = hw->seg;
        do {
-               u8 i;
+               u16 i;
 
                fv = (struct ice_fv *)
                        ice_pkg_enum_entry(ice_seg, &state, ICE_SID_FLD_VEC_SW,
@@ -1633,16 +1700,17 @@ err:
 }
 
 /**
- * ice_init_profile_to_result_bm - Initialize the profile result index bitmap
+ * ice_init_prof_result_bm - Initialize the profile result index bitmap
  * @hw: pointer to hardware structure
  */
-void
-ice_init_prof_result_bm(struct ice_hw *hw)
+void ice_init_prof_result_bm(struct ice_hw *hw)
 {
        struct ice_pkg_enum state;
        struct ice_seg *ice_seg;
        struct ice_fv *fv;
 
+       ice_memset(&state, 0, sizeof(state), ICE_NONDMA_MEM);
+
        if (!hw->seg)
                return;
 
@@ -1801,7 +1869,7 @@ static u16 ice_pkg_buf_get_active_sections(struct ice_buf_build *bld)
 }
 
 /**
- * ice_pkg_buf_header
+ * ice_pkg_buf
  * @bld: pointer to pkg build (allocated by ice_pkg_buf_alloc())
  *
  * Return a pointer to the buffer's header
@@ -1815,7 +1883,7 @@ static struct ice_buf *ice_pkg_buf(struct ice_buf_build *bld)
 }
 
 /**
- * ice_tunnel_port_in_use
+ * ice_tunnel_port_in_use_hlpr - helper function to determine tunnel usage
  * @hw: pointer to the HW structure
  * @port: port to search for
  * @index: optionally returns index
@@ -1823,7 +1891,7 @@ static struct ice_buf *ice_pkg_buf(struct ice_buf_build *bld)
  * Returns whether a port is already in use as a tunnel, and optionally its
  * index
  */
-bool ice_tunnel_port_in_use(struct ice_hw *hw, u16 port, u16 *index)
+static bool ice_tunnel_port_in_use_hlpr(struct ice_hw *hw, u16 port, u16 *index)
 {
        u16 i;
 
@@ -1837,6 +1905,26 @@ bool ice_tunnel_port_in_use(struct ice_hw *hw, u16 port, u16 *index)
        return false;
 }
 
+/**
+ * ice_tunnel_port_in_use
+ * @hw: pointer to the HW structure
+ * @port: port to search for
+ * @index: optionally returns index
+ *
+ * Returns whether a port is already in use as a tunnel, and optionally its
+ * index
+ */
+bool ice_tunnel_port_in_use(struct ice_hw *hw, u16 port, u16 *index)
+{
+       bool res;
+
+       ice_acquire_lock(&hw->tnl_lock);
+       res = ice_tunnel_port_in_use_hlpr(hw, port, index);
+       ice_release_lock(&hw->tnl_lock);
+
+       return res;
+}
+
 /**
  * ice_tunnel_get_type
  * @hw: pointer to the HW structure
@@ -1848,15 +1936,21 @@ bool ice_tunnel_port_in_use(struct ice_hw *hw, u16 port, u16 *index)
 bool
 ice_tunnel_get_type(struct ice_hw *hw, u16 port, enum ice_tunnel_type *type)
 {
+       bool res = false;
        u16 i;
 
+       ice_acquire_lock(&hw->tnl_lock);
+
        for (i = 0; i < hw->tnl.count && i < ICE_TUNNEL_MAX_ENTRIES; i++)
                if (hw->tnl.tbl[i].in_use && hw->tnl.tbl[i].port == port) {
                        *type = hw->tnl.tbl[i].type;
-                       return true;
+                       res = true;
+                       break;
                }
 
-       return false;
+       ice_release_lock(&hw->tnl_lock);
+
+       return res;
 }
 
 /**
@@ -1885,7 +1979,7 @@ ice_find_free_tunnel_entry(struct ice_hw *hw, enum ice_tunnel_type type,
 }
 
 /**
- * ice_get_tunnel_port - retrieve an open tunnel port
+ * ice_get_open_tunnel_port - retrieve an open tunnel port
  * @hw: pointer to the HW structure
  * @type: tunnel type (TNL_ALL will return any open port)
  * @port: returns open port
@@ -1894,25 +1988,33 @@ bool
 ice_get_open_tunnel_port(struct ice_hw *hw, enum ice_tunnel_type type,
                         u16 *port)
 {
+       bool res = false;
        u16 i;
 
+       ice_acquire_lock(&hw->tnl_lock);
+
        for (i = 0; i < hw->tnl.count && i < ICE_TUNNEL_MAX_ENTRIES; i++)
                if (hw->tnl.tbl[i].valid && hw->tnl.tbl[i].in_use &&
                    (type == TNL_ALL || hw->tnl.tbl[i].type == type)) {
                        *port = hw->tnl.tbl[i].port;
-                       return true;
+                       res = true;
+                       break;
                }
 
-       return false;
+       ice_release_lock(&hw->tnl_lock);
+
+       return res;
 }
 
 /**
  * ice_create_tunnel
  * @hw: pointer to the HW structure
  * @type: type of tunnel
- * @port: port to use for vxlan tunnel
+ * @port: port of tunnel to create
  *
- * Creates a tunnel
+ * Create a tunnel by updating the parse graph in the parser. We do that by
+ * creating a package buffer with the tunnel info and issuing an update package
+ * command.
  */
 enum ice_status
 ice_create_tunnel(struct ice_hw *hw, enum ice_tunnel_type type, u16 port)
@@ -1922,15 +2024,24 @@ ice_create_tunnel(struct ice_hw *hw, enum ice_tunnel_type type, u16 port)
        struct ice_buf_build *bld;
        u16 index;
 
-       if (ice_tunnel_port_in_use(hw, port, NULL))
-               return ICE_ERR_ALREADY_EXISTS;
+       ice_acquire_lock(&hw->tnl_lock);
 
-       if (!ice_find_free_tunnel_entry(hw, type, &index))
-               return ICE_ERR_OUT_OF_RANGE;
+       if (ice_tunnel_port_in_use_hlpr(hw, port, &index)) {
+               hw->tnl.tbl[index].ref++;
+               status = ICE_SUCCESS;
+               goto ice_create_tunnel_end;
+       }
+
+       if (!ice_find_free_tunnel_entry(hw, type, &index)) {
+               status = ICE_ERR_OUT_OF_RANGE;
+               goto ice_create_tunnel_end;
+       }
 
        bld = ice_pkg_buf_alloc(hw);
-       if (!bld)
-               return ICE_ERR_NO_MEMORY;
+       if (!bld) {
+               status = ICE_ERR_NO_MEMORY;
+               goto ice_create_tunnel_end;
+       }
 
        /* allocate 2 sections, one for Rx parser, one for Tx parser */
        if (ice_pkg_buf_reserve_section(bld, 2))
@@ -1959,7 +2070,7 @@ ice_create_tunnel(struct ice_hw *hw, enum ice_tunnel_type type, u16 port)
         */
        ice_set_key((u8 *)&sect_rx->tcam[0].key, sizeof(sect_rx->tcam[0].key),
                    (u8 *)&port, NULL, NULL, NULL,
-                   offsetof(struct ice_boost_key_value, hv_dst_port_key),
+                   (u16)offsetof(struct ice_boost_key_value, hv_dst_port_key),
                    sizeof(sect_rx->tcam[0].key.key.hv_dst_port_key));
 
        /* exact copy of entry to Tx section entry */
@@ -1970,11 +2081,15 @@ ice_create_tunnel(struct ice_hw *hw, enum ice_tunnel_type type, u16 port)
        if (!status) {
                hw->tnl.tbl[index].port = port;
                hw->tnl.tbl[index].in_use = true;
+               hw->tnl.tbl[index].ref = 1;
        }
 
 ice_create_tunnel_err:
        ice_pkg_buf_free(hw, bld);
 
+ice_create_tunnel_end:
+       ice_release_lock(&hw->tnl_lock);
+
        return status;
 }
 
@@ -1994,24 +2109,38 @@ enum ice_status ice_destroy_tunnel(struct ice_hw *hw, u16 port, bool all)
        enum ice_status status = ICE_ERR_MAX_LIMIT;
        struct ice_buf_build *bld;
        u16 count = 0;
+       u16 index;
        u16 size;
        u16 i;
 
+       ice_acquire_lock(&hw->tnl_lock);
+
+       if (!all && ice_tunnel_port_in_use_hlpr(hw, port, &index))
+               if (hw->tnl.tbl[index].ref > 1) {
+                       hw->tnl.tbl[index].ref--;
+                       status = ICE_SUCCESS;
+                       goto ice_destroy_tunnel_end;
+               }
+
        /* determine count */
        for (i = 0; i < hw->tnl.count && i < ICE_TUNNEL_MAX_ENTRIES; i++)
                if (hw->tnl.tbl[i].valid && hw->tnl.tbl[i].in_use &&
                    (all || hw->tnl.tbl[i].port == port))
                        count++;
 
-       if (!count)
-               return ICE_ERR_PARAM;
+       if (!count) {
+               status = ICE_ERR_PARAM;
+               goto ice_destroy_tunnel_end;
+       }
 
        /* size of section - there is at least one entry */
-       size = (count - 1) * sizeof(*sect_rx->tcam) + sizeof(*sect_rx);
+       size = ice_struct_size(sect_rx, tcam, count - 1);
 
        bld = ice_pkg_buf_alloc(hw);
-       if (!bld)
-               return ICE_ERR_NO_MEMORY;
+       if (!bld) {
+               status = ICE_ERR_NO_MEMORY;
+               goto ice_destroy_tunnel_end;
+       }
 
        /* allocate 2 sections, one for Rx parser, one for Tx parser */
        if (ice_pkg_buf_reserve_section(bld, 2))
@@ -2053,6 +2182,7 @@ enum ice_status ice_destroy_tunnel(struct ice_hw *hw, u16 port, bool all)
                for (i = 0; i < hw->tnl.count &&
                     i < ICE_TUNNEL_MAX_ENTRIES; i++)
                        if (hw->tnl.tbl[i].marked) {
+                               hw->tnl.tbl[i].ref = 0;
                                hw->tnl.tbl[i].port = 0;
                                hw->tnl.tbl[i].in_use = false;
                                hw->tnl.tbl[i].marked = false;
@@ -2061,6 +2191,9 @@ enum ice_status ice_destroy_tunnel(struct ice_hw *hw, u16 port, bool all)
 ice_destroy_tunnel_err:
        ice_pkg_buf_free(hw, bld);
 
+ice_destroy_tunnel_end:
+       ice_release_lock(&hw->tnl_lock);
+
        return status;
 }
 
@@ -2074,7 +2207,7 @@ ice_destroy_tunnel_err:
  * @off: variable to receive the protocol offset
  */
 enum ice_status
-ice_find_prot_off(struct ice_hw *hw, enum ice_block blk, u8 prof, u8 fv_idx,
+ice_find_prot_off(struct ice_hw *hw, enum ice_block blk, u8 prof, u16 fv_idx,
                  u8 *prot, u16 *off)
 {
        struct ice_fv_word *fv_ext;
@@ -2103,7 +2236,7 @@ ice_find_prot_off(struct ice_hw *hw, enum ice_block blk, u8 prof, u8 fv_idx,
  * @ptg: pointer to variable that receives the PTG
  *
  * This function will search the PTGs for a particular ptype, returning the
- * PTG ID that contains it through the ptg parameter, with the value of
+ * PTG ID that contains it through the PTG parameter, with the value of
  * ICE_DEFAULT_PTG (0) meaning it is part the default PTG.
  */
 static enum ice_status
@@ -2120,13 +2253,12 @@ ice_ptg_find_ptype(struct ice_hw *hw, enum ice_block blk, u16 ptype, u8 *ptg)
  * ice_ptg_alloc_val - Allocates a new packet type group ID by value
  * @hw: pointer to the hardware structure
  * @blk: HW block
- * @ptg: the ptg to allocate
+ * @ptg: the PTG to allocate
  *
- * This function allocates a given packet type group ID specified by the ptg
+ * This function allocates a given packet type group ID specified by the PTG
  * parameter.
  */
-static
-void ice_ptg_alloc_val(struct ice_hw *hw, enum ice_block blk, u8 ptg)
+static void ice_ptg_alloc_val(struct ice_hw *hw, enum ice_block blk, u8 ptg)
 {
        hw->blk[blk].xlt1.ptg_tbl[ptg].in_use = true;
 }
@@ -2136,9 +2268,9 @@ void ice_ptg_alloc_val(struct ice_hw *hw, enum ice_block blk, u8 ptg)
  * @hw: pointer to the hardware structure
  * @blk: HW block
  * @ptype: the ptype to remove
- * @ptg: the ptg to remove the ptype from
+ * @ptg: the PTG to remove the ptype from
  *
- * This function will remove the ptype from the specific ptg, and move it to
+ * This function will remove the ptype from the specific PTG, and move it to
  * the default PTG (ICE_DEFAULT_PTG).
  */
 static enum ice_status
@@ -2181,7 +2313,7 @@ ice_ptg_remove_ptype(struct ice_hw *hw, enum ice_block blk, u16 ptype, u8 ptg)
  * @hw: pointer to the hardware structure
  * @blk: HW block
  * @ptype: the ptype to add or move
- * @ptg: the ptg to add or move the ptype to
+ * @ptg: the PTG to add or move the ptype to
  *
  * This function will either add or move a ptype to a particular PTG depending
  * on if the ptype is already part of another group. Note that using a
@@ -2234,7 +2366,7 @@ struct ice_blk_size_details {
        u16 xlt2;                       /* # XLT2 entries */
        u16 prof_tcam;                  /* # profile ID TCAM entries */
        u16 prof_id;                    /* # profile IDs */
-       u8 prof_cdid_bits;              /* # cdid one-hot bits used in key */
+       u8 prof_cdid_bits;              /* # CDID one-hot bits used in key */
        u16 prof_redir;                 /* # profile redirection entries */
        u16 es;                         /* # extraction sequence entries */
        u16 fvw;                        /* # field vector words */
@@ -2353,9 +2485,9 @@ ice_vsig_find_vsi(struct ice_hw *hw, enum ice_block blk, u16 vsi, u16 *vsig)
  * ice_vsig_alloc_val - allocate a new VSIG by value
  * @hw: pointer to the hardware structure
  * @blk: HW block
- * @vsig: the vsig to allocate
+ * @vsig: the VSIG to allocate
  *
- * This function will allocate a given VSIG specified by the vsig parameter.
+ * This function will allocate a given VSIG specified by the VSIG parameter.
  */
 static u16 ice_vsig_alloc_val(struct ice_hw *hw, enum ice_block blk, u16 vsig)
 {
@@ -2677,43 +2809,16 @@ ice_find_prof_id_with_mask(struct ice_hw *hw, enum ice_block blk,
                           struct ice_fv_word *fv, u16 *masks, u8 *prof_id)
 {
        struct ice_es *es = &hw->blk[blk].es;
-       u16 i;
+       u8 i;
 
-       for (i = 0; i < es->count; i++) {
+       for (i = 0; i < (u8)es->count; i++) {
                u16 off = i * es->fvw;
 
                if (memcmp(&es->t[off], fv, es->fvw * sizeof(*fv)))
                        continue;
 
                /* check if masks settings are the same for this profile */
-               if (!ice_prof_has_mask(hw, blk, i, masks))
-                       continue;
-
-               *prof_id = i;
-               return ICE_SUCCESS;
-       }
-
-       return ICE_ERR_DOES_NOT_EXIST;
-}
-
-/**
- * ice_find_prof_id - find profile ID for a given field vector
- * @hw: pointer to the hardware structure
- * @blk: HW block
- * @fv: field vector to search for
- * @prof_id: receives the profile ID
- */
-static enum ice_status
-ice_find_prof_id(struct ice_hw *hw, enum ice_block blk,
-                struct ice_fv_word *fv, u8 *prof_id)
-{
-       struct ice_es *es = &hw->blk[blk].es;
-       u16 off, i;
-
-       for (i = 0; i < es->count; i++) {
-               off = i * es->fvw;
-
-               if (memcmp(&es->t[off], fv, es->fvw * sizeof(*fv)))
+               if (masks && !ice_prof_has_mask(hw, blk, i, masks))
                        continue;
 
                *prof_id = i;
@@ -3091,7 +3196,8 @@ ice_free_prof_mask(struct ice_hw *hw, enum ice_block blk, u16 mask_idx)
        hw->blk[blk].masks.masks[mask_idx].idx = 0;
 
        /* update mask as unused entry */
-       ice_debug(hw, ICE_DBG_PKG, "Free mask, blk %d, mask %d", blk, mask_idx);
+       ice_debug(hw, ICE_DBG_PKG, "Free mask, blk %d, mask %d\n", blk,
+                 mask_idx);
        ice_write_prof_mask_reg(hw, blk, mask_idx, 0, 0);
 
 exit_ice_free_prof_mask:
@@ -3307,8 +3413,7 @@ static const u32 ice_blk_sids[ICE_BLK_COUNT][ICE_SID_OFF_COUNT] = {
  * @hw: pointer to the hardware structure
  * @blk: the HW block to initialize
  */
-static
-void ice_init_sw_xlt1_db(struct ice_hw *hw, enum ice_block blk)
+static void ice_init_sw_xlt1_db(struct ice_hw *hw, enum ice_block blk)
 {
        u16 pt;
 
@@ -3552,7 +3657,8 @@ static void ice_free_flow_profs(struct ice_hw *hw, u8 blk_idx)
 
                LIST_FOR_EACH_ENTRY_SAFE(e, t, &p->entries,
                                         ice_flow_entry, l_entry)
-                       ice_flow_rem_entry(hw, ICE_FLOW_ENTRY_HNDL(e));
+                       ice_flow_rem_entry(hw, (enum ice_block)blk_idx,
+                                          ICE_FLOW_ENTRY_HNDL(e));
 
                LIST_DEL(&p->l_entry);
                if (p->acts)
@@ -3625,7 +3731,8 @@ void ice_free_hw_tbls(struct ice_hw *hw)
                ice_free(hw, r);
        }
        ice_destroy_lock(&hw->rss_locks);
-       ice_shutdown_all_prof_masks(hw);
+       if (!hw->dcf_enabled)
+               ice_shutdown_all_prof_masks(hw);
        ice_memset(hw->blk, 0, sizeof(hw->blk), ICE_NONDMA_MEM);
 }
 
@@ -3640,6 +3747,61 @@ static void ice_init_flow_profs(struct ice_hw *hw, u8 blk_idx)
        INIT_LIST_HEAD(&hw->fl_profs[blk_idx]);
 }
 
+/**
+ * ice_clear_hw_tbls - clear HW tables and flow profiles
+ * @hw: pointer to the hardware structure
+ */
+void ice_clear_hw_tbls(struct ice_hw *hw)
+{
+       u8 i;
+
+       for (i = 0; i < ICE_BLK_COUNT; i++) {
+               struct ice_prof_redir *prof_redir = &hw->blk[i].prof_redir;
+               struct ice_prof_tcam *prof = &hw->blk[i].prof;
+               struct ice_xlt1 *xlt1 = &hw->blk[i].xlt1;
+               struct ice_xlt2 *xlt2 = &hw->blk[i].xlt2;
+               struct ice_es *es = &hw->blk[i].es;
+
+               if (hw->blk[i].is_list_init) {
+                       ice_free_prof_map(hw, i);
+                       ice_free_flow_profs(hw, i);
+               }
+
+               ice_free_vsig_tbl(hw, (enum ice_block)i);
+
+               ice_memset(xlt1->ptypes, 0, xlt1->count * sizeof(*xlt1->ptypes),
+                          ICE_NONDMA_MEM);
+               ice_memset(xlt1->ptg_tbl, 0,
+                          ICE_MAX_PTGS * sizeof(*xlt1->ptg_tbl),
+                          ICE_NONDMA_MEM);
+               ice_memset(xlt1->t, 0, xlt1->count * sizeof(*xlt1->t),
+                          ICE_NONDMA_MEM);
+
+               ice_memset(xlt2->vsis, 0, xlt2->count * sizeof(*xlt2->vsis),
+                          ICE_NONDMA_MEM);
+               ice_memset(xlt2->vsig_tbl, 0,
+                          xlt2->count * sizeof(*xlt2->vsig_tbl),
+                          ICE_NONDMA_MEM);
+               ice_memset(xlt2->t, 0, xlt2->count * sizeof(*xlt2->t),
+                          ICE_NONDMA_MEM);
+
+               ice_memset(prof->t, 0, prof->count * sizeof(*prof->t),
+                          ICE_NONDMA_MEM);
+               ice_memset(prof_redir->t, 0,
+                          prof_redir->count * sizeof(*prof_redir->t),
+                          ICE_NONDMA_MEM);
+
+               ice_memset(es->t, 0, es->count * sizeof(*es->t),
+                          ICE_NONDMA_MEM);
+               ice_memset(es->ref_count, 0, es->count * sizeof(*es->ref_count),
+                          ICE_NONDMA_MEM);
+               ice_memset(es->written, 0, es->count * sizeof(*es->written),
+                          ICE_NONDMA_MEM);
+               ice_memset(es->mask_ena, 0, es->count * sizeof(*es->mask_ena),
+                          ICE_NONDMA_MEM);
+       }
+}
+
 /**
  * ice_init_hw_tbls - init hardware table memory
  * @hw: pointer to the hardware structure
@@ -3650,7 +3812,8 @@ enum ice_status ice_init_hw_tbls(struct ice_hw *hw)
 
        ice_init_lock(&hw->rss_locks);
        INIT_LIST_HEAD(&hw->rss_list_head);
-       ice_init_all_prof_masks(hw);
+       if (!hw->dcf_enabled)
+               ice_init_all_prof_masks(hw);
        for (i = 0; i < ICE_BLK_COUNT; i++) {
                struct ice_prof_redir *prof_redir = &hw->blk[i].prof_redir;
                struct ice_prof_tcam *prof = &hw->blk[i].prof;
@@ -3760,7 +3923,7 @@ err:
  * @blk: the block in which to write profile ID to
  * @ptg: packet type group (PTG) portion of key
  * @vsig: VSIG portion of key
- * @cdid: cdid portion of key
+ * @cdid: CDID portion of key
  * @flags: flag portion of key
  * @vl_msk: valid mask
  * @dc_msk: don't care mask
@@ -3803,7 +3966,7 @@ ice_prof_gen_key(struct ice_hw *hw, enum ice_block blk, u8 ptg, u16 vsig,
        default:
                ice_debug(hw, ICE_DBG_PKG, "Error in profile config\n");
                break;
-       };
+       }
 
        return ice_set_key(key, ICE_TCAM_KEY_SZ, (u8 *)&inkey, vl_msk, dc_msk,
                           nm_msk, 0, ICE_TCAM_KEY_SZ / 2);
@@ -3817,7 +3980,7 @@ ice_prof_gen_key(struct ice_hw *hw, enum ice_block blk, u8 ptg, u16 vsig,
  * @prof_id: profile ID
  * @ptg: packet type group (PTG) portion of key
  * @vsig: VSIG portion of key
- * @cdid: cdid portion of key
+ * @cdid: CDID: portion of key
  * @flags: flag portion of key
  * @vl_msk: valid mask
  * @dc_msk: don't care mask
@@ -3855,6 +4018,7 @@ ice_vsig_get_ref(struct ice_hw *hw, enum ice_block blk, u16 vsig, u16 *refs)
 {
        u16 idx = vsig & ICE_VSIG_IDX_M;
        struct ice_vsig_vsi *ptr;
+
        *refs = 0;
 
        if (!hw->blk[blk].xlt2.vsig_tbl[idx].in_use)
@@ -4019,19 +4183,13 @@ ice_prof_bld_xlt2(enum ice_block blk, struct ice_buf_build *bld,
        struct ice_chs_chg *tmp;
 
        LIST_FOR_EACH_ENTRY(tmp, chgs, ice_chs_chg, list_entry) {
-               bool found = false;
-
-               if (tmp->type == ICE_VSIG_ADD)
-                       found = true;
-               else if (tmp->type == ICE_VSI_MOVE)
-                       found = true;
-               else if (tmp->type == ICE_VSIG_REM)
-                       found = true;
-
-               if (found) {
-                       struct ice_xlt2_section *p;
-                       u32 id;
+               struct ice_xlt2_section *p;
+               u32 id;
 
+               switch (tmp->type) {
+               case ICE_VSIG_ADD:
+               case ICE_VSI_MOVE:
+               case ICE_VSIG_REM:
                        id = ice_sect_id(blk, ICE_XLT2);
                        p = (struct ice_xlt2_section *)
                                ice_pkg_buf_alloc_section(bld, id, sizeof(*p));
@@ -4042,6 +4200,9 @@ ice_prof_bld_xlt2(enum ice_block blk, struct ice_buf_build *bld,
                        p->count = CPU_TO_LE16(1);
                        p->offset = CPU_TO_LE16(tmp->vsi);
                        p->value[0] = CPU_TO_LE16(tmp->vsig);
+                       break;
+               default:
+                       break;
                }
        }
 
@@ -4061,12 +4222,12 @@ ice_upd_prof_hw(struct ice_hw *hw, enum ice_block blk,
        struct ice_buf_build *b;
        struct ice_chs_chg *tmp;
        enum ice_status status;
-       u16 pkg_sects = 0;
-       u16 sects = 0;
+       u16 pkg_sects;
        u16 xlt1 = 0;
        u16 xlt2 = 0;
        u16 tcam = 0;
        u16 es = 0;
+       u16 sects;
 
        /* count number of sections we need */
        LIST_FOR_EACH_ENTRY(tmp, chgs, ice_chs_chg, list_entry) {
@@ -4141,7 +4302,7 @@ ice_upd_prof_hw(struct ice_hw *hw, enum ice_block blk,
        /* update package */
        status = ice_update_pkg(hw, ice_pkg_buf(b), 1);
        if (status == ICE_ERR_AQ_ERROR)
-               ice_debug(hw, ICE_DBG_INIT, "Unable to update HW profile.");
+               ice_debug(hw, ICE_DBG_INIT, "Unable to update HW profile\n");
 
 error_tmp:
        ice_pkg_buf_free(hw, b);
@@ -4165,8 +4326,6 @@ static void ice_update_fd_mask(struct ice_hw *hw, u16 prof_id, u32 mask_sel)
                  GLQF_FDMASK_SEL(prof_id), mask_sel);
 }
 
-#define ICE_SRC_DST_MAX_COUNT  8
-
 struct ice_fd_src_dst_pair {
        u8 prot_id;
        u8 count;
@@ -4358,127 +4517,58 @@ ice_update_fd_swap(struct ice_hw *hw, u16 prof_id, struct ice_fv_word *es)
        return ICE_SUCCESS;
 }
 
+/* The entries here needs to match the order of enum ice_ptype_attrib */
+static const struct ice_ptype_attrib_info ice_ptype_attributes[] = {
+       { ICE_GTP_PDU_EH,       ICE_GTP_PDU_FLAG_MASK },
+       { ICE_GTP_SESSION,      ICE_GTP_FLAGS_MASK },
+       { ICE_GTP_DOWNLINK,     ICE_GTP_FLAGS_MASK },
+       { ICE_GTP_UPLINK,       ICE_GTP_FLAGS_MASK },
+};
+
 /**
- * ice_add_prof_with_mask - add profile
- * @hw: pointer to the HW struct
- * @blk: hardware block
- * @id: profile tracking ID
- * @ptypes: array of bitmaps indicating ptypes (ICE_FLOW_PTYPE_MAX bits)
- * @es: extraction sequence (length of array is determined by the block)
- * @masks: extraction sequence (length of array is determined by the block)
- *
- * This function registers a profile, which matches a set of PTYPES with a
- * particular extraction sequence. While the hardware profile is allocated
- * it will not be written until the first call to ice_add_flow that specifies
- * the ID value used here.
+ * ice_get_ptype_attrib_info - get ptype attribute information
+ * @type: attribute type
+ * @info: pointer to variable to the attribute information
  */
-enum ice_status
-ice_add_prof_with_mask(struct ice_hw *hw, enum ice_block blk, u64 id,
-                      u8 ptypes[], struct ice_fv_word *es, u16 *masks)
+static void
+ice_get_ptype_attrib_info(enum ice_ptype_attrib_type type,
+                         struct ice_ptype_attrib_info *info)
 {
-       u32 bytes = DIVIDE_AND_ROUND_UP(ICE_FLOW_PTYPE_MAX, BITS_PER_BYTE);
-       ice_declare_bitmap(ptgs_used, ICE_XLT1_CNT);
-       struct ice_prof_map *prof;
-       enum ice_status status;
-       u32 byte = 0;
-       u8 prof_id;
-
-       ice_zero_bitmap(ptgs_used, ICE_XLT1_CNT);
-
-       ice_acquire_lock(&hw->blk[blk].es.prof_map_lock);
-
-       /* search for existing profile */
-       status = ice_find_prof_id_with_mask(hw, blk, es, masks, &prof_id);
-       if (status) {
-               /* allocate profile ID */
-               status = ice_alloc_prof_id(hw, blk, &prof_id);
-               if (status)
-                       goto err_ice_add_prof;
-               if (blk == ICE_BLK_FD) {
-                       /* For Flow Director block, the extraction sequence may
-                        * need to be altered in the case where there are paired
-                        * fields that have no match. This is necessary because
-                        * for Flow Director, src and dest fields need to paired
-                        * for filter programming and these values are swapped
-                        * during Tx.
-                        */
-                       status = ice_update_fd_swap(hw, prof_id, es);
-                       if (status)
-                               goto err_ice_add_prof;
-               }
-               status = ice_update_prof_masking(hw, blk, prof_id, es, masks);
-               if (status)
-                       goto err_ice_add_prof;
-
-               /* and write new es */
-               ice_write_es(hw, blk, prof_id, es);
-       }
-
-       ice_prof_inc_ref(hw, blk, prof_id);
-
-       /* add profile info */
-
-       prof = (struct ice_prof_map *)ice_malloc(hw, sizeof(*prof));
-       if (!prof)
-               goto err_ice_add_prof;
-
-       prof->profile_cookie = id;
-       prof->prof_id = prof_id;
-       prof->ptg_cnt = 0;
-       prof->context = 0;
-
-       /* build list of ptgs */
-       while (bytes && prof->ptg_cnt < ICE_MAX_PTG_PER_PROFILE) {
-               u32 bit;
-
-               if (!ptypes[byte]) {
-                       bytes--;
-                       byte++;
-                       continue;
-               }
-               /* Examine 8 bits per byte */
-               for (bit = 0; bit < 8; bit++) {
-                       if (ptypes[byte] & BIT(bit)) {
-                               u16 ptype;
-                               u8 ptg;
-                               u8 m;
-
-                               ptype = byte * BITS_PER_BYTE + bit;
-
-                               /* The package should place all ptypes in a
-                                * non-zero PTG, so the following call should
-                                * never fail.
-                                */
-                               if (ice_ptg_find_ptype(hw, blk, ptype, &ptg))
-                                       continue;
+       *info = ice_ptype_attributes[type];
+}
 
-                               /* If PTG is already added, skip and continue */
-                               if (ice_is_bit_set(ptgs_used, ptg))
-                                       continue;
+/**
+ * ice_add_prof_attrib - add any PTG with attributes to profile
+ * @prof: pointer to the profile to which PTG entries will be added
+ * @ptg: PTG to be added
+ * @ptype: PTYPE that needs to be looked up
+ * @attr: array of attributes that will be considered
+ * @attr_cnt: number of elements in the attribute array
+ */
+static enum ice_status
+ice_add_prof_attrib(struct ice_prof_map *prof, u8 ptg, u16 ptype,
+                   const struct ice_ptype_attributes *attr, u16 attr_cnt)
+{
+       bool found = false;
+       u16 i;
 
-                               ice_set_bit(ptg, ptgs_used);
-                               prof->ptg[prof->ptg_cnt] = ptg;
+       for (i = 0; i < attr_cnt; i++) {
+               if (attr[i].ptype == ptype) {
+                       found = true;
 
-                               if (++prof->ptg_cnt >= ICE_MAX_PTG_PER_PROFILE)
-                                       break;
+                       prof->ptg[prof->ptg_cnt] = ptg;
+                       ice_get_ptype_attrib_info(attr[i].attrib,
+                                                 &prof->attr[prof->ptg_cnt]);
 
-                               /* nothing left in byte, then exit */
-                               m = ~((1 << (bit + 1)) - 1);
-                               if (!(ptypes[byte] & m))
-                                       break;
-                       }
+                       if (++prof->ptg_cnt >= ICE_MAX_PTG_PER_PROFILE)
+                               return ICE_ERR_MAX_LIMIT;
                }
-
-               bytes--;
-               byte++;
        }
 
-       LIST_ADD(&prof->list, &hw->blk[blk].es.prof_map);
-       status = ICE_SUCCESS;
+       if (!found)
+               return ICE_ERR_DOES_NOT_EXIST;
 
-err_ice_add_prof:
-       ice_release_lock(&hw->blk[blk].es.prof_map_lock);
-       return status;
+       return ICE_SUCCESS;
 }
 
 /**
@@ -4487,22 +4577,26 @@ err_ice_add_prof:
  * @blk: hardware block
  * @id: profile tracking ID
  * @ptypes: array of bitmaps indicating ptypes (ICE_FLOW_PTYPE_MAX bits)
+ * @attr: array of attributes
+ * @attr_cnt: number of elements in attrib array
  * @es: extraction sequence (length of array is determined by the block)
+ * @masks: mask for extraction sequence
  *
- * This function registers a profile, which matches a set of PTGs with a
+ * This function registers a profile, which matches a set of PTYPES with a
  * particular extraction sequence. While the hardware profile is allocated
  * it will not be written until the first call to ice_add_flow that specifies
  * the ID value used here.
  */
 enum ice_status
 ice_add_prof(struct ice_hw *hw, enum ice_block blk, u64 id, u8 ptypes[],
-            struct ice_fv_word *es)
+            const struct ice_ptype_attributes *attr, u16 attr_cnt,
+            struct ice_fv_word *es, u16 *masks)
 {
        u32 bytes = DIVIDE_AND_ROUND_UP(ICE_FLOW_PTYPE_MAX, BITS_PER_BYTE);
        ice_declare_bitmap(ptgs_used, ICE_XLT1_CNT);
        struct ice_prof_map *prof;
        enum ice_status status;
-       u32 byte = 0;
+       u8 byte = 0;
        u8 prof_id;
 
        ice_zero_bitmap(ptgs_used, ICE_XLT1_CNT);
@@ -4510,7 +4604,7 @@ ice_add_prof(struct ice_hw *hw, enum ice_block blk, u64 id, u8 ptypes[],
        ice_acquire_lock(&hw->blk[blk].es.prof_map_lock);
 
        /* search for existing profile */
-       status = ice_find_prof_id(hw, blk, es, &prof_id);
+       status = ice_find_prof_id_with_mask(hw, blk, es, masks, &prof_id);
        if (status) {
                /* allocate profile ID */
                status = ice_alloc_prof_id(hw, blk, &prof_id);
@@ -4528,6 +4622,9 @@ ice_add_prof(struct ice_hw *hw, enum ice_block blk, u64 id, u8 ptypes[],
                        if (status)
                                goto err_ice_add_prof;
                }
+               status = ice_update_prof_masking(hw, blk, prof_id, es, masks);
+               if (status)
+                       goto err_ice_add_prof;
 
                /* and write new es */
                ice_write_es(hw, blk, prof_id, es);
@@ -4548,7 +4645,7 @@ ice_add_prof(struct ice_hw *hw, enum ice_block blk, u64 id, u8 ptypes[],
 
        /* build list of ptgs */
        while (bytes && prof->ptg_cnt < ICE_MAX_PTG_PER_PROFILE) {
-               u32 bit;
+               u8 bit;
 
                if (!ptypes[byte]) {
                        bytes--;
@@ -4576,13 +4673,28 @@ ice_add_prof(struct ice_hw *hw, enum ice_block blk, u64 id, u8 ptypes[],
                                        continue;
 
                                ice_set_bit(ptg, ptgs_used);
-                               prof->ptg[prof->ptg_cnt] = ptg;
-
-                               if (++prof->ptg_cnt >= ICE_MAX_PTG_PER_PROFILE)
+                               /* Check to see there are any attributes for
+                                * this ptype, and add them if found.
+                                */
+                               status = ice_add_prof_attrib(prof, ptg, ptype,
+                                                            attr, attr_cnt);
+                               if (status == ICE_ERR_MAX_LIMIT)
                                        break;
+                               if (status) {
+                                       /* This is simple a ptype/PTG with no
+                                        * attribute
+                                        */
+                                       prof->ptg[prof->ptg_cnt] = ptg;
+                                       prof->attr[prof->ptg_cnt].flags = 0;
+                                       prof->attr[prof->ptg_cnt].mask = 0;
+
+                                       if (++prof->ptg_cnt >=
+                                           ICE_MAX_PTG_PER_PROFILE)
+                                               break;
+                               }
 
                                /* nothing left in byte, then exit */
-                               m = ~((1 << (bit + 1)) - 1);
+                               m = ~(u8)((1 << (bit + 1)) - 1);
                                if (!(ptypes[byte] & m))
                                        break;
                        }
@@ -4772,9 +4884,7 @@ ice_rem_vsig(struct ice_hw *hw, enum ice_block blk, u16 vsig,
                } while (vsi_cur);
        }
 
-       status = ice_vsig_free(hw, blk, vsig);
-
-       return status;
+       return ice_vsig_free(hw, blk, vsig);
 }
 
 /**
@@ -4885,8 +4995,6 @@ enum ice_status ice_rem_prof(struct ice_hw *hw, enum ice_block blk, u64 id)
        LIST_DEL(&pmap->list);
        ice_free(hw, pmap);
 
-       status = ICE_SUCCESS;
-
 err_ice_rem_prof:
        ice_release_lock(&hw->blk[blk].es.prof_map_lock);
        return status;
@@ -4922,6 +5030,7 @@ ice_get_prof(struct ice_hw *hw, enum ice_block blk, u64 hdl,
                        p->type = ICE_PTG_ES_ADD;
                        p->ptype = 0;
                        p->ptg = map->ptg[i];
+                       p->attr = map->attr[i];
                        p->add_ptg = 0;
 
                        p->add_prof = 1;
@@ -4991,8 +5100,8 @@ static enum ice_status
 ice_add_prof_to_lst(struct ice_hw *hw, enum ice_block blk,
                    struct LIST_HEAD_TYPE *lst, u64 hdl)
 {
-       struct ice_vsig_prof *p;
        struct ice_prof_map *map;
+       struct ice_vsig_prof *p;
        u16 i;
 
        map = ice_search_prof_id(hw, blk, hdl);
@@ -5011,6 +5120,7 @@ ice_add_prof_to_lst(struct ice_hw *hw, enum ice_block blk,
                p->tcam[i].prof_id = map->prof_id;
                p->tcam[i].tcam_idx = ICE_INVALID_TCAM;
                p->tcam[i].ptg = map->ptg[i];
+               p->tcam[i].attr = map->attr[i];
        }
 
        LIST_ADD(&p->list, lst);
@@ -5057,12 +5167,45 @@ ice_move_vsi(struct ice_hw *hw, enum ice_block blk, u16 vsi, u16 vsig,
        return ICE_SUCCESS;
 }
 
+/**
+ * ice_set_tcam_flags - set TCAM flag don't care mask
+ * @mask: mask for flags
+ * @dc_mask: pointer to the don't care mask
+ */
+static void ice_set_tcam_flags(u16 mask, u8 dc_mask[ICE_TCAM_KEY_VAL_SZ])
+{
+       u16 *flag_word;
+
+       /* flags are lowest u16 */
+       flag_word = (u16 *)dc_mask;
+       *flag_word = ~mask;
+}
+
+/**
+ * ice_rem_chg_tcam_ent - remove a specific TCAM entry from change list
+ * @hw: pointer to the HW struct
+ * @idx: the index of the TCAM entry to remove
+ * @chg: the list of change structures to search
+ */
+static void
+ice_rem_chg_tcam_ent(struct ice_hw *hw, u16 idx, struct LIST_HEAD_TYPE *chg)
+{
+       struct ice_chs_chg *pos, *tmp;
+
+       LIST_FOR_EACH_ENTRY_SAFE(tmp, pos, chg, ice_chs_chg, list_entry) {
+               if (tmp->type == ICE_TCAM_ADD && tmp->tcam_idx == idx) {
+                       LIST_DEL(&tmp->list_entry);
+                       ice_free(hw, tmp);
+               }
+       }
+}
+
 /**
  * ice_prof_tcam_ena_dis - add enable or disable TCAM change
  * @hw: pointer to the HW struct
  * @blk: hardware block
  * @enable: true to enable, false to disable
- * @vsig: the vsig of the TCAM entry
+ * @vsig: the VSIG of the TCAM entry
  * @tcam: pointer the TCAM info structure of the TCAM to disable
  * @chg: the change list
  *
@@ -5076,20 +5219,25 @@ ice_prof_tcam_ena_dis(struct ice_hw *hw, enum ice_block blk, bool enable,
        enum ice_status status;
        struct ice_chs_chg *p;
 
-       /* Default: enable means change the low flag bit to don't care */
-       u8 dc_msk[ICE_TCAM_KEY_VAL_SZ] = { 0x01, 0x00, 0x00, 0x00, 0x00 };
+       u8 vl_msk[ICE_TCAM_KEY_VAL_SZ] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
+       u8 dc_msk[ICE_TCAM_KEY_VAL_SZ] = { 0xFF, 0xFF, 0x00, 0x00, 0x00 };
        u8 nm_msk[ICE_TCAM_KEY_VAL_SZ] = { 0x00, 0x00, 0x00, 0x00, 0x00 };
-       u8 vl_msk[ICE_TCAM_KEY_VAL_SZ] = { 0x01, 0x00, 0x00, 0x00, 0x00 };
 
-       /* if disabling, free the tcam */
+       /* if disabling, free the TCAM */
        if (!enable) {
-               status = ice_free_tcam_ent(hw, blk, tcam->tcam_idx);
+               status = ice_rel_tcam_idx(hw, blk, tcam->tcam_idx);
+
+               /* if we have already created a change for this TCAM entry, then
+                * we need to remove that entry, in order to prevent writing to
+                * a TCAM entry we no longer will have ownership of.
+                */
+               ice_rem_chg_tcam_ent(hw, tcam->tcam_idx, chg);
                tcam->tcam_idx = 0;
                tcam->in_use = 0;
                return status;
        }
 
-       /* for re-enabling, reallocate a tcam */
+       /* for re-enabling, reallocate a TCAM */
        status = ice_alloc_tcam_ent(hw, blk, &tcam->tcam_idx);
        if (status)
                return status;
@@ -5099,9 +5247,12 @@ ice_prof_tcam_ena_dis(struct ice_hw *hw, enum ice_block blk, bool enable,
        if (!p)
                return ICE_ERR_NO_MEMORY;
 
+       /* set don't care masks for TCAM flags */
+       ice_set_tcam_flags(tcam->attr.mask, dc_msk);
+
        status = ice_tcam_write_entry(hw, blk, tcam->tcam_idx, tcam->prof_id,
-                                     tcam->ptg, vsig, 0, 0, vl_msk, dc_msk,
-                                     nm_msk);
+                                     tcam->ptg, vsig, 0, tcam->attr.flags,
+                                     vl_msk, dc_msk, nm_msk);
        if (status)
                goto err_ice_prof_tcam_ena_dis;
 
@@ -5124,6 +5275,32 @@ err_ice_prof_tcam_ena_dis:
        return status;
 }
 
+/**
+ * ice_ptg_attr_in_use - determine if PTG and attribute pair is in use
+ * @ptg_attr: pointer to the PTG and attribute pair to check
+ * @ptgs_used: bitmap that denotes which PTGs are in use
+ * @attr_used: array of PTG and attributes pairs already used
+ * @attr_cnt: count of entries in the attr_used array
+ */
+static bool
+ice_ptg_attr_in_use(struct ice_tcam_inf *ptg_attr, ice_bitmap_t *ptgs_used,
+                   struct ice_tcam_inf *attr_used[], u16 attr_cnt)
+{
+       u16 i;
+
+       if (!ice_is_bit_set(ptgs_used, ptg_attr->ptg))
+               return false;
+
+       /* the PTG is used, so now look for correct attributes */
+       for (i = 0; i < attr_cnt; i++)
+               if (attr_used[i]->ptg == ptg_attr->ptg &&
+                   attr_used[i]->attr.flags == ptg_attr->attr.flags &&
+                   attr_used[i]->attr.mask == ptg_attr->attr.mask)
+                       return true;
+
+       return false;
+}
+
 /**
  * ice_adj_prof_priorities - adjust profile based on priorities
  * @hw: pointer to the HW struct
@@ -5136,10 +5313,18 @@ ice_adj_prof_priorities(struct ice_hw *hw, enum ice_block blk, u16 vsig,
                        struct LIST_HEAD_TYPE *chg)
 {
        ice_declare_bitmap(ptgs_used, ICE_XLT1_CNT);
+       struct ice_tcam_inf **attr_used;
+       enum ice_status status = ICE_SUCCESS;
        struct ice_vsig_prof *t;
-       enum ice_status status;
+       u16 attr_used_cnt = 0;
        u16 idx;
 
+#define ICE_MAX_PTG_ATTRS      1024
+       attr_used = (struct ice_tcam_inf **)ice_calloc(hw, ICE_MAX_PTG_ATTRS,
+                                                      sizeof(*attr_used));
+       if (!attr_used)
+               return ICE_ERR_NO_MEMORY;
+
        ice_zero_bitmap(ptgs_used, ICE_XLT1_CNT);
        idx = vsig & ICE_VSIG_IDX_M;
 
@@ -5157,11 +5342,15 @@ ice_adj_prof_priorities(struct ice_hw *hw, enum ice_block blk, u16 vsig,
                u16 i;
 
                for (i = 0; i < t->tcam_count; i++) {
+                       bool used;
+
                        /* Scan the priorities from newest to oldest.
                         * Make sure that the newest profiles take priority.
                         */
-                       if (ice_is_bit_set(ptgs_used, t->tcam[i].ptg) &&
-                           t->tcam[i].in_use) {
+                       used = ice_ptg_attr_in_use(&t->tcam[i], ptgs_used,
+                                                  attr_used, attr_used_cnt);
+
+                       if (used && t->tcam[i].in_use) {
                                /* need to mark this PTG as never match, as it
                                 * was already in use and therefore duplicate
                                 * (and lower priority)
@@ -5171,9 +5360,8 @@ ice_adj_prof_priorities(struct ice_hw *hw, enum ice_block blk, u16 vsig,
                                                               &t->tcam[i],
                                                               chg);
                                if (status)
-                                       return status;
-                       } else if (!ice_is_bit_set(ptgs_used, t->tcam[i].ptg) &&
-                                  !t->tcam[i].in_use) {
+                                       goto err_ice_adj_prof_priorities;
+                       } else if (!used && !t->tcam[i].in_use) {
                                /* need to enable this PTG, as it in not in use
                                 * and not enabled (highest priority)
                                 */
@@ -5182,15 +5370,22 @@ ice_adj_prof_priorities(struct ice_hw *hw, enum ice_block blk, u16 vsig,
                                                               &t->tcam[i],
                                                               chg);
                                if (status)
-                                       return status;
+                                       goto err_ice_adj_prof_priorities;
                        }
 
                        /* keep track of used ptgs */
                        ice_set_bit(t->tcam[i].ptg, ptgs_used);
+                       if (attr_used_cnt < ICE_MAX_PTG_ATTRS)
+                               attr_used[attr_used_cnt++] = &t->tcam[i];
+                       else
+                               ice_debug(hw, ICE_DBG_INIT,
+                                         "Warn: ICE_MAX_PTG_ATTRS exceeded\n");
                }
        }
 
-       return ICE_SUCCESS;
+err_ice_adj_prof_priorities:
+       ice_free(hw, attr_used);
+       return status;
 }
 
 /**
@@ -5199,11 +5394,12 @@ ice_adj_prof_priorities(struct ice_hw *hw, enum ice_block blk, u16 vsig,
  * @blk: hardware block
  * @vsig: the VSIG to which this profile is to be added
  * @hdl: the profile handle indicating the profile to add
+ * @rev: true to add entries to the end of the list
  * @chg: the change list
  */
 static enum ice_status
 ice_add_prof_id_vsig(struct ice_hw *hw, enum ice_block blk, u16 vsig, u64 hdl,
-                    struct LIST_HEAD_TYPE *chg)
+                    bool rev, struct LIST_HEAD_TYPE *chg)
 {
        /* Masks that ignore flags */
        u8 vl_msk[ICE_TCAM_KEY_VAL_SZ] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
@@ -5212,7 +5408,7 @@ ice_add_prof_id_vsig(struct ice_hw *hw, enum ice_block blk, u16 vsig, u64 hdl,
        struct ice_prof_map *map;
        struct ice_vsig_prof *t;
        struct ice_chs_chg *p;
-       u16 i;
+       u16 vsig_idx, i;
 
        /* Get the details on the profile specified by the handle ID */
        map = ice_search_prof_id(hw, blk, hdl);
@@ -5226,7 +5422,7 @@ ice_add_prof_id_vsig(struct ice_hw *hw, enum ice_block blk, u16 vsig, u64 hdl,
        /* new VSIG profile structure */
        t = (struct ice_vsig_prof *)ice_malloc(hw, sizeof(*t));
        if (!t)
-               goto err_ice_add_prof_id_vsig;
+               return ICE_ERR_NO_MEMORY;
 
        t->profile_cookie = map->profile_cookie;
        t->prof_id = map->prof_id;
@@ -5252,6 +5448,7 @@ ice_add_prof_id_vsig(struct ice_hw *hw, enum ice_block blk, u16 vsig, u64 hdl,
                t->tcam[i].ptg = map->ptg[i];
                t->tcam[i].prof_id = map->prof_id;
                t->tcam[i].tcam_idx = tcam_idx;
+               t->tcam[i].attr = map->attr[i];
                t->tcam[i].in_use = true;
 
                p->type = ICE_TCAM_ADD;
@@ -5261,21 +5458,32 @@ ice_add_prof_id_vsig(struct ice_hw *hw, enum ice_block blk, u16 vsig, u64 hdl,
                p->vsig = vsig;
                p->tcam_idx = t->tcam[i].tcam_idx;
 
+               /* set don't care masks for TCAM flags */
+               ice_set_tcam_flags(t->tcam[i].attr.mask, dc_msk);
+
                /* write the TCAM entry */
                status = ice_tcam_write_entry(hw, blk, t->tcam[i].tcam_idx,
                                              t->tcam[i].prof_id,
-                                             t->tcam[i].ptg, vsig, 0, 0,
-                                             vl_msk, dc_msk, nm_msk);
-               if (status)
+                                             t->tcam[i].ptg, vsig, 0,
+                                             t->tcam[i].attr.flags, vl_msk,
+                                             dc_msk, nm_msk);
+               if (status) {
+                       ice_free(hw, p);
                        goto err_ice_add_prof_id_vsig;
+               }
 
                /* log change */
                LIST_ADD(&p->list_entry, chg);
        }
 
        /* add profile to VSIG */
-       LIST_ADD(&t->list,
-                &hw->blk[blk].xlt2.vsig_tbl[(vsig & ICE_VSIG_IDX_M)].prop_lst);
+       vsig_idx = vsig & ICE_VSIG_IDX_M;
+       if (rev)
+               LIST_ADD_TAIL(&t->list,
+                             &hw->blk[blk].xlt2.vsig_tbl[vsig_idx].prop_lst);
+       else
+               LIST_ADD(&t->list,
+                        &hw->blk[blk].xlt2.vsig_tbl[vsig_idx].prop_lst);
 
        return ICE_SUCCESS;
 
@@ -5315,7 +5523,7 @@ ice_create_prof_id_vsig(struct ice_hw *hw, enum ice_block blk, u16 vsi, u64 hdl,
        if (status)
                goto err_ice_create_prof_id_vsig;
 
-       status = ice_add_prof_id_vsig(hw, blk, new_vsig, hdl, chg);
+       status = ice_add_prof_id_vsig(hw, blk, new_vsig, hdl, false, chg);
        if (status)
                goto err_ice_create_prof_id_vsig;
 
@@ -5335,16 +5543,18 @@ err_ice_create_prof_id_vsig:
 }
 
 /**
- * ice_create_vsig_from_list - create a new VSIG with a list of profiles
+ * ice_create_vsig_from_lst - create a new VSIG with a list of profiles
  * @hw: pointer to the HW struct
  * @blk: hardware block
  * @vsi: the initial VSI that will be in VSIG
  * @lst: the list of profile that will be added to the VSIG
+ * @new_vsig: return of new VSIG
  * @chg: the change list
  */
 static enum ice_status
 ice_create_vsig_from_lst(struct ice_hw *hw, enum ice_block blk, u16 vsi,
-                        struct LIST_HEAD_TYPE *lst, struct LIST_HEAD_TYPE *chg)
+                        struct LIST_HEAD_TYPE *lst, u16 *new_vsig,
+                        struct LIST_HEAD_TYPE *chg)
 {
        struct ice_vsig_prof *t;
        enum ice_status status;
@@ -5359,12 +5569,15 @@ ice_create_vsig_from_lst(struct ice_hw *hw, enum ice_block blk, u16 vsi,
                return status;
 
        LIST_FOR_EACH_ENTRY(t, lst, ice_vsig_prof, list) {
+               /* Reverse the order here since we are copying the list */
                status = ice_add_prof_id_vsig(hw, blk, vsig, t->profile_cookie,
-                                             chg);
+                                             true, chg);
                if (status)
                        return status;
        }
 
+       *new_vsig = vsig;
+
        return ICE_SUCCESS;
 }
 
@@ -5457,13 +5670,11 @@ ice_add_prof_id_flow(struct ice_hw *hw, enum ice_block blk, u16 vsi, u64 hdl)
        struct ice_vsig_prof *tmp1, *del1;
        struct LIST_HEAD_TYPE union_lst;
        struct ice_chs_chg *tmp, *del;
-       struct LIST_HEAD_TYPE chrs;
        struct LIST_HEAD_TYPE chg;
        enum ice_status status;
-       u16 vsig, or_vsig = 0;
+       u16 vsig;
 
        INIT_LIST_HEAD(&union_lst);
-       INIT_LIST_HEAD(&chrs);
        INIT_LIST_HEAD(&chg);
 
        /* Get profile */
@@ -5475,9 +5686,10 @@ ice_add_prof_id_flow(struct ice_hw *hw, enum ice_block blk, u16 vsi, u64 hdl)
        status = ice_vsig_find_vsi(hw, blk, vsi, &vsig);
        if (!status && vsig) {
                bool only_vsi;
+               u16 or_vsig;
                u16 ref;
 
-               /* found in vsig */
+               /* found in VSIG */
                or_vsig = vsig;
 
                /* make sure that there is no overlap/conflict between the new
@@ -5528,7 +5740,8 @@ ice_add_prof_id_flow(struct ice_hw *hw, enum ice_block blk, u16 vsi, u64 hdl)
                         * not sharing entries and we can simply add the new
                         * profile to the VSIG.
                         */
-                       status = ice_add_prof_id_vsig(hw, blk, vsig, hdl, &chg);
+                       status = ice_add_prof_id_vsig(hw, blk, vsig, hdl, false,
+                                                     &chg);
                        if (status)
                                goto err_ice_add_prof_id_flow;
 
@@ -5539,7 +5752,8 @@ ice_add_prof_id_flow(struct ice_hw *hw, enum ice_block blk, u16 vsi, u64 hdl)
                } else {
                        /* No match, so we need a new VSIG */
                        status = ice_create_vsig_from_lst(hw, blk, vsi,
-                                                         &union_lst, &chg);
+                                                         &union_lst, &vsig,
+                                                         &chg);
                        if (status)
                                goto err_ice_add_prof_id_flow;
 
@@ -5582,11 +5796,6 @@ err_ice_add_prof_id_flow:
                ice_free(hw, del1);
        }
 
-       LIST_FOR_EACH_ENTRY_SAFE(del1, tmp1, &chrs, ice_vsig_prof, list) {
-               LIST_DEL(&del1->list);
-               ice_free(hw, del1);
-       }
-
        return status;
 }
 
@@ -5711,7 +5920,8 @@ ice_rem_prof_id_flow(struct ice_hw *hw, enum ice_block blk, u16 vsi, u64 hdl)
                                 * new VSIG and TCAM entries
                                 */
                                status = ice_create_vsig_from_lst(hw, blk, vsi,
-                                                                 &copy, &chg);
+                                                                 &copy, &vsig,
+                                                                 &chg);
                                if (status)
                                        goto err_ice_rem_prof_id_flow;