summaryrefslogtreecommitdiff
path: root/sys/dev
diff options
context:
space:
mode:
authorStuart Henderson <sthen@cvs.openbsd.org>2009-07-18 11:24:40 +0000
committerStuart Henderson <sthen@cvs.openbsd.org>2009-07-18 11:24:40 +0000
commitde3846087d2f21acdeb812943417c4bb5c56b6c5 (patch)
treea0f3ced0bf0d81cc2ff372a59660b3e3b23cdc63 /sys/dev
parent904a36c91acddf7a4c92806b02217e4973c937b7 (diff)
Rewrite the ioctl handling code and the receive filter
handling to clean up the code and eliminate unnecessary resets. From Brad, promisc tested by Olivier Cherrier, promisc/multicast by me.
Diffstat (limited to 'sys/dev')
-rw-r--r--sys/dev/ic/rtl81x9.c122
1 files changed, 47 insertions, 75 deletions
diff --git a/sys/dev/ic/rtl81x9.c b/sys/dev/ic/rtl81x9.c
index 7ef1c14f2b7..bdcfe83046f 100644
--- a/sys/dev/ic/rtl81x9.c
+++ b/sys/dev/ic/rtl81x9.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: rtl81x9.c,v 1.64 2009/06/02 17:27:39 jsg Exp $ */
+/* $OpenBSD: rtl81x9.c,v 1.65 2009/07/18 11:24:39 sthen Exp $ */
/*
* Copyright (c) 1997, 1998
@@ -158,7 +158,7 @@ int rl_miibus_readreg(struct device *, int, int);
void rl_miibus_writereg(struct device *, int, int, int);
void rl_miibus_statchg(struct device *);
-void rl_setmulti(struct rl_softc *);
+void rl_iff(struct rl_softc *);
void rl_reset(struct rl_softc *);
int rl_list_tx_init(struct rl_softc *);
@@ -457,63 +457,56 @@ int rl_mii_writereg(sc, frame)
return(0);
}
-/*
- * Program the 64-bit multicast hash filter.
- */
-void rl_setmulti(sc)
+void rl_iff(sc)
struct rl_softc *sc;
{
- struct ifnet *ifp;
+ struct ifnet *ifp = &sc->sc_arpcom.ac_if;
int h = 0;
- u_int32_t hashes[2] = { 0, 0 };
+ u_int32_t hashes[2];
struct arpcom *ac = &sc->sc_arpcom;
struct ether_multi *enm;
struct ether_multistep step;
u_int32_t rxfilt;
- int mcnt = 0;
-
- ifp = &sc->sc_arpcom.ac_if;
rxfilt = CSR_READ_4(sc, RL_RXCFG);
+ rxfilt &= ~(RL_RXCFG_RX_ALLPHYS | RL_RXCFG_RX_BROAD |
+ RL_RXCFG_RX_INDIV | RL_RXCFG_RX_MULTI);
+ ifp->if_flags &= ~IFF_ALLMULTI;
-allmulti:
- if (ifp->if_flags & IFF_ALLMULTI || ifp->if_flags & IFF_PROMISC) {
+ /*
+ * Always accept frames destined to our station address.
+ * Always accept broadcast frames.
+ */
+ rxfilt |= RL_RXCFG_RX_INDIV | RL_RXCFG_RX_BROAD;
+
+ if (ifp->if_flags & IFF_PROMISC || ac->ac_multirangecnt > 0) {
+ ifp ->if_flags |= IFF_ALLMULTI;
rxfilt |= RL_RXCFG_RX_MULTI;
- CSR_WRITE_4(sc, RL_RXCFG, rxfilt);
- CSR_WRITE_4(sc, RL_MAR0, 0xFFFFFFFF);
- CSR_WRITE_4(sc, RL_MAR4, 0xFFFFFFFF);
- return;
- }
+ if (ifp->if_flags & IFF_PROMISC)
+ rxfilt |= RL_RXCFG_RX_ALLPHYS;
+ hashes[0] = hashes[1] = 0xFFFFFFFF;
+ } else {
+ rxfilt |= RL_RXCFG_RX_MULTI;
+ /* Program new filter. */
+ bzero(hashes, sizeof(hashes));
+
+ ETHER_FIRST_MULTI(step, ac, enm);
+ while (enm != NULL) {
+ h = ether_crc32_be(enm->enm_addrlo,
+ ETHER_ADDR_LEN) >> 26;
- /* first, zot all the existing hash bits */
- CSR_WRITE_4(sc, RL_MAR0, 0);
- CSR_WRITE_4(sc, RL_MAR4, 0);
+ if (h < 32)
+ hashes[0] |= (1 << h);
+ else
+ hashes[1] |= (1 << (h - 32));
- /* now program new ones */
- ETHER_FIRST_MULTI(step, ac, enm);
- while (enm != NULL) {
- if (bcmp(enm->enm_addrlo, enm->enm_addrhi, ETHER_ADDR_LEN)) {
- ifp->if_flags |= IFF_ALLMULTI;
- goto allmulti;
+ ETHER_NEXT_MULTI(step, enm);
}
- mcnt++;
- h = ether_crc32_be(enm->enm_addrlo, ETHER_ADDR_LEN) >> 26;
- if (h < 32)
- hashes[0] |= (1 << h);
- else
- hashes[1] |= (1 << (h - 32));
- mcnt++;
- ETHER_NEXT_MULTI(step, enm);
}
- if (mcnt)
- rxfilt |= RL_RXCFG_RX_MULTI;
- else
- rxfilt &= ~RL_RXCFG_RX_MULTI;
-
- CSR_WRITE_4(sc, RL_RXCFG, rxfilt);
CSR_WRITE_4(sc, RL_MAR0, hashes[0]);
CSR_WRITE_4(sc, RL_MAR4, hashes[1]);
+ CSR_WRITE_4(sc, RL_RXCFG, rxfilt);
}
void
@@ -958,7 +951,6 @@ void rl_init(xsc)
struct rl_softc *sc = xsc;
struct ifnet *ifp = &sc->sc_arpcom.ac_if;
int s;
- u_int32_t rxcfg = 0;
s = splnet();
@@ -996,30 +988,10 @@ void rl_init(xsc)
CSR_WRITE_4(sc, RL_TXCFG, RL_TXCFG_CONFIG);
CSR_WRITE_4(sc, RL_RXCFG, RL_RXCFG_CONFIG);
- /* Set the individual bit to receive frames for this host only. */
- rxcfg = CSR_READ_4(sc, RL_RXCFG);
- rxcfg |= RL_RXCFG_RX_INDIV;
-
- /* If we want promiscuous mode, set the allframes bit. */
- if (ifp->if_flags & IFF_PROMISC)
- rxcfg |= RL_RXCFG_RX_ALLPHYS;
- else
- rxcfg &= ~RL_RXCFG_RX_ALLPHYS;
- CSR_WRITE_4(sc, RL_RXCFG, rxcfg);
-
- /*
- * Set capture broadcast bit to capture broadcast frames.
- */
- if (ifp->if_flags & IFF_BROADCAST)
- rxcfg |= RL_RXCFG_RX_BROAD;
- else
- rxcfg &= ~RL_RXCFG_RX_BROAD;
- CSR_WRITE_4(sc, RL_RXCFG, rxcfg);
-
/*
- * Program the multicast filter, if necessary.
+ * Program promiscuous mode and multicast filters.
*/
- rl_setmulti(sc);
+ rl_iff(sc);
/*
* Enable interrupts.
@@ -1089,38 +1061,38 @@ int rl_ioctl(ifp, command, data)
switch(command) {
case SIOCSIFADDR:
ifp->if_flags |= IFF_UP;
- switch (ifa->ifa_addr->sa_family) {
-#ifdef INET
- case AF_INET:
+ if (!(ifp->if_flags & IFF_RUNNING))
rl_init(sc);
+#ifdef INET
+ if (ifa->ifa_addr->sa_family == AF_INET)
arp_ifinit(&sc->sc_arpcom, ifa);
- break;
#endif /* INET */
- default:
- rl_init(sc);
- break;
- }
break;
+
case SIOCSIFFLAGS:
if (ifp->if_flags & IFF_UP) {
- rl_init(sc);
+ if (ifp->if_flags & IFF_RUNNING)
+ error = ENETRESET;
+ else
+ rl_init(sc);
} else {
if (ifp->if_flags & IFF_RUNNING)
rl_stop(sc);
}
- error = 0;
break;
+
case SIOCGIFMEDIA:
case SIOCSIFMEDIA:
error = ifmedia_ioctl(ifp, ifr, &sc->sc_mii.mii_media, command);
break;
+
default:
error = ether_ioctl(ifp, &sc->sc_arpcom, command, data);
}
if (error == ENETRESET) {
if (ifp->if_flags & IFF_RUNNING)
- rl_setmulti(sc);
+ rl_iff(sc);
error = 0;
}