diff options
author | stas <stas@FreeBSD.org> | 2009-05-10 08:54:10 +0000 |
---|---|---|
committer | stas <stas@FreeBSD.org> | 2009-05-10 08:54:10 +0000 |
commit | d69c3902d5797890570d6cacf8c6199bb4588b18 (patch) | |
tree | 8a91755e5669729748531fa2f6ff9bb95770e324 /sys/arm/at91 | |
parent | ff540a7f599a544251236e9926ca2f2cf4c11de0 (diff) | |
download | FreeBSD-src-d69c3902d5797890570d6cacf8c6199bb4588b18.zip FreeBSD-src-d69c3902d5797890570d6cacf8c6199bb4588b18.tar.gz |
- 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.
Diffstat (limited to 'sys/arm/at91')
-rw-r--r-- | sys/arm/at91/if_ate.c | 65 |
1 files changed, 53 insertions, 12 deletions
diff --git a/sys/arm/at91/if_ate.c b/sys/arm/at91/if_ate.c index 9e7995f..01bf3e5 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; |