Index: sys/dev/e1000/if_em.c =================================================================== --- sys/dev/e1000/if_em.c +++ sys/dev/e1000/if_em.c @@ -1340,23 +1340,8 @@ 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)); @@ -3411,6 +3396,7 @@ bit = vtag & 0x1F; adapter->shadow_vfta[index] |= (1 << bit); ++adapter->num_vlans; + em_setup_vlan_hw_support(adapter); } static void @@ -3423,11 +3409,13 @@ bit = vtag & 0x1F; adapter->shadow_vfta[index] &= ~(1 << bit); --adapter->num_vlans; + em_setup_vlan_hw_support(adapter); } static void em_setup_vlan_hw_support(struct adapter *adapter) { + struct ifnet *ifp = iflib_get_ifp(adapter->ctx); struct e1000_hw *hw = &adapter->hw; u32 reg; @@ -3440,24 +3428,54 @@ if (adapter->num_vlans == 0) return; + if (adapter->vf_ifp) { + e1000_rlpml_set_vf(hw, + adapter->shared->isc_max_frame_size + VLAN_TAG_SIZE); + return; + } + + if (ifp->if_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 ((ifp->if_capenable & IFCAP_VLAN_HWFILTER) == 0 || + em_disable_crc_stripping) + return; + + /* Disable interrupts for lem-class devices during the filter change */ + if (hw->mac.type < em_mac_min) + em_if_intr_disable(adapter->ctx); + /* * 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); + for (int i = 0; i < EM_VFTA_SIZE; i++) + if (adapter->shadow_vfta[i] != 0) { + if (adapter->vf_ifp) + e1000_vfta_set_vf(hw, adapter->shadow_vfta[i], TRUE); + else + e1000_write_vfta(hw, i, adapter->shadow_vfta[i]); + } /* 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); + + /* Re-enable interrupts for lem-class devices */ + if (hw->mac.type < em_mac_min) + em_if_intr_enable(adapter->ctx); } static void @@ -4088,6 +4106,7 @@ { switch (event) { case IFLIB_RESTART_VLAN_CONFIG: + return (false); default: return (true); }