git: 2796f7cab107 - main - e1000: Fix up HW vlan ops

Kevin Bowling kevin.bowling at kev009.com
Thu Sep 16 15:32:43 UTC 2021


PR mentioned should have been 258258 with 230996 as a partial

On Wed, Sep 15, 2021 at 10:33 PM Kevin Bowling <kbowling at freebsd.org> wrote:
>
> The branch main has been updated by kbowling (ports committer):
>
> URL: https://cgit.FreeBSD.org/src/commit/?id=2796f7cab10785ef40efbba97ef67ab319c96e9c
>
> commit 2796f7cab10785ef40efbba97ef67ab319c96e9c
> 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-15 15:03:01 +0000
>
>     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 at gmail.com>
>     MFC after:      2 weeks
>     Differential Revision:  https://reviews.freebsd.org/D30002
> ---
>  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 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);
>         }
> _______________________________________________
> dev-commits-src-main at freebsd.org mailing list
> https://lists.freebsd.org/mailman/listinfo/dev-commits-src-main
> To unsubscribe, send any mail to "dev-commits-src-main-unsubscribe at freebsd.org"


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