git: d239e11a57c9 - stable/12 - e1000: Fix up HW vlan ops

Kevin Bowling kbowling at FreeBSD.org
Tue Sep 28 16:35:28 UTC 2021


The branch stable/12 has been updated by kbowling (ports committer):

URL: https://cgit.FreeBSD.org/src/commit/?id=d239e11a57c9b4ebc5e4289a8520511bb7b40b2d

commit d239e11a57c9b4ebc5e4289a8520511bb7b40b2d
Author:     Kevin Bowling <kbowling at FreeBSD.org>
AuthorDate: 2021-09-15 14:47:19 +0000
Commit:     Kevin Bowling <kbowling at FreeBSD.org>
CommitDate: 2021-09-28 16:34:18 +0000

    e1000: Fix up HW vlan ops
    
    2796f7ca:
    * Don't reset the entire adapter for vlan changes, fix up the problems
    * Add some functions for vlan filter (vfta) manipulation
    * Don't muck with the vfta if we aren't doing HW vlan filtering
    * Disable interrupts when manipulating vfta on lem(4)-class NICs
    * On the I350 there is a specification update (2.4.20) in which the
    suggested workaround is to write to the vfta 10 times (if at first you
    don't succeed, try, try again). Our shared code has the goods, use it
    * Increase a VF's frame receive size in the case of vlans
    
    From the referenced PR, this reduced vlan configuration from minutes
    to seconds with hundreds or thousands of vlans and prevents wedging the
    adapter with needless adapter reinitialization for each vlan ID.
    
    PR:             230996
    Reviewed by:    markj
    Tested by:      Ozkan KIRIK <ozkan.kirik at gmail.com>
    Differential Revision:  https://reviews.freebsd.org/D30002
    
    22b20b45:
    e1000: Fix variable typo
    
    Forgot to git add this in last commit
    
    Reported by:    jenkins
    Fixes:          2796f7cab107
    
    (cherry picked from commit 2796f7cab10785ef40efbba97ef67ab319c96e9c)
    (cherry picked from commit 22b20b45c9118bf6ef313c074cdb107a1eaca78e)
---
 sys/dev/e1000/if_em.c | 166 ++++++++++++++++++++++++++++++++++++++------------
 1 file changed, 126 insertions(+), 40 deletions(-)

diff --git a/sys/dev/e1000/if_em.c b/sys/dev/e1000/if_em.c
index ce13d57da60b..68937925a2aa 100644
--- a/sys/dev/e1000/if_em.c
+++ b/sys/dev/e1000/if_em.c
@@ -297,6 +297,11 @@ static void	em_if_debug(if_ctx_t ctx);
 static void	em_update_stats_counters(struct adapter *);
 static void	em_add_hw_stats(struct adapter *adapter);
 static int	em_if_set_promisc(if_ctx_t ctx, int flags);
+static bool	em_if_vlan_filter_capable(struct adapter *);
+static bool	em_if_vlan_filter_used(struct adapter *);
+static void	em_if_vlan_filter_enable(struct adapter *);
+static void	em_if_vlan_filter_disable(struct adapter *);
+static void	em_if_vlan_filter_write(struct adapter *);
 static void	em_setup_vlan_hw_support(struct adapter *);
 static int	em_sysctl_nvm_info(SYSCTL_HANDLER_ARGS);
 static void	em_print_nvm_info(struct adapter *);
@@ -909,6 +914,9 @@ em_if_attach_pre(if_ctx_t ctx)
 		scctx->isc_capabilities = scctx->isc_capenable = LEM_CAPS;
 		if (hw->mac.type < e1000_82543)
 			scctx->isc_capenable &= ~(IFCAP_HWCSUM|IFCAP_VLAN_HWCSUM);
+		/* 82541ER doesn't do HW tagging */
+		if (hw->device_id == E1000_DEV_ID_82541ER || hw->device_id == E1000_DEV_ID_82541ER_LOM)
+			scctx->isc_capenable &= ~IFCAP_VLAN_HWTAGGING;
 		/* INTx only */
 		scctx->isc_msix_bar = 0;
 	}
@@ -1341,23 +1349,8 @@ em_if_init(if_ctx_t ctx)
 	adapter->rx_mbuf_sz = iflib_get_rx_mbuf_sz(ctx);
 	em_initialize_receive_unit(ctx);
 
