summaryrefslogtreecommitdiffstats
path: root/sys/dev/xl/if_xl.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/dev/xl/if_xl.c')
-rw-r--r--sys/dev/xl/if_xl.c235
1 files changed, 107 insertions, 128 deletions
diff --git a/sys/dev/xl/if_xl.c b/sys/dev/xl/if_xl.c
index 1db6ece..004b511 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
@@ -2485,8 +2518,7 @@ xl_encap(struct xl_softc *sc, struct xl_chain *c, struct mbuf **m_head)
htole32(sc->xl_cdata.xl_tx_segs[i].ds_len);
total_len += sc->xl_cdata.xl_tx_segs[i].ds_len;
}
- c->xl_ptr->xl_frag[nseg - 1].xl_len =
- htole32(sc->xl_cdata.xl_tx_segs[nseg - 1].ds_len | XL_LAST_FRAG);
+ c->xl_ptr->xl_frag[nseg - 1].xl_len |= htole32(XL_LAST_FRAG);
c->xl_ptr->xl_status = htole32(total_len);
c->xl_ptr->xl_next = 0;
@@ -2611,8 +2643,7 @@ xl_start_locked(struct ifnet *ifp)
* get an interrupt once for the whole chain rather than
* once for each packet.
*/
- cur_tx->xl_ptr->xl_status = htole32(le32toh(cur_tx->xl_ptr->xl_status) |
- XL_TXSTAT_DL_INTR);
+ cur_tx->xl_ptr->xl_status |= htole32(XL_TXSTAT_DL_INTR);
bus_dmamap_sync(sc->xl_ldata.xl_tx_tag, sc->xl_ldata.xl_tx_dmamap,
BUS_DMASYNC_PREWRITE);
@@ -2628,8 +2659,8 @@ xl_start_locked(struct ifnet *ifp)
sc->xl_cdata.xl_tx_tail->xl_ptr->xl_next =
htole32(start_tx->xl_phys);
status = sc->xl_cdata.xl_tx_tail->xl_ptr->xl_status;
- sc->xl_cdata.xl_tx_tail->xl_ptr->xl_status =
- htole32(le32toh(status) & ~XL_TXSTAT_DL_INTR);
+ sc->xl_cdata.xl_tx_tail->xl_ptr->xl_status &=
+ htole32(~XL_TXSTAT_DL_INTR);
sc->xl_cdata.xl_tx_tail = cur_tx;
} else {
sc->xl_cdata.xl_tx_head = start_tx;
@@ -2733,8 +2764,7 @@ xl_start_90xB_locked(struct ifnet *ifp)
* get an interrupt once for the whole chain rather than
* once for each packet.
*/
- cur_tx->xl_ptr->xl_status = htole32(le32toh(cur_tx->xl_ptr->xl_status) |
- XL_TXSTAT_DL_INTR);
+ cur_tx->xl_ptr->xl_status |= htole32(XL_TXSTAT_DL_INTR);
bus_dmamap_sync(sc->xl_ldata.xl_tx_tag, sc->xl_ldata.xl_tx_dmamap,
BUS_DMASYNC_PREWRITE);
@@ -2763,7 +2793,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 +2891,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 +3120,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 +3137,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