From accb2dabd423aedef14ca20999087d18b27b4482 Mon Sep 17 00:00:00 2001 From: ryo Date: Mon, 10 Feb 2020 05:53:11 +0000 Subject: [PATCH] add support VLAN HW filter --- share/man/man4/aq.4 | 9 ++---- sys/dev/pci/if_aq.c | 78 ++++++++++++++++++++++++++++++++++++++------- 2 files changed, 69 insertions(+), 18 deletions(-) diff --git a/share/man/man4/aq.4 b/share/man/man4/aq.4 index 2a696ae79c93..199847bb965f 100644 --- a/share/man/man4/aq.4 +++ b/share/man/man4/aq.4 @@ -1,4 +1,4 @@ -.\" $NetBSD: aq.4,v 1.2 2020/01/01 20:13:19 wiz Exp $ +.\" $NetBSD: aq.4,v 1.3 2020/02/10 05:53:11 ryo Exp $ .\" .\" Copyright (c) 2020 Ryo Shimizu .\" All rights reserved. @@ -24,7 +24,7 @@ .\" IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE .\" POSSIBILITY OF SUCH DAMAGE. .\" -.Dd January 1, 2020 +.Dd February 10, 2020 .Dt AQ 4 .Os .Sh NAME @@ -71,6 +71,7 @@ D109 2.5 Gigabit Network Adapter .Xr ifmedia 4 , .Xr netintro 4 , .Xr pci 4 , +.Xr vlan 4 , .Xr ifconfig 8 .Sh HISTORY The @@ -80,7 +81,3 @@ driver first appeared in and is based on the .Fx driver of the same name, but has been drastically rewritten by Ryo Shimizu. -.Sh BUGS -The -.Nm -driver does not support the VLAN hardware filter. diff --git a/sys/dev/pci/if_aq.c b/sys/dev/pci/if_aq.c index cd5181875b20..51aec472bb4e 100644 --- a/sys/dev/pci/if_aq.c +++ b/sys/dev/pci/if_aq.c @@ -1,4 +1,4 @@ -/* $NetBSD: if_aq.c,v 1.9 2020/02/10 05:07:28 ryo Exp $ */ +/* $NetBSD: if_aq.c,v 1.10 2020/02/10 05:53:12 ryo Exp $ */ /** * aQuantia Corporation Network Driver @@ -62,7 +62,7 @@ */ #include -__KERNEL_RCSID(0, "$NetBSD: if_aq.c,v 1.9 2020/02/10 05:07:28 ryo Exp $"); +__KERNEL_RCSID(0, "$NetBSD: if_aq.c,v 1.10 2020/02/10 05:53:12 ryo Exp $"); #ifdef _KERNEL_OPT #include "opt_if_aq.h" @@ -1051,6 +1051,7 @@ static int aq_establish_msix_intr(struct aq_softc *, bool, bool); static int aq_ifmedia_change(struct ifnet * const); static void aq_ifmedia_status(struct ifnet * const, struct ifmediareq *); +static int aq_vlan_cb(struct ethercom *ec, uint16_t vid, bool set); static int aq_ifflags_cb(struct ethercom *); static int aq_init(struct ifnet *); static void aq_send_common_locked(struct ifnet *, struct aq_softc *, @@ -1404,14 +1405,15 @@ aq_attach(device_t parent, device_t self, void *aux) #if notyet /* TODO */ sc->sc_ethercom.ec_capabilities |= ETHERCAP_EEE; - sc->sc_ethercom.ec_capabilities |= ETHERCAP_VLAN_HWFILTER; #endif sc->sc_ethercom.ec_capabilities |= ETHERCAP_JUMBO_MTU | ETHERCAP_VLAN_MTU | - ETHERCAP_VLAN_HWTAGGING; + ETHERCAP_VLAN_HWTAGGING | + ETHERCAP_VLAN_HWFILTER; sc->sc_ethercom.ec_capenable |= - ETHERCAP_VLAN_HWTAGGING; + ETHERCAP_VLAN_HWTAGGING | + ETHERCAP_VLAN_HWFILTER; ifp->if_capabilities = 0; ifp->if_capenable = 0; @@ -1446,6 +1448,7 @@ aq_attach(device_t parent, device_t self, void *aux) if_attach(ifp); if_deferred_start_init(ifp, NULL); ether_ifattach(ifp, sc->sc_enaddr.ether_addr_octet); + ether_set_vlan_cb(&sc->sc_ethercom, aq_vlan_cb); ether_set_ifflags_cb(&sc->sc_ethercom, aq_ifflags_cb); aq_enable_intr(sc, true, false); /* only intr about link */ @@ -2944,7 +2947,7 @@ aq_hw_init_rx_path(struct aq_softc *sc) ETHERTYPE_QINQ); AQ_WRITE_REG_BIT(sc, RPF_VLAN_TPID_REG, RPF_VLAN_TPID_INNER, ETHERTYPE_VLAN); - AQ_WRITE_REG_BIT(sc, RPF_VLAN_MODE_REG, RPF_VLAN_MODE_PROMISC, 1); + AQ_WRITE_REG_BIT(sc, RPF_VLAN_MODE_REG, RPF_VLAN_MODE_PROMISC, 0); if (sc->sc_features & FEATURES_REV_B) { AQ_WRITE_REG_BIT(sc, RPF_VLAN_MODE_REG, @@ -3216,18 +3219,55 @@ aq_hw_l3_filter_set(struct aq_softc *sc) } static void -aq_update_vlan_filters(struct aq_softc *sc) +aq_set_vlan_filters(struct aq_softc *sc) { - /* XXX: notyet. vlan always promisc */ + struct ethercom *ec = &sc->sc_ethercom; + struct ifnet *ifp = &sc->sc_ethercom.ec_if; + struct vlanid_list *vlanidp; int i; - for (i = 0; i < RPF_VLAN_MAX_FILTERS; i++) { + ETHER_LOCK(ec); + + /* disable all vlan filters */ + for (i = 0; i < RPF_VLAN_MAX_FILTERS; i++) + AQ_WRITE_REG(sc, RPF_VLAN_FILTER_REG(i), 0); + + /* count VID */ + i = 0; + SIMPLEQ_FOREACH(vlanidp, &ec->ec_vids, vid_list) + i++; + + if (((sc->sc_ethercom.ec_capenable & ETHERCAP_VLAN_HWFILTER) == 0) || + (ifp->if_flags & IFF_PROMISC) || + (i > RPF_VLAN_MAX_FILTERS)) { + /* + * no vlan hwfilter, in promiscuous mode, or too many VID? + * must receive all VID + */ + AQ_WRITE_REG_BIT(sc, RPF_VLAN_MODE_REG, + RPF_VLAN_MODE_PROMISC, 1); + goto done; + } + + /* receive only selected VID */ + AQ_WRITE_REG_BIT(sc, RPF_VLAN_MODE_REG, RPF_VLAN_MODE_PROMISC, 0); + i = 0; + SIMPLEQ_FOREACH(vlanidp, &ec->ec_vids, vid_list) { AQ_WRITE_REG_BIT(sc, RPF_VLAN_FILTER_REG(i), - RPF_VLAN_FILTER_EN, 0); + RPF_VLAN_FILTER_EN, 1); AQ_WRITE_REG_BIT(sc, RPF_VLAN_FILTER_REG(i), RPF_VLAN_FILTER_RXQ_EN, 0); + AQ_WRITE_REG_BIT(sc, RPF_VLAN_FILTER_REG(i), + RPF_VLAN_FILTER_RXQ, 0); + AQ_WRITE_REG_BIT(sc, RPF_VLAN_FILTER_REG(i), + RPF_VLAN_FILTER_ACTION, RPF_ACTION_HOST); + AQ_WRITE_REG_BIT(sc, RPF_VLAN_FILTER_REG(i), + RPF_VLAN_FILTER_ID, vlanidp->vid); + i++; } - AQ_WRITE_REG_BIT(sc, RPF_VLAN_MODE_REG, RPF_VLAN_MODE_PROMISC, 1); + + done: + ETHER_UNLOCK(ec); } static int @@ -4388,6 +4428,16 @@ aq_rx_intr(void *arg) return n; } +static int +aq_vlan_cb(struct ethercom *ec, uint16_t vid, bool set) +{ + struct ifnet *ifp = &ec->ec_if; + struct aq_softc *sc = ifp->if_softc; + + aq_set_vlan_filters(sc); + return 0; +} + static int aq_ifflags_cb(struct ethercom *ec) { @@ -4412,6 +4462,10 @@ aq_ifflags_cb(struct ethercom *ec) } } + /* vlan configuration depends on also interface promiscuous mode */ + if ((ecchange & ETHERCAP_VLAN_HWFILTER) || (iffchange & IFF_PROMISC)) + aq_set_vlan_filters(sc); + sc->sc_ec_capenable = ec->ec_capenable; sc->sc_if_flags = ifp->if_flags; @@ -4428,7 +4482,7 @@ aq_init(struct ifnet *ifp) AQ_LOCK(sc); - aq_update_vlan_filters(sc); + aq_set_vlan_filters(sc); aq_set_capability(sc); for (i = 0; i < sc->sc_nqueues; i++) {