diff options
author | Dale Rahn <drahn@cvs.openbsd.org> | 2002-06-07 23:44:06 +0000 |
---|---|---|
committer | Dale Rahn <drahn@cvs.openbsd.org> | 2002-06-07 23:44:06 +0000 |
commit | 08f96ba6c16338245fb5dbe0652b5118ed5b5a4c (patch) | |
tree | d102dab9e9831074099485299973d4a0691ed575 /sys/dev/ic/gem.c | |
parent | 1429ec93a7f19c59112349ed91f5771d3a72cf4e (diff) |
Multicast fixes, Gig-E support, mostly from netbsd. ok jason@
Diffstat (limited to 'sys/dev/ic/gem.c')
-rw-r--r-- | sys/dev/ic/gem.c | 151 |
1 files changed, 110 insertions, 41 deletions
diff --git a/sys/dev/ic/gem.c b/sys/dev/ic/gem.c index 13e42a02a0f..c423ba88f12 100644 --- a/sys/dev/ic/gem.c +++ b/sys/dev/ic/gem.c @@ -1,4 +1,4 @@ -/* $OpenBSD: gem.c,v 1.21 2002/05/07 20:44:41 jason Exp $ */ +/* $OpenBSD: gem.c,v 1.22 2002/06/07 23:44:05 drahn Exp $ */ /* $NetBSD: gem.c,v 1.1 2001/09/16 00:11:43 eeh Exp $ */ /* @@ -144,6 +144,7 @@ gem_config(sc) struct mii_data *mii = &sc->sc_mii; struct mii_softc *child; int i, error; + struct ifmedia_entry *ifm; bcopy(sc->sc_enaddr, sc->sc_arpcom.ac_enaddr, ETHER_ADDR_LEN); @@ -211,6 +212,10 @@ gem_config(sc) printf("%s: Ethernet address %s\n", sc->sc_dev.dv_xname, ether_sprintf(sc->sc_enaddr)); + /* Get RX FIFO size */ + sc->sc_rxfifosize = 64 * + bus_space_read_4(sc->sc_bustag, sc->sc_h, GEM_RX_FIFO_SIZE); + /* Initialize ifnet structure. */ strcpy(ifp->if_xname, sc->sc_dev.dv_xname); ifp->if_softc = sc; @@ -292,6 +297,26 @@ gem_config(sc) ifmedia_set(&sc->sc_media, IFM_ETHER|IFM_AUTO); } + /* + * If we support GigE media, we support jumbo frames too. + * Unless we are Apple. + */ + TAILQ_FOREACH(ifm, &sc->sc_media.ifm_list, ifm_list) { + if (IFM_SUBTYPE(ifm->ifm_media) == IFM_1000_TX || + IFM_SUBTYPE(ifm->ifm_media) == IFM_1000_SX || + IFM_SUBTYPE(ifm->ifm_media) == IFM_1000_LX || + IFM_SUBTYPE(ifm->ifm_media) == IFM_1000_CX) { +#if 0 + if (sc->sc_variant != GEM_APPLE_GMAC) + sc->sc_ethercom.ec_capabilities + |= ETHERCAP_JUMBO_MTU; +#endif + + sc->sc_flags |= GEM_GIGABIT; + break; + } + } + /* Attach the interface. */ if_attach(ifp); ether_ifattach(ifp); @@ -682,10 +707,12 @@ gem_ringsize(int sz) int gem_init(struct ifnet *ifp) { + struct gem_softc *sc = (struct gem_softc *)ifp->if_softc; bus_space_tag_t t = sc->sc_bustag; bus_space_handle_t h = sc->sc_h; int s; + u_int max_frame_size; u_int32_t v; s = splimp(); @@ -715,7 +742,13 @@ gem_init(struct ifnet *ifp) /* step 4. TX MAC registers & counters */ gem_init_regs(sc); - v = (GEM_MTU) | (0x2000 << 16) /* Burst size */; + max_frame_size = max(ifp->if_mtu, ETHERMTU); + max_frame_size += ETHER_HDR_LEN + ETHER_CRC_LEN; +#if 0 + if (sc->sc_ethercom.ec_capenable & ETHERCAP_VLAN_MTU) + max_frame_size += ETHER_VLAN_ENCAP_LEN; +#endif + v = (max_frame_size) | (0x2000 << 16) /* Burst size */; bus_space_write_4(t, h, GEM_MAC_MAC_MAX_FRAME, v); /* step 5. RX MAC registers & counters */ @@ -738,18 +771,19 @@ gem_init(struct ifnet *ifp) GEM_INTR_RX_TAG_ERR|GEM_INTR_PCS| GEM_INTR_MAC_CONTROL|GEM_INTR_MIF| GEM_INTR_BERR)); - bus_space_write_4(t, h, GEM_MAC_RX_MASK, 0); /* XXXX */ + bus_space_write_4(t, h, GEM_MAC_RX_MASK, + GEM_MAC_RX_DONE|GEM_MAC_RX_FRAME_CNT); bus_space_write_4(t, h, GEM_MAC_TX_MASK, 0xffff); /* XXXX */ bus_space_write_4(t, h, GEM_MAC_CONTROL_MASK, 0); /* XXXX */ /* step 9. ETX Configuration: use mostly default values */ /* Enable DMA */ - bus_space_write_4(t, h, GEM_TX_KICK, 0); v = gem_ringsize(GEM_NTXDESC /*XXX*/); bus_space_write_4(t, h, GEM_TX_CONFIG, v|GEM_TX_CONFIG_TXDMA_EN| ((0x400<<10)&GEM_TX_CONFIG_TXFIFO_TH)); + bus_space_write_4(t, h, GEM_TX_KICK, 0); /* step 10. ERX Configuration */ @@ -762,14 +796,16 @@ gem_init(struct ifnet *ifp) (2<<GEM_RX_CONFIG_FBOFF_SHFT)|GEM_RX_CONFIG_RXDMA_EN| (0<<GEM_RX_CONFIG_CXM_START_SHFT)); /* - * The following value is for an OFF Threshold of about 15.5 Kbytes - * and an ON Threshold of 4K bytes. + * The following value is for an OFF Threshold of about 3/4 full + * and an ON Threshold of 1/4 full. */ - bus_space_write_4(t, h, GEM_RX_PAUSE_THRESH, 0xf8 | (0x40 << 12)); - bus_space_write_4(t, h, GEM_RX_BLANKING, (2<<12)|6); + bus_space_write_4(t, h, GEM_RX_PAUSE_THRESH, + (3 * sc->sc_rxfifosize / 256) | + ( (sc->sc_rxfifosize / 256) << 12)); + bus_space_write_4(t, h, GEM_RX_BLANKING, (6<<12)|6); /* step 11. Configure Media */ - gem_mii_statchg(&sc->sc_dev); + mii_mediachg(&sc->sc_mii); /* step 12. RX_MAC Configuration Register */ v = bus_space_read_4(t, h, GEM_MAC_RX_CONFIG); @@ -815,15 +851,17 @@ gem_init_regs(struct gem_softc *sc) bus_space_write_4(t, h, GEM_MAC_MAC_MIN_FRAME, ETHER_MIN_LEN); /* Max frame and max burst size */ - v = (GEM_MTU) | (0x2000 << 16) /* Burst size */; + v = ETHER_MAX_LEN | (0x2000 << 16) /* Burst size */; bus_space_write_4(t, h, GEM_MAC_MAC_MAX_FRAME, v); + bus_space_write_4(t, h, GEM_MAC_PREAMBLE_LEN, 0x7); bus_space_write_4(t, h, GEM_MAC_JAM_SIZE, 0x4); bus_space_write_4(t, h, GEM_MAC_ATTEMPT_LIMIT, 0x10); /* Dunno.... */ bus_space_write_4(t, h, GEM_MAC_CONTROL_TYPE, 0x8088); bus_space_write_4(t, h, GEM_MAC_RANDOM_SEED, - ((sc->sc_enaddr[5]<<8)|sc->sc_enaddr[4])&0x3ff); + ((sc->sc_enaddr[5]<<8)|sc->sc_enaddr[4])&0x3ff); + /* Secondary MAC addr set to 0:0:0:0:0:0 */ bus_space_write_4(t, h, GEM_MAC_ADDR3, 0); bus_space_write_4(t, h, GEM_MAC_ADDR4, 0); @@ -870,6 +908,18 @@ gem_init_regs(struct gem_softc *sc) bus_space_write_4(t, h, GEM_MAC_ADDR2, (sc->sc_enaddr[0]<<8) | sc->sc_enaddr[1]); + + /* + * Enable MII outputs. Enable GMII if there is a gigabit PHY. + */ + sc->sc_mif_config = bus_space_read_4(t, h, GEM_MIF_CONFIG); + v = GEM_MAC_XIF_TX_MII_ENA; + if (sc->sc_mif_config & GEM_MIF_CONFIG_MDI1) { + v |= GEM_MAC_XIF_FDPLX_LED; + if (sc->sc_flags & GEM_GIGABIT) + v |= GEM_MAC_XIF_GMII_MODE; + } + bus_space_write_4(t, h, GEM_MAC_XIF_CONFIG, v); } /* @@ -1249,9 +1299,17 @@ gem_mii_statchg(dev) if ((IFM_OPTIONS(sc->sc_mii.mii_media_active) & IFM_FDX) != 0) /* turn on full duplex LED */ v |= GEM_MAC_XIF_FDPLX_LED; - else - /* half duplex -- disable echo */ - v |= GEM_MAC_XIF_ECHO_DISABL; + else + /* half duplex -- disable echo */ + v |= GEM_MAC_XIF_ECHO_DISABL; + + switch (IFM_SUBTYPE(sc->sc_mii.mii_media_active)) { + case IFM_1000_TX: /* Gigabit using GMII interface */ + v |= GEM_MAC_XIF_GMII_MODE; + break; + default: + v &= ~GEM_MAC_XIF_GMII_MODE; + } } else /* Internal MII needs buf enable */ v |= GEM_MAC_XIF_MII_BUF_ENA; @@ -1263,9 +1321,14 @@ gem_mediachange(ifp) struct ifnet *ifp; { struct gem_softc *sc = ifp->if_softc; + struct mii_data *mii = &sc->sc_mii; - if (IFM_TYPE(sc->sc_media.ifm_media) != IFM_ETHER) - return (EINVAL); + if (mii->mii_instance) { + struct mii_softc *miisc; + for (miisc = LIST_FIRST(&mii->mii_phys); miisc != NULL; + miisc = LIST_NEXT(miisc, mii_list)) + mii_phy_reset(miisc); + } return (mii_mediachg(&sc->sc_mii)); } @@ -1277,9 +1340,6 @@ gem_mediastatus(ifp, ifmr) { struct gem_softc *sc = ifp->if_softc; - if ((ifp->if_flags & IFF_UP) == 0) - return; - mii_pollstat(&sc->sc_mii); ifmr->ifm_active = sc->sc_mii.mii_media_active; ifmr->ifm_status = sc->sc_mii.mii_media_status; @@ -1427,33 +1487,38 @@ gem_setladrf(sc) u_int32_t crc, hash[16], v; int i; - /* Clear hash table */ - for (i = 0; i < 16; i++) - hash[i] = 0; - /* Get current RX configuration */ v = bus_space_read_4(t, h, GEM_MAC_RX_CONFIG); + + /* + * Turn off promiscuous mode, promiscuous group mode (all multicast), + * and hash filter. Depending on the case, the right bit will be + * enabled. + */ + v &= ~(GEM_MAC_RX_PROMISCUOUS|GEM_MAC_RX_HASH_FILTER| + GEM_MAC_RX_PROMISC_GRP); + if ((ifp->if_flags & IFF_PROMISC) != 0) { - /* Turn on promiscuous mode; turn off the hash filter */ + /* Turn on promiscuous mode */ v |= GEM_MAC_RX_PROMISCUOUS; - v &= ~GEM_MAC_RX_HASH_FILTER; ifp->if_flags |= IFF_ALLMULTI; goto chipit; } - /* Turn off promiscuous mode; turn on the hash filter */ - v &= ~GEM_MAC_RX_PROMISCUOUS; - v |= GEM_MAC_RX_HASH_FILTER; - /* * Set up multicast address filter by passing all multicast addresses - * through a crc generator, and then using the high order 6 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. + * 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 4 + * bits select the word, while the other 4 bits select the bit within + * the word (where bit 0 is the MSB). */ + /* Clear hash table */ + for (i = 0; i < 16; i++) + hash[i] = 0; + + ETHER_FIRST_MULTI(step, ac, enm); while (enm != NULL) { if (bcmp(enm->enm_addrlo, enm->enm_addrhi, ETHER_ADDR_LEN)) { @@ -1464,31 +1529,35 @@ gem_setladrf(sc) * 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.) + * XXX use the addr filter for this */ - for (i = 0; i < 16; i++) - hash[i] = 0xffff; ifp->if_flags |= IFF_ALLMULTI; + v |= GEM_MAC_RX_PROMISC_GRP; goto chipit; } crc = ether_crc32_le(enm->enm_addrlo, ETHER_ADDR_LEN); - /* Just want the 8 most sigificant bits. */ + /* Just want the 8 most significant bits. */ crc >>= 24; /* Set the corresponding bit in the filter. */ - hash[crc >> 4] |= 1 << (crc & 0xf); + hash[crc >> 4] |= 1 << (15 - (crc & 15)); ETHER_NEXT_MULTI(step, enm); } + v |= GEM_MAC_RX_HASH_FILTER; ifp->if_flags &= ~IFF_ALLMULTI; -chipit: - /* Now load the hash table into the chip */ - for (i = 0; i < 16; i++) - bus_space_write_4(t, h, GEM_MAC_HASH0 + (i * 4), hash[i]); + /* Now load the hash table into the chip (if we are using it) */ + for (i = 0; i < 16; i++) { + bus_space_write_4(t, h, + GEM_MAC_HASH0 + i * (GEM_MAC_HASH1-GEM_MAC_HASH0), + hash[i]); + } +chipit: bus_space_write_4(t, h, GEM_MAC_RX_CONFIG, v); } |