From 36ffa1b9de88ed89d4a1254c63df3253705386d7 Mon Sep 17 00:00:00 2001 From: Stanislav Sedov Date: Sun, 10 May 2009 08:54:10 +0000 Subject: [PATCH] - Fix promisc/multicast/broadcast parameters setting by introducing the new ate_rxfilter function to set requested parameters. Use this function on parameters change rather than reinitializing the chip. --- sys/arm/at91/if_ate.c | 65 +++++++++++++++++++++++++++++++++++-------- 1 file changed, 53 insertions(+), 12 deletions(-) diff --git a/sys/arm/at91/if_ate.c b/sys/arm/at91/if_ate.c index 9e7995fbff7f..01bf3e5c9e55 100644 --- a/sys/arm/at91/if_ate.c +++ b/sys/arm/at91/if_ate.c @@ -76,6 +76,11 @@ __FBSDID("$FreeBSD$"); #define ATE_MAX_TX_BUFFERS 2 /* We have ping-pong tx buffers */ #define ATE_MAX_RX_BUFFERS 64 +/* + * Driver-specific flags. + */ +#define ATE_FLAG_DETACHING 0x01 + struct ate_softc { struct ifnet *ifp; /* ifnet pointer */ @@ -100,6 +105,8 @@ struct ate_softc eth_rx_desc_t *rx_descs; int use_rmii; struct ifmib_iso_8802_3 mibdata; /* stuff for network mgmt */ + int flags; + int if_flags; }; static inline uint32_t @@ -149,6 +156,7 @@ static int ate_ifmedia_upd(struct ifnet *ifp); static void ate_ifmedia_sts(struct ifnet *ifp, struct ifmediareq *ifmr); static int ate_get_mac(struct ate_softc *sc, u_char *eaddr); static void ate_set_mac(struct ate_softc *sc, u_char *eaddr); +static void ate_rxfilter(struct ate_softc *sc); /* * The AT91 family of products has the ethernet called EMAC. However, @@ -238,6 +246,7 @@ ate_attach(device_t dev) ifp->if_linkmib = &sc->mibdata; ifp->if_linkmiblen = sizeof(sc->mibdata); sc->mibdata.dot3Compliance = DOT3COMPLIANCE_COLLS; + sc->if_flags = ifp->if_flags; ether_ifattach(ifp, eaddr); @@ -763,13 +772,6 @@ ateinit_locked(void *xsc) else WR4(sc, ETH_CFG, RD4(sc, ETH_CFG) & ~ETH_CFG_RMII); - /* - * Turn on the multicast hash, and write 0's to it. - */ - WR4(sc, ETH_CFG, RD4(sc, ETH_CFG) | ETH_CFG_MTI); - WR4(sc, ETH_HSH, 0); - WR4(sc, ETH_HSL, 0); - 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); @@ -780,6 +782,7 @@ ateinit_locked(void *xsc) * 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); @@ -940,25 +943,63 @@ atestop(struct ate_softc *sc) */ } +static void +ate_rxfilter(struct ate_softc *sc) +{ + struct ifnet *ifp; + uint32_t reg; + + KASSERT(sc != NULL, ("[ate, %d]: sc is NULL!", __LINE__)); + ATE_ASSERT_LOCKED(sc); + ifp = sc->ifp; + + /* + * Wipe out old filter settings. + */ + reg = RD4(sc, ETH_CFG); + reg &= ~(ETH_CFG_CAF | ETH_CFG_MTI | ETH_CFG_UNI); + reg |= ETH_CFG_NBC; + + /* + * Set new parameters. + */ + if ((ifp->if_flags & IFF_BROADCAST) != 0) + reg &= ~ETH_CFG_NBC; + if ((ifp->if_flags & IFF_PROMISC) != 0) + reg |= ETH_CFG_CAF; + if ((ifp->if_flags & IFF_ALLMULTI) != 0) + reg |= ETH_CFG_MTI; + WR4(sc, ETH_CFG, reg); +} + static int ateioctl(struct ifnet *ifp, u_long cmd, caddr_t data) { struct ate_softc *sc = ifp->if_softc; struct mii_data *mii; struct ifreq *ifr = (struct ifreq *)data; + int drv_flags, flags; int mask, error = 0; + flags = ifp->if_flags; + drv_flags = ifp->if_drv_flags; switch (cmd) { case SIOCSIFFLAGS: ATE_LOCK(sc); - if ((ifp->if_flags & IFF_UP) == 0 && - ifp->if_drv_flags & IFF_DRV_RUNNING) { + if ((flags & IFF_UP) != 0) { + if ((drv_flags & IFF_DRV_RUNNING) != 0) { + if (((flags ^ sc->if_flags) + & (IFF_PROMISC | IFF_ALLMULTI)) != 0) + ate_rxfilter(sc); + } else { + if ((sc->flags & ATE_FLAG_DETACHING) == 0) + ateinit_locked(sc); + } + } else if ((drv_flags & IFF_DRV_RUNNING) != 0) { ifp->if_drv_flags &= ~IFF_DRV_RUNNING; atestop(sc); - } else { - /* reinitialize card on any parameter change */ - ateinit_locked(sc); } + sc->if_flags = flags; ATE_UNLOCK(sc); break;