Index: sys/dev/igc/if_igc.c =================================================================== --- sys/dev/igc/if_igc.c +++ sys/dev/igc/if_igc.c @@ -117,6 +117,11 @@ static void igc_update_stats_counters(struct igc_adapter *); static void igc_add_hw_stats(struct igc_adapter *adapter); static int igc_if_set_promisc(if_ctx_t ctx, int flags); +static bool igc_if_vlan_filter_capable(struct igc_adapter *); +static bool igc_if_vlan_filter_used(struct igc_adapter *); +static void igc_if_vlan_filter_enable(struct igc_adapter *); +static void igc_if_vlan_filter_disable(struct igc_adapter *); +static void igc_if_vlan_filter_write(struct igc_adapter *); static void igc_setup_vlan_hw_support(struct igc_adapter *); static int igc_sysctl_nvm_info(SYSCTL_HANDLER_ARGS); static void igc_print_nvm_info(struct igc_adapter *); @@ -844,18 +849,8 @@ adapter->rx_mbuf_sz = iflib_get_rx_mbuf_sz(ctx); igc_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 */ - igc_setup_vlan_hw_support(adapter); - else { - u32 ctrl; - ctrl = IGC_READ_REG(&adapter->hw, IGC_CTRL); - ctrl |= IGC_CTRL_VME; - IGC_WRITE_REG(&adapter->hw, IGC_CTRL, ctrl); - } - } + /* Set up VLAN support and filter */ + igc_setup_vlan_hw_support(adapter); /* Don't lose promiscuous settings */ igc_if_set_promisc(ctx, IFF_PROMISC); @@ -1112,14 +1107,19 @@ if (flags & IFF_PROMISC) { reg_rctl |= (IGC_RCTL_UPE | IGC_RCTL_MPE); + igc_if_vlan_filter_disable(adapter); /* Turn this on if you want to see bad packets */ if (igc_debug_sbp) reg_rctl |= IGC_RCTL_SBP; IGC_WRITE_REG(&adapter->hw, IGC_RCTL, reg_rctl); - } else if (flags & IFF_ALLMULTI) { - reg_rctl |= IGC_RCTL_MPE; - reg_rctl &= ~IGC_RCTL_UPE; - IGC_WRITE_REG(&adapter->hw, IGC_RCTL, reg_rctl); + } else { + if (flags & IFF_ALLMULTI) { + reg_rctl |= IGC_RCTL_MPE; + reg_rctl &= ~IGC_RCTL_UPE; + IGC_WRITE_REG(&adapter->hw, IGC_RCTL, reg_rctl); + } + if (igc_if_vlan_filter_used(adapter)) + igc_if_vlan_filter_enable(adapter); } return (0); } @@ -2147,6 +2147,7 @@ bit = vtag & 0x1F; adapter->shadow_vfta[index] |= (1 << bit); ++adapter->num_vlans; + igc_if_vlan_filter_write(adapter); } static void @@ -2159,41 +2160,100 @@ bit = vtag & 0x1F; adapter->shadow_vfta[index] &= ~(1 << bit); --adapter->num_vlans; + igc_if_vlan_filter_write(adapter); +} + +static bool +igc_if_vlan_filter_capable(struct igc_adapter *adapter) +{ + if_softc_ctx_t scctx = adapter->shared; + + if ((scctx->isc_capenable & IFCAP_VLAN_HWFILTER) && + !igc_disable_crc_stripping) + return (true); + + return (false); +} + +static bool +igc_if_vlan_filter_used(struct igc_adapter *adapter) +{ + if (!igc_if_vlan_filter_capable(adapter)) + return (false); + + for (int i = 0; i < IGC_VFTA_SIZE; i++) + if (adapter->shadow_vfta[i] != 0) + return (true); + + return (false); +} + +static void +igc_if_vlan_filter_enable(struct igc_adapter *adapter) +{ + struct igc_hw *hw = &adapter->hw; + u32 reg; + + reg = IGC_READ_REG(hw, IGC_RCTL); + reg &= ~IGC_RCTL_CFIEN; + reg |= IGC_RCTL_VFE; + IGC_WRITE_REG(hw, IGC_RCTL, reg); +} + +static void +igc_if_vlan_filter_disable(struct igc_adapter *adapter) +{ + struct igc_hw *hw = &adapter->hw; + u32 reg; + + reg = IGC_READ_REG(hw, IGC_RCTL); + reg &= ~(IGC_RCTL_VFE | IGC_RCTL_CFIEN); + IGC_WRITE_REG(hw, IGC_RCTL, reg); +} + +static void +igc_if_vlan_filter_write(struct igc_adapter *adapter) +{ + struct igc_hw *hw = &adapter->hw; + + for (int i = 0; i < IGC_VFTA_SIZE; i++) + if (adapter->shadow_vfta[i] != 0) { + igc_write_vfta(hw, i, adapter->shadow_vfta[i]); + } } static void igc_setup_vlan_hw_support(struct igc_adapter *adapter) { + if_softc_ctx_t scctx = adapter->shared; struct igc_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. - */ - if (adapter->num_vlans == 0) + if (scctx->isc_capenable & IFCAP_VLAN_HWTAGGING && + !igc_disable_crc_stripping) { + reg = IGC_READ_REG(hw, IGC_CTRL); + reg |= IGC_CTRL_VME; + IGC_WRITE_REG(hw, IGC_CTRL, reg); + } else { + reg = IGC_READ_REG(hw, IGC_CTRL); + reg &= ~IGC_CTRL_VME; + IGC_WRITE_REG(hw, IGC_CTRL, reg); + } + + /* If we aren't doing HW filtering, we're done */ + if (!igc_if_vlan_filter_capable(adapter)) { + igc_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 < IGC_VFTA_SIZE; i++) - if (adapter->shadow_vfta[i] != 0) - IGC_WRITE_REG_ARRAY(hw, IGC_VFTA, - i, adapter->shadow_vfta[i]); - - reg = IGC_READ_REG(hw, IGC_CTRL); - reg |= IGC_CTRL_VME; - IGC_WRITE_REG(hw, IGC_CTRL, reg); + igc_if_vlan_filter_write(adapter); /* Enable the Filter Table */ - reg = IGC_READ_REG(hw, IGC_RCTL); - reg &= ~IGC_RCTL_CFIEN; - reg |= IGC_RCTL_VFE; - IGC_WRITE_REG(hw, IGC_RCTL, reg); + igc_if_vlan_filter_enable(adapter); } static void @@ -2469,6 +2529,7 @@ { switch (event) { case IFLIB_RESTART_VLAN_CONFIG: + return (false); default: return (true); }