diff options
author | yongari <yongari@FreeBSD.org> | 2011-05-06 22:01:46 +0000 |
---|---|---|
committer | yongari <yongari@FreeBSD.org> | 2011-05-06 22:01:46 +0000 |
commit | 809c03efc562581a5488f89b67c4c45c7228af40 (patch) | |
tree | 2f81f35a71c9a84431904d863cc47a4831cc5dec /sys/dev/xl/if_xl.c | |
parent | 0aab37190f5e64dee05a299b33d8f1d89cfbdfd9 (diff) | |
download | FreeBSD-src-809c03efc562581a5488f89b67c4c45c7228af40.zip FreeBSD-src-809c03efc562581a5488f89b67c4c45c7228af40.tar.gz |
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.
Diffstat (limited to 'sys/dev/xl/if_xl.c')
-rw-r--r-- | sys/dev/xl/if_xl.c | 222 |
1 files changed, 102 insertions, 120 deletions
diff --git a/sys/dev/xl/if_xl.c b/sys/dev/xl/if_xl.c index 1db6ece..a319b86 100644 --- a/sys/dev/xl/if_xl.c +++ b/sys/dev/xl/if_xl.c @@ -263,10 +263,11 @@ static void xl_mii_send(struct xl_softc *, u_int32_t, int); 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, caddr_t dest, int off, int cnt, int swap) 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; - - /* 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); + /* 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; - /* 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 command, caddr_t data) 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 command, caddr_t data) } 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: |