Module Name: src Committed By: jmcneill Date: Tue Oct 21 00:01:01 UTC 2014
Modified Files: src/sys/dev/ic: dwc_gmac.c dwc_gmac_reg.h Log Message: multicast hash filter support To generate a diff of this commit: cvs rdiff -u -r1.19 -r1.20 src/sys/dev/ic/dwc_gmac.c cvs rdiff -u -r1.10 -r1.11 src/sys/dev/ic/dwc_gmac_reg.h Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.
Modified files: Index: src/sys/dev/ic/dwc_gmac.c diff -u src/sys/dev/ic/dwc_gmac.c:1.19 src/sys/dev/ic/dwc_gmac.c:1.20 --- src/sys/dev/ic/dwc_gmac.c:1.19 Mon Oct 20 23:41:46 2014 +++ src/sys/dev/ic/dwc_gmac.c Tue Oct 21 00:01:01 2014 @@ -1,4 +1,4 @@ -/* $NetBSD: dwc_gmac.c,v 1.19 2014/10/20 23:41:46 matt Exp $ */ +/* $NetBSD: dwc_gmac.c,v 1.20 2014/10/21 00:01:01 jmcneill Exp $ */ /*- * Copyright (c) 2013, 2014 The NetBSD Foundation, Inc. @@ -41,7 +41,7 @@ #include <sys/cdefs.h> -__KERNEL_RCSID(1, "$NetBSD: dwc_gmac.c,v 1.19 2014/10/20 23:41:46 matt Exp $"); +__KERNEL_RCSID(1, "$NetBSD: dwc_gmac.c,v 1.20 2014/10/21 00:01:01 jmcneill Exp $"); /* #define DWC_GMAC_DEBUG 1 */ @@ -90,6 +90,7 @@ static int dwc_gmac_queue(struct dwc_gma static int dwc_gmac_ioctl(struct ifnet *, u_long, void *); static void dwc_gmac_tx_intr(struct dwc_gmac_softc *sc); static void dwc_gmac_rx_intr(struct dwc_gmac_softc *sc); +static void dwc_gmac_setmulti(struct dwc_gmac_softc *sc); #define TX_DESC_OFFSET(N) ((AWGE_RX_RING_COUNT+(N)) \ *sizeof(struct dwc_gmac_dev_dmadesc)) @@ -722,14 +723,25 @@ dwc_gmac_init(struct ifnet *ifp) /* * Set up address filter */ - ffilt = 0; - if (ifp->if_flags & IFF_PROMISC) + ffilt = bus_space_read_4(sc->sc_bst, sc->sc_bsh, AWIN_GMAC_MAC_FFILT); + if (ifp->if_flags & IFF_PROMISC) { ffilt |= AWIN_GMAC_MAC_FFILT_PR; - else if (ifp->if_flags & IFF_ALLMULTI) - ffilt |= AWIN_GMAC_MAC_FFILT_PM; + } else { + ffilt &= ~AWIN_GMAC_MAC_FFILT_PR; + } + if (ifp->if_flags & IFF_BROADCAST) { + ffilt &= ~AWIN_GMAC_MAC_FFILT_DBF; + } else { + ffilt |= AWIN_GMAC_MAC_FFILT_DBF; + } bus_space_write_4(sc->sc_bst, sc->sc_bsh, AWIN_GMAC_MAC_FFILT, ffilt); /* + * Set up multicast filter + */ + dwc_gmac_setmulti(sc); + + /* * Set up dma pointer for RX and TX ring */ bus_space_write_4(sc->sc_bst, sc->sc_bsh, AWIN_GMAC_DMA_RX_ADDR, @@ -888,6 +900,7 @@ dwc_gmac_queue(struct dwc_gmac_softc *sc static int dwc_gmac_ioctl(struct ifnet *ifp, u_long cmd, void *data) { + struct dwc_gmac_softc *sc = ifp->if_softc; struct ifaddr *ifa = (struct ifaddr *)data; int s, error = 0; @@ -950,7 +963,7 @@ dwc_gmac_ioctl(struct ifnet *ifp, u_long if (cmd != SIOCADDMULTI && cmd != SIOCDELMULTI) ; else if (ifp->if_flags & IFF_RUNNING) - /* setmulti */; + dwc_gmac_setmulti(sc); break; } @@ -1121,6 +1134,63 @@ skip: } +static void +dwc_gmac_setmulti(struct dwc_gmac_softc *sc) +{ + struct ifnet * const ifp = &sc->sc_ec.ec_if; + struct ether_multi *enm; + struct ether_multistep step; + uint32_t hashes[2] = { 0, 0 }; + uint32_t ffilt; + int h, mcnt; + + ffilt = bus_space_read_4(sc->sc_bst, sc->sc_bsh, AWIN_GMAC_MAC_FFILT); + + if (ifp->if_flags & IFF_PROMISC) { +allmulti: + ifp->if_flags |= IFF_ALLMULTI; + ffilt |= AWIN_GMAC_MAC_FFILT_PM; + bus_space_write_4(sc->sc_bst, sc->sc_bsh, AWIN_GMAC_MAC_FFILT, + ffilt); + bus_space_write_4(sc->sc_bst, sc->sc_bsh, AWIN_GMAC_MAC_HTLOW, + 0xffffffff); + bus_space_write_4(sc->sc_bst, sc->sc_bsh, AWIN_GMAC_MAC_HTHIGH, + 0xffffffff); + return; + } + + ifp->if_flags &= ~IFF_ALLMULTI; + ffilt &= ~AWIN_GMAC_MAC_FFILT_PM; + + bus_space_write_4(sc->sc_bst, sc->sc_bsh, AWIN_GMAC_MAC_HTLOW, 0); + bus_space_write_4(sc->sc_bst, sc->sc_bsh, AWIN_GMAC_MAC_HTHIGH, 0); + + ETHER_FIRST_MULTI(step, &sc->sc_ec, enm); + mcnt = 0; + while (enm != NULL) { + if (memcmp(enm->enm_addrlo, enm->enm_addrhi, + ETHER_ADDR_LEN) != 0) + goto allmulti; + + h = (~ether_crc32_le(enm->enm_addrlo, ETHER_ADDR_LEN)) >> 26; + hashes[h >> 5] |= (1 << (h & 0x1f)); + + mcnt++; + ETHER_NEXT_MULTI(step, enm); + } + + if (mcnt) + ffilt |= AWIN_GMAC_MAC_FFILT_HMC; + else + ffilt &= ~AWIN_GMAC_MAC_FFILT_HMC; + + bus_space_write_4(sc->sc_bst, sc->sc_bsh, AWIN_GMAC_MAC_FFILT, ffilt); + bus_space_write_4(sc->sc_bst, sc->sc_bsh, AWIN_GMAC_MAC_HTLOW, + hashes[0]); + bus_space_write_4(sc->sc_bst, sc->sc_bsh, AWIN_GMAC_MAC_HTHIGH, + hashes[1]); +} + int dwc_gmac_intr(struct dwc_gmac_softc *sc) { Index: src/sys/dev/ic/dwc_gmac_reg.h diff -u src/sys/dev/ic/dwc_gmac_reg.h:1.10 src/sys/dev/ic/dwc_gmac_reg.h:1.11 --- src/sys/dev/ic/dwc_gmac_reg.h:1.10 Mon Oct 20 20:10:05 2014 +++ src/sys/dev/ic/dwc_gmac_reg.h Tue Oct 21 00:01:01 2014 @@ -1,4 +1,4 @@ -/* $NetBSD: dwc_gmac_reg.h,v 1.10 2014/10/20 20:10:05 jmcneill Exp $ */ +/* $NetBSD: dwc_gmac_reg.h,v 1.11 2014/10/21 00:01:01 jmcneill Exp $ */ /*- * Copyright (c) 2013, 2014 The NetBSD Foundation, Inc. @@ -55,10 +55,16 @@ #define AWIN_GMAC_MAC_CONF_TXENABLE __BIT(3) /* enable TX dma engine */ #define AWIN_GMAC_MAC_CONF_RXENABLE __BIT(2) /* enable RX dma engine */ -#define AWIN_GMAC_MAC_FFILT_PM __BIT(4) /* promiscious multicast */ -#define AWIN_GMAC_MAC_FFILT_HMC __BIT(2) /* multicast hash compare */ -#define AWIN_GMAC_MAC_FFILT_HUC __BIT(1) /* unicast hash compare */ -#define AWIN_GMAC_MAC_FFILT_PR __BIT(0) /* promiscious mode */ +#define AWIN_GMAC_MAC_FFILT_RA __BIT(31) /* receive all mode */ +#define AWIN_GMAC_MAC_FFILT_HPF __BIT(10) /* hash or perfect filter */ +#define AWIN_GMAC_MAC_FFILT_SAF __BIT(9) /* source address filter */ +#define AWIN_GMAC_MAC_FFILT_SAIF __BIT(8) /* inverse filtering */ +#define AWIN_GMAC_MAC_FFILT_DBF __BIT(5) /* disable broadcast frames */ +#define AWIN_GMAC_MAC_FFILT_PM __BIT(4) /* promiscious multicast */ +#define AWIN_GMAC_MAC_FFILT_DAIF __BIT(3) /* DA inverse filtering */ +#define AWIN_GMAC_MAC_FFILT_HMC __BIT(2) /* multicast hash compare */ +#define AWIN_GMAC_MAC_FFILT_HUC __BIT(1) /* unicast hash compare */ +#define AWIN_GMAC_MAC_FFILT_PR __BIT(0) /* promiscious mode */ #define AWIN_GMAC_MAC_INT_LPI __BIT(10) #define AWIN_GMAC_MAC_INT_TSI __BIT(9)