net/sfc/base: add APIs for PTP privilege configuration
[dpdk.git] / drivers / net / ice / base / ice_flex_pipe.c
index 99108d8..14e632f 100644 (file)
@@ -1274,6 +1274,25 @@ void ice_free_seg(struct ice_hw *hw)
        hw->seg = NULL;
 }
 
+/**
+ * ice_init_fd_mask_regs - initialize Flow Director mask registers
+ * @hw: pointer to the HW struct
+ *
+ * This function sets up the Flow Director mask registers to allow for complete
+ * masking off of any of the 24 Field Vector words. After this call, mask 0 will
+ * mask off all of FV index 0, mask 1 will mask off all of FV index 1, etc.
+ */
+static void ice_init_fd_mask_regs(struct ice_hw *hw)
+{
+       u16 i;
+
+       for (i = 0; i < hw->blk[ICE_BLK_FD].es.fvw; i++) {
+               wr32(hw, GLQF_FDMASK(i), i);
+               ice_debug(hw, ICE_DBG_INIT, "init fd mask(%d): %x = %x\n", i,
+                         GLQF_FDMASK(i), i);
+       }
+}
+
 /**
  * ice_init_pkg_regs - initialize additional package registers
  * @hw: pointer to the hardware structure
@@ -1287,6 +1306,8 @@ static void ice_init_pkg_regs(struct ice_hw *hw)
        /* 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);
        wr32(hw, GL_PREEXT_L2_PMASK1(ICE_SW_BLK_IDX), ICE_SW_BLK_INP_MASK_H);
+       /* setup default flow director masks */
+       ice_init_fd_mask_regs(hw);
 }
 
 /**
@@ -2281,21 +2302,23 @@ ice_vsig_free(struct ice_hw *hw, enum ice_block blk, u16 vsig)
        hw->blk[blk].xlt2.vsig_tbl[idx].in_use = false;
 
        vsi_cur = hw->blk[blk].xlt2.vsig_tbl[idx].first_vsi;
-       if (!vsi_cur)
-               return ICE_ERR_CFG;
-
-       /* remove all vsis associated with this VSIG XLT2 entry */
-       do {
-               struct ice_vsig_vsi *tmp = vsi_cur->next_vsi;
-
-               vsi_cur->vsig = ICE_DEFAULT_VSIG;
-               vsi_cur->changed = 1;
-               vsi_cur->next_vsi = NULL;
-               vsi_cur = tmp;
-       } while (vsi_cur);
-
-       /* NULL terminate head of vsi list */
-       hw->blk[blk].xlt2.vsig_tbl[idx].first_vsi = NULL;
+       /* If the VSIG has at least 1 VSI then iterate through the
+        * list and remove the VSIs before deleting the group.
+        */
+       if (vsi_cur) {
+               /* remove all vsis associated with this VSIG XLT2 entry */
+               do {
+                       struct ice_vsig_vsi *tmp = vsi_cur->next_vsi;
+
+                       vsi_cur->vsig = ICE_DEFAULT_VSIG;
+                       vsi_cur->changed = 1;
+                       vsi_cur->next_vsi = NULL;
+                       vsi_cur = tmp;
+               } while (vsi_cur);
+
+               /* NULL terminate head of VSI list */
+               hw->blk[blk].xlt2.vsig_tbl[idx].first_vsi = NULL;
+       }
 
        /* free characteristic list */
        LIST_FOR_EACH_ENTRY_SAFE(del, dtmp,
@@ -2444,7 +2467,7 @@ ice_find_prof_id(struct ice_hw *hw, enum ice_block blk,
        for (i = 0; i < es->count; i++) {
                off = i * es->fvw;
 
-               if (memcmp(&es->t[off], fv, es->fvw * 2))
+               if (memcmp(&es->t[off], fv, es->fvw * sizeof(*fv)))
                        continue;
 
                *prof_id = i;
@@ -2512,199 +2535,6 @@ static bool ice_tcam_ent_rsrc_type(enum ice_block blk, u16 *rsrc_type)
        return true;
 }
 
-/**
- * ice_workaround_get_res_blk - determine the block from a resource type
- * @type: type of resource
- * @blk: pointer to a enum that will receive the block type
- * @tcam: pointer to variable that will be set to true for a TCAM resource type
- */
-static enum
-ice_status ice_workaround_get_res_blk(u16 type, enum ice_block *blk, bool *tcam)
-{
-       /* just need to support TCAM entries and Profile IDs for now */
-       *tcam = false;
-
-       switch (type) {
-       case ICE_AQC_RES_TYPE_SWITCH_PROF_BLDR_TCAM:
-               *blk = ICE_BLK_SW;
-               *tcam = true;
-               break;
-       case ICE_AQC_RES_TYPE_ACL_PROF_BLDR_TCAM:
-               *blk = ICE_BLK_ACL;
-               *tcam = true;
-               break;
-       case ICE_AQC_RES_TYPE_FD_PROF_BLDR_TCAM:
-               *blk = ICE_BLK_FD;
-               *tcam = true;
-               break;
-       case ICE_AQC_RES_TYPE_HASH_PROF_BLDR_TCAM:
-               *blk = ICE_BLK_RSS;
-               *tcam = true;
-               break;
-       case ICE_AQC_RES_TYPE_QHASH_PROF_BLDR_TCAM:
-               *blk = ICE_BLK_PE;
-               *tcam = true;
-               break;
-       case ICE_AQC_RES_TYPE_SWITCH_PROF_BLDR_PROFID:
-               *blk = ICE_BLK_SW;
-               break;
-       case ICE_AQC_RES_TYPE_ACL_PROF_BLDR_PROFID:
-               *blk = ICE_BLK_ACL;
-               break;
-       case ICE_AQC_RES_TYPE_FD_PROF_BLDR_PROFID:
-               *blk = ICE_BLK_FD;
-               break;
-       case ICE_AQC_RES_TYPE_HASH_PROF_BLDR_PROFID:
-               *blk = ICE_BLK_RSS;
-               break;
-       case ICE_AQC_RES_TYPE_QHASH_PROF_BLDR_PROFID:
-               *blk = ICE_BLK_PE;
-               break;
-       default:
-               return ICE_ERR_PARAM;
-       }
-
-       return ICE_SUCCESS;
-}
-
-/**
- * ice_alloc_res_workaround
- * @hw: pointer to the hw struct
- * @type: type of resource
- * @num: number of resources to allocate
- * @res: pointer to array that will receive the resources
- */
-static enum ice_status
-ice_alloc_res_workaround(struct ice_hw *hw, u16 type, u16 num, u16 *res)
-{
-       enum ice_block blk;
-       u16 count = 0;
-       bool tcam;
-       u16 first;
-       u16 last;
-       u16 max;
-       u16 i;
-
-/* Number of PFs we support with this workaround */
-#define ICE_WA_PF_COUNT        4
-#define ICE_WA_1ST_TCAM        4
-#define ICE_WA_1ST_FV  4
-
-       /* Only allow our supported PFs */
-       if (hw->pf_id >= ICE_WA_PF_COUNT)
-               return ICE_ERR_AQ_ERROR;
-
-       if (ice_workaround_get_res_blk(type, &blk, &tcam))
-               return ICE_ERR_AQ_ERROR;
-
-       if (tcam) {
-               /* range of entries based on PF */
-               max = hw->blk[blk].prof.count / ICE_WA_PF_COUNT;
-               first = max * hw->pf_id;
-               last = first + max;
-
-               /* Profile IDs - start at non-zero index for PROF ID TCAM table
-                * The first few entries are for bypass, default and errors
-                * (only relevant for PF 0)
-                */
-               first += hw->pf_id ? 0 : ICE_WA_1ST_TCAM;
-
-               for (i = first; i < last && count < num; i++) {
-                       if (!hw->blk[blk].prof.resource_used_hack[i]) {
-                               res[count++] = i;
-                               hw->blk[blk].prof.resource_used_hack[i] = true;
-                       }
-               }
-
-               /* handle failure case */
-               if (count < num) {
-                       for (i = 0; i < count; i++) {
-                               hw->blk[blk].prof.resource_used_hack[res[i]] =
-                                       false;
-                               res[i] = 0;
-                       }
-
-                       return ICE_ERR_AQ_ERROR;
-               }
-       } else {
-               /* range of entries based on PF */
-               max = hw->blk[blk].es.count / ICE_WA_PF_COUNT;
-               first = max * hw->pf_id;
-               last = first + max;
-
-               /* FV index - start at non-zero index for Field vector table
-                * The first few entries are for bypass, default and errors
-                * (only relevant for PF 0)
-                */
-               first += hw->pf_id ? 0 : ICE_WA_1ST_FV;
-
-               for (i = first; i < last && count < num; i++) {
-                       if (!hw->blk[blk].es.resource_used_hack[i]) {
-                               res[count++] = i;
-                               hw->blk[blk].es.resource_used_hack[i] = true;
-                       }
-               }
-
-               /* handle failure case */
-               if (count < num) {
-                       for (i = 0; i < count; i++) {
-                               hw->blk[blk].es.resource_used_hack[res[i]] =
-                                       false;
-                               res[i] = 0;
-                       }
-
-                       return ICE_ERR_AQ_ERROR;
-               }
-       }
-
-       return ICE_SUCCESS;
-}
-
-/**
- * ice_free_res_workaround
- * @hw: pointer to the hw struct
- * @type: type of resource to free
- * @num: number of resources
- * @res: array of resource ids to free
- */
-static enum ice_status
-ice_free_res_workaround(struct ice_hw *hw, u16 type, u16 num, u16 *res)
-{
-       enum ice_block blk;
-       bool tcam = false;
-       u16 i;
-
-       if (ice_workaround_get_res_blk(type, &blk, &tcam))
-               return ICE_ERR_AQ_ERROR;
-
-       if (tcam) {
-               /* TCAM entries */
-               for (i = 0; i < num; i++) {
-                       if (res[i] < hw->blk[blk].prof.count) {
-                               u16 idx = res[i];
-
-                               ice_free_hw_res(hw, type, 1, &idx);
-                               hw->blk[blk].prof.resource_used_hack[res[i]] =
-                                       false;
-                       }
-               }
-
-       } else {
-               /* Profile IDs */
-               for (i = 0; i < num; i++) {
-                       if (res[i] < hw->blk[blk].es.count) {
-                               u16 idx = res[i];
-
-                               ice_free_hw_res(hw, type, 1, &idx);
-                               hw->blk[blk].es.resource_used_hack[res[i]] =
-                                       false;
-                       }
-               }
-       }
-
-       return ICE_SUCCESS;
-}
-
 /**
  * ice_alloc_tcam_ent - allocate hardware TCAM entry
  * @hw: pointer to the HW struct
@@ -2722,7 +2552,7 @@ ice_alloc_tcam_ent(struct ice_hw *hw, enum ice_block blk, u16 *tcam_idx)
        if (!ice_tcam_ent_rsrc_type(blk, &res_type))
                return ICE_ERR_PARAM;
 
-       return ice_alloc_res_workaround(hw, res_type, 1, tcam_idx);
+       return ice_alloc_hw_res(hw, res_type, 1, true, tcam_idx);
 }
 
 /**
@@ -2741,7 +2571,7 @@ ice_free_tcam_ent(struct ice_hw *hw, enum ice_block blk, u16 tcam_idx)
        if (!ice_tcam_ent_rsrc_type(blk, &res_type))
                return ICE_ERR_PARAM;
 
-       return ice_free_res_workaround(hw, res_type, 1, &tcam_idx);
+       return ice_free_hw_res(hw, res_type, 1, &tcam_idx);
 }
 
 /**
@@ -2763,7 +2593,7 @@ ice_alloc_prof_id(struct ice_hw *hw, enum ice_block blk, u8 *prof_id)
        if (!ice_prof_id_rsrc_type(blk, &res_type))
                return ICE_ERR_PARAM;
 
-       status = ice_alloc_res_workaround(hw, res_type, 1, &get_prof);
+       status = ice_alloc_hw_res(hw, res_type, 1, false, &get_prof);
        if (!status)
                *prof_id = (u8)get_prof;
 
@@ -2787,15 +2617,7 @@ ice_free_prof_id(struct ice_hw *hw, enum ice_block blk, u8 prof_id)
        if (!ice_prof_id_rsrc_type(blk, &res_type))
                return ICE_ERR_PARAM;
 
-       return ice_free_res_workaround(hw, res_type, 1, &tmp_prof_id);
-       /* The following code is a WORKAROUND until DCR 076 is available.
-        * DCR 076 - Update to Profile ID TCAM Resource Allocation
-        *
-        * Once the DCR 076 changes are available in FW, this code can be
-        * restored. Original code:
-        *
-        * return ice_free_res(hw, res_type, 1, &tmp_prof_id);
-        */
+       return ice_free_hw_res(hw, res_type, 1, &tmp_prof_id);
 }
 
 /**
@@ -3102,8 +2924,7 @@ static void ice_free_prof_map(struct ice_hw *hw, enum ice_block blk)
 
        LIST_FOR_EACH_ENTRY_SAFE(del, tmp, &hw->blk[blk].es.prof_map,
                                 ice_prof_map, list) {
-               LIST_DEL(&del->list);
-               ice_free(hw, del);
+               ice_rem_prof(hw, blk, del->profile_cookie);
        }
 }
 
@@ -3145,9 +2966,6 @@ void ice_free_hw_tbls(struct ice_hw *hw)
                ice_free(hw, hw->blk[i].prof_redir.t);
                ice_free(hw, hw->blk[i].es.t);
                ice_free(hw, hw->blk[i].es.ref_count);
-
-               ice_free(hw, hw->blk[i].es.resource_used_hack);
-               ice_free(hw, hw->blk[i].prof.resource_used_hack);
                ice_free(hw, hw->blk[i].es.written);
        }
 
@@ -3324,18 +3142,6 @@ enum ice_status ice_init_hw_tbls(struct ice_hw *hw)
                if (!es->ref_count)
                        goto err;
 
-               es->resource_used_hack = (u8 *)
-                       ice_calloc(hw, hw->blk[i].es.count, sizeof(u8));
-
-               if (!es->resource_used_hack)
-                       goto err;
-
-               prof->resource_used_hack = (u8 *)ice_calloc(hw, prof->count,
-                                                           sizeof(u8));
-
-               if (!prof->resource_used_hack)
-                       goto err;
-
                INIT_LIST_HEAD(&es->prof_map);
 
                /* Now that tables are allocated, read in package data */
@@ -3782,6 +3588,205 @@ error_tmp:
        return status;
 }
 