-	/* Use real VLAN Filter support? */
-	if (if_getcapenable(ifp) & IFCAP_VLAN_HWTAGGING) {
-		if (if_getcapenable(ifp) & IFCAP_VLAN_HWFILTER)
-			/* Use real VLAN Filter support */
-			em_setup_vlan_hw_support(adapter);
-		else {
-			u32 ctrl;
-			ctrl = E1000_READ_REG(&adapter->hw, E1000_CTRL);
-			ctrl |= E1000_CTRL_VME;
-			E1000_WRITE_REG(&adapter->hw, E1000_CTRL, ctrl);
-		}
-	} else {
-		u32 ctrl;
-		ctrl = E1000_READ_REG(&adapter->hw, E1000_CTRL);
-		ctrl &= ~E1000_CTRL_VME;
-		E1000_WRITE_REG(&adapter->hw, E1000_CTRL, ctrl);
-	}
+	/* Set up VLAN support and filter */
+	em_setup_vlan_hw_support(adapter);
 
 	/* Don't lose promiscuous settings */
 	em_if_set_promisc(ctx, if_getflags(ifp));
@@ -1676,14 +1669,19 @@ em_if_set_promisc(if_ctx_t ctx, int flags)
 
 	if (flags & IFF_PROMISC) {
 		reg_rctl |= (E1000_RCTL_UPE | E1000_RCTL_MPE);
+		em_if_vlan_filter_disable(adapter);
 		/* Turn this on if you want to see bad packets */
 		if (em_debug_sbp)
 			reg_rctl |= E1000_RCTL_SBP;
 		E1000_WRITE_REG(&adapter->hw, E1000_RCTL, reg_rctl);
-	} else if (flags & IFF_ALLMULTI) {
-		reg_rctl |= E1000_RCTL_MPE;
-		reg_rctl &= ~E1000_RCTL_UPE;
-		E1000_WRITE_REG(&adapter->hw, E1000_RCTL, reg_rctl);
+	} else {
+		if (flags & IFF_ALLMULTI) {
+			reg_rctl |= E1000_RCTL_MPE;
+			reg_rctl &= ~E1000_RCTL_UPE;
+			E1000_WRITE_REG(&adapter->hw, E1000_RCTL, reg_rctl);
+		}
+		if (em_if_vlan_filter_used(adapter))
+			em_if_vlan_filter_enable(adapter);
 	}
 	return (0);
 }
@@ -3322,7 +3320,11 @@ em_initialize_receive_unit(if_ctx_t ctx)
 			/* are we on a vlan? */
 			if (ifp->if_vlantrunk != NULL)
 				psize += VLAN_TAG_SIZE;
-			E1000_WRITE_REG(hw, E1000_RLPML, psize);
+
+			if (adapter->vf_ifp)
+				e1000_rlpml_set_vf(hw, psize);
+			else
+				E1000_WRITE_REG(hw, E1000_RLPML, psize);
 		}
 
 		/* Set maximum packet buffer len */
@@ -3419,6 +3421,7 @@ em_if_vlan_register(if_ctx_t ctx, u16 vtag)
 	bit = vtag & 0x1F;
 	adapter->shadow_vfta[index] |= (1 << bit);
 	++adapter->num_vlans;
+	em_if_vlan_filter_write(adapter);
 }
 
 static void
@@ -3431,41 +3434,121 @@ em_if_vlan_unregister(if_ctx_t ctx, u16 vtag)
 	bit = vtag & 0x1F;
 	adapter->shadow_vfta[index] &= ~(1 << bit);
 	--adapter->num_vlans;
