X-Git-Url: http://git.droids-corp.org/?a=blobdiff_plain;f=drivers%2Fnet%2Fice%2Fbase%2Fice_flex_pipe.c;h=11601f2c2a75c197b9de2dfffe5bfaf51fdc7809;hb=737dcad0f8b14184f2344be856e23efd763a85d2;hp=92d3d29ad9ba7983615bc530f1fc569f0cd63230;hpb=5c8af3625389ad8b398945889d82ab983d43b309;p=dpdk.git diff --git a/drivers/net/ice/base/ice_flex_pipe.c b/drivers/net/ice/base/ice_flex_pipe.c index 92d3d29ad9..11601f2c2a 100644 --- a/drivers/net/ice/base/ice_flex_pipe.c +++ b/drivers/net/ice/base/ice_flex_pipe.c @@ -398,7 +398,7 @@ ice_find_boost_entry(struct ice_seg *ice_seg, u16 addr, * Handles enumeration of individual label entries. */ static void * -ice_label_enum_handler(u32 __always_unused sect_type, void *section, u32 index, +ice_label_enum_handler(u32 __ALWAYS_UNUSED sect_type, void *section, u32 index, u32 *offset) { struct ice_label_section *labels; @@ -461,7 +461,7 @@ ice_enum_labels(struct ice_seg *ice_seg, u32 type, struct ice_pkg_enum *state, * 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; @@ -640,7 +640,7 @@ static bool ice_bits_max_set(const u8 *mask, u16 size, u16 max) * @size: the size of the complete key in bytes (must be even) * @val: array of 8-bit values that makes up the value portion of the key * @upd: array of 8-bit masks that determine what key portion to update - * @dc: array of 8-bit masks that make up the dont' care mask + * @dc: array of 8-bit masks that make up the don't care mask * @nm: array of 8-bit masks that make up the never match mask * @off: the offset of the first byte in the key to update * @len: the number of bytes in the key update @@ -706,7 +706,7 @@ ice_acquire_global_cfg_lock(struct ice_hw *hw, { 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); @@ -739,7 +739,7 @@ static void ice_release_global_cfg_lock(struct ice_hw *hw) 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); @@ -753,7 +753,7 @@ ice_acquire_change_lock(struct ice_hw *hw, enum ice_aq_res_access_type access) */ 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); } @@ -779,7 +779,7 @@ ice_aq_download_pkg(struct ice_hw *hw, struct ice_buf_hdr *pkg_buf, 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; @@ -808,28 +808,6 @@ ice_aq_download_pkg(struct ice_hw *hw, struct ice_buf_hdr *pkg_buf, 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 @@ -851,7 +829,7 @@ ice_aq_update_pkg(struct ice_hw *hw, struct ice_buf_hdr *pkg_buf, u16 buf_size, 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; @@ -890,14 +868,14 @@ ice_aq_update_pkg(struct ice_hw *hw, struct ice_buf_hdr *pkg_buf, u16 buf_size, * 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) { u32 i; ice_debug(hw, ICE_DBG_TRACE, "%s\n", __func__); - ice_debug(hw, ICE_DBG_PKG, "Package version: %d.%d.%d.%d\n", + ice_debug(hw, ICE_DBG_PKG, "Package format version: %d.%d.%d.%d\n", pkg_hdr->format_ver.major, pkg_hdr->format_ver.minor, pkg_hdr->format_ver.update, pkg_hdr->format_ver.draft); @@ -982,9 +960,19 @@ ice_dwnld_cfg_bufs(struct ice_hw *hw, struct ice_buf *bufs, u32 count) 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); @@ -1007,6 +995,9 @@ ice_dwnld_cfg_bufs(struct ice_hw *hw, struct ice_buf *bufs, u32 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", @@ -1039,7 +1030,7 @@ ice_aq_get_pkg_info_list(struct ice_hw *hw, { 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); @@ -1052,7 +1043,8 @@ ice_aq_get_pkg_info_list(struct ice_hw *hw, * * 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; @@ -1081,7 +1073,7 @@ enum ice_status ice_download_pkg(struct ice_hw *hw, struct ice_seg *ice_seg) * * 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; @@ -1133,8 +1125,7 @@ ice_init_pkg_info(struct ice_hw *hw, struct ice_pkg_hdr *pkg_hdr) * * 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; @@ -1165,6 +1156,7 @@ ice_get_pkg_info(struct ice_hw *hw) 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'; @@ -1187,41 +1179,6 @@ init_pkg_free_alloc: 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 @@ -1327,7 +1284,6 @@ static void ice_init_pkg_regs(struct ice_hw *hw) /** * ice_chk_pkg_version - check package version for compatibility with driver - * @hw: pointer to the hardware structure * @pkg_ver: pointer to a version structure to check * * Check to make sure that the package about to be downloaded is compatible with @@ -1335,18 +1291,11 @@ static void ice_init_pkg_regs(struct ice_hw *hw) * version must match our ICE_PKG_SUPP_VER_MAJ and ICE_PKG_SUPP_VER_MNR * definitions. */ -static enum ice_status -ice_chk_pkg_version(struct ice_hw *hw, struct ice_pkg_ver *pkg_ver) +static enum ice_status ice_chk_pkg_version(struct ice_pkg_ver *pkg_ver) { if (pkg_ver->major != ICE_PKG_SUPP_VER_MAJ || - pkg_ver->minor != ICE_PKG_SUPP_VER_MNR) { - ice_info(hw, "ERROR: Incompatible package: %d.%d.%d.%d - requires package version: %d.%d.*.*\n", - pkg_ver->major, pkg_ver->minor, pkg_ver->update, - pkg_ver->draft, ICE_PKG_SUPP_VER_MAJ, - ICE_PKG_SUPP_VER_MNR); - + pkg_ver->minor != ICE_PKG_SUPP_VER_MNR) return ICE_ERR_NOT_SUPPORTED; - } return ICE_SUCCESS; } @@ -1401,7 +1350,7 @@ enum ice_status ice_init_pkg(struct ice_hw *hw, u8 *buf, u32 len) /* before downloading the package, check package version for * compatibility with driver */ - status = ice_chk_pkg_version(hw, &hw->pkg_ver); + status = ice_chk_pkg_version(&hw->pkg_ver); if (status) return status; @@ -1427,7 +1376,7 @@ enum ice_status ice_init_pkg(struct ice_hw *hw, u8 *buf, u32 len) if (!status) { status = ice_get_pkg_info(hw); if (!status) - status = ice_chk_pkg_version(hw, &hw->active_pkg_ver); + status = ice_chk_pkg_version(&hw->active_pkg_ver); } if (!status) { @@ -1499,7 +1448,7 @@ enum ice_status ice_copy_and_init_pkg(struct ice_hw *hw, const u8 *buf, u32 len) * 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; @@ -1546,11 +1495,84 @@ ice_sw_fv_handler(u32 sect_type, void *section, u32 index, u32 *offset) 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 @@ -1562,7 +1584,7 @@ ice_sw_fv_handler(u32 sect_type, void *section, u32 index, u32 *offset) */ 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; @@ -1581,8 +1603,17 @@ ice_get_sw_fv_list(struct ice_hw *hw, u16 *prot_ids, u8 ids_cnt, 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 @@ -1606,7 +1637,6 @@ ice_get_sw_fv_list(struct ice_hw *hw, u16 *prot_ids, u8 ids_cnt, break; } } - ice_seg = NULL; } while (fv); if (LIST_EMPTY(fv_list)) return ICE_ERR_CFG; @@ -1623,40 +1653,56 @@ err: } /** - * ice_pkg_buf_alloc_single_section - * @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 - * - * Allocates a package buffer with a single section. - * Note: all package contents must be in Little Endian form. + * ice_init_profile_to_result_bm - Initialize the profile result index bitmap + * @hw: pointer to hardware structure */ -static struct ice_buf_build * -ice_pkg_buf_alloc_single_section(struct ice_hw *hw, u32 type, u16 size, - void **section) +void +ice_init_prof_result_bm(struct ice_hw *hw) { - struct ice_buf_build *buf; + struct ice_pkg_enum state; + struct ice_seg *ice_seg; + struct ice_fv *fv; - if (!section) - return NULL; + if (!hw->seg) + return; - buf = ice_pkg_buf_alloc(hw); - if (!buf) - return NULL; + ice_seg = hw->seg; + do { + u32 off; + u16 i; - if (ice_pkg_buf_reserve_section(buf, 1)) - goto ice_pkg_buf_alloc_single_section_err; + fv = (struct ice_fv *) + ice_pkg_enum_entry(ice_seg, &state, ICE_SID_FLD_VEC_SW, + &off, ice_sw_fv_handler); + ice_seg = NULL; + if (!fv) + break; - *section = ice_pkg_buf_alloc_section(buf, type, size); - if (!*section) - goto ice_pkg_buf_alloc_single_section_err; + ice_zero_bitmap(hw->switch_info->prof_res_bm[off], + ICE_MAX_FV_WORDS); - return buf; + /* Determine empty field vector indices, these can be + * used for recipe results. Skip index 0, since it is + * always used for Switch ID. + */ + for (i = 1; i < ICE_MAX_FV_WORDS; i++) + if (fv->ew[i].prot_id == ICE_PROT_INVALID && + fv->ew[i].off == ICE_FV_OFFSET_INVAL) + ice_set_bit(i, + hw->switch_info->prof_res_bm[off]); + } while (fv); +} -ice_pkg_buf_alloc_single_section_err: - ice_pkg_buf_free(hw, buf); - return NULL; +/** + * ice_pkg_buf_free + * @hw: pointer to the HW structure + * @bld: pointer to pkg build (allocated by ice_pkg_buf_alloc()) + * + * Frees a package buffer + */ +static void ice_pkg_buf_free(struct ice_hw *hw, struct ice_buf_build *bld) +{ + ice_free(hw, bld); } /** @@ -1672,7 +1718,7 @@ ice_pkg_buf_alloc_single_section_err: * 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; @@ -1700,48 +1746,6 @@ ice_pkg_buf_reserve_section(struct ice_buf_build *bld, u16 count) 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()) @@ -1754,7 +1758,7 @@ ice_pkg_buf_unreserve_section(struct ice_buf_build *bld, u16 count) * 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; @@ -1795,24 +1799,6 @@ ice_pkg_buf_alloc_section(struct ice_buf_build *bld, u32 type, u16 size) 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()) @@ -1823,7 +1809,7 @@ u16 ice_pkg_buf_get_free_space(struct ice_buf_build *bld) * 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; @@ -1840,7 +1826,7 @@ u16 ice_pkg_buf_get_active_sections(struct ice_buf_build *bld) * * 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; @@ -1849,164 +1835,320 @@ struct ice_buf *ice_pkg_buf(struct ice_buf_build *bld) } /** - * 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); + + 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_ptg_alloc_val - Allocates a new packet type group ID by value + * 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; } /** @@ -2066,7 +2208,7 @@ ice_ptg_remove_ptype(struct ice_hw *hw, enum ice_block blk, u16 ptype, u8 ptg) * 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; @@ -2202,71 +2344,6 @@ ice_match_prop_lst(struct LIST_HEAD_TYPE *list1, struct LIST_HEAD_TYPE *list2) /* 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 @@ -2346,7 +2423,7 @@ static u16 ice_vsig_alloc(struct ice_hw *hw, enum ice_block blk) * 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) { @@ -2373,7 +2450,7 @@ ice_find_dup_props_vsig(struct ice_hw *hw, enum ice_block blk, * 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; @@ -2424,6 +2501,62 @@ ice_vsig_free(struct ice_hw *hw, enum ice_block blk, u16 vsig) 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 @@ -2436,7 +2569,7 @@ ice_vsig_free(struct ice_hw *hw, enum ice_block blk, u16 vsig) * 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; @@ -2488,59 +2621,99 @@ ice_vsig_add_mv_vsi(struct ice_hw *hw, enum ice_block blk, u16 vsi, u16 vsig) } /** - * 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; } /** @@ -2730,6 +2903,334 @@ ice_prof_inc_ref(struct ice_hw *hw, enum ice_block blk, u8 prof_id) 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 @@ -2769,6 +3270,7 @@ ice_prof_dec_ref(struct ice_hw *hw, enum ice_block blk, u8 prof_id) 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); } } @@ -2903,7 +3405,7 @@ static void ice_fill_tbl(struct ice_hw *hw, enum ice_block block_id, u32 sid) 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) { @@ -2995,7 +3497,7 @@ static void ice_fill_tbl(struct ice_hw *hw, enum ice_block block_id, u32 sid) 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. */ @@ -3014,7 +3516,7 @@ static void ice_fill_tbl(struct ice_hw *hw, enum ice_block block_id, u32 sid) * * 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) { @@ -3029,8 +3531,28 @@ void ice_fill_blk_tbls(struct ice_hw *hw) ice_fill_tbl(hw, blk_id, hw->blk[blk_id].prof_redir.sid); 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); } /** @@ -3042,10 +3564,7 @@ static void ice_free_flow_profs(struct ice_hw *hw, u8 blk_idx) { 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; @@ -3059,6 +3578,7 @@ static void ice_free_flow_profs(struct ice_hw *hw, u8 blk_idx) 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 @@ -3095,17 +3615,12 @@ void ice_free_hw_tbls(struct ice_hw *hw) 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); @@ -3120,6 +3635,7 @@ void ice_free_hw_tbls(struct ice_hw *hw) 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, @@ -3128,6 +3644,7 @@ void ice_free_hw_tbls(struct ice_hw *hw) ice_free(hw, r); } ice_destroy_lock(&hw->rss_locks); + ice_shutdown_all_prof_masks(hw); ice_memset(hw->blk, 0, sizeof(hw->blk), ICE_NONDMA_MEM); } @@ -3152,6 +3669,7 @@ enum ice_status ice_init_hw_tbls(struct ice_hw *hw) ice_init_lock(&hw->rss_locks); INIT_LIST_HEAD(&hw->rss_list_head); + ice_init_all_prof_masks(hw); 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; @@ -3243,7 +3761,8 @@ enum ice_status ice_init_hw_tbls(struct ice_hw *hw) 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; } @@ -3369,43 +3888,6 @@ ice_vsig_get_ref(struct ice_hw *hw, enum ice_block blk, u16 vsig, u16 *refs) 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 @@ -3757,7 +4239,7 @@ ice_update_fd_swap(struct ice_hw *hw, u16 prof_id, struct ice_fv_word *es) 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); @@ -3802,7 +4284,7 @@ ice_update_fd_swap(struct ice_hw *hw, u16 prof_id, struct ice_fv_word *es) 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 */ @@ -3812,6 +4294,9 @@ ice_update_fd_swap(struct ice_hw *hw, u16 prof_id, struct ice_fv_word *es) 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); } @@ -3885,12 +4370,13 @@ ice_update_fd_swap(struct ice_hw *hw, u16 prof_id, struct ice_fv_word *es) } /** - * 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 @@ -3898,15 +4384,140 @@ ice_update_fd_swap(struct ice_hw *hw, u16 prof_id, struct ice_fv_word *es) * 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 */ @@ -3943,11 +4554,11 @@ ice_add_prof(struct ice_hw *hw, enum ice_block blk, u64 id, u8 ptypes[], 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]) { @@ -3957,18 +4568,29 @@ ice_add_prof(struct ice_hw *hw, enum ice_block blk, u64 id, u8 ptypes[], } /* 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); @@ -4035,44 +4657,6 @@ ice_search_prof_id(struct ice_hw *hw, enum ice_block blk, u64 id) 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 @@ -4134,10 +4718,13 @@ ice_rem_prof_id(struct ice_hw *hw, enum ice_block blk, 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; @@ -4317,15 +4904,15 @@ err_ice_rem_prof: } /** - * 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; @@ -4336,27 +4923,19 @@ ice_get_prof_ptgs(struct ice_hw *hw, enum ice_block blk, u64 hdl, 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; @@ -4367,7 +4946,7 @@ ice_get_prof_ptgs(struct ice_hw *hw, enum ice_block blk, u64 hdl, return ICE_SUCCESS; -err_ice_get_prof_ptgs: +err_ice_get_prof: /* let caller clean up the change list */ return ICE_ERR_NO_MEMORY; } @@ -4393,12 +4972,11 @@ ice_get_profs_vsig(struct ice_hw *hw, enum ice_block blk, u16 vsig, 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); } @@ -4438,17 +5016,12 @@ ice_add_prof_to_lst(struct ice_hw *hw, enum ice_block blk, 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); @@ -4479,6 +5052,7 @@ ice_move_vsi(struct ice_hw *hw, enum ice_block blk, u16 vsi, u16 vsig, status = ice_vsig_find_vsi(hw, blk, vsi, &orig_vsig); if (!status) status = ice_vsig_add_mv_vsi(hw, blk, vsi, vsig); + if (status) { ice_free(hw, p); return status; @@ -4518,12 +5092,19 @@ ice_prof_tcam_ena_dis(struct ice_hw *hw, enum ice_block blk, bool enable, 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) @@ -4535,7 +5116,7 @@ ice_prof_tcam_ena_dis(struct ice_hw *hw, enum ice_block blk, bool enable, 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; @@ -4570,7 +5151,7 @@ ice_adj_prof_priorities(struct ice_hw *hw, enum ice_block blk, u16 vsig, 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 @@ -4660,21 +5241,12 @@ ice_add_prof_id_vsig(struct ice_hw *hw, enum ice_block blk, u16 vsig, u64 hdl, 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)); @@ -4688,7 +5260,7 @@ ice_add_prof_id_vsig(struct ice_hw *hw, enum ice_block blk, u16 vsig, u64 hdl, 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; @@ -4838,6 +5410,47 @@ ice_find_prof_vsig(struct ice_hw *hw, enum ice_block blk, u64 hdl, u16 *vsig) 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 @@ -4864,7 +5477,8 @@ ice_add_prof_id_flow(struct ice_hw *hw, enum ice_block blk, u16 vsi, u64 hdl) 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; @@ -4987,34 +5601,6 @@ err_ice_add_prof_id_flow: 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 @@ -5168,31 +5754,3 @@ err_ice_rem_prof_id_flow: 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; -}