aboutsummaryrefslogtreecommitdiff
path: root/sys/dev/e1000
diff options
context:
space:
mode:
authorKevin Bowling <kbowling@FreeBSD.org>2021-09-15 14:47:19 +0000
committerKevin Bowling <kbowling@FreeBSD.org>2021-09-15 15:03:01 +0000
commit2796f7cab10785ef40efbba97ef67ab319c96e9c (patch)
treeff5c3202a6f88dd1ad615fc888caa5df836d4c3e /sys/dev/e1000
parentb51f8bae570b4e908191a1dae9da38aacf8c0fab (diff)
downloadsrc-2796f7cab10785ef40efbba97ef67ab319c96e9c.tar.gz
src-2796f7cab10785ef40efbba97ef67ab319c96e9c.zip
e1000: Fix up HW vlan ops
* 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@gmail.com> MFC after: 2 weeks Differential Revision: https://reviews.freebsd.org/D30002
Diffstat (limited to 'sys/dev/e1000')
-rw-r--r--sys/dev/e1000/if_em.c166
1 files changed, 126 insertions, 40 deletions
diff --git a/sys/dev/e1000/if_em.c b/sys/dev/e1000/if_em.c
index 6e3a8f73190f..7900e550c55f 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 *);
@@ -906,6 +911,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;
}
@@ -1335,23 +1343,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));
@@ -1670,14 +1663,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);
}
@@ -3323,7 +3321,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, pszie);
+ else
+ E1000_WRITE_REG(hw, E1000_RLPML, psize);
}
/* Set maximum packet buffer len */
@@ -3420,6 +3422,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
@@ -3432,41 +3435,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
@@ -3481,6 +3564,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
@@ -3492,6 +3576,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
@@ -4101,6 +4186,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);
}