Date: Tue, 28 Sep 2021 16:33:16 GMT From: Kevin Bowling <kbowling@FreeBSD.org> To: src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-branches@FreeBSD.org Subject: git: 9c6432dc4bb9 - stable/13 - e1000: Fix up HW vlan ops Message-ID: <202109281633.18SGXGf7008166@gitrepo.freebsd.org>
next in thread | raw e-mail | index | archive | help
The branch stable/13 has been updated by kbowling (ports committer): URL: https://cgit.FreeBSD.org/src/commit/?id=9c6432dc4bb936f0842d766d8b3b19dfcde15da2 commit 9c6432dc4bb936f0842d766d8b3b19dfcde15da2 Author: Kevin Bowling <kbowling@FreeBSD.org> AuthorDate: 2021-09-15 14:47:19 +0000 Commit: Kevin Bowling <kbowling@FreeBSD.org> CommitDate: 2021-09-28 16:31:52 +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@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 5b7437fc5a58..6942fd47b471 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; } @@ -1338,23 +1346,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)); @@ -1673,14 +1666,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); } @@ -3326,7 +3324,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 */ @@ -3423,6 +3425,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 @@ -3435,41 +3438,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 @@ -3484,6 +3567,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 @@ -3495,6 +3579,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 @@ -4100,6 +4185,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); }
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?202109281633.18SGXGf7008166>