[v2,045/148] net/ice/base: implement switch recipe reuse feature

Message ID 74a3104269c42c046591d46ef7de8be4ddf8cd49.1718204528.git.anatoly.burakov@intel.com (mailing list archive)
State Superseded, archived
Delegated to: Bruce Richardson
Headers
Series Update net/ice base driver to latest upstream snapshot |

Checks

Context Check Description
ci/checkpatch warning coding style issues

Commit Message

Anatoly Burakov June 12, 2024, 3 p.m. UTC
From: Ian Stokes <ian.stokes@intel.com>

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 <steven.zou@intel.com>
Signed-off-by: Ian Stokes <ian.stokes@intel.com>
---
 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(-)
  

Comments

Bruce Richardson June 18, 2024, 2:53 p.m. UTC | #1
On Wed, Jun 12, 2024 at 04:00:39PM +0100, Anatoly Burakov wrote:
> From: Ian Stokes <ian.stokes@intel.com>
> 
> 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 <steven.zou@intel.com>
> Signed-off-by: Ian Stokes <ian.stokes@intel.com>
> ---
>  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(-)
> 

<snip> 

> +/**
> + * 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)

This use of ice_status here in this patch breaks the patch-by-patch builds.

error: conflicting types for 'ice_alloc_recipe' due to enum/integer mismatch;

Probably want to convert the ice_status's to ints globally here.

/Bruce
  

Patch

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 */