Author: yongari
Date: Fri May  6 22:01:46 2011
New Revision: 221555
URL: http://svn.freebsd.org/changeset/base/221555

Log:
  Rewrite RX filter logic and provide controller specific filter
  handler for 3C90x and 3C90xB/C respectively.  This simplifies ioctl
  handler as well as enhancing readability.
  While I'm here don't reprogram multicast filter when driver is not
  running.

Modified:
  head/sys/dev/xl/if_xl.c

Modified: head/sys/dev/xl/if_xl.c
==============================================================================
--- head/sys/dev/xl/if_xl.c     Fri May  6 21:53:29 2011        (r221554)
+++ head/sys/dev/xl/if_xl.c     Fri May  6 22:01:46 2011        (r221555)
@@ -263,10 +263,11 @@ static void xl_mii_send(struct xl_softc 
 static int xl_mii_readreg(struct xl_softc *, struct xl_mii_frame *);
 static int xl_mii_writereg(struct xl_softc *, struct xl_mii_frame *);
 
+static void xl_rxfilter(struct xl_softc *);
+static void xl_rxfilter_90x(struct xl_softc *);
+static void xl_rxfilter_90xB(struct xl_softc *);
 static void xl_setcfg(struct xl_softc *);
 static void xl_setmode(struct xl_softc *, int);
-static void xl_setmulti(struct xl_softc *);
-static void xl_setmulti_hash(struct xl_softc *);
 static void xl_reset(struct xl_softc *);
 static int xl_list_rx_init(struct xl_softc *);
 static int xl_list_tx_init(struct xl_softc *);
@@ -701,101 +702,133 @@ xl_read_eeprom(struct xl_softc *sc, cadd
        return (err ? 1 : 0);
 }
 
+static void
+xl_rxfilter(struct xl_softc *sc)
+{
+
+       if (sc->xl_type == XL_TYPE_905B)
+               xl_rxfilter_90xB(sc);
+       else
+               xl_rxfilter_90x(sc);
+}
+
 /*
  * NICs older than the 3c905B have only one multicast option, which
  * is to enable reception of all multicast frames.
  */
 static void
-xl_setmulti(struct xl_softc *sc)
+xl_rxfilter_90x(struct xl_softc *sc)
 {
-       struct ifnet            *ifp = sc->xl_ifp;
+       struct ifnet            *ifp;
        struct ifmultiaddr      *ifma;
        u_int8_t                rxfilt;
-       int                     mcnt = 0;
 
        XL_LOCK_ASSERT(sc);
 
+       ifp = sc->xl_ifp;
+
        XL_SEL_WIN(5);
        rxfilt = CSR_READ_1(sc, XL_W5_RX_FILTER);
+       rxfilt &= ~(XL_RXFILTER_ALLFRAMES | XL_RXFILTER_ALLMULTI |
+           XL_RXFILTER_BROADCAST | XL_RXFILTER_INDIVIDUAL);
 
-       if (ifp->if_flags & IFF_ALLMULTI) {
-               rxfilt |= XL_RXFILTER_ALLMULTI;
-               CSR_WRITE_2(sc, XL_COMMAND, XL_CMD_RX_SET_FILT|rxfilt);
-               return;
-       }
-
-       if_maddr_rlock(ifp);
-       TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link)
-               mcnt++;
-       if_maddr_runlock(ifp);
+       /* Set the individual bit to receive frames for this host only. */
+       rxfilt |= XL_RXFILTER_INDIVIDUAL;
+       /* Set capture broadcast bit to capture broadcast frames. */
+       if (ifp->if_flags & IFF_BROADCAST)
+               rxfilt |= XL_RXFILTER_BROADCAST;
 
-       if (mcnt)
-               rxfilt |= XL_RXFILTER_ALLMULTI;
-       else
-               rxfilt &= ~XL_RXFILTER_ALLMULTI;
+       /* If we want promiscuous mode, set the allframes bit. */
+       if (ifp->if_flags & (IFF_PROMISC | IFF_ALLMULTI)) {
+               if (ifp->if_flags & IFF_PROMISC)
+                       rxfilt |= XL_RXFILTER_ALLFRAMES;
+               if (ifp->if_flags & IFF_ALLMULTI)
+                       rxfilt |= XL_RXFILTER_ALLMULTI;
+       } else {
+               if_maddr_rlock(ifp);
+               TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) {
+                       if (ifma->ifma_addr->sa_family != AF_LINK)
+                               continue;
+                       rxfilt |= XL_RXFILTER_ALLMULTI;
+                       break;
+               }
+               if_maddr_runlock(ifp);
+       }
 
-       CSR_WRITE_2(sc, XL_COMMAND, XL_CMD_RX_SET_FILT|rxfilt);
+       CSR_WRITE_2(sc, XL_COMMAND, rxfilt | XL_CMD_RX_SET_FILT);
+       XL_SEL_WIN(7);
 }
 
 /*
  * 3c905B adapters have a hash filter that we can program.
  */
 static void
