diff options
Diffstat (limited to 'drivers/net/ethernet/intel/i40e/i40e_main.c')
| -rw-r--r-- | drivers/net/ethernet/intel/i40e/i40e_main.c | 1484 | 
1 files changed, 841 insertions, 643 deletions
diff --git a/drivers/net/ethernet/intel/i40e/i40e_main.c b/drivers/net/ethernet/intel/i40e/i40e_main.c index 31c97e3937a4..ad4cf639430e 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_main.c +++ b/drivers/net/ethernet/intel/i40e/i40e_main.c @@ -41,7 +41,7 @@ static const char i40e_driver_string[] =  #define DRV_VERSION_MAJOR 1  #define DRV_VERSION_MINOR 6 -#define DRV_VERSION_BUILD 16 +#define DRV_VERSION_BUILD 25  #define DRV_VERSION __stringify(DRV_VERSION_MAJOR) "." \  	     __stringify(DRV_VERSION_MINOR) "." \  	     __stringify(DRV_VERSION_BUILD)    DRV_KERN @@ -86,6 +86,8 @@ static const struct pci_device_id i40e_pci_tbl[] = {  	{PCI_VDEVICE(INTEL, I40E_DEV_ID_SFP_I_X722), 0},  	{PCI_VDEVICE(INTEL, I40E_DEV_ID_20G_KR2), 0},  	{PCI_VDEVICE(INTEL, I40E_DEV_ID_20G_KR2_A), 0}, +	{PCI_VDEVICE(INTEL, I40E_DEV_ID_25G_B), 0}, +	{PCI_VDEVICE(INTEL, I40E_DEV_ID_25G_SFP28), 0},  	/* required last entry */  	{0, }  }; @@ -93,8 +95,8 @@ MODULE_DEVICE_TABLE(pci, i40e_pci_tbl);  #define I40E_MAX_VF_COUNT 128  static int debug = -1; -module_param(debug, int, 0); -MODULE_PARM_DESC(debug, "Debug level (0=none,...,16=all)"); +module_param(debug, uint, 0); +MODULE_PARM_DESC(debug, "Debug level (0=none,...,16=all), Debug mask (0x8XXXXXXX)");  MODULE_AUTHOR("Intel Corporation, <[email protected]>");  MODULE_DESCRIPTION("Intel(R) Ethernet Connection XL710 Network Driver"); @@ -286,8 +288,7 @@ struct i40e_vsi *i40e_find_vsi_from_id(struct i40e_pf *pf, u16 id)  void i40e_service_event_schedule(struct i40e_pf *pf)  {  	if (!test_bit(__I40E_DOWN, &pf->state) && -	    !test_bit(__I40E_RESET_RECOVERY_PENDING, &pf->state) && -	    !test_and_set_bit(__I40E_SERVICE_SCHED, &pf->state)) +	    !test_bit(__I40E_RESET_RECOVERY_PENDING, &pf->state))  		queue_work(i40e_wq, &pf->service_task);  } @@ -1145,25 +1146,22 @@ void i40e_update_stats(struct i40e_vsi *vsi)   * @vsi: the VSI to be searched   * @macaddr: the MAC address   * @vlan: the vlan - * @is_vf: make sure its a VF filter, else doesn't matter - * @is_netdev: make sure its a netdev filter, else doesn't matter   *   * Returns ptr to the filter object or NULL   **/  static struct i40e_mac_filter *i40e_find_filter(struct i40e_vsi *vsi, -						u8 *macaddr, s16 vlan, -						bool is_vf, bool is_netdev) +						const u8 *macaddr, s16 vlan)  {  	struct i40e_mac_filter *f; +	u64 key;  	if (!vsi || !macaddr)  		return NULL; -	list_for_each_entry(f, &vsi->mac_filter_list, list) { +	key = i40e_addr_to_hkey(macaddr); +	hash_for_each_possible(vsi->mac_filter_hash, f, hlist, key) {  		if ((ether_addr_equal(macaddr, f->macaddr)) && -		    (vlan == f->vlan)    && -		    (!is_vf || f->is_vf) && -		    (!is_netdev || f->is_netdev)) +		    (vlan == f->vlan))  			return f;  	}  	return NULL; @@ -1173,24 +1171,21 @@ static struct i40e_mac_filter *i40e_find_filter(struct i40e_vsi *vsi,   * i40e_find_mac - Find a mac addr in the macvlan filters list   * @vsi: the VSI to be searched   * @macaddr: the MAC address we are searching for - * @is_vf: make sure its a VF filter, else doesn't matter - * @is_netdev: make sure its a netdev filter, else doesn't matter   *   * Returns the first filter with the provided MAC address or NULL if   * MAC address was not found   **/ -struct i40e_mac_filter *i40e_find_mac(struct i40e_vsi *vsi, u8 *macaddr, -				      bool is_vf, bool is_netdev) +struct i40e_mac_filter *i40e_find_mac(struct i40e_vsi *vsi, const u8 *macaddr)  {  	struct i40e_mac_filter *f; +	u64 key;  	if (!vsi || !macaddr)  		return NULL; -	list_for_each_entry(f, &vsi->mac_filter_list, list) { -		if ((ether_addr_equal(macaddr, f->macaddr)) && -		    (!is_vf || f->is_vf) && -		    (!is_netdev || f->is_netdev)) +	key = i40e_addr_to_hkey(macaddr); +	hash_for_each_possible(vsi->mac_filter_hash, f, hlist, key) { +		if ((ether_addr_equal(macaddr, f->macaddr)))  			return f;  	}  	return NULL; @@ -1204,86 +1199,132 @@ struct i40e_mac_filter *i40e_find_mac(struct i40e_vsi *vsi, u8 *macaddr,   **/  bool i40e_is_vsi_in_vlan(struct i40e_vsi *vsi)  { -	struct i40e_mac_filter *f; +	/* If we have a PVID, always operate in VLAN mode */ +	if (vsi->info.pvid) +		return true; -	/* Only -1 for all the filters denotes not in vlan mode -	 * so we have to go through all the list in order to make sure +	/* We need to operate in VLAN mode whenever we have any filters with +	 * a VLAN other than I40E_VLAN_ALL. We could check the table each +	 * time, incurring search cost repeatedly. However, we can notice two +	 * things: +	 * +	 * 1) the only place where we can gain a VLAN filter is in +	 *    i40e_add_filter. +	 * +	 * 2) the only place where filters are actually removed is in +	 *    i40e_sync_filters_subtask. +	 * +	 * Thus, we can simply use a boolean value, has_vlan_filters which we +	 * will set to true when we add a VLAN filter in i40e_add_filter. Then +	 * we have to perform the full search after deleting filters in +	 * i40e_sync_filters_subtask, but we already have to search +	 * filters here and can perform the check at the same time. This +	 * results in avoiding embedding a loop for VLAN mode inside another +	 * loop over all the filters, and should maintain correctness as noted +	 * above.  	 */ -	list_for_each_entry(f, &vsi->mac_filter_list, list) { -		if (f->vlan >= 0 || vsi->info.pvid) -			return true; -	} - -	return false; +	return vsi->has_vlan_filter;  }  /** - * i40e_put_mac_in_vlan - Make macvlan filters from macaddrs and vlans - * @vsi: the VSI to be searched - * @macaddr: the mac address to be filtered - * @is_vf: true if it is a VF - * @is_netdev: true if it is a netdev + * i40e_correct_mac_vlan_filters - Correct non-VLAN filters if necessary + * @vsi: the VSI to configure + * @tmp_add_list: list of filters ready to be added + * @tmp_del_list: list of filters ready to be deleted + * @vlan_filters: the number of active VLAN filters   * - * Goes through all the macvlan filters and adds a - * macvlan filter for each unique vlan that already exists + * Update VLAN=0 and VLAN=-1 (I40E_VLAN_ANY) filters properly so that they + * behave as expected. If we have any active VLAN filters remaining or about + * to be added then we need to update non-VLAN filters to be marked as VLAN=0 + * so that they only match against untagged traffic. If we no longer have any + * active VLAN filters, we need to make all non-VLAN filters marked as VLAN=-1 + * so that they match against both tagged and untagged traffic. In this way, + * we ensure that we correctly receive the desired traffic. This ensures that + * when we have an active VLAN we will receive only untagged traffic and + * traffic matching active VLANs. If we have no active VLANs then we will + * operate in non-VLAN mode and receive all traffic, tagged or untagged.   * - * Returns first filter found on success, else NULL - **/ -struct i40e_mac_filter *i40e_put_mac_in_vlan(struct i40e_vsi *vsi, u8 *macaddr, -					     bool is_vf, bool is_netdev) + * Finally, in a similar fashion, this function also corrects filters when + * there is an active PVID assigned to this VSI. + * + * In case of memory allocation failure return -ENOMEM. Otherwise, return 0. + * + * This function is only expected to be called from within + * i40e_sync_vsi_filters. + * + * NOTE: This function expects to be called while under the + * mac_filter_hash_lock + */ +static int i40e_correct_mac_vlan_filters(struct i40e_vsi *vsi, +					 struct hlist_head *tmp_add_list, +					 struct hlist_head *tmp_del_list, +					 int vlan_filters)  { -	struct i40e_mac_filter *f; +	struct i40e_mac_filter *f, *add_head; +	struct hlist_node *h; +	int bkt, new_vlan; -	list_for_each_entry(f, &vsi->mac_filter_list, list) { -		if (vsi->info.pvid) -			f->vlan = le16_to_cpu(vsi->info.pvid); -		if (!i40e_find_filter(vsi, macaddr, f->vlan, -				      is_vf, is_netdev)) { -			if (!i40e_add_filter(vsi, macaddr, f->vlan, -					     is_vf, is_netdev)) -				return NULL; -		} -	} +	/* To determine if a particular filter needs to be replaced we +	 * have the three following conditions: +	 * +	 * a) if we have a PVID assigned, then all filters which are +	 *    not marked as VLAN=PVID must be replaced with filters that +	 *    are. +	 * b) otherwise, if we have any active VLANS, all filters +	 *    which are marked as VLAN=-1 must be replaced with +	 *    filters marked as VLAN=0 +	 * c) finally, if we do not have any active VLANS, all filters +	 *    which are marked as VLAN=0 must be replaced with filters +	 *    marked as VLAN=-1 +	 */ -	return list_first_entry_or_null(&vsi->mac_filter_list, -					struct i40e_mac_filter, list); -} +	/* Update the filters about to be added in place */ +	hlist_for_each_entry(f, tmp_add_list, hlist) { +		if (vsi->info.pvid && f->vlan != vsi->info.pvid) +			f->vlan = vsi->info.pvid; +		else if (vlan_filters && f->vlan == I40E_VLAN_ANY) +			f->vlan = 0; +		else if (!vlan_filters && f->vlan == 0) +			f->vlan = I40E_VLAN_ANY; +	} + +	/* Update the remaining active filters */ +	hash_for_each_safe(vsi->mac_filter_hash, bkt, h, f, hlist) { +		/* Combine the checks for whether a filter needs to be changed +		 * and then determine the new VLAN inside the if block, in +		 * order to avoid duplicating code for adding the new filter +		 * then deleting the old filter. +		 */ +		if ((vsi->info.pvid && f->vlan != vsi->info.pvid) || +		    (vlan_filters && f->vlan == I40E_VLAN_ANY) || +		    (!vlan_filters && f->vlan == 0)) { +			/* Determine the new vlan we will be adding */ +			if (vsi->info.pvid) +				new_vlan = vsi->info.pvid; +			else if (vlan_filters) +				new_vlan = 0; +			else +				new_vlan = I40E_VLAN_ANY; -/** - * i40e_del_mac_all_vlan - Remove a MAC filter from all VLANS - * @vsi: the VSI to be searched - * @macaddr: the mac address to be removed - * @is_vf: true if it is a VF - * @is_netdev: true if it is a netdev - * - * Removes a given MAC address from a VSI, regardless of VLAN - * - * Returns 0 for success, or error - **/ -int i40e_del_mac_all_vlan(struct i40e_vsi *vsi, u8 *macaddr, -			  bool is_vf, bool is_netdev) -{ -	struct i40e_mac_filter *f = NULL; -	int changed = 0; +			/* Create the new filter */ +			add_head = i40e_add_filter(vsi, f->macaddr, new_vlan); +			if (!add_head) +				return -ENOMEM; -	WARN(!spin_is_locked(&vsi->mac_filter_list_lock), -	     "Missing mac_filter_list_lock\n"); -	list_for_each_entry(f, &vsi->mac_filter_list, list) { -		if ((ether_addr_equal(macaddr, f->macaddr)) && -		    (is_vf == f->is_vf) && -		    (is_netdev == f->is_netdev)) { -			f->counter--; -			changed = 1; -			if (f->counter == 0) -				f->state = I40E_FILTER_REMOVE; +			/* Put the replacement filter into the add list */ +			hash_del(&add_head->hlist); +			hlist_add_head(&add_head->hlist, tmp_add_list); + +			/* Put the original filter into the delete list */ +			f->state = I40E_FILTER_REMOVE; +			hash_del(&f->hlist); +			hlist_add_head(&f->hlist, tmp_del_list);  		}  	} -	if (changed) { -		vsi->flags |= I40E_VSI_FLAG_FILTER_CHANGED; -		vsi->back->flags |= I40E_FLAG_FILTER_SYNC; -		return 0; -	} -	return -ENOENT; + +	vsi->has_vlan_filter = !!vlan_filters; + +	return 0;  }  /** @@ -1324,36 +1365,32 @@ static void i40e_rm_default_mac_filter(struct i40e_vsi *vsi, u8 *macaddr)   * @vsi: the VSI to be searched   * @macaddr: the MAC address   * @vlan: the vlan - * @is_vf: make sure its a VF filter, else doesn't matter - * @is_netdev: make sure its a netdev filter, else doesn't matter   *   * Returns ptr to the filter object or NULL when no memory available.   * - * NOTE: This function is expected to be called with mac_filter_list_lock + * NOTE: This function is expected to be called with mac_filter_hash_lock   * being held.   **/  struct i40e_mac_filter *i40e_add_filter(struct i40e_vsi *vsi, -					u8 *macaddr, s16 vlan, -					bool is_vf, bool is_netdev) +					const u8 *macaddr, s16 vlan)  {  	struct i40e_mac_filter *f; -	int changed = false; +	u64 key;  	if (!vsi || !macaddr)  		return NULL; -	/* Do not allow broadcast filter to be added since broadcast filter -	 * is added as part of add VSI for any newly created VSI except -	 * FDIR VSI -	 */ -	if (is_broadcast_ether_addr(macaddr)) -		return NULL; - -	f = i40e_find_filter(vsi, macaddr, vlan, is_vf, is_netdev); +	f = i40e_find_filter(vsi, macaddr, vlan);  	if (!f) {  		f = kzalloc(sizeof(*f), GFP_ATOMIC);  		if (!f) -			goto add_filter_out; +			return NULL; + +		/* Update the boolean indicating if we need to function in +		 * VLAN mode. +		 */ +		if (vlan >= 0) +			vsi->has_vlan_filter = true;  		ether_addr_copy(f->macaddr, macaddr);  		f->vlan = vlan; @@ -1365,100 +1402,148 @@ struct i40e_mac_filter *i40e_add_filter(struct i40e_vsi *vsi,  			f->state = I40E_FILTER_FAILED;  		else  			f->state = I40E_FILTER_NEW; -		changed = true; -		INIT_LIST_HEAD(&f->list); -		list_add_tail(&f->list, &vsi->mac_filter_list); -	} +		INIT_HLIST_NODE(&f->hlist); -	/* increment counter and add a new flag if needed */ -	if (is_vf) { -		if (!f->is_vf) { -			f->is_vf = true; -			f->counter++; -		} -	} else if (is_netdev) { -		if (!f->is_netdev) { -			f->is_netdev = true; -			f->counter++; -		} -	} else { -		f->counter++; -	} +		key = i40e_addr_to_hkey(macaddr); +		hash_add(vsi->mac_filter_hash, &f->hlist, key); -	if (changed) {  		vsi->flags |= I40E_VSI_FLAG_FILTER_CHANGED;  		vsi->back->flags |= I40E_FLAG_FILTER_SYNC;  	} -add_filter_out: +	/* If we're asked to add a filter that has been marked for removal, it +	 * is safe to simply restore it to active state. __i40e_del_filter +	 * will have simply deleted any filters which were previously marked +	 * NEW or FAILED, so if it is currently marked REMOVE it must have +	 * previously been ACTIVE. Since we haven't yet run the sync filters +	 * task, just restore this filter to the ACTIVE state so that the +	 * sync task leaves it in place +	 */ +	if (f->state == I40E_FILTER_REMOVE) +		f->state = I40E_FILTER_ACTIVE; +  	return f;  }  /** - * i40e_del_filter - Remove a mac/vlan filter from the VSI + * __i40e_del_filter - Remove a specific filter from the VSI + * @vsi: VSI to remove from + * @f: the filter to remove from the list + * + * This function should be called instead of i40e_del_filter only if you know + * the exact filter you will remove already, such as via i40e_find_filter or + * i40e_find_mac. + * + * NOTE: This function is expected to be called with mac_filter_hash_lock + * being held. + * ANOTHER NOTE: This function MUST be called from within the context of + * the "safe" variants of any list iterators, e.g. list_for_each_entry_safe() + * instead of list_for_each_entry(). + **/ +static void __i40e_del_filter(struct i40e_vsi *vsi, struct i40e_mac_filter *f) +{ +	if (!f) +		return; + +	if ((f->state == I40E_FILTER_FAILED) || +	    (f->state == I40E_FILTER_NEW)) { +		/* this one never got added by the FW. Just remove it, +		 * no need to sync anything. +		 */ +		hash_del(&f->hlist); +		kfree(f); +	} else { +		f->state = I40E_FILTER_REMOVE; +		vsi->flags |= I40E_VSI_FLAG_FILTER_CHANGED; +		vsi->back->flags |= I40E_FLAG_FILTER_SYNC; +	} +} + +/** + * i40e_del_filter - Remove a MAC/VLAN filter from the VSI   * @vsi: the VSI to be searched   * @macaddr: the MAC address - * @vlan: the vlan - * @is_vf: make sure it's a VF filter, else doesn't matter - * @is_netdev: make sure it's a netdev filter, else doesn't matter + * @vlan: the VLAN   * - * NOTE: This function is expected to be called with mac_filter_list_lock + * NOTE: This function is expected to be called with mac_filter_hash_lock   * being held.   * ANOTHER NOTE: This function MUST be called from within the context of   * the "safe" variants of any list iterators, e.g. list_for_each_entry_safe()   * instead of list_for_each_entry().   **/ -void i40e_del_filter(struct i40e_vsi *vsi, -		     u8 *macaddr, s16 vlan, -		     bool is_vf, bool is_netdev) +void i40e_del_filter(struct i40e_vsi *vsi, const u8 *macaddr, s16 vlan)  {  	struct i40e_mac_filter *f;  	if (!vsi || !macaddr)  		return; -	f = i40e_find_filter(vsi, macaddr, vlan, is_vf, is_netdev); -	if (!f || f->counter == 0) -		return; +	f = i40e_find_filter(vsi, macaddr, vlan); +	__i40e_del_filter(vsi, f); +} -	if (is_vf) { -		if (f->is_vf) { -			f->is_vf = false; -			f->counter--; -		} -	} else if (is_netdev) { -		if (f->is_netdev) { -			f->is_netdev = false; -			f->counter--; -		} -	} else { -		/* make sure we don't remove a filter in use by VF or netdev */ -		int min_f = 0; +/** + * i40e_put_mac_in_vlan - Make macvlan filters from macaddrs and vlans + * @vsi: the VSI to be searched + * @macaddr: the mac address to be filtered + * + * Goes through all the macvlan filters and adds a macvlan filter for each + * unique vlan that already exists. If a PVID has been assigned, instead only + * add the macaddr to that VLAN. + * + * Returns last filter added on success, else NULL + **/ +struct i40e_mac_filter *i40e_put_mac_in_vlan(struct i40e_vsi *vsi, +					     const u8 *macaddr) +{ +	struct i40e_mac_filter *f, *add = NULL; +	struct hlist_node *h; +	int bkt; -		min_f += (f->is_vf ? 1 : 0); -		min_f += (f->is_netdev ? 1 : 0); +	if (vsi->info.pvid) +		return i40e_add_filter(vsi, macaddr, +				       le16_to_cpu(vsi->info.pvid)); -		if (f->counter > min_f) -			f->counter--; +	hash_for_each_safe(vsi->mac_filter_hash, bkt, h, f, hlist) { +		if (f->state == I40E_FILTER_REMOVE) +			continue; +		add = i40e_add_filter(vsi, macaddr, f->vlan); +		if (!add) +			return NULL;  	} -	/* counter == 0 tells sync_filters_subtask to -	 * remove the filter from the firmware's list -	 */ -	if (f->counter == 0) { -		if ((f->state == I40E_FILTER_FAILED) || -		    (f->state == I40E_FILTER_NEW)) { -			/* this one never got added by the FW. Just remove it, -			 * no need to sync anything. -			 */ -			list_del(&f->list); -			kfree(f); -		} else { -			f->state = I40E_FILTER_REMOVE; -			vsi->flags |= I40E_VSI_FLAG_FILTER_CHANGED; -			vsi->back->flags |= I40E_FLAG_FILTER_SYNC; +	return add; +} + +/** + * i40e_del_mac_all_vlan - Remove a MAC filter from all VLANS + * @vsi: the VSI to be searched + * @macaddr: the mac address to be removed + * + * Removes a given MAC address from a VSI, regardless of VLAN + * + * Returns 0 for success, or error + **/ +int i40e_del_mac_all_vlan(struct i40e_vsi *vsi, const u8 *macaddr) +{ +	struct i40e_mac_filter *f; +	struct hlist_node *h; +	bool found = false; +	int bkt; + +	WARN(!spin_is_locked(&vsi->mac_filter_hash_lock), +	     "Missing mac_filter_hash_lock\n"); +	hash_for_each_safe(vsi->mac_filter_hash, bkt, h, f, hlist) { +		if (ether_addr_equal(macaddr, f->macaddr)) { +			__i40e_del_filter(vsi, f); +			found = true;  		}  	} + +	if (found) +		return 0; +	else +		return -ENOENT;  }  /** @@ -1499,10 +1584,10 @@ static int i40e_set_mac(struct net_device *netdev, void *p)  	else  		netdev_info(netdev, "set new mac address %pM\n", addr->sa_data); -	spin_lock_bh(&vsi->mac_filter_list_lock); -	i40e_del_mac_all_vlan(vsi, netdev->dev_addr, false, true); -	i40e_put_mac_in_vlan(vsi, addr->sa_data, false, true); -	spin_unlock_bh(&vsi->mac_filter_list_lock); +	spin_lock_bh(&vsi->mac_filter_hash_lock); +	i40e_del_mac_all_vlan(vsi, netdev->dev_addr); +	i40e_put_mac_in_vlan(vsi, addr->sa_data); +	spin_unlock_bh(&vsi->mac_filter_hash_lock);  	ether_addr_copy(netdev->dev_addr, addr->sa_data);  	if (vsi->type == I40E_VSI_MAIN) {  		i40e_status ret; @@ -1666,6 +1751,52 @@ static void i40e_vsi_setup_queue_map(struct i40e_vsi *vsi,  }  /** + * i40e_addr_sync - Callback for dev_(mc|uc)_sync to add address + * @netdev: the netdevice + * @addr: address to add + * + * Called by __dev_(mc|uc)_sync when an address needs to be added. We call + * __dev_(uc|mc)_sync from .set_rx_mode and guarantee to hold the hash lock. + */ +static int i40e_addr_sync(struct net_device *netdev, const u8 *addr) +{ +	struct i40e_netdev_priv *np = netdev_priv(netdev); +	struct i40e_vsi *vsi = np->vsi; +	struct i40e_mac_filter *f; + +	if (i40e_is_vsi_in_vlan(vsi)) +		f = i40e_put_mac_in_vlan(vsi, addr); +	else +		f = i40e_add_filter(vsi, addr, I40E_VLAN_ANY); + +	if (f) +		return 0; +	else +		return -ENOMEM; +} + +/** + * i40e_addr_unsync - Callback for dev_(mc|uc)_sync to remove address + * @netdev: the netdevice + * @addr: address to add + * + * Called by __dev_(mc|uc)_sync when an address needs to be removed. We call + * __dev_(uc|mc)_sync from .set_rx_mode and guarantee to hold the hash lock. + */ +static int i40e_addr_unsync(struct net_device *netdev, const u8 *addr) +{ +	struct i40e_netdev_priv *np = netdev_priv(netdev); +	struct i40e_vsi *vsi = np->vsi; + +	if (i40e_is_vsi_in_vlan(vsi)) +		i40e_del_mac_all_vlan(vsi, addr); +	else +		i40e_del_filter(vsi, addr, I40E_VLAN_ANY); + +	return 0; +} + +/**   * i40e_set_rx_mode - NDO callback to set the netdev filters   * @netdev: network interface device structure   **/ @@ -1676,62 +1807,14 @@ static void i40e_set_rx_mode(struct net_device *netdev)  #endif  {  	struct i40e_netdev_priv *np = netdev_priv(netdev); -	struct i40e_mac_filter *f, *ftmp;  	struct i40e_vsi *vsi = np->vsi; -	struct netdev_hw_addr *uca; -	struct netdev_hw_addr *mca; -	struct netdev_hw_addr *ha; - -	spin_lock_bh(&vsi->mac_filter_list_lock); - -	/* add addr if not already in the filter list */ -	netdev_for_each_uc_addr(uca, netdev) { -		if (!i40e_find_mac(vsi, uca->addr, false, true)) { -			if (i40e_is_vsi_in_vlan(vsi)) -				i40e_put_mac_in_vlan(vsi, uca->addr, -						     false, true); -			else -				i40e_add_filter(vsi, uca->addr, I40E_VLAN_ANY, -						false, true); -		} -	} -	netdev_for_each_mc_addr(mca, netdev) { -		if (!i40e_find_mac(vsi, mca->addr, false, true)) { -			if (i40e_is_vsi_in_vlan(vsi)) -				i40e_put_mac_in_vlan(vsi, mca->addr, -						     false, true); -			else -				i40e_add_filter(vsi, mca->addr, I40E_VLAN_ANY, -						false, true); -		} -	} - -	/* remove filter if not in netdev list */ -	list_for_each_entry_safe(f, ftmp, &vsi->mac_filter_list, list) { - -		if (!f->is_netdev) -			continue; +	spin_lock_bh(&vsi->mac_filter_hash_lock); -		netdev_for_each_mc_addr(mca, netdev) -			if (ether_addr_equal(mca->addr, f->macaddr)) -				goto bottom_of_search_loop; +	__dev_uc_sync(netdev, i40e_addr_sync, i40e_addr_unsync); +	__dev_mc_sync(netdev, i40e_addr_sync, i40e_addr_unsync); -		netdev_for_each_uc_addr(uca, netdev) -			if (ether_addr_equal(uca->addr, f->macaddr)) -				goto bottom_of_search_loop; - -		for_each_dev_addr(netdev, ha) -			if (ether_addr_equal(ha->addr, f->macaddr)) -				goto bottom_of_search_loop; - -		/* f->macaddr wasn't found in uc, mc, or ha list so delete it */ -		i40e_del_filter(vsi, f->macaddr, I40E_VLAN_ANY, false, true); - -bottom_of_search_loop: -		continue; -	} -	spin_unlock_bh(&vsi->mac_filter_list_lock); +	spin_unlock_bh(&vsi->mac_filter_hash_lock);  	/* check for other flag changes */  	if (vsi->current_netdev_flags != vsi->netdev->flags) { @@ -1746,21 +1829,26 @@ bottom_of_search_loop:  }  /** - * i40e_undo_del_filter_entries - Undo the changes made to MAC filter entries - * @vsi: pointer to vsi struct + * i40e_undo_filter_entries - Undo the changes made to MAC filter entries + * @vsi: Pointer to VSI struct   * @from: Pointer to list which contains MAC filter entries - changes to   *        those entries needs to be undone.   * - * MAC filter entries from list were slated to be removed from device. + * MAC filter entries from list were slated to be sent to firmware, either for + * addition or deletion.   **/ -static void i40e_undo_del_filter_entries(struct i40e_vsi *vsi, -					 struct list_head *from) +static void i40e_undo_filter_entries(struct i40e_vsi *vsi, +				     struct hlist_head *from)  { -	struct i40e_mac_filter *f, *ftmp; +	struct i40e_mac_filter *f; +	struct hlist_node *h; + +	hlist_for_each_entry_safe(f, h, from, hlist) { +		u64 key = i40e_addr_to_hkey(f->macaddr); -	list_for_each_entry_safe(f, ftmp, from, list) {  		/* Move the element back into MAC filter list*/ -		list_move_tail(&f->list, &vsi->mac_filter_list); +		hlist_del(&f->hlist); +		hash_add(vsi->mac_filter_hash, &f->hlist, key);  	}  } @@ -1770,7 +1858,6 @@ static void i40e_undo_del_filter_entries(struct i40e_vsi *vsi,   * @count: Number of filters added   * @add_list: return data from fw   * @head: pointer to first filter in current batch - * @aq_err: status from fw   *   * MAC filter entries from list were slated to be added to device. Returns   * number of successful filters. Note that 0 does NOT mean success! @@ -1778,45 +1865,146 @@ static void i40e_undo_del_filter_entries(struct i40e_vsi *vsi,  static int  i40e_update_filter_state(int count,  			 struct i40e_aqc_add_macvlan_element_data *add_list, -			 struct i40e_mac_filter *add_head, int aq_err) +			 struct i40e_mac_filter *add_head)  {  	int retval = 0;  	int i; - -	if (!aq_err) { -		retval = count; -		/* Everything's good, mark all filters active. */ -		for (i = 0; i < count ; i++) { -			add_head->state = I40E_FILTER_ACTIVE; -			add_head = list_next_entry(add_head, list); -		} -	} else if (aq_err == I40E_AQ_RC_ENOSPC) { -		/* Device ran out of filter space. Check the return value -		 * for each filter to see which ones are active. +	for (i = 0; i < count; i++) { +		/* Always check status of each filter. We don't need to check +		 * the firmware return status because we pre-set the filter +		 * status to I40E_AQC_MM_ERR_NO_RES when sending the filter +		 * request to the adminq. Thus, if it no longer matches then +		 * we know the filter is active.  		 */ -		for (i = 0; i < count ; i++) { -			if (add_list[i].match_method == -			    I40E_AQC_MM_ERR_NO_RES) { -				add_head->state = I40E_FILTER_FAILED; -			} else { -				add_head->state = I40E_FILTER_ACTIVE; -				retval++; -			} -			add_head = list_next_entry(add_head, list); -		} -	} else { -		/* Some other horrible thing happened, fail all filters */ -		retval = 0; -		for (i = 0; i < count ; i++) { +		if (add_list[i].match_method == I40E_AQC_MM_ERR_NO_RES) {  			add_head->state = I40E_FILTER_FAILED; -			add_head = list_next_entry(add_head, list); +		} else { +			add_head->state = I40E_FILTER_ACTIVE; +			retval++;  		} + +		add_head = hlist_entry(add_head->hlist.next, +				       typeof(struct i40e_mac_filter), +				       hlist);  	} +  	return retval;  }  /** + * i40e_aqc_del_filters - Request firmware to delete a set of filters + * @vsi: ptr to the VSI + * @vsi_name: name to display in messages + * @list: the list of filters to send to firmware + * @num_del: the number of filters to delete + * @retval: Set to -EIO on failure to delete + * + * Send a request to firmware via AdminQ to delete a set of filters. Uses + * *retval instead of a return value so that success does not force ret_val to + * be set to 0. This ensures that a sequence of calls to this function + * preserve the previous value of *retval on successful delete. + */ +static +void i40e_aqc_del_filters(struct i40e_vsi *vsi, const char *vsi_name, +			  struct i40e_aqc_remove_macvlan_element_data *list, +			  int num_del, int *retval) +{ +	struct i40e_hw *hw = &vsi->back->hw; +	i40e_status aq_ret; +	int aq_err; + +	aq_ret = i40e_aq_remove_macvlan(hw, vsi->seid, list, num_del, NULL); +	aq_err = hw->aq.asq_last_status; + +	/* Explicitly ignore and do not report when firmware returns ENOENT */ +	if (aq_ret && !(aq_err == I40E_AQ_RC_ENOENT)) { +		*retval = -EIO; +		dev_info(&vsi->back->pdev->dev, +			 "ignoring delete macvlan error on %s, err %s, aq_err %s\n", +			 vsi_name, i40e_stat_str(hw, aq_ret), +			 i40e_aq_str(hw, aq_err)); +	} +} + +/** + * i40e_aqc_add_filters - Request firmware to add a set of filters + * @vsi: ptr to the VSI + * @vsi_name: name to display in messages + * @list: the list of filters to send to firmware + * @add_head: Position in the add hlist + * @num_add: the number of filters to add + * @promisc_change: set to true on exit if promiscuous mode was forced on + * + * Send a request to firmware via AdminQ to add a chunk of filters. Will set + * promisc_changed to true if the firmware has run out of space for more + * filters. + */ +static +void i40e_aqc_add_filters(struct i40e_vsi *vsi, const char *vsi_name, +			  struct i40e_aqc_add_macvlan_element_data *list, +			  struct i40e_mac_filter *add_head, +			  int num_add, bool *promisc_changed) +{ +	struct i40e_hw *hw = &vsi->back->hw; +	int aq_err, fcnt; + +	i40e_aq_add_macvlan(hw, vsi->seid, list, num_add, NULL); +	aq_err = hw->aq.asq_last_status; +	fcnt = i40e_update_filter_state(num_add, list, add_head); + +	if (fcnt != num_add) { +		*promisc_changed = true; +		set_bit(__I40E_FILTER_OVERFLOW_PROMISC, &vsi->state); +		dev_warn(&vsi->back->pdev->dev, +			 "Error %s adding RX filters on %s, promiscuous mode forced on\n", +			 i40e_aq_str(hw, aq_err), +			 vsi_name); +	} +} + +/** + * i40e_aqc_broadcast_filter - Set promiscuous broadcast flags + * @vsi: pointer to the VSI + * @f: filter data + * + * This function sets or clears the promiscuous broadcast flags for VLAN + * filters in order to properly receive broadcast frames. Assumes that only + * broadcast filters are passed. + **/ +static +void i40e_aqc_broadcast_filter(struct i40e_vsi *vsi, const char *vsi_name, +			       struct i40e_mac_filter *f) +{ +	bool enable = f->state == I40E_FILTER_NEW; +	struct i40e_hw *hw = &vsi->back->hw; +	i40e_status aq_ret; + +	if (f->vlan == I40E_VLAN_ANY) { +		aq_ret = i40e_aq_set_vsi_broadcast(hw, +						   vsi->seid, +						   enable, +						   NULL); +	} else { +		aq_ret = i40e_aq_set_vsi_bc_promisc_on_vlan(hw, +							    vsi->seid, +							    enable, +							    f->vlan, +							    NULL); +	} + +	if (aq_ret) { +		dev_warn(&vsi->back->pdev->dev, +			 "Error %s setting broadcast promiscuous mode on %s\n", +			 i40e_aq_str(hw, hw->aq.asq_last_status), +			 vsi_name); +		f->state = I40E_FILTER_FAILED; +	} else if (enable) { +		f->state = I40E_FILTER_ACTIVE; +	} +} + +/**   * i40e_sync_vsi_filters - Update the VSI filter list to the HW   * @vsi: ptr to the VSI   * @@ -1826,22 +2014,24 @@ i40e_update_filter_state(int count,   **/  int i40e_sync_vsi_filters(struct i40e_vsi *vsi)  { -	struct i40e_mac_filter *f, *ftmp, *add_head = NULL; -	struct list_head tmp_add_list, tmp_del_list; +	struct hlist_head tmp_add_list, tmp_del_list; +	struct i40e_mac_filter *f, *add_head = NULL;  	struct i40e_hw *hw = &vsi->back->hw; +	unsigned int failed_filters = 0; +	unsigned int vlan_filters = 0;  	bool promisc_changed = false;  	char vsi_name[16] = "PF";  	int filter_list_len = 0; -	u32 changed_flags = 0;  	i40e_status aq_ret = 0; -	int retval = 0; +	u32 changed_flags = 0; +	struct hlist_node *h;  	struct i40e_pf *pf;  	int num_add = 0;  	int num_del = 0; -	int aq_err = 0; +	int retval = 0;  	u16 cmd_flags;  	int list_size; -	int fcnt; +	int bkt;  	/* empty array typed pointers, kcalloc later */  	struct i40e_aqc_add_macvlan_element_data *add_list; @@ -1856,8 +2046,8 @@ int i40e_sync_vsi_filters(struct i40e_vsi *vsi)  		vsi->current_netdev_flags = vsi->netdev->flags;  	} -	INIT_LIST_HEAD(&tmp_add_list); -	INIT_LIST_HEAD(&tmp_del_list); +	INIT_HLIST_HEAD(&tmp_add_list); +	INIT_HLIST_HEAD(&tmp_del_list);  	if (vsi->type == I40E_VSI_SRIOV)  		snprintf(vsi_name, sizeof(vsi_name) - 1, "VF %d", vsi->vf_id); @@ -1867,43 +2057,64 @@ int i40e_sync_vsi_filters(struct i40e_vsi *vsi)  	if (vsi->flags & I40E_VSI_FLAG_FILTER_CHANGED) {  		vsi->flags &= ~I40E_VSI_FLAG_FILTER_CHANGED; -		spin_lock_bh(&vsi->mac_filter_list_lock); +		spin_lock_bh(&vsi->mac_filter_hash_lock);  		/* Create a list of filters to delete. */ -		list_for_each_entry_safe(f, ftmp, &vsi->mac_filter_list, list) { +		hash_for_each_safe(vsi->mac_filter_hash, bkt, h, f, hlist) {  			if (f->state == I40E_FILTER_REMOVE) { -				WARN_ON(f->counter != 0);  				/* Move the element into temporary del_list */ -				list_move_tail(&f->list, &tmp_del_list); -				vsi->active_filters--; +				hash_del(&f->hlist); +				hlist_add_head(&f->hlist, &tmp_del_list); + +				/* Avoid counting removed filters */ +				continue;  			}  			if (f->state == I40E_FILTER_NEW) { -				WARN_ON(f->counter == 0); -				/* Move the element into temporary add_list */ -				list_move_tail(&f->list, &tmp_add_list); +				hash_del(&f->hlist); +				hlist_add_head(&f->hlist, &tmp_add_list);  			} + +			/* Count the number of active (current and new) VLAN +			 * filters we have now. Does not count filters which +			 * are marked for deletion. +			 */ +			if (f->vlan > 0) +				vlan_filters++;  		} -		spin_unlock_bh(&vsi->mac_filter_list_lock); + +		retval = i40e_correct_mac_vlan_filters(vsi, +						       &tmp_add_list, +						       &tmp_del_list, +						       vlan_filters); +		if (retval) +			goto err_no_memory_locked; + +		spin_unlock_bh(&vsi->mac_filter_hash_lock);  	}  	/* Now process 'del_list' outside the lock */ -	if (!list_empty(&tmp_del_list)) { +	if (!hlist_empty(&tmp_del_list)) {  		filter_list_len = hw->aq.asq_buf_size /  			    sizeof(struct i40e_aqc_remove_macvlan_element_data);  		list_size = filter_list_len *  			    sizeof(struct i40e_aqc_remove_macvlan_element_data);  		del_list = kzalloc(list_size, GFP_ATOMIC); -		if (!del_list) { -			/* Undo VSI's MAC filter entry element updates */ -			spin_lock_bh(&vsi->mac_filter_list_lock); -			i40e_undo_del_filter_entries(vsi, &tmp_del_list); -			spin_unlock_bh(&vsi->mac_filter_list_lock); -			retval = -ENOMEM; -			goto out; -		} +		if (!del_list) +			goto err_no_memory; -		list_for_each_entry_safe(f, ftmp, &tmp_del_list, list) { +		hlist_for_each_entry_safe(f, h, &tmp_del_list, hlist) {  			cmd_flags = 0; +			/* handle broadcast filters by updating the broadcast +			 * promiscuous flag instead of deleting a MAC filter. +			 */ +			if (is_broadcast_ether_addr(f->macaddr)) { +				i40e_aqc_broadcast_filter(vsi, vsi_name, f); + +				hlist_del(&f->hlist); +				kfree(f); +				continue; +			} +  			/* add to delete list */  			ether_addr_copy(del_list[num_del].mac_addr, f->macaddr);  			if (f->vlan == I40E_VLAN_ANY) { @@ -1920,73 +2131,57 @@ int i40e_sync_vsi_filters(struct i40e_vsi *vsi)  			/* flush a full buffer */  			if (num_del == filter_list_len) { -				aq_ret = i40e_aq_remove_macvlan(hw, vsi->seid, -								del_list, -								num_del, NULL); -				aq_err = hw->aq.asq_last_status; -				num_del = 0; +				i40e_aqc_del_filters(vsi, vsi_name, del_list, +						     num_del, &retval);  				memset(del_list, 0, list_size); - -				/* Explicitly ignore and do not report when -				 * firmware returns ENOENT. -				 */ -				if (aq_ret && !(aq_err == I40E_AQ_RC_ENOENT)) { -					retval = -EIO; -					dev_info(&pf->pdev->dev, -						 "ignoring delete macvlan error on %s, err %s, aq_err %s\n", -						 vsi_name, -						 i40e_stat_str(hw, aq_ret), -						 i40e_aq_str(hw, aq_err)); -				} +				num_del = 0;  			}  			/* Release memory for MAC filter entries which were  			 * synced up with HW.  			 */ -			list_del(&f->list); +			hlist_del(&f->hlist);  			kfree(f);  		}  		if (num_del) { -			aq_ret = i40e_aq_remove_macvlan(hw, vsi->seid, del_list, -							num_del, NULL); -			aq_err = hw->aq.asq_last_status; -			num_del = 0; - -			/* Explicitly ignore and do not report when firmware -			 * returns ENOENT. -			 */ -			if (aq_ret && !(aq_err == I40E_AQ_RC_ENOENT)) { -				retval = -EIO; -				dev_info(&pf->pdev->dev, -					 "ignoring delete macvlan error on %s, err %s aq_err %s\n", -					 vsi_name, -					 i40e_stat_str(hw, aq_ret), -					 i40e_aq_str(hw, aq_err)); -			} +			i40e_aqc_del_filters(vsi, vsi_name, del_list, +					     num_del, &retval);  		}  		kfree(del_list);  		del_list = NULL;  	} -	if (!list_empty(&tmp_add_list)) { +	if (!hlist_empty(&tmp_add_list)) {  		/* Do all the adds now. */  		filter_list_len = hw->aq.asq_buf_size /  			       sizeof(struct i40e_aqc_add_macvlan_element_data);  		list_size = filter_list_len *  			       sizeof(struct i40e_aqc_add_macvlan_element_data);  		add_list = kzalloc(list_size, GFP_ATOMIC); -		if (!add_list) { -			retval = -ENOMEM; -			goto out; -		} +		if (!add_list) +			goto err_no_memory; +  		num_add = 0; -		list_for_each_entry(f, &tmp_add_list, list) { +		hlist_for_each_entry_safe(f, h, &tmp_add_list, hlist) {  			if (test_bit(__I40E_FILTER_OVERFLOW_PROMISC,  				     &vsi->state)) {  				f->state = I40E_FILTER_FAILED;  				continue;  			} + +			/* handle broadcast filters by updating the broadcast +			 * promiscuous flag instead of adding a MAC filter. +			 */ +			if (is_broadcast_ether_addr(f->macaddr)) { +				u64 key = i40e_addr_to_hkey(f->macaddr); +				i40e_aqc_broadcast_filter(vsi, vsi_name, f); + +				hlist_del(&f->hlist); +				hash_add(vsi->mac_filter_hash, &f->hlist, key); +				continue; +			} +  			/* add to add array */  			if (num_add == 0)  				add_head = f; @@ -2000,88 +2195,70 @@ int i40e_sync_vsi_filters(struct i40e_vsi *vsi)  					cpu_to_le16((u16)(f->vlan));  			}  			add_list[num_add].queue_number = 0; +			/* set invalid match method for later detection */ +			add_list[num_add].match_method = I40E_AQC_MM_ERR_NO_RES;  			cmd_flags |= I40E_AQC_MACVLAN_ADD_PERFECT_MATCH;  			add_list[num_add].flags = cpu_to_le16(cmd_flags);  			num_add++;  			/* flush a full buffer */  			if (num_add == filter_list_len) { -				aq_ret = i40e_aq_add_macvlan(hw, vsi->seid, -							     add_list, num_add, -							     NULL); -				aq_err = hw->aq.asq_last_status; -				fcnt = i40e_update_filter_state(num_add, -								add_list, -								add_head, -								aq_ret); -				vsi->active_filters += fcnt; - -				if (fcnt != num_add) { -					promisc_changed = true; -					set_bit(__I40E_FILTER_OVERFLOW_PROMISC, -						&vsi->state); -					vsi->promisc_threshold = -						(vsi->active_filters * 3) / 4; -					dev_warn(&pf->pdev->dev, -						 "Error %s adding RX filters on %s, promiscuous mode forced on\n", -						 i40e_aq_str(hw, aq_err), -						 vsi_name); -				} +				i40e_aqc_add_filters(vsi, vsi_name, add_list, +						     add_head, num_add, +						     &promisc_changed);  				memset(add_list, 0, list_size);  				num_add = 0;  			}  		}  		if (num_add) { -			aq_ret = i40e_aq_add_macvlan(hw, vsi->seid, -						     add_list, num_add, NULL); -			aq_err = hw->aq.asq_last_status; -			fcnt = i40e_update_filter_state(num_add, add_list, -							add_head, aq_ret); -			vsi->active_filters += fcnt; -			if (fcnt != num_add) { -				promisc_changed = true; -				set_bit(__I40E_FILTER_OVERFLOW_PROMISC, -					&vsi->state); -				vsi->promisc_threshold = -						(vsi->active_filters * 3) / 4; -				dev_warn(&pf->pdev->dev, -					 "Error %s adding RX filters on %s, promiscuous mode forced on\n", -					 i40e_aq_str(hw, aq_err), vsi_name); -			} +			i40e_aqc_add_filters(vsi, vsi_name, add_list, add_head, +					     num_add, &promisc_changed);  		}  		/* Now move all of the filters from the temp add list back to  		 * the VSI's list.  		 */ -		spin_lock_bh(&vsi->mac_filter_list_lock); -		list_for_each_entry_safe(f, ftmp, &tmp_add_list, list) { -			list_move_tail(&f->list, &vsi->mac_filter_list); +		spin_lock_bh(&vsi->mac_filter_hash_lock); +		hlist_for_each_entry_safe(f, h, &tmp_add_list, hlist) { +			u64 key = i40e_addr_to_hkey(f->macaddr); + +			hlist_del(&f->hlist); +			hash_add(vsi->mac_filter_hash, &f->hlist, key);  		} -		spin_unlock_bh(&vsi->mac_filter_list_lock); +		spin_unlock_bh(&vsi->mac_filter_hash_lock);  		kfree(add_list);  		add_list = NULL;  	} -	/* Check to see if we can drop out of overflow promiscuous mode. */ +	/* Determine the number of active and failed filters. */ +	spin_lock_bh(&vsi->mac_filter_hash_lock); +	vsi->active_filters = 0; +	hash_for_each(vsi->mac_filter_hash, bkt, f, hlist) { +		if (f->state == I40E_FILTER_ACTIVE) +			vsi->active_filters++; +		else if (f->state == I40E_FILTER_FAILED) +			failed_filters++; +	} +	spin_unlock_bh(&vsi->mac_filter_hash_lock); + +	/* If promiscuous mode has changed, we need to calculate a new +	 * threshold for when we are safe to exit +	 */ +	if (promisc_changed) +		vsi->promisc_threshold = (vsi->active_filters * 3) / 4; + +	/* Check if we are able to exit overflow promiscuous mode. We can +	 * safely exit if we didn't just enter, we no longer have any failed +	 * filters, and we have reduced filters below the threshold value. +	 */  	if (test_bit(__I40E_FILTER_OVERFLOW_PROMISC, &vsi->state) && +	    !promisc_changed && !failed_filters &&  	    (vsi->active_filters < vsi->promisc_threshold)) { -		int failed_count = 0; -		/* See if we have any failed filters. We can't drop out of -		 * promiscuous until these have all been deleted. -		 */ -		spin_lock_bh(&vsi->mac_filter_list_lock); -		list_for_each_entry(f, &vsi->mac_filter_list, list) { -			if (f->state == I40E_FILTER_FAILED) -				failed_count++; -		} -		spin_unlock_bh(&vsi->mac_filter_list_lock); -		if (!failed_count) { -			dev_info(&pf->pdev->dev, -				 "filter logjam cleared on %s, leaving overflow promiscuous mode\n", -				 vsi_name); -			clear_bit(__I40E_FILTER_OVERFLOW_PROMISC, &vsi->state); -			promisc_changed = true; -			vsi->promisc_threshold = 0; -		} +		dev_info(&pf->pdev->dev, +			 "filter logjam cleared on %s, leaving overflow promiscuous mode\n", +			 vsi_name); +		clear_bit(__I40E_FILTER_OVERFLOW_PROMISC, &vsi->state); +		promisc_changed = true; +		vsi->promisc_threshold = 0;  	}  	/* if the VF is not trusted do not do promisc */ @@ -2201,6 +2378,18 @@ out:  	clear_bit(__I40E_CONFIG_BUSY, &vsi->state);  	return retval; + +err_no_memory: +	/* Restore elements on the temporary add and delete lists */ +	spin_lock_bh(&vsi->mac_filter_hash_lock); +err_no_memory_locked: +	i40e_undo_filter_entries(vsi, &tmp_del_list); +	i40e_undo_filter_entries(vsi, &tmp_add_list); +	spin_unlock_bh(&vsi->mac_filter_hash_lock); + +	vsi->flags |= I40E_VSI_FLAG_FILTER_CHANGED; +	clear_bit(__I40E_CONFIG_BUSY, &vsi->state); +	return -ENOMEM;  }  /** @@ -2239,13 +2428,8 @@ static void i40e_sync_filters_subtask(struct i40e_pf *pf)  static int i40e_change_mtu(struct net_device *netdev, int new_mtu)  {  	struct i40e_netdev_priv *np = netdev_priv(netdev); -	int max_frame = new_mtu + ETH_HLEN + ETH_FCS_LEN + VLAN_HLEN;  	struct i40e_vsi *vsi = np->vsi; -	/* MTU < 68 is an error and causes problems on some kernels */ -	if ((new_mtu < 68) || (max_frame > I40E_MAX_RXBUFFER)) -		return -EINVAL; -  	netdev_info(netdev, "changing MTU from %d to %d\n",  		    netdev->mtu, new_mtu);  	netdev->mtu = new_mtu; @@ -2354,88 +2538,54 @@ static void i40e_vlan_rx_register(struct net_device *netdev, u32 features)  }  /** - * i40e_vsi_add_vlan - Add vsi membership for given vlan + * i40e_add_vlan_all_mac - Add a MAC/VLAN filter for each existing MAC address   * @vsi: the vsi being configured   * @vid: vlan id to be added (0 = untagged only , -1 = any) + * + * This is a helper function for adding a new MAC/VLAN filter with the + * specified VLAN for each existing MAC address already in the hash table. + * This function does *not* perform any accounting to update filters based on + * VLAN mode. + * + * NOTE: this function expects to be called while under the + * mac_filter_hash_lock   **/ -int i40e_vsi_add_vlan(struct i40e_vsi *vsi, s16 vid) +int i40e_add_vlan_all_mac(struct i40e_vsi *vsi, s16 vid)  { -	struct i40e_mac_filter *f, *ftmp, *add_f; -	bool is_netdev, is_vf; - -	is_vf = (vsi->type == I40E_VSI_SRIOV); -	is_netdev = !!(vsi->netdev); - -	/* Locked once because all functions invoked below iterates list*/ -	spin_lock_bh(&vsi->mac_filter_list_lock); - -	if (is_netdev) { -		add_f = i40e_add_filter(vsi, vsi->netdev->dev_addr, vid, -					is_vf, is_netdev); -		if (!add_f) { -			dev_info(&vsi->back->pdev->dev, -				 "Could not add vlan filter %d for %pM\n", -				 vid, vsi->netdev->dev_addr); -			spin_unlock_bh(&vsi->mac_filter_list_lock); -			return -ENOMEM; -		} -	} +	struct i40e_mac_filter *f, *add_f; +	struct hlist_node *h; +	int bkt; -	list_for_each_entry_safe(f, ftmp, &vsi->mac_filter_list, list) { -		add_f = i40e_add_filter(vsi, f->macaddr, vid, is_vf, is_netdev); +	hash_for_each_safe(vsi->mac_filter_hash, bkt, h, f, hlist) { +		if (f->state == I40E_FILTER_REMOVE) +			continue; +		add_f = i40e_add_filter(vsi, f->macaddr, vid);  		if (!add_f) {  			dev_info(&vsi->back->pdev->dev,  				 "Could not add vlan filter %d for %pM\n",  				 vid, f->macaddr); -			spin_unlock_bh(&vsi->mac_filter_list_lock);  			return -ENOMEM;  		}  	} -	/* Now if we add a vlan tag, make sure to check if it is the first -	 * tag (i.e. a "tag" -1 does exist) and if so replace the -1 "tag" -	 * with 0, so we now accept untagged and specified tagged traffic -	 * (and not all tags along with untagged) -	 */ -	if (vid > 0) { -		if (is_netdev && i40e_find_filter(vsi, vsi->netdev->dev_addr, -						  I40E_VLAN_ANY, -						  is_vf, is_netdev)) { -			i40e_del_filter(vsi, vsi->netdev->dev_addr, -					I40E_VLAN_ANY, is_vf, is_netdev); -			add_f = i40e_add_filter(vsi, vsi->netdev->dev_addr, 0, -						is_vf, is_netdev); -			if (!add_f) { -				dev_info(&vsi->back->pdev->dev, -					 "Could not add filter 0 for %pM\n", -					 vsi->netdev->dev_addr); -				spin_unlock_bh(&vsi->mac_filter_list_lock); -				return -ENOMEM; -			} -		} -	} +	return 0; +} -	/* Do not assume that I40E_VLAN_ANY should be reset to VLAN 0 */ -	if (vid > 0 && !vsi->info.pvid) { -		list_for_each_entry_safe(f, ftmp, &vsi->mac_filter_list, list) { -			if (!i40e_find_filter(vsi, f->macaddr, I40E_VLAN_ANY, -					      is_vf, is_netdev)) -				continue; -			i40e_del_filter(vsi, f->macaddr, I40E_VLAN_ANY, -					is_vf, is_netdev); -			add_f = i40e_add_filter(vsi, f->macaddr, -						0, is_vf, is_netdev); -			if (!add_f) { -				dev_info(&vsi->back->pdev->dev, -					 "Could not add filter 0 for %pM\n", -					f->macaddr); -				spin_unlock_bh(&vsi->mac_filter_list_lock); -				return -ENOMEM; -			} -		} -	} +/** + * i40e_vsi_add_vlan - Add VSI membership for given VLAN + * @vsi: the VSI being configured + * @vid: VLAN id to be added (0 = untagged only , -1 = any) + **/ +int i40e_vsi_add_vlan(struct i40e_vsi *vsi, s16 vid) +{ +	int err; -	spin_unlock_bh(&vsi->mac_filter_list_lock); +	/* Locked once because all functions invoked below iterates list*/ +	spin_lock_bh(&vsi->mac_filter_hash_lock); +	err = i40e_add_vlan_all_mac(vsi, vid); +	spin_unlock_bh(&vsi->mac_filter_hash_lock); +	if (err) +		return err;  	/* schedule our worker thread which will take care of  	 * applying the new filter changes @@ -2445,82 +2595,45 @@ int i40e_vsi_add_vlan(struct i40e_vsi *vsi, s16 vid)  }  /** - * i40e_vsi_kill_vlan - Remove vsi membership for given vlan + * i40e_rm_vlan_all_mac - Remove MAC/VLAN pair for all MAC with the given VLAN   * @vsi: the vsi being configured   * @vid: vlan id to be removed (0 = untagged only , -1 = any)   * - * Return: 0 on success or negative otherwise - **/ -int i40e_vsi_kill_vlan(struct i40e_vsi *vsi, s16 vid) + * This function should be used to remove all VLAN filters which match the + * given VID. It does not schedule the service event and does not take the + * mac_filter_hash_lock so it may be combined with other operations under + * a single invocation of the mac_filter_hash_lock. + * + * NOTE: this function expects to be called while under the + * mac_filter_hash_lock + */ +void i40e_rm_vlan_all_mac(struct i40e_vsi *vsi, s16 vid)  { -	struct net_device *netdev = vsi->netdev; -	struct i40e_mac_filter *f, *ftmp, *add_f; -	bool is_vf, is_netdev; -	int filter_count = 0; - -	is_vf = (vsi->type == I40E_VSI_SRIOV); -	is_netdev = !!(netdev); - -	/* Locked once because all functions invoked below iterates list */ -	spin_lock_bh(&vsi->mac_filter_list_lock); - -	if (is_netdev) -		i40e_del_filter(vsi, netdev->dev_addr, vid, is_vf, is_netdev); - -	list_for_each_entry_safe(f, ftmp, &vsi->mac_filter_list, list) -		i40e_del_filter(vsi, f->macaddr, vid, is_vf, is_netdev); - -	/* go through all the filters for this VSI and if there is only -	 * vid == 0 it means there are no other filters, so vid 0 must -	 * be replaced with -1. This signifies that we should from now -	 * on accept any traffic (with any tag present, or untagged) -	 */ -	list_for_each_entry(f, &vsi->mac_filter_list, list) { -		if (is_netdev) { -			if (f->vlan && -			    ether_addr_equal(netdev->dev_addr, f->macaddr)) -				filter_count++; -		} - -		if (f->vlan) -			filter_count++; -	} - -	if (!filter_count && is_netdev) { -		i40e_del_filter(vsi, netdev->dev_addr, 0, is_vf, is_netdev); -		f = i40e_add_filter(vsi, netdev->dev_addr, I40E_VLAN_ANY, -				    is_vf, is_netdev); -		if (!f) { -			dev_info(&vsi->back->pdev->dev, -				 "Could not add filter %d for %pM\n", -				 I40E_VLAN_ANY, netdev->dev_addr); -			spin_unlock_bh(&vsi->mac_filter_list_lock); -			return -ENOMEM; -		} -	} +	struct i40e_mac_filter *f; +	struct hlist_node *h; +	int bkt; -	if (!filter_count) { -		list_for_each_entry_safe(f, ftmp, &vsi->mac_filter_list, list) { -			i40e_del_filter(vsi, f->macaddr, 0, is_vf, is_netdev); -			add_f = i40e_add_filter(vsi, f->macaddr, I40E_VLAN_ANY, -						is_vf, is_netdev); -			if (!add_f) { -				dev_info(&vsi->back->pdev->dev, -					 "Could not add filter %d for %pM\n", -					 I40E_VLAN_ANY, f->macaddr); -				spin_unlock_bh(&vsi->mac_filter_list_lock); -				return -ENOMEM; -			} -		} +	hash_for_each_safe(vsi->mac_filter_hash, bkt, h, f, hlist) { +		if (f->vlan == vid) +			__i40e_del_filter(vsi, f);  	} +} -	spin_unlock_bh(&vsi->mac_filter_list_lock); +/** + * i40e_vsi_kill_vlan - Remove VSI membership for given VLAN + * @vsi: the VSI being configured + * @vid: VLAN id to be removed (0 = untagged only , -1 = any) + **/ +void i40e_vsi_kill_vlan(struct i40e_vsi *vsi, s16 vid) +{ +	spin_lock_bh(&vsi->mac_filter_hash_lock); +	i40e_rm_vlan_all_mac(vsi, vid); +	spin_unlock_bh(&vsi->mac_filter_hash_lock);  	/* schedule our worker thread which will take care of  	 * applying the new filter changes  	 */  	i40e_service_event_schedule(vsi->back); -	return 0;  }  /** @@ -2542,7 +2655,7 @@ static int i40e_vlan_rx_add_vid(struct net_device *netdev,  	struct i40e_vsi *vsi = np->vsi;  	int ret = 0; -	if (vid > 4095) +	if (vid >= VLAN_N_VID)  		return -EINVAL;  	/* If the network stack called us with vid = 0 then @@ -2554,7 +2667,7 @@ static int i40e_vlan_rx_add_vid(struct net_device *netdev,  	if (vid)  		ret = i40e_vsi_add_vlan(vsi, vid); -	if (!ret && (vid < VLAN_N_VID)) +	if (!ret)  		set_bit(vid, vsi->active_vlans);  	return ret; @@ -3322,6 +3435,33 @@ static irqreturn_t i40e_msix_clean_rings(int irq, void *data)  }  /** + * i40e_irq_affinity_notify - Callback for affinity changes + * @notify: context as to what irq was changed + * @mask: the new affinity mask + * + * This is a callback function used by the irq_set_affinity_notifier function + * so that we may register to receive changes to the irq affinity masks. + **/ +static void i40e_irq_affinity_notify(struct irq_affinity_notify *notify, +				     const cpumask_t *mask) +{ +	struct i40e_q_vector *q_vector = +		container_of(notify, struct i40e_q_vector, affinity_notify); + +	q_vector->affinity_mask = *mask; +} + +/** + * i40e_irq_affinity_release - Callback for affinity notifier release + * @ref: internal core kernel usage + * + * This is a callback function used by the irq_set_affinity_notifier function + * to inform the current notification subscriber that they will no longer + * receive notifications. + **/ +static void i40e_irq_affinity_release(struct kref *ref) {} + +/**   * i40e_vsi_request_irq_msix - Initialize MSI-X interrupts   * @vsi: the VSI being configured   * @basename: name for the vector @@ -3336,10 +3476,13 @@ static int i40e_vsi_request_irq_msix(struct i40e_vsi *vsi, char *basename)  	int rx_int_idx = 0;  	int tx_int_idx = 0;  	int vector, err; +	int irq_num;  	for (vector = 0; vector < q_vectors; vector++) {  		struct i40e_q_vector *q_vector = vsi->q_vectors[vector]; +		irq_num = pf->msix_entries[base + vector].vector; +  		if (q_vector->tx.ring && q_vector->rx.ring) {  			snprintf(q_vector->name, sizeof(q_vector->name) - 1,  				 "%s-%s-%d", basename, "TxRx", rx_int_idx++); @@ -3354,7 +3497,7 @@ static int i40e_vsi_request_irq_msix(struct i40e_vsi *vsi, char *basename)  			/* skip this unused q_vector */  			continue;  		} -		err = request_irq(pf->msix_entries[base + vector].vector, +		err = request_irq(irq_num,  				  vsi->irq_handler,  				  0,  				  q_vector->name, @@ -3364,9 +3507,13 @@ static int i40e_vsi_request_irq_msix(struct i40e_vsi *vsi, char *basename)  				 "MSIX request_irq failed, error: %d\n", err);  			goto free_queue_irqs;  		} + +		/* register for affinity change notifications */ +		q_vector->affinity_notify.notify = i40e_irq_affinity_notify; +		q_vector->affinity_notify.release = i40e_irq_affinity_release; +		irq_set_affinity_notifier(irq_num, &q_vector->affinity_notify);  		/* assign the mask for this irq */ -		irq_set_affinity_hint(pf->msix_entries[base + vector].vector, -				      &q_vector->affinity_mask); +		irq_set_affinity_hint(irq_num, &q_vector->affinity_mask);  	}  	vsi->irqs_ready = true; @@ -3375,10 +3522,10 @@ static int i40e_vsi_request_irq_msix(struct i40e_vsi *vsi, char *basename)  free_queue_irqs:  	while (vector) {  		vector--; -		irq_set_affinity_hint(pf->msix_entries[base + vector].vector, -				      NULL); -		free_irq(pf->msix_entries[base + vector].vector, -			 &(vsi->q_vectors[vector])); +		irq_num = pf->msix_entries[base + vector].vector; +		irq_set_affinity_notifier(irq_num, NULL); +		irq_set_affinity_hint(irq_num, NULL); +		free_irq(irq_num, &vsi->q_vectors[vector]);  	}  	return err;  } @@ -3480,7 +3627,7 @@ static irqreturn_t i40e_intr(int irq, void *data)  	    (ena_mask & I40E_PFINT_ICR0_ENA_PE_CRITERR_MASK)) {  		ena_mask &= ~I40E_PFINT_ICR0_ENA_PE_CRITERR_MASK;  		icr0 &= ~I40E_PFINT_ICR0_ENA_PE_CRITERR_MASK; -		dev_info(&pf->pdev->dev, "cleared PE_CRITERR\n"); +		dev_dbg(&pf->pdev->dev, "cleared PE_CRITERR\n");  	}  	/* only q0 is used in MSI/Legacy mode, and none are used in MSIX */ @@ -3973,30 +4120,36 @@ static int i40e_vsi_control_rx(struct i40e_vsi *vsi, bool enable)  }  /** - * i40e_vsi_control_rings - Start or stop a VSI's rings + * i40e_vsi_start_rings - Start a VSI's rings   * @vsi: the VSI being configured - * @enable: start or stop the rings   **/ -int i40e_vsi_control_rings(struct i40e_vsi *vsi, bool request) +int i40e_vsi_start_rings(struct i40e_vsi *vsi)  {  	int ret = 0;  	/* do rx first for enable and last for disable */ -	if (request) { -		ret = i40e_vsi_control_rx(vsi, request); -		if (ret) -			return ret; -		ret = i40e_vsi_control_tx(vsi, request); -	} else { -		/* Ignore return value, we need to shutdown whatever we can */ -		i40e_vsi_control_tx(vsi, request); -		i40e_vsi_control_rx(vsi, request); -	} +	ret = i40e_vsi_control_rx(vsi, true); +	if (ret) +		return ret; +	ret = i40e_vsi_control_tx(vsi, true);  	return ret;  }  /** + * i40e_vsi_stop_rings - Stop a VSI's rings + * @vsi: the VSI being configured + **/ +void i40e_vsi_stop_rings(struct i40e_vsi *vsi) +{ +	/* do rx first for enable and last for disable +	 * Ignore return value, we need to shutdown whatever we can +	 */ +	i40e_vsi_control_tx(vsi, false); +	i40e_vsi_control_rx(vsi, false); +} + +/**   * i40e_vsi_free_irq - Free the irq association with the OS   * @vsi: the VSI being configured   **/ @@ -4017,19 +4170,23 @@ static void i40e_vsi_free_irq(struct i40e_vsi *vsi)  		vsi->irqs_ready = false;  		for (i = 0; i < vsi->num_q_vectors; i++) { -			u16 vector = i + base; +			int irq_num; +			u16 vector; + +			vector = i + base; +			irq_num = pf->msix_entries[vector].vector;  			/* free only the irqs that were actually requested */  			if (!vsi->q_vectors[i] ||  			    !vsi->q_vectors[i]->num_ringpairs)  				continue; +			/* clear the affinity notifier in the IRQ descriptor */ +			irq_set_affinity_notifier(irq_num, NULL);  			/* clear the affinity_mask in the IRQ descriptor */ -			irq_set_affinity_hint(pf->msix_entries[vector].vector, -					      NULL); -			synchronize_irq(pf->msix_entries[vector].vector); -			free_irq(pf->msix_entries[vector].vector, -				 vsi->q_vectors[i]); +			irq_set_affinity_hint(irq_num, NULL); +			synchronize_irq(irq_num); +			free_irq(irq_num, vsi->q_vectors[i]);  			/* Tear down the interrupt queue link list  			 * @@ -5116,12 +5273,16 @@ out:   */  void i40e_print_link_message(struct i40e_vsi *vsi, bool isup)  { +	enum i40e_aq_link_speed new_speed;  	char *speed = "Unknown";  	char *fc = "Unknown"; -	if (vsi->current_isup == isup) +	new_speed = vsi->back->hw.phy.link_info.link_speed; + +	if ((vsi->current_isup == isup) && (vsi->current_speed == new_speed))  		return;  	vsi->current_isup = isup; +	vsi->current_speed = new_speed;  	if (!isup) {  		netdev_info(vsi->netdev, "NIC Link is Down\n");  		return; @@ -5143,6 +5304,9 @@ void i40e_print_link_message(struct i40e_vsi *vsi, bool isup)  	case I40E_LINK_SPEED_20GB:  		speed = "20 G";  		break; +	case I40E_LINK_SPEED_25GB: +		speed = "25 G"; +		break;  	case I40E_LINK_SPEED_10GB:  		speed = "10 G";  		break; @@ -5190,7 +5354,7 @@ static int i40e_up_complete(struct i40e_vsi *vsi)  		i40e_configure_msi_and_legacy(vsi);  	/* start rings */ -	err = i40e_vsi_control_rings(vsi, true); +	err = i40e_vsi_start_rings(vsi);  	if (err)  		return err; @@ -5287,7 +5451,7 @@ void i40e_down(struct i40e_vsi *vsi)  		netif_tx_disable(vsi->netdev);  	}  	i40e_vsi_disable_irq(vsi); -	i40e_vsi_control_rings(vsi, false); +	i40e_vsi_stop_rings(vsi);  	i40e_napi_disable_all(vsi);  	for (i = 0; i < vsi->num_queue_pairs; i++) { @@ -5833,19 +5997,6 @@ static void i40e_handle_lan_overflow_event(struct i40e_pf *pf,  }  /** - * i40e_service_event_complete - Finish up the service event - * @pf: board private structure - **/ -static void i40e_service_event_complete(struct i40e_pf *pf) -{ -	WARN_ON(!test_bit(__I40E_SERVICE_SCHED, &pf->state)); - -	/* flush memory to make sure state is correct before next watchog */ -	smp_mb__before_atomic(); -	clear_bit(__I40E_SERVICE_SCHED, &pf->state); -} - -/**   * i40e_get_cur_guaranteed_fd_count - Get the consumed guaranteed FD filters   * @pf: board private structure   **/ @@ -6670,7 +6821,6 @@ static int i40e_vsi_clear(struct i40e_vsi *vsi);  static void i40e_fdir_sb_setup(struct i40e_pf *pf)  {  	struct i40e_vsi *vsi; -	int i;  	/* quick workaround for an NVM issue that leaves a critical register  	 * uninitialized @@ -6681,6 +6831,7 @@ static void i40e_fdir_sb_setup(struct i40e_pf *pf)  			0xeacb7d61, 0xaa4f05b6, 0x9c5c89ed, 0xfc425ddb,  			0xa4654832, 0xfc7461d4, 0x8f827619, 0xf5c63c21,  			0x95b3a76d}; +		int i;  		for (i = 0; i <= I40E_GLQF_HKEY_MAX_INDEX; i++)  			wr32(&pf->hw, I40E_GLQF_HKEY(i), hkey[i]); @@ -6690,13 +6841,7 @@ static void i40e_fdir_sb_setup(struct i40e_pf *pf)  		return;  	/* find existing VSI and see if it needs configuring */ -	vsi = NULL; -	for (i = 0; i < pf->num_alloc_vsi; i++) { -		if (pf->vsi[i] && pf->vsi[i]->type == I40E_VSI_FDIR) { -			vsi = pf->vsi[i]; -			break; -		} -	} +	vsi = i40e_find_vsi_by_type(pf, I40E_VSI_FDIR);  	/* create a new VSI if none exists */  	if (!vsi) { @@ -6718,15 +6863,12 @@ static void i40e_fdir_sb_setup(struct i40e_pf *pf)   **/  static void i40e_fdir_teardown(struct i40e_pf *pf)  { -	int i; +	struct i40e_vsi *vsi;  	i40e_fdir_filter_exit(pf); -	for (i = 0; i < pf->num_alloc_vsi; i++) { -		if (pf->vsi[i] && pf->vsi[i]->type == I40E_VSI_FDIR) { -			i40e_vsi_release(pf->vsi[i]); -			break; -		} -	} +	vsi = i40e_find_vsi_by_type(pf, I40E_VSI_FDIR); +	if (vsi) +		i40e_vsi_release(vsi);  }  /** @@ -7163,10 +7305,12 @@ static void i40e_service_task(struct work_struct *work)  	/* don't bother with service tasks if a reset is in progress */  	if (test_bit(__I40E_RESET_RECOVERY_PENDING, &pf->state)) { -		i40e_service_event_complete(pf);  		return;  	} +	if (test_and_set_bit(__I40E_SERVICE_SCHED, &pf->state)) +		return; +  	i40e_detect_recover_hung(pf);  	i40e_sync_filters_subtask(pf);  	i40e_reset_subtask(pf); @@ -7179,7 +7323,9 @@ static void i40e_service_task(struct work_struct *work)  	i40e_sync_udp_filters_subtask(pf);  	i40e_clean_adminq_subtask(pf); -	i40e_service_event_complete(pf); +	/* flush memory to make sure state is correct before next watchdog */ +	smp_mb__before_atomic(); +	clear_bit(__I40E_SERVICE_SCHED, &pf->state);  	/* If the tasks have taken longer than one timer cycle or there  	 * is more work to be done, reschedule the service task now @@ -7354,7 +7500,7 @@ static int i40e_vsi_mem_alloc(struct i40e_pf *pf, enum i40e_vsi_type type)  				pf->rss_table_size : 64;  	vsi->netdev_registered = false;  	vsi->work_limit = I40E_DEFAULT_IRQ_WORK; -	INIT_LIST_HEAD(&vsi->mac_filter_list); +	hash_init(vsi->mac_filter_hash);  	vsi->irqs_ready = false;  	ret = i40e_set_num_rings_in_vsi(vsi); @@ -7369,7 +7515,7 @@ static int i40e_vsi_mem_alloc(struct i40e_pf *pf, enum i40e_vsi_type type)  	i40e_vsi_setup_irqhandler(vsi, i40e_msix_clean_rings);  	/* Initialize VSI lock */ -	spin_lock_init(&vsi->mac_filter_list_lock); +	spin_lock_init(&vsi->mac_filter_hash_lock);  	pf->vsi[vsi_idx] = vsi;  	ret = vsi_idx;  	goto unlock_pf; @@ -8345,8 +8491,8 @@ int i40e_reconfig_rss_queues(struct i40e_pf *pf, int queue_count)  		i40e_pf_config_rss(pf);  	} -	dev_info(&pf->pdev->dev, "RSS count/HW max RSS count:  %d/%d\n", -		 pf->alloc_rss_size, pf->rss_size_max); +	dev_info(&pf->pdev->dev, "User requested queue count/HW max RSS count:  %d/%d\n", +		 vsi->req_queue_pairs, pf->rss_size_max);  	return pf->alloc_rss_size;  } @@ -8489,15 +8635,6 @@ static int i40e_sw_init(struct i40e_pf *pf)  	int err = 0;  	int size; -	pf->msg_enable = netif_msg_init(I40E_DEFAULT_MSG_ENABLE, -				(NETIF_MSG_DRV|NETIF_MSG_PROBE|NETIF_MSG_LINK)); -	if (debug != -1 && debug != I40E_DEFAULT_MSG_ENABLE) { -		if (I40E_DEBUG_USER & debug) -			pf->hw.debug_mask = debug; -		pf->msg_enable = netif_msg_init((debug & ~I40E_DEBUG_USER), -						I40E_DEFAULT_MSG_ENABLE); -	} -  	/* Set default capability flags */  	pf->flags = I40E_FLAG_RX_CSUM_ENABLED |  		    I40E_FLAG_MSI_ENABLED     | @@ -8605,7 +8742,8 @@ static int i40e_sw_init(struct i40e_pf *pf)  			     I40E_FLAG_MULTIPLE_TCP_UDP_RSS_PCTYPE |  			     I40E_FLAG_NO_PCI_LINK_CHECK |  			     I40E_FLAG_USE_SET_LLDP_MIB | -			     I40E_FLAG_GENEVE_OFFLOAD_CAPABLE; +			     I40E_FLAG_GENEVE_OFFLOAD_CAPABLE | +			     I40E_FLAG_PTP_L4_CAPABLE;  	} else if ((pf->hw.aq.api_maj_ver > 1) ||  		   ((pf->hw.aq.api_maj_ver == 1) &&  		    (pf->hw.aq.api_min_ver > 4))) { @@ -9037,10 +9175,6 @@ static int i40e_ndo_bridge_getlink(struct sk_buff *skb, u32 pid, u32 seq,  				       0, 0, nlflags, filter_mask, NULL);  } -/* Hardware supports L4 tunnel length of 128B (=2^7) which includes - * inner mac plus all inner ethertypes. - */ -#define I40E_MAX_TUNNEL_HDR_LEN 128  /**   * i40e_features_check - Validate encapsulated packet conforms to limits   * @skb: skb buff @@ -9051,12 +9185,52 @@ static netdev_features_t i40e_features_check(struct sk_buff *skb,  					     struct net_device *dev,  					     netdev_features_t features)  { -	if (skb->encapsulation && -	    ((skb_inner_network_header(skb) - skb_transport_header(skb)) > -	     I40E_MAX_TUNNEL_HDR_LEN)) -		return features & ~(NETIF_F_CSUM_MASK | NETIF_F_GSO_MASK); +	size_t len; + +	/* No point in doing any of this if neither checksum nor GSO are +	 * being requested for this frame.  We can rule out both by just +	 * checking for CHECKSUM_PARTIAL +	 */ +	if (skb->ip_summed != CHECKSUM_PARTIAL) +		return features; + +	/* We cannot support GSO if the MSS is going to be less than +	 * 64 bytes.  If it is then we need to drop support for GSO. +	 */ +	if (skb_is_gso(skb) && (skb_shinfo(skb)->gso_size < 64)) +		features &= ~NETIF_F_GSO_MASK; + +	/* MACLEN can support at most 63 words */ +	len = skb_network_header(skb) - skb->data; +	if (len & ~(63 * 2)) +		goto out_err; + +	/* IPLEN and EIPLEN can support at most 127 dwords */ +	len = skb_transport_header(skb) - skb_network_header(skb); +	if (len & ~(127 * 4)) +		goto out_err; + +	if (skb->encapsulation) { +		/* L4TUNLEN can support 127 words */ +		len = skb_inner_network_header(skb) - skb_transport_header(skb); +		if (len & ~(127 * 2)) +			goto out_err; + +		/* IPLEN can support at most 127 dwords */ +		len = skb_inner_transport_header(skb) - +		      skb_inner_network_header(skb); +		if (len & ~(127 * 4)) +			goto out_err; +	} + +	/* No need to validate L4LEN as TCP is the only protocol with a +	 * a flexible value and we support all possible values supported +	 * by TCP, which is at most 15 dwords +	 */  	return features; +out_err: +	return features & ~(NETIF_F_CSUM_MASK | NETIF_F_GSO_MASK);  }  static const struct net_device_ops i40e_netdev_ops = { @@ -9109,6 +9283,7 @@ static int i40e_config_netdev(struct i40e_vsi *vsi)  	struct i40e_hw *hw = &pf->hw;  	struct i40e_netdev_priv *np;  	struct net_device *netdev; +	u8 broadcast[ETH_ALEN];  	u8 mac_addr[ETH_ALEN];  	int etherdev_size; @@ -9169,20 +9344,38 @@ static int i40e_config_netdev(struct i40e_vsi *vsi)  		 * which must be replaced by a normal filter.  		 */  		i40e_rm_default_mac_filter(vsi, mac_addr); -		spin_lock_bh(&vsi->mac_filter_list_lock); -		i40e_add_filter(vsi, mac_addr, I40E_VLAN_ANY, false, true); -		spin_unlock_bh(&vsi->mac_filter_list_lock); +		spin_lock_bh(&vsi->mac_filter_hash_lock); +		i40e_add_filter(vsi, mac_addr, I40E_VLAN_ANY); +		spin_unlock_bh(&vsi->mac_filter_hash_lock);  	} else {  		/* relate the VSI_VMDQ name to the VSI_MAIN name */  		snprintf(netdev->name, IFNAMSIZ, "%sv%%d",  			 pf->vsi[pf->lan_vsi]->netdev->name);  		random_ether_addr(mac_addr); -		spin_lock_bh(&vsi->mac_filter_list_lock); -		i40e_add_filter(vsi, mac_addr, I40E_VLAN_ANY, false, false); -		spin_unlock_bh(&vsi->mac_filter_list_lock); +		spin_lock_bh(&vsi->mac_filter_hash_lock); +		i40e_add_filter(vsi, mac_addr, I40E_VLAN_ANY); +		spin_unlock_bh(&vsi->mac_filter_hash_lock);  	} +	/* Add the broadcast filter so that we initially will receive +	 * broadcast packets. Note that when a new VLAN is first added the +	 * driver will convert all filters marked I40E_VLAN_ANY into VLAN +	 * specific filters as part of transitioning into "vlan" operation. +	 * When more VLANs are added, the driver will copy each existing MAC +	 * filter and add it for the new VLAN. +	 * +	 * Broadcast filters are handled specially by +	 * i40e_sync_filters_subtask, as the driver must to set the broadcast +	 * promiscuous bit instead of adding this directly as a MAC/VLAN +	 * filter. The subtask will update the correct broadcast promiscuous +	 * bits as VLANs become active or inactive. +	 */ +	eth_broadcast_addr(broadcast); +	spin_lock_bh(&vsi->mac_filter_hash_lock); +	i40e_add_filter(vsi, broadcast, I40E_VLAN_ANY); +	spin_unlock_bh(&vsi->mac_filter_hash_lock); +  	ether_addr_copy(netdev->dev_addr, mac_addr);  	ether_addr_copy(netdev->perm_addr, mac_addr); @@ -9198,6 +9391,11 @@ static int i40e_config_netdev(struct i40e_vsi *vsi)  	i40e_fcoe_config_netdev(netdev, vsi);  #endif +	/* MTU range: 68 - 9706 */ +	netdev->min_mtu = ETH_MIN_MTU; +	netdev->max_mtu = I40E_MAX_RXBUFFER - +			  (ETH_HLEN + ETH_FCS_LEN + VLAN_HLEN); +  	return 0;  } @@ -9260,11 +9458,12 @@ int i40e_is_vsi_uplink_mode_veb(struct i40e_vsi *vsi)  static int i40e_add_vsi(struct i40e_vsi *vsi)  {  	int ret = -ENODEV; -	i40e_status aq_ret = 0;  	struct i40e_pf *pf = vsi->back;  	struct i40e_hw *hw = &pf->hw;  	struct i40e_vsi_context ctxt; -	struct i40e_mac_filter *f, *ftmp; +	struct i40e_mac_filter *f; +	struct hlist_node *h; +	int bkt;  	u8 enabled_tc = 0x1; /* TC0 enabled */  	int f_count = 0; @@ -9448,28 +9647,16 @@ static int i40e_add_vsi(struct i40e_vsi *vsi)  		vsi->seid = ctxt.seid;  		vsi->id = ctxt.vsi_number;  	} -	/* Except FDIR VSI, for all othet VSI set the broadcast filter */ -	if (vsi->type != I40E_VSI_FDIR) { -		aq_ret = i40e_aq_set_vsi_broadcast(hw, vsi->seid, true, NULL); -		if (aq_ret) { -			ret = i40e_aq_rc_to_posix(aq_ret, -						  hw->aq.asq_last_status); -			dev_info(&pf->pdev->dev, -				 "set brdcast promisc failed, err %s, aq_err %s\n", -				 i40e_stat_str(hw, aq_ret), -				 i40e_aq_str(hw, hw->aq.asq_last_status)); -		} -	}  	vsi->active_filters = 0;  	clear_bit(__I40E_FILTER_OVERFLOW_PROMISC, &vsi->state); -	spin_lock_bh(&vsi->mac_filter_list_lock); +	spin_lock_bh(&vsi->mac_filter_hash_lock);  	/* If macvlan filters already exist, force them to get loaded */ -	list_for_each_entry_safe(f, ftmp, &vsi->mac_filter_list, list) { +	hash_for_each_safe(vsi->mac_filter_hash, bkt, h, f, hlist) {  		f->state = I40E_FILTER_NEW;  		f_count++;  	} -	spin_unlock_bh(&vsi->mac_filter_list_lock); +	spin_unlock_bh(&vsi->mac_filter_hash_lock);  	if (f_count) {  		vsi->flags |= I40E_VSI_FLAG_FILTER_CHANGED; @@ -9499,11 +9686,12 @@ err:   **/  int i40e_vsi_release(struct i40e_vsi *vsi)  { -	struct i40e_mac_filter *f, *ftmp; +	struct i40e_mac_filter *f; +	struct hlist_node *h;  	struct i40e_veb *veb = NULL;  	struct i40e_pf *pf;  	u16 uplink_seid; -	int i, n; +	int i, n, bkt;  	pf = vsi->back; @@ -9533,11 +9721,19 @@ int i40e_vsi_release(struct i40e_vsi *vsi)  		i40e_vsi_disable_irq(vsi);  	} -	spin_lock_bh(&vsi->mac_filter_list_lock); -	list_for_each_entry_safe(f, ftmp, &vsi->mac_filter_list, list) -		i40e_del_filter(vsi, f->macaddr, f->vlan, -				f->is_vf, f->is_netdev); -	spin_unlock_bh(&vsi->mac_filter_list_lock); +	spin_lock_bh(&vsi->mac_filter_hash_lock); + +	/* clear the sync flag on all filters */ +	if (vsi->netdev) { +		__dev_uc_unsync(vsi->netdev, NULL); +		__dev_mc_unsync(vsi->netdev, NULL); +	} + +	/* make sure any remaining filters are marked for deletion */ +	hash_for_each_safe(vsi->mac_filter_hash, bkt, h, f, hlist) +		__i40e_del_filter(vsi, f); + +	spin_unlock_bh(&vsi->mac_filter_hash_lock);  	i40e_sync_vsi_filters(vsi); @@ -10806,10 +11002,12 @@ static int i40e_probe(struct pci_dev *pdev, const struct pci_device_id *ent)  	mutex_init(&hw->aq.asq_mutex);  	mutex_init(&hw->aq.arq_mutex); -	if (debug != -1) { -		pf->msg_enable = pf->hw.debug_mask; -		pf->msg_enable = debug; -	} +	pf->msg_enable = netif_msg_init(debug, +					NETIF_MSG_DRV | +					NETIF_MSG_PROBE | +					NETIF_MSG_LINK); +	if (debug < -1) +		pf->hw.debug_mask = debug;  	/* do a special CORER for clearing PXE mode once at init */  	if (hw->revision_id == 0 && @@ -10951,7 +11149,7 @@ static int i40e_probe(struct pci_dev *pdev, const struct pci_device_id *ent)  	err = i40e_init_pf_dcb(pf);  	if (err) {  		dev_info(&pdev->dev, "DCB init failed %d, disabled\n", err); -		pf->flags &= ~(I40E_FLAG_DCB_CAPABLE & I40E_FLAG_DCB_ENABLED); +		pf->flags &= ~(I40E_FLAG_DCB_CAPABLE | I40E_FLAG_DCB_ENABLED);  		/* Continue without DCB enabled */  	}  #endif /* CONFIG_I40E_DCB */ @@ -11209,7 +11407,6 @@ static int i40e_probe(struct pci_dev *pdev, const struct pci_device_id *ent)  		dev_dbg(&pf->pdev->dev, "get supported phy types ret =  %s last_status =  %s\n",  			i40e_stat_str(&pf->hw, err),  			i40e_aq_str(&pf->hw, pf->hw.aq.asq_last_status)); -	pf->hw.phy.phy_types = le32_to_cpu(abilities.phy_type);  	/* Add a filter to drop all Flow control frames from any VSI from being  	 * transmitted. By doing so we stop a malicious VF from sending out @@ -11221,9 +11418,10 @@ static int i40e_probe(struct pci_dev *pdev, const struct pci_device_id *ent)  						       pf->main_vsi_seid);  	if ((pf->hw.device_id == I40E_DEV_ID_10G_BASE_T) || -	    (pf->hw.device_id == I40E_DEV_ID_10G_BASE_T4)) -		pf->flags |= I40E_FLAG_HAVE_10GBASET_PHY; - +		(pf->hw.device_id == I40E_DEV_ID_10G_BASE_T4)) +		pf->flags |= I40E_FLAG_PHY_CONTROLS_LEDS; +	if (pf->hw.device_id == I40E_DEV_ID_SFP_I_X722) +		pf->flags |= I40E_FLAG_HAVE_CRT_RETIMER;  	/* print a string summarizing features */  	i40e_print_features(pf);  |