add support VLAN HW filter

This commit is contained in:
ryo 2020-02-10 05:53:11 +00:00
parent c7d7f2416b
commit accb2dabd4
2 changed files with 69 additions and 18 deletions

View File

@ -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 <ryo@nerv.org>
.\" 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.

View File

@ -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 <sys/cdefs.h>
__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++) {