diff options
Diffstat (limited to 'sys/arch')
-rw-r--r-- | sys/arch/powerpc/mac/if_gm.c | 112 | ||||
-rw-r--r-- | sys/arch/powerpc/mac/if_gmreg.h | 3 |
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 |