diff options
Diffstat (limited to 'drivers/net/ethernet/intel/ice/ice_main.c')
| -rw-r--r-- | drivers/net/ethernet/intel/ice/ice_main.c | 127 | 
1 files changed, 90 insertions, 37 deletions
| diff --git a/drivers/net/ethernet/intel/ice/ice_main.c b/drivers/net/ethernet/intel/ice/ice_main.c index b588d7995631..d768925785ca 100644 --- a/drivers/net/ethernet/intel/ice/ice_main.c +++ b/drivers/net/ethernet/intel/ice/ice_main.c @@ -243,8 +243,7 @@ static int ice_add_mac_to_unsync_list(struct net_device *netdev, const u8 *addr)  static bool ice_vsi_fltr_changed(struct ice_vsi *vsi)  {  	return test_bit(ICE_VSI_UMAC_FLTR_CHANGED, vsi->state) || -	       test_bit(ICE_VSI_MMAC_FLTR_CHANGED, vsi->state) || -	       test_bit(ICE_VSI_VLAN_FLTR_CHANGED, vsi->state); +	       test_bit(ICE_VSI_MMAC_FLTR_CHANGED, vsi->state);  }  /** @@ -260,10 +259,15 @@ static int ice_set_promisc(struct ice_vsi *vsi, u8 promisc_m)  	if (vsi->type != ICE_VSI_PF)  		return 0; -	if (ice_vsi_has_non_zero_vlans(vsi)) -		status = ice_fltr_set_vlan_vsi_promisc(&vsi->back->hw, vsi, promisc_m); -	else -		status = ice_fltr_set_vsi_promisc(&vsi->back->hw, vsi->idx, promisc_m, 0); +	if (ice_vsi_has_non_zero_vlans(vsi)) { +		promisc_m |= (ICE_PROMISC_VLAN_RX | ICE_PROMISC_VLAN_TX); +		status = ice_fltr_set_vlan_vsi_promisc(&vsi->back->hw, vsi, +						       promisc_m); +	} else { +		status = ice_fltr_set_vsi_promisc(&vsi->back->hw, vsi->idx, +						  promisc_m, 0); +	} +  	return status;  } @@ -280,10 +284,15 @@ static int ice_clear_promisc(struct ice_vsi *vsi, u8 promisc_m)  	if (vsi->type != ICE_VSI_PF)  		return 0; -	if (ice_vsi_has_non_zero_vlans(vsi)) -		status = ice_fltr_clear_vlan_vsi_promisc(&vsi->back->hw, vsi, promisc_m); -	else -		status = ice_fltr_clear_vsi_promisc(&vsi->back->hw, vsi->idx, promisc_m, 0); +	if (ice_vsi_has_non_zero_vlans(vsi)) { +		promisc_m |= (ICE_PROMISC_VLAN_RX | ICE_PROMISC_VLAN_TX); +		status = ice_fltr_clear_vlan_vsi_promisc(&vsi->back->hw, vsi, +							 promisc_m); +	} else { +		status = ice_fltr_clear_vsi_promisc(&vsi->back->hw, vsi->idx, +						    promisc_m, 0); +	} +  	return status;  } @@ -302,7 +311,6 @@ static int ice_vsi_sync_fltr(struct ice_vsi *vsi)  	struct ice_pf *pf = vsi->back;  	struct ice_hw *hw = &pf->hw;  	u32 changed_flags = 0; -	u8 promisc_m;  	int err;  	if (!vsi->netdev) @@ -320,7 +328,6 @@ static int ice_vsi_sync_fltr(struct ice_vsi *vsi)  	if (ice_vsi_fltr_changed(vsi)) {  		clear_bit(ICE_VSI_UMAC_FLTR_CHANGED, vsi->state);  		clear_bit(ICE_VSI_MMAC_FLTR_CHANGED, vsi->state); -		clear_bit(ICE_VSI_VLAN_FLTR_CHANGED, vsi->state);  		/* grab the netdev's addr_list_lock */  		netif_addr_lock_bh(netdev); @@ -369,29 +376,15 @@ static int ice_vsi_sync_fltr(struct ice_vsi *vsi)  	/* check for changes in promiscuous modes */  	if (changed_flags & IFF_ALLMULTI) {  		if (vsi->current_netdev_flags & IFF_ALLMULTI) { -			if (ice_vsi_has_non_zero_vlans(vsi)) -				promisc_m = ICE_MCAST_VLAN_PROMISC_BITS; -			else -				promisc_m = ICE_MCAST_PROMISC_BITS; - -			err = ice_set_promisc(vsi, promisc_m); +			err = ice_set_promisc(vsi, ICE_MCAST_PROMISC_BITS);  			if (err) { -				netdev_err(netdev, "Error setting Multicast promiscuous mode on VSI %i\n", -					   vsi->vsi_num);  				vsi->current_netdev_flags &= ~IFF_ALLMULTI;  				goto out_promisc;  			}  		} else {  			/* !(vsi->current_netdev_flags & IFF_ALLMULTI) */ -			if (ice_vsi_has_non_zero_vlans(vsi)) -				promisc_m = ICE_MCAST_VLAN_PROMISC_BITS; -			else -				promisc_m = ICE_MCAST_PROMISC_BITS; - -			err = ice_clear_promisc(vsi, promisc_m); +			err = ice_clear_promisc(vsi, ICE_MCAST_PROMISC_BITS);  			if (err) { -				netdev_err(netdev, "Error clearing Multicast promiscuous mode on VSI %i\n", -					   vsi->vsi_num);  				vsi->current_netdev_flags |= IFF_ALLMULTI;  				goto out_promisc;  			} @@ -2569,7 +2562,7 @@ static int ice_xdp_alloc_setup_rings(struct ice_vsi *vsi)  		spin_lock_init(&xdp_ring->tx_lock);  		for (j = 0; j < xdp_ring->count; j++) {  			tx_desc = ICE_TX_DESC(xdp_ring, j); -			tx_desc->cmd_type_offset_bsz = cpu_to_le64(ICE_TX_DESC_DTYPE_DESC_DONE); +			tx_desc->cmd_type_offset_bsz = 0;  		}  	} @@ -2765,8 +2758,10 @@ free_qmap:  	ice_for_each_xdp_txq(vsi, i)  		if (vsi->xdp_rings[i]) { -			if (vsi->xdp_rings[i]->desc) +			if (vsi->xdp_rings[i]->desc) { +				synchronize_rcu();  				ice_free_tx_ring(vsi->xdp_rings[i]); +			}  			kfree_rcu(vsi->xdp_rings[i], rcu);  			vsi->xdp_rings[i] = NULL;  		} @@ -3488,6 +3483,20 @@ ice_vlan_rx_add_vid(struct net_device *netdev, __be16 proto, u16 vid)  	if (!vid)  		return 0; +	while (test_and_set_bit(ICE_CFG_BUSY, vsi->state)) +		usleep_range(1000, 2000); + +	/* Add multicast promisc rule for the VLAN ID to be added if +	 * all-multicast is currently enabled. +	 */ +	if (vsi->current_netdev_flags & IFF_ALLMULTI) { +		ret = ice_fltr_set_vsi_promisc(&vsi->back->hw, vsi->idx, +					       ICE_MCAST_VLAN_PROMISC_BITS, +					       vid); +		if (ret) +			goto finish; +	} +  	vlan_ops = ice_get_compat_vsi_vlan_ops(vsi);  	/* Add a switch rule for this VLAN ID so its corresponding VLAN tagged @@ -3495,8 +3504,23 @@ ice_vlan_rx_add_vid(struct net_device *netdev, __be16 proto, u16 vid)  	 */  	vlan = ICE_VLAN(be16_to_cpu(proto), vid, 0);  	ret = vlan_ops->add_vlan(vsi, &vlan); -	if (!ret) -		set_bit(ICE_VSI_VLAN_FLTR_CHANGED, vsi->state); +	if (ret) +		goto finish; + +	/* If all-multicast is currently enabled and this VLAN ID is only one +	 * besides VLAN-0 we have to update look-up type of multicast promisc +	 * rule for VLAN-0 from ICE_SW_LKUP_PROMISC to ICE_SW_LKUP_PROMISC_VLAN. +	 */ +	if ((vsi->current_netdev_flags & IFF_ALLMULTI) && +	    ice_vsi_num_non_zero_vlans(vsi) == 1) { +		ice_fltr_clear_vsi_promisc(&vsi->back->hw, vsi->idx, +					   ICE_MCAST_PROMISC_BITS, 0); +		ice_fltr_set_vsi_promisc(&vsi->back->hw, vsi->idx, +					 ICE_MCAST_VLAN_PROMISC_BITS, 0); +	} + +finish: +	clear_bit(ICE_CFG_BUSY, vsi->state);  	return ret;  } @@ -3522,6 +3546,9 @@ ice_vlan_rx_kill_vid(struct net_device *netdev, __be16 proto, u16 vid)  	if (!vid)  		return 0; +	while (test_and_set_bit(ICE_CFG_BUSY, vsi->state)) +		usleep_range(1000, 2000); +  	vlan_ops = ice_get_compat_vsi_vlan_ops(vsi);  	/* Make sure VLAN delete is successful before updating VLAN @@ -3530,10 +3557,33 @@ ice_vlan_rx_kill_vid(struct net_device *netdev, __be16 proto, u16 vid)  	vlan = ICE_VLAN(be16_to_cpu(proto), vid, 0);  	ret = vlan_ops->del_vlan(vsi, &vlan);  	if (ret) -		return ret; +		goto finish; -	set_bit(ICE_VSI_VLAN_FLTR_CHANGED, vsi->state); -	return 0; +	/* Remove multicast promisc rule for the removed VLAN ID if +	 * all-multicast is enabled. +	 */ +	if (vsi->current_netdev_flags & IFF_ALLMULTI) +		ice_fltr_clear_vsi_promisc(&vsi->back->hw, vsi->idx, +					   ICE_MCAST_VLAN_PROMISC_BITS, vid); + +	if (!ice_vsi_has_non_zero_vlans(vsi)) { +		/* Update look-up type of multicast promisc rule for VLAN 0 +		 * from ICE_SW_LKUP_PROMISC_VLAN to ICE_SW_LKUP_PROMISC when +		 * all-multicast is enabled and VLAN 0 is the only VLAN rule. +		 */ +		if (vsi->current_netdev_flags & IFF_ALLMULTI) { +			ice_fltr_clear_vsi_promisc(&vsi->back->hw, vsi->idx, +						   ICE_MCAST_VLAN_PROMISC_BITS, +						   0); +			ice_fltr_set_vsi_promisc(&vsi->back->hw, vsi->idx, +						 ICE_MCAST_PROMISC_BITS, 0); +		} +	} + +finish: +	clear_bit(ICE_CFG_BUSY, vsi->state); + +	return ret;  }  /** @@ -5475,16 +5525,19 @@ static int ice_set_mac_address(struct net_device *netdev, void *pi)  	/* Add filter for new MAC. If filter exists, return success */  	err = ice_fltr_add_mac(vsi, mac, ICE_FWD_TO_VSI); -	if (err == -EEXIST) +	if (err == -EEXIST) {  		/* Although this MAC filter is already present in hardware it's  		 * possible in some cases (e.g. bonding) that dev_addr was  		 * modified outside of the driver and needs to be restored back  		 * to this value.  		 */  		netdev_dbg(netdev, "filter for MAC %pM already exists\n", mac); -	else if (err) + +		return 0; +	} else if (err) {  		/* error if the new filter addition failed */  		err = -EADDRNOTAVAIL; +	}  err_update_filters:  	if (err) { |