Skip to contentSkip to conversation

i40e: Fix attach VF to VM issue

PATCH New Alice Michael 2 participants 9 messages Mar 7, 2018 – Mar 8, 2018

Subsystems (2)
lore
Share & tools
lore
#0 lore raw

PATCH 1/7 i40e: Fix attach VF to VM issue

From: Pawe? Jab?o?ski <[email protected]>

Fix for "Resource temporarily unavailable" problem when virsh is trying to attach a device to VM. When the VF driver is loaded on host and virsh is trying to attach it to the VM and set a MAC address, it ends with a race condition between i40e_reset_vf and i40e_ndo_set_vf_mac functions. The bug is fixed by adding polling in i40e_ndo_set_vf_mac function For when the VF is in Reset mode.

---
 drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c | 11 +++++++++++
 1 file changed, 11 insertions(+)
drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c +11 -0
index 6049a56..8559c09 100644
@@ -3742,6 +3742,7 @@ int i40e_ndo_set_vf_mac(struct net_device *netdev, int vf_id, u8 *mac)
 	int ret = 0;
 	struct hlist_node *h;
 	int bkt;
+	u8 i;
 
 	/* validate the request */
 	if (vf_id >= pf->num_alloc_vfs) {
@@ -3753,6 +3754,16 @@ int i40e_ndo_set_vf_mac(struct net_device *netdev, int vf_id, u8 *mac)
 
 	vf = &(pf->vf[vf_id]);
 	vsi = pf->vsi[vf->lan_vsi_idx];
+
+	/* When the VF is resetting wait until it is done.
+	 * It can take up to 200 milliseconds,
+	 * but wait for up to 300 milliseconds to be safe.
+	 */
+	for (i = 0; i < 15; i++) {
+		if (test_bit(I40E_VF_STATE_INIT, &vf->vf_states))
+			break;
+		msleep(20);
+	}
 	if (!test_bit(I40E_VF_STATE_INIT, &vf->vf_states)) {
 		dev_err(&pf->pdev->dev, "VF %d still in reset. Try again.\n",
 			vf_id);
Signature · 1 line
2.9.5
#1 lore raw

PATCH 2/7 i40e: rename i40e_vlan_rx_register to i40e_setup_vlan_stripping

From: Jacob Keller <[email protected]>

We used to use the function i40e_vlan_rx_register as a way to hook into the now defunct .ndo_vlan_rx_register netdev hook. This was removed but we kept the function around because we still used it internally to control enabling or disabling of VLAN stripping.

Simplify this function and make its intent clear. Pass the *vsi pointer directly instead of the netdev pointer. Additionally, move it closer to the point where it is called in the file.

This helps clarify the functions use and purpose, and makes the code a bit easier to understand.

---
 drivers/net/ethernet/intel/i40e/i40e_main.c | 31 +++++++++++++----------------
 1 file changed, 14 insertions(+), 17 deletions(-)
drivers/net/ethernet/intel/i40e/i40e_main.c +14 -17
index 4b34bbc..31938b2 100644
@@ -2720,22 +2720,6 @@ void i40e_vlan_stripping_disable(struct i40e_vsi *vsi)
 }
 
 /**
- * i40e_vlan_rx_register - Setup or shutdown vlan offload
- * @netdev: network interface to be adjusted
- * @features: netdev features to test if VLAN offload is enabled or not
- **/
-static void i40e_vlan_rx_register(struct net_device *netdev, u32 features)
-{
-	struct i40e_netdev_priv *np = netdev_priv(netdev);
-	struct i40e_vsi *vsi = np->vsi;
-
-	if (features & NETIF_F_HW_VLAN_CTAG_RX)
-		i40e_vlan_stripping_enable(vsi);
-	else
-		i40e_vlan_stripping_disable(vsi);
-}
-
-/**
  * 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)
@@ -2900,6 +2884,19 @@ static int i40e_vlan_rx_kill_vid(struct net_device *netdev,
 }
 
 /**
+ * i40e_setup_vlan_stripping - Enable or disable VLAN stripping
+ * @vsi: the vsi being configured
+ * @features: netdevice feature flags
+ **/
+static void i40e_setup_vlan_stripping(struct i40e_vsi *vsi, u32 features)
+{
+	if (features & NETIF_F_HW_VLAN_CTAG_RX)
+		i40e_vlan_stripping_enable(vsi);
+	else
+		i40e_vlan_stripping_disable(vsi);
+}
+
+/**
  * i40e_restore_vlan - Reinstate vlans when vsi/netdev comes back up
  * @vsi: the vsi being brought back up
  **/
@@ -2910,7 +2907,7 @@ static void i40e_restore_vlan(struct i40e_vsi *vsi)
 	if (!vsi->netdev)
 		return;
 
-	i40e_vlan_rx_register(vsi->netdev, vsi->netdev->features);
+	i40e_setup_vlan_stripping(vsi, vsi->netdev->features);
 
 	for_each_set_bit(vid, vsi->active_vlans, VLAN_N_VID)
 		i40e_vlan_rx_add_vid(vsi->netdev, htons(ETH_P_8021Q),
Signature · 1 line
2.9.5
#2 lore raw

PATCH 2/7 i40e: rename i40e_vlan_rx_register to i40e_setup_vlan_stripping

Quoted 67 lines · Alice Michael

From: Jacob Keller <[email protected]>

We used to use the function i40e_vlan_rx_register as a way to hook into the now defunct .ndo_vlan_rx_register netdev hook. This was removed but we kept the function around because we still used it internally to control enabling or disabling of VLAN stripping.

Simplify this function and make its intent clear. Pass the *vsi pointer directly instead of the netdev pointer. Additionally, move it closer to the point where it is called in the file.

This helps clarify the functions use and purpose, and makes the code a bit easier to understand.

---
  drivers/net/ethernet/intel/i40e/i40e_main.c | 31 +++++++++++++----------------
  1 file changed, 14 insertions(+), 17 deletions(-)
drivers/net/ethernet/intel/i40e/i40e_main.c +13 -16
index 4b34bbc..31938b2 100644
@@ -2720,22 +2720,6 @@ void i40e_vlan_stripping_disable(struct i40e_vsi *vsi)
  }
 
  /**
- * i40e_vlan_rx_register - Setup or shutdown vlan offload
- * @netdev: network interface to be adjusted
- * @features: netdev features to test if VLAN offload is enabled or not
- **/
-static void i40e_vlan_rx_register(struct net_device *netdev, u32 features)
-{
-	struct i40e_netdev_priv *np = netdev_priv(netdev);
-	struct i40e_vsi *vsi = np->vsi;
-
-	if (features & NETIF_F_HW_VLAN_CTAG_RX)
-		i40e_vlan_stripping_enable(vsi);
-	else
-		i40e_vlan_stripping_disable(vsi);
-}
-
-/**
   * 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)
@@ -2900,6 +2884,19 @@ static int i40e_vlan_rx_kill_vid(struct net_device *netdev,
  }
 
  /**
+ * i40e_setup_vlan_stripping - Enable or disable VLAN stripping
+ * @vsi: the vsi being configured
+ * @features: netdevice feature flags
+ **/
+static void i40e_setup_vlan_stripping(struct i40e_vsi *vsi, u32 features)
+{
+	if (features & NETIF_F_HW_VLAN_CTAG_RX)
+		i40e_vlan_stripping_enable(vsi);
+	else
+		i40e_vlan_stripping_disable(vsi);
+}
+
+/**
   * i40e_restore_vlan - Reinstate vlans when vsi/netdev comes back up
   * @vsi: the vsi being brought back up
   **/

drivers/net/ethernet/intel/i40e/i40e_main.c static void i40e_restore_vlan(struct i40e_vsi *vsi) · line 2910

Quoted 5 lines
drivers/net/ethernet/intel/i40e/i40e_main.c +1 -1
@@ -2910,7 +2907,7 @@ static void i40e_restore_vlan(struct i40e_vsi *vsi)
  	if (!vsi->netdev)
  		return;
 
-	i40e_vlan_rx_register(vsi->netdev, vsi->netdev->features);
+	i40e_setup_vlan_stripping(vsi, vsi->netdev->features);

IIRC, in a response to a previous review comment, Jake said he was going to simplify this and just get rid of the i40e_setup_vlan_stripping() function and put the code here. Is that not going to happen?

sln

Quoted 4 lines
drivers/net/ethernet/intel/i40e/i40e_main.c +0 -0
  	for_each_set_bit(vid, vsi->active_vlans, VLAN_N_VID)
  		i40e_vlan_rx_add_vid(vsi->netdev, htons(ETH_P_8021Q),
 
#3 lore raw

PATCH 3/7 i40e: Fix permission check for VF MAC filters

In reply to Alice Michael

From: Filip Sadowski <[email protected]>

When VF requests adding of MAC filters the checking is done against number of already present MAC filters not adding them at the same time. It makes it possible to add a bunch of filters at once possibly exceeding acceptable limit of I40E_VC_MAX_MAC_ADDR_PER_VF filters.

This happens because when checking vf->num_mac, we do not check how many filters are being requested at once. Modify the check function to ensure that it knows how many filters are being requested. This allows the check to ensure that the total number of filters in a single request does not cause us to go over the limit.

Additionally, move the check to within the lock to ensure that the vf->num_mac is checked while holding the lock to maintain consistency. We could have simply moved the call to i40e_vf_check_permission to within the loop, but this could cause a request to be non-atomic, and add some but not all the addresses, while reporting an error code. We want to avoid this behavior so that users are not confused about which filters have or have not been added.

---
 drivers/net/ethernet/intel/i40e/i40e_main.c        | 18 ++---
 drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c | 79 ++++++++++++++--------
 2 files changed, 55 insertions(+), 42 deletions(-)
drivers/net/ethernet/intel/i40e/i40e_main.c +4 -14
index 31938b2..183c8b8 100644
@@ -2884,19 +2884,6 @@ static int i40e_vlan_rx_kill_vid(struct net_device *netdev,
 }
 
 /**
- * i40e_setup_vlan_stripping - Enable or disable VLAN stripping
- * @vsi: the vsi being configured
- * @features: netdevice feature flags
- **/
-static void i40e_setup_vlan_stripping(struct i40e_vsi *vsi, u32 features)
-{
-	if (features & NETIF_F_HW_VLAN_CTAG_RX)
-		i40e_vlan_stripping_enable(vsi);
-	else
-		i40e_vlan_stripping_disable(vsi);
-}
-
-/**
  * i40e_restore_vlan - Reinstate vlans when vsi/netdev comes back up
  * @vsi: the vsi being brought back up
  **/
@@ -2907,7 +2894,10 @@ static void i40e_restore_vlan(struct i40e_vsi *vsi)
 	if (!vsi->netdev)
 		return;
 
-	i40e_setup_vlan_stripping(vsi, vsi->netdev->features);
+	if (vsi->netdev->features & NETIF_F_HW_VLAN_CTAG_RX)
+		i40e_vlan_stripping_enable(vsi);
+	else
+		i40e_vlan_stripping_disable(vsi);
 
 	for_each_set_bit(vid, vsi->active_vlans, VLAN_N_VID)
 		i40e_vlan_rx_add_vid(vsi->netdev, htons(ETH_P_8021Q),
drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c +51 -28

109 lines not on this page · raw message

Signature · 1 line
2.9.5
#4 lore raw

PATCH 3/7 i40e: Fix permission check for VF MAC filters

Quoted 52 lines · Alice Michael

From: Filip Sadowski <[email protected]>

When VF requests adding of MAC filters the checking is done against number of already present MAC filters not adding them at the same time. It makes it possible to add a bunch of filters at once possibly exceeding acceptable limit of I40E_VC_MAX_MAC_ADDR_PER_VF filters.

This happens because when checking vf->num_mac, we do not check how many filters are being requested at once. Modify the check function to ensure that it knows how many filters are being requested. This allows the check to ensure that the total number of filters in a single request does not cause us to go over the limit.

Additionally, move the check to within the lock to ensure that the vf->num_mac is checked while holding the lock to maintain consistency. We could have simply moved the call to i40e_vf_check_permission to within the loop, but this could cause a request to be non-atomic, and add some but not all the addresses, while reporting an error code. We want to avoid this behavior so that users are not confused about which filters have or have not been added.

---
  drivers/net/ethernet/intel/i40e/i40e_main.c        | 18 ++---
  drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c | 79 ++++++++++++++--------
  2 files changed, 55 insertions(+), 42 deletions(-)
drivers/net/ethernet/intel/i40e/i40e_main.c +0 -13
index 31938b2..183c8b8 100644
@@ -2884,19 +2884,6 @@ static int i40e_vlan_rx_kill_vid(struct net_device *netdev,
  }
 
  /**
- * i40e_setup_vlan_stripping - Enable or disable VLAN stripping
- * @vsi: the vsi being configured
- * @features: netdevice feature flags
- **/
-static void i40e_setup_vlan_stripping(struct i40e_vsi *vsi, u32 features)
-{
-	if (features & NETIF_F_HW_VLAN_CTAG_RX)
-		i40e_vlan_stripping_enable(vsi);
-	else
-		i40e_vlan_stripping_disable(vsi);
-}
-
-/**
   * i40e_restore_vlan - Reinstate vlans when vsi/netdev comes back up
   * @vsi: the vsi being brought back up
   **/

drivers/net/ethernet/intel/i40e/i40e_main.c static void i40e_restore_vlan(struct i40e_vsi *vsi) · line 2900

Quoted 8 lines
drivers/net/ethernet/intel/i40e/i40e_main.c +4 -1
@@ -2907,7 +2894,10 @@ static void i40e_restore_vlan(struct i40e_vsi *vsi)
  	if (!vsi->netdev)
  		return;
 
-	i40e_setup_vlan_stripping(vsi, vsi->netdev->features);
+	if (vsi->netdev->features & NETIF_F_HW_VLAN_CTAG_RX)
+		i40e_vlan_stripping_enable(vsi);
+	else
+		i40e_vlan_stripping_disable(vsi);

Oh, here's Jake's change... probably doesn't belong here. sln

Quoted 121 lines
drivers/net/ethernet/intel/i40e/i40e_main.c +0 -0
  	for_each_set_bit(vid, vsi->active_vlans, VLAN_N_VID)
  		i40e_vlan_rx_add_vid(vsi->netdev, htons(ETH_P_8021Q),
drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c +51 -28
index 8559c09..8d9a456 100644
@@ -2369,25 +2369,47 @@ static int i40e_vc_get_stats_msg(struct i40e_vf *vf, u8 *msg, u16 msglen)
  /**
   * i40e_check_vf_permission
   * @vf: pointer to the VF info
- * @macaddr: pointer to the MAC Address being checked
+ * @al: MAC address list from virtchnl
   *
- * Check if the VF has permission to add or delete unicast MAC address
- * filters and return error code -EPERM if not.  Then check if the
- * address filter requested is broadcast or zero and if so return
- * an invalid MAC address error code.
+ * Check that the given list of MAC addresses is allowed. Will return -EPERM
+ * if any address in the list is not valid. Checks the following conditions:
+ *
+ * 1) broadcast and zero addresses are never valid
+ * 2) unicast addresses are not allowed if the VMM has administratively set
+ *    the VF MAC address, unless the VF is marked as privileged.
+ * 3) There is enough space to add all the addresses.
+ *
+ * Note that to guarantee consistency, it is expected this function be called
+ * while holding the mac_filter_hash_lock, as otherwise the current number of
+ * addresses might not be accurate.
   **/
-static inline int i40e_check_vf_permission(struct i40e_vf *vf, u8 *macaddr)
+static inline int i40e_check_vf_permission(struct i40e_vf *vf,
+					   struct virtchnl_ether_addr_list *al)
  {
  	struct i40e_pf *pf = vf->pf;
-	int ret = 0;
+	int i;
+
+	/* If this VF is not privileged, then we can't add more than a limited
+	 * number of addresses. Check to make sure that the additions do not
+	 * push us over the limit.
+	 */
+	if (!test_bit(I40E_VIRTCHNL_VF_CAP_PRIVILEGE, &vf->vf_caps) &&
+	    (vf->num_mac + al->num_elements) > I40E_VC_MAX_MAC_ADDR_PER_VF) {
+		dev_err(&pf->pdev->dev,
+			"Cannot add more MAC addresses, VF is not trusted, switch the VF to trusted to add more functionality\n");
+		return -EPERM;
+	}
+
+	for (i = 0; i < al->num_elements; i++) {
+		u8 *addr = al->list[i].addr;
+
+		if (is_broadcast_ether_addr(addr) ||
+		    is_zero_ether_addr(addr)) {
+			dev_err(&pf->pdev->dev, "invalid VF MAC addr %pM\n",
+				addr);
+			return I40E_ERR_INVALID_MAC_ADDR;
+		}
 
-	if (is_broadcast_ether_addr(macaddr) ||
-		   is_zero_ether_addr(macaddr)) {
-		dev_err(&pf->pdev->dev, "invalid VF MAC addr %pM\n", macaddr);
-		ret = I40E_ERR_INVALID_MAC_ADDR;
-	} else if (vf->pf_set_mac && !is_multicast_ether_addr(macaddr) &&
-		   !test_bit(I40E_VIRTCHNL_VF_CAP_PRIVILEGE, &vf->vf_caps) &&
-		   !ether_addr_equal(macaddr, vf->default_lan_addr.addr)) {
  		/* If the host VMM administrator has set the VF MAC address
  		 * administratively via the ndo_set_vf_mac command then deny
  		 * permission to the VF to add or delete unicast MAC addresses.
@@ -2395,16 +2417,16 @@ static inline int i40e_check_vf_permission(struct i40e_vf *vf, u8 *macaddr)
  		 * The VF may request to set the MAC address filter already
  		 * assigned to it so do not return an error in that case.
  		 */
-		dev_err(&pf->pdev->dev,
-			"VF attempting to override administratively set MAC address, reload the VF driver to resume normal operation\n");
-		ret = -EPERM;
-	} else if ((vf->num_mac >= I40E_VC_MAX_MAC_ADDR_PER_VF) &&
-		   !test_bit(I40E_VIRTCHNL_VF_CAP_PRIVILEGE, &vf->vf_caps)) {
-		dev_err(&pf->pdev->dev,
-			"VF is not trusted, switch the VF to trusted to add more functionality\n");
-		ret = -EPERM;
+		if (!test_bit(I40E_VIRTCHNL_VF_CAP_PRIVILEGE, &vf->vf_caps) &&
+		    !is_multicast_ether_addr(addr) && vf->pf_set_mac &&
+		    !ether_addr_equal(addr, vf->default_lan_addr.addr)) {
+			dev_err(&pf->pdev->dev,
+				"VF attempting to override administratively set MAC address, reload the VF driver to resume normal operation\n");
+			return -EPERM;
+		}
  	}
-	return ret;
+
+	return 0;
  }
 
  /**
@@ -2431,11 +2453,6 @@ static int i40e_vc_add_mac_addr_msg(struct i40e_vf *vf, u8 *msg, u16 msglen)
  		goto error_param;
  	}
 
-	for (i = 0; i < al->num_elements; i++) {
-		ret = i40e_check_vf_permission(vf, al->list[i].addr);
-		if (ret)
-			goto error_param;
-	}
  	vsi = pf->vsi[vf->lan_vsi_idx];
 
  	/* Lock once, because all function inside for loop accesses VSI's
@@ -2443,6 +2460,12 @@ static int i40e_vc_add_mac_addr_msg(struct i40e_vf *vf, u8 *msg, u16 msglen)
  	 */
  	spin_lock_bh(&vsi->mac_filter_hash_lock);
 
+	ret = i40e_check_vf_permission(vf, al);
+	if (ret) {
+		spin_unlock_bh(&vsi->mac_filter_hash_lock);
+		goto error_param;
+	}
+
  	/* add new addresses to the list */
  	for (i = 0; i < al->num_elements; i++) {
  		struct i40e_mac_filter *f;
#5 lore raw

PATCH 4/7 i40e: track filter type statistics when deleting invalid filters

In reply to Alice Michael

From: Jacob Keller <[email protected]>

When hardware has trouble with a particular filter, we delete it from the list. Unfortunately, we did not properly update the per-filter statistic when doing so.

Create a helper function to handle this, and properly reduce the necessary counter so that it tracks the number of active filters properly.

---
 drivers/net/ethernet/intel/i40e/i40e_main.c | 56 ++++++++++++++++++++++++-----
 1 file changed, 48 insertions(+), 8 deletions(-)
drivers/net/ethernet/intel/i40e/i40e_main.c +48 -8
index 183c8b8..0b45650 100644
@@ -8137,6 +8137,51 @@ u32 i40e_get_global_fd_count(struct i40e_pf *pf)
 }
 
 /**
+ * i40e_delete_invalid_filter - Delete an invalid FDIR filter
+ * @pf: board private structure
+ * @filter: FDir filter to remove
+ */
+static void i40e_delete_invalid_filter(struct i40e_pf *pf,
+				       struct i40e_fdir_filter *filter)
+{
+	/* Update counters */
+	pf->fdir_pf_active_filters--;
+	pf->fd_inv = 0;
+
+	switch (filter->flow_type) {
+	case TCP_V4_FLOW:
+		pf->fd_tcp4_filter_cnt--;
+		break;
+	case UDP_V4_FLOW:
+		pf->fd_udp4_filter_cnt--;
+		break;
+	case SCTP_V4_FLOW:
+		pf->fd_sctp4_filter_cnt--;
+		break;
+	case IP_USER_FLOW:
+		switch (filter->ip4_proto) {
+		case IPPROTO_TCP:
+			pf->fd_tcp4_filter_cnt--;
+			break;
+		case IPPROTO_UDP:
+			pf->fd_udp4_filter_cnt--;
+			break;
+		case IPPROTO_SCTP:
+			pf->fd_sctp4_filter_cnt--;
+			break;
+		case IPPROTO_IP:
+			pf->fd_ip4_filter_cnt--;
+			break;
+		}
+		break;
+	}
+
+	/* Remove the filter from the list and free memory */
+	hlist_del(&filter->fdir_node);
+	kfree(filter);
+}
+
+/**
  * i40e_fdir_check_and_reenable - Function to reenabe FD ATR or SB if disabled
  * @pf: board private structure
  **/
@@ -8180,14 +8225,9 @@ void i40e_fdir_check_and_reenable(struct i40e_pf *pf)
 	/* if hw had a problem adding a filter, delete it */
 	if (pf->fd_inv > 0) {
 		hlist_for_each_entry_safe(filter, node,
-					  &pf->fdir_filter_list, fdir_node) {
-			if (filter->fd_id == pf->fd_inv) {
-				hlist_del(&filter->fdir_node);
-				kfree(filter);
-				pf->fdir_pf_active_filters--;
-				pf->fd_inv = 0;
-			}
-		}
+					  &pf->fdir_filter_list, fdir_node)
+			if (filter->fd_id == pf->fd_inv)
+				i40e_delete_invalid_filter(pf, filter);
 	}
 }
 
Signature · 1 line
2.9.5
#6 lore raw

PATCH 5/7 i40e: factor out re-enable functions for ATR and SB

In reply to Alice Michael

From: Jacob Keller <[email protected]>

A future patch needs to expand on the logic for re-enabling ATR. Doing so would cause some code to break the 80-character line limit.

To reduce the level of indentation, factor out helper functions for re-enabling ATR and SB rules.

---
 drivers/net/ethernet/intel/i40e/i40e_main.c | 48 +++++++++++++++++++----------
 1 file changed, 32 insertions(+), 16 deletions(-)
drivers/net/ethernet/intel/i40e/i40e_main.c +32 -16
index 0b45650..89bcfd1 100644
@@ -8137,6 +8137,34 @@ u32 i40e_get_global_fd_count(struct i40e_pf *pf)
 }
 
 /**
+ * i40e_reenable_fdir_sb - Restore FDir SB capability
+ * @pf: board private structure
+ **/
+static void i40e_reenable_fdir_sb(struct i40e_pf *pf)
+{
+	if (pf->flags & I40E_FLAG_FD_SB_AUTO_DISABLED) {
+		pf->flags &= ~I40E_FLAG_FD_SB_AUTO_DISABLED;
+		if ((pf->flags & I40E_FLAG_FD_SB_ENABLED) &&
+		    (I40E_DEBUG_FD & pf->hw.debug_mask))
+			dev_info(&pf->pdev->dev, "FD Sideband/ntuple is being enabled since we have space in the table now\n");
+	}
+}
+
+/**
+ * i40e_reenable_fdir_atr - Restore FDir ATR capability
+ * @pf: board private structure
+ **/
+static void i40e_reenable_fdir_atr(struct i40e_pf *pf)
+{
+	if (pf->flags & I40E_FLAG_FD_ATR_AUTO_DISABLED) {
+		pf->flags &= ~I40E_FLAG_FD_ATR_AUTO_DISABLED;
+		if ((pf->flags & I40E_FLAG_FD_ATR_ENABLED) &&
+		    (I40E_DEBUG_FD & pf->hw.debug_mask))
+			dev_info(&pf->pdev->dev, "ATR is being enabled since we have space in the table and there are no conflicting ntuple rules\n");
+	}
+}
+
+/**
  * i40e_delete_invalid_filter - Delete an invalid FDIR filter
  * @pf: board private structure
  * @filter: FDir filter to remove
@@ -8199,28 +8227,16 @@ void i40e_fdir_check_and_reenable(struct i40e_pf *pf)
 	fcnt_avail = pf->fdir_pf_filter_count;
 	if ((fcnt_prog < (fcnt_avail - I40E_FDIR_BUFFER_HEAD_ROOM)) ||
 	    (pf->fd_add_err == 0) ||
-	    (i40e_get_current_atr_cnt(pf) < pf->fd_atr_cnt)) {
-		if (pf->flags & I40E_FLAG_FD_SB_AUTO_DISABLED) {
-			pf->flags &= ~I40E_FLAG_FD_SB_AUTO_DISABLED;
-			if ((pf->flags & I40E_FLAG_FD_SB_ENABLED) &&
-			    (I40E_DEBUG_FD & pf->hw.debug_mask))
-				dev_info(&pf->pdev->dev, "FD Sideband/ntuple is being enabled since we have space in the table now\n");
-		}
-	}
+	    (i40e_get_current_atr_cnt(pf) < pf->fd_atr_cnt))
+		i40e_reenable_fdir_sb(pf);
 
 	/* We should wait for even more space before re-enabling ATR.
 	 * Additionally, we cannot enable ATR as long as we still have TCP SB
 	 * rules active.
 	 */
 	if ((fcnt_prog < (fcnt_avail - I40E_FDIR_BUFFER_HEAD_ROOM_FOR_ATR)) &&
-	    (pf->fd_tcp4_filter_cnt == 0)) {
-		if (pf->flags & I40E_FLAG_FD_ATR_AUTO_DISABLED) {
-			pf->flags &= ~I40E_FLAG_FD_ATR_AUTO_DISABLED;
-			if ((pf->flags & I40E_FLAG_FD_ATR_ENABLED) &&
-			    (I40E_DEBUG_FD & pf->hw.debug_mask))
-				dev_info(&pf->pdev->dev, "ATR is being enabled since we have space in the table and there are no conflicting ntuple rules\n");
-		}
-	}
+	    (pf->fd_tcp4_filter_cnt == 0))
+		i40e_reenable_fdir_atr(pf);
 
 	/* if hw had a problem adding a filter, delete it */
 	if (pf->fd_inv > 0) {
Signature · 1 line
2.9.5
#7 lore raw

PATCH 6/7 i40e: fix for wrong partition id calculation on OCP mezz cards

In reply to Alice Michael

From: Mariusz Stachura <[email protected]>

This patch overwrites number of ports for X722 devices with support for OCP PHY mezzanine.
The old method with checking if port is disabled in the PRTGEN_CNF register cannot be used in this case. When the OCP is removed, ports were seen as disabled, which resulted in wrong calculation of partition id, that caused WoL to be disabled on certain ports.

---
 drivers/net/ethernet/intel/i40e/i40e_common.c | 23 ++++++++++++++++++++++-
 drivers/net/ethernet/intel/i40e/i40e_type.h   |  3 +++
 2 files changed, 25 insertions(+), 1 deletion(-)
drivers/net/ethernet/intel/i40e/i40e_common.c +22 -1
index 6ee3102..792d420 100644
@@ -3201,9 +3201,10 @@ static void i40e_parse_discover_capabilities(struct i40e_hw *hw, void *buff,
 	u32 valid_functions, num_functions;
 	u32 number, logical_id, phys_id;
 	struct i40e_hw_capabilities *p;
+	u16 id, ocp_cfg_word0;
+	i40e_status status;
 	u8 major_rev;
 	u32 i = 0;
-	u16 id;
 
 	cap = (struct i40e_aqc_list_capabilities_element_resp *) buff;
 
@@ -3390,6 +3391,26 @@ static void i40e_parse_discover_capabilities(struct i40e_hw *hw, void *buff,
 			hw->num_ports++;
 	}
 
+	/* OCP cards case: if a mezz is removed the ethernet port is at
+	 * disabled state in PRTGEN_CNF register. Additional NVM read is
+	 * needed in order to check if we are dealing with OCP card.
+	 * Those cards have 4 PFs at minimum, so using PRTGEN_CNF for counting
+	 * physical ports results in wrong partition id calculation and thus
+	 * not supporting WoL.
+	 */
+	if (hw->mac.type == I40E_MAC_X722) {
+		if (!i40e_acquire_nvm(hw, I40E_RESOURCE_READ)) {
+			status = i40e_aq_read_nvm(hw, I40E_SR_EMP_MODULE_PTR,
+						  2 * I40E_SR_OCP_CFG_WORD0,
+						  sizeof(ocp_cfg_word0),
+						  &ocp_cfg_word0, true, NULL);
+			if (!status &&
+			    (ocp_cfg_word0 & I40E_SR_OCP_ENABLED))
+				hw->num_ports = 4;
+			i40e_release_nvm(hw);
+		}
+	}
+
 	valid_functions = p->valid_functions;
 	num_functions = 0;
 	while (valid_functions) {
drivers/net/ethernet/intel/i40e/i40e_type.h +3 -0
index 7485bd4..7ff2c6d 100644
@@ -1337,6 +1337,9 @@ struct i40e_hw_port_stats {
 #define I40E_SR_PCIE_ALT_MODULE_MAX_SIZE	1024
 #define I40E_SR_CONTROL_WORD_1_SHIFT		0x06
 #define I40E_SR_CONTROL_WORD_1_MASK	(0x03 << I40E_SR_CONTROL_WORD_1_SHIFT)
+#define I40E_PTR_TYPE				BIT(15)
+#define I40E_SR_OCP_CFG_WORD0			0x2B
+#define I40E_SR_OCP_ENABLED			BIT(15)
 
 /* Shadow RAM related */
 #define I40E_SR_SECTOR_SIZE_IN_WORDS	0x800
Signature · 1 line
2.9.5
#8 lore raw

PATCH 7/7 i40e: restore TCPv4 input set when re-enabling ATR

In reply to Alice Michael

From: Jacob Keller <[email protected]>

When we re-enable ATR we need to restore the input set for TCPv4 filters, in order for ATR to function correctly. We already do this for the normal case of re-enabling ATR when disabling ntuple support. However, when re-enabling ATR after the last tcp4 filter is removed (but when ntuple support is still active), we did not restore the TCPv4 filter input set.

This can cause problems if the TCPv4 filters from FDir had changed the input set, as ATR will no longer behave as expected.

When clearing the ATR auto-disable flag, make sure we restore the TCPv4 input set to avoid this.

---
 drivers/net/ethernet/intel/i40e/i40e_main.c | 9 +++++++++
 1 file changed, 9 insertions(+)
drivers/net/ethernet/intel/i40e/i40e_main.c +9 -0
index 89bcfd1..0df21e4 100644
@@ -8157,6 +8157,15 @@ static void i40e_reenable_fdir_sb(struct i40e_pf *pf)
 static void i40e_reenable_fdir_atr(struct i40e_pf *pf)
 {
 	if (pf->flags & I40E_FLAG_FD_ATR_AUTO_DISABLED) {
+		/* ATR uses the same filtering logic as SB rules. It only
+		 * functions properly if the input set mask is at the default
+		 * settings. It is safe to restore the default input set
+		 * because there are no active TCPv4 filter rules.
+		 */
+		i40e_write_fd_input_set(pf, I40E_FILTER_PCTYPE_NONF_IPV4_TCP,
+					I40E_L3_SRC_MASK | I40E_L3_DST_MASK |
+					I40E_L4_SRC_MASK | I40E_L4_DST_MASK);
+
 		pf->flags &= ~I40E_FLAG_FD_ATR_AUTO_DISABLED;
 		if ((pf->flags & I40E_FLAG_FD_ATR_ENABLED) &&
 		    (I40E_DEBUG_FD & pf->hw.debug_mask))
Signature · 1 line
2.9.5