Skip site navigation (1)Skip section navigation (2)
Date:      Sun, 10 May 2009 08:54:10 +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: r191959 - head/sys/arm/at91
Message-ID:  <200905100854.n4A8sAPw048368@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: stas
Date: Sun May 10 08:54:10 2009
New Revision: 191959
URL: http://svn.freebsd.org/changeset/base/191959

Log:
  - 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.

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 05:17:51 2009	(r191958)
+++ head/sys/arm/at91/if_ate.c	Sun May 10 08:54:10 2009	(r191959)
@@ -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 
 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;
 



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200905100854.n4A8sAPw048368>