+	em_if_vlan_filter_write(adapter);
+}
+
+static bool
+em_if_vlan_filter_capable(struct adapter *adapter)
+{
+	if_softc_ctx_t scctx = adapter->shared;
+
+	if ((scctx->isc_capenable & IFCAP_VLAN_HWFILTER) &&
+	    !em_disable_crc_stripping)
+		return (true);
+
+	return (false);
+}
+
+static bool
+em_if_vlan_filter_used(struct adapter *adapter)
+{
+	if (!em_if_vlan_filter_capable(adapter))
+		return (false);
+
+	for (int i = 0; i < EM_VFTA_SIZE; i++)
+		if (adapter->shadow_vfta[i] != 0)
+			return (true);
+
+	return (false);
+}
+
+static void
+em_if_vlan_filter_enable(struct adapter *adapter)
+{
+	struct e1000_hw *hw = &adapter->hw;
+	u32 reg;
+
+	reg = E1000_READ_REG(hw, E1000_RCTL);
+	reg &= ~E1000_RCTL_CFIEN;
+	reg |= E1000_RCTL_VFE;
+	E1000_WRITE_REG(hw, E1000_RCTL, reg);
+}
+
+static void
+em_if_vlan_filter_disable(struct adapter *adapter)
+{
+	struct e1000_hw *hw = &adapter->hw;
+	u32 reg;
+
+	reg = E1000_READ_REG(hw, E1000_RCTL);
+	reg &= ~(E1000_RCTL_VFE | E1000_RCTL_CFIEN);
+	E1000_WRITE_REG(hw, E1000_RCTL, reg);
+}
+
+static void
+em_if_vlan_filter_write(struct adapter *adapter)
+{
+	struct e1000_hw *hw = &adapter->hw;
+
+	if (adapter->vf_ifp)
+		return;
+
+	/* Disable interrupts for lem-class devices during the filter change */
+	if (hw->mac.type < em_mac_min)
+		em_if_intr_disable(adapter->ctx);
+
+	for (int i = 0; i < EM_VFTA_SIZE; i++)
+		if (adapter->shadow_vfta[i] != 0) {
+			/* XXXKB: incomplete VF support, we return early above */
+			if (adapter->vf_ifp)
+				e1000_vfta_set_vf(hw, adapter->shadow_vfta[i], TRUE);
+			else
+				e1000_write_vfta(hw, i, adapter->shadow_vfta[i]);
+		}
+
+	/* Re-enable interrupts for lem-class devices */
+	if (hw->mac.type < em_mac_min)
+		em_if_intr_enable(adapter->ctx);
 }
 
 static void
 em_setup_vlan_hw_support(struct adapter *adapter)
 {
+	if_softc_ctx_t scctx = adapter->shared;
 	struct e1000_hw *hw = &adapter->hw;
 	u32 reg;
 
-	/*
-	 * We get here thru init_locked, meaning
-	 * a soft reset, this has already cleared
-	 * the VFTA and other state, so if there
-	 * have been no vlan's registered do nothing.
+	/* XXXKB: Return early if we are a VF until VF decap and filter management
+	 * is ready and tested.
 	 */
-	if (adapter->num_vlans == 0)
+	if (adapter->vf_ifp)
+		return;
+
+	if (scctx->isc_capenable & IFCAP_VLAN_HWTAGGING &&
+	    !em_disable_crc_stripping) {
+		reg = E1000_READ_REG(hw, E1000_CTRL);
+		reg |= E1000_CTRL_VME;
+		E1000_WRITE_REG(hw, E1000_CTRL, reg);
+	} else {
+		reg = E1000_READ_REG(hw, E1000_CTRL);
+		reg &= ~E1000_CTRL_VME;
+		E1000_WRITE_REG(hw, E1000_CTRL, reg);
+	}
+
+	/* If we aren't doing HW filtering, we're done */
+	if (!em_if_vlan_filter_capable(adapter))  {
+		em_if_vlan_filter_disable(adapter);
 		return;
+	}
 
 	/*
 	 * A soft reset zero's out the VFTA, so
 	 * we need to repopulate it now.
 	 */
-	for (int i = 0; i < EM_VFTA_SIZE; i++)
-		if (adapter->shadow_vfta[i] != 0)
-			E1000_WRITE_REG_ARRAY(hw, E1000_VFTA,
-			    i, adapter->shadow_vfta[i]);
-
-	reg = E1000_READ_REG(hw, E1000_CTRL);
-	reg |= E1000_CTRL_VME;
-	E1000_WRITE_REG(hw, E1000_CTRL, reg);
+	em_if_vlan_filter_write(adapter);
 
 	/* Enable the Filter Table */
-	reg = E1000_READ_REG(hw, E1000_RCTL);
-	reg &= ~E1000_RCTL_CFIEN;
-	reg |= E1000_RCTL_VFE;
-	E1000_WRITE_REG(hw, E1000_RCTL, reg);
+	em_if_vlan_filter_enable(adapter);
 }
 
 static void
@@ -3480,6 +3563,7 @@ em_if_intr_enable(if_ctx_t ctx)
 		ims_mask |= adapter->ims;
 	}
 	E1000_WRITE_REG(hw, E1000_IMS, ims_mask);
+	E1000_WRITE_FLUSH(hw);
 }
 
 static void
@@ -3491,6 +3575,7 @@ em_if_intr_disable(if_ctx_t ctx)
 	if (adapter->intr_type == IFLIB_INTR_MSIX)
 		E1000_WRITE_REG(hw, EM_EIAC, 0);
 	E1000_WRITE_REG(hw, E1000_IMC, 0xffffffff);
+	E1000_WRITE_FLUSH(hw);
 }
 
 static void
@@ -4096,6 +4181,7 @@ em_if_needs_restart(if_ctx_t ctx __unused, enum iflib_restart_event event)
 {
 	switch (event) {
 	case IFLIB_RESTART_VLAN_CONFIG:
+		return (false);
 	default:
 		return (true);
 	}


More information about the dev-commits-src-all mailing list