+/**
+ * ice_update_fd_mask - set Flow Director Field Vector mask for a profile
+ * @hw: pointer to the HW struct
+ * @prof_id: profile ID
+ * @mask_sel: mask select
+ *
+ * This function enable any of the masks selected by the mask select parameter
+ * for the profile specified.
+ */
+static void ice_update_fd_mask(struct ice_hw *hw, u16 prof_id, u32 mask_sel)
+{
+       wr32(hw, GLQF_FDMASK_SEL(prof_id), mask_sel);
+
+       ice_debug(hw, ICE_DBG_INIT, "fd mask(%d): %x = %x\n", prof_id,
+                 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;
+       u16 off;
+};
+
+static const struct ice_fd_src_dst_pair ice_fd_pairs[] = {
+       /* These are defined in pairs */
+       { ICE_PROT_IPV4_OF_OR_S, 2, 12 },
+       { ICE_PROT_IPV4_OF_OR_S, 2, 16 },
+
+       { ICE_PROT_IPV4_IL, 2, 12 },
+       { ICE_PROT_IPV4_IL, 2, 16 },
+
+       { ICE_PROT_IPV6_OF_OR_S, 8, 8 },
+       { ICE_PROT_IPV6_OF_OR_S, 8, 24 },
+
+       { ICE_PROT_IPV6_IL, 8, 8 },
+       { ICE_PROT_IPV6_IL, 8, 24 },
+
+       { ICE_PROT_TCP_IL, 1, 0 },
+       { ICE_PROT_TCP_IL, 1, 2 },
+
+       { ICE_PROT_UDP_OF, 1, 0 },
+       { ICE_PROT_UDP_OF, 1, 2 },
+
+       { ICE_PROT_UDP_IL_OR_S, 1, 0 },
+       { ICE_PROT_UDP_IL_OR_S, 1, 2 },
+
+       { ICE_PROT_SCTP_IL, 1, 0 },
+       { ICE_PROT_SCTP_IL, 1, 2 }
+};
+
+#define ICE_FD_SRC_DST_PAIR_COUNT      ARRAY_SIZE(ice_fd_pairs)
+
+/**
+ * ice_update_fd_swap - set register appropriately for a FD FV extraction
+ * @hw: pointer to the HW struct
+ * @prof_id: profile ID
+ * @es: extraction sequence (length of array is determined by the block)
+ */
+static enum ice_status
+ice_update_fd_swap(struct ice_hw *hw, u16 prof_id, struct ice_fv_word *es)
+{
+       ice_declare_bitmap(pair_list, ICE_FD_SRC_DST_PAIR_COUNT);
+       u8 pair_start[ICE_FD_SRC_DST_PAIR_COUNT] = { 0 };
+#define ICE_FD_FV_NOT_FOUND (-2)
+       s8 first_free = ICE_FD_FV_NOT_FOUND;
+       u8 used[ICE_MAX_FV_WORDS] = { 0 };
+       s8 orig_free, si;
+       u32 mask_sel = 0;
+       u8 i, j, k;
+
+       ice_memset(pair_list, 0, sizeof(pair_list), ICE_NONDMA_MEM);
+
+       ice_init_fd_mask_regs(hw);
+
+       /* This code assumes that the Flow Director field vectors are assigned
+        * from the end of the FV indexes working towards the zero index, that
+        * only complete fields will be included and will be consecutive, and
+        * that there are no gaps between valid indexes.
+        */
+
+       /* Determine swap fields present */
+       for (i = 0; i < hw->blk[ICE_BLK_FD].es.fvw; i++) {
+               /* Find the first free entry, assuming right to left population.
+                * This is where we can start adding additional pairs if needed.
+                */
+               if (first_free == ICE_FD_FV_NOT_FOUND && es[i].prot_id !=
+                   ICE_PROT_INVALID)
+                       first_free = i - 1;
+
+               for (j = 0; j < ICE_FD_SRC_DST_PAIR_COUNT; j++) {
+                       if (es[i].prot_id == ice_fd_pairs[j].prot_id &&
+                           es[i].off == ice_fd_pairs[j].off) {
+                               ice_set_bit(j, pair_list);
+                               pair_start[j] = i;
+                       }
+               }
+       }
+
+       orig_free = first_free;
+
+       /* determine missing swap fields that need to be added */
+       for (i = 0; i < ICE_FD_SRC_DST_PAIR_COUNT; i += 2) {
+               u8 bit1 = ice_is_bit_set(pair_list, i + 1);
+               u8 bit0 = ice_is_bit_set(pair_list, i);
+
+               if (bit0 ^ bit1) {
+                       u8 index;
+
+                       /* add the appropriate 'paired' entry */
+                       if (!bit0)
+                               index = i;
+                       else
+                               index = i + 1;
+
+                       /* check for room */
+                       if (first_free + 1 < ice_fd_pairs[index].count)
+                               return ICE_ERR_MAX_LIMIT;
+
+                       /* place in extraction sequence */
+                       for (k = 0; k < ice_fd_pairs[index].count; k++) {
+                               es[first_free - k].prot_id =
+                                       ice_fd_pairs[index].prot_id;
+                               es[first_free - k].off =
+                                       ice_fd_pairs[index].off + (k * 2);
+
+                               /* keep track of non-relevant fields */
+                               mask_sel |= 1 << (first_free - k);
+                       }
+
+                       pair_start[index] = first_free;
+                       first_free -= ice_fd_pairs[index].count;
+               }
+       }
+
+       /* fill in the swap array */
+       si = hw->blk[ICE_BLK_FD].es.fvw - 1;
+       do {
+               u8 indexes_used = 1;
+
+               /* assume flat at this index */
+#define ICE_SWAP_VALID 0x80
+               used[si] = si | ICE_SWAP_VALID;
+
+               if (orig_free == ICE_FD_FV_NOT_FOUND || si <= orig_free) {
+                       si -= indexes_used;
+                       continue;
+               }
+
+               /* check for a swap location */
+               for (j = 0; j < ICE_FD_SRC_DST_PAIR_COUNT; j++) {
+                       if (es[si].prot_id == ice_fd_pairs[j].prot_id &&
+                           es[si].off == ice_fd_pairs[j].off) {
+                               u8 idx;
+
+                               /* determine the appropriate matching field */
+                               idx = j + ((j % 2) ? -1 : 1);
+
+                               indexes_used = ice_fd_pairs[idx].count;
+                               for (k = 0; k < indexes_used; k++) {
+                                       used[si - k] = (pair_start[idx] - k) |
+                                               ICE_SWAP_VALID;
+                               }
+
+                               break;
+                       }
+               }
+
+               si -= indexes_used;
+       } while (si >= 0);
+
+       /* for each set of 4 swap indexes, write the appropriate register */
+       for (j = 0; j < hw->blk[ICE_BLK_FD].es.fvw / 4; j++) {
+               u32 raw_entry = 0;
+
+               for (k = 0; k < 4; k++) {
+                       u8 idx;
+
+                       idx = (j * 4) + k;
+                       if (used[idx])
+                               raw_entry |= used[idx] << (k * 8);
+               }
+
+               /* write the appropriate register set, based on HW block */
+               wr32(hw, GLQF_FDSWAP(prof_id, j), raw_entry);
+
+               ice_debug(hw, ICE_DBG_INIT, "swap wr(%d, %d): %x = %x\n",
+                         prof_id, j, GLQF_FDSWAP(prof_id, j), raw_entry);
+       }
+
+       /* update the masks for this profile to be sure we ignore fields that
+        * are not relevant to our match criteria
+        */
+       ice_update_fd_mask(hw, prof_id, mask_sel);
+
+       return ICE_SUCCESS;
+}
+
 /**
  * ice_add_prof - add profile
  * @hw: pointer to the HW struct
@@ -3812,6 +3817,18 @@ ice_add_prof(struct ice_hw *hw, enum ice_block blk, u64 id, u8 ptypes[],
                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;
+               }
 
                /* and write new es */
                ice_write_es(hw, blk, prof_id, es);
@@ -4035,36 +4052,32 @@ ice_rem_vsig(struct ice_hw *hw, enum ice_block blk, u16 vsig,
 
        /* Move all VSIS associated with this VSIG to the default VSIG */
        vsi_cur = hw->blk[blk].xlt2.vsig_tbl[idx].first_vsi;
-       if (!vsi_cur)
-               return ICE_ERR_CFG;
-
-       do {
-               struct ice_vsig_vsi *tmp = vsi_cur->next_vsi;
-               struct ice_chs_chg *p;
-
-               p = (struct ice_chs_chg *)ice_malloc(hw, sizeof(*p));
-               if (!p)
-                       goto err_ice_rem_vsig;
+       /* If the VSIG has at least 1 VSI then iterate through the list
+        * and remove the VSIs before deleting the group.
+        */
+       if (vsi_cur) {
+               do {
+                       struct ice_vsig_vsi *tmp = vsi_cur->next_vsi;
+                       struct ice_chs_chg *p;
 
-               p->type = ICE_VSIG_REM;
-               p->orig_vsig = vsig;
-               p->vsig = ICE_DEFAULT_VSIG;
-               p->vsi = vsi_cur - hw->blk[blk].xlt2.vsis;
+                       p = (struct ice_chs_chg *)ice_malloc(hw, sizeof(*p));
+                       if (!p)
+                               return ICE_ERR_NO_MEMORY;
 
-               LIST_ADD(&p->list_entry, chg);
+                       p->type = ICE_VSIG_REM;
+                       p->orig_vsig = vsig;
+                       p->vsig = ICE_DEFAULT_VSIG;
+                       p->vsi = vsi_cur - hw->blk[blk].xlt2.vsis;
 
-               status = ice_vsig_free(hw, blk, vsig);
-               if (status)
-                       return status;
+                       LIST_ADD(&p->list_entry, chg);
 
-               vsi_cur = tmp;
-       } while (vsi_cur);
+                       vsi_cur = tmp;
+               } while (vsi_cur);
+       }
 
-       return ICE_SUCCESS;
+       status = ice_vsig_free(hw, blk, vsig);
 
-err_ice_rem_vsig:
-       /* the caller will free up the change list */
-       return ICE_ERR_NO_MEMORY;
+       return status;
 }
 
 /**
@@ -4160,13 +4173,13 @@ enum ice_status ice_rem_prof(struct ice_hw *hw, enum ice_block blk, u64 id)
        if (!pmap)
                return ICE_ERR_DOES_NOT_EXIST;
 
-       status = ice_free_prof_id(hw, blk, pmap->prof_id);
-
+       /* remove all flows with this profile */
+       status = ice_rem_flow_all(hw, blk, pmap->profile_cookie);
        if (status)
                return status;
 
-       /* remove all flows with this profile */
-       status = ice_rem_flow_all(hw, blk, pmap->profile_cookie);
+       /* remove profile */
+       status = ice_free_prof_id(hw, blk, pmap->prof_id);
        if (status)
                return status;
        /* dereference profile, and possibly remove */
@@ -4261,7 +4274,7 @@ ice_get_profs_vsig(struct ice_hw *hw, enum ice_block blk, u16 vsig,
 
                ice_memcpy(p, ent1, sizeof(*p), ICE_NONDMA_TO_NONDMA);
 
-               LIST_ADD(&p->list, lst);
+               LIST_ADD_TAIL(&p->list, lst);
        }
 
        return ICE_SUCCESS;
@@ -4768,14 +4781,13 @@ ice_add_prof_id_flow(struct ice_hw *hw, enum ice_block blk, u16 vsi, u64 hdl)
                /* search for an existing VSIG with an exact charc match */
                status = ice_find_dup_props_vsig(hw, blk, &union_lst, &vsig);
                if (!status) {
-                       /* found an exact match */
-                       /* move vsi to the VSIG that matches */
+                       /* move VSI to the VSIG that matches */
                        status = ice_move_vsi(hw, blk, vsi, vsig, &chg);
                        if (status)
                                goto err_ice_add_prof_id_flow;
 
-                       /* remove original VSIG if we just moved the only VSI
-                        * from it
+                       /* VSI has been moved out of or_vsig. If the or_vsig had
+                        * only that VSI it is now empty and can be removed.
                         */
                        if (only_vsi) {
                                status = ice_rem_vsig(hw, blk, or_vsig, &chg);