--- share/man/man4/gem.4.dist 2005-06-27 07:44:44.000000000 +0100 +++ share/man/man4/gem.4 2008-01-05 19:56:37.000000000 +0000 @@ -31,7 +31,7 @@ .\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE .\" POSSIBILITY OF SUCH DAMAGE. .\" -.Dd February 20, 2005 +.Dd December 18, 2007 .Dt GEM 4 .Os .Sh NAME @@ -39,6 +39,7 @@ .Nd ERI/GEM/GMAC Ethernet device driver .Sh SYNOPSIS .Cd "gem* at pci? dev ? function ?" +.Cd "gem* at sbus? slot ? offset ?" .Pp Configuration of PHYs may also be necessary. See @@ -53,7 +54,7 @@ Cards supported by this driver include: .Bl -bullet -compact -offset indent .It -Sun GEM gigabit ethernet +Sun GEM gigabit ethernet (including SX fibre variants) .It Sun ERI 10/100 .It @@ -61,7 +62,7 @@ .El .Pp The GEM family supports hardware checksumming to assist in computing -IPv4 TCP/UDP checksums. +IPv4 TCP checksums. The .Nm driver supports this feature of the chip. @@ -69,12 +70,16 @@ .Xr ifconfig 8 for information on how to enable this feature. .Sh SEE ALSO -.Xr bm 4 , -.Xr de 4 , -.Xr hme 4 , -.Xr mc 4 , +.Xr bmtphy 4 , +.Xr ifmedia 4 , +.Xr intro 4 , .Xr mii 4 , -.Xr tlp 4 +.Xr ifconfig 8 +.Rs +.%T "GEM Gigabit Ethernet ASIC Specification" +.%A Sun Microsystems +.%O http://www.sun.com/processors/manuals/ge.pdf +.Re .Sh HISTORY The .Nm @@ -90,3 +95,9 @@ The man page was written by .An Thomas Klausner .Aq wiz@NetBSD.org . +.Sh BUGS +On the SX fibre variants of the hardware, the link will stay down if there is +a duplex mismatch. +Also, packet transmission may fail when in +.Cm half-duplex +mode. --- sys/dev/ic/gem.c.dist 2006-11-27 07:13:29.000000000 +0000 +++ sys/dev/ic/gem.c 2008-01-05 19:11:38.000000000 +0000 @@ -3,6 +3,7 @@ /* * * Copyright (C) 2001 Eduardo Horvath. + * Copyright (c) 2001-2003 Thomas Moestl * All rights reserved. * * @@ -30,7 +31,9 @@ */ /* - * Driver for Sun GEM ethernet controllers. + * Driver for Apple GMAC, Sun ERI and Sun GEM Ethernet controllers + * See `GEM Gigabit Ethernet ASIC Specification' + * http://www.sun.com/processors/manuals/ge.pdf */ #include @@ -91,6 +94,8 @@ void gem_tick(void *); void gem_watchdog(struct ifnet *); void gem_shutdown(void *); +void gem_pcs_start(struct gem_softc *sc); +void gem_pcs_stop(struct gem_softc *sc, int); int gem_init(struct ifnet *); void gem_init_regs(struct gem_softc *sc); static int gem_ringsize(int sz); @@ -100,6 +105,8 @@ u_int32_t, u_int32_t); void gem_reset(struct gem_softc *); int gem_reset_rx(struct gem_softc *sc); +static void gem_reset_rxdma(struct gem_softc *sc); +static void gem_rx_common(struct gem_softc *sc); int gem_reset_tx(struct gem_softc *sc); int gem_disable_rx(struct gem_softc *sc); int gem_disable_tx(struct gem_softc *sc); @@ -112,18 +119,22 @@ static void gem_mii_writereg(struct device *, int, int, int); static void gem_mii_statchg(struct device *); +void gem_statuschange(struct gem_softc *); + int gem_mediachange(struct ifnet *); void gem_mediastatus(struct ifnet *, struct ifmediareq *); struct mbuf *gem_get(struct gem_softc *, int, int); int gem_put(struct gem_softc *, int, struct mbuf *); void gem_read(struct gem_softc *, int, int); +int gem_pint(struct gem_softc *); int gem_eint(struct gem_softc *, u_int); int gem_rint(struct gem_softc *); int gem_tint(struct gem_softc *); void gem_power(int, void *); #ifdef GEM_DEBUG +static void gem_txsoft_print(const struct gem_softc *, int, int); #define DPRINTF(sc, x) if ((sc)->sc_ethercom.ec_if.if_flags & IFF_DEBUG) \ printf x #else @@ -145,6 +156,8 @@ { struct ifnet *ifp = &sc->sc_ethercom.ec_if; struct mii_data *mii = &sc->sc_mii; + bus_space_tag_t t = sc->sc_bustag; + bus_space_handle_t h = sc->sc_h1; struct mii_softc *child; struct ifmedia_entry *ifm; int i, error; @@ -169,7 +182,7 @@ goto fail_0; } -/* XXX should map this in with correct endianness */ + /* XXX should map this in with correct endianness */ if ((error = bus_dmamem_map(sc->sc_dmatag, &sc->sc_cdseg, sc->sc_cdnseg, sizeof(struct gem_control_data), (caddr_t *)&sc->sc_control_data, BUS_DMA_COHERENT)) != 0) { @@ -255,6 +268,114 @@ sc->sc_rxsoft[i].rxs_mbuf = NULL; } + /* Initialize ifmedia structures and MII info */ + mii->mii_ifp = ifp; + mii->mii_readreg = gem_mii_readreg; + mii->mii_writereg = gem_mii_writereg; + mii->mii_statchg = gem_mii_statchg; + + ifmedia_init(&mii->mii_media, IFM_IMASK, gem_mediachange, gem_mediastatus); + + /* + * Initialization based on `GEM Gigabit Ethernet ASIC Specification' + * Section 3.2.1 `Initialization Sequence'. + * However, we can't assume SERDES or Serialink if neither + * GEM_MIF_CONFIG_MDI0 nor GEM_MIF_CONFIG_MDI1 are set + * being set, as both are set on Sun X1141A (with SERDES). So, + * we rely on our bus attachment setting GEM_SERDES or GEM_SERIAL. + */ + gem_mifinit(sc); + + if ((sc->sc_flags & (GEM_SERDES | GEM_SERIAL)) == 0) { + mii_attach(&sc->sc_dev, mii, 0xffffffff, + MII_PHY_ANY, MII_OFFSET_ANY, MIIF_FORCEANEG); + child = LIST_FIRST(&mii->mii_phys); + if (child == NULL) { + /* No PHY attached */ + aprint_error("%s: PHY probe failed\n", + sc->sc_dev.dv_xname); + goto fail_7; + } else { + /* + * Walk along the list of attached MII devices and + * establish an `MII instance' to `PHY number' + * mapping. + */ + for (; child != NULL; + child = LIST_NEXT(child, mii_list)) { + /* + * Note: we support just one PHY: the internal + * or external MII is already selected for us + * by the GEM_MIF_CONFIG register. + */ + if (child->mii_phy > 1 || child->mii_inst > 0) { + aprint_error( + "%s: cannot accommodate MII device" + " %s at PHY %d, instance %d\n", + sc->sc_dev.dv_xname, + child->mii_dev.dv_xname, + child->mii_phy, child->mii_inst); + continue; + } + sc->sc_phys[child->mii_inst] = child->mii_phy; + } + + if (sc->sc_mif_config & GEM_MIF_CONFIG_MDI0) { +#ifdef GEM_DEBUG + aprint_debug("%s: using PHY at MDIO_0\n", + sc->sc_dev.dv_xname); +#endif + } else { +#ifdef GEM_DEBUG + aprint_debug("%s: using PHY at MDIO_1\n", + sc->sc_dev.dv_xname); +#endif + } + if (sc->sc_variant != GEM_SUN_ERI) + bus_space_write_4(t, h, GEM_MII_DATAPATH_MODE, + GEM_MII_DATAPATH_MII); + + /* + * XXX - we can really do the following ONLY if the + * PHY indeed has the auto negotiation capability!! + */ + ifmedia_set(&sc->sc_media, IFM_ETHER|IFM_AUTO); + } + } else { + /* SERDES or Serialink */ + if (sc->sc_flags & GEM_SERDES) { + bus_space_write_4(t, h, GEM_MII_DATAPATH_MODE, + GEM_MII_DATAPATH_SERDES); + } else { + sc->sc_flags |= GEM_SERIAL; + bus_space_write_4(t, h, GEM_MII_DATAPATH_MODE, + GEM_MII_DATAPATH_SERIAL); + } + + aprint_normal("%s: using external PCS %s: ", + sc->sc_dev.dv_xname, + sc->sc_flags & GEM_SERDES ? "SERDES" : "Serialink"); + + ifmedia_add(&sc->sc_media, IFM_ETHER|IFM_AUTO, 0, NULL); + /* Check for FDX and HDX capabilities */ + sc->sc_mii_anar = bus_space_read_4(t, h, GEM_MII_ANAR); + if (sc->sc_mii_anar & GEM_MII_ANEG_FUL_DUPLX) { + ifmedia_add(&sc->sc_media, + IFM_ETHER|IFM_1000_SX|IFM_MANUAL|IFM_FDX, 0, NULL); + aprint_normal("1000baseSX-FDX, "); + } + if (sc->sc_mii_anar & GEM_MII_ANEG_HLF_DUPLX) { + ifmedia_add(&sc->sc_media, + IFM_ETHER|IFM_1000_SX|IFM_MANUAL|IFM_HDX, 0, NULL); + aprint_normal("1000baseSX-HDX, "); + } + ifmedia_set(&sc->sc_media, IFM_ETHER|IFM_AUTO); + sc->sc_mii_media = IFM_AUTO; + aprint_normal("auto\n"); + + gem_pcs_stop(sc, 1); + } + /* * From this point forward, the attachment cannot fail. A failure * before this point releases all resources that may have been @@ -267,11 +388,11 @@ /* Get RX FIFO size */ sc->sc_rxfifosize = 64 * - bus_space_read_4(sc->sc_bustag, sc->sc_h1, GEM_RX_FIFO_SIZE); + bus_space_read_4(t, h, GEM_RX_FIFO_SIZE); aprint_normal(", %uKB RX fifo", sc->sc_rxfifosize / 1024); /* Get TX FIFO size */ - v = bus_space_read_4(sc->sc_bustag, sc->sc_h1, GEM_TX_FIFO_SIZE); + v = bus_space_read_4(t, h, GEM_TX_FIFO_SIZE); aprint_normal(", %uKB TX fifo\n", v / 16); /* Initialize ifnet structure. */ @@ -280,9 +401,9 @@ ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_NOTRAILERS | IFF_MULTICAST; sc->sc_if_flags = ifp->if_flags; + /* The GEM hardware supports basic TCP checksum offloading only. */ ifp->if_capabilities |= - IFCAP_CSUM_TCPv4_Tx | IFCAP_CSUM_TCPv4_Rx | - IFCAP_CSUM_UDPv4_Tx | IFCAP_CSUM_UDPv4_Rx; + IFCAP_CSUM_TCPv4_Tx | IFCAP_CSUM_TCPv4_Rx; ifp->if_start = gem_start; ifp->if_ioctl = gem_ioctl; ifp->if_watchdog = gem_watchdog; @@ -290,83 +411,6 @@ ifp->if_init = gem_init; IFQ_SET_READY(&ifp->if_snd); - /* Initialize ifmedia structures and MII info */ - mii->mii_ifp = ifp; - mii->mii_readreg = gem_mii_readreg; - mii->mii_writereg = gem_mii_writereg; - mii->mii_statchg = gem_mii_statchg; - - ifmedia_init(&mii->mii_media, IFM_IMASK, gem_mediachange, gem_mediastatus); - - gem_mifinit(sc); - -#if defined (PMAC_G5) - mii_attach(&sc->sc_dev, mii, 0xffffffff, - 1, MII_OFFSET_ANY, MIIF_FORCEANEG); -#else - mii_attach(&sc->sc_dev, mii, 0xffffffff, - MII_PHY_ANY, MII_OFFSET_ANY, MIIF_FORCEANEG); -#endif - - child = LIST_FIRST(&mii->mii_phys); - if (child == NULL) { - /* No PHY attached */ - ifmedia_add(&sc->sc_media, IFM_ETHER|IFM_MANUAL, 0, NULL); - ifmedia_set(&sc->sc_media, IFM_ETHER|IFM_MANUAL); - } else { - /* - * Walk along the list of attached MII devices and - * establish an `MII instance' to `phy number' - * mapping. We'll use this mapping in media change - * requests to determine which phy to use to program - * the MIF configuration register. - */ - for (; child != NULL; child = LIST_NEXT(child, mii_list)) { - /* - * Note: we support just two PHYs: the built-in - * internal device and an external on the MII - * connector. - */ - if (child->mii_phy > 1 || child->mii_inst > 1) { - aprint_error( - "%s: cannot accommodate MII device %s" - " at phy %d, instance %d\n", - sc->sc_dev.dv_xname, - child->mii_dev.dv_xname, - child->mii_phy, child->mii_inst); - continue; - } - - sc->sc_phys[child->mii_inst] = child->mii_phy; - } - - /* - * Now select and activate the PHY we will use. - * - * The order of preference is External (MDI1), - * Internal (MDI0), Serial Link (no MII). - */ - if (sc->sc_phys[1]) { -#ifdef GEM_DEBUG - aprint_debug("using external phy\n"); -#endif - sc->sc_mif_config |= GEM_MIF_CONFIG_PHY_SEL; - } else { -#ifdef GEM_DEBUG - aprint_debug("using internal phy\n"); -#endif - sc->sc_mif_config &= ~GEM_MIF_CONFIG_PHY_SEL; - } - bus_space_write_4(sc->sc_bustag, sc->sc_h1, GEM_MIF_CONFIG, - sc->sc_mif_config); - - /* - * XXX - we can really do the following ONLY if the - * phy indeed has the auto negotiation capability!! - */ - ifmedia_set(&sc->sc_media, IFM_ETHER|IFM_AUTO); - } - /* * If we support GigE media, we support jumbo frames too. * Unless we are Apple. @@ -487,12 +531,19 @@ struct gem_softc *sc = arg; int s; - s = splnet(); - mii_tick(&sc->sc_mii); - splx(s); - - callout_reset(&sc->sc_tick_ch, hz, gem_tick, sc); - + if ((sc->sc_flags & (GEM_SERDES | GEM_SERIAL)) != 0) { + /* + * We have to reset everything if we failed to get a + * PCS interrupt. Restarting the callout is handled + * in gem_pcs_start(). + */ + gem_init(&sc->sc_ethercom.ec_if); + } else { + s = splnet(); + mii_tick(&sc->sc_mii); + splx(s); + callout_reset(&sc->sc_tick_ch, hz, gem_tick, sc); + } } static int @@ -570,11 +621,14 @@ DPRINTF(sc, ("%s: gem_stop\n", sc->sc_dev.dv_xname)); callout_stop(&sc->sc_tick_ch); - mii_down(&sc->sc_mii); + if ((sc->sc_flags & (GEM_SERDES | GEM_SERIAL)) != 0) + gem_pcs_stop(sc, disable); + else + mii_down(&sc->sc_mii); /* XXX - Should we reset these instead? */ - gem_disable_rx(sc); gem_disable_tx(sc); + gem_disable_rx(sc); /* * Release any queued transmit buffers. @@ -619,14 +673,14 @@ */ gem_disable_rx(sc); bus_space_write_4(t, h, GEM_RX_CONFIG, 0); + bus_space_barrier(t, h, GEM_RX_CONFIG, 4, BUS_SPACE_BARRIER_WRITE); /* Wait till it finishes */ if (!gem_bitwait(sc, h, GEM_RX_CONFIG, 1, 0)) printf("%s: cannot disable read dma\n", sc->sc_dev.dv_xname); - /* Wait 5ms extra. */ - delay(5000); /* Finally, reset the ERX */ bus_space_write_4(t, h2, GEM_RESET, GEM_RESET_RX); + bus_space_barrier(t, h, GEM_RESET, 4, BUS_SPACE_BARRIER_WRITE); /* Wait till it finishes */ if (!gem_bitwait(sc, h2, GEM_RESET, GEM_RESET_RX, 0)) { printf("%s: cannot reset receiver\n", sc->sc_dev.dv_xname); @@ -637,6 +691,80 @@ /* + * Reset the receiver DMA engine. + * + * Intended to be used in case of GEM_INTR_RX_TAG_ERR, GEM_MAC_RX_OVERFLOW + * etc in order to reset the receiver DMA engine only and not do a full + * reset which amongst others also downs the link and clears the FIFOs. + */ +static void +gem_reset_rxdma(struct gem_softc *sc) +{ + struct ifnet *ifp = &sc->sc_ethercom.ec_if; + bus_space_tag_t t = sc->sc_bustag; + bus_space_handle_t h = sc->sc_h1; + int i; + + if (gem_reset_rx(sc) != 0) { + gem_init(ifp); + return; + } + for (i = 0; i < GEM_NRXDESC; i++) + if (sc->sc_rxsoft[i].rxs_mbuf != NULL) + GEM_UPDATE_RXDESC(sc, i); + sc->sc_rxptr = 0; + GEM_CDSYNC(sc, BUS_DMASYNC_PREWRITE); + GEM_CDSYNC(sc, BUS_DMASYNC_PREREAD); + + /* Reprogram Descriptor Ring Base Addresses */ + /* NOTE: we use only 32-bit DMA addresses here. */ + bus_space_write_4(t, h, GEM_RX_RING_PTR_HI, 0); + bus_space_write_4(t, h, GEM_RX_RING_PTR_LO, GEM_CDRXADDR(sc, 0)); + + /* Redo ERX Configuration */ + gem_rx_common(sc); + + /* Give the reciever a swift kick */ + bus_space_write_4(t, h, GEM_RX_KICK, GEM_NRXDESC - 4); +} + +/* + * Common RX configuration for gem_init() and gem_reset_rxdma(). + */ +static void +gem_rx_common(struct gem_softc *sc) +{ + bus_space_tag_t t = sc->sc_bustag; + bus_space_handle_t h = sc->sc_h1; + u_int32_t v; + + /* Encode Receive Descriptor ring size: four possible values */ + v = gem_ringsize(GEM_NRXDESC /*XXX*/); + + /* Set receive h/w checksum offset */ +#ifdef INET + v |= (ETHER_HDR_LEN + sizeof(struct ip) + + ((sc->sc_ethercom.ec_capenable & ETHERCAP_VLAN_MTU) ? + ETHER_VLAN_ENCAP_LEN : 0)) << GEM_RX_CONFIG_CXM_START_SHFT; +#endif + + /* Enable RX DMA */ + bus_space_write_4(t, h, GEM_RX_CONFIG, + v | (GEM_THRSH_1024 << GEM_RX_CONFIG_FIFO_THRS_SHIFT) | + (2 << GEM_RX_CONFIG_FBOFF_SHFT) | GEM_RX_CONFIG_RXDMA_EN); + + /* + * 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, + (3 * sc->sc_rxfifosize / 256) | + ((sc->sc_rxfifosize / 256) << 12)); + bus_space_write_4(t, h, GEM_RX_BLANKING, + (6 << GEM_RX_BLANKING_TIME_SHIFT) | 6); +} + +/* * Reset the transmitter */ int @@ -651,6 +779,7 @@ */ gem_disable_tx(sc); bus_space_write_4(t, h, GEM_TX_CONFIG, 0); + bus_space_barrier(t, h, GEM_TX_CONFIG, 4, BUS_SPACE_BARRIER_WRITE); /* Wait till it finishes */ if (!gem_bitwait(sc, h, GEM_TX_CONFIG, 1, 0)) printf("%s: cannot disable read dma\n", sc->sc_dev.dv_xname); @@ -659,6 +788,7 @@ /* Finally, reset the ETX */ bus_space_write_4(t, h2, GEM_RESET, GEM_RESET_TX); + bus_space_barrier(t, h, GEM_RESET, 4, BUS_SPACE_BARRIER_WRITE); /* Wait till it finishes */ if (!gem_bitwait(sc, h2, GEM_RESET, GEM_RESET_TX, 0)) { printf("%s: cannot reset receiver\n", @@ -682,7 +812,7 @@ cfg = bus_space_read_4(t, h, GEM_MAC_RX_CONFIG); cfg &= ~GEM_MAC_RX_ENABLE; bus_space_write_4(t, h, GEM_MAC_RX_CONFIG, cfg); - + bus_space_barrier(t, h, GEM_MAC_RX_CONFIG, 4, BUS_SPACE_BARRIER_WRITE); /* Wait for it to finish */ return (gem_bitwait(sc, h, GEM_MAC_RX_CONFIG, GEM_MAC_RX_ENABLE, 0)); } @@ -701,7 +831,7 @@ cfg = bus_space_read_4(t, h, GEM_MAC_TX_CONFIG); cfg &= ~GEM_MAC_TX_ENABLE; bus_space_write_4(t, h, GEM_MAC_TX_CONFIG, cfg); - + bus_space_barrier(t, h, GEM_MAC_TX_CONFIG, 4, BUS_SPACE_BARRIER_WRITE); /* Wait for it to finish */ return (gem_bitwait(sc, h, GEM_MAC_TX_CONFIG, GEM_MAC_TX_ENABLE, 0)); } @@ -751,6 +881,9 @@ GEM_INIT_RXDESC(sc, i); } sc->sc_rxptr = 0; + sc->sc_meminited = 1; + GEM_CDSYNC(sc, BUS_DMASYNC_PREWRITE); + GEM_CDSYNC(sc, BUS_DMASYNC_PREREAD); return (0); } @@ -783,6 +916,102 @@ } } + +/* + * Start PCS + */ +void +gem_pcs_start(struct gem_softc *sc) +{ + bus_space_tag_t t = sc->sc_bustag; + bus_space_handle_t h = sc->sc_h1; + uint32_t v; + +#ifdef GEM_DEBUG + aprint_debug("%s: gem_pcs_start()\n", sc->sc_dev.dv_xname); +#endif + + /* + * Set up. We must disable the MII before modifying the + * GEM_MII_ANAR register + */ + if (sc->sc_flags & GEM_SERDES) { + bus_space_write_4(t, h, GEM_MII_DATAPATH_MODE, + GEM_MII_DATAPATH_SERDES); + bus_space_write_4(t, h, GEM_MII_SLINK_CONTROL, + GEM_MII_SLINK_LOOPBACK); + } else { + bus_space_write_4(t, h, GEM_MII_DATAPATH_MODE, + GEM_MII_DATAPATH_SERIAL); + bus_space_write_4(t, h, GEM_MII_SLINK_CONTROL, 0); + } + bus_space_write_4(t, h, GEM_MII_CONFIG, 0); + v = bus_space_read_4(t, h, GEM_MII_ANAR); + v |= (GEM_MII_ANEG_SYM_PAUSE | GEM_MII_ANEG_ASYM_PAUSE); + if (sc->sc_mii_media == IFM_AUTO) + v |= (GEM_MII_ANEG_FUL_DUPLX | GEM_MII_ANEG_HLF_DUPLX); + else if (sc->sc_mii_media == IFM_FDX) { + v |= GEM_MII_ANEG_FUL_DUPLX; + v &= ~GEM_MII_ANEG_HLF_DUPLX; + } else if (sc->sc_mii_media == IFM_HDX) { + v &= ~GEM_MII_ANEG_FUL_DUPLX; + v |= GEM_MII_ANEG_HLF_DUPLX; + } + + /* Configure link. */ + bus_space_write_4(t, h, GEM_MII_ANAR, v); + bus_space_write_4(t, h, GEM_MII_CONTROL, + GEM_MII_CONTROL_AUTONEG | GEM_MII_CONTROL_RAN); + bus_space_write_4(t, h, GEM_MII_CONFIG, GEM_MII_CONFIG_ENABLE); + gem_bitwait(sc, h, GEM_MII_STATUS, 0, GEM_MII_STATUS_ANEG_CPT); + + /* Start the 10 second timer */ + callout_reset(&sc->sc_tick_ch, hz * 10, gem_tick, sc); +} + +/* + * Stop PCS + */ +void +gem_pcs_stop(struct gem_softc *sc, int disable) +{ + bus_space_tag_t t = sc->sc_bustag; + bus_space_handle_t h = sc->sc_h1; + +#ifdef GEM_DEBUG + aprint_debug("%s: gem_pcs_stop()\n", sc->sc_dev.dv_xname); +#endif + + /* Tell link partner that we're going away */ + bus_space_write_4(t, h, GEM_MII_ANAR, GEM_MII_ANEG_RF); + + /* + * Disable PCS MII. The documentation suggests that setting + * GEM_MII_CONFIG_ENABLE to zero and then restarting auto- + * negotiation will shut down the link. However, it appears + * that we also need to unset the datapath mode. + */ + bus_space_write_4(t, h, GEM_MII_CONFIG, 0); + bus_space_write_4(t, h, GEM_MII_CONTROL, + GEM_MII_CONTROL_AUTONEG | GEM_MII_CONTROL_RAN); + bus_space_write_4(t, h, GEM_MII_DATAPATH_MODE, GEM_MII_DATAPATH_MII); + bus_space_write_4(t, h, GEM_MII_CONFIG, 0); + + if (disable) { + if (sc->sc_flags & GEM_SERDES) + bus_space_write_4(t, h, GEM_MII_SLINK_CONTROL, + GEM_MII_SLINK_POWER_OFF); + else + bus_space_write_4(t, h, GEM_MII_SLINK_CONTROL, + GEM_MII_SLINK_LOOPBACK | GEM_MII_SLINK_POWER_OFF); + } + + sc->sc_flags &= ~GEM_LINK; + sc->sc_mii.mii_media_active = IFM_ETHER | IFM_NONE; + sc->sc_mii.mii_media_status = IFM_AVALID; +} + + /* * Initialization of interface; set up initialization block * and transmit/receive descriptor rings. @@ -815,12 +1044,19 @@ /* Re-initialize the MIF */ gem_mifinit(sc); + /* Set up correct datapath for non-SERDES/Serialink */ + if ((sc->sc_flags & (GEM_SERDES | GEM_SERIAL)) == 0 && + sc->sc_variant != GEM_SUN_ERI) + bus_space_write_4(t, h, GEM_MII_DATAPATH_MODE, + GEM_MII_DATAPATH_MII); + /* Call MI reset function if any */ if (sc->sc_hwreset) (*sc->sc_hwreset)(sc); /* step 3. Setup data structures in host memory */ - gem_meminit(sc); + if (gem_meminit(sc) != 0) + return 1; /* step 4. TX MAC registers & counters */ gem_init_regs(sc); @@ -843,58 +1079,38 @@ bus_space_write_4(t, h, GEM_RX_RING_PTR_LO, GEM_CDRXADDR(sc, 0)); /* step 8. Global Configuration & Interrupt Mask */ + if ((sc->sc_flags & (GEM_SERDES | GEM_SERIAL)) != 0) + v = GEM_INTR_PCS; + else + v = GEM_INTR_MIF; bus_space_write_4(t, h, GEM_INTMASK, - ~(GEM_INTR_TX_INTME| - GEM_INTR_TX_EMPTY| - GEM_INTR_RX_DONE|GEM_INTR_RX_NOBUF| - GEM_INTR_RX_TAG_ERR|GEM_INTR_PCS| - GEM_INTR_MAC_CONTROL|GEM_INTR_MIF| - GEM_INTR_BERR)); + ~(GEM_INTR_TX_INTME | + GEM_INTR_TX_EMPTY | + GEM_INTR_TX_MAC | + GEM_INTR_RX_DONE | GEM_INTR_RX_NOBUF| + GEM_INTR_RX_TAG_ERR | GEM_INTR_MAC_CONTROL| + GEM_INTR_BERR | v)); 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 */ + GEM_MAC_RX_DONE | GEM_MAC_RX_FRAME_CNT); + bus_space_write_4(t, h, GEM_MAC_TX_MASK, 0xffff); /* XXX */ + bus_space_write_4(t, h, GEM_MAC_CONTROL_MASK, + GEM_MAC_PAUSED | GEM_MAC_PAUSE | GEM_MAC_RESUME); /* step 9. ETX Configuration: use mostly default values */ - /* Enable DMA */ + /* Enable TX DMA */ 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)); + ((0x4FF<<10)&GEM_TX_CONFIG_TXFIFO_TH)); bus_space_write_4(t, h, GEM_TX_KICK, sc->sc_txnext); /* step 10. ERX Configuration */ - - /* Encode Receive Descriptor ring size: four possible values */ - v = gem_ringsize(GEM_NRXDESC /*XXX*/); - - /* Set receive h/w checksum offset */ -#ifdef INET - v |= (ETHER_HDR_LEN + sizeof(struct ip) + - ((sc->sc_ethercom.ec_capenable & ETHERCAP_VLAN_MTU) ? - ETHER_VLAN_ENCAP_LEN : 0)) << GEM_RX_CONFIG_CXM_START_SHFT; -#endif - - /* Enable DMA */ - bus_space_write_4(t, h, GEM_RX_CONFIG, - v|(GEM_THRSH_1024<sc_rxfifosize / 256) | - ( (sc->sc_rxfifosize / 256) << 12)); - bus_space_write_4(t, h, GEM_RX_BLANKING, (6<<12)|6); + gem_rx_common(sc); /* step 11. Configure Media */ - mii_mediachg(&sc->sc_mii); - -/* XXXX Serial link needs a whole different setup. */ - + if ((sc->sc_flags & (GEM_SERDES | GEM_SERIAL)) == 0) + mii_mediachg(&sc->sc_mii); /* step 12. RX_MAC Configuration Register */ v = bus_space_read_4(t, h, GEM_MAC_RX_CONFIG); @@ -911,13 +1127,19 @@ /* step 15. Give the reciever a swift kick */ bus_space_write_4(t, h, GEM_RX_KICK, GEM_NRXDESC-4); - /* Start the one second timer. */ - callout_reset(&sc->sc_tick_ch, hz, gem_tick, sc); + if ((sc->sc_flags & (GEM_SERDES | GEM_SERIAL)) != 0) + /* Configure PCS */ + gem_pcs_start(sc); + else + /* Start the one second timer. */ + callout_reset(&sc->sc_tick_ch, hz, gem_tick, sc); + sc->sc_flags &= ~GEM_LINK; ifp->if_flags |= IFF_RUNNING; ifp->if_flags &= ~IFF_OACTIVE; ifp->if_timer = 0; sc->sc_if_flags = ifp->if_flags; + splx(s); return (0); @@ -935,20 +1157,19 @@ /* These regs are not cleared on reset */ if (!sc->sc_inited) { - /* Wooo. Magic values. */ - bus_space_write_4(t, h, GEM_MAC_IPG0, 0); - bus_space_write_4(t, h, GEM_MAC_IPG1, 8); - bus_space_write_4(t, h, GEM_MAC_IPG2, 4); + /* Load recommended values */ + bus_space_write_4(t, h, GEM_MAC_IPG0, 0x00); + bus_space_write_4(t, h, GEM_MAC_IPG1, 0x08); + bus_space_write_4(t, h, GEM_MAC_IPG2, 0x04); bus_space_write_4(t, h, GEM_MAC_MAC_MIN_FRAME, ETHER_MIN_LEN); /* Max frame and max burst size */ bus_space_write_4(t, h, GEM_MAC_MAC_MAX_FRAME, - ETHER_MAX_LEN | (0x2000<<16)); + ETHER_MAX_LEN | (0x2000<<16)); - 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_PREAMBLE_LEN, 0x07); + bus_space_write_4(t, h, GEM_MAC_JAM_SIZE, 0x04); 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, ((laddr[5]<<8)|laddr[4])&0x3ff); @@ -987,12 +1208,20 @@ bus_space_write_4(t, h, GEM_MAC_RX_CRC_ERR_CNT, 0); bus_space_write_4(t, h, GEM_MAC_RX_CODE_VIOL, 0); - /* Un-pause stuff */ -#if 0 + /* Set XOFF PAUSE time. */ bus_space_write_4(t, h, GEM_MAC_SEND_PAUSE_CMD, 0x1BF0); -#else - bus_space_write_4(t, h, GEM_MAC_SEND_PAUSE_CMD, 0); -#endif + + /* + * Set the internal arbitration to "infinite" bursts of the + * maximum length of 31 * 64 bytes so DMA transfers aren't + * split up in cache line size chunks. This greatly improves + * especially RX performance. + * Enable silicon bug workarounds for the Apple variants. + */ + bus_space_write_4(t, h, GEM_CONFIG, + GEM_CONFIG_TXDMA_LIMIT | GEM_CONFIG_RXDMA_LIMIT | + GEM_CONFIG_BURST_INF | (GEM_IS_APPLE(sc) ? + GEM_CONFIG_RONPAULBIT | GEM_CONFIG_BUG2FIX : 0)); /* * Set the station address. @@ -1001,31 +1230,40 @@ bus_space_write_4(t, h, GEM_MAC_ADDR1, (laddr[2]<<8)|laddr[3]); bus_space_write_4(t, h, GEM_MAC_ADDR2, (laddr[0]<<8)|laddr[1]); -#if 0 - if (sc->sc_variant != APPLE_GMAC) - return; -#endif - /* * 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; - } + if (sc->sc_flags & GEM_GIGABIT) + v |= GEM_MAC_XIF_GMII_MODE; bus_space_write_4(t, h, GEM_MAC_XIF_CONFIG, v); } +#ifdef GEM_DEBUG +static void +gem_txsoft_print(const struct gem_softc *sc, int firstdesc, int lastdesc) +{ + int i; + + for (i = firstdesc;; i = GEM_NEXTTX(i)) { + printf("descriptor %d:\t", i); + printf("gd_flags: 0x%016" PRIx64 "\t", + GEM_DMA_READ(sc, sc->sc_txdescs[i].gd_flags)); + printf("gd_addr: 0x%016" PRIx64 "\n", + GEM_DMA_READ(sc, sc->sc_txdescs[i].gd_addr)); + if (i == lastdesc) + break; + } +} +#endif + static void gem_start(ifp) struct ifnet *ifp; { struct gem_softc *sc = (struct gem_softc *)ifp->if_softc; struct mbuf *m0, *m; - struct gem_txsoft *txs, *last_txs; + struct gem_txsoft *txs; bus_dmamap_t dmamap; int error, firsttx, nexttx = -1, lasttx = -1, ofree, seg; uint64_t flags = 0; @@ -1049,7 +1287,7 @@ * descriptors. */ while ((txs = SIMPLEQ_FIRST(&sc->sc_txfreeq)) != NULL && - sc->sc_txfree != 0) { + sc->sc_txfree != 0) { /* * Grab a packet off the queue. */ @@ -1167,9 +1405,8 @@ #ifdef INET /* h/w checksum */ - if (ifp->if_csum_flags_tx & (M_CSUM_TCPv4 | - M_CSUM_UDPv4) && m0->m_pkthdr.csum_flags & - (M_CSUM_TCPv4|M_CSUM_UDPv4)) { + if (ifp->if_csum_flags_tx & M_CSUM_TCPv4 && + m0->m_pkthdr.csum_flags & M_CSUM_TCPv4) { struct ether_header *eh; uint16_t offset, start; @@ -1238,20 +1475,13 @@ #ifdef GEM_DEBUG if (ifp->if_flags & IFF_DEBUG) { printf(" gem_start %p transmit chain:\n", txs); - for (seg = sc->sc_txnext;; seg = GEM_NEXTTX(seg)) { - printf("descriptor %d:\t", seg); - printf("gd_flags: 0x%016llx\t", (long long) - GEM_DMA_READ(sc, sc->sc_txdescs[seg].gd_flags)); - printf("gd_addr: 0x%016llx\n", (long long) - GEM_DMA_READ(sc, sc->sc_txdescs[seg].gd_addr)); - if (seg == lasttx) - break; - } + gem_txsoft_print(sc, txs->txs_firstdesc, + txs->txs_lastdesc); } #endif /* Sync the descriptors we're using. */ - GEM_CDTXSYNC(sc, sc->sc_txnext, dmamap->dm_nsegs, + GEM_CDTXSYNC(sc, txs->txs_firstdesc, txs->txs_ndescs, BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE); /* Advance the tx pointer. */ @@ -1261,8 +1491,6 @@ SIMPLEQ_REMOVE_HEAD(&sc->sc_txfreeq, txs_q); SIMPLEQ_INSERT_TAIL(&sc->sc_txdirtyq, txs, txs_q); - last_txs = txs; - #if NBPFILTER > 0 /* * Pass the packet to any BPF listeners. @@ -1311,7 +1539,6 @@ int txlast; int progress = 0; - DPRINTF(sc, ("%s: gem_tint\n", sc->sc_dev.dv_xname)); /* @@ -1336,65 +1563,60 @@ * frames that have been transmitted. */ while ((txs = SIMPLEQ_FIRST(&sc->sc_txdirtyq)) != NULL) { - GEM_CDTXSYNC(sc, txs->txs_lastdesc, - txs->txs_ndescs, - BUS_DMASYNC_POSTREAD|BUS_DMASYNC_POSTWRITE); - -#ifdef GEM_DEBUG - if (ifp->if_flags & IFF_DEBUG) { - int i; - printf(" txsoft %p transmit chain:\n", txs); - for (i = txs->txs_firstdesc;; i = GEM_NEXTTX(i)) { - printf("descriptor %d: ", i); - printf("gd_flags: 0x%016llx\t", (long long) - GEM_DMA_READ(sc, sc->sc_txdescs[i].gd_flags)); - printf("gd_addr: 0x%016llx\n", (long long) - GEM_DMA_READ(sc, sc->sc_txdescs[i].gd_addr)); - if (i == txs->txs_lastdesc) - break; - } - } -#endif - /* - * In theory, we could harveast some descriptors before + * In theory, we could harvest some descriptors before * the ring is empty, but that's a bit complicated. * * GEM_TX_COMPLETION points to the last descriptor * processed +1. + * + * Let's assume that the NIC writes back to the Tx + * descriptors before it updates the completion + * register. If the NIC has posted writes to the + * Tx descriptors, PCI ordering requires that the + * posted writes flush to RAM before the register-read + * finishes. So let's read the completion register, + * before syncing the descriptors, so that we + * examine Tx descriptors that are at least as + * current as the completion register. */ txlast = bus_space_read_4(t, mac, GEM_TX_COMPLETION); DPRINTF(sc, ("gem_tint: txs->txs_lastdesc = %d, txlast = %d\n", txs->txs_lastdesc, txlast)); if (txs->txs_firstdesc <= txs->txs_lastdesc) { - if ((txlast >= txs->txs_firstdesc) && - (txlast <= txs->txs_lastdesc)) - break; - } else { - /* Ick -- this command wraps */ - if ((txlast >= txs->txs_firstdesc) || - (txlast <= txs->txs_lastdesc)) + if (txlast >= txs->txs_firstdesc && + txlast <= txs->txs_lastdesc) break; + } else if (txlast >= txs->txs_firstdesc || + txlast <= txs->txs_lastdesc) + break; + + GEM_CDTXSYNC(sc, txs->txs_firstdesc, txs->txs_ndescs, + BUS_DMASYNC_POSTREAD|BUS_DMASYNC_POSTWRITE); + +#ifdef GEM_DEBUG /* XXX DMA synchronization? */ + if (ifp->if_flags & IFF_DEBUG) { + printf(" txsoft %p transmit chain:\n", txs); + gem_txsoft_print(sc, txs->txs_firstdesc, + txs->txs_lastdesc); } +#endif + DPRINTF(sc, ("gem_tint: releasing a desc\n")); SIMPLEQ_REMOVE_HEAD(&sc->sc_txdirtyq, txs_q); sc->sc_txfree += txs->txs_ndescs; - if (txs->txs_mbuf == NULL) { -#ifdef DIAGNOSTIC - panic("gem_txintr: null mbuf"); -#endif - } - bus_dmamap_sync(sc->sc_dmatag, txs->txs_dmamap, 0, txs->txs_dmamap->dm_mapsize, BUS_DMASYNC_POSTWRITE); bus_dmamap_unload(sc->sc_dmatag, txs->txs_dmamap); - m_freem(txs->txs_mbuf); - txs->txs_mbuf = NULL; + if (txs->txs_mbuf != NULL) { + m_freem(txs->txs_mbuf); + txs->txs_mbuf = NULL; + } SIMPLEQ_INSERT_TAIL(&sc->sc_txfreeq, txs, txs_q); @@ -1418,12 +1640,11 @@ if (sc->sc_txfree == GEM_NTXDESC - 1) sc->sc_txwin = 0; + /* Freed some descriptors, so reset IFF_OACTIVE and restart. */ ifp->if_flags &= ~IFF_OACTIVE; sc->sc_if_flags = ifp->if_flags; + ifp->if_timer = SIMPLEQ_EMPTY(&sc->sc_txdirtyq) ? 0 : 5; gem_start(ifp); - - if (SIMPLEQ_EMPTY(&sc->sc_txdirtyq)) - ifp->if_timer = 0; } DPRINTF(sc, ("%s: gem_tint: watchdog %d\n", sc->sc_dev.dv_xname, ifp->if_timer)); @@ -1450,13 +1671,20 @@ DPRINTF(sc, ("%s: gem_rint\n", sc->sc_dev.dv_xname)); /* + * Ignore spurious interrupt that sometimes occurs before + * we are set up when we network boot. + */ + if (!sc->sc_meminited) + return 1; + + /* * Read the completion register once. This limits * how long the following loop can execute. */ rxcomp = bus_space_read_4(t, h, GEM_RX_COMPLETION); /* - * XXXX Read the lastrx only once at the top for speed. + * XXX Read the lastrx only once at the top for speed. */ DPRINTF(sc, ("gem_rint: sc->rxptr %d, complete %d\n", sc->sc_rxptr, rxcomp)); @@ -1474,6 +1702,7 @@ rxstat = GEM_DMA_READ(sc, sc->sc_rxdescs[i].gd_flags); if (rxstat & GEM_RD_OWN) { + GEM_CDRXSYNC(sc, i, BUS_DMASYNC_PREREAD); /* * We have processed all of the receive buffers. */ @@ -1528,18 +1757,17 @@ #if NBPFILTER > 0 /* * Pass this up to any BPF listeners, but only - * pass it up the stack if its for us. + * pass it up the stack if it's for us. */ if (ifp->if_bpf) bpf_mtap(ifp->if_bpf, m); -#endif /* NPBFILTER > 0 */ +#endif /* NBPFILTER > 0 */ #ifdef INET /* hardware checksum */ - if (ifp->if_csum_flags_rx & (M_CSUM_UDPv4 | M_CSUM_TCPv4)) { + if (ifp->if_csum_flags_rx & M_CSUM_TCPv4) { struct ether_header *eh; struct ip *ip; - struct udphdr *uh; int32_t hlen, pktlen; if (sc->sc_ethercom.ec_capenable & ETHERCAP_VLAN_MTU) { @@ -1581,16 +1809,7 @@ m->m_pkthdr.csum_flags = M_CSUM_TCPv4; break; case IPPROTO_UDP: - if (! (ifp->if_csum_flags_rx & M_CSUM_UDPv4)) - goto swcsum; - if (pktlen < (hlen + sizeof(struct udphdr))) - goto swcsum; - uh = (struct udphdr *)((caddr_t)ip + hlen); - /* no checksum */ - if (uh->uh_sum == 0) - goto swcsum; - m->m_pkthdr.csum_flags = M_CSUM_UDPv4; - break; + /* FALLTHROUGH */ default: goto swcsum; } @@ -1726,23 +1945,124 @@ int -gem_eint(sc, status) - struct gem_softc *sc; - u_int status; +gem_eint(struct gem_softc *sc, u_int status) { char bits[128]; + u_int32_t v; if ((status & GEM_INTR_MIF) != 0) { printf("%s: XXXlink status changed\n", sc->sc_dev.dv_xname); return (1); } + if ((status & GEM_INTR_RX_TAG_ERR) != 0) { + gem_reset_rxdma(sc); + return (1); + } + + if (status & GEM_INTR_BERR) { + bus_space_read_4(sc->sc_bustag, sc->sc_h2, GEM_ERROR_STATUS); + v = bus_space_read_4(sc->sc_bustag, sc->sc_h2, + GEM_ERROR_STATUS); + printf("%s: bus error interrupt: 0x%02x\n", + sc->sc_dev.dv_xname, v); + return (1); + } + printf("%s: status=%s\n", sc->sc_dev.dv_xname, bitmask_snprintf(status, GEM_INTR_BITS, bits, sizeof(bits))); return (1); } +/* + * PCS interrupts. + * We should receive these when the link status changes, but sometimes + * we don't receive them for link up. We compensate for this in the + * gem_tick() callout. + */ +int +gem_pint(struct gem_softc *sc) +{ + struct ifnet *ifp = &sc->sc_ethercom.ec_if; + bus_space_tag_t t = sc->sc_bustag; + bus_space_handle_t h = sc->sc_h1; + u_int32_t v, v2; + + /* + * Clear the PCS interrupt from GEM_STATUS. The PCS register is + * latched, so we have to read it twice. There is only one bit in + * use, so the value is meaningless. + */ + bus_space_read_4(t, h, GEM_MII_INTERRUP_STATUS); + bus_space_read_4(t, h, GEM_MII_INTERRUP_STATUS); + + if ((ifp->if_flags & IFF_UP) == 0) + return 1; + + if ((sc->sc_flags & (GEM_SERDES | GEM_SERIAL)) == 0) + return 1; + + v = bus_space_read_4(t, h, GEM_MII_STATUS); + /* If we see remote fault, our link partner is probably going away */ + if ((v & GEM_MII_STATUS_REM_FLT) != 0) { + gem_bitwait(sc, h, GEM_MII_STATUS, GEM_MII_STATUS_REM_FLT, 0); + v = bus_space_read_4(t, h, GEM_MII_STATUS); + /* Otherwise, we may need to wait after auto-negotiation completes */ + } else if ((v & (GEM_MII_STATUS_LINK_STS | GEM_MII_STATUS_ANEG_CPT)) == + GEM_MII_STATUS_ANEG_CPT) { + gem_bitwait(sc, h, GEM_MII_STATUS, 0, GEM_MII_STATUS_LINK_STS); + v = bus_space_read_4(t, h, GEM_MII_STATUS); + } + if ((v & GEM_MII_STATUS_LINK_STS) != 0) { + if (sc->sc_flags & GEM_LINK) { + return 1; + } + callout_stop(&sc->sc_tick_ch); + v = bus_space_read_4(t, h, GEM_MII_ANAR); + v2 = bus_space_read_4(t, h, GEM_MII_ANLPAR); + sc->sc_mii.mii_media_active = IFM_ETHER | IFM_1000_SX; + sc->sc_mii.mii_media_status = IFM_AVALID | IFM_ACTIVE; + v &= v2; + if (v & GEM_MII_ANEG_FUL_DUPLX) { + sc->sc_mii.mii_media_active |= IFM_FDX; +#ifdef GEM_DEBUG + aprint_debug("%s: link up: full duplex\n", + sc->sc_dev.dv_xname); +#endif + } else if (v & GEM_MII_ANEG_HLF_DUPLX) { + sc->sc_mii.mii_media_active |= IFM_HDX; +#ifdef GEM_DEBUG + aprint_debug("%s: link up: half duplex\n", + sc->sc_dev.dv_xname); +#endif + } else { +#ifdef GEM_DEBUG + aprint_debug("%s: duplex mismatch\n", + sc->sc_dev.dv_xname); +#endif + } + gem_statuschange(sc); + } else { + if ((sc->sc_flags & GEM_LINK) == 0) { + return 1; + } + sc->sc_mii.mii_media_active = IFM_ETHER | IFM_NONE; + sc->sc_mii.mii_media_status = IFM_AVALID; +#ifdef GEM_DEBUG + aprint_debug("%s: link down\n", + sc->sc_dev.dv_xname); +#endif + gem_statuschange(sc); + + /* Start the 10 second timer */ + callout_reset(&sc->sc_tick_ch, hz * 10, gem_tick, sc); + } + return 1; +} + + + int gem_intr(v) void *v; @@ -1750,16 +2070,18 @@ struct gem_softc *sc = (struct gem_softc *)v; struct ifnet *ifp = &sc->sc_ethercom.ec_if; bus_space_tag_t t = sc->sc_bustag; - bus_space_handle_t seb = sc->sc_h1; + bus_space_handle_t h = sc->sc_h1; u_int32_t status; int r = 0; #ifdef GEM_DEBUG char bits[128]; #endif + /* XXX We should probably mask out interrupts until we're done */ + sc->sc_ev_intr.ev_count++; - status = bus_space_read_4(t, seb, GEM_STATUS); + status = bus_space_read_4(t, h, GEM_STATUS); DPRINTF(sc, ("%s: gem_intr: cplt 0x%x status %s\n", sc->sc_dev.dv_xname, (status >> 19), bitmask_snprintf(status, GEM_INTR_BITS, bits, sizeof(bits)))); @@ -1767,6 +2089,7 @@ if ((status & (GEM_INTR_RX_TAG_ERR | GEM_INTR_BERR)) != 0) r |= gem_eint(sc, status); + /* We don't bother with GEM_INTR_TX_DONE */ if ((status & (GEM_INTR_TX_EMPTY | GEM_INTR_TX_INTME)) != 0) { GEM_COUNTER_INCR(sc, sc_ev_txint); r |= gem_tint(sc); @@ -1779,7 +2102,7 @@ /* We should eventually do more than just print out error stats. */ if (status & GEM_INTR_TX_MAC) { - int txstat = bus_space_read_4(t, seb, GEM_MAC_TX_STATUS); + int txstat = bus_space_read_4(t, h, GEM_MAC_TX_STATUS); if (txstat & ~GEM_MAC_TX_XMIT_DONE) printf("%s: MAC tx fault, status %x\n", sc->sc_dev.dv_xname, txstat); @@ -1787,20 +2110,43 @@ gem_init(ifp); } if (status & GEM_INTR_RX_MAC) { - int rxstat = bus_space_read_4(t, seb, GEM_MAC_RX_STATUS); + int rxstat = bus_space_read_4(t, h, GEM_MAC_RX_STATUS); if (rxstat & ~GEM_MAC_RX_DONE) printf("%s: MAC rx fault, status %x\n", sc->sc_dev.dv_xname, rxstat); /* - * On some chip revisions GEM_MAC_RX_OVERFLOW happen often - * due to a silicon bug so handle them silently. + * At least with GEM_SUN_GEM and some GEM_SUN_ERI + * revisions GEM_MAC_RX_OVERFLOW happen often due to a + * silicon bug so handle them silently. Moreover, it's + * likely that the receiver has hung so we reset it. */ - if (rxstat & GEM_MAC_RX_OVERFLOW) - gem_init(ifp); - else if (rxstat & ~(GEM_MAC_RX_DONE | GEM_MAC_RX_FRAME_CNT)) + if (rxstat & GEM_MAC_RX_OVERFLOW) { + ifp->if_ierrors++; + gem_reset_rxdma(sc); + } else if (rxstat & ~(GEM_MAC_RX_DONE | GEM_MAC_RX_FRAME_CNT)) printf("%s: MAC rx fault, status %x\n", sc->sc_dev.dv_xname, rxstat); } + if (status & GEM_INTR_PCS) { + r |= gem_pint(sc); + } + +/* Do we need to do anything with these? + if ((status & GEM_MAC_CONTROL_STATUS) != 0) { + status2 = bus_read_4(sc->sc_res[0], GEM_MAC_CONTROL_STATUS); + if ((status2 & GEM_MAC_PAUSED) != 0) + aprintf_debug("%s: PAUSE received (%d slots)\n", + GEM_MAC_PAUSE_TIME(status2), sc->sc_dev.dv_xname); + if ((status2 & GEM_MAC_PAUSE) != 0) + aprintf_debug("%s: transited to PAUSE state\n", + sc->sc_dev.dv_xname); + if ((status2 & GEM_MAC_RESUME) != 0) + aprintf_debug("%s: transited to non-PAUSE state\n", + sc->sc_dev.dv_xname); + } + if ((status & GEM_INTR_MIF) != 0) + aprintf_debug("%s: MIF interrupt\n", sc->sc_dev.dv_xname); +*/ #if NRND > 0 rnd_add_uint32(&sc->rnd_source, status); #endif @@ -1870,18 +2216,7 @@ #ifdef GEM_DEBUG1 if (sc->sc_debug) - printf("gem_mii_readreg: phy %d reg %d\n", phy, reg); -#endif - -#if 0 - /* Select the desired PHY in the MIF configuration register */ - v = bus_space_read_4(t, mif, GEM_MIF_CONFIG); - /* Clear PHY select bit */ - v &= ~GEM_MIF_CONFIG_PHY_SEL; - if (phy == GEM_PHYAD_EXTERNAL) - /* Set PHY select bit to get at external device */ - v |= GEM_MIF_CONFIG_PHY_SEL; - bus_space_write_4(t, mif, GEM_MIF_CONFIG, v); + printf("gem_mii_readreg: PHY %d reg %d\n", phy, reg); #endif /* Construct the frame command */ @@ -1913,20 +2248,10 @@ #ifdef GEM_DEBUG1 if (sc->sc_debug) - printf("gem_mii_writereg: phy %d reg %d val %x\n", + printf("gem_mii_writereg: PHY %d reg %d val %x\n", phy, reg, val); #endif -#if 0 - /* Select the desired PHY in the MIF configuration register */ - v = bus_space_read_4(t, mif, GEM_MIF_CONFIG); - /* Clear PHY select bit */ - v &= ~GEM_MIF_CONFIG_PHY_SEL; - if (phy == GEM_PHYAD_EXTERNAL) - /* Set PHY select bit to get at external device */ - v |= GEM_MIF_CONFIG_PHY_SEL; - bus_space_write_4(t, mif, GEM_MIF_CONFIG, v); -#endif /* Construct the frame command */ v = GEM_MIF_FRAME_WRITE | (phy << GEM_MIF_PHY_SHIFT) | @@ -1952,52 +2277,111 @@ #ifdef GEM_DEBUG int instance = IFM_INST(sc->sc_mii.mii_media.ifm_cur->ifm_media); #endif - bus_space_tag_t t = sc->sc_bustag; - bus_space_handle_t mac = sc->sc_h1; - u_int32_t v; #ifdef GEM_DEBUG if (sc->sc_debug) printf("gem_mii_statchg: status change: phy = %d\n", sc->sc_phys[instance]); #endif + gem_statuschange(sc); +} +/* + * Common status change for gem_mii_statchg() and gem_pint() + */ +void +gem_statuschange(struct gem_softc* sc) +{ + struct ifnet *ifp = &sc->sc_ethercom.ec_if; + bus_space_tag_t t = sc->sc_bustag; + bus_space_handle_t mac = sc->sc_h1; + int gigabit; + u_int32_t rxcfg, txcfg, v; - /* Set tx full duplex options */ - bus_space_write_4(t, mac, GEM_MAC_TX_CONFIG, 0); - delay(10000); /* reg must be cleared and delay before changing. */ - v = GEM_MAC_TX_ENA_IPG0|GEM_MAC_TX_NGU|GEM_MAC_TX_NGU_LIMIT| - GEM_MAC_TX_ENABLE; - if ((IFM_OPTIONS(sc->sc_mii.mii_media_active) & IFM_FDX) != 0) { - v |= GEM_MAC_TX_IGN_CARRIER|GEM_MAC_TX_IGN_COLLIS; + if ((sc->sc_mii.mii_media_status & IFM_ACTIVE) != 0 && + IFM_SUBTYPE(sc->sc_mii.mii_media_active) != IFM_NONE) + sc->sc_flags |= GEM_LINK; + else + sc->sc_flags &= ~GEM_LINK; + + switch (IFM_SUBTYPE(sc->sc_mii.mii_media_active)) { + case IFM_1000_SX: + case IFM_1000_LX: + case IFM_1000_CX: + case IFM_1000_T: + gigabit = 1; + break; + default: + gigabit = 0; } - bus_space_write_4(t, mac, GEM_MAC_TX_CONFIG, v); - /* XIF Configuration */ - /* We should really calculate all this rather than rely on defaults */ - v = bus_space_read_4(t, mac, GEM_MAC_XIF_CONFIG); - v = GEM_MAC_XIF_LINK_LED; - v |= GEM_MAC_XIF_TX_MII_ENA; + /* + * The configuration done here corresponds to the steps F) and + * G) and as far as enabling of RX and TX MAC goes also step H) + * of the initialization sequence outlined in section 3.2.1 of + * the GEM Gigabit Ethernet ASIC Specification. + */ - /* If an external transceiver is connected, enable its MII drivers */ - sc->sc_mif_config = bus_space_read_4(t, mac, GEM_MIF_CONFIG); - if ((sc->sc_mif_config & GEM_MIF_CONFIG_MDI1) != 0) { - /* External MII needs echo disable if half duplex. */ - 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; + rxcfg = bus_space_read_4(t, mac, GEM_MAC_RX_CONFIG); + rxcfg &= ~(GEM_MAC_RX_CARR_EXTEND | GEM_MAC_RX_ENABLE); + txcfg = GEM_MAC_TX_ENA_IPG0 | GEM_MAC_TX_NGU | GEM_MAC_TX_NGU_LIMIT; + if ((IFM_OPTIONS(sc->sc_mii.mii_media_active) & IFM_FDX) != 0) + txcfg |= GEM_MAC_TX_IGN_CARRIER | GEM_MAC_TX_IGN_COLLIS; + else if (gigabit) { + rxcfg |= GEM_MAC_RX_CARR_EXTEND; + txcfg |= GEM_MAC_RX_CARR_EXTEND; + } + bus_space_write_4(t, mac, GEM_MAC_TX_CONFIG, 0); + bus_space_barrier(t, mac, GEM_MAC_TX_CONFIG, 4, + BUS_SPACE_BARRIER_WRITE); + if (!gem_bitwait(sc, mac, GEM_MAC_TX_CONFIG, GEM_MAC_TX_ENABLE, 0)) + aprint_normal("%s: cannot disable TX MAC\n", + sc->sc_dev.dv_xname); + bus_space_write_4(t, mac, GEM_MAC_TX_CONFIG, txcfg); + bus_space_write_4(t, mac, GEM_MAC_RX_CONFIG, 0); + bus_space_barrier(t, mac, GEM_MAC_RX_CONFIG, 4, + BUS_SPACE_BARRIER_WRITE); + if (!gem_bitwait(sc, mac, GEM_MAC_RX_CONFIG, GEM_MAC_RX_ENABLE, 0)) + aprint_normal("%s: cannot disable RX MAC\n", + sc->sc_dev.dv_xname); + bus_space_write_4(t, mac, GEM_MAC_RX_CONFIG, rxcfg); - if (sc->sc_ethercom.ec_if.if_baudrate == IF_Mbps(1000)) - v |= GEM_MAC_XIF_GMII_MODE; - else - v &= ~GEM_MAC_XIF_GMII_MODE; - } else - /* Internal MII needs buf enable */ + v = bus_space_read_4(t, mac, GEM_MAC_CONTROL_CONFIG) & + ~(GEM_MAC_CC_RX_PAUSE | GEM_MAC_CC_TX_PAUSE); + bus_space_write_4(t, mac, GEM_MAC_CONTROL_CONFIG, v); + + if ((IFM_OPTIONS(sc->sc_mii.mii_media_active) & IFM_FDX) == 0 && + gigabit != 0) + bus_space_write_4(t, mac, GEM_MAC_SLOT_TIME, + GEM_MAC_SLOT_TIME_CARR_EXTEND); + else + bus_space_write_4(t, mac, GEM_MAC_SLOT_TIME, + GEM_MAC_SLOT_TIME_NORMAL); + + /* XIF Configuration */ + if (sc->sc_flags & GEM_LINK) + v = GEM_MAC_XIF_LINK_LED; + else + v = 0; + v |= GEM_MAC_XIF_TX_MII_ENA; + if ((IFM_OPTIONS(sc->sc_mii.mii_media_active) & IFM_FDX) == 0) { + /* MII/GMII needs echo disable if half duplex. */ + if ((sc->sc_flags &(GEM_SERDES | GEM_SERIAL)) == 0) + v |= GEM_MAC_XIF_ECHO_DISABL; + v &= ~GEM_MAC_XIF_FDPLX_LED; + } else { v |= GEM_MAC_XIF_MII_BUF_ENA; - bus_space_write_4(t, mac, GEM_MAC_XIF_CONFIG, v); + v |= GEM_MAC_XIF_FDPLX_LED; + } + if (gigabit != 0) + v |= GEM_MAC_XIF_GMII_MODE; + if ((ifp->if_flags & IFF_RUNNING) != 0 && + (sc->sc_flags & GEM_LINK) != 0) { + bus_space_write_4(t, mac, GEM_MAC_TX_CONFIG, + txcfg | GEM_MAC_TX_ENABLE); + bus_space_write_4(t, mac, GEM_MAC_RX_CONFIG, + rxcfg | GEM_MAC_RX_ENABLE); + } } int @@ -2005,11 +2389,49 @@ struct ifnet *ifp; { struct gem_softc *sc = ifp->if_softc; + u_int s, t; if (IFM_TYPE(sc->sc_media.ifm_media) != IFM_ETHER) - return (EINVAL); + return EINVAL; - return (mii_mediachg(&sc->sc_mii)); + if ((sc->sc_flags & (GEM_SERDES | GEM_SERIAL)) != 0) { + s = IFM_SUBTYPE(sc->sc_media.ifm_media); + if (s == IFM_AUTO) { + if (sc->sc_mii_media != s) { +#ifdef GEM_DEBUG + aprint_debug("%s: setting media to auto\n", + sc->sc_dev.dv_xname); +#endif + sc->sc_mii_media = s; + if (ifp->if_flags & IFF_UP) { + gem_pcs_stop(sc, 0); + gem_pcs_start(sc); + } + } + return 0; + } + if (s == IFM_1000_SX) { + t = IFM_OPTIONS(sc->sc_media.ifm_media); + if (t == IFM_FDX || t == IFM_HDX) { + if (sc->sc_mii_media != t) { + sc->sc_mii_media = t; +#ifdef GEM_DEBUG + aprint_debug("%s:" + " setting media to 1000baseSX-%s\n", + sc->sc_dev.dv_xname, + t == IFM_FDX ? "FDX" : "HDX"); +#endif + if (ifp->if_flags & IFF_UP) { + gem_pcs_stop(sc, 0); + gem_pcs_start(sc); + } + } + return 0; + } + } + return EINVAL; + } else + return (mii_mediachg(&sc->sc_mii)); } void @@ -2022,7 +2444,8 @@ if ((ifp->if_flags & IFF_UP) == 0) return; - mii_pollstat(&sc->sc_mii); + if ((sc->sc_flags & (GEM_SERDES | GEM_SERIAL)) == 0) + mii_pollstat(&sc->sc_mii); ifmr->ifm_active = sc->sc_mii.mii_media_active; ifmr->ifm_status = sc->sc_mii.mii_media_status; } @@ -2147,7 +2570,7 @@ * 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 + * XXX should use the address filters for this */ ifp->if_flags |= IFF_ALLMULTI; v |= GEM_MAC_RX_PROMISC_GRP; --- sys/dev/ic/gemreg.h.dist 2006-11-27 07:13:30.000000000 +0000 +++ sys/dev/ic/gemreg.h 2007-12-21 10:11:29.000000000 +0000 @@ -32,20 +32,29 @@ #ifndef _IF_GEMREG_H #define _IF_GEMREG_H -/* Register definitions for Sun GEM gigabit ethernet */ +/* + * Register definitions for Sun GEM Gigabit Ethernet + * See `GEM Gigabit Ethernet ASIC Specification' + * http://www.sun.com/processors/manuals/ge.pdf + * Section 3.1.3 GEM Register Space (from Rev 1.2) + */ /* + * Global Resources + * Section 3.1.4.1 + * * First bank: this registers live at the start of the PCI * mapping, and at the start of the second bank of the SBUS * version. */ -#define GEM_SEB_STATE 0x0000 /* SEB state reg, R/O */ -#define GEM_CONFIG 0x0004 /* config reg */ -#define GEM_STATUS 0x000c /* status reg */ -/* Note: Reading the status reg clears bits 0-6 */ -#define GEM_INTMASK 0x0010 -#define GEM_INTACK 0x0014 /* Interrupt acknowledge, W/O */ -#define GEM_STATUS_ALIAS 0x001c +#define GEM_SEB_STATE 0x0000 /* SEB State (R/O) */ +#define GEM_CONFIG 0x0004 /* Configuration */ +#define GEM_STATUS 0x000c /* Status */ +/* Note: Reading the status register auto-clears bits 0-6 */ +#define GEM_INTMASK 0x0010 /* Interrupt Mask */ +#define GEM_INTACK 0x0014 /* Interrupt Acknowledge (W/O) */ +#define GEM_STATUS_ALIAS 0x001c /* Status Alias */ +/* This is the same as GEM_STATUS but reading it does not auto-clear bits. */ /* * Second bank: this registers live at offset 0x1000 of the PCI @@ -54,37 +63,39 @@ */ #define GEM_PCI_BANK2_OFFSET 0x1000 #define GEM_PCI_BANK2_SIZE 0x14 -/* This is the same as the GEM_STATUS reg but reading it does not clear bits. */ -#define GEM_ERROR_STATUS 0x0000 /* PCI error status R/C */ -#define GEM_ERROR_MASK 0x0004 +#define GEM_ERROR_STATUS 0x0000 /* PCI error Status */ +#define GEM_ERROR_MASK 0x0004 /* PCI Error Mask */ #define GEM_SBUS_CONFIG 0x0004 -#define GEM_BIF_CONFIG 0x0008 /* BIF config reg */ -#define GEM_BIF_DIAG 0x000c -#define GEM_RESET 0x0010 /* Software reset register */ +#define GEM_BIF_CONFIG 0x0008 /* BIF Configuration */ +#define GEM_BIF_DIAG 0x000c /* BIF Diagnostic */ +#define GEM_RESET 0x0010 /* Software Reset */ -/* Bits in GEM_SEB register */ +/* + * Bits in GEM_SEB_STATE register + * For diagnostic use + */ #define GEM_SEB_ARB 0x000000002 /* Arbitration status */ #define GEM_SEB_RXWON 0x000000004 -/* Bits in GEM_SBUS_CONFIG register */ -#define GEM_SBUS_CFG_BMODE64 0x00000008 -#define GEM_SBUS_CFG_PARITY 0x00000200 - -/* Bits in GEM_CONFIG register */ +/* + * Bits in GEM_CONFIG register + * Default: 0x00042 + */ #define GEM_CONFIG_BURST_64 0x000000000 /* 0->infinity, 1->64KB */ #define GEM_CONFIG_BURST_INF 0x000000001 /* 0->infinity, 1->64KB */ #define GEM_CONFIG_TXDMA_LIMIT 0x00000003e #define GEM_CONFIG_RXDMA_LIMIT 0x0000007c0 +/* GEM_CONFIG_RONPAULBIT and GEM_CONFIG_BUG2FIX are Apple only. */ +#define GEM_CONFIG_RONPAULBIT 0x000000800 /* after infinite burst use + * memory read multiple for + * PCI commands */ +#define GEM_CONFIG_BUG2FIX 0x000001000 /* fix RX hang after overflow */ #define GEM_CONFIG_TXDMA_LIMIT_SHIFT 1 #define GEM_CONFIG_RXDMA_LIMIT_SHIFT 6 -/* Top part of GEM_STATUS has TX completion information */ -#define GEM_STATUS_TX_COMPL 0xfff800000 /* TX completion reg. */ - - /* * Interrupt bits, for both the GEM_STATUS and GEM_INTMASK regs. * Bits 0-6 auto-clear when read. @@ -93,13 +104,14 @@ #define GEM_INTR_TX_EMPTY 0x000000002 /* TX ring empty */ #define GEM_INTR_TX_DONE 0x000000004 /* TX complete */ #define GEM_INTR_RX_DONE 0x000000010 /* Got a packet */ -#define GEM_INTR_RX_NOBUF 0x000000020 -#define GEM_INTR_RX_TAG_ERR 0x000000040 -#define GEM_INTR_PCS 0x000002000 /* Physical Code Sub-layer */ -#define GEM_INTR_TX_MAC 0x000004000 -#define GEM_INTR_RX_MAC 0x000008000 +#define GEM_INTR_RX_NOBUF 0x000000020 /* No free receive buffers */ +#define GEM_INTR_RX_TAG_ERR 0x000000040 /* RX Tag framing error */ +#define GEM_INTR_PERR 0x000000080 /* Parity error */ +#define GEM_INTR_PCS 0x000002000 /* PCS interrupt */ +#define GEM_INTR_TX_MAC 0x000004000 /* TX MAC interrupt */ +#define GEM_INTR_RX_MAC 0x000008000 /* RX MAC interrupt */ #define GEM_INTR_MAC_CONTROL 0x000010000 /* MAC control interrupt */ -#define GEM_INTR_MIF 0x000020000 +#define GEM_INTR_MIF 0x000020000 /* MIF interrupt */ #define GEM_INTR_BERR 0x000040000 /* Bus error interrupt */ #define GEM_INTR_BITS "\177\020" \ "b\0INTME\0b\1TXEMPTY\0b\2TXDONE\0" \ @@ -107,16 +119,32 @@ "b\xdPCS\0b\xeTXMAC\0b\xfRXMAC\0" \ "b\x10MAC_CONTROL\0b\x11MIF\0b\x12IBERR\0\0" +/* Top part (bits 19-31) of GEM_STATUS has TX completion information */ +#define GEM_STATUS_TX_COMPL 0xfff800000 /* TX completion reg. */ -/* GEM_ERROR_STATUS and GEM_ERROR_MASK PCI error bits */ +/* + * Bits in GEM_ERROR_STATUS and GEM_ERROR_MASK PCI registers + */ #define GEM_ERROR_STAT_BADACK 0x000000001 /* No ACK64# */ #define GEM_ERROR_STAT_DTRTO 0x000000002 /* Delayed xaction timeout */ -#define GEM_ERROR_STAT_OTHERS 0x000000004 +#define GEM_ERROR_STAT_OTHERS 0x000000004 /* Other PCI errors. Read PCI + Status Register in PCI + Configuration space */ #define GEM_ERROR_BITS "\177\020b\0ACKBAD\0b\1DTRTO\0b\2OTHER\0\0" -/* GEM_BIF_CONFIG register bits */ +/* + * Bits in GEM_SBUS_CONFIG register + */ +#define GEM_SBUS_CFG_BMODE64 0x00000008 +#define GEM_SBUS_CFG_PARITY 0x00000200 + + +/* + * Bits in GEM_BIF_CONFIG register + * Default: 0x0 + */ #define GEM_BIF_CONFIG_SLOWCLK 0x000000001 /* Parity error timing */ #define GEM_BIF_CONFIG_HOST_64 0x000000002 /* 64-bit host */ #define GEM_BIF_CONFIG_B64D_DIS 0x000000004 /* no 64-bit data cycle */ @@ -125,40 +153,65 @@ "b\2B64DIS\0b\3M66EN\0\0" -/* GEM_RESET register bits -- TX and RX self clear when complete. */ +/* + * Bits in GEM_BIF_DIAG register + * Default: 0x00000000 + */ +#define GEN_BIF_DIAG_PCIBURST 0x007f0000 /* PCI Burst Controller state + * machine */ +#define GEN_BIF_DIAG_STATE 0xff000000 /* BIF state machine */ + +/* + * Bits in GEM_RESET register + * RESET_TX and RESET_RX self clear when complete. + */ #define GEM_RESET_TX 0x000000001 /* Reset TX half */ #define GEM_RESET_RX 0x000000002 /* Reset RX half */ +#define GEM_RESET_GLOBAL 0x000000003 /* Global Reset */ #define GEM_RESET_RSTOUT 0x000000004 /* Force PCI RSTOUT# */ -/* GEM TX DMA registers */ -#define GEM_TX_KICK 0x2000 /* Write last valid desc + 1 */ -#define GEM_TX_CONFIG 0x2004 -#define GEM_TX_RING_PTR_LO 0x2008 -#define GEM_TX_RING_PTR_HI 0x200c - -#define GEM_TX_FIFO_WR_PTR 0x2014 /* FIFO write pointer */ -#define GEM_TX_FIFO_SDWR_PTR 0x2018 /* FIFO shadow write pointer */ -#define GEM_TX_FIFO_RD_PTR 0x201c /* FIFO read pointer */ -#define GEM_TX_FIFO_SDRD_PTR 0x2020 /* FIFO shadow read pointer */ -#define GEM_TX_FIFO_PKT_CNT 0x2024 /* FIFO packet counter */ - -#define GEM_TX_STATE_MACHINE 0x2028 /* ETX state machine reg */ -#define GEM_TX_DATA_PTR 0x2030 /* ETX state machine reg (64-bit)*/ - -#define GEM_TX_COMPLETION 0x2100 -#define GEM_TX_FIFO_ADDRESS 0x2104 -#define GEM_TX_FIFO_TAG 0x2108 -#define GEM_TX_FIFO_DATA_LO 0x210c -#define GEM_TX_FIFO_DATA_HI_T1 0x2110 -#define GEM_TX_FIFO_DATA_HI_T0 0x2114 -#define GEM_TX_FIFO_SIZE 0x2118 +/* + * TX DMA Programmable Resources + * Section 3.1.4.2 + * The 53 most significant bits of the Descriptor Base Low/High registers + * are used as the TX descriptor ring base address. The ring base must be + * initialized to a 2KByte-aligned address after power-on or software reset. + */ +#define GEM_TX_KICK 0x2000 /* TX Kick */ +/* Note: Write last valid desc + 1 */ +#define GEM_TX_CONFIG 0x2004 /* TX Configuration */ +#define GEM_TX_RING_PTR_LO 0x2008 /* TX Descriptor Base Low */ +#define GEM_TX_RING_PTR_HI 0x200c /* TX Descriptor Base High */ +/* 0x2010 Reserved */ +#define GEM_TX_FIFO_WR_PTR 0x2014 /* TX FIFO Write Pointer */ +#define GEM_TX_FIFO_SDWR_PTR 0x2018 /* TX FIFO Shadow Write Ptr */ +#define GEM_TX_FIFO_RD_PTR 0x201c /* TX FIFO Read Pointer */ +#define GEM_TX_FIFO_SDRD_PTR 0x2020 /* TX FIFO Shadow Read Ptr */ +#define GEM_TX_FIFO_PKT_CNT 0x2024 /* TX FIFO Packet Counter */ +#define GEM_TX_STATE_MACHINE 0x2028 /* TX State Machine */ +/* 0x202c Unknown */ +#define GEM_TX_DATA_PTR_LO 0x2030 /* TX Data Pointer Low */ +#define GEM_TX_DATA_PTR_HI 0x2034 /* TX Data Pointer High */ + +#define GEM_TX_COMPLETION 0x2100 /* TX Completion */ +#define GEM_TX_FIFO_ADDRESS 0x2104 /* TX FIFO Address */ +#define GEM_TX_FIFO_TAG 0x2108 /* TX FIFO Tag */ +#define GEM_TX_FIFO_DATA_LO 0x210c /* TX FIFO Data Low */ +#define GEM_TX_FIFO_DATA_HI_T1 0x2110 /* TX FIFO Data HighT1 */ +#define GEM_TX_FIFO_DATA_HI_T0 0x2114 /* TX FIFO Data HighT0 */ +#define GEM_TX_FIFO_SIZE 0x2118 /* TX FIFO Size */ #define GEM_TX_DEBUG 0x3028 -/* GEM_TX_CONFIG register bits. */ +/* + * Bits in GEM_TX_CONFIG register + * Default: 0x118c10 + * TX FIFO Threshold should be set to 0x4ff + */ #define GEM_TX_CONFIG_TXDMA_EN 0x00000001 /* TX DMA enable */ #define GEM_TX_CONFIG_TXRING_SZ 0x0000001e /* TX ring size */ +#define GEM_TX_CONFIG_TXFIFO_SL 0x00000020 /* TX DMA FIFO PIO select */ #define GEM_TX_CONFIG_TXFIFO_TH 0x001ffc00 /* TX fifo threshold */ #define GEM_TX_CONFIG_PACED 0x00200000 /* TX_all_int modifier */ @@ -170,42 +223,50 @@ #define GEM_RING_SZ_1024 (5<<1) #define GEM_RING_SZ_2048 (6<<1) #define GEM_RING_SZ_4096 (7<<1) -#define GEM_RING_SZ_8192 (8<<1) +#define GEM_RING_SZ_8192 (8<<1) /* Default */ -/* GEM_TX_COMPLETION register bits */ +/* + * Bits in GEM_TX_COMPLETION register + */ #define GEM_TX_COMPLETION_MASK 0x00001fff /* # of last descriptor */ -/* GEM RX DMA registers */ -#define GEM_RX_CONFIG 0x4000 -#define GEM_RX_RING_PTR_LO 0x4004 /* 64-bits unaligned GAK! */ -#define GEM_RX_RING_PTR_HI 0x4008 /* 64-bits unaligned GAK! */ - -#define GEM_RX_FIFO_WR_PTR 0x400c /* FIFO write pointer */ -#define GEM_RX_FIFO_SDWR_PTR 0x4010 /* FIFO shadow write pointer */ -#define GEM_RX_FIFO_RD_PTR 0x4014 /* FIFO read pointer */ -#define GEM_RX_FIFO_PKT_CNT 0x4018 /* FIFO packet counter */ - -#define GEM_RX_STATE_MACHINE 0x401c /* ERX state machine reg */ -#define GEM_RX_PAUSE_THRESH 0x4020 - -#define GEM_RX_DATA_PTR_LO 0x4024 /* ERX state machine reg */ -#define GEM_RX_DATA_PTR_HI 0x4028 /* Damn thing is unaligned */ - -#define GEM_RX_KICK 0x4100 /* Write last valid desc + 1 */ -#define GEM_RX_COMPLETION 0x4104 /* First pending desc */ -#define GEM_RX_BLANKING 0x4108 /* Interrupt blanking reg */ - -#define GEM_RX_FIFO_ADDRESS 0x410c -#define GEM_RX_FIFO_TAG 0x4110 -#define GEM_RX_FIFO_DATA_LO 0x4114 -#define GEM_RX_FIFO_DATA_HI_T1 0x4118 -#define GEM_RX_FIFO_DATA_HI_T0 0x411c -#define GEM_RX_FIFO_SIZE 0x4120 +/* + * RX DMA Programmable Resources + * Section 3.1.4.3 + * The 53 most significant bits of the Descriptor Base Low/High registers + * are used as the RX descriptor ring base address. The ring base must be + * initialized to a 2KByte-aligned address after power-on or software reset. + */ +#define GEM_RX_CONFIG 0x4000 /* RX Configuration */ +#define GEM_RX_RING_PTR_LO 0x4004 /* RX Descriptor Base Low */ +#define GEM_RX_RING_PTR_HI 0x4008 /* RX Descriptor Base High */ +#define GEM_RX_FIFO_WR_PTR 0x400c /* RX FIFO Write Pointer */ +#define GEM_RX_FIFO_SDWR_PTR 0x4010 /* RX FIFO Shadow Write Ptr */ +#define GEM_RX_FIFO_RD_PTR 0x4014 /* RX FIFO Read Pointer */ +#define GEM_RX_FIFO_PKT_CNT 0x4018 /* RX FIFO Packet Counter */ +#define GEM_RX_STATE_MACHINE 0x401c /* RX State Machine */ +#define GEM_RX_PAUSE_THRESH 0x4020 /* Pause Thresholds */ +#define GEM_RX_DATA_PTR_LO 0x4024 /* RX Data Pointer Low */ +#define GEM_RX_DATA_PTR_HI 0x4028 /* RX Data Pointer High */ + +#define GEM_RX_KICK 0x4100 /* RX Kick */ +/* Note: Write last valid desc + 1. Must be a multiple of 4 */ +#define GEM_RX_COMPLETION 0x4104 /* RX Completion */ +#define GEM_RX_BLANKING 0x4108 /* RX Blanking */ +#define GEM_RX_FIFO_ADDRESS 0x410c /* RX FIFO Address */ +#define GEM_RX_FIFO_TAG 0x4110 /* RX FIFO Tag */ +#define GEM_RX_FIFO_DATA_LO 0x4114 /* RX FIFO Data Low */ +#define GEM_RX_FIFO_DATA_HI_T1 0x4118 /* RX FIFO Data HighT0 */ +#define GEM_RX_FIFO_DATA_HI_T0 0x411c /* RX FIFO Data HighT1 */ +#define GEM_RX_FIFO_SIZE 0x4120 /* RX FIFO Size */ -/* GEM_RX_CONFIG register bits. */ +/* + * Bits in GEM_RX_CONFIG register + * Default: 0x1000010 + */ #define GEM_RX_CONFIG_RXDMA_EN 0x00000001 /* RX DMA enable */ #define GEM_RX_CONFIG_RXRING_SZ 0x0000001e /* RX ring size */ #define GEM_RX_CONFIG_BATCH_DIS 0x00000020 /* desc batching disable */ @@ -237,30 +298,34 @@ /* One tick is 2048 PCI clocks, or 16us at 66MHz */ -/* GEM_MAC registers */ -#define GEM_MAC_TXRESET 0x6000 /* Store 1, cleared when done */ -#define GEM_MAC_RXRESET 0x6004 /* ditto */ -#define GEM_MAC_SEND_PAUSE_CMD 0x6008 -#define GEM_MAC_TX_STATUS 0x6010 -#define GEM_MAC_RX_STATUS 0x6014 -#define GEM_MAC_CONTROL_STATUS 0x6018 /* MAC control status reg */ -#define GEM_MAC_TX_MASK 0x6020 /* TX MAC mask register */ -#define GEM_MAC_RX_MASK 0x6024 -#define GEM_MAC_CONTROL_MASK 0x6028 -#define GEM_MAC_TX_CONFIG 0x6030 -#define GEM_MAC_RX_CONFIG 0x6034 -#define GEM_MAC_CONTROL_CONFIG 0x6038 -#define GEM_MAC_XIF_CONFIG 0x603c -#define GEM_MAC_IPG0 0x6040 /* inter packet gap 0 */ -#define GEM_MAC_IPG1 0x6044 /* inter packet gap 1 */ -#define GEM_MAC_IPG2 0x6048 /* inter packet gap 2 */ -#define GEM_MAC_SLOT_TIME 0x604c /* slot time, bits 0-7 */ -#define GEM_MAC_MAC_MIN_FRAME 0x6050 -#define GEM_MAC_MAC_MAX_FRAME 0x6054 -#define GEM_MAC_PREAMBLE_LEN 0x6058 -#define GEM_MAC_JAM_SIZE 0x605c -#define GEM_MAC_ATTEMPT_LIMIT 0x6060 -#define GEM_MAC_CONTROL_TYPE 0x6064 +/* + * MAC Programmable Resources + * Section 3.1.5 + */ +#define GEM_MAC_TXRESET 0x6000 /* TX MAC Software Reset Cmd */ +#define GEM_MAC_RXRESET 0x6004 /* RX MAC Software Reset Cmd */ +/* Note: Store 1, cleared when done for TXRESET and RXRESET */ +#define GEM_MAC_SEND_PAUSE_CMD 0x6008 /* Send Pause Command */ +#define GEM_MAC_TX_STATUS 0x6010 /* TX MAC Status */ +#define GEM_MAC_RX_STATUS 0x6014 /* RX MAC Status */ +#define GEM_MAC_CONTROL_STATUS 0x6018 /* MAC Control Status */ +#define GEM_MAC_TX_MASK 0x6020 /* TX MAC Mask */ +#define GEM_MAC_RX_MASK 0x6024 /* RX MAC Mask */ +#define GEM_MAC_CONTROL_MASK 0x6028 /* MAC Control Mask */ +#define GEM_MAC_TX_CONFIG 0x6030 /* TX MAC Configuration */ +#define GEM_MAC_RX_CONFIG 0x6034 /* XX MAC Configuration */ +#define GEM_MAC_CONTROL_CONFIG 0x6038 /* MAC Control Configuration */ +#define GEM_MAC_XIF_CONFIG 0x603c /* XIF Configuration */ +#define GEM_MAC_IPG0 0x6040 /* InterPacketGap0 */ +#define GEM_MAC_IPG1 0x6044 /* InterPacketGap1 */ +#define GEM_MAC_IPG2 0x6048 /* InterPacketGap2 */ +#define GEM_MAC_SLOT_TIME 0x604c /* SlotTime, bits 0-7 */ +#define GEM_MAC_MAC_MIN_FRAME 0x6050 /* MinFrameSize */ +#define GEM_MAC_MAC_MAX_FRAME 0x6054 /* MaxFrameSize */ +#define GEM_MAC_PREAMBLE_LEN 0x6058 /* PA Size */ +#define GEM_MAC_JAM_SIZE 0x605c /* JamSize */ +#define GEM_MAC_ATTEMPT_LIMIT 0x6060 /* Attempt Limit */ +#define GEM_MAC_CONTROL_TYPE 0x6064 /* MAC Control Type */ #define GEM_MAC_ADDR0 0x6080 /* Normal MAC address 0 */ #define GEM_MAC_ADDR1 0x6084 @@ -272,11 +337,11 @@ #define GEM_MAC_ADDR7 0x609c #define GEM_MAC_ADDR8 0x60a0 -#define GEM_MAC_ADDR_FILTER0 0x60a4 +#define GEM_MAC_ADDR_FILTER0 0x60a4 /* Address Filter */ #define GEM_MAC_ADDR_FILTER1 0x60a8 #define GEM_MAC_ADDR_FILTER2 0x60ac -#define GEM_MAC_ADR_FLT_MASK1_2 0x60b0 /* Address filter mask 1,2 */ -#define GEM_MAC_ADR_FLT_MASK0 0x60b4 /* Address filter mask 0 reg */ +#define GEM_MAC_ADR_FLT_MASK1_2 0x60b0 /* Address Filter Mask 2&1 */ +#define GEM_MAC_ADR_FLT_MASK0 0x60b4 /* Address Filter Mask 0 */ #define GEM_MAC_HASH0 0x60c0 /* Hash table 0 */ #define GEM_MAC_HASH1 0x60c4 @@ -295,58 +360,78 @@ #define GEM_MAC_HASH14 0x60f8 #define GEM_MAC_HASH15 0x60fc -#define GEM_MAC_NORM_COLL_CNT 0x6100 /* Normal collision counter */ -#define GEM_MAC_FIRST_COLL_CNT 0x6104 /* 1st successful collision cntr */ -#define GEM_MAC_EXCESS_COLL_CNT 0x6108 /* Excess collision counter */ -#define GEM_MAC_LATE_COLL_CNT 0x610c /* Late collision counter */ -#define GEM_MAC_DEFER_TMR_CNT 0x6110 /* defer timer counter */ -#define GEM_MAC_PEAK_ATTEMPTS 0x6114 -#define GEM_MAC_RX_FRAME_COUNT 0x6118 -#define GEM_MAC_RX_LEN_ERR_CNT 0x611c -#define GEM_MAC_RX_ALIGN_ERR 0x6120 -#define GEM_MAC_RX_CRC_ERR_CNT 0x6124 -#define GEM_MAC_RX_CODE_VIOL 0x6128 -#define GEM_MAC_RANDOM_SEED 0x6130 -#define GEM_MAC_MAC_STATE 0x6134 /* MAC sstate machine reg */ +#define GEM_MAC_NORM_COLL_CNT 0x6100 /* Normal Collision Counter */ +#define GEM_MAC_FIRST_COLL_CNT 0x6104 /* First Attempt Successful + Collision Counter */ +#define GEM_MAC_EXCESS_COLL_CNT 0x6108 /* Excess Collision Counter */ +#define GEM_MAC_LATE_COLL_CNT 0x610c /* Late Collision Counter */ +#define GEM_MAC_DEFER_TMR_CNT 0x6110 /* Defer Timer */ +#define GEM_MAC_PEAK_ATTEMPTS 0x6114 /* Peak Attempts */ +#define GEM_MAC_RX_FRAME_COUNT 0x6118 /* Receive Frame Counter */ +#define GEM_MAC_RX_LEN_ERR_CNT 0x611c /* Length Error Counter */ +#define GEM_MAC_RX_ALIGN_ERR 0x6120 /* Alignment Error Counter */ +#define GEM_MAC_RX_CRC_ERR_CNT 0x6124 /* FCS Error Counter */ +#define GEM_MAC_RX_CODE_VIOL 0x6128 /* RX Code Violation Error + Counter */ +#define GEM_MAC_RANDOM_SEED 0x6130 /* Random Number Seed */ +#define GEM_MAC_MAC_STATE 0x6134 /* State Machine */ -/* GEM_MAC_SEND_PAUSE_CMD register bits */ + +/* + * Bits in GEM_MAC_SEND_PAUSE_CMD register + * Pause time is in units of Slot Times. + */ #define GEM_MAC_PAUSE_CMD_TIME 0x0000ffff #define GEM_MAC_PAUSE_CMD_SEND 0x00010000 -/* GEM_MAC_TX_STATUS and _MASK register bits */ -#define GEM_MAC_TX_XMIT_DONE 0x00000001 -#define GEM_MAC_TX_UNDERRUN 0x00000002 -#define GEM_MAC_TX_PKT_TOO_LONG 0x00000004 -#define GEM_MAC_TX_NCC_EXP 0x00000008 /* Normal collision cnt exp */ -#define GEM_MAC_TX_ECC_EXP 0x00000010 -#define GEM_MAC_TX_LCC_EXP 0x00000020 -#define GEM_MAC_TX_FCC_EXP 0x00000040 -#define GEM_MAC_TX_DEFER_EXP 0x00000080 -#define GEM_MAC_TX_PEAK_EXP 0x00000100 - - -/* GEM_MAC_RX_STATUS and _MASK register bits */ -#define GEM_MAC_RX_DONE 0x00000001 -#define GEM_MAC_RX_OVERFLOW 0x00000002 -#define GEM_MAC_RX_FRAME_CNT 0x00000004 -#define GEM_MAC_RX_ALIGN_EXP 0x00000008 -#define GEM_MAC_RX_CRC_EXP 0x00000010 -#define GEM_MAC_RX_LEN_EXP 0x00000020 -#define GEM_MAC_RX_CVI_EXP 0x00000040 /* Code violation */ +/* + * Bits in GEM_MAC_TX_STATUS and _MASK register + * Interrupt bits are auto-cleared when the status register is read and + * the corresponding bit is set in the mask register. + */ +#define GEM_MAC_TX_XMIT_DONE 0x00000001 /* Successful transmission */ +#define GEM_MAC_TX_UNDERRUN 0x00000002 /* TX "data starvation" */ +#define GEM_MAC_TX_PKT_TOO_LONG 0x00000004 /* Frame exceeds max. length */ +#define GEM_MAC_TX_NCC_EXP 0x00000008 /* Normal collision counter has + rolled over */ +#define GEM_MAC_TX_ECC_EXP 0x00000010 /* Excessive coll cnt rolled */ +#define GEM_MAC_TX_LCC_EXP 0x00000020 /* Late coll cnt rolled */ +#define GEM_MAC_TX_FCC_EXP 0x00000040 /* First coll cnt rolled */ +#define GEM_MAC_TX_DEFER_EXP 0x00000080 /* Defer timer cnt rolled */ +#define GEM_MAC_TX_PEAK_EXP 0x00000100 /* Peak attempts cnt rolled */ + + +/* + * Bits in GEM_MAC_RX_STATUS and _MASK register + */ +#define GEM_MAC_RX_DONE 0x00000001 /* Successful reception */ +#define GEM_MAC_RX_OVERFLOW 0x00000002 /* RX resource lack */ +#define GEM_MAC_RX_FRAME_CNT 0x00000004 /* Receive frame counter has + rolled over */ +#define GEM_MAC_RX_ALIGN_EXP 0x00000008 /* Alignment error cnt rolled */ +#define GEM_MAC_RX_CRC_EXP 0x00000010 /* CRC error cnt rolled */ +#define GEM_MAC_RX_LEN_EXP 0x00000020 /* Length error cnt rolled */ +#define GEM_MAC_RX_CVI_EXP 0x00000040 /* Code violation err rolled */ -/* GEM_MAC_CONTROL_STATUS and GEM_MAC_CONTROL_MASK register bits */ +/* + * Bits in GEM_MAC_CONTROL_STATUS and GEM_MAC_CONTROL_MASK register + */ #define GEM_MAC_PAUSED 0x00000001 /* Pause received */ #define GEM_MAC_PAUSE 0x00000002 /* enter pause state */ #define GEM_MAC_RESUME 0x00000004 /* exit pause state */ -#define GEM_MAC_PAUSE_TIME 0xffff0000 +#define GEM_MAC_PAUSE_TIME 0xffff0000 /* Pause time received */ #define GEM_MAC_STATUS_BITS "\177\020b\0PAUSED\0b\1PAUSE\0b\2RESUME\0\0" -/* GEM_MAC_XIF_CONFIG register bits */ -#define GEM_MAC_XIF_TX_MII_ENA 0x00000001 /* Enable XIF output drivers */ -#define GEM_MAC_XIF_MII_LOOPBK 0x00000002 /* Enable MII loopback mode */ + +/* + * Bits in GEM_MAC_XIF_CONFIG register + * Default: 0x00 + */ +#define GEM_MAC_XIF_TX_MII_ENA 0x00000001 /* Enable MII output */ +#define GEM_MAC_XIF_MII_LOOPBK 0x00000002 /* Enable (G)MII loopback */ #define GEM_MAC_XIF_ECHO_DISABL 0x00000004 /* Disable echo */ #define GEM_MAC_XIF_GMII_MODE 0x00000008 /* Select GMII/MII mode */ #define GEM_MAC_XIF_MII_BUF_ENA 0x00000010 /* Enable MII recv buffers */ @@ -356,23 +441,27 @@ "\0b\3GMII\0b\4MIIBUFENA\0b\5LINKLED\0" \ "b\6FDLED\0\0" -/* GEM_MAC_SLOT_TIME register bits */ -#define GEM_MAC_SLOT_INT 0x40 -#define GEM_MAC_SLOT_EXT 0x200 /* external phy */ -#define GEM_MAC_SLOT_BITS "\177\020b\6INTSLOT\0b\x9SLOTEXT\0\0" -/* GEM_MAC_TX_CONFIG register bits */ +/* + * Bits in GEM_MAC_TX_CONFIG register + * GEM_MAC_TX_ENABLE must be cleared and a delay imposed before writing to + * other bits in this register or any of the MAC parameters registers. + * The GEM_MAC_TX_ENABLE bit will read 0 when the transmitter has stopped. + * Carrier Extension must be set when operating in Half-Duplex at 1Gbps, + * and disabled otherwise. To enable this GEM_MAC_TX_CARR_EXTEND and + * GEM_MAC_RX_CARR_EXTEND must be set to 1 and the Slot Time register must + * be set to 0x200. + */ #define GEM_MAC_TX_ENABLE 0x00000001 /* TX enable */ #define GEM_MAC_TX_IGN_CARRIER 0x00000002 /* Ignore carrier sense */ #define GEM_MAC_TX_IGN_COLLIS 0x00000004 /* ignore collisions */ #define GEM_MAC_TX_ENA_IPG0 0x00000008 /* extend Rx-to-TX IPG */ #define GEM_MAC_TX_NGU 0x00000010 /* Never give up */ #define GEM_MAC_TX_NGU_LIMIT 0x00000020 /* Never give up limit */ -#define GEM_MAC_TX_NO_BACKOFF 0x00000040 -#define GEM_MAC_TX_SLOWDOWN 0x00000080 +#define GEM_MAC_TX_NO_BACKOFF 0x00000040 /* Never backoff on coll */ +#define GEM_MAC_TX_SLOWDOWN 0x00000080 /* Watch carrier sense */ #define GEM_MAC_TX_NO_FCS 0x00000100 /* no FCS will be generated */ #define GEM_MAC_TX_CARR_EXTEND 0x00000200 /* Ena TX Carrier Extension */ -/* Carrier Extension is required for half duplex Gbps operation */ #define GEM_MAC_TX_CONFIG_BITS "\177\020" \ "b\0TXENA\0b\1IGNCAR\0b\2IGNCOLLIS\0" \ "b\3IPG0ENA\0b\4TXNGU\0b\5TXNGULIM\0" \ @@ -380,7 +469,20 @@ "b\x9TXCARREXT\0\0" -/* GEM_MAC_RX_CONFIG register bits */ +/* + * Bits in GEM_MAC_RX_CONFIG register + * The GEM_MAC_RX_ENABLE bit must be cleared and a delay of 3.2ms imposed + * before writing to other bits in this register or any of the MAC + * parameters registers. The GEM_MAC_RX_ENABLE bit will read 0 when the + * receiver has stopped. + * The GEM_MAC_RX_HASH_FILTER bit must be cleared and a delay of 3.2ms + * imposed before writing to any of the Hash Table registers. The + * GEM_MAC_RX_HASH_FILTER bit will read 0 when the registers may be written. + * The GEM_MAC_RX_ADDR_FILTER bit must be cleared and a delay of 3.2ms + * imposed before writing to any of the Address Filter registers. The + * GEM_MAC_RX_ADDR_FILTER bit will read 0 when the registers may be written. + * See "Carrier Extension" above. + */ #define GEM_MAC_RX_ENABLE 0x00000001 /* RX enable */ #define GEM_MAC_RX_STRIP_PAD 0x00000002 /* strip pad bytes */ #define GEM_MAC_RX_STRIP_CRC 0x00000004 @@ -388,43 +490,124 @@ #define GEM_MAC_RX_PROMISC_GRP 0x00000010 /* promiscuous group mode */ #define GEM_MAC_RX_HASH_FILTER 0x00000020 /* enable hash filter */ #define GEM_MAC_RX_ADDR_FILTER 0x00000040 /* enable address filter */ -#define GEM_MAC_RX_ERRCHK_DIS 0x00000080 /* disable error checking */ +#define GEM_MAC_RX_ERRCHK_DIS 0x00000080 /* disable error discard */ #define GEM_MAC_RX_CARR_EXTEND 0x00000100 /* Ena RX Carrier Extension */ -/* - * Carrier Extension enables reception of packet bursts generated by - * senders with carrier extension enabled. - */ #define GEM_MAC_RX_CONFIG_BITS "\177\020" \ "b\0RXENA\0b\1STRPAD\0b\2STRCRC\0" \ "b\3PROMIS\0b\4PROMISCGRP\0b\5HASHFLTR\0" \ "b\6ADDRFLTR\0b\7ERRCHKDIS\0b\x9TXCARREXT\0\0" -/* GEM_MAC_CONTROL_CONFIG bits */ +/* + * Bits in GEM_MAC_CONTROL_CONFIG + * Default; 0x0 + */ #define GEM_MAC_CC_TX_PAUSE 0x00000001 /* send pause enabled */ #define GEM_MAC_CC_RX_PAUSE 0x00000002 /* receive pause enabled */ #define GEM_MAC_CC_PASS_PAUSE 0x00000004 /* pass pause up */ #define GEM_MAC_CC_BITS "\177\020b\0TXPAUSE\0b\1RXPAUSE\0b\2NOPAUSE\0\0" -/* GEM MIF registers */ -/* Bit bang registers use low bit only */ -#define GEM_MIF_BB_CLOCK 0x6200 /* bit bang clock */ -#define GEM_MIF_BB_DATA 0x6204 /* bit bang data */ -#define GEM_MIF_BB_OUTPUT_ENAB 0x6208 -#define GEM_MIF_FRAME 0x620c /* MIF frame - ctl and data */ -#define GEM_MIF_CONFIG 0x6210 -#define GEM_MIF_INTERRUPT_MASK 0x6214 -#define GEM_MIF_BASIC_STATUS 0x6218 -#define GEM_MIF_STATE_MACHINE 0x621c +/* + * Bits in GEM_MAC_SLOT_TIME register + * The slot time is used as PAUSE time unit, value depends on whether carrier + * extension is enabled. + */ +#define GEM_MAC_SLOT_TIME_CARR_EXTEND 0x200 +#define GEM_MAC_SLOT_TIME_NORMAL 0x40 + + +/* + * Recommended values for MAC registers: + * GEM_MAC_IPG0 0x00 + * GEM_MAC_IPG1 0x08 + * GEM_MAC_IPG2 0x04 + * GEM_MAC_SLOT_TIME 0x40 (see "Carrier Extension" above) + * Bits in GEM_MAC_MAC_MAX_FRAME register + * max burst size 0x7fff0000 + * max frame size 0x00007fff + * GEM_MAC_MAC_MIN_FRAME 0x40 + * GEM_MAC_MAC_MAX_FRAME 0x200005ee + * GEM_MAC_PREAMBLE_LEN 0x07 (minimum of 0x02) + * GEM_MAC_JAM_SIZE 0x04 + * GEM_MAC_ATTEMPT_LIMIT 0x10 + * GEM_MAC_CONTROL_TYPE 0x8808 + */ -/* GEM_MIF_FRAME bits */ -#define GEM_MIF_FRAME_DATA 0x0000ffff +/* + * Address detection and filtering registers (16-bit unless noted): + * GEM_MAC_ADDR0 normal priority MAC address bits 32-47 + * GEM_MAC_ADDR1 normal priority MAC address bits 16-31 + * GEM_MAC_ADDR2 normal priority MAC address bits 0-15 + * GEM_MAC_ADDR3 alternate MAC address bits 32-47 + * GEM_MAC_ADDR4 alternate MAC address bits 16-31 + * GEM_MAC_ADDR5 alternate MAC address bits 0-15 + * GEM_MAC_ADDR6 MAC control address bits 32-47 + * GEM_MAC_ADDR7 MAC control address bits 16-31 + * GEM_MAC_ADDR8 MAC control address bits 0-15 + * GEM_MAC_ADDR_FILTER0 address filter bits 32-47 + * GEM_MAC_ADDR_FILTER1 address filter bits 16-31 + * GEM_MAC_ADDR_FILTER2 address filter bits 0-15 + * GEM_MAC_ADR_FLT_MASK1_2 mask for GEM_MAC_ADDR_FILTER1 and 2 (8-bit) + * GEM_MAC_ADR_FLT_MASK0 mask for GEM_MAC_ADDR_FILTER0 + * GEM_MAC_HASH0 hash table bits 240-255 + * GEM_MAC_HASH1 hash table bits 224-239 + * GEM_MAC_HASH2 hash table bits 208-223 + * GEM_MAC_HASH3 hash table bits 192-207 + * GEM_MAC_HASH4 hash table bits 176-191 + * GEM_MAC_HASH5 hash table bits 160-175 + * GEM_MAC_HASH6 hash table bits 144-159 + * GEM_MAC_HASH7 hash table bits 128-143 + * GEM_MAC_HASH8 hash table bits 112-127 + * GEM_MAC_HASH9 hash table bits 96-111 + * GEM_MAC_HASH10 hash table bits 80-95 + * GEM_MAC_HASH11 hash table bits 64-79 + * GEM_MAC_HASH12 hash table bits 48-63 + * GEM_MAC_HASH13 hash table bits 32-47 + * GEM_MAC_HASH14 hash table bits 16-31 + * GEM_MAC_HASH15 hash table bits 0-15 + */ + +/* + * Recommended values for statistic registers: + * GEM_MAC_NORM_COLL_CNT 0x0000 + * GEM_MAC_FIRST_COLL_CNT 0x0000 + * GEM_MAC_EXCESS_COLL_CNT 0x0000 + * GEM_MAC_LATE_COLL_CNT 0x0000 + * GEM_MAC_DEFER_TMR_CNT 0x0000 + * GEM_MAC_PEAK_ATTEMPTS 0x0000 + * GEM_MAC_RX_FRAME_COUNT 0x0000 + * GEM_MAC_RX_LEN_ERR_CNT 0x0000 + * GEM_MAC_RX_ALIGN_ERR 0x0000 + * GEM_MAC_RX_CRC_ERR_CNT 0x0000 + * GEM_MAC_RX_CODE_VIOL 0x0000 + */ + + +/* + * MIF Programmable Resources + * Section 3.1.5.8 + * Bit-bang registers use low bit only + */ +#define GEM_MIF_BB_CLOCK 0x6200 /* MIF Bit-Bang Clock */ +#define GEM_MIF_BB_DATA 0x6204 /* MIF Bit-Bang Data */ +#define GEM_MIF_BB_OUTPUT_ENAB 0x6208 /* MIF Bit-Bang Output Enable */ +#define GEM_MIF_FRAME 0x620c /* MIF Frame/Output */ +#define GEM_MIF_CONFIG 0x6210 /* MIF Configuration */ +#define GEM_MIF_INTERRUPT_MASK 0x6214 /* MIF Mask */ +#define GEM_MIF_BASIC_STATUS 0x6218 /* MIF Status */ +#define GEM_MIF_STATE_MACHINE 0x621c /* MIF State Machine */ + + +/* + * Bits in GEM_MIF_FRAME register + */ +#define GEM_MIF_FRAME_DATA 0x0000ffff /* Instruction payload */ #define GEM_MIF_FRAME_TA0 0x00010000 /* TA bit, 1 for completion */ #define GEM_MIF_FRAME_TA1 0x00020000 /* TA bits */ -#define GEM_MIF_FRAME_REG_ADDR 0x007c0000 -#define GEM_MIF_FRAME_PHY_ADDR 0x0f800000 /* phy address, should be 0 */ +#define GEM_MIF_FRAME_REG_ADDR 0x007c0000 /* Register address */ +#define GEM_MIF_FRAME_PHY_ADDR 0x0f800000 /* PHY address, should be 0 */ #define GEM_MIF_FRAME_OP 0x30000000 /* operation - write/read */ #define GEM_MIF_FRAME_START 0xc0000000 /* START bits */ @@ -435,102 +618,128 @@ #define GEM_MIF_PHY_SHIFT 23 -/* GEM_MIF_CONFIG register bits */ -#define GEM_MIF_CONFIG_PHY_SEL 0x00000001 /* PHY select, 0=MDIO0 */ +/* + * Bits in GEM_MIF_CONFIG register + */ +#define GEM_MIF_CONFIG_PHY_SEL 0x00000001 /* PHY select, 0=MDIO_0 */ #define GEM_MIF_CONFIG_POLL_ENA 0x00000002 /* poll enable */ #define GEM_MIF_CONFIG_BB_ENA 0x00000004 /* bit bang enable */ #define GEM_MIF_CONFIG_REG_ADR 0x000000f8 /* poll register address */ -#define GEM_MIF_CONFIG_MDI0 0x00000100 /* MDIO_0 Data/MDIO_0 atached */ -#define GEM_MIF_CONFIG_MDI1 0x00000200 /* MDIO_1 Data/MDIO_1 atached */ +#define GEM_MIF_CONFIG_MDI0 0x00000100 /* MDIO_0 B-B data/attached */ +#define GEM_MIF_CONFIG_MDI1 0x00000200 /* MDIO_1 B-B data/attached */ #define GEM_MIF_CONFIG_PHY_ADR 0x00007c00 /* poll PHY address */ -/* MDI0 is onboard transceiver MID1 is external, PHYAD for both is 0 */ +/* MDIO_0 is onboard transceiver MDIO_1 is external, PHY addr for both is 0 */ #define GEM_MIF_CONFIG_BITS "\177\020b\0PHYSEL\0b\1POLL\0b\2BBENA\0" \ "b\x8MDIO0\0b\x9MDIO1\0\0" -/* GEM_MIF_BASIC_STATUS and GEM_MIF_INTERRUPT_MASK bits */ -#define GEM_MIF_STATUS 0x0000ffff -#define GEM_MIF_BASIC 0xffff0000 /* + * Bits in GEM_MIF_BASIC_STATUS and GEM_MIF_INTERRUPT_MASK * The Basic part is the last value read in the POLL field of the config * register. - * * The status part indicates the bits that have changed. */ +#define GEM_MIF_STATUS 0x0000ffff +#define GEM_MIF_BASIC 0xffff0000 -/* The GEM PCS/Serial link registers. */ -/* DO NOT TOUCH THESE REGISTERS ON ERI -- IT HARD HANGS. */ -#define GEM_MII_CONTROL 0x9000 -#define GEM_MII_STATUS 0x9004 -#define GEM_MII_ANAR 0x9008 /* MII advertisement reg */ -#define GEM_MII_ANLPAR 0x900c /* Link Partner Ability Reg */ -#define GEM_MII_CONFIG 0x9010 -#define GEM_MII_STATE_MACHINE 0x9014 -#define GEM_MII_INTERRUP_STATUS 0x9018 /* PCS interrupt state */ -#define GEM_MII_DATAPATH_MODE 0x9050 -#define GEM_MII_SLINK_CONTROL 0x9054 /* Serial link control */ -#define GEM_MII_OUTPUT_SELECT 0x9058 -#define GEM_MII_SLINK_STATUS 0x905c /* serial link status */ - - -/* GEM_MII_CONTROL bits - PCS "BMCR" (Basic Mode Control Reg) */ -#define GEM_MII_CONTROL_RESET 0x00008000 -#define GEM_MII_CONTROL_LOOPBK 0x00004000 /* 10-bit i/f loopback */ -#define GEM_MII_CONTROL_1000M 0x00002000 /* speed select, always 0 */ -#define GEM_MII_CONTROL_AUTONEG 0x00001000 /* auto negotiation enabled */ -#define GEM_MII_CONTROL_POWERDN 0x00000800 -#define GEM_MII_CONTROL_ISOLATE 0x00000400 /* isolate phy from mii */ -#define GEM_MII_CONTROL_RAN 0x00000200 /* restart auto negotiation */ -#define GEM_MII_CONTROL_FDUPLEX 0x00000100 /* full duplex, always 0 */ +/* + * PCS/Serialink Registers + * Section 3.1.6 + * DO NOT TOUCH THESE REGISTERS ON ERI -- IT HARD HANGS. + */ +#define GEM_MII_CONTROL 0x9000 /* PCS MII Control */ +#define GEM_MII_STATUS 0x9004 /* PCS MII Status */ +#define GEM_MII_ANAR 0x9008 /* PCS MII Advertisement */ +#define GEM_MII_ANLPAR 0x900c /* PCS MII Link Partner + Ability */ +#define GEM_MII_CONFIG 0x9010 /* PCS Configuration */ +#define GEM_MII_STATE_MACHINE 0x9014 /* PCS State Machine */ +#define GEM_MII_INTERRUP_STATUS 0x9018 /* PCS Interrupt Status */ +#define GEM_MII_DATAPATH_MODE 0x9050 /* Datapath Mode Register */ +#define GEM_MII_SLINK_CONTROL 0x9054 /* Serialink Control */ +#define GEM_MII_OUTPUT_SELECT 0x9058 /* Share Output Select */ +#define GEM_MII_SLINK_STATUS 0x905c /* Serialink Status */ + + +/* + * Bits in GEM_MII_CONTROL register + * PCS "BMCR" (Basic Mode Control Reg) + * Default: 0x1040 + * AUTONEG and RESET self clear when relevant process is completed. + */ +#define GEM_MII_1GB_SPEED_SEL 0x00000040 /* 1000Mb/s, always 1 */ #define GEM_MII_CONTROL_COL_TST 0x00000080 /* collision test */ +#define GEM_MII_CONTROL_FDUPLEX 0x00000100 /* full duplex, always 0 */ +#define GEM_MII_CONTROL_RAN 0x00000200 /* restart auto negotiation */ +#define GEM_MII_CONTROL_ISOLATE 0x00000400 /* isolate PHY, ignored */ +#define GEM_MII_CONTROL_POWERDN 0x00000800 /* power down, ignored */ +#define GEM_MII_CONTROL_AUTONEG 0x00001000 /* auto negotiation enabled */ +#define GEM_MII_CONTROL_SPEED 0x00002000 /* speed select, ignored */ +#define GEM_MII_CONTROL_LOOPBK 0x00004000 /* Serialink loopback */ +#define GEM_MII_CONTROL_RESET 0x00008000 /* Reset PCS */ #define GEM_MII_CONTROL_BITS "\177\020b\7COLTST\0b\x8_FD\0b\x9RAN\0" \ "b\xaISOLATE\0b\xbPWRDWN\0b\xc_ANEG\0" \ "b\xdGIGE\0b\xeLOOP\0b\xfRESET\0\0" -/* GEM_MII_STATUS reg - PCS "BMSR" (Basic Mode Status Reg) */ -#define GEM_MII_STATUS_GB_FDX 0x00000400 /* can perform GBit FDX */ -#define GEM_MII_STATUS_GB_HDX 0x00000200 /* can perform GBit HDX */ -#define GEM_MII_STATUS_UNK 0x00000100 -#define GEM_MII_STATUS_ANEG_CPT 0x00000020 /* auto negotiate compete */ +/* + * Bits in GEM_MII_STATUS register. + * PCS "BMSR" (Basic Mode Status Reg) + * Default: 0x0108 + */ +#define GEM_MII_STATUS_EXTCAP 0x00000001 /* extended capability, always 0 */ +#define GEM_MII_STATUS_JABBER 0x00000002 /* jabber detected, always 0 */ +#define GEM_MII_STATUS_LINK_STS 0x00000004 /* link status, 1=up */ +#define GEM_MII_STATUS_ACFG 0x00000008 /* can auto neg, always 1 */ #define GEM_MII_STATUS_REM_FLT 0x00000010 /* remote fault detected */ -#define GEM_MII_STATUS_ACFG 0x00000008 /* can auto negotiate */ -#define GEM_MII_STATUS_LINK_STS 0x00000004 /* link status */ -#define GEM_MII_STATUS_JABBER 0x00000002 /* jabber condition detected */ -#define GEM_MII_STATUS_EXTCAP 0x00000001 /* extended register capability */ +#define GEM_MII_STATUS_ANEG_CPT 0x00000020 /* auto negotiate complete */ +#define GEM_MII_STATUS_EXT_STS 0x00000100 /* Is 1000Base-X, always 1 */ +#define GEM_MII_STATUS_GB_HDX 0x00000200 /* can perform GBit HDX */ +#define GEM_MII_STATUS_GB_FDX 0x00000400 /* can perform GBit FDX */ #define GEM_MII_STATUS_BITS "\177\020b\0EXTCAP\0b\1JABBER\0b\2LINKSTS\0" \ "b\3ACFG\0b\4REMFLT\0b\5ANEGCPT\0b\x9GBHDX\0" \ "b\xaGBFDX\0\0" -/* GEM_MII_ANAR and GEM_MII_ANLPAR reg bits */ -#define GEM_MII_ANEG_NP 0x00008000 /* next page bit */ -#define GEM_MII_ANEG_ACK 0x00004000 /* ack reception of */ - /* Link Partner Capability */ -#define GEM_MII_ANEG_RF 0x00003000 /* advertise remote fault cap */ -#define GEM_MII_ANEG_ASYM_PAUSE 0x00000100 /* asymmetric pause */ -#define GEM_MII_ANEG_SYM_PAUSE 0x00000080 /* symmetric pause */ -#define GEM_MII_ANEG_HLF_DUPLX 0x00000040 -#define GEM_MII_ANEG_FUL_DUPLX 0x00000020 +/* + * Bits in GEM_MII_ANAR and GEM_MII_ANLPAR registers + * GEM_MII_ANAR contains our capabilities for auto- negotiation + * (Default: 0x00e0) and GEM_MII_ANLPAR contains the link partners + * abilities and is only valid after auto-negotiation completes. + */ +#define GEM_MII_ANEG_FUL_DUPLX 0x00000020 /* can do 1000Base-X FDX */ +#define GEM_MII_ANEG_HLF_DUPLX 0x00000040 /* can do 1000Base-X HDX */ +#define GEM_MII_ANEG_SYM_PAUSE 0x00000080 /* can do symmetric pause */ +#define GEM_MII_ANEG_ASYM_PAUSE 0x00000100 /* can do asymmetric pause */ +#define GEM_MII_ANEG_RF 0x00003000 /* advertise remote fault */ +#define GEM_MII_ANEG_ACK 0x00004000 /* ack reception of + Link Partner Capability */ +#define GEM_MII_ANEG_NP 0x00008000 /* next page bit, always 0 */ #define GEM_MII_ANEG_BITS "\177\020b\5FDX\0b\6HDX\0b\7SYMPAUSE\0" \ "\b\x8_ASYMPAUSE\0\b\xdREMFLT\0\b\xeLPACK\0" \ "\b\xfNPBIT\0\0" -/* GEM_MII_CONFIG reg */ +/* + * Bits in GEM_MII_CONFIG register + * Default: 0x0 + * GEM_MII_CONFIG_ENABLE must be 0 when modifiying the GEM_MII_ANAR + * register. To isolate the MC from the media, set this bit to 0 and + * restart auto-negotiation in GEM_MII_CONTROL. + */ +#define GEM_MII_CONFIG_ENABLE 0x00000001 /* Enable PCS */ +#define GEM_MII_CONFIG_SDO 0x00000002 /* Signal Detect Override */ +#define GEM_MII_CONFIG_SDL 0x00000004 /* Signal Detect active low */ #define GEM_MII_CONFIG_TIMER 0x0000000e /* link monitor timer values */ -#define GEM_MII_CONFIG_ANTO 0x00000020 /* 10ms ANEG timer override */ #define GEM_MII_CONFIG_JS 0x00000018 /* Jitter Study, 0 normal * 1 high freq, 2 low freq */ -#define GEM_MII_CONFIG_SDL 0x00000004 /* Signal Detect active low */ -#define GEM_MII_CONFIG_SDO 0x00000002 /* Signal Detect Override */ -#define GEM_MII_CONFIG_ENABLE 0x00000001 /* Enable PCS */ +#define GEM_MII_CONFIG_ANTO 0x00000020 /* 10ms ANEG timer override */ #define GEM_MII_CONFIG_BITS "\177\020b\0PCSENA\0\0" /* - * GEM_MII_STATE_MACHINE + * Bits in GEM_MII_STATE_MACHINE register * XXX These are best guesses from observed behavior. */ #define GEM_MII_FSM_STOP 0x00000000 /* stopped */ @@ -540,41 +749,70 @@ /* - * GEM_MII_INTERRUP_STATUS reg + * Bits in GEM_MII_INTERRUP_STATUS register * No mask register; mask with the global interrupt mask register. */ -#define GEM_MII_INTERRUP_LINK 0x00000002 /* PCS link status change */ +#define GEM_MII_INTERRUP_LINK 0x00000004 /* PCS link status change */ -/* GEM_MII_DATAPATH_MODE reg */ -#define GEM_MII_DATAPATH_SERIAL 0x00000001 /* Serial link */ +/* + * Bits in GEM_MII_DATAPATH_MODE register + * Default: none + */ +#define GEM_MII_DATAPATH_SERIAL 0x00000001 /* Use internal Serialink */ #define GEM_MII_DATAPATH_SERDES 0x00000002 /* Use PCS via 10bit interfac */ #define GEM_MII_DATAPATH_MII 0x00000004 /* Use {G}MII, not PCS */ -#define GEM_MII_DATAPATH_MIIOUT 0x00000008 /* enable serial output on GMII */ -#define GEM_MII_DATAPATH_BITS "\177\020" \ +#define GEM_MII_DATAPATH_MIIOUT 0x00000008 /* Set serial output on GMII */ +#define GEM_MII_DATAPATH_BITS "\177\020" \ "b\0SERIAL\0b\1SERDES\0b\2MII\0b\3MIIOUT\0\0" -/* GEM_MII_SLINK_CONTROL reg */ -#define GEM_MII_SLINK_LOOPBACK 0x00000001 /* enable loopback at sl, logic - * reversed for SERDES */ +/* + * Bits in GEM_MII_SLINK_CONTROL register + * Default: 0x000 + */ +#define GEM_MII_SLINK_LOOPBACK 0x00000001 /* enable loopback on Serialink + disable loopback on SERDES */ #define GEM_MII_SLINK_EN_SYNC_D 0x00000002 /* enable sync detection */ #define GEM_MII_SLINK_LOCK_REF 0x00000004 /* lock reference clock */ -#define GEM_MII_SLINK_EMPHASIS 0x00000008 /* enable emphasis */ +#define GEM_MII_SLINK_EMPHASIS 0x00000018 /* enable emphasis */ #define GEM_MII_SLINK_SELFTEST 0x000001c0 -#define GEM_MII_SLINK_POWER_OFF 0x00000200 /* Power down serial link */ -#define GEM_MII_SLINK_CONTROL_BITS \ +#define GEM_MII_SLINK_POWER_OFF 0x00000200 /* Power down Serialink block */ +#define GEM_MII_SLINK_RX_ZERO 0x00000c00 /* PLL input to Serialink */ +#define GEM_MII_SLINK_RX_POLL 0x00003000 /* PLL input to Serialink */ +#define GEM_MII_SLINK_TX_ZERO 0x0000c000 /* PLL input to Serialink */ +#define GEM_MII_SLINK_TX_POLL 0x00030000 /* PLL input to Serialink */ +#define GEM_MII_SLINK_CONTROL_BITS \ "\177\020b\0LOOP\0b\1ENASYNC\0b\2LOCKREF" \ - "\0b\3EMPHASIS\0b\x9PWRDWN\0\0" + "\0b\3EMPHASIS1\0b\4EMPHASIS2\0b\x9PWRDWN\0\0" + + +/* + * Bits in GEM_MII_OUTPUT_SELECT register + * Default: 0x0 + */ +#define GEM_MII_PROM_ADDR 0x00000003 /* Test output multiplexor */ -/* GEM_MII_SLINK_STATUS reg */ +/* + * Bits in GEM_MII_SLINK_STATUS register + * Default: 0x0 + */ #define GEM_MII_SLINK_TEST 0x00000000 /* undergoing test */ #define GEM_MII_SLINK_LOCKED 0x00000001 /* waiting 500us lockrefn */ #define GEM_MII_SLINK_COMMA 0x00000002 /* waiting for comma detect */ #define GEM_MII_SLINK_SYNC 0x00000003 /* recv data synchronized */ +/* + * PCI Expansion ROM runtime access + * Sun GEMs map a 1MB space for the PCI Expansion ROM as the second half + * of the first register bank, although they only support up to 64KB ROMs. + */ +#define GEM_PCI_ROM_OFFSET 0x100000 +#define GEM_PCI_ROM_SIZE 0x10000 + + /* Wired GEM PHY addresses */ #define GEM_PHYAD_INTERNAL 1 #define GEM_PHYAD_EXTERNAL 0 --- sys/dev/ic/gemvar.h.dist 2006-11-27 07:13:30.000000000 +0000 +++ sys/dev/ic/gemvar.h 2007-12-16 16:59:05.000000000 +0000 @@ -130,16 +130,27 @@ int sc_phys[2]; /* MII instance -> PHY map */ int sc_mif_config; /* Selected MII reg setting */ + uint32_t sc_mii_anar; /* copy of PCS GEM_MII_ANAR register */ + int sc_mii_media; /* Media selected for PCS MII */ - int sc_pci; /* XXXXX -- PCI buses are LE. */ u_int sc_variant; /* which GEM are we dealing with? */ #define GEM_UNKNOWN 0 /* don't know */ #define GEM_SUN_GEM 1 /* Sun GEM variant */ -#define GEM_APPLE_GMAC 2 /* Apple GMAC variant */ +#define GEM_SUN_ERI 2 /* Sun ERI variant */ +#define GEM_APPLE_GMAC 3 /* Apple GMAC variant */ +#define GEM_APPLE_K2_GMAC 4 /* Apple K2 GMAC */ + +#define GEM_IS_APPLE(sc) \ + ((sc)->sc_variant == GEM_APPLE_GMAC || \ + (sc)->sc_variant == GEM_APPLE_K2_GMAC) u_int sc_flags; /* */ short sc_if_flags; /* copy of ifp->if_flags */ #define GEM_GIGABIT 0x0001 /* has a gigabit PHY */ +#define GEM_LINK 0x0002 /* link is up */ +#define GEM_PCI 0x0004 /* XXX PCI busses are little-endian */ +#define GEM_SERDES 0x0008 /* use the SERDES */ +#define GEM_SERIAL 0x0010 /* use the serial link */ void *sc_sdhook; /* shutdown hook */ void *sc_powerhook; /* power management hook */ @@ -179,6 +190,7 @@ /* ========== */ int sc_inited; + int sc_meminited; int sc_debug; void *sc_sh; /* shutdownhook cookie */ @@ -207,13 +219,15 @@ #endif -#define GEM_DMA_READ(sc, v) (((sc)->sc_pci) ? le64toh(v) : be64toh(v)) -#define GEM_DMA_WRITE(sc, v) (((sc)->sc_pci) ? htole64(v) : htobe64(v)) +#define GEM_DMA_READ(sc, v) \ + (((sc)->sc_flags & GEM_PCI) ? le64toh(v) : be64toh(v)) +#define GEM_DMA_WRITE(sc, v) \ + (((sc)->sc_flags & GEM_PCI) ? htole64(v) : htobe64(v)) #define GEM_CDTXADDR(sc, x) ((sc)->sc_cddma + GEM_CDTXOFF((x))) #define GEM_CDRXADDR(sc, x) ((sc)->sc_cddma + GEM_CDRXOFF((x))) -#define GEM_CDSPADDR(sc) ((sc)->sc_cddma + GEM_CDSPOFF) +#define GEM_CDADDR(sc) ((sc)->sc_cddma + GEM_CDOFF) #define GEM_CDTXSYNC(sc, x, n, ops) \ do { \ @@ -240,9 +254,9 @@ bus_dmamap_sync((sc)->sc_dmatag, (sc)->sc_cddmamap, \ GEM_CDRXOFF((x)), sizeof(struct gem_desc), (ops)) -#define GEM_CDSPSYNC(sc, ops) \ +#define GEM_CDSYNC(sc, ops) \ bus_dmamap_sync((sc)->sc_dmatag, (sc)->sc_cddmamap, \ - GEM_CDSPOFF, GEM_SETUP_PACKET_LEN, (ops)) + 0, sizeof(struct gem_control_data), (ops)) #define GEM_INIT_RXDESC(sc, x) \ do { \ @@ -260,6 +274,18 @@ GEM_CDRXSYNC((sc), (x), BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE); \ } while (0) +#define GEM_UPDATE_RXDESC(sc, x) \ +do { \ + struct gem_rxsoft *__rxs = &sc->sc_rxsoft[(x)]; \ + struct gem_desc *__rxd = &sc->sc_rxdescs[(x)]; \ + struct mbuf *__m = __rxs->rxs_mbuf; \ + \ + __rxd->gd_flags = \ + GEM_DMA_WRITE((sc), \ + (((__m->m_ext.ext_size)<mpd_name, MII_REV(ma->mii_id2)); + sc->mii_mpd_model = MII_MODEL(ma->mii_id2); sc->mii_inst = mii->mii_instance; sc->mii_phy = ma->mii_phyno; sc->mii_funcs = &bmtphy_funcs; @@ -273,6 +275,35 @@ mii->mii_media_active |= IFM_10_T; if (aux_csr & AUX_CSR_FDX) mii->mii_media_active |= IFM_FDX; + else + mii->mii_media_active |= IFM_HDX; } else mii->mii_media_active = ife->ifm_media; } + +static void +bmtphy_reset(struct mii_softc *sc) +{ + u_int16_t data; + + mii_phy_reset(sc); + + if (sc->mii_mpd_model == MII_MODEL_xxBROADCOM_BCM5221) { + /* Enable shadow register mode */ + data = PHY_READ(sc, 0x1f); + PHY_WRITE(sc, 0x1f, data | 0x0080); + + /* Enable APD (Auto PowerDetect) */ + data = PHY_READ(sc, MII_BMTPHY_AUX2); + PHY_WRITE(sc, MII_BMTPHY_AUX2, data | 0x0020); + + /* Enable clocks across APD for + * Auto-MDIX functionality */ + data = PHY_READ(sc, MII_BMTPHY_INTR); + PHY_WRITE(sc, MII_BMTPHY_INTR, data | 0x0004); + + /* Disable shadow register mode */ + data = PHY_READ(sc, 0x1f); + PHY_WRITE(sc, 0x1f, data & ~0x0080); + } +} --- sys/dev/pci/pcidevs.dist 2007-11-24 07:51:51.000000000 +0000 +++ sys/dev/pci/pcidevs 2007-12-09 15:53:39.000000000 +0000 @@ -973,6 +973,7 @@ product APPLE U3_PPB5 0x0049 U3 PCI-PCI bridge product APPLE U3_AGP 0x004b U3 AGP Interface product APPLE K2_GMAC 0x004c GMAC Ethernet +product APPLE SHASTA_GMAC 0x0051 Shasta GMAC product APPLE INTREPID2_AGP 0x0066 Intrepid 2 AGP product APPLE INTREPID2_PCI1 0x0067 Intrepid 2 PCI product APPLE INTREPID2_PCI2 0x0068 Intrepid 2 PCI --- sys/dev/pci/pcidevs.h.dist 2007-11-24 07:51:51.000000000 +0000 +++ sys/dev/pci/pcidevs.h 2007-12-09 15:54:58.000000000 +0000 @@ -1,10 +1,10 @@ -/* $NetBSD: pcidevs.h,v 1.854.2.16 2007/11/15 10:28:25 pavel Exp $ */ +/* $NetBSD$ */ /* * THIS FILE AUTOMATICALLY GENERATED. DO NOT EDIT. * * generated from: - * NetBSD + * NetBSD: pcidevs,v 1.855.2.16 2007/11/15 10:28:24 pavel Exp */ /* @@ -980,6 +980,7 @@ #define PCI_PRODUCT_APPLE_U3_PPB5 0x0049 /* U3 PCI-PCI bridge */ #define PCI_PRODUCT_APPLE_U3_AGP 0x004b /* U3 AGP Interface */ #define PCI_PRODUCT_APPLE_K2_GMAC 0x004c /* GMAC Ethernet */ +#define PCI_PRODUCT_APPLE_SHASTA_GMAC 0x0051 /* Shasta GMAC */ #define PCI_PRODUCT_APPLE_INTREPID2_AGP 0x0066 /* Intrepid 2 AGP */ #define PCI_PRODUCT_APPLE_INTREPID2_PCI1 0x0067 /* Intrepid 2 PCI */ #define PCI_PRODUCT_APPLE_INTREPID2_PCI2 0x0068 /* Intrepid 2 PCI */ --- sys/dev/pci/pcidevs_data.h.dist 2007-11-24 07:51:52.000000000 +0000 +++ sys/dev/pci/pcidevs_data.h 2007-12-09 15:54:58.000000000 +0000 @@ -1,10 +1,10 @@ -/* $NetBSD: pcidevs_data.h,v 1.853.2.16 2007/11/15 10:28:26 pavel Exp $ */ +/* $NetBSD$ */ /* * THIS FILE AUTOMATICALLY GENERATED. DO NOT EDIT. * * generated from: - * NetBSD + * NetBSD: pcidevs,v 1.855.2.16 2007/11/15 10:28:24 pavel Exp */ /* @@ -3520,6 +3520,10 @@ "GMAC Ethernet", }, { + PCI_VENDOR_APPLE, PCI_PRODUCT_APPLE_SHASTA_GMAC, + "Shasta GMAC", + }, + { PCI_VENDOR_APPLE, PCI_PRODUCT_APPLE_INTREPID2_AGP, "Intrepid 2 AGP", }, @@ -12888,4 +12892,4 @@ "Video Controller", }, }; -const int pci_nproducts = 2627; +const int pci_nproducts = 2628; --- sys/dev/pci/if_gem_pci.c.dist 2007-12-16 23:26:08.000000000 +0000 +++ sys/dev/pci/if_gem_pci.c 2007-12-28 08:02:39.000000000 +0000 @@ -30,7 +30,7 @@ */ /* - * PCI bindings for Sun GEM ethernet controllers. + * PCI bindings for Apple GMAC, Sun ERI and Sun GEM Ethernet controllers */ #include @@ -79,6 +79,15 @@ #include #endif +#ifndef GEM_USE_LOCAL_MAC_ADDRESS +#if defined (macppc) || defined (__sparc__) +#define GEM_USE_LOCAL_MAC_ADDRESS 0 /* use system-wide address */ +#else +#define GEM_USE_LOCAL_MAC_ADDRESS 1 +#endif +#endif + + struct gem_pci_softc { struct gem_softc gsc_gem; /* GEM device */ void *gsc_ih; @@ -111,6 +120,7 @@ (PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_APPLE_GMAC || PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_APPLE_GMAC2 || PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_APPLE_GMAC3 || + PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_APPLE_SHASTA_GMAC || PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_APPLE_K2_GMAC)) return (1); @@ -118,6 +128,35 @@ return (0); } +#if GEM_USE_LOCAL_MAC_ADDRESS +static inline int +gempromvalid(u_int8_t* buf) +{ + return buf[0] == 0x18 && buf[1] == 0x00 && /* structure length */ + buf[2] == 0x00 && /* revision */ + (buf[3] == 0x00 || /* hme */ + buf[3] == 0x80) && /* qfe */ + buf[4] == PCI_SUBCLASS_NETWORK_ETHERNET && /* subclass code */ + buf[5] == PCI_CLASS_NETWORK; /* class code */ +} + +static inline int +isshared_pins(u_int8_t* buf) +{ + return buf[0] == 's' && buf[1] == 'h' && buf[2] == 'a' && + buf[3] == 'r' && buf[4] == 'e' && buf[5] == 'd' && + buf[6] == '-' && buf[7] == 'p' && buf[8] == 'i' && + buf[9] == 'n' && buf[10] == 's'; +} +#endif + +static inline int +isserdes(u_int8_t* buf) +{ + return buf[0] == 's' && buf[1] == 'e' && buf[2] == 'r' && + buf[3] == 'd' && buf[4] == 'e' && buf[5] == 's'; +} + void gem_attach_pci(parent, self, aux) struct device *parent, *self; @@ -130,6 +169,26 @@ const char *intrstr; char devinfo[256]; uint8_t enaddr[ETHER_ADDR_LEN]; +#if GEM_USE_LOCAL_MAC_ADDRESS + u_int8_t *enp; + bus_space_handle_t romh; + u_int8_t buf[0x0800]; + int dataoff, vpdoff, serdes; +#ifdef GEM_DEBUG + int i, j; +#endif + struct pci_vpd *vpd; + static const u_int8_t promhdr[] = { 0x55, 0xaa }; +#define PROMHDR_PTR_DATA 0x18 + static const u_int8_t promdat[] = { + 0x50, 0x43, 0x49, 0x52, /* "PCIR" */ + PCI_VENDOR_SUN & 0xff, PCI_VENDOR_SUN >> 8, + PCI_PRODUCT_SUN_GEMNETWORK & 0xff, + PCI_PRODUCT_SUN_GEMNETWORK >> 8 + }; +#define PROMDATA_PTR_VPD 0x08 +#define PROMDATA_DATA2 0x0a +#endif /* GEM_USE_LOCAL_MAC_ADDRESS */ aprint_naive(": Ethernet controller\n"); @@ -137,19 +196,38 @@ aprint_normal(": %s (rev. 0x%02x)\n", devinfo, PCI_REVISION(pa->pa_class)); + /* + * Some Sun GEMs/ERIs do have their intpin register bogusly set to 0, + * although it should be 1. correct that. + */ + if (pa->pa_intrpin == 0) + pa->pa_intrpin = 1; + + sc->sc_variant = GEM_UNKNOWN; + sc->sc_dmatag = pa->pa_dmat; - sc->sc_pci = 1; /* XXX */ + sc->sc_flags |= GEM_PCI; - if (PCI_VENDOR(pa->pa_id) == PCI_VENDOR_SUN && - (PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_SUN_ERINETWORK || - PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_SUN_GEMNETWORK)) - sc->sc_variant = GEM_SUN_GEM; - else if (PCI_VENDOR(pa->pa_id) == PCI_VENDOR_APPLE && - (PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_APPLE_GMAC || - PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_APPLE_GMAC2 || - PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_APPLE_K2_GMAC)) - sc->sc_variant = GEM_APPLE_GMAC; + if (PCI_VENDOR(pa->pa_id) == PCI_VENDOR_SUN) { + if (PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_SUN_GEMNETWORK) + sc->sc_variant = GEM_SUN_GEM; + if (PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_SUN_ERINETWORK) + sc->sc_variant = GEM_SUN_ERI; + } else if (PCI_VENDOR(pa->pa_id) == PCI_VENDOR_APPLE) { + if (PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_APPLE_GMAC || + PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_APPLE_GMAC2 || + PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_APPLE_GMAC3 || + PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_APPLE_SHASTA_GMAC) + sc->sc_variant = GEM_APPLE_GMAC; + if (PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_APPLE_K2_GMAC) + sc->sc_variant = GEM_APPLE_K2_GMAC; + } + + if (sc->sc_variant == GEM_UNKNOWN) { + aprint_error("%s: unknown adaptor\n", sc->sc_dev.dv_xname); + return; + } #define PCI_GEM_BASEADDR (PCI_MAPREG_START + 0x00) @@ -169,18 +247,125 @@ return; } +#if GEM_USE_LOCAL_MAC_ADDRESS /* - * XXX This should be done with properties, when those are - * XXX fleshed out. + * Dig out VPD (vital product data) and acquire Ethernet address. + * The VPD of gem resides in the PCI PROM (PCI FCode). */ + /* + * ``Writing FCode 3.x Programs'' (newer ones, dated 1997 and later) + * chapter 2 describes the data structure. + */ + + enp = NULL; + + if (sc->sc_variant == GEM_SUN_GEM && + (bus_space_subregion(sc->sc_bustag, sc->sc_h1, + GEM_PCI_ROM_OFFSET, GEM_PCI_ROM_SIZE, &romh)) == 0) { + + /* read PCI Expansion PROM Header */ + bus_space_read_region_1(sc->sc_bustag, + romh, 0, buf, sizeof buf); + + /* Check for "shared-pins = serdes" in FCode. */ + i = 0; + serdes = 0; + while (i < (sizeof buf) - sizeof "serdes") { + if (!serdes) { + if (isserdes(&buf[i])) + serdes = 1; + } else { + if (isshared_pins(&buf[i])) + serdes = 2; + } + if (serdes == 2) { + sc->sc_flags |= GEM_SERDES; + break; + } + i++; + } +#ifdef GEM_DEBUG + /* PROM dump */ + printf("%s: PROM dump (0x0000 to %04lx)\n", sc->sc_dev.dv_xname, + (sizeof buf) - 1); + i = 0; + j = 0; + printf(" %04x ", i); + while (i < sizeof buf) { + printf("%02x ", buf[i]); + if (i && !(i % 8)) + printf(" "); + if (i && !(i % 16)) { + printf(" "); + while (j < i) { + if (buf[j] > 31 && buf[j] < 128) + printf("%c", buf[j]); + else + printf("."); + j++; + } + j = i; + printf("\n %04x ", i); + } + i++; + } + printf("\n"); +#endif + + if (memcmp(buf, promhdr, sizeof promhdr) == 0 && + (dataoff = (buf[PROMHDR_PTR_DATA] | + (buf[PROMHDR_PTR_DATA + 1] << 8))) >= 0x1c) { + + /* read PCI Expansion PROM Data */ + bus_space_read_region_1(sc->sc_bustag, romh, dataoff, + buf, 64); + if (memcmp(buf, promdat, sizeof promdat) == 0 && + gempromvalid(buf + PROMDATA_DATA2) && + (vpdoff = (buf[PROMDATA_PTR_VPD] | + (buf[PROMDATA_PTR_VPD + 1] << 8))) >= 0x1c) { + + /* + * The VPD of gem is not in PCI 2.2 standard + * format. The length in the resource header + * is in big endian, and resources are not + * properly terminated (only one resource + * and no end tag). + */ + /* read PCI VPD */ + bus_space_read_region_1(sc->sc_bustag, romh, + vpdoff, buf, 64); + vpd = (void *)(buf + 3); + if (PCI_VPDRES_ISLARGE(buf[0]) && + PCI_VPDRES_LARGE_NAME(buf[0]) + == PCI_VPDRES_TYPE_VPD && + vpd->vpd_key0 == 0x4e /* N */ && + vpd->vpd_key1 == 0x41 /* A */ && + vpd->vpd_len == ETHER_ADDR_LEN) { + /* + * Ethernet address found + */ + enp = buf + 6; + } + } + } + } + + if (enp) + memcpy(enaddr, enp, ETHER_ADDR_LEN); + else +#endif /* GEM_USE_LOCAL_MAC_ADDRESS */ #ifdef __sparc__ { + if (strcmp(prom_getpropstring(PCITAG_NODE(pa->pa_tag), + "shared-pins"), "serdes") == 0) + sc->sc_flags |= GEM_SERDES; prom_getether(PCITAG_NODE(pa->pa_tag), enaddr); } -#endif /* __sparc__ */ +#else #ifdef macppc { int node; + char sp[6]; /* "serdes" */ node = pcidev_to_ofdev(pa->pa_pc, pa->pa_tag); if (node == 0) { @@ -189,9 +374,15 @@ return; } + OF_getprop(node, "shared-pins", sp, sizeof(sp)); + if (isserdes(sp)) + sc->sc_flags |= GEM_SERDES; OF_getprop(node, "local-mac-address", enaddr, sizeof(enaddr)); } +#else + printf("%s: no Ethernet address found\n", sc->sc_dev.dv_xname); #endif /* macppc */ +#endif /* __sparc__ */ if (pci_intr_map(pa, &ih) != 0) { aprint_error("%s: unable to map interrupt\n",