summaryrefslogtreecommitdiffstats
path: root/sys/arm/at91
diff options
context:
space:
mode:
authorstas <stas@FreeBSD.org>2009-05-10 08:54:10 +0000
committerstas <stas@FreeBSD.org>2009-05-10 08:54:10 +0000
commitd69c3902d5797890570d6cacf8c6199bb4588b18 (patch)
tree8a91755e5669729748531fa2f6ff9bb95770e324 /sys/arm/at91
parentff540a7f599a544251236e9926ca2f2cf4c11de0 (diff)
downloadFreeBSD-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.c65
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;
OpenPOWER on IntegriCloud