summaryrefslogtreecommitdiff
path: root/sys/arch
diff options
context:
space:
mode:
Diffstat (limited to 'sys/arch')
-rw-r--r--sys/arch/powerpc/mac/if_gm.c112
-rw-r--r--sys/arch/powerpc/mac/if_gmreg.h3
2 files changed, 113 insertions, 2 deletions
diff --git a/sys/arch/powerpc/mac/if_gm.c b/sys/arch/powerpc/mac/if_gm.c
index 238a285f852..07272deaed7 100644
--- a/sys/arch/powerpc/mac/if_gm.c
+++ b/sys/arch/powerpc/mac/if_gm.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: if_gm.c,v 1.12 2001/05/03 00:28:17 drahn Exp $ */
+/* $OpenBSD: if_gm.c,v 1.13 2001/06/24 20:26:13 drahn Exp $ */
/* $NetBSD: if_gm.c,v 1.2 2000/03/04 11:17:00 tsubai Exp $ */
/*-
@@ -119,6 +119,7 @@ void gmac_stop __P((struct gmac_softc *));
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 *));
@@ -130,6 +131,8 @@ void gmac_mii_writereg __P((struct device *, int, int, int));
void gmac_mii_statchg __P((struct device *));
void gmac_mii_tick __P((void *));
+u_int32_t ether_crc32_le(const u_int8_t *buf, size_t len);
+
struct cfattach gm_ca = {
sizeof(struct gmac_softc), gmac_match, gmac_attach
};
@@ -780,6 +783,88 @@ gmac_init_mac(sc)
}
void
+gmac_setladrf(sc)
+ struct gmac_softc *sc;
+{
+ struct ifnet *ifp = &sc->sc_if;
+ struct ether_multi *enm;
+ struct ether_multistep step;
+#if defined(__OpenBSD__)
+ struct arpcom *ec = &sc->arpcom;
+#else
+ struct ethercom *ec = &sc->sc_ethercom;
+#endif
+ u_int32_t crc;
+ u_int32_t hash[16];
+ u_int v;
+ int 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;
+ }
+
+ crc = ether_crc32_le(enm->enm_addrlo, ETHER_ADDR_LEN);
+
+ /* 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;
{
@@ -791,6 +876,7 @@ gmac_init(sc)
gmac_stop_rxdma(sc);
gmac_init_mac(sc);
+ gmac_setladrf(sc);
x = gmac_read_reg(sc, GMAC_RXMACCONFIG);
if (ifp->if_flags & IFF_PROMISC)
@@ -1069,3 +1155,27 @@ gmac_enable_hack()
printf("gmac enabled\n");
}
+
+/* HACK, THIS SHOULD NOT BE IN THIS FILE */
+u_int32_t
+ether_crc32_le(const u_int8_t *buf, size_t len)
+{
+ static const u_int32_t crctab[] = {
+ 0x00000000, 0x1db71064, 0x3b6e20c8, 0x26d930ac,
+ 0x76dc4190, 0x6b6b51f4, 0x4db26158, 0x5005713c,
+ 0xedb88320, 0xf00f9344, 0xd6d6a3e8, 0xcb61b38c,
+ 0x9b64c2b0, 0x86d3d2d4, 0xa00ae278, 0xbdbdf21c
+ };
+ u_int32_t crc;
+ int i;
+
+ crc = 0xffffffffU; /* initial value */
+
+ for (i = 0; i < len; i++) {
+ crc ^= buf[i];
+ crc = (crc >> 4) ^ crctab[crc & 0xf];
+ crc = (crc >> 4) ^ crctab[crc & 0xf];
+ }
+
+ return (crc);
+}
diff --git a/sys/arch/powerpc/mac/if_gmreg.h b/sys/arch/powerpc/mac/if_gmreg.h
index 44c14ec0bf0..2b2a9018de6 100644
--- a/sys/arch/powerpc/mac/if_gmreg.h
+++ b/sys/arch/powerpc/mac/if_gmreg.h
@@ -41,7 +41,8 @@ struct gmac_dma {
#define GMAC_INT_TXDONE 0x04
#define GMAC_INT_RXDONE 0x10
-#define GMAC_RXMAC_PR 0x08
+#define GMAC_RXMAC_PR 0x08 /* enable promiscuous mode */
+#define GMAC_RXMAC_HEN 0x10 /* enable the hash filter */
/*
* register offset