Please test the following diff to rewrite the promisc mode / multicast
handling code for the sparc hme(4) driver and is based off of the MI
hme(4) driver.
Index: hme.c
===================================================================
RCS file: /cvs/src/sys/arch/sparc/dev/hme.c,v
retrieving revision 1.61
diff -u -p -r1.61 hme.c
--- hme.c 16 Jul 2009 07:18:47 -0000 1.61
+++ hme.c 17 Jul 2009 21:58:10 -0000
@@ -126,7 +126,7 @@ int hme_mii_read(struct device *, int, i
void hme_mii_write(struct device *, int, int, int);
void hme_mii_statchg(struct device *);
-void hme_mcreset(struct hme_softc *);
+void hme_iff(struct hme_softc *);
struct cfattach hme_ca = {
sizeof (struct hme_softc), hmematch, hmeattach
@@ -445,7 +445,7 @@ hmeioctl(ifp, cmd, data)
if (error == ENETRESET) {
if (ifp->if_flags & IFF_RUNNING)
- hme_mcreset(sc);
+ hme_iff(sc);
error = 0;
}
@@ -575,7 +575,7 @@ hmeinit(sc)
printf("%s: setting rxreg->cfg failed.\n", sc->sc_dev.dv_xname);
cr->rx_cfg = 0;
- hme_mcreset(sc);
+ hme_iff(sc);
DELAY(10);
cr->tx_cfg |= CR_TXCFG_DGIVEUP;
@@ -959,89 +959,52 @@ hme_read(sc, idx, len, flags)
ether_input_mbuf(ifp, m);
}
-/*
- * Program the multicast receive filter.
- */
void
-hme_mcreset(sc)
+hme_iff(sc)
struct hme_softc *sc;
{
struct arpcom *ac = &sc->sc_arpcom;
struct ifnet *ifp = &sc->sc_arpcom.ac_if;
struct hme_cr *cr = sc->sc_cr;
- u_int32_t crc;
- u_int16_t hash[4];
- u_int8_t octet;
- int i, j;
struct ether_multi *enm;
struct ether_multistep step;
+ u_int32_t rxfg, crc;
+ u_int32_t hash[4];
- if (ifp->if_flags & IFF_PROMISC) {
- cr->rx_cfg |= CR_RXCFG_PMISC;
- return;
- }
- else
- cr->rx_cfg &= ~CR_RXCFG_PMISC;
+ rxcfg = cr->rx_cfg;
+ rxcfg &= ~(CR_RXCFG_HENABLE | CR_RXCFG_PMISC);
+ if->if_flags &= ~IFF_ALLMULTI;
+ /* Clear hash table */
+ hash[0] = hash[1] = hash[2] = hash[3] = 0;
- if (ifp->if_flags & IFF_ALLMULTI) {
- cr->htable3 = 0xffff;
- cr->htable2 = 0xffff;
- cr->htable1 = 0xffff;
- cr->htable0 = 0xffff;
- cr->rx_cfg |= CR_RXCFG_HENABLE;
- return;
- }
-
- hash[3] = hash[2] = hash[1] = hash[0] = 0;
-
- ETHER_FIRST_MULTI(step, ac, enm);
- while (enm != NULL) {
- if (bcmp(enm->enm_addrlo, enm->enm_addrhi, ETHER_ADDR_LEN)) {
- /*
- * We must listen to a range of multicast
- * addresses. For now, just accept all
- * multicasts, rather than trying to set only
- * those filter bits needed to match the range.
- * (At this time, the only use of address
- * ranges is for IP multicast routing, for
- * which the range is big enough to require
- * all bits set.)
- */
- cr->htable3 = 0xffff;
- cr->htable2 = 0xffff;
- cr->htable1 = 0xffff;
- cr->htable0 = 0xffff;
- cr->rx_cfg |= CR_RXCFG_HENABLE;
- ifp->if_flags |= IFF_ALLMULTI;
- return;
- }
-
- crc = 0xffffffff;
+ if (ifp->if_flags & IFF_PROMISC) {
+ ifp->if_flags |= IFF_ALLMULTI;
+ rxcfg |= CR_RXCFG_PMISC;
+ } else if (ac->ac_multirangecnt > 0) {
+ ifp->if_flags |= IFF_ALLMULTI;
+ rxcfg |= CR_RXFG_HENABLE;
+ hash[0] = hash[1] = hash[2] = hash[3] = 0xffff;
+ } else {
+ rxcfg |= CR_RXFG_HENABLE;
+
+ ETHER_FIRST_MULTI(step, ac, enm);
+ while (enm != NULL) {
+ crc = ether_crc32_le(enm->enm_addrlo,
+ ETHER_ADDR_LEN) >> 26;
- for (i = 0; i < ETHER_ADDR_LEN; i++) {
- octet = enm->enm_addrlo[i];
+ /* Set the corresponding bit in the filter. */
+ hash[crc >> 4] |= 1 << (crc & 0xf);
- for (j = 0; j < 8; j++) {
- if ((crc & 1) ^ (octet & 1)) {
- crc >>= 1;
- crc ^= ETHER_CRC_POLY_LE;
- }
- else
- crc >>= 1;
- octet >>= 1;
- }
+ ETHER_NEXT_MULTI(step, enm);
}
-
- crc >>=26;
- hash[crc >> 4] |= 1 << (crc & 0xf);
- ETHER_NEXT_MULTI(step, enm);
}
- cr->htable3 = hash[3];
- cr->htable2 = hash[2];
- cr->htable1 = hash[1];
+
+ /* Now load the hash table into the chip */
cr->htable0 = hash[0];
- cr->rx_cfg |= CR_RXCFG_HENABLE;
- ifp->if_flags &= ~IFF_ALLMULTI;
+ cr->htable1 = hash[1];
+ cr->htable2 = hash[2];
+ cr->htable3 = hash[3];
+ cr->rx_cfg = rxcfg;
}
/*
--
This message has been scanned for viruses and
dangerous content by MailScanner, and is
believed to be clean.