Date: Sun, 10 May 2009 10:32:29 +0000 (UTC) From: Stanislav Sedov <stas@FreeBSD.org> To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org Subject: svn commit: r191960 - head/sys/arm/at91 Message-ID: <200905101032.n4AAWT0x050353@svn.freebsd.org>
next in thread | raw e-mail | index | archive | help
Author: stas Date: Sun May 10 10:32:29 2009 New Revision: 191960 URL: http://svn.freebsd.org/changeset/base/191960 Log: - Fix multicast operation that I broke in previous commit. - Do not enable multicast hash lookup if no multicast addresses were configured or if promisc mode is enabled. Modified: head/sys/arm/at91/if_ate.c Modified: head/sys/arm/at91/if_ate.c ============================================================================== --- head/sys/arm/at91/if_ate.c Sun May 10 08:54:10 2009 (r191959) +++ head/sys/arm/at91/if_ate.c Sun May 10 10:32:29 2009 (r191960) @@ -80,6 +80,7 @@ __FBSDID("$FreeBSD$"); * Driver-specific flags. */ #define ATE_FLAG_DETACHING 0x01 +#define ATE_FLAG_MULTICAST 0x02 struct ate_softc { @@ -316,26 +317,39 @@ ate_load_rx_buf(void *arg, bus_dma_segme * of different MAC chips use this method (or the reverse the bits) * method. */ -static void +static int ate_setmcast(struct ate_softc *sc) { uint32_t index; uint32_t mcaf[2]; u_char *af = (u_char *) mcaf; struct ifmultiaddr *ifma; + struct ifnet *ifp; + + ifp = sc->ifp; + + if ((ifp->if_flags & IFF_PROMISC) != 0) + return (0); + if ((ifp->if_flags & IFF_ALLMULTI) != 0) { + WR4(sc, ETH_HSL, 0xffffffff); + WR4(sc, ETH_HSH, 0xffffffff); + return (1); + } + /* + * Compute the multicast hash. + */ mcaf[0] = 0; mcaf[1] = 0; - - IF_ADDR_LOCK(sc->ifp); - TAILQ_FOREACH(ifma, &sc->ifp->if_multiaddrs, ifma_link) { + IF_ADDR_LOCK(ifp); + TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { if (ifma->ifma_addr->sa_family != AF_LINK) continue; index = ether_crc32_be(LLADDR((struct sockaddr_dl *) ifma->ifma_addr), ETHER_ADDR_LEN) >> 26; af[index >> 3] |= 1 << (index & 7); } - IF_ADDR_UNLOCK(sc->ifp); + IF_ADDR_UNLOCK(ifp); /* * Write the hash to the hash register. This card can also @@ -346,6 +360,7 @@ ate_setmcast(struct ate_softc *sc) */ WR4(sc, ETH_HSL, mcaf[0]); WR4(sc, ETH_HSH, mcaf[1]); + return (mcaf[0] || mcaf[1]); } static int @@ -772,6 +787,11 @@ ateinit_locked(void *xsc) else WR4(sc, ETH_CFG, RD4(sc, ETH_CFG) & ~ETH_CFG_RMII); + ate_rxfilter(sc); + + /* + * Turn on MACs and interrupt processing. + */ WR4(sc, ETH_CTL, RD4(sc, ETH_CTL) | ETH_CTL_TE | ETH_CTL_RE); WR4(sc, ETH_IER, ETH_ISR_RCOM | ETH_ISR_TCOM | ETH_ISR_RBNA); @@ -781,8 +801,6 @@ ateinit_locked(void *xsc) * the byte order is big endian, not little endian, so we have some * swapping to do. Again, if we need it (which I don't think we do). */ - ate_setmcast(sc); - ate_rxfilter(sc); /* enable big packets */ WR4(sc, ETH_CFG, RD4(sc, ETH_CFG) | ETH_CFG_BIG); @@ -948,6 +966,7 @@ ate_rxfilter(struct ate_softc *sc) { struct ifnet *ifp; uint32_t reg; + int enabled; KASSERT(sc != NULL, ("[ate, %d]: sc is NULL!", __LINE__)); ATE_ASSERT_LOCKED(sc); @@ -959,16 +978,22 @@ ate_rxfilter(struct ate_softc *sc) reg = RD4(sc, ETH_CFG); reg &= ~(ETH_CFG_CAF | ETH_CFG_MTI | ETH_CFG_UNI); reg |= ETH_CFG_NBC; + sc->flags &= ~ATE_FLAG_MULTICAST; /* * Set new parameters. */ if ((ifp->if_flags & IFF_BROADCAST) != 0) reg &= ~ETH_CFG_NBC; - if ((ifp->if_flags & IFF_PROMISC) != 0) + if ((ifp->if_flags & IFF_PROMISC) != 0) { reg |= ETH_CFG_CAF; - if ((ifp->if_flags & IFF_ALLMULTI) != 0) - reg |= ETH_CFG_MTI; + } else { + enabled = ate_setmcast(sc); + if (enabled != 0) { + reg |= ETH_CFG_MTI; + sc->flags |= ATE_FLAG_MULTICAST; + } + } WR4(sc, ETH_CFG, reg); } @@ -979,8 +1004,9 @@ ateioctl(struct ifnet *ifp, u_long cmd, struct mii_data *mii; struct ifreq *ifr = (struct ifreq *)data; int drv_flags, flags; - int mask, error = 0; + int mask, error, enabled; + error = 0; flags = ifp->if_flags; drv_flags = ifp->if_drv_flags; switch (cmd) { @@ -1005,11 +1031,13 @@ ateioctl(struct ifnet *ifp, u_long cmd, case SIOCADDMULTI: case SIOCDELMULTI: - /* update multicast filter list. */ - ATE_LOCK(sc); - ate_setmcast(sc); - ATE_UNLOCK(sc); - error = 0; + if ((drv_flags & IFF_DRV_RUNNING) != 0) { + ATE_LOCK(sc); + enabled = ate_setmcast(sc); + if (enabled != (sc->flags & ATE_FLAG_MULTICAST)) + ate_rxfilter(sc); + ATE_UNLOCK(sc); + } break; case SIOCSIFMEDIA:
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200905101032.n4AAWT0x050353>