summaryrefslogtreecommitdiff
path: root/sys/dev/ic/re.c
diff options
context:
space:
mode:
authorBrad Smith <brad@cvs.openbsd.org>2008-08-28 17:51:10 +0000
committerBrad Smith <brad@cvs.openbsd.org>2008-08-28 17:51:10 +0000
commit15e434b18f794c4767c143ce9e8b4b863d267113 (patch)
tree5223d25f73aede4d00778bbab5aeb39b0046dd14 /sys/dev/ic/re.c
parentd0c1c279b05d5161982057e18e320ac408e78914 (diff)
Rewrite the multicast/promiscuous handling and in the process merge into
one function. Also fix reception of multicast packets when in promisuous mode. The Realtek chips are a little different than most others in that they will not receive multicast packets by enabling promiscuous mode alone. Tested by naddy@ and sthen@ ok naddy@
Diffstat (limited to 'sys/dev/ic/re.c')
-rw-r--r--sys/dev/ic/re.c113
1 files changed, 38 insertions, 75 deletions
diff --git a/sys/dev/ic/re.c b/sys/dev/ic/re.c
index 7d45fa54f56..da5c9e49961 100644
--- a/sys/dev/ic/re.c
+++ b/sys/dev/ic/re.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: re.c,v 1.87 2008/08/13 03:18:19 brad Exp $ */
+/* $OpenBSD: re.c,v 1.88 2008/08/28 17:51:09 brad Exp $ */
/* $FreeBSD: if_re.c,v 1.31 2004/09/04 07:54:05 ru Exp $ */
/*
* Copyright (c) 1997, 1998-2003
@@ -185,8 +185,7 @@ int re_miibus_readreg(struct device *, int, int);
void re_miibus_writereg(struct device *, int, int, int);
void re_miibus_statchg(struct device *);
-void re_setmulti(struct rl_softc *);
-void re_setpromisc(struct rl_softc *);
+void re_iff(struct rl_softc *);
void re_reset(struct rl_softc *);
#ifdef RE_DIAG
@@ -504,13 +503,10 @@ re_miibus_statchg(struct device *dev)
{
}
-/*
- * Program the 64-bit multicast hash filter.
- */
void
-re_setmulti(struct rl_softc *sc)
+re_iff(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 rxfilt;
@@ -518,50 +514,40 @@ re_setmulti(struct rl_softc *sc)
struct arpcom *ac = &sc->sc_arpcom;
struct ether_multi *enm;
struct ether_multistep step;
-
- ifp = &sc->sc_arpcom.ac_if;
rxfilt = CSR_READ_4(sc, RL_RXCFG);
+ rxfilt &= ~(RL_RXCFG_RX_ALLPHYS | RL_RXCFG_RX_MULTI);
+ ifp->if_flags &= ~IFF_ALLMULTI;
- if (ifp->if_flags & IFF_ALLMULTI || ifp->if_flags & IFF_PROMISC) {
+ 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;
- }
-
- /* first, zot all the existing hash bits */
- CSR_WRITE_4(sc, RL_MAR0, 0);
- CSR_WRITE_4(sc, RL_MAR4, 0);
-
- /* 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;
- mcnt = MAX_NUM_MULTICAST_ADDRESSES;
+ if (ifp->if_flags & IFF_PROMISC)
+ rxfilt |= RL_RXCFG_RX_ALLPHYS;
+ hashes[0] = hashes[1] = 0xFFFFFFFF;
+ } else {
+ /* first, zot all the existing hash bits */
+ CSR_WRITE_4(sc, RL_MAR0, 0);
+ CSR_WRITE_4(sc, RL_MAR4, 0);
+
+ /* now program new ones */
+ ETHER_FIRST_MULTI(step, ac, enm);
+ while (enm != NULL) {
+ 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 == MAX_NUM_MULTICAST_ADDRESSES)
- break;
- h = (ether_crc32_be(enm->enm_addrlo,
- ETHER_ADDR_LEN) >> 26) & 0x0000003F;
- 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;
}
- if (mcnt)
- rxfilt |= RL_RXCFG_RX_MULTI;
- else
- rxfilt &= ~RL_RXCFG_RX_MULTI;
-
- CSR_WRITE_4(sc, RL_RXCFG, rxfilt);
-
/*
* For some unfathomable reason, RealTek decided to reverse
* the order of the multicast hash registers in the PCI Express
@@ -575,22 +561,8 @@ re_setmulti(struct rl_softc *sc)
CSR_WRITE_4(sc, RL_MAR0, hashes[0]);
CSR_WRITE_4(sc, RL_MAR4, hashes[1]);
}
-}
-void
-re_setpromisc(struct rl_softc *sc)
-{
- struct ifnet *ifp;
- u_int32_t rxcfg = 0;
-
- ifp = &sc->sc_arpcom.ac_if;
-
- rxcfg = CSR_READ_4(sc, RL_RXCFG);
- if (ifp->if_flags & IFF_PROMISC)
- rxcfg |= RL_RXCFG_RX_ALLPHYS;
- else
- rxcfg &= ~RL_RXCFG_RX_ALLPHYS;
- CSR_WRITE_4(sc, RL_RXCFG, rxcfg);
+ CSR_WRITE_4(sc, RL_RXCFG, rxfilt);
}
void
@@ -1976,13 +1948,8 @@ re_init(struct ifnet *ifp)
CSR_WRITE_4(sc, RL_RXCFG, rxcfg);
- /* Set promiscuous mode. */
- re_setpromisc(sc);
-
- /*
- * Program the multicast filter, if necessary.
- */
- re_setmulti(sc);
+ /* Program promiscuous mode and multicast filters. */
+ re_iff(sc);
/*
* Enable interrupts.
@@ -2100,14 +2067,10 @@ re_ioctl(struct ifnet *ifp, u_long command, caddr_t data)
break;
case SIOCSIFFLAGS:
if (ifp->if_flags & IFF_UP) {
- if (ifp->if_flags & IFF_RUNNING &&
- ((ifp->if_flags ^ sc->if_flags) &
- IFF_PROMISC)) {
- re_setpromisc(sc);
- } else {
- if (!(ifp->if_flags & IFF_RUNNING))
- re_init(ifp);
- }
+ if (ifp->if_flags & IFF_RUNNING)
+ re_iff(sc);
+ else
+ re_init(ifp);
} else {
if (ifp->if_flags & IFF_RUNNING)
re_stop(ifp, 1);
@@ -2125,7 +2088,7 @@ re_ioctl(struct ifnet *ifp, u_long command, caddr_t data)
* filter accordingly.
*/
if (ifp->if_flags & IFF_RUNNING)
- re_setmulti(sc);
+ re_iff(sc);
error = 0;
}
break;