Source-Changes-HG archive

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

[src/trunk]: src/sys/arch/powerpc/ibm4xx/dev Add promiscuous and multicast su...



details:   https://anonhg.NetBSD.org/src/rev/354fefc4f6e1
branches:  trunk
changeset: 559802:354fefc4f6e1
user:      simonb <simonb%NetBSD.org@localhost>
date:      Wed Mar 24 07:45:23 2004 +0000

description:
Add promiscuous and multicast support.

>From KIYOHARA Takashi in PR port-powerpc/23892.

diffstat:

 sys/arch/powerpc/ibm4xx/dev/if_emac.c |  77 ++++++++++++++++++++++++++++++----
 1 files changed, 67 insertions(+), 10 deletions(-)

diffs (128 lines):

diff -r 0f5370fc61c1 -r 354fefc4f6e1 sys/arch/powerpc/ibm4xx/dev/if_emac.c
--- a/sys/arch/powerpc/ibm4xx/dev/if_emac.c     Wed Mar 24 06:55:58 2004 +0000
+++ b/sys/arch/powerpc/ibm4xx/dev/if_emac.c     Wed Mar 24 07:45:23 2004 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: if_emac.c,v 1.17 2003/10/27 03:58:17 simonb Exp $      */
+/*     $NetBSD: if_emac.c,v 1.18 2004/03/24 07:45:23 simonb Exp $      */
 
 /*
  * Copyright 2001, 2002 Wasabi Systems, Inc.
@@ -36,7 +36,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: if_emac.c,v 1.17 2003/10/27 03:58:17 simonb Exp $");
+__KERNEL_RCSID(0, "$NetBSD: if_emac.c,v 1.18 2004/03/24 07:45:23 simonb Exp $");
 
 #include "bpfilter.h"
 
@@ -242,6 +242,11 @@
 #define        EMAC_READ(sc, reg) \
        bus_space_read_stream_4((sc)->sc_st, (sc)->sc_sh, (reg))
 
+#define        EMAC_SET_FILTER(aht, category) \
+do {                                                                   \
+       (aht)[3 - ((category) >> 4)] |= 1 << ((category) & 0xf);        \
+} while (/*CONSTCOND*/0)
+
 static int     emac_match(struct device *, struct cfdata *, void *);
 static void    emac_attach(struct device *, struct device *, void *);
 
@@ -255,6 +260,7 @@
 static void    emac_start(struct ifnet *);
 static void    emac_stop(struct ifnet *, int);
 static void    emac_watchdog(struct ifnet *);
+static int     emac_set_filter(struct emac_softc *);
 
 static int     emac_wol_intr(void *);
 static int     emac_serr_intr(void *);
@@ -789,11 +795,9 @@
        /*
         * Enable Individual and (possibly) Broadcast Address modes,
         * runt packets, and strip padding.
-        *
-        * XXX: promiscuous mode (and promiscuous multicast mode) need to be
-        *      dealt with here!
         */
        EMAC_WRITE(sc, EMAC_RMR, RMR_IAE | RMR_RRP | RMR_SP |
+           (ifp->if_flags & IFF_PROMISC ? RMR_PME : 0) |
            (ifp->if_flags & IFF_BROADCAST ? RMR_BAE : 0));
 
        /*
@@ -1010,11 +1014,7 @@
                         * Multicast list has changed; set the hardware filter
                         * accordingly.
                         */
-#if 0
-                       error = emac_set_filter(sc);    /* XXX not done yet */
-#else
-                       error = emac_init(ifp);
-#endif
+                       error = emac_set_filter(sc);
                }
                break;
        }
@@ -1046,6 +1046,63 @@
            MAL0_CFG_SD | MAL0_CFG_PLBLT);
 }
 
+static int
+emac_set_filter(struct emac_softc *sc)
+{
+       struct ether_multistep step;
+       struct ether_multi *enm;
+       struct ifnet *ifp = &sc->sc_ethercom.ec_if;
+       uint32_t rmr, crc, gaht[4] = {0, 0, 0, 0};
+       int category, cnt = 0;
+
+       rmr = EMAC_READ(sc, EMAC_RMR);
+       rmr &= ~(RMR_PMME | RMR_MAE);
+       ifp->if_flags &= ~IFF_ALLMULTI;
+
+       ETHER_FIRST_MULTI(step, &sc->sc_ethercom, enm);
+       while (enm != NULL) {
+               if (memcmp(enm->enm_addrlo,
+                   enm->enm_addrhi, ETHER_ADDR_LEN) != 0) {
+                       /*
+                        * 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.)
+                        */
+                       gaht[0] = gaht[1] = gaht[2] = gaht[3] = 0xffff;
+                       break;
+               }
+
+               crc = ether_crc32_be(enm->enm_addrlo, ETHER_ADDR_LEN);
+
+               /* Just want the 6 most significant bits. */
+               category = crc >> 26;
+               EMAC_SET_FILTER(gaht, category);
+
+               ETHER_NEXT_MULTI(step, enm);
+               cnt++;
+       }
+
+       if ((gaht[0] & gaht[1] & gaht[2] & gaht[3]) == 0xffff) {
+               /* All categories are true. */
+               ifp->if_flags |= IFF_ALLMULTI;
+               rmr |= RMR_PMME;
+       } else if (cnt != 0) {
+               /* Some categories are true. */
+               EMAC_WRITE(sc, EMAC_GAHT1, gaht[0]); 
+               EMAC_WRITE(sc, EMAC_GAHT2, gaht[1]);
+               EMAC_WRITE(sc, EMAC_GAHT3, gaht[2]);
+               EMAC_WRITE(sc, EMAC_GAHT4, gaht[3]);
+
+               rmr |= RMR_MAE;
+       }
+       EMAC_WRITE(sc, EMAC_RMR, rmr);
+
+       return 0;
+}
+
 /*
  * EMAC General interrupt handler
  */



Home | Main Index | Thread Index | Old Index