summaryrefslogtreecommitdiffstats
path: root/sys/dev/xl
diff options
context:
space:
mode:
authoryongari <yongari@FreeBSD.org>2011-05-06 22:01:46 +0000
committeryongari <yongari@FreeBSD.org>2011-05-06 22:01:46 +0000
commit809c03efc562581a5488f89b67c4c45c7228af40 (patch)
tree2f81f35a71c9a84431904d863cc47a4831cc5dec /sys/dev/xl
parent0aab37190f5e64dee05a299b33d8f1d89cfbdfd9 (diff)
downloadFreeBSD-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')
-rw-r--r--sys/dev/xl/if_xl.c222
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:
OpenPOWER on IntegriCloud