Commit 95ad92d6 authored by Steven Zou's avatar Steven Zou Committed by Tony Nguyen

ice: Add switch recipe reusing feature

New E810 firmware supports the corresponding functionality, so the driver
allows PFs to subscribe the same switch recipes. Then when the PF is done
with a switch recipes, the PF can ask firmware to free that switch recipe.

When users configure a rule to PFn into E810 switch component, if there is
no existing recipe matching this rule's pattern, the driver will request
firmware to allocate and return a new recipe resource for the rule by
calling ice_add_sw_recipe() and ice_alloc_recipe(). If there is an existing
recipe matching this rule's pattern with different key value, or this is a
same second rule to PFm into switch component, the driver checks out this
recipe by calling ice_find_recp(), the driver will tell firmware to share
using this same recipe resource by calling ice_subscribable_recp_shared()
and ice_subscribe_recipe().

When firmware detects that all subscribing PFs have freed the switch
recipe, firmware 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.
Reviewed-by: default avatarPrzemek Kitszel <przemyslaw.kitszel@intel.com>
Reviewed-by: default avatarAndrii Staikov <andrii.staikov@intel.com>
Reviewed-by: default avatarSimon Horman <horms@kernel.org>
Signed-off-by: default avatarSteven Zou <steven.zou@intel.com>
Tested-by: default avatarMayank Sharma <mayank.sharma@intel.com>
Signed-off-by: default avatarTony Nguyen <anthony.l.nguyen@intel.com>
parent 22118810
......@@ -264,6 +264,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
......
......@@ -1142,6 +1142,8 @@ int ice_init_hw(struct ice_hw *hw)
if (status)
goto err_unroll_fltr_mgmt_struct;
mutex_init(&hw->tnl_lock);
ice_init_chk_recipe_reuse_support(hw);
return 0;
err_unroll_fltr_mgmt_struct:
......
......@@ -2148,6 +2148,18 @@ ice_aq_get_recipe_to_profile(struct ice_hw *hw, u32 profile_id, u64 *r_assoc,
return status;
}
/**
* ice_init_chk_recipe_reuse_support - check if recipe reuse is supported
* @hw: pointer to the hardware structure
*/
void ice_init_chk_recipe_reuse_support(struct ice_hw *hw)
{
struct ice_nvm_info *nvm = &hw->flash.nvm;
hw->recp_reuse = (nvm->major == 0x4 && nvm->minor >= 0x30) ||
nvm->major > 0x4;
}
/**
* ice_alloc_recipe - add recipe resource
* @hw: pointer to the hardware structure
......@@ -2157,12 +2169,16 @@ int ice_alloc_recipe(struct ice_hw *hw, u16 *rid)
{
DEFINE_RAW_FLEX(struct ice_aqc_alloc_free_res_elem, sw_buf, elem, 1);
u16 buf_len = __struct_size(sw_buf);
u16 res_type;
int status;
sw_buf->num_elems = cpu_to_le16(1);
sw_buf->res_type = cpu_to_le16((ICE_AQC_RES_TYPE_RECIPE <<
ICE_AQC_RES_TYPE_S) |
ICE_AQC_RES_TYPE_FLAG_SHARED);
res_type = FIELD_PREP(ICE_AQC_RES_TYPE_M, ICE_AQC_RES_TYPE_RECIPE);
if (hw->recp_reuse)
res_type |= ICE_AQC_RES_TYPE_FLAG_SUBSCRIBE_SHARED;
else
res_type |= ICE_AQC_RES_TYPE_FLAG_SHARED;
sw_buf->res_type = cpu_to_le16(res_type);
status = ice_aq_alloc_free_res(hw, sw_buf, buf_len,
ice_aqc_opc_alloc_res);
if (!status)
......@@ -2171,6 +2187,70 @@ int ice_alloc_recipe(struct ice_hw *hw, u16 *rid)
return status;
}
/**
* ice_free_recipe_res - free recipe resource
* @hw: pointer to the hardware structure
* @rid: recipe ID to free
*
* Return: 0 on success, and others on error
*/
static int ice_free_recipe_res(struct ice_hw *hw, u16 rid)
{
return ice_free_hw_res(hw, ICE_AQC_RES_TYPE_RECIPE, 1, &rid);
}
/**
* ice_release_recipe_res - disassociate and free recipe resource
* @hw: pointer to the hardware structure
* @recp: the recipe struct resource to unassociate and free
*
* Return: 0 on success, and others on error
*/
static int ice_release_recipe_res(struct ice_hw *hw,
struct ice_sw_recipe *recp)
{
DECLARE_BITMAP(r_bitmap, ICE_MAX_NUM_RECIPES);
struct ice_switch_info *sw = hw->switch_info;
u64 recp_assoc;
u32 rid, prof;
int status;
for_each_set_bit(rid, recp->r_bitmap, ICE_MAX_NUM_RECIPES) {
for_each_set_bit(prof, recipe_to_profile[rid],
ICE_MAX_NUM_PROFILES) {
status = ice_aq_get_recipe_to_profile(hw, prof,
&recp_assoc,
NULL);
if (status)
return status;
bitmap_from_arr64(r_bitmap, &recp_assoc,
ICE_MAX_NUM_RECIPES);
bitmap_andnot(r_bitmap, r_bitmap, recp->r_bitmap,
ICE_MAX_NUM_RECIPES);
bitmap_to_arr64(&recp_assoc, r_bitmap,
ICE_MAX_NUM_RECIPES);
ice_aq_map_recipe_to_profile(hw, prof,
recp_assoc, NULL);
clear_bit(rid, profile_to_recipe[prof]);
clear_bit(prof, recipe_to_profile[rid]);
}
status = ice_free_recipe_res(hw, rid);
if (status)
return status;
sw->recp_list[rid].recp_created = false;
sw->recp_list[rid].adv_rule = false;
memset(&sw->recp_list[rid].lkup_exts, 0,
sizeof(sw->recp_list[rid].lkup_exts));
clear_bit(rid, recp->r_bitmap);
}
return 0;
}
/**
* ice_get_recp_to_prof_map - updates recipe to profile mapping
* @hw: pointer to hardware structure
......@@ -2220,6 +2300,7 @@ ice_collect_result_idx(struct ice_aqc_recipe_data_elem *buf,
* @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
......@@ -2227,7 +2308,7 @@ ice_collect_result_idx(struct ice_aqc_recipe_data_elem *buf,
*/
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)
{
DECLARE_BITMAP(result_bm, ICE_MAX_FV_WORDS);
struct ice_aqc_recipe_data_elem *tmp;
......@@ -2344,8 +2425,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->recp_reuse && is_add)
recps[idx].recp_created = true;
continue;
}
/* Only do the following for root recipes entries */
memcpy(recps[idx].r_bitmap, root_bufs.recipe_bitmap,
......@@ -2369,7 +2454,8 @@ ice_get_recp_frm_fw(struct ice_hw *hw, struct ice_sw_recipe *recps, u8 rid,
/* Copy result indexes */
bitmap_copy(recps[rid].res_idxs, result_bm, ICE_MAX_FV_WORDS);
recps[rid].recp_created = true;
if (is_add)
recps[rid].recp_created = true;
err_unroll:
kfree(tmp);
......@@ -4653,12 +4739,13 @@ static struct ice_protocol_entry ice_prot_id_tbl[ICE_PROTOCOL_LAST] = {
* @hw: pointer to the hardware structure
* @lkup_exts: extension sequence to match
* @rinfo: information regarding the rule e.g. priority and action info
* @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,
const struct ice_adv_rule_info *rinfo)
const struct ice_adv_rule_info *rinfo, bool is_add)
{
bool refresh_required = true;
struct ice_sw_recipe *recp;
......@@ -4672,11 +4759,12 @@ 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->recp_reuse) {
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 &
......@@ -5360,6 +5448,49 @@ ice_get_compat_fv_bitmap(struct ice_hw *hw, struct ice_adv_rule_info *rinfo,
ice_get_sw_fv_bitmap(hw, prof_type, bm);
}
/**
* ice_subscribe_recipe - subscribe to an existing recipe
* @hw: pointer to the hardware structure
* @rid: recipe ID to subscribe to
*
* Return: 0 on success, and others on error
*/
static int ice_subscribe_recipe(struct ice_hw *hw, u16 rid)
{
DEFINE_RAW_FLEX(struct ice_aqc_alloc_free_res_elem, sw_buf, elem, 1);
u16 buf_len = __struct_size(sw_buf);
u16 res_type;
int status;
/* Prepare buffer to allocate resource */
sw_buf->num_elems = cpu_to_le16(1);
res_type = FIELD_PREP(ICE_AQC_RES_TYPE_M, ICE_AQC_RES_TYPE_RECIPE) |
ICE_AQC_RES_TYPE_FLAG_SUBSCRIBE_SHARED |
ICE_AQC_RES_TYPE_FLAG_SUBSCRIBE_CTL;
sw_buf->res_type = cpu_to_le16(res_type);
sw_buf->elem[0].e.sw_resp = cpu_to_le16(rid);
status = ice_aq_alloc_free_res(hw, sw_buf, buf_len,
ice_aqc_opc_alloc_res);
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)
{
struct ice_sw_recipe *recps = hw->switch_info->recp_list;
u16 sub_rid;
for_each_set_bit(sub_rid, recps[rid].r_bitmap, ICE_MAX_NUM_RECIPES)
ice_subscribe_recipe(hw, sub_rid);
}
/**
* ice_add_adv_recipe - Add an advanced recipe that is not part of the default
* @hw: pointer to hardware structure
......@@ -5382,6 +5513,7 @@ ice_add_adv_recipe(struct ice_hw *hw, struct ice_adv_lkup_elem *lkups,
struct ice_sw_fv_list_entry *tmp;
struct ice_sw_recipe *rm;
int status = 0;
u16 rid_tmp;
u8 i;
if (!lkups_cnt)
......@@ -5459,10 +5591,14 @@ 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);
if (*rid < ICE_MAX_NUM_RECIPES)
*rid = ice_find_recp(hw, lkup_exts, rinfo, true);
if (*rid < ICE_MAX_NUM_RECIPES) {
/* Success if found a recipe that match the existing criteria */
if (hw->recp_reuse)
ice_subscribable_recp_shared(hw, *rid);
goto err_unroll;
}
rm->tun_type = rinfo->tun_type;
/* Recipe we need does not exist, add a recipe */
......@@ -5481,14 +5617,14 @@ 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,
&recp_assoc, NULL);
if (status)
goto err_unroll;
goto err_free_recipe;
bitmap_from_arr64(r_bitmap, &recp_assoc, ICE_MAX_NUM_RECIPES);
bitmap_or(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;
goto err_free_recipe;
bitmap_to_arr64(&recp_assoc, r_bitmap, ICE_MAX_NUM_RECIPES);
status = ice_aq_map_recipe_to_profile(hw, fvit->profile_id,
......@@ -5496,7 +5632,7 @@ ice_add_adv_recipe(struct ice_hw *hw, struct ice_adv_lkup_elem *lkups,
ice_release_change_lock(hw);
if (status)
goto err_unroll;
goto err_free_recipe;
/* Update profile to recipe bitmap array */
bitmap_copy(profile_to_recipe[fvit->profile_id], r_bitmap,
......@@ -5510,6 +5646,16 @@ ice_add_adv_recipe(struct ice_hw *hw, struct ice_adv_lkup_elem *lkups,
*rid = rm->root_rid;
memcpy(&hw->switch_info->recp_list[*rid].lkup_exts, lkup_exts,
sizeof(*lkup_exts));
goto err_unroll;
err_free_recipe:
if (hw->recp_reuse) {
for_each_set_bit(rid_tmp, rm->r_bitmap, ICE_MAX_NUM_RECIPES) {
if (!ice_free_recipe_res(hw, rid_tmp))
clear_bit(rid_tmp, rm->r_bitmap);
}
}
err_unroll:
list_for_each_entry_safe(r_entry, r_tmp, &rm->rg_list, l_entry) {
list_del(&r_entry->l_entry);
......@@ -6529,7 +6675,7 @@ ice_rem_adv_rule(struct ice_hw *hw, struct ice_adv_lkup_elem *lkups,
return -EIO;
}
rid = ice_find_recp(hw, &lkup_exts, rinfo);
rid = ice_find_recp(hw, &lkup_exts, rinfo, false);
/* If did not find a recipe that match the existing criteria */
if (rid == ICE_MAX_NUM_RECIPES)
return -EINVAL;
......@@ -6573,14 +6719,21 @@ ice_rem_adv_rule(struct ice_hw *hw, struct ice_adv_lkup_elem *lkups,
ice_aqc_opc_remove_sw_rules, NULL);
if (!status || status == -ENOENT) {
struct ice_switch_info *sw = hw->switch_info;
struct ice_sw_recipe *r_list = sw->recp_list;
mutex_lock(rule_lock);
list_del(&list_elem->list_entry);
devm_kfree(ice_hw_to_dev(hw), list_elem->lkups);
devm_kfree(ice_hw_to_dev(hw), list_elem);
mutex_unlock(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->recp_reuse)
ice_release_recipe_res(hw,
&r_list[rid]);
}
}
kfree(s_rule);
}
......
......@@ -432,5 +432,6 @@ ice_aq_get_recipe_to_profile(struct ice_hw *hw, u32 profile_id, u64 *r_assoc,
int
ice_aq_map_recipe_to_profile(struct ice_hw *hw, u32 profile_id, u64 r_assoc,
struct ice_sq_cd *cd);
void ice_init_chk_recipe_reuse_support(struct ice_hw *hw);
#endif /* _ICE_SWITCH_H_ */
......@@ -848,6 +848,8 @@ struct ice_hw {
u16 max_burst_size; /* driver sets this value */
u8 recp_reuse:1; /* indicates whether FW supports recipe reuse */
/* Tx Scheduler values */
u8 num_tx_sched_layers;
u8 num_tx_sched_phys_layers;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment