From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from mails.dpdk.org (mails.dpdk.org [217.70.189.124]) by inbox.dpdk.org (Postfix) with ESMTP id AD5EE4404F; Wed, 12 Jun 2024 17:12:05 +0200 (CEST) Received: from mails.dpdk.org (localhost [127.0.0.1]) by mails.dpdk.org (Postfix) with ESMTP id A303842D80; Wed, 12 Jun 2024 17:04:36 +0200 (CEST) Received: from mgamail.intel.com (mgamail.intel.com [198.175.65.10]) by mails.dpdk.org (Postfix) with ESMTP id 8292F427E3 for ; Wed, 12 Jun 2024 17:04:31 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1718204672; x=1749740672; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=6kdM1mUzmMBgHBJMerDcba18VcL7rhmfil+BOcwyPbA=; b=NRBStD6z9LOWjtxocfVUlDfKRWFeIXn6WIR4dUpnCO8WkIz2A5w0rfQI gdz/9V7X+HRuozfd2nNDGaA4PgHQcKelzH1B7kdxPfR8nieLds7xs4YCF CmHrLvAdt8f+LY2W1qH46sPiTdfT2RQEUoJeQWRPbaFaRLefVa2fLZTCg uF+DjMaR45MPg24wKiN2jt1YIHtfDJ3gqZ4Q4sXs9GTtQR5brZAQY8K7S H5kZtrVzsRyXEN8AvQ6msfJAToA69elhUes4o9anwAGW93cvIYd7RXjUf /7LmQgaODjnie+v6JxXrU69iDiCysq1C25Rfh+LjYVQDWAyHQpBZP5x0Q g==; X-CSE-ConnectionGUID: qZbiR1SFQfeyzqCJFBtsuQ== X-CSE-MsgGUID: mc3aqKQQTRmMz7OXeYIG7Q== X-IronPort-AV: E=McAfee;i="6700,10204,11101"; a="32459457" X-IronPort-AV: E=Sophos;i="6.08,233,1712646000"; d="scan'208";a="32459457" Received: from orviesa009.jf.intel.com ([10.64.159.149]) by orvoesa102.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 12 Jun 2024 08:04:30 -0700 X-CSE-ConnectionGUID: gLMewYEeTEyOIjoTCLksVQ== X-CSE-MsgGUID: NvWoEwfjTDWTXm7wElPC9Q== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="6.08,233,1712646000"; d="scan'208";a="39925196" Received: from silpixa00401119.ir.intel.com ([10.55.129.167]) by orviesa009.jf.intel.com with ESMTP; 12 Jun 2024 08:04:29 -0700 From: Anatoly Burakov To: dev@dpdk.org Cc: Ian Stokes , bruce.richardson@intel.com, Steven Zou Subject: [PATCH v2 045/148] net/ice/base: implement switch recipe reuse feature Date: Wed, 12 Jun 2024 16:00:39 +0100 Message-ID: <74a3104269c42c046591d46ef7de8be4ddf8cd49.1718204528.git.anatoly.burakov@intel.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: References: <20240430154014.1026-1-ian.stokes@intel.com> MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-BeenThere: dev@dpdk.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: DPDK patches and discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: dev-bounces@dpdk.org From: Ian Stokes If FW supports the corresponding functionality, the driver allows PFs to subscribe the same switch recipes. Then when the PF is done with a switch recipe, the PF can ask the FW to free that switch recipe. When the FW detects that all subscribing PFs have freed the switch recipe, the FW will free the switch recipe so that it can be reused. This feature also fixes a problem where all switch recipes would eventually be exhausted because switch recipes could not be freed, as freeing a shared recipe could potentially break other PFs that were using it. Signed-off-by: Steven Zou Signed-off-by: Ian Stokes --- drivers/net/ice/base/ice_adminq_cmd.h | 2 + drivers/net/ice/base/ice_common.c | 2 + drivers/net/ice/base/ice_switch.c | 277 +++++++++++++++++++++++--- drivers/net/ice/base/ice_switch.h | 2 + drivers/net/ice/base/ice_type.h | 2 + 5 files changed, 262 insertions(+), 23 deletions(-) diff --git a/drivers/net/ice/base/ice_adminq_cmd.h b/drivers/net/ice/base/ice_adminq_cmd.h index cfc13f0b2b..8d6de52a72 100644 --- a/drivers/net/ice/base/ice_adminq_cmd.h +++ b/drivers/net/ice/base/ice_adminq_cmd.h @@ -308,6 +308,8 @@ struct ice_aqc_set_port_params { #define ICE_AQC_RES_TYPE_FLAG_SHARED BIT(7) #define ICE_AQC_RES_TYPE_FLAG_SCAN_BOTTOM BIT(12) #define ICE_AQC_RES_TYPE_FLAG_IGNORE_INDEX BIT(13) +#define ICE_AQC_RES_TYPE_FLAG_SUBSCRIBE_SHARED BIT(14) +#define ICE_AQC_RES_TYPE_FLAG_SUBSCRIBE_CTL BIT(15) #define ICE_AQC_RES_TYPE_FLAG_DEDICATED 0x00 diff --git a/drivers/net/ice/base/ice_common.c b/drivers/net/ice/base/ice_common.c index 6c487e02dc..45fea193da 100644 --- a/drivers/net/ice/base/ice_common.c +++ b/drivers/net/ice/base/ice_common.c @@ -1141,6 +1141,8 @@ int ice_init_hw(struct ice_hw *hw) goto err_unroll_fltr_mgmt_struct; ice_init_lock(&hw->tnl_lock); + ice_init_chk_subscribable_recipe_support(hw); + return 0; err_unroll_fltr_mgmt_struct: diff --git a/drivers/net/ice/base/ice_switch.c b/drivers/net/ice/base/ice_switch.c index ba8d2eb4b1..fc9a690b6f 100644 --- a/drivers/net/ice/base/ice_switch.c +++ b/drivers/net/ice/base/ice_switch.c @@ -2426,14 +2426,14 @@ static enum ice_sw_tunnel_type ice_get_tun_type_for_recipe(u8 rid, bool vlan) * @recps: struct that we need to populate * @rid: recipe ID that we are populating * @refresh_required: true if we should get recipe to profile mapping from FW + * @is_add: flag of adding recipe * - * This function is used to populate all the necessary entries into our - * bookkeeping so that we have a current list of all the recipes that are - * programmed in the firmware. + * Populate all the necessary entries into SW bookkeeping so that we have a + * current list of all the recipes that are programmed in the firmware. */ static int ice_get_recp_frm_fw(struct ice_hw *hw, struct ice_sw_recipe *recps, u8 rid, - bool *refresh_required) + bool *refresh_required, bool *is_add) { ice_declare_bitmap(result_bm, ICE_MAX_FV_WORDS); struct ice_aqc_recipe_data_elem *tmp; @@ -2557,8 +2557,12 @@ ice_get_recp_frm_fw(struct ice_hw *hw, struct ice_sw_recipe *recps, u8 rid, recps[idx].chain_idx = ICE_INVAL_CHAIN_IND; } - if (!is_root) + if (!is_root) { + if (hw->subscribable_recipes_supported && *is_add) + recps[idx].recp_created = true; + continue; + } /* Only do the following for root recipes entries */ ice_memcpy(recps[idx].r_bitmap, root_bufs.recipe_bitmap, @@ -2581,7 +2585,8 @@ ice_get_recp_frm_fw(struct ice_hw *hw, struct ice_sw_recipe *recps, u8 rid, /* Copy result indexes */ ice_cp_bitmap(recps[rid].res_idxs, result_bm, ICE_MAX_FV_WORDS); - recps[rid].recp_created = true; + if (!hw->subscribable_recipes_supported || (hw->subscribable_recipes_supported && *is_add)) + recps[rid].recp_created = true; err_unroll: ice_free(hw, tmp); @@ -3770,11 +3775,26 @@ ice_aq_get_recipe_to_profile(struct ice_hw *hw, u32 profile_id, u8 *r_bitmap, } /** - * ice_alloc_recipe - add recipe resource + * ice_init_chk_subscribable_recipe_support - are subscribable recipes available + * @hw: pointer to the hardware structure + */ +void ice_init_chk_subscribable_recipe_support(struct ice_hw *hw) +{ + struct ice_nvm_info *nvm = &hw->flash.nvm; + + if (nvm->major >= 0x04 && nvm->minor >= 0x30) + hw->subscribable_recipes_supported = true; + else + hw->subscribable_recipes_supported = false; +} + +/** + * ice_alloc_legacy_shared_recipe - alloc legacy shared recipe * @hw: pointer to the hardware structure * @rid: recipe ID returned as response to AQ call */ -int ice_alloc_recipe(struct ice_hw *hw, u16 *rid) +static int +ice_alloc_legacy_shared_recipe(struct ice_hw *hw, u16 *rid) { struct ice_aqc_alloc_free_res_elem *sw_buf; u16 buf_len; @@ -3798,6 +3818,174 @@ int ice_alloc_recipe(struct ice_hw *hw, u16 *rid) return status; } +/** + * ice_alloc_subscribable_recipe - alloc shared recipe that can be subscribed to + * @hw: pointer to the hardware structure + * @rid: recipe ID returned as response to AQ call + */ +static enum ice_status +ice_alloc_subscribable_recipe(struct ice_hw *hw, u16 *rid) +{ + struct ice_aqc_alloc_free_res_elem *buf; + enum ice_status status; + u16 buf_len; + + buf_len = ice_struct_size(buf, elem, 1); + buf = (struct ice_aqc_alloc_free_res_elem *)ice_malloc(hw, buf_len); + if (!buf) + return ICE_ERR_NO_MEMORY; + + /* Prepare buffer to allocate resource */ + buf->num_elems = CPU_TO_LE16(1); + buf->res_type = CPU_TO_LE16((ICE_AQC_RES_TYPE_RECIPE << + ICE_AQC_RES_TYPE_S) | + ICE_AQC_RES_TYPE_FLAG_SUBSCRIBE_SHARED); + + status = ice_aq_alloc_free_res(hw, 1, buf, buf_len, + ice_aqc_opc_alloc_res, NULL); + + if (status) + goto exit; + + ice_memcpy(rid, buf->elem, sizeof(*buf->elem) * 1, + ICE_NONDMA_TO_NONDMA); + +exit: + ice_free(hw, buf); + return status; +} + +/** + * ice_alloc_recipe - add recipe resource + * @hw: pointer to the hardware structure + * @rid: recipe ID returned as response to AQ call + */ +enum ice_status ice_alloc_recipe(struct ice_hw *hw, u16 *rid) +{ + if (hw->subscribable_recipes_supported) + return ice_alloc_subscribable_recipe(hw, rid); + else + return ice_alloc_legacy_shared_recipe(hw, rid); +} + +/** + * ice_free_recipe_res - free recipe resource + * @hw: pointer to the hardware structure + * @rid: recipe ID to free + */ +static enum ice_status ice_free_recipe_res(struct ice_hw *hw, u16 rid) +{ + return ice_free_hw_res(hw, ICE_AQC_RES_TYPE_RECIPE, 1, &rid); +} + +/* + * ice_subscribe_recipe - subscribe to an existing recipe + * @hw: pointer to the hardware structure + * @rid: recipe ID to subscribe to + */ +static enum ice_status ice_subscribe_recipe(struct ice_hw *hw, u16 rid) +{ + struct ice_aqc_alloc_free_res_elem *buf; + enum ice_status status; + u16 buf_len; + + buf_len = ice_struct_size(buf, elem, 1); + buf = (struct ice_aqc_alloc_free_res_elem *)ice_malloc(hw, buf_len); + if (!buf) + return ICE_ERR_NO_MEMORY; + + /* Prepare buffer to allocate resource */ + buf->num_elems = CPU_TO_LE16(1); + buf->res_type = CPU_TO_LE16((ICE_AQC_RES_TYPE_RECIPE << + ICE_AQC_RES_TYPE_S) | + ICE_AQC_RES_TYPE_FLAG_SUBSCRIBE_SHARED | + ICE_AQC_RES_TYPE_FLAG_SUBSCRIBE_CTL); + + buf->elem[0].e.flu_resp = CPU_TO_LE16(rid); + + status = ice_aq_alloc_free_res(hw, 1, buf, buf_len, + ice_aqc_opc_alloc_res, NULL); + + ice_free(hw, buf); + return status; +} + +/** + * ice_subscribable_recp_shared - share an existing subscribable recipe + * @hw: pointer to the hardware structure + * @rid: recipe ID to subscribe to + */ +static void ice_subscribable_recp_shared(struct ice_hw *hw, u16 rid) +{ + ice_declare_bitmap(sub_bitmap, ICE_MAX_NUM_RECIPES); + struct ice_sw_recipe *recps; + u8 i, cnt; + + recps = hw->switch_info->recp_list; + ice_cp_bitmap(sub_bitmap, recps[rid].r_bitmap, ICE_MAX_NUM_RECIPES); + cnt = ice_bitmap_hweight(sub_bitmap, ICE_MAX_NUM_RECIPES); + for (i = 0; i < cnt; i++) { + u8 sub_rid; + + sub_rid = (u8)ice_find_first_bit(sub_bitmap, + ICE_MAX_NUM_RECIPES); + ice_subscribe_recipe(hw, sub_rid); + ice_clear_bit(sub_rid, sub_bitmap); + } +} + +/** + * ice_release_recipe_res - disassociate and free recipe resource + * @hw: pointer to the hardware structure + * @recp: the recipe struct resource to unassociate and free + */ +static enum ice_status ice_release_recipe_res(struct ice_hw *hw, + struct ice_sw_recipe *recp) +{ + ice_declare_bitmap(r_bitmap, ICE_MAX_NUM_RECIPES); + struct ice_switch_info *sw = hw->switch_info; + u8 num_recp, rid, num_prof, prof, i, j; + enum ice_status status = ICE_SUCCESS; + + num_recp = ice_bitmap_hweight(recp->r_bitmap, ICE_MAX_NUM_RECIPES); + for (i = 0; i < num_recp; i++) { + rid = (u8)ice_find_first_bit(recp->r_bitmap, + ICE_MAX_NUM_RECIPES); + num_prof = ice_bitmap_hweight(recipe_to_profile[rid], + ICE_MAX_NUM_PROFILES); + for (j = 0; j < num_prof; j++) { + prof = (u8)ice_find_first_bit(recipe_to_profile[rid], + ICE_MAX_NUM_PROFILES); + status = ice_aq_get_recipe_to_profile(hw, prof, + (u8 *)r_bitmap, + NULL); + if (status) + goto exit; + + ice_andnot_bitmap(r_bitmap, r_bitmap, + recp->r_bitmap, ICE_MAX_NUM_RECIPES); + ice_aq_map_recipe_to_profile(hw, prof, + (u8 *)r_bitmap, NULL); + + ice_clear_bit(rid, profile_to_recipe[prof]); + ice_clear_bit(prof, recipe_to_profile[rid]); + } + + status = ice_free_recipe_res(hw, rid); + if (status) + goto exit; + + sw->recp_list[rid].recp_created = false; + sw->recp_list[rid].adv_rule = false; + memset(&sw->recp_list[rid].lkup_exts, 0, + sizeof(struct ice_prot_lkup_ext)); + ice_clear_bit(rid, recp->r_bitmap); + } + +exit: + return status; +} + /* ice_init_port_info - Initialize port_info with switch configuration data * @pi: pointer to port_info * @vsi_port_num: VSI number or port number @@ -7121,11 +7309,15 @@ static struct ice_protocol_entry ice_prot_id_tbl[ICE_PROTOCOL_LAST] = { * ice_find_recp - find a recipe * @hw: pointer to the hardware structure * @lkup_exts: extension sequence to match + * @tun_type: tunnel type of switch filter + * @priority: priority of switch filter + * @is_add: flag of adding recipe * * Returns index of matching recipe, or ICE_MAX_NUM_RECIPES if not found. */ static u16 ice_find_recp(struct ice_hw *hw, struct ice_prot_lkup_ext *lkup_exts, - enum ice_sw_tunnel_type tun_type, u32 priority) + enum ice_sw_tunnel_type tun_type, u32 priority, + bool *is_add) { bool refresh_required = true; struct ice_sw_recipe *recp; @@ -7139,11 +7331,12 @@ static u16 ice_find_recp(struct ice_hw *hw, struct ice_prot_lkup_ext *lkup_exts, * entry update it in our SW bookkeeping and continue with the * matching. */ - if (!recp[i].recp_created) + if (hw->subscribable_recipes_supported) { if (ice_get_recp_frm_fw(hw, hw->switch_info->recp_list, i, - &refresh_required)) + &refresh_required, is_add)) continue; + } /* Skip inverse action recipes */ if (recp[i].root_buf && recp[i].root_buf->content.act_ctrl & @@ -8184,7 +8377,8 @@ ice_add_adv_recipe(struct ice_hw *hw, struct ice_adv_lkup_elem *lkups, struct ice_recp_grp_entry *r_tmp; struct ice_sw_fv_list_entry *tmp; struct ice_sw_recipe *rm; - u8 i; + u8 i, cnt, rid_tmp; + bool is_add = true; int status = ICE_SUCCESS; if (!ice_is_prof_rule(rinfo->tun_type) && !lkups_cnt) @@ -8287,10 +8481,15 @@ ice_add_adv_recipe(struct ice_hw *hw, struct ice_adv_lkup_elem *lkups, } /* Look for a recipe which matches our requested fv / mask list */ - *rid = ice_find_recp(hw, lkup_exts, rinfo->tun_type, rinfo->priority); - if (*rid < ICE_MAX_NUM_RECIPES) + *rid = ice_find_recp(hw, lkup_exts, rinfo->tun_type, + rinfo->priority, &is_add); + if (*rid < ICE_MAX_NUM_RECIPES) { /* Success if found a recipe that match the existing criteria */ + if (hw->subscribable_recipes_supported) + ice_subscribable_recp_shared(hw, *rid); + goto err_unroll; + } rm->tun_type = rinfo->tun_type; /* Recipe we need does not exist, add a recipe */ @@ -8308,22 +8507,34 @@ ice_add_adv_recipe(struct ice_hw *hw, struct ice_adv_lkup_elem *lkups, status = ice_aq_get_recipe_to_profile(hw, fvit->profile_id, (u8 *)r_bitmap, NULL); - if (status) - goto err_unroll; + if (status) { + if (hw->subscribable_recipes_supported) + goto err_free_recipe; + else + goto err_unroll; + } ice_or_bitmap(r_bitmap, r_bitmap, rm->r_bitmap, ICE_MAX_NUM_RECIPES); status = ice_acquire_change_lock(hw, ICE_RES_WRITE); - if (status) - goto err_unroll; + if (status) { + if (hw->subscribable_recipes_supported) + goto err_free_recipe; + else + goto err_unroll; + } status = ice_aq_map_recipe_to_profile(hw, fvit->profile_id, (u8 *)r_bitmap, NULL); ice_release_change_lock(hw); - if (status) - goto err_unroll; + if (status) { + if (hw->subscribable_recipes_supported) + goto err_free_recipe; + else + goto err_unroll; + } /* Update profile to recipe bitmap array */ ice_cp_bitmap(profile_to_recipe[fvit->profile_id], r_bitmap, @@ -8338,6 +8549,18 @@ ice_add_adv_recipe(struct ice_hw *hw, struct ice_adv_lkup_elem *lkups, *rid = rm->root_rid; ice_memcpy(&hw->switch_info->recp_list[*rid].lkup_exts, lkup_exts, sizeof(*lkup_exts), ICE_NONDMA_TO_NONDMA); + goto err_unroll; + +err_free_recipe: + cnt = ice_bitmap_hweight(rm->r_bitmap, ICE_MAX_NUM_RECIPES); + for (i = 0; i < cnt; i++) { + rid_tmp = (u8)ice_find_first_bit(rm->r_bitmap, + ICE_MAX_NUM_RECIPES); + if (hw->subscribable_recipes_supported) { + if (!ice_free_recipe_res(hw, rid_tmp)) + ice_clear_bit(rid_tmp, rm->r_bitmap); + } + } err_unroll: LIST_FOR_EACH_ENTRY_SAFE(r_entry, r_tmp, &rm->rg_list, ice_recp_grp_entry, l_entry) { @@ -9811,7 +10034,8 @@ ice_rem_adv_rule(struct ice_hw *hw, struct ice_adv_lkup_elem *lkups, if (status) return status; - rid = ice_find_recp(hw, &lkup_exts, rinfo->tun_type, rinfo->priority); + rid = ice_find_recp(hw, &lkup_exts, rinfo->tun_type, + rinfo->priority, &is_add); /* If did not find a recipe that match the existing criteria */ if (rid == ICE_MAX_NUM_RECIPES) return ICE_ERR_PARAM; @@ -9858,14 +10082,21 @@ ice_rem_adv_rule(struct ice_hw *hw, struct ice_adv_lkup_elem *lkups, ice_aqc_opc_remove_sw_rules, NULL); if (status == ICE_SUCCESS || status == ICE_ERR_DOES_NOT_EXIST) { struct ice_switch_info *sw = hw->switch_info; + struct ice_sw_recipe *r_list = sw->recp_list; ice_acquire_lock(rule_lock); LIST_DEL(&list_elem->list_entry); ice_free(hw, list_elem->lkups); ice_free(hw, list_elem); ice_release_lock(rule_lock); - if (LIST_EMPTY(&sw->recp_list[rid].filt_rules)) - sw->recp_list[rid].adv_rule = false; + if (LIST_EMPTY(&r_list[rid].filt_rules)) { + r_list[rid].adv_rule = false; + + /* All rules for this recipe are now removed */ + if (hw->subscribable_recipes_supported) + ice_release_recipe_res(hw, + &r_list[rid]); + } } ice_free(hw, s_rule); } diff --git a/drivers/net/ice/base/ice_switch.h b/drivers/net/ice/base/ice_switch.h index 184e30f226..939fa6df3c 100644 --- a/drivers/net/ice/base/ice_switch.h +++ b/drivers/net/ice/base/ice_switch.h @@ -565,6 +565,8 @@ int ice_aq_get_recipe_to_profile(struct ice_hw *hw, u32 profile_id, u8 *r_bitmap, struct ice_sq_cd *cd); +void ice_init_chk_subscribable_recipe_support(struct ice_hw *hw); + int ice_alloc_recipe(struct ice_hw *hw, u16 *recipe_id); int ice_add_adv_rule(struct ice_hw *hw, struct ice_adv_lkup_elem *lkups, diff --git a/drivers/net/ice/base/ice_type.h b/drivers/net/ice/base/ice_type.h index 907764d66b..79a6c1aa0f 100644 --- a/drivers/net/ice/base/ice_type.h +++ b/drivers/net/ice/base/ice_type.h @@ -1400,6 +1400,8 @@ struct ice_hw { ice_declare_bitmap(hw_ptype, ICE_FLOW_PTYPE_MAX); u8 dvm_ena; u16 io_expander_handle; + + bool subscribable_recipes_supported; }; /* Statistics collected by each port, VSI, VEB, and S-channel */ -- 2.43.0