diff options
Diffstat (limited to 'drivers/net/ethernet/intel/ice/ice_lib.c')
| -rw-r--r-- | drivers/net/ethernet/intel/ice/ice_lib.c | 400 | 
1 files changed, 381 insertions, 19 deletions
diff --git a/drivers/net/ethernet/intel/ice/ice_lib.c b/drivers/net/ethernet/intel/ice/ice_lib.c index e7449248fab4..1874c9f51a32 100644 --- a/drivers/net/ethernet/intel/ice/ice_lib.c +++ b/drivers/net/ethernet/intel/ice/ice_lib.c @@ -3,6 +3,7 @@  #include "ice.h"  #include "ice_base.h" +#include "ice_flow.h"  #include "ice_lib.h"  #include "ice_dcb_lib.h" @@ -493,7 +494,28 @@ bool ice_is_safe_mode(struct ice_pf *pf)  }  /** - * ice_rss_clean - Delete RSS related VSI structures that hold user inputs + * ice_vsi_clean_rss_flow_fld - Delete RSS configuration + * @vsi: the VSI being cleaned up + * + * This function deletes RSS input set for all flows that were configured + * for this VSI + */ +static void ice_vsi_clean_rss_flow_fld(struct ice_vsi *vsi) +{ +	struct ice_pf *pf = vsi->back; +	enum ice_status status; + +	if (ice_is_safe_mode(pf)) +		return; + +	status = ice_rem_vsi_rss_cfg(&pf->hw, vsi->idx); +	if (status) +		dev_dbg(ice_pf_to_dev(pf), "ice_rem_vsi_rss_cfg failed for vsi = %d, error = %d\n", +			vsi->vsi_num, status); +} + +/** + * ice_rss_clean - Delete RSS related VSI structures and configuration   * @vsi: the VSI being removed   */  static void ice_rss_clean(struct ice_vsi *vsi) @@ -507,6 +529,11 @@ static void ice_rss_clean(struct ice_vsi *vsi)  		devm_kfree(dev, vsi->rss_hkey_user);  	if (vsi->rss_lut_user)  		devm_kfree(dev, vsi->rss_lut_user); + +	ice_vsi_clean_rss_flow_fld(vsi); +	/* remove RSS replay list */ +	if (!ice_is_safe_mode(pf)) +		ice_rem_vsi_rss_list(&pf->hw, vsi->idx);  }  /** @@ -817,12 +844,23 @@ static int ice_vsi_init(struct ice_vsi *vsi, bool init_vsi)  		ctxt->info.valid_sections |=  			cpu_to_le16(ICE_AQ_VSI_PROP_RXQ_MAP_VALID); -	/* Enable MAC Antispoof with new VSI being initialized or updated */ -	if (vsi->type == ICE_VSI_VF && pf->vf[vsi->vf_id].spoofchk) { +	/* enable/disable MAC and VLAN anti-spoof when spoofchk is on/off +	 * respectively +	 */ +	if (vsi->type == ICE_VSI_VF) {  		ctxt->info.valid_sections |=  			cpu_to_le16(ICE_AQ_VSI_PROP_SECURITY_VALID); -		ctxt->info.sec_flags |= -			ICE_AQ_VSI_SEC_FLAG_ENA_MAC_ANTI_SPOOF; +		if (pf->vf[vsi->vf_id].spoofchk) { +			ctxt->info.sec_flags |= +				ICE_AQ_VSI_SEC_FLAG_ENA_MAC_ANTI_SPOOF | +				(ICE_AQ_VSI_SEC_TX_VLAN_PRUNE_ENA << +				 ICE_AQ_VSI_SEC_TX_PRUNE_ENA_S); +		} else { +			ctxt->info.sec_flags &= +				~(ICE_AQ_VSI_SEC_FLAG_ENA_MAC_ANTI_SPOOF | +				  (ICE_AQ_VSI_SEC_TX_VLAN_PRUNE_ENA << +				   ICE_AQ_VSI_SEC_TX_PRUNE_ENA_S)); +		}  	}  	/* Allow control frames out of main VSI */ @@ -1076,6 +1114,115 @@ ice_vsi_cfg_rss_exit:  }  /** + * ice_vsi_set_vf_rss_flow_fld - Sets VF VSI RSS input set for different flows + * @vsi: VSI to be configured + * + * This function will only be called during the VF VSI setup. Upon successful + * completion of package download, this function will configure default RSS + * input sets for VF VSI. + */ +static void ice_vsi_set_vf_rss_flow_fld(struct ice_vsi *vsi) +{ +	struct ice_pf *pf = vsi->back; +	enum ice_status status; +	struct device *dev; + +	dev = ice_pf_to_dev(pf); +	if (ice_is_safe_mode(pf)) { +		dev_dbg(dev, "Advanced RSS disabled. Package download failed, vsi num = %d\n", +			vsi->vsi_num); +		return; +	} + +	status = ice_add_avf_rss_cfg(&pf->hw, vsi->idx, ICE_DEFAULT_RSS_HENA); +	if (status) +		dev_dbg(dev, "ice_add_avf_rss_cfg failed for vsi = %d, error = %d\n", +			vsi->vsi_num, status); +} + +/** + * ice_vsi_set_rss_flow_fld - Sets RSS input set for different flows + * @vsi: VSI to be configured + * + * This function will only be called after successful download package call + * during initialization of PF. Since the downloaded package will erase the + * RSS section, this function will configure RSS input sets for different + * flow types. The last profile added has the highest priority, therefore 2 + * tuple profiles (i.e. IPv4 src/dst) are added before 4 tuple profiles + * (i.e. IPv4 src/dst TCP src/dst port). + */ +static void ice_vsi_set_rss_flow_fld(struct ice_vsi *vsi) +{ +	u16 vsi_handle = vsi->idx, vsi_num = vsi->vsi_num; +	struct ice_pf *pf = vsi->back; +	struct ice_hw *hw = &pf->hw; +	enum ice_status status; +	struct device *dev; + +	dev = ice_pf_to_dev(pf); +	if (ice_is_safe_mode(pf)) { +		dev_dbg(dev, "Advanced RSS disabled. Package download failed, vsi num = %d\n", +			vsi_num); +		return; +	} +	/* configure RSS for IPv4 with input set IP src/dst */ +	status = ice_add_rss_cfg(hw, vsi_handle, ICE_FLOW_HASH_IPV4, +				 ICE_FLOW_SEG_HDR_IPV4); +	if (status) +		dev_dbg(dev, "ice_add_rss_cfg failed for ipv4 flow, vsi = %d, error = %d\n", +			vsi_num, status); + +	/* configure RSS for IPv6 with input set IPv6 src/dst */ +	status = ice_add_rss_cfg(hw, vsi_handle, ICE_FLOW_HASH_IPV6, +				 ICE_FLOW_SEG_HDR_IPV6); +	if (status) +		dev_dbg(dev, "ice_add_rss_cfg failed for ipv6 flow, vsi = %d, error = %d\n", +			vsi_num, status); + +	/* configure RSS for tcp4 with input set IP src/dst, TCP src/dst */ +	status = ice_add_rss_cfg(hw, vsi_handle, ICE_HASH_TCP_IPV4, +				 ICE_FLOW_SEG_HDR_TCP | ICE_FLOW_SEG_HDR_IPV4); +	if (status) +		dev_dbg(dev, "ice_add_rss_cfg failed for tcp4 flow, vsi = %d, error = %d\n", +			vsi_num, status); + +	/* configure RSS for udp4 with input set IP src/dst, UDP src/dst */ +	status = ice_add_rss_cfg(hw, vsi_handle, ICE_HASH_UDP_IPV4, +				 ICE_FLOW_SEG_HDR_UDP | ICE_FLOW_SEG_HDR_IPV4); +	if (status) +		dev_dbg(dev, "ice_add_rss_cfg failed for udp4 flow, vsi = %d, error = %d\n", +			vsi_num, status); + +	/* configure RSS for sctp4 with input set IP src/dst */ +	status = ice_add_rss_cfg(hw, vsi_handle, ICE_FLOW_HASH_IPV4, +				 ICE_FLOW_SEG_HDR_SCTP | ICE_FLOW_SEG_HDR_IPV4); +	if (status) +		dev_dbg(dev, "ice_add_rss_cfg failed for sctp4 flow, vsi = %d, error = %d\n", +			vsi_num, status); + +	/* configure RSS for tcp6 with input set IPv6 src/dst, TCP src/dst */ +	status = ice_add_rss_cfg(hw, vsi_handle, ICE_HASH_TCP_IPV6, +				 ICE_FLOW_SEG_HDR_TCP | ICE_FLOW_SEG_HDR_IPV6); +	if (status) +		dev_dbg(dev, "ice_add_rss_cfg failed for tcp6 flow, vsi = %d, error = %d\n", +			vsi_num, status); + +	/* configure RSS for udp6 with input set IPv6 src/dst, UDP src/dst */ +	status = ice_add_rss_cfg(hw, vsi_handle, ICE_HASH_UDP_IPV6, +				 ICE_FLOW_SEG_HDR_UDP | ICE_FLOW_SEG_HDR_IPV6); +	if (status) +		dev_dbg(dev, "ice_add_rss_cfg failed for udp6 flow, vsi = %d, error = %d\n", +			vsi_num, status); + +	/* configure RSS for sctp6 with input set IPv6 src/dst */ +	status = ice_add_rss_cfg(hw, vsi_handle, ICE_FLOW_HASH_IPV6, +				 ICE_FLOW_SEG_HDR_SCTP | ICE_FLOW_SEG_HDR_IPV6); +	if (status) +		dev_dbg(dev, "ice_add_rss_cfg failed for sctp6 flow, vsi = %d, error = %d\n", +			vsi_num, status); +} + +/**   * ice_add_mac_to_list - Add a MAC address filter entry to the list   * @vsi: the VSI to be forwarded to   * @add_list: pointer to the list which contains MAC filter entries @@ -1636,22 +1783,14 @@ int ice_cfg_vlan_pruning(struct ice_vsi *vsi, bool ena, bool vlan_promisc)  	ctxt->info = vsi->info; -	if (ena) { -		ctxt->info.sec_flags |= -			ICE_AQ_VSI_SEC_TX_VLAN_PRUNE_ENA << -			ICE_AQ_VSI_SEC_TX_PRUNE_ENA_S; +	if (ena)  		ctxt->info.sw_flags2 |= ICE_AQ_VSI_SW_FLAG_RX_VLAN_PRUNE_ENA; -	} else { -		ctxt->info.sec_flags &= -			~(ICE_AQ_VSI_SEC_TX_VLAN_PRUNE_ENA << -			  ICE_AQ_VSI_SEC_TX_PRUNE_ENA_S); +	else  		ctxt->info.sw_flags2 &= ~ICE_AQ_VSI_SW_FLAG_RX_VLAN_PRUNE_ENA; -	}  	if (!vlan_promisc)  		ctxt->info.valid_sections = -			cpu_to_le16(ICE_AQ_VSI_PROP_SECURITY_VALID | -				    ICE_AQ_VSI_PROP_SW_VALID); +			cpu_to_le16(ICE_AQ_VSI_PROP_SW_VALID);  	status = ice_update_vsi(&pf->hw, vsi->idx, ctxt, NULL);  	if (status) { @@ -1661,7 +1800,6 @@ int ice_cfg_vlan_pruning(struct ice_vsi *vsi, bool ena, bool vlan_promisc)  		goto err_out;  	} -	vsi->info.sec_flags = ctxt->info.sec_flags;  	vsi->info.sw_flags2 = ctxt->info.sw_flags2;  	kfree(ctxt); @@ -1899,8 +2037,10 @@ ice_vsi_setup(struct ice_pf *pf, struct ice_port_info *pi,  		 * receive traffic on first queue. Hence no need to capture  		 * return value  		 */ -		if (test_bit(ICE_FLAG_RSS_ENA, pf->flags)) +		if (test_bit(ICE_FLAG_RSS_ENA, pf->flags)) {  			ice_vsi_cfg_rss_lut_key(vsi); +			ice_vsi_set_rss_flow_fld(vsi); +		}  		break;  	case ICE_VSI_VF:  		/* VF driver will take care of creating netdev for this type and @@ -1924,8 +2064,10 @@ ice_vsi_setup(struct ice_pf *pf, struct ice_port_info *pi,  		 * receive traffic on first queue. Hence no need to capture  		 * return value  		 */ -		if (test_bit(ICE_FLAG_RSS_ENA, pf->flags)) +		if (test_bit(ICE_FLAG_RSS_ENA, pf->flags)) {  			ice_vsi_cfg_rss_lut_key(vsi); +			ice_vsi_set_vf_rss_flow_fld(vsi); +		}  		break;  	case ICE_VSI_LB:  		ret = ice_vsi_alloc_rings(vsi); @@ -2402,6 +2544,97 @@ int ice_vsi_release(struct ice_vsi *vsi)  }  /** + * ice_vsi_rebuild_update_coalesce - set coalesce for a q_vector + * @q_vector: pointer to q_vector which is being updated + * @coalesce: pointer to array of struct with stored coalesce + * + * Set coalesce param in q_vector and update these parameters in HW. + */ +static void +ice_vsi_rebuild_update_coalesce(struct ice_q_vector *q_vector, +				struct ice_coalesce_stored *coalesce) +{ +	struct ice_ring_container *rx_rc = &q_vector->rx; +	struct ice_ring_container *tx_rc = &q_vector->tx; +	struct ice_hw *hw = &q_vector->vsi->back->hw; + +	tx_rc->itr_setting = coalesce->itr_tx; +	rx_rc->itr_setting = coalesce->itr_rx; + +	/* dynamic ITR values will be updated during Tx/Rx */ +	if (!ITR_IS_DYNAMIC(tx_rc->itr_setting)) +		wr32(hw, GLINT_ITR(tx_rc->itr_idx, q_vector->reg_idx), +		     ITR_REG_ALIGN(tx_rc->itr_setting) >> +		     ICE_ITR_GRAN_S); +	if (!ITR_IS_DYNAMIC(rx_rc->itr_setting)) +		wr32(hw, GLINT_ITR(rx_rc->itr_idx, q_vector->reg_idx), +		     ITR_REG_ALIGN(rx_rc->itr_setting) >> +		     ICE_ITR_GRAN_S); + +	q_vector->intrl = coalesce->intrl; +	wr32(hw, GLINT_RATE(q_vector->reg_idx), +	     ice_intrl_usec_to_reg(q_vector->intrl, hw->intrl_gran)); +} + +/** + * ice_vsi_rebuild_get_coalesce - get coalesce from all q_vectors + * @vsi: VSI connected with q_vectors + * @coalesce: array of struct with stored coalesce + * + * Returns array size. + */ +static int +ice_vsi_rebuild_get_coalesce(struct ice_vsi *vsi, +			     struct ice_coalesce_stored *coalesce) +{ +	int i; + +	ice_for_each_q_vector(vsi, i) { +		struct ice_q_vector *q_vector = vsi->q_vectors[i]; + +		coalesce[i].itr_tx = q_vector->tx.itr_setting; +		coalesce[i].itr_rx = q_vector->rx.itr_setting; +		coalesce[i].intrl = q_vector->intrl; +	} + +	return vsi->num_q_vectors; +} + +/** + * ice_vsi_rebuild_set_coalesce - set coalesce from earlier saved arrays + * @vsi: VSI connected with q_vectors + * @coalesce: pointer to array of struct with stored coalesce + * @size: size of coalesce array + * + * Before this function, ice_vsi_rebuild_get_coalesce should be called to save + * ITR params in arrays. If size is 0 or coalesce wasn't stored set coalesce + * to default value. + */ +static void +ice_vsi_rebuild_set_coalesce(struct ice_vsi *vsi, +			     struct ice_coalesce_stored *coalesce, int size) +{ +	int i; + +	if ((size && !coalesce) || !vsi) +		return; + +	for (i = 0; i < size && i < vsi->num_q_vectors; i++) +		ice_vsi_rebuild_update_coalesce(vsi->q_vectors[i], +						&coalesce[i]); + +	for (; i < vsi->num_q_vectors; i++) { +		struct ice_coalesce_stored coalesce_dflt = { +			.itr_tx = ICE_DFLT_TX_ITR, +			.itr_rx = ICE_DFLT_RX_ITR, +			.intrl = 0 +		}; +		ice_vsi_rebuild_update_coalesce(vsi->q_vectors[i], +						&coalesce_dflt); +	} +} + +/**   * ice_vsi_rebuild - Rebuild VSI after reset   * @vsi: VSI to be rebuild   * @init_vsi: is this an initialization or a reconfigure of the VSI @@ -2411,6 +2644,8 @@ int ice_vsi_release(struct ice_vsi *vsi)  int ice_vsi_rebuild(struct ice_vsi *vsi, bool init_vsi)  {  	u16 max_txqs[ICE_MAX_TRAFFIC_CLASS] = { 0 }; +	struct ice_coalesce_stored *coalesce; +	int prev_num_q_vectors = 0;  	struct ice_vf *vf = NULL;  	enum ice_status status;  	struct ice_pf *pf; @@ -2423,6 +2658,11 @@ int ice_vsi_rebuild(struct ice_vsi *vsi, bool init_vsi)  	if (vsi->type == ICE_VSI_VF)  		vf = &pf->vf[vsi->vf_id]; +	coalesce = kcalloc(vsi->num_q_vectors, +			   sizeof(struct ice_coalesce_stored), GFP_KERNEL); +	if (coalesce) +		prev_num_q_vectors = ice_vsi_rebuild_get_coalesce(vsi, +								  coalesce);  	ice_rm_vsi_lan_cfg(vsi->port_info, vsi->idx);  	ice_vsi_free_q_vectors(vsi); @@ -2535,6 +2775,9 @@ int ice_vsi_rebuild(struct ice_vsi *vsi, bool init_vsi)  			return ice_schedule_reset(pf, ICE_RESET_PFR);  		}  	} +	ice_vsi_rebuild_set_coalesce(vsi, coalesce, prev_num_q_vectors); +	kfree(coalesce); +  	return 0;  err_vectors: @@ -2549,6 +2792,7 @@ err_rings:  err_vsi:  	ice_vsi_clear(vsi);  	set_bit(__ICE_RESET_FAILED, pf->state); +	kfree(coalesce);  	return ret;  } @@ -2740,3 +2984,121 @@ cfg_mac_fltr_exit:  	ice_free_fltr_list(&vsi->back->pdev->dev, &tmp_add_list);  	return status;  } + +/** + * ice_is_dflt_vsi_in_use - check if the default forwarding VSI is being used + * @sw: switch to check if its default forwarding VSI is free + * + * Return true if the default forwarding VSI is already being used, else returns + * false signalling that it's available to use. + */ +bool ice_is_dflt_vsi_in_use(struct ice_sw *sw) +{ +	return (sw->dflt_vsi && sw->dflt_vsi_ena); +} + +/** + * ice_is_vsi_dflt_vsi - check if the VSI passed in is the default VSI + * @sw: switch for the default forwarding VSI to compare against + * @vsi: VSI to compare against default forwarding VSI + * + * If this VSI passed in is the default forwarding VSI then return true, else + * return false + */ +bool ice_is_vsi_dflt_vsi(struct ice_sw *sw, struct ice_vsi *vsi) +{ +	return (sw->dflt_vsi == vsi && sw->dflt_vsi_ena); +} + +/** + * ice_set_dflt_vsi - set the default forwarding VSI + * @sw: switch used to assign the default forwarding VSI + * @vsi: VSI getting set as the default forwarding VSI on the switch + * + * If the VSI passed in is already the default VSI and it's enabled just return + * success. + * + * If there is already a default VSI on the switch and it's enabled then return + * -EEXIST since there can only be one default VSI per switch. + * + *  Otherwise try to set the VSI passed in as the switch's default VSI and + *  return the result. + */ +int ice_set_dflt_vsi(struct ice_sw *sw, struct ice_vsi *vsi) +{ +	enum ice_status status; +	struct device *dev; + +	if (!sw || !vsi) +		return -EINVAL; + +	dev = ice_pf_to_dev(vsi->back); + +	/* the VSI passed in is already the default VSI */ +	if (ice_is_vsi_dflt_vsi(sw, vsi)) { +		dev_dbg(dev, "VSI %d passed in is already the default forwarding VSI, nothing to do\n", +			vsi->vsi_num); +		return 0; +	} + +	/* another VSI is already the default VSI for this switch */ +	if (ice_is_dflt_vsi_in_use(sw)) { +		dev_err(dev, +			"Default forwarding VSI %d already in use, disable it and try again\n", +			sw->dflt_vsi->vsi_num); +		return -EEXIST; +	} + +	status = ice_cfg_dflt_vsi(&vsi->back->hw, vsi->idx, true, ICE_FLTR_RX); +	if (status) { +		dev_err(dev, +			"Failed to set VSI %d as the default forwarding VSI, error %d\n", +			vsi->vsi_num, status); +		return -EIO; +	} + +	sw->dflt_vsi = vsi; +	sw->dflt_vsi_ena = true; + +	return 0; +} + +/** + * ice_clear_dflt_vsi - clear the default forwarding VSI + * @sw: switch used to clear the default VSI + * + * If the switch has no default VSI or it's not enabled then return error. + * + * Otherwise try to clear the default VSI and return the result. + */ +int ice_clear_dflt_vsi(struct ice_sw *sw) +{ +	struct ice_vsi *dflt_vsi; +	enum ice_status status; +	struct device *dev; + +	if (!sw) +		return -EINVAL; + +	dev = ice_pf_to_dev(sw->pf); + +	dflt_vsi = sw->dflt_vsi; + +	/* there is no default VSI configured */ +	if (!ice_is_dflt_vsi_in_use(sw)) +		return -ENODEV; + +	status = ice_cfg_dflt_vsi(&dflt_vsi->back->hw, dflt_vsi->idx, false, +				  ICE_FLTR_RX); +	if (status) { +		dev_err(dev, +			"Failed to clear the default forwarding VSI %d, error %d\n", +			dflt_vsi->vsi_num, status); +		return -EIO; +	} + +	sw->dflt_vsi = NULL; +	sw->dflt_vsi_ena = false; + +	return 0; +}  |