Source-Changes-HG archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

[src/trunk]: src/sys/arch/macppc/dev Implement multicast address filter. (St...



details:   https://anonhg.NetBSD.org/src/rev/888583274136
branches:  trunk
changeset: 487948:888583274136
user:      tsubai <tsubai%NetBSD.org@localhost>
date:      Thu Jun 15 18:36:52 2000 +0000

description:
Implement multicast address filter.  (Stolen from hme.c)

diffstat:

 sys/arch/macppc/dev/if_gm.c |  110 +++++++++++++++++++++++++++++++++++++++----
 1 files changed, 98 insertions(+), 12 deletions(-)

diffs (154 lines):

diff -r 601acf29506c -r 888583274136 sys/arch/macppc/dev/if_gm.c
--- a/sys/arch/macppc/dev/if_gm.c       Thu Jun 15 18:23:52 2000 +0000
+++ b/sys/arch/macppc/dev/if_gm.c       Thu Jun 15 18:36:52 2000 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: if_gm.c,v 1.5 2000/04/02 12:03:04 tsubai Exp $ */
+/*     $NetBSD: if_gm.c,v 1.6 2000/06/15 18:36:52 tsubai Exp $ */
 
 /*-
  * Copyright (c) 2000 Tsubai Masanari.  All rights reserved.
@@ -107,6 +107,7 @@
 void gmac_reset __P((struct gmac_softc *));
 void gmac_init __P((struct gmac_softc *));
 void gmac_init_mac __P((struct gmac_softc *));
+void gmac_setladrf __P((struct gmac_softc *));
 
 int gmac_ioctl __P((struct ifnet *, u_long, caddr_t));
 void gmac_watchdog __P((struct ifnet *));
@@ -227,7 +228,6 @@
        ifp->if_watchdog = gmac_watchdog;
        ifp->if_flags =
                IFF_BROADCAST | IFF_SIMPLEX | IFF_NOTRAILERS | IFF_MULTICAST;
-       ifp->if_flags |= IFF_ALLMULTI;
 
        mii->mii_ifp = ifp;
        mii->mii_readreg = gmac_mii_readreg;
@@ -644,7 +644,7 @@
        gmac_write_reg(sc, GMAC_MACADDRFILT2_1MASK, 0);
        gmac_write_reg(sc, GMAC_MACADDRFILT0MASK, 0);
 
-       for (i = 0; i < 0x6c; i+= 4)
+       for (i = 0; i < 0x6c; i += 4)
                gmac_write_reg(sc, GMAC_HASHTABLE0 + i, 0);
 
        gmac_write_reg(sc, GMAC_SLOTTIME, 0x40);
@@ -664,24 +664,110 @@
 }
 
 void
+gmac_setladrf(sc)
+       struct gmac_softc *sc;
+{
+       struct ifnet *ifp = &sc->sc_if;
+       struct ether_multi *enm;
+       struct ether_multistep step;
+       struct ethercom *ec = &sc->sc_ethercom;
+       u_char *cp;
+       u_int32_t crc;
+       u_int32_t hash[16];
+       u_int v;
+       int len, i;
+
+       /* Clear hash table */
+       for (i = 0; i < 16; i++)
+               hash[i] = 0;
+
+       /* Get current RX configuration */
+       v = gmac_read_reg(sc, GMAC_RXMACCONFIG);
+
+       if ((ifp->if_flags & IFF_PROMISC) != 0) {
+               /* Turn on promiscuous mode; turn off the hash filter */
+               v |= GMAC_RXMAC_PR;
+               v &= ~GMAC_RXMAC_HEN;
+               ifp->if_flags |= IFF_ALLMULTI;
+               goto chipit;
+       }
+
+       /* Turn off promiscuous mode; turn on the hash filter */
+       v &= ~GMAC_RXMAC_PR;
+       v |= GMAC_RXMAC_HEN;
+
+       /*
+        * Set up multicast address filter by passing all multicast addresses
+        * through a crc generator, and then using the high order 8 bits as an
+        * index into the 256 bit logical address filter.  The high order bit
+        * selects the word, while the rest of the bits select the bit within
+        * the word.
+        */
+
+       ETHER_FIRST_MULTI(step, ec, enm);
+       while (enm != NULL) {
+               if (bcmp(enm->enm_addrlo, enm->enm_addrhi, 6)) {
+                       /*
+                        * 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.)
+                        */
+                       for (i = 0; i < 16; i++)
+                               hash[i] = 0xffff;
+                       ifp->if_flags |= IFF_ALLMULTI;
+                       goto chipit;
+               }
+
+               cp = enm->enm_addrlo;
+               crc = 0xffffffff;
+               for (len = sizeof(enm->enm_addrlo); --len >= 0;) {
+                       int octet = *cp++;
+                       int i;
+
+#define MC_POLY_LE     0xedb88320UL    /* mcast crc, little endian */
+                       for (i = 0; i < 8; i++) {
+                               if ((crc & 1) ^ (octet & 1)) {
+                                       crc >>= 1;
+                                       crc ^= MC_POLY_LE;
+                               } else {
+                                       crc >>= 1;
+                               }
+                               octet >>= 1;
+                       }
+               }
+               /* Just want the 8 most significant bits. */
+               crc >>= 24;
+
+               /* Set the corresponding bit in the filter. */
+               hash[crc >> 4] |= 1 << (crc & 0xf);
+
+               ETHER_NEXT_MULTI(step, enm);
+       }
+
+       ifp->if_flags &= ~IFF_ALLMULTI;
+
+chipit:
+       /* Now load the hash table into the chip */
+       for (i = 0; i < 16; i++)
+               gmac_write_reg(sc, GMAC_HASHTABLE0 + i * 4, hash[i]);
+
+       gmac_write_reg(sc, GMAC_RXMACCONFIG, v);
+}
+
+void
 gmac_init(sc)
        struct gmac_softc *sc;
 {
        struct ifnet *ifp = &sc->sc_if;
-       u_int x;
-       int i;
 
        gmac_stop_txdma(sc);
        gmac_stop_rxdma(sc);
 
        gmac_init_mac(sc);
-
-       x = gmac_read_reg(sc, GMAC_RXMACCONFIG);
-       if (ifp->if_flags & IFF_PROMISC)
-               x |= GMAC_RXMAC_PR;
-       else
-               x &= ~GMAC_RXMAC_PR;
-       gmac_write_reg(sc, GMAC_RXMACCONFIG, x);
+       gmac_setladrf(sc);
 
        gmac_start_txdma(sc);
        gmac_start_rxdma(sc);



Home | Main Index | Thread Index | Old Index