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