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
/* 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);
}
/**
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,
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;
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
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);
}
/**
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);
}
/**
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;
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);
}
/**
return ICE_SUCCESS;
}
+/**
+ * ice_write_es - write an extraction sequence to hardware
+ * @hw: pointer to the HW struct
+ * @blk: the block in which to write the extraction sequence
+ * @prof_id: the profile ID to write
+ * @fv: pointer to the extraction sequence to write - NULL to clear extraction
+ */
+static void
+ice_write_es(struct ice_hw *hw, enum ice_block blk, u8 prof_id,
+ struct ice_fv_word *fv)
+{
+ u16 off;
+
+ off = prof_id * hw->blk[blk].es.fvw;
+ if (!fv) {
+ ice_memset(&hw->blk[blk].es.t[off], 0, hw->blk[blk].es.fvw *
+ sizeof(*fv), ICE_NONDMA_MEM);
+ hw->blk[blk].es.written[prof_id] = false;
+ } else {
+ ice_memcpy(&hw->blk[blk].es.t[off], fv, hw->blk[blk].es.fvw *
+ sizeof(*fv), ICE_NONDMA_TO_NONDMA);
+ }
+}
+
/**
* ice_prof_dec_ref - decrement reference count for profile
* @hw: pointer to the HW struct
return ICE_ERR_PARAM;
if (hw->blk[blk].es.ref_count[prof_id] > 0) {
- if (!--hw->blk[blk].es.ref_count[prof_id])
+ if (!--hw->blk[blk].es.ref_count[prof_id]) {
+ ice_write_es(hw, blk, prof_id, NULL);
return ice_free_prof_id(hw, blk, prof_id);
+ }
}
return ICE_SUCCESS;
}
-/**
- * ice_write_es - write an extraction sequence to hardware
- * @hw: pointer to the HW struct
- * @blk: the block in which to write the extraction sequence
- * @prof_id: the profile ID to write
- * @fv: pointer to the extraction sequence to write
- */
-static void
-ice_write_es(struct ice_hw *hw, enum ice_block blk, u8 prof_id,
- struct ice_fv_word *fv)
-{
- u16 off;
-
- off = prof_id * hw->blk[blk].es.fvw;
- ice_memcpy(&hw->blk[blk].es.t[off], fv, hw->blk[blk].es.fvw * 2,
- ICE_NONDMA_TO_NONDMA);
-}
-
/* Block / table section IDs */
static const u32 ice_blk_sids[ICE_BLK_COUNT][ICE_SID_OFF_COUNT] = {
/* SWITCH */
while (sect) {
switch (sid) {
+ case ICE_SID_XLT1_SW:
case ICE_SID_XLT1_FD:
case ICE_SID_XLT1_RSS:
case ICE_SID_XLT1_ACL:
+ case ICE_SID_XLT1_PE:
xlt1 = (struct ice_xlt1_section *)sect;
src = xlt1->value;
sect_len = LE16_TO_CPU(xlt1->count) *
dst_len = hw->blk[block_id].xlt1.count *
sizeof(*hw->blk[block_id].xlt1.t);
break;
+ case ICE_SID_XLT2_SW:
case ICE_SID_XLT2_FD:
case ICE_SID_XLT2_RSS:
case ICE_SID_XLT2_ACL:
+ case ICE_SID_XLT2_PE:
xlt2 = (struct ice_xlt2_section *)sect;
src = (u8 *)xlt2->value;
sect_len = LE16_TO_CPU(xlt2->count) *
dst_len = hw->blk[block_id].xlt2.count *
sizeof(*hw->blk[block_id].xlt2.t);
break;
+ case ICE_SID_PROFID_TCAM_SW:
case ICE_SID_PROFID_TCAM_FD:
case ICE_SID_PROFID_TCAM_RSS:
case ICE_SID_PROFID_TCAM_ACL:
+ case ICE_SID_PROFID_TCAM_PE:
pid = (struct ice_prof_id_section *)sect;
src = (u8 *)pid->entry;
sect_len = LE16_TO_CPU(pid->count) *
dst_len = hw->blk[block_id].prof.count *
sizeof(*hw->blk[block_id].prof.t);
break;
+ case ICE_SID_PROFID_REDIR_SW:
case ICE_SID_PROFID_REDIR_FD:
case ICE_SID_PROFID_REDIR_RSS:
case ICE_SID_PROFID_REDIR_ACL:
+ case ICE_SID_PROFID_REDIR_PE:
pr = (struct ice_prof_redir_section *)sect;
src = pr->redir_value;
sect_len = LE16_TO_CPU(pr->count) *
dst_len = hw->blk[block_id].prof_redir.count *
sizeof(*hw->blk[block_id].prof_redir.t);
break;
+ case ICE_SID_FLD_VEC_SW:
case ICE_SID_FLD_VEC_FD:
case ICE_SID_FLD_VEC_RSS:
case ICE_SID_FLD_VEC_ACL:
+ case ICE_SID_FLD_VEC_PE:
es = (struct ice_sw_fv_section *)sect;
src = (u8 *)es->fv;
sect_len = LE16_TO_CPU(es->count) *
- sizeof(*hw->blk[block_id].prof_redir.t);
+ hw->blk[block_id].es.fvw *
+ sizeof(*hw->blk[block_id].es.t);
dst = (u8 *)hw->blk[block_id].es.t;
dst_len = hw->blk[block_id].es.count *
+ hw->blk[block_id].es.fvw *
sizeof(*hw->blk[block_id].es.t);
break;
default:
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);
}
}
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);
}
ice_memset(hw->blk, 0, sizeof(hw->blk), ICE_NONDMA_MEM);
es->ref_count = (u16 *)
ice_calloc(hw, es->count, sizeof(*es->ref_count));
- if (!es->ref_count)
- goto err;
+ es->written = (u8 *)
+ ice_calloc(hw, es->count, sizeof(*es->written));
- 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)
+ if (!es->ref_count)
goto err;
INIT_LIST_HEAD(&es->prof_map);
struct ice_chs_chg *tmp;
LIST_FOR_EACH_ENTRY(tmp, chgs, ice_chs_chg, list_entry) {
- if ((tmp->type == ICE_TCAM_ADD && tmp->add_tcam_idx) ||
- tmp->type == ICE_TCAM_REM) {
+ if (tmp->type == ICE_TCAM_ADD && tmp->add_tcam_idx) {
struct ice_prof_id_section *p;
u32 id;
es++;
break;
case ICE_TCAM_ADD:
- case ICE_TCAM_REM:
tcam++;
break;
case ICE_VSIG_ADD:
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
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);
}
+ ice_prof_inc_ref(hw, blk, prof_id);
+
/* add profile info */
prof = (struct ice_prof_map *)ice_malloc(hw, sizeof(*prof));
* ice_rem_prof_id - remove one profile from a VSIG
* @hw: pointer to the HW struct
* @blk: hardware block
- * @vsig: VSIG to remove the profile from
* @prof: pointer to profile structure to remove
- * @chg: pointer to list to record changes
*/
static enum ice_status
-ice_rem_prof_id(struct ice_hw *hw, enum ice_block blk, u16 vsig,
- struct ice_vsig_prof *prof, struct LIST_HEAD_TYPE *chg)
+ice_rem_prof_id(struct ice_hw *hw, enum ice_block blk,
+ struct ice_vsig_prof *prof)
{
enum ice_status status;
- struct ice_chs_chg *p;
u16 i;
for (i = 0; i < prof->tcam_count; i++) {
- p = (struct ice_chs_chg *)ice_malloc(hw, sizeof(*p));
- if (!p)
- goto err_ice_rem_prof_id;
-
- p->type = ICE_TCAM_REM;
- p->vsig = vsig;
- p->prof_id = prof->tcam[i].prof_id;
- p->tcam_idx = prof->tcam[i].tcam_idx;
-
- p->ptg = prof->tcam[i].ptg;
prof->tcam[i].in_use = false;
- p->orig_ent = hw->blk[blk].prof.t[p->tcam_idx];
- status = ice_rel_tcam_idx(hw, blk, p->tcam_idx);
- if (!status)
- status = ice_prof_dec_ref(hw, blk, p->prof_id);
-
- LIST_ADD(&p->list_entry, chg);
-
+ status = ice_rel_tcam_idx(hw, blk, prof->tcam[i].tcam_idx);
if (status)
- goto err_ice_rem_prof_id;
+ return ICE_ERR_HW_TABLE;
}
return ICE_SUCCESS;
-
-err_ice_rem_prof_id:
- /* caller will clean up the change list */
- return ICE_ERR_NO_MEMORY;
}
/**
LIST_FOR_EACH_ENTRY_SAFE(d, t,
&hw->blk[blk].xlt2.vsig_tbl[idx].prop_lst,
ice_vsig_prof, list) {
- status = ice_rem_prof_id(hw, blk, vsig, d, chg);
+ status = ice_rem_prof_id(hw, blk, d);
if (status)
- goto err_ice_rem_vsig;
+ return status;
LIST_DEL(&d->list);
ice_free(hw, d);
/* 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;
}
/**
/* this is the last profile, remove the VSIG */
return ice_rem_vsig(hw, blk, vsig, chg);
- status = ice_rem_prof_id(hw, blk, vsig, p, chg);
+ status = ice_rem_prof_id(hw, blk, p);
if (!status) {
LIST_DEL(&p->list);
ice_free(hw, p);
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 */
+ ice_prof_dec_ref(hw, blk, pmap->prof_id);
+
LIST_DEL(&pmap->list);
ice_free(hw, pmap);
if (status)
goto err_ice_get_prof_ptgs;
- if (add || !hw->blk[blk].es.ref_count[map->prof_id]) {
+ if (add || !hw->blk[blk].es.written[map->prof_id]) {
/* add PTG to change list */
p = (struct ice_chs_chg *)ice_malloc(hw, sizeof(*p));
if (!p)
p->ptg = ptg;
p->add_ptg = add;
- p->add_prof = !hw->blk[blk].es.ref_count[map->prof_id];
+ p->add_prof = !hw->blk[blk].es.written[map->prof_id];
p->prof_id = map->prof_id;
+ hw->blk[blk].es.written[map->prof_id] = true;
+
LIST_ADD(&p->list_entry, chg);
}
}
ice_memcpy(p, ent1, sizeof(*p), ICE_NONDMA_TO_NONDMA);
- LIST_ADD(&p->list, lst);
+ LIST_ADD_TAIL(&p->list, lst);
}
return ICE_SUCCESS;
p->tcam_count = map->ptype_count;
for (i = 0; i < map->ptype_count; i++) {
- enum ice_status status;
u8 ptg;
p->tcam[i].prof_id = map->prof_id;
p->tcam[i].tcam_idx = ICE_INVALID_TCAM;
- status = ice_ptg_find_ptype(hw, blk, map->ptype[i], &ptg);
- if (status) {
- ice_free(hw, p);
- return status;
- }
+ ice_ptg_find_ptype(hw, blk, map->ptype[i], &ptg);
p->tcam[i].ptg = ptg;
}
/* allocate the TCAM entry index */
status = ice_alloc_tcam_ent(hw, blk, &tcam_idx);
- if (status)
+ if (status) {
+ ice_free(hw, p);
goto err_ice_add_prof_id_vsig;
+ }
t->tcam[i].ptg = ptg;
t->tcam[i].prof_id = map->prof_id;
if (status)
goto err_ice_add_prof_id_vsig;
- /* this increments the reference count of how many TCAM entries
- * are using this HW profile ID
- */
- status = ice_prof_inc_ref(hw, blk, t->tcam[i].prof_id);
-
/* log change */
LIST_ADD(&p->list_entry, chg);
}
err_ice_add_prof_id_vsig:
/* let caller clean up the change list */
+ ice_free(hw, t);
return ICE_ERR_NO_MEMORY;
}
return ICE_ERR_NO_MEMORY;
new_vsig = ice_vsig_alloc(hw, blk);
- if (!new_vsig)
- return ICE_ERR_HW_TABLE;
+ if (!new_vsig) {
+ status = ICE_ERR_HW_TABLE;
+ goto err_ice_create_prof_id_vsig;
+ }
status = ice_move_vsi(hw, blk, vsi, new_vsig, chg);
if (status)
- return status;
+ goto err_ice_create_prof_id_vsig;
status = ice_add_prof_id_vsig(hw, blk, new_vsig, hdl, chg);
if (status)
- return status;
+ goto err_ice_create_prof_id_vsig;
p->type = ICE_VSIG_ADD;
p->vsi = vsi;
LIST_ADD(&p->list_entry, chg);
return ICE_SUCCESS;
+
+err_ice_create_prof_id_vsig:
+ /* let caller clean up the change list */
+ ice_free(hw, p);
+ return status;
}
/**
/* 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);
if (status)
goto err_ice_rem_prof_id_flow;
- } else if (ice_find_dup_props_vsig(hw, blk, ©,
- &vsig)) {
+ } else if (!ice_find_dup_props_vsig(hw, blk, ©,
+ &vsig)) {
/* found an exact match */
/* add or move VSI to the VSIG that matches */
/* Search for a VSIG with a matching profile