-xl_setmulti_hash(struct xl_softc *sc)
+xl_rxfilter_90xB(struct xl_softc *sc)
 {
-       struct ifnet            *ifp = sc->xl_ifp;
-       int                     h = 0, i;
+       struct ifnet            *ifp;
        struct ifmultiaddr      *ifma;
+       int                     i, mcnt;
+       u_int16_t               h;
        u_int8_t                rxfilt;
-       int                     mcnt = 0;
 
        XL_LOCK_ASSERT(sc);
 
+       ifp = sc->xl_ifp;
+
        XL_SEL_WIN(5);
        rxfilt = CSR_READ_1(sc, XL_W5_RX_FILTER);
+       rxfilt &= ~(XL_RXFILTER_ALLFRAMES | XL_RXFILTER_ALLMULTI |
+           XL_RXFILTER_BROADCAST | XL_RXFILTER_INDIVIDUAL |
+           XL_RXFILTER_MULTIHASH);
 
-       if (ifp->if_flags & IFF_ALLMULTI) {
-               rxfilt |= XL_RXFILTER_ALLMULTI;
-               CSR_WRITE_2(sc, XL_COMMAND, XL_CMD_RX_SET_FILT|rxfilt);
-               return;
-       } else
-               rxfilt &= ~XL_RXFILTER_ALLMULTI;
+       /* Set the individual bit to receive frames for this host only. */
+       rxfilt |= XL_RXFILTER_INDIVIDUAL;
+       /* Set capture broadcast bit to capture broadcast frames. */
+       if (ifp->if_flags & IFF_BROADCAST)
+               rxfilt |= XL_RXFILTER_BROADCAST;
 
-       /* first, zot all the existing hash bits */
-       for (i = 0; i < XL_HASHFILT_SIZE; i++)
-               CSR_WRITE_2(sc, XL_COMMAND, XL_CMD_RX_SET_HASH|i);
-
-       /* now program new ones */
-       if_maddr_rlock(ifp);
-       TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) {
-               if (ifma->ifma_addr->sa_family != AF_LINK)
-                       continue;
-               /*
-                * Note: the 3c905B currently only supports a 64-bit hash
-                * table, which means we really only need 6 bits, but the
-                * manual indicates that future chip revisions will have a
-                * 256-bit hash table, hence the routine is set up to
-                * calculate 8 bits of position info in case we need it some
-                * day.
-                * Note II, The Sequel: _CURRENT_ versions of the 3c905B have
-                * a 256 bit hash table. This means we have to use all 8 bits
-                * regardless. On older cards, the upper 2 bits will be
-                * ignored. Grrrr....
-                */
-               h = ether_crc32_be(LLADDR((struct sockaddr_dl *)
-                   ifma->ifma_addr), ETHER_ADDR_LEN) & 0xFF;
-               CSR_WRITE_2(sc, XL_COMMAND,
-                   h | XL_CMD_RX_SET_HASH | XL_HASH_SET);
-               mcnt++;
+       /* If we want promiscuous mode, set the allframes bit. */
+       if (ifp->if_flags & (IFF_PROMISC | IFF_ALLMULTI)) {
+               if (ifp->if_flags & IFF_PROMISC)
+                       rxfilt |= XL_RXFILTER_ALLFRAMES;
+               if (ifp->if_flags & IFF_ALLMULTI)
+                       rxfilt |= XL_RXFILTER_ALLMULTI;
+       } else {
+               /* First, zot all the existing hash bits. */
+               for (i = 0; i < XL_HASHFILT_SIZE; i++)
+                       CSR_WRITE_2(sc, XL_COMMAND, XL_CMD_RX_SET_HASH | i);
+
+               /* Now program new ones. */
+               mcnt = 0;
+               if_maddr_rlock(ifp);
+               TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) {
+                       if (ifma->ifma_addr->sa_family != AF_LINK)
+                               continue;
+                       /*
+                        * Note: the 3c905B currently only supports a 64-bit
+                        * hash table, which means we really only need 6 bits,
+                        * but the manual indicates that future chip revisions
+                        * will have a 256-bit hash table, hence the routine
+                        * is set up to calculate 8 bits of position info in
+                        * case we need it some day.
+                        * Note II, The Sequel: _CURRENT_ versions of the
+                        * 3c905B have a 256 bit hash table. This means we have
+                        * to use all 8 bits regardless.  On older cards, the
+                        * upper 2 bits will be ignored. Grrrr....
+                        */
+                       h = ether_crc32_be(LLADDR((struct sockaddr_dl *)
+                           ifma->ifma_addr), ETHER_ADDR_LEN) & 0xFF;
+                       CSR_WRITE_2(sc, XL_COMMAND,
+                           h | XL_CMD_RX_SET_HASH | XL_HASH_SET);
+                       mcnt++;
+               }
+               if_maddr_runlock(ifp);
+               if (mcnt > 0)
+                       rxfilt |= XL_RXFILTER_MULTIHASH;
        }
-       if_maddr_runlock(ifp);
-
-       if (mcnt)
-               rxfilt |= XL_RXFILTER_MULTIHASH;
-       else
-               rxfilt &= ~XL_RXFILTER_MULTIHASH;
 
        CSR_WRITE_2(sc, XL_COMMAND, rxfilt | XL_CMD_RX_SET_FILT);
+       XL_SEL_WIN(7);
 }
 
 static void
@@ -2763,7 +2796,6 @@ xl_init_locked(struct xl_softc *sc)
 {
        struct ifnet            *ifp = sc->xl_ifp;
        int                     error, i;
-       u_int16_t               rxfilt = 0;
        struct mii_data         *mii = NULL;
 
        XL_LOCK_ASSERT(sc);
@@ -2862,39 +2894,7 @@ xl_init_locked(struct xl_softc *sc)
        }
 
        /* Set RX filter bits. */
-       XL_SEL_WIN(5);
-       rxfilt = CSR_READ_1(sc, XL_W5_RX_FILTER);
-
-       /* Set the individual bit to receive frames for this host only. */
-       rxfilt |= XL_RXFILTER_INDIVIDUAL;
-
-       /* If we want promiscuous mode, set the allframes bit. */
-       if (ifp->if_flags & IFF_PROMISC) {
-               rxfilt |= XL_RXFILTER_ALLFRAMES;
-               CSR_WRITE_2(sc, XL_COMMAND, XL_CMD_RX_SET_FILT|rxfilt);
-       } else {
-               rxfilt &= ~XL_RXFILTER_ALLFRAMES;
-               CSR_WRITE_2(sc, XL_COMMAND, XL_CMD_RX_SET_FILT|rxfilt);
-       }
-
-       /*
-        * Set capture broadcast bit to capture broadcast frames.
-        */
-       if (ifp->if_flags & IFF_BROADCAST) {
-               rxfilt |= XL_RXFILTER_BROADCAST;
-               CSR_WRITE_2(sc, XL_COMMAND, XL_CMD_RX_SET_FILT|rxfilt);
-       } else {
-               rxfilt &= ~XL_RXFILTER_BROADCAST;
-               CSR_WRITE_2(sc, XL_COMMAND, XL_CMD_RX_SET_FILT|rxfilt);
-       }
-
-       /*
-        * Program the multicast filter, if necessary.
-        */
-       if (sc->xl_type == XL_TYPE_905B)
-               xl_setmulti_hash(sc);
-       else
-               xl_setmulti(sc);
+       xl_rxfilter(sc);
 
        /*
         * Load the address of the RX list. We have to
@@ -3123,30 +3123,16 @@ xl_ioctl(struct ifnet *ifp, u_long comma
        struct ifreq            *ifr = (struct ifreq *) data;
        int                     error = 0, mask;
        struct mii_data         *mii = NULL;
-       u_int8_t                rxfilt;
 
        switch (command) {
        case SIOCSIFFLAGS:
                XL_LOCK(sc);
-
-               XL_SEL_WIN(5);
-               rxfilt = CSR_READ_1(sc, XL_W5_RX_FILTER);
                if (ifp->if_flags & IFF_UP) {
                        if (ifp->if_drv_flags & IFF_DRV_RUNNING &&
-                           ifp->if_flags & IFF_PROMISC &&
-                           !(sc->xl_if_flags & IFF_PROMISC)) {
-                               rxfilt |= XL_RXFILTER_ALLFRAMES;
-                               CSR_WRITE_2(sc, XL_COMMAND,
-                                   XL_CMD_RX_SET_FILT|rxfilt);
-                               XL_SEL_WIN(7);
-                       } else if (ifp->if_drv_flags & IFF_DRV_RUNNING &&
-                           !(ifp->if_flags & IFF_PROMISC) &&
-                           sc->xl_if_flags & IFF_PROMISC) {
-                               rxfilt &= ~XL_RXFILTER_ALLFRAMES;
-                               CSR_WRITE_2(sc, XL_COMMAND,
-                                   XL_CMD_RX_SET_FILT|rxfilt);
-                               XL_SEL_WIN(7);
-                       } else
+                           (ifp->if_flags ^ sc->xl_if_flags) &
+                           (IFF_PROMISC | IFF_ALLMULTI))
+                               xl_rxfilter(sc);
+                       else
                                xl_init_locked(sc);
                } else {
                        if (ifp->if_drv_flags & IFF_DRV_RUNNING)
@@ -3154,18 +3140,14 @@ xl_ioctl(struct ifnet *ifp, u_long comma
                }
                sc->xl_if_flags = ifp->if_flags;
                XL_UNLOCK(sc);
-               error = 0;
                break;
        case SIOCADDMULTI:
        case SIOCDELMULTI:
                /* XXX Downcall from if_addmulti() possibly with locks held. */
                XL_LOCK(sc);
-               if (sc->xl_type == XL_TYPE_905B)
-                       xl_setmulti_hash(sc);
-               else
-                       xl_setmulti(sc);
+               if (ifp->if_drv_flags & IFF_DRV_RUNNING)
+                       xl_rxfilter(sc);
                XL_UNLOCK(sc);
-               error = 0;
                break;
        case SIOCGIFMEDIA:
        case SIOCSIFMEDIA:
_______________________________________________
svn-src-all@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "svn-src-all-unsubscr...@freebsd.org"

Reply via email to