diff options
Diffstat (limited to 'drivers/net/ethernet/intel/ice/ice_switch.c')
| -rw-r--r-- | drivers/net/ethernet/intel/ice/ice_switch.c | 276 | 
1 files changed, 259 insertions, 17 deletions
diff --git a/drivers/net/ethernet/intel/ice/ice_switch.c b/drivers/net/ethernet/intel/ice/ice_switch.c index b4ea935e8300..94d6670d0901 100644 --- a/drivers/net/ethernet/intel/ice/ice_switch.c +++ b/drivers/net/ethernet/intel/ice/ice_switch.c @@ -42,6 +42,7 @@ enum {  	ICE_PKT_KMALLOC		= BIT(9),  	ICE_PKT_PPPOE		= BIT(10),  	ICE_PKT_L2TPV3		= BIT(11), +	ICE_PKT_PFCP		= BIT(12),  };  struct ice_dummy_pkt_offsets { @@ -1110,6 +1111,77 @@ ICE_DECLARE_PKT_TEMPLATE(ipv6_gtp) = {  	0x00, 0x00,  }; +ICE_DECLARE_PKT_OFFSETS(pfcp_session_ipv4) = { +	{ ICE_MAC_OFOS,		0 }, +	{ ICE_ETYPE_OL,		12 }, +	{ ICE_IPV4_OFOS,	14 }, +	{ ICE_UDP_ILOS,		34 }, +	{ ICE_PFCP,		42 }, +	{ ICE_PROTOCOL_LAST,	0 }, +}; + +ICE_DECLARE_PKT_TEMPLATE(pfcp_session_ipv4) = { +	0x00, 0x00, 0x00, 0x00, /* ICE_MAC_OFOS 0 */ +	0x00, 0x00, 0x00, 0x00, +	0x00, 0x00, 0x00, 0x00, + +	0x08, 0x00,		/* ICE_ETYPE_OL 12 */ + +	0x45, 0x00, 0x00, 0x2c, /* ICE_IPV4_OFOS 14 */ +	0x00, 0x01, 0x00, 0x00, +	0x00, 0x11, 0x00, 0x00, +	0x00, 0x00, 0x00, 0x00, +	0x00, 0x00, 0x00, 0x00, + +	0x00, 0x00, 0x22, 0x65, /* ICE_UDP_ILOS 34 */ +	0x00, 0x18, 0x00, 0x00, + +	0x21, 0x01, 0x00, 0x0c, /* ICE_PFCP 42 */ +	0x00, 0x00, 0x00, 0x00, +	0x00, 0x00, 0x00, 0x00, +	0x00, 0x00, 0x00, 0x00, + +	0x00, 0x00,		/* 2 bytes for 4 byte alignment */ +}; + +ICE_DECLARE_PKT_OFFSETS(pfcp_session_ipv6) = { +	{ ICE_MAC_OFOS,		0 }, +	{ ICE_ETYPE_OL,		12 }, +	{ ICE_IPV6_OFOS,	14 }, +	{ ICE_UDP_ILOS,		54 }, +	{ ICE_PFCP,		62 }, +	{ ICE_PROTOCOL_LAST,	0 }, +}; + +ICE_DECLARE_PKT_TEMPLATE(pfcp_session_ipv6) = { +	0x00, 0x00, 0x00, 0x00, /* ICE_MAC_OFOS 0 */ +	0x00, 0x00, 0x00, 0x00, +	0x00, 0x00, 0x00, 0x00, + +	0x86, 0xdd,		/* ICE_ETYPE_OL 12 */ + +	0x60, 0x00, 0x00, 0x00, /* ICE_IPV6_OFOS 14 */ +	0x00, 0x10, 0x11, 0x00, /* Next header UDP */ +	0x00, 0x00, 0x00, 0x00, +	0x00, 0x00, 0x00, 0x00, +	0x00, 0x00, 0x00, 0x00, +	0x00, 0x00, 0x00, 0x00, +	0x00, 0x00, 0x00, 0x00, +	0x00, 0x00, 0x00, 0x00, +	0x00, 0x00, 0x00, 0x00, +	0x00, 0x00, 0x00, 0x00, + +	0x00, 0x00, 0x22, 0x65, /* ICE_UDP_ILOS 54 */ +	0x00, 0x18, 0x00, 0x00, + +	0x21, 0x01, 0x00, 0x0c, /* ICE_PFCP 62 */ +	0x00, 0x00, 0x00, 0x00, +	0x00, 0x00, 0x00, 0x00, +	0x00, 0x00, 0x00, 0x00, + +	0x00, 0x00,		/* 2 bytes for 4 byte alignment */ +}; +  ICE_DECLARE_PKT_OFFSETS(pppoe_ipv4_tcp) = {  	{ ICE_MAC_OFOS,		0 },  	{ ICE_ETYPE_OL,		12 }, @@ -1343,6 +1415,8 @@ static const struct ice_dummy_pkt_profile ice_dummy_pkt_profiles[] = {  	ICE_PKT_PROFILE(ipv4_gtpu_ipv4_tcp, ICE_PKT_TUN_GTPU),  	ICE_PKT_PROFILE(ipv6_gtp, ICE_PKT_TUN_GTPC | ICE_PKT_OUTER_IPV6),  	ICE_PKT_PROFILE(ipv4_gtpu_ipv4, ICE_PKT_TUN_GTPC), +	ICE_PKT_PROFILE(pfcp_session_ipv6, ICE_PKT_PFCP | ICE_PKT_OUTER_IPV6), +	ICE_PKT_PROFILE(pfcp_session_ipv4, ICE_PKT_PFCP),  	ICE_PKT_PROFILE(pppoe_ipv6_udp, ICE_PKT_PPPOE | ICE_PKT_OUTER_IPV6 |  					ICE_PKT_INNER_UDP),  	ICE_PKT_PROFILE(pppoe_ipv6_tcp, ICE_PKT_PPPOE | ICE_PKT_OUTER_IPV6), @@ -2075,6 +2149,18 @@ ice_aq_get_recipe_to_profile(struct ice_hw *hw, u32 profile_id, u64 *r_assoc,  }  /** + * 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   * @rid: recipe ID returned as response to AQ call @@ -2083,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) @@ -2098,6 +2188,70 @@ int ice_alloc_recipe(struct ice_hw *hw, u16 *rid)  }  /** + * 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   * @@ -2146,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 @@ -2153,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; @@ -2270,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, @@ -2295,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); @@ -2446,6 +2606,9 @@ static void ice_fill_sw_info(struct ice_hw *hw, struct ice_fltr_info *fi)  			fi->lan_en = true;  		}  	} + +	if (fi->flag & ICE_FLTR_TX_ONLY) +		fi->lan_en = false;  }  /** @@ -3821,6 +3984,7 @@ ice_cfg_dflt_vsi(struct ice_port_info *pi, u16 vsi_handle, bool set,  	} else if (f_info.flag & ICE_FLTR_TX) {  		f_info.src_id = ICE_SRC_ID_VSI;  		f_info.src = hw_vsi_id; +		f_info.flag |= ICE_FLTR_TX_ONLY;  	}  	f_list_entry.fltr_info = f_info; @@ -4528,6 +4692,7 @@ static const struct ice_prot_ext_tbl_entry ice_prot_ext[ICE_PROTOCOL_LAST] = {  	ICE_PROTOCOL_ENTRY(ICE_NVGRE, 0, 2, 4, 6),  	ICE_PROTOCOL_ENTRY(ICE_GTP, 8, 10, 12, 14, 16, 18, 20, 22),  	ICE_PROTOCOL_ENTRY(ICE_GTP_NO_PAY, 8, 10, 12, 14), +	ICE_PROTOCOL_ENTRY(ICE_PFCP, 8, 10, 12, 14, 16, 18, 20, 22),  	ICE_PROTOCOL_ENTRY(ICE_PPPOE, 0, 2, 4, 6),  	ICE_PROTOCOL_ENTRY(ICE_L2TPV3, 0, 2, 4, 6, 8, 10),  	ICE_PROTOCOL_ENTRY(ICE_VLAN_EX, 2, 0), @@ -4561,6 +4726,7 @@ static struct ice_protocol_entry ice_prot_id_tbl[ICE_PROTOCOL_LAST] = {  	{ ICE_NVGRE,		ICE_GRE_OF_HW },  	{ ICE_GTP,		ICE_UDP_OF_HW },  	{ ICE_GTP_NO_PAY,	ICE_UDP_ILOS_HW }, +	{ ICE_PFCP,		ICE_UDP_ILOS_HW },  	{ ICE_PPPOE,		ICE_PPPOE_HW },  	{ ICE_L2TPV3,		ICE_L2TPV3_HW },  	{ ICE_VLAN_EX,          ICE_VLAN_OF_HW }, @@ -4573,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; @@ -4592,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 & @@ -5268,6 +5436,9 @@ ice_get_compat_fv_bitmap(struct ice_hw *hw, struct ice_adv_rule_info *rinfo,  	case ICE_SW_TUN_GTPC:  		prof_type = ICE_PROF_TUN_GTPC;  		break; +	case ICE_SW_TUN_PFCP: +		prof_type = ICE_PROF_TUN_PFCP; +		break;  	case ICE_SW_TUN_AND_NON_TUN:  	default:  		prof_type = ICE_PROF_ALL; @@ -5278,6 +5449,49 @@ ice_get_compat_fv_bitmap(struct ice_hw *hw, struct ice_adv_rule_info *rinfo,  }  /** + * 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   * @lkups: lookup elements or match criteria for the advanced recipe, one @@ -5299,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) @@ -5376,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 */ @@ -5398,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, @@ -5413,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, @@ -5427,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); @@ -5552,6 +5781,9 @@ ice_find_dummy_packet(struct ice_adv_lkup_elem *lkups, u16 lkups_cnt,  	case ICE_SW_TUN_VXLAN:  		match |= ICE_PKT_TUN_UDP;  		break; +	case ICE_SW_TUN_PFCP: +		match |= ICE_PKT_PFCP; +		break;  	default:  		break;  	} @@ -5692,6 +5924,9 @@ ice_fill_adv_dummy_packet(struct ice_adv_lkup_elem *lkups, u16 lkups_cnt,  		case ICE_GTP:  			len = sizeof(struct ice_udp_gtp_hdr);  			break; +		case ICE_PFCP: +			len = sizeof(struct ice_pfcp_hdr); +			break;  		case ICE_PPPOE:  			len = sizeof(struct ice_pppoe_hdr);  			break; @@ -6440,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; @@ -6484,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);  	}  |