mirror of
https://github.com/torvalds/linux.git
synced 2026-05-27 00:22:00 +02:00
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: Przemek Kitszel <przemyslaw.kitszel@intel.com> Reviewed-by: Andrii Staikov <andrii.staikov@intel.com> Reviewed-by: Simon Horman <horms@kernel.org> Signed-off-by: Steven Zou <steven.zou@intel.com> Tested-by: Mayank Sharma <mayank.sharma@intel.com> Signed-off-by: Tony Nguyen <anthony.l.nguyen@intel.com>
This commit is contained in:
parent
22118810fc
commit
95ad92d687
|
|
@ -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;
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user