* since the first call to ice_enum_labels requires a pointer to an actual
* ice_seg structure.
*/
-void ice_init_pkg_hints(struct ice_hw *hw, struct ice_seg *ice_seg)
+static void ice_init_pkg_hints(struct ice_hw *hw, struct ice_seg *ice_seg)
{
struct ice_pkg_enum state;
char *label_name;
{
enum ice_status status;
- ice_debug(hw, ICE_DBG_TRACE, "ice_acquire_global_cfg_lock");
+ ice_debug(hw, ICE_DBG_TRACE, "%s\n", __func__);
status = ice_acquire_res(hw, ICE_GLOBAL_CFG_LOCK_RES_ID, access,
ICE_GLOBAL_CFG_LOCK_TIMEOUT);
enum ice_status
ice_acquire_change_lock(struct ice_hw *hw, enum ice_aq_res_access_type access)
{
- ice_debug(hw, ICE_DBG_TRACE, "ice_acquire_change_lock");
+ ice_debug(hw, ICE_DBG_TRACE, "%s\n", __func__);
return ice_acquire_res(hw, ICE_CHANGE_LOCK_RES_ID, access,
ICE_CHANGE_LOCK_TIMEOUT);
*/
void ice_release_change_lock(struct ice_hw *hw)
{
- ice_debug(hw, ICE_DBG_TRACE, "ice_release_change_lock");
+ ice_debug(hw, ICE_DBG_TRACE, "%s\n", __func__);
ice_release_res(hw, ICE_CHANGE_LOCK_RES_ID);
}
struct ice_aq_desc desc;
enum ice_status status;
- ice_debug(hw, ICE_DBG_TRACE, "ice_aq_download_pkg");
+ ice_debug(hw, ICE_DBG_TRACE, "%s\n", __func__);
if (error_offset)
*error_offset = 0;
return status;
}
-/**
- * ice_aq_upload_section
- * @hw: pointer to the hardware structure
- * @pkg_buf: the package buffer which will receive the section
- * @buf_size: the size of the package buffer
- * @cd: pointer to command details structure or NULL
- *
- * Upload Section (0x0C41)
- */
-enum ice_status
-ice_aq_upload_section(struct ice_hw *hw, struct ice_buf_hdr *pkg_buf,
- u16 buf_size, struct ice_sq_cd *cd)
-{
- struct ice_aq_desc desc;
-
- ice_debug(hw, ICE_DBG_TRACE, "ice_aq_upload_section");
- ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_upload_section);
- desc.flags |= CPU_TO_LE16(ICE_AQ_FLAG_RD);
-
- return ice_aq_send_cmd(hw, &desc, pkg_buf, buf_size, cd);
-}
-
/**
* ice_aq_update_pkg
* @hw: pointer to the hardware structure
struct ice_aq_desc desc;
enum ice_status status;
- ice_debug(hw, ICE_DBG_TRACE, "ice_aq_update_pkg");
+ ice_debug(hw, ICE_DBG_TRACE, "%s\n", __func__);
if (error_offset)
*error_offset = 0;
* success it returns a pointer to the segment header, otherwise it will
* return NULL.
*/
-struct ice_generic_seg_hdr *
+static struct ice_generic_seg_hdr *
ice_find_seg_in_pkg(struct ice_hw *hw, u32 seg_type,
struct ice_pkg_hdr *pkg_hdr)
{
if (LE32_TO_CPU(bh->section_entry[0].type) & ICE_METADATA_BUF)
return ICE_SUCCESS;
+ /* reset pkg_dwnld_status in case this function is called in the
+ * reset/rebuild flow
+ */
+ hw->pkg_dwnld_status = ICE_AQ_RC_OK;
+
status = ice_acquire_global_cfg_lock(hw, ICE_RES_WRITE);
- if (status)
+ if (status) {
+ if (status == ICE_ERR_AQ_NO_WORK)
+ hw->pkg_dwnld_status = ICE_AQ_RC_EEXIST;
+ else
+ hw->pkg_dwnld_status = hw->adminq.sq_last_status;
return status;
+ }
for (i = 0; i < count; i++) {
bool last = ((i + 1) == count);
status = ice_aq_download_pkg(hw, bh, ICE_PKG_BUF_SIZE, last,
&offset, &info, NULL);
+
+ /* Save AQ status from download package */
+ hw->pkg_dwnld_status = hw->adminq.sq_last_status;
if (status) {
ice_debug(hw, ICE_DBG_PKG,
"Pkg download failed: err %d off %d inf %d\n",
{
struct ice_aq_desc desc;
- ice_debug(hw, ICE_DBG_TRACE, "ice_aq_get_pkg_info_list");
+ ice_debug(hw, ICE_DBG_TRACE, "%s\n", __func__);
ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_get_pkg_info_list);
return ice_aq_send_cmd(hw, &desc, pkg_info, buf_size, cd);
*
* Handles the download of a complete package.
*/
-enum ice_status ice_download_pkg(struct ice_hw *hw, struct ice_seg *ice_seg)
+static enum ice_status
+ice_download_pkg(struct ice_hw *hw, struct ice_seg *ice_seg)
{
struct ice_buf_table *ice_buf_tbl;
*
* Saves off the package details into the HW structure.
*/
-enum ice_status
+static enum ice_status
ice_init_pkg_info(struct ice_hw *hw, struct ice_pkg_hdr *pkg_hdr)
{
struct ice_global_metadata_seg *meta_seg;
*
* Store details of the package currently loaded in HW into the HW structure.
*/
-enum ice_status
-ice_get_pkg_info(struct ice_hw *hw)
+static enum ice_status ice_get_pkg_info(struct ice_hw *hw)
{
struct ice_aqc_get_pkg_info_resp *pkg_info;
enum ice_status status;
pkg_info->pkg_info[i].name,
sizeof(hw->active_pkg_name),
ICE_NONDMA_TO_NONDMA);
+ hw->active_pkg_in_nvm = pkg_info->pkg_info[i].is_in_nvm;
}
if (pkg_info->pkg_info[i].is_active_at_boot)
flags[place++] = 'B';
return status;
}
-/**
- * ice_find_label_value
- * @ice_seg: pointer to the ice segment (non-NULL)
- * @name: name of the label to search for
- * @type: the section type that will contain the label
- * @value: pointer to a value that will return the label's value if found
- *
- * Finds a label's value given the label name and the section type to search.
- * The ice_seg parameter must not be NULL since the first call to
- * ice_enum_labels requires a pointer to an actual ice_seg structure.
- */
-enum ice_status
-ice_find_label_value(struct ice_seg *ice_seg, char const *name, u32 type,
- u16 *value)
-{
- struct ice_pkg_enum state;
- char *label_name;
- u16 val;
-
- if (!ice_seg)
- return ICE_ERR_PARAM;
-
- do {
- label_name = ice_enum_labels(ice_seg, type, &state, &val);
- if (label_name && !strcmp(label_name, name)) {
- *value = val;
- return ICE_SUCCESS;
- }
-
- ice_seg = NULL;
- } while (label_name);
-
- return ICE_ERR_CFG;
-}
-
/**
* ice_verify_pkg - verify package
* @pkg: pointer to the package buffer
* Allocates a package buffer and returns a pointer to the buffer header.
* Note: all package contents must be in Little Endian form.
*/
-struct ice_buf_build *ice_pkg_buf_alloc(struct ice_hw *hw)
+static struct ice_buf_build *ice_pkg_buf_alloc(struct ice_hw *hw)
{
struct ice_buf_build *bld;
struct ice_buf_hdr *buf;
return fv_section->fv + index;
}
+/**
+ * ice_get_sw_prof_type - determine switch profile type
+ * @hw: pointer to the HW structure
+ * @fv: pointer to the switch field vector
+ */
+static enum ice_prof_type
+ice_get_sw_prof_type(struct ice_hw *hw, struct ice_fv *fv)
+{
+ u16 i;
+
+ for (i = 0; i < hw->blk[ICE_BLK_SW].es.fvw; i++) {
+ /* UDP tunnel will have UDP_OF protocol ID and VNI offset */
+ if (fv->ew[i].prot_id == (u8)ICE_PROT_UDP_OF &&
+ fv->ew[i].off == ICE_VNI_OFFSET)
+ return ICE_PROF_TUN_UDP;
+
+ /* GRE tunnel will have GRE protocol */
+ if (fv->ew[i].prot_id == (u8)ICE_PROT_GRE_OF)
+ return ICE_PROF_TUN_GRE;
+
+ /* PPPOE tunnel will have PPPOE protocol */
+ if (fv->ew[i].prot_id == (u8)ICE_PROT_PPPOE)
+ return ICE_PROF_TUN_PPPOE;
+ }
+
+ return ICE_PROF_NON_TUN;
+}
+
+/**
+ * ice_get_sw_fv_bitmap - Get switch field vector bitmap based on profile type
+ * @hw: pointer to hardware structure
+ * @type: 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_bitmap_t *bm)
+{
+ struct ice_pkg_enum state;
+ struct ice_seg *ice_seg;
+ struct ice_fv *fv;
+
+ if (type == ICE_PROF_ALL) {
+ u16 i;
+
+ for (i = 0; i < ICE_MAX_NUM_PROFILES; i++)
+ ice_set_bit(i, bm);
+ return;
+ }
+
+ ice_zero_bitmap(bm, ICE_MAX_NUM_PROFILES);
+
+ ice_seg = hw->seg;
+ do {
+ enum ice_prof_type prof_type;
+ u32 offset;
+
+ fv = (struct ice_fv *)
+ ice_pkg_enum_entry(ice_seg, &state, ICE_SID_FLD_VEC_SW,
+ &offset, ice_sw_fv_handler);
+ ice_seg = NULL;
+
+ if (fv) {
+ /* Determine field vector type */
+ prof_type = ice_get_sw_prof_type(hw, fv);
+
+ if (type & prof_type)
+ ice_set_bit((u16)offset, bm);
+ }
+ } while (fv);
+}
+
/**
* ice_get_sw_fv_list
* @hw: pointer to the HW structure
* @prot_ids: field vector to search for with a given protocol ID
* @ids_cnt: lookup/protocol count
+ * @bm: bitmap of field vectors to consider
* @fv_list: Head of a list
*
* Finds all the field vector entries from switch block that contain
*/
enum ice_status
ice_get_sw_fv_list(struct ice_hw *hw, u16 *prot_ids, u8 ids_cnt,
- struct LIST_HEAD_TYPE *fv_list)
+ ice_bitmap_t *bm, struct LIST_HEAD_TYPE *fv_list)
{
struct ice_sw_fv_list_entry *fvl;
struct ice_sw_fv_list_entry *tmp;
fv = (struct ice_fv *)
ice_pkg_enum_entry(ice_seg, &state, ICE_SID_FLD_VEC_SW,
&offset, ice_sw_fv_handler);
+ if (!fv)
+ break;
+ ice_seg = NULL;
+
+ /* If field vector is not in the bitmap list, then skip this
+ * profile.
+ */
+ if (!ice_is_bit_set(bm, (u16)offset))
+ continue;
- for (i = 0; i < ids_cnt && fv; i++) {
+ for (i = 0; i < ids_cnt; i++) {
int j;
/* This code assumes that if a switch field vector line
break;
}
}
- ice_seg = NULL;
} while (fv);
if (LIST_EMPTY(fv_list))
return ICE_ERR_CFG;
}
/**
- * ice_pkg_buf_alloc_single_section
+ * ice_pkg_buf_free
* @hw: pointer to the HW structure
- * @type: the section type value
- * @size: the size of the section to reserve (in bytes)
- * @section: returns pointer to the section
+ * @bld: pointer to pkg build (allocated by ice_pkg_buf_alloc())
*
- * Allocates a package buffer with a single section.
- * Note: all package contents must be in Little Endian form.
+ * Frees a package buffer
*/
-static struct ice_buf_build *
-ice_pkg_buf_alloc_single_section(struct ice_hw *hw, u32 type, u16 size,
- void **section)
+static void ice_pkg_buf_free(struct ice_hw *hw, struct ice_buf_build *bld)
{
- struct ice_buf_build *buf;
-
- if (!section)
- return NULL;
-
- buf = ice_pkg_buf_alloc(hw);
- if (!buf)
- return NULL;
-
- if (ice_pkg_buf_reserve_section(buf, 1))
- goto ice_pkg_buf_alloc_single_section_err;
-
- *section = ice_pkg_buf_alloc_section(buf, type, size);
- if (!*section)
- goto ice_pkg_buf_alloc_single_section_err;
-
- return buf;
-
-ice_pkg_buf_alloc_single_section_err:
- ice_pkg_buf_free(hw, buf);
- return NULL;
+ ice_free(hw, bld);
}
/**
* result in some wasted space in the buffer.
* Note: all package contents must be in Little Endian form.
*/
-enum ice_status
+static enum ice_status
ice_pkg_buf_reserve_section(struct ice_buf_build *bld, u16 count)
{
struct ice_buf_hdr *buf;
return ICE_SUCCESS;
}
-/**
- * ice_pkg_buf_unreserve_section
- * @bld: pointer to pkg build (allocated by ice_pkg_buf_alloc())
- * @count: the number of sections to unreserve
- *
- * Unreserves one or more section table entries in a package buffer, releasing
- * space that can be used for section data. This routine can be called
- * multiple times as long as they are made before calling
- * ice_pkg_buf_alloc_section(). Once ice_pkg_buf_alloc_section()
- * is called once, the number of sections that can be allocated will not be able
- * to be increased; not using all reserved sections is fine, but this will
- * result in some wasted space in the buffer.
- * Note: all package contents must be in Little Endian form.
- */
-enum ice_status
-ice_pkg_buf_unreserve_section(struct ice_buf_build *bld, u16 count)
-{
- struct ice_buf_hdr *buf;
- u16 section_count;
- u16 data_end;
-
- if (!bld)
- return ICE_ERR_PARAM;
-
- buf = (struct ice_buf_hdr *)&bld->buf;
-
- /* already an active section, can't decrease table size */
- section_count = LE16_TO_CPU(buf->section_count);
- if (section_count > 0)
- return ICE_ERR_CFG;
-
- if (count > bld->reserved_section_table_entries)
- return ICE_ERR_CFG;
- bld->reserved_section_table_entries -= count;
-
- data_end = LE16_TO_CPU(buf->data_end) -
- (count * sizeof(buf->section_entry[0]));
- buf->data_end = CPU_TO_LE16(data_end);
-
- return ICE_SUCCESS;
-}
-
/**
* ice_pkg_buf_alloc_section
* @bld: pointer to pkg build (allocated by ice_pkg_buf_alloc())
* section contents.
* Note: all package contents must be in Little Endian form.
*/
-void *
+static void *
ice_pkg_buf_alloc_section(struct ice_buf_build *bld, u32 type, u16 size)
{
struct ice_buf_hdr *buf;
return NULL;
}
-/**
- * ice_pkg_buf_get_free_space
- * @bld: pointer to pkg build (allocated by ice_pkg_buf_alloc())
- *
- * Returns the number of free bytes remaining in the buffer.
- * Note: all package contents must be in Little Endian form.
- */
-u16 ice_pkg_buf_get_free_space(struct ice_buf_build *bld)
-{
- struct ice_buf_hdr *buf;
-
- if (!bld)
- return 0;
-
- buf = (struct ice_buf_hdr *)&bld->buf;
- return ICE_MAX_S_DATA_END - LE16_TO_CPU(buf->data_end);
-}
-
/**
* ice_pkg_buf_get_active_sections
* @bld: pointer to pkg build (allocated by ice_pkg_buf_alloc())
* not be used.
* Note: all package contents must be in Little Endian form.
*/
-u16 ice_pkg_buf_get_active_sections(struct ice_buf_build *bld)
+static u16 ice_pkg_buf_get_active_sections(struct ice_buf_build *bld)
{
struct ice_buf_hdr *buf;
*
* Return a pointer to the buffer's header
*/
-struct ice_buf *ice_pkg_buf(struct ice_buf_build *bld)
+static struct ice_buf *ice_pkg_buf(struct ice_buf_build *bld)
{
if (!bld)
return NULL;
}
/**
- * ice_pkg_buf_free
+ * ice_tunnel_port_in_use
* @hw: pointer to the HW structure
- * @bld: pointer to pkg build (allocated by ice_pkg_buf_alloc())
+ * @port: port to search for
+ * @index: optionally returns index
*
- * Frees a package buffer
+ * Returns whether a port is already in use as a tunnel, and optionally its
+ * index
*/
-void ice_pkg_buf_free(struct ice_hw *hw, struct ice_buf_build *bld)
+bool ice_tunnel_port_in_use(struct ice_hw *hw, u16 port, u16 *index)
{
- ice_free(hw, bld);
+ u16 i;
+
+ 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) {
+ if (index)
+ *index = i;
+ return true;
+ }
+
+ return false;
}
/**
- * ice_find_prot_off - find prot ID and offset pair, based on prof and FV index
- * @hw: pointer to the hardware structure
- * @blk: hardware block
- * @prof: profile ID
- * @fv_idx: field vector word index
- * @prot: variable to receive the protocol ID
- * @off: variable to receive the protocol offset
+ * ice_tunnel_get_type
+ * @hw: pointer to the HW structure
+ * @port: port to search for
+ * @type: returns tunnel index
+ *
+ * For a given port number, will return the type of tunnel.
*/
-enum ice_status
-ice_find_prot_off(struct ice_hw *hw, enum ice_block blk, u8 prof, u8 fv_idx,
- u8 *prot, u16 *off)
+bool
+ice_tunnel_get_type(struct ice_hw *hw, u16 port, enum ice_tunnel_type *type)
{
- struct ice_fv_word *fv_ext;
+ u16 i;
- if (prof >= hw->blk[blk].es.count)
- return ICE_ERR_PARAM;
+ 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;
+ }
- if (fv_idx >= hw->blk[blk].es.fvw)
- return ICE_ERR_PARAM;
+ return false;
+}
- fv_ext = hw->blk[blk].es.t + (prof * hw->blk[blk].es.fvw);
+/**
+ * ice_find_free_tunnel_entry
+ * @hw: pointer to the HW structure
+ * @type: tunnel type
+ * @index: optionally returns index
+ *
+ * Returns whether there is a free tunnel entry, and optionally its index
+ */
+static bool
+ice_find_free_tunnel_entry(struct ice_hw *hw, enum ice_tunnel_type type,
+ u16 *index)
+{
+ u16 i;
- *prot = fv_ext[fv_idx].prot_id;
- *off = fv_ext[fv_idx].off;
+ 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 &&
+ hw->tnl.tbl[i].type == type) {
+ if (index)
+ *index = i;
+ return true;
+ }
- return ICE_SUCCESS;
+ return false;
}
-/* PTG Management */
+/**
+ * ice_get_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
+ */
+bool
+ice_get_open_tunnel_port(struct ice_hw *hw, enum ice_tunnel_type type,
+ u16 *port)
+{
+ u16 i;
+
+ 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;
+ }
+
+ return false;
+}
/**
- * ice_ptg_update_xlt1 - Updates packet type groups in HW via XLT1 table
- * @hw: pointer to the hardware structure
- * @blk: HW block
+ * ice_create_tunnel
+ * @hw: pointer to the HW structure
+ * @type: type of tunnel
+ * @port: port to use for vxlan tunnel
*
- * This function will update the XLT1 hardware table to reflect the new
- * packet type group configuration.
+ * Creates a tunnel
*/
-enum ice_status ice_ptg_update_xlt1(struct ice_hw *hw, enum ice_block blk)
+enum ice_status
+ice_create_tunnel(struct ice_hw *hw, enum ice_tunnel_type type, u16 port)
{
- struct ice_xlt1_section *sect;
+ struct ice_boost_tcam_section *sect_rx, *sect_tx;
+ enum ice_status status = ICE_ERR_MAX_LIMIT;
struct ice_buf_build *bld;
- enum ice_status status;
u16 index;
- bld = ice_pkg_buf_alloc_single_section(hw, ice_sect_id(blk, ICE_XLT1),
- ICE_XLT1_SIZE(ICE_XLT1_CNT),
- (void **)§);
+ if (ice_tunnel_port_in_use(hw, port, NULL))
+ return ICE_ERR_ALREADY_EXISTS;
+
+ if (!ice_find_free_tunnel_entry(hw, type, &index))
+ return ICE_ERR_OUT_OF_RANGE;
+
+ bld = ice_pkg_buf_alloc(hw);
if (!bld)
return ICE_ERR_NO_MEMORY;
- sect->count = CPU_TO_LE16(ICE_XLT1_CNT);
- sect->offset = CPU_TO_LE16(0);
- for (index = 0; index < ICE_XLT1_CNT; index++)
- sect->value[index] = hw->blk[blk].xlt1.ptypes[index].ptg;
+ /* allocate 2 sections, one for Rx parser, one for Tx parser */
+ if (ice_pkg_buf_reserve_section(bld, 2))
+ goto ice_create_tunnel_err;
+
+ sect_rx = (struct ice_boost_tcam_section *)
+ ice_pkg_buf_alloc_section(bld, ICE_SID_RXPARSER_BOOST_TCAM,
+ sizeof(*sect_rx));
+ if (!sect_rx)
+ goto ice_create_tunnel_err;
+ sect_rx->count = CPU_TO_LE16(1);
+
+ sect_tx = (struct ice_boost_tcam_section *)
+ ice_pkg_buf_alloc_section(bld, ICE_SID_TXPARSER_BOOST_TCAM,
+ sizeof(*sect_tx));
+ if (!sect_tx)
+ goto ice_create_tunnel_err;
+ sect_tx->count = CPU_TO_LE16(1);
+
+ /* copy original boost entry to update package buffer */
+ ice_memcpy(sect_rx->tcam, hw->tnl.tbl[index].boost_entry,
+ sizeof(*sect_rx->tcam), ICE_NONDMA_TO_NONDMA);
+
+ /* over-write the never-match dest port key bits with the encoded port
+ * bits
+ */
+ ice_set_key((u8 *)§_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),
+ sizeof(sect_rx->tcam[0].key.key.hv_dst_port_key));
+
+ /* exact copy of entry to Tx section entry */
+ ice_memcpy(sect_tx->tcam, sect_rx->tcam, sizeof(*sect_tx->tcam),
+ ICE_NONDMA_TO_NONDMA);
status = ice_update_pkg(hw, ice_pkg_buf(bld), 1);
+ if (!status) {
+ hw->tnl.tbl[index].port = port;
+ hw->tnl.tbl[index].in_use = true;
+ }
+ice_create_tunnel_err:
ice_pkg_buf_free(hw, bld);
return status;
}
/**
- * ice_ptg_find_ptype - Search for packet type group using packet type (ptype)
- * @hw: pointer to the hardware structure
- * @blk: HW block
- * @ptype: the ptype to search for
- * @ptg: pointer to variable that receives the PTG
+ * ice_destroy_tunnel
+ * @hw: pointer to the HW structure
+ * @port: port of tunnel to destroy (ignored if the all parameter is true)
+ * @all: flag that states to destroy all tunnels
*
- * 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
- * ICE_DEFAULT_PTG (0) meaning it is part the default PTG.
+ * Destroys a tunnel or all tunnels by creating an update package buffer
+ * targeting the specific updates requested and then performing an update
+ * package.
*/
-enum ice_status
-ice_ptg_find_ptype(struct ice_hw *hw, enum ice_block blk, u16 ptype, u8 *ptg)
+enum ice_status ice_destroy_tunnel(struct ice_hw *hw, u16 port, bool all)
{
- if (ptype >= ICE_XLT1_CNT || !ptg)
+ struct ice_boost_tcam_section *sect_rx, *sect_tx;
+ enum ice_status status = ICE_ERR_MAX_LIMIT;
+ struct ice_buf_build *bld;
+ u16 count = 0;
+ u16 size;
+ u16 i;
+
+ /* 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;
- *ptg = hw->blk[blk].xlt1.ptypes[ptype].ptg;
- return ICE_SUCCESS;
-}
+ /* size of section - there is at least one entry */
+ size = (count - 1) * sizeof(*sect_rx->tcam) + sizeof(*sect_rx);
-/**
- * ice_ptg_alloc_val - Allocates a new packet type group ID by value
+ bld = ice_pkg_buf_alloc(hw);
+ if (!bld)
+ return ICE_ERR_NO_MEMORY;
+
+ /* allocate 2 sections, one for Rx parser, one for Tx parser */
+ if (ice_pkg_buf_reserve_section(bld, 2))
+ goto ice_destroy_tunnel_err;
+
+ sect_rx = (struct ice_boost_tcam_section *)
+ ice_pkg_buf_alloc_section(bld, ICE_SID_RXPARSER_BOOST_TCAM,
+ size);
+ if (!sect_rx)
+ goto ice_destroy_tunnel_err;
+ sect_rx->count = CPU_TO_LE16(1);
+
+ sect_tx = (struct ice_boost_tcam_section *)
+ ice_pkg_buf_alloc_section(bld, ICE_SID_TXPARSER_BOOST_TCAM,
+ size);
+ if (!sect_tx)
+ goto ice_destroy_tunnel_err;
+ sect_tx->count = CPU_TO_LE16(1);
+
+ /* copy original boost entry to update package buffer, one copy to Rx
+ * section, another copy to the Tx section
+ */
+ 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)) {
+ ice_memcpy(sect_rx->tcam + i,
+ hw->tnl.tbl[i].boost_entry,
+ sizeof(*sect_rx->tcam),
+ ICE_NONDMA_TO_NONDMA);
+ ice_memcpy(sect_tx->tcam + i,
+ hw->tnl.tbl[i].boost_entry,
+ sizeof(*sect_tx->tcam),
+ ICE_NONDMA_TO_NONDMA);
+ hw->tnl.tbl[i].marked = true;
+ }
+
+ status = ice_update_pkg(hw, ice_pkg_buf(bld), 1);
+ if (!status)
+ for (i = 0; i < hw->tnl.count &&
+ i < ICE_TUNNEL_MAX_ENTRIES; i++)
+ if (hw->tnl.tbl[i].marked) {
+ hw->tnl.tbl[i].port = 0;
+ hw->tnl.tbl[i].in_use = false;
+ hw->tnl.tbl[i].marked = false;
+ }
+
+ice_destroy_tunnel_err:
+ ice_pkg_buf_free(hw, bld);
+
+ return status;
+}
+
+/**
+ * ice_find_prot_off - find prot ID and offset pair, based on prof and FV index
* @hw: pointer to the hardware structure
- * @blk: HW block
- * @ptg: the ptg to allocate
- *
- * This function allocates a given packet type group ID specified by the ptg
- * parameter.
+ * @blk: hardware block
+ * @prof: profile ID
+ * @fv_idx: field vector word index
+ * @prot: variable to receive the protocol ID
+ * @off: variable to receive the protocol offset
*/
-static
-void ice_ptg_alloc_val(struct ice_hw *hw, enum ice_block blk, u8 ptg)
+enum ice_status
+ice_find_prot_off(struct ice_hw *hw, enum ice_block blk, u8 prof, u8 fv_idx,
+ u8 *prot, u16 *off)
{
- hw->blk[blk].xlt1.ptg_tbl[ptg].in_use = true;
+ struct ice_fv_word *fv_ext;
+
+ if (prof >= hw->blk[blk].es.count)
+ return ICE_ERR_PARAM;
+
+ if (fv_idx >= hw->blk[blk].es.fvw)
+ return ICE_ERR_PARAM;
+
+ fv_ext = hw->blk[blk].es.t + (prof * hw->blk[blk].es.fvw);
+
+ *prot = fv_ext[fv_idx].prot_id;
+ *off = fv_ext[fv_idx].off;
+
+ return ICE_SUCCESS;
}
+/* PTG Management */
+
/**
- * ice_ptg_alloc - Find a free entry and allocates a new packet type group ID
+ * ice_ptg_find_ptype - Search for packet type group using packet type (ptype)
* @hw: pointer to the hardware structure
* @blk: HW block
+ * @ptype: the ptype to search for
+ * @ptg: pointer to variable that receives the PTG
*
- * This function allocates and returns a new packet type group ID. Note
- * that 0 is the default packet type group, so successfully created PTGs will
- * have a non-zero ID value; which means a 0 return value indicates an error.
+ * 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
+ * ICE_DEFAULT_PTG (0) meaning it is part the default PTG.
*/
-u8 ice_ptg_alloc(struct ice_hw *hw, enum ice_block blk)
+static enum ice_status
+ice_ptg_find_ptype(struct ice_hw *hw, enum ice_block blk, u16 ptype, u8 *ptg)
{
- u16 i;
-
- /* Skip the default PTG of 0 */
- for (i = 1; i < ICE_MAX_PTGS; i++)
- if (!hw->blk[blk].xlt1.ptg_tbl[i].in_use) {
- /* found a free PTG ID */
- ice_ptg_alloc_val(hw, blk, i);
- return (u8)i;
- }
+ if (ptype >= ICE_XLT1_CNT || !ptg)
+ return ICE_ERR_PARAM;
- return 0;
+ *ptg = hw->blk[blk].xlt1.ptypes[ptype].ptg;
+ return ICE_SUCCESS;
}
/**
- * ice_ptg_free - Frees a packet type group
+ * 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 ID to free
+ * @ptg: the ptg to allocate
*
- * This function frees a packet type group, and returns all the current ptypes
- * within it to the default PTG.
+ * This function allocates a given packet type group ID specified by the ptg
+ * parameter.
*/
-void ice_ptg_free(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)
{
- struct ice_ptg_ptype *p, *temp;
-
- hw->blk[blk].xlt1.ptg_tbl[ptg].in_use = false;
- p = hw->blk[blk].xlt1.ptg_tbl[ptg].first_ptype;
- while (p) {
- p->ptg = ICE_DEFAULT_PTG;
- temp = p->next_ptype;
- p->next_ptype = NULL;
- p = temp;
- }
-
- hw->blk[blk].xlt1.ptg_tbl[ptg].first_ptype = NULL;
+ hw->blk[blk].xlt1.ptg_tbl[ptg].in_use = true;
}
/**
* a destination PTG ID of ICE_DEFAULT_PTG (0) will move the ptype to the
* default PTG.
*/
-enum ice_status
+static enum ice_status
ice_ptg_add_mv_ptype(struct ice_hw *hw, enum ice_block blk, u16 ptype, u8 ptg)
{
enum ice_status status;
/* VSIG Management */
-/**
- * ice_vsig_update_xlt2_sect - update one section of XLT2 table
- * @hw: pointer to the hardware structure
- * @blk: HW block
- * @vsi: HW VSI number to program
- * @vsig: vsig for the VSI
- *
- * This function will update the XLT2 hardware table with the input VSI
- * group configuration.
- */
-static enum ice_status
-ice_vsig_update_xlt2_sect(struct ice_hw *hw, enum ice_block blk, u16 vsi,
- u16 vsig)
-{
- struct ice_xlt2_section *sect;
- struct ice_buf_build *bld;
- enum ice_status status;
-
- bld = ice_pkg_buf_alloc_single_section(hw, ice_sect_id(blk, ICE_XLT2),
- sizeof(struct ice_xlt2_section),
- (void **)§);
- if (!bld)
- return ICE_ERR_NO_MEMORY;
-
- sect->count = CPU_TO_LE16(1);
- sect->offset = CPU_TO_LE16(vsi);
- sect->value[0] = CPU_TO_LE16(vsig);
-
- status = ice_update_pkg(hw, ice_pkg_buf(bld), 1);
-
- ice_pkg_buf_free(hw, bld);
-
- return status;
-}
-
-/**
- * ice_vsig_update_xlt2 - update XLT2 table with VSIG configuration
- * @hw: pointer to the hardware structure
- * @blk: HW block
- *
- * This function will update the XLT2 hardware table with the input VSI
- * group configuration of used vsis.
- */
-enum ice_status ice_vsig_update_xlt2(struct ice_hw *hw, enum ice_block blk)
-{
- u16 vsi;
-
- for (vsi = 0; vsi < ICE_MAX_VSI; vsi++) {
- /* update only vsis that have been changed */
- if (hw->blk[blk].xlt2.vsis[vsi].changed) {
- enum ice_status status;
- u16 vsig;
-
- vsig = hw->blk[blk].xlt2.vsis[vsi].vsig;
- status = ice_vsig_update_xlt2_sect(hw, blk, vsi, vsig);
- if (status)
- return status;
-
- hw->blk[blk].xlt2.vsis[vsi].changed = 0;
- }
- }
-
- return ICE_SUCCESS;
-}
-
/**
* ice_vsig_find_vsi - find a VSIG that contains a specified VSI
* @hw: pointer to the hardware structure
* for, the list must match exactly, including the order in which the
* characteristics are listed.
*/
-enum ice_status
+static enum ice_status
ice_find_dup_props_vsig(struct ice_hw *hw, enum ice_block blk,
struct LIST_HEAD_TYPE *chs, u16 *vsig)
{
* The function will remove all VSIs associated with the input VSIG and move
* them to the DEFAULT_VSIG and mark the VSIG available.
*/
-enum ice_status
+static enum ice_status
ice_vsig_free(struct ice_hw *hw, enum ice_block blk, u16 vsig)
{
struct ice_vsig_prof *dtmp, *del;
return ICE_SUCCESS;
}
+/**
+ * ice_vsig_remove_vsi - remove VSI from VSIG
+ * @hw: pointer to the hardware structure
+ * @blk: HW block
+ * @vsi: VSI to remove
+ * @vsig: VSI group to remove from
+ *
+ * The function will remove the input VSI from its VSI group and move it
+ * to the DEFAULT_VSIG.
+ */
+static enum ice_status
+ice_vsig_remove_vsi(struct ice_hw *hw, enum ice_block blk, u16 vsi, u16 vsig)
+{
+ struct ice_vsig_vsi **vsi_head, *vsi_cur, *vsi_tgt;
+ u16 idx;
+
+ idx = vsig & ICE_VSIG_IDX_M;
+
+ if (vsi >= ICE_MAX_VSI || idx >= ICE_MAX_VSIGS)
+ return ICE_ERR_PARAM;
+
+ if (!hw->blk[blk].xlt2.vsig_tbl[idx].in_use)
+ return ICE_ERR_DOES_NOT_EXIST;
+
+ /* entry already in default VSIG, don't have to remove */
+ if (idx == ICE_DEFAULT_VSIG)
+ return ICE_SUCCESS;
+
+ vsi_head = &hw->blk[blk].xlt2.vsig_tbl[idx].first_vsi;
+ if (!(*vsi_head))
+ return ICE_ERR_CFG;
+
+ vsi_tgt = &hw->blk[blk].xlt2.vsis[vsi];
+ vsi_cur = (*vsi_head);
+
+ /* iterate the VSI list, skip over the entry to be removed */
+ while (vsi_cur) {
+ if (vsi_tgt == vsi_cur) {
+ (*vsi_head) = vsi_cur->next_vsi;
+ break;
+ }
+ vsi_head = &vsi_cur->next_vsi;
+ vsi_cur = vsi_cur->next_vsi;
+ }
+
+ /* verify if VSI was removed from group list */
+ if (!vsi_cur)
+ return ICE_ERR_DOES_NOT_EXIST;
+
+ vsi_cur->vsig = ICE_DEFAULT_VSIG;
+ vsi_cur->changed = 1;
+ vsi_cur->next_vsi = NULL;
+
+ return ICE_SUCCESS;
+}
+
/**
* ice_vsig_add_mv_vsi - add or move a VSI to a VSI group
* @hw: pointer to the hardware structure
* move the entry to the DEFAULT_VSIG, update the original VSIG and
* then move entry to the new VSIG.
*/
-enum ice_status
+static enum ice_status
ice_vsig_add_mv_vsi(struct ice_hw *hw, enum ice_block blk, u16 vsi, u16 vsig)
{
struct ice_vsig_vsi *tmp;
}
/**
- * ice_vsig_remove_vsi - remove VSI from VSIG
+ * ice_prof_has_mask_idx - determine if profile index masking is identical
* @hw: pointer to the hardware structure
* @blk: HW block
- * @vsi: VSI to remove
- * @vsig: VSI group to remove from
- *
- * The function will remove the input VSI from its VSI group and move it
- * to the DEFAULT_VSIG.
+ * @prof: profile to check
+ * @idx: profile index to check
+ * @masks: masks to match
*/
-enum ice_status
-ice_vsig_remove_vsi(struct ice_hw *hw, enum ice_block blk, u16 vsi, u16 vsig)
+static bool
+ice_prof_has_mask_idx(struct ice_hw *hw, enum ice_block blk, u8 prof, u16 idx,
+ u16 mask)
{
- struct ice_vsig_vsi **vsi_head, *vsi_cur, *vsi_tgt;
- u16 idx;
+ bool expect_no_mask = false;
+ bool found = false;
+ bool match = false;
+ u16 i;
- idx = vsig & ICE_VSIG_IDX_M;
+ /* If mask is 0x0000 or 0xffff, then there is no masking */
+ if (mask == 0 || mask == 0xffff)
+ expect_no_mask = true;
+
+ /* Scan the enabled masks on this profile, for the specified idx */
+ for (i = 0; i < ICE_PROFILE_MASK_COUNT; i++)
+ if (hw->blk[blk].es.mask_ena[prof] & BIT(i))
+ if (hw->blk[blk].masks.masks[i].in_use &&
+ hw->blk[blk].masks.masks[i].idx == idx) {
+ found = true;
+ if (hw->blk[blk].masks.masks[i].mask == mask)
+ match = true;
+ break;
+ }
- if (vsi >= ICE_MAX_VSI || idx >= ICE_MAX_VSIGS)
- return ICE_ERR_PARAM;
+ if (expect_no_mask) {
+ if (found)
+ return false;
+ } else {
+ if (!match)
+ return false;
+ }
- if (!hw->blk[blk].xlt2.vsig_tbl[idx].in_use)
- return ICE_ERR_DOES_NOT_EXIST;
+ return true;
+}
- /* entry already in default VSIG, don't have to remove */
- if (idx == ICE_DEFAULT_VSIG)
- return ICE_SUCCESS;
+/**
+ * ice_prof_has_mask - determine if profile masking is identical
+ * @hw: pointer to the hardware structure
+ * @blk: HW block
+ * @prof: profile to check
+ * @masks: masks to match
+ */
+static bool
+ice_prof_has_mask(struct ice_hw *hw, enum ice_block blk, u8 prof, u16 *masks)
+{
+ u16 i;
- vsi_head = &hw->blk[blk].xlt2.vsig_tbl[idx].first_vsi;
- if (!(*vsi_head))
- return ICE_ERR_CFG;
+ /* es->mask_ena[prof] will have the mask */
+ for (i = 0; i < hw->blk[blk].es.fvw; i++)
+ if (!ice_prof_has_mask_idx(hw, blk, prof, i, masks[i]))
+ return false;
- vsi_tgt = &hw->blk[blk].xlt2.vsis[vsi];
- vsi_cur = (*vsi_head);
+ return true;
+}
- /* iterate the VSI list, skip over the entry to be removed */
- while (vsi_cur) {
- if (vsi_tgt == vsi_cur) {
- (*vsi_head) = vsi_cur->next_vsi;
- break;
- }
- vsi_head = &vsi_cur->next_vsi;
- vsi_cur = vsi_cur->next_vsi;
- }
+/**
+ * ice_find_prof_id_with_mask - find profile ID for a given field vector
+ * @hw: pointer to the hardware structure
+ * @blk: HW block
+ * @fv: field vector to search for
+ * @masks: masks for fv
+ * @prof_id: receives the profile ID
+ */
+static enum ice_status
+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;
- /* verify if VSI was removed from group list */
- if (!vsi_cur)
- return ICE_ERR_DOES_NOT_EXIST;
+ for (i = 0; i < es->count; i++) {
+ u16 off = i * es->fvw;
+ u16 j;
- vsi_cur->vsig = ICE_DEFAULT_VSIG;
- vsi_cur->changed = 1;
- vsi_cur->next_vsi = NULL;
+ if (memcmp(&es->t[off], fv, es->fvw * sizeof(*fv)))
+ continue;
- return ICE_SUCCESS;
+ /* 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;
}
/**
return ICE_SUCCESS;
}
+/**
+ * ice_write_prof_mask_reg - write profile mask register
+ * @hw: pointer to the HW struct
+ * @blk: hardware block
+ * @mask_idx: mask index
+ * @idx: index of the FV which will use the mask
+ * @mask: the 16-bit mask
+ */
+static void
+ice_write_prof_mask_reg(struct ice_hw *hw, enum ice_block blk, u16 mask_idx,
+ u16 idx, u16 mask)
+{
+ u32 offset;
+ u32 val;
+
+ switch (blk) {
+ case ICE_BLK_RSS:
+ offset = GLQF_HMASK(mask_idx);
+ val = (idx << GLQF_HMASK_MSK_INDEX_S) &
+ GLQF_HMASK_MSK_INDEX_M;
+ val |= (mask << GLQF_HMASK_MASK_S) & GLQF_HMASK_MASK_M;
+ break;
+ case ICE_BLK_FD:
+ offset = GLQF_FDMASK(mask_idx);
+ val = (idx << GLQF_FDMASK_MSK_INDEX_S) &
+ GLQF_FDMASK_MSK_INDEX_M;
+ val |= (mask << GLQF_FDMASK_MASK_S) &
+ GLQF_FDMASK_MASK_M;
+ break;
+ default:
+ ice_debug(hw, ICE_DBG_PKG, "No profile masks for block %d\n",
+ blk);
+ return;
+ }
+
+ wr32(hw, offset, val);
+ ice_debug(hw, ICE_DBG_PKG, "write mask, blk %d (%d): %x = %x\n",
+ blk, idx, offset, val);
+}
+
+/**
+ * ice_write_prof_mask_enable_res - write profile mask enable register
+ * @hw: pointer to the HW struct
+ * @blk: hardware block
+ * @prof_id: profile ID
+ * @enable_mask: enable mask
+ */
+static void
+ice_write_prof_mask_enable_res(struct ice_hw *hw, enum ice_block blk,
+ u16 prof_id, u32 enable_mask)
+{
+ u32 offset;
+
+ switch (blk) {
+ case ICE_BLK_RSS:
+ offset = GLQF_HMASK_SEL(prof_id);
+ break;
+ case ICE_BLK_FD:
+ offset = GLQF_FDMASK_SEL(prof_id);
+ break;
+ default:
+ ice_debug(hw, ICE_DBG_PKG, "No profile masks for block %d\n",
+ blk);
+ return;
+ }
+
+ wr32(hw, offset, enable_mask);
+ ice_debug(hw, ICE_DBG_PKG, "write mask enable, blk %d (%d): %x = %x\n",
+ blk, prof_id, offset, enable_mask);
+}
+
+/**
+ * ice_init_prof_masks - initial prof masks
+ * @hw: pointer to the HW struct
+ * @blk: hardware block
+ */
+static void ice_init_prof_masks(struct ice_hw *hw, enum ice_block blk)
+{
+#define MAX_NUM_PORTS 8
+ u16 num_ports = MAX_NUM_PORTS;
+ u16 i;
+
+ ice_init_lock(&hw->blk[blk].masks.lock);
+
+ hw->blk[blk].masks.count = ICE_PROFILE_MASK_COUNT / num_ports;
+ hw->blk[blk].masks.first = hw->pf_id * hw->blk[blk].masks.count;
+
+ ice_memset(hw->blk[blk].masks.masks, 0,
+ sizeof(hw->blk[blk].masks.masks), ICE_NONDMA_MEM);
+
+ for (i = hw->blk[blk].masks.first;
+ i < hw->blk[blk].masks.first + hw->blk[blk].masks.count; i++)
+ ice_write_prof_mask_reg(hw, blk, i, 0, 0);
+}
+
+/**
+ * ice_init_all_prof_masks - initial all prof masks
+ * @hw: pointer to the HW struct
+ */
+void ice_init_all_prof_masks(struct ice_hw *hw)
+{
+ ice_init_prof_masks(hw, ICE_BLK_RSS);
+ ice_init_prof_masks(hw, ICE_BLK_FD);
+}
+
+/**
+ * ice_alloc_prof_mask - allocate profile mask
+ * @hw: pointer to the HW struct
+ * @blk: hardware block
+ * @idx: index of FV which will use the mask
+ * @mask: the 16-bit mask
+ * @mask_idx: variable to receive the mask index
+ */
+static enum ice_status
+ice_alloc_prof_mask(struct ice_hw *hw, enum ice_block blk, u16 idx, u16 mask,
+ u16 *mask_idx)
+{
+ bool found_unused = false, found_copy = false;
+ enum ice_status status = ICE_ERR_MAX_LIMIT;
+ u16 unused_idx = 0, copy_idx = 0;
+ u16 i;
+
+ if (blk != ICE_BLK_RSS && blk != ICE_BLK_FD)
+ return ICE_ERR_PARAM;
+
+ ice_acquire_lock(&hw->blk[blk].masks.lock);
+
+ for (i = hw->blk[blk].masks.first;
+ i < hw->blk[blk].masks.first + hw->blk[blk].masks.count; i++)
+ if (hw->blk[blk].masks.masks[i].in_use) {
+ /* if mask is in use and it exactly duplicates the
+ * desired mask and index, then in can be reused
+ */
+ if (hw->blk[blk].masks.masks[i].mask == mask &&
+ hw->blk[blk].masks.masks[i].idx == idx) {
+ found_copy = true;
+ copy_idx = i;
+ break;
+ }
+ } else {
+ /* save off unused index, but keep searching in case
+ * there is an exact match later on
+ */
+ if (!found_unused) {
+ found_unused = true;
+ unused_idx = i;
+ }
+ }
+
+ if (found_copy)
+ i = copy_idx;
+ else if (found_unused)
+ i = unused_idx;
+ else
+ goto err_ice_alloc_prof_mask;
+
+ /* update mask for a new entry */
+ if (found_unused) {
+ hw->blk[blk].masks.masks[i].in_use = true;
+ hw->blk[blk].masks.masks[i].mask = mask;
+ hw->blk[blk].masks.masks[i].idx = idx;
+ hw->blk[blk].masks.masks[i].ref = 0;
+ ice_write_prof_mask_reg(hw, blk, i, idx, mask);
+ }
+
+ hw->blk[blk].masks.masks[i].ref++;
+ *mask_idx = i;
+ status = ICE_SUCCESS;
+
+err_ice_alloc_prof_mask:
+ ice_release_lock(&hw->blk[blk].masks.lock);
+
+ return status;
+}
+
+/**
+ * ice_free_prof_mask - free profile mask
+ * @hw: pointer to the HW struct
+ * @blk: hardware block
+ * @mask_idx: index of mask
+ */
+static enum ice_status
+ice_free_prof_mask(struct ice_hw *hw, enum ice_block blk, u16 mask_idx)
+{
+ if (blk != ICE_BLK_RSS && blk != ICE_BLK_FD)
+ return ICE_ERR_PARAM;
+
+ if (!(mask_idx >= hw->blk[blk].masks.first &&
+ mask_idx < hw->blk[blk].masks.first + hw->blk[blk].masks.count))
+ return ICE_ERR_DOES_NOT_EXIST;
+
+ ice_acquire_lock(&hw->blk[blk].masks.lock);
+
+ if (!hw->blk[blk].masks.masks[mask_idx].in_use)
+ goto exit_ice_free_prof_mask;
+
+ if (hw->blk[blk].masks.masks[mask_idx].ref > 1) {
+ hw->blk[blk].masks.masks[mask_idx].ref--;
+ goto exit_ice_free_prof_mask;
+ }
+
+ /* remove mask */
+ hw->blk[blk].masks.masks[mask_idx].in_use = false;
+ hw->blk[blk].masks.masks[mask_idx].mask = 0;
+ 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_write_prof_mask_reg(hw, blk, mask_idx, 0, 0);
+
+exit_ice_free_prof_mask:
+ ice_release_lock(&hw->blk[blk].masks.lock);
+
+ return ICE_SUCCESS;
+}
+
+/**
+ * ice_free_prof_masks - free all profile masks for a profile
+ * @hw: pointer to the HW struct
+ * @blk: hardware block
+ * @prof_id: profile ID
+ */
+static enum ice_status
+ice_free_prof_masks(struct ice_hw *hw, enum ice_block blk, u16 prof_id)
+{
+ u32 mask_bm;
+ u16 i;
+
+ if (blk != ICE_BLK_RSS && blk != ICE_BLK_FD)
+ return ICE_ERR_PARAM;
+
+ mask_bm = hw->blk[blk].es.mask_ena[prof_id];
+ for (i = 0; i < BITS_PER_BYTE * sizeof(mask_bm); i++)
+ if (mask_bm & BIT(i))
+ ice_free_prof_mask(hw, blk, i);
+
+ return ICE_SUCCESS;
+}
+
+/**
+ * ice_shutdown_prof_masks - releases lock for masking
+ * @hw: pointer to the HW struct
+ * @blk: hardware block
+ *
+ * This should be called before unloading the driver
+ */
+static void ice_shutdown_prof_masks(struct ice_hw *hw, enum ice_block blk)
+{
+ u16 i;
+
+ ice_acquire_lock(&hw->blk[blk].masks.lock);
+
+ for (i = hw->blk[blk].masks.first;
+ i < hw->blk[blk].masks.first + hw->blk[blk].masks.count; i++) {
+ ice_write_prof_mask_reg(hw, blk, i, 0, 0);
+
+ hw->blk[blk].masks.masks[i].in_use = false;
+ hw->blk[blk].masks.masks[i].idx = 0;
+ hw->blk[blk].masks.masks[i].mask = 0;
+ }
+
+ ice_release_lock(&hw->blk[blk].masks.lock);
+ ice_destroy_lock(&hw->blk[blk].masks.lock);
+}
+
+/**
+ * ice_shutdown_all_prof_masks - releases all locks for masking
+ * @hw: pointer to the HW struct
+ * @blk: hardware block
+ *
+ * This should be called before unloading the driver
+ */
+void ice_shutdown_all_prof_masks(struct ice_hw *hw)
+{
+ ice_shutdown_prof_masks(hw, ICE_BLK_RSS);
+ ice_shutdown_prof_masks(hw, ICE_BLK_FD);
+}
+
+/**
+ * ice_update_prof_masking - set registers according to masking
+ * @hw: pointer to the HW struct
+ * @blk: hardware block
+ * @prof_id: profile ID
+ * @es: field vector
+ * @masks: masks
+ */
+static enum ice_status
+ice_update_prof_masking(struct ice_hw *hw, enum ice_block blk, u16 prof_id,
+ struct ice_fv_word *es, u16 *masks)
+{
+ bool err = false;
+ u32 ena_mask = 0;
+ u16 idx;
+ u16 i;
+
+ /* Only support FD and RSS masking, otherwise nothing to be done */
+ if (blk != ICE_BLK_RSS && blk != ICE_BLK_FD)
+ return ICE_SUCCESS;
+
+ for (i = 0; i < hw->blk[blk].es.fvw; i++)
+ if (masks[i] && masks[i] != 0xFFFF) {
+ if (!ice_alloc_prof_mask(hw, blk, i, masks[i], &idx)) {
+ ena_mask |= BIT(idx);
+ } else {
+ /* not enough bitmaps */
+ err = true;
+ break;
+ }
+ }
+
+ if (err) {
+ /* free any bitmaps we have allocated */
+ for (i = 0; i < BITS_PER_BYTE * sizeof(ena_mask); i++)
+ if (ena_mask & BIT(i))
+ ice_free_prof_mask(hw, blk, i);
+
+ return ICE_ERR_OUT_OF_RANGE;
+ }
+
+ /* enable the masks for this profile */
+ ice_write_prof_mask_enable_res(hw, blk, prof_id, ena_mask);
+
+ /* store enabled masks with profile so that they can be freed later */
+ hw->blk[blk].es.mask_ena[prof_id] = ena_mask;
+
+ return ICE_SUCCESS;
+}
+
/**
* ice_write_es - write an extraction sequence to hardware
* @hw: pointer to the HW struct
if (hw->blk[blk].es.ref_count[prof_id] > 0) {
if (!--hw->blk[blk].es.ref_count[prof_id]) {
ice_write_es(hw, blk, prof_id, NULL);
+ ice_free_prof_masks(hw, blk, prof_id);
return ice_free_prof_id(hw, blk, prof_id);
}
}
void *sect;
/* if the HW segment pointer is null then the first iteration of
- * ice_pkg_enum_section() will fail. In this case the Hw tables will
+ * ice_pkg_enum_section() will fail. In this case the HW tables will
* not be filled and return success.
*/
if (!hw->seg) {
return;
/* if the sum of section size and offset exceed destination size
- * then we are out of bounds of the Hw table size for that PF.
+ * then we are out of bounds of the HW table size for that PF.
* Changing section length to fill the remaining table space
* of that PF.
*/
*
* Reads the current package contents and populates the driver
* database with the data iteratively for all advanced feature
- * blocks. Assume that the Hw tables have been allocated.
+ * blocks. Assume that the HW tables have been allocated.
*/
void ice_fill_blk_tbls(struct ice_hw *hw)
{
ice_fill_tbl(hw, blk_id, hw->blk[blk_id].es.sid);
}
- ice_init_sw_db(hw);
+ ice_init_sw_db(hw);
+}
+
+/**
+ * ice_free_prof_map - free profile map
+ * @hw: pointer to the hardware structure
+ * @blk_idx: HW block index
+ */
+static void ice_free_prof_map(struct ice_hw *hw, u8 blk_idx)
+{
+ struct ice_es *es = &hw->blk[blk_idx].es;
+ struct ice_prof_map *del, *tmp;
+
+ ice_acquire_lock(&es->prof_map_lock);
+ LIST_FOR_EACH_ENTRY_SAFE(del, tmp, &es->prof_map,
+ ice_prof_map, list) {
+ LIST_DEL(&del->list);
+ ice_free(hw, del);
+ }
+ INIT_LIST_HEAD(&es->prof_map);
+ ice_release_lock(&es->prof_map_lock);
}
/**
{
struct ice_flow_prof *p, *tmp;
- /* This call is being made as part of resource deallocation
- * during unload. Lock acquire and release will not be
- * necessary here.
- */
+ ice_acquire_lock(&hw->fl_profs_locks[blk_idx]);
LIST_FOR_EACH_ENTRY_SAFE(p, tmp, &hw->fl_profs[blk_idx],
ice_flow_prof, l_entry) {
struct ice_flow_entry *e, *t;
ice_free(hw, p->acts);
ice_free(hw, p);
}
+ ice_release_lock(&hw->fl_profs_locks[blk_idx]);
/* if driver is in reset and tables are being cleared
* re-initialize the flow profile list heads
for (i = 0; i < ICE_BLK_COUNT; i++) {
if (hw->blk[i].is_list_init) {
struct ice_es *es = &hw->blk[i].es;
- struct ice_prof_map *del, *tmp;
-
- LIST_FOR_EACH_ENTRY_SAFE(del, tmp, &es->prof_map,
- ice_prof_map, list) {
- LIST_DEL(&del->list);
- ice_free(hw, del);
- }
+ ice_free_prof_map(hw, i);
ice_destroy_lock(&es->prof_map_lock);
ice_free_flow_profs(hw, i);
ice_destroy_lock(&hw->fl_profs_locks[i]);
+
hw->blk[i].is_list_init = false;
}
ice_free_vsig_tbl(hw, (enum ice_block)i);
ice_free(hw, hw->blk[i].es.t);
ice_free(hw, hw->blk[i].es.ref_count);
ice_free(hw, hw->blk[i].es.written);
+ ice_free(hw, hw->blk[i].es.mask_ena);
}
LIST_FOR_EACH_ENTRY_SAFE(r, rt, &hw->rss_list_head,
ice_free(hw, r);
}
ice_destroy_lock(&hw->rss_locks);
+ ice_shutdown_all_prof_masks(hw);
ice_memset(hw->blk, 0, sizeof(hw->blk), ICE_NONDMA_MEM);
}
ice_init_lock(&hw->rss_locks);
INIT_LIST_HEAD(&hw->rss_list_head);
+ 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;
es->written = (u8 *)
ice_calloc(hw, es->count, sizeof(*es->written));
-
+ es->mask_ena = (u32 *)
+ ice_calloc(hw, es->count, sizeof(*es->mask_ena));
if (!es->ref_count)
goto err;
}
return ICE_SUCCESS;
}
-/**
- * ice_get_ptg - get or allocate a ptg for a ptype
- * @hw: pointer to the hardware structure
- * @blk: HW block
- * @ptype: the ptype to retrieve the PTG for
- * @ptg: receives the PTG of the ptype
- * @add: receive boolean indicating whether PTG was added or not
- */
-static enum ice_status
-ice_get_ptg(struct ice_hw *hw, enum ice_block blk, u16 ptype, u8 *ptg,
- bool *add)
-{
- enum ice_status status;
-
- *ptg = ICE_DEFAULT_PTG;
- *add = false;
-
- status = ice_ptg_find_ptype(hw, blk, ptype, ptg);
- if (status)
- return status;
-
- if (*ptg == ICE_DEFAULT_PTG) {
- /* need to allocate a PTG, and add ptype to it */
- *ptg = ice_ptg_alloc(hw, blk);
- if (*ptg == ICE_DEFAULT_PTG)
- return ICE_ERR_HW_TABLE;
-
- status = ice_ptg_add_mv_ptype(hw, blk, ptype, *ptg);
- if (status)
- return ICE_ERR_HW_TABLE;
-
- *add = true;
- }
-
- return ICE_SUCCESS;
-};
-
/**
* ice_has_prof_vsig - check to see if VSIG has a specific profile
* @hw: pointer to the hardware structure
u32 mask_sel = 0;
u8 i, j, k;
- ice_memset(pair_list, 0, sizeof(pair_list), ICE_NONDMA_MEM);
+ ice_zero_bitmap(pair_list, ICE_FD_SRC_DST_PAIR_COUNT);
ice_init_fd_mask_regs(hw);
index = i + 1;
/* check for room */
- if (first_free + 1 < ice_fd_pairs[index].count)
+ if (first_free + 1 < (s8)ice_fd_pairs[index].count)
return ICE_ERR_MAX_LIMIT;
/* place in extraction sequence */
es[first_free - k].off =
ice_fd_pairs[index].off + (k * 2);
+ if (k > first_free)
+ return ICE_ERR_OUT_OF_RANGE;
+
/* keep track of non-relevant fields */
mask_sel |= 1 << (first_free - k);
}
}
/**
- * ice_add_prof - add profile
+ * 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
* the ID value used here.
*/
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)
+{
+ 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;
+
+ /* If PTG is already added, skip and continue */
+ if (ice_is_bit_set(ptgs_used, ptg))
+ continue;
+
+ ice_set_bit(ptg, ptgs_used);
+ prof->ptg[prof->ptg_cnt] = ptg;
+
+ if (++prof->ptg_cnt >= ICE_MAX_PTG_PER_PROFILE)
+ break;
+
+ /* nothing left in byte, then exit */
+ m = ~((1 << (bit + 1)) - 1);
+ if (!(ptypes[byte] & m))
+ break;
+ }
+ }
+
+ bytes--;
+ byte++;
+ }
+
+ LIST_ADD(&prof->list, &hw->blk[blk].es.prof_map);
+ status = ICE_SUCCESS;
+
+err_ice_add_prof:
+ ice_release_lock(&hw->blk[blk].es.prof_map_lock);
+ return status;
+}
+
+/**
+ * ice_add_prof - 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)
+ *
+ * This function registers a profile, which matches a set of PTGs 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)
{
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 */
prof->profile_cookie = id;
prof->prof_id = prof_id;
- prof->ptype_count = 0;
+ prof->ptg_cnt = 0;
prof->context = 0;
/* build list of ptgs */
- while (bytes && prof->ptype_count < ICE_MAX_PTYPE_PER_PROFILE) {
+ while (bytes && prof->ptg_cnt < ICE_MAX_PTG_PER_PROFILE) {
u32 bit;
if (!ptypes[byte]) {
}
/* Examine 8 bits per byte */
for (bit = 0; bit < 8; bit++) {
- if (ptypes[byte] & 1 << bit) {
+ if (ptypes[byte] & BIT(bit)) {
u16 ptype;
+ u8 ptg;
u8 m;
ptype = byte * BITS_PER_BYTE + bit;
- if (ptype < ICE_FLOW_PTYPE_MAX) {
- prof->ptype[prof->ptype_count] = ptype;
- if (++prof->ptype_count >=
- ICE_MAX_PTYPE_PER_PROFILE)
- break;
- }
+ /* 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;
+
+ /* If PTG is already added, skip and continue */
+ if (ice_is_bit_set(ptgs_used, ptg))
+ continue;
+
+ ice_set_bit(ptg, ptgs_used);
+ prof->ptg[prof->ptg_cnt] = ptg;
+
+ if (++prof->ptg_cnt >= ICE_MAX_PTG_PER_PROFILE)
+ break;
/* nothing left in byte, then exit */
m = ~((1 << (bit + 1)) - 1);
return entry;
}
-/**
- * ice_set_prof_context - Set context for a given profile
- * @hw: pointer to the HW struct
- * @blk: hardware block
- * @id: profile tracking ID
- * @cntxt: context
- */
-struct ice_prof_map *
-ice_set_prof_context(struct ice_hw *hw, enum ice_block blk, u64 id, u64 cntxt)
-{
- struct ice_prof_map *entry;
-
- entry = ice_search_prof_id(hw, blk, id);
- if (entry)
- entry->context = cntxt;
-
- return entry;
-}
-
-/**
- * ice_get_prof_context - Get context for a given profile
- * @hw: pointer to the HW struct
- * @blk: hardware block
- * @id: profile tracking ID
- * @cntxt: pointer to variable to receive the context
- */
-struct ice_prof_map *
-ice_get_prof_context(struct ice_hw *hw, enum ice_block blk, u64 id, u64 *cntxt)
-{
- struct ice_prof_map *entry;
-
- entry = ice_search_prof_id(hw, blk, id);
- if (entry)
- *cntxt = entry->context;
-
- return entry;
-}
-
/**
* ice_vsig_prof_id_count - count profiles in a VSIG
* @hw: pointer to the HW struct
u16 i;
for (i = 0; i < prof->tcam_count; i++) {
- prof->tcam[i].in_use = false;
- status = ice_rel_tcam_idx(hw, blk, prof->tcam[i].tcam_idx);
- if (status)
- return ICE_ERR_HW_TABLE;
+ if (prof->tcam[i].in_use) {
+ prof->tcam[i].in_use = false;
+ status = ice_rel_tcam_idx(hw, blk,
+ prof->tcam[i].tcam_idx);
+ if (status)
+ return ICE_ERR_HW_TABLE;
+ }
}
return ICE_SUCCESS;
}
/**
- * ice_get_prof_ptgs - get ptgs for profile
+ * ice_get_prof - get profile
* @hw: pointer to the HW struct
* @blk: hardware block
* @hdl: profile handle
* @chg: change list
*/
static enum ice_status
-ice_get_prof_ptgs(struct ice_hw *hw, enum ice_block blk, u64 hdl,
- struct LIST_HEAD_TYPE *chg)
+ice_get_prof(struct ice_hw *hw, enum ice_block blk, u64 hdl,
+ struct LIST_HEAD_TYPE *chg)
{
struct ice_prof_map *map;
struct ice_chs_chg *p;
if (!map)
return ICE_ERR_DOES_NOT_EXIST;
- for (i = 0; i < map->ptype_count; i++) {
- enum ice_status status;
- bool add;
- u8 ptg;
-
- status = ice_get_ptg(hw, blk, map->ptype[i], &ptg, &add);
- if (status)
- goto err_ice_get_prof_ptgs;
-
- if (add || !hw->blk[blk].es.written[map->prof_id]) {
- /* add PTG to change list */
+ for (i = 0; i < map->ptg_cnt; i++) {
+ if (!hw->blk[blk].es.written[map->prof_id]) {
+ /* add ES to change list */
p = (struct ice_chs_chg *)ice_malloc(hw, sizeof(*p));
if (!p)
- goto err_ice_get_prof_ptgs;
+ goto err_ice_get_prof;
p->type = ICE_PTG_ES_ADD;
- p->ptype = map->ptype[i];
- p->ptg = ptg;
- p->add_ptg = add;
+ p->ptype = 0;
+ p->ptg = map->ptg[i];
+ p->add_ptg = 0;
- p->add_prof = !hw->blk[blk].es.written[map->prof_id];
+ p->add_prof = 1;
p->prof_id = map->prof_id;
hw->blk[blk].es.written[map->prof_id] = true;
return ICE_SUCCESS;
-err_ice_get_prof_ptgs:
+err_ice_get_prof:
/* let caller clean up the change list */
return ICE_ERR_NO_MEMORY;
}
struct ice_vsig_prof *p;
/* copy to the input list */
- p = (struct ice_vsig_prof *)ice_malloc(hw, sizeof(*p));
+ p = (struct ice_vsig_prof *)ice_memdup(hw, ent1, sizeof(*p),
+ ICE_NONDMA_TO_NONDMA);
if (!p)
goto err_ice_get_profs_vsig;
- ice_memcpy(p, ent1, sizeof(*p), ICE_NONDMA_TO_NONDMA);
-
LIST_ADD_TAIL(&p->list, lst);
}
p->profile_cookie = map->profile_cookie;
p->prof_id = map->prof_id;
- p->tcam_count = map->ptype_count;
-
- for (i = 0; i < map->ptype_count; i++) {
- u8 ptg;
+ p->tcam_count = map->ptg_cnt;
+ for (i = 0; i < map->ptg_cnt; i++) {
p->tcam[i].prof_id = map->prof_id;
p->tcam[i].tcam_idx = ICE_INVALID_TCAM;
-
- ice_ptg_find_ptype(hw, blk, map->ptype[i], &ptg);
-
- p->tcam[i].ptg = ptg;
+ p->tcam[i].ptg = map->ptg[i];
}
LIST_ADD(&p->list, lst);
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 disabled, change the low flag bit to never match */
+ /* if disabling, free the tcam */
if (!enable) {
- dc_msk[0] = 0x00;
- nm_msk[0] = 0x01;
+ status = ice_free_tcam_ent(hw, blk, tcam->tcam_idx);
+ tcam->tcam_idx = 0;
+ tcam->in_use = 0;
+ return status;
}
+ /* for re-enabling, reallocate a tcam */
+ status = ice_alloc_tcam_ent(hw, blk, &tcam->tcam_idx);
+ if (status)
+ return status;
+
/* add TCAM to change list */
p = (struct ice_chs_chg *)ice_malloc(hw, sizeof(*p));
if (!p)
if (status)
goto err_ice_prof_tcam_ena_dis;
- tcam->in_use = enable;
+ tcam->in_use = 1;
p->type = ICE_TCAM_ADD;
p->add_tcam_idx = true;
enum ice_status status;
u16 idx;
- ice_memset(ptgs_used, 0, sizeof(ptgs_used), ICE_NONDMA_MEM);
+ ice_zero_bitmap(ptgs_used, ICE_XLT1_CNT);
idx = vsig & ICE_VSIG_IDX_M;
/* Priority is based on the order in which the profiles are added. The
t->profile_cookie = map->profile_cookie;
t->prof_id = map->prof_id;
- t->tcam_count = map->ptype_count;
+ t->tcam_count = map->ptg_cnt;
/* create TCAM entries */
- for (i = 0; i < map->ptype_count; i++) {
+ for (i = 0; i < map->ptg_cnt; i++) {
enum ice_status status;
u16 tcam_idx;
- bool add;
- u8 ptg;
-
- /* If properly sequenced, we should never have to allocate new
- * PTGs
- */
- status = ice_get_ptg(hw, blk, map->ptype[i], &ptg, &add);
- if (status)
- goto err_ice_add_prof_id_vsig;
/* add TCAM to change list */
p = (struct ice_chs_chg *)ice_malloc(hw, sizeof(*p));
goto err_ice_add_prof_id_vsig;
}
- t->tcam[i].ptg = ptg;
+ 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].in_use = true;
return status == ICE_SUCCESS;
}
+/**
+ * ice_add_vsi_flow - add VSI flow
+ * @hw: pointer to the HW struct
+ * @blk: hardware block
+ * @vsi: input VSI
+ * @vsig: target VSIG to include the input VSI
+ *
+ * Calling this function will add the VSI to a given VSIG and
+ * update the HW tables accordingly. This call can be used to
+ * add multiple VSIs to a VSIG if we know beforehand that those
+ * VSIs have the same characteristics of the VSIG. This will
+ * save time in generating a new VSIG and TCAMs till a match is
+ * found and subsequent rollback when a matching VSIG is found.
+ */
+enum ice_status
+ice_add_vsi_flow(struct ice_hw *hw, enum ice_block blk, u16 vsi, u16 vsig)
+{
+ struct ice_chs_chg *tmp, *del;
+ struct LIST_HEAD_TYPE chg;
+ enum ice_status status;
+
+ /* if target VSIG is default the move is invalid */
+ if ((vsig & ICE_VSIG_IDX_M) == ICE_DEFAULT_VSIG)
+ return ICE_ERR_PARAM;
+
+ INIT_LIST_HEAD(&chg);
+
+ /* move VSI to the VSIG that matches */
+ status = ice_move_vsi(hw, blk, vsi, vsig, &chg);
+ /* update hardware if success */
+ if (!status)
+ status = ice_upd_prof_hw(hw, blk, &chg);
+
+ LIST_FOR_EACH_ENTRY_SAFE(del, tmp, &chg, ice_chs_chg, list_entry) {
+ LIST_DEL(&del->list_entry);
+ ice_free(hw, del);
+ }
+
+ return status;
+}
+
/**
* ice_add_prof_id_flow - add profile flow
* @hw: pointer to the HW struct
INIT_LIST_HEAD(&chrs);
INIT_LIST_HEAD(&chg);
- status = ice_get_prof_ptgs(hw, blk, hdl, &chg);
+ /* Get profile */
+ status = ice_get_prof(hw, blk, hdl, &chg);
if (status)
return status;
return status;
}
-/**
- * ice_add_flow - add flow
- * @hw: pointer to the HW struct
- * @blk: hardware block
- * @vsi: array of VSIs to enable with the profile specified by ID
- * @count: number of elements in the VSI array
- * @id: profile tracking ID
- *
- * Calling this function will update the hardware tables to enable the
- * profile indicated by the ID parameter for the VSIs specified in the VSI
- * array. Once successfully called, the flow will be enabled.
- */
-enum ice_status
-ice_add_flow(struct ice_hw *hw, enum ice_block blk, u16 vsi[], u8 count,
- u64 id)
-{
- enum ice_status status;
- u16 i;
-
- for (i = 0; i < count; i++) {
- status = ice_add_prof_id_flow(hw, blk, vsi[i], id);
- if (status)
- return status;
- }
-
- return ICE_SUCCESS;
-}
-
/**
* ice_rem_prof_from_list - remove a profile from list
* @hw: pointer to the HW struct
return status;
}
-
-/**
- * ice_rem_flow - remove flow
- * @hw: pointer to the HW struct
- * @blk: hardware block
- * @vsi: array of VSIs from which to remove the profile specified by ID
- * @count: number of elements in the VSI array
- * @id: profile tracking ID
- *
- * The function will remove flows from the specified VSIs that were enabled
- * using ice_add_flow. The ID value will indicated which profile will be
- * removed. Once successfully called, the flow will be disabled.
- */
-enum ice_status
-ice_rem_flow(struct ice_hw *hw, enum ice_block blk, u16 vsi[], u8 count,
- u64 id)
-{
- enum ice_status status;
- u16 i;
-
- for (i = 0; i < count; i++) {
- status = ice_rem_prof_id_flow(hw, blk, vsi[i], id);
- if (status)
- return status;
- }
-
- return ICE_SUCCESS;